##// END OF EJS Templates
Don't show list of all sections when none is entered
neko259 -
r1259:859d1228 default
parent child Browse files
Show More
@@ -1,387 +1,386 b''
1 import re
1 import re
2 import time
2 import time
3 import pytz
3 import pytz
4
4
5 from django import forms
5 from django import forms
6 from django.core.files.uploadedfile import SimpleUploadedFile
6 from django.core.files.uploadedfile import SimpleUploadedFile
7 from django.core.exceptions import ObjectDoesNotExist
7 from django.core.exceptions import ObjectDoesNotExist
8 from django.forms.util import ErrorList
8 from django.forms.util import ErrorList
9 from django.utils.translation import ugettext_lazy as _
9 from django.utils.translation import ugettext_lazy as _
10 import requests
10 import requests
11
11
12 from boards.mdx_neboard import formatters
12 from boards.mdx_neboard import formatters
13 from boards.models.post import TITLE_MAX_LENGTH
13 from boards.models.post import TITLE_MAX_LENGTH
14 from boards.models import Tag, Post
14 from boards.models import Tag, Post
15 from neboard import settings
15 from neboard import settings
16 import boards.settings as board_settings
16 import boards.settings as board_settings
17
17
18 HEADER_CONTENT_LENGTH = 'content-length'
18 HEADER_CONTENT_LENGTH = 'content-length'
19 HEADER_CONTENT_TYPE = 'content-type'
19 HEADER_CONTENT_TYPE = 'content-type'
20
20
21 CONTENT_TYPE_IMAGE = (
21 CONTENT_TYPE_IMAGE = (
22 'image/jpeg',
22 'image/jpeg',
23 'image/jpg',
23 'image/jpg',
24 'image/png',
24 'image/png',
25 'image/gif',
25 'image/gif',
26 'image/bmp',
26 'image/bmp',
27 )
27 )
28
28
29 REGEX_TAGS = re.compile(r'^[\w\s\d]+$', re.UNICODE)
29 REGEX_TAGS = re.compile(r'^[\w\s\d]+$', re.UNICODE)
30
30
31 VETERAN_POSTING_DELAY = 5
31 VETERAN_POSTING_DELAY = 5
32
32
33 ATTRIBUTE_PLACEHOLDER = 'placeholder'
33 ATTRIBUTE_PLACEHOLDER = 'placeholder'
34 ATTRIBUTE_ROWS = 'rows'
34 ATTRIBUTE_ROWS = 'rows'
35
35
36 LAST_POST_TIME = 'last_post_time'
36 LAST_POST_TIME = 'last_post_time'
37 LAST_LOGIN_TIME = 'last_login_time'
37 LAST_LOGIN_TIME = 'last_login_time'
38 TEXT_PLACEHOLDER = _('Type message here. Use formatting panel for more advanced usage.')
38 TEXT_PLACEHOLDER = _('Type message here. Use formatting panel for more advanced usage.')
39 TAGS_PLACEHOLDER = _('music images i_dont_like_tags')
39 TAGS_PLACEHOLDER = _('music images i_dont_like_tags')
40
40
41 LABEL_TITLE = _('Title')
41 LABEL_TITLE = _('Title')
42 LABEL_TEXT = _('Text')
42 LABEL_TEXT = _('Text')
43 LABEL_TAG = _('Tag')
43 LABEL_TAG = _('Tag')
44 LABEL_SEARCH = _('Search')
44 LABEL_SEARCH = _('Search')
45
45
46 ERROR_SPEED = _('Please wait %s seconds before sending message')
46 ERROR_SPEED = _('Please wait %s seconds before sending message')
47
47
48 TAG_MAX_LENGTH = 20
48 TAG_MAX_LENGTH = 20
49
49
50 IMAGE_DOWNLOAD_CHUNK_BYTES = 100000
50 IMAGE_DOWNLOAD_CHUNK_BYTES = 100000
51
51
52 HTTP_RESULT_OK = 200
52 HTTP_RESULT_OK = 200
53
53
54 TEXTAREA_ROWS = 4
54 TEXTAREA_ROWS = 4
55
55
56
56
57 def get_timezones():
57 def get_timezones():
58 timezones = []
58 timezones = []
59 for tz in pytz.common_timezones:
59 for tz in pytz.common_timezones:
60 timezones.append((tz, tz),)
60 timezones.append((tz, tz),)
61 return timezones
61 return timezones
62
62
63
63
64 class FormatPanel(forms.Textarea):
64 class FormatPanel(forms.Textarea):
65 """
65 """
66 Panel for text formatting. Consists of buttons to add different tags to the
66 Panel for text formatting. Consists of buttons to add different tags to the
67 form text area.
67 form text area.
68 """
68 """
69
69
70 def render(self, name, value, attrs=None):
70 def render(self, name, value, attrs=None):
71 output = '<div id="mark-panel">'
71 output = '<div id="mark-panel">'
72 for formatter in formatters:
72 for formatter in formatters:
73 output += '<span class="mark_btn"' + \
73 output += '<span class="mark_btn"' + \
74 ' onClick="addMarkToMsg(\'' + formatter.format_left + \
74 ' onClick="addMarkToMsg(\'' + formatter.format_left + \
75 '\', \'' + formatter.format_right + '\')">' + \
75 '\', \'' + formatter.format_right + '\')">' + \
76 formatter.preview_left + formatter.name + \
76 formatter.preview_left + formatter.name + \
77 formatter.preview_right + '</span>'
77 formatter.preview_right + '</span>'
78
78
79 output += '</div>'
79 output += '</div>'
80 output += super(FormatPanel, self).render(name, value, attrs=None)
80 output += super(FormatPanel, self).render(name, value, attrs=None)
81
81
82 return output
82 return output
83
83
84
84
85 class PlainErrorList(ErrorList):
85 class PlainErrorList(ErrorList):
86 def __unicode__(self):
86 def __unicode__(self):
87 return self.as_text()
87 return self.as_text()
88
88
89 def as_text(self):
89 def as_text(self):
90 return ''.join(['(!) %s ' % e for e in self])
90 return ''.join(['(!) %s ' % e for e in self])
91
91
92
92
93 class NeboardForm(forms.Form):
93 class NeboardForm(forms.Form):
94 """
94 """
95 Form with neboard-specific formatting.
95 Form with neboard-specific formatting.
96 """
96 """
97
97
98 def as_div(self):
98 def as_div(self):
99 """
99 """
100 Returns this form rendered as HTML <as_div>s.
100 Returns this form rendered as HTML <as_div>s.
101 """
101 """
102
102
103 return self._html_output(
103 return self._html_output(
104 # TODO Do not show hidden rows in the list here
104 # TODO Do not show hidden rows in the list here
105 normal_row='<div class="form-row">'
105 normal_row='<div class="form-row">'
106 '<div class="form-label">'
106 '<div class="form-label">'
107 '%(label)s'
107 '%(label)s'
108 '</div>'
108 '</div>'
109 '<div class="form-input">'
109 '<div class="form-input">'
110 '%(field)s'
110 '%(field)s'
111 '</div>'
111 '</div>'
112 '</div>'
112 '</div>'
113 '<div class="form-row">'
113 '<div class="form-row">'
114 '%(help_text)s'
114 '%(help_text)s'
115 '</div>',
115 '</div>',
116 error_row='<div class="form-row">'
116 error_row='<div class="form-row">'
117 '<div class="form-label"></div>'
117 '<div class="form-label"></div>'
118 '<div class="form-errors">%s</div>'
118 '<div class="form-errors">%s</div>'
119 '</div>',
119 '</div>',
120 row_ender='</div>',
120 row_ender='</div>',
121 help_text_html='%s',
121 help_text_html='%s',
122 errors_on_separate_row=True)
122 errors_on_separate_row=True)
123
123
124 def as_json_errors(self):
124 def as_json_errors(self):
125 errors = []
125 errors = []
126
126
127 for name, field in list(self.fields.items()):
127 for name, field in list(self.fields.items()):
128 if self[name].errors:
128 if self[name].errors:
129 errors.append({
129 errors.append({
130 'field': name,
130 'field': name,
131 'errors': self[name].errors.as_text(),
131 'errors': self[name].errors.as_text(),
132 })
132 })
133
133
134 return errors
134 return errors
135
135
136
136
137 class PostForm(NeboardForm):
137 class PostForm(NeboardForm):
138
138
139 title = forms.CharField(max_length=TITLE_MAX_LENGTH, required=False,
139 title = forms.CharField(max_length=TITLE_MAX_LENGTH, required=False,
140 label=LABEL_TITLE)
140 label=LABEL_TITLE)
141 text = forms.CharField(
141 text = forms.CharField(
142 widget=FormatPanel(attrs={
142 widget=FormatPanel(attrs={
143 ATTRIBUTE_PLACEHOLDER: TEXT_PLACEHOLDER,
143 ATTRIBUTE_PLACEHOLDER: TEXT_PLACEHOLDER,
144 ATTRIBUTE_ROWS: TEXTAREA_ROWS,
144 ATTRIBUTE_ROWS: TEXTAREA_ROWS,
145 }),
145 }),
146 required=False, label=LABEL_TEXT)
146 required=False, label=LABEL_TEXT)
147 image = forms.ImageField(required=False, label=_('Image'),
147 image = forms.ImageField(required=False, label=_('Image'),
148 widget=forms.ClearableFileInput(
148 widget=forms.ClearableFileInput(
149 attrs={'accept': 'image/*'}))
149 attrs={'accept': 'image/*'}))
150 image_url = forms.CharField(required=False, label=_('Image URL'),
150 image_url = forms.CharField(required=False, label=_('Image URL'),
151 widget=forms.TextInput(
151 widget=forms.TextInput(
152 attrs={ATTRIBUTE_PLACEHOLDER:
152 attrs={ATTRIBUTE_PLACEHOLDER:
153 'http://example.com/image.png'}))
153 'http://example.com/image.png'}))
154
154
155 # This field is for spam prevention only
155 # This field is for spam prevention only
156 email = forms.CharField(max_length=100, required=False, label=_('e-mail'),
156 email = forms.CharField(max_length=100, required=False, label=_('e-mail'),
157 widget=forms.TextInput(attrs={
157 widget=forms.TextInput(attrs={
158 'class': 'form-email'}))
158 'class': 'form-email'}))
159 threads = forms.CharField(required=False, label=_('Additional threads'),
159 threads = forms.CharField(required=False, label=_('Additional threads'),
160 widget=forms.TextInput(attrs={ATTRIBUTE_PLACEHOLDER:
160 widget=forms.TextInput(attrs={ATTRIBUTE_PLACEHOLDER:
161 '123 456 789'}))
161 '123 456 789'}))
162
162
163 session = None
163 session = None
164 need_to_ban = False
164 need_to_ban = False
165
165
166 def clean_title(self):
166 def clean_title(self):
167 title = self.cleaned_data['title']
167 title = self.cleaned_data['title']
168 if title:
168 if title:
169 if len(title) > TITLE_MAX_LENGTH:
169 if len(title) > TITLE_MAX_LENGTH:
170 raise forms.ValidationError(_('Title must have less than %s '
170 raise forms.ValidationError(_('Title must have less than %s '
171 'characters') %
171 'characters') %
172 str(TITLE_MAX_LENGTH))
172 str(TITLE_MAX_LENGTH))
173 return title
173 return title
174
174
175 def clean_text(self):
175 def clean_text(self):
176 text = self.cleaned_data['text'].strip()
176 text = self.cleaned_data['text'].strip()
177 if text:
177 if text:
178 max_length = board_settings.get_int('Forms', 'MaxTextLength')
178 max_length = board_settings.get_int('Forms', 'MaxTextLength')
179 if len(text) > max_length:
179 if len(text) > max_length:
180 raise forms.ValidationError(_('Text must have less than %s '
180 raise forms.ValidationError(_('Text must have less than %s '
181 'characters') % str(max_length))
181 'characters') % str(max_length))
182 return text
182 return text
183
183
184 def clean_image(self):
184 def clean_image(self):
185 image = self.cleaned_data['image']
185 image = self.cleaned_data['image']
186
186
187 if image:
187 if image:
188 self.validate_image_size(image.size)
188 self.validate_image_size(image.size)
189
189
190 return image
190 return image
191
191
192 def clean_image_url(self):
192 def clean_image_url(self):
193 url = self.cleaned_data['image_url']
193 url = self.cleaned_data['image_url']
194
194
195 image = None
195 image = None
196 if url:
196 if url:
197 image = self._get_image_from_url(url)
197 image = self._get_image_from_url(url)
198
198
199 if not image:
199 if not image:
200 raise forms.ValidationError(_('Invalid URL'))
200 raise forms.ValidationError(_('Invalid URL'))
201 else:
201 else:
202 self.validate_image_size(image.size)
202 self.validate_image_size(image.size)
203
203
204 return image
204 return image
205
205
206 def clean_threads(self):
206 def clean_threads(self):
207 threads_str = self.cleaned_data['threads']
207 threads_str = self.cleaned_data['threads']
208
208
209 if len(threads_str) > 0:
209 if len(threads_str) > 0:
210 threads_id_list = threads_str.split(' ')
210 threads_id_list = threads_str.split(' ')
211
211
212 threads = list()
212 threads = list()
213
213
214 for thread_id in threads_id_list:
214 for thread_id in threads_id_list:
215 try:
215 try:
216 thread = Post.objects.get(id=int(thread_id))
216 thread = Post.objects.get(id=int(thread_id))
217 if not thread.is_opening() or thread.get_thread().archived:
217 if not thread.is_opening() or thread.get_thread().archived:
218 raise ObjectDoesNotExist()
218 raise ObjectDoesNotExist()
219 threads.append(thread)
219 threads.append(thread)
220 except (ObjectDoesNotExist, ValueError):
220 except (ObjectDoesNotExist, ValueError):
221 raise forms.ValidationError(_('Invalid additional thread list'))
221 raise forms.ValidationError(_('Invalid additional thread list'))
222
222
223 return threads
223 return threads
224
224
225 def clean(self):
225 def clean(self):
226 cleaned_data = super(PostForm, self).clean()
226 cleaned_data = super(PostForm, self).clean()
227
227
228 if cleaned_data['email']:
228 if cleaned_data['email']:
229 self.need_to_ban = True
229 self.need_to_ban = True
230 raise forms.ValidationError('A human cannot enter a hidden field')
230 raise forms.ValidationError('A human cannot enter a hidden field')
231
231
232 if not self.errors:
232 if not self.errors:
233 self._clean_text_image()
233 self._clean_text_image()
234
234
235 if not self.errors and self.session:
235 if not self.errors and self.session:
236 self._validate_posting_speed()
236 self._validate_posting_speed()
237
237
238 return cleaned_data
238 return cleaned_data
239
239
240 def get_image(self):
240 def get_image(self):
241 """
241 """
242 Gets image from file or URL.
242 Gets image from file or URL.
243 """
243 """
244
244
245 image = self.cleaned_data['image']
245 image = self.cleaned_data['image']
246 return image if image else self.cleaned_data['image_url']
246 return image if image else self.cleaned_data['image_url']
247
247
248 def _clean_text_image(self):
248 def _clean_text_image(self):
249 text = self.cleaned_data.get('text')
249 text = self.cleaned_data.get('text')
250 image = self.get_image()
250 image = self.get_image()
251
251
252 if (not text) and (not image):
252 if (not text) and (not image):
253 error_message = _('Either text or image must be entered.')
253 error_message = _('Either text or image must be entered.')
254 self._errors['text'] = self.error_class([error_message])
254 self._errors['text'] = self.error_class([error_message])
255
255
256 def _validate_posting_speed(self):
256 def _validate_posting_speed(self):
257 can_post = True
257 can_post = True
258
258
259 posting_delay = settings.POSTING_DELAY
259 posting_delay = settings.POSTING_DELAY
260
260
261 if board_settings.get_bool('Forms', 'LimitPostingSpeed'):
261 if board_settings.get_bool('Forms', 'LimitPostingSpeed'):
262 now = time.time()
262 now = time.time()
263
263
264 current_delay = 0
264 current_delay = 0
265 need_delay = False
265 need_delay = False
266
266
267 if not LAST_POST_TIME in self.session:
267 if not LAST_POST_TIME in self.session:
268 self.session[LAST_POST_TIME] = now
268 self.session[LAST_POST_TIME] = now
269
269
270 need_delay = True
270 need_delay = True
271 else:
271 else:
272 last_post_time = self.session.get(LAST_POST_TIME)
272 last_post_time = self.session.get(LAST_POST_TIME)
273 current_delay = int(now - last_post_time)
273 current_delay = int(now - last_post_time)
274
274
275 need_delay = current_delay < posting_delay
275 need_delay = current_delay < posting_delay
276
276
277 if need_delay:
277 if need_delay:
278 error_message = ERROR_SPEED % str(posting_delay
278 error_message = ERROR_SPEED % str(posting_delay
279 - current_delay)
279 - current_delay)
280 self._errors['text'] = self.error_class([error_message])
280 self._errors['text'] = self.error_class([error_message])
281
281
282 can_post = False
282 can_post = False
283
283
284 if can_post:
284 if can_post:
285 self.session[LAST_POST_TIME] = now
285 self.session[LAST_POST_TIME] = now
286
286
287 def validate_image_size(self, size: int):
287 def validate_image_size(self, size: int):
288 max_size = board_settings.get_int('Forms', 'MaxImageSize')
288 max_size = board_settings.get_int('Forms', 'MaxImageSize')
289 if size > max_size:
289 if size > max_size:
290 raise forms.ValidationError(
290 raise forms.ValidationError(
291 _('Image must be less than %s bytes')
291 _('Image must be less than %s bytes')
292 % str(max_size))
292 % str(max_size))
293
293
294 def _get_image_from_url(self, url: str) -> SimpleUploadedFile:
294 def _get_image_from_url(self, url: str) -> SimpleUploadedFile:
295 """
295 """
296 Gets an image file from URL.
296 Gets an image file from URL.
297 """
297 """
298
298
299 img_temp = None
299 img_temp = None
300
300
301 try:
301 try:
302 # Verify content headers
302 # Verify content headers
303 response_head = requests.head(url, verify=False)
303 response_head = requests.head(url, verify=False)
304 content_type = response_head.headers[HEADER_CONTENT_TYPE].split(';')[0]
304 content_type = response_head.headers[HEADER_CONTENT_TYPE].split(';')[0]
305 if content_type in CONTENT_TYPE_IMAGE:
305 if content_type in CONTENT_TYPE_IMAGE:
306 length_header = response_head.headers.get(HEADER_CONTENT_LENGTH)
306 length_header = response_head.headers.get(HEADER_CONTENT_LENGTH)
307 if length_header:
307 if length_header:
308 length = int(length_header)
308 length = int(length_header)
309 self.validate_image_size(length)
309 self.validate_image_size(length)
310 # Get the actual content into memory
310 # Get the actual content into memory
311 response = requests.get(url, verify=False, stream=True)
311 response = requests.get(url, verify=False, stream=True)
312
312
313 # Download image, stop if the size exceeds limit
313 # Download image, stop if the size exceeds limit
314 size = 0
314 size = 0
315 content = b''
315 content = b''
316 for chunk in response.iter_content(IMAGE_DOWNLOAD_CHUNK_BYTES):
316 for chunk in response.iter_content(IMAGE_DOWNLOAD_CHUNK_BYTES):
317 size += len(chunk)
317 size += len(chunk)
318 self.validate_image_size(size)
318 self.validate_image_size(size)
319 content += chunk
319 content += chunk
320
320
321 if response.status_code == HTTP_RESULT_OK and content:
321 if response.status_code == HTTP_RESULT_OK and content:
322 # Set a dummy file name that will be replaced
322 # Set a dummy file name that will be replaced
323 # anyway, just keep the valid extension
323 # anyway, just keep the valid extension
324 filename = 'image.' + content_type.split('/')[1]
324 filename = 'image.' + content_type.split('/')[1]
325 img_temp = SimpleUploadedFile(filename, content,
325 img_temp = SimpleUploadedFile(filename, content,
326 content_type)
326 content_type)
327 except Exception:
327 except Exception:
328 # Just return no image
328 # Just return no image
329 pass
329 pass
330
330
331 return img_temp
331 return img_temp
332
332
333
333
334 class ThreadForm(PostForm):
334 class ThreadForm(PostForm):
335
335
336 tags = forms.CharField(
336 tags = forms.CharField(
337 widget=forms.TextInput(attrs={ATTRIBUTE_PLACEHOLDER: TAGS_PLACEHOLDER}),
337 widget=forms.TextInput(attrs={ATTRIBUTE_PLACEHOLDER: TAGS_PLACEHOLDER}),
338 max_length=100, label=_('Tags'), required=True)
338 max_length=100, label=_('Tags'), required=True)
339
339
340 def clean_tags(self):
340 def clean_tags(self):
341 tags = self.cleaned_data['tags'].strip()
341 tags = self.cleaned_data['tags'].strip()
342
342
343 if not tags or not REGEX_TAGS.match(tags):
343 if not tags or not REGEX_TAGS.match(tags):
344 raise forms.ValidationError(
344 raise forms.ValidationError(
345 _('Inappropriate characters in tags.'))
345 _('Inappropriate characters in tags.'))
346
346
347 required_tag_exists = False
347 required_tag_exists = False
348 for tag in tags.split():
348 for tag in tags.split():
349 try:
349 try:
350 Tag.objects.get(name=tag.strip().lower(), required=True)
350 Tag.objects.get(name=tag.strip().lower(), required=True)
351 required_tag_exists = True
351 required_tag_exists = True
352 break
352 break
353 except ObjectDoesNotExist:
353 except ObjectDoesNotExist:
354 pass
354 pass
355
355
356 if not required_tag_exists:
356 if not required_tag_exists:
357 all_tags = Tag.objects.filter(required=True)
357 all_tags = Tag.objects.filter(required=True)
358 raise forms.ValidationError(
358 raise forms.ValidationError(
359 _('Need at least one of the tags: ')
359 _('Need at least one section.'))
360 + ', '.join([tag.name for tag in all_tags]))
361
360
362 return tags
361 return tags
363
362
364 def clean(self):
363 def clean(self):
365 cleaned_data = super(ThreadForm, self).clean()
364 cleaned_data = super(ThreadForm, self).clean()
366
365
367 return cleaned_data
366 return cleaned_data
368
367
369
368
370 class SettingsForm(NeboardForm):
369 class SettingsForm(NeboardForm):
371
370
372 theme = forms.ChoiceField(choices=settings.THEMES, label=_('Theme'))
371 theme = forms.ChoiceField(choices=settings.THEMES, label=_('Theme'))
373 image_viewer = forms.ChoiceField(choices=settings.IMAGE_VIEWERS, label=_('Image view mode'))
372 image_viewer = forms.ChoiceField(choices=settings.IMAGE_VIEWERS, label=_('Image view mode'))
374 username = forms.CharField(label=_('User name'), required=False)
373 username = forms.CharField(label=_('User name'), required=False)
375 timezone = forms.ChoiceField(choices=get_timezones(), label=_('Time zone'))
374 timezone = forms.ChoiceField(choices=get_timezones(), label=_('Time zone'))
376
375
377 def clean_username(self):
376 def clean_username(self):
378 username = self.cleaned_data['username']
377 username = self.cleaned_data['username']
379
378
380 if username and not REGEX_TAGS.match(username):
379 if username and not REGEX_TAGS.match(username):
381 raise forms.ValidationError(_('Inappropriate characters.'))
380 raise forms.ValidationError(_('Inappropriate characters.'))
382
381
383 return username
382 return username
384
383
385
384
386 class SearchForm(NeboardForm):
385 class SearchForm(NeboardForm):
387 query = forms.CharField(max_length=500, label=LABEL_SEARCH, required=False)
386 query = forms.CharField(max_length=500, label=LABEL_SEARCH, required=False)
1 NO CONTENT: modified file, binary diff hidden
NO CONTENT: modified file, binary diff hidden
@@ -1,440 +1,438 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-08-03 18:26+0300\n"
10 "POT-Creation-Date: 2015-08-09 22:38+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:38
41 #: forms.py:38
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:39
46 #: forms.py:39
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:41
50 #: forms.py:41
51 msgid "Title"
51 msgid "Title"
52 msgstr "Заголовок"
52 msgstr "Заголовок"
53
53
54 #: forms.py:42
54 #: forms.py:42
55 msgid "Text"
55 msgid "Text"
56 msgstr "Текст"
56 msgstr "Текст"
57
57
58 #: forms.py:43
58 #: forms.py:43
59 msgid "Tag"
59 msgid "Tag"
60 msgstr "Метка"
60 msgstr "Метка"
61
61
62 #: forms.py:44 templates/boards/base.html:40 templates/search/search.html:7
62 #: forms.py:44 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:46
66 #: forms.py:46
67 #, python-format
67 #, python-format
68 msgid "Please wait %s seconds before sending message"
68 msgid "Please wait %s seconds before sending message"
69 msgstr "Пожалуйста подождите %s секунд перед отправкой сообщения"
69 msgstr "Пожалуйста подождите %s секунд перед отправкой сообщения"
70
70
71 #: forms.py:147
71 #: forms.py:147
72 msgid "Image"
72 msgid "Image"
73 msgstr "Изображение"
73 msgstr "Изображение"
74
74
75 #: forms.py:150
75 #: forms.py:150
76 msgid "Image URL"
76 msgid "Image URL"
77 msgstr "URL изображения"
77 msgstr "URL изображения"
78
78
79 #: forms.py:156
79 #: forms.py:156
80 msgid "e-mail"
80 msgid "e-mail"
81 msgstr ""
81 msgstr ""
82
82
83 #: forms.py:159
83 #: forms.py:159
84 msgid "Additional threads"
84 msgid "Additional threads"
85 msgstr "Дополнительные темы"
85 msgstr "Дополнительные темы"
86
86
87 #: forms.py:170
87 #: forms.py:170
88 #, python-format
88 #, python-format
89 msgid "Title must have less than %s characters"
89 msgid "Title must have less than %s characters"
90 msgstr "Заголовок должен иметь меньше %s символов"
90 msgstr "Заголовок должен иметь меньше %s символов"
91
91
92 #: forms.py:180
92 #: forms.py:180
93 #, python-format
93 #, python-format
94 msgid "Text must have less than %s characters"
94 msgid "Text must have less than %s characters"
95 msgstr "Текст должен быть короче %s символов"
95 msgstr "Текст должен быть короче %s символов"
96
96
97 #: forms.py:200
97 #: forms.py:200
98 msgid "Invalid URL"
98 msgid "Invalid URL"
99 msgstr "Неверный URL"
99 msgstr "Неверный URL"
100
100
101 #: forms.py:221
101 #: forms.py:221
102 msgid "Invalid additional thread list"
102 msgid "Invalid additional thread list"
103 msgstr "Неверный список дополнительных тем"
103 msgstr "Неверный список дополнительных тем"
104
104
105 #: forms.py:253
105 #: forms.py:253
106 msgid "Either text or image must be entered."
106 msgid "Either text or image must be entered."
107 msgstr "Текст или картинка должны быть введены."
107 msgstr "Текст или картинка должны быть введены."
108
108
109 #: forms.py:291
109 #: forms.py:291
110 #, python-format
110 #, python-format
111 msgid "Image must be less than %s bytes"
111 msgid "Image must be less than %s bytes"
112 msgstr "Изображение должно быть менее %s байт"
112 msgstr "Изображение должно быть менее %s байт"
113
113
114 #: forms.py:338 templates/boards/all_threads.html:136
114 #: forms.py:338 templates/boards/all_threads.html:141
115 #: templates/boards/rss/post.html:10 templates/boards/tags.html:6
115 #: templates/boards/rss/post.html:10 templates/boards/tags.html:6
116 msgid "Tags"
116 msgid "Tags"
117 msgstr "Метки"
117 msgstr "Метки"
118
118
119 #: forms.py:345
119 #: forms.py:345
120 msgid "Inappropriate characters in tags."
120 msgid "Inappropriate characters in tags."
121 msgstr "Недопустимые символы в метках."
121 msgstr "Недопустимые символы в метках."
122
122
123 #: forms.py:359
123 #: forms.py:359
124 msgid "Need at least one of the tags: "
124 #| msgid "Need at least one of the tags: "
125 msgstr "Нужна хотя бы одна из меток: "
125 msgid "Need at least one section."
126 msgstr "Нужен хотя бы один раздел."
126
127
127 #: forms.py:372
128 #: forms.py:371
128 msgid "Theme"
129 msgid "Theme"
129 msgstr "Тема"
130 msgstr "Тема"
130
131
131 #: forms.py:373
132 #: forms.py:372
132 msgid "Image view mode"
133 msgid "Image view mode"
133 msgstr "Режим просмотра изображений"
134 msgstr "Режим просмотра изображений"
134
135
135 #: forms.py:374
136 #: forms.py:373
136 msgid "User name"
137 msgid "User name"
137 msgstr "Имя пользователя"
138 msgstr "Имя пользователя"
138
139
139 #: forms.py:375
140 #: forms.py:374
140 msgid "Time zone"
141 msgid "Time zone"
141 msgstr "Часовой пояс"
142 msgstr "Часовой пояс"
142
143
143 #: forms.py:381
144 #: forms.py:380
144 msgid "Inappropriate characters."
145 msgid "Inappropriate characters."
145 msgstr "Недопустимые символы."
146 msgstr "Недопустимые символы."
146
147
147 #: templates/boards/404.html:6
148 #: templates/boards/404.html:6
148 msgid "Not found"
149 msgid "Not found"
149 msgstr "Не найдено"
150 msgstr "Не найдено"
150
151
151 #: templates/boards/404.html:12
152 #: templates/boards/404.html:12
152 msgid "This page does not exist"
153 msgid "This page does not exist"
153 msgstr "Этой страницы не существует"
154 msgstr "Этой страницы не существует"
154
155
155 #: templates/boards/all_threads.html:35
156 #: templates/boards/all_threads.html:35
156 msgid "Related message"
157 msgid "Related message"
157 msgstr "Связанное сообщение"
158 msgstr "Связанное сообщение"
158
159
159 #: templates/boards/all_threads.html:68
160 #: templates/boards/all_threads.html:68
160 msgid "Edit tag"
161 msgid "Edit tag"
161 msgstr "Изменить метку"
162 msgstr "Изменить метку"
162
163
163 #: templates/boards/all_threads.html:71
164 #: templates/boards/all_threads.html:76
164 #, python-format
165 #, python-format
165 msgid "This tag has %(thread_count)s threads and %(post_count)s posts."
166 msgid "This tag has %(thread_count)s threads and %(post_count)s posts."
166 msgstr "С этой меткой есть %(thread_count)s тем и %(post_count)s сообщений."
167 msgstr "С этой меткой есть %(thread_count)s тем и %(post_count)s сообщений."
167
168
168 #: templates/boards/all_threads.html:78 templates/boards/feed.html:30
169 #: templates/boards/all_threads.html:83 templates/boards/feed.html:30
169 #: templates/boards/notifications.html:17 templates/search/search.html:26
170 #: templates/boards/notifications.html:17 templates/search/search.html:26
170 msgid "Previous page"
171 msgid "Previous page"
171 msgstr "Предыдущая страница"
172 msgstr "Предыдущая страница"
172
173
173 #: templates/boards/all_threads.html:92
174 #: templates/boards/all_threads.html:97
174 #, python-format
175 #, python-format
175 msgid "Skipped %(count)s replies. Open thread to see all replies."
176 msgid "Skipped %(count)s replies. Open thread to see all replies."
176 msgstr "Пропущено %(count)s ответов. Откройте тред, чтобы увидеть все ответы."
177 msgstr "Пропущено %(count)s ответов. Откройте тред, чтобы увидеть все ответы."
177
178
178 #: templates/boards/all_threads.html:110 templates/boards/feed.html:40
179 #: templates/boards/all_threads.html:115 templates/boards/feed.html:40
179 #: templates/boards/notifications.html:27 templates/search/search.html:37
180 #: templates/boards/notifications.html:27 templates/search/search.html:37
180 msgid "Next page"
181 msgid "Next page"
181 msgstr "Следующая страница"
182 msgstr "Следующая страница"
182
183
183 #: templates/boards/all_threads.html:115
184 #: templates/boards/all_threads.html:120
184 msgid "No threads exist. Create the first one!"
185 msgid "No threads exist. Create the first one!"
185 msgstr "Нет тем. Создайте первую!"
186 msgstr "Нет тем. Создайте первую!"
186
187
187 #: templates/boards/all_threads.html:121
188 #: templates/boards/all_threads.html:126
188 msgid "Create new thread"
189 msgid "Create new thread"
189 msgstr "Создать новую тему"
190 msgstr "Создать новую тему"
190
191
191 #: templates/boards/all_threads.html:126 templates/boards/preview.html:16
192 #: templates/boards/all_threads.html:131 templates/boards/preview.html:16
192 #: templates/boards/thread_normal.html:38
193 #: templates/boards/thread_normal.html:38
193 msgid "Post"
194 msgid "Post"
194 msgstr "Отправить"
195 msgstr "Отправить"
195
196
196 #: templates/boards/all_threads.html:131
197 #: templates/boards/all_threads.html:136
197 msgid "Tags must be delimited by spaces. Text or image is required."
198 msgid "Tags must be delimited by spaces. Text or image is required."
198 msgstr ""
199 msgstr ""
199 "Метки должны быть разделены пробелами. Текст или изображение обязательны."
200 "Метки должны быть разделены пробелами. Текст или изображение обязательны."
200
201
201 #: templates/boards/all_threads.html:133 templates/boards/preview.html:6
202 #: templates/boards/all_threads.html:138 templates/boards/preview.html:6
202 #: templates/boards/staticpages/help.html:21
203 #: templates/boards/staticpages/help.html:21
203 #: templates/boards/thread_normal.html:42
204 #: templates/boards/thread_normal.html:42
204 msgid "Preview"
205 msgid "Preview"
205 msgstr "Предпросмотр"
206 msgstr "Предпросмотр"
206
207
207 #: templates/boards/all_threads.html:135 templates/boards/thread_normal.html:45
208 #: templates/boards/all_threads.html:140 templates/boards/thread_normal.html:45
208 msgid "Text syntax"
209 msgid "Text syntax"
209 msgstr "Синтаксис текста"
210 msgstr "Синтаксис текста"
210
211
211 #: templates/boards/all_threads.html:149 templates/boards/feed.html:53
212 #: templates/boards/all_threads.html:154 templates/boards/feed.html:53
212 msgid "Pages:"
213 msgid "Pages:"
213 msgstr "Страницы: "
214 msgstr "Страницы: "
214
215
215 #: templates/boards/authors.html:6 templates/boards/authors.html.py:12
216 #: templates/boards/authors.html:6 templates/boards/authors.html.py:12
216 msgid "Authors"
217 msgid "Authors"
217 msgstr "Авторы"
218 msgstr "Авторы"
218
219
219 #: templates/boards/authors.html:26
220 #: templates/boards/authors.html:26
220 msgid "Distributed under the"
221 msgid "Distributed under the"
221 msgstr "Распространяется под"
222 msgstr "Распространяется под"
222
223
223 #: templates/boards/authors.html:28
224 #: templates/boards/authors.html:28
224 msgid "license"
225 msgid "license"
225 msgstr "лицензией"
226 msgstr "лицензией"
226
227
227 #: templates/boards/authors.html:30
228 #: templates/boards/authors.html:30
228 msgid "Repository"
229 msgid "Repository"
229 msgstr "Репозиторий"
230 msgstr "Репозиторий"
230
231
231 #: templates/boards/base.html:14 templates/boards/base.html.py:41
232 #: templates/boards/base.html:14 templates/boards/base.html.py:41
232 msgid "Feed"
233 msgid "Feed"
233 msgstr "Лента"
234 msgstr "Лента"
234
235
235 #: templates/boards/base.html:31
236 #: templates/boards/base.html:31
236 msgid "All threads"
237 msgid "All threads"
237 msgstr "Все темы"
238 msgstr "Все темы"
238
239
239 #: templates/boards/base.html:37
240 #: templates/boards/base.html:37
240 msgid "Add tags"
241 msgid "Add tags"
241 msgstr "Добавить метки"
242 msgstr "Добавить метки"
242
243
243 #: templates/boards/base.html:39
244 #: templates/boards/base.html:39
244 msgid "Tag management"
245 msgid "Tag management"
245 msgstr "Управление метками"
246 msgstr "Управление метками"
246
247
247 #: templates/boards/base.html:39
248 #: templates/boards/base.html:39
248 msgid "tags"
249 msgid "tags"
249 msgstr "метки"
250 msgstr "метки"
250
251
251 #: templates/boards/base.html:40
252 #: templates/boards/base.html:40
252 msgid "search"
253 msgid "search"
253 msgstr "поиск"
254 msgstr "поиск"
254
255
255 #: templates/boards/base.html:41 templates/boards/feed.html:11
256 #: templates/boards/base.html:41 templates/boards/feed.html:11
256 msgid "feed"
257 msgid "feed"
257 msgstr "лента"
258 msgstr "лента"
258
259
259 #: templates/boards/base.html:42 templates/boards/random.html:6
260 #: templates/boards/base.html:42 templates/boards/random.html:6
260 msgid "Random images"
261 msgid "Random images"
261 msgstr "Случайные изображения"
262 msgstr "Случайные изображения"
262
263
263 #: templates/boards/base.html:42
264 #: templates/boards/base.html:42
264 msgid "random"
265 msgid "random"
265 msgstr "случайные"
266 msgstr "случайные"
266
267
267 #: templates/boards/base.html:45 templates/boards/base.html.py:46
268 #: templates/boards/base.html:45 templates/boards/base.html.py:46
268 #: templates/boards/notifications.html:8
269 #: templates/boards/notifications.html:8
269 msgid "Notifications"
270 msgid "Notifications"
270 msgstr "Уведомления"
271 msgstr "Уведомления"
271
272
272 #: templates/boards/base.html:53 templates/boards/settings.html:8
273 #: templates/boards/base.html:53 templates/boards/settings.html:8
273 msgid "Settings"
274 msgid "Settings"
274 msgstr "Настройки"
275 msgstr "Настройки"
275
276
276 #: templates/boards/base.html:66
277 #: templates/boards/base.html:66
277 msgid "Admin"
278 msgid "Admin"
278 msgstr "Администрирование"
279 msgstr "Администрирование"
279
280
280 #: templates/boards/base.html:68
281 #: templates/boards/base.html:68
281 #, python-format
282 #, python-format
282 msgid "Speed: %(ppd)s posts per day"
283 msgid "Speed: %(ppd)s posts per day"
283 msgstr "Скорость: %(ppd)s сообщений в день"
284 msgstr "Скорость: %(ppd)s сообщений в день"
284
285
285 #: templates/boards/base.html:70
286 #: templates/boards/base.html:70
286 msgid "Up"
287 msgid "Up"
287 msgstr "Вверх"
288 msgstr "Вверх"
288
289
289 #: templates/boards/feed.html:45
290 #: templates/boards/feed.html:45
290 msgid "No posts exist. Create the first one!"
291 msgid "No posts exist. Create the first one!"
291 msgstr "Нет сообщений. Создайте первое!"
292 msgstr "Нет сообщений. Создайте первое!"
292
293
293 #: templates/boards/post.html:25
294 #: templates/boards/post.html:25
294 msgid "Open"
295 msgid "Open"
295 msgstr "Открыть"
296 msgstr "Открыть"
296
297
297 #: templates/boards/post.html:27 templates/boards/post.html.py:38
298 #: templates/boards/post.html:27 templates/boards/post.html.py:38
298 msgid "Reply"
299 msgid "Reply"
299 msgstr "Ответить"
300 msgstr "Ответить"
300
301
301 #: templates/boards/post.html:33
302 #: templates/boards/post.html:33
302 msgid " in "
303 msgid " in "
303 msgstr " в "
304 msgstr " в "
304
305
305 #: templates/boards/post.html:43
306 #: templates/boards/post.html:43
306 msgid "Edit"
307 msgid "Edit"
307 msgstr "Изменить"
308 msgstr "Изменить"
308
309
309 #: templates/boards/post.html:45
310 #: templates/boards/post.html:45
310 msgid "Edit thread"
311 msgid "Edit thread"
311 msgstr "Изменить тему"
312 msgstr "Изменить тему"
312
313
313 #: templates/boards/post.html:84
314 #: templates/boards/post.html:84
314 msgid "Replies"
315 msgid "Replies"
315 msgstr "Ответы"
316 msgstr "Ответы"
316
317
317 #: templates/boards/post.html:97 templates/boards/thread.html:34
318 #: templates/boards/post.html:97 templates/boards/thread.html:34
318 msgid "messages"
319 msgid "messages"
319 msgstr "сообщений"
320 msgstr "сообщений"
320
321
321 #: templates/boards/post.html:98 templates/boards/thread.html:35
322 #: templates/boards/post.html:98 templates/boards/thread.html:35
322 msgid "images"
323 msgid "images"
323 msgstr "изображений"
324 msgstr "изображений"
324
325
325 #: templates/boards/rss/post.html:5
326 #: templates/boards/rss/post.html:5
326 msgid "Post image"
327 msgid "Post image"
327 msgstr "Изображение сообщения"
328 msgstr "Изображение сообщения"
328
329
329 #: templates/boards/settings.html:16
330 #: templates/boards/settings.html:16
330 msgid "You are moderator."
331 msgid "You are moderator."
331 msgstr "Вы модератор."
332 msgstr "Вы модератор."
332
333
333 #: templates/boards/settings.html:20
334 #: templates/boards/settings.html:20
334 msgid "Hidden tags:"
335 msgid "Hidden tags:"
335 msgstr "Скрытые метки:"
336 msgstr "Скрытые метки:"
336
337
337 #: templates/boards/settings.html:28
338 #: templates/boards/settings.html:28
338 msgid "No hidden tags."
339 msgid "No hidden tags."
339 msgstr "Нет скрытых меток."
340 msgstr "Нет скрытых меток."
340
341
341 #: templates/boards/settings.html:37
342 #: templates/boards/settings.html:37
342 msgid "Save"
343 msgid "Save"
343 msgstr "Сохранить"
344 msgstr "Сохранить"
344
345
345 #: templates/boards/staticpages/banned.html:6
346 #: templates/boards/staticpages/banned.html:6
346 msgid "Banned"
347 msgid "Banned"
347 msgstr "Заблокирован"
348 msgstr "Заблокирован"
348
349
349 #: templates/boards/staticpages/banned.html:11
350 #: templates/boards/staticpages/banned.html:11
350 msgid "Your IP address has been banned. Contact the administrator"
351 msgid "Your IP address has been banned. Contact the administrator"
351 msgstr "Ваш IP адрес был заблокирован. Свяжитесь с администратором"
352 msgstr "Ваш IP адрес был заблокирован. Свяжитесь с администратором"
352
353
353 #: templates/boards/staticpages/help.html:6
354 #: templates/boards/staticpages/help.html:6
354 #: templates/boards/staticpages/help.html:10
355 #: templates/boards/staticpages/help.html:10
355 msgid "Syntax"
356 msgid "Syntax"
356 msgstr "Синтаксис"
357 msgstr "Синтаксис"
357
358
358 #: templates/boards/staticpages/help.html:11
359 #: templates/boards/staticpages/help.html:11
359 msgid "Italic text"
360 msgid "Italic text"
360 msgstr "Курсивный текст"
361 msgstr "Курсивный текст"
361
362
362 #: templates/boards/staticpages/help.html:12
363 #: templates/boards/staticpages/help.html:12
363 msgid "Bold text"
364 msgid "Bold text"
364 msgstr "Полужирный текст"
365 msgstr "Полужирный текст"
365
366
366 #: templates/boards/staticpages/help.html:13
367 #: templates/boards/staticpages/help.html:13
367 msgid "Spoiler"
368 msgid "Spoiler"
368 msgstr "Спойлер"
369 msgstr "Спойлер"
369
370
370 #: templates/boards/staticpages/help.html:14
371 #: templates/boards/staticpages/help.html:14
371 msgid "Link to a post"
372 msgid "Link to a post"
372 msgstr "Ссылка на сообщение"
373 msgstr "Ссылка на сообщение"
373
374
374 #: templates/boards/staticpages/help.html:15
375 #: templates/boards/staticpages/help.html:15
375 msgid "Strikethrough text"
376 msgid "Strikethrough text"
376 msgstr "Зачеркнутый текст"
377 msgstr "Зачеркнутый текст"
377
378
378 #: templates/boards/staticpages/help.html:16
379 #: templates/boards/staticpages/help.html:16
379 msgid "Comment"
380 msgid "Comment"
380 msgstr "Комментарий"
381 msgstr "Комментарий"
381
382
382 #: templates/boards/staticpages/help.html:17
383 #: templates/boards/staticpages/help.html:17
383 #: templates/boards/staticpages/help.html:18
384 #: templates/boards/staticpages/help.html:18
384 msgid "Quote"
385 msgid "Quote"
385 msgstr "Цитата"
386 msgstr "Цитата"
386
387
387 #: templates/boards/staticpages/help.html:21
388 #: templates/boards/staticpages/help.html:21
388 msgid "You can try pasting the text and previewing the result here:"
389 msgid "You can try pasting the text and previewing the result here:"
389 msgstr "Вы можете попробовать вставить текст и проверить результат здесь:"
390 msgstr "Вы можете попробовать вставить текст и проверить результат здесь:"
390
391
391 #: templates/boards/tags.html:14
392 #: templates/boards/tags.html:14
392 msgid "Sections:"
393 msgid "Sections:"
393 msgstr "Разделы:"
394 msgstr "Разделы:"
394
395
395 #: templates/boards/tags.html:26
396 #: templates/boards/tags.html:26
396 #| msgid "Hidden tags:"
397 msgid "Other tags:"
397 msgid "Other tags:"
398 msgstr "Другие метки:"
398 msgstr "Другие метки:"
399
399
400 #: templates/boards/tags.html:38
400 #: templates/boards/tags.html:38
401 #| msgid "All tags"
402 msgid "All tags..."
401 msgid "All tags..."
403 msgstr "Все метки..."
402 msgstr "Все метки..."
404
403
405 #: templates/boards/thread.html:15
404 #: templates/boards/thread.html:15
406 msgid "Normal"
405 msgid "Normal"
407 msgstr "Нормальный"
406 msgstr "Нормальный"
408
407
409 #: templates/boards/thread.html:16
408 #: templates/boards/thread.html:16
410 msgid "Gallery"
409 msgid "Gallery"
411 msgstr "Галерея"
410 msgstr "Галерея"
412
411
413 #: templates/boards/thread.html:17
412 #: templates/boards/thread.html:17
414 msgid "Tree"
413 msgid "Tree"
415 msgstr "Дерево"
414 msgstr "Дерево"
416
415
417 #: templates/boards/thread.html:36
416 #: templates/boards/thread.html:36
418 msgid "Last update: "
417 msgid "Last update: "
419 msgstr "Последнее обновление: "
418 msgstr "Последнее обновление: "
420
419
421 #: templates/boards/thread_gallery.html:36
420 #: templates/boards/thread_gallery.html:36
422 msgid "No images."
421 msgid "No images."
423 msgstr "Нет изображений."
422 msgstr "Нет изображений."
424
423
425 #: templates/boards/thread_normal.html:17
424 #: templates/boards/thread_normal.html:17
426 msgid "posts to bumplimit"
425 msgid "posts to bumplimit"
427 msgstr "сообщений до бамплимита"
426 msgstr "сообщений до бамплимита"
428
427
429 #: templates/boards/thread_normal.html:31
428 #: templates/boards/thread_normal.html:31
430 msgid "Reply to thread"
429 msgid "Reply to thread"
431 msgstr "Ответить в тему"
430 msgstr "Ответить в тему"
432
431
433 #: templates/boards/thread_normal.html:46
432 #: templates/boards/thread_normal.html:46
434 msgid "Close form"
433 msgid "Close form"
435 msgstr "Закрыть форму"
434 msgstr "Закрыть форму"
436
435
437 #: templates/search/search.html:17
436 #: templates/search/search.html:17
438 msgid "Ok"
437 msgid "Ok"
439 msgstr "Ок"
438 msgstr "Ок"
440
General Comments 0
You need to be logged in to leave comments. Login now