##// END OF EJS Templates
Checking file uniqueness is not an image download mode
neko259 -
r1959:09e0382a default
parent child Browse files
Show More
@@ -1,590 +1,591 b''
1 import hashlib
1 import hashlib
2 import logging
2 import logging
3 import re
3 import re
4 import time
4 import time
5
5
6 import pytz
6 import pytz
7
7
8 from PIL import Image
8 from PIL import Image
9
9
10 from django import forms
10 from django import forms
11 from django.core.files.uploadedfile import SimpleUploadedFile, UploadedFile
11 from django.core.files.uploadedfile import SimpleUploadedFile, UploadedFile
12 from django.forms.utils import ErrorList
12 from django.forms.utils import ErrorList
13 from django.utils.translation import ugettext_lazy as _, ungettext_lazy
13 from django.utils.translation import ugettext_lazy as _, ungettext_lazy
14 from django.core.files.images import get_image_dimensions
14 from django.core.files.images import get_image_dimensions
15 from django.core.cache import cache
15 from django.core.cache import cache
16
16
17 import boards.settings as board_settings
17 import boards.settings as board_settings
18 import neboard
18 import neboard
19 from boards import utils
19 from boards import utils
20 from boards.abstracts.constants import REGEX_TAGS
20 from boards.abstracts.constants import REGEX_TAGS
21 from boards.abstracts.sticker_factory import get_attachment_by_alias
21 from boards.abstracts.sticker_factory import get_attachment_by_alias
22 from boards.abstracts.settingsmanager import get_settings_manager
22 from boards.abstracts.settingsmanager import get_settings_manager
23 from boards.forms.fields import UrlFileField
23 from boards.forms.fields import UrlFileField
24 from boards.mdx_neboard import formatters
24 from boards.mdx_neboard import formatters
25 from boards.models import Attachment
25 from boards.models import Attachment
26 from boards.models import Tag
26 from boards.models import Tag
27 from boards.models.attachment import StickerPack
27 from boards.models.attachment import StickerPack
28 from boards.models.attachment.downloaders import download, REGEX_MAGNET
28 from boards.models.attachment.downloaders import download, REGEX_MAGNET
29 from boards.models.post import TITLE_MAX_LENGTH
29 from boards.models.post import TITLE_MAX_LENGTH
30 from boards.utils import validate_file_size, get_file_mimetype, \
30 from boards.utils import validate_file_size, get_file_mimetype, \
31 FILE_EXTENSION_DELIMITER
31 FILE_EXTENSION_DELIMITER
32 from boards.models.attachment.viewers import FILE_TYPES_IMAGE
32 from boards.models.attachment.viewers import FILE_TYPES_IMAGE
33 from neboard import settings
33 from neboard import settings
34
34
35 SECTION_FORMS = 'Forms'
35 SECTION_FORMS = 'Forms'
36
36
37 POW_HASH_LENGTH = 16
37 POW_HASH_LENGTH = 16
38 POW_LIFE_MINUTES = 5
38 POW_LIFE_MINUTES = 5
39
39
40 REGEX_USERNAMES = re.compile(r'^[\w\s\d,]+$', re.UNICODE)
40 REGEX_USERNAMES = re.compile(r'^[\w\s\d,]+$', re.UNICODE)
41 REGEX_URL = re.compile(r'^(http|https|ftp):\/\/', re.UNICODE)
41 REGEX_URL = re.compile(r'^(http|https|ftp):\/\/', re.UNICODE)
42
42
43 VETERAN_POSTING_DELAY = 5
43 VETERAN_POSTING_DELAY = 5
44
44
45 ATTRIBUTE_PLACEHOLDER = 'placeholder'
45 ATTRIBUTE_PLACEHOLDER = 'placeholder'
46 ATTRIBUTE_ROWS = 'rows'
46 ATTRIBUTE_ROWS = 'rows'
47
47
48 LAST_POST_TIME = 'last_post_time'
48 LAST_POST_TIME = 'last_post_time'
49 LAST_LOGIN_TIME = 'last_login_time'
49 LAST_LOGIN_TIME = 'last_login_time'
50 TEXT_PLACEHOLDER = _('Type message here. Use formatting panel for more advanced usage.')
50 TEXT_PLACEHOLDER = _('Type message here. Use formatting panel for more advanced usage.')
51 TAGS_PLACEHOLDER = _('music images i_dont_like_tags')
51 TAGS_PLACEHOLDER = _('music images i_dont_like_tags')
52
52
53 LABEL_TITLE = _('Title')
53 LABEL_TITLE = _('Title')
54 LABEL_TEXT = _('Text')
54 LABEL_TEXT = _('Text')
55 LABEL_TAG = _('Tag')
55 LABEL_TAG = _('Tag')
56 LABEL_SEARCH = _('Search')
56 LABEL_SEARCH = _('Search')
57 LABEL_FILE = _('File')
57 LABEL_FILE = _('File')
58 LABEL_DUPLICATES = _('Check for duplicates')
58 LABEL_DUPLICATES = _('Check for duplicates')
59 LABEL_URL = _('Do not download URLs')
59 LABEL_URL = _('Do not download URLs')
60
60
61 ERROR_SPEED = 'Please wait %(delay)d second before sending message'
61 ERROR_SPEED = 'Please wait %(delay)d second before sending message'
62 ERROR_SPEED_PLURAL = 'Please wait %(delay)d seconds before sending message'
62 ERROR_SPEED_PLURAL = 'Please wait %(delay)d seconds before sending message'
63 ERROR_MANY_FILES = 'You can post no more than %(files)d file.'
63 ERROR_MANY_FILES = 'You can post no more than %(files)d file.'
64 ERROR_MANY_FILES_PLURAL = 'You can post no more than %(files)d files.'
64 ERROR_MANY_FILES_PLURAL = 'You can post no more than %(files)d files.'
65 ERROR_DUPLICATES = 'Some files are already present on the board.'
65 ERROR_DUPLICATES = 'Some files are already present on the board.'
66
66
67 TAG_MAX_LENGTH = 20
67 TAG_MAX_LENGTH = 20
68
68
69 TEXTAREA_ROWS = 4
69 TEXTAREA_ROWS = 4
70
70
71 TRIPCODE_DELIM = '##'
71 TRIPCODE_DELIM = '##'
72
72
73 # TODO Maybe this may be converted into the database table?
73 # TODO Maybe this may be converted into the database table?
74 MIMETYPE_EXTENSIONS = {
74 MIMETYPE_EXTENSIONS = {
75 'image/jpeg': 'jpeg',
75 'image/jpeg': 'jpeg',
76 'image/png': 'png',
76 'image/png': 'png',
77 'image/gif': 'gif',
77 'image/gif': 'gif',
78 'video/webm': 'webm',
78 'video/webm': 'webm',
79 'application/pdf': 'pdf',
79 'application/pdf': 'pdf',
80 'x-diff': 'diff',
80 'x-diff': 'diff',
81 'image/svg+xml': 'svg',
81 'image/svg+xml': 'svg',
82 'application/x-shockwave-flash': 'swf',
82 'application/x-shockwave-flash': 'swf',
83 'image/x-ms-bmp': 'bmp',
83 'image/x-ms-bmp': 'bmp',
84 'image/bmp': 'bmp',
84 'image/bmp': 'bmp',
85 }
85 }
86
86
87 DOWN_MODE_DOWNLOAD = 'DOWNLOAD'
87 DOWN_MODE_DOWNLOAD = 'DOWNLOAD'
88 DOWN_MODE_DOWNLOAD_UNIQUE = 'DOWNLOAD_UNIQUE'
88 DOWN_MODE_URL = 'URL'
89 DOWN_MODE_URL = 'URL'
89 DOWN_MODE_TRY = 'TRY'
90 DOWN_MODE_TRY = 'TRY'
90
91
91
92
92 logger = logging.getLogger('boards.forms')
93 logger = logging.getLogger('boards.forms')
93
94
94
95
95 def get_timezones():
96 def get_timezones():
96 timezones = []
97 timezones = []
97 for tz in pytz.common_timezones:
98 for tz in pytz.common_timezones:
98 timezones.append((tz, tz),)
99 timezones.append((tz, tz),)
99 return timezones
100 return timezones
100
101
101
102
102 class FormatPanel(forms.Textarea):
103 class FormatPanel(forms.Textarea):
103 """
104 """
104 Panel for text formatting. Consists of buttons to add different tags to the
105 Panel for text formatting. Consists of buttons to add different tags to the
105 form text area.
106 form text area.
106 """
107 """
107
108
108 def render(self, name, value, attrs=None):
109 def render(self, name, value, attrs=None):
109 output = '<div id="mark-panel">'
110 output = '<div id="mark-panel">'
110 for formatter in formatters:
111 for formatter in formatters:
111 output += '<span class="mark_btn"' + \
112 output += '<span class="mark_btn"' + \
112 ' onClick="addMarkToMsg(\'' + formatter.format_left + \
113 ' onClick="addMarkToMsg(\'' + formatter.format_left + \
113 '\', \'' + formatter.format_right + '\')">' + \
114 '\', \'' + formatter.format_right + '\')">' + \
114 formatter.preview_left + formatter.name + \
115 formatter.preview_left + formatter.name + \
115 formatter.preview_right + '</span>'
116 formatter.preview_right + '</span>'
116
117
117 output += '</div>'
118 output += '</div>'
118 output += super(FormatPanel, self).render(name, value, attrs=attrs)
119 output += super(FormatPanel, self).render(name, value, attrs=attrs)
119
120
120 return output
121 return output
121
122
122
123
123 class PlainErrorList(ErrorList):
124 class PlainErrorList(ErrorList):
124 def __unicode__(self):
125 def __unicode__(self):
125 return self.as_text()
126 return self.as_text()
126
127
127 def as_text(self):
128 def as_text(self):
128 return ''.join(['(!) %s ' % e for e in self])
129 return ''.join(['(!) %s ' % e for e in self])
129
130
130
131
131 class NeboardForm(forms.Form):
132 class NeboardForm(forms.Form):
132 """
133 """
133 Form with neboard-specific formatting.
134 Form with neboard-specific formatting.
134 """
135 """
135 required_css_class = 'required-field'
136 required_css_class = 'required-field'
136
137
137 def as_div(self):
138 def as_div(self):
138 """
139 """
139 Returns this form rendered as HTML <as_div>s.
140 Returns this form rendered as HTML <as_div>s.
140 """
141 """
141
142
142 return self._html_output(
143 return self._html_output(
143 # TODO Do not show hidden rows in the list here
144 # TODO Do not show hidden rows in the list here
144 normal_row='<div class="form-row">'
145 normal_row='<div class="form-row">'
145 '<div class="form-label">'
146 '<div class="form-label">'
146 '%(label)s'
147 '%(label)s'
147 '</div>'
148 '</div>'
148 '<div class="form-input">'
149 '<div class="form-input">'
149 '%(field)s'
150 '%(field)s'
150 '</div>'
151 '</div>'
151 '</div>'
152 '</div>'
152 '<div class="form-row">'
153 '<div class="form-row">'
153 '%(help_text)s'
154 '%(help_text)s'
154 '</div>',
155 '</div>',
155 error_row='<div class="form-row">'
156 error_row='<div class="form-row">'
156 '<div class="form-label"></div>'
157 '<div class="form-label"></div>'
157 '<div class="form-errors">%s</div>'
158 '<div class="form-errors">%s</div>'
158 '</div>',
159 '</div>',
159 row_ender='</div>',
160 row_ender='</div>',
160 help_text_html='%s',
161 help_text_html='%s',
161 errors_on_separate_row=True)
162 errors_on_separate_row=True)
162
163
163 def as_json_errors(self):
164 def as_json_errors(self):
164 errors = []
165 errors = []
165
166
166 for name, field in list(self.fields.items()):
167 for name, field in list(self.fields.items()):
167 if self[name].errors:
168 if self[name].errors:
168 errors.append({
169 errors.append({
169 'field': name,
170 'field': name,
170 'errors': self[name].errors.as_text(),
171 'errors': self[name].errors.as_text(),
171 })
172 })
172
173
173 return errors
174 return errors
174
175
175
176
176 class PostForm(NeboardForm):
177 class PostForm(NeboardForm):
177
178
178 title = forms.CharField(max_length=TITLE_MAX_LENGTH, required=False,
179 title = forms.CharField(max_length=TITLE_MAX_LENGTH, required=False,
179 label=LABEL_TITLE,
180 label=LABEL_TITLE,
180 widget=forms.TextInput(
181 widget=forms.TextInput(
181 attrs={ATTRIBUTE_PLACEHOLDER: 'Title{}tripcode'.format(TRIPCODE_DELIM)}))
182 attrs={ATTRIBUTE_PLACEHOLDER: 'Title{}tripcode'.format(TRIPCODE_DELIM)}))
182 text = forms.CharField(
183 text = forms.CharField(
183 widget=FormatPanel(attrs={
184 widget=FormatPanel(attrs={
184 ATTRIBUTE_PLACEHOLDER: TEXT_PLACEHOLDER,
185 ATTRIBUTE_PLACEHOLDER: TEXT_PLACEHOLDER,
185 ATTRIBUTE_ROWS: TEXTAREA_ROWS,
186 ATTRIBUTE_ROWS: TEXTAREA_ROWS,
186 }),
187 }),
187 required=False, label=LABEL_TEXT)
188 required=False, label=LABEL_TEXT)
188 download_mode = forms.ChoiceField(
189 download_mode = forms.ChoiceField(
189 choices=(
190 choices=(
190 (DOWN_MODE_TRY, _('Download or add URL')),
191 (DOWN_MODE_TRY, _('Download or insert as URLs')),
191 (DOWN_MODE_DOWNLOAD, _('Download or fail')),
192 (DOWN_MODE_DOWNLOAD, _('Download')),
193 (DOWN_MODE_DOWNLOAD_UNIQUE, _('Download and check for uniqueness')),
192 (DOWN_MODE_URL, _('Insert as URLs')),
194 (DOWN_MODE_URL, _('Insert as URLs')),
193 ),
195 ),
194 initial=DOWN_MODE_TRY,
196 initial=DOWN_MODE_TRY,
195 label=_('URL download mode'))
197 label=_('File process mode'))
196 file = UrlFileField(required=False, label=LABEL_FILE)
198 file = UrlFileField(required=False, label=LABEL_FILE)
197
199
198 # This field is for spam prevention only
200 # This field is for spam prevention only
199 email = forms.CharField(max_length=100, required=False, label=_('e-mail'),
201 email = forms.CharField(max_length=100, required=False, label=_('e-mail'),
200 widget=forms.TextInput(attrs={
202 widget=forms.TextInput(attrs={
201 'class': 'form-email'}))
203 'class': 'form-email'}))
202 subscribe = forms.BooleanField(required=False, label=_('Subscribe to thread'))
204 subscribe = forms.BooleanField(required=False, label=_('Subscribe to thread'))
203 check_duplicates = forms.BooleanField(required=False, label=LABEL_DUPLICATES)
204
205
205 guess = forms.CharField(widget=forms.HiddenInput(), required=False)
206 guess = forms.CharField(widget=forms.HiddenInput(), required=False)
206 timestamp = forms.CharField(widget=forms.HiddenInput(), required=False)
207 timestamp = forms.CharField(widget=forms.HiddenInput(), required=False)
207 iteration = forms.CharField(widget=forms.HiddenInput(), required=False)
208 iteration = forms.CharField(widget=forms.HiddenInput(), required=False)
208
209
209 session = None
210 session = None
210 need_to_ban = False
211 need_to_ban = False
211
212
212 def clean_title(self):
213 def clean_title(self):
213 title = self.cleaned_data['title']
214 title = self.cleaned_data['title']
214 if title:
215 if title:
215 if len(title) > TITLE_MAX_LENGTH:
216 if len(title) > TITLE_MAX_LENGTH:
216 raise forms.ValidationError(_('Title must have less than %s '
217 raise forms.ValidationError(_('Title must have less than %s '
217 'characters') %
218 'characters') %
218 str(TITLE_MAX_LENGTH))
219 str(TITLE_MAX_LENGTH))
219 return title
220 return title
220
221
221 def clean_text(self):
222 def clean_text(self):
222 text = self.cleaned_data['text'].strip()
223 text = self.cleaned_data['text'].strip()
223 if text:
224 if text:
224 max_length = board_settings.get_int(SECTION_FORMS, 'MaxTextLength')
225 max_length = board_settings.get_int(SECTION_FORMS, 'MaxTextLength')
225 if len(text) > max_length:
226 if len(text) > max_length:
226 raise forms.ValidationError(_('Text must have less than %s '
227 raise forms.ValidationError(_('Text must have less than %s '
227 'characters') % str(max_length))
228 'characters') % str(max_length))
228 return text
229 return text
229
230
230 def clean_file(self):
231 def clean_file(self):
231 return self._clean_files(self.cleaned_data['file'])
232 return self._clean_files(self.cleaned_data['file'])
232
233
233 def clean(self):
234 def clean(self):
234 cleaned_data = super(PostForm, self).clean()
235 cleaned_data = super(PostForm, self).clean()
235
236
236 if cleaned_data['email']:
237 if cleaned_data['email']:
237 if board_settings.get_bool(SECTION_FORMS, 'Autoban'):
238 if board_settings.get_bool(SECTION_FORMS, 'Autoban'):
238 self.need_to_ban = True
239 self.need_to_ban = True
239 raise forms.ValidationError('A human cannot enter a hidden field')
240 raise forms.ValidationError('A human cannot enter a hidden field')
240
241
241 if not self.errors:
242 if not self.errors:
242 self._clean_text_file()
243 self._clean_text_file()
243
244
244 limit_speed = board_settings.get_bool(SECTION_FORMS, 'LimitPostingSpeed')
245 limit_speed = board_settings.get_bool(SECTION_FORMS, 'LimitPostingSpeed')
245 limit_first = board_settings.get_bool(SECTION_FORMS, 'LimitFirstPosting')
246 limit_first = board_settings.get_bool(SECTION_FORMS, 'LimitFirstPosting')
246
247
247 settings_manager = get_settings_manager(self)
248 settings_manager = get_settings_manager(self)
248 if not self.errors and limit_speed or (limit_first and not settings_manager.get_setting('confirmed_user')):
249 if not self.errors and limit_speed or (limit_first and not settings_manager.get_setting('confirmed_user')):
249 pow_difficulty = board_settings.get_int(SECTION_FORMS, 'PowDifficulty')
250 pow_difficulty = board_settings.get_int(SECTION_FORMS, 'PowDifficulty')
250 if pow_difficulty > 0:
251 if pow_difficulty > 0:
251 # PoW-based
252 # PoW-based
252 if cleaned_data['timestamp'] \
253 if cleaned_data['timestamp'] \
253 and cleaned_data['iteration'] and cleaned_data['guess'] \
254 and cleaned_data['iteration'] and cleaned_data['guess'] \
254 and not settings_manager.get_setting('confirmed_user'):
255 and not settings_manager.get_setting('confirmed_user'):
255 self._validate_hash(cleaned_data['timestamp'], cleaned_data['iteration'], cleaned_data['guess'], cleaned_data['text'])
256 self._validate_hash(cleaned_data['timestamp'], cleaned_data['iteration'], cleaned_data['guess'], cleaned_data['text'])
256 else:
257 else:
257 # Time-based
258 # Time-based
258 self._validate_posting_speed()
259 self._validate_posting_speed()
259 settings_manager.set_setting('confirmed_user', True)
260 settings_manager.set_setting('confirmed_user', True)
260 if self.cleaned_data['check_duplicates']:
261 if self.cleaned_data['download_mode'] == DOWN_MODE_DOWNLOAD_UNIQUE:
261 self._check_file_duplicates(self.get_files())
262 self._check_file_duplicates(self.get_files())
262
263
263 return cleaned_data
264 return cleaned_data
264
265
265 def get_files(self):
266 def get_files(self):
266 """
267 """
267 Gets file from form or URL.
268 Gets file from form or URL.
268 """
269 """
269
270
270 files = []
271 files = []
271 for file in self.cleaned_data['file']:
272 for file in self.cleaned_data['file']:
272 if isinstance(file, UploadedFile):
273 if isinstance(file, UploadedFile):
273 files.append(file)
274 files.append(file)
274
275
275 return files
276 return files
276
277
277 def get_file_urls(self):
278 def get_file_urls(self):
278 files = []
279 files = []
279 for file in self.cleaned_data['file']:
280 for file in self.cleaned_data['file']:
280 if type(file) == str:
281 if type(file) == str:
281 files.append(file)
282 files.append(file)
282
283
283 return files
284 return files
284
285
285 def get_tripcode(self):
286 def get_tripcode(self):
286 title = self.cleaned_data['title']
287 title = self.cleaned_data['title']
287 if title is not None and TRIPCODE_DELIM in title:
288 if title is not None and TRIPCODE_DELIM in title:
288 code = title.split(TRIPCODE_DELIM, maxsplit=1)[1] + neboard.settings.SECRET_KEY
289 code = title.split(TRIPCODE_DELIM, maxsplit=1)[1] + neboard.settings.SECRET_KEY
289 tripcode = hashlib.md5(code.encode()).hexdigest()
290 tripcode = hashlib.md5(code.encode()).hexdigest()
290 else:
291 else:
291 tripcode = ''
292 tripcode = ''
292 return tripcode
293 return tripcode
293
294
294 def get_title(self):
295 def get_title(self):
295 title = self.cleaned_data['title']
296 title = self.cleaned_data['title']
296 if title is not None and TRIPCODE_DELIM in title:
297 if title is not None and TRIPCODE_DELIM in title:
297 return title.split(TRIPCODE_DELIM, maxsplit=1)[0]
298 return title.split(TRIPCODE_DELIM, maxsplit=1)[0]
298 else:
299 else:
299 return title
300 return title
300
301
301 def get_images(self):
302 def get_images(self):
302 return self.cleaned_data.get('stickers', [])
303 return self.cleaned_data.get('stickers', [])
303
304
304 def is_subscribe(self):
305 def is_subscribe(self):
305 return self.cleaned_data['subscribe']
306 return self.cleaned_data['subscribe']
306
307
307 def _update_file_extension(self, file):
308 def _update_file_extension(self, file):
308 if file:
309 if file:
309 mimetype = get_file_mimetype(file)
310 mimetype = get_file_mimetype(file)
310 extension = MIMETYPE_EXTENSIONS.get(mimetype)
311 extension = MIMETYPE_EXTENSIONS.get(mimetype)
311 if extension:
312 if extension:
312 filename = file.name.split(FILE_EXTENSION_DELIMITER, 1)[0]
313 filename = file.name.split(FILE_EXTENSION_DELIMITER, 1)[0]
313 new_filename = filename + FILE_EXTENSION_DELIMITER + extension
314 new_filename = filename + FILE_EXTENSION_DELIMITER + extension
314
315
315 file.name = new_filename
316 file.name = new_filename
316 else:
317 else:
317 logger.info('Unrecognized file mimetype: {}'.format(mimetype))
318 logger.info('Unrecognized file mimetype: {}'.format(mimetype))
318
319
319 def _clean_files(self, inputs):
320 def _clean_files(self, inputs):
320 files = []
321 files = []
321
322
322 max_file_count = board_settings.get_int(SECTION_FORMS, 'MaxFileCount')
323 max_file_count = board_settings.get_int(SECTION_FORMS, 'MaxFileCount')
323 if len(inputs) > max_file_count:
324 if len(inputs) > max_file_count:
324 raise forms.ValidationError(
325 raise forms.ValidationError(
325 ungettext_lazy(ERROR_MANY_FILES, ERROR_MANY_FILES,
326 ungettext_lazy(ERROR_MANY_FILES, ERROR_MANY_FILES,
326 max_file_count) % {'files': max_file_count})
327 max_file_count) % {'files': max_file_count})
327 for file_input in inputs:
328 for file_input in inputs:
328 if isinstance(file_input, UploadedFile):
329 if isinstance(file_input, UploadedFile):
329 files.append(self._clean_file_file(file_input))
330 files.append(self._clean_file_file(file_input))
330 else:
331 else:
331 files.append(self._clean_file_url(file_input))
332 files.append(self._clean_file_url(file_input))
332
333
333 for file in files:
334 for file in files:
334 self._validate_image_dimensions(file)
335 self._validate_image_dimensions(file)
335
336
336 return files
337 return files
337
338
338 def _validate_image_dimensions(self, file):
339 def _validate_image_dimensions(self, file):
339 if isinstance(file, UploadedFile):
340 if isinstance(file, UploadedFile):
340 mimetype = get_file_mimetype(file)
341 mimetype = get_file_mimetype(file)
341 if mimetype.split('/')[-1] in FILE_TYPES_IMAGE:
342 if mimetype.split('/')[-1] in FILE_TYPES_IMAGE:
342 Image.warnings.simplefilter('error', Image.DecompressionBombWarning)
343 Image.warnings.simplefilter('error', Image.DecompressionBombWarning)
343 try:
344 try:
344 print(get_image_dimensions(file))
345 print(get_image_dimensions(file))
345 except Exception:
346 except Exception:
346 raise forms.ValidationError('Possible decompression bomb or large image.')
347 raise forms.ValidationError('Possible decompression bomb or large image.')
347
348
348 def _clean_file_file(self, file):
349 def _clean_file_file(self, file):
349 validate_file_size(file.size)
350 validate_file_size(file.size)
350 self._update_file_extension(file)
351 self._update_file_extension(file)
351
352
352 return file
353 return file
353
354
354 def _clean_file_url(self, url):
355 def _clean_file_url(self, url):
355 file = None
356 file = None
356
357
357 if url:
358 if url:
358 mode = self.cleaned_data['download_mode']
359 mode = self.cleaned_data['download_mode']
359 if mode == DOWN_MODE_URL:
360 if mode == DOWN_MODE_URL:
360 return url
361 return url
361
362
362 try:
363 try:
363 image = get_attachment_by_alias(url, self.session)
364 image = get_attachment_by_alias(url, self.session)
364 if image is not None:
365 if image is not None:
365 if 'stickers' not in self.cleaned_data:
366 if 'stickers' not in self.cleaned_data:
366 self.cleaned_data['stickers'] = []
367 self.cleaned_data['stickers'] = []
367 self.cleaned_data['stickers'].append(image)
368 self.cleaned_data['stickers'].append(image)
368 return
369 return
369
370
370 if file is None:
371 if file is None:
371 file = self._get_file_from_url(url)
372 file = self._get_file_from_url(url)
372 if not file:
373 if not file:
373 raise forms.ValidationError(_('Invalid URL'))
374 raise forms.ValidationError(_('Invalid URL'))
374 else:
375 else:
375 validate_file_size(file.size)
376 validate_file_size(file.size)
376 self._update_file_extension(file)
377 self._update_file_extension(file)
377 except forms.ValidationError as e:
378 except forms.ValidationError as e:
378 # Assume we will get the plain URL instead of a file and save it
379 # Assume we will get the plain URL instead of a file and save it
379 if mode == DOWN_MODE_TRY and (REGEX_URL.match(url) or REGEX_MAGNET.match(url)):
380 if mode == DOWN_MODE_TRY and (REGEX_URL.match(url) or REGEX_MAGNET.match(url)):
380 logger.info('Error in forms: {}'.format(e))
381 logger.info('Error in forms: {}'.format(e))
381 return url
382 return url
382 else:
383 else:
383 raise e
384 raise e
384
385
385 return file
386 return file
386
387
387 def _clean_text_file(self):
388 def _clean_text_file(self):
388 text = self.cleaned_data.get('text')
389 text = self.cleaned_data.get('text')
389 file = self.get_files()
390 file = self.get_files()
390 file_url = self.get_file_urls()
391 file_url = self.get_file_urls()
391 images = self.get_images()
392 images = self.get_images()
392
393
393 if (not text) and (not file) and (not file_url) and len(images) == 0:
394 if (not text) and (not file) and (not file_url) and len(images) == 0:
394 error_message = _('Either text or file must be entered.')
395 error_message = _('Either text or file must be entered.')
395 self._add_general_error(error_message)
396 self._add_general_error(error_message)
396
397
397 def _get_cache_key(self, key):
398 def _get_cache_key(self, key):
398 return '{}_{}'.format(self.session.session_key, key)
399 return '{}_{}'.format(self.session.session_key, key)
399
400
400 def _set_session_cache(self, key, value):
401 def _set_session_cache(self, key, value):
401 cache.set(self._get_cache_key(key), value)
402 cache.set(self._get_cache_key(key), value)
402
403
403 def _get_session_cache(self, key):
404 def _get_session_cache(self, key):
404 return cache.get(self._get_cache_key(key))
405 return cache.get(self._get_cache_key(key))
405
406
406 def _get_last_post_time(self):
407 def _get_last_post_time(self):
407 last = self._get_session_cache(LAST_POST_TIME)
408 last = self._get_session_cache(LAST_POST_TIME)
408 if last is None:
409 if last is None:
409 last = self.session.get(LAST_POST_TIME)
410 last = self.session.get(LAST_POST_TIME)
410 return last
411 return last
411
412
412 def _validate_posting_speed(self):
413 def _validate_posting_speed(self):
413 can_post = True
414 can_post = True
414
415
415 posting_delay = board_settings.get_int(SECTION_FORMS, 'PostingDelay')
416 posting_delay = board_settings.get_int(SECTION_FORMS, 'PostingDelay')
416
417
417 if board_settings.get_bool(SECTION_FORMS, 'LimitPostingSpeed'):
418 if board_settings.get_bool(SECTION_FORMS, 'LimitPostingSpeed'):
418 now = time.time()
419 now = time.time()
419
420
420 current_delay = 0
421 current_delay = 0
421
422
422 if LAST_POST_TIME not in self.session:
423 if LAST_POST_TIME not in self.session:
423 self.session[LAST_POST_TIME] = now
424 self.session[LAST_POST_TIME] = now
424
425
425 need_delay = True
426 need_delay = True
426 else:
427 else:
427 last_post_time = self._get_last_post_time()
428 last_post_time = self._get_last_post_time()
428 current_delay = int(now - last_post_time)
429 current_delay = int(now - last_post_time)
429
430
430 need_delay = current_delay < posting_delay
431 need_delay = current_delay < posting_delay
431
432
432 self._set_session_cache(LAST_POST_TIME, now)
433 self._set_session_cache(LAST_POST_TIME, now)
433
434
434 if need_delay:
435 if need_delay:
435 delay = posting_delay - current_delay
436 delay = posting_delay - current_delay
436 error_message = ungettext_lazy(ERROR_SPEED, ERROR_SPEED_PLURAL,
437 error_message = ungettext_lazy(ERROR_SPEED, ERROR_SPEED_PLURAL,
437 delay) % {'delay': delay}
438 delay) % {'delay': delay}
438 self._add_general_error(error_message)
439 self._add_general_error(error_message)
439
440
440 can_post = False
441 can_post = False
441
442
442 if can_post:
443 if can_post:
443 self.session[LAST_POST_TIME] = now
444 self.session[LAST_POST_TIME] = now
444 else:
445 else:
445 # Reset the time since posting failed
446 # Reset the time since posting failed
446 self._set_session_cache(LAST_POST_TIME, self.session[LAST_POST_TIME])
447 self._set_session_cache(LAST_POST_TIME, self.session[LAST_POST_TIME])
447
448
448 def _get_file_from_url(self, url: str) -> SimpleUploadedFile:
449 def _get_file_from_url(self, url: str) -> SimpleUploadedFile:
449 """
450 """
450 Gets an file file from URL.
451 Gets an file file from URL.
451 """
452 """
452
453
453 try:
454 try:
454 return download(url)
455 return download(url)
455 except forms.ValidationError as e:
456 except forms.ValidationError as e:
456 raise e
457 raise e
457 except Exception as e:
458 except Exception as e:
458 raise forms.ValidationError(e)
459 raise forms.ValidationError(e)
459
460
460 def _validate_hash(self, timestamp: str, iteration: str, guess: str, message: str):
461 def _validate_hash(self, timestamp: str, iteration: str, guess: str, message: str):
461 payload = timestamp + message.replace('\r\n', '\n')
462 payload = timestamp + message.replace('\r\n', '\n')
462 difficulty = board_settings.get_int(SECTION_FORMS, 'PowDifficulty')
463 difficulty = board_settings.get_int(SECTION_FORMS, 'PowDifficulty')
463 target = str(int(2 ** (POW_HASH_LENGTH * 3) / difficulty))
464 target = str(int(2 ** (POW_HASH_LENGTH * 3) / difficulty))
464 if len(target) < POW_HASH_LENGTH:
465 if len(target) < POW_HASH_LENGTH:
465 target = '0' * (POW_HASH_LENGTH - len(target)) + target
466 target = '0' * (POW_HASH_LENGTH - len(target)) + target
466
467
467 computed_guess = hashlib.sha256((payload + iteration).encode())\
468 computed_guess = hashlib.sha256((payload + iteration).encode())\
468 .hexdigest()[0:POW_HASH_LENGTH]
469 .hexdigest()[0:POW_HASH_LENGTH]
469 if guess != computed_guess or guess > target:
470 if guess != computed_guess or guess > target:
470 self._add_general_error(_('Invalid PoW.'))
471 self._add_general_error(_('Invalid PoW.'))
471
472
472 def _check_file_duplicates(self, files):
473 def _check_file_duplicates(self, files):
473 for file in files:
474 for file in files:
474 file_hash = utils.get_file_hash(file)
475 file_hash = utils.get_file_hash(file)
475 if Attachment.objects.get_existing_duplicate(file_hash, file):
476 if Attachment.objects.get_existing_duplicate(file_hash, file):
476 self._add_general_error(_(ERROR_DUPLICATES))
477 self._add_general_error(_(ERROR_DUPLICATES))
477
478
478 def _add_general_error(self, message):
479 def _add_general_error(self, message):
479 self.add_error('text', forms.ValidationError(message))
480 self.add_error('text', forms.ValidationError(message))
480
481
481
482
482 class ThreadForm(PostForm):
483 class ThreadForm(PostForm):
483
484
484 tags = forms.CharField(
485 tags = forms.CharField(
485 widget=forms.TextInput(attrs={ATTRIBUTE_PLACEHOLDER: TAGS_PLACEHOLDER}),
486 widget=forms.TextInput(attrs={ATTRIBUTE_PLACEHOLDER: TAGS_PLACEHOLDER}),
486 max_length=100, label=_('Tags'), required=True)
487 max_length=100, label=_('Tags'), required=True)
487 monochrome = forms.BooleanField(label=_('Monochrome'), required=False)
488 monochrome = forms.BooleanField(label=_('Monochrome'), required=False)
488 stickerpack = forms.BooleanField(label=_('Sticker Pack'), required=False)
489 stickerpack = forms.BooleanField(label=_('Sticker Pack'), required=False)
489
490
490 def clean_tags(self):
491 def clean_tags(self):
491 tags = self.cleaned_data['tags'].strip()
492 tags = self.cleaned_data['tags'].strip()
492
493
493 if not tags or not REGEX_TAGS.match(tags):
494 if not tags or not REGEX_TAGS.match(tags):
494 raise forms.ValidationError(
495 raise forms.ValidationError(
495 _('Inappropriate characters in tags.'))
496 _('Inappropriate characters in tags.'))
496
497
497 default_tag_name = board_settings.get(SECTION_FORMS, 'DefaultTag')\
498 default_tag_name = board_settings.get(SECTION_FORMS, 'DefaultTag')\
498 .strip().lower()
499 .strip().lower()
499
500
500 required_tag_exists = False
501 required_tag_exists = False
501 tag_set = set()
502 tag_set = set()
502 for tag_string in tags.split():
503 for tag_string in tags.split():
503 tag_name = tag_string.strip().lower()
504 tag_name = tag_string.strip().lower()
504 if tag_name == default_tag_name:
505 if tag_name == default_tag_name:
505 required_tag_exists = True
506 required_tag_exists = True
506 tag, created = Tag.objects.get_or_create_with_alias(
507 tag, created = Tag.objects.get_or_create_with_alias(
507 name=tag_name, required=True)
508 name=tag_name, required=True)
508 else:
509 else:
509 tag, created = Tag.objects.get_or_create_with_alias(name=tag_name)
510 tag, created = Tag.objects.get_or_create_with_alias(name=tag_name)
510 tag_set.add(tag)
511 tag_set.add(tag)
511
512
512 # If this is a new tag, don't check for its parents because nobody
513 # If this is a new tag, don't check for its parents because nobody
513 # added them yet
514 # added them yet
514 if not created:
515 if not created:
515 tag_set |= set(tag.get_all_parents())
516 tag_set |= set(tag.get_all_parents())
516
517
517 for tag in tag_set:
518 for tag in tag_set:
518 if tag.required:
519 if tag.required:
519 required_tag_exists = True
520 required_tag_exists = True
520 break
521 break
521
522
522 # Use default tag if no section exists
523 # Use default tag if no section exists
523 if not required_tag_exists:
524 if not required_tag_exists:
524 default_tag, created = Tag.objects.get_or_create_with_alias(
525 default_tag, created = Tag.objects.get_or_create_with_alias(
525 name=default_tag_name, required=True)
526 name=default_tag_name, required=True)
526 tag_set.add(default_tag)
527 tag_set.add(default_tag)
527
528
528 return tag_set
529 return tag_set
529
530
530 def clean(self):
531 def clean(self):
531 cleaned_data = super(ThreadForm, self).clean()
532 cleaned_data = super(ThreadForm, self).clean()
532
533
533 return cleaned_data
534 return cleaned_data
534
535
535 def is_monochrome(self):
536 def is_monochrome(self):
536 return self.cleaned_data['monochrome']
537 return self.cleaned_data['monochrome']
537
538
538 def clean_stickerpack(self):
539 def clean_stickerpack(self):
539 stickerpack = self.cleaned_data['stickerpack']
540 stickerpack = self.cleaned_data['stickerpack']
540 if stickerpack:
541 if stickerpack:
541 tripcode = self.get_tripcode()
542 tripcode = self.get_tripcode()
542 if not tripcode:
543 if not tripcode:
543 raise forms.ValidationError(_(
544 raise forms.ValidationError(_(
544 'Tripcode should be specified to own a stickerpack.'))
545 'Tripcode should be specified to own a stickerpack.'))
545 title = self.get_title()
546 title = self.get_title()
546 if not title:
547 if not title:
547 raise forms.ValidationError(_(
548 raise forms.ValidationError(_(
548 'Title should be specified as a stickerpack name.'))
549 'Title should be specified as a stickerpack name.'))
549 if not REGEX_TAGS.match(title):
550 if not REGEX_TAGS.match(title):
550 raise forms.ValidationError(_('Inappropriate sticker pack name.'))
551 raise forms.ValidationError(_('Inappropriate sticker pack name.'))
551
552
552 existing_pack = StickerPack.objects.filter(name=title).first()
553 existing_pack = StickerPack.objects.filter(name=title).first()
553 if existing_pack:
554 if existing_pack:
554 if existing_pack.tripcode != tripcode:
555 if existing_pack.tripcode != tripcode:
555 raise forms.ValidationError(_(
556 raise forms.ValidationError(_(
556 'A sticker pack with this name already exists and is'
557 'A sticker pack with this name already exists and is'
557 ' owned by another tripcode.'))
558 ' owned by another tripcode.'))
558 if not existing_pack.tripcode:
559 if not existing_pack.tripcode:
559 raise forms.ValidationError(_(
560 raise forms.ValidationError(_(
560 'This sticker pack can only be updated by an '
561 'This sticker pack can only be updated by an '
561 'administrator.'))
562 'administrator.'))
562
563
563 return stickerpack
564 return stickerpack
564
565
565 def is_stickerpack(self):
566 def is_stickerpack(self):
566 return self.cleaned_data['stickerpack']
567 return self.cleaned_data['stickerpack']
567
568
568
569
569 class SettingsForm(NeboardForm):
570 class SettingsForm(NeboardForm):
570
571
571 theme = forms.ChoiceField(
572 theme = forms.ChoiceField(
572 choices=board_settings.get_list_dict('View', 'Themes'),
573 choices=board_settings.get_list_dict('View', 'Themes'),
573 label=_('Theme'))
574 label=_('Theme'))
574 image_viewer = forms.ChoiceField(
575 image_viewer = forms.ChoiceField(
575 choices=board_settings.get_list_dict('View', 'ImageViewers'),
576 choices=board_settings.get_list_dict('View', 'ImageViewers'),
576 label=_('Image view mode'))
577 label=_('Image view mode'))
577 username = forms.CharField(label=_('User name'), required=False)
578 username = forms.CharField(label=_('User name'), required=False)
578 timezone = forms.ChoiceField(choices=get_timezones(), label=_('Time zone'))
579 timezone = forms.ChoiceField(choices=get_timezones(), label=_('Time zone'))
579
580
580 def clean_username(self):
581 def clean_username(self):
581 username = self.cleaned_data['username']
582 username = self.cleaned_data['username']
582
583
583 if username and not REGEX_USERNAMES.match(username):
584 if username and not REGEX_USERNAMES.match(username):
584 raise forms.ValidationError(_('Inappropriate characters.'))
585 raise forms.ValidationError(_('Inappropriate characters.'))
585
586
586 return username
587 return username
587
588
588
589
589 class SearchForm(NeboardForm):
590 class SearchForm(NeboardForm):
590 query = forms.CharField(max_length=500, label=LABEL_SEARCH, required=False)
591 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,642 +1,645 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/thread.html:14
427 #: templates/boards/thread.html:14
428 msgid "Normal"
428 msgid "Normal"
429 msgstr "Нормальный"
429 msgstr "Нормальный"
430
430
431 #: templates/boards/thread.html:15
431 #: templates/boards/thread.html:15
432 msgid "Gallery"
432 msgid "Gallery"
433 msgstr "Галерея"
433 msgstr "Галерея"
434
434
435 #: templates/boards/thread.html:16
435 #: templates/boards/thread.html:16
436 msgid "Tree"
436 msgid "Tree"
437 msgstr "Дерево"
437 msgstr "Дерево"
438
438
439 #: templates/boards/thread.html:35
439 #: templates/boards/thread.html:35
440 msgid "message"
440 msgid "message"
441 msgid_plural "messages"
441 msgid_plural "messages"
442 msgstr[0] "сообщение"
442 msgstr[0] "сообщение"
443 msgstr[1] "сообщения"
443 msgstr[1] "сообщения"
444 msgstr[2] "сообщений"
444 msgstr[2] "сообщений"
445
445
446 #: templates/boards/thread.html:38
446 #: templates/boards/thread.html:38
447 msgid "image"
447 msgid "image"
448 msgid_plural "images"
448 msgid_plural "images"
449 msgstr[0] "изображение"
449 msgstr[0] "изображение"
450 msgstr[1] "изображения"
450 msgstr[1] "изображения"
451 msgstr[2] "изображений"
451 msgstr[2] "изображений"
452
452
453 #: templates/boards/thread.html:40
453 #: templates/boards/thread.html:40
454 msgid "Last update: "
454 msgid "Last update: "
455 msgstr "Последнее обновление: "
455 msgstr "Последнее обновление: "
456
456
457 #: templates/boards/thread_gallery.html:36
457 #: templates/boards/thread_gallery.html:36
458 msgid "No images."
458 msgid "No images."
459 msgstr "Нет изображений."
459 msgstr "Нет изображений."
460
460
461 #: templates/boards/thread_normal.html:30
461 #: templates/boards/thread_normal.html:30
462 msgid "posts to bumplimit"
462 msgid "posts to bumplimit"
463 msgstr "сообщений до бамплимита"
463 msgstr "сообщений до бамплимита"
464
464
465 #: templates/boards/thread_normal.html:44
465 #: templates/boards/thread_normal.html:44
466 msgid "Reply to thread"
466 msgid "Reply to thread"
467 msgstr "Ответить в тему"
467 msgstr "Ответить в тему"
468
468
469 #: templates/boards/thread_normal.html:44
469 #: templates/boards/thread_normal.html:44
470 msgid "to message "
470 msgid "to message "
471 msgstr "на сообщение"
471 msgstr "на сообщение"
472
472
473 #: templates/boards/thread_normal.html:59
473 #: templates/boards/thread_normal.html:59
474 msgid "Reset form"
474 msgid "Reset form"
475 msgstr "Сбросить форму"
475 msgstr "Сбросить форму"
476
476
477 #: templates/search/search.html:17
477 #: templates/search/search.html:17
478 msgid "Ok"
478 msgid "Ok"
479 msgstr "Ок"
479 msgstr "Ок"
480
480
481 #: utils.py:120
481 #: utils.py:120
482 #, python-format
482 #, python-format
483 msgid "File must be less than %s but is %s."
483 msgid "File must be less than %s but is %s."
484 msgstr "Файл должен быть менее %s, но его размер %s."
484 msgstr "Файл должен быть менее %s, но его размер %s."
485
485
486 msgid "Please wait %(delay)d second before sending message"
486 msgid "Please wait %(delay)d second before sending message"
487 msgid_plural "Please wait %(delay)d seconds before sending message"
487 msgid_plural "Please wait %(delay)d seconds before sending message"
488 msgstr[0] "Пожалуйста подождите %(delay)d секунду перед отправкой сообщения"
488 msgstr[0] "Пожалуйста подождите %(delay)d секунду перед отправкой сообщения"
489 msgstr[1] "Пожалуйста подождите %(delay)d секунды перед отправкой сообщения"
489 msgstr[1] "Пожалуйста подождите %(delay)d секунды перед отправкой сообщения"
490 msgstr[2] "Пожалуйста подождите %(delay)d секунд перед отправкой сообщения"
490 msgstr[2] "Пожалуйста подождите %(delay)d секунд перед отправкой сообщения"
491
491
492 msgid "New threads"
492 msgid "New threads"
493 msgstr "Новые темы"
493 msgstr "Новые темы"
494
494
495 #, python-format
495 #, python-format
496 msgid "Max file size is %(size)s."
496 msgid "Max file size is %(size)s."
497 msgstr "Максимальный размер файла %(size)s."
497 msgstr "Максимальный размер файла %(size)s."
498
498
499 msgid "Size of media:"
499 msgid "Size of media:"
500 msgstr "Размер медиа:"
500 msgstr "Размер медиа:"
501
501
502 msgid "Statistics"
502 msgid "Statistics"
503 msgstr "Статистика"
503 msgstr "Статистика"
504
504
505 msgid "Invalid PoW."
505 msgid "Invalid PoW."
506 msgstr "Неверный PoW."
506 msgstr "Неверный PoW."
507
507
508 msgid "Stale PoW."
508 msgid "Stale PoW."
509 msgstr "PoW устарел."
509 msgstr "PoW устарел."
510
510
511 msgid "Show"
511 msgid "Show"
512 msgstr "Показывать"
512 msgstr "Показывать"
513
513
514 msgid "Hide"
514 msgid "Hide"
515 msgstr "Скрывать"
515 msgstr "Скрывать"
516
516
517 msgid "Add to favorites"
517 msgid "Add to favorites"
518 msgstr "Добавить в избранное"
518 msgstr "Добавить в избранное"
519
519
520 msgid "Remove from favorites"
520 msgid "Remove from favorites"
521 msgstr "Убрать из избранного"
521 msgstr "Убрать из избранного"
522
522
523 msgid "Monochrome"
523 msgid "Monochrome"
524 msgstr "Монохромный"
524 msgstr "Монохромный"
525
525
526 msgid "Subsections: "
526 msgid "Subsections: "
527 msgstr "Подразделы: "
527 msgstr "Подразделы: "
528
528
529 msgid "Change file source"
529 msgid "Change file source"
530 msgstr "Изменить источник файла"
530 msgstr "Изменить источник файла"
531
531
532 msgid "interesting"
532 msgid "interesting"
533 msgstr "интересное"
533 msgstr "интересное"
534
534
535 msgid "images"
535 msgid "images"
536 msgstr "изображения"
536 msgstr "изображения"
537
537
538 msgid "Delete post"
538 msgid "Delete post"
539 msgstr "Удалить пост"
539 msgstr "Удалить пост"
540
540
541 msgid "Delete thread"
541 msgid "Delete thread"
542 msgstr "Удалить тему"
542 msgstr "Удалить тему"
543
543
544 msgid "Messages per day/week/month:"
544 msgid "Messages per day/week/month:"
545 msgstr "Сообщений за день/неделю/месяц:"
545 msgstr "Сообщений за день/неделю/месяц:"
546
546
547 msgid "Subscribe to thread"
547 msgid "Subscribe to thread"
548 msgstr "Подписаться на тему"
548 msgstr "Подписаться на тему"
549
549
550 msgid "Active threads:"
550 msgid "Active threads:"
551 msgstr "Активные темы:"
551 msgstr "Активные темы:"
552
552
553 msgid "No active threads today."
553 msgid "No active threads today."
554 msgstr "Сегодня нет активных тем."
554 msgstr "Сегодня нет активных тем."
555
555
556 msgid "Insert URLs on separate lines."
556 msgid "Insert URLs on separate lines."
557 msgstr "Вставляйте ссылки на отдельных строках."
557 msgstr "Вставляйте ссылки на отдельных строках."
558
558
559 msgid "You can post no more than %(files)d file."
559 msgid "You can post no more than %(files)d file."
560 msgid_plural "You can post no more than %(files)d files."
560 msgid_plural "You can post no more than %(files)d files."
561 msgstr[0] "Вы можете отправить не более %(files)d файла."
561 msgstr[0] "Вы можете отправить не более %(files)d файла."
562 msgstr[1] "Вы можете отправить не более %(files)d файлов."
562 msgstr[1] "Вы можете отправить не более %(files)d файлов."
563 msgstr[2] "Вы можете отправить не более %(files)d файлов."
563 msgstr[2] "Вы можете отправить не более %(files)d файлов."
564
564
565 #, python-format
565 #, python-format
566 msgid "Max file number is %(max_files)s."
566 msgid "Max file number is %(max_files)s."
567 msgstr "Максимальное количество файлов %(max_files)s."
567 msgstr "Максимальное количество файлов %(max_files)s."
568
568
569 msgid "Moderation"
569 msgid "Moderation"
570 msgstr "Модерация"
570 msgstr "Модерация"
571
571
572 msgid "Check for duplicates"
572 msgid "Check for duplicates"
573 msgstr "Проверять на дубликаты"
573 msgstr "Проверять на дубликаты"
574
574
575 msgid "Some files are already present on the board."
575 msgid "Some files are already present on the board."
576 msgstr "Некоторые файлы уже присутствуют на борде."
576 msgstr "Некоторые файлы уже присутствуют на борде."
577
577
578 msgid "Do not download URLs"
578 msgid "Do not download URLs"
579 msgstr "Не загружать ссылки"
579 msgstr "Не загружать ссылки"
580
580
581 msgid "Ban and delete"
581 msgid "Ban and delete"
582 msgstr "Забанить и удалить"
582 msgstr "Забанить и удалить"
583
583
584 msgid "Are you sure?"
584 msgid "Are you sure?"
585 msgstr "Вы уверены?"
585 msgstr "Вы уверены?"
586
586
587 msgid "Ban"
587 msgid "Ban"
588 msgstr "Забанить"
588 msgstr "Забанить"
589
589
590 msgid "URL download mode"
590 msgid "File process mode"
591 msgstr "Режим загрузки ссылок"
591 msgstr "Режим обработки файлов"
592
593 msgid "Download or insert as URLs"
594 msgstr "Загрузить или вставить как ссылки"
592
595
593 msgid "Download or add URL"
596 msgid "Download"
594 msgstr "Загрузить или добавить ссылку"
597 msgstr "Загрузить"
595
598
596 msgid "Download or fail"
599 msgid "Download and check for uniqueness"
597 msgstr "Загрузить или отказать"
600 msgstr "Загрузить и проверить на уникальность"
598
601
599 msgid "Insert as URLs"
602 msgid "Insert as URLs"
600 msgstr "Вставлять как ссылки"
603 msgstr "Вставить как ссылки"
601
604
602 msgid "Help"
605 msgid "Help"
603 msgstr "Справка"
606 msgstr "Справка"
604
607
605 msgid "View available stickers:"
608 msgid "View available stickers:"
606 msgstr "Просмотреть доступные стикеры:"
609 msgstr "Просмотреть доступные стикеры:"
607
610
608 msgid "Stickers"
611 msgid "Stickers"
609 msgstr "Стикеры"
612 msgstr "Стикеры"
610
613
611 msgid "Available by addresses:"
614 msgid "Available by addresses:"
612 msgstr "Доступно по адресам:"
615 msgstr "Доступно по адресам:"
613
616
614 msgid "Local stickers"
617 msgid "Local stickers"
615 msgstr "Локальные стикеры"
618 msgstr "Локальные стикеры"
616
619
617 msgid "Global stickers"
620 msgid "Global stickers"
618 msgstr "Глобальные стикеры"
621 msgstr "Глобальные стикеры"
619
622
620 msgid "Remove sticker"
623 msgid "Remove sticker"
621 msgstr "Удалить стикер"
624 msgstr "Удалить стикер"
622
625
623 msgid "Sticker Pack"
626 msgid "Sticker Pack"
624 msgstr "Набор Стикеров"
627 msgstr "Набор Стикеров"
625
628
626 msgid "Tripcode should be specified to own a stickerpack."
629 msgid "Tripcode should be specified to own a stickerpack."
627 msgstr "Для владения набором стикеров необходимо указать трипкод."
630 msgstr "Для владения набором стикеров необходимо указать трипкод."
628
631
629 msgid "Title should be specified as a stickerpack name."
632 msgid "Title should be specified as a stickerpack name."
630 msgstr "Заголовок должен быть указан в качестве имени набора стикеров."
633 msgstr "Заголовок должен быть указан в качестве имени набора стикеров."
631
634
632 msgid "A sticker pack with this name already exists and is owned by another tripcode."
635 msgid "A sticker pack with this name already exists and is owned by another tripcode."
633 msgstr "Набор стикеров с данным именем уже существует и принадлежит другому трипкоду."
636 msgstr "Набор стикеров с данным именем уже существует и принадлежит другому трипкоду."
634
637
635 msgid "This sticker pack can only be updated by an administrator."
638 msgid "This sticker pack can only be updated by an administrator."
636 msgstr "Этот набор стикеров может быть изменён только администратором."
639 msgstr "Этот набор стикеров может быть изменён только администратором."
637
640
638 msgid "To add a sticker, create a stickerpack thread using the title as a pack name, and a tripcode to own the pack. Then, add posts with title as a sticker name, and the same tripcode, to the thread. Their attachments would become stickers."
641 msgid "To add a sticker, create a stickerpack thread using the title as a pack name, and a tripcode to own the pack. Then, add posts with title as a sticker name, and the same tripcode, to the thread. Their attachments would become stickers."
639 msgstr "Чтобы добавить стикер, создайте тему-набор с заголовком в качестве названия набора стикеров, и трипкодом для подтверждения владения набором. Затем, добавляйте сообщения с заголовком в качестве имени стикера, и тем же трипкодомм. Их вложения станут стикерами."
642 msgstr "Чтобы добавить стикер, создайте тему-набор с заголовком в качестве названия набора стикеров, и трипкодом для подтверждения владения набором. Затем, добавляйте сообщения с заголовком в качестве имени стикера, и тем же трипкодомм. Их вложения станут стикерами."
640
643
641 msgid "Inappropriate sticker pack name."
644 msgid "Inappropriate sticker pack name."
642 msgstr "Недопустимое имя набора стикеров."
645 msgstr "Недопустимое имя набора стикеров."
1 NO CONTENT: modified file, binary diff hidden
NO CONTENT: modified file, binary diff hidden
@@ -1,642 +1,645 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/thread.html:14
427 #: templates/boards/thread.html:14
428 msgid "Normal"
428 msgid "Normal"
429 msgstr "Звичайний"
429 msgstr "Звичайний"
430
430
431 #: templates/boards/thread.html:15
431 #: templates/boards/thread.html:15
432 msgid "Gallery"
432 msgid "Gallery"
433 msgstr "Галерея"
433 msgstr "Галерея"
434
434
435 #: templates/boards/thread.html:16
435 #: templates/boards/thread.html:16
436 msgid "Tree"
436 msgid "Tree"
437 msgstr "Віник"
437 msgstr "Віник"
438
438
439 #: templates/boards/thread.html:35
439 #: templates/boards/thread.html:35
440 msgid "message"
440 msgid "message"
441 msgid_plural "messages"
441 msgid_plural "messages"
442 msgstr[0] "повідомлення"
442 msgstr[0] "повідомлення"
443 msgstr[1] "повідомлення"
443 msgstr[1] "повідомлення"
444 msgstr[2] "повідомлень"
444 msgstr[2] "повідомлень"
445
445
446 #: templates/boards/thread.html:38
446 #: templates/boards/thread.html:38
447 msgid "image"
447 msgid "image"
448 msgid_plural "images"
448 msgid_plural "images"
449 msgstr[0] "зображення"
449 msgstr[0] "зображення"
450 msgstr[1] "зображення"
450 msgstr[1] "зображення"
451 msgstr[2] "зображень"
451 msgstr[2] "зображень"
452
452
453 #: templates/boards/thread.html:40
453 #: templates/boards/thread.html:40
454 msgid "Last update: "
454 msgid "Last update: "
455 msgstr "Останнє оновлення: "
455 msgstr "Останнє оновлення: "
456
456
457 #: templates/boards/thread_gallery.html:36
457 #: templates/boards/thread_gallery.html:36
458 msgid "No images."
458 msgid "No images."
459 msgstr "Нема зображень."
459 msgstr "Нема зображень."
460
460
461 #: templates/boards/thread_normal.html:30
461 #: templates/boards/thread_normal.html:30
462 msgid "posts to bumplimit"
462 msgid "posts to bumplimit"
463 msgstr "повідомлень до бамплямату"
463 msgstr "повідомлень до бамплямату"
464
464
465 #: templates/boards/thread_normal.html:44
465 #: templates/boards/thread_normal.html:44
466 msgid "Reply to thread"
466 msgid "Reply to thread"
467 msgstr "Відповісти до нитки"
467 msgstr "Відповісти до нитки"
468
468
469 #: templates/boards/thread_normal.html:44
469 #: templates/boards/thread_normal.html:44
470 msgid "to message "
470 msgid "to message "
471 msgstr "на повідомлення"
471 msgstr "на повідомлення"
472
472
473 #: templates/boards/thread_normal.html:59
473 #: templates/boards/thread_normal.html:59
474 msgid "Reset form"
474 msgid "Reset form"
475 msgstr "Скинути форму"
475 msgstr "Скинути форму"
476
476
477 #: templates/search/search.html:17
477 #: templates/search/search.html:17
478 msgid "Ok"
478 msgid "Ok"
479 msgstr "Файно"
479 msgstr "Файно"
480
480
481 #: utils.py:120
481 #: utils.py:120
482 #, python-format
482 #, python-format
483 msgid "File must be less than %s but is %s."
483 msgid "File must be less than %s but is %s."
484 msgstr "Файл мусить бути менше %s, але його розмір %s."
484 msgstr "Файл мусить бути менше %s, але його розмір %s."
485
485
486 msgid "Please wait %(delay)d second before sending message"
486 msgid "Please wait %(delay)d second before sending message"
487 msgid_plural "Please wait %(delay)d seconds before sending message"
487 msgid_plural "Please wait %(delay)d seconds before sending message"
488 msgstr[0] "Зачекайте, будь ласка, %(delay)d секунду перед надсиланням повідомлення"
488 msgstr[0] "Зачекайте, будь ласка, %(delay)d секунду перед надсиланням повідомлення"
489 msgstr[1] "Зачекайте, будь ласка, %(delay)d секунди перед надсиланням повідомлення"
489 msgstr[1] "Зачекайте, будь ласка, %(delay)d секунди перед надсиланням повідомлення"
490 msgstr[2] "Зачекайте, будь ласка, %(delay)d секунд перед надсиланням повідомлення"
490 msgstr[2] "Зачекайте, будь ласка, %(delay)d секунд перед надсиланням повідомлення"
491
491
492 msgid "New threads"
492 msgid "New threads"
493 msgstr "Нові нитки"
493 msgstr "Нові нитки"
494
494
495 #, python-format
495 #, python-format
496 msgid "Max file size is %(size)s."
496 msgid "Max file size is %(size)s."
497 msgstr "Максимальний розмір файлу %(size)s."
497 msgstr "Максимальний розмір файлу %(size)s."
498
498
499 msgid "Size of media:"
499 msgid "Size of media:"
500 msgstr "Розмір посередника:"
500 msgstr "Розмір посередника:"
501
501
502 msgid "Statistics"
502 msgid "Statistics"
503 msgstr "Статистика"
503 msgstr "Статистика"
504
504
505 msgid "Invalid PoW."
505 msgid "Invalid PoW."
506 msgstr "Хибний PoW."
506 msgstr "Хибний PoW."
507
507
508 msgid "Stale PoW."
508 msgid "Stale PoW."
509 msgstr "PoW застарів."
509 msgstr "PoW застарів."
510
510
511 msgid "Show"
511 msgid "Show"
512 msgstr "Показувати"
512 msgstr "Показувати"
513
513
514 msgid "Hide"
514 msgid "Hide"
515 msgstr "Ховати"
515 msgstr "Ховати"
516
516
517 msgid "Add to favorites"
517 msgid "Add to favorites"
518 msgstr "Я це люблю"
518 msgstr "Я це люблю"
519
519
520 msgid "Remove from favorites"
520 msgid "Remove from favorites"
521 msgstr "Вже не люблю"
521 msgstr "Вже не люблю"
522
522
523 msgid "Monochrome"
523 msgid "Monochrome"
524 msgstr "Без барв"
524 msgstr "Без барв"
525
525
526 msgid "Subsections: "
526 msgid "Subsections: "
527 msgstr "Підрозділи: "
527 msgstr "Підрозділи: "
528
528
529 msgid "Change file source"
529 msgid "Change file source"
530 msgstr "Змінити джерело файлу"
530 msgstr "Змінити джерело файлу"
531
531
532 msgid "interesting"
532 msgid "interesting"
533 msgstr "цікаве"
533 msgstr "цікаве"
534
534
535 msgid "images"
535 msgid "images"
536 msgstr "пічкури"
536 msgstr "пічкури"
537
537
538 msgid "Delete post"
538 msgid "Delete post"
539 msgstr "Видалити повідомлення"
539 msgstr "Видалити повідомлення"
540
540
541 msgid "Delete thread"
541 msgid "Delete thread"
542 msgstr "Вирвати нитку"
542 msgstr "Вирвати нитку"
543
543
544 msgid "Messages per day/week/month:"
544 msgid "Messages per day/week/month:"
545 msgstr "Повідомлень за день/тиждень/тижмісяць:"
545 msgstr "Повідомлень за день/тиждень/тижмісяць:"
546
546
547 msgid "Subscribe to thread"
547 msgid "Subscribe to thread"
548 msgstr "Стежити за ниткою"
548 msgstr "Стежити за ниткою"
549
549
550 msgid "Active threads:"
550 msgid "Active threads:"
551 msgstr "Активні нитки:"
551 msgstr "Активні нитки:"
552
552
553 msgid "No active threads today."
553 msgid "No active threads today."
554 msgstr "Щось усі замовкли."
554 msgstr "Щось усі замовкли."
555
555
556 msgid "Insert URLs on separate lines."
556 msgid "Insert URLs on separate lines."
557 msgstr "Вставляйте посилання окремими рядками."
557 msgstr "Вставляйте посилання окремими рядками."
558
558
559 msgid "You can post no more than %(files)d file."
559 msgid "You can post no more than %(files)d file."
560 msgid_plural "You can post no more than %(files)d files."
560 msgid_plural "You can post no more than %(files)d files."
561 msgstr[0] "Ви можете надіслати не більше %(files)d файлу."
561 msgstr[0] "Ви можете надіслати не більше %(files)d файлу."
562 msgstr[1] "Вы можете надіслати не більше %(files)d файлів."
562 msgstr[1] "Вы можете надіслати не більше %(files)d файлів."
563 msgstr[2] "Вы можете надіслати не більше %(files)d файлів."
563 msgstr[2] "Вы можете надіслати не більше %(files)d файлів."
564
564
565 #, python-format
565 #, python-format
566 msgid "Max file number is %(max_files)s."
566 msgid "Max file number is %(max_files)s."
567 msgstr "Максимальна кількість файлів %(max_files)s."
567 msgstr "Максимальна кількість файлів %(max_files)s."
568
568
569 msgid "Moderation"
569 msgid "Moderation"
570 msgstr "Модерація"
570 msgstr "Модерація"
571
571
572 msgid "Check for duplicates"
572 msgid "Check for duplicates"
573 msgstr "Перевіряти на дублікати"
573 msgstr "Перевіряти на дублікати"
574
574
575 msgid "Some files are already present on the board."
575 msgid "Some files are already present on the board."
576 msgstr "Деякі файли вже є на дошці."
576 msgstr "Деякі файли вже є на дошці."
577
577
578 msgid "Do not download URLs"
578 msgid "Do not download URLs"
579 msgstr "Не завантажувати посилання"
579 msgstr "Не завантажувати посилання"
580
580
581 msgid "Ban and delete"
581 msgid "Ban and delete"
582 msgstr "Заблокувати й видалити"
582 msgstr "Заблокувати й видалити"
583
583
584 msgid "Are you sure?"
584 msgid "Are you sure?"
585 msgstr "Чи ви певні?"
585 msgstr "Чи ви певні?"
586
586
587 msgid "Ban"
587 msgid "Ban"
588 msgstr "Заблокувати"
588 msgstr "Заблокувати"
589
589
590 msgid "URL download mode"
590 msgid "File process mode"
591 msgstr "Режим завантаження посилань"
591 msgstr "Режим обробки файлів"
592
593 msgid "Download or insert as URLs"
594 msgstr "Завантажити або вставити як посилання"
592
595
593 msgid "Download or add URL"
596 msgid "Download"
594 msgstr "Завантажити або додати посилання"
597 msgstr "Завантажити"
595
598
596 msgid "Download or fail"
599 msgid "Download and check for uniqueness"
597 msgstr "Завантажити або відмовити"
600 msgstr "Завантажити та перевірити на унікальність"
598
601
599 msgid "Insert as URLs"
602 msgid "Insert as URLs"
600 msgstr "Вставляти як посилання"
603 msgstr "Вставити як посилання"
601
604
602 msgid "Help"
605 msgid "Help"
603 msgstr "Справка"
606 msgstr "Справка"
604
607
605 msgid "View available stickers:"
608 msgid "View available stickers:"
606 msgstr "Передивитися доступні стікери:"
609 msgstr "Передивитися доступні стікери:"
607
610
608 msgid "Stickers"
611 msgid "Stickers"
609 msgstr "Стікери"
612 msgstr "Стікери"
610
613
611 msgid "Available by addresses:"
614 msgid "Available by addresses:"
612 msgstr "Доступно за адресами:"
615 msgstr "Доступно за адресами:"
613
616
614 msgid "Local stickers"
617 msgid "Local stickers"
615 msgstr "Локальні стікери"
618 msgstr "Локальні стікери"
616
619
617 msgid "Global stickers"
620 msgid "Global stickers"
618 msgstr "Глобальні стікери"
621 msgstr "Глобальні стікери"
619
622
620 msgid "Remove sticker"
623 msgid "Remove sticker"
621 msgstr "Видалити стікер"
624 msgstr "Видалити стікер"
622
625
623 msgid "Sticker Pack"
626 msgid "Sticker Pack"
624 msgstr "Набір Стікерів"
627 msgstr "Набір Стікерів"
625
628
626 msgid "Tripcode should be specified to own a stickerpack."
629 msgid "Tripcode should be specified to own a stickerpack."
627 msgstr "Для володіння набором стікерів необхідно вказати тріпкод."
630 msgstr "Для володіння набором стікерів необхідно вказати тріпкод."
628
631
629 msgid "Title should be specified as a stickerpack name."
632 msgid "Title should be specified as a stickerpack name."
630 msgstr "Заголовок повинен бути вказаний в якості імені набору стікерів."
633 msgstr "Заголовок повинен бути вказаний в якості імені набору стікерів."
631
634
632 msgid "A sticker pack with this name already exists and is owned by another tripcode."
635 msgid "A sticker pack with this name already exists and is owned by another tripcode."
633 msgstr "Набір стікерів з вказаним іменем вже є в наявності та належить іншому тріпкоду."
636 msgstr "Набір стікерів з вказаним іменем вже є в наявності та належить іншому тріпкоду."
634
637
635 msgid "This sticker pack can only be updated by an administrator."
638 msgid "This sticker pack can only be updated by an administrator."
636 msgstr "Цей набір стікерів може бути змінений лише адміністратором."
639 msgstr "Цей набір стікерів може бути змінений лише адміністратором."
637
640
638 msgid "To add a sticker, create a stickerpack thread using the title as a pack name, and a tripcode to own the pack. Then, add posts with title as a sticker name, and the same tripcode, to the thread. Their attachments would become stickers."
641 msgid "To add a sticker, create a stickerpack thread using the title as a pack name, and a tripcode to own the pack. Then, add posts with title as a sticker name, and the same tripcode, to the thread. Their attachments would become stickers."
639 msgstr "Щоб додати стікер, створіть тему-набір з заголовком у якості набору стікерів, та тріпкодом для підтвердження володіння наборомт. Потім, додавайте повідомлення з заголовком у якості імені стікеру та з тим самим тріпкодом. Їхні вкладення станут стікерами."
642 msgstr "Щоб додати стікер, створіть тему-набір з заголовком у якості набору стікерів, та тріпкодом для підтвердження володіння наборомт. Потім, додавайте повідомлення з заголовком у якості імені стікеру та з тим самим тріпкодом. Їхні вкладення станут стікерами."
640
643
641 msgid "Inappropriate sticker pack name."
644 msgid "Inappropriate sticker pack name."
642 msgstr "Неприпустиме ім'я набору стікерів."
645 msgstr "Неприпустиме ім'я набору стікерів."
General Comments 0
You need to be logged in to leave comments. Login now