Version bump

This commit is contained in:
Neil Lalonde 2016-05-26 11:51:58 -04:00
commit 9558393e7b
125 changed files with 1503 additions and 590 deletions

View File

@ -32,7 +32,8 @@ rvm:
services:
- redis-server
sudo: false
sudo: required
dist: trusty
cache:
directories:

View File

@ -105,8 +105,8 @@ gem 'sidekiq-statistic'
# for sidekiq web
gem 'sinatra', require: false
gem 'therubyracer'
gem 'execjs', require: false
gem 'mini_racer'
gem 'thin', require: false
gem 'highline', require: false
gem 'rack-protection' # security

View File

@ -38,16 +38,16 @@ GEM
minitest (~> 5.1)
thread_safe (~> 0.3, >= 0.3.4)
tzinfo (~> 1.1)
annotate (2.7.0)
annotate (2.7.1)
activerecord (>= 3.2, < 6.0)
rake (~> 10.4)
rake (>= 10.4, < 12.0)
arel (6.0.3)
aws-sdk (2.2.9)
aws-sdk-resources (= 2.2.9)
aws-sdk-core (2.2.9)
aws-sdk (2.3.7)
aws-sdk-resources (= 2.3.7)
aws-sdk-core (2.3.7)
jmespath (~> 1.0)
aws-sdk-resources (2.2.9)
aws-sdk-core (= 2.2.9)
aws-sdk-resources (2.3.7)
aws-sdk-core (= 2.3.7)
babel-source (5.8.34)
babel-transpiler (0.7.0)
babel-source (>= 4.0, < 6)
@ -94,7 +94,7 @@ GEM
erubis (2.7.0)
eventmachine (1.2.0.1)
excon (0.45.4)
execjs (2.6.0)
execjs (2.7.0)
exifr (1.2.4)
fabrication (2.9.8)
fakeweb (1.3.0)
@ -108,7 +108,7 @@ GEM
fast_xs (0.8.0)
ffi (1.9.10)
flamegraph (0.9.5)
foreman (0.78.0)
foreman (0.82.0)
thor (~> 0.19.1)
fspath (2.1.1)
gctools (0.2.3)
@ -117,7 +117,7 @@ GEM
globalid (0.3.6)
activesupport (>= 4.1.0)
guess_html_encoding (0.0.11)
hashie (3.4.3)
hashie (3.4.4)
highline (1.7.8)
hiredis (0.6.1)
htmlentities (4.3.4)
@ -133,18 +133,20 @@ GEM
progress (~> 3.0, >= 3.0.1)
image_size (1.4.1)
in_threads (1.3.1)
jmespath (1.1.3)
jmespath (1.2.4)
json_pure (>= 1.8.1)
jquery-rails (4.0.5)
rails-dom-testing (~> 1.0)
railties (>= 4.2.0)
thor (>= 0.14, < 2.0)
json (1.8.3)
json_pure (1.8.3)
jwt (1.5.2)
kgio (2.10.0)
librarian (0.1.2)
highline
thor (~> 0.15)
libv8 (3.16.14.13)
libv8 (5.0.71.48.3)
listen (0.7.3)
logster (1.2.3)
loofah (2.0.3)
@ -159,12 +161,14 @@ GEM
method_source (0.8.2)
mime-types (2.99.1)
mini_portile2 (2.1.0)
minitest (5.8.4)
mini_racer (0.1.3)
libv8 (~> 5.0)
minitest (5.9.0)
mocha (1.1.0)
metaclass (~> 0.0.1)
mock_redis (0.15.4)
moneta (0.8.0)
msgpack (0.7.4)
msgpack (0.7.6)
multi_json (1.11.2)
multi_xml (0.5.5)
multipart-post (2.0.0)
@ -211,7 +215,7 @@ GEM
omniauth-twitter (1.2.1)
json (~> 1.3)
omniauth-oauth (~> 1.1)
onebox (1.5.39)
onebox (1.5.41)
htmlentities (~> 4.3.4)
moneta (~> 0.8)
multi_json (~> 1.11)
@ -270,26 +274,25 @@ GEM
activesupport (= 4.2.6)
rake (>= 0.8.7)
thor (>= 0.18.1, < 2.0)
raindrops (0.15.0)
rake (10.5.0)
raindrops (0.16.0)
rake (11.1.2)
rake-compiler (0.9.9)
rake
rb-fsevent (0.9.7)
rb-inotify (0.9.5)
rb-inotify (0.9.7)
ffi (>= 0.5.0)
rbtrace (0.4.7)
rbtrace (0.4.8)
ffi (>= 1.0.6)
msgpack (>= 0.4.3)
trollop (>= 1.16.2)
redis (3.3.0)
redis-namespace (1.5.2)
redis (~> 3.0, >= 3.0.4)
ref (2.0.0)
rest-client (1.8.0)
http-cookie (>= 1.0.2, < 2.0)
mime-types (>= 1.16, < 3.0)
netrc (~> 0.7)
rinku (1.7.3)
rinku (2.0.0)
rmmseg-cpp (0.2.9)
rspec (3.2.0)
rspec-core (~> 3.2.0)
@ -373,9 +376,6 @@ GEM
activesupport (>= 4.0)
sprockets (>= 3.0.0)
stackprof (0.2.9)
therubyracer (0.12.2)
libv8 (~> 3.16.14.0)
ref
thin (1.6.4)
daemons (~> 1.0, >= 1.0.9)
eventmachine (~> 1.0, >= 1.0.4)
@ -387,15 +387,13 @@ GEM
trollop (2.1.2)
tzinfo (1.2.2)
thread_safe (~> 0.1)
uglifier (2.7.2)
execjs (>= 0.3.0)
json (>= 1.8.0)
uglifier (3.0.0)
execjs (>= 0.3.0, < 3)
unf (0.1.4)
unf_ext
unf_ext (0.0.7.1)
unicorn (5.0.1)
unicorn (5.1.0)
kgio (~> 2.6)
rack
raindrops (~> 0.7)
PLATFORMS
@ -417,6 +415,7 @@ DEPENDENCIES
ember-rails (= 0.18.5)
ember-source (= 1.12.2)
excon
execjs
fabrication (= 2.9.8)
fakeweb (~> 1.3.0)
fast_blank
@ -439,6 +438,7 @@ DEPENDENCIES
memory_profiler
message_bus (= 2.0.0.beta.11)
mime-types
mini_racer
minitest
mocha
mock_redis
@ -493,7 +493,6 @@ DEPENDENCIES
sinatra
spork-rails
stackprof
therubyracer
thin
timecop
uglifier

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 434 B

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 216 B

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 412 B

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 600 B

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 655 B

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 834 B

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 272 B

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 415 B

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 225 B

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

@ -29,7 +29,10 @@
&mdash;
{{/if}}
</td>
<td><a href='mailto:{{unbound l.to_address}}'>{{l.to_address}}</a></td>
<td>
{{#if l.bounced}}{{fa-icon "repeat" title="admin.email.bounced"}}{{/if}}
<a href='mailto:{{unbound l.to_address}}'>{{l.to_address}}</a>
</td>
<td>{{l.email_type}}</td>
<td class='post-link'>
{{#if l.post_url}}

View File

@ -62,6 +62,24 @@ export default Ember.Controller.extend(CanCheckEmails, {
return this.siteSettings.available_locales.split('|').map(s => ({ name: s, value: s }));
},
@computed()
frequencyEstimate() {
var estimate = this.get('model.mailing_list_posts_per_day');
if (!estimate || estimate < 2) {
return I18n.t('user.mailing_list_mode.few_per_day');
} else {
return I18n.t('user.mailing_list_mode.many_per_day', { dailyEmailEstimate: estimate });
}
},
@computed()
mailingListModeOptions() {
return [
{name: I18n.t('user.mailing_list_mode.daily'), value: 0},
{name: this.get('frequencyEstimate'), value: 1}
];
},
previousRepliesOptions: [
{name: I18n.t('user.email_previous_replies.always'), value: 0},
{name: I18n.t('user.email_previous_replies.unless_emailed'), value: 1},
@ -116,13 +134,12 @@ export default Ember.Controller.extend(CanCheckEmails, {
Em.run.next(()=>{
const postsPerDay = this.get('model.mailing_list_posts_per_day');
if (!postsPerDay || postsPerDay < 2) {
this.set('model.user_option.mailing_list_mode', true);
return;
return true;
}
bootbox.confirm(I18n.t("user.enable_mailing_list", {count: postsPerDay}), I18n.t("no_value"), I18n.t("yes_value"), (success) => {
if (success) {
this.set('model.user_option.mailing_list_mode', true);
if (!success) {
this.set('model.user_option.mailing_list_mode', false);
}
});
});

View File

@ -12,6 +12,7 @@ export function iconHTML(icon, params) {
params = params || {};
var html = "<i class='" + iconClasses(icon, params) + "'";
if (params.title) { html += ` title='${I18n.t(params.title)}'`; }
if (params.label) { html += " aria-hidden='true'"; }
html += "></i>";
if (params.label) {

View File

@ -15,6 +15,7 @@ const bindings = {
'd': {postAction: 'deletePost'},
'e': {postAction: 'editPost'},
'end': {handler: 'goToLastPost', anonymous: true},
'command+down': {handler: 'goToLastPost', anonymous: true},
'f': {handler: 'toggleBookmarkTopic'},
'g h': {path: '/', anonymous: true},
'g l': {path: '/latest', anonymous: true},
@ -26,6 +27,7 @@ const bindings = {
'g p': {path: '/my/activity'},
'g m': {path: '/my/messages'},
'home': {handler: 'goToFirstPost', anonymous: true},
'command+up': {handler: 'goToFirstPost', anonymous: true},
'j': {handler: 'selectDown', anonymous: true},
'k': {handler: 'selectUp', anonymous: true},
'l': {click: '.topic-post.selected button.toggle-like'},

View File

@ -124,6 +124,9 @@ export default class {
const postNumbers = Object.keys(newTimings).map(v => parseInt(v, 10));
controller.readPosts(topicId, postNumbers);
}
}).catch(e => {
const error = e.jqXHR;
if (error.status === 405 && error.responseJSON.error_type === "read_only") return;
});
} else if (this._anonCallback) {
// Anonymous viewer - save to localStorage

View File

@ -269,7 +269,7 @@ Discourse.Utilities = {
// is Audio/Video
return Discourse.Utilities.uploadLocation(upload.url);
} else {
return '<a class="attachment" href="' + upload.url + '">' + upload.original_filename + '</a> (' + I18n.toHumanSize(upload.filesize) + ')';
return '<a class="attachment" href="' + upload.url + '">' + upload.original_filename + '</a> (' + I18n.toHumanSize(upload.filesize) + ')\n';
}
},

View File

@ -155,6 +155,7 @@ const User = RestModel.extend({
[ 'email_always',
'mailing_list_mode',
'mailing_list_mode_frequency',
'external_links_in_new_tab',
'email_digests',
'email_direct',

View File

@ -1,4 +1,4 @@
<label class='checkbox-label'>
{{input type="checkbox" checked=checked}}
{{input type="checkbox" disabled=disabled checked=checked}}
{{label}}
</label>

View File

@ -1,2 +1,2 @@
<a href {{action "closeMessage" this}} class='close'><i class='fa fa-times-circle'></i></a>
<a href {{action "closeMessage" this}} class='close'><i class='fa fa-close'></i></a>
{{{body}}}

View File

@ -1,4 +1,4 @@
<a href {{action "closeMessage" this}} class='close'>{{fa-icon "times-circle"}}</a>
<a href {{action "closeMessage" this}} class='close'>{{fa-icon "close"}}</a>
<h3>{{i18n 'composer.similar_topics'}}</h3>
<ul class='topics'>

View File

@ -15,6 +15,6 @@
{{/each}}
<div class='link'>
<a href {{action "close"}} aria-label='{{i18n 'share.close'}}' title='{{i18n 'share.close'}}'>{{fa-icon "times-circle"}}</a>
<a href {{action "close"}} aria-label='{{i18n 'share.close'}}' title='{{i18n 'share.close'}}'>{{fa-icon "close"}}</a>
</div>
{{/if}}

View File

@ -24,6 +24,7 @@
{{/if}}
{{#if canEditTags}}
<br>
{{tag-chooser tags=buffered.tags}}
{{/if}}

View File

@ -185,9 +185,6 @@
{{preference-checkbox labelKey="user.email_in_reply_to" checked=model.user_option.email_in_reply_to}}
{{preference-checkbox labelKey="user.email_private_messages" checked=model.user_option.email_private_messages}}
{{preference-checkbox labelKey="user.email_direct" checked=model.user_option.email_direct}}
{{#unless siteSettings.disable_mailing_list_mode}}
{{preference-checkbox warning="checkMailingList" labelKey="user.mailing_list_mode" checked=model.user_option.mailing_list_mode}}
{{/unless}}
{{preference-checkbox labelKey="user.email_always" checked=model.user_option.email_always}}
{{#unless model.user_option.email_always}}
<div class='instructions'>
@ -198,11 +195,33 @@
{{/if}}
</div>
{{/unless}}
</div>
<div class='control-group pref-activity-summary'>
<label class="control-label">{{i18n 'user.email_activity_summary'}}</label>
{{#if canReceiveDigest}}
{{preference-checkbox labelKey="user.email_digests.title" disabled=model.user_option.mailing_list_mode checked=model.user_option.email_digests}}
{{#if model.user_option.email_digests}}
<div class='controls controls-dropdown'>
{{combo-box valueAttribute="value" content=digestFrequencies value=model.user_option.digest_after_minutes}}
</div>
{{/if}}
{{/if}}
</div>
{{#unless siteSettings.disable_mailing_list_mode}}
<div class='control-group pref-mailing-list-mode'>
<label class="control-label">{{i18n 'user.mailing_list_mode.label'}}</label>
{{preference-checkbox labelKey="user.mailing_list_mode.enabled" warning="checkMailingList" checked=model.user_option.mailing_list_mode}}
<div class='instructions'>{{{i18n 'user.mailing_list_mode.instructions'}}}</div>
{{#if model.user_option.mailing_list_mode}}
<div class='controls controls-dropdown'>
{{combo-box valueAttribute="value" content=mailingListModeOptions value=model.user_option.mailing_list_mode_frequency}}
</div>
{{/if}}
</div>
{{/unless}}
<div class="control-group notifications">
<label class="control-label">{{i18n 'user.desktop_notifications.label'}}</label>
{{desktop-notification-config}}

View File

@ -83,12 +83,13 @@ a.loading-onebox {
@mixin onebox-favicon($class, $image) {
&.#{$class} .source {
background: image-url("favicons/#{$image}.png") no-repeat;
background-size: 16px 16px;
padding-left: 20px;
}
}
aside.onebox {
@include post-aside;
border: 5px solid dark-light-diff($primary, $secondary, 90%, -85%);
padding: 12px 25px 12px 12px;
font-size: 1em;

View File

@ -141,6 +141,10 @@ header .discourse-tag {color: $tag-color !important; }
margin: 5px 0;
}
.title-wrapper .tag-chooser {
width: 500px;
}
.admin-tag {
position: relative;
float: right;

View File

@ -448,7 +448,7 @@ a.star {
padding: 10px 10px 0 0;
p {
line-height: 32px;
color: $primary;
color: dark-light-choose(scale-color($primary, $lightness: 50%), scale-color($secondary, $lightness: 50%));
}
.btn {
margin-bottom: 5px;
@ -757,8 +757,16 @@ $topic-avatar-width: 45px;
border: 1px solid dark-light-diff($primary, $secondary, 90%, -60%);
box-shadow: 0 1px 5px rgba(0,0,0, .4);
background-clip: padding-box;
span {font-size: 0.857em;}
.title {font-weight: bold; display: block; font-size: 1em;}
span {
font-size: 0.857em;
color: dark-light-choose(scale-color($primary, $lightness: 50%), scale-color($secondary, $lightness: 50%));
}
span.title {
font-weight: bold;
display: block;
font-size: 1em;
color: $primary;
}
}
.dropdown-menu a {
display: block;

View File

@ -8,6 +8,10 @@
article.post {
border-bottom: 1px solid #ddd;
img.avatar {
border-radius: 50%;
}
&.deleted {
background-color: #ffe5e5;
}
@ -141,3 +145,18 @@ footer {
// load onebox CSS at the end
@import "./common/base/onebox";
// we apparently use bottom margins on paras in the embed CSS, leading to weirdness
// which we will now clean up
aside.onebox {
margin-bottom: 20px;
p {
margin-bottom: 0 !important;
}
}
// images large enough for the lightbox wrapper don't have bottom margins
// either, unless we add one now
div.lightbox-wrapper {
margin-bottom: 20px;
}

View File

@ -327,10 +327,11 @@ a.star {
}
}
/* this is to force the drop-down notification state description para below the button */
#topic-footer-buttons p {
clear: both;
clear: both; /* this is to force the drop-down notification state description para below the button */
margin: 0;
color: dark-light-choose(scale-color($primary, $lightness: 50%), scale-color($secondary, $lightness: 50%));
}
#suggested-topics {
@ -408,6 +409,12 @@ iframe {
margin-right: 5px;
padding-top: 1px;
}
span {
color: dark-light-choose(scale-color($primary, $lightness: 50%), scale-color($secondary, $lightness: 50%));
}
span.title {
color: $primary;
}
}
.btn-group {

View File

@ -544,7 +544,7 @@ class PostsController < ApplicationController
:reply_to_post_number,
:auto_track,
:typing_duration_msecs,
:composer_open_duration_msecs
:composer_open_duration_msecs,
]
# param munging for WordPress
@ -557,6 +557,10 @@ class PostsController < ApplicationController
# We allow `embed_url` via the API
permitted << :embed_url
# We allow `created_at` via the API
permitted << :created_at
end
params.require(:raw)

View File

@ -167,11 +167,11 @@ class TagsController < ::ApplicationController
parent_category_id = nil
if parent_slug_or_id.present?
parent_category_id = Category.query_parent_category(parent_slug_or_id)
raise Discourse::NotFound if parent_category_id.blank?
redirect_or_not_found and return if parent_category_id.blank?
end
@filter_on_category = Category.query_category(slug_or_id, parent_category_id)
raise Discourse::NotFound if !@filter_on_category
redirect_or_not_found and return if !@filter_on_category
guardian.ensure_can_see!(@filter_on_category)
end
@ -197,4 +197,17 @@ class TagsController < ::ApplicationController
options
end
def redirect_or_not_found
# automatic redirects for renamed categories
url = params[:parent_category] ? "c/#{params[:parent_category]}/#{params[:category]}" : "c/#{params[:category]}"
permalink = Permalink.find_by_url(url)
if permalink.present? && permalink.category_id
redirect_to "#{Discourse::base_uri}/tags#{permalink.target_url}/#{params[:tag_id]}", status: :moved_permanently
else
# redirect to 404
raise Discourse::NotFound
end
end
end

View File

@ -211,7 +211,6 @@ class UsersController < ApplicationController
def is_local_username
usernames = params[:usernames]
usernames = [params[:username]] if usernames.blank?
usernames.each(&:downcase!)
groups = Group.where(name: usernames).pluck(:name)
mentionable_groups =
@ -223,6 +222,7 @@ class UsersController < ApplicationController
end
usernames -= groups
usernames.each(&:downcase!)
result = User.where(staged: false)
.where(username_lower: usernames)

View File

@ -65,9 +65,9 @@ module UserNotificationsHelper
normalize_name(post.user.name) != normalize_name(post.user.username)
end
def format_for_email(post, use_excerpt)
def format_for_email(post, use_excerpt, style = nil)
html = use_excerpt ? post.excerpt : post.cooked
PrettyText.format_for_email(html, post).html_safe
PrettyText.format_for_email(html, post, style).html_safe
end
end

View File

@ -6,56 +6,76 @@ module Jobs
class ExportCsvFile < Jobs::Base
include ActionView::Helpers::NumberHelper
HEADER_ATTRS_FOR = {}
HEADER_ATTRS_FOR['user_archive'] = ['topic_title','category','sub_category','is_pm','post','like_count','reply_count','url','created_at']
HEADER_ATTRS_FOR['user_list'] = ['id','name','username','email','title','created_at','last_seen_at','last_posted_at','last_emailed_at','trust_level','approved','suspended_at','suspended_till','blocked','active','admin','moderator','ip_address']
HEADER_ATTRS_FOR['user_stats'] = ['topics_entered','posts_read_count','time_read','topic_count','post_count','likes_given','likes_received']
HEADER_ATTRS_FOR['user_sso'] = ['external_id','external_email', 'external_username', 'external_name', 'external_avatar_url']
HEADER_ATTRS_FOR['staff_action'] = ['staff_user','action','subject','created_at','details', 'context']
HEADER_ATTRS_FOR['screened_email'] = ['email','action','match_count','last_match_at','created_at','ip_address']
HEADER_ATTRS_FOR['screened_ip'] = ['ip_address','action','match_count','last_match_at','created_at']
HEADER_ATTRS_FOR['screened_url'] = ['domain','action','match_count','last_match_at','created_at']
HEADER_ATTRS_FOR['report'] = ['date', 'value']
sidekiq_options retry: false
attr_accessor :current_user
HEADER_ATTRS_FOR ||= HashWithIndifferentAccess.new({
user_archive: ['topic_title','category','sub_category','is_pm','post','like_count','reply_count','url','created_at'],
user_list: ['id','name','username','email','title','created_at','last_seen_at','last_posted_at','last_emailed_at','trust_level','approved','suspended_at','suspended_till','blocked','active','admin','moderator','ip_address'],
user_stats: ['topics_entered','posts_read_count','time_read','topic_count','post_count','likes_given','likes_received'],
user_sso: ['external_id','external_email', 'external_username', 'external_name', 'external_avatar_url'],
staff_action: ['staff_user','action','subject','created_at','details', 'context'],
screened_email: ['email','action','match_count','last_match_at','created_at','ip_address'],
screened_ip: ['ip_address','action','match_count','last_match_at','created_at'],
screened_url: ['domain','action','match_count','last_match_at','created_at'],
report: ['date', 'value'],
})
def execute(args)
@entity = args[:entity]
@extra = HashWithIndifferentAccess.new(args[:args]) if args[:args]
@file_name = @entity
@current_user = User.find_by(id: args[:user_id])
export_method = "#{@entity}_export".to_sym
data =
if respond_to?(export_method)
send(export_method)
else
raise Discourse::InvalidParameters.new(:entity)
end
export_method = :"#{@entity}_export"
raise Discourse::InvalidParameters.new(:entity) unless respond_to?(export_method)
if data && data.length > 0
set_file_path
write_csv_file(data)
file_name_prefix = if @entity == "user_archive"
"#{@entity.split('_').join('-')}-#{@current_user.username}-#{Time.now.strftime("%y%m%d-%H%M%S")}"
else
"#{@entity.split('_').join('-')}-#{Time.now.strftime("%y%m%d-%H%M%S")}"
end
file = UserExport.create(file_name: file_name_prefix, user_id: @current_user.id)
file_name = "#{file_name_prefix}-#{file.id}.csv"
absolute_path = "#{UserExport.base_directory}/#{file_name}"
# ensure directory exists
FileUtils.mkdir_p(UserExport.base_directory) unless Dir.exists?(UserExport.base_directory)
# write to CSV file
CSV.open(absolute_path, "w") do |csv|
csv << get_header
send(export_method).each { |d| csv << d }
end
# compress CSV file
`gzip -5 #{absolute_path}`
ensure
notify_user
notify_user(file_name, absolute_path)
end
def user_archive_export
user_archive_data = Post.includes(:topic => :category).where(user_id: @current_user.id).select(:topic_id, :post_number, :raw, :like_count, :reply_count, :created_at).order(:created_at).with_deleted.to_a
user_archive_data.map do |user_archive|
get_user_archive_fields(user_archive)
return enum_for(:user_archive_export) unless block_given?
Post.includes(topic: :category)
.where(user_id: @current_user.id)
.select(:topic_id, :post_number, :raw, :like_count, :reply_count, :created_at)
.order(:created_at)
.with_deleted
.each do |user_archive|
yield get_user_archive_fields(user_archive)
end
end
def user_list_export
return enum_for(:user_list_export) unless block_given?
user_array = []
user_field_ids = UserField.pluck(:id)
condition = {}
if @extra && @extra[:trust_level] && trust_level = TrustLevel.levels[@extra[:trust_level].to_sym]
condition = {trust_level: trust_level}
condition = { trust_level: trust_level }
end
if SiteSetting.enable_sso
@ -65,8 +85,7 @@ module Jobs
user_info_string = add_single_sign_on(user, user_info_string)
user_info_string = add_custom_fields(user, user_info_string, user_field_ids)
user_info_string = add_group_names(user, user_info_string)
user_array.push(user_info_string.split(","))
user_info_string = nil
yield user_info_string.split(",")
end
else
# SSO disabled
@ -74,78 +93,78 @@ module Jobs
user_info_string = get_base_user_string(user)
user_info_string = add_custom_fields(user, user_info_string, user_field_ids)
user_info_string = add_group_names(user, user_info_string)
user_array.push(user_info_string.split(","))
user_info_string = nil
yield user_info_string.split(",")
end
end
user_field_ids = nil
user_array
end
def staff_action_export
if @current_user.admin?
staff_action_data = UserHistory.only_staff_actions.order('id DESC').to_a
return enum_for(:staff_action_export) unless block_given?
staff_action_data = if @current_user.admin?
UserHistory.only_staff_actions.order('id DESC')
else
# moderator
staff_action_data = UserHistory.where(admin_only: false).only_staff_actions.order('id DESC').to_a
UserHistory.where(admin_only: false).only_staff_actions.order('id DESC')
end
staff_action_data.map do |staff_action|
get_staff_action_fields(staff_action)
staff_action_data.each do |staff_action|
yield get_staff_action_fields(staff_action)
end
end
def screened_email_export
screened_email_data = ScreenedEmail.order('last_match_at desc').to_a
screened_email_data.map do |screened_email|
get_screened_email_fields(screened_email)
return enum_for(:screened_email_export) unless block_given?
ScreenedEmail.order('last_match_at DESC').each do |screened_email|
yield get_screened_email_fields(screened_email)
end
end
def screened_ip_export
screened_ip_data = ScreenedIpAddress.order('id desc').to_a
screened_ip_data.map do |screened_ip|
get_screened_ip_fields(screened_ip)
return enum_for(:screened_ip_export) unless block_given?
ScreenedIpAddress.order('id DESC').each do |screened_ip|
yield get_screened_ip_fields(screened_ip)
end
end
def screened_url_export
screened_url_data = ScreenedUrl.select("domain, sum(match_count) as match_count, max(last_match_at) as last_match_at, min(created_at) as created_at").group(:domain).order('last_match_at DESC').to_a
screened_url_data.map do |screened_url|
get_screened_url_fields(screened_url)
return enum_for(:screened_url_export) unless block_given?
ScreenedUrl.select("domain, sum(match_count) as match_count, max(last_match_at) as last_match_at, min(created_at) as created_at")
.group(:domain)
.order('last_match_at DESC')
.each do |screened_url|
yield get_screened_url_fields(screened_url)
end
end
def report_export
@extra[:start_date] = @extra[:start_date].to_date if @extra[:start_date].is_a?(String)
@extra[:end_date] = @extra[:end_date].to_date if @extra[:end_date].is_a?(String)
@extra[:category_id] = @extra[:category_id].to_i if @extra[:category_id]
@extra[:group_id] = @extra[:group_id].to_i if @extra[:group_id]
r = Report.find(@extra[:name], @extra)
r.data.map do |row|
[row[:x].to_s(:db), row[:y].to_s(:db)]
return enum_for(:report_export) unless block_given?
@extra[:start_date] = @extra[:start_date].to_date if @extra[:start_date].is_a?(String)
@extra[:end_date] = @extra[:end_date].to_date if @extra[:end_date].is_a?(String)
@extra[:category_id] = @extra[:category_id].to_i if @extra[:category_id]
@extra[:group_id] = @extra[:group_id].to_i if @extra[:group_id]
Report.find(@extra[:name], @extra).data.each do |row|
yield [row[:x].to_s(:db), row[:y].to_s(:db)]
end
end
def get_header
case @entity
when 'user_list'
header_array = HEADER_ATTRS_FOR['user_list'] + HEADER_ATTRS_FOR['user_stats']
if SiteSetting.enable_sso
header_array.concat(HEADER_ATTRS_FOR['user_sso'])
if @entity == 'user_list'
header_array = HEADER_ATTRS_FOR['user_list'] + HEADER_ATTRS_FOR['user_stats']
header_array.concat(HEADER_ATTRS_FOR['user_sso']) if SiteSetting.enable_sso
user_custom_fields = UserField.all
if user_custom_fields.present?
user_custom_fields.each do |custom_field|
header_array.push("#{custom_field.name} (custom user field)")
end
user_custom_fields = UserField.all
if user_custom_fields.present?
user_custom_fields.each do |custom_field|
header_array.push("#{custom_field.name} (custom user field)")
end
end
header_array.push("group_names")
else
header_array = HEADER_ATTRS_FOR[@entity]
end
header_array.push("group_names")
else
header_array = HEADER_ATTRS_FOR[@entity]
end
header_array
end
@ -227,7 +246,7 @@ module Jobs
user.username if !user.nil?
elsif attr == 'subject'
user = User.find_by(id: staff_action.attributes['target_user_id'])
user.nil? ? staff_action.attributes[attr] : "#{user.username} #{staff_action.attributes[attr]}"
user.nil? ? staff_action.attributes[attr] : "#{user.username} #{staff_action.attributes[attr]}"
else
staff_action.attributes[attr]
end
@ -289,43 +308,20 @@ module Jobs
screened_url_array
end
def set_file_path
if @entity == "user_archive"
file_name_prefix = "#{@file_name.split('_').join('-')}-#{current_user.username}-#{Time.now.strftime("%y%m%d-%H%M%S")}"
else
file_name_prefix = "#{@file_name.split('_').join('-')}-#{Time.now.strftime("%y%m%d-%H%M%S")}"
end
@file = UserExport.create(file_name: file_name_prefix, user_id: @current_user.id)
@file_name = "#{file_name_prefix}-#{@file.id}.csv"
# ensure directory exists
dir = File.dirname("#{UserExport.base_directory}/#{@file_name}")
FileUtils.mkdir_p(dir) unless Dir.exists?(dir)
end
def write_csv_file(data)
# write to CSV file
CSV.open(File.expand_path("#{UserExport.base_directory}/#{@file_name}", __FILE__), "w") do |csv|
csv << get_header
data.each do |value|
csv << value
end
end
# compress CSV file
`gzip -5 #{File.expand_path("#{UserExport.base_directory}/#{@file_name}", __FILE__)}`
end
def notify_user
def notify_user(file_name, absolute_path)
if @current_user
if @file_name != "" && File.exists?("#{UserExport.base_directory}/#{@file_name}.gz")
SystemMessage.create_from_system_user(@current_user, :csv_export_succeeded, download_link: "#{Discourse.base_uri}/export_csv/#{@file_name}.gz", file_name: "#{@file_name}.gz", file_size: number_to_human_size(File.size("#{UserExport.base_directory}/#{@file_name}.gz")))
if file_name.present? && File.exists?("#{absolute_path}.gz")
SystemMessage.create_from_system_user(
@current_user,
:csv_export_succeeded,
download_link: "#{Discourse.base_uri}/export_csv/#{file_name}.gz",
file_name: "#{file_name}.gz",
file_size: number_to_human_size(File.size("#{absolute_path}.gz"))
)
else
SystemMessage.create_from_system_user(@current_user, :csv_export_failed)
end
end
end
end
end

View File

@ -16,7 +16,7 @@ module Jobs
users =
User.activated.not_blocked.not_suspended.real
.joins(:user_option)
.where(user_options: {mailing_list_mode: true})
.where(user_options: {mailing_list_mode: true, mailing_list_mode_frequency: 1})
.where('NOT EXISTS(
SELECT 1
FROM topic_users tu

View File

@ -0,0 +1,27 @@
module Jobs
class EnqueueMailingListEmails < Jobs::Scheduled
every 1.hour
def execute(args)
return if SiteSetting.disable_mailing_list_mode?
target_user_ids.each do |user_id|
Jobs.enqueue(:user_email, type: :mailing_list, user_id: user_id)
end
end
def target_user_ids
# Users who want to receive daily mailing list emails
User.real
.not_suspended
.joins(:user_option)
.where(active: true, staged: false, user_options: {mailing_list_mode: true, mailing_list_mode_frequency: 0})
.where("#{!SiteSetting.must_approve_users?} OR approved OR moderator OR admin")
.where("date_part('hour', first_seen_at) = date_part('hour', CURRENT_TIMESTAMP)") # where the hour of first_seen_at is the same as the current hour
.where("COALESCE(first_seen_at, '2010-01-01') <= CURRENT_TIMESTAMP - '23 HOURS'::INTERVAL") # don't send unless you've been around for a day already
.pluck(:id)
end
end
end

View File

@ -73,16 +73,27 @@ class UserNotifications < ActionMailer::Base
end
end
def digest(user, opts={})
@user = user
@base_url = Discourse.base_url
def mailing_list(user, opts={})
@since = opts[:since] || 1.day.ago
@since_formatted = short_date(@since)
@new_topic_posts = Post.mailing_list_new_topics(user, @since).group_by(&:topic) || {}
@existing_topic_posts = Post.mailing_list_updates(user, @since).group_by(&:topic) || {}
@posts_by_topic = @new_topic_posts.merge @existing_topic_posts
return unless @posts_by_topic.present?
build_summary_for(user)
build_email @user.email,
from_alias: I18n.t('user_notifications.mailing_list.from', site_name: SiteSetting.title),
subject: I18n.t('user_notifications.mailing_list.subject_template',
site_name: @site_name,
date: @date)
end
def digest(user, opts={})
build_summary_for(user)
min_date = opts[:since] || @user.last_emailed_at || @user.last_seen_at || 1.month.ago
@site_name = SiteSetting.email_prefix.presence || SiteSetting.title
@header_color = ColorScheme.hex_for_name('header_background')
@anchor_color = ColorScheme.hex_for_name('tertiary')
@last_seen_at = short_date(@user.last_seen_at || @user.created_at)
# A list of topics to show the user
@ -106,10 +117,8 @@ class UserNotifications < ActionMailer::Base
end
@featured_topics, @new_topics = @featured_topics[0..4], @featured_topics[5..-1]
@markdown_linker = MarkdownLinker.new(Discourse.base_url)
@unsubscribe_key = DigestUnsubscribeKey.create_key_for(@user)
build_email user.email,
build_email @user.email,
from_alias: I18n.t('user_notifications.digest.from', site_name: SiteSetting.title),
subject: I18n.t('user_notifications.digest.subject_template',
site_name: @site_name,
@ -396,4 +405,17 @@ class UserNotifications < ActionMailer::Base
build_email(user.email, email_opts)
end
private
def build_summary_for(user)
@user = user
@date = short_date(Time.now)
@base_url = Discourse.base_url
@site_name = SiteSetting.email_prefix.presence || SiteSetting.title
@header_color = ColorScheme.hex_for_name('header_background')
@anchor_color = ColorScheme.hex_for_name('tertiary')
@markdown_linker = MarkdownLinker.new(@base_url)
@unsubscribe_key = DigestUnsubscribeKey.create_key_for(@user)
end
end

View File

@ -91,7 +91,7 @@ class AdminDashboardData
]
add_problem_check :rails_env_check, :ruby_version_check, :host_names_check,
:gc_checks, :ram_check, :google_oauth2_config_check,
:ram_check, :google_oauth2_config_check,
:facebook_config_check, :twitter_config_check,
:github_config_check, :s3_config_check, :image_magick_check,
:failing_emails_check, :default_logo_check, :contact_email_check,
@ -169,10 +169,6 @@ class AdminDashboardData
I18n.t("dashboard.host_names_warning") if ['localhost', 'production.localhost'].include?(Discourse.current_hostname)
end
def gc_checks
I18n.t("dashboard.gc_warning") if ENV['RUBY_GC_MALLOC_LIMIT'].nil?
end
def sidekiq_check
last_job_performed_at = Jobs.last_job_performed_at
I18n.t('dashboard.sidekiq_warning') if Jobs.queued > 0 and (last_job_performed_at.nil? or last_job_performed_at < 2.minutes.ago)

View File

@ -3,7 +3,7 @@ class IncomingEmail < ActiveRecord::Base
belongs_to :topic
belongs_to :post
scope :errored, -> { where.not(error: nil) }
scope :errored, -> { where("NOT is_bounce AND LENGTH(COALESCE(error,'')) > 0") }
end
# == Schema Information

View File

@ -0,0 +1,19 @@
require_dependency 'enum_site_setting'
class MailingListModeSiteSetting < EnumSiteSetting
def self.valid_value?(val)
val.to_i.to_s == val.to_s &&
values.any? { |v| v[:value] == val.to_i }
end
def self.values
@values ||= [
{ name: 'user.mailing_list_mode.daily', value: 0 },
{ name: 'user.mailing_list_mode.individual', value: 1 }
]
end
def self.translate_names?
true
end
end

View File

@ -45,6 +45,8 @@ class OptimizedImage < ActiveRecord::Base
if extension =~ /\.svg$/i
FileUtils.cp(original_path, temp_path)
resized = true
elsif opts[:crop]
resized = crop(original_path, temp_path, width, height, opts)
else
resized = resize(original_path, temp_path, width, height, opts)
end
@ -124,6 +126,25 @@ class OptimizedImage < ActiveRecord::Base
}
end
def self.crop_instructions(from, to, dimensions, opts={})
%W{
convert
#{from}[0]
-gravity north
-background transparent
-thumbnail #{opts[:width]}
-crop #{dimensions}+0+0
-unsharp 2x0.5+0.7+0
-quality 98
-profile #{File.join(Rails.root, 'vendor', 'data', 'RT_sRGB.icm')}
#{to}
}
end
def self.crop_instructions_animated(from, to, dimensions, opts={})
resize_instructions_animated(from, to, dimensions, opts)
end
def self.downsize_instructions(from, to, dimensions, opts={})
%W{
convert
@ -144,6 +165,11 @@ class OptimizedImage < ActiveRecord::Base
optimize("resize", from, to, "#{width}x#{height}", opts)
end
def self.crop(from, to, width, height, opts={})
opts[:width] = width
optimize("crop", from, to, "#{width}x#{height}", opts)
end
def self.downsize(from, to, dimensions, opts={})
optimize("downsize", from, to, dimensions, opts)
end

View File

@ -65,6 +65,14 @@ class Post < ActiveRecord::Base
scope :with_topic_subtype, ->(subtype) { joins(:topic).where('topics.subtype = ?', subtype) }
scope :visible, -> { joins(:topic).where('topics.visible = true').where(hidden: false) }
scope :secured, lambda { |guardian| where('posts.post_type in (?)', Topic.visible_post_types(guardian && guardian.user))}
scope :for_mailing_list, ->(user, since) {
created_since(since)
.joins(:topic)
.where(topic: Topic.for_digest(user, 100.years.ago)) # we want all topics with new content, regardless when they were created
.order('posts.created_at ASC')
}
scope :mailing_list_new_topics, ->(user, since) { for_mailing_list(user, since).where('topics.created_at > ?', since) }
scope :mailing_list_updates, ->(user, since) { for_mailing_list(user, since).where('topics.created_at <= ?', since) }
delegate :username, to: :user

View File

@ -59,7 +59,7 @@ SCRIPT
begin
code = transpile(node.inner_html, node['version'])
node.replace("<script>#{code}</script>")
rescue Tilt::ES6ModuleTranspilerTemplate::JavaScriptError => ex
rescue MiniRacer::RuntimeError => ex
node.replace("<script type='text/discourse-js-error'>#{ex.message}</script>")
end
end

View File

@ -25,9 +25,13 @@ TopicStatusUpdate = Struct.new(:topic, :user) do
topic.reload.set_auto_close(nil).save
end
# pick up the changes right away as opposed to waiting for
# the schedule
CategoryFeaturedTopic.feature_topics_for(topic.category)
# remove featured topics if we close/archive/make them invisible. Previously we used
# to run the whole featuring logic but that could be very slow and have concurrency
# errors on large sites with many autocloses and topics being created.
if ((status.enabled? && (status.autoclosed? || status.closed? || status.archived?)) ||
(status.disabled? && status.visible?))
CategoryFeaturedTopic.where(topic_id: topic.id).delete_all
end
end
def create_moderator_post_for(status, message=nil)
@ -81,7 +85,7 @@ TopicStatusUpdate = Struct.new(:topic, :user) do
end
Status = Struct.new(:name, :enabled) do
%w(pinned_globally pinned autoclosed closed).each do |status|
%w(pinned_globally pinned autoclosed closed visible archived).each do |status|
define_method("#{status}?") { name == status }
end

View File

@ -95,7 +95,10 @@ class TrustLevel3Requirements
end
def min_topics_viewed
(TrustLevel3Requirements.num_topics_in_time_period.to_i * (SiteSetting.tl3_requires_topics_viewed.to_f / 100.0)).round
[
(TrustLevel3Requirements.num_topics_in_time_period.to_i * (SiteSetting.tl3_requires_topics_viewed.to_f / 100.0)).round,
SiteSetting.tl3_requires_topics_viewed_cap
].min
end
def posts_read
@ -103,7 +106,10 @@ class TrustLevel3Requirements
end
def min_posts_read
(TrustLevel3Requirements.num_posts_in_time_period.to_i * (SiteSetting.tl3_requires_posts_read.to_f / 100.0)).round
[
(TrustLevel3Requirements.num_posts_in_time_period.to_i * (SiteSetting.tl3_requires_posts_read.to_f / 100.0)).round,
SiteSetting.tl3_requires_posts_read_cap
].min
end
def topics_viewed_all_time

View File

@ -29,19 +29,16 @@ class Upload < ActiveRecord::Base
thumbnail(width, height).present?
end
def create_thumbnail!(width, height)
def create_thumbnail!(width, height, crop=false)
return unless SiteSetting.create_thumbnails?
thumbnail = OptimizedImage.create_for(
self,
width,
height,
opts = {
filename: self.original_filename,
allow_animation: SiteSetting.allow_animated_thumbnails
)
allow_animation: SiteSetting.allow_animated_thumbnails,
crop: crop
}
if thumbnail
optimized_images << thumbnail
if thumbnail = OptimizedImage.create_for(self, width, height, opts)
self.width = width
self.height = height
save(validate: false)

View File

@ -476,6 +476,7 @@ class User < ActiveRecord::Base
update_previous_visit(now)
# using update_column to avoid the AR transaction
update_column(:last_seen_at, now)
update_column(:first_seen_at, now) unless self.first_seen_at
end
def self.gravatar_template(email)

View File

@ -2,23 +2,16 @@ class UserExport < ActiveRecord::Base
def self.get_download_path(filename)
path = File.join(UserExport.base_directory, filename)
if File.exists?(path)
return path
else
nil
end
File.exists?(path) ? path : nil
end
def self.remove_old_exports
expired_exports = UserExport.where('created_at < ?', 2.days.ago).to_a
expired_exports.map do |expired_export|
UserExport.where('created_at < ?', 2.days.ago).find_each do |expired_export|
file_name = "#{expired_export.file_name}-#{expired_export.id}.csv.gz"
file_path = "#{UserExport.base_directory}/#{file_name}"
if File.exist?(file_path)
File.delete(file_path)
end
UserExport.find(expired_export.id).destroy
File.delete(file_path) if File.exist?(file_path)
expired_export.destroy
end
end

View File

@ -24,6 +24,7 @@ class UserOption < ActiveRecord::Base
def set_defaults
self.email_always = SiteSetting.default_email_always
self.mailing_list_mode = SiteSetting.default_email_mailing_list_mode
self.mailing_list_mode_frequency = SiteSetting.default_email_mailing_list_mode_frequency
self.email_direct = SiteSetting.default_email_direct
self.automatically_unpin_topics = SiteSetting.default_topics_automatic_unpin
self.email_private_messages = SiteSetting.default_email_private_messages

View File

@ -1,7 +1,7 @@
class UserProfile < ActiveRecord::Base
belongs_to :user, inverse_of: :user_profile
WEBSITE_REGEXP = /(^$)|(^(http|https):\/\/[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,9}(([0-9]{1,5})?\/.*)?$)/ix
WEBSITE_REGEXP = /(^$)|(^(http|https):\/\/[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,10}(([0-9]{1,5})?\/.*)?$)/ix
validates :bio_raw, length: { maximum: 3000 }
validates :website, format: { with: WEBSITE_REGEXP }, allow_blank: true, if: Proc.new { |c| c.new_record? || c.website_changed? }

View File

@ -30,7 +30,7 @@ class QueuedPostSerializer < ApplicationSerializer
end
def include_can_delete_user?
user.trust_level == TrustLevel[0]
user && user.trust_level == TrustLevel[0]
end
end

View File

@ -2,6 +2,7 @@ class UserOptionSerializer < ApplicationSerializer
attributes :user_id,
:email_always,
:mailing_list_mode,
:mailing_list_mode_frequency,
:email_digests,
:email_private_messages,
:email_direct,

View File

@ -9,6 +9,7 @@ class UserUpdater
OPTION_ATTR = [
:email_always,
:mailing_list_mode,
:mailing_list_mode_frequency,
:email_digests,
:email_direct,
:email_private_messages,

View File

@ -0,0 +1,76 @@
<div id="top"></div>
<table style='width: 100%; border: 20px solid #eee;' cellspacing='0' cellpadding='0'>
<thead>
<td style='padding: 10px 10px; background-color: #<%= @header_color %>;'>
<a href='<%= Discourse.base_url %>' style='color: #<%= @anchor_color %>'>
<% if logo_url.blank? %>
<%= SiteSetting.title %>
<% else %>
<img src='<%= logo_url %>' style='max-height: 35px; min-height: 35px; height: 35px;' class='site-logo'></a>
<% end %>
<br />
<div style='padding-top: 10px;'>
<%= raw(t 'user_notifications.mailing_list.why', site_link: html_site_link(@anchor_color), date: @since_formatted) %>
</div>
<hr />
</a>
</td>
</thead>
<tr>
<td>
<h4 style="padding: 0 25px; margin: 10px 0;"><%= t('user_notifications.mailing_list.new_topics') %></h3>
<ul>
<% @new_topic_posts.keys.each do |topic| %>
<li>
<a href='<%= Discourse.base_url + topic.relative_url %>' style='color: #<%= @anchor_color %>'><%= raw format_topic_title(topic.title) %></a>
<span><%= @new_topic_posts[topic].length %></span>
<%= category_badge(topic.category, inline_style: true, absolute_url: true) %>
</li>
<% end %>
</ul>
<h4 style="padding: 0 25px; margin: 10px 0;"><%= t('user_notifications.mailing_list.topic_updates') %></h3>
<ul>
<% @existing_topic_posts.keys.each do |topic| %>
<li>
<a href='<%= Discourse.base_url + topic.relative_url %>' style='color: #<%= @anchor_color %>'><%= raw format_topic_title(topic.title) %></a>
<span><%= @existing_topic_posts[topic].length %></span>
<%= category_badge(topic.category, inline_style: true, absolute_url: true) %>
</li>
<% end %>
</ul>
</td>
</tr>
</table>
<table style='width: 100%; background: #eee;' cellspacing='0' cellpadding='0'>
<% @posts_by_topic.keys.each do |topic| %>
<tr>
<td>
<h3 style='padding: 20px 20px 10px; margin: 0;'>
<a href='<%= Discourse.base_url + topic.relative_url %>' style='color: #<%= @anchor_color %>'><%= raw format_topic_title(topic.title) %></a>
</h3>
</td>
</tr>
<tr>
<td style='border-left: 20px solid #eee; border-right: 20px solid #eee; border-bottom: 10px solid #eee; padding: 10px 10px; background: #fff;'>
<% @posts_by_topic[topic].each do |post| %>
<div>
<img style="float: left; width: 20px; padding-right: 5px;" src="<%= post.user.small_avatar_url %>" title="<%= post.user.username%>">
<p style="font-size: 15px; color: #888">
<a href='<%= [Discourse.base_url, :users, post.user.username].join('/') %>'><%= post.user.name || post.user.username %></a>
<span> - </span>
<span><%= I18n.l(post.created_at, format: :long) %></span>
</p>
<%= raw format_for_email(post, false, :notification) %>
<hr />
</div>
<% end %>
<a style='font-size: 12px; float: right;' href='<%= Discourse.base_url + topic.relative_url %>'><%= t('user_notifications.mailing_list.view_this_topic') %></a>
</td>
</tr>
<tr>
<td style='padding: 0 20px; font-size: 12px;'>
<a href="#top"><%= t('user_notifications.mailing_list.back_to_top') %></a>
</td>
</tr>
<% end %>
</table>

View File

@ -0,0 +1,31 @@
<%- site_link = raw(@markdown_linker.create(@site_name, '/')) %>
<%= raw(t 'user_notifications.mailing_list.why', site_link: site_link, date: @since_formatted) %>
<%- if @new_topic_posts.keys.present? -%>
### <%= t 'user_notifications.mailing_list.new_topics' %>
<%- @new_topic_posts.keys.each do |topic| %>
<%= raw(@markdown_linker.create(topic.title, topic.relative_url)) %>
<%- end -%>
<%- end -%>
<%- if @existing_topic_posts.keys.present? -%>
### <%= t 'user_notifications.mailing_list.new_topics' %>
<%- @existing_topic_posts.keys.each do |topic| -%>
<%= raw(@markdown_linker.create(topic.title, topic.relative_url)) %>
<%= @existing_topic_posts[topic].length %>
<%- end -%>
<%- end -%>
--------------------------------------------------------------------------------
<%- @posts_by_topic.keys.each do |topic| %>
### <%= raw(@markdown_linker.create(topic.title, topic.relative_url)) %>
<%- @posts_by_topic[topic].each do |post| -%>
<%= post.user.name || post.user.username %> - <%= post.created_at %>
--------------------------------------------------------------------------------
<%= post.raw %>
<%- end -%>
<%- end %>

View File

@ -8,7 +8,7 @@
<% else %>
<%=form_tag({}, method: :put) do %>
<%= label_tag(:email, t('admin_login.email_input')) %>
<%= text_field_tag(:email) %><br><br>
<%= text_field_tag(:email, nil, autofocus: true) %><br><br>
<%= submit_tag t('admin_login.submit_button') %>
<% end %>
<% end %>

View File

@ -43,7 +43,7 @@ end
namespace :deploy do
desc 'Start thin servers'
task :start, :roles => :app, :except => { :no_release => true } do
run "cd #{current_path} && RUBY_GC_MALLOC_LIMIT=90000000 bundle exec thin -C config/thin.yml start", :pty => false
run "cd #{current_path} && bundle exec thin -C config/thin.yml start", :pty => false
end
desc 'Stop thin servers'
@ -53,7 +53,7 @@ namespace :deploy do
desc 'Restart thin servers'
task :restart, :roles => :app, :except => { :no_release => true } do
run "cd #{current_path} && RUBY_GC_MALLOC_LIMIT=90000000 bundle exec thin -C config/thin.yml restart"
run "cd #{current_path} && bundle exec thin -C config/thin.yml restart"
end
end

View File

@ -13,7 +13,6 @@ respawn limit 3 30
start on runlevel [2345]
stop on runlevel [06]
env RUBY_GC_MALLOC_LIMIT=90000000
env RAILS_ROOT=/var/www/discourse
env RAILS_ENV=production
env NUM_WEBS=4

View File

@ -111,6 +111,7 @@ da:
google+: 'del dette link på Google+'
email: 'send dette link i en e-mail'
action_codes:
public_topic: "offentliggjorde dette emne %{when}"
split_topic: "delte dette emne op %{when}"
invited_user: "Inviterede %{who} %{when}"
removed_user: "fjernede %{who} %{when}"
@ -285,6 +286,8 @@ da:
title: "Brugere"
likes_given: "Givet"
likes_received: "Modtaget"
topics_entered: "Set"
topics_entered_long: "Læste emner"
time_read: "Læsetid"
topic_count: "Emner"
topic_count_long: "Emner oprettet"

View File

@ -504,7 +504,17 @@ en:
suspended_notice: "This user is suspended until {{date}}."
suspended_reason: "Reason: "
github_profile: "Github"
mailing_list_mode: "Send me an email for every new post (unless I mute the topic or category)"
email_activity_summary: "Activity Summary"
mailing_list_mode:
label: "Mailing list mode"
enabled: "Enable mailing list mode."
instructions: |
This setting overrides the activity summary.<br />
Muted topics and categories are not included in these emails.
daily: "Send daily updates."
individual: "Send an email for every new post."
many_per_day: "Send me an email for every new post (about {{dailyEmailEstimate}} per day)."
few_per_day: "Send me an email for every new post (less than 2 per day)."
watched_categories: "Watched"
watched_categories_instructions: "You will automatically watch all new topics in these categories. You will be notified of all new posts and topics, and a count of new posts will also appear next to the topic."
tracked_categories: "Tracked"
@ -1137,7 +1147,7 @@ en:
context:
user: "Search posts by @{{username}}"
category: "Search the \"{{category}}\" category"
category: "Search the #{{category}} category"
topic: "Search this topic"
private_messages: "Search messages"

View File

@ -302,6 +302,8 @@ es:
title: "Usuarios"
likes_given: "Dados"
likes_received: "Recibidos"
topics_entered: "Vistos"
topics_entered_long: "Temas vistos"
time_read: "Tiempo de Lectura"
topic_count: "Temas"
topic_count_long: "Temas creados"
@ -2620,6 +2622,7 @@ es:
embed_truncate: "Truncar los posts insertados"
embed_whitelist_selector: "Selector CSS para permitir elementos a embeber"
embed_blacklist_selector: "Selector CSS para restringir elementos a embeber"
embed_classname_whitelist: "Clases CSS permitidas"
feed_polling_enabled: "Importar posts usando RSS/ATOM"
feed_polling_url: "URL del feed RSS/ATOM del que extraer datos"
save: "Guardar ajustes de Insertado"

View File

@ -111,6 +111,8 @@ fi:
google+: 'jaa tämä linkki Google+:ssa'
email: 'lähetä tämä linkki sähköpostissa'
action_codes:
public_topic: "teki ketjusta julkisen %{when}"
private_topic: "teki ketjusta yksityisen %{when}"
split_topic: "pilkkoi tämän ketjun %{when}"
invited_user: "kutsui käyttäjän %{who} %{when}"
removed_user: "poisti käyttäjän %{who} %{when}"

View File

@ -302,6 +302,8 @@ fr:
title: "Utilisateurs"
likes_given: "Donnés"
likes_received: "Reçus"
topics_entered: "Vus"
topics_entered_long: "Sujets consultés"
time_read: "Temps de lecture"
topic_count: "Sujets"
topic_count_long: "Sujets créés"
@ -2620,6 +2622,7 @@ fr:
embed_truncate: "Tronquer les messages intégrés"
embed_whitelist_selector: "Sélecteur CSS pour les éléments qui seront autorisés dans les contenus intégrés"
embed_blacklist_selector: "Sélecteur CSS pour les éléments qui seront interdits dans les contenus intégrés"
embed_classname_whitelist: "Classes CSS autorisées"
feed_polling_enabled: "Importer les messages via flux RSS/ATOM"
feed_polling_url: "URL du flux RSS/ATOM à importer"
save: "Sauvegarder paramètres d'intégration"
@ -2753,6 +2756,9 @@ fr:
watching:
title: "Suivie"
description: "Vous serez automatiquement abonné aux nouveaux sujets de ces catégories. Vous serez notifié de tous les nouveaux messages et sujets, et le décompte des messages non-lus et nouveaux aussi à côté de chaque sujet."
tracking:
title: "Suivi"
description: "Vous allez suivre automatiquement tous les nouveaux sujets dans ce tag. Le nombre de messages nouveaux et non lus apparaîtra à côté du sujet."
regular:
title: "Habitué"
description: "Vous serez averti si quelqu'un mentionne votre @pseudo ou répond à votre message."
@ -2765,3 +2771,18 @@ fr:
new: "Vous n'avez aucun nouveau sujet."
read: "Vous n'avez lu aucun sujet pour le moment."
posted: "Vous n'avez écrit aucun message pour le moment."
latest: "Il n'y a pas de sujets récents."
hot: "Il n'y a pas de sujets populaires."
bookmarks: "Vous n'avez pas encore de sujets ajoutés aux signets."
top: "Il n'y a pas de meilleurs sujets."
search: "Il n'y a pas de résultats de recherche."
bottom:
latest: "Il n'y a plus de sujets récents."
hot: "Il n'y a plus de sujets populaires."
posted: "Il n'y a plus de sujets publiés."
read: "Il n'y a plus de sujets lus."
new: "Il n'y a plus de nouveaux sujets."
unread: "Il n'y a plus de sujets non lus."
top: "Il n'y a plus de meilleurs sujets."
bookmarks: "Il n'y a plus de sujets ajoutés aux signets."
search: "Il n'y a plus de résultats de recherche."

View File

@ -302,6 +302,8 @@ it:
title: "Utenti"
likes_given: "Dati"
likes_received: "Ricevuti"
topics_entered: "Visualizzati"
topics_entered_long: "Argomenti Visualizzati"
time_read: "Tempo di Lettura"
topic_count: "Argomenti"
topic_count_long: "Argomenti Creati"
@ -701,6 +703,9 @@ it:
top_badges: "Migliori Targhette"
no_badges: "Ancora nessuna targhetta."
more_badges: "Altre Targhette"
top_links: "Migliori Collegamenti"
no_links: "Ancora nessun collegamento."
no_likes: "Ancora nessun \"Mi piace\"."
associated_accounts: "Login"
ip_address:
title: "Ultimo indirizzo IP"
@ -2192,6 +2197,8 @@ it:
grant_moderation: "assegna moderazione"
revoke_moderation: "revoca moderazione"
backup_operation: "operazione di backup"
deleted_tag: "etichetta cancellata"
renamed_tag: "etichetta rinominata"
screened_emails:
title: "Email Scansionate"
description: "Quando qualcuno cerca di creare un nuovo account, verrando controllati i seguenti indirizzi email e la registrazione viene bloccata, o eseguita qualche altra azione."
@ -2478,6 +2485,7 @@ it:
login: "Accesso"
plugins: "Plugin"
user_preferences: "Preferenze Utente"
tags: "Etichette"
badges:
title: Targhette
new_badge: Nuova Targhetta
@ -2686,3 +2694,29 @@ it:
<button class="btn btn-primary">Google</button>
</form>
</p>
tagging:
all_tags: "Tutte Le Etichette"
selector_all_tags: "tutte le etichette"
changed: "etichette cambiate:"
tags: "Etichette"
choose_for_topic: "scegli delle etichette opzionali per questo argomento"
delete_tag: "Cancella Etichetta"
delete_confirm: "Sicuro di voler eliminare l'etichetta?"
rename_tag: "Rinomina Etichetta"
rename_instructions: "Scegli un nome per l'etichetta:"
sort_by: "Ordina per:"
sort_by_count: "conteggio"
sort_by_name: "nome"
filters:
without_category: "%{filter} %{tag} argomenti"
with_category: "%{filter} %{tag} argomenti in %{category}"
topics:
bottom:
hot: "Non ci sono ulteriori argomenti caldi."
posted: "Non ci sono ulteriori argomenti pubblicati."
read: "Non ci sono ulteriori argomenti letti."
new: "Non ci sono ulteriori nuovi argomenti."
unread: "Non ci sono ulteriori argomenti non letti."
top: "Non ci sono ulteriori argomenti di punta."
bookmarks: "Non ci sono ulteriori argomenti aggiunti ai segnalibri."
search: "Non ci sono ulteriori risultati di ricerca."

View File

@ -29,8 +29,8 @@ ja:
long_no_year: "MMM D h:mm a"
long_no_year_no_time: "MMM D"
full_no_year_no_time: "MMMM Do"
long_with_year: "YYYY, D MMM h:mm a"
long_with_year_no_time: "YYYY, D MMM"
long_with_year: "YYYY, MMM D h:mm a"
long_with_year_no_time: "YYYY, MMM D"
full_with_year_no_time: "MMMM Do, YYYY"
long_date_with_year: "MMM D, 'YY LT"
long_date_without_year: "MMM D, LT"
@ -38,13 +38,13 @@ ja:
long_date_without_year_with_linebreak: "MMM D <br/>LT"
long_date_with_year_with_linebreak: "MMM D, 'YY <br/>LT"
tiny:
half_a_minute: "< 1分"
half_a_minute: "1分"
less_than_x_seconds:
other: "< %{count}秒"
other: "%{count}秒"
x_seconds:
other: "%{count}秒"
less_than_x_minutes:
other: "< %{count}分"
other: "%{count}分"
x_minutes:
other: "%{count}分"
about_x_hours:
@ -54,10 +54,10 @@ ja:
about_x_years:
other: "%{count}年"
over_x_years:
other: "> %{count}年"
other: "%{count}年以上前"
almost_x_years:
other: "%{count}年"
date_month: "MMM D"
date_month: "MMM D"
date_year: "MMM 'YY"
medium:
x_minutes:
@ -92,12 +92,17 @@ ja:
google+: 'Google+ でこのリンクを共有する'
email: 'メールでこのリンクを送る'
action_codes:
public_topic: "%{when} にこのトピックは公開されました"
private_topic: "%{when} にこのトピックは非公開にされました"
invited_user: "%{who} から招待されました: %{when}"
autoclosed:
enabled: 'クローズされました // %{when}'
enabled: 'クローズされました: %{when}'
closed:
enabled: 'クローズされました // %{when}'
topic_admin_menu: "トピック管理"
enabled: 'クローズされました: %{when}'
visible:
enabled: 'リストに表示: %{when}'
disabled: 'リストから非表示: %{when}'
topic_admin_menu: "トピックの管理"
emails_are_disabled: "メールアドレスの送信は管理者によって無効化されています。全てのメール通知は行われません"
s3:
regions:
@ -113,7 +118,7 @@ ja:
ap_northeast_2: "Asia Pacific (Seoul)"
sa_east_1: "South America (Sao Paulo)"
edit: 'このトピックのタイトルとカテゴリを編集'
not_implemented: "申し訳ありませんが、この機能はまだ実装されていません"
not_implemented: "この機能はまだ実装されていません"
no_value: "いいえ"
yes_value: "はい"
generic_error: "申し訳ありませんが、エラーが発生しました"
@ -122,14 +127,14 @@ ja:
log_in: "ログイン"
age: "経過"
joined: "参加時刻"
admin_title: "Admin"
admin_title: "管理設定"
flags_title: "通報"
show_more: "もっと見る"
show_help: "オプション"
links: "リンク"
links_lowercase:
other: "リンク"
faq: "よくある質問"
faq: "FAQ"
guidelines: "ガイドライン"
privacy_policy: "プライバシーポリシー"
privacy: "プライバシー"
@ -155,7 +160,7 @@ ja:
other: "{{count}}文字"
suggested_topics:
title: "関連トピック"
pm_title: "提案したメッセージ"
pm_title: "他のメッセージ"
about:
simple_title: "このサイトについて"
title: "%{title}について"
@ -163,7 +168,7 @@ ja:
our_admins: "管理者"
our_moderators: "モデレータ"
stat:
all_time: "今まで"
all_time: "すべて"
last_7_days: "過去7日間"
last_30_days: "過去30日間"
like_count: "いいね!"
@ -191,7 +196,7 @@ ja:
topic_count_unread:
other: "{{count}} 個の未読トピック。"
topic_count_new:
other: "{{count}} 個の新規トピック。"
other: "{{count}} 件の新しいトピック"
click_to_show: "クリックして表示"
preview: "プレビュー"
cancel: "キャンセル"
@ -317,35 +322,35 @@ ja:
'9': "引用"
'11': "編集"
'12': "アイテム送信"
'13': "インボックス"
'13': "受信ボックス"
'14': "保留"
categories:
all: "てのカテゴリ"
all_subcategories: "てのサブカテゴリ"
all: "すべてのカテゴリ"
all_subcategories: "すべてのサブカテゴリ"
no_subcategory: "サブカテゴリなし"
category: "カテゴリ"
category_list: "カテゴリリストを表示"
reorder:
title: "カテゴリを並び替える"
title_long: "カテゴリリストを再構築"
title: "カテゴリの並び替え"
title_long: "カテゴリリストを並べ直します"
fix_order: "位置を修正"
save: "オーダーを保存"
save: "順番を保存"
apply_all: "適用"
position: "位置"
posts: "投稿"
topics: "トピック"
latest: "最の投稿"
latest_by: "最新投稿 "
latest: "最の投稿"
latest_by: "最新投稿: "
toggle_ordering: "カテゴリの並び替えモードを切り替え"
subcategories: "サブカテゴリ:"
topic_stats: "新しいトピック数"
topic_stat_sentence:
other: "過去 %{unit} 間 %{count} 個の新トピック。"
post_stats: "新トピック数:"
other: "過去 %{unit} 間 %{count} 個の新トピック。"
post_stats: "新トピック数:"
post_stat_sentence:
other: "過去 %{unit} 間 %{count} 個の新しい投稿。"
ip_lookup:
title: IPアドレス検索
title: IPアドレス検索
hostname: ホスト名
location: 現在地
location_not_found: (不明)
@ -356,7 +361,7 @@ ja:
username: "ユーザ名"
trust_level: "トラストレベル"
read_time: "読んだ時間"
topics_entered: "Topics Entered"
topics_entered: "入力したトピック"
post_count: "# 投稿"
confirm_delete_other_accounts: "これらのアカウントを削除してもよろしいですか?"
user_fields:
@ -367,7 +372,7 @@ ja:
mute: "ミュート"
edit: "プロフィールを編集"
download_archive: "自分の投稿をダウンロード"
new_private_message: "新メッセージ"
new_private_message: "新しいメッセージ"
private_message: "メッセージ"
private_messages: "メッセージ"
activity_stream: "アクティビティ"
@ -393,7 +398,7 @@ ja:
disable_jump_reply: "返信した後に投稿へ移動しない"
dynamic_favicon: "新規または更新されたトピックのカウントをブラウザアイコンに表示する"
edit_history_public: "投稿の編集履歴を公開する"
external_links_in_new_tab: "外部リンクを全て新しいタブで開く"
external_links_in_new_tab: "外部リンクをすべて別のタブで開く"
enable_quoting: "選択したテキストを引用して返信する"
change: "変更"
moderator: "{{user}} はモデレータです"
@ -404,14 +409,19 @@ ja:
suspended_notice: "このユーザは {{date}} まで凍結状態です。"
suspended_reason: "理由: "
github_profile: "Github"
mailing_list_mode: "投稿される度にメールで通知を受け取る(ミュートにしたトピック、カテゴリ以外)"
email_activity_summary: "アクティビティの情報"
mailing_list_mode:
enabled: "メーリングリストモードを有効にする"
instructions: |
この設定は、アクティビティの情報機能を無効化します。<br />
ミュートしているトピックやカテゴリはこれらのメールには含まれません。
watched_categories: "ウォッチ中"
watched_categories_instructions: "これらのカテゴリに新しく投稿されたトピックを自動的に参加します。これらのカテゴリに対して新しい投稿があった場合、登録されたメールアドレスと、コミュニティ内の通知ボックスに通知が届き、トピック一覧に新しい投稿数がつきます。"
tracked_categories: "追跡中"
tracked_categories_instructions: "カテゴリの新しいトピックを自動的に追跡します。トピックに対して新しい投稿があった場合、トピック一覧に新しい投稿数がつきます。"
muted_categories: "ミュート中"
delete_account: "アカウントを削除する"
delete_account_confirm: "本当にアカウントを削除しますか?削除されたアカウントは復元できません。"
delete_account_confirm: "アカウントを削除してもよろしいですか?削除されたアカウントは復元できません。"
deleted_yourself: "あなたのアカウントは削除されました。"
delete_yourself_not_allowed: "アカウントを削除できませんでした。サイトの管理者へ連絡してください。"
unread_message_count: "メッセージ"
@ -428,15 +438,15 @@ ja:
warnings_received: "警告"
messages:
all: "すべて"
inbox: "Inbox"
inbox: "受信ボックス"
sent: "送信済み"
archive: "アーカイブ"
groups: "自分のグループ"
bulk_select: "メッセージを選択"
move_to_inbox: "Inboxへ移動"
move_to_inbox: "受信ボックスへ移動"
move_to_archive: "アーカイブ"
failed_to_move: "選択したメッセージを移動できませんでした(ネットワークがダウンしている可能性があります)"
select_all: "全てを選択する"
select_all: "すべて選択する"
change_password:
success: "(メールを送信しました)"
in_progress: "(メールを送信中)"
@ -448,7 +458,7 @@ ja:
error: "変更中にエラーが発生しました。"
change_username:
title: "ユーザ名を変更"
confirm: "ユーザ名を変更すると、投稿への引用と @ユーザ名でメンションされた時のリンクが解除されます。本当にユーザ名を変更してもよろしいですか?"
confirm: "ユーザ名を変更すると、投稿への引用と @ユーザ名でメンションされた時のリンクが解除されます。ユーザ名を変更しても本当によろしいですか?"
taken: "このユーザ名は既に使われています。"
error: "ユーザ名変更中にエラーが発生しました。"
invalid: "このユーザ名は無効です。英数字のみ利用可能です。"
@ -481,6 +491,8 @@ ja:
ok: "確認用メールを送信します"
invalid: "正しいメールアドレスを入力してください"
authenticated: "あなたのメールアドレスは {{provider}} によって認証されています"
frequency:
other: "最後に利用されてから{{count}}分以上経過した場合にメールを送ります。"
name:
title: "名前"
instructions: "フルネーム(任意)"
@ -520,24 +532,30 @@ ja:
title: "いいねされた時に通知"
always: "常時"
email_previous_replies:
title: "メールの文章の下部に以前の返信を含める"
always: "常に"
email_digests:
title: "サイトを訪れていない場合、ダイジェストをメールで送信する"
title: "サイトを訪れていない場合、まとめをメールで送る"
every_30_minutes: "30分毎"
every_hour: "1時間毎"
daily: "毎日"
every_three_days: "3日毎"
weekly: "毎週"
every_two_weeks: "2週間に1回"
include_tl0_in_digests: "新しいユーザからの投稿を含める"
email_direct: "誰かが投稿を引用した時、投稿に返信があった時、私のユーザ名にメンションがあった時、またはトピックへの招待があった時にメールで通知を受け取る。"
email_private_messages: "メッセージを受け取ったときにメールで通知を受け取る。"
email_always: "フォーラムにアクティブに参加している状態でも常にメール通知を受け取る"
email_always: "常にメールへ通知を送る"
other_settings: "その他"
categories_settings: "カテゴリ設定"
new_topic_duration:
label: "以下の条件でトピックを新規と見なす"
not_viewed: "未読のもの"
not_viewed: "未読"
last_here: "ログアウトした後に投稿されたもの"
after_1_day: "昨日投稿されたもの"
after_2_days: "2日前に投稿されたもの"
after_1_week: "先週投稿されたもの"
after_2_weeks: "2週間前に投稿されたもの"
auto_track_topics: "自動でトピックを追跡する"
auto_track_options:
never: "追跡しない"
@ -593,13 +611,23 @@ ja:
time_read: "読んだ時間"
topic_count:
other: "つのトピックを作成"
post_count:
other: "つの投稿"
likes_given:
other: "あげた <i class='fa fa-heart'></i>"
likes_received:
other: "もらった <i class='fa fa-heart'></i>"
days_visited:
other: "訪問日数"
posts_read:
other: "読んだ投稿"
bookmark_count:
other: "つのブックマーク"
no_replies: "まだ返信はありません。"
no_topics: "まだトピックはありません。"
top_badges: "最近ゲットしたバッジ"
no_badges: "まだバッジはありません。"
more_badges: "バッジをもっと見る"
associated_accounts: "関連アカウント"
ip_address:
title: "最近使用したIPアドレス"
@ -667,7 +695,7 @@ ja:
enabled_description: "トピックのまとめを表示されています。"
description: "<b>{{replyCount}}</b>件の返信があります。"
enable: 'このトピックを要訳する'
disable: 'ての投稿を表示する'
disable: 'すべての投稿を表示する'
deleted_filter:
enabled_description: "削除された投稿は非表示になっています。"
disabled_description: "削除された投稿は表示しています。"
@ -675,8 +703,8 @@ ja:
disable: "削除された投稿を表示する"
private_message_info:
title: "メッセージ"
invite: "友だちを招待する..."
remove_allowed_user: "このメッセージから{{name}}を本当に取り除きますか?"
invite: "他の人を招待する..."
remove_allowed_user: "このメッセージから {{name}} を削除してもよろしいですか?"
email: 'メール'
username: 'ユーザ名'
last_seen: '最終アクティビティ'
@ -693,9 +721,9 @@ ja:
invite: "ユーザ名かメールアドレスを入力してください。パスワードリセット用のメールを送信します。"
reset: "パスワードをリセット"
complete_username: "<b>%{username}</b>,アカウントにパスワード再設定メールを送りました。"
complete_email: "<b>%{email}</b>にパスワード再設定メールを送りました。"
complete_email: "<b>%{email}</b>宛にパスワード再設定メールを送信しました。"
complete_username_found: "<b>%{username}</b>,アカウントにパスワード再設定メールを送りました。"
complete_email_found: "<b>%{email}</b>にパスワード再設定メールを送りました。"
complete_email_found: "<b>%{email}</b>宛にパスワード再設定メールを送信しました。"
complete_username_not_found: " <b>%{username}</b>は見つかりませんでした"
complete_email_not_found: "<b>%{email}</b>で登録したアカウントがありません。"
login:
@ -767,13 +795,14 @@ ja:
reply_here: "ここに返信"
reply: "返信"
cancel: "キャンセル"
create_topic: "トピック作成"
create_topic: "トピックを作る"
create_pm: "メッセージ"
title: "またはCtrl+Enter"
users_placeholder: "ユーザの追加"
title_placeholder: "トピックのタイトルを入力してください。"
edit_reason_placeholder: "編集する理由は何ですか?"
show_edit_reason: "(編集理由を追加)"
reply_placeholder: "文章を入力してください。 Markdown, BBコード, HTMLが使用出来ます。 画像はドラッグアンドドロップで貼り付けられます。"
view_new_post: "新しい投稿を見る。"
saving: "保存中"
saved: "保存完了!"
@ -832,7 +861,7 @@ ja:
invitee_accepted: "<i title='accepted your invitation' class='fa fa-user'></i><p><span>{{username}}</span> accepted your invitation</p>"
moved_post: "<i title='moved post' class='fa fa-sign-out'></i><p><span>{{username}}</span> moved {{description}}</p>"
linked: "<i title='linked post' class='fa fa-arrow-left'></i><p><span>{{username}}</span> {{description}}</p>"
granted_badge: "<i title='badge granted' class='fa fa-certificate'></i><p> {{description}}バッジをゲットしました</p>"
granted_badge: "<i title='badge granted' class='fa fa-certificate'></i><p> '{{description}}' バッジをゲット!</p>"
group_message_summary:
other: "<i title='グループ宛にメッセージが届いています' class='fa fa-group'></i><p> {{count}}件のメッセージが{{group_name}}へ着ています</p>"
alt:
@ -844,6 +873,7 @@ ja:
invitee_accepted: "招待が承認されました: "
moved_post: "投稿を移動しました: "
linked: "あなたの投稿にリンク"
granted_badge: "バッジを付与"
group_message_summary: "グループ宛のメッセージがあります"
popup:
mentioned: '"{{topic}}"で{{username}} がタグ付けしました - {{site_title}}'
@ -865,20 +895,25 @@ ja:
select_file: "ファイル選択"
image_link: "イメージのリンク先"
search:
latest_post: "最新の投稿"
select_all: "全てを選択する"
sort_by: "並べ替え"
relevance: "一番関連しているもの"
latest_post: "最近の投稿"
most_viewed: "最も閲覧されている順"
most_liked: "「いいね!」されている順"
select_all: "すべて選択する"
clear_all: "すべてクリア"
title: "トピック、投稿、ユーザ、カテゴリを探す"
no_results: "何も見つかりませんでした。"
no_more_results: "何も見つかりませんでした。"
no_more_results: "検索結果は以上です。"
search_help: 検索ヘルプ
searching: "検索中..."
post_format: "#{{post_number}} {{username}}から"
context:
user: "@{{username}}の投稿を検索"
category: "\"{{category}}\" カテゴリで検索する"
topic: "このトピックを探す"
private_messages: "メッセージ検索"
hamburger_menu: "他のトピック一覧やカテゴリを見る"
new_item: "新着"
go_back: '戻る'
not_logged_in_user: 'ユーザアクティビティと設定ページ'
current_user: 'ユーザページに移動'
@ -887,7 +922,7 @@ ja:
unlist_topics: "トピックをリストから非表示にする"
reset_read: "未読に設定"
delete: "トピックを削除"
dismiss_new: "既読に設定"
dismiss_new: "既読にする"
toggle: "選択したトピックを切り替え"
actions: "操作"
change_category: "カテゴリを変更"
@ -897,6 +932,7 @@ ja:
choose_new_category: "このトピックの新しいカテゴリを選択してください"
selected:
other: "あなたは <b>{{count}}</b> トピックを選択しました。"
change_tags: "タグを変更"
none:
unread: "未読のトピックはありません。"
new: "新しいトピックはありません。"
@ -910,13 +946,13 @@ ja:
search: "検索結果はありません。"
educate:
new: '<p>新しいトピックがここに表示されます。</p><p>デフォルトで、新しいトピックがある場合は2日間、 <span class="badge new-topic badge-notification" style="vertical-align:middle;line-height:inherit;">new</span> が表示されます。</p><p>設定は<a href="%{userPrefsUrl}">プロフィール設定</a>から変更できます。</p>'
unread: '<p>新しいトピックがここに表示されます。</p><p>未読のトピックがある場合は、<span class="badge new-posts badge-notification">1</span>表示されます。 もし、</p><ul><li>トピックを作る</li><li>トピックに返信</li><li>4分以上のトピックを読む場合</li></ul><p>などを設定した場合、トピックを追跡してそれぞれのトピックの下にある通知の設定を経由してウォッチします。</p><p><a href="%{userPrefsUrl}">プロフィール</a> から変更できます。</p>'
unread: '<p>新しいトピックがここに表示されます。</p><p>未読のトピックがある場合は、<span class="badge new-posts badge-notification">1</span>表示されます。 もし、</p><ul><li>トピックを作る</li><li>トピックに返信</li><li>トピックを4分以上読む</li></ul><p>などを行った場合、トピックを追跡してそれぞれのトピックの下にある通知の設定を経由してウォッチします。</p><p><a href="%{userPrefsUrl}">プロフィール</a>から変更できます。</p>'
bottom:
latest: "最新のトピックは以上です。"
hot: "ホットなトピックは以上です。"
posted: "投稿のあるトピックは以上です。"
read: "既読のトピックは以上です。"
new: "新トピックは以上です。"
new: "新トピックは以上です。"
unread: "未読のトピックは以上です。"
category: "{{category}}トピックは以上です。"
top: "トップトピックはこれ以上ありません。"
@ -929,11 +965,13 @@ ja:
private_message: 'メッセージを書く'
archive_message:
title: 'アーカイブ'
move_to_inbox:
title: '受信ボックスへ移動'
list: 'トピック'
new: '新規トピック'
new: '新トピック'
unread: '未読'
new_topics:
other: '{{count}}個の新トピック'
other: '{{count}}個の新トピック'
unread_topics:
other: '{{count}}個の未読トピック'
title: 'トピック'
@ -958,7 +996,7 @@ ja:
back_to_list: "トピックリストに戻る"
options: "トピックオプション"
show_links: "このトピック内のリンクを表示"
toggle_information: "トピック詳細をトグル"
toggle_information: "トピックの詳細を切り替え"
read_more_in_category: "{{catLink}}の他のトピックを見る or {{latestLink}}。"
read_more: "{{catLink}} or {{latestLink}}。"
read_more_MF: "{ UNREAD, plural, =0 {} one { <a href='/unread'>未読 1つ</a> } other { <a href='/unread'>未読 #つ</a> } } { NEW, plural, =0 {} one { {BOTH, select, true{} false {} other{}} <a href='/new'>新規トピック 1つ</a>} other { {BOTH, select, true{} false {} other{}} <a href='/new'>新規トピック #つ</a>} } remaining, or {CATEGORY, select, true {{catLink}の他のトピックを読む} false {{latestLink}} other {}}"
@ -1026,7 +1064,7 @@ ja:
actions:
recover: "トピックの削除を取り消す"
delete: "トピックを削除"
open: "トピックを開く"
open: "トピックをオープン"
close: "トピックをクローズする"
multi_select: "投稿を選択"
auto_close: "自動でクローズする..."
@ -1086,6 +1124,7 @@ ja:
success: "ユーザにメッセージへの参加を招待しました。"
error: "申し訳ありませんが、ユーザ招待中にエラーが発生しました。"
group_name: "グループ名"
controls: "オプション"
invite_reply:
title: '招待'
username_placeholder: "ユーザ名"
@ -1137,7 +1176,7 @@ ja:
select_replies: '返信と選択'
delete: 選択中のものを削除
cancel: 選択を外す
select_all: 全てを選択する
select_all: すべて選択する
deselect_all: 全ての選択を外す
description:
other: <b>{{count}}</b>個の投稿を選択中。
@ -1207,7 +1246,7 @@ ja:
unwiki: "wiki投稿から外す"
convert_to_moderator: "スタッフカラーを追加"
revert_to_regular: "スタッフカラーを外す"
rebake: "HTMLを再構"
rebake: "HTMLを再構"
unhide: "表示する"
change_owner: "オーナーシップを変更"
actions:
@ -1278,7 +1317,7 @@ ja:
other: "{{count}}人のユーザがこのポストに投票しました"
delete:
confirm:
other: "本当にこれらの投稿を削除しますか?"
other: "これらの投稿を削除してもよろしいですか?"
revisions:
controls:
first: "最初のリビジョン"
@ -1311,7 +1350,7 @@ ja:
topic_template: "トピックテンプレート"
delete: 'カテゴリを削除する'
create: '新規カテゴリ'
create_long: '新しいカテゴリを作'
create_long: '新しいカテゴリを作ります'
save: 'カテゴリを保存する'
slug: 'カテゴリスラグ'
slug_placeholder: '(任意)URL用'
@ -1327,7 +1366,7 @@ ja:
foreground_color: "文字表示色"
name_placeholder: "簡潔な名前にしてください。"
color_placeholder: "任意の Web カラー"
delete_confirm: "本当にこのカテゴリを削除してもよいですか?"
delete_confirm: "このカテゴリを削除してもよろしいですか?"
delete_error: "カテゴリ削除に失敗しました。"
list: "カテゴリをリストする"
no_description: "このカテゴリの説明はありません。トピック定義を編集してください。"
@ -1475,7 +1514,7 @@ ja:
lower_title_with_count:
other: "{{count}}件"
lower_title: "新着"
title: "新"
title: "新"
title_with_count:
other: "最新 ({{count}})"
help: "最近投稿されたトピック"
@ -1494,25 +1533,25 @@ ja:
title: "トップ"
help: "過去年間、月間、週間及び日間のアクティブトピック"
all:
title: "今まで"
title: "すべて"
yearly:
title: "年"
title: "ごと"
quarterly:
title: "3ヶ月おき"
monthly:
title: "月"
title: "ごと"
weekly:
title: "毎週"
daily:
title: "日"
all_time: "今まで"
title: "ごと"
all_time: "すべて"
this_year: "年"
this_quarter: "今季"
this_month: "月"
this_week: "週"
today: "日"
today: "日"
other_periods: "次の期間のトピックを見る"
browser_update: '<a href="http://www.discourse.org/faq/#browser">ここで動作するにはブラウザのバージョンが古すぎます。</a> 。 <a href="http://browsehappy.com">ここでブラウザアップグレード</a>.'
browser_update: '<a href="http://www.discourse.org/faq/#browser">ご利用のブラウザのバージョンが古いです</a>。 <a href="http://browsehappy.com">ブラウザをアップデート</a>してください。'
permission_types:
full: "作成 / 返信 / 閲覧"
create_post: "返信 / 閲覧"
@ -1661,7 +1700,7 @@ ja:
regenerate: "API キーを再生成"
revoke: "無効化"
confirm_regen: "このAPIキーを新しいものに置き換えてもよろしいですか?"
confirm_revoke: "このキーを無効化しても本当によろしいですか?"
confirm_revoke: "このキーを無効化してもよろしいですか?"
info_html: "API キーを使うと、JSON 呼び出しでトピックの作成・更新を行うことが出来ます。"
all_users: "全てのユーザ"
note_html: "このキーは、秘密にしてください。このキーを持っている全てのユーザは任意のユーザとして、好きな投稿を作成できます"
@ -1708,10 +1747,10 @@ ja:
cancel:
label: "キャンセル"
title: "バックアップ作業をキャンセルする"
confirm: "本当に実行中バックアップ作業をキャンセルしますか?"
confirm: "実行中のバックアップをキャンセルしてもよろしいですか?"
backup:
label: "バックアップ"
title: "バックアップを作成"
title: "バックアップを行います"
confirm: "新しくバックアップを行ってもよろしいですか?"
without_uploads: "はい(ファイルは含まない)"
download:
@ -1727,10 +1766,10 @@ ja:
confirm: "バックアップを復元してもよろしいですか?"
rollback:
label: "ロールバック"
title: "データベースを元の作業状態にロールバックする"
title: "データベースを前回の状態に戻します"
export_csv:
user_archive_confirm: "投稿をダウンロードしてもよろしいですか?"
success: "エスクポートを開始しました。処理が完了すると、メッセージで通知されます。"
success: "エクスポートを開始しました。処理が完了した後、メッセージでお知らせします。"
failed: "出力失敗。詳しくはログに参考してください。"
rate_limit_error: "投稿は1日に1度だけダウンロードできます。また明日お試しください。"
button_text: "エクスポート"
@ -1768,7 +1807,7 @@ ja:
explain_rescue_preview: "既定スタイルシートでサイトを表示する"
save: "保存"
new: "新規"
new_style: "新スタイル"
new_style: "新しいスタイル"
import: "インポート"
import_title: "ファイルを選択するかテキストをペースト"
delete: "削除"
@ -1826,7 +1865,7 @@ ja:
email:
title: "メール"
settings: "設定"
preview_digest: "ダイジェストのプレビュー"
preview_digest: "まとめのプレビュー"
sending_test: "テストメールを送信中..."
error: "<b>ERROR</b> - %{server_error}"
test_error: "テストメールを送れませんでした。メール設定、またはホストをメールコネクションをブロックされていないようを確認してください。"
@ -1859,7 +1898,7 @@ ja:
title: "フィルター"
user_placeholder: "ユーザ名"
address_placeholder: "name@example.com"
type_placeholder: "ダイジェスト、サインアップ..."
type_placeholder: "まとめ、サインアップ..."
reply_key_placeholder: "返信キー"
skipped_reason_placeholder: "理由"
logs:
@ -1881,7 +1920,7 @@ ja:
staff_actions:
title: "スタッフ操作"
instructions: "ユーザ名、アクションをクリックすると、リストはフィルタされます。プロフィール画像をクリックするとユーザページに遷移します"
clear_filters: "全てを表示する"
clear_filters: "すべて表示する"
staff_user: "スタッフユーザ"
target_user: "対象ユーザ"
subject: "対象"
@ -1934,7 +1973,7 @@ ja:
screened_ips:
title: "スクリーン対象IP"
description: '参加中のIPアドレス。IPアドレスをホワイトリストに追加するには "許可" を利用してください。'
delete_confirm: "%{ip_address} のルールを本当に削除しますか?"
delete_confirm: "%{ip_address} のルールを削除してもよろしいですか?"
roll_up_confirm: "Are you sure you want to roll up commonly screened IP addresses into subnets?"
rolled_up_some_subnets: "Successfully rolled up IP ban entries to these subnets: %{subnets}."
rolled_up_no_subnet: "There was nothing to roll up."
@ -1982,7 +2021,7 @@ ja:
active: 'アクティブユーザ'
new: '新規ユーザ'
pending: '保留中のユーザ'
newuser: 'トラストレベル0のユーザ (新ユーザ)'
newuser: 'トラストレベル0のユーザ (新しいユーザ)'
basic: 'トラストレベル1のユーザ (ベーシックユーザ)'
staff: "スタッフ"
admins: '管理者ユーザ'
@ -2011,17 +2050,18 @@ ja:
suspend: "凍結"
unsuspend: "凍結解除"
suspended: "凍結状態"
moderator: "モデレータ?"
admin: "管理者?"
blocked: "ブロック中?"
moderator: "モデレータ権限の所有"
admin: "管理者権限の所有"
blocked: "ブロック状態"
staged: "ステージドモードの状態"
show_admin_profile: "アカウントの管理"
edit_title: "タイトルを編集"
save_title: "タイトルを保存"
refresh_browsers: "ブラウザを強制リフレッシュ"
refresh_browsers_message: "全てのクライアントにメッセージが送信されました!"
show_public_profile: "公開されるプロフィールを見る"
show_public_profile: "公開プロフィールを見る"
impersonate: 'このユーザになりすます'
ip_lookup: "IP検索"
ip_lookup: "IPアドレスを検索"
log_out: "ログアウト"
logged_out: "すべてのデバイスでログアウトしました"
revoke_admin: '管理者権限を剥奪'
@ -2061,7 +2101,7 @@ ja:
other: "全ての投稿を削除できませんでした。%{count}日以上経過した投稿があります。(設定: delete_user_max_post_age)"
cant_delete_all_too_many_posts:
other: "全ての投稿を削除できませんでした。ユーザは%{count} 件以上投稿しています。(delete_all_posts_max)"
delete_confirm: "本当にこのユーザを削除しますか?"
delete_confirm: "このユーザを削除してもよろしいですか?"
delete_and_block: " 削除する。このメールとIPアドレスからのサインアップを以後<b>ブロック</b>"
delete_dont_block: "削除する"
deleted: "ユーザが削除されました。"
@ -2079,6 +2119,7 @@ ja:
deactivate_explanation: "アクティベート解除されたユーザは、メールで再アクティベートする必要があります。"
suspended_explanation: "凍結中のユーザはログインできません。"
block_explanation: "ブロックされているユーザは投稿およびトピックの作成ができません。"
staged_explanation: "ステージドユーザは特定のトピック宛に、メールを経由して投稿する事が出来ます。"
trust_level_change_failed: "ユーザのトラストレベル変更に失敗しました。"
suspend_modal_title: "凍結中のユーザ"
trust_level_2_users: "トラストレベル2のユーザ"
@ -2187,20 +2228,21 @@ ja:
title: バッジ
new_badge: 新しいバッジ
new: 新規
name: バッジ
name: バッジ
badge: バッジ
display_name: バッジの表示名
description: バッジの説明
long_description: 詳しい説明
badge_type: バッジの種類
badge_grouping: グループ
badge_groupings:
modal_title: バッジの振り分け
modal_title: バッジのグループ
granted_by: 'バッジをつけた人: '
granted_at: 'バッジをつけた日: '
reason_help: (投稿かトピックへのリンク)
save: バッジを保存する
delete: バッジを削除する
delete_confirm: 本当にこのバッジを削除しますか?
delete: 削除
delete_confirm: このバッジを削除してもよろしいですか?
revoke: 取り消す
reason: 理由
expand: '&hellipを展開'
@ -2212,17 +2254,17 @@ ja:
no_user_badges: "%{name} はバッジを付けられていません。"
no_badges: 付けられるバッジがありません
none_selected: "バッジを選択して開始"
allow_title: バッジは、タイトルとして使用されることを許可する
multiple_grant: 複数回付与することができます
listable: パブリックパッジページに表示するバッジ
enabled: バッジシステムを使う
allow_title: バッジタイトルとして使用されることを許可する
multiple_grant: 何度もゲットできるようにする
listable: 公開されるバッジページにバッジを表示する
enabled: バッジを有効にする
icon: アイコン
image: 画像
icon_help: "Font Awesomeのクラスか画像のURLを使用してください"
query: バッジクエリ(SQL)
target_posts: 投稿を対象
auto_revoke: 毎日失効クエリを実行
show_posts: バッジページの付与したバッジで投稿を表示
auto_revoke: 毎日クエリの取り消しを実行
show_posts: バッジページでバッジを取得したことを投稿する
trigger: トリガー
trigger_type:
none: "毎日更新する"
@ -2279,16 +2321,18 @@ ja:
search_help:
title: 'Search Help'
keyboard_shortcuts_help:
title: 'キーボードショートカット'
title: 'ショートカットキー'
jump_to:
title: 'ページ移動'
home: '<b>g</b>, <b>h</b> ホーム'
latest: '<b>g</b>, <b>l</b> 最新'
new: '<b>g</b>, <b>n</b> 新'
new: '<b>g</b>, <b>n</b> 新'
unread: '<b>g</b>, <b>u</b> 未読'
categories: '<b>g</b>, <b>c</b> カテゴリ'
top: '<b>g</b>, <b>t</b> トップ'
bookmarks: '<b>g</b>, <b>b</b> ブックマーク'
profile: '<b>g</b>, <b>p</b> プロフィール'
messages: '<b>g</b>, <b>m</b> メッセージ'
navigation:
title: 'ナビゲーション'
jump: '<b>#</b> # 投稿へ'
@ -2300,6 +2344,7 @@ ja:
title: 'アプリケーション'
create: '<b>c</b> 新しいトピックを作成'
notifications: '<b>n</b> お知らせを開く'
hamburger_menu: '<b>=</b> メニューを開く'
user_profile_menu: '<b>p</b> ユーザメニュを開く'
show_incoming_updated_topics: '<b>.</b> 更新されたトピックを表示する'
search: '<b>/</b> 検索'
@ -2308,7 +2353,7 @@ ja:
dismiss_topics: 'Dismiss Topics'
actions:
title: '操作'
bookmark_topic: '<b>f</b> トピックのブックマークをトグル'
bookmark_topic: '<b>f</b> トピックのブックマークを切り替え'
pin_unpin_topic: '<b>shift</b>+<b>p</b>トピックを ピン留め/ピン留め解除'
share_topic: '<b>shift</b>+<b>s</b> トピックをシェア'
share_post: '<b>s</b> 投稿をシェアする'
@ -2326,7 +2371,10 @@ ja:
mark_tracking: '<b>m</b>, <b>t</b> トピックを追跡する'
mark_watching: '<b>m</b>, <b>w</b> トピックを参加中にする'
badges:
granted_on: "%{date} にゲット"
title: バッジ
allow_title: "タイトルとしての使用"
multiple_grant: "何度も取得可能"
badge_count:
other: "%{count} バッジ"
more_badges:
@ -2337,7 +2385,7 @@ ja:
none: "<none>"
badge_grouping:
getting_started:
name: Getting Started
name: はじめの一歩
community:
name: コミュニティ
trust_level:
@ -2345,4 +2393,12 @@ ja:
other:
name: その他
posting:
name: 投稿中
name: 投稿
tagging:
changed: "タグを変更しました:"
sort_by: "並べ替え:"
topics:
none:
search: "検索結果は何もありません。"
bottom:
search: "検索結果は以上です。"

View File

@ -111,6 +111,8 @@ pt:
google+: 'partilhar esta hiperligação no Google+'
email: 'enviar esta hiperligação por email'
action_codes:
public_topic: "tornei este tópico publico %{when}"
private_topic: "tornei este tópico privado %{when}"
split_topic: "dividir este tópico %{when}"
invited_user: "Convidou %{who} %{when}"
removed_user: "Removeu %{who} %{when}"
@ -2115,6 +2117,7 @@ pt:
test_error: "Occorreu um problema no envio do email de teste. Por favor verifique novamente as suas definições de email, verifique se o seu host não está a bloquear conexões de email, e tente novamente."
sent: "Enviado"
skipped: "Ignorado"
bounced: "Devolvida"
received: "Recebido"
rejected: "Rejeitado"
sent_at: "Enviado em"
@ -2765,3 +2768,10 @@ pt:
bottom:
latest: "Não há mais tópicos recentes."
hot: "Não há mais tópicos quentes."
posted: "Não existem mais tópicos publicados."
read: "Não existem mais tópicos lidos."
new: "Não existem mais tópicos novos."
unread: "Não existem mais tópicos por ler."
top: "Não existem mais tópicos de topo."
bookmarks: "Não existem mais tópicos marcados."
search: "Não existem mais resultados de pesquisa."

View File

@ -554,7 +554,7 @@ ro:
username:
title: "Nume Utilizator"
instructions: "Numele de utilizator trebuie sa fie unic, fără spații, scurt."
short_instructions: "Ceilalți te pot numii @{{username}}."
short_instructions: "Ceilalți te pot menționa ca @{{username}}."
available: "Numele de utilizator este valabil."
global_match: "Emailul se potrivește numelui de utilizator înregistrat."
global_mismatch: "Deja înregistrat. Încearcă:{{suggestion}}?"
@ -1501,10 +1501,11 @@ ro:
muted:
title: "Silențios"
flagging:
title: 'De ce marcați această postare ca fiind privată?'
title: 'Mulțumim că ne ajuți să păstrăm o comunitate civilizată!'
action: 'Marcare'
take_action: "Actionează"
notify_action: 'Mesaj'
official_warning: 'Avertismen Oficial'
delete_spammer: "Șterge spammer"
delete_confirm: "Sunteți pe punctul de a șterge postarea <b>%{posts}</b> și postările <b>%{topics}</b> ale acestui uitilizator, de a-i anula contul, de a-i bloca autentificarea de la adresa IP <b>%{ip_address}</b>, adresa de email <b>%{email}</b> și de a bloca listarea permanent. Sunteți sigur ca acest utilizator este un spammer?"
yes_delete_spammer: "Da, Șterge spammer"
@ -1513,6 +1514,7 @@ ro:
submit_tooltip: "Acceptă marcarea privată"
take_action_tooltip: "Accesati permisiunea marcarii imediat, nu mai asteptati alte marcaje comune"
cant: "Ne pare rău nu puteți marca această postare deocamdată."
notify_staff: 'Notifică un moderator în privat'
formatted_name:
off_topic: "În afară discuției"
inappropriate: "Inadecvat"

View File

@ -124,7 +124,7 @@ sq:
disabled: 'hapur %{when}'
archived:
enabled: 'arkivoi %{when}'
disabled: 'çarkivuar %{when}'
disabled: 'paarkivuar %{when}'
pinned:
enabled: 'mbërthyer %{when}'
disabled: 'zbërthyer %{when}'

View File

@ -2602,8 +2602,8 @@ zh_CN:
</form>
</p>
tagging:
all_tags: "所标签"
selector_all_tags: "所标签"
all_tags: "所标签"
selector_all_tags: "所标签"
changed: "标签被修改"
tags: "标签"
choose_for_topic: "为主题选择可选标签"

View File

@ -898,7 +898,7 @@ ar:
post_excerpt_maxlength: "الحد الأقصى لطول وظيفة مقتطف / ملخص."
post_onebox_maxlength: "الحد الأقصى لطول مشاركة oneboxed Discourse بالأحرف."
onebox_domains_whitelist: "قائمة بالمجالات للسماح روابط تفصيلي؛ وينبغي دعم هذه المجالات OpenGraph أو oEmbed. اختبار لهم في http://iframely.com/debug"
logo_url: "صورة الشعار في الجزء العلوي الأيسر من موقع الويب الخاص بك، يجب أن تكون على شكل مستطيل واسع. إذا كان سيتم إظهار غادر نص عنوان موقع على بياض."
logo_url: "صورة الشعار في الجزء العلوي الأيسر من موقع الويب الخاص بك، يجب أن تكون على شكل مستطيل واسع. إذا ترك الحقل فارغا فسيتم استخدام اسم الموقع."
logo_small_url: "صورة الشعار صغيرة في الجزء العلوي الأيسر من موقع الويب الخاص بك، يجب أن تكون على شكل مربع، وينظر عند التمرير لأسفل. وإذا ترك فارغا أن أظهرت الصورة الرمزية المنزل."
favicon_url: "الأيقونة الخاصة بموقعك, شاهد http://en.wikipedia.org/wiki/Favicon, لتعمل بشكل صحيح ضمن CDN يجب ان تكون بصيغة png."
mobile_logo_url: "صورة الشعار الثابتة ستظهر في الجزء العلوي الأيسر في نسخة الجوال من موقعك. يجب أن تكون مربعة. إذا تُركت فارغة، سيتم استخدام الـ `logo_url`. على سبيل المثال: http://example.com/uploads/default/logo.png"

View File

@ -28,6 +28,7 @@ en:
short_no_year: "%B %-d"
# Format directives: http://ruby-doc.org/core-2.2.0/Time.html#method-i-strftime
date_only: "%B %-d, %Y"
long: "%B %-d, %Y, %l:%M%P"
date:
# Do not remove the brackets and commas and do not translate the first month name. It should be "null".
month_names:
@ -35,6 +36,8 @@ en:
<<: *datetime_formats
time:
<<: *datetime_formats
am: "am"
pm: "pm"
title: "Discourse"
topics: "Topics"
@ -1065,7 +1068,9 @@ en:
tl3_requires_days_visited: "Minimum number of days that a user needs to have visited the site in the last (tl3 time period) days to qualify for promotion to trust level 3. Set higher than tl3 time period to disable promotions to tl3. (0 or higher)"
tl3_requires_topics_replied_to: "Minimum number of topics a user needs to have replied to in the last (tl3 time period) days to qualify for promotion to trust level 3. (0 or higher)"
tl3_requires_topics_viewed: "The percentage of topics created in the last (tl3 time period) days that a user needs to have viewed to qualify for promotion to trust level 3. (0 to 100)"
tl3_requires_topics_viewed_cap: "The maximum required number of topics viewed in the last (tl3 time period) days."
tl3_requires_posts_read: "The percentage of posts created in the last (tl3 time period) days that a user needs to have viewed to qualify for promotion to trust level 3. (0 to 100)"
tl3_requires_posts_read_cap: "The maximum required number of posts read in the last (tl3 time period) days."
tl3_requires_topics_viewed_all_time: "The minimum total number of topics a user must have viewed to qualify for trust level 3."
tl3_requires_posts_read_all_time: "The minimum total number of posts a user must have read to qualify for trust level 3."
tl3_requires_max_flagged: "User must not have had more than x posts flagged by x different users in the last (tl3 time period) days to qualify for promotion to trust level 3, where x is this setting's value. (0 or higher)"
@ -1161,6 +1166,7 @@ en:
reply_by_email_enabled: "Enable replying to topics via email."
reply_by_email_address: "Template for reply by email incoming email address, for example: %{reply_key}@reply.example.com or replies+%{reply_key}@example.com"
incoming_email_prefer_html: "Use the HTML instead of the text for incoming email. May cause unexcpeted formatting issues!"
disable_emails: "Prevent Discourse from sending any kind of emails"
@ -1300,6 +1306,7 @@ en:
default_email_private_messages: "Send an email when someone messages the user by default."
default_email_direct: "Send an email when someone quotes/replies to/mentions or invites the user by default."
default_email_mailing_list_mode: "Send an email for every new post by default."
default_email_mailing_list_mode_frequency: "Users who enable mailing list mode will receive emails this often by default."
disable_mailing_list_mode: "Disallow users from enabling mailing list mode."
default_email_always: "Send an email notification even when the user is active by default."
default_email_previous_replies: "Include previous replies in emails by default."
@ -2278,6 +2285,15 @@ en:
more_topics: "There were %{new_topics_since_seen} other new topics."
more_topics_category: "More new topics:"
mailing_list:
why: "All activity on %{site_link} for %{date}"
subject_template: "[%{site_name}] Summary for %{date}"
unsubscribe: "This summary is sent daily due to mailing list mode being enabled. To unsubscribe %{unsubscribe_link}."
from: "%{site_name} summary"
new_topics: "New topics"
topic_updates: "Topic updates"
view_this_topic: "View this topic"
back_to_top: "Back to top"
forgot_password:
subject_template: "[%{site_name}] Password reset"
text_body_template: |

View File

@ -31,6 +31,7 @@ es:
incoming:
default_subject: "Email entrante desde %{email}"
show_trimmed_content: "Mostrar contenido recortado"
maximum_staged_user_per_email_reached: "Alcanzado el número máximo de usuarios provisionales creados por email."
errors:
empty_email_error: "Sucede cuando el texto en bruto del email que recibimos está en blanco."
no_message_id_error: "Sucede cuando el email no tiene Id del mensaje en el encabezado."
@ -44,7 +45,7 @@ es:
reply_user_not_matching_error: "Sucede cuando una respuesta vino de una dirección de email diferente a la que fue enviada la notificación."
topic_not_found_error: "Sucede cuando entró una respuesta pero el tema relacionado ha sido eliminado."
topic_closed_error: "Sucede cuando entró una respuesta pero el tema relacionado ha sido cerrado. "
bounced_email_report: "El email es un reporte que ha rebotado."
bounced_email_error: "El email es un reporte de correo rebotado."
auto_generated_email_reply: "El email contiene una respuesta a un correo autogenerado."
screened_email_error: "Sucede cuando la dirección de email del remitente ya ha sido filtrada."
errors: &errors
@ -1120,6 +1121,8 @@ es:
default_categories_tracking: "Lista de categorías que están seguidas por defecto"
default_categories_muted: "Lista de categorías que están silenciadas por defecto."
tagging_enabled: "¿Activar etiquetas para los temas?"
min_trust_to_create_tag: "El mínimo nivel de confianza requerido para crear una etiqueta."
max_tags_per_topic: "El máximo número de etiquetas que se pueden añadir a un tema."
errors:
invalid_email: "Dirección de correo electrónico inválida. "
invalid_username: "No existe ningún usuario con ese nombre de usuario. "

View File

@ -24,7 +24,7 @@ fi:
loading: "Lataa"
powered_by_html: 'Voimanlähteenä <a href="http://www.discourse.org">Discourse</a>, toimii parhaiten, kun JavaScript on käytössä'
log_in: "Kirjaudu"
purge_reason: "Poistettu automaattisesti hylättynä, aktivoimattomana tilinä"
purge_reason: "Hylätty, aktivoimaton tili poistettiin automaattisesti"
disable_remote_images_download_reason: "Linkattujen kuvien lataaminen poistettiin käytöstä vähäisen tallennustilan vuoksi."
anonymous: "Anonyymejä"
emails:
@ -172,7 +172,8 @@ fi:
private_posts: "Uusimmat yksityisviestit"
group_posts: "Uusimmat viestit ryhmässä %{group_name}"
group_mentions: "Uusimmat maininnat ryhmässä %{group_name}"
tag: "Tagatut aiheet"
user_posts: "Viimeisimmät viestit käyttäjältä @%{username}"
user_topics: "Viimeisimmät ketjut käyttäjältä @%{username}"
too_late_to_edit: "Tämä viesti luotiin liian kauan sitten. Sitä ei voi enää muokata tai poistaa."
revert_version_same: "Nykyinen revisio on sama, kuin jonka yrität palauttaa."
excerpt_image: "kuva"

View File

@ -31,6 +31,7 @@ fr:
incoming:
default_subject: "Courriel arrivant de %{email}"
show_trimmed_content: "Montrer le contenu raccourci"
maximum_staged_user_per_email_reached: "Vous avez atteint le nombre maximal d'utilisateurs qui peuvent être créés par mail."
errors:
empty_email_error: "Arrive quand le courriel reçu était vide."
no_message_id_error: "Arrive quand le courrier n'a pas d'en-tête \"Message-Id\"."
@ -44,7 +45,7 @@ fr:
reply_user_not_matching_error: "Arrive quand une réponse est venue d'une adresse de courriel différente de celle où a été envoyée la notification."
topic_not_found_error: "Arrive quand quelqu'un répond à un sujet qui a été supprimé."
topic_closed_error: "Arrive quand quelqu'un répond mais le sujet lié a été fermé."
bounced_email_report: "Le courriel est un rapport de courriel rejeté."
bounced_email_error: "Le courriel est un rapport de courriel rejeté."
auto_generated_email_reply: "Email contient une réponse à un email automatiquement généré."
screened_email_error: "Arrive quand l'adresse courriel de l'expéditeur est déjà sous surveillance."
errors: &errors
@ -713,6 +714,9 @@ fr:
site_contact_username_warning: "Saisissez le pseudo d'un responsable sympathique à partir duquel sera envoyé les messages importants. Mettez à jour site_contact_username dans les <a href='/admin/site_settings'>Paramètres du site</a>."
notification_email_warning: "Les courriels de notification ne serot pas envoyés depuis une adresse de courriel valide sur votre domaine ; l'envoie des courriels sera aléatoire et peu fiable. Veuillez saisir une adresse de courriel locale dans notification_email dans les <a href='/admin/site_settings'>Paramètres du site</a>."
subfolder_ends_in_slash: "Votre configuration de sous-répertoire est erronée; DISCOURSE_RELATIVE_URL_ROOT se termine avec une barre oblique ."
email_polling_errored_recently:
one: "La vérification des mails a généré une erreur au cours des 24 dernières heures. Vérifiez <a href='/logs' target='_blank'>le journal</a> pour plus de détails."
other: "La vérification des mails a généré %{count} erreurs au cours des 24 dernières heures. Vérifiez <a href='/logs' target='_blank'>le journal</a> pour plus de détails."
bad_favicon_url: "Impossible de charger la favicon. Vérifiez le paramètre favicon_url dans les <a href='/admin/site_settings'>paramètres du site</a>"
site_settings:
censored_words: "Mots qui seront automatiquement remplacés par &#9632;&#9632;&#9632;&#9632;"
@ -1105,10 +1109,8 @@ fr:
default_categories_watching: "Liste de catégories surveillées par défaut."
default_categories_tracking: "Liste de catégories suivies par défaut."
default_categories_muted: "Liste de catégories silencées par défaut."
tagging_enabled: "Autoriser les utilisateurs à mettre des tags sur les sujets ?"
min_trust_to_create_tag: "Le niveau de confiance requis pour créer un tag."
max_tags_per_topic: "Le nombre maximum de tags qui peuvent être ajouté à un sujet."
max_tag_length: "The nombre maximum de caractères qui peuvent être utilisés pour un tag."
tagging_enabled: "Activer les tags sur les sujets ?"
tag_style: "Style visuel pour tag badges."
errors:
invalid_email: "Adresse de courriel invalide."
invalid_username: "Il n'y a pas d'utilisateur ayant ce pseudo."
@ -1929,6 +1931,7 @@ fr:
avatar:
missing: "Désolé, nous ne parvenons pas à trouver un avatar associé à cette adresse mail. Pouvez-vous essayer de la télécharger à nouveau ?"
email_log:
post_user_deleted: "L'auteur du message a été supprimé."
no_user: "Impossible de trouver l'utilisateur avec l'id %{user_id}"
anonymous_user: "L'utilisateur est anonyme"
suspended_not_pm: "L'utilisateur est suspendu, pas de message"
@ -2211,25 +2214,23 @@ fr:
Ce badge est accordé lorsque vous utilisez tous les 50 de vos j'aime quotidiens. Rappelez-vous de prendre un moment pour aimer les messages qui vous plaisent et d'apprécier encourager vos membres de la communauté pour créer encore plus de grandes discussions à l'avenir.
higher_love:
name: Amour plus fort
description: A utilisé 50 likes en un jour 5 fois
long_description: |
Ce badge est accordé lorsque vous utilisez tous les 50 j'aime par jour pendant 5 jours. Merci de prendre le temps activement d'encourager les meilleures conversations chaque jour!
crazy_in_love:
name: Fou amoureux
description: A utilisé 50 likes en un jour 20 fois
long_description: |
Ce badge est accordé lorsque vous utilisez tous les 50 de vos j'aime par jour pendant 20 jours. Hou la la! Vous êtes un modèle de régulièrement encourager vos membres de la communauté!
thank_you:
name: 'Merci '
description: A 20 messages ayant reçu un j'aime et a donné 10 j'aime
long_description: "Ce badge vous est accordé quand vous avez reçu 20 j'aime sur vos messages et en avez donné 10 ou plus en retour. Quand quelqu'un aime vos messages, vous trouvez le temps d'aimer ce que les autres postent à leur tour. \n"
gives_back:
name: Redonne
description: A 100 messages ayant reçu un j'aime et a donné 100 j'aime
long_description: |
Ce badge vous est accordé quand vous avez reçu 100 j'aime et en avez donné 100 ou plus en retour. Merci pour tout cela.
empathetic:
name: Empathique
description: A 500 messages ayant reçu un j'aime et a donné 1000 j'aime
long_description: "Ce badge vous est accordé quand vous avez reçu 500 j'aime et en avez donné 1000 ou plus en retour. Whaou ! Vous êtes un modèle de générosité et d'amour mutuel :two_hearts:. \n"
first_emoji:
name: Premier Emoji
description: A utilisé un emoji dans un message
@ -2253,9 +2254,10 @@ fr:
initial_topic_title: Rapports de performances du site
topic_invite:
user_exists: "Désolé, cet utilisateur a déjà été invité. Vous ne pouvez inviter un utilisateur qu'une seule fois par sujet."
tags:
title: "Tags"
time:
<<: *datetime_formats
activemodel:
errors:
<<: *errors
rss_by_tag: "Sujets portant le tag %{tag}"

View File

@ -159,8 +159,16 @@ it:
rss_description:
latest: "Argomenti più recenti"
hot: "Argomenti caldi"
top: "Argomenti di punta"
posts: "Ultimi messaggi"
private_posts: "Ultimi messaggi privati"
group_posts: "Ultimi messaggi da %{group_name}"
group_mentions: "Ultime menzioni da %{group_name}"
user_posts: "Ultimi messaggi di @%{username}"
user_topics: "Ultimi argomenti di @%{username}"
tag: "Argomenti etichettati"
too_late_to_edit: "Questo messaggio è stato creato troppo tempo fa. Non può più essere modificato né cancellato."
revert_version_same: "La versione attuale è la stessa versione che stai cercando di ripristinare."
excerpt_image: "immagine"
queue:
delete_reason: "Cancellato attraverso la coda di moderazione"
@ -169,6 +177,7 @@ it:
can_not_modify_automatic: "Non puoi modificare un gruppo automatico"
member_already_exist: "'%{username}' è già membro di questo gruppo."
invalid_domain: "'%{domain}' non è un dominio valido."
invalid_incoming_email: "'%{email}' non è un indirizzo email valido."
default_names:
everyone: "chiunque"
admins: "amministratori"
@ -728,7 +737,7 @@ it:
share_links: "Determina quali elementi appaiono nella finestra di condivisione e in quale ordine."
track_external_right_clicks: "Segui i collegamenti esterni sui quali viene fatto click destro (es: apri in una nuova tab). Disabilitato di default perché riscrive le URL"
site_contact_username: "Un utente dello staff valido da cui inviare tutti i messaggi automatici. Se lasciato vuoto verrà usato l'account System di default."
send_welcome_message: "nvia a tutti i nuovi utenti un messaggio di benvenuto con una guida di avvio rapido."
send_welcome_message: "Invia a tutti i nuovi utenti un messaggio di benvenuto con una guida di avvio rapido."
suppress_reply_directly_below: "Non mostrare il conteggio espandibile delle risposte quando c'è una sola risposta sotto quel messaggio."
suppress_reply_directly_above: "Non mostrare in-risposta-a espandibile in un messaggio quando c'è una sola risposta sopra quel messaggio. "
suppress_reply_when_quoting: "Non mostrare in-risposta-a espandibile in un messaggio quando il messaggio include la citazione."
@ -1273,6 +1282,10 @@ it:
privacy_topic:
title: "Politica della Privacy"
badges:
welcome:
description: Hai ricevuto un Mi piace
great_topic:
description: Hai ricevuto 50 Mi piace su 1 argomento
first_like:
name: Primo "Mi piace"
description: Ha messo "Mi piace" a un messaggio
@ -1286,11 +1299,21 @@ it:
name: Primo Collegamento
first_quote:
description: Ha citato un messaggio
appreciated:
description: Hai ricevuto 1 Mi piace su 20 messaggi
respected:
description: Hai ricevuto 2 Mi piace su 100 messaggi
admired:
description: Hai ricevuto 5 Mi piace su 300 messaggi
admin_login:
success: "email Inviata"
error: "Errore!"
email_input: "Email Amministratore"
submit_button: "Invia Email"
tags:
title: "Etichette"
staff_tag_remove_disallowed: "L'etichetta \"%{tag}\" può essere cancellata soltanto dallo staff."
rss_by_tag: "Argomenti etichettati %{tag}"
time:
<<: *datetime_formats
activemodel:

View File

@ -9,7 +9,7 @@ ja:
dates:
short_date_no_year: "MMM D"
short_date: "YYYY MMM D"
long_date: "MMMM D, YYYY h:mma"
long_date: "YYYY MMMM D h:mma"
date:
month_names: [null, 1月, 2月, 3月, 4月, 5月, 6月, 7月, 8月, 9月, 10月, 11月, 12月]
title: "Discourse"
@ -23,20 +23,21 @@ ja:
emails:
incoming:
default_subject: "%{email}からメール"
show_trimmed_content: "続きを読む"
errors: &errors
format: '%{attribute} %{message}'
messages:
too_long_validation: "は、最大文字数(%{max}文字)を超えています。(入力したのは%{length}文字 ) "
invalid_boolean: "無効なboolean."
invalid_boolean: "無効な選択肢"
taken: "は既に使用されています"
accepted: に同意する必要があります
blank: を入力してください
present: は入力しないでください
confirmation: "と%{attribute}の入力が一致しません"
empty: 本文が未入力です。.
empty: 本文が入力されていません
equal_to: は%{count}にしてください
even: は偶数にしてください
exclusion: 予約されています
exclusion: すでに使われています
greater_than: は%{count}より大きい値にしてください
greater_than_or_equal_to: は%{count}以上の値にしてください
has_already_been_used: "は既に使用されています"
@ -74,7 +75,7 @@ ja:
not_logged_in: "ログインしてください。"
not_found: "リクエストされたURL、リソースは見つかりませんでした"
invalid_access: "リクエストしたリソースの閲覧が許可されていません"
read_only_mode_enabled: "このサイトは読み取り専用モードです。会話は無効になっています。"
read_only_mode_enabled: "このサイトは閲覧専用状態です。変更などの操作は無効になっています。"
too_many_replies:
other: "申し訳ありません、新しいユーザーの同じトピックへの返信は、一時的に %{count} 回に制限されています。"
embed:
@ -82,12 +83,14 @@ ja:
continue: "議論を続ける"
more_replies:
other: "%{count} 以上の返信"
loading: "会話をロードしています…"
loading: "会話を読み込んでいます…"
permalink: "パーマリンク"
imported_from: "これは、オリジナルエントリ%{link}に対するディスカッショントピックです"
in_reply_to: "▶ %{username}"
replies:
other: "%{count} 通の返信"
no_mentions_allowed: "あなたは他のユーザへメンションを送ることができません。"
no_images_allowed: "新規ユーザは投稿に画像を付ける事はできません。"
spamming_host: "申し訳ありませんが、このホストへのリンクを貼ることはできません。"
user_is_suspended: "アカウントが凍結中のユーザーは投稿ができません。"
topic_not_found: "問題が発生しました。トピックがクローズしたか、閲覧中に削除された可能性があります。"
@ -108,9 +111,10 @@ ja:
read_full_topic: "完全なトピックを読む"
private_message_abbrev: "メッセージ"
rss_description:
latest: "最新トピック"
latest: "最新トピック"
hot: "ホットトピック"
posts: "最近の投稿"
private_posts: "最新のプライベートメッセージ"
too_late_to_edit: "この投稿の編集・削除期間が過ぎました。編集・削除が出来ません。"
excerpt_image: "画像"
queue:
@ -161,11 +165,12 @@ ja:
回答を追加する代わりに、以前の回答を編集するか、別のトピックを訪れる事を検討してください。
reviving_old_topic: |
### このトピックを復活させすか?
### このトピックを復活させてもよろしいですか?
このトピックの最後の回答は%{days}日前です。あなたの回答はトピックを一覧のトップに上げて、以前回答した誰がか気付きます。
このトピックへの最後の返信は%{days}日前です。
あなたの返信はトピック一覧の一番上に移動させ、以前に返信した人宛に通知が送られます。
本当に過去の議論を続けますか?
本当に過去の会話を復元してもよろしいですか?
activerecord:
attributes:
category:
@ -209,7 +214,7 @@ ja:
lounge_welcome:
title: "ラウンジへようこそ"
category:
topic_prefix: "%{category} カテゴリの定義"
topic_prefix: "%{category}カテゴリについて"
errors:
uncategorized_parent: "未分類カテゴリは親カテゴリに設定出来ません。"
self_parent: "自分自身がサブカテゴリの親になることはできません"
@ -222,7 +227,7 @@ ja:
topic_exists_no_oldest: "%{count}個のトピックを持っているため、このカテゴリを削除できません。"
trust_levels:
newuser:
title: "新ユーザ"
title: "新しいユーザ"
basic:
title: "ベーシックユーザ"
change_failed_explanation: "%{user_name} を '%{new_trust_level}' に格下げしようとしましたが、既にトラストレベルが '%{current_trust_level}' です。%{user_name} は '%{current_trust_level}' のままになります - もしユーザーを降格させたい場合は、トラストレベルをロックしてください"
@ -236,15 +241,15 @@ ja:
other: "%{count} 秒"
datetime:
distance_in_words:
half_a_minute: "< 1分"
half_a_minute: "1分"
less_than_x_seconds:
other: "< %{count} 秒"
x_seconds:
other: "%{count} 秒"
less_than_x_minutes:
other: "< %{count} 分"
other: "%{count}分"
x_minutes:
other: "%{count} 分"
other: "%{count}分"
about_x_hours:
other: "%{count} 時間"
x_days:
@ -266,9 +271,9 @@ ja:
x_seconds:
other: "%{count} 秒前"
less_than_x_minutes:
other: "%{count} 分未満"
other: "%{count}分未満"
x_minutes:
other: "%{count} 分前"
other: "%{count}分前"
about_x_hours:
other: "%{count} 時間前"
x_days:
@ -534,7 +539,7 @@ ja:
title_nag: "サイトの名前が正しくありません。<a href='/admin/site_settings'>サイトの設定</a>で更新してください"
site_description_missing: "検索結果に表示される説明文を入力してください。<a href='/admin/site_settings'>サイトの設定</a>で更新してください"
consumer_email_warning: "サイトはメール送信に Gmail (または他のカスタムメールサービス) を利用するように設定されています。<a href='http://support.google.com/a/bin/answer.py?hl=en&answer=166852' target='_blank'>Gmail で送信可能なメール数には制限があります</a>。メールを確実に送信するために mandrill.com などのメールサービスプロバイダーの利用を検討してください。"
site_contact_username_warning: "重要な自動メッセージを送信するフレンドリースタッフユーザーアカウントの名前を入力してください。<a href='/admin/site_settings'>サイト設定</a> のsite_contact_username を更新してください。"
site_contact_username_warning: "重要なメッセージを送るために、スタッフユーザの名前を入力してください。<a href='/admin/site_settings'>サイト設定</a> のsite_contact_username を更新してください。"
notification_email_warning: "通知用メールがあなたのドメインで有効なメールアドレスから送信されていません。メール配信が不安定になり、信頼性が低くなります。\n<a href='/admin/site_settings'>サイトの設定</a>で更新してください"
site_settings:
censored_words: "自動的に &#9632;&#9632;&#9632;&#9632; で置換されます"
@ -583,12 +588,12 @@ ja:
notification_email: "The from: email address used when sending all essential system emails. The domain specified here must have SPF, DKIM and reverse PTR records set correctly for email to arrive."
email_custom_headers: "カスタムメールヘッダのリスト (パイプ(バーティカルバー) 区切り)"
email_subject: "標準のメールタイトルをカスタマイズできます。https://meta.discourse.org/t/customize-subject-format-for-standard-emails/20801 を参照してください"
use_https: "サイトのURL(Discourse.base_url)をhttpかhttpsにしますか \"既に設定が完了し、動作していない限り、HTTPSは選択しないでください!\""
summary_score_threshold: "'トピックサマリー'に投稿が含まれるために必要な最低スコア"
summary_posts_required: "'トピックサマリー'が有効になるために必要な最小投稿数"
summary_likes_required: "'トピックサマリー'が有効になるために必要な最小「いいね!」数"
summary_percent_filter: "ユーザが'トピックサマリー'をクリックしたとき, 上位何パーセントのポストを表示するか"
summary_max_results: "'トピックサマリー'として返却される最大ポスト数"
enable_private_messages: "トラストレベル1のユーザにメッセージの作成と返信を許可する(最小のトラストレベルを介して設定可能なメッセージを送信します)"
enable_long_polling: "通知用のメッセージバスによるロングポーリングの利用を許可する"
long_polling_base_url: "ロングポーリングのベースURL(CDNが動的コンテンツを配信している場合、これをoriginに指定してください) eg: http://origin.site.com"
long_polling_interval: "ユーザに送信するデータが存在しないとき、サーバが待機する時間(ログインユーザーのみ)"
@ -601,7 +606,7 @@ ja:
tl2_additional_likes_per_day_multiplier: "この数字を掛けると TL2 (メンバー) の1日あたりの「いいね」の上限を増やします"
tl3_additional_likes_per_day_multiplier: "この数字を掛けると TL3 (レギュラー) の1日あたりの「いいね」の上限を増やします"
tl4_additional_likes_per_day_multiplier: "この数字を掛けると TL4 (リーダー) の1日あたりの「いいね」の上限を増やします"
num_flags_to_block_new_user: "新規ユーザの投稿に対して、何人のユーザによりここで指定した数のスパムフラグが立てられたら、全てのポストを非表示状態にした上でこのユーザからのポストを拒否するか。0 で無効化"
num_flags_to_block_new_user: "もし新しいユーザがnum_users_to_block_new_userで定義されている数の通報を受けたらそれらの投稿を全て非表示にし、今後の投稿をブロックします。0で無効にします。"
num_users_to_block_new_user: "新規ユーザのポストに対して、ここで指定した数のユーザにより何個のスパムフラグが立てられたら、全てのポストを非表示状態にした上でこのユーザからのポストを拒否するか。0 で無効化"
notify_mods_when_user_blocked: "ユーザが自動的にブロックされた際に、すべてのモデレータにメッセージを送信する。"
flag_sockpuppets: "トピックを作成したユーザーと同じIPアドレスで、新規ユーザーがトピックに回答した場合、両者を潜在的なスパムとしてフラグを立てるか"
@ -615,7 +620,7 @@ ja:
enable_noscript_support: "noscript タグ経由でアクセスしてきた標準サーチエンジンクローラのサポートを有効にする"
allow_moderators_to_create_categories: "モデレータのカテゴリ作成を許可"
cors_origins: "CORSを許可。オリジンはhttp://かhttps://を含む必要があります。CORSを有効にするには、環境変数 DISCOURSE_ENABLE_CORSにtrueをセットする必要があります"
top_menu: "ホームナビゲーゲションに表示する項目、表示順を指定。例: latest|new|unread|categories|top|read|posted|bookmarks"
top_menu: "ホームナビゲーションに表示する項目・表示順を指定。例: latest|new|unread|categories|top|read|posted|bookmarks"
post_menu: "投稿メニューに表示する項目を指定。例 like|edit|flag|delete|share|bookmark|reply"
post_menu_hidden_items: "開くボタンをクリックするまで投稿のメニュー項目を隠します"
share_links: "シェアダイアログに表示する項目、表示順を指定"
@ -632,13 +637,13 @@ ja:
show_email_on_profile: "プロフィールのメールアドレスを表示(自分とスタッフのみ閲覧できます)"
email_token_valid_hours: "パスワードリマインダ、アカウントアクティベート時のトークンを何時間有効にするか"
email_token_grace_period_hours: "パスワードリマインダ、アカウントアクティベート時のトークンを無効するときに、何時間猶予を与えるか"
enable_badges: "バッジシステムを有効にする"
enable_badges: "バッジ機能を有効にする"
allow_index_in_robots_txt: "サーチエンジンにインデックスを許可するようにrobots.txtを指定する"
email_domains_blacklist: "ユーザーがアカウント登録をすることができない、パイプ区切りのドメイン名のリスト。 例 : mailinator.com|trashmail.net"
email_domains_whitelist: "ユーザー登録に必要なパイプ区切りのメールドメインのリスト。警告: 指定したメールドメイン以外のユーザは許可されません!"
forgot_password_strict: "パスワードリマインダダイアログで、アカウントの存在を通知しない"
log_out_strict: "ログアウトした際に、そのユーザーの全デバイスのセッションをログアウトさせる"
version_checks: "Discourse Hub にアップデート、新バージョンの有無を問い合わせ /admin ダッシュボードにバージョンメッセージを表示する"
version_checks: "Discourse Hubからのアップデートを確認し、管理ページにバージョンやアップデートメッセージを表示する"
new_version_emails: "Discourseの新しいバージョンが利用可能になった際に contact_email アドレスにメールで通知する"
port: "開発者用! 警告! デフォルトの80番ポートではなく、ここで指定した HTTP ポートを利用する。空欄でデフォルトの80番ポートを利用。"
force_hostname: "開発者用! 警告! URL 内のホスト名を指定。空欄でデフォルト値を利用。"
@ -658,7 +663,7 @@ ja:
sso_overrides_avatar: "SSOペイロードから取得した外部サイトのプロフィール画像でローカルのプロフィール画像を上書きする。有効にする場合、プロフィール画像のアップデートを無効にする事を強く薦めます"
sso_not_approved_url: "このURLに承認されていないSSOアカウントをリダイレクト"
enable_local_logins: "ローカルのユーザ名、パスワードでのログインを有効にする (注意: 招待を使用するには有効にする必要があります)"
allow_new_registrations: "新規ユーザー登録を許可。誰でもユーザーを作れるのを防ぐには、チェックを外してください。"
allow_new_registrations: "新しいユーザの登録を許可。ユーザを誰でも作れないようにするためには、チェックを外してください。"
enable_yahoo_logins: "Yahoo 認証を有効にする"
enable_google_oauth2_logins: "グーグル Oauth2 認証を有効にします。これはグーグルが現在サポートしている認証方式です。key と secret が必要です。"
google_oauth2_client_id: "あなたのGoogleアプリケーションのクライアントID"
@ -678,12 +683,12 @@ ja:
enable_s3_backups: "完了時にS3にバックアップをアップロードします。重要: 有効なS3 credentialsがファイル設定に必要です"
s3_backup_bucket: "バックアップを保持するバケット。 警告: 必ずプライベートバケットになっていることを確認してください"
active_user_rate_limit_secs: "'last_seen_at' フィールドを更新する頻度 (秒)"
verbose_localization: "ローカライゼーションtipsを展開するUIを表示する"
verbose_localization: "翻訳者向けの機能を表示をします"
previous_visit_timeout_hours: "'previous' visit とみなす時間 (時間)"
rate_limit_create_topic: "トピック作成後、次のトピックを作成するまでにユーザが待たなければならない時間 (秒)"
rate_limit_create_post: "ポスト投稿後、次のポストを投稿するまでにユーザが待たなければならない時間 (秒)"
rate_limit_new_user_create_topic: "トピック作成後、次のトピックを作成するまでに新規ユーザが待たなければならない時間 (秒)"
rate_limit_new_user_create_post: "ポスト投稿後、次のポストを投稿するまでに新ユーザが待たなければならない時間 (秒)"
rate_limit_new_user_create_topic: "新しいユーザがトピックを作った後、次のトピックが作成できるまでの時間(秒)"
rate_limit_new_user_create_post: "投稿後、次のポストを投稿するまでに新しいユーザが待たなければならない時間 (秒)"
max_likes_per_day: "ユーザが一日に「いいね!」できる最大数"
max_flags_per_day: "ユーザが一日に行える通報の回数"
max_bookmarks_per_day: "ユーザが一日にブックマークできる最大数"
@ -725,11 +730,11 @@ ja:
tl3_links_no_follow: "トラストレベル3のユーザのポスト内のrel=nofolowを削除しない"
min_trust_to_create_topic: "新規にトピックを作成するために必要な最低トラストレベル。"
min_trust_to_edit_wiki_post: "ポストをwikiにするために必要な最低トラストレベル"
newuser_max_links: "新規ユーザがポスト内に作成できるリンクの数"
newuser_max_images: "新規ユーザがポスト内にアップロードできる画像の数"
newuser_max_attachments: "新規ユーザがポスト内に添付できるファイルの数"
newuser_max_mentions_per_post: "新規ユーザがポスト内で @name で通知できる最大数"
newuser_max_replies_per_topic: "新ユーザが1つのトピックで誰かがそれに回答するまでに回答できる最大数"
newuser_max_links: "新しいユーザが投稿内に貼れるリンクの数"
newuser_max_images: "新しいユーザが投稿内にアップロードできる画像の数"
newuser_max_attachments: "新しいユーザが投稿内に添付できるファイルの数"
newuser_max_mentions_per_post: "新しいユーザが投稿内で @name で通知できる最大の数"
newuser_max_replies_per_topic: "新しいユーザが1つのトピックで誰かがそれに回答するまでに回答できる最大数"
max_mentions_per_post: "ユーザがポスト内で@name で通知できる最大数"
create_thumbnails: "大きすぎる画像はポストにフィットするように、サムネイルを作成しlightbox 画像を作成する"
email_time_window_mins: "ユーザによるポストの最終編集チャンスを与えるために、通知用メール送信までに待つ時間 (分)"
@ -760,7 +765,7 @@ ja:
topic_post_like_heat_low: "いいね数/ ポスト数の比率がこの比率を超えると、ポスト数のフィールドがやや強調されます"
topic_post_like_heat_medium: "いいね数/ ポスト数の比率がこの比率を超えると、ポスト数のフィールドが適度に強調されます"
topic_post_like_heat_high: "いいね数/ ポスト数の比率がこの比率を超えると、ポスト数のフィールドが強く強調されます"
faq_url: "他サイトに FAQ をホストしている場合は、フル URL をここに指定。"
faq_url: "FAQが他のサイトにある場合、URLをここに指定します。"
tos_url: "他サイトに利用規約をホストしている場合は、フル URL をここに指定。"
privacy_policy_url: "他サイトにプライバシーポリシーをホストしている場合は、フル URL を個々に指定。"
white_listed_spam_host_domains: "スパムホスト検査から除外するドメインのリスト。新規ユーザはこれらのドメインでポスト内にリンクを作成することを制限されません"
@ -806,9 +811,9 @@ ja:
allow_animated_thumbnails: "アニメgifからアニメーションサムネイルを生成する"
default_avatars: "新規ユーザが変更するまで使用されるデフォルトのプロフィール画像URL"
automatically_download_gravatars: "アカウントの生成時、メールアドレスの変更時にGravatarをダウンロード"
digest_topics: "ダイジェストメールに表示されるトピックの最大数"
digest_min_excerpt_length: "ダイジェストメール内の投稿の抜粋の最小文字数"
disable_digest_emails: "全てのユーザのダイジェストメールを無効にする"
digest_topics: "まとめメールに表示されるトピックの最大数"
digest_min_excerpt_length: "まとめメール内の投稿の抜粋の最小文字数"
disable_digest_emails: "すべてのユーザのまとめメールを無効にする"
detect_custom_avatars: "ユーザがプロフィール画像をアップロードしたか確認する"
max_daily_gravatar_crawls: "Discourseがプロフィール画像の確認をgravastarに行う回数の上限"
public_user_custom_fields: "パブリックに公開されるカスタムフィールドのホワイトリスト"
@ -839,7 +844,7 @@ ja:
embed_by_username: "embedされたトピックの作成者として表示されるDiscourseユーザー名"
embed_username_key_from_feed: "フィードからDsicourseユーザ名をプルするキー"
embed_truncate: "embedされた投稿をtruncateする"
embed_post_limit: "embedで表示する投稿の最大数"
embed_post_limit: "表示可能な投稿の最大数を埋め込む"
embed_whitelist_selector: "embedを許可するエレメントのCSS Selector"
embed_blacklist_selector: "embedから削除するエレメントのCSS Selector"
notify_about_flags_after: "この数時間後に処理されていない通報がある場合は、contact_emailにメールを送信する。0を設定すると無効になります"
@ -852,6 +857,7 @@ ja:
emoji_set: "How would you like your emoji?"
enforce_square_emoji: "絵文字のアスペクト比を強制的に揃える"
approve_unless_trust_level: "トラストレベル以下のユーザーの投稿には承認が必要"
default_email_previous_replies: "デフォルトでメールの文章に以前の返信を含める"
errors:
invalid_email: "不正なメールアドレスです"
invalid_username: "そのユーザ名のユーザは存在しません"
@ -894,7 +900,7 @@ ja:
not_seen_in_a_month: "お帰りなさい! 最近見かけませんでしたね。 これらがあなたが離れてから最も人気のトピックです"
move_posts:
new_topic_moderator_post:
other: "%{count} 件のポストを新しいトピックに分割しました: %{topic_link}"
other: "%{count}件の投稿を新しいトピックに分割しました: %{topic_link}"
existing_topic_moderator_post:
other: "%{count} 件のポストを既存のトピックにマージしました: %{topic_link}"
change_owner:
@ -945,7 +951,7 @@ ja:
something_already_taken: "エラーが発生しました。ユーザ名またはメールアドレスが既に使用中の可能性があります。パスワードリセットを行ってください。"
omniauth_error: "あなたの アカウントの認可に失敗しました。アカウントの認可を許可したか確認してください"
omniauth_error_unknown: "ログインに失敗しました。もう一度試してください。"
new_registrations_disabled: "新規登録は、この時点で許可されていません"
new_registrations_disabled: "新規登録は現在行えません。"
password_too_long: "パスワードは200文字までです"
email_too_long: "メールアドレスが長過ぎます。アドレス部は254文字以内に、ドメイン部は253文字以内にする必要があります"
reserved_username: "そのユーザー名は許可されていません"
@ -964,7 +970,7 @@ ja:
blocked: "は許可されていません。"
ip_address:
blocked: "あなたのIPアドレスからの新規登録は許可されていません"
max_new_accounts_per_registration_ip: "あなたのIPアドレスからの新規登録は許可されていません(最大数に達しました)。スタッフメンバーに連絡してください"
max_new_accounts_per_registration_ip: "あなたのIPアドレスからの新規登録は行えません(登録可能な数を超えています)。スタッフへお問い合わせください。"
flags_reminder:
subject_template:
other: "%{count}件の通報が対応待ちです"
@ -1002,9 +1008,36 @@ ja:
test_mailer:
subject_template: "[%{site_name}] メール送信テスト"
new_version_mailer:
subject_template: "[%{site_name}] New Discourse version, update available"
subject_template: "[%{site_name}] Discourseの新しいバージョンがあります。"
text_body_template: |
最新版の[Discourse](http://www.discourse.org)が利用出来ます!
現在利用しているバージョン: %{installed_version}
新しいバージョン: **%{new_version}**
- 更新は**[ワンクリックブラウザ・アップグレード](%{base_url}/admin/upgrade)**から簡単にできます。
- 更新内容は[GitHubの更新履歴](https://github.com/discourse/discourse/commits/master)をご覧ください。
- [meta.discourse.org](http://meta.discourse.org)にて、Discourseに関するお知らせ、話し合い、サポートを行っています。
new_version_mailer_with_notes:
subject_template: "[%{site_name}] update available"
subject_template: "[%{site_name}] アップデートがあります"
text_body_template: |+
最新版の[Discourse](http://www.discourse.org)が利用出来ます!
現在利用しているバージョン: %{installed_version}
新しいバージョン: **%{new_version}**
- 更新は**[ワンクリックブラウザ・アップグレード](%{base_url}/admin/upgrade)**から簡単にできます。
- 更新内容は[GitHubの更新履歴](https://github.com/discourse/discourse/commits/master)をご覧ください。
- [meta.discourse.org](http://meta.discourse.org)にて、Discourseに関するお知らせ、話し合い、サポートを行っています。
### リリースノート
%{notes}
queued_posts_reminder:
subject_template:
other: "[%{site_name}] %{count} 件の投稿がレビュー待ちです"
@ -1058,7 +1091,7 @@ ja:
```
restore_succeeded:
subject_template: "復元が正常に完了しました"
text_body_template: "復元に成功しました"
text_body_template: "復元が完了しました。"
restore_failed:
subject_template: "復元に失敗しました"
text_body_template: |
@ -1083,7 +1116,7 @@ ja:
%{logs}
```
csv_export_succeeded:
subject_template: "データ出力完了"
subject_template: "データのダウンロード準備が完了しました"
text_body_template: |
データ出力が完了しました! :dvd:
@ -1091,8 +1124,8 @@ ja:
このダウンロードリンクは48時間有効です
csv_export_failed:
subject_template: "データ出力失敗"
text_body_template: "申し訳ありません。データ出力に失敗しました。ログを確認するかスタッフメンバーに連絡してください"
subject_template: "データのエクスポートに失敗しました"
text_body_template: "申し訳ありません。データのエクスポートに失敗しました。ログを確認するかスタッフメンバーにお問い合わせください。"
email_reject_no_account:
subject_template: "[%{site_name}] Email issue -- 不明なアカウント"
email_reject_empty:
@ -1152,16 +1185,18 @@ ja:
subject_template: "[%{site_name}] [プライベートメッセージ] %{topic_title}"
digest:
why: "あなたが最後にアクセスした %{last_seen_at} 以降の %{site_link} のまとめです"
subject_template: "[%{site_name}] ダイジェスト"
subject_template: "[%{site_name}] のまとめ"
new_activity: "あなたのトピックおよびポストにおけるアクティビティ:"
top_topics: "人気の投稿"
other_new_topics: "人気のトピック"
unsubscribe: "このダイジェストは、あなたからのアクセスがしばらくない場合、%{site_link}から送信されます。配信停止はこちら %{unsubscribe_link}"
unsubscribe: "このまとめは、サイトへのアクセスが一定期間無い場合に、%{site_link}から送られます。配信停止はこちらから行えます: %{unsubscribe_link}"
click_here: "ここをクリック"
from: "%{site_name} ダイジェスト"
from: "%{site_name} のまとめ"
read_more: "もっと読む"
more_topics: " %{new_topics_since_seen}個の新しいトピックがありました"
more_topics_category: "もっと新しいトピック:"
mailing_list:
new_topics: "新着トピック"
forgot_password:
subject_template: "[%{site_name}] パスワードのリセット"
text_body_template: |
@ -1189,6 +1224,12 @@ ja:
以下のリンクをクリックしてパスワードを設定してください:
%{base_url}/users/password-reset/%{email_token}
confirm_new_email:
subject_template: "[%{site_name}] 新しいメールアドレスを確認してください"
text_body_template: |
以下のリンクをクリックして、%{site_name}で利用するメールアドレスを有効化してください:
%{base_url}/users/authorize-email/%{email_token}
signup_after_approval:
subject_template: "%{site_name} への参加承認完了!"
signup:
@ -1196,11 +1237,12 @@ ja:
text_body_template: |
Welcome to %{site_name}!
次のリンクをクリックして、新たなアカウントの承認およびアクティベーションを行ってください:
リンクをクリックして、アカウントを有効化してください:
%{base_url}/users/activate-account/%{email_token}
もし、上記のURLがクリックできない場合は、ブラウザのアドレスバーへURLをコピーして貼り付けて下さい。
page_not_found:
title: "ページが見つからないか、アクセス出来ない場所にあります。"
popular_topics: "人気"
recent_topics: "最新"
see_more: "もっと見る"
@ -1248,19 +1290,73 @@ ja:
csv_export:
boolean_yes: "はい"
boolean_no: "いいえ"
static_topic_first_reply: |+
static_topic_first_reply: |
%{page_name}ページのコンテンツを編集するには、このトピックの最初の投稿を編集してください
guidelines_topic:
title: "よくある質問/コミュニティガイドライン"
title: "FAQ/ガイドライン"
tos_topic:
title: "利用規約"
privacy_topic:
title: "プライバシーポリシー"
static:
search_help: |
<h3>マメ知識</h3>
<p>
<ul>
<li>検索はタイトルが優先されます。 &ndash; 迷った時はタイトルを調べてみましょう。</li>
<li>調べたい物特有の、他にはない言葉で調べると良いでしょう。</li>
<li>特定のカテゴリ、トピック、ユーザーページにて検索してみましょう。</li>
</ul>
</p>
<h3>オプション</h3>
<p>
<table>
<tr><td><code>order:views</code></td><td><code>order:latest</code></td><td><code>order:likes</code></td><td><code>@username</code></td><td><code>user:foo</code></td></tr>
<tr><td><code>status:open</code></td><td><code>status:closed</code></td><td><code>status:archived</code></td><td><code>status:noreplies</code></td><td><code>status:single_user</code></td></tr>
<tr><td><code>#category-slug</code></td><td><code>category:foo</code></td><td><code>group:foo</code></td><td><code>badge:foo</code></td><td></td></tr>
<tr><td><code>in:likes</code></td><td><code>in:posted</code></td><td><code>in:watching</code></td><td><code>in:tracking</code></td><td><code>in:private</code></td></tr>
<tr><td><code>in:bookmarks</code></td><td><code>in:first</code></td><td><code>in:pinned</code></td><td><code>in:unpinned</code></td><td><code>in:wiki</code></td></tr>
<tr><td><code>posts_count:num</code></td><td><code>before:days or date</code></td><td><code>after:days or date</code></td> <td colspan=2></td></tr>
</table>
</p>
<h3>サンプル</h3>
<p>
<ul>
<li><code>rainbows #parks</code> で、"parks"カテゴリの"rainbows"という言葉を含むトピックを検索します。</li>
<li><code>rainbows category:parks status:open order:latest</code> 最終投稿の日付順に並べ替え、”parks”カテゴリの"rainbows"を含むクローズ/アーカイブされていないトピックを検索します。</li>
<li><code>rainbows category:"parks and gardens" in:bookmarks</code> ブックマークされている"parks and gardens"カテゴリの中で、"rainbows"という言葉を含むトピックを検索します。</li>
</ul>
</p>
badges:
editor:
name: 編集者
description: 最初の投稿を編集する
autobiographer:
name: あなたはだれ?
description: <a href="/my/preferences">プロフィール</a>をすべて書く
nice_post:
name: ナイスな返事
good_post:
name: イカす返事
great_post:
name: 素晴らしい返事
nice_topic:
name: ナイスなトピック
good_topic:
name: イカすトピック
first_flag:
name: はじめの通報
description: 通報した投稿
read_guidelines:
description: <a href="/guidelines">ガイドライン</a>を読む
popular_link:
name: 人気のリンク
hot_link:
name: ウワサのリンク
famous_link:
name: 伝説のリンク
first_emoji:
name: はじめての絵文字
admin_login:
success: "メールを送信しました"
error: "エラー!"

View File

@ -24,7 +24,7 @@ pt:
loading: "A carregar"
powered_by_html: 'Desenvolvido por <a href="http://www.discourse.org">Discourse</a>, e melhor visualizado com o JavaScript ativo'
log_in: "Iniciar Sessão"
purge_reason: "Automaticamente eliminado devido a abandono, conta inativada"
purge_reason: "Conta removida automaticamente como conta abandonada, desactivada."
disable_remote_images_download_reason: "O download remoto de imagens foi desativado por não haver espaço disponível no disco."
anonymous: "Anónimo"
emails:
@ -35,7 +35,7 @@ pt:
empty_email_error: "Acontece quando, a informação não processada, do email recebido veio em branco."
no_message_id_error: "Acontece quando o email recebido não tem 'Message-Id' no cabeçalho da mensagem."
auto_generated_email_error: "Acontece quando o cabeçalho 'precedence' é definida como: 'list', 'junk' ou 'auto_reply', ou quando algum cabeçalho contém: 'auto-submitted', 'auto-replied' ou 'auto-generated'."
no_body_detected_error: "Acontece quando não conseguimos extrair o corpo da mensagem e não existem anexos."
no_body_detected_error: "Acontece quando não se consegue obter um corpo de mensagem e não existem anexos."
inactive_user_error: "Acontece quando o remetente não está activo."
blocked_user_error: "Acontece quando o remetente está bloqueado."
bad_destination_address: "Acontece quando nenhum dos endereços de email nos campos para/cc/bcc coincide com um endereço de email configurado."
@ -44,6 +44,9 @@ pt:
reply_user_not_matching_error: "Acontece quando uma resposta veio de um endereço de email diferente do destinatário da notificação."
topic_not_found_error: "Acontece quando a resposta veio de um tópico relacionado mas o tópico relacionado foi apagado."
topic_closed_error: "Acontece quando uma resposta chegou mas o tópico relacionado foi fechado."
bounced_email_error: "O email é um relatório devolvido."
auto_generated_email_reply: "O email contém uma resposta a um email gerado automaticamente."
screened_email_error: "Acontece quando a morada de email da pessoa que enviou já foi confirmada."
errors: &errors
format: '%{attribute} %{message}'
messages:
@ -174,6 +177,7 @@ pt:
group_mentions: "Últimas menções em %{group_name}"
user_posts: "Mensagens mais recentes criados por @%{username}"
user_topics: "Tópicos mais recentes criados por @%{username}"
tag: "Tópicos etiquetados"
too_late_to_edit: "Essa mensagem foi criada há muito tempo. Já não pode ser editada ou apagada."
revert_version_same: "A versão atual é o mesma versão para a qual você está tentando reverter."
excerpt_image: "imagem"
@ -181,7 +185,7 @@ pt:
delete_reason: "Eliminado através da fila de moderação de mensagens"
groups:
errors:
can_not_modify_automatic: "Não pode modificar um grupo automático"
can_not_modify_automatic: "Não pode modificar um grupo automatico"
member_already_exist: "'%{username}' já é membro deste grupo."
invalid_domain: "'%{domain}' não é um domínio válido."
invalid_incoming_email: "'%{email}' não é um endereço de email válido."
@ -475,7 +479,7 @@ pt:
continue_button: "Continuar para %{site_name}"
welcome_to: "Bem-vindo a %{site_name}!"
approval_required: "Um moderador tem que aprovar a sua conta antes de poder aceder a este fórum. Irá receber um email quando a sua conta for aprovada!"
missing_session: "Não conseguimos detetar se a sua conta foi criada, por favor assegure-se que tem os cookies ativos."
missing_session: "Não conseguimos detectar se a sua conta foi criada, pelo que pedimos que confirme que tem os cookies possibilitados."
post_action_types:
off_topic:
title: 'Fora de Contexto'
@ -721,6 +725,9 @@ pt:
email_polling_errored_recently:
one: "A consulta automática de emails gerou um erro nas últimas 24 horas. Consulte em <a href='/logs' target='_blank'>os registos</a> para mais detalhes."
other: "A consulta automática de emails gerou %{count} erros nas últimas 24 horas. Consulte em <a href='/logs' target='_blank'>os registos</a> para mais detalhes."
bad_favicon_url: "Não estamos a conseguir carregar o favicon. Pot favor, confirme a sua configuração favicon_url nas <a href='/admin/site_settings'>Configurações do sítio</a>."
poll_pop3_timeout: "A tentativa de ligação ao servidor POP3 está a ultrapassar o tempo máximo. Email de caixa de entrada não pôde ser obtido. Por favor verifique a sua <a href='/admin/site_settings/category/email'>configuração de POP3</a> e fornecedor de serviço internet."
poll_pop3_auth_error: "A tentativa de ligação ao servidor POP3 está a falhar por motivos de erro de autenticação. Por favor verifique a sua <a href='/admin/site_settings/category/email'>configuração de POP3</a>."
site_settings:
censored_words: "Palavras que serão automaticamente substituídas por &#9632;&#9632;&#9632;&#9632;"
delete_old_hidden_posts: "Eliminar automaticamente quaisquer mensagens ocultas que permaneçam escondidas por mais de 30 dias."
@ -765,6 +772,7 @@ pt:
post_onebox_maxlength: "Tamanho máximo de uma mensagem Discourse de caixa única, em caracteres."
onebox_domains_whitelist: "Lista de domínios que permitem colocar em caixa única; estes domínios devem suportar OpenGraph ou oEmbed. Teste-os em http://iframely.com/debug"
logo_url: "A imagem do logótipo no canto superior esquerdo do seu sítio, deve ter uma forma retangular. Quando deixada em branco, o texto do título do sítio será exibido."
digest_logo_url: "O logotipo alternativo usado no topo do email de resumo do seu sítio. Deve ter um formato rectangular amplo. Não pode ser uma imagem em formato SVG. Se deixado em branco, `logo_url` será utilizado."
logo_small_url: "A pequena imagem do logótipo no canto superior esquerdo do seu sítio, deve ter uma forma quadrada, visível quando arrastado para baixo. Quando deixado em branco, um glifo de início será exibido."
favicon_url: "Um favicon para o seu sítio, veja http://en.wikipedia.org/wiki/Favicon, para trabalhar corretamente sobre um CDN deve ser um png"
mobile_logo_url: "A imagem do logótipo com posição fixa utilizada no canto superior esquerdo do seu sítio móvel deve ter uma forma quadrada. Quando deixado em branco, `logo_url` será utilizado. ex: http://exemplo.com/uploads/default/logo.png"
@ -785,6 +793,7 @@ pt:
polling_interval: "Quando não está a ocorrer uma solicitação ao servidor, com que frequência devem os clientes ligados requerer uma atualização, em milissegundos"
anon_polling_interval: "Com que frequência os clientes não registados podem fazer solicitações ao servidor, em milisegundos"
background_polling_interval: "Com que frequência deverão os clientes solicitar o servidor, em milissegundos (quando a janela está em plano de fundo)"
flags_required_to_hide_post: "Número de bandeiras que fazem com que uma mensagem seja automaticamente escondida e uma mensagem enviada ao utilizador (0 se nunca)"
cooldown_minutes_after_hiding_posts: "Número de minutos que o utilizador deve esperar antes de poder editar uma mensagem oculta devido a sinalizações por parte da comunidade"
max_topics_in_first_day: "O número máximo de tópicos que é o utilizador pode criar no seu primeiro dia no Fórum."
max_replies_in_first_day: "Número máximo de mensagens que um utilizador pode criar no seu primeiro dia no Fórum."

View File

@ -24,7 +24,7 @@ pt_BR:
loading: "Carregando"
powered_by_html: 'Desenvolvido por <a href="http://www.discourse.org">Discourse</a>, melhor visualizado com JavaScript ativado'
log_in: "Entrar"
purge_reason: "A conta não verificada, foi excluída."
purge_reason: "Automaticamente eliminada por ser uma conta abandonada, não ativada"
disable_remote_images_download_reason: "Download de imagens remotas foi desativado porque não havia espaço suficiente em disco disponível."
anonymous: "Anônimo"
emails:

View File

@ -340,7 +340,7 @@ ro:
please_continue: "Noul dvs cont este confirmat, iar acum sunteți autentificat."
continue_button: "Continuă cu %{site_name}"
welcome_to: "Bine ați venit la %{site_name}!"
approval_required: "Un moderator trebuie să aprobe manual contul înaine să puteți accesa forumul. Veți primii un email când acesta a fost aprobat!"
approval_required: "Un moderator trebuie să aprobe manual contul înaine să puteți accesa forumul. Vei primi un email când acesta a fost aprobat!"
post_action_types:
off_topic:
title: 'În afară discuției'
@ -352,7 +352,7 @@ ro:
long_form: 'marchează aceasta ca spam'
inappropriate:
title: 'Necorespunzător'
description: 'Această postare are conținut pe care o persoană normală l-ar numii ofesator, abuziv, sau o violare a <a href="/guidelines"> regulilor comune</a>.'
description: 'Această postare are conținut ce ar putea fi considerat drept ofesator, abuziv, sau o violare a <a href="/guidelines"> regulilor comune</a>.'
long_form: 'marcat ca necorespunzător'
notify_user:
email_title: 'Despre postarea dvs din "%{title}"'
@ -379,7 +379,7 @@ ro:
long_form: 'Marchează asta ca spam'
inappropriate:
title: 'Necorespunzător'
description: 'Această discuție are conținut pe care o persoană normală l-ar numii ofesantor, abuziv, sau o violare a <a href="/guidelines"> regulilor comune</a>.'
description: 'Această discuție are conținut ce ar putea fi considerat drept ofesantor, abuziv, sau o violare a <a href="/guidelines"> regulilor comune</a>.'
long_form: 'marcat ca necorespunzător'
notify_moderators:
title: "Notifică moderatori"
@ -601,7 +601,7 @@ ro:
invite_expiry_days: "Cat timp sun valabile cheile de invitație ale utilizatorilor, în zile"
invite_passthrough_hours: "Cât timp un utilizator poate folosii o cheie de invitație recuperată anterior pentru autentificare, în ore"
invite_only: "Înregistrarea publică este dezactivată, toți utilizatorii noi trebuie să fie exclusiv invitați de un alt membru sau personalul site-ului."
login_required: "Autentificarea e necesară pentru a citii conținutul site-ului, nu permite accesul anonim."
login_required: "Autentificarea este necesară pentru a citi conținutul site-ului, nu permite accesul anonim."
min_password_length: "Lungimea minimă de caractere pentru parolă."
block_common_passwords: "nu permite parole ce sunt în cele 10,000 cele mai cunoscute parole."
enable_local_logins: "Activează numele de utilizator local și a conturilor bazate pe logare cu parola. (Notă: Aceasta trebuie activiată pentru invitații pt a funcționa)"
@ -874,7 +874,7 @@ ro:
previous_discussion: "Răspunsurile precedente"
unsubscribe:
title: "Dezabonare"
description: "Nu sunteți interesat în a primii aceste email-uri? Nicio problemă! Faceți clic dedesubt pentru a vă dezabona imediat:"
description: "Nu ești interesat în a primi aceste email-uri? Nicio problemă! Faceți click dedesubt pentru a vă dezabona imediat:"
posted_by: "Postat de %{username} pe data %{post_date}"
user_replied:
subject_template: "[%{site_name}] %{topic_title}"

View File

@ -12,7 +12,7 @@ ru:
long_date: "D MMMM YYYY, HH:mm"
datetime_formats: &datetime_formats
formats:
short: "%m-%d-%Y"
short: "%d.%m.%Y"
date:
month_names: [null, Январь, Февраль, Март, Апрель, Май, Июнь, Июль, Август, Сентябрь, Октябрь, Ноябрь, Декабрь]
<<: *datetime_formats
@ -22,7 +22,7 @@ ru:
loading: "Загрузка..."
powered_by_html: 'При поддержке <a href="http://www.discourse.org">Discourse</a>, лучше всего использовать с включенным JavaScript'
log_in: "Войти"
purge_reason: "Автоматически удален, как неактивная, неактивированная учетная запись"
purge_reason: "Деактивированная учетная запись будет автоматически удалена как заброшенная"
disable_remote_images_download_reason: "Загрузка картинок была отключена из-за недостаточности места на диске."
anonymous: "Гость"
emails:

View File

@ -2436,18 +2436,14 @@ zh_CN:
thank_you:
name: 感谢你
description: 有 20 个被赞的帖子,给出过 10 个赞
long_description: |
该徽章授予给收到了 20 个赞,且赞过别人 10 次的你。当别人感谢你的帖子时,你也感谢他们的帖子。
gives_back:
name: 回馈
description: 有 100 个被赞的帖子,给出过 100 个赞
long_description: |
该徽章授予给收到了 100 个赞,且赞过别人 100 次的你。感谢你回馈赞给社群!
empathetic:
name: 感性
description: 有 500 个被赞的帖子,给出过 1000 个赞
long_description: |
该徽章授予给收到了 500 个赞,且赞过别人 1000 次的你。哇!你是一个富有同情心且会换位思考的模范。 :two_hearts:
first_emoji:
description: 在帖子中使用表情符号
admin_login:
success: "邮件已发送"
error: "错误!"

View File

@ -544,6 +544,8 @@ email:
pop3_polling_username: ''
pop3_polling_password: ''
log_mail_processing_failures: false
incoming_email_prefer_html:
default: false
email_in:
default: false
client: true
@ -698,6 +700,7 @@ trust:
tl3_time_period:
default: 100
min: 1
max: 1000000
tl3_requires_days_visited:
default: 50
min: 0
@ -708,10 +711,16 @@ trust:
default: 25
min: 0
max: 100
tl3_requires_topics_viewed_cap:
default: 500
min: 0
tl3_requires_posts_read:
default: 25
min: 0
max: 100
tl3_requires_posts_read_cap:
default: 20000
min: 0
tl3_requires_topics_viewed_all_time:
default: 200
min: 0
@ -1128,6 +1137,9 @@ user_preferences:
default_email_private_messages: true
default_email_direct: true
default_email_mailing_list_mode: false
default_email_mailing_list_mode_frequency:
enum: 'MailingListModeSiteSetting'
default: 1
disable_mailing_list_mode:
default: false
client: true

View File

@ -23,7 +23,6 @@ exec /bin/bash <<'EOT'
# set HOME to the setuid user's home, there doesn't seem to be a better, portable way
export HOME="$(eval echo ~$(id -un))"
export RAILS_ENV=production
export RUBY_GC_MALLOC_LIMIT=90000000
cd /var/www/discourse

View File

@ -0,0 +1,5 @@
class AddMailingListModeFrequency < ActiveRecord::Migration
def change
add_column :user_options, :mailing_list_mode_frequency, :integer, default: 0, null: false
end
end

View File

@ -0,0 +1,5 @@
class AddUserFirstVisit < ActiveRecord::Migration
def change
add_column :users, :first_seen_at, :datetime
end
end

View File

@ -0,0 +1,12 @@
class ShortenTopicCustomFieldsIndex < ActiveRecord::Migration
def up
remove_index :topic_custom_fields, :value
add_index :topic_custom_fields, [:value, :name],
name: 'topic_custom_fields_value_key_idx',
where: 'value IS NOT NULL AND char_length(value) < 400'
end
def down
remove_index :topic_custom_fields, :value, name: 'topic_custom_fields_value_key_idx'
add_index :topic_custom_fields, :value
end
end

View File

@ -257,12 +257,12 @@ module BackupRestore
end
end
log "Gzipping archive..."
log "Gzipping archive, this may take a while..."
`gzip -5 #{tar_filename}`
end
def after_create_hook
log "Executing the after_create_hook for the backup"
log "Executing the after_create_hook for the backup..."
backup = Backup.create_from_filename("#{File.basename(@archive_basename)}.tar.gz")
backup.after_create_hook
end

View File

@ -161,7 +161,7 @@ module BackupRestore
end
def unzip_archive
log "Unzipping archive..."
log "Unzipping archive, this may take a while..."
FileUtils.cd(@tmp_directory) { `gzip --decompress '#{@archive_filename}'` }
end

View File

@ -194,7 +194,10 @@ class CookedPostProcessor
original_width, original_height = get_size(src)
# can't reach the image...
if original_width.nil? || original_height.nil?
if original_width.nil? ||
original_height.nil? ||
original_width == 0 ||
original_height == 0
Rails.logger.info "Can't reach '#{src}' to get its dimension."
return
end
@ -204,8 +207,16 @@ class CookedPostProcessor
return if is_a_hyperlink?(img)
crop = false
if original_width.to_f / original_height.to_f < 0.75
crop = true
width, height = ImageSizer.crop(original_width, original_height)
img["width"] = width
img["height"] = height
end
if upload = Upload.get_from_url(src)
upload.create_thumbnail!(width, height)
upload.create_thumbnail!(width, height, crop)
end
add_lightbox!(img, original_width, original_height, upload)

View File

@ -212,16 +212,21 @@ module Email
text = fix_charset(@mail)
end
# prefer text over html
text = trim_discourse_markers(text) if text.present?
text, elided = EmailReplyTrimmer.trim(text, true) if text.present?
return [text, elided] if text.present?
use_html = html.present? && (!text.present? || SiteSetting.incoming_email_prefer_html)
use_text = text.present? unless use_html
# clean the html if that's all we've got
html = Email::HtmlCleaner.new(html).output_html if html.present?
html = trim_discourse_markers(html) if html.present?
html, elided = EmailReplyTrimmer.trim(html, true) if html.present?
return [html, elided] if html.present?
if use_text
text = trim_discourse_markers(text)
text, elided = EmailReplyTrimmer.trim(text, true)
return [text, elided]
end
if use_html
html = Email::HtmlCleaner.new(html).output_html
html = trim_discourse_markers(html)
html, elided = EmailReplyTrimmer.trim(html, true)
return [html, elided]
end
end
def fix_charset(mail_part)

View File

@ -6,6 +6,10 @@ module Email
class Styles
@@plugin_callbacks = []
attr_accessor :fragment
delegate :css, to: :fragment
def initialize(html, opts=nil)
@html = html
@opts = opts || {}
@ -33,7 +37,7 @@ module Email
@fragment.css('img').each do |img|
next if img['class'] == 'site-logo'
if img['class'] == "emoji" || img['src'] =~ /plugins\/emoji/
if img['class'] == "emoji" || img['src'] =~ /(plugins|images)\/emoji/
img['width'] = 20
img['height'] = 20
else
@ -90,6 +94,7 @@ module Email
style('.rtl', 'direction: rtl;')
style('td.body', 'padding-top:5px;', colspan: "2")
style('.whisper td.body', 'font-style: italic; color: #9c9c9c;')
style('.lightbox-wrapper .meta', 'display: none')
correct_first_body_margin
correct_footer_style
reset_tables
@ -186,6 +191,17 @@ module Email
@fragment.to_s
end
def make_all_links_absolute
site_uri = URI(Discourse.base_url)
@fragment.css("a").each do |link|
begin
link["href"] = "#{site_uri}#{link['href']}" unless URI(link["href"].to_s).host.present?
rescue URI::InvalidURIError, URI::InvalidComponentError
# leave it
end
end
end
private
def replace_relative_urls

View File

@ -1,22 +1,9 @@
require 'execjs'
require 'babel/transpiler'
require 'mini_racer'
module Tilt
class Console
def initialize(prefix=nil)
@prefix = prefix || ''
end
def log(msg)
Rails.logger.info("#{@prefix}#{msg}")
end
def error(msg)
Rails.logger.error("#{@prefix}#{msg}")
end
end
class ES6ModuleTranspilerTemplate < Tilt::Template
self.default_mime_type = 'application/javascript'
@ -30,10 +17,19 @@ module Tilt
def self.create_new_context
# timeout any eval that takes longer than 15 seconds
ctx = V8::Context.new(timeout: 15000)
ctx = MiniRacer::Context.new(timeout: 15000)
ctx.eval("var self = this; #{File.read(Babel::Transpiler.script_path)}")
ctx.eval("module = {}; exports = {};");
ctx.load("#{Rails.root}/lib/es6_module_transpiler/support/es6-module-transpiler.js")
ctx.attach("rails.logger.info", proc{|err| Rails.logger.info(err.to_s)})
ctx.attach("rails.logger.error", proc{|err| Rails.logger.error(err.to_s)})
ctx.eval <<JS
console = {
prefix: "",
log: function(msg){ rails.logger.info(console.prefix + msg); },
error: function(msg){ rails.logger.error(console.prefix + msg); }
}
JS
ctx
end
@ -60,19 +56,9 @@ module Tilt
end
def self.protect
rval = nil
@mutex.synchronize do
begin
rval = yield
# This may seem a bit odd, but we don't want to leak out
# objects that require locks on the v8 vm, to get a backtrace
# you need a lock, if this happens in the wrong spot you can
# deadlock a process
rescue V8::Error => e
raise JavaScriptError.new(e.message, e.backtrace)
end
yield
end
rval
end
def whitelisted?(path)
@ -98,7 +84,7 @@ module Tilt
def babel_transpile(source)
klass = self.class
klass.protect do
klass.v8['console'] = Console.new("BABEL: babel-eval: ")
klass.v8.eval("console.prefix = 'BABEL: babel-eval: ';")
@output = klass.v8.eval(babel_source(source))
end
end
@ -108,7 +94,7 @@ module Tilt
klass = self.class
klass.protect do
klass.v8['console'] = Console.new("BABEL: #{scope.logical_path}: ")
klass.v8.eval("console.prefix = 'BABEL: #{scope.logical_path}: ';")
@output = klass.v8.eval(generate_source(scope))
end

View File

@ -12,11 +12,10 @@ module FileStore
def remove_file(url)
return unless is_relative?(url)
path = public_dir + url
return if !File.exists?(path)
tombstone = public_dir + url.sub("/uploads/", "/tombstone/")
FileUtils.mkdir_p(Pathname.new(tombstone).dirname)
FileUtils.move(path, tombstone, :force => true)
rescue Errno::ENOENT
# don't care if the file isn't there
end
def has_been_uploaded?(url)

View File

@ -16,4 +16,19 @@ module ImageSizer
[(w * ratio).floor, (h * ratio).floor]
end
def self.crop(width, height, opts = {})
return if width.blank? || height.blank?
max_width = (opts[:max_width] || SiteSetting.max_image_width).to_f
max_height = (opts[:max_height] || SiteSetting.max_image_height).to_f
w = width.to_f
h = height.to_f
return [w.floor, h.floor] if w <= max_width && h <= max_height
ratio = max_width / w
[max_width.floor, [max_height, (h * ratio)].min.floor]
end
end

View File

@ -1171,10 +1171,7 @@
}
utils_hooks__hooks.createFromInputFallback = deprecate(
'moment construction falls back to js Date. This is ' +
'discouraged and will be removed in upcoming major ' +
'release. Please refer to ' +
'https://github.com/moment/moment/issues/1407 for more info.',
'moment construction falls back to js Date. This is discouraged and will be removed in upcoming major release. Please refer to https://github.com/moment/moment/issues/1407 for more info.',
function (config) {
config._d = new Date(config._i + (config._useUTC ? ' UTC' : ''));
}

View File

@ -154,15 +154,25 @@ module JsLocaleHelper
result
end
def self.compile_message_format(locale, format)
ctx = V8::Context.new
ctx.load(Rails.root + 'lib/javascripts/messageformat.js')
path = Rails.root + "lib/javascripts/locale/#{locale}.js"
ctx.load(path) if File.exists?(path)
ctx.eval("mf = new MessageFormat('#{locale}');")
ctx.eval("mf.precompile(mf.parse(#{format.inspect}))")
@mutex = Mutex.new
def self.with_context
@mutex.synchronize do
yield @ctx ||= begin
ctx = MiniRacer::Context.new
ctx.load(Rails.root + 'lib/javascripts/messageformat.js')
ctx
end
end
end
rescue V8::Error => e
def self.compile_message_format(locale, format)
with_context do |ctx|
path = Rails.root + "lib/javascripts/locale/#{locale}.js"
ctx.load(path) if File.exists?(path)
ctx.eval("mf = new MessageFormat('#{locale}');")
ctx.eval("mf.precompile(mf.parse(#{format.inspect}))")
end
rescue MiniRacer::EvalError => e
message = "Invalid Format: " << e.message
"function(){ return #{message.inspect};}"
end

View File

@ -1,4 +1,4 @@
require 'v8'
require 'mini_racer'
require 'nokogiri'
require_dependency 'url_helper'
require_dependency 'excerpt_parser'
@ -7,7 +7,9 @@ require_dependency 'discourse_tagging'
module PrettyText
class Helpers
module Helpers
extend self
def t(key, opts)
key = "js." + key
unless opts
@ -81,6 +83,7 @@ module PrettyText
nil
end
end
end
@mutex = Mutex.new
@ -92,9 +95,11 @@ module PrettyText
def self.create_new_context
# timeout any eval that takes longer than 15 seconds
ctx = V8::Context.new(timeout: 15000)
ctx = MiniRacer::Context.new(timeout: 15000)
ctx["helpers"] = Helpers.new
Helpers.instance_methods.each do |method|
ctx.attach("helpers.#{method}", Helpers.method(method))
end
ctx_load(ctx,
"vendor/assets/javascripts/md5.js",
@ -198,6 +203,7 @@ module PrettyText
# we use the exact same markdown converter as the client
# TODO: use the same extensions on both client and server (in particular the template for mentions)
baked = nil
text = text || ""
protect do
context = v8
@ -206,8 +212,9 @@ module PrettyText
context_opts = opts || {}
context_opts[:sanitize] = true unless context_opts[:sanitize] == false
context['opts'] = context_opts
context['raw'] = text
context.eval("opts = #{context_opts.to_json};")
context.eval("raw = #{text.inspect};")
if Post.white_listed_image_classes.present?
Post.white_listed_image_classes.each do |klass|
@ -258,8 +265,10 @@ module PrettyText
# leaving this here, cause it invokes v8, don't want to implement twice
def self.avatar_img(avatar_template, size)
protect do
v8['avatarTemplate'] = avatar_template
v8['size'] = size
v8.eval <<JS
avatarTemplate = #{avatar_template.inspect};
size = #{size.inspect};
JS
decorate_context(v8)
v8.eval("Discourse.Utilities.avatarImg({ avatarTemplate: avatarTemplate, size: size });")
end
@ -267,9 +276,8 @@ module PrettyText
def self.unescape_emoji(title)
protect do
v8["title"] = title
decorate_context(v8)
v8.eval("Discourse.Emoji.unescape(title)")
v8.eval("Discourse.Emoji.unescape(#{title.inspect})")
end
end
@ -386,31 +394,16 @@ module PrettyText
fragment.to_html
end
# Given a Nokogiri doc, convert all links to absolute
def self.make_all_links_absolute(doc)
site_uri = nil
doc.css("a").each do |link|
href = link["href"].to_s
begin
uri = URI(href)
site_uri ||= URI(Discourse.base_url)
link["href"] = "#{site_uri}#{link['href']}" unless uri.host.present?
rescue URI::InvalidURIError, URI::InvalidComponentError
# leave it
end
end
end
def self.strip_image_wrapping(doc)
doc.css(".lightbox-wrapper .meta").remove
end
def self.format_for_email(html, post = nil)
doc = Nokogiri::HTML.fragment(html)
DiscourseEvent.trigger(:reduce_cooked, doc, post)
make_all_links_absolute(doc)
strip_image_wrapping(doc)
doc.to_html
def self.format_for_email(html, post = nil, style = nil)
Email::Styles.new(html, style: style).tap do |doc|
DiscourseEvent.trigger(:reduce_cooked, doc, post)
doc.make_all_links_absolute
doc.send :"format_#{style}" if style
end.to_html
end
protected
@ -428,15 +421,7 @@ module PrettyText
def self.protect
rval = nil
@mutex.synchronize do
begin
rval = yield
# This may seem a bit odd, but we don't want to leak out
# objects that require locks on the v8 vm, to get a backtrace
# you need a lock, if this happens in the wrong spot you can
# deadlock a process
rescue V8::Error => e
raise JavaScriptError.new(e.message, e.backtrace)
end
rval = yield
end
rval
end

View File

@ -21,9 +21,9 @@ task "avatars:clean" => :environment do
puts "Cleaning up avatar thumbnails"
puts
OptimizedImage.where("upload_id IN (SELECT custom_upload_id FROM user_avatars)")
.where("upload_id IN (SELECT gravatar_upload_id FROM user_avatars)")
.where("upload_id IN (SELECT uploaded_avatar_id FROM users)")
OptimizedImage.where("upload_id IN (SELECT custom_upload_id FROM user_avatars) OR
upload_id IN (SELECT gravatar_upload_id FROM user_avatars) OR
upload_id IN (SELECT uploaded_avatar_id FROM users)")
.find_each do |optimized_image|
optimized_image.destroy!
putc "." if (i += 1) % 10 == 0

Some files were not shown because too many files have changed in this diff Show More