##// END OF EJS Templates
Image search in every image view, using context menu
neko259 -
r1812:f2a9c571 default
parent child Browse files
Show More
1 NO CONTENT: modified file, binary diff hidden
NO CONTENT: modified file, binary diff hidden
@@ -1,583 +1,586 b''
1 # SOME DESCRIPTIVE TITLE.
1 # SOME DESCRIPTIVE TITLE.
2 # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
2 # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
3 # This file is distributed under the same license as the PACKAGE package.
3 # This file is distributed under the same license as the PACKAGE package.
4 # FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
4 # FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
5 #
5 #
6 msgid ""
6 msgid ""
7 msgstr ""
7 msgstr ""
8 "Project-Id-Version: PACKAGE VERSION\n"
8 "Project-Id-Version: PACKAGE VERSION\n"
9 "Report-Msgid-Bugs-To: \n"
9 "Report-Msgid-Bugs-To: \n"
10 "POT-Creation-Date: 2015-10-09 23:21+0300\n"
10 "POT-Creation-Date: 2015-10-09 23:21+0300\n"
11 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
11 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
12 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
12 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
13 "Language-Team: LANGUAGE <LL@li.org>\n"
13 "Language-Team: LANGUAGE <LL@li.org>\n"
14 "Language: ru\n"
14 "Language: ru\n"
15 "MIME-Version: 1.0\n"
15 "MIME-Version: 1.0\n"
16 "Content-Type: text/plain; charset=UTF-8\n"
16 "Content-Type: text/plain; charset=UTF-8\n"
17 "Content-Transfer-Encoding: 8bit\n"
17 "Content-Transfer-Encoding: 8bit\n"
18 "Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n"
18 "Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n"
19 "%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
19 "%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
20
20
21 #: admin.py:22
21 #: admin.py:22
22 msgid "{} posters were banned"
22 msgid "{} posters were banned"
23 msgstr ""
23 msgstr ""
24
24
25 #: authors.py:9
25 #: authors.py:9
26 msgid "author"
26 msgid "author"
27 msgstr "автор"
27 msgstr "автор"
28
28
29 #: authors.py:10
29 #: authors.py:10
30 msgid "developer"
30 msgid "developer"
31 msgstr "разработчик"
31 msgstr "разработчик"
32
32
33 #: authors.py:11
33 #: authors.py:11
34 msgid "javascript developer"
34 msgid "javascript developer"
35 msgstr "разработчик javascript"
35 msgstr "разработчик javascript"
36
36
37 #: authors.py:12
37 #: authors.py:12
38 msgid "designer"
38 msgid "designer"
39 msgstr "дизайнер"
39 msgstr "дизайнер"
40
40
41 #: forms.py:30
41 #: forms.py:30
42 msgid "Type message here. Use formatting panel for more advanced usage."
42 msgid "Type message here. Use formatting panel for more advanced usage."
43 msgstr ""
43 msgstr ""
44 "Вводите сообщение сюда. Используйте панель для более сложного форматирования."
44 "Вводите сообщение сюда. Используйте панель для более сложного форматирования."
45
45
46 #: forms.py:31
46 #: forms.py:31
47 msgid "music images i_dont_like_tags"
47 msgid "music images i_dont_like_tags"
48 msgstr "музыка картинки теги_не_нужны"
48 msgstr "музыка картинки теги_не_нужны"
49
49
50 #: forms.py:33
50 #: forms.py:33
51 msgid "Title"
51 msgid "Title"
52 msgstr "Заголовок"
52 msgstr "Заголовок"
53
53
54 #: forms.py:34
54 #: forms.py:34
55 msgid "Text"
55 msgid "Text"
56 msgstr "Текст"
56 msgstr "Текст"
57
57
58 #: forms.py:35
58 #: forms.py:35
59 msgid "Tag"
59 msgid "Tag"
60 msgstr "Метка"
60 msgstr "Метка"
61
61
62 #: forms.py:36 templates/boards/base.html:40 templates/search/search.html:7
62 #: forms.py:36 templates/boards/base.html:40 templates/search/search.html:7
63 msgid "Search"
63 msgid "Search"
64 msgstr "Поиск"
64 msgstr "Поиск"
65
65
66 #: forms.py:48
66 #: forms.py:48
67 msgid "File 1"
67 msgid "File 1"
68 msgstr "Файл 1"
68 msgstr "Файл 1"
69
69
70 #: forms.py:48
70 #: forms.py:48
71 msgid "File 2"
71 msgid "File 2"
72 msgstr "Файл 2"
72 msgstr "Файл 2"
73
73
74 #: forms.py:142
74 #: forms.py:142
75 msgid "File URL"
75 msgid "File URL"
76 msgstr "URL файла"
76 msgstr "URL файла"
77
77
78 #: forms.py:148
78 #: forms.py:148
79 msgid "e-mail"
79 msgid "e-mail"
80 msgstr ""
80 msgstr ""
81
81
82 #: forms.py:151
82 #: forms.py:151
83 msgid "Additional threads"
83 msgid "Additional threads"
84 msgstr "Дополнительные темы"
84 msgstr "Дополнительные темы"
85
85
86 #: forms.py:162
86 #: forms.py:162
87 #, python-format
87 #, python-format
88 msgid "Title must have less than %s characters"
88 msgid "Title must have less than %s characters"
89 msgstr "Заголовок должен иметь меньше %s символов"
89 msgstr "Заголовок должен иметь меньше %s символов"
90
90
91 #: forms.py:172
91 #: forms.py:172
92 #, python-format
92 #, python-format
93 msgid "Text must have less than %s characters"
93 msgid "Text must have less than %s characters"
94 msgstr "Текст должен быть короче %s символов"
94 msgstr "Текст должен быть короче %s символов"
95
95
96 #: forms.py:192
96 #: forms.py:192
97 msgid "Invalid URL"
97 msgid "Invalid URL"
98 msgstr "Неверный URL"
98 msgstr "Неверный URL"
99
99
100 #: forms.py:213
100 #: forms.py:213
101 msgid "Invalid additional thread list"
101 msgid "Invalid additional thread list"
102 msgstr "Неверный список дополнительных тем"
102 msgstr "Неверный список дополнительных тем"
103
103
104 #: forms.py:258
104 #: forms.py:258
105 msgid "Either text or file must be entered."
105 msgid "Either text or file must be entered."
106 msgstr "Текст или файл должны быть введены."
106 msgstr "Текст или файл должны быть введены."
107
107
108 #: forms.py:317 templates/boards/all_threads.html:153
108 #: forms.py:317 templates/boards/all_threads.html:153
109 #: templates/boards/rss/post.html:10 templates/boards/tags.html:6
109 #: templates/boards/rss/post.html:10 templates/boards/tags.html:6
110 msgid "Tags"
110 msgid "Tags"
111 msgstr "Метки"
111 msgstr "Метки"
112
112
113 #: forms.py:324
113 #: forms.py:324
114 msgid "Inappropriate characters in tags."
114 msgid "Inappropriate characters in tags."
115 msgstr "Недопустимые символы в метках."
115 msgstr "Недопустимые символы в метках."
116
116
117 #: forms.py:344
117 #: forms.py:344
118 msgid "Need at least one section."
118 msgid "Need at least one section."
119 msgstr "Нужен хотя бы один раздел."
119 msgstr "Нужен хотя бы один раздел."
120
120
121 #: forms.py:356
121 #: forms.py:356
122 msgid "Theme"
122 msgid "Theme"
123 msgstr "Тема"
123 msgstr "Тема"
124
124
125 #: forms.py:357
125 #: forms.py:357
126 msgid "Image view mode"
126 msgid "Image view mode"
127 msgstr "Режим просмотра изображений"
127 msgstr "Режим просмотра изображений"
128
128
129 #: forms.py:358
129 #: forms.py:358
130 msgid "User name"
130 msgid "User name"
131 msgstr "Имя пользователя"
131 msgstr "Имя пользователя"
132
132
133 #: forms.py:359
133 #: forms.py:359
134 msgid "Time zone"
134 msgid "Time zone"
135 msgstr "Часовой пояс"
135 msgstr "Часовой пояс"
136
136
137 #: forms.py:365
137 #: forms.py:365
138 msgid "Inappropriate characters."
138 msgid "Inappropriate characters."
139 msgstr "Недопустимые символы."
139 msgstr "Недопустимые символы."
140
140
141 #: templates/boards/404.html:6
141 #: templates/boards/404.html:6
142 msgid "Not found"
142 msgid "Not found"
143 msgstr "Не найдено"
143 msgstr "Не найдено"
144
144
145 #: templates/boards/404.html:12
145 #: templates/boards/404.html:12
146 msgid "This page does not exist"
146 msgid "This page does not exist"
147 msgstr "Этой страницы не существует"
147 msgstr "Этой страницы не существует"
148
148
149 #: templates/boards/all_threads.html:35
149 #: templates/boards/all_threads.html:35
150 msgid "Details"
150 msgid "Details"
151 msgstr "Подробности"
151 msgstr "Подробности"
152
152
153 #: templates/boards/all_threads.html:69
153 #: templates/boards/all_threads.html:69
154 msgid "Edit tag"
154 msgid "Edit tag"
155 msgstr "Изменить метку"
155 msgstr "Изменить метку"
156
156
157 #: templates/boards/all_threads.html:76
157 #: templates/boards/all_threads.html:76
158 #, python-format
158 #, python-format
159 msgid "%(count)s active thread"
159 msgid "%(count)s active thread"
160 msgid_plural "%(count)s active threads"
160 msgid_plural "%(count)s active threads"
161 msgstr[0] "%(count)s активная тема"
161 msgstr[0] "%(count)s активная тема"
162 msgstr[1] "%(count)s активные темы"
162 msgstr[1] "%(count)s активные темы"
163 msgstr[2] "%(count)s активных тем"
163 msgstr[2] "%(count)s активных тем"
164
164
165 #: templates/boards/all_threads.html:76
165 #: templates/boards/all_threads.html:76
166 #, python-format
166 #, python-format
167 msgid "%(count)s thread in bumplimit"
167 msgid "%(count)s thread in bumplimit"
168 msgid_plural "%(count)s threads in bumplimit"
168 msgid_plural "%(count)s threads in bumplimit"
169 msgstr[0] "%(count)s тема в бамплимите"
169 msgstr[0] "%(count)s тема в бамплимите"
170 msgstr[1] "%(count)s темы в бамплимите"
170 msgstr[1] "%(count)s темы в бамплимите"
171 msgstr[2] "%(count)s тем в бамплимите"
171 msgstr[2] "%(count)s тем в бамплимите"
172
172
173 #: templates/boards/all_threads.html:77
173 #: templates/boards/all_threads.html:77
174 #, python-format
174 #, python-format
175 msgid "%(count)s archived thread"
175 msgid "%(count)s archived thread"
176 msgid_plural "%(count)s archived thread"
176 msgid_plural "%(count)s archived thread"
177 msgstr[0] "%(count)s архивная тема"
177 msgstr[0] "%(count)s архивная тема"
178 msgstr[1] "%(count)s архивные темы"
178 msgstr[1] "%(count)s архивные темы"
179 msgstr[2] "%(count)s архивных тем"
179 msgstr[2] "%(count)s архивных тем"
180
180
181 #: templates/boards/all_threads.html:78 templates/boards/post.html:102
181 #: templates/boards/all_threads.html:78 templates/boards/post.html:102
182 #, python-format
182 #, python-format
183 #| msgid "%(count)s message"
183 #| msgid "%(count)s message"
184 #| msgid_plural "%(count)s messages"
184 #| msgid_plural "%(count)s messages"
185 msgid "%(count)s message"
185 msgid "%(count)s message"
186 msgid_plural "%(count)s messages"
186 msgid_plural "%(count)s messages"
187 msgstr[0] "%(count)s сообщение"
187 msgstr[0] "%(count)s сообщение"
188 msgstr[1] "%(count)s сообщения"
188 msgstr[1] "%(count)s сообщения"
189 msgstr[2] "%(count)s сообщений"
189 msgstr[2] "%(count)s сообщений"
190
190
191 #: templates/boards/all_threads.html:95 templates/boards/feed.html:30
191 #: templates/boards/all_threads.html:95 templates/boards/feed.html:30
192 #: templates/boards/notifications.html:17 templates/search/search.html:26
192 #: templates/boards/notifications.html:17 templates/search/search.html:26
193 msgid "Previous page"
193 msgid "Previous page"
194 msgstr "Предыдущая страница"
194 msgstr "Предыдущая страница"
195
195
196 #: templates/boards/all_threads.html:109
196 #: templates/boards/all_threads.html:109
197 #, python-format
197 #, python-format
198 msgid "Skipped %(count)s reply. Open thread to see all replies."
198 msgid "Skipped %(count)s reply. Open thread to see all replies."
199 msgid_plural "Skipped %(count)s replies. Open thread to see all replies."
199 msgid_plural "Skipped %(count)s replies. Open thread to see all replies."
200 msgstr[0] "Пропущен %(count)s ответ. Откройте тред, чтобы увидеть все ответы."
200 msgstr[0] "Пропущен %(count)s ответ. Откройте тред, чтобы увидеть все ответы."
201 msgstr[1] ""
201 msgstr[1] ""
202 "Пропущено %(count)s ответа. Откройте тред, чтобы увидеть все ответы."
202 "Пропущено %(count)s ответа. Откройте тред, чтобы увидеть все ответы."
203 msgstr[2] ""
203 msgstr[2] ""
204 "Пропущено %(count)s ответов. Откройте тред, чтобы увидеть все ответы."
204 "Пропущено %(count)s ответов. Откройте тред, чтобы увидеть все ответы."
205
205
206 #: templates/boards/all_threads.html:127 templates/boards/feed.html:40
206 #: templates/boards/all_threads.html:127 templates/boards/feed.html:40
207 #: templates/boards/notifications.html:27 templates/search/search.html:37
207 #: templates/boards/notifications.html:27 templates/search/search.html:37
208 msgid "Next page"
208 msgid "Next page"
209 msgstr "Следующая страница"
209 msgstr "Следующая страница"
210
210
211 #: templates/boards/all_threads.html:132
211 #: templates/boards/all_threads.html:132
212 msgid "No threads exist. Create the first one!"
212 msgid "No threads exist. Create the first one!"
213 msgstr "Нет тем. Создайте первую!"
213 msgstr "Нет тем. Создайте первую!"
214
214
215 #: templates/boards/all_threads.html:138
215 #: templates/boards/all_threads.html:138
216 msgid "Create new thread"
216 msgid "Create new thread"
217 msgstr "Создать новую тему"
217 msgstr "Создать новую тему"
218
218
219 #: templates/boards/all_threads.html:143 templates/boards/preview.html:16
219 #: templates/boards/all_threads.html:143 templates/boards/preview.html:16
220 #: templates/boards/thread_normal.html:51
220 #: templates/boards/thread_normal.html:51
221 msgid "Post"
221 msgid "Post"
222 msgstr "Отправить"
222 msgstr "Отправить"
223
223
224 #: templates/boards/all_threads.html:144 templates/boards/preview.html:6
224 #: templates/boards/all_threads.html:144 templates/boards/preview.html:6
225 #: templates/boards/staticpages/help.html:21
225 #: templates/boards/staticpages/help.html:21
226 #: templates/boards/thread_normal.html:52
226 #: templates/boards/thread_normal.html:52
227 msgid "Preview"
227 msgid "Preview"
228 msgstr "Предпросмотр"
228 msgstr "Предпросмотр"
229
229
230 #: templates/boards/all_threads.html:149
230 #: templates/boards/all_threads.html:149
231 msgid "Tags must be delimited by spaces. Text or image is required."
231 msgid "Tags must be delimited by spaces. Text or image is required."
232 msgstr ""
232 msgstr ""
233 "Метки должны быть разделены пробелами. Текст или изображение обязательны."
233 "Метки должны быть разделены пробелами. Текст или изображение обязательны."
234
234
235 #: templates/boards/all_threads.html:152 templates/boards/thread_normal.html:58
235 #: templates/boards/all_threads.html:152 templates/boards/thread_normal.html:58
236 msgid "Text syntax"
236 msgid "Text syntax"
237 msgstr "Синтаксис текста"
237 msgstr "Синтаксис текста"
238
238
239 #: templates/boards/all_threads.html:166 templates/boards/feed.html:53
239 #: templates/boards/all_threads.html:166 templates/boards/feed.html:53
240 msgid "Pages:"
240 msgid "Pages:"
241 msgstr "Страницы: "
241 msgstr "Страницы: "
242
242
243 #: templates/boards/authors.html:6 templates/boards/authors.html.py:12
243 #: templates/boards/authors.html:6 templates/boards/authors.html.py:12
244 msgid "Authors"
244 msgid "Authors"
245 msgstr "Авторы"
245 msgstr "Авторы"
246
246
247 #: templates/boards/authors.html:26
247 #: templates/boards/authors.html:26
248 msgid "Distributed under the"
248 msgid "Distributed under the"
249 msgstr "Распространяется под"
249 msgstr "Распространяется под"
250
250
251 #: templates/boards/authors.html:28
251 #: templates/boards/authors.html:28
252 msgid "license"
252 msgid "license"
253 msgstr "лицензией"
253 msgstr "лицензией"
254
254
255 #: templates/boards/authors.html:30
255 #: templates/boards/authors.html:30
256 msgid "Repository"
256 msgid "Repository"
257 msgstr "Репозиторий"
257 msgstr "Репозиторий"
258
258
259 #: templates/boards/base.html:14 templates/boards/base.html.py:41
259 #: templates/boards/base.html:14 templates/boards/base.html.py:41
260 msgid "Feed"
260 msgid "Feed"
261 msgstr "Лента"
261 msgstr "Лента"
262
262
263 #: templates/boards/base.html:31
263 #: templates/boards/base.html:31
264 msgid "All threads"
264 msgid "All threads"
265 msgstr "Все темы"
265 msgstr "Все темы"
266
266
267 #: templates/boards/base.html:37
267 #: templates/boards/base.html:37
268 msgid "Add tags"
268 msgid "Add tags"
269 msgstr "Добавить метки"
269 msgstr "Добавить метки"
270
270
271 #: templates/boards/base.html:39
271 #: templates/boards/base.html:39
272 msgid "Tag management"
272 msgid "Tag management"
273 msgstr "Управление метками"
273 msgstr "Управление метками"
274
274
275 #: templates/boards/base.html:39
275 #: templates/boards/base.html:39
276 msgid "tags"
276 msgid "tags"
277 msgstr "метки"
277 msgstr "метки"
278
278
279 #: templates/boards/base.html:40
279 #: templates/boards/base.html:40
280 msgid "search"
280 msgid "search"
281 msgstr "поиск"
281 msgstr "поиск"
282
282
283 #: templates/boards/base.html:41 templates/boards/feed.html:11
283 #: templates/boards/base.html:41 templates/boards/feed.html:11
284 msgid "feed"
284 msgid "feed"
285 msgstr "лента"
285 msgstr "лента"
286
286
287 #: templates/boards/base.html:42 templates/boards/random.html:6
287 #: templates/boards/base.html:42 templates/boards/random.html:6
288 msgid "Random images"
288 msgid "Random images"
289 msgstr "Случайные изображения"
289 msgstr "Случайные изображения"
290
290
291 #: templates/boards/base.html:42
291 #: templates/boards/base.html:42
292 msgid "random"
292 msgid "random"
293 msgstr "случайные"
293 msgstr "случайные"
294
294
295 #: templates/boards/base.html:44
295 #: templates/boards/base.html:44
296 msgid "favorites"
296 msgid "favorites"
297 msgstr "избранное"
297 msgstr "избранное"
298
298
299 #: templates/boards/base.html:48 templates/boards/base.html.py:49
299 #: templates/boards/base.html:48 templates/boards/base.html.py:49
300 #: templates/boards/notifications.html:8
300 #: templates/boards/notifications.html:8
301 msgid "Notifications"
301 msgid "Notifications"
302 msgstr "Уведомления"
302 msgstr "Уведомления"
303
303
304 #: templates/boards/base.html:56 templates/boards/settings.html:8
304 #: templates/boards/base.html:56 templates/boards/settings.html:8
305 msgid "Settings"
305 msgid "Settings"
306 msgstr "Настройки"
306 msgstr "Настройки"
307
307
308 #: templates/boards/base.html:59
308 #: templates/boards/base.html:59
309 msgid "Loading..."
309 msgid "Loading..."
310 msgstr "Загрузка..."
310 msgstr "Загрузка..."
311
311
312 #: templates/boards/base.html:71
312 #: templates/boards/base.html:71
313 msgid "Admin"
313 msgid "Admin"
314 msgstr "Администрирование"
314 msgstr "Администрирование"
315
315
316 #: templates/boards/base.html:73
316 #: templates/boards/base.html:73
317 #, python-format
317 #, python-format
318 msgid "Speed: %(ppd)s posts per day"
318 msgid "Speed: %(ppd)s posts per day"
319 msgstr "Скорость: %(ppd)s сообщений в день"
319 msgstr "Скорость: %(ppd)s сообщений в день"
320
320
321 #: templates/boards/base.html:75
321 #: templates/boards/base.html:75
322 msgid "Up"
322 msgid "Up"
323 msgstr "Вверх"
323 msgstr "Вверх"
324
324
325 #: templates/boards/feed.html:45
325 #: templates/boards/feed.html:45
326 msgid "No posts exist. Create the first one!"
326 msgid "No posts exist. Create the first one!"
327 msgstr "Нет сообщений. Создайте первое!"
327 msgstr "Нет сообщений. Создайте первое!"
328
328
329 #: templates/boards/post.html:33
329 #: templates/boards/post.html:33
330 msgid "Open"
330 msgid "Open"
331 msgstr "Открыть"
331 msgstr "Открыть"
332
332
333 #: templates/boards/post.html:35 templates/boards/post.html.py:46
333 #: templates/boards/post.html:35 templates/boards/post.html.py:46
334 msgid "Reply"
334 msgid "Reply"
335 msgstr "Ответить"
335 msgstr "Ответить"
336
336
337 #: templates/boards/post.html:41
337 #: templates/boards/post.html:41
338 msgid " in "
338 msgid " in "
339 msgstr " в "
339 msgstr " в "
340
340
341 #: templates/boards/post.html:51
341 #: templates/boards/post.html:51
342 msgid "Edit"
342 msgid "Edit"
343 msgstr "Изменить"
343 msgstr "Изменить"
344
344
345 #: templates/boards/post.html:53
345 #: templates/boards/post.html:53
346 msgid "Edit thread"
346 msgid "Edit thread"
347 msgstr "Изменить тему"
347 msgstr "Изменить тему"
348
348
349 #: templates/boards/post.html:91
349 #: templates/boards/post.html:91
350 msgid "Replies"
350 msgid "Replies"
351 msgstr "Ответы"
351 msgstr "Ответы"
352
352
353 #: templates/boards/post.html:103
353 #: templates/boards/post.html:103
354 #, python-format
354 #, python-format
355 msgid "%(count)s image"
355 msgid "%(count)s image"
356 msgid_plural "%(count)s images"
356 msgid_plural "%(count)s images"
357 msgstr[0] "%(count)s изображение"
357 msgstr[0] "%(count)s изображение"
358 msgstr[1] "%(count)s изображения"
358 msgstr[1] "%(count)s изображения"
359 msgstr[2] "%(count)s изображений"
359 msgstr[2] "%(count)s изображений"
360
360
361 #: templates/boards/rss/post.html:5
361 #: templates/boards/rss/post.html:5
362 msgid "Post image"
362 msgid "Post image"
363 msgstr "Изображение сообщения"
363 msgstr "Изображение сообщения"
364
364
365 #: templates/boards/settings.html:15
365 #: templates/boards/settings.html:15
366 msgid "You are moderator."
366 msgid "You are moderator."
367 msgstr "Вы модератор."
367 msgstr "Вы модератор."
368
368
369 #: templates/boards/settings.html:19
369 #: templates/boards/settings.html:19
370 msgid "Hidden tags:"
370 msgid "Hidden tags:"
371 msgstr "Скрытые метки:"
371 msgstr "Скрытые метки:"
372
372
373 #: templates/boards/settings.html:25
373 #: templates/boards/settings.html:25
374 msgid "No hidden tags."
374 msgid "No hidden tags."
375 msgstr "Нет скрытых меток."
375 msgstr "Нет скрытых меток."
376
376
377 #: templates/boards/settings.html:34
377 #: templates/boards/settings.html:34
378 msgid "Save"
378 msgid "Save"
379 msgstr "Сохранить"
379 msgstr "Сохранить"
380
380
381 #: templates/boards/staticpages/banned.html:6
381 #: templates/boards/staticpages/banned.html:6
382 msgid "Banned"
382 msgid "Banned"
383 msgstr "Заблокирован"
383 msgstr "Заблокирован"
384
384
385 #: templates/boards/staticpages/banned.html:11
385 #: templates/boards/staticpages/banned.html:11
386 msgid "Your IP address has been banned. Contact the administrator"
386 msgid "Your IP address has been banned. Contact the administrator"
387 msgstr "Ваш IP адрес был заблокирован. Свяжитесь с администратором"
387 msgstr "Ваш IP адрес был заблокирован. Свяжитесь с администратором"
388
388
389 #: templates/boards/staticpages/help.html:6
389 #: templates/boards/staticpages/help.html:6
390 #: templates/boards/staticpages/help.html:10
390 #: templates/boards/staticpages/help.html:10
391 msgid "Syntax"
391 msgid "Syntax"
392 msgstr "Синтаксис"
392 msgstr "Синтаксис"
393
393
394 #: templates/boards/staticpages/help.html:11
394 #: templates/boards/staticpages/help.html:11
395 msgid "Italic text"
395 msgid "Italic text"
396 msgstr "Курсивный текст"
396 msgstr "Курсивный текст"
397
397
398 #: templates/boards/staticpages/help.html:12
398 #: templates/boards/staticpages/help.html:12
399 msgid "Bold text"
399 msgid "Bold text"
400 msgstr "Полужирный текст"
400 msgstr "Полужирный текст"
401
401
402 #: templates/boards/staticpages/help.html:13
402 #: templates/boards/staticpages/help.html:13
403 msgid "Spoiler"
403 msgid "Spoiler"
404 msgstr "Спойлер"
404 msgstr "Спойлер"
405
405
406 #: templates/boards/staticpages/help.html:14
406 #: templates/boards/staticpages/help.html:14
407 msgid "Link to a post"
407 msgid "Link to a post"
408 msgstr "Ссылка на сообщение"
408 msgstr "Ссылка на сообщение"
409
409
410 #: templates/boards/staticpages/help.html:15
410 #: templates/boards/staticpages/help.html:15
411 msgid "Strikethrough text"
411 msgid "Strikethrough text"
412 msgstr "Зачеркнутый текст"
412 msgstr "Зачеркнутый текст"
413
413
414 #: templates/boards/staticpages/help.html:16
414 #: templates/boards/staticpages/help.html:16
415 msgid "Comment"
415 msgid "Comment"
416 msgstr "Комментарий"
416 msgstr "Комментарий"
417
417
418 #: templates/boards/staticpages/help.html:17
418 #: templates/boards/staticpages/help.html:17
419 #: templates/boards/staticpages/help.html:18
419 #: templates/boards/staticpages/help.html:18
420 msgid "Quote"
420 msgid "Quote"
421 msgstr "Цитата"
421 msgstr "Цитата"
422
422
423 #: templates/boards/staticpages/help.html:21
423 #: templates/boards/staticpages/help.html:21
424 msgid "You can try pasting the text and previewing the result here:"
424 msgid "You can try pasting the text and previewing the result here:"
425 msgstr "Вы можете попробовать вставить текст и проверить результат здесь:"
425 msgstr "Вы можете попробовать вставить текст и проверить результат здесь:"
426
426
427 #: templates/boards/tags.html:17
427 #: templates/boards/tags.html:17
428 msgid "Sections:"
428 msgid "Sections:"
429 msgstr "Разделы:"
429 msgstr "Разделы:"
430
430
431 #: templates/boards/tags.html:30
431 #: templates/boards/tags.html:30
432 msgid "Other tags:"
432 msgid "Other tags:"
433 msgstr "Другие метки:"
433 msgstr "Другие метки:"
434
434
435 #: templates/boards/tags.html:43
435 #: templates/boards/tags.html:43
436 msgid "All tags..."
436 msgid "All tags..."
437 msgstr "Все метки..."
437 msgstr "Все метки..."
438
438
439 #: templates/boards/thread.html:14
439 #: templates/boards/thread.html:14
440 msgid "Normal"
440 msgid "Normal"
441 msgstr "Нормальный"
441 msgstr "Нормальный"
442
442
443 #: templates/boards/thread.html:15
443 #: templates/boards/thread.html:15
444 msgid "Gallery"
444 msgid "Gallery"
445 msgstr "Галерея"
445 msgstr "Галерея"
446
446
447 #: templates/boards/thread.html:16
447 #: templates/boards/thread.html:16
448 msgid "Tree"
448 msgid "Tree"
449 msgstr "Дерево"
449 msgstr "Дерево"
450
450
451 #: templates/boards/thread.html:35
451 #: templates/boards/thread.html:35
452 msgid "message"
452 msgid "message"
453 msgid_plural "messages"
453 msgid_plural "messages"
454 msgstr[0] "сообщение"
454 msgstr[0] "сообщение"
455 msgstr[1] "сообщения"
455 msgstr[1] "сообщения"
456 msgstr[2] "сообщений"
456 msgstr[2] "сообщений"
457
457
458 #: templates/boards/thread.html:38
458 #: templates/boards/thread.html:38
459 msgid "image"
459 msgid "image"
460 msgid_plural "images"
460 msgid_plural "images"
461 msgstr[0] "изображение"
461 msgstr[0] "изображение"
462 msgstr[1] "изображения"
462 msgstr[1] "изображения"
463 msgstr[2] "изображений"
463 msgstr[2] "изображений"
464
464
465 #: templates/boards/thread.html:40
465 #: templates/boards/thread.html:40
466 msgid "Last update: "
466 msgid "Last update: "
467 msgstr "Последнее обновление: "
467 msgstr "Последнее обновление: "
468
468
469 #: templates/boards/thread_gallery.html:36
469 #: templates/boards/thread_gallery.html:36
470 msgid "No images."
470 msgid "No images."
471 msgstr "Нет изображений."
471 msgstr "Нет изображений."
472
472
473 #: templates/boards/thread_normal.html:30
473 #: templates/boards/thread_normal.html:30
474 msgid "posts to bumplimit"
474 msgid "posts to bumplimit"
475 msgstr "сообщений до бамплимита"
475 msgstr "сообщений до бамплимита"
476
476
477 #: templates/boards/thread_normal.html:44
477 #: templates/boards/thread_normal.html:44
478 msgid "Reply to thread"
478 msgid "Reply to thread"
479 msgstr "Ответить в тему"
479 msgstr "Ответить в тему"
480
480
481 #: templates/boards/thread_normal.html:44
481 #: templates/boards/thread_normal.html:44
482 msgid "to message "
482 msgid "to message "
483 msgstr "на сообщение"
483 msgstr "на сообщение"
484
484
485 #: templates/boards/thread_normal.html:59
485 #: templates/boards/thread_normal.html:59
486 msgid "Close form"
486 msgid "Close form"
487 msgstr "Закрыть форму"
487 msgstr "Закрыть форму"
488
488
489 #: templates/search/search.html:17
489 #: templates/search/search.html:17
490 msgid "Ok"
490 msgid "Ok"
491 msgstr "Ок"
491 msgstr "Ок"
492
492
493 #: utils.py:120
493 #: utils.py:120
494 #, python-format
494 #, python-format
495 msgid "File must be less than %s but is %s."
495 msgid "File must be less than %s but is %s."
496 msgstr "Файл должен быть менее %s, но его размер %s."
496 msgstr "Файл должен быть менее %s, но его размер %s."
497
497
498 msgid "Please wait %(delay)d second before sending message"
498 msgid "Please wait %(delay)d second before sending message"
499 msgid_plural "Please wait %(delay)d seconds before sending message"
499 msgid_plural "Please wait %(delay)d seconds before sending message"
500 msgstr[0] "Пожалуйста подождите %(delay)d секунду перед отправкой сообщения"
500 msgstr[0] "Пожалуйста подождите %(delay)d секунду перед отправкой сообщения"
501 msgstr[1] "Пожалуйста подождите %(delay)d секунды перед отправкой сообщения"
501 msgstr[1] "Пожалуйста подождите %(delay)d секунды перед отправкой сообщения"
502 msgstr[2] "Пожалуйста подождите %(delay)d секунд перед отправкой сообщения"
502 msgstr[2] "Пожалуйста подождите %(delay)d секунд перед отправкой сообщения"
503
503
504 msgid "New threads"
504 msgid "New threads"
505 msgstr "Новые темы"
505 msgstr "Новые темы"
506
506
507 #, python-format
507 #, python-format
508 msgid "Max file size is %(size)s."
508 msgid "Max file size is %(size)s."
509 msgstr "Максимальный размер файла %(size)s."
509 msgstr "Максимальный размер файла %(size)s."
510
510
511 msgid "Size of media:"
511 msgid "Size of media:"
512 msgstr "Размер медиа:"
512 msgstr "Размер медиа:"
513
513
514 msgid "Statistics"
514 msgid "Statistics"
515 msgstr "Статистика"
515 msgstr "Статистика"
516
516
517 msgid "Invalid PoW."
517 msgid "Invalid PoW."
518 msgstr "Неверный PoW."
518 msgstr "Неверный PoW."
519
519
520 msgid "Stale PoW."
520 msgid "Stale PoW."
521 msgstr "PoW устарел."
521 msgstr "PoW устарел."
522
522
523 msgid "Show"
523 msgid "Show"
524 msgstr "Показывать"
524 msgstr "Показывать"
525
525
526 msgid "Hide"
526 msgid "Hide"
527 msgstr "Скрывать"
527 msgstr "Скрывать"
528
528
529 msgid "Add to favorites"
529 msgid "Add to favorites"
530 msgstr "Добавить в избранное"
530 msgstr "Добавить в избранное"
531
531
532 msgid "Remove from favorites"
532 msgid "Remove from favorites"
533 msgstr "Убрать из избранного"
533 msgstr "Убрать из избранного"
534
534
535 msgid "Monochrome"
535 msgid "Monochrome"
536 msgstr "Монохромный"
536 msgstr "Монохромный"
537
537
538 msgid "Subsections: "
538 msgid "Subsections: "
539 msgstr "Подразделы: "
539 msgstr "Подразделы: "
540
540
541 msgid "Change file source"
541 msgid "Change file source"
542 msgstr "Изменить источник файла"
542 msgstr "Изменить источник файла"
543
543
544 msgid "interesting"
544 msgid "interesting"
545 msgstr "интересное"
545 msgstr "интересное"
546
546
547 msgid "images"
547 msgid "images"
548 msgstr "изображения"
548 msgstr "изображения"
549
549
550 msgid "Delete post"
550 msgid "Delete post"
551 msgstr "Удалить пост"
551 msgstr "Удалить пост"
552
552
553 msgid "Delete thread"
553 msgid "Delete thread"
554 msgstr "Удалить тему"
554 msgstr "Удалить тему"
555
555
556 msgid "Messages per day/week/month:"
556 msgid "Messages per day/week/month:"
557 msgstr "Сообщений за день/неделю/месяц:"
557 msgstr "Сообщений за день/неделю/месяц:"
558
558
559 msgid "Subscribe to thread"
559 msgid "Subscribe to thread"
560 msgstr "Подписаться на тему"
560 msgstr "Подписаться на тему"
561
561
562 msgid "Active threads:"
562 msgid "Active threads:"
563 msgstr "Активные темы:"
563 msgstr "Активные темы:"
564
564
565 msgid "No active threads today."
565 msgid "No active threads today."
566 msgstr "Сегодня нет активных тем."
566 msgstr "Сегодня нет активных тем."
567
567
568 msgid "Insert URLs on separate lines."
568 msgid "Insert URLs on separate lines."
569 msgstr "Вставляйте ссылки на отдельных строках."
569 msgstr "Вставляйте ссылки на отдельных строках."
570
570
571 msgid "You can post no more than %(files)d file."
571 msgid "You can post no more than %(files)d file."
572 msgid_plural "You can post no more than %(files)d files."
572 msgid_plural "You can post no more than %(files)d files."
573 msgstr[0] "Вы можете отправить не более %(files)d файла."
573 msgstr[0] "Вы можете отправить не более %(files)d файла."
574 msgstr[1] "Вы можете отправить не более %(files)d файлов."
574 msgstr[1] "Вы можете отправить не более %(files)d файлов."
575 msgstr[2] "Вы можете отправить не более %(files)d файлов."
575 msgstr[2] "Вы можете отправить не более %(files)d файлов."
576
576
577 #, python-format
577 #, python-format
578 msgid "Max file number is %(max_files)s."
578 msgid "Max file number is %(max_files)s."
579 msgstr "Максимальное количество файлов %(max_files)s."
579 msgstr "Максимальное количество файлов %(max_files)s."
580
580
581 msgid "Moderation"
581 msgid "Moderation"
582 msgstr "Модерация"
582 msgstr "Модерация"
583
583
584 msgid "Duplicates search"
585 msgstr "Поиск дубликатов"
586
@@ -1,209 +1,255 b''
1 import re
1 import re
2
2
3 from django.contrib.staticfiles import finders
3 from django.contrib.staticfiles import finders
4 from django.contrib.staticfiles.templatetags.staticfiles import static
4 from django.contrib.staticfiles.templatetags.staticfiles import static
5 from django.core.files.images import get_image_dimensions
5 from django.core.files.images import get_image_dimensions
6 from django.template.defaultfilters import filesizeformat
6 from django.template.defaultfilters import filesizeformat
7 from django.core.urlresolvers import reverse
8 from django.utils.translation import ugettext_lazy as _, ungettext_lazy
7
9
8 from boards.utils import get_domain, cached_result
10 from boards.utils import get_domain, cached_result
11 from boards import settings
9
12
10
13
11 FILE_STUB_IMAGE = 'images/file.png'
14 FILE_STUB_IMAGE = 'images/file.png'
12 FILE_STUB_URL = 'url'
15 FILE_STUB_URL = 'url'
13 FILE_FILEFORMAT = 'images/fileformats/{}.png'
16 FILE_FILEFORMAT = 'images/fileformats/{}.png'
14
17
15
18
16 FILE_TYPES_VIDEO = (
19 FILE_TYPES_VIDEO = (
17 'webm',
20 'webm',
18 'mp4',
21 'mp4',
19 'mpeg',
22 'mpeg',
20 'ogv',
23 'ogv',
21 )
24 )
22 FILE_TYPE_SVG = 'svg'
25 FILE_TYPE_SVG = 'svg'
23 FILE_TYPES_AUDIO = (
26 FILE_TYPES_AUDIO = (
24 'ogg',
27 'ogg',
25 'mp3',
28 'mp3',
26 'opus',
29 'opus',
27 )
30 )
28 FILE_TYPES_IMAGE = (
31 FILE_TYPES_IMAGE = (
29 'jpeg',
32 'jpeg',
30 'jpg',
33 'jpg',
31 'png',
34 'png',
32 'bmp',
35 'bmp',
33 'gif',
36 'gif',
34 )
37 )
35
38
36 PLAIN_FILE_FORMATS = {
39 PLAIN_FILE_FORMATS = {
37 'zip': 'archive',
40 'zip': 'archive',
38 'tar': 'archive',
41 'tar': 'archive',
39 'gz': 'archive',
42 'gz': 'archive',
40 'mid' : 'midi',
43 'mid' : 'midi',
41 }
44 }
42
45
43 URL_PROTOCOLS = {
46 URL_PROTOCOLS = {
44 'magnet': 'magnet',
47 'magnet': 'magnet',
45 }
48 }
46
49
47 CSS_CLASS_IMAGE = 'image'
50 CSS_CLASS_IMAGE = 'image'
48 CSS_CLASS_THUMB = 'thumb'
51 CSS_CLASS_THUMB = 'thumb'
49
52
50
53
51 def get_viewers():
54 def get_viewers():
52 return AbstractViewer.__subclasses__()
55 return AbstractViewer.__subclasses__()
53
56
54
57
55 def get_static_dimensions(filename):
58 def get_static_dimensions(filename):
56 file_path = finders.find(filename)
59 file_path = finders.find(filename)
57 return get_image_dimensions(file_path)
60 return get_image_dimensions(file_path)
58
61
59
62
60 # TODO Move this to utils
63 # TODO Move this to utils
61 def file_exists(filename):
64 def file_exists(filename):
62 return finders.find(filename) is not None
65 return finders.find(filename) is not None
63
66
64
67
65 class AbstractViewer:
68 class AbstractViewer:
66 def __init__(self, file, file_type, hash, url):
69 def __init__(self, file, file_type, hash, url):
67 self.file = file
70 self.file = file
68 self.file_type = file_type
71 self.file_type = file_type
69 self.hash = hash
72 self.hash = hash
70 self.url = url
73 self.url = url
71
74
72 @staticmethod
75 @staticmethod
73 def supports(file_type):
76 def supports(file_type):
74 return True
77 return True
75
78
76 def get_view(self):
79 def get_view(self):
77 return '<div class="image">'\
80 return '<div class="image" id="file{}">'\
78 '{}'\
81 '{}'\
79 '<div class="image-metadata"><a href="{}" download >{}, {}</a></div>'\
82 '<div class="image-metadata"><a href="{}" download >{}, {}</a>'\
80 '</div>'.format(self.get_format_view(), self.file.url,
83 ' <a class="file-menu" href="#">🔍 </a></div>'\
81 self.file_type, filesizeformat(self.file.size))
84 '</div>'.format(self.hash, self.get_format_view(), self.file.url,
85 self.file_type, filesizeformat(self.file.size))\
86 + self._build_context_menu(self.get_context_menu())
82
87
83 def get_format_view(self):
88 def get_format_view(self):
84 image_name = PLAIN_FILE_FORMATS.get(self.file_type, self.file_type)
89 image_name = PLAIN_FILE_FORMATS.get(self.file_type, self.file_type)
85 file_name = FILE_FILEFORMAT.format(image_name)
90 file_name = FILE_FILEFORMAT.format(image_name)
86
91
87 if file_exists(file_name):
92 if file_exists(file_name):
88 image = file_name
93 image = file_name
89 else:
94 else:
90 image = FILE_STUB_IMAGE
95 image = FILE_STUB_IMAGE
91
96
92 w, h = get_static_dimensions(image)
97 w, h = get_static_dimensions(image)
93
98
94 return '<a href="{}">'\
99 return '<a href="{}">'\
95 '<img class="url-image" src="{}" width="{}" height="{}"/>'\
100 '<img class="url-image" src="{}" width="{}" height="{}"/>'\
96 '</a>'.format(self.file.url, static(image), w, h)
101 '</a>'.format(self.file.url, static(image), w, h)
97
102
103 def get_context_menu(self):
104 items = []
105 items.append({
106 'name': 'duplicates',
107 'label': _('Duplicates search'),
108 'url': reverse('feed') + '?image_hash=' + self.hash,
109 })
110
111 return items
112
113 def _build_context_menu(self, items):
114 if not items:
115 return ''
116
117 cm_items = []
118 for item in items:
119 cm_items.append(('{}: {{name: "{}", callback: function(key, opt) {{window.location="{}";}}}}')\
120 .format(item['name'], item['label'], item['url']))
121 return '<script>$.contextMenu({{trigger: "left", selector: "#file{} .file-menu", items: {{ {} }} }});</script>'.format(self.hash, ', '.join(cm_items))
122
98
123
99 class VideoViewer(AbstractViewer):
124 class VideoViewer(AbstractViewer):
100 @staticmethod
125 @staticmethod
101 def supports(file_type):
126 def supports(file_type):
102 return file_type in FILE_TYPES_VIDEO
127 return file_type in FILE_TYPES_VIDEO
103
128
104 def get_format_view(self):
129 def get_format_view(self):
105 return '<video width="200" height="150" controls src="{}"></video>'\
130 return '<video width="200" height="150" controls src="{}"></video>'\
106 .format(self.file.url)
131 .format(self.file.url)
107
132
108
133
109 class AudioViewer(AbstractViewer):
134 class AudioViewer(AbstractViewer):
110 @staticmethod
135 @staticmethod
111 def supports(file_type):
136 def supports(file_type):
112 return file_type in FILE_TYPES_AUDIO
137 return file_type in FILE_TYPES_AUDIO
113
138
114 def get_format_view(self):
139 def get_format_view(self):
115 return '<audio controls src="{}"></audio>'.format(self.file.url)
140 return '<audio controls src="{}"></audio>'.format(self.file.url)
116
141
117
142
118 class SvgViewer(AbstractViewer):
143 class SvgViewer(AbstractViewer):
119 @staticmethod
144 @staticmethod
120 def supports(file_type):
145 def supports(file_type):
121 return file_type == FILE_TYPE_SVG
146 return file_type == FILE_TYPE_SVG
122
147
123 def get_format_view(self):
148 def get_format_view(self):
124 return '<a class="thumb" href="{}">'\
149 return '<a class="thumb" href="{}">'\
125 '<img class="post-image-preview" width="200" height="150" src="{}" />'\
150 '<img class="post-image-preview" width="200" height="150" src="{}" />'\
126 '</a>'.format(self.file.url, self.file.url)
151 '</a>'.format(self.file.url, self.file.url)
127
152
128
153
129 class ImageViewer(AbstractViewer):
154 class ImageViewer(AbstractViewer):
130 @staticmethod
155 @staticmethod
131 def supports(file_type):
156 def supports(file_type):
132 return file_type in FILE_TYPES_IMAGE
157 return file_type in FILE_TYPES_IMAGE
133
158
134 def get_format_view(self):
159 def get_format_view(self):
135 metadata = '{}, {}'.format(self.file.name.split('.')[-1],
160 metadata = '{}, {}'.format(self.file.name.split('.')[-1],
136 filesizeformat(self.file.size))
161 filesizeformat(self.file.size))
137 width, height = get_image_dimensions(self.file.file)
162 width, height = get_image_dimensions(self.file.file)
138 preview_path = self.file.path.replace('.', '.200x150.')
163 preview_path = self.file.path.replace('.', '.200x150.')
139 pre_width, pre_height = get_image_dimensions(preview_path)
164 pre_width, pre_height = get_image_dimensions(preview_path)
140
165
141 split = self.file.url.rsplit('.', 1)
166 split = self.file.url.rsplit('.', 1)
142 w, h = 200, 150
167 w, h = 200, 150
143 thumb_url = '%s.%sx%s.%s' % (split[0], w, h, split[1])
168 thumb_url = '%s.%sx%s.%s' % (split[0], w, h, split[1])
144
169
145 return '<a class="{}" href="{full}">' \
170 return '<a class="{}" href="{full}">' \
146 '<img class="post-image-preview"' \
171 '<img class="post-image-preview"' \
147 ' src="{}"' \
172 ' src="{}"' \
148 ' alt="{}"' \
173 ' alt="{}"' \
149 ' width="{}"' \
174 ' width="{}"' \
150 ' height="{}"' \
175 ' height="{}"' \
151 ' data-width="{}"' \
176 ' data-width="{}"' \
152 ' data-height="{}" />' \
177 ' data-height="{}" />' \
153 '</a>' \
178 '</a>' \
154 .format(CSS_CLASS_THUMB,
179 .format(CSS_CLASS_THUMB,
155 thumb_url,
180 thumb_url,
156 self.hash,
181 self.hash,
157 str(pre_width),
182 str(pre_width),
158 str(pre_height), str(width), str(height),
183 str(pre_height), str(width), str(height),
159 full=self.file.url, image_meta=metadata)
184 full=self.file.url, image_meta=metadata)
160
185
186 def get_context_menu(self):
187 items = super().get_context_menu()
188
189 image_url = settings.get('External', 'ImageSearchHost') + self.file.url
190
191 items.append({
192 'name': 'google',
193 'label': 'Google',
194 'url': 'https://www.google.com/searchbyimage?image_url={}'.format(image_url),
195 })
196 items.append({
197 'name': 'iqdb',
198 'label': 'iqdb',
199 'url': 'http://iqdb.org/?url={}'.format(image_url)
200 })
201
202 return items
203
161
204
162 class UrlViewer(AbstractViewer):
205 class UrlViewer(AbstractViewer):
163 @staticmethod
206 @staticmethod
164 def supports(file_type):
207 def supports(file_type):
165 return file_type is None
208 return file_type is None
166
209
167 def get_view(self):
210 def get_view(self):
168 return '<div class="image">' \
211 return '<div class="image">' \
169 '{}' \
212 '{}' \
170 '<div class="image-metadata">{}</div>' \
213 '<div class="image-metadata">{}</div>' \
171 '</div>'.format(self.get_format_view(), get_domain(self.url))
214 '</div>'.format(self.get_format_view(), get_domain(self.url))
172
215
173 def get_format_view(self):
216 def get_format_view(self):
174 protocol = self.url.split(':')[0]
217 protocol = self.url.split(':')[0]
175
218
176 domain = get_domain(self.url)
219 domain = get_domain(self.url)
177
220
178 if protocol in URL_PROTOCOLS:
221 if protocol in URL_PROTOCOLS:
179 url_image_name = URL_PROTOCOLS.get(protocol)
222 url_image_name = URL_PROTOCOLS.get(protocol)
180 elif domain:
223 elif domain:
181 url_image_name = self._find_image_for_domains(domain) or FILE_STUB_URL
224 url_image_name = self._find_image_for_domains(domain) or FILE_STUB_URL
182 else:
225 else:
183 url_image_name = FILE_STUB_URL
226 url_image_name = FILE_STUB_URL
184
227
185 image_path = 'images/{}.png'.format(url_image_name)
228 image_path = 'images/{}.png'.format(url_image_name)
186 image = static(image_path)
229 image = static(image_path)
187 w, h = get_static_dimensions(image_path)
230 w, h = get_static_dimensions(image_path)
188
231
189 return '<a href="{}">' \
232 return '<a href="{}">' \
190 '<img class="url-image" src="{}" width="{}" height="{}"/>' \
233 '<img class="url-image" src="{}" width="{}" height="{}"/>' \
191 '</a>'.format(self.url, image, w, h)
234 '</a>'.format(self.url, image, w, h)
192
235
236 def get_context_menu(self):
237 return []
238
193 @cached_result()
239 @cached_result()
194 def _find_image_for_domains(self, domain):
240 def _find_image_for_domains(self, domain):
195 """
241 """
196 Searches for the domain image for every domain level except top.
242 Searches for the domain image for every domain level except top.
197 E.g. for l3.example.co.uk it will search for l3.example.co.uk, then
243 E.g. for l3.example.co.uk it will search for l3.example.co.uk, then
198 example.co.uk, then co.uk
244 example.co.uk, then co.uk
199 """
245 """
200 levels = domain.split('.')
246 levels = domain.split('.')
201 while len(levels) > 1:
247 while len(levels) > 1:
202 domain = '.'.join(levels)
248 domain = '.'.join(levels)
203
249
204 filename = 'images/domains/{}.png'.format(domain)
250 filename = 'images/domains/{}.png'.format(domain)
205 if file_exists(filename):
251 if file_exists(filename):
206 return 'domains/' + domain
252 return 'domains/' + domain
207 else:
253 else:
208 del levels[0]
254 del levels[0]
209
255
@@ -1,40 +1,38 b''
1 {% extends "boards/thread.html" %}
1 {% extends "boards/thread.html" %}
2
2
3 {% load i18n %}
3 {% load i18n %}
4 {% load static from staticfiles %}
4 {% load static from staticfiles %}
5 {% load board %}
5 {% load board %}
6 {% load tz %}
6 {% load tz %}
7
7
8 {% block head %}
8 {% block head %}
9 <meta name="robots" content="noindex">
9 <meta name="robots" content="noindex">
10 <title>{{ thread.get_opening_post.get_title|striptags|truncatewords:10 }}
10 <title>{{ thread.get_opening_post.get_title|striptags|truncatewords:10 }}
11 - {{ site_name }}</title>
11 - {{ site_name }}</title>
12 {% endblock %}
12 {% endblock %}
13
13
14 {% block thread_content %}
14 {% block thread_content %}
15 {% get_current_language as LANGUAGE_CODE %}
15 {% get_current_language as LANGUAGE_CODE %}
16 {% get_current_timezone as TIME_ZONE %}
16 {% get_current_timezone as TIME_ZONE %}
17
17
18 <div id="posts-table">
18 <div id="posts-table">
19 {% if posts %}
19 {% if posts %}
20 {% for post in posts %}
20 {% for post in posts %}
21 {% for image in post.get_images %}
21 {% for image in post.get_images %}
22 <div class="gallery_image">
22 <div class="gallery_image">
23 {% autoescape off %}
23 {% autoescape off %}
24 {{ image.get_view }}
24 {{ image.get_view }}
25 <div class="gallery_image_metadata">
25 <div class="gallery_image_metadata">
26 {{ image.get_size.0 }}x{{ image.get_size.1 }}
26 {{ image.get_size.0 }}x{{ image.get_size.1 }}
27 {% image_actions image.file.url %},
28 [<a href="{% url 'feed' %}?image_hash={{ image.hash }}">{{ site_name }}</a>]
29 <br />
27 <br />
30 <a href="{{ post.get_absolute_url }}">>>{{ post.id }}</a>
28 <a href="{{ post.get_absolute_url }}">>>{{ post.id }}</a>
31 </div>
29 </div>
32 {% endautoescape %}
30 {% endautoescape %}
33 </div>
31 </div>
34 {% endfor %}
32 {% endfor %}
35 {% endfor %}
33 {% endfor %}
36 {% else %}
34 {% else %}
37 {% trans 'No images.' %}
35 {% trans 'No images.' %}
38 {% endif %}
36 {% endif %}
39 </div>
37 </div>
40 {% endblock %}
38 {% endblock %}
@@ -1,123 +1,100 b''
1 import re
1 import re
2
2
3 from django.shortcuts import get_object_or_404
3 from django.shortcuts import get_object_or_404
4 from django import template
4 from django import template
5 from django.utils.text import re_tag
5 from django.utils.text import re_tag
6 from django.core.urlresolvers import reverse
6 from django.core.urlresolvers import reverse
7
7
8 from boards.mdx_neboard import LINE_BREAK_HTML
8 from boards.mdx_neboard import LINE_BREAK_HTML
9 from boards import settings
9 from boards import settings
10
10
11
11
12 IMG_ACTION_URL = '[<a href="{}">{}</a>]'
12 IMG_ACTION_URL = '[<a href="{}">{}</a>]'
13 REGEX_NEWLINE = re.compile(LINE_BREAK_HTML)
13 REGEX_NEWLINE = re.compile(LINE_BREAK_HTML)
14 TRUNCATOR = '...'
14 TRUNCATOR = '...'
15 HTML4_SINGLETS =(
15 HTML4_SINGLETS =(
16 'br', 'col', 'link', 'base', 'img', 'param', 'area', 'hr', 'input'
16 'br', 'col', 'link', 'base', 'img', 'param', 'area', 'hr', 'input'
17 )
17 )
18
18
19
19
20 register = template.Library()
20 register = template.Library()
21
21
22 actions = [
23 {
24 'name': 'google',
25 'link': 'https://www.google.com/searchbyimage?image_url={}',
26 },
27 {
28 'name': 'iqdb',
29 'link': 'http://iqdb.org/?url={}',
30 },
31 ]
32
33
22
34 @register.simple_tag(name='post_url')
23 @register.simple_tag(name='post_url')
35 def post_url(*args, **kwargs):
24 def post_url(*args, **kwargs):
36 post_id = args[0]
25 post_id = args[0]
37
26
38 post = get_object_or_404('Post', id=post_id)
27 post = get_object_or_404('Post', id=post_id)
39
28
40 return post.get_absolute_url()
29 return post.get_absolute_url()
41
30
42
31
43 @register.simple_tag(name='image_actions')
44 def image_actions(*args, **kwargs):
45 image_link = args[0]
46 host = settings.get('External', 'ImageSearchHost')
47 if host.endswith('/'):
48 host = host[:-1]
49 image_link = settings.get('External', 'ImageSearchHost') + image_link
50
51 return ', '.join([IMG_ACTION_URL.format(
52 action['link'].format(image_link), action['name']) for action in actions])
53
54
55 @register.inclusion_tag('boards/post.html', name='post_view', takes_context=True)
32 @register.inclusion_tag('boards/post.html', name='post_view', takes_context=True)
56 def post_view(context, post, *args, **kwargs):
33 def post_view(context, post, *args, **kwargs):
57 kwargs['perms'] = context['perms']
34 kwargs['perms'] = context['perms']
58 return post.get_view_params(*args, **kwargs)
35 return post.get_view_params(*args, **kwargs)
59
36
60
37
61 @register.simple_tag(name='page_url')
38 @register.simple_tag(name='page_url')
62 def page_url(paginator, page_number, *args, **kwargs):
39 def page_url(paginator, page_number, *args, **kwargs):
63 if paginator.supports_urls():
40 if paginator.supports_urls():
64 return paginator.get_page_url(page_number)
41 return paginator.get_page_url(page_number)
65
42
66
43
67 @register.filter(name='truncatenewlines_html')
44 @register.filter(name='truncatenewlines_html')
68 def truncatenewlines_html(value, arg):
45 def truncatenewlines_html(value, arg):
69 end_pos = 0
46 end_pos = 0
70 start_pos = 0
47 start_pos = 0
71 match_count = 0
48 match_count = 0
72
49
73 # Collect places for truncation
50 # Collect places for truncation
74 while match_count <= arg:
51 while match_count <= arg:
75 m = REGEX_NEWLINE.search(value, end_pos)
52 m = REGEX_NEWLINE.search(value, end_pos)
76 if m is None:
53 if m is None:
77 break
54 break
78 else:
55 else:
79 match_count += 1
56 match_count += 1
80 end_pos = m.end()
57 end_pos = m.end()
81 start_pos = m.start()
58 start_pos = m.start()
82
59
83 # Find and close open tags
60 # Find and close open tags
84 if match_count > arg:
61 if match_count > arg:
85 truncate_pos = start_pos
62 truncate_pos = start_pos
86
63
87 open_tags = []
64 open_tags = []
88 text = value[:truncate_pos]
65 text = value[:truncate_pos]
89 current_pos = 0
66 current_pos = 0
90 while True:
67 while True:
91 tag = re_tag.search(text, current_pos)
68 tag = re_tag.search(text, current_pos)
92 if tag is None:
69 if tag is None:
93 break
70 break
94 else:
71 else:
95 closing_tag, tagname, self_closing = tag.groups()
72 closing_tag, tagname, self_closing = tag.groups()
96 tagname = tagname.lower()
73 tagname = tagname.lower()
97 if self_closing or tagname in HTML4_SINGLETS:
74 if self_closing or tagname in HTML4_SINGLETS:
98 pass
75 pass
99 elif closing_tag:
76 elif closing_tag:
100 # Check for match in open tags list
77 # Check for match in open tags list
101 try:
78 try:
102 i = open_tags.index(tagname)
79 i = open_tags.index(tagname)
103 except ValueError:
80 except ValueError:
104 pass
81 pass
105 else:
82 else:
106 # SGML: An end tag closes, back to the matching start tag,
83 # SGML: An end tag closes, back to the matching start tag,
107 # all unclosed intervening start tags with omitted end tags
84 # all unclosed intervening start tags with omitted end tags
108 open_tags = open_tags[i + 1:]
85 open_tags = open_tags[i + 1:]
109 else:
86 else:
110 # Add it to the start of the open tags list
87 # Add it to the start of the open tags list
111 open_tags.insert(0, tagname)
88 open_tags.insert(0, tagname)
112
89
113 current_pos = tag.end()
90 current_pos = tag.end()
114
91
115 if not text.endswith(TRUNCATOR):
92 if not text.endswith(TRUNCATOR):
116 text += TRUNCATOR
93 text += TRUNCATOR
117 for tag in open_tags:
94 for tag in open_tags:
118 text += '</{}>'.format(tag)
95 text += '</{}>'.format(tag)
119 else:
96 else:
120 text = value
97 text = value
121
98
122 return text
99 return text
123
100
General Comments 0
You need to be logged in to leave comments. Login now