diff --git a/.github/workflows/docker-image.yml b/.github/workflows/docker-image.yml index 719fe8173..5e54eeb1f 100644 --- a/.github/workflows/docker-image.yml +++ b/.github/workflows/docker-image.yml @@ -27,7 +27,7 @@ jobs: - name: version run: | - npm version --no-git-tag-version $(node -p "require('./package.json').version")-${GITHUB_SHA::8} + npm version --no-git-tag-version $(node -p "require('./package.json').version")-en-${GITHUB_SHA::8} - name: Install dependencies run: npm ci @@ -57,7 +57,7 @@ jobs: id: docker_meta_backend uses: docker/metadata-action@v5 with: - images: ${{ env.REGISTRY }}/pastvu/backend/ru + images: ${{ env.REGISTRY }}/pastvu/backend/en - name: Build and push backend id: docker_build_backend @@ -75,7 +75,7 @@ jobs: id: docker_meta_frontend uses: docker/metadata-action@v5 with: - images: ${{ env.REGISTRY }}/pastvu/frontend/ru + images: ${{ env.REGISTRY }}/pastvu/frontend/en - name: Build and push frontend id: docker_build_frontend diff --git a/Makefile b/Makefile new file mode 100644 index 000000000..65c4e01c9 --- /dev/null +++ b/Makefile @@ -0,0 +1,4 @@ +VERSION := $(shell node -p "require('./package.json').version") +BRANCH := $(shell git branch --show-current) +tag: + git tag v$(VERSION)-$(BRANCH) diff --git a/app/errors/intl.js b/app/errors/intl.js index d737c2f3f..98d116cec 100644 --- a/app/errors/intl.js +++ b/app/errors/intl.js @@ -4,61 +4,62 @@ */ export default { - DENY: 'У вас нет прав на это действие', + DENY: 'You do not have permission for this action', - BAD_PARAMS: 'Неверные параметры запроса', + BAD_PARAMS: 'Invalid request parameters', BAD_BROWSER: 'Bad browser, we do not support it', - SESSION_CAN_REGET_REGISTERED_ONLY: 'Ошибка выборки пользователей', + SESSION_CAN_REGET_REGISTERED_ONLY: 'Error while selecting users', + SESSION_EXPIRED_ARCHIVE_NO_RESULT: 'Archive sessions error', SESSION_NO_HEADERS: 'Bad request - no header or user agent', - SESSION_NOT_FOUND: 'Сессия не найдена', + SESSION_NOT_FOUND: 'Session was not found', - TIMEOUT: 'Превышено время ожидания', - UNHANDLED_ERROR: 'На сервере возникла ошибка', - COUNTER_ERROR: 'На сервере возникла ошибка', + TIMEOUT: 'Waiting time was exceeded', + UNHANDLED_ERROR: 'Error occurred on server', + COUNTER_ERROR: 'Error occurred on server', - NOTICE: 'Уведомление', + NOTICE: 'Notice', - NOT_FOUND: 'Ресурс не найден', - NOT_FOUND_USER: 'Пользователь не найден', - NO_SUCH_METHOD: 'Запрашиваемый метод не сушествует', - NO_SUCH_RESOURCE: 'Ресурс не найден', - NO_SUCH_PHOTO: 'Запрашиваемой фотографии не существует или она не доступна', - NO_SUCH_USER: 'Запрашиваемый пользователь не существует', - NO_SUCH_REGION: 'Такого региона не существует', - NO_SUCH_REGIONS: 'Таких регионов не существует', - NO_SUCH_NEWS: 'Такой новости не существует', + NOT_FOUND: 'Resource was not found', + NOT_FOUND_USER: 'User was not found', + NO_SUCH_METHOD: 'Requested method does not exist', + NO_SUCH_RESOURCE: 'Resource was not found', + NO_SUCH_PHOTO: 'Requested photo does not exist or it is not available to you', + NO_SUCH_USER: 'Requested user does not exist', + NO_SUCH_REGION: 'Requested region does not exist', + NO_SUCH_REGIONS: 'Requested regions don\'t exist', + NO_SUCH_NEWS: 'Requested news does not exist', - INPUT: 'Ошибка ввода', - INPUT_FIELD_REQUIRED: 'Обязтельное поле ввода', - INPUT_LOGIN_REQUIRED: 'Заполните имя пользователя', - INPUT_LOGIN_CONSTRAINT: 'Имя пользователя должно содержать от 3 до 15 латинских символов, начинаться с буквы и заканчиваться на букву или цифру.' + - 'В состав слова могут входить цифры, точка, подчеркивание и тире', - INPUT_PASS_REQUIRED: 'Введите пароль', - INPUT_EMAIL_REQUIRED: 'Введите адрес email', + INPUT: 'Input error', + INPUT_FIELD_REQUIRED: 'Required input field', + INPUT_LOGIN_REQUIRED: 'Fill in the username', + INPUT_LOGIN_CONSTRAINT: 'Username should be between 3 and 15 characters long, it should start with a letter and end with a letter or digit. ' + + 'Username may contain digits, dot, underline and hyphen characters.', + INPUT_PASS_REQUIRED: 'Enter password', + INPUT_EMAIL_REQUIRED: 'Enter email', - AUTHENTICATION: 'Ошибка аутентификации', - AUTHENTICATION_REGISTRATION: 'Ошибка аутентификации', - AUTHENTICATION_PASSCHANGE: 'Ошибка смены пароля', - AUTHENTICATION_DOESNT_MATCH: 'Неправильная пара логин-пароль', - AUTHENTICATION_MAX_ATTEMPTS: 'Ваш аккаунт временно заблокирован из-за превышения количества попыток ввода неверных данных', - AUTHENTICATION_NOT_ALLOWED: 'Указанному пользователю не разрешено заходить на сайт', - AUTHENTICATION_PASS_WRONG: 'Пароль не верен', - AUTHENTICATION_CURRPASS_WRONG: 'Текущий пароль не верен', - AUTHENTICATION_PASSWORDS_DONT_MATCH: 'Пароли не совпадают', - AUTHENTICATION_USER_EXISTS: 'Пользователь с таким именем уже зарегистрирован', - AUTHENTICATION_USER_DOESNT_EXISTS: 'Пользователя с таким логином или e-mail не существует', - AUTHENTICATION_EMAIL_EXISTS: 'Пользователь с таким email уже зарегистрирован', - AUTHENTICATION_KEY_DOESNT_EXISTS: 'Переданного вами ключа не существует', + AUTHENTICATION: 'Authentication error', + AUTHENTICATION_REGISTRATION: 'Authentication error', + AUTHENTICATION_PASSCHANGE: 'Password change error', + AUTHENTICATION_DOESNT_MATCH: 'Wrong login or password', + AUTHENTICATION_MAX_ATTEMPTS: 'Your account has been suspended due to exceeding the number of failed attempts', + AUTHENTICATION_NOT_ALLOWED: 'Specified user is not allowed to login', + AUTHENTICATION_PASS_WRONG: 'Wrong password', + AUTHENTICATION_CURRPASS_WRONG: 'Wrong current password', + AUTHENTICATION_PASSWORDS_DONT_MATCH: 'Passwords do not match', + AUTHENTICATION_USER_EXISTS: 'This user name is already registered', + AUTHENTICATION_USER_DOESNT_EXISTS: 'User with such password or e-mail does not exist', + AUTHENTICATION_EMAIL_EXISTS: 'User with this email is already registered', + AUTHENTICATION_KEY_DOESNT_EXISTS: 'The key you passed does not exist', - PHOTO_CHANGED: 'С момента обновления вами страницы, информация на ней была кем-то изменена', - PHOTO_NEED_REASON: 'Необходимо указать причину операции', - PHOTO_NEED_COORD: 'Фотография должна иметь координату или быть привязана к региону вручную', - PHOTO_NEED_TITLE: 'Необходимо заполнить название фотографии', - PHOTO_ANOTHER_STATUS: 'Фотография уже в другом статусе, обновите страницу', - PHOTO_YEARS_CONSTRAINT: 'Опубликованные фотографии должны иметь предполагаемую датировку в интервале 1826—2000гг.', - PAINTING_YEARS_CONSTRAINT: 'Опубликованные изображения должны иметь предполагаемую датировку в интервале 100 BC — 1980г.', - PHOTO_CONVERT_PROCEEDING: 'Вы уже отправили запрос и он еще выполняется. Попробуйте позже', + PHOTO_CHANGED: 'From the moment you had got the page, the information on it has been altered by someone', + PHOTO_NEED_REASON: 'You must specify the reason for the operation', + PHOTO_NEED_COORD: 'The photo must have coordinates or be tied to the region manually', + PHOTO_NEED_TITLE: 'You must fill in the name of the photo', + PHOTO_ANOTHER_STATUS: 'Photo is already in other status, refresh the page', + PHOTO_YEARS_CONSTRAINT: 'Published photos must be in the range of 1826-2000', + PAINTING_YEARS_CONSTRAINT: 'Published painting must be in the range of 100 BC — 1980 AD', + PHOTO_CONVERT_PROCEEDING: 'You have already sent a request and it is still running. try later', REGION_PARENT_THE_SAME: 'Вы пытаетесь указать родителем его самого', REGION_PARENT_DOESNT_EXISTS: 'Указанного родительского региона не существует', @@ -73,9 +74,9 @@ export default { REGION_SAVED_BUT_REFILL_CACHE: 'Сохранено, но возникла ошибка во время пересчета кэша регионов. Рекоммендуется перезагрузка сервера', REGION_SELECT_LIMIT: 'Вы можете выбрать до 10 регионов', - COMMENT_NO_OBJECT: 'Комментируемого объекта не существует, или он находится в недоступном вам режиме', - COMMENT_NOT_ALLOWED: 'Операции с комментариями на этой странице запрещены', - COMMENT_DOESNT_EXISTS: 'Комментария не существует', + COMMENT_NO_OBJECT: 'Commented object does not exist or moderators changed it status, which is not available to you', + COMMENT_NOT_ALLOWED: 'Operations with the comments on this page are forbidden', + COMMENT_DOESNT_EXISTS: 'Comment does not exist', COMMENT_WRONG_PARENT: 'Что-то не так с родительским комментарием. Возможно он был удален. Пожалуйста, обновите страницу', COMMENT_TOO_LONG: 'Комментарий длиннее допустимого значения (12000)', COMMENT_UNKNOWN_USER: 'Неизвестный пользователь в комментариях', @@ -84,12 +85,12 @@ export default { ADMIN_SUPER_CANT_BE_ASSIGNED: 'Суперадминистратор не может быть назначен через интерфейс управления пользователями', ADMIN_ONLY_SUPER_CAN_ASSIGN: 'Только суперадминистратор может назначать администраторов', - CONVERT_PHOTOS_ALL: 'Ошибка отправки на конвертацию', + CONVERT_PHOTOS_ALL: 'Error sending for conversion', CONVERT_PROMISE_GENERATOR: 'Ошибка выполнения операции в конвейере конвертации', - SETTING_DOESNT_EXISTS: 'Такой настройки не существует', + SETTING_DOESNT_EXISTS: 'Such setting does not exist', - MAIL_SEND: 'Ошибка отправки письма', - MAIL_WRONG: 'Неверный формат email, проверьте еще раз', - MAIL_IN_USE: 'Этот email уже используется другим пользователем', + MAIL_SEND: 'Error sending mail', + MAIL_WRONG: 'Wrong email, check it one more time', + MAIL_IN_USE: 'This email is already in use by another user', }; diff --git a/config/default.config.js b/config/default.config.js index d475e41ae..632d7cfeb 100644 --- a/config/default.config.js +++ b/config/default.config.js @@ -9,7 +9,8 @@ const ms = require('ms'); module.exports = { env: 'development', // Enviroment: development, test, production locales: ['en', 'ru'], // List of supported locales. First one is the default locale, if user transferred nothing - lang: 'ru', // Language: ru, en + lang: 'en', // Language: ru, en + admin: { email: '', }, diff --git a/controllers/auth.js b/controllers/auth.js index 49e92d9b9..fa655a8be 100755 --- a/controllers/auth.js +++ b/controllers/auth.js @@ -165,7 +165,7 @@ async function register({ login, email, pass, pass2 }) { sender: 'noreply', receiver: { alias: login, email }, bcc: config.admin.email, - subject: 'Подтверждение регистрации', + subject: 'Registration Confirmation', head: true, body: regTpl({ email, @@ -173,10 +173,10 @@ async function register({ login, email, pass, pass2 }) { config, confirmKey, username: login, - greeting: 'Спасибо за регистрацию на проекте PastVu!', - linkvalid: `${human2d} (до ${moment.utc().add(ms2d).format('LLL')})`, + greeting: 'Thank you for the registering on PastVu!', + linkvalid: `${human2d} (till ${moment.utc().add(ms2d).format('LLL')})`, }), - text: `Перейдите по следующей ссылке: ${config.client.origin}/confirm/${confirmKey}`, + text: `Click the following link: ${config.client.origin}/confirm/${confirmKey}`, }); } catch (err) { await User.deleteOne({ login }).exec(); @@ -186,8 +186,8 @@ async function register({ login, email, pass, pass2 }) { } return { - message: 'Учетная запись создана успешно. Для завершения регистрации следуйте инструкциям, ' + - 'отправленным на указанный вами e-mail', + message: 'Account has been successfully created. To confirm registration, ' + + 'follow the instructions sent to Your e-mail', }; } @@ -221,19 +221,19 @@ async function recall({ login }) { sendMail({ sender: 'noreply', receiver: { alias: user.login, email: user.email }, - subject: 'Запрос на восстановление пароля', + subject: 'Password recovery request', head: true, body: recallTpl({ config, confirmKey, username: user.disp, - linkvalid: `${human2d} (до ${moment.utc().add(ms2d).format('LLL')})`, + linkvalid: `${human2d} (till ${moment.utc().add(ms2d).format('LLL')})`, }), - text: `Перейдите по следующей ссылке: ${config.client.origin}/confirm/${confirmKey}`, + text: `Click the following link: ${config.client.origin}/confirm/${confirmKey}`, }); return { - message: 'Запрос успешно отправлен. Для продолжения процедуры следуйте инструкциям, высланным на Ваш e-mail', + message: 'The data has been successfully sent. To restore the password, follow the instructions sent to Your e-mail', }; } @@ -274,7 +274,7 @@ async function passChangeRecall({ key, pass, pass2 }) { await Promise.all([user.save(), confirm.deleteOne()]); - return { message: 'Новый пароль сохранен успешно' }; + return { message: 'New password has been saved successfully' }; } // Password changing in user's settings page with entering current password @@ -302,7 +302,7 @@ async function passChange({ login, pass, passNew, passNew2 }) { iAm.user.pass = passNew; await iAm.user.save(); - return { message: 'Новый пароль установлен успешно' }; + return { message: 'Password has been changed successfully' }; } // Check confirm key @@ -325,7 +325,7 @@ async function checkConfirm({ key }) { await Promise.all([user.save(), confirm.deleteOne()]); return { - message: 'Спасибо, регистрация подтверждена! Теперь вы можете войти в систему, используя ваш логин и пароль', + message: 'Thank you! Your registration is confirmed. Now you can log in using your username and password', type: 'noty', }; } diff --git a/controllers/mail.js b/controllers/mail.js index 600119e66..d6dabe1a3 100755 --- a/controllers/mail.js +++ b/controllers/mail.js @@ -37,7 +37,7 @@ export async function send(options) { 'X-Laziness-level': 1000, }, html: options.body, - text: options.text || 'Зайдите, чтобы посмотреть', + text: options.text || 'Visit to see', }; if (Array.isArray(options.attachments) && options.attachments.length) { diff --git a/controllers/photo.js b/controllers/photo.js index a852161b4..eeb5d9cdf 100755 --- a/controllers/photo.js +++ b/controllers/photo.js @@ -408,9 +408,9 @@ async function give(params) { } } - const regionFields = photo.geo ? ['cid', 'title_local'] : + const regionFields = photo.geo ? ['cid', 'title_en'] : // If photo has no coordinates, additionally take home position of regions - { _id: 0, cid: 1, title_local: 1, center: 1, bbox: 1, bboxhome: 1 }; + { _id: 0, cid: 1, title_en: 1, center: 1, bbox: 1, bboxhome: 1 }; const regions = await this.call('region.getObjRegionList', { obj: photo, fields: regionFields, fromDb: !photo.geo }); @@ -3299,7 +3299,7 @@ async function giveObjHist({ cid, fetchId, showDiff }) { // If regions exists, get theirs objects if (Object.keys(regions).length) { - result.regions = regionController.fillRegionsHash(regions, ['cid', 'title_local']); + result.regions = regionController.fillRegionsHash(regions, ['cid', 'title_en']); } // If reasons exists, get theirs headers diff --git a/controllers/region.js b/controllers/region.js index 15d0deb3b..b5646325e 100644 --- a/controllers/region.js +++ b/controllers/region.js @@ -462,7 +462,7 @@ export const genObjsShortRegionsArr = function (objs, showlvls = ['r0', 'r1'], d } if (Object.keys(shortRegionsHash).length) { - fillRegionsHash(shortRegionsHash, ['cid', 'title_local']); + fillRegionsHash(shortRegionsHash, ['cid', 'title_en']); } else { shortRegionsHash = undefined; } @@ -1390,7 +1390,7 @@ async function give(data) { children = []; for (const cid of childrenCids) { - const { cdate, udate, title_local: title, childLen } = regionCacheHash[cid]; + const { cdate, udate, title_en: title, childLen } = regionCacheHash[cid]; children.push({ cid, cdate, udate, title, childLen, childrenCount: _.size(regionsChildrenArrHash[cid]) || undefined }); } diff --git a/controllers/routes.js b/controllers/routes.js index c15fc1d28..82f971bc9 100644 --- a/controllers/routes.js +++ b/controllers/routes.js @@ -136,7 +136,8 @@ function meta(req) { } else if (!_.isEmpty(photo.regions)) { // If there in no description, create it as regions names desc = og.desc = twitter.desc = photo.regions.reduceRight( - (result, region, index) => result + region.title_local + (index ? ', ' : ''), '' + + (result, region, index) => result + region.title_en + (index ? ', ' : ''), '' ); } else { desc = ''; @@ -307,7 +308,7 @@ export function bindRoutes(app) { res.statusCode = 200; res.render('status/badbrowser', { agent: req.browser && req.browser.agent, - title: 'Вы используете устаревшую версию браузера', + title: 'You are using outdated browser', }); }); diff --git a/controllers/subscr.js b/controllers/subscr.js index 1ec61c309..12d9d384b 100644 --- a/controllers/subscr.js +++ b/controllers/subscr.js @@ -8,7 +8,6 @@ import _ from 'lodash'; import path from 'path'; import pug from 'pug'; import log4js from 'log4js'; -import Utils from '../commons/Utils'; import * as session from './_session'; import config from '../config'; import { waitDb } from './connection'; @@ -37,8 +36,8 @@ const sortNotice = (a, b) => a.brief.newest < b.brief.newest ? 1 : a.brief.newes const sortSubscr = ({ ccount_new: aCount = 0, sbscr_create: aDate }, { ccount_new: bCount = 0, sbscr_create: bDate }) => aCount < bCount ? 1 : aCount > bCount ? -1 : aDate < bDate ? 1 : aDate > bDate ? -1 : 0; const declension = { - comment: [' новый комментарий', ' новых комментария', ' новых комментариев'], - commentUnread: [' непрочитанный', ' непрочитанных', ' непрочитанных'], + comment: [' new comment', ' new comments'], + commentUnread: [' unread'], }; // Subscribe to/unsubscribe from object (external, for current user by object cid) @@ -437,10 +436,10 @@ async function sendUserNotice(userId) { totalNewestComments += newest; - obj.briefFormat = { newest: newest + Utils.format.wordEndOfNum(newest, declension.comment) }; + obj.briefFormat = { newest: newest + ' new comment' + (newest > 1 ? 's' : '') }; if (newest !== unread) { - obj.briefFormat.unread = unread + Utils.format.wordEndOfNum(unread, declension.commentUnread); + obj.briefFormat.unread = unread + declension.commentUnread; } result.push(obj); @@ -461,7 +460,7 @@ async function sendUserNotice(userId) { await sendMail({ sender: 'noreply', receiver: { alias: String(user.disp), email: user.email }, - subject: 'Новое уведомление', + subject: 'New notification', head: true, body: noticeTpl({ user, @@ -469,11 +468,9 @@ async function sendUserNotice(userId) { news: newsResult, photos: photosResult, username: String(user.disp), - greeting: 'Уведомление о событиях на PastVu', + greeting: 'Notification about events on PastVu', }), - text: totalNewestComments + - (totalNewestComments === 1 ? ' новый коментарий' : ' новых ' + - (totalNewestComments < 5 ? 'комментария' : 'комментариев')), + text: totalNewestComments + ' new comment' + (totalNewestComments > 1 ? 's' : ''), }); } diff --git a/public/js/globalVM.js b/public/js/globalVM.js index 8a8a71444..6417179c7 100644 --- a/public/js/globalVM.js +++ b/public/js/globalVM.js @@ -68,10 +68,10 @@ define(['jquery', 'Browser', 'Utils', 'underscore', 'Params', 'intl', 'i18n', 'k repository: {}, ranks: { - mec: { src: '/img/rank/bronse.jpg', title: 'Меценат' }, - mec_silv: { src: '/img/rank/silver.jpg', title: 'Серебряный меценат' }, - mec_gold: { src: '/img/rank/gold.jpg', title: 'Золотой меценат' }, - adviser: { src: '/img/rank/adviser.jpg', title: 'Советник' }, + mec: { src: '/img/rank/bronse.jpg', title: 'Maecenas' }, + mec_silv: { src: '/img/rank/silver.jpg', title: 'Silver maecenas' }, + mec_gold: { src: '/img/rank/gold.jpg', title: 'Gold maecenas' }, + adviser: { src: '/img/rank/adviser.jpg', title: 'counselor' }, }, func: { diff --git a/public/js/i18n.js b/public/js/i18n.js index 9518bf094..68e438b11 100644 --- a/public/js/i18n.js +++ b/public/js/i18n.js @@ -8,13 +8,13 @@ define(['knockout', 'knockout.mapping'], function (ko, koMapping) { const i18n = { en: { - login: 'Login', - logout: 'Logout', - register: 'Registration', + login: 'Log In', + logout: 'Log Out', + register: 'Sign Up', mod: 'Moderation', admin: 'Administration', gallery: 'Gallery', - image_upload: 'Upload Image', + image_upload: 'Upload', }, ru: { login: 'Вход', diff --git a/public/js/intl/intl.js b/public/js/intl/intl.js index bf7ba9d02..2f47bd0de 100644 --- a/public/js/intl/intl.js +++ b/public/js/intl/intl.js @@ -6,9 +6,9 @@ define(['Utils'], function () { 'use strict'; - const intlNumFormat = new Intl.NumberFormat('ru-RU').format; - const intlDateFormat = new Intl.DateTimeFormat('ru-RU').format; - const intlDateFullFormat = new Intl.DateTimeFormat('ru-RU', { + const intlNumFormat = new Intl.NumberFormat('en-US').format; + const intlDateFormat = new Intl.DateTimeFormat('en-US').format; + const intlDateFullFormat = new Intl.DateTimeFormat('en-US', { weekday: 'long', day: 'numeric', month: 'long', diff --git a/public/js/lib/Utils.js b/public/js/lib/Utils.js index d2eb9aea0..7fd167635 100644 --- a/public/js/lib/Utils.js +++ b/public/js/lib/Utils.js @@ -554,27 +554,42 @@ define(['jquery', 'underscore', 'underscore.string', 'lib/geocoordsparser', 'lib format: (function () { const dateFormat = (function () { const months = [ - 'января', 'февраля', 'марта', 'апреля', 'мая', 'июня', 'июля', 'августа', 'сентября', 'октября', 'ноября', 'декабря', + 'january', 'february', 'march', 'april', 'may', 'june', 'july', 'august', 'september', 'october', 'november', 'december', ]; const weekDays = [ - 'Воскресенье', 'Понедельник', 'Вторник', 'Среда', 'Четверг', 'Пятница', 'Суббота', + 'Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', ]; const weekDaysIn = [ - 'в воскресенье', 'в понедельник', 'во вторник', 'в среду', 'в четверг', 'в пятницу', 'в субботу', + 'at sunday', 'at monday', 'at tuesday', 'at wednesday', 'at thursday', 'at friday', 'at saturday', ]; function dMMYYYYhhmm(date) { - const hours = date.getHours(); - const mintues = date.getMinutes(); - - return date.getDate() + ' ' + months[date.getMonth()] + ' ' + date.getFullYear() + ', ' + (hours > 9 ? hours : '0' + hours) + ':' + (mintues > 9 ? mintues : '0' + mintues); + return date.getDate() + ' ' + months[date.getMonth()] + ' ' + date.getFullYear() + ', ' + hhmm(date); } function hhmm(date) { - const hours = date.getHours(); + let hours = date.getHours(); const mintues = date.getMinutes(); + let ext; + + if (hours > 12) { + ext = 'PM'; + hours -= 12; + + if (hours < 10) { + hours = '0' + hours; + } else if (hours === 12) { + hours = '12'; + ext = 'AM'; + } + } else if (hours < 12) { + hours = hours < 10 ? '0' + hours : hours; + ext = 'AM'; + } else if (hours === 12) { + ext = 'PM'; + } - return (hours > 9 ? hours : '0' + hours) + ':' + (mintues > 9 ? mintues : '0' + mintues); + return hours + ':' + (mintues > 9 ? mintues : '0' + mintues) + ' ' + ext; } // Возвращает дату относительно переданной в формате "Сегодня в 12:15" @@ -588,10 +603,10 @@ define(['jquery', 'underscore', 'underscore.string', 'lib/geocoordsparser', 'lib if (dateMs < Utils.times.midnight - Utils.times.msDay) { result = weekDays[date.getDay()] + ', ' + dateFormat.hhmm(date); } else { - result = 'Вчера в ' + dateFormat.hhmm(date); + result = 'Yesterday at ' + dateFormat.hhmm(date); } } else { - result = 'Сегодня в ' + dateFormat.hhmm(date); + result = 'Today at ' + dateFormat.hhmm(date); } return result; @@ -607,10 +622,10 @@ define(['jquery', 'underscore', 'underscore.string', 'lib/geocoordsparser', 'lib if (dateMs < Utils.times.midnight - Utils.times.msDay) { result = weekDaysIn[date.getDay()] + ', ' + dateFormat.hhmm(date); } else { - result = 'вчера в ' + dateFormat.hhmm(date); + result = 'yesterday at ' + dateFormat.hhmm(date); } } else { - result = 'сегодня в ' + dateFormat.hhmm(date); + result = 'today at ' + dateFormat.hhmm(date); } return result; diff --git a/public/js/module/admin/conveyer.js b/public/js/module/admin/conveyer.js index dc0cad2a8..8e34f2ed9 100644 --- a/public/js/module/admin/conveyer.js +++ b/public/js/module/admin/conveyer.js @@ -380,7 +380,7 @@ define([ }, series: [ { - name: 'Фотографий в очереди', + name: 'Photos in the queue', data: self.conveyerLengthData, tooltip: { valueDecimals: 0, @@ -394,7 +394,7 @@ define([ }, series: [ { - name: 'Фотографий конвертированно', + name: 'Converted photos', data: self.conveyerConvertData, tooltip: { valueDecimals: 0, @@ -434,7 +434,7 @@ define([ this.exe(true); noties.confirm({ - message: 'Конвейер будет очищен. Подтвердить операцию?', + message: 'The conveyor will be cleared.
Confirm the operation?', onOk: function (confirmer) { confirmer.disable(); diff --git a/public/js/module/admin/region.js b/public/js/module/admin/region.js index c2f9ef2c2..56eddc02e 100644 --- a/public/js/module/admin/region.js +++ b/public/js/module/admin/region.js @@ -10,7 +10,7 @@ define([ ], function (_, $, Utils, socket, P, ko, koMapping, Cliche, globalVM, L, noties, statuses, renderer, pug) { 'use strict'; - const collator = new Intl.Collator('ru-RU', { numeric: true, sensitivity: 'base' }); + const collator = new Intl.Collator('en', { numeric: true, sensitivity: 'base' }); const regionDef = { cid: 0, parents: [], @@ -349,7 +349,7 @@ define([ result.push({ status: status, count: photostat['s' + status] || 0, title: statuses[key].filter_title }); }, []); photostat.icon = 'camera'; - photostat.title = 'Фотографий'; + photostat.title = 'Photos'; photostat.linkprefix = '/ps?f=r!' + region.cid + '_t!1'; this.photostat(photostat); @@ -357,7 +357,7 @@ define([ result.push({ status: status, count: paintstat['s' + status] || 0, title: statuses[key].filter_title }); }, []); paintstat.icon = 'picture'; - paintstat.title = 'Картин'; + paintstat.title = 'Paintings'; paintstat.linkprefix = '/ps?f=r!' + region.cid + '_t!2'; this.paintstat(paintstat); @@ -365,10 +365,10 @@ define([ result.push({ status: status, count: imagestat['s' + status] || 0, title: statuses[key].filter_title }); }, []); imagestat.icon = 'camera'; - imagestat.title = 'Изображений'; + imagestat.title = 'Images'; if (paintstat.all) { - imagestat.alterAll = globalVM.intl.num(imagestat.all) + ' (' + globalVM.intl.num(paintstat.all) + ' картин)'; + imagestat.alterAll = globalVM.intl.num(imagestat.all) + ' (' + globalVM.intl.num(paintstat.all) + ' paintings)'; } imagestat.linkprefix = '/ps?f=r!' + region.cid; @@ -466,7 +466,7 @@ define([ this.centerMarker = L.marker(this.region.center(), { draggable: true, - title: 'Центр региона', + title: 'Center of the region', icon: L.icon({ iconSize: [26, 43], iconAnchor: [13, 36], @@ -631,7 +631,7 @@ define([ if (!saveData.geo) { noties.alert({ - message: 'GeoJSON обязателен!', + message: 'GeoJSON is required!', type: 'warning', timeout: 2000, }); @@ -645,7 +645,7 @@ define([ if (!saveData.title_en) { noties.alert({ - message: 'Нужно заполнить английское название', + message: 'It is necessary to fill in English name', type: 'warning', timeout: 2000, }); @@ -665,7 +665,7 @@ define([ if (!saveData.parent) { noties.alert({ - message: 'Если уровень региона ниже Страны, необходимо указать номер родительского региона!', + message: 'If the level is below the country level, you must specify the id of the parent region!', type: 'warning', timeout: 5000, ok: true, @@ -698,7 +698,7 @@ define([ } if (!error) { - let msg = 'Регион ' + this.region.title_local() + ' успешно ' + (parentIsChanged ? 'перенесён и ' : '') + 'сохранен
'; + let msg = 'Region ' + this.region.title_en() + ' has been successfully ' + (parentIsChanged ? 'transferred and ' : '') + 'saved
'; let geoChangePhotosCount; if (resultStat && Object.keys(resultStat).length) { @@ -706,7 +706,7 @@ define([ geoChangePhotosCount = resultStat.photosCountAfter - resultStat.photosCountBefore; if (geoChangePhotosCount) { - msg += '
' + Math.abs(geoChangePhotosCount) + ' фотографий ' + (geoChangePhotosCount > 0 ? 'добавлено в регион' : 'удалено из региона') + ' вследствии изменения коордиант поолигона.'; + msg += '
' + Math.abs(geoChangePhotosCount) + ' photos are ' + (geoChangePhotosCount > 0 ? 'added to the region' : 'removed from the region') + ' because of polygon coordinates changing.'; } } @@ -714,24 +714,24 @@ define([ geoChangePhotosCount = resultStat.commentsCountAfter - resultStat.commentsCountBefore; if (geoChangePhotosCount) { - msg += '
' + Math.abs(geoChangePhotosCount) + ' комментариев ' + (geoChangePhotosCount > 0 ? 'добавлено в регион' : 'удалено из региона') + ' вследствии переноса фотографий.'; + msg += '
' + Math.abs(geoChangePhotosCount) + ' comments are ' + (geoChangePhotosCount > 0 ? 'added to the region' : 'removed from the region') + ' because of photos transfer.'; } } if (resultStat.affectedPhotos) { - msg += '
' + resultStat.affectedPhotos + ' фотографий переехали по дереву вслед за регионом.'; + msg += '
' + resultStat.affectedPhotos + ' photos have been moved following the region.'; } if (resultStat.affectedComments) { - msg += '
' + resultStat.affectedComments + ' комментариев переехали вслед за своими фотографиями.'; + msg += '
' + resultStat.affectedComments + ' comments have been moved following their photos. '; } if (resultStat.affectedUsers) { - msg += '
У ' + resultStat.affectedUsers + ' пользователей были сокрашены "Мои регионы".'; + msg += '
' + resultStat.affectedUsers + ' users have been reduced in "my regions" count.'; } if (resultStat.affectedMods) { - msg += '
У ' + resultStat.affectedMods + ' модераторов были сокрашены модерируемые регионы.'; + msg += '
' + resultStat.affectedMods + ' moderators have been reduced moderators regions.'; } } @@ -779,76 +779,76 @@ define([ this.exe(true); const cid = this.region.cid(); - const title = this.region.title_local(); + const title = this.region.title_en(); let regionParent; const that = this; const childLenArr = this.childLenArr(); let msg = 'Регион ' + title + ' будет удален
'; if (childLenArr.length) { - msg += '
Также будут удалено ' + + msg += '
Also ' + childLenArr.reduce(function (previousValue, currentValue) { return previousValue + currentValue; - }) + ' дочерних регионов
'; + }) + '
children regions will be removed
'; } - msg += 'Все объекты, входящие в этот регион и в дочерние, '; + msg += 'All objects within the region and it children, '; if (!this.region.parents().length) { - msg += 'будут присвоены Открытому морю
'; + msg += 'will be assigned to the Open sea
'; } else { regionParent = _.last(this.region.parents()); - msg += 'остануться в вышестоящем регионе ' + regionParent.title_local() + '
'; + msg += 'will remain in upper region ' + regionParent.title_en() + '
'; } - msg += '
Это может занять несколько минут. Подтверждаете?
' + - 'Операция продолжит выполняться даже при закрытии браузера'; + msg += '
It may take a few minutes. Confirm?
' + + 'The operation continues to run even if you close your browser'; noties.confirm({ message: msg, - okText: 'Да', + okText: 'Yes', onOk: function (confirmer) { confirmer.close(); noties.confirm({ - message: 'Изменения будут необратимы.
' + - 'Вы действительно хотите удалить регион ' + title + '?', - okText: 'Да', + message: 'The changes will be irreversible.
Are you sure you want to delete the region ' + + '' + title + '?', + okText: 'Yes', onOk: function (confirmer) { confirmer.disable(); socket.run('region.remove', { cid: cid }) .then(function (data) { - msg = 'Регион ' + title + ' успешно удалён
'; + msg = 'Region ' + title + ' removed successfully
'; if (data.affectedPhotos) { msg += '' + data.affectedPhotos + ' ' + - 'фотографий сменили региональную принадлежность.
'; + 'photo have been changed their regions.
'; } if (data.affectedComments) { msg += '' + data.affectedComments + ' ' + - 'комментариев сменили региональную принадлежность вслед за своими фотографиями.
'; + 'comments have been moved following their photos.
'; } if (data.homeAffectedUsers) { - msg += 'У ' + data.homeAffectedUsers + ' ' + - 'пользователей домашние регионы были заменены на ' + - data.homeReplacedWith.title_en + ' (номер ' + data.homeReplacedWith.cid + ').
'; + msg += '' + data.homeAffectedUsers + ' ' + + 'users chenged theire home regions to ' + data.homeReplacedWith.title_en + + ' (id ' + data.homeReplacedWith.cid + ').
'; } if (data.affectedUsers) { - msg += 'У ' + data.affectedUsers + ' ' + - 'пользователей были сокрашены "Мои регионы".
'; + msg += '' + data.affectedUsers + ' ' + + 'users have been reduced in "my regions" count.
'; } if (data.affectedMods) { - msg += 'У ' + data.affectedMods + ' ' + - 'модераторов были сокрашены модерируемые регионы.'; + msg += '' + data.affectedMods + ' ' + + 'moderators have been reduced moderators regions.'; if (data.affectedModsLose) { - msg += 'Из них ' + data.affectedModsLose + ' ' + - 'пользователей лишились роли модератора.'; + msg += '' + data.affectedModsLose + ' ' + + 'of them lost moderation status.'; } msg += '
'; @@ -866,19 +866,19 @@ define([ }) .catch(function (error) { console.error(error); - confirmer.error(error, 'Закрыть', null, function () { + confirmer.error(error, 'Close', null, function () { that.exe(false); }); }); }, - cancelText: 'Нет', + cancelText: 'No', cancelClass: 'btn-success', onCancel: function () { that.exe(false); }, }); }, - cancelText: 'Отмена', + cancelText: 'Cancel', onCancel: function () { that.exe(false); }, @@ -896,28 +896,28 @@ define([ const that = this; const cid = this.region.cid(); - const title = this.region.title_local(); + const title = this.region.title_en(); socket.run('region.recalcStatistics', { cids: [cid] }) .then(function (data) { let msg; if (data.running) { - msg = 'В данный момент статистика пересчитывается по всем регионам'; + msg = 'Statistics is being recalculated for all regions at this moment'; } else { - msg = 'Статистика по региону ' + title + ' пересчитана
'; + msg = 'Statistics for ' + title + ' has been recalculated
'; if (data.valuesChanged) { - msg += '' + globalVM.intl.num(data.valuesChanged) + ' значений было изменено'; + msg += '' + globalVM.intl.num(data.valuesChanged) + ' values have been changed'; } else { - msg += 'Значения не изменились'; + msg += 'Values have not been changed'; } } noties.alert({ message: msg, ok: true, - text: 'Закрыть', + text: 'Close', countdown: 10, onOk: function () { that.getOneRegion(cid, function () { @@ -933,31 +933,31 @@ define([ }, changeParentWarn: function (cb, ctx) { - let msg = 'Вы хотите поменять положение региона в иерархии.'; + let msg = 'You want to change the position of the region in the hierarchy.'; const childLenArr = this.childLenArr(); if (childLenArr.length) { - msg += '
При этом также будут перенесены ' + + msg += '
Also will be moved ' + childLenArr.reduce(function (previousValue, currentValue) { return previousValue + currentValue; - }) + ' дочерних регионов
'; + }) + '
child regions
'; } - msg += '
У пользователей, одновременно подписанных на переносимые регионы и их новые родительские, ' + - 'подписка на переносимые будет удалена, т.к. подписка родительских включает и дочерние регионы. ' + - 'То же касается региональных модераторских прав.'; - msg += '
Это может занять несколько минут. Подтверждаете?
' + - 'Операция продолжит выполняться даже при закрытии браузера'; + msg += '
Users, who signed on moved regions and their new parents, ' + + 'subscription on moved will be removed, because subscription includes parent and child regions. ' + + 'The same applies to regional moderator permissions.'; + msg += '
It may take a few minutes. Confirm?
' + + 'The operation continues to run even if you close your browser'; noties.confirm({ message: msg, - okText: 'Да', + okText: 'Yes', okClass: 'btn-warning', onOk: function (confirmer) { confirmer.disable(); cb.call(ctx, confirmer); }, - cancelText: 'Нет', + cancelText: 'No', cancelClass: 'btn-success', onCancel: function () { cb.call(ctx, false); diff --git a/public/js/module/admin/regionCheck.js b/public/js/module/admin/regionCheck.js index 9e1109fcc..37e11943f 100644 --- a/public/js/module/admin/regionCheck.js +++ b/public/js/module/admin/regionCheck.js @@ -140,7 +140,7 @@ define([ this.goToGeo(geo); } else { noties.alert({ - message: 'Неверный формат', + message: 'Incorrect format', type: 'warning', }); } @@ -159,7 +159,7 @@ define([ this.marker = L.marker(geo, { draggable: true, - title: 'Точка для проверки региона', + title: 'Point for region check', icon: L.icon({ iconSize: [26, 43], iconAnchor: [13, 36], diff --git a/public/js/module/admin/regionFeatureInsert.js b/public/js/module/admin/regionFeatureInsert.js index 1fecc3009..bc9eed905 100644 --- a/public/js/module/admin/regionFeatureInsert.js +++ b/public/js/module/admin/regionFeatureInsert.js @@ -71,7 +71,7 @@ define([ const geoChangePhotosCount = stat.photosCountAfter - stat.photosCountBefore; if (geoChangePhotosCount) { - stats.push('' + globalVM.intl.num(Math.abs(geoChangePhotosCount)) + ' фотографий ' + (geoChangePhotosCount > 0 ? 'добавлено в регион' : 'удалено из региона') + ' вследствии изменения коордиант поолигона.'); + stats.push('' + globalVM.intl.num(Math.abs(geoChangePhotosCount)) + ' photos are ' + (geoChangePhotosCount > 0 ? 'added to the region' : 'removed from the region') + ' because of polygon coordinates changing.'); } } @@ -79,24 +79,24 @@ define([ const geoChangeCommentsCount = stat.commentsCountAfter - stat.commentsCountBefore; if (geoChangeCommentsCount) { - stats.push('' + globalVM.intl.num(Math.abs(geoChangeCommentsCount)) + ' комментариев ' + (geoChangeCommentsCount > 0 ? 'добавлено в регион' : 'удалено из региона') + ' вследствии переноса фотографий.'); + stats.push('' + globalVM.intl.num(Math.abs(geoChangeCommentsCount)) + ' comments are ' + (geoChangeCommentsCount > 0 ? 'added to the region' : 'removed from the region') + ' because of photos transfer.'); } } if (stat.affectedPhotos) { - stats.push('' + globalVM.intl.num(stat.affectedPhotos) + ' фотографий переехали по дереву вслед за регионом.'); + stats.push('' + globalVM.intl.num(stat.affectedPhotos) + ' photos have been moved following the region.'); } if (stat.affectedComments) { - stats.push('' + globalVM.intl.num(stat.affectedComments) + ' комментариев переехали вслед за своими фотографиями.'); + stats.push('' + globalVM.intl.num(stat.affectedComments) + ' comments have been moved following their photos.'); } if (stat.affectedUsers) { - stats.push('У ' + globalVM.intl.num(stat.affectedUsers) + ' пользователей были сокрашены "Мои регионы".'); + stats.push('' + globalVM.intl.num(stat.affectedUsers) + ' users have been reduced in "my regions" count.'); } if (stat.affectedMods) { - stats.push('У ' + globalVM.intl.num(stat.affectedMods) + ' модераторов были сокрашены модерируемые регионы.'); + stats.push('' + globalVM.intl.num(stat.affectedMods) + ' moderators have been reduced moderators regions.'); } } diff --git a/public/js/module/admin/regionList.js b/public/js/module/admin/regionList.js index 937aced6d..3f427cf4e 100644 --- a/public/js/module/admin/regionList.js +++ b/public/js/module/admin/regionList.js @@ -9,7 +9,7 @@ define([ ], function (_, $, Utils, socket, P, ko, Cliche, globalVM, storage, noties, pug) { 'use strict'; - const collator = new Intl.Collator('ru-RU', { numeric: true, sensitivity: 'base' }); + const collator = new Intl.Collator('en', { numeric: true, sensitivity: 'base' }); const months = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December']; return Cliche.extend({ @@ -98,7 +98,7 @@ define([ (function recursiveSort(arr) { arr.sort(function (a, b) { - return sort * collator.compare(a.title_local, b.title_local); + return sort * collator.compare(a.title_en, b.title_en); }); arr = arr(); @@ -121,7 +121,7 @@ define([ //Сортируем массим по уровням и названиям в пределах одного уровня arr.sort(function (a, b) { if (a.parents.length === b.parents.length) { - return collator.compare(a.title_local, b.title_local); + return collator.compare(a.title_en, b.title_en); } return a.parents.length < b.parents.length ? -1 : 1; diff --git a/public/js/module/admin/submenu.js b/public/js/module/admin/submenu.js index 0fd5c786c..a8f0e25dd 100644 --- a/public/js/module/admin/submenu.js +++ b/public/js/module/admin/submenu.js @@ -15,18 +15,18 @@ define(['underscore', 'knockout', 'm/_moduleCliche', 'globalVM', 'text!tpl/admin this.submenus = { index: [ - { name: 'Главная', href: '/admin', section: 'main' }, - { name: 'Новости', href: '/admin/news', section: 'news' }, + { name: 'Main', href: '/admin', section: 'main' }, + { name: 'News', href: '/admin/news', section: 'news' }, ], map: [ - { name: 'Кластеры', href: '/admin/map/cluster', section: 'cluster' }, + { name: 'Clusters', href: '/admin/map/cluster', section: 'cluster' }, ], photo: [ - { name: 'Конвейер конвертаций', href: '/admin/photo/conveyer', section: 'conveyer' }, + { name: 'Conversions conveyor', href: '/admin/photo/conveyer', section: 'conveyer' }, ], region: [ - { name: 'Список и просмотр', href: '/admin/region', section: 'region' }, - { name: 'Проверка по точке', href: '/admin/region/check', section: 'regionCheck' }, + { name: 'List and view', href: '/admin/region', section: 'region' }, + { name: 'Check by point', href: '/admin/region/check', section: 'regionCheck' }, ], }; diff --git a/public/js/module/appAdmin.js b/public/js/module/appAdmin.js index 67d18ca16..a1b343a29 100644 --- a/public/js/module/appAdmin.js +++ b/public/js/module/appAdmin.js @@ -156,7 +156,7 @@ require([ }, }; - moment.locale('ru'); + moment.locale('en'); $('body').append(html); ko.applyBindings(globalVM); diff --git a/public/js/module/appMain.js b/public/js/module/appMain.js index 577c47c53..425a74c6c 100644 --- a/public/js/module/appMain.js +++ b/public/js/module/appMain.js @@ -11,7 +11,7 @@ require([ ], function (domReady, $, Browser, Utils, socket, _, ko, moment, globalVM, P, renderer, router, Photo, User, noties, analytics, html) { 'use strict'; - Utils.title.setPostfix('Фотографии прошлого'); + Utils.title.setPostfix('Retro photos'); const routerDeferred = $.Deferred(); const routerAnatomy = { @@ -177,7 +177,7 @@ require([ }, }; - moment.locale('ru'); + moment.locale('en'); $('body').append(html); ko.applyBindings(globalVM); diff --git a/public/js/module/comment/comments.js b/public/js/module/comment/comments.js index b077a7605..5c61926e5 100644 --- a/public/js/module/comment/comments.js +++ b/public/js/module/comment/comments.js @@ -765,7 +765,7 @@ define([ if ($withContent.length) { noties.alert({ - message: 'У вас есть незавершенный комментарий. Отправьте или отмените его и переходите к новому', + message: 'You have an incomplete comment. Send or cancel it and move on to new', type: 'warning', timeout: 4000, }); @@ -860,7 +860,7 @@ define([ action += '.own'; } - this.reasonSelect(action, 'Причина удаления', function (cancel, reason) { + this.reasonSelect(action, 'Removing reason', function (cancel, reason) { if (cancel) { $('.hlRemove', this.$cmts).removeClass('hlRemove'); @@ -940,7 +940,7 @@ define([ ga('send', 'event', 'comment', 'delete', 'comment delete success', count); noties.alert({ - message: 'Удалено комментариев: ' + count + ', от ' + result.countUsers + ' пользователя(ей)', + message: '' + count + ' comments are removed,
from ' + result.countUsers + ' user(s)', type: 'information', layout: 'topRight', timeout: 5000, @@ -961,10 +961,9 @@ define([ } $('[data-origin="' + cid + '"]', that.$cmts).add($c).addClass('hlRestore'); - noties.confirm({ - message: 'Восстановить комментарий и его потомков, которые были удалены вместе с ним
(подсвечены зеленым)?', - okText: 'Да', + message: 'Restore comment and his children that were deleted along with it
(highlighted in green)?', + okText: 'Yes', okClass: 'btn-success', onOk: function (confirmer) { confirmer.disable(); @@ -1017,7 +1016,7 @@ define([ confirmer.close(); }); }, - cancelText: 'Нет', + cancelText: 'No', cancelClass: 'btn-warning', onCancel: function () { $('.hlRestore', that.$cmts).removeClass('hlRestore'); @@ -1085,7 +1084,7 @@ define([ }); }) .catch(function () { - $('.delico', $c).removeClass('loading').html('Показать'); + $('.delico', $c).removeClass('loading').html('Show'); that.loadingDel = false; }); }, @@ -1120,14 +1119,14 @@ define([ maxWidthRatio: 0.75, animateScale: true, offIcon: { - text: 'Отмена', click: function () { + text: 'Cancel', click: function () { cb.call(ctx, true); this.reasonDestroy(); }, ctx: this, }, btns: [ { - css: 'btn-warning', text: 'Выполнить', glyphicon: 'glyphicon-ok', + css: 'btn-warning', text: 'Execute', glyphicon: 'glyphicon-ok', click: function () { const reason = this.reasonVM.getReason(); @@ -1138,7 +1137,7 @@ define([ }, ctx: this, }, { - css: 'btn-success', text: 'Отмена', + css: 'btn-success', text: 'Cancel', click: function () { cb.call(ctx, true); this.reasonDestroy(); @@ -1390,12 +1389,12 @@ define([ module: 'm/comment/hist', options: { objCid: this.cid, cid: cid, type: this.type }, modal: { - topic: 'История изменений комментария', + topic: 'History of comment changes', animateScale: true, curtainClick: { click: this.closeHistory, ctx: this }, - offIcon: { text: 'Закрыть', click: this.closeHistory, ctx: this }, + offIcon: { text: 'Close', click: this.closeHistory, ctx: this }, btns: [ - { css: 'btn-primary', text: 'Закрыть', click: this.closeHistory, ctx: this }, + { css: 'btn-primary', text: 'Close', click: this.closeHistory, ctx: this }, ], }, callback: function (vm) { @@ -1516,7 +1515,7 @@ define([ this.navScrollCounterOn(); } else { // Если дерево еще скрыто, т.е. receive еще не было, просто пишем сколько новых комментариев ниже - $('.navigator .down', this.$dom).addClass('active').find('.navTxt').attr('title', 'Следующий непрочитанный комментарий').text(this.countNew()); + $('.navigator .down', this.$dom).addClass('active').find('.navTxt').attr('title', 'Next unread comment').text(this.countNew()); this.navScrollCounterOff(); } } else { @@ -1568,11 +1567,11 @@ define([ up.classList[upCount ? 'add' : 'remove']('active'); up.querySelector('.navTxt').innerHTML = upCount ? globalVM.intl.num(upCount) : ''; - up[upCount ? 'setAttribute' : 'removeAttribute']('title', 'Предыдущий непрочитанный комментарий'); + up[upCount ? 'setAttribute' : 'removeAttribute']('title', 'Previous unread comment'); down.classList[downCount ? 'add' : 'remove']('active'); down.querySelector('.navTxt').innerHTML = downCount ? globalVM.intl.num(downCount) : ''; - down[downCount ? 'setAttribute' : 'removeAttribute']('title', 'Следующий непрочитанный комментарий'); + down[downCount ? 'setAttribute' : 'removeAttribute']('title', 'Next unread comment'); }, }); }); diff --git a/public/js/module/comment/hist.js b/public/js/module/comment/hist.js index 9d40a512e..4e4e05b04 100644 --- a/public/js/module/comment/hist.js +++ b/public/js/module/comment/hist.js @@ -8,9 +8,9 @@ define(['underscore', 'Utils', 'socket!', 'Params', 'knockout', 'knockout.mappin let tplHist; const changeFragTexts = { - f1: ' Добавлен фрагмент', - f2: ' Изменен фрагмент', - f3: ' Удален фрагмент', + f1: ' Fragment was added', + f2: ' Fragment was changed', + f3: ' Fragment was removed', }; return Cliche.extend({ diff --git a/public/js/module/common/dummy.js b/public/js/module/common/dummy.js index 121a70704..bdd2aa15b 100644 --- a/public/js/module/common/dummy.js +++ b/public/js/module/common/dummy.js @@ -7,7 +7,7 @@ define(['jquery', 'Utils', 'Params', 'globalVM', 'knockout', 'm/_moduleCliche', return Cliche.extend({ pug: pug, create: function () { - this.dummytext = ko.observable('Заглушка'); + this.dummytext = ko.observable('Dummy'); }, }); }); diff --git a/public/js/module/common/foot.js b/public/js/module/common/foot.js index 42b63f27c..5d7135c0d 100644 --- a/public/js/module/common/foot.js +++ b/public/js/module/common/foot.js @@ -45,13 +45,13 @@ define(['underscore', 'Params', 'knockout', 'm/_moduleCliche', 'globalVM', 'rend { module: 'm/diff/about', modal: { - topic: 'О проекте', + topic: 'About', initWidth: '1000px', //animateScale: true, curtainClick: { click: this.closePopup, ctx: this }, - offIcon: { text: 'Закрыть', click: this.closePopup, ctx: this }, + offIcon: { text: 'Close', click: this.closePopup, ctx: this }, btns: [ - { css: 'btn-primary', text: 'Закрыть', click: this.closePopup, ctx: this }, + { css: 'btn-primary', text: 'Close', click: this.closePopup, ctx: this }, ], }, callback: function (vm) { diff --git a/public/js/module/common/reason.js b/public/js/module/common/reason.js index 4ccf1ed88..f238cea66 100644 --- a/public/js/module/common/reason.js +++ b/public/js/module/common/reason.js @@ -84,7 +84,7 @@ define(['underscore', 'jquery', 'Utils', 'socket!', 'Params', 'globalVM', 'knock const descmax = selected.desc.max || 1000; if (desc.length < descmin || desc.length > descmax) { - this.errMsg('Длина описания должна быть в пределах ' + descmin + ' - ' + descmax + ' символов'); + this.errMsg('Description length must be between ' + descmin + ' and ' + descmax + ' symbols'); return false; } diff --git a/public/js/module/diff/news.js b/public/js/module/diff/news.js index 0a0cbd397..701957f1f 100644 --- a/public/js/module/diff/news.js +++ b/public/js/module/diff/news.js @@ -8,7 +8,7 @@ define(['underscore', 'Utils', 'socket!', 'Params', 'knockout', 'knockout.mappin const newsDefault = { pdate: new Date(), - title: 'Нет заголовка', + title: 'No title', txt: '', ccount: 0, ccount_new: 0, diff --git a/public/js/module/diff/newsList.js b/public/js/module/diff/newsList.js index ad6e726e4..db75e3f05 100644 --- a/public/js/module/diff/newsList.js +++ b/public/js/module/diff/newsList.js @@ -46,7 +46,7 @@ define([ }, routeHandler: function () { this.getAllNews(function (/*data*/) { - Utils.title.setTitle({ title: 'Новости' }); + Utils.title.setTitle({ title: 'News' }); gtag('event', 'page_view'); }); }, diff --git a/public/js/module/main/bottomPanel.js b/public/js/module/main/bottomPanel.js index 65797080c..9ef5e3a9e 100644 --- a/public/js/module/main/bottomPanel.js +++ b/public/js/module/main/bottomPanel.js @@ -7,11 +7,11 @@ define(['underscore', 'Browser', 'Utils', 'socket!', 'Params', 'knockout', 'knoc 'use strict'; const catsObj = { - photosToApprove: { name: 'Ожидают подтверждения', tpl: 'photosTpl' }, - photos: { name: 'Новые фото', tpl: 'photosTpl' }, - photosNoGeo: { name: 'Где это?', tpl: 'photosTpl' }, - ratings: { name: 'Рейтинги', tpl: 'ratingsTpl' }, - stats: { name: 'Статистика', tpl: 'statsTpl' }, + photosToApprove: { name: 'Awaiting confirmation', tpl: 'photosTpl' }, + photos: { name: 'New photos', tpl: 'photosTpl' }, + photosNoGeo: { name: 'Where is it?', tpl: 'photosTpl' }, + ratings: { name: 'Rating', tpl: 'ratingsTpl' }, + stats: { name: 'Statistic', tpl: 'statsTpl' }, }; const cats = [ 'photos', @@ -24,11 +24,11 @@ define(['underscore', 'Browser', 'Utils', 'socket!', 'Params', 'knockout', 'knoc ]; const imgFailTpl = _.template('
${ txt }
'); const declension = { - user: [' пользователь', ' пользователя', ' пользователей'], - reg: [' зарегистрирован', ' зарегистрированых', ' зарегистрированых'], - photo: [' фотография', ' фотографии', ' фотографий'], - comment: [' комментарий', ' комментария', ' комментариев'], - view: [' просмотр', ' просмотра', ' просмотров'], + user: [' user', ' users', ' users'], + reg: [' registerd', ' registerd', ' registerd'], + photo: [' photo', ' photos', ' photos'], + comment: [' comment', ' comments', ' comments'], + view: [' view', ' views', ' views'], }; return Cliche.extend({ @@ -293,9 +293,9 @@ define(['underscore', 'Browser', 'Utils', 'socket!', 'Params', 'knockout', 'knoc if (self.catLoading() === 'stats') { self.stats.all = data.all; self.stats.common = data.common; - self.stats.common.onlineTxt = 'Сейчас на сайте ' + globalVM.intl.num(data.common.onall) + - Utils.format.wordEndOfNum(data.common.onall, declension.user) + - ', из них ' + globalVM.intl.num(data.common.onreg) + Utils.format.wordEndOfNum(data.common.onall, declension.reg); + self.stats.common.onlineTxt = 'Now ' + globalVM.intl.num(data.common.onall) + + declension.user[0] + (data.common.onall > 1 ? 's are' : ' is') + ' online, ' + + data.common.onreg + ' of them are registered'; success = true; } @@ -322,7 +322,7 @@ define(['underscore', 'Browser', 'Utils', 'socket!', 'Params', 'knockout', 'knoc photo.link = '/p/' + photo.cid; if (!photo.title) { - photo.title = 'Без названия'; + photo.title = 'Without title'; } if (numField && numFormat) { @@ -369,17 +369,17 @@ define(['underscore', 'Browser', 'Utils', 'socket!', 'Params', 'knockout', 'knoc if (data.conv) { content = imgFailTpl({ style: 'margin-top:7px;padding-top:20px; background: url(/img/misc/photoConvWhite.png) 50% 0 no-repeat;', - txt: 'Превью уже создается
пожалуйста, обновите позже', + txt: 'Preview is being created
please update later', }); } else if (data.convqueue) { content = imgFailTpl({ style: 'margin-top:7px;', - txt: '
Превью скоро будет создано', + txt: '
Preview will be created soon', }); } else { content = imgFailTpl({ style: 'margin-top:7px;padding-top:25px; background: url(/img/misc/imgw.png) 50% 0 no-repeat;', - txt: 'Превью недоступно', + txt: 'Preview is unavailable', }); } diff --git a/public/js/module/main/mainPage.js b/public/js/module/main/mainPage.js index aea4d4c97..b125edcf6 100644 --- a/public/js/module/main/mainPage.js +++ b/public/js/module/main/mainPage.js @@ -58,7 +58,7 @@ define(['underscore', 'Utils', 'Params', 'knockout', 'knockout.mapping', 'm/_mod this.show(); }, show: function () { - Utils.title.setTitle({ title: 'Главная' }); + Utils.title.setTitle({ title: 'Main' }); this.sizesCalc(); globalVM.func.showContainer(this.$container); this.showing = true; diff --git a/public/js/module/map/map.js b/public/js/module/map/map.js index 1a68b2eb9..64d0c0425 100644 --- a/public/js/module/map/map.js +++ b/public/js/module/map/map.js @@ -170,7 +170,7 @@ define([ selected: ko.observable(false), options: { urlTemplate: 'https://{s}tilecart.kosmosnimki.ru/kosmo/{z}/{x}/{y}.png', - attribution: '© ООО ИТЦ "СКАНЭКС" | © участники сообщества OpenStreetMap', + attribution: '© ScanEx | © OpenStreetMap contributors', updateWhenIdle: false, maxZoom: 18, maxNativeZoom: 17, @@ -182,7 +182,7 @@ define([ selected: ko.observable(false), options: { urlTemplate: 'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', - attribution: '© участники сообщества OpenStreetMap', + attribution: '© OpenStreetMap contributors', updateWhenIdle: false, maxZoom: 20, maxNativeZoom: 19, @@ -197,7 +197,7 @@ define([ updateWhenIdle: false, maxZoom: 19, maxNativeZoom: 18, - attribution: 'OSM Deutsch | © участники сообщества OpenStreetMap', + attribution: 'OSM Deutsch | © OpenStreetMap contributors', }, limitZoom: 18, maxAfter: 'osm.openstreetmap', @@ -211,21 +211,21 @@ define([ updateWhenIdle: false, maxZoom: 19, maxNativeZoom: 18, - attribution: 'OSM Française | © участники сообщества OpenStreetMap', + attribution: 'OSM Française | © OpenStreetMap contributors', }, limitZoom: 18, maxAfter: 'osm.openstreetmap', }, { id: 'opentopomap', - desc: 'Топограф', + desc: 'Topographer', selected: ko.observable(false), options: { urlTemplate: 'https://{s}.tile.opentopomap.org/{z}/{x}/{y}.png', updateWhenIdle: false, maxZoom: 15, maxNativeZoom: 14, - attribution: '© участники сообщества OpenStreetMap | SRTM | Стиль карты: © OpenTopoMap (CC-BY-SA)', + attribution: '© OpenStreetMap contributors | SRTM | Map style: © OpenTopoMap (CC-BY-SA)', }, }, ]), @@ -240,7 +240,7 @@ define([ types: ko.observableArray([ { id: 'scheme', - desc: 'Схема', + desc: 'Scheme', selected: ko.observable(false), options: { type: 'roadmap', @@ -249,7 +249,7 @@ define([ }, { id: 'sat', - desc: 'Спутник', + desc: 'Satellite', selected: ko.observable(false), options: { type: 'satellite', @@ -258,7 +258,7 @@ define([ }, { id: 'hyb', - desc: 'Гибрид', + desc: 'Hybrid', selected: ko.observable(false), options: { type: 'hybrid', @@ -267,7 +267,7 @@ define([ }, { id: 'land', - desc: 'Ландшафт', + desc: 'Terrain', selected: ko.observable(false), options: { type: 'terrain', @@ -281,13 +281,13 @@ define([ if (P.settings.USE_YANDEX_API()) { this.layers.push({ id: 'yandex', - desc: 'Яндекс', + desc: 'Yandex', deps: 'leaflet-extends/L.Yandex', selected: ko.observable(false), types: ko.observableArray([ { id: 'scheme', - desc: 'Схема', + desc: 'Scheme', selected: ko.observable(false), options: { type: 'map', @@ -296,7 +296,7 @@ define([ }, { id: 'sat', - desc: 'Спутник', + desc: 'Satellite', selected: ko.observable(false), options: { type: 'satellite', @@ -305,7 +305,7 @@ define([ }, { id: 'hyb', - desc: 'Гибрид', + desc: 'Hybrid', selected: ko.observable(false), options: { type: 'hybrid', @@ -318,16 +318,16 @@ define([ this.layers.push({ id: 'other', - desc: 'Прочие', + desc: 'Other', selected: ko.observable(false), types: ko.observableArray([ { id: 'esri_satimg', - desc: 'Esri Снимки', + desc: 'Esri', selected: ko.observable(false), options: { urlTemplate: 'https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}', - attribution: '© Esri — Источники: Esri, i-cubed, USDA, USGS, AEX, GeoEye, Getmapping, Aerogrid, IGN, IGP, UPR-EGP, и ГИС сообщество', + attribution: '© Esri — Sources: Esri, i-cubed, USDA, USGS, AEX, GeoEye, Getmapping, Aerogrid, IGN, IGP, UPR-EGP, and the GIS User Community', updateWhenIdle: false, maxZoom: 20, maxNativeZoom: 19, @@ -335,11 +335,11 @@ define([ }, { id: 'mtb', - desc: 'MTB пеш.', + desc: 'MTB', selected: ko.observable(false), options: { urlTemplate: 'https://tile.mtbmap.cz/mtbmap_tiles/{z}/{x}/{y}.png', - attribution: '© участники сообщества OpenStreetMap | mtbmap.cz', + attribution: '© OpenStreetMap contributors | mtbmap.cz', updateWhenIdle: false, maxZoom: 19, maxNativeZoom: 18, @@ -349,11 +349,11 @@ define([ }, { id: 'warfly', - desc: 'Аэрофото ВОВ', + desc: 'WWII Aerial', selected: ko.observable(false), options: { urlTemplate: 'https://hutun.ru/tiles/4/061942/Z{z}/{y}/{x}.jpg', - attribution: 'Немецкая аэрофотосъемка 1939-1943 годов (доступна для отдельных городов) | retromap.ru', + attribution: 'WWII Aerial photos 1939-1943 (coverage is limited to some locations) | retromap.ru', updateWhenIdle: false, minZoom: 9, maxZoom: 19, @@ -916,7 +916,7 @@ define([ const tooltip = $(evt.currentTarget).siblings('.tltp').hide(); Utils.copyTextToClipboard(this.geoInputComputed()); - Utils.flashTooltip(evt.currentTarget, 'Скопировано').then(function () { + Utils.flashTooltip(evt.currentTarget, 'Copied').then(function () { tooltip.show(); }); } diff --git a/public/js/module/map/mapClusterCalc.js b/public/js/module/map/mapClusterCalc.js index a4bcf3393..540aaf0fa 100644 --- a/public/js/module/map/mapClusterCalc.js +++ b/public/js/module/map/mapClusterCalc.js @@ -75,25 +75,25 @@ define([ types: ko.observableArray([ { id: 'scheme', - desc: 'Схема', + desc: 'Scheme', selected: ko.observable(false), params: 'roadmap', }, { id: 'sat', - desc: 'Спутник', + desc: 'Satellite', selected: ko.observable(false), params: 'satellite', }, { id: 'hyb', - desc: 'Гибрид', + desc: 'Hybrid', selected: ko.observable(false), params: 'hybrid', }, { id: 'land', - desc: 'Ландшафт', + desc: 'Terrain', selected: ko.observable(false), params: 'terrain', }, @@ -104,37 +104,37 @@ define([ if (P.settings.USE_YANDEX_API()) { this.layers.push({ id: 'yandex', - desc: 'Яндекс', + desc: 'Yandex', deps: 'leaflet-extends/L.Yandex', selected: ko.observable(false), types: ko.observableArray([ { id: 'scheme', - desc: 'Схема', + desc: 'Scheme', selected: ko.observable(false), params: 'map', }, { id: 'sat', - desc: 'Спутник', + desc: 'Satellite', selected: ko.observable(false), params: 'satellite', }, { id: 'hyb', - desc: 'Гибрид', + desc: 'Hybrid', selected: ko.observable(false), params: 'hybrid', }, { id: 'pub', - desc: 'Народная', + desc: 'Public', selected: ko.observable(false), params: 'publicMap', }, { id: 'pubhyb', - desc: 'Народный гибрид', + desc: 'Public hybrid', selected: ko.observable(false), params: 'publicMapHybrid', }, @@ -285,10 +285,9 @@ define([ const _this = this; noties.confirm({ - message: 'Новые параметры кластера посчитаны для всех ' + arr.length + ' уровней зума.
' + - 'Отправить данные на сервер для формирования новой кластерной сетки всех фотографий?
' + - 'Это может занять несколько минут', - okText: 'Да', + message: 'New cluster parameters is calculated for all ' + arr.length + ' zooms.
' + + 'Send data to server for forming new cluster grid for all photos?
It may takes several minutes', + okText: 'Yes', okClass: 'btn-warning', onOk: function (confirmer) { confirmer.disable(); @@ -296,7 +295,7 @@ define([ socket.run('cluster.recalcAll', { params: arr, conditions: _this.saveParams }, true) .then(function () { if (confirmer) { - confirmer.success('Новая кластерная сетка сформированна', 'Ok', null, function () { + confirmer.success('New cluster grid is complete', 'Ok', null, function () { _this.finish(); }); } @@ -310,9 +309,9 @@ define([ }); confirmer.success( - 'Данные отправлены на сервер для пересчета.
' + - 'Вы можете закрыть этот диалог - данные расчитываются на сервере.
' + - 'Диалог обновится при получении результата расчета с сервера', 'Закрыть', null, function () { + 'Data has been sent to server for calculation.
' + + 'You may close this dialog - grid is being calculated on server-side.
' + + 'This dialog will be updated after receiving result from server', 'Close', null, function () { confirmer = null; _this.finish(); }); diff --git a/public/js/module/photo/fields.js b/public/js/module/photo/fields.js index 50d4435bf..6dc563897 100644 --- a/public/js/module/photo/fields.js +++ b/public/js/module/photo/fields.js @@ -31,54 +31,54 @@ define(['Browser'], function (Browser) { return { getDirIcon: getDirIcon, - s: 'Статус', - y: 'Год', - geo: 'Координаты', - type: 'Тип', - regions: 'Регион', - title: 'Название фотографии', - desc: 'Описание', - source: 'Источник', - author: 'Автор', - address: 'Адрес точки съемки', - dir: 'Направление съемки', + s: 'Status', + y: 'Year', + geo: 'Coordinates', + type: 'Type', + regions: 'Region', + title: 'Photo title', + desc: 'Description', + source: 'Source', + author: 'Author', + address: 'Adress of shooting point', + dir: 'Shooting direction', typeVals: { - 1: 'Фотография', - 2: 'Картина/рисунок', + 1: 'Photograph', + 2: 'Painting', }, types: ['1', '2'], dirVals: { - n: 'Север', - ne: 'Северо-Восток', - e: 'Восток', - se: 'Юго-Восток', - s: 'Юг', - sw: 'Юго-Запад', - w: 'Запад', - nw: 'Северо-Запад', - aero: 'Аэро/Спутник', + n: 'North', + ne: 'Northeast', + e: 'East', + se: 'Southeast', + s: 'South', + sw: 'Southwest', + w: 'West', + nw: 'Northwest', + aero: 'Aero/Satellite', }, dirValsArr: ['w', 'nw', 'n', 'ne', 'e', 'se', 's', 'sw', 'aero'], watersign: { - 'title': 'Подпись на вотермарке', - 'profile': 'Как указано в профиле', - 'individual': 'Индивидуально', - 'option': 'Добавлять подпись на вотермарк', - 'default': 'Настройки системы', - 'text': 'Текст', + 'title': 'Text on picture\'s watermark', + 'profile': 'As specified in profile', + 'individual': 'Individually', + 'option': 'Add text to picture\'s watermark', + 'default': 'System setting', + 'text': 'Text', }, - watersignText: 'Подпись на вотермарке', + watersignText: 'Text on watermark', watersignLength: 65, watersignPattern: /[\w\.,:;\(\)\[\]\\\|/№§©®℗℠™•\?!@#\$%\^&\*\+\-={}"'<>~` ]/g, //eslint-disable-line no-useless-escape downloadOrigin: { - title: 'Скачивание оригинала', - profile: 'Как указано в профиле', - individual: 'Индивидуально', - option: 'Разрешать другим пользователям скачивать оригинал', + title: 'Origin download', + profile: 'As specified in profile', + individual: 'Individually', + option: 'Allow other users to download original', }, painting: { - title: 'Название', + title: 'Title', }, }; }); diff --git a/public/js/module/photo/gallery.js b/public/js/module/photo/gallery.js index 960f7edc6..5142b46fe 100644 --- a/public/js/module/photo/gallery.js +++ b/public/js/module/photo/gallery.js @@ -212,12 +212,12 @@ define([ if (count) { if (this.feed() || this.coin()) { - txt = 'Всего ' + globalVM.intl.num(count) + ' фотографий'; + txt = '' + globalVM.intl.num(count) + ' images total'; } else { - txt = 'Показаны ' + globalVM.intl.num(this.pageFirstItem()) + ' – ' + globalVM.intl.num(this.pageLastItem()) + ' из ' + globalVM.intl.num(count); + txt = '' + globalVM.intl.num(this.pageFirstItem()) + ' – ' + globalVM.intl.num(this.pageLastItem()) + ' of ' + globalVM.intl.num(count) + ' are shown'; } } else { - txt = 'Пока нет ни одной фотографии'; + txt = 'No images found'; } return txt; @@ -325,9 +325,9 @@ define([ if (page === 'feed') { if (this.u) { - Utils.title.setTitle({ pre: preTitle + 'Лента изображений - ' }); + Utils.title.setTitle({ pre: preTitle + 'Images feed - ' }); } else { - Utils.title.setTitle({ title: preTitle + 'Лента всех изображений' }); + Utils.title.setTitle({ title: preTitle + 'Feed of all images' }); } if (!this.coin() && this.page() === 1 && currPhotoLength && currPhotoLength <= this.limit) { @@ -348,7 +348,7 @@ define([ return; } - Utils.title.setTitle({ title: preTitle + 'Случайные изображения' }); + Utils.title.setTitle({ title: preTitle + 'Random images' }); page = 1; this.feed(false); @@ -356,9 +356,9 @@ define([ this.coin(true); } else { if (this.u) { - Utils.title.setTitle({ pre: preTitle + 'Галерея - ' }); + Utils.title.setTitle({ pre: preTitle + 'Gallery - ' }); } else { - Utils.title.setTitle({ title: preTitle + 'Галерея' }); + Utils.title.setTitle({ title: preTitle + 'Gallery' }); } if (!this.coin() && page === 1 && this.page() === 1 && currPhotoLength) { @@ -1318,7 +1318,7 @@ define([ Photo.factory(photo, { type: 'compact', pic: 'h', - customDefaults: { title: 'Без названия' }, + customDefaults: { title: 'Without title' }, can: { 'protected': photo.protected }, }); @@ -1381,16 +1381,16 @@ define([ { module: 'm/user/photoUpload', modal: { - topic: 'Загрузка изображений', + topic: 'Image upload', initWidth: '1000px', offIcon: { - text: 'Отмена', click: function () { + text: 'Cancel', click: function () { this.closeUpload(); }, ctx: this, }, btns: [ { - css: 'btn-success', text: 'Завершить', + css: 'btn-success', text: 'Finish', click: function () { this.uploadVM.createPhotos(function (data) { if (data && !data.error) { @@ -1403,7 +1403,7 @@ define([ }, ctx: this, }, { - css: 'btn-warning', text: 'Отмена', + css: 'btn-warning', text: 'Cancel', click: function () { this.closeUpload(); }, ctx: this, @@ -1481,17 +1481,17 @@ define([ if (data.conv) { content = imgFailTpl({ style: 'margin-top:7px;padding-top:20px; background: url(/img/misc/photoConvWhite.png) 50% 0 no-repeat;', - txt: 'Превью уже создается
пожалуйста, обновите позже', + txt: 'Preview is being created
please update later', }); } else if (data.convqueue) { content = imgFailTpl({ style: 'margin-top:7px;', - txt: '
Превью скоро будет создано
пожалуйста, обновите позже', + txt: '
Preview will be created soon', }); } else { content = imgFailTpl({ style: 'margin-top:7px;padding-top:25px; background: url(/img/misc/imgw.png) 50% 0 no-repeat;', - txt: 'Превью недоступно', + txt: 'Preview is unavailable', }); } @@ -1511,23 +1511,23 @@ define([ selectedInit: this.filter.disp.r(), }, modal: { - topic: 'Выбор регионов для фильтрации', + topic: 'Select regions for filtration', initWidth: '900px', maxWidthRatio: 0.95, fullHeight: true, withScroll: true, - offIcon: { text: 'Отмена', click: this.closeRegionSelect, ctx: this }, + offIcon: { text: 'Cancel', click: this.closeRegionSelect, ctx: this }, btns: [ { css: 'btn-success', - text: 'Применить', + text: 'Apply', glyphicon: 'glyphicon-ok', click: function () { - const regions = this.regselectVM.getSelectedRegions(['cid', 'parents', 'title_local', 'childLen']); + const regions = this.regselectVM.getSelectedRegions(['cid', 'parents', 'title_en', 'childLen']); if (regions.length > 10) { return noties.alert({ - message: 'Допускается выбирать до 10 регионов', + message: 'Allowed to select up to 10 regions', type: 'warning', timeout: 4000, ok: true, @@ -1537,7 +1537,7 @@ define([ this.filter.disp.r(regions.map(function (region) { if (region.parents) { region.parentRegionsArr = this.regselectVM - .getRegionsByCids(region.parents, ['cid', 'parents', 'title_local', 'childLen']) + .getRegionsByCids(region.parents, ['cid', 'parents', 'title_en', 'childLen']) .reverse(); } @@ -1548,7 +1548,7 @@ define([ }, ctx: this, }, - { css: 'btn-warning', text: 'Отмена', click: this.closeRegionSelect, ctx: this }, + { css: 'btn-warning', text: 'Cancel', click: this.closeRegionSelect, ctx: this }, ], }, callback: function (vm) { @@ -1605,23 +1605,23 @@ define([ neverSelectable: topcids, }, modal: { - topic: 'Выбор регионов для исключения из фильтрации', + topic: 'Select regions to exclude from filtration', initWidth: '900px', maxWidthRatio: 0.95, fullHeight: true, withScroll: true, - offIcon: { text: 'Отмена', click: this.closeRegionExcludeSelect, ctx: this }, + offIcon: { text: 'Cancel', click: this.closeRegionExcludeSelect, ctx: this }, btns: [ { css: 'btn-success', - text: 'Применить', + text: 'Apply', glyphicon: 'glyphicon-ok', click: function () { - const regions = this.regselectVM.getSelectedRegions(['cid', 'parents', 'title_local']); + const regions = this.regselectVM.getSelectedRegions(['cid', 'parents', 'title_en']); if (regions.length > 10) { return noties.alert({ - message: 'Допускается выбирать до 10 регионов', + message: 'Allowed to select up to 10 regions', type: 'warning', timeout: 4000, ok: true, @@ -1631,7 +1631,7 @@ define([ this.filter.disp.re(regions.map(function (region) { if (region.parents) { region.parentRegionsArr = this.regselectVM - .getRegionsByCids(region.parents, ['cid', 'parents', 'title_local', 'childLen']) + .getRegionsByCids(region.parents, ['cid', 'parents', 'title_en', 'childLen']) .reverse(); } @@ -1644,7 +1644,7 @@ define([ }, ctx: this, }, - { css: 'btn-warning', text: 'Отмена', click: this.closeRegionExcludeSelect, ctx: this }, + { css: 'btn-warning', text: 'Cancel', click: this.closeRegionExcludeSelect, ctx: this }, ], }, callback: function (vm) { diff --git a/public/js/module/photo/photo.js b/public/js/module/photo/photo.js index 1290bfbce..c98694753 100644 --- a/public/js/module/photo/photo.js +++ b/public/js/module/photo/photo.js @@ -76,7 +76,7 @@ define(['underscore', 'Utils', 'Browser', 'socket!', 'Params', 'knockout', 'knoc } if (this.edit()) { - this.setMessage('Фото в режиме редактирования', 'Внесите необходимую информацию и сохраните изменения', 'warning'); + this.setMessage('Photo in editing mode', 'Put necessary information and save changes', 'warning'); //globalVM.pb.publish('/top/message', // ['Photo is in edit mode. Please fill in the underlying fields and save the changes', 'warn']); } else if (status && status.title) { @@ -192,7 +192,7 @@ define(['underscore', 'Utils', 'Browser', 'socket!', 'Params', 'knockout', 'knoc owner: this, }); - const userInfoTpl = _.template('Добавил${ addEnd } ${ name }, ${ stamp }'); + const userInfoTpl = _.template('Added by ${ name }, ${ stamp }'); this.userInfo = this.co.userInfo = ko.computed(function () { return userInfoTpl( @@ -835,23 +835,23 @@ define(['underscore', 'Utils', 'Browser', 'socket!', 'Params', 'knockout', 'knoc selectedInit: selected, }, modal: { - topic: 'Выбор региона принадлежности для фотографии', + topic: 'Selectin region of photo', initWidth: '900px', maxWidthRatio: 0.95, fullHeight: true, withScroll: true, - offIcon: { text: 'Отмена', click: this.closeRegionSelect, ctx: this }, + offIcon: { text: 'Cancel', click: this.closeRegionSelect, ctx: this }, btns: [ { css: 'btn-success', - text: 'Применить', + text: 'Apply', glyphicon: 'glyphicon-ok', click: function () { - const regions = this.regselectVM.getSelectedRegionsFull(['cid', 'title_local']); + const regions = this.regselectVM.getSelectedRegionsFull(['cid', 'title_en']); if (regions.length > 1) { noties.alert({ - message: 'Допускается выбрать только один регион', + message: 'It\'s allowed to choose only one region', type: 'error', timeout: 2500, }); @@ -864,7 +864,7 @@ define(['underscore', 'Utils', 'Browser', 'socket!', 'Params', 'knockout', 'knoc }, ctx: this, }, - { css: 'btn-warning', text: 'Отмена', click: this.closeRegionSelect, ctx: this }, + { css: 'btn-warning', text: 'Cancel', click: this.closeRegionSelect, ctx: this }, ], }, callback: function (vm) { @@ -914,8 +914,7 @@ define(['underscore', 'Utils', 'Browser', 'socket!', 'Params', 'knockout', 'knoc notifyReady: function () { noties.alert({ - message: 'Чтобы фотография была опубликована, необходимо оповестить об этом модераторов
' + - 'Вы можете сделать это в любое время, нажав кнопку «На публикацию»', + message: 'Moderators must be notified to publish photo
You can do this at any time by pressing the "Publish"', type: 'information', layout: 'topRight', timeout: 6000, @@ -923,8 +922,7 @@ define(['underscore', 'Utils', 'Browser', 'socket!', 'Params', 'knockout', 'knoc }, notifyReconvert: function () { noties.alert({ - message: 'Вы изменили настройки подписи на вотермарке фотографии.
' + - 'Изображение изменится в течении нескольких минут, обновите страницу позже', + message: 'You changed watermark text on photo.
Image will change within a few minutes, refresh the page later', type: 'information', layout: 'topRight', timeout: 5000, @@ -932,17 +930,16 @@ define(['underscore', 'Utils', 'Browser', 'socket!', 'Params', 'knockout', 'knoc }, askForGeo: function (cb, ctx) { noties.alert({ - message: 'Вы не указали точку съемки фотографии на карте и регион, к которому она может принадлежать.

' + - 'Установить точку можно в режиме редактирования, кликнув по карте справа и перемещая появившийся маркер.

' + - 'Без точки на карте фотография попадет в раздел «Где это?». ' + - 'В этом случае, чтобы сообщество в дальнейшем помогло определить координаты, необходимо указать регион, ' + - 'в котором предположительно сделана данная фотография

', + message: 'You have not specified shooting point coordinates on the map and the region to which it may belong.

' + + 'Point can be specified in the edit mode by clicking on the map and moving the marker.

' + + 'Whithout point photo will be published at "Where is it?" secion. ' + + 'In this case you need to specify region, so community may help further coordinates searching.

', type: 'confirm', animation: { open: 'animated fadeIn' }, buttons: [ { addClass: 'btn btn-success margBott', - text: 'Указать координаты', + text: 'Enter coordinates', onClick: function ($noty) { this.edit(true); $noty.close(); @@ -950,7 +947,7 @@ define(['underscore', 'Utils', 'Browser', 'socket!', 'Params', 'knockout', 'knoc }, { addClass: 'btn btn-warning margBott', - text: 'Выбрать регион вручную', + text: 'Select region manually', onClick: function ($noty) { this.edit(true); $noty.close(); @@ -958,7 +955,7 @@ define(['underscore', 'Utils', 'Browser', 'socket!', 'Params', 'knockout', 'knoc }.bind(this), }, { - addClass: 'btn btn-danger margBott', text: 'Отмена', + addClass: 'btn btn-danger margBott', text: 'Cancel', onClick: function ($noty) { if (cb) { cb.call(ctx); @@ -987,14 +984,14 @@ define(['underscore', 'Utils', 'Browser', 'socket!', 'Params', 'knockout', 'knoc maxWidthRatio: 0.75, animateScale: true, offIcon: { - text: 'Отмена', click: function () { + text: 'Cancel', click: function () { cb.call(ctx, true); this.reasonDestroy(); }, ctx: this, }, btns: [ { - css: 'btn-warning', text: 'Выполнить', glyphicon: 'glyphicon-ok', + css: 'btn-warning', text: 'Execute', glyphicon: 'glyphicon-ok', click: function () { const reason = this.reasonVM.getReason(); @@ -1005,7 +1002,7 @@ define(['underscore', 'Utils', 'Browser', 'socket!', 'Params', 'knockout', 'knoc }, ctx: this, }, { - css: 'btn-success', text: 'Отмена', + css: 'btn-success', text: 'Cancel', click: function () { cb.call(ctx, true); this.reasonDestroy(); @@ -1045,14 +1042,14 @@ define(['underscore', 'Utils', 'Browser', 'socket!', 'Params', 'knockout', 'knoc newSince: self.p.vdate(), }, modal: { - topic: 'История изменений изображений', + topic: 'History of image changes', initWidth: '1400px', maxWidthRatio: 0.82, animateScale: true, curtainClick: { click: self.closeHistoryOrShare, ctx: self }, - offIcon: { text: 'Закрыть', click: self.closeHistoryOrShare, ctx: self }, + offIcon: { text: 'Close', click: self.closeHistoryOrShare, ctx: self }, btns: [ - { css: 'btn-primary', text: 'Закрыть', click: self.closeHistoryOrShare, ctx: self }, + { css: 'btn-primary', text: 'Close', click: self.closeHistoryOrShare, ctx: self }, ], }, callback: function (vm) { @@ -1099,7 +1096,7 @@ define(['underscore', 'Utils', 'Browser', 'socket!', 'Params', 'knockout', 'knoc } else if (!_.isEmpty(p.regions())) { // If there in no description, create it as regions names desc = p.regions().reduceRight(function (result, region, index) { - result += region.title_local() + (index ? ', ' : ''); + result += region.title_en() + (index ? ', ' : ''); return result; }, ''); @@ -1117,13 +1114,13 @@ define(['underscore', 'Utils', 'Browser', 'socket!', 'Params', 'knockout', 'knoc linkObject: '/_p/a/' + p.file(), }, modal: { - topic: 'Поделиться изображением', + topic: 'Share this image', initWidth: '500px', animateScale: true, curtainClick: { click: self.closeHistoryOrShare, ctx: self }, - offIcon: { text: 'Закрыть', click: self.closeHistoryOrShare, ctx: self }, + offIcon: { text: 'Close', click: self.closeHistoryOrShare, ctx: self }, btns: [ - { css: 'btn-primary', text: 'Закрыть', click: self.closeHistoryOrShare, ctx: self }, + { css: 'btn-primary', text: 'Close', click: self.closeHistoryOrShare, ctx: self }, ], }, callback: function (vm) { @@ -1250,9 +1247,9 @@ define(['underscore', 'Utils', 'Browser', 'socket!', 'Params', 'knockout', 'knoc } const message = error.message + (customChangedMessage || - '
Посмотреть последнюю версию'); - const okText = proceedText || 'Продолжить операцию'; - const cancelText = 'Отменить операцию'; + '
View the latest version'); + const okText = proceedText || 'Proceed operation'; + const cancelText = 'Cancel operation'; if (error.code === 'PHOTO_ANOTHER_STATUS') { noties.alert({ @@ -1282,7 +1279,7 @@ define(['underscore', 'Utils', 'Browser', 'socket!', 'Params', 'knockout', 'knoc } if (confirmer) { - confirmer.error(error, 'Закрыть', 4000, function () { + confirmer.error(error, 'Close', 4000, function () { self.exe(false); }); } else { @@ -1429,12 +1426,12 @@ define(['underscore', 'Utils', 'Browser', 'socket!', 'Params', 'knockout', 'knoc } const params = { cid: cid, cdate: p.cdate(), s: p.s(), changes: changes }; - const changedMessage = '
В случае продолжения сохранения, ваши изменения заменят более ранние' + - '
Посмотреть историю изменений' + - '
Открыть последнюю версию'; + const changedMessage = '
If you continue to save, your changes will overwrite the earlier' + + '
Show history of changes' + + '
Open last version'; self.tryOperation({ - proceedText: 'Продолжить сохранение', customChangedMessage: changedMessage, + proceedText: 'Proceed saving', customChangedMessage: changedMessage, requestCreater: function (ignoreChange) { return socket.run('photo.save', _.assign({ ignoreChange: ignoreChange }, params)) .then(function (data) { @@ -1473,9 +1470,9 @@ define(['underscore', 'Utils', 'Browser', 'socket!', 'Params', 'knockout', 'knoc self.exe(true); noties.confirm({ - message: 'Фотография будет перемещена в корзину и не попадет в очередь на публикацию
Подтвердить операцию?', - okText: 'Да', - cancelText: 'Нет', + message: 'The photo will be moved to the Trash, and misses the turn to the publication
Confirm the operation?', + okText: 'Yes', + cancelText: 'No', onOk: function (initConfirmer) { initConfirmer.disable(); @@ -1483,7 +1480,7 @@ define(['underscore', 'Utils', 'Browser', 'socket!', 'Params', 'knockout', 'knoc const params = { cid: p.cid(), cdate: p.cdate(), s: p.s() }; self.tryOperation({ - proceedText: 'Продолжить отзыв', confirmer: initConfirmer, + proceedText: 'Proceed ', confirmer: initConfirmer, requestCreater: function (ignoreChange) { return socket.run('photo.revoke', _.assign({ ignoreChange: ignoreChange }, params)).then(function (data) { self.rechargeData(data.photo, data.can); @@ -1519,7 +1516,7 @@ define(['underscore', 'Utils', 'Browser', 'socket!', 'Params', 'knockout', 'knoc const params = { cid: p.cid(), cdate: p.cdate(), s: p.s() }; self.tryOperation({ - proceedText: 'Продолжить отправку', + proceedText: 'Proceed sending', requestCreater: function (ignoreChange) { return socket.run('photo.ready', _.assign({ ignoreChange: ignoreChange }, params)).then(function (data) { self.rechargeData(data.photo, data.can); @@ -1542,7 +1539,7 @@ define(['underscore', 'Utils', 'Browser', 'socket!', 'Params', 'knockout', 'knoc } self.exe(true); - self.reasonSelect('photo.revision', 'Причина возврата', function (cancel, reason) { + self.reasonSelect('photo.revision', 'Reason for revision', function (cancel, reason) { if (cancel) { self.exe(false); @@ -1553,7 +1550,7 @@ define(['underscore', 'Utils', 'Browser', 'socket!', 'Params', 'knockout', 'knoc const params = { cid: p.cid(), cdate: p.cdate(), s: p.s(), reason: reason }; self.tryOperation({ - proceedText: 'Продолжить операцию возврата', + proceedText: 'Continue', requestCreater: function (ignoreChange) { return socket.run('photo.toRevision', _.assign({ ignoreChange: ignoreChange }, params)).then(function (data) { self.rechargeData(data.photo, data.can); @@ -1577,7 +1574,7 @@ define(['underscore', 'Utils', 'Browser', 'socket!', 'Params', 'knockout', 'knoc } self.exe(true); - self.reasonSelect('photo.reject', 'Причина отклонения', function (cancel, reason) { + self.reasonSelect('photo.reject', 'Reason of rejection', function (cancel, reason) { if (cancel) { return self.exe(false); } @@ -1586,7 +1583,7 @@ define(['underscore', 'Utils', 'Browser', 'socket!', 'Params', 'knockout', 'knoc const params = { cid: p.cid(), cdate: p.cdate(), s: p.s(), reason: reason }; self.tryOperation({ - proceedText: 'Продолжить отклонение', + proceedText: 'Proceed rejection', requestCreater: function (ignoreChange) { return socket.run('photo.reject', _.assign({ ignoreChange: ignoreChange }, params)).then(function (data) { self.rechargeData(data.photo, data.can); @@ -1610,7 +1607,7 @@ define(['underscore', 'Utils', 'Browser', 'socket!', 'Params', 'knockout', 'knoc } self.exe(true); - self.reasonSelect('photo.rereject', 'Причина восстановления', function (cancel, reason) { + self.reasonSelect('photo.rereject', 'Reason of restoring', function (cancel, reason) { if (cancel) { return self.exe(false); } @@ -1619,7 +1616,7 @@ define(['underscore', 'Utils', 'Browser', 'socket!', 'Params', 'knockout', 'knoc const params = { cid: p.cid(), cdate: p.cdate(), s: p.s(), reason: reason }; self.tryOperation({ - proceedText: 'Продолжить восстановление', + proceedText: 'Proceed restoring', requestCreater: function (ignoreChange) { return socket.run('photo.rereject', _.assign({ ignoreChange: ignoreChange }, params)).then(function (data) { self.rechargeData(data.photo, data.can); @@ -1646,7 +1643,7 @@ define(['underscore', 'Utils', 'Browser', 'socket!', 'Params', 'knockout', 'knoc const params = { cid: p.cid(), cdate: p.cdate(), s: p.s() }; self.tryOperation({ - proceedText: 'Продолжить публикацию', + proceedText: 'Proceed publishing', requestCreater: function (ignoreChange) { return socket.run('photo.approve', _.assign({ ignoreChange: ignoreChange }, params)).then(function (data) { self.rechargeData(data.photo, data.can); @@ -1673,7 +1670,7 @@ define(['underscore', 'Utils', 'Browser', 'socket!', 'Params', 'knockout', 'knoc self.exe(true); if (disable) { - self.reasonSelect('photo.deactivate', 'Причина деактивации', function (cancel, reason) { + self.reasonSelect('photo.deactivate', 'Reason of deactivaion', function (cancel, reason) { if (cancel) { self.exe(false); } else { @@ -1718,7 +1715,7 @@ define(['underscore', 'Utils', 'Browser', 'socket!', 'Params', 'knockout', 'knoc } self.exe(true); - self.reasonSelect('photo.remove', 'Причина удаления', function (cancel, reason) { + self.reasonSelect('photo.remove', 'Reason of removing', function (cancel, reason) { if (cancel) { return self.exe(false); } @@ -1727,7 +1724,7 @@ define(['underscore', 'Utils', 'Browser', 'socket!', 'Params', 'knockout', 'knoc const params = { cid: p.cid(), cdate: p.cdate(), s: p.s(), reason: reason }; self.tryOperation({ - proceedText: 'Продолжить удаление', + proceedText: 'Proceed removing', requestCreater: function (ignoreChange) { return socket.run('photo.remove', _.assign({ ignoreChange: ignoreChange }, params)).then(function (data) { self.rechargeData(data.photo, data.can); @@ -1738,9 +1735,9 @@ define(['underscore', 'Utils', 'Browser', 'socket!', 'Params', 'knockout', 'knoc ga('send', 'event', 'photo', 'delete', 'photo delete ' + (result.error ? 'error' : 'success')); noties.alert({ - message: 'Фотография удалена', + message: 'Photo has been removed', ok: true, - text: 'Завершить', + text: 'Finish', countdown: 5, onOk: function () { globalVM.router.navigate('/u/' + p.user.login() + '/photo'); @@ -1760,7 +1757,7 @@ define(['underscore', 'Utils', 'Browser', 'socket!', 'Params', 'knockout', 'knoc } self.exe(true); - self.reasonSelect('photo.restore', 'Причина восстановления', function (cancel, reason) { + self.reasonSelect('photo.restore', 'Reason of restoration', function (cancel, reason) { if (cancel) { return self.exe(false); } @@ -1769,7 +1766,7 @@ define(['underscore', 'Utils', 'Browser', 'socket!', 'Params', 'knockout', 'knoc const params = { cid: p.cid(), cdate: p.cdate(), s: p.s(), reason: reason }; self.tryOperation({ - proceedText: 'Продолжить восстановление', + proceedText: 'Proceed restoration', requestCreater: function (ignoreChange) { return socket.run('photo.restore', _.assign({ ignoreChange: ignoreChange }, params)).then(function (data) { self.rechargeData(data.photo, data.can); diff --git a/public/js/module/photo/status.js b/public/js/module/photo/status.js index ef82d80ea..3df215879 100644 --- a/public/js/module/photo/status.js +++ b/public/js/module/photo/status.js @@ -9,11 +9,11 @@ define(['underscore'], function (_) { const statuses = { NEW: { // Новое num: 0, - title: 'Новая фотография. Должна быть заполнена и отправлена на премодерацию для публикации', - title_owner: 'Новая фотография. Заполните необходимую информацию и отправьте на премодерацию для публикации', - filter_title: 'Новые', - action: 'Загружена пользователем', - tip: 'Новая загруженная фотография', + title: 'New photo. Must be filled and sended to premoderation for further publishing', + title_owner: 'New photo. Fill necessary information and send it to premoderation for further publishing', + filter_title: 'New', + action: 'Uploaded by user', + tip: 'New uploaded photo', icon: 'glyphicon-asterisk', icon_history: 'glyphicon-cloud-upload', label: 'success', @@ -21,71 +21,71 @@ define(['underscore'], function (_) { }, REVISION: { // На доработке num: 1, - title: 'Информация о фотографии должна быть доработана по требованию модератора', - title_owner: 'Вам необходимо доработать информацию о фотографии согласно требованиям модератора и снова отправить на публикацию', - filter_title: 'На доработке', - action: 'Отправлена на доработку', - tip: 'На доработке', + title: 'Photo information should be modified by moderator\'s request', + title_owner: 'You ought to modify onformation about the photo as required by the moderator and then send for publication again', + filter_title: 'On revision', + action: 'Returned for revision', + tip: 'On revision', icon: 'glyphicon-repeat', label: 'warning', color: '#e99100', }, READY: { // Ожидает публикации num: 2, - title: 'Фотография находится на премодерации в ожидании публикации', - tip: 'Готово к публикации', - action: 'Отправлена на премодерацию для публикации', - filter_title: 'Готовые', + title: 'Photo is on the premoderation in anticipation of the publication', + tip: 'Ready to publish', + action: 'Sent to premoderation for publishing', + filter_title: 'Ready', icon: 'glyphicon-flag', label: 'success', color: '#5FA803', }, REVOKE: { // Отозвано владельцем num: 3, - title: 'Фотография отозвана загрузившим пользователем до публикации', - title_owner: 'Вы отозвали фотографию', - filter_title: 'Отозванные', - action: 'Отозвана пользователем', - tip: 'Отозвана', + title: 'Photo is revoked by user before publishing', + title_owner: 'You revoked this photo', + filter_title: 'Revoked', + action: 'Revoked by user', + tip: 'Revoked', icon: 'glyphicon-remove-circle', label: 'default', color: '#999', }, REJECT: { // Отклонено num: 4, - title: 'Фотография отклонена модератором', - filter_title: 'Отклоненные', - action: 'Отклонена', - tip: 'Отклонена', + title: 'Photo is reject by the moderator', + filter_title: 'Reject', + action: 'Rejected', + tip: 'Rejected', icon: 'glyphicon-ban-circle', label: 'danger', color: '#c60c1a', }, PUBLIC: { // Опубликованное num: 5, - filter_title: 'Публичные', - action: 'Опубликована', + filter_title: 'Public', + action: 'Published', icon_history: 'glyphicon-globe', color: '#0a6d04', }, DEACTIVATE: { // Деактивировано num: 7, - title: 'Фотография деактивирована', - title_owner: 'Ваша фотография деактивирована. Только вы и модераторы можете видеть изображение и редактировать страницу', - filter_title: 'Неактивные', - action: 'Деактивирована', - tip: 'Фотография неактивна', + title: 'Photo is deactivated', + title_owner: 'Your photo is deactivated. Only you and moderators can see its image and edit this page', + filter_title: 'Inactive', + action: 'Deactivated', + tip: 'Photo is inactive', icon: 'glyphicon-lock', label: 'warning', color: '#e99100', }, REMOVE: { // Удалено num: 9, - title: 'Фотография удалена', - title_owner: 'Ваша фотография удалена.
Только вы можете видеть изображение и только администрация может редактировать информацию на этой странице', - filter_title: 'Удаленные', - action: 'Удалена', - tip: 'Фотография удалена', + title: 'Photo is removed', + title_owner: 'Your photo has been removed.
Only you can see its image and only admin can edit this page', + filter_title: 'Removed', + action: 'Removed', + tip: 'Photo is removed', icon: 'glyphicon-trash', label: 'danger', color: '#c60c1a', diff --git a/public/js/module/region/select.js b/public/js/module/region/select.js index b94e9de0a..fb910cb45 100644 --- a/public/js/module/region/select.js +++ b/public/js/module/region/select.js @@ -10,7 +10,7 @@ define([ ], function (_, $, Utils, socket, P, ko, koMapping, Cliche, globalVM, storage, noties, pug) { 'use strict'; - const collator = new Intl.Collator('ru-RU', { numeric: true, sensitivity: 'base' }); + const collator = new Intl.Collator('en', { numeric: true, sensitivity: 'base' }); const $window = $(window); let cache = null; @@ -43,7 +43,7 @@ define([ if (this.selectedInit && this.selectedInit.length) { this.selectedInit.forEach(function (region) { this.selectedInitHash[region.cid] = region; - this.selectedInitTkns.push({ cid: region.cid, value: region.title_local }); + this.selectedInitTkns.push({ cid: region.cid, value: region.title_en }); }, this); } @@ -331,7 +331,7 @@ define([ } } } else { - $(e.relatedTarget).addClass('invalid').attr('title', 'Нет такого региона'); + $(e.relatedTarget).addClass('invalid').attr('title', 'No such region'); } }, //Событие удаления токена непосредственно из поля @@ -363,7 +363,7 @@ define([ if (this.checkBranchSelected(region)) { noties.alert({ - message: 'Нельзя одновременно выбирать родительский и дочерний регионы', + message: 'You can not choose the parent and child regions simultaneously', type: 'warning', timeout: 4000, ok: true, @@ -388,7 +388,7 @@ define([ if (add) { if (this.selectRegion(region)) { - tkn.tokenfield('createToken', { cid: region.cid, value: region.title_local }); + tkn.tokenfield('createToken', { cid: region.cid, value: region.title_en }); } } else { region.selected(false); @@ -491,8 +491,8 @@ define([ cid = region.cid; this.regionsTypehead.push({ cid: cid, - value: region.title_local, - parentTitle: region.parent && region.parent.title_local, + value: region.title_en, + parentTitle: region.parent && region.parent.title_en, tokens: [String(cid), region.title_local, region.title_en], }); @@ -585,7 +585,7 @@ define([ break; case 'alphabet': default: - field = 'title_local'; + field = 'title_en'; } return (function recursiveSort(arr) { @@ -622,7 +622,7 @@ define([ // If values are equal (exists or not) if (sortBy !== 'alphabet') { // If it is not alphabetical order, order by title - return collator.compare(a.title_local, b.title_local); + return collator.compare(a.title_en, b.title_en); } // Otherwise don't sort diff --git a/public/js/module/user/brief.js b/public/js/module/user/brief.js index 695f454f5..0a3d203ba 100644 --- a/public/js/module/user/brief.js +++ b/public/js/module/user/brief.js @@ -10,11 +10,11 @@ define([ 'use strict'; const mess = { - ftype: 'Тип файла не соответствует правилам', - fmax: 'Файл больше разрешенного размера', - fmin: 'Файл слишком мал', - fpx: 'Согласно правилам, размер изображения должен быть не менее 100px по каждой из сторон', - finvalid: 'Файл не прошел валидацию', //Сообщение по умолчанию для валидации + ftype: 'File type does not correspond site rules', + fmax: 'File is bigger then allowed', + fmin: 'File is too small', + fpx: 'According the rules, image size must be at least 100px for each sides', + finvalid: 'The file has not passed validation', //Сообщение по умолчанию для валидации }; return Cliche.extend({ @@ -171,7 +171,7 @@ define([ if (receivedFile && receivedFile.file) { if (receivedFile.error) { noties.error({ - message: mess[receivedFile.error] || mess.finvalid || 'Ошибка загрузки аватары', + message: mess[receivedFile.error] || mess.finvalid || 'Failed to load avatar', }); this.avaexe(false); ga('send', 'event', 'avatar', 'upload', 'avatar upload error'); @@ -205,7 +205,7 @@ define([ }, avaFail: function (e, data) { noties.error({ - message: data && data.message || 'Ошибка загрузки аватары', + message: data && data.message || 'Failed to load avatar', }); this.avaexe(false); }, diff --git a/public/js/module/user/comments.js b/public/js/module/user/comments.js index 1e5c791df..45e829255 100644 --- a/public/js/module/user/comments.js +++ b/public/js/module/user/comments.js @@ -87,9 +87,9 @@ define(['underscore', 'Utils', 'socket!', 'Params', 'knockout', 'knockout.mappin let txt = ''; if (count) { - txt = 'Показаны ' + globalVM.intl.num(this.pageFirstItem()) + ' – ' + globalVM.intl.num(this.pageLastItem()) + ' из ' + globalVM.intl.num(count); + txt = '' + globalVM.intl.num(this.pageFirstItem()) + ' – ' + globalVM.intl.num(this.pageLastItem()) + ' of ' + globalVM.intl.num(count) + ' are shown'; } else { - txt = 'Пользователь пока не оставил комментариев в данной категории'; + txt = 'User still has no comments in this category'; } return txt; @@ -284,12 +284,12 @@ define(['underscore', 'Utils', 'socket!', 'Params', 'knockout', 'knockout.mappin { module: 'm/comment/hist', modal: { - topic: 'История изменений комментария', + topic: 'History of comment\'s changes', animateScale: true, curtainClick: { click: this.closeHistory, ctx: this }, - offIcon: { text: 'Закрыть', click: this.closeHistory, ctx: this }, + offIcon: { text: 'Close', click: this.closeHistory, ctx: this }, btns: [ - { css: 'btn-primary', text: 'Закрыть', click: this.closeHistory, ctx: this }, + { css: 'btn-primary', text: 'Close', click: this.closeHistory, ctx: this }, ], }, options: { objCid: objCid, cid: cid, type: this.type() }, diff --git a/public/js/module/user/manage.js b/public/js/module/user/manage.js index 2db21f5e5..ae7985751 100644 --- a/public/js/module/user/manage.js +++ b/public/js/module/user/manage.js @@ -12,10 +12,10 @@ define([ } const ranksLang = { - mec: 'Меценат', - mec_silv: 'Серебряный меценат', - mec_gold: 'Золотой меценат', - adviser: 'Советник', + mec: 'Maecenas', + mec_silv: 'Silver maecenas', + mec_gold: 'Gold maecenas', + adviser: 'Counselor', }; return Cliche.extend({ @@ -37,10 +37,10 @@ define([ this.role = ko.observable(String(this.u_origin.role)); this.roles = [ - { cat: 'reg', name: 'Обычный пользователь' }, - { cat: 'mod', name: 'Модератор' }, - { cat: 'adm', name: 'Администратор' }, - { cat: 'sadm', name: 'Суперадминистратор' }, + { cat: 'reg', name: 'Regular user' }, + { cat: 'mod', name: 'Moderator' }, + { cat: 'adm', name: 'Administrator' }, + { cat: 'sadm', name: 'Superadministrator' }, ]; this.roleCategory = ko.computed({ read: function () { @@ -87,7 +87,7 @@ define([ this.photoNewCan = ko.observable(0); this.photoNewLimit = ko.observable(null); - this.photoNewLimitOrigin = ko.observable('Авто'); + this.photoNewLimitOrigin = ko.observable('Auto'); this.photoNewLimitOption = ko.computed({ read: function () { return _.isString(that.photoNewLimit()) ? 'manual' : 'auto'; @@ -148,7 +148,7 @@ define([ this.photoNewLimitOrigin(this.photoNewLimit()); } else { this.photoNewLimit(null); - this.photoNewLimitOrigin('Авто'); + this.photoNewLimitOrigin('Auto'); } this.photoNewCan(info.canPhotoNew || 0); @@ -200,21 +200,21 @@ define([ selectedInit: this.regions(), }, modal: { - topic: 'Изменение списка регионов для модерирования', + topic: 'Change the list of regions for moderation', initWidth: '900px', maxWidthRatio: 0.95, fullHeight: true, withScroll: true, - offIcon: { text: 'Отмена', click: this.closeRegionSelect, ctx: this }, + offIcon: { text: 'Cancel', click: this.closeRegionSelect, ctx: this }, btns: [ { - css: 'btn-success', text: 'Применить', glyphicon: 'glyphicon-ok', + css: 'btn-success', text: 'Apply', glyphicon: 'glyphicon-ok', click: function () { - const regions = this.regselectVM.getSelectedRegions(['cid', 'title_local']); + const regions = this.regselectVM.getSelectedRegions(['cid', 'title_en']); if (regions.length > 20) { return noties.alert({ - message: 'Допускается выбирать до 20 регионов', + message: 'Allowed to select up to 20 regions', type: 'warning', timeout: 3000, }); @@ -225,7 +225,7 @@ define([ }, ctx: this, }, - { css: 'btn-warning', text: 'Отмена', click: this.closeRegionSelect, ctx: this }, + { css: 'btn-warning', text: 'Cancel', click: this.closeRegionSelect, ctx: this }, ], }, callback: function (vm) { diff --git a/public/js/module/user/photoUpload.js b/public/js/module/user/photoUpload.js index 9097af4b2..57ee4cb9b 100644 --- a/public/js/module/user/photoUpload.js +++ b/public/js/module/user/photoUpload.js @@ -7,14 +7,14 @@ define(['underscore', 'Browser', 'Utils', 'socket!', 'Params', 'knockout', 'knoc 'use strict'; const mess = { - fsuccess: 'Файл успешно загружен', - fcount: 'Превышено разрешенное количество файлов', - - ftype: 'Тип файла не соответствует Правилам', - fmax: 'Файл больше разрешенного размера', - fmin: 'Файл слишком мал', - fpx: 'Согласно Правилам, размер изображения должен быть не менее 350px по меньшей стороне и не менее 700px по большей стороне', - finvalid: 'Файл не прошел валидацию', //Сообщение по умолчанию для валидации + fsuccess: 'File has been successfully uploaded', + fcount: 'Allowed count of files exceeded', + + ftype: 'File type does not correspond to the Rules', + fmax: 'File is bigger then allowed', + fmin: 'File is too small', + fpx: 'According the rules, image size must be at least 350px on the smaller side and 700 on the larger side', + finvalid: 'The file has not passed validation', //Сообщение по умолчанию для валидации }; return Cliche.extend({ @@ -54,9 +54,9 @@ define(['underscore', 'Browser', 'Utils', 'socket!', 'Params', 'knockout', 'knoc this.canCount(this.canCountTotal); if (!this.canCount()) { - this.toptext('У вас нет свободных лимитов для загрузки файлов, так как вы имеете ' + this.u.pfcount() + ' неподтвержденных модератором фотографий. Это максимально разрешенное количество, установленное для вашего профиля.'); + this.toptext('You are out of limits for uploading files, because you have ' + this.u.pfcount() + ' unconfirmed images by moderator. It is maximum value for your profile type.'); } else { - this.toptext('Выберите файлы, нажав на кнопку добавления' + (this.filereader() ? ' или перетащив их в пунктирную область' : '')); + this.toptext('Select files by pushing add button' + (this.filereader() ? ' or draging them inside dashed area' : '')); this.canLoad(true); this.fileOptions = { @@ -82,7 +82,7 @@ define(['underscore', 'Browser', 'Utils', 'socket!', 'Params', 'knockout', 'knoc }, this); } else { this.toptext( - this.auth.iAm.nophotoupload() ? 'У вас нет прав на загрузку фотографий' : 'Вы не авторизованы для загрузки фотографий' + this.auth.iAm.nophotoupload() ? "You don't have rights for uploading photos" : 'You are not authorized for uploading photos' ); ko.applyBindings(globalVM, this.$dom[0]); this.show(); @@ -256,7 +256,7 @@ define(['underscore', 'Browser', 'Utils', 'socket!', 'Params', 'knockout', 'knoc data.files.forEach(function (file) { file.ext.uploading(true); file.ext.uploaded(false); - this.setMessage(file, 'Пожалуйста подождите. Загрузка..', 'muted'); //Please wait. Loading.. + this.setMessage(file, 'Wait please. Loading..', 'muted'); //Please wait. Loading.. }, this); }, onFileSend: function (e, data) { @@ -368,7 +368,7 @@ define(['underscore', 'Browser', 'Utils', 'socket!', 'Params', 'knockout', 'knoc const that = this; const options = this.fileOptions; - this.setMessage(file, 'Подготовка файла..', 'muted'); + this.setMessage(file, 'Preparing file..', 'muted'); loadImage( file, function (img) { diff --git a/public/js/module/user/settings.js b/public/js/module/user/settings.js index 7bf95eb34..d6b61361c 100644 --- a/public/js/module/user/settings.js +++ b/public/js/module/user/settings.js @@ -219,8 +219,8 @@ define([ const warning = !result.updated; noties.alert({ - message: warning ? 'Ни одной фотографии не отправлено на конвертацию' : - result.updated + ' фотографий отправлено на повторную конвертацию', + message: warning ? 'No photos are sent for conversion' : + result.updated + ' photos has been sent to the re-conversion', type: warning ? 'warning' : 'success', layout: 'topRight', timeout: 4000, @@ -244,18 +244,18 @@ define([ } noties.confirm({ - message: 'Вы уверены что хотите сбросить индивидуальные настройки подписи в фотографиях' + - (region ? ' указанного региона' : '') + '?', - okText: 'Да, сбросить', - cancelText: 'Отменить', + message: 'Are you sure you want to reset individual watermark settings on photos' + + (region ? ' in specified region' : '') + '?', + okText: 'Yes, reset', + cancelText: 'Cancel', onOk: function (confirmer) { socket.run('photo.convertByUser', { login: self.u.login(), r: region, resetIndividual: true }, true) .then(function (result) { const warning = !result.updated; noties.alert({ - message: warning ? 'Не найдено ни одной фотографии с индивидуальными настройками подписи' : - 'У ' + result.updated + ' фотографий сброшены индивидуальные настройки подписи и они отправлены на повторную конвертацию', + message: warning ? 'There is no photos with custom watermark' : + 'Individual settings have been reset for ' + result.updated + ' photos and they were send to reconvert', type: warning ? 'warning' : 'success', layout: 'topRight', timeout: 4000, @@ -288,18 +288,18 @@ define([ } noties.confirm({ - message: 'Вы уверены что хотите сбросить индивидуальные настройки скачивания оргиналов фотографий' + - (region ? ' указанного региона' : '') + '?', - okText: 'Да, сбросить', - cancelText: 'Отменить', + message: 'Are you sure you want to reset individual download settings of photos' + + (region ? ' in specified region' : '') + '?', + okText: 'Yes, reset', + cancelText: 'Cancel', onOk: function (confirmer) { socket.run('photo.resetIndividualDownloadOrigin', { login: self.u.login(), r: region }, true) .then(function (result) { const warning = !result.updated; noties.alert({ - message: warning ? 'Не найдено ни одной фотографии с индивидуальными настройками скачивания' : - 'У ' + result.updated + ' фотографий сброшены индивидуальные настройки скачивания', + message: warning ? 'There is no photos with individual download settings' : + 'Individual download settings have been reset at ' + result.updated + ' photos', type: warning ? 'warning' : 'success', layout: 'topRight', timeout: 4000, @@ -451,16 +451,16 @@ define([ }, regionHomeSelect: function () { if (!this.regHomeselectVM) { - this.regionSelect([koMapping.toJS(this.u.regionHome)], 1, 1, 'Выбор домашнего региона', + this.regionSelect([koMapping.toJS(this.u.regionHome)], 1, 1, 'Home region selection', function (vm) { this.regHomeselectVM = vm; }, function () { - const regions = this.regHomeselectVM.getSelectedRegions(['cid', 'title_local']); + const regions = this.regHomeselectVM.getSelectedRegions(['cid', 'title_en']); if (regions.length !== 1) { return noties.alert({ - message: 'Необходимо выбрать один регион', + message: 'Necessary to choose only one region', type: 'warning', timeout: 4000, ok: true, @@ -485,16 +485,16 @@ define([ }, regionFilterSelect: function () { if (!this.regselectVM) { - this.regionSelect(koMapping.toJS(this.u.regions), 0, 10, 'Изменение списка регионов для фильтрации по умолчанию', + this.regionSelect(koMapping.toJS(this.u.regions), 0, 10, 'List of regions for filtering by default', function (vm) { this.regselectVM = vm; }, function () { - const regions = this.regselectVM.getSelectedRegions(['cid', 'title_local']); + const regions = this.regselectVM.getSelectedRegions(['cid', 'title_en']); if (regions.length > 10) { return noties.alert({ - message: 'Допускается выбирать до 10 регионов', + message: 'Allowed to select up to 10 regions', type: 'warning', timeout: 4000, ok: true, @@ -533,16 +533,16 @@ define([ maxWidthRatio: 0.95, fullHeight: true, withScroll: true, - offIcon: { text: 'Отмена', click: onCancel, ctx: ctx }, + offIcon: { text: 'Cancel', click: onCancel, ctx: ctx }, btns: [ { css: 'btn-success', - text: 'Применить', + text: 'Apply', glyphicon: 'glyphicon-ok', click: onApply, ctx: ctx, }, - { css: 'btn-warning', text: 'Отмена', click: onCancel, ctx: ctx }, + { css: 'btn-warning', text: 'Cancel', click: onCancel, ctx: ctx }, ], }, callback: function (vm) { diff --git a/public/js/module/user/subscr.js b/public/js/module/user/subscr.js index 353360cdc..d831913cf 100644 --- a/public/js/module/user/subscr.js +++ b/public/js/module/user/subscr.js @@ -79,9 +79,9 @@ define(['underscore', 'Utils', 'socket!', 'Params', 'knockout', 'knockout.mappin let txt = ''; if (count) { - txt = 'Показаны ' + globalVM.intl.num(this.pageFirstItem()) + ' – ' + globalVM.intl.num(this.pageLastItem() || this.pageSize()) + ' из ' + globalVM.intl.num(count); + txt = '' + globalVM.intl.num(this.pageFirstItem()) + ' – ' + globalVM.intl.num(this.pageLastItem() || this.pageSize()) + ' of ' + globalVM.intl.num(count) + ' are shown'; } else { - txt = 'Пока нет подписок в данной категории'; + txt = 'Still has no subscription in this category'; } return txt; diff --git a/public/js/module/user/userPage.js b/public/js/module/user/userPage.js index 2f77e9835..a4e9cd959 100644 --- a/public/js/module/user/userPage.js +++ b/public/js/module/user/userPage.js @@ -56,20 +56,20 @@ define(['underscore', 'Utils', 'Params', 'renderer', 'knockout', 'knockout.mappi this.menuItems = this.co.menuItems = ko.computed(function () { const login = this.user.login(); const result = [ - { name: 'Профиль', href: '/u/' + login, section: 'profile' }, - { name: 'Изображения', href: '/u/' + login + '/photo', section: 'photo' }, - { name: 'Комментарии', href: '/u/' + login + '/comments', section: 'comments' }, + { name: 'Profile', href: '/u/' + login, section: 'profile' }, + { name: 'Images', href: '/u/' + login + '/photo', section: 'photo' }, + { name: 'Comments', href: '/u/' + login + '/comments', section: 'comments' }, ]; if (this.auth.loggedIn() && (this.auth.iAm.login() === login || this.auth.iAm.role() > 9)) { - result.push({ name: 'Подписки', href: '/u/' + login + '/subscriptions', section: 'subscriptions' }); - result.push({ name: 'Настройки', href: '/u/' + login + '/settings', section: 'settings' }); - result.push({ name: 'Сессии', href: '/u/' + login + '/sessions', section: 'sessions' }); + result.push({ name: 'Subscriptions', href: '/u/' + login + '/subscriptions', section: 'subscriptions' }); + result.push({ name: 'Settings', href: '/u/' + login + '/settings', section: 'settings' }); + result.push({ name: 'Sessions', href: '/u/' + login + '/sessions', section: 'sessions' }); //result.push({name: 'Messages', href: "/u/" + login + '/pm', disable: true, section: 'pm'}); } if (this.auth.iAm.role() > 9) { - result.push({ name: 'Управление', href: '/u/' + login + '/manage', section: 'manage' }); + result.push({ name: 'Manage', href: '/u/' + login + '/manage', section: 'manage' }); } return result; @@ -211,25 +211,25 @@ define(['underscore', 'Utils', 'Params', 'renderer', 'knockout', 'knockout.mappi moduleOptions.options.goUpload = true; //Если нет, говорим что надо открыть при загрузке галереи } - Utils.title.setTitle({ pre: 'Загрузка - ', title: this.user.disp() }); + Utils.title.setTitle({ pre: 'Upload - ', title: this.user.disp() }); } else { - Utils.title.setTitle({ pre: 'Галерея - ', title: this.user.disp() }); + Utils.title.setTitle({ pre: 'Gallery - ', title: this.user.disp() }); } } else if (section === 'comments') { module = 'm/user/comments'; - Utils.title.setTitle({ pre: 'Комментарии - ', title: this.user.disp() }); + Utils.title.setTitle({ pre: 'Comments - ', title: this.user.disp() }); } else if (section === 'subscriptions') { module = 'm/user/subscr'; - Utils.title.setTitle({ pre: 'Подписки - ', title: this.user.disp() }); + Utils.title.setTitle({ pre: 'Subscriptions - ', title: this.user.disp() }); } else if (section === 'settings') { module = 'm/user/settings'; - Utils.title.setTitle({ pre: 'Настройки - ', title: this.user.disp() }); + Utils.title.setTitle({ pre: 'Settings - ', title: this.user.disp() }); } else if (section === 'sessions') { module = 'm/user/sessions'; - Utils.title.setTitle({ pre: 'Сессии - ', title: this.user.disp() }); + Utils.title.setTitle({ pre: 'Sessions - ', title: this.user.disp() }); } else if (section === 'manage') { module = 'm/user/manage'; - Utils.title.setTitle({ pre: 'Управление - ', title: this.user.disp() }); + Utils.title.setTitle({ pre: 'Manage - ', title: this.user.disp() }); } this.section(section); diff --git a/public/js/noties.js b/public/js/noties.js index 28eb70c25..e04684e41 100644 --- a/public/js/noties.js +++ b/public/js/noties.js @@ -32,7 +32,7 @@ define(['underscore', 'jquery', 'Utils'], function (_, $, Utils) { } function getErrorMessage(error) { - let message = 'Возникла ошибка'; + let message = 'An error occurred'; if (!_.isEmpty(error)) { if (_.isString(error)) { @@ -156,7 +156,7 @@ define(['underscore', 'jquery', 'Utils'], function (_, $, Utils) { }, }, { - addClass: cancelClass, text: params.cancelText || 'Отмена', + addClass: cancelClass, text: params.cancelText || 'Cancel', onClick: function ($noty) { $noty.close(); @@ -252,7 +252,7 @@ define(['underscore', 'jquery', 'Utils'], function (_, $, Utils) { notyAlert({ message: getErrorMessage(error), type: 'error', timeout: params.timeout || 120000, - ok: true, text: 'Закрыть', + ok: true, text: 'Close', }); } diff --git a/public/js/socket.js b/public/js/socket.js index 1ecd1fa26..6b8138fe7 100644 --- a/public/js/socket.js +++ b/public/js/socket.js @@ -30,10 +30,10 @@ define(['module'], function (/* module */) { const disconnectionDataReturn = { error: true, noconnect: true, - message: 'Нет соединения с сервером, повторите после восстановления связи', + message: 'No connection with the server, please try again after reconnecting', }; - const noConnWait = '
Нет соединения с сервером, пробую подключиться.. После восстановления связи сообщение пропадет автоматически
'; - const noConnFail = '
Не удалось автоматически подключиться к серверу. Продолжать попытки
'; + const noConnWait = '
No connection with the server, trying to connect .. After the restoration of connection message will disappear automatically
'; + const noConnFail = '
Failed to connect to the server automatically. Keep trying
'; /** * Событие первого соединения с сервером @@ -233,7 +233,7 @@ define(['module'], function (/* module */) { return socket.request(name, data, timeToWaitIfNoConnection) .catch(function (error) { if (error instanceof TimeoutError) { - error.message = 'Превышено время ожидания запроса'; + error.message = 'Request timed out'; } return { error: error }; diff --git a/views/mail/head.pug b/views/mail/head.pug index a58c65375..0e1234d56 100644 --- a/views/mail/head.pug +++ b/views/mail/head.pug @@ -5,7 +5,7 @@ table(style="width: 100%; margin-top: 0px; background-color: #214A78; color: #F2 img(src='cid:pastvulogo', style="width: 47px; height: 49px; vertical-align: middle; border-image-width: 0; border-width: 0px;") td(style="line-height: 1.4em;") span(style="vertical-align: middle;") - | Здравствуйте, #{username}! + | Hello, #{username}! if greeting br = greeting \ No newline at end of file diff --git a/views/mail/notice.pug b/views/mail/notice.pug index 95d01180f..28a689995 100644 --- a/views/mail/notice.pug +++ b/views/mail/notice.pug @@ -6,34 +6,34 @@ mixin noticeLi(arr, path) div(style="margin-left: 13px;") = val.briefFormat.newest if val.briefFormat.unread - = ' (всего ' + val.briefFormat.unread + ')' + = ' (' + val.briefFormat.unread + ' total)' if usersLogin.length > 1 div(style="margin-left: 13px; margin-bottom: 4px;") - | Авторы: + | Authors: each login, index in usersLogin if (index < 6) if (index > 0) | , = ' ' + val.brief.users[login] if usersLogin.length > 6 - = ' и др.' + = ' et al.' if usersLogin.length === 1 div(style="margin-left: 13px; margin-bottom: 4px;") - | Автор: #{val.brief.users[usersLogin[0]]} + | Author: #{val.brief.users[usersLogin[0]]} include head - var origin = config.client.origin -p На момент отправки данного уведомления в темах, на которые вы подписаны, было добавлено следующее количество комментариев: +p At the time of sending this notice the following number of comments was added to topics, which you have subscribed: if news.length p(style="margin-bottom: 2px;") - strong Новости: + strong News: +noticeLi(news, '/news/') if photos.length p(style="margin-bottom: 2px;") - strong Фотографии: + strong Photos: +noticeLi(photos, '/p/') div(style="border-top: 1px solid #eee; border-bottom: 1px solid #fff; margin-top: 1em;") p(style="font-size: smaller; margin-top: 0.5em;") - | Управлять материалами, на которые вы подписаны, можно на странице подписок: #{config.client.host + '/u/' + user.login + '/subscriptions'} + | You can manage your subscriptions on subscriptions page: #{config.client.host + '/u/' + user.login + '/subscriptions'} br - | Задать интервал уведомлений или отключить их вы можете на странице настроек: #{config.client.host + '/u/' + user.login + '/settings'} + | You can set notification interval or disable notifications on the settings page: #{config.client.host + '/u/' + user.login + '/settings'} diff --git a/views/mail/recall.pug b/views/mail/recall.pug index c7730d9a0..f93571408 100644 --- a/views/mail/recall.pug +++ b/views/mail/recall.pug @@ -1,12 +1,12 @@ include head p - | Для Вашей учетной записи был создан запрос на восстановление пароля на проекте PastVu. + | Password recovery request was created for your PastVu account. br - | Если Вы не производили таких действий на нашем сайте, то просто проигнорируйте и удалите письмо. + | If you didn't request it, just ignore this email. p - | Для ввода нового пароля перейдите по следующей ссылке: + | Click on the following link to enter a new password: br a(href=config.client.origin + '/confirm/' + confirmKey, target='_blank') = config.client.host + '/confirm/' + confirmKey br - small Ссылка действительна #{linkvalid}, по истечении которых Вам будет необходимо запрашивать смену пароля повторно + small The link is valid for #{linkvalid}, after which you will need to request a password change again diff --git a/views/mail/registration.pug b/views/mail/registration.pug index 9d9f66c79..876d4b33e 100644 --- a/views/mail/registration.pug +++ b/views/mail/registration.pug @@ -1,22 +1,22 @@ include head p(style="padding-left: 3px; border-style: solid; border-width: 0px 0px 0px 3px; border-color: #5D88B6;") - | Вы указали следующие реквизиты: + | You have specified the following details: br - | Логин: #{login} + | Login username: #{login} br | E-mail: #{email} br - small Для лучшей безопасности мы не храним оригинал вашего пароля. Если вы его забудете, просто установите новый с помощью процедуры восстановления на сайте + small For better security, we do not store your original password. If you forget it, just set the new one with recovery procedures on the site p - | Мы требуем от всех пользователей подтверждения регистрации, для проверки того, что введённый e-mail адрес реальный. + | We require that all new users should to confirm their email, to be sure that email is real. br - | Это требуется для защиты от спамеров и многократной регистрации. + | This is required for protection against spammers and multiple registration. p(style="padding-left: 3px; border-style: solid; border-width: 0px 0px 0px 3px; border-color: #5D88B6;") - | Для активации Вашего аккаунта, пройдите по следующей ссылке: + | To activate your account, click the following link: br a(href=config.client.origin + '/confirm/' + confirmKey, target='_blank') = config.client.host + '/confirm/' + confirmKey br - small Ссылка действительна #{linkvalid}, по истечении которых Вам будет необходимо зарегистрироваться повторно + small The link is valid for #{linkvalid}, after which you will need to register again p(style="color: #999;") - small Вы получили это письмо, так как этот e-mail адрес был использован при регистрации. Если Вы не регистрировались на нашем сайте, то просто проигнорируйте и удалите письмо. \ No newline at end of file + small You have received this letter because this email address was used for registration. If you didn't register on our website, simply ignore and delete the email. \ No newline at end of file diff --git a/views/module/admin/conveyer.pug b/views/module/admin/conveyer.pug index 65e46b0a2..52fcf62f0 100644 --- a/views/module/admin/conveyer.pug +++ b/views/module/admin/conveyer.pug @@ -1,50 +1,50 @@ .conveyerModuleWrapper(data-bind="with: repository[M!M]") - h4 Управление конвейером конвертаций фотографий + h4 Conveyor control .row .col-xs-5.col-md-4 - h5 Действия + h5 Actions button.btn.btn-sm(type="button", data-bind="css: {disabled: exe(), 'btn-warning': conveyerEnabled(), 'btn-success': !conveyerEnabled()}, click: startstop, attr: {disabled: exe()}") span.glyphicon(data-bind="css: {'glyphicon-stop': conveyerEnabled(), 'glyphicon-play': !conveyerEnabled()}") - span(data-bind="text: conveyerEnabled() ? ' Остановить' : ' Запустить'") + span(data-bind="text: conveyerEnabled() ? ' Stop' : ' Start'") button.btn.btn-sm.btn-danger(type="button", data-bind="css: {disabled: exe()}, click: clearConveyer, attr: {disabled: exe()}") span.glyphicon.glyphicon-trash - | Очистить + | Clear br br .toConvertSection - h5 Отправить на конвертацию все фото: + h5 Send to convert all photos: form.form-inline .form-group - | Номера фотографий:  + | Photos id:  input.form-control(type="number", placeholder="min", data-bind="attr: {disabled: exe()}, value: reconvertCidMin, valueUpdate: 'afterkeydown'", style="width: 70px;") input.form-control(type="number", placeholder="max", data-bind="attr: {disabled: exe()}, value: reconvertCidMax, valueUpdate: 'afterkeydown'", style="width: 70px;") |   form.form-inline .form-group - | Номера статусов:  - input.form-control(data-bind="attr: {disabled: exe()}, value: reconvertStatuses, valueUpdate: 'afterkeydown'", style="width: 140px;", placeholder="Через запятую") + | Status numbers:  + input.form-control(data-bind="attr: {disabled: exe()}, value: reconvertStatuses, valueUpdate: 'afterkeydown'", style="width: 140px;", placeholder="Comma-separated") |   form.form-inline .form-group - | Номер региона:  + | Region id:  input.form-control(type="number", data-bind="attr: {disabled: exe()}, value: reconvertRegion, valueUpdate: 'afterkeydown'", style="width: 70px;") |   - button.btn.btn-primary(data-bind="click: toConvert, attr: {disabled: exe()}") Cтарт + button.btn.btn-primary(data-bind="click: toConvert, attr: {disabled: exe()}") Start .col-xs-7.col-md-8(style="padding-left: 10px;") - h5 Текущее состояние конвейера - div(data-bind="css: {'text-success': conveyerEnabled(), 'text-error': !conveyerEnabled()}, text: conveyerEnabled() ? 'Конвейер активен' : 'Конвейер остановлен'") + h5 The current state of the conveyor + div(data-bind="css: {'text-success': conveyerEnabled(), 'text-error': !conveyerEnabled()}, text: conveyerEnabled() ? 'Conveyor is active' : 'Conveyor is stopped'") div span.stateRate(data-bind="text:converted()") - span.stateDesc Конвертировано за текущую 10-ти минутку + span.stateDesc Converted since last 10-minute interval div span.stateRate(data-bind="text:clength()") - span.stateDesc Текущая длина конвейера + span.stateDesc Current conveyor length div span.stateRate(data-bind="text:cmaxlength()") - span.stateDesc Максимальная длина конвейера за текущую 10-ти минутку + span.stateDesc Maximum conveyor length for the current 10-minute interval br - h5 Сконвертированно + h5 Converted #conveyerConvertGraph br - h5 Максимальная длина конвейера + h5 Maximum conveyor length #conveyerLengthGraph diff --git a/views/module/admin/main.pug b/views/module/admin/main.pug index 924ec5a42..77e0ffe45 100644 --- a/views/module/admin/main.pug +++ b/views/module/admin/main.pug @@ -1,5 +1,5 @@ .mainAdmin(data-bind="with: repository[M!M]") - h6 Текущие соединения + h6 Current connections div span.stateRate .rate(data-bind="text: onlines.users()") @@ -7,7 +7,7 @@ .rate(data-bind="text: (onlines.all() - onlines.users())") | / .rate(data-bind="text: onlines.all()") - span.stateDesc Посетителей авторизованных/анонимных/всего + span.stateDesc Visitors authorised/anonymous/total div span.stateRate .rate(data-bind="text: onlines.sessUC()") @@ -15,7 +15,7 @@ .rate(data-bind="text: onlines.sessAC()") | / .rate(data-bind="text: (onlines.sessUC() + onlines.sessAC())") - span.stateDesc(data-bind="text: 'Активных сессий авторизованных/анонимных/всего. С нулем соединений: [' + onlines.sessUZC() + '/' + onlines.sessAZC() + ']. Без соединений: [' + onlines.sessUNC() + '/' + onlines.sessANC() + '].'") + span.stateDesc(data-bind="text: 'Active sessionsauthorised/anonymous/total. With zero connections: [' + onlines.sessUZC() + '/' + onlines.sessAZC() + ']. With no connections: [' + onlines.sessUNC() + '/' + onlines.sessANC() + '].'") div span.stateRate @@ -24,7 +24,7 @@ .rate(data-bind="text: onlines.sessWCAC()") | / .rate(data-bind="text: (onlines.sessWCUC() + onlines.sessWCAC())") - span.stateDesc Ожидающих сессий авторизованных/анонимных/всего + span.stateDesc Sessions waiting connections authorised/anonymous/total div span.stateRate .rate(data-bind="text: onlines.sockUC()") @@ -32,9 +32,9 @@ .rate(data-bind="text: onlines.sockAC()") | / .rate(data-bind="text: (onlines.sockUC() + onlines.sockAC())") - span.stateDesc Активных соединений авторизованных/анонимных/всего + span.stateDesc Active connections authorised/anonymous/total div - span.stateDesc Хэши объектов пользователя в памяти:  + span.stateDesc Map of user objects in memory:  span.stateRate | usSid: .rate(data-bind="text: ' '+ onlines.cusSid()") @@ -43,7 +43,7 @@ | , usId: .rate(data-bind="text: ' '+ onlines.cusId()") div - span.stateDesc Хэши сессий в памяти:  + span.stateDesc Map of sessions in memory:  span.stateRate | sessConnected: .rate(data-bind="text: ' '+ onlines.csessConnected()") @@ -52,23 +52,23 @@ | , sessWaitingSelect: .rate(data-bind="text: ' '+ onlines.csessWaitingSelect()") .desc - strong Активная сессия - | - один браузер клиента с открытым pastvu хотябы на одной вкладке. Если есть с нулем соединений, значит закрытие соединения не очистило сессию (норма по нулям). Если есть без соединения, значит сессия проскочила в активную без установки реального соединения (норма по нулям). + strong Active session + | - one client browser with opened pastvu at least in one tab. If exists with zero connections, means that connection closing didn't clear session (should not be). If without connection, means session jumped in active state without socket connection (should not be). br - strong Ожидающая сессия - | - клиент, прошедший рукопожатие (handshake), но не установивший в дальнейшем реального соединения. Такая сессия удаляется через 5 минут, если соединение так и не будет установлено. + strong Waiting session + | - client passed handshake, but still have no reac socket connection. Such session remove in 5 minutes if connection would not established. br - strong Активное соединение - | - каждая открытая клиентом вкладка активной сессии + strong Active connection + | - every opened browser tab of active session br br - | В каждой сессии (браузере) клиента может быть несколько открытых соединений (вкладок) + | In each client session (broeser) can be several opened connections (tabs) br - | Пользователь, авторизованный (залогиненный) в нескольких браузерах одновременно, считается как один, но имеет несколько сессий, по количеству открытых браузеров. Поэтому "активных сессий авторизованных" может быть больше числа авторизованных. + | User, who authorised in several browser at the same time, counts as one, but have several sessions according the number of open browsers. That's why number of active authorised sessions may be more then number of authorised br //ko if: headers().length - h6 Заголовки АКТИВНЫХ сессий без соединений (при наличии): + h6 Headers of ACTIVE sessions without connections (if exists): div(data-bind="foreach: headers") | ------- .headers(data-bind="html: $data") @@ -76,7 +76,7 @@ // /ko //ko if: headersWC().length - h6 Заголовки ОЖИАЮЩИХ сессий без соединений (при наличии): + h6 Headers of WAITING sessions without connections (if exists): div(data-bind="foreach: headersWC") | ------- .headers(data-bind="html: $data") diff --git a/views/module/admin/newsEdit.pug b/views/module/admin/newsEdit.pug index 9c9a58c8a..573ffbb6c 100644 --- a/views/module/admin/newsEdit.pug +++ b/views/module/admin/newsEdit.pug @@ -1,21 +1,21 @@ .adminNews(data-bind="with: repository[M!M]") - h4(data-bind="text: createMode() ? 'Создание новости' : 'Редактирование новости'") + h4(data-bind="text: createMode() ? 'News creation' : 'News edit'") form.form-horizontal(action='', autocomplete="off", method='POST', data-bind="event: {submit: submit}") .form-group - label.col-xs-3.col-md-2.col-lg-1.control-label Заголовок + label.col-xs-3.col-md-2.col-lg-1.control-label Title .col-xs-3.col-md-2 input.form-control(type='text', data-bind="value: news.title, valueUpdate: 'afterkeydown'") .form-group - label.col-xs-3.col-md-2.col-lg-1.control-label Публикация + label.col-xs-3.col-md-2.col-lg-1.control-label Publish .col-xs-3.col-md-2 .input-group.date#newsPdate input.form-control(data-format="DD.MM.YYYY HH:mm:ss", type="text") span.input-group-addon span.glyphicon.glyphicon-calendar .col-xs-4.col-md-3(style="text-align: right;") - button.btn.btn-sm.btn-primary.toggleTDate(type="button", title="Время, когда новость пропадет с главной. В общем списке она останется", data-bind="click: toggleTDate") - span(data-bind="text: tDateExists() ? 'Убрать время скрытия с главной' : 'Добавить время скрытия с главной'") + button.btn.btn-sm.btn-primary.toggleTDate(type="button", title="The time when the news will disappear from the main page. In the general list it will remain", data-bind="click: toggleTDate") + span(data-bind="text: tDateExists() ? 'Remove hidding time from the main page' : 'Add hidding time from the main page'") //ko if: tDateExists() .col-xs-3.col-md-2 .input-group.date#newsTdate @@ -28,21 +28,21 @@ .checkbox label input(type="checkbox", data-bind="checked: news.nocomments") - | Без комментариев + | Without comments .form-group .textName button.btn.btn-sm.btn-primary.toggleNotice(type="button", data-bind="click: toggleNotice") - span(data-bind="text: noticeExists() ? 'Убрать краткую версию' : 'Добавить краткую версию'") + span(data-bind="text: noticeExists() ? 'Remove short version' : 'Add short version'") //ko if: noticeExists() - span.text-muted Краткая версия + span.text-muted Short version // /ko //ko if: noticeExists() textarea#newsNotice // /ko .form-group - .textName Полная версия + .textName Full version textarea#newsPrimary .form-group button.btn.btn-success(type="submit") span.glyphicon.glyphicon-ok - | Сохранить \ No newline at end of file + | Save \ No newline at end of file diff --git a/views/module/admin/region.pug b/views/module/admin/region.pug index 8346bd75f..64c6f2456 100644 --- a/views/module/admin/region.pug +++ b/views/module/admin/region.pug @@ -1,65 +1,65 @@ .adminRegion(data-bind="with: repository[M!M]") //ko if: createMode() - h4 Создание региона + h4 Region creation // /ko form.form-horizontal(action='', autocomplete="off", data-bind="event: {submit: save}", style="overflow:hidden;") //ko if: !createMode() .form-group - label.col-xs-4.col-sm-3.col-lg-2.control-label Редактирование региона + label.col-xs-4.col-sm-3.col-lg-2.control-label Edit region .col-xs-8.col-sm-9.col-lg-10 p.form-control-static - = 'Номер: ' + = 'Id: ' strong(data-bind="text: region.cid()") - = '; Уровень: ' + = '; Level: ' strong(data-bind="text: (Number(haveParent()) ? region.parents().length + 1 : 1)") - = '; Создан: ' + = '; Created: ' strong(data-bind="text: fDateIn(new Date(region.cdate()))") //ko if: region.udate && region.cdate() !== region.udate() - = '; Обновлен: ' + = '; Updated: ' strong(data-bind="text: fDateIn(new Date(region.udate()))") // /ko // /ko .form-group - label.col-xs-4.col-sm-3.col-lg-2.control-label Название + label.col-xs-4.col-sm-3.col-lg-2.control-label Title .col-xs-2.col-sm-2 - input.form-control(type='text', data-bind="value: region.title_en, valueUpdate: 'keyup'", placeholder="(EN) Английское", required="required", autocorrect="off", autocapitalize="off") + input.form-control(type='text', data-bind="value: region.title_en, valueUpdate: 'keyup'", placeholder="(EN) English", required="required", autocorrect="off", autocapitalize="off") .col-xs-2.col-sm-2 - input.form-control(type='text', data-bind="value: region.title_local, valueUpdate: 'keyup'", placeholder="(RU) Русское", autocorrect="off", autocapitalize="off") + input.form-control(type='text', data-bind="value: region.title_local, valueUpdate: 'keyup'", placeholder="(RU) Russian", autocorrect="off", autocapitalize="off") //ko if: !createMode() .col-xs-2.col-sm-2(style="padding: 1px 0 0 4px;") - a.btn.btn-sm.btn-primary(type="button", title="Показать в дереве регионов", data-bind="attr: {href: '/admin/region?hl=' + region.cid()}") + a.btn.btn-sm.btn-primary(type="button", title="Show in regions tree", data-bind="attr: {href: '/admin/region?hl=' + region.cid()}") span.glyphicon.glyphicon-indent-left - a.btn.btn-sm.btn-primary(type="button", title="Перейти в галерею региона", data-bind="attr: {href: '/ps?f=r!' + region.cid()}") + a.btn.btn-sm.btn-primary(type="button", title="Jump te region's gallery", data-bind="attr: {href: '/ps?f=r!' + region.cid()}") span.glyphicon.glyphicon-th // /ko .form-group - label.col-xs-4.col-sm-3.col-lg-2.control-label Родительский регион + label.col-xs-4.col-sm-3.col-lg-2.control-label Parent region .col-xs-6.col-sm-4 .row .col-xs-8.col-sm-9.col-md-8.col-lg-6 label.radio-inline input.thr(type="radio", id="parent_radios_0", name="parent_radios", value="0", data-bind="checked: haveParent") - | Отсутствует + | Is absent label.radio-inline input.thr(type="radio", id="parent_radios_1", name="parent_radios", value="1", data-bind="checked: haveParent") - | Есть + | Exists //ko if: Number(haveParent()) .col-xs-4.col-sm-3.col-lg-3 - input.form-control(type='text', data-bind="value: parentCid, valueUpdate: 'keyup'", placeholder="Номер родительского региона", required="required", autocorrect="off", autocapitalize="off") + input.form-control(type='text', data-bind="value: parentCid, valueUpdate: 'keyup'", placeholder="Id of perent region", required="required", autocorrect="off", autocapitalize="off") // /ko //ko if: region.parents().length || childLenArr().length .form-group - label.col-xs-4.col-sm-3.col-lg-2.control-label Путь региона + label.col-xs-4.col-sm-3.col-lg-2.control-label Region path .col-xs-8.col-sm-9.col-lg-10 p.form-control-static.path //ko foreach: region.parents - a(data-bind="text: ' ' + $data.title_local(), attr: {href: '/admin/region/' + $data.cid()}") + a(data-bind="text: ' ' + $data.title_en(), attr: {href: '/admin/region/' + $data.cid()}") |   span.glyphicon.glyphicon-play |   // /ko //ko if: !createMode() - span.current(title="Текущий регион", data-bind="text: ' ' + region.title_local()") + span.current(title="Current region", data-bind="text: ' ' + region.title_en()") // /ko //ko foreach: childLenArr |   @@ -69,12 +69,12 @@ // /ko //ko if: !createMode() && region.parents().length < maxRegionLevel .form-group - label.col-xs-4.col-sm-3.col-lg-2.control-label Прямые потомки + label.col-xs-4.col-sm-3.col-lg-2.control-label Direct children .col-xs-8.col-sm-9.col-lg-10(style="padding-top: 2px") span.children(data-bind="css: {more: childrenExpand() === 1, expanded: childrenExpand() === 2}") - a(data-bind="attr: {href: '/admin/region/create?parent=' + region.cid()}", title="Добавить дочерний регион") [+1] + a(data-bind="attr: {href: '/admin/region/create?parent=' + region.cid()}", title="Add child region") [+1] //ko if: auth.iAm.login() === 'klimashkin' - a(data-bind="click: addFeatures", href="javascript:void(0);", title="Добавить дочерние через FeatureCollection") [+FC] + a(data-bind="click: addFeatures", href="javascript:void(0);", title="Add child region using FeatureCollection") [+FC] // /ko //ko if: children().length = ' | ' @@ -85,10 +85,10 @@ a(data-bind="attr: {href: '/admin/region/' + $data.cid}, css: {'noPhotos': !$data.phc && !$data.pac && !$data.cc}") span(data-bind="text: $data.title") //ko if: $data.childrenCount - span(data-bind="text: ' +' + $data.childrenCount", style="color:#5b6d82;font-size:10px;", title="Кол-во прямых потомков") + span(data-bind="text: ' +' + $data.childrenCount", style="color:#5b6d82;font-size:10px;", title="Number of direct descendants") // /ko //ko if: $data.childLen && $data.childrenCount !== $data.childLen - span(data-bind="text: '(' + $data.childLen + ')'", style="color:#5b6d82;font-size:10px;", title="Кол-во всех потомков") + span(data-bind="text: '(' + $data.childLen + ')'", style="color:#5b6d82;font-size:10px;", title="Number of all descendants") // /ko | , .tltp.tltp-top.tltp-animate-opacity.rytltp @@ -148,28 +148,28 @@ // /ko //ko if: createMode() || showGeo() .form-group - label.col-xs-4.col-sm-3.col-lg-2.control-label Доп. параметры + label.col-xs-4.col-sm-3.col-lg-2.control-label Additional parameters .col-xs-8.col-sm-9.col-lg-10(style="padding-top: 3px") .dopparam - abbr(title="Центральная точка региона в его домашнем положении") Центр + abbr(title="The central point of the region in it home position") Center | : - input.form-control.input-sm.center(type="text", data-bind="centerInput: true, attr: {readonly: region.centerAuto(), placeholder: region.centerAuto() ? 'Пока не рассчитан' : 'Не задан'}, css: {invalid: !region.centerAuto() && !centerValid()}") + input.form-control.input-sm.center(type="text", data-bind="centerInput: true, attr: {readonly: region.centerAuto(), placeholder: region.centerAuto() ? 'Not yet calculated' : 'Not specified'}, css: {invalid: !region.centerAuto() && !centerValid()}") .btn-group.btn-group-sm - button.btn.btn-primary.yes(type="button", data-bind="css: {active: region.centerAuto()}, click: centerAutoToggle") Авто - button.btn.btn-primary.no(type="button", data-bind="css: {active: !region.centerAuto()}, click: centerAutoToggle") Вручную + button.btn.btn-primary.yes(type="button", data-bind="css: {active: region.centerAuto()}, click: centerAutoToggle") Auto + button.btn.btn-primary.no(type="button", data-bind="css: {active: !region.centerAuto()}, click: centerAutoToggle") Manual br .dopparam - abbr(title="Bounding box - прямоугольник, в который целиком вписан регион") Bbox + abbr(title="Bounding box - rectangle in which entire region is fits") Bbox | : - input.form-control.input-sm.bbox(type="text", readonly, data-bind="attr: {value: region.bbox() ? region.bbox().join(', ') : ''}", placeholder="Пока не рассчитан") + input.form-control.input-sm.bbox(type="text", readonly, data-bind="attr: {value: region.bbox() ? region.bbox().join(', ') : ''}", placeholder="Not yet calculated") .dopparam - abbr(title="Прямоугольник, который должен быть виден в домашнем положении карты для данного региона. Нужен для расчета масштаба") Bbox дом + abbr(title="The rectangle that should be visible in the home position of the map. We need to calculate the scale") Bbox home | .: .btn-group.btn-group-sm - button.btn.btn-primary.yes(type="button", data-bind="css: {active: bboxAuto()}, click: bboxHomeToggle") Как bbox - button.btn.btn-primary.no(type="button", data-bind="css: {active: !bboxAuto()}, click: bboxHomeToggle") Вручную + button.btn.btn-primary.yes(type="button", data-bind="css: {active: bboxAuto()}, click: bboxHomeToggle") As bbox + button.btn.btn-primary.no(type="button", data-bind="css: {active: !bboxAuto()}, click: bboxHomeToggle") Manual //ko if: !bboxAuto() - input.form-control.input-sm.bbox(type="text", data-bind="bboxhomeInput: true, attr: {readonly: bboxAuto()}, css: {invalid: !bboxAuto() && !bboxhomeValid()}", placeholder="Не задан") + input.form-control.input-sm.bbox(type="text", data-bind="bboxhomeInput: true, attr: {readonly: bboxAuto()}, css: {invalid: !bboxAuto() && !bboxhomeValid()}", placeholder="Not specified") // /ko .form-group label.col-xs-4.col-sm-3.col-lg-2.control-label GeoJSON @@ -180,14 +180,14 @@ .form-group.actions button.btn.btn-success(type="submit", data-bind="attr: {disabled: exe()}") span.glyphicon.glyphicon-ok - | Сохранить + | Save button.btn.btn-danger(type="button", data-bind="click: remove, attr: {disabled: exe()}") span.glyphicon.glyphicon-remove - | Удалить + | Remove //ko if: !createMode() button.btn.btn-primary(type="button", data-bind="click: toggleGeo, attr: {disabled: exe()}") span.glyphicon.glyphicon-th-list - span(data-bind="text: showGeo() ? ' Скрыть геометрию' : ' Управление геометрией'") + span(data-bind="text: showGeo() ? ' Hide geometry' : ' Show geometry'") // /ko .maprow .map(data-bind="style: {height: mh()}") @@ -197,7 +197,7 @@ //ko if: photostat().all && paintstat().all .stats-section.stats-photo | - .toggleStatByType(data-bind="text: (imagesByType() ? 'Скрыть' : 'Показать') + ' статистику по типам изображений', click: toggleImagesStatType") + .toggleStatByType(data-bind="text: (imagesByType() ? 'Hide' : 'Show') + ' statistics by image type', click: toggleImagesStatType") // /ko //ko if: photostat().all && (!paintstat().all || imagesByType()) .stats-section.stats-photo(data-bind="template: {name: 'photoStat', data: photostat()}") @@ -208,13 +208,13 @@ .stats-section.stats-comment(data-bind="with: cstat()") .stats-head span.glyphicon.glyphicon-comment - = " Комментариев: " + = " Comments: " span(data-bind="text: $root.intl.num(all)") div(style="margin-top:3px;") - b= "Активных: " + b= "Active: " span(data-bind="text: $root.intl.num(all - del)") div - b= "Удаленных: " + b= "Deleted: " span(data-bind="text: $root.intl.num(del)") b(style="display:block;margin-top:4px;") Активных по статусам изображений: //ko foreach: statuses @@ -225,7 +225,7 @@ // /ko button.btn.btn-primary(type="button", data-bind="click: recalcStats, attr: {disabled: exe()}") span.glyphicon.glyphicon-refresh - span Пересчитать статистику + span Recalculate stat // /ko | | | | | | | \ No newline at end of file diff --git a/views/module/common/foot.pug b/views/module/common/foot.pug index 4f6c6a1e0..5d619e12a 100644 --- a/views/module/common/foot.pug +++ b/views/module/common/foot.pug @@ -1,10 +1,10 @@ .foot.fringe(data-bind="with: repository[M!M]") .rightSide.hide-text a.footElem.strokeAfter(href="mailto:support@pastvu.com", target="_blank", onclick="ga('send', 'event', 'support', 'click', 'support click common');") - | Поддержка: support@pastvu.com - a.footElem.strokeAfter(data-bind="attr: {href: getRulesUrl()}", target="_blank", onclick="ga('send', 'event', 'rules', 'click', 'rules click common');") - | Правила - .footElem.strokeAfter(data-bind="click: navigateAbout") О проекте + | Support: support@pastvu.com + a.footElem.strokeAfter(data-bind="attr: {href: getRulesUrl()}", target="_blank", onclick="ga('send', 'event', 'rules', 'click', 'rules click common'); ") + | Rules + .footElem.strokeAfter(data-bind="click: navigateAbout") About a.footElem.strokeAfter(href="https://github.com/PastVu", target="_blank", onclick="ga('send', 'event', 'github', 'click', 'go to github');") span.github |  GitHub diff --git a/views/module/common/reason.pug b/views/module/common/reason.pug index 02c25cc73..41a1fe6a6 100644 --- a/views/module/common/reason.pug +++ b/views/module/common/reason.pug @@ -10,7 +10,7 @@ .form-group //- Выводим заголовок описания, если он есть или это не свободное описание и вариантов выбора несколько //ko if: selected().desc.label || selections().length > 1 && Number(selected().cid) !== 0 - label.desclabel(for="desc", data-bind="html: selected().desc.label || ('Дополнительная информация' + (selected().desc.required ? '' : ' (опционально)'))") + label.desclabel(for="desc", data-bind="html: selected().desc.label || ('Additional info' + (selected().desc.required ? '' : ' (optional)'))") // /ko textarea#desc.form-control(data-bind="value: desc, attr: {placeholder: selected().desc.placeholder || '', minLength: minLength(), maxlength: selected().desc.max || '1000'}", style="resize: vertical;") .form-group diff --git a/views/module/common/share.pug b/views/module/common/share.pug index 4a37641e1..f72da67a4 100644 --- a/views/module/common/share.pug +++ b/views/module/common/share.pug @@ -1,6 +1,6 @@ .share(data-bind="with: repository[M!M]") .shareBlock - .shareName Разместить в социальных сетях + .shareName Share in social networks .socials //ko foreach: {data:socials, as: 'social'} .social(data-bind="click: social.action, style: {backgroundImage: 'url(\"'+ social.icon + '\")'}, attr: {title: social.name}") @@ -8,18 +8,18 @@ //ko if: options.linkPage hr .shareBlock - .shareName Ссылка на страницу + .shareName Link to this page .inputWrap .input-group(data-bind="style: {width: (location.host+options.linkPage).length * 7 + 30 + 'px'}") input.form-control.inputLink(type="url", readonly, data-bind="click: linkClick, value: location.host + options.linkPage", autocorrect="off", autocapitalize="off") - .input-group-addon.form-control.copy(title="Скопировать адрес в буфер обмена" data-bind="click: copyClick") + .input-group-addon.form-control.copy(title="Copy link to clipboard" data-bind="click: copyClick") // /ko //ko if: options.linkObject hr .shareBlock - .shareName Ссылка на изображение + .shareName Link to image .inputWrap .input-group(data-bind="style: {width: (location.host+options.linkObject).length * 7 + 'px'}") input.form-control.inputLink(type="url", readonly, data-bind="click: linkClick, value: location.host + options.linkObject", autocorrect="off", autocapitalize="off") - .input-group-addon.form-control.copy(title="Скопировать адрес в буфер обмена" data-bind="click: copyClick") + .input-group-addon.form-control.copy(title="Copy link to clipboard" data-bind="click: copyClick") // /ko diff --git a/views/module/common/top.pug b/views/module/common/top.pug index 1297c569a..e3d82d0cc 100644 --- a/views/module/common/top.pug +++ b/views/module/common/top.pug @@ -1,22 +1,22 @@ #top(data-bind="with: repository[M!M]") .fringe#panel - a#brand(href='/', title="PastVu - ретроспектива среды обитания человечества") + a#brand(href='/', title="PastVu - retro photo of mankind's habitat") img.logo(src="/img/misc/logow.png") .name(data-bind="html: pageTitle()") #panelTools.hide-text //ko if: auth.loggedIn() && !auth.iAm.nophotoupload() a#toUpload.labledIco.strokeAfter(href="/photoUpload") .glyphicon.glyphicon-cloud-upload - .text Загрузить фото + .text Upload photo // /ko a#gallery.labledIco.strokeAfter(href="/ps") .glyphicon.glyphicon-th - .text Галерея + .text Gallery //ko if: auth.loggedIn() //ko if: can.adm() a#toAdmin.labledIco.strokeAfter(href="/admin", target="_blank") .glyphicon.glyphicon-cog - .text Админ + .text Admin // /ko a#toProfile.labledIco(data-bind="attr:{href: '/u/'+auth.iAm.login()}") .ico.fringe(data-bind="style: {backgroundImage: 'url('+profileAvatar()+')'}") @@ -25,14 +25,14 @@ //ko if: !auth.loggedIn() #toRegister.labledIco(data-bind="click: function(data, evt){auth.show('reg')}") .ico - .text Регистрация + .text Sign Up #toLogIn.labledIco.strokeBefore.iconAfter(data-bind="click: function(data, evt){auth.show('login')}") - .text Вход + .text Log In .ico // /ko //ko if: auth.loggedIn() #toLogOut.labledIco.strokeBefore.iconAfter(data-bind="click: function(data, evt){auth.doLogout()}") - .text Выход + .text Log Out .ico // /ko #lang.labledIco.strokeBefore(data-bind="click: langClick") diff --git a/views/module/diff/about.pug b/views/module/diff/about.pug index 7b35bef12..44f28cb75 100644 --- a/views/module/diff/about.pug +++ b/views/module/diff/about.pug @@ -1,25 +1,25 @@ .about(data-bind="with: repository[M!M]") header.line - | PastVu — проект по сбору свидетельств прошлого. Взгляд на историю среды обитания человечества. + | PastVu — project to collect vintage images. A look at the history of humanity habitat. .postrow div.line - | Подробная информация о проекте находится  - a(target="_blank", data-bind="attr: {href: getAboutUrl()}") в базе знаний + | More detailed information on project is in  + a(target="_blank", data-bind="attr: {href: getAboutUrl()}") documentation resources | . div.line - | Открытая разработка ведется  - a(target="_blank", href="https://github.com/PastVu") на GitHub - | . Следите за выполнением задач и принимайте участие в развитии! + | Open development is on  + a(target="_blank", href="https://github.com/PastVu") GitHub + | . You can track issues progress and participate in development! .postrow hr div.line - | Версия приложения  + | Webapp version  span(data-bind="text: version") - | . Исходный код доступен по лицензии  + | . Source code is licensed under  a(target="_blank", href="https://github.com/PastVu/pastvu/blob/master/COPYING") GNU AGPL v3.0 | . div.line - | Данные по границам географических и административных регионов: ©  + | Administrative and geographic boundaries data: ©  a(target="_blank", href="https://www.openstreetmap.org/copyright") OpenStreetMap contributors | . .postrow diff --git a/views/module/diff/news.pug b/views/module/diff/news.pug index 991df04b4..d8ed021a1 100644 --- a/views/module/diff/news.pug +++ b/views/module/diff/news.pug @@ -1,5 +1,5 @@ .newsApart(data-bind="with: repository[M!M]") - .newsHeader Новости проекта + .newsHeader Project news .news .novelAuthor @@ -17,7 +17,7 @@ .dotDelimeter · a.newsEdit(data-bind="attr: {href: '/admin/news/edit/' + news.cid()}") span.glyphicon.glyphicon-pencil - | Редактировать + | Edit // /ko .newsTxt(data-bind="html: news.txt()") hr diff --git a/views/module/diff/newsList.pug b/views/module/diff/newsList.pug index f6684355d..b3bf405a4 100644 --- a/views/module/diff/newsList.pug +++ b/views/module/diff/newsList.pug @@ -1,10 +1,10 @@ .newsWrapper(data-bind="with: repository[M!M]") - .newsHeader Новости проекта + .newsHeader Project news //ko if: canEdit() .row a.addNews(href="/admin/news/create") span.glyphicon.glyphicon-plus - | Добавить новость + | Add news // /ko .news //ko foreach: news @@ -15,7 +15,7 @@ img(data-bind="attr: {src: $data.user.avatar}") .newsDate(data-bind="text: moment($data.pdate).format('D MMM YYYY')") //ko if: $data.ccount - a.comm(data-bind="html: $root.intl.num($data.ccount) + ($data.ccount_new ? ' +' + $root.intl.num($data.ccount_new) + '' : ''), attr: {href: '/news/' + $data.cid + '?hl=comments'}", title="Перейти к комментариям новости") + a.comm(data-bind="html: $root.intl.num($data.ccount) + ($data.ccount_new ? ' +' + $root.intl.num($data.ccount_new) + '' : ''), attr: {href: '/news/' + $data.cid + '?hl=comments'}", title="Jump to news comments") // /ko .newsBody .newsHead @@ -26,7 +26,7 @@ .dotDelimeter · a.newsEdit(data-bind="attr: {href: '/admin/news/edit/' + $data.cid}") span.glyphicon.glyphicon-pencil - | Редактировать + | Edit // /ko //ko if: $parent.canEdit() && !$data.ccount .dotDelimeter · @@ -36,6 +36,6 @@ // /ko .newsNotice(data-bind="html: $data.notice, css: {expandable: $data.expand}") //ko if: $data.expand - a.newsExpand(data-bind="attr: {href: '/news/' + $data.cid}") [Читать полностью..] + a.newsExpand(data-bind="attr: {href: '/news/' + $data.cid}") [Read more..] // /ko // /ko diff --git a/views/module/main/bottomPanel.pug b/views/module/main/bottomPanel.pug index f673fa91e..ea61b3dac 100644 --- a/views/module/main/bottomPanel.pug +++ b/views/module/main/bottomPanel.pug @@ -1,7 +1,7 @@ .bottomPanel(data-bind="with: repository[M!M]") //ko if: news().length > 0 .news - .newsHeader Новости проекта + .newsHeader Project news //ko foreach: news //ko if: $index() hr @@ -10,13 +10,13 @@ .newsLeft .newsDate(data-bind="text: moment($data.pdate).format('D MMM')") //ko if: $data.ccount - a.newsComms(data-bind="html: $root.intl.num($data.ccount) + ($data.ccount_new ? '
+' + $root.intl.num($data.ccount_new) + '
' : ''), attr: {href: '/news/' + $data.cid + '?hl=comments'}", title="Перейти к комментариям новости") + a.newsComms(data-bind="html: $root.intl.num($data.ccount) + ($data.ccount_new ? '
+' + $root.intl.num($data.ccount_new) + '
' : ''), attr: {href: '/news/' + $data.cid + '?hl=comments'}", title="Jump to news comments") // /ko .newsBody a.newsTitle(data-bind="text: $data.title, attr: {href: '/news/' + $data.cid}") .newsNotice(data-bind="html: $data.notice") //ko if: $data.expand - a.newsExpand(data-bind="attr: {href: '/news/' + $data.cid}") [Читать полностью..] + a.newsExpand(data-bind="attr: {href: '/news/' + $data.cid}") [Read more..] // /ko // /ko // /ko @@ -28,7 +28,7 @@ // /ko li a(target="_blank", href="/news") - | Архив новостей + | News archive span.glyphicon.glyphicon-share //ko if: catActive() .catContent(data-bind="template: catsObj[catActive()].tpl") @@ -42,7 +42,7 @@ img.img(data-bind="attr: {src: sfile, alt: title}, event: {load: $parent.onPreviewLoad, error: $parent.onPreviewErr}") .curtain //ko if: $data.my - .status.upper.mine.fringe(title="Это ваша фотография") + .status.upper.mine.fringe(title="It is your photo") span.glyphicon.glyphicon-user // /ko .info @@ -50,7 +50,7 @@ //ko if: $data.rs .regions(data-bind="foreach: $data.rs", title=" ") | , - a.shortRegion(data-bind="css: {where: !$data.cid}, attr: {href: '/ps?f='+(!$data.cid ? 'geo!0'+($parent.rs[$index()+1] ? '_r!'+$parent.rs[$index()+1].cid : '') : 'r!'+$data.cid), title: $data.title_local}, text: $data.title_local") + a.shortRegion(data-bind="css: {where: !$data.cid}, attr: {href: '/ps?f='+(!$data.cid ? 'geo!0'+($parent.rs[$index()+1] ? '_r!'+$parent.rs[$index()+1].cid : '') : 'r!'+$data.cid), title: $data.title_en}, text: $data.title_en") // /ko //ko if: $data.ccount || $data.changed .rightBlocks @@ -58,7 +58,7 @@ a.rightBlock.comm(data-bind="html: $root.intl.num($data.ccount) + ($data.ccount_new ? ' +' + $root.intl.num($data.ccount_new) + '' : ''), attr: {href: $data.link + '?hl=comments'}", title="Комментарии") // /ko //ko if: $data.changed - a.rightBlock.changed(data-bind="attr: {href: $data.link + '?history=1'}", title="Фотография изменена с момента прошлого просмотра") + a.rightBlock.changed(data-bind="attr: {href: $data.link + '?history=1'}", title="Photo has been changed since last view") span.glyphicon.glyphicon-pencil // /ko // /ko @@ -67,48 +67,48 @@ a.photoPreview.withInfo.nextPhoto(data-bind="attr: {href: moreLink()}") .nextPhotoTxt span.glyphicon.glyphicon-fast-forward - | Еще.. + | More.. // /ko | | @@ -127,29 +127,29 @@ .onlineStat(data-bind="text: stats.common.onlineTxt") .row .col-xs-12 - .catHead Весь проект + .catHead The entire project .statrow - = 'Зарегистрированных пользователей: ' + = 'Registered users: ' b(data-bind="text: $root.intl.num(stats.all.userCount)") .statrow - = 'Фотографий: ' - b(data-bind="text: $root.intl.num(stats.all.pallCount) + (auth.loggedIn() ? ', из них ' + $root.intl.num(stats.all.ppubCount) + ' публичных' : '')") + = 'Photos: ' + b(data-bind="text: $root.intl.num(stats.all.pallCount) + (auth.loggedIn() ? ', of which ' + $root.intl.num(stats.all.ppubCount) + ' are public' : '')") .statrow - span(data-bind="text: 'Больше всего фотографий относится к ' + stats.all.photoYear.pop.year + ' году, их '") + span(data-bind="text: 'Vast majority of photos refers to ' + stats.all.photoYear.pop.year + ' year, '") b(data-bind="text: $root.intl.num(stats.all.photoYear.pop.count)") .statrow - = 'Сегодня новых фотографий: ' + = 'New photos today: ' b(data-bind="text: $root.intl.num(stats.all.pdayCount)") .statrow - = 'За неделю новых фотографий: ' + = 'New photos this week: ' b(data-bind="text: $root.intl.num(stats.all.pweekCount)") .statrow - = 'Комментариев: ' - b(data-bind="text: $root.intl.num(stats.all.callCount)+ (auth.loggedIn() ? ', из них ' + $root.intl.num(stats.all.callCount - stats.all.cpubCount) + ' удаленных' : '')") + = 'Comments: ' + b(data-bind="text: $root.intl.num(stats.all.callCount)+ (auth.loggedIn() ? ', of which ' + $root.intl.num(stats.all.callCount - stats.all.cpubCount) + ' are deleted' : '')") .statrow - = 'Сегодня новых комментариев: ' + = 'Today new comments: ' b(data-bind="text: $root.intl.num(stats.all.cdayCount)") .statrow - = 'За неделю новых комментариев: ' + = 'New comments this week: ' b(data-bind="text: $root.intl.num(stats.all.cweekCount)") | \ No newline at end of file diff --git a/views/module/main/commentsFeed.pug b/views/module/main/commentsFeed.pug index a1f2492b8..b82d4a0b5 100644 --- a/views/module/main/commentsFeed.pug +++ b/views/module/main/commentsFeed.pug @@ -1,7 +1,7 @@ .commentsFeed(data-bind="with: repository[M!M]") //-a.help(href="http://start.planeta.ru/campaigns/1694", target="_blank", title="Узнайте как помочь проекту") img.img-responsive.helpimg(data-bind="attr: {src: '/img/misc/fund2/bn_right_' + _.random(1,4) + '.jpg'}", alt="Помогите PastVu") - .ribbonHead.lineBehind: span Новые комментарии + .ribbonHead.lineBehind: span New comments .commentsBody | \ No newline at end of file diff --git a/views/module/photo/hist.pug b/views/module/photo/hist.pug index 7a584fbcd..5cc5713c6 100644 --- a/views/module/photo/hist.pug +++ b/views/module/photo/hist.pug @@ -1,16 +1,16 @@ .objHist(data-bind="with: repository[M!M]") // ko if: haveDiff() - .diffSwitch(data-bind="text: showDiff() ? 'Скрыть подсветку разницы значений' : 'Показать разницу значений', click: switchDiff") + .diffSwitch(data-bind="text: showDiff() ? 'Hide difference highlighting' : 'Show difference highlighting', click: switchDiff") // /ko ul.media-list.hists //ko if: haveDiff() && switchDiff2() - .diffSwitch(data-bind="text: showDiff() ? 'Скрыть подсветку разницы значений' : 'Показать разницу значений', click: switchDiff") + .diffSwitch(data-bind="text: showDiff() ? 'Hide difference highlighting' : 'Show difference highlighting', click: switchDiff") // /ko | @@ -35,10 +35,10 @@ a.author(target="_blank", href="{{='/u/'+h.user.login}}") {{=h.user.disp}} ='{{?h.role}} ' .role - | {{?h.role===5}}как модератор - | {{?h.roleregion}} региона  - a(target="_blank", href="{{='/ps?f=r!' + h.roleregion.cid}}") {{=h.roleregion.title_local}}{{?}} - | {{??h.role>9}}как администратор{{?}} + | {{?h.role===5}}as moderator + | {{?h.roleregion}} of region  + a(target="_blank", href="{{='/ps?f=r!' + h.roleregion.cid}}") {{=h.roleregion.title_en}}{{?}} + | {{??h.role>9}}as administrator{{?}} | {{?}} .dotDelimeter · a.histStamp(data-replace="true", href="/p/{{=it.cid}}?history={{=h.stamp}}") {{=it.fDate(new Date(h.stamp))}} @@ -52,7 +52,7 @@ | {{?h.del}} .info.red.iconed span.glyphicon.glyphicon-minus - | Удален{{?h.del.length>1}}ы{{??}}о{{?}}: + | Removed{{?h.del.length>1}}{{??}}{{?}}: | {{~h.del :del:delIndex}} | {{?delIndex}},{{?}} span.del {{=it.fields[del]}} @@ -62,7 +62,7 @@ | {{?h.values.nocomments !== undefined}} .info.iconed(class="{{?h.values.nocomments}}red{{??}}green{{?}}") span.glyphicon(class="glyphicon-{{?h.values.nocomments}}ban-circle{{??}}ok{{?}}") - | Комментирование {{?h.values.nocomments}}запрещено{{??}}разрешено{{?}} + | Commenting is {{?h.values.nocomments}}forbidden{{??}}allowed{{?}} | {{?}} | {{?h.values.histmissing}} @@ -73,7 +73,7 @@ | {{?h.reason}} .value - .name Причина + .name Reason .val | {{?h.reason.cid}}{{=it.reasonsHash[h.reason.cid].title}}{{?}} | {{?h.reason.desc}} diff --git a/views/module/photo/photo.pug b/views/module/photo/photo.pug index 580567742..a9ee4fd95 100644 --- a/views/module/photo/photo.pug +++ b/views/module/photo/photo.pug @@ -38,21 +38,21 @@ .tool.type .tltp-wrap span.glyphicon.light(data-bind="css: {'glyphicon-camera': !isPainting(), 'glyphicon-picture': isPainting()}") - .tltp.tltp-right.tltp-animate-move(data-bind="text: isPainting() ? 'Картина/рисунок' : 'Фотография'") + .tltp.tltp-right.tltp-animate-move(data-bind="text: isPainting() ? 'Painting' : 'Photo'") .tool.watched - span.glyphicon.glyphicon-eye-open.light(title="Количество просмотров изображения") + span.glyphicon.glyphicon-eye-open.light(title="Number of image views") .tltp-wrap .watch(data-bind="text: toolsNumFormat(p.vdcount())") - .tltp.tltp-right.tltp-animate-move(data-bind="text: $root.intl.num(p.vdcount())+ ' раз смотрели сегодня'") + .tltp.tltp-right.tltp-animate-move(data-bind="text: $root.intl.num(p.vdcount())+ ' views today'") .tltp-wrap .watch(data-bind="text: toolsNumFormat(p.vwcount())") - .tltp.tltp-right.tltp-animate-move(data-bind="text: $root.intl.num(p.vwcount())+ ' раз смотрели за неделю'") + .tltp.tltp-right.tltp-animate-move(data-bind="text: $root.intl.num(p.vwcount())+ ' views this week'") .tltp-wrap .watch(data-bind="text: toolsNumFormat(p.vcount())") - .tltp.tltp-right.tltp-animate-move(data-bind="text: $root.intl.num(p.vcount())+ ' раз смотрели всего'") + .tltp.tltp-right.tltp-animate-move(data-bind="text: $root.intl.num(p.vcount())+ ' views total'") .toolsBtm(data-bind="style: {width: ws() + 'px'}") span.toolsTxt - | Размеры:  + | Sizes:  //ko if: ws() !== p.ws() && hs() !== p.hs() .sizeThis(data-bind="text: ws() + '×' + hs()") |  |  @@ -65,30 +65,26 @@ button.btn.btn-xxs.btn-primary(data-state="hscaleTumbler", data-bind="css: {active: hscaleTumbler()}, click: stateChange") span.glyphicon.glyphicon-resize-vertical .tltp.tltp-bottom.tltp-animate-move - = 'Подгонять по высоте' + = 'Adjust by the height' br - = 'видимой области' + = 'of the visible area' // /ko .tltp-wrap button.btn.btn-xxs.btn-primary(data-state="watermarkShow", data-bind="css: {active: watermarkShow()}, click: stateChange") | W - .tltp.tltp-bottom.tltp-animate-move - = 'Показывать вотермарк' - br - = 'на изображении' + .tltp.tltp-bottom.tltp-animate-move Show watermark //ko if: p.s()===statuses.keys.PUBLIC .tltp-wrap a.btn.btn-xxs.btn-primary(href="?share=1", data-replace="true") span.glyphicon.glyphicon-share-alt - .tltp.tltp-bottom.tltp-animate-move Поделиться + .tltp.tltp-bottom.tltp-animate-move Share // /ko //ko if: can.download() && !edit() .tltp-wrap a.btn.btn-xxs(data-bind="click: download, css: downloadCSSClass(), attr: {href: p.fileroot()+'/a/'+p.file(), download:p.cid()+' '+(p.title()||'').replace(/[\/|]/g, '-')+'.jpg'}") span.glyphicon.glyphicon-save - .tltp.tltp-bottom.tltp-animate-move(data-bind="html:'Скачать '+(downLoadOrigin()?'оригинал':'в полном размере')+'
'+p.w() + '×' + p.h()") + .tltp.tltp-bottom.tltp-animate-move(data-bind="html:'Download '+(downLoadOrigin()?'original':'full size')+'
'+p.w() + '×' + p.h()") // /ko - //ko template: {name: edit() ? p.type() === '2' ? 'paintingEdit' : 'photoEdit' : 'photoView', afterRender: tplAfterRender} // /ko .col-xs-12.col-sm-4.col-lg-4.rightPanel @@ -113,7 +109,7 @@ // /ko .rightrow.photoMap.mContainer.mHidden(data-bind="allowBindings: false, style: {height: mapH()}") //ko if: nearestRibbon().length - .rightrow: .lineBehind: span Ближайшие изображения + .rightrow: .lineBehind: span Nearby images .rightrow.nearesTiles(data-bind="foreach: nearestRibbon") a.photoPreview(data-bind="attr: {href: '/p/' + cid, title: $data.title}"): .photoBox img.img(data-bind="attr: {src: sfile, title: $data.title}, event: {load: $parent.onPreviewLoad, error: $parent.onPreviewErr}, style: {width: $parent.thumbW, height: $parent.thumbH}") @@ -126,57 +122,57 @@ //ko if: can.edit() button.btn.btn-primary(type="button", data-bind="click: editSave, attr: {disabled: exe()}") span.glyphicon.glyphicon-pencil - | Редактировать + | Edit // /ko //ko if: can.ready() - button.btn.btn-success(type="button", title="Отправить на премодерацию и дальнейшую публикацию", data-bind="click: ready, attr: {disabled: exe()}") + button.btn.btn-success(type="button", title="Send to premoderation and further publishing", data-bind="click: ready, attr: {disabled: exe()}") span.glyphicon.glyphicon-check - | На публикацию + | To publishing // /ko //ko if: can.approve() - button.btn.btn-success(type="button", title="Подтвердить и опубликовать эту фотографию", data-bind="click: approve, attr: {disabled: exe()}") + button.btn.btn-success(type="button", title="Confirm and publish this photo", data-bind="click: approve, attr: {disabled: exe()}") span.glyphicon.glyphicon-ok - | Опубликовать + | Publish // /ko //ko if: can.revision() - button.btn.btn-warning(type="button", title="Отправить пользователю на доработку", data-bind="click: toRevision, attr: {disabled: exe()}") + button.btn.btn-warning(type="button", title="Send to user for revision", data-bind="click: toRevision, attr: {disabled: exe()}") span.glyphicon.glyphicon-check - | На доработку + | To revision // /ko //ko if: can.rereject() button.btn.btn-success(type="button", data-bind="click: rereject, attr: {disabled: exe()}") span.glyphicon.glyphicon-repeat - span Восстановить + span Restore // /ko //ko if: can.revoke() - button.btn.btn-danger(type="button", data-bind="click: revoke, attr: {disabled: exe()}", title="Отозвать эту фотографию, снять с возможной публикации") + button.btn.btn-danger(type="button", data-bind="click: revoke, attr: {disabled: exe()}", title="Revoke this photo from possible publication") span.glyphicon.glyphicon-remove - | Отозвать + | Revoke // /ko //ko if: can.reject() - button.btn.btn-danger(type="button", data-bind="click: reject, attr: {disabled: exe()}", title="Отклонить фотографию, снять с возможной публикации") + button.btn.btn-danger(type="button", data-bind="click: reject, attr: {disabled: exe()}", title="Reject this photo from possible publication") span.glyphicon.glyphicon-remove - | Отклонить + | Reject // /ko //ko if: can.activate() button.btn.btn-success(type="button", data-bind="click: toggleDisable, attr: {disabled: exe()}") span.glyphicon.glyphicon-ok-sign - | Активировать + | Activate // /ko //ko if: can.deactivate() button.btn.btn-warning(type="button", data-bind="click: toggleDisable, attr: {disabled: exe()}") span.glyphicon.glyphicon-exclamation-sign - | Деактивировать + | Deactivate // /ko //ko if: can.remove() button.btn.btn-danger(type="button", data-bind="click: remove, attr: {disabled: exe()}") span.glyphicon.glyphicon-trash - | Удалить + | Remove // /ko //ko if: can.restore() button.btn.btn-success(type="button", data-bind="click: restore, attr: {disabled: exe()}") span.glyphicon.glyphicon-repeat - span Восстановить + span Restore // /ko | @@ -184,10 +180,10 @@ | @@ -206,7 +202,7 @@ //ko if: p.regions().length .tltp.tltp-top.tltp-touch.tltp-hotizontal-left.tltp-animate-opacity.rytltp.ytltp(data-bind="foreach: p.regions") .yregion - a(data-bind="text:$parent.p.year()+' '+$data.title_local(), attr: {href: '/ps?f=r!'+$data.cid()+'_y!'+$parent.p.year()+'!'+$parent.p.year()}") + a(data-bind="text:$parent.p.year()+' '+$data.title_en(), attr: {href: '/ps?f=r!'+$data.cid()+'_y!'+$parent.p.year()+'!'+$parent.p.year()}") // /ko // /ko //ko if: p.year2() && p.year() !== p.year2() @@ -216,14 +212,14 @@ //ko if: p.regions().length .tltp.tltp-top.tltp-touch.tltp-hotizontal-left.tltp-animate-opacity.rytltp.ytltpBetween(data-bind="foreach: p.regions") .yregion - a(data-bind="text:$parent.p.year()+' – '+$parent.p.year2()+' '+$data.title_local(), attr: {href: '/ps?f=r!'+$data.cid()+'_y!'+$parent.p.year()+'!'+$parent.p.year2()}") + a(data-bind="text:$parent.p.year()+' – '+$parent.p.year2()+' '+$data.title_en(), attr: {href: '/ps?f=r!'+$data.cid()+'_y!'+$parent.p.year()+'!'+$parent.p.year2()}") // /ko span.tltp-wrap.rytltp-wrap a(data-bind="text:p.year2(), attr: {href:'/ps?f=y!'+p.year2()+'!'+p.year2()}") //ko if: p.regions().length .tltp.tltp-top.tltp-touch.tltp-hotizontal-left.tltp-animate-opacity.rytltp.ytltp2(data-bind="foreach: p.regions") .yregion - a(data-bind="text:$parent.p.year2()+' '+$data.title_local(), attr: {href: '/ps?f=r!'+$data.cid()+'_y!'+$parent.p.year2()+'!'+$parent.p.year2()}") + a(data-bind="text:$parent.p.year2()+' '+$data.title_en(), attr: {href: '/ps?f=r!'+$data.cid()+'_y!'+$parent.p.year2()+'!'+$parent.p.year2()}") // /ko // /ko @@ -236,11 +232,11 @@ .region .tltp-wrap.rytltp-wrap |   - a(data-bind="text: $data.title_local(), attr: {href: '/ps?f=r!' + $data.cid()}") + a(data-bind="text: $data.title_en(), attr: {href: '/ps?f=r!' + $data.cid()}") //ko if: $parent.IAdmin() || $data.phc() || $data.pac() || $data.cc() .tltp.tltp-top.tltp-touch.tltp-animate-opacity.rytltp(data-bind="css: {'tltp-hotizontal-left': !$index()}") //ko if: $parent.IAdmin() - .region-type-stat.region-type-stat-clickable(title="Перейти в редактирование региона", style="margin:1px 0;padding-right:4px;border-right:1px solid #e8e8e8;") + .region-type-stat.region-type-stat-clickable(title="Edit region", style="margin:1px 0;padding-right:4px;border-right:1px solid #e8e8e8;") a(data-bind="attr: {href: '/admin/region/' + $data.cid()}", style="color:orange;") span.glyphicon.glyphicon-pencil // /ko @@ -266,7 +262,7 @@ //ko if: !p.geo() =', ' .region - a(data-bind="text: 'Где это?', attr: {href: '/ps?f=geo!0_r!' + p.regions()[p.regions().length-1].cid()}", style="color: #BEA265;") + a(data-bind="text: 'Where is it?', attr: {href: '/ps?f=geo!0_r!' + p.regions()[p.regions().length-1].cid()}", style="color: #BEA265;") // /ko // /ko //ko if: p.desc().length @@ -303,7 +299,7 @@ //ko if: p.cdate .infoBlock .info - a(href="?history=1", data-replace="true", data-bind="css: {changed: p.changed()}, html: 'Последнее изменение ' + fDateIn(p.cdate())") + a(href="?history=1", data-replace="true", data-bind="css: {changed: p.changed()}, html: 'Last changed at ' + fDateIn(p.cdate())") // /ko //-a.help.visible-lg(href="http://start.planeta.ru/campaigns/1694", target="_blank", title="Узнайте как помочь проекту") @@ -314,7 +310,7 @@ | @@ -438,7 +434,7 @@ | diff --git a/views/module/region/select.pug b/views/module/region/select.pug index 3219acefe..d33c7a58c 100644 --- a/views/module/region/select.pug +++ b/views/module/region/select.pug @@ -1,51 +1,51 @@ .regsel(data-bind="with: repository[M!M]") //ko if: loading() - .loading Загрузка + .loading Loading // /ko //ko ifnot: loading() h4.namehead span.glyphicon.glyphicon-globe - span(data-bind="text: ' Выбор регион' + (options.max > 1 ? 'ов' : 'а')") - abbr(style="margin-left:5px;vertical-align:middle;font-size:10px;", title="Для каждого региона указано кол-во публичный изображений и не удаленных комментариев") + span(data-bind="text: ' Region' + (options.max > 1 ? 's' : '') + ' select'") + abbr(style="margin-left:5px;vertical-align:middle;font-size:10px;", title="For each region specified number of public images and deleted comments") span.glyphicon.glyphicon-info-sign .offsetwrap - div Вводите имя региона непосредственно в поле выбора или найдите его вручную в дереве регионов ниже + div Type the name of the region directly in the input or find it in the below tree //ko if: options.max > 1 - div(data-bind="text: 'Возможно выбрать ' + (options.min ? 'от ' + options.min: '')+ ' до ' + options.max + ' регионов, они не должны быть вложены друг в друга'") + div(data-bind="text: 'Allowed to select ' + (options.min ? 'from ' + options.min: 'up ')+ ' to ' + options.max + ' regions, they should not be nested within each other'") // /ko .inputwrap.surrogate .inputwrap.origin .input-group.regionsgroup - span.input-group-addon Выбор: - input.regionstkn.form-control(type="text", placeholder="Начните вводить имя региона") + span.input-group-addon Selection: + input.regionstkn.form-control(type="text", placeholder="Start typing region name") .offsetwrap .regionsHead - = 'Сортировать по: ' - .sortOption(data-bind="click:sortByAlphabet, css: {'selected':sortBy()==='alphabet'}") алфавиту - = ', количеству: ' + = 'Sort by: ' + .sortOption(data-bind="click:sortByAlphabet, css: {'selected':sortBy()==='alphabet'}") alphabet + = ', number of: ' = ' ' - .sortOption(data-bind="click:sortByPhoto, css: {'selected':sortBy()==='photo'}") фотографий + .sortOption(data-bind="click:sortByPhoto, css: {'selected':sortBy()==='photo'}") photos = ', ' - .sortOption(data-bind="click:sortByPic, css: {'selected':sortBy()==='pic'}") картин + .sortOption(data-bind="click:sortByPic, css: {'selected':sortBy()==='pic'}") pictures = ', ' - .sortOption(data-bind="click:sortByComment, css: {'selected':sortBy()==='comment'}") комментариев + .sortOption(data-bind="click:sortByComment, css: {'selected':sortBy()==='comment'}") comments = ', ' - .sortOption(data-bind="click:sortBySub, css: {'selected':sortBy()==='sub'}") подрегионов + .sortOption(data-bind="click:sortBySub, css: {'selected':sortBy()==='sub'}") subregions .offsetwrap .regionsHead .headElem.interact(data-bind="click: expandAll") span.glyphicon.glyphicon-plus - | Раскрыть все + | Expand all .headElem.interact(data-bind="click: collapseAll") span.glyphicon.glyphicon-minus - | Свернуть все + | Collapse all //ko if: auth.loggedIn() && auth.iAm.regionHome.cid() && topCidsFilter.length === 0 label.checkbox-inline(style="margin-left:10px;padding-left:10px;") input(type="checkbox", data-bind="checked: pinHome", style="margin-left:-15px;") - | Прикрепить домашний регион + | Pin home region // /ko .tree ul(data-bind="template: {name: 'treeNode', foreach: regionsTree}") @@ -55,33 +55,33 @@ li(data-bind="css: {isparent: $data.childLen}") .lirow(data-bind="css: {selected: $data.selected(), selectable: $data.selectable()}") //ko if: $data.childLen - .chevron(data-bind="click: $data.collapseToggle, attr: {title: ($data.opened() ? 'Скрыть' : 'Раскрыть') + ' дочерние регионы'}") + .chevron(data-bind="click: $data.collapseToggle, attr: {title: ($data.opened() ? 'Collapse' : 'Expand') + ' children regions'}") span.glyphicon(data-bind="css: {'glyphicon-minus': $data.opened(), 'glyphicon-plus': !$data.opened()}") // /ko - .rname(data-bind="click: $data.clickNode, attr: {title: $data.selected() ? 'Снять выбор' : ($data.selectable() ? 'Выбрать регион' : '')}") - .name(data-bind="text: ' ' + $data.title_local, css: {'nameborder': $data.phc || $data.pac || $data.cc}") + .rname(data-bind="click: $data.clickNode, attr: {title: $data.selected() ? 'Deselect region' : ($data.selectable() ? 'Select region' : '')}") + .name(data-bind="text: ' ' + $data.title_en, css: {'nameborder': $data.phc || $data.pac || $data.cc}") //ko if: $data.phc - .section(title="Фотографии") + .section(title="Photos") span.glyphicon.glyphicon-camera span(data-bind="text: ' ' + $root.intl.num($data.phc)") // /ko //ko if: $data.pac - .section(title="Картины") + .section(title="Paintings") span.glyphicon.glyphicon-picture span(data-bind="text: ' ' + $root.intl.num($data.pac)") // /ko //ko if: $data.cc - .section(title="Комментарии") + .section(title="Comments") span.glyphicon.glyphicon-comment(style="vertical-align:text-top;") span(data-bind="text: ' ' + $root.intl.num($data.cc)") // /ko //ko if: $data.childLen - .section(title="Подрегионы") + .section(title="Subregions") span.glyphicon.glyphicon-play(style="vertical-align:text-top;") span(data-bind="text: ' ' + $root.intl.num($data.childLen)") // /ko //ko if: $data.home - .home(title="Домашний регион"): span.glyphicon.glyphicon-home + .home(title="Home region"): span.glyphicon.glyphicon-home //ko if: $parents[$data.level].pinHome() && !$data.opened() hr.homeDivider // /ko diff --git a/views/module/user/brief.pug b/views/module/user/brief.pug index d0c281acc..eb99f857e 100644 --- a/views/module/user/brief.pug +++ b/views/module/user/brief.pug @@ -1,55 +1,55 @@ .user_brief(data-bind="with: repository[M!M]") - .briefBlock - .avatar.fringe - img(data-bind="attr: {src: user.avatar(), alt: user.disp()}, event: {load: onAvaLoad, error: onAvaError}") - //ko if: avaexe() - .avaLoadCurtain - // /ko - //ko if: canAva() - button.btn.btn-sm.btn-primary.avaEdit(data-bind="click: avaActionToggle, css: {disabled: avaexe()}, attr: {disabled: avaexe()}", title="Редактировать аватару") - span.glyphicon.glyphicon-pencil - //ko if: avaction() - .avaAction - input.avaInput(type="file", name="files[]") - button.btn.btn-primary.avaSelect(data-bind="click: avaSelect, css: {disabled: avaexe()}, attr: {disabled: avaexe()}", title="Загрузить новое изображение") - span.glyphicon.glyphicon-cloud-upload - | Сменить - //ko if: avaExists() - button.btn.btn-primary.avaDel(data-bind="click: avaDel, css: {disabled: avaexe()}, attr: {disabled: avaexe()}", title="Удалить загруженное изображение") - span.glyphicon.glyphicon-remove - | Удалить - // /ko - // /ko - // /ko + .briefBlock + .avatar.fringe + img(data-bind="attr: {src: user.avatar(), alt: user.disp()}, event: {load: onAvaLoad, error: onAvaError}") + //ko if: avaexe() + .avaLoadCurtain + // /ko + //ko if: canAva() + button.btn.btn-sm.btn-primary.avaEdit(data-bind="click: avaActionToggle, css: {disabled: avaexe()}, attr: {disabled: avaexe()}", title="Edit avatar") + span.glyphicon.glyphicon-pencil + //ko if: avaction() + .avaAction + input.avaInput(type="file", name="files[]") + button.btn.btn-primary.avaSelect(data-bind="click: avaSelect, css: {disabled: avaexe()}, attr: {disabled: avaexe()}", title="Upload new image") + span.glyphicon.glyphicon-cloud-upload + | Change + //ko if: avaExists() + button.btn.btn-primary.avaDel(data-bind="click: avaDel, css: {disabled: avaexe()}, attr: {disabled: avaexe()}", title="Remove image") + span.glyphicon.glyphicon-remove + | Remove + // /ko + // /ko + // /ko - .userName(data-bind="text: user.disp()") - //ko if: rn() - .roleName(data-bind="text: rn(), css: rc()") - // /ko + .userName(data-bind="text: user.disp()") + //ko if: rn() + .roleName(data-bind="text: rn(), css: rc()") + // /ko - //-.row(data-bind="style: {display: can_pm() ? '': 'none'}") - button.btn.btn-primary(type="button", data-bind="event: {}") - span.glyphicon.glyphicon-envelope - span Send message - .briefBlock - .head Общее - .h_separator - table.briefTable - tbody - tr - td Регистрация: - td(data-bind="text: moment(user.regdate()).format('D MMMM YYYY')") - tr - td Статус: - td(data-bind="text: user.online() ? 'Онлайн' : 'Оффлайн', css: {online : user.online()}") - .briefBlock - .head Краткая статистика - .h_separator - table.briefTable - tbody - tr - td Фотографий: - td(data-bind="text: $root.intl.num(user.pcount())") - tr - td Комментариев: - td(data-bind="text: $root.intl.num(user.ccount())") + //-.row(data-bind="style: {display: can_pm() ? '': 'none'}") + button.btn.btn-primary(type="button", data-bind="event: {}") + span.glyphicon.glyphicon-envelope + span Send message + .briefBlock + .head Common + .h_separator + table.briefTable + tbody + tr + td Registration: + td(data-bind="text: moment(user.regdate()).format('D MMMM YYYY')") + tr + td Status: + td(data-bind="text: user.online() ? 'Онлайн' : 'Оффлайн', css: {online : user.online()}") + .briefBlock + .head Brief statistics + .h_separator + table.briefTable + tbody + tr + td Photos: + td(data-bind="text: $root.intl.num(user.pcount())") + tr + td Comments: + td(data-bind="text: $root.intl.num(user.ccount())") diff --git a/views/module/user/comments.pug b/views/module/user/comments.pug index 9090f58bf..5fae461f1 100644 --- a/views/module/user/comments.pug +++ b/views/module/user/comments.pug @@ -1,20 +1,20 @@ .comments(data-bind="with: repository[M!M]") .top-select - h4(data-bind="text: itsMe()?'Ваши комментарии:':'Комментарии пользователя:'") + h4(data-bind="text: itsMe()?'Your comments:':'User comments:'") //ko if: itsMe() || auth.loggedIn() && auth.iAm.role() > 9 dd: span.panel-block(style="padding-bottom:5px;") label.checkbox-inline input(type="checkbox", value="active" data-bind="checked: statusesCheckboxed") - span(data-bind="text: 'Активные [' + $root.intl.num(statuses['active_persist']()) + ']'") + span(data-bind="text: 'Active [' + $root.intl.num(statuses['active_persist']()) + ']'") label.checkbox-inline input(type="checkbox", value="del" data-bind="checked: statusesCheckboxed") - span(data-bind="text: 'Удаленные ['+ $root.intl.num(statuses['del_persist']()) + ']'") + span(data-bind="text: 'Removed ['+ $root.intl.num(statuses['del_persist']()) + ']'") // /ko ul.nav.nav-tabs li(data-bind="css: {active: type() === 'photo'}") - a(data-bind="attr: {href: pageUrl() + getUrlParams(page(), 'photo', encodeStatuses())}, text: 'К изображениям [' + $root.intl.num(types['photo_persist']()) + ']'") + a(data-bind="attr: {href: pageUrl() + getUrlParams(page(), 'photo', encodeStatuses())}, text: 'Images [' + $root.intl.num(types['photo_persist']()) + ']'") li(data-bind="css: {active: type() === 'news'}") - a(data-bind="attr: {href: pageUrl() + getUrlParams(page(), 'news', encodeStatuses())}, text: 'К новостям [' + $root.intl.num(types['news_persist']()) + ']'") + a(data-bind="attr: {href: pageUrl() + getUrlParams(page(), 'news', encodeStatuses())}, text: 'News [' + $root.intl.num(types['news_persist']()) + ']'") .navContent .row .col-xs-6.col-md-3.topcol @@ -34,7 +34,7 @@ span.glyphicon(data-bind="css: $data.obj.status.icon") // /ko //ko if: $data.obj.my - .status.upper.mine.fringe(title="Это ваша фотография") + .status.upper.mine.fringe(title="It is your photo") span.glyphicon.glyphicon-user // /ko .commentHead @@ -43,7 +43,7 @@ a.commentStamp(data-bind="attr: {href: $data.link}, text: moment($data.stamp).calendar()") //ko if: $data.lastChanged .dotDelimeter · - .commentChanged(title="Показать историю изменений", data-bind="text: ($data.del ? 'Удален ' : 'Изменен ') + moment($data.lastChanged).calendar().toLowerCase(), click: function () {$parent.showHistory($data.obj.cid, $data.cid)}") + .commentChanged(title="Show history of changes", data-bind="text: ($data.del ? 'Removed at ' : 'Changed at ') + moment($data.lastChanged).calendar().toLowerCase(), click: function () {$parent.showHistory($data.obj.cid, $data.cid)}") // /ko a.commentText(data-bind="attr: {href: $data.link}, html: $data.txt") | @@ -56,18 +56,19 @@ a.commentStamp(data-bind="attr: {href: $data.link}, text: moment($data.stamp).calendar()") //ko if: $data.lastChanged .dotDelimeter · - .commentChanged(title="Показать историю изменений", data-bind="text: ($data.del ? 'Удален ' : 'Изменен ') + moment($data.lastChanged).calendar().toLowerCase(), click: function () {$parent.showHistory($data.obj.cid, $data.cid)}") + .commentChanged(title="Show history of changes", data-bind="text: ($data.del ? 'Removed at ' : 'Changed at ') + moment($data.lastChanged).calendar().toLowerCase(), click: function () {$parent.showHistory($data.obj.cid, $data.cid)}") // /ko a.commentText(style="margin-left:29px", data-bind="attr: {href: $data.link}, html: $data.txt") | | \ No newline at end of file + li.edge(data-bind="css: {disabled: !pageHasNext()}"): a(data-bind="attr: {href: pageUrl() + '/' + (page() + 1) + pageQuery()}", title="Next page") » + li.edge(data-bind="css: {disabled: page() === pageLast()}"): a(data-bind="attr: {href: pageUrl() + '/' + pageLast() + pageQuery()}", title="Last page") »» + | + diff --git a/views/module/user/manage.pug b/views/module/user/manage.pug index 4f7e5e3ae..8b3ecebb7 100644 --- a/views/module/user/manage.pug +++ b/views/module/user/manage.pug @@ -2,7 +2,7 @@ .panel-group#accordion .panel.panel-pastvu .panel-heading: .panel-title - a.accordion-toggle(data-toggle="collapse", href="#credentials") Полномочия + a.accordion-toggle(data-toggle="collapse", href="#credentials") Credentials .panel-collapse.collapse.in#credentials: .panel-body form .form-group @@ -13,145 +13,145 @@ .form-group: .col-xs-12 .checkbox: label input(type="checkbox", value = '5', data-bind="checked: role") - | Региональный:  + | Regions:  //ko if: !regions().length span.region span.glyphicon.glyphicon-globe - | Весь мир + | Whole world // /ko //ko foreach: regions - span.region.candrop(title="Убрать регион", data-bind="click: function() {$parent.regionDrop($data.cid);}") - span(data-bind="text: $data.title_local") + span.region.candrop(title="Remove region", data-bind="click: function() {$parent.regionDrop($data.cid);}") + span(data-bind="text: $data.title_en") // /ko span.regionEdit(data-bind="click: regionSelect") span.glyphicon.glyphicon-pencil - | Изменить + | Change .checkbox: label input(type="checkbox", disabled) - | Языковой + | Language // /ko //ko if: credentialsChanged() .form-group: .col-xs-12 button.btn.btn-sm.btn-success(type="button", data-bind="event: {click: saveCredentials}, attr: {disabled: exe()}") span.glyphicon.glyphicon-ok - | Сохранить полномочия + | Save credentials button.btn.btn-sm.btn-danger(type="button", data-bind="event: {click: cancelCredentials}, attr: {disabled: exe()}") span.glyphicon.glyphicon-remove - | Отмена + | Cancel // /ko .panel.panel-pastvu .panel-heading: .panel-title - a.accordion-toggle(data-toggle="collapse", href="#restrictions") Права и ограничения + a.accordion-toggle(data-toggle="collapse", href="#restrictions") Restrictions .panel-collapse.collapse.in#restrictions: .panel-body dl.dl-horizontal dt.helpexists .help.tltp-wrap span.glyphicon.glyphicon-info-sign .tltp.tltp-top.tltp-animate-move - | Разрешать заходить на сайт под своим именем. + | Allow to login using their name. br - | Будет разлогинен если в данный момент онлайн - |  Может логиниться + | Will be logout if currently online + |  Can login dd .btn-group.btn-group-sm - button.btn.btn-primary.yes(type="button", data-bind="css: {active: !u.nologin()}, click: changenologin") Да - button.btn.btn-primary.no(type="button", data-bind="css: {active: u.nologin()}, click: changenologin") Нет + button.btn.btn-primary.yes(type="button", data-bind="css: {active: !u.nologin()}, click: changenologin") Yes + button.btn.btn-primary.no(type="button", data-bind="css: {active: u.nologin()}, click: changenologin") No dl.dl-horizontal dt.helpexists .help.tltp-wrap span.glyphicon.glyphicon-info-sign .tltp.tltp-top.tltp-animate-move - | Разрешать изменять информацию на странице профиля + | Allow changing information on profile page br - | и менять свою аватарку - |  Может редактировать свой профиль + | and replace/remove own avatar + |  Can edit own profile dd .btn-group.btn-group-sm - button.btn.btn-primary.yes(type="button", data-bind="css: {active: !u.noprofile()}, click: changenoprofile") Да - button.btn.btn-primary.no(type="button", data-bind="css: {active: u.noprofile()}, click: changenoprofile") Нет + button.btn.btn-primary.yes(type="button", data-bind="css: {active: !u.noprofile()}, click: changenoprofile") Yes + button.btn.btn-primary.no(type="button", data-bind="css: {active: u.noprofile()}, click: changenoprofile") No dl.dl-horizontal dt.helpexists .help.tltp-wrap span.glyphicon.glyphicon-info-sign .tltp.tltp-top.tltp-animate-move - | Разрешать загружать фотографии - |  Может загружать фотографии + | Allow uploading pictures + |  Can upload pictures dd .btn-group.btn-group-sm - button.btn.btn-primary.yes(type="button", data-bind="css: {active: !u.nophotoupload()}, click: changenophotoupload") Да - button.btn.btn-primary.no(type="button", data-bind="css: {active: u.nophotoupload()}, click: changenophotoupload") Нет + button.btn.btn-primary.yes(type="button", data-bind="css: {active: !u.nophotoupload()}, click: changenophotoupload") Yes + button.btn.btn-primary.no(type="button", data-bind="css: {active: u.nophotoupload()}, click: changenophotoupload") No dl.dl-horizontal dt.helpexists .help.tltp-wrap span.glyphicon.glyphicon-info-sign .tltp.tltp-top.tltp-animate-move - | Разрешать редактировать фотографии - |  Может редактировать свои фотографии + | Allow editing their own pictures + |  Can edit their pictures dd .btn-group.btn-group-sm - button.btn.btn-primary.yes(type="button", data-bind="css: {active: !u.nophotoedit()}, click: changenophotoedit") Да - button.btn.btn-primary.no(type="button", data-bind="css: {active: u.nophotoedit()}, click: changenophotoedit") Нет + button.btn.btn-primary.yes(type="button", data-bind="css: {active: !u.nophotoedit()}, click: changenophotoedit") Yes + button.btn.btn-primary.no(type="button", data-bind="css: {active: u.nophotoedit()}, click: changenophotoedit") No p.text-muted(style="padding:6px 0 0 6px;line-height:1.1;font-size:11px;") sup(style="margin-left:-6px;") * - | Пользователь сможет редактировать свои "Новые" и фотографии "На доработке" всегда, даже с выбранной опцией Нет + | The user will be able to edit their "New" and "On Revision" photos always, even with the option No selected dl.dl-horizontal dt.helpexists .help.tltp-wrap span.glyphicon.glyphicon-info-sign .tltp.tltp-top.tltp-animate-move - | Разрешать пользователю отзывать еще неопубликованную фотографию, + | Allow user to recall an unpublished photo, br - | и удалять деактивированную - |  Может деактивировать + | and remove deactivated + |  Can deactivate br - | и удалять свои фотографии + | and remove their photos dd .btn-group.btn-group-sm - button.btn.btn-primary.yes(type="button", data-bind="css: {active: !u.nophotostatus()}, click: changenophotostatus") Да - button.btn.btn-primary.no(type="button", data-bind="css: {active: u.nophotostatus()}, click: changenophotostatus") Нет + button.btn.btn-primary.yes(type="button", data-bind="css: {active: !u.nophotostatus()}, click: changenophotostatus") Yes + button.btn.btn-primary.no(type="button", data-bind="css: {active: u.nophotostatus()}, click: changenophotostatus") No p.text-muted(style="padding:6px 0 0 6px;line-height:1.1;font-size:11px;") sup(style="margin-left:-6px;") * - | Пользователь сможет отправлять на публикацию свои "Новые" и фотографии "На доработке" всегда, даже с выбранной опцией Нет + | The user will be able to send his “New” and “On Revision” photos to publication always, even with the No option selected dl.dl-horizontal dt.helpexists .help.tltp-wrap span.glyphicon.glyphicon-info-sign .tltp.tltp-top.tltp-animate-move - | Разрешать менять подпись на своих фотографиях, + | Allow to change watermark on own photos, br - | управлять настройками скачивания оригинала и + | manage downloading settings of original and br - | отправлять свои фотографии на переконвертацию - |  Может менять вотермарк и правила скачивания + | send own photos to reconvert + |  Can change watermark and download settings dd .btn-group.btn-group-sm - button.btn.btn-primary.yes(type="button", data-bind="css: {active: !u.nowaterchange()}, click: changewaterchange") Да - button.btn.btn-primary.no(type="button", data-bind="css: {active: u.nowaterchange()}, click: changewaterchange") Нет + button.btn.btn-primary.yes(type="button", data-bind="css: {active: !u.nowaterchange()}, click: changewaterchange") Yes + button.btn.btn-primary.no(type="button", data-bind="css: {active: u.nowaterchange()}, click: changewaterchange") No p.text-muted(style="padding:6px 0 0 6px;line-height:1.1;font-size:11px;") sup(style="margin-left:-6px;") * - | Это глобальная настройка для пользователя, действующая на возможность изменения им соответствующих настроек в профиле и индивидуальных настроек в каждой фотографии. При этом в каждой фотографии можно запретить/разрешить это индивидуально + | This is a global setting for the user, affecting on the possibility of changing settings in their profile and individual settings for each photo. For each photo it can disable/enable it individually dl.dl-horizontal dt.helpexists .help.tltp-wrap span.glyphicon.glyphicon-info-sign .tltp.tltp-top.tltp-animate-move - | Разрешать добавлять комментарии, + | Allow user to add new comments, br - | и редактировать уже добавленные - |  Может оставлять комментарии + | and edit the existing ones + |  Can leave comments dd .btn-group.btn-group-sm - button.btn.btn-primary.yes(type="button", data-bind="css: {active: !u.nocomments()}, click: changenocomments") Да - button.btn.btn-primary.no(type="button", data-bind="css: {active: u.nocomments()}, click: changenocomments") Нет + button.btn.btn-primary.yes(type="button", data-bind="css: {active: !u.nocomments()}, click: changenocomments") Yes + button.btn.btn-primary.no(type="button", data-bind="css: {active: u.nocomments()}, click: changenocomments") No .panel.panel-pastvu .panel-heading: .panel-title - a.accordion-toggle(data-toggle="collapse", href="#ranks") Специальные настройки + a.accordion-toggle(data-toggle="collapse", href="#ranks") Special settings .panel-collapse.collapse.in#ranks: .panel-body - .setTitle Присваиваемые звания + .setTitle Assigned ranks form: .form-group //ko foreach: ranks label.checkbox-inline @@ -159,17 +159,17 @@ span(data-bind="text: $data.desc") // /ko - .setTitle Лимит количества неподтвержденных фотографий - div(data-bind="html: 'Действующая настройка: '+$root.intl.num(photoNewLimitOrigin())+''", style="margin-bottom: 2px;") - .calcInfo(data-bind="html: 'Доступный лимит: '+$root.intl.num(photoNewCan())+''") - .calcInfo(data-bind="html: 'Всего неподтвержденных: '+$root.intl.num(u.pfcount())+''") - .calcInfo(data-bind="html: 'Всего опубликованных: '+$root.intl.num(u.pcount())+''") + .setTitle Limit of unconfirmed photos + div(data-bind="html: 'Current setting: '+$root.intl.num(photoNewLimitOrigin())+''", style="margin-bottom: 2px;") + .calcInfo(data-bind="html: 'Available limit: '+$root.intl.num(photoNewCan())+''") + .calcInfo(data-bind="html: 'Total unconfirmed: '+$root.intl.num(u.pfcount())+''") + .calcInfo(data-bind="html: 'Total published: '+$root.intl.num(u.pcount())+''") form.form-inline(style="margin-top: 7px;"): .form-group .radio: label.radio-inline input(type="radio", value="auto", name="photo_new_radios", data-bind="checked: photoNewLimitOption") - | Авто + | Auto .radio: label.radio-inline input(type="radio", value="manual", name="photo_new_radios", data-bind="checked: photoNewLimitOption") - | Вручную + | Manual .form-group - input.form-control.input-sm.photoLimit(type="text", title="Число от 0 до 10000", maxlength="5", pattern="[0-9]{1,5}", data-bind="value: photoNewLimit, valueUpdate: 'keyup', attr: {disabled: photoNewLimitOption() === 'auto'}, css: {}") \ No newline at end of file + input.form-control.input-sm.photoLimit(type="text", title="A number between 0 and 10000", maxlength="5", pattern="[0-9]{1,5}", data-bind="value: photoNewLimit, valueUpdate: 'keyup', attr: {disabled: photoNewLimitOption() === 'auto'}, css: {}") \ No newline at end of file diff --git a/views/module/user/photoUpload.pug b/views/module/user/photoUpload.pug index a0bd576ea..a91e5c594 100644 --- a/views/module/user/photoUpload.pug +++ b/views/module/user/photoUpload.pug @@ -6,27 +6,27 @@ //ko if: canLoad() .warn(style="font-size: 12px; color: #A57A30;") - | Согласно  - a(data-bind="attr: {href: getRulesUrl()}", target="_blank") Правилам - | , к публикации будут допущены: + | According to the  + a(data-bind="attr: {href: getRulesUrl()}", target="_blank") Rules + | , these kind of images will be allowed for publishing: br - | Фотографии, снятые до 2000 года, и картины, созданные до 1980 года. + | Photos filmed up to 2000 year, and paintings, created up to 1980 year. br - | Имеющие историческую ценность и отображающие объект съемки в уникальном ракурсе или времени. + | That have historical value and display the subject in a unique angle or time form.uploadForm(method="POST", enctype="multipart/form-data") #addFiles input.fileInput(type="file", name="files[]", accept="image/*", multiple) button.btn.btn-primary.fileSelect(data-bind="click: selectFile") span.glyphicon.glyphicon-plus - | Добавить... + | Add... .addfiles_area.centering_content(data-bind="css: {hide: !filereader()}") - #or.centering_content или - span Перетащите изображения сюда + #or.centering_content or + span Drag image here #dropzone //-Отображаем возможное кол-во к загрузке, если менее 25 разрешено //ko if: canCount() < 25 - .canCount(data-bind="text: 'Вы можете добавить еще ' + canCount() + ' фото'") + .canCount(data-bind="text: 'You can add another ' + canCount() + ' images'") // /ko div(data-bind="style: {display: fileList().length > 0 ? '' : 'none'}") @@ -35,14 +35,14 @@ .progress-bar(data-bind="style: {width: fileProgressAll() + '%'}") .extText(data-bind="text: fileProgressAllText()") table.table.table-striped.table-hover.filesTable - caption Добавленные фотографии + caption Added images tbody //ko foreach: fileList tr td.preview div.forcanvas(data-bind="attr: {'data-fileuid': ext.uid}, css: {noValid: !ext.valid, tooBig: ext.tooBigPreview}") //ko if: ext.tooBigPreview - .msg Слишком большая для превью + .msg Too big for preview // /ko td.desc div(data-bind="text: name") @@ -58,10 +58,10 @@ //ko if: ext.valid && !$parent.options.auto && !ext.uploaded() button.btn.btn-success(data-bind="click: function () {$parent.startFile($data)}, css: {disabled: ext.uploading()}, attr: {disabled: ext.uploading()}") span.glyphicon.glyphicon-upload - | Загрузить + | Upload // /ko button.btn(data-bind="click: function () {$parent.cancelFile($data)}, css: {'btn-warning': !ext.uploaded(), 'btn-danger': ext.uploaded()}") span.glyphicon(data-bind="css: {'glyphicon-ban-circle': !ext.uploaded(), 'glyphicon-remove-circle': ext.uploaded()}") - span(data-bind="text: ext.uploaded() ? ' Удалить' : ' Отменить'") + span(data-bind="text: ext.uploaded() ? ' Remove' : ' Cancel'") // /ko // /ko diff --git a/views/module/user/profile.pug b/views/module/user/profile.pug index de2125a79..bea2b9514 100644 --- a/views/module/user/profile.pug +++ b/views/module/user/profile.pug @@ -1,58 +1,58 @@ .user_profile(data-bind="with: repository[M!M]") - form.form-horizontal(data-bind="css: {canBeEdit: canBeEdit(), cannotBeEdit: !canBeEdit()}") - .form-group - label.col-sm-3.col-md-2.control-label(for="inName") Псевдоним - .col-sm-9.col-md-9 - p.form-control-static - span.glyphicon.glyphicon-user - span.loginName(data-bind="text: ' ' + u.login()") - .form-group(data-bind="style: {display: canBeEdit() || u.firstName().length || u.lastName().length > 0 ? '' : 'none'}") - label.col-sm-3.col-md-2.control-label(for="inName") Реальное имя - .col-sm-3.col-md-2 - input.form-control(type="text", id="inName", data-bind="attr: {size: u.firstName().length, disabled: !editMode(), placeholder: !editMode() ? '' : 'Имя'}, value: u.firstName, valueUpdate: 'afterkeydown'") - .col-sm-3.col-md-2 - input.form-control(type="text", id="inLastName", data-bind="attr: {disabled: !editMode(), placeholder: !editMode() ? '': 'Фамилия'}, value: u.lastName, valueUpdate: 'afterkeydown'") - .form-group(data-bind="style: {display: canBeEdit() || u.birthdate().length ? '' : 'none'}") - label.col-sm-3.col-md-2.control-label(for="inBirthdate") Дата рождения - .col-sm-3.col-md-2 - input#inBirthdate.form-control(type="text", data-bind="attr: {disabled: !editMode()}, value: u.birthdate, valueUpdate: 'keyup'") - .form-group(data-bind="style: {display: canBeEdit() || u.sex().length > 0 ? '' : 'none'}") - label.col-sm-3.col-md-2.control-label(for="inSex2") Пол - .col-sm-4.col-md-3 - input.form-control(type="text", id="inSex2", disabled, data-bind="style: {display: (!canBeEdit() ? '' : 'none')}, value: u.sex()=='m' ? 'Мужчина' : 'Женщина'") - div(data-bind="style: {display: canBeEdit() ? '' : 'none'}") - label.radio-inline - input(type="radio", id='inSex', name="sex", value="", data-bind="checked: u.sex, attr: {disabled: !editMode()}") - |  Не указан - label.radio-inline - input(type="radio", id='inSex', name="sex", value="m", data-bind="checked: u.sex, attr: {disabled: !editMode()}") - |  Мужчина - label.radio-inline - input(type="radio", id='inSex', name="sex", value="f", data-bind="checked: u.sex, attr: {disabled: !editMode()}") - |  Женщина - .form-group(data-bind="style: {display: canBeEdit() || u.country().length || u.city().length > 0 ? '' : 'none'}") - label.col-sm-3.col-md-2.control-label(for="inResidence") Откуда - .col-sm-3.col-md-2 - input.form-control(type="text", id='inResidence', data-bind="attr: {disabled: !editMode(), placeholder: !editMode() ? '': 'Страна'}, size: u.country().length, value: u.country, valueUpdate: 'afterkeydown'") - .col-sm-3.col-md-2 - input.form-control(type="text", id="inResidence2", data-bind="attr: {disabled: !editMode(), placeholder: !editMode() ? '': 'Город'}, value: u.city, valueUpdate: 'afterkeydown'") - .form-group(data-bind="style: {display: canBeEdit() || u.work().length > 0 ? '' : 'none'}") - label.col-sm-3.col-md-2.control-label(for="inInterested") Деятельность - .col-sm-3.col-md-2 - input.form-control(type="text", id='inInterested', data-bind="attr: {disabled: !editMode()}, value: u.work, valueUpdate: 'afterkeydown'") - .form-group(data-bind="style: {display: canBeEdit() || u.www().length > 0 ? '' : 'none'}") - label.col-sm-3.col-md-2.control-label(for="inWebsite") Веб-сайт - .col-sm-3.col-md-2 - input.form-control(type="text", id='inWebsite', data-bind="attr: {disabled: !editMode()}, value: u.www, valueUpdate: 'afterkeydown'") - .form-group(data-bind="style: {display: canBeEdit() || u.aboutme().length > 0 ? '' : 'none'}") - label.col-sm-3.col-md-2.control-label(for="inaboutme") Обо мне - .col-sm-7.col-md-8 - textarea.form-control(rows="4", id='inaboutme', data-bind="attr: {disabled: !editMode()}, value: u.aboutme, valueUpdate: 'afterkeydown'") - .form-group(data-bind="style: {display: canBeEdit() ? '' : 'none'}") - .col-sm-12 - button.btn.btn-primary(type="button", data-bind="css: {'btn-success': editMode()}, event: {click: function(data, event) { if (!data.editMode()){data.edit(true)} else{data.saveUser()}}}") - span.glyphicon(data-bind="css: {'glyphicon-pencil': !editMode(), 'glyphicon-ok': editMode()}") - span(data-bind="text: editMode() ? ' Сохранить профиль' : ' Редактировать'") - button.btn.btn-danger(type="button", data-bind="style: {display: editMode() ? '' : 'none'}, event: {click: function(data, event) { if (data.editMode()) {data.cancelUser()}}}") - span.glyphicon.glyphicon-remove - | Отмена + form.form-horizontal(data-bind="css: {canBeEdit: canBeEdit(), cannotBeEdit: !canBeEdit()}") + .form-group + label.col-sm-3.col-md-2.control-label(for="inName") Username + .col-sm-9.col-md-9 + p.form-control-static + span.glyphicon.glyphicon-user + span.loginName(data-bind="text: ' ' + u.login()") + .form-group(data-bind="style: {display: canBeEdit() || u.firstName().length || u.lastName().length > 0 ? '' : 'none'}") + label.col-sm-3.col-md-2.control-label(for="inName") Real name + .col-sm-3.col-md-2 + input.form-control(type="text", id="inName", data-bind="attr: {size: u.firstName().length, disabled: !editMode(), placeholder: !editMode() ? '' : 'First name'}, value: u.firstName, valueUpdate: 'afterkeydown'") + .col-sm-3.col-md-2 + input.form-control(type="text", id="inLastName", data-bind="attr: {disabled: !editMode(), placeholder: !editMode() ? '' : 'Last name'}, value: u.lastName, valueUpdate: 'afterkeydown'") + .form-group(data-bind="style: {display: canBeEdit() || u.birthdate().length ? '' : 'none'}") + label.col-sm-3.col-md-2.control-label(for="inBirthdate") Birthdate + .col-sm-3.col-md-2 + input#inBirthdate.form-control(type="text", data-bind="attr: {disabled: !editMode()}, value: u.birthdate, valueUpdate: 'keyup'") + .form-group(data-bind="style: {display: canBeEdit() || u.sex().length > 0 ? '' : 'none'}") + label.col-sm-3.col-md-2.control-label(for="inSex2") Gender + .col-sm-4.col-md-3 + input.form-control(type="text", id="inSex2", disabled, data-bind="style: {display: (!canBeEdit() ? '' : 'none')}, value: u.sex()=='m' ? 'Male' : 'Female'") + div(data-bind="style: {display: canBeEdit() ? '' : 'none'}") + label.radio-inline + input(type="radio", name="sex", value="", data-bind="checked: u.sex, attr: {disabled: !editMode()}") + |  Not specified + label.radio-inline + input(type="radio", name="sex", value="m", data-bind="checked: u.sex, attr: {disabled: !editMode()}") + |  Male + label.radio-inline + input(type="radio", name="sex", value="f", data-bind="checked: u.sex, attr: {disabled: !editMode()}") + |  Female + .form-group(data-bind="style: {display: canBeEdit() || u.country().length || u.city().length > 0 ? '' : 'none'}") + label.col-sm-3.col-md-2.control-label(for="inResidence") Residence + .col-sm-3.col-md-2 + input.form-control(type="text", id='inResidence', data-bind="attr: {disabled: !editMode(), placeholder: !editMode() ? '' : 'Country'}, size: u.country().length, value: u.country, valueUpdate: 'afterkeydown'") + .col-sm-3.col-md-2 + input.form-control(type="text", id="inResidence2", data-bind="attr: {disabled: !editMode(), placeholder: !editMode() ? '' : 'City'}, value: u.city, valueUpdate: 'afterkeydown'") + .form-group(data-bind="style: {display: canBeEdit() || u.work().length > 0 ? '' : 'none'}") + label.col-sm-3.col-md-2.control-label(for="inInterested") Occupation + .col-sm-3.col-md-2 + input.form-control(type="text", id='inInterested', data-bind="attr: {disabled: !editMode()}, value: u.work, valueUpdate: 'afterkeydown'") + .form-group(data-bind="style: {display: canBeEdit() || u.www().length > 0 ? '' : 'none'}") + label.col-sm-3.col-md-2.control-label(for="inWebsite") Website + .col-sm-3.col-md-2 + input.form-control(type="text", id='inWebsite', data-bind="attr: {disabled: !editMode()}, value: u.www, valueUpdate: 'afterkeydown'") + .form-group(data-bind="style: {display: canBeEdit() || u.aboutme().length > 0 ? '' : 'none'}") + label.col-sm-3.col-md-2.control-label(for="inaboutme") About me + .col-sm-7.col-md-8 + textarea.form-control(rows="4", id='inaboutme', data-bind="attr: {disabled: !editMode()}, value: u.aboutme, valueUpdate: 'afterkeydown'") + .form-group(data-bind="style: {display: canBeEdit() ? '' : 'none'}") + .col-sm-12 + button.btn.btn-primary(type="button", data-bind="css: {'btn-success': editMode()}, event: {click: function(data, event) { if (!data.editMode()){data.edit(true)} else{data.saveUser()}}}") + span.glyphicon(data-bind="css: {'glyphicon-pencil': !editMode(), 'glyphicon-ok': editMode()}") + span(data-bind="text: editMode() ? ' Save profile' : ' Edit'") + button.btn.btn-danger(type="button", data-bind="style: {display: editMode() ? '' : 'none'}, event: {click: function(data, event) { if (data.editMode()) {data.cancelUser()}}}") + span.glyphicon.glyphicon-remove + | Cancel diff --git a/views/module/user/session.pug b/views/module/user/session.pug index 31c24d1f3..e249aaf81 100644 --- a/views/module/user/session.pug +++ b/views/module/user/session.pug @@ -1,45 +1,45 @@ .user_session(data-bind="with: repository[M!M]") dl.dl-horizontal - dt Первая активность: + dt First activity: dd(data-bind="text: $root.intl.dateFull(session.created)") //ko if: !session.sockets - dt Последняя активность: + dt Last activity: dd(data-bind="text: $root.intl.dateFull(session.stamp)") // /ko //ko if: session.lang - dt Язык: + dt Language: dd(data-bind="text: session.lang") // /ko //ko if: session.sockets - dt Количество вкладок: + dt Number of tabs: dd(data-bind="text: $root.intl.num(session.sockets)") // /ko dt - | IP адреса: + | IP addresses: //ko if: session.ips.length > 2 br .btn-group.btn-group-sm(style="margin:3px") - button.btn.btn-primary.yes(type="button", data-bind="css: {active: !ipsHist()}, click: toggleIPs") Уникальные - button.btn.btn-primary.no(type="button", data-bind="css: {active: ipsHist()}, click: toggleIPs") История + button.btn.btn-primary.yes(type="button", data-bind="css: {active: !ipsHist()}, click: toggleIPs") Unique + button.btn.btn-primary.no(type="button", data-bind="css: {active: ipsHist()}, click: toggleIPs") History // /ko dd // ko if: session.ips.length === 101 - div Предыдущие адреса возможно были отброшены + div Previous ip addresses might have been dropped due to the storage limits // /ko //ko foreach: ips div span.ip(data-bind="text: $data.ip") //ko if: $parent.ipsHist() && $data.off - span(data-bind="text: ' (до ' + $root.intl.dateFullDigit($data.off) + ')'") + span(data-bind="text: ' (until ' + $root.intl.dateFullDigit($data.off) + ')'") // /ko //ko if: $data.ip === $parent.ipLast && (!$parent.ipsHist() || !$data.off) - i(data-bind="text: $parent.online ? ' (текущий адрес)' : ' ( последний адрес)'") + i(data-bind="text: $parent.online ? ' (current address)' : ' (last address)'") // /ko // /ko dt Клиенты: dd // ko if: session.agents.length === 101 - div Предыдущие клиенты возможно были отброшены + div Previous clients might have been dropped due to the storage limits // /ko //ko foreach: session.agents .versions @@ -55,9 +55,9 @@ span(data-bind="text: $data.browser") // /ko //ko if: $data.off - span(data-bind="text: ' (до ' + $root.intl.dateFullDigit($data.off) + ')'") + span(data-bind="text: ' (until ' + $root.intl.dateFullDigit($data.off) + ')'") // /ko //ko if: !$data.off - i(data-bind="text: $parent.online ? ' (текущий клиент)' : ' (последний клиент)'") + i(data-bind="text: $parent.online ? ' (current client)' : ' (last client)'") // /ko // /ko diff --git a/views/module/user/sessions.pug b/views/module/user/sessions.pug index 509516cb5..a685670d5 100644 --- a/views/module/user/sessions.pug +++ b/views/module/user/sessions.pug @@ -1,15 +1,15 @@ .user_sessions(data-bind="with: repository[M!M]"): .panel-group#accordion .panel.panel-pastvu - .panel-heading: .panel-title: a(data-toggle="collapse", href="#sessions") Активные сессии + .panel-heading: .panel-title: a(data-toggle="collapse", href="#sessions") Active sessions .panel-collapse.collapse.in#sessions: .panel-body dl.dl-horizontal //ko if: !onlines().length && !offlines().length - | Пользователь не имеет активных сессий + | The user doesn't have active sessions br br // /ko //ko if: onlines().length - dt.online Онлайн + dt.online Online dd //ko foreach: onlines .session(data-bind="click: function () {$parent.handleShowSession($data.key, false, true)}") @@ -35,18 +35,18 @@ i(data-bind="text: ' (+' + $data.ipCount + ')'") // /ko //ko if: $data.lang - div(data-bind="text: 'Язык: ' + $data.lang") + div(data-bind="text: 'Language: ' + $data.lang") // /ko div - | Количество открытых вкладок:  + | Number of open browser tabs:  span(data-bind="text: $root.intl.num($data.sockets)") - div(data-bind="text: 'Первая активность: ' + $root.intl.dateFull($data.created)") + div(data-bind="text: 'First activity: ' + $root.intl.dateFull($data.created)") //ko if: $data.isCurrent - div.online(style="min-width:80px; margin-right:4px; padding: 0 10px; text-align:center; font-style:italic") Текущая + div.online(style="min-width:80px; margin-right:4px; padding: 0 10px; text-align:center; font-style:italic") Current // /ko //ko if: !$data.isCurrent - button.btn.btn-primary(type="button", title="Уничтожить сессию", data-bind="attr: {disabled: $parent.removing.indexOf($data.key) > -1}, event:{click: $parent.handleSessionDestroy}", style="min-width:80px;") - | Выйти + button.btn.btn-primary(type="button", title="Destroy session", data-bind="attr: {disabled: $parent.removing.indexOf($data.key) > -1}, event:{click: $parent.handleSessionDestroy}", style="min-width:80px;") + | Exit // /ko // /ko // /ko @@ -57,7 +57,7 @@ // /ko //ko if: offlines().length - dt Оффлайн + dt Offline dd //ko foreach: offlines .session(data-bind="click: function () {$parent.handleShowSession($data.key)}") @@ -82,11 +82,11 @@ //ko if: $data.ipCount i(data-bind="text: ' (+' + $data.ipCount + ')'") // /ko - div(data-bind="text: 'Язык: ' + $data.lang") - div(data-bind="text: 'Первая активность: ' + $root.intl.dateFull($data.created)") - div(data-bind="text: 'Последняя активность: ' + $root.intl.dateFull($data.stamp)") - button.btn.btn-primary(type="button", title="Уничтожить сессию", data-bind="attr: {disabled: $parent.removing.indexOf($data.key) > -1}, event:{click: $parent.handleSessionDestroy}", style="min-width:80px;") - | Удалить + div(data-bind="text: 'Language: ' + $data.lang") + div(data-bind="text: 'First activity: ' + $root.intl.dateFull($data.created)") + div(data-bind="text: 'Last activity: ' + $root.intl.dateFull($data.stamp)") + button.btn.btn-primary(type="button", title="Destroy session", data-bind="attr: {disabled: $parent.removing.indexOf($data.key) > -1}, event:{click: $parent.handleSessionDestroy}", style="min-width:80px;") + | Remove // /ko // /ko @@ -99,12 +99,12 @@ .help.tltp-wrap span.glyphicon.glyphicon-info-sign .tltp.tltp-top.tltp-animate-move - | Просмотр архивных сессий + | Viewing archive sessions br - | доступен только администраторам - |  Архивные + | is available only to admin + |  Archive dd - button.btn.btn-primary(type="button", data-bind="text: archivedShow() ? 'Скрыть' : 'Показать (' + archivedCount() + ')', event:{click: toggleArchive}, attr: {disabled: archivedFetching()}", style="min-width:80px;") + button.btn.btn-primary(type="button", data-bind="text: archivedShow() ? 'Hide' : 'Show (' + archivedCount() + ')', event:{click: toggleArchive}, attr: {disabled: archivedFetching()}", style="min-width:80px;") //ko if: archives() br br @@ -133,9 +133,9 @@ i(data-bind="text: ' (+' + $data.ipCount + ')'") // /ko //ko if: $data.lang - div(data-bind="text: 'Язык: ' + $data.lang") + div(data-bind="text: 'Language: ' + $data.lang") // /ko - div(data-bind="text: 'Первая активность: ' + $root.intl.dateFull($data.created)") - div(data-bind="text: 'Последняя активность: ' + $root.intl.dateFull($data.stamp)") + div(data-bind="text: 'First activity: ' + $root.intl.dateFull($data.created)") + div(data-bind="text: 'Last activity: ' + $root.intl.dateFull($data.stamp)") // /ko // /ko diff --git a/views/module/user/settings.pug b/views/module/user/settings.pug index 19dc0efb7..d0a716d79 100644 --- a/views/module/user/settings.pug +++ b/views/module/user/settings.pug @@ -1,9 +1,9 @@ .user_settings(data-bind="with: repository[M!M]"): .panel-group#accordion .panel.panel-pastvu - .panel-heading: .panel-title: a(data-toggle="collapse", href="#privacy") Конфиденциальность + .panel-heading: .panel-title: a(data-toggle="collapse", href="#privacy") Privacy .panel-collapse.collapse.in#privacy: .panel-body dl.dl-horizontal - dt Мой email + dt My email dd: .row: .col-xs-9.col-sm-10.col-md-7.col-lg-4 .input-group input.form-control(type="email", data-bind="attr: {size: u.email().length, disabled: !editEmail()}, value: u.email, valueUpdate: 'afterkeydown', executeOnEnter: saveEmail") @@ -14,77 +14,77 @@ span.glyphicon.glyphicon-remove // /ko dl.dl-horizontal - dt Мой пароль + dt My password dd //ko if: itsMe() - button.btn.btn-sm.btn-primary(type="button", title="Сменить текущий пароль", data-bind="event:{click: function(data, evt){auth.show('passChange')}}") - span Сменить + button.btn.btn-sm.btn-primary(type="button", title="Change current password", data-bind="event:{click: function(data, evt){auth.show('passChange')}}") + span Change // /ko - button.btn.btn-sm.btn-primary(type="button", title="Сменить через почту без ввода текущего", data-bind="event:{click: function(data, evt){auth.showRecallRequest(u.login())}}") - span Запросить смену + button.btn.btn-sm.btn-primary(type="button", title="Change through email without entering current", data-bind="event:{click: function(data, evt){auth.showRecallRequest(u.login())}}") + span Request change dl.dl-horizontal - dt Показывать в обсуждениях реальное имя + dt Show real name in conversations dd: .btn-group.btn-group-sm - button.btn.btn-primary.yes(type="button", data-bind="css: {active: showName()}, click: toggleDisp") Да - button.btn.btn-primary.no(type="button", data-bind="css: {active: !showName()}, click: toggleDisp") Нет + button.btn.btn-primary.yes(type="button", data-bind="css: {active: showName()}, click: toggleDisp") Yes + button.btn.btn-primary.no(type="button", data-bind="css: {active: !showName()}, click: toggleDisp") No .panel.panel-pastvu - .panel-heading: .panel-title: a(data-toggle="collapse", href="#region") Регионы + .panel-heading: .panel-title: a(data-toggle="collapse", href="#region") Regions .panel-collapse.collapse.in#region: .panel-body dl.dl-horizontal dt.helpexists .help.tltp-wrap span.glyphicon.glyphicon-info-sign .tltp.tltp-top.tltp-animate-move - | Регион, который определяет некоторые настройки, + | Region, which affects some settings, br - | например, позицию кнопки Домой на карте, + | for example, region of Home button on map, br - | первый элемент в списке выбора регионов и т.д. + | first element on list of regions etc. |   span.glyphicon.glyphicon-home - |  Домашний регион + |  Home region dd span.region - span(data-bind="text: u.regionHome.title_local()") + span(data-bind="text: u.regionHome.title_en()") span.regionEdit(data-bind="click: regionHomeSelect") span.glyphicon.glyphicon-pencil - | Изменить + | Change //ko if: u.role() === 5 && u.mod_regions() dl.dl-horizontal.forMod dt.helpexists .help.tltp-wrap span.glyphicon.glyphicon-info-sign .tltp.tltp-top.tltp-animate-move - | Регионы, в которых вы являетесь модератором + | Regions, where you are a moderator br - | Назначаются администратором - |  Модерируемые мной регионы + | Assigned by administrator + |  Regions where I am a moderator dd //ko if: !u.mod_regions().length span.region span.glyphicon.glyphicon-globe - | Весь мир + | Whole world // /ko //ko foreach: u.mod_regions span.region - span(data-bind="text: $data.title_local()") + span(data-bind="text: $data.title_en()") // /ko // /ko .panel.panel-pastvu - .panel-heading: .panel-title: a(data-toggle="collapse", href="#filters") Фильтрация данных по умолчанию + .panel-heading: .panel-title: a(data-toggle="collapse", href="#filters") Filter by default .panel-collapse.collapse.in#filters: .panel-body dl.dl-horizontal dt.helpexists .help.tltp-wrap span.glyphicon.glyphicon-info-sign .tltp.tltp-top.tltp-animate-move - | Изображения, по которым будет производится + | Images, which define br - | автоматическая фильтрация контента + | automatic content filtration |   span.glyphicon.glyphicon-filter - |  Типы изображений + |  Image types dd: span.panel-block(style="padding-bottom:5px;") //ko foreach: vars.photo_filter_type label.checkbox-inline @@ -96,89 +96,89 @@ .help.tltp-wrap span.glyphicon.glyphicon-info-sign .tltp.tltp-top.tltp-animate-move - | Регионы, по которым будет производится + | Regions, which define br - | автоматическая фильтрация контента + | automatic content filtration |   span.glyphicon.glyphicon-filter - | Регионы + | Regions dd: span.panel-block .radio(style="margin-top:0"): label input(type="radio", name="regfilter_radios", value="all", data-bind="checked: regfiltercheck") span.glyphicon.glyphicon-globe - | Весь мир (без фильтра) + | Whole world (no filter) .radio: label input(type="radio", name="regfilter_radios", value="home", data-bind="checked: regfiltercheck") span.glyphicon.glyphicon-home - | Домашний регион + | Home region .radio(style="margin-bottom:5px"): label input(type="radio", name="regfilter_radios", value="list", data-bind="checked: regfiltercheck") span.glyphicon.glyphicon-list - span Список + span List //ko if: regfiltercheck() === 'list' | :  //ko foreach: u.regions - span.region.candrop(title="Убрать из моих регионов", data-bind="click: function() {$parent.regionDrop($data.cid());}") - span(data-bind="text: $data.title_local()") + span.region.candrop(title="Remove from my regions", data-bind="click: function() {$parent.regionDrop($data.cid());}") + span(data-bind="text: $data.title_en()") // /ko //ko if: u.regions().length span.regionEdit(data-bind="click: regionFilterSelect") span.glyphicon.glyphicon-pencil - | Изменить + | Change // /ko // /ko dl.dl-horizontal dt.helpexists(style="color: #27578d;") - | По умолчанию фильтровать по выбранным опциям также: + | Filter by default with selected options also: dd dl.dl-horizontal.dl-tight dt.helpexists .help.tltp-wrap span.glyphicon.glyphicon-info-sign .tltp.tltp-top.tltp-animate-move - | Изображения пользователей, + | Images which located br - | доступые в соответствующих профилях - |  Галереи пользователей + | in users profile + |  User galleries dd .btn-group.btn-group-sm - button.btn.btn-primary.yes(type="button", data-bind="css: {active: u.settings.r_f_user_gal()}, click: regionUserGal") Да - button.btn.btn-primary.no(type="button", data-bind="css: {active: !u.settings.r_f_user_gal()}, click: regionUserGal") Нет + button.btn.btn-primary.yes(type="button", data-bind="css: {active: u.settings.r_f_user_gal()}, click: regionUserGal") Yes + button.btn.btn-primary.no(type="button", data-bind="css: {active: !u.settings.r_f_user_gal()}, click: regionUserGal") No dl.dl-horizontal.dl-tight dt.helpexists .help.tltp-wrap span.glyphicon.glyphicon-info-sign .tltp.tltp-top.tltp-animate-move - | Полоса изображений, находящаяся рядом с именем пользователя, + | Strip, which located close br - | на странице просмотра загруженного им изображения - |  Полосу других изображений пользователя + | to user avatar on photo page + |  Strip of other user's images dd .btn-group.btn-group-sm - button.btn.btn-primary.yes(type="button", data-bind="css: {active: u.settings.r_f_photo_user_gal()}, click: regionPhotoUserGal") Да - button.btn.btn-primary.no(type="button", data-bind="css: {active: !u.settings.r_f_photo_user_gal()}, click: regionPhotoUserGal") Нет + button.btn.btn-primary.yes(type="button", data-bind="css: {active: u.settings.r_f_photo_user_gal()}, click: regionPhotoUserGal") Yes + button.btn.btn-primary.no(type="button", data-bind="css: {active: !u.settings.r_f_photo_user_gal()}, click: regionPhotoUserGal") No .panel.panel-pastvu - .panel-heading: .panel-title: a(data-toggle="collapse", href="#photo") Изображения + .panel-heading: .panel-title: a(data-toggle="collapse", href="#photo") Images .panel-collapse.collapse.in#photo: .panel-body dl.dl-horizontal dt.helpexists .help.tltp-wrap span.glyphicon.glyphicon-info-sign .tltp.tltp-top.tltp-animate-move - | Показывать по умолчанию вотермарк + | Show by default pastvu.com br - | pastvu.com, встроенный в изображение - |  Показывать вотермарк изображения + | watermark embedded in image + |  Show watermark by default dd .btn-group.btn-group-sm - button.btn.btn-primary.yes(type="button", data-bind="css: {active: u.settings.photo_show_watermark()}, click: watermarkShow") Да - button.btn.btn-primary.no(type="button", data-bind="css: {active: !u.settings.photo_show_watermark()}, click: watermarkShow") Нет + button.btn.btn-primary.yes(type="button", data-bind="css: {active: u.settings.photo_show_watermark()}, click: watermarkShow") Yes + button.btn.btn-primary.no(type="button", data-bind="css: {active: !u.settings.photo_show_watermark()}, click: watermarkShow") No //ko if: u.nowaterchange() dl.dl-horizontal: .helpexists: .help.text-danger span.glyphicon.glyphicon-warning-sign - span(data-bind="text: ' Администратор запретил ' + (itsMe()?'вам':'пользователю') + ' управлять настройками установки подписи на ' + (itsMe()?'ваших':'его') + ' изображениях'") + span(data-bind="text: ' Administrator has forbidden ' + (itsMe()?'you':'user') + ' to change watermark settings on ' + (itsMe()?'your':'his') + ' images'") // /ko .watersingcontrol(data-bind="css: {deny: itsMe() && u.nowaterchange()}") dl.dl-horizontal @@ -186,26 +186,24 @@ .help.tltp-wrap span.glyphicon.glyphicon-info-sign .tltp.tltp-top.tltp-animate-move - | Поведение можно менять на каждом отдельном + | Behavior can be changed for each image br - | изображении на странице редактирования - |  Подпись на вотермарке - br - | загружаемых мной изображений + | individually on image's edit page + |  Text on watermark on my images dd: span.panel-block .btn-group.btn-group-sm(style="margin-bottom:8px") - button.btn.btn-primary.yes(type="button", data-bind="css: {active: !!u.settings.photo_watermark_add_sign()}, click: watersignAdd") Да - button.btn.btn-primary.no(type="button", data-bind="css: {active: !u.settings.photo_watermark_add_sign()}, click: watersignAdd") Нет + button.btn.btn-primary.yes(type="button", data-bind="css: {active: !!u.settings.photo_watermark_add_sign()}, click: watersignAdd") Yes + button.btn.btn-primary.no(type="button", data-bind="css: {active: !u.settings.photo_watermark_add_sign()}, click: watersignAdd") No br // ko if: !!u.settings.photo_watermark_add_sign() .radio(style="margin-top:3px"): label input(type="radio", name="watersign", value="true", data-bind="checked: watersigncheck") - | Настройки системы ( + | System settings ( span(style="color:#777", data-bind="text: 'uploaded by ' + u.login()") | ) .radio(style="margin-top:0"): .input-group(style="max-width:500px") input(type="radio", name="watersign", value="custom", data-bind="checked: watersigncheck") - span.input-group-addon Текст + span.input-group-addon Text input.form-control(type="text", data-bind="attr: {disabled: watersigncheck()!=='custom'}, value: u.watersignCustom, symbols: {pattern:fields.watersignPattern,watch:u.watersignCustom,noMultiplySpace:true,maxLength:fields.watersignLength}, valueUpdate: 'input', executeOnEnter: watermarkCustomSave") span.input-group-addon.action.save(data-bind="style: {visibility: watersignCustomChanged() ? 'visible' : 'hidden'}, click: watermarkCustomSave") span.glyphicon.glyphicon-ok @@ -214,146 +212,140 @@ // /ko p.text-muted(style="padding-left:8px;line-height:1.1;font-size:11px;") sup(style="margin-left:-6px;") * - | Настройка сохраняется автоматически и будет применена ко всем вновь загружаемым изображениям. Чтобы применить ее к существующим изображениям, нажмите "применить" ниже + | Setting saves automatically and will be applied to all newly uploaded images. To apply it to existing images, push "Apply" below hr(style="margin:8px 0 9px;") .tltp-wrap - abbr(title="") Применить настройку к загруженным изображениям, у которых нет индивидульных настроек подписи: + abbr(title="") Apply setting to existing images, which have no individual watermark setting: .tltp.tltp-top.tltp-hotizontal-left.tltp-animate-move - | Отправить на переконвертацию свои изображения, + | Send to reconvert own images, br - | в которых подпись на вотермарке берется из текущих настроек профиля + | which have no individual watermark setting div label.radio-inline input(type="radio", name="reconvert", value="all", data-bind="checked: reconvertcheck") - | Все + | All label.radio-inline input(type="radio", name="reconvert", value="region", data-bind="checked: reconvertcheck") span - | В регионе - input.form-control(id="reconvertRegion", data-bind="attr: {disabled: reconvertcheck()!=='region'}", style="display:inline-block;margin-left:6px;width:180px;", type="number", placeholder="Введите номер региона", maxlength="6") - button.btn.btn-sm.btn-primary(type="button", style="margin: 5px 0 8px;", data-bind="click: reconvertPhotos, attr: {disabled: reconvertingPhotos()}") Применить + | Within region + input.form-control(id="reconvertRegion", data-bind="attr: {disabled: reconvertcheck()!=='region'}", style="display:inline-block;margin-left:6px;width:180px;", type="number", placeholder="Type region id", maxlength="6") + button.btn.btn-sm.btn-primary(type="button", style="margin: 5px 0 8px;", data-bind="click: reconvertPhotos, attr: {disabled: reconvertingPhotos()}") Apply hr(style="margin:8px 0 9px;") .tltp-wrap - abbr(title="") Сбросить установленные в изображениях индивидульные настройки подписи + abbr(title="") Reset individual watermark settings .tltp.tltp-top.tltp-hotizontal-left.tltp-animate-move - | Сбросить установленные индивидульные настройки - br - |подписи в изображениям (если такие устанавливались) + | Reset individual watermark settings div label.radio-inline input(type="radio", name="resetwatersign", value="all", data-bind="checked: resetwatersigncheck") - | Все + | All label.radio-inline input(type="radio", name="resetwatersign", value="region", data-bind="checked: resetwatersigncheck") span - | В регионе - input.form-control(id="resetwatersignRegion", data-bind="attr: {disabled: resetwatersigncheck()!=='region'}", style="display:inline-block;margin-left:6px;width:180px;", type="number", placeholder="Введите номер региона", maxlength="6") + | Within region + input.form-control(id="resetwatersignRegion", data-bind="attr: {disabled: resetwatersigncheck()!=='region'}", style="display:inline-block;margin-left:6px;width:180px;", type="number", placeholder="Type region id", maxlength="6") button.btn.btn-sm.btn-primary(type="button", style="margin: 5px 0 8px;", data-bind="click: individualWatersignReset, attr: {disabled: reconvertingPhotos()}") Сбросить p.text-muted(style="padding-left:8px;line-height:1.1;font-size:11px;") sup(style="margin-left:-6px;") * - | Изображениям будет установлена настройка подписи по умолчанию, указанная выше. Эти изображения будут отправлены на переконвертацию автоматически + | Images will receive setting by default, which specified above. This images will be reconverted automatically dl.dl-horizontal dt.helpexists .help.tltp-wrap span.glyphicon.glyphicon-info-sign .tltp.tltp-top.tltp-animate-move - | Другие зарегистрированные пользователи + | Another registered users will be able br - | смогут скачивать оригиналы ваших изображений - |  Разрешать скачивать оригиналы - br - | моих изображений + | to download file that you uploaded + |  Allow to download origin of my images dd: span.panel-block .btn-group.btn-group-sm(style="margin-bottom:8px") - button.btn.btn-primary.yes(type="button", data-bind="attr: {disabled: !u.settings.photo_watermark_add_sign()}, css: {active: !u.settings.photo_watermark_add_sign() || !u.settings.photo_disallow_download_origin()}, click: disallowDownloadOrigin") Да - button.btn.btn-primary.no(type="button", data-bind="attr: {disabled: !u.settings.photo_watermark_add_sign()}, css: {active: !!u.settings.photo_watermark_add_sign() && !!u.settings.photo_disallow_download_origin()}, click: disallowDownloadOrigin") Нет + button.btn.btn-primary.yes(type="button", data-bind="attr: {disabled: !u.settings.photo_watermark_add_sign()}, css: {active: !u.settings.photo_watermark_add_sign() || !u.settings.photo_disallow_download_origin()}, click: disallowDownloadOrigin") Yes + button.btn.btn-primary.no(type="button", data-bind="attr: {disabled: !u.settings.photo_watermark_add_sign()}, css: {active: !!u.settings.photo_watermark_add_sign() && !!u.settings.photo_disallow_download_origin()}, click: disallowDownloadOrigin") No p.text-muted(style="padding-left:8px;line-height:1.1;font-size:11px;") sup(style="margin-left:-6px;") * - | Запретить скачивать оригинал можно только в случае наличия подписи на вотермарке изображения + | Disallowance of downloading original can be established only for image that has text on watermark p.text-muted(style="padding-left:8px;line-height:1.1;font-size:11px;") sup(style="margin-left:-6px;") * - | Для других пользователей кнопка скачивания изображения будет окрашена в зеленый цвет, если скачивание оригинала разрешено. Вы всегда сможете скачивать оригиналы своих изображений, а если другие пользователи не могут этого делать согласно вашей настройке, то для вас кнопка скачивания будет синей с зеленой стрелкой + | For another users download button will be green, if original download is allowed. You always will be able to download original file of your images, if other users can't do it, button will be blue with green arrow hr(style="margin:8px 0 9px;") - | Сбросить установленные в изображениях индивидульные настройки разрешения на скачивание + | Reset individual settings about downloading original image div label.radio-inline input(type="radio", name="disallowDownloadOrigin", value="all", data-bind="checked: resetDisallowDownloadOrigin") - | Все + | All label.radio-inline input(type="radio", name="disallowDownloadOrigin", value="region", data-bind="checked: resetDisallowDownloadOrigin") span - | В регионе - input.form-control(id="resetDisallowDownloadOriginRegion", data-bind="attr: {disabled: resetDisallowDownloadOrigin()!=='region'}", style="display:inline-block;margin-left:6px;width:180px;", type="number", placeholder="Введите номер региона", maxlength="6") - button.btn.btn-sm.btn-primary(type="button", style="margin: 5px 0 8px;", data-bind="click: individualDisallowDownloadOriginReset, attr: {disabled: reconvertingPhotos()}") Сбросить + | In region + input.form-control(id="resetDisallowDownloadOriginRegion", data-bind="attr: {disabled: resetDisallowDownloadOrigin()!=='region'}", style="display:inline-block;margin-left:6px;width:180px;", type="number", placeholder="Type region id", maxlength="6") + button.btn.btn-sm.btn-primary(type="button", style="margin: 5px 0 8px;", data-bind="click: individualDisallowDownloadOriginReset, attr: {disabled: reconvertingPhotos()}") Reset p.text-muted(style="padding-left:8px;line-height:1.1;font-size:11px;") sup(style="margin-left:-6px;") * - | В каждом изображении вы можете устанавливать разрешение на скачивание индивидуально. Здесь вы можете сбросить индивидуальную настройку в этих изображениях и к ним будет применена общая, указанная выше + | For each image you can set allowance of downloading original individually. Here you can reset such individual settings and common setting, specified above, will be applied to them .panel.panel-pastvu - .panel-heading: .panel-title: a(data-toggle="collapse", href="#comments") Комментарии + .panel-heading: .panel-title: a(data-toggle="collapse", href="#comments") Comments .panel-collapse.collapse.in#comments: .panel-body dl.dl-horizontal dt.helpexists .help.tltp-wrap span.glyphicon.glyphicon-info-sign .tltp.tltp-top.tltp-animate-move - | Показывать удаленные комментарии + | Show deleted comments br - | автоматически при заходе на страницу - |  Показывать удаленные комментарии + | automatically on page load + |  Show deleted comments br - | по умолчанию + | by default dd .btn-group.btn-group-sm - button.btn.btn-primary.yes(type="button", data-bind="css: {active: u.settings.comment_show_deleted()}, click: deletedCommentsShow") Да - button.btn.btn-primary.no(type="button", data-bind="css: {active: !u.settings.comment_show_deleted()}, click: deletedCommentsShow") Нет + button.btn.btn-primary.yes(type="button", data-bind="css: {active: u.settings.comment_show_deleted()}, click: deletedCommentsShow") Yes + button.btn.btn-primary.no(type="button", data-bind="css: {active: !u.settings.comment_show_deleted()}, click: deletedCommentsShow") No .panel.panel-pastvu - .panel-heading: .panel-title: a(data-toggle="collapse", href="#notice") Подписка и уведомления + .panel-heading: .panel-title: a(data-toggle="collapse", href="#notice") Subscription and notifications .panel-collapse.collapse.in#notice: .panel-body dl.dl-horizontal dt.helpexists .help.tltp-wrap span.glyphicon.glyphicon-info-sign .tltp.tltp-top.tltp-animate-move - | Исходное состояние опции - br - | «Подписаться на тему» + | Default state of the «Subscribe» checkbox br - | при отправке комментария - |  Автоподписка при комментировании темы + | below the comment writing input + |  Subscribe automatically on the comment submission dd .btn-group.btn-group-sm - button.btn.btn-primary.yes(type="button", data-bind="css: {active: u.settings.subscr_auto_reply()}, click: autoReply") Да - button.btn.btn-primary.no(type="button", data-bind="css: {active: !u.settings.subscr_auto_reply()}, click: autoReply") Нет + button.btn.btn-primary.yes(type="button", data-bind="css: {active: u.settings.subscr_auto_reply()}, click: autoReply") Yes + button.btn.btn-primary.no(type="button", data-bind="css: {active: !u.settings.subscr_auto_reply()}, click: autoReply") No dl.dl-horizontal dt.helpexists .help.tltp-wrap span.glyphicon.glyphicon-info-sign .tltp.tltp-top.tltp-animate-move - | При отключенной опции уведомления на эл. почту приходить не будут. + | When disabled, email notification will not be sent. br - | При включении, уведомления будут приходить на комментарии, + | When enabled, notifications will be sent on comments br - | созданные с момента включения опции. - |  Присылать уведомления + | created after the setting was enabled. + |  Send notifications dd .btn-group.btn-group-sm - button.btn.btn-primary.yes(type="button", data-bind="css: {active: !u.settings.subscr_disable_noty()}, click: disableNoty") Да - button.btn.btn-primary.no(type="button", data-bind="css: {active: u.settings.subscr_disable_noty()}, click: disableNoty") Нет + button.btn.btn-primary.yes(type="button", data-bind="css: {active: !u.settings.subscr_disable_noty()}, click: disableNoty") Yes + button.btn.btn-primary.no(type="button", data-bind="css: {active: u.settings.subscr_disable_noty()}, click: disableNoty") No dl.dl-horizontal dt.helpexists .help.tltp-wrap span.glyphicon.glyphicon-info-sign .tltp.tltp-top.tltp-animate-move - | Минимальное время, которое должно пройти + | Minimal amount of time between br - | между отправками писем с уведомлением - |  Минимальный интервал между отправками + | sending of notification emails + |  Minimum interval between sendings dd.throttle(data-bind="foreach: vars.subscr_throttle") label.radio-inline input(type="radio", name="subscr_throttle_radios", data-bind="attr: {disabled: $parent.u.settings.subscr_disable_noty(), id: 'subscr_throttle_radios_' + $index(), value: ''+$data}, checked: $parent.u.settings.subscr_throttle") - span(data-bind="text: ($data/60000 > 59 ? $data/3600000 + 'ч' : $data/60000 + 'мин')") + span(data-bind="text: ($data/60000 > 59 ? $data/3600000 + 'h' : $data/60000 + 'm')") diff --git a/views/module/user/subscr.pug b/views/module/user/subscr.pug index becd362c9..836b872ef 100644 --- a/views/module/user/subscr.pug +++ b/views/module/user/subscr.pug @@ -1,16 +1,16 @@ .subscr(data-bind="with: repository[M!M]") - h4(data-bind="text: (itsMe()?'Ваши подписки':'Подписки пользователя')+' на комментарии'") + h4(data-bind="text: (itsMe()?'Your subscriptions':'User subscriptions')") //ko if: nextNoty() !== null .pagOverTop .nextNoty span.glyphicon.glyphicon-bullhorn - span.text-success(data-bind="text: 'Отправка следующего уведомления запланирована на ' + nextNoty().calendar().toLowerCase() + ' (' + nextNoty().fromNow() + ')'") + span.text-success(data-bind="text: 'Sending next notice is scheduled for ' + nextNoty().calendar().toLowerCase() + ' (' + nextNoty().fromNow() + ')'") // /ko ul.nav.nav-tabs li(data-bind="css: {active: type() === 'photo'}") - a(data-bind="attr: {href: pageUrl()}, text: 'Изображения [' + $root.intl.num(types['photo_persist']()) + ']'") + a(data-bind="attr: {href: pageUrl()}, text: 'Images [' + $root.intl.num(types['photo_persist']()) + ']'") li(data-bind="css: {active: type() === 'news'}") - a(data-bind="attr: {href: pageUrl() + '?type=news'}, text: 'Новости [' + $root.intl.num(types['news_persist']()) + ']'") + a(data-bind="attr: {href: pageUrl() + '?type=news'}, text: 'News [' + $root.intl.num(types['news_persist']()) + ']'") .navContent .row .col-xs-6.col-md-3.topcol @@ -30,15 +30,15 @@ span.glyphicon(data-bind="css: $data.status.icon") // /ko //ko if: $data.my - .status.upper.mine.fringe(title="Это ваша фотография") + .status.upper.mine.fringe(title="It is your photo") span.glyphicon.glyphicon-user // /ko a.objTitle(data-bind="attr: {href: $data.link}, text: $data.title") //ko if: $data.ccount br - a.count(data-bind="html: $root.intl.num($data.ccount) + ($data.ccount_new ? ' +' + $root.intl.num($data.ccount_new) + '' : ''), attr: {href: $data.link + '?hl=comments'}", title="Комментарии") + a.count(data-bind="html: $root.intl.num($data.ccount) + ($data.ccount_new ? ' +' + $root.intl.num($data.ccount_new) + '' : ''), attr: {href: $data.link + '?hl=comments'}", title="Comments") //ko if: $data.sbscr_noty - .planed(title="Сообщение о новых комментариях запланированно к отправке в предстоящем уведомлении.") + .planed(title="Message about new comment is scheduled to be sent in the next notice.") span.glyphicon.glyphicon-bullhorn // /ko // /ko @@ -49,9 +49,9 @@ a.objTitle(data-bind="attr: {href: $data.link}, text: $data.cid + '. ' + $data.title") //ko if: $data.ccount br - a.count(data-bind="html: $root.intl.num($data.ccount) + ($data.ccount_new ? ' +' + $root.intl.num($data.ccount_new) + '' : ''), attr: {href: $data.link + '?hl=comments'}", title="Комментарии") + a.count(data-bind="html: $root.intl.num($data.ccount) + ($data.ccount_new ? ' +' + $root.intl.num($data.ccount_new) + '' : ''), attr: {href: $data.link + '?hl=comments'}", title="Comments") //ko if: $data.sbscr_noty - .planed(title="Сообщение о новых комментариях запланированно к отправке в предстоящем уведомлении.") + .planed(title="Message about new comment is scheduled to be sent in the next notice.") span.glyphicon.glyphicon-bullhorn // /ko // /ko @@ -59,11 +59,11 @@ | \ No newline at end of file diff --git a/views/module/user/tabs.pug b/views/module/user/tabs.pug index 4be02cf81..060710a54 100644 --- a/views/module/user/tabs.pug +++ b/views/module/user/tabs.pug @@ -1,15 +1,15 @@ .span9-10 - .navbar - .navbar-inner - ul.nav - li.active - a(href="#") Profile - li - a(href="#") Messages - li - a(href="#") Photo - li - a(href="#") Blogs - li - a(href="#") Comments - .row.mContainer#profile \ No newline at end of file + .navbar + .navbar-inner + ul.nav + li.active + a(href="#") Profile + li + a(href="#") Messages + li + a(href="#") Photo + li + a(href="#") Blogs + li + a(href="#") Comments + .row.mContainer#profile \ No newline at end of file diff --git a/views/module/user/userPage.pug b/views/module/user/userPage.pug index 97f9c69bc..96143fc28 100644 --- a/views/module/user/userPage.pug +++ b/views/module/user/userPage.pug @@ -1,9 +1,9 @@ .row.userPage(data-bind="with: repository[M!M]") - .col-xs-12.col-sm-3.col-lg-2(style="z-index:2;") - .mContainer.mNoDisplay.mFadeIn.affix-top.userBrief(data-bind="style: {width: briefW()}") - .col-xs-12.col-sm-9.col-lg-10.userBody - nav.navbar.navbar-pastvu.user_menu - ul.nav.navbar-nav(data-bind="foreach: menuItems") - li(data-bind="css: {active: $data.section === $parent.section()}") - a(data-bind="text: $data.name, attr: {href: ($data.disable ? '' : $data.href)}, css: {disabled: $data.disable}") - .mContainer.mHidden.mFadeIn#user_content \ No newline at end of file + .col-xs-12.col-sm-3.col-lg-2(style="z-index:2;") + .mContainer.mNoDisplay.mFadeIn.affix-top.userBrief(data-bind="style: {width: briefW()}") + .col-xs-12.col-sm-9.col-lg-10.userBody + nav.navbar.navbar-pastvu.user_menu + ul.nav.navbar-nav(data-bind="foreach: menuItems") + li(data-bind="css: {active: $data.section === $parent.section()}") + a(data-bind="text: $data.name, attr: {href: ($data.disable ? '' : $data.href)}, css: {disabled: $data.disable}") + .mContainer.mHidden.mFadeIn#user_content \ No newline at end of file diff --git a/views/status/500.pug b/views/status/500.pug index 0666ab992..6c0c7a01d 100644 --- a/views/status/500.pug +++ b/views/status/500.pug @@ -2,7 +2,7 @@ doctype html html head include ../includes/head_meta - title Ошибка - PastVu + title Error - PastVu link(rel="stylesheet", type="text/css", href='/style/normalize.css?__=' + config.hash) link(rel="stylesheet", type="text/css", href='/style/fonts.css?__=' + config.hash) style. diff --git a/views/status/badbrowser.pug b/views/status/badbrowser.pug index 99d7d8a13..8d1e89075 100644 --- a/views/status/badbrowser.pug +++ b/views/status/badbrowser.pug @@ -4,7 +4,7 @@ html include ../includes/head_top_cap body .top.fringe - a.brand(href='/', title="PastVu - ретроспектива среды обитания человечества") + a.brand(href='/', title="PastVu - retro photos of mankind's habitat") img.logo(src="/img/misc/logo.png") img.name(src="/img/misc/name-2x.png", srcset="/img/misc/name.png 1x, /img/misc/name-2x.png 2x") style. @@ -57,18 +57,18 @@ body .cent.centering_content .content.fringe p - span Команда PastVu считает, что ваш браузер + span PastVu team considers, that your browser if agent && agent.family span.curr=' '+agent.family+' '+agent.major - span устарел и не отвечает современным требованиям, по которым разработан наш сайт + span is obsolete and does not meet modern requirements, which developed our website br br - | Пожалуйста, обновите ваш браузер или установите с официального сайта один из перечисленных ниже. + | Please upgrade your browser or install one of the following from the official website. br - | Это займет всего несколько минут, но откроет вам быстрый современный интернет. + | It will take a few minutes, but will open you a fast modern Internet. br br - | А после установки возвращайтесь к нам - на самый большой архив исторических фотографий PastVu.com! + | After installation return to us - the largest archive of history photos PastVu.com! .browsers a.chrome(href="http://www.google.com/chrome", target="_blank") Google Chrome a.firefox(href="http://www.mozilla.org", target="_blank") Mozilla Firefox @@ -76,5 +76,5 @@ body a.safari(href="http://www.apple.com/safari", target="_blank") Apple Safari a.yandex(href="http://browser.yandex.net", target="_blank") Yandex .support - a(href='mailto:support@pastvu.comm?subject=Сайт выдаёт сообщение об устаревшем браузере&body=Добрый день! Идентификатор моего браузера: '+(agent&&agent.source?agent.source:''), target="_blank") - | Напишите, если мы ошибаемся: support@pastvu.com \ No newline at end of file + a(href='mailto:support@pastvu.comm?subject=Website displays a message about an outdated browser&body=Good afternoon! My browser: '+(agent&&agent.source?agent.source:''), target="_blank") + | Please write, if we are mistaken: support@pastvu.com \ No newline at end of file diff --git a/views/status/myua.pug b/views/status/myua.pug index c48e06977..b2cb41ab2 100644 --- a/views/status/myua.pug +++ b/views/status/myua.pug @@ -4,7 +4,7 @@ html include ../includes/head_top_cap body .top.fringe - a.brand(href='/', title="PastVu - ретроспектива среды обитания человечества") + a.brand(href='/', title="PastVu - retro photos of mankind's habitat") img.logo(src="/img/misc/logo.png") img.name(src="/img/misc/name-2x.png", srcset="/img/misc/name.png 1x, /img/misc/name-2x.png 2x") style.