From 29840888e5eef2f6cf73e59bcc8f346708776169 Mon Sep 17 00:00:00 2001 From: Erick Guan Date: Sat, 14 Feb 2015 23:51:52 +0800 Subject: [PATCH 001/114] FIX: respect default locale settings when seed We seed special categories during migration so we have to set the locale before the migration happens. --- lib/tasks/db.rake | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/tasks/db.rake b/lib/tasks/db.rake index aefe26f50b..ab40a807c2 100644 --- a/lib/tasks/db.rake +++ b/lib/tasks/db.rake @@ -1,6 +1,10 @@ -# we need to run seed_fu every time we run rake db:migrate -task 'db:migrate' => 'environment' do +# we should set the locale before the migration +task 'set_locale' do I18n.locale = (SiteSetting.default_locale || :en) rescue :en +end + +# we need to run seed_fu every time we run rake db:migrate +task 'db:migrate' => ['environment', 'set_locale'] do SeedFu.seed if SiteSetting.vacuum_db_days > 0 && From 4cc22a55a0eee06ce31561f04eab03dd0a5d182f Mon Sep 17 00:00:00 2001 From: riking Date: Mon, 2 Mar 2015 11:00:19 -0800 Subject: [PATCH 002/114] Remove topic_auto_close at from PostSerializer We should look at extracting some of the cruft from these repsonses. --- app/serializers/post_serializer.rb | 5 ----- 1 file changed, 5 deletions(-) diff --git a/app/serializers/post_serializer.rb b/app/serializers/post_serializer.rb index 3496159a52..412aea761a 100644 --- a/app/serializers/post_serializer.rb +++ b/app/serializers/post_serializer.rb @@ -27,7 +27,6 @@ class PostSerializer < BasicPostSerializer :yours, :topic_id, :topic_slug, - :topic_auto_close_at, :display_username, :primary_group_name, :version, @@ -72,10 +71,6 @@ class PostSerializer < BasicPostSerializer object.try(:topic).try(:slug) end - def topic_auto_close_at - object.try(:topic).try(:auto_close_at) - end - def moderator? !!(object.try(:user).try(:moderator?)) end From 0f3677424612277b3350630dcaed8548e8c19b2b Mon Sep 17 00:00:00 2001 From: "Jason W. May" Date: Mon, 2 Mar 2015 11:25:25 -0800 Subject: [PATCH 003/114] group manager can invite members into the group from any restricted topic --- .../discourse/controllers/invite.js.es6 | 1 + app/models/invite.rb | 22 +++++++++++- lib/guardian.rb | 25 ++++++++++--- spec/components/guardian_spec.rb | 6 ++++ spec/controllers/topics_controller_spec.rb | 16 ++++++++- spec/fabricators/category_fabricator.rb | 12 +++++++ spec/models/invite_spec.rb | 22 ++++++++++++ spec/models/topic_spec.rb | 35 ++++++++++++++++++- 8 files changed, 132 insertions(+), 7 deletions(-) diff --git a/app/assets/javascripts/discourse/controllers/invite.js.es6 b/app/assets/javascripts/discourse/controllers/invite.js.es6 index 965d4128dc..6adc0f0208 100644 --- a/app/assets/javascripts/discourse/controllers/invite.js.es6 +++ b/app/assets/javascripts/discourse/controllers/invite.js.es6 @@ -21,6 +21,7 @@ export default ObjectController.extend(ModalFunctionality, { if (this.get('saving')) return true; if (this.blank('email')) return true; if (!Discourse.Utilities.emailValid(this.get('email'))) return true; + if (this.get('model.details.can_invite_to')) return false; if (this.get('isPrivateTopic') && this.blank('groupNames')) return true; return false; }.property('email', 'isPrivateTopic', 'groupNames', 'saving'), diff --git a/app/models/invite.rb b/app/models/invite.rb index 3ad2910328..6b84554d2b 100644 --- a/app/models/invite.rb +++ b/app/models/invite.rb @@ -56,6 +56,21 @@ class Invite < ActiveRecord::Base end + def add_groups_for_topic(topic) + if topic.category + (topic.category.groups - groups).each { |group| group.add(user) } + end + end + + def self.extend_permissions(topic, user, invited_by) + if topic.private_message? + topic.grant_permission_to_user(user.email) + elsif topic.category && topic.category.groups.any? + if Guardian.new(invited_by).can_invite_to?(topic) + (topic.category.groups - user.groups).each { |group| group.add(user) } + end + end + end # Create an invite for a user, supplying an optional topic # # Return the previously existing invite if already exists. Returns nil if the invite can't be created. @@ -64,7 +79,7 @@ class Invite < ActiveRecord::Base user = User.find_by(email: lower_email) if user - topic.grant_permission_to_user(lower_email) if topic && topic.private_message? + extend_permissions(topic, user, invited_by) if topic return nil end @@ -93,6 +108,11 @@ class Invite < ActiveRecord::Base group_ids.each do |group_id| invite.invited_groups.create!(group_id: group_id) end + else + if topic && topic.category # && Guardian.new(invited_by).can_invite_to?(topic) + group_ids = topic.category.groups.pluck(:id) - invite.invited_groups.pluck(:group_id) + group_ids.each { |group_id| invite.invited_groups.create!(group_id: group_id) } + end end Jobs.enqueue(:invite_email, invite_id: invite.id) diff --git a/lib/guardian.rb b/lib/guardian.rb index d644e5485c..d3e2911ee1 100644 --- a/lib/guardian.rb +++ b/lib/guardian.rb @@ -197,6 +197,12 @@ class Guardian is_me?(user) end + def invitations_allowed? + !SiteSetting.enable_sso && + SiteSetting.enable_local_logins && + (!SiteSetting.must_approve_users? || is_staff?) + end + def can_invite_to_forum?(groups=nil) authenticated? && !SiteSetting.enable_sso && @@ -209,10 +215,21 @@ class Guardian end def can_invite_to?(object, group_ids=nil) - can_invite = can_see?(object) && can_invite_to_forum? && ( group_ids.blank? || is_admin? ) - #TODO how should invite to PM work? - can_invite = can_invite && ( !object.category.read_restricted || is_admin? ) if object.is_a?(Topic) && object.category - can_invite + return false if ! authenticated? + return false if ! invitations_allowed? + return true if is_admin? + return false if ! can_see?(object) + + return false if group_ids.present? + + if object.is_a?(Topic) && object.category + if object.category.groups.any? + return true if object.category.groups.all? { |g| can_edit_group?(g) } + end + return false if object.category.read_restricted + end + + user.has_trust_level?(TrustLevel[2]) end def can_bulk_invite_to_forum?(user) diff --git a/spec/components/guardian_spec.rb b/spec/components/guardian_spec.rb index 6cb9eaf3bc..f685842292 100644 --- a/spec/components/guardian_spec.rb +++ b/spec/components/guardian_spec.rb @@ -266,6 +266,9 @@ describe Guardian do let(:user) { topic.user } let(:moderator) { Fabricate(:moderator) } let(:admin) { Fabricate(:admin) } + let(:private_category) { Fabricate(:private_category, group: group) } + let(:group_private_topic) { Fabricate(:topic, category: private_category) } + let(:group_manager) { group_private_topic.user.tap { |u| group.add(u); group.appoint_manager(u) } } it 'handles invitation correctly' do expect(Guardian.new(nil).can_invite_to?(topic)).to be_falsey @@ -298,6 +301,9 @@ describe Guardian do expect(Guardian.new(admin).can_invite_to?(private_topic)).to be_truthy end + it 'returns true for a group manager' do + expect(Guardian.new(group_manager).can_invite_to?(group_private_topic)).to be_truthy + end end describe 'can_see?' do diff --git a/spec/controllers/topics_controller_spec.rb b/spec/controllers/topics_controller_spec.rb index 490545cfe5..0036c209b4 100644 --- a/spec/controllers/topics_controller_spec.rb +++ b/spec/controllers/topics_controller_spec.rb @@ -790,6 +790,20 @@ describe TopicsController do expect { xhr :post, :invite, topic_id: 1, email: 'jake@adventuretime.ooo' }.to raise_error(Discourse::NotLoggedIn) end + describe 'when logged in as group manager' do + let(:group_manager) { log_in } + let(:group) { Fabricate(:group).tap { |g| g.add(group_manager); g.appoint_manager(group_manager) } } + let(:private_category) { Fabricate(:private_category, group: group) } + let(:group_private_topic) { Fabricate(:topic, category: private_category, user: group_manager) } + let(:recipient) { 'jake@adventuretime.ooo' } + + it "should attach group to the invite" do + xhr :post, :invite, topic_id: group_private_topic.id, user: recipient + expect(response).to be_success + expect(Invite.find_by(email: recipient).groups).to eq([group]) + end + end + describe 'when logged in' do before do @topic = Fabricate(:topic, user: log_in) @@ -806,7 +820,7 @@ describe TopicsController do end end - describe 'with permission' do + describe 'with admin permission' do let!(:admin) do log_in :admin diff --git a/spec/fabricators/category_fabricator.rb b/spec/fabricators/category_fabricator.rb index 1f237b5d68..5a23366276 100644 --- a/spec/fabricators/category_fabricator.rb +++ b/spec/fabricators/category_fabricator.rb @@ -13,3 +13,15 @@ Fabricator(:happy_category, from: :category) do slug 'happy' user end + +Fabricator(:private_category, from: :category) do + transient :group + + name 'Private Category' + slug 'private' + user + after_build do |cat, transients| + cat.update!(read_restricted: true) + cat.category_groups.build(group_id: transients[:group].id, permission_type: :full) + end +end diff --git a/spec/models/invite_spec.rb b/spec/models/invite_spec.rb index a7a1b02a2b..9430203306 100644 --- a/spec/models/invite_spec.rb +++ b/spec/models/invite_spec.rb @@ -127,6 +127,28 @@ describe Invite do end end + context 'to a group-private topic' do + let(:group) { Fabricate(:group) } + let(:private_category) { Fabricate(:private_category, group: group) } + let(:group_private_topic) { Fabricate(:topic, category: private_category) } + let(:inviter) { group_private_topic.user } + + before do + @invite = group_private_topic.invite_by_email(inviter, iceking) + end + + it 'should add the groups to the invite' do + expect(@invite.groups).to eq([group]) + end + + context 'when duplicated' do + it 'should not duplicate the groups' do + expect(group_private_topic.invite_by_email(inviter, iceking)).to eq(@invite) + expect(@invite.groups).to eq([group]) + end + end + end + context 'an existing user' do let(:topic) { Fabricate(:topic, category_id: nil, archetype: 'private_message') } let(:coding_horror) { Fabricate(:coding_horror) } diff --git a/spec/models/topic_spec.rb b/spec/models/topic_spec.rb index 0f49c41431..66ce8e17b3 100644 --- a/spec/models/topic_spec.rb +++ b/spec/models/topic_spec.rb @@ -1,4 +1,4 @@ -# encoding: UTF-8 +# encoding: utf-8 require 'spec_helper' require_dependency 'post_destroyer' @@ -1352,4 +1352,37 @@ describe Topic do topic.last_posted_at = 1.minute.ago expect(topic.save).to eq(true) end + + context 'invite by group manager' do + let(:group_manager) { Fabricate(:user) } + let(:group) { Fabricate(:group).tap { |g| g.add(group_manager); g.appoint_manager(group_manager) } } + let(:private_category) { Fabricate(:private_category, group: group) } + let(:group_private_topic) { Fabricate(:topic, category: private_category, user: group_manager) } + + context 'to an email' do + let(:randolph) { 'randolph@duke.ooo' } + + it "should attach group to the invite" do + invite = group_private_topic.invite(group_manager, randolph) + expect(invite.groups).to eq([group]) + end + end + + # should work for an existing user - give access, send notification + context 'to an existing user' do + let(:walter) { Fabricate(:walter_white) } + + it "should add user to the group" do + expect(Guardian.new(walter).can_see?(group_private_topic)).to be_falsey + invite = group_private_topic.invite(group_manager, walter.email) + expect(invite).to be_nil + expect(walter.groups).to include(group) + expect(Guardian.new(walter).can_see?(group_private_topic)).to be_truthy + end + end + + context 'to a previously-invited user' do + + end + end end From b5426763e49ce1ea14004ed796b1b0de1edb90b4 Mon Sep 17 00:00:00 2001 From: Gerhard Schlager Date: Thu, 12 Mar 2015 21:15:02 +0100 Subject: [PATCH 004/114] FIX: Importers should allow categories with existing name if the parent category is different This changes the content of `@categories_lookup` from `Category` objects to IDs since the category names aren't needed anymore. The lookup method has been renamed too. --- script/import_scripts/base.rb | 13 +++++++------ script/import_scripts/bbpress.rb | 2 +- script/import_scripts/bespoke_1.rb | 2 +- script/import_scripts/discuz_x.rb | 5 ++--- script/import_scripts/drupal.rb | 2 +- script/import_scripts/drupal_qa.rb | 2 +- script/import_scripts/kunena.rb | 5 ++--- script/import_scripts/mybb.rb | 5 ++--- script/import_scripts/ning.rb | 2 +- script/import_scripts/phpbb3.rb | 5 ++--- script/import_scripts/smf2.rb | 4 ++-- script/import_scripts/vanilla.rb | 5 ++--- script/import_scripts/vbulletin.rb | 4 ++-- script/import_scripts/vbulletin_old.rb | 2 +- 14 files changed, 27 insertions(+), 31 deletions(-) diff --git a/script/import_scripts/base.rb b/script/import_scripts/base.rb index 9ce88d6f97..190e0309d9 100644 --- a/script/import_scripts/base.rb +++ b/script/import_scripts/base.rb @@ -47,7 +47,7 @@ class ImportScripts::Base puts "loading existing categories..." CategoryCustomField.where(name: 'import_id').pluck(:category_id, :value).each do |category_id, import_id| - @categories_lookup[import_id] = Category.find(category_id.to_i) + @categories_lookup[import_id] = category_id end puts "loading existing posts..." @@ -156,7 +156,7 @@ class ImportScripts::Base end # Get the Discourse Category id based on the id of the source category - def category_from_imported_category_id(import_id) + def category_id_from_imported_category_id(import_id) @categories_lookup[import_id] || @categories_lookup[import_id.to_s] end @@ -330,7 +330,8 @@ class ImportScripts::Base results.each do |c| params = yield(c) - next if params.nil? # block returns nil to skip + # block returns nil to skip + next if params.nil? || category_id_from_imported_category_id(params[:id]) # Basic massaging on the category name params[:name] = "Blank" if params[:name].blank? @@ -347,13 +348,13 @@ class ImportScripts::Base end new_category = create_category(params, params[:id]) - @categories_lookup[params[:id]] = new_category + @categories_lookup[params[:id]] = new_category.id end end def create_category(opts, import_id) - existing = category_from_imported_category_id(import_id) || Category.where("LOWER(name) = ?", opts[:name].downcase).first - return existing if existing + existing = Category.where("LOWER(name) = ?", opts[:name].downcase).first + return existing if existing && existing.parent_category.try(:id) == opts[:parent_category_id] post_create_action = opts.delete(:post_create_action) diff --git a/script/import_scripts/bbpress.rb b/script/import_scripts/bbpress.rb index a06d85da5c..4a1937eed5 100644 --- a/script/import_scripts/bbpress.rb +++ b/script/import_scripts/bbpress.rb @@ -87,7 +87,7 @@ class ImportScripts::Bbpress < ImportScripts::Base mapped[:custom_fields] = {import_id: post["id"]} if post["post_type"] == "topic" - mapped[:category] = category_from_imported_category_id(post["post_parent"]).try(:name) + mapped[:category] = category_id_from_imported_category_id(post["post_parent"]) mapped[:title] = CGI.unescapeHTML post["post_title"] else parent = topic_lookup_from_imported_post_id(post["post_parent"]) diff --git a/script/import_scripts/bespoke_1.rb b/script/import_scripts/bespoke_1.rb index 2b94283aea..171b95b4a0 100644 --- a/script/import_scripts/bespoke_1.rb +++ b/script/import_scripts/bespoke_1.rb @@ -199,7 +199,7 @@ class ImportScripts::Bespoke < ImportScripts::Base topic = topics[post[:topic_id]] unless topic[:post_id] - mapped[:category] = category_from_imported_category_id(topic[:category_id]).try(:name) + mapped[:category] = category_id_from_imported_category_id(topic[:category_id]) mapped[:title] = post[:title] topic[:post_id] = post[:id] else diff --git a/script/import_scripts/discuz_x.rb b/script/import_scripts/discuz_x.rb index a3795bf7b9..6aef9b15e3 100644 --- a/script/import_scripts/discuz_x.rb +++ b/script/import_scripts/discuz_x.rb @@ -171,8 +171,7 @@ class ImportScripts::DiscuzX < ImportScripts::Base position: row['position'].to_i + max_position } if row['parent_id'].to_i > 0 - parent = category_from_imported_category_id(row['parent_id']) - h[:parent_category_id] = parent.id if parent + h[:parent_category_id] = category_id_from_imported_category_id(row['parent_id']) end h end @@ -217,7 +216,7 @@ class ImportScripts::DiscuzX < ImportScripts::Base mapped[:created_at] = Time.zone.at(m['post_time']) if m['is_first_post'] == 1 - mapped[:category] = category_from_imported_category_id(m['category_id']).try(:name) + mapped[:category] = category_id_from_imported_category_id(m['category_id']) mapped[:title] = CGI.unescapeHTML(m['title']) @first_post_id_by_topic_id[m['topic_id']] = m['id'] else diff --git a/script/import_scripts/drupal.rb b/script/import_scripts/drupal.rb index 7194a9a0fb..4a455c2042 100644 --- a/script/import_scripts/drupal.rb +++ b/script/import_scripts/drupal.rb @@ -122,7 +122,7 @@ class ImportScripts::Drupal < ImportScripts::Base { id: "nid:#{row['nid']}", user_id: user_id_from_imported_user_id(row['uid']) || -1, - category: category_from_imported_category_id(row['tid']).try(:name), + category: category_id_from_imported_category_id(row['tid']), raw: row['body'], created_at: Time.zone.at(row['created']), pinned_at: row['sticky'].to_i == 1 ? Time.zone.at(row['created']) : nil, diff --git a/script/import_scripts/drupal_qa.rb b/script/import_scripts/drupal_qa.rb index 307a7655f1..6b87f36528 100644 --- a/script/import_scripts/drupal_qa.rb +++ b/script/import_scripts/drupal_qa.rb @@ -61,7 +61,7 @@ class ImportScripts::DrupalQA < ImportScripts::Drupal { id: "nid:#{row['nid']}", user_id: user_id_from_imported_user_id(row['uid']) || -1, - category: category_from_imported_category_id((row['tid'] || '').split(',')[0]).try(:name), + category: category_id_from_imported_category_id((row['tid'] || '').split(',')[0]), raw: row['body'], created_at: Time.zone.at(row['created']), pinned_at: nil, diff --git a/script/import_scripts/kunena.rb b/script/import_scripts/kunena.rb index fe2634f111..f5b5e3a441 100644 --- a/script/import_scripts/kunena.rb +++ b/script/import_scripts/kunena.rb @@ -41,8 +41,7 @@ class ImportScripts::Kunena < ImportScripts::Base create_categories(@client.query("SELECT id, parent, name, description, ordering FROM jos_kunena_categories ORDER BY parent, id;")) do |c| h = {id: c['id'], name: c['name'], description: c['description'], position: c['ordering'].to_i} if c['parent'].to_i > 0 - parent = category_from_imported_category_id(c['parent']) - h[:parent_category_id] = parent.id if parent + h[:parent_category_id] = category_id_from_imported_category_id(c['parent']) end h end @@ -121,7 +120,7 @@ class ImportScripts::Kunena < ImportScripts::Base mapped[:created_at] = Time.zone.at(m['time']) if m['id'] == m['thread'] - mapped[:category] = category_from_imported_category_id(m['catid']).try(:name) + mapped[:category] = category_id_from_imported_category_id(m['catid']) mapped[:title] = m['subject'] else parent = topic_lookup_from_imported_post_id(m['parent']) diff --git a/script/import_scripts/mybb.rb b/script/import_scripts/mybb.rb index 2241748438..90e09714e6 100644 --- a/script/import_scripts/mybb.rb +++ b/script/import_scripts/mybb.rb @@ -69,8 +69,7 @@ class ImportScripts::MyBB < ImportScripts::Base create_categories(results) do |row| h = {id: row['id'], name: CGI.unescapeHTML(row['name']), description: CGI.unescapeHTML(row['description'])} if row['parent_id'].to_i > 0 - parent = category_from_imported_category_id(row['parent_id']) - h[:parent_category_id] = parent.id if parent + h[:parent_category_id] = category_id_from_imported_category_id(row['parent_id']) end h end @@ -125,7 +124,7 @@ class ImportScripts::MyBB < ImportScripts::Base mapped[:created_at] = Time.zone.at(m['post_time']) if m['id'] == m['first_post_id'] - mapped[:category] = category_from_imported_category_id(m['category_id']).try(:name) + mapped[:category] = category_id_from_imported_category_id(m['category_id']) mapped[:title] = CGI.unescapeHTML(m['title']) else parent = topic_lookup_from_imported_post_id(m['first_post_id']) diff --git a/script/import_scripts/ning.rb b/script/import_scripts/ning.rb index 5d81154204..2a1110f69d 100644 --- a/script/import_scripts/ning.rb +++ b/script/import_scripts/ning.rb @@ -200,7 +200,7 @@ class ImportScripts::Ning < ImportScripts::Base mapped[:user_id] = user_id_from_imported_user_id(topic["contributorName"]) || -1 mapped[:created_at] = Time.zone.parse(topic["createdDate"]) unless topic["category"].nil? || topic["category"].downcase == "uncategorized" - mapped[:category] = category_from_imported_category_id(topic["category"]).try(:name) + mapped[:category] = category_id_from_imported_category_id(topic["category"]) end if topic["category"].nil? && default_category mapped[:category] = default_category diff --git a/script/import_scripts/phpbb3.rb b/script/import_scripts/phpbb3.rb index 289141372c..bc0259c7db 100644 --- a/script/import_scripts/phpbb3.rb +++ b/script/import_scripts/phpbb3.rb @@ -114,8 +114,7 @@ class ImportScripts::PhpBB3 < ImportScripts::Base create_categories(results) do |row| h = {id: row['id'], name: CGI.unescapeHTML(row['name']), description: CGI.unescapeHTML(row['description'])} if row['parent_id'].to_i > 0 - parent = category_from_imported_category_id(row['parent_id']) - h[:parent_category_id] = parent.id if parent + h[:parent_category_id] = category_id_from_imported_category_id(row['parent_id']) end h end @@ -156,7 +155,7 @@ class ImportScripts::PhpBB3 < ImportScripts::Base mapped[:created_at] = Time.zone.at(m['post_time']) if m['id'] == m['first_post_id'] - mapped[:category] = category_from_imported_category_id(m['category_id']).try(:name) + mapped[:category] = category_id_from_imported_category_id(m['category_id']) mapped[:title] = CGI.unescapeHTML(m['title']) else parent = topic_lookup_from_imported_post_id(m['first_post_id']) diff --git a/script/import_scripts/smf2.rb b/script/import_scripts/smf2.rb index 9f08e63a11..3b03914f86 100644 --- a/script/import_scripts/smf2.rb +++ b/script/import_scripts/smf2.rb @@ -145,7 +145,7 @@ class ImportScripts::Smf2 < ImportScripts::Base FROM {prefix}boards ORDER BY id_parent ASC, id_board ASC SQL - parent_id = category_from_imported_category_id(board[:id_parent]).id if board[:id_parent] > 0 + parent_id = category_id_from_imported_category_id(board[:id_parent]) if board[:id_parent] > 0 groups = (board[:member_groups] || "").split(/,/).map(&:to_i) restricted = !groups.include?(GUEST_GROUP) && !groups.include?(MEMBER_GROUP) { @@ -257,7 +257,7 @@ class ImportScripts::Smf2 < ImportScripts::Base end } if message[:id_msg] == message[:id_first_msg] - post[:category] = category_from_imported_category_id(message[:id_board]).try(:name) + post[:category] = category_id_from_imported_category_id(message[:id_board]) post[:title] = decode_entities(message[:subject]) else parent = topic_lookup_from_imported_post_id(message[:id_first_msg]) diff --git a/script/import_scripts/vanilla.rb b/script/import_scripts/vanilla.rb index c65c27ebfb..264cb80eea 100644 --- a/script/import_scripts/vanilla.rb +++ b/script/import_scripts/vanilla.rb @@ -144,8 +144,7 @@ class ImportScripts::Vanilla < ImportScripts::Base description: clean_up(category[:description]), } if category[:parent_category_id] != "-1" - parent_category = category_from_imported_category_id(category[:parent_category_id]) - c[:parent_category_id] = parent_category.id if parent_category + c[:parent_category_id] = category_id_from_imported_category_id(category[:parent_category_id]) end c end @@ -162,7 +161,7 @@ class ImportScripts::Vanilla < ImportScripts::Base id: "discussion#" + discussion[:discussion_id], user_id: user_id_from_imported_user_id(discussion[:insert_user_id]) || Discourse::SYSTEM_USER_ID, title: discussion[:name], - category: category_from_imported_category_id(discussion[:category_id]).try(:name), + category: category_id_from_imported_category_id(discussion[:category_id]), raw: clean_up(discussion[:body]), created_at: parse_date(discussion[:date_inserted]), } diff --git a/script/import_scripts/vbulletin.rb b/script/import_scripts/vbulletin.rb index af83fd7129..77fc6119de 100644 --- a/script/import_scripts/vbulletin.rb +++ b/script/import_scripts/vbulletin.rb @@ -181,7 +181,7 @@ class ImportScripts::VBulletin < ImportScripts::Base name: @htmlentities.decode(category["title"]).strip, position: category["displayorder"], description: @htmlentities.decode(category["description"]).strip, - parent_category_id: category_from_imported_category_id(category["parentid"]).try(:[], "id") + parent_category_id: category_id_from_imported_category_id(category["parentid"]) } end end @@ -216,7 +216,7 @@ class ImportScripts::VBulletin < ImportScripts::Base id: topic_id, user_id: user_id_from_imported_user_id(topic["postuserid"]) || Discourse::SYSTEM_USER_ID, title: @htmlentities.decode(topic["title"]).strip[0...255], - category: category_from_imported_category_id(topic["forumid"]).try(:name), + category: category_id_from_imported_category_id(topic["forumid"]), raw: raw, created_at: parse_timestamp(topic["dateline"]), visible: topic["visible"].to_i == 1, diff --git a/script/import_scripts/vbulletin_old.rb b/script/import_scripts/vbulletin_old.rb index 6e27f034b2..b2989199d7 100644 --- a/script/import_scripts/vbulletin_old.rb +++ b/script/import_scripts/vbulletin_old.rb @@ -460,7 +460,7 @@ class ImportScripts::VBulletinOld < ImportScripts::Base id: id, user_id: user_id_from_imported_user_id(topic[:postuserid]) || Discourse::SYSTEM_USER_ID, title: CGI.unescapeHTML(topic[:title]).strip[0...255], - category: category_from_imported_category_id(topic[:forumid]).try(:name), + category: category_id_from_imported_category_id(topic[:forumid]), raw: post[:raw], created_at: Time.at(topic[:dateline].to_i), visible: topic[:visible].to_i == 1, From 1e339ad527c885cbba1d20e0291e62045bc2a86c Mon Sep 17 00:00:00 2001 From: Neil Lalonde Date: Thu, 12 Mar 2015 18:46:22 -0400 Subject: [PATCH 005/114] FIX: handle missing post body in json in Ning importer --- script/import_scripts/ning.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/script/import_scripts/ning.rb b/script/import_scripts/ning.rb index 2a1110f69d..1387768757 100644 --- a/script/import_scripts/ning.rb +++ b/script/import_scripts/ning.rb @@ -270,6 +270,7 @@ class ImportScripts::Ning < ImportScripts::Base end def process_ning_post_body(arg) + return "" if arg.nil? raw = arg.gsub("

\n", "

") # youtube iframe From a82530012a0d20dfd52ab8a69afa1423f43da48c Mon Sep 17 00:00:00 2001 From: Sam Date: Fri, 13 Mar 2015 16:15:13 +1100 Subject: [PATCH 006/114] FEATURE: Allow selection of highlight js languages PERF: stop loading highlight js on load To get latest highlight js run bin/rake highlightjs:update --- .../discourse/dialects/code_dialect.js | 27 ++++++++++------ .../discourse/lib/highlight-syntax.js.es6 | 2 +- .../discourse/lib/load-script.js.es6 | 10 ++++-- app/assets/javascripts/main_include.js | 5 --- app/controllers/highlight_js_controller.rb | 26 +++++++++++++++ .../common/_discourse_javascript.html.erb | 1 + config/application.rb | 3 ++ config/initializers/06-mini_profiler.rb | 1 + config/locales/server.en.yml | 1 + config/nginx.sample.conf | 2 +- config/routes.rb | 2 ++ config/site_settings.yml | 5 +++ lib/highlight_js/assets/highlight.js | 1 + lib/highlight_js/assets/lang/1c.js | 1 + lib/highlight_js/assets/lang/actionscript.js | 1 + lib/highlight_js/assets/lang/apache.js | 1 + lib/highlight_js/assets/lang/applescript.js | 1 + lib/highlight_js/assets/lang/asciidoc.js | 1 + lib/highlight_js/assets/lang/aspectj.js | 1 + lib/highlight_js/assets/lang/autohotkey.js | 1 + lib/highlight_js/assets/lang/avrasm.js | 1 + lib/highlight_js/assets/lang/axapta.js | 1 + lib/highlight_js/assets/lang/bash.js | 1 + lib/highlight_js/assets/lang/brainfuck.js | 1 + lib/highlight_js/assets/lang/capnproto.js | 1 + lib/highlight_js/assets/lang/clojure-repl.js | 1 + lib/highlight_js/assets/lang/clojure.js | 1 + lib/highlight_js/assets/lang/cmake.js | 1 + lib/highlight_js/assets/lang/coffeescript.js | 1 + lib/highlight_js/assets/lang/cpp.js | 1 + lib/highlight_js/assets/lang/cs.js | 1 + lib/highlight_js/assets/lang/css.js | 1 + lib/highlight_js/assets/lang/d.js | 1 + lib/highlight_js/assets/lang/dart.js | 1 + lib/highlight_js/assets/lang/delphi.js | 1 + lib/highlight_js/assets/lang/diff.js | 1 + lib/highlight_js/assets/lang/django.js | 1 + lib/highlight_js/assets/lang/dockerfile.js | 1 + lib/highlight_js/assets/lang/dos.js | 1 + lib/highlight_js/assets/lang/dust.js | 1 + lib/highlight_js/assets/lang/elixir.js | 1 + lib/highlight_js/assets/lang/erb.js | 1 + lib/highlight_js/assets/lang/erlang-repl.js | 1 + lib/highlight_js/assets/lang/erlang.js | 1 + lib/highlight_js/assets/lang/fix.js | 1 + lib/highlight_js/assets/lang/fortran.js | 1 + lib/highlight_js/assets/lang/fsharp.js | 1 + lib/highlight_js/assets/lang/gcode.js | 1 + lib/highlight_js/assets/lang/gherkin.js | 1 + lib/highlight_js/assets/lang/glsl.js | 1 + lib/highlight_js/assets/lang/go.js | 1 + lib/highlight_js/assets/lang/gradle.js | 1 + lib/highlight_js/assets/lang/groovy.js | 1 + lib/highlight_js/assets/lang/haml.js | 1 + lib/highlight_js/assets/lang/handlebars.js | 1 + lib/highlight_js/assets/lang/haskell.js | 1 + lib/highlight_js/assets/lang/haxe.js | 1 + lib/highlight_js/assets/lang/http.js | 1 + lib/highlight_js/assets/lang/ini.js | 1 + lib/highlight_js/assets/lang/java.js | 1 + lib/highlight_js/assets/lang/javascript.js | 1 + lib/highlight_js/assets/lang/json.js | 1 + lib/highlight_js/assets/lang/julia.js | 1 + lib/highlight_js/assets/lang/lasso.js | 1 + lib/highlight_js/assets/lang/less.js | 1 + lib/highlight_js/assets/lang/lisp.js | 1 + .../assets/lang/livecodeserver.js | 1 + lib/highlight_js/assets/lang/livescript.js | 1 + lib/highlight_js/assets/lang/lua.js | 1 + lib/highlight_js/assets/lang/makefile.js | 1 + lib/highlight_js/assets/lang/markdown.js | 1 + lib/highlight_js/assets/lang/mathematica.js | 2 ++ lib/highlight_js/assets/lang/matlab.js | 1 + lib/highlight_js/assets/lang/mel.js | 1 + lib/highlight_js/assets/lang/mercury.js | 1 + lib/highlight_js/assets/lang/mizar.js | 1 + lib/highlight_js/assets/lang/monkey.js | 1 + lib/highlight_js/assets/lang/nginx.js | 1 + lib/highlight_js/assets/lang/nimrod.js | 1 + lib/highlight_js/assets/lang/nix.js | 1 + lib/highlight_js/assets/lang/nsis.js | 1 + lib/highlight_js/assets/lang/objectivec.js | 1 + lib/highlight_js/assets/lang/ocaml.js | 1 + lib/highlight_js/assets/lang/oxygene.js | 1 + lib/highlight_js/assets/lang/parser3.js | 1 + lib/highlight_js/assets/lang/perl.js | 1 + lib/highlight_js/assets/lang/pf.js | 1 + lib/highlight_js/assets/lang/php.js | 1 + lib/highlight_js/assets/lang/powershell.js | 1 + lib/highlight_js/assets/lang/processing.js | 1 + lib/highlight_js/assets/lang/profile.js | 1 + lib/highlight_js/assets/lang/protobuf.js | 1 + lib/highlight_js/assets/lang/puppet.js | 1 + lib/highlight_js/assets/lang/python.js | 1 + lib/highlight_js/assets/lang/q.js | 1 + lib/highlight_js/assets/lang/r.js | 1 + lib/highlight_js/assets/lang/rib.js | 1 + lib/highlight_js/assets/lang/roboconf.js | 1 + lib/highlight_js/assets/lang/rsl.js | 1 + lib/highlight_js/assets/lang/ruby.js | 1 + lib/highlight_js/assets/lang/ruleslanguage.js | 1 + lib/highlight_js/assets/lang/rust.js | 1 + lib/highlight_js/assets/lang/scala.js | 1 + lib/highlight_js/assets/lang/scheme.js | 1 + lib/highlight_js/assets/lang/scilab.js | 1 + lib/highlight_js/assets/lang/scss.js | 1 + lib/highlight_js/assets/lang/smali.js | 1 + lib/highlight_js/assets/lang/smalltalk.js | 1 + lib/highlight_js/assets/lang/sml.js | 1 + lib/highlight_js/assets/lang/sql.js | 1 + lib/highlight_js/assets/lang/stata.js | 1 + lib/highlight_js/assets/lang/step21.js | 1 + lib/highlight_js/assets/lang/stylus.js | 1 + lib/highlight_js/assets/lang/swift.js | 1 + lib/highlight_js/assets/lang/tcl.js | 1 + lib/highlight_js/assets/lang/tex.js | 1 + lib/highlight_js/assets/lang/thrift.js | 1 + lib/highlight_js/assets/lang/twig.js | 1 + lib/highlight_js/assets/lang/typescript.js | 1 + lib/highlight_js/assets/lang/vala.js | 1 + lib/highlight_js/assets/lang/vbnet.js | 1 + lib/highlight_js/assets/lang/vbscript-html.js | 1 + lib/highlight_js/assets/lang/vbscript.js | 1 + lib/highlight_js/assets/lang/verilog.js | 1 + lib/highlight_js/assets/lang/vhdl.js | 1 + lib/highlight_js/assets/lang/vim.js | 1 + lib/highlight_js/assets/lang/x86asm.js | 1 + lib/highlight_js/assets/lang/xl.js | 1 + lib/highlight_js/assets/lang/xml.js | 1 + lib/highlight_js/highlight_js.rb | 32 +++++++++++++++++++ lib/pretty_text.rb | 1 - lib/site_setting_extension.rb | 11 +++++-- lib/tasks/highlight.rake | 25 +++++++++++++++ .../highlight_js/highlight_js_spec.rb | 23 +++++++++++++ spec/components/pretty_text_spec.rb | 4 +++ test/javascripts/helpers/site-settings.js | 2 +- test/javascripts/test_helper.js | 2 -- 137 files changed, 277 insertions(+), 26 deletions(-) create mode 100644 app/controllers/highlight_js_controller.rb create mode 100644 lib/highlight_js/assets/highlight.js create mode 100644 lib/highlight_js/assets/lang/1c.js create mode 100644 lib/highlight_js/assets/lang/actionscript.js create mode 100644 lib/highlight_js/assets/lang/apache.js create mode 100644 lib/highlight_js/assets/lang/applescript.js create mode 100644 lib/highlight_js/assets/lang/asciidoc.js create mode 100644 lib/highlight_js/assets/lang/aspectj.js create mode 100644 lib/highlight_js/assets/lang/autohotkey.js create mode 100644 lib/highlight_js/assets/lang/avrasm.js create mode 100644 lib/highlight_js/assets/lang/axapta.js create mode 100644 lib/highlight_js/assets/lang/bash.js create mode 100644 lib/highlight_js/assets/lang/brainfuck.js create mode 100644 lib/highlight_js/assets/lang/capnproto.js create mode 100644 lib/highlight_js/assets/lang/clojure-repl.js create mode 100644 lib/highlight_js/assets/lang/clojure.js create mode 100644 lib/highlight_js/assets/lang/cmake.js create mode 100644 lib/highlight_js/assets/lang/coffeescript.js create mode 100644 lib/highlight_js/assets/lang/cpp.js create mode 100644 lib/highlight_js/assets/lang/cs.js create mode 100644 lib/highlight_js/assets/lang/css.js create mode 100644 lib/highlight_js/assets/lang/d.js create mode 100644 lib/highlight_js/assets/lang/dart.js create mode 100644 lib/highlight_js/assets/lang/delphi.js create mode 100644 lib/highlight_js/assets/lang/diff.js create mode 100644 lib/highlight_js/assets/lang/django.js create mode 100644 lib/highlight_js/assets/lang/dockerfile.js create mode 100644 lib/highlight_js/assets/lang/dos.js create mode 100644 lib/highlight_js/assets/lang/dust.js create mode 100644 lib/highlight_js/assets/lang/elixir.js create mode 100644 lib/highlight_js/assets/lang/erb.js create mode 100644 lib/highlight_js/assets/lang/erlang-repl.js create mode 100644 lib/highlight_js/assets/lang/erlang.js create mode 100644 lib/highlight_js/assets/lang/fix.js create mode 100644 lib/highlight_js/assets/lang/fortran.js create mode 100644 lib/highlight_js/assets/lang/fsharp.js create mode 100644 lib/highlight_js/assets/lang/gcode.js create mode 100644 lib/highlight_js/assets/lang/gherkin.js create mode 100644 lib/highlight_js/assets/lang/glsl.js create mode 100644 lib/highlight_js/assets/lang/go.js create mode 100644 lib/highlight_js/assets/lang/gradle.js create mode 100644 lib/highlight_js/assets/lang/groovy.js create mode 100644 lib/highlight_js/assets/lang/haml.js create mode 100644 lib/highlight_js/assets/lang/handlebars.js create mode 100644 lib/highlight_js/assets/lang/haskell.js create mode 100644 lib/highlight_js/assets/lang/haxe.js create mode 100644 lib/highlight_js/assets/lang/http.js create mode 100644 lib/highlight_js/assets/lang/ini.js create mode 100644 lib/highlight_js/assets/lang/java.js create mode 100644 lib/highlight_js/assets/lang/javascript.js create mode 100644 lib/highlight_js/assets/lang/json.js create mode 100644 lib/highlight_js/assets/lang/julia.js create mode 100644 lib/highlight_js/assets/lang/lasso.js create mode 100644 lib/highlight_js/assets/lang/less.js create mode 100644 lib/highlight_js/assets/lang/lisp.js create mode 100644 lib/highlight_js/assets/lang/livecodeserver.js create mode 100644 lib/highlight_js/assets/lang/livescript.js create mode 100644 lib/highlight_js/assets/lang/lua.js create mode 100644 lib/highlight_js/assets/lang/makefile.js create mode 100644 lib/highlight_js/assets/lang/markdown.js create mode 100644 lib/highlight_js/assets/lang/mathematica.js create mode 100644 lib/highlight_js/assets/lang/matlab.js create mode 100644 lib/highlight_js/assets/lang/mel.js create mode 100644 lib/highlight_js/assets/lang/mercury.js create mode 100644 lib/highlight_js/assets/lang/mizar.js create mode 100644 lib/highlight_js/assets/lang/monkey.js create mode 100644 lib/highlight_js/assets/lang/nginx.js create mode 100644 lib/highlight_js/assets/lang/nimrod.js create mode 100644 lib/highlight_js/assets/lang/nix.js create mode 100644 lib/highlight_js/assets/lang/nsis.js create mode 100644 lib/highlight_js/assets/lang/objectivec.js create mode 100644 lib/highlight_js/assets/lang/ocaml.js create mode 100644 lib/highlight_js/assets/lang/oxygene.js create mode 100644 lib/highlight_js/assets/lang/parser3.js create mode 100644 lib/highlight_js/assets/lang/perl.js create mode 100644 lib/highlight_js/assets/lang/pf.js create mode 100644 lib/highlight_js/assets/lang/php.js create mode 100644 lib/highlight_js/assets/lang/powershell.js create mode 100644 lib/highlight_js/assets/lang/processing.js create mode 100644 lib/highlight_js/assets/lang/profile.js create mode 100644 lib/highlight_js/assets/lang/protobuf.js create mode 100644 lib/highlight_js/assets/lang/puppet.js create mode 100644 lib/highlight_js/assets/lang/python.js create mode 100644 lib/highlight_js/assets/lang/q.js create mode 100644 lib/highlight_js/assets/lang/r.js create mode 100644 lib/highlight_js/assets/lang/rib.js create mode 100644 lib/highlight_js/assets/lang/roboconf.js create mode 100644 lib/highlight_js/assets/lang/rsl.js create mode 100644 lib/highlight_js/assets/lang/ruby.js create mode 100644 lib/highlight_js/assets/lang/ruleslanguage.js create mode 100644 lib/highlight_js/assets/lang/rust.js create mode 100644 lib/highlight_js/assets/lang/scala.js create mode 100644 lib/highlight_js/assets/lang/scheme.js create mode 100644 lib/highlight_js/assets/lang/scilab.js create mode 100644 lib/highlight_js/assets/lang/scss.js create mode 100644 lib/highlight_js/assets/lang/smali.js create mode 100644 lib/highlight_js/assets/lang/smalltalk.js create mode 100644 lib/highlight_js/assets/lang/sml.js create mode 100644 lib/highlight_js/assets/lang/sql.js create mode 100644 lib/highlight_js/assets/lang/stata.js create mode 100644 lib/highlight_js/assets/lang/step21.js create mode 100644 lib/highlight_js/assets/lang/stylus.js create mode 100644 lib/highlight_js/assets/lang/swift.js create mode 100644 lib/highlight_js/assets/lang/tcl.js create mode 100644 lib/highlight_js/assets/lang/tex.js create mode 100644 lib/highlight_js/assets/lang/thrift.js create mode 100644 lib/highlight_js/assets/lang/twig.js create mode 100644 lib/highlight_js/assets/lang/typescript.js create mode 100644 lib/highlight_js/assets/lang/vala.js create mode 100644 lib/highlight_js/assets/lang/vbnet.js create mode 100644 lib/highlight_js/assets/lang/vbscript-html.js create mode 100644 lib/highlight_js/assets/lang/vbscript.js create mode 100644 lib/highlight_js/assets/lang/verilog.js create mode 100644 lib/highlight_js/assets/lang/vhdl.js create mode 100644 lib/highlight_js/assets/lang/vim.js create mode 100644 lib/highlight_js/assets/lang/x86asm.js create mode 100644 lib/highlight_js/assets/lang/xl.js create mode 100644 lib/highlight_js/assets/lang/xml.js create mode 100644 lib/highlight_js/highlight_js.rb create mode 100644 lib/tasks/highlight.rake create mode 100644 spec/components/highlight_js/highlight_js_spec.rb diff --git a/app/assets/javascripts/discourse/dialects/code_dialect.js b/app/assets/javascripts/discourse/dialects/code_dialect.js index 9131775a34..f6260d8318 100644 --- a/app/assets/javascripts/discourse/dialects/code_dialect.js +++ b/app/assets/javascripts/discourse/dialects/code_dialect.js @@ -2,13 +2,22 @@ Support for various code blocks **/ -var acceptableCodeClasses = - ["auto", "1c", "actionscript", "apache", "applescript", "avrasm", "axapta", "bash", "brainfuck", - "clojure", "cmake", "coffeescript", "cpp", "cs", "css", "d", "delphi", "diff", "xml", "django", "dos", - "erlang-repl", "erlang", "glsl", "go", "handlebars", "haskell", "http", "ini", "java", "javascript", - "json", "lisp", "lua", "markdown", "matlab", "mel", "nginx", "nohighlight", "objectivec", "parser3", - "perl", "php", "profile", "python", "r", "rib", "rsl", "ruby", "rust", "scala", "smalltalk", "sql", - "tex", "text", "vala", "vbscript", "vhdl"]; +var acceptableCodeClasses; + +function init() { + acceptableCodeClasses = Discourse.SiteSettings.highlighted_languages.split("|"); + if (Discourse.SiteSettings.highlighted_languages.length > 0) { + var regexpSource = "^lang-(" + "nohighlight|auto|" + Discourse.SiteSettings.highlighted_languages + ")$"; + Discourse.Markdown.whiteListTag('code', 'class', new RegExp(regexpSource, "i")); + } +} + +if (Discourse.SiteSettings && Discourse.SiteSettings.highlighted_languages) { + init(); +} else { + Discourse.initializer({initialize: init, name: 'load-acceptable-code-classes'}); +} + var textCodeClasses = ["text", "pre", "plain"]; @@ -27,6 +36,7 @@ Discourse.Dialect.replaceBlock({ emitter: function(blockContents, matches) { var klass = Discourse.SiteSettings.default_code_lang; + if (matches[1] && acceptableCodeClasses.indexOf(matches[1]) !== -1) { klass = matches[1]; } @@ -69,6 +79,3 @@ Discourse.Dialect.on('parseNode', function (event) { } }); -// Whitelist the language classes -var regexpSource = "^lang-(" + acceptableCodeClasses.join('|') + ")$"; -Discourse.Markdown.whiteListTag('code', 'class', new RegExp(regexpSource, "i")); diff --git a/app/assets/javascripts/discourse/lib/highlight-syntax.js.es6 b/app/assets/javascripts/discourse/lib/highlight-syntax.js.es6 index e1224dee3b..a30c86e303 100644 --- a/app/assets/javascripts/discourse/lib/highlight-syntax.js.es6 +++ b/app/assets/javascripts/discourse/lib/highlight-syntax.js.es6 @@ -5,6 +5,6 @@ import loadScript from 'discourse/lib/load-script'; export default function highlightSyntax($elem) { const selector = Discourse.SiteSettings.autohighlight_all_code ? 'pre code' : 'pre code[class]'; $(selector, $elem).each(function(i, e) { - loadScript("/javascripts/highlight.pack.js").then(() => hljs.highlightBlock(e)); + loadScript(Discourse.HighlightJSPath).then(() => hljs.highlightBlock(e)); }); } diff --git a/app/assets/javascripts/discourse/lib/load-script.js.es6 b/app/assets/javascripts/discourse/lib/load-script.js.es6 index d6dd96bd39..6b39d650af 100644 --- a/app/assets/javascripts/discourse/lib/load-script.js.es6 +++ b/app/assets/javascripts/discourse/lib/load-script.js.es6 @@ -31,13 +31,19 @@ export default function loadScript(url, opts) { resolve(); }; + var cdnUrl = url; + + if (Discourse.CDN && url[0] === "/") { + cdnUrl = Discourse.CDN + url; + } + // Some javascript depends on the path of where it is loaded (ace editor) // to dynamically load more JS. In that case, add the `scriptTag: true` // option. if (opts.scriptTag) { - loadWithTag(url, cb); + loadWithTag(cdnUrl, cb); } else { - $.getScript(url).then(cb); + $.getScript(cdnUrl).then(cb); } }); } diff --git a/app/assets/javascripts/main_include.js b/app/assets/javascripts/main_include.js index e2e63bd42e..b6dad34ded 100644 --- a/app/assets/javascripts/main_include.js +++ b/app/assets/javascripts/main_include.js @@ -4,11 +4,6 @@ // Pagedown customizations //= require ./pagedown_custom.js -// This is a BUG we should fix -// it is only required here cause preview is not loading it using LAB -//= require highlight.pack.js -// - // Stuff we need to load first //= require ./discourse/lib/load-script //= require ./discourse/lib/notification-levels diff --git a/app/controllers/highlight_js_controller.rb b/app/controllers/highlight_js_controller.rb new file mode 100644 index 0000000000..74ed98b3c8 --- /dev/null +++ b/app/controllers/highlight_js_controller.rb @@ -0,0 +1,26 @@ +class HighlightJsController < ApplicationController + skip_before_filter :redirect_to_login_if_required, :check_xhr, :verify_authenticity_token, only: [:show] + + def show + RailsMultisite::ConnectionManagement.with_hostname(params[:hostname]) do + + current_version = HighlightJs.version(SiteSetting.highlighted_languages) + + if current_version != params[:version] + return redirect_to path(HighlightJs.path) + end + + # note, this can be slightly optimised by caching the bundled file, it cuts down on N reads + # our nginx config caches this so in practical terms it does not really matter and keeps + # code simpler + highlight_js = HighlightJs.bundle(SiteSetting.highlighted_languages.split("|")) + + response.headers["Last-Modified"] = 10.years.ago.httpdate + response.headers["Content-Length"] = highlight_js.bytesize.to_s + expires_in 1.year, public: true + + render text: highlight_js, disposition: nil, content_type: 'application/javascript' + end + end +end + diff --git a/app/views/common/_discourse_javascript.html.erb b/app/views/common/_discourse_javascript.html.erb index bcacaa4321..8f0c83dd7e 100644 --- a/app/views/common/_discourse_javascript.html.erb +++ b/app/views/common/_discourse_javascript.html.erb @@ -41,6 +41,7 @@ Discourse.start(); Discourse.set('assetVersion','<%= Discourse.assets_digest %>'); Discourse.Session.currentProp("disableCustomCSS", <%= loading_admin? %>); + Discourse.HighlightJSPath = <%= HighlightJs.path.inspect.html_safe %>; <%= script 'browser-update' %> diff --git a/config/application.rb b/config/application.rb index 193810ffcf..2f72b3a826 100644 --- a/config/application.rb +++ b/config/application.rb @@ -32,6 +32,9 @@ module Discourse require 'es6_module_transpiler/rails' require 'js_locale_helper' + # tiny file needed by site settings + require 'highlight_js/highlight_js' + # mocha hates us, active_support/testing/mochaing.rb line 2 is requiring the wrong # require, patched in source, on upgrade remove this if Rails.env.test? || Rails.env.development? diff --git a/config/initializers/06-mini_profiler.rb b/config/initializers/06-mini_profiler.rb index 89254a7d2e..cc583b4bb3 100644 --- a/config/initializers/06-mini_profiler.rb +++ b/config/initializers/06-mini_profiler.rb @@ -27,6 +27,7 @@ if defined?(Rack::MiniProfiler) (path !~ /assets/) && (path !~ /\/user_avatar\//) && (path !~ /\/letter_avatar\//) && + (path !~ /\/highlight-js\//) && (path !~ /qunit/) && (path !~ /srv\/status/) && (path !~ /commits-widget/) && diff --git a/config/locales/server.en.yml b/config/locales/server.en.yml index 7a39442b8b..4dae96ad89 100644 --- a/config/locales/server.en.yml +++ b/config/locales/server.en.yml @@ -1104,6 +1104,7 @@ en: default_code_lang: "Default programming language syntax highlighting applied to GitHub code blocks (lang-auto, ruby, python etc.)" warn_reviving_old_topic_age: "When someone starts replying to a topic where the last reply is older than this many days, a warning will be displayed. Disable by setting to 0." autohighlight_all_code: "Force apply code highlighting to all preformatted code blocks even when they didn't explicitly specify the language." + highlighted_languages: "Included syntax highlighting rules. (Warning: including too many langauges may impact performance) see: https://highlightjs.org/static/demo/ for a demo" embeddable_host: "Host that can embed the comments from this Discourse forum. Hostname only, do not begin with http://" feed_polling_enabled: "EMBEDDING ONLY: Whether to embed a RSS/ATOM feed as posts." diff --git a/config/nginx.sample.conf b/config/nginx.sample.conf index 0f0e61fe92..7ff30b9dfd 100644 --- a/config/nginx.sample.conf +++ b/config/nginx.sample.conf @@ -158,7 +158,7 @@ server { # This big block is needed so we can selectively enable # acceleration for backups and avatars # see note about repetition above - location ~ ^/(letter_avatar|user_avatar) { + location ~ ^/(letter_avatar|user_avatar|highlight-js) { proxy_set_header Host $http_host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; diff --git a/config/routes.rb b/config/routes.rb index a1d38c8fb6..c4b3851b20 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -274,6 +274,8 @@ Discourse::Application.routes.draw do get "letter_avatar/:username/:size/:version.png" => "user_avatars#show_letter", format: false, constraints: { hostname: /[\w\.-]+/ } get "user_avatar/:hostname/:username/:size/:version.png" => "user_avatars#show", format: false, constraints: { hostname: /[\w\.-]+/ } + get "highlight-js/:hostname/:version.js" => "highlight_js#show", format: false, constraints: { hostname: /[\w\.-]+/ } + get "uploads/:site/:id/:sha.:extension" => "uploads#show", constraints: {site: /\w+/, id: /\d+/, sha: /[a-z0-9]{15,16}/i, extension: /\w{2,}/} get "uploads/:site/:sha" => "uploads#show", constraints: { site: /\w+/, sha: /[a-z0-9]{40}/} post "uploads" => "uploads#create" diff --git a/config/site_settings.yml b/config/site_settings.yml index 3982f5253a..e1e0e9ddc8 100644 --- a/config/site_settings.yml +++ b/config/site_settings.yml @@ -400,6 +400,11 @@ posting: autohighlight_all_code: client: true default: false + highlighted_languages: + default: 'apache|bash|cs|cpp|css|coffeescript|diff|xml|http|ini|json|java|javascript|makefile|markdown|nginx|objectivec|ruby|perl|php|python|sql|handlebars' + choices: 'HighlightJs.languages' + type: list + client: true delete_old_hidden_posts: true censored_words: client: true diff --git a/lib/highlight_js/assets/highlight.js b/lib/highlight_js/assets/highlight.js new file mode 100644 index 0000000000..98da88297b --- /dev/null +++ b/lib/highlight_js/assets/highlight.js @@ -0,0 +1 @@ +!function(e){"undefined"!=typeof exports?e(exports):(window.hljs=e({}),"function"==typeof define&&define.amd&&define([],function(){return window.hljs}))}(function(e){function n(e){return e.replace(/&/gm,"&").replace(//gm,">")}function t(e){return e.nodeName.toLowerCase()}function r(e,n){var t=e&&e.exec(n);return t&&0==t.index}function a(e){var n=(e.className+" "+(e.parentNode?e.parentNode.className:"")).split(/\s+/);return n=n.map(function(e){return e.replace(/^lang(uage)?-/,"")}),n.filter(function(e){return N(e)||/no(-?)highlight|plain|text/.test(e)})[0]}function i(e,n){var t,r={};for(t in e)r[t]=e[t];if(n)for(t in n)r[t]=n[t];return r}function o(e){var n=[];return function r(e,a){for(var i=e.firstChild;i;i=i.nextSibling)3==i.nodeType?a+=i.nodeValue.length:1==i.nodeType&&(n.push({event:"start",offset:a,node:i}),a=r(i,a),t(i).match(/br|hr|img|input/)||n.push({event:"stop",offset:a,node:i}));return a}(e,0),n}function u(e,r,a){function i(){return e.length&&r.length?e[0].offset!=r[0].offset?e[0].offset"}function u(e){l+=""}function c(e){("start"==e.event?o:u)(e.node)}for(var s=0,l="",f=[];e.length||r.length;){var g=i();if(l+=n(a.substr(s,g[0].offset-s)),s=g[0].offset,g==e){f.reverse().forEach(u);do c(g.splice(0,1)[0]),g=i();while(g==e&&g.length&&g[0].offset==s);f.reverse().forEach(o)}else"start"==g[0].event?f.push(g[0].node):f.pop(),c(g.splice(0,1)[0])}return l+n(a.substr(s))}function c(e){function n(e){return e&&e.source||e}function t(t,r){return new RegExp(n(t),"m"+(e.cI?"i":"")+(r?"g":""))}function r(a,o){if(!a.compiled){if(a.compiled=!0,a.k=a.k||a.bK,a.k){var u={},c=function(n,t){e.cI&&(t=t.toLowerCase()),t.split(" ").forEach(function(e){var t=e.split("|");u[t[0]]=[n,t[1]?Number(t[1]):1]})};"string"==typeof a.k?c("keyword",a.k):Object.keys(a.k).forEach(function(e){c(e,a.k[e])}),a.k=u}a.lR=t(a.l||/\b\w+\b/,!0),o&&(a.bK&&(a.b="\\b("+a.bK.split(" ").join("|")+")\\b"),a.b||(a.b=/\B|\b/),a.bR=t(a.b),a.e||a.eW||(a.e=/\B|\b/),a.e&&(a.eR=t(a.e)),a.tE=n(a.e)||"",a.eW&&o.tE&&(a.tE+=(a.e?"|":"")+o.tE)),a.i&&(a.iR=t(a.i)),void 0===a.r&&(a.r=1),a.c||(a.c=[]);var s=[];a.c.forEach(function(e){e.v?e.v.forEach(function(n){s.push(i(e,n))}):s.push("self"==e?a:e)}),a.c=s,a.c.forEach(function(e){r(e,a)}),a.starts&&r(a.starts,o);var l=a.c.map(function(e){return e.bK?"\\.?("+e.b+")\\.?":e.b}).concat([a.tE,a.i]).map(n).filter(Boolean);a.t=l.length?t(l.join("|"),!0):{exec:function(){return null}}}}r(e)}function s(e,t,a,i){function o(e,n){for(var t=0;t";return i+=e+'">',i+n+o}function d(){if(!L.k)return n(y);var e="",t=0;L.lR.lastIndex=0;for(var r=L.lR.exec(y);r;){e+=n(y.substr(t,r.index-t));var a=g(L,r);a?(B+=a[1],e+=p(a[0],n(r[0]))):e+=n(r[0]),t=L.lR.lastIndex,r=L.lR.exec(y)}return e+n(y.substr(t))}function h(){if(L.sL&&!w[L.sL])return n(y);var e=L.sL?s(L.sL,y,!0,M[L.sL]):l(y);return L.r>0&&(B+=e.r),"continuous"==L.subLanguageMode&&(M[L.sL]=e.top),p(e.language,e.value,!1,!0)}function b(){return void 0!==L.sL?h():d()}function v(e,t){var r=e.cN?p(e.cN,"",!0):"";e.rB?(k+=r,y=""):e.eB?(k+=n(t)+r,y=""):(k+=r,y=t),L=Object.create(e,{parent:{value:L}})}function m(e,t){if(y+=e,void 0===t)return k+=b(),0;var r=o(t,L);if(r)return k+=b(),v(r,t),r.rB?0:t.length;var a=u(L,t);if(a){var i=L;i.rE||i.eE||(y+=t),k+=b();do L.cN&&(k+=""),B+=L.r,L=L.parent;while(L!=a.parent);return i.eE&&(k+=n(t)),y="",a.starts&&v(a.starts,""),i.rE?0:t.length}if(f(t,L))throw new Error('Illegal lexeme "'+t+'" for mode "'+(L.cN||"")+'"');return y+=t,t.length||1}var E=N(e);if(!E)throw new Error('Unknown language: "'+e+'"');c(E);var R,L=i||E,M={},k="";for(R=L;R!=E;R=R.parent)R.cN&&(k=p(R.cN,"",!0)+k);var y="",B=0;try{for(var C,j,I=0;;){if(L.t.lastIndex=I,C=L.t.exec(t),!C)break;j=m(t.substr(I,C.index-I),C[0]),I=C.index+j}for(m(t.substr(I)),R=L;R.parent;R=R.parent)R.cN&&(k+="");return{r:B,value:k,language:e,top:L}}catch(S){if(-1!=S.message.indexOf("Illegal"))return{r:0,value:n(t)};throw S}}function l(e,t){t=t||x.languages||Object.keys(w);var r={r:0,value:n(e)},a=r;return t.forEach(function(n){if(N(n)){var t=s(n,e,!1);t.language=n,t.r>a.r&&(a=t),t.r>r.r&&(a=r,r=t)}}),a.language&&(r.second_best=a),r}function f(e){return x.tabReplace&&(e=e.replace(/^((<[^>]+>|\t)+)/gm,function(e,n){return n.replace(/\t/g,x.tabReplace)})),x.useBR&&(e=e.replace(/\n/g,"
")),e}function g(e,n,t){var r=n?E[n]:t,a=[e.trim()];return e.match(/\bhljs\b/)||a.push("hljs"),-1===e.indexOf(r)&&a.push(r),a.join(" ").trim()}function p(e){var n=a(e);if(!/no(-?)highlight|plain|text/.test(n)){var t;x.useBR?(t=document.createElementNS("http://www.w3.org/1999/xhtml","div"),t.innerHTML=e.innerHTML.replace(/\n/g,"").replace(//g,"\n")):t=e;var r=t.textContent,i=n?s(n,r,!0):l(r),c=o(t);if(c.length){var p=document.createElementNS("http://www.w3.org/1999/xhtml","div");p.innerHTML=i.value,i.value=u(c,o(p),r)}i.value=f(i.value),e.innerHTML=i.value,e.className=g(e.className,n,i.language),e.result={language:i.language,re:i.r},i.second_best&&(e.second_best={language:i.second_best.language,re:i.second_best.r})}}function d(e){x=i(x,e)}function h(){if(!h.called){h.called=!0;var e=document.querySelectorAll("pre code");Array.prototype.forEach.call(e,p)}}function b(){addEventListener("DOMContentLoaded",h,!1),addEventListener("load",h,!1)}function v(n,t){var r=w[n]=t(e);r.aliases&&r.aliases.forEach(function(e){E[e]=n})}function m(){return Object.keys(w)}function N(e){return w[e]||w[E[e]]}var x={classPrefix:"hljs-",tabReplace:null,useBR:!1,languages:void 0},w={},E={};return e.highlight=s,e.highlightAuto=l,e.fixMarkup=f,e.highlightBlock=p,e.configure=d,e.initHighlighting=h,e.initHighlightingOnLoad=b,e.registerLanguage=v,e.listLanguages=m,e.getLanguage=N,e.inherit=i,e.IR="[a-zA-Z]\\w*",e.UIR="[a-zA-Z_]\\w*",e.NR="\\b\\d+(\\.\\d+)?",e.CNR="\\b(0[xX][a-fA-F0-9]+|(\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)",e.BNR="\\b(0b[01]+)",e.RSR="!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|-|-=|/=|/|:|;|<<|<<=|<=|<|===|==|=|>>>=|>>=|>=|>>>|>>|>|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~",e.BE={b:"\\\\[\\s\\S]",r:0},e.ASM={cN:"string",b:"'",e:"'",i:"\\n",c:[e.BE]},e.QSM={cN:"string",b:'"',e:'"',i:"\\n",c:[e.BE]},e.PWM={b:/\b(a|an|the|are|I|I'm|isn't|don't|doesn't|won't|but|just|should|pretty|simply|enough|gonna|going|wtf|so|such)\b/},e.C=function(n,t,r){var a=e.inherit({cN:"comment",b:n,e:t,c:[]},r||{});return a.c.push(e.PWM),a},e.CLCM=e.C("//","$"),e.CBCM=e.C("/\\*","\\*/"),e.HCM=e.C("#","$"),e.NM={cN:"number",b:e.NR,r:0},e.CNM={cN:"number",b:e.CNR,r:0},e.BNM={cN:"number",b:e.BNR,r:0},e.CSSNM={cN:"number",b:e.NR+"(%|em|ex|ch|rem|vw|vh|vmin|vmax|cm|mm|in|pt|pc|px|deg|grad|rad|turn|s|ms|Hz|kHz|dpi|dpcm|dppx)?",r:0},e.RM={cN:"regexp",b:/\//,e:/\/[gimuy]*/,i:/\n/,c:[e.BE,{b:/\[/,e:/\]/,r:0,c:[e.BE]}]},e.TM={cN:"title",b:e.IR,r:0},e.UTM={cN:"title",b:e.UIR,r:0},e}); \ No newline at end of file diff --git a/lib/highlight_js/assets/lang/1c.js b/lib/highlight_js/assets/lang/1c.js new file mode 100644 index 0000000000..a6f1f57e2c --- /dev/null +++ b/lib/highlight_js/assets/lang/1c.js @@ -0,0 +1 @@ +hljs.registerLanguage("1c",function(c){var e="[a-zA-Zа-яА-Я][a-zA-Z0-9_а-яА-Я]*",r="возврат дата для если и или иначе иначеесли исключение конецесли конецпопытки конецпроцедуры конецфункции конеццикла константа не перейти перем перечисление по пока попытка прервать продолжить процедура строка тогда фс функция цикл число экспорт",t="ansitooem oemtoansi ввестивидсубконто ввестидату ввестизначение ввестиперечисление ввестипериод ввестиплансчетов ввестистроку ввестичисло вопрос восстановитьзначение врег выбранныйплансчетов вызватьисключение датагод датамесяц датачисло добавитьмесяц завершитьработусистемы заголовоксистемы записьжурналарегистрации запуститьприложение зафиксироватьтранзакцию значениевстроку значениевстрокувнутр значениевфайл значениеизстроки значениеизстрокивнутр значениеизфайла имякомпьютера имяпользователя каталогвременныхфайлов каталогиб каталогпользователя каталогпрограммы кодсимв командасистемы конгода конецпериодаби конецрассчитанногопериодаби конецстандартногоинтервала конквартала конмесяца коннедели лев лог лог10 макс максимальноеколичествосубконто мин монопольныйрежим названиеинтерфейса названиенабораправ назначитьвид назначитьсчет найти найтипомеченныенаудаление найтиссылки началопериодаби началостандартногоинтервала начатьтранзакцию начгода начквартала начмесяца начнедели номерднягода номерднянедели номернеделигода нрег обработкаожидания окр описаниеошибки основнойжурналрасчетов основнойплансчетов основнойязык открытьформу открытьформумодально отменитьтранзакцию очиститьокносообщений периодстр полноеимяпользователя получитьвремята получитьдатута получитьдокументта получитьзначенияотбора получитьпозициюта получитьпустоезначение получитьта прав праводоступа предупреждение префиксавтонумерации пустаястрока пустоезначение рабочаядаттьпустоезначение рабочаядата разделительстраниц разделительстрок разм разобратьпозициюдокумента рассчитатьрегистрына рассчитатьрегистрыпо сигнал симв символтабуляции создатьобъект сокрл сокрлп сокрп сообщить состояние сохранитьзначение сред статусвозврата стрдлина стрзаменить стрколичествострок стрполучитьстроку стрчисловхождений сформироватьпозициюдокумента счетпокоду текущаядата текущеевремя типзначения типзначениястр удалитьобъекты установитьтана установитьтапо фиксшаблон формат цел шаблон",i={cN:"dquote",b:'""'},n={cN:"string",b:'"',e:'"|$',c:[i]},a={cN:"string",b:"\\|",e:'"|$',c:[i]};return{cI:!0,l:e,k:{keyword:r,built_in:t},c:[c.CLCM,c.NM,n,a,{cN:"function",b:"(процедура|функция)",e:"$",l:e,k:"процедура функция",c:[c.inherit(c.TM,{b:e}),{cN:"tail",eW:!0,c:[{cN:"params",b:"\\(",e:"\\)",l:e,k:"знач",c:[n,a]},{cN:"export",b:"экспорт",eW:!0,l:e,k:"экспорт",c:[c.CLCM]}]},c.CLCM]},{cN:"preprocessor",b:"#",e:"$"},{cN:"date",b:"'\\d{2}\\.\\d{2}\\.(\\d{2}|\\d{4})'"}]}}); \ No newline at end of file diff --git a/lib/highlight_js/assets/lang/actionscript.js b/lib/highlight_js/assets/lang/actionscript.js new file mode 100644 index 0000000000..eab42f9699 --- /dev/null +++ b/lib/highlight_js/assets/lang/actionscript.js @@ -0,0 +1 @@ +hljs.registerLanguage("actionscript",function(e){var a="[a-zA-Z_$][a-zA-Z0-9_$]*",c="([*]|[a-zA-Z_$][a-zA-Z0-9_$]*)",t={cN:"rest_arg",b:"[.]{3}",e:a,r:10};return{aliases:["as"],k:{keyword:"as break case catch class const continue default delete do dynamic each else extends final finally for function get if implements import in include instanceof interface internal is namespace native new override package private protected public return set static super switch this throw try typeof use var void while with",literal:"true false null undefined"},c:[e.ASM,e.QSM,e.CLCM,e.CBCM,e.CNM,{cN:"package",bK:"package",e:"{",c:[e.TM]},{cN:"class",bK:"class interface",e:"{",eE:!0,c:[{bK:"extends implements"},e.TM]},{cN:"preprocessor",bK:"import include",e:";"},{cN:"function",bK:"function",e:"[{;]",eE:!0,i:"\\S",c:[e.TM,{cN:"params",b:"\\(",e:"\\)",c:[e.ASM,e.QSM,e.CLCM,e.CBCM,t]},{cN:"type",b:":",e:c,r:10}]}]}}); \ No newline at end of file diff --git a/lib/highlight_js/assets/lang/apache.js b/lib/highlight_js/assets/lang/apache.js new file mode 100644 index 0000000000..24877edf3b --- /dev/null +++ b/lib/highlight_js/assets/lang/apache.js @@ -0,0 +1 @@ +hljs.registerLanguage("apache",function(e){var r={cN:"number",b:"[\\$%]\\d+"};return{aliases:["apacheconf"],cI:!0,c:[e.HCM,{cN:"tag",b:""},{cN:"keyword",b:/\w+/,r:0,k:{common:"order deny allow setenv rewriterule rewriteengine rewritecond documentroot sethandler errordocument loadmodule options header listen serverroot servername"},starts:{e:/$/,r:0,k:{literal:"on off all"},c:[{cN:"sqbracket",b:"\\s\\[",e:"\\]$"},{cN:"cbracket",b:"[\\$%]\\{",e:"\\}",c:["self",r]},r,e.QSM]}}],i:/\S/}}); \ No newline at end of file diff --git a/lib/highlight_js/assets/lang/applescript.js b/lib/highlight_js/assets/lang/applescript.js new file mode 100644 index 0000000000..28a5f9860c --- /dev/null +++ b/lib/highlight_js/assets/lang/applescript.js @@ -0,0 +1 @@ +hljs.registerLanguage("applescript",function(e){var t=e.inherit(e.QSM,{i:""}),r={cN:"params",b:"\\(",e:"\\)",c:["self",e.CNM,t]},o=e.C("--","$"),n=e.C("\\(\\*","\\*\\)",{c:["self",o]}),a=[o,n,e.HCM];return{aliases:["osascript"],k:{keyword:"about above after against and around as at back before beginning behind below beneath beside between but by considering contain contains continue copy div does eighth else end equal equals error every exit fifth first for fourth from front get given global if ignoring in into is it its last local me middle mod my ninth not of on onto or over prop property put ref reference repeat returning script second set seventh since sixth some tell tenth that the|0 then third through thru timeout times to transaction try until where while whose with without",constant:"AppleScript false linefeed return pi quote result space tab true",type:"alias application boolean class constant date file integer list number real record string text",command:"activate beep count delay launch log offset read round run say summarize write",property:"character characters contents day frontmost id item length month name paragraph paragraphs rest reverse running time version weekday word words year"},c:[t,e.CNM,{cN:"type",b:"\\bPOSIX file\\b"},{cN:"command",b:"\\b(clipboard info|the clipboard|info for|list (disks|folder)|mount volume|path to|(close|open for) access|(get|set) eof|current date|do shell script|get volume settings|random number|set volume|system attribute|system info|time to GMT|(load|run|store) script|scripting components|ASCII (character|number)|localized string|choose (application|color|file|file name|folder|from list|remote application|URL)|display (alert|dialog))\\b|^\\s*return\\b"},{cN:"constant",b:"\\b(text item delimiters|current application|missing value)\\b"},{cN:"keyword",b:"\\b(apart from|aside from|instead of|out of|greater than|isn't|(doesn't|does not) (equal|come before|come after|contain)|(greater|less) than( or equal)?|(starts?|ends|begins?) with|contained by|comes (before|after)|a (ref|reference))\\b"},{cN:"property",b:"\\b(POSIX path|(date|time) string|quoted form)\\b"},{cN:"function_start",bK:"on",i:"[${=;\\n]",c:[e.UTM,r]}].concat(a),i:"//|->|=>"}}); \ No newline at end of file diff --git a/lib/highlight_js/assets/lang/asciidoc.js b/lib/highlight_js/assets/lang/asciidoc.js new file mode 100644 index 0000000000..8212bea519 --- /dev/null +++ b/lib/highlight_js/assets/lang/asciidoc.js @@ -0,0 +1 @@ +hljs.registerLanguage("asciidoc",function(e){return{aliases:["adoc"],c:[e.C("^/{4,}\\n","\\n/{4,}$",{r:10}),e.C("^//","$",{r:0}),{cN:"title",b:"^\\.\\w.*$"},{b:"^[=\\*]{4,}\\n",e:"\\n^[=\\*]{4,}$",r:10},{cN:"header",b:"^(={1,5}) .+?( \\1)?$",r:10},{cN:"header",b:"^[^\\[\\]\\n]+?\\n[=\\-~\\^\\+]{2,}$",r:10},{cN:"attribute",b:"^:.+?:",e:"\\s",eE:!0,r:10},{cN:"attribute",b:"^\\[.+?\\]$",r:0},{cN:"blockquote",b:"^_{4,}\\n",e:"\\n_{4,}$",r:10},{cN:"code",b:"^[\\-\\.]{4,}\\n",e:"\\n[\\-\\.]{4,}$",r:10},{b:"^\\+{4,}\\n",e:"\\n\\+{4,}$",c:[{b:"<",e:">",sL:"xml",r:0}],r:10},{cN:"bullet",b:"^(\\*+|\\-+|\\.+|[^\\n]+?::)\\s+"},{cN:"label",b:"^(NOTE|TIP|IMPORTANT|WARNING|CAUTION):\\s+",r:10},{cN:"strong",b:"\\B\\*(?![\\*\\s])",e:"(\\n{2}|\\*)",c:[{b:"\\\\*\\w",r:0}]},{cN:"emphasis",b:"\\B'(?!['\\s])",e:"(\\n{2}|')",c:[{b:"\\\\'\\w",r:0}],r:0},{cN:"emphasis",b:"_(?![_\\s])",e:"(\\n{2}|_)",r:0},{cN:"smartquote",v:[{b:"``.+?''"},{b:"`.+?'"}]},{cN:"code",b:"(`.+?`|\\+.+?\\+)",r:0},{cN:"code",b:"^[ \\t]",e:"$",r:0},{cN:"horizontal_rule",b:"^'{3,}[ \\t]*$",r:10},{b:"(link:)?(http|https|ftp|file|irc|image:?):\\S+\\[.*?\\]",rB:!0,c:[{b:"(link|image:?):",r:0},{cN:"link_url",b:"\\w",e:"[^\\[]+",r:0},{cN:"link_label",b:"\\[",e:"\\]",eB:!0,eE:!0,r:0}],r:10}]}}); \ No newline at end of file diff --git a/lib/highlight_js/assets/lang/aspectj.js b/lib/highlight_js/assets/lang/aspectj.js new file mode 100644 index 0000000000..570faf4bcb --- /dev/null +++ b/lib/highlight_js/assets/lang/aspectj.js @@ -0,0 +1 @@ +hljs.registerLanguage("aspectj",function(e){var t="false synchronized int abstract float private char boolean static null if const for true while long throw strictfp finally protected import native final return void enum else extends implements break transient new catch instanceof byte super volatile case assert short package default double public try this switch continue throws privileged aspectOf adviceexecution proceed cflowbelow cflow initialization preinitialization staticinitialization withincode target within execution getWithinTypeName handler thisJoinPoint thisJoinPointStaticPart thisEnclosingJoinPointStaticPart declare parents warning error soft precedence thisAspectInstance",i="get set args call";return{k:t,i:/<\//,c:[{cN:"javadoc",b:"/\\*\\*",e:"\\*/",r:0,c:[{cN:"javadoctag",b:"(^|\\s)@[A-Za-z]+"}]},e.CLCM,e.CBCM,e.ASM,e.QSM,{cN:"aspect",bK:"aspect",e:/[{;=]/,eE:!0,i:/[:;"\[\]]/,c:[{bK:"extends implements pertypewithin perthis pertarget percflowbelow percflow issingleton"},e.UTM,{b:/\([^\)]*/,e:/[)]+/,k:t+" "+i,eE:!1}]},{cN:"class",bK:"class interface",e:/[{;=]/,eE:!0,r:0,k:"class interface",i:/[:"\[\]]/,c:[{bK:"extends implements"},e.UTM]},{bK:"pointcut after before around throwing returning",e:/[)]/,eE:!1,i:/["\[\]]/,c:[{b:e.UIR+"\\s*\\(",rB:!0,c:[e.UTM]}]},{b:/[:]/,rB:!0,e:/[{;]/,r:0,eE:!1,k:t,i:/["\[\]]/,c:[{b:e.UIR+"\\s*\\(",k:t+" "+i},e.QSM]},{bK:"new throw",r:0},{cN:"function",b:/\w+ +\w+(\.)?\w+\s*\([^\)]*\)\s*((throws)[\w\s,]+)?[\{;]/,rB:!0,e:/[{;=]/,k:t,eE:!0,c:[{b:e.UIR+"\\s*\\(",rB:!0,r:0,c:[e.UTM]},{cN:"params",b:/\(/,e:/\)/,r:0,k:t,c:[e.ASM,e.QSM,e.CNM,e.CBCM]},e.CLCM,e.CBCM]},e.CNM,{cN:"annotation",b:"@[A-Za-z]+"}]}}); \ No newline at end of file diff --git a/lib/highlight_js/assets/lang/autohotkey.js b/lib/highlight_js/assets/lang/autohotkey.js new file mode 100644 index 0000000000..9cecca8166 --- /dev/null +++ b/lib/highlight_js/assets/lang/autohotkey.js @@ -0,0 +1 @@ +hljs.registerLanguage("autohotkey",function(e){var r={cN:"escape",b:"`[\\s\\S]"},c=e.C(";","$",{r:0}),n=[{cN:"built_in",b:"A_[a-zA-Z0-9]+"},{cN:"built_in",bK:"ComSpec Clipboard ClipboardAll ErrorLevel"}];return{cI:!0,k:{keyword:"Break Continue Else Gosub If Loop Return While",literal:"A true false NOT AND OR"},c:n.concat([r,e.inherit(e.QSM,{c:[r]}),c,{cN:"number",b:e.NR,r:0},{cN:"var_expand",b:"%",e:"%",i:"\\n",c:[r]},{cN:"label",c:[r],v:[{b:'^[^\\n";]+::(?!=)'},{b:'^[^\\n";]+:(?!=)',r:0}]},{b:",\\s*,",r:10}])}}); \ No newline at end of file diff --git a/lib/highlight_js/assets/lang/avrasm.js b/lib/highlight_js/assets/lang/avrasm.js new file mode 100644 index 0000000000..c3ff1ee24e --- /dev/null +++ b/lib/highlight_js/assets/lang/avrasm.js @@ -0,0 +1 @@ +hljs.registerLanguage("avrasm",function(r){return{cI:!0,l:"\\.?"+r.IR,k:{keyword:"adc add adiw and andi asr bclr bld brbc brbs brcc brcs break breq brge brhc brhs brid brie brlo brlt brmi brne brpl brsh brtc brts brvc brvs bset bst call cbi cbr clc clh cli cln clr cls clt clv clz com cp cpc cpi cpse dec eicall eijmp elpm eor fmul fmuls fmulsu icall ijmp in inc jmp ld ldd ldi lds lpm lsl lsr mov movw mul muls mulsu neg nop or ori out pop push rcall ret reti rjmp rol ror sbc sbr sbrc sbrs sec seh sbi sbci sbic sbis sbiw sei sen ser ses set sev sez sleep spm st std sts sub subi swap tst wdr",built_in:"r0 r1 r2 r3 r4 r5 r6 r7 r8 r9 r10 r11 r12 r13 r14 r15 r16 r17 r18 r19 r20 r21 r22 r23 r24 r25 r26 r27 r28 r29 r30 r31 x|0 xh xl y|0 yh yl z|0 zh zl ucsr1c udr1 ucsr1a ucsr1b ubrr1l ubrr1h ucsr0c ubrr0h tccr3c tccr3a tccr3b tcnt3h tcnt3l ocr3ah ocr3al ocr3bh ocr3bl ocr3ch ocr3cl icr3h icr3l etimsk etifr tccr1c ocr1ch ocr1cl twcr twdr twar twsr twbr osccal xmcra xmcrb eicra spmcsr spmcr portg ddrg ping portf ddrf sreg sph spl xdiv rampz eicrb eimsk gimsk gicr eifr gifr timsk tifr mcucr mcucsr tccr0 tcnt0 ocr0 assr tccr1a tccr1b tcnt1h tcnt1l ocr1ah ocr1al ocr1bh ocr1bl icr1h icr1l tccr2 tcnt2 ocr2 ocdr wdtcr sfior eearh eearl eedr eecr porta ddra pina portb ddrb pinb portc ddrc pinc portd ddrd pind spdr spsr spcr udr0 ucsr0a ucsr0b ubrr0l acsr admux adcsr adch adcl porte ddre pine pinf",preprocessor:".byte .cseg .db .def .device .dseg .dw .endmacro .equ .eseg .exit .include .list .listmac .macro .nolist .org .set"},c:[r.CBCM,r.C(";","$",{r:0}),r.CNM,r.BNM,{cN:"number",b:"\\b(\\$[a-zA-Z0-9]+|0o[0-7]+)"},r.QSM,{cN:"string",b:"'",e:"[^\\\\]'",i:"[^\\\\][^']"},{cN:"label",b:"^[A-Za-z0-9_.$]+:"},{cN:"preprocessor",b:"#",e:"$"},{cN:"localvars",b:"@[0-9]+"}]}}); \ No newline at end of file diff --git a/lib/highlight_js/assets/lang/axapta.js b/lib/highlight_js/assets/lang/axapta.js new file mode 100644 index 0000000000..4574e0628f --- /dev/null +++ b/lib/highlight_js/assets/lang/axapta.js @@ -0,0 +1 @@ +hljs.registerLanguage("axapta",function(e){return{k:"false int abstract private char boolean static null if for true while long throw finally protected final return void enum else break new catch byte super case short default double public try this switch continue reverse firstfast firstonly forupdate nofetch sum avg minof maxof count order group by asc desc index hint like dispaly edit client server ttsbegin ttscommit str real date container anytype common div mod",c:[e.CLCM,e.CBCM,e.ASM,e.QSM,e.CNM,{cN:"preprocessor",b:"#",e:"$"},{cN:"class",bK:"class interface",e:"{",eE:!0,i:":",c:[{bK:"extends implements"},e.UTM]}]}}); \ No newline at end of file diff --git a/lib/highlight_js/assets/lang/bash.js b/lib/highlight_js/assets/lang/bash.js new file mode 100644 index 0000000000..dc42cd4d25 --- /dev/null +++ b/lib/highlight_js/assets/lang/bash.js @@ -0,0 +1 @@ +hljs.registerLanguage("bash",function(e){var t={cN:"variable",v:[{b:/\$[\w\d#@][\w\d_]*/},{b:/\$\{(.*?)}/}]},s={cN:"string",b:/"/,e:/"/,c:[e.BE,t,{cN:"variable",b:/\$\(/,e:/\)/,c:[e.BE]}]},a={cN:"string",b:/'/,e:/'/};return{aliases:["sh","zsh"],l:/-?[a-z\.]+/,k:{keyword:"if then else elif fi for while in do done case esac function",literal:"true false",built_in:"break cd continue eval exec exit export getopts hash pwd readonly return shift test times trap umask unset alias bind builtin caller command declare echo enable help let local logout mapfile printf read readarray source type typeset ulimit unalias set shopt autoload bg bindkey bye cap chdir clone comparguments compcall compctl compdescribe compfiles compgroups compquote comptags comptry compvalues dirs disable disown echotc echoti emulate fc fg float functions getcap getln history integer jobs kill limit log noglob popd print pushd pushln rehash sched setcap setopt stat suspend ttyctl unfunction unhash unlimit unsetopt vared wait whence where which zcompile zformat zftp zle zmodload zparseopts zprof zpty zregexparse zsocket zstyle ztcp",operator:"-ne -eq -lt -gt -f -d -e -s -l -a"},c:[{cN:"shebang",b:/^#![^\n]+sh\s*$/,r:10},{cN:"function",b:/\w[\w\d_]*\s*\(\s*\)\s*\{/,rB:!0,c:[e.inherit(e.TM,{b:/\w[\w\d_]*/})],r:0},e.HCM,e.NM,s,a,t]}}); \ No newline at end of file diff --git a/lib/highlight_js/assets/lang/brainfuck.js b/lib/highlight_js/assets/lang/brainfuck.js new file mode 100644 index 0000000000..b1a4c509fc --- /dev/null +++ b/lib/highlight_js/assets/lang/brainfuck.js @@ -0,0 +1 @@ +hljs.registerLanguage("brainfuck",function(r){var n={cN:"literal",b:"[\\+\\-]",r:0};return{aliases:["bf"],c:[r.C("[^\\[\\]\\.,\\+\\-<> \r\n]","[\\[\\]\\.,\\+\\-<> \r\n]",{rE:!0,r:0}),{cN:"title",b:"[\\[\\]]",r:0},{cN:"string",b:"[\\.,]",r:0},{b:/\+\+|\-\-/,rB:!0,c:[n]},n]}}); \ No newline at end of file diff --git a/lib/highlight_js/assets/lang/capnproto.js b/lib/highlight_js/assets/lang/capnproto.js new file mode 100644 index 0000000000..a4240ccf4e --- /dev/null +++ b/lib/highlight_js/assets/lang/capnproto.js @@ -0,0 +1 @@ +hljs.registerLanguage("capnproto",function(t){return{aliases:["capnp"],k:{keyword:"struct enum interface union group import using const annotation extends in of on as with from fixed",built_in:"Void Bool Int8 Int16 Int32 Int64 UInt8 UInt16 UInt32 UInt64 Float32 Float64 Text Data AnyPointer AnyStruct Capability List",literal:"true false"},c:[t.QSM,t.NM,t.HCM,{cN:"shebang",b:/@0x[\w\d]{16};/,i:/\n/},{cN:"number",b:/@\d+\b/},{cN:"class",bK:"struct enum",e:/\{/,i:/\n/,c:[t.inherit(t.TM,{starts:{eW:!0,eE:!0}})]},{cN:"class",bK:"interface",e:/\{/,i:/\n/,c:[t.inherit(t.TM,{starts:{eW:!0,eE:!0}})]}]}}); \ No newline at end of file diff --git a/lib/highlight_js/assets/lang/clojure-repl.js b/lib/highlight_js/assets/lang/clojure-repl.js new file mode 100644 index 0000000000..6d89bd2cad --- /dev/null +++ b/lib/highlight_js/assets/lang/clojure-repl.js @@ -0,0 +1 @@ +hljs.registerLanguage("clojure-repl",function(){return{c:[{cN:"prompt",b:/^([\w.-]+|\s*#_)=>/,starts:{e:/$/,sL:"clojure",subLanguageMode:"continuous"}}]}}); \ No newline at end of file diff --git a/lib/highlight_js/assets/lang/clojure.js b/lib/highlight_js/assets/lang/clojure.js new file mode 100644 index 0000000000..1c6926e81e --- /dev/null +++ b/lib/highlight_js/assets/lang/clojure.js @@ -0,0 +1 @@ +hljs.registerLanguage("clojure",function(e){var t={built_in:"def cond apply if-not if-let if not not= = < > <= >= == + / * - rem quot neg? pos? delay? symbol? keyword? true? false? integer? empty? coll? list? set? ifn? fn? associative? sequential? sorted? counted? reversible? number? decimal? class? distinct? isa? float? rational? reduced? ratio? odd? even? char? seq? vector? string? map? nil? contains? zero? instance? not-every? not-any? libspec? -> ->> .. . inc compare do dotimes mapcat take remove take-while drop letfn drop-last take-last drop-while while intern condp case reduced cycle split-at split-with repeat replicate iterate range merge zipmap declare line-seq sort comparator sort-by dorun doall nthnext nthrest partition eval doseq await await-for let agent atom send send-off release-pending-sends add-watch mapv filterv remove-watch agent-error restart-agent set-error-handler error-handler set-error-mode! error-mode shutdown-agents quote var fn loop recur throw try monitor-enter monitor-exit defmacro defn defn- macroexpand macroexpand-1 for dosync and or when when-not when-let comp juxt partial sequence memoize constantly complement identity assert peek pop doto proxy defstruct first rest cons defprotocol cast coll deftype defrecord last butlast sigs reify second ffirst fnext nfirst nnext defmulti defmethod meta with-meta ns in-ns create-ns import refer keys select-keys vals key val rseq name namespace promise into transient persistent! conj! assoc! dissoc! pop! disj! use class type num float double short byte boolean bigint biginteger bigdec print-method print-dup throw-if printf format load compile get-in update-in pr pr-on newline flush read slurp read-line subvec with-open memfn time re-find re-groups rand-int rand mod locking assert-valid-fdecl alias resolve ref deref refset swap! reset! set-validator! compare-and-set! alter-meta! reset-meta! commute get-validator alter ref-set ref-history-count ref-min-history ref-max-history ensure sync io! new next conj set! to-array future future-call into-array aset gen-class reduce map filter find empty hash-map hash-set sorted-map sorted-map-by sorted-set sorted-set-by vec vector seq flatten reverse assoc dissoc list disj get union difference intersection extend extend-type extend-protocol int nth delay count concat chunk chunk-buffer chunk-append chunk-first chunk-rest max min dec unchecked-inc-int unchecked-inc unchecked-dec-inc unchecked-dec unchecked-negate unchecked-add-int unchecked-add unchecked-subtract-int unchecked-subtract chunk-next chunk-cons chunked-seq? prn vary-meta lazy-seq spread list* str find-keyword keyword symbol gensym force rationalize"},r="a-zA-Z_\\-!.?+*=<>&#'",n="["+r+"]["+r+"0-9/;:]*",a="[-+]?\\d+(\\.\\d+)?",o={b:n,r:0},s={cN:"number",b:a,r:0},i=e.inherit(e.QSM,{i:null}),c=e.C(";","$",{r:0}),d={cN:"literal",b:/\b(true|false|nil)\b/},l={cN:"collection",b:"[\\[\\{]",e:"[\\]\\}]"},m={cN:"comment",b:"\\^"+n},p=e.C("\\^\\{","\\}"),u={cN:"attribute",b:"[:]"+n},f={cN:"list",b:"\\(",e:"\\)"},h={eW:!0,r:0},y={k:t,l:n,cN:"keyword",b:n,starts:h},b=[f,i,m,p,c,u,l,s,d,o];return f.c=[e.C("comment",""),y,h],h.c=b,l.c=b,{aliases:["clj"],i:/\S/,c:[f,i,m,p,c,u,l,s,d]}}); \ No newline at end of file diff --git a/lib/highlight_js/assets/lang/cmake.js b/lib/highlight_js/assets/lang/cmake.js new file mode 100644 index 0000000000..e2605bef3d --- /dev/null +++ b/lib/highlight_js/assets/lang/cmake.js @@ -0,0 +1 @@ +hljs.registerLanguage("cmake",function(e){return{aliases:["cmake.in"],cI:!0,k:{keyword:"add_custom_command add_custom_target add_definitions add_dependencies add_executable add_library add_subdirectory add_test aux_source_directory break build_command cmake_minimum_required cmake_policy configure_file create_test_sourcelist define_property else elseif enable_language enable_testing endforeach endfunction endif endmacro endwhile execute_process export find_file find_library find_package find_path find_program fltk_wrap_ui foreach function get_cmake_property get_directory_property get_filename_component get_property get_source_file_property get_target_property get_test_property if include include_directories include_external_msproject include_regular_expression install link_directories load_cache load_command macro mark_as_advanced message option output_required_files project qt_wrap_cpp qt_wrap_ui remove_definitions return separate_arguments set set_directory_properties set_property set_source_files_properties set_target_properties set_tests_properties site_name source_group string target_link_libraries try_compile try_run unset variable_watch while build_name exec_program export_library_dependencies install_files install_programs install_targets link_libraries make_directory remove subdir_depends subdirs use_mangled_mesa utility_source variable_requires write_file qt5_use_modules qt5_use_package qt5_wrap_cpp on off true false and or",operator:"equal less greater strless strgreater strequal matches"},c:[{cN:"envvar",b:"\\${",e:"}"},e.HCM,e.QSM,e.NM]}}); \ No newline at end of file diff --git a/lib/highlight_js/assets/lang/coffeescript.js b/lib/highlight_js/assets/lang/coffeescript.js new file mode 100644 index 0000000000..2b0f0173ba --- /dev/null +++ b/lib/highlight_js/assets/lang/coffeescript.js @@ -0,0 +1 @@ +hljs.registerLanguage("coffeescript",function(e){var c={keyword:"in if for while finally new do return else break catch instanceof throw try this switch continue typeof delete debugger super then unless until loop of by when and or is isnt not",literal:"true false null undefined yes no on off",reserved:"case default function var void with const let enum export import native __hasProp __extends __slice __bind __indexOf",built_in:"npm require console print module global window document"},n="[A-Za-z$_][0-9A-Za-z$_]*",t={cN:"subst",b:/#\{/,e:/}/,k:c},r=[e.BNM,e.inherit(e.CNM,{starts:{e:"(\\s*/)?",r:0}}),{cN:"string",v:[{b:/'''/,e:/'''/,c:[e.BE]},{b:/'/,e:/'/,c:[e.BE]},{b:/"""/,e:/"""/,c:[e.BE,t]},{b:/"/,e:/"/,c:[e.BE,t]}]},{cN:"regexp",v:[{b:"///",e:"///",c:[t,e.HCM]},{b:"//[gim]*",r:0},{b:/\/(?![ *])(\\\/|.)*?\/[gim]*(?=\W|$)/}]},{cN:"property",b:"@"+n},{b:"`",e:"`",eB:!0,eE:!0,sL:"javascript"}];t.c=r;var i=e.inherit(e.TM,{b:n}),s="(\\(.*\\))?\\s*\\B[-=]>",o={cN:"params",b:"\\([^\\(]",rB:!0,c:[{b:/\(/,e:/\)/,k:c,c:["self"].concat(r)}]};return{aliases:["coffee","cson","iced"],k:c,i:/\/\*/,c:r.concat([e.C("###","###"),e.HCM,{cN:"function",b:"^\\s*"+n+"\\s*=\\s*"+s,e:"[-=]>",rB:!0,c:[i,o]},{b:/[:\(,=]\s*/,r:0,c:[{cN:"function",b:s,e:"[-=]>",rB:!0,c:[o]}]},{cN:"class",bK:"class",e:"$",i:/[:="\[\]]/,c:[{bK:"extends",eW:!0,i:/[:="\[\]]/,c:[i]},i]},{cN:"attribute",b:n+":",e:":",rB:!0,rE:!0,r:0}])}}); \ No newline at end of file diff --git a/lib/highlight_js/assets/lang/cpp.js b/lib/highlight_js/assets/lang/cpp.js new file mode 100644 index 0000000000..67ef5a60e4 --- /dev/null +++ b/lib/highlight_js/assets/lang/cpp.js @@ -0,0 +1 @@ +hljs.registerLanguage("cpp",function(t){var i={keyword:"false int float while private char catch export virtual operator sizeof dynamic_cast|10 typedef const_cast|10 const struct for static_cast|10 union namespace unsigned long volatile static protected bool template mutable if public friend do goto auto void enum else break extern using true class asm case typeid short reinterpret_cast|10 default double register explicit signed typename try this switch continue wchar_t inline delete alignof char16_t char32_t constexpr decltype noexcept nullptr static_assert thread_local restrict _Bool complex _Complex _Imaginary intmax_t uintmax_t int8_t uint8_t int16_t uint16_t int32_t uint32_t int64_t uint64_t int_least8_t uint_least8_t int_least16_t uint_least16_t int_least32_t uint_least32_t int_least64_t uint_least64_t int_fast8_t uint_fast8_t int_fast16_t uint_fast16_t int_fast32_t uint_fast32_t int_fast64_t uint_fast64_t intptr_t uintptr_t atomic_bool atomic_char atomic_schar atomic_uchar atomic_short atomic_ushort atomic_int atomic_uint atomic_long atomic_ulong atomic_llong atomic_ullong atomic_wchar_t atomic_char16_t atomic_char32_t atomic_intmax_t atomic_uintmax_t atomic_intptr_t atomic_uintptr_t atomic_size_t atomic_ptrdiff_t atomic_int_least8_t atomic_int_least16_t atomic_int_least32_t atomic_int_least64_t atomic_uint_least8_t atomic_uint_least16_t atomic_uint_least32_t atomic_uint_least64_t atomic_int_fast8_t atomic_int_fast16_t atomic_int_fast32_t atomic_int_fast64_t atomic_uint_fast8_t atomic_uint_fast16_t atomic_uint_fast32_t atomic_uint_fast64_t",built_in:"std string cin cout cerr clog stringstream istringstream ostringstream auto_ptr deque list queue stack vector map set bitset multiset multimap unordered_set unordered_map unordered_multiset unordered_multimap array shared_ptr abort abs acos asin atan2 atan calloc ceil cosh cos exit exp fabs floor fmod fprintf fputs free frexp fscanf isalnum isalpha iscntrl isdigit isgraph islower isprint ispunct isspace isupper isxdigit tolower toupper labs ldexp log10 log malloc memchr memcmp memcpy memset modf pow printf putchar puts scanf sinh sin snprintf sprintf sqrt sscanf strcat strchr strcmp strcpy strcspn strlen strncat strncmp strncpy strpbrk strrchr strspn strstr tanh tan vfprintf vprintf vsprintf"};return{aliases:["c","cc","h","c++","h++","hpp"],k:i,i:""]',k:"include",i:"\\n"},t.CLCM]},{b:"\\b(deque|list|queue|stack|vector|map|set|bitset|multiset|multimap|unordered_map|unordered_set|unordered_multiset|unordered_multimap|array)\\s*<",e:">",k:i,c:["self"]},{b:t.IR+"::",k:i},{bK:"new throw return else",r:0},{cN:"function",b:"("+t.IR+"\\s+)+"+t.IR+"\\s*\\(",rB:!0,e:/[{;=]/,eE:!0,k:i,c:[{b:t.IR+"\\s*\\(",rB:!0,c:[t.TM],r:0},{cN:"params",b:/\(/,e:/\)/,k:i,r:0,c:[t.CBCM]},t.CLCM,t.CBCM]}]}}); \ No newline at end of file diff --git a/lib/highlight_js/assets/lang/cs.js b/lib/highlight_js/assets/lang/cs.js new file mode 100644 index 0000000000..dae456dc44 --- /dev/null +++ b/lib/highlight_js/assets/lang/cs.js @@ -0,0 +1 @@ +hljs.registerLanguage("cs",function(e){var r="abstract as base bool break byte case catch char checked const continue decimal dynamic default delegate do double else enum event explicit extern false finally fixed float for foreach goto if implicit in int interface internal is lock long null when object operator out override params private protected public readonly ref sbyte sealed short sizeof stackalloc static string struct switch this true try typeof uint ulong unchecked unsafe ushort using virtual volatile void while async protected public private internal ascending descending from get group into join let orderby partial select set value var where yield",t=e.IR+"(<"+e.IR+">)?";return{aliases:["csharp"],k:r,i:/::/,c:[e.C("///","$",{rB:!0,c:[{cN:"xmlDocTag",v:[{b:"///",r:0},{b:""},{b:""}]}]}),e.CLCM,e.CBCM,{cN:"preprocessor",b:"#",e:"$",k:"if else elif endif define undef warning error line region endregion pragma checksum"},{cN:"string",b:'@"',e:'"',c:[{b:'""'}]},e.ASM,e.QSM,e.CNM,{bK:"class namespace interface",e:/[{;=]/,i:/[^\s:]/,c:[e.TM,e.CLCM,e.CBCM]},{bK:"new return throw await",r:0},{cN:"function",b:"("+t+"\\s+)+"+e.IR+"\\s*\\(",rB:!0,e:/[{;=]/,eE:!0,k:r,c:[{b:e.IR+"\\s*\\(",rB:!0,c:[e.TM],r:0},{cN:"params",b:/\(/,e:/\)/,k:r,r:0,c:[e.ASM,e.QSM,e.CNM,e.CBCM]},e.CLCM,e.CBCM]}]}}); \ No newline at end of file diff --git a/lib/highlight_js/assets/lang/css.js b/lib/highlight_js/assets/lang/css.js new file mode 100644 index 0000000000..08ab217234 --- /dev/null +++ b/lib/highlight_js/assets/lang/css.js @@ -0,0 +1 @@ +hljs.registerLanguage("css",function(e){var c="[a-zA-Z-][a-zA-Z0-9_-]*",a={cN:"function",b:c+"\\(",rB:!0,eE:!0,e:"\\("};return{cI:!0,i:"[=/|']",c:[e.CBCM,{cN:"id",b:"\\#[A-Za-z0-9_-]+"},{cN:"class",b:"\\.[A-Za-z0-9_-]+",r:0},{cN:"attr_selector",b:"\\[",e:"\\]",i:"$"},{cN:"pseudo",b:":(:)?[a-zA-Z0-9\\_\\-\\+\\(\\)\\\"\\']+"},{cN:"at_rule",b:"@(font-face|page)",l:"[a-z-]+",k:"font-face page"},{cN:"at_rule",b:"@",e:"[{;]",c:[{cN:"keyword",b:/\S+/},{b:/\s/,eW:!0,eE:!0,r:0,c:[a,e.ASM,e.QSM,e.CSSNM]}]},{cN:"tag",b:c,r:0},{cN:"rules",b:"{",e:"}",i:"[^\\s]",r:0,c:[e.CBCM,{cN:"rule",b:"[^\\s]",rB:!0,e:";",eW:!0,c:[{cN:"attribute",b:"[A-Z\\_\\.\\-]+",e:":",eE:!0,i:"[^\\s]",starts:{cN:"value",eW:!0,eE:!0,c:[a,e.CSSNM,e.QSM,e.ASM,e.CBCM,{cN:"hexcolor",b:"#[0-9A-Fa-f]+"},{cN:"important",b:"!important"}]}}]}]}]}}); \ No newline at end of file diff --git a/lib/highlight_js/assets/lang/d.js b/lib/highlight_js/assets/lang/d.js new file mode 100644 index 0000000000..12386f8441 --- /dev/null +++ b/lib/highlight_js/assets/lang/d.js @@ -0,0 +1 @@ +hljs.registerLanguage("d",function(e){var r={keyword:"abstract alias align asm assert auto body break byte case cast catch class const continue debug default delete deprecated do else enum export extern final finally for foreach foreach_reverse|10 goto if immutable import in inout int interface invariant is lazy macro mixin module new nothrow out override package pragma private protected public pure ref return scope shared static struct super switch synchronized template this throw try typedef typeid typeof union unittest version void volatile while with __FILE__ __LINE__ __gshared|10 __thread __traits __DATE__ __EOF__ __TIME__ __TIMESTAMP__ __VENDOR__ __VERSION__",built_in:"bool cdouble cent cfloat char creal dchar delegate double dstring float function idouble ifloat ireal long real short string ubyte ucent uint ulong ushort wchar wstring",literal:"false null true"},t="(0|[1-9][\\d_]*)",a="(0|[1-9][\\d_]*|\\d[\\d_]*|[\\d_]+?\\d)",i="0[bB][01_]+",n="([\\da-fA-F][\\da-fA-F_]*|_[\\da-fA-F][\\da-fA-F_]*)",c="0[xX]"+n,_="([eE][+-]?"+a+")",d="("+a+"(\\.\\d*|"+_+")|\\d+\\."+a+a+"|\\."+t+_+"?)",o="(0[xX]("+n+"\\."+n+"|\\.?"+n+")[pP][+-]?"+a+")",s="("+t+"|"+i+"|"+c+")",l="("+o+"|"+d+")",u="\\\\(['\"\\?\\\\abfnrtv]|u[\\dA-Fa-f]{4}|[0-7]{1,3}|x[\\dA-Fa-f]{2}|U[\\dA-Fa-f]{8})|&[a-zA-Z\\d]{2,};",b={cN:"number",b:"\\b"+s+"(L|u|U|Lu|LU|uL|UL)?",r:0},f={cN:"number",b:"\\b("+l+"([fF]|L|i|[fF]i|Li)?|"+s+"(i|[fF]i|Li))",r:0},g={cN:"string",b:"'("+u+"|.)",e:"'",i:"."},h={b:u,r:0},p={cN:"string",b:'"',c:[h],e:'"[cwd]?'},w={cN:"string",b:'[rq]"',e:'"[cwd]?',r:5},N={cN:"string",b:"`",e:"`[cwd]?"},A={cN:"string",b:'x"[\\da-fA-F\\s\\n\\r]*"[cwd]?',r:10},F={cN:"string",b:'q"\\{',e:'\\}"'},m={cN:"shebang",b:"^#!",e:"$",r:5},y={cN:"preprocessor",b:"#(line)",e:"$",r:5},L={cN:"keyword",b:"@[a-zA-Z_][a-zA-Z_\\d]*"},v=e.C("\\/\\+","\\+\\/",{c:["self"],r:10});return{l:e.UIR,k:r,c:[e.CLCM,e.CBCM,v,A,p,w,N,F,f,b,g,m,y,L]}}); \ No newline at end of file diff --git a/lib/highlight_js/assets/lang/dart.js b/lib/highlight_js/assets/lang/dart.js new file mode 100644 index 0000000000..5e6d1472b6 --- /dev/null +++ b/lib/highlight_js/assets/lang/dart.js @@ -0,0 +1 @@ +hljs.registerLanguage("dart",function(e){var t={cN:"subst",b:"\\$\\{",e:"}",k:"true false null this is new super"},r={cN:"string",v:[{b:"r'''",e:"'''"},{b:'r"""',e:'"""'},{b:"r'",e:"'",i:"\\n"},{b:'r"',e:'"',i:"\\n"},{b:"'''",e:"'''",c:[e.BE,t]},{b:'"""',e:'"""',c:[e.BE,t]},{b:"'",e:"'",i:"\\n",c:[e.BE,t]},{b:'"',e:'"',i:"\\n",c:[e.BE,t]}]};t.c=[e.CNM,r];var n={keyword:"assert break case catch class const continue default do else enum extends false final finally for if in is new null rethrow return super switch this throw true try var void while with",literal:"abstract as dynamic export external factory get implements import library operator part set static typedef",built_in:"print Comparable DateTime Duration Function Iterable Iterator List Map Match Null Object Pattern RegExp Set Stopwatch String StringBuffer StringSink Symbol Type Uri bool double int num document window querySelector querySelectorAll Element ElementList"};return{k:n,c:[r,{cN:"dartdoc",b:"/\\*\\*",e:"\\*/",sL:"markdown",subLanguageMode:"continuous"},{cN:"dartdoc",b:"///",e:"$",sL:"markdown",subLanguageMode:"continuous"},e.CLCM,e.CBCM,{cN:"class",bK:"class interface",e:"{",eE:!0,c:[{bK:"extends implements"},e.UTM]},e.CNM,{cN:"annotation",b:"@[A-Za-z]+"},{b:"=>"}]}}); \ No newline at end of file diff --git a/lib/highlight_js/assets/lang/delphi.js b/lib/highlight_js/assets/lang/delphi.js new file mode 100644 index 0000000000..709910af61 --- /dev/null +++ b/lib/highlight_js/assets/lang/delphi.js @@ -0,0 +1 @@ +hljs.registerLanguage("delphi",function(e){var r="exports register file shl array record property for mod while set ally label uses raise not stored class safecall var interface or private static exit index inherited to else stdcall override shr asm far resourcestring finalization packed virtual out and protected library do xorwrite goto near function end div overload object unit begin string on inline repeat until destructor write message program with read initialization except default nil if case cdecl in downto threadvar of try pascal const external constructor type public then implementation finally published procedure",t=[e.CLCM,e.C(/\{/,/\}/,{r:0}),e.C(/\(\*/,/\*\)/,{r:10})],i={cN:"string",b:/'/,e:/'/,c:[{b:/''/}]},c={cN:"string",b:/(#\d+)+/},o={b:e.IR+"\\s*=\\s*class\\s*\\(",rB:!0,c:[e.TM]},n={cN:"function",bK:"function constructor destructor procedure",e:/[:;]/,k:"function constructor|10 destructor|10 procedure|10",c:[e.TM,{cN:"params",b:/\(/,e:/\)/,k:r,c:[i,c]}].concat(t)};return{cI:!0,k:r,i:/"|\$[G-Zg-z]|\/\*|<\/|\|/,c:[i,c,e.NM,o,n].concat(t)}}); \ No newline at end of file diff --git a/lib/highlight_js/assets/lang/diff.js b/lib/highlight_js/assets/lang/diff.js new file mode 100644 index 0000000000..c2102c9adb --- /dev/null +++ b/lib/highlight_js/assets/lang/diff.js @@ -0,0 +1 @@ +hljs.registerLanguage("diff",function(){return{aliases:["patch"],c:[{cN:"chunk",r:10,v:[{b:/^@@ +\-\d+,\d+ +\+\d+,\d+ +@@$/},{b:/^\*\*\* +\d+,\d+ +\*\*\*\*$/},{b:/^\-\-\- +\d+,\d+ +\-\-\-\-$/}]},{cN:"header",v:[{b:/Index: /,e:/$/},{b:/=====/,e:/=====$/},{b:/^\-\-\-/,e:/$/},{b:/^\*{3} /,e:/$/},{b:/^\+\+\+/,e:/$/},{b:/\*{5}/,e:/\*{5}$/}]},{cN:"addition",b:"^\\+",e:"$"},{cN:"deletion",b:"^\\-",e:"$"},{cN:"change",b:"^\\!",e:"$"}]}}); \ No newline at end of file diff --git a/lib/highlight_js/assets/lang/django.js b/lib/highlight_js/assets/lang/django.js new file mode 100644 index 0000000000..86f738f16e --- /dev/null +++ b/lib/highlight_js/assets/lang/django.js @@ -0,0 +1 @@ +hljs.registerLanguage("django",function(e){var t={cN:"filter",b:/\|[A-Za-z]+:?/,k:"truncatewords removetags linebreaksbr yesno get_digit timesince random striptags filesizeformat escape linebreaks length_is ljust rjust cut urlize fix_ampersands title floatformat capfirst pprint divisibleby add make_list unordered_list urlencode timeuntil urlizetrunc wordcount stringformat linenumbers slice date dictsort dictsortreversed default_if_none pluralize lower join center default truncatewords_html upper length phone2numeric wordwrap time addslashes slugify first escapejs force_escape iriencode last safe safeseq truncatechars localize unlocalize localtime utc timezone",c:[{cN:"argument",b:/"/,e:/"/},{cN:"argument",b:/'/,e:/'/}]};return{aliases:["jinja"],cI:!0,sL:"xml",subLanguageMode:"continuous",c:[e.C(/\{%\s*comment\s*%}/,/\{%\s*endcomment\s*%}/),e.C(/\{#/,/#}/),{cN:"template_tag",b:/\{%/,e:/%}/,k:"comment endcomment load templatetag ifchanged endifchanged if endif firstof for endfor in ifnotequal endifnotequal widthratio extends include spaceless endspaceless regroup by as ifequal endifequal ssi now with cycle url filter endfilter debug block endblock else autoescape endautoescape csrf_token empty elif endwith static trans blocktrans endblocktrans get_static_prefix get_media_prefix plural get_current_language language get_available_languages get_current_language_bidi get_language_info get_language_info_list localize endlocalize localtime endlocaltime timezone endtimezone get_current_timezone verbatim",c:[t]},{cN:"variable",b:/\{\{/,e:/}}/,c:[t]}]}}); \ No newline at end of file diff --git a/lib/highlight_js/assets/lang/dockerfile.js b/lib/highlight_js/assets/lang/dockerfile.js new file mode 100644 index 0000000000..e505c66063 --- /dev/null +++ b/lib/highlight_js/assets/lang/dockerfile.js @@ -0,0 +1 @@ +hljs.registerLanguage("dockerfile",function(n){return{aliases:["docker"],cI:!0,k:{built_ins:"from maintainer cmd expose add copy entrypoint volume user workdir onbuild run env"},c:[n.HCM,{k:{built_in:"run cmd entrypoint volume add copy workdir onbuild"},b:/^ *(onbuild +)?(run|cmd|entrypoint|volume|add|copy|workdir) +/,starts:{e:/[^\\]\n/,sL:"bash",subLanguageMode:"continuous"}},{k:{built_in:"from maintainer expose env user onbuild"},b:/^ *(onbuild +)?(from|maintainer|expose|env|user|onbuild) +/,e:/[^\\]\n/,c:[n.ASM,n.QSM,n.NM,n.HCM]}]}}); \ No newline at end of file diff --git a/lib/highlight_js/assets/lang/dos.js b/lib/highlight_js/assets/lang/dos.js new file mode 100644 index 0000000000..4002382b7a --- /dev/null +++ b/lib/highlight_js/assets/lang/dos.js @@ -0,0 +1 @@ +hljs.registerLanguage("dos",function(e){var r=e.C(/@?rem\b/,/$/,{r:10}),t={cN:"label",b:"^\\s*[A-Za-z._?][A-Za-z0-9_$#@~.?]*(:|\\s+label)",r:0};return{aliases:["bat","cmd"],cI:!0,k:{flow:"if else goto for in do call exit not exist errorlevel defined",operator:"equ neq lss leq gtr geq",keyword:"shift cd dir echo setlocal endlocal set pause copy",stream:"prn nul lpt3 lpt2 lpt1 con com4 com3 com2 com1 aux",winutils:"ping net ipconfig taskkill xcopy ren del",built_in:"append assoc at attrib break cacls cd chcp chdir chkdsk chkntfs cls cmd color comp compact convert date dir diskcomp diskcopy doskey erase fs find findstr format ftype graftabl help keyb label md mkdir mode more move path pause print popd pushd promt rd recover rem rename replace restore rmdir shiftsort start subst time title tree type ver verify vol"},c:[{cN:"envvar",b:/%%[^ ]|%[^ ]+?%|![^ ]+?!/},{cN:"function",b:t.b,e:"goto:eof",c:[e.inherit(e.TM,{b:"([_a-zA-Z]\\w*\\.)*([_a-zA-Z]\\w*:)?[_a-zA-Z]\\w*"}),r]},{cN:"number",b:"\\b\\d+",r:0},r]}}); \ No newline at end of file diff --git a/lib/highlight_js/assets/lang/dust.js b/lib/highlight_js/assets/lang/dust.js new file mode 100644 index 0000000000..dc98b882e9 --- /dev/null +++ b/lib/highlight_js/assets/lang/dust.js @@ -0,0 +1 @@ +hljs.registerLanguage("dust",function(){var e="if eq ne lt lte gt gte select default math sep";return{aliases:["dst"],cI:!0,sL:"xml",subLanguageMode:"continuous",c:[{cN:"expression",b:"{",e:"}",r:0,c:[{cN:"begin-block",b:"#[a-zA-Z- .]+",k:e},{cN:"string",b:'"',e:'"'},{cN:"end-block",b:"\\/[a-zA-Z- .]+",k:e},{cN:"variable",b:"[a-zA-Z-.]+",k:e,r:0}]}]}}); \ No newline at end of file diff --git a/lib/highlight_js/assets/lang/elixir.js b/lib/highlight_js/assets/lang/elixir.js new file mode 100644 index 0000000000..06827aa027 --- /dev/null +++ b/lib/highlight_js/assets/lang/elixir.js @@ -0,0 +1 @@ +hljs.registerLanguage("elixir",function(e){var r="[a-zA-Z_][a-zA-Z0-9_]*(\\!|\\?)?",b="[a-zA-Z_]\\w*[!?=]?|[-+~]\\@|<<|>>|=~|===?|<=>|[<>]=?|\\*\\*|[-/+%^&*~`|]|\\[\\]=?",n="and false then defined module in return redo retry end for true self when next until do begin unless nil break not case cond alias while ensure or include use alias fn quote",c={cN:"subst",b:"#\\{",e:"}",l:r,k:n},a={cN:"string",c:[e.BE,c],v:[{b:/'/,e:/'/},{b:/"/,e:/"/}]},s={eW:!0,rE:!0,l:r,k:n,r:0},i={cN:"function",bK:"def defp defmacro",e:/\bdo\b/,c:[e.inherit(e.TM,{b:b,starts:s})]},l=e.inherit(i,{cN:"class",bK:"defmodule defrecord",e:/\bdo\b|$|;/}),t=[a,e.HCM,l,i,{cN:"constant",b:"(\\b[A-Z_]\\w*(.)?)+",r:0},{cN:"symbol",b:":",c:[a,{b:b}],r:0},{cN:"symbol",b:r+":",r:0},{cN:"number",b:"(\\b0[0-7_]+)|(\\b0x[0-9a-fA-F_]+)|(\\b[1-9][0-9_]*(\\.[0-9_]+)?)|[0_]\\b",r:0},{cN:"variable",b:"(\\$\\W)|((\\$|\\@\\@?)(\\w+))"},{b:"->"},{b:"("+e.RSR+")\\s*",c:[e.HCM,{cN:"regexp",i:"\\n",c:[e.BE,c],v:[{b:"/",e:"/[a-z]*"},{b:"%r\\[",e:"\\][a-z]*"}]}],r:0}];return c.c=t,s.c=t,{l:r,k:n,c:t}}); \ No newline at end of file diff --git a/lib/highlight_js/assets/lang/erb.js b/lib/highlight_js/assets/lang/erb.js new file mode 100644 index 0000000000..26ff7c3be1 --- /dev/null +++ b/lib/highlight_js/assets/lang/erb.js @@ -0,0 +1 @@ +hljs.registerLanguage("erb",function(e){return{sL:"xml",subLanguageMode:"continuous",c:[e.C("<%#","%>"),{b:"<%[%=-]?",e:"[%-]?%>",sL:"ruby",eB:!0,eE:!0}]}}); \ No newline at end of file diff --git a/lib/highlight_js/assets/lang/erlang-repl.js b/lib/highlight_js/assets/lang/erlang-repl.js new file mode 100644 index 0000000000..ca148f619a --- /dev/null +++ b/lib/highlight_js/assets/lang/erlang-repl.js @@ -0,0 +1 @@ +hljs.registerLanguage("erlang-repl",function(r){return{k:{special_functions:"spawn spawn_link self",reserved:"after and andalso|10 band begin bnot bor bsl bsr bxor case catch cond div end fun if let not of or orelse|10 query receive rem try when xor"},c:[{cN:"prompt",b:"^[0-9]+> ",r:10},r.C("%","$"),{cN:"number",b:"\\b(\\d+#[a-fA-F0-9]+|\\d+(\\.\\d+)?([eE][-+]?\\d+)?)",r:0},r.ASM,r.QSM,{cN:"constant",b:"\\?(::)?([A-Z]\\w*(::)?)+"},{cN:"arrow",b:"->"},{cN:"ok",b:"ok"},{cN:"exclamation_mark",b:"!"},{cN:"function_or_atom",b:"(\\b[a-z'][a-zA-Z0-9_']*:[a-z'][a-zA-Z0-9_']*)|(\\b[a-z'][a-zA-Z0-9_']*)",r:0},{cN:"variable",b:"[A-Z][a-zA-Z0-9_']*",r:0}]}}); \ No newline at end of file diff --git a/lib/highlight_js/assets/lang/erlang.js b/lib/highlight_js/assets/lang/erlang.js new file mode 100644 index 0000000000..3894bdbd3e --- /dev/null +++ b/lib/highlight_js/assets/lang/erlang.js @@ -0,0 +1 @@ +hljs.registerLanguage("erlang",function(e){var r="[a-z'][a-zA-Z0-9_']*",c="("+r+":"+r+"|"+r+")",a={keyword:"after and andalso|10 band begin bnot bor bsl bzr bxor case catch cond div end fun if let not of orelse|10 query receive rem try when xor",literal:"false true"},n=e.C("%","$"),i={cN:"number",b:"\\b(\\d+#[a-fA-F0-9]+|\\d+(\\.\\d+)?([eE][-+]?\\d+)?)",r:0},b={b:"fun\\s+"+r+"/\\d+"},d={b:c+"\\(",e:"\\)",rB:!0,r:0,c:[{cN:"function_name",b:c,r:0},{b:"\\(",e:"\\)",eW:!0,rE:!0,r:0}]},o={cN:"tuple",b:"{",e:"}",r:0},t={cN:"variable",b:"\\b_([A-Z][A-Za-z0-9_]*)?",r:0},l={cN:"variable",b:"[A-Z][a-zA-Z0-9_]*",r:0},f={b:"#"+e.UIR,r:0,rB:!0,c:[{cN:"record_name",b:"#"+e.UIR,r:0},{b:"{",e:"}",r:0}]},s={bK:"fun receive if try case",e:"end",k:a};s.c=[n,b,e.inherit(e.ASM,{cN:""}),s,d,e.QSM,i,o,t,l,f];var u=[n,b,s,d,e.QSM,i,o,t,l,f];d.c[1].c=u,o.c=u,f.c[1].c=u;var v={cN:"params",b:"\\(",e:"\\)",c:u};return{aliases:["erl"],k:a,i:"(",rB:!0,i:"\\(|#|//|/\\*|\\\\|:|;",c:[v,e.inherit(e.TM,{b:r})],starts:{e:";|\\.",k:a,c:u}},n,{cN:"pp",b:"^-",e:"\\.",r:0,eE:!0,rB:!0,l:"-"+e.IR,k:"-module -record -undef -export -ifdef -ifndef -author -copyright -doc -vsn -import -include -include_lib -compile -define -else -endif -file -behaviour -behavior -spec",c:[v]},i,e.QSM,f,t,l,o,{b:/\.$/}]}}); \ No newline at end of file diff --git a/lib/highlight_js/assets/lang/fix.js b/lib/highlight_js/assets/lang/fix.js new file mode 100644 index 0000000000..0da7d375da --- /dev/null +++ b/lib/highlight_js/assets/lang/fix.js @@ -0,0 +1 @@ +hljs.registerLanguage("fix",function(){return{c:[{b:/[^\u2401\u0001]+/,e:/[\u2401\u0001]/,eE:!0,rB:!0,rE:!1,c:[{b:/([^\u2401\u0001=]+)/,e:/=([^\u2401\u0001=]+)/,rE:!0,rB:!1,cN:"attribute"},{b:/=/,e:/([\u2401\u0001])/,eE:!0,eB:!0,cN:"string"}]}],cI:!0}}); \ No newline at end of file diff --git a/lib/highlight_js/assets/lang/fortran.js b/lib/highlight_js/assets/lang/fortran.js new file mode 100644 index 0000000000..430f466dc5 --- /dev/null +++ b/lib/highlight_js/assets/lang/fortran.js @@ -0,0 +1 @@ +hljs.registerLanguage("fortran",function(e){var t={cN:"params",b:"\\(",e:"\\)"},n={constant:".False. .True.",type:"integer real character complex logical dimension allocatable|10 parameter external implicit|10 none double precision assign intent optional pointer target in out common equivalence data",keyword:"kind do while private call intrinsic where elsewhere type endtype endmodule endselect endinterface end enddo endif if forall endforall only contains default return stop then public subroutine|10 function program .and. .or. .not. .le. .eq. .ge. .gt. .lt. goto save else use module select case access blank direct exist file fmt form formatted iostat name named nextrec number opened rec recl sequential status unformatted unit continue format pause cycle exit c_null_char c_alert c_backspace c_form_feed flush wait decimal round iomsg synchronous nopass non_overridable pass protected volatile abstract extends import non_intrinsic value deferred generic final enumerator class associate bind enum c_int c_short c_long c_long_long c_signed_char c_size_t c_int8_t c_int16_t c_int32_t c_int64_t c_int_least8_t c_int_least16_t c_int_least32_t c_int_least64_t c_int_fast8_t c_int_fast16_t c_int_fast32_t c_int_fast64_t c_intmax_t C_intptr_t c_float c_double c_long_double c_float_complex c_double_complex c_long_double_complex c_bool c_char c_null_ptr c_null_funptr c_new_line c_carriage_return c_horizontal_tab c_vertical_tab iso_c_binding c_loc c_funloc c_associated c_f_pointer c_ptr c_funptr iso_fortran_env character_storage_size error_unit file_storage_size input_unit iostat_end iostat_eor numeric_storage_size output_unit c_f_procpointer ieee_arithmetic ieee_support_underflow_control ieee_get_underflow_mode ieee_set_underflow_mode newunit contiguous pad position action delim readwrite eor advance nml interface procedure namelist include sequence elemental pure",built_in:"alog alog10 amax0 amax1 amin0 amin1 amod cabs ccos cexp clog csin csqrt dabs dacos dasin datan datan2 dcos dcosh ddim dexp dint dlog dlog10 dmax1 dmin1 dmod dnint dsign dsin dsinh dsqrt dtan dtanh float iabs idim idint idnint ifix isign max0 max1 min0 min1 sngl algama cdabs cdcos cdexp cdlog cdsin cdsqrt cqabs cqcos cqexp cqlog cqsin cqsqrt dcmplx dconjg derf derfc dfloat dgamma dimag dlgama iqint qabs qacos qasin qatan qatan2 qcmplx qconjg qcos qcosh qdim qerf qerfc qexp qgamma qimag qlgama qlog qlog10 qmax1 qmin1 qmod qnint qsign qsin qsinh qsqrt qtan qtanh abs acos aimag aint anint asin atan atan2 char cmplx conjg cos cosh exp ichar index int log log10 max min nint sign sin sinh sqrt tan tanh print write dim lge lgt lle llt mod nullify allocate deallocate adjustl adjustr all allocated any associated bit_size btest ceiling count cshift date_and_time digits dot_product eoshift epsilon exponent floor fraction huge iand ibclr ibits ibset ieor ior ishft ishftc lbound len_trim matmul maxexponent maxloc maxval merge minexponent minloc minval modulo mvbits nearest pack present product radix random_number random_seed range repeat reshape rrspacing scale scan selected_int_kind selected_real_kind set_exponent shape size spacing spread sum system_clock tiny transpose trim ubound unpack verify achar iachar transfer dble entry dprod cpu_time command_argument_count get_command get_command_argument get_environment_variable is_iostat_end ieee_arithmetic ieee_support_underflow_control ieee_get_underflow_mode ieee_set_underflow_mode is_iostat_eor move_alloc new_line selected_char_kind same_type_as extends_type_ofacosh asinh atanh bessel_j0 bessel_j1 bessel_jn bessel_y0 bessel_y1 bessel_yn erf erfc erfc_scaled gamma log_gamma hypot norm2 atomic_define atomic_ref execute_command_line leadz trailz storage_size merge_bits bge bgt ble blt dshiftl dshiftr findloc iall iany iparity image_index lcobound ucobound maskl maskr num_images parity popcnt poppar shifta shiftl shiftr this_image"};return{cI:!0,aliases:["f90","f95"],k:n,c:[e.inherit(e.ASM,{cN:"string",r:0}),e.inherit(e.QSM,{cN:"string",r:0}),{cN:"function",bK:"subroutine function program",i:"[${=\\n]",c:[e.UTM,t]},e.C("!","$",{r:0}),{cN:"number",b:"(?=\\b|\\+|\\-|\\.)(?=\\.\\d|\\d)(?:\\d+)?(?:\\.?\\d*)(?:[de][+-]?\\d+)?\\b\\.?",r:0}]}}); \ No newline at end of file diff --git a/lib/highlight_js/assets/lang/fsharp.js b/lib/highlight_js/assets/lang/fsharp.js new file mode 100644 index 0000000000..43238bce5b --- /dev/null +++ b/lib/highlight_js/assets/lang/fsharp.js @@ -0,0 +1 @@ +hljs.registerLanguage("fsharp",function(e){var t={b:"<",e:">",c:[e.inherit(e.TM,{b:/'[a-zA-Z0-9_]+/})]};return{aliases:["fs"],k:"yield! return! let! do!abstract and as assert base begin class default delegate do done downcast downto elif else end exception extern false finally for fun function global if in inherit inline interface internal lazy let match member module mutable namespace new null of open or override private public rec return sig static struct then to true try type upcast use val void when while with yield",c:[{cN:"string",b:'@"',e:'"',c:[{b:'""'}]},{cN:"string",b:'"""',e:'"""'},e.C("\\(\\*","\\*\\)"),{cN:"class",bK:"type",e:"\\(|=|$",eE:!0,c:[e.UTM,t]},{cN:"annotation",b:"\\[<",e:">\\]",r:10},{cN:"attribute",b:"\\B('[A-Za-z])\\b",c:[e.BE]},e.CLCM,e.inherit(e.QSM,{i:null}),e.CNM]}}); \ No newline at end of file diff --git a/lib/highlight_js/assets/lang/gcode.js b/lib/highlight_js/assets/lang/gcode.js new file mode 100644 index 0000000000..00607061b6 --- /dev/null +++ b/lib/highlight_js/assets/lang/gcode.js @@ -0,0 +1 @@ +hljs.registerLanguage("gcode",function(e){var N="[A-Z_][A-Z0-9_.]*",i="\\%",c={literal:"",built_in:"",keyword:"IF DO WHILE ENDWHILE CALL ENDIF SUB ENDSUB GOTO REPEAT ENDREPEAT EQ LT GT NE GE LE OR XOR"},r={cN:"preprocessor",b:"([O])([0-9]+)"},l=[e.CLCM,e.CBCM,e.C(/\(/,/\)/),e.inherit(e.CNM,{b:"([-+]?([0-9]*\\.?[0-9]+\\.?))|"+e.CNR}),e.inherit(e.ASM,{i:null}),e.inherit(e.QSM,{i:null}),{cN:"keyword",b:"([G])([0-9]+\\.?[0-9]?)"},{cN:"title",b:"([M])([0-9]+\\.?[0-9]?)"},{cN:"title",b:"(VC|VS|#)",e:"(\\d+)"},{cN:"title",b:"(VZOFX|VZOFY|VZOFZ)"},{cN:"built_in",b:"(ATAN|ABS|ACOS|ASIN|SIN|COS|EXP|FIX|FUP|ROUND|LN|TAN)(\\[)",e:"([-+]?([0-9]*\\.?[0-9]+\\.?))(\\])"},{cN:"label",v:[{b:"N",e:"\\d+",i:"\\W"}]}];return{aliases:["nc"],cI:!0,l:N,k:c,c:[{cN:"preprocessor",b:i},r].concat(l)}}); \ No newline at end of file diff --git a/lib/highlight_js/assets/lang/gherkin.js b/lib/highlight_js/assets/lang/gherkin.js new file mode 100644 index 0000000000..2df5db806a --- /dev/null +++ b/lib/highlight_js/assets/lang/gherkin.js @@ -0,0 +1 @@ +hljs.registerLanguage("gherkin",function(e){return{aliases:["feature"],k:"Feature Background Ability Business Need Scenario Scenarios Scenario Outline Scenario Template Examples Given And Then But When",c:[{cN:"keyword",b:"\\*"},e.C("@[^@\r\n ]+","$"),{cN:"string",b:"\\|",e:"\\$"},{cN:"variable",b:"<",e:">"},e.HCM,{cN:"string",b:'"""',e:'"""'},e.QSM]}}); \ No newline at end of file diff --git a/lib/highlight_js/assets/lang/glsl.js b/lib/highlight_js/assets/lang/glsl.js new file mode 100644 index 0000000000..b7c4058892 --- /dev/null +++ b/lib/highlight_js/assets/lang/glsl.js @@ -0,0 +1 @@ +hljs.registerLanguage("glsl",function(e){return{k:{keyword:"atomic_uint attribute bool break bvec2 bvec3 bvec4 case centroid coherent const continue default discard dmat2 dmat2x2 dmat2x3 dmat2x4 dmat3 dmat3x2 dmat3x3 dmat3x4 dmat4 dmat4x2 dmat4x3 dmat4x4 do double dvec2 dvec3 dvec4 else flat float for highp if iimage1D iimage1DArray iimage2D iimage2DArray iimage2DMS iimage2DMSArray iimage2DRect iimage3D iimageBuffer iimageCube iimageCubeArray image1D image1DArray image2D image2DArray image2DMS image2DMSArray image2DRect image3D imageBuffer imageCube imageCubeArray in inout int invariant isampler1D isampler1DArray isampler2D isampler2DArray isampler2DMS isampler2DMSArray isampler2DRect isampler3D isamplerBuffer isamplerCube isamplerCubeArray ivec2 ivec3 ivec4 layout lowp mat2 mat2x2 mat2x3 mat2x4 mat3 mat3x2 mat3x3 mat3x4 mat4 mat4x2 mat4x3 mat4x4 mediump noperspective out patch precision readonly restrict return sample sampler1D sampler1DArray sampler1DArrayShadow sampler1DShadow sampler2D sampler2DArray sampler2DArrayShadow sampler2DMS sampler2DMSArray sampler2DRect sampler2DRectShadow sampler2DShadow sampler3D samplerBuffer samplerCube samplerCubeArray samplerCubeArrayShadow samplerCubeShadow smooth struct subroutine switch uimage1D uimage1DArray uimage2D uimage2DArray uimage2DMS uimage2DMSArray uimage2DRect uimage3D uimageBuffer uimageCube uimageCubeArray uint uniform usampler1D usampler1DArray usampler2D usampler2DArray usampler2DMS usampler2DMSArray usampler2DRect usampler3D usamplerBuffer usamplerCube usamplerCubeArray uvec2 uvec3 uvec4 varying vec2 vec3 vec4 void volatile while writeonly",built_in:"gl_BackColor gl_BackLightModelProduct gl_BackLightProduct gl_BackMaterial gl_BackSecondaryColor gl_ClipDistance gl_ClipPlane gl_ClipVertex gl_Color gl_DepthRange gl_EyePlaneQ gl_EyePlaneR gl_EyePlaneS gl_EyePlaneT gl_Fog gl_FogCoord gl_FogFragCoord gl_FragColor gl_FragCoord gl_FragData gl_FragDepth gl_FrontColor gl_FrontFacing gl_FrontLightModelProduct gl_FrontLightProduct gl_FrontMaterial gl_FrontSecondaryColor gl_InstanceID gl_InvocationID gl_Layer gl_LightModel gl_LightSource gl_MaxAtomicCounterBindings gl_MaxAtomicCounterBufferSize gl_MaxClipDistances gl_MaxClipPlanes gl_MaxCombinedAtomicCounterBuffers gl_MaxCombinedAtomicCounters gl_MaxCombinedImageUniforms gl_MaxCombinedImageUnitsAndFragmentOutputs gl_MaxCombinedTextureImageUnits gl_MaxDrawBuffers gl_MaxFragmentAtomicCounterBuffers gl_MaxFragmentAtomicCounters gl_MaxFragmentImageUniforms gl_MaxFragmentInputComponents gl_MaxFragmentUniformComponents gl_MaxFragmentUniformVectors gl_MaxGeometryAtomicCounterBuffers gl_MaxGeometryAtomicCounters gl_MaxGeometryImageUniforms gl_MaxGeometryInputComponents gl_MaxGeometryOutputComponents gl_MaxGeometryOutputVertices gl_MaxGeometryTextureImageUnits gl_MaxGeometryTotalOutputComponents gl_MaxGeometryUniformComponents gl_MaxGeometryVaryingComponents gl_MaxImageSamples gl_MaxImageUnits gl_MaxLights gl_MaxPatchVertices gl_MaxProgramTexelOffset gl_MaxTessControlAtomicCounterBuffers gl_MaxTessControlAtomicCounters gl_MaxTessControlImageUniforms gl_MaxTessControlInputComponents gl_MaxTessControlOutputComponents gl_MaxTessControlTextureImageUnits gl_MaxTessControlTotalOutputComponents gl_MaxTessControlUniformComponents gl_MaxTessEvaluationAtomicCounterBuffers gl_MaxTessEvaluationAtomicCounters gl_MaxTessEvaluationImageUniforms gl_MaxTessEvaluationInputComponents gl_MaxTessEvaluationOutputComponents gl_MaxTessEvaluationTextureImageUnits gl_MaxTessEvaluationUniformComponents gl_MaxTessGenLevel gl_MaxTessPatchComponents gl_MaxTextureCoords gl_MaxTextureImageUnits gl_MaxTextureUnits gl_MaxVaryingComponents gl_MaxVaryingFloats gl_MaxVaryingVectors gl_MaxVertexAtomicCounterBuffers gl_MaxVertexAtomicCounters gl_MaxVertexAttribs gl_MaxVertexImageUniforms gl_MaxVertexOutputComponents gl_MaxVertexTextureImageUnits gl_MaxVertexUniformComponents gl_MaxVertexUniformVectors gl_MaxViewports gl_MinProgramTexelOffsetgl_ModelViewMatrix gl_ModelViewMatrixInverse gl_ModelViewMatrixInverseTranspose gl_ModelViewMatrixTranspose gl_ModelViewProjectionMatrix gl_ModelViewProjectionMatrixInverse gl_ModelViewProjectionMatrixInverseTranspose gl_ModelViewProjectionMatrixTranspose gl_MultiTexCoord0 gl_MultiTexCoord1 gl_MultiTexCoord2 gl_MultiTexCoord3 gl_MultiTexCoord4 gl_MultiTexCoord5 gl_MultiTexCoord6 gl_MultiTexCoord7 gl_Normal gl_NormalMatrix gl_NormalScale gl_ObjectPlaneQ gl_ObjectPlaneR gl_ObjectPlaneS gl_ObjectPlaneT gl_PatchVerticesIn gl_PerVertex gl_Point gl_PointCoord gl_PointSize gl_Position gl_PrimitiveID gl_PrimitiveIDIn gl_ProjectionMatrix gl_ProjectionMatrixInverse gl_ProjectionMatrixInverseTranspose gl_ProjectionMatrixTranspose gl_SampleID gl_SampleMask gl_SampleMaskIn gl_SamplePosition gl_SecondaryColor gl_TessCoord gl_TessLevelInner gl_TessLevelOuter gl_TexCoord gl_TextureEnvColor gl_TextureMatrixInverseTranspose gl_TextureMatrixTranspose gl_Vertex gl_VertexID gl_ViewportIndex gl_in gl_out EmitStreamVertex EmitVertex EndPrimitive EndStreamPrimitive abs acos acosh all any asin asinh atan atanh atomicCounter atomicCounterDecrement atomicCounterIncrement barrier bitCount bitfieldExtract bitfieldInsert bitfieldReverse ceil clamp cos cosh cross dFdx dFdy degrees determinant distance dot equal exp exp2 faceforward findLSB findMSB floatBitsToInt floatBitsToUint floor fma fract frexp ftransform fwidth greaterThan greaterThanEqual imageAtomicAdd imageAtomicAnd imageAtomicCompSwap imageAtomicExchange imageAtomicMax imageAtomicMin imageAtomicOr imageAtomicXor imageLoad imageStore imulExtended intBitsToFloat interpolateAtCentroid interpolateAtOffset interpolateAtSample inverse inversesqrt isinf isnan ldexp length lessThan lessThanEqual log log2 matrixCompMult max memoryBarrier min mix mod modf noise1 noise2 noise3 noise4 normalize not notEqual outerProduct packDouble2x32 packHalf2x16 packSnorm2x16 packSnorm4x8 packUnorm2x16 packUnorm4x8 pow radians reflect refract round roundEven shadow1D shadow1DLod shadow1DProj shadow1DProjLod shadow2D shadow2DLod shadow2DProj shadow2DProjLod sign sin sinh smoothstep sqrt step tan tanh texelFetch texelFetchOffset texture texture1D texture1DLod texture1DProj texture1DProjLod texture2D texture2DLod texture2DProj texture2DProjLod texture3D texture3DLod texture3DProj texture3DProjLod textureCube textureCubeLod textureGather textureGatherOffset textureGatherOffsets textureGrad textureGradOffset textureLod textureLodOffset textureOffset textureProj textureProjGrad textureProjGradOffset textureProjLod textureProjLodOffset textureProjOffset textureQueryLod textureSize transpose trunc uaddCarry uintBitsToFloat umulExtended unpackDouble2x32 unpackHalf2x16 unpackSnorm2x16 unpackSnorm4x8 unpackUnorm2x16 unpackUnorm4x8 usubBorrow gl_TextureMatrix gl_TextureMatrixInverse",literal:"true false"},i:'"',c:[e.CLCM,e.CBCM,e.CNM,{cN:"preprocessor",b:"#",e:"$"}]}}); \ No newline at end of file diff --git a/lib/highlight_js/assets/lang/go.js b/lib/highlight_js/assets/lang/go.js new file mode 100644 index 0000000000..96c9447539 --- /dev/null +++ b/lib/highlight_js/assets/lang/go.js @@ -0,0 +1 @@ +hljs.registerLanguage("go",function(e){var t={keyword:"break default func interface select case map struct chan else goto package switch const fallthrough if range type continue for import return var go defer",constant:"true false iota nil",typename:"bool byte complex64 complex128 float32 float64 int8 int16 int32 int64 string uint8 uint16 uint32 uint64 int uint uintptr rune",built_in:"append cap close complex copy imag len make new panic print println real recover delete"};return{aliases:["golang"],k:t,i:"",e:",\\s+",rB:!0,eW:!0,c:[{cN:"symbol",b:":\\w+"},{cN:"string",b:'"',e:'"'},{cN:"string",b:"'",e:"'"},{b:"\\w+",r:0}]}]},{b:"\\(\\s*",e:"\\s*\\)",eE:!0,c:[{b:"\\w+\\s*=",e:"\\s+",rB:!0,eW:!0,c:[{cN:"attribute",b:"\\w+",r:0},{cN:"string",b:'"',e:'"'},{cN:"string",b:"'",e:"'"},{b:"\\w+",r:0}]}]}]},{cN:"bullet",b:"^\\s*[=~]\\s*",r:0},{b:"#{",starts:{e:"}",sL:"ruby"}}]}}); \ No newline at end of file diff --git a/lib/highlight_js/assets/lang/handlebars.js b/lib/highlight_js/assets/lang/handlebars.js new file mode 100644 index 0000000000..21387ac325 --- /dev/null +++ b/lib/highlight_js/assets/lang/handlebars.js @@ -0,0 +1 @@ +hljs.registerLanguage("handlebars",function(){var e="each in with if else unless bindattr action collection debugger log outlet template unbound view yield";return{aliases:["hbs","html.hbs","html.handlebars"],cI:!0,sL:"xml",subLanguageMode:"continuous",c:[{cN:"expression",b:"{{",e:"}}",c:[{cN:"begin-block",b:"#[a-zA-Z- .]+",k:e},{cN:"string",b:'"',e:'"'},{cN:"end-block",b:"\\/[a-zA-Z- .]+",k:e},{cN:"variable",b:"[a-zA-Z-.]+",k:e}]}]}}); \ No newline at end of file diff --git a/lib/highlight_js/assets/lang/haskell.js b/lib/highlight_js/assets/lang/haskell.js new file mode 100644 index 0000000000..42f0ba1dd0 --- /dev/null +++ b/lib/highlight_js/assets/lang/haskell.js @@ -0,0 +1 @@ +hljs.registerLanguage("haskell",function(e){var c=[e.C("--","$"),e.C("{-","-}",{c:["self"]})],a={cN:"pragma",b:"{-#",e:"#-}"},i={cN:"preprocessor",b:"^#",e:"$"},n={cN:"type",b:"\\b[A-Z][\\w']*",r:0},t={cN:"container",b:"\\(",e:"\\)",i:'"',c:[a,i,{cN:"type",b:"\\b[A-Z][\\w]*(\\((\\.\\.|,|\\w+)\\))?"},e.inherit(e.TM,{b:"[_a-z][\\w']*"})].concat(c)},l={cN:"container",b:"{",e:"}",c:t.c};return{aliases:["hs"],k:"let in if then else case of where do module import hiding qualified type data newtype deriving class instance as default infix infixl infixr foreign export ccall stdcall cplusplus jvm dotnet safe unsafe family forall mdo proc rec",c:[{cN:"module",b:"\\bmodule\\b",e:"where",k:"module where",c:[t].concat(c),i:"\\W\\.|;"},{cN:"import",b:"\\bimport\\b",e:"$",k:"import|0 qualified as hiding",c:[t].concat(c),i:"\\W\\.|;"},{cN:"class",b:"^(\\s*)?(class|instance)\\b",e:"where",k:"class family instance where",c:[n,t].concat(c)},{cN:"typedef",b:"\\b(data|(new)?type)\\b",e:"$",k:"data family type newtype deriving",c:[a,n,t,l].concat(c)},{cN:"default",bK:"default",e:"$",c:[n,t].concat(c)},{cN:"infix",bK:"infix infixl infixr",e:"$",c:[e.CNM].concat(c)},{cN:"foreign",b:"\\bforeign\\b",e:"$",k:"foreign import export ccall stdcall cplusplus jvm dotnet safe unsafe",c:[n,e.QSM].concat(c)},{cN:"shebang",b:"#!\\/usr\\/bin\\/env runhaskell",e:"$"},a,i,e.QSM,e.CNM,n,e.inherit(e.TM,{b:"^[_a-z][\\w']*"}),{b:"->|<-"}].concat(c)}}); \ No newline at end of file diff --git a/lib/highlight_js/assets/lang/haxe.js b/lib/highlight_js/assets/lang/haxe.js new file mode 100644 index 0000000000..4d2a775d10 --- /dev/null +++ b/lib/highlight_js/assets/lang/haxe.js @@ -0,0 +1 @@ +hljs.registerLanguage("haxe",function(e){var r="([*]|[a-zA-Z_$][a-zA-Z0-9_$]*)";return{aliases:["hx"],k:{keyword:"break callback case cast catch class continue default do dynamic else enum extends extern for function here if implements import in inline interface never new override package private public return static super switch this throw trace try typedef untyped using var while",literal:"true false null"},c:[e.ASM,e.QSM,e.CLCM,e.CBCM,e.CNM,{cN:"class",bK:"class interface",e:"{",eE:!0,c:[{bK:"extends implements"},e.TM]},{cN:"preprocessor",b:"#",e:"$",k:"if else elseif end error"},{cN:"function",bK:"function",e:"[{;]",eE:!0,i:"\\S",c:[e.TM,{cN:"params",b:"\\(",e:"\\)",c:[e.ASM,e.QSM,e.CLCM,e.CBCM]},{cN:"type",b:":",e:r,r:10}]}]}}); \ No newline at end of file diff --git a/lib/highlight_js/assets/lang/http.js b/lib/highlight_js/assets/lang/http.js new file mode 100644 index 0000000000..0322887205 --- /dev/null +++ b/lib/highlight_js/assets/lang/http.js @@ -0,0 +1 @@ +hljs.registerLanguage("http",function(){return{aliases:["https"],i:"\\S",c:[{cN:"status",b:"^HTTP/[0-9\\.]+",e:"$",c:[{cN:"number",b:"\\b\\d{3}\\b"}]},{cN:"request",b:"^[A-Z]+ (.*?) HTTP/[0-9\\.]+$",rB:!0,e:"$",c:[{cN:"string",b:" ",e:" ",eB:!0,eE:!0}]},{cN:"attribute",b:"^\\w",e:": ",eE:!0,i:"\\n|\\s|=",starts:{cN:"string",e:"$"}},{b:"\\n\\n",starts:{sL:"",eW:!0}}]}}); \ No newline at end of file diff --git a/lib/highlight_js/assets/lang/ini.js b/lib/highlight_js/assets/lang/ini.js new file mode 100644 index 0000000000..6618500ecd --- /dev/null +++ b/lib/highlight_js/assets/lang/ini.js @@ -0,0 +1 @@ +hljs.registerLanguage("ini",function(e){return{cI:!0,i:/\S/,c:[e.C(";","$"),{cN:"title",b:"^\\[",e:"\\]"},{cN:"setting",b:"^[a-z0-9\\[\\]_-]+[ \\t]*=[ \\t]*",e:"$",c:[{cN:"value",eW:!0,k:"on off true false yes no",c:[e.QSM,e.NM],r:0}]}]}}); \ No newline at end of file diff --git a/lib/highlight_js/assets/lang/java.js b/lib/highlight_js/assets/lang/java.js new file mode 100644 index 0000000000..c58ebcc78b --- /dev/null +++ b/lib/highlight_js/assets/lang/java.js @@ -0,0 +1 @@ +hljs.registerLanguage("java",function(e){var a=e.UIR+"(<"+e.UIR+">)?",t="false synchronized int abstract float private char boolean static null if const for true while long strictfp finally protected import native final void enum else break transient catch instanceof byte super volatile case assert short package default double public try this switch continue throws protected public private",c="(\\b(0b[01_]+)|\\b0[xX][a-fA-F0-9_]+|(\\b[\\d_]+(\\.[\\d_]*)?|\\.[\\d_]+)([eE][-+]?\\d+)?)[lLfF]?",r={cN:"number",b:c,r:0};return{aliases:["jsp"],k:t,i:/<\//,c:[{cN:"javadoc",b:"/\\*\\*",e:"\\*/",r:0,c:[{cN:"javadoctag",b:"(^|\\s)@[A-Za-z]+"}]},e.CLCM,e.CBCM,e.ASM,e.QSM,{cN:"class",bK:"class interface",e:/[{;=]/,eE:!0,k:"class interface",i:/[:"\[\]]/,c:[{bK:"extends implements"},e.UTM]},{bK:"new throw return",r:0},{cN:"function",b:"("+a+"\\s+)+"+e.UIR+"\\s*\\(",rB:!0,e:/[{;=]/,eE:!0,k:t,c:[{b:e.UIR+"\\s*\\(",rB:!0,r:0,c:[e.UTM]},{cN:"params",b:/\(/,e:/\)/,k:t,r:0,c:[e.ASM,e.QSM,e.CNM,e.CBCM]},e.CLCM,e.CBCM]},r,{cN:"annotation",b:"@[A-Za-z]+"}]}}); \ No newline at end of file diff --git a/lib/highlight_js/assets/lang/javascript.js b/lib/highlight_js/assets/lang/javascript.js new file mode 100644 index 0000000000..a06bc721c1 --- /dev/null +++ b/lib/highlight_js/assets/lang/javascript.js @@ -0,0 +1 @@ +hljs.registerLanguage("javascript",function(e){return{aliases:["js"],k:{keyword:"in of if for while finally var new function do return void else break catch instanceof with throw case default try this switch continue typeof delete let yield const export super debugger as",literal:"true false null undefined NaN Infinity",built_in:"eval isFinite isNaN parseFloat parseInt decodeURI decodeURIComponent encodeURI encodeURIComponent escape unescape Object Function Boolean Error EvalError InternalError RangeError ReferenceError StopIteration SyntaxError TypeError URIError Number Math Date String RegExp Array Float32Array Float64Array Int16Array Int32Array Int8Array Uint16Array Uint32Array Uint8Array Uint8ClampedArray ArrayBuffer DataView JSON Intl arguments require module console window document Symbol Set Map WeakSet WeakMap Proxy Reflect Promise"},c:[{cN:"pi",r:10,v:[{b:/^\s*('|")use strict('|")/},{b:/^\s*('|")use asm('|")/}]},e.ASM,e.QSM,{cN:"string",b:"`",e:"`",c:[e.BE,{cN:"subst",b:"\\$\\{",e:"\\}"}]},e.CLCM,e.CBCM,{cN:"number",b:"\\b(0[xXbBoO][a-fA-F0-9]+|(\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)",r:0},{b:"("+e.RSR+"|\\b(case|return|throw)\\b)\\s*",k:"return throw case",c:[e.CLCM,e.CBCM,e.RM,{b:/\s*[);\]]/,r:0,sL:"xml"}],r:0},{cN:"function",bK:"function",e:/\{/,eE:!0,c:[e.inherit(e.TM,{b:/[A-Za-z$_][0-9A-Za-z$_]*/}),{cN:"params",b:/\(/,e:/\)/,c:[e.CLCM,e.CBCM],i:/["'\(]/}],i:/\[|%/},{b:/\$[(.]/},{b:"\\."+e.IR,r:0},{bK:"import",e:"[;$]",k:"import from as",c:[e.ASM,e.QSM]},{cN:"class",bK:"class",e:/[{;=]/,eE:!0,i:/[:"\[\]]/,c:[{bK:"extends"},e.UTM]}]}}); \ No newline at end of file diff --git a/lib/highlight_js/assets/lang/json.js b/lib/highlight_js/assets/lang/json.js new file mode 100644 index 0000000000..38f9c0010a --- /dev/null +++ b/lib/highlight_js/assets/lang/json.js @@ -0,0 +1 @@ +hljs.registerLanguage("json",function(e){var t={literal:"true false null"},i=[e.QSM,e.CNM],l={cN:"value",e:",",eW:!0,eE:!0,c:i,k:t},c={b:"{",e:"}",c:[{cN:"attribute",b:'\\s*"',e:'"\\s*:\\s*',eB:!0,eE:!0,c:[e.BE],i:"\\n",starts:l}],i:"\\S"},n={b:"\\[",e:"\\]",c:[e.inherit(l,{cN:null})],i:"\\S"};return i.splice(i.length,0,c,n),{c:i,k:t,i:"\\S"}}); \ No newline at end of file diff --git a/lib/highlight_js/assets/lang/julia.js b/lib/highlight_js/assets/lang/julia.js new file mode 100644 index 0000000000..1aa4c111cb --- /dev/null +++ b/lib/highlight_js/assets/lang/julia.js @@ -0,0 +1 @@ +hljs.registerLanguage("julia",function(r){var e={keyword:"in abstract baremodule begin bitstype break catch ccall const continue do else elseif end export finally for function global if immutable import importall let local macro module quote return try type typealias using while",literal:"true false ANY ARGS CPU_CORES C_NULL DL_LOAD_PATH DevNull ENDIAN_BOM ENV I|0 Inf Inf16 Inf32 InsertionSort JULIA_HOME LOAD_PATH MS_ASYNC MS_INVALIDATE MS_SYNC MergeSort NaN NaN16 NaN32 OS_NAME QuickSort RTLD_DEEPBIND RTLD_FIRST RTLD_GLOBAL RTLD_LAZY RTLD_LOCAL RTLD_NODELETE RTLD_NOLOAD RTLD_NOW RoundDown RoundFromZero RoundNearest RoundToZero RoundUp STDERR STDIN STDOUT VERSION WORD_SIZE catalan cglobal e eu eulergamma golden im nothing pi γ π φ",built_in:"ASCIIString AbstractArray AbstractRNG AbstractSparseArray Any ArgumentError Array Associative Base64Pipe Bidiagonal BigFloat BigInt BitArray BitMatrix BitVector Bool BoundsError Box CFILE Cchar Cdouble Cfloat Char CharString Cint Clong Clonglong ClusterManager Cmd Coff_t Colon Complex Complex128 Complex32 Complex64 Condition Cptrdiff_t Cshort Csize_t Cssize_t Cuchar Cuint Culong Culonglong Cushort Cwchar_t DArray DataType DenseArray Diagonal Dict DimensionMismatch DirectIndexString Display DivideError DomainError EOFError EachLine Enumerate ErrorException Exception Expr Factorization FileMonitor FileOffset Filter Float16 Float32 Float64 FloatRange FloatingPoint Function GetfieldNode GotoNode Hermitian IO IOBuffer IOStream IPv4 IPv6 InexactError Int Int128 Int16 Int32 Int64 Int8 IntSet Integer InterruptException IntrinsicFunction KeyError LabelNode LambdaStaticData LineNumberNode LoadError LocalProcess MIME MathConst MemoryError MersenneTwister Method MethodError MethodTable Module NTuple NewvarNode Nothing Number ObjectIdDict OrdinalRange OverflowError ParseError PollingFileWatcher ProcessExitedException ProcessGroup Ptr QuoteNode Range Range1 Ranges Rational RawFD Real Regex RegexMatch RemoteRef RepString RevString RopeString RoundingMode Set SharedArray Signed SparseMatrixCSC StackOverflowError Stat StatStruct StepRange String SubArray SubString SymTridiagonal Symbol SymbolNode Symmetric SystemError Task TextDisplay Timer TmStruct TopNode Triangular Tridiagonal Type TypeConstructor TypeError TypeName TypeVar UTF16String UTF32String UTF8String UdpSocket Uint Uint128 Uint16 Uint32 Uint64 Uint8 UndefRefError UndefVarError UniformScaling UnionType UnitRange Unsigned Vararg VersionNumber WString WeakKeyDict WeakRef Woodbury Zip"},t="[A-Za-z_\\u00A1-\\uFFFF][A-Za-z_0-9\\u00A1-\\uFFFF]*",o={l:t,k:e},n={cN:"type-annotation",b:/::/},a={cN:"subtype",b:/<:/},i={cN:"number",b:/(\b0x[\d_]*(\.[\d_]*)?|0x\.\d[\d_]*)p[-+]?\d+|\b0[box][a-fA-F0-9][a-fA-F0-9_]*|(\b\d[\d_]*(\.[\d_]*)?|\.\d[\d_]*)([eEfF][-+]?\d+)?/,r:0},l={cN:"char",b:/'(.|\\[xXuU][a-zA-Z0-9]+)'/},c={cN:"subst",b:/\$\(/,e:/\)/,k:e},u={cN:"variable",b:"\\$"+t},d={cN:"string",c:[r.BE,c,u],v:[{b:/\w*"/,e:/"\w*/},{b:/\w*"""/,e:/"""\w*/}]},g={cN:"string",c:[r.BE,c,u],b:"`",e:"`"},s={cN:"macrocall",b:"@"+t},S={cN:"comment",v:[{b:"#=",e:"=#",r:10},{b:"#",e:"$"}]};return o.c=[i,l,n,a,d,g,s,S,r.HCM],c.c=o.c,o}); \ No newline at end of file diff --git a/lib/highlight_js/assets/lang/lasso.js b/lib/highlight_js/assets/lang/lasso.js new file mode 100644 index 0000000000..24e01c7ed5 --- /dev/null +++ b/lib/highlight_js/assets/lang/lasso.js @@ -0,0 +1 @@ +hljs.registerLanguage("lasso",function(e){var r="[a-zA-Z_][a-zA-Z0-9_.]*",a="<\\?(lasso(script)?|=)",t="\\]|\\?>",s={literal:"true false none minimal full all void and or not bw nbw ew new cn ncn lt lte gt gte eq neq rx nrx ft",built_in:"array date decimal duration integer map pair string tag xml null boolean bytes keyword list locale queue set stack staticarray local var variable global data self inherited",keyword:"error_code error_msg error_pop error_push error_reset cache database_names database_schemanames database_tablenames define_tag define_type email_batch encode_set html_comment handle handle_error header if inline iterate ljax_target link link_currentaction link_currentgroup link_currentrecord link_detail link_firstgroup link_firstrecord link_lastgroup link_lastrecord link_nextgroup link_nextrecord link_prevgroup link_prevrecord log loop namespace_using output_none portal private protect records referer referrer repeating resultset rows search_args search_arguments select sort_args sort_arguments thread_atomic value_list while abort case else if_empty if_false if_null if_true loop_abort loop_continue loop_count params params_up return return_value run_children soap_definetag soap_lastrequest soap_lastresponse tag_name ascending average by define descending do equals frozen group handle_failure import in into join let match max min on order parent protected provide public require returnhome skip split_thread sum take thread to trait type where with yield yieldhome"},n=e.C("",{r:0}),o={cN:"preprocessor",b:"\\[noprocess\\]",starts:{cN:"markup",e:"\\[/noprocess\\]",rE:!0,c:[n]}},i={cN:"preprocessor",b:"\\[/noprocess|"+a},l={cN:"variable",b:"'"+r+"'"},c=[e.CLCM,{cN:"javadoc",b:"/\\*\\*!",e:"\\*/",c:[e.PWM]},e.CBCM,e.inherit(e.CNM,{b:e.CNR+"|(-?infinity|nan)\\b"}),e.inherit(e.ASM,{i:null}),e.inherit(e.QSM,{i:null}),{cN:"string",b:"`",e:"`"},{cN:"variable",v:[{b:"[#$]"+r},{b:"#",e:"\\d+",i:"\\W"}]},{cN:"tag",b:"::\\s*",e:r,i:"\\W"},{cN:"attribute",v:[{b:"-"+e.UIR,r:0},{b:"(\\.\\.\\.)"}]},{cN:"subst",v:[{b:"->\\s*",c:[l]},{b:":=|/(?!\\w)=?|[-+*%=<>&|!?\\\\]+",r:0}]},{cN:"built_in",b:"\\.\\.?\\s*",r:0,c:[l]},{cN:"class",bK:"define",rE:!0,e:"\\(|=>",c:[e.inherit(e.TM,{b:e.UIR+"(=(?!>))?"})]}];return{aliases:["ls","lassoscript"],cI:!0,l:r+"|&[lg]t;",k:s,c:[{cN:"preprocessor",b:t,r:0,starts:{cN:"markup",e:"\\[|"+a,rE:!0,r:0,c:[n]}},o,i,{cN:"preprocessor",b:"\\[no_square_brackets",starts:{e:"\\[/no_square_brackets\\]",l:r+"|&[lg]t;",k:s,c:[{cN:"preprocessor",b:t,r:0,starts:{cN:"markup",e:"\\[noprocess\\]|"+a,rE:!0,c:[n]}},o,i].concat(c)}},{cN:"preprocessor",b:"\\[",r:0},{cN:"shebang",b:"^#!.+lasso9\\b",r:10}].concat(c)}}); \ No newline at end of file diff --git a/lib/highlight_js/assets/lang/less.js b/lib/highlight_js/assets/lang/less.js new file mode 100644 index 0000000000..61f038720f --- /dev/null +++ b/lib/highlight_js/assets/lang/less.js @@ -0,0 +1 @@ +hljs.registerLanguage("less",function(e){var r="[\\w-]+",t="("+r+"|@{"+r+"})",a=[],c=[],n=function(e){return{cN:"string",b:"~?"+e+".*?"+e}},i=function(e,r,t){return{cN:e,b:r,r:t}},s=function(r,t,a){return e.inherit({cN:r,b:t+"\\(",e:"\\(",rB:!0,eE:!0,r:0},a)},b={b:"\\(",e:"\\)",c:c,r:0};c.push(e.CLCM,e.CBCM,n("'"),n('"'),e.CSSNM,i("hexcolor","#[0-9A-Fa-f]+\\b"),s("function","(url|data-uri)",{starts:{cN:"string",e:"[\\)\\n]",eE:!0}}),s("function",r),b,i("variable","@@?"+r,10),i("variable","@{"+r+"}"),i("built_in","~?`[^`]*?`"),{cN:"attribute",b:r+"\\s*:",e:":",rB:!0,eE:!0});var o=c.concat({b:"{",e:"}",c:a}),u={bK:"when",eW:!0,c:[{bK:"and not"}].concat(c)},C={cN:"attribute",b:t,e:":",eE:!0,c:[e.CLCM,e.CBCM],i:/\S/,starts:{e:"[;}]",rE:!0,c:c,i:"[<=$]"}},l={cN:"at_rule",b:"@(import|media|charset|font-face|(-[a-z]+-)?keyframes|supports|document|namespace|page|viewport|host)\\b",starts:{e:"[;{}]",rE:!0,c:c,r:0}},d={cN:"variable",v:[{b:"@"+r+"\\s*:",r:15},{b:"@"+r}],starts:{e:"[;}]",rE:!0,c:o}},p={v:[{b:"[\\.#:&\\[]",e:"[;{}]"},{b:t+"[^;]*{",e:"{"}],rB:!0,rE:!0,i:"[<='$\"]",c:[e.CLCM,e.CBCM,u,i("keyword","all\\b"),i("variable","@{"+r+"}"),i("tag",t+"%?",0),i("id","#"+t),i("class","\\."+t,0),i("keyword","&",0),s("pseudo",":not"),s("keyword",":extend"),i("pseudo","::?"+t),{cN:"attr_selector",b:"\\[",e:"\\]"},{b:"\\(",e:"\\)",c:o},{b:"!important"}]};return a.push(e.CLCM,e.CBCM,l,d,p,C),{cI:!0,i:"[=>'/<($\"]",c:a}}); \ No newline at end of file diff --git a/lib/highlight_js/assets/lang/lisp.js b/lib/highlight_js/assets/lang/lisp.js new file mode 100644 index 0000000000..ca9b5814e8 --- /dev/null +++ b/lib/highlight_js/assets/lang/lisp.js @@ -0,0 +1 @@ +hljs.registerLanguage("lisp",function(e){var b="[a-zA-Z_\\-\\+\\*\\/\\<\\=\\>\\&\\#][a-zA-Z0-9_\\-\\+\\*\\/\\<\\=\\>\\&\\#!]*",c="\\|[^]*?\\|",r="(\\-|\\+)?\\d+(\\.\\d+|\\/\\d+)?((d|e|f|l|s)(\\+|\\-)?\\d+)?",a={cN:"shebang",b:"^#!",e:"$"},i={cN:"literal",b:"\\b(t{1}|nil)\\b"},l={cN:"number",v:[{b:r,r:0},{b:"#b[0-1]+(/[0-1]+)?"},{b:"#o[0-7]+(/[0-7]+)?"},{b:"#x[0-9a-f]+(/[0-9a-f]+)?"},{b:"#c\\("+r+" +"+r,e:"\\)"}]},t=e.inherit(e.QSM,{i:null}),d=e.C(";","$",{r:0}),n={cN:"variable",b:"\\*",e:"\\*"},u={cN:"keyword",b:"[:&]"+b},N={b:c},o={b:"\\(",e:"\\)",c:["self",i,t,l]},s={cN:"quoted",c:[l,t,n,u,o],v:[{b:"['`]\\(",e:"\\)"},{b:"\\(quote ",e:"\\)",k:"quote"},{b:"'"+c}]},f={cN:"quoted",b:"'"+b},v={cN:"list",b:"\\(",e:"\\)"},g={eW:!0,r:0};return v.c=[{cN:"keyword",v:[{b:b},{b:c}]},g],g.c=[s,f,v,i,l,t,d,n,u,N],{i:/\S/,c:[l,a,i,t,d,s,f,v]}}); \ No newline at end of file diff --git a/lib/highlight_js/assets/lang/livecodeserver.js b/lib/highlight_js/assets/lang/livecodeserver.js new file mode 100644 index 0000000000..b2d10f2fd0 --- /dev/null +++ b/lib/highlight_js/assets/lang/livecodeserver.js @@ -0,0 +1 @@ +hljs.registerLanguage("livecodeserver",function(e){var r={cN:"variable",b:"\\b[gtps][A-Z]+[A-Za-z0-9_\\-]*\\b|\\$_[A-Z]+",r:0},t=[e.CBCM,e.HCM,e.C("--","$"),e.C("[^:]//","$")],a=e.inherit(e.TM,{v:[{b:"\\b_*rig[A-Z]+[A-Za-z0-9_\\-]*"},{b:"\\b_[a-z0-9\\-]+"}]}),o=e.inherit(e.TM,{b:"\\b([A-Za-z0-9_\\-]+)\\b"});return{cI:!1,k:{keyword:"$_COOKIE $_FILES $_GET $_GET_BINARY $_GET_RAW $_POST $_POST_BINARY $_POST_RAW $_SESSION $_SERVER codepoint codepoints segment segments codeunit codeunits sentence sentences trueWord trueWords paragraph after byte bytes english the until http forever descending using line real8 with seventh for stdout finally element word words fourth before black ninth sixth characters chars stderr uInt1 uInt1s uInt2 uInt2s stdin string lines relative rel any fifth items from middle mid at else of catch then third it file milliseconds seconds second secs sec int1 int1s int4 int4s internet int2 int2s normal text item last long detailed effective uInt4 uInt4s repeat end repeat URL in try into switch to words https token binfile each tenth as ticks tick system real4 by dateItems without char character ascending eighth whole dateTime numeric short first ftp integer abbreviated abbr abbrev private case while if",constant:"SIX TEN FORMFEED NINE ZERO NONE SPACE FOUR FALSE COLON CRLF PI COMMA ENDOFFILE EOF EIGHT FIVE QUOTE EMPTY ONE TRUE RETURN CR LINEFEED RIGHT BACKSLASH NULL SEVEN TAB THREE TWO six ten formfeed nine zero none space four false colon crlf pi comma endoffile eof eight five quote empty one true return cr linefeed right backslash null seven tab three two RIVERSION RISTATE FILE_READ_MODE FILE_WRITE_MODE FILE_WRITE_MODE DIR_WRITE_MODE FILE_READ_UMASK FILE_WRITE_UMASK DIR_READ_UMASK DIR_WRITE_UMASK",operator:"div mod wrap and or bitAnd bitNot bitOr bitXor among not in a an within contains ends with begins the keys of keys",built_in:"put abs acos aliasReference annuity arrayDecode arrayEncode asin atan atan2 average avg avgDev base64Decode base64Encode baseConvert binaryDecode binaryEncode byteOffset byteToNum cachedURL cachedURLs charToNum cipherNames codepointOffset codepointProperty codepointToNum codeunitOffset commandNames compound compress constantNames cos date dateFormat decompress directories diskSpace DNSServers exp exp1 exp2 exp10 extents files flushEvents folders format functionNames geometricMean global globals hasMemory harmonicMean hostAddress hostAddressToName hostName hostNameToAddress isNumber ISOToMac itemOffset keys len length libURLErrorData libUrlFormData libURLftpCommand libURLLastHTTPHeaders libURLLastRHHeaders libUrlMultipartFormAddPart libUrlMultipartFormData libURLVersion lineOffset ln ln1 localNames log log2 log10 longFilePath lower macToISO matchChunk matchText matrixMultiply max md5Digest median merge millisec millisecs millisecond milliseconds min monthNames nativeCharToNum normalizeText num number numToByte numToChar numToCodepoint numToNativeChar offset open openfiles openProcesses openProcessIDs openSockets paragraphOffset paramCount param params peerAddress pendingMessages platform popStdDev populationStandardDeviation populationVariance popVariance processID random randomBytes replaceText result revCreateXMLTree revCreateXMLTreeFromFile revCurrentRecord revCurrentRecordIsFirst revCurrentRecordIsLast revDatabaseColumnCount revDatabaseColumnIsNull revDatabaseColumnLengths revDatabaseColumnNames revDatabaseColumnNamed revDatabaseColumnNumbered revDatabaseColumnTypes revDatabaseConnectResult revDatabaseCursors revDatabaseID revDatabaseTableNames revDatabaseType revDataFromQuery revdb_closeCursor revdb_columnbynumber revdb_columncount revdb_columnisnull revdb_columnlengths revdb_columnnames revdb_columntypes revdb_commit revdb_connect revdb_connections revdb_connectionerr revdb_currentrecord revdb_cursorconnection revdb_cursorerr revdb_cursors revdb_dbtype revdb_disconnect revdb_execute revdb_iseof revdb_isbof revdb_movefirst revdb_movelast revdb_movenext revdb_moveprev revdb_query revdb_querylist revdb_recordcount revdb_rollback revdb_tablenames revGetDatabaseDriverPath revNumberOfRecords revOpenDatabase revOpenDatabases revQueryDatabase revQueryDatabaseBlob revQueryResult revQueryIsAtStart revQueryIsAtEnd revUnixFromMacPath revXMLAttribute revXMLAttributes revXMLAttributeValues revXMLChildContents revXMLChildNames revXMLCreateTreeFromFileWithNamespaces revXMLCreateTreeWithNamespaces revXMLDataFromXPathQuery revXMLEvaluateXPath revXMLFirstChild revXMLMatchingNode revXMLNextSibling revXMLNodeContents revXMLNumberOfChildren revXMLParent revXMLPreviousSibling revXMLRootNode revXMLRPC_CreateRequest revXMLRPC_Documents revXMLRPC_Error revXMLRPC_GetHost revXMLRPC_GetMethod revXMLRPC_GetParam revXMLText revXMLRPC_Execute revXMLRPC_GetParamCount revXMLRPC_GetParamNode revXMLRPC_GetParamType revXMLRPC_GetPath revXMLRPC_GetPort revXMLRPC_GetProtocol revXMLRPC_GetRequest revXMLRPC_GetResponse revXMLRPC_GetSocket revXMLTree revXMLTrees revXMLValidateDTD revZipDescribeItem revZipEnumerateItems revZipOpenArchives round sampVariance sec secs seconds sentenceOffset sha1Digest shell shortFilePath sin specialFolderPath sqrt standardDeviation statRound stdDev sum sysError systemVersion tan tempName textDecode textEncode tick ticks time to tokenOffset toLower toUpper transpose truewordOffset trunc uniDecode uniEncode upper URLDecode URLEncode URLStatus uuid value variableNames variance version waitDepth weekdayNames wordOffset xsltApplyStylesheet xsltApplyStylesheetFromFile xsltLoadStylesheet xsltLoadStylesheetFromFile add breakpoint cancel clear local variable file word line folder directory URL close socket process combine constant convert create new alias folder directory decrypt delete variable word line folder directory URL dispatch divide do encrypt filter get include intersect kill libURLDownloadToFile libURLFollowHttpRedirects libURLftpUpload libURLftpUploadFile libURLresetAll libUrlSetAuthCallback libURLSetCustomHTTPHeaders libUrlSetExpect100 libURLSetFTPListCommand libURLSetFTPMode libURLSetFTPStopTime libURLSetStatusCallback load multiply socket prepare process post seek rel relative read from process rename replace require resetAll resolve revAddXMLNode revAppendXML revCloseCursor revCloseDatabase revCommitDatabase revCopyFile revCopyFolder revCopyXMLNode revDeleteFolder revDeleteXMLNode revDeleteAllXMLTrees revDeleteXMLTree revExecuteSQL revGoURL revInsertXMLNode revMoveFolder revMoveToFirstRecord revMoveToLastRecord revMoveToNextRecord revMoveToPreviousRecord revMoveToRecord revMoveXMLNode revPutIntoXMLNode revRollBackDatabase revSetDatabaseDriverPath revSetXMLAttribute revXMLRPC_AddParam revXMLRPC_DeleteAllDocuments revXMLAddDTD revXMLRPC_Free revXMLRPC_FreeAll revXMLRPC_DeleteDocument revXMLRPC_DeleteParam revXMLRPC_SetHost revXMLRPC_SetMethod revXMLRPC_SetPort revXMLRPC_SetProtocol revXMLRPC_SetSocket revZipAddItemWithData revZipAddItemWithFile revZipAddUncompressedItemWithData revZipAddUncompressedItemWithFile revZipCancel revZipCloseArchive revZipDeleteItem revZipExtractItemToFile revZipExtractItemToVariable revZipSetProgressCallback revZipRenameItem revZipReplaceItemWithData revZipReplaceItemWithFile revZipOpenArchive send set sort split start stop subtract union unload wait write"},c:[r,{cN:"keyword",b:"\\bend\\sif\\b"},{cN:"function",bK:"function",e:"$",c:[r,o,e.ASM,e.QSM,e.BNM,e.CNM,a]},{cN:"function",bK:"end",e:"$",c:[o,a]},{cN:"command",bK:"command on",e:"$",c:[r,o,e.ASM,e.QSM,e.BNM,e.CNM,a]},{cN:"command",bK:"end",e:"$",c:[o,a]},{cN:"preprocessor",b:"<\\?rev|<\\?lc|<\\?livecode",r:10},{cN:"preprocessor",b:"<\\?"},{cN:"preprocessor",b:"\\?>"},e.ASM,e.QSM,e.BNM,e.CNM,a].concat(t),i:";$|^\\[|^="}}); \ No newline at end of file diff --git a/lib/highlight_js/assets/lang/livescript.js b/lib/highlight_js/assets/lang/livescript.js new file mode 100644 index 0000000000..72340804fb --- /dev/null +++ b/lib/highlight_js/assets/lang/livescript.js @@ -0,0 +1 @@ +hljs.registerLanguage("livescript",function(e){var t={keyword:"in if for while finally new do return else break catch instanceof throw try this switch continue typeof delete debugger case default function var with then unless until loop of by when and or is isnt not it that otherwise from to til fallthrough super case default function var void const let enum export import native __hasProp __extends __slice __bind __indexOf",literal:"true false null undefined yes no on off it that void",built_in:"npm require console print module global window document"},s="[A-Za-z$_](?:-[0-9A-Za-z$_]|[0-9A-Za-z$_])*",i=e.inherit(e.TM,{b:s}),n={cN:"subst",b:/#\{/,e:/}/,k:t},r={cN:"subst",b:/#[A-Za-z$_]/,e:/(?:\-[0-9A-Za-z$_]|[0-9A-Za-z$_])*/,k:t},c=[e.BNM,{cN:"number",b:"(\\b0[xX][a-fA-F0-9_]+)|(\\b\\d(\\d|_\\d)*(\\.(\\d(\\d|_\\d)*)?)?(_*[eE]([-+]\\d(_\\d|\\d)*)?)?[_a-z]*)",r:0,starts:{e:"(\\s*/)?",r:0}},{cN:"string",v:[{b:/'''/,e:/'''/,c:[e.BE]},{b:/'/,e:/'/,c:[e.BE]},{b:/"""/,e:/"""/,c:[e.BE,n,r]},{b:/"/,e:/"/,c:[e.BE,n,r]},{b:/\\/,e:/(\s|$)/,eE:!0}]},{cN:"pi",v:[{b:"//",e:"//[gim]*",c:[n,e.HCM]},{b:/\/(?![ *])(\\\/|.)*?\/[gim]*(?=\W|$)/}]},{cN:"property",b:"@"+s},{b:"``",e:"``",eB:!0,eE:!0,sL:"javascript"}];n.c=c;var a={cN:"params",b:"\\(",rB:!0,c:[{b:/\(/,e:/\)/,k:t,c:["self"].concat(c)}]};return{aliases:["ls"],k:t,i:/\/\*/,c:c.concat([e.C("\\/\\*","\\*\\/"),e.HCM,{cN:"function",c:[i,a],rB:!0,v:[{b:"("+s+"\\s*(?:=|:=)\\s*)?(\\(.*\\))?\\s*\\B\\->\\*?",e:"\\->\\*?"},{b:"("+s+"\\s*(?:=|:=)\\s*)?!?(\\(.*\\))?\\s*\\B[-~]{1,2}>\\*?",e:"[-~]{1,2}>\\*?"},{b:"("+s+"\\s*(?:=|:=)\\s*)?(\\(.*\\))?\\s*\\B!?[-~]{1,2}>\\*?",e:"!?[-~]{1,2}>\\*?"}]},{cN:"class",bK:"class",e:"$",i:/[:="\[\]]/,c:[{bK:"extends",eW:!0,i:/[:="\[\]]/,c:[i]},i]},{cN:"attribute",b:s+":",e:":",rB:!0,rE:!0,r:0}])}}); \ No newline at end of file diff --git a/lib/highlight_js/assets/lang/lua.js b/lib/highlight_js/assets/lang/lua.js new file mode 100644 index 0000000000..00cf60a27a --- /dev/null +++ b/lib/highlight_js/assets/lang/lua.js @@ -0,0 +1 @@ +hljs.registerLanguage("lua",function(e){var t="\\[=*\\[",a="\\]=*\\]",r={b:t,e:a,c:["self"]},n=[e.C("--(?!"+t+")","$"),e.C("--"+t,a,{c:[r],r:10})];return{l:e.UIR,k:{keyword:"and break do else elseif end false for if in local nil not or repeat return then true until while",built_in:"_G _VERSION assert collectgarbage dofile error getfenv getmetatable ipairs load loadfile loadstring module next pairs pcall print rawequal rawget rawset require select setfenv setmetatable tonumber tostring type unpack xpcall coroutine debug io math os package string table"},c:n.concat([{cN:"function",bK:"function",e:"\\)",c:[e.inherit(e.TM,{b:"([_a-zA-Z]\\w*\\.)*([_a-zA-Z]\\w*:)?[_a-zA-Z]\\w*"}),{cN:"params",b:"\\(",eW:!0,c:n}].concat(n)},e.CNM,e.ASM,e.QSM,{cN:"string",b:t,e:a,c:[r],r:5}])}}); \ No newline at end of file diff --git a/lib/highlight_js/assets/lang/makefile.js b/lib/highlight_js/assets/lang/makefile.js new file mode 100644 index 0000000000..8575486c0c --- /dev/null +++ b/lib/highlight_js/assets/lang/makefile.js @@ -0,0 +1 @@ +hljs.registerLanguage("makefile",function(e){var a={cN:"variable",b:/\$\(/,e:/\)/,c:[e.BE]};return{aliases:["mk","mak"],c:[e.HCM,{b:/^\w+\s*\W*=/,rB:!0,r:0,starts:{cN:"constant",e:/\s*\W*=/,eE:!0,starts:{e:/$/,r:0,c:[a]}}},{cN:"title",b:/^[\w]+:\s*$/},{cN:"phony",b:/^\.PHONY:/,e:/$/,k:".PHONY",l:/[\.\w]+/},{b:/^\t+/,e:/$/,r:0,c:[e.QSM,a]}]}}); \ No newline at end of file diff --git a/lib/highlight_js/assets/lang/markdown.js b/lib/highlight_js/assets/lang/markdown.js new file mode 100644 index 0000000000..521ab6f751 --- /dev/null +++ b/lib/highlight_js/assets/lang/markdown.js @@ -0,0 +1 @@ +hljs.registerLanguage("markdown",function(){return{aliases:["md","mkdown","mkd"],c:[{cN:"header",v:[{b:"^#{1,6}",e:"$"},{b:"^.+?\\n[=-]{2,}$"}]},{b:"<",e:">",sL:"xml",r:0},{cN:"bullet",b:"^([*+-]|(\\d+\\.))\\s+"},{cN:"strong",b:"[*_]{2}.+?[*_]{2}"},{cN:"emphasis",v:[{b:"\\*.+?\\*"},{b:"_.+?_",r:0}]},{cN:"blockquote",b:"^>\\s+",e:"$"},{cN:"code",v:[{b:"`.+?`"},{b:"^( {4}| )",e:"$",r:0}]},{cN:"horizontal_rule",b:"^[-\\*]{3,}",e:"$"},{b:"\\[.+?\\][\\(\\[].*?[\\)\\]]",rB:!0,c:[{cN:"link_label",b:"\\[",e:"\\]",eB:!0,rE:!0,r:0},{cN:"link_url",b:"\\]\\(",e:"\\)",eB:!0,eE:!0},{cN:"link_reference",b:"\\]\\[",e:"\\]",eB:!0,eE:!0}],r:10},{b:"^\\[.+\\]:",rB:!0,c:[{cN:"link_reference",b:"\\[",e:"\\]:",eB:!0,eE:!0,starts:{cN:"link_url",e:"$"}}]}]}}); \ No newline at end of file diff --git a/lib/highlight_js/assets/lang/mathematica.js b/lib/highlight_js/assets/lang/mathematica.js new file mode 100644 index 0000000000..4e3e612aa5 --- /dev/null +++ b/lib/highlight_js/assets/lang/mathematica.js @@ -0,0 +1,2 @@ +hljs.registerLanguage("mathematica",function(e){return{aliases:["mma"],l:"(\\$|\\b)"+e.IR+"\\b",k:"AbelianGroup Abort AbortKernels AbortProtect Above Abs Absolute AbsoluteCorrelation AbsoluteCorrelationFunction AbsoluteCurrentValue AbsoluteDashing AbsoluteFileName AbsoluteOptions AbsolutePointSize AbsoluteThickness AbsoluteTime AbsoluteTiming AccountingForm Accumulate Accuracy AccuracyGoal ActionDelay ActionMenu ActionMenuBox ActionMenuBoxOptions Active ActiveItem ActiveStyle AcyclicGraphQ AddOnHelpPath AddTo AdjacencyGraph AdjacencyList AdjacencyMatrix AdjustmentBox AdjustmentBoxOptions AdjustTimeSeriesForecast AffineTransform After AiryAi AiryAiPrime AiryAiZero AiryBi AiryBiPrime AiryBiZero AlgebraicIntegerQ AlgebraicNumber AlgebraicNumberDenominator AlgebraicNumberNorm AlgebraicNumberPolynomial AlgebraicNumberTrace AlgebraicRules AlgebraicRulesData Algebraics AlgebraicUnitQ Alignment AlignmentMarker AlignmentPoint All AllowedDimensions AllowGroupClose AllowInlineCells AllowKernelInitialization AllowReverseGroupClose AllowScriptLevelChange AlphaChannel AlternatingGroup AlternativeHypothesis Alternatives AmbientLight Analytic AnchoredSearch And AndersonDarlingTest AngerJ AngleBracket AngularGauge Animate AnimationCycleOffset AnimationCycleRepetitions AnimationDirection AnimationDisplayTime AnimationRate AnimationRepetitions AnimationRunning Animator AnimatorBox AnimatorBoxOptions AnimatorElements Annotation Annuity AnnuityDue Antialiasing Antisymmetric Apart ApartSquareFree Appearance AppearanceElements AppellF1 Append AppendTo Apply ArcCos ArcCosh ArcCot ArcCoth ArcCsc ArcCsch ArcSec ArcSech ArcSin ArcSinDistribution ArcSinh ArcTan ArcTanh Arg ArgMax ArgMin ArgumentCountQ ARIMAProcess ArithmeticGeometricMean ARMAProcess ARProcess Array ArrayComponents ArrayDepth ArrayFlatten ArrayPad ArrayPlot ArrayQ ArrayReshape ArrayRules Arrays Arrow Arrow3DBox ArrowBox Arrowheads AspectRatio AspectRatioFixed Assert Assuming Assumptions AstronomicalData Asynchronous AsynchronousTaskObject AsynchronousTasks AtomQ Attributes AugmentedSymmetricPolynomial AutoAction AutoDelete AutoEvaluateEvents AutoGeneratedPackage AutoIndent AutoIndentSpacings AutoItalicWords AutoloadPath AutoMatch Automatic AutomaticImageSize AutoMultiplicationSymbol AutoNumberFormatting AutoOpenNotebooks AutoOpenPalettes AutorunSequencing AutoScaling AutoScroll AutoSpacing AutoStyleOptions AutoStyleWords Axes AxesEdge AxesLabel AxesOrigin AxesStyle Axis BabyMonsterGroupB Back Background BackgroundTasksSettings Backslash Backsubstitution Backward Band BandpassFilter BandstopFilter BarabasiAlbertGraphDistribution BarChart BarChart3D BarLegend BarlowProschanImportance BarnesG BarOrigin BarSpacing BartlettHannWindow BartlettWindow BaseForm Baseline BaselinePosition BaseStyle BatesDistribution BattleLemarieWavelet Because BeckmannDistribution Beep Before Begin BeginDialogPacket BeginFrontEndInteractionPacket BeginPackage BellB BellY Below BenfordDistribution BeniniDistribution BenktanderGibratDistribution BenktanderWeibullDistribution BernoulliB BernoulliDistribution BernoulliGraphDistribution BernoulliProcess BernsteinBasis BesselFilterModel BesselI BesselJ BesselJZero BesselK BesselY BesselYZero Beta BetaBinomialDistribution BetaDistribution BetaNegativeBinomialDistribution BetaPrimeDistribution BetaRegularized BetweennessCentrality BezierCurve BezierCurve3DBox BezierCurve3DBoxOptions BezierCurveBox BezierCurveBoxOptions BezierFunction BilateralFilter Binarize BinaryFormat BinaryImageQ BinaryRead BinaryReadList BinaryWrite BinCounts BinLists Binomial BinomialDistribution BinomialProcess BinormalDistribution BiorthogonalSplineWavelet BipartiteGraphQ BirnbaumImportance BirnbaumSaundersDistribution BitAnd BitClear BitGet BitLength BitNot BitOr BitSet BitShiftLeft BitShiftRight BitXor Black BlackmanHarrisWindow BlackmanNuttallWindow BlackmanWindow Blank BlankForm BlankNullSequence BlankSequence Blend Block BlockRandom BlomqvistBeta BlomqvistBetaTest Blue Blur BodePlot BohmanWindow Bold Bookmarks Boole BooleanConsecutiveFunction BooleanConvert BooleanCountingFunction BooleanFunction BooleanGraph BooleanMaxterms BooleanMinimize BooleanMinterms Booleans BooleanTable BooleanVariables BorderDimensions BorelTannerDistribution Bottom BottomHatTransform BoundaryStyle Bounds Box BoxBaselineShift BoxData BoxDimensions Boxed Boxes BoxForm BoxFormFormatTypes BoxFrame BoxID BoxMargins BoxMatrix BoxRatios BoxRotation BoxRotationPoint BoxStyle BoxWhiskerChart Bra BracketingBar BraKet BrayCurtisDistance BreadthFirstScan Break Brown BrownForsytheTest BrownianBridgeProcess BrowserCategory BSplineBasis BSplineCurve BSplineCurve3DBox BSplineCurveBox BSplineCurveBoxOptions BSplineFunction BSplineSurface BSplineSurface3DBox BubbleChart BubbleChart3D BubbleScale BubbleSizes BulletGauge BusinessDayQ ButterflyGraph ButterworthFilterModel Button ButtonBar ButtonBox ButtonBoxOptions ButtonCell ButtonContents ButtonData ButtonEvaluator ButtonExpandable ButtonFrame ButtonFunction ButtonMargins ButtonMinHeight ButtonNote ButtonNotebook ButtonSource ButtonStyle ButtonStyleMenuListing Byte ByteCount ByteOrdering C CachedValue CacheGraphics CalendarData CalendarType CallPacket CanberraDistance Cancel CancelButton CandlestickChart Cap CapForm CapitalDifferentialD CardinalBSplineBasis CarmichaelLambda Cases Cashflow Casoratian Catalan CatalanNumber Catch CauchyDistribution CauchyWindow CayleyGraph CDF CDFDeploy CDFInformation CDFWavelet Ceiling Cell CellAutoOverwrite CellBaseline CellBoundingBox CellBracketOptions CellChangeTimes CellContents CellContext CellDingbat CellDynamicExpression CellEditDuplicate CellElementsBoundingBox CellElementSpacings CellEpilog CellEvaluationDuplicate CellEvaluationFunction CellEventActions CellFrame CellFrameColor CellFrameLabelMargins CellFrameLabels CellFrameMargins CellGroup CellGroupData CellGrouping CellGroupingRules CellHorizontalScrolling CellID CellLabel CellLabelAutoDelete CellLabelMargins CellLabelPositioning CellMargins CellObject CellOpen CellPrint CellProlog Cells CellSize CellStyle CellTags CellularAutomaton CensoredDistribution Censoring Center CenterDot CentralMoment CentralMomentGeneratingFunction CForm ChampernowneNumber ChanVeseBinarize Character CharacterEncoding CharacterEncodingsPath CharacteristicFunction CharacteristicPolynomial CharacterRange Characters ChartBaseStyle ChartElementData ChartElementDataFunction ChartElementFunction ChartElements ChartLabels ChartLayout ChartLegends ChartStyle Chebyshev1FilterModel Chebyshev2FilterModel ChebyshevDistance ChebyshevT ChebyshevU Check CheckAbort CheckAll Checkbox CheckboxBar CheckboxBox CheckboxBoxOptions ChemicalData ChessboardDistance ChiDistribution ChineseRemainder ChiSquareDistribution ChoiceButtons ChoiceDialog CholeskyDecomposition Chop Circle CircleBox CircleDot CircleMinus CirclePlus CircleTimes CirculantGraph CityData Clear ClearAll ClearAttributes ClearSystemCache ClebschGordan ClickPane Clip ClipboardNotebook ClipFill ClippingStyle ClipPlanes ClipRange Clock ClockGauge ClockwiseContourIntegral Close Closed CloseKernels ClosenessCentrality Closing ClosingAutoSave ClosingEvent ClusteringComponents CMYKColor Coarse Coefficient CoefficientArrays CoefficientDomain CoefficientList CoefficientRules CoifletWavelet Collect Colon ColonForm ColorCombine ColorConvert ColorData ColorDataFunction ColorFunction ColorFunctionScaling Colorize ColorNegate ColorOutput ColorProfileData ColorQuantize ColorReplace ColorRules ColorSelectorSettings ColorSeparate ColorSetter ColorSetterBox ColorSetterBoxOptions ColorSlider ColorSpace Column ColumnAlignments ColumnBackgrounds ColumnForm ColumnLines ColumnsEqual ColumnSpacings ColumnWidths CommonDefaultFormatTypes Commonest CommonestFilter CommonUnits CommunityBoundaryStyle CommunityGraphPlot CommunityLabels CommunityRegionStyle CompatibleUnitQ CompilationOptions CompilationTarget Compile Compiled CompiledFunction Complement CompleteGraph CompleteGraphQ CompleteKaryTree CompletionsListPacket Complex Complexes ComplexExpand ComplexInfinity ComplexityFunction ComponentMeasurements ComponentwiseContextMenu Compose ComposeList ComposeSeries Composition CompoundExpression CompoundPoissonDistribution CompoundPoissonProcess CompoundRenewalProcess Compress CompressedData Condition ConditionalExpression Conditioned Cone ConeBox ConfidenceLevel ConfidenceRange ConfidenceTransform ConfigurationPath Congruent Conjugate ConjugateTranspose Conjunction Connect ConnectedComponents ConnectedGraphQ ConnesWindow ConoverTest ConsoleMessage ConsoleMessagePacket ConsolePrint Constant ConstantArray Constants ConstrainedMax ConstrainedMin ContentPadding ContentsBoundingBox ContentSelectable ContentSize Context ContextMenu Contexts ContextToFilename ContextToFileName Continuation Continue ContinuedFraction ContinuedFractionK ContinuousAction ContinuousMarkovProcess ContinuousTimeModelQ ContinuousWaveletData ContinuousWaveletTransform ContourDetect ContourGraphics ContourIntegral ContourLabels ContourLines ContourPlot ContourPlot3D Contours ContourShading ContourSmoothing ContourStyle ContraharmonicMean Control ControlActive ControlAlignment ControllabilityGramian ControllabilityMatrix ControllableDecomposition ControllableModelQ ControllerDuration ControllerInformation ControllerInformationData ControllerLinking ControllerManipulate ControllerMethod ControllerPath ControllerState ControlPlacement ControlsRendering ControlType Convergents ConversionOptions ConversionRules ConvertToBitmapPacket ConvertToPostScript ConvertToPostScriptPacket Convolve ConwayGroupCo1 ConwayGroupCo2 ConwayGroupCo3 CoordinateChartData CoordinatesToolOptions CoordinateTransform CoordinateTransformData CoprimeQ Coproduct CopulaDistribution Copyable CopyDirectory CopyFile CopyTag CopyToClipboard CornerFilter CornerNeighbors Correlation CorrelationDistance CorrelationFunction CorrelationTest Cos Cosh CoshIntegral CosineDistance CosineWindow CosIntegral Cot Coth Count CounterAssignments CounterBox CounterBoxOptions CounterClockwiseContourIntegral CounterEvaluator CounterFunction CounterIncrements CounterStyle CounterStyleMenuListing CountRoots CountryData Covariance CovarianceEstimatorFunction CovarianceFunction CoxianDistribution CoxIngersollRossProcess CoxModel CoxModelFit CramerVonMisesTest CreateArchive CreateDialog CreateDirectory CreateDocument CreateIntermediateDirectories CreatePalette CreatePalettePacket CreateScheduledTask CreateTemporary CreateWindow CriticalityFailureImportance CriticalitySuccessImportance CriticalSection Cross CrossingDetect CrossMatrix Csc Csch CubeRoot Cubics Cuboid CuboidBox Cumulant CumulantGeneratingFunction Cup CupCap Curl CurlyDoubleQuote CurlyQuote CurrentImage CurrentlySpeakingPacket CurrentValue CurvatureFlowFilter CurveClosed Cyan CycleGraph CycleIndexPolynomial Cycles CyclicGroup Cyclotomic Cylinder CylinderBox CylindricalDecomposition D DagumDistribution DamerauLevenshteinDistance DampingFactor Darker Dashed Dashing DataCompression DataDistribution DataRange DataReversed Date DateDelimiters DateDifference DateFunction DateList DateListLogPlot DateListPlot DatePattern DatePlus DateRange DateString DateTicksFormat DaubechiesWavelet DavisDistribution DawsonF DayCount DayCountConvention DayMatchQ DayName DayPlus DayRange DayRound DeBruijnGraph Debug DebugTag Decimal DeclareKnownSymbols DeclarePackage Decompose Decrement DedekindEta Default DefaultAxesStyle DefaultBaseStyle DefaultBoxStyle DefaultButton DefaultColor DefaultControlPlacement DefaultDuplicateCellStyle DefaultDuration DefaultElement DefaultFaceGridsStyle DefaultFieldHintStyle DefaultFont DefaultFontProperties DefaultFormatType DefaultFormatTypeForStyle DefaultFrameStyle DefaultFrameTicksStyle DefaultGridLinesStyle DefaultInlineFormatType DefaultInputFormatType DefaultLabelStyle DefaultMenuStyle DefaultNaturalLanguage DefaultNewCellStyle DefaultNewInlineCellStyle DefaultNotebook DefaultOptions DefaultOutputFormatType DefaultStyle DefaultStyleDefinitions DefaultTextFormatType DefaultTextInlineFormatType DefaultTicksStyle DefaultTooltipStyle DefaultValues Defer DefineExternal DefineInputStreamMethod DefineOutputStreamMethod Definition Degree DegreeCentrality DegreeGraphDistribution DegreeLexicographic DegreeReverseLexicographic Deinitialization Del Deletable Delete DeleteBorderComponents DeleteCases DeleteContents DeleteDirectory DeleteDuplicates DeleteFile DeleteSmallComponents DeleteWithContents DeletionWarning Delimiter DelimiterFlashTime DelimiterMatching Delimiters Denominator DensityGraphics DensityHistogram DensityPlot DependentVariables Deploy Deployed Depth DepthFirstScan Derivative DerivativeFilter DescriptorStateSpace DesignMatrix Det DGaussianWavelet DiacriticalPositioning Diagonal DiagonalMatrix Dialog DialogIndent DialogInput DialogLevel DialogNotebook DialogProlog DialogReturn DialogSymbols Diamond DiamondMatrix DiceDissimilarity DictionaryLookup DifferenceDelta DifferenceOrder DifferenceRoot DifferenceRootReduce Differences DifferentialD DifferentialRoot DifferentialRootReduce DifferentiatorFilter DigitBlock DigitBlockMinimum DigitCharacter DigitCount DigitQ DihedralGroup Dilation Dimensions DiracComb DiracDelta DirectedEdge DirectedEdges DirectedGraph DirectedGraphQ DirectedInfinity Direction Directive Directory DirectoryName DirectoryQ DirectoryStack DirichletCharacter DirichletConvolve DirichletDistribution DirichletL DirichletTransform DirichletWindow DisableConsolePrintPacket DiscreteChirpZTransform DiscreteConvolve DiscreteDelta DiscreteHadamardTransform DiscreteIndicator DiscreteLQEstimatorGains DiscreteLQRegulatorGains DiscreteLyapunovSolve DiscreteMarkovProcess DiscretePlot DiscretePlot3D DiscreteRatio DiscreteRiccatiSolve DiscreteShift DiscreteTimeModelQ DiscreteUniformDistribution DiscreteVariables DiscreteWaveletData DiscreteWaveletPacketTransform DiscreteWaveletTransform Discriminant Disjunction Disk DiskBox DiskMatrix Dispatch DispersionEstimatorFunction Display DisplayAllSteps DisplayEndPacket DisplayFlushImagePacket DisplayForm DisplayFunction DisplayPacket DisplayRules DisplaySetSizePacket DisplayString DisplayTemporary DisplayWith DisplayWithRef DisplayWithVariable DistanceFunction DistanceTransform Distribute Distributed DistributedContexts DistributeDefinitions DistributionChart DistributionDomain DistributionFitTest DistributionParameterAssumptions DistributionParameterQ Dithering Div Divergence Divide DivideBy Dividers Divisible Divisors DivisorSigma DivisorSum DMSList DMSString Do DockedCells DocumentNotebook DominantColors DOSTextFormat Dot DotDashed DotEqual Dotted DoubleBracketingBar DoubleContourIntegral DoubleDownArrow DoubleLeftArrow DoubleLeftRightArrow DoubleLeftTee DoubleLongLeftArrow DoubleLongLeftRightArrow DoubleLongRightArrow DoubleRightArrow DoubleRightTee DoubleUpArrow DoubleUpDownArrow DoubleVerticalBar DoublyInfinite Down DownArrow DownArrowBar DownArrowUpArrow DownLeftRightVector DownLeftTeeVector DownLeftVector DownLeftVectorBar DownRightTeeVector DownRightVector DownRightVectorBar Downsample DownTee DownTeeArrow DownValues DragAndDrop DrawEdges DrawFrontFaces DrawHighlighted Drop DSolve Dt DualLinearProgramming DualSystemsModel DumpGet DumpSave DuplicateFreeQ Dynamic DynamicBox DynamicBoxOptions DynamicEvaluationTimeout DynamicLocation DynamicModule DynamicModuleBox DynamicModuleBoxOptions DynamicModuleParent DynamicModuleValues DynamicName DynamicNamespace DynamicReference DynamicSetting DynamicUpdating DynamicWrapper DynamicWrapperBox DynamicWrapperBoxOptions E EccentricityCentrality EdgeAdd EdgeBetweennessCentrality EdgeCapacity EdgeCapForm EdgeColor EdgeConnectivity EdgeCost EdgeCount EdgeCoverQ EdgeDashing EdgeDelete EdgeDetect EdgeForm EdgeIndex EdgeJoinForm EdgeLabeling EdgeLabels EdgeLabelStyle EdgeList EdgeOpacity EdgeQ EdgeRenderingFunction EdgeRules EdgeShapeFunction EdgeStyle EdgeThickness EdgeWeight Editable EditButtonSettings EditCellTagsSettings EditDistance EffectiveInterest Eigensystem Eigenvalues EigenvectorCentrality Eigenvectors Element ElementData Eliminate EliminationOrder EllipticE EllipticExp EllipticExpPrime EllipticF EllipticFilterModel EllipticK EllipticLog EllipticNomeQ EllipticPi EllipticReducedHalfPeriods EllipticTheta EllipticThetaPrime EmitSound EmphasizeSyntaxErrors EmpiricalDistribution Empty EmptyGraphQ EnableConsolePrintPacket Enabled Encode End EndAdd EndDialogPacket EndFrontEndInteractionPacket EndOfFile EndOfLine EndOfString EndPackage EngineeringForm Enter EnterExpressionPacket EnterTextPacket Entropy EntropyFilter Environment Epilog Equal EqualColumns EqualRows EqualTilde EquatedTo Equilibrium EquirippleFilterKernel Equivalent Erf Erfc Erfi ErlangB ErlangC ErlangDistribution Erosion ErrorBox ErrorBoxOptions ErrorNorm ErrorPacket ErrorsDialogSettings EstimatedDistribution EstimatedProcess EstimatorGains EstimatorRegulator EuclideanDistance EulerE EulerGamma EulerianGraphQ EulerPhi Evaluatable Evaluate Evaluated EvaluatePacket EvaluationCell EvaluationCompletionAction EvaluationElements EvaluationMode EvaluationMonitor EvaluationNotebook EvaluationObject EvaluationOrder Evaluator EvaluatorNames EvenQ EventData EventEvaluator EventHandler EventHandlerTag EventLabels ExactBlackmanWindow ExactNumberQ ExactRootIsolation ExampleData Except ExcludedForms ExcludePods Exclusions ExclusionsStyle Exists Exit ExitDialog Exp Expand ExpandAll ExpandDenominator ExpandFileName ExpandNumerator Expectation ExpectationE ExpectedValue ExpGammaDistribution ExpIntegralE ExpIntegralEi Exponent ExponentFunction ExponentialDistribution ExponentialFamily ExponentialGeneratingFunction ExponentialMovingAverage ExponentialPowerDistribution ExponentPosition ExponentStep Export ExportAutoReplacements ExportPacket ExportString Expression ExpressionCell ExpressionPacket ExpToTrig ExtendedGCD Extension ExtentElementFunction ExtentMarkers ExtentSize ExternalCall ExternalDataCharacterEncoding Extract ExtractArchive ExtremeValueDistribution FaceForm FaceGrids FaceGridsStyle Factor FactorComplete Factorial Factorial2 FactorialMoment FactorialMomentGeneratingFunction FactorialPower FactorInteger FactorList FactorSquareFree FactorSquareFreeList FactorTerms FactorTermsList Fail FailureDistribution False FARIMAProcess FEDisableConsolePrintPacket FeedbackSector FeedbackSectorStyle FeedbackType FEEnableConsolePrintPacket Fibonacci FieldHint FieldHintStyle FieldMasked FieldSize File FileBaseName FileByteCount FileDate FileExistsQ FileExtension FileFormat FileHash FileInformation FileName FileNameDepth FileNameDialogSettings FileNameDrop FileNameJoin FileNames FileNameSetter FileNameSplit FileNameTake FilePrint FileType FilledCurve FilledCurveBox Filling FillingStyle FillingTransform FilterRules FinancialBond FinancialData FinancialDerivative FinancialIndicator Find FindArgMax FindArgMin FindClique FindClusters FindCurvePath FindDistributionParameters FindDivisions FindEdgeCover FindEdgeCut FindEulerianCycle FindFaces FindFile FindFit FindGeneratingFunction FindGeoLocation FindGeometricTransform FindGraphCommunities FindGraphIsomorphism FindGraphPartition FindHamiltonianCycle FindIndependentEdgeSet FindIndependentVertexSet FindInstance FindIntegerNullVector FindKClan FindKClique FindKClub FindKPlex FindLibrary FindLinearRecurrence FindList FindMaximum FindMaximumFlow FindMaxValue FindMinimum FindMinimumCostFlow FindMinimumCut FindMinValue FindPermutation FindPostmanTour FindProcessParameters FindRoot FindSequenceFunction FindSettings FindShortestPath FindShortestTour FindThreshold FindVertexCover FindVertexCut Fine FinishDynamic FiniteAbelianGroupCount FiniteGroupCount FiniteGroupData First FirstPassageTimeDistribution FischerGroupFi22 FischerGroupFi23 FischerGroupFi24Prime FisherHypergeometricDistribution FisherRatioTest FisherZDistribution Fit FitAll FittedModel FixedPoint FixedPointList FlashSelection Flat Flatten FlattenAt FlatTopWindow FlipView Floor FlushPrintOutputPacket Fold FoldList Font FontColor FontFamily FontForm FontName FontOpacity FontPostScriptName FontProperties FontReencoding FontSize FontSlant FontSubstitutions FontTracking FontVariations FontWeight For ForAll Format FormatRules FormatType FormatTypeAutoConvert FormatValues FormBox FormBoxOptions FortranForm Forward ForwardBackward Fourier FourierCoefficient FourierCosCoefficient FourierCosSeries FourierCosTransform FourierDCT FourierDCTFilter FourierDCTMatrix FourierDST FourierDSTMatrix FourierMatrix FourierParameters FourierSequenceTransform FourierSeries FourierSinCoefficient FourierSinSeries FourierSinTransform FourierTransform FourierTrigSeries FractionalBrownianMotionProcess FractionalPart FractionBox FractionBoxOptions FractionLine Frame FrameBox FrameBoxOptions Framed FrameInset FrameLabel Frameless FrameMargins FrameStyle FrameTicks FrameTicksStyle FRatioDistribution FrechetDistribution FreeQ FrequencySamplingFilterKernel FresnelC FresnelS Friday FrobeniusNumber FrobeniusSolve FromCharacterCode FromCoefficientRules FromContinuedFraction FromDate FromDigits FromDMS Front FrontEndDynamicExpression FrontEndEventActions FrontEndExecute FrontEndObject FrontEndResource FrontEndResourceString FrontEndStackSize FrontEndToken FrontEndTokenExecute FrontEndValueCache FrontEndVersion FrontFaceColor FrontFaceOpacity Full FullAxes FullDefinition FullForm FullGraphics FullOptions FullSimplify Function FunctionExpand FunctionInterpolation FunctionSpace FussellVeselyImportance GaborFilter GaborMatrix GaborWavelet GainMargins GainPhaseMargins Gamma GammaDistribution GammaRegularized GapPenalty Gather GatherBy GaugeFaceElementFunction GaugeFaceStyle GaugeFrameElementFunction GaugeFrameSize GaugeFrameStyle GaugeLabels GaugeMarkers GaugeStyle GaussianFilter GaussianIntegers GaussianMatrix GaussianWindow GCD GegenbauerC General GeneralizedLinearModelFit GenerateConditions GeneratedCell GeneratedParameters GeneratingFunction Generic GenericCylindricalDecomposition GenomeData GenomeLookup GeodesicClosing GeodesicDilation GeodesicErosion GeodesicOpening GeoDestination GeodesyData GeoDirection GeoDistance GeoGridPosition GeometricBrownianMotionProcess GeometricDistribution GeometricMean GeometricMeanFilter GeometricTransformation GeometricTransformation3DBox GeometricTransformation3DBoxOptions GeometricTransformationBox GeometricTransformationBoxOptions GeoPosition GeoPositionENU GeoPositionXYZ GeoProjectionData GestureHandler GestureHandlerTag Get GetBoundingBoxSizePacket GetContext GetEnvironment GetFileName GetFrontEndOptionsDataPacket GetLinebreakInformationPacket GetMenusPacket GetPageBreakInformationPacket Glaisher GlobalClusteringCoefficient GlobalPreferences GlobalSession Glow GoldenRatio GompertzMakehamDistribution GoodmanKruskalGamma GoodmanKruskalGammaTest Goto Grad Gradient GradientFilter GradientOrientationFilter Graph GraphAssortativity GraphCenter GraphComplement GraphData GraphDensity GraphDiameter GraphDifference GraphDisjointUnion GraphDistance GraphDistanceMatrix GraphElementData GraphEmbedding GraphHighlight GraphHighlightStyle GraphHub Graphics Graphics3D Graphics3DBox Graphics3DBoxOptions GraphicsArray GraphicsBaseline GraphicsBox GraphicsBoxOptions GraphicsColor GraphicsColumn GraphicsComplex GraphicsComplex3DBox GraphicsComplex3DBoxOptions GraphicsComplexBox GraphicsComplexBoxOptions GraphicsContents GraphicsData GraphicsGrid GraphicsGridBox GraphicsGroup GraphicsGroup3DBox GraphicsGroup3DBoxOptions GraphicsGroupBox GraphicsGroupBoxOptions GraphicsGrouping GraphicsHighlightColor GraphicsRow GraphicsSpacing GraphicsStyle GraphIntersection GraphLayout GraphLinkEfficiency GraphPeriphery GraphPlot GraphPlot3D GraphPower GraphPropertyDistribution GraphQ GraphRadius GraphReciprocity GraphRoot GraphStyle GraphUnion Gray GrayLevel GreatCircleDistance Greater GreaterEqual GreaterEqualLess GreaterFullEqual GreaterGreater GreaterLess GreaterSlantEqual GreaterTilde Green Grid GridBaseline GridBox GridBoxAlignment GridBoxBackground GridBoxDividers GridBoxFrame GridBoxItemSize GridBoxItemStyle GridBoxOptions GridBoxSpacings GridCreationSettings GridDefaultElement GridElementStyleOptions GridFrame GridFrameMargins GridGraph GridLines GridLinesStyle GroebnerBasis GroupActionBase GroupCentralizer GroupElementFromWord GroupElementPosition GroupElementQ GroupElements GroupElementToWord GroupGenerators GroupMultiplicationTable GroupOrbits GroupOrder GroupPageBreakWithin GroupSetwiseStabilizer GroupStabilizer GroupStabilizerChain Gudermannian GumbelDistribution HaarWavelet HadamardMatrix HalfNormalDistribution HamiltonianGraphQ HammingDistance HammingWindow HankelH1 HankelH2 HankelMatrix HannPoissonWindow HannWindow HaradaNortonGroupHN HararyGraph HarmonicMean HarmonicMeanFilter HarmonicNumber Hash HashTable Haversine HazardFunction Head HeadCompose Heads HeavisideLambda HeavisidePi HeavisideTheta HeldGroupHe HeldPart HelpBrowserLookup HelpBrowserNotebook HelpBrowserSettings HermiteDecomposition HermiteH HermitianMatrixQ HessenbergDecomposition Hessian HexadecimalCharacter Hexahedron HexahedronBox HexahedronBoxOptions HiddenSurface HighlightGraph HighlightImage HighpassFilter HigmanSimsGroupHS HilbertFilter HilbertMatrix Histogram Histogram3D HistogramDistribution HistogramList HistogramTransform HistogramTransformInterpolation HitMissTransform HITSCentrality HodgeDual HoeffdingD HoeffdingDTest Hold HoldAll HoldAllComplete HoldComplete HoldFirst HoldForm HoldPattern HoldRest HolidayCalendar HomeDirectory HomePage Horizontal HorizontalForm HorizontalGauge HorizontalScrollPosition HornerForm HotellingTSquareDistribution HoytDistribution HTMLSave Hue HumpDownHump HumpEqual HurwitzLerchPhi HurwitzZeta HyperbolicDistribution HypercubeGraph HyperexponentialDistribution Hyperfactorial Hypergeometric0F1 Hypergeometric0F1Regularized Hypergeometric1F1 Hypergeometric1F1Regularized Hypergeometric2F1 Hypergeometric2F1Regularized HypergeometricDistribution HypergeometricPFQ HypergeometricPFQRegularized HypergeometricU Hyperlink HyperlinkCreationSettings Hyphenation HyphenationOptions HypoexponentialDistribution HypothesisTestData I Identity IdentityMatrix If IgnoreCase Im Image Image3D Image3DSlices ImageAccumulate ImageAdd ImageAdjust ImageAlign ImageApply ImageAspectRatio ImageAssemble ImageCache ImageCacheValid ImageCapture ImageChannels ImageClip ImageColorSpace ImageCompose ImageConvolve ImageCooccurrence ImageCorners ImageCorrelate ImageCorrespondingPoints ImageCrop ImageData ImageDataPacket ImageDeconvolve ImageDemosaic ImageDifference ImageDimensions ImageDistance ImageEffect ImageFeatureTrack ImageFileApply ImageFileFilter ImageFileScan ImageFilter ImageForestingComponents ImageForwardTransformation ImageHistogram ImageKeypoints ImageLevels ImageLines ImageMargins ImageMarkers ImageMeasurements ImageMultiply ImageOffset ImagePad ImagePadding ImagePartition ImagePeriodogram ImagePerspectiveTransformation ImageQ ImageRangeCache ImageReflect ImageRegion ImageResize ImageResolution ImageRotate ImageRotated ImageScaled ImageScan ImageSize ImageSizeAction ImageSizeCache ImageSizeMultipliers ImageSizeRaw ImageSubtract ImageTake ImageTransformation ImageTrim ImageType ImageValue ImageValuePositions Implies Import ImportAutoReplacements ImportString ImprovementImportance In IncidenceGraph IncidenceList IncidenceMatrix IncludeConstantBasis IncludeFileExtension IncludePods IncludeSingularTerm Increment Indent IndentingNewlineSpacings IndentMaxFraction IndependenceTest IndependentEdgeSetQ IndependentUnit IndependentVertexSetQ Indeterminate IndexCreationOptions Indexed IndexGraph IndexTag Inequality InexactNumberQ InexactNumbers Infinity Infix Information Inherited InheritScope Initialization InitializationCell InitializationCellEvaluation InitializationCellWarning InlineCounterAssignments InlineCounterIncrements InlineRules Inner Inpaint Input InputAliases InputAssumptions InputAutoReplacements InputField InputFieldBox InputFieldBoxOptions InputForm InputGrouping InputNamePacket InputNotebook InputPacket InputSettings InputStream InputString InputStringPacket InputToBoxFormPacket Insert InsertionPointObject InsertResults Inset Inset3DBox Inset3DBoxOptions InsetBox InsetBoxOptions Install InstallService InString Integer IntegerDigits IntegerExponent IntegerLength IntegerPart IntegerPartitions IntegerQ Integers IntegerString Integral Integrate Interactive InteractiveTradingChart Interlaced Interleaving InternallyBalancedDecomposition InterpolatingFunction InterpolatingPolynomial Interpolation InterpolationOrder InterpolationPoints InterpolationPrecision Interpretation InterpretationBox InterpretationBoxOptions InterpretationFunction InterpretTemplate InterquartileRange Interrupt InterruptSettings Intersection Interval IntervalIntersection IntervalMemberQ IntervalUnion Inverse InverseBetaRegularized InverseCDF InverseChiSquareDistribution InverseContinuousWaveletTransform InverseDistanceTransform InverseEllipticNomeQ InverseErf InverseErfc InverseFourier InverseFourierCosTransform InverseFourierSequenceTransform InverseFourierSinTransform InverseFourierTransform InverseFunction InverseFunctions InverseGammaDistribution InverseGammaRegularized InverseGaussianDistribution InverseGudermannian InverseHaversine InverseJacobiCD InverseJacobiCN InverseJacobiCS InverseJacobiDC InverseJacobiDN InverseJacobiDS InverseJacobiNC InverseJacobiND InverseJacobiNS InverseJacobiSC InverseJacobiSD InverseJacobiSN InverseLaplaceTransform InversePermutation InverseRadon InverseSeries InverseSurvivalFunction InverseWaveletTransform InverseWeierstrassP InverseZTransform Invisible InvisibleApplication InvisibleTimes IrreduciblePolynomialQ IsolatingInterval IsomorphicGraphQ IsotopeData Italic Item ItemBox ItemBoxOptions ItemSize ItemStyle ItoProcess JaccardDissimilarity JacobiAmplitude Jacobian JacobiCD JacobiCN JacobiCS JacobiDC JacobiDN JacobiDS JacobiNC JacobiND JacobiNS JacobiP JacobiSC JacobiSD JacobiSN JacobiSymbol JacobiZeta JankoGroupJ1 JankoGroupJ2 JankoGroupJ3 JankoGroupJ4 JarqueBeraALMTest JohnsonDistribution Join Joined JoinedCurve JoinedCurveBox JoinForm JordanDecomposition JordanModelDecomposition K KagiChart KaiserBesselWindow KaiserWindow KalmanEstimator KalmanFilter KarhunenLoeveDecomposition KaryTree KatzCentrality KCoreComponents KDistribution KelvinBei KelvinBer KelvinKei KelvinKer KendallTau KendallTauTest KernelExecute KernelMixtureDistribution KernelObject Kernels Ket Khinchin KirchhoffGraph KirchhoffMatrix KleinInvariantJ KnightTourGraph KnotData KnownUnitQ KolmogorovSmirnovTest KroneckerDelta KroneckerModelDecomposition KroneckerProduct KroneckerSymbol KuiperTest KumaraswamyDistribution Kurtosis KuwaharaFilter Label Labeled LabeledSlider LabelingFunction LabelStyle LaguerreL LambdaComponents LambertW LanczosWindow LandauDistribution Language LanguageCategory LaplaceDistribution LaplaceTransform Laplacian LaplacianFilter LaplacianGaussianFilter Large Larger Last Latitude LatitudeLongitude LatticeData LatticeReduce Launch LaunchKernels LayeredGraphPlot LayerSizeFunction LayoutInformation LCM LeafCount LeapYearQ LeastSquares LeastSquaresFilterKernel Left LeftArrow LeftArrowBar LeftArrowRightArrow LeftDownTeeVector LeftDownVector LeftDownVectorBar LeftRightArrow LeftRightVector LeftTee LeftTeeArrow LeftTeeVector LeftTriangle LeftTriangleBar LeftTriangleEqual LeftUpDownVector LeftUpTeeVector LeftUpVector LeftUpVectorBar LeftVector LeftVectorBar LegendAppearance Legended LegendFunction LegendLabel LegendLayout LegendMargins LegendMarkers LegendMarkerSize LegendreP LegendreQ LegendreType Length LengthWhile LerchPhi Less LessEqual LessEqualGreater LessFullEqual LessGreater LessLess LessSlantEqual LessTilde LetterCharacter LetterQ Level LeveneTest LeviCivitaTensor LevyDistribution Lexicographic LibraryFunction LibraryFunctionError LibraryFunctionInformation LibraryFunctionLoad LibraryFunctionUnload LibraryLoad LibraryUnload LicenseID LiftingFilterData LiftingWaveletTransform LightBlue LightBrown LightCyan Lighter LightGray LightGreen Lighting LightingAngle LightMagenta LightOrange LightPink LightPurple LightRed LightSources LightYellow Likelihood Limit LimitsPositioning LimitsPositioningTokens LindleyDistribution Line Line3DBox LinearFilter LinearFractionalTransform LinearModelFit LinearOffsetFunction LinearProgramming LinearRecurrence LinearSolve LinearSolveFunction LineBox LineBreak LinebreakAdjustments LineBreakChart LineBreakWithin LineColor LineForm LineGraph LineIndent LineIndentMaxFraction LineIntegralConvolutionPlot LineIntegralConvolutionScale LineLegend LineOpacity LineSpacing LineWrapParts LinkActivate LinkClose LinkConnect LinkConnectedQ LinkCreate LinkError LinkFlush LinkFunction LinkHost LinkInterrupt LinkLaunch LinkMode LinkObject LinkOpen LinkOptions LinkPatterns LinkProtocol LinkRead LinkReadHeld LinkReadyQ Links LinkWrite LinkWriteHeld LiouvilleLambda List Listable ListAnimate ListContourPlot ListContourPlot3D ListConvolve ListCorrelate ListCurvePathPlot ListDeconvolve ListDensityPlot Listen ListFourierSequenceTransform ListInterpolation ListLineIntegralConvolutionPlot ListLinePlot ListLogLinearPlot ListLogLogPlot ListLogPlot ListPicker ListPickerBox ListPickerBoxBackground ListPickerBoxOptions ListPlay ListPlot ListPlot3D ListPointPlot3D ListPolarPlot ListQ ListStreamDensityPlot ListStreamPlot ListSurfacePlot3D ListVectorDensityPlot ListVectorPlot ListVectorPlot3D ListZTransform Literal LiteralSearch LocalClusteringCoefficient LocalizeVariables LocationEquivalenceTest LocationTest Locator LocatorAutoCreate LocatorBox LocatorBoxOptions LocatorCentering LocatorPane LocatorPaneBox LocatorPaneBoxOptions LocatorRegion Locked Log Log10 Log2 LogBarnesG LogGamma LogGammaDistribution LogicalExpand LogIntegral LogisticDistribution LogitModelFit LogLikelihood LogLinearPlot LogLogisticDistribution LogLogPlot LogMultinormalDistribution LogNormalDistribution LogPlot LogRankTest LogSeriesDistribution LongEqual Longest LongestAscendingSequence LongestCommonSequence LongestCommonSequencePositions LongestCommonSubsequence LongestCommonSubsequencePositions LongestMatch LongForm Longitude LongLeftArrow LongLeftRightArrow LongRightArrow Loopback LoopFreeGraphQ LowerCaseQ LowerLeftArrow LowerRightArrow LowerTriangularize LowpassFilter LQEstimatorGains LQGRegulator LQOutputRegulatorGains LQRegulatorGains LUBackSubstitution LucasL LuccioSamiComponents LUDecomposition LyapunovSolve LyonsGroupLy MachineID MachineName MachineNumberQ MachinePrecision MacintoshSystemPageSetup Magenta Magnification Magnify MainSolve MaintainDynamicCaches Majority MakeBoxes MakeExpression MakeRules MangoldtLambda ManhattanDistance Manipulate Manipulator MannWhitneyTest MantissaExponent Manual Map MapAll MapAt MapIndexed MAProcess MapThread MarcumQ MardiaCombinedTest MardiaKurtosisTest MardiaSkewnessTest MarginalDistribution MarkovProcessProperties Masking MatchingDissimilarity MatchLocalNameQ MatchLocalNames MatchQ Material MathematicaNotation MathieuC MathieuCharacteristicA MathieuCharacteristicB MathieuCharacteristicExponent MathieuCPrime MathieuGroupM11 MathieuGroupM12 MathieuGroupM22 MathieuGroupM23 MathieuGroupM24 MathieuS MathieuSPrime MathMLForm MathMLText Matrices MatrixExp MatrixForm MatrixFunction MatrixLog MatrixPlot MatrixPower MatrixQ MatrixRank Max MaxBend MaxDetect MaxExtraBandwidths MaxExtraConditions MaxFeatures MaxFilter Maximize MaxIterations MaxMemoryUsed MaxMixtureKernels MaxPlotPoints MaxPoints MaxRecursion MaxStableDistribution MaxStepFraction MaxSteps MaxStepSize MaxValue MaxwellDistribution McLaughlinGroupMcL Mean MeanClusteringCoefficient MeanDegreeConnectivity MeanDeviation MeanFilter MeanGraphDistance MeanNeighborDegree MeanShift MeanShiftFilter Median MedianDeviation MedianFilter Medium MeijerG MeixnerDistribution MemberQ MemoryConstrained MemoryInUse Menu MenuAppearance MenuCommandKey MenuEvaluator MenuItem MenuPacket MenuSortingValue MenuStyle MenuView MergeDifferences Mesh MeshFunctions MeshRange MeshShading MeshStyle Message MessageDialog MessageList MessageName MessageOptions MessagePacket Messages MessagesNotebook MetaCharacters MetaInformation Method MethodOptions MexicanHatWavelet MeyerWavelet Min MinDetect MinFilter MinimalPolynomial MinimalStateSpaceModel Minimize Minors MinRecursion MinSize MinStableDistribution Minus MinusPlus MinValue Missing MissingDataMethod MittagLefflerE MixedRadix MixedRadixQuantity MixtureDistribution Mod Modal Mode Modular ModularLambda Module Modulus MoebiusMu Moment Momentary MomentConvert MomentEvaluate MomentGeneratingFunction Monday Monitor MonomialList MonomialOrder MonsterGroupM MorletWavelet MorphologicalBinarize MorphologicalBranchPoints MorphologicalComponents MorphologicalEulerNumber MorphologicalGraph MorphologicalPerimeter MorphologicalTransform Most MouseAnnotation MouseAppearance MouseAppearanceTag MouseButtons Mouseover MousePointerNote MousePosition MovingAverage MovingMedian MoyalDistribution MultiedgeStyle MultilaunchWarning MultiLetterItalics MultiLetterStyle MultilineFunction Multinomial MultinomialDistribution MultinormalDistribution MultiplicativeOrder Multiplicity Multiselection MultivariateHypergeometricDistribution MultivariatePoissonDistribution MultivariateTDistribution N NakagamiDistribution NameQ Names NamespaceBox Nand NArgMax NArgMin NBernoulliB NCache NDSolve NDSolveValue Nearest NearestFunction NeedCurrentFrontEndPackagePacket NeedCurrentFrontEndSymbolsPacket NeedlemanWunschSimilarity Needs Negative NegativeBinomialDistribution NegativeMultinomialDistribution NeighborhoodGraph Nest NestedGreaterGreater NestedLessLess NestedScriptRules NestList NestWhile NestWhileList NevilleThetaC NevilleThetaD NevilleThetaN NevilleThetaS NewPrimitiveStyle NExpectation Next NextPrime NHoldAll NHoldFirst NHoldRest NicholsGridLines NicholsPlot NIntegrate NMaximize NMaxValue NMinimize NMinValue NominalVariables NonAssociative NoncentralBetaDistribution NoncentralChiSquareDistribution NoncentralFRatioDistribution NoncentralStudentTDistribution NonCommutativeMultiply NonConstants None NonlinearModelFit NonlocalMeansFilter NonNegative NonPositive Nor NorlundB Norm Normal NormalDistribution NormalGrouping Normalize NormalizedSquaredEuclideanDistance NormalsFunction NormFunction Not NotCongruent NotCupCap NotDoubleVerticalBar Notebook NotebookApply NotebookAutoSave NotebookClose NotebookConvertSettings NotebookCreate NotebookCreateReturnObject NotebookDefault NotebookDelete NotebookDirectory NotebookDynamicExpression NotebookEvaluate NotebookEventActions NotebookFileName NotebookFind NotebookFindReturnObject NotebookGet NotebookGetLayoutInformationPacket NotebookGetMisspellingsPacket NotebookInformation NotebookInterfaceObject NotebookLocate NotebookObject NotebookOpen NotebookOpenReturnObject NotebookPath NotebookPrint NotebookPut NotebookPutReturnObject NotebookRead NotebookResetGeneratedCells Notebooks NotebookSave NotebookSaveAs NotebookSelection NotebookSetupLayoutInformationPacket NotebooksMenu NotebookWrite NotElement NotEqualTilde NotExists NotGreater NotGreaterEqual NotGreaterFullEqual NotGreaterGreater NotGreaterLess NotGreaterSlantEqual NotGreaterTilde NotHumpDownHump NotHumpEqual NotLeftTriangle NotLeftTriangleBar NotLeftTriangleEqual NotLess NotLessEqual NotLessFullEqual NotLessGreater NotLessLess NotLessSlantEqual NotLessTilde NotNestedGreaterGreater NotNestedLessLess NotPrecedes NotPrecedesEqual NotPrecedesSlantEqual NotPrecedesTilde NotReverseElement NotRightTriangle NotRightTriangleBar NotRightTriangleEqual NotSquareSubset NotSquareSubsetEqual NotSquareSuperset NotSquareSupersetEqual NotSubset NotSubsetEqual NotSucceeds NotSucceedsEqual NotSucceedsSlantEqual NotSucceedsTilde NotSuperset NotSupersetEqual NotTilde NotTildeEqual NotTildeFullEqual NotTildeTilde NotVerticalBar NProbability NProduct NProductFactors NRoots NSolve NSum NSumTerms Null NullRecords NullSpace NullWords Number NumberFieldClassNumber NumberFieldDiscriminant NumberFieldFundamentalUnits NumberFieldIntegralBasis NumberFieldNormRepresentatives NumberFieldRegulator NumberFieldRootsOfUnity NumberFieldSignature NumberForm NumberFormat NumberMarks NumberMultiplier NumberPadding NumberPoint NumberQ NumberSeparator NumberSigns NumberString Numerator NumericFunction NumericQ NuttallWindow NValues NyquistGridLines NyquistPlot O ObservabilityGramian ObservabilityMatrix ObservableDecomposition ObservableModelQ OddQ Off Offset OLEData On ONanGroupON OneIdentity Opacity Open OpenAppend Opener OpenerBox OpenerBoxOptions OpenerView OpenFunctionInspectorPacket Opening OpenRead OpenSpecialOptions OpenTemporary OpenWrite Operate OperatingSystem OptimumFlowData Optional OptionInspectorSettings OptionQ Options OptionsPacket OptionsPattern OptionValue OptionValueBox OptionValueBoxOptions Or Orange Order OrderDistribution OrderedQ Ordering Orderless OrnsteinUhlenbeckProcess Orthogonalize Out Outer OutputAutoOverwrite OutputControllabilityMatrix OutputControllableModelQ OutputForm OutputFormData OutputGrouping OutputMathEditExpression OutputNamePacket OutputResponse OutputSizeLimit OutputStream Over OverBar OverDot Overflow OverHat Overlaps Overlay OverlayBox OverlayBoxOptions Overscript OverscriptBox OverscriptBoxOptions OverTilde OverVector OwenT OwnValues PackingMethod PaddedForm Padding PadeApproximant PadLeft PadRight PageBreakAbove PageBreakBelow PageBreakWithin PageFooterLines PageFooters PageHeaderLines PageHeaders PageHeight PageRankCentrality PageWidth PairedBarChart PairedHistogram PairedSmoothHistogram PairedTTest PairedZTest PaletteNotebook PalettePath Pane PaneBox PaneBoxOptions Panel PanelBox PanelBoxOptions Paneled PaneSelector PaneSelectorBox PaneSelectorBoxOptions PaperWidth ParabolicCylinderD ParagraphIndent ParagraphSpacing ParallelArray ParallelCombine ParallelDo ParallelEvaluate Parallelization Parallelize ParallelMap ParallelNeeds ParallelProduct ParallelSubmit ParallelSum ParallelTable ParallelTry Parameter ParameterEstimator ParameterMixtureDistribution ParameterVariables ParametricFunction ParametricNDSolve ParametricNDSolveValue ParametricPlot ParametricPlot3D ParentConnect ParentDirectory ParentForm Parenthesize ParentList ParetoDistribution Part PartialCorrelationFunction PartialD ParticleData Partition PartitionsP PartitionsQ ParzenWindow PascalDistribution PassEventsDown PassEventsUp Paste PasteBoxFormInlineCells PasteButton Path PathGraph PathGraphQ Pattern PatternSequence PatternTest PauliMatrix PaulWavelet Pause PausedTime PDF PearsonChiSquareTest PearsonCorrelationTest PearsonDistribution PerformanceGoal PeriodicInterpolation Periodogram PeriodogramArray PermutationCycles PermutationCyclesQ PermutationGroup PermutationLength PermutationList PermutationListQ PermutationMax PermutationMin PermutationOrder PermutationPower PermutationProduct PermutationReplace Permutations PermutationSupport Permute PeronaMalikFilter Perpendicular PERTDistribution PetersenGraph PhaseMargins Pi Pick PIDData PIDDerivativeFilter PIDFeedforward PIDTune Piecewise PiecewiseExpand PieChart PieChart3D PillaiTrace PillaiTraceTest Pink Pivoting PixelConstrained PixelValue PixelValuePositions Placed Placeholder PlaceholderReplace Plain PlanarGraphQ Play PlayRange Plot Plot3D Plot3Matrix PlotDivision PlotJoined PlotLabel PlotLayout PlotLegends PlotMarkers PlotPoints PlotRange PlotRangeClipping PlotRangePadding PlotRegion PlotStyle Plus PlusMinus Pochhammer PodStates PodWidth Point Point3DBox PointBox PointFigureChart PointForm PointLegend PointSize PoissonConsulDistribution PoissonDistribution PoissonProcess PoissonWindow PolarAxes PolarAxesOrigin PolarGridLines PolarPlot PolarTicks PoleZeroMarkers PolyaAeppliDistribution PolyGamma Polygon Polygon3DBox Polygon3DBoxOptions PolygonBox PolygonBoxOptions PolygonHoleScale PolygonIntersections PolygonScale PolyhedronData PolyLog PolynomialExtendedGCD PolynomialForm PolynomialGCD PolynomialLCM PolynomialMod PolynomialQ PolynomialQuotient PolynomialQuotientRemainder PolynomialReduce PolynomialRemainder Polynomials PopupMenu PopupMenuBox PopupMenuBoxOptions PopupView PopupWindow Position Positive PositiveDefiniteMatrixQ PossibleZeroQ Postfix PostScript Power PowerDistribution PowerExpand PowerMod PowerModList PowerSpectralDensity PowersRepresentations PowerSymmetricPolynomial Precedence PrecedenceForm Precedes PrecedesEqual PrecedesSlantEqual PrecedesTilde Precision PrecisionGoal PreDecrement PredictionRoot PreemptProtect PreferencesPath Prefix PreIncrement Prepend PrependTo PreserveImageOptions Previous PriceGraphDistribution PrimaryPlaceholder Prime PrimeNu PrimeOmega PrimePi PrimePowerQ PrimeQ Primes PrimeZetaP PrimitiveRoot PrincipalComponents PrincipalValue Print PrintAction PrintForm PrintingCopies PrintingOptions PrintingPageRange PrintingStartingPageNumber PrintingStyleEnvironment PrintPrecision PrintTemporary Prism PrismBox PrismBoxOptions PrivateCellOptions PrivateEvaluationOptions PrivateFontOptions PrivateFrontEndOptions PrivateNotebookOptions PrivatePaths Probability ProbabilityDistribution ProbabilityPlot ProbabilityPr ProbabilityScalePlot ProbitModelFit ProcessEstimator ProcessParameterAssumptions ProcessParameterQ ProcessStateDomain ProcessTimeDomain Product ProductDistribution ProductLog ProgressIndicator ProgressIndicatorBox ProgressIndicatorBoxOptions Projection Prolog PromptForm Properties Property PropertyList PropertyValue Proportion Proportional Protect Protected ProteinData Pruning PseudoInverse Purple Put PutAppend Pyramid PyramidBox PyramidBoxOptions QBinomial QFactorial QGamma QHypergeometricPFQ QPochhammer QPolyGamma QRDecomposition QuadraticIrrationalQ Quantile QuantilePlot Quantity QuantityForm QuantityMagnitude QuantityQ QuantityUnit Quartics QuartileDeviation Quartiles QuartileSkewness QueueingNetworkProcess QueueingProcess QueueProperties Quiet Quit Quotient QuotientRemainder RadialityCentrality RadicalBox RadicalBoxOptions RadioButton RadioButtonBar RadioButtonBox RadioButtonBoxOptions Radon RamanujanTau RamanujanTauL RamanujanTauTheta RamanujanTauZ Random RandomChoice RandomComplex RandomFunction RandomGraph RandomImage RandomInteger RandomPermutation RandomPrime RandomReal RandomSample RandomSeed RandomVariate RandomWalkProcess Range RangeFilter RangeSpecification RankedMax RankedMin Raster Raster3D Raster3DBox Raster3DBoxOptions RasterArray RasterBox RasterBoxOptions Rasterize RasterSize Rational RationalFunctions Rationalize Rationals Ratios Raw RawArray RawBoxes RawData RawMedium RayleighDistribution Re Read ReadList ReadProtected Real RealBlockDiagonalForm RealDigits RealExponent Reals Reap Record RecordLists RecordSeparators Rectangle RectangleBox RectangleBoxOptions RectangleChart RectangleChart3D RecurrenceFilter RecurrenceTable RecurringDigitsForm Red Reduce RefBox ReferenceLineStyle ReferenceMarkers ReferenceMarkerStyle Refine ReflectionMatrix ReflectionTransform Refresh RefreshRate RegionBinarize RegionFunction RegionPlot RegionPlot3D RegularExpression Regularization Reinstall Release ReleaseHold ReliabilityDistribution ReliefImage ReliefPlot Remove RemoveAlphaChannel RemoveAsynchronousTask Removed RemoveInputStreamMethod RemoveOutputStreamMethod RemoveProperty RemoveScheduledTask RenameDirectory RenameFile RenderAll RenderingOptions RenewalProcess RenkoChart Repeated RepeatedNull RepeatedString Replace ReplaceAll ReplaceHeldPart ReplaceImageValue ReplaceList ReplacePart ReplacePixelValue ReplaceRepeated Resampling Rescale RescalingTransform ResetDirectory ResetMenusPacket ResetScheduledTask Residue Resolve Rest Resultant ResumePacket Return ReturnExpressionPacket ReturnInputFormPacket ReturnPacket ReturnTextPacket Reverse ReverseBiorthogonalSplineWavelet ReverseElement ReverseEquilibrium ReverseGraph ReverseUpEquilibrium RevolutionAxis RevolutionPlot3D RGBColor RiccatiSolve RiceDistribution RidgeFilter RiemannR RiemannSiegelTheta RiemannSiegelZ Riffle Right RightArrow RightArrowBar RightArrowLeftArrow RightCosetRepresentative RightDownTeeVector RightDownVector RightDownVectorBar RightTee RightTeeArrow RightTeeVector RightTriangle RightTriangleBar RightTriangleEqual RightUpDownVector RightUpTeeVector RightUpVector RightUpVectorBar RightVector RightVectorBar RiskAchievementImportance RiskReductionImportance RogersTanimotoDissimilarity Root RootApproximant RootIntervals RootLocusPlot RootMeanSquare RootOfUnityQ RootReduce Roots RootSum Rotate RotateLabel RotateLeft RotateRight RotationAction RotationBox RotationBoxOptions RotationMatrix RotationTransform Round RoundImplies RoundingRadius Row RowAlignments RowBackgrounds RowBox RowHeights RowLines RowMinHeight RowReduce RowsEqual RowSpacings RSolve RudvalisGroupRu Rule RuleCondition RuleDelayed RuleForm RulerUnits Run RunScheduledTask RunThrough RuntimeAttributes RuntimeOptions RussellRaoDissimilarity SameQ SameTest SampleDepth SampledSoundFunction SampledSoundList SampleRate SamplingPeriod SARIMAProcess SARMAProcess SatisfiabilityCount SatisfiabilityInstances SatisfiableQ Saturday Save Saveable SaveAutoDelete SaveDefinitions SawtoothWave Scale Scaled ScaleDivisions ScaledMousePosition ScaleOrigin ScalePadding ScaleRanges ScaleRangeStyle ScalingFunctions ScalingMatrix ScalingTransform Scan ScheduledTaskActiveQ ScheduledTaskData ScheduledTaskObject ScheduledTasks SchurDecomposition ScientificForm ScreenRectangle ScreenStyleEnvironment ScriptBaselineShifts ScriptLevel ScriptMinSize ScriptRules ScriptSizeMultipliers Scrollbars ScrollingOptions ScrollPosition Sec Sech SechDistribution SectionGrouping SectorChart SectorChart3D SectorOrigin SectorSpacing SeedRandom Select Selectable SelectComponents SelectedCells SelectedNotebook Selection SelectionAnimate SelectionCell SelectionCellCreateCell SelectionCellDefaultStyle SelectionCellParentStyle SelectionCreateCell SelectionDebuggerTag SelectionDuplicateCell SelectionEvaluate SelectionEvaluateCreateCell SelectionMove SelectionPlaceholder SelectionSetStyle SelectWithContents SelfLoops SelfLoopStyle SemialgebraicComponentInstances SendMail Sequence SequenceAlignment SequenceForm SequenceHold SequenceLimit Series SeriesCoefficient SeriesData SessionTime Set SetAccuracy SetAlphaChannel SetAttributes Setbacks SetBoxFormNamesPacket SetDelayed SetDirectory SetEnvironment SetEvaluationNotebook SetFileDate SetFileLoadingContext SetNotebookStatusLine SetOptions SetOptionsPacket SetPrecision SetProperty SetSelectedNotebook SetSharedFunction SetSharedVariable SetSpeechParametersPacket SetStreamPosition SetSystemOptions Setter SetterBar SetterBox SetterBoxOptions Setting SetValue Shading Shallow ShannonWavelet ShapiroWilkTest Share Sharpen ShearingMatrix ShearingTransform ShenCastanMatrix Short ShortDownArrow Shortest ShortestMatch ShortestPathFunction ShortLeftArrow ShortRightArrow ShortUpArrow Show ShowAutoStyles ShowCellBracket ShowCellLabel ShowCellTags ShowClosedCellArea ShowContents ShowControls ShowCursorTracker ShowGroupOpenCloseIcon ShowGroupOpener ShowInvisibleCharacters ShowPageBreaks ShowPredictiveInterface ShowSelection ShowShortBoxForm ShowSpecialCharacters ShowStringCharacters ShowSyntaxStyles ShrinkingDelay ShrinkWrapBoundingBox SiegelTheta SiegelTukeyTest Sign Signature SignedRankTest SignificanceLevel SignPadding SignTest SimilarityRules SimpleGraph SimpleGraphQ Simplify Sin Sinc SinghMaddalaDistribution SingleEvaluation SingleLetterItalics SingleLetterStyle SingularValueDecomposition SingularValueList SingularValuePlot SingularValues Sinh SinhIntegral SinIntegral SixJSymbol Skeleton SkeletonTransform SkellamDistribution Skewness SkewNormalDistribution Skip SliceDistribution Slider Slider2D Slider2DBox Slider2DBoxOptions SliderBox SliderBoxOptions SlideView Slot SlotSequence Small SmallCircle Smaller SmithDelayCompensator SmithWatermanSimilarity SmoothDensityHistogram SmoothHistogram SmoothHistogram3D SmoothKernelDistribution SocialMediaData Socket SokalSneathDissimilarity Solve SolveAlways SolveDelayed Sort SortBy Sound SoundAndGraphics SoundNote SoundVolume Sow Space SpaceForm Spacer Spacings Span SpanAdjustments SpanCharacterRounding SpanFromAbove SpanFromBoth SpanFromLeft SpanLineThickness SpanMaxSize SpanMinSize SpanningCharacters SpanSymmetric SparseArray SpatialGraphDistribution Speak SpeakTextPacket SpearmanRankTest SpearmanRho Spectrogram SpectrogramArray Specularity SpellingCorrection SpellingDictionaries SpellingDictionariesPath SpellingOptions SpellingSuggestionsPacket Sphere SphereBox SphericalBesselJ SphericalBesselY SphericalHankelH1 SphericalHankelH2 SphericalHarmonicY SphericalPlot3D SphericalRegion SpheroidalEigenvalue SpheroidalJoiningFactor SpheroidalPS SpheroidalPSPrime SpheroidalQS SpheroidalQSPrime SpheroidalRadialFactor SpheroidalS1 SpheroidalS1Prime SpheroidalS2 SpheroidalS2Prime Splice SplicedDistribution SplineClosed SplineDegree SplineKnots SplineWeights Split SplitBy SpokenString Sqrt SqrtBox SqrtBoxOptions Square SquaredEuclideanDistance SquareFreeQ SquareIntersection SquaresR SquareSubset SquareSubsetEqual SquareSuperset SquareSupersetEqual SquareUnion SquareWave StabilityMargins StabilityMarginsStyle StableDistribution Stack StackBegin StackComplete StackInhibit StandardDeviation StandardDeviationFilter StandardForm Standardize StandbyDistribution Star StarGraph StartAsynchronousTask StartingStepSize StartOfLine StartOfString StartScheduledTask StartupSound StateDimensions StateFeedbackGains StateOutputEstimator StateResponse StateSpaceModel StateSpaceRealization StateSpaceTransform StationaryDistribution StationaryWaveletPacketTransform StationaryWaveletTransform StatusArea StatusCentrality StepMonitor StieltjesGamma StirlingS1 StirlingS2 StopAsynchronousTask StopScheduledTask StrataVariables StratonovichProcess StreamColorFunction StreamColorFunctionScaling StreamDensityPlot StreamPlot StreamPoints StreamPosition Streams StreamScale StreamStyle String StringBreak StringByteCount StringCases StringCount StringDrop StringExpression StringForm StringFormat StringFreeQ StringInsert StringJoin StringLength StringMatchQ StringPosition StringQ StringReplace StringReplaceList StringReplacePart StringReverse StringRotateLeft StringRotateRight StringSkeleton StringSplit StringTake StringToStream StringTrim StripBoxes StripOnInput StripWrapperBoxes StrokeForm StructuralImportance StructuredArray StructuredSelection StruveH StruveL Stub StudentTDistribution Style StyleBox StyleBoxAutoDelete StyleBoxOptions StyleData StyleDefinitions StyleForm StyleKeyMapping StyleMenuListing StyleNameDialogSettings StyleNames StylePrint StyleSheetPath Subfactorial Subgraph SubMinus SubPlus SubresultantPolynomialRemainders SubresultantPolynomials Subresultants Subscript SubscriptBox SubscriptBoxOptions Subscripted Subset SubsetEqual Subsets SubStar Subsuperscript SubsuperscriptBox SubsuperscriptBoxOptions Subtract SubtractFrom SubValues Succeeds SucceedsEqual SucceedsSlantEqual SucceedsTilde SuchThat Sum SumConvergence Sunday SuperDagger SuperMinus SuperPlus Superscript SuperscriptBox SuperscriptBoxOptions Superset SupersetEqual SuperStar Surd SurdForm SurfaceColor SurfaceGraphics SurvivalDistribution SurvivalFunction SurvivalModel SurvivalModelFit SuspendPacket SuzukiDistribution SuzukiGroupSuz SwatchLegend Switch Symbol SymbolName SymletWavelet Symmetric SymmetricGroup SymmetricMatrixQ SymmetricPolynomial SymmetricReduction Symmetrize SymmetrizedArray SymmetrizedArrayRules SymmetrizedDependentComponents SymmetrizedIndependentComponents SymmetrizedReplacePart SynchronousInitialization SynchronousUpdating Syntax SyntaxForm SyntaxInformation SyntaxLength SyntaxPacket SyntaxQ SystemDialogInput SystemException SystemHelpPath SystemInformation SystemInformationData SystemOpen SystemOptions SystemsModelDelay SystemsModelDelayApproximate SystemsModelDelete SystemsModelDimensions SystemsModelExtract SystemsModelFeedbackConnect SystemsModelLabels SystemsModelOrder SystemsModelParallelConnect SystemsModelSeriesConnect SystemsModelStateFeedbackConnect SystemStub Tab TabFilling Table TableAlignments TableDepth TableDirections TableForm TableHeadings TableSpacing TableView TableViewBox TabSpacings TabView TabViewBox TabViewBoxOptions TagBox TagBoxNote TagBoxOptions TaggingRules TagSet TagSetDelayed TagStyle TagUnset Take TakeWhile Tally Tan Tanh TargetFunctions TargetUnits TautologyQ TelegraphProcess TemplateBox TemplateBoxOptions TemplateSlotSequence TemporalData Temporary TemporaryVariable TensorContract TensorDimensions TensorExpand TensorProduct TensorQ TensorRank TensorReduce TensorSymmetry TensorTranspose TensorWedge Tetrahedron TetrahedronBox TetrahedronBoxOptions TeXForm TeXSave Text Text3DBox Text3DBoxOptions TextAlignment TextBand TextBoundingBox TextBox TextCell TextClipboardType TextData TextForm TextJustification TextLine TextPacket TextParagraph TextRecognize TextRendering TextStyle Texture TextureCoordinateFunction TextureCoordinateScaling Therefore ThermometerGauge Thick Thickness Thin Thinning ThisLink ThompsonGroupTh Thread ThreeJSymbol Threshold Through Throw Thumbnail Thursday Ticks TicksStyle Tilde TildeEqual TildeFullEqual TildeTilde TimeConstrained TimeConstraint Times TimesBy TimeSeriesForecast TimeSeriesInvertibility TimeUsed TimeValue TimeZone Timing Tiny TitleGrouping TitsGroupT ToBoxes ToCharacterCode ToColor ToContinuousTimeModel ToDate ToDiscreteTimeModel ToeplitzMatrix ToExpression ToFileName Together Toggle ToggleFalse Toggler TogglerBar TogglerBox TogglerBoxOptions ToHeldExpression ToInvertibleTimeSeries TokenWords Tolerance ToLowerCase ToNumberField TooBig Tooltip TooltipBox TooltipBoxOptions TooltipDelay TooltipStyle Top TopHatTransform TopologicalSort ToRadicals ToRules ToString Total TotalHeight TotalVariationFilter TotalWidth TouchscreenAutoZoom TouchscreenControlPlacement ToUpperCase Tr Trace TraceAbove TraceAction TraceBackward TraceDepth TraceDialog TraceForward TraceInternal TraceLevel TraceOff TraceOn TraceOriginal TracePrint TraceScan TrackedSymbols TradingChart TraditionalForm TraditionalFunctionNotation TraditionalNotation TraditionalOrder TransferFunctionCancel TransferFunctionExpand TransferFunctionFactor TransferFunctionModel TransferFunctionPoles TransferFunctionTransform TransferFunctionZeros TransformationFunction TransformationFunctions TransformationMatrix TransformedDistribution TransformedField Translate TranslationTransform TransparentColor Transpose TreeForm TreeGraph TreeGraphQ TreePlot TrendStyle TriangleWave TriangularDistribution Trig TrigExpand TrigFactor TrigFactorList Trigger TrigReduce TrigToExp TrimmedMean True TrueQ TruncatedDistribution TsallisQExponentialDistribution TsallisQGaussianDistribution TTest Tube TubeBezierCurveBox TubeBezierCurveBoxOptions TubeBox TubeBSplineCurveBox TubeBSplineCurveBoxOptions Tuesday TukeyLambdaDistribution TukeyWindow Tuples TuranGraph TuringMachine Transparent UnateQ Uncompress Undefined UnderBar Underflow Underlined Underoverscript UnderoverscriptBox UnderoverscriptBoxOptions Underscript UnderscriptBox UnderscriptBoxOptions UndirectedEdge UndirectedGraph UndirectedGraphQ UndocumentedTestFEParserPacket UndocumentedTestGetSelectionPacket Unequal Unevaluated UniformDistribution UniformGraphDistribution UniformSumDistribution Uninstall Union UnionPlus Unique UnitBox UnitConvert UnitDimensions Unitize UnitRootTest UnitSimplify UnitStep UnitTriangle UnitVector Unprotect UnsameQ UnsavedVariables Unset UnsetShared UntrackedVariables Up UpArrow UpArrowBar UpArrowDownArrow Update UpdateDynamicObjects UpdateDynamicObjectsSynchronous UpdateInterval UpDownArrow UpEquilibrium UpperCaseQ UpperLeftArrow UpperRightArrow UpperTriangularize Upsample UpSet UpSetDelayed UpTee UpTeeArrow UpValues URL URLFetch URLFetchAsynchronous URLSave URLSaveAsynchronous UseGraphicsRange Using UsingFrontEnd V2Get ValidationLength Value ValueBox ValueBoxOptions ValueForm ValueQ ValuesData Variables Variance VarianceEquivalenceTest VarianceEstimatorFunction VarianceGammaDistribution VarianceTest VectorAngle VectorColorFunction VectorColorFunctionScaling VectorDensityPlot VectorGlyphData VectorPlot VectorPlot3D VectorPoints VectorQ Vectors VectorScale VectorStyle Vee Verbatim Verbose VerboseConvertToPostScriptPacket VerifyConvergence VerifySolutions VerifyTestAssumptions Version VersionNumber VertexAdd VertexCapacity VertexColors VertexComponent VertexConnectivity VertexCoordinateRules VertexCoordinates VertexCorrelationSimilarity VertexCosineSimilarity VertexCount VertexCoverQ VertexDataCoordinates VertexDegree VertexDelete VertexDiceSimilarity VertexEccentricity VertexInComponent VertexInDegree VertexIndex VertexJaccardSimilarity VertexLabeling VertexLabels VertexLabelStyle VertexList VertexNormals VertexOutComponent VertexOutDegree VertexQ VertexRenderingFunction VertexReplace VertexShape VertexShapeFunction VertexSize VertexStyle VertexTextureCoordinates VertexWeight Vertical VerticalBar VerticalForm VerticalGauge VerticalSeparator VerticalSlider VerticalTilde ViewAngle ViewCenter ViewMatrix ViewPoint ViewPointSelectorSettings ViewPort ViewRange ViewVector ViewVertical VirtualGroupData Visible VisibleCell VoigtDistribution VonMisesDistribution WaitAll WaitAsynchronousTask WaitNext WaitUntil WakebyDistribution WalleniusHypergeometricDistribution WaringYuleDistribution WatershedComponents WatsonUSquareTest WattsStrogatzGraphDistribution WaveletBestBasis WaveletFilterCoefficients WaveletImagePlot WaveletListPlot WaveletMapIndexed WaveletMatrixPlot WaveletPhi WaveletPsi WaveletScale WaveletScalogram WaveletThreshold WeaklyConnectedComponents WeaklyConnectedGraphQ WeakStationarity WeatherData WeberE Wedge Wednesday WeibullDistribution WeierstrassHalfPeriods WeierstrassInvariants WeierstrassP WeierstrassPPrime WeierstrassSigma WeierstrassZeta WeightedAdjacencyGraph WeightedAdjacencyMatrix WeightedData WeightedGraphQ Weights WelchWindow WheelGraph WhenEvent Which While White Whitespace WhitespaceCharacter WhittakerM WhittakerW WienerFilter WienerProcess WignerD WignerSemicircleDistribution WilksW WilksWTest WindowClickSelect WindowElements WindowFloating WindowFrame WindowFrameElements WindowMargins WindowMovable WindowOpacity WindowSelected WindowSize WindowStatusArea WindowTitle WindowToolbars WindowWidth With WolframAlpha WolframAlphaDate WolframAlphaQuantity WolframAlphaResult Word WordBoundary WordCharacter WordData WordSearch WordSeparators WorkingPrecision Write WriteString Wronskian XMLElement XMLObject Xnor Xor Yellow YuleDissimilarity ZernikeR ZeroSymmetric ZeroTest ZeroWidthTimes Zeta ZetaZero ZipfDistribution ZTest ZTransform $Aborted $ActivationGroupID $ActivationKey $ActivationUserRegistered $AddOnsDirectory $AssertFunction $Assumptions $AsynchronousTask $BaseDirectory $BatchInput $BatchOutput $BoxForms $ByteOrdering $Canceled $CharacterEncoding $CharacterEncodings $CommandLine $CompilationTarget $ConditionHold $ConfiguredKernels $Context $ContextPath $ControlActiveSetting $CreationDate $CurrentLink $DateStringFormat $DefaultFont $DefaultFrontEnd $DefaultImagingDevice $DefaultPath $Display $DisplayFunction $DistributedContexts $DynamicEvaluation $Echo $Epilog $ExportFormats $Failed $FinancialDataSource $FormatType $FrontEnd $FrontEndSession $GeoLocation $HistoryLength $HomeDirectory $HTTPCookies $IgnoreEOF $ImagingDevices $ImportFormats $InitialDirectory $Input $InputFileName $InputStreamMethods $Inspector $InstallationDate $InstallationDirectory $InterfaceEnvironment $IterationLimit $KernelCount $KernelID $Language $LaunchDirectory $LibraryPath $LicenseExpirationDate $LicenseID $LicenseProcesses $LicenseServer $LicenseSubprocesses $LicenseType $Line $Linked $LinkSupported $LoadedFiles $MachineAddresses $MachineDomain $MachineDomains $MachineEpsilon $MachineID $MachineName $MachinePrecision $MachineType $MaxExtraPrecision $MaxLicenseProcesses $MaxLicenseSubprocesses $MaxMachineNumber $MaxNumber $MaxPiecewiseCases $MaxPrecision $MaxRootDegree $MessageGroups $MessageList $MessagePrePrint $Messages $MinMachineNumber $MinNumber $MinorReleaseNumber $MinPrecision $ModuleNumber $NetworkLicense $NewMessage $NewSymbol $Notebooks $NumberMarks $Off $OperatingSystem $Output $OutputForms $OutputSizeLimit $OutputStreamMethods $Packages $ParentLink $ParentProcessID $PasswordFile $PatchLevelID $Path $PathnameSeparator $PerformanceGoal $PipeSupported $Post $Pre $PreferencesDirectory $PrePrint $PreRead $PrintForms $PrintLiteral $ProcessID $ProcessorCount $ProcessorType $ProductInformation $ProgramName $RandomState $RecursionLimit $ReleaseNumber $RootDirectory $ScheduledTask $ScriptCommandLine $SessionID $SetParentLink $SharedFunctions $SharedVariables $SoundDisplay $SoundDisplayFunction $SuppressInputFormHeads $SynchronousEvaluation $SyntaxHandler $System $SystemCharacterEncoding $SystemID $SystemWordLength $TemporaryDirectory $TemporaryPrefix $TextStyle $TimedOut $TimeUnit $TimeZone $TopDirectory $TraceOff $TraceOn $TracePattern $TracePostAction $TracePreAction $Urgent $UserAddOnsDirectory $UserBaseDirectory $UserDocumentsDirectory $UserName $Version $VersionNumber", +c:[{cN:"comment",b:/\(\*/,e:/\*\)/},e.ASM,e.QSM,e.CNM,{cN:"list",b:/\{/,e:/\}/,i:/:/}]}}); \ No newline at end of file diff --git a/lib/highlight_js/assets/lang/matlab.js b/lib/highlight_js/assets/lang/matlab.js new file mode 100644 index 0000000000..ef7746c8c0 --- /dev/null +++ b/lib/highlight_js/assets/lang/matlab.js @@ -0,0 +1 @@ +hljs.registerLanguage("matlab",function(e){var a=[e.CNM,{cN:"string",b:"'",e:"'",c:[e.BE,{b:"''"}]}],s={r:0,c:[{cN:"operator",b:/'['\.]*/}]};return{k:{keyword:"break case catch classdef continue else elseif end enumerated events for function global if methods otherwise parfor persistent properties return spmd switch try while",built_in:"sin sind sinh asin asind asinh cos cosd cosh acos acosd acosh tan tand tanh atan atand atan2 atanh sec secd sech asec asecd asech csc cscd csch acsc acscd acsch cot cotd coth acot acotd acoth hypot exp expm1 log log1p log10 log2 pow2 realpow reallog realsqrt sqrt nthroot nextpow2 abs angle complex conj imag real unwrap isreal cplxpair fix floor ceil round mod rem sign airy besselj bessely besselh besseli besselk beta betainc betaln ellipj ellipke erf erfc erfcx erfinv expint gamma gammainc gammaln psi legendre cross dot factor isprime primes gcd lcm rat rats perms nchoosek factorial cart2sph cart2pol pol2cart sph2cart hsv2rgb rgb2hsv zeros ones eye repmat rand randn linspace logspace freqspace meshgrid accumarray size length ndims numel disp isempty isequal isequalwithequalnans cat reshape diag blkdiag tril triu fliplr flipud flipdim rot90 find sub2ind ind2sub bsxfun ndgrid permute ipermute shiftdim circshift squeeze isscalar isvector ans eps realmax realmin pi i inf nan isnan isinf isfinite j why compan gallery hadamard hankel hilb invhilb magic pascal rosser toeplitz vander wilkinson"},i:'(//|"|#|/\\*|\\s+/\\w+)',c:[{cN:"function",bK:"function",e:"$",c:[e.UTM,{cN:"params",b:"\\(",e:"\\)"},{cN:"params",b:"\\[",e:"\\]"}]},{b:/[a-zA-Z_][a-zA-Z_0-9]*'['\.]*/,rB:!0,r:0,c:[{b:/[a-zA-Z_][a-zA-Z_0-9]*/,r:0},s.c[0]]},{cN:"matrix",b:"\\[",e:"\\]",c:a,r:0,starts:s},{cN:"cell",b:"\\{",e:/}/,c:a,r:0,starts:s},{b:/\)/,r:0,starts:s},e.C("^\\s*\\%\\{\\s*$","^\\s*\\%\\}\\s*$"),e.C("\\%","$")].concat(a)}}); \ No newline at end of file diff --git a/lib/highlight_js/assets/lang/mel.js b/lib/highlight_js/assets/lang/mel.js new file mode 100644 index 0000000000..639a4a6594 --- /dev/null +++ b/lib/highlight_js/assets/lang/mel.js @@ -0,0 +1 @@ +hljs.registerLanguage("mel",function(e){return{k:"int float string vector matrix if else switch case default while do for in break continue global proc return about abs addAttr addAttributeEditorNodeHelp addDynamic addNewShelfTab addPP addPanelCategory addPrefixToName advanceToNextDrivenKey affectedNet affects aimConstraint air alias aliasAttr align alignCtx alignCurve alignSurface allViewFit ambientLight angle angleBetween animCone animCurveEditor animDisplay animView annotate appendStringArray applicationName applyAttrPreset applyTake arcLenDimContext arcLengthDimension arclen arrayMapper art3dPaintCtx artAttrCtx artAttrPaintVertexCtx artAttrSkinPaintCtx artAttrTool artBuildPaintMenu artFluidAttrCtx artPuttyCtx artSelectCtx artSetPaintCtx artUserPaintCtx assignCommand assignInputDevice assignViewportFactories attachCurve attachDeviceAttr attachSurface attrColorSliderGrp attrCompatibility attrControlGrp attrEnumOptionMenu attrEnumOptionMenuGrp attrFieldGrp attrFieldSliderGrp attrNavigationControlGrp attrPresetEditWin attributeExists attributeInfo attributeMenu attributeQuery autoKeyframe autoPlace bakeClip bakeFluidShading bakePartialHistory bakeResults bakeSimulation basename basenameEx batchRender bessel bevel bevelPlus binMembership bindSkin blend2 blendShape blendShapeEditor blendShapePanel blendTwoAttr blindDataType boneLattice boundary boxDollyCtx boxZoomCtx bufferCurve buildBookmarkMenu buildKeyframeMenu button buttonManip CBG cacheFile cacheFileCombine cacheFileMerge cacheFileTrack camera cameraView canCreateManip canvas capitalizeString catch catchQuiet ceil changeSubdivComponentDisplayLevel changeSubdivRegion channelBox character characterMap characterOutlineEditor characterize chdir checkBox checkBoxGrp checkDefaultRenderGlobals choice circle circularFillet clamp clear clearCache clip clipEditor clipEditorCurrentTimeCtx clipSchedule clipSchedulerOutliner clipTrimBefore closeCurve closeSurface cluster cmdFileOutput cmdScrollFieldExecuter cmdScrollFieldReporter cmdShell coarsenSubdivSelectionList collision color colorAtPoint colorEditor colorIndex colorIndexSliderGrp colorSliderButtonGrp colorSliderGrp columnLayout commandEcho commandLine commandPort compactHairSystem componentEditor compositingInterop computePolysetVolume condition cone confirmDialog connectAttr connectControl connectDynamic connectJoint connectionInfo constrain constrainValue constructionHistory container containsMultibyte contextInfo control convertFromOldLayers convertIffToPsd convertLightmap convertSolidTx convertTessellation convertUnit copyArray copyFlexor copyKey copySkinWeights cos cpButton cpCache cpClothSet cpCollision cpConstraint cpConvClothToMesh cpForces cpGetSolverAttr cpPanel cpProperty cpRigidCollisionFilter cpSeam cpSetEdit cpSetSolverAttr cpSolver cpSolverTypes cpTool cpUpdateClothUVs createDisplayLayer createDrawCtx createEditor createLayeredPsdFile createMotionField createNewShelf createNode createRenderLayer createSubdivRegion cross crossProduct ctxAbort ctxCompletion ctxEditMode ctxTraverse currentCtx currentTime currentTimeCtx currentUnit curve curveAddPtCtx curveCVCtx curveEPCtx curveEditorCtx curveIntersect curveMoveEPCtx curveOnSurface curveSketchCtx cutKey cycleCheck cylinder dagPose date defaultLightListCheckBox defaultNavigation defineDataServer defineVirtualDevice deformer deg_to_rad delete deleteAttr deleteShadingGroupsAndMaterials deleteShelfTab deleteUI deleteUnusedBrushes delrandstr detachCurve detachDeviceAttr detachSurface deviceEditor devicePanel dgInfo dgdirty dgeval dgtimer dimWhen directKeyCtx directionalLight dirmap dirname disable disconnectAttr disconnectJoint diskCache displacementToPoly displayAffected displayColor displayCull displayLevelOfDetail displayPref displayRGBColor displaySmoothness displayStats displayString displaySurface distanceDimContext distanceDimension doBlur dolly dollyCtx dopeSheetEditor dot dotProduct doubleProfileBirailSurface drag dragAttrContext draggerContext dropoffLocator duplicate duplicateCurve duplicateSurface dynCache dynControl dynExport dynExpression dynGlobals dynPaintEditor dynParticleCtx dynPref dynRelEdPanel dynRelEditor dynamicLoad editAttrLimits editDisplayLayerGlobals editDisplayLayerMembers editRenderLayerAdjustment editRenderLayerGlobals editRenderLayerMembers editor editorTemplate effector emit emitter enableDevice encodeString endString endsWith env equivalent equivalentTol erf error eval evalDeferred evalEcho event exactWorldBoundingBox exclusiveLightCheckBox exec executeForEachObject exists exp expression expressionEditorListen extendCurve extendSurface extrude fcheck fclose feof fflush fgetline fgetword file fileBrowserDialog fileDialog fileExtension fileInfo filetest filletCurve filter filterCurve filterExpand filterStudioImport findAllIntersections findAnimCurves findKeyframe findMenuItem findRelatedSkinCluster finder firstParentOf fitBspline flexor floatEq floatField floatFieldGrp floatScrollBar floatSlider floatSlider2 floatSliderButtonGrp floatSliderGrp floor flow fluidCacheInfo fluidEmitter fluidVoxelInfo flushUndo fmod fontDialog fopen formLayout format fprint frameLayout fread freeFormFillet frewind fromNativePath fwrite gamma gauss geometryConstraint getApplicationVersionAsFloat getAttr getClassification getDefaultBrush getFileList getFluidAttr getInputDeviceRange getMayaPanelTypes getModifiers getPanel getParticleAttr getPluginResource getenv getpid glRender glRenderEditor globalStitch gmatch goal gotoBindPose grabColor gradientControl gradientControlNoAttr graphDollyCtx graphSelectContext graphTrackCtx gravity grid gridLayout group groupObjectsByName HfAddAttractorToAS HfAssignAS HfBuildEqualMap HfBuildFurFiles HfBuildFurImages HfCancelAFR HfConnectASToHF HfCreateAttractor HfDeleteAS HfEditAS HfPerformCreateAS HfRemoveAttractorFromAS HfSelectAttached HfSelectAttractors HfUnAssignAS hardenPointCurve hardware hardwareRenderPanel headsUpDisplay headsUpMessage help helpLine hermite hide hilite hitTest hotBox hotkey hotkeyCheck hsv_to_rgb hudButton hudSlider hudSliderButton hwReflectionMap hwRender hwRenderLoad hyperGraph hyperPanel hyperShade hypot iconTextButton iconTextCheckBox iconTextRadioButton iconTextRadioCollection iconTextScrollList iconTextStaticLabel ikHandle ikHandleCtx ikHandleDisplayScale ikSolver ikSplineHandleCtx ikSystem ikSystemInfo ikfkDisplayMethod illustratorCurves image imfPlugins inheritTransform insertJoint insertJointCtx insertKeyCtx insertKnotCurve insertKnotSurface instance instanceable instancer intField intFieldGrp intScrollBar intSlider intSliderGrp interToUI internalVar intersect iprEngine isAnimCurve isConnected isDirty isParentOf isSameObject isTrue isValidObjectName isValidString isValidUiName isolateSelect itemFilter itemFilterAttr itemFilterRender itemFilterType joint jointCluster jointCtx jointDisplayScale jointLattice keyTangent keyframe keyframeOutliner keyframeRegionCurrentTimeCtx keyframeRegionDirectKeyCtx keyframeRegionDollyCtx keyframeRegionInsertKeyCtx keyframeRegionMoveKeyCtx keyframeRegionScaleKeyCtx keyframeRegionSelectKeyCtx keyframeRegionSetKeyCtx keyframeRegionTrackCtx keyframeStats lassoContext lattice latticeDeformKeyCtx launch launchImageEditor layerButton layeredShaderPort layeredTexturePort layout layoutDialog lightList lightListEditor lightListPanel lightlink lineIntersection linearPrecision linstep listAnimatable listAttr listCameras listConnections listDeviceAttachments listHistory listInputDeviceAxes listInputDeviceButtons listInputDevices listMenuAnnotation listNodeTypes listPanelCategories listRelatives listSets listTransforms listUnselected listerEditor loadFluid loadNewShelf loadPlugin loadPluginLanguageResources loadPrefObjects localizedPanelLabel lockNode loft log longNameOf lookThru ls lsThroughFilter lsType lsUI Mayatomr mag makeIdentity makeLive makePaintable makeRoll makeSingleSurface makeTubeOn makebot manipMoveContext manipMoveLimitsCtx manipOptions manipRotateContext manipRotateLimitsCtx manipScaleContext manipScaleLimitsCtx marker match max memory menu menuBarLayout menuEditor menuItem menuItemToShelf menuSet menuSetPref messageLine min minimizeApp mirrorJoint modelCurrentTimeCtx modelEditor modelPanel mouse movIn movOut move moveIKtoFK moveKeyCtx moveVertexAlongDirection multiProfileBirailSurface mute nParticle nameCommand nameField namespace namespaceInfo newPanelItems newton nodeCast nodeIconButton nodeOutliner nodePreset nodeType noise nonLinear normalConstraint normalize nurbsBoolean nurbsCopyUVSet nurbsCube nurbsEditUV nurbsPlane nurbsSelect nurbsSquare nurbsToPoly nurbsToPolygonsPref nurbsToSubdiv nurbsToSubdivPref nurbsUVSet nurbsViewDirectionVector objExists objectCenter objectLayer objectType objectTypeUI obsoleteProc oceanNurbsPreviewPlane offsetCurve offsetCurveOnSurface offsetSurface openGLExtension openMayaPref optionMenu optionMenuGrp optionVar orbit orbitCtx orientConstraint outlinerEditor outlinerPanel overrideModifier paintEffectsDisplay pairBlend palettePort paneLayout panel panelConfiguration panelHistory paramDimContext paramDimension paramLocator parent parentConstraint particle particleExists particleInstancer particleRenderInfo partition pasteKey pathAnimation pause pclose percent performanceOptions pfxstrokes pickWalk picture pixelMove planarSrf plane play playbackOptions playblast plugAttr plugNode pluginInfo pluginResourceUtil pointConstraint pointCurveConstraint pointLight pointMatrixMult pointOnCurve pointOnSurface pointPosition poleVectorConstraint polyAppend polyAppendFacetCtx polyAppendVertex polyAutoProjection polyAverageNormal polyAverageVertex polyBevel polyBlendColor polyBlindData polyBoolOp polyBridgeEdge polyCacheMonitor polyCheck polyChipOff polyClipboard polyCloseBorder polyCollapseEdge polyCollapseFacet polyColorBlindData polyColorDel polyColorPerVertex polyColorSet polyCompare polyCone polyCopyUV polyCrease polyCreaseCtx polyCreateFacet polyCreateFacetCtx polyCube polyCut polyCutCtx polyCylinder polyCylindricalProjection polyDelEdge polyDelFacet polyDelVertex polyDuplicateAndConnect polyDuplicateEdge polyEditUV polyEditUVShell polyEvaluate polyExtrudeEdge polyExtrudeFacet polyExtrudeVertex polyFlipEdge polyFlipUV polyForceUV polyGeoSampler polyHelix polyInfo polyInstallAction polyLayoutUV polyListComponentConversion polyMapCut polyMapDel polyMapSew polyMapSewMove polyMergeEdge polyMergeEdgeCtx polyMergeFacet polyMergeFacetCtx polyMergeUV polyMergeVertex polyMirrorFace polyMoveEdge polyMoveFacet polyMoveFacetUV polyMoveUV polyMoveVertex polyNormal polyNormalPerVertex polyNormalizeUV polyOptUvs polyOptions polyOutput polyPipe polyPlanarProjection polyPlane polyPlatonicSolid polyPoke polyPrimitive polyPrism polyProjection polyPyramid polyQuad polyQueryBlindData polyReduce polySelect polySelectConstraint polySelectConstraintMonitor polySelectCtx polySelectEditCtx polySeparate polySetToFaceNormal polySewEdge polyShortestPathCtx polySmooth polySoftEdge polySphere polySphericalProjection polySplit polySplitCtx polySplitEdge polySplitRing polySplitVertex polyStraightenUVBorder polySubdivideEdge polySubdivideFacet polyToSubdiv polyTorus polyTransfer polyTriangulate polyUVSet polyUnite polyWedgeFace popen popupMenu pose pow preloadRefEd print progressBar progressWindow projFileViewer projectCurve projectTangent projectionContext projectionManip promptDialog propModCtx propMove psdChannelOutliner psdEditTextureFile psdExport psdTextureFile putenv pwd python querySubdiv quit rad_to_deg radial radioButton radioButtonGrp radioCollection radioMenuItemCollection rampColorPort rand randomizeFollicles randstate rangeControl readTake rebuildCurve rebuildSurface recordAttr recordDevice redo reference referenceEdit referenceQuery refineSubdivSelectionList refresh refreshAE registerPluginResource rehash reloadImage removeJoint removeMultiInstance removePanelCategory rename renameAttr renameSelectionList renameUI render renderGlobalsNode renderInfo renderLayerButton renderLayerParent renderLayerPostProcess renderLayerUnparent renderManip renderPartition renderQualityNode renderSettings renderThumbnailUpdate renderWindowEditor renderWindowSelectContext renderer reorder reorderDeformers requires reroot resampleFluid resetAE resetPfxToPolyCamera resetTool resolutionNode retarget reverseCurve reverseSurface revolve rgb_to_hsv rigidBody rigidSolver roll rollCtx rootOf rot rotate rotationInterpolation roundConstantRadius rowColumnLayout rowLayout runTimeCommand runup sampleImage saveAllShelves saveAttrPreset saveFluid saveImage saveInitialState saveMenu savePrefObjects savePrefs saveShelf saveToolSettings scale scaleBrushBrightness scaleComponents scaleConstraint scaleKey scaleKeyCtx sceneEditor sceneUIReplacement scmh scriptCtx scriptEditorInfo scriptJob scriptNode scriptTable scriptToShelf scriptedPanel scriptedPanelType scrollField scrollLayout sculpt searchPathArray seed selLoadSettings select selectContext selectCurveCV selectKey selectKeyCtx selectKeyframeRegionCtx selectMode selectPref selectPriority selectType selectedNodes selectionConnection separator setAttr setAttrEnumResource setAttrMapping setAttrNiceNameResource setConstraintRestPosition setDefaultShadingGroup setDrivenKeyframe setDynamic setEditCtx setEditor setFluidAttr setFocus setInfinity setInputDeviceMapping setKeyCtx setKeyPath setKeyframe setKeyframeBlendshapeTargetWts setMenuMode setNodeNiceNameResource setNodeTypeFlag setParent setParticleAttr setPfxToPolyCamera setPluginResource setProject setStampDensity setStartupMessage setState setToolTo setUITemplate setXformManip sets shadingConnection shadingGeometryRelCtx shadingLightRelCtx shadingNetworkCompare shadingNode shapeCompare shelfButton shelfLayout shelfTabLayout shellField shortNameOf showHelp showHidden showManipCtx showSelectionInTitle showShadingGroupAttrEditor showWindow sign simplify sin singleProfileBirailSurface size sizeBytes skinCluster skinPercent smoothCurve smoothTangentSurface smoothstep snap2to2 snapKey snapMode snapTogetherCtx snapshot soft softMod softModCtx sort sound soundControl source spaceLocator sphere sphrand spotLight spotLightPreviewPort spreadSheetEditor spring sqrt squareSurface srtContext stackTrace startString startsWith stitchAndExplodeShell stitchSurface stitchSurfacePoints strcmp stringArrayCatenate stringArrayContains stringArrayCount stringArrayInsertAtIndex stringArrayIntersector stringArrayRemove stringArrayRemoveAtIndex stringArrayRemoveDuplicates stringArrayRemoveExact stringArrayToString stringToStringArray strip stripPrefixFromName stroke subdAutoProjection subdCleanTopology subdCollapse subdDuplicateAndConnect subdEditUV subdListComponentConversion subdMapCut subdMapSewMove subdMatchTopology subdMirror subdToBlind subdToPoly subdTransferUVsToCache subdiv subdivCrease subdivDisplaySmoothness substitute substituteAllString substituteGeometry substring surface surfaceSampler surfaceShaderList swatchDisplayPort switchTable symbolButton symbolCheckBox sysFile system tabLayout tan tangentConstraint texLatticeDeformContext texManipContext texMoveContext texMoveUVShellContext texRotateContext texScaleContext texSelectContext texSelectShortestPathCtx texSmudgeUVContext texWinToolCtx text textCurves textField textFieldButtonGrp textFieldGrp textManip textScrollList textToShelf textureDisplacePlane textureHairColor texturePlacementContext textureWindow threadCount threePointArcCtx timeControl timePort timerX toNativePath toggle toggleAxis toggleWindowVisibility tokenize tokenizeList tolerance tolower toolButton toolCollection toolDropped toolHasOptions toolPropertyWindow torus toupper trace track trackCtx transferAttributes transformCompare transformLimits translator trim trunc truncateFluidCache truncateHairCache tumble tumbleCtx turbulence twoPointArcCtx uiRes uiTemplate unassignInputDevice undo undoInfo ungroup uniform unit unloadPlugin untangleUV untitledFileName untrim upAxis updateAE userCtx uvLink uvSnapshot validateShelfName vectorize view2dToolCtx viewCamera viewClipPlane viewFit viewHeadOn viewLookAt viewManip viewPlace viewSet visor volumeAxis vortex waitCursor warning webBrowser webBrowserPrefs whatIs window windowPref wire wireContext workspace wrinkle wrinkleContext writeTake xbmLangPathList xform",i:""},{b:"<=",r:0},{b:"=>",r:0},{b:"/\\\\"},{b:"\\\\/"}]},c={cN:"built_in",v:[{b:":-\\|-->"},{b:"=",r:0}]};return{aliases:["m","moo"],k:i,c:[s,c,t,_,n,e.NM,a,o,{b:/:-/}]}}); \ No newline at end of file diff --git a/lib/highlight_js/assets/lang/mizar.js b/lib/highlight_js/assets/lang/mizar.js new file mode 100644 index 0000000000..05e21b096e --- /dev/null +++ b/lib/highlight_js/assets/lang/mizar.js @@ -0,0 +1 @@ +hljs.registerLanguage("mizar",function(e){return{k:"environ vocabularies notations constructors definitions registrations theorems schemes requirements begin end definition registration cluster existence pred func defpred deffunc theorem proof let take assume then thus hence ex for st holds consider reconsider such that and in provided of as from be being by means equals implies iff redefine define now not or attr is mode suppose per cases set thesis contradiction scheme reserve struct correctness compatibility coherence symmetry assymetry reflexivity irreflexivity connectedness uniqueness commutativity idempotence involutiveness projectivity",c:[e.C("::","$")]}}); \ No newline at end of file diff --git a/lib/highlight_js/assets/lang/monkey.js b/lib/highlight_js/assets/lang/monkey.js new file mode 100644 index 0000000000..cb123439af --- /dev/null +++ b/lib/highlight_js/assets/lang/monkey.js @@ -0,0 +1 @@ +hljs.registerLanguage("monkey",function(e){var n={cN:"number",r:0,v:[{b:"[$][a-fA-F0-9]+"},e.NM]};return{cI:!0,k:{keyword:"public private property continue exit extern new try catch eachin not abstract final select case default const local global field end if then else elseif endif while wend repeat until forever for to step next return module inline throw",built_in:"DebugLog DebugStop Error Print ACos ACosr ASin ASinr ATan ATan2 ATan2r ATanr Abs Abs Ceil Clamp Clamp Cos Cosr Exp Floor Log Max Max Min Min Pow Sgn Sgn Sin Sinr Sqrt Tan Tanr Seed PI HALFPI TWOPI",literal:"true false null and or shl shr mod"},c:[e.C("#rem","#end"),e.C("'","$",{r:0}),{cN:"function",bK:"function method",e:"[(=:]|$",i:/\n/,c:[e.UTM]},{cN:"class",bK:"class interface",e:"$",c:[{bK:"extends implements"},e.UTM]},{cN:"variable",b:"\\b(self|super)\\b"},{cN:"preprocessor",bK:"import",e:"$"},{cN:"preprocessor",b:"\\s*#",e:"$",k:"if else elseif endif end then"},{cN:"pi",b:"^\\s*strict\\b"},{bK:"alias",e:"=",c:[e.UTM]},e.QSM,n]}}); \ No newline at end of file diff --git a/lib/highlight_js/assets/lang/nginx.js b/lib/highlight_js/assets/lang/nginx.js new file mode 100644 index 0000000000..8131f37aad --- /dev/null +++ b/lib/highlight_js/assets/lang/nginx.js @@ -0,0 +1 @@ +hljs.registerLanguage("nginx",function(e){var r={cN:"variable",v:[{b:/\$\d+/},{b:/\$\{/,e:/}/},{b:"[\\$\\@]"+e.UIR}]},b={eW:!0,l:"[a-z/_]+",k:{built_in:"on off yes no true false none blocked debug info notice warn error crit select break last permanent redirect kqueue rtsig epoll poll /dev/poll"},r:0,i:"=>",c:[e.HCM,{cN:"string",c:[e.BE,r],v:[{b:/"/,e:/"/},{b:/'/,e:/'/}]},{cN:"url",b:"([a-z]+):/",e:"\\s",eW:!0,eE:!0,c:[r]},{cN:"regexp",c:[e.BE,r],v:[{b:"\\s\\^",e:"\\s|{|;",rE:!0},{b:"~\\*?\\s+",e:"\\s|{|;",rE:!0},{b:"\\*(\\.[a-z\\-]+)+"},{b:"([a-z\\-]+\\.)+\\*"}]},{cN:"number",b:"\\b\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}(:\\d{1,5})?\\b"},{cN:"number",b:"\\b\\d+[kKmMgGdshdwy]*\\b",r:0},r]};return{aliases:["nginxconf"],c:[e.HCM,{b:e.UIR+"\\s",e:";|{",rB:!0,c:[{cN:"title",b:e.UIR,starts:b}],r:0}],i:"[^\\s\\}]"}}); \ No newline at end of file diff --git a/lib/highlight_js/assets/lang/nimrod.js b/lib/highlight_js/assets/lang/nimrod.js new file mode 100644 index 0000000000..02774be244 --- /dev/null +++ b/lib/highlight_js/assets/lang/nimrod.js @@ -0,0 +1 @@ +hljs.registerLanguage("nimrod",function(t){return{aliases:["nim"],k:{keyword:"addr and as asm bind block break|0 case|0 cast const|0 continue|0 converter discard distinct|10 div do elif else|0 end|0 enum|0 except export finally for from generic if|0 import|0 in include|0 interface is isnot|10 iterator|10 let|0 macro method|10 mixin mod nil not notin|10 object|0 of or out proc|10 ptr raise ref|10 return shl shr static template|10 try|0 tuple type|0 using|0 var|0 when while|0 with without xor yield",literal:"shared guarded stdin stdout stderr result|10 true false"},c:[{cN:"decorator",b:/{\./,e:/\.}/,r:10},{cN:"string",b:/[a-zA-Z]\w*"/,e:/"/,c:[{b:/""/}]},{cN:"string",b:/([a-zA-Z]\w*)?"""/,e:/"""/},t.QSM,{cN:"type",b:/\b[A-Z]\w+\b/,r:0},{cN:"type",b:/\b(int|int8|int16|int32|int64|uint|uint8|uint16|uint32|uint64|float|float32|float64|bool|char|string|cstring|pointer|expr|stmt|void|auto|any|range|array|openarray|varargs|seq|set|clong|culong|cchar|cschar|cshort|cint|csize|clonglong|cfloat|cdouble|clongdouble|cuchar|cushort|cuint|culonglong|cstringarray|semistatic)\b/},{cN:"number",b:/\b(0[xX][0-9a-fA-F][_0-9a-fA-F]*)('?[iIuU](8|16|32|64))?/,r:0},{cN:"number",b:/\b(0o[0-7][_0-7]*)('?[iIuUfF](8|16|32|64))?/,r:0},{cN:"number",b:/\b(0(b|B)[01][_01]*)('?[iIuUfF](8|16|32|64))?/,r:0},{cN:"number",b:/\b(\d[_\d]*)('?[iIuUfF](8|16|32|64))?/,r:0},t.HCM]}}); \ No newline at end of file diff --git a/lib/highlight_js/assets/lang/nix.js b/lib/highlight_js/assets/lang/nix.js new file mode 100644 index 0000000000..562874efff --- /dev/null +++ b/lib/highlight_js/assets/lang/nix.js @@ -0,0 +1 @@ +hljs.registerLanguage("nix",function(e){var t={keyword:"rec with let in inherit assert if else then",constant:"true false or and null",built_in:"import abort baseNameOf dirOf isNull builtins map removeAttrs throw toString derivation"},i={cN:"subst",b:/\$\{/,e:/}/,k:t},r={cN:"variable",b:/[a-zA-Z0-9-_]+(\s*=)/},n={cN:"string",b:"''",e:"''",c:[i]},s={cN:"string",b:'"',e:'"',c:[i]},a=[e.NM,e.HCM,e.CBCM,n,s,r];return i.c=a,{aliases:["nixos"],k:t,c:a}}); \ No newline at end of file diff --git a/lib/highlight_js/assets/lang/nsis.js b/lib/highlight_js/assets/lang/nsis.js new file mode 100644 index 0000000000..d6c072dc8b --- /dev/null +++ b/lib/highlight_js/assets/lang/nsis.js @@ -0,0 +1 @@ +hljs.registerLanguage("nsis",function(e){var t={cN:"symbol",b:"\\$(ADMINTOOLS|APPDATA|CDBURN_AREA|CMDLINE|COMMONFILES32|COMMONFILES64|COMMONFILES|COOKIES|DESKTOP|DOCUMENTS|EXEDIR|EXEFILE|EXEPATH|FAVORITES|FONTS|HISTORY|HWNDPARENT|INSTDIR|INTERNET_CACHE|LANGUAGE|LOCALAPPDATA|MUSIC|NETHOOD|OUTDIR|PICTURES|PLUGINSDIR|PRINTHOOD|PROFILE|PROGRAMFILES32|PROGRAMFILES64|PROGRAMFILES|QUICKLAUNCH|RECENT|RESOURCES_LOCALIZED|RESOURCES|SENDTO|SMPROGRAMS|SMSTARTUP|STARTMENU|SYSDIR|TEMP|TEMPLATES|VIDEOS|WINDIR)"},n={cN:"constant",b:"\\$+{[a-zA-Z0-9_]+}"},i={cN:"variable",b:"\\$+[a-zA-Z0-9_]+",i:"\\(\\){}"},r={cN:"constant",b:"\\$+\\([a-zA-Z0-9_]+\\)"},o={cN:"params",b:"(ARCHIVE|FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_NORMAL|FILE_ATTRIBUTE_OFFLINE|FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_SYSTEM|FILE_ATTRIBUTE_TEMPORARY|HKCR|HKCU|HKDD|HKEY_CLASSES_ROOT|HKEY_CURRENT_CONFIG|HKEY_CURRENT_USER|HKEY_DYN_DATA|HKEY_LOCAL_MACHINE|HKEY_PERFORMANCE_DATA|HKEY_USERS|HKLM|HKPD|HKU|IDABORT|IDCANCEL|IDIGNORE|IDNO|IDOK|IDRETRY|IDYES|MB_ABORTRETRYIGNORE|MB_DEFBUTTON1|MB_DEFBUTTON2|MB_DEFBUTTON3|MB_DEFBUTTON4|MB_ICONEXCLAMATION|MB_ICONINFORMATION|MB_ICONQUESTION|MB_ICONSTOP|MB_OK|MB_OKCANCEL|MB_RETRYCANCEL|MB_RIGHT|MB_RTLREADING|MB_SETFOREGROUND|MB_TOPMOST|MB_USERICON|MB_YESNO|NORMAL|OFFLINE|READONLY|SHCTX|SHELL_CONTEXT|SYSTEM|TEMPORARY)"},l={cN:"constant",b:"\\!(addincludedir|addplugindir|appendfile|cd|define|delfile|echo|else|endif|error|execute|finalize|getdllversionsystem|ifdef|ifmacrodef|ifmacrondef|ifndef|if|include|insertmacro|macroend|macro|makensis|packhdr|searchparse|searchreplace|tempfile|undef|verbose|warning)"};return{cI:!1,k:{keyword:"Abort AddBrandingImage AddSize AllowRootDirInstall AllowSkipFiles AutoCloseWindow BGFont BGGradient BrandingText BringToFront Call CallInstDLL Caption ChangeUI CheckBitmap ClearErrors CompletedText ComponentText CopyFiles CRCCheck CreateDirectory CreateFont CreateShortCut Delete DeleteINISec DeleteINIStr DeleteRegKey DeleteRegValue DetailPrint DetailsButtonText DirText DirVar DirVerify EnableWindow EnumRegKey EnumRegValue Exch Exec ExecShell ExecWait ExpandEnvStrings File FileBufSize FileClose FileErrorText FileOpen FileRead FileReadByte FileReadUTF16LE FileReadWord FileSeek FileWrite FileWriteByte FileWriteUTF16LE FileWriteWord FindClose FindFirst FindNext FindWindow FlushINI FunctionEnd GetCurInstType GetCurrentAddress GetDlgItem GetDLLVersion GetDLLVersionLocal GetErrorLevel GetFileTime GetFileTimeLocal GetFullPathName GetFunctionAddress GetInstDirError GetLabelAddress GetTempFileName Goto HideWindow Icon IfAbort IfErrors IfFileExists IfRebootFlag IfSilent InitPluginsDir InstallButtonText InstallColors InstallDir InstallDirRegKey InstProgressFlags InstType InstTypeGetText InstTypeSetText IntCmp IntCmpU IntFmt IntOp IsWindow LangString LicenseBkColor LicenseData LicenseForceSelection LicenseLangString LicenseText LoadLanguageFile LockWindow LogSet LogText ManifestDPIAware ManifestSupportedOS MessageBox MiscButtonText Name Nop OutFile Page PageCallbacks PageExEnd Pop Push Quit ReadEnvStr ReadINIStr ReadRegDWORD ReadRegStr Reboot RegDLL Rename RequestExecutionLevel ReserveFile Return RMDir SearchPath SectionEnd SectionGetFlags SectionGetInstTypes SectionGetSize SectionGetText SectionGroupEnd SectionIn SectionSetFlags SectionSetInstTypes SectionSetSize SectionSetText SendMessage SetAutoClose SetBrandingImage SetCompress SetCompressor SetCompressorDictSize SetCtlColors SetCurInstType SetDatablockOptimize SetDateSave SetDetailsPrint SetDetailsView SetErrorLevel SetErrors SetFileAttributes SetFont SetOutPath SetOverwrite SetPluginUnload SetRebootFlag SetRegView SetShellVarContext SetSilent ShowInstDetails ShowUninstDetails ShowWindow SilentInstall SilentUnInstall Sleep SpaceTexts StrCmp StrCmpS StrCpy StrLen SubCaption SubSectionEnd Unicode UninstallButtonText UninstallCaption UninstallIcon UninstallSubCaption UninstallText UninstPage UnRegDLL Var VIAddVersionKey VIFileVersion VIProductVersion WindowIcon WriteINIStr WriteRegBin WriteRegDWORD WriteRegExpandStr WriteRegStr WriteUninstaller XPStyle",literal:"admin all auto both colored current false force hide highest lastused leave listonly none normal notset off on open print show silent silentlog smooth textonly true user "},c:[e.HCM,e.CBCM,{cN:"string",b:'"',e:'"',i:"\\n",c:[{cN:"symbol",b:"\\$(\\\\(n|r|t)|\\$)"},t,n,i,r]},e.C(";","$",{r:0}),{cN:"function",bK:"Function PageEx Section SectionGroup SubSection",e:"$"},l,n,i,r,o,e.NM,{cN:"literal",b:e.IR+"::"+e.IR}]}}); \ No newline at end of file diff --git a/lib/highlight_js/assets/lang/objectivec.js b/lib/highlight_js/assets/lang/objectivec.js new file mode 100644 index 0000000000..2d69980a10 --- /dev/null +++ b/lib/highlight_js/assets/lang/objectivec.js @@ -0,0 +1 @@ +hljs.registerLanguage("objectivec",function(e){var t={cN:"built_in",b:"(AV|CA|CF|CG|CI|MK|MP|NS|UI)\\w+"},i={keyword:"int float while char export sizeof typedef const struct for union unsigned long volatile static bool mutable if do return goto void enum else break extern asm case short default double register explicit signed typename this switch continue wchar_t inline readonly assign readwrite self @synchronized id typeof nonatomic super unichar IBOutlet IBAction strong weak copy in out inout bycopy byref oneway __strong __weak __block __autoreleasing @private @protected @public @try @property @end @throw @catch @finally @autoreleasepool @synthesize @dynamic @selector @optional @required",literal:"false true FALSE TRUE nil YES NO NULL",built_in:"BOOL dispatch_once_t dispatch_queue_t dispatch_sync dispatch_async dispatch_once"},o=/[a-zA-Z@][a-zA-Z0-9_]*/,n="@interface @class @protocol @implementation";return{aliases:["m","mm","objc","obj-c"],k:i,l:o,i:""}]}]},{cN:"class",b:"("+n.split(" ").join("|")+")\\b",e:"({|$)",eE:!0,k:n,l:o,c:[e.UTM]},{cN:"variable",b:"\\."+e.UIR,r:0}]}}); \ No newline at end of file diff --git a/lib/highlight_js/assets/lang/ocaml.js b/lib/highlight_js/assets/lang/ocaml.js new file mode 100644 index 0000000000..95a4e523d8 --- /dev/null +++ b/lib/highlight_js/assets/lang/ocaml.js @@ -0,0 +1 @@ +hljs.registerLanguage("ocaml",function(e){return{aliases:["ml"],k:{keyword:"and as assert asr begin class constraint do done downto else end exception external for fun function functor if in include inherit! inherit initializer land lazy let lor lsl lsr lxor match method!|10 method mod module mutable new object of open! open or private rec sig struct then to try type val! val virtual when while with parser value",built_in:"array bool bytes char exn|5 float int int32 int64 list lazy_t|5 nativeint|5 string unit in_channel out_channel ref",literal:"true false"},i:/\/\/|>>/,l:"[a-z_]\\w*!?",c:[{cN:"literal",b:"\\[(\\|\\|)?\\]|\\(\\)"},e.C("\\(\\*","\\*\\)",{c:["self"]}),{cN:"symbol",b:"'[A-Za-z_](?!')[\\w']*"},{cN:"tag",b:"`[A-Z][\\w']*"},{cN:"type",b:"\\b[A-Z][\\w']*",r:0},{b:"[a-z_]\\w*'[\\w']*"},e.inherit(e.ASM,{cN:"char",r:0}),e.inherit(e.QSM,{i:null}),{cN:"number",b:"\\b(0[xX][a-fA-F0-9_]+[Lln]?|0[oO][0-7_]+[Lln]?|0[bB][01_]+[Lln]?|[0-9][0-9_]*([Lln]|(\\.[0-9_]*)?([eE][-+]?[0-9_]+)?)?)",r:0},{b:/[-=]>/}]}}); \ No newline at end of file diff --git a/lib/highlight_js/assets/lang/oxygene.js b/lib/highlight_js/assets/lang/oxygene.js new file mode 100644 index 0000000000..51c019056c --- /dev/null +++ b/lib/highlight_js/assets/lang/oxygene.js @@ -0,0 +1 @@ +hljs.registerLanguage("oxygene",function(e){var r="abstract add and array as asc aspect assembly async begin break block by case class concat const copy constructor continue create default delegate desc distinct div do downto dynamic each else empty end ensure enum equals event except exit extension external false final finalize finalizer finally flags for forward from function future global group has if implementation implements implies in index inherited inline interface into invariants is iterator join locked locking loop matching method mod module namespace nested new nil not notify nullable of old on operator or order out override parallel params partial pinned private procedure property protected public queryable raise read readonly record reintroduce remove repeat require result reverse sealed select self sequence set shl shr skip static step soft take then to true try tuple type union unit unsafe until uses using var virtual raises volatile where while with write xor yield await mapped deprecated stdcall cdecl pascal register safecall overload library platform reference packed strict published autoreleasepool selector strong weak unretained",t=e.C("{","}",{r:0}),a=e.C("\\(\\*","\\*\\)",{r:10}),n={cN:"string",b:"'",e:"'",c:[{b:"''"}]},o={cN:"string",b:"(#\\d+)+"},i={cN:"function",bK:"function constructor destructor procedure method",e:"[:;]",k:"function constructor|10 destructor|10 procedure|10 method|10",c:[e.TM,{cN:"params",b:"\\(",e:"\\)",k:r,c:[n,o]},t,a]};return{cI:!0,k:r,i:'("|\\$[G-Zg-z]|\\/\\*||->)',c:[t,a,e.CLCM,n,o,e.NM,i,{cN:"class",b:"=\\bclass\\b",e:"end;",k:r,c:[n,o,t,a,e.CLCM,i]}]}}); \ No newline at end of file diff --git a/lib/highlight_js/assets/lang/parser3.js b/lib/highlight_js/assets/lang/parser3.js new file mode 100644 index 0000000000..b8fb48b8df --- /dev/null +++ b/lib/highlight_js/assets/lang/parser3.js @@ -0,0 +1 @@ +hljs.registerLanguage("parser3",function(r){var e=r.C("{","}",{c:["self"]});return{sL:"xml",r:0,c:[r.C("^#","$"),r.C("\\^rem{","}",{r:10,c:[e]}),{cN:"preprocessor",b:"^@(?:BASE|USE|CLASS|OPTIONS)$",r:10},{cN:"title",b:"@[\\w\\-]+\\[[\\w^;\\-]*\\](?:\\[[\\w^;\\-]*\\])?(?:.*)$"},{cN:"variable",b:"\\$\\{?[\\w\\-\\.\\:]+\\}?"},{cN:"keyword",b:"\\^[\\w\\-\\.\\:]+"},{cN:"number",b:"\\^#[0-9a-fA-F]+"},r.CNM]}}); \ No newline at end of file diff --git a/lib/highlight_js/assets/lang/perl.js b/lib/highlight_js/assets/lang/perl.js new file mode 100644 index 0000000000..90dac8c895 --- /dev/null +++ b/lib/highlight_js/assets/lang/perl.js @@ -0,0 +1 @@ +hljs.registerLanguage("perl",function(e){var t="getpwent getservent quotemeta msgrcv scalar kill dbmclose undef lc ma syswrite tr send umask sysopen shmwrite vec qx utime local oct semctl localtime readpipe do return format read sprintf dbmopen pop getpgrp not getpwnam rewinddir qqfileno qw endprotoent wait sethostent bless s|0 opendir continue each sleep endgrent shutdown dump chomp connect getsockname die socketpair close flock exists index shmgetsub for endpwent redo lstat msgctl setpgrp abs exit select print ref gethostbyaddr unshift fcntl syscall goto getnetbyaddr join gmtime symlink semget splice x|0 getpeername recv log setsockopt cos last reverse gethostbyname getgrnam study formline endhostent times chop length gethostent getnetent pack getprotoent getservbyname rand mkdir pos chmod y|0 substr endnetent printf next open msgsnd readdir use unlink getsockopt getpriority rindex wantarray hex system getservbyport endservent int chr untie rmdir prototype tell listen fork shmread ucfirst setprotoent else sysseek link getgrgid shmctl waitpid unpack getnetbyname reset chdir grep split require caller lcfirst until warn while values shift telldir getpwuid my getprotobynumber delete and sort uc defined srand accept package seekdir getprotobyname semop our rename seek if q|0 chroot sysread setpwent no crypt getc chown sqrt write setnetent setpriority foreach tie sin msgget map stat getlogin unless elsif truncate exec keys glob tied closedirioctl socket readlink eval xor readline binmode setservent eof ord bind alarm pipe atan2 getgrent exp time push setgrent gt lt or ne m|0 break given say state when",r={cN:"subst",b:"[$@]\\{",e:"\\}",k:t},s={b:"->{",e:"}"},n={cN:"variable",v:[{b:/\$\d/},{b:/[\$%@](\^\w\b|#\w+(::\w+)*|{\w+}|\w+(::\w*)*)/},{b:/[\$%@][^\s\w{]/,r:0}]},i=e.C("^(__END__|__DATA__)","\\n$",{r:5}),o=[e.BE,r,n],a=[n,e.HCM,i,e.C("^\\=\\w","\\=cut",{eW:!0}),s,{cN:"string",c:o,v:[{b:"q[qwxr]?\\s*\\(",e:"\\)",r:5},{b:"q[qwxr]?\\s*\\[",e:"\\]",r:5},{b:"q[qwxr]?\\s*\\{",e:"\\}",r:5},{b:"q[qwxr]?\\s*\\|",e:"\\|",r:5},{b:"q[qwxr]?\\s*\\<",e:"\\>",r:5},{b:"qw\\s+q",e:"q",r:5},{b:"'",e:"'",c:[e.BE]},{b:'"',e:'"'},{b:"`",e:"`",c:[e.BE]},{b:"{\\w+}",c:[],r:0},{b:"-?\\w+\\s*\\=\\>",c:[],r:0}]},{cN:"number",b:"(\\b0[0-7_]+)|(\\b0x[0-9a-fA-F_]+)|(\\b[1-9][0-9_]*(\\.[0-9_]+)?)|[0_]\\b",r:0},{b:"(\\/\\/|"+e.RSR+"|\\b(split|return|print|reverse|grep)\\b)\\s*",k:"split return print reverse grep",r:0,c:[e.HCM,i,{cN:"regexp",b:"(s|tr|y)/(\\\\.|[^/])*/(\\\\.|[^/])*/[a-z]*",r:10},{cN:"regexp",b:"(m|qr)?/",e:"/[a-z]*",c:[e.BE],r:0}]},{cN:"sub",bK:"sub",e:"(\\s*\\(.*?\\))?[;{]",r:5},{cN:"operator",b:"-\\w\\b",r:0}];return r.c=a,s.c=a,{aliases:["pl"],k:t,c:a}}); \ No newline at end of file diff --git a/lib/highlight_js/assets/lang/pf.js b/lib/highlight_js/assets/lang/pf.js new file mode 100644 index 0000000000..538736d8bd --- /dev/null +++ b/lib/highlight_js/assets/lang/pf.js @@ -0,0 +1 @@ +hljs.registerLanguage("pf",function(t){var o={cN:"variable",b:/\$[\w\d#@][\w\d_]*/},e={cN:"variable",b://};return{aliases:["pf.conf"],l:/[a-z0-9_<>-]+/,k:{built_in:"block match pass load anchor|5 antispoof|10 set table",keyword:"in out log quick on rdomain inet inet6 proto from port os to routeallow-opts divert-packet divert-reply divert-to flags group icmp-typeicmp6-type label once probability recieved-on rtable prio queuetos tag tagged user keep fragment for os dropaf-to|10 binat-to|10 nat-to|10 rdr-to|10 bitmask least-stats random round-robinsource-hash static-portdup-to reply-to route-toparent bandwidth default min max qlimitblock-policy debug fingerprints hostid limit loginterface optimizationreassemble ruleset-optimization basic none profile skip state-defaultsstate-policy timeoutconst counters persistno modulate synproxy state|5 floating if-bound no-sync pflow|10 sloppysource-track global rule max-src-nodes max-src-states max-src-connmax-src-conn-rate overload flushscrub|5 max-mss min-ttl no-df|10 random-id",literal:"all any no-route self urpf-failed egress|5 unknown"},c:[t.HCM,t.NM,t.QSM,o,e]}}); \ No newline at end of file diff --git a/lib/highlight_js/assets/lang/php.js b/lib/highlight_js/assets/lang/php.js new file mode 100644 index 0000000000..5f53dba24d --- /dev/null +++ b/lib/highlight_js/assets/lang/php.js @@ -0,0 +1 @@ +hljs.registerLanguage("php",function(e){var c={cN:"variable",b:"\\$+[a-zA-Z_-ÿ][a-zA-Z0-9_-ÿ]*"},i={cN:"preprocessor",b:/<\?(php)?|\?>/},a={cN:"string",c:[e.BE,i],v:[{b:'b"',e:'"'},{b:"b'",e:"'"},e.inherit(e.ASM,{i:null}),e.inherit(e.QSM,{i:null})]},n={v:[e.BNM,e.CNM]};return{aliases:["php3","php4","php5","php6"],cI:!0,k:"and include_once list abstract global private echo interface as static endswitch array null if endwhile or const for endforeach self var while isset public protected exit foreach throw elseif include __FILE__ empty require_once do xor return parent clone use __CLASS__ __LINE__ else break print eval new catch __METHOD__ case exception default die require __FUNCTION__ enddeclare final try switch continue endfor endif declare unset true false trait goto instanceof insteadof __DIR__ __NAMESPACE__ yield finally",c:[e.CLCM,e.HCM,e.C("/\\*","\\*/",{c:[{cN:"phpdoc",b:"\\s@[A-Za-z]+"},i]}),e.C("__halt_compiler.+?;",!1,{eW:!0,k:"__halt_compiler",l:e.UIR}),{cN:"string",b:"<<<['\"]?\\w+['\"]?$",e:"^\\w+;",c:[e.BE]},i,c,{b:/(::|->)+[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*/},{cN:"function",bK:"function",e:/[;{]/,eE:!0,i:"\\$|\\[|%",c:[e.UTM,{cN:"params",b:"\\(",e:"\\)",c:["self",c,e.CBCM,a,n]}]},{cN:"class",bK:"class interface",e:"{",eE:!0,i:/[:\(\$"]/,c:[{bK:"extends implements"},e.UTM]},{bK:"namespace",e:";",i:/[\.']/,c:[e.UTM]},{bK:"use",e:";",c:[e.UTM]},{b:"=>"},a,n]}}); \ No newline at end of file diff --git a/lib/highlight_js/assets/lang/powershell.js b/lib/highlight_js/assets/lang/powershell.js new file mode 100644 index 0000000000..a9fda41e98 --- /dev/null +++ b/lib/highlight_js/assets/lang/powershell.js @@ -0,0 +1 @@ +hljs.registerLanguage("powershell",function(e){var t={b:"`[\\s\\S]",r:0},r={cN:"variable",v:[{b:/\$[\w\d][\w\d_:]*/}]},o={cN:"string",b:/"/,e:/"/,c:[t,r,{cN:"variable",b:/\$[A-z]/,e:/[^A-z]/}]},a={cN:"string",b:/'/,e:/'/};return{aliases:["ps"],l:/-?[A-z\.\-]+/,cI:!0,k:{keyword:"if else foreach return function do while until elseif begin for trap data dynamicparam end break throw param continue finally in switch exit filter try process catch",literal:"$null $true $false",built_in:"Add-Content Add-History Add-Member Add-PSSnapin Clear-Content Clear-Item Clear-Item Property Clear-Variable Compare-Object ConvertFrom-SecureString Convert-Path ConvertTo-Html ConvertTo-SecureString Copy-Item Copy-ItemProperty Export-Alias Export-Clixml Export-Console Export-Csv ForEach-Object Format-Custom Format-List Format-Table Format-Wide Get-Acl Get-Alias Get-AuthenticodeSignature Get-ChildItem Get-Command Get-Content Get-Credential Get-Culture Get-Date Get-EventLog Get-ExecutionPolicy Get-Help Get-History Get-Host Get-Item Get-ItemProperty Get-Location Get-Member Get-PfxCertificate Get-Process Get-PSDrive Get-PSProvider Get-PSSnapin Get-Service Get-TraceSource Get-UICulture Get-Unique Get-Variable Get-WmiObject Group-Object Import-Alias Import-Clixml Import-Csv Invoke-Expression Invoke-History Invoke-Item Join-Path Measure-Command Measure-Object Move-Item Move-ItemProperty New-Alias New-Item New-ItemProperty New-Object New-PSDrive New-Service New-TimeSpan New-Variable Out-Default Out-File Out-Host Out-Null Out-Printer Out-String Pop-Location Push-Location Read-Host Remove-Item Remove-ItemProperty Remove-PSDrive Remove-PSSnapin Remove-Variable Rename-Item Rename-ItemProperty Resolve-Path Restart-Service Resume-Service Select-Object Select-String Set-Acl Set-Alias Set-AuthenticodeSignature Set-Content Set-Date Set-ExecutionPolicy Set-Item Set-ItemProperty Set-Location Set-PSDebug Set-Service Set-TraceSource Set-Variable Sort-Object Split-Path Start-Service Start-Sleep Start-Transcript Stop-Process Stop-Service Stop-Transcript Suspend-Service Tee-Object Test-Path Trace-Command Update-FormatData Update-TypeData Where-Object Write-Debug Write-Error Write-Host Write-Output Write-Progress Write-Verbose Write-Warning",operator:"-ne -eq -lt -gt -ge -le -not -like -notlike -match -notmatch -contains -notcontains -in -notin -replace"},c:[e.HCM,e.NM,o,a,r]}}); \ No newline at end of file diff --git a/lib/highlight_js/assets/lang/processing.js b/lib/highlight_js/assets/lang/processing.js new file mode 100644 index 0000000000..6c7f0e3cab --- /dev/null +++ b/lib/highlight_js/assets/lang/processing.js @@ -0,0 +1 @@ +hljs.registerLanguage("processing",function(e){return{k:{keyword:"BufferedReader PVector PFont PImage PGraphics HashMap boolean byte char color double float int long String Array FloatDict FloatList IntDict IntList JSONArray JSONObject Object StringDict StringList Table TableRow XML false synchronized int abstract float private char boolean static null if const for true while long throw strictfp finally protected import native final return void enum else break transient new catch instanceof byte super volatile case assert short package default double public try this switch continue throws protected public private",constant:"P2D P3D HALF_PI PI QUARTER_PI TAU TWO_PI",variable:"displayHeight displayWidth mouseY mouseX mousePressed pmouseX pmouseY key keyCode pixels focused frameCount frameRate height width",title:"setup draw",built_in:"size createGraphics beginDraw createShape loadShape PShape arc ellipse line point quad rect triangle bezier bezierDetail bezierPoint bezierTangent curve curveDetail curvePoint curveTangent curveTightness shape shapeMode beginContour beginShape bezierVertex curveVertex endContour endShape quadraticVertex vertex ellipseMode noSmooth rectMode smooth strokeCap strokeJoin strokeWeight mouseClicked mouseDragged mouseMoved mousePressed mouseReleased mouseWheel keyPressed keyPressedkeyReleased keyTyped print println save saveFrame day hour millis minute month second year background clear colorMode fill noFill noStroke stroke alpha blue brightness color green hue lerpColor red saturation modelX modelY modelZ screenX screenY screenZ ambient emissive shininess specular add createImage beginCamera camera endCamera frustum ortho perspective printCamera printProjection cursor frameRate noCursor exit loop noLoop popStyle pushStyle redraw binary boolean byte char float hex int str unbinary unhex join match matchAll nf nfc nfp nfs split splitTokens trim append arrayCopy concat expand reverse shorten sort splice subset box sphere sphereDetail createInput createReader loadBytes loadJSONArray loadJSONObject loadStrings loadTable loadXML open parseXML saveTable selectFolder selectInput beginRaw beginRecord createOutput createWriter endRaw endRecord PrintWritersaveBytes saveJSONArray saveJSONObject saveStream saveStrings saveXML selectOutput popMatrix printMatrix pushMatrix resetMatrix rotate rotateX rotateY rotateZ scale shearX shearY translate ambientLight directionalLight lightFalloff lights lightSpecular noLights normal pointLight spotLight image imageMode loadImage noTint requestImage tint texture textureMode textureWrap blend copy filter get loadPixels set updatePixels blendMode loadShader PShaderresetShader shader createFont loadFont text textFont textAlign textLeading textMode textSize textWidth textAscent textDescent abs ceil constrain dist exp floor lerp log mag map max min norm pow round sq sqrt acos asin atan atan2 cos degrees radians sin tan noise noiseDetail noiseSeed random randomGaussian randomSeed"},c:[e.CLCM,e.CBCM,e.ASM,e.QSM,e.CNM]}}); \ No newline at end of file diff --git a/lib/highlight_js/assets/lang/profile.js b/lib/highlight_js/assets/lang/profile.js new file mode 100644 index 0000000000..06ec826acd --- /dev/null +++ b/lib/highlight_js/assets/lang/profile.js @@ -0,0 +1 @@ +hljs.registerLanguage("profile",function(e){return{c:[e.CNM,{cN:"built_in",b:"{",e:"}$",eB:!0,eE:!0,c:[e.ASM,e.QSM],r:0},{cN:"filename",b:"[a-zA-Z_][\\da-zA-Z_]+\\.[\\da-zA-Z_]{1,3}",e:":",eE:!0},{cN:"header",b:"(ncalls|tottime|cumtime)",e:"$",k:"ncalls tottime|10 cumtime|10 filename",r:10},{cN:"summary",b:"function calls",e:"$",c:[e.CNM],r:10},e.ASM,e.QSM,{cN:"function",b:"\\(",e:"\\)$",c:[e.UTM],r:0}]}}); \ No newline at end of file diff --git a/lib/highlight_js/assets/lang/protobuf.js b/lib/highlight_js/assets/lang/protobuf.js new file mode 100644 index 0000000000..cc43065180 --- /dev/null +++ b/lib/highlight_js/assets/lang/protobuf.js @@ -0,0 +1 @@ +hljs.registerLanguage("protobuf",function(e){return{k:{keyword:"package import option optional required repeated group",built_in:"double float int32 int64 uint32 uint64 sint32 sint64 fixed32 fixed64 sfixed32 sfixed64 bool string bytes",literal:"true false"},c:[e.QSM,e.NM,e.CLCM,{cN:"class",bK:"message enum service",e:/\{/,i:/\n/,c:[e.inherit(e.TM,{starts:{eW:!0,eE:!0}})]},{cN:"function",bK:"rpc",e:/;/,eE:!0,k:"rpc returns"},{cN:"constant",b:/^\s*[A-Z_]+/,e:/\s*=/,eE:!0}]}}); \ No newline at end of file diff --git a/lib/highlight_js/assets/lang/puppet.js b/lib/highlight_js/assets/lang/puppet.js new file mode 100644 index 0000000000..d52bf46433 --- /dev/null +++ b/lib/highlight_js/assets/lang/puppet.js @@ -0,0 +1 @@ +hljs.registerLanguage("puppet",function(e){var s="augeas computer cron exec file filebucket host interface k5login macauthorization mailalias maillist mcx mount nagios_command nagios_contact nagios_contactgroup nagios_host nagios_hostdependency nagios_hostescalation nagios_hostextinfo nagios_hostgroup nagios_service firewall nagios_servicedependency nagios_serviceescalation nagios_serviceextinfo nagios_servicegroup nagios_timeperiod notify package resources router schedule scheduled_task selboolean selmodule service ssh_authorized_key sshkey stage tidy user vlan yumrepo zfs zone zpool",r="alias audit before loglevel noop require subscribe tag owner ensure group mode name|0 changes context force incl lens load_path onlyif provider returns root show_diff type_check en_address ip_address realname command environment hour monute month monthday special target weekday creates cwd ogoutput refresh refreshonly tries try_sleep umask backup checksum content ctime force ignore links mtime purge recurse recurselimit replace selinux_ignore_defaults selrange selrole seltype seluser source souirce_permissions sourceselect validate_cmd validate_replacement allowdupe attribute_membership auth_membership forcelocal gid ia_load_module members system host_aliases ip allowed_trunk_vlans description device_url duplex encapsulation etherchannel native_vlan speed principals allow_root auth_class auth_type authenticate_user k_of_n mechanisms rule session_owner shared options device fstype enable hasrestart directory present absent link atboot blockdevice device dump pass remounts poller_tag use message withpath adminfile allow_virtual allowcdrom category configfiles flavor install_options instance package_settings platform responsefile status uninstall_options vendor unless_system_user unless_uid binary control flags hasstatus manifest pattern restart running start stop allowdupe auths expiry gid groups home iterations key_membership keys managehome membership password password_max_age password_min_age profile_membership profiles project purge_ssh_keys role_membership roles salt shell uid baseurl cost descr enabled enablegroups exclude failovermethod gpgcheck gpgkey http_caching include includepkgs keepalive metadata_expire metalink mirrorlist priority protect proxy proxy_password proxy_username repo_gpgcheck s3_enabled skip_if_unavailable sslcacert sslclientcert sslclientkey sslverify mounted",a={keyword:"and case class default define else elsif false if in import enherits node or true undef unless main settings $string "+s,literal:r,built_in:"architecture augeasversion blockdevices boardmanufacturer boardproductname boardserialnumber cfkey dhcp_servers domain ec2_ ec2_userdata facterversion filesystems ldom fqdn gid hardwareisa hardwaremodel hostname id|0 interfaces ipaddress ipaddress_ ipaddress6 ipaddress6_ iphostnumber is_virtual kernel kernelmajversion kernelrelease kernelversion kernelrelease kernelversion lsbdistcodename lsbdistdescription lsbdistid lsbdistrelease lsbmajdistrelease lsbminordistrelease lsbrelease macaddress macaddress_ macosx_buildversion macosx_productname macosx_productversion macosx_productverson_major macosx_productversion_minor manufacturer memoryfree memorysize netmask metmask_ network_ operatingsystem operatingsystemmajrelease operatingsystemrelease osfamily partitions path physicalprocessorcount processor processorcount productname ps puppetversion rubysitedir rubyversion selinux selinux_config_mode selinux_config_policy selinux_current_mode selinux_current_mode selinux_enforced selinux_policyversion serialnumber sp_ sshdsakey sshecdsakey sshrsakey swapencrypted swapfree swapsize timezone type uniqueid uptime uptime_days uptime_hours uptime_seconds uuid virtual vlans xendomains zfs_version zonenae zones zpool_version"},i=e.C("#","$"),o={cN:"string",c:[e.BE],v:[{b:/'/,e:/'/},{b:/"/,e:/"/}]},n=[o,i,{cN:"keyword",bK:"class",e:"$|;",i:/=/,c:[e.inherit(e.TM,{b:"(::)?[A-Za-z_]\\w*(::\\w+)*"}),i,o]},{cN:"keyword",b:"([a-zA-Z_(::)]+ *\\{)",c:[o,i],r:0},{cN:"keyword",b:"(\\}|\\{)",r:0},{cN:"function",b:"[a-zA-Z_]+\\s*=>"},{cN:"constant",b:"(::)?(\\b[A-Z][a-z_]*(::)?)+",r:0},{cN:"number",b:"(\\b0[0-7_]+)|(\\b0x[0-9a-fA-F_]+)|(\\b[1-9][0-9_]*(\\.[0-9_]+)?)|[0_]\\b",r:0}];return{aliases:["pp"],k:a,c:n}}); \ No newline at end of file diff --git a/lib/highlight_js/assets/lang/python.js b/lib/highlight_js/assets/lang/python.js new file mode 100644 index 0000000000..6547de692c --- /dev/null +++ b/lib/highlight_js/assets/lang/python.js @@ -0,0 +1 @@ +hljs.registerLanguage("python",function(e){var r={cN:"prompt",b:/^(>>>|\.\.\.) /},b={cN:"string",c:[e.BE],v:[{b:/(u|b)?r?'''/,e:/'''/,c:[r],r:10},{b:/(u|b)?r?"""/,e:/"""/,c:[r],r:10},{b:/(u|r|ur)'/,e:/'/,r:10},{b:/(u|r|ur)"/,e:/"/,r:10},{b:/(b|br)'/,e:/'/},{b:/(b|br)"/,e:/"/},e.ASM,e.QSM]},l={cN:"number",r:0,v:[{b:e.BNR+"[lLjJ]?"},{b:"\\b(0o[0-7]+)[lLjJ]?"},{b:e.CNR+"[lLjJ]?"}]},c={cN:"params",b:/\(/,e:/\)/,c:["self",r,l,b]};return{aliases:["py","gyp"],k:{keyword:"and elif is global as in if from raise for except finally print import pass return exec else break not with class assert yield try while continue del or def lambda nonlocal|10 None True False",built_in:"Ellipsis NotImplemented"},i:/(<\/|->|\?)/,c:[r,l,b,e.HCM,{v:[{cN:"function",bK:"def",r:10},{cN:"class",bK:"class"}],e:/:/,i:/[${=;\n]/,c:[e.UTM,c]},{cN:"decorator",b:/@/,e:/$/},{b:/\b(print|exec)\(/}]}}); \ No newline at end of file diff --git a/lib/highlight_js/assets/lang/q.js b/lib/highlight_js/assets/lang/q.js new file mode 100644 index 0000000000..6e4bfc3fb5 --- /dev/null +++ b/lib/highlight_js/assets/lang/q.js @@ -0,0 +1 @@ +hljs.registerLanguage("q",function(e){var s={keyword:"do while select delete by update from",constant:"0b 1b",built_in:"neg not null string reciprocal floor ceiling signum mod xbar xlog and or each scan over prior mmu lsq inv md5 ltime gtime count first var dev med cov cor all any rand sums prds mins maxs fills deltas ratios avgs differ prev next rank reverse iasc idesc asc desc msum mcount mavg mdev xrank mmin mmax xprev rotate distinct group where flip type key til get value attr cut set upsert raze union inter except cross sv vs sublist enlist read0 read1 hopen hclose hdel hsym hcount peach system ltrim rtrim trim lower upper ssr view tables views cols xcols keys xkey xcol xasc xdesc fkeys meta lj aj aj0 ij pj asof uj ww wj wj1 fby xgroup ungroup ej save load rsave rload show csv parse eval min max avg wavg wsum sin cos tan sum",typename:"`float `double int `timestamp `timespan `datetime `time `boolean `symbol `char `byte `short `long `real `month `date `minute `second `guid"};return{aliases:["k","kdb"],k:s,l:/\b(`?)[A-Za-z0-9_]+\b/,c:[e.CLCM,e.QSM,e.CNM]}}); \ No newline at end of file diff --git a/lib/highlight_js/assets/lang/r.js b/lib/highlight_js/assets/lang/r.js new file mode 100644 index 0000000000..bdbaaa1e46 --- /dev/null +++ b/lib/highlight_js/assets/lang/r.js @@ -0,0 +1 @@ +hljs.registerLanguage("r",function(e){var r="([a-zA-Z]|\\.[a-zA-Z.])[a-zA-Z0-9._]*";return{c:[e.HCM,{b:r,l:r,k:{keyword:"function if in break next repeat else for return switch while try tryCatch stop warning require library attach detach source setMethod setGeneric setGroupGeneric setClass ...",literal:"NULL NA TRUE FALSE T F Inf NaN NA_integer_|10 NA_real_|10 NA_character_|10 NA_complex_|10"},r:0},{cN:"number",b:"0[xX][0-9a-fA-F]+[Li]?\\b",r:0},{cN:"number",b:"\\d+(?:[eE][+\\-]?\\d*)?L\\b",r:0},{cN:"number",b:"\\d+\\.(?!\\d)(?:i\\b)?",r:0},{cN:"number",b:"\\d+(?:\\.\\d*)?(?:[eE][+\\-]?\\d*)?i?\\b",r:0},{cN:"number",b:"\\.\\d+(?:[eE][+\\-]?\\d*)?i?\\b",r:0},{b:"`",e:"`",r:0},{cN:"string",c:[e.BE],v:[{b:'"',e:'"'},{b:"'",e:"'"}]}]}}); \ No newline at end of file diff --git a/lib/highlight_js/assets/lang/rib.js b/lib/highlight_js/assets/lang/rib.js new file mode 100644 index 0000000000..e79ffce7ad --- /dev/null +++ b/lib/highlight_js/assets/lang/rib.js @@ -0,0 +1 @@ +hljs.registerLanguage("rib",function(e){return{k:"ArchiveRecord AreaLightSource Atmosphere Attribute AttributeBegin AttributeEnd Basis Begin Blobby Bound Clipping ClippingPlane Color ColorSamples ConcatTransform Cone CoordinateSystem CoordSysTransform CropWindow Curves Cylinder DepthOfField Detail DetailRange Disk Displacement Display End ErrorHandler Exposure Exterior Format FrameAspectRatio FrameBegin FrameEnd GeneralPolygon GeometricApproximation Geometry Hider Hyperboloid Identity Illuminate Imager Interior LightSource MakeCubeFaceEnvironment MakeLatLongEnvironment MakeShadow MakeTexture Matte MotionBegin MotionEnd NuPatch ObjectBegin ObjectEnd ObjectInstance Opacity Option Orientation Paraboloid Patch PatchMesh Perspective PixelFilter PixelSamples PixelVariance Points PointsGeneralPolygons PointsPolygons Polygon Procedural Projection Quantize ReadArchive RelativeDetail ReverseOrientation Rotate Scale ScreenWindow ShadingInterpolation ShadingRate Shutter Sides Skew SolidBegin SolidEnd Sphere SubdivisionMesh Surface TextureCoordinates Torus Transform TransformBegin TransformEnd TransformPoints Translate TrimCurve WorldBegin WorldEnd",i:">|=~|===?|<=>|[<>]=?|\\*\\*|[-/+%^&*~`|]|\\[\\]=?",r="and false then defined module in return redo if BEGIN retry end for true self when next until do begin unless END rescue nil else break undef not super class case require yield alias while ensure elsif or include attr_reader attr_writer attr_accessor",b={cN:"yardoctag",b:"@[A-Za-z]+"},a={cN:"value",b:"#<",e:">"},n=[e.C("#","$",{c:[b]}),e.C("^\\=begin","^\\=end",{c:[b],r:10}),e.C("^__END__","\\n$")],s={cN:"subst",b:"#\\{",e:"}",k:r},t={cN:"string",c:[e.BE,s],v:[{b:/'/,e:/'/},{b:/"/,e:/"/},{b:/`/,e:/`/},{b:"%[qQwWx]?\\(",e:"\\)"},{b:"%[qQwWx]?\\[",e:"\\]"},{b:"%[qQwWx]?{",e:"}"},{b:"%[qQwWx]?<",e:">"},{b:"%[qQwWx]?/",e:"/"},{b:"%[qQwWx]?%",e:"%"},{b:"%[qQwWx]?-",e:"-"},{b:"%[qQwWx]?\\|",e:"\\|"},{b:/\B\?(\\\d{1,3}|\\x[A-Fa-f0-9]{1,2}|\\u[A-Fa-f0-9]{4}|\\?\S)\b/}]},i={cN:"params",b:"\\(",e:"\\)",k:r},d=[t,a,{cN:"class",bK:"class module",e:"$|;",i:/=/,c:[e.inherit(e.TM,{b:"[A-Za-z_]\\w*(::\\w+)*(\\?|\\!)?"}),{cN:"inheritance",b:"<\\s*",c:[{cN:"parent",b:"("+e.IR+"::)?"+e.IR}]}].concat(n)},{cN:"function",bK:"def",e:" |$|;",r:0,c:[e.inherit(e.TM,{b:c}),i].concat(n)},{cN:"constant",b:"(::)?(\\b[A-Z]\\w*(::)?)+",r:0},{cN:"symbol",b:e.UIR+"(\\!|\\?)?:",r:0},{cN:"symbol",b:":",c:[t,{b:c}],r:0},{cN:"number",b:"(\\b0[0-7_]+)|(\\b0x[0-9a-fA-F_]+)|(\\b[1-9][0-9_]*(\\.[0-9_]+)?)|[0_]\\b",r:0},{cN:"variable",b:"(\\$\\W)|((\\$|\\@\\@?)(\\w+))"},{b:"("+e.RSR+")\\s*",c:[a,{cN:"regexp",c:[e.BE,s],i:/\n/,v:[{b:"/",e:"/[a-z]*"},{b:"%r{",e:"}[a-z]*"},{b:"%r\\(",e:"\\)[a-z]*"},{b:"%r!",e:"![a-z]*"},{b:"%r\\[",e:"\\][a-z]*"}]}].concat(n),r:0}].concat(n);s.c=d,i.c=d;var o="[>?]>",l="[\\w#]+\\(\\w+\\):\\d+:\\d+>",u="(\\w+-)?\\d+\\.\\d+\\.\\d(p\\d+)?[^>]+>",N=[{b:/^\s*=>/,cN:"status",starts:{e:"$",c:d}},{cN:"prompt",b:"^("+o+"|"+l+"|"+u+")",starts:{e:"$",c:d}}];return{aliases:["rb","gemspec","podspec","thor","irb"],k:r,c:n.concat(N).concat(d)}}); \ No newline at end of file diff --git a/lib/highlight_js/assets/lang/ruleslanguage.js b/lib/highlight_js/assets/lang/ruleslanguage.js new file mode 100644 index 0000000000..e2741467d7 --- /dev/null +++ b/lib/highlight_js/assets/lang/ruleslanguage.js @@ -0,0 +1 @@ +hljs.registerLanguage("ruleslanguage",function(T){return{k:{keyword:"BILL_PERIOD BILL_START BILL_STOP RS_EFFECTIVE_START RS_EFFECTIVE_STOP RS_JURIS_CODE RS_OPCO_CODE INTDADDATTRIBUTE|5 INTDADDVMSG|5 INTDBLOCKOP|5 INTDBLOCKOPNA|5 INTDCLOSE|5 INTDCOUNT|5 INTDCOUNTSTATUSCODE|5 INTDCREATEMASK|5 INTDCREATEDAYMASK|5 INTDCREATEFACTORMASK|5 INTDCREATEHANDLE|5 INTDCREATEOVERRIDEDAYMASK|5 INTDCREATEOVERRIDEMASK|5 INTDCREATESTATUSCODEMASK|5 INTDCREATETOUPERIOD|5 INTDDELETE|5 INTDDIPTEST|5 INTDEXPORT|5 INTDGETERRORCODE|5 INTDGETERRORMESSAGE|5 INTDISEQUAL|5 INTDJOIN|5 INTDLOAD|5 INTDLOADACTUALCUT|5 INTDLOADDATES|5 INTDLOADHIST|5 INTDLOADLIST|5 INTDLOADLISTDATES|5 INTDLOADLISTENERGY|5 INTDLOADLISTHIST|5 INTDLOADRELATEDCHANNEL|5 INTDLOADSP|5 INTDLOADSTAGING|5 INTDLOADUOM|5 INTDLOADUOMDATES|5 INTDLOADUOMHIST|5 INTDLOADVERSION|5 INTDOPEN|5 INTDREADFIRST|5 INTDREADNEXT|5 INTDRECCOUNT|5 INTDRELEASE|5 INTDREPLACE|5 INTDROLLAVG|5 INTDROLLPEAK|5 INTDSCALAROP|5 INTDSCALE|5 INTDSETATTRIBUTE|5 INTDSETDSTPARTICIPANT|5 INTDSETSTRING|5 INTDSETVALUE|5 INTDSETVALUESTATUS|5 INTDSHIFTSTARTTIME|5 INTDSMOOTH|5 INTDSORT|5 INTDSPIKETEST|5 INTDSUBSET|5 INTDTOU|5 INTDTOURELEASE|5 INTDTOUVALUE|5 INTDUPDATESTATS|5 INTDVALUE|5 STDEV INTDDELETEEX|5 INTDLOADEXACTUAL|5 INTDLOADEXCUT|5 INTDLOADEXDATES|5 INTDLOADEX|5 INTDLOADEXRELATEDCHANNEL|5 INTDSAVEEX|5 MVLOAD|5 MVLOADACCT|5 MVLOADACCTDATES|5 MVLOADACCTHIST|5 MVLOADDATES|5 MVLOADHIST|5 MVLOADLIST|5 MVLOADLISTDATES|5 MVLOADLISTHIST|5 IF FOR NEXT DONE SELECT END CALL ABORT CLEAR CHANNEL FACTOR LIST NUMBER OVERRIDE SET WEEK DISTRIBUTIONNODE ELSE WHEN THEN OTHERWISE IENUM CSV INCLUDE LEAVE RIDER SAVE DELETE NOVALUE SECTION WARN SAVE_UPDATE DETERMINANT LABEL REPORT REVENUE EACH IN FROM TOTAL CHARGE BLOCK AND OR CSV_FILE RATE_CODE AUXILIARY_DEMAND UIDACCOUNT RS BILL_PERIOD_SELECT HOURS_PER_MONTH INTD_ERROR_STOP SEASON_SCHEDULE_NAME ACCOUNTFACTOR ARRAYUPPERBOUND CALLSTOREDPROC GETADOCONNECTION GETCONNECT GETDATASOURCE GETQUALIFIER GETUSERID HASVALUE LISTCOUNT LISTOP LISTUPDATE LISTVALUE PRORATEFACTOR RSPRORATE SETBINPATH SETDBMONITOR WQ_OPEN BILLINGHOURS DATE DATEFROMFLOAT DATETIMEFROMSTRING DATETIMETOSTRING DATETOFLOAT DAY DAYDIFF DAYNAME DBDATETIME HOUR MINUTE MONTH MONTHDIFF MONTHHOURS MONTHNAME ROUNDDATE SAMEWEEKDAYLASTYEAR SECOND WEEKDAY WEEKDIFF YEAR YEARDAY YEARSTR COMPSUM HISTCOUNT HISTMAX HISTMIN HISTMINNZ HISTVALUE MAXNRANGE MAXRANGE MINRANGE COMPIKVA COMPKVA COMPKVARFROMKQKW COMPLF IDATTR FLAG LF2KW LF2KWH MAXKW POWERFACTOR READING2USAGE AVGSEASON MAXSEASON MONTHLYMERGE SEASONVALUE SUMSEASON ACCTREADDATES ACCTTABLELOAD CONFIGADD CONFIGGET CREATEOBJECT CREATEREPORT EMAILCLIENT EXPBLKMDMUSAGE EXPMDMUSAGE EXPORT_USAGE FACTORINEFFECT GETUSERSPECIFIEDSTOP INEFFECT ISHOLIDAY RUNRATE SAVE_PROFILE SETREPORTTITLE USEREXIT WATFORRUNRATE TO TABLE ACOS ASIN ATAN ATAN2 BITAND CEIL COS COSECANT COSH COTANGENT DIVQUOT DIVREM EXP FABS FLOOR FMOD FREPM FREXPN LOG LOG10 MAX MAXN MIN MINNZ MODF POW ROUND ROUND2VALUE ROUNDINT SECANT SIN SINH SQROOT TAN TANH FLOAT2STRING FLOAT2STRINGNC INSTR LEFT LEN LTRIM MID RIGHT RTRIM STRING STRINGNC TOLOWER TOUPPER TRIM NUMDAYS READ_DATE STAGING",built_in:"IDENTIFIER OPTIONS XML_ELEMENT XML_OP XML_ELEMENT_OF DOMDOCCREATE DOMDOCLOADFILE DOMDOCLOADXML DOMDOCSAVEFILE DOMDOCGETROOT DOMDOCADDPI DOMNODEGETNAME DOMNODEGETTYPE DOMNODEGETVALUE DOMNODEGETCHILDCT DOMNODEGETFIRSTCHILD DOMNODEGETSIBLING DOMNODECREATECHILDELEMENT DOMNODESETATTRIBUTE DOMNODEGETCHILDELEMENTCT DOMNODEGETFIRSTCHILDELEMENT DOMNODEGETSIBLINGELEMENT DOMNODEGETATTRIBUTECT DOMNODEGETATTRIBUTEI DOMNODEGETATTRIBUTEBYNAME DOMNODEGETBYNAME"},c:[T.CLCM,T.CBCM,T.ASM,T.QSM,T.CNM,{cN:"array",b:"#[a-zA-Z .]+"}]}}); \ No newline at end of file diff --git a/lib/highlight_js/assets/lang/rust.js b/lib/highlight_js/assets/lang/rust.js new file mode 100644 index 0000000000..dd64320298 --- /dev/null +++ b/lib/highlight_js/assets/lang/rust.js @@ -0,0 +1 @@ +hljs.registerLanguage("rust",function(e){var t=e.inherit(e.CBCM);return t.c.push("self"),{aliases:["rs"],k:{keyword:"alignof as be box break const continue crate do else enum extern false fn for if impl in let loop match mod mut offsetof once priv proc pub pure ref return self sizeof static struct super trait true type typeof unsafe unsized use virtual while yield int i8 i16 i32 i64 uint u8 u32 u64 float f32 f64 str char bool",built_in:"assert! assert_eq! bitflags! bytes! cfg! col! concat! concat_idents! debug_assert! debug_assert_eq! env! panic! file! format! format_args! include_bin! include_str! line! local_data_key! module_path! option_env! print! println! select! stringify! try! unimplemented! unreachable! vec! write! writeln!"},l:e.IR+"!?",i:""}]}}); \ No newline at end of file diff --git a/lib/highlight_js/assets/lang/scala.js b/lib/highlight_js/assets/lang/scala.js new file mode 100644 index 0000000000..4a33dfe7ef --- /dev/null +++ b/lib/highlight_js/assets/lang/scala.js @@ -0,0 +1 @@ +hljs.registerLanguage("scala",function(e){var t={cN:"annotation",b:"@[A-Za-z]+"},a={cN:"string",b:'u?r?"""',e:'"""',r:10},r={cN:"symbol",b:"'\\w[\\w\\d_]*(?!')"},c={cN:"type",b:"\\b[A-Z][A-Za-z0-9_]*",r:0},i={cN:"title",b:/[^0-9\n\t "'(),.`{}\[\]:;][^\n\t "'(),.`{}\[\]:;]+|[^0-9\n\t "'(),.`{}\[\]:;=]/,r:0},l={cN:"class",bK:"class object trait type",e:/[:={\[(\n;]/,c:[{cN:"keyword",bK:"extends with",r:10},i]},n={cN:"function",bK:"def val",e:/[:={\[(\n;]/,c:[i]};return{k:{literal:"true false null",keyword:"type yield lazy override def with val var sealed abstract private trait object if forSome for while throw finally protected extends import final return else break new catch super class case package default try this match continue throws implicit"},c:[e.CLCM,e.CBCM,a,e.QSM,r,c,n,l,e.CNM,t]}}); \ No newline at end of file diff --git a/lib/highlight_js/assets/lang/scheme.js b/lib/highlight_js/assets/lang/scheme.js new file mode 100644 index 0000000000..c6f706bf9f --- /dev/null +++ b/lib/highlight_js/assets/lang/scheme.js @@ -0,0 +1 @@ +hljs.registerLanguage("scheme",function(e){var t="[^\\(\\)\\[\\]\\{\\}\",'`;#|\\\\\\s]+",r="(\\-|\\+)?\\d+([./]\\d+)?",i=r+"[+\\-]"+r+"i",a={built_in:"case-lambda call/cc class define-class exit-handler field import inherit init-field interface let*-values let-values let/ec mixin opt-lambda override protect provide public rename require require-for-syntax syntax syntax-case syntax-error unit/sig unless when with-syntax and begin call-with-current-continuation call-with-input-file call-with-output-file case cond define define-syntax delay do dynamic-wind else for-each if lambda let let* let-syntax letrec letrec-syntax map or syntax-rules ' * + , ,@ - ... / ; < <= = => > >= ` abs acos angle append apply asin assoc assq assv atan boolean? caar cadr call-with-input-file call-with-output-file call-with-values car cdddar cddddr cdr ceiling char->integer char-alphabetic? char-ci<=? char-ci=? char-ci>? char-downcase char-lower-case? char-numeric? char-ready? char-upcase char-upper-case? char-whitespace? char<=? char=? char>? char? close-input-port close-output-port complex? cons cos current-input-port current-output-port denominator display eof-object? eq? equal? eqv? eval even? exact->inexact exact? exp expt floor force gcd imag-part inexact->exact inexact? input-port? integer->char integer? interaction-environment lcm length list list->string list->vector list-ref list-tail list? load log magnitude make-polar make-rectangular make-string make-vector max member memq memv min modulo negative? newline not null-environment null? number->string number? numerator odd? open-input-file open-output-file output-port? pair? peek-char port? positive? procedure? quasiquote quote quotient rational? rationalize read read-char real-part real? remainder reverse round scheme-report-environment set! set-car! set-cdr! sin sqrt string string->list string->number string->symbol string-append string-ci<=? string-ci=? string-ci>? string-copy string-fill! string-length string-ref string-set! string<=? string=? string>? string? substring symbol->string symbol? tan transcript-off transcript-on truncate values vector vector->list vector-fill! vector-length vector-ref vector-set! with-input-from-file with-output-to-file write write-char zero?"},n={cN:"shebang",b:"^#!",e:"$"},c={cN:"literal",b:"(#t|#f|#\\\\"+t+"|#\\\\.)"},l={cN:"number",v:[{b:r,r:0},{b:i,r:0},{b:"#b[0-1]+(/[0-1]+)?"},{b:"#o[0-7]+(/[0-7]+)?"},{b:"#x[0-9a-f]+(/[0-9a-f]+)?"}]},s=e.QSM,o=[e.C(";","$",{r:0}),e.C("#\\|","\\|#")],u={b:t,r:0},p={cN:"variable",b:"'"+t},d={eW:!0,r:0},g={cN:"list",v:[{b:"\\(",e:"\\)"},{b:"\\[",e:"\\]"}],c:[{cN:"keyword",b:t,l:t,k:a},d]};return d.c=[c,l,s,u,p,g].concat(o),{i:/\S/,c:[n,l,s,p,g].concat(o)}}); \ No newline at end of file diff --git a/lib/highlight_js/assets/lang/scilab.js b/lib/highlight_js/assets/lang/scilab.js new file mode 100644 index 0000000000..f97d023358 --- /dev/null +++ b/lib/highlight_js/assets/lang/scilab.js @@ -0,0 +1 @@ +hljs.registerLanguage("scilab",function(e){var n=[e.CNM,{cN:"string",b:"'|\"",e:"'|\"",c:[e.BE,{b:"''"}]}];return{aliases:["sci"],k:{keyword:"abort break case clear catch continue do elseif else endfunction end for functionglobal if pause return resume select try then while%f %F %t %T %pi %eps %inf %nan %e %i %z %s",built_in:"abs and acos asin atan ceil cd chdir clearglobal cosh cos cumprod deff disp errorexec execstr exists exp eye gettext floor fprintf fread fsolve imag isdef isemptyisinfisnan isvector lasterror length load linspace list listfiles log10 log2 logmax min msprintf mclose mopen ones or pathconvert poly printf prod pwd rand realround sinh sin size gsort sprintf sqrt strcat strcmps tring sum system tanh tantype typename warning zeros matrix"},i:'("|#|/\\*|\\s+/\\w+)',c:[{cN:"function",bK:"function endfunction",e:"$",k:"function endfunction|10",c:[e.UTM,{cN:"params",b:"\\(",e:"\\)"}]},{cN:"transposed_variable",b:"[a-zA-Z_][a-zA-Z_0-9]*('+[\\.']*|[\\.']+)",e:"",r:0},{cN:"matrix",b:"\\[",e:"\\]'*[\\.']*",r:0,c:n},e.C("//","$")].concat(n)}}); \ No newline at end of file diff --git a/lib/highlight_js/assets/lang/scss.js b/lib/highlight_js/assets/lang/scss.js new file mode 100644 index 0000000000..d45dc48070 --- /dev/null +++ b/lib/highlight_js/assets/lang/scss.js @@ -0,0 +1 @@ +hljs.registerLanguage("scss",function(e){{var t="[a-zA-Z-][a-zA-Z0-9_-]*",i={cN:"variable",b:"(\\$"+t+")\\b"},r={cN:"function",b:t+"\\(",rB:!0,eE:!0,e:"\\("},o={cN:"hexcolor",b:"#[0-9A-Fa-f]+"};({cN:"attribute",b:"[A-Z\\_\\.\\-]+",e:":",eE:!0,i:"[^\\s]",starts:{cN:"value",eW:!0,eE:!0,c:[r,o,e.CSSNM,e.QSM,e.ASM,e.CBCM,{cN:"important",b:"!important"}]}})}return{cI:!0,i:"[=/|']",c:[e.CLCM,e.CBCM,r,{cN:"id",b:"\\#[A-Za-z0-9_-]+",r:0},{cN:"class",b:"\\.[A-Za-z0-9_-]+",r:0},{cN:"attr_selector",b:"\\[",e:"\\]",i:"$"},{cN:"tag",b:"\\b(a|abbr|acronym|address|area|article|aside|audio|b|base|big|blockquote|body|br|button|canvas|caption|cite|code|col|colgroup|command|datalist|dd|del|details|dfn|div|dl|dt|em|embed|fieldset|figcaption|figure|footer|form|frame|frameset|(h[1-6])|head|header|hgroup|hr|html|i|iframe|img|input|ins|kbd|keygen|label|legend|li|link|map|mark|meta|meter|nav|noframes|noscript|object|ol|optgroup|option|output|p|param|pre|progress|q|rp|rt|ruby|samp|script|section|select|small|span|strike|strong|style|sub|sup|table|tbody|td|textarea|tfoot|th|thead|time|title|tr|tt|ul|var|video)\\b",r:0},{cN:"pseudo",b:":(visited|valid|root|right|required|read-write|read-only|out-range|optional|only-of-type|only-child|nth-of-type|nth-last-of-type|nth-last-child|nth-child|not|link|left|last-of-type|last-child|lang|invalid|indeterminate|in-range|hover|focus|first-of-type|first-line|first-letter|first-child|first|enabled|empty|disabled|default|checked|before|after|active)"},{cN:"pseudo",b:"::(after|before|choices|first-letter|first-line|repeat-index|repeat-item|selection|value)"},i,{cN:"attribute",b:"\\b(z-index|word-wrap|word-spacing|word-break|width|widows|white-space|visibility|vertical-align|unicode-bidi|transition-timing-function|transition-property|transition-duration|transition-delay|transition|transform-style|transform-origin|transform|top|text-underline-position|text-transform|text-shadow|text-rendering|text-overflow|text-indent|text-decoration-style|text-decoration-line|text-decoration-color|text-decoration|text-align-last|text-align|tab-size|table-layout|right|resize|quotes|position|pointer-events|perspective-origin|perspective|page-break-inside|page-break-before|page-break-after|padding-top|padding-right|padding-left|padding-bottom|padding|overflow-y|overflow-x|overflow-wrap|overflow|outline-width|outline-style|outline-offset|outline-color|outline|orphans|order|opacity|object-position|object-fit|normal|none|nav-up|nav-right|nav-left|nav-index|nav-down|min-width|min-height|max-width|max-height|mask|marks|margin-top|margin-right|margin-left|margin-bottom|margin|list-style-type|list-style-position|list-style-image|list-style|line-height|letter-spacing|left|justify-content|initial|inherit|ime-mode|image-orientation|image-resolution|image-rendering|icon|hyphens|height|font-weight|font-variant-ligatures|font-variant|font-style|font-stretch|font-size-adjust|font-size|font-language-override|font-kerning|font-feature-settings|font-family|font|float|flex-wrap|flex-shrink|flex-grow|flex-flow|flex-direction|flex-basis|flex|filter|empty-cells|display|direction|cursor|counter-reset|counter-increment|content|column-width|column-span|column-rule-width|column-rule-style|column-rule-color|column-rule|column-gap|column-fill|column-count|columns|color|clip-path|clip|clear|caption-side|break-inside|break-before|break-after|box-sizing|box-shadow|box-decoration-break|bottom|border-width|border-top-width|border-top-style|border-top-right-radius|border-top-left-radius|border-top-color|border-top|border-style|border-spacing|border-right-width|border-right-style|border-right-color|border-right|border-radius|border-left-width|border-left-style|border-left-color|border-left|border-image-width|border-image-source|border-image-slice|border-image-repeat|border-image-outset|border-image|border-color|border-collapse|border-bottom-width|border-bottom-style|border-bottom-right-radius|border-bottom-left-radius|border-bottom-color|border-bottom|border|background-size|background-repeat|background-position|background-origin|background-image|background-color|background-clip|background-attachment|background|backface-visibility|auto|animation-timing-function|animation-play-state|animation-name|animation-iteration-count|animation-fill-mode|animation-duration|animation-direction|animation-delay|animation|align-self|align-items|align-content)\\b",i:"[^\\s]"},{cN:"value",b:"\\b(whitespace|wait|w-resize|visible|vertical-text|vertical-ideographic|uppercase|upper-roman|upper-alpha|underline|transparent|top|thin|thick|text|text-top|text-bottom|tb-rl|table-header-group|table-footer-group|sw-resize|super|strict|static|square|solid|small-caps|separate|se-resize|scroll|s-resize|rtl|row-resize|ridge|right|repeat|repeat-y|repeat-x|relative|progress|pointer|overline|outside|outset|oblique|nowrap|not-allowed|normal|none|nw-resize|no-repeat|no-drop|newspaper|ne-resize|n-resize|move|middle|medium|ltr|lr-tb|lowercase|lower-roman|lower-alpha|loose|list-item|line|line-through|line-edge|lighter|left|keep-all|justify|italic|inter-word|inter-ideograph|inside|inset|inline|inline-block|inherit|inactive|ideograph-space|ideograph-parenthesis|ideograph-numeric|ideograph-alpha|horizontal|hidden|help|hand|groove|fixed|ellipsis|e-resize|double|dotted|distribute|distribute-space|distribute-letter|distribute-all-lines|disc|disabled|default|decimal|dashed|crosshair|collapse|col-resize|circle|char|center|capitalize|break-word|break-all|bottom|both|bolder|bold|block|bidi-override|below|baseline|auto|always|all-scroll|absolute|table|table-cell)\\b"},{cN:"value",b:":",e:";",c:[r,i,o,e.CSSNM,e.QSM,e.ASM,{cN:"important",b:"!important"}]},{cN:"at_rule",b:"@",e:"[{;]",k:"mixin include extend for if else each while charset import debug media page content font-face namespace warn",c:[r,i,e.QSM,e.ASM,o,e.CSSNM,{cN:"preprocessor",b:"\\s[A-Za-z0-9_.-]+",r:0}]}]}}); \ No newline at end of file diff --git a/lib/highlight_js/assets/lang/smali.js b/lib/highlight_js/assets/lang/smali.js new file mode 100644 index 0000000000..795a401c64 --- /dev/null +++ b/lib/highlight_js/assets/lang/smali.js @@ -0,0 +1 @@ +hljs.registerLanguage("smali",function(r){var t=["add","and","cmp","cmpg","cmpl","const","div","double","float","goto","if","int","long","move","mul","neg","new","nop","not","or","rem","return","shl","shr","sput","sub","throw","ushr","xor"],n=["aget","aput","array","check","execute","fill","filled","goto/16","goto/32","iget","instance","invoke","iput","monitor","packed","sget","sparse"],s=["transient","constructor","abstract","final","synthetic","public","private","protected","static","bridge","system"];return{aliases:["smali"],c:[{cN:"string",b:'"',e:'"',r:0},r.C("#","$",{r:0}),{cN:"keyword",b:"\\s*\\.end\\s[a-zA-Z0-9]*",r:1},{cN:"keyword",b:"^[ ]*\\.[a-zA-Z]*",r:0},{cN:"keyword",b:"\\s:[a-zA-Z_0-9]*",r:0},{cN:"keyword",b:"\\s("+s.join("|")+")",r:1},{cN:"keyword",b:"\\[",r:0},{cN:"instruction",b:"\\s("+t.join("|")+")\\s",r:1},{cN:"instruction",b:"\\s("+t.join("|")+")((\\-|/)[a-zA-Z0-9]+)+\\s",r:10},{cN:"instruction",b:"\\s("+n.join("|")+")((\\-|/)[a-zA-Z0-9]+)*\\s",r:10},{cN:"class",b:"L[^(;:\n]*;",r:0},{cN:"function",b:'( |->)[^(\n ;"]*\\(',r:0},{cN:"function",b:"\\)",r:0},{cN:"variable",b:"[vp][0-9]+",r:0}]}}); \ No newline at end of file diff --git a/lib/highlight_js/assets/lang/smalltalk.js b/lib/highlight_js/assets/lang/smalltalk.js new file mode 100644 index 0000000000..0ffe8c4333 --- /dev/null +++ b/lib/highlight_js/assets/lang/smalltalk.js @@ -0,0 +1 @@ +hljs.registerLanguage("smalltalk",function(a){var r="[a-z][a-zA-Z0-9_]*",s={cN:"char",b:"\\$.{1}"},c={cN:"symbol",b:"#"+a.UIR};return{aliases:["st"],k:"self super nil true false thisContext",c:[a.C('"','"'),a.ASM,{cN:"class",b:"\\b[A-Z][A-Za-z0-9_]*",r:0},{cN:"method",b:r+":",r:0},a.CNM,c,s,{cN:"localvars",b:"\\|[ ]*"+r+"([ ]+"+r+")*[ ]*\\|",rB:!0,e:/\|/,i:/\S/,c:[{b:"(\\|[ ]*)?"+r}]},{cN:"array",b:"\\#\\(",e:"\\)",c:[a.ASM,s,a.CNM,c]}]}}); \ No newline at end of file diff --git a/lib/highlight_js/assets/lang/sml.js b/lib/highlight_js/assets/lang/sml.js new file mode 100644 index 0000000000..31a942095b --- /dev/null +++ b/lib/highlight_js/assets/lang/sml.js @@ -0,0 +1 @@ +hljs.registerLanguage("sml",function(e){return{aliases:["ml"],k:{keyword:"abstype and andalso as case datatype do else end eqtype exception fn fun functor handle if in include infix infixr let local nonfix of op open orelse raise rec sharing sig signature struct structure then type val with withtype where while",built_in:"array bool char exn int list option order real ref string substring vector unit word",literal:"true false NONE SOME LESS EQUAL GREATER nil"},i:/\/\/|>>/,l:"[a-z_]\\w*!?",c:[{cN:"literal",b:"\\[(\\|\\|)?\\]|\\(\\)"},e.C("\\(\\*","\\*\\)",{c:["self"]}),{cN:"symbol",b:"'[A-Za-z_](?!')[\\w']*"},{cN:"tag",b:"`[A-Z][\\w']*"},{cN:"type",b:"\\b[A-Z][\\w']*",r:0},{b:"[a-z_]\\w*'[\\w']*"},e.inherit(e.ASM,{cN:"char",r:0}),e.inherit(e.QSM,{i:null}),{cN:"number",b:"\\b(0[xX][a-fA-F0-9_]+[Lln]?|0[oO][0-7_]+[Lln]?|0[bB][01_]+[Lln]?|[0-9][0-9_]*([Lln]|(\\.[0-9_]*)?([eE][-+]?[0-9_]+)?)?)",r:0},{b:/[-=]>/}]}}); \ No newline at end of file diff --git a/lib/highlight_js/assets/lang/sql.js b/lib/highlight_js/assets/lang/sql.js new file mode 100644 index 0000000000..2ff0644801 --- /dev/null +++ b/lib/highlight_js/assets/lang/sql.js @@ -0,0 +1 @@ +hljs.registerLanguage("sql",function(e){var t=e.C("--","$");return{cI:!0,i:/[<>]/,c:[{cN:"operator",bK:"begin end start commit rollback savepoint lock alter create drop rename call delete do handler insert load replace select truncate update set show pragma grant merge describe use explain help declare prepare execute deallocate savepoint release unlock purge reset change stop analyze cache flush optimize repair kill install uninstall checksum restore check backup revoke",e:/;/,eW:!0,k:{keyword:"abs absolute acos action add adddate addtime aes_decrypt aes_encrypt after aggregate all allocate alter analyze and any are as asc ascii asin assertion at atan atan2 atn2 authorization authors avg backup before begin benchmark between bin binlog bit_and bit_count bit_length bit_or bit_xor both by cache call cascade cascaded case cast catalog ceil ceiling chain change changed char_length character_length charindex charset check checksum checksum_agg choose close coalesce coercibility collate collation collationproperty column columns columns_updated commit compress concat concat_ws concurrent connect connection connection_id consistent constraint constraints continue contributors conv convert convert_tz corresponding cos cot count count_big crc32 create cross cume_dist curdate current current_date current_time current_timestamp current_user cursor curtime data database databases datalength date_add date_format date_sub dateadd datediff datefromparts datename datepart datetime2fromparts datetimeoffsetfromparts day dayname dayofmonth dayofweek dayofyear deallocate declare decode default deferrable deferred degrees delayed delete des_decrypt des_encrypt des_key_file desc describe descriptor diagnostics difference disconnect distinct distinctrow div do domain double drop dumpfile each else elt enclosed encode encrypt end end-exec engine engines eomonth errors escape escaped event eventdata events except exception exec execute exists exp explain export_set extended external extract fast fetch field fields find_in_set first first_value floor flush for force foreign format found found_rows from from_base64 from_days from_unixtime full function get get_format get_lock getdate getutcdate global go goto grant grants greatest group group_concat grouping grouping_id gtid_subset gtid_subtract handler having help hex high_priority hosts hour ident_current ident_incr ident_seed identified identity if ifnull ignore iif ilike immediate in index indicator inet6_aton inet6_ntoa inet_aton inet_ntoa infile initially inner innodb input insert install instr intersect into is is_free_lock is_ipv4 is_ipv4_compat is_ipv4_mapped is_not is_not_null is_used_lock isdate isnull isolation join key kill language last last_day last_insert_id last_value lcase lead leading least leaves left len lenght level like limit lines ln load load_file local localtime localtimestamp locate lock log log10 log2 logfile logs low_priority lower lpad ltrim make_set makedate maketime master master_pos_wait match matched max md5 medium merge microsecond mid min minute mod mode module month monthname mutex name_const names national natural nchar next no no_write_to_binlog not now nullif nvarchar oct octet_length of old_password on only open optimize option optionally or ord order outer outfile output pad parse partial partition password patindex percent_rank percentile_cont percentile_disc period_add period_diff pi plugin position pow power pragma precision prepare preserve primary prior privileges procedure procedure_analyze processlist profile profiles public publishingservername purge quarter query quick quote quotename radians rand read references regexp relative relaylog release release_lock rename repair repeat replace replicate reset restore restrict return returns reverse revoke right rlike rollback rollup round row row_count rows rpad rtrim savepoint schema scroll sec_to_time second section select serializable server session session_user set sha sha1 sha2 share show sign sin size slave sleep smalldatetimefromparts snapshot some soname soundex sounds_like space sql sql_big_result sql_buffer_result sql_cache sql_calc_found_rows sql_no_cache sql_small_result sql_variant_property sqlstate sqrt square start starting status std stddev stddev_pop stddev_samp stdev stdevp stop str str_to_date straight_join strcmp string stuff subdate substr substring subtime subtring_index sum switchoffset sysdate sysdatetime sysdatetimeoffset system_user sysutcdatetime table tables tablespace tan temporary terminated tertiary_weights then time time_format time_to_sec timediff timefromparts timestamp timestampadd timestampdiff timezone_hour timezone_minute to to_base64 to_days to_seconds todatetimeoffset trailing transaction translation trigger trigger_nestlevel triggers trim truncate try_cast try_convert try_parse ucase uncompress uncompressed_length unhex unicode uninstall union unique unix_timestamp unknown unlock update upgrade upped upper usage use user user_resources using utc_date utc_time utc_timestamp uuid uuid_short validate_password_strength value values var var_pop var_samp variables variance varp version view warnings week weekday weekofyear weight_string when whenever where with work write xml xor year yearweek zon",literal:"true false null",built_in:"array bigint binary bit blob boolean char character date dec decimal float int integer interval number numeric real serial smallint varchar varying int8 serial8 text"},c:[{cN:"string",b:"'",e:"'",c:[e.BE,{b:"''"}]},{cN:"string",b:'"',e:'"',c:[e.BE,{b:'""'}]},{cN:"string",b:"`",e:"`",c:[e.BE]},e.CNM,e.CBCM,t]},e.CBCM,t]}}); \ No newline at end of file diff --git a/lib/highlight_js/assets/lang/stata.js b/lib/highlight_js/assets/lang/stata.js new file mode 100644 index 0000000000..98b110022b --- /dev/null +++ b/lib/highlight_js/assets/lang/stata.js @@ -0,0 +1 @@ +hljs.registerLanguage("stata",function(e){return{aliases:["do","ado"],cI:!0,k:"if else in foreach for forv forva forval forvalu forvalue forvalues by bys bysort xi quietly qui capture about ac ac_7 acprplot acprplot_7 adjust ado adopath adoupdate alpha ameans an ano anov anova anova_estat anova_terms anovadef aorder ap app appe appen append arch arch_dr arch_estat arch_p archlm areg areg_p args arima arima_dr arima_estat arima_p as asmprobit asmprobit_estat asmprobit_lf asmprobit_mfx__dlg asmprobit_p ass asse asser assert avplot avplot_7 avplots avplots_7 bcskew0 bgodfrey binreg bip0_lf biplot bipp_lf bipr_lf bipr_p biprobit bitest bitesti bitowt blogit bmemsize boot bootsamp bootstrap bootstrap_8 boxco_l boxco_p boxcox boxcox_6 boxcox_p bprobit br break brier bro brow brows browse brr brrstat bs bs_7 bsampl_w bsample bsample_7 bsqreg bstat bstat_7 bstat_8 bstrap bstrap_7 ca ca_estat ca_p cabiplot camat canon canon_8 canon_8_p canon_estat canon_p cap caprojection capt captu captur capture cat cc cchart cchart_7 cci cd censobs_table centile cf char chdir checkdlgfiles checkestimationsample checkhlpfiles checksum chelp ci cii cl class classutil clear cli clis clist clo clog clog_lf clog_p clogi clogi_sw clogit clogit_lf clogit_p clogitp clogl_sw cloglog clonevar clslistarray cluster cluster_measures cluster_stop cluster_tree cluster_tree_8 clustermat cmdlog cnr cnre cnreg cnreg_p cnreg_sw cnsreg codebook collaps4 collapse colormult_nb colormult_nw compare compress conf confi confir confirm conren cons const constr constra constrai constrain constraint continue contract copy copyright copysource cor corc corr corr2data corr_anti corr_kmo corr_smc corre correl correla correlat correlate corrgram cou coun count cox cox_p cox_sw coxbase coxhaz coxvar cprplot cprplot_7 crc cret cretu cretur creturn cross cs cscript cscript_log csi ct ct_is ctset ctst_5 ctst_st cttost cumsp cumsp_7 cumul cusum cusum_7 cutil d datasig datasign datasigna datasignat datasignatu datasignatur datasignature datetof db dbeta de dec deco decod decode deff des desc descr descri describ describe destring dfbeta dfgls dfuller di di_g dir dirstats dis discard disp disp_res disp_s displ displa display distinct do doe doed doedi doedit dotplot dotplot_7 dprobit drawnorm drop ds ds_util dstdize duplicates durbina dwstat dydx e ed edi edit egen eivreg emdef en enc enco encod encode eq erase ereg ereg_lf ereg_p ereg_sw ereghet ereghet_glf ereghet_glf_sh ereghet_gp ereghet_ilf ereghet_ilf_sh ereghet_ip eret eretu eretur ereturn err erro error est est_cfexist est_cfname est_clickable est_expand est_hold est_table est_unhold est_unholdok estat estat_default estat_summ estat_vce_only esti estimates etodow etof etomdy ex exi exit expand expandcl fac fact facto factor factor_estat factor_p factor_pca_rotated factor_rotate factormat fcast fcast_compute fcast_graph fdades fdadesc fdadescr fdadescri fdadescrib fdadescribe fdasav fdasave fdause fh_st file open file read file close file filefilter fillin find_hlp_file findfile findit findit_7 fit fl fli flis flist for5_0 form forma format fpredict frac_154 frac_adj frac_chk frac_cox frac_ddp frac_dis frac_dv frac_in frac_mun frac_pp frac_pq frac_pv frac_wgt frac_xo fracgen fracplot fracplot_7 fracpoly fracpred fron_ex fron_hn fron_p fron_tn fron_tn2 frontier ftodate ftoe ftomdy ftowdate g gamhet_glf gamhet_gp gamhet_ilf gamhet_ip gamma gamma_d2 gamma_p gamma_sw gammahet gdi_hexagon gdi_spokes ge gen gene gener genera generat generate genrank genstd genvmean gettoken gl gladder gladder_7 glim_l01 glim_l02 glim_l03 glim_l04 glim_l05 glim_l06 glim_l07 glim_l08 glim_l09 glim_l10 glim_l11 glim_l12 glim_lf glim_mu glim_nw1 glim_nw2 glim_nw3 glim_p glim_v1 glim_v2 glim_v3 glim_v4 glim_v5 glim_v6 glim_v7 glm glm_6 glm_p glm_sw glmpred glo glob globa global glogit glogit_8 glogit_p gmeans gnbre_lf gnbreg gnbreg_5 gnbreg_p gomp_lf gompe_sw gomper_p gompertz gompertzhet gomphet_glf gomphet_glf_sh gomphet_gp gomphet_ilf gomphet_ilf_sh gomphet_ip gphdot gphpen gphprint gprefs gprobi_p gprobit gprobit_8 gr gr7 gr_copy gr_current gr_db gr_describe gr_dir gr_draw gr_draw_replay gr_drop gr_edit gr_editviewopts gr_example gr_example2 gr_export gr_print gr_qscheme gr_query gr_read gr_rename gr_replay gr_save gr_set gr_setscheme gr_table gr_undo gr_use graph graph7 grebar greigen greigen_7 greigen_8 grmeanby grmeanby_7 gs_fileinfo gs_filetype gs_graphinfo gs_stat gsort gwood h hadimvo hareg hausman haver he heck_d2 heckma_p heckman heckp_lf heckpr_p heckprob hel help hereg hetpr_lf hetpr_p hetprob hettest hexdump hilite hist hist_7 histogram hlogit hlu hmeans hotel hotelling hprobit hreg hsearch icd9 icd9_ff icd9p iis impute imtest inbase include inf infi infil infile infix inp inpu input ins insheet insp inspe inspec inspect integ inten intreg intreg_7 intreg_p intrg2_ll intrg_ll intrg_ll2 ipolate iqreg ir irf irf_create irfm iri is_svy is_svysum isid istdize ivprob_1_lf ivprob_lf ivprobit ivprobit_p ivreg ivreg_footnote ivtob_1_lf ivtob_lf ivtobit ivtobit_p jackknife jacknife jknife jknife_6 jknife_8 jkstat joinby kalarma1 kap kap_3 kapmeier kappa kapwgt kdensity kdensity_7 keep ksm ksmirnov ktau kwallis l la lab labe label labelbook ladder levels levelsof leverage lfit lfit_p li lincom line linktest lis list lloghet_glf lloghet_glf_sh lloghet_gp lloghet_ilf lloghet_ilf_sh lloghet_ip llogi_sw llogis_p llogist llogistic llogistichet lnorm_lf lnorm_sw lnorma_p lnormal lnormalhet lnormhet_glf lnormhet_glf_sh lnormhet_gp lnormhet_ilf lnormhet_ilf_sh lnormhet_ip lnskew0 loadingplot loc loca local log logi logis_lf logistic logistic_p logit logit_estat logit_p loglogs logrank loneway lookfor lookup lowess lowess_7 lpredict lrecomp lroc lroc_7 lrtest ls lsens lsens_7 lsens_x lstat ltable ltable_7 ltriang lv lvr2plot lvr2plot_7 m ma mac macr macro makecns man manova manova_estat manova_p manovatest mantel mark markin markout marksample mat mat_capp mat_order mat_put_rr mat_rapp mata mata_clear mata_describe mata_drop mata_matdescribe mata_matsave mata_matuse mata_memory mata_mlib mata_mosave mata_rename mata_which matalabel matcproc matlist matname matr matri matrix matrix_input__dlg matstrik mcc mcci md0_ md1_ md1debug_ md2_ md2debug_ mds mds_estat mds_p mdsconfig mdslong mdsmat mdsshepard mdytoe mdytof me_derd mean means median memory memsize meqparse mer merg merge mfp mfx mhelp mhodds minbound mixed_ll mixed_ll_reparm mkassert mkdir mkmat mkspline ml ml_5 ml_adjs ml_bhhhs ml_c_d ml_check ml_clear ml_cnt ml_debug ml_defd ml_e0 ml_e0_bfgs ml_e0_cycle ml_e0_dfp ml_e0i ml_e1 ml_e1_bfgs ml_e1_bhhh ml_e1_cycle ml_e1_dfp ml_e2 ml_e2_cycle ml_ebfg0 ml_ebfr0 ml_ebfr1 ml_ebh0q ml_ebhh0 ml_ebhr0 ml_ebr0i ml_ecr0i ml_edfp0 ml_edfr0 ml_edfr1 ml_edr0i ml_eds ml_eer0i ml_egr0i ml_elf ml_elf_bfgs ml_elf_bhhh ml_elf_cycle ml_elf_dfp ml_elfi ml_elfs ml_enr0i ml_enrr0 ml_erdu0 ml_erdu0_bfgs ml_erdu0_bhhh ml_erdu0_bhhhq ml_erdu0_cycle ml_erdu0_dfp ml_erdu0_nrbfgs ml_exde ml_footnote ml_geqnr ml_grad0 ml_graph ml_hbhhh ml_hd0 ml_hold ml_init ml_inv ml_log ml_max ml_mlout ml_mlout_8 ml_model ml_nb0 ml_opt ml_p ml_plot ml_query ml_rdgrd ml_repor ml_s_e ml_score ml_searc ml_technique ml_unhold mleval mlf_ mlmatbysum mlmatsum mlog mlogi mlogit mlogit_footnote mlogit_p mlopts mlsum mlvecsum mnl0_ mor more mov move mprobit mprobit_lf mprobit_p mrdu0_ mrdu1_ mvdecode mvencode mvreg mvreg_estat n nbreg nbreg_al nbreg_lf nbreg_p nbreg_sw nestreg net newey newey_7 newey_p news nl nl_7 nl_9 nl_9_p nl_p nl_p_7 nlcom nlcom_p nlexp2 nlexp2_7 nlexp2a nlexp2a_7 nlexp3 nlexp3_7 nlgom3 nlgom3_7 nlgom4 nlgom4_7 nlinit nllog3 nllog3_7 nllog4 nllog4_7 nlog_rd nlogit nlogit_p nlogitgen nlogittree nlpred no nobreak noi nois noisi noisil noisily note notes notes_dlg nptrend numlabel numlist odbc old_ver olo olog ologi ologi_sw ologit ologit_p ologitp on one onew onewa oneway op_colnm op_comp op_diff op_inv op_str opr opro oprob oprob_sw oprobi oprobi_p oprobit oprobitp opts_exclusive order orthog orthpoly ou out outf outfi outfil outfile outs outsh outshe outshee outsheet ovtest pac pac_7 palette parse parse_dissim pause pca pca_8 pca_display pca_estat pca_p pca_rotate pcamat pchart pchart_7 pchi pchi_7 pcorr pctile pentium pergram pergram_7 permute permute_8 personal peto_st pkcollapse pkcross pkequiv pkexamine pkexamine_7 pkshape pksumm pksumm_7 pl plo plot plugin pnorm pnorm_7 poisgof poiss_lf poiss_sw poisso_p poisson poisson_estat post postclose postfile postutil pperron pr prais prais_e prais_e2 prais_p predict predictnl preserve print pro prob probi probit probit_estat probit_p proc_time procoverlay procrustes procrustes_estat procrustes_p profiler prog progr progra program prop proportion prtest prtesti pwcorr pwd q\\s qby qbys qchi qchi_7 qladder qladder_7 qnorm qnorm_7 qqplot qqplot_7 qreg qreg_c qreg_p qreg_sw qu quadchk quantile quantile_7 que quer query range ranksum ratio rchart rchart_7 rcof recast reclink recode reg reg3 reg3_p regdw regr regre regre_p2 regres regres_p regress regress_estat regriv_p remap ren rena renam rename renpfix repeat replace report reshape restore ret retu retur return rm rmdir robvar roccomp roccomp_7 roccomp_8 rocf_lf rocfit rocfit_8 rocgold rocplot rocplot_7 roctab roctab_7 rolling rologit rologit_p rot rota rotat rotate rotatemat rreg rreg_p ru run runtest rvfplot rvfplot_7 rvpplot rvpplot_7 sa safesum sample sampsi sav save savedresults saveold sc sca scal scala scalar scatter scm_mine sco scob_lf scob_p scobi_sw scobit scor score scoreplot scoreplot_help scree screeplot screeplot_help sdtest sdtesti se search separate seperate serrbar serrbar_7 serset set set_defaults sfrancia sh she shel shell shewhart shewhart_7 signestimationsample signrank signtest simul simul_7 simulate simulate_8 sktest sleep slogit slogit_d2 slogit_p smooth snapspan so sor sort spearman spikeplot spikeplot_7 spikeplt spline_x split sqreg sqreg_p sret sretu sretur sreturn ssc st st_ct st_hc st_hcd st_hcd_sh st_is st_issys st_note st_promo st_set st_show st_smpl st_subid stack statsby statsby_8 stbase stci stci_7 stcox stcox_estat stcox_fr stcox_fr_ll stcox_p stcox_sw stcoxkm stcoxkm_7 stcstat stcurv stcurve stcurve_7 stdes stem stepwise stereg stfill stgen stir stjoin stmc stmh stphplot stphplot_7 stphtest stphtest_7 stptime strate strate_7 streg streg_sw streset sts sts_7 stset stsplit stsum sttocc sttoct stvary stweib su suest suest_8 sum summ summa summar summari summariz summarize sunflower sureg survcurv survsum svar svar_p svmat svy svy_disp svy_dreg svy_est svy_est_7 svy_estat svy_get svy_gnbreg_p svy_head svy_header svy_heckman_p svy_heckprob_p svy_intreg_p svy_ivreg_p svy_logistic_p svy_logit_p svy_mlogit_p svy_nbreg_p svy_ologit_p svy_oprobit_p svy_poisson_p svy_probit_p svy_regress_p svy_sub svy_sub_7 svy_x svy_x_7 svy_x_p svydes svydes_8 svygen svygnbreg svyheckman svyheckprob svyintreg svyintreg_7 svyintrg svyivreg svylc svylog_p svylogit svymarkout svymarkout_8 svymean svymlog svymlogit svynbreg svyolog svyologit svyoprob svyoprobit svyopts svypois svypois_7 svypoisson svyprobit svyprobt svyprop svyprop_7 svyratio svyreg svyreg_p svyregress svyset svyset_7 svyset_8 svytab svytab_7 svytest svytotal sw sw_8 swcnreg swcox swereg swilk swlogis swlogit swologit swoprbt swpois swprobit swqreg swtobit swweib symmetry symmi symplot symplot_7 syntax sysdescribe sysdir sysuse szroeter ta tab tab1 tab2 tab_or tabd tabdi tabdis tabdisp tabi table tabodds tabodds_7 tabstat tabu tabul tabula tabulat tabulate te tempfile tempname tempvar tes test testnl testparm teststd tetrachoric time_it timer tis tob tobi tobit tobit_p tobit_sw token tokeni tokeniz tokenize tostring total translate translator transmap treat_ll treatr_p treatreg trim trnb_cons trnb_mean trpoiss_d2 trunc_ll truncr_p truncreg tsappend tset tsfill tsline tsline_ex tsreport tsrevar tsrline tsset tssmooth tsunab ttest ttesti tut_chk tut_wait tutorial tw tware_st two twoway twoway__fpfit_serset twoway__function_gen twoway__histogram_gen twoway__ipoint_serset twoway__ipoints_serset twoway__kdensity_gen twoway__lfit_serset twoway__normgen_gen twoway__pci_serset twoway__qfit_serset twoway__scatteri_serset twoway__sunflower_gen twoway_ksm_serset ty typ type typeof u unab unabbrev unabcmd update us use uselabel var var_mkcompanion var_p varbasic varfcast vargranger varirf varirf_add varirf_cgraph varirf_create varirf_ctable varirf_describe varirf_dir varirf_drop varirf_erase varirf_graph varirf_ograph varirf_rename varirf_set varirf_table varlist varlmar varnorm varsoc varstable varstable_w varstable_w2 varwle vce vec vec_fevd vec_mkphi vec_p vec_p_w vecirf_create veclmar veclmar_w vecnorm vecnorm_w vecrank vecstable verinst vers versi versio version view viewsource vif vwls wdatetof webdescribe webseek webuse weib1_lf weib2_lf weib_lf weib_lf0 weibhet_glf weibhet_glf_sh weibhet_glfa weibhet_glfa_sh weibhet_gp weibhet_ilf weibhet_ilf_sh weibhet_ilfa weibhet_ilfa_sh weibhet_ip weibu_sw weibul_p weibull weibull_c weibull_s weibullhet wh whelp whi which whil while wilc_st wilcoxon win wind windo window winexec wntestb wntestb_7 wntestq xchart xchart_7 xcorr xcorr_7 xi xi_6 xmlsav xmlsave xmluse xpose xsh xshe xshel xshell xt_iis xt_tis xtab_p xtabond xtbin_p xtclog xtcloglog xtcloglog_8 xtcloglog_d2 xtcloglog_pa_p xtcloglog_re_p xtcnt_p xtcorr xtdata xtdes xtfront_p xtfrontier xtgee xtgee_elink xtgee_estat xtgee_makeivar xtgee_p xtgee_plink xtgls xtgls_p xthaus xthausman xtht_p xthtaylor xtile xtint_p xtintreg xtintreg_8 xtintreg_d2 xtintreg_p xtivp_1 xtivp_2 xtivreg xtline xtline_ex xtlogit xtlogit_8 xtlogit_d2 xtlogit_fe_p xtlogit_pa_p xtlogit_re_p xtmixed xtmixed_estat xtmixed_p xtnb_fe xtnb_lf xtnbreg xtnbreg_pa_p xtnbreg_refe_p xtpcse xtpcse_p xtpois xtpoisson xtpoisson_d2 xtpoisson_pa_p xtpoisson_refe_p xtpred xtprobit xtprobit_8 xtprobit_d2 xtprobit_re_p xtps_fe xtps_lf xtps_ren xtps_ren_8 xtrar_p xtrc xtrc_p xtrchh xtrefe_p xtreg xtreg_be xtreg_fe xtreg_ml xtreg_pa_p xtreg_re xtregar xtrere_p xtset xtsf_ll xtsf_llti xtsum xttab xttest0 xttobit xttobit_8 xttobit_p xttrans yx yxview__barlike_draw yxview_area_draw yxview_bar_draw yxview_dot_draw yxview_dropline_draw yxview_function_draw yxview_iarrow_draw yxview_ilabels_draw yxview_normal_draw yxview_pcarrow_draw yxview_pcbarrow_draw yxview_pccapsym_draw yxview_pcscatter_draw yxview_pcspike_draw yxview_rarea_draw yxview_rbar_draw yxview_rbarm_draw yxview_rcap_draw yxview_rcapsym_draw yxview_rconnected_draw yxview_rline_draw yxview_rscatter_draw yxview_rspike_draw yxview_spike_draw yxview_sunflower_draw zap_s zinb zinb_llf zinb_plf zip zip_llf zip_p zip_plf zt_ct_5 zt_hc_5 zt_hcd_5 zt_is_5 zt_iss_5 zt_sho_5 zt_smp_5 ztbase_5 ztcox_5 ztdes_5 ztereg_5 ztfill_5 ztgen_5 ztir_5 ztjoin_5 ztnb ztnb_p ztp ztp_p zts_5 ztset_5 ztspli_5 ztsum_5 zttoct_5 ztvary_5 ztweib_5",c:[{cN:"label",v:[{b:"\\$\\{?[a-zA-Z0-9_]+\\}?"},{b:"`[a-zA-Z0-9_]+'"}]},{cN:"string",v:[{b:'`"[^\r\n]*?"\''},{b:'"[^\r\n"]*"'}]},{cN:"literal",v:[{b:"\\b(abs|acos|asin|atan|atan2|atanh|ceil|cloglog|comb|cos|digamma|exp|floor|invcloglog|invlogit|ln|lnfact|lnfactorial|lngamma|log|log10|max|min|mod|reldif|round|sign|sin|sqrt|sum|tan|tanh|trigamma|trunc|betaden|Binomial|binorm|binormal|chi2|chi2tail|dgammapda|dgammapdada|dgammapdadx|dgammapdx|dgammapdxdx|F|Fden|Ftail|gammaden|gammap|ibeta|invbinomial|invchi2|invchi2tail|invF|invFtail|invgammap|invibeta|invnchi2|invnFtail|invnibeta|invnorm|invnormal|invttail|nbetaden|nchi2|nFden|nFtail|nibeta|norm|normal|normalden|normd|npnchi2|tden|ttail|uniform|abbrev|char|index|indexnot|length|lower|ltrim|match|plural|proper|real|regexm|regexr|regexs|reverse|rtrim|string|strlen|strlower|strltrim|strmatch|strofreal|strpos|strproper|strreverse|strrtrim|strtrim|strupper|subinstr|subinword|substr|trim|upper|word|wordcount|_caller|autocode|byteorder|chop|clip|cond|e|epsdouble|epsfloat|group|inlist|inrange|irecode|matrix|maxbyte|maxdouble|maxfloat|maxint|maxlong|mi|minbyte|mindouble|minfloat|minint|minlong|missing|r|recode|replay|return|s|scalar|d|date|day|dow|doy|halfyear|mdy|month|quarter|week|year|d|daily|dofd|dofh|dofm|dofq|dofw|dofy|h|halfyearly|hofd|m|mofd|monthly|q|qofd|quarterly|tin|twithin|w|weekly|wofd|y|yearly|yh|ym|yofd|yq|yw|cholesky|colnumb|colsof|corr|det|diag|diag0cnt|el|get|hadamard|I|inv|invsym|issym|issymmetric|J|matmissing|matuniform|mreldif|nullmat|rownumb|rowsof|sweep|syminv|trace|vec|vecdiag)(?=\\(|$)"}]},e.C("^[ ]*\\*.*$",!1),e.CLCM,e.CBCM]}}); \ No newline at end of file diff --git a/lib/highlight_js/assets/lang/step21.js b/lib/highlight_js/assets/lang/step21.js new file mode 100644 index 0000000000..932f1b1289 --- /dev/null +++ b/lib/highlight_js/assets/lang/step21.js @@ -0,0 +1 @@ +hljs.registerLanguage("step21",function(e){var r="[A-Z_][A-Z0-9_.]*",i="END-ISO-10303-21;",l={literal:"",built_in:"",keyword:"HEADER ENDSEC DATA"},s={cN:"preprocessor",b:"ISO-10303-21;",r:10},t=[e.CLCM,e.CBCM,e.C("/\\*\\*!","\\*/"),e.CNM,e.inherit(e.ASM,{i:null}),e.inherit(e.QSM,{i:null}),{cN:"string",b:"'",e:"'"},{cN:"label",v:[{b:"#",e:"\\d+",i:"\\W"}]}];return{aliases:["p21","step","stp"],cI:!0,l:r,k:l,c:[{cN:"preprocessor",b:i,r:10},s].concat(t)}}); \ No newline at end of file diff --git a/lib/highlight_js/assets/lang/stylus.js b/lib/highlight_js/assets/lang/stylus.js new file mode 100644 index 0000000000..b1250298d8 --- /dev/null +++ b/lib/highlight_js/assets/lang/stylus.js @@ -0,0 +1 @@ +hljs.registerLanguage("stylus",function(t){var e={cN:"variable",b:"\\$"+t.IR},o={cN:"hexcolor",b:"#([a-fA-F0-9]{6}|[a-fA-F0-9]{3})",r:10},i=["charset","css","debug","extend","font-face","for","import","include","media","mixin","page","warn","while"],r=["after","before","first-letter","first-line","active","first-child","focus","hover","lang","link","visited"],n=["a","abbr","address","article","aside","audio","b","blockquote","body","button","canvas","caption","cite","code","dd","del","details","dfn","div","dl","dt","em","fieldset","figcaption","figure","footer","form","h1","h2","h3","h4","h5","h6","header","hgroup","html","i","iframe","img","input","ins","kbd","label","legend","li","mark","menu","nav","object","ol","p","q","quote","samp","section","span","strong","summary","sup","table","tbody","td","textarea","tfoot","th","thead","time","tr","ul","var","video"],a="[\\.\\s\\n\\[\\:,]",l=["align-content","align-items","align-self","animation","animation-delay","animation-direction","animation-duration","animation-fill-mode","animation-iteration-count","animation-name","animation-play-state","animation-timing-function","auto","backface-visibility","background","background-attachment","background-clip","background-color","background-image","background-origin","background-position","background-repeat","background-size","border","border-bottom","border-bottom-color","border-bottom-left-radius","border-bottom-right-radius","border-bottom-style","border-bottom-width","border-collapse","border-color","border-image","border-image-outset","border-image-repeat","border-image-slice","border-image-source","border-image-width","border-left","border-left-color","border-left-style","border-left-width","border-radius","border-right","border-right-color","border-right-style","border-right-width","border-spacing","border-style","border-top","border-top-color","border-top-left-radius","border-top-right-radius","border-top-style","border-top-width","border-width","bottom","box-decoration-break","box-shadow","box-sizing","break-after","break-before","break-inside","caption-side","clear","clip","clip-path","color","column-count","column-fill","column-gap","column-rule","column-rule-color","column-rule-style","column-rule-width","column-span","column-width","columns","content","counter-increment","counter-reset","cursor","direction","display","empty-cells","filter","flex","flex-basis","flex-direction","flex-flow","flex-grow","flex-shrink","flex-wrap","float","font","font-family","font-feature-settings","font-kerning","font-language-override","font-size","font-size-adjust","font-stretch","font-style","font-variant","font-variant-ligatures","font-weight","height","hyphens","icon","image-orientation","image-rendering","image-resolution","ime-mode","inherit","initial","justify-content","left","letter-spacing","line-height","list-style","list-style-image","list-style-position","list-style-type","margin","margin-bottom","margin-left","margin-right","margin-top","marks","mask","max-height","max-width","min-height","min-width","nav-down","nav-index","nav-left","nav-right","nav-up","none","normal","object-fit","object-position","opacity","order","orphans","outline","outline-color","outline-offset","outline-style","outline-width","overflow","overflow-wrap","overflow-x","overflow-y","padding","padding-bottom","padding-left","padding-right","padding-top","page-break-after","page-break-before","page-break-inside","perspective","perspective-origin","pointer-events","position","quotes","resize","right","tab-size","table-layout","text-align","text-align-last","text-decoration","text-decoration-color","text-decoration-line","text-decoration-style","text-indent","text-overflow","text-rendering","text-shadow","text-transform","text-underline-position","top","transform","transform-origin","transform-style","transition","transition-delay","transition-duration","transition-property","transition-timing-function","unicode-bidi","vertical-align","visibility","white-space","widows","width","word-break","word-spacing","word-wrap","z-index"],d=["\\{","\\}","\\?","(\\bReturn\\b)","(\\bEnd\\b)","(\\bend\\b)",";","#\\s","\\*\\s","===\\s","\\|"];return{aliases:["styl"],cI:!1,i:"("+d.join("|")+")",k:"if else for in",c:[t.QSM,t.ASM,t.CLCM,t.CBCM,o,{b:"\\.[a-zA-Z][a-zA-Z0-9_-]*"+a,rB:!0,c:[{cN:"class",b:"\\.[a-zA-Z][a-zA-Z0-9_-]*"}]},{b:"\\#[a-zA-Z][a-zA-Z0-9_-]*"+a,rB:!0,c:[{cN:"id",b:"\\#[a-zA-Z][a-zA-Z0-9_-]*"}]},{b:"\\b("+n.join("|")+")"+a,rB:!0,c:[{cN:"tag",b:"\\b[a-zA-Z][a-zA-Z0-9_-]*"}]},{cN:"pseudo",b:"&?:?:\\b("+r.join("|")+")"+a},{cN:"at_rule",b:"@("+i.join("|")+")\\b"},e,t.CSSNM,t.NM,{cN:"function",b:"\\b[a-zA-Z][a-zA-Z0-9_-]*\\(.*\\)",i:"[\\n]",rB:!0,c:[{cN:"title",b:"\\b[a-zA-Z][a-zA-Z0-9_-]*"},{cN:"params",b:/\(/,e:/\)/,c:[o,e,t.ASM,t.CSSNM,t.NM,t.QSM]}]},{cN:"attribute",b:"\\b("+l.reverse().join("|")+")\\b"}]}}); \ No newline at end of file diff --git a/lib/highlight_js/assets/lang/swift.js b/lib/highlight_js/assets/lang/swift.js new file mode 100644 index 0000000000..b4f3e48b42 --- /dev/null +++ b/lib/highlight_js/assets/lang/swift.js @@ -0,0 +1 @@ +hljs.registerLanguage("swift",function(e){var i={keyword:"class deinit enum extension func import init let protocol static struct subscript typealias var break case continue default do else fallthrough if in for return switch where while as dynamicType is new super self Self Type __COLUMN__ __FILE__ __FUNCTION__ __LINE__ associativity didSet get infix inout left mutating none nonmutating operator override postfix precedence prefix right set unowned unowned safe unsafe weak willSet",literal:"true false nil",built_in:"abs advance alignof alignofValue assert bridgeFromObjectiveC bridgeFromObjectiveCUnconditional bridgeToObjectiveC bridgeToObjectiveCUnconditional c contains count countElements countLeadingZeros debugPrint debugPrintln distance dropFirst dropLast dump encodeBitsAsWords enumerate equal false filter find getBridgedObjectiveCType getVaList indices insertionSort isBridgedToObjectiveC isBridgedVerbatimToObjectiveC isUniquelyReferenced join lexicographicalCompare map max maxElement min minElement nil numericCast partition posix print println quickSort reduce reflect reinterpretCast reverse roundUpToAlignment sizeof sizeofValue sort split startsWith strideof strideofValue swap swift toString transcode true underestimateCount unsafeReflect withExtendedLifetime withObjectAtPlusZero withUnsafePointer withUnsafePointerToObject withUnsafePointers withVaList"},t={cN:"type",b:"\\b[A-Z][\\w']*",r:0},n=e.C("/\\*","\\*/",{c:["self"]}),r={cN:"subst",b:/\\\(/,e:"\\)",k:i,c:[]},s={cN:"number",b:"\\b([\\d_]+(\\.[\\deE_]+)?|0x[a-fA-F0-9_]+(\\.[a-fA-F0-9p_]+)?|0b[01_]+|0o[0-7_]+)\\b",r:0},o=e.inherit(e.QSM,{c:[r,e.BE]});return r.c=[s],{k:i,c:[o,e.CLCM,n,t,s,{cN:"func",bK:"func",e:"{",eE:!0,c:[e.inherit(e.TM,{b:/[A-Za-z$_][0-9A-Za-z$_]*/,i:/\(/}),{cN:"generics",b://,i:/>/},{cN:"params",b:/\(/,e:/\)/,k:i,c:["self",s,o,e.CBCM,{b:":"}],i:/["']/}],i:/\[|%/},{cN:"class",bK:"struct protocol class extension enum",k:i,e:"\\{",eE:!0,c:[e.inherit(e.TM,{b:/[A-Za-z$_][0-9A-Za-z$_]*/})]},{cN:"preprocessor",b:"(@assignment|@class_protocol|@exported|@final|@lazy|@noreturn|@NSCopying|@NSManaged|@objc|@optional|@required|@auto_closure|@noreturn|@IBAction|@IBDesignable|@IBInspectable|@IBOutlet|@infix|@prefix|@postfix)"}]}}); \ No newline at end of file diff --git a/lib/highlight_js/assets/lang/tcl.js b/lib/highlight_js/assets/lang/tcl.js new file mode 100644 index 0000000000..67eb9974af --- /dev/null +++ b/lib/highlight_js/assets/lang/tcl.js @@ -0,0 +1 @@ +hljs.registerLanguage("tcl",function(e){return{aliases:["tk"],k:"after append apply array auto_execok auto_import auto_load auto_mkindex auto_mkindex_old auto_qualify auto_reset bgerror binary break catch cd chan clock close concat continue dde dict encoding eof error eval exec exit expr fblocked fconfigure fcopy file fileevent filename flush for foreach format gets glob global history http if incr info interp join lappend|10 lassign|10 lindex|10 linsert|10 list llength|10 load lrange|10 lrepeat|10 lreplace|10 lreverse|10 lsearch|10 lset|10 lsort|10 mathfunc mathop memory msgcat namespace open package parray pid pkg::create pkg_mkIndex platform platform::shell proc puts pwd read refchan regexp registry regsub|10 rename return safe scan seek set socket source split string subst switch tcl_endOfWord tcl_findLibrary tcl_startOfNextWord tcl_startOfPreviousWord tcl_wordBreakAfter tcl_wordBreakBefore tcltest tclvars tell time tm trace unknown unload unset update uplevel upvar variable vwait while",c:[e.C(";[ \\t]*#","$"),e.C("^[ \\t]*#","$"),{bK:"proc",e:"[\\{]",eE:!0,c:[{cN:"symbol",b:"[ \\t\\n\\r]+(::)?[a-zA-Z_]((::)?[a-zA-Z0-9_])*",e:"[ \\t\\n\\r]",eW:!0,eE:!0}]},{cN:"variable",eE:!0,v:[{b:"\\$(\\{)?(::)?[a-zA-Z_]((::)?[a-zA-Z0-9_])*\\(([a-zA-Z0-9_])*\\)",e:"[^a-zA-Z0-9_\\}\\$]"},{b:"\\$(\\{)?(::)?[a-zA-Z_]((::)?[a-zA-Z0-9_])*",e:"(\\))?[^a-zA-Z0-9_\\}\\$]"}]},{cN:"string",c:[e.BE],v:[e.inherit(e.ASM,{i:null}),e.inherit(e.QSM,{i:null})]},{cN:"number",v:[e.BNM,e.CNM]}]}}); \ No newline at end of file diff --git a/lib/highlight_js/assets/lang/tex.js b/lib/highlight_js/assets/lang/tex.js new file mode 100644 index 0000000000..cec61e254f --- /dev/null +++ b/lib/highlight_js/assets/lang/tex.js @@ -0,0 +1 @@ +hljs.registerLanguage("tex",function(c){var e={cN:"command",b:"\\\\[a-zA-Zа-яА-я]+[\\*]?"},m={cN:"command",b:"\\\\[^a-zA-Zа-яА-я0-9]"},r={cN:"special",b:"[{}\\[\\]\\&#~]",r:0};return{c:[{b:"\\\\[a-zA-Zа-яА-я]+[\\*]? *= *-?\\d*\\.?\\d+(pt|pc|mm|cm|in|dd|cc|ex|em)?",rB:!0,c:[e,m,{cN:"number",b:" *=",e:"-?\\d*\\.?\\d+(pt|pc|mm|cm|in|dd|cc|ex|em)?",eB:!0}],r:10},e,m,r,{cN:"formula",b:"\\$\\$",e:"\\$\\$",c:[e,m,r],r:0},{cN:"formula",b:"\\$",e:"\\$",c:[e,m,r],r:0},c.C("%","$",{r:0})]}}); \ No newline at end of file diff --git a/lib/highlight_js/assets/lang/thrift.js b/lib/highlight_js/assets/lang/thrift.js new file mode 100644 index 0000000000..4c97db0fe5 --- /dev/null +++ b/lib/highlight_js/assets/lang/thrift.js @@ -0,0 +1 @@ +hljs.registerLanguage("thrift",function(e){var t="bool byte i16 i32 i64 double string binary";return{k:{keyword:"namespace const typedef struct enum service exception void oneway set list map required optional",built_in:t,literal:"true false"},c:[e.QSM,e.NM,e.CLCM,e.CBCM,{cN:"class",bK:"struct enum service exception",e:/\{/,i:/\n/,c:[e.inherit(e.TM,{starts:{eW:!0,eE:!0}})]},{b:"\\b(set|list|map)\\s*<",e:">",k:t,c:["self"]}]}}); \ No newline at end of file diff --git a/lib/highlight_js/assets/lang/twig.js b/lib/highlight_js/assets/lang/twig.js new file mode 100644 index 0000000000..3d7f9edbcd --- /dev/null +++ b/lib/highlight_js/assets/lang/twig.js @@ -0,0 +1 @@ +hljs.registerLanguage("twig",function(e){var t={cN:"params",b:"\\(",e:"\\)"},a="attribute block constant cycle date dump include max min parent random range source template_from_string",r={cN:"function",bK:a,r:0,c:[t]},c={cN:"filter",b:/\|[A-Za-z]+:?/,k:"abs batch capitalize convert_encoding date date_modify default escape first format join json_encode keys last length lower merge nl2br number_format raw replace reverse round slice sort split striptags title trim upper url_encode",c:[r]},n="autoescape block do embed extends filter flush for if import include macro sandbox set spaceless use verbatim";return n=n+" "+n.split(" ").map(function(e){return"end"+e}).join(" "),{aliases:["craftcms"],cI:!0,sL:"xml",subLanguageMode:"continuous",c:[e.C(/\{#/,/#}/),{cN:"template_tag",b:/\{%/,e:/%}/,k:n,c:[c,r]},{cN:"variable",b:/\{\{/,e:/}}/,c:[c,r]}]}}); \ No newline at end of file diff --git a/lib/highlight_js/assets/lang/typescript.js b/lib/highlight_js/assets/lang/typescript.js new file mode 100644 index 0000000000..7479cab8b1 --- /dev/null +++ b/lib/highlight_js/assets/lang/typescript.js @@ -0,0 +1 @@ +hljs.registerLanguage("typescript",function(e){return{aliases:["ts"],k:{keyword:"in if for while finally var new function|0 do return void else break catch instanceof with throw case default try this switch continue typeof delete let yield const class public private get set super interface extendsstatic constructor implements enum export import declare type protected",literal:"true false null undefined NaN Infinity",built_in:"eval isFinite isNaN parseFloat parseInt decodeURI decodeURIComponent encodeURI encodeURIComponent escape unescape Object Function Boolean Error EvalError InternalError RangeError ReferenceError StopIteration SyntaxError TypeError URIError Number Math Date String RegExp Array Float32Array Float64Array Int16Array Int32Array Int8Array Uint16Array Uint32Array Uint8Array Uint8ClampedArray ArrayBuffer DataView JSON Intl arguments require module console window document any number boolean string void"},c:[{cN:"pi",b:/^\s*('|")use strict('|")/,r:0},e.ASM,e.QSM,e.CLCM,e.CBCM,e.CNM,{b:"("+e.RSR+"|\\b(case|return|throw)\\b)\\s*",k:"return throw case",c:[e.CLCM,e.CBCM,e.RM,{b:/;/,r:0,sL:"xml"}],r:0},{cN:"function",bK:"function",e:/\{/,eE:!0,c:[e.inherit(e.TM,{b:/[A-Za-z$_][0-9A-Za-z$_]*/}),{cN:"params",b:/\(/,e:/\)/,c:[e.CLCM,e.CBCM],i:/["'\(]/}],i:/\[|%/,r:0},{cN:"constructor",bK:"constructor",e:/\{/,eE:!0,r:10},{cN:"module",bK:"module",e:/\{/,eE:!0},{cN:"interface",bK:"interface",e:/\{/,eE:!0},{b:/\$[(.]/},{b:"\\."+e.IR,r:0}]}}); \ No newline at end of file diff --git a/lib/highlight_js/assets/lang/vala.js b/lib/highlight_js/assets/lang/vala.js new file mode 100644 index 0000000000..35e405f84f --- /dev/null +++ b/lib/highlight_js/assets/lang/vala.js @@ -0,0 +1 @@ +hljs.registerLanguage("vala",function(e){return{k:{keyword:"char uchar unichar int uint long ulong short ushort int8 int16 int32 int64 uint8 uint16 uint32 uint64 float double bool struct enum string void weak unowned owned async signal static abstract interface override while do for foreach else switch case break default return try catch public private protected internal using new this get set const stdout stdin stderr var",built_in:"DBus GLib CCode Gee Object",literal:"false true null"},c:[{cN:"class",bK:"class interface delegate namespace",e:"{",eE:!0,i:"[^,:\\n\\s\\.]",c:[e.UTM]},e.CLCM,e.CBCM,{cN:"string",b:'"""',e:'"""',r:5},e.ASM,e.QSM,e.CNM,{cN:"preprocessor",b:"^#",e:"$",r:2},{cN:"constant",b:" [A-Z_]+ ",r:0}]}}); \ No newline at end of file diff --git a/lib/highlight_js/assets/lang/vbnet.js b/lib/highlight_js/assets/lang/vbnet.js new file mode 100644 index 0000000000..7d7444dc7d --- /dev/null +++ b/lib/highlight_js/assets/lang/vbnet.js @@ -0,0 +1 @@ +hljs.registerLanguage("vbnet",function(e){return{aliases:["vb"],cI:!0,k:{keyword:"addhandler addressof alias and andalso aggregate ansi as assembly auto binary by byref byval call case catch class compare const continue custom declare default delegate dim distinct do each equals else elseif end enum erase error event exit explicit finally for friend from function get global goto group handles if implements imports in inherits interface into is isfalse isnot istrue join key let lib like loop me mid mod module mustinherit mustoverride mybase myclass namespace narrowing new next not notinheritable notoverridable of off on operator option optional or order orelse overloads overridable overrides paramarray partial preserve private property protected public raiseevent readonly redim rem removehandler resume return select set shadows shared skip static step stop structure strict sub synclock take text then throw to try unicode until using when where while widening with withevents writeonly xor",built_in:"boolean byte cbool cbyte cchar cdate cdec cdbl char cint clng cobj csbyte cshort csng cstr ctype date decimal directcast double gettype getxmlnamespace iif integer long object sbyte short single string trycast typeof uinteger ulong ushort",literal:"true false nothing"},i:"//|{|}|endif|gosub|variant|wend",c:[e.inherit(e.QSM,{c:[{b:'""'}]}),e.C("'","$",{rB:!0,c:[{cN:"xmlDocTag",b:"'''|",c:[e.PWM]},{cN:"xmlDocTag",b:"",c:[e.PWM]}]}),e.CNM,{cN:"preprocessor",b:"#",e:"$",k:"if else elseif end region externalsource"}]}}); \ No newline at end of file diff --git a/lib/highlight_js/assets/lang/vbscript-html.js b/lib/highlight_js/assets/lang/vbscript-html.js new file mode 100644 index 0000000000..3d731f4bd0 --- /dev/null +++ b/lib/highlight_js/assets/lang/vbscript-html.js @@ -0,0 +1 @@ +hljs.registerLanguage("vbscript-html",function(){return{sL:"xml",subLanguageMode:"continuous",c:[{b:"<%",e:"%>",sL:"vbscript"}]}}); \ No newline at end of file diff --git a/lib/highlight_js/assets/lang/vbscript.js b/lib/highlight_js/assets/lang/vbscript.js new file mode 100644 index 0000000000..71a645ba42 --- /dev/null +++ b/lib/highlight_js/assets/lang/vbscript.js @@ -0,0 +1 @@ +hljs.registerLanguage("vbscript",function(e){return{aliases:["vbs"],cI:!0,k:{keyword:"call class const dim do loop erase execute executeglobal exit for each next function if then else on error option explicit new private property let get public randomize redim rem select case set stop sub while wend with end to elseif is or xor and not class_initialize class_terminate default preserve in me byval byref step resume goto",built_in:"lcase month vartype instrrev ubound setlocale getobject rgb getref string weekdayname rnd dateadd monthname now day minute isarray cbool round formatcurrency conversions csng timevalue second year space abs clng timeserial fixs len asc isempty maths dateserial atn timer isobject filter weekday datevalue ccur isdate instr datediff formatdatetime replace isnull right sgn array snumeric log cdbl hex chr lbound msgbox ucase getlocale cos cdate cbyte rtrim join hour oct typename trim strcomp int createobject loadpicture tan formatnumber mid scriptenginebuildversion scriptengine split scriptengineminorversion cint sin datepart ltrim sqr scriptenginemajorversion time derived eval date formatpercent exp inputbox left ascw chrw regexp server response request cstr err",literal:"true false null nothing empty"},i:"//",c:[e.inherit(e.QSM,{c:[{b:'""'}]}),e.C(/'/,/$/,{r:0}),e.CNM]}}); \ No newline at end of file diff --git a/lib/highlight_js/assets/lang/verilog.js b/lib/highlight_js/assets/lang/verilog.js new file mode 100644 index 0000000000..1da1fd36b2 --- /dev/null +++ b/lib/highlight_js/assets/lang/verilog.js @@ -0,0 +1 @@ +hljs.registerLanguage("verilog",function(e){return{aliases:["v"],cI:!0,k:{keyword:"always and assign begin buf bufif0 bufif1 case casex casez cmos deassign default defparam disable edge else end endcase endfunction endmodule endprimitive endspecify endtable endtask event for force forever fork function if ifnone initial inout input join macromodule module nand negedge nmos nor not notif0 notif1 or output parameter pmos posedge primitive pulldown pullup rcmos release repeat rnmos rpmos rtran rtranif0 rtranif1 specify specparam table task timescale tran tranif0 tranif1 wait while xnor xor",typename:"highz0 highz1 integer large medium pull0 pull1 real realtime reg scalared signed small strong0 strong1 supply0 supply0 supply1 supply1 time tri tri0 tri1 triand trior trireg vectored wand weak0 weak1 wire wor"},c:[e.CBCM,e.CLCM,e.QSM,{cN:"number",b:"\\b(\\d+'(b|h|o|d|B|H|O|D))?[0-9xzXZ]+",c:[e.BE],r:0},{cN:"typename",b:"\\.\\w+",r:0},{cN:"value",b:"#\\((?!parameter).+\\)"},{cN:"keyword",b:"\\+|-|\\*|/|%|<|>|=|#|`|\\!|&|\\||@|:|\\^|~|\\{|\\}",r:0}]}}); \ No newline at end of file diff --git a/lib/highlight_js/assets/lang/vhdl.js b/lib/highlight_js/assets/lang/vhdl.js new file mode 100644 index 0000000000..d6cae6290b --- /dev/null +++ b/lib/highlight_js/assets/lang/vhdl.js @@ -0,0 +1 @@ +hljs.registerLanguage("vhdl",function(e){var t="\\d(_|\\d)*",r="[eE][-+]?"+t,n=t+"(\\."+t+")?("+r+")?",o="\\w+",i=t+"#"+o+"(\\."+o+")?#("+r+")?",a="\\b("+i+"|"+n+")";return{cI:!0,k:{keyword:"abs access after alias all and architecture array assert attribute begin block body buffer bus case component configuration constant context cover disconnect downto default else elsif end entity exit fairness file for force function generate generic group guarded if impure in inertial inout is label library linkage literal loop map mod nand new next nor not null of on open or others out package port postponed procedure process property protected pure range record register reject release rem report restrict restrict_guarantee return rol ror select sequence severity shared signal sla sll sra srl strong subtype then to transport type unaffected units until use variable vmode vprop vunit wait when while with xnor xor",typename:"boolean bit character severity_level integer time delay_length natural positive string bit_vector file_open_kind file_open_status std_ulogic std_ulogic_vector std_logic std_logic_vector unsigned signed boolean_vector integer_vector real_vector time_vector"},i:"{",c:[e.CBCM,e.C("--","$"),e.QSM,{cN:"number",b:a,r:0},{cN:"literal",b:"'(U|X|0|1|Z|W|L|H|-)'",c:[e.BE]},{cN:"attribute",b:"'[A-Za-z](_?[A-Za-z0-9])*",c:[e.BE]}]}}); \ No newline at end of file diff --git a/lib/highlight_js/assets/lang/vim.js b/lib/highlight_js/assets/lang/vim.js new file mode 100644 index 0000000000..64b321060b --- /dev/null +++ b/lib/highlight_js/assets/lang/vim.js @@ -0,0 +1 @@ +hljs.registerLanguage("vim",function(e){return{l:/[!#@\w]+/,k:{keyword:"N|0 P|0 X|0 a|0 ab abc abo al am an|0 ar arga argd arge argdo argg argl argu as au aug aun b|0 bN ba bad bd be bel bf bl bm bn bo bp br brea breaka breakd breakl bro bufdo buffers bun bw c|0 cN cNf ca cabc caddb cad caddf cal cat cb cc ccl cd ce cex cf cfir cgetb cgete cg changes chd che checkt cl cla clo cm cmapc cme cn cnew cnf cno cnorea cnoreme co col colo com comc comp con conf cope cp cpf cq cr cs cst cu cuna cunme cw d|0 delm deb debugg delc delf dif diffg diffo diffp diffpu diffs diffthis dig di dl dell dj dli do doautoa dp dr ds dsp e|0 ea ec echoe echoh echom echon el elsei em en endfo endf endt endw ene ex exe exi exu f|0 files filet fin fina fini fir fix fo foldc foldd folddoc foldo for fu g|0 go gr grepa gu gv ha h|0 helpf helpg helpt hi hid his i|0 ia iabc if ij il im imapc ime ino inorea inoreme int is isp iu iuna iunme j|0 ju k|0 keepa kee keepj lN lNf l|0 lad laddb laddf la lan lat lb lc lch lcl lcs le lefta let lex lf lfir lgetb lgete lg lgr lgrepa lh ll lla lli lmak lm lmapc lne lnew lnf ln loadk lo loc lockv lol lope lp lpf lr ls lt lu lua luad luaf lv lvimgrepa lw m|0 ma mak map mapc marks mat me menut mes mk mks mksp mkv mkvie mod mz mzf nbc nb nbs n|0 new nm nmapc nme nn nnoreme noa no noh norea noreme norm nu nun nunme ol o|0 om omapc ome on ono onoreme opt ou ounme ow p|0 profd prof pro promptr pc ped pe perld po popu pp pre prev ps pt ptN ptf ptj ptl ptn ptp ptr pts pu pw py3 python3 py3d py3f py pyd pyf q|0 quita qa r|0 rec red redi redr redraws reg res ret retu rew ri rightb rub rubyd rubyf rund ru rv s|0 sN san sa sal sav sb sbN sba sbf sbl sbm sbn sbp sbr scrip scripte scs se setf setg setl sf sfir sh sim sig sil sl sla sm smap smapc sme sn sni sno snor snoreme sor so spelld spe spelli spellr spellu spellw sp spr sre st sta startg startr star stopi stj sts sun sunm sunme sus sv sw sy synti sync t|0 tN tabN tabc tabdo tabe tabf tabfir tabl tabm tabnew tabn tabo tabp tabr tabs tab ta tags tc tcld tclf te tf th tj tl tm tn to tp tr try ts tu u|0 undoj undol una unh unl unlo unm unme uns up v|0 ve verb vert vim vimgrepa vi viu vie vm vmapc vme vne vn vnoreme vs vu vunme windo w|0 wN wa wh wi winc winp wn wp wq wqa ws wu wv x|0 xa xmapc xm xme xn xnoreme xu xunme y|0 z|0 ~ Next Print append abbreviate abclear aboveleft all amenu anoremenu args argadd argdelete argedit argglobal arglocal argument ascii autocmd augroup aunmenu buffer bNext ball badd bdelete behave belowright bfirst blast bmodified bnext botright bprevious brewind break breakadd breakdel breaklist browse bunload bwipeout change cNext cNfile cabbrev cabclear caddbuffer caddexpr caddfile call catch cbuffer cclose center cexpr cfile cfirst cgetbuffer cgetexpr cgetfile chdir checkpath checktime clist clast close cmap cmapclear cmenu cnext cnewer cnfile cnoremap cnoreabbrev cnoremenu copy colder colorscheme command comclear compiler continue confirm copen cprevious cpfile cquit crewind cscope cstag cunmap cunabbrev cunmenu cwindow delete delmarks debug debuggreedy delcommand delfunction diffupdate diffget diffoff diffpatch diffput diffsplit digraphs display deletel djump dlist doautocmd doautoall deletep drop dsearch dsplit edit earlier echo echoerr echohl echomsg else elseif emenu endif endfor endfunction endtry endwhile enew execute exit exusage file filetype find finally finish first fixdel fold foldclose folddoopen folddoclosed foldopen function global goto grep grepadd gui gvim hardcopy help helpfind helpgrep helptags highlight hide history insert iabbrev iabclear ijump ilist imap imapclear imenu inoremap inoreabbrev inoremenu intro isearch isplit iunmap iunabbrev iunmenu join jumps keepalt keepmarks keepjumps lNext lNfile list laddexpr laddbuffer laddfile last language later lbuffer lcd lchdir lclose lcscope left leftabove lexpr lfile lfirst lgetbuffer lgetexpr lgetfile lgrep lgrepadd lhelpgrep llast llist lmake lmap lmapclear lnext lnewer lnfile lnoremap loadkeymap loadview lockmarks lockvar lolder lopen lprevious lpfile lrewind ltag lunmap luado luafile lvimgrep lvimgrepadd lwindow move mark make mapclear match menu menutranslate messages mkexrc mksession mkspell mkvimrc mkview mode mzscheme mzfile nbclose nbkey nbsart next nmap nmapclear nmenu nnoremap nnoremenu noautocmd noremap nohlsearch noreabbrev noremenu normal number nunmap nunmenu oldfiles open omap omapclear omenu only onoremap onoremenu options ounmap ounmenu ownsyntax print profdel profile promptfind promptrepl pclose pedit perl perldo pop popup ppop preserve previous psearch ptag ptNext ptfirst ptjump ptlast ptnext ptprevious ptrewind ptselect put pwd py3do py3file python pydo pyfile quit quitall qall read recover redo redir redraw redrawstatus registers resize retab return rewind right rightbelow ruby rubydo rubyfile rundo runtime rviminfo substitute sNext sandbox sargument sall saveas sbuffer sbNext sball sbfirst sblast sbmodified sbnext sbprevious sbrewind scriptnames scriptencoding scscope set setfiletype setglobal setlocal sfind sfirst shell simalt sign silent sleep slast smagic smapclear smenu snext sniff snomagic snoremap snoremenu sort source spelldump spellgood spellinfo spellrepall spellundo spellwrong split sprevious srewind stop stag startgreplace startreplace startinsert stopinsert stjump stselect sunhide sunmap sunmenu suspend sview swapname syntax syntime syncbind tNext tabNext tabclose tabedit tabfind tabfirst tablast tabmove tabnext tabonly tabprevious tabrewind tag tcl tcldo tclfile tearoff tfirst throw tjump tlast tmenu tnext topleft tprevious trewind tselect tunmenu undo undojoin undolist unabbreviate unhide unlet unlockvar unmap unmenu unsilent update vglobal version verbose vertical vimgrep vimgrepadd visual viusage view vmap vmapclear vmenu vnew vnoremap vnoremenu vsplit vunmap vunmenu write wNext wall while winsize wincmd winpos wnext wprevious wqall wsverb wundo wviminfo xit xall xmapclear xmap xmenu xnoremap xnoremenu xunmap xunmenu yank",built_in:"abs acos add and append argc argidx argv asin atan atan2 browse browsedir bufexists buflisted bufloaded bufname bufnr bufwinnr byte2line byteidx call ceil changenr char2nr cindent clearmatches col complete complete_add complete_check confirm copy cos cosh count cscope_connection cursor deepcopy delete did_filetype diff_filler diff_hlID empty escape eval eventhandler executable exists exp expand extend feedkeys filereadable filewritable filter finddir findfile float2nr floor fmod fnameescape fnamemodify foldclosed foldclosedend foldlevel foldtext foldtextresult foreground function garbagecollect get getbufline getbufvar getchar getcharmod getcmdline getcmdpos getcmdtype getcwd getfontname getfperm getfsize getftime getftype getline getloclist getmatches getpid getpos getqflist getreg getregtype gettabvar gettabwinvar getwinposx getwinposy getwinvar glob globpath has has_key haslocaldir hasmapto histadd histdel histget histnr hlexists hlID hostname iconv indent index input inputdialog inputlist inputrestore inputsave inputsecret insert invert isdirectory islocked items join keys len libcall libcallnr line line2byte lispindent localtime log log10 luaeval map maparg mapcheck match matchadd matcharg matchdelete matchend matchlist matchstr max min mkdir mode mzeval nextnonblank nr2char or pathshorten pow prevnonblank printf pumvisible py3eval pyeval range readfile reltime reltimestr remote_expr remote_foreground remote_peek remote_read remote_send remove rename repeat resolve reverse round screenattr screenchar screencol screenrow search searchdecl searchpair searchpairpos searchpos server2client serverlist setbufvar setcmdpos setline setloclist setmatches setpos setqflist setreg settabvar settabwinvar setwinvar sha256 shellescape shiftwidth simplify sin sinh sort soundfold spellbadword spellsuggest split sqrt str2float str2nr strchars strdisplaywidth strftime stridx string strlen strpart strridx strtrans strwidth submatch substitute synconcealed synID synIDattr synIDtrans synstack system tabpagebuflist tabpagenr tabpagewinnr tagfiles taglist tan tanh tempname tolower toupper tr trunc type undofile undotree values virtcol visualmode wildmenumode winbufnr wincol winheight winline winnr winrestcmd winrestview winsaveview winwidth writefile xor"},i:/[{:]/,c:[e.NM,e.ASM,{cN:"string",b:/"((\\")|[^"\n])*("|\n)/},{cN:"variable",b:/[bwtglsav]:[\w\d_]*/},{cN:"function",bK:"function function!",e:"$",r:0,c:[e.TM,{cN:"params",b:"\\(",e:"\\)"}]}]}}); \ No newline at end of file diff --git a/lib/highlight_js/assets/lang/x86asm.js b/lib/highlight_js/assets/lang/x86asm.js new file mode 100644 index 0000000000..294e6cae31 --- /dev/null +++ b/lib/highlight_js/assets/lang/x86asm.js @@ -0,0 +1 @@ +hljs.registerLanguage("x86asm",function(s){return{cI:!0,l:"\\.?"+s.IR,k:{keyword:"lock rep repe repz repne repnz xaquire xrelease bnd nobnd aaa aad aam aas adc add and arpl bb0_reset bb1_reset bound bsf bsr bswap bt btc btr bts call cbw cdq cdqe clc cld cli clts cmc cmp cmpsb cmpsd cmpsq cmpsw cmpxchg cmpxchg486 cmpxchg8b cmpxchg16b cpuid cpu_read cpu_write cqo cwd cwde daa das dec div dmint emms enter equ f2xm1 fabs fadd faddp fbld fbstp fchs fclex fcmovb fcmovbe fcmove fcmovnb fcmovnbe fcmovne fcmovnu fcmovu fcom fcomi fcomip fcomp fcompp fcos fdecstp fdisi fdiv fdivp fdivr fdivrp femms feni ffree ffreep fiadd ficom ficomp fidiv fidivr fild fimul fincstp finit fist fistp fisttp fisub fisubr fld fld1 fldcw fldenv fldl2e fldl2t fldlg2 fldln2 fldpi fldz fmul fmulp fnclex fndisi fneni fninit fnop fnsave fnstcw fnstenv fnstsw fpatan fprem fprem1 fptan frndint frstor fsave fscale fsetpm fsin fsincos fsqrt fst fstcw fstenv fstp fstsw fsub fsubp fsubr fsubrp ftst fucom fucomi fucomip fucomp fucompp fxam fxch fxtract fyl2x fyl2xp1 hlt ibts icebp idiv imul in inc incbin insb insd insw int int01 int1 int03 int3 into invd invpcid invlpg invlpga iret iretd iretq iretw jcxz jecxz jrcxz jmp jmpe lahf lar lds lea leave les lfence lfs lgdt lgs lidt lldt lmsw loadall loadall286 lodsb lodsd lodsq lodsw loop loope loopne loopnz loopz lsl lss ltr mfence monitor mov movd movq movsb movsd movsq movsw movsx movsxd movzx mul mwait neg nop not or out outsb outsd outsw packssdw packsswb packuswb paddb paddd paddsb paddsiw paddsw paddusb paddusw paddw pand pandn pause paveb pavgusb pcmpeqb pcmpeqd pcmpeqw pcmpgtb pcmpgtd pcmpgtw pdistib pf2id pfacc pfadd pfcmpeq pfcmpge pfcmpgt pfmax pfmin pfmul pfrcp pfrcpit1 pfrcpit2 pfrsqit1 pfrsqrt pfsub pfsubr pi2fd pmachriw pmaddwd pmagw pmulhriw pmulhrwa pmulhrwc pmulhw pmullw pmvgezb pmvlzb pmvnzb pmvzb pop popa popad popaw popf popfd popfq popfw por prefetch prefetchw pslld psllq psllw psrad psraw psrld psrlq psrlw psubb psubd psubsb psubsiw psubsw psubusb psubusw psubw punpckhbw punpckhdq punpckhwd punpcklbw punpckldq punpcklwd push pusha pushad pushaw pushf pushfd pushfq pushfw pxor rcl rcr rdshr rdmsr rdpmc rdtsc rdtscp ret retf retn rol ror rdm rsdc rsldt rsm rsts sahf sal salc sar sbb scasb scasd scasq scasw sfence sgdt shl shld shr shrd sidt sldt skinit smi smint smintold smsw stc std sti stosb stosd stosq stosw str sub svdc svldt svts swapgs syscall sysenter sysexit sysret test ud0 ud1 ud2b ud2 ud2a umov verr verw fwait wbinvd wrshr wrmsr xadd xbts xchg xlatb xlat xor cmove cmovz cmovne cmovnz cmova cmovnbe cmovae cmovnb cmovb cmovnae cmovbe cmovna cmovg cmovnle cmovge cmovnl cmovl cmovnge cmovle cmovng cmovc cmovnc cmovo cmovno cmovs cmovns cmovp cmovpe cmovnp cmovpo je jz jne jnz ja jnbe jae jnb jb jnae jbe jna jg jnle jge jnl jl jnge jle jng jc jnc jo jno js jns jpo jnp jpe jp sete setz setne setnz seta setnbe setae setnb setnc setb setnae setcset setbe setna setg setnle setge setnl setl setnge setle setng sets setns seto setno setpe setp setpo setnp addps addss andnps andps cmpeqps cmpeqss cmpleps cmpless cmpltps cmpltss cmpneqps cmpneqss cmpnleps cmpnless cmpnltps cmpnltss cmpordps cmpordss cmpunordps cmpunordss cmpps cmpss comiss cvtpi2ps cvtps2pi cvtsi2ss cvtss2si cvttps2pi cvttss2si divps divss ldmxcsr maxps maxss minps minss movaps movhps movlhps movlps movhlps movmskps movntps movss movups mulps mulss orps rcpps rcpss rsqrtps rsqrtss shufps sqrtps sqrtss stmxcsr subps subss ucomiss unpckhps unpcklps xorps fxrstor fxrstor64 fxsave fxsave64 xgetbv xsetbv xsave xsave64 xsaveopt xsaveopt64 xrstor xrstor64 prefetchnta prefetcht0 prefetcht1 prefetcht2 maskmovq movntq pavgb pavgw pextrw pinsrw pmaxsw pmaxub pminsw pminub pmovmskb pmulhuw psadbw pshufw pf2iw pfnacc pfpnacc pi2fw pswapd maskmovdqu clflush movntdq movnti movntpd movdqa movdqu movdq2q movq2dq paddq pmuludq pshufd pshufhw pshuflw pslldq psrldq psubq punpckhqdq punpcklqdq addpd addsd andnpd andpd cmpeqpd cmpeqsd cmplepd cmplesd cmpltpd cmpltsd cmpneqpd cmpneqsd cmpnlepd cmpnlesd cmpnltpd cmpnltsd cmpordpd cmpordsd cmpunordpd cmpunordsd cmppd comisd cvtdq2pd cvtdq2ps cvtpd2dq cvtpd2pi cvtpd2ps cvtpi2pd cvtps2dq cvtps2pd cvtsd2si cvtsd2ss cvtsi2sd cvtss2sd cvttpd2pi cvttpd2dq cvttps2dq cvttsd2si divpd divsd maxpd maxsd minpd minsd movapd movhpd movlpd movmskpd movupd mulpd mulsd orpd shufpd sqrtpd sqrtsd subpd subsd ucomisd unpckhpd unpcklpd xorpd addsubpd addsubps haddpd haddps hsubpd hsubps lddqu movddup movshdup movsldup clgi stgi vmcall vmclear vmfunc vmlaunch vmload vmmcall vmptrld vmptrst vmread vmresume vmrun vmsave vmwrite vmxoff vmxon invept invvpid pabsb pabsw pabsd palignr phaddw phaddd phaddsw phsubw phsubd phsubsw pmaddubsw pmulhrsw pshufb psignb psignw psignd extrq insertq movntsd movntss lzcnt blendpd blendps blendvpd blendvps dppd dpps extractps insertps movntdqa mpsadbw packusdw pblendvb pblendw pcmpeqq pextrb pextrd pextrq phminposuw pinsrb pinsrd pinsrq pmaxsb pmaxsd pmaxud pmaxuw pminsb pminsd pminud pminuw pmovsxbw pmovsxbd pmovsxbq pmovsxwd pmovsxwq pmovsxdq pmovzxbw pmovzxbd pmovzxbq pmovzxwd pmovzxwq pmovzxdq pmuldq pmulld ptest roundpd roundps roundsd roundss crc32 pcmpestri pcmpestrm pcmpistri pcmpistrm pcmpgtq popcnt getsec pfrcpv pfrsqrtv movbe aesenc aesenclast aesdec aesdeclast aesimc aeskeygenassist vaesenc vaesenclast vaesdec vaesdeclast vaesimc vaeskeygenassist vaddpd vaddps vaddsd vaddss vaddsubpd vaddsubps vandpd vandps vandnpd vandnps vblendpd vblendps vblendvpd vblendvps vbroadcastss vbroadcastsd vbroadcastf128 vcmpeq_ospd vcmpeqpd vcmplt_ospd vcmpltpd vcmple_ospd vcmplepd vcmpunord_qpd vcmpunordpd vcmpneq_uqpd vcmpneqpd vcmpnlt_uspd vcmpnltpd vcmpnle_uspd vcmpnlepd vcmpord_qpd vcmpordpd vcmpeq_uqpd vcmpnge_uspd vcmpngepd vcmpngt_uspd vcmpngtpd vcmpfalse_oqpd vcmpfalsepd vcmpneq_oqpd vcmpge_ospd vcmpgepd vcmpgt_ospd vcmpgtpd vcmptrue_uqpd vcmptruepd vcmplt_oqpd vcmple_oqpd vcmpunord_spd vcmpneq_uspd vcmpnlt_uqpd vcmpnle_uqpd vcmpord_spd vcmpeq_uspd vcmpnge_uqpd vcmpngt_uqpd vcmpfalse_ospd vcmpneq_ospd vcmpge_oqpd vcmpgt_oqpd vcmptrue_uspd vcmppd vcmpeq_osps vcmpeqps vcmplt_osps vcmpltps vcmple_osps vcmpleps vcmpunord_qps vcmpunordps vcmpneq_uqps vcmpneqps vcmpnlt_usps vcmpnltps vcmpnle_usps vcmpnleps vcmpord_qps vcmpordps vcmpeq_uqps vcmpnge_usps vcmpngeps vcmpngt_usps vcmpngtps vcmpfalse_oqps vcmpfalseps vcmpneq_oqps vcmpge_osps vcmpgeps vcmpgt_osps vcmpgtps vcmptrue_uqps vcmptrueps vcmplt_oqps vcmple_oqps vcmpunord_sps vcmpneq_usps vcmpnlt_uqps vcmpnle_uqps vcmpord_sps vcmpeq_usps vcmpnge_uqps vcmpngt_uqps vcmpfalse_osps vcmpneq_osps vcmpge_oqps vcmpgt_oqps vcmptrue_usps vcmpps vcmpeq_ossd vcmpeqsd vcmplt_ossd vcmpltsd vcmple_ossd vcmplesd vcmpunord_qsd vcmpunordsd vcmpneq_uqsd vcmpneqsd vcmpnlt_ussd vcmpnltsd vcmpnle_ussd vcmpnlesd vcmpord_qsd vcmpordsd vcmpeq_uqsd vcmpnge_ussd vcmpngesd vcmpngt_ussd vcmpngtsd vcmpfalse_oqsd vcmpfalsesd vcmpneq_oqsd vcmpge_ossd vcmpgesd vcmpgt_ossd vcmpgtsd vcmptrue_uqsd vcmptruesd vcmplt_oqsd vcmple_oqsd vcmpunord_ssd vcmpneq_ussd vcmpnlt_uqsd vcmpnle_uqsd vcmpord_ssd vcmpeq_ussd vcmpnge_uqsd vcmpngt_uqsd vcmpfalse_ossd vcmpneq_ossd vcmpge_oqsd vcmpgt_oqsd vcmptrue_ussd vcmpsd vcmpeq_osss vcmpeqss vcmplt_osss vcmpltss vcmple_osss vcmpless vcmpunord_qss vcmpunordss vcmpneq_uqss vcmpneqss vcmpnlt_usss vcmpnltss vcmpnle_usss vcmpnless vcmpord_qss vcmpordss vcmpeq_uqss vcmpnge_usss vcmpngess vcmpngt_usss vcmpngtss vcmpfalse_oqss vcmpfalsess vcmpneq_oqss vcmpge_osss vcmpgess vcmpgt_osss vcmpgtss vcmptrue_uqss vcmptruess vcmplt_oqss vcmple_oqss vcmpunord_sss vcmpneq_usss vcmpnlt_uqss vcmpnle_uqss vcmpord_sss vcmpeq_usss vcmpnge_uqss vcmpngt_uqss vcmpfalse_osss vcmpneq_osss vcmpge_oqss vcmpgt_oqss vcmptrue_usss vcmpss vcomisd vcomiss vcvtdq2pd vcvtdq2ps vcvtpd2dq vcvtpd2ps vcvtps2dq vcvtps2pd vcvtsd2si vcvtsd2ss vcvtsi2sd vcvtsi2ss vcvtss2sd vcvtss2si vcvttpd2dq vcvttps2dq vcvttsd2si vcvttss2si vdivpd vdivps vdivsd vdivss vdppd vdpps vextractf128 vextractps vhaddpd vhaddps vhsubpd vhsubps vinsertf128 vinsertps vlddqu vldqqu vldmxcsr vmaskmovdqu vmaskmovps vmaskmovpd vmaxpd vmaxps vmaxsd vmaxss vminpd vminps vminsd vminss vmovapd vmovaps vmovd vmovq vmovddup vmovdqa vmovqqa vmovdqu vmovqqu vmovhlps vmovhpd vmovhps vmovlhps vmovlpd vmovlps vmovmskpd vmovmskps vmovntdq vmovntqq vmovntdqa vmovntpd vmovntps vmovsd vmovshdup vmovsldup vmovss vmovupd vmovups vmpsadbw vmulpd vmulps vmulsd vmulss vorpd vorps vpabsb vpabsw vpabsd vpacksswb vpackssdw vpackuswb vpackusdw vpaddb vpaddw vpaddd vpaddq vpaddsb vpaddsw vpaddusb vpaddusw vpalignr vpand vpandn vpavgb vpavgw vpblendvb vpblendw vpcmpestri vpcmpestrm vpcmpistri vpcmpistrm vpcmpeqb vpcmpeqw vpcmpeqd vpcmpeqq vpcmpgtb vpcmpgtw vpcmpgtd vpcmpgtq vpermilpd vpermilps vperm2f128 vpextrb vpextrw vpextrd vpextrq vphaddw vphaddd vphaddsw vphminposuw vphsubw vphsubd vphsubsw vpinsrb vpinsrw vpinsrd vpinsrq vpmaddwd vpmaddubsw vpmaxsb vpmaxsw vpmaxsd vpmaxub vpmaxuw vpmaxud vpminsb vpminsw vpminsd vpminub vpminuw vpminud vpmovmskb vpmovsxbw vpmovsxbd vpmovsxbq vpmovsxwd vpmovsxwq vpmovsxdq vpmovzxbw vpmovzxbd vpmovzxbq vpmovzxwd vpmovzxwq vpmovzxdq vpmulhuw vpmulhrsw vpmulhw vpmullw vpmulld vpmuludq vpmuldq vpor vpsadbw vpshufb vpshufd vpshufhw vpshuflw vpsignb vpsignw vpsignd vpslldq vpsrldq vpsllw vpslld vpsllq vpsraw vpsrad vpsrlw vpsrld vpsrlq vptest vpsubb vpsubw vpsubd vpsubq vpsubsb vpsubsw vpsubusb vpsubusw vpunpckhbw vpunpckhwd vpunpckhdq vpunpckhqdq vpunpcklbw vpunpcklwd vpunpckldq vpunpcklqdq vpxor vrcpps vrcpss vrsqrtps vrsqrtss vroundpd vroundps vroundsd vroundss vshufpd vshufps vsqrtpd vsqrtps vsqrtsd vsqrtss vstmxcsr vsubpd vsubps vsubsd vsubss vtestps vtestpd vucomisd vucomiss vunpckhpd vunpckhps vunpcklpd vunpcklps vxorpd vxorps vzeroall vzeroupper pclmullqlqdq pclmulhqlqdq pclmullqhqdq pclmulhqhqdq pclmulqdq vpclmullqlqdq vpclmulhqlqdq vpclmullqhqdq vpclmulhqhqdq vpclmulqdq vfmadd132ps vfmadd132pd vfmadd312ps vfmadd312pd vfmadd213ps vfmadd213pd vfmadd123ps vfmadd123pd vfmadd231ps vfmadd231pd vfmadd321ps vfmadd321pd vfmaddsub132ps vfmaddsub132pd vfmaddsub312ps vfmaddsub312pd vfmaddsub213ps vfmaddsub213pd vfmaddsub123ps vfmaddsub123pd vfmaddsub231ps vfmaddsub231pd vfmaddsub321ps vfmaddsub321pd vfmsub132ps vfmsub132pd vfmsub312ps vfmsub312pd vfmsub213ps vfmsub213pd vfmsub123ps vfmsub123pd vfmsub231ps vfmsub231pd vfmsub321ps vfmsub321pd vfmsubadd132ps vfmsubadd132pd vfmsubadd312ps vfmsubadd312pd vfmsubadd213ps vfmsubadd213pd vfmsubadd123ps vfmsubadd123pd vfmsubadd231ps vfmsubadd231pd vfmsubadd321ps vfmsubadd321pd vfnmadd132ps vfnmadd132pd vfnmadd312ps vfnmadd312pd vfnmadd213ps vfnmadd213pd vfnmadd123ps vfnmadd123pd vfnmadd231ps vfnmadd231pd vfnmadd321ps vfnmadd321pd vfnmsub132ps vfnmsub132pd vfnmsub312ps vfnmsub312pd vfnmsub213ps vfnmsub213pd vfnmsub123ps vfnmsub123pd vfnmsub231ps vfnmsub231pd vfnmsub321ps vfnmsub321pd vfmadd132ss vfmadd132sd vfmadd312ss vfmadd312sd vfmadd213ss vfmadd213sd vfmadd123ss vfmadd123sd vfmadd231ss vfmadd231sd vfmadd321ss vfmadd321sd vfmsub132ss vfmsub132sd vfmsub312ss vfmsub312sd vfmsub213ss vfmsub213sd vfmsub123ss vfmsub123sd vfmsub231ss vfmsub231sd vfmsub321ss vfmsub321sd vfnmadd132ss vfnmadd132sd vfnmadd312ss vfnmadd312sd vfnmadd213ss vfnmadd213sd vfnmadd123ss vfnmadd123sd vfnmadd231ss vfnmadd231sd vfnmadd321ss vfnmadd321sd vfnmsub132ss vfnmsub132sd vfnmsub312ss vfnmsub312sd vfnmsub213ss vfnmsub213sd vfnmsub123ss vfnmsub123sd vfnmsub231ss vfnmsub231sd vfnmsub321ss vfnmsub321sd rdfsbase rdgsbase rdrand wrfsbase wrgsbase vcvtph2ps vcvtps2ph adcx adox rdseed clac stac xstore xcryptecb xcryptcbc xcryptctr xcryptcfb xcryptofb montmul xsha1 xsha256 llwpcb slwpcb lwpval lwpins vfmaddpd vfmaddps vfmaddsd vfmaddss vfmaddsubpd vfmaddsubps vfmsubaddpd vfmsubaddps vfmsubpd vfmsubps vfmsubsd vfmsubss vfnmaddpd vfnmaddps vfnmaddsd vfnmaddss vfnmsubpd vfnmsubps vfnmsubsd vfnmsubss vfrczpd vfrczps vfrczsd vfrczss vpcmov vpcomb vpcomd vpcomq vpcomub vpcomud vpcomuq vpcomuw vpcomw vphaddbd vphaddbq vphaddbw vphadddq vphaddubd vphaddubq vphaddubw vphaddudq vphadduwd vphadduwq vphaddwd vphaddwq vphsubbw vphsubdq vphsubwd vpmacsdd vpmacsdqh vpmacsdql vpmacssdd vpmacssdqh vpmacssdql vpmacsswd vpmacssww vpmacswd vpmacsww vpmadcsswd vpmadcswd vpperm vprotb vprotd vprotq vprotw vpshab vpshad vpshaq vpshaw vpshlb vpshld vpshlq vpshlw vbroadcasti128 vpblendd vpbroadcastb vpbroadcastw vpbroadcastd vpbroadcastq vpermd vpermpd vpermps vpermq vperm2i128 vextracti128 vinserti128 vpmaskmovd vpmaskmovq vpsllvd vpsllvq vpsravd vpsrlvd vpsrlvq vgatherdpd vgatherqpd vgatherdps vgatherqps vpgatherdd vpgatherqd vpgatherdq vpgatherqq xabort xbegin xend xtest andn bextr blci blcic blsi blsic blcfill blsfill blcmsk blsmsk blsr blcs bzhi mulx pdep pext rorx sarx shlx shrx tzcnt tzmsk t1mskc valignd valignq vblendmpd vblendmps vbroadcastf32x4 vbroadcastf64x4 vbroadcasti32x4 vbroadcasti64x4 vcompresspd vcompressps vcvtpd2udq vcvtps2udq vcvtsd2usi vcvtss2usi vcvttpd2udq vcvttps2udq vcvttsd2usi vcvttss2usi vcvtudq2pd vcvtudq2ps vcvtusi2sd vcvtusi2ss vexpandpd vexpandps vextractf32x4 vextractf64x4 vextracti32x4 vextracti64x4 vfixupimmpd vfixupimmps vfixupimmsd vfixupimmss vgetexppd vgetexpps vgetexpsd vgetexpss vgetmantpd vgetmantps vgetmantsd vgetmantss vinsertf32x4 vinsertf64x4 vinserti32x4 vinserti64x4 vmovdqa32 vmovdqa64 vmovdqu32 vmovdqu64 vpabsq vpandd vpandnd vpandnq vpandq vpblendmd vpblendmq vpcmpltd vpcmpled vpcmpneqd vpcmpnltd vpcmpnled vpcmpd vpcmpltq vpcmpleq vpcmpneqq vpcmpnltq vpcmpnleq vpcmpq vpcmpequd vpcmpltud vpcmpleud vpcmpnequd vpcmpnltud vpcmpnleud vpcmpud vpcmpequq vpcmpltuq vpcmpleuq vpcmpnequq vpcmpnltuq vpcmpnleuq vpcmpuq vpcompressd vpcompressq vpermi2d vpermi2pd vpermi2ps vpermi2q vpermt2d vpermt2pd vpermt2ps vpermt2q vpexpandd vpexpandq vpmaxsq vpmaxuq vpminsq vpminuq vpmovdb vpmovdw vpmovqb vpmovqd vpmovqw vpmovsdb vpmovsdw vpmovsqb vpmovsqd vpmovsqw vpmovusdb vpmovusdw vpmovusqb vpmovusqd vpmovusqw vpord vporq vprold vprolq vprolvd vprolvq vprord vprorq vprorvd vprorvq vpscatterdd vpscatterdq vpscatterqd vpscatterqq vpsraq vpsravq vpternlogd vpternlogq vptestmd vptestmq vptestnmd vptestnmq vpxord vpxorq vrcp14pd vrcp14ps vrcp14sd vrcp14ss vrndscalepd vrndscaleps vrndscalesd vrndscaless vrsqrt14pd vrsqrt14ps vrsqrt14sd vrsqrt14ss vscalefpd vscalefps vscalefsd vscalefss vscatterdpd vscatterdps vscatterqpd vscatterqps vshuff32x4 vshuff64x2 vshufi32x4 vshufi64x2 kandnw kandw kmovw knotw kortestw korw kshiftlw kshiftrw kunpckbw kxnorw kxorw vpbroadcastmb2q vpbroadcastmw2d vpconflictd vpconflictq vplzcntd vplzcntq vexp2pd vexp2ps vrcp28pd vrcp28ps vrcp28sd vrcp28ss vrsqrt28pd vrsqrt28ps vrsqrt28sd vrsqrt28ss vgatherpf0dpd vgatherpf0dps vgatherpf0qpd vgatherpf0qps vgatherpf1dpd vgatherpf1dps vgatherpf1qpd vgatherpf1qps vscatterpf0dpd vscatterpf0dps vscatterpf0qpd vscatterpf0qps vscatterpf1dpd vscatterpf1dps vscatterpf1qpd vscatterpf1qps prefetchwt1 bndmk bndcl bndcu bndcn bndmov bndldx bndstx sha1rnds4 sha1nexte sha1msg1 sha1msg2 sha256rnds2 sha256msg1 sha256msg2 hint_nop0 hint_nop1 hint_nop2 hint_nop3 hint_nop4 hint_nop5 hint_nop6 hint_nop7 hint_nop8 hint_nop9 hint_nop10 hint_nop11 hint_nop12 hint_nop13 hint_nop14 hint_nop15 hint_nop16 hint_nop17 hint_nop18 hint_nop19 hint_nop20 hint_nop21 hint_nop22 hint_nop23 hint_nop24 hint_nop25 hint_nop26 hint_nop27 hint_nop28 hint_nop29 hint_nop30 hint_nop31 hint_nop32 hint_nop33 hint_nop34 hint_nop35 hint_nop36 hint_nop37 hint_nop38 hint_nop39 hint_nop40 hint_nop41 hint_nop42 hint_nop43 hint_nop44 hint_nop45 hint_nop46 hint_nop47 hint_nop48 hint_nop49 hint_nop50 hint_nop51 hint_nop52 hint_nop53 hint_nop54 hint_nop55 hint_nop56 hint_nop57 hint_nop58 hint_nop59 hint_nop60 hint_nop61 hint_nop62 hint_nop63",literal:"ip eip rip al ah bl bh cl ch dl dh sil dil bpl spl r8b r9b r10b r11b r12b r13b r14b r15b ax bx cx dx si di bp sp r8w r9w r10w r11w r12w r13w r14w r15w eax ebx ecx edx esi edi ebp esp eip r8d r9d r10d r11d r12d r13d r14d r15d rax rbx rcx rdx rsi rdi rbp rsp r8 r9 r10 r11 r12 r13 r14 r15 cs ds es fs gs ss st st0 st1 st2 st3 st4 st5 st6 st7 mm0 mm1 mm2 mm3 mm4 mm5 mm6 mm7 xmm0 xmm1 xmm2 xmm3 xmm4 xmm5 xmm6 xmm7 xmm8 xmm9 xmm10 xmm11 xmm12 xmm13 xmm14 xmm15 xmm16 xmm17 xmm18 xmm19 xmm20 xmm21 xmm22 xmm23 xmm24 xmm25 xmm26 xmm27 xmm28 xmm29 xmm30 xmm31 ymm0 ymm1 ymm2 ymm3 ymm4 ymm5 ymm6 ymm7 ymm8 ymm9 ymm10 ymm11 ymm12 ymm13 ymm14 ymm15 ymm16 ymm17 ymm18 ymm19 ymm20 ymm21 ymm22 ymm23 ymm24 ymm25 ymm26 ymm27 ymm28 ymm29 ymm30 ymm31 zmm0 zmm1 zmm2 zmm3 zmm4 zmm5 zmm6 zmm7 zmm8 zmm9 zmm10 zmm11 zmm12 zmm13 zmm14 zmm15 zmm16 zmm17 zmm18 zmm19 zmm20 zmm21 zmm22 zmm23 zmm24 zmm25 zmm26 zmm27 zmm28 zmm29 zmm30 zmm31 k0 k1 k2 k3 k4 k5 k6 k7 bnd0 bnd1 bnd2 bnd3 cr0 cr1 cr2 cr3 cr4 cr8 dr0 dr1 dr2 dr3 dr8 tr3 tr4 tr5 tr6 tr7 r0 r1 r2 r3 r4 r5 r6 r7 r0b r1b r2b r3b r4b r5b r6b r7b r0w r1w r2w r3w r4w r5w r6w r7w r0d r1d r2d r3d r4d r5d r6d r7d r0h r1h r2h r3h r0l r1l r2l r3l r4l r5l r6l r7l r8l r9l r10l r11l r12l r13l r14l r15l",pseudo:"db dw dd dq dt ddq do dy dz resb resw resd resq rest resdq reso resy resz incbin equ times",preprocessor:"%define %xdefine %+ %undef %defstr %deftok %assign %strcat %strlen %substr %rotate %elif %else %endif %ifmacro %ifctx %ifidn %ifidni %ifid %ifnum %ifstr %iftoken %ifempty %ifenv %error %warning %fatal %rep %endrep %include %push %pop %repl %pathsearch %depend %use %arg %stacksize %local %line %comment %endcomment .nolist byte word dword qword nosplit rel abs seg wrt strict near far a32 ptr __FILE__ __LINE__ __SECT__ __BITS__ __OUTPUT_FORMAT__ __DATE__ __TIME__ __DATE_NUM__ __TIME_NUM__ __UTC_DATE__ __UTC_TIME__ __UTC_DATE_NUM__ __UTC_TIME_NUM__ __PASS__ struc endstruc istruc at iend align alignb sectalign daz nodaz up down zero default option assume public ",built_in:"bits use16 use32 use64 default section segment absolute extern global common cpu float __utf16__ __utf16le__ __utf16be__ __utf32__ __utf32le__ __utf32be__ __float8__ __float16__ __float32__ __float64__ __float80m__ __float80e__ __float128l__ __float128h__ __Infinity__ __QNaN__ __SNaN__ Inf NaN QNaN SNaN float8 float16 float32 float64 float80m float80e float128l float128h __FLOAT_DAZ__ __FLOAT_ROUND__ __FLOAT__"},c:[s.C(";","$",{r:0}),{cN:"number",b:"\\b(?:([0-9][0-9_]*)?\\.[0-9_]*(?:[eE][+-]?[0-9_]+)?|(0[Xx])?[0-9][0-9_]*\\.?[0-9_]*(?:[pP](?:[+-]?[0-9_]+)?)?)\\b",r:0},{cN:"number",b:"\\$[0-9][0-9A-Fa-f]*",r:0},{cN:"number",b:"\\b(?:[0-9A-Fa-f][0-9A-Fa-f_]*[HhXx]|[0-9][0-9_]*[DdTt]?|[0-7][0-7_]*[QqOo]|[0-1][0-1_]*[BbYy])\\b"},{cN:"number",b:"\\b(?:0[HhXx][0-9A-Fa-f_]+|0[DdTt][0-9_]+|0[QqOo][0-7_]+|0[BbYy][0-1_]+)\\b"},s.QSM,{cN:"string",b:"'",e:"[^\\\\]'",r:0},{cN:"string",b:"`",e:"[^\\\\]`",r:0},{cN:"string",b:"\\.[A-Za-z0-9]+",r:0},{cN:"label",b:"^\\s*[A-Za-z._?][A-Za-z0-9_$#@~.?]*(:|\\s+label)",r:0},{cN:"label",b:"^\\s*%%[A-Za-z0-9_$#@~.?]*:",r:0},{cN:"argument",b:"%[0-9]+",r:0},{cN:"built_in",b:"%!S+",r:0}]}}); \ No newline at end of file diff --git a/lib/highlight_js/assets/lang/xl.js b/lib/highlight_js/assets/lang/xl.js new file mode 100644 index 0000000000..daaea52acf --- /dev/null +++ b/lib/highlight_js/assets/lang/xl.js @@ -0,0 +1 @@ +hljs.registerLanguage("xl",function(e){var t="ObjectLoader Animate MovieCredits Slides Filters Shading Materials LensFlare Mapping VLCAudioVideo StereoDecoder PointCloud NetworkAccess RemoteControl RegExp ChromaKey Snowfall NodeJS Speech Charts",o={keyword:"if then else do while until for loop import with is as where when by data constant",literal:"true false nil",type:"integer real text name boolean symbol infix prefix postfix block tree",built_in:"in mod rem and or xor not abs sign floor ceil sqrt sin cos tan asin acos atan exp expm1 log log2 log10 log1p pi at",module:t,id:"text_length text_range text_find text_replace contains page slide basic_slide title_slide title subtitle fade_in fade_out fade_at clear_color color line_color line_width texture_wrap texture_transform texture scale_?x scale_?y scale_?z? translate_?x translate_?y translate_?z? rotate_?x rotate_?y rotate_?z? rectangle circle ellipse sphere path line_to move_to quad_to curve_to theme background contents locally time mouse_?x mouse_?y mouse_buttons"},a={cN:"constant",b:"[A-Z][A-Z_0-9]+",r:0},r={cN:"variable",b:"([A-Z][a-z_0-9]+)+",r:0},i={cN:"id",b:"[a-z][a-z_0-9]+",r:0},l={cN:"string",b:'"',e:'"',i:"\\n"},n={cN:"string",b:"'",e:"'",i:"\\n"},s={cN:"string",b:"<<",e:">>"},c={cN:"number",b:"[0-9]+#[0-9A-Z_]+(\\.[0-9-A-Z_]+)?#?([Ee][+-]?[0-9]+)?",r:10},_={cN:"import",bK:"import",e:"$",k:{keyword:"import",module:t},r:0,c:[l]},d={cN:"function",b:"[a-z].*->"};return{aliases:["tao"],l:/[a-zA-Z][a-zA-Z0-9_?]*/,k:o,c:[e.CLCM,e.CBCM,l,n,s,d,_,a,r,i,c,e.NM]}}); \ No newline at end of file diff --git a/lib/highlight_js/assets/lang/xml.js b/lib/highlight_js/assets/lang/xml.js new file mode 100644 index 0000000000..403807f8c5 --- /dev/null +++ b/lib/highlight_js/assets/lang/xml.js @@ -0,0 +1 @@ +hljs.registerLanguage("xml",function(t){var e="[A-Za-z0-9\\._:-]+",s={b:/<\?(php)?(?!\w)/,e:/\?>/,sL:"php",subLanguageMode:"continuous"},c={eW:!0,i:/]+/}]}]}]};return{aliases:["html","xhtml","rss","atom","xsl","plist"],cI:!0,c:[{cN:"doctype",b:"",r:10,c:[{b:"\\[",e:"\\]"}]},t.C("",{r:10}),{cN:"cdata",b:"<\\!\\[CDATA\\[",e:"\\]\\]>",r:10},{cN:"tag",b:"|$)",e:">",k:{title:"style"},c:[c],starts:{e:"",rE:!0,sL:"css"}},{cN:"tag",b:"|$)",e:">",k:{title:"script"},c:[c],starts:{e:"",rE:!0,sL:""}},s,{cN:"pi",b:/<\?\w+/,e:/\?>/,r:10},{cN:"tag",b:"",c:[{cN:"title",b:/[^ \/><\n\t]+/,r:0},c]}]}}); \ No newline at end of file diff --git a/lib/highlight_js/highlight_js.rb b/lib/highlight_js/highlight_js.rb new file mode 100644 index 0000000000..22c93609cf --- /dev/null +++ b/lib/highlight_js/highlight_js.rb @@ -0,0 +1,32 @@ +module HighlightJs + + def self.languages + Dir.glob(File.dirname(__FILE__) << "/assets/lang/*.js").map do |path| + File.basename(path)[0..-4] + end + end + + def self.bundle(langs) + path = File.dirname(__FILE__) << "/assets/" + + result = File.read(path + "highlight.js") + langs.each do |lang| + begin + result << "\n" << File.read(path + "lang/#{lang}.js") + rescue Errno::ENOENT + # no file, don't care + end + end + + result + end + + def self.version(lang_string) + (@lang_string_cache ||= {})[lang_string] ||= + Digest::SHA1.hexdigest(bundle lang_string.split("|")) + end + + def self.path + "/highlight-js/#{Discourse.current_hostname}/#{version SiteSetting.highlighted_languages}.js" + end +end diff --git a/lib/pretty_text.rb b/lib/pretty_text.rb index fadc410ed8..9e0c9672a5 100644 --- a/lib/pretty_text.rb +++ b/lib/pretty_text.rb @@ -86,7 +86,6 @@ module PrettyText decorate_context(ctx) ctx_load(ctx, - "public/javascripts/highlight.pack.js", "vendor/assets/javascripts/better_markdown.js", "app/assets/javascripts/defer/html-sanitizer-bundle.js", "app/assets/javascripts/discourse/dialects/dialect.js", diff --git a/lib/site_setting_extension.rb b/lib/site_setting_extension.rb index a3b655e99c..3f8b033308 100644 --- a/lib/site_setting_extension.rb +++ b/lib/site_setting_extension.rb @@ -78,10 +78,15 @@ module SiteSettingExtension opts[:type] ||= :enum end - if opts[:choices] + if new_choices = opts[:choices] + + if String === new_choices + new_choices = eval(new_choices) + end + choices.has_key?(name) ? - choices[name].concat(opts[:choices]) : - choices[name] = opts[:choices] + choices[name].concat(new_choices) : + choices[name] = new_choices end if type = opts[:type] diff --git a/lib/tasks/highlight.rake b/lib/tasks/highlight.rake new file mode 100644 index 0000000000..d6baa771fb --- /dev/null +++ b/lib/tasks/highlight.rake @@ -0,0 +1,25 @@ +desc "download latest version of highlight and prepare it" +task "highlightjs:update" do + + def run(cmd, opts={}) + puts cmd + system(cmd, opts.merge(out: $stdout, err: :out)) + end + run("cd tmp && rm -fr highlight.js && git clone --depth 1 https://github.com/isagalaev/highlight.js.git") + run("cd tmp && rm -fr highlight_distrib && mkdir -p highlight_distrib/lang") + run("cd tmp/highlight.js && npm install") + run("cd tmp/highlight.js && node tools/build.js -t cdn none") + + run("mv tmp/highlight.js/build/highlight.min.js tmp/highlight_distrib/highlight.js") + + run("cd tmp/highlight.js && npm install && node tools/build.js -t cdn") + + Dir.glob("tmp/highlight.js/build/languages/*.min.js") do |path| + lang = File.basename(path)[0..-8] + run("mv #{path} tmp/highlight_distrib/lang/#{lang}.js") + end + + run("rm -fr lib/highlight_js/assets") + run("mv tmp/highlight_distrib lib/highlight_js/assets") + +end diff --git a/spec/components/highlight_js/highlight_js_spec.rb b/spec/components/highlight_js/highlight_js_spec.rb new file mode 100644 index 0000000000..2bc86dc0b6 --- /dev/null +++ b/spec/components/highlight_js/highlight_js_spec.rb @@ -0,0 +1,23 @@ +require 'spec_helper' +require_dependency 'highlight_js/highlight_js' + +describe HighlightJs do + it 'can list languages' do + HighlightJs.languages.should include('thrift') + end + + it 'can generate a packed bundle' do + bundle = HighlightJs.bundle(["thrift", "http"]) + bundle.should =~ /thrift/ + bundle.should =~ /http/ + bundle.should_not =~ /applescript/ + end + + + it 'can get a version string' do + version1 = HighlightJs.version("http|cpp") + version2 = HighlightJs.version("rust|cpp|fake") + + version1.should_not == version2 + end +end diff --git a/spec/components/pretty_text_spec.rb b/spec/components/pretty_text_spec.rb index 00bb220717..57576faca2 100644 --- a/spec/components/pretty_text_spec.rb +++ b/spec/components/pretty_text_spec.rb @@ -304,4 +304,8 @@ describe PrettyText do expect(PrettyText.cook("***\\****a")).to match_html("

*a

") end + it 'can include code class correctly' do + expect(PrettyText.cook("```cpp\ncpp\n```")).to match_html("

cpp
") + end + end diff --git a/test/javascripts/helpers/site-settings.js b/test/javascripts/helpers/site-settings.js index f1266061d8..881162480a 100644 --- a/test/javascripts/helpers/site-settings.js +++ b/test/javascripts/helpers/site-settings.js @@ -1,3 +1,3 @@ /*jshint maxlen:10000000 */ -Discourse.SiteSettingsOriginal = {"title":"Discourse Meta","logo_url":"/assets/logo.png","logo_small_url":"/assets/logo-single.png","mobile_logo_url":"","favicon_url":"//meta.discourse.org/uploads/default/2499/79d53726406d87af.ico","allow_user_locale":false,"suggested_topics":7,"track_external_right_clicks":false,"ga_universal_tracking_code":"","ga_universal_domain_name":"auto","ga_tracking_code":"UA-33736483-2","ga_domain_name":"","top_menu":"latest|new|unread|categories|top","post_menu":"like|share|flag|edit|bookmark|delete|admin|reply","post_menu_hidden_items":"edit|delete|admin","share_links":"twitter|facebook|google+|email","category_colors":"BF1E2E|F1592A|F7941D|9EB83B|3AB54A|12A89D|25AAE2|0E76BD|652D90|92278F|ED207B|8C6238|231F20|808281|B3B5B4|283890","enable_mobile_theme":true,"relative_date_duration":14,"category_featured_topics":4,"fixed_category_positions":false,"show_subcategory_list":false,"enable_badges":true,"invite_only":false,"login_required":false,"must_approve_users":false,"enable_local_logins":true,"allow_new_registrations":true,"enable_google_logins":true,"enable_google_oauth2_logins":false,"enable_yahoo_logins":true,"enable_twitter_logins":true,"enable_facebook_logins":true,"enable_github_logins":true,"enable_sso":false,"min_username_length":3,"max_username_length":20,"min_password_length":8,"enable_names":true,"invites_shown":30,"delete_user_max_post_age":60,"delete_all_posts_max":15,"min_post_length":20,"min_private_message_post_length":10,"max_post_length":32000,"min_topic_title_length":15,"max_topic_title_length":255,"min_private_message_title_length":2,"allow_uncategorized_topics":true,"min_title_similar_length":10,"min_body_similar_length":15,"edit_history_visible_to_public":true,"delete_removed_posts_after":24,"traditional_markdown_linebreaks":false,"suppress_reply_directly_below":true,"suppress_reply_directly_above":true,"newuser_max_images":0,"newuser_max_attachments":0,"display_name_on_posts":true,"short_progress_text_threshold":10000,"default_code_lang":"lang-auto","autohighlight_all_code":false,"email_in":false,"max_image_size_kb":3072,"max_attachment_size_kb":1024,"authorized_extensions":".jpg|.jpeg|.png|.gif|.svg|.txt|.ico|.yml","max_image_width":690,"max_image_height":500,"allow_profile_backgrounds":true,"allow_uploaded_avatars":true,"allow_animated_avatars":false,"tl1_requires_read_posts":30,"enable_long_polling":true,"polling_interval":3000,"anon_polling_interval":30000,"flush_timings_secs":5,"tos_url":"","privacy_policy_url":"","tos_accept_required":false,"faq_url":"","allow_restore":false,"maximum_backups":7,"version_checks":true,"suppress_uncategorized_badge":true,"min_search_term_length":3,"topic_views_heat_low":1000,"topic_views_heat_medium":2000,"topic_views_heat_high":5000,"global_notice":"","show_create_topics_notice":true,"available_locales":"cs|da|de|en|es|fr|he|id|it|ja|ko|nb_NO|nl|pl_PL|pt|pt_BR|ru|sv|uk|zh_CN|zh_TW"}; +Discourse.SiteSettingsOriginal = {"title":"Discourse Meta","logo_url":"/assets/logo.png","logo_small_url":"/assets/logo-single.png","mobile_logo_url":"","favicon_url":"//meta.discourse.org/uploads/default/2499/79d53726406d87af.ico","allow_user_locale":false,"suggested_topics":7,"track_external_right_clicks":false,"ga_universal_tracking_code":"","ga_universal_domain_name":"auto","ga_tracking_code":"UA-33736483-2","ga_domain_name":"","top_menu":"latest|new|unread|categories|top","post_menu":"like|share|flag|edit|bookmark|delete|admin|reply","post_menu_hidden_items":"edit|delete|admin","share_links":"twitter|facebook|google+|email","category_colors":"BF1E2E|F1592A|F7941D|9EB83B|3AB54A|12A89D|25AAE2|0E76BD|652D90|92278F|ED207B|8C6238|231F20|808281|B3B5B4|283890","enable_mobile_theme":true,"relative_date_duration":14,"category_featured_topics":4,"fixed_category_positions":false,"show_subcategory_list":false,"enable_badges":true,"invite_only":false,"login_required":false,"must_approve_users":false,"enable_local_logins":true,"allow_new_registrations":true,"enable_google_logins":true,"enable_google_oauth2_logins":false,"enable_yahoo_logins":true,"enable_twitter_logins":true,"enable_facebook_logins":true,"enable_github_logins":true,"enable_sso":false,"min_username_length":3,"max_username_length":20,"min_password_length":8,"enable_names":true,"invites_shown":30,"delete_user_max_post_age":60,"delete_all_posts_max":15,"min_post_length":20,"min_private_message_post_length":10,"max_post_length":32000,"min_topic_title_length":15,"max_topic_title_length":255,"min_private_message_title_length":2,"allow_uncategorized_topics":true,"min_title_similar_length":10,"min_body_similar_length":15,"edit_history_visible_to_public":true,"delete_removed_posts_after":24,"traditional_markdown_linebreaks":false,"suppress_reply_directly_below":true,"suppress_reply_directly_above":true,"newuser_max_images":0,"newuser_max_attachments":0,"display_name_on_posts":true,"short_progress_text_threshold":10000,"default_code_lang":"lang-auto","autohighlight_all_code":false,"email_in":false,"max_image_size_kb":3072,"max_attachment_size_kb":1024,"authorized_extensions":".jpg|.jpeg|.png|.gif|.svg|.txt|.ico|.yml","max_image_width":690,"max_image_height":500,"allow_profile_backgrounds":true,"allow_uploaded_avatars":true,"allow_animated_avatars":false,"tl1_requires_read_posts":30,"enable_long_polling":true,"polling_interval":3000,"anon_polling_interval":30000,"flush_timings_secs":5,"tos_url":"","privacy_policy_url":"","tos_accept_required":false,"faq_url":"","allow_restore":false,"maximum_backups":7,"version_checks":true,"suppress_uncategorized_badge":true,"min_search_term_length":3,"topic_views_heat_low":1000,"topic_views_heat_medium":2000,"topic_views_heat_high":5000,"global_notice":"","show_create_topics_notice":true,"available_locales":"cs|da|de|en|es|fr|he|id|it|ja|ko|nb_NO|nl|pl_PL|pt|pt_BR|ru|sv|uk|zh_CN|zh_TW","highlighted_languages":"apache|bash|cs|cpp|css|coffeescript|diff|xml|http|ini|json|java|javascript|makefile|markdown|nginx|objectivec|ruby|perl|php|python|sql|handlebars"}; Discourse.SiteSettings = jQuery.extend(true, {}, Discourse.SiteSettingsOriginal); diff --git a/test/javascripts/test_helper.js b/test/javascripts/test_helper.js index 38c3eb2a96..94b842a546 100644 --- a/test/javascripts/test_helper.js +++ b/test/javascripts/test_helper.js @@ -25,8 +25,6 @@ // Pagedown customizations //= require ../../app/assets/javascripts/pagedown_custom.js -//= require ../../public/javascripts/highlight.pack.js - //= require vendor //= require htmlparser.js From 1da2b466ba563e47b9e6fc238622bb3da4dcba31 Mon Sep 17 00:00:00 2001 From: Sam Date: Fri, 13 Mar 2015 16:28:31 +1100 Subject: [PATCH 007/114] jshint ignore --- .jshintignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.jshintignore b/.jshintignore index c4ab1fd1a9..3e20ec4747 100644 --- a/.jshintignore +++ b/.jshintignore @@ -12,6 +12,7 @@ lib/javascripts/locale/ lib/javascripts/messageformat.js lib/javascripts/moment.js lib/javascripts/moment_locale/ +lib/highlight_js lib/es6_module_transpiler/support/es6-module-transpiler.js public/javascripts/ spec/phantom_js/smoke_test.js From 6262ff457d475cf62bb0c29b2e942775210d24d8 Mon Sep 17 00:00:00 2001 From: Sam Date: Fri, 13 Mar 2015 16:34:57 +1100 Subject: [PATCH 008/114] hmmm --- .jshintignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.jshintignore b/.jshintignore index 3e20ec4747..b48df2c179 100644 --- a/.jshintignore +++ b/.jshintignore @@ -12,7 +12,7 @@ lib/javascripts/locale/ lib/javascripts/messageformat.js lib/javascripts/moment.js lib/javascripts/moment_locale/ -lib/highlight_js +lib/highlight_js/ lib/es6_module_transpiler/support/es6-module-transpiler.js public/javascripts/ spec/phantom_js/smoke_test.js From 20ab1f97e4b20431a358f84b0d6a25e943b451f7 Mon Sep 17 00:00:00 2001 From: Sam Date: Fri, 13 Mar 2015 16:55:27 +1100 Subject: [PATCH 009/114] REGRESSION: not caching async scripts, remove cache buster --- app/assets/javascripts/discourse/lib/load-script.js.es6 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/assets/javascripts/discourse/lib/load-script.js.es6 b/app/assets/javascripts/discourse/lib/load-script.js.es6 index 6b39d650af..2644ec29a7 100644 --- a/app/assets/javascripts/discourse/lib/load-script.js.es6 +++ b/app/assets/javascripts/discourse/lib/load-script.js.es6 @@ -43,7 +43,7 @@ export default function loadScript(url, opts) { if (opts.scriptTag) { loadWithTag(cdnUrl, cb); } else { - $.getScript(cdnUrl).then(cb); + Discourse.ajax({url: cdnUrl, dataType: "script", cache: true}).then(cb); } }); } From 01fcc7503a08ec7160e42acf34edb86b12bc420b Mon Sep 17 00:00:00 2001 From: Sam Date: Fri, 13 Mar 2015 17:45:55 +1100 Subject: [PATCH 010/114] big hacks to get tests to pass --- test/javascripts/helpers/create-pretender.js.es6 | 9 +++++++++ test/javascripts/test_helper.js | 5 +++++ 2 files changed, 14 insertions(+) diff --git a/test/javascripts/helpers/create-pretender.js.es6 b/test/javascripts/helpers/create-pretender.js.es6 index c64d4c1b6b..8eb11ad131 100644 --- a/test/javascripts/helpers/create-pretender.js.es6 +++ b/test/javascripts/helpers/create-pretender.js.es6 @@ -55,6 +55,15 @@ export default function() { return response({}); }); + this.get('/javascripts/jquery.magnific-popup-min.js', function() { + return response({}); + }); + + + this.get('/highlight.js', function() { + return response({}); + }); + this.post('/session', function(request) { var data = parsePostData(request.requestBody); diff --git a/test/javascripts/test_helper.js b/test/javascripts/test_helper.js index 94b842a546..5935a81552 100644 --- a/test/javascripts/test_helper.js +++ b/test/javascripts/test_helper.js @@ -47,6 +47,8 @@ //= require_tree ./lib //= require_tree . //= require_self +// +//= require ../../public/javascripts/jquery.magnific-popup-min.js // sinon settings sinon.config = { @@ -73,6 +75,9 @@ Discourse.injectTestHelpers(); Discourse.runInitializers(); Discourse.start(); Discourse.Route.mapRoutes(); +Discourse.HighlightJSPath = "/highlight.js"; +// messy but we need to pass tests +window.hljs = {highlightBlock: function(){}} // disable logster error reporting if (window.Logster) { From f6d56fef9e6eb98e97f212a8d444fbf67b29cbea Mon Sep 17 00:00:00 2001 From: Sam Date: Fri, 13 Mar 2015 18:33:47 +1100 Subject: [PATCH 011/114] correct behavior --- app/assets/javascripts/discourse/lib/load-script.js.es6 | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/assets/javascripts/discourse/lib/load-script.js.es6 b/app/assets/javascripts/discourse/lib/load-script.js.es6 index 2644ec29a7..5265e843ae 100644 --- a/app/assets/javascripts/discourse/lib/load-script.js.es6 +++ b/app/assets/javascripts/discourse/lib/load-script.js.es6 @@ -34,7 +34,8 @@ export default function loadScript(url, opts) { var cdnUrl = url; if (Discourse.CDN && url[0] === "/") { - cdnUrl = Discourse.CDN + url; + // ensure stuff is rooted correctly + cdnUrl = Discourse.CDN.replace(/\/$/,"") + url.substr(1); } // Some javascript depends on the path of where it is loaded (ace editor) From 08abb85682eeaf0fd2f26e0e455cab239c5c56fa Mon Sep 17 00:00:00 2001 From: Sam Date: Fri, 13 Mar 2015 18:50:34 +1100 Subject: [PATCH 012/114] oops --- app/assets/javascripts/discourse/lib/load-script.js.es6 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/assets/javascripts/discourse/lib/load-script.js.es6 b/app/assets/javascripts/discourse/lib/load-script.js.es6 index 5265e843ae..34b723e53b 100644 --- a/app/assets/javascripts/discourse/lib/load-script.js.es6 +++ b/app/assets/javascripts/discourse/lib/load-script.js.es6 @@ -35,7 +35,7 @@ export default function loadScript(url, opts) { if (Discourse.CDN && url[0] === "/") { // ensure stuff is rooted correctly - cdnUrl = Discourse.CDN.replace(/\/$/,"") + url.substr(1); + cdnUrl = Discourse.CDN.replace(/\/$/,"") + url; } // Some javascript depends on the path of where it is loaded (ace editor) From a09d4715142a1a818a2fbec71803387e7f722c46 Mon Sep 17 00:00:00 2001 From: Sam Date: Fri, 13 Mar 2015 19:31:33 +1100 Subject: [PATCH 013/114] Correct CDN url creation for "//" rooted CDNs --- app/assets/javascripts/discourse/lib/load-script.js.es6 | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/app/assets/javascripts/discourse/lib/load-script.js.es6 b/app/assets/javascripts/discourse/lib/load-script.js.es6 index 34b723e53b..6fe8342459 100644 --- a/app/assets/javascripts/discourse/lib/load-script.js.es6 +++ b/app/assets/javascripts/discourse/lib/load-script.js.es6 @@ -35,7 +35,14 @@ export default function loadScript(url, opts) { if (Discourse.CDN && url[0] === "/") { // ensure stuff is rooted correctly - cdnUrl = Discourse.CDN.replace(/\/$/,"") + url; + cdnUrl = Discourse.CDN.replace(/\/$/,""); + + // protocol agnostic so append protocol + if ( cdnUrl[0] === "/" && cdnUrl[1] === "/") { + cdnUrl = window.location.protocol + cdnUrl; + } + + cdnUrl += url; } // Some javascript depends on the path of where it is loaded (ace editor) From 4301ce661389b02f983fa6f7ba10fc86c744ba49 Mon Sep 17 00:00:00 2001 From: Sam Date: Fri, 13 Mar 2015 20:05:24 +1100 Subject: [PATCH 014/114] another try at a fix --- app/assets/javascripts/discourse/lib/load-script.js.es6 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/assets/javascripts/discourse/lib/load-script.js.es6 b/app/assets/javascripts/discourse/lib/load-script.js.es6 index 6fe8342459..025b6f2d50 100644 --- a/app/assets/javascripts/discourse/lib/load-script.js.es6 +++ b/app/assets/javascripts/discourse/lib/load-script.js.es6 @@ -33,7 +33,7 @@ export default function loadScript(url, opts) { var cdnUrl = url; - if (Discourse.CDN && url[0] === "/") { + if (Discourse.CDN && url[0] === "/" && url[1] !== "/") { // ensure stuff is rooted correctly cdnUrl = Discourse.CDN.replace(/\/$/,""); From f359cdeddc4369e9fadace3cd1311b1e1d3bfdc8 Mon Sep 17 00:00:00 2001 From: Sam Date: Fri, 13 Mar 2015 20:50:38 +1100 Subject: [PATCH 015/114] remove hacky protocol code, not needed --- .../javascripts/discourse/lib/load-script.js.es6 | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/app/assets/javascripts/discourse/lib/load-script.js.es6 b/app/assets/javascripts/discourse/lib/load-script.js.es6 index 025b6f2d50..1c56f9f029 100644 --- a/app/assets/javascripts/discourse/lib/load-script.js.es6 +++ b/app/assets/javascripts/discourse/lib/load-script.js.es6 @@ -33,16 +33,9 @@ export default function loadScript(url, opts) { var cdnUrl = url; + // Scripts should always load from CDN if (Discourse.CDN && url[0] === "/" && url[1] !== "/") { - // ensure stuff is rooted correctly - cdnUrl = Discourse.CDN.replace(/\/$/,""); - - // protocol agnostic so append protocol - if ( cdnUrl[0] === "/" && cdnUrl[1] === "/") { - cdnUrl = window.location.protocol + cdnUrl; - } - - cdnUrl += url; + cdnUrl = Discourse.CDN.replace(/\/$/,"") + url; } // Some javascript depends on the path of where it is loaded (ace editor) From 77f9d1e22336ffcc9061a2616d11ddf9ed5f7640 Mon Sep 17 00:00:00 2001 From: Robin Ward Date: Fri, 13 Mar 2015 12:08:28 -0400 Subject: [PATCH 016/114] Use pretender's passthrough for dynamically loaded scripts --- .../discourse/lib/highlight-syntax.js.es6 | 8 +- .../javascripts/discourse/mixins/ajax.js | 8 +- .../helpers/create-pretender.js.es6 | 29 ++--- test/javascripts/test_helper.js | 3 - vendor/assets/javascripts/pretender.js | 111 +++++++++++++++++- 5 files changed, 131 insertions(+), 28 deletions(-) diff --git a/app/assets/javascripts/discourse/lib/highlight-syntax.js.es6 b/app/assets/javascripts/discourse/lib/highlight-syntax.js.es6 index a30c86e303..39be2a1d33 100644 --- a/app/assets/javascripts/discourse/lib/highlight-syntax.js.es6 +++ b/app/assets/javascripts/discourse/lib/highlight-syntax.js.es6 @@ -3,8 +3,12 @@ import loadScript from 'discourse/lib/load-script'; export default function highlightSyntax($elem) { - const selector = Discourse.SiteSettings.autohighlight_all_code ? 'pre code' : 'pre code[class]'; + const selector = Discourse.SiteSettings.autohighlight_all_code ? 'pre code' : 'pre code[class]', + path = Discourse.HighlightJSPath; + + if (!path) { return; } + $(selector, $elem).each(function(i, e) { - loadScript(Discourse.HighlightJSPath).then(() => hljs.highlightBlock(e)); + loadScript(path).then(() => hljs.highlightBlock(e)); }); } diff --git a/app/assets/javascripts/discourse/mixins/ajax.js b/app/assets/javascripts/discourse/mixins/ajax.js index 37e0ccc65a..cc85af1db8 100644 --- a/app/assets/javascripts/discourse/mixins/ajax.js +++ b/app/assets/javascripts/discourse/mixins/ajax.js @@ -49,9 +49,11 @@ Discourse.Ajax = Em.Mixin.create({ var performAjax = function(resolve, reject) { + args.headers = args.headers || {}; + if (_trackView && (!args.type || args.type === "GET")) { _trackView = false; - args.headers = { 'Discourse-Track-View': true }; + args.headers['Discourse-Track-View'] = true; } args.success = function(xhr) { @@ -80,6 +82,10 @@ Discourse.Ajax = Em.Mixin.create({ if (!args.type) args.type = 'GET'; if (!args.dataType && args.type.toUpperCase() === 'GET') args.dataType = 'json'; + if (args.dataType === "script") { + args.headers['Discourse-Script'] = true; + } + if (args.type === 'GET' && args.cache !== true) { args.cache = false; } diff --git a/test/javascripts/helpers/create-pretender.js.es6 b/test/javascripts/helpers/create-pretender.js.es6 index 8eb11ad131..06ebebbd74 100644 --- a/test/javascripts/helpers/create-pretender.js.es6 +++ b/test/javascripts/helpers/create-pretender.js.es6 @@ -1,7 +1,7 @@ function parsePostData(query) { - var result = {}; + const result = {}; query.split("&").forEach(function(part) { - var item = part.split("="); + const item = part.split("="); result[item[0]] = decodeURIComponent(item[1]); }); return result; @@ -25,15 +25,15 @@ const _widgets = [ ]; export default function() { - var server = new Pretender(function() { + const server = new Pretender(function() { // Load any fixtures automatically - var self = this; + const self = this; Ember.keys(require._eak_seen).forEach(function(entry) { if (/^fixtures/.test(entry)) { - var fixture = require(entry, null, null, true); + const fixture = require(entry, null, null, true); if (fixture && fixture.default) { - var obj = fixture.default; + const obj = fixture.default; Ember.keys(obj).forEach(function(url) { self.get(url, function() { return response(obj[url]); @@ -55,17 +55,8 @@ export default function() { return response({}); }); - this.get('/javascripts/jquery.magnific-popup-min.js', function() { - return response({}); - }); - - - this.get('/highlight.js', function() { - return response({}); - }); - this.post('/session', function(request) { - var data = parsePostData(request.requestBody); + const data = parsePostData(request.requestBody); if (data.password === 'correct') { return response({username: 'eviltrout'}); @@ -130,10 +121,14 @@ export default function() { }; server.unhandledRequest = function(verb, path) { - var error = 'Unhandled request in test environment: ' + path + ' (' + verb + ')'; + const error = 'Unhandled request in test environment: ' + path + ' (' + verb + ')'; window.console.error(error); throw error; }; + server.checkPassthrough = function(request) { + return request.requestHeaders['Discourse-Script']; + }; + return server; } diff --git a/test/javascripts/test_helper.js b/test/javascripts/test_helper.js index 5935a81552..bf87e3d254 100644 --- a/test/javascripts/test_helper.js +++ b/test/javascripts/test_helper.js @@ -75,9 +75,6 @@ Discourse.injectTestHelpers(); Discourse.runInitializers(); Discourse.start(); Discourse.Route.mapRoutes(); -Discourse.HighlightJSPath = "/highlight.js"; -// messy but we need to pass tests -window.hljs = {highlightBlock: function(){}} // disable logster error reporting if (window.Logster) { diff --git a/vendor/assets/javascripts/pretender.js b/vendor/assets/javascripts/pretender.js index b416deb6a4..d86f40dc1c 100644 --- a/vendor/assets/javascripts/pretender.js +++ b/vendor/assets/javascripts/pretender.js @@ -19,6 +19,7 @@ function Pretender(maps){ this.handlers = []; this.handledRequests = []; + this.passthroughRequests = []; this.unhandledRequests = []; // reference the native XMLHttpRequest object so @@ -29,6 +30,9 @@ function Pretender(maps){ // the route map. window.XMLHttpRequest = interceptor(this); + // "start" the server + this.running = true; + // trigger the route map DSL. maps.call(this); } @@ -41,10 +45,65 @@ function interceptor(pretender) { // extend var proto = new FakeXMLHttpRequest(); proto.send = function send(){ - FakeXMLHttpRequest.prototype.send.apply(this, arguments); - pretender.handleRequest(this); + if (!pretender.running) { + throw new Error('You shut down a Pretender instance while there was a pending request. '+ + 'That request just tried to complete. Check to see if you accidentally shut down '+ + 'a pretender earlier than you intended to'); + } + + if (!pretender.checkPassthrough(this)) { + FakeXMLHttpRequest.prototype.send.apply(this, arguments); + pretender.handleRequest(this); + } + else { + var xhr = createPassthrough(this); + xhr.send.apply(xhr, arguments); + } }; + // passthrough handling + var evts = ['load', 'error', 'timeout', 'progress', 'abort', 'readystatechange']; + var lifecycleProps = ['readyState', 'responseText', 'responseXML', 'status', 'statusText']; + function createPassthrough(fakeXHR) { + var xhr = fakeXHR._passthroughRequest = new pretender._nativeXMLHttpRequest(); + // listen to all events to update lifecycle properties + for (var i = 0; i < evts.length; i++) (function(evt) { + xhr['on' + evt] = function(e) { + // update lifecycle props on each event + for (var i = 0; i < lifecycleProps.length; i++) { + var prop = lifecycleProps[i]; + if (xhr[prop]) { + fakeXHR[prop] = xhr[prop]; + } + } + // fire fake events where applicable + fakeXHR.dispatchEvent(evt, e); + if (fakeXHR['on' + evt]) { + fakeXHR['on' + evt](e); + } + }; + })(evts[i]); + xhr.open(fakeXHR.method, fakeXHR.url, fakeXHR.async, fakeXHR.username, fakeXHR.password); + xhr.timeout = fakeXHR.timeout; + xhr.withCredentials = fakeXHR.withCredentials; + return xhr; + } + proto._passthroughCheck = function(method, arguments) { + if (this._passthroughRequest) { + return this._passthroughRequest[method].apply(this._passthroughRequest, arguments); + } + return FakeXMLHttpRequest.prototype[method].apply(this, arguments); + } + proto.abort = function abort(){ + return this._passthroughCheck('abort', arguments); + } + proto.getResponseHeader = function getResponseHeader(){ + return this._passthroughCheck('getResponseHeader', arguments); + } + proto.getAllResponseHeaders = function getAllResponseHeaders(){ + return this._passthroughCheck('getAllResponseHeaders', arguments); + } + FakeRequest.prototype = proto; return FakeRequest; } @@ -55,6 +114,22 @@ function verbify(verb){ }; } +function throwIfURLDetected(url){ + var HTTP_REGEXP = /^https?/; + var message; + + if(HTTP_REGEXP.test(url)) { + var parser = window.document.createElement('a'); + parser.href = url; + + message = "Pretender will not respond to requests for URLs. It is not possible to accurately simluate the browser's CSP. "+ + "Remove the " + parser.protocol +"//"+ parser.hostname +" from " + url + " and try again"; + throw new Error(message) + } +} + +var PASSTHROUGH = {}; + Pretender.prototype = { get: verbify('GET'), post: verbify('POST'), @@ -69,9 +144,29 @@ Pretender.prototype = { var registry = this.registry[verb]; registry.add([{path: path, handler: handler}]); }, + passthrough: PASSTHROUGH, + checkPassthrough: function(request) { + var verb = request.method.toUpperCase(); + var path = request.url; + + throwIfURLDetected(path); + + verb = verb.toUpperCase(); + + var recognized = this.registry[verb].recognize(path); + var match = recognized && recognized[0]; + if (match && match.handler == PASSTHROUGH) { + this.passthroughRequests.push(request); + this.passthroughRequest(verb, path, request); + return true; + } + + return false; + }, handleRequest: function handleRequest(request){ var verb = request.method.toUpperCase(); var path = request.url; + var handler = this._handlerFor(verb, path, request); if (handler) { @@ -81,9 +176,10 @@ Pretender.prototype = { try { var statusHeadersAndBody = handler.handler(request), status = statusHeadersAndBody[0], - headers = statusHeadersAndBody[1], + headers = this.prepareHeaders(statusHeadersAndBody[1]), body = this.prepareBody(statusHeadersAndBody[2]); request.respond(status, headers, body); + this.handledRequest(verb, path, request); } catch (error) { this.erroredRequest(verb, path, request, error); @@ -93,8 +189,10 @@ Pretender.prototype = { this.unhandledRequest(verb, path, request); } }, - prepareBody: function(body){ return body; }, - handledRequest: function(verb, path, request){/* no-op */}, + prepareBody: function(body) { return body; }, + prepareHeaders: function(headers) { return headers; }, + handledRequest: function(verb, path, request) { /* no-op */}, + passthroughRequest: function(verb, path, request) { /* no-op */}, unhandledRequest: function(verb, path, request) { throw new Error("Pretender intercepted "+verb+" "+path+" but no handler was defined for this type of request"); }, @@ -116,6 +214,9 @@ Pretender.prototype = { }, shutdown: function shutdown(){ window.XMLHttpRequest = this._nativeXMLHttpRequest; + + // "stop" the server + this.running = false; } }; From 53591ade001f5108d5eb32da6429d388eddcb273 Mon Sep 17 00:00:00 2001 From: Gerhard Schlager Date: Fri, 13 Mar 2015 21:24:11 +0100 Subject: [PATCH 017/114] Adds a few enhancements to the base importer - Allows importing globally pinned topics - Doesn't restore the original value of a SiteSetting anymore if an importer changed its value - Allows all file extensions during the import - Adds the ability to import bookmarks --- lib/post_creator.rb | 1 + lib/topic_creator.rb | 1 + script/import_scripts/base.rb | 47 ++++++++++++++++++++++++++++++++--- script/import_scripts/smf2.rb | 4 --- 4 files changed, 45 insertions(+), 8 deletions(-) diff --git a/lib/post_creator.rb b/lib/post_creator.rb index 3c1d60279f..4bc5e7d8f0 100644 --- a/lib/post_creator.rb +++ b/lib/post_creator.rb @@ -43,6 +43,7 @@ class PostCreator # meta_data - Topic meta data hash # created_at - Topic creation time (optional) # pinned_at - Topic pinned time (optional) + # pinned_globally - Is the topic pinned globally (optional) # def initialize(user, opts) # TODO: we should reload user in case it is tainted, should take in a user_id as opposed to user diff --git a/lib/topic_creator.rb b/lib/topic_creator.rb index 179e8d2333..40b6aee9dc 100644 --- a/lib/topic_creator.rb +++ b/lib/topic_creator.rb @@ -87,6 +87,7 @@ class TopicCreator topic_params[:created_at] = Time.zone.parse(@opts[:created_at].to_s) if @opts[:created_at].present? topic_params[:pinned_at] = Time.zone.parse(@opts[:pinned_at].to_s) if @opts[:pinned_at].present? + topic_params[:pinned_globally] = @opts[:pinned_globally] if @opts[:pinned_globally].present? topic_params end diff --git a/script/import_scripts/base.rb b/script/import_scripts/base.rb index 190e0309d9..a3120edd24 100644 --- a/script/import_scripts/base.rb +++ b/script/import_scripts/base.rb @@ -32,6 +32,7 @@ class ImportScripts::Base @categories_lookup = {} @existing_posts = {} @topic_lookup = {} + @site_settings_during_import @old_site_settings = {} @start_time = Time.now @@ -94,17 +95,18 @@ class ImportScripts::Base end def change_site_settings - new_settings = { + @site_settings_during_import = { email_domains_blacklist: '', min_topic_title_length: 1, min_post_length: 1, min_private_message_post_length: 1, min_private_message_title_length: 1, allow_duplicate_topic_titles: true, - disable_emails: true + disable_emails: true, + authorized_extensions: '*' } - new_settings.each do |key, value| + @site_settings_during_import.each do |key, value| @old_site_settings[key] = SiteSetting.send(key) SiteSetting.set(key, value) end @@ -114,7 +116,8 @@ class ImportScripts::Base def reset_site_settings @old_site_settings.each do |key, value| - SiteSetting.set(key, value) + current_value = SiteSetting.send(key) + SiteSetting.set(key, value) unless current_value != @site_settings_during_import[key] end RateLimiter.enable @@ -469,6 +472,42 @@ class ImportScripts::Base tmp.unlink rescue nil end + # Iterate through a list of bookmark records to be imported. + # Takes a collection, and yields to the block for each element. + # Block should return a hash with the attributes for the bookmark. + # Required fields are :user_id and :post_id, where both ids are + # the values in the original datasource. + def create_bookmarks(results, opts={}) + bookmarks_created = 0 + bookmarks_skipped = 0 + total = opts[:total] || results.size + + user = User.new + post = Post.new + + results.each do |result| + params = yield(result) + + # only the IDs are needed, so this should be enough + user.id = user_id_from_imported_user_id(params[:user_id]) + post.id = post_id_from_imported_post_id(params[:post_id]) + + if user.id.nil? || post.id.nil? + bookmarks_skipped += 1 + puts "Skipping bookmark for user id #{params[:user_id]} and post id #{params[:post_id]}" + else + begin + PostAction.act(user, post, PostActionType.types[:bookmark]) + bookmarks_created += 1 + rescue PostAction::AlreadyActed + bookmarks_skipped += 1 + end + + print_status bookmarks_created + bookmarks_skipped + (opts[:offset] || 0), total + end + end + end + def close_inactive_topics(opts={}) num_days = opts[:days] || 30 puts '', "Closing topics that have been inactive for more than #{num_days} days." diff --git a/script/import_scripts/smf2.rb b/script/import_scripts/smf2.rb index 3b03914f86..5daa29a4cd 100644 --- a/script/import_scripts/smf2.rb +++ b/script/import_scripts/smf2.rb @@ -61,15 +61,11 @@ class ImportScripts::Smf2 < ImportScripts::Base end def execute - authorized_extensions = SiteSetting.authorized_extensions - SiteSetting.authorized_extensions = "*" import_groups import_users import_categories import_posts postprocess_posts - ensure - SiteSetting.authorized_extensions = authorized_extensions end def import_groups From 424a3b042ae445de3a1507ff24564a0733d2956b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9gis=20Hanol?= Date: Sat, 14 Mar 2015 01:18:05 +0100 Subject: [PATCH 018/114] FEATURE: unified UI for pinning/banner topics REFACTOR: ES6ified all the modals --- .../{ => modals}/admin-agree-flag.js.es6 | 0 .../{ => modals}/admin-badge-preview.js.es6 | 0 .../{ => modals}/admin-delete-flag.js.es6 | 0 .../admin-edit-badge-groupings.js.es6 | 0 .../admin-staff-action-log-details.js.es6 | 0 .../{ => modals}/admin-suspend-user.js.es6 | 1 - .../change-site-customization-details.js.es6 | 0 .../delete-site-customization-details.js.es6 | 4 +- .../admin/routes/admin-badges-show.js.es6 | 4 +- .../admin/routes/admin-flags-list.js.es6 | 4 +- .../admin-logs-staff-action-logs.js.es6 | 5 +- .../admin/routes/admin-user-index.js.es6 | 2 +- ...e_flag_view.js => admin-agree-flag.js.es6} | 4 +- ...iew_view.js => admin-badge-preview.js.es6} | 3 +- .../views/modals/admin-delete-flag.js.es6 | 6 ++ ...w.js => admin-edit-badge-groupings.js.es6} | 3 +- .../admin-staff-action-log-details.js.es6 | 6 ++ ...ckup_view.js => admin-start-backup.js.es6} | 4 +- .../views/modals/admin-suspend-user.js.es6 | 6 ++ .../views/modals/admin_delete_flag_view.js | 12 --- .../admin_staff_action_log_details_view.js | 12 --- .../views/modals/admin_suspend_user_view.js | 12 --- .../change-site-customization-details.js.es6 | 6 ++ .../change_site_customization_details_view.js | 13 ---- .../delete-site-customization-details.js.es6 | 6 ++ .../delete_site_customization_details_view.js | 13 ---- .../controllers/feature-topic.js.es6 | 77 +++++++++++++++++++ .../discourse/controllers/topic.js.es6 | 38 +++++++-- .../discourse/lib/show-modal.js.es6 | 12 +-- .../javascripts/discourse/models/topic.js.es6 | 12 +-- .../discourse/routes/application.js.es6 | 2 +- .../javascripts/discourse/routes/topic.js.es6 | 5 ++ .../templates/modal/feature-topic.hbs | 62 +++++++++++++++ .../discourse/templates/topic-admin-menu.hbs | 25 ++---- .../views/archetype-options-modal.js.es6 | 4 +- .../discourse/views/avatar-selector.js.es6 | 10 +-- .../discourse/views/change-owner.js.es6 | 4 +- .../discourse/views/create-account.js.es6 | 6 +- .../discourse/views/edit-category.js.es6 | 4 +- .../views/edit-topic-auto-close.js.es6 | 4 +- .../discourse/views/feature-topic.js.es6 | 6 ++ .../javascripts/discourse/views/flag.js.es6 | 11 ++- .../discourse/views/forgot-password.js.es6 | 4 +- .../discourse/views/history.js.es6 | 6 +- .../discourse/views/invite-private.js.es6 | 4 +- .../javascripts/discourse/views/invite.js.es6 | 14 ++-- .../views/keyboard-shortcuts-help.js.es6 | 4 +- .../javascripts/discourse/views/login.js.es6 | 12 +-- .../discourse/views/merge-topic.js.es6 | 4 +- .../discourse/views/modal-body.js.es6 | 30 ++++++++ .../javascripts/discourse/views/modal.js.es6 | 10 +-- .../discourse/views/modal_body_view.js | 48 ------------ .../discourse/views/not-activated.js.es6 | 4 +- .../javascripts/discourse/views/raw-email.es6 | 6 +- .../discourse/views/search-help.js.es6 | 4 +- .../discourse/views/split-topic.js.es6 | 4 +- .../discourse/views/topic-bulk-actions.js.es6 | 4 +- .../discourse/views/upload-selector.js.es6 | 25 +++--- app/assets/javascripts/main_include.js | 2 +- app/assets/javascripts/main_include_admin.js | 1 - app/controllers/topics_controller.rb | 15 +++- config/locales/client.en.yml | 28 ++++++- config/routes.rb | 1 + .../javascripts/integration/modal-test.js.es6 | 2 +- 64 files changed, 410 insertions(+), 230 deletions(-) rename app/assets/javascripts/admin/controllers/{ => modals}/admin-agree-flag.js.es6 (100%) rename app/assets/javascripts/admin/controllers/{ => modals}/admin-badge-preview.js.es6 (100%) rename app/assets/javascripts/admin/controllers/{ => modals}/admin-delete-flag.js.es6 (100%) rename app/assets/javascripts/admin/controllers/{ => modals}/admin-edit-badge-groupings.js.es6 (100%) rename app/assets/javascripts/admin/controllers/{ => modals}/admin-staff-action-log-details.js.es6 (100%) rename app/assets/javascripts/admin/controllers/{ => modals}/admin-suspend-user.js.es6 (99%) rename app/assets/javascripts/admin/controllers/{ => modals}/change-site-customization-details.js.es6 (100%) rename app/assets/javascripts/admin/controllers/{ => modals}/delete-site-customization-details.js.es6 (65%) rename app/assets/javascripts/admin/views/modals/{admin_agree_flag_view.js => admin-agree-flag.js.es6} (54%) rename app/assets/javascripts/admin/views/modals/{admin_badge_preview_view.js => admin-badge-preview.js.es6} (55%) create mode 100644 app/assets/javascripts/admin/views/modals/admin-delete-flag.js.es6 rename app/assets/javascripts/admin/views/modals/{admin_edit_badge_groupings_view.js => admin-edit-badge-groupings.js.es6} (58%) create mode 100644 app/assets/javascripts/admin/views/modals/admin-staff-action-log-details.js.es6 rename app/assets/javascripts/admin/views/modals/{admin_start_backup_view.js => admin-start-backup.js.es6} (56%) create mode 100644 app/assets/javascripts/admin/views/modals/admin-suspend-user.js.es6 delete mode 100644 app/assets/javascripts/admin/views/modals/admin_delete_flag_view.js delete mode 100644 app/assets/javascripts/admin/views/modals/admin_staff_action_log_details_view.js delete mode 100644 app/assets/javascripts/admin/views/modals/admin_suspend_user_view.js create mode 100644 app/assets/javascripts/admin/views/modals/change-site-customization-details.js.es6 delete mode 100644 app/assets/javascripts/admin/views/modals/change_site_customization_details_view.js create mode 100644 app/assets/javascripts/admin/views/modals/delete-site-customization-details.js.es6 delete mode 100644 app/assets/javascripts/admin/views/modals/delete_site_customization_details_view.js create mode 100644 app/assets/javascripts/discourse/controllers/feature-topic.js.es6 create mode 100644 app/assets/javascripts/discourse/templates/modal/feature-topic.hbs create mode 100644 app/assets/javascripts/discourse/views/feature-topic.js.es6 create mode 100644 app/assets/javascripts/discourse/views/modal-body.js.es6 delete mode 100644 app/assets/javascripts/discourse/views/modal_body_view.js diff --git a/app/assets/javascripts/admin/controllers/admin-agree-flag.js.es6 b/app/assets/javascripts/admin/controllers/modals/admin-agree-flag.js.es6 similarity index 100% rename from app/assets/javascripts/admin/controllers/admin-agree-flag.js.es6 rename to app/assets/javascripts/admin/controllers/modals/admin-agree-flag.js.es6 diff --git a/app/assets/javascripts/admin/controllers/admin-badge-preview.js.es6 b/app/assets/javascripts/admin/controllers/modals/admin-badge-preview.js.es6 similarity index 100% rename from app/assets/javascripts/admin/controllers/admin-badge-preview.js.es6 rename to app/assets/javascripts/admin/controllers/modals/admin-badge-preview.js.es6 diff --git a/app/assets/javascripts/admin/controllers/admin-delete-flag.js.es6 b/app/assets/javascripts/admin/controllers/modals/admin-delete-flag.js.es6 similarity index 100% rename from app/assets/javascripts/admin/controllers/admin-delete-flag.js.es6 rename to app/assets/javascripts/admin/controllers/modals/admin-delete-flag.js.es6 diff --git a/app/assets/javascripts/admin/controllers/admin-edit-badge-groupings.js.es6 b/app/assets/javascripts/admin/controllers/modals/admin-edit-badge-groupings.js.es6 similarity index 100% rename from app/assets/javascripts/admin/controllers/admin-edit-badge-groupings.js.es6 rename to app/assets/javascripts/admin/controllers/modals/admin-edit-badge-groupings.js.es6 diff --git a/app/assets/javascripts/admin/controllers/admin-staff-action-log-details.js.es6 b/app/assets/javascripts/admin/controllers/modals/admin-staff-action-log-details.js.es6 similarity index 100% rename from app/assets/javascripts/admin/controllers/admin-staff-action-log-details.js.es6 rename to app/assets/javascripts/admin/controllers/modals/admin-staff-action-log-details.js.es6 diff --git a/app/assets/javascripts/admin/controllers/admin-suspend-user.js.es6 b/app/assets/javascripts/admin/controllers/modals/admin-suspend-user.js.es6 similarity index 99% rename from app/assets/javascripts/admin/controllers/admin-suspend-user.js.es6 rename to app/assets/javascripts/admin/controllers/modals/admin-suspend-user.js.es6 index b2d30f96d0..49999aa092 100644 --- a/app/assets/javascripts/admin/controllers/admin-suspend-user.js.es6 +++ b/app/assets/javascripts/admin/controllers/modals/admin-suspend-user.js.es6 @@ -1,5 +1,4 @@ import ModalFunctionality from 'discourse/mixins/modal-functionality'; - import ObjectController from 'discourse/controllers/object'; export default ObjectController.extend(ModalFunctionality, { diff --git a/app/assets/javascripts/admin/controllers/change-site-customization-details.js.es6 b/app/assets/javascripts/admin/controllers/modals/change-site-customization-details.js.es6 similarity index 100% rename from app/assets/javascripts/admin/controllers/change-site-customization-details.js.es6 rename to app/assets/javascripts/admin/controllers/modals/change-site-customization-details.js.es6 diff --git a/app/assets/javascripts/admin/controllers/delete-site-customization-details.js.es6 b/app/assets/javascripts/admin/controllers/modals/delete-site-customization-details.js.es6 similarity index 65% rename from app/assets/javascripts/admin/controllers/delete-site-customization-details.js.es6 rename to app/assets/javascripts/admin/controllers/modals/delete-site-customization-details.js.es6 index 57e3c9652a..d38c396ceb 100644 --- a/app/assets/javascripts/admin/controllers/delete-site-customization-details.js.es6 +++ b/app/assets/javascripts/admin/controllers/modals/delete-site-customization-details.js.es6 @@ -1,7 +1,7 @@ -import ChangeSiteCustomizationDetailsController from "admin/controllers/change-site-customization-details"; +import ChangeSiteCustomizationDetailsController from "admin/controllers/modals/change-site-customization-details"; export default ChangeSiteCustomizationDetailsController.extend({ onShow: function() { - this.selectPrevious(); + this.send("selectPrevious"); } }); diff --git a/app/assets/javascripts/admin/routes/admin-badges-show.js.es6 b/app/assets/javascripts/admin/routes/admin-badges-show.js.es6 index 3d2ac34459..56d0f93daf 100644 --- a/app/assets/javascripts/admin/routes/admin-badges-show.js.es6 +++ b/app/assets/javascripts/admin/routes/admin-badges-show.js.es6 @@ -25,7 +25,7 @@ export default Ember.Route.extend({ editGroupings() { const groupings = this.controllerFor('admin-badges').get('badgeGroupings'); - showModal('admin_edit_badge_groupings', groupings); + showModal('modals/admin-edit-badge-groupings', groupings); }, preview(badge, explain) { @@ -40,7 +40,7 @@ export default Ember.Route.extend({ } }).then(function(json) { badge.set('preview_loading', false); - showModal('admin_badge_preview', json); + showModal('modals/admin-badge-preview', json); }).catch(function(error) { badge.set('preview_loading', false); Em.Logger.error(error); diff --git a/app/assets/javascripts/admin/routes/admin-flags-list.js.es6 b/app/assets/javascripts/admin/routes/admin-flags-list.js.es6 index afe3d8ab46..99ceba7717 100644 --- a/app/assets/javascripts/admin/routes/admin-flags-list.js.es6 +++ b/app/assets/javascripts/admin/routes/admin-flags-list.js.es6 @@ -13,12 +13,12 @@ export default Discourse.Route.extend({ actions: { showAgreeFlagModal(flaggedPost) { - showModal('admin_agree_flag', flaggedPost); + showModal('modals/admin-agree-flag', flaggedPost); this.controllerFor('modal').set('modalClass', 'agree-flag-modal'); }, showDeleteFlagModal(flaggedPost) { - showModal('admin_delete_flag', flaggedPost); + showModal('modals/admin-delete-flag', flaggedPost); this.controllerFor('modal').set('modalClass', 'delete-flag-modal'); } diff --git a/app/assets/javascripts/admin/routes/admin-logs-staff-action-logs.js.es6 b/app/assets/javascripts/admin/routes/admin-logs-staff-action-logs.js.es6 index 29a40ed77c..f0f08ab2f5 100644 --- a/app/assets/javascripts/admin/routes/admin-logs-staff-action-logs.js.es6 +++ b/app/assets/javascripts/admin/routes/admin-logs-staff-action-logs.js.es6 @@ -13,12 +13,13 @@ export default Discourse.Route.extend({ actions: { showDetailsModal(logRecord) { - showModal('admin_staff_action_log_details', logRecord); + showModal('modals/admin-staff-action-log-details', logRecord); this.controllerFor('modal').set('modalClass', 'log-details-modal'); }, showCustomDetailsModal(logRecord) { - showModal(logRecord.action_name + '_details', logRecord); + const modalName = "modals/" + (logRecord.action_name + '_details').replace("_", "-"); + showModal(modalName, logRecord); this.controllerFor('modal').set('modalClass', 'tabbed-modal log-details-modal'); } } diff --git a/app/assets/javascripts/admin/routes/admin-user-index.js.es6 b/app/assets/javascripts/admin/routes/admin-user-index.js.es6 index e9c084ab3e..07cbfa8fc3 100644 --- a/app/assets/javascripts/admin/routes/admin-user-index.js.es6 +++ b/app/assets/javascripts/admin/routes/admin-user-index.js.es6 @@ -25,7 +25,7 @@ export default Discourse.Route.extend({ actions: { showSuspendModal(user) { - showModal('admin_suspend_user', user); + showModal('modals/admin-suspend-user', user); this.controllerFor('modal').set('modalClass', 'suspend-user-modal'); } } diff --git a/app/assets/javascripts/admin/views/modals/admin_agree_flag_view.js b/app/assets/javascripts/admin/views/modals/admin-agree-flag.js.es6 similarity index 54% rename from app/assets/javascripts/admin/views/modals/admin_agree_flag_view.js rename to app/assets/javascripts/admin/views/modals/admin-agree-flag.js.es6 index cabb3c7fde..0a4aba513f 100644 --- a/app/assets/javascripts/admin/views/modals/admin_agree_flag_view.js +++ b/app/assets/javascripts/admin/views/modals/admin-agree-flag.js.es6 @@ -1,4 +1,6 @@ -Discourse.AdminAgreeFlagView = Discourse.ModalBodyView.extend({ +import ModalBodyView from "discourse/views/modal-body"; + +export default ModalBodyView.extend({ templateName: 'admin/templates/modal/admin_agree_flag', title: I18n.t('admin.flags.agree_flag_modal_title') }); diff --git a/app/assets/javascripts/admin/views/modals/admin_badge_preview_view.js b/app/assets/javascripts/admin/views/modals/admin-badge-preview.js.es6 similarity index 55% rename from app/assets/javascripts/admin/views/modals/admin_badge_preview_view.js rename to app/assets/javascripts/admin/views/modals/admin-badge-preview.js.es6 index 0d890b3d66..6431ba9362 100644 --- a/app/assets/javascripts/admin/views/modals/admin_badge_preview_view.js +++ b/app/assets/javascripts/admin/views/modals/admin-badge-preview.js.es6 @@ -1,5 +1,6 @@ +import ModalBodyView from "discourse/views/modal-body"; -Discourse.AdminBadgePreviewView = Discourse.ModalBodyView.extend({ +export default ModalBodyView.extend({ templateName: 'admin/templates/modal/admin_badge_preview', title: I18n.t('admin.badges.preview.modal_title') }); diff --git a/app/assets/javascripts/admin/views/modals/admin-delete-flag.js.es6 b/app/assets/javascripts/admin/views/modals/admin-delete-flag.js.es6 new file mode 100644 index 0000000000..379b2ef773 --- /dev/null +++ b/app/assets/javascripts/admin/views/modals/admin-delete-flag.js.es6 @@ -0,0 +1,6 @@ +import ModalBodyView from "discourse/views/modal-body"; + +export default ModalBodyView.extend({ + templateName: 'admin/templates/modal/admin_delete_flag', + title: I18n.t('admin.flags.delete_flag_modal_title') +}); diff --git a/app/assets/javascripts/admin/views/modals/admin_edit_badge_groupings_view.js b/app/assets/javascripts/admin/views/modals/admin-edit-badge-groupings.js.es6 similarity index 58% rename from app/assets/javascripts/admin/views/modals/admin_edit_badge_groupings_view.js rename to app/assets/javascripts/admin/views/modals/admin-edit-badge-groupings.js.es6 index cf2227f35b..ccc5f49a3b 100644 --- a/app/assets/javascripts/admin/views/modals/admin_edit_badge_groupings_view.js +++ b/app/assets/javascripts/admin/views/modals/admin-edit-badge-groupings.js.es6 @@ -1,5 +1,6 @@ +import ModalBodyView from "discourse/views/modal-body"; -Discourse.AdminEditBadgeGroupingsView = Discourse.ModalBodyView.extend({ +export default ModalBodyView.extend({ templateName: 'admin/templates/modal/admin_edit_badge_groupings', title: I18n.t('admin.badges.badge_groupings.modal_title') }); diff --git a/app/assets/javascripts/admin/views/modals/admin-staff-action-log-details.js.es6 b/app/assets/javascripts/admin/views/modals/admin-staff-action-log-details.js.es6 new file mode 100644 index 0000000000..a31a61e0c9 --- /dev/null +++ b/app/assets/javascripts/admin/views/modals/admin-staff-action-log-details.js.es6 @@ -0,0 +1,6 @@ +import ModalBodyView from "discourse/views/modal-body"; + +export default ModalBodyView.extend({ + templateName: 'admin/templates/logs/details_modal', + title: I18n.t('admin.logs.staff_actions.modal_title') +}); diff --git a/app/assets/javascripts/admin/views/modals/admin_start_backup_view.js b/app/assets/javascripts/admin/views/modals/admin-start-backup.js.es6 similarity index 56% rename from app/assets/javascripts/admin/views/modals/admin_start_backup_view.js rename to app/assets/javascripts/admin/views/modals/admin-start-backup.js.es6 index b59207f26c..e363ee1a15 100644 --- a/app/assets/javascripts/admin/views/modals/admin_start_backup_view.js +++ b/app/assets/javascripts/admin/views/modals/admin-start-backup.js.es6 @@ -1,4 +1,6 @@ -Discourse.AdminStartBackupView = Discourse.ModalBodyView.extend({ +import ModalBodyView from "discourse/views/modal-body"; + +export default ModalBodyView.extend({ templateName: 'admin/templates/modal/admin_start_backup', title: I18n.t('admin.backups.operations.backup.confirm') }); diff --git a/app/assets/javascripts/admin/views/modals/admin-suspend-user.js.es6 b/app/assets/javascripts/admin/views/modals/admin-suspend-user.js.es6 new file mode 100644 index 0000000000..9f3dcb1635 --- /dev/null +++ b/app/assets/javascripts/admin/views/modals/admin-suspend-user.js.es6 @@ -0,0 +1,6 @@ +import ModalBodyView from "discourse/views/modal-body"; + +export default ModalBodyView.extend({ + templateName: 'admin/templates/modal/admin_suspend_user', + title: I18n.t('admin.user.suspend_modal_title') +}); diff --git a/app/assets/javascripts/admin/views/modals/admin_delete_flag_view.js b/app/assets/javascripts/admin/views/modals/admin_delete_flag_view.js deleted file mode 100644 index 204e7b382a..0000000000 --- a/app/assets/javascripts/admin/views/modals/admin_delete_flag_view.js +++ /dev/null @@ -1,12 +0,0 @@ -/** - A modal view for deleting a flag. - - @class AdminDeleteFlagView - @extends Discourse.ModalBodyView - @namespace Discourse - @module Discourse -**/ -Discourse.AdminDeleteFlagView = Discourse.ModalBodyView.extend({ - templateName: 'admin/templates/modal/admin_delete_flag', - title: I18n.t('admin.flags.delete_flag_modal_title') -}); diff --git a/app/assets/javascripts/admin/views/modals/admin_staff_action_log_details_view.js b/app/assets/javascripts/admin/views/modals/admin_staff_action_log_details_view.js deleted file mode 100644 index 7e6e623e30..0000000000 --- a/app/assets/javascripts/admin/views/modals/admin_staff_action_log_details_view.js +++ /dev/null @@ -1,12 +0,0 @@ -/** - A modal view for details of a staff action log record in a modal. - - @class AdminStaffActionLogDetailsView - @extends Discourse.ModalBodyView - @namespace Discourse - @module Discourse -**/ -Discourse.AdminStaffActionLogDetailsView = Discourse.ModalBodyView.extend({ - templateName: 'admin/templates/logs/details_modal', - title: I18n.t('admin.logs.staff_actions.modal_title') -}); diff --git a/app/assets/javascripts/admin/views/modals/admin_suspend_user_view.js b/app/assets/javascripts/admin/views/modals/admin_suspend_user_view.js deleted file mode 100644 index 102a5e765c..0000000000 --- a/app/assets/javascripts/admin/views/modals/admin_suspend_user_view.js +++ /dev/null @@ -1,12 +0,0 @@ -/** - A modal view for suspending a user. - - @class AdminSuspendUserView - @extends Discourse.ModalBodyView - @namespace Discourse - @module Discourse -**/ -Discourse.AdminSuspendUserView = Discourse.ModalBodyView.extend({ - templateName: 'admin/templates/modal/admin_suspend_user', - title: I18n.t('admin.user.suspend_modal_title') -}); diff --git a/app/assets/javascripts/admin/views/modals/change-site-customization-details.js.es6 b/app/assets/javascripts/admin/views/modals/change-site-customization-details.js.es6 new file mode 100644 index 0000000000..28cc323e48 --- /dev/null +++ b/app/assets/javascripts/admin/views/modals/change-site-customization-details.js.es6 @@ -0,0 +1,6 @@ +import ModalBodyView from "discourse/views/modal-body"; + +export default ModalBodyView.extend({ + templateName: 'admin/templates/logs/site_customization_change_modal', + title: I18n.t('admin.logs.staff_actions.modal_title') +}); diff --git a/app/assets/javascripts/admin/views/modals/change_site_customization_details_view.js b/app/assets/javascripts/admin/views/modals/change_site_customization_details_view.js deleted file mode 100644 index 7728bf7775..0000000000 --- a/app/assets/javascripts/admin/views/modals/change_site_customization_details_view.js +++ /dev/null @@ -1,13 +0,0 @@ -/** - A modal view for details of a staff action log record in a modal - for when a site customization is created or changed. - - @class ChangeSiteCustomizationDetailsView - @extends Discourse.ModalBodyView - @namespace Discourse - @module Discourse -**/ -Discourse.ChangeSiteCustomizationDetailsView = Discourse.ModalBodyView.extend({ - templateName: 'admin/templates/logs/site_customization_change_modal', - title: I18n.t('admin.logs.staff_actions.modal_title') -}); diff --git a/app/assets/javascripts/admin/views/modals/delete-site-customization-details.js.es6 b/app/assets/javascripts/admin/views/modals/delete-site-customization-details.js.es6 new file mode 100644 index 0000000000..28cc323e48 --- /dev/null +++ b/app/assets/javascripts/admin/views/modals/delete-site-customization-details.js.es6 @@ -0,0 +1,6 @@ +import ModalBodyView from "discourse/views/modal-body"; + +export default ModalBodyView.extend({ + templateName: 'admin/templates/logs/site_customization_change_modal', + title: I18n.t('admin.logs.staff_actions.modal_title') +}); diff --git a/app/assets/javascripts/admin/views/modals/delete_site_customization_details_view.js b/app/assets/javascripts/admin/views/modals/delete_site_customization_details_view.js deleted file mode 100644 index a4670c6974..0000000000 --- a/app/assets/javascripts/admin/views/modals/delete_site_customization_details_view.js +++ /dev/null @@ -1,13 +0,0 @@ -/** - A modal view for details of a staff action log record in a modal - for when a site customization is deleted. - - @class DeleteSiteCustomizationDetailsView - @extends Discourse.ModalBodyView - @namespace Discourse - @module Discourse -**/ -Discourse.DeleteSiteCustomizationDetailsView = Discourse.ModalBodyView.extend({ - templateName: 'admin/templates/logs/site_customization_change_modal', - title: I18n.t('admin.logs.staff_actions.modal_title') -}); diff --git a/app/assets/javascripts/discourse/controllers/feature-topic.js.es6 b/app/assets/javascripts/discourse/controllers/feature-topic.js.es6 new file mode 100644 index 0000000000..f7ae397e82 --- /dev/null +++ b/app/assets/javascripts/discourse/controllers/feature-topic.js.es6 @@ -0,0 +1,77 @@ +import ModalFunctionality from 'discourse/mixins/modal-functionality'; +import ObjectController from 'discourse/controllers/object'; +import { categoryLinkHTML } from 'discourse/helpers/category-link'; + +export default ObjectController.extend(ModalFunctionality, { + needs: ["topic"], + + loading: true, + pinnedInCategoryCount: 0, + pinnedGloballyCount: 0, + bannerCount: 0, + + categoryLink: function() { + return categoryLinkHTML(this.get("category"), { allowUncategorized: true }); + }.property("category"), + + unPinMessage: function() { + return this.get("pinned_globally") ? + I18n.t("topic.feature_topic.unpin_globally") : + I18n.t("topic.feature_topic.unpin", { categoryLink: this.get("categoryLink") }); + }.property("categoryLink", "pinned_globally"), + + pinMessage: function() { + return I18n.t("topic.feature_topic.pin", { categoryLink: this.get("categoryLink") }); + }.property("categoryLink"), + + alreadyPinnedMessage: function() { + return I18n.t("topic.feature_topic.already_pinned", { categoryLink: this.get("categoryLink"), count: this.get("pinnedInCategoryCount") }); + }.property("categoryLink", "pinnedInCategoryCount"), + + onShow() { + const self = this; + + this.set("loading", true); + + return Discourse.ajax("/topics/feature_stats.json", { + data: { category_id: this.get("category.id") } + }).then(function(result) { + if (result) { + self.setProperties({ + pinnedInCategoryCount: result.pinned_in_category_count, + pinnedGloballyCount: result.pinned_globally_count, + bannerCount: result.banner_count, + }); + } + }).finally(function() { + self.set("loading", false); + }); + }, + + _forwardAction(name) { + this.get("controllers.topic").send(name); + this.send("closeModal"); + }, + + _confirmBeforePinning(count, name, action) { + if (count < 4) { + this._forwardAction(action); + } else { + this.send("hideModal"); + const message = I18n.t("topic.feature_topic.confirm_" + name, { count: count }); + bootbox.confirm( + message, I18n.t("no_value"), I18n.t("yes_value"), + (confirmed) => confirmed ? this._forwardAction(action) : this.send("reopenModal") + ); + } + }, + + actions: { + pin() { this._confirmBeforePinning(this.get("pinnedInCategoryCount"), "pin", "togglePinned"); }, + pinGlobally() { this._confirmBeforePinning(this.get("pinnedGloballyCount"), "pin_globally", "pinGlobally"); }, + unpin() { this._forwardAction("togglePinned"); }, + makeBanner() { this._forwardAction("makeBanner"); }, + removeBanner() { this._forwardAction("removeBanner"); }, + } + +}); diff --git a/app/assets/javascripts/discourse/controllers/topic.js.es6 b/app/assets/javascripts/discourse/controllers/topic.js.es6 index e0da67fe63..c99a986550 100644 --- a/app/assets/javascripts/discourse/controllers/topic.js.es6 +++ b/app/assets/javascripts/discourse/controllers/topic.js.es6 @@ -94,6 +94,19 @@ export default ObjectController.extend(Discourse.SelectedPostsCount, BufferedCon this.set('selectedReplies', []); }.on('init'), + _togglePinnedStates(property) { + const value = this.get('pinned_at') ? false : true, + topic = this.get('content'); + + // optimistic update + topic.setProperties({ + pinned_at: value, + pinned_globally: value + }); + + return topic.saveStatus(property, value); + }, + actions: { deleteTopic() { this.deleteTopic(); @@ -352,13 +365,28 @@ export default ObjectController.extend(Discourse.SelectedPostsCount, BufferedCon }, togglePinned() { - // Note that this is different than clearPin - this.get('content').setStatus('pinned', this.get('pinned_at') ? false : true); + const value = this.get('pinned_at') ? false : true, + topic = this.get('content'); + + // optimistic update + topic.setProperties({ + pinned_at: value ? moment() : null, + pinned_globally: false + }); + + return topic.saveStatus("pinned", value); }, - togglePinnedGlobally() { - // Note that this is different than clearPin - this.get('content').setStatus('pinned_globally', this.get('pinned_at') ? false : true); + pinGlobally() { + const topic = this.get('content'); + + // optimistic update + topic.setProperties({ + pinned_at: moment(), + pinned_globally: true + }); + + return topic.saveStatus("pinned_globally", true); }, toggleArchived() { diff --git a/app/assets/javascripts/discourse/lib/show-modal.js.es6 b/app/assets/javascripts/discourse/lib/show-modal.js.es6 index f12435c496..667a344ddd 100644 --- a/app/assets/javascripts/discourse/lib/show-modal.js.es6 +++ b/app/assets/javascripts/discourse/lib/show-modal.js.es6 @@ -1,19 +1,15 @@ export default function showModal(name, model) { - // We use the container here because modals are like singletons // in Discourse. Only one can be shown with a particular state. const route = Discourse.__container__.lookup('route:application'); route.controllerFor('modal').set('modalClass', null); - route.render(name, {into: 'modal', outlet: 'modalBody'}); + route.render(name, { into: 'modal', outlet: 'modalBody' }); + const controller = route.controllerFor(name); if (controller) { - if (model) { - controller.set('model', model); - } - if (controller.onShow) { - controller.onShow(); - } + if (model) { controller.set('model', model); } + if (controller.onShow) { controller.onShow(); } controller.set('flashMessage', null); } return controller; diff --git a/app/assets/javascripts/discourse/models/topic.js.es6 b/app/assets/javascripts/discourse/models/topic.js.es6 index 5ae5ee7ec4..93ff2850de 100644 --- a/app/assets/javascripts/discourse/models/topic.js.es6 +++ b/app/assets/javascripts/discourse/models/topic.js.es6 @@ -145,24 +145,16 @@ const Topic = Discourse.Model.extend({ toggleStatus(property) { this.toggleProperty(property); - this.saveStatus(property, this.get(property) ? true : false); - }, - - setStatus(property, value) { - this.set(property, value); - this.saveStatus(property, value); + this.saveStatus(property, !this.get(property)); }, saveStatus(property, value) { if (property === 'closed' && value === true) { this.set('details.auto_close_at', null); } - if (property === 'pinned') { - this.set('pinned_at', value ? moment() : null); - } return Discourse.ajax(this.get('url') + "/status", { type: 'PUT', - data: {status: property, enabled: value ? 'true' : 'false' } + data: { status: property, enabled: !!value } }); }, diff --git a/app/assets/javascripts/discourse/routes/application.js.es6 b/app/assets/javascripts/discourse/routes/application.js.es6 index 681a097cbd..3ba76b6490 100644 --- a/app/assets/javascripts/discourse/routes/application.js.es6 +++ b/app/assets/javascripts/discourse/routes/application.js.es6 @@ -102,7 +102,7 @@ const ApplicationRoute = Discourse.Route.extend({ // Close the current modal, and destroy its state. closeModal() { - this.render('hide-modal', {into: 'modal', outlet: 'modalBody'}); + this.render('hide-modal', { into: 'modal', outlet: 'modalBody' }); }, /** diff --git a/app/assets/javascripts/discourse/routes/topic.js.es6 b/app/assets/javascripts/discourse/routes/topic.js.es6 index 1b14742861..d7948ce3a3 100644 --- a/app/assets/javascripts/discourse/routes/topic.js.es6 +++ b/app/assets/javascripts/discourse/routes/topic.js.es6 @@ -59,6 +59,11 @@ const TopicRoute = Discourse.Route.extend(ShowFooter, { this.controllerFor('modal').set('modalClass', 'edit-auto-close-modal'); }, + showFeatureTopic() { + showModal('featureTopic', this.modelFor('topic')); + this.controllerFor('modal').set('modalClass', 'feature-topic-modal'); + }, + showInvite() { showModal('invite', this.modelFor('topic')); this.controllerFor('invite').reset(); diff --git a/app/assets/javascripts/discourse/templates/modal/feature-topic.hbs b/app/assets/javascripts/discourse/templates/modal/feature-topic.hbs new file mode 100644 index 0000000000..b517a37624 --- /dev/null +++ b/app/assets/javascripts/discourse/templates/modal/feature-topic.hbs @@ -0,0 +1,62 @@ + + diff --git a/app/assets/javascripts/discourse/templates/topic-admin-menu.hbs b/app/assets/javascripts/discourse/templates/topic-admin-menu.hbs index ef204205eb..0840dfc347 100644 --- a/app/assets/javascripts/discourse/templates/topic-admin-menu.hbs +++ b/app/assets/javascripts/discourse/templates/topic-admin-menu.hbs @@ -27,26 +27,11 @@ {{#unless isPrivateMessage}} -
  • - {{#if isBanner}} - {{d-button action="removeBanner" icon="bullhorn" label="topic.actions.remove_banner" class="btn-admin"}} - {{else}} - {{#if visible}} - {{d-button action="makeBanner" icon="bullhorn" label="topic.actions.make_banner" class="btn-admin"}} - {{/if}} - {{/if}} -
  • - -
  • - {{#if pinned_at}} - {{d-button action="togglePinned" icon="thumb-tack" label="topic.actions.unpin" class="btn-admin"}} - {{else}} - {{#if visible}} - {{d-button action="togglePinned" icon="thumb-tack" label="topic.actions.pin" class="btn-admin"}} - {{d-button action="togglePinnedGlobally" icon="thumb-tack" label="topic.actions.pin_globally" class="btn-admin"}} - {{/if}} - {{/if}} -
  • + {{#if visible}} +
  • + {{d-button action="showFeatureTopic" icon="bullhorn" label="topic.actions.feature" class="btn-admin"}} +
  • + {{/if}} {{/unless}}
  • diff --git a/app/assets/javascripts/discourse/views/archetype-options-modal.js.es6 b/app/assets/javascripts/discourse/views/archetype-options-modal.js.es6 index 2daa63756d..d6ebb0c277 100644 --- a/app/assets/javascripts/discourse/views/archetype-options-modal.js.es6 +++ b/app/assets/javascripts/discourse/views/archetype-options-modal.js.es6 @@ -1,4 +1,6 @@ -export default Discourse.ModalBodyView.extend({ +import ModalBodyView from "discourse/views/modal-body"; + +export default ModalBodyView.extend({ templateName: 'modal/archetype_options', title: I18n.t('topic.options') }); diff --git a/app/assets/javascripts/discourse/views/avatar-selector.js.es6 b/app/assets/javascripts/discourse/views/avatar-selector.js.es6 index c87e91fcdf..40414660a6 100644 --- a/app/assets/javascripts/discourse/views/avatar-selector.js.es6 +++ b/app/assets/javascripts/discourse/views/avatar-selector.js.es6 @@ -1,4 +1,6 @@ -export default Discourse.ModalBodyView.extend({ +import ModalBodyView from "discourse/views/modal-body"; + +export default ModalBodyView.extend({ templateName: 'modal/avatar_selector', classNames: ['avatar-selector'], title: I18n.t('user.change_avatar.title'), @@ -9,10 +11,6 @@ export default Discourse.ModalBodyView.extend({ // *HACK* used to select the proper radio button, cause {{action}} // stops the default behavior selectedChanged: function() { - var self = this; - Em.run.next(function() { - var value = self.get('controller.selected'); - $('input:radio[name="avatar"]').val([value]); - }); + Em.run.next(() => $('input:radio[name="avatar"]').val([this.get('controller.selected')]) ); }.observes('controller.selected') }); diff --git a/app/assets/javascripts/discourse/views/change-owner.js.es6 b/app/assets/javascripts/discourse/views/change-owner.js.es6 index afce839d67..604dfbe562 100644 --- a/app/assets/javascripts/discourse/views/change-owner.js.es6 +++ b/app/assets/javascripts/discourse/views/change-owner.js.es6 @@ -1,4 +1,6 @@ -export default Discourse.ModalBodyView.extend({ +import ModalBodyView from "discourse/views/modal-body"; + +export default ModalBodyView.extend({ templateName: 'modal/change_owner', title: I18n.t('topic.change_owner.title') }); diff --git a/app/assets/javascripts/discourse/views/create-account.js.es6 b/app/assets/javascripts/discourse/views/create-account.js.es6 index 8de0a1864d..da0e281582 100644 --- a/app/assets/javascripts/discourse/views/create-account.js.es6 +++ b/app/assets/javascripts/discourse/views/create-account.js.es6 @@ -1,4 +1,6 @@ -export default Discourse.ModalBodyView.extend({ +import ModalBodyView from "discourse/views/modal-body"; + +export default ModalBodyView.extend({ templateName: 'modal/create-account', title: I18n.t('create_account.title'), classNames: ['create-account'], @@ -6,7 +8,7 @@ export default Discourse.ModalBodyView.extend({ _setup: function() { // allows the submission the form when pressing 'ENTER' on *any* text input field // but only when the submit button is enabled - var createAccountController = this.get('controller'); + const createAccountController = this.get('controller'); Em.run.schedule('afterRender', function() { $("input[type='text'], input[type='password']").keydown(function(e) { if (createAccountController.get('submitDisabled') === false && e.keyCode === 13) { diff --git a/app/assets/javascripts/discourse/views/edit-category.js.es6 b/app/assets/javascripts/discourse/views/edit-category.js.es6 index 6d0fb05a5c..ea93cc99be 100644 --- a/app/assets/javascripts/discourse/views/edit-category.js.es6 +++ b/app/assets/javascripts/discourse/views/edit-category.js.es6 @@ -1,4 +1,6 @@ -export default Discourse.ModalBodyView.extend({ +import ModalBodyView from "discourse/views/modal-body"; + +export default ModalBodyView.extend({ templateName: 'modal/edit-category', _initializePanels: function() { diff --git a/app/assets/javascripts/discourse/views/edit-topic-auto-close.js.es6 b/app/assets/javascripts/discourse/views/edit-topic-auto-close.js.es6 index 57d7e55f66..b5b5c33287 100644 --- a/app/assets/javascripts/discourse/views/edit-topic-auto-close.js.es6 +++ b/app/assets/javascripts/discourse/views/edit-topic-auto-close.js.es6 @@ -1,4 +1,6 @@ -export default Discourse.ModalBodyView.extend({ +import ModalBodyView from "discourse/views/modal-body"; + +export default ModalBodyView.extend({ templateName: 'modal/auto_close', title: I18n.t('topic.auto_close_title') }); diff --git a/app/assets/javascripts/discourse/views/feature-topic.js.es6 b/app/assets/javascripts/discourse/views/feature-topic.js.es6 new file mode 100644 index 0000000000..2a106541e0 --- /dev/null +++ b/app/assets/javascripts/discourse/views/feature-topic.js.es6 @@ -0,0 +1,6 @@ +import ModalBodyView from "discourse/views/modal-body"; + +export default ModalBodyView.extend({ + templateName: 'modal/feature-topic', + title: I18n.t('topic.feature_topic.title') +}); diff --git a/app/assets/javascripts/discourse/views/flag.js.es6 b/app/assets/javascripts/discourse/views/flag.js.es6 index a819d7efbe..b948c35f0a 100644 --- a/app/assets/javascripts/discourse/views/flag.js.es6 +++ b/app/assets/javascripts/discourse/views/flag.js.es6 @@ -1,4 +1,6 @@ -export default Discourse.ModalBodyView.extend({ +import ModalBodyView from "discourse/views/modal-body"; + +export default ModalBodyView.extend({ templateName: 'modal/flag', title: function() { @@ -6,12 +8,13 @@ export default Discourse.ModalBodyView.extend({ }.property('controller.flagTopic'), selectedChanged: function() { - var self = this; + const self = this; + Em.run.next(function() { self.$("input[type='radio']").prop('checked', false); - var nameKey = self.get('controller.selected.name_key'); - if (!nameKey) return; + const nameKey = self.get('controller.selected.name_key'); + if (!nameKey) { return; } self.$('#radio_' + nameKey).prop('checked', 'true'); }); diff --git a/app/assets/javascripts/discourse/views/forgot-password.js.es6 b/app/assets/javascripts/discourse/views/forgot-password.js.es6 index 5bb6b40ee1..40f4094b0f 100644 --- a/app/assets/javascripts/discourse/views/forgot-password.js.es6 +++ b/app/assets/javascripts/discourse/views/forgot-password.js.es6 @@ -1,4 +1,6 @@ -export default Discourse.ModalBodyView.extend({ +import ModalBodyView from "discourse/views/modal-body"; + +export default ModalBodyView.extend({ templateName: 'modal/forgot_password', title: I18n.t('forgot_password.title'), }); diff --git a/app/assets/javascripts/discourse/views/history.js.es6 b/app/assets/javascripts/discourse/views/history.js.es6 index f88b3f178c..7bec4d846e 100644 --- a/app/assets/javascripts/discourse/views/history.js.es6 +++ b/app/assets/javascripts/discourse/views/history.js.es6 @@ -1,9 +1,11 @@ -export default Discourse.ModalBodyView.extend({ +import ModalBodyView from "discourse/views/modal-body"; + +export default ModalBodyView.extend({ templateName: 'modal/history', title: I18n.t('history'), resizeModal: function(){ - var viewPortHeight = $(window).height(); + const viewPortHeight = $(window).height(); this.$(".modal-body").css("max-height", Math.floor(0.8 * viewPortHeight) + "px"); }.on("didInsertElement") }); diff --git a/app/assets/javascripts/discourse/views/invite-private.js.es6 b/app/assets/javascripts/discourse/views/invite-private.js.es6 index 0b827d29b7..461a6e102d 100644 --- a/app/assets/javascripts/discourse/views/invite-private.js.es6 +++ b/app/assets/javascripts/discourse/views/invite-private.js.es6 @@ -1,4 +1,6 @@ -export default Discourse.ModalBodyView.extend({ +import ModalBodyView from "discourse/views/modal-body"; + +export default ModalBodyView.extend({ templateName: 'modal/invite_private', title: I18n.t('topic.invite_private.title') }); diff --git a/app/assets/javascripts/discourse/views/invite.js.es6 b/app/assets/javascripts/discourse/views/invite.js.es6 index 6f8a2e8f19..03f4a72c4d 100644 --- a/app/assets/javascripts/discourse/views/invite.js.es6 +++ b/app/assets/javascripts/discourse/views/invite.js.es6 @@ -1,10 +1,12 @@ -export default Discourse.ModalBodyView.extend({ +import ModalBodyView from "discourse/views/modal-body"; + +export default ModalBodyView.extend({ templateName: 'modal/invite', + title: function() { - if (this.get('controller.invitingToTopic')) { - return I18n.t('topic.invite_reply.title'); - } else { - return I18n.t('user.invited.create'); - } + return this.get('controller.invitingToTopic') ? + I18n.t('topic.invite_reply.title') : + I18n.t('user.invited.create'); }.property('controller.invitingToTopic') + }); diff --git a/app/assets/javascripts/discourse/views/keyboard-shortcuts-help.js.es6 b/app/assets/javascripts/discourse/views/keyboard-shortcuts-help.js.es6 index 33ed361518..eeb174f620 100644 --- a/app/assets/javascripts/discourse/views/keyboard-shortcuts-help.js.es6 +++ b/app/assets/javascripts/discourse/views/keyboard-shortcuts-help.js.es6 @@ -1,4 +1,6 @@ -export default Discourse.ModalBodyView.extend({ +import ModalBodyView from "discourse/views/modal-body"; + +export default ModalBodyView.extend({ templateName: 'modal/keyboard_shortcuts_help', title: I18n.t('keyboard_shortcuts_help.title') }); diff --git a/app/assets/javascripts/discourse/views/login.js.es6 b/app/assets/javascripts/discourse/views/login.js.es6 index 334e91774b..f2b61efb5a 100644 --- a/app/assets/javascripts/discourse/views/login.js.es6 +++ b/app/assets/javascripts/discourse/views/login.js.es6 @@ -1,4 +1,6 @@ -export default Discourse.ModalBodyView.extend({ +import ModalBodyView from "discourse/views/modal-body"; + +export default ModalBodyView.extend({ templateName: 'modal/login', title: I18n.t('login.title'), classNames: ['login-modal'], @@ -9,7 +11,7 @@ export default Discourse.ModalBodyView.extend({ }, _setup: function() { - var loginController = this.get('controller'); + const loginController = this.get('controller'); // Get username and password from the browser's password manager, // if it filled the hidden static login form: @@ -18,10 +20,8 @@ export default Discourse.ModalBodyView.extend({ Em.run.schedule('afterRender', function() { $('#login-account-password, #login-account-name').keydown(function(e) { - if (e.keyCode === 13) { - if (!loginController.get('loginDisabled')) { - loginController.send('login'); - } + if (e.keyCode === 13 && !loginController.get('loginDisabled')) { + loginController.send('login'); } }); }); diff --git a/app/assets/javascripts/discourse/views/merge-topic.js.es6 b/app/assets/javascripts/discourse/views/merge-topic.js.es6 index b4394c57b7..bf31e00606 100644 --- a/app/assets/javascripts/discourse/views/merge-topic.js.es6 +++ b/app/assets/javascripts/discourse/views/merge-topic.js.es6 @@ -1,4 +1,6 @@ -export default Discourse.ModalBodyView.extend({ +import ModalBodyView from "discourse/views/modal-body"; + +export default ModalBodyView.extend({ templateName: 'modal/merge_topic', title: I18n.t('topic.merge_topic.title') }); diff --git a/app/assets/javascripts/discourse/views/modal-body.js.es6 b/app/assets/javascripts/discourse/views/modal-body.js.es6 new file mode 100644 index 0000000000..720e955164 --- /dev/null +++ b/app/assets/javascripts/discourse/views/modal-body.js.es6 @@ -0,0 +1,30 @@ +export default Discourse.View.extend({ + focusInput: true, + + _setupModal: function() { + $('#modal-alert').hide(); + $('#discourse-modal').modal('show'); + + // Focus on first element + if (!Discourse.Mobile.mobileView && this.get('focusInput')) { + Em.run.schedule('afterRender', () => this.$('input:first').focus() ); + } + + const title = this.get('title'); + if (title) { + this.set('controller.controllers.modal.title', title); + } + }.on('didInsertElement'), + + flashMessageChanged: function() { + const flashMessage = this.get('controller.flashMessage'); + if (flashMessage) { + const messageClass = flashMessage.get('messageClass') || 'success'; + $('#modal-alert').hide() + .removeClass('alert-error', 'alert-success') + .addClass("alert alert-" + messageClass).html(flashMessage.get('message')) + .fadeIn(); + } + }.observes('controller.flashMessage') + +}); diff --git a/app/assets/javascripts/discourse/views/modal.js.es6 b/app/assets/javascripts/discourse/views/modal.js.es6 index 8da41fcc3a..4621445dc6 100644 --- a/app/assets/javascripts/discourse/views/modal.js.es6 +++ b/app/assets/javascripts/discourse/views/modal.js.es6 @@ -4,13 +4,13 @@ export default Ember.View.extend({ classNameBindings: [':modal', ':hidden', 'controller.modalClass'], click: function(e) { - var $target = $(e.target); + const $target = $(e.target); if ($target.hasClass("modal-middle-container") || $target.hasClass("modal-outer-container")) { - // Delegate click to modal backdrop if clicked outside. We do this - // because some CSS of ours seems to cover the backdrop and makes it - // unclickable. - $('.modal-backdrop').click(); + // Delegate click to modal close if clicked outside. + // We do this because some CSS of ours seems to cover + // the backdrop and makes it unclickable. + $('.modal-header a.close').click(); } } }); diff --git a/app/assets/javascripts/discourse/views/modal_body_view.js b/app/assets/javascripts/discourse/views/modal_body_view.js deleted file mode 100644 index 10eec8f6cd..0000000000 --- a/app/assets/javascripts/discourse/views/modal_body_view.js +++ /dev/null @@ -1,48 +0,0 @@ -/** - A base class for helping us display modal content - - @class ModalBodyView - @extends Discourse.View - @namespace Discourse - @module Discourse -**/ -Discourse.ModalBodyView = Discourse.View.extend({ - focusInput: true, - - _setupModal: function() { - var self = this, - $discourseModal = $('#discourse-modal'); - - $discourseModal.modal('show'); - $discourseModal.one("hide", function () { - self.get("controller").send("closeModal"); - }); - - $('#modal-alert').hide(); - - // Focus on first element - if (!Discourse.Mobile.mobileView && self.get('focusInput')) { - Em.run.schedule('afterRender', function() { - self.$('input:first').focus(); - }); - } - - var title = this.get('title'); - if (title) { - this.set('controller.controllers.modal.title', title); - } - }.on('didInsertElement'), - - flashMessageChanged: function() { - var flashMessage = this.get('controller.flashMessage'); - if (flashMessage) { - var messageClass = flashMessage.get('messageClass') || 'success'; - var $alert = $('#modal-alert').hide().removeClass('alert-error', 'alert-success'); - $alert.addClass("alert alert-" + messageClass).html(flashMessage.get('message')); - $alert.fadeIn(); - } - }.observes('controller.flashMessage') - -}); - - diff --git a/app/assets/javascripts/discourse/views/not-activated.js.es6 b/app/assets/javascripts/discourse/views/not-activated.js.es6 index 30f4da1172..86e942fc3d 100644 --- a/app/assets/javascripts/discourse/views/not-activated.js.es6 +++ b/app/assets/javascripts/discourse/views/not-activated.js.es6 @@ -1,4 +1,6 @@ -export default Discourse.ModalBodyView.extend({ +import ModalBodyView from "discourse/views/modal-body"; + +export default ModalBodyView.extend({ templateName: 'modal/not_activated', title: I18n.t('log_in') }); diff --git a/app/assets/javascripts/discourse/views/raw-email.es6 b/app/assets/javascripts/discourse/views/raw-email.es6 index d529b1063b..c14d201f31 100644 --- a/app/assets/javascripts/discourse/views/raw-email.es6 +++ b/app/assets/javascripts/discourse/views/raw-email.es6 @@ -1,9 +1,11 @@ -export default Discourse.ModalBodyView.extend({ +import ModalBodyView from "discourse/views/modal-body"; + +export default ModalBodyView.extend({ templateName: 'modal/raw_email', title: I18n.t('raw_email.title'), resizeModal: function(){ - var viewPortHeight = $(window).height(); + const viewPortHeight = $(window).height(); this.$(".modal-body").css("max-height", Math.floor(0.8 * viewPortHeight) + "px"); }.on("didInsertElement") }); diff --git a/app/assets/javascripts/discourse/views/search-help.js.es6 b/app/assets/javascripts/discourse/views/search-help.js.es6 index 888c48bb4d..d16b2fc79f 100644 --- a/app/assets/javascripts/discourse/views/search-help.js.es6 +++ b/app/assets/javascripts/discourse/views/search-help.js.es6 @@ -1,4 +1,6 @@ -export default Discourse.ModalBodyView.extend({ +import ModalBodyView from "discourse/views/modal-body"; + +export default ModalBodyView.extend({ templateName: 'modal/search_help', title: I18n.t('search_help.title'), focusInput: false diff --git a/app/assets/javascripts/discourse/views/split-topic.js.es6 b/app/assets/javascripts/discourse/views/split-topic.js.es6 index b4be70f88e..1c5be40e94 100644 --- a/app/assets/javascripts/discourse/views/split-topic.js.es6 +++ b/app/assets/javascripts/discourse/views/split-topic.js.es6 @@ -1,4 +1,6 @@ -export default Discourse.ModalBodyView.extend(Discourse.SelectedPostsCount, { +import ModalBodyView from "discourse/views/modal-body"; + +export default ModalBodyView.extend(Discourse.SelectedPostsCount, { templateName: 'modal/split_topic', title: I18n.t('topic.split_topic.title') }); diff --git a/app/assets/javascripts/discourse/views/topic-bulk-actions.js.es6 b/app/assets/javascripts/discourse/views/topic-bulk-actions.js.es6 index dd6490a71f..8b8b693fb8 100644 --- a/app/assets/javascripts/discourse/views/topic-bulk-actions.js.es6 +++ b/app/assets/javascripts/discourse/views/topic-bulk-actions.js.es6 @@ -1,4 +1,6 @@ -export default Discourse.ModalBodyView.extend({ +import ModalBodyView from "discourse/views/modal-body"; + +export default ModalBodyView.extend({ templateName: 'modal/topic-bulk-actions', title: I18n.t('topics.bulk.actions') }); diff --git a/app/assets/javascripts/discourse/views/upload-selector.js.es6 b/app/assets/javascripts/discourse/views/upload-selector.js.es6 index 50b46b6960..2a46973338 100644 --- a/app/assets/javascripts/discourse/views/upload-selector.js.es6 +++ b/app/assets/javascripts/discourse/views/upload-selector.js.es6 @@ -1,10 +1,12 @@ +import ModalBodyView from "discourse/views/modal-body"; + function uploadTranslate(key, options) { - var opts = options || {}; + const opts = options || {}; if (Discourse.Utilities.allowsAttachments()) { key += "_with_attachments"; } return I18n.t("upload_selector." + key, opts); } -export default Discourse.ModalBodyView.extend({ +export default ModalBodyView.extend({ templateName: 'modal/upload_selector', classNames: ['upload-selector'], @@ -12,17 +14,16 @@ export default Discourse.ModalBodyView.extend({ uploadIcon: function() { return Discourse.Utilities.allowsAttachments() ? "fa-upload" : "fa-picture-o"; }.property(), tip: function() { - var source = this.get("controller.local") ? "local" : "remote"; - var opts = { authorized_extensions: Discourse.Utilities.authorizedExtensions() }; + const source = this.get("controller.local") ? "local" : "remote", + opts = { authorized_extensions: Discourse.Utilities.authorizedExtensions() }; return uploadTranslate(source + "_tip", opts); }.property("controller.local"), hint: function() { // cf. http://stackoverflow.com/a/9851769/11983 - var isChrome = !!window.chrome && !(!!window.opera || navigator.userAgent.indexOf(' OPR/') >= 0); - var isFirefox = typeof InstallTrigger !== 'undefined'; - var isSupported = isChrome || isFirefox; - + const isChrome = !!window.chrome && !(!!window.opera || navigator.userAgent.indexOf(' OPR/') >= 0), + isFirefox = typeof InstallTrigger !== 'undefined', + isSupported = isChrome || isFirefox; // chrome is the only browser that support copy & paste of images. return I18n.t("upload_selector.hint" + (isSupported ? "_for_supported_browsers" : "")); }.property(), @@ -32,7 +33,7 @@ export default Discourse.ModalBodyView.extend({ }.on('didInsertElement'), selectedChanged: function() { - var self = this; + const self = this; Em.run.next(function() { // *HACK* to select the proper radio button var value = self.get('controller.local') ? 'local' : 'remote'; @@ -47,9 +48,9 @@ export default Discourse.ModalBodyView.extend({ if (this.get("controller.local")) { $('#reply-control').fileupload('add', { fileInput: $('#filename-input') }); } else { - var imageUrl = $('#fileurl-input').val(); - var imageLink = $('#link-input').val(); - var composerView = this.get('controller.composerView'); + const imageUrl = $('#fileurl-input').val(), + imageLink = $('#link-input').val(), + composerView = this.get('controller.composerView'); if (this.get("controller.showMore") && imageLink.length > 3) { composerView.addMarkdown("[![](" + imageUrl +")](" + imageLink + ")"); } else { diff --git a/app/assets/javascripts/main_include.js b/app/assets/javascripts/main_include.js index b6dad34ded..489ed3c13d 100644 --- a/app/assets/javascripts/main_include.js +++ b/app/assets/javascripts/main_include.js @@ -36,7 +36,7 @@ //= require ./discourse/controllers/navigation/default //= require ./discourse/views/view //= require ./discourse/views/container -//= require ./discourse/views/modal_body_view +//= require ./discourse/views/modal-body //= require ./discourse/views/flag //= require ./discourse/views/combo-box //= require ./discourse/views/button diff --git a/app/assets/javascripts/main_include_admin.js b/app/assets/javascripts/main_include_admin.js index 9a66a6965b..6ba3cb51e8 100644 --- a/app/assets/javascripts/main_include_admin.js +++ b/app/assets/javascripts/main_include_admin.js @@ -2,7 +2,6 @@ //= require admin/models/user-field //= require admin/models/site-setting //= require admin/controllers/admin-email-skipped -//= require admin/controllers/change-site-customization-details //= require discourse/lib/export-result //= require_tree ./admin diff --git a/app/controllers/topics_controller.rb b/app/controllers/topics_controller.rb index 0f76977cc6..cdc7a2819f 100644 --- a/app/controllers/topics_controller.rb +++ b/app/controllers/topics_controller.rb @@ -158,6 +158,19 @@ class TopicsController < ApplicationController render_serialized(topics, BasicTopicSerializer) end + def feature_stats + params.require(:category_id) + category_id = params[:category_id].to_i + + topics = Topic.listable_topics.visible + + render json: { + pinned_in_category_count: topics.where(category_id: category_id).where(pinned_globally: false).where.not(pinned_at: nil).count, + pinned_globally_count: topics.where(pinned_globally: true).where.not(pinned_at: nil).count, + banner_count: topics.where(archetype: Archetype.banner).count, + } + end + def status params.require(:status) params.require(:enabled) @@ -492,7 +505,7 @@ class TopicsController < ApplicationController end def check_for_status_presence(key, attr) - invalid_param(key) unless %w(pinned_globally visible closed pinned archived).include?(attr) + invalid_param(key) unless %w(pinned pinned_globally visible closed archived).include?(attr) end def invalid_param(key) diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml index 71609c40e3..07738bf14a 100644 --- a/config/locales/client.en.yml +++ b/config/locales/client.en.yml @@ -973,10 +973,11 @@ en: open: "Open Topic" close: "Close Topic" auto_close: "Auto Close" + feature: "Feature Topic" make_banner: "Banner Topic" remove_banner: "Remove Banner Topic" - unpin: "Un-Pin Topic" pin: "Pin Topic" + unpin: "Un-Pin Topic" pin_globally: "Pin Topic Globally" unarchive: "Unarchive Topic" archive: "Archive Topic" @@ -1002,6 +1003,31 @@ en: help: 'privately flag this topic for attention or send a private notification about it' success_message: 'You successfully flagged this topic.' + feature_topic: + title: "Feature this topic" + pin: "Make this topic appear at the top of the {{categoryLink}} category." + confirm_pin: "Are you sure? You already have {{count}} pinned topics -- too many pinned topics can obscure other active topics." + unpin: "Remove this topic from the topic of the {{categoryLink}} category." + pin_note: "Users can unpin the topic individually for themselves." + already_pinned: + zero: "No topic currently pinned in {{categoryLink}}." + one: "Topic currently pinned in {{categoryLink}}: 1." + other: "Topics currently pinned in {{categoryLink}}: {{count}}." + pin_globally: "Make this topic appear at the top of all topic lists, until a staff member unpins it." + confirm_pin_globally: "Are you sure? You already have {{count}} globally pinned topics -- too many pinned topics can obscure other active topics." + unpin_globally: "Remove this topic from the top of all topic lists." + global_pin_note: "Users can unpin the topic individually for themselves." + already_pinned_globally: + zero: "No topic currently pinned globally." + one: "Topic currently pinned globally: 1." + other: "Topics currently pinned globally: {{count}}." + make_banner: "Make this topic into a banner that appears at the top of all pages." + remove_banner: "Remove the banner that appears at the top of all pages." + banner_note: "Users can dismiss the banner by closing it. Only one topic can be bannered at any given time." + already_banner: + zero: "There is currently no banner topic." + one: "There is currently a banner topic." + inviting: "Inviting..." automatically_add_to_groups_optional: "This invite also includes access to these groups: (optional, admin only)" automatically_add_to_groups_required: "This invite also includes access to these groups: (Required, admin only)" diff --git a/config/routes.rb b/config/routes.rb index c4b3851b20..427a319605 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -392,6 +392,7 @@ Discourse::Application.routes.draw do put "topics/reset-new" => 'topics#reset_new' post "topics/timings" get "topics/similar_to" + get "topics/feature_stats" get "topics/created-by/:username" => "list#topics_by", as: "topics_by", constraints: {username: USERNAME_ROUTE_FORMAT} get "topics/private-messages/:username" => "list#private_messages", as: "topics_private_messages", constraints: {username: USERNAME_ROUTE_FORMAT} get "topics/private-messages-sent/:username" => "list#private_messages_sent", as: "topics_private_messages_sent", constraints: {username: USERNAME_ROUTE_FORMAT} diff --git a/test/javascripts/integration/modal-test.js.es6 b/test/javascripts/integration/modal-test.js.es6 index 0a7fc92883..e89dce2b9c 100644 --- a/test/javascripts/integration/modal-test.js.es6 +++ b/test/javascripts/integration/modal-test.js.es6 @@ -19,7 +19,7 @@ test("modal", function() { click('.login-button'); andThen(function() { - ok(find('#discourse-modal:visible').length === 1, 'modal should appear'); + ok(find('#discourse-modal:visible').length === 1, 'modal should reappear'); }); keyEvent('#main-outlet', 'keyup', 27); From 4787e73954c88c558495ea33b23c9c5033ee92e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9gis=20Hanol?= Date: Sat, 14 Mar 2015 02:45:33 +0100 Subject: [PATCH 019/114] FIX: toggle topic status was inverted --- app/assets/javascripts/discourse/models/topic.js.es6 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/assets/javascripts/discourse/models/topic.js.es6 b/app/assets/javascripts/discourse/models/topic.js.es6 index 93ff2850de..054f35a67b 100644 --- a/app/assets/javascripts/discourse/models/topic.js.es6 +++ b/app/assets/javascripts/discourse/models/topic.js.es6 @@ -145,7 +145,7 @@ const Topic = Discourse.Model.extend({ toggleStatus(property) { this.toggleProperty(property); - this.saveStatus(property, !this.get(property)); + this.saveStatus(property, !!this.get(property)); }, saveStatus(property, value) { From 399418e1ff186651cedb3044f7d807b8105e670f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9gis=20Hanol?= Date: Sat, 14 Mar 2015 12:46:46 +0100 Subject: [PATCH 020/114] FIX: modal backup wasn't working --- .../admin/controllers/{ => modals}/admin-start-backup.js.es6 | 5 ++--- app/assets/javascripts/admin/routes/admin-backups.js.es6 | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) rename app/assets/javascripts/admin/controllers/{ => modals}/admin-start-backup.js.es6 (90%) diff --git a/app/assets/javascripts/admin/controllers/admin-start-backup.js.es6 b/app/assets/javascripts/admin/controllers/modals/admin-start-backup.js.es6 similarity index 90% rename from app/assets/javascripts/admin/controllers/admin-start-backup.js.es6 rename to app/assets/javascripts/admin/controllers/modals/admin-start-backup.js.es6 index 969216e38b..1af962e41c 100644 --- a/app/assets/javascripts/admin/controllers/admin-start-backup.js.es6 +++ b/app/assets/javascripts/admin/controllers/modals/admin-start-backup.js.es6 @@ -2,7 +2,6 @@ import ModalFunctionality from 'discourse/mixins/modal-functionality'; import Controller from 'discourse/controllers/controller'; export default Controller.extend(ModalFunctionality, { - needs: ["adminBackupsLogs"], _startBackup: function (withUploads) { @@ -17,11 +16,11 @@ export default Controller.extend(ModalFunctionality, { actions: { startBackup: function () { - return this._startBackup(); + this._startBackup(); }, startBackupWithoutUpload: function () { - return this._startBackup(false); + this._startBackup(false); }, cancel: function () { diff --git a/app/assets/javascripts/admin/routes/admin-backups.js.es6 b/app/assets/javascripts/admin/routes/admin-backups.js.es6 index 64b8984ed7..981dc5394b 100644 --- a/app/assets/javascripts/admin/routes/admin-backups.js.es6 +++ b/app/assets/javascripts/admin/routes/admin-backups.js.es6 @@ -45,7 +45,7 @@ export default Discourse.Route.extend({ actions: { startBackup() { - showModal('admin_start_backup'); + showModal('modals/admin-start-backup'); this.controllerFor('modal').set('modalClass', 'start-backup-modal'); }, From 1cc7db23707a70889dd135c0cde32ff1850013e5 Mon Sep 17 00:00:00 2001 From: Jens Maier Date: Sun, 15 Mar 2015 01:57:46 +0100 Subject: [PATCH 021/114] Fix gem load order for SFM2 importer --- script/import_scripts/smf2.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/script/import_scripts/smf2.rb b/script/import_scripts/smf2.rb index 5daa29a4cd..076824a56e 100644 --- a/script/import_scripts/smf2.rb +++ b/script/import_scripts/smf2.rb @@ -1,7 +1,7 @@ +require 'mysql2' + require File.expand_path(File.dirname(__FILE__) + '/base.rb') -require 'mysql2' -require 'color' require 'htmlentities' require 'tsort' require 'set' From b8d855227d56b053bd56cbf24f08860d2dfaabae Mon Sep 17 00:00:00 2001 From: Dan Dascalescu Date: Sat, 14 Mar 2015 21:29:17 -0700 Subject: [PATCH 022/114] Fix broken mysql2 load order in mybb import script --- script/import_scripts/mybb.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/script/import_scripts/mybb.rb b/script/import_scripts/mybb.rb index 90e09714e6..68de23d07a 100644 --- a/script/import_scripts/mybb.rb +++ b/script/import_scripts/mybb.rb @@ -1,7 +1,7 @@ -require File.expand_path(File.dirname(__FILE__) + "/base.rb") - require "mysql2" +require File.expand_path(File.dirname(__FILE__) + "/base.rb") + # Call it like this: # RAILS_ENV=production bundle exec ruby script/import_scripts/mybb.rb class ImportScripts::MyBB < ImportScripts::Base From 9cd59d382d083c36ada41c8918f87630c559461c Mon Sep 17 00:00:00 2001 From: Dan Dascalescu Date: Sat, 14 Mar 2015 22:31:08 -0700 Subject: [PATCH 023/114] Add support for MyBB table prefix --- script/import_scripts/mybb.rb | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/script/import_scripts/mybb.rb b/script/import_scripts/mybb.rb index 90e09714e6..49a2f21fde 100644 --- a/script/import_scripts/mybb.rb +++ b/script/import_scripts/mybb.rb @@ -1,12 +1,13 @@ -require File.expand_path(File.dirname(__FILE__) + "/base.rb") - require "mysql2" +require File.expand_path(File.dirname(__FILE__) + "/base.rb") + # Call it like this: # RAILS_ENV=production bundle exec ruby script/import_scripts/mybb.rb class ImportScripts::MyBB < ImportScripts::Base MYBB_DB = "mybb_db" + TABLE_PREFIX = "mybb_" BATCH_SIZE = 1000 def initialize @@ -32,15 +33,15 @@ class ImportScripts::MyBB < ImportScripts::Base puts '', "creating users" total_count = mysql_query("SELECT count(*) count - FROM mybb_users u - JOIN mybb_usergroups g ON g.gid = u.usergroup + FROM #{TABLE_PREFIX}users u + JOIN #{TABLE_PREFIX}usergroups g ON g.gid = u.usergroup WHERE g.title != 'Banned';").first['count'] batches(BATCH_SIZE) do |offset| results = mysql_query( "SELECT uid id, email email, username, regdate, g.title `group` - FROM mybb_users u - JOIN mybb_usergroups g ON g.gid = u.usergroup + FROM #{TABLE_PREFIX}users u + JOIN #{TABLE_PREFIX}usergroups g ON g.gid = u.usergroup WHERE g.title != 'Banned' ORDER BY u.uid ASC LIMIT #{BATCH_SIZE} @@ -62,7 +63,7 @@ class ImportScripts::MyBB < ImportScripts::Base def import_categories results = mysql_query(" SELECT fid id, pid parent_id, left(name, 50) name, description - FROM mybb_forums + FROM #{TABLE_PREFIX}forums ORDER BY pid ASC, fid ASC ") @@ -78,7 +79,7 @@ class ImportScripts::MyBB < ImportScripts::Base def import_posts puts "", "creating topics and posts" - total_count = mysql_query("SELECT count(*) count from mybb_posts").first["count"] + total_count = mysql_query("SELECT count(*) count from #{TABLE_PREFIX}posts").first["count"] batches(BATCH_SIZE) do |offset| results = mysql_query(" @@ -90,8 +91,8 @@ class ImportScripts::MyBB < ImportScripts::Base p.uid user_id, p.message raw, p.dateline post_time - FROM mybb_posts p, - mybb_threads t + FROM #{TABLE_PREFIX}posts p, + #{TABLE_PREFIX}threads t WHERE p.tid = t.tid ORDER BY p.dateline LIMIT #{BATCH_SIZE} @@ -105,14 +106,14 @@ class ImportScripts::MyBB < ImportScripts::Base mapped = {} # If you have imported a phpbb forum to mybb previously there might - # be a problem with mybb_threads.firstpost. If these ids are wrong + # be a problem with #{TABLE_PREFIX}threads.firstpost. If these ids are wrong # the thread cannot be imported to discourse as the topic post is # missing. This query retrieves the first_post_id manually. As it # will decrease the performance it is commented out by default. # m['first_post_id'] = mysql_query(" # SELECT p.pid id, - # FROM mybb_posts p, - # mybb_threads t + # FROM #{TABLE_PREFIX}posts p, + # #{TABLE_PREFIX}threads t # WHERE p.tid = #{m['topic_id']} AND t.tid = #{m['topic_id']} # ORDER BY p.dateline # LIMIT 1 From 876d8a5174b8255b24cef43fcfcf0874d5e851e5 Mon Sep 17 00:00:00 2001 From: Jeff Atwood Date: Sun, 15 Mar 2015 02:23:18 -0700 Subject: [PATCH 024/114] de-emphasize categories on mobile a bit --- app/assets/stylesheets/mobile/discourse.scss | 5 +++++ app/assets/stylesheets/mobile/topic-list.scss | 1 - 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/app/assets/stylesheets/mobile/discourse.scss b/app/assets/stylesheets/mobile/discourse.scss index 1aaab8a820..edd907e495 100644 --- a/app/assets/stylesheets/mobile/discourse.scss +++ b/app/assets/stylesheets/mobile/discourse.scss @@ -83,3 +83,8 @@ h2#site-text-logo margin: 0; margin-left: 10px; } + +// categories should not be bold on mobile; they fight with the topic title too much +.badge-wrapper { + font-weight: normal; +} diff --git a/app/assets/stylesheets/mobile/topic-list.scss b/app/assets/stylesheets/mobile/topic-list.scss index e682b50600..d23bc8e12a 100644 --- a/app/assets/stylesheets/mobile/topic-list.scss +++ b/app/assets/stylesheets/mobile/topic-list.scss @@ -305,6 +305,5 @@ button.dismiss-read { td.main-link { a.title { padding: 5px 10px 5px 0; - font-weight: bold; } } From 705e7105c8bf1be681ba7e363dba0ab1aab06fe4 Mon Sep 17 00:00:00 2001 From: Jeff Atwood Date: Sun, 15 Mar 2015 03:03:24 -0700 Subject: [PATCH 025/114] safer default all time post edit limit we have wiki for this now anyway --- config/site_settings.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/site_settings.yml b/config/site_settings.yml index e1e0e9ddc8..6c9c5a82ae 100644 --- a/config/site_settings.yml +++ b/config/site_settings.yml @@ -346,7 +346,7 @@ posting: default: 15 enable_private_messages: true ninja_edit_window: 300 - post_edit_time_limit: 262800 + post_edit_time_limit: 86400 edit_history_visible_to_public: client: true default: true From 98c31f399afae3fd609593be4175dac69187c3c2 Mon Sep 17 00:00:00 2001 From: riking Date: Fri, 13 Mar 2015 23:53:41 -0700 Subject: [PATCH 026/114] FEATURE: Style 'Feature Topic' dialog --- .../templates/modal/feature-topic.hbs | 115 +++++++++++------- .../common/base/topic-admin-menu.scss | 30 +++++ 2 files changed, 98 insertions(+), 47 deletions(-) diff --git a/app/assets/javascripts/discourse/templates/modal/feature-topic.hbs b/app/assets/javascripts/discourse/templates/modal/feature-topic.hbs index b517a37624..2cc24a5c1c 100644 --- a/app/assets/javascripts/discourse/templates/modal/feature-topic.hbs +++ b/app/assets/javascripts/discourse/templates/modal/feature-topic.hbs @@ -1,60 +1,81 @@ -
  • - {{d-button action="showFeatureTopic" icon="bullhorn" label="topic.actions.feature" class="btn-admin"}} + {{#if isFeatured}} + {{d-button action="showFeatureTopic" icon="bullhorn" label="topic.actions.remove_feature" class="btn-admin"}} + {{else}} + {{d-button action="showFeatureTopic" icon="bullhorn" label="topic.actions.feature" class="btn-admin"}} + {{/if}}
  • {{/if}} {{/unless}} diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml index 07738bf14a..b078cd1d7d 100644 --- a/config/locales/client.en.yml +++ b/config/locales/client.en.yml @@ -974,6 +974,7 @@ en: close: "Close Topic" auto_close: "Auto Close" feature: "Feature Topic" + remove_feature: "Remove Feature" make_banner: "Banner Topic" remove_banner: "Remove Banner Topic" pin: "Pin Topic" From 83a2a832b1cc48aad8ff59deb856f4e7a3acb4f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9gis=20Hanol?= Date: Mon, 16 Mar 2015 17:06:23 +0100 Subject: [PATCH 034/114] FIX: hide draft status when uploading an image --- app/assets/javascripts/discourse/templates/composer.hbs | 4 +++- config/locales/client.en.yml | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/app/assets/javascripts/discourse/templates/composer.hbs b/app/assets/javascripts/discourse/templates/composer.hbs index 9226c11b3b..68e5c3a2a1 100644 --- a/app/assets/javascripts/discourse/templates/composer.hbs +++ b/app/assets/javascripts/discourse/templates/composer.hbs @@ -95,7 +95,9 @@ so I'm going to stop rendering it until we figure out what's up {{i18n 'upload'}} {{/if}} -
    {{model.draftStatus}}
    +
    + {{model.draftStatus}} +
    diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml index b078cd1d7d..81a8405c91 100644 --- a/config/locales/client.en.yml +++ b/config/locales/client.en.yml @@ -674,7 +674,7 @@ en: add_warning: "This is an official warning." posting_not_on_topic: "Which topic do you want to reply to?" - saving_draft_tip: "saving" + saving_draft_tip: "saving..." saved_draft_tip: "saved" saved_local_draft_tip: "saved locally" similar_topics: "Your topic is similar to..." From 50bf066afdd3db85b7b34924c0878450470b8146 Mon Sep 17 00:00:00 2001 From: Robin Ward Date: Mon, 16 Mar 2015 13:18:20 -0400 Subject: [PATCH 035/114] Add subcategory support to BBPress import --- script/import_scripts/bbpress.rb | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/script/import_scripts/bbpress.rb b/script/import_scripts/bbpress.rb index 4a1937eed5..3f28d36681 100644 --- a/script/import_scripts/bbpress.rb +++ b/script/import_scripts/bbpress.rb @@ -2,12 +2,12 @@ # `createdb bbpress` # `bundle exec rake db:migrate` +require 'mysql2' require File.expand_path(File.dirname(__FILE__) + "/base.rb") -BB_PRESS_DB = "bbpress" +BB_PRESS_DB = ENV['BBPRESS_DB'] || "bbpress" DB_TABLE_PREFIX = "wp_" -require 'mysql2' class ImportScripts::Bbpress < ImportScripts::Base @@ -40,8 +40,13 @@ class ImportScripts::Bbpress < ImportScripts::Base ActiveSupport::HashWithIndifferentAccess.new(u) end - create_categories(@client.query("SELECT id, post_name from #{table_name 'posts'} WHERE post_type = 'forum' AND post_name != ''")) do |c| - {id: c['id'], name: c['post_name']} + create_categories(@client.query("SELECT id, post_name, post_parent from #{table_name 'posts'} WHERE post_type = 'forum' AND post_name != '' ORDER BY post_parent")) do |c| + result = {id: c['id'], name: c['post_name']} + parent_id = c['post_parent'].to_i + if parent_id > 0 + result[:parent_category_id] = category_id_from_imported_category_id(parent_id) + end + result end import_posts From 4ff1e19712143d3de4997759c275958848360bff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9gis=20Hanol?= Date: Mon, 16 Mar 2015 18:28:11 +0100 Subject: [PATCH 036/114] FIX: emoji aliases were not recognised --- .../discourse/lib/emoji/emoji.js.erb | 45 ++++++++++--------- app/models/emoji.rb | 21 ++++++++- 2 files changed, 44 insertions(+), 22 deletions(-) diff --git a/app/assets/javascripts/discourse/lib/emoji/emoji.js.erb b/app/assets/javascripts/discourse/lib/emoji/emoji.js.erb index 786485e496..5abf50e18d 100644 --- a/app/assets/javascripts/discourse/lib/emoji/emoji.js.erb +++ b/app/assets/javascripts/discourse/lib/emoji/emoji.js.erb @@ -4,6 +4,7 @@ Discourse.Emoji = {}; Discourse.Emoji.ImageVersion = "0" var emoji = <%= Emoji.standard.map(&:name).flatten.inspect %>; +var aliases = <%= Emoji.aliases.inspect.gsub("=>", ":") %>; var extendedEmoji = {}; Discourse.Dialect.registerEmoji = function(code, url) { @@ -13,19 +14,19 @@ Discourse.Dialect.registerEmoji = function(code, url) { Discourse.Emoji.list = function(){ var list = emoji.slice(0); + _.each(aliases, function(v,k){ list.push(k); }); _.each(extendedEmoji, function(v,k){ list.push(k); }); return list; }; var toSearch; -var search = function(term, options) { +Discourse.Emoji.search = function(term, options) { var maxResults = (options && options["maxResults"]) || -1; - - toSearch = toSearch || emoji.concat(Object.keys(extendedEmoji)); - if (maxResults === 0) { return []; } + toSearch = toSearch || Discourse.Emoji.list(); + var i, results = []; var done = function() { @@ -51,12 +52,17 @@ var search = function(term, options) { return results; } -Discourse.Emoji.search = search; - var emojiHash = {}; +// add all default emojis emoji.forEach(function(code){ emojiHash[code] = true; }); +// and their aliases +for (var name in aliases) { + aliases[name].forEach(function(alias) { + emojiHash[alias] = true; + }); +} -var urlFor = function(code) { +Discourse.Emoji.urlFor = urlFor = function(code) { var url, set = Discourse.SiteSettings.emoji_set; code = code.toLowerCase(); @@ -66,6 +72,7 @@ var urlFor = function(code) { } if(!url && emojiHash.hasOwnProperty(code)) { + if (aliases.hasOwnProperty(code)) { code = aliases[code]; } url = Discourse.getURL('/images/emoji/' + set + '/' + code + '.png'); } @@ -80,8 +87,6 @@ var urlFor = function(code) { return url; } -Discourse.Emoji.urlFor = urlFor; - Discourse.Emoji.exists = function(code){ code = code.toLowerCase(); return !!(extendedEmoji.hasOwnProperty(code) || emojiHash.hasOwnProperty(code)); @@ -98,27 +103,27 @@ function imageFor(code) { // Also support default emotions var translations = { ':)' : 'smile', - ':-)' : 'smile', + ':-)' : 'smile', ':(' : 'frowning', - ':-(' : 'frowning', + ':-(' : 'frowning', ';)' : 'wink', - ';-)' : 'wink', + ';-)' : 'wink', ':\'(' : 'cry', - ':\'-(' : 'cry', - ':-\'(' : 'cry', + ':\'-(': 'cry', + ':-\'(': 'cry', ':p' : 'stuck_out_tongue', ':P' : 'stuck_out_tongue', - ':-P' : 'stuck_out_tongue', + ':-P' : 'stuck_out_tongue', ':O' : 'open_mouth', - ':-O' : 'open_mouth', + ':-O' : 'open_mouth', ':D' : 'smiley', - ':-D' : 'smiley', + ':-D' : 'smiley', ':|' : 'expressionless', - ':-|' : 'expressionless', + ':-|' : 'expressionless', ";P" : 'stuck_out_tongue_winking_eye', - ";-P" : 'stuck_out_tongue_winking_eye', + ";-P" : 'stuck_out_tongue_winking_eye', ":$" : 'blush', - ":-$" : 'blush' + ":-$" : 'blush' }; Discourse.Emoji.translations = translations; diff --git a/app/models/emoji.rb b/app/models/emoji.rb index 0ae75aee09..d1dcab4ade 100644 --- a/app/models/emoji.rb +++ b/app/models/emoji.rb @@ -27,6 +27,10 @@ class Emoji Discourse.cache.fetch("standard_emojis") { load_standard } end + def self.aliases + Discourse.cache.fetch("aliases_emojis") { load_aliases } + end + def self.custom Discourse.cache.fetch("custom_emojis") { load_custom } end @@ -74,6 +78,7 @@ class Emoji def self.clear_cache Discourse.cache.delete("custom_emojis") Discourse.cache.delete("standard_emojis") + Discourse.cache.delete("aliases_emojis") Discourse.cache.delete("all_emojis") end @@ -81,9 +86,21 @@ class Emoji "#{Rails.root}/lib/emoji/db.json" end + def self.db + @db ||= File.open(db_file, "r:UTF-8") { |f| JSON.parse(f.read) } + end + def self.load_standard - File.open(db_file, "r:UTF-8") { |f| JSON.parse(f.read) } - .map { |emoji| Emoji.create_from_db_item(emoji) } + db.map { |emoji| Emoji.create_from_db_item(emoji) } + end + + def self.load_aliases + aliases = {} + + db.select { |emoji| emoji["aliases"].count > 1 } + .each { |emoji| aliases[emoji["aliases"][0]] = emoji["aliases"][1..-1] } + + aliases end def self.load_custom From 5d74cadf2feabd347bbcd935ae76d7a471aec006 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9gis=20Hanol?= Date: Mon, 16 Mar 2015 18:57:15 +0100 Subject: [PATCH 037/114] FIX: picture would be hidden when [details] block was closed in the composer --- lib/cooked_post_processor.rb | 5 +- spec/components/cooked_post_processor_spec.rb | 46 +++++++++++++++---- 2 files changed, 41 insertions(+), 10 deletions(-) diff --git a/lib/cooked_post_processor.rb b/lib/cooked_post_processor.rb index e58f17bd17..02686aaf11 100644 --- a/lib/cooked_post_processor.rb +++ b/lib/cooked_post_processor.rb @@ -98,7 +98,10 @@ class CookedPostProcessor return unless image_sizes.present? image_sizes.each do |image_size| url, size = image_size[0], image_size[1] - return [size["width"], size["height"]] if url && size && url.include?(src) + if url && url.include?(src) && + size && size["width"].to_i > 0 && size["height"].to_i > 0 + return [size["width"], size["height"]] + end end end diff --git a/spec/components/cooked_post_processor_spec.rb b/spec/components/cooked_post_processor_spec.rb index 6b5ff79f41..02d50f82fc 100644 --- a/spec/components/cooked_post_processor_spec.rb +++ b/spec/components/cooked_post_processor_spec.rb @@ -40,20 +40,48 @@ describe CookedPostProcessor do context ".post_process_images" do - context "with image_sizes" do - - let(:post) { build(:post_with_image_urls) } - let(:cpp) { CookedPostProcessor.new(post, image_sizes: {"http://foo.bar/image.png" => {"width" => 111, "height" => 222}}) } - - before { cpp.post_process_images } - - it "works" do + shared_examples "leave dimensions alone" do + it "doesn't use them" do # adds the width from the image sizes provided when no dimension is provided - expect(cpp.html).to match(/src="http:\/\/foo.bar\/image.png" width="111" height="222"/) + expect(cpp.html).to match(/src="http:\/\/foo.bar\/image.png" width="" height=""/) # adds the width from the image sizes provided expect(cpp.html).to match(/src="http:\/\/domain.com\/picture.jpg" width="50" height="42"/) expect(cpp).to be_dirty end + end + + context "with image_sizes" do + let(:post) { build(:post_with_image_urls) } + let(:cpp) { CookedPostProcessor.new(post, image_sizes: image_sizes) } + + before { cpp.post_process_images } + + context "valid" do + let(:image_sizes) { {"http://foo.bar/image.png" => {"width" => 111, "height" => 222}} } + + it "use them" do + # adds the width from the image sizes provided when no dimension is provided + expect(cpp.html).to match(/src="http:\/\/foo.bar\/image.png" width="111" height="222"/) + # adds the width from the image sizes provided + expect(cpp.html).to match(/src="http:\/\/domain.com\/picture.jpg" width="50" height="42"/) + expect(cpp).to be_dirty + end + end + + context "invalid width" do + let(:image_sizes) { {"http://foo.bar/image.png" => {"width" => 0, "height" => 222}} } + include_examples "leave dimensions alone" + end + + context "invalid height" do + let(:image_sizes) { {"http://foo.bar/image.png" => {"width" => 111, "height" => 0}} } + include_examples "leave dimensions alone" + end + + context "invalid width & height" do + let(:image_sizes) { {"http://foo.bar/image.png" => {"width" => 0, "height" => 0}} } + include_examples "leave dimensions alone" + end end From 10ef30ab3cf7df87394f5170328b0fef27a6b4b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9gis=20Hanol?= Date: Mon, 16 Mar 2015 19:25:28 +0100 Subject: [PATCH 038/114] FIX: better handling of the 'read guidelines' badge --- .../discourse/lib/is-element-in-viewport.js.es6 | 11 +++++++++++ .../javascripts/discourse/views/static.js.es6 | 16 +++++++++------- 2 files changed, 20 insertions(+), 7 deletions(-) create mode 100644 app/assets/javascripts/discourse/lib/is-element-in-viewport.js.es6 diff --git a/app/assets/javascripts/discourse/lib/is-element-in-viewport.js.es6 b/app/assets/javascripts/discourse/lib/is-element-in-viewport.js.es6 new file mode 100644 index 0000000000..4e071af528 --- /dev/null +++ b/app/assets/javascripts/discourse/lib/is-element-in-viewport.js.es6 @@ -0,0 +1,11 @@ +export default function (element) { + if (element instanceof jQuery) { element = element[0]; } + + const $window = $(window), + rect = element.getBoundingClientRect(); + + return rect.top >= 0 && + rect.left >= 0 && + rect.bottom <= $window.height() && + rect.right <= $window.width(); +} diff --git a/app/assets/javascripts/discourse/views/static.js.es6 b/app/assets/javascripts/discourse/views/static.js.es6 index 6ee6700226..318ee2cf78 100644 --- a/app/assets/javascripts/discourse/views/static.js.es6 +++ b/app/assets/javascripts/discourse/views/static.js.es6 @@ -1,13 +1,15 @@ +import isElementInViewport from "discourse/lib/is-element-in-viewport"; + var readFaq = false; export default Ember.View.extend(Discourse.ScrollTop, { + _checkRead: function() { - var path = this.get('controller.model.path'); - if(path === "faq" || path === "guidelines"){ - var $window = $(window), - controller = this.get('controller'); - $window.on('scroll.faq', function(){ - if(!readFaq && ($window.scrollTop() + $window.height() > $(document).height() - 10)) { + const path = this.get('controller.model.path'); + if (path === "faq" || path === "guidelines") { + const controller = this.get('controller'); + $(window).on('load.faq resize.faq scroll.faq', function() { + if (!readFaq && isElementInViewport($(".contents p").last())) { readFaq = true; controller.send('markFaqRead'); } @@ -16,6 +18,6 @@ export default Ember.View.extend(Discourse.ScrollTop, { }.on('didInsertElement'), _stopChecking: function(){ - $(window).off('scroll.faq'); + $(window).off('load.faq resize.faq scroll.faq'); }.on('willDestroyElement') }); From 6be645e1ca6e88009bbfb65adb6bb4e273c983a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9gis=20Hanol?= Date: Mon, 16 Mar 2015 22:06:11 +0100 Subject: [PATCH 039/114] FEATURE: ask confirmation when clearing more than 1 bookmark --- .../javascripts/discourse/models/topic.js.es6 | 92 +++++++++---------- config/locales/client.en.yml | 1 + 2 files changed, 46 insertions(+), 47 deletions(-) diff --git a/app/assets/javascripts/discourse/models/topic.js.es6 b/app/assets/javascripts/discourse/models/topic.js.es6 index 054f35a67b..a2e984ea30 100644 --- a/app/assets/javascripts/discourse/models/topic.js.es6 +++ b/app/assets/javascripts/discourse/models/topic.js.es6 @@ -179,63 +179,61 @@ const Topic = Discourse.Model.extend({ }.property('word_count'), toggleBookmark() { + if (this.get("bookmarking")) { return; } + this.set("bookmarking", true); + const self = this, stream = this.get('postStream'), posts = Em.get(stream, 'posts'), - firstPost = posts && - posts[0] && - posts[0].get('post_number') === 1 && - posts[0], - bookmark = !self.get('bookmarked'); + firstPost = posts && posts[0] && posts[0].get('post_number') === 1 && posts[0], + bookmark = !this.get('bookmarked'), + path = bookmark ? '/bookmark' : '/remove_bookmarks'; - var path = bookmark ? '/bookmark' : '/remove_bookmarks'; - var unbookmarkedPosts = [], - bookmarkedPost; + const toggleBookmarkOnServer = function() { + return Discourse.ajax('/t/' + self.get('id') + path, { + type: 'PUT', + }).then(function() { + self.toggleProperty('bookmarked'); + if (bookmark && firstPost) { firstPost.set('bookmarked', true); } + if (!bookmark && posts) { + posts.forEach((post) => post.get('bookmarked') && post.set('bookmarked', false)); + } + }).catch(function(error) { + let showGenericError = true; + if (error && error.responseText) { + try { + bootbox.alert($.parseJSON(error.responseText).errors); + showGenericError = false; + } catch(e) { } + } - this.toggleProperty('bookmarked'); + if (showGenericError) { + bootbox.alert(I18n.t('generic_error')); + } - if (bookmark && firstPost) { - firstPost.set('bookmarked', true); - bookmarkedPost = firstPost; - } + throw error; + }).finally(function() { + self.set("bookmarking", false); + }); + }; + let unbookmarkedPosts = []; if (!bookmark && posts) { - posts.forEach(function(post){ - if(post.get('bookmarked')){ - post.set('bookmarked', false); - unbookmarkedPosts.push(post); - } - }); + posts.forEach((post) => post.get('bookmarked') && unbookmarkedPosts.push(post)); } - return Discourse.ajax('/t/' + this.get('id') + path, { - type: 'PUT', - }).catch(function(error) { - - self.toggleProperty('bookmarked'); - - if(bookmarkedPost) { - bookmarkedPost.set('bookmarked', false); - } - - unbookmarkedPosts.forEach(function(p){ - p.set('bookmarked', true); - }); - - let showGenericError = true; - if (error && error.responseText) { - try { - bootbox.alert($.parseJSON(error.responseText).errors); - showGenericError = false; - } catch(e){} - } - - if(showGenericError){ - bootbox.alert(I18n.t('generic_error')); - } - - throw error; - }); + if (unbookmarkedPosts.length > 1) { + return bootbox.confirm( + I18n.t("bookmarks.confirm_clear"), + I18n.t("no_value"), + I18n.t("yes_value"), + function (confirmed) { + if (confirmed) { return toggleBookmarkOnServer(); } + } + ); + } else { + return toggleBookmarkOnServer(); + } }, createInvite(emailOrUsername, groupNames) { diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml index 81a8405c91..5fd0fdd60b 100644 --- a/config/locales/client.en.yml +++ b/config/locales/client.en.yml @@ -179,6 +179,7 @@ en: not_bookmarked: "you've read this post; click to bookmark it" last_read: "this is the last post you've read; click to bookmark it" remove: "Remove Bookmark" + confirm_clear: "Are you sure you want to clear all the bookmarks from this topic?" topic_count_latest: one: "{{count}} new or updated topic." From 177cbf392d80597e6e4664ab2efbb7724fde1ce7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9gis=20Hanol?= Date: Mon, 16 Mar 2015 22:38:33 +0100 Subject: [PATCH 040/114] UX: remove outline on lightboxes --- app/assets/stylesheets/common/base/lightbox.scss | 1 + app/assets/stylesheets/common/base/magnific-popup.scss | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/app/assets/stylesheets/common/base/lightbox.scss b/app/assets/stylesheets/common/base/lightbox.scss index dc010a29bc..681eec6253 100644 --- a/app/assets/stylesheets/common/base/lightbox.scss +++ b/app/assets/stylesheets/common/base/lightbox.scss @@ -11,6 +11,7 @@ .lightbox-wrapper { display: inline-block; + &, * { outline: 0; } } .meta { diff --git a/app/assets/stylesheets/common/base/magnific-popup.scss b/app/assets/stylesheets/common/base/magnific-popup.scss index 0c689265a0..98ead180b7 100644 --- a/app/assets/stylesheets/common/base/magnific-popup.scss +++ b/app/assets/stylesheets/common/base/magnific-popup.scss @@ -96,7 +96,7 @@ $use-visuallyhidden: false !default; // Hide content from browsers, height: 100%; z-index: $z-index-base + 3; position: fixed; - outline: none !important; + outline: 0 !important; -webkit-backface-visibility: hidden; // fixes webkit bug that can cause "false" scrollbar } @@ -293,6 +293,7 @@ button { &:hover, &:focus { opacity: 1; + outline: 0; @if $IE7support { filter: unquote("alpha(opacity=#{1*100})"); } @@ -348,6 +349,7 @@ button { } &:hover, &:focus { + outline: 0; opacity: 1; @if $IE7support { filter: unquote("alpha(opacity=#{1*100})"); From 8fcbea0c2ca236f33a3631b7bbbd3e5606728226 Mon Sep 17 00:00:00 2001 From: Neil Lalonde Date: Tue, 17 Mar 2015 11:18:39 -0400 Subject: [PATCH 041/114] FIX: don't show delete all posts button in admin when there are no posts --- app/assets/javascripts/admin/templates/user_index.hbs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/app/assets/javascripts/admin/templates/user_index.hbs b/app/assets/javascripts/admin/templates/user_index.hbs index 2546f3ae23..25223ae661 100644 --- a/app/assets/javascripts/admin/templates/user_index.hbs +++ b/app/assets/javascripts/admin/templates/user_index.hbs @@ -384,10 +384,12 @@
    {{post_count}}
    {{#if can_delete_all_posts}} - + {{#if post_count}} + + {{/if}} {{else}} {{deleteAllPostsExplanation}} {{/if}} From aa41a9ce700a1a39d13c189d0f769694bce603aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9gis=20Hanol?= Date: Tue, 17 Mar 2015 17:27:16 +0100 Subject: [PATCH 042/114] FIX: remove empty lines but keep whitespace on first line in code blocks --- .../javascripts/discourse/dialects/dialect.js | 13 ++++++++----- test/javascripts/lib/markdown-test.js.es6 | 2 +- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/app/assets/javascripts/discourse/dialects/dialect.js b/app/assets/javascripts/discourse/dialects/dialect.js index d5d785e2a3..9d0cbef8d7 100644 --- a/app/assets/javascripts/discourse/dialects/dialect.js +++ b/app/assets/javascripts/discourse/dialects/dialect.js @@ -167,6 +167,11 @@ function outdent(t) { return t.replace(/^([ ]{4}|\t)/gm, ""); } +function removeEmptyLines(t) { + return t.replace(/^\n+/, "") + .replace(/\s+$/, ""); +} + function hideBackslashEscapedCharacters(t) { return t.replace(/\\\\/g, "\u1E800") .replace(/\\`/g, "\u1E8001"); @@ -186,14 +191,14 @@ function hoistCodeBlocksAndSpans(text) { //
    ...
    code blocks text = text.replace(/(^\n*|\n\n)
    ([\s\S]*?)<\/pre>/ig, function(_, before, content) {
         var hash = md5(content);
    -    hoisted[hash] = escape(showBackslashEscapedCharacters(content.trim()));
    +    hoisted[hash] = escape(showBackslashEscapedCharacters(removeEmptyLines(content)));
         return before + "
    " + hash + "
    "; }); // fenced code blocks (AKA GitHub code blocks) text = text.replace(/(^\n*|\n\n)```([a-z0-9\-]*)\n([\s\S]*?)\n```/g, function(_, before, language, content) { var hash = md5(content); - hoisted[hash] = escape(showBackslashEscapedCharacters(content.trim())); + hoisted[hash] = escape(showBackslashEscapedCharacters(removeEmptyLines(content))); return before + "```" + language + "\n" + hash + "\n```"; }); @@ -209,9 +214,7 @@ function hoistCodeBlocksAndSpans(text) { } // we can safely hoist the code block var hash = md5(content); - // only remove trailing whitespace - content = content.replace(/\s+$/, ""); - hoisted[hash] = escape(outdent(showBackslashEscapedCharacters(content))); + hoisted[hash] = escape(outdent(showBackslashEscapedCharacters(removeEmptyLines(content)))); return before + " " + hash + "\n"; }); diff --git a/test/javascripts/lib/markdown-test.js.es6 b/test/javascripts/lib/markdown-test.js.es6 index 6ae727c550..f5859165f1 100644 --- a/test/javascripts/lib/markdown-test.js.es6 +++ b/test/javascripts/lib/markdown-test.js.es6 @@ -529,6 +529,6 @@ test("censoring", function() { test("code blocks/spans hoisting", function() { cooked("```\n\n some code\n```", - "

    some code

    ", + "

        some code

    ", "it works when nesting standard markdown code blocks within a fenced code block"); }); From 56e01a766b4e3ebc64b37dcc3b3da1b2a6f7bbb1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9gis=20Hanol?= Date: Tue, 17 Mar 2015 17:29:18 +0100 Subject: [PATCH 043/114] FIX: clear emoji cache after restore --- lib/backup_restore/restorer.rb | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/backup_restore/restorer.rb b/lib/backup_restore/restorer.rb index 8b7fcff2d0..bccd2e607d 100644 --- a/lib/backup_restore/restorer.rb +++ b/lib/backup_restore/restorer.rb @@ -50,6 +50,7 @@ module BackupRestore migrate_database reconnect_database reload_site_settings + clear_emoji_cache disable_readonly_mode ### READ-ONLY / END ### @@ -267,6 +268,11 @@ module BackupRestore SiteSetting.refresh! end + def clear_emoji_cache + log "Clearing emoji cache..." + Emoji.clear_cache + end + def extract_uploads if `tar --list --file #{@tar_filename} | grep 'uploads/'`.present? log "Extracting uploads..." From 9cbd0f8e7867daa42acb74a4da9473270fc3643a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9gis=20Hanol?= Date: Tue, 17 Mar 2015 22:59:05 +0100 Subject: [PATCH 044/114] UX: separate custom from automatic groups in user admin REFACTOR: some moar ES6 refactoring --- .../components/admin-group-selector.js.es6 | 35 +- .../admin/controllers/admin-user-index.js.es6 | 81 +-- .../{admin_user.js => admin-user.js.es6} | 475 +++++++++--------- .../admin/templates/user_index.hbs | 109 ++-- config/locales/client.en.yml | 4 + 5 files changed, 349 insertions(+), 355 deletions(-) rename app/assets/javascripts/admin/models/{admin_user.js => admin-user.js.es6} (51%) diff --git a/app/assets/javascripts/admin/components/admin-group-selector.js.es6 b/app/assets/javascripts/admin/components/admin-group-selector.js.es6 index f838830b08..0f8841889e 100644 --- a/app/assets/javascripts/admin/components/admin-group-selector.js.es6 +++ b/app/assets/javascripts/admin/components/admin-group-selector.js.es6 @@ -1,31 +1,36 @@ export default Ember.Component.extend({ tagName: 'div', - didInsertElement: function(){ + _init: function(){ this.$("input").select2({ multiple: true, width: '100%', - query: function(opts){ - opts.callback({ - results: this.get("available").map(this._format) - }); + query: function(opts) { + opts.callback({ results: this.get("available").map(this._format) }); }.bind(this) }).on("change", function(evt) { if (evt.added){ - this.triggerAction({action: "groupAdded", - actionContext: this.get("available" - ).findBy("id", evt.added.id)}); + this.triggerAction({ + action: "groupAdded", + actionContext: this.get("available").findBy("id", evt.added.id) + }); } else if (evt.removed) { - this.triggerAction({action:"groupRemoved", - actionContext: this.get("selected" - ).findBy("id", evt.removed.id)}); + this.triggerAction({ + action:"groupRemoved", + actionContext: evt.removed.id + }); } }.bind(this)); - this._refreshOnReset(); - }, - _format: function(item){ - return {"text": item.name, "id": item.id, "locked": item.automatic}; + this._refreshOnReset(); + }.on("didInsertElement"), + + _format(item) { + return { + "text": item.name, + "id": item.id, + "locked": item.automatic + }; }, _refreshOnReset: function() { diff --git a/app/assets/javascripts/admin/controllers/admin-user-index.js.es6 b/app/assets/javascripts/admin/controllers/admin-user-index.js.es6 index 89e4c2441b..88d775b1b8 100644 --- a/app/assets/javascripts/admin/controllers/admin-user-index.js.es6 +++ b/app/assets/javascripts/admin/controllers/admin-user-index.js.es6 @@ -11,58 +11,61 @@ export default ObjectController.extend(CanCheckEmails, { primaryGroupDirty: Discourse.computed.propertyNotEqual('originalPrimaryGroupId', 'primary_group_id'), - custom_groups: Ember.computed.filter("model.groups", function(g){ - return (!g.automatic && g.visible); - }), + automaticGroups: function() { + return this.get("model.automaticGroups").map((g) => g.name).join(", "); + }.property("model.automaticGroups"), userFields: function() { - var siteUserFields = this.site.get('user_fields'), - userFields = this.get('user_fields'); + const siteUserFields = this.site.get('user_fields'), + userFields = this.get('user_fields'); if (!Ember.isEmpty(siteUserFields)) { return siteUserFields.map(function(uf) { - var value = userFields ? userFields[uf.get('id').toString()] : null; - return {name: uf.get('name'), value: value}; + let value = userFields ? userFields[uf.get('id').toString()] : null; + return { name: uf.get('name'), value: value }; }); } return []; }.property('user_fields.@each'), actions: { - toggleTitleEdit: function() { + toggleTitleEdit() { this.toggleProperty('editingTitle'); }, - saveTitle: function() { - Discourse.ajax("/users/" + this.get('username').toLowerCase(), { + saveTitle() { + const self = this; + + return Discourse.ajax("/users/" + this.get('username').toLowerCase(), { data: {title: this.get('title')}, type: 'PUT' - }).then(null, function(e){ + }).catch(function(e) { bootbox.alert(I18n.t("generic_error_with_reason", {error: "http: " + e.status + " - " + e.body})); + }).finally(function() { + self.send('toggleTitleEdit'); }); - - this.send('toggleTitleEdit'); }, - generateApiKey: function() { + generateApiKey() { this.get('model').generateApiKey(); }, - groupAdded: function(added){ + groupAdded(added) { this.get('model').groupAdded(added).catch(function() { bootbox.alert(I18n.t('generic_error')); }); }, - groupRemoved: function(removed){ - this.get('model').groupRemoved(removed).catch(function() { + groupRemoved(groupId) { + this.get('model').groupRemoved(groupId).catch(function() { bootbox.alert(I18n.t('generic_error')); }); }, - savePrimaryGroup: function() { - var self = this; - Discourse.ajax("/admin/users/" + this.get('id') + "/primary_group", { + savePrimaryGroup() { + const self = this; + + return Discourse.ajax("/admin/users/" + this.get('id') + "/primary_group", { type: 'PUT', data: {primary_group_id: this.get('primary_group_id')} }).then(function () { @@ -72,33 +75,41 @@ export default ObjectController.extend(CanCheckEmails, { }); }, - resetPrimaryGroup: function() { + resetPrimaryGroup() { this.set('primary_group_id', this.get('originalPrimaryGroupId')); }, - regenerateApiKey: function() { - var self = this; - bootbox.confirm(I18n.t("admin.api.confirm_regen"), I18n.t("no_value"), I18n.t("yes_value"), function(result) { - if (result) { - self.get('model').generateApiKey(); + regenerateApiKey() { + const self = this; + + bootbox.confirm( + I18n.t("admin.api.confirm_regen"), + I18n.t("no_value"), + I18n.t("yes_value"), + function(result) { + if (result) { self.get('model').generateApiKey(); } } - }); + ); }, - revokeApiKey: function() { - var self = this; - bootbox.confirm(I18n.t("admin.api.confirm_revoke"), I18n.t("no_value"), I18n.t("yes_value"), function(result) { - if (result) { - self.get('model').revokeApiKey(); + revokeApiKey() { + const self = this; + + bootbox.confirm( + I18n.t("admin.api.confirm_revoke"), + I18n.t("no_value"), + I18n.t("yes_value"), + function(result) { + if (result) { self.get('model').revokeApiKey(); } } - }); + ); }, - anonymize: function() { + anonymize() { this.get('model').anonymize(); }, - destroy: function() { + destroy() { this.get('model').destroy(); } } diff --git a/app/assets/javascripts/admin/models/admin_user.js b/app/assets/javascripts/admin/models/admin-user.js.es6 similarity index 51% rename from app/assets/javascripts/admin/models/admin_user.js rename to app/assets/javascripts/admin/models/admin-user.js.es6 index b2d6c1a17e..98230fbafe 100644 --- a/app/assets/javascripts/admin/models/admin_user.js +++ b/app/assets/javascripts/admin/models/admin-user.js.es6 @@ -1,58 +1,36 @@ -/** - Our data model for dealing with users from the admin section. +const AdminUser = Discourse.User.extend({ - @class AdminUser - @extends Discourse.Model - @namespace Discourse - @module Discourse -**/ -Discourse.AdminUser = Discourse.User.extend({ + customGroups: Em.computed.filter("groups", (g) => !g.automatic && g.visible && Discourse.Group.create(g)), + automaticGroups: Em.computed.filter("groups", (g) => g.automatic && Discourse.Group.create(g)), - /** - Generates an API key for the user. Will regenerate if they already have one. - - @method generateApiKey - @returns {Promise} a promise that resolves to the newly generated API key - **/ - generateApiKey: function() { - var self = this; - return Discourse.ajax("/admin/users/" + this.get('id') + "/generate_api_key", {type: 'POST'}).then(function (result) { - var apiKey = Discourse.ApiKey.create(result.api_key); + generateApiKey() { + const self = this; + return Discourse.ajax("/admin/users/" + this.get('id') + "/generate_api_key", { + type: 'POST' + }).then(function (result) { + const apiKey = Discourse.ApiKey.create(result.api_key); self.set('api_key', apiKey); return apiKey; }); }, - groupAdded: function(added){ - var self = this; + groupAdded(added) { return Discourse.ajax("/admin/users/" + this.get('id') + "/groups", { type: 'POST', - data: {group_id: added.id} - }).then(function () { - self.get('groups').pushObject(added); - }); + data: { group_id: added.id } + }).then(() => this.get('groups').pushObject(added)); }, - groupRemoved: function(removed){ - var self = this; - return Discourse.ajax("/admin/users/" + this.get('id') + "/groups/" + removed.id, { + groupRemoved(groupId) { + return Discourse.ajax("/admin/users/" + this.get('id') + "/groups/" + groupId, { type: 'DELETE' - }).then(function () { - self.set('groups.[]', self.get('groups').rejectBy("id", removed.id)); - }); + }).then(() => this.set('groups.[]', this.get('groups').rejectBy("id", groupId))); }, - /** - Revokes a user's current API key - - @method revokeApiKey - @returns {Promise} a promise that resolves when the API key has been deleted - **/ - revokeApiKey: function() { - var self = this; - return Discourse.ajax("/admin/users/" + this.get('id') + "/revoke_api_key", {type: 'DELETE'}).then(function () { - self.set('api_key', null); - }); + revokeApiKey() { + return Discourse.ajax("/admin/users/" + this.get('id') + "/revoke_api_key", { + type: 'DELETE' + }).then(() => this.set('api_key', null)); }, deleteAllPostsExplanation: function() { @@ -70,99 +48,111 @@ Discourse.AdminUser = Discourse.User.extend({ } }.property('can_delete_all_posts', 'deleteForbidden'), - deleteAllPosts: function() { - var user = this; - var message = I18n.t('admin.user.delete_all_posts_confirm', {posts: user.get('post_count'), topics: user.get('topic_count')}); - var buttons = [{ - "label": I18n.t("composer.cancel"), - "class": "cancel-inline", - "link": true - }, { - "label": ' ' + I18n.t("admin.user.delete_all_posts"), - "class": "btn btn-danger", - "callback": function() { - Discourse.ajax("/admin/users/" + (user.get('id')) + "/delete_all_posts", {type: 'PUT'}).then(function(){ - user.set('post_count', 0); - }); - } - }]; - bootbox.dialog(message, buttons, {"classes": "delete-all-posts"}); + deleteAllPosts() { + const user = this, + message = I18n.t('admin.user.delete_all_posts_confirm', { posts: user.get('post_count'), topics: user.get('topic_count') }), + buttons = [{ + "label": I18n.t("composer.cancel"), + "class": "cancel-inline", + "link": true + }, { + "label": ' ' + I18n.t("admin.user.delete_all_posts"), + "class": "btn btn-danger", + "callback": function() { + Discourse.ajax("/admin/users/" + user.get('id') + "/delete_all_posts", { + type: 'PUT' + }).then(() => user.set('post_count', 0)); + } + }]; + bootbox.dialog(message, buttons, { "classes": "delete-all-posts" }); }, - // Revoke the user's admin access - revokeAdmin: function() { - this.set('admin', false); - this.set('can_grant_admin', true); - this.set('can_revoke_admin', false); - return Discourse.ajax("/admin/users/" + (this.get('id')) + "/revoke_admin", {type: 'PUT'}); - }, - - grantAdmin: function() { - this.set('admin', true); - this.set('can_grant_admin', false); - this.set('can_revoke_admin', true); - var self = this; - - Discourse.ajax("/admin/users/" + (this.get('id')) + "/grant_admin", {type: 'PUT'}) - .then(null, function(e) { - self.set('admin', false); - self.set('can_grant_admin', true); - self.set('can_revoke_admin', false); - - var error; - if (e.responseJSON && e.responseJSON.error) { - error = e.responseJSON.error; - } - error = error || I18n.t('admin.user.grant_admin_failed', { error: "http: " + e.status + " - " + e.body }); - bootbox.alert(error); + revokeAdmin() { + const self = this; + return Discourse.ajax("/admin/users/" + this.get('id') + "/revoke_admin", { + type: 'PUT' + }).then(function() { + self.setProperties({ + admin: false, + can_grant_admin: true, + can_revoke_admin: false }); + }); }, - // Revoke the user's moderation access - revokeModeration: function() { - this.set('moderator', false); - this.set('can_grant_moderation', true); - this.set('can_revoke_moderation', false); - return Discourse.ajax("/admin/users/" + (this.get('id')) + "/revoke_moderation", {type: 'PUT'}); + grantAdmin() { + const self = this; + return Discourse.ajax("/admin/users/" + this.get('id') + "/grant_admin", { + type: 'PUT' + }).then(function() { + self.setProperties({ + admin: true, + can_grant_admin: false, + can_revoke_admin: true + }); + }).catch(function(e) { + let error; + if (e.responseJSON && e.responseJSON.error) { + error = e.responseJSON.error; + } + error = error || I18n.t('admin.user.grant_admin_failed', { error: "http: " + e.status + " - " + e.body }); + bootbox.alert(error); + }); }, - grantModeration: function() { - this.set('moderator', true); - this.set('can_grant_moderation', false); - this.set('can_revoke_moderation', true); - var self = this; - Discourse.ajax("/admin/users/" + (this.get('id')) + "/grant_moderation", {type: 'PUT'}) - .then(null, function(e) { - self.set('moderator', false); - self.set('can_grant_moderation', true); - self.set('can_revoke_moderation', false); - - var error; - if (e.responseJSON && e.responseJSON.error) { - error = e.responseJSON.error; - } - error = error || I18n.t('admin.user.grant_moderation_failed', { error: "http: " + e.status + " - " + e.body }); - bootbox.alert(error); - }); + revokeModeration() { + const self = this; + return Discourse.ajax("/admin/users/" + this.get('id') + "/revoke_moderation", { + type: 'PUT' + }).then(function() { + self.setProperties({ + moderator: false, + can_grant_moderation: true, + can_revoke_moderation: false + }); + }); }, - refreshBrowsers: function() { - Discourse.ajax("/admin/users/" + (this.get('id')) + "/refresh_browsers", {type: 'POST'}); - bootbox.alert(I18n.t("admin.user.refresh_browsers_message")); + grantModeration() { + const self = this; + return Discourse.ajax("/admin/users/" + this.get('id') + "/grant_moderation", { + type: 'PUT' + }).then(function() { + self.setProperties({ + moderator: true, + can_grant_moderation: false, + can_revoke_moderation: true + }); + }).catch(function(e) { + let error; + if (e.responseJSON && e.responseJSON.error) { + error = e.responseJSON.error; + } + error = error || I18n.t('admin.user.grant_moderation_failed', { error: "http: " + e.status + " - " + e.body }); + bootbox.alert(error); + }); }, - approve: function() { - this.set('can_approve', false); - this.set('approved', true); - this.set('approved_by', Discourse.User.current()); - Discourse.ajax("/admin/users/" + (this.get('id')) + "/approve", {type: 'PUT'}); + refreshBrowsers() { + return Discourse.ajax("/admin/users/" + this.get('id') + "/refresh_browsers", { + type: 'POST' + }).finally(() => bootbox.alert(I18n.t("admin.user.refresh_browsers_message"))); }, - username_lower: (function() { - return this.get('username').toLowerCase(); - }).property('username'), + approve() { + const self = this; + return Discourse.ajax("/admin/users/" + this.get('id') + "/approve", { + type: 'PUT' + }).then(function() { + self.setProperties({ + can_approve: false, + approved: true, + approved_by: Discourse.User.current() + }); + }); + }, - setOriginalTrustLevel: function() { + setOriginalTrustLevel() { this.set('originalTrustLevel', this.get('trust_level')); }, @@ -172,16 +162,14 @@ Discourse.AdminUser = Discourse.User.extend({ dirty: Discourse.computed.propertyNotEqual('originalTrustLevel', 'trustLevel.id'), - saveTrustLevel: function() { - Discourse.ajax("/admin/users/" + this.id + "/trust_level", { + saveTrustLevel() { + return Discourse.ajax("/admin/users/" + this.id + "/trust_level", { type: 'PUT', - data: {level: this.get('trustLevel.id')} - }).then(function () { - // succeeded + data: { level: this.get('trustLevel.id') } + }).then(function() { window.location.reload(); - }, function(e) { - // failure - var error; + }).catch(function(e) { + let error; if (e.responseJSON && e.responseJSON.errors) { error = e.responseJSON.errors[0]; } @@ -190,20 +178,18 @@ Discourse.AdminUser = Discourse.User.extend({ }); }, - restoreTrustLevel: function() { + restoreTrustLevel() { this.set('trustLevel.id', this.get('originalTrustLevel')); }, - lockTrustLevel: function(locked) { - Discourse.ajax("/admin/users/" + this.id + "/trust_level_lock", { + lockTrustLevel(locked) { + return Discourse.ajax("/admin/users/" + this.id + "/trust_level_lock", { type: 'PUT', data: { locked: !!locked } }).then(function() { - // succeeded window.location.reload(); - }, function(e) { - // failure - var error; + }).catch(function(e) { + let error; if (e.responseJSON && e.responseJSON.errors) { error = e.responseJSON.errors[0]; } @@ -212,7 +198,7 @@ Discourse.AdminUser = Discourse.User.extend({ }); }, - canLockTrustLevel: function(){ + canLockTrustLevel: function() { return this.get('trust_level') < 4; }.property('trust_level'), @@ -220,51 +206,45 @@ Discourse.AdminUser = Discourse.User.extend({ canSuspend: Em.computed.not('staff'), suspendDuration: function() { - var suspended_at = moment(this.suspended_at); - var suspended_till = moment(this.suspended_till); + const suspended_at = moment(this.suspended_at), + suspended_till = moment(this.suspended_till); return suspended_at.format('L') + " - " + suspended_till.format('L'); }.property('suspended_till', 'suspended_at'), - suspend: function(duration, reason) { + suspend(duration, reason) { return Discourse.ajax("/admin/users/" + this.id + "/suspend", { type: 'PUT', - data: {duration: duration, reason: reason} + data: { duration: duration, reason: reason } }); }, - unsuspend: function() { - Discourse.ajax("/admin/users/" + this.id + "/unsuspend", { + unsuspend() { + return Discourse.ajax("/admin/users/" + this.id + "/unsuspend", { type: 'PUT' }).then(function() { - // succeeded window.location.reload(); - }, function(e) { - // failed + }).catch(function(e) { var error = I18n.t('admin.user.unsuspend_failed', { error: "http: " + e.status + " - " + e.body }); bootbox.alert(error); }); }, - log_out: function(){ - Discourse.ajax("/admin/users/" + this.id + "/log_out", { - type: 'POST', - data: { username_or_email: this.get('username') } - }).then( - function(){ - bootbox.alert(I18n.t("admin.user.logged_out")); - } - ); - }, - - impersonate: function() { - Discourse.ajax("/admin/impersonate", { + log_out() { + return Discourse.ajax("/admin/users/" + this.id + "/log_out", { + type: 'POST', + data: { username_or_email: this.get('username') } + }).then(function() { + bootbox.alert(I18n.t("admin.user.logged_out")); + }); + }, + + impersonate() { + return Discourse.ajax("/admin/impersonate", { type: 'POST', data: { username_or_email: this.get('username') } }).then(function() { - // succeeded document.location = "/"; - }, function(e) { - // failed + }).catch(function(e) { if (e.status === 404) { bootbox.alert(I18n.t('admin.impersonate.not_found')); } else { @@ -273,56 +253,57 @@ Discourse.AdminUser = Discourse.User.extend({ }); }, - activate: function() { - Discourse.ajax('/admin/users/' + this.id + '/activate', {type: 'PUT'}).then(function() { - // succeeded + activate() { + return Discourse.ajax('/admin/users/' + this.id + '/activate', { + type: 'PUT' + }).then(function() { window.location.reload(); - }, function(e) { - // failed + }).catch(function(e) { var error = I18n.t('admin.user.activate_failed', { error: "http: " + e.status + " - " + e.body }); bootbox.alert(error); }); }, - deactivate: function() { - Discourse.ajax('/admin/users/' + this.id + '/deactivate', {type: 'PUT'}).then(function() { - // succeeded + deactivate() { + return Discourse.ajax('/admin/users/' + this.id + '/deactivate', { + type: 'PUT' + }).then(function() { window.location.reload(); - }, function(e) { - // failed + }).catch(function(e) { var error = I18n.t('admin.user.deactivate_failed', { error: "http: " + e.status + " - " + e.body }); bootbox.alert(error); }); }, - unblock: function() { - Discourse.ajax('/admin/users/' + this.id + '/unblock', {type: 'PUT'}).then(function() { - // succeeded + unblock() { + return Discourse.ajax('/admin/users/' + this.id + '/unblock', { + type: 'PUT' + }).then(function() { window.location.reload(); - }, function(e) { - // failed + }).catch(function(e) { var error = I18n.t('admin.user.unblock_failed', { error: "http: " + e.status + " - " + e.body }); bootbox.alert(error); }); }, - block: function() { - Discourse.ajax('/admin/users/' + this.id + '/block', {type: 'PUT'}).then(function() { - // succeeded + block() { + return Discourse.ajax('/admin/users/' + this.id + '/block', { + type: 'PUT' + }).then(function() { window.location.reload(); - }, function(e) { - // failed + }).catch(function(e) { var error = I18n.t('admin.user.block_failed', { error: "http: " + e.status + " - " + e.body }); bootbox.alert(error); }); }, - sendActivationEmail: function() { - Discourse.ajax('/users/action/send_activation_email', {data: {username: this.get('username')}, type: 'POST'}).then(function() { - // succeeded + sendActivationEmail() { + return Discourse.ajax('/users/action/send_activation_email', { + type: 'POST', + data: { username: this.get('username') } + }).then(function() { bootbox.alert( I18n.t('admin.user.activation_email_sent') ); - }, function(e) { - // failed + }).catch(function(e) { var error = I18n.t('admin.user.send_activation_email_failed', { error: "http: " + e.status + " - " + e.body }); bootbox.alert(error); }); @@ -330,11 +311,14 @@ Discourse.AdminUser = Discourse.User.extend({ anonymizeForbidden: Em.computed.not("can_be_anonymized"), - anonymize: function() { - var user = this; + anonymize() { + const user = this, + message = I18n.t("admin.user.anonymize_confirm"); - var performAnonymize = function() { - Discourse.ajax("/admin/users/" + user.get('id') + '/anonymize.json', {type: 'PUT'}).then(function(data) { + const performAnonymize = function() { + return Discourse.ajax("/admin/users/" + user.get('id') + '/anonymize.json', { + type: 'PUT' + }).then(function(data) { if (data.success) { if (data.username) { document.location = "/admin/users/" + data.username; @@ -347,26 +331,22 @@ Discourse.AdminUser = Discourse.User.extend({ user.setProperties(data.user); } } - }, function() { + }).catch(function() { bootbox.alert(I18n.t("admin.user.anonymize_failed")); }); }; - var message = I18n.t("admin.user.anonymize_confirm"); - - var buttons = [{ + const buttons = [{ "label": I18n.t("composer.cancel"), "class": "cancel", "link": true }, { "label": '' + I18n.t('admin.user.anonymize_yes'), "class": "btn btn-danger", - "callback": function(){ - performAnonymize(); - } + "callback": function() { performAnonymize(); } }]; - bootbox.dialog(message, buttons, {"classes": "delete-user-modal"}); + bootbox.dialog(message, buttons, { "classes": "delete-user-modal" }); }, deleteForbidden: Em.computed.not("canBeDeleted"), @@ -383,12 +363,13 @@ Discourse.AdminUser = Discourse.User.extend({ } }.property('deleteForbidden'), - destroy: function(opts) { - var user = this; - var location = document.location.pathname; + destroy(opts) { + const user = this, + message = I18n.t("admin.user.delete_confirm"), + location = document.location.pathname; - var performDestroy = function(block) { - var formData = { context: location }; + const performDestroy = function(block) { + let formData = { context: location }; if (block) { formData["block_email"] = true; formData["block_urls"] = true; @@ -397,7 +378,7 @@ Discourse.AdminUser = Discourse.User.extend({ if (opts && opts.deletePosts) { formData["delete_posts"] = true; } - Discourse.ajax("/admin/users/" + user.get('id') + '.json', { + return Discourse.ajax("/admin/users/" + user.get('id') + '.json', { type: 'DELETE', data: formData }).then(function(data) { @@ -413,47 +394,42 @@ Discourse.AdminUser = Discourse.User.extend({ user.setProperties(data.user); } } - }, function() { + }).catch(function() { Discourse.AdminUser.find( user.get('username') ).then(function(u){ user.setProperties(u); }); bootbox.alert(I18n.t("admin.user.delete_failed")); }); }; - var message = I18n.t("admin.user.delete_confirm"); - - var buttons = [{ + const buttons = [{ "label": I18n.t("composer.cancel"), "class": "cancel", "link": true }, { "label": I18n.t('admin.user.delete_dont_block'), "class": "btn", - "callback": function(){ - performDestroy(false); - } + "callback": function(){ performDestroy(false); } }, { "label": '' + I18n.t('admin.user.delete_and_block'), "class": "btn btn-danger", - "callback": function(){ - performDestroy(true); - } + "callback": function(){ performDestroy(true); } }]; - bootbox.dialog(message, buttons, {"classes": "delete-user-modal"}); + bootbox.dialog(message, buttons, { "classes": "delete-user-modal" }); }, - deleteAsSpammer: function(successCallback) { - var user = this; + deleteAsSpammer(successCallback) { + const user = this; user.checkEmail().then(function() { - var data = { + const data = { posts: user.get('post_count'), topics: user.get('topic_count'), email: user.get('email') || I18n.t("flagging.hidden_email_address"), ip_address: user.get('ip_address') || I18n.t("flagging.ip_address_missing") - }; - var message = I18n.t('flagging.delete_confirm', data); - var buttons = [{ + }; + + const message = I18n.t('flagging.delete_confirm', data), + buttons = [{ "label": I18n.t("composer.cancel"), "class": "cancel-inline", "link": true @@ -461,7 +437,7 @@ Discourse.AdminUser = Discourse.User.extend({ "label": ' ' + I18n.t("flagging.yes_delete_spammer"), "class": "btn btn-danger", "callback": function() { - Discourse.ajax("/admin/users/" + user.get('id') + '.json', { + return Discourse.ajax("/admin/users/" + user.get('id') + '.json', { type: 'DELETE', data: { delete_posts: true, @@ -477,23 +453,24 @@ Discourse.AdminUser = Discourse.User.extend({ } else { bootbox.alert(I18n.t("admin.user.delete_failed")); } - }, function() { + }).catch(function() { bootbox.alert(I18n.t("admin.user.delete_failed")); }); } }]; + bootbox.dialog(message, buttons, {"classes": "flagging-delete-spammer"}); }); - }, - loadDetails: function() { - var model = this; - if (model.get('loadedDetails')) { return Ember.RSVP.resolve(model); } + loadDetails() { + const user = this; - return Discourse.AdminUser.find(model.get('username_lower')).then(function (result) { - model.setProperties(result); - model.set('loadedDetails', true); + if (user.get('loadedDetails')) { return Ember.RSVP.resolve(user); } + + return Discourse.AdminUser.find(user.get('username_lower')).then(function (result) { + user.setProperties(result); + user.set('loadedDetails', true); }); }, @@ -517,29 +494,25 @@ Discourse.AdminUser = Discourse.User.extend({ }); -Discourse.AdminUser.reopenClass({ +AdminUser.reopenClass({ - bulkApprove: function(users) { + bulkApprove(users) { _.each(users, function(user) { - user.set('approved', true); - user.set('can_approve', false); - return user.set('selected', false); + user.setProperties({ + approved: true, + can_approve: false, + selected: false + }); }); - bootbox.alert(I18n.t("admin.user.approve_bulk_success")); - return Discourse.ajax("/admin/users/approve-bulk", { type: 'PUT', - data: { - users: users.map(function(u) { - return u.id; - }) - } - }); + data: { users: users.map((u) => u.id) } + }).finally(() => bootbox.alert(I18n.t("admin.user.approve_bulk_success"))); }, - bulkReject: function(users) { - _.each(users, function(user){ + bulkReject(users) { + _.each(users, function(user) { user.set('can_approve', false); user.set('selected', false); }); @@ -547,26 +520,26 @@ Discourse.AdminUser.reopenClass({ return Discourse.ajax("/admin/users/reject-bulk", { type: 'DELETE', data: { - users: users.map(function(u) { return u.id; }), + users: users.map((u) => u.id), context: window.location.pathname } }); }, - find: function(username) { + find(username) { return Discourse.ajax("/admin/users/" + username + ".json").then(function (result) { result.loadedDetails = true; return Discourse.AdminUser.create(result); }); }, - findAll: function(query, filter) { + findAll(query, filter) { return Discourse.ajax("/admin/users/list/" + query + ".json", { data: filter }).then(function(users) { - return users.map(function(u) { - return Discourse.AdminUser.create(u); - }); + return users.map((u) => Discourse.AdminUser.create(u)); }); } }); + +export default AdminUser; diff --git a/app/assets/javascripts/admin/templates/user_index.hbs b/app/assets/javascripts/admin/templates/user_index.hbs index 25223ae661..e6347ff68c 100644 --- a/app/assets/javascripts/admin/templates/user_index.hbs +++ b/app/assets/javascripts/admin/templates/user_index.hbs @@ -3,20 +3,20 @@
    {{#if active}} {{#link-to 'user' model class="btn"}} - + {{fa-icon "user"}} {{i18n 'admin.user.show_public_profile'}} {{/link-to}} {{#if can_impersonate}} - + {{/if}} {{#if currentUser.admin}} - + {{/if}} {{/if}}
    @@ -26,7 +26,7 @@
    {{username}}
    {{#link-to 'preferences.username' model class="btn"}} - + {{fa-icon "pencil"}} {{i18n 'user.change_username.title'}} {{/link-to}}
    @@ -75,28 +75,32 @@
    {{#if editingTitle}} - - {{i18n 'cancel'}} + {{d-button action="saveTitle" label="admin.user.save_title"}} + {{i18n 'cancel'}} {{else}} - + {{d-button action="toggleTitleEdit" icon="pencil" label="admin.user.edit_title"}} {{/if}}
    {{#if currentUser.admin}}
    -
    {{i18n 'admin.groups.title'}}
    +
    {{i18n 'admin.groups.automatic.title'}}
    +
    {{automaticGroups}}
    +
    +
    +
    {{i18n 'admin.groups.custom.title'}}
    - {{admin-group-selector selected=model.groups available=availableGroups}} + {{admin-group-selector selected=customGroups available=availableGroups}}
    - {{#if custom_groups}} + {{#if customGroups}} {{i18n 'admin.groups.primary'}} - {{combo-box content=custom_groups value=primary_group_id nameProperty="name" none="admin.groups.no_primary"}} + {{combo-box content=customGroups value=primary_group_id nameProperty="name" none="admin.groups.no_primary"}} {{/if}} {{#if primaryGroupDirty}} - - + {{d-button icon="check" class="ok no-text" action="savePrimaryGroup"}} + {{d-button icon="times" class="cancel no-text" action="resetPrimaryGroup"}} {{/if}}
    @@ -132,7 +136,7 @@ {{i18n 'badges.badge_count' count=badge_count}}
    - {{#link-to 'adminUser.badges' this class="btn"}}{{i18n 'admin.badges.edit_badges'}}{{/link-to}} + {{#link-to 'adminUser.badges' this class="btn"}}{{fa-icon "certificate"}}{{i18n 'admin.badges.edit_badges'}}{{/link-to}}
    {{/if}} @@ -165,13 +169,11 @@
    {{#if approved}} {{i18n 'admin.user.approved_by'}} - {{#link-to 'adminUser' approvedBy}}{{avatar approvedBy imageSize="small"}}{{/link-to}} {{#link-to 'adminUser' approvedBy}}{{approvedBy.username}}{{/link-to}} {{else}} {{i18n 'no_value'}} {{/if}} -
    {{#if approved}} @@ -179,7 +181,7 @@ {{else}} {{#if can_approve}} {{/if}} @@ -206,13 +208,13 @@ {{else}} {{#if can_send_activation_email}} {{/if}} {{#if can_activate}} {{/if}} @@ -222,19 +224,18 @@
    {{i18n 'admin.api.key'}}
    - {{#if api_key}}
    {{api_key.key}} - - + {{d-button action="regenerateApiKey" icon="undo" label="admin.api.regenerate"}} + {{d-button action="revokeApiKey" icon="times" label="admin.api.revoke"}}
    {{else}}
    - — + —
    - + {{d-button action="generateApiKey" icon="key" label="admin.api.generate"}}
    {{/if}}
    @@ -245,37 +246,36 @@
    {{#if can_revoke_admin}} {{/if}} {{#if can_grant_admin}} {{/if}}
    -
    +
    {{i18n 'admin.user.moderator'}}
    {{moderator}}
    {{#if can_revoke_moderation}} {{/if}} {{#if can_grant_moderation}} {{/if}}
    -
    @@ -284,8 +284,8 @@ {{combo-box content=trustLevels value=trust_level nameProperty="detailedName"}} {{#if dirty}}
    - - + +
    {{/if}}
    @@ -300,7 +300,6 @@ {{#if tl3Requirements}} {{#link-to 'adminUser.tl3Requirements' this class="btn"}}{{i18n 'admin.user.trust_level_3_requirements'}}{{/link-to}} {{/if}} - @@ -310,7 +309,7 @@
    {{#if isSuspended}} {{suspendDuration}} @@ -318,7 +317,7 @@ {{else}} {{#if canSuspend}} {{i18n 'admin.user.suspended_explanation'}} @@ -328,17 +327,17 @@
    {{#if isSuspended}} -
    -
    {{i18n 'admin.user.suspended_by'}}
    -
    - {{#link-to 'adminUser' suspendedBy}}{{avatar suspendedBy imageSize="tiny"}}{{/link-to}} - {{#link-to 'adminUser' suspendedBy}}{{suspendedBy.username}}{{/link-to}} +
    +
    {{i18n 'admin.user.suspended_by'}}
    +
    + {{#link-to 'adminUser' suspendedBy}}{{avatar suspendedBy imageSize="tiny"}}{{/link-to}} + {{#link-to 'adminUser' suspendedBy}}{{suspendedBy.username}}{{/link-to}} +
    +
    + {{i18n 'admin.user.suspend_reason'}}: + {{suspend_reason}} +
    -
    - {{i18n 'admin.user.suspend_reason'}}: - {{suspend_reason}} -
    -
    {{/if}}
    @@ -347,7 +346,7 @@
    {{#if blocked}} {{i18n 'admin.user.block_explanation'}} @@ -386,7 +385,7 @@ {{#if can_delete_all_posts}} {{#if post_count}} {{/if}} @@ -473,7 +472,9 @@ {{#if deleteExplanation}}

    -
    {{deleteExplanation}}
    +
    + {{fa-icon "exclamation-triangle"}} {{deleteExplanation}} +
    {{/if}}
    diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml index 5fd0fdd60b..1b01d8f579 100644 --- a/config/locales/client.en.yml +++ b/config/locales/client.en.yml @@ -1683,6 +1683,10 @@ en: automatic: "Automatic" automatic_membership_email_domains: "Users who register with an email domain that exactly matches one in this list will be automatically added to this group:" automatic_membership_retroactive: "Apply the same email domain rule to add existing registered users" + custom: + title: "Custom Groups" + automatic: + title: "Automatic Groups" api: generate_master: "Generate Master API Key" From a0369855b9164b0626e3606db414f051b3feed9c Mon Sep 17 00:00:00 2001 From: Sam Date: Wed, 18 Mar 2015 09:10:23 +1100 Subject: [PATCH 045/114] FIX: subfolder offsite message bus was not returning wrong header --- config/initializers/04-message_bus.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/initializers/04-message_bus.rb b/config/initializers/04-message_bus.rb index 18c4f0c878..7ada7b9ffa 100644 --- a/config/initializers/04-message_bus.rb +++ b/config/initializers/04-message_bus.rb @@ -4,7 +4,7 @@ end MessageBus.extra_response_headers_lookup do |env| { - "Access-Control-Allow-Origin" => Discourse.base_url, + "Access-Control-Allow-Origin" => Discourse.base_url_no_prefix, "Access-Control-Allow-Methods" => "GET, POST", "Access-Control-Allow-Headers" => "X-SILENCE-LOGGER, X-Shared-Session-Key" } From 948617cb0b2e67b3186e0525c652402aa60298fa Mon Sep 17 00:00:00 2001 From: Sam Date: Wed, 18 Mar 2015 16:25:24 +1100 Subject: [PATCH 046/114] FIX: ruby 2.2 using new parsing library which is way too lax --- app/models/post_analyzer.rb | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/app/models/post_analyzer.rb b/app/models/post_analyzer.rb index dabb36733e..b60502b98f 100644 --- a/app/models/post_analyzer.rb +++ b/app/models/post_analyzer.rb @@ -55,6 +55,12 @@ class PostAnalyzer @raw_mentions = results.uniq.map { |un| un.first.downcase.gsub!(/^@/, '') } end + # from rack ... compat with ruby 2.2 + def self.parse_uri_rfc2396(uri) + @parser ||= defined?(URI::RFC2396_Parser) ? URI::RFC2396_Parser.new : URI + @parser.parse(uri) + end + # Count how many hosts are linked in the post def linked_hosts return {} if raw_links.blank? @@ -64,7 +70,7 @@ class PostAnalyzer raw_links.each do |u| begin - uri = URI.parse(u) + uri = self.class.parse_uri_rfc2396(u) host = uri.host @linked_hosts[host] ||= 1 unless host.nil? rescue URI::InvalidURIError From 89ea125c732b3aae36b65a074c6fef3196948ea3 Mon Sep 17 00:00:00 2001 From: Sam Date: Wed, 18 Mar 2015 17:47:39 +1100 Subject: [PATCH 047/114] automatic need only be added once to the hash --- spec/controllers/admin/groups_controller_spec.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/spec/controllers/admin/groups_controller_spec.rb b/spec/controllers/admin/groups_controller_spec.rb index b56f2a4d6f..2e362fd23a 100644 --- a/spec/controllers/admin/groups_controller_spec.rb +++ b/spec/controllers/admin/groups_controller_spec.rb @@ -21,7 +21,6 @@ describe Admin::GroupsController do expect(response.status).to eq(200) expect(::JSON.parse(response.body).keep_if {|r| r["id"] == group.id }).to eq([{ "id"=>group.id, - "automatic"=>false, "name"=>group.name, "user_count"=>1, "automatic"=>false, From 27a793073ab97022aa24c490dcb42fe417a15622 Mon Sep 17 00:00:00 2001 From: Arpit Jalan Date: Wed, 18 Mar 2015 18:27:27 +0530 Subject: [PATCH 048/114] Update Translations --- config/locales/client.ar.yml | 346 +++++++++++++++++++++++++++++++- config/locales/client.cs.yml | 16 +- config/locales/client.da.yml | 29 ++- config/locales/client.de.yml | 19 +- config/locales/client.es.yml | 26 ++- config/locales/client.fi.yml | 26 ++- config/locales/client.fr.yml | 20 +- config/locales/client.he.yml | 27 ++- config/locales/client.id.yml | 1 - config/locales/client.it.yml | 54 ++--- config/locales/client.ja.yml | 27 ++- config/locales/client.ko.yml | 10 - config/locales/client.nb_NO.yml | 19 +- config/locales/client.nl.yml | 10 - config/locales/client.pl_PL.yml | 18 +- config/locales/client.pt.yml | 10 - config/locales/client.pt_BR.yml | 25 ++- config/locales/client.ru.yml | 24 ++- config/locales/client.sq.yml | 10 - config/locales/client.sv.yml | 10 - config/locales/client.te.yml | 94 ++++++++- config/locales/client.tr_TR.yml | 24 ++- config/locales/client.uk.yml | 106 ++++++++-- config/locales/client.zh_CN.yml | 16 +- config/locales/client.zh_TW.yml | 10 - config/locales/server.es.yml | 1 + config/locales/server.he.yml | 69 +++++++ config/locales/server.it.yml | 1 + config/locales/server.ja.yml | 38 ++++ config/locales/server.pl_PL.yml | 17 ++ config/locales/server.pt_BR.yml | 5 + config/locales/server.ru.yml | 30 +++ config/locales/server.te.yml | 2 + 33 files changed, 916 insertions(+), 224 deletions(-) diff --git a/config/locales/client.ar.yml b/config/locales/client.ar.yml index ecd81288d2..9934adcba3 100644 --- a/config/locales/client.ar.yml +++ b/config/locales/client.ar.yml @@ -123,9 +123,13 @@ ar: user_count: "مستخدمون جدد" active_user_count: "مستخدمون نشطون" contact: "اتصل بنا" + contact_info: "في حالة حدوث أي مشكلة حرجة أو مسألة عاجلة تؤثر على هذا الموقع، يرجى الاتصال بنا على %{contact_email}." bookmarked: title: "المفضلة" clear_bookmarks: "حذف المفضله" + help: + bookmark: "انقر هنا لإضافة أول رد في هذا الموضوع الى المفضلة" + unbookmark: "أنقر هنا لحذف كل المفضلة في هذا الموضوع" bookmarks: not_logged_in: "نعتذر يجب ان تكون متصلا لكي تقوم بإضافة هدا الموضوع للمفضلة" created: "لقد نجحت في إضافة الموضوع للمفضلة" @@ -363,7 +367,6 @@ ar: title: "إرسال رسالة إلكترونية تحتوي على جديد الموقع عندما لا أزور الموقع" daily: "يومي" weekly: "اسبوعي" - every_two_weeks: "كل اسبوعين" email_direct: "تلقي رسالة إلكترونية عند اقتباس مشاركة لك أو الرد على عليها أو في حالة ذكر اسمك @username" email_private_messages: "إرسال إشعار بالبريد الإلكتروني عندما يرسل لك شخصاً رسالة خاصة" email_always: "لاتفعل ارسال رسائل بريدية اذا كنت متفاعل مع الموقع" @@ -550,9 +553,6 @@ ar: saved_local_draft_tip: "تم الحفظ محلياً" similar_topics: "موضوعك مشابه لـ ..." drafts_offline: "مسودات محفوظة " - min_length: - need_more_for_title: "{{n}} لذهاب الى العنوان" - need_more_for_reply: "{{n}} الذهاب الى" error: title_missing: "العنوان مطلوب" title_too_short: "العنوان يجب أن يكون اكثر {{min}} حرف" @@ -883,6 +883,7 @@ ar: attachment_too_large: "نعتذر، الملف الذي تريد رفعه كبير جداَ ( الحد الاقصى {{max_size_kb}} كيلوبايت )" file_too_large: "المعذرة، الملف الذي تحاول رفعه أكبر من المسموح به {{max_size_kb}} كيلوبايت" too_many_uploads: "نأسف, يمكنك رفع ملف واحد فقط في نفس الوقت." + too_many_dragged_and_dropped_files: "يمكنك سحب و إفلات ١٠ ملفات في الوقت الواحد كحد أقصى." upload_not_authorized: "المعذرة، الملف الذي تحاول رفعه غير مسموح به، الامتدادات المسموح بها هي {{authorized_extensions}}." image_upload_not_allowed_for_new_user: "نعتذر، المستخدمين الجدد لا يمكنهم رفع صور." attachment_upload_not_allowed_for_new_user: "نعتذر، المستخدمين الجدد لا يمكنهم رفع مرفقات." @@ -1015,6 +1016,7 @@ ar: images: "الصور" auto_close_label: "الإغلاق التلقائي للمواضيع بعد:" auto_close_units: "ساعات" + email_in: "تعيين بريد إلكتروني خاص:" email_in_allow_strangers: "قبول بريد إلكتروني من مستخدمين لا يملكون حسابات" email_in_disabled: "إضافة مواضيع جديدة من خلال البريد الإلكتروني موقف في الوقت الحالي من خلال إعدادات الموقع. لتفعيل إضافة مواضيع جديدة من خلال البريد الإلكتروني," email_in_disabled_click: 'قم بتفعيل خيار "email in" في الإعدادات' @@ -1024,16 +1026,26 @@ ar: this_year: "هذه السنة" position: "المكان" default_position: "المكان الافتراضي" + position_disabled: "التصنيفات يتم عرضها حسب النشاط. لتغيير طريقة ترتيب التصنيفات، " + position_disabled_click: 'فعّل خيار " تثبيت مكان التصنيفات".' + parent: "التصنيف الأب" notifications: watching: title: "مشاهده " + description: "ستتابع بشكل تلقائي جديد هذه التصنيفات. سيتم إشعارك بكل مشاركة او موضوع، بالإضافة لذلك سيتم عرض عدد المشاركات الغير مقروءة و الجديدة بجانب الموضوع." tracking: title: "تتبع " + description: "ستتابع بشكل تلقائي جديد هذه التصنيفات. سيتم إشعارك بكل مشاركة او موضوع، بالإضافة لذلك سيتم عرض عدد المشاركات الغير مقروءة و الجديدة بجانب الموضوع." regular: title: "طبيعي" + description: ".سيتم إشعارك إذا ذكر أحد ما اسمك أو رد على مشاركاتك" muted: title: "كتم" + description: "لن يتم إشعارك بأي جديد يخص هذا الموضوع ولن يظهرهذا الموضوع في تبويب المواضيع الغير مقروءة." flagging: + title: 'شكرا لمساعدتك في إبقاء مجتمعنا نظيفاً.' + private_reminder: 'التبليغات ذات خصوصية، تظهر فقط للمشرفين' + action: 'التبليغ عن مشاركة' take_action: "أجراء العمليه " notify_action: 'رسائل خاصة' delete_spammer: "حذف مرسلي البريد المزعج" @@ -1041,16 +1053,22 @@ ar: yes_delete_spammer: "نعم , حذف مرسلي البريد المزعج" ip_address_missing: "(N/A)" hidden_email_address: "(مخفي)" + submit_tooltip: "إرسال تبليغ" + take_action_tooltip: "الوصول إلى الحد الأعلى للتبليغات دون انتظار تبليغات أكثر من أعضاء الموقع." + cant: "المعذرة، لا يمكنك التبليغ عن هذه المشاركة في هذه اللحظة." formatted_name: off_topic: "خارج عن الموضوع" + inappropriate: "غير لائق" spam: "هذا سبام" custom_placeholder_notify_user: "كن محدد, استدلالي ودائما حسن الاخلاق" + custom_placeholder_notify_moderators: "ممكن تزودنا بمعلومات أكثر عن سبب عدم ارتياحك حول هذه المشاركة؟ زودنا ببعض الروابط و الأمثلة قدر الإمكان." custom_message: at_least: "ادخل على الاقل {{n}} حرف" more: "{{n}} الذهاب الى" left: "{{n}} باقي" flagging_topic: title: "شكرا لمساعدتنا في ابقاء مجتمعنا نضيفا" + action: "التبليغ عن الموضوع" notify_action: "رسالة خاصة" topic_map: title: "ملخص الموضوع" @@ -1073,17 +1091,105 @@ ar: help: "هذا الموضوع مثبت لك, سوف يتم عرضه في اول القسم" archived: help: "هذا الموضوع مؤرشف,لن تستطيع أن تعدل عليه" + invisible: + help: "هذا الموضوع غير مصنف لن يظهر في قائمة التصانيف ولايمكن الدخول عليه الابرابط مباشر." posts: "مشاركات" posts_lowercase: "مشاركات" + posts_long: "هناك {{number}} مشاركات في هذا الموضوع" + original_post: "المشاركة الاصلية" + views: "مشاهدات" + views_lowercase: "مشاهدات" + replies: "ردود " + views_long: "هذا الموضوع قد تمت مشاهدته {{number}} مرات" activity: "النشاط" likes: "اعجابات" likes_lowercase: "اعجابات" + likes_long: "هناك {{number}} اعجابات في هذا الموضوع" users: "مستخدمين" users_lowercase: "مستخدمين" category_title: "قسم" + history: "تاريخ" + changed_by: "الكاتب {{author}}" + raw_email: + title: "البريد الإلكتروني" + not_available: "غير متوفر" + categories_list: "قائمة الاقسام" + filters: + with_topics: "%{filter} مواضيع" + with_category: "%{filter} %{category} مواضيع" + latest: + title: "آخر" + help: "مواضيع بآخر المشاركات" + hot: + title: "ساخن" + help: "مختارات من مواضيع ساخنة" + read: + title: "قراءة" + help: "مواضيع قمت بقراءتها بترتيب آخر قراءة" + categories: + title: "اقسام" + title_in: "قسم - {{categoryName}}" + help: "جميع المواضيع تتبع القسم" + unread: + title: + zero: "غير مقروء" + one: "غير مقروء (1)" + other: "غير مقروء ({{count}})" + help: "مواضيع أنت تشاهدها بمشاركات غير مقروءة " + lower_title_with_count: + one: "1 غير مقروء" + other: "{{count}} غير مقروء" + new: + lower_title_with_count: + one: "1 جديد" + other: "{{count}} جديد" + lower_title: "جديد" + title: + zero: "جديد" + one: "جديد (1)" + other: "جديد ({{count}})" + help: "مواضيع جديد في الايام السابقة" + posted: + title: "مشاركاتي" + help: "مواضيع شاركت بها " + bookmarks: + title: "المفضلة" + help: "مواضيع قمت بتفضيلها" + category: + title: + zero: "{{categoryName}}" + one: "{{categoryName}} (1)" + other: "{{categoryName}} ({{count}})" + help: "آخر المواضيع في {{categoryName}} قسم" + top: + title: "أعلى" + help: "أكثر المواضيع نشاطا خلال سنة, شهر, اسبوع او يوم" + yearly: + title: "الاعلى في السنة" + monthly: + title: "الاعلى في الشهر" + weekly: + title: "الاعلى في الاسبوع" + daily: + title: "الاعلى في اليوم" + all: "كل الاوقات" + this_year: "هذه السنة" + this_month: "هذا الشهر" + this_week: "هذا الاسبوع" + today: "اليوم" + other_periods: "الاطلاع على مواضيع زيادة" + browser_update: 'للأسف, متصفحك قديم لكي يفتح هذه الصفحة. Please قم بتحديث متصفحك.' + permission_types: + full: "انشاء / رد / مشاهدة" + create_post: "رد / مشاهدة" + readonly: "مشاهدة" admin_js: + type_to_filter: "اكتب لتصفية" admin: + title: 'مدير المجتمع' + moderator: 'مراقب' dashboard: + title: "داشبورد" version: "الاصدار" critical_available: "يوجد تحديث هام." updates_available: "يوجد تحديثات." @@ -1097,7 +1203,10 @@ ar: moderators: 'مراقبين:' admins: 'مدراء:' blocked: 'محظور:' + suspended: 'موقوف:' private_messages_title: "رسائل خاصة" + uploads: "عمليات الرفع" + backups: "النسخ الاحتياطية" reports: today: "اليوم" yesterday: "امس" @@ -1113,42 +1222,267 @@ ar: flags: old: "قديم" active: "نشط" + defer_flag_title: "إزالة البلاغ، لا يتطلب منك إجراء في الوقت الحالي." + delete: "حذف" + delete_title: "حذف المشاركة المرتبطة بهذا البلاغ" + delete_post_defer_flag_title: "حذف المشاركة. اذا كانت المشاركة الاولى, احذف الموضوع" + delete_post_agree_flag: "حذف المشاركة مع الموافقة على البلاغ" + delete_post_agree_flag_title: "حذف المشاركة. اذا كانت المشاركة الاولى, احذف الموضوع" + delete_flag_modal_title: "حذف مع ..." + delete_spammer: "حذف مرسلي البريد المزعج" + delete_spammer_title: "احذف المستخدم مع مشاركاته و مواضيعه." + disagree_flag_unhide_post: "أختلف مع البلاغ، إعادة إظهار المشاركة." + disagree_flag_unhide_post_title: "حذف أي بلاغ يخص هذه المشاركة مع إظهارها مرة أخرى" + disagree_flag: "أختلف" + disagree_flag_title: "رفض هذا البلاغ لكونه خاطئ" + clear_topic_flags: "إتمام العملية" + clear_topic_flags_title: "تم فحص الموضوع وحل المشاكل المتعلقة به. إضغط على إتمام العملية لحذف هذه البلاغات." + more: "ردود أكثر..." + dispositions: + agreed: "متفق" + disagreed: "أختلف" + deferred: "مؤجل" + flagged_by: "مُبلّغ عنه بواسطة" + resolved_by: "تم حلّه بواسطة" + system: "النظام" error: "حدث خطأ ما" + no_results: "لا يوجد بلاغات." + visit_topic: "زيارة الموضوع لاتخاذ قرار" + was_edited: "تم تعديل المشاركة بعد أول بلاغ" groups: + primary: "المجموعة الأساسية" + no_primary: "(لايوجد مجموعة أساسية)" title: "مجموعات" edit: "تعديل المجموعة" + refresh: "تحديث" + new: "جديد" + selector_placeholder: "أدخل اسم المستخدم" name_placeholder: "اسم المجموعة, بدون مسافة, مثل قاعدة اسم المستخدم" about: "هنا عدّل على عضوية المجموعة والاسماء" + group_members: "اعضاء المجموعة" delete: "حذف" delete_confirm: "حذف هذة المجموعة؟" delete_failed: "لا يمكن حذف هذه المجموعة. اذا كانت هذة المجموعة مجموعة تلقائية, لا يمكن حذفها." + delete_member_confirm: "ازالة '%{username}' من '%{group}' المجموعة?" + name: "الاسم" + add: "اضافة" + add_members: "اضافة عضو" + custom: "مخصص" + automatic: "تلقائي" + automatic_membership_email_domains: "المستخدمين الذين يمتلكون بريد الالكتروني عنوانه مطابق للعنوان الذي في القائمة سيتم تلقائيا اضافتهم للمجموعة." + automatic_membership_retroactive: "اضافة الاعضاء الذين يمتكلون عنوان ايميل مطابق للعنوان الموجود في القائمة." api: + generate_master: "Generate Master API Key" + none: "There are no active API keys right now" + user: "مستخدمين" title: "API" key: "API Key" generate: "إنشاء" regenerate: "إعادة إنشاء" + revoke: "Revoke" + confirm_regen: "هل أنت متأكد من استبدال مفتاح الAPI بالمفتاح الجديد ؟" + confirm_revoke: "هل أنت متأكد من رغبتك في تعطيل هذا المفتاح؟" + info_html: "Your API key will allow you to create and update topics using JSON calls." + all_users: "جميع المستخدمين" + note_html: "Keep this key secret, all users that have it may create arbitrary posts as any user." + plugins: + title: "اضافات" + installed: "اضافات مثيته" + name: "الاسم" + none_installed: "لاتملك اي اضافة مثبته" + version: "الاصدار" + change_settings: "تغيير الاعدادت" + howto: "كيف اثبت اضافة؟" + backups: + title: "نسخة احتياطية" + menu: + backups: "نسخة احتياطية" + logs: "Logs" + none: "لاتوجد نسخ احتياطية" + read_only: + enable: + title: "تفعيل وضع القراءة فقط" + text: "تفعيل وضع القراءة فقط" + confirm: "هل أنت متأكد من تفعيل وضع القراءة فقط؟" + disable: + title: "تعطيل وضع القراءة فقط" + text: "تعطيل وضع القراءة فقط" + logs: + none: "No logs yet." + columns: + filename: "اسم الملف" + size: "حجم" + upload: + text: "رفع" + uploading: "يتم الرفع..." + success: "'{{filename}}' تم رفعه بنجاح." + error: "هناك مشكلة في رفع '{{filename}}': {{message}}" + operations: + is_running: "هناك عملية مازالت تعمل ..." + failed: "الـ {{operation}} فشلت. الرجاء التحقق من logs." + cancel: + text: "إلغاء" + title: "الغاء العملية الحالية" + confirm: "هل أنت متأكد من رغبتك في الغاء العملية الحالية ؟" + backup: + text: "نسخة احتياطية" + title: "انشاء نسخة احتياطية" + confirm: "هل تريد انشاء نسخة احتياطية جديدة ؟" + without_uploads: "نعم (لا تضمن الملفات)" + download: + text: "تحميل" + title: "تحميل النسخة الاحتياطية" + destroy: + text: "حذف" + title: "حذف النسخة الاحتياطية" + confirm: "هل أنت متأكد من رغبتك في حذف النسخة الاحتياطية؟" + restore: + is_disabled: "Restore is disabled in the site settings." + text: "Restore" + title: "اعادة تخزين النسخة الاحتياطية" + confirm: "هل أنت متأكد من رغبتك في اعادة تخزين النسخة الاحتياطية؟" + rollback: + text: "اعادة السنخة السابقة" + title: "Rollback the database to previous working state" + confirm: "Are your sure you want to rollback the database to the previous working state?" + export_csv: + user_archive_confirm: "هل أنت متأكد من رغبتك في تحميل جميع مشاركاتك ؟" + success: "Export initiated, you will be notified via private message when the process is complete." + failed: "فشل في التصدير, الرجاء التحقق من الـ logs" + rate_limit_error: "المشاركات يمكن تحميلها لمرة واحدة في اليوم , الرجاء المحاولة غدا." + button_text: "التصدير" + button_title: + user: "تصدير قائمة المستخدمين على شكل CSV" + staff_action: "تصدير قائمة الموظفين على شكل CSV." + screened_email: "Export full screened email list in CSV format." + screened_ip: "Export full screened IP list in CSV format." + screened_url: "Export full screened URL list in CSV format." + invite: + button_text: "ارسال دعوات" + button_title: "ارسال دعوات" customize: title: "تخصيص" long_title: "تخصيص الموقع" + css: "CSS" + header: "Header" + top: "Top" + footer: "Footer" + head_tag: + text: "" + title: "HTML that will be inserted before the tag" + body_tag: + text: "" + title: "HTML that will be inserted before the tag" + override_default: "Do not include standard style sheet" enabled: "تفعيل؟" preview: "معاينة" + undo_preview: "ازالة المعاينة" + rescue_preview: "الشكل الافتراضي" + explain_preview: "مشاهدة الموقع مع الثيم الجديد" + explain_undo_preview: "الرجوع الى الثيم السابق" + explain_rescue_preview: "مشاهدة الموقع مع الثيم الافتراضي" save: "حفظ" new: "جديد" + new_style: "ثيم جديد" delete: "حذف" delete_confirm: "حذف هذا التخصيص؟" + about: "Modify CSS stylesheets and HTML headers on the site. Add a customization to start." + color: "Color" + opacity: "Opacity" + copy: "نسخ" + css_html: + title: "CSS/HTML" + long_title: "CSS and HTML Customizations" + colors: + title: "اللون" + long_title: "نمط الألوان" + about: "Modify the colors used on the site without writing CSS. Add a scheme to start." + new_name: "New Color Scheme" + copy_name_prefix: "نسخة من" + delete_confirm: "حذف جميع الالوان؟" + undo: "تراجع" + undo_title: "التراجع عن تغيير اللن الى اللون السابق" + revert: "تراجع" + revert_title: "اعادة ضبط اللون الى اللون الافتراضي للموقع" + primary: + name: 'اساسي' + description: 'Most text, icons, and borders.' + secondary: + name: 'ثانوي' + description: 'اللون الاساسي للخلفية, والنص للايقونة' + tertiary: + name: 'tertiary' + description: 'الروابط، الأزرار، الإشعارات و أشياء أخرى.' + quaternary: + name: "رباعي" + description: "الروابط" + header_background: + name: "خلفية رأس الصفحة" + description: "لون الخلفية لرأس الصفحة الخاصة بالموقع" + header_primary: + name: "رأس الصفحة الأساسي" + description: "لون و أيقونات رأس الصفحة الخاصة بالموقع." + highlight: + name: 'تحديد' + description: 'لون خلفية النصوص و العناصر المحددة في جسم الصفحة مثل المشاركات و المواضيع.' + danger: + name: 'خطر' + description: 'لون بعض الأوامر مثل حذف المشاركات و المواضيع' + success: + name: 'نجاح' + description: 'يستخدم لإظهار نجاح عملية ما.' + love: + name: 'إعجاب' + description: "لون زر الإعجاب." + wiki: + name: 'ويكي' + description: "اللون الأساسي المستخدم كخلفية لمشاركات الويكي." email: title: "بريد الكتروني" settings: "اعدادات" + all: "الكل" + sending_test: "إرسال بريد إلكتروني للتجربة..." + error: "خطأ - %{server_error}" + test_error: "حدث خطأ أثناء إرسال رسالة تجريبية. الرجاء فحص إعدادات البريد الإلكتروني و التأكد من أن الاستضافة لا تمنع مرور البريد الإلكتروني والمحاولة مرة أخرى." + sent: "تم الإرسال" + skipped: "تم التجاوز" sent_at: "أرسلت في" + time: "الوقت" + user: "المستخدم" email_type: "نوع البريد الكتروني" to_address: "الى العناوين" test_email_address: "عنوان البريد الكتروني للتجربة" + send_test: "ارسل رسالة تجربة" sent_test: "اٌرسلت!" delivery_method: "طريقة التسليم" refresh: "تحديث" + format: "التنسيق" html: "html" text: "نص" last_seen_user: "آخر مستخدم تواجد:" + logs: + filters: + user_placeholder: "اسم المستخدم" + logs: + delete: 'حذف' + edit: 'تعديل' + save: 'حفظ' + screened_actions: + block: "حظر" + do_nothing: "لا تفعل شيء" + staff_actions: + title: "عمليات المشرفين" + clear_filters: "إظهار الكل" + subject: "الموضوع" + when: "متى" + context: "السياق" + details: "التفاصيل" + previous_value: "معاينة" + new_value: "جديد" + diff: "الاختلافات" + show: "إظهار" + modal_title: "التفاصيل" + no_previous: "لا يوجد قيمة سابقة." users: title: 'مستخدمين' create: 'اضافة مدير' @@ -1196,6 +1530,10 @@ ar: block_failed: 'حدث خطأ عند حظر هذا المستخدم.' site_settings: none: 'لا شيء' + badges: + save: حفظ + delete: حذف + reason: السبب badges: badge: first_share: diff --git a/config/locales/client.cs.yml b/config/locales/client.cs.yml index 17f5180bf0..7ea7731d63 100644 --- a/config/locales/client.cs.yml +++ b/config/locales/client.cs.yml @@ -425,7 +425,6 @@ cs: title: "Když tady dlouho nebudu, chci emailem zaslat co je nového:" daily: "denně" weekly: "týdně" - every_two_weeks: "jednou za 14 dní" email_direct: "Upozornit emailem na moje citace, odpovědi na můj příspěvek a na @jmeno" email_private_messages: "Upozornit emailem na nové soukromé konverzace" email_always: "Posílat upozorňovací emaily i když jsem zrovna na webu aktivní" @@ -486,6 +485,7 @@ cs: too_short: "Vaše heslo je příliš krátké." common: "Toto heslo je používané moc často." same_as_username: "Vaše heslo je stejné jako Vaše uživatelské jméno." + same_as_email: "Vaše heslo je stejné jako váš e-mail." ok: "Vaše heslo je v pořádku." instructions: "Alespo %{count} znaků." associated_accounts: "Přihlášení" @@ -596,6 +596,7 @@ cs: requires_invite: "Promiňte, toto fórum je pouze pro zvané." not_activated: "Ještě se nemůžete přihlásit. Zaslali jsme vám aktivační email v {{sentTo}}. Prosím následujte instrukce v tomto emailu, abychom mohli váš účet aktivovat." not_allowed_from_ip_address: "Z této IP adresy se nemůžete přihlásit." + admin_not_allowed_from_ip_address: "Z této IP adresy se nemůžete přihlásit jako administrátor." resend_activation_email: "Klikněte sem pro zaslání aktivačního emailu." sent_activation_email_again: "Zaslali jsme vám další aktivační email na {{currentEmail}}. Může trvat několik minut, než vám dorazí. Zkontrolujte také vaši složku s nevyžádanou pošlou." google: @@ -621,6 +622,7 @@ cs: twitter: "Twitter" emoji_one: "Emoji One" composer: + emoji: "Emoji :smile:" add_warning: "Toto je oficiální varování." posting_not_on_topic: "Rozepsali jste odpověď na téma \"{{title}}\", ale nyní máte otevřené jiné téma." saving_draft_tip: "ukládám" @@ -628,9 +630,6 @@ cs: saved_local_draft_tip: "uloženo lokálně" similar_topics: "Podobná témata" drafts_offline: "koncepty offline" - min_length: - need_more_for_title: "ještě {{n}} znaků nadpisu tématu" - need_more_for_reply: "ještě {{n}} znaků" error: title_missing: "Název musí být vyplněn" title_too_short: "Název musí být dlouhý alespoň {{min}} znaků" @@ -695,6 +694,7 @@ cs: examples: 'Zadejte počet hodin (24).' notifications: title: "oznámení o zmínkách pomocí @jméno, odpovědi na vaše příspěvky a témata, soukromé zprávy, atd." + none: "Notifikace nebylo možné načíst." more: "zobrazit starší oznámení" total_flagged: "celkem nahlášeno příspěvků" mentioned: "@

    {{username}} {{description}}

    " @@ -777,6 +777,7 @@ cs: unread: "Nejsou tu žádná další nepřečtená témata." category: "V kategorii {{category}} nejsou žádná další témata." top: "Nejsou tu žádná další populární témata." + bookmarks: "Žádná další oblíbená témata nejsou k dispozici." topic: filter_to: "{{post_count}} příspěvků v tématu" create: 'Nové téma' @@ -937,6 +938,7 @@ cs: to_forum: "Pošleme krátký email dovolující vašemu příteli se okamžitě zapojit s pomocí kliknutí na odkaz. Nebude potřeba registrace." email_placeholder: 'jmeno@priklad.cz' success: "Zaslali jsme pozvánku na {{email}}. Upozorníme vás až bude pozvánka použita. Své pozvánky můžete sledovat v tabulce pozvánek na svém uživatelském profilu." + error: "Bohužel se nepodařilo pozvat tuto osobu. Není již registrovaným uživatelem? (Pozvánky jsou omezeny)." login_reply: 'Přihlaste se, chcete-li odpovědět' filters: n_posts: @@ -1313,12 +1315,6 @@ cs: posts: "Příspěvků" posts_lowercase: "příspěvky" posts_long: "v tomto tématu je {{number}} příspěvků" - posts_likes_MF: | - Toto téma má {count, plural, one {1 příspěvek} few {# příspěvky} other {# příspěvků}} {ratio, select, - low {s velkým poměrem líbí se na příspěvek} - med {s velmi velkým poměrem líbí se na příspěvek} - high {s extrémně velkým poměrem líbí se na příspěvek} - other {}} original_post: "Původní příspěvek" views: "Zobrazení" views_lowercase: "zobrazení" diff --git a/config/locales/client.da.yml b/config/locales/client.da.yml index a2fd5f7aa2..3da53a8d5d 100644 --- a/config/locales/client.da.yml +++ b/config/locales/client.da.yml @@ -125,6 +125,7 @@ da: daily: "dagligt" weekly: "ugentligt" every_two_weeks: "hver anden uge" + every_three_days: "hver tredje dag" max_of_count: "max af {{count}}" character_count: one: "{{count}} tegn" @@ -147,6 +148,7 @@ da: user_count: "Nye brugere" active_user_count: "Aktive brugere" contact: "Kontakt os" + contact_info: "I tilfælde af kritiske situationer eller vigtige spørgsmål angående denne side, kontakt os venligst på %{contact_emal}." bookmarked: title: "Bogmærke" clear_bookmarks: "Ryd Bogmærker" @@ -400,6 +402,7 @@ da: email_digests: title: "Når jeg ikke besøger her, send mig en email med nyheder." daily: "dagligt" + every_three_days: "hver tredje dag" weekly: "ugenligt" every_two_weeks: "hver anden uge" email_direct: "Send mig en email når nogen citere mig, svar på mit indlæg, eller nævner mit @brugernavn" @@ -457,6 +460,8 @@ da: title: "Adgangskode" too_short: "Din adgangskode er for kort." common: "Den adgangskode er for udbredt." + same_as_username: "Dit password er det samme som dit brugernavn." + same_as_email: "Dit password er det samme som din email adresse." ok: "Din adgangskode ser fin ud." instructions: "Mindst %{count} tegn" associated_accounts: "Logins" @@ -567,6 +572,7 @@ da: requires_invite: "Beklager, det kræve en invitation at blive medlem af dette forum." not_activated: "Du kan ikke logge ind endnu. Vi har tidligere sendt en aktiverings-e-mail til dig på {{sentTo}}. Følg venligst instruktionerne i den e-mail for at aktivere din konto." not_allowed_from_ip_address: "Du kan ikke logge ind fra den IP adresse." + admin_not_allowed_from_ip_address: "Du kan ikke logge på som administrator fra denne IP adresse." resend_activation_email: "Klik her for at sende aktiverings-e-mail’en igen." sent_activation_email_again: "Vi har sendt endnu en aktiverings-e-mail til dig på {{currentEmail}}. Det kan tage nogen få minutter før den når frem; kontrollér også din spam-mappe." google: @@ -600,9 +606,6 @@ da: saved_local_draft_tip: "gemt lokalt" similar_topics: "Dit emne minder om…" drafts_offline: "kladder offline" - min_length: - need_more_for_title: "der mangler {{n}} tegn i titlen" - need_more_for_reply: "{{n}} tilbage" error: title_missing: "Titlen er påkrævet" title_too_short: "Titlen skal være på mindst {{min}} tegn" @@ -724,6 +727,7 @@ da: close_topics: "Luk indlæg" archive_topics: "Arkiver Emner" notification_level: "Skift niveau for underetninger" + choose_new_category: "Vælg den nye kategori for emnerne:" selected: one: "Du har valgt 1 indlæg." other: "Du har valgt {{count}} indlæg." @@ -1258,10 +1262,10 @@ da: posts_lowercase: "indlæg" posts_long: "{{number}} indlæg i dette emne" posts_likes_MF: | - Dette emne har {count, plural, one {1 indlæg} other {# indlæg}} {ratio, select, - low {with a high like to post ratio} - med {with a very high like to post ratio} - high {with an extremely high like to post ratio} + Dette emne har {count, plural, one {1 svar} other {# svar}} {ratio, select, + low {med et højt like pr. indlæg forhold} + med {med et meget højt like pr. indlæg forhold} + high {med et ekstremt højt like pr. indlæg forhold} other {}} original_post: "Oprindeligt indlæg" views: "Visninger" @@ -1339,6 +1343,7 @@ da: title: "Top ugentligt" daily: title: "Top dagligt" + all: "Alt" this_year: "Dette år" this_month: "Denne måned" this_week: "Denne uge" @@ -1735,6 +1740,7 @@ da: delete_topic: "slet emne" delete_post: "slet indlæg" impersonate: "Udgiv dig for bruger" + anonymize_user: "anonymiser bruger" screened_emails: title: "Blokerede e-mails" description: "Følgende e-mail-adresser kontrolleres når nogen prøver at oprette en konto, og oprettelsen vil enten blive blokeret, eller der vil blive foretaget en anden handling." @@ -1868,8 +1874,13 @@ da: approve_success: "Bruger godkendt og e-mail med aktiveringsvejledning sendt." approve_bulk_success: "Succes! Alle valgte brugere er blevet godkendt og underrettet." time_read: "Læsetid" + anonymize: "Anonymiser Bruger" + anonymize_confirm: "Er du HELT SIKKER på at du vil anonymisere denne konto? Dette vil ændre brugernavnet og email adressen, samt nulstille profil informationen." + anonymize_yes: "Ja, anonymiser denne konto" + anonymize_failed: "Der var problemer med at anonymisere denne konto." delete: "Slet bruger" delete_forbidden_because_staff: "Admins og moderatorer kan ikke slettes." + delete_posts_forbidden_because_staff: "Kan ikke slette alle indlæg fra administratorer og moderatorer." delete_forbidden: one: "Brugere kan ikke slettes hvis de har oprettet sig for mere end %{count} dag siden, eller hvis de har oprettet indlæg. Slet alle indlæg før du forsøger at slette en bruger." other: "Brugere kan ikke slettes hvis de har oprettet sig for mere end %{count} dage siden, eller hvis de har oprettet indlæg. Slet alle indlæg før du forsøger at slette en bruger." @@ -1976,6 +1987,7 @@ da: none: 'ingen' no_results: "Ingen resultater fundet." clear_filter: "Ryd" + add_url: "tilføj URL" categories: all_results: 'Alle' required: 'Obligatoriske' @@ -2011,10 +2023,13 @@ da: modal_title: Badge grupperinger granted_by: Givet af granted_at: Givet på + reason_help: (Et link til et indlæg eller et emne) save: Gem delete: Slet delete_confirm: Er du sikker på du vil slette denne badge ? revoke: Fratag + reason: Grund + expand: Fold ud … revoke_confirm: Er du sikker på du vil fratage brugeren denne badge ? edit_badges: Rediger Badges grant_badge: Tildel Badge diff --git a/config/locales/client.de.yml b/config/locales/client.de.yml index 51e8abc48d..63570c1ea3 100644 --- a/config/locales/client.de.yml +++ b/config/locales/client.de.yml @@ -125,6 +125,7 @@ de: daily: "täglich" weekly: "wöchentlich" every_two_weeks: "jede zweite Woche" + every_three_days: "alle drei Tage" max_of_count: "von max. {{count}}" character_count: one: "{{count}} Zeichen" @@ -401,8 +402,9 @@ de: email_digests: title: "Schicke eine E-Mail mit Neuigkeiten, wenn ich länger nicht hier bin:" daily: "täglich" + every_three_days: "alle drei Tage" weekly: "wöchentlich" - every_two_weeks: "alle zwei Wochen" + every_two_weeks: "alle drei Tage" email_direct: "Schicke eine E-Mail, wenn mich jemand zitiert, auf meine Beiträge antwortet oder meinen @Namen erwähnt." email_private_messages: "Schicke eine E-Mail, wenn mir jemand eine private Nachricht sendet." email_always: "E-Mail-Benachrichtigungen nicht unterdrücken, während ich im Forum aktiv bin" @@ -459,6 +461,7 @@ de: too_short: "Dein Passwort ist zu kurz." common: "Das Passwort wird zu häufig verwendet." same_as_username: "Dein Passwort entspricht deinem Benutzernamen." + same_as_email: "Dein Passwort entspricht deiner E-Mail-Adresse." ok: "Dein Passwort sieht in Ordnung aus." instructions: "Mindestens %{count} Zeichen." associated_accounts: "Anmeldeinformationen" @@ -568,7 +571,8 @@ de: awaiting_approval: "Dein Konto wurde noch nicht von einem Mitarbeiter genehmigt. Du bekommst eine E-Mail, sobald das geschehen ist." requires_invite: "Entschuldige, der Zugriff auf dieses Forum ist nur mit einer Einladung möglich." not_activated: "Du kannst dich noch nicht anmelden. Wir haben dir schon eine E-Mail zur Aktivierung an {{sentTo}} geschickt. Bitte folge den Anweisungen in dieser E-Mail, um dein Benutzerkonto zu aktivieren." - not_allowed_from_ip_address: "Du kannst dich mit dieser IP-Adresse nicht anmelden." + not_allowed_from_ip_address: "Von dieser IP-Adresse darfst du dich nicht anmelden." + admin_not_allowed_from_ip_address: "Von dieser IP-Adresse darfst du dich nicht als Administrator anmelden." resend_activation_email: "Klicke hier, um eine neue Aktivierungsmail zu schicken." sent_activation_email_again: "Wir haben dir eine weitere E-Mail zur Aktivierung an {{currentEmail}} geschickt. Es könnte ein paar Minuten dauern, bis diese ankommt; sieh auch im Spam-Ordner nach." google: @@ -602,9 +606,6 @@ de: saved_local_draft_tip: "lokal gespeichert" similar_topics: "Dein Thema hat Ähnlichkeit mit..." drafts_offline: "Entwürfe offline" - min_length: - need_more_for_title: "im Titel fehlen noch {{n}} Zeichen" - need_more_for_reply: "noch {{n}} Zeichen" error: title_missing: "Titel ist erforderlich" title_too_short: "Titel muss mindestens {{min}} Zeichen lang sein" @@ -1262,11 +1263,7 @@ de: posts_lowercase: "Beiträge" posts_long: "dieses Thema enthält {{number}} Beiträge" posts_likes_MF: | - Dieses Thema hat {count, plural, one {1 Beitrag} other {# Beiträge}} {ratio, select, - low {mit einem hohen Verhältnis von Likes zu Beiträgen} - med {mit einem sehr hohen Verhältnis von Likes zu Beiträgen} - high {mit einem extrem hohen Verhältnis von Likes zu Beiträgen} - other {}} + Dieses Thema hat {count, plural, one {1 Antwort} other {# Antworten}} {ratio, select, low {mit einem hohen Verhältnis von Likes zu Beiträgen} med {mit einem sehr hohen Verhältnis von Likes zu Beiträgen} high {mit einem extrem hohen Verhältnis von Likes zu Beiträgen} other {}} original_post: "Original-Beitrag" views: "Aufrufe" views_lowercase: "Aufrufe" @@ -1343,6 +1340,7 @@ de: title: "Angesagt wöchentlich" daily: title: "Angesagt täglich" + all: "Gesamte Zeit" this_year: "Dieses Jahr" this_month: "Dieser Monat" this_week: "Diese Woche" @@ -1980,6 +1978,7 @@ de: none: 'keine' no_results: "Keine Ergebnisse gefunden." clear_filter: "Filter zurücksetzen" + add_url: "URL hinzufügen" categories: all_results: 'Alle' required: 'Erforderlich' diff --git a/config/locales/client.es.yml b/config/locales/client.es.yml index ee62c82535..6058333b10 100644 --- a/config/locales/client.es.yml +++ b/config/locales/client.es.yml @@ -112,7 +112,7 @@ es: guidelines: "Directrices" privacy_policy: "Política de Privacidad" privacy: "Privacidad" - terms_of_service: "Condiciones Generales de Uso" + terms_of_service: "Condiciones de uso" mobile_view: "Versión móvil" desktop_view: "Versión de escritorio" you: "Tú" @@ -125,6 +125,7 @@ es: daily: "cada día" weekly: "cada semana" every_two_weeks: "cada dos semanas" + every_three_days: "cada tres días" max_of_count: "máximo de {{count}}" character_count: one: "{{count}} carácter" @@ -401,6 +402,7 @@ es: email_digests: title: "Cuando no visite la página, enviarme un correo con las últimas novedades." daily: "diariamente" + every_three_days: "cada tres días" weekly: "semanalmente" every_two_weeks: "cada dos semanas" email_direct: "Enviarme un email cuando alguien me cita, responde a mi post o menciona mi @usuario" @@ -459,6 +461,7 @@ es: too_short: "Tu contraseña es demasiada corta." common: "Esa contraseña es demasiado común." same_as_username: "Tu contraseña es la misma que tu nombre de usuario." + same_as_email: "Tu contraseña es la misma que tu dirección de correo electrónico." ok: "Tu contraseña es válida." instructions: "Debe contener al menos %{count} caracteres." associated_accounts: "Inicios de sesión" @@ -569,6 +572,7 @@ es: requires_invite: "Lo sentimos pero solo se puede acceder a este foro mediante invitación." not_activated: "No puedes iniciar sesión todavía. Anteriormente te hemos enviado un email de activación a {{sentTo}}. Por favor sigue las instrucciones en ese email para activar tu cuenta." not_allowed_from_ip_address: "No puedes iniciar sesión desde esa dirección IP." + admin_not_allowed_from_ip_address: "No puedes iniciar sesión como admin desde esta dirección IP." resend_activation_email: "Has clic aquí para enviar el email de activación nuevamente." sent_activation_email_again: "Te hemos enviado otro e-mail de activación a {{currentemail}}. Podría tardar algunos minutos en llegar; asegúrate de revisar tu carpeta de spam." google: @@ -602,9 +606,6 @@ es: saved_local_draft_tip: "guardado localmente" similar_topics: "Tu tema es similar a..." drafts_offline: "borradores offline" - min_length: - need_more_for_title: "{{n}} para completar el título" - need_more_for_reply: "{{n}} para completar" error: title_missing: "Es necesario un título" title_too_short: "El título debe ser por lo menos de {{min}} caracteres." @@ -726,6 +727,7 @@ es: close_topics: "Cerrar temas" archive_topics: "Archivar temas" notification_level: "Cambiar el Nivel de Notificación" + choose_new_category: "Elige una nueva categoría para los temas:" selected: one: "Has seleccionado 1 tema." other: "Has seleccionado {{count}} temas." @@ -1260,7 +1262,7 @@ es: posts_lowercase: "posts" posts_long: "{{number}} posts en este tema" posts_likes_MF: | - Este tema tiene {count, plural, one {1 post} other {# posts}} {ratio, select, + Este tema tiene {count, plural, one {1 respuesta} other {# respuestas}} {ratio, select, low {con una ratio de me gusta por post elevada} med {con una ratio de me gusta por post bastante elevada} high {con una ratio de me gusta por post elevadísima} @@ -1341,6 +1343,7 @@ es: title: "Top de la semana" daily: title: "Top del día" + all: "Todo el tiempo" this_year: "Este año" this_month: "Este mes" this_week: "Esta semana" @@ -1737,6 +1740,7 @@ es: delete_topic: "eliminar tema" delete_post: "eliminar post" impersonate: "impersonar" + anonymize_user: "anonimizar usuario" screened_emails: title: "Correos bloqueados" description: "Cuando alguien trata de crear una cuenta nueva, los siguientes correos serán revisados y el registro será bloqueado, o alguna otra acción será realizada." @@ -1825,14 +1829,14 @@ es: unsuspend_failed: "Algo salió mal quitando ban a este usuario {{error}}" suspend_duration: "¿Cuánto tiempo le gustaría aplicar ban al usuario? (days)" suspend_duration_units: "(días)" - suspend_reason_label: "¿Por qué lo pospones? Este texto será visible para todos en la página de perfil del usuario, y además será mostrado al usuario cuando trate de ingresar en el sitio web. Mantenlo simplificado." + suspend_reason_label: "¿Por qué lo suspendes? Este texto será visible para todos en la página de perfil del usuario y se mostrará al usuario cuando intente iniciar sesión. Sé conciso." suspend_reason: "Causa" suspended_by: "Suspendido por" delete_all_posts: "Eliminar todos los posts" delete_all_posts_confirm: "Estás a punto de borrar %{posts} posts y %{topics} temas. ¿Estás seguro?" suspend: "Suspender" - unsuspend: "Quitar ban" - suspended: "¿Baneado?" + unsuspend: "Quitar suspensión" + suspended: "¿Suspendido?" moderator: "¿Moderador?" admin: "¿Administrador?" blocked: "¿Bloqueado?" @@ -1870,8 +1874,13 @@ es: approve_success: "Usuario aprobado y correo electrónico enviado con instrucciones para la activación." approve_bulk_success: "¡Perfecto! Todos los usuarios seleccionados han sido aprobados y notificados." time_read: "Tiempo de lectura" + anonymize: "Anonimizar usuario" + anonymize_confirm: "¿SEGURO que quieres hacer anónima esta cuenta? Esto cambiará el nombre de usuario y el email, y reseteará toda la información de perfil." + anonymize_yes: "Sí, hacer anónima esta cuenta." + anonymize_failed: "Hubo un problema al hacer anónima la cuenta." delete: "Borrar usuario" delete_forbidden_because_staff: "Administradores y moderadores no pueden ser eliminados" + delete_posts_forbidden_because_staff: "No se pueden eliminar todos los posts de admins y moderadores." delete_forbidden: one: "Los usuarios no se pueden borrar si han sido registrados hace más de %{count} día, o si tienen publicaciones. Borra todas publicaciones antes de tratar de borrar un usuario." other: "Los usuarios no se pueden borrar si han sido registrados hace más de %{count} días, o si tienen publicaciones. Borra todas publicaciones antes de tratar de borrar un usuario." @@ -1978,6 +1987,7 @@ es: none: 'ninguno' no_results: "Ningún resultado encontrado" clear_filter: "Limpiar filtro" + add_url: "añadir URL" categories: all_results: 'Todo' required: 'Requerido' diff --git a/config/locales/client.fi.yml b/config/locales/client.fi.yml index 7903916d88..8791f42d2e 100644 --- a/config/locales/client.fi.yml +++ b/config/locales/client.fi.yml @@ -147,6 +147,7 @@ fi: user_count: "Uusia käyttäjiä" active_user_count: "Aktiivisia käyttäjiä" contact: "Yhteystiedot" + contact_info: "Sivustoon liittyvissä kiireellisissä asioissa, ota yhteyttä osoitteeseen %{contact_email}." bookmarked: title: "Kirjanmerkki" bookmarks: @@ -397,7 +398,6 @@ fi: title: "Lähetä tiivistelmä uusista viesteistä sähköpostilla, jos en käy sivustolla " daily: "päivittäin" weekly: "viikottain" - every_two_weeks: "joka toinen viikko" email_direct: "Lähetä minulle sähköposti, jos joku lainaa viestiäni, vastaa viestiini tai viittaa @nimeeni." email_private_messages: "Lähetä minulle sähköposti jos joku lähettää minulle yksityisviestin" email_always: "Älä jätä lähettämättä sähköposti-ilmoituksia, vaikka olen aktiivinen palstalla." @@ -453,6 +453,8 @@ fi: title: "Salasana" too_short: "Salasanasi on liian lyhyt." common: "Annettu salasana on liian yleinen." + same_as_username: "Salasanasi on sama kuin käyttäjätunnuksesi." + same_as_email: "Salasanasi on sama kuin sähköpostisi." ok: "Salasana vaikuttaa hyvältä." instructions: "Vähintään %{count} merkkiä." associated_accounts: "Kirjautumiset" @@ -596,9 +598,6 @@ fi: saved_local_draft_tip: "tallennettu omalla koneella" similar_topics: "Tämä ketju vaikuttaa samalta kuin.." drafts_offline: "offline luonnokset" - min_length: - need_more_for_title: "Tarvitaan vielä {{n}} merkkiä otsikkoon" - need_more_for_reply: "vielä {{n}}" error: title_missing: "Otsikko on pakollinen" title_too_short: "Otsikon täytyy olla vähintään {{min}} merkkiä pitkä" @@ -1252,12 +1251,6 @@ fi: posts: "Viestejä" posts_lowercase: "viestejä" posts_long: "tässä ketjussa on {{number}} viestiä" - posts_likes_MF: | - Tässä ketjussa on {count, plural, one {1 viesti, jolla on} other {# viestiä, joilla on}} {ratio, select, - low {suuri määrä tykkäyksiä suhteessa viestien määrään} - med {erittäin suuri määrä tykkäyksiä suhteessa viestien määrään} - high {äärimmäisen suuri määrä tykkäyksiä suhteessa viestien määrään} - other {}} original_post: "Aloitusviesti" views: "Katselut" views_lowercase: "katselut" @@ -1334,6 +1327,7 @@ fi: title: "Viikon huiput" daily: title: "Päivän huiput" + all: "Kaikki" this_year: "Tänä vuonna" this_month: "Tässä kuussa" this_week: "Tällä viikolla" @@ -1377,6 +1371,8 @@ fi: backups: "varmuuskopiot" traffic_short: "Liikenne" traffic: "Sovelluksen web-pyynnöt" + page_views: "API pyynnöt" + page_views_short: "API pyynnöt" show_traffic_report: "Näytä yksityiskohtainen liikenneraportti" reports: today: "Tänään" @@ -1554,6 +1550,7 @@ fi: title: "Palauta tietokanta edelliseen toimivaan tilaan" confirm: "Oletko varma, että haluat palauttaa tietokannan edelliseen toimivaan tilaan?" export_csv: + user_archive_confirm: "Oletko varma, että haluat ladata viestisi?" success: "Vienti on käynnissä. Saat ilmoituksen yksityisviestillä, kun prosessi on valmis." failed: "Vienti epäonnistui. Tarkista loki-tiedostot." rate_limit_error: "Viestit voidaan ladata kerran päivässä, yritä uudestaan huomenna." @@ -1564,6 +1561,9 @@ fi: screened_email: "Vie koko lista seulotuista sähköpostiosoitteista CSV-formaatissa." screened_ip: "Vie koko lista seulotuista IP-osoitteista CSV-formaatissa." screened_url: "Vie koko lista seulotuista URL-osoitteista CSV-formaatissa." + invite: + button_text: "Lähetä kutsut" + button_title: "Lähetä kutsut" customize: title: "Mukauta" long_title: "Sivuston mukautukset" @@ -1965,6 +1965,7 @@ fi: none: 'ei mitään' no_results: "Ei tuloksia." clear_filter: "Tyhjennä" + add_url: "Lisää URL" categories: all_results: 'Kaikki' required: 'Pakolliset' @@ -2004,6 +2005,8 @@ fi: delete: Poista delete_confirm: Oletko varma, että haluat poistaa tämän arvomerkin? revoke: Peruuta + reason: Syy + expand: Laajenna … revoke_confirm: Oletko varma, että haluat peruuttaa arvomerkin? edit_badges: Muokkaa arvomerkkejä grant_badge: Myönnä arvomerkki @@ -2154,6 +2157,9 @@ fi: autobiographer: name: Muistelmien kirjoittaja description: Täytti käyttäjätiedot + anniversary: + name: Vuosipäivä + description: Ollut vuoden aktiivinen jäsen, kirjoittanut vähintään kerran nice_post: name: Kiva viesti description: Sai 10 tykkäystä viestistä. Tämä arvomerkki voidaan myöntää useita kertoja diff --git a/config/locales/client.fr.yml b/config/locales/client.fr.yml index c198bd93ae..1f51d79085 100644 --- a/config/locales/client.fr.yml +++ b/config/locales/client.fr.yml @@ -125,6 +125,7 @@ fr: daily: "quotidiennes" weekly: "hebdomadaires" every_two_weeks: "bi-mensuelles" + every_three_days: "tous les trois jours" max_of_count: "maximum sur {{count}}" character_count: one: "{{count}} caractère" @@ -401,8 +402,9 @@ fr: email_digests: title: "Quand je ne visite pas ce site, m'envoyer un résumé des nouveautés par courriel:" daily: "quotidien" + every_three_days: "tous les trois jours" weekly: "hebdomadaire" - every_two_weeks: "tous les 15 jours" + every_two_weeks: "toutes les deux semaines" email_direct: "M'envoyer un courriel quand quelqu'un me cite, répond à mon message ou mentionne mon @pseudo" email_private_messages: "M'envoyer un courriel quand quelqu'un m'envoie un message privé" email_always: "Ne pas recevoir de courriel de notifications lorsque je suis actif sur le site" @@ -459,6 +461,7 @@ fr: too_short: "Votre mot de passe est trop court." common: "Ce mot de passe est trop commun." same_as_username: "Votre mot de passe est le même que votre pseudo." + same_as_email: "Votre mot de passe est le même que votre adresse mail." ok: "Votre mot de passe semble correct." instructions: "Au moins %{count} caractères." associated_accounts: "Connexions" @@ -569,6 +572,7 @@ fr: requires_invite: "Désolé, l'accès à ce forum est sur invitation seulement." not_activated: "Vous ne pouvez pas vous encore vous connecter. Nous avons envoyé un courriel d'activation à {{sentTo}}. Merci de suivre les instructions afin d'activer votre compte." not_allowed_from_ip_address: "Vous ne pouvez pas vous connecter depuis cette adresse IP." + admin_not_allowed_from_ip_address: "Vous ne pouvez pas vous connecter comme administrateur depuis cette adresse IP." resend_activation_email: "Cliquez ici pour envoyer à nouveau le courriel d'activation." sent_activation_email_again: "Nous venons d'envoyer un nouveau courriel d'activation à {{currentEmail}}. Il peut prendre quelques minutes à arriver; n'oubliez pas de vérifier votre répertoire spam." google: @@ -602,9 +606,6 @@ fr: saved_local_draft_tip: "sauvegardé en local" similar_topics: "Votre message est similaire à..." drafts_offline: "sauvegardé hors ligne" - min_length: - need_more_for_title: "{{n}} caractères restant pour le titre" - need_more_for_reply: "{{n}} restants" error: title_missing: "Le titre est obligatoire." title_too_short: "Le titre doit avoir au moins {{min}} caractères" @@ -726,6 +727,7 @@ fr: close_topics: "Fermer les sujets" archive_topics: "Sujets archivés" notification_level: "Modifier le niveau de notification" + choose_new_category: "Choisissez la nouvelle catégorie pour les sujets :" selected: one: "Vous avez sélectionné 1 sujet." other: "Vous avez sélectionné {{count}} sujets." @@ -1264,7 +1266,7 @@ fr: posts_lowercase: "messages" posts_long: "il y a {{number}} messages dans ce sujet" posts_likes_MF: | - Ce sujet a {count, plural, one {1 message} other {# messages}} {ratio, select, + Ce sujet a {count, plural, one {1 réponse} other {# réponses}} {ratio, select, low {avec un haut ratio de J'aime/Message} med {avec un très haut ratio J'aime/Message} high {avec un énorme ratio J'aime/Message} @@ -1345,6 +1347,7 @@ fr: title: "Top Hebdomadaire" daily: title: "Top Quotidien" + all: "depuis toujours" this_year: "Cette année" this_month: "Ce mois-ci" this_week: "Cette semaine" @@ -1741,6 +1744,7 @@ fr: delete_topic: "supprimer le sujet" delete_post: "supprimer le message" impersonate: "incarner" + anonymize_user: "rendre l'utilisateur anonyme" screened_emails: title: "Courriels affichés" description: "Lorsque quelqu'un essaye de créé un nouveau compte, les adresses de courriel suivantes seront vérifiées et l'inscription sera bloquée, ou une autre action sera réalisée." @@ -1874,8 +1878,13 @@ fr: approve_success: "Utilisateur approuvé et un courriel avec les instructions d'activation a été envoyé." approve_bulk_success: "Bravo! Tous les utlisateurs sélectionnés ont été approuvés et notifiés." time_read: "Temps de lecture" + anonymize: "Rendre l'utilisateur anonyme" + anonymize_confirm: "Êtes-vous sûr de vouloir rendre ce compte anonyme ? Ceci entraînera la modification du pseudo et de l'adresse courriel, et réinitialisera les informations du profil." + anonymize_yes: "Oui, rendre ce compte anonyme" + anonymize_failed: "Il y a eu un problème lors de l'anonymisation de ce compte." delete: "Supprimer l'utilisateur" delete_forbidden_because_staff: "Administrateurs et modérateurs ne peuvent pas être supprimés." + delete_posts_forbidden_because_staff: "Vous ne pouvez pas supprimer tous les messages des administrateurs ou des modérateurs." delete_forbidden: one: "Les utilisateurs ne peuvent pas être supprimés s'ils ont posté des messages Supprimer tous les messages avant d'essayer de supprimer un utilisateur. (Les messages plus vieux que %{count} jour ne peut pas être supprimé.)" other: "Les utilisateurs ne peuvent pas être supprimés s'ils ont crée des messages. Supprimer tous les messages avant d'essayer de supprimer un utilisateur. (Les messages plus vieux que %{count} jours ne peuvent pas être supprimés.)" @@ -1982,6 +1991,7 @@ fr: none: 'rien' no_results: "Aucun résultat trouvé." clear_filter: "Effacer" + add_url: "ajouter URL" categories: all_results: 'Toutes' required: 'Requis' diff --git a/config/locales/client.he.yml b/config/locales/client.he.yml index 535b3e3630..e99ed33a52 100644 --- a/config/locales/client.he.yml +++ b/config/locales/client.he.yml @@ -125,6 +125,7 @@ he: daily: "יומית" weekly: "שבועית" every_two_weeks: "דו-שבועית" + every_three_days: "כל שלושה ימים" max_of_count: "מקסימום של {{count}}" character_count: one: "תו אחד" @@ -147,6 +148,7 @@ he: user_count: "חדשים" active_user_count: "משתמשים פעילים" contact: "צרו קשר" + contact_info: "במקרה של ארוע בנושא חשוב או חירומים המשפיע על האתר, אנא צרו איתנו קשר ב:%{contact_info}." bookmarked: title: "סימניה" clear_bookmarks: "ניקוי סימניות" @@ -296,7 +298,7 @@ he: suspended_reason: "הסיבה: " github_profile: "גיטהאב" mailing_list_mode: "שלחו לי דוא\"ל על כל פרסום חדש (אלא אם אשתיק את המעקב אחר הנושא או הקטגוריה)" - watched_categories: "נצפה" + watched_categories: "צופה" watched_categories_instructions: "את/ה תצפו אוטומטית בכל הנושאים החדשים בקטגוריות האלה ותקבלו התראות על כל ההודעות והנושאים החדשים. כמו כן כמות ההודעות החדשות ואלו שלא נקראו תופיע לצד כל נושא." tracked_categories: "במעקב" tracked_categories_instructions: "מעקב אוטומטי אחרי נושאים חדשים בקטגוריות אלו. מספר הפרסומים החדשים ואלו שלא נקראו יופיע לצד הנושא." @@ -400,8 +402,9 @@ he: email_digests: title: "כשאיני מבקר/ת כאן, שלחו לי מייל עם תקציר העדכונים:" daily: "יומית" + every_three_days: "כל שלושה ימים" weekly: "שבועית" - every_two_weeks: "דו-שבועית" + every_two_weeks: "כל שבועיים" email_direct: "שלחו לי דואל כשמישהו/י מצטטים אותי, מגיבים לפרסום שלי או מזכירים את @שם_המשתמש/ת" email_private_messages: "שלחו לי דוא\"ל כשמישהו/מישהי שולחים לי מסר פרטי" email_always: "אל תמנעו התראות דוא\"ל כאשר אני פעיל/ה באתר" @@ -457,6 +460,8 @@ he: title: "סיסמה" too_short: "הסיסמה שלך קצרה מידי." common: "הסיסמה הזו נפוצה מידי." + same_as_username: "הסיסמה שלך זהה לשם המשתמש/ת שלך." + same_as_email: "הסיסמה שלך זהה לכתובת הדוא\"ל שלך." ok: "הסיסמה שלך נראית טוב." instructions: "לפחות %{count} תווים." associated_accounts: "התחברויות" @@ -567,6 +572,7 @@ he: requires_invite: "סליחה, גישה לפורום הזה היא בהזמנה בלבד." not_activated: "אינך יכול להתחבר עדיין. שלחנו לך דואר אלקטרוני להפעלת החשבון לכתובת: {{sentTo}}. יש לעקוב אחר ההוראות בדואר כדי להפעיל את החשבון." not_allowed_from_ip_address: "אינכם יכולים להתחבר מכתובת IP זו." + admin_not_allowed_from_ip_address: "אינך יכול/ה להתחבר כמנהל מערכת מכתובת IP זו." resend_activation_email: "יש ללחוץ כאן לשליחת דואר אלקטרוני חוזר להפעלת החשבון." sent_activation_email_again: "שלחנו לך הודעת דואר אלקטרוני נוספת להפעלת החשבון לכתובת {{currentEmail}}. זה יכול לקחת כמה דקות עד שיגיע, לא לשכוח לבדוק את תיבת דואר הזבל." google: @@ -600,9 +606,6 @@ he: saved_local_draft_tip: "נשמר מקומית" similar_topics: "הנושא שלך דומה ל..." drafts_offline: "טיוטות מנותקות" - min_length: - need_more_for_title: "{{n}} תווים נשארו לכותרת" - need_more_for_reply: "עוד {{n}} " error: title_missing: "יש להזין כותרת." title_too_short: "על הכותרת להיות באורך {{min}} תווים לפחות." @@ -724,6 +727,7 @@ he: close_topics: "סגירת נושאים" archive_topics: "ארכיון הנושאים" notification_level: "שינוי רמת התראה" + choose_new_category: "בחרו את הקטגוריה עבור הנושאים:" selected: one: "בחרת נושא אחד." other: "בחרת {{count}} נושאים." @@ -1192,7 +1196,7 @@ he: title: "צופה" description: "תצפו באופן אוטומטי בכל הנושאים החדשים בקטגוריות אלה. תקבלו התראה על כל פרסום ונושא חדש, ובנוסף, סך הפרסומים החדשים ושלא נקראו יופיעו לצד הנושא." tracking: - title: "במעקב" + title: "עוקב" description: "תעקבו באופן אוטומטי אחרי כל הנושאים החדשים בקטגוריות אלה. סך הפרסומים החדשים ושלא נקראו יופיעו לצד הנושא." regular: title: "רגיל" @@ -1339,6 +1343,7 @@ he: title: "המיטב השבועי" daily: title: "המיטב היומי" + all: "כל הזמנים" this_year: "השנה" this_month: "החודש" this_week: "השבוע" @@ -1735,6 +1740,7 @@ he: delete_topic: "מחיקת נושא" delete_post: "מחיקת פרסום" impersonate: "התחזה" + anonymize_user: "הפיכת משתמש/ת לאנונימיים" screened_emails: title: "הודעות דואר מסוננות" description: "כשמישהו מנסה ליצור חשבון חדש, כתובות הדואר האלקטרוני הבאות ייבדקו וההרשמה תחסם או שיבוצו פעולות אחרות." @@ -1868,8 +1874,13 @@ he: approve_success: "משתמש אושר ונשלחה לו הודעות דואר אלקטרוני עם הוראות הפעלה" approve_bulk_success: "הצלחה! כל המשתמשים שנבחרו אושרו ויודעו על כך." time_read: "זמן קריאה" + anonymize: "הפיכת משתמש/ת לאנונימיים" + anonymize_confirm: "האם אתם ב-ט-ו-ח-י-ם שאתם רוצים להפוך חשבון זה לאנונימי? פעולה זו תשנה את שם המשתמש/ת וכתובת הדוא\"ל ותאתחל את כל המידע בפרופיל." + anonymize_yes: "כן, הפיכת חשבון זה לאנונימי" + anonymize_failed: "התרחשה בעיה בהפיכת חשבון זה לאנונימי." delete: "מחק משתמש" delete_forbidden_because_staff: "לא ניתן למחוק מנהלים ראשיים ומנהלים." + delete_posts_forbidden_because_staff: "לא ניתן למחוק את כל הפרסומים של מנהלי מערכת ומפקחים." delete_forbidden: one: "לא ניתן למחוק משתמשים אם יש להם הודעות. מחק את כל ההודעות לפני ניסיון מחיקה של משתמש. (הודעות ישנות יותר מ-%{count} ימים לא ניתן למחוק.)" other: "לא ניתן למחוק משתמשים אם יש להם הודעות. מחק את כל ההודעות לפני ניסיון מחיקה של משתמש. (הודעות ישנות יותר מ-%{count} ימים לא ניתן למחוק.)" @@ -1976,6 +1987,7 @@ he: none: 'ללא' no_results: "לא נמצאו תוצאות." clear_filter: "נקה" + add_url: "הוספת כתובת URL" categories: all_results: 'הכל' required: 'נדרש' @@ -2011,10 +2023,13 @@ he: modal_title: תג קבוצות granted_by: הוענק ע"י granted_at: הוענק ב + reason_help: (קישור לפרסום או לנושא) save: שמור delete: מחק delete_confirm: אתה בטוח שברצונך למחוק את התג הזה? revoke: שלול + reason: סיבה + expand: הרחבה … revoke_confirm: אתה בטוח שברצונך לשלול את התג הזה? edit_badges: ערוך תגים grant_badge: הענק תג diff --git a/config/locales/client.id.yml b/config/locales/client.id.yml index f62dde877a..a1e66224f2 100644 --- a/config/locales/client.id.yml +++ b/config/locales/client.id.yml @@ -287,7 +287,6 @@ id: email_digests: daily: "harian" weekly: "mingguan" - every_two_weeks: "setiap dua minggu" auto_track_options: never: "tidak pernah" always: "selalu" diff --git a/config/locales/client.it.yml b/config/locales/client.it.yml index 8848a79c41..a59c43711c 100644 --- a/config/locales/client.it.yml +++ b/config/locales/client.it.yml @@ -125,6 +125,7 @@ it: daily: "giornaliero" weekly: "settimanale" every_two_weeks: "bisettimanale" + every_three_days: "ogni tre giorni" max_of_count: "massimo di {{count}}" character_count: one: "{{count}} carattere" @@ -139,21 +140,21 @@ it: our_moderators: "I Nostri Moderatori" stat: all_time: "Sempre" - last_7_days: "Ultimi 7 giorni" - last_30_days: "Ultimi 30 Giorni" + last_7_days: "ultimi 7 giorni" + last_30_days: "ultimi 30 giorni" like_count: "Mi piace" topic_count: "Argomenti" post_count: "Messaggi" user_count: "Nuovi Utenti" active_user_count: "Utenti Attivi" contact: "Contattaci" - contact_info: "In caso di un problema critico o questione urgente su questo sito, per favore contattaci su %{contact_info}." + contact_info: "Nel caso di un problema grave o urgente riguardante il sito, per favore contattaci all'indirizzo %{contact_info}." bookmarked: title: "Segnalibro" clear_bookmarks: "Cancella Segnalibri" help: - bookmark: "Clicca per aggiungere ai segnalibri il primo post su questo topic" - unbookmark: "Clicca per rimuovere tutti i segnalibri in questo argomento" + bookmark: "Clicca per aggiungere un segnalibro al primo messaggio di questo argomento" + unbookmark: "Clicca per rimuovere tutti i segnalibri a questo argomento" bookmarks: not_logged_in: "spiacenti, devi essere connesso per aggiungere segnalibri ai messaggi" created: "hai inserito questo messaggio nei segnalibri." @@ -401,8 +402,9 @@ it: email_digests: title: "Quando non visito il sito, invia un riassunto delle novità per email: " daily: "ogni giorno" + every_three_days: "ogni tre giorni" weekly: "ogni settimana" - every_two_weeks: "bisettimanale" + every_two_weeks: "ogni due settimane" email_direct: "Inviami un'email quando qualcuno mi cita, risponde a un mio messaggio o menziona il mio @nome" email_private_messages: "Inviami un'email quando qualcuno mi scrive un messaggio privato" email_always: "Non sospendere le notifiche via email anche quando sono attivo sul sito" @@ -459,6 +461,7 @@ it: too_short: "La password è troppo breve." common: "Questa password è troppo comune." same_as_username: "La tua password è uguale al tuo nome utente." + same_as_email: "La password coincide con l'email." ok: "La password è adeguata" instructions: "Minimo %{count} caratteri." associated_accounts: "Login" @@ -569,6 +572,7 @@ it: requires_invite: "Spiacenti, l'accesso a questo forum e solo ad invito." not_activated: "Non puoi ancora effettuare l'accesso. Abbiamo inviato un'email di attivazione a {{sentTo}}. Per favore segui le istruzioni contenute nell'email per attivare l'account." not_allowed_from_ip_address: "Non puoi collegarti con questo indirizzo IP." + admin_not_allowed_from_ip_address: "Non puoi collegarti come amministratore dal quell'indirizzo IP." resend_activation_email: "Clicca qui per inviare nuovamente l'email di attivazione." sent_activation_email_again: "Ti abbiamo mandato un'altra email di attivazione su {{currentEmail}}. Potrebbero essere necessari alcuni minuti di attesa; assicurati di controllare anche la cartella dello spam." google: @@ -602,9 +606,6 @@ it: saved_local_draft_tip: "salvato in locale" similar_topics: "Il tuo argomento è simile a..." drafts_offline: "bozze offline" - min_length: - need_more_for_title: "{{n}} per andare al titolo" - need_more_for_reply: "ne mancano {{n}}" error: title_missing: "Il titolo è richiesto" title_too_short: "Il titolo deve essere lungo almeno {{min}} caratteri" @@ -726,6 +727,7 @@ it: close_topics: "Chiudi Argomenti" archive_topics: "Archivia Argomenti" notification_level: "Cambia Livello Notifiche" + choose_new_category: "Scegli la nuova categoria per gli argomenti:" selected: one: "Hai selezionato 1 argomento." other: "Hai selezionato {{count}} argomenti." @@ -858,7 +860,7 @@ it: description: "Non ti verrà notificato nulla di questo argomento e non comparirà nella tab dei non letti." actions: recover: "Ripristina Argomento" - delete: "Cancella l'argomento" + delete: "Cancella Argomento" open: "Apri Argomento" close: "Chiudi Argomento" auto_close: "Chiudi Automaticamente" @@ -981,7 +983,7 @@ it: attachment_too_large: "Spiacenti, il file che stai tentando di caricare è troppo grande (il massimo consentito è {{max_size_kb}}kb)." file_too_large: "Spiacenti, il file che stai cercando di caricare è troppo grande (la grandezza massima è {{max_size_kb}}kb)" too_many_uploads: "Spiacenti, puoi caricare un solo file per volta." - too_many_dragged_and_dropped_files: "Mi dispiace, puoi trascinare e spostare solo 10 file alla volta." + too_many_dragged_and_dropped_files: "Spiacenti, puoi trascinare e rilasciare solo 10 file alla volta." upload_not_authorized: "Spiacenti, il file che stai cercando di caricare non è autorizzato (estensioni autorizzate: {{authorized_extensions}})." image_upload_not_allowed_for_new_user: "Spiacenti, i nuovi utenti non possono caricare immagini." attachment_upload_not_allowed_for_new_user: "Spiacenti, i nuovi utenti non possono caricare allegati." @@ -1260,11 +1262,7 @@ it: posts_lowercase: "messaggi" posts_long: "ci sono {{number}} messaggi in questo argomento" posts_likes_MF: | - Questo argomento ha {count, plural, one {1 messaggio} other {# messaggi}} {ratio, select, - low {con un alto rapporto "mi piace" / messaggi} - med {con un altissimo rapporto "mi piace" / messaggi} - high {con un estremamente alto rapporto "mi piace" / messaggi} - other {}} + Questo argomento ha {count, plural, one {1 risposta} other {# risposte}} {ratio, select, low {con un alto rapporto "mi piace" / messaggi} med {con un altissimo rapporto "mi piace" / messaggi} high {con un estremamente alto rapporto "mi piace" / messaggi} other {}} original_post: "Messaggio Originale" views: "Visualizzazioni" views_lowercase: "visualizzazioni" @@ -1341,6 +1339,7 @@ it: title: "Migliori della settimana" daily: title: "Migliori del giorno" + all: "Senza limiti di tempo" this_year: "Quest'anno" this_month: "Questo mese" this_week: "Questa settimana" @@ -1504,12 +1503,12 @@ it: note_html: "Mantieni segreta questa chiave, tutti gli utenti che la possiedono possono creare messaggi per conto di altri." plugins: title: "Plugin" - installed: "Plugin installati" + installed: "Plugin Installati" name: "Nome" none_installed: "Non hai installato nessun plugin." version: "Versione" - change_settings: "Cambia le impostazioni" - howto: "Come installare i plugin?" + change_settings: "Cambia Impostazioni" + howto: "Come installo i plugin?" backups: title: "Backup" menu: @@ -1563,7 +1562,7 @@ it: title: "Ripristina il database a una versione funzionante precedente" confirm: "Sicuro di voler ripristinare una precedente versione funzionante del database?" export_csv: - user_archive_confirm: "Sei sicuro di voler scaricare i tuoi post?" + user_archive_confirm: "Sei sicuro di voler scaricare i tuoi messaggi?" success: "Esportazione iniziata, verrai avvertito con un messaggio privato al termine del processo." failed: "Esportazione fallita. Controlla i log." rate_limit_error: "I messaggi possono essere scaricati una volta al giorno, prova ancora domani." @@ -1737,6 +1736,7 @@ it: delete_topic: "cancella argomento" delete_post: "cancella messaggio" impersonate: "impersona" + anonymize_user: "rendi anonimo l'utente " 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." @@ -1870,8 +1870,13 @@ it: approve_success: "Utente approvato ed email inviata con istruzioni di attivazione." approve_bulk_success: "Riuscito! Tutti gli utenti selezionati sono stati approvati e notificati." time_read: "Tempo di lettura" + anonymize: "Rendi Anonimo Utente " + anonymize_confirm: "Sei SICURO di voler rendere anonimo questo account? Verrà cambiato il nome utente e la email e reimpostate tutte le informazioni del profilo." + anonymize_yes: "Sì, rendi anonimo questo account" + anonymize_failed: "Si è verificato un problema nel rendere anonimo l'account." delete: "Cancella utente" delete_forbidden_because_staff: "Amministratori e moderatori non possono essere cancellati." + delete_posts_forbidden_because_staff: "Impossibile cancellare tutti i messaggi degli amministratori e dei moderatori." delete_forbidden: one: "Non è possibile cancellare utenti se hanno post attivi. Elimina tutti i posti prima di cancellare un utente (post più vecchi di %{count} giorni non possono essere cancellati)." other: "Non è possibile cancellare utenti se hanno messaggi. Elimina tutti i messaggi prima di cancellare un utente (i messaggi più vecchi di %{count} giorni non possono essere cancellati)." @@ -1978,6 +1983,7 @@ it: none: 'nessuno' no_results: "Nessun risultato trovato." clear_filter: "Pulisci" + add_url: "aggiungi URL" categories: all_results: 'Tutti' required: 'Obbligatorie' @@ -2013,7 +2019,7 @@ it: modal_title: Raggruppamento Targhette granted_by: Assegnata Da granted_at: Assegnata in data - reason_help: (Un link a un post o argomento) + reason_help: (Un collegamento a un messaggio o argomento) save: Salva delete: Cancella delete_confirm: Sei sicuro di voler cancellare questa targhetta? @@ -2106,7 +2112,7 @@ it: dismiss_topics: 'x, t Chiudi Argomenti' actions: title: 'Azioni' - bookmark_topic: 'f Segna argomento preferito' + bookmark_topic: 'f Aggiungi/togli argomento nei segnalibri' pin_unpin_topic: 'shift+p Appunta/Spunta argomento' share_topic: 'shift+s Condividi argomento' share_post: 's Condividi messaggio' @@ -2172,8 +2178,8 @@ it: name: Autobiografo description: Completato le informazioni del tuo profilo utente anniversary: - name: Anniversario - description: Membro attivo per un anno, ha postato almeno una volta + name: Compleanno + description: Membro attivo da un anno, ha scritto almeno una volta nice_post: name: Buon Messaggio description: Ricevuto 10 "mi piace" in un messaggio. Questa targhetta può essere assegnata più volte. diff --git a/config/locales/client.ja.yml b/config/locales/client.ja.yml index 16e3dfd885..db0a974d50 100644 --- a/config/locales/client.ja.yml +++ b/config/locales/client.ja.yml @@ -68,6 +68,7 @@ ja: other: "%{count} 日前" share: topic: 'このトピックのリンクをシェアする' + post: 'ポスト #%{postNumber}' close: '閉じる' twitter: 'Twitter でこのリンクを共有する' facebook: 'Facebook でこのリンクを共有する' @@ -106,6 +107,7 @@ ja: daily: "毎日" weekly: "毎週" every_two_weeks: "隔週" + every_three_days: "3日毎" max_of_count: "最大 {{count}}" character_count: other: "{{count}} 文字" @@ -120,7 +122,14 @@ ja: stat: all_time: "All Time" last_7_days: "過去7日間" + last_30_days: "過去30日間" topic_count: "トピック" + post_count: "ポスト" + user_count: "新規ユーザ" + active_user_count: "アクティブユーザ" + bookmarked: + title: "ブックマーク" + clear_bookmarks: "ブックマークをクリア" bookmarks: not_logged_in: "ポストをブックマークするには、ログインする必要があります" created: "このポストをブックマークしました" @@ -223,6 +232,7 @@ ja: profile: "プロフィール" mute: "ミュート" edit: "プロフィールを編集" + download_archive: "自分の投稿をダウンロード" private_message: "プライベートメッセージ" private_messages: "メッセージ" activity_stream: "アクティビティ" @@ -232,6 +242,8 @@ ja: invited_by: "招待者" trust_level: "トラストレベル" notifications: "通知" + dismiss_notifications: "全て既読にする" + dismiss_notifications_tooltip: "全ての未読の通知を既読にします" dynamic_favicon: "favicon に受信したメッセージ通知を表示する" edit_history_public: "投稿編集履歴を公開する" external_links_in_new_tab: "外部リンクを全て新しいタブで開く" @@ -243,6 +255,7 @@ ja: admin_tooltip: "このユーザは管理者であり" suspended_notice: "このユーザは {{date}} までサスペンド状態です。" suspended_reason: "理由: " + mailing_list_mode: "投稿される度にメールで通知を受け取る(ミュートにしたトピック、カテゴリー以外)" watched_categories: "参加中" watched_categories_instructions: "このカテゴリに新しく投稿されたトピックを自動的に参加します。このカテゴリに対して新しい投稿があった場合、登録されたメールアドレスと、コミュニティ内の通知ボックスに通知が届き、トピック一覧に新しい投稿数がつきます。" tracked_categories: "トラック中" @@ -284,8 +297,10 @@ ja: error: "メールアドレス変更中にエラーが発生しました。既にこのアドレスが使われているのかもしれません。" success: "このアドレスにメールを送信しました。メールの指示に従って確認処理を行ってください。" change_avatar: + title: "プロフィール画像を変更" gravatar: "Gravatar, based on" refresh_gravatar_title: "グラバターを更新する" + letter_based: "システムプロフィール画像" uploaded_avatar: "カスタム画像" uploaded_avatar_empty: "カスタム画像を追加" upload_title: "画像をアップロード" @@ -293,12 +308,19 @@ ja: image_is_not_a_square: "警告: 画像が正方形ではなかったためクロップしました。" change_profile_background: title: "プロフィール背景" + instructions: "プロフィール背景は、幅850pxでセンタリングされます" + change_card_background: + title: "ユーザーカード背景" + instructions: "背景画像は、幅590pxでセンタリングされます" email: title: "メールアドレス" + instructions: "外部に公開されることはありません" name: title: "名前" + instructions: "フルネーム(任意)" username: title: "ユーザ名" + instructions: "空白を含まないユニークな名前を入力してください" global_mismatch: "既に利用されています。{{suggestion}} などはいかがでしょう?" not_available: "利用できません。{{suggestion}} などはいかがでしょう?" checking: "ユーザ名が利用可能か確認しています..." @@ -314,12 +336,13 @@ ja: created: "参加時刻" log_out: "サインアウト" location: "所在地" + card_badge: + title: "ユーザーカードバッジ" website: "ウェブサイト" email_settings: "メール" email_digests: daily: "毎日" weekly: "毎週" - every_two_weeks: "隔週" email_always: "ログインしている際にメール通知を受け取る。" other_settings: "その他" categories_settings: "カテゴリ設定" @@ -497,8 +520,6 @@ ja: saved_local_draft_tip: "ローカルに保存しました" similar_topics: "このトピックに似ているトピック..." drafts_offline: "オフラインで下書き" - min_length: - need_more_for_title: "タイトルにあと{{n}}文字必要" error: title_missing: "タイトルを入力してください。" title_too_short: "タイトルは{{min}}文字以上必要です。" diff --git a/config/locales/client.ko.yml b/config/locales/client.ko.yml index 65fdabc0cc..8bee44e384 100644 --- a/config/locales/client.ko.yml +++ b/config/locales/client.ko.yml @@ -374,7 +374,6 @@ ko: title: "사이트 방문이 없을 경우, 새로운 글을 요약하여 메일로 보냄" daily: "매일" weekly: "매주" - every_two_weeks: "격주" email_direct: "누군가 나를 인용했을 때, 내 글에 답글을 달았을때, 혹은 내 이름을 언급했을때 이메일 보내기" email_private_messages: "누군가 나에게 개인 메시지를 보냈을때 이메일 보내기" email_always: "싸이트에 방문 중 일 때 이메일 알림을 보내지 마세요." @@ -569,9 +568,6 @@ ko: saved_local_draft_tip: "로컬로 저장됩니다." similar_topics: "작성하려는 내용과 비슷한 토픽들..." drafts_offline: "초안" - min_length: - need_more_for_title: "제목을 {{n}}글자 더 입력해주세요" - need_more_for_reply: "{{n}} to go" error: title_missing: "제목은 필수 항목입니다" title_too_short: "제목은 최소 {{min}} 글자 이상이어야 합니다." @@ -1190,12 +1186,6 @@ ko: posts: "게시물" posts_lowercase: "게시글" posts_long: "이 토픽의 게시물 수는 {{number}}개 입니다." - posts_likes_MF: | - 이 토픽의 좋아요 현황: {count, plural, one {1 post} other {# posts}} {ratio, select, - low {with a high like to post ratio} - med {with a very high like to post ratio} - high {with an extremely high like to post ratio} - other {}} original_post: "원본 게시물" views: "조회수" views_lowercase: "조회" diff --git a/config/locales/client.nb_NO.yml b/config/locales/client.nb_NO.yml index d2aafd0925..f65b5586e3 100644 --- a/config/locales/client.nb_NO.yml +++ b/config/locales/client.nb_NO.yml @@ -402,7 +402,6 @@ nb_NO: title: "Send meg sammendrag av hva som er nytt på e-post når jeg ikke er ofte innom:" daily: "daglig" weekly: "ukentlig" - every_two_weeks: "hver andre uke" email_direct: "Send meg e-post når noen siteter meg, svarer meg eller nevner mitt @brukernavn" email_private_messages: "Notta en email når noen sender deg en privat melding" email_always: "Ikke stans e-postvarsler mens jeg er aktiv på nettstedet." @@ -410,6 +409,7 @@ nb_NO: categories_settings: "Kategorier" new_topic_duration: label: "Anse emner som nye når" + not_viewed: "Jeg har ikke sett på dem enda." last_here: "opprettet siden jeg var her sist" after_n_days: one: "opprettet den siste {{count}} dagen" @@ -600,9 +600,6 @@ nb_NO: saved_local_draft_tip: "lagret lokalt" similar_topics: "Emnet ditt har likheter med..." drafts_offline: "utkast offline" - min_length: - need_more_for_title: "{{n}} igen for tittelen" - need_more_for_reply: "{{n}} gjenstår" error: title_missing: "Tittel er påkrevd" title_too_short: "Tittel må være minst {{min}} tegn" @@ -1256,12 +1253,6 @@ nb_NO: posts: "Innlegg" posts_lowercase: "innlegg" posts_long: "{{number}} innlegg i dette emnet" - posts_likes_MF: | - Dette emnet har {count, plural, one {1 post} other {# posts}} {ratio, select, - lavt {with a high like to post ratio} - medium {with a very high like to post ratio} - høyt {with an extremely high like to post ratio} - andre {}} original_post: "Originalt Innlegg" views: "Visninger" views_lowercase: "visninger" @@ -1480,6 +1471,7 @@ nb_NO: name: "Navn" add: "Legg til" add_members: "Legg til medlemmer" + custom: "Tilpasset" automatic: "Automatisk" api: generate_master: "Generer Master API-nøkkel" @@ -1499,6 +1491,7 @@ nb_NO: name: "Navn" version: "Versjon" change_settings: "Endre instillinger" + howto: "Hvordan innstallerer jeg plugins?" backups: title: "Sikkerhetskopieringer" menu: @@ -1552,7 +1545,9 @@ nb_NO: title: "Gjenopprett databasen til en tidligere fungerende tilstand" confirm: "Er du sikker på at du vil gjenopprette databasen til en tidligere fungerende tilstand?" export_csv: + user_archive_confirm: "Er du sikker på at du vil laste ned innleggene dine?" failed: "Eksporteringen feilet. Venligst undersøk loggene." + rate_limit_error: "Innlegg kan lastes ned en gang om dagen, vennligst prøv igjen i morgen." button_text: "Eksporter" button_title: user: "Eksporter full medlemsliste i CSV format." @@ -1568,6 +1563,7 @@ nb_NO: long_title: "Nettstedstilpasninger" css: "CSS" header: "Header" + top: "Topp" footer: "Footer" head_tag: text: "" @@ -1958,6 +1954,7 @@ nb_NO: none: 'intet' no_results: "Ingen treff funnet." clear_filter: "Tøm" + add_url: "legg til URL" categories: all_results: 'Alle' required: 'Påkrevd' @@ -2143,6 +2140,8 @@ nb_NO: autobiographer: name: Selvbiograf description: Fylte ut informasjon om brukerprofilen + anniversary: + name: Jubileum nice_post: name: Fint innlegg description: Fått 10 liker for et innlegg. Dette merket kan bli tildelt flere ganger diff --git a/config/locales/client.nl.yml b/config/locales/client.nl.yml index c0fdbf6133..06dcb41f7f 100644 --- a/config/locales/client.nl.yml +++ b/config/locales/client.nl.yml @@ -391,7 +391,6 @@ nl: email_digests: daily: "dagelijks" weekly: "wekelijks" - every_two_weeks: "elke twee weken" email_always: "E-mailnotificaties niet onderdrukken als ik actief ben op de site" other_settings: "Overige" categories_settings: "Categorieën" @@ -584,9 +583,6 @@ nl: saved_local_draft_tip: "lokaal opgeslagen" similar_topics: "Jouw topic lijkt op..." drafts_offline: "concepten offline" - min_length: - need_more_for_title: "Nog {{n}} tekens nodig voor de titel" - need_more_for_reply: "{{n}} te gaan" error: title_missing: "Titel is verplicht" title_too_short: "Titel moet uit minstens {{min}} tekens bestaan" @@ -1195,12 +1191,6 @@ nl: posts: "Berichten" posts_lowercase: "berichten" posts_long: "er zijn {{number}} berichten in deze topic" - posts_likes_MF: | - Dit topic heeft {count, plural, one {1 post} other {# posts}} {ratio, select, - low {met een hoge likes per post verhouding} - med {met een erg hoge likes per post verhouding} - high {met een zeer hoge likes per post verhouding} - other {}} original_post: "Originele bericht" views: "Bekeken" views_lowercase: "weergaves" diff --git a/config/locales/client.pl_PL.yml b/config/locales/client.pl_PL.yml index 1a3864460c..92b9ad2968 100644 --- a/config/locales/client.pl_PL.yml +++ b/config/locales/client.pl_PL.yml @@ -141,6 +141,7 @@ pl_PL: daily: "dziennie" weekly: "tygodniowo" every_two_weeks: "co dwa tygodnie" + every_three_days: "co trzy dni" max_of_count: "max z {{count}}" character_count: one: "1 znak" @@ -424,8 +425,9 @@ pl_PL: email_digests: title: "Gdy nie odwiedzam strony, wysyłaj e-mail z podsumowaniem aktywności:" daily: "codziennie" + every_three_days: "co trzy dni" weekly: "co tydzień" - every_two_weeks: "co 2 tygodnie" + every_two_weeks: "co dwa tygodnie" email_direct: "Wysyłaj powiadomienia gdy ktoś mnie cytuje, odpowiada na mój wpis lub wywołuje moją @nazwę" email_private_messages: "Wysyłaj powiadomienia, gdy ktoś wyśle mi prywatną wiadomość" email_always: "Wysyłaj powiadomienia email nawet gdy przejawiam aktywność na forum" @@ -486,6 +488,7 @@ pl_PL: too_short: "Hasło jest za krótkie." common: "To hasło jest zbyt popularne." same_as_username: "Twoje hasło jest takie samo jak nazwa użytkownika." + same_as_email: "Twoje hasło jest takie samo jak twój e-mail." ok: "Twoje hasło jest poprawne." instructions: "Co najmniej %{count} znaków." associated_accounts: "Powiązane konta" @@ -596,6 +599,7 @@ pl_PL: requires_invite: "Przepraszamy, dostęp do tego forum jest tylko za zaproszeniem." not_activated: "Nie możesz się jeszcze zalogować. Wysłaliśmy email aktywujący konto na adres {{sentTo}}. W celu aktywacji konta postępuj zgodnie z instrukcjami otrzymanymi w emailu." not_allowed_from_ip_address: "Nie możesz się zalogować z tego adresu IP." + admin_not_allowed_from_ip_address: "Nie możesz się zalogować jako admin z tego adresu IP." resend_activation_email: "Kliknij tutaj, aby ponownie wysłać email z aktywacją konta." sent_activation_email_again: "Wysłaliśmy do ciebie kolejny email z aktywacją konta na {{currentEmail}}. Zanim dotrze, może minąć kilka minut; pamiętaj, żeby sprawdzić folder ze spamem." google: @@ -629,9 +633,6 @@ pl_PL: saved_local_draft_tip: "zapisano lokalnie" similar_topics: "Twój temat jest podobny do…" drafts_offline: "szkice offline" - min_length: - need_more_for_title: "jeszcze co najmniej {{n}} znaków w tytule" - need_more_for_reply: "jeszcze co najmniej {{n}} znaków" error: title_missing: "tytuł jest wymagany" title_too_short: "tytuł musi zawierać co najmniej {{min}} znaków" @@ -753,6 +754,7 @@ pl_PL: close_topics: "Zamknij wpisy" archive_topics: "Zarchiwizuj tematy" notification_level: "Poziom powiadomień o zmianach" + choose_new_category: "Wybierz nową kategorię dla tematów:" selected: one: "Zaznaczono 1 temat." few: "Zaznaczono {{count}} tematy." @@ -1399,6 +1401,7 @@ pl_PL: title: "Popularne w tym tygodniu" daily: title: "Popularne dzisiaj" + all: "Od zawsze" this_year: "W tym roku" this_month: "W tym miesiącu" this_week: "W tym tygodniu" @@ -1800,6 +1803,7 @@ pl_PL: delete_topic: "usunięcie tematu" delete_post: "usunięcie wpisu" impersonate: "udawanie użytkownika" + anonymize_user: "anonimizuj użytkownika" screened_emails: title: "Ekranowane emaile" description: "Kiedy ktoś próbuje założyć nowe konto, jego adres email zostaje sprawdzony i rejestracja zostaje zablokowana, lub inna akcja jest podejmowana." @@ -1937,8 +1941,13 @@ pl_PL: approve_success: "Użytkownik zatwierdzony i został wysłany email z instrukcjami aktywacji." approve_bulk_success: "Sukces! Wszyscy wybrani użytkownicy zostali zatwierdzeni i powiadomieni." time_read: "Czas czytania" + anonymize: "Anonimizacja użytkownika" + anonymize_confirm: "Czy na pewno chcesz anonimizować to konto? Zmianie ulegnie nazwa użytkownika, e-mail oraz zawartość profilu." + anonymize_yes: "Tak, anonimizuj to konto." + anonymize_failed: "Wystąpił problem podczas anonimizacji konta." delete: "Usuń użytkownika" delete_forbidden_because_staff: "Admini i moderatorzy nie mogą zostać usunięci." + delete_posts_forbidden_because_staff: "Nie można usunąć wszystkich wpisów administratorów i moderatorów." delete_forbidden: one: "Użytkownik nie może zostać usunięty jeśli posiada wpisy. Usuń wszystkie jego wpisy przed usunięciem użytkownika. (Nie można usunąć wpisów starszych niż %{count} dzień.)" few: "Użytkownik nie może zostać usunięty jeśli posiada wpisy. Usuń wszystkie jego wpisy przed usunięciem użytkownika. (Nie można usunąć wpisów starszych niż %{count} dni.)" @@ -2048,6 +2057,7 @@ pl_PL: none: 'żadne' no_results: "Brak wyników wyszukiwania" clear_filter: "Wyczyść" + add_url: "dodaj URL" categories: all_results: 'Wszystkie' required: 'Wymagane' diff --git a/config/locales/client.pt.yml b/config/locales/client.pt.yml index 7d81418f49..c0df8d4b4e 100644 --- a/config/locales/client.pt.yml +++ b/config/locales/client.pt.yml @@ -396,7 +396,6 @@ pt: email_digests: daily: "diariamente" weekly: "semanalmente" - every_two_weeks: "a cada duas semanas" email_always: "Não suprimir notificações de email quando estou ativo no sítio" other_settings: "Outros" categories_settings: "Categorias" @@ -588,9 +587,6 @@ pt: saved_local_draft_tip: "guardado localmente" similar_topics: "O seu tópico é similar a..." drafts_offline: "rascunhos offline" - min_length: - need_more_for_title: "{{n}} para avançar para o título" - need_more_for_reply: "{{n}} para avançar" error: title_missing: "O título é obrigatório" title_too_short: "O título tem que ter pelo menos {{min}} caracteres." @@ -1237,12 +1233,6 @@ pt: posts: "Mensagens" posts_lowercase: "mensagens" posts_long: "existem {{number}} mensagens neste tópico" - posts_likes_MF: | - Este tópico tem {count, plural, one {1 mensagem} other {# mensagens}} {ratio, select, - low {com uma proporção de gostos alta} - med {com uma proporção de gostos muito alta} - high {com uma proporção de gostos extremamente alta} - other {}} original_post: "Mensagem Original" views: "Visualizações" views_lowercase: "visualizações" diff --git a/config/locales/client.pt_BR.yml b/config/locales/client.pt_BR.yml index 4d943ae401..585dfbdb20 100644 --- a/config/locales/client.pt_BR.yml +++ b/config/locales/client.pt_BR.yml @@ -147,6 +147,7 @@ pt_BR: user_count: "Novos Usuários" active_user_count: "Usuários Ativos" contact: "Contate-nos" + contact_info: "Em caso de um evento crítico ou de urgência afetando este site, por favor contacte-nos em %{contact_info}." bookmarked: title: "Favorito" clear_bookmarks: "Limpar Favoritos" @@ -401,7 +402,6 @@ pt_BR: title: "Quando eu não visitar aqui, envie um resumo via email do que há de novo:" daily: "diariamente" weekly: "semanalmente" - every_two_weeks: "duas em duas semanas" email_direct: "Me envie um email quando alguém me citar, responder ao meu post, ou mencionar meu @nomedeusuário" email_private_messages: "Me envie um email quando alguém me enviar mensagem particular" email_always: "Não suprimir notificações de email quando eu estiver ativo no site" @@ -457,6 +457,8 @@ pt_BR: title: "Senha" too_short: "A sua senha é muito curta." common: "Essa senha é muito comum." + same_as_username: "Sua senha é a mesma que o seu nome de usuário." + same_as_email: "Sua senha é a mesma que o seu email." ok: "A sua senha parece boa." instructions: "Deve ter pelo menos %{count} caracteres." associated_accounts: "Logins" @@ -567,6 +569,7 @@ pt_BR: requires_invite: "Desculpe, o acesso a este fórum é permitido somente por convite de outro membro." not_activated: "Você não pode entrar ainda. Nós lhe enviamos um email de ativação anteriormente no endereço {{sentTo}}. Por favor siga as instruções contidas neste email para ativar a sua conta." not_allowed_from_ip_address: "Você não pode logar deste endereço IP." + admin_not_allowed_from_ip_address: "Você não pode entrar como administrador a partir deste endereço IP." resend_activation_email: "Clique aqui para enviar o email de ativação novamente." sent_activation_email_again: "Nós enviamos mais um email de ativação para você no endereço {{currentEmail}}. Pode ser que demore alguns minutos para chegar; verifique sempre sua caixa de spams." google: @@ -600,9 +603,6 @@ pt_BR: saved_local_draft_tip: "salvo localmente" similar_topics: "Seu tópico é parecido com..." drafts_offline: "rascunhos offline" - min_length: - need_more_for_title: "Escreva no mínimo mais {{n}} caracteres" - need_more_for_reply: "{{n}} faltando" error: title_missing: "Título é obrigatório" title_too_short: "O título tem que ter no mínimo {{min}} caracteres" @@ -1041,6 +1041,7 @@ pt_BR: people: off_topic: "{{icons}} marcado como off-topic" spam: "{{icons}} marcado como spam" + spam_with_url: "{{icons}} marcou isto como spam" inappropriate: "{{icons}} marcado como inapropriado" notify_moderators: "{{icons}} notificaram os moderadores" notify_moderators_with_url: "{{icons}} notificaram os moderadores" @@ -1256,12 +1257,6 @@ pt_BR: posts: "Mensagens" posts_lowercase: "posts" posts_long: "há {{number}} mensagens neste tópico" - posts_likes_MF: | - Este tópico tem {count, plural, one {1 post} other {# posts}} {ratio, select, - baixo {with a high post to like ratio} - médio {with a very high post to like ratio} - alto {with an extremely high post to like ratio} - outro {}} original_post: "Resposta original" views: "Visualizações" views_lowercase: "visualizações" @@ -1338,6 +1333,7 @@ pt_BR: title: "Melhores da Semana" daily: title: "Melhores do Dia" + all: "Todo Tempo" this_year: "Neste ano" this_month: "Neste mes" this_week: "Nesta semana" @@ -1381,6 +1377,7 @@ pt_BR: backups: "backups" traffic_short: "Tráfego" traffic: "Solicitações do aplicativo pela web" + page_views: "Solicitações de API" show_traffic_report: "Mostrar Relatório de Tráfego Detalhado" reports: today: "Hoje" @@ -1558,6 +1555,7 @@ pt_BR: title: "Reverter o banco de dados para seu estado anterior" confirm: "Tem certeza de que quer reverter o banco de dados para o estado anterior?" export_csv: + user_archive_confirm: "Tem certeza que você quer baixar os seus tópicos?" success: "Exportação iniciada, você será notificado por mensagem particular quando o processo estiver completo." failed: "Falha na exportação. Por favor verifique os logs." rate_limit_error: "O download de posts pode ser feito apenas uma vez por dia, por favor, tente novamente amanhã." @@ -1568,6 +1566,9 @@ pt_BR: screened_email: "Exportar lista completa de emails filtrados em formato CSV." screened_ip: "Exportar lista completa de IPs filtrados em formato CSV." screened_url: "Exportar lista completa de URLs filtradas em formato CSV." + invite: + button_text: "Enviar Convites" + button_title: "Enviar Convites" customize: title: "Personalizar" long_title: "Personalizações do Site" @@ -1969,6 +1970,7 @@ pt_BR: none: 'nenhum' no_results: "Nenhum resultado encontrado." clear_filter: "Limpar" + add_url: "adicionar URL" categories: all_results: 'Todas' required: 'Requerido' @@ -2008,6 +2010,7 @@ pt_BR: delete: Remover delete_confirm: Tem certeza de que deseja remover este emblema? revoke: Revogar + reason: Motivo revoke_confirm: Tem certeza de que deseja revogar este emblema? edit_badges: Editar Emblemas grant_badge: Conceder Emblema @@ -2158,6 +2161,8 @@ pt_BR: autobiographer: name: Autobiógrafo description: Preencher informações do perfil + anniversary: + description: Membro ativo por um ano, postou ao menos uma vez nice_post: name: Post Legal description: Recebeu 10 curtidas em uma resposta. Esse emblema pode ser concedido várias vezes. diff --git a/config/locales/client.ru.yml b/config/locales/client.ru.yml index 93168e9093..042a865c94 100644 --- a/config/locales/client.ru.yml +++ b/config/locales/client.ru.yml @@ -141,6 +141,7 @@ ru: daily: "ежедневно" weekly: "еженедельно" every_two_weeks: "каждые две недели" + every_three_days: "каждые 3 дня" max_of_count: "{{count}} макс." character_count: one: "{{count}} буква" @@ -384,6 +385,7 @@ ru: authenticated: "Ваш адрес электронной почты подтвержден {{provider}}" frequency: zero: "Получать уведомления о новых непрочитанных сообщениях незамедлительно." + one: "Мы отправим вам письмо только если не видели вас онлайн в последние несколько минут." name: title: "Имя" instructions: "Ваше полное имя (опционально)" @@ -421,8 +423,9 @@ ru: email_digests: title: "В случае моего отсутствия на форуме присылайте мне сводку новостей по почте:" daily: "ежедневно" + every_three_days: "каждые 3 дня" weekly: "еженедельно" - every_two_weeks: "каждые две недели" + every_two_weeks: "каждые 2 недели" email_direct: "Присылать почтовое уведомление, когда кто-то цитирует меня, отвечает на мой пост или упоминает мой @псевдоним" email_private_messages: "Присылать почтовое уведомление, когда кто-то оставляет мне личное сообщение" email_always: "Отправлять оповещения по e-mail даже когда я нахожусь на сайте." @@ -482,6 +485,8 @@ ru: title: "Пароль" too_short: "Пароль слишком короткий." common: "Пароль слишком короткий." + same_as_username: "Ваш пароль такой же, как и ваше имя пользователя." + same_as_email: "Ваш пароль такой же, как и ваш email." ok: "Допустимый пароль." instructions: "Не менее %{count} символов." associated_accounts: "Связанные аккаунты" @@ -592,6 +597,7 @@ ru: requires_invite: "К сожалению, доступ к этому форуму только по приглашениям." not_activated: "Прежде, чем вы сможете войти на форум, вам необходимо активировать свою учетную запись. Мы отправили на почту {{sentTo}} подробные инструкции, как это cделать." not_allowed_from_ip_address: "С этого IP адреса вход запрещен." + admin_not_allowed_from_ip_address: "Вы не можете войти в качестве админа с этого IP адреса." resend_activation_email: "Щелкните здесь, чтобы мы повторно выслали вам письмо для активации учетной записи." sent_activation_email_again: "По адресу {{currentEmail}} повторно отправлено письмо с инструкциями по активации вашей учетной записи. Доставка сообщения может занять несколько минут. Имейте в виду, что иногда по ошибке письмо может попасть в папку Спам." google: @@ -625,9 +631,6 @@ ru: saved_local_draft_tip: "сохранено локально" similar_topics: "Ваша тема похожа на..." drafts_offline: "Сохраненные черновики" - min_length: - need_more_for_title: "для заголовка необходимо еще {{n}} символов" - need_more_for_reply: "Нужно еще символов: {{n}}" error: title_missing: "Требуется заголовок" title_too_short: "Заголовок должен быть не менее {{min}} символов" @@ -1316,12 +1319,6 @@ ru: posts: "Сообщ." posts_lowercase: "сообщения" posts_long: "{{number}} сообщений в теме" - posts_likes_MF: | - В этой теме {count, plural, one {1 сообщение} few {# сообщения} other {# сообщений}} {ratio, select, - low {с высоким рейтингом симпатий} - med {с очень высоким рейтингом симпатий} - high {с чрезвычайно высоким рейтингом симпатий} - other {}} original_post: "Начальное сообщение" views: "Просм." views_lowercase: "просм." @@ -1398,6 +1395,7 @@ ru: title: "Обсуждаемые за неделю" daily: title: "Обсуждаемые за день" + all: "За всё время" this_year: "За год" this_month: "За месяц" this_week: "За неделю" @@ -1441,6 +1439,8 @@ ru: backups: "резервные копии" traffic_short: "Трафик" traffic: "Трафик" + page_views: "Запросы API" + page_views_short: "Запросы API" show_traffic_report: "Раширенный отчет" reports: today: "Сегодня" @@ -2042,6 +2042,7 @@ ru: none: '(нет)' no_results: "Ничего не найдено." clear_filter: "Очистить" + add_url: "добавить URL" categories: all_results: 'Всего' required: 'Обязательные' @@ -2081,6 +2082,8 @@ ru: delete: Удалить delete_confirm: Вы уверены, что хотите удалить эту награду? revoke: Отозвать + reason: Причина + expand: Развернуть … revoke_confirm: Вы уверены, что хотите отозвать эту награду? edit_badges: Редактировать награды grant_badge: Выдать награду @@ -2167,6 +2170,7 @@ ru: dismiss_topics: 'x, t Отложить темы' actions: title: 'Действия' + bookmark_topic: 'f Добавить в Избранное' pin_unpin_topic: 'shift+p Закрепить/Открепить тему' share_topic: 'shift+s Поделиться темой' share_post: 's Поделиться сообщением' diff --git a/config/locales/client.sq.yml b/config/locales/client.sq.yml index 3877735299..6c6b1732e3 100644 --- a/config/locales/client.sq.yml +++ b/config/locales/client.sq.yml @@ -357,7 +357,6 @@ sq: email_digests: daily: "ditore" weekly: "javore" - every_two_weeks: "çdo dy javë" email_always: "Do not suppress email notifications when I am active on the site" other_settings: "Tjetër" categories_settings: "Kategoritë" @@ -540,9 +539,6 @@ sq: saved_local_draft_tip: "saved locally" similar_topics: "Your topic is similar to..." drafts_offline: "drafts offline" - min_length: - need_more_for_title: "{{n}} to go for the title" - need_more_for_reply: "{{n}} shko tek" error: title_missing: "Title is required" title_too_short: "Title must be at least {{min}} characters" @@ -1183,12 +1179,6 @@ sq: posts: "Postime" posts_lowercase: "postime" posts_long: "there are {{number}} posts in this topic" - posts_likes_MF: | - This topic has {count, plural, one {1 post} other {# posts}} {ratio, select, - low {with a high like to post ratio} - med {with a very high like to post ratio} - high {with an extremely high like to post ratio} - other {}} original_post: "Postimi Origjinal" views: "Shikimet" views_lowercase: "shikime" diff --git a/config/locales/client.sv.yml b/config/locales/client.sv.yml index 257dc1f71a..e6d801e21b 100644 --- a/config/locales/client.sv.yml +++ b/config/locales/client.sv.yml @@ -391,7 +391,6 @@ sv: email_digests: daily: "dagligen" weekly: "veckovis" - every_two_weeks: "varannan vecka" email_direct: "Skicka ett e-postmeddelande när någon citerar mig, svarar på mitt inlägg, eller nämner mitt @användarnamn" email_private_messages: "Skicka ett e-postmeddelande till mig när någon skickar mig ett privatmeddelande." email_always: "Ta emot notifieringar via mail även om jag är aktiv på forumet" @@ -586,9 +585,6 @@ sv: saved_local_draft_tip: "sparat lokalt" similar_topics: "Din tråd liknar..." drafts_offline: "utkast offline" - min_length: - need_more_for_title: "{{n}} tecken kvar för titeln" - need_more_for_reply: "{{n}} fler..." error: title_missing: "Du måste ange en rubrik" title_too_short: "Titeln måste vara minst {{min}} tecken lång." @@ -1234,12 +1230,6 @@ sv: posts: "Inlägg" posts_lowercase: "inlägg" posts_long: "{{number}} inlägg i den här tråden" - posts_likes_MF: | - Det här ämnet har {count, plural, en {1 post} annan {# posts}} {ratio, välj, - låg {med en hög gilla mot inlägg ratio} - medel {med en väldigt hög gilla mot inlägg ratio} - hög {med en extremt hög gilla mot inlägg ratio} - annan {}} original_post: "Originalinlägg" views: "Visningar" views_lowercase: "visningar" diff --git a/config/locales/client.te.yml b/config/locales/client.te.yml index b134c08ca4..a2df67b7ca 100644 --- a/config/locales/client.te.yml +++ b/config/locales/client.te.yml @@ -125,6 +125,7 @@ te: daily: "ప్రతిరోజూ" weekly: "ప్రతీవారం" every_two_weeks: "రెండువారాలకోసారి" + every_three_days: "ప్రతి మూడు రోజులకీ" max_of_count: "{{count}} గరిష్టం" character_count: one: "{{count}} అక్షరం" @@ -401,8 +402,9 @@ te: email_digests: title: "నేను ఇక్కడికి రాకపోతే, కొత్త విషయాలు నాకు ఈమెయిల్ గా పంపండి:" daily: "ప్రతీరోజు" + every_three_days: "ప్రతి మూడు రోజులకీ" weekly: "ప్రతీవారం" - every_two_weeks: "ప్రతీ రెండు వారాలకు" + every_two_weeks: "ప్రతి రెండు వారాలకీ" email_direct: "ఎవరన్నా నన్ను కోట్ చేసినా, నా టపాలకు జవాబిచ్చినా, నా @పేరు ప్రస్తావిస్తే నాకు ఈమెయిల్ పంపండి" email_private_messages: "ఎవరన్నా ప్రైవేటు సందేశం పంపితే నాకు ఈమెయిల్ పంపండి." email_always: "నేను ఈసైటుపై క్రియాశీలంగా ఉన్నా నాకు ఈమెయిల్ పంపుట ఆపవద్దు" @@ -459,6 +461,7 @@ te: too_short: "మీ సంకేతపదం మరీ చిన్నది." common: "ఆ సంకేతపదం మరీ సాధారణం." same_as_username: "మీ సంకేతపదం మీ వినియోగదారుపేరు ని పోలి ఉంది." + same_as_email: "మీ సంకేతపదం మీ ఈమెయిల్ ను పోలి ఉంది." ok: "మీ సంకేతపదం బాగుంది." instructions: "కనీసం %{count} అక్షరాలు ఉండాలి." associated_accounts: "లాగిన్లు" @@ -569,6 +572,7 @@ te: requires_invite: "క్షమించాలి. ఈ పోరమ్ ప్రవేశం కేవలం ఆహ్వానితులకు మాత్రమే." not_activated: "మీరప్పుడే లాగిన్ అవ్వలేరు. గతంలో మేము మీకు చేతన ఈమెయల్ {{sentTo}} కు పంపాము. దయచేసి ఆ వేగులోని సూచనలు పాటించి మీ ఖాతాను చేతనం చేసుకోండి." not_allowed_from_ip_address: "ఆ ఐపీ చిరునామా నుండి మీరు లాగిన్ అవ్వలేరు." + admin_not_allowed_from_ip_address: "మీరు ఆ IP చిరునామా నుండి నిర్వాహకుని వలె లాగిన్ కాలేరు." resend_activation_email: "చేతన ఈమెయిల్ మరలా పంపడానికి ఇక్కడ నొక్కండి." sent_activation_email_again: "మీకు {{currentEmail}} మరో చేతన ఈమెయిల్ పంపాము. అది చేరుకోడానికి కొద్ది నిమిషాలు పట్టవచ్చు. ఇంకా స్పామ్ ఫోల్డరు చూడటం మర్చిపోకండి సుమా. " google: @@ -602,9 +606,6 @@ te: saved_local_draft_tip: "స్థానికంగా భద్రం" similar_topics: "మీ విషయం దీని వలె ఉంది..." drafts_offline: "చిత్తుప్రతులు ఆఫ్లైను." - min_length: - need_more_for_title: "శీర్షికకు ఇంకా {{n}} కావాలి" - need_more_for_reply: "{{n}} కావాలి" error: title_missing: "శీర్షిక తప్పనిసరి" title_too_short: "శీర్షిక కనీసం {{min}} అక్షరాలు ఉండాలి" @@ -726,6 +727,7 @@ te: close_topics: "విషయాలు మూయు" archive_topics: "విషయాలు కట్టకట్టు" notification_level: "ప్రకటన స్థాయి మార్చు" + choose_new_category: "విషయం కొరకు కొత్త వర్గం ఎంచుకొండి:" selected: one: "మీరు 1 విషయం ఎంచుకున్నారు." other: " మీరు {{count}} విషయాలు ఎంచుకున్నారు." @@ -1208,6 +1210,7 @@ te: take_action: "చర్య తీసుకో" notify_action: 'ప్రైవేటు సందేశం' delete_spammer: "స్పామరును తొలగించు" + delete_confirm: "మీరు ఈ వినియోగదారుని %{టపాలు} టపాలు మరియు %{విషయాలు} విషయాలు తొలగించబోతున్నారు, వారి ఖాతా తొలగించి,వారి IP అడ్రస్ నుండి సైన్‌అప్‌లు మూసివేయండి%{ip_అడ్రస్}, మరియు శాశ్వత మూసివేత జాబితాకి వారి ఈ-మెయిల్ అడ్రస్ %{ఈ-మెయిల్} ని కలపండి.మీరు నిజంగా ఈ వినియోగదారుని స్పామర్ గా భావిస్తున్నారా ?" yes_delete_spammer: "అవులు, స్పామరును తొలగించు" ip_address_missing: "వర్తించదు" hidden_email_address: "(దాయబడింది)" @@ -1333,11 +1336,13 @@ te: title: "వారంలోని అగ్ర" daily: title: "రోజులోని అగ్ర" + all: "మొత్తం సమయం" this_year: "ఈ సంవత్సరం" this_month: "ఈ నెల" this_week: "ఈ వారం" today: "ఈ రోజు" other_periods: "మరిన్ని అగ్ర విషయాలు చూడు" + browser_update: 'దురదృష్టవశాత్తు, ఈ సైట్ లో పనిచేయడానికి మీ బ్రౌజర్ చాలా పాతది . దయచేసి మీ బ్రౌజర్ ని నవీకరించండి.' permission_types: full: "సృష్టించి / జవాబివ్వు / చూడు" create_post: "జవాబివ్వు / చూడు" @@ -1477,6 +1482,7 @@ te: add_members: "సభ్యులను కలుపు" custom: "అనురూప" automatic: "స్వీయంగా" + automatic_membership_email_domains: "వినియోగదారుడు ఏ ఈ-మెయిల్ డొమైన్ తో నమోదు చేసుకున్నాడో అది ఖచ్చితంగా ఈ జాబితాలో ఒక దానిని పోలి స్వయంసిధ్ధంగా గ్రూప్ కి కలుస్తాయి:" automatic_membership_retroactive: "ఇప్పటికే నమోదిత వినియోగదారులను జోడించడానికి అదే ఇమెయిల్ డొమైన్ రూల్ వర్తిస్తుంది" api: generate_master: "మాస్టరు ఏపీఐ కీ ఉత్తపత్తించు" @@ -1650,6 +1656,7 @@ te: all: "అన్నీ" sending_test: "పరీక్షా ఈమెయిల్ పంపుతున్నామ్..." error: "దోషం - %{server_error}" + test_error: "టెస్ట్ మెయిల్ పంపడంలో ఒక సమస్య ఉంది.దయచేసి మీ మెయిల్ సెట్టింగ్స్ రెండోసారి తనిఖీ చేసి,మీ హోస్ట్ మెయిల్ కనెక్షన్ నిరోధించుటలేదని నిర్ధారించుకోండి, మరియు తిరిగి ప్రయత్నించండి." sent: "పంపిన" skipped: "వదిలిన" sent_at: "వద్ద పంపారు" @@ -1738,6 +1745,7 @@ te: domain: "డొమైన్" screened_ips: title: "స్క్రీన్ చేసిన ఐపీలు" + description: 'IP చిరునామాలు చూస్తారు.IP చిరునామాల "అనుమతి"లో మంచివరుస పాటించండి.' delete_confirm: "మీరు నిజంగా %{ip_address} కు ఈ నియమాన్ని తొలగించాలనుకుంటున్నారా? " rolled_up_some_subnets: "IP నిషేధిత ప్రవేశాలు ఈ సబ్‌నెట్స్‌కు విజయవంతంగా చేర్చారు: %{subnets}." rolled_up_no_subnet: "రోల్ అప్ చేయుటకు ఏమీ లేదు." @@ -1757,6 +1765,7 @@ te: title: "దోష లాగులు" impersonate: title: "పరకాయప్రవేశించు" + help: "అనుకరించిన వినియోగదారుని ఖాతా దోషవిశ్లేషణ ప్రయోజనాలకు ఈ ఉపకరణం వినియోగించండి.పూర్తి అయిన తర్వాత మీరు లాగవుట్ చేయండి." users: title: 'సభ్యులు' create: 'అధికారి సభ్యుడిని కలుపు' @@ -1809,9 +1818,11 @@ te: unsuspend_failed: "ఈ వినియోగదారు వలన ఏదో తొలగింపబడని తప్పు జరిగింది {{దోషం}}" suspend_duration: "వినియోగదారు ఎంతకాలం నిలిపివేయబడ్డాడు?" suspend_duration_units: "(రోజులు)" + suspend_reason_label: "మీరు ఎందుకు తొలగించబడ్డారు? ఈ పాఠ్యం వినియోగదారును ప్రొఫైల్ పుట మీద ప్రతివారికి కనబడుతుంది, మరియు వినియోగదారుడు లాగిన్‌కు ప్రయత్నించినపుడు చూస్తారు.చిన్నదిగా ఉంచండి." suspend_reason: "కారణం" suspended_by: "సస్పెండు చేసినవారు" delete_all_posts: "అన్ని టపాలూ తొలగించు" + delete_all_posts_confirm: "మీరు తొలగించబడిన %{టపాలు} టపాలు మరియు %{విషయాలు} విషయాలు గురించి మాట్లాడుతున్నారు. ఖచ్చితమా ?" suspend: "సస్పెండు" unsuspend: "సస్పెండు తొలగించు" suspended: "సస్పెండయ్యాడా? " @@ -1827,6 +1838,7 @@ te: impersonate: 'పరకాయప్రవేశం చేయి' ip_lookup: "ఐపీ లుకప్" log_out: "లాగవుట్" + logged_out: "వినియోగదారుడు అన్ని పరికరాలు లాగవుట్ చేశారు" revoke_admin: 'నిర్వాహకులు తొలగించారు' grant_admin: 'నిర్వాహకులు సమ్మతించారు' revoke_moderation: 'సమన్వయం నిలిపివేశారు' @@ -1853,10 +1865,12 @@ te: time_read: "చదువు సమయం" delete: "సభ్యుడిని తొలగించు" delete_forbidden_because_staff: "అధికారులు మరియు నిర్వాహకులను తొలగించలేరు" + delete_posts_forbidden_because_staff: "నిర్వాహకుల మరియు పరిశీలకుల అన్ని టపాలు తొలగించలేము." delete_confirm: "మీరు నిజంగా ఈ వినియోగదారుని తొలగిద్దాం అనుకుంటున్నారా ? ఇది శాశ్వతం!" delete_and_block: "ఈ ఈ-మెయిల్ మరియు IP అడ్రస్ ను తొలగించండి మరియు నిరోధించండి" delete_dont_block: "తొలగింపు మాత్రమే" deleted: "ఈ సభ్యుడు తొలగించబడ్డాడు" + delete_failed: "వినియోగదారుని తొలగించుటలో ఒక దోషం ఉంది.వినియోగదారుని తొలగించడానికి ప్రయత్నించకముందే టపాలు అన్ని తొలగించండి." send_activation_email: "చేతన ఈమెయిల్ పంపు" activation_email_sent: "ఒక చేతన ఈమెయిల్ పంపాము." send_activation_email_failed: "చేతన ఈమెయిల్ పంపుటలో దోషం %{error}" @@ -1875,6 +1889,10 @@ te: suspend_modal_title: "సభ్యుడిని సస్పెండు చేయి" trust_level_2_users: "నమ్మకం స్థాయి 2 సభ్యులు" trust_level_3_requirements: "నమ్మకపు స్థాయి 3 అవసరాలు" + trust_level_locked_tip: "నమ్మకపు స్థాయి బంధింపబడిఉంది, వ్యవస్థ వినియోగదారుని ప్రోత్సాహించలేదు లేదా స్థాయి తగ్గించలేదు" + trust_level_unlocked_tip: "నమ్మకపు స్థాయి బంధింపబడలేదు, వ్యవస్థ వినియోగదారుని ప్రోత్సాహించవచ్చు లేదా స్థాయి తగ్గించవచ్చు" + lock_trust_level: "నమ్మకపు స్థాయి ని బంధించు" + unlock_trust_level: "నమ్మకపు స్థాయిని వదిలేయి" tl3_requirements: title: "నమ్మకపు స్థాయి 3 అవసరాలు" table_title: "గత 100 రోజుల్లో:" @@ -1882,6 +1900,7 @@ te: requirement_heading: "అవసరం" visits: "సందర్శనాలు" days: "రోజులు" + topics_replied_to: "విషయాలు సమాధానంగా" topics_viewed: "చూసిన విషయాలు " topics_viewed_all_time: "చూసిన విషయాలు (అన్ని వేళలా)" posts_read: "చదివిన టపాలు" @@ -1892,7 +1911,15 @@ te: likes_received: "అందుకున్న ఇష్టాలు" likes_received_days: "స్వీకరించిన ఇష్టాలు:ప్రత్యేకమైన రోజులు" likes_received_users: "స్వీకరించిన ఇష్టాలు:ప్రత్యేకమైన వినియోగదారులు" + qualifies: "నమ్మకపు స్థాయి 3 కు అర్హత ." + does_not_qualify: "నమ్మకపు స్థాయి 3 కు అర్హత లేదు." + will_be_promoted: "త్వరలో స్థాయి పెరుగును." + will_be_demoted: "త్వరలో స్థాయి తగ్గును." + on_grace_period: "ప్రస్తుతం స్థాయి పెరుగుదల అదనపుకాలంలో ఉంది, స్థాయి తగ్గింపు జరగదు." + locked_will_not_be_promoted: "నమ్మకపు స్థాయి బంధించబడి ఉంది. స్థాయి పెరుగుదల ఉండదు." + locked_will_not_be_demoted: "నమ్మకపు స్థాయి బంధించబడి ఉంది.ఎప్పటికీ స్థానాన్ని తగ్గించలేరు." sso: + title: "ఒక సైన్ ఆన్" external_id: "బాహ్య ఐడీ" external_username: "సభ్యనామం" external_name: "పేరు" @@ -1900,6 +1927,7 @@ te: external_avatar_url: "ప్రవర బొమ్మ యూఆర్ యల్" user_fields: title: "సభ్య క్షేత్రాలు" + help: "వినియోగదారులు పూర్తి చేసిన వాటిని జోడించండి." create: "సభ్య క్షేత్రం సృష్టించు" untitled: "పేరులేని" name: "క్షేత్రం పేరు" @@ -1911,9 +1939,11 @@ te: cancel: "రద్దు" delete_confirm: "మీరు నిజంగా ఈ సభ్య క్షేత్రం తొలగించాలనుకుంటున్నారా?" required: + title: "సైన్అప్ అవసరమా?" enabled: "కావాలి" disabled: "అవసరంలేదు" editable: + title: "సైన్అప్ తరువాత సవరించగలమా?" enabled: "సవరించదగిన" disabled: "సవరించలేని" show_on_profile: @@ -1922,14 +1952,18 @@ te: disabled: "ప్రవరపై చూపబడలేదు" field_types: text: 'పాఠ్య క్షేత్రం' + confirm: 'ఖాయము' site_text: + none: "సవరణను ప్రారంభించడానికి విషయం రకాన్ని ఎంచుకోండి." title: 'పాఠ్య కాంటెంటు' site_settings: + show_overriden: 'ప్రాబల్యం ఉన్న వాటిని మాత్రమే చూపించు' title: 'అమరికలు' reset: 'రీసెట్' none: 'ఏదీకాదు' no_results: "ఏ ఫలితాలూ కనిపించలేదు." clear_filter: "శుభ్రపరుచు" + add_url: "URL కలుపు" categories: all_results: 'అన్నీ' required: 'కావాలి' @@ -1945,6 +1979,7 @@ te: spam: 'స్పాము' rate_limits: 'రోట్ హద్దులు' developer: 'డవలపరు' + embedding: "దేనిలోనైనా ఒదుగు" legal: "న్యాయ" uncategorized: 'ఇతర' backups: "బ్యాకప్పులు" @@ -1964,6 +1999,7 @@ te: modal_title: బ్యాడ్జ్ గ్రూపులు granted_by: ఇచ్చిన వారు granted_at: ఇచ్చిన సమయం + reason_help: (టపాకి లేదా విషయానికి లంకె ) save: దాచు delete: తొలగించు delete_confirm: మీరు నిజంగా ఈ బ్యాడ్జి తొలగించాలనుకుంటున్నారా? @@ -1974,24 +2010,44 @@ te: grant_badge: బ్యాడ్జి ఇవ్వు granted_badges: ఇచ్చిన బ్యాడ్జీలు grant: ఇవ్వు + no_user_badges: "%{పేరు} ఏ చిహ్నాలు మంజూరు చేయలేదు." + no_badges: మంజూరు చేసే చిహ్నాలు లేవు. none_selected: "ఆరంభించడానికి ఒక బ్యాడ్జీని ఎంచుకోండి." + allow_title: చిహ్నాన్ని శీర్షికగా వాడుకోవడానికి అనుమతి ఇవ్వండి. + multiple_grant: అనేకసార్లు మంజూరు చేయవచ్చు + listable: బహిరంగ చిహ్నాల పుటలో చూపండి enabled: బ్యాడ్జి చేతనం చేయి icon: ఐకాన్ image: బొమ్మ + icon_help: "చిత్రానికి బ్రహ్మాండమైన ఫాంట్ లేదా URL గాని ఉపయోగించండి" + target_posts: టపాలు లక్ష్యంగా ప్రశ్న + show_posts: చిహ్నాల పుటలో మంజూరు అయిన చిహ్నాన్ని చూపండి trigger: ట్రిగ్గరు trigger_type: none: "రోజు ఉన్నతీకరించు" + post_action: "వినియోగదారుడు టపాపై పనిచేసినపుడు" + post_revision: "వినియోగదారుడు టపా సృష్టిస్తున్నప్పుడు లేదా సవరిస్తున్నప్పుడు" + trust_level_change: "వినియోగదారుడు నమ్మకపుస్థాయి మార్చినప్పుడు" + user_change: "వినియోగదారుడు సవరిస్తున్నపుడు లేదా సృష్టిస్తున్నపుడు" preview: + sql_error_header: "ప్రశ్నతో దోషం ఉంది." bad_count_warning: header: "హెచ్చరిక!" + grant_count: + zero: "ఏ చిహ్నాలు కేటాయించలేదు." + one: "1 కేటాయించిన చిహ్నం." + other: "%{లెక్క} కేటాయించిన చిహ్నాలు." sample: "శాంపిలు:" grant: + with: %{వినియోగదారు పేరు} + with_post: %{వినియోగదారు పేరు} టపా కొరకు%{లంకె} with_post_time: %{username} for post in %{link} at %{time} emoji: title: "ఇమోజి" add: "కొత్త ఇమోజి కలుపు" name: "పేరు" image: "బొమ్మ" + delete_confirm: "మీరు నిజంగా %{పేరు}: ఎమోజీ ని తొలగించాలనుకుంటున్నారా ?" lightbox: download: "దిగుమతించు" search_help: @@ -2000,26 +2056,35 @@ te: title: 'కీబోర్డు షార్ట్ కట్లు' jump_to: title: 'వెళ్లు' + home: 'g, h హోమ్ (తాజా)' latest: 'g, l తాజా' new: 'g, n కొత్త' unread: 'g, u చదవనవి' categories: 'g, c వర్గాలు' + top: 'g, t పైన' navigation: title: 'నావిగేషను' jump: '# టపాకు వెళ్లు #' back: 'u వెనుకకు' open: 'o or ప్రవేశం ఎంచుకున్న విషయం తెరువు' + next_prev: 'మార్పు+j/మార్పు+k తర్వాతి/ముందరి విభాగం' application: title: 'అనువర్తనం' create: 'c కొత్త టపా సృష్టించు' notifications: 'n తెరచిన ప్రకటనలు' site_map_menu: '= సైట్ మెనూ తెరువు' user_profile_menu: 'p యూజర్ మెనూ తెరువు' + show_incoming_updated_topics: '. నవీకరించిన విషయాలను చూపించండి' search: '/ వెతుకు' + help: '? కీ బోర్డ్ సహాయాన్ని తెరువు' + dismiss_new_posts: 'x, r తీసివేసిన కొత్త/టపాలు' + dismiss_topics: 'x, t తీసివేసిన విషయాలు' actions: title: 'చర్యలు' + pin_unpin_topic: 'shift+p విషయం చేర్చు/విడదీయు' share_topic: 'shift+s విషయం పంచు' share_post: 's టపా పంచు' + reply_as_new_topic: 't లంకె విషయంగా సమాధానం' reply_topic: 'shift+r టపా కి సమాధానం' reply_post: 'r టపా కి సమాధానం' like: 'l టపా ని ఇష్టపడు' @@ -2027,10 +2092,21 @@ te: bookmark: 'bటపా పేజీక' edit: 'e టపా సవరణ' delete: 'd టపా తొలగించు' + mark_muted: 'm, m విషయాన్ని ఆపివేయండి' + mark_regular: 'm, r నిత్య (అప్రమేయ) విషయం' + mark_tracking: 'm, t విషయం వెతుకు' + mark_watching: 'm, w చూసిన విషయం' badges: title: బ్యాడ్జీలు allow_title: "శీర్షికగా కూడా వాడవచ్చు" multiple_grant: "పలుమార్లు బహూకరించవచ్చు" + more_badges: + one: "+%{count} కంటే" + other: "+%{count} ఇంకా" + granted: + one: "1 మంజూరు" + other: "%{లెక్క} మంజూరు" + select_badge_for_title: మీ శీర్షికగా ఉపయోగించడానికి ఒక చిహ్నాన్ని ఎంపిక చేయండి. none: "" badge_grouping: getting_started: @@ -2049,8 +2125,10 @@ te: description: తొలి టపా సవరణ basic_user: name: ప్రాథమిక + description: మంజూరు చేసిన అన్ని ఆవశ్యక సామాజిక చర్యలు member: name: సభ్యుడు + description: మంజూరు చేసిన ఆహ్వానాలు regular: name: రెగ్యులరు leader: @@ -2060,20 +2138,28 @@ te: description: ఒక ఇష్టాన్ని అందుకున్నారు autobiographer: name: ఆత్మకధావాది + description: వినియోగదారు నింపిన ఫ్రొపైల్ సమాచారం anniversary: name: వార్షికోత్సవం + description: ఒక సంవత్సరం నుండి చురుకైన సభ్యుడు, కనీసం ఒకసారి టపా చేశాడు nice_post: name: మంచి టపా + description: ఒక టపా 10 ఇష్టాలు స్వీకరిస్తే , ఈ చిహ్నం అనేక సార్లు మంజూరు అవుతుంది good_post: name: చాలా మంచి టపా + description: ఒక టపా 25 ఇష్టాలు స్వీకరిస్తే , ఈ చిహ్నం అనేక సార్లు మంజూరు అవుతుంది great_post: name: బహుమంచి టపా + description: ఒక టపా 50 ఇష్టాలు స్వీకరిస్తే , ఈ చిహ్నం అనేక సార్లు మంజూరు అవుతుంది nice_topic: name: మంచి విషయం + description: ఒక విషయం 10 ఇష్టాలు స్వీకరిస్తే , ఈ చిహ్నం అనేక సార్లు మంజూరు అవుతుంది good_topic: name: చాలా మంచి విషయం + description: ఒక విషయం 25 ఇష్టాలు స్వీకరిస్తే , ఈ చిహ్నం అనేక సార్లు మంజూరు అవుతుంది great_topic: name: బహుమంచి విషయం + description: ఒక విషయం 50 ఇష్టాలు స్వీకరిస్తే , ఈ చిహ్నం అనేక సార్లు మంజూరు అవుతుంది nice_share: name: మంచి పంపకం description: ఒక టపాను 25మంది సభ్యులతో పంచుకున్నారు diff --git a/config/locales/client.tr_TR.yml b/config/locales/client.tr_TR.yml index 82ee1e53cd..1dde0885ec 100644 --- a/config/locales/client.tr_TR.yml +++ b/config/locales/client.tr_TR.yml @@ -109,6 +109,7 @@ tr_TR: daily: "günlük" weekly: "haftalık" every_two_weeks: "her iki haftada bir" + every_three_days: "her üç gün" max_of_count: "azami {{count}}" character_count: other: "{{count}} karakter" @@ -378,8 +379,9 @@ tr_TR: email_digests: title: "Burayı ziyaret etmediğim zamanlarda bana yeni şeylerin özetini içeren bir email yolla:" daily: "günlük" + every_three_days: "her üç gün" weekly: "haftalık" - every_two_weeks: "her iki haftada bir" + every_two_weeks: "her iki hafta" email_direct: "Birisi gönderime cevap verdiğinde, benden alıntı yaptığında ya da benden @username bahsettiğinde bana bir email at" email_private_messages: "Biri bana özel mesaj yazdığında bana bir email at" email_always: "Sayfada etkin olduğum anlarda da e-posta bildirimleri yollamaya devam et" @@ -432,6 +434,7 @@ tr_TR: too_short: "Parolanız çok kısa." common: "Bu parola çok yaygın." same_as_username: "Şifreniz kullanıcı adınızla aynı." + same_as_email: "Şifreniz e-posta adresinizle aynı." ok: "Parolanız uygun gözüküyor." instructions: "En az %{count} karakter." associated_accounts: "Girişler" @@ -542,6 +545,7 @@ tr_TR: requires_invite: "Üzgünüz, bu foruma sadece davetliler erişebilir." not_activated: "Henüz giriş yapamazsınız. Hesabınızı etkinleştirmek için lütfen daha önceden {{sentTo}} adresine yollanan etkinleştirme e-postasındaki açıklamaları okuyun." not_allowed_from_ip_address: "Bu IP adresiyle giriş yapamazsınız." + admin_not_allowed_from_ip_address: "Bu IP adresinden admin olarak giriş yapamazsınız." resend_activation_email: "Etkinleştirme e-postasını tekrar yollamak için buraya tıklayın. " sent_activation_email_again: "{{currentEmail}} adresine yeni bir etkinleştirme e-postası yolladık. Bu e-postanın size ulaşması bir kaç dakika sürebilir; spam klasörüzü kontrol etmeyi unutmayın." google: @@ -575,9 +579,6 @@ tr_TR: saved_local_draft_tip: "yerele kaydedildi" similar_topics: "Konunuz bu konuya benziyor..." drafts_offline: "çevrimdışı taslaklar" - min_length: - need_more_for_title: "başlığa gitmek için {{n}}" - need_more_for_reply: "{{n}} adet kaldı" error: title_missing: "Başlık gerekli" title_too_short: "Başlık en az {{min}} karakter olmalı" @@ -699,6 +700,7 @@ tr_TR: close_topics: "Konuları Kapat" archive_topics: "Konuları Arşivle" notification_level: "Bildirim Seviyesini Değiştir" + choose_new_category: "Konular için yeni bir kategori seçin:" selected: other: "{{count}} konu seçtiniz." none: @@ -1197,12 +1199,6 @@ tr_TR: posts: "Gönderi" posts_lowercase: "gönderi" posts_long: "bu konuda {{number}} gönderi var" - posts_likes_MF: | - Bu konuda {ratio, select, - low {beğeni/gönderi oranı yüksek} - med {beğeni/gönderi oranı çok yüksek} - high {beğeni/gönderi oranı aşırı yüksek} - other {}} {count, plural, one {1 gönderi} other {# gönderi}} var original_post: "Ana Gönderi" views: "Görüntüleme" views_lowercase: "görüntüleme" @@ -1279,6 +1275,7 @@ tr_TR: title: "Haftanın En Popülerleri" daily: title: "Günün En Popülerleri" + all: "Tüm Zamanlar" this_year: "Bu yıl" this_month: "Bu ay" this_week: "Bu hafta" @@ -1670,6 +1667,7 @@ tr_TR: delete_topic: "konuyu sil" delete_post: "gönderiyi sil" impersonate: "rolüne gir" + anonymize_user: "anonim kullanıcı" screened_emails: title: "Taranmış E-postalar" description: "Biri yeni bir hesap oluşturmaya çalıştığında, aşağıdaki e-posta adresleri kontrol edilecek ve kayıt önlenecek veya başka bir aksiyon alınacak." @@ -1799,8 +1797,13 @@ tr_TR: approve_success: "Kullanıcı onaylandı ve etkinleştirme bilgilerini içeren bir e-posta yollandı." approve_bulk_success: "Tebrikler! Seçilen tüm kullanıcılar onaylandı ve bilgilendirildi." time_read: "Okunma Zamanı" + anonymize: "Anonim Kullanıcı" + anonymize_confirm: "Bu hesabı anonim yapmak istediğinize EMİN misiniz? Bu kullanıcı adı ve e-postayı değiştirip, tüm profil bilgilerini sıfırlayacaktır." + anonymize_yes: "Evet, bu hesap anonim" + anonymize_failed: "Hesap anonim yapılırken bir hata oluştu." delete: "Kullanıcıyı Sil" delete_forbidden_because_staff: "Adminler ve moderatörler silinemez." + delete_posts_forbidden_because_staff: "Admin ve moderatörlerin tüm mesajları silinemez." delete_forbidden: other: "Gönderisi olan kullanıcılar silinemez. Kullanıcıyı silmeden önce tüm gönderilerini silin. (%{count} günden eski gönderiler silinemez.)" cant_delete_all_posts: @@ -1904,6 +1907,7 @@ tr_TR: none: 'Hiçbiri' no_results: "Hiç sonuç bulunamadı." clear_filter: "Temizle" + add_url: "URL ekle" categories: all_results: 'Hepsi' required: 'Gerekli' diff --git a/config/locales/client.uk.yml b/config/locales/client.uk.yml index 93b78611b1..a4bd2cb5f0 100644 --- a/config/locales/client.uk.yml +++ b/config/locales/client.uk.yml @@ -28,29 +28,35 @@ uk: x_hours: one: "1 годину тому" few: "годин тому: %{count}" - other: "годин тому: %{count}" + other: "%{count} годин тому" x_days: one: "1 день тому" few: "днів тому: %{count}" - other: "днів тому: %{count}" + other: "%{count} днів тому" share: topic: 'поширити посилання на цю тему' + post: 'допис #%{postNumber}' close: 'сховати' twitter: 'поширити це посилання в Twitter' facebook: 'поширити це посилання в Facebook' google+: 'поширити це посилання в Google+' email: 'надіслати це посилання електронною поштою' + topic_admin_menu: "керування темою" + emails_are_disabled: "Надсилання повідомлень електронною поштою було глобально вимкнено адміністратором. Жодне сповіщення електронною поштою не буде надіслано." edit: 'редагувати назву та категорію цієї теми' not_implemented: "Цей функціонал ще не реалізовано, даруйте!" no_value: "Ні" yes_value: "Так" generic_error: "Даруйте, виникла помилка." generic_error_with_reason: "Виникла помилка: %{error}" + sign_up: "Зареєструватись" + log_in: "Увійти" age: "Вік" joined: "Приєднався(-лась)" admin_title: "Адмін" flags_title: "Скарги" show_more: "показати більше" + show_help: "Допомога" links: "Посилання" links_lowercase: "посилання" faq: "Часті запитання" @@ -70,18 +76,43 @@ uk: daily: "щодня" weekly: "щотижня" every_two_weeks: "кожні два тижні" + every_three_days: "Кожні три дня" + max_of_count: "Не більше {{count}}" suggested_topics: title: "Пропоновані теми" + about: + simple_title: "Про" + title: "Про %{title}" + stats: "Статистика" + our_admins: "Адміни" + our_moderators: "Модератори" + stat: + all_time: "Весь час" + last_7_days: "Останні 7 днів" + last_30_days: "Останні 30 днів" + like_count: "Вподобання" + topic_count: "Теми" + post_count: "Дописи:" + user_count: "Нові користувачі" + active_user_count: "Діючі користувачі" + contact: "Зв’язатися з нами" + contact_info: "У випадку серйозних проблем з цим сайтом, будь ласка, зв’яжіться з нами через %{contact_info}." + bookmarked: + title: "Лишити закладку" + clear_bookmarks: "Видалити закладки" + help: + bookmark: "Натисніть щоб закласти перший допис у цій темі" + unbookmark: "Натисніть щоб видалити усі закладки у цій темі" bookmarks: not_logged_in: "вибачте, але ви повинні увійти, щоб додавати повідомлення до закладок " created: "ви додали цей допис до закладок" not_bookmarked: "ви прочитали цей допис; натисніть, щоб додати його до закладок" last_read: "це останній допис, що ви прочитали; натисніть, щоб додати його до закладок" - remove: "Видалити Закладку" + remove: "Видалити закладку" topic_count_latest: one: "{{count}} нова чи оновлена тема." few: "нових чи оновлених тем: {{count}}." - other: "нових чи оновлених тем {{count}}." + other: "непрочитаних тем: {{count}}." topic_count_unread: one: "{{count}} непрочитана тема." few: "непрочитаних тем: {{count}}." @@ -103,6 +134,9 @@ uk: disable: "Відключити" undo: "Скасувати" revert: "Повернути" + failed: "Помилка" + banner: + close: "Сховати" choose_topic: none_found: "Не знайдено тем." title: @@ -128,15 +162,15 @@ uk: one: "група" few: "групи" other: "групи" - members: "Members" - posts: "Posts" + members: "Учасники" + posts: "Дописи" alias_levels: - title: "Who can use this group as an alias?" - nobody: "Nobody" - only_admins: "Only admins" - mods_and_admins: "Only moderators and Admins" - members_mods_and_admins: "Only group members, moderators and admins" - everyone: "Everyone" + title: "Хто може використовувати цю групу як аліас?" + nobody: "Ніхто" + only_admins: "Лише адміністратори" + mods_and_admins: "Лише модератори та адміністратори" + members_mods_and_admins: "Лише участики групи, модератори та адміністратори" + everyone: "Усі" user_action_groups: '1': "Вподобані" '2': "Отримані вподобання" @@ -158,7 +192,7 @@ uk: posts: "Повідомлення" topics: "Теми" latest: "Останні" - latest_by: "latest by" + latest_by: "Останні від" toggle_ordering: "показати/сховати елемент керування для впорядкування" subcategories: "Підкатегорії" topic_stats: "Кількість нових тем." @@ -167,12 +201,23 @@ uk: title: Пошук IP адреси hostname: Ім'я хоста location: Місцеположення + location_not_found: (невідомо) organisation: Організація phone: Телефон + other_accounts: "Інші облікові записи з цією IP адресою" + delete_other_accounts: "Видалити %{count}" + username: "Ім'я користувача" + read_time: "час читання" + topics_entered: "створено тем" + post_count: "кількість дописів" + confirm_delete_other_accounts: "Ви впевнені, що хочете видалити цих користувачів?" user: + said: "{{username}}:" profile: "Профіль" mute: "Mute" edit: "Редагувати налаштування" + download_archive: "Завантажити мої дописи" + new_private_message: "Нове приватне повідомлення" private_message: "Приватне повідомлення" private_messages: "Повідомлення" activity_stream: "Активність" @@ -182,6 +227,9 @@ uk: invited_by: "Запрошений(а)" trust_level: "Рівень довіри" notifications: "Сповіщення" + dismiss_notifications: "Позначити все як прочитане" + dismiss_notifications_tooltip: "Позначити всі сповіщення як прочитані" + disable_jump_reply: "Не перескакувати до мого допису коли я відповім" dynamic_favicon: "Відображати сповіщення про вхідні повідомлення на піктограмі сайта (експериментальне)" edit_history_public: "Дати іншим дивитися версії мого повідомлення" external_links_in_new_tab: "Відкривати всі зовнішні посилання у новій вкладці" @@ -193,19 +241,25 @@ uk: admin_tooltip: "Цей користувач є адміністратором" suspended_notice: "Цього користувача призупинено до {{date}}." suspended_reason: "Причина: " + mailing_list_mode: "Надсилати всі нові дописи мені електронною поштою (доки я це не вимкну)" watched_categories: "Відслідковувані" watched_categories_instructions: "You will automatically watch all new topics in these categories. You will be notified of all new posts and topics, plus the count of unread and new posts will also appear next to the topic's listing." tracked_categories: "Відстежувані" + tracked_categories_instructions: "Ви будете автоматично відстежувати всі нові теми у цих категоріях. Число непрочитаних та нових дописів з'являтиметься навпроти теми." muted_categories: "Ігноровані" muted_categories_instructions: "Ви не будете отримувати жодних сповіщень про нові теми у цих категоріях, і вони не з'являтимуться у вкладці Непрочитані." delete_account: "Delete My Account" delete_account_confirm: "Are you sure you want to permanently delete your account? This action cannot be undone!" deleted_yourself: "Your account has been deleted successfully." delete_yourself_not_allowed: "You cannot delete your account right now. Contact an admin to do delete your account for you." + unread_message_count: "Повідомлення" + admin_delete: "Видалити" staff_counters: + flags_given: "корисні позначки" flagged_posts: "Позначені дописи" deleted_posts: "видалені повідомлення" suspensions: "тимчасові припинення" + warnings_received: "попередження" messages: all: "Всі" mine: "Мої" @@ -231,13 +285,18 @@ uk: success: "Ми надсілали листа на цю скриньку. Будь ласка, виконайте інструкції щодо підтердження." change_avatar: gravatar: "Gravatar, враховуючи" + refresh_gravatar_title: "Оновити мій Gravatar" + letter_based: "Ваше зображення додане системою" uploaded_avatar: "Інше зображення" uploaded_avatar_empty: "Додати інше зображення" upload_title: "Завантажити своє зображення" - upload_picture: "Завантажити Зображення" + upload_picture: "Завантажити зображення" image_is_not_a_square: "Попередження: ми обрізали Ваше зображення, оскільки воно не квадратне." change_profile_background: - title: "Фон Профіля" + title: "Фон профіля" + instructions: "Фон профіля буде відцентровано, його ширина 850 пікселів (за замовчуванням)." + change_card_background: + title: "Фон вашої візитки" email: title: "Електронна пошта" name: @@ -246,6 +305,8 @@ uk: title: "Ім'я користувача" global_mismatch: "Вже зареєстровано. Спробуєте {{suggestion}}?" not_available: "Не доступно. Спробуєте {{suggestion}}?" + too_short: "Ваше ім'я закоротке" + too_long: "Ваше ім'я довге" checking: "Перевірка доступності імені користувача..." locale: title: "Interface language" @@ -256,13 +317,15 @@ uk: last_emailed: "Останній електронний лист" last_seen: "Помічено востаннє" created: "Приєднався(лась)" + log_out: "Вийти" location: "Місцеположення" + card_badge: + title: "Візитка користувача" website: "Вебсайт" email_settings: "Електронна пошта" email_digests: daily: "щодня" weekly: "щотижня" - every_two_weeks: "кожні два тижні" other_settings: "Інше" categories_settings: "Категорії" new_topic_duration: @@ -298,6 +361,8 @@ uk: title: "Остання IP-адреса" registration_ip_address: title: "IP Адреса Реєстрації" + avatar: + title: "Аватар" title: title: "Назва" filters: @@ -363,6 +428,7 @@ uk: reset: "Скинути пароль" complete_username: "Якщо обліковий запис збігається з %{username}, у найближчий час ви отримаєте email з інструкціями, як змінити ваш пароль." login: + title: "Увійти" username: "Користувач" password: "Пароль" email_placeholder: "електронна скринька або ім'я користувача" @@ -401,8 +467,6 @@ uk: saved_local_draft_tip: "збережено локально" similar_topics: "Ваша тема схожа на..." drafts_offline: "чернетки в офлайні" - min_length: - need_more_for_title: "для назви треба ще {{n}}" error: title_missing: "Заголовок є необхідним" title_too_short: "Заголовок має бути мінімум {{min}} символів" @@ -415,6 +479,8 @@ uk: reply_here: "Відповісти тут" reply: "Відповісти" cancel: "Скасувати" + create_topic: "Нова тема" + create_pm: "Приватне повідомлення" title: "Or press Ctrl+Enter" users_placeholder: "Додати користувача" title_placeholder: "Про що це обговорення, у одному короткому реченні?" @@ -479,6 +545,7 @@ uk: topics: bulk: reset_read: "Reset Read" + delete: "Видалити теми" dismiss_new: "Dismiss New" toggle: "перемикач масової дії над темами" actions: "Масові дії" @@ -505,6 +572,7 @@ uk: top: "There are no more top topics." topic: filter_to: "Показати {{post_count}} дописів в темі" + create: 'Нова тема' create_long: 'Створити нову тему' private_message: 'Надіслати приватне повідомлення' list: 'Теми' @@ -538,6 +606,7 @@ uk: auto_close_remove: "Не закривати цю тему автоматично" progress: title: просування по темі + go_bottom: "Кнопка" jump_bottom_with_number: "перейти до допису %{post_number}" total: всього дописів current: поточний допис @@ -604,6 +673,7 @@ uk: action: "Запросити" error: "Даруйте, під час запрошення цього користувача сталася помилка." invite_reply: + title: 'Запрошення' action: 'Надіслати запрошення' help: 'надіслати запрошення друзям, щоб вони могли відповісти на цю тему в один клац' email_placeholder: 'електронна скринька' diff --git a/config/locales/client.zh_CN.yml b/config/locales/client.zh_CN.yml index 5df75d66df..4484fe6930 100644 --- a/config/locales/client.zh_CN.yml +++ b/config/locales/client.zh_CN.yml @@ -130,6 +130,7 @@ zh_CN: user_count: "新用户" active_user_count: "活跃用户" contact: "联系我们" + contact_info: "在遇到影响站点的重大错误或者紧急事件时,请通过 %{contact_info} 联系我们。" bookmarked: title: "书签" clear_bookmarks: "删除书签" @@ -378,7 +379,6 @@ zh_CN: title: "当我不访问时,向我的邮箱发送最新信息:" daily: "每天" weekly: "每周" - every_two_weeks: "每两周" email_direct: "当有人引用我、回复我的帖子或提及@你时发送一封邮件给我" email_private_messages: "当有人给发私信给我时发送一封邮件给我" email_always: "即使在论坛中活跃时也接收电子邮件提醒" @@ -430,6 +430,8 @@ zh_CN: title: "密码" too_short: "你设置的密码太短了。" common: "你设置的密码太常见了。" + same_as_username: "你的密码与用户名相同。" + same_as_email: "你的密码与电子邮箱相同。" ok: "你设置的密码符合要求。" instructions: "至少需要 %{count} 个字符。" associated_accounts: "登录" @@ -573,9 +575,6 @@ zh_CN: saved_local_draft_tip: "已本地保存" similar_topics: "你的主题有些类似于..." drafts_offline: "离线草稿" - min_length: - need_more_for_title: "请给标题再输入至少 {{n}} 个字符" - need_more_for_reply: "还差 {{n}} 个……" error: title_missing: "缺少标题" title_too_short: "标题太短,至少 {{min}} 个字符" @@ -1195,12 +1194,6 @@ zh_CN: posts: "帖子" posts_lowercase: "帖子" posts_long: "本主题有 {{number}} 个帖子" - posts_likes_MF: | - 这个主题有 {count, plural, other {# 个帖子}},{ratio, select, - low {并被很多人赞了} - med {并被非常多人赞了} - high {并被特别多人赞了} - other {}} original_post: "原始帖" views: "浏览" views_lowercase: "浏览" @@ -1937,10 +1930,13 @@ zh_CN: modal_title: 徽章组 granted_by: 授予由 granted_at: 授予于 + reason_help: (一个至主题或帖子的链接) save: 保存 delete: 删除 delete_confirm: 你确定要删除此徽章吗? revoke: 撤销 + reason: 理由 + expand: 展开 … revoke_confirm: 你确定要撤销此徽章吗? edit_badges: 编辑徽章 grant_badge: 授予徽章 diff --git a/config/locales/client.zh_TW.yml b/config/locales/client.zh_TW.yml index 4a3888f1b6..ca19f07256 100644 --- a/config/locales/client.zh_TW.yml +++ b/config/locales/client.zh_TW.yml @@ -379,7 +379,6 @@ zh_TW: title: "當我很久沒來此網站時,以電子郵件通知我最近有什麼新文章:" daily: "每天" weekly: "每週" - every_two_weeks: "每兩週" email_direct: "當有人引用、回覆我的發文,或以 @用戶名稱 提到我時,請以電子郵件通知我。" email_private_messages: "當有人寄給我私人訊息時,以電子郵件通知我。" email_always: "不要因為我在網站上活動而不寄信通知。" @@ -575,9 +574,6 @@ zh_TW: saved_local_draft_tip: "本地儲存完畢" similar_topics: "與你的討論話題類似的討論..." drafts_offline: "離線草稿" - min_length: - need_more_for_title: "討論話題名稱還需要 {{n}} 個字" - need_more_for_reply: "還需要 {{n}} 個字" error: title_missing: "標題為必填欄位" title_too_short: "標題必須至少 {{min}} 個字" @@ -1197,12 +1193,6 @@ zh_TW: posts: "文章" posts_lowercase: "文章" posts_long: "此討論話題有 {{number}} 篇文章" - posts_likes_MF: | - 這個主題有 {count, plural, one {1 篇文章} other {# 篇文章}},{ratio, select, - low {並被很多人按讚了} - med {並被非常多人按讚了} - high {並被特別多人按讚了} - other {}} original_post: "原始文章" views: "觀看" views_lowercase: "觀看" diff --git a/config/locales/server.es.yml b/config/locales/server.es.yml index f242022516..6c2251ab21 100644 --- a/config/locales/server.es.yml +++ b/config/locales/server.es.yml @@ -897,6 +897,7 @@ es: max_age_unmatched_ips: "Eliminar entradas de IP que no coincidan después de (N) días." num_flaggers_to_close_topic: "Número mínimo de denunciantes únicos requerido para pausar un tema automáticamente para intervención" num_flags_to_close_topic: "Valor mínimo de reportes activos requerido para pausar un tema automáticamente para intervención" + auto_respond_to_flag_actions: "Activar la respuesta automática al deshacer un reporte." reply_by_email_enabled: "Habilitar la respuesta a temas por email." reply_by_email_address: "Plantilla para la dirección de email que aparecerá al recibir correos con la función de respuesta por email: %{reply_key}@respuesta.ejemplo.com o respuestas+%{reply_key}@ejemplo.com" disable_emails: "Impedir que Discourse envié cualquier tipo de e-mail." diff --git a/config/locales/server.he.yml b/config/locales/server.he.yml index b0888992a4..52def2096e 100644 --- a/config/locales/server.he.yml +++ b/config/locales/server.he.yml @@ -53,6 +53,15 @@ he: too_short: one: קצר מידי (המינימום הנדרש הוא תו 1) other: קצר מידי (המינימום הנדרש הוא %{count} תוים) + wrong_length: + one: באורך שגוי (צריך להיות באורך תו אחד) + other: באורך שגוי (צריך להיות %{count} תוים) + other_than: "צריך להיות שונה מ-%{count}" + template: + body: 'היו בעיות עם השדות הבאים:' + header: + one: שגיאה מנעה מ-%{model} להישמר. + other: '%{count} שגיאות מנעו מ-%{model} להישמר.' embed: load_from_remote: "ארעה שגיאה בטעינת ההודעה הזו." bulk_invite: @@ -62,6 +71,8 @@ he: backup_file_should_be_tar_gz: "קובץ הגיוי צריך להיות .tar.gz." not_enough_space_on_disk: "אין מספיק מקום על הדיסק כדי להעלות את הגיבוי הזה." not_logged_in: "אתה צריך להיות מחובר כדי לעשות את זה." + not_found: "המשאב או כתובת ה-URL המבוקשת לא נמצא/ה." + invalid_access: "אינך מורשה/מורשית לצפות במשאב שביקשת." read_only_mode_enabled: "האתר הזה במצב קריאה בלבד. פעולות אין אפשריות." too_many_replies: one: "אנחנו מצטערים, אבל משתמשים חדשים מוגבלים זמנים לתגובה אחת לאותו הנושא." @@ -120,6 +131,7 @@ he: latest: "נושאים מדוברים" hot: "נושאים חמים" too_late_to_edit: "ההודעה הזו נוצרה לפני זמן רב מידי. לא ניתן יותר לערוך או למחוק אותה." + excerpt_image: "תמונה" groups: errors: can_not_modify_automatic: "אתה לא יכול לשנות קבוצה אוטומטית" @@ -198,6 +210,8 @@ he: attributes: password: common: "אחת מתוך 10000 הסיסמאות הנפוצות. אנא השתמשו בסיסמא בטוחה יותר." + same_as_username: "זהה לשם המשתמש/ת שלך. אנא השתמש/י בסיסמה בטוחה יותר." + same_as_email: "זהה לכתובת הדוא\"ל שלך. אנא השתמש/י בסיסמה בטוחה יותר." ip_address: signup_not_allowed: " הרשמה אינו מורשית מהחשבון הזה." color_scheme_color: @@ -376,6 +390,8 @@ he: title: 'ספאם' description: 'ההודעה הזו היא פרסמות. היא לא מועילה או רלוונטית לשיחה הנוכחית, אבל קידומית באופייה.' long_form: 'דוגלל כספאם' + email_title: '"%{title}" סומן כספאם' + email_body: "%{link}\n\n%{message}" inappropriate: title: 'לא ראוי' description: 'פרסום זה מכיל תוכן שאדם סביר היה רואה כפוגעני, מתעלל או הפרה של כללי הקהילה .' @@ -447,6 +463,7 @@ he: xaxis: "יום" yaxis: "מספר ביקורים" signups: + title: "משתמשים חדשים" xaxis: "יום" yaxis: "מספר משתמשים חדשים" topics: @@ -516,6 +533,46 @@ he: title: "נושאים מיוחסים" xaxis: "נושא" num_clicks: "לחיצות" + page_view_anon_reqs: + title: "אנונימי" + xaxis: "יום" + yaxis: "בקשות API אנונימיות" + page_view_logged_in_reqs: + title: "מחובר/ת" + xaxis: "יום" + yaxis: "בקשות API עם חיבור" + page_view_crawler_reqs: + title: "זחלן רשת" + xaxis: "יום" + yaxis: "בקשות API של זחלני רשת" + page_view_total_reqs: + title: "סה\"כ" + xaxis: "יום" + yaxis: "סך כל בקשות ה-API" + http_background_reqs: + title: "רקע" + xaxis: "יום" + yaxis: "בשקות שמשמשות לעדכונים חיים ולמעקב" + http_2xx_reqs: + title: "סטטוס 2xx (OK)" + xaxis: "יום" + yaxis: "בקשות מוצלחות (Status 2xx)" + http_3xx_reqs: + title: "HTTP 3xx (Redirect)" + xaxis: "יום" + yaxis: "בקשות מופנות Redicrect HTTP 3xx (Redirect)" + http_4xx_reqs: + title: "HTTP 4xx (Client Error)" + xaxis: "יום" + yaxis: "שגיאות לקוח (Status 4xx)" + http_5xx_reqs: + title: "HTTP 5xx (שגיאת שרת)" + xaxis: "יום" + yaxis: "שגיאות שרת (Status 5xx)" + http_total_reqs: + title: "סה\"כ" + xaxis: "יום" + yaxis: "סה\"כ הבקשות" dashboard: rails_env_warning: "השרת שלך רץ במצב %{env}." ruby_version_warning: "You are running a version of Ruby 2.0.0 that is known to have problems. Upgrade to patch level 247 or later." @@ -534,7 +591,14 @@ he: s3_backup_config_warning: 'The server is configured to upload backups to s3, but at least one the following setting is not set: s3_access_key_id, s3_secret_access_key or s3_backup_bucket. Go to the Site Settings and update the settings. See "How to set up image uploads to S3?" to learn more.' image_magick_warning: 'The server is configured to create thumbnails of large images, but ImageMagick is not installed. Install ImageMagick using your favorite package manager or download the latest release.' failing_emails_warning: 'There are %{num_failed_jobs} email jobs that failed. Check your config/discourse.conf file and ensure that the mail server settings are correct. See the failed jobs in Sidekiq.' + default_logo_warning: "כוונו את הסמלילים הגרפיים לשימוש באתר שלך. עדכנו את כתובת ה-URL של הלוגו, כתובת ה-URL ללוגו המוקטן, וכתובת ה-URL של ה-favicon. " + contact_email_missing: "הזינו כתובת דוא\"ל ליצירת קשר, בה ניתן יהיה ליצור עמכם קשר בנושאים דחופים בנוגע לאתר שלכם. עדכנו אותה בהגדרות האתר." + contact_email_invalid: "כתובת הדוא\"ל ליצירת קשר של האתר אינה תקינה. עדכנו אותה ב הגדרות האתר." + title_nag: "הזינו את השם של האתר שלך. עדכנו את הכותרת בהגדרות האתר." + site_description_missing: "הזינו משפט אחד לתיאור האתר שלך אשר יופיע בתוצאות מנועי חיפוש. עדכנו את תיאור האתר בהגדרות האתר." consumer_email_warning: "Your site is configured to use Gmail (or another consumer email service) to send email. Gmail limits how many emails you can send. Consider using an email service provider like mandrill.com to ensure email deliverability." + site_contact_username_warning: "הזינו שם חשבון של חבר/ת צוות ידידותיים ממנו יישלחו אוטומטית הודעות פרטיות. עדכנו את שם המשתמש של הדמות ליצירת קשר ב הגדרות אתר." + notification_email_warning: "מיילים ליידוע אינם נשלחים מכתובת תקינה בדומיין שלכם; משלוח דוא\"ל יהיה בעייתי ולא אמין. אנא כוונו את כתובת המייל למשלוח התראות לכתובת מקומית תקינה בהגדרות האתר." content_types: education_new_reply: title: "New User Education: First Replies" @@ -583,6 +647,9 @@ he: allow_duplicate_topic_titles: "אשר/י נושאים עם כותרות זהות או משוכפלות." unique_posts_mins: "How many minutes before a user can make a post with the same content again" educate_until_posts: "כאשר המשתמש/ת מתחילים להקיש את (n) ההודעות הראשונות שלהם, הציגו פאנל הנחיה למשתמש באזור חיבור ההודעות." + title: "שם האתר הזה, כפי שהוא משתמש בתגית הכותרת." + site_description: "תארו את האתר הזה במשפט אחד, כפי שהוא מופיע במטא-תגית התיאור." + contact_email: "כתובת דוא\"ל של איש/אשת קשר האחראי לאתר זה. משמש להתראות חשובות, כמו סימונים שלא טופלו, כמו גם ליצירת קשר חירום בעמוד האודות." queue_jobs: "DEVELOPER ONLY! WARNING! By default, queue jobs in sidekiq. If disabled, your site will be broken." crawl_images: "אחזור תמונות מכתובת URL רחוקה כדי להכניס את מימדי האורך והרוחב הנכונים." download_remote_images_to_local: "המרת תמונות מרחוק לתמונות מקומיות באמצעות הורדות; למניעת שגיאות של תמונות חסרות" @@ -1537,3 +1604,5 @@ he: א0 נחליט לשנות את מדיניות הפרטיות שלנו, נפרסם שינויים אלו בעמוד זה. מסמך זה מפורסם תחת רשיון CC-BY-SA. הוא עודכן לאחרונה ב-31 למאי, 2013. + static: + search_help: "

    טיפים

    \n

    \n

      \n
    • כותרות מוצגות על פי סדר עדיפות, כך שכשיש ספק, חפשו: titles
    • \n
    • מלים ייחודיות ולא מקובלות יציגו תמיד את התוצאות הטובות ביותר
    • \n
    • כאשר זה אפשרי, צמצמו את החיפוש שלכם לקטגוריה, משתמש או נושא
    • \n
    \n

    \n

    אפשרויות

    \n

    \n \n \n \n \n \nin:private\n\n\n
    order:viewsorder:latest
    status:openstatus:closedstatus:archivedstatus:norepliesstatus:singleuser
    category:foouser:foo
    in:likesin:postedin:watchingin:tracking
    in:bookmarks
    \n

    \n

    \n rainbows category:parks status:open order:latest \nיחפש נושאים הכוללים את המילה \"rainbows\" בקטגוריה \"parks\" שאינם סגורים או מאורכבים, על פי סדר תאריך הפרסום האחרון.

    \n" diff --git a/config/locales/server.it.yml b/config/locales/server.it.yml index 8cfbe84a0d..0df0775232 100644 --- a/config/locales/server.it.yml +++ b/config/locales/server.it.yml @@ -214,6 +214,7 @@ it: password: common: "è una delle 10000 password più comuni. Usa una password più sicura." same_as_username: "è la stessa del tuo nome utente. Per favore usa una password più sicura." + same_as_email: "coincide con la tua email. Per favore scegli una password più sicura." ip_address: signup_not_allowed: "L'iscrizione non è permessa da questo account." color_scheme_color: diff --git a/config/locales/server.ja.yml b/config/locales/server.ja.yml index a6e58f4481..bf89c691b7 100644 --- a/config/locales/server.ja.yml +++ b/config/locales/server.ja.yml @@ -18,12 +18,45 @@ ja: log_in: "ログイン" via: "%{username} via %{site_name}" is_reserved: "is reserved" + purge_reason: "アクティブでないアカウントは放棄されたとして削除されました" disable_remote_images_download_reason: "ディスク容量が不足しているため、リモートでの画像ダウンロードは無効になっています。" errors: messages: too_long_validation: "は、最大文字数(%{max}文字)を超えています。(入力したのは%{length}文字 ) " invalid_boolean: "無効なboolean." + taken: "は既に使用されています" + accepted: に同意する必要があります + blank: を入力してください + present: は入力しないでください + confirmation: "と%{attribute}の入力が一致しません" empty: 本文が未入力です。. + equal_to: は%{count}にしてください + even: は偶数にしてください + exclusion: は予約されています + greater_than: は%{count}より大きい値にしてください + greater_than_or_equal_to: は%{count}以上の値にしてください + inclusion: は一覧にありません + invalid: は不正な値です + less_than: は%{count}より小さい値にしてください + less_than_or_equal_to: は%{count}以下の値にしてください + not_a_number: は数値で入力してください + not_an_integer: は整数で入力してください + odd: は奇数にしてください + record_invalid: 'バリデーションに失敗しました。 %{errors}' + restrict_dependent_destroy: + one: "%{record}が存在しているので削除できません" + many: "%{record}が存在しているので削除できません。" + too_long: + other: は%{count}文字以内で入力してください + too_short: + other: は%{count}文字以上で入力してください + wrong_length: + other: は%{count}文字で入力してください + other_than: "は%{count}以外の値にしてください" + template: + body: '次のフィールドに問題があります:' + header: + other: '%{model} の保存中に%{count} 個のエラーが発生しました' embed: load_from_remote: "投稿の読み込みに失敗しました。" bulk_invite: @@ -33,6 +66,8 @@ ja: backup_file_should_be_tar_gz: "バックアップファイルは .tar .gz 形式でなければいけません。" not_enough_space_on_disk: "このバックアップファイルをアップロードするディスクの空き容量が足りません。" not_logged_in: "ログインしてください。" + not_found: "リクエストされたURL、リソースは見つかりませんでした" + invalid_access: "リクエストしたリソースの閲覧が許可されていません" read_only_mode_enabled: "このサイトは読み取り専用モードです。会話は無効になっています。" too_many_replies: other: "申し訳ありません、新しいユーザーの同じトピックへの返信は、一時的に %{count} 回に制限されています。" @@ -322,6 +357,7 @@ ja: yaxis: "新規ブックマーク数" starred: title: "お気に入り" + xaxis: "日" users_by_trust_level: title: "トラストレベル毎のユーザ" xaxis: "トラストレベル" @@ -365,6 +401,8 @@ ja: title: "トップ被参照トピック" xaxis: "トピック" num_clicks: "クリック" + page_view_anon_reqs: + xaxis: "日" dashboard: rails_env_warning: "サーバは %{env} モードで起動中です。" ruby_version_warning: "現在起動中の Ruby 2.0.0 にはいくつか問題があります。パッチレベル p247 以降にアップグレードしてください。" diff --git a/config/locales/server.pl_PL.yml b/config/locales/server.pl_PL.yml index 9c77610d3b..54d66c354a 100644 --- a/config/locales/server.pl_PL.yml +++ b/config/locales/server.pl_PL.yml @@ -70,6 +70,8 @@ pl_PL: backup_file_should_be_tar_gz: "Plik z kopią zapasową powinien mieć postać archiwum .tar.gz." not_enough_space_on_disk: "Nie ma wystarczającej ilości wolnego miejsca, aby wczytać tę kopię zapasową." not_logged_in: "Aby to zrobić musisz się zalogować." + not_found: "Żądany URL lub źródło nie mógł zostać znaleziony." + invalid_access: "Nie jesteś uprawniony by zobaczyć żądane źródło." read_only_mode_enabled: "Strona jest w trybie tylko do odczytu. Możliwość interakcji jest wyłączona." too_many_replies: one: "Przepraszamy, ale nowi użytkownicy są tymczasowo ograniczeni do 1 odpowiedzi w ramach jednego tematu." @@ -482,6 +484,7 @@ pl_PL: xaxis: "Dzień" yaxis: "Liczba wizyt" signups: + title: "Nowi Użytkownicy" xaxis: "Dzień" yaxis: "Liczba nowych użytkowników" topics: @@ -562,20 +565,31 @@ pl_PL: page_view_crawler_reqs: title: "Bot indeksujący" xaxis: "Dzień" + yaxis: "API robotów indeksujących żąda" page_view_total_reqs: title: "Łącznie" xaxis: "Dzień" + yaxis: "Razem żądań API" http_background_reqs: title: "Tło" xaxis: "Dzień" + yaxis: "Żądania użyte w dynamicznej aktualizacji i śledzeniu" http_2xx_reqs: + title: "Status 2xx (OK)" xaxis: "Dzień" + yaxis: "Udane żądania (Status 2xx)" http_3xx_reqs: + title: "HTTP 3xx (Przekierowanie)" xaxis: "Dzień" + yaxis: "Przekierowanie żądań (Status 3xx)" http_4xx_reqs: + title: "HTTP 4xx (Błąd klienta)" xaxis: "Dzień" + yaxis: "Błędy klienta (Status 4xx)" http_5xx_reqs: + title: "HTTP 5xx (Błąd serwera)" xaxis: "Dzień" + yaxis: "Błędy serwera (Status 5xx)" http_total_reqs: title: "Łącznie" xaxis: "Dzień" @@ -598,7 +612,10 @@ pl_PL: image_magick_warning: 'Serwer jest skonfigurowany by tworzyć miniaturki dużych obrazów, ale ImageMagick nie jest zainstalowany. Zainstaluj ImageMagick za pomocą ulubionego menedżera pakietów lub pobierz najnowszą wersję.' failing_emails_warning: '%{num_failed_jobs} prac emailowych nie powiodło się. Sprawdź plik config/discourse.conf i upewnij się, że ustawienia serwera poczty są poprawne. Zobacz nieudane prace w Sidekiqu.' default_logo_warning: "Ustaw logo dla swojej strony. Zaktualizuj logo_url, logo_small_url i favicon_url tutaj: ustawienia strony." + contact_email_missing: "Wprowadź kontaktowy adres e-mail strony, aby otrzymywać ważne powiadomienia w sprawie strony. Zaktualizuj to w Ustawieniach strony. " + contact_email_invalid: "Kontaktowy adres email jest zły. Zaktualizuj to w Ustawieniach strony." title_nag: "Wprowadź nazwę swojej strony. Zaktualizuj tytuł w Ustawieniach strony." + site_description_missing: "Wprowadź jedno zdanie opisujące Twoją stronę, które pojawi się w wynikach wyszukiwania. Zaktualizuj opis strony w Ustawieniach strony." consumer_email_warning: "Twój serwis jest skonfigurowany by używać Gmaila (lub innego konsumenckiego serwisu poczty) do wysyłania emaili. Gmail ogranicza jak dużo wiadomości możesz wysłać. Rozważ wykorzystanie dostawcy serwisu pocztowego jak mandrill.com by zagwarantować dostarczanie poczty." content_types: education_new_reply: diff --git a/config/locales/server.pt_BR.yml b/config/locales/server.pt_BR.yml index 7e2f2b49a8..ee323c1a96 100644 --- a/config/locales/server.pt_BR.yml +++ b/config/locales/server.pt_BR.yml @@ -71,6 +71,8 @@ pt_BR: backup_file_should_be_tar_gz: "O arquivo de backup deve ser um arquivo .tar.gz." not_enough_space_on_disk: "Não há espaço suficiente no disco para carregar este backup." not_logged_in: "Você precisa estar conectado para fazer isso." + not_found: "A URL ou recurso solicitado não pôde ser encontrado." + invalid_access: "Você não tem permissão para ver o recurso solicitado." read_only_mode_enabled: "O site está em modo somente leitura. As interações estão desativadas." too_many_replies: one: "Lamentamos, mas usuários novos estão temporariamente limitados a 1 resposta no mesmo tópico." @@ -207,6 +209,8 @@ pt_BR: attributes: password: common: "é uma das 10000 senhas mais comuns. Por favor, use uma senha mais segura." + same_as_username: "é igual o seu nome de usuário. Por favor use uma senha mais segura." + same_as_email: "é igual o seu email. Por favor use uma senha mais segura." ip_address: signup_not_allowed: "Cadastro não é permitido a partir desta conta." color_scheme_color: @@ -1491,6 +1495,7 @@ pt_BR: body_blank: "body está em branco" color_schemes: base_theme_name: "Base" + about: "Sobre" guidelines: "Diretrizes" privacy: "Privacidade" edit_this_page: "Editar esta página" diff --git a/config/locales/server.ru.yml b/config/locales/server.ru.yml index 051fa5bad4..7795a5f8b8 100644 --- a/config/locales/server.ru.yml +++ b/config/locales/server.ru.yml @@ -25,6 +25,24 @@ ru: messages: too_long_validation: "не может быть длиннее %{max} символов, а введено %{length}." invalid_boolean: "Неправильное булевое значение." + taken: "уже занято" + accepted: должно быть принято + blank: не может быть пустым + present: должно быть пустым + confirmation: "не совпадает с %{attribute}" + empty: не может быть пустым + equal_to: должно быть равно %{count} + even: должно быть четным + exclusion: зарезервировано + greater_than: должно быть больше чем %{count} + greater_than_or_equal_to: должно быть больше или равно %{count} + inclusion: не включен в список + invalid: неверный + less_than: должен быть меньше %{count} + less_than_or_equal_to: должен быть меньше или равен %{count} + not_a_number: не число + not_an_integer: должно быть целым + odd: должно быть нечетным embed: load_from_remote: "Произошла ошибка при загрузке сообщения." bulk_invite: @@ -441,6 +459,7 @@ ru: xaxis: "День" yaxis: "Количество визитов" signups: + title: "Новые пользователи" xaxis: "День" yaxis: "Количество новых пользователей" topics: @@ -513,6 +532,7 @@ ru: page_view_anon_reqs: title: "Анонимы" xaxis: "Дата" + yaxis: "Анонимные запросы API" page_view_logged_in_reqs: title: "Пользователи" xaxis: "Дата" @@ -530,8 +550,15 @@ ru: title: "Статус 2xx (OK)" xaxis: "Дата" yaxis: "Запросов" + http_3xx_reqs: + xaxis: "День" + http_4xx_reqs: + xaxis: "День" + http_5xx_reqs: + xaxis: "День" http_total_reqs: title: "Всего" + xaxis: "День" yaxis: "Всего" dashboard: rails_env_warning: "Ваш сервер работает в режиме %{env}." @@ -1041,6 +1068,8 @@ ru: ``` %{logs} ``` + csv_export_failed: + subject_template: "Экспорт не удался" email_reject_trust_level: subject_template: "Проблема с письмом - недостаточный уровень доверия" text_body_template: | @@ -1292,6 +1321,7 @@ ru: body_blank: "Cообщения письма пусто" color_schemes: base_theme_name: "Базовая" + about: "О нас" guidelines: "Руководство" privacy: "Политика конфиденциальности" edit_this_page: "Отредактировать эту страницу" diff --git a/config/locales/server.te.yml b/config/locales/server.te.yml index 5c828aee6b..b64e4ec144 100644 --- a/config/locales/server.te.yml +++ b/config/locales/server.te.yml @@ -503,6 +503,7 @@ te: page_view_total_reqs: title: "మొత్తం" xaxis: "రోజు" + yaxis: "మొత్తం API అభ్యర్ధనలు" http_background_reqs: title: "వెనుతలం" xaxis: "రోజు" @@ -592,6 +593,7 @@ te: max_topics_in_first_day: "ఈ సైట్ లో వినియోగదారు మొదటి రోజున గరిష్ఠంగా ఎన్ని విషయాలకి అనుమతి ఉంది " max_replies_in_first_day: "ఈ సైట్ లో వినియోగదారు మొదటి రోజున గరిష్ఠంగా ఎన్ని జవాబులకు అనుమతి ఉంది " allow_moderators_to_create_categories: "మధ్యవర్తులు కొత్త వర్గాలు సృష్టించడానికి అనుమతించు" + topics_per_period_in_top_summary: "అప్రమేయ అగ్ర విషయాల సారాంశంలో చూపే అగ్ర విషయాల సంఖ్య." invite_expiry_days: "వాడుకరుల ఆహ్వాన కీ ఎన్ని రోజులు చెల్లుతుంది" min_password_length: "సంకేతపదపు కనీస పొడవు." max_likes_per_day: "వినియోగదారులు గరిష్ఠంగా రోజుకు చేయగలిగే లైక్‌ల సంఖ్య" From 4bc101d40c482562ed0c6631fe9100880e12bb2d Mon Sep 17 00:00:00 2001 From: Jeff Atwood Date: Wed, 18 Mar 2015 10:11:30 -0700 Subject: [PATCH 049/114] increase urgency of Google warning --- config/locales/server.en.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/locales/server.en.yml b/config/locales/server.en.yml index 9e61260cc6..b788332c80 100644 --- a/config/locales/server.en.yml +++ b/config/locales/server.en.yml @@ -676,7 +676,7 @@ en: sidekiq_warning: 'Sidekiq is not running. Many tasks, like sending emails, are executed asynchronously by sidekiq. Please ensure at least one sidekiq process is running. Learn about Sidekiq here.' queue_size_warning: 'The number of queued jobs is %{queue_size}, which is high. This could indicate a problem with the Sidekiq process(es), or you may need to add more Sidekiq workers.' memory_warning: 'Your server is running with less than 1 GB of total memory. At least 1 GB of memory is recommended.' - enable_google_logins_warning: "You are using a deprecated version of Google's OpenID authentication. Google will be ending support for OpenID by April 20, 2015. Start using Google OAuth2 as soon as possible. See this guide to learn more" + enable_google_logins_warning: "WARNING! Support is ending for your current method of Google authentication on April 20, 2015! Please switch to the new method now!" both_googles_warning: "You have both enable_google_logins and enable_google_oauth2_logins checked in the site settings. Disable enable_google_logins." google_oauth2_config_warning: 'The server is configured to allow signup and log in with Google OAuth2 (enable_google_oauth2_logins), but the client id and client secret values are not set. Go to the Site Settings and update the settings. See this guide to learn more.' facebook_config_warning: 'The server is configured to allow signup and log in with Facebook (enable_facebook_logins), but the app id and app secret values are not set. Go to the Site Settings and update the settings. See this guide to learn more.' From 6b85d5582c89717c78a263e012648226c1c7e368 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9gis=20Hanol?= Date: Wed, 18 Mar 2015 18:23:55 +0100 Subject: [PATCH 050/114] FIX: 'uploads:migrate_from_s3' rake task --- lib/tasks/uploads.rake | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/lib/tasks/uploads.rake b/lib/tasks/uploads.rake index e24e7b03aa..f8b8c25b9c 100644 --- a/lib/tasks/uploads.rake +++ b/lib/tasks/uploads.rake @@ -26,6 +26,11 @@ task "uploads:migrate_from_s3" => :environment do local_store = FileStore::LocalStore.new max_file_size = [SiteSetting.max_image_size_kb, SiteSetting.max_attachment_size_kb].max.kilobytes + puts "Deleting all optimized images..." + puts + + OptimizedImage.destroy_all + puts "Migrating uploads from S3 to local storage" puts @@ -57,8 +62,8 @@ task "uploads:migrate_from_s3" => :environment do if upload.save # update & rebake the posts (if any) Post.where("raw ILIKE ?", "%#{previous_url}%").find_each do |post| - post.raw.gsub!(previous_url, upload.url) - post.rebake! + post.raw = post.raw.gsub(previous_url, upload.url) + post.save end putc '#' From 3d2d2243125847f3a941a05d0847cda65382ac1b Mon Sep 17 00:00:00 2001 From: Robin Ward Date: Mon, 16 Mar 2015 15:14:33 -0400 Subject: [PATCH 051/114] FEATURE: User Directory, with sorting and time period filter --- .../discourse/adapters/rest.js.es6 | 30 ++++++--- .../components/directory-toggle.js.es6 | 28 ++++++++ ...d-chooser.js.es6 => period-chooser.js.es6} | 19 ++++-- .../components/top-period-buttons.js.es6 | 13 +++- .../components/top-title-button.js.es6 | 13 ---- .../discourse/components/top-title.js.es6 | 10 --- .../controllers/directory-show.js.es6 | 13 ++++ .../discourse/controllers/discovery.js.es6 | 18 ++--- .../discourse/helpers/period-title.js.es6 | 11 ++++ .../discourse/mixins/string-buffer.js.es6 | 19 +++--- .../javascripts/discourse/models/rest.js.es6 | 20 ++++++ .../discourse/models/result-set.js.es6 | 22 +++++++ .../javascripts/discourse/models/store.js.es6 | 66 ++++++++++++------- .../discourse/models/top-period.js.es6 | 32 --------- .../discourse/routes/app-route-map.js.es6 | 4 ++ .../routes/build-category-route.js.es6 | 3 +- .../discourse/routes/build-topic-route.js.es6 | 6 +- .../discourse/routes/directory-index.js.es6 | 6 ++ .../discourse/routes/directory-show.js.es6 | 31 +++++++++ .../templates/components/period-chooser.hbs | 11 ++++ .../components/top-period-buttons.hbs | 6 +- .../components/top-period-chooser.hbs | 11 ---- .../discourse/templates/directory.hbs | 5 ++ .../discourse/templates/directory/show.hbs | 50 ++++++++++++++ .../discourse/templates/discovery/topics.hbs | 4 +- .../templates/mobile/discovery/topics.hbs | 4 +- .../discourse/templates/site-map.hbs | 2 + .../discourse/views/directory-show.js.es6 | 5 ++ app/assets/javascripts/main_include.js | 2 - .../stylesheets/common/base/_topic-list.scss | 7 +- .../stylesheets/common/base/directory.scss | 46 +++++++++++++ app/controllers/directory_controller.rb | 8 +++ app/controllers/directory_items_controller.rb | 35 ++++++++++ app/jobs/scheduled/directory_refresh.rb | 9 +++ app/models/directory_item.rb | 57 ++++++++++++++++ app/serializers/directory_item_serializer.rb | 35 ++++++++++ app/serializers/directory_serializer.rb | 9 +++ config/locales/client.en.yml | 13 ++++ config/routes.rb | 3 + .../20150318143915_create_directory_items.rb | 16 +++++ .../directory_items_controller_spec.rb | 31 +++++++++ spec/models/directory_item_spec.rb | 15 +++++ .../fixtures/directory-fixtures.js.es6 | 3 + .../helpers/create-pretender.js.es6 | 28 ++++++-- .../integration/directory-test.js.es6 | 8 +++ .../javascripts/models/result-set-test.js.es6 | 28 ++++++++ test/javascripts/models/store-test.js.es6 | 15 ++++- 47 files changed, 684 insertions(+), 146 deletions(-) create mode 100644 app/assets/javascripts/discourse/components/directory-toggle.js.es6 rename app/assets/javascripts/discourse/components/{top-period-chooser.js.es6 => period-chooser.js.es6} (68%) delete mode 100644 app/assets/javascripts/discourse/components/top-title-button.js.es6 delete mode 100644 app/assets/javascripts/discourse/components/top-title.js.es6 create mode 100644 app/assets/javascripts/discourse/controllers/directory-show.js.es6 create mode 100644 app/assets/javascripts/discourse/helpers/period-title.js.es6 create mode 100644 app/assets/javascripts/discourse/models/rest.js.es6 create mode 100644 app/assets/javascripts/discourse/models/result-set.js.es6 delete mode 100644 app/assets/javascripts/discourse/models/top-period.js.es6 create mode 100644 app/assets/javascripts/discourse/routes/directory-index.js.es6 create mode 100644 app/assets/javascripts/discourse/routes/directory-show.js.es6 create mode 100644 app/assets/javascripts/discourse/templates/components/period-chooser.hbs delete mode 100644 app/assets/javascripts/discourse/templates/components/top-period-chooser.hbs create mode 100644 app/assets/javascripts/discourse/templates/directory.hbs create mode 100644 app/assets/javascripts/discourse/templates/directory/show.hbs create mode 100644 app/assets/javascripts/discourse/views/directory-show.js.es6 create mode 100644 app/assets/stylesheets/common/base/directory.scss create mode 100644 app/controllers/directory_controller.rb create mode 100644 app/controllers/directory_items_controller.rb create mode 100644 app/jobs/scheduled/directory_refresh.rb create mode 100644 app/models/directory_item.rb create mode 100644 app/serializers/directory_item_serializer.rb create mode 100644 app/serializers/directory_serializer.rb create mode 100644 db/migrate/20150318143915_create_directory_items.rb create mode 100644 spec/controllers/directory_items_controller_spec.rb create mode 100644 spec/models/directory_item_spec.rb create mode 100644 test/javascripts/fixtures/directory-fixtures.js.es6 create mode 100644 test/javascripts/integration/directory-test.js.es6 create mode 100644 test/javascripts/models/result-set-test.js.es6 diff --git a/app/assets/javascripts/discourse/adapters/rest.js.es6 b/app/assets/javascripts/discourse/adapters/rest.js.es6 index 959bf9beee..da499c963d 100644 --- a/app/assets/javascripts/discourse/adapters/rest.js.es6 +++ b/app/assets/javascripts/discourse/adapters/rest.js.es6 @@ -1,31 +1,45 @@ const ADMIN_MODELS = ['plugin']; export default Ember.Object.extend({ - pathFor(type, id) { - let path = "/" + Ember.String.underscore(type + 's'); + pathFor(store, type, findArgs) { + let path = "/" + Ember.String.underscore(store.pluralize(type)); if (ADMIN_MODELS.indexOf(type) !== -1) { path = "/admin/" + path; } - if (id) { path += "/" + id; } + + if (findArgs) { + if (typeof findArgs === "object") { + const queryString = Object.keys(findArgs) + .reject(k => !findArgs[k]) + .map(k => k + "=" + encodeURIComponent(findArgs[k])); + + if (queryString.length) { + path += "?" + queryString.join('&'); + } + } else { + // It's serializable as a string if not an object + path += "/" + findArgs; + } + } return path; }, findAll(store, type) { - return Discourse.ajax(this.pathFor(type)); + return Discourse.ajax(this.pathFor(store, type)); }, - find(store, type, id) { - return Discourse.ajax(this.pathFor(type, id)); + find(store, type, findArgs) { + return Discourse.ajax(this.pathFor(store, type, findArgs)); }, update(store, type, id, attrs) { const data = {}; data[Ember.String.underscore(type)] = attrs; - return Discourse.ajax(this.pathFor(type, id), { method: 'PUT', data }); + return Discourse.ajax(this.pathFor(store, type, id), { method: 'PUT', data }); }, destroyRecord(store, type, record) { - return Discourse.ajax(this.pathFor(type, record.get('id')), { method: 'DELETE' }); + return Discourse.ajax(this.pathFor(store, type, record.get('id')), { method: 'DELETE' }); } }); diff --git a/app/assets/javascripts/discourse/components/directory-toggle.js.es6 b/app/assets/javascripts/discourse/components/directory-toggle.js.es6 new file mode 100644 index 0000000000..8c4b4761bd --- /dev/null +++ b/app/assets/javascripts/discourse/components/directory-toggle.js.es6 @@ -0,0 +1,28 @@ +import StringBuffer from 'discourse/mixins/string-buffer'; +import { iconHTML } from 'discourse/helpers/fa-icon'; + +export default Ember.Component.extend(StringBuffer, { + tagName: 'th', + classNames: ['sortable'], + rerenderTriggers: ['order', 'asc'], + + renderString(buffer) { + const field = this.get('field'); + buffer.push(I18n.t('directory.' + field)); + + if (field === this.get('order')) { + buffer.push(iconHTML(this.get('asc') ? 'chevron-up' : 'chevron-down')); + } + }, + + click() { + const currentOrder = this.get('order'), + field = this.get('field'); + + if (currentOrder === field) { + this.set('asc', this.get('asc') ? null : true); + } else { + this.setProperties({ order: field, asc: null }); + } + } +}); diff --git a/app/assets/javascripts/discourse/components/top-period-chooser.js.es6 b/app/assets/javascripts/discourse/components/period-chooser.js.es6 similarity index 68% rename from app/assets/javascripts/discourse/components/top-period-chooser.js.es6 rename to app/assets/javascripts/discourse/components/period-chooser.js.es6 index ee63a0ae4c..1bbf20c03c 100644 --- a/app/assets/javascripts/discourse/components/top-period-chooser.js.es6 +++ b/app/assets/javascripts/discourse/components/period-chooser.js.es6 @@ -10,9 +10,9 @@ export default Ember.Component.extend(CleansUp, { }, _clickToClose: function() { - var self = this; + const self = this; $('html').off('mousedown.top-period').on('mousedown.top-period', function(e) { - var $target = $(e.target); + const $target = $(e.target); if (($target.prop('id') === 'topic-entrance') || (self.$().has($target).length !== 0)) { return; } @@ -20,12 +20,23 @@ export default Ember.Component.extend(CleansUp, { }); }, - click: function() { + click(e) { + if ($(e.target).closest('.period-popup').length) { return; } + if (!this.get('showPeriods')) { - var $chevron = this.$('i.fa-caret-down'); + const $chevron = this.$('i.fa-caret-down'); this.$('#period-popup').css($chevron.position()); this.set('showPeriods', true); this._clickToClose(); } + }, + + actions: { + changePeriod(p) { + this.cleanUp(); + this.set('period', p); + this.sendAction('action', p); + } } + }); diff --git a/app/assets/javascripts/discourse/components/top-period-buttons.js.es6 b/app/assets/javascripts/discourse/components/top-period-buttons.js.es6 index eec8000a46..3273805d73 100644 --- a/app/assets/javascripts/discourse/components/top-period-buttons.js.es6 +++ b/app/assets/javascripts/discourse/components/top-period-buttons.js.es6 @@ -1,3 +1,14 @@ export default Ember.Component.extend({ - classNames: ['top-title-buttons'] + classNames: ['top-title-buttons'], + + periods: function() { + const period = this.get('period'); + return this.site.get('periods').filter(p => p !== period); + }.property('period'), + + actions: { + changePeriod(p) { + this.sendAction('action', p); + } + } }); diff --git a/app/assets/javascripts/discourse/components/top-title-button.js.es6 b/app/assets/javascripts/discourse/components/top-title-button.js.es6 deleted file mode 100644 index 8da2fd5078..0000000000 --- a/app/assets/javascripts/discourse/components/top-title-button.js.es6 +++ /dev/null @@ -1,13 +0,0 @@ -import TopTitle from 'discourse/components/top-title'; - -export default TopTitle.extend({ - tagName: 'button', - classNameBindings: [':btn', ':btn-default', 'unless:hidden'], - - click: function() { - var url = this.get('period.showMoreUrl'); - if (url) { - Discourse.URL.routeTo(url); - } - } -}); diff --git a/app/assets/javascripts/discourse/components/top-title.js.es6 b/app/assets/javascripts/discourse/components/top-title.js.es6 deleted file mode 100644 index cfa065429f..0000000000 --- a/app/assets/javascripts/discourse/components/top-title.js.es6 +++ /dev/null @@ -1,10 +0,0 @@ -import StringBuffer from 'discourse/mixins/string-buffer'; - -export default Ember.Component.extend(StringBuffer, { - tagName: 'h2', - rerenderTriggers: ['period.title'], - - renderString: function(buffer) { - buffer.push(" " + this.get('period.title')); - } -}); diff --git a/app/assets/javascripts/discourse/controllers/directory-show.js.es6 b/app/assets/javascripts/discourse/controllers/directory-show.js.es6 new file mode 100644 index 0000000000..2ea3630764 --- /dev/null +++ b/app/assets/javascripts/discourse/controllers/directory-show.js.es6 @@ -0,0 +1,13 @@ +export default Ember.Controller.extend({ + queryParams: ['order', 'asc'], + order: 'likes_received', + asc: null, + + showTimeRead: Ember.computed.equal('period', 'all'), + + actions: { + loadMore() { + this.get('model').loadMore(); + } + } +}); diff --git a/app/assets/javascripts/discourse/controllers/discovery.js.es6 b/app/assets/javascripts/discourse/controllers/discovery.js.es6 index 45fa7d2957..abaaa1e2b4 100644 --- a/app/assets/javascripts/discourse/controllers/discovery.js.es6 +++ b/app/assets/javascripts/discourse/controllers/discovery.js.es6 @@ -1,5 +1,4 @@ import ObjectController from 'discourse/controllers/object'; -import TopPeriod from 'discourse/models/top-period'; export default ObjectController.extend({ needs: ['navigation/category', 'discovery/topics', 'application'], @@ -15,7 +14,7 @@ export default ObjectController.extend({ }.observes("loadedAllItems"), showMoreUrl(period) { - var url = '', category = this.get('category'); + let url = '', category = this.get('category'); if (category) { url = '/c/' + Discourse.Category.slugFor(category) + (this.get('noSubcategories') ? '/none' : '') + '/l'; } @@ -23,15 +22,10 @@ export default ObjectController.extend({ return url; }, - periods: function() { - const self = this, - periods = []; - this.site.get('periods').forEach(function(p) { - periods.pushObject(TopPeriod.create({ id: p, - showMoreUrl: self.showMoreUrl(p), - periods })); - }); - return periods; - }.property('category', 'noSubcategories'), + actions: { + changePeriod(p) { + Discourse.URL.routeTo(this.showMoreUrl(p)); + } + } }); diff --git a/app/assets/javascripts/discourse/helpers/period-title.js.es6 b/app/assets/javascripts/discourse/helpers/period-title.js.es6 new file mode 100644 index 0000000000..c856439349 --- /dev/null +++ b/app/assets/javascripts/discourse/helpers/period-title.js.es6 @@ -0,0 +1,11 @@ +import { iconHTML } from 'discourse/helpers/fa-icon'; + +const TITLE_SUBS = { yearly: 'this_year', + monthly: 'this_month', + daily: 'today', + all: 'all' }; + +export default Ember.Handlebars.makeBoundHelper(function (period) { + const title = I18n.t('filters.top.' + (TITLE_SUBS[period] || 'this_week')); + return new Handlebars.SafeString(iconHTML('calendar-o') + " " + title); +}); diff --git a/app/assets/javascripts/discourse/mixins/string-buffer.js.es6 b/app/assets/javascripts/discourse/mixins/string-buffer.js.es6 index a11f7419ac..469873d22f 100644 --- a/app/assets/javascripts/discourse/mixins/string-buffer.js.es6 +++ b/app/assets/javascripts/discourse/mixins/string-buffer.js.es6 @@ -1,33 +1,30 @@ export default Ember.Mixin.create({ _watchProps: function() { - var args = this.get('rerenderTriggers'); + const args = this.get('rerenderTriggers'); if (!Ember.isNone(args)) { - var self = this; - args.forEach(function(k) { - self.addObserver(k, self.rerenderString); - }); + args.forEach(k => this.addObserver(k, this.rerenderString)); } }.on('init'), - render: function(buffer) { + render(buffer) { this.renderString(buffer); }, - renderString: function(buffer){ - var template = Discourse.__container__.lookup('template:' + this.rawTemplate); + renderString(buffer){ + const template = Discourse.__container__.lookup('template:' + this.rawTemplate); if (template) { buffer.push(template(this)); } }, - _rerenderString: function() { - var buffer = []; + _rerenderString() { + const buffer = []; this.renderString(buffer); this.$().html(buffer.join('')); }, - rerenderString: function() { + rerenderString() { Ember.run.once(this, '_rerenderString'); } diff --git a/app/assets/javascripts/discourse/models/rest.js.es6 b/app/assets/javascripts/discourse/models/rest.js.es6 new file mode 100644 index 0000000000..d85475644c --- /dev/null +++ b/app/assets/javascripts/discourse/models/rest.js.es6 @@ -0,0 +1,20 @@ +export default Ember.Object.extend({ + update(attrs) { + const self = this, + type = this.get('__type'); + return this.store.update(type, this.get('id'), attrs).then(function(result) { + if (result && result[type]) { + Object.keys(result).forEach(function(k) { + attrs[k] = result[k]; + }); + } + self.setProperties(attrs); + return result; + }); + }, + + destroyRecord() { + const type = this.get('__type'); + return this.store.destroyRecord(type, this); + } +}); diff --git a/app/assets/javascripts/discourse/models/result-set.js.es6 b/app/assets/javascripts/discourse/models/result-set.js.es6 new file mode 100644 index 0000000000..210a83e4aa --- /dev/null +++ b/app/assets/javascripts/discourse/models/result-set.js.es6 @@ -0,0 +1,22 @@ +export default Ember.ArrayProxy.extend({ + loading: false, + loadingMore: false, + totalRows: 0, + + loadMore() { + const loadMoreUrl = this.get('loadMoreUrl'); + if (!loadMoreUrl) { return; } + + const totalRows = this.get('totalRows'); + if (this.get('length') < totalRows && !this.get('loadingMore')) { + this.set('loadingMore', true); + + const self = this; + return this.store.appendResults(this, this.get('__type'), loadMoreUrl).then(function() { + self.set('loadingMore', false); + }); + } + + return Ember.RSVP.resolve(); + } +}); diff --git a/app/assets/javascripts/discourse/models/store.js.es6 b/app/assets/javascripts/discourse/models/store.js.es6 index a55d8849ab..72f36db374 100644 --- a/app/assets/javascripts/discourse/models/store.js.es6 +++ b/app/assets/javascripts/discourse/models/store.js.es6 @@ -1,40 +1,49 @@ +import RestModel from 'discourse/models/rest'; +import ResultSet from 'discourse/models/result-set'; + const _identityMap = {}; -const RestModel = Ember.Object.extend({ - update(attrs) { - const self = this, - type = this.get('__type'); - return this.store.update(type, this.get('id'), attrs).then(function(result) { - if (result && result[type]) { - Object.keys(result).forEach(function(k) { - attrs[k] = result[k]; - }); - } - self.setProperties(attrs); - return result; - }); +export default Ember.Object.extend({ + pluralize(thing) { + return thing + "s"; }, - destroyRecord() { - const type = this.get('__type'); - return this.store.destroyRecord(type, this); - } -}); - -export default Ember.Object.extend({ findAll(type) { const adapter = this.container.lookup('adapter:' + type) || this.container.lookup('adapter:rest'); const self = this; return adapter.findAll(this, type).then(function(result) { - return result[Ember.String.underscore(type + 's')].map(obj => self._hydrate(type, obj)); + return self._resultSet(type, result); }); }, - find(type, id) { + find(type, findArgs) { const adapter = this.container.lookup('adapter:' + type) || this.container.lookup('adapter:rest'); const self = this; - return adapter.find(this, type, id).then(function(result) { - return self._hydrate(type, result[Ember.String.underscore(type)]); + return adapter.find(this, type, findArgs).then(function(result) { + if (typeof findArgs === "object") { + return self._resultSet(type, result); + } else { + return self._hydrate(type, result[Ember.String.underscore(type)]); + } + }); + }, + + appendResults(resultSet, type, url) { + const self = this; + + return Discourse.ajax(url).then(function(result) { + const typeName = Ember.String.underscore(self.pluralize(type)), + totalRows = result["total_rows_" + typeName] || result.get('totalRows'), + loadMoreUrl = result["load_more_" + typeName], + content = result[typeName].map(obj => self._hydrate(type, obj)); + + resultSet.setProperties({ totalRows, loadMoreUrl }); + resultSet.get('content').pushObjects(content); + + // If we've loaded them all, clear the load more URL + if (resultSet.get('length') >= totalRows) { + resultSet.set('loadMoreUrl', null); + } }); }, @@ -63,6 +72,15 @@ export default Ember.Object.extend({ }); }, + _resultSet(type, result) { + const typeName = Ember.String.underscore(this.pluralize(type)), + content = result[typeName].map(obj => this._hydrate(type, obj)), + totalRows = result["total_rows_" + typeName] || content.length, + loadMoreUrl = result["load_more_" + typeName]; + + return ResultSet.create({ content, totalRows, loadMoreUrl, store: this, __type: type }); + }, + _hydrate(type, obj) { if (!obj) { throw "Can't hydrate " + type + " of `null`"; } if (!obj.id) { throw "Can't hydrate " + type + " without an `id`"; } diff --git a/app/assets/javascripts/discourse/models/top-period.js.es6 b/app/assets/javascripts/discourse/models/top-period.js.es6 deleted file mode 100644 index ad4323b681..0000000000 --- a/app/assets/javascripts/discourse/models/top-period.js.es6 +++ /dev/null @@ -1,32 +0,0 @@ -export default Ember.Object.extend({ - title: null, - - availablePeriods: function() { - var periods = this.get('periods'); - if (!periods) { return; } - - var self = this; - return periods.filter(function(p) { - return p !== self; - }); - }.property('showMoreUrl'), - - _createTitle: function() { - var id = this.get('id'); - if (id) { - var title = "this_week"; - if (id === "yearly") { - title = "this_year"; - } else if (id === "monthly") { - title = "this_month"; - } else if (id === "daily") { - title = "today"; - } else if (id === "all") { - title = "all"; - } - - this.set('title', I18n.t("filters.top." + title)); - } - }.on('init') - -}); diff --git a/app/assets/javascripts/discourse/routes/app-route-map.js.es6 b/app/assets/javascripts/discourse/routes/app-route-map.js.es6 index f73f132b14..e6adf86307 100644 --- a/app/assets/javascripts/discourse/routes/app-route-map.js.es6 +++ b/app/assets/javascripts/discourse/routes/app-route-map.js.es6 @@ -11,6 +11,10 @@ export default function() { }); this.resource('topicBySlug', { path: '/t/:slug' }); + this.resource('directory', function() { + this.route('show', {path: '/:period'}); + }); + this.resource('discovery', { path: '/' }, function() { // top this.route('top'); diff --git a/app/assets/javascripts/discourse/routes/build-category-route.js.es6 b/app/assets/javascripts/discourse/routes/build-category-route.js.es6 index e3567ef850..8113104ea9 100644 --- a/app/assets/javascripts/discourse/routes/build-category-route.js.es6 +++ b/app/assets/javascripts/discourse/routes/build-category-route.js.es6 @@ -67,14 +67,13 @@ export default function(filter, params) { setupController: function(controller, model) { var topics = this.get('topics'), - periods = this.controllerFor('discovery').get('periods'), periodId = topics.get('for_period') || (filter.indexOf('/') > 0 ? filter.split('/')[1] : ''); this.controllerFor('navigation/category').set('canCreateTopic', topics.get('can_create_topic')); this.controllerFor('discovery/topics').setProperties({ model: topics, category: model, - period: periods.findBy('id', periodId), + period: periodId, selected: [], noSubcategories: params && !!params.no_subcategories, order: topics.get('params.order'), diff --git a/app/assets/javascripts/discourse/routes/build-topic-route.js.es6 b/app/assets/javascripts/discourse/routes/build-topic-route.js.es6 index 84127c3a85..4b21e9b0bb 100644 --- a/app/assets/javascripts/discourse/routes/build-topic-route.js.es6 +++ b/app/assets/javascripts/discourse/routes/build-topic-route.js.es6 @@ -45,13 +45,11 @@ export default function(filter, extras) { }))); } - const periods = this.controllerFor('discovery').get('periods'), - periodId = model.get('for_period') || (filter.indexOf('/') > 0 ? filter.split('/')[1] : ''); - + const period = model.get('for_period') || (filter.indexOf('/') > 0 ? filter.split('/')[1] : ''); const topicOpts = { model, category: null, - period: periods.findBy('id', periodId), + period, selected: [], expandGloballyPinned: true }; diff --git a/app/assets/javascripts/discourse/routes/directory-index.js.es6 b/app/assets/javascripts/discourse/routes/directory-index.js.es6 new file mode 100644 index 0000000000..cc8c807302 --- /dev/null +++ b/app/assets/javascripts/discourse/routes/directory-index.js.es6 @@ -0,0 +1,6 @@ +export default Discourse.Route.extend({ + beforeModel: function() { + this.controllerFor('directory-show').setProperties({ sort: null, asc: null }); + this.replaceWith('directory.show', 'all'); + } +}); diff --git a/app/assets/javascripts/discourse/routes/directory-show.js.es6 b/app/assets/javascripts/discourse/routes/directory-show.js.es6 new file mode 100644 index 0000000000..fc319f6897 --- /dev/null +++ b/app/assets/javascripts/discourse/routes/directory-show.js.es6 @@ -0,0 +1,31 @@ +export default Discourse.Route.extend({ + queryParams: { + order: { refreshModel: true }, + asc: { refreshModel: true }, + }, + + model(params) { + // If we refresh via `refreshModel` set the old model to loading + const existing = this.modelFor('directory-show'); + if (existing) { + existing.set('loading', true); + } + + this._period = params.period; + return this.store.find('directoryItem', { + id: params.period, + asc: params.asc, + order: params.order + }); + }, + + setupController(controller, model) { + controller.setProperties({ model, period: this._period }); + }, + + actions: { + changePeriod(period) { + this.transitionTo('directory.show', period); + } + } +}); diff --git a/app/assets/javascripts/discourse/templates/components/period-chooser.hbs b/app/assets/javascripts/discourse/templates/components/period-chooser.hbs new file mode 100644 index 0000000000..8f7fddc94f --- /dev/null +++ b/app/assets/javascripts/discourse/templates/components/period-chooser.hbs @@ -0,0 +1,11 @@ +

    {{period-title period}}

    + + +
    + +
    +
    diff --git a/app/assets/javascripts/discourse/templates/components/top-period-buttons.hbs b/app/assets/javascripts/discourse/templates/components/top-period-buttons.hbs index 4b6c2ffab8..169d69432e 100644 --- a/app/assets/javascripts/discourse/templates/components/top-period-buttons.hbs +++ b/app/assets/javascripts/discourse/templates/components/top-period-buttons.hbs @@ -1,3 +1,5 @@ -{{#each p in period.availablePeriods}} - {{top-title-button period=p}} +{{#each p in periods}} + {{#d-button action="changePeriod" actionParam=p}} + {{period-title p}} + {{/d-button}} {{/each}} diff --git a/app/assets/javascripts/discourse/templates/components/top-period-chooser.hbs b/app/assets/javascripts/discourse/templates/components/top-period-chooser.hbs deleted file mode 100644 index 53181310a9..0000000000 --- a/app/assets/javascripts/discourse/templates/components/top-period-chooser.hbs +++ /dev/null @@ -1,11 +0,0 @@ -{{top-title period=period}} - - -
    - -
    -
    diff --git a/app/assets/javascripts/discourse/templates/directory.hbs b/app/assets/javascripts/discourse/templates/directory.hbs new file mode 100644 index 0000000000..68207c4602 --- /dev/null +++ b/app/assets/javascripts/discourse/templates/directory.hbs @@ -0,0 +1,5 @@ +
    +
    + {{outlet}} +
    +
    diff --git a/app/assets/javascripts/discourse/templates/directory/show.hbs b/app/assets/javascripts/discourse/templates/directory/show.hbs new file mode 100644 index 0000000000..e06356f61c --- /dev/null +++ b/app/assets/javascripts/discourse/templates/directory/show.hbs @@ -0,0 +1,50 @@ +{{period-chooser period=period action="changePeriod"}} + +{{#loading-spinner condition=model.loading}} + {{#if model.length}} + {{i18n "directory.total_rows" count=model.totalRows}} + + + + + {{directory-toggle field="likes_received" order=order asc=asc}} + {{directory-toggle field="likes_given" order=order asc=asc}} + {{directory-toggle field="topic_count" order=order asc=asc}} + {{directory-toggle field="post_count" order=order asc=asc}} + {{directory-toggle field="topics_entered" order=order asc=asc}} + {{#if showTimeRead}} + + {{/if}} + + + {{#each item in model}} + + + + + + + + {{#if showTimeRead}} + + {{/if}} + + {{/each}} + +
     {{i18n "directory.time_read"}}
    + {{avatar item imageSize="tiny"}} + {{#link-to 'user' item.username}}{{unbound item.username}}{{/link-to}} + {{number item.topic_count}}{{number item.post_count}}{{number item.topics_entered}}{{unbound item.time_read}}
    + + {{loading-spinner condition=model.loadingMore}} + {{else}} +
    +

    {{i18n "directory.no_results"}}

    + {{/if}} +{{/loading-spinner}} diff --git a/app/assets/javascripts/discourse/templates/discovery/topics.hbs b/app/assets/javascripts/discourse/templates/discovery/topics.hbs index 41c9ecd37f..494da1abba 100644 --- a/app/assets/javascripts/discourse/templates/discovery/topics.hbs +++ b/app/assets/javascripts/discourse/templates/discovery/topics.hbs @@ -19,7 +19,7 @@
    {{#if top}}
    - {{top-period-chooser period=period}} + {{period-chooser period=period action="changePeriod"}}
    {{/if}} {{#if topicTrackingState.hasIncoming}} @@ -73,7 +73,7 @@ {{#if top}}

    {{#link-to "discovery.categories"}}{{i18n 'topic.browse_all_categories'}}{{/link-to}}, {{#link-to 'discovery.latest'}}{{i18n 'topic.view_latest_topics'}}{{/link-to}} {{i18n 'or'}} {{i18n 'filters.top.other_periods'}} - {{top-period-buttons period=period}} + {{top-period-buttons period=period action="changePeriod"}}

    {{else}}
    diff --git a/app/assets/javascripts/discourse/templates/mobile/discovery/topics.hbs b/app/assets/javascripts/discourse/templates/mobile/discovery/topics.hbs index 984a40198a..feb13c5d46 100644 --- a/app/assets/javascripts/discourse/templates/mobile/discovery/topics.hbs +++ b/app/assets/javascripts/discourse/templates/mobile/discovery/topics.hbs @@ -1,7 +1,7 @@
    {{#if top}}
    - {{top-period-chooser period=period}} + {{period-chooser period=period action="changePeriod"}}
    {{/if}} @@ -45,7 +45,7 @@

    {{#link-to "discovery.categories"}}{{i18n 'topic.browse_all_categories'}}{{/link-to}}, {{#link-to 'discovery.latest'}}{{i18n 'topic.view_latest_topics'}}{{/link-to}} {{i18n 'or'}} {{i18n 'filters.top.other_periods'}}
    - {{top-period-buttons period=period}} + {{top-period-buttons period=period action="changePeriod"}}

    {{else}}
    diff --git a/app/assets/javascripts/discourse/templates/site-map.hbs b/app/assets/javascripts/discourse/templates/site-map.hbs index 34660f8f63..d4be2d7bda 100644 --- a/app/assets/javascripts/discourse/templates/site-map.hbs +++ b/app/assets/javascripts/discourse/templates/site-map.hbs @@ -22,6 +22,8 @@ {{/if}} +
  • {{#link-to 'directory'}}{{i18n "directory.title"}}{{/link-to}}
  • + {{plugin-outlet "site-map-links"}} {{#if showKeyboardShortcuts}} diff --git a/app/assets/javascripts/discourse/views/directory-show.js.es6 b/app/assets/javascripts/discourse/views/directory-show.js.es6 new file mode 100644 index 0000000000..9fdb9eb2d8 --- /dev/null +++ b/app/assets/javascripts/discourse/views/directory-show.js.es6 @@ -0,0 +1,5 @@ +import LoadMore from 'discourse/mixins/load-more'; + +export default Discourse.View.extend(LoadMore, { + eyelineSelector: '.directory tbody tr' +}); diff --git a/app/assets/javascripts/main_include.js b/app/assets/javascripts/main_include.js index 489ed3c13d..b318d01a19 100644 --- a/app/assets/javascripts/main_include.js +++ b/app/assets/javascripts/main_include.js @@ -29,7 +29,6 @@ //= require ./discourse/models/post-stream //= require ./discourse/models/topic-details //= require ./discourse/models/topic -//= require ./discourse/models/top-period //= require ./discourse/controllers/controller //= require ./discourse/controllers/discovery-sortable //= require ./discourse/controllers/object @@ -51,7 +50,6 @@ //= require ./discourse/routes/user-topic-list //= require ./discourse/routes/user-activity-stream //= require ./discourse/routes/topic-from-params -//= require ./discourse/components/top-title //= require ./discourse/components/text-field //= require ./discourse/components/visible //= require ./discourse/components/conditional-loading-spinner diff --git a/app/assets/stylesheets/common/base/_topic-list.scss b/app/assets/stylesheets/common/base/_topic-list.scss index e9b1645da4..3ac9c951e0 100644 --- a/app/assets/stylesheets/common/base/_topic-list.scss +++ b/app/assets/stylesheets/common/base/_topic-list.scss @@ -226,11 +226,12 @@ ol.category-breadcrumb { } .period-chooser { - + display: inline-block; @include unselectable; h2 { float: left; + margin: 5px 0 10px; } button { @@ -274,6 +275,10 @@ ol.category-breadcrumb { .top-title-buttons { display: inline; + + button { + margin-right: 0.5em; + } } div.education { diff --git a/app/assets/stylesheets/common/base/directory.scss b/app/assets/stylesheets/common/base/directory.scss new file mode 100644 index 0000000000..d11141fbea --- /dev/null +++ b/app/assets/stylesheets/common/base/directory.scss @@ -0,0 +1,46 @@ +.directory { + margin-bottom: 100px; + + .period-chooser { + float: left; + } + .total-rows { + margin-top: 0.5em; + color: darken(scale-color-diff(), 20%); + float: right; + } + .spinner { + clear: both; + } + + table { + width: 100%; + margin-top: 1em; + margin-bottom: 1em; + + td, th { + padding: 0.5em; + text-align: left; + border-bottom: 1px solid scale-color-diff(); + } + + th.sortable { + cursor: pointer; + + width: 13%; + i.fa { + margin-left: 1em; + } + + &:hover { + background-color: scale-color-diff(); + } + } + + td.likes { + i { + color: $love; + } + } + } +} diff --git a/app/controllers/directory_controller.rb b/app/controllers/directory_controller.rb new file mode 100644 index 0000000000..aea4bbc201 --- /dev/null +++ b/app/controllers/directory_controller.rb @@ -0,0 +1,8 @@ +class DirectoryController < ApplicationController + # This controller just exists to avoid 404s and to have the ember app load up + def index + end + + def show + end +end diff --git a/app/controllers/directory_items_controller.rb b/app/controllers/directory_items_controller.rb new file mode 100644 index 0000000000..221149d223 --- /dev/null +++ b/app/controllers/directory_items_controller.rb @@ -0,0 +1,35 @@ +class DirectoryItemsController < ApplicationController + PAGE_SIZE = 50 + + def index + id = params.require(:id) + period_type = DirectoryItem.period_types[id.to_sym] + raise Discourse::InvalidAccess.new(:period_type) unless period_type + + result = DirectoryItem.where(period_type: period_type).includes(:user) + + order = params[:order] || DirectoryItem.headings.first + if DirectoryItem.headings.include?(order.to_sym) + dir = params[:asc] ? 'ASC' : 'DESC' + result = result.order("directory_items.#{order} #{dir}") + end + + if period_type == DirectoryItem.period_types[:all] + result = result.includes(:user_stat) + end + page = params[:page].to_i + result = result.order('users.username') + result_count = result.dup.count + result = result.limit(PAGE_SIZE).offset(PAGE_SIZE * page) + + serialized = serialize_data(result, DirectoryItemSerializer) + + more_params = params.slice(:id, :order, :asc) + more_params[:page] = page + 1 + + render_json_dump directory_items: serialized, + total_rows_directory_items: result_count, + load_more_directory_items: directory_items_path(more_params) + + end +end diff --git a/app/jobs/scheduled/directory_refresh.rb b/app/jobs/scheduled/directory_refresh.rb new file mode 100644 index 0000000000..2809ac210a --- /dev/null +++ b/app/jobs/scheduled/directory_refresh.rb @@ -0,0 +1,9 @@ +module Jobs + class DirectoryRefresh < Jobs::Scheduled + every 1.hour + + def execute(args) + DirectoryItem.refresh! + end + end +end diff --git a/app/models/directory_item.rb b/app/models/directory_item.rb new file mode 100644 index 0000000000..d2b8c02a56 --- /dev/null +++ b/app/models/directory_item.rb @@ -0,0 +1,57 @@ +class DirectoryItem < ActiveRecord::Base + belongs_to :user + has_one :user_stat, foreign_key: :user_id, primary_key: :user_id + + def self.headings + @headings ||= [:likes_received, + :likes_given, + :topics_entered, + :topic_count, + :post_count] + end + + def self.period_types + @types ||= Enum.new(:all, :yearly, :monthly, :weekly, :daily) + end + + def self.refresh! + ActiveRecord::Base.transaction do + exec_sql "TRUNCATE TABLE directory_items" + period_types.keys.each {|p| refresh_period!(p)} + end + end + + def self.refresh_period!(period_type) + since = case period_type + when :daily then 1.day.ago + when :weekly then 1.week.ago + when :monthly then 1.month.ago + when :yearly then 1.year.ago + else 1000.years.ago + end + + exec_sql "INSERT INTO directory_items + (period_type, user_id, likes_received, likes_given, topics_entered, topic_count, post_count) + SELECT + :period_type, + u.id, + SUM(CASE WHEN ua.action_type = :was_liked_type THEN 1 ELSE 0 END), + SUM(CASE WHEN ua.action_type = :like_type THEN 1 ELSE 0 END), + (SELECT COUNT(topic_id) FROM topic_views AS v WHERE v.user_id = u.id AND v.viewed_at > :since), + SUM(CASE WHEN ua.action_type = :new_topic_type THEN 1 ELSE 0 END), + SUM(CASE WHEN ua.action_type = :reply_type THEN 1 ELSE 0 END) + FROM users AS u + LEFT OUTER JOIN user_actions AS ua ON ua.user_id = u.id + WHERE u.active + AND NOT u.blocked + AND COALESCE(ua.created_at, :since) >= :since + AND u.id > 0 + GROUP BY u.id", + period_type: period_types[period_type], + since: since, + like_type: UserAction::LIKE, + was_liked_type: UserAction::WAS_LIKED, + new_topic_type: UserAction::NEW_TOPIC, + reply_type: UserAction::REPLY + end +end diff --git a/app/serializers/directory_item_serializer.rb b/app/serializers/directory_item_serializer.rb new file mode 100644 index 0000000000..242196a83f --- /dev/null +++ b/app/serializers/directory_item_serializer.rb @@ -0,0 +1,35 @@ +class DirectoryItemSerializer < ApplicationSerializer + + attributes :id, + :username, + :uploaded_avatar_id, + :avatar_template, + :time_read + + attributes *DirectoryItem.headings + + def id + object.user_id + end + + def username + object.user.username + end + + def uploaded_avatar_id + object.user.uploaded_avatar_id + end + + def avatar_template + object.user.avatar_template + end + + def time_read + AgeWords.age_words(object.user_stat.time_read) + end + + def include_time_read? + object.period_type == DirectoryItem.period_types[:all] + end + +end diff --git a/app/serializers/directory_serializer.rb b/app/serializers/directory_serializer.rb new file mode 100644 index 0000000000..415d9b7bf6 --- /dev/null +++ b/app/serializers/directory_serializer.rb @@ -0,0 +1,9 @@ +class DirectorySerializer < ApplicationSerializer + attributes :id + has_many :directory_items, serializer: DirectoryItemSerializer, embed: :objects + + def id + object.filter + end + +end diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml index 1b01d8f579..2320f3730d 100644 --- a/config/locales/client.en.yml +++ b/config/locales/client.en.yml @@ -237,6 +237,19 @@ en: sent_by_user: "Sent by {{user}}" sent_by_you: "Sent by you" + directory: + title: "User Directory" + likes_given: "Likes Given" + likes_received: "Likes Received" + topics_entered: "Topics Entered" + time_read: "Time Read" + topic_count: "Topics" + post_count: "Replies" + no_results: "No results were found for this time period." + total_rows: + one: "1 user found" + other: "%{count} users found" + groups: visible: "Group is visible to all users" title: diff --git a/config/routes.rb b/config/routes.rb index 427a319605..a3cfd922be 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -25,6 +25,9 @@ Discourse::Application.routes.draw do resources :about + resources :directory + resources :directory_items + get "site" => "site#site" namespace :site do get "settings" diff --git a/db/migrate/20150318143915_create_directory_items.rb b/db/migrate/20150318143915_create_directory_items.rb new file mode 100644 index 0000000000..37f08336a1 --- /dev/null +++ b/db/migrate/20150318143915_create_directory_items.rb @@ -0,0 +1,16 @@ +class CreateDirectoryItems < ActiveRecord::Migration + def change + create_table :directory_items do |t| + t.integer :period_type, null: false + t.references :user, null: false + t.integer :likes_received, null: false + t.integer :likes_given, null: false + t.integer :topics_entered, null: false + t.integer :topic_count, null: false + t.integer :post_count, null: false + t.timestamps + end + + add_index :directory_items, :period_type + end +end diff --git a/spec/controllers/directory_items_controller_spec.rb b/spec/controllers/directory_items_controller_spec.rb new file mode 100644 index 0000000000..bc36d9b861 --- /dev/null +++ b/spec/controllers/directory_items_controller_spec.rb @@ -0,0 +1,31 @@ +require 'spec_helper' + +describe DirectoryItemsController do + + it "requires an `id` param" do + ->{ xhr :get, :index }.should raise_error + end + + it "requires a proper `id` param" do + xhr :get, :index, id: 'eviltrout' + response.should_not be_success + end + + context "with data" do + before do + Fabricate(:user) + DirectoryItem.refresh! + end + + it "succeeds with a valid value" do + xhr :get, :index, id: 'all' + response.should be_success + json = ::JSON.parse(response.body) + + json.should be_present + json['directory_items'].should be_present + json['total_rows_directory_items'].should be_present + json['load_more_directory_items'].should be_present + end + end +end diff --git a/spec/models/directory_item_spec.rb b/spec/models/directory_item_spec.rb new file mode 100644 index 0000000000..624027c241 --- /dev/null +++ b/spec/models/directory_item_spec.rb @@ -0,0 +1,15 @@ +require 'spec_helper' + +describe DirectoryItem do + context 'refresh' do + let!(:user) { Fabricate(:user) } + + it "creates the record for the user" do + DirectoryItem.refresh! + expect(DirectoryItem.where(period_type: DirectoryItem.period_types[:all]) + .where(user_id: user.id) + .exists?).to be_true + end + + end +end diff --git a/test/javascripts/fixtures/directory-fixtures.js.es6 b/test/javascripts/fixtures/directory-fixtures.js.es6 new file mode 100644 index 0000000000..cb70d2aa7e --- /dev/null +++ b/test/javascripts/fixtures/directory-fixtures.js.es6 @@ -0,0 +1,3 @@ +export default { + "directory_items": {"directory_items":[{"id":32,"username":"codinghorror","uploaded_avatar_id":null,"avatar_template":"/letter_avatar/codinghorror/{size}/2.png","time_read":"55d","likes_received":9370,"likes_given":7725,"topics_entered":11453,"topic_count":184,"post_count":12263},{"id":1,"username":"sam","uploaded_avatar_id":null,"avatar_template":"/letter_avatar/sam/{size}/2.png","time_read":"52d","likes_received":7834,"likes_given":2693,"topics_entered":11024,"topic_count":276,"post_count":7802},{"id":19,"username":"eviltrout","uploaded_avatar_id":null,"avatar_template":"/letter_avatar/eviltrout/{size}/2.png","time_read":"25d","likes_received":2383,"likes_given":319,"topics_entered":8041,"topic_count":34,"post_count":1602},{"id":6626,"username":"riking","uploaded_avatar_id":null,"avatar_template":"/letter_avatar/riking/{size}/2.png","time_read":"17d","likes_received":2101,"likes_given":2756,"topics_entered":9055,"topic_count":163,"post_count":2548},{"id":1995,"username":"zogstrip","uploaded_avatar_id":null,"avatar_template":"/letter_avatar/zogstrip/{size}/2.png","time_read":"32d","likes_received":1838,"likes_given":4588,"topics_entered":10823,"topic_count":16,"post_count":2050},{"id":8300,"username":"cpradio","uploaded_avatar_id":null,"avatar_template":"/letter_avatar/cpradio/{size}/2.png","time_read":"11d","likes_received":1538,"likes_given":1001,"topics_entered":6121,"topic_count":111,"post_count":1430},{"id":2,"username":"neil","uploaded_avatar_id":null,"avatar_template":"/letter_avatar/neil/{size}/2.png","time_read":"24d","likes_received":1238,"likes_given":684,"topics_entered":3250,"topic_count":27,"post_count":969},{"id":4263,"username":"mcwumbly","uploaded_avatar_id":null,"avatar_template":"/letter_avatar/mcwumbly/{size}/2.png","time_read":"15d","likes_received":1223,"likes_given":1296,"topics_entered":5924,"topic_count":81,"post_count":1031},{"id":5351,"username":"erlend_sh","uploaded_avatar_id":null,"avatar_template":"/letter_avatar/erlend_sh/{size}/2.png","time_read":"9d","likes_received":1115,"likes_given":747,"topics_entered":3260,"topic_count":154,"post_count":721},{"id":5559,"username":"downey","uploaded_avatar_id":null,"avatar_template":"/letter_avatar/downey/{size}/2.png","time_read":"5d","likes_received":983,"likes_given":1713,"topics_entered":2995,"topic_count":131,"post_count":850},{"id":2770,"username":"awesomerobot","uploaded_avatar_id":null,"avatar_template":"/letter_avatar/awesomerobot/{size}/2.png","time_read":"9d","likes_received":952,"likes_given":195,"topics_entered":2411,"topic_count":13,"post_count":402},{"id":9775,"username":"elberet","uploaded_avatar_id":null,"avatar_template":"/letter_avatar/elberet/{size}/2.png","time_read":"7d","likes_received":930,"likes_given":159,"topics_entered":4077,"topic_count":28,"post_count":755},{"id":8222,"username":"techAPJ","uploaded_avatar_id":null,"avatar_template":"/letter_avatar/techapj/{size}/2.png","time_read":"12d","likes_received":791,"likes_given":1005,"topics_entered":3691,"topic_count":43,"post_count":463},{"id":6060,"username":"lightyear","uploaded_avatar_id":null,"avatar_template":"/letter_avatar/lightyear/{size}/2.png","time_read":"3d","likes_received":708,"likes_given":330,"topics_entered":1717,"topic_count":34,"post_count":312},{"id":8,"username":"geek","uploaded_avatar_id":null,"avatar_template":"/letter_avatar/geek/{size}/2.png","time_read":"20d","likes_received":634,"likes_given":152,"topics_entered":920,"topic_count":48,"post_count":298},{"id":464,"username":"DeanMarkTaylor","uploaded_avatar_id":null,"avatar_template":"/letter_avatar/deanmarktaylor/{size}/2.png","time_read":"10d","likes_received":578,"likes_given":299,"topics_entered":2976,"topic_count":116,"post_count":485},{"id":11160,"username":"boomzilla","uploaded_avatar_id":null,"avatar_template":"/letter_avatar/boomzilla/{size}/2.png","time_read":"1d","likes_received":561,"likes_given":398,"topics_entered":822,"topic_count":23,"post_count":185},{"id":4457,"username":"Lee_Ars","uploaded_avatar_id":null,"avatar_template":"/letter_avatar/lee_ars/{size}/2.png","time_read":"3d","likes_received":530,"likes_given":163,"topics_entered":2250,"topic_count":46,"post_count":327},{"id":8571,"username":"tobiaseigen","uploaded_avatar_id":null,"avatar_template":"/letter_avatar/tobiaseigen/{size}/2.png","time_read":"6d","likes_received":524,"likes_given":1275,"topics_entered":2545,"topic_count":140,"post_count":435},{"id":3,"username":"supermathie","uploaded_avatar_id":null,"avatar_template":"/letter_avatar/supermathie/{size}/2.png","time_read":"20d","likes_received":510,"likes_given":312,"topics_entered":1733,"topic_count":62,"post_count":438},{"id":8493,"username":"PJH","uploaded_avatar_id":null,"avatar_template":"/letter_avatar/pjh/{size}/2.png","time_read":"3d","likes_received":458,"likes_given":96,"topics_entered":1219,"topic_count":74,"post_count":318},{"id":8617,"username":"Mittineague","uploaded_avatar_id":null,"avatar_template":"/letter_avatar/mittineague/{size}/2.png","time_read":"16d","likes_received":415,"likes_given":291,"topics_entered":6662,"topic_count":22,"post_count":757},{"id":10778,"username":"Lid","uploaded_avatar_id":null,"avatar_template":"/letter_avatar/lid/{size}/2.png","time_read":"8d","likes_received":398,"likes_given":296,"topics_entered":1771,"topic_count":82,"post_count":307},{"id":6548,"username":"michaeld","uploaded_avatar_id":null,"avatar_template":"/letter_avatar/michaeld/{size}/2.png","time_read":"3d","likes_received":387,"likes_given":165,"topics_entered":1407,"topic_count":48,"post_count":330},{"id":471,"username":"BhaelOchon","uploaded_avatar_id":null,"avatar_template":"/letter_avatar/bhaelochon/{size}/2.png","time_read":"22d","likes_received":386,"likes_given":765,"topics_entered":8051,"topic_count":55,"post_count":486},{"id":4881,"username":"gerhard","uploaded_avatar_id":null,"avatar_template":"/letter_avatar/gerhard/{size}/2.png","time_read":"6d","likes_received":360,"likes_given":393,"topics_entered":3030,"topic_count":57,"post_count":250},{"id":5707,"username":"trident","uploaded_avatar_id":null,"avatar_template":"/letter_avatar/trident/{size}/2.png","time_read":"6d","likes_received":344,"likes_given":181,"topics_entered":4905,"topic_count":2,"post_count":549},{"id":3987,"username":"Sander78","uploaded_avatar_id":null,"avatar_template":"/letter_avatar/sander78/{size}/2.png","time_read":"3d","likes_received":326,"likes_given":276,"topics_entered":3613,"topic_count":94,"post_count":392},{"id":3415,"username":"radq","uploaded_avatar_id":null,"avatar_template":"/letter_avatar/radq/{size}/2.png","time_read":"3d","likes_received":299,"likes_given":110,"topics_entered":2503,"topic_count":16,"post_count":157},{"id":2989,"username":"meglio","uploaded_avatar_id":null,"avatar_template":"/letter_avatar/meglio/{size}/2.png","time_read":"3d","likes_received":280,"likes_given":436,"topics_entered":1086,"topic_count":198,"post_count":458},{"id":4,"username":"stienman","uploaded_avatar_id":null,"avatar_template":"/letter_avatar/stienman/{size}/2.png","time_read":"15d","likes_received":276,"likes_given":100,"topics_entered":291,"topic_count":13,"post_count":132},{"id":10855,"username":"abarker","uploaded_avatar_id":null,"avatar_template":"/letter_avatar/abarker/{size}/2.png","time_read":"1d","likes_received":270,"likes_given":131,"topics_entered":703,"topic_count":14,"post_count":77},{"id":9653,"username":"TechnoBear","uploaded_avatar_id":null,"avatar_template":"/letter_avatar/technobear/{size}/2.png","time_read":"4d","likes_received":263,"likes_given":507,"topics_entered":2931,"topic_count":51,"post_count":220},{"id":7948,"username":"probus","uploaded_avatar_id":null,"avatar_template":"/letter_avatar/probus/{size}/2.png","time_read":"6d","likes_received":261,"likes_given":71,"topics_entered":2399,"topic_count":51,"post_count":206},{"id":9741,"username":"chapel","uploaded_avatar_id":null,"avatar_template":"/letter_avatar/chapel/{size}/2.png","time_read":"2d","likes_received":239,"likes_given":169,"topics_entered":1228,"topic_count":11,"post_count":167},{"id":8810,"username":"fantasticfears","uploaded_avatar_id":null,"avatar_template":"/letter_avatar/fantasticfears/{size}/2.png","time_read":"4d","likes_received":213,"likes_given":184,"topics_entered":2161,"topic_count":29,"post_count":227},{"id":38,"username":"frandallfarmer","uploaded_avatar_id":null,"avatar_template":"/letter_avatar/frandallfarmer/{size}/2.png","time_read":"19d","likes_received":212,"likes_given":104,"topics_entered":3169,"topic_count":6,"post_count":114},{"id":8085,"username":"watchmanmonitor","uploaded_avatar_id":null,"avatar_template":"/letter_avatar/watchmanmonitor/{size}/2.png","time_read":"2d","likes_received":202,"likes_given":654,"topics_entered":1453,"topic_count":73,"post_count":278},{"id":8909,"username":"AdamCapriola","uploaded_avatar_id":null,"avatar_template":"/letter_avatar/adamcapriola/{size}/2.png","time_read":"3d","likes_received":200,"likes_given":179,"topics_entered":1689,"topic_count":49,"post_count":169},{"id":14,"username":"clay","uploaded_avatar_id":null,"avatar_template":"/letter_avatar/clay/{size}/2.png","time_read":"14d","likes_received":183,"likes_given":103,"topics_entered":780,"topic_count":24,"post_count":97},{"id":6613,"username":"haiku","uploaded_avatar_id":null,"avatar_template":"/letter_avatar/haiku/{size}/2.png","time_read":"3d","likes_received":183,"likes_given":308,"topics_entered":1919,"topic_count":33,"post_count":188},{"id":13132,"username":"purldator","uploaded_avatar_id":null,"avatar_template":"/letter_avatar/purldator/{size}/2.png","time_read":"4d","likes_received":178,"likes_given":685,"topics_entered":1891,"topic_count":20,"post_count":299},{"id":810,"username":"ChrisHanel","uploaded_avatar_id":null,"avatar_template":"/letter_avatar/chrishanel/{size}/2.png","time_read":"16d","likes_received":169,"likes_given":42,"topics_entered":639,"topic_count":9,"post_count":94},{"id":2625,"username":"kpfleming","uploaded_avatar_id":null,"avatar_template":"/letter_avatar/kpfleming/{size}/2.png","time_read":"10d","likes_received":165,"likes_given":288,"topics_entered":2539,"topic_count":15,"post_count":233},{"id":7717,"username":"lake54","uploaded_avatar_id":null,"avatar_template":"/letter_avatar/lake54/{size}/2.png","time_read":"2d","likes_received":148,"likes_given":440,"topics_entered":1604,"topic_count":33,"post_count":194},{"id":8018,"username":"shivermetimbers","uploaded_avatar_id":null,"avatar_template":"/letter_avatar/shivermetimbers/{size}/2.png","time_read":"15h","likes_received":139,"likes_given":40,"topics_entered":185,"topic_count":30,"post_count":181},{"id":2316,"username":"pakl","uploaded_avatar_id":null,"avatar_template":"/letter_avatar/pakl/{size}/2.png","time_read":"14d","likes_received":135,"likes_given":198,"topics_entered":1034,"topic_count":46,"post_count":130},{"id":3681,"username":"Ajarn","uploaded_avatar_id":null,"avatar_template":"/letter_avatar/ajarn/{size}/2.png","time_read":"3d","likes_received":126,"likes_given":664,"topics_entered":1893,"topic_count":46,"post_count":291},{"id":7229,"username":"DavidGNavas","uploaded_avatar_id":null,"avatar_template":"/letter_avatar/davidgnavas/{size}/2.png","time_read":"4d","likes_received":124,"likes_given":210,"topics_entered":2032,"topic_count":17,"post_count":60},{"id":3062,"username":"Sailsman63","uploaded_avatar_id":null,"avatar_template":"/letter_avatar/sailsman63/{size}/2.png","time_read":"8d","likes_received":124,"likes_given":139,"topics_entered":4257,"topic_count":10,"post_count":146}],"total_rows_directory_items":12546,"load_more_directory_items":"/directory_items?id=all&order=likes_received&page=1"} +}; diff --git a/test/javascripts/helpers/create-pretender.js.es6 b/test/javascripts/helpers/create-pretender.js.es6 index 06ebebbd74..cc51c3db0b 100644 --- a/test/javascripts/helpers/create-pretender.js.es6 +++ b/test/javascripts/helpers/create-pretender.js.es6 @@ -7,6 +7,10 @@ function parsePostData(query) { return result; } +function clone(obj) { + return JSON.parse(JSON.stringify(obj)); +} + function response(code, obj) { if (typeof code === "object") { obj = code; @@ -24,6 +28,11 @@ const _widgets = [ {id: 124, name: 'Evil Repellant'} ]; +const _moreWidgets = [ + {id: 223, name: 'Bass Lure'}, + {id: 224, name: 'Good Repellant'} +]; + export default function() { const server = new Pretender(function() { @@ -101,12 +110,23 @@ export default function() { this.put('/widgets/:widget_id', function(request) { const w = _widgets.findBy('id', parseInt(request.params.widget_id)); - const cloned = JSON.parse(JSON.stringify(w)); - return response({ widget: cloned }); + return response({ widget: clone(w) }); }); - this.get('/widgets', function() { - return response({ widgets: _widgets }); + this.get('/widgets', function(request) { + let result = _widgets; + + const qp = request.queryParams; + if (qp) { + if (qp.name) { result = result.filterBy('name', qp.name); } + if (qp.id) { result = result.filterBy('id', parseInt(qp.id)); } + } + + return response({ widgets: result, total_rows_widgets: 4, load_more_widgets: '/load-more-widgets' }); + }); + + this.get('/load-more-widgets', function() { + return response({ widgets: _moreWidgets, total_rows_widgets: 4, load_more_widgets: '/load-more-widgets' }); }); this.delete('/widgets/:widget_id', success); diff --git a/test/javascripts/integration/directory-test.js.es6 b/test/javascripts/integration/directory-test.js.es6 new file mode 100644 index 0000000000..84c3c30071 --- /dev/null +++ b/test/javascripts/integration/directory-test.js.es6 @@ -0,0 +1,8 @@ +integration("User Directory"); + +test("Visit Page", function() { + visit("/directory/all"); + andThen(function() { + ok(exists('.directory table tr'), "has a list of users"); + }); +}); diff --git a/test/javascripts/models/result-set-test.js.es6 b/test/javascripts/models/result-set-test.js.es6 new file mode 100644 index 0000000000..7ce1f4ebf1 --- /dev/null +++ b/test/javascripts/models/result-set-test.js.es6 @@ -0,0 +1,28 @@ +module('result-set'); + +import ResultSet from 'discourse/models/result-set'; +import createStore from 'helpers/create-store'; + +test('defaults', function() { + const rs = ResultSet.create({ content: [] }); + equal(rs.get('length'), 0); + equal(rs.get('totalRows'), 0); + ok(!rs.get('loadMoreUrl')); + ok(!rs.get('loading')); + ok(!rs.get('loadingMore')); +}); + +test('pagination support', function() { + const store = createStore(); + store.findAll('widget').then(function(rs) { + equal(rs.get('length'), 2); + equal(rs.get('totalRows'), 4); + ok(rs.get('loadMoreUrl'), 'has a url to load more'); + + rs.loadMore().then(function() { + equal(rs.get('length'), 4); + ok(!rs.get('loadMoreUrl')); + }); + }); + +}); diff --git a/test/javascripts/models/store-test.js.es6 b/test/javascripts/models/store-test.js.es6 index 20f5cce30d..d9e68fc785 100644 --- a/test/javascripts/models/store-test.js.es6 +++ b/test/javascripts/models/store-test.js.es6 @@ -19,7 +19,20 @@ test('find', function() { store.find('widget', 123).then(function(w2) { equal(w, w2); }); + }); +}); +test('find with object id', function() { + const store = createStore(); + store.find('widget', {id: 123}).then(function(w) { + equal(w.get('firstObject.name'), 'Trout Lure'); + }); +}); + +test('find with query param', function() { + const store = createStore(); + store.find('widget', {name: 'Trout Lure'}).then(function(w) { + equal(w.get('firstObject.id'), 123); }); }); @@ -33,7 +46,7 @@ test('update', function() { test('findAll', function() { const store = createStore(); store.findAll('widget').then(function(result) { - equal(result.length, 2); + equal(result.get('length'), 2); const w = result.findBy('id', 124); equal(w.get('name'), 'Evil Repellant'); }); From a412e9bede825c074997499550f100b0c92528a5 Mon Sep 17 00:00:00 2001 From: Gerhard Schlager Date: Wed, 18 Mar 2015 20:30:42 +0100 Subject: [PATCH 052/114] Fix gem load order for all importers https://meta.discourse.org/t/migrating-from-mybb/25563/8 --- script/import_scripts/discuz_x.rb | 3 +-- script/import_scripts/drupal.rb | 3 +-- script/import_scripts/drupal_qa.rb | 3 +-- script/import_scripts/kunena.rb | 3 +-- script/import_scripts/phpbb3.rb | 3 +-- script/import_scripts/vanilla.rb | 2 +- script/import_scripts/vbulletin.rb | 2 +- script/import_scripts/vbulletin_old.rb | 2 +- 8 files changed, 8 insertions(+), 13 deletions(-) diff --git a/script/import_scripts/discuz_x.rb b/script/import_scripts/discuz_x.rb index 6aef9b15e3..f1232a39ec 100644 --- a/script/import_scripts/discuz_x.rb +++ b/script/import_scripts/discuz_x.rb @@ -7,9 +7,8 @@ # This script is tested only on Simplified Chinese Discuz! X instances # If you want to import data other than Simplified Chinese, email me. -require File.expand_path(File.dirname(__FILE__) + "/base.rb") - require 'mysql2' +require File.expand_path(File.dirname(__FILE__) + "/base.rb") class ImportScripts::DiscuzX < ImportScripts::Base diff --git a/script/import_scripts/drupal.rb b/script/import_scripts/drupal.rb index 4a455c2042..3660761350 100644 --- a/script/import_scripts/drupal.rb +++ b/script/import_scripts/drupal.rb @@ -1,6 +1,5 @@ -require File.expand_path(File.dirname(__FILE__) + "/base.rb") - require "mysql2" +require File.expand_path(File.dirname(__FILE__) + "/base.rb") class ImportScripts::Drupal < ImportScripts::Base diff --git a/script/import_scripts/drupal_qa.rb b/script/import_scripts/drupal_qa.rb index 6b87f36528..9ce0b556e8 100644 --- a/script/import_scripts/drupal_qa.rb +++ b/script/import_scripts/drupal_qa.rb @@ -1,8 +1,7 @@ +require "mysql2" require File.expand_path(File.dirname(__FILE__) + "/base.rb") require File.expand_path(File.dirname(__FILE__) + "/drupal.rb") -require "mysql2" - class ImportScripts::DrupalQA < ImportScripts::Drupal def categories_query diff --git a/script/import_scripts/kunena.rb b/script/import_scripts/kunena.rb index f5b5e3a441..8e1f6275b3 100644 --- a/script/import_scripts/kunena.rb +++ b/script/import_scripts/kunena.rb @@ -1,6 +1,5 @@ -require File.expand_path(File.dirname(__FILE__) + "/base.rb") - require "mysql2" +require File.expand_path(File.dirname(__FILE__) + "/base.rb") class ImportScripts::Kunena < ImportScripts::Base diff --git a/script/import_scripts/phpbb3.rb b/script/import_scripts/phpbb3.rb index bc0259c7db..10a0f3c401 100644 --- a/script/import_scripts/phpbb3.rb +++ b/script/import_scripts/phpbb3.rb @@ -1,6 +1,5 @@ -require File.expand_path(File.dirname(__FILE__) + "/base.rb") require "mysql2" - +require File.expand_path(File.dirname(__FILE__) + "/base.rb") class ImportScripts::PhpBB3 < ImportScripts::Base diff --git a/script/import_scripts/vanilla.rb b/script/import_scripts/vanilla.rb index 264cb80eea..e60fcebca8 100644 --- a/script/import_scripts/vanilla.rb +++ b/script/import_scripts/vanilla.rb @@ -1,5 +1,5 @@ -require File.expand_path(File.dirname(__FILE__) + "/base.rb") require "csv" +require File.expand_path(File.dirname(__FILE__) + "/base.rb") class ImportScripts::Vanilla < ImportScripts::Base diff --git a/script/import_scripts/vbulletin.rb b/script/import_scripts/vbulletin.rb index 77fc6119de..84001c16bd 100644 --- a/script/import_scripts/vbulletin.rb +++ b/script/import_scripts/vbulletin.rb @@ -1,5 +1,5 @@ -require File.expand_path(File.dirname(__FILE__) + "/base.rb") require 'mysql2' +require File.expand_path(File.dirname(__FILE__) + "/base.rb") require 'htmlentities' class ImportScripts::VBulletin < ImportScripts::Base diff --git a/script/import_scripts/vbulletin_old.rb b/script/import_scripts/vbulletin_old.rb index b2989199d7..94013fb785 100644 --- a/script/import_scripts/vbulletin_old.rb +++ b/script/import_scripts/vbulletin_old.rb @@ -1,6 +1,6 @@ +require "csv" require File.expand_path(File.dirname(__FILE__) + "/base.rb") require "optparse" -require "csv" class ImportScripts::VBulletinOld < ImportScripts::Base From 9913dfa6c63d7a11789996da83ff3d2d545e9e1c Mon Sep 17 00:00:00 2001 From: Gerhard Schlager Date: Wed, 18 Mar 2015 20:48:26 +0100 Subject: [PATCH 053/114] Imported users shouldn't get an email immediately after the import This sets the last_emailed_at for imported users to now which postpones the sending of digest emails for the configured amount of time. Therefore, the first digest email gets sent after 1 week (the default value of default_digest_email_frequency). As suggested in https://meta.discourse.org/t/dont-trigger-digests-on-migration/26345/7 --- script/import_scripts/base.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/script/import_scripts/base.rb b/script/import_scripts/base.rb index a3120edd24..eebc0a08c4 100644 --- a/script/import_scripts/base.rb +++ b/script/import_scripts/base.rb @@ -293,6 +293,7 @@ class ImportScripts::Base opts[:trust_level] = TrustLevel[1] unless opts[:trust_level] opts[:active] = opts.fetch(:active, true) opts[:import_mode] = true + opts[:last_emailed_at] = opts.fetch(:last_emailed_at, Time.now) u = User.new(opts) u.custom_fields["import_id"] = import_id From b31c05704a00f08f4f66a33686fc6a8f017690e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9gis=20Hanol?= Date: Wed, 18 Mar 2015 22:46:24 +0100 Subject: [PATCH 054/114] UX: fix [Object object] on admin/groups buttons --- app/assets/javascripts/admin/templates/groups.hbs | 4 ++-- config/locales/client.en.yml | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/app/assets/javascripts/admin/templates/groups.hbs b/app/assets/javascripts/admin/templates/groups.hbs index 0de3fc5c79..754ad67441 100644 --- a/app/assets/javascripts/admin/templates/groups.hbs +++ b/app/assets/javascripts/admin/templates/groups.hbs @@ -1,6 +1,6 @@ {{#admin-nav}} - {{admin-nav-item route='adminGroupsType' routeParam='custom' label='admin.groups.custom'}} - {{admin-nav-item route='adminGroupsType' routeParam='automatic' label='admin.groups.automatic'}} + {{admin-nav-item route='adminGroupsType' routeParam='custom' label='admin.groups.custom.label'}} + {{admin-nav-item route='adminGroupsType' routeParam='automatic' label='admin.groups.automatic.label'}} {{/admin-nav}}
    diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml index 2320f3730d..60d311b7b3 100644 --- a/config/locales/client.en.yml +++ b/config/locales/client.en.yml @@ -1692,14 +1692,14 @@ en: name: "Name" add: "Add" add_members: "Add members" - custom: "Custom" - automatic: "Automatic" - automatic_membership_email_domains: "Users who register with an email domain that exactly matches one in this list will be automatically added to this group:" - automatic_membership_retroactive: "Apply the same email domain rule to add existing registered users" custom: + label: "Custom" title: "Custom Groups" automatic: + label: "Automatic" title: "Automatic Groups" + automatic_membership_email_domains: "Users who register with an email domain that exactly matches one in this list will be automatically added to this group:" + automatic_membership_retroactive: "Apply the same email domain rule to add existing registered users" api: generate_master: "Generate Master API Key" From b2845a3dec3af1d37b7eea579b86afc4bda4dd1d Mon Sep 17 00:00:00 2001 From: Jeff Atwood Date: Wed, 18 Mar 2015 15:05:17 -0700 Subject: [PATCH 055/114] make link to mailjet https --- config/locales/server.en.yml | 2 +- config/locales/server.fi.yml | 2 +- config/locales/server.fr.yml | 2 +- config/locales/server.pt_BR.yml | 2 +- config/locales/server.tr_TR.yml | 2 +- config/locales/server.zh_CN.yml | 2 +- docs/ADMIN-QUICK-START-GUIDE.md | 2 +- docs/INSTALL-digital-ocean.md | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/config/locales/server.en.yml b/config/locales/server.en.yml index b788332c80..c539494b3b 100644 --- a/config/locales/server.en.yml +++ b/config/locales/server.en.yml @@ -1344,7 +1344,7 @@ en: [8]: http://www.openspf.org/SPF_Record_Syntax [md]: http://mandrill.com [mg]: http://www.mailgun.com/ - [mj]: http://www.mailjet.com/pricing + [mj]: https://www.mailjet.com/pricing new_version_mailer: subject_template: "[%{site_name}] New Discourse version, update available" diff --git a/config/locales/server.fi.yml b/config/locales/server.fi.yml index 6af7a6255c..0ef26e81c0 100644 --- a/config/locales/server.fi.yml +++ b/config/locales/server.fi.yml @@ -1142,7 +1142,7 @@ fi: [8]: http://www.openspf.org/SPF_Record_Syntax [md]: http://mandrill.com [mg]: http://www.mailgun.com/ - [mj]: http://www.mailjet.com/pricing + [mj]: https://www.mailjet.com/pricing new_version_mailer: subject_template: "[%{site_name}] Uusi Discourse versio, päivitys saatavilla" text_body_template: |+ diff --git a/config/locales/server.fr.yml b/config/locales/server.fr.yml index ed2d37654f..6b06edd78c 100644 --- a/config/locales/server.fr.yml +++ b/config/locales/server.fr.yml @@ -1161,7 +1161,7 @@ fr: [8]: http://www.openspf.org/SPF_Record_Syntax [md]: http://mandrill.com [mg]: http://www.mailgun.com/ - [mj]: http://www.mailjet.com/pricing + [mj]: https://www.mailjet.com/pricing new_version_mailer: subject_template: "[%{site_name}] Nouvelle version de Discourse, mise à jour disponible" text_body_template: | diff --git a/config/locales/server.pt_BR.yml b/config/locales/server.pt_BR.yml index ee323c1a96..45076ebbe2 100644 --- a/config/locales/server.pt_BR.yml +++ b/config/locales/server.pt_BR.yml @@ -1096,7 +1096,7 @@ pt_BR: test_mailer: subject_template: "[%{site_name}] Teste de entrega de email" text_body_template: "Este é um email de teste de\n\n[**%{base_url}**][0]\n\nEntregabilidade de email é complicada. Aqui estão algumas poucas coisas importantes que você deve verificar primeiro:\n\n- Esteja *certo* de definir o from: do `email de notificação` corretamente nas configurações do seu site. **O domínio especificado no endereço \"from\" dos emails que você envia é o domínio contra o qual o seu email será validado**.\n\n- Aprenda como ver o código cru de email no seu cliente de email, para que assim você possa examinar os cabeçalhos de email por pistas importantes. No Gmail, isso é a opção \"exibir original\" no menu drop-down no topo à direita de cada email.\n\n- **IMPORTANTE:** O seu provedor de acesso à internet possui um record de DNS reverso configurado para associar os nomes de domínio e endereços IP dos quais você envia email? [Teste seu record de PTR Reverso][2] aqui. Se o seu provedor de acesso à internet não configurar o record de DNS reverso apropriadamente, é muito pouco provável que qualquer do seu email será entregue.\n\n- O [record SPF][8] do seu domínio é correto? [Teste seu record SPF][1] aqui. Note que TXT \n é o tipo oficialmente correto de record para SPF.\n\n- O [record DKIM][3] do seu domínio é correto? Isso melhorará significativamente a entregabilidade de email. [Teste seu record DKIM][7] aqui.\n\n- Se você roda o seu próprio servidor de emails, verifique e certifique-se que os IPs do seu servidor de emails [não estão em quaisquer blacklists de emails][4]. Também verifique que ele esteja decisivamente enviando um fully-qualified hostname que se resolve em DNS em sua mensagem HELO. Caso contrário, isso fará com que seu email seja rejeitado por muitos serviços de email. \n\n(O modo *fácil* é criar uma conta grátis no [Mandrill][md] ou [Mailgun][mg] ou [Mailjet][mj], os quais têm generosos planos grátis de email e serão suficientes para pequenas comunidades. Você ainda precisará configurar os records SPF e DKIM no seu DNS, apesar disso!) \n\nNós esperamos que você tenha recebido este teste de entregabilidade de email OK!\n\nBoa sorte,\n\nSeus amigos do [Discourse](http://www.discourse.org)\n\n\ - [0]: %{base_url}\n[1]: http://www.kitterman.com/spf/validate.html\n[2]: http://mxtoolbox.com/ReverseLookup.aspx\n[3]: http://www.dkim.org/\n[4]: http://whatismyipaddress.com/blacklist-check\n[7]: http://dkimcore.org/tools/dkimrecordcheck.html\n[8]: http://www.openspf.org/SPF_Record_Syntax\n[md]: http://mandrill.com\n[mg]: http://www.mailgun.com/\n[mj]: http://www.mailjet.com/pricing\n" + [0]: %{base_url}\n[1]: http://www.kitterman.com/spf/validate.html\n[2]: http://mxtoolbox.com/ReverseLookup.aspx\n[3]: http://www.dkim.org/\n[4]: http://whatismyipaddress.com/blacklist-check\n[7]: http://dkimcore.org/tools/dkimrecordcheck.html\n[8]: http://www.openspf.org/SPF_Record_Syntax\n[md]: http://mandrill.com\n[mg]: http://www.mailgun.com/\n[mj]: https://www.mailjet.com/pricing\n" new_version_mailer: subject_template: "[%{site_name}] Nova versão do Discourse, atualização disponível" text_body_template: | diff --git a/config/locales/server.tr_TR.yml b/config/locales/server.tr_TR.yml index 13bb1dfba7..c1e221e9dc 100644 --- a/config/locales/server.tr_TR.yml +++ b/config/locales/server.tr_TR.yml @@ -1046,7 +1046,7 @@ tr_TR: test_mailer: subject_template: "[%{site_name}] E-posta Ulaştırma Testi" text_body_template: "Bu aşağıdaki adresten gönderilen bir test emailidir\n\n[**%{base_url}**][0]\n\nEmailların ulaştırılması karışık bir meseledir. Öncelikle dikkat etmeniz gereken bir kaç önemli nokta:\n\n- Site ayarlarınızda 'bildiri emailları' için gönderen adresini doğru ayarladığınıza emin olun. **Yolladığınız emaillarda \"gönderen\" adresi olarak belirlediğiniz alan adı, emaillarınızın doğrulanacağı alan adıdır.**\n\n- Email başlıklarındaki önemli ipuçlarını yakalayabilmek için email istemcinizde emailların kaynak kodunu nasıl görüntüleyebileceğinizi öğrenin. Gmail'da, her emailin sağ üstündeki açılır menüden \"show original\" opsiyonuna tıklayabilirsiniz.\n\n- **ÖNEMLİ:** ISP'nizde email yollamak için kullanıdığınız alan adlarıyla IP adreslerinin eşleşmesini sağlayacak bir reverse DNS kaydı var mı? Buradan [reverse PTR kayıtlarınızı test edin][2]. Eğer ISP'niz doğru reverse DNS pointer kaydı girmezse, büyük ihtimal emaillarınızın hiç biri yerine ulaşmayacaktır.\n\n- Alan adınızın [SPF kaydı][8] doğru mu? Buradan [SPF kaydınızı test edin][1]. SPF için doğru resmi kayıt tipinin TXT olduğunu unutmayın.\n\n- Alan adınızın [DKIM kaydı][3] doğru mu? Bu emailların ulaştırılabilirliğini ciddi şekilde artıracaktır. Buradan [DKIM kaydınızı test edin][7].\n\n- Kendi email sunucunuzu kullanıyorsanız, email sunucunuzun IPlerinin [hiç bir email karalistesine][4] alınmadığına emin olun. Sunucunuzun, kesinlikle, HELLO mesajında DNS olarak çözümlenen tam tanımlanmış bilgisayar adı da gönderdiğinden emin olun. Göndermemesi, emailinizin bir çok email servisi tarafından reddedilmesine sebep olacaktır.\n\n(En kolayı, küçük topluluklar için rahat rahat yetecek sayıda bedava email yollama paketleri içeren, [Mandrill][md] veya [Mailgun][mg] veya [Mailjet][mj]'te ücretsiz hesap açmak. Tabi, gene DNS ayarlarınızda SPF ve DKIM kayıtlarını oluşturmanız gerekecek.)\n\nUmarız bu email ulaştırma testini başarıyla atlatmışsınızdır. \n\nİyi şanslar,\n\n[Discourse](http://www.discourse.org)'tan arkadaşlarınız\n\n[0]: %{base_url}\n[1]: http://www.kitterman.com/spf/validate.html\n[2]:\ - \ http://mxtoolbox.com/ReverseLookup.aspx\n[3]: http://www.dkim.org/\n[4]: http://whatismyipaddress.com/blacklist-check\n[7]: http://dkimcore.org/tools/dkimrecordcheck.html\n[8]: http://www.openspf.org/SPF_Record_Syntax\n[md]: http://mandrill.com\n[mg]: http://www.mailgun.com/\n[mj]: http://www.mailjet.com/pricing\n" + \ http://mxtoolbox.com/ReverseLookup.aspx\n[3]: http://www.dkim.org/\n[4]: http://whatismyipaddress.com/blacklist-check\n[7]: http://dkimcore.org/tools/dkimrecordcheck.html\n[8]: http://www.openspf.org/SPF_Record_Syntax\n[md]: http://mandrill.com\n[mg]: http://www.mailgun.com/\n[mj]: https://www.mailjet.com/pricing\n" new_version_mailer: subject_template: "[%{site_name}] Yeni Discourse versiyonu, güncelleme var" text_body_template: |2 diff --git a/config/locales/server.zh_CN.yml b/config/locales/server.zh_CN.yml index a0f11f20dd..8b86ac03bb 100644 --- a/config/locales/server.zh_CN.yml +++ b/config/locales/server.zh_CN.yml @@ -1119,7 +1119,7 @@ zh_CN: [8]: http://www.openspf.org/SPF_Record_Syntax [md]: http://mandrill.com [mg]: http://www.mailgun.com/ - [mj]: http://www.mailjet.com/pricing + [mj]: https://www.mailjet.com/pricing [sc]: http://sendcloud.sohu.com/ new_version_mailer: subject_template: "[%{site_name}] 有新的 Discourse 版本,可供升级" diff --git a/docs/ADMIN-QUICK-START-GUIDE.md b/docs/ADMIN-QUICK-START-GUIDE.md index f235ba2654..eaa2232655 100644 --- a/docs/ADMIN-QUICK-START-GUIDE.md +++ b/docs/ADMIN-QUICK-START-GUIDE.md @@ -74,7 +74,7 @@ Email is required for new account signups and notifications. **Test your email t - You got the test email? Great! **Read that email closely**, it has important email deliverability tips. - You didn't get the test email? This means your users probably aren't getting any signup or notification emails either. -Email deliverability can be hard. We strongly recommend using dedicated email services like [Mandrill](http://mandrill.com), [MailGun](http://www.mailgun.com/), or [MailJet](http://www.mailjet.com/), which offer generous free plans that work fine for most communities. +Email deliverability can be hard. We strongly recommend using dedicated email services like [Mandrill](http://mandrill.com), [MailGun](http://www.mailgun.com/), or [MailJet](https://www.mailjet.com/), which offer generous free plans that work fine for most communities. If you'd like to enable *replying* to topics via email, [see this howto](https://meta.discourse.org/t/set-up-reply-via-email-support/14003). diff --git a/docs/INSTALL-digital-ocean.md b/docs/INSTALL-digital-ocean.md index 1249bde6de..042c921012 100644 --- a/docs/INSTALL-digital-ocean.md +++ b/docs/INSTALL-digital-ocean.md @@ -171,6 +171,6 @@ If anything needs to be improved in this guide, feel free to ask on [meta.discou [meta]: https://meta.discourse.org [do]: https://www.digitalocean.com/?refcode=5fa48ac82415 [lts]: https://wiki.ubuntu.com/LTS - [jet]: http://www.mailjet.com/pricing + [jet]: https://www.mailjet.com/pricing [gun]: http://www.mailgun.com/ [put]: http://www.chiark.greenend.org.uk/~sgtatham/putty/download.html From 85df7436bbe2b39695a61a600ca384f075e613e6 Mon Sep 17 00:00:00 2001 From: Sam Date: Thu, 19 Mar 2015 16:09:03 +1100 Subject: [PATCH 056/114] added get satisfaction importer for gradle --- script/import_scripts/getsatisfaction.rb | 340 +++++++++++++++++++++++ 1 file changed, 340 insertions(+) create mode 100644 script/import_scripts/getsatisfaction.rb diff --git a/script/import_scripts/getsatisfaction.rb b/script/import_scripts/getsatisfaction.rb new file mode 100644 index 0000000000..8e17014fd5 --- /dev/null +++ b/script/import_scripts/getsatisfaction.rb @@ -0,0 +1,340 @@ +# getsatisfaction importer +# +# pre-req: you will get a bunch of CSV files, be sure to rename them all so +# +# - users.csv is the users table export (it may come from getsatisfaction as Users-Table 1.csv +# - replies.csv is the reply table export +# - topics.csv is the topics table export +# +# +# note, the importer will import all topics into a new category called 'Old Forum' and close all the topics +# +require 'csv' +require File.expand_path(File.dirname(__FILE__) + "/base.rb") + +# Call it like this: +# RAILS_ENV=production bundle exec ruby script/import_scripts/getsatisfaction.rb +class ImportScripts::GetSatisfaction < ImportScripts::Base + + BATCH_SIZE = 1000 + + def initialize(path) + @path = path + super() + @bbcode_to_md = true + + puts "loading post mappings..." + @post_number_map = {} + Post.pluck(:id, :post_number).each do |post_id, post_number| + @post_number_map[post_id] = post_number + end + end + + def created_post(post) + @post_number_map[post.id] = post.post_number + super + end + + def execute + + c = Category.find_by(name: 'Old Forum') || + Category.create!(name: 'Old Forum', user: Discourse.system_user) + + import_users + import_posts(c) + + Topic.where(category: c).update_all(closed: true) + end + + class RowResolver + def load(row) + @row = row + end + + def self.create(cols) + Class.new(RowResolver).new(cols) + end + + def initialize(cols) + cols.each_with_index do |col,idx| + self.class.send(:define_method, col) do + @row[idx] + end + end + end + end + + def load_user_batch!(users, offset, total) + if users.length > 0 + create_users(users, offset: offset, total: total) do |user| + user + end + users.clear + end + end + + def csv_parse(name) + filename = "#{@path}/#{name}.csv" + first = true + row = nil + + current_row = ""; + double_quote_count = 0 + + File.open(filename).each_line do |line| + + # escaping is mental here + line.gsub!(/\\(.{1})/){|m| m[-1] == '"'? '""': m[-1]} + line.strip! + + current_row << "\n" unless current_row.empty? + current_row << line + + double_quote_count += line.scan('"').count + + if double_quote_count % 2 == 1 + next + end + + raw = begin + CSV.parse(current_row, col_sep: ";") + rescue CSV::MalformedCSVError => e + puts e.message + puts "*" * 100 + puts "Bad row skipped, line is: #{line}" + puts + puts current_row + puts + puts "double quote count is : #{double_quote_count}" + puts "*" * 100 + + current_row = "" + double_quote_count = 0 + next + end[0] + + if first + row = RowResolver.create(raw) + + current_row = "" + double_quote_count = 0 + first = false + next + end + + row.load(raw) + + yield row + + current_row = "" + double_quote_count = 0 + end + end + + def total_rows(table) + File.foreach("#{@path}/#{table}.csv").inject(0) {|c, line| c+1} - 1 + end + + def import_users + puts "", "creating users" + + count = 0 + users = [] + + total = total_rows("users") + + csv_parse("users") do |row| + + if row.suspended_at + puts "skipping suspended user" + p row + next + end + + id = row.user_id + email = row.email + + # fake it + if row.email.blank? || row.email !~ /@/ + email = SecureRandom.hex << "@domain.com" + end + + name = row.real_name + username = row.nick + created_at = DateTime.parse(row.m_created) + + username = name if username == "NULL" + username = email.split("@")[0] if username.blank? + name = email.split("@")[0] if name.blank? + + users << { + id: id, + email: email, + name: name, + username: username, + created_at: created_at, + active: false + } + + count += 1 + if count % BATCH_SIZE == 0 + load_user_batch! users, count - users.length, total + end + + end + + load_user_batch! users, count, total + end + + def import_categories + rows = [] + csv_parse("categories") do |row| + rows << {id: row.id, name: row.name, description: row.description} + end + + create_categories(rows) do |row| + row + end + end + + def normalize_raw!(raw) + raw = raw.dup + + # hoist code + hoisted = {} + raw.gsub!(/(
    \s*)?(.*?)<\/code>(\s*<\/pre>)?/mi) do
    +      code = $2
    +      hoist = SecureRandom.hex
    +      # tidy code, wow, this is impressively crazy
    +      code.gsub!(/  (\s*)/,"\n\\1")
    +      code.gsub!(/^\s*\n$/, "\n")
    +      code.gsub!(/\n+/m, "\n")
    +      code.strip!
    +      hoisted[hoist] = code
    +      hoist
    +    end
    +
    +    # impressive seems to be using tripple space as a 

    unless hoisted + # in this case double space works best ... so odd + raw.gsub!(" ", "\n\n") + + hoisted.each do |hoist, code| + raw.gsub!(hoist, "\n```\n" << code << "\n```\n") + end + + raw + end + + def import_post_batch!(posts, topics, offset, total) + create_posts(posts, total: total, offset: offset) do |post| + + mapped = {} + + mapped[:id] = post[:id] + mapped[:user_id] = user_id_from_imported_user_id(post[:user_id]) || -1 + mapped[:raw] = post[:body] + mapped[:created_at] = post[:created_at] + + topic = topics[post[:topic_id]] + + unless topic + p "MISSING TOPIC #{post[:topic_id]}" + p post + next + end + + + unless topic[:post_id] + mapped[:title] = post[:title] + topic[:post_id] = post[:id] + mapped[:category] = post[:category] + else + parent = topic_lookup_from_imported_post_id(topic[:post_id]) + next unless parent + + mapped[:topic_id] = parent[:topic_id] + + reply_to_post_id = post_id_from_imported_post_id(post[:reply_id]) + if reply_to_post_id + reply_to_post_number = @post_number_map[reply_to_post_id] + if reply_to_post_number && reply_to_post_number > 1 + mapped[:reply_to_post_number] = reply_to_post_number + end + end + end + + next if topic[:deleted] or post[:deleted] + + mapped + end + + posts.clear + end + + def import_posts(category) + puts "", "creating topics and posts" + + topic_map = {} + + csv_parse("topics") do |topic| + topic_map[topic.id] = { + id: topic.id, + topic_id: topic.id, + title: topic.subject, + deleted: topic.removed == "1", + closed: true, + body: topic.additional_detail && normalize_raw!(topic.additional_detail), + created_at: DateTime.parse(topic.created_at), + user_id: topic.UserId, + category: category.name + } + end + + total = total_rows("replies") + + posts = [] + count = 0 + + topic_map.each do |_, topic| + # a bit lazy + posts << topic if topic[:body] + end + + csv_parse("replies") do |row| + + unless row.created_at + puts "NO CREATION DATE FOR POST" + p row + next + end + + row = { + id: row.id, + topic_id: row.topic_id, + reply_id: row.parent_id, + user_id: row.UserId, + body: normalize_raw!(row.content), + created_at: DateTime.parse(row.created_at) + } + posts << row + count+=1 + + if posts.length > 0 && posts.length % BATCH_SIZE == 0 + import_post_batch!(posts, topic_map, count - posts.length, total) + end + end + + import_post_batch!(posts, topic_map, count - posts.length, total) if posts.length > 0 + + exit + end + + +end + +unless ARGV[0] && Dir.exist?(ARGV[0]) + puts "", "Usage:", "", "bundle exec ruby script/import_scripts/getsatisfaction.rb DIRNAME", "" + exit 1 +end + +ImportScripts::GetSatisfaction.new(ARGV[0]).perform From df3b1f69681640daaf8b38780cb84d97ef31fd11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9gis=20Hanol?= Date: Thu, 19 Mar 2015 12:22:56 +0100 Subject: [PATCH 057/114] FIX: editing a post wasn't showing error messages from the server --- .../discourse/controllers/composer.js.es6 | 18 ++++---- .../javascripts/discourse/models/_post.js | 6 +-- .../discourse/models/composer.js.es6 | 42 ++++++++----------- app/controllers/application_controller.rb | 4 +- lib/json_error.rb | 9 ++-- .../javascripts/integration/about-test.js.es6 | 4 +- .../integration/badges-test.js.es6 | 6 +-- .../create-account-user-fields-test.js.es6 | 12 +++--- .../integration/directory-test.js.es6 | 4 +- .../integration/groups-test.js.es6 | 7 ++-- .../integration/header-anonymous-test.js.es6 | 14 +++---- .../integration/header-test-staff.js.es6 | 8 ++-- .../integration/login-required-test.js.es6 | 16 +++---- .../javascripts/integration/modal-test.js.es6 | 12 +++--- .../integration/sign-in-test.js.es6 | 18 ++++---- .../integration/static-test.js.es6 | 12 +++--- .../integration/topic-discovery-test.js.es6 | 10 ++--- .../javascripts/integration/topic-test.js.es6 | 8 ++-- .../integration/unknown-test.js.es6 | 4 +- .../integration/user-card-test.js.es6 | 4 +- test/javascripts/integration/user-test.js.es6 | 12 ++++-- 21 files changed, 113 insertions(+), 117 deletions(-) diff --git a/app/assets/javascripts/discourse/controllers/composer.js.es6 b/app/assets/javascripts/discourse/controllers/composer.js.es6 index 4676e6d320..881d7bb343 100644 --- a/app/assets/javascripts/discourse/controllers/composer.js.es6 +++ b/app/assets/javascripts/discourse/controllers/composer.js.es6 @@ -211,13 +211,13 @@ export default DiscourseController.extend({ } } - var staged = false, - disableJumpReply = Discourse.User.currentProp('disable_jump_reply'); - var promise = composer.save({ + var staged = false; + const disableJumpReply = Discourse.User.currentProp('disable_jump_reply'); + + const promise = composer.save({ imageSizes: this.get('view').imageSizes(), editReason: this.get("editReason") }).then(function(opts) { - // If we replied as a new topic successfully, remove the draft. if (self.get('replyAsNewTopicDraft')) { self.destroyDraft(); @@ -240,21 +240,21 @@ export default DiscourseController.extend({ Discourse.URL.routeTo(opts.post.get('url')); } } - }, function(error) { + }).catch(function(error) { composer.set('disableDrafts', false); bootbox.alert(error); }); - if ( this.get('controllers.application.currentRouteName').split('.')[0] === 'topic' && - composer.get('topic.id') === this.get('controllers.topic.model.id') ) { + if (this.get('controllers.application.currentRouteName').split('.')[0] === 'topic' && + composer.get('topic.id') === this.get('controllers.topic.model.id')) { staged = composer.get('stagedPost'); } Em.run.schedule('afterRender', function() { if (staged && !disableJumpReply) { - var postNumber = staged.get('post_number'); - Discourse.URL.jumpToPost(postNumber, {skipIfOnScreen: true}); + const postNumber = staged.get('post_number'); + Discourse.URL.jumpToPost(postNumber, { skipIfOnScreen: true }); self.appEvents.trigger('post:highlight', postNumber); } }); diff --git a/app/assets/javascripts/discourse/models/_post.js b/app/assets/javascripts/discourse/models/_post.js index 4311bbbe0e..7ae7058cbc 100644 --- a/app/assets/javascripts/discourse/models/_post.js +++ b/app/assets/javascripts/discourse/models/_post.js @@ -123,7 +123,6 @@ Discourse.Post = Discourse.Model.extend({ save: function(complete, error) { var self = this; if (!this.get('newPost')) { - // We're updating a post return Discourse.ajax("/posts/" + (this.get('id')), { type: 'PUT', @@ -137,13 +136,12 @@ Discourse.Post = Discourse.Model.extend({ self.set('version', result.post.version); if (result.category) Discourse.Site.current().updateCategory(result.category); if (complete) complete(Discourse.Post.create(result.post)); - }, function(result) { + }).catch(function(result) { // Post failed to update if (error) error(result); }); } else { - // We're saving a post var data = this.getProperties(Discourse.Composer.serializedFieldsForCreate()); data.reply_to_post_number = this.get('reply_to_post_number'); @@ -162,7 +160,7 @@ Discourse.Post = Discourse.Model.extend({ }).then(function(result) { // Post created if (complete) complete(Discourse.Post.create(result)); - }, function(result) { + }).catch(function(result) { // Failed to create a post if (error) error(result); }); diff --git a/app/assets/javascripts/discourse/models/composer.js.es6 b/app/assets/javascripts/discourse/models/composer.js.es6 index 4a80fdeab0..e21261066b 100644 --- a/app/assets/javascripts/discourse/models/composer.js.es6 +++ b/app/assets/javascripts/discourse/models/composer.js.es6 @@ -385,7 +385,7 @@ const Composer = Discourse.Model.extend({ }, save(opts) { - if( !this.get('cantSubmitPost') ) { + if (!this.get('cantSubmitPost')) { return this.get('editingPost') ? this.editPost(opts) : this.createPost(opts); } }, @@ -409,8 +409,9 @@ const Composer = Discourse.Model.extend({ // When you edit a post editPost(opts) { const post = this.get('post'), - oldCooked = post.get('cooked'), - self = this; + oldCooked = post.get('cooked'), + self = this; + let promise; // Update the title if we've changed it, otherwise consider it a @@ -418,7 +419,6 @@ const Composer = Discourse.Model.extend({ if (this.get('title') && post.get('post_number') === 1 && this.get('topic.details.can_edit')) { - const topicProps = this.getProperties(Object.keys(_edit_topic_serializer)); promise = Discourse.Topic.update(this.get('topic'), topicProps); } else { @@ -431,33 +431,26 @@ const Composer = Discourse.Model.extend({ imageSizes: opts.imageSizes, cooked: this.getCookedHtml() }); + this.set('composeState', CLOSED); return promise.then(function() { return post.save(function(result) { post.updateFromPost(result); self.clearState(); - }).catch(function(error) { - const response = $.parseJSON(error.responseText); - if (response && response.errors) { - return(response.errors[0]); - } else { - return(I18n.t('generic_error')); - } + }, function (error) { post.set('cooked', oldCooked); self.set('composeState', OPEN); + const response = $.parseJSON(error.responseText); + throw response && response.errors ? response.errors[0] : I18n.t('generic_error'); }); }); }, serialize(serializer, dest) { - if (!dest) { - dest = {}; - } - - const self = this; - Object.keys(serializer).forEach(function(f) { - const val = self.get(serializer[f]); + dest = dest || {}; + Object.keys(serializer).forEach(f => { + const val = this.get(serializer[f]); if (typeof val !== 'undefined') { Ember.set(dest, f, val); } @@ -468,9 +461,10 @@ const Composer = Discourse.Model.extend({ // Create a new Post createPost(opts) { const post = this.get('post'), - topic = this.get('topic'), - currentUser = Discourse.User.current(), - postStream = this.get('topic.postStream'); + topic = this.get('topic'), + currentUser = Discourse.User.current(), + postStream = this.get('topic.postStream'); + let addedToStream = false; // Build the post object @@ -530,10 +524,10 @@ const Composer = Discourse.Model.extend({ } } - const composer = this; - const promise = new Ember.RSVP.Promise(function(resolve, reject) { - + const composer = this, + promise = new Ember.RSVP.Promise(function(resolve, reject) { composer.set('composeState', SAVING); + createdPost.save(function(result) { let saving = true; diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 9ba833c705..e9b058151a 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -316,9 +316,7 @@ class ApplicationController < ActionController::Base # type - a machine-readable description of the error # status - HTTP status code to return def render_json_error(obj, opts={}) - if opts.is_a? Fixnum - opts = {status: opts} - end + opts = { status: opts } if opts.is_a?(Fixnum) render json: MultiJson.dump(create_errors_json(obj, opts[:type])), status: opts[:status] || 422 end diff --git a/lib/json_error.rb b/lib/json_error.rb index c882c2f472..e52f18edf4 100644 --- a/lib/json_error.rb +++ b/lib/json_error.rb @@ -9,18 +9,17 @@ module JsonError private def create_errors_array(obj) - # If we're passed a string, assume that is the error message - return {errors: [obj]} if obj.is_a?(String) + return { errors: [obj] } if obj.is_a?(String) # If it's an AR exception target the record obj = obj.record if obj.is_a?(ActiveRecord::RecordInvalid) # If it looks like an activerecord object, extract its messages - return {errors: obj.errors.full_messages } if obj.respond_to?(:errors) && obj.errors.present? + return { errors: obj.errors.full_messages } if obj.respond_to?(:errors) && obj.errors.present? # If we're passed an array, it's an array of error messages - return {errors: obj.map {|e| e.to_s}} if obj.is_a?(Array) && obj.present? + return { errors: obj.map(&:to_s) } if obj.is_a?(Array) && obj.present? # Log a warning (unless obj is nil) Rails.logger.warn("create_errors_json called with unrecognized type: #{obj.inspect}") if obj @@ -30,7 +29,7 @@ module JsonError end def self.generic_error - {errors: [I18n.t('js.generic_error')]} + { errors: [I18n.t('js.generic_error')] } end end diff --git a/test/javascripts/integration/about-test.js.es6 b/test/javascripts/integration/about-test.js.es6 index 23796fa76f..586195ac11 100644 --- a/test/javascripts/integration/about-test.js.es6 +++ b/test/javascripts/integration/about-test.js.es6 @@ -1,8 +1,8 @@ integration("About"); -test("viewing", function() { +test("viewing", () => { visit("/about"); - andThen(function() { + andThen(() => { ok(exists('.about.admins .user-small'), 'has admins'); ok(exists('.about.moderators .user-small'), 'has moderators'); ok(exists('.about.stats tr td'), 'has stats'); diff --git a/test/javascripts/integration/badges-test.js.es6 b/test/javascripts/integration/badges-test.js.es6 index 50e89fab57..6ff2b3bf8c 100644 --- a/test/javascripts/integration/badges-test.js.es6 +++ b/test/javascripts/integration/badges-test.js.es6 @@ -1,13 +1,13 @@ integration("Badges"); -test("Visit Badge Pages", function() { +test("Visit Badge Pages", () => { visit("/badges"); - andThen(function() { + andThen(() => { ok(exists('.badges-listing tr'), "has a list of badges"); }); visit("/badges/9/autobiographer"); - andThen(function() { + andThen(() => { ok(exists('.badges-listing tr'), "has the badge in the listing"); ok(exists('.badge-user'), "has the list of users with that badge"); }); diff --git a/test/javascripts/integration/create-account-user-fields-test.js.es6 b/test/javascripts/integration/create-account-user-fields-test.js.es6 index 63198c24dd..a3822f62bc 100644 --- a/test/javascripts/integration/create-account-user-fields-test.js.es6 +++ b/test/javascripts/integration/create-account-user-fields-test.js.es6 @@ -8,11 +8,11 @@ integration("Create Account - User Fields", { } }); -test("create account with user fields", function() { +test("create account with user fields", () => { visit("/"); click("header .sign-up-button"); - andThen(function() { + andThen(() => { ok(exists('.create-account'), "it shows the create account modal"); ok(exists('.user-field'), "it has at least one user field"); ok(exists('.modal-footer .btn-primary:disabled'), 'create account is disabled at first'); @@ -23,24 +23,24 @@ test("create account with user fields", function() { fillIn('#new-account-email', 'good.tuna@test.com'); fillIn('#new-account-username', 'goodtuna'); - andThen(function() { + andThen(() => { ok(exists('#username-validation.good'), 'the username validation is good'); ok(exists('.modal-footer .btn-primary:disabled'), 'create account is still disabled due to lack of user fields'); }); fillIn(".user-field input[type=text]:first", "Barky"); - andThen(function() { + andThen(() => { ok(exists('.modal-footer .btn-primary:disabled'), 'create account is disabled because field is not checked'); }); click(".user-field input[type=checkbox]"); - andThen(function() { + andThen(() => { not(exists('.modal-footer .btn-primary:disabled'), 'create account is enabled because field is not checked'); }); click(".user-field input[type=checkbox]"); - andThen(function() { + andThen(() => { ok(exists('.modal-footer .btn-primary:disabled'), 'unclicking the checkbox disables the submit'); }); diff --git a/test/javascripts/integration/directory-test.js.es6 b/test/javascripts/integration/directory-test.js.es6 index 84c3c30071..460cf4915c 100644 --- a/test/javascripts/integration/directory-test.js.es6 +++ b/test/javascripts/integration/directory-test.js.es6 @@ -1,8 +1,8 @@ integration("User Directory"); -test("Visit Page", function() { +test("Visit Page", () => { visit("/directory/all"); - andThen(function() { + andThen(() => { ok(exists('.directory table tr'), "has a list of users"); }); }); diff --git a/test/javascripts/integration/groups-test.js.es6 b/test/javascripts/integration/groups-test.js.es6 index 3d52deb95c..2f40696812 100644 --- a/test/javascripts/integration/groups-test.js.es6 +++ b/test/javascripts/integration/groups-test.js.es6 @@ -1,12 +1,13 @@ integration("Groups"); -test("Browsing Groups", function() { +test("Browsing Groups", () => { visit("/groups/discourse"); - andThen(function() { + andThen(() => { ok(count('.user-stream .item') > 0, "it has stream items"); }); + visit("/groups/discourse/members"); - andThen(function() { + andThen(() => { ok(count('.group-members tr') > 0, "it lists group members"); }); }); diff --git a/test/javascripts/integration/header-anonymous-test.js.es6 b/test/javascripts/integration/header-anonymous-test.js.es6 index eff5910757..97cf0b8ac8 100644 --- a/test/javascripts/integration/header-anonymous-test.js.es6 +++ b/test/javascripts/integration/header-anonymous-test.js.es6 @@ -1,8 +1,8 @@ integration("Header (Anonymous)"); -test("header", function() { +test("header", () => { visit("/"); - andThen(function() { + andThen(() => { ok(exists("header"), "is rendered"); ok(exists(".logo-big"), "it renders the large logo by default"); not(exists("#notifications-dropdown li"), "no notifications at first"); @@ -12,17 +12,17 @@ test("header", function() { }); // Logo changing - andThen(function() { + andThen(() => { controllerFor('header').set("showExtraInfo", true); }); - andThen(function() { + andThen(() => { ok(exists(".logo-small"), "it shows the small logo when `showExtraInfo` is enabled"); }); // Site Map click("#site-map"); - andThen(function() { + andThen(() => { ok(exists('#site-map-dropdown'), "is rendered after user opens it"); ok(exists("#site-map-dropdown .faq-link"), "it shows the faq link"); ok(exists("#site-map-dropdown .category-links"), "has categories correctly bound"); @@ -30,14 +30,14 @@ test("header", function() { // Search click("#search-button"); - andThen(function() { + andThen(() => { ok(exists("#search-dropdown:visible"), "after clicking a button search box opens"); not(exists("#search-dropdown .heading"), "initially, immediately after opening, search box is empty"); }); // Perform Search fillIn("#search-term", "hello"); - andThen(function() { + andThen(() => { ok(exists("#search-dropdown .heading"), "when user completes a search, search box shows search results"); equal(find("#search-dropdown .results a:first").attr("href"), "/t/hello-bar-integration-issues/17638", "there is a search result"); }); diff --git a/test/javascripts/integration/header-test-staff.js.es6 b/test/javascripts/integration/header-test-staff.js.es6 index d1adcf6c9a..bd126c0c3c 100644 --- a/test/javascripts/integration/header-test-staff.js.es6 +++ b/test/javascripts/integration/header-test-staff.js.es6 @@ -4,12 +4,12 @@ integration("Header (Staff)", { site_flagged_posts_count: 1 } }); -test("header", function() { +test("header", () => { visit("/"); // Notifications click("#user-notifications"); - andThen(function() { + andThen(() => { var $items = $("#notifications-dropdown li"); ok(exists($items), "is lazily populated after user opens it"); ok($items.first().hasClass("read"), "correctly binds items' 'read' class"); @@ -17,14 +17,14 @@ test("header", function() { // Site Map click("#site-map"); - andThen(function() { + andThen(() => { ok(exists("#site-map-dropdown .admin-link"), "it has the admin link"); ok(exists("#site-map-dropdown .flagged-posts.badge-notification"), "it displays flag notifications"); }); // User dropdown click("#current-user"); - andThen(function() { + andThen(() => { ok(exists("#user-dropdown:visible"), "is lazily rendered after user opens it"); ok(exists("#user-dropdown .user-dropdown-links"), "has showing / hiding user-dropdown links correctly bound"); }); diff --git a/test/javascripts/integration/login-required-test.js.es6 b/test/javascripts/integration/login-required-test.js.es6 index a399ef8f12..c860418d0d 100644 --- a/test/javascripts/integration/login-required-test.js.es6 +++ b/test/javascripts/integration/login-required-test.js.es6 @@ -4,39 +4,39 @@ integration("Login Required", { } }); -test("redirect", function() { +test("redirect", () => { visit('/latest'); - andThen(function() { + andThen(() => { equal(currentPath(), "login", "it redirects them to login"); }); click('#site-logo'); - andThen(function() { + andThen(() => { equal(currentPath(), "login", "clicking the logo keeps them on login"); }); click('header .login-button'); - andThen(function() { + andThen(() => { ok(exists('.login-modal'), "they can still access the login modal"); }); click('.modal-header .close'); - andThen(function() { + andThen(() => { ok(!exists('.login-modal'), "it closes the login modal"); }); click('#search-button'); - andThen(function() { + andThen(() => { ok(exists('.login-modal'), "clicking search opens the login modal"); }); click('.modal-header .close'); - andThen(function() { + andThen(() => { ok(!exists('.login-modal'), "it closes the login modal"); }); click('#site-map'); - andThen(function() { + andThen(() => { ok(exists('.login-modal'), "site map opens the login modal"); }); }); diff --git a/test/javascripts/integration/modal-test.js.es6 b/test/javascripts/integration/modal-test.js.es6 index e89dce2b9c..6eeb6da103 100644 --- a/test/javascripts/integration/modal-test.js.es6 +++ b/test/javascripts/integration/modal-test.js.es6 @@ -1,29 +1,29 @@ integration("Modal"); -test("modal", function() { +test("modal", () => { visit('/'); - andThen(function() { + andThen(() => { ok(find('#discourse-modal:visible').length === 0, 'there is no modal at first'); }); click('.login-button'); - andThen(function() { + andThen(() => { ok(find('#discourse-modal:visible').length === 1, 'modal should appear'); }); click('.modal-outer-container'); - andThen(function() { + andThen(() => { ok(find('#discourse-modal:visible').length === 0, 'modal should disappear when you click outside'); }); click('.login-button'); - andThen(function() { + andThen(() => { ok(find('#discourse-modal:visible').length === 1, 'modal should reappear'); }); keyEvent('#main-outlet', 'keyup', 27); - andThen(function() { + andThen(() => { ok(find('#discourse-modal:visible').length === 0, 'ESC should close the modal'); }); }); diff --git a/test/javascripts/integration/sign-in-test.js.es6 b/test/javascripts/integration/sign-in-test.js.es6 index 5a66d6ecda..0d665b4e6c 100644 --- a/test/javascripts/integration/sign-in-test.js.es6 +++ b/test/javascripts/integration/sign-in-test.js.es6 @@ -1,9 +1,9 @@ integration("Signing In"); -test("sign in", function() { +test("sign in", () => { visit("/"); click("header .login-button"); - andThen(function() { + andThen(() => { ok(exists('.login-modal'), "it shows the login modal"); }); @@ -11,7 +11,7 @@ test("sign in", function() { fillIn('#login-account-name', 'eviltrout'); fillIn('#login-account-password', 'incorrect'); click('.modal-footer .btn-primary'); - andThen(function() { + andThen(() => { ok(exists('#modal-alert:visible', 'it displays the login error')); not(exists('.modal-footer .btn-primary:disabled'), "enables the login button"); }); @@ -19,16 +19,16 @@ test("sign in", function() { // Use the correct password fillIn('#login-account-password', 'correct'); click('.modal-footer .btn-primary'); - andThen(function() { + andThen(() => { ok(exists('.modal-footer .btn-primary:disabled'), "disables the login button"); }); }); -test("create account", function() { +test("create account", () => { visit("/"); click("header .sign-up-button"); - andThen(function() { + andThen(() => { ok(exists('.create-account'), "it shows the create account modal"); ok(exists('.modal-footer .btn-primary:disabled'), 'create account is disabled at first'); }); @@ -39,19 +39,19 @@ test("create account", function() { // Check username fillIn('#new-account-email', 'good.tuna@test.com'); fillIn('#new-account-username', 'taken'); - andThen(function() { + andThen(() => { ok(exists('#username-validation.bad'), 'the username validation is bad'); ok(exists('.modal-footer .btn-primary:disabled'), 'create account is still disabled'); }); fillIn('#new-account-username', 'goodtuna'); - andThen(function() { + andThen(() => { ok(exists('#username-validation.good'), 'the username validation is good'); not(exists('.modal-footer .btn-primary:disabled'), 'create account is enabled'); }); click('.modal-footer .btn-primary'); - andThen(function() { + andThen(() => { ok(exists('.modal-footer .btn-primary:disabled'), "create account is disabled"); }); diff --git a/test/javascripts/integration/static-test.js.es6 b/test/javascripts/integration/static-test.js.es6 index 6eaa2fb083..8b1b184e9c 100644 --- a/test/javascripts/integration/static-test.js.es6 +++ b/test/javascripts/integration/static-test.js.es6 @@ -1,28 +1,28 @@ integration("Static"); -test("Static Pages", function() { +test("Static Pages", () => { visit("/faq"); - andThen(function() { + andThen(() => { ok(exists(".body-page"), "The content is present"); }); visit("/guidelines"); - andThen(function() { + andThen(() => { ok(exists(".body-page"), "The content is present"); }); visit("/tos"); - andThen(function() { + andThen(() => { ok(exists(".body-page"), "The content is present"); }); visit("/privacy"); - andThen(function() { + andThen(() => { ok(exists(".body-page"), "The content is present"); }); visit("/login"); - andThen(function() { + andThen(() => { equal(currentPath(), "discovery.latest", "it redirects them to latest unless `login_required`"); }); }); diff --git a/test/javascripts/integration/topic-discovery-test.js.es6 b/test/javascripts/integration/topic-discovery-test.js.es6 index ea4dbac42c..729680336c 100644 --- a/test/javascripts/integration/topic-discovery-test.js.es6 +++ b/test/javascripts/integration/topic-discovery-test.js.es6 @@ -1,21 +1,21 @@ integration("Topic Discovery"); -test("Visit Discovery Pages", function() { +test("Visit Discovery Pages", () => { visit("/"); - andThen(function() { + andThen(() => { ok(exists(".topic-list"), "The list of topics was rendered"); ok(exists('.topic-list .topic-list-item'), "has topics"); }); visit("/c/bug"); - andThen(function() { + andThen(() => { ok(exists(".topic-list"), "The list of topics was rendered"); ok(exists('.topic-list .topic-list-item'), "has topics"); ok($('body.category-bug').length, "has a custom css class for the category id on the body"); }); visit("/categories"); - andThen(function() { + andThen(() => { ok($('body.category-bug').length === 0, "removes the custom category class"); ok(exists('.category'), "has a list of categories"); @@ -23,7 +23,7 @@ test("Visit Discovery Pages", function() { }); visit("/top"); - andThen(function() { + andThen(() => { ok($('body.categories-list').length === 0, "removes the `categories-list` class"); ok(exists('.topic-list .topic-list-item'), "has topics"); }); diff --git a/test/javascripts/integration/topic-test.js.es6 b/test/javascripts/integration/topic-test.js.es6 index 503d3f912c..5757d4091a 100644 --- a/test/javascripts/integration/topic-test.js.es6 +++ b/test/javascripts/integration/topic-test.js.es6 @@ -1,16 +1,16 @@ integration("View Topic"); -test("Enter a Topic", function() { +test("Enter a Topic", () => { visit("/t/internationalization-localization/280"); - andThen(function() { + andThen(() => { ok(exists("#topic"), "The topic was rendered"); ok(exists("#topic .post-cloak"), "The topic has cloaked posts"); }); }); -test("Enter without an id", function() { +test("Enter without an id", () => { visit("/t/internationalization-localization"); - andThen(function() { + andThen(() => { ok(exists("#topic"), "The topic was rendered"); }); }); diff --git a/test/javascripts/integration/unknown-test.js.es6 b/test/javascripts/integration/unknown-test.js.es6 index 6bef185b1d..c2b96f81a2 100644 --- a/test/javascripts/integration/unknown-test.js.es6 +++ b/test/javascripts/integration/unknown-test.js.es6 @@ -1,9 +1,9 @@ integration("Unknown"); -test("Unknown URL", function() { +test("Unknown URL", () => { expect(1); visit("/url-that-doesn't-exist"); - andThen(function() { + andThen(() => { ok(exists(".page-not-found"), "The not found content is present"); }); }); diff --git a/test/javascripts/integration/user-card-test.js.es6 b/test/javascripts/integration/user-card-test.js.es6 index bc5cc6c668..98a76828ae 100644 --- a/test/javascripts/integration/user-card-test.js.es6 +++ b/test/javascripts/integration/user-card-test.js.es6 @@ -1,12 +1,12 @@ integration("User Card"); -test("card", function() { +test("card", () => { visit('/'); ok(invisible('#user-card'), 'user card is invisible by default'); click('a[data-user-card=eviltrout]:first'); - andThen(function() { + andThen(() => { ok(visible('#user-card'), 'card should appear'); }); diff --git a/test/javascripts/integration/user-test.js.es6 b/test/javascripts/integration/user-test.js.es6 index b610b966f5..ef8cd9aa30 100644 --- a/test/javascripts/integration/user-test.js.es6 +++ b/test/javascripts/integration/user-test.js.es6 @@ -1,34 +1,40 @@ integration("User"); function hasStream() { - andThen(function() { + andThen(() => { ok(exists('.user-main .about'), 'it has the about section'); ok(count('.user-stream .item') > 0, 'it has stream items'); }); } function hasTopicList() { - andThen(function() { + andThen(() => { equal(count('.user-stream .item'), 0, "has no stream displayed"); ok(count('.topic-list tr') > 0, 'it has a topic list'); }); } -test("Filters", function() { +test("Filters", () => { expect(14); visit("/users/eviltrout"); hasStream(); + visit("/users/eviltrout/activity/topics"); hasTopicList(); + visit("/users/eviltrout/activity/posts"); hasStream(); + visit("/users/eviltrout/activity/replies"); hasStream(); + visit("/users/eviltrout/activity/likes-given"); hasStream(); + visit("/users/eviltrout/activity/likes-received"); hasStream(); + visit("/users/eviltrout/activity/edits"); hasStream(); }); From a7a3b199eff45f9e5178ad1d417d2fdb6662bf97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9gis=20Hanol?= Date: Thu, 19 Mar 2015 13:42:13 +0100 Subject: [PATCH 058/114] FIX: popups stopped appearing --- .../controllers/composer-messages.js.es6 | 48 +++++-------------- .../discourse/controllers/composer.js.es6 | 16 ++----- 2 files changed, 16 insertions(+), 48 deletions(-) diff --git a/app/assets/javascripts/discourse/controllers/composer-messages.js.es6 b/app/assets/javascripts/discourse/controllers/composer-messages.js.es6 index 8fdbb1937d..345837474f 100644 --- a/app/assets/javascripts/discourse/controllers/composer-messages.js.es6 +++ b/app/assets/javascripts/discourse/controllers/composer-messages.js.es6 @@ -5,10 +5,9 @@ export default Ember.ArrayController.extend({ // Whether we've checked our messages checkedMessages: false, - init() { - this._super(); + _init: function() { this.reset(); - }, + }.on("init"), actions: { closeMessage(message) { @@ -29,14 +28,11 @@ export default Ember.ArrayController.extend({ this.pushObject(message); messagesByTemplate[templateName] = message; } - }, + } }, - /** - Resets all active messages. For example if composing a new post. - - @method reset - **/ + // Resets all active messages. + // For example if composing a new post. reset() { this.clear(); this.setProperties({ @@ -46,42 +42,22 @@ export default Ember.ArrayController.extend({ }); }, - /** - Called after the user has typed a reply. Some messages only get shown after being - typed. - - @method typedReply - **/ + // Called after the user has typed a reply. + // Some messages only get shown after being typed. typedReply() { - var self = this; - this.get('queuedForTyping').forEach(function(msg){ - if(self.popup){ - self.popup(msg); - } - }); + this.get('queuedForTyping').forEach(msg => this.send("popup", msg)); }, - /** - Figure out if there are any messages that should be displayed above the composer. - - @method queryFor - @params {Discourse.Composer} composer The composer model - **/ + // Figure out if there are any messages that should be displayed above the composer. queryFor(composer) { if (this.get('checkedMessages')) { return; } const self = this; - let queuedForTyping = self.get('queuedForTyping'); + var queuedForTyping = self.get('queuedForTyping'); - Discourse.ComposerMessage.find(composer).then(function (messages) { + Discourse.ComposerMessage.find(composer).then(messages => { self.set('checkedMessages', true); - messages.forEach(function (msg) { - if (msg.wait_for_typing) { - queuedForTyping.addObject(msg); - } else { - self.popup(msg); - } - }); + messages.forEach(msg => msg.wait_for_typing ? queuedForTyping.addObject(msg) : self.send("popup", msg)); }); } diff --git a/app/assets/javascripts/discourse/controllers/composer.js.es6 b/app/assets/javascripts/discourse/controllers/composer.js.es6 index 881d7bb343..341dba1fab 100644 --- a/app/assets/javascripts/discourse/controllers/composer.js.es6 +++ b/app/assets/javascripts/discourse/controllers/composer.js.es6 @@ -267,12 +267,8 @@ export default DiscourseController.extend({ return promise; }, - /** - Checks to see if a reply has been typed. This is signaled by a keyUp - event in a view. - - @method checkReplyLength - **/ + // Checks to see if a reply has been typed. + // This is signaled by a keyUp event in a view. checkReplyLength() { if (this.present('model.reply')) { // Notify the composer messages controller that a reply has been typed. Some @@ -281,12 +277,8 @@ export default DiscourseController.extend({ } }, - /** - Fired after a user stops typing. Considers whether to check for similar - topics based on the current composer state. - - @method findSimilarTopics - **/ + // Fired after a user stops typing. + // Considers whether to check for similar topics based on the current composer state. findSimilarTopics() { // We don't care about similar topics unless creating a topic if (!this.get('model.creatingTopic')) { return; } From c0881a6a7d5de2bf9cc4052ed9c1ab9dc34d7cc8 Mon Sep 17 00:00:00 2001 From: Erik Ordway Date: Thu, 19 Mar 2015 08:39:15 -0700 Subject: [PATCH 059/114] single quote password in backup command This protects against characters like '&' in passwords. Sometimes you are assigned passwords by idiots or are and idiot that uses pronounceable passwords. Anyways this small change protects against ruby's shell interpreter from background the pg_dump command before it has really started. --- lib/backup_restore/backuper.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/backup_restore/backuper.rb b/lib/backup_restore/backuper.rb index 3c0ddaf7d8..02b1c48811 100644 --- a/lib/backup_restore/backuper.rb +++ b/lib/backup_restore/backuper.rb @@ -174,7 +174,7 @@ module BackupRestore def pg_dump_command db_conf = BackupRestore.database_configuration - password_argument = "PGPASSWORD=#{db_conf.password}" if db_conf.password.present? + password_argument = "PGPASSWORD='#{db_conf.password}'" if db_conf.password.present? host_argument = "--host=#{db_conf.host}" if db_conf.host.present? port_argument = "--port=#{db_conf.port}" if db_conf.port.present? username_argument = "--username=#{db_conf.username}" if db_conf.username.present? From 7ef306cd3bbffc1fe8e19d223c1024dd3caf2004 Mon Sep 17 00:00:00 2001 From: Robin Ward Date: Thu, 19 Mar 2015 11:48:16 -0400 Subject: [PATCH 060/114] A bunch of tweaks to the Users directory - Move user directory from `/directory` to `/users/` - Defaults to 'weekly' time period - Don't include deleted topics/posts in the results - Move heart icon to header instead of on each row - "Users" instead of "Users found" --- .../components/directory-toggle.js.es6 | 6 +++ .../{directory-show.js.es6 => users.js.es6} | 3 +- .../discourse/routes/app-route-map.js.es6 | 5 +- .../discourse/routes/directory-index.js.es6 | 6 --- .../{directory-show.js.es6 => users.js.es6} | 15 ++---- .../discourse/templates/directory.hbs | 5 -- .../discourse/templates/directory/show.hbs | 50 ------------------- .../discourse/templates/site-map.hbs | 2 +- .../javascripts/discourse/templates/users.hbs | 50 +++++++++++++++++++ .../{directory-show.js.es6 => users.js.es6} | 0 .../stylesheets/common/base/directory.scss | 13 +++-- app/controllers/directory_controller.rb | 8 --- app/controllers/directory_items_controller.rb | 6 +-- app/controllers/users_controller.rb | 3 ++ app/models/directory_item.rb | 4 ++ config/locales/client.en.yml | 4 +- config/routes.rb | 1 - .../directory_items_controller_spec.rb | 8 +-- ...irectory-test.js.es6 => users-test.js.es6} | 4 +- 19 files changed, 87 insertions(+), 106 deletions(-) rename app/assets/javascripts/discourse/controllers/{directory-show.js.es6 => users.js.es6} (77%) delete mode 100644 app/assets/javascripts/discourse/routes/directory-index.js.es6 rename app/assets/javascripts/discourse/routes/{directory-show.js.es6 => users.js.es6} (60%) delete mode 100644 app/assets/javascripts/discourse/templates/directory.hbs delete mode 100644 app/assets/javascripts/discourse/templates/directory/show.hbs create mode 100644 app/assets/javascripts/discourse/templates/users.hbs rename app/assets/javascripts/discourse/views/{directory-show.js.es6 => users.js.es6} (100%) delete mode 100644 app/controllers/directory_controller.rb rename test/javascripts/integration/{directory-test.js.es6 => users-test.js.es6} (69%) diff --git a/app/assets/javascripts/discourse/components/directory-toggle.js.es6 b/app/assets/javascripts/discourse/components/directory-toggle.js.es6 index 8c4b4761bd..3b6b35c96c 100644 --- a/app/assets/javascripts/discourse/components/directory-toggle.js.es6 +++ b/app/assets/javascripts/discourse/components/directory-toggle.js.es6 @@ -7,6 +7,12 @@ export default Ember.Component.extend(StringBuffer, { rerenderTriggers: ['order', 'asc'], renderString(buffer) { + + const icon = this.get('icon'); + if (icon) { + buffer.push(iconHTML(icon)); + } + const field = this.get('field'); buffer.push(I18n.t('directory.' + field)); diff --git a/app/assets/javascripts/discourse/controllers/directory-show.js.es6 b/app/assets/javascripts/discourse/controllers/users.js.es6 similarity index 77% rename from app/assets/javascripts/discourse/controllers/directory-show.js.es6 rename to app/assets/javascripts/discourse/controllers/users.js.es6 index 2ea3630764..631be71d77 100644 --- a/app/assets/javascripts/discourse/controllers/directory-show.js.es6 +++ b/app/assets/javascripts/discourse/controllers/users.js.es6 @@ -1,5 +1,6 @@ export default Ember.Controller.extend({ - queryParams: ['order', 'asc'], + queryParams: ['period', 'order', 'asc'], + period: 'weekly', order: 'likes_received', asc: null, diff --git a/app/assets/javascripts/discourse/routes/app-route-map.js.es6 b/app/assets/javascripts/discourse/routes/app-route-map.js.es6 index e6adf86307..15d469230c 100644 --- a/app/assets/javascripts/discourse/routes/app-route-map.js.es6 +++ b/app/assets/javascripts/discourse/routes/app-route-map.js.es6 @@ -11,10 +11,6 @@ export default function() { }); this.resource('topicBySlug', { path: '/t/:slug' }); - this.resource('directory', function() { - this.route('show', {path: '/:period'}); - }); - this.resource('discovery', { path: '/' }, function() { // top this.route('top'); @@ -56,6 +52,7 @@ export default function() { }); // User routes + this.resource('users'); this.resource('user', { path: '/users/:username' }, function() { this.resource('userActivity', { path: '/activity' }, function() { var self = this; diff --git a/app/assets/javascripts/discourse/routes/directory-index.js.es6 b/app/assets/javascripts/discourse/routes/directory-index.js.es6 deleted file mode 100644 index cc8c807302..0000000000 --- a/app/assets/javascripts/discourse/routes/directory-index.js.es6 +++ /dev/null @@ -1,6 +0,0 @@ -export default Discourse.Route.extend({ - beforeModel: function() { - this.controllerFor('directory-show').setProperties({ sort: null, asc: null }); - this.replaceWith('directory.show', 'all'); - } -}); diff --git a/app/assets/javascripts/discourse/routes/directory-show.js.es6 b/app/assets/javascripts/discourse/routes/users.js.es6 similarity index 60% rename from app/assets/javascripts/discourse/routes/directory-show.js.es6 rename to app/assets/javascripts/discourse/routes/users.js.es6 index fc319f6897..22fc3575b4 100644 --- a/app/assets/javascripts/discourse/routes/directory-show.js.es6 +++ b/app/assets/javascripts/discourse/routes/users.js.es6 @@ -1,31 +1,22 @@ export default Discourse.Route.extend({ queryParams: { + period: { refreshModel: true }, order: { refreshModel: true }, asc: { refreshModel: true }, }, model(params) { // If we refresh via `refreshModel` set the old model to loading - const existing = this.modelFor('directory-show'); + const existing = this.modelFor('users'); if (existing) { existing.set('loading', true); } this._period = params.period; - return this.store.find('directoryItem', { - id: params.period, - asc: params.asc, - order: params.order - }); + return this.store.find('directoryItem', params); }, setupController(controller, model) { controller.setProperties({ model, period: this._period }); - }, - - actions: { - changePeriod(period) { - this.transitionTo('directory.show', period); - } } }); diff --git a/app/assets/javascripts/discourse/templates/directory.hbs b/app/assets/javascripts/discourse/templates/directory.hbs deleted file mode 100644 index 68207c4602..0000000000 --- a/app/assets/javascripts/discourse/templates/directory.hbs +++ /dev/null @@ -1,5 +0,0 @@ -

    -
    - {{outlet}} -
    -
    diff --git a/app/assets/javascripts/discourse/templates/directory/show.hbs b/app/assets/javascripts/discourse/templates/directory/show.hbs deleted file mode 100644 index e06356f61c..0000000000 --- a/app/assets/javascripts/discourse/templates/directory/show.hbs +++ /dev/null @@ -1,50 +0,0 @@ -{{period-chooser period=period action="changePeriod"}} - -{{#loading-spinner condition=model.loading}} - {{#if model.length}} - {{i18n "directory.total_rows" count=model.totalRows}} - - - - - {{directory-toggle field="likes_received" order=order asc=asc}} - {{directory-toggle field="likes_given" order=order asc=asc}} - {{directory-toggle field="topic_count" order=order asc=asc}} - {{directory-toggle field="post_count" order=order asc=asc}} - {{directory-toggle field="topics_entered" order=order asc=asc}} - {{#if showTimeRead}} - - {{/if}} - - - {{#each item in model}} - - - - - - - - {{#if showTimeRead}} - - {{/if}} - - {{/each}} - -
     {{i18n "directory.time_read"}}
    - {{avatar item imageSize="tiny"}} - {{#link-to 'user' item.username}}{{unbound item.username}}{{/link-to}} - {{number item.topic_count}}{{number item.post_count}}{{number item.topics_entered}}{{unbound item.time_read}}
    - - {{loading-spinner condition=model.loadingMore}} - {{else}} -
    -

    {{i18n "directory.no_results"}}

    - {{/if}} -{{/loading-spinner}} diff --git a/app/assets/javascripts/discourse/templates/site-map.hbs b/app/assets/javascripts/discourse/templates/site-map.hbs index d4be2d7bda..c7995ef22e 100644 --- a/app/assets/javascripts/discourse/templates/site-map.hbs +++ b/app/assets/javascripts/discourse/templates/site-map.hbs @@ -22,7 +22,7 @@ {{/if}} -
  • {{#link-to 'directory'}}{{i18n "directory.title"}}{{/link-to}}
  • +
  • {{#link-to 'users'}}{{i18n "directory.title"}}{{/link-to}}
  • {{plugin-outlet "site-map-links"}} diff --git a/app/assets/javascripts/discourse/templates/users.hbs b/app/assets/javascripts/discourse/templates/users.hbs new file mode 100644 index 0000000000..7285ea21e4 --- /dev/null +++ b/app/assets/javascripts/discourse/templates/users.hbs @@ -0,0 +1,50 @@ +
    +
    + + {{period-chooser period=period}} + + {{#loading-spinner condition=model.loading}} + {{#if model.length}} + {{i18n "directory.total_rows" count=model.totalRows}} + + + + + {{directory-toggle field="likes_received" order=order asc=asc icon="heart"}} + {{directory-toggle field="likes_given" order=order asc=asc icon="heart"}} + {{directory-toggle field="topic_count" order=order asc=asc}} + {{directory-toggle field="post_count" order=order asc=asc}} + {{directory-toggle field="topics_entered" order=order asc=asc}} + {{#if showTimeRead}} + + {{/if}} + + + {{#each item in model}} + + + + + + + + {{#if showTimeRead}} + + {{/if}} + + {{/each}} + +
     {{i18n "directory.time_read"}}
    + {{avatar item imageSize="tiny"}} + {{#link-to 'user' item.username}}{{unbound item.username}}{{/link-to}} + {{number item.likes_received}}{{number item.likes_given}}{{number item.topic_count}}{{number item.post_count}}{{number item.topics_entered}}{{unbound item.time_read}}
    + + {{loading-spinner condition=model.loadingMore}} + {{else}} +
    +

    {{i18n "directory.no_results"}}

    + {{/if}} + {{/loading-spinner}} + +
    +
    diff --git a/app/assets/javascripts/discourse/views/directory-show.js.es6 b/app/assets/javascripts/discourse/views/users.js.es6 similarity index 100% rename from app/assets/javascripts/discourse/views/directory-show.js.es6 rename to app/assets/javascripts/discourse/views/users.js.es6 diff --git a/app/assets/stylesheets/common/base/directory.scss b/app/assets/stylesheets/common/base/directory.scss index d11141fbea..16aad83c3d 100644 --- a/app/assets/stylesheets/common/base/directory.scss +++ b/app/assets/stylesheets/common/base/directory.scss @@ -26,9 +26,14 @@ th.sortable { cursor: pointer; + white-space: nowrap; width: 13%; - i.fa { + i.fa-heart { + color: $love; + margin-right: 0.5em; + } + i.fa-chevron-down, i.fa-chevron-up { margin-left: 1em; } @@ -36,11 +41,5 @@ background-color: scale-color-diff(); } } - - td.likes { - i { - color: $love; - } - } } } diff --git a/app/controllers/directory_controller.rb b/app/controllers/directory_controller.rb deleted file mode 100644 index aea4bbc201..0000000000 --- a/app/controllers/directory_controller.rb +++ /dev/null @@ -1,8 +0,0 @@ -class DirectoryController < ApplicationController - # This controller just exists to avoid 404s and to have the ember app load up - def index - end - - def show - end -end diff --git a/app/controllers/directory_items_controller.rb b/app/controllers/directory_items_controller.rb index 221149d223..a70a872aa8 100644 --- a/app/controllers/directory_items_controller.rb +++ b/app/controllers/directory_items_controller.rb @@ -2,8 +2,8 @@ class DirectoryItemsController < ApplicationController PAGE_SIZE = 50 def index - id = params.require(:id) - period_type = DirectoryItem.period_types[id.to_sym] + period = params.require(:period) + period_type = DirectoryItem.period_types[period.to_sym] raise Discourse::InvalidAccess.new(:period_type) unless period_type result = DirectoryItem.where(period_type: period_type).includes(:user) @@ -24,7 +24,7 @@ class DirectoryItemsController < ApplicationController serialized = serialize_data(result, DirectoryItemSerializer) - more_params = params.slice(:id, :order, :asc) + more_params = params.slice(:period, :order, :asc) more_params[:page] = page + 1 render_json_dump directory_items: serialized, diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index d257cb7e2d..4642bef895 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -25,6 +25,9 @@ class UsersController < ApplicationController :authorize_email, :password_reset] + def index + end + def show @user = fetch_user_from_params user_serializer = UserSerializer.new(@user, scope: guardian, root: 'user') diff --git a/app/models/directory_item.rb b/app/models/directory_item.rb index d2b8c02a56..facd8d4874 100644 --- a/app/models/directory_item.rb +++ b/app/models/directory_item.rb @@ -42,9 +42,13 @@ class DirectoryItem < ActiveRecord::Base SUM(CASE WHEN ua.action_type = :reply_type THEN 1 ELSE 0 END) FROM users AS u LEFT OUTER JOIN user_actions AS ua ON ua.user_id = u.id + LEFT OUTER JOIN topics AS t ON ua.target_topic_id = t.id + LEFT OUTER JOIN posts AS p ON ua.target_post_id = p.id WHERE u.active AND NOT u.blocked AND COALESCE(ua.created_at, :since) >= :since + AND t.deleted_at IS NULL + AND p.deleted_at IS NULL AND u.id > 0 GROUP BY u.id", period_type: period_types[period_type], diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml index 60d311b7b3..8a40413bab 100644 --- a/config/locales/client.en.yml +++ b/config/locales/client.en.yml @@ -247,8 +247,8 @@ en: post_count: "Replies" no_results: "No results were found for this time period." total_rows: - one: "1 user found" - other: "%{count} users found" + one: "1 user" + other: "%{count} users" groups: visible: "Group is visible to all users" diff --git a/config/routes.rb b/config/routes.rb index a3cfd922be..5e8d9ef728 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -25,7 +25,6 @@ Discourse::Application.routes.draw do resources :about - resources :directory resources :directory_items get "site" => "site#site" diff --git a/spec/controllers/directory_items_controller_spec.rb b/spec/controllers/directory_items_controller_spec.rb index bc36d9b861..8f46747d8f 100644 --- a/spec/controllers/directory_items_controller_spec.rb +++ b/spec/controllers/directory_items_controller_spec.rb @@ -2,12 +2,12 @@ require 'spec_helper' describe DirectoryItemsController do - it "requires an `id` param" do + it "requires a `period` param" do ->{ xhr :get, :index }.should raise_error end - it "requires a proper `id` param" do - xhr :get, :index, id: 'eviltrout' + it "requires a proper `period` param" do + xhr :get, :index, period: 'eviltrout' response.should_not be_success end @@ -18,7 +18,7 @@ describe DirectoryItemsController do end it "succeeds with a valid value" do - xhr :get, :index, id: 'all' + xhr :get, :index, period: 'all' response.should be_success json = ::JSON.parse(response.body) diff --git a/test/javascripts/integration/directory-test.js.es6 b/test/javascripts/integration/users-test.js.es6 similarity index 69% rename from test/javascripts/integration/directory-test.js.es6 rename to test/javascripts/integration/users-test.js.es6 index 460cf4915c..96f27623d1 100644 --- a/test/javascripts/integration/directory-test.js.es6 +++ b/test/javascripts/integration/users-test.js.es6 @@ -1,7 +1,7 @@ integration("User Directory"); -test("Visit Page", () => { - visit("/directory/all"); +test("Visit Page", function() { + visit("/users"); andThen(() => { ok(exists('.directory table tr'), "has a list of users"); }); From b706307ac76a5db188d4ef8de7b8823f72158d14 Mon Sep 17 00:00:00 2001 From: Arpit Jalan Date: Thu, 19 Mar 2015 19:47:55 +0530 Subject: [PATCH 061/114] FEATURE: new site setting min_first_post_length --- .../javascripts/discourse/models/composer.js.es6 | 7 ++++++- app/models/site_setting.rb | 4 ++++ config/locales/server.en.yml | 1 + config/site_settings.yml | 6 ++++++ lib/validators/post_validator.rb | 12 +++++++++++- script/import_scripts/base.rb | 1 + spec/models/site_setting_spec.rb | 6 ++++++ test/javascripts/models/composer-test.js.es6 | 10 ++++++---- 8 files changed, 41 insertions(+), 6 deletions(-) diff --git a/app/assets/javascripts/discourse/models/composer.js.es6 b/app/assets/javascripts/discourse/models/composer.js.es6 index 4a80fdeab0..af68aeda92 100644 --- a/app/assets/javascripts/discourse/models/composer.js.es6 +++ b/app/assets/javascripts/discourse/models/composer.js.es6 @@ -40,6 +40,8 @@ const Composer = Discourse.Model.extend({ return this.get('creatingPrivateMessage') || this.get('topic.archetype') === 'private_message'; }.property('creatingPrivateMessage', 'topic'), + topicFirstPost: Em.computed.or('creatingTopic', 'editingFirstPost'), + editingPost: Em.computed.equal('action', EDIT), replyingToTopic: Em.computed.equal('action', REPLY), @@ -215,10 +217,13 @@ const Composer = Discourse.Model.extend({ minimumPostLength: function() { if( this.get('privateMessage') ) { return Discourse.SiteSettings.min_private_message_post_length; + } else if (this.get('topicFirstPost')) { + // first post (topic body) + return Discourse.SiteSettings.min_first_post_length; } else { return Discourse.SiteSettings.min_post_length; } - }.property('privateMessage'), + }.property('privateMessage', 'topicFirstPost'), /** Computes the length of the title minus non-significant whitespaces diff --git a/app/models/site_setting.rb b/app/models/site_setting.rb index 284df6d532..5b272c0d91 100644 --- a/app/models/site_setting.rb +++ b/app/models/site_setting.rb @@ -48,6 +48,10 @@ class SiteSetting < ActiveRecord::Base min_post_length..max_post_length end + def self.first_post_length + min_first_post_length..max_post_length + end + def self.private_message_post_length min_private_message_post_length..max_post_length end diff --git a/config/locales/server.en.yml b/config/locales/server.en.yml index 9e61260cc6..8d30d9f1da 100644 --- a/config/locales/server.en.yml +++ b/config/locales/server.en.yml @@ -733,6 +733,7 @@ en: default_locale: "The default language of this Discourse instance (ISO 639-1 Code)" allow_user_locale: "Allow users to choose their own language interface preference" min_post_length: "Minimum allowed post length in characters" + min_first_post_length: "Minimum allowed first post (topic body) length in characters" min_private_message_post_length: "Minimum allowed post length in characters for private messages" max_post_length: "Maximum allowed post length in characters" min_topic_title_length: "Minimum allowed topic title length in characters" diff --git a/config/site_settings.yml b/config/site_settings.yml index 6c9c5a82ae..a958214d72 100644 --- a/config/site_settings.yml +++ b/config/site_settings.yml @@ -310,6 +310,12 @@ posting: default: test: 5 default: 20 + min_first_post_length: + client: true + min: 1 + default: + test: 5 + default: 20 min_private_message_post_length: client: true min: 1 diff --git a/lib/validators/post_validator.rb b/lib/validators/post_validator.rb index 04b0fb7862..a5751ccade 100644 --- a/lib/validators/post_validator.rb +++ b/lib/validators/post_validator.rb @@ -25,7 +25,17 @@ class Validators::PostValidator < ActiveModel::Validator end def stripped_length(post) - range = post.topic.try(:private_message?) ? SiteSetting.private_message_post_length : SiteSetting.post_length + range = if post.topic.try(:private_message?) + # private message + SiteSetting.private_message_post_length + elsif ( post.is_first_post? || (post.topic.present? && post.topic.posts_count == 0) ) + # creating/editing first post + SiteSetting.first_post_length + else + # regular post + SiteSetting.post_length + end + Validators::StrippedLengthValidator.validate(post, :raw, post.raw, range) end diff --git a/script/import_scripts/base.rb b/script/import_scripts/base.rb index a3120edd24..2b41c6e285 100644 --- a/script/import_scripts/base.rb +++ b/script/import_scripts/base.rb @@ -99,6 +99,7 @@ class ImportScripts::Base email_domains_blacklist: '', min_topic_title_length: 1, min_post_length: 1, + min_first_post_length: 1, min_private_message_post_length: 1, min_private_message_title_length: 1, allow_duplicate_topic_titles: true, diff --git a/spec/models/site_setting_spec.rb b/spec/models/site_setting_spec.rb index e1466a4000..0cd8691a66 100644 --- a/spec/models/site_setting_spec.rb +++ b/spec/models/site_setting_spec.rb @@ -35,6 +35,12 @@ describe SiteSetting do end end + describe 'first_post_length' do + it 'returns a range of min/max first post length' do + expect(SiteSetting.first_post_length).to eq(SiteSetting.defaults[:min_first_post_length]..SiteSetting.defaults[:max_post_length]) + end + end + describe 'private_message_title_length' do it 'returns a range of min/max pm topic title length' do expect(SiteSetting.private_message_title_length).to eq(SiteSetting.defaults[:min_private_message_title_length]..SiteSetting.defaults[:max_topic_title_length]) diff --git a/test/javascripts/models/composer-test.js.es6 b/test/javascripts/models/composer-test.js.es6 index cf359e9976..413156077e 100644 --- a/test/javascripts/models/composer-test.js.es6 +++ b/test/javascripts/models/composer-test.js.es6 @@ -22,13 +22,15 @@ test('replyLength', function() { }); test('missingReplyCharacters', function() { - var missingReplyCharacters = function(val, isPM, expected, message) { - var composer = Discourse.Composer.create({ reply: val, creatingPrivateMessage: isPM }); + Discourse.SiteSettings.min_first_post_length = 40; + var missingReplyCharacters = function(val, isPM, isFirstPost, expected, message) { + var composer = Discourse.Composer.create({ reply: val, creatingPrivateMessage: isPM, creatingTopic: isFirstPost }); equal(composer.get('missingReplyCharacters'), expected, message); }; - missingReplyCharacters('hi', false, Discourse.SiteSettings.min_post_length - 2, 'too short public post'); - missingReplyCharacters('hi', true, Discourse.SiteSettings.min_private_message_post_length - 2, 'too short private message'); + missingReplyCharacters('hi', false, false, Discourse.SiteSettings.min_post_length - 2, 'too short public post'); + missingReplyCharacters('hi', false, true, Discourse.SiteSettings.min_first_post_length - 2, 'too short first post'); + missingReplyCharacters('hi', true, false, Discourse.SiteSettings.min_private_message_post_length - 2, 'too short private message'); }); test('missingTitleCharacters', function() { From ae695d64385d4f5b26d73705de5e492b6f167e93 Mon Sep 17 00:00:00 2001 From: Robin Ward Date: Thu, 19 Mar 2015 14:53:52 -0400 Subject: [PATCH 062/114] UX: Show two lines per user on directory --- .../discourse/components/user-small.js.es6 | 10 ++++- .../templates/components/user-small.hbs | 8 ++-- .../javascripts/discourse/templates/users.hbs | 5 +-- app/assets/stylesheets/common/base/about.scss | 39 ------------------ .../stylesheets/common/base/directory.scss | 1 + app/assets/stylesheets/common/base/user.scss | 40 +++++++++++++++++++ app/controllers/directory_items_controller.rb | 4 +- app/serializers/directory_item_serializer.rb | 16 +------- 8 files changed, 58 insertions(+), 65 deletions(-) diff --git a/app/assets/javascripts/discourse/components/user-small.js.es6 b/app/assets/javascripts/discourse/components/user-small.js.es6 index fbbd65827f..d4eaf001e5 100644 --- a/app/assets/javascripts/discourse/components/user-small.js.es6 +++ b/app/assets/javascripts/discourse/components/user-small.js.es6 @@ -1,3 +1,11 @@ export default Ember.Component.extend({ - classNames: ['user-small'] + classNames: ['user-small'], + + name: function() { + const name = this.get('user.name'); + if (name && this.get('user.username') !== name) { + return name; + } + }.property('user.name') + }); diff --git a/app/assets/javascripts/discourse/templates/components/user-small.hbs b/app/assets/javascripts/discourse/templates/components/user-small.hbs index ac22ea37ae..87f72c07bc 100644 --- a/app/assets/javascripts/discourse/templates/components/user-small.hbs +++ b/app/assets/javascripts/discourse/templates/components/user-small.hbs @@ -3,7 +3,9 @@
    - {{#link-to 'user' user.username}}{{user.username}}{{/link-to}} - {{user.name}} - {{user.title}} +
    + {{#link-to 'user' user.username}}{{user.username}}{{/link-to}} + {{name}} +
    +
    {{user.title}}
    diff --git a/app/assets/javascripts/discourse/templates/users.hbs b/app/assets/javascripts/discourse/templates/users.hbs index 7285ea21e4..1c00ed06f0 100644 --- a/app/assets/javascripts/discourse/templates/users.hbs +++ b/app/assets/javascripts/discourse/templates/users.hbs @@ -22,10 +22,7 @@ {{#each item in model}} - - {{avatar item imageSize="tiny"}} - {{#link-to 'user' item.username}}{{unbound item.username}}{{/link-to}} - + {{user-small user=item.user}} {{number item.likes_received}} {{number item.likes_given}} {{number item.topic_count}} diff --git a/app/assets/stylesheets/common/base/about.scss b/app/assets/stylesheets/common/base/about.scss index af5d06a5c1..596f3f1a71 100644 --- a/app/assets/stylesheets/common/base/about.scss +++ b/app/assets/stylesheets/common/base/about.scss @@ -5,46 +5,7 @@ section.about { margin-top: 10px; } - .user-small { - padding: 8px; - width: 205px; - height: 60px; - float: left; - .user-image { - float: left; - padding-right: 4px; - } - - .user-detail { - float: left; - width: 70%; - - span { - float: left; - width: 90%; - padding-left: 5px; - } - - .username a { - font-weight: bold; - font-size: 16px; - color: scale-color($primary, $lightness: 30%); - } - - .name { - font-size: 13px; - color: scale-color($primary, $lightness: 30%); - } - - .title { - font-size: 13px; - color: scale-color($primary, $lightness: 50%); - } - - } - } - p { margin: 10px 0; } diff --git a/app/assets/stylesheets/common/base/directory.scss b/app/assets/stylesheets/common/base/directory.scss index 16aad83c3d..956d6ccdcd 100644 --- a/app/assets/stylesheets/common/base/directory.scss +++ b/app/assets/stylesheets/common/base/directory.scss @@ -22,6 +22,7 @@ padding: 0.5em; text-align: left; border-bottom: 1px solid scale-color-diff(); + vertical-align: top; } th.sortable { diff --git a/app/assets/stylesheets/common/base/user.scss b/app/assets/stylesheets/common/base/user.scss index f1495540f7..a1d5a3f967 100644 --- a/app/assets/stylesheets/common/base/user.scss +++ b/app/assets/stylesheets/common/base/user.scss @@ -86,3 +86,43 @@ .new-private-message { margin-bottom: 15px; } + +.user-small { + display: inline-block; + width: 333px; + clear: both; + + .user-image { + float: left; + padding-right: 4px; + } + + .user-detail { + float: left; + width: 70%; + padding-left: 5px; + font-size: 13px; + + .name-line { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } + + .username a { + font-weight: bold; + color: scale-color($primary, $lightness: 30%); + } + + .name { + margin-left: 5px; + color: scale-color($primary, $lightness: 30%); + } + + .title { + margin-top: 3px; + color: scale-color($primary, $lightness: 50%); + } + + } +} diff --git a/app/controllers/directory_items_controller.rb b/app/controllers/directory_items_controller.rb index a70a872aa8..8cb7c5d507 100644 --- a/app/controllers/directory_items_controller.rb +++ b/app/controllers/directory_items_controller.rb @@ -22,12 +22,10 @@ class DirectoryItemsController < ApplicationController result_count = result.dup.count result = result.limit(PAGE_SIZE).offset(PAGE_SIZE * page) - serialized = serialize_data(result, DirectoryItemSerializer) - more_params = params.slice(:period, :order, :asc) more_params[:page] = page + 1 - render_json_dump directory_items: serialized, + render_json_dump directory_items: serialize_data(result, DirectoryItemSerializer), total_rows_directory_items: result_count, load_more_directory_items: directory_items_path(more_params) diff --git a/app/serializers/directory_item_serializer.rb b/app/serializers/directory_item_serializer.rb index 242196a83f..e241dc6f6c 100644 --- a/app/serializers/directory_item_serializer.rb +++ b/app/serializers/directory_item_serializer.rb @@ -1,29 +1,15 @@ class DirectoryItemSerializer < ApplicationSerializer attributes :id, - :username, - :uploaded_avatar_id, - :avatar_template, :time_read + has_one :user, embed: :objects, serializer: UserNameSerializer attributes *DirectoryItem.headings def id object.user_id end - def username - object.user.username - end - - def uploaded_avatar_id - object.user.uploaded_avatar_id - end - - def avatar_template - object.user.avatar_template - end - def time_read AgeWords.age_words(object.user_stat.time_read) end From 11bf7da63cbbd5ebcb0066f2774577cabf806550 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9gis=20Hanol?= Date: Thu, 19 Mar 2015 19:57:07 +0100 Subject: [PATCH 063/114] FIX: profile picture wasn't properly updating --- .../admin/templates/user_index.hbs | 4 +- .../components/avatar-uploader.js.es6 | 16 +++---- .../discourse/components/d-button.js.es6 | 1 + .../controllers/avatar-selector.js.es6 | 26 +++++------ .../discourse/lib/show-modal.js.es6 | 5 +-- .../discourse/mixins/show-footer.js.es6 | 9 ++-- .../discourse/routes/preferences.js.es6 | 43 ++++++++++--------- .../discourse/routes/restricted-user.js.es6 | 5 +-- .../templates/modal/avatar_selector.hbs | 14 +++--- .../discourse/templates/user/preferences.hbs | 14 +++--- .../discourse/views/avatar-selector.js.es6 | 3 -- app/assets/stylesheets/desktop/user.scss | 7 +++ .../controllers/avatar-selector-test.js.es6 | 15 +++---- 13 files changed, 82 insertions(+), 80 deletions(-) diff --git a/app/assets/javascripts/admin/templates/user_index.hbs b/app/assets/javascripts/admin/templates/user_index.hbs index e6347ff68c..4dff9338a4 100644 --- a/app/assets/javascripts/admin/templates/user_index.hbs +++ b/app/assets/javascripts/admin/templates/user_index.hbs @@ -455,7 +455,7 @@ {{#unless anonymizeForbidden}} {{d-button label="admin.user.anonymize" icon="exclamation-triangle" - class="btn btn-danger" + class="btn-danger" disabled=anonymizeForbidden action="anonymize"}} {{/unless}} @@ -463,7 +463,7 @@ {{#unless deleteForbidden}} {{d-button label="admin.user.delete" icon="exclamation-triangle" - class="btn btn-danger" + class="btn-danger" disabled=deleteForbidden action="destroy"}} {{/unless}} diff --git a/app/assets/javascripts/discourse/components/avatar-uploader.js.es6 b/app/assets/javascripts/discourse/components/avatar-uploader.js.es6 index b67da9c65f..f00f674280 100644 --- a/app/assets/javascripts/discourse/components/avatar-uploader.js.es6 +++ b/app/assets/javascripts/discourse/components/avatar-uploader.js.es6 @@ -1,19 +1,19 @@ import UploadMixin from 'discourse/mixins/upload'; export default Em.Component.extend(UploadMixin, { + type: 'avatar', tagName: 'span', imageIsNotASquare: false, - type: 'avatar', uploadUrl: Discourse.computed.url('username', '/users/%@/preferences/user_image'), uploadButtonText: function() { - return this.get("uploading") ? I18n.t("uploading") : I18n.t("user.change_avatar.upload_picture"); + return this.get("uploading") ? + I18n.t("uploading") : + I18n.t("user.change_avatar.upload_picture"); }.property("uploading"), - uploadDone: function(data) { - var self = this; - + uploadDone(data) { // display a warning whenever the image is not a square this.set("imageIsNotASquare", data.result.width !== data.result.height); @@ -21,13 +21,13 @@ export default Em.Component.extend(UploadMixin, { // indeed, the server gives us back the url to the file we've just uploaded // often, this file is not a square, so we need to crop it properly // this will also capture the first frame of animated avatars when they're not allowed - Discourse.Utilities.cropAvatar(data.result.url, data.files[0].type).then(function(avatarTemplate) { - self.set("uploadedAvatarTemplate", avatarTemplate); + Discourse.Utilities.cropAvatar(data.result.url, data.files[0].type).then(avatarTemplate => { + this.set("uploadedAvatarTemplate", avatarTemplate); // indicates the users is using an uploaded avatar (must happen after cropping, otherwise // we will attempt to load an invalid avatar and cache a redirect to old one, uploadedAvatarTemplate // trumps over custom avatar upload id) - self.set("custom_avatar_upload_id", data.result.upload_id); + this.set("custom_avatar_upload_id", data.result.upload_id); }); // the upload is now done diff --git a/app/assets/javascripts/discourse/components/d-button.js.es6 b/app/assets/javascripts/discourse/components/d-button.js.es6 index 21ebedc8e8..973405128f 100644 --- a/app/assets/javascripts/discourse/components/d-button.js.es6 +++ b/app/assets/javascripts/discourse/components/d-button.js.es6 @@ -32,5 +32,6 @@ export default Ember.Component.extend({ click() { this.sendAction("action", this.get("actionParam")); + return false; } }); diff --git a/app/assets/javascripts/discourse/controllers/avatar-selector.js.es6 b/app/assets/javascripts/discourse/controllers/avatar-selector.js.es6 index e856b5a09f..3909f31aff 100644 --- a/app/assets/javascripts/discourse/controllers/avatar-selector.js.es6 +++ b/app/assets/javascripts/discourse/controllers/avatar-selector.js.es6 @@ -2,8 +2,10 @@ import ModalFunctionality from 'discourse/mixins/modal-functionality'; import DiscourseController from 'discourse/controllers/controller'; export default DiscourseController.extend(ModalFunctionality, { + uploadedAvatarTemplate: null, + hasUploadedAvatar: Em.computed.or('uploadedAvatarTemplate', 'custom_avatar_upload_id'), - selectedUploadId: function(){ + selectedUploadId: function() { switch (this.get("selected")) { case "system": return this.get("system_avatar_upload_id"); case "gravatar": return this.get("gravatar_avatar_upload_id"); @@ -12,18 +14,16 @@ export default DiscourseController.extend(ModalFunctionality, { }.property('selected', 'system_avatar_upload_id', 'gravatar_avatar_upload_id', 'custom_avatar_upload_id'), actions: { - useUploadedAvatar: function() { this.set("selected", "uploaded"); }, - useGravatar: function() { this.set("selected", "gravatar"); }, - useSystem: function() { this.set("selected", "system"); }, - refreshGravatar: function() { - var self = this; - self.set("gravatarRefreshDisabled", true); - Discourse - .ajax("/user_avatar/" + this.get("username") + "/refresh_gravatar", {method: 'POST'}) - .then(function(result){ - self.set("gravatarRefreshDisabled", false); - self.set("gravatar_avatar_upload_id", result.upload_id); - }); + useUploadedAvatar() { this.set("selected", "uploaded"); }, + useGravatar() { this.set("selected", "gravatar"); }, + useSystem() { this.set("selected", "system"); }, + + refreshGravatar() { + this.set("gravatarRefreshDisabled", true); + return Discourse + .ajax("/user_avatar/" + this.get("username") + "/refresh_gravatar.json", { method: 'POST' }) + .then(result => this.set("gravatar_avatar_upload_id", result.upload_id)) + .finally(() => this.set("gravatarRefreshDisabled", false)); } } diff --git a/app/assets/javascripts/discourse/lib/show-modal.js.es6 b/app/assets/javascripts/discourse/lib/show-modal.js.es6 index 667a344ddd..7fac8a1158 100644 --- a/app/assets/javascripts/discourse/lib/show-modal.js.es6 +++ b/app/assets/javascripts/discourse/lib/show-modal.js.es6 @@ -1,4 +1,4 @@ -export default function showModal(name, model) { +export default (name, model) => { // We use the container here because modals are like singletons // in Discourse. Only one can be shown with a particular state. const route = Discourse.__container__.lookup('route:application'); @@ -12,5 +12,4 @@ export default function showModal(name, model) { if (controller.onShow) { controller.onShow(); } controller.set('flashMessage', null); } - return controller; -} +}; diff --git a/app/assets/javascripts/discourse/mixins/show-footer.js.es6 b/app/assets/javascripts/discourse/mixins/show-footer.js.es6 index a83fdbcf2d..b97014153a 100644 --- a/app/assets/javascripts/discourse/mixins/show-footer.js.es6 +++ b/app/assets/javascripts/discourse/mixins/show-footer.js.es6 @@ -1,14 +1,13 @@ export default Em.Mixin.create({ actions: { - didTransition: function() { - var self = this; - Em.run.schedule("afterRender", function() { - self.controllerFor("application").set("showFooter", true); + didTransition() { + Em.run.schedule("afterRender", () => { + this.controllerFor("application").set("showFooter", true); }); return true; }, - willTransition: function() { + willTransition() { this.controllerFor("application").set("showFooter", false); return true; } diff --git a/app/assets/javascripts/discourse/routes/preferences.js.es6 b/app/assets/javascripts/discourse/routes/preferences.js.es6 index 79712f495e..7fb2ba4a41 100644 --- a/app/assets/javascripts/discourse/routes/preferences.js.es6 +++ b/app/assets/javascripts/discourse/routes/preferences.js.es6 @@ -8,7 +8,10 @@ export default RestrictedUserRoute.extend(ShowFooter, { }, setupController(controller, user) { - controller.setProperties({ model: user, newNameInput: user.get('name') }); + controller.setProperties({ + model: user, + newNameInput: user.get('name') + }); }, actions: { @@ -16,15 +19,15 @@ export default RestrictedUserRoute.extend(ShowFooter, { showModal('avatar-selector'); // all the properties needed for displaying the avatar selector modal - const controller = this.controllerFor('avatar-selector'); - const user = this.modelFor('user'); - const props = user.getProperties( - 'username', 'email', - 'uploaded_avatar_id', - 'system_avatar_upload_id', - 'gravatar_avatar_upload_id', - 'custom_avatar_upload_id' - ); + const controller = this.controllerFor('avatar-selector'), + props = this.modelFor('user').getProperties( + 'email', + 'username', + 'uploaded_avatar_id', + 'system_avatar_upload_id', + 'gravatar_avatar_upload_id', + 'custom_avatar_upload_id' + ); switch (props.uploaded_avatar_id) { case props.system_avatar_upload_id: @@ -40,20 +43,20 @@ export default RestrictedUserRoute.extend(ShowFooter, { controller.setProperties(props); }, - saveAvatarSelection: function() { - const user = this.modelFor('user'); - const avatarSelector = this.controllerFor('avatar-selector'); + saveAvatarSelection() { + const user = this.modelFor('user'), + avatarSelector = this.controllerFor('avatar-selector'); // sends the information to the server if it has changed if (avatarSelector.get('selectedUploadId') !== user.get('uploaded_avatar_id')) { user.pickAvatar(avatarSelector.get('selectedUploadId')) - .then(function(){ - user.setProperties(avatarSelector.getProperties( - 'system_avatar_upload_id', - 'gravatar_avatar_upload_id', - 'custom_avatar_upload_id' - )); - }); + .then(() => { + user.setProperties(avatarSelector.getProperties( + 'system_avatar_upload_id', + 'gravatar_avatar_upload_id', + 'custom_avatar_upload_id' + )); + }); } // saves the data back diff --git a/app/assets/javascripts/discourse/routes/restricted-user.js.es6 b/app/assets/javascripts/discourse/routes/restricted-user.js.es6 index ad9cb411ef..46cc1fe6fe 100644 --- a/app/assets/javascripts/discourse/routes/restricted-user.js.es6 +++ b/app/assets/javascripts/discourse/routes/restricted-user.js.es6 @@ -2,9 +2,8 @@ export default Discourse.Route.extend({ - afterModel: function() { - var user = this.modelFor('user'); - if (!user.get('can_edit')) { + afterModel() { + if (!this.modelFor('user').get('can_edit')) { this.replaceWith('userActivity'); } } diff --git a/app/assets/javascripts/discourse/templates/modal/avatar_selector.hbs b/app/assets/javascripts/discourse/templates/modal/avatar_selector.hbs index caad9187ac..0e375179c2 100644 --- a/app/assets/javascripts/discourse/templates/modal/avatar_selector.hbs +++ b/app/assets/javascripts/discourse/templates/modal/avatar_selector.hbs @@ -7,14 +7,14 @@
    - + {{d-button action="refreshGravatar" title="user.change_avatar.refresh_gravatar_title" disabled=gravatarRefreshDisabled class="no-text" icon="refresh"}}
    {{avatar-uploader username=username - uploadedAvatarTemplate=view.uploadedAvatarTemplate - custom_avatar_upload_id=controller.custom_avatar_upload_id + uploadedAvatarTemplate=uploadedAvatarTemplate + custom_avatar_upload_id=custom_avatar_upload_id done="useUploadedAvatar"}}
    diff --git a/app/assets/javascripts/discourse/templates/user/preferences.hbs b/app/assets/javascripts/discourse/templates/user/preferences.hbs index 4a617f999a..d7cc7b20c3 100644 --- a/app/assets/javascripts/discourse/templates/user/preferences.hbs +++ b/app/assets/javascripts/discourse/templates/user/preferences.hbs @@ -54,7 +54,7 @@
    {{email}} {{#if can_edit_email}} - {{#link-to "preferences.email" class="btn btn-small pad-left no-text"}}{{/link-to}} + {{#link-to "preferences.email" class="btn btn-small pad-left no-text"}}{{fa-icon "pencil"}}{{/link-to}} {{/if}}
    @@ -62,7 +62,7 @@
    {{else}}
    - + {{d-button action="checkEmail" actionParam=this title="admin.users.check_email.title" icon="envelope-o" label="admin.users.check_email.text"}}
    {{/if}}
    @@ -72,7 +72,8 @@
    - + + {{fa-icon "envelope"}} {{#if no_password}} {{i18n 'user.change_password.set_password'}} {{else}} @@ -87,9 +88,10 @@
    - {{bound-avatar model "large"}} + {{! we want the "huge" version even though we're downsizing it to "large" in CSS }} + {{bound-avatar model "huge"}} {{#if allowAvatarUpload}} - + {{d-button action="showAvatarSelector" class="pad-left no-text" icon="pencil"}} {{else}} {{#unless ssoOverridesAvatar}} {{fa-icon "pencil"}} @@ -245,7 +247,7 @@ {{/if}} diff --git a/app/assets/javascripts/discourse/views/avatar-selector.js.es6 b/app/assets/javascripts/discourse/views/avatar-selector.js.es6 index 40414660a6..ed60610505 100644 --- a/app/assets/javascripts/discourse/views/avatar-selector.js.es6 +++ b/app/assets/javascripts/discourse/views/avatar-selector.js.es6 @@ -4,9 +4,6 @@ export default ModalBodyView.extend({ templateName: 'modal/avatar_selector', classNames: ['avatar-selector'], title: I18n.t('user.change_avatar.title'), - saveDisabled: false, - gravatarRefreshEnabled: Em.computed.not('controller.gravatarRefreshDisabled'), - hasUploadedAvatar: Em.computed.or('uploadedAvatarTemplate', 'controller.custom_avatar_upload_id'), // *HACK* used to select the proper radio button, cause {{action}} // stops the default behavior diff --git a/app/assets/stylesheets/desktop/user.scss b/app/assets/stylesheets/desktop/user.scss index cc3fe23158..6936c8d605 100644 --- a/app/assets/stylesheets/desktop/user.scss +++ b/app/assets/stylesheets/desktop/user.scss @@ -170,6 +170,13 @@ border-bottom: 1px solid scale-color-diff(); } } + + .pref-avatar { + .avatar { + max-width: 45px; + max-height: 45px; + } + } } .about { diff --git a/test/javascripts/controllers/avatar-selector-test.js.es6 b/test/javascripts/controllers/avatar-selector-test.js.es6 index 8d7441d6e2..3f2f0af811 100644 --- a/test/javascripts/controllers/avatar-selector-test.js.es6 +++ b/test/javascripts/controllers/avatar-selector-test.js.es6 @@ -3,7 +3,8 @@ moduleFor("controller:avatar-selector", "controller:avatar-selector", { }); test("avatarTemplate", function() { - var avatarSelectorController = this.subject(); + const avatarSelectorController = this.subject(); + avatarSelectorController.setProperties({ selected: "system", system_avatar_upload_id:1, @@ -11,17 +12,11 @@ test("avatarTemplate", function() { custom_avatar_upload_id: 3 }); - equal(avatarSelectorController.get("selectedUploadId"), 1, - "we are using system by default"); + equal(avatarSelectorController.get("selectedUploadId"), 1, "we are using system by default"); avatarSelectorController.set('selected', 'gravatar'); - - equal(avatarSelectorController.get("selectedUploadId"), 2, - "we are using gravatar when set"); + equal(avatarSelectorController.get("selectedUploadId"), 2, "we are using gravatar when set"); avatarSelectorController.set("selected", "custom"); - - equal(avatarSelectorController.get("selectedUploadId"), 3, - "we are using custom when set"); - + equal(avatarSelectorController.get("selectedUploadId"), 3, "we are using custom when set"); }); From 28c0f9dd1ff2b0476b6c98b4e9d515aeceea5dd9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9gis=20Hanol?= Date: Thu, 19 Mar 2015 20:05:03 +0100 Subject: [PATCH 064/114] FIX: only nag when pinning globally --- .../discourse/controllers/feature-topic.js.es6 | 9 +++++---- config/locales/client.en.yml | 4 ++-- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/app/assets/javascripts/discourse/controllers/feature-topic.js.es6 b/app/assets/javascripts/discourse/controllers/feature-topic.js.es6 index f7ae397e82..57c09e39e0 100644 --- a/app/assets/javascripts/discourse/controllers/feature-topic.js.es6 +++ b/app/assets/javascripts/discourse/controllers/feature-topic.js.es6 @@ -58,16 +58,17 @@ export default ObjectController.extend(ModalFunctionality, { this._forwardAction(action); } else { this.send("hideModal"); - const message = I18n.t("topic.feature_topic.confirm_" + name, { count: count }); bootbox.confirm( - message, I18n.t("no_value"), I18n.t("yes_value"), - (confirmed) => confirmed ? this._forwardAction(action) : this.send("reopenModal") + I18n.t("topic.feature_topic.confirm_" + name, { count: count }), + I18n.t("no_value"), + I18n.t("yes_value"), + confirmed => confirmed ? this._forwardAction(action) : this.send("reopenModal") ); } }, actions: { - pin() { this._confirmBeforePinning(this.get("pinnedInCategoryCount"), "pin", "togglePinned"); }, + pin() { this._forwardAction("togglePinned"); }, pinGlobally() { this._confirmBeforePinning(this.get("pinnedGloballyCount"), "pin_globally", "pinGlobally"); }, unpin() { this._forwardAction("togglePinned"); }, makeBanner() { this._forwardAction("makeBanner"); }, diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml index 8a40413bab..a2586b7ac9 100644 --- a/config/locales/client.en.yml +++ b/config/locales/client.en.yml @@ -1021,7 +1021,7 @@ en: feature_topic: title: "Feature this topic" pin: "Make this topic appear at the top of the {{categoryLink}} category." - confirm_pin: "Are you sure? You already have {{count}} pinned topics -- too many pinned topics can obscure other active topics." + confirm_ping: "You already have {{count}} pinned topics. Too many pinned topics may be a burden for new and anonymous users. Are you sure you want to pin another topic in this category?" unpin: "Remove this topic from the topic of the {{categoryLink}} category." pin_note: "Users can unpin the topic individually for themselves." already_pinned: @@ -1029,7 +1029,7 @@ en: one: "Topic currently pinned in {{categoryLink}}: 1." other: "Topics currently pinned in {{categoryLink}}: {{count}}." pin_globally: "Make this topic appear at the top of all topic lists, until a staff member unpins it." - confirm_pin_globally: "Are you sure? You already have {{count}} globally pinned topics -- too many pinned topics can obscure other active topics." + confirm_pin_globally: "You already have {{count}} globally pinned topics. Too many pinned topics may be a burden for new and anonymous users. Are you sure you want to pin another topic globally?" unpin_globally: "Remove this topic from the top of all topic lists." global_pin_note: "Users can unpin the topic individually for themselves." already_pinned_globally: From 225c1dc6827a65932b597de51263165ba284950d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9gis=20Hanol?= Date: Thu, 19 Mar 2015 20:07:48 +0100 Subject: [PATCH 065/114] oops - typo (:fired:) --- config/locales/client.en.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml index a2586b7ac9..02e23ea9f4 100644 --- a/config/locales/client.en.yml +++ b/config/locales/client.en.yml @@ -1021,7 +1021,7 @@ en: feature_topic: title: "Feature this topic" pin: "Make this topic appear at the top of the {{categoryLink}} category." - confirm_ping: "You already have {{count}} pinned topics. Too many pinned topics may be a burden for new and anonymous users. Are you sure you want to pin another topic in this category?" + confirm_pin: "You already have {{count}} pinned topics. Too many pinned topics may be a burden for new and anonymous users. Are you sure you want to pin another topic in this category?" unpin: "Remove this topic from the topic of the {{categoryLink}} category." pin_note: "Users can unpin the topic individually for themselves." already_pinned: From b18dfa7ca053dae7d7d2bc64e4f0156f821c49b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9gis=20Hanol?= Date: Thu, 19 Mar 2015 20:30:19 +0100 Subject: [PATCH 066/114] change copy of the 'save' button when creating a topic --- config/locales/client.en.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml index 02e23ea9f4..7da0ac1e3e 100644 --- a/config/locales/client.en.yml +++ b/config/locales/client.en.yml @@ -707,7 +707,7 @@ en: reply_here: "Reply Here" reply: "Reply" cancel: "Cancel" - create_topic: "New Topic" + create_topic: "Create Topic" create_pm: "Private Message" title: "Or press Ctrl+Enter" From 19318501517cd61791753282475538f9bd565baa Mon Sep 17 00:00:00 2001 From: Robin Ward Date: Thu, 19 Mar 2015 15:31:29 -0400 Subject: [PATCH 067/114] UX: Always show the current user at the top of the directory --- .../controllers/directory-item.js.es6 | 3 +++ .../javascripts/discourse/templates/users.hbs | 18 +++++++++--------- .../stylesheets/common/base/directory.scss | 6 ++++++ app/controllers/directory_items_controller.rb | 6 ++++++ 4 files changed, 24 insertions(+), 9 deletions(-) create mode 100644 app/assets/javascripts/discourse/controllers/directory-item.js.es6 diff --git a/app/assets/javascripts/discourse/controllers/directory-item.js.es6 b/app/assets/javascripts/discourse/controllers/directory-item.js.es6 new file mode 100644 index 0000000000..8858982408 --- /dev/null +++ b/app/assets/javascripts/discourse/controllers/directory-item.js.es6 @@ -0,0 +1,3 @@ +export default Ember.Controller.extend({ + me: Discourse.computed.propertyEqual('model.user.id', 'currentUser.id') +}); diff --git a/app/assets/javascripts/discourse/templates/users.hbs b/app/assets/javascripts/discourse/templates/users.hbs index 1c00ed06f0..74d124e608 100644 --- a/app/assets/javascripts/discourse/templates/users.hbs +++ b/app/assets/javascripts/discourse/templates/users.hbs @@ -20,16 +20,16 @@ {{/if}} - {{#each item in model}} - - {{user-small user=item.user}} - {{number item.likes_received}} - {{number item.likes_given}} - {{number item.topic_count}} - {{number item.post_count}} - {{number item.topics_entered}} + {{#each item in model itemController="directory-item"}} + + {{user-small user=item.model.user}} + {{number item.model.likes_received}} + {{number item.model.likes_given}} + {{number item.model.topic_count}} + {{number item.model.post_count}} + {{number item.model.topics_entered}} {{#if showTimeRead}} - {{unbound item.time_read}} + {{unbound item.model.time_read}} {{/if}} {{/each}} diff --git a/app/assets/stylesheets/common/base/directory.scss b/app/assets/stylesheets/common/base/directory.scss index 956d6ccdcd..3a922e2a71 100644 --- a/app/assets/stylesheets/common/base/directory.scss +++ b/app/assets/stylesheets/common/base/directory.scss @@ -25,6 +25,12 @@ vertical-align: top; } + tr.me { + td { + background-color: scale-color($highlight, $lightness: 50%); + } + } + th.sortable { cursor: pointer; white-space: nowrap; diff --git a/app/controllers/directory_items_controller.rb b/app/controllers/directory_items_controller.rb index 8cb7c5d507..9de15381e2 100644 --- a/app/controllers/directory_items_controller.rb +++ b/app/controllers/directory_items_controller.rb @@ -8,6 +8,10 @@ class DirectoryItemsController < ApplicationController result = DirectoryItem.where(period_type: period_type).includes(:user) + if current_user.present? + result = result.order("CASE WHEN users.id = #{current_user.id.to_i} THEN 0 ELSE 1 END") + end + order = params[:order] || DirectoryItem.headings.first if DirectoryItem.headings.include?(order.to_sym) dir = params[:asc] ? 'ASC' : 'DESC' @@ -18,6 +22,8 @@ class DirectoryItemsController < ApplicationController result = result.includes(:user_stat) end page = params[:page].to_i + + result = result.order('users.username') result_count = result.dup.count result = result.limit(PAGE_SIZE).offset(PAGE_SIZE * page) From 326dff6068b5460335e4e3dc6a8af792adaa9d62 Mon Sep 17 00:00:00 2001 From: Robin Ward Date: Thu, 19 Mar 2015 16:50:01 -0400 Subject: [PATCH 068/114] UX: User directory tweaks. Also includes Better refresh semantics for query params (avoids transition) --- .../javascripts/discourse/routes/discourse.js.es6 | 12 ++++++++++++ .../javascripts/discourse/routes/users.js.es6 | 14 ++++++++------ .../javascripts/discourse/templates/users.hbs | 2 +- app/assets/stylesheets/common/base/directory.scss | 8 ++++++-- config/locales/client.en.yml | 4 ++-- 5 files changed, 29 insertions(+), 11 deletions(-) diff --git a/app/assets/javascripts/discourse/routes/discourse.js.es6 b/app/assets/javascripts/discourse/routes/discourse.js.es6 index dcd4d68691..2bb5fa9544 100644 --- a/app/assets/javascripts/discourse/routes/discourse.js.es6 +++ b/app/assets/javascripts/discourse/routes/discourse.js.es6 @@ -2,6 +2,18 @@ import showModal from 'discourse/lib/show-modal'; const DiscourseRoute = Ember.Route.extend({ + refreshModel: null, + + refresh: function() { + // Implement `refreshModel` to avoid a full transition to ourselves + if (!this.refreshModel) { return this._super(); } + + if (!this.router.router.activeTransition) { + const params = this.controller.getProperties(Object.keys(this.queryParams)); + this.refreshModel(params); + } + }, + /** NOT called every time we enter a route on Discourse. Only called the FIRST time we enter a route. diff --git a/app/assets/javascripts/discourse/routes/users.js.es6 b/app/assets/javascripts/discourse/routes/users.js.es6 index 22fc3575b4..f8aae7fb8d 100644 --- a/app/assets/javascripts/discourse/routes/users.js.es6 +++ b/app/assets/javascripts/discourse/routes/users.js.es6 @@ -2,16 +2,18 @@ export default Discourse.Route.extend({ queryParams: { period: { refreshModel: true }, order: { refreshModel: true }, - asc: { refreshModel: true }, + asc: { refreshModel: true } + }, + + refreshModel(params) { + const controller = this.controllerFor('users'); + controller.set('model.loading', true); + + this.model(params).then(model => this.setupController(controller, model)); }, model(params) { // If we refresh via `refreshModel` set the old model to loading - const existing = this.modelFor('users'); - if (existing) { - existing.set('loading', true); - } - this._period = params.period; return this.store.find('directoryItem', params); }, diff --git a/app/assets/javascripts/discourse/templates/users.hbs b/app/assets/javascripts/discourse/templates/users.hbs index 74d124e608..c486a99952 100644 --- a/app/assets/javascripts/discourse/templates/users.hbs +++ b/app/assets/javascripts/discourse/templates/users.hbs @@ -29,7 +29,7 @@ {{number item.model.post_count}} {{number item.model.topics_entered}} {{#if showTimeRead}} - {{unbound item.model.time_read}} + {{unbound item.model.time_read}} {{/if}} {{/each}} diff --git a/app/assets/stylesheets/common/base/directory.scss b/app/assets/stylesheets/common/base/directory.scss index 3a922e2a71..a904883baf 100644 --- a/app/assets/stylesheets/common/base/directory.scss +++ b/app/assets/stylesheets/common/base/directory.scss @@ -22,7 +22,11 @@ padding: 0.5em; text-align: left; border-bottom: 1px solid scale-color-diff(); - vertical-align: top; + + .number, .time-read { + font-size: 1.4em; + color: darken(scale-color-diff(), 40%); + } } tr.me { @@ -41,7 +45,7 @@ margin-right: 0.5em; } i.fa-chevron-down, i.fa-chevron-up { - margin-left: 1em; + margin-left: 0.5em; } &:hover { diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml index 7da0ac1e3e..ce53ed9651 100644 --- a/config/locales/client.en.yml +++ b/config/locales/client.en.yml @@ -239,8 +239,8 @@ en: directory: title: "User Directory" - likes_given: "Likes Given" - likes_received: "Likes Received" + likes_given: "Given" + likes_received: "Received" topics_entered: "Topics Entered" time_read: "Time Read" topic_count: "Topics" From 8bc5de665b615c23397d880b0f022258efa6fe53 Mon Sep 17 00:00:00 2001 From: Sam Date: Fri, 20 Mar 2015 09:01:32 +1100 Subject: [PATCH 069/114] message bus upgrade to correct polling in background tabs --- Gemfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index 2588ddf6a6..ffd6e6e259 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -213,7 +213,7 @@ GEM mime-types (~> 1.16) treetop (~> 1.4.8) memory_profiler (0.9.0) - message_bus (1.0.7) + message_bus (1.0.8) eventmachine rack (>= 1.1.3) redis From 9e13067be0aba414ce947245fc987e068c22d654 Mon Sep 17 00:00:00 2001 From: Robin Ward Date: Thu, 19 Mar 2015 17:16:21 -0400 Subject: [PATCH 070/114] Replace `refreshModel` with a custom property --- .../javascripts/discourse/routes/discourse.js.es6 | 15 ++++++++++----- .../javascripts/discourse/routes/users.js.es6 | 7 +------ 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/app/assets/javascripts/discourse/routes/discourse.js.es6 b/app/assets/javascripts/discourse/routes/discourse.js.es6 index 2bb5fa9544..9061124460 100644 --- a/app/assets/javascripts/discourse/routes/discourse.js.es6 +++ b/app/assets/javascripts/discourse/routes/discourse.js.es6 @@ -2,15 +2,20 @@ import showModal from 'discourse/lib/show-modal'; const DiscourseRoute = Ember.Route.extend({ - refreshModel: null, + // Set to true to refresh a model without a transition if a query param + // changes + resfreshQueryWithoutTransition: false, refresh: function() { - // Implement `refreshModel` to avoid a full transition to ourselves - if (!this.refreshModel) { return this._super(); } + if (!this.refreshQueryWithoutTransition) { return this._super(); } if (!this.router.router.activeTransition) { - const params = this.controller.getProperties(Object.keys(this.queryParams)); - this.refreshModel(params); + const controller = this.controller, + model = controller.get('model'), + params = this.controller.getProperties(Object.keys(this.queryParams)); + + model.set('loading', true); + this.model(params).then(model => this.setupController(controller, model)); } }, diff --git a/app/assets/javascripts/discourse/routes/users.js.es6 b/app/assets/javascripts/discourse/routes/users.js.es6 index f8aae7fb8d..d30e57097b 100644 --- a/app/assets/javascripts/discourse/routes/users.js.es6 +++ b/app/assets/javascripts/discourse/routes/users.js.es6 @@ -5,12 +5,7 @@ export default Discourse.Route.extend({ asc: { refreshModel: true } }, - refreshModel(params) { - const controller = this.controllerFor('users'); - controller.set('model.loading', true); - - this.model(params).then(model => this.setupController(controller, model)); - }, + refreshQueryWithoutTransition: true, model(params) { // If we refresh via `refreshModel` set the old model to loading From 051a2a3d143ddb0e601dc02879758aa7904f7f38 Mon Sep 17 00:00:00 2001 From: Robin Ward Date: Thu, 19 Mar 2015 18:07:31 -0400 Subject: [PATCH 071/114] FEATURE: Can search the user directory by name --- .../discourse/controllers/users.js.es6 | 7 ++++++- .../javascripts/discourse/lib/debounce.js | 5 ----- .../javascripts/discourse/routes/users.js.es6 | 19 ++++++++++++++++--- .../javascripts/discourse/templates/users.hbs | 7 +++++-- .../stylesheets/common/base/directory.scss | 9 +++++---- app/controllers/directory_items_controller.rb | 15 ++++++++++++++- config/locales/client.en.yml | 3 ++- 7 files changed, 48 insertions(+), 17 deletions(-) diff --git a/app/assets/javascripts/discourse/controllers/users.js.es6 b/app/assets/javascripts/discourse/controllers/users.js.es6 index 631be71d77..8ff6e6e498 100644 --- a/app/assets/javascripts/discourse/controllers/users.js.es6 +++ b/app/assets/javascripts/discourse/controllers/users.js.es6 @@ -1,11 +1,16 @@ export default Ember.Controller.extend({ - queryParams: ['period', 'order', 'asc'], + queryParams: ['period', 'order', 'asc', 'name'], period: 'weekly', order: 'likes_received', asc: null, + name: '', showTimeRead: Ember.computed.equal('period', 'all'), + _setName: Discourse.debounce(function() { + this.set('name', this.get('nameInput')); + }, 500).observes('nameInput'), + actions: { loadMore() { this.get('model').loadMore(); diff --git a/app/assets/javascripts/discourse/lib/debounce.js b/app/assets/javascripts/discourse/lib/debounce.js index 571e146ae2..583e8bb9b4 100644 --- a/app/assets/javascripts/discourse/lib/debounce.js +++ b/app/assets/javascripts/discourse/lib/debounce.js @@ -2,11 +2,6 @@ Debounce a Javascript function. This means if it's called many times in a time limit it should only be executed once (at the end of the limit counted from the last call made). Original function will be called with the context and arguments from the last call made. - - @method debounce - @module Discourse - @param {function} func The function to debounce - @param {Number} wait how long to wait **/ Discourse.debounce = function(func, wait) { var self, args; diff --git a/app/assets/javascripts/discourse/routes/users.js.es6 b/app/assets/javascripts/discourse/routes/users.js.es6 index d30e57097b..e033ae08ee 100644 --- a/app/assets/javascripts/discourse/routes/users.js.es6 +++ b/app/assets/javascripts/discourse/routes/users.js.es6 @@ -2,18 +2,31 @@ export default Discourse.Route.extend({ queryParams: { period: { refreshModel: true }, order: { refreshModel: true }, - asc: { refreshModel: true } + asc: { refreshModel: true }, + name: { refreshModel: true, replace: true } }, refreshQueryWithoutTransition: true, + resetController(controller, isExiting, transition) { + if (isExiting) { + controller.setProperties({ + period: 'weekly', + order: 'likes_received', + asc: null, + name: '' + }); + } + }, + model(params) { // If we refresh via `refreshModel` set the old model to loading - this._period = params.period; + this._params = params; return this.store.find('directoryItem', params); }, setupController(controller, model) { - controller.setProperties({ model, period: this._period }); + const params = this._params; + controller.setProperties({ model, period: params.period, nameInput: params.name }); } }); diff --git a/app/assets/javascripts/discourse/templates/users.hbs b/app/assets/javascripts/discourse/templates/users.hbs index c486a99952..83d9e8993f 100644 --- a/app/assets/javascripts/discourse/templates/users.hbs +++ b/app/assets/javascripts/discourse/templates/users.hbs @@ -1,11 +1,14 @@
    - {{period-chooser period=period}} +
    + {{period-chooser period=period}} + {{text-field value=nameInput placeholderKey="directory.filter_name" class="filter-name"}} +
    {{#loading-spinner condition=model.loading}} {{#if model.length}} - {{i18n "directory.total_rows" count=model.totalRows}} +
    {{i18n "directory.total_rows" count=model.totalRows}}
    diff --git a/app/assets/stylesheets/common/base/directory.scss b/app/assets/stylesheets/common/base/directory.scss index a904883baf..c9562135f4 100644 --- a/app/assets/stylesheets/common/base/directory.scss +++ b/app/assets/stylesheets/common/base/directory.scss @@ -4,18 +4,19 @@ .period-chooser { float: left; } - .total-rows { - margin-top: 0.5em; - color: darken(scale-color-diff(), 20%); + .filter-name { float: right; } + .total-rows { + color: darken(scale-color-diff(), 20%); + text-align: right; + } .spinner { clear: both; } table { width: 100%; - margin-top: 1em; margin-bottom: 1em; td, th { diff --git a/app/controllers/directory_items_controller.rb b/app/controllers/directory_items_controller.rb index 9de15381e2..1c44e7d54b 100644 --- a/app/controllers/directory_items_controller.rb +++ b/app/controllers/directory_items_controller.rb @@ -23,10 +23,23 @@ class DirectoryItemsController < ApplicationController end page = params[:page].to_i + user_ids = nil + if params[:name].present? + user_ids = UserSearch.new(params[:name]).search.pluck(:id) + if user_ids.present? + # Add the current user if we have at least one other match + if current_user && result.dup.where(user_id: user_ids).count > 0 + user_ids << current_user.id + end + result = result.where(user_id: user_ids) + else + result = result.where('false') + end + end result = result.order('users.username') result_count = result.dup.count - result = result.limit(PAGE_SIZE).offset(PAGE_SIZE * page) + result = result.limit(PAGE_SIZE).offset(PAGE_SIZE * page).to_a more_params = params.slice(:period, :order, :asc) more_params[:page] = page + 1 diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml index ce53ed9651..af0f69377c 100644 --- a/config/locales/client.en.yml +++ b/config/locales/client.en.yml @@ -238,6 +238,7 @@ en: sent_by_you: "Sent by you" directory: + filter_name: "filter by username" title: "User Directory" likes_given: "Given" likes_received: "Received" @@ -245,7 +246,7 @@ en: time_read: "Time Read" topic_count: "Topics" post_count: "Replies" - no_results: "No results were found for this time period." + no_results: "No results were found." total_rows: one: "1 user" other: "%{count} users" From 640a92ce305ce659399e792749b6be3844cf45d7 Mon Sep 17 00:00:00 2001 From: Robin Ward Date: Thu, 19 Mar 2015 18:30:19 -0400 Subject: [PATCH 072/114] JSHint fix --- app/assets/javascripts/discourse/routes/users.js.es6 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/assets/javascripts/discourse/routes/users.js.es6 b/app/assets/javascripts/discourse/routes/users.js.es6 index e033ae08ee..fcf816d377 100644 --- a/app/assets/javascripts/discourse/routes/users.js.es6 +++ b/app/assets/javascripts/discourse/routes/users.js.es6 @@ -8,7 +8,7 @@ export default Discourse.Route.extend({ refreshQueryWithoutTransition: true, - resetController(controller, isExiting, transition) { + resetController(controller, isExiting) { if (isExiting) { controller.setProperties({ period: 'weekly', From c5dd11f64c3def7b36460d1884960e58aae0b538 Mon Sep 17 00:00:00 2001 From: Sam Date: Fri, 20 Mar 2015 16:49:58 +1100 Subject: [PATCH 073/114] we dont need much of the escaping magic cause for whatever crazy reason this CSV format does not allow newlines --- script/import_scripts/getsatisfaction.rb | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/script/import_scripts/getsatisfaction.rb b/script/import_scripts/getsatisfaction.rb index 8e17014fd5..f7cc74fa78 100644 --- a/script/import_scripts/getsatisfaction.rb +++ b/script/import_scripts/getsatisfaction.rb @@ -35,8 +35,8 @@ class ImportScripts::GetSatisfaction < ImportScripts::Base super end - def execute + def execute c = Category.find_by(name: 'Old Forum') || Category.create!(name: 'Old Forum', user: Discourse.system_user) @@ -83,19 +83,11 @@ class ImportScripts::GetSatisfaction < ImportScripts::Base File.open(filename).each_line do |line| - # escaping is mental here - line.gsub!(/\\(.{1})/){|m| m[-1] == '"'? '""': m[-1]} line.strip! current_row << "\n" unless current_row.empty? current_row << line - double_quote_count += line.scan('"').count - - if double_quote_count % 2 == 1 - next - end - raw = begin CSV.parse(current_row, col_sep: ";") rescue CSV::MalformedCSVError => e @@ -110,6 +102,7 @@ class ImportScripts::GetSatisfaction < ImportScripts::Base current_row = "" double_quote_count = 0 + next end[0] From e70597a0d0f1da2c6e56132e8f0506a90945328a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9gis=20Hanol?= Date: Fri, 20 Mar 2015 10:17:16 +0100 Subject: [PATCH 074/114] typo --- config/locales/client.en.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml index af0f69377c..9b3399ed4d 100644 --- a/config/locales/client.en.yml +++ b/config/locales/client.en.yml @@ -1023,7 +1023,7 @@ en: title: "Feature this topic" pin: "Make this topic appear at the top of the {{categoryLink}} category." confirm_pin: "You already have {{count}} pinned topics. Too many pinned topics may be a burden for new and anonymous users. Are you sure you want to pin another topic in this category?" - unpin: "Remove this topic from the topic of the {{categoryLink}} category." + unpin: "Remove this topic from the top of the {{categoryLink}} category." pin_note: "Users can unpin the topic individually for themselves." already_pinned: zero: "No topic currently pinned in {{categoryLink}}." From 18f4f6095656f7ba4bdaf4580f978bf17d8fb0cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9gis=20Hanol?= Date: Fri, 20 Mar 2015 11:43:05 +0100 Subject: [PATCH 075/114] FIX: used 'pin' terminology instead of 'feature topic' --- .../discourse/controllers/feature-topic.js.es6 | 10 +++------- .../discourse/templates/modal/feature-topic.hbs | 4 ++-- .../discourse/templates/topic-admin-menu.hbs | 4 ++-- config/locales/client.en.yml | 2 -- 4 files changed, 7 insertions(+), 13 deletions(-) diff --git a/app/assets/javascripts/discourse/controllers/feature-topic.js.es6 b/app/assets/javascripts/discourse/controllers/feature-topic.js.es6 index 57c09e39e0..a3eb9d56d1 100644 --- a/app/assets/javascripts/discourse/controllers/feature-topic.js.es6 +++ b/app/assets/javascripts/discourse/controllers/feature-topic.js.es6 @@ -29,23 +29,19 @@ export default ObjectController.extend(ModalFunctionality, { }.property("categoryLink", "pinnedInCategoryCount"), onShow() { - const self = this; - this.set("loading", true); return Discourse.ajax("/topics/feature_stats.json", { data: { category_id: this.get("category.id") } - }).then(function(result) { + }).then(result => { if (result) { - self.setProperties({ + this.setProperties({ pinnedInCategoryCount: result.pinned_in_category_count, pinnedGloballyCount: result.pinned_globally_count, bannerCount: result.banner_count, }); } - }).finally(function() { - self.set("loading", false); - }); + }).finally(() => this.set("loading", false)); }, _forwardAction(name) { diff --git a/app/assets/javascripts/discourse/templates/modal/feature-topic.hbs b/app/assets/javascripts/discourse/templates/modal/feature-topic.hbs index 2cc24a5c1c..d06840bf56 100644 --- a/app/assets/javascripts/discourse/templates/modal/feature-topic.hbs +++ b/app/assets/javascripts/discourse/templates/modal/feature-topic.hbs @@ -58,9 +58,9 @@
    {{#if isBanner}} - {{d-button action="removeBanner" icon="bullhorn" label="topic.actions.remove_banner" class="btn-primary"}} + {{d-button action="removeBanner" icon="thumb-tack" label="topic.actions.remove_banner" class="btn-primary"}} {{else}} - {{d-button action="makeBanner" icon="bullhorn" label="topic.actions.make_banner" class="btn-primary"}} + {{d-button action="makeBanner" icon="thumb-tack" label="topic.actions.make_banner" class="btn-primary"}} {{/if}}
    diff --git a/app/assets/javascripts/discourse/templates/topic-admin-menu.hbs b/app/assets/javascripts/discourse/templates/topic-admin-menu.hbs index 195743465c..67daf1343f 100644 --- a/app/assets/javascripts/discourse/templates/topic-admin-menu.hbs +++ b/app/assets/javascripts/discourse/templates/topic-admin-menu.hbs @@ -30,9 +30,9 @@ {{#if visible}}
  • {{#if isFeatured}} - {{d-button action="showFeatureTopic" icon="bullhorn" label="topic.actions.remove_feature" class="btn-admin"}} + {{d-button action="showFeatureTopic" icon="thumb-tack" label="topic.actions.unpin" class="btn-admin"}} {{else}} - {{d-button action="showFeatureTopic" icon="bullhorn" label="topic.actions.feature" class="btn-admin"}} + {{d-button action="showFeatureTopic" icon="thumb-tack" label="topic.actions.pin" class="btn-admin"}} {{/if}}
  • {{/if}} diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml index 9b3399ed4d..571bd3938b 100644 --- a/config/locales/client.en.yml +++ b/config/locales/client.en.yml @@ -988,8 +988,6 @@ en: open: "Open Topic" close: "Close Topic" auto_close: "Auto Close" - feature: "Feature Topic" - remove_feature: "Remove Feature" make_banner: "Banner Topic" remove_banner: "Remove Banner Topic" pin: "Pin Topic" From 38fbbb28e35e13831ae88b5af99a45e92916dc7f Mon Sep 17 00:00:00 2001 From: Ben Hadley-Evans Date: Fri, 20 Mar 2015 12:53:56 +0000 Subject: [PATCH 076/114] Fix Discourse.Utilities.avatarImg test on Fx. This qUnit test was failing in Firefox 36 with "setting a property that has only a getter" because devicePixelRatio was being changed directly. The fix uses defineProperty to redefine devicePixelRatio instead. --- test/javascripts/lib/utilities-test.js.es6 | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/test/javascripts/lib/utilities-test.js.es6 b/test/javascripts/lib/utilities-test.js.es6 index 15ee484673..c73153f7da 100644 --- a/test/javascripts/lib/utilities-test.js.es6 +++ b/test/javascripts/lib/utilities-test.js.es6 @@ -123,9 +123,17 @@ test("avatarUrl", function() { equal(utils.avatarUrl('/fake/template/{size}.png', 'large'), "/fake/template/" + rawSize(45) + ".png", "different size"); }); +var setDevicePixelRatio = function(value) { + if(Object.defineProperty) { + Object.defineProperty(window, "devicePixelRatio", { value: 2 }) + } else { + window.devicePixelRatio = value; + } +}; + test("avatarImg", function() { var oldRatio = window.devicePixelRatio; - window.devicePixelRatio = 2; + setDevicePixelRatio(2); var avatarTemplate = "/path/to/avatar/{size}.png"; equal(utils.avatarImg({avatarTemplate: avatarTemplate, size: 'tiny'}), @@ -143,7 +151,7 @@ test("avatarImg", function() { blank(utils.avatarImg({avatarTemplate: "", size: 'tiny'}), "it doesn't render avatars for invalid avatar template"); - window.devicePixelRatio = oldRatio; + setDevicePixelRatio(oldRatio); }); test("allowsAttachments", function() { From 9f22be286554b0015a48b976ce6956a26638a767 Mon Sep 17 00:00:00 2001 From: Robin Ward Date: Fri, 20 Mar 2015 11:32:28 -0400 Subject: [PATCH 077/114] Restrict User Directory results more based on privacy --- app/models/directory_item.rb | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/app/models/directory_item.rb b/app/models/directory_item.rb index facd8d4874..759e1b1d81 100644 --- a/app/models/directory_item.rb +++ b/app/models/directory_item.rb @@ -44,11 +44,16 @@ class DirectoryItem < ActiveRecord::Base LEFT OUTER JOIN user_actions AS ua ON ua.user_id = u.id LEFT OUTER JOIN topics AS t ON ua.target_topic_id = t.id LEFT OUTER JOIN posts AS p ON ua.target_post_id = p.id + LEFT OUTER JOIN categories AS c ON t.category_id = c.id WHERE u.active AND NOT u.blocked AND COALESCE(ua.created_at, :since) >= :since AND t.deleted_at IS NULL + AND COALESCE(t.visible, true) + AND COALESCE(t.archetype, 'regular') = 'regular' AND p.deleted_at IS NULL + AND NOT (COALESCE(p.hidden, false)) + AND NOT COALESCE(c.read_restricted, false) AND u.id > 0 GROUP BY u.id", period_type: period_types[period_type], From 605fe4b11d3dce54f261e252e639fac26b609ae3 Mon Sep 17 00:00:00 2001 From: Robin Ward Date: Fri, 20 Mar 2015 12:14:14 -0400 Subject: [PATCH 078/114] Don't count moderator actions in the user directory stats --- app/models/directory_item.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/models/directory_item.rb b/app/models/directory_item.rb index 759e1b1d81..64361abb48 100644 --- a/app/models/directory_item.rb +++ b/app/models/directory_item.rb @@ -54,6 +54,7 @@ class DirectoryItem < ActiveRecord::Base AND p.deleted_at IS NULL AND NOT (COALESCE(p.hidden, false)) AND NOT COALESCE(c.read_restricted, false) + AND p.post_type != :moderator_action AND u.id > 0 GROUP BY u.id", period_type: period_types[period_type], @@ -61,6 +62,7 @@ class DirectoryItem < ActiveRecord::Base like_type: UserAction::LIKE, was_liked_type: UserAction::WAS_LIKED, new_topic_type: UserAction::NEW_TOPIC, - reply_type: UserAction::REPLY + reply_type: UserAction::REPLY, + moderator_action: Post.types[:moderator_action] end end From e8648350ebb155ccff4600e2b2667bcd6e7f6dfc Mon Sep 17 00:00:00 2001 From: Dan Singerman Date: Fri, 20 Mar 2015 17:03:24 +0000 Subject: [PATCH 079/114] Add an sso option to suppress welcome emails As discussed here: https://meta.discourse.org/t/create-new-sso-users-without-sending-welcome-emails/24894 --- app/models/discourse_single_sign_on.rb | 2 +- lib/single_sign_on.rb | 4 ++-- spec/models/discourse_single_sign_on_spec.rb | 22 ++++++++++++++++++++ 3 files changed, 25 insertions(+), 3 deletions(-) diff --git a/app/models/discourse_single_sign_on.rb b/app/models/discourse_single_sign_on.rb index 1c3770d862..377cb21028 100644 --- a/app/models/discourse_single_sign_on.rb +++ b/app/models/discourse_single_sign_on.rb @@ -60,7 +60,7 @@ class DiscourseSingleSignOn < SingleSignOn if sso_record && (user = sso_record.user) && !user.active user.active = true user.save! - user.enqueue_welcome_message('welcome_user') + user.enqueue_welcome_message('welcome_user') unless suppress_welcome_message end custom_fields.each do |k,v| diff --git a/lib/single_sign_on.rb b/lib/single_sign_on.rb index 928e0b00ca..66285e4dcc 100644 --- a/lib/single_sign_on.rb +++ b/lib/single_sign_on.rb @@ -1,8 +1,8 @@ class SingleSignOn ACCESSORS = [:nonce, :name, :username, :email, :avatar_url, :avatar_force_update, - :about_me, :external_id, :return_sso_url, :admin, :moderator] + :about_me, :external_id, :return_sso_url, :admin, :moderator, :suppress_welcome_message] FIXNUMS = [] - BOOLS = [:avatar_force_update, :admin, :moderator] + BOOLS = [:avatar_force_update, :admin, :moderator, :suppress_welcome_message] NONCE_EXPIRY_TIME = 10.minutes attr_accessor(*ACCESSORS) diff --git a/spec/models/discourse_single_sign_on_spec.rb b/spec/models/discourse_single_sign_on_spec.rb index e335d3d18e..8c5017bf97 100644 --- a/spec/models/discourse_single_sign_on_spec.rb +++ b/spec/models/discourse_single_sign_on_spec.rb @@ -106,6 +106,28 @@ describe DiscourseSingleSignOn do expect(sso.nonce).to_not be_nil end + context 'welcome emails' do + let(:sso) { + sso = DiscourseSingleSignOn.new + sso.username = "test" + sso.name = "test" + sso.email = "test@example.com" + sso.external_id = "A" + sso + } + + it "sends a welcome email by default" do + User.any_instance.expects(:enqueue_welcome_message).once + user = sso.lookup_or_create_user(ip_address) + end + + it "suppresses the welcome email when asked to" do + User.any_instance.expects(:enqueue_welcome_message).never + sso.suppress_welcome_message = true + user = sso.lookup_or_create_user(ip_address) + end + end + context 'when sso_overrides_avatar is enabled' do let!(:sso_record) { Fabricate(:single_sign_on_record, external_avatar_url: "http://example.com/an_image.png") } let!(:sso) { From 3c0fee178670e524173a406147b678c282559d7c Mon Sep 17 00:00:00 2001 From: Robin Ward Date: Fri, 20 Mar 2015 13:24:03 -0400 Subject: [PATCH 080/114] Fixes broken spec --- app/models/directory_item.rb | 7 ++++--- spec/models/directory_item_spec.rb | 4 ++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/app/models/directory_item.rb b/app/models/directory_item.rb index 64361abb48..0c9e5d6756 100644 --- a/app/models/directory_item.rb +++ b/app/models/directory_item.rb @@ -52,9 +52,9 @@ class DirectoryItem < ActiveRecord::Base AND COALESCE(t.visible, true) AND COALESCE(t.archetype, 'regular') = 'regular' AND p.deleted_at IS NULL - AND NOT (COALESCE(p.hidden, false)) - AND NOT COALESCE(c.read_restricted, false) - AND p.post_type != :moderator_action + AND (NOT (COALESCE(p.hidden, false))) + AND (NOT COALESCE(c.read_restricted, false)) + AND COALESCE(p.post_type, :regular_post_type) != :moderator_action AND u.id > 0 GROUP BY u.id", period_type: period_types[period_type], @@ -63,6 +63,7 @@ class DirectoryItem < ActiveRecord::Base was_liked_type: UserAction::WAS_LIKED, new_topic_type: UserAction::NEW_TOPIC, reply_type: UserAction::REPLY, + regular_post_type: Post.types[:regular], moderator_action: Post.types[:moderator_action] end end diff --git a/spec/models/directory_item_spec.rb b/spec/models/directory_item_spec.rb index 624027c241..f6008fddc0 100644 --- a/spec/models/directory_item_spec.rb +++ b/spec/models/directory_item_spec.rb @@ -2,12 +2,12 @@ require 'spec_helper' describe DirectoryItem do context 'refresh' do - let!(:user) { Fabricate(:user) } + let!(:post) { Fabricate(:post) } it "creates the record for the user" do DirectoryItem.refresh! expect(DirectoryItem.where(period_type: DirectoryItem.period_types[:all]) - .where(user_id: user.id) + .where(user_id: post.user.id) .exists?).to be_true end From 4d26ef5e298251f8e5a15ff2a6c9a7d225c09ae4 Mon Sep 17 00:00:00 2001 From: Robin Ward Date: Fri, 20 Mar 2015 14:20:50 -0400 Subject: [PATCH 081/114] Add Title tag, rename to "Users" --- app/assets/javascripts/discourse/routes/users.js.es6 | 4 ++++ config/locales/client.en.yml | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/app/assets/javascripts/discourse/routes/users.js.es6 b/app/assets/javascripts/discourse/routes/users.js.es6 index fcf816d377..e9d516543f 100644 --- a/app/assets/javascripts/discourse/routes/users.js.es6 +++ b/app/assets/javascripts/discourse/routes/users.js.es6 @@ -8,6 +8,10 @@ export default Discourse.Route.extend({ refreshQueryWithoutTransition: true, + titleToken() { + return I18n.t('directory.title'); + }, + resetController(controller, isExiting) { if (isExiting) { controller.setProperties({ diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml index 571bd3938b..fe118eb8cf 100644 --- a/config/locales/client.en.yml +++ b/config/locales/client.en.yml @@ -239,7 +239,7 @@ en: directory: filter_name: "filter by username" - title: "User Directory" + title: "Users" likes_given: "Given" likes_received: "Received" topics_entered: "Topics Entered" From 8041342267cc9d56e8e8a0c959f893b2c47505af Mon Sep 17 00:00:00 2001 From: Robin Ward Date: Fri, 20 Mar 2015 14:55:46 -0400 Subject: [PATCH 082/114] UX: Support dark themes on user directory --- app/assets/stylesheets/common/base/directory.scss | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/app/assets/stylesheets/common/base/directory.scss b/app/assets/stylesheets/common/base/directory.scss index c9562135f4..e5d9c11f31 100644 --- a/app/assets/stylesheets/common/base/directory.scss +++ b/app/assets/stylesheets/common/base/directory.scss @@ -8,7 +8,7 @@ float: right; } .total-rows { - color: darken(scale-color-diff(), 20%); + color: dark-light-diff($primary, $secondary, 50%, -50%); text-align: right; } .spinner { @@ -26,13 +26,17 @@ .number, .time-read { font-size: 1.4em; - color: darken(scale-color-diff(), 40%); + color: dark-light-diff($primary, $secondary, 50%, -50%); } } tr.me { td { background-color: scale-color($highlight, $lightness: 50%); + + .username a, .name, .title, .number, .time-read { + color: scale-color($highlight, $lightness: -50%); + } } } From 6d38005a2294a23e1754573f2ce3089fb9f12077 Mon Sep 17 00:00:00 2001 From: Robin Ward Date: Fri, 20 Mar 2015 15:18:43 -0400 Subject: [PATCH 083/114] Allow staff to change uneditable user fields --- .../discourse/controllers/preferences.js.es6 | 72 ++++++++++--------- app/controllers/users_controller.rb | 5 +- spec/controllers/users_controller_spec.rb | 15 ++++ 3 files changed, 57 insertions(+), 35 deletions(-) diff --git a/app/assets/javascripts/discourse/controllers/preferences.js.es6 b/app/assets/javascripts/discourse/controllers/preferences.js.es6 index 1e40e4ba16..b7a3bb54df 100644 --- a/app/assets/javascripts/discourse/controllers/preferences.js.es6 +++ b/app/assets/javascripts/discourse/controllers/preferences.js.es6 @@ -19,12 +19,17 @@ export default ObjectController.extend(CanCheckEmails, { newNameInput: null, userFields: function() { - var siteUserFields = this.site.get('user_fields'); + let siteUserFields = this.site.get('user_fields'); if (!Ember.isEmpty(siteUserFields)) { - var userFields = this.get('user_fields'); - return siteUserFields.filterProperty('editable', true).sortBy('field_type').map(function(uf) { - var val = userFields ? userFields[uf.get('id').toString()] : null; - return Ember.Object.create({value: val, field: uf}); + const userFields = this.get('user_fields'); + + // Staff can edit fields that are not `editable` + if (!this.get('currentUser.staff')) { + siteUserFields = siteUserFields.filterProperty('editable', true); + } + return siteUserFields.sortBy('field_type').map(function(field) { + const value = userFields ? userFields[field.get('id').toString()] : null; + return Ember.Object.create({ value, field }); }); } }.property('user_fields.@each.value'), @@ -82,16 +87,16 @@ export default ObjectController.extend(CanCheckEmails, { actions: { - save: function() { - var self = this; + save() { + const self = this; this.setProperties({ saving: true, saved: false }); - var model = this.get('model'), + const model = this.get('model'), userFields = this.get('userFields'); // Update the user fields if (!Ember.isEmpty(userFields)) { - var modelFields = model.get('user_fields'); + const modelFields = model.get('user_fields'); if (!Ember.isEmpty(modelFields)) { userFields.forEach(function(uf) { modelFields[uf.get('field.id').toString()] = uf.get('value'); @@ -120,8 +125,8 @@ export default ObjectController.extend(CanCheckEmails, { }); }, - changePassword: function() { - var self = this; + changePassword() { + const self = this; if (!this.get('passwordProgress')) { this.set('passwordProgress', I18n.t("user.change_password.in_progress")); return this.get('model').changePassword().then(function() { @@ -140,32 +145,31 @@ export default ObjectController.extend(CanCheckEmails, { } }, - delete: function() { + delete() { this.set('deleting', true); - var self = this, + const self = this, message = I18n.t('user.delete_account_confirm'), model = this.get('model'), - buttons = [{ - "label": I18n.t("cancel"), - "class": "cancel-inline", - "link": true, - "callback": function() { - self.set('deleting', false); - } - }, { - "label": ' ' + I18n.t("user.delete_account"), - "class": "btn btn-danger", - "callback": function() { - model.delete().then(function() { - bootbox.alert(I18n.t('user.deleted_yourself'), function() { - window.location.pathname = Discourse.getURL('/'); - }); - }, function() { - bootbox.alert(I18n.t('user.delete_yourself_not_allowed')); - self.set('deleting', false); - }); - } - }]; + buttons = [ + { label: I18n.t("cancel"), + class: "cancel-inline", + link: true, + callback: () => { this.set('deleting', false); } + }, + { label: ' ' + I18n.t("user.delete_account"), + class: "btn btn-danger", + callback() { + model.delete().then(function() { + bootbox.alert(I18n.t('user.deleted_yourself'), function() { + window.location.pathname = Discourse.getURL('/'); + }); + }, function() { + bootbox.alert(I18n.t('user.delete_yourself_not_allowed')); + self.set('deleting', false); + }); + } + } + ]; bootbox.dialog(message, buttons, {"classes": "delete-account"}); } } diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index 4642bef895..5f9277d121 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -73,7 +73,10 @@ class UsersController < ApplicationController if params[:user_fields].present? params[:custom_fields] = {} unless params[:custom_fields].present? - UserField.where(editable: true).each do |f| + + fields = UserField.all + fields = fields.where(editable: true) unless current_user.staff? + fields.each do |f| val = params[:user_fields][f.id.to_s] val = nil if val === "false" val = val[0...UserField.max_length] if val diff --git a/spec/controllers/users_controller_spec.rb b/spec/controllers/users_controller_spec.rb index 92b2d3fc63..8fe685e90f 100644 --- a/spec/controllers/users_controller_spec.rb +++ b/spec/controllers/users_controller_spec.rb @@ -963,6 +963,21 @@ describe UsersController do end end + context "as a staff user" do + let!(:user) { log_in(:admin) } + + context "uneditable field" do + let!(:user_field) { Fabricate(:user_field, editable: false) } + + it "allows staff to edit the field" do + put :update, username: user.username, name: 'Jim Tom', user_fields: { user_field.id.to_s => 'happy' } + expect(response).to be_success + expect(user.user_fields[user_field.id.to_s]).to eq('happy') + end + end + + end + context 'with authenticated user' do context 'with permission to update' do let!(:user) { log_in(:user) } From c6afeb2259108d945eb32c12596391a8c06f76e0 Mon Sep 17 00:00:00 2001 From: Robin Ward Date: Fri, 20 Mar 2015 15:40:28 -0400 Subject: [PATCH 084/114] Show the user card when clicking on users in the directory --- .../javascripts/discourse/components/user-small.js.es6 | 2 ++ .../discourse/templates/components/user-small.hbs | 8 ++++---- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/app/assets/javascripts/discourse/components/user-small.js.es6 b/app/assets/javascripts/discourse/components/user-small.js.es6 index d4eaf001e5..b12a0ebb40 100644 --- a/app/assets/javascripts/discourse/components/user-small.js.es6 +++ b/app/assets/javascripts/discourse/components/user-small.js.es6 @@ -1,6 +1,8 @@ export default Ember.Component.extend({ classNames: ['user-small'], + userPath: Discourse.computed.url('username', '/users/%@'), + name: function() { const name = this.get('user.name'); if (name && this.get('user.username') !== name) { diff --git a/app/assets/javascripts/discourse/templates/components/user-small.hbs b/app/assets/javascripts/discourse/templates/components/user-small.hbs index 87f72c07bc..83edc9c958 100644 --- a/app/assets/javascripts/discourse/templates/components/user-small.hbs +++ b/app/assets/javascripts/discourse/templates/components/user-small.hbs @@ -1,11 +1,11 @@
    - {{#link-to 'user' user.username}}{{avatar user imageSize="large"}}{{/link-to}} + {{avatar user imageSize="large"}}
    - {{#link-to 'user' user.username}}{{user.username}}{{/link-to}} - {{name}} + {{unbound user.username}} + {{unbound name}}
    -
    {{user.title}}
    +
    {{unbound user.title}}
    From ce09adb5ff1bcc154666b05699ef0ac75f1a6fdc Mon Sep 17 00:00:00 2001 From: Jeff Atwood Date: Fri, 20 Mar 2015 12:47:35 -0700 Subject: [PATCH 085/114] some tweaks to Feature this Topic --- .../common/base/topic-admin-menu.scss | 2 ++ config/locales/client.en.yml | 16 ++++++++-------- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/app/assets/stylesheets/common/base/topic-admin-menu.scss b/app/assets/stylesheets/common/base/topic-admin-menu.scss index 27d16c2026..3301a1ea08 100644 --- a/app/assets/stylesheets/common/base/topic-admin-menu.scss +++ b/app/assets/stylesheets/common/base/topic-admin-menu.scss @@ -35,6 +35,8 @@ .button { width: 33%; display: inline-block; + vertical-align: top; + margin-top: 15px; } .desc { display: inline-block; diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml index fe118eb8cf..3294e75a41 100644 --- a/config/locales/client.en.yml +++ b/config/locales/client.en.yml @@ -1024,23 +1024,23 @@ en: unpin: "Remove this topic from the top of the {{categoryLink}} category." pin_note: "Users can unpin the topic individually for themselves." already_pinned: - zero: "No topic currently pinned in {{categoryLink}}." - one: "Topic currently pinned in {{categoryLink}}: 1." - other: "Topics currently pinned in {{categoryLink}}: {{count}}." + zero: "There are no topics pinned in {{categoryLink}}." + one: "Topics currently pinned in {{categoryLink}}: 1" + other: "Topics currently pinned in {{categoryLink}}: {{count}}" pin_globally: "Make this topic appear at the top of all topic lists, until a staff member unpins it." confirm_pin_globally: "You already have {{count}} globally pinned topics. Too many pinned topics may be a burden for new and anonymous users. Are you sure you want to pin another topic globally?" unpin_globally: "Remove this topic from the top of all topic lists." global_pin_note: "Users can unpin the topic individually for themselves." already_pinned_globally: - zero: "No topic currently pinned globally." - one: "Topic currently pinned globally: 1." - other: "Topics currently pinned globally: {{count}}." + zero: "There are no topics pinned globally." + one: "Topics currently pinned globally: 1" + other: "Topics currently pinned globally: {{count}}." make_banner: "Make this topic into a banner that appears at the top of all pages." remove_banner: "Remove the banner that appears at the top of all pages." banner_note: "Users can dismiss the banner by closing it. Only one topic can be bannered at any given time." already_banner: - zero: "There is currently no banner topic." - one: "There is currently a banner topic." + zero: "There is no banner topic." + one: "There is currently a banner topic." inviting: "Inviting..." automatically_add_to_groups_optional: "This invite also includes access to these groups: (optional, admin only)" From 3c4cee5f629c73a921506812aeb454612eeeb89b Mon Sep 17 00:00:00 2001 From: Neil Lalonde Date: Fri, 20 Mar 2015 15:54:42 -0400 Subject: [PATCH 086/114] FIX: improve imported code blocks from bbPress importer --- script/import_scripts/bbpress.rb | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/script/import_scripts/bbpress.rb b/script/import_scripts/bbpress.rb index 3f28d36681..3ea8778cef 100644 --- a/script/import_scripts/bbpress.rb +++ b/script/import_scripts/bbpress.rb @@ -36,10 +36,15 @@ class ImportScripts::Bbpress < ImportScripts::Base user_registered created_at FROM #{table_name 'users'}", cache_rows: false) + puts '', "creating users" + create_users(users_results) do |u| ActiveSupport::HashWithIndifferentAccess.new(u) end + + puts '', '', "creating categories" + create_categories(@client.query("SELECT id, post_name, post_parent from #{table_name 'posts'} WHERE post_type = 'forum' AND post_name != '' ORDER BY post_parent")) do |c| result = {id: c['id'], name: c['post_name']} parent_id = c['post_parent'].to_i @@ -88,6 +93,9 @@ class ImportScripts::Bbpress < ImportScripts::Base mapped[:id] = post["id"] mapped[:user_id] = user_id_from_imported_user_id(post["post_author"]) || find_user_by_import_id(post["post_author"]).try(:id) || -1 mapped[:raw] = post["post_content"] + if mapped[:raw] + mapped[:raw] = mapped[:raw].gsub("
    ", "```\n").gsub("
    ", "\n```") + end mapped[:created_at] = post["post_date"] mapped[:custom_fields] = {import_id: post["id"]} From b1d78a4fd544fdde48928621c3cc818a8c5ec5a7 Mon Sep 17 00:00:00 2001 From: Neil Lalonde Date: Fri, 20 Mar 2015 17:05:13 -0400 Subject: [PATCH 087/114] FIX: use batches for speed, and show progress from importers' update_tl0 --- script/import_scripts/base.rb | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/script/import_scripts/base.rb b/script/import_scripts/base.rb index 57df5214bc..2e8c8d3336 100644 --- a/script/import_scripts/base.rb +++ b/script/import_scripts/base.rb @@ -612,8 +612,15 @@ class ImportScripts::Base end def update_tl0 - User.all.each do |user| + puts "", "setting users with no posts to trust level 0" + + total_count = User.count + progress_count = 0 + + User.find_each do |user| user.change_trust_level!(0) if Post.where(user_id: user.id).count == 0 + progress_count += 1 + print_status(progress_count, total_count) end end From acf6b253e1bb1bcf3a66aace0d6c1d61d8c4a111 Mon Sep 17 00:00:00 2001 From: Sam Date: Mon, 23 Mar 2015 11:57:59 +1100 Subject: [PATCH 088/114] FEATURE: pick a valid hostname for notification email based on hostname FEATURE: allow notification email to be set via ENV --- config/site_settings.yml | 1 + db/fixtures/999_settings.rb | 4 ++++ 2 files changed, 5 insertions(+) create mode 100644 db/fixtures/999_settings.rb diff --git a/config/site_settings.yml b/config/site_settings.yml index a958214d72..d6f3a041c6 100644 --- a/config/site_settings.yml +++ b/config/site_settings.yml @@ -31,6 +31,7 @@ required: notification_email: default: 'noreply@unconfigured.discourse.org' type: email + shadowed_by_global: true site_contact_username: default: '' type: username diff --git a/db/fixtures/999_settings.rb b/db/fixtures/999_settings.rb new file mode 100644 index 0000000000..d34d4687a2 --- /dev/null +++ b/db/fixtures/999_settings.rb @@ -0,0 +1,4 @@ +if SiteSetting.notification_email == SiteSetting.defaults[:notification_email] + # don't crash for invalid hostname, which is possible in dev + SiteSetting.notification_email = "noreply@#{Discourse.current_hostname}" rescue nil +end From 24e4808aeb9354e3e758c5ca0e6df6ab51961076 Mon Sep 17 00:00:00 2001 From: Sam Date: Mon, 23 Mar 2015 11:58:17 +1100 Subject: [PATCH 089/114] ensure titles exist --- script/import_scripts/getsatisfaction.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/script/import_scripts/getsatisfaction.rb b/script/import_scripts/getsatisfaction.rb index f7cc74fa78..7693ddbca1 100644 --- a/script/import_scripts/getsatisfaction.rb +++ b/script/import_scripts/getsatisfaction.rb @@ -238,7 +238,7 @@ class ImportScripts::GetSatisfaction < ImportScripts::Base unless topic[:post_id] - mapped[:title] = post[:title] + mapped[:title] = post[:title] || "Topic title missing" topic[:post_id] = post[:id] mapped[:category] = post[:category] else From 23ed7e9db88aa43833a25cc6075ad90a0a41ae80 Mon Sep 17 00:00:00 2001 From: Sam Date: Mon, 23 Mar 2015 12:16:21 +1100 Subject: [PATCH 090/114] Exceptions we use in the app should inherit off StandardError --- db/fixtures/999_settings.rb | 6 +++++- lib/discourse.rb | 20 ++++++++++---------- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/db/fixtures/999_settings.rb b/db/fixtures/999_settings.rb index d34d4687a2..98e0ef84dd 100644 --- a/db/fixtures/999_settings.rb +++ b/db/fixtures/999_settings.rb @@ -1,4 +1,8 @@ if SiteSetting.notification_email == SiteSetting.defaults[:notification_email] # don't crash for invalid hostname, which is possible in dev - SiteSetting.notification_email = "noreply@#{Discourse.current_hostname}" rescue nil + begin + SiteSetting.notification_email = "noreply@#{Discourse.current_hostname}" + rescue Discourse::InvalidParameters + STDERR.puts "Discourse hostname: #{Discourse.current_hostname} is not a valid domain for emails!" + end end diff --git a/lib/discourse.rb b/lib/discourse.rb index 7955d72459..3c42c12ea1 100644 --- a/lib/discourse.rb +++ b/lib/discourse.rb @@ -27,33 +27,33 @@ module Discourse end # Expected less matches than what we got in a find - class TooManyMatches < Exception; end + class TooManyMatches < StandardError; end # When they try to do something they should be logged in for - class NotLoggedIn < Exception; end + class NotLoggedIn < StandardError; end # When the input is somehow bad - class InvalidParameters < Exception; end + class InvalidParameters < StandardError; end # When they don't have permission to do something - class InvalidAccess < Exception; end + class InvalidAccess < StandardError; end # When something they want is not found - class NotFound < Exception; end + class NotFound < StandardError; end # When a setting is missing - class SiteSettingMissing < Exception; end + class SiteSettingMissing < StandardError; end # When ImageMagick is missing - class ImageMagickMissing < Exception; end + class ImageMagickMissing < StandardError; end - class InvalidPost < Exception; end + class InvalidPost < StandardError; end # When read-only mode is enabled - class ReadOnly < Exception; end + class ReadOnly < StandardError; end # Cross site request forgery - class CSRF < Exception; end + class CSRF < StandardError; end def self.filters @filters ||= [:latest, :unread, :new, :read, :posted, :bookmarks] From 23513eaf874ed6c6ffbbfadd5e034a95ec24a8c4 Mon Sep 17 00:00:00 2001 From: Sam Date: Mon, 23 Mar 2015 12:16:43 +1100 Subject: [PATCH 091/114] get satisfaction has topics with no body --- script/import_scripts/getsatisfaction.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/script/import_scripts/getsatisfaction.rb b/script/import_scripts/getsatisfaction.rb index 7693ddbca1..74a163414c 100644 --- a/script/import_scripts/getsatisfaction.rb +++ b/script/import_scripts/getsatisfaction.rb @@ -276,7 +276,7 @@ class ImportScripts::GetSatisfaction < ImportScripts::Base title: topic.subject, deleted: topic.removed == "1", closed: true, - body: topic.additional_detail && normalize_raw!(topic.additional_detail), + body: normalize_raw!(topic.additional_detail || topic.subject || ""), created_at: DateTime.parse(topic.created_at), user_id: topic.UserId, category: category.name From bb20f64cb26cdf1e5bb135df2dace86b683dda57 Mon Sep 17 00:00:00 2001 From: Sam Date: Mon, 23 Mar 2015 12:20:50 +1100 Subject: [PATCH 092/114] use standard error so its easier to catch --- app/controllers/application_controller.rb | 4 ++-- app/jobs/base.rb | 2 +- app/jobs/regular/crawl_topic_link.rb | 2 +- lib/autospec/qunit_runner.rb | 2 +- lib/rate_limiter/limit_exceeded.rb | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index e9b058151a..afaf3ef11e 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -62,7 +62,7 @@ class ApplicationController < ActionController::Base end # Some exceptions - class RenderEmpty < Exception; end + class RenderEmpty < StandardError; end # Render nothing rescue_from RenderEmpty do @@ -121,7 +121,7 @@ class ApplicationController < ActionController::Base end end - class PluginDisabled < Exception; end + class PluginDisabled < StandardError; end # If a controller requires a plugin, it will raise an exception if that plugin is # disabled. This allows plugins to be disabled programatically. diff --git a/app/jobs/base.rb b/app/jobs/base.rb index bd9f66c86a..2f7f680023 100644 --- a/app/jobs/base.rb +++ b/app/jobs/base.rb @@ -186,7 +186,7 @@ module Jobs end - class HandledExceptionWrapper < Exception + class HandledExceptionWrapper < StandardError attr_accessor :wrapped def initialize(ex) super("Wrapped #{ex.class}: #{ex.message}") diff --git a/app/jobs/regular/crawl_topic_link.rb b/app/jobs/regular/crawl_topic_link.rb index 6c0bf6a917..fa64abffa8 100644 --- a/app/jobs/regular/crawl_topic_link.rb +++ b/app/jobs/regular/crawl_topic_link.rb @@ -5,7 +5,7 @@ require 'excon' module Jobs class CrawlTopicLink < Jobs::Base - class ReadEnough < Exception; end + class ReadEnough < StandardError; end # Retrieve a header regardless of case sensitivity def self.header_for(head, name) diff --git a/lib/autospec/qunit_runner.rb b/lib/autospec/qunit_runner.rb index 3dae8a2f24..06d3e23623 100644 --- a/lib/autospec/qunit_runner.rb +++ b/lib/autospec/qunit_runner.rb @@ -24,7 +24,7 @@ module Autospec require "socket" - class PhantomJsNotInstalled < Exception; end + class PhantomJsNotInstalled < StandardError; end def initialize ensure_phantomjs_is_installed diff --git a/lib/rate_limiter/limit_exceeded.rb b/lib/rate_limiter/limit_exceeded.rb index ca6025f8e9..2b85b467b0 100644 --- a/lib/rate_limiter/limit_exceeded.rb +++ b/lib/rate_limiter/limit_exceeded.rb @@ -1,7 +1,7 @@ class RateLimiter # A rate limit has been exceeded. - class LimitExceeded < Exception + class LimitExceeded < StandardError attr_accessor :available_in def initialize(available_in) @available_in = available_in From 536c9300907bc29bcdb71072d627f5599584d62e Mon Sep 17 00:00:00 2001 From: Sam Date: Mon, 23 Mar 2015 12:26:18 +1100 Subject: [PATCH 093/114] update message bus so we pick up on Exception -> StandardError change --- Gemfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index ffd6e6e259..fba2dcc399 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -213,7 +213,7 @@ GEM mime-types (~> 1.16) treetop (~> 1.4.8) memory_profiler (0.9.0) - message_bus (1.0.8) + message_bus (1.0.9) eventmachine rack (>= 1.1.3) redis From 8cb380354ec9fc765eba5913576b6a1e0fc86d8e Mon Sep 17 00:00:00 2001 From: Sam Date: Mon, 23 Mar 2015 15:49:02 +1100 Subject: [PATCH 094/114] leftover debug code --- script/import_scripts/getsatisfaction.rb | 2 -- 1 file changed, 2 deletions(-) diff --git a/script/import_scripts/getsatisfaction.rb b/script/import_scripts/getsatisfaction.rb index 74a163414c..a448250a94 100644 --- a/script/import_scripts/getsatisfaction.rb +++ b/script/import_scripts/getsatisfaction.rb @@ -318,8 +318,6 @@ class ImportScripts::GetSatisfaction < ImportScripts::Base end import_post_batch!(posts, topic_map, count - posts.length, total) if posts.length > 0 - - exit end From 229ecc4f8a834cb14ffa09d7b8202718d405f189 Mon Sep 17 00:00:00 2001 From: Sam Date: Mon, 23 Mar 2015 15:50:45 +1100 Subject: [PATCH 095/114] FEATURE: allow end users to opt out of getting any private messages --- .../javascripts/discourse/models/user.js.es6 | 1 + .../discourse/templates/user/preferences.hbs | 1 + app/serializers/user_serializer.rb | 7 ++++- app/services/user_updater.rb | 8 +++--- config/locales/client.en.yml | 1 + ..._allow_private_messages_to_user_profile.rb | 5 ++++ lib/guardian.rb | 2 ++ spec/components/post_creator_spec.rb | 27 +++++++++++++++---- 8 files changed, 41 insertions(+), 11 deletions(-) create mode 100644 db/migrate/20150323034933_add_allow_private_messages_to_user_profile.rb diff --git a/app/assets/javascripts/discourse/models/user.js.es6 b/app/assets/javascripts/discourse/models/user.js.es6 index 23816363ea..62874c5b2e 100644 --- a/app/assets/javascripts/discourse/models/user.js.es6 +++ b/app/assets/javascripts/discourse/models/user.js.es6 @@ -181,6 +181,7 @@ const User = Discourse.Model.extend({ 'email_direct', 'email_always', 'email_private_messages', + 'allow_private_messages', 'dynamic_favicon', 'digest_after_days', 'new_topic_duration_minutes', diff --git a/app/assets/javascripts/discourse/templates/user/preferences.hbs b/app/assets/javascripts/discourse/templates/user/preferences.hbs index d7cc7b20c3..7d9ee810c4 100644 --- a/app/assets/javascripts/discourse/templates/user/preferences.hbs +++ b/app/assets/javascripts/discourse/templates/user/preferences.hbs @@ -211,6 +211,7 @@ {{preference-checkbox labelKey="user.enable_quoting" checked=enable_quoting}} {{preference-checkbox labelKey="user.dynamic_favicon" checked=dynamic_favicon}} {{preference-checkbox labelKey="user.disable_jump_reply" checked=disable_jump_reply}} + {{preference-checkbox labelKey="user.allow_private_messages" checked=allow_private_messages}} {{#unless editHistoryVisible}} {{preference-checkbox labelKey="user.edit_history_public" checked=edit_history_public}} {{/unless}} diff --git a/app/serializers/user_serializer.rb b/app/serializers/user_serializer.rb index f589b329fe..31273a8a98 100644 --- a/app/serializers/user_serializer.rb +++ b/app/serializers/user_serializer.rb @@ -95,7 +95,8 @@ class UserSerializer < BasicUserSerializer :custom_avatar_upload_id, :has_title_badges, :card_image_badge, - :card_image_badge_id + :card_image_badge_id, + :allow_private_messages untrusted_attributes :bio_raw, :bio_cooked, @@ -157,6 +158,10 @@ class UserSerializer < BasicUserSerializer object.user_profile.location end + def allow_private_messages + object.user_profile.allow_private_messages + end + def can_edit scope.can_edit?(object) end diff --git a/app/services/user_updater.rb b/app/services/user_updater.rb index 8fd14c2362..8dc753cb9b 100644 --- a/app/services/user_updater.rb +++ b/app/services/user_updater.rb @@ -19,11 +19,6 @@ class UserUpdater :edit_history_public ] - PROFILE_ATTR = [ - :location, - :dismissed_banner_key - ] - def initialize(actor, user) @user = user @guardian = Guardian.new(actor) @@ -33,6 +28,9 @@ class UserUpdater user_profile = user.user_profile user_profile.website = format_url(attributes.fetch(:website) { user_profile.website }) user_profile.bio_raw = attributes.fetch(:bio_raw) { user_profile.bio_raw } + user_profile.allow_private_messages = attributes.fetch(:allow_private_messages) { + user_profile.allow_private_messages + } user.name = attributes.fetch(:name) { user.name } user.locale = attributes.fetch(:locale) { user.locale } diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml index 3294e75a41..2a1d3522bf 100644 --- a/config/locales/client.en.yml +++ b/config/locales/client.en.yml @@ -335,6 +335,7 @@ en: dismiss_notifications: "Mark all as Read" dismiss_notifications_tooltip: "Mark all unread notifications as read" disable_jump_reply: "Don't jump to my post after I reply" + allow_private_messages: "Allow users to send me private messages" dynamic_favicon: "Show incoming message notifications on favicon (experimental)" edit_history_public: "Let other users view my post revisions" external_links_in_new_tab: "Open all external links in a new tab" diff --git a/db/migrate/20150323034933_add_allow_private_messages_to_user_profile.rb b/db/migrate/20150323034933_add_allow_private_messages_to_user_profile.rb new file mode 100644 index 0000000000..f80bc1b11c --- /dev/null +++ b/db/migrate/20150323034933_add_allow_private_messages_to_user_profile.rb @@ -0,0 +1,5 @@ +class AddAllowPrivateMessagesToUserProfile < ActiveRecord::Migration + def change + add_column :user_profiles, :allow_private_messages, :boolean, default: true, null: false + end +end diff --git a/lib/guardian.rb b/lib/guardian.rb index d3e2911ee1..3cff690120 100644 --- a/lib/guardian.rb +++ b/lib/guardian.rb @@ -260,6 +260,8 @@ class Guardian (SiteSetting.enable_private_messages || @user.username == SiteSetting.site_contact_username || @user == Discourse.system_user) && + # Only staff can send PMs to users that opt-out + (!target.is_a?(User) || is_staff? || target.user_profile.allow_private_messages) && # Can't send PMs to suspended users (is_staff? || target.is_a?(Group) || !target.suspended?) end diff --git a/spec/components/post_creator_spec.rb b/spec/components/post_creator_spec.rb index 77d658f08c..bd64f97f2d 100644 --- a/spec/components/post_creator_spec.rb +++ b/spec/components/post_creator_spec.rb @@ -393,14 +393,30 @@ describe PostCreator do let(:target_user1) { Fabricate(:coding_horror) } let(:target_user2) { Fabricate(:moderator) } let(:unrelated) { Fabricate(:user) } - let(:post) do - PostCreator.create(user, title: 'hi there welcome to my topic', + + def create_pm(from, to) + PostCreator.create(from, title: 'hi there welcome to my topic', raw: "this is my awesome message @#{unrelated.username_lower}", archetype: Archetype.private_message, - target_usernames: [target_user1.username, target_user2.username].join(','), + target_usernames: to.join(','), category: 1) end + let(:post) do + create_pm(user, [target_user1.username, target_user2.username]) + end + + it 'disallows PM to end users that disable it' do + profile = target_user2.user_profile + profile.allow_private_messages = false + profile.save + + post = create_pm(user, [target_user2.username]) + + expect(post).to be_nil + + end + it 'acts correctly' do # It's not a warning expect(post.topic.warning).to be_blank @@ -476,10 +492,11 @@ describe PostCreator do end let(:unrelated) { Fabricate(:user) } let(:post) do - PostCreator.create(user, title: 'hi there welcome to my topic', + PostCreator.new(user, title: 'hi there welcome to my topic', raw: "this is my awesome message @#{unrelated.username_lower}", archetype: Archetype.private_message, - target_group_names: group.name) + target_group_names: group.name).create + end it 'acts correctly' do From 1601211617d2e60e469042ba6ef34cad83713a73 Mon Sep 17 00:00:00 2001 From: Sam Date: Mon, 23 Mar 2015 17:21:58 +1100 Subject: [PATCH 096/114] Revert "FEATURE: allow end users to opt out of getting any private messages" This reverts commit 229ecc4f8a834cb14ffa09d7b8202718d405f189. --- .../javascripts/discourse/models/user.js.es6 | 1 - .../discourse/templates/user/preferences.hbs | 1 - app/serializers/user_serializer.rb | 7 +---- app/services/user_updater.rb | 3 --- config/locales/client.en.yml | 1 - lib/guardian.rb | 2 -- spec/components/post_creator_spec.rb | 27 ++++--------------- 7 files changed, 6 insertions(+), 36 deletions(-) diff --git a/app/assets/javascripts/discourse/models/user.js.es6 b/app/assets/javascripts/discourse/models/user.js.es6 index 62874c5b2e..23816363ea 100644 --- a/app/assets/javascripts/discourse/models/user.js.es6 +++ b/app/assets/javascripts/discourse/models/user.js.es6 @@ -181,7 +181,6 @@ const User = Discourse.Model.extend({ 'email_direct', 'email_always', 'email_private_messages', - 'allow_private_messages', 'dynamic_favicon', 'digest_after_days', 'new_topic_duration_minutes', diff --git a/app/assets/javascripts/discourse/templates/user/preferences.hbs b/app/assets/javascripts/discourse/templates/user/preferences.hbs index 7d9ee810c4..d7cc7b20c3 100644 --- a/app/assets/javascripts/discourse/templates/user/preferences.hbs +++ b/app/assets/javascripts/discourse/templates/user/preferences.hbs @@ -211,7 +211,6 @@ {{preference-checkbox labelKey="user.enable_quoting" checked=enable_quoting}} {{preference-checkbox labelKey="user.dynamic_favicon" checked=dynamic_favicon}} {{preference-checkbox labelKey="user.disable_jump_reply" checked=disable_jump_reply}} - {{preference-checkbox labelKey="user.allow_private_messages" checked=allow_private_messages}} {{#unless editHistoryVisible}} {{preference-checkbox labelKey="user.edit_history_public" checked=edit_history_public}} {{/unless}} diff --git a/app/serializers/user_serializer.rb b/app/serializers/user_serializer.rb index 31273a8a98..f589b329fe 100644 --- a/app/serializers/user_serializer.rb +++ b/app/serializers/user_serializer.rb @@ -95,8 +95,7 @@ class UserSerializer < BasicUserSerializer :custom_avatar_upload_id, :has_title_badges, :card_image_badge, - :card_image_badge_id, - :allow_private_messages + :card_image_badge_id untrusted_attributes :bio_raw, :bio_cooked, @@ -158,10 +157,6 @@ class UserSerializer < BasicUserSerializer object.user_profile.location end - def allow_private_messages - object.user_profile.allow_private_messages - end - def can_edit scope.can_edit?(object) end diff --git a/app/services/user_updater.rb b/app/services/user_updater.rb index 8dc753cb9b..1881f40a78 100644 --- a/app/services/user_updater.rb +++ b/app/services/user_updater.rb @@ -28,9 +28,6 @@ class UserUpdater user_profile = user.user_profile user_profile.website = format_url(attributes.fetch(:website) { user_profile.website }) user_profile.bio_raw = attributes.fetch(:bio_raw) { user_profile.bio_raw } - user_profile.allow_private_messages = attributes.fetch(:allow_private_messages) { - user_profile.allow_private_messages - } user.name = attributes.fetch(:name) { user.name } user.locale = attributes.fetch(:locale) { user.locale } diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml index 2a1d3522bf..3294e75a41 100644 --- a/config/locales/client.en.yml +++ b/config/locales/client.en.yml @@ -335,7 +335,6 @@ en: dismiss_notifications: "Mark all as Read" dismiss_notifications_tooltip: "Mark all unread notifications as read" disable_jump_reply: "Don't jump to my post after I reply" - allow_private_messages: "Allow users to send me private messages" dynamic_favicon: "Show incoming message notifications on favicon (experimental)" edit_history_public: "Let other users view my post revisions" external_links_in_new_tab: "Open all external links in a new tab" diff --git a/lib/guardian.rb b/lib/guardian.rb index 3cff690120..d3e2911ee1 100644 --- a/lib/guardian.rb +++ b/lib/guardian.rb @@ -260,8 +260,6 @@ class Guardian (SiteSetting.enable_private_messages || @user.username == SiteSetting.site_contact_username || @user == Discourse.system_user) && - # Only staff can send PMs to users that opt-out - (!target.is_a?(User) || is_staff? || target.user_profile.allow_private_messages) && # Can't send PMs to suspended users (is_staff? || target.is_a?(Group) || !target.suspended?) end diff --git a/spec/components/post_creator_spec.rb b/spec/components/post_creator_spec.rb index bd64f97f2d..77d658f08c 100644 --- a/spec/components/post_creator_spec.rb +++ b/spec/components/post_creator_spec.rb @@ -393,30 +393,14 @@ describe PostCreator do let(:target_user1) { Fabricate(:coding_horror) } let(:target_user2) { Fabricate(:moderator) } let(:unrelated) { Fabricate(:user) } - - def create_pm(from, to) - PostCreator.create(from, title: 'hi there welcome to my topic', + let(:post) do + PostCreator.create(user, title: 'hi there welcome to my topic', raw: "this is my awesome message @#{unrelated.username_lower}", archetype: Archetype.private_message, - target_usernames: to.join(','), + target_usernames: [target_user1.username, target_user2.username].join(','), category: 1) end - let(:post) do - create_pm(user, [target_user1.username, target_user2.username]) - end - - it 'disallows PM to end users that disable it' do - profile = target_user2.user_profile - profile.allow_private_messages = false - profile.save - - post = create_pm(user, [target_user2.username]) - - expect(post).to be_nil - - end - it 'acts correctly' do # It's not a warning expect(post.topic.warning).to be_blank @@ -492,11 +476,10 @@ describe PostCreator do end let(:unrelated) { Fabricate(:user) } let(:post) do - PostCreator.new(user, title: 'hi there welcome to my topic', + PostCreator.create(user, title: 'hi there welcome to my topic', raw: "this is my awesome message @#{unrelated.username_lower}", archetype: Archetype.private_message, - target_group_names: group.name).create - + target_group_names: group.name) end it 'acts correctly' do From 624b0b81b28d17f293e05596aa1efa4118662416 Mon Sep 17 00:00:00 2001 From: Sam Date: Mon, 23 Mar 2015 17:24:23 +1100 Subject: [PATCH 097/114] remove uneeded column --- ...062322_remove_allow_private_messages_from_user_profile.rb | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 db/migrate/20150323062322_remove_allow_private_messages_from_user_profile.rb diff --git a/db/migrate/20150323062322_remove_allow_private_messages_from_user_profile.rb b/db/migrate/20150323062322_remove_allow_private_messages_from_user_profile.rb new file mode 100644 index 0000000000..ea120aa584 --- /dev/null +++ b/db/migrate/20150323062322_remove_allow_private_messages_from_user_profile.rb @@ -0,0 +1,5 @@ +class RemoveAllowPrivateMessagesFromUserProfile < ActiveRecord::Migration + def change + remove_column :user_profiles, :allow_private_messages + end +end From 84d41be1960f633929ea2a1b7b86d53805010dc6 Mon Sep 17 00:00:00 2001 From: Kris Aubuchon Date: Mon, 23 Mar 2015 10:23:42 -0400 Subject: [PATCH 098/114] clearfix for admin contents --- app/assets/stylesheets/common/admin/admin_base.scss | 1 + .../stylesheets/common/foundation/mixins.scss | 13 +++++++++++++ 2 files changed, 14 insertions(+) diff --git a/app/assets/stylesheets/common/admin/admin_base.scss b/app/assets/stylesheets/common/admin/admin_base.scss index bb0591f5c6..095b02ff9a 100644 --- a/app/assets/stylesheets/common/admin/admin_base.scss +++ b/app/assets/stylesheets/common/admin/admin_base.scss @@ -33,6 +33,7 @@ td.flaggers td { margin-bottom: 50px; .admin-contents { padding: 8px; + @include clearfix(); } .view-options { diff --git a/app/assets/stylesheets/common/foundation/mixins.scss b/app/assets/stylesheets/common/foundation/mixins.scss index cd4fd4ca26..60a682ac09 100644 --- a/app/assets/stylesheets/common/foundation/mixins.scss +++ b/app/assets/stylesheets/common/foundation/mixins.scss @@ -33,6 +33,19 @@ // CSS3 properties // -------------------------------------------------- +// Clearfix + +@mixin clearfix() { + &:before, + &:after { + content: ""; + display: table; + } + &:after { + clear: both; + } +} + // Border radius @mixin border-radius-all($radius) { From dce258017f23d5c8a265a2d847f59fb942540793 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9gis=20Hanol?= Date: Mon, 23 Mar 2015 16:08:46 +0100 Subject: [PATCH 099/114] FIX: Avatar shows over banner on mobile cf. https://meta.discourse.org/t/avatar-shows-over-banner-on-mobile/26668 --- app/assets/stylesheets/common/components/banner.css.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/assets/stylesheets/common/components/banner.css.scss b/app/assets/stylesheets/common/components/banner.css.scss index f423c7356d..5ea03bd882 100644 --- a/app/assets/stylesheets/common/components/banner.css.scss +++ b/app/assets/stylesheets/common/components/banner.css.scss @@ -8,7 +8,7 @@ background: scale-color($tertiary, $lightness: 90%); box-shadow: 0 1px 2px scale-color($tertiary, $lightness: 70%); color: darken($tertiary, 45%); - z-index: 501; + z-index: 1001; overflow: auto; &.overlay { From 3954f69514cf763fd28cc5713fbde314423d6ab6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9gis=20Hanol?= Date: Mon, 23 Mar 2015 16:33:41 +0100 Subject: [PATCH 100/114] FIX: hoisting issue with regexp replacement patterns --- app/assets/javascripts/discourse/dialects/dialect.js | 4 +++- test/javascripts/lib/markdown-test.js.es6 | 4 ++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/app/assets/javascripts/discourse/dialects/dialect.js b/app/assets/javascripts/discourse/dialects/dialect.js index 9d0cbef8d7..e5b9048401 100644 --- a/app/assets/javascripts/discourse/dialects/dialect.js +++ b/app/assets/javascripts/discourse/dialects/dialect.js @@ -278,7 +278,9 @@ Discourse.Dialect = { var keys = Object.keys(hoisted); if (keys.length) { keys.forEach(function(key) { - result = result.replace(new RegExp(key, "g"), hoisted[key]); + result = result.replace(new RegExp(key, "g"), function() { + return hoisted[key]; + }); }); } diff --git a/test/javascripts/lib/markdown-test.js.es6 b/test/javascripts/lib/markdown-test.js.es6 index f5859165f1..25c2a69014 100644 --- a/test/javascripts/lib/markdown-test.js.es6 +++ b/test/javascripts/lib/markdown-test.js.es6 @@ -531,4 +531,8 @@ test("code blocks/spans hoisting", function() { cooked("```\n\n some code\n```", "

        some code

    ", "it works when nesting standard markdown code blocks within a fenced code block"); + + cooked("`$&`", + "

    $&

    ", + "it works even when hoisting special replacement patterns"); }); From 5bf7f3f4b568852efd0d383a98930c2558195333 Mon Sep 17 00:00:00 2001 From: Robin Ward Date: Mon, 23 Mar 2015 13:04:33 -0400 Subject: [PATCH 101/114] FIX: Leaky DOM with `combo-box` --- .../discourse/views/combo-box.js.es6 | 48 ++++++++----------- 1 file changed, 20 insertions(+), 28 deletions(-) diff --git a/app/assets/javascripts/discourse/views/combo-box.js.es6 b/app/assets/javascripts/discourse/views/combo-box.js.es6 index 7c4bea6c7d..96afbc9b89 100644 --- a/app/assets/javascripts/discourse/views/combo-box.js.es6 +++ b/app/assets/javascripts/discourse/views/combo-box.js.es6 @@ -1,29 +1,22 @@ -/** - This view handles rendering of a combobox - - @class ComboboxView - @extends Discourse.View - @namespace Discourse - @module Discourse -**/ +// This view handles rendering of a combobox export default Discourse.View.extend({ tagName: 'select', attributeBindings: ['tabindex'], classNames: ['combobox'], valueAttribute: 'id', - buildData: function(o) { - var data = ""; - if (this.dataAttributes) { - this.dataAttributes.forEach(function(a) { - data += "data-" + a + "=\"" + o.get(a) + "\" "; + buildData(o) { + let result = ""; + if (this.resultAttributes) { + this.resultAttributes.forEach(function(a) { + result += "data-" + a + "=\"" + o.get(a) + "\" "; }); } - return data; + return result; }, - render: function(buffer) { - var nameProperty = this.get('nameProperty') || 'name', + render(buffer) { + const nameProperty = this.get('nameProperty') || 'name', none = this.get('none'); // Add none option if required @@ -33,23 +26,23 @@ export default Discourse.View.extend({ buffer.push(""); } - var selected = this.get('value'); + let selected = this.get('value'); if (!Em.isNone(selected)) { selected = selected.toString(); } if (this.get('content')) { - var self = this; + const self = this; this.get('content').forEach(function(o) { - var val = o[self.get('valueAttribute')]; + let val = o[self.get('valueAttribute')]; if (!Em.isNone(val)) { val = val.toString(); } - var selectedText = (val === selected) ? "selected" : ""; + const selectedText = (val === selected) ? "selected" : ""; buffer.push(""); }); } }, valueChanged: function() { - var $combo = this.$(), + const $combo = this.$(), val = this.get('value'); if (val !== undefined && val !== null) { $combo.select2('val', val.toString()); @@ -63,7 +56,7 @@ export default Discourse.View.extend({ }.observes('content.@each'), _initializeCombo: function() { - var $elem = this.$(), + const $elem = this.$(), self = this; // Workaround for https://github.com/emberjs/ember.js/issues/9813 @@ -74,9 +67,9 @@ export default Discourse.View.extend({ $elem.select2({formatResult: this.template, minimumResultsForSearch: 5, width: 'resolve'}); - var castInteger = this.get('castInteger'); + const castInteger = this.get('castInteger'); $elem.on("change", function (e) { - var val = $(e.target).val(); + let val = $(e.target).val(); if (val.length && castInteger) { val = parseInt(val, 10); } @@ -84,9 +77,8 @@ export default Discourse.View.extend({ }); }.on('didInsertElement'), - willClearRender: function() { - var elementId = "s2id_" + this.$().attr('id'); - Ember.$("#" + elementId).remove(); - } + _destroyDropdown: function() { + this.$().select2('destroy'); + }.on('willDestroyElement') }); From 8513045381bfe2bf7b9696804600ca521b753187 Mon Sep 17 00:00:00 2001 From: Robin Ward Date: Mon, 23 Mar 2015 14:12:11 -0400 Subject: [PATCH 102/114] Include user title in email notifications --- app/helpers/application_helper.rb | 1 + app/views/email/_post.html.erb | 6 +++++- lib/email/styles.rb | 1 + 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 909c563401..3edce092e6 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -7,6 +7,7 @@ require_dependency 'configurable_urls' require_dependency 'mobile_detection' require_dependency 'category_badge' require_dependency 'global_path' +require_dependency 'canonical_url' module ApplicationHelper include CurrentUser diff --git a/app/views/email/_post.html.erb b/app/views/email/_post.html.erb index 8cacf66f99..b5447c68ed 100644 --- a/app/views/email/_post.html.erb +++ b/app/views/email/_post.html.erb @@ -5,7 +5,11 @@
    diff --git a/lib/email/styles.rb b/lib/email/styles.rb index 1257cc004d..46495aef3e 100644 --- a/lib/email/styles.rb +++ b/lib/email/styles.rb @@ -75,6 +75,7 @@ module Email style('.previous-discussion', 'font-size: 17px; color: #444;') style('.notification-date', "text-align:right;color:#999999;padding-right:5px;font-family:'lucida grande',tahoma,verdana,arial,sans-serif;font-size:11px") style('.username', "font-size:13px;font-family:'lucida grande',tahoma,verdana,arial,sans-serif;color:#3b5998;text-decoration:none;font-weight:bold") + style('.user-title', "font-size:13px;font-family:'lucida grande',tahoma,verdana,arial,sans-serif;text-decoration:none;font-weight:bold;margin-left:7px;") style('.post-wrapper', "margin-bottom:25px;") style('.user-avatar', 'vertical-align:top;width:55px;') style('.user-avatar img', nil, width: '45', height: '45') From 0124187e3a7c3aa93ee74e19bdb528160673b95c Mon Sep 17 00:00:00 2001 From: Neil Lalonde Date: Mon, 23 Mar 2015 13:52:53 -0400 Subject: [PATCH 103/114] FIX: Ning json files sometimes have an extra ] at the end --- script/import_scripts/ning.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/script/import_scripts/ning.rb b/script/import_scripts/ning.rb index 1387768757..d5a81944bc 100644 --- a/script/import_scripts/ning.rb +++ b/script/import_scripts/ning.rb @@ -55,6 +55,8 @@ class ImportScripts::Ning < ImportScripts::Base arg.gsub!(/^\(/, "") # content of file is surround by ( ) arg.gsub!(/\)$/, "") + arg.gsub!(/\]\]$/, "]") # there can be an extra ] at the end + arg.gsub!(/\}\{/, "},{") # missing commas sometimes! arg.gsub!("}]{", "},{") # surprise square brackets From 55f293d062c6965ac0c69094f73fdb3e0e3b57d2 Mon Sep 17 00:00:00 2001 From: Neil Lalonde Date: Mon, 23 Mar 2015 15:13:55 -0400 Subject: [PATCH 104/114] FEATURE: add a route to show the password reset dialog: /password-reset --- .../discourse/routes/app-route-map.js.es6 | 1 + .../discourse/routes/forgot-password.js.es6 | 22 +++++++++++++++++++ app/views/static/password_reset.html.erb | 0 config/locales/client.en.yml | 2 +- config/routes.rb | 1 + 5 files changed, 25 insertions(+), 1 deletion(-) create mode 100644 app/assets/javascripts/discourse/routes/forgot-password.js.es6 create mode 100644 app/views/static/password_reset.html.erb diff --git a/app/assets/javascripts/discourse/routes/app-route-map.js.es6 b/app/assets/javascripts/discourse/routes/app-route-map.js.es6 index 15d469230c..b866d99a27 100644 --- a/app/assets/javascripts/discourse/routes/app-route-map.js.es6 +++ b/app/assets/javascripts/discourse/routes/app-route-map.js.es6 @@ -84,6 +84,7 @@ export default function() { this.route('signup', {path: '/signup'}); this.route('login', {path: '/login'}); + this.route('forgot-password', {path: '/password-reset'}); this.route('faq', {path: '/faq'}); this.route('tos', {path: '/tos'}); this.route('privacy', {path: '/privacy'}); diff --git a/app/assets/javascripts/discourse/routes/forgot-password.js.es6 b/app/assets/javascripts/discourse/routes/forgot-password.js.es6 new file mode 100644 index 0000000000..e82fd5a8c4 --- /dev/null +++ b/app/assets/javascripts/discourse/routes/forgot-password.js.es6 @@ -0,0 +1,22 @@ +export default Discourse.Route.extend({ + beforeModel: function() { + this.replaceWith('discovery.latest').then(function(e) { + Ember.run.next(function() { + e.send('showForgotPassword'); + }); + }); + }, + + model: function() { + return Discourse.StaticPage.find('password-reset'); + }, + + renderTemplate: function() { + // do nothing + this.render('static'); + }, + + setupController: function(controller, model) { + this.controllerFor('static').set('model', model); + } +}); diff --git a/app/views/static/password_reset.html.erb b/app/views/static/password_reset.html.erb new file mode 100644 index 0000000000..e69de29bb2 diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml index 3294e75a41..82934516fc 100644 --- a/config/locales/client.en.yml +++ b/config/locales/client.en.yml @@ -629,7 +629,7 @@ en: failed: "Something went wrong, perhaps this email is already registered, try the forgot password link" forgot_password: - title: "Forgot Password" + title: "Password Reset" action: "I forgot my password" invite: "Enter your username or email address, and we'll send you a password reset email." reset: "Reset Password" diff --git a/config/routes.rb b/config/routes.rb index 5e8d9ef728..ccf716477d 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -222,6 +222,7 @@ Discourse::Application.routes.draw do resources :static post "login" => "static#enter" get "login" => "static#show", id: "login" + get "password-reset" => "static#show", id: "password_reset" get "faq" => "static#show", id: "faq" get "guidelines" => "static#show", id: "guidelines" get "tos" => "static#show", id: "tos" From 6930c8919e3b889e4bc948fe2a5ae045a9d9defb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9gis=20Hanol?= Date: Mon, 23 Mar 2015 21:35:53 +0100 Subject: [PATCH 105/114] FIX: duplicate emojis in emoji-toolbar --- app/assets/javascripts/discourse/lib/emoji/emoji.js.erb | 2 -- 1 file changed, 2 deletions(-) diff --git a/app/assets/javascripts/discourse/lib/emoji/emoji.js.erb b/app/assets/javascripts/discourse/lib/emoji/emoji.js.erb index 5abf50e18d..8a1206d886 100644 --- a/app/assets/javascripts/discourse/lib/emoji/emoji.js.erb +++ b/app/assets/javascripts/discourse/lib/emoji/emoji.js.erb @@ -14,7 +14,6 @@ Discourse.Dialect.registerEmoji = function(code, url) { Discourse.Emoji.list = function(){ var list = emoji.slice(0); - _.each(aliases, function(v,k){ list.push(k); }); _.each(extendedEmoji, function(v,k){ list.push(k); }); return list; }; @@ -72,7 +71,6 @@ Discourse.Emoji.urlFor = urlFor = function(code) { } if(!url && emojiHash.hasOwnProperty(code)) { - if (aliases.hasOwnProperty(code)) { code = aliases[code]; } url = Discourse.getURL('/images/emoji/' + set + '/' + code + '.png'); } From ff3e1e1dd7df06627c317048f2139e196d8cb07c Mon Sep 17 00:00:00 2001 From: Robin Ward Date: Mon, 23 Mar 2015 18:12:37 -0400 Subject: [PATCH 106/114] FIX: User's topic lists weren't consistent WRT visibility --- .../javascripts/discourse/models/user.js.es6 | 14 ++------------ lib/topic_query.rb | 8 +++++++- spec/components/topic_query_spec.rb | 12 ++++++++++++ 3 files changed, 21 insertions(+), 13 deletions(-) diff --git a/app/assets/javascripts/discourse/models/user.js.es6 b/app/assets/javascripts/discourse/models/user.js.es6 index 23816363ea..1f9141604e 100644 --- a/app/assets/javascripts/discourse/models/user.js.es6 +++ b/app/assets/javascripts/discourse/models/user.js.es6 @@ -256,12 +256,7 @@ const User = Discourse.Model.extend({ ua.action_type === Discourse.UserAction.TYPES.topics; }, - /** - The user's stat count, excluding PMs. - - @property statsCountNonPM - @type {Integer} - **/ + // The user's stat count, excluding PMs. statsCountNonPM: function() { var self = this; @@ -275,12 +270,7 @@ const User = Discourse.Model.extend({ return count; }.property('statsExcludingPms.@each.count'), - /** - The user's stats, excluding PMs. - - @property statsExcludingPms - @type {Array} - **/ + // The user's stats, excluding PMs. statsExcludingPms: function() { if (this.blank('stats')) return []; return this.get('stats').rejectProperty('isPM'); diff --git a/lib/topic_query.rb b/lib/topic_query.rb index 6ffdab0a59..c19e01b961 100644 --- a/lib/topic_query.rb +++ b/lib/topic_query.rb @@ -105,6 +105,7 @@ class TopicQuery end def list_topics_by(user) + @options[:filtered_to_user] = user.id create_list(:user_topics) do |topics| topics.where(user_id: user.id) end @@ -281,6 +282,10 @@ class TopicQuery options.reverse_merge!(@options) options.reverse_merge!(per_page: per_page_setting) + # Whether to return visible topics + options[:visible] = true if @user.nil? || @user.regular? + options[:visible] = false if @user && @user.id == options[:filtered_to_user] + # Start with a list of all topics result = Topic.unscoped @@ -310,7 +315,8 @@ class TopicQuery end result = result.limit(options[:per_page]) unless options[:limit] == false - result = result.visible if options[:visible] || @user.nil? || @user.regular? + + result = result.visible if options[:visible] result = result.where.not(topics: {id: options[:except_topic_ids]}).references(:topics) if options[:except_topic_ids] result = result.offset(options[:page].to_i * options[:per_page]) if options[:page] diff --git a/spec/components/topic_query_spec.rb b/spec/components/topic_query_spec.rb index 378248a501..54882d9669 100644 --- a/spec/components/topic_query_spec.rb +++ b/spec/components/topic_query_spec.rb @@ -40,6 +40,18 @@ describe TopicQuery do end + context "list_topics_by" do + + it "allows users to view their own invisible topics" do + topic = Fabricate(:topic, user: user) + invisible_topic = Fabricate(:topic, user: user, visible: false) + + expect(TopicQuery.new(nil).list_topics_by(user).topics.count).to eq(1) + expect(TopicQuery.new(user).list_topics_by(user).topics.count).to eq(2) + end + + end + context 'bookmarks' do it "filters and returns bookmarks correctly" do post = Fabricate(:post) From 92e371f0b38de9df495aa3f074177dc4251a205b Mon Sep 17 00:00:00 2001 From: Sam Date: Tue, 24 Mar 2015 11:55:22 +1100 Subject: [PATCH 107/114] FEATURE: civilized mute Allow user to mute all notifications generated by specific users --- .../javascripts/discourse/models/user.js.es6 | 3 +- .../discourse/templates/user/preferences.hbs | 8 ++++++ app/assets/stylesheets/desktop/user.scss | 6 ++-- app/models/muted_user.rb | 4 +++ app/models/user.rb | 3 ++ app/serializers/user_serializer.rb | 7 ++++- app/services/post_alerter.rb | 3 ++ app/services/user_updater.rb | 28 +++++++++++++++++++ config/locales/client.en.yml | 3 ++ db/migrate/20150323234856_add_muted_users.rb | 12 ++++++++ spec/controllers/users_controller_spec.rb | 21 +++++++++++++- spec/services/post_alerter_spec.rb | 9 ++++++ 12 files changed, 102 insertions(+), 5 deletions(-) create mode 100644 app/models/muted_user.rb create mode 100644 db/migrate/20150323234856_add_muted_users.rb diff --git a/app/assets/javascripts/discourse/models/user.js.es6 b/app/assets/javascripts/discourse/models/user.js.es6 index 1f9141604e..dc5df8c226 100644 --- a/app/assets/javascripts/discourse/models/user.js.es6 +++ b/app/assets/javascripts/discourse/models/user.js.es6 @@ -189,7 +189,8 @@ const User = Discourse.Model.extend({ 'enable_quoting', 'disable_jump_reply', 'custom_fields', - 'user_fields'); + 'user_fields', + 'muted_usernames'); ['muted','watched','tracked'].forEach(function(s){ var cats = self.get(s + 'Categories').map(function(c){ return c.get('id')}); diff --git a/app/assets/javascripts/discourse/templates/user/preferences.hbs b/app/assets/javascripts/discourse/templates/user/preferences.hbs index d7cc7b20c3..5bd6133858 100644 --- a/app/assets/javascripts/discourse/templates/user/preferences.hbs +++ b/app/assets/javascripts/discourse/templates/user/preferences.hbs @@ -237,6 +237,14 @@
    {{i18n 'user.muted_categories_instructions'}}
    +
    + +
    + + {{user-selector excludeCurrentUser=true usernames=muted_usernames class="user-selector"}} +
    +
    {{i18n 'user.muted_users_instructions'}}
    +
    {{partial 'user/preferences/saveButton'}} diff --git a/app/assets/stylesheets/desktop/user.scss b/app/assets/stylesheets/desktop/user.scss index 6936c8d605..1ce508b649 100644 --- a/app/assets/stylesheets/desktop/user.scss +++ b/app/assets/stylesheets/desktop/user.scss @@ -22,8 +22,8 @@ } .user-preferences { - input.category-group { - width: 500px; + input.category-group, input.user-selector { + width: 530px; } textarea { @@ -31,6 +31,8 @@ height: 100px; } + input + input[type=text] { @include small-width { width: 450px; diff --git a/app/models/muted_user.rb b/app/models/muted_user.rb new file mode 100644 index 0000000000..a60b30202b --- /dev/null +++ b/app/models/muted_user.rb @@ -0,0 +1,4 @@ +class MutedUser < ActiveRecord::Base + belongs_to :user + belongs_to :muted_user, class_name: 'User' +end diff --git a/app/models/user.rb b/app/models/user.rb index e815e86d25..b53d8c3e93 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -55,6 +55,9 @@ class User < ActiveRecord::Base has_many :group_managers, dependent: :destroy has_many :managed_groups, through: :group_managers, source: :group + has_many :muted_user_records, class_name: 'MutedUser' + has_many :muted_users, through: :muted_user_records + has_one :user_search_data, dependent: :destroy has_one :api_key, dependent: :destroy diff --git a/app/serializers/user_serializer.rb b/app/serializers/user_serializer.rb index f589b329fe..37d42599c8 100644 --- a/app/serializers/user_serializer.rb +++ b/app/serializers/user_serializer.rb @@ -95,7 +95,8 @@ class UserSerializer < BasicUserSerializer :custom_avatar_upload_id, :has_title_badges, :card_image_badge, - :card_image_badge_id + :card_image_badge_id, + :muted_usernames untrusted_attributes :bio_raw, :bio_cooked, @@ -252,6 +253,10 @@ class UserSerializer < BasicUserSerializer CategoryUser.lookup(object, :watching).pluck(:category_id) end + def muted_usernames + MutedUser.where(user_id: object.id).joins(:muted_user).pluck(:username) + end + def include_private_message_stats? can_edit && !(omit_stats == true) end diff --git a/app/services/post_alerter.rb b/app/services/post_alerter.rb index ac24e0ff54..e62c06c43b 100644 --- a/app/services/post_alerter.rb +++ b/app/services/post_alerter.rb @@ -86,6 +86,9 @@ class PostAlerter # Make sure the user can see the post return unless Guardian.new(user).can_see?(post) + # apply muting here + return if post.user_id && MutedUser.where(user_id: user.id, muted_user_id: post.user_id).exists? + # skip if muted on the topic return if TopicUser.get(post.topic, user).try(:notification_level) == TopicUser.notification_levels[:muted] diff --git a/app/services/user_updater.rb b/app/services/user_updater.rb index 1881f40a78..9dc5ee7948 100644 --- a/app/services/user_updater.rb +++ b/app/services/user_updater.rb @@ -66,6 +66,11 @@ class UserUpdater end User.transaction do + + if attributes.key?(:muted_usernames) + update_muted_users(attributes[:muted_usernames]) + end + user_profile.save && user.save end end @@ -74,6 +79,29 @@ class UserUpdater attr_reader :user, :guardian + def update_muted_users(usernames) + usernames ||= "" + desired_ids = User.where(username: usernames.split(",")).pluck(:id) + if desired_ids.empty? + MutedUser.where(user_id: user.id).destroy_all + else + MutedUser.where('id not in (?)', desired_ids).destroy_all + + # SQL is easier here than figuring out how to do the same in AR + MutedUser.exec_sql("INSERT into muted_users(user_id, muted_user_id, created_at, updated_at) + SELECT :user_id, id, :now, :now + FROM users + WHERE + id in (:desired_ids) AND + id NOT IN ( + SELECT muted_user_id + FROM muted_users + WHERE user_id = :user_id + )", + now: Time.now, user_id: user.id, desired_ids: desired_ids) + end + end + def format_url(website) if website =~ /^http/ website diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml index 82934516fc..d572ba63ec 100644 --- a/config/locales/client.en.yml +++ b/config/locales/client.en.yml @@ -360,6 +360,9 @@ en: delete_yourself_not_allowed: "You cannot delete your account right now. Contact an admin to do delete your account for you." unread_message_count: "Messages" admin_delete: "Delete" + users: "Users" + muted_users: "Muted" + muted_users_instructions: "Suppress all notifications from these users." staff_counters: flags_given: "helpful flags" diff --git a/db/migrate/20150323234856_add_muted_users.rb b/db/migrate/20150323234856_add_muted_users.rb new file mode 100644 index 0000000000..2e7c5048f6 --- /dev/null +++ b/db/migrate/20150323234856_add_muted_users.rb @@ -0,0 +1,12 @@ +class AddMutedUsers < ActiveRecord::Migration + def change + create_table :muted_users do |t| + t.integer :user_id, null: false + t.integer :muted_user_id, null: false + t.timestamps + end + + add_index :muted_users, [:user_id, :muted_user_id], unique: true + add_index :muted_users, [:muted_user_id, :user_id], unique: true + end +end diff --git a/spec/controllers/users_controller_spec.rb b/spec/controllers/users_controller_spec.rb index 8fe685e90f..cbd2d81659 100644 --- a/spec/controllers/users_controller_spec.rb +++ b/spec/controllers/users_controller_spec.rb @@ -983,13 +983,32 @@ describe UsersController do let!(:user) { log_in(:user) } it 'allows the update' do - put :update, username: user.username, name: 'Jim Tom', custom_fields: {test: :it} + + user2 = Fabricate(:user) + user3 = Fabricate(:user) + + put :update, + username: user.username, + name: 'Jim Tom', + custom_fields: {test: :it}, + muted_usernames: "#{user2.username},#{user3.username}" + expect(response).to be_success user.reload expect(user.name).to eq 'Jim Tom' expect(user.custom_fields['test']).to eq 'it' + expect(user.muted_users.pluck(:username).sort).to eq [user2.username,user3.username].sort + + put :update, + username: user.username, + muted_usernames: "" + + user.reload + + expect(user.muted_users.pluck(:username).sort).to be_empty + end context "with user fields" do diff --git a/spec/services/post_alerter_spec.rb b/spec/services/post_alerter_spec.rb index 1de486e195..fb6e8974c6 100644 --- a/spec/services/post_alerter_spec.rb +++ b/spec/services/post_alerter_spec.rb @@ -11,6 +11,15 @@ describe PostAlerter do context 'quotes' do + it 'does not notify for muted users' do + post = Fabricate(:post, raw: '[quote="EvilTrout, post:1"]whatup[/quote]') + MutedUser.create!(user_id: evil_trout.id, muted_user_id: post.user_id) + + lambda { + PostAlerter.post_created(post) + }.should change(evil_trout.notifications, :count).by(0) + end + it 'notifies a user by username' do lambda { create_post_with_alerts(raw: '[quote="EvilTrout, post:1"]whatup[/quote]') From 1bdce815e24c175c9f50a6e3b074e569a4a7d6e7 Mon Sep 17 00:00:00 2001 From: Sam Date: Tue, 24 Mar 2015 17:43:05 +1100 Subject: [PATCH 108/114] FIX: workaround for Safari on iOS causing crazy composer positioning see: http://stackoverflow.com/questions/29001977/safari-in-ios8-is-scrolling-screen-when-fixed-elements-get-focus --- .../discourse/lib/safari-hacks.js.es6 | 61 +++++++++++++++++++ .../discourse/views/composer.js.es6 | 4 ++ app/assets/javascripts/main_include.js | 1 + 3 files changed, 66 insertions(+) create mode 100644 app/assets/javascripts/discourse/lib/safari-hacks.js.es6 diff --git a/app/assets/javascripts/discourse/lib/safari-hacks.js.es6 b/app/assets/javascripts/discourse/lib/safari-hacks.js.es6 new file mode 100644 index 0000000000..d03d756106 --- /dev/null +++ b/app/assets/javascripts/discourse/lib/safari-hacks.js.es6 @@ -0,0 +1,61 @@ +function applicable() { + + // CriOS is Chrome on iPad / iPhone, OPiOS is Opera (they need no patching) + // Dolphin has a wierd user agent, rest seem a bit nitch + return navigator.userAgent.match(/(iPad|iPhone|iPod)/g) && + navigator.userAgent.match(/Safari/g) && + !navigator.userAgent.match(/CriOS/g) && + !navigator.userAgent.match(/OPiOS/g); +} + +// per http://stackoverflow.com/questions/29001977/safari-in-ios8-is-scrolling-screen-when-fixed-elements-get-focus/29064810 +function positioningWorkaround($fixedElement) { + if (!applicable()) { + return; + } + + const fixedElement = $fixedElement[0]; + + + var positioningHack = function(evt){ + + const self = this; + + if (fixedElement.style.position !== 'absolute') { + evt.preventDefault(); + fixedElement.style.position = 'absolute'; + fixedElement.style.top = (window.scrollY + $('.d-header').height() + 10) + 'px'; + } + + var blurred = function() { + if (_.include($(document.activeElement).parents(), fixedElement)) { + // something in focus so skip + return; + } + fixedElement.style.position = ''; + fixedElement.style.top = ''; + self.removeEventListener('blur', blurred); + }; + + blurred = _.debounce(blurred, 300); + + if (this !== document.activeElement) { + self.focus(); + } + + self.addEventListener('blur', blurred); + }; + + const checkForInputs = _.debounce(function(){ + $fixedElement.find('input,textarea').each(function(){ + if (!$(this).data('listening')) { + this.addEventListener('touchstart', positioningHack); + $(this).data('listening', true); + } + }); + }, 100); + + fixedElement.addEventListener('DOMNodeInserted', checkForInputs); +} + +export default positioningWorkaround; diff --git a/app/assets/javascripts/discourse/views/composer.js.es6 b/app/assets/javascripts/discourse/views/composer.js.es6 index 19f10e9c14..fcd4c8a76f 100644 --- a/app/assets/javascripts/discourse/views/composer.js.es6 +++ b/app/assets/javascripts/discourse/views/composer.js.es6 @@ -2,6 +2,7 @@ import userSearch from 'discourse/lib/user-search'; import afterTransition from 'discourse/lib/after-transition'; import loadScript from 'discourse/lib/load-script'; import avatarTemplate from 'discourse/lib/avatar-template'; +import positioningWorkaround from 'discourse/lib/safari-hacks'; const ComposerView = Discourse.View.extend(Ember.Evented, { _lastKeyTimeout: null, @@ -122,6 +123,9 @@ const ComposerView = Discourse.View.extend(Ember.Evented, { afterTransition($replyControl, this.resize.bind(self)); this.ensureMaximumDimensionForImagesInPreview(); this.set('controller.view', this); + + positioningWorkaround(this.$()); + }.on('didInsertElement'), _unlinkView: function() { diff --git a/app/assets/javascripts/main_include.js b/app/assets/javascripts/main_include.js index b318d01a19..9816d42f55 100644 --- a/app/assets/javascripts/main_include.js +++ b/app/assets/javascripts/main_include.js @@ -22,6 +22,7 @@ //= require ./discourse/lib/after-transition //= require ./discourse/lib/debounce //= require ./discourse/lib/avatar-template +//= require ./discourse/lib/safari-hacks //= require_tree ./discourse/adapters //= require ./discourse/models/model //= require ./discourse/models/user_action From 186c99a1a7c688e01153294f3ce9157cf38b6c09 Mon Sep 17 00:00:00 2001 From: Erick Guan Date: Tue, 24 Mar 2015 17:59:08 +0800 Subject: [PATCH 109/114] update regex to remove the bbcode tags --- script/import_scripts/discuz_x.rb | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/script/import_scripts/discuz_x.rb b/script/import_scripts/discuz_x.rb index f1232a39ec..68f1738061 100644 --- a/script/import_scripts/discuz_x.rb +++ b/script/import_scripts/discuz_x.rb @@ -364,18 +364,22 @@ class ImportScripts::DiscuzX < ImportScripts::Base # Convert image bbcode s.gsub!(/\[img=(\d+),(\d+)\]([^\]]*)\[\/img\]/i, '') - # Remove the font tag + # Remove the font, p and backcolor tag # Discourse doesn't support the font tag - s.gsub!(/\[font=[^ \t\r\n\f\]]*?\]/i, '') + s.gsub!(/\[font=[^\]]*?\]/i, '') s.gsub!(/\[\/font\]/i, '') + s.gsub!(/\[p=[^\]]*?\]/i, '') + s.gsub!(/\[\/p\]/i, '') + s.gsub!(/\[backcolor=[^\]]*?\]/i, '') + s.gsub!(/\[\/backcolor\]/i, '') # Remove the size tag # I really have no idea what is this - s.gsub!(/\[size=[^ \t\r\n\f\]]*?\]/i, '') + s.gsub!(/\[size=[^\]]*?\]/i, '') s.gsub!(/\[\/size\]/i, '') # Remove the color tag - s.gsub!(/\[color=[^ \t\r\n\f\]]*?\]/i, '') + s.gsub!(/\[color=[^\]]*?\]/i, '') s.gsub!(/\[\/color\]/i, '') # Remove the hide tag @@ -383,7 +387,7 @@ class ImportScripts::DiscuzX < ImportScripts::Base # Remove the align tag # still don't know what it is - s.gsub!(/\[align=[^ \t\r\n\f\]]*?\]/i, '') + s.gsub!(/\[align=[^\]]*?\]/i, '') s.gsub!(/\[\/align\]/i, "\n") # Convert code From 4aa20392385384c741d9f1803fb9753ad9fb69ad Mon Sep 17 00:00:00 2001 From: Robin Ward Date: Tue, 24 Mar 2015 11:25:47 -0400 Subject: [PATCH 110/114] Add full name in emails, tweak styles a bit. --- .../discourse/components/poster-name.js.es6 | 37 ++++++++----------- app/views/email/_post.html.erb | 5 ++- lib/email/styles.rb | 3 +- 3 files changed, 21 insertions(+), 24 deletions(-) diff --git a/app/assets/javascripts/discourse/components/poster-name.js.es6 b/app/assets/javascripts/discourse/components/poster-name.js.es6 index ae1617f182..3c5738cac4 100644 --- a/app/assets/javascripts/discourse/components/poster-name.js.es6 +++ b/app/assets/javascripts/discourse/components/poster-name.js.es6 @@ -1,21 +1,22 @@ -var PosterNameComponent = Em.Component.extend({ +const PosterNameComponent = Em.Component.extend({ classNames: ['names', 'trigger-user-card'], displayNameOnPosts: Discourse.computed.setting('display_name_on_posts'), // sanitize name for comparison - sanitizeName: function(name){ + sanitizeName(name){ return name.toLowerCase().replace(/[\s_-]/g,''); }, - render: function(buffer) { - var post = this.get('post'); + render(buffer) { + const post = this.get('post'); if (post) { - var name = post.get('name'), - username = post.get('username'), - linkClass = 'username', - primaryGroupName = post.get('primary_group_name'), - url = post.get('usernameUrl'); + const username = post.get('username'), + primaryGroupName = post.get('primary_group_name'), + url = post.get('usernameUrl'); + + var linkClass = 'username', + name = post.get('name'); if (post.get('staff')) { linkClass += ' staff'; } if (post.get('admin')) { linkClass += ' admin'; } @@ -29,7 +30,7 @@ var PosterNameComponent = Em.Component.extend({ buffer.push("" + username + ""); // Add a glyph if we have one - var glyph = this.posterGlyph(post); + const glyph = this.posterGlyph(post); if (!Em.isEmpty(glyph)) { buffer.push(glyph); } @@ -42,7 +43,7 @@ var PosterNameComponent = Em.Component.extend({ } // User titles - var title = post.get('user_title'); + let title = post.get('user_title'); if (!Em.isEmpty(title)) { title = Handlebars.Utils.escapeExpression(title); @@ -59,18 +60,10 @@ var PosterNameComponent = Em.Component.extend({ } }, - /** - Overwrite this to give a user a custom font awesome glyph. - - @method posterGlyph - @param {Post} the related post. - @return {String} the glyph to render (or null for none) - **/ - posterGlyph: function(post) { - var desc; - + // Overwrite this to give a user a custom font awesome glyph. + posterGlyph(post) { if(post.get('moderator')) { - desc = I18n.t('user.moderator_tooltip'); + const desc = I18n.t('user.moderator_tooltip'); return ''; } } diff --git a/app/views/email/_post.html.erb b/app/views/email/_post.html.erb index b5447c68ed..122df1af5e 100644 --- a/app/views/email/_post.html.erb +++ b/app/views/email/_post.html.erb @@ -2,10 +2,13 @@
    - <%= post.user.username %>
    + <%= post.user.username %> + <%- if post.user.title.present? %> + <%= post.user.title %> + <% end %> +
    <%= l post.created_at, format: :short_no_year %>
    - + <%= post.user.username %> + <%- if SiteSetting.enable_names? && post.user.name.present? && post.user.name != post.user.username %> + <%= post.user.name %> + <% end %> <%- if post.user.title.present? %> <%= post.user.title %> <% end %> diff --git a/lib/email/styles.rb b/lib/email/styles.rb index 46495aef3e..ee0a973c99 100644 --- a/lib/email/styles.rb +++ b/lib/email/styles.rb @@ -75,7 +75,8 @@ module Email style('.previous-discussion', 'font-size: 17px; color: #444;') style('.notification-date', "text-align:right;color:#999999;padding-right:5px;font-family:'lucida grande',tahoma,verdana,arial,sans-serif;font-size:11px") style('.username', "font-size:13px;font-family:'lucida grande',tahoma,verdana,arial,sans-serif;color:#3b5998;text-decoration:none;font-weight:bold") - style('.user-title', "font-size:13px;font-family:'lucida grande',tahoma,verdana,arial,sans-serif;text-decoration:none;font-weight:bold;margin-left:7px;") + style('.user-title', "font-size:13px;font-family:'lucida grande',tahoma,verdana,arial,sans-serif;text-decoration:none;margin-left:7px;color: #999;") + style('.user-name', "font-size:13px;font-family:'lucida grande',tahoma,verdana,arial,sans-serif;text-decoration:none;margin-left:7px;color: #3b5998;font-weight:normal;") style('.post-wrapper', "margin-bottom:25px;") style('.user-avatar', 'vertical-align:top;width:55px;') style('.user-avatar img', nil, width: '45', height: '45') From 7acae703d95022fd4a43894f5004e2a561ef9f36 Mon Sep 17 00:00:00 2001 From: Arpit Jalan Date: Tue, 24 Mar 2015 20:57:12 +0530 Subject: [PATCH 111/114] Update Translations --- config/locales/client.ar.yml | 5 +- config/locales/client.cs.yml | 21 +- config/locales/client.da.yml | 48 +++- config/locales/client.de.yml | 72 +++++- config/locales/client.es.yml | 53 +++- config/locales/client.fi.yml | 30 ++- config/locales/client.fr.yml | 51 +++- config/locales/client.he.yml | 5 +- config/locales/client.it.yml | 5 +- config/locales/client.ja.yml | 442 +++++++++++++++++++++++++++++++- config/locales/client.ko.yml | 5 +- config/locales/client.nb_NO.yml | 5 +- config/locales/client.nl.yml | 9 +- config/locales/client.pl_PL.yml | 52 +++- config/locales/client.pt.yml | 3 +- config/locales/client.pt_BR.yml | 5 +- config/locales/client.ru.yml | 26 +- config/locales/client.sq.yml | 11 +- config/locales/client.sv.yml | 5 +- config/locales/client.te.yml | 5 +- config/locales/client.tr_TR.yml | 17 +- config/locales/client.uk.yml | 3 +- config/locales/client.zh_CN.yml | 30 ++- config/locales/client.zh_TW.yml | 37 ++- config/locales/server.de.yml | 354 ++++++++++++++++++------- config/locales/server.es.yml | 6 +- config/locales/server.fi.yml | 41 --- config/locales/server.fr.yml | 7 +- config/locales/server.he.yml | 2 - config/locales/server.it.yml | 1 - config/locales/server.ja.yml | 378 ++++++++++++++++++++++++++- config/locales/server.ko.yml | 1 - config/locales/server.nl.yml | 29 +++ config/locales/server.pl_PL.yml | 1 - config/locales/server.pt.yml | 2 - config/locales/server.pt_BR.yml | 4 - config/locales/server.ru.yml | 51 +++- config/locales/server.sq.yml | 2 - config/locales/server.te.yml | 13 + config/locales/server.tr_TR.yml | 6 +- config/locales/server.uk.yml | 1 - config/locales/server.zh_CN.yml | 41 +-- config/locales/server.zh_TW.yml | 239 ++++++++++++++++- 43 files changed, 1824 insertions(+), 300 deletions(-) diff --git a/config/locales/client.ar.yml b/config/locales/client.ar.yml index 9934adcba3..1e08093d81 100644 --- a/config/locales/client.ar.yml +++ b/config/locales/client.ar.yml @@ -548,7 +548,6 @@ ar: emoji: "تعبيرات: ابتسامة" add_warning: "هذا تحذير رسمي" posting_not_on_topic: "أي موضوع تود الرد عليه؟" - saving_draft_tip: "يتم الحفظ" saved_draft_tip: "تم الحفظ" saved_local_draft_tip: "تم الحفظ محلياً" similar_topics: "موضوعك مشابه لـ ..." @@ -790,8 +789,8 @@ ar: auto_close: "إغلاق تلقائي" make_banner: "موضوع إعلاني" remove_banner: "حذف الموضوع الإعلاني" - unpin: "إلغاء تثبيت الموضوع" pin: "تثبيت الموضوع" + unpin: "إلغاء تثبيت الموضوع" pin_globally: "تثبيت الموضوع على مستوى الموقع" unarchive: "التراجع عن أرشفة الموضوع" archive: "أرشفة الموضوع" @@ -1267,8 +1266,6 @@ ar: name: "الاسم" add: "اضافة" add_members: "اضافة عضو" - custom: "مخصص" - automatic: "تلقائي" automatic_membership_email_domains: "المستخدمين الذين يمتلكون بريد الالكتروني عنوانه مطابق للعنوان الذي في القائمة سيتم تلقائيا اضافتهم للمجموعة." automatic_membership_retroactive: "اضافة الاعضاء الذين يمتكلون عنوان ايميل مطابق للعنوان الموجود في القائمة." api: diff --git a/config/locales/client.cs.yml b/config/locales/client.cs.yml index 7ea7731d63..f4d030fbe0 100644 --- a/config/locales/client.cs.yml +++ b/config/locales/client.cs.yml @@ -224,6 +224,19 @@ cs: posted_by_you: "Odesláno vámi" sent_by_user: "Posláno uživatelem {{user}}" sent_by_you: "Posláno vámi" + directory: + title: "Seznam uživatelů" + likes_given: "Rozdaných libí se" + likes_received: "Obdržených líbí se" + topics_entered: "Navštívených témat" + time_read: "Čas strávený čtením" + topic_count: "Témata" + post_count: "Odpovědi" + no_results: "Pro toto období nebylo nic nalezeno" + total_rows: + one: "nalezen 1 uživatel" + few: "nalezeni %{count} uživatelé" + other: "nalezeno %{count} uživatelů" groups: visible: "Skupina je viditelná pro všechny uživatele" title: @@ -625,7 +638,6 @@ cs: emoji: "Emoji :smile:" add_warning: "Toto je oficiální varování." posting_not_on_topic: "Rozepsali jste odpověď na téma \"{{title}}\", ale nyní máte otevřené jiné téma." - saving_draft_tip: "ukládám" saved_draft_tip: "uloženo" saved_local_draft_tip: "uloženo lokálně" similar_topics: "Podobná témata" @@ -895,10 +907,12 @@ cs: open: "Otevřít téma" close: "Zavřít téma" auto_close: "Automaticky zavřít" + feature: "Povýšit téma" + remove_feature: "Zrušit povýšení tématu" make_banner: "Banner Topic" remove_banner: "Remove Banner Topic" - unpin: "Odstranit připnutí" pin: "Připnout téma" + unpin: "Odstranit připnutí" pin_globally: "Připnout téma globálně" unarchive: "Navrátit z archivu" archive: "Archivovat téma" @@ -1390,6 +1404,7 @@ cs: title: "Nejlepší podle týdne" daily: title: "Nejlepší podle dní" + all: "Za celou dobu" this_year: "Letos" this_month: "Tenhle měsíc" this_week: "Tenhle týden" @@ -1538,8 +1553,6 @@ cs: name: "Jméno" add: "Přidat" add_members: "Přidat členy" - custom: "Přizpůsobené" - automatic: "Automatické" automatic_membership_email_domains: "Uživatelé zaregistrovaní s emailem jehož doména se přesně shoduje s jednou z tohoto seznamu budou automaticky přidáni to této skupiny:" automatic_membership_retroactive: "Aplikovat stejné doménové pravidlo na už existující uživatele" api: diff --git a/config/locales/client.da.yml b/config/locales/client.da.yml index 3da53a8d5d..ea187cd5e9 100644 --- a/config/locales/client.da.yml +++ b/config/locales/client.da.yml @@ -161,6 +161,7 @@ da: not_bookmarked: "Du har læst dette indlæg; klik for at bogmærke det" last_read: "Dette er det seneste indlæg, du har læst; klik for at bogmærke det" remove: "Fjern bogmærke" + confirm_clear: "Er du sikker på du vil slette alle bogmærker fra dette emne?" topic_count_latest: one: "{{count}} nyt eller opdateret emne." other: "{{count}} nye eller opdaterede emner." @@ -205,6 +206,15 @@ da: posted_by_you: "Oprettet af dig" sent_by_user: "Sendt af {{user}}" sent_by_you: "Sendt af dig" + directory: + title: "Bruger liste" + likes_given: "Likes givet" + likes_received: "Likes modtaget" + topics_entered: "Emner indstastet" + time_read: "Læsetid" + topic_count: "Emner" + post_count: "Svar" + no_results: "Der blev ikke fundet nogen resultater for denne periode." groups: visible: "Gruppen er synlige for alle brugere" title: @@ -601,7 +611,7 @@ da: emoji: "Emoji :smile:" add_warning: "Dette er en officiel advarsel." posting_not_on_topic: "Hvilket emne vil du svare på?" - saving_draft_tip: "gemmer" + saving_draft_tip: "gemmer..." saved_draft_tip: "gemt" saved_local_draft_tip: "gemt lokalt" similar_topics: "Dit emne minder om…" @@ -864,10 +874,12 @@ da: open: "Åbn emne" close: "Luk emne" auto_close: "Luk automatisk" + feature: "Fremhævet Emne" + remove_feature: "Fjern Fremhævning" make_banner: "Banner emne" remove_banner: "Fjern banner emne" - unpin: "Frigør emne" pin: "Fastgør emne" + unpin: "Frigør emne" pin_globally: "Fastgør emnet globalt" unarchive: "Gendan emne fra arkiv" archive: "Arkivér emne" @@ -888,6 +900,30 @@ da: title: 'Rapportér indlæg' help: 'gør moderator opmærksom på dette indlæg' success_message: 'Du har nu rapporteret dette emne til administrator.' + feature_topic: + title: "Fremhæv dette emne" + pin: "Lad dette emne stå i toppen af {{categoryLink}} kategorien." + confirm_pin: "Er du sikker? Du har allerede {{count}} pinnede emner -- for mange pinnede emner kan gør det uoverskueligt at finde de andre emner." + unpin: "Fjern dette emne fra titlen på {{categoryLink}} kategorien." + pin_note: "Brugere kan unpinne emnet individuelt." + already_pinned: + zero: "Ingen emner er pinnet lige nu i {{categoryLink}}." + one: "Emner der er pinnet i {{categoryLink}}: 1." + other: "Emner der er pinnet i {{categoryLink}}: {{count}}." + pin_globally: "Få dette emne til at stå i toppen af alle emne lister, indtil et medlem af \"staff\" unpinner det." + confirm_pin_globally: "Er du sikker? Du har allerede {{count}} globalt pinnede emner -- for mange pinnede emner, kan gøre det svært at finde andre aktive emner." + unpin_globally: "Fjern dette emne fra toppen af alle emne lister." + global_pin_note: "Brugere kan unpinne emnet individuelt." + already_pinned_globally: + zero: "Der er ingen globalt pinnede emner." + one: "Emner der er globalt pinnede: 1." + other: "Emner der er globalt pinnede: {{count}}" + make_banner: "Gør dette emne til en banner, der kommer til at stå i toppen på alle sider." + remove_banner: "Fjern banneret, der står på toppen af alle sider." + banner_note: "Brugere kan fjernet banneret ved at lukke det. Kun én banner kan være aktiv ad gangen." + already_banner: + zero: "Der er ingen banner emner lige nu." + one: "Der er et aktiv banner emne." inviting: "Inviterer…" automatically_add_to_groups_optional: "Denne invitation giver også adgang til disse grupper: (valgfrit, kun for administrator)" automatically_add_to_groups_required: "Denne invitation giver også adgang til disse grupper: (Påkrævet, kun for administrator)" @@ -1487,8 +1523,12 @@ da: name: "Navn" add: "Tilføj" add_members: "Tilføj medlemmer" - custom: "Brugerdefineret" - automatic: "Automatisk" + custom: + label: "Brugerdefineret" + title: "Brugerdefinerede grupper" + automatic: + label: "Automatisk" + title: "Automatiske grupper" automatic_membership_email_domains: "Brugere der registrerer med et email domæne der præcist matcher et på denne liste, vil automatisk blive tilføjet til denne gruppe:" automatic_membership_retroactive: "Brug denne email domæne regel til at tilføje brugere der allerede er registrerede brugere" api: diff --git a/config/locales/client.de.yml b/config/locales/client.de.yml index 63570c1ea3..55a1146b18 100644 --- a/config/locales/client.de.yml +++ b/config/locales/client.de.yml @@ -161,6 +161,7 @@ de: not_bookmarked: "Du hast diesen Beitrag gelesen. Klicke, um ein Lesezeichen zu setzen." last_read: "Das ist der letzte Beitrag, den du gelesen hast. Klicke, um ein Lesezeichen zu setzen." remove: "Lesezeichen entfernen" + confirm_clear: "Bist du sicher, dass du alle Lesezeichen in diesem Thema entfernen möchtest?" topic_count_latest: one: "{{count}} neues oder geändertes Thema." other: "{{count}} neue oder geänderte Themen." @@ -205,6 +206,18 @@ de: posted_by_you: "Von dir geschrieben" sent_by_user: "Von {{user}} gesendet" sent_by_you: "Von dir gesendet" + directory: + title: "Benutzerverzeichnis" + likes_given: "Abgegebene Likes" + likes_received: "Erhaltene Likes" + topics_entered: "Betrachtete Themen" + time_read: "Lesezeit" + topic_count: "Themen" + post_count: "Antworten" + no_results: "Keine Ergebnisse für den gewählten Zeitabschnitt gefunden." + total_rows: + one: "1 Benutzer gefunden" + other: "%{count} Benutzer gefunden" groups: visible: "Gruppe ist für alle Benutzer sichtbar" title: @@ -601,7 +614,7 @@ de: emoji: "Emoji :smile:" add_warning: "Dies ist eine offizielle Warnung." posting_not_on_topic: "Auf welches Thema möchtest du antworten?" - saving_draft_tip: "speichere" + saving_draft_tip: "wird gespeichert..." saved_draft_tip: "gespeichert" saved_local_draft_tip: "lokal gespeichert" similar_topics: "Dein Thema hat Ähnlichkeit mit..." @@ -727,6 +740,7 @@ de: close_topics: "Themen schließen" archive_topics: "Themen archivieren" notification_level: "Benachrichtigungsstufe ändern" + choose_new_category: "Neue Kategorie für die gewählten Themen:" selected: one: "Du hast ein Thema ausgewählt." other: "Du hast {{count}} Themen ausgewählt." @@ -865,10 +879,12 @@ de: open: "Thema öffnen" close: "Thema schließen" auto_close: "Automatisch schließen" + feature: "Thema hervorheben" + remove_feature: "Hervorhebung entfernen" make_banner: "Banner-Thema" remove_banner: "Kein Banner-Thema" - unpin: "Thema loslösen" pin: "Thema anheften" + unpin: "Thema loslösen" pin_globally: "Thema global anheften" unarchive: "Thema aus Archiv holen" archive: "Thema archivieren" @@ -889,6 +905,30 @@ de: title: 'Melden' help: 'Dieses Thema den Moderatoren melden oder eine private Nachricht senden.' success_message: 'Du hast dieses Thema erfolgreich gemeldet.' + feature_topic: + title: "Thema hervorheben" + pin: "Das Thema immer am Anfang der {{categoryLink}} Kategorie anzeigen." + confirm_pin: "Bist du sicher? Es gibt bereits {{count}} angeheftete Themen -- zu viele angeheftete Themen können die Sichtbarkeit anderer aktiver Themen beeinträchtigen." + unpin: "Das Thema vom Anfang der {{categoryLink}} Kategorie loslösen." + pin_note: "Benutzer können das Thema für sich selbst loslösen." + already_pinned: + zero: "Momentan sind in {{categoryLink}} keine Themen angeheftet." + one: "Momentan in {{categoryLink}} angeheftete Themen: 1." + other: "Momentan in {{categoryLink}} angeheftete Themen: {{count}}." + pin_globally: "Das Thema immer am Anfang aller Themenlisten anzeigen, bis ein Mitarbeiter es wieder loslöst." + confirm_pin_globally: "Bist du sicher? Es gibt bereits {{count}} global angeheftete Themen -- zu viele angeheftete Themen können die Sichtbarkeit anderer aktiver Themen beeinträchtigen." + unpin_globally: "Das Thema vom Anfang aller Themenlisten loslösen." + global_pin_note: "Benutzer können das Thema für sich selbst loslösen." + already_pinned_globally: + zero: "Momentan sind keine Themen global angeheftet." + one: "Momentan global angeheftete Themen: 1." + other: "Momentan global angeheftete Themen: {{count}}." + make_banner: "Macht das Thema zu einem Ankündigungsbanner, welcher am Anfang aller Seiten angezeigt wird." + remove_banner: "Entfernt das Ankündigungsbanner vom Anfang aller Seiten." + banner_note: "Benutzer können das Ankündigungsbanner schließen und so für sich selbst dauerhaft ausblenden. Es kann zu jeder Zeit höchstens ein Thema ein Banner sein." + already_banner: + zero: "Momentan gibt es kein Ankündigungsbanner." + one: "Es gibt derzeit ein anderes Ankündigungsbanner." inviting: "Einladungen werden gesendet..." automatically_add_to_groups_optional: "Diese Einladung beinhaltet auch Zugang zu den folgenden Gruppen: (optional, nur Admin)" automatically_add_to_groups_required: "Diese Einladung beinhaltet auch Zugang zu folgenden Gruppen: (erforderlich, nur Admin)" @@ -1484,8 +1524,12 @@ de: name: "Name" add: "Hinzufügen" add_members: "Mitglieder hinzufügen" - custom: "Benutzerdefiniert" - automatic: "Automatisch" + custom: + label: "Benutzerdefiniert" + title: "Benutzerdefinierte Gruppen" + automatic: + label: "Automatisch" + title: "Automatische Gruppen" automatic_membership_email_domains: "Benutzer, deren E-Mail-Domain mit einem der folgenden Listeneinträge genau übereinstimmt, werden automatisch zu dieser Gruppe hinzugefügt:" automatic_membership_retroactive: "Diese Regel auch auf existierende Benutzer anwenden, um diese zur Gruppe hinzuzufügen." api: @@ -1571,9 +1615,9 @@ de: button_title: user: "Vollständige Benutzerliste im CSV-Format exportieren." staff_action: "Vollständiges Moderations-Protokoll im CSV-Format exportieren." - screened_email: "Vollständige Liste der überprüften E-Mail-Adressen im CSV-Format exportieren." - screened_ip: "Vollständige Liste der überprüften IP-Adressen im CSV-Format exportieren." - screened_url: "Vollständige Liste der überprüften URLs im CSV-Format exportieren." + screened_email: "Vollständige Liste der gefilterten E-Mail-Adressen im CSV-Format exportieren." + screened_ip: "Vollständige Liste der gefilterten IP-Adressen im CSV-Format exportieren." + screened_url: "Vollständige Liste der gefilterten URLs im CSV-Format exportieren." invite: button_text: "Einladungen versenden" button_title: "Einladungen versenden" @@ -1737,22 +1781,23 @@ de: delete_topic: "Thema löschen" delete_post: "Beitrag löschen" impersonate: "Nutzersicht" + anonymize_user: "Benutzer anonymisieren" screened_emails: - title: "Überprüfte E-Mails" + title: "Gefilterte E-Mails" description: "Wenn jemand ein Konto erstellt, werden die folgenden E-Mail-Adressen überprüft und es wird die Anmeldung blockiert oder eine andere Aktion ausgeführt." email: "E-Mail-Adresse" actions: allow: "Erlauben" screened_urls: - title: "Überprüfte URLs" + title: "Gefilterte URLs" description: "Die aufgelisteten URLs wurden in Beiträgen verwendet, die von Spammen erstellt wurden." url: "URL" domain: "Domain" screened_ips: - title: "Überprüfte IPs" + title: "Gefilterte IPs" description: 'IP-Adressen die beobachtet werden. Benutze „Erlauben“, um IP-Adressen auf die Whitelist zu setzen.' delete_confirm: "Möchtest du wirklich die Regel für %{ip_address} entfernen?" - roll_up_confirm: "Möchtest du wirklich die häufig blockierten IP-Adressen zu Subnetzen zusammenfassen?" + roll_up_confirm: "Möchtest du wirklich die häufig gefilterten IP-Adressen zu Subnetzen zusammenfassen?" rolled_up_some_subnets: "Die geblockten IP-Adressen wurden erfolgreich zu diesen Subnetzen zusammengefasst: %{subnets}" rolled_up_no_subnet: "Es gab nichts zum Zusammenfassen." actions: @@ -1870,8 +1915,13 @@ de: approve_success: "Benutzer wurde genehmigt und eine E-Mail mit Anweisungen zur Aktivierung wurde gesendet." approve_bulk_success: "Erfolgreich! Alle ausgewählten Benutzer wurden genehmigt und benachrichtigt." time_read: "Lesezeit" + anonymize: "Benutzer anonymisieren" + anonymize_confirm: "Willst du dieses Konto wirklich anonymisieren? Dadurch werden der Benutzername und die E-Mail-Adresse unkenntlich gemacht und alle Informationen im Profil entfernt." + anonymize_yes: "Ja, diesen Benutzer anonymisieren" + anonymize_failed: "Beim Anonymisieren des Benutzers ist ein Fehler aufgetreten." delete: "Benutzer löschen" delete_forbidden_because_staff: "Administratoren und Moderatoren können nicht gelöscht werden." + delete_posts_forbidden_because_staff: "Löschen aller Beiträge von Administratoren und Moderatoren ist nicht möglich." delete_forbidden: one: "Benutzer können nicht gelöscht werden, wenn diese Beiträge haben. Lösche zuerst all dessen Beiträge, bevor du versuchst einen Benutzer zu löschen. (Beiträge, die älter als %{count} Tag sind, können nicht gelöscht werden.)" other: "Benutzer können nicht gelöscht werden, wenn diese Beiträge haben. Lösche zuerst all dessen Beiträge, bevor du versuchst einen Benutzer zu löschen. (Beiträge, die älter als %{count} Tage sind, können nicht gelöscht werden.)" diff --git a/config/locales/client.es.yml b/config/locales/client.es.yml index 6058333b10..9d50165843 100644 --- a/config/locales/client.es.yml +++ b/config/locales/client.es.yml @@ -142,7 +142,7 @@ es: all_time: "Todo el tiempo" last_7_days: "Últimos 7 días" last_30_days: "Últimos 30 días" - like_count: "Likes" + like_count: "Me Gusta" topic_count: "Temas" post_count: "Posts" user_count: "Nuevos usuarios" @@ -161,6 +161,7 @@ es: not_bookmarked: "has leído este post, haz clic para marcarlo como favorito" last_read: "este es el último post que has leído; haz clic para marcarlo como favorito" remove: "Eliminar marcador" + confirm_clear: "¿Seguro que deseas borrar todos los marcadores de este tema?" topic_count_latest: one: "Un tema nuevo o actualizado." other: "{{count}} temas nuevos o actualizados." @@ -205,6 +206,18 @@ es: posted_by_you: "Publicado por ti" sent_by_user: "Enviado por {{user}}" sent_by_you: "Enviado por ti" + directory: + title: "Directorio de usuario" + likes_given: "Me Gusta dados" + likes_received: "Me Gusta recibidos" + topics_entered: "Temas Vistos" + time_read: "Tiempo de Lectura" + topic_count: "Temas" + post_count: "Respuestas" + no_results: "No se han encontrado resultados para este período de tiempo." + total_rows: + one: "1 usuario encontrado" + other: "%{count} usuarios encontrados" groups: visible: "El grupo es visible para todos los usuarios" title: @@ -601,7 +614,7 @@ es: emoji: "Emoji :smile:" add_warning: "Ésta es una advertencia oficial." posting_not_on_topic: "¿A qué tema quieres responder?" - saving_draft_tip: "guardando" + saving_draft_tip: "guardando..." saved_draft_tip: "guardado" saved_local_draft_tip: "guardado localmente" similar_topics: "Tu tema es similar a..." @@ -864,10 +877,12 @@ es: open: "Abrir tema" close: "Cerrar tema" auto_close: "Auto-cierre" + feature: "Característica del Tema" + remove_feature: "Quitar Característica" make_banner: "Tema de encabezado. " remove_banner: "Remover tema de encabezado. " - unpin: "Dejar de destacar" pin: "Destacar tema" + unpin: "Dejar de destacar" pin_globally: "Destacar tema globalmente" unarchive: "Desarchivar Tema" archive: "Archivar Tema" @@ -888,6 +903,30 @@ es: title: 'Reportar' help: 'reportar de forma privada para atención de los moderadores o enviar una notificación privada sobre él' success_message: 'Has reportado este tema correctamente.' + feature_topic: + title: "Característica de este Tema" + pin: "Hacer que este tema aparecerá en la parte superior de la {{categoryLink}} categoría." + confirm_pin: "¿Estás seguro? Ya tiene {{count}} temas anclados - demasiados temas anclados pueden ocultar otros temas activos." + unpin: "Eliminar este tema desde el tema de la {{categoryLink}} categoría." + pin_note: "Los usuarios pueden desanclar el tema de forma individual por sí mismos." + already_pinned: + zero: "Actualmente no hay temas anclados en {{categoryLink}}." + one: "Tema anclado actualmente en {{categoryLink}}: 1." + other: "Temas anclados actualmente en {{categoryLink}}: {{count}}." + pin_globally: "Haz que este tema aparezca en la parte superior de todas las listas de temas, hasta que un miembro del personal le quite el anclaje." + confirm_pin_globally: "¿Estás seguro? Ya tiene {{count}} temas anclados a nivel global -- demasiados temas anclados pueden ocultar otros temas activos." + unpin_globally: "Eliminar este tema de la parte superior de todas las listas de temas." + global_pin_note: "Los usuarios pueden desanclar el tema de forma individual por sí mismos." + already_pinned_globally: + zero: "No hay temas anclados actualmente a nivel global." + one: "Tema anclado actualmente a nivel global: 1." + other: "Temas anclados actualmente a nivel global: {{count}}." + make_banner: "Hacer de este tema una pancarta que aparece en la parte superior de todas las páginas." + remove_banner: "Retire la pancarta que aparece en la parte superior de todas las páginas." + banner_note: "Los usuarios pueden descartar la pancarta cerrándola. Sólo un tema puede ser una pancarta en cualquier momento dado." + already_banner: + zero: "Actualmente no hay ningún tema como pancarta." + one: "Actualmente existe un tema como pancarta." inviting: "Invitando..." automatically_add_to_groups_optional: "Esta invitación incluye además acceso a estos grupos: (opcional, solo administradores)" automatically_add_to_groups_required: "Esta invitación incluye además acceso a estos grupos: (Requerido, solo administradores)" @@ -1487,8 +1526,12 @@ es: name: "Nombre" add: "Añadir" add_members: "Añadir miembros" - custom: "Personalizado" - automatic: "Automático" + custom: + label: "Personalizar" + title: "Grupos Personalizados" + automatic: + label: "Automático" + title: "Grupos Automáticos" automatic_membership_email_domains: "Los usuarios que se registren con un dominio de e-mail que esté en esta lista serán automáticamente añadidos a este grupo:" automatic_membership_retroactive: "Aplicar la misma regla de dominio de email para usuarios registrados existentes " api: diff --git a/config/locales/client.fi.yml b/config/locales/client.fi.yml index 8791f42d2e..fbe1f216dd 100644 --- a/config/locales/client.fi.yml +++ b/config/locales/client.fi.yml @@ -125,6 +125,7 @@ fi: daily: "päivittäin" weekly: "viikottain" every_two_weeks: "kahden viikon välein" + every_three_days: "joka kolmas päivä" max_of_count: "korkeintaan {{count}}" character_count: one: "{{count}} merkki" @@ -147,9 +148,10 @@ fi: user_count: "Uusia käyttäjiä" active_user_count: "Aktiivisia käyttäjiä" contact: "Yhteystiedot" - contact_info: "Sivustoon liittyvissä kiireellisissä asioissa, ota yhteyttä osoitteeseen %{contact_email}." + contact_info: "Sivustoon liittyvissä kiireellisissä asioissa, ota yhteyttä osoitteeseen %{contact_info}." bookmarked: title: "Kirjanmerkki" + clear_bookmarks: "Tyhjennä kirjanmerkit" bookmarks: not_logged_in: "pahoittelut, sinun täytyy kirjautua sisään voidaksesi lisätä viestin kirjanmerkin" created: "olet lisännyt tämän viestin kirjainmerkkeihisi" @@ -200,6 +202,18 @@ fi: posted_by_you: "Kirjoittaja sinä" sent_by_user: "Lähettäjä {{user}}" sent_by_you: "Lähettäjä sinä" + directory: + title: "Käyttäjät" + likes_given: "Annetut tykkäykset" + likes_received: "Saadut tykkäykset" + topics_entered: "Mukana ketjuissa" + time_read: "Lukuaika" + topic_count: "Ketjut" + post_count: "Vastaukset" + no_results: "Tänä aikana ei löytynyt tuloksia" + total_rows: + one: "1 käyttäjä" + other: "%{count} käyttäjää" groups: visible: "Ryhmä näkyy kaikille käyttäjille" title: @@ -397,7 +411,9 @@ fi: email_digests: title: "Lähetä tiivistelmä uusista viesteistä sähköpostilla, jos en käy sivustolla " daily: "päivittäin" + every_three_days: "joka kolmas päivä" weekly: "viikottain" + every_two_weeks: "joka toinen viikko" email_direct: "Lähetä minulle sähköposti, jos joku lainaa viestiäni, vastaa viestiini tai viittaa @nimeeni." email_private_messages: "Lähetä minulle sähköposti jos joku lähettää minulle yksityisviestin" email_always: "Älä jätä lähettämättä sähköposti-ilmoituksia, vaikka olen aktiivinen palstalla." @@ -593,7 +609,7 @@ fi: emoji: "Emoji :smile:" add_warning: "Tämä on virallinen varoitus." posting_not_on_topic: "Mihin ketjuun haluat vastata?" - saving_draft_tip: "tallennetaan" + saving_draft_tip: "tallennetaan..." saved_draft_tip: "tallennettu" saved_local_draft_tip: "tallennettu omalla koneella" similar_topics: "Tämä ketju vaikuttaa samalta kuin.." @@ -855,10 +871,12 @@ fi: open: "Avaa ketju" close: "Sulje ketju" auto_close: "Automaattinen sulkeminen" + feature: "Nosta ketju" + remove_feature: "Poista nosto" make_banner: "Tee ketjusta banneri" remove_banner: "Poista banneri" - unpin: "Poista ketjun kiinnitys" pin: "Kiinnitä ketju" + unpin: "Poista ketjun kiinnitys" pin_globally: "Kiinnitä ketju koko palstalle" unarchive: "Poista ketjun arkistointi" archive: "Arkistoi ketju" @@ -879,6 +897,8 @@ fi: title: 'Liputa' help: 'liputa tämä ketju tai lähetä siitä yksityinen ilmoitus valvojalle' success_message: 'Ketjun liputus onnistui.' + feature_topic: + title: "Nosta tämä ketju" inviting: "Kutsutaan..." automatically_add_to_groups_optional: "Tämä kutsu sisältää automaattisesti pääsyn ryhmiin: (valinnainen, vain ylläpitäjille)" automatically_add_to_groups_required: "Tämä kutsu sisältää automaattisesti pääsyn ryhmiin: (Vaaditaan, vain ylläpitäjille)" @@ -1471,8 +1491,8 @@ fi: name: "Nimi" add: "Lisää" add_members: "Lisää jäseniä" - custom: "Mukautetut" - automatic: "Automaattiset" + automatic: + label: "Automaattinen" automatic_membership_email_domains: "Käyttäjät, jotka luovat tunnuksen sähköpostiosoitteella, jonka verkkotunnus on tällä listalla, lisätään tähän ryhmään:" automatic_membership_retroactive: "Lisää jo olemassa olevat käyttäjät käyttäen samaa sääntöä verkkotunnuksista" api: diff --git a/config/locales/client.fr.yml b/config/locales/client.fr.yml index 1f51d79085..c48e880517 100644 --- a/config/locales/client.fr.yml +++ b/config/locales/client.fr.yml @@ -161,6 +161,7 @@ fr: not_bookmarked: "vous avez lu ce message; cliquez pour l'ajouter dans vos signets" last_read: "ceci est le dernier message que vous avez lu; cliquez pour l'ajouter dans vos signets" remove: "Retirer de vos signets" + confirm_clear: "Êtes-vous sûr de vouloir effacer tous les signets de ce sujet?" topic_count_latest: one: "{{count}} sujet récent." other: "{{count}} sujets récents." @@ -205,6 +206,18 @@ fr: posted_by_you: "Rédigé par vous" sent_by_user: "Envoyé par {{user}}" sent_by_you: "Envoyé par vous" + directory: + title: "Répertoire utilisateur" + likes_given: "J'aime donnés" + likes_received: "J'aime reçus" + topics_entered: "Sujets visités" + time_read: "Temps de lecture" + topic_count: "Sujets" + post_count: "Réponses" + no_results: "Aucun résultat n'a été trouvé pour cette période de temps." + total_rows: + one: "1 utilisateur trouvé" + other: "%{count} utilisateurs trouvés" groups: visible: "Ce groupe est visible par tous les utilisateurs" title: @@ -601,7 +614,7 @@ fr: emoji: "Emoji :smile:" add_warning: "Ceci est un avertissement officiel." posting_not_on_topic: "À quel sujet voulez-vous répondre ?" - saving_draft_tip: "sauvegarde…" + saving_draft_tip: "sauvegarde en cours..." saved_draft_tip: "sauvegardé" saved_local_draft_tip: "sauvegardé en local" similar_topics: "Votre message est similaire à..." @@ -868,10 +881,12 @@ fr: open: "Ouvrir Sujet" close: "Fermer le sujet" auto_close: "Fermeture automatique" + feature: "Mettre sujet en évidence" + remove_feature: "Enlever mise en évidence" make_banner: "Bannière de sujet" remove_banner: "Retirer la bannière de sujet" - unpin: "De-épingler le sujet" pin: "Épingler le sujet" + unpin: "De-épingler le sujet" pin_globally: "Épingler le sujet globalement" unarchive: "Désarchiver le sujet" archive: "Archiver le sujet" @@ -892,6 +907,30 @@ fr: title: 'Signaler' help: 'signaler secrètement ce sujet pour attirer l''attention ou envoyer une notification privée à son propos.' success_message: 'Vous avez signalé ce sujet avec succès.' + feature_topic: + title: "Mettre ce sujet en évidence" + pin: "Faire apparaître ce sujet en haut de la catégorie {{categoryLink}}." + confirm_pin: "Êtes-vous sûr? Vous avez déjà {{count}} sujets épinglés - s'il y a trop de sujets épinglés cela peut cacher les sujets actifs." + unpin: "Enlever ce sujet du haut de la catégorie {{categoryLink}}." + pin_note: "Les utilisateurs peuvent enlever l'épingle de ce sujet eux-mêmes." + already_pinned: + zero: "Aucun sujet actuellement épinglé dans {{categoryLink}}." + one: "Sujets actuellement épinglés dans {{categoryLink}}: 1." + other: "Sujets actuellement épinglés dans {{categoryLink}}: {{count}}." + pin_globally: "Faire apparaître ce sujet en haut de toutes les listes de sujet, jusqu'à ce qu'un responsable l'enlève." + confirm_pin_globally: "Êtes-vous sûr? Vous avez déjà {{count}} sujets épinglés globalement - s'il y a trop de sujets épinglés cela peut cacher les sujets actifs." + unpin_globally: "Enlever ce sujet du haut de toutes les listes de sujet." + global_pin_note: "Les utilisateurs peuvent enlever l'épingle du sujet individuellement." + already_pinned_globally: + zero: "Aucun sujet épinglé globalement." + one: "Sujets actuellement épinglés globalement : 1." + other: "Sujets actuellement épinglés globalement : {{count}}." + make_banner: "Transformer ce sujet en gros titre qui apparaît en haut de chaque page." + remove_banner: "Enlever le gros titre qui apparaît en haut de chaque page." + banner_note: "Les utilisateurs peuvent fermer le gros titre. Seul un sujet peut être mis en gros titre à la fois." + already_banner: + zero: "Il n'y a pas actuellement de sujet en gros titre." + one: "Il y a actuellement un sujet en gros titre." inviting: "Invitation en cours…" automatically_add_to_groups_optional: "Cette invitation inclus l'accès à ces groupes: (optionnel, administrateur uniquement)" automatically_add_to_groups_required: "Cette invitation inclus l'accès à ces groupes: (Requis, administrateur uniquement)" @@ -1491,8 +1530,12 @@ fr: name: "Nom" add: "Ajouter" add_members: "Ajouter des membres" - custom: "Personnaliser" - automatic: "Automatique" + custom: + label: "Personnalisé" + title: "Groupes personnalisés" + automatic: + label: "Automatique" + title: "Groupes automatiques" automatic_membership_email_domains: "Les utilisateurs qui s'enregistrent avec un domaine courriel qui correspond exactement à un élément de cette liste seront automatiquement ajoutés à ce groupe:" automatic_membership_retroactive: "Appliquer la même règle de domaine courriel pour les utilisateurs existants" api: diff --git a/config/locales/client.he.yml b/config/locales/client.he.yml index e99ed33a52..b6cf97408d 100644 --- a/config/locales/client.he.yml +++ b/config/locales/client.he.yml @@ -601,7 +601,6 @@ he: emoji: "Emoji :smile:" add_warning: "זוהי התראה רשמית." posting_not_on_topic: "לאיזה נושא רצית להגיב?" - saving_draft_tip: "שומר" saved_draft_tip: "נשמר" saved_local_draft_tip: "נשמר מקומית" similar_topics: "הנושא שלך דומה ל..." @@ -866,8 +865,8 @@ he: auto_close: "נעילה אוטומטית" make_banner: "נושא הבאנר" remove_banner: "הסרת נושא הבאנר" - unpin: "בטל נעיצת נושא" pin: "נעץ נושא" + unpin: "בטל נעיצת נושא" pin_globally: "נעץ נושא גלובלית" unarchive: "הוצא נושא מארכיון" archive: "הכנס נושא לארכיון" @@ -1487,8 +1486,6 @@ he: name: "שם" add: "הוספה" add_members: "הוספת חברים וחברות" - custom: "מותאם" - automatic: "אוטומטית" automatic_membership_email_domains: "משתמשים אשר נרשמים עם מארח דוא\"ל שתואם בדיוק לאחד מהרשימה, יוספו באופן אוטומטי לקבוצה זו:" automatic_membership_retroactive: "החלת כלל מארח דוא\"ל זהה כדי להוסיף משתמשים רשומים" api: diff --git a/config/locales/client.it.yml b/config/locales/client.it.yml index a59c43711c..5a86a93b1c 100644 --- a/config/locales/client.it.yml +++ b/config/locales/client.it.yml @@ -601,7 +601,6 @@ it: emoji: "Emoji :smile:" add_warning: "Questo è un avvertimento ufficiale." posting_not_on_topic: "A quale argomento vuoi rispondere?" - saving_draft_tip: "salvataggio" saved_draft_tip: "salvato" saved_local_draft_tip: "salvato in locale" similar_topics: "Il tuo argomento è simile a..." @@ -866,8 +865,8 @@ it: auto_close: "Chiudi Automaticamente" make_banner: "Argomento Annuncio" remove_banner: "Rimuovi Argomento Annuncio" - unpin: "Spunta Argomento" pin: "Appunta Argomento" + unpin: "Spunta Argomento" pin_globally: "Appunta Argomento Globalmente" unarchive: "De-archivia Argomento" archive: "Archivia Argomento" @@ -1483,8 +1482,6 @@ it: name: "Nome" add: "Aggiungi" add_members: "Aggiungi membri" - custom: "Personalizzato" - automatic: "Automatico" automatic_membership_email_domains: "Gli utenti che si registrano con un dominio email che corrisponde esattamente a uno presente in questa lista, saranno aggiunti automaticamente a questo gruppo:" automatic_membership_retroactive: "Applica la stessa regola sul dominio email per aggiungere utenti registrati esistenti" api: diff --git a/config/locales/client.ja.yml b/config/locales/client.ja.yml index db0a974d50..bebada7ac5 100644 --- a/config/locales/client.ja.yml +++ b/config/locales/client.ja.yml @@ -74,6 +74,8 @@ ja: facebook: 'Facebook でこのリンクを共有する' google+: 'Google+ でこのリンクを共有する' email: 'メールでこのリンクを送る' + topic_admin_menu: "トピック管理" + emails_are_disabled: "全てのメールアドレスの送信が管理者によって無効化されています。全ての種類のメール通知は行われません" edit: 'このトピックのタイトルとカテゴリを編集' not_implemented: "申し訳ありませんが、この機能はまだ実装されていません" no_value: "いいえ" @@ -123,19 +125,26 @@ ja: all_time: "All Time" last_7_days: "過去7日間" last_30_days: "過去30日間" + like_count: "いいね!" topic_count: "トピック" post_count: "ポスト" user_count: "新規ユーザ" active_user_count: "アクティブユーザ" + contact: "問い合わせ" + contact_info: "このサイトに影響を与える重要な問題や緊急の問題が発生した場合は、 %{ contact_info }までご連絡ください" bookmarked: title: "ブックマーク" clear_bookmarks: "ブックマークをクリア" + help: + bookmark: "クリックするとトピックの最初のポストをブックマークします" + unbookmark: "クリックするとトピック内の全てのブックマークを削除します" bookmarks: not_logged_in: "ポストをブックマークするには、ログインする必要があります" created: "このポストをブックマークしました" not_bookmarked: "このポストをブックマークする" last_read: "このポストをブックマークする" remove: "ブックマークを削除" + confirm_clear: "このトピックの全てのブックマークを削除してもよいですか?" topic_count_latest: other: "{{count}} 個新しいトピック" topic_count_unread: @@ -177,6 +186,17 @@ ja: posted_by_you: "あなた がポストを投稿" sent_by_user: "{{user}} が送信" sent_by_you: "あなた が送信" + directory: + title: "ユーザーディレクトリ" + likes_given: "与えた「いいね!」" + likes_received: "もらった「いいね!」" + topics_entered: "閲覧したトピック数" + time_read: "読んだ時間" + topic_count: "トピック" + post_count: "返信" + no_results: "この範囲に結果はありませんでした" + total_rows: + other: "%{count} 人のユーザー" groups: visible: "このグループは全てのユーザに表示されています。" title: @@ -227,12 +247,21 @@ ja: location_not_found: (不明) organisation: 組織 phone: 電話 + other_accounts: "同じIDアドレスを持つアカウント" + delete_other_accounts: "%{count} 件削除" + username: "ユーザ名" + trust_level: "トラストレベル" + read_time: "読んだ時間" + topics_entered: "Topics Entered" + post_count: "# ポスト" + confirm_delete_other_accounts: "これらのアカウントを削除してよいですか?" user: said: "{{username}}:" profile: "プロフィール" mute: "ミュート" edit: "プロフィールを編集" download_archive: "自分の投稿をダウンロード" + new_private_message: "プライベートメッセージ作成" private_message: "プライベートメッセージ" private_messages: "メッセージ" activity_stream: "アクティビティ" @@ -244,6 +273,7 @@ ja: notifications: "通知" dismiss_notifications: "全て既読にする" dismiss_notifications_tooltip: "全ての未読の通知を既読にします" + disable_jump_reply: "返信したあとに投稿に移動しない" dynamic_favicon: "favicon に受信したメッセージ通知を表示する" edit_history_public: "投稿編集履歴を公開する" external_links_in_new_tab: "外部リンクを全て新しいタブで開く" @@ -255,6 +285,7 @@ ja: admin_tooltip: "このユーザは管理者であり" suspended_notice: "このユーザは {{date}} までサスペンド状態です。" suspended_reason: "理由: " + github_profile: "Github" mailing_list_mode: "投稿される度にメールで通知を受け取る(ミュートにしたトピック、カテゴリー以外)" watched_categories: "参加中" watched_categories_instructions: "このカテゴリに新しく投稿されたトピックを自動的に参加します。このカテゴリに対して新しい投稿があった場合、登録されたメールアドレスと、コミュニティ内の通知ボックスに通知が届き、トピック一覧に新しい投稿数がつきます。" @@ -267,6 +298,7 @@ ja: deleted_yourself: "あなたのアカウントは削除されました。" delete_yourself_not_allowed: "アカウントを削除できませんでした。サイトアドミンを連絡してください。" unread_message_count: "メッセージ" + admin_delete: "削除" staff_counters: flags_given: "役に立たフラグ" flagged_posts: "フラグしたポスト" @@ -315,15 +347,31 @@ ja: email: title: "メールアドレス" instructions: "外部に公開されることはありません" + ok: "確認用メールを送信します" + invalid: "正しいメールアドレスを入力してください" + authenticated: "あなたのメールアドレスは{{provider}}によって認証されています" + frequency: + zero: "読んでいないメールがあった場合、すぐにメールを送信します" + one: "直前にページを閲覧していなかった場合だけメールを送信します" + other: "{{count}}分間ページを閲覧していなかった場合だけメールを送信します" name: title: "名前" instructions: "フルネーム(任意)" + too_short: "名前が短すぎます" + ok: "よい名前です" username: title: "ユーザ名" instructions: "空白を含まないユニークな名前を入力してください" + short_instructions: "@{{username}} であなたをタグ付けできます" + available: "ユーザ名は利用できます" + global_match: "メールアドレスが登録済みのユーザー名と一致しました" global_mismatch: "既に利用されています。{{suggestion}} などはいかがでしょう?" not_available: "利用できません。{{suggestion}} などはいかがでしょう?" + too_short: "ユーザ名が短すぎます" + too_long: "ユーザ名が長過ぎます" checking: "ユーザ名が利用可能か確認しています..." + enter_email: 'ユーザ名とEメールアドレスが一致' + prefilled: "この登録ユーザにマッチするメールアドレスが見つかりました" locale: title: "表示言語" instructions: "ユーザインタフェイス表示言語。ページを更新する際には、表示言語を更新されます。" @@ -341,17 +389,25 @@ ja: website: "ウェブサイト" email_settings: "メール" email_digests: + title: "サイトを訪れていない場合、ダイジェストをメールで送信する" daily: "毎日" + every_three_days: "3日毎" weekly: "毎週" + every_two_weeks: "2週間に1回" + email_direct: "自分のユーザ名に言及したり、ユーザ名が引用された場合はメールで知らせる" + email_private_messages: "プライベートメッセージが来た場合はメールを送る" email_always: "ログインしている際にメール通知を受け取る。" other_settings: "その他" categories_settings: "カテゴリ設定" new_topic_duration: label: "以下の条件でトピックを新規と見なす" + not_viewed: "未読のもの" + last_here: "前回ログアウト後に投稿されたもの" after_n_days: other: "過去{{count}}日間に投稿されたもの" after_n_weeks: other: "過去{{count}}週間に投稿されたもの" + auto_track_topics: "自動でトピックをトラックする" auto_track_options: never: "トラックしない" always: "常にトラックする" @@ -383,17 +439,23 @@ ja: none: "あなたはまだ誰も招待していません。" text: "ファイルからまとめて招待をする" uploading: "アップロード中..." + success: "ファイルアップロードが成功しました。処理が完了したら、プライベートメッセージで通知されます" error: "ファイルアップロードエラー:'{{filename}}': {{message}}" password: title: "パスワード" too_short: "パスワードが短すぎます。" common: "このパスワードは他の人が使用している可能性があります。" + same_as_username: "パスワードがユーザ名と一致しています" + same_as_email: "パスワードとメールアドレスが一致しています" ok: "パスワード OK。" instructions: "%{count} 文字以上の長さにしてください。" + associated_accounts: "関連アカウント" ip_address: title: "最近使用したIPアドレス" registration_ip_address: title: "登録したときのIPアドレス" + avatar: + title: "プロフィール画像" title: title: "タイトル" filters: @@ -423,6 +485,8 @@ ja: fixed: "ページロード" close: "閉じる" assets_changed_confirm: "Discourseはアップデートされました。ページ更新して最新バージョンを導入しますか?" + logout: "ログアウトしました" + refresh: "Refresh" read_only_mode: enabled: "読み取り専用モードにされています。サイトインターアクションを無効されています。" login_disabled: "読み取り専用モードにされています。ログインできません。" @@ -461,6 +525,7 @@ ja: created: '作成' created_lowercase: '作成' trust_level: 'トラストレベル' + search_hint: 'ユーザ名、メールアドレスまたはIPアドレス' create_account: title: "アカウントの作成" failed: "エラーが発生しました。既にこのメールアドレスは使用中かもしれません。「パスワードを忘れました」リンクを試してみてください" @@ -492,6 +557,7 @@ ja: requires_invite: "申し訳ありませんが、このフォーラムは招待制です。" not_activated: "まだログインできません。{{sentTo}} にアクティベーションメールを送信しております。メールの指示に従ってアカウントのアクティベーションを行ってください。" not_allowed_from_ip_address: "このIPアドレスでログインできません" + admin_not_allowed_from_ip_address: "そのIPアドレスからは管理者としてログインできません" resend_activation_email: "再度アクティベーションメールを送信するにはここをクリックシてください。" sent_activation_email_again: "{{currentEmail}} にアクティベーションメールを再送しました。メール到着まで数分かかることがあります (いつまで立ってもメールが届かない場合は、念のためスパムフォルダの中も確認してみてください)。" google: @@ -512,10 +578,15 @@ ja: github: title: "with GitHub" message: "Github による認証 (ポップアップがブロックされていないことを確認してください)" + apple_international: "Apple/International" + google: "Google" + twitter: "Twitter" + emoji_one: "Emoji One" composer: + emoji: "Emoji :smile:" add_warning: "これは公式の警告です。" posting_not_on_topic: "回答したいトピックはどれですか?" - saving_draft_tip: "保存中" + saving_draft_tip: "保存中..." saved_draft_tip: "保存しました" saved_local_draft_tip: "ローカルに保存しました" similar_topics: "このトピックに似ているトピック..." @@ -532,6 +603,8 @@ ja: reply_here: "ここに回答" reply: "回答" cancel: "キャンセル" + create_topic: "新しいトピック" + create_pm: "プライベートメッセージ" title: "またはCtrl+Enter" users_placeholder: "ユーザの追加" title_placeholder: "このディスカッションを簡潔に説明してください。" @@ -541,6 +614,7 @@ ja: view_new_post: "新規ポストを見る。" saving: "保存中..." saved: "保存完了!" + saved_draft: "編集中の投稿があります。選択すると再開します" uploading: "アップロード中..." show_preview: 'プレビューを表示する »' hide_preview: '« プレビューを隠す' @@ -570,8 +644,18 @@ ja: help: "Markdown 編集のヘルプ" toggler: "編集パネルの表示/非表示" admin_options_title: "このトピックの詳細設定" + auto_close: + label: "このトピックを自動的に終了する時間:" + error: "正しい値を入力してください。" + based_on_last_post: "このトピックの最新のポストが古くなるまでは終了しない" + all: + examples: '時間 (例: 24), 時刻(例: 17:30 ), タイムスタンプ(2013-11-22 14:00) を入力してください' + limited: + units: "(# of hours)" + examples: '時間(24)を入力してください' notifications: title: "@ユーザ名 のタグ付けやあなたのポストやトピックへの回答、プライベートメッセージなどの通知" + none: "通知はありません" more: "古い通知を確認する" total_flagged: "フラグがたったポストの総数" mentioned: "@

    {{username}} {{description}}

    " @@ -591,7 +675,10 @@ ja: title_with_attachments: "画像/ファイルをアップロード" from_my_computer: "このデバイスから" from_the_web: "Web から" + remote_tip: "画像へのリンク" + remote_tip_with_attachments: "画像かファイルへのリンク ({{authorized_extensions}})" local_tip: "クリックしてアップロードする画像を選択してください" + local_tip_with_attachments: "ローカルからの画像・ファイルを選択する場合はこちらをクリック ({{authorized_extensions}})" hint: "(アップロードする画像をエディタにドラッグ&ドロップすることもできます)" hint_for_supported_browsers: "(アップロードする画像をエディタにドラッグ&ドロップまたは貼り付けることもできます)" uploading: "アップロード中" @@ -605,6 +692,7 @@ ja: user: "@{{username}}のポストを検索" category: "\"{{category}}\" カテゴリで検索する" topic: "このトピックを探す" + private_messages: "プライベートメッセージ検索" site_map: "別のトピックリストやカテゴリに移動" go_back: '戻る' not_logged_in_user: 'ユーザアクチビティと設定ページ' @@ -624,6 +712,7 @@ ja: close_topics: "トピックを閉じる" archive_topics: "アーカイブトピック" notification_level: "通知レベル変更" + choose_new_category: "このトピックへの新しいカテゴリを選択してください" selected: other: "あなたは {{count}} トピックを選択しました。" none: @@ -633,6 +722,7 @@ ja: posted: "まだトピックを一つも投稿していません。" latest: "最新のトピックはありません。" hot: "ホットなトピックはありません。" + bookmarks: "ブックマークしたトピックがありません" category: "{{category}} トピックはありません。" top: "トップトピック無し" educate: @@ -647,8 +737,10 @@ ja: unread: "未読のトピックは以上です。" category: "{{category}} トピックは以上です。" top: "トップトピックはありません。" + bookmarks: "これ以上ブックマーク済みのトピックはありません" topic: filter_to: "トピック内の{{post_count}}個のポストを表示" + create: 'トピック' create_long: '新しいトピックの作成' private_message: 'プライベートメッセージを作成' list: 'トピック' @@ -691,6 +783,7 @@ ja: jump_reply_down: 以後の回答へジャンプ deleted: "トピックは削除されました" auto_close_notice: "このトピックは%{timeLeft}で自動的に終了します。" + auto_close_notice_based_on_last_post: "このトピックは最後の返信から%{duration} 経つと終了します" auto_close_title: '自動終了設定' auto_close_save: "保存" auto_close_remove: "このトピックを自動終了しない" @@ -714,6 +807,8 @@ ja: '2_4': 'このトピックに回答したため通知されます。' '2_2': 'このトピックをトラック中のため通知されます。' '2': 'このトピックを閲覧したため通知されます。' + '1_2': '他ユーザーからタグ付けをされた場合、またはあなたの投稿に回答が付いた場合に通知されます' + '1': '他ユーザーからタグ付けをされた場合、またはあなたの投稿に回答が付いた場合に通知されます' '0_7': 'このカテゴリに関して一切通知を受けません。' '0_2': 'このトピックに関して一切通知を受けません。' '0': 'このトピックに関して一切通知を受けません。' @@ -725,12 +820,16 @@ ja: description: "このトピックに対して新しい投稿があった場合、登録されたメールアドレスと、NVコミュニティ内の通知ボックスに通知が届き、トピック一覧に新しい投稿数がつきます。" tracking_pm: title: "トラック中" + description: "未読件数と新しい投稿がプライベートメッセージされます。他ユーザーからタグ付けをされた場合、またはあなたの投稿に回答が付いた場合に通知されます" tracking: title: "トラック中" + description: "未読件数と新しい投稿がプライベートメッセージされます。他ユーザーからタグ付けをされた場合、またはあなたの投稿に回答が付いた場合に通知されます" regular: title: "通常" + description: "他ユーザーからタグ付けをされた場合、またはあなたの投稿に回答が付いた場合に通知されます" regular_pm: title: "通常" + description: "他ユーザーからタグ付けをされた場合、またはあなたのメッセージに回答が付いた場合に通知されます" muted_pm: title: "ミュートされました" description: "このプライベートメッセージについての通知を受け取りません。" @@ -743,10 +842,12 @@ ja: open: "トピックを開く" close: "トピックを終了する" auto_close: "自動終了" + feature: "特集トピック" + remove_feature: "特集を解除" make_banner: "バナートピック" remove_banner: "バナートピックを削除" - unpin: "トピックのピン留め解除" pin: "トピックのピン留め" + unpin: "トピックのピン留め解除" pin_globally: "トピックを全サイト的にピン留めする" unarchive: "トピックのアーカイブ解除" archive: "トピックのアーカイブ" @@ -767,6 +868,30 @@ ja: title: 'フラグ' help: '注目したいトピックにフラグを立てることで、それについての通知をプライベートに受け取ることが出来ます' success_message: 'このトピックをフラグしました。' + feature_topic: + title: "トピックを特集" + pin: "このトピックを{{categoryLink}}カテゴリのトップに表示する" + confirm_pin: " 続けますか? 既に{{count}} 個ピン留めしています。 多すぎるピン留めはアクティブなトピックが分かりにくくなります" + unpin: " {{categoryLink}} カテゴリからトピックを削除" + pin_note: "ユーザーはトピックを個別にピン留め解除することができます" + already_pinned: + zero: "{{categoryLink}}のトピックはピン留めされていません" + one: " {{categoryLink}}内のトピックは現在1個ピン留めされています" + other: "{{categoryLink}}内のトピックは現在{{count}}個ピン留めされています" + pin_globally: "スタッフメンバーがこのトピックをピン留め解除しない限り、トピック一覧のトップに表示する" + confirm_pin_globally: "続けますか? 既に{{count}} 個ピン留めしています。 多すぎるピン留めはアクティブなトピックが分かりにくくなります" + unpin_globally: "トピック一覧のトップからこのトピックを削除します" + global_pin_note: "ユーザーはトピックを個別にピン留め解除することができます" + already_pinned_globally: + zero: "現在ピン留めされていません" + one: "現在1個ピン留めされています" + other: "現在{{count}}個ピン留めされています" + make_banner: "このトピックを全てのページのバナーに表示します" + remove_banner: "全てのページのバナーを削除します" + banner_note: "ユーザーはバナーを閉じることができます。常に1つのトピックだけがバナー表示されます" + already_banner: + zero: "バナートピックはありません" + one: "現在のバナートピックです" inviting: "招待中..." automatically_add_to_groups_optional: "この招待によって、リストされたグループに参加することができます。" automatically_add_to_groups_required: "この招待によって、リストされたグループに参加することができます。" @@ -786,10 +911,12 @@ ja: to_forum: "ログインしなくてもこの投稿に返信ができることを、あなたの友人に知らせます。" email_placeholder: 'メールアドレス' success: "{{email}}に招待を送りました。" + error: "申し訳ありません、そのユーザは招待することができませんでした。既にアカウント登録されていませんか?(招待は制限されています)" login_reply: 'ログインして返信' filters: n_posts: other: "{{count}} ポスト" + cancel: "フィルター削除" split_topic: title: "新規トピックに移動" action: "新規トピックに移動" @@ -811,6 +938,7 @@ ja: placeholder: "新しい所有者のユーザ名" instructions: other: "この {{count}} つポストの新しい所有者を選択してください。(元所有者:{{old_user}})" + instructions_warn: "このポストについての通知が新しいユーザーにさかのぼって転送されることはないので注意してください。
    警告: 投稿の関連データの所有権は、新しいユーザに転送されません。 注意して使用してください" multi_select: select: '選択' selected: '選択中 ({{count}})' @@ -851,6 +979,7 @@ ja: attachment_too_large: "申し訳ありませんが、アップロード対象ファイルが大きすぎます (最大サイズは {{max_size_kb}}kb)。" file_too_large: "申し訳ありませんが、アップロード対象ファイルが大きすぎます (最大サイズは {{max_size_kb}}kb)" too_many_uploads: "申し訳ありませんが、複数のファイルは同時にアップロードできません。" + too_many_dragged_and_dropped_files: "申し訳ありません。一度にドラッグ&ドロップできるのは10ファイルまでです" upload_not_authorized: "申し訳ありませんが、対象ファイルをアップロードする権限がありません (利用可能な拡張子: {{authorized_extensions}})." image_upload_not_allowed_for_new_user: "申し訳ありませんが、新規ユーザは画像のアップロードができません。" attachment_upload_not_allowed_for_new_user: "申し訳ありませんが、新規ユーザはファイルの添付ができません。" @@ -890,6 +1019,8 @@ ja: unhide: "表示する" actions: flag: 'フラグ' + defer_flags: + other: "デファーフラグ" it_too: off_topic: "フラグをたてる" spam: "フラグをたてる" @@ -908,6 +1039,7 @@ ja: people: off_topic: "{{icons}} オフトピックとしてマーク" spam: "{{icons}} スパムとしてマーク" + spam_with_url: "{{icons}} スパムとしてフラグ付き" inappropriate: "{{icons}} 不適切であると報告するフラグを立つ" notify_moderators: "{{icons}} がモデレータに通報しました" notify_moderators_with_url: "{{icons}} 通知されたモデレータ" @@ -972,6 +1104,8 @@ ja: previous: "一つ前のリビジョン" next: "次のリビジョン" last: "最後のリビジョン" + hide: "リビジョンを隠す" + show: "リビジョンを表示" comparing_previous_to_current_out_of_total: "{{previous}} vs {{current}} ({{total}}のうち)" displays: inline: @@ -995,7 +1129,10 @@ ja: general: '一般' settings: '設定' delete: 'カテゴリを削除する' + create: '新しいカテゴリ' save: 'カテゴリを保存する' + slug: 'カテゴリスラグ' + slug_placeholder: '(任意)URL用' creation_error: カテゴリの作成に失敗しました。 save_error: カテゴリの保存に失敗しました。 name: "カテゴリ名" @@ -1020,11 +1157,16 @@ ja: auto_close_units: "時間" email_in: "カスタムメールアドレス" email_in_allow_strangers: "登録されていないユーザーからメールを受けとります。" + email_in_disabled: "メールでの新規投稿は、サイトの設定で無効になっています。メールでの新規投稿を有効にするには" + email_in_disabled_click: '"email in"設定を有効にしてください' + allow_badges_label: "このカテゴリでバッジが付与されることを許可" edit_permissions: "パーミッションを編集" add_permission: "パーミッションを追加" this_year: "今年" position: "ポジション" default_position: "デフォルトポジション" + position_disabled: "カテゴリはアクティビティで並び替えられます。カテゴリ一覧の順番を制御するには" + position_disabled_click: '"fixed category positions"設定を有効にしてください' parent: "親カテゴリ" notifications: watching: @@ -1035,23 +1177,36 @@ ja: description: "このカテゴリに対して新しい投稿があった場合、トピック一覧に新しい投稿数がつきます。" regular: title: "通常" + description: "他ユーザーからタグ付けをされた場合、またはあなたのポストに回答が付いた場合に通知されます" muted: title: "ミュート中" description: "このカテゴリに投稿されたトピックについての通知を受け取りません。また、未読タブにも通知されません。" flagging: + title: '私達のコミュニティの維持を助けてくれてありがとうごうざいます' + private_reminder: 'フラッグはプライベートです。スタッフのみが参照できます' action: 'フラグをつける' take_action: "アクションをする" notify_action: '通知する' delete_spammer: "スパマーの削除" delete_confirm: "このユーザによる%{posts}個のポストと%{topics}個のトピックを削除し、アカウントを削除し、このユーザのメールアドレス %{email} をブロックリストに追加しようとしています。本当にこのユーザをスマパー認定してもよいですか?" yes_delete_spammer: "はい、スパマーを削除する" + ip_address_missing: "(N/A)" + hidden_email_address: "(hidden)" submit_tooltip: "プライベートフラッグを通知する" + take_action_tooltip: "コミュニティのフラッグを待つのではなく、すぐにフラッグを始めましょう" cant: "申し訳ありませんが、現在このポストにフラグを立てることはできません。" + formatted_name: + off_topic: "オフトピック" + inappropriate: "不適切" + spam: "スパム" + custom_placeholder_notify_user: "具体的に、建設的に、そして常に親切にしましょう" + custom_placeholder_notify_moderators: "特に何を懸念しているかを伝えてください。可能な場合、関連するリンクや例を提供してください" custom_message: at_least: "少なくとも{{n}}文字入力してください" more: "あと{{n}}文字..." left: "残り{{n}}文字" flagging_topic: + title: "私達のコミュニティの維持を助けてくれてありがとうごうざいます" action: "トピックにフラグを立てる" notify_action: "プライベートメッセージ" topic_map: @@ -1060,20 +1215,34 @@ ja: clicks: other: "%{count} クリック" topic_statuses: + warning: + help: "これは公式の警告です" + bookmarked: + help: "このトピックをブックマークしました" locked: help: "このトピックは終了しています。新たに回答を投稿することはできません\"" unpinned: title: "ピン留め解除しました" + help: "このトピックはピン留めされていません。 既定の順番に表示されます。" pinned_globally: title: "全サイト的にピン留めされました" help: "このトピックは全サイト的にピン留めされました;全てのリストのトップに表示されます。" pinned: title: "ピン留め" + help: "このトピックはピン留めされています。常にカテゴリのトップに表示されます" archived: help: "このトピックはアーカイブされています。凍結状態のため一切の変更ができません" + invisible: + help: "このトピックはリストされていません。トピックリストには表示されません。直接リンクでのみアクセス可能です" posts: "投稿" posts_lowercase: "投稿" posts_long: "このトピックには{{number}}個のポストがあります" + posts_likes_MF: | + This topic has {count, plural, one {1 reply} other {# replies}} {ratio, select, + low {with a high like to post ratio} + med {with a very high like to post ratio} + high {with an extremely high like to post ratio} + other {}} original_post: "大元のポスト" views: "閲覧" views_lowercase: "閲覧" @@ -1088,6 +1257,9 @@ ja: category_title: "カテゴリ" history: "History" changed_by: "by {{author}}" + raw_email: + title: "メール" + not_available: "利用不可" categories_list: "カテゴリ一覧" filters: with_topics: "%{filter} トピック" @@ -1127,6 +1299,9 @@ ja: posted: title: "あなたのポスト" help: "あなたが投稿したトピック" + bookmarks: + title: "ブックマーク" + help: "ブックマークしたトピック" category: title: zero: "{{categoryName}}" @@ -1144,6 +1319,7 @@ ja: title: "週間トップ" daily: title: "日間トップ" + all: "全て" this_year: "今年" this_month: "今月" this_week: "今週" @@ -1182,6 +1358,14 @@ ja: suspended: '停止中:' private_messages_short: "PMs" private_messages_title: "プライベートメッセージ" + space_free: "{{size}} free" + uploads: "アップロード" + backups: "バックアップ" + traffic_short: "トラフィック" + traffic: "Application web requests" + page_views: "API Requests" + page_views_short: "API Requests" + show_traffic_report: "Show Detailed Traffic Report" reports: today: "今日" yesterday: "昨日" @@ -1191,6 +1375,11 @@ ja: 7_days_ago: "7日前" 30_days_ago: "30日前" all: "全て" + view_table: "table" + view_chart: "bar chart" + refresh_report: "Refresh Report" + start_date: "Start Date" + end_date: "End Date" commits: latest_changes: "最新の更新内容:" by: "by" @@ -1199,28 +1388,47 @@ ja: old: "古いフラグ" active: "アクティブなフラグ" agree: "賛成" + agree_title: "有効かつ正しいとしてフラッグを確認" + agree_flag_modal_title: "Agree and..." + agree_flag_hide_post: "賛成(ポスト非表示 + プライベートメッセージ送信)" + agree_flag_hide_post_title: "このポストを非表示にし、編集を促すプライベートメッセージをユーザに自動的に送信する" + agree_flag_restore_post: "賛成(投稿を復元)" + agree_flag_restore_post_title: "この投稿を復元" agree_flag: "フラッグに賛成する" + agree_flag_title: "フラグとポストを変更しないことに賛成" defer_flag: "Defer" + defer_flag_title: "フラグを削除します。何のアクションも必要としません" delete: "削除する" + delete_title: "このフラグが参照しているポストを削除" + delete_post_defer_flag: "投稿を削除し、フラグを外す" delete_post_defer_flag_title: "投稿を削除する。もしこの最初の投稿を削除すると、トピックも削除されます。" + delete_post_agree_flag: "投稿を削除し、フラグに賛成" delete_post_agree_flag_title: "投稿を削除する。もしこの最初の投稿を削除すると、トピックも削除されます。" + delete_flag_modal_title: "Delete and..." delete_spammer: "スパムユーザーを削除" + delete_spammer_title: "ユーザとそのユーザが投稿した全てのポストとトピックを削除します" disagree_flag_unhide_post: "反対する(投稿を表示する)" disagree_flag_unhide_post_title: "投稿に付けたフラッグを削除する。ポストを表示する" disagree_flag: "反対する" + disagree_flag_title: "無効または、不正としてこのフラグを拒否" clear_topic_flags: "トピックのフラグをクリアしました" clear_topic_flags_title: "このトピックについての問題が解決されました。「完了」をクリックしてフラグを外します。" + more: "(more replies...)" dispositions: agreed: "賛成した。" disagreed: "反対する" + deferred: "deferred" flagged_by: "フラグを立てた人" resolved_by: "解決方法" + took_action: "Took action" system: "システム" error: "何らかの理由でうまくいきませんでした" reply_message: "返信する" no_results: "フラグはありません。" topic_flagged: "この トピック はフラグされました。" visit_topic: "トピックを閲覧して問題を調査してくさだい" + was_edited: "最初のフラグ後に編集されたポスト" + previous_flags_count: "このポストは既に {{count}} 回フラグされています" summary: action_type_3: other: "オフトピック x{{count}}" @@ -1239,12 +1447,25 @@ ja: edit: "グループの編集" refresh: "リフレッシュ" new: "新規" + selector_placeholder: "ユーザ名を入力" name_placeholder: "グループ名を入力 (ユーザ名同様にスペースなし)" about: "グループメンバーとグループ名を編集" group_members: "グループメンバー" delete: "削除" delete_confirm: "このグループを削除しますか?" delete_failed: "グループの削除に失敗しました。自動作成グループを削除することはできません。" + delete_member_confirm: "'%{group}' グループから'%{username}' を削除しますか?" + name: "名前" + add: "追加" + add_members: "メンバー追加" + custom: + label: "カスタム" + title: "カスタムグループ" + automatic: + label: "Automatic" + title: "自動作成グループ" + automatic_membership_email_domains: "リスト内のメールアドレスのドメインに正確に一致したユーザーは自動的にグループに追加される" + automatic_membership_retroactive: "同じメールアドレスドメインのルールを既に登録済みのユーザにも適用" api: generate_master: "マスターAPIキーを生成" none: "現在アクティブなAPIキーが存在しません。" @@ -1258,6 +1479,15 @@ ja: confirm_revoke: "このキーを無効化しても本当によろしいですか?" info_html: "API キーを使うと、JSON 呼び出しでトピックの作成・更新を行うことが出来ます。" all_users: "全てのユーザ" + note_html: "このキーは、秘密にしてください。このキーを持っている全てのユーザーは任意のユーザとして、任意のポストを作成できます" + plugins: + title: "プラグイン" + installed: "インストール済みプラグイン" + name: "名前" + none_installed: "インストール済みのプラグインはありません" + version: "バージョン" + change_settings: "設定変更" + howto: "プラグインをインストールするには?" backups: title: "バックアップ" menu: @@ -1292,6 +1522,8 @@ ja: backup: text: "バックアップ" title: "バックアップを作成します" + confirm: "新しいバックアップを作成したいですか?" + without_uploads: "はい(ファイルは含まない)" download: text: "ダウンロード" title: "バックアップをダウンロード" @@ -1309,11 +1541,33 @@ ja: title: "データベースを元の作業状態にロールバックする" confirm: "本当にデータベースを元の作業状態にロールバックしますか?" export_csv: + user_archive_confirm: "あなたのポストをダウンロードしてよいですか?" + success: "エクスポートは開始されました。処理が完了すると、プライベートメッセージで通知されます" failed: "出力失敗。詳しくはログに参考してください。" + rate_limit_error: "ポストは1日1回ダウンロードできます。明日試してください" + button_text: "エクスポート" + button_title: + user: "全てのユーザーをCSV出力" + staff_action: "スタッフの操作ログをCSV出力" + screened_email: "全てのスクリーンメールアドレスをCSV出力" + screened_ip: "全てのスクリーンIPリストをCSV出力" + screened_url: "全てのスクリーンURLリストをCSV出力" + invite: + button_text: "招待を送信" + button_title: "招待を送信" customize: title: "カスタマイズ" long_title: "サイトのカスタマイズ" + css: "CSS" header: "ヘッダ" + top: "トップ" + footer: "フッター" + head_tag: + text: "" + title: "タグの前に挿入されるHTML" + body_tag: + text: "" + title: "タグの前に挿入されるHTML" override_default: "標準のスタイルシートを読み込まない" enabled: "有効にする" preview: "プレビュー" @@ -1337,10 +1591,12 @@ ja: colors: title: "色" long_title: "色スキーマ" + about: "CSSを記述することなくサイトのカラーを変更できます。スキームを追加して始めてください" new_name: "新しい色スキーム" copy_name_prefix: "のコピー" delete_confirm: "このカラースキームを削除しますか?" undo: "取り消す" + undo_title: "変更を元に戻して、前回保存されたカラーにします" revert: "取り戻す" revert_title: "既定の配色に戻る" primary: @@ -1349,22 +1605,39 @@ ja: secondary: name: 'セカンダリー' description: 'メイン背景とボタンのテキスト色' + tertiary: + name: 'ターシャリ' + description: 'リンク、いくつかのボタン、通知、アクセントカラー' quaternary: + name: "クォータナリ" description: "ナビゲーションリンク" header_background: name: "ヘッダー背景" description: "ヘッダー背景色" + header_primary: + name: "ヘッダープライマリー" + description: "サイトヘッダーのテキストとアイコン" + highlight: + name: 'ハイライト' + description: 'ポストやトピックといった、ページのハイライトされた要素の背景色' danger: name: '危険' + description: 'ポストやトピックの削除などのアクションのハイライトカラー' success: name: '成功' + description: '操作が成功したことを示すために使用します' love: + name: 'love' description: "ライクボタンの色" + wiki: + name: 'wiki' + description: "Wiki投稿の背景に使用する基本色" email: title: "メール" settings: "設定" all: "全て" sending_test: "テストメールを送信中..." + error: "ERROR - %{server_error}" test_error: "テストメールを送れませんでした。メール設定、またはホストをメールコネクションをブロックされていないようを確認してください。" sent: "送信済み" skipped: "スキップ済み" @@ -1378,6 +1651,7 @@ ja: sent_test: "送信完了!" delivery_method: "送信方法" preview_digest: "ダイジェストのプレビュー" + preview_digest_desc: "非アクティブユーザに送る週刊ダイジェストメールのコンテンツをプレビューします" refresh: "更新" format: "フォーマット" html: "html" @@ -1392,6 +1666,7 @@ ja: user_placeholder: "ユーザ名" address_placeholder: "name@example.com" type_placeholder: "ダイジェスト、サインアップ..." + reply_key_placeholder: "回答キー" skipped_reason_placeholder: "理由" logs: title: "ログ" @@ -1400,6 +1675,8 @@ ja: last_match_at: "最終マッチ" match_count: "マッチ" ip_address: "IP" + topic_id: "トピックID" + post_id: "ポストID" delete: '削除' edit: '編集' save: '保存' @@ -1408,6 +1685,7 @@ ja: do_nothing: "何もしない" staff_actions: title: "スタッフ操作" + instructions: "ユーザー名、アクションをクリックすると、リストふぁフィルタされます。プロフィール画像をクリックするとユーザページに遷移します" clear_filters: "全てを表示する" staff_user: "スタッフユーザ" target_user: "対象ユーザ" @@ -1425,6 +1703,7 @@ ja: actions: delete_user: "ユーザを削除" change_trust_level: "トラストレベルを変更" + change_username: "ユーザー名変更" change_site_setting: "サイトの設定を変更" change_site_customization: "サイトのカスタマイズ設定を変更" delete_site_customization: "サイトのカスタマイズ設定を削除" @@ -1433,6 +1712,10 @@ ja: grant_badge: "バッジを付ける" revoke_badge: "バッジを取り消す" check_email: "メールアドレスを表示する" + delete_topic: "トピック削除" + delete_post: "ポスト削除" + impersonate: "なりすまし" + anonymize_user: "匿名ユーザー" screened_emails: title: "ブロック対象アドレス" description: "新規アカウント作成時、次のメールアドレスからの登録をブロックする。" @@ -1448,13 +1731,21 @@ ja: title: "スクリーン対象IP" description: '参加中のIPアドレス。IPアドレスをホワイトリストに追加するには "許可" を利用してください。' 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." actions: block: "ブロック" do_nothing: "許可" + allow_admin: "Allow Admin" form: label: "新規:" ip_address: "IPアドレス" add: "追加" + filter: "Search" + roll_up: + text: "Roll up" + title: "Creates new subnet ban entries if there are at least 'min_ban_entries_for_roll_up' entries." logster: title: "エラーログ" impersonate: @@ -1465,13 +1756,17 @@ ja: create: '管理者を追加' last_emailed: "最終メール" not_found: "このユーザネームはシステムに存在しません。" + id_not_found: "申し訳ありません。そのユーザーIDはシステムに存在していません" active: "アクティブ" + show_emails: "メールアドレス参照" nav: new: "新規" active: "アクティブ" pending: "保留中" + staff: 'スタッフ' suspended: 'サスペンド中' blocked: 'ブロック中' + suspect: 'サスペクト' approved: "承認?" approved_selected: other: "承認ユーザ ({{count}})" @@ -1483,10 +1778,15 @@ ja: pending: '保留中のユーザ' newuser: 'トラストレベル0のユーザ (新規ユーザ)' basic: 'トラストレベル1のユーザ (ベーシックユーザ)' + regular: 'トラストレベル 2(メンバー)のユーザ' + leader: 'トラストレベル3(レギュラー)のユーザ' + elder: 'トラストレベル4(リーダー)のユーザ' + staff: "スタッフ" admins: '管理者ユーザ' moderators: 'モデレータ' blocked: 'ブロック中のユーザ' suspended: 'サスペンド中のユーザ' + suspect: 'サスペクトユーザ' reject_successful: other: "%{count}人のユーザの拒否に成功しました。" reject_failures: @@ -1515,6 +1815,7 @@ ja: edit_title: "タイトルを編集" save_title: "タイトルを保存" refresh_browsers: "ブラウザを強制リフレッシュ" + refresh_browsers_message: "全てのクライアントにメッセージが送信されました!" show_public_profile: "一般プロファイルを表示" impersonate: 'このユーザになりすます' ip_lookup: "IP検索" @@ -1530,19 +1831,27 @@ ja: permissions: パーミッション activity: アクティビティ like_count: 「いいね!」付けた/もらった数 + last_100_days: '過去100日に' private_topics_count: プライベートトピック数 posts_read_count: 読んだポスト数 post_count: 投稿したポスト数 topics_entered: 閲覧したトピック数 flags_given_count: 設定したフラグ数 flags_received_count: 設定されたフラグ数 + warnings_received_count: 警告をもらった + flags_given_received_count: 'フラグを与えた/もらった' approve: '承認' approved_by: "承認したユーザ" approve_success: "ユーザが承認され、アクティベーション方法を記載したメールが送信されました。" approve_bulk_success: "成功!!選択したユーザ全員が承認され、メールが送信されました。" time_read: "リード時間" + anonymize: "匿名ユーザ" + anonymize_confirm: "このアカウントと匿名化してよいですか?ユーザ名、メールアドレスが変更され、全てのプロフィール情報がリセットされます" + anonymize_yes: "はい。アカウントを匿名化してください" + anonymize_failed: "アカウントの匿名化中に問題が発生しました" delete: "ユーザを削除" delete_forbidden_because_staff: "アドミンおよびモデレータアカウントは削除できません。" + delete_posts_forbidden_because_staff: "管理者、モデレーターの全てのポストは削除できません" delete_forbidden: other: "ポスト投稿済のユーザは削除できません。ユーザ削除の前に全てのポストを削除してください。(投稿後%{count}日以上が経過したポストは削除できません )" cant_delete_all_posts: @@ -1567,9 +1876,15 @@ ja: suspended_explanation: "サスペンド中のユーザはログインできません。" block_explanation: "ブロック中のユーザはポストの投稿およびトピックの作成ができません。" trust_level_change_failed: "ユーザのトラストレベル変更に失敗しました。" + grant_admin_failed: "管理者特権の付与中に問題が発生しました" + grant_moderation_failed: "モデレーター特権の付与中に問題が発生しました" suspend_modal_title: "サスペンド中ユーザ" trust_level_2_users: "トラストレベル2のユーザ" trust_level_3_requirements: "トラストレベル3の条件" + trust_level_locked_tip: "トラストレベルはロックされています。システムがユーザーを昇格、降格させることはありません" + trust_level_unlocked_tip: "トラストレベルはアンロックされています。システムはユーザーを昇格、降格させます" + lock_trust_level: "トラストレベルをロック" + unlock_trust_level: "トラストレベルをアンロック" tl3_requirements: title: "トラストレベル3の条件" table_title: "過去100日に:" @@ -1586,12 +1901,53 @@ ja: flagged_by_users: "フラグを立ったユーザ" likes_given: "与えた「いいね!」" likes_received: "もらった「いいね!」" + likes_received_days: "「いいね!」数:日別" + likes_received_users: "「いいね!」数: ユーザー別" qualifies: "トラストレベル3の条件を満たしています。" does_not_qualify: "トラストレベル3の条件を満たしていません。" + will_be_promoted: "もうすぐ昇格します" + will_be_demoted: "もうすぐ降格します" + on_grace_period: "現在の昇格期間中は、降格されません" + locked_will_not_be_promoted: "トラストレベルはロックされています。昇格することはありません" + locked_will_not_be_demoted: "トラストレベルはロックされています。降格することはありません" sso: + title: "シングルサインオン" + external_id: "External ID" external_username: "ユーザ名" external_name: "名前" external_email: "メール" + external_avatar_url: "プロフィール画像URL" + user_fields: + title: "ユーザーフィールド" + help: "ユーザーが記入するフィールドを追加します" + create: "ユーザーフィールド作成" + untitled: "無題" + name: "フィールド名" + type: "フィールドタイプ" + description: "フィールド説明" + save: "保存" + edit: "編集" + delete: "削除" + cancel: "キャンセル" + delete_confirm: "ユーザーフィールドを削除してもよいですか?" + required: + title: "サインアップ時に必須?" + enabled: "必須" + disabled: "任意" + editable: + title: "サインアップ後に編集可能?" + enabled: "編集可能" + disabled: "編集不可" + show_on_profile: + title: "パブリックプロフィールに表示?" + enabled: "プロフィールに表示" + disabled: "プロフィール非表示" + field_types: + text: 'テキストフィールド' + confirm: '確認' + site_text: + none: "コンテンツの種類を選択してください" + title: 'テキストコンテンツ' site_settings: show_overriden: '上書き部分のみ表示' title: '設定' @@ -1599,6 +1955,7 @@ ja: none: 'なし' no_results: "何も見つかりませんでした。" clear_filter: "クリア" + add_url: "URL追加" categories: all_results: '全て' required: '必須設定' @@ -1619,6 +1976,7 @@ ja: uncategorized: 'その他' backups: "バックアップ" login: "ログインする" + plugins: "プラグイン" badges: title: バッジ new_badge: 新しいバッジ @@ -1629,11 +1987,17 @@ ja: description: バッジの説明 badge_type: バッジの種類 badge_grouping: グループ + badge_groupings: + modal_title: バッジグルーピング granted_by: バッジ付与者 + granted_at: バッジ付与日 + reason_help: (ポストかトピックへのリンク) save: バッジを保存する delete: バッジを削除する delete_confirm: 本当にこのバッジを削除しますか? revoke: 取り消す + reason: 理由 + expand: '&hellipを展開' revoke_confirm: このバッジを取り消しますか? edit_badges: バッジを編集する grant_badge: バッジを付ける @@ -1641,18 +2005,55 @@ ja: grant: 付ける no_user_badges: "%{name} はバッジを付けられていません。" no_badges: 付けられるバッジがありません + none_selected: "バッジを選択して開始" allow_title: バッジは、タイトルとして使用されることを許可する multiple_grant: 複数回付与することができます + listable: パブリックパッジページに表示するバッジ enabled: バッジシステムを使う icon: アイコン + image: 画像 + icon_help: "Font Awesomeのクラスか画像のURLを使用してください" + query: バッジクエリ(SQL) + target_posts: クエリ対象ポスト + auto_revoke: 毎日失効クエリを実行 + show_posts: バッジページの付与したバッジでポストを表示 + trigger: トリガー trigger_type: none: "毎日更新する" + post_action: "ユーザがポストに影響を与えたとき" + post_revision: "ユーザーがポストを作成、編集したとき" + trust_level_change: "ユーザのトラストレベルが変わったとき" + user_change: "ユーザを作成、編集したとき" preview: + link_text: "付与するバッジをプレビュー" + plan_text: "クエリ計画をプレビュー" + modal_title: "バッジクエリをプレビュー" + sql_error_header: "クエリにエラーがあります" + error_help: "バッジクエリのヘルプについては、以下のリンクを参照してください" + bad_count_warning: + header: "WARNING!" + text: "There are missing grant samples. This happens when the badge query returns user IDs or post IDs that do not exist. This may cause unexpected results later on - please double-check your query." + grant_count: + zero: "付与されたバッジはありません" + one: "1 個のバッジが付与されています" + other: "%{count} 個のバッジが付与されています" sample: "サンプル:" grant: with: %{username} + with_post: %{username} for post in %{link} + with_post_time: %{username} for post in %{link} at %{time} + with_time: %{username} at %{time} + emoji: + title: "Emoji" + help: "Add new emoji that will be available to everyone. (PROTIP: drag & drop multiple files at once)" + add: "Add New Emoji" + name: "名前" + image: "画像" + delete_confirm: "Are you sure you want to delete the :%{name}: emoji?" lightbox: download: "ダウンロード" + search_help: + title: 'Search Help' keyboard_shortcuts_help: title: 'キーボードショートカット' jump_to: @@ -1669,6 +2070,7 @@ ja: back: 'u 戻る' up_down: 'k/j トピック・投稿 ↑ ↓移動' open: 'o or Enter トピックへ' + next_prev: 'shift+j/shift+k 次のセクション/前のセクション' application: title: 'アプリケーション' create: 'c 新しいトピックを作成' @@ -1682,7 +2084,12 @@ ja: dismiss_topics: 'Dismiss Topics' actions: title: '操作' + bookmark_topic: 'f トピックのブックマークをトグル' + pin_unpin_topic: 'shift+pトピックを ピン留め/ピン留め解除' + share_topic: 'shift+s トピックをシェア' share_post: 's 投稿をシェアする' + reply_as_new_topic: 't リンクトピックとして引用返信' + reply_topic: 'shift+r トピックに返信' reply_post: 'r 投稿に返信' quote_post: 'q 投稿を引用する' like: 'l 投稿を「いいね!」する' @@ -1696,6 +2103,8 @@ ja: mark_watching: 'm, w トピックを参加中にする' badges: title: バッジ + allow_title: "タイトルとして使用できる" + multiple_grant: "複数回受け取ることができる" badge_count: other: "%{count} バッジ" more_badges: @@ -1703,7 +2112,10 @@ ja: granted: other: "%{count} つバッジを付与されました" select_badge_for_title: タイトルとして使用するバッジを選択 + none: "" badge_grouping: + getting_started: + name: Getting Started community: name: コミュニティ trust_level: @@ -1715,17 +2127,28 @@ ja: badge: editor: name: 編集者 + description: 最初のポスト編集 basic_user: name: ベーシックユーザ + description: Granted all essential community functions member: name: メンバー + description: Granted invitations regular: name: レギュラー + description: Granted recategorize, rename, followed links and lounge leader: name: リーダー + description: Granted global edit, pin, close, archive, split and merge welcome: name: ようこそ description: 「いいね!」を受けました + autobiographer: + name: Autobiographer + description: Filled user profile information + anniversary: + name: アニバーサリー + description: 今年一度でも投稿したアクティブメンバー nice_post: name: 良いポスト description: 10人に「いいね!」をされました。このバッジは何度でももらえます。 @@ -1737,16 +2160,22 @@ ja: description: 50人に「いいね!」をされました。このバッジは何度でももらえます。 nice_topic: name: ナイストピック + description: トピックが10回「いいね!」されました。このバッジは何度でももらえます good_topic: name: グッドトピック + description: トピックが25回「いいね!」されました。このバッジは何度でももらえます great_topic: name: グレートトピック + description: トピックが50回「いいね!」されました。このバッジは何度でももらえます nice_share: name: ナイスシェア + description: 25人の訪問者にポストがシェアされました good_share: name: グッドシェア + description: 300人の訪問者にポストがシェアされました great_share: name: グレートシェア + description: 1000人の訪問者にポストがシェアされました first_like: name: 初めての「いいね!」 description: 投稿に「いいね!」した @@ -1768,3 +2197,12 @@ ja: reader: name: 閲覧者 description: 100以上の投稿があるトピック内の投稿をすべて読みました。 + google_search: | +

    Googleで探す

    +

    +

    +

    diff --git a/config/locales/client.ko.yml b/config/locales/client.ko.yml index 8bee44e384..2b02928c84 100644 --- a/config/locales/client.ko.yml +++ b/config/locales/client.ko.yml @@ -563,7 +563,6 @@ ko: emoji: "Emoji :smile:" add_warning: "공식적인 경고입니다." posting_not_on_topic: "어떤 토픽에 답글을 작성하시겠습니까?" - saving_draft_tip: "저장 중..." saved_draft_tip: "저장 완료" saved_local_draft_tip: "로컬로 저장됩니다." similar_topics: "작성하려는 내용과 비슷한 토픽들..." @@ -820,8 +819,8 @@ ko: auto_close: "자동으로 닫기" make_banner: "배너 토픽" remove_banner: "배너 토픽 제거" - unpin: "토픽 고정 취소" pin: "토픽 고정" + unpin: "토픽 고정 취소" pin_globally: "전체 공지글로 설정하기" unarchive: "보관 안된 토픽" archive: "보관된 토픽" @@ -1398,8 +1397,6 @@ ko: name: "이름" add: "추가" add_members: "사용자 추가하기" - custom: "커스텀" - automatic: "오토메틱" automatic_membership_email_domains: "이 목록의 있는 항목과 사용자들이 등록한 이메일 도메인이 일치할때 이 그룹에 포함" automatic_membership_retroactive: "이미 등록된 사용자에게 같은 이메일 도메인 규칙 적용하기" api: diff --git a/config/locales/client.nb_NO.yml b/config/locales/client.nb_NO.yml index f65b5586e3..5cde6dda5f 100644 --- a/config/locales/client.nb_NO.yml +++ b/config/locales/client.nb_NO.yml @@ -595,7 +595,6 @@ nb_NO: emoji: "Emoji :smile:" add_warning: "Dette er en offisiell advarsel." posting_not_on_topic: "Du svarer på emnet \"{{title}}\", men for øyeblikket ser du på et annet emne." - saving_draft_tip: "lagrer" saved_draft_tip: "lagret" saved_local_draft_tip: "lagret lokalt" similar_topics: "Emnet ditt har likheter med..." @@ -859,8 +858,8 @@ nb_NO: auto_close: "Auto-Lukk" make_banner: "Banneremne" remove_banner: "Fjern banneremne" - unpin: "Løsgjør emne" pin: "Fastsett emne" + unpin: "Løsgjør emne" pin_globally: "Fastsett emne globalt" unarchive: "Uarkiver Emne" archive: "Arkiver Emne" @@ -1471,8 +1470,6 @@ nb_NO: name: "Navn" add: "Legg til" add_members: "Legg til medlemmer" - custom: "Tilpasset" - automatic: "Automatisk" api: generate_master: "Generer Master API-nøkkel" none: "Det er ingen aktive API-nøkler akkurat nå." diff --git a/config/locales/client.nl.yml b/config/locales/client.nl.yml index 06dcb41f7f..50f76840c5 100644 --- a/config/locales/client.nl.yml +++ b/config/locales/client.nl.yml @@ -145,9 +145,9 @@ nl: post_count: "Berichten" user_count: "Nieuwe leden" active_user_count: "Actieve leden" - contact: "Neem contact op" + contact: "Neem contact met ons op" bookmarked: - title: "Bewaar" + title: "Voeg toe aan favorieten" bookmarks: not_logged_in: "sorry, je moet ingelogd zijn om berichten aan je favorieten toe te kunnen voegen" created: "je hebt dit bericht aan je favorieten toegevoegd" @@ -578,7 +578,6 @@ nl: composer: add_warning: "Dit is een officiële waarschuwing." posting_not_on_topic: "In welke topic wil je je antwoord plaatsen?" - saving_draft_tip: "wordt opgeslagen" saved_draft_tip: "opgeslagen" saved_local_draft_tip: "lokaal opgeslagen" similar_topics: "Jouw topic lijkt op..." @@ -825,8 +824,8 @@ nl: auto_close: "Automatisch sluiten" make_banner: "Zet topic in als banner" remove_banner: "Verwijder bannertopic" - unpin: "Ontpin topic" pin: "Pin topic vast" + unpin: "Ontpin topic" pin_globally: "Pin topic globaal vast" unarchive: "De-archiveer topic" archive: "Archiveer topic" @@ -1402,8 +1401,6 @@ nl: name: "Naam" add: "Voeg toe" add_members: "Voeg leden toe" - custom: "Aangepast" - automatic: "Automatisch" api: generate_master: "Genereer Master API Key" none: "Er zijn geen actieve API keys" diff --git a/config/locales/client.pl_PL.yml b/config/locales/client.pl_PL.yml index 92b9ad2968..45b166e18b 100644 --- a/config/locales/client.pl_PL.yml +++ b/config/locales/client.pl_PL.yml @@ -178,6 +178,7 @@ pl_PL: not_bookmarked: "wpis przeczytany: kliknij, aby dodać zakładkę" last_read: "to ostatni przeczytany przez ciebie wpis: kliknij, aby dodać zakładkę" remove: "Usuń zakładkę" + confirm_clear: "Czy na pewno chcesz usunąć wszystkie zakładki ustawione w tym temacie?" topic_count_latest: one: "{{count}} nowy lub zaktualizowany temat" few: "{{count}} nowe lub zaktualizowane tematy" @@ -225,6 +226,19 @@ pl_PL: posted_by_you: "Dodany przez ciebie" sent_by_user: "Wysłano przez {{user}}" sent_by_you: "Wysłano przez Ciebie" + directory: + title: "Lista użytkowników" + likes_given: "Przekazane ♥" + likes_received: "Otrzymane ♥" + topics_entered: "Utworzone tematy" + time_read: "Czas" + topic_count: "Tematy" + post_count: "Odpowiedzi" + no_results: "Nie znaleziono wyników dla wskazanego przedziału czasu." + total_rows: + one: "1 znaleziony użytkownik" + few: "%{count} znalezionych użytkowników" + other: "%{count} znalezionych użytkowników" groups: visible: "Grupa jest widoczna dla wszystkich użytkowników" title: @@ -628,7 +642,7 @@ pl_PL: emoji: "Emoji :smile:" add_warning: "To jest oficjalne ostrzeżenie." posting_not_on_topic: "W którym temacie chcesz odpowiedzieć?" - saving_draft_tip: "zapisywanie" + saving_draft_tip: "zapisuję..." saved_draft_tip: "zapisano" saved_local_draft_tip: "zapisano lokalnie" similar_topics: "Twój temat jest podobny do…" @@ -900,10 +914,12 @@ pl_PL: open: "Otwórz temat" close: "Zamknij temat" auto_close: "Zamknij automatycznie" + feature: "Wyróżnij temat" + remove_feature: "Cofnij wyróżnienie" make_banner: "Ustaw jako baner" remove_banner: "Wyłącz ten baner" - unpin: "Odepnij temat" pin: "Przypnij temat" + unpin: "Odepnij temat" pin_globally: "Przypnij temat globalnie" unarchive: "Przywróć z archiwum" archive: "Archiwizuj temat" @@ -924,6 +940,30 @@ pl_PL: title: 'Zgłoś' help: 'zgłoś ten temat, aby zwrócić uwagę moderacji lub wyślij powiadomienie o nim' success_message: 'Ten temat został pomyślnie zgłoszony.' + feature_topic: + title: "Wyróżnij ten temat" + pin: "Wyróżnij ten temat przypinając go na górze w kategorii {{categoryLink}} " + confirm_pin: "Na pewno? Masz już {{count}} przypiętych tematów -- zbyt wiele może obniżyć czytelność innych aktywnych tematów." + unpin: "Usuń wyróżnienie dla tego tematu odpinając go z początku kategorii {{categoryLink}}" + pin_note: "Użytkownicy mogą przypinać tematy dla samych siebie." + already_pinned: + zero: "Brak przypiętych tematów w {{categoryLink}}." + one: "Przypięte tematy w {{categoryLink}}: 1." + other: "Przypięte tematy w {{categoryLink}}: {{count}}." + pin_globally: "Wyróżnij ten temat przypinając go na górze wszystkich list." + confirm_pin_globally: "Na pewno? Masz już {{count}} przypiętych tematów -- zbyt wiele może obniżyć czytelność innych aktywnych tematów." + unpin_globally: "Usuń wyróżnienie dla tego tematu odpinając go z początku wszystkich list." + global_pin_note: "Użytkownicy mogą przypinać tematy dla samych siebie." + already_pinned_globally: + zero: "Brak przypiętych globalnie tematów." + one: "Globalnie przypięte tematy: 1." + other: "Globalnie przypięte tematy: {{count}}." + make_banner: "Ustaw ten temat jako baner wyświetlany na górze każdej strony." + remove_banner: "Usuń ten temat jako baner wyświetlany na górze każdej strony." + banner_note: "Użytkownicy mogą usunąć baner zamykając go przyciskiem. Tylko jeden temat może być banerem w danej chwili." + already_banner: + zero: "Baner nie jest obecnie ustawiony." + one: "Baner jest ustawiony." inviting: "Zapraszam…" automatically_add_to_groups_optional: "To zaproszenie daje dostęp do tych grup: (opcjonalne, tylko dla admina)" automatically_add_to_groups_required: "To zaproszenie daje dostęp do tych grup: (Wymagane, tylko dla admina)" @@ -1550,8 +1590,12 @@ pl_PL: name: "Nazwa" add: "Dodaj" add_members: "Dodaj członków" - custom: "Personalizacje" - automatic: "Automatyczne" + custom: + label: "Niestandardowe" + title: "Grupy niestandardowe " + automatic: + label: "Automatyczne" + title: "Grupy automatyczne" automatic_membership_email_domains: "Użytkownicy rejestrujący się przy pomocy adresu z tej listy zostaną automatycznie przypisani do tej grupy." automatic_membership_retroactive: "Zastosuj tę regułę domenową do już istniejących użytkowników." api: diff --git a/config/locales/client.pt.yml b/config/locales/client.pt.yml index c0df8d4b4e..1fdb5ff2c7 100644 --- a/config/locales/client.pt.yml +++ b/config/locales/client.pt.yml @@ -582,7 +582,6 @@ pt: emoji: "Emoji :smile:" add_warning: "Este é um aviso oficial." posting_not_on_topic: "A que tópico quer responder?" - saving_draft_tip: "a guardar" saved_draft_tip: "guardado" saved_local_draft_tip: "guardado localmente" similar_topics: "O seu tópico é similar a..." @@ -843,8 +842,8 @@ pt: auto_close: "Fechar Automaticamente" make_banner: "Apresentar tópico como Banner" remove_banner: "Remover apresentação do tópico como banner" - unpin: "Remover Destaque do Tópico" pin: "Destacar Tópico" + unpin: "Remover Destaque do Tópico" pin_globally: "Destacar Tópico Globalmente" unarchive: "Desarquivar Tópico" archive: "Arquivar Tópico" diff --git a/config/locales/client.pt_BR.yml b/config/locales/client.pt_BR.yml index 585dfbdb20..80552991ea 100644 --- a/config/locales/client.pt_BR.yml +++ b/config/locales/client.pt_BR.yml @@ -598,7 +598,6 @@ pt_BR: emoji: "Emoji :smile:" add_warning: "Este é um aviso oficial." posting_not_on_topic: "Qual tópico você gostaria de responder?" - saving_draft_tip: "salvando" saved_draft_tip: "salvo" saved_local_draft_tip: "salvo localmente" similar_topics: "Seu tópico é parecido com..." @@ -862,8 +861,8 @@ pt_BR: auto_close: "Fechar automaticamente" make_banner: "Banner do Tópico" remove_banner: "Remover Banner do Tópico" - unpin: "Remover destaque do tópico" pin: "Destacar tópico" + unpin: "Remover destaque do tópico" pin_globally: "Fixar Tópico Globalmente" unarchive: "Desarquivar tópico" archive: "Arquivar tópico" @@ -1476,8 +1475,6 @@ pt_BR: name: "Nome" add: "Adicionar" add_members: "Adicionar membros" - custom: "Definidos" - automatic: "Automáticos" automatic_membership_email_domains: "Usuários que se registram com um domínio de email que confere precisamente com algum desta lista serão automaticamente adicionados a este grupo:" automatic_membership_retroactive: "Aplicar a mesma regra de domínio de email para adicionar usuários registrados" api: diff --git a/config/locales/client.ru.yml b/config/locales/client.ru.yml index 042a865c94..5684e77538 100644 --- a/config/locales/client.ru.yml +++ b/config/locales/client.ru.yml @@ -224,6 +224,18 @@ ru: posted_by_you: "Размещено Вами" sent_by_user: "Отправлено пользователем {{user}}" sent_by_you: "Отправлено Вами" + directory: + likes_given: "Выразил симпатий" + likes_received: "Получил симпатий" + topics_entered: "Посещено тем" + time_read: "Время чтения" + topic_count: "Тем" + post_count: "Ответов" + no_results: "Нет результатов за этот временной промежуток." + total_rows: + one: "Найден 1 пользователь" + few: "Найдено %{count} пользователя" + other: "Найдено %{count} пользователей" groups: visible: "Группа видима всем пользователям" title: @@ -626,7 +638,7 @@ ru: emoji: "Emoji :smile:" add_warning: "Это официальное предупреждение." posting_not_on_topic: "В какой теме вы хотите ответить?" - saving_draft_tip: "сохранение" + saving_draft_tip: "Сохранение..." saved_draft_tip: "сохранено" saved_local_draft_tip: "сохранено локально" similar_topics: "Ваша тема похожа на..." @@ -752,6 +764,7 @@ ru: close_topics: "Закрыть темы" archive_topics: "Архивировать темы" notification_level: "Изменить уровень оповещения" + choose_new_category: "Выберите новый раздел для тем:" selected: one: "Вы выбрали 1 тему." few: "Вы выбрали {{count}} темы." @@ -897,8 +910,8 @@ ru: auto_close: "Автоматическое закрытие" make_banner: "Сделать объявлением" remove_banner: "Больше не показывать объявлением" - unpin: "Отлепить тему" pin: "Прилепить тему" + unpin: "Отлепить тему" pin_globally: "Прилепить тему глобально" unarchive: "Разархивировать тему" archive: "Архивировать тему" @@ -919,6 +932,10 @@ ru: title: 'Жалоба' help: 'пожаловаться на сообщение' success_message: 'Вы пожаловались на тему.' + feature_topic: + already_banner: + zero: "Нет активных тем-объявлений." + one: "Есть активная тема-объявление." inviting: "Высылаю приглашение..." automatically_add_to_groups_optional: "Это приглашение также включает в себя доступ к следующим группам: (опционально, только для администратора)" automatically_add_to_groups_required: "Это приглашение также включает в себя доступ к следующим группам: (Обязательно, только для администратора)" @@ -1022,6 +1039,7 @@ ru: attachment_too_large: "Файл, который вы пытаетесь загрузить, слишком большой (максимальный разрешенный размер {{max_size_kb}}КБ)." file_too_large: "К сожалению, файл, который вы пытаетесь загрузить, слишком большой (максимально допустимый размер {{max_size_kb}}kb)" too_many_uploads: "К сожалению, за один раз можно загрузить только одно изображение." + too_many_dragged_and_dropped_files: "За один раз можно перетянуть не более 10 файлов." upload_not_authorized: "К сожалению, вы не можете загрузить файл данного типа (список разрешенных типов файлов: {{authorized_extensions}})." image_upload_not_allowed_for_new_user: "К сожалению, загрузка изображений недоступна новым пользователям." attachment_upload_not_allowed_for_new_user: "К сожалению, загрузка файлов недоступна новым пользователям." @@ -1544,8 +1562,6 @@ ru: name: "Имя" add: "Добавить" add_members: "Добавить участников" - custom: "Настраиваемые" - automatic: "Автоматические" api: generate_master: "Сгенерировать ключ API" none: "Отсутствует ключ API." @@ -1933,6 +1949,7 @@ ru: time_read: "Время чтения" delete: "Удалить пользователя" delete_forbidden_because_staff: "Администраторы и модераторы не могут быть удалены" + delete_posts_forbidden_because_staff: "Нельзя удалить все сообщения администраторов и модераторов." delete_forbidden: one: "Пользователи не могут быть удалены, если у них есть сообщения. Перед удалением пользователя удалите все его сообщения. (Сообщения старше %{count} дня не могут быть удалены.)" few: "Пользователи не могут быть удалены, если у них есть сообщения. Перед удалением пользователя удалите все его сообщения. (Сообщения старше %{count} дней не могут быть удалены.)" @@ -2078,6 +2095,7 @@ ru: modal_title: Типы наград granted_by: Кем выдана granted_at: Когда выдана + reason_help: (Ссылка на сообщение или тему) save: Сохранить delete: Удалить delete_confirm: Вы уверены, что хотите удалить эту награду? diff --git a/config/locales/client.sq.yml b/config/locales/client.sq.yml index 6c6b1732e3..04ff6d5327 100644 --- a/config/locales/client.sq.yml +++ b/config/locales/client.sq.yml @@ -84,6 +84,7 @@ sq: other: "%{count} ditë më parë" share: topic: 'shpërnda një lidhje tek kjo temë' + post: 'post #%{postNumber}' close: 'mbylle' twitter: 'shpërndaje këtë lidhe në Twitter' facebook: 'shpërndaje këtë lidhje ne Facebook' @@ -141,6 +142,7 @@ sq: like_count: "Pëlqime" topic_count: "Tema" post_count: "Postime" + contact: "Kontaktoni" bookmarks: not_logged_in: "ju duhet të jeni të identifikuar për të ruajtur temën." created: "ju ruajtët këtë temë" @@ -191,6 +193,9 @@ sq: posted_by_you: "Postuar nga ju" sent_by_user: "Dërguar nga {{user}}" sent_by_you: "Dërguar nga ju" + directory: + time_read: "Koha e Leximit" + post_count: "Përgjigje" groups: visible: "Grupi është i dukshëm për të gjithë përdoruesit" title: @@ -245,6 +250,7 @@ sq: organisation: Organizata phone: Telefoni trust_level: "TL" + read_time: "koha e leximit" post_count: "# postimeve" user: said: "{{username}}:" @@ -534,7 +540,7 @@ sq: composer: add_warning: "This is an official warning." posting_not_on_topic: "Which topic do you want to reply to?" - saving_draft_tip: "saving" + saving_draft_tip: "duke e ruajtur..." saved_draft_tip: "saved" saved_local_draft_tip: "saved locally" similar_topics: "Your topic is similar to..." @@ -552,6 +558,7 @@ sq: reply: "Përgjigju" cancel: "Anulo" create_topic: "Temë e Re" + create_pm: "Mesazh Privat" title: "Or press Ctrl+Enter" users_placeholder: "Add a user" title_placeholder: "What is this discussion about in one brief sentence?" @@ -793,8 +800,8 @@ sq: auto_close: "Mbyllje Automatike" make_banner: "Banner Topic" remove_banner: "Remove Banner Topic" - unpin: "Un-Pin Topic" pin: "Pin Topic" + unpin: "Un-Pin Topic" pin_globally: "Pin Topic Globally" unarchive: "Unarchive Topic" archive: "Archive Topic" diff --git a/config/locales/client.sv.yml b/config/locales/client.sv.yml index e6d801e21b..76f87f8030 100644 --- a/config/locales/client.sv.yml +++ b/config/locales/client.sv.yml @@ -580,7 +580,6 @@ sv: composer: add_warning: "Det här är en officiell varning" posting_not_on_topic: "Du svarar på tråden \"{{title}}\", men du besöker just nu en annan tråd." - saving_draft_tip: "sparar" saved_draft_tip: "sparat" saved_local_draft_tip: "sparat lokalt" similar_topics: "Din tråd liknar..." @@ -842,8 +841,8 @@ sv: auto_close: "Stäng Automatiskt" make_banner: "Banderollämne" remove_banner: "Radera Banderollämne" - unpin: "Avnåla Tråd" pin: "Nåla Tråd" + unpin: "Avnåla Tråd" pin_globally: "Nåla diskussionen globalt" unarchive: "Dearkivera Tråd" archive: "Arkivera Tråd" @@ -1446,8 +1445,6 @@ sv: name: "Namn" add: "Lägg till" add_members: "Lägg till medlemmar" - custom: "Anpassad" - automatic: "Automatisk" automatic_membership_email_domains: "Användare som registrerar sig med en email där domänen liknar exact en av dom ovanstående domänerna kommer automatiskt att bli tillagd i den här gruppen:" automatic_membership_retroactive: "Avänd samma email domän regel för att lägga till nya avändare" api: diff --git a/config/locales/client.te.yml b/config/locales/client.te.yml index a2df67b7ca..73d3c02053 100644 --- a/config/locales/client.te.yml +++ b/config/locales/client.te.yml @@ -601,7 +601,6 @@ te: emoji: "Emoji :smile:" add_warning: "ఇది ఒక అధికారిక హెచ్చరిక" posting_not_on_topic: "ఏ విషయానికి మీరు జవాబివ్వాలనుకుంటున్నారు? " - saving_draft_tip: "భద్రమవుతోంది" saved_draft_tip: "భద్రం" saved_local_draft_tip: "స్థానికంగా భద్రం" similar_topics: "మీ విషయం దీని వలె ఉంది..." @@ -865,8 +864,8 @@ te: auto_close: "స్వీయ మూయు" make_banner: "బ్యానరు విషయం" remove_banner: "బ్యానరు విషయం తొలగించు" - unpin: "విషయం అగ్గుచ్చు" pin: "విషయం గుచ్చు" + unpin: "విషయం అగ్గుచ్చు" pin_globally: "సార్వత్రికంగా విషయాన్ని గుచ్చు" unarchive: "విషయాన్ని కట్టవిప్పు" archive: "విషయాన్ని కట్టకట్టు" @@ -1480,8 +1479,6 @@ te: name: "పేరు" add: "కలుపు" add_members: "సభ్యులను కలుపు" - custom: "అనురూప" - automatic: "స్వీయంగా" automatic_membership_email_domains: "వినియోగదారుడు ఏ ఈ-మెయిల్ డొమైన్ తో నమోదు చేసుకున్నాడో అది ఖచ్చితంగా ఈ జాబితాలో ఒక దానిని పోలి స్వయంసిధ్ధంగా గ్రూప్ కి కలుస్తాయి:" automatic_membership_retroactive: "ఇప్పటికే నమోదిత వినియోగదారులను జోడించడానికి అదే ఇమెయిల్ డొమైన్ రూల్ వర్తిస్తుంది" api: diff --git a/config/locales/client.tr_TR.yml b/config/locales/client.tr_TR.yml index 1dde0885ec..e039e1f34c 100644 --- a/config/locales/client.tr_TR.yml +++ b/config/locales/client.tr_TR.yml @@ -185,6 +185,14 @@ tr_TR: posted_by_you: "Sizin tarafınızdan gönderildi" sent_by_user: "{{user}} tarafından yollandı" sent_by_you: "Sizin tarafınızdan yollandı" + directory: + title: "Kullanıcı Dizini" + likes_given: "Beğendikleriniz" + likes_received: "Beğenilenleriniz" + time_read: "Okuma Zamanı" + topic_count: "Konular" + post_count: "Cevaplar" + no_results: "Bu zaman aralığı için sonuç bulunamadı." groups: visible: "Grup tüm kullanıcılar tarafından görüntülenebiliyor" title: @@ -574,7 +582,7 @@ tr_TR: emoji: "Emoji :smile:" add_warning: "Bu resmi bir uyarıdır." posting_not_on_topic: "Hangi konuyu cevaplamak istiyorsun?" - saving_draft_tip: "kaydediliyor" + saving_draft_tip: "kaydediliyor..." saved_draft_tip: "kaydedildi" saved_local_draft_tip: "yerele kaydedildi" similar_topics: "Konunuz bu konuya benziyor..." @@ -832,8 +840,8 @@ tr_TR: auto_close: "Otomatik Kapatma" make_banner: "Manşet Konusu Yap" remove_banner: "Manşet Konusunu Kaldır" - unpin: "Konuyu Başa Tutturma" pin: "Konuyu Başa Tuttur" + unpin: "Konuyu Başa Tutturma" pin_globally: "Konuyu Her Yerde Başa Tuttur" unarchive: "Konuyu Arşivden Kaldır" archive: "Konuyu Arşivle" @@ -1414,8 +1422,9 @@ tr_TR: name: "Ad" add: "Ekle" add_members: "Üye ekle" - custom: "Özel" - automatic: "Otomatik" + automatic: + label: "Otomatik" + title: "Otomatik Gruplar" automatic_membership_email_domains: "Bu listedeki bir email alan adıyla kaydolan kullanıcılar otomatik olarak bu gruba eklenecekler:" automatic_membership_retroactive: "Varolan kayıtlı kullanıcıları eklemek için aynı email alan adı kuralını uygula" api: diff --git a/config/locales/client.uk.yml b/config/locales/client.uk.yml index a4bd2cb5f0..d3b62329d8 100644 --- a/config/locales/client.uk.yml +++ b/config/locales/client.uk.yml @@ -462,7 +462,6 @@ uk: message: "Автентифікація через GitHub (перевірте, щоб блокувальники спливних вікон були вимкнені)" composer: posting_not_on_topic: "На яку тему Ви хочете відповісти?" - saving_draft_tip: "збереження" saved_draft_tip: "збережено" saved_local_draft_tip: "збережено локально" similar_topics: "Ваша тема схожа на..." @@ -646,8 +645,8 @@ uk: open: "Відкрити тему" close: "Закрити тему" auto_close: "Автоматичне закриття" - unpin: "Відкріпити тему" pin: "Закріпити тему" + unpin: "Відкріпити тему" unarchive: "Розархівувати тему" archive: "Заархівувати тему" reset_read: "Скинути дані про прочитаність" diff --git a/config/locales/client.zh_CN.yml b/config/locales/client.zh_CN.yml index 4484fe6930..1816ff64aa 100644 --- a/config/locales/client.zh_CN.yml +++ b/config/locales/client.zh_CN.yml @@ -109,6 +109,7 @@ zh_CN: daily: "每天" weekly: "每周" every_two_weeks: "每两周" + every_three_days: "每三天" max_of_count: "最多 {{count}}" character_count: other: "%{count} 个字符" @@ -143,6 +144,7 @@ zh_CN: not_bookmarked: "你已经阅读过此帖;点此为其添加书签" last_read: "这是你阅读过的最后一帖;点此给它加上书签" remove: "删除书签" + confirm_clear: "你确定要删除该主题的所有书签吗?" topic_count_latest: other: "{{count}} 个新的或更新的主题。" topic_count_unread: @@ -184,6 +186,17 @@ zh_CN: posted_by_you: "发起人 " sent_by_user: "发送人 {{user}}" sent_by_you: "发送人 " + directory: + title: "用户目录" + likes_given: "赞" + likes_received: "被赞" + topics_entered: "参与的主题" + time_read: "阅读时间" + topic_count: "主题" + post_count: "回复" + no_results: "该时间段内没有找到结果" + total_rows: + other: "找到 %{count} 个用户" groups: visible: "群组对所有用户可见" title: @@ -378,7 +391,9 @@ zh_CN: email_digests: title: "当我不访问时,向我的邮箱发送最新信息:" daily: "每天" + every_three_days: "每三天" weekly: "每周" + every_two_weeks: "每两周" email_direct: "当有人引用我、回复我的帖子或提及@你时发送一封邮件给我" email_private_messages: "当有人给发私信给我时发送一封邮件给我" email_always: "即使在论坛中活跃时也接收电子邮件提醒" @@ -570,7 +585,7 @@ zh_CN: emoji: "Emoji :smile:" add_warning: "这是一个正式的警告。" posting_not_on_topic: "你想回复哪一个主题?" - saving_draft_tip: "保存中" + saving_draft_tip: "保存中……" saved_draft_tip: "已保存" saved_local_draft_tip: "已本地保存" similar_topics: "你的主题有些类似于..." @@ -827,8 +842,8 @@ zh_CN: auto_close: "自动关闭" make_banner: "横幅主题" remove_banner: "移除横幅主题" - unpin: "解除主题置顶" pin: "置顶主题" + unpin: "解除主题置顶" pin_globally: "全局置顶主题" unarchive: "解除主题存档" archive: "存档主题" @@ -1408,8 +1423,12 @@ zh_CN: name: "名字" add: "添加" add_members: "添加成员" - custom: "定制" - automatic: "自动" + custom: + label: "定制" + title: "定制分组" + automatic: + label: "自动" + title: "自动分组" automatic_membership_email_domains: "用户注册时邮箱域名若与列表完全匹配则自动添加至这个群组:" automatic_membership_retroactive: "应用同样的邮件域名规则添加已经注册的用户" api: @@ -1661,6 +1680,7 @@ zh_CN: delete_topic: "删除主题" delete_post: "删除帖子" impersonate: "检视" + anonymize_user: "匿名用户" screened_emails: title: "被屏蔽的邮件地址" description: "当有人试图用以下邮件地址注册时,将受到阻止或其它系统操作。" @@ -1790,6 +1810,7 @@ zh_CN: approve_success: "用户已被批准, 激活邮件已发送。" approve_bulk_success: "成功!所有选定的用户已批准并通知。" time_read: "阅读次数" + anonymize: "匿名用户" delete: "删除用户" delete_forbidden_because_staff: "不能删除管理员和版主。" delete_forbidden: @@ -1895,6 +1916,7 @@ zh_CN: none: '无' no_results: "找不到结果。" clear_filter: "清除" + add_url: "增加链接" categories: all_results: '全部' required: '必填' diff --git a/config/locales/client.zh_TW.yml b/config/locales/client.zh_TW.yml index ca19f07256..1f8542218b 100644 --- a/config/locales/client.zh_TW.yml +++ b/config/locales/client.zh_TW.yml @@ -109,6 +109,7 @@ zh_TW: daily: "每天" weekly: "每週" every_two_weeks: "每兩週" + every_three_days: "每三天" max_of_count: "(最大 {{count}})" character_count: other: "{{count}} 個字" @@ -143,6 +144,7 @@ zh_TW: not_bookmarked: "你已閱讀過這篇文章,按此加上書籤" last_read: "這是你最後閱讀的文章,按此加上書籤" remove: "移除書籤" + confirm_clear: "你確定要刪除該主題的所有書籤嗎?" topic_count_latest: other: "有 {{count}} 個更新過或是新的討論話題。" topic_count_unread: @@ -184,6 +186,17 @@ zh_TW: posted_by_you: "作者為 " sent_by_user: "寄件者為 {{user}}" sent_by_you: "寄件者為 " + directory: + title: "用戶目錄" + likes_given: "給予喜愛" + likes_received: "接受喜愛" + topics_entered: "進入話題" + time_read: "閱讀多少次" + topic_count: "話題" + post_count: "回覆" + no_results: "該時間段內沒有找到結果。" + total_rows: + other: "找到 %{count} 個用戶" groups: visible: "群組可被所有用戶看到" title: @@ -378,7 +391,9 @@ zh_TW: email_digests: title: "當我很久沒來此網站時,以電子郵件通知我最近有什麼新文章:" daily: "每天" + every_three_days: "每三天" weekly: "每週" + every_two_weeks: "每兩星期" email_direct: "當有人引用、回覆我的發文,或以 @用戶名稱 提到我時,請以電子郵件通知我。" email_private_messages: "當有人寄給我私人訊息時,以電子郵件通知我。" email_always: "不要因為我在網站上活動而不寄信通知。" @@ -431,6 +446,7 @@ zh_TW: too_short: "你的密碼太短。" common: "此密碼太簡單。" same_as_username: "密碼與使用者名稱相同" + same_as_email: "你的密碼與電郵相同。" ok: "你的密碼符合要求。" instructions: "至少 %{count} 個字。" associated_accounts: "登入" @@ -541,6 +557,7 @@ zh_TW: requires_invite: "抱歉,只有受邀請者才能進入此論壇。" not_activated: "你還無法登入,我們之前曾將啟用帳號的電子郵件寄至 {{sentTo}},請從該電子郵件啟用你的帳號。" not_allowed_from_ip_address: "你無法透過此 IP 登入。" + admin_not_allowed_from_ip_address: "你無法透過此 IP 登入成為管理員。" resend_activation_email: "按這裡重新寄出啟用帳號的電子郵件。" sent_activation_email_again: "我們已經將啟用帳號的電子郵件寄至 {{currentEmail}},你可能幾分鐘後才會收到,如果一直沒收到,請檢查垃圾郵件資料夾。" google: @@ -569,7 +586,7 @@ zh_TW: emoji: "Emoji :smile:" add_warning: "這是正式警告。" posting_not_on_topic: "你想要回覆哪個討論話題?" - saving_draft_tip: "正在儲存" + saving_draft_tip: "正在儲存..." saved_draft_tip: "儲存完畢" saved_local_draft_tip: "本地儲存完畢" similar_topics: "與你的討論話題類似的討論..." @@ -826,8 +843,8 @@ zh_TW: auto_close: "自動關閉" make_banner: "橫幅討論話題" remove_banner: "移除橫幅討論話題" - unpin: "復原已置頂的討論話題" pin: "置頂討論話題" + unpin: "復原已置頂的討論話題" pin_globally: "全區置頂討論話題" unarchive: "復原已封存的討論話題" archive: "封存討論話題" @@ -1269,6 +1286,7 @@ zh_TW: title: "本週精選" daily: title: "本日精選" + all: "所有時間" this_year: "本年" this_month: "本月" this_week: "本週" @@ -1407,8 +1425,12 @@ zh_TW: name: "名稱" add: "加入" add_members: "新增成員" - custom: "自訂" - automatic: "自動" + custom: + label: "自訂" + title: "自訂群組" + automatic: + label: "自動" + title: "自動群組" automatic_membership_email_domains: "註冊的用戶的電子郵件地址網域,完全符合列表裡某項時,會自動加進這個群組裡:" automatic_membership_retroactive: "套用相同的電子郵件網域規則到已經註冊的用戶上:" api: @@ -1660,6 +1682,7 @@ zh_TW: delete_topic: "刪除討論話題" delete_post: "刪除文章" impersonate: "檢視" + anonymize_user: "匿名用戶" screened_emails: title: "過濾的電子郵件地址" description: "以下的電子郵件地址將無法用來建立新用戶。" @@ -1789,8 +1812,13 @@ zh_TW: approve_success: "用戶已獲得批准並送出啟用帳號的電子郵件。" approve_bulk_success: "完成! 已批准所有選取的用戶並送出通知。" time_read: "閱讀時間" + anonymize: "匿名用戶" + anonymize_confirm: "你確定要將這個帳戶變成匿名?這將改變用戶名和電子郵件,並重置所有個人資料信息。" + anonymize_yes: "是,將這個帳戶變成匿名" + anonymize_failed: "將這個帳戶變成匿名時發生錯誤。" delete: "刪除用戶" delete_forbidden_because_staff: "管理員與板主不可刪除。" + delete_posts_forbidden_because_staff: "無法刪除管理員和版主的所有帖子。" delete_forbidden: other: "不能刪除擁有文章的用戶。請先刪除所有文章後才能刪除該用戶。( 發表超過 %{count} 天的文章不能刪除 )" cant_delete_all_posts: @@ -1894,6 +1922,7 @@ zh_TW: none: '無' no_results: "未找到任何結果。" clear_filter: "清除" + add_url: "加入網址" categories: all_results: '全部' required: '必要設定' diff --git a/config/locales/server.de.yml b/config/locales/server.de.yml index d1ff5e36ab..2233fa54ce 100644 --- a/config/locales/server.de.yml +++ b/config/locales/server.de.yml @@ -13,31 +13,31 @@ de: title: "Discourse" topics: "Themen" posts: "Beiträge" - loading: "Lädt" + loading: "Wird geladen" powered_by_html: 'Basiert auf Discourse, funktioniert am besten mit aktiviertem JavaScript' log_in: "Anmelden" via: "%{username} via %{site_name}" is_reserved: "ist reserviert" purge_reason: "Stillgelegtes, nicht aktives Konto wurde automatisch gelöscht." - disable_remote_images_download_reason: "Da nicht mehr genug Plattenplatz vorhanden ist, wurde der Download von Bildern deaktiviert." + disable_remote_images_download_reason: "Der Download von Bildern wurde deaktiviert, weil nicht mehr genug Plattenplatz vorhanden war." errors: format: '%{attribute} %{message}' messages: - too_long_validation: "darf höchstens %{max} Zeichen lang sein; Du hast %{length} eingegeben." - invalid_boolean: "Ungültiger Boolescher Wert" + too_long_validation: "darf höchstens %{max} Zeichen lang sein; du hast %{length} eingegeben." + invalid_boolean: "Ungültiger boolescher Wert." taken: "wird bereits verwendet" - accepted: muss angenommen werden + accepted: muss akzeptiert werden blank: darf nicht leer sein present: muss leer sein - confirmation: "passt nicht zu %{attribute}" - empty: kann nicht leer sein + confirmation: "stimmt nicht mit %{attribute} überein" + empty: darf nicht leer sein equal_to: muss gleich %{count} sein even: muss gerade sein exclusion: ist reserviert greater_than: muss größer als %{count} sein greater_than_or_equal_to: muss größer oder gleich %{count} sein inclusion: ist nicht in der Liste enthalten - invalid: ist gültig + invalid: ist ungültig less_than: muss weniger als %{count} sein less_than_or_equal_to: muss weniger oder gleich %{count} sein not_a_number: ist keine Zahl @@ -45,25 +45,38 @@ de: odd: muss ungerade sein record_invalid: 'Validierung gescheitert: %{errors}' restrict_dependent_destroy: - one: "Kann wegen einer bereits existenten Abhängigkeit zu %{record} nicht gelöscht werden" - other_than: "muss von %{count} verschieden sein" + one: "Eintrag kann nicht gelöscht werden, da noch ein davon abhängiger %{record} existiert." + many: "Eintrag kann nicht gelöscht werden, da noch davon abhängige %{record} existieren." + too_long: + one: ist zu lang (Maximum ist 1 Zeichen) + other: ist zu lang (Maximum sind %{count} Zeichen) + too_short: + one: ist zu kurz (Minimum ist 1 Zeichen) + other: ist zu kurz (Minimum sind %{count} Zeichen) + wrong_length: + one: hat die falsche Länge (sollte 1 Zeichen lang sein) + other: hat die falsche Länge (sollte %{count} Zeichen lang sein) + other_than: "darf nicht %{count} sein" template: + body: 'Es gab Probleme mit diesen Feldern:' header: - one: '%{count} Fehler verhindern, dass %{model} gespeichert wird.' - other: '%{count} Fehler verhindern, dass %{model} gespeichert wird.' + one: 1 Fehler verhindert, dass %{model} gespeichert wird + other: '%{count} Fehler verhindern, dass %{model} gespeichert wird' embed: load_from_remote: "Beim Laden des Beitrags ist ein Fehler aufgetreten." bulk_invite: file_should_be_csv: "Die hochgeladene Datei sollte im CSV oder TXT Format vorliegen." backup: - operation_already_running: " %{operation} läuft gerade. Kann deshalb keine weitere %{operation} Aktion starten." + operation_already_running: "Eine Arbeitsschritt wird momentan bearbeitet. Im Moment kann kein neuer Vorgang gestartet werden." backup_file_should_be_tar_gz: "Die Sicherungsdatei sollte ein .tar.gz-Archiv sein." - not_enough_space_on_disk: "Es gibt nicht genügend freien Festplattenspeicher, um diese Sicherung hochzuladen." - not_logged_in: "Dazu musst Du angemeldet sein." + not_enough_space_on_disk: "Es gibt nicht genügend freien Festplattenspeicher, um dieses Backup hochzuladen." + not_logged_in: "Dazu musst du angemeldet sein." + not_found: "Die angeforderte URL oder Ressource konnte nicht gefunden werden." + invalid_access: "Du hast nicht die Erlaubnis, die angeforderte Ressource zu betrachten." read_only_mode_enabled: "Die Seite befindet sich im Nur-Lesen Modus. Interaktionen sind deaktiviert." too_many_replies: - one: "Entschuldigung, aber neue Benutzer sind temporär auf 1 Antwort im gleichen Thema beschränkt." - other: "Entschuldigung, aber neue Benutzer sind temporär auf %{count} Antworten im gleichen Thema beschränkt." + one: "Entschuldigung, aber neue Benutzer sind vorübergehend auf eine Antwort pro Thema beschränkt." + other: "Entschuldigung, aber neue Benutzer sind vorübergehend auf %{count} Antworten pro Thema beschränkt." embed: start_discussion: "Diskussion beginnen" continue: "Diskussion fortsetzen" @@ -78,11 +91,11 @@ de: one: "1 Antwort" other: "%{count} Antworten" too_many_mentions: - zero: "Entschuldigung, Du kannst keine anderen Nutzer erwähnen." - one: "Entschuldigung, Du kannst nur einen anderen Nutzer in Deinem Beitrag erwähnen." - other: "Entschuldigung, Du kannst nur %{count} Nutzer in einem Beitrag erwähnen." + zero: "Entschuldigung, du kannst keine anderen Nutzer erwähnen." + one: "Entschuldigung, du kannst nur einen anderen Nutzer in Deinem Beitrag erwähnen." + other: "Entschuldigung, du kannst nur %{count} Nutzer in einem Beitrag erwähnen." too_many_mentions_newuser: - zero: "Entschuldige, neue Benutzer können andere Nutzer nicht erwähnen." + zero: "Entschuldigung, neue Benutzer können andere Nutzer nicht erwähnen." one: "Entschuldige, neue Benutzer können nur einen anderen Nutzer in einem Beitrag erwähnen." other: "Entschuldige, neue Benutzer können nur %{count} Nutzer in einem Beitrag erwähnen." too_many_images: @@ -97,13 +110,14 @@ de: zero: "Entschuldige, neue Benutzer können Beiträgen keine Links hinzufügen." one: "Entschuldige, neue Benutzer können Beiträgen nur einen Link hinzufügen." other: "Entschuldige, neue Benutzer können Beiträge nur %{count} Links hinzufügen." - spamming_host: "Entschuldigung, Du kannst keine Links zu diesem Webserver posten." + spamming_host: "Entschuldigung, du kannst keine Links zu diesem Webserver posten." user_is_suspended: "Gesperrte Benutzer dürfen keine Beiträge schreiben." + topic_not_found: "Etwas ist schief gelaufen. Wurde das Thema eventuell geschlossen oder gelöscht, während du es angeschaut hast?" just_posted_that: "ist einer einer vor Kurzem von Ihnen geschriebenen Nachricht zu ähnlich" has_already_been_used: "wurde schon benutzt" invalid_characters: "enthält ungültige Zeichen" is_invalid: "ist ungültig; bitte ein wenig anschaulicher" - next_page: "Nächste Seite →" + next_page: "nächste Seite →" prev_page: "← vorherige Seite" page_num: "Seite %{num}" topics_in_category: "Themen in der Kategorie '%{category}'" @@ -116,7 +130,7 @@ de: private_message_abbrev: "PN" rss_description: latest: "Aktuelle Themen" - hot: "Angesagte Themen" + hot: "Beliebte Themen" too_late_to_edit: "Dieser Beitrag wurde vor zu langer Zeit erstellt. Er kann nicht mehr bearbeitet oder gelöscht werden." excerpt_image: "Bild" groups: @@ -141,9 +155,9 @@ de: - Ist der Titel eine adäquate Beschreibung dessen, was ein Nutzer vorzufinden erwartet, wenn er dieses Thema aufruft? - - Der erste Beitrag umschreibt das Thema: Worum geht es? Wer wäre interessiert daran? Warum ist es wichtig? Welche Arten von Antworten erhoffst Du dir von der Community? + - Der erste Beitrag umschreibt das Thema: Worum geht es? Wer wäre interessiert daran? Warum ist es wichtig? Welche Arten von Antworten erhoffst du dir von der Community? - - Versuche, die richtigen Worte zu verwenden, so dass andere Dein Thema *finden* können. Wenn möglich, wähle eine angemessene Kategorie für Dein Thema. + - Versuche, die richtigen Worte zu verwenden, so dass andere dein Thema *finden* können. Wenn möglich, wähle eine angemessene Kategorie für dein Thema. Bitte beachte auch [unsere Richtlinien](/guidelines). Dieser Hilfetext wird nur bei deinen ersten %{education_posts_text} Beiträgen angezeigt. new-reply: | @@ -151,7 +165,7 @@ de: - Fügt dein Beitrag dem Gespräch etwas Neues hinzu, und sei es auch wenig? - - Behandle deine Gesprächspartner mit demselben Respekt, den Du von ihnen erwartest. + - Behandle deine Gesprächspartner mit demselben Respekt, den du von ihnen erwartest. - Kritk ist in Ordnung, aber bitte kritisiere nur *Ideen*, nicht Menschen. @@ -164,12 +178,20 @@ de: Hast du darüber nachgedacht **[besuche dein Benutzerprofil](%{profile_path})** und ein eigenes Bild hochzuladen? Es ist einfacher gemeinschaftlichen Diskussionen zu folgen und interessante Leute zu finden, wenn jeder ein eigenes Avatar hat. + sequential_replies: | + ### Versuche, mehreren Beitragen gleichzeitig zu antworten + + Statt mehrmals hintereinander in einem Thema zu antworten, versuche eventuell, einen einzigen Beitrag zu verfassen, der Zitate oder @name Verweise enthält. + + Du kannst deine letzte Antwort bearbeiten und ein Zitat hinzufügen, indem Du den jeweiligen Text markierst und dann auf Antwort zitieren klickst. + + Es ist für jeden einfacher, Themen zu lesen, die anstelle vieler kleiner Antworten etwas weniger tiefgründigere Antworten enthalten. dominating_topic: | ### Lass auch andere die Konversation mitgestalten - Dieses Thema ist Dir eindeutig wichtig – Du hast mehr als %{percent}% aller Antworten verfasst. + Dieses Thema ist dir eindeutig wichtig – Du hast mehr als %{percent}% aller Antworten verfasst. - Bist Du sicher, dass Du anderen Benutzern genügend Zeit lässt, ihre eigenen Sichtweisen darzulegen? + Bist du sicher, dass du anderen Benutzern genügend Zeit lässt, ihre eigenen Sichtweisen darzulegen? too_many_replies: | ### Du hast das Antwort-Limit für dieses Thema erreicht. @@ -201,11 +223,13 @@ de: warning_requires_pm: "Du kannst eine Warnung nur an eine Nachricht zugleich anhängen." too_many_users: "Du kannst eine Warnung nur an einen Benutzer zugleich anhängen." cant_send_pm: "Entschuldigung, Sie können diesem Nutzer keine private Nachricht schicken." - no_user_selected: "Sie müssen einen gültigen Benutzer auswählen." + no_user_selected: "Du musst einen gültigen Benutzer auswählen." user: attributes: password: common: "ist eines der 10000 meist verwendeten Passwörter. Bitte verwende ein sichereres Passwort." + same_as_username: "ist mit deinem Benutzernamen identisch. Bitte verwende ein sichereres Passwort." + same_as_email: "ist mit deiner E-Mail-Adresse identisch. Bitte verwende ein sichereres Passwort." ip_address: signup_not_allowed: "Eine Registrierung ist von diesem Konto nicht erlaubt." color_scheme_color: @@ -213,7 +237,7 @@ de: hex: invalid: "ist keine gültige Farbe" user_profile: - no_info_me: "
    Das 'Über mich'-Feld Deines Profils ist aktuell leer, möchtest Du es ausfüllen?
    " + no_info_me: "
    Das 'Über mich'-Feld deines Profils ist aktuell leer, möchtest du es ausfüllen?
    " no_info_other: "
    %{name} hat noch nichts in das 'Über mich'-Feld des Nutzerprofils eingetragen
    " vip_category_name: "Lounge" vip_category_description: "Eine Kategorie exklusiv für Mitglieder mit einer Vertrauensstufe Level 3 oder höher." @@ -309,7 +333,7 @@ de: one: "vor einer Sekunde" other: "vor %{count} Sekunden" less_than_x_minutes: - one: "vor weniger als 1 Minute" + one: "vor weniger als einer Minute" other: "vor weniger als %{count} Minuten" x_minutes: one: "vor einer Minute" @@ -355,7 +379,7 @@ de: please_continue: "Dein neuer Account ist jetzt bestätigt; du wirst auf die Startseite weitergeleitet." continue_button: "Weiter zu %{site_name}" welcome_to: "Willkommen bei %{site_name}!" - approval_required: "Bevor Du auf das Forum zugreifen kannst, muss Dein neues Konto noch von einem Moderator genehmigt werden. Du erhälst eine E-Mail, sobald dies geschehen ist!" + approval_required: "Bevor du auf das Forum zugreifen kannst, muss dein neues Konto noch von einem Moderator genehmigt werden. Du erhältst eine E-Mail, sobald dies geschehen ist!" post_action_types: off_topic: title: 'Am Thema vorbei' @@ -365,6 +389,7 @@ de: title: 'Reklame' description: 'Dieser Beitrag besteht effektiv nur aus Werbung, die nicht als solche ausgewiesen ist. Er trägt nichts zum aktuellen Gespräch bei.' long_form: 'dies als Spam gemeldet' + email_title: '"%{title}" wurde als Spam markiert' email_body: "%{link}\n\n%{message}" inappropriate: title: 'Unangemessen' @@ -422,9 +447,9 @@ de: unsubscribed: title: 'Abo abbestellt' description: "Dein Abo wurde abbestellt. Wir werden Dich nicht wieder kontaktieren!" - oops: "Bitte klicke unten, falls Du das nicht tun wolltest." + oops: "Bitte klicke unten, falls du das nicht tun wolltest." error: "Beim Löschen des Abonnements trat ein Fehler auf." - preferences_link: "Du kannst den Empfang von Zusammenfassungen per E-Mail auch in Deinen Profil-Einstellungen deaktivieren." + preferences_link: "Du kannst den Empfang von Zusammenfassungen per E-Mail auch in deinen Profil-Einstellungen deaktivieren." different_user_description: "Die Zusammenfassung wurde einem anderen als dem momentan angemeldeten Benutzer geschickt. Bitte melde Dich ab und versuche es erneut." not_found_description: "Entschuldige, wir konnten Dein Abo nicht abbestellen. Möglicherweise ist der Link aus deiner Mail veraltet." resubscribe: @@ -510,25 +535,31 @@ de: page_view_anon_reqs: title: "Anonym" xaxis: "Tag" - yaxis: "Anonyme API-Anforderungen" + yaxis: "Anonyme API-Anfragen" page_view_logged_in_reqs: title: "Angemeldet" xaxis: "Tag" + yaxis: "API-Anfragen mit Login" page_view_crawler_reqs: + title: "Suchmaschinen" xaxis: "Tag" + yaxis: "API-Anfragen von Suchmaschinen" page_view_total_reqs: title: "Gesamt" xaxis: "Tag" - yaxis: "Gesamte API-Anforderungen" + yaxis: "Gesamte API-Anfragen" http_background_reqs: title: "Hintergrund" xaxis: "Tag" + yaxis: "Anfragen für Live-Updates und Tracking" http_2xx_reqs: title: "Status 2xx (OK)" xaxis: "Tag" - yaxis: "Erfolgreiche Anforderungen (Status 2xx)" + yaxis: "Erfolgreiche Anfragen (Status 2xx)" http_3xx_reqs: + title: "HTTP 3xx (Weiterleitung)" xaxis: "Tag" + yaxis: "Anfragen mit Weiterleitung (Status 3xx)" http_4xx_reqs: title: "HTTP 4xx (Client-Fehler)" xaxis: "Tag" @@ -540,29 +571,33 @@ de: http_total_reqs: title: "Gesamt" xaxis: "Tag" - yaxis: "Gesamte Anforderungen" + yaxis: "Gesamte Anfragen" dashboard: rails_env_warning: "Dein Server läuft im %{env}-Modus." ruby_version_warning: "Du verwendest eine Version von Ruby 2.0.0, die für Probleme bekannt ist. Aktualisiere auf Patchlevel 247 oder höher." host_names_warning: "Deine config/database.yml-Datei verwendet localhost als Hostname. Trage hier den Hostnamen deiner Webseite ein." gc_warning: 'Dein Server verwendet die Standardparameter für Rubys Garbage-Collector, die nicht optimal sind. Lese dieses Thema über Performanzeinstellungen (en): Tuning Ruby and Rails for Discourse.' sidekiq_warning: 'Sidekiq läuft nicht. Viele Aufgaben, wie zum Beispiel das Versenden von Mails, werden asynchron durch Sidekiq ausgeführt. Stelle sicher, dass mindestens eine Sidekiq-Prozess läuft. Mehr über Sidekiq erfährst du hier (en).' - queue_size_warning: 'Es befinden sich sehr viele (%{queue_size}) Jobs in der Warteschlange. Dies könnte auf ein Problem mit Sidekiq hinweisen oder Du musst zusätzliche Sidekiq Worker starten.' + queue_size_warning: 'Es befinden sich sehr viele (%{queue_size}) Jobs in der Warteschlange. Dies könnte auf ein Problem mit Sidekiq hinweisen oder du musst zusätzliche Sidekiq Worker starten.' memory_warning: 'Dein Server läuft mit weniger als 1 GB Hauptspeicher. Mindestens 1 GB Hauptspeicher werden empfohlen.' - enable_google_logins_warning: "Du verwendest eine veraltete Version der Google OpenID Authentifikation. Google wird die Unterstützung dafür am 20. April 2015 beenden. Bitte stelle möglichst bald auf Google Oauth2 um. Eine Anleitung zu diesem Thema findet sich hier." + enable_google_logins_warning: "ACHTUNG! Die derzeit von dir genutzte Methode für die Authentifizierung mit Google wird ab dem 20. April 2015 nicht mehr unterstützt! Bitte steige möglichst bald auf die neue Methode um!" both_googles_warning: "Sowohl enable_google_logins als auch enable_google_oauth2_logins sind in den Einstellungen aktiviert. Bitte deaktiviere enable_google_logins." - google_oauth2_config_warning: 'Der Server ist für Anmeldung und Login mit Google OAuth2 (enable_google_oauth2_logins) konfiguriert, aber die Client ID und das Client Gemeheimnis sind nicht gesetzt. Trage diese in den Einstellung ein. Eine Anleitung zu diesem Thema findet sich hier.' + google_oauth2_config_warning: 'Der Server ist für Anmeldung und Login mit Google OAuth2 (enable_google_oauth2_logins) konfiguriert, aber die Client-ID und das Client-Gemeheimnis sind nicht gesetzt. Trage diese in den Einstellung ein. Eine Anleitung zu diesem Thema findest du hier.' facebook_config_warning: 'Der Server erlaubt die Anmeldung mit Facebook (enable_facebook_logins), aber die App ID und der Geheimcode sind nicht gesetzt. Besuche die Einstellungen um die fehlenden Einträge hinzuzufügen. Besuche den Leitfaden um mehr zu erfahren.' - twitter_config_warning: 'Der Server erlaubt die Anmeldung mit Facebook Twitter (enable_twitter_logins), aber der Schlüssel und der Geheimcode sind nicht gesetzt. Besuche die Einstellungen um die fehlenden Einträge hinzuzufügen. Besuche den Leitfaden um mehr zu erfahren.' - github_config_warning: 'Der Server erlaubt die Anmeldung mit Facebook GitHub (enable_github_logins), aber die Kunden ID und der Geheimcode sind nicht gesetzt. Besuche die Einstellungen um die fehlenden Einträge hinzuzufügen. Besuche den Leitfaden um mehr zu erfahren.' + twitter_config_warning: 'Der Server erlaubt die Anmeldung mit Twitter (enable_twitter_logins), aber der Schlüssel und der Geheimcode sind nicht gesetzt. Besuche die Einstellungen um die fehlenden Einträge hinzuzufügen. Besuche den Leitfaden um mehr zu erfahren.' + github_config_warning: 'Der Server erlaubt die Anmeldung mit Facebook GitHub (enable_github_logins), aber die Kunden-ID und der Geheimcode sind nicht gesetzt. Besuche die Einstellungen um die fehlenden Einträge hinzuzufügen. Besuche den Leitfaden um mehr zu erfahren.' s3_config_warning: 'Der Server wurde konfiguriert um Dateien nach s3 hochzuladen, aber mindestens der folgenden Einstellungen fehlt: s3_access_key_id, s3_secret_access_key oder s3_upload_bucket. Besuche die Einstellungen um die fehlenden Einträge hinzuzufügen. Besuche "How to set up image uploads to S3?" um mehr zu erfahren.' s3_backup_config_warning: 'Der Server ist so konfiguriert, dass Datensicherungen auf S3 geladen werden, aber mindestens einer der folgenden Einstellungen: s3_access_key_id, s3_secret_access_key or s3_backup_bucket ist nicht festgelegt. Gehe Sie zu den Seiteneinstellungen und aktualisieren Sie die Einstellungen. Siehe "Wie konfiguriere ich das Hochladen von Bildern zu S3?" um mehr darüber zu erfahren.' image_magick_warning: 'Der Server wurde konfiguriert um Vorschaubilder von grossen Bildern zu erstellen, aber ImageMagick ist nicht installiertd. Installiere ImageMagick mit deinem bevorzugten Packetmanager oder besuche um das aktuelle Paket herunterzuladen.' failing_emails_warning: 'Es konnten insgesamt %{num_failed_jobs} Mails nicht versendet werden. Bitte überprüfe die Mailserver-Einstellungen in config/discourse.conf. Siehe auch: Fehlgeschlagene Jobs in Sidekiq.' default_logo_warning: "Richte das Logo für deine Seite ein. Konfiguriere dafür logo_url, logo_small_url, und favicon_url unter Website-Einstellungen." + contact_email_missing: "Gib eine Kontakt-E-Mail-Adresse an, damit du dringende Meldungen bezüglich deiner Seite erhalten kannst. Trage sie in den Einstellungen ein." + contact_email_invalid: "Die Kontakt E-Mail-Adresse ist ungültig. Ändere sie in den Einstellungen." title_nag: "Gib einen Namen für deine Website ein. Aktualisiere dazu den „title“ in den Einstellungen." site_description_missing: "Gib eine kurze Beschreibung deiner Website ein, die in Suchergebnissen angezeigt werden soll. Aktualisiere dazu die „site_description“ in den Einstellungen." consumer_email_warning: "Deine Seite verwendet Gmail (oder einen anderen für Endkunden gedachten Mailserver) um E-Mails zu versenden. Gmail hat eine Schranke bezüglich des Sendens von E-Mails. Um die E-Mail-Zustellung zu gewährleisten, solltest du die Verwendung eines anderen E-Mail-Diensts in Erwägung ziehen." + site_contact_username_warning: "Gib den Benutzernamen eines Mitarbeiters an, in dessen Namen wichtige, automatisch erzeugte private Nachrichten gesendet werden sollen. Ändere site_contact_username in den Einstellungen." + notification_email_warning: "Benachrichtigungs-E-Mails werden nicht von einer gültigen, zu deiner Domain gehörenden E-Mail-Adresse versandt; der E-Mail-Versand wird unberechenbar und unzuverlässig sein. Bitte trage in den Einstellungen unter notification_email eine gültige lokale E-Mail-Adresse ein." content_types: education_new_reply: title: "Hilfe: Erste Beiträge" @@ -595,7 +630,7 @@ de: title: "Unterer Teil der Seiten" description: "HTML das vor dem Tag eingefügt wird." site_settings: - censored_words: "Wörter, die automatisch durch■■■■ ersetzt werden" + censored_words: "Wörter, die automatisch durch ■■■■ ersetzt werden" delete_old_hidden_posts: "Automatisch alle Beiträge löschen, die länger als 30 Tage versteckt bleiben." default_locale: "Die Standardsprache dieser Discourse-Instanz (kodiert in ISO 639-1)." allow_user_locale: "Erlaube Benutzern ihre eigene Interfacesprache zu wählen" @@ -611,7 +646,10 @@ de: allow_duplicate_topic_titles: "Erlaube Themen mit identischen und doppelten Titeln." unique_posts_mins: "Minuten, nach denen ein Nutzer denselben Inhalt noch einmal posten kann." educate_until_posts: "Zeige das Hilfe-Panel im Editor sobald ein Nutzer einen seiner ersten (n) Beiträge zu schreiben beginnt." + title: "Der Name dieser Seite, wird für das Title-Tag verwendet." + site_description: "Beschreibe diese Seite in einem Satz. Wird für das \"description\" Meta-Tag verwendet." contact_email: "Die E-Mail-Adresse des Hauptverantwortlichen dieser Seite. Wird verwendet um kritische Benachrichtigungen wie beispielsweise unbearbeitete Meldungen, als auch solche die via /about Kontaktformular eintreffen. " + contact_url: "URL für Kontaktanfragen bezüglich dieser Seite. Wird unter /about im Kontaktformular für dringende Angelegenheiten verwendet." queue_jobs: "NUR FÜR ENTWICKLER! ACHTUNG! Benutze Sidekiq zur Ausführung von Jobs. Wenn dies abgeschaltet wird, dann wird die Seite nicht mehr richtig funktionieren!" crawl_images: "Lade Bilder von fremden URLs herunter, um ihre Höhe und Breite zu bestimmen." download_remote_images_to_local: "Lade eine Kopie von extern gehosteten Bildern herunter und ersetze Links in Beiträgen entsprechend; dies verhindert defekte Bilder." @@ -626,13 +664,16 @@ de: category_featured_topics: "Anzahl der angezeigten Themen je Kategorie auf der Kategorieseite /categories. Nachdem dieser Wert geändert wurde, dauert es bis zu 15 Minuten bis die Kategorieseite aktualisiert ist." show_subcategory_list: "Zeige Liste von Unterkategorien statt einer Liste von Themen wenn eine Kategorie ausgewählt wird." fixed_category_positions: "Falls aktiviert können Kategorien in einer fest vorgegebenen Reihenfolge angeordnet werden. Andernfalls werden Kategorien nach Aktivität sortiert aufgelistet." - add_rel_nofollow_to_user_content: "Füge mit Ausnahme interner Links allen nutzergenerierten Inhalten 'rel nofollow' hinzu (inkludiert übergeordnete Domains). Die Änderung dieser Einstellung erfordert, dass Du sämtliche Markdown-Beiträge aktualisierst." + add_rel_nofollow_to_user_content: "Füge mit Ausnahme interner Links allen nutzergenerierten Inhalten 'rel nofollow' hinzu (inkludiert übergeordnete Domains). Die Änderung dieser Einstellung erfordert, dass du sämtliche Markdown-Beiträge aktualisierst." exclude_rel_nofollow_domains: "Liste aller Domains, durch senkrechte Striche getrennt, bei denen 'nofollow' nicht hinzugefügt wird (tld.com erlaubt auch sub.tld.com)." post_excerpt_maxlength: "Maximale Länge eines Beitrags-Auszuges bzw. -Zusammfassung." post_onebox_maxlength: "Maximale Länge eines Onebox-Discourse-Beitrags in Zeichen." onebox_domains_whitelist: "Liste von Domains, deren Inhalte für Oneboxen erlaubt sind; diese Domains sollten OpenGraph oder oEmbed unterstützen. Teste ihre Kompatibilität unter http://iframely.com/debug" + logo_url: "Die Logo-Grafik oben links auf deiner Seite; wenn leer wird der Name der Seite angezeigt." digest_logo_url: "Alternatives Logo, das oben in E-Mail-Zusammenfassungen verwendet wird. Wenn leer wird `logo_url` verwendet. Zum Beispiel: http://example.com/logo.png " + logo_small_url: "Kleine Logo-Grafik oben links auf der Seite, die beim Herunterscrollen angezeigt wird. Falls leer wird ein \"Home\" Zeichen angezeigt." favicon_url: "Das Favicon deiner Website, siehe http://de.wikipedia.org/wiki/Favicon" + mobile_logo_url: "Die statische Logo-Grafik oben links auf deiner Seite für mobile Geräte. Falls leer wird der Name der Seite angezeigt." apple_touch_icon_url: "Icon für berührungsempfindliche Apple Geräte. Empfohlene Grösse ist 144px auf 144px." notification_email: "Die E-Mail-Adresse die als \"From:\" Absender aller wichtiger System-Emails benutzt wird. Die benutzte Domain sollte über korrekte SPF, DKIM und PTR Einträge verfügen, damit Emails sicher zugestellt werden können." email_custom_headers: "Eine Pipe-getrennte (|) Liste von eigenen Mail Headern" @@ -661,20 +702,22 @@ de: notify_mods_when_user_blocked: "Wenn ein Benutzer automatisch gesperrt wird, sende eine Mail an alle Moderatoren." flag_sockpuppets: "Wenn ein neuer Nutzer auf ein Thema antwortet, das von einem anderen neuen Nutzer aber mit der gleichen IP-Adresse begonnen wurde, markiere beide Beiträge als Werbung." traditional_markdown_linebreaks: "Traditionelle Zeilenumbrüche in Markdown, welche zwei nachfolgende Leerzeichen für einen Zeilenumbruch benötigen." - post_undo_action_window_mins: "Sekunden, die ein Nutzer hat, um Aktionen auf Beiträgen rückgängig zu machen (Like, Meldung, etc.)." + post_undo_action_window_mins: "Sekunden, die ein Nutzer hat, um Aktionen auf Beiträgen rückgängig zu machen (Like, Meldung, usw.)." must_approve_users: "Alle neuen Benutzerkonten müssen von Mitarbeitern freigeschaltet werden, bevor sie Zugriff auf die Seite erhalten." ga_tracking_code: "Google Analytics Trackingcode, zum Beispiel: UA-12345678-9; siehe http://google.com/analytics" ga_domain_name: "Google Analytics Domänenname, zum Beispiel: mysite.com; siehe http://google.com/analytics" ga_universal_tracking_code: "Google Universal Analytics (analytics.js) tracking code code, beispielsweise: UA-12345678-9; Siehe http://google.com/analytics" ga_universal_domain_name: "Google Universal Analytics (analytics.js) domain name, eg: mysite.com; Siehe http://google.com/analytics" enable_escaped_fragments: "Verwende Googles API für Ajax-Crawling, falls kein Webcrawler erkannt werden kann. Siehe dazu auch https://support.google.com/webmasters/answer/174992?hl=en" - enable_noscript_support: "Aktiviere standard Suchmaschinen-Webcrawler Unterstützung durch den noscript Tag" + enable_noscript_support: "Aktiviere Standard-Suchmaschinen-Webcrawler-Unterstützung durch den noscript-Tag" allow_moderators_to_create_categories: "Erlaube Moderatoren neue Kategorien zu erstellen" cors_origins: "Erlaubte Adressen für Cross-Origin-Requests (CORS). Jede Adresse muss http:// oder https:// enthalten. Die Umgebungsvariable DISCOURSE_ENABLE_CORS muss gesetzt sein, um CORS zu aktivieren." + top_menu: "Bestimme, welche Elemente in der Navigationsleiste der Homepage auftauchen sollen, und in welcher Reihenfolge. Beispiel: latest|new|unread|categories|top|read|posted|bookmarks" post_menu: "Bestimme, welche Funktionen in welcher Reihenfolge im Beitragsmenü auftauchen. Beispiel: like|edit|flag|delete|share|bookmark|reply" post_menu_hidden_items: "Die Einträge im Menü eines Beitrags, die standardmäßig hinter einer erweiterbaren Ellipse versteckt werden sollen." share_links: "Bestimme, welche Dienste in welcher Reihenfolge im Teilen-Dialog auftauchen." track_external_right_clicks: "Verfolge, welche externen Links per Rechtsklick geöffnet werden (zum Beispiel in einem neuen Browser-Tab). Standardmäßig deaktiviert, da dies URL-Rewrites erfordert." + site_contact_username: "Benutzername eines Mitarbeiters, in dessen Namen alle automatisch erzeugten privaten Nachrichten versendet werden sollen. Falls leer wird das Standardkonto \"system\" verwendet." send_welcome_message: "Sende allen neuen Nutzern eine private Willkommensnachricht mit Hinweisen zur Benutzung des Forums." suppress_reply_directly_below: "Zeige die erweiterbare Anzahl der Antworten auf einen Beitrag nicht, falls die einzige Antwort direkt darunter folgt." suppress_reply_directly_above: "Verstecke das erweiterbare „Antwort auf“-Feld in einem Beitrag, wenn der beantwortete Beitrag direkt darüber angezeigt wird." @@ -692,6 +735,7 @@ de: email_domains_blacklist: "Eine Liste von E-Mail-Domains, die bei der Registrierung neuer Konten nicht erlaubt sind. Beispiel: mailinator.com trashmail.net" email_domains_whitelist: "Eine Liste von E-Mail-Domains, mit denen neue Konten registriert werden dürfen. ACHTUNG: Benutzer mit E-Mail-Adressen anderer Domains können sich dann nicht mehr registrieren!" forgot_password_strict: "Benutzer nicht über das Vorhandensein von Konten informieren, wenn sie den \"„Passwort vergessen“-Dialog verwenden." + log_out_strict: "Beim Abmelden ALLE Sitzungen des Benutzers auf allen Geräten beenden" version_checks: "Kontaktiere den Discourse Hub zur Überprüfung auf neue Versionen und zeige Benachrichtigungen über neue Versionen auf der Administratorkonsole an." new_version_emails: "Sende eine E-Mail an contact_email Adresse wenn eine neue Version von Discourse verfügbar ist." port: "NUR FÜR ENTWICKLER! ACHTUNG! Benutze diesen HTTP-Port anstatt den Standardport 80. Diese Feld leer lassen heißt 'keinen'. Dient hauptsächlich Entwicklungszwecken." @@ -704,27 +748,30 @@ de: max_username_length: "Maximale Länge für Benutzernamen in Zeichen. WARNUNG: EXISTIERENDE BENUTZER, DEREN BENUTZERNAMEN LÄNGER SIND, WERDEN DIE WEBSITE NICHT MEHR BENUTZEN KÖNNEN." min_password_length: "Minimale Länge des Passworts." block_common_passwords: "Erlaube kein Passwort unter den 10000 meist verwendeten Passwörter." + enable_sso: "Aktiviere Single-Sign-On mittels einer externen Seite (ACHTUNG: kann bei fehlerhafter Konfiguration die Anmeldung aller Benutzer unmöglich machen, DICH SELBST EINGESCHLOSSEN! Deaktiviert außerdem Einladungen.)" + enable_sso_provider: "Aktiviere das Discourse SSO Anbieter Protokoll unter /session/sso_provider; benötigt sso_secret." sso_url: "URL des Single Sign On Endpunkts" + sso_secret: "Geheime Zeichenkette die als Schlüssel für die Authentifizierung von SSO-Informationen verwendet wird. Sollte unbedingt 10 Zeichen oder länger sein." sso_overrides_email: "Überschreibt lokale mit externer E-Mail-Adresse aus den SSO Daten (WARNUNG: es können dennoch Unterschiede auf Grund von Normalisierung lokaler E-Mail-Adressen auftreten)" sso_overrides_username: "Überschreibt lokale Benutzernamen mit externen Seiten-Usernamen von SSO Daten (WARNUNG: Diskrepanzen können aufgrund von Unterschieden in Benutzernamenlängen/-anforderungen, auftreten)" sso_overrides_name: "Überschreibt lokalen Namen mit Namen der externen Seite aus SSO Daten (WARNUNG: Diskrepanzen können aufgrund von Normalisierung von lokalen Namen auftreten)" sso_overrides_avatar: "Überschreibt den Avatar des Benutzers mit dem Avatar aus der SSO Payload. Wenn aktiv, dann sollte allow_uploaded_avatars deaktiviert werden." enable_local_logins: "Aktiviere Login mit lokal gespeicherten Benutzernamen und Passwörtern. (Anmerkung: muss aktiviert sein, damit Einladungen funktionieren)" allow_new_registrations: "Erlaube das Registrieren neuer Benutzerkonten. Wird dies deaktiviert, so kann niemand mehr ein neues Konto erstellen." - enable_google_logins: "(Veraltet) Google-Authentifikation aktivieren. Dies verwendet OpenID zur Authentifikation und wurde von Google für veraltet erklärt. Neue Installationen werden hiermit NICHT funktionieren; benutze statt dessen Google Oauth2. Existierende Installationen müssen bis 20. April 2015 auf Google Oauth2 umsteigen." - enable_yahoo_logins: "Aktiviere Yahoo Authentisierung." - enable_google_oauth2_logins: "Google Oauth2-Authentifikation aktivieren. Dies ist der momentan von Google unterstützte Authentifikations-Mechanismus. Benötigt Client-ID und Secret." - google_oauth2_client_id: "Client-ID Deiner Google Anwendung." - google_oauth2_client_secret: "Secret Deiner Google Anwendung." - enable_twitter_logins: "Aktiviere Twitter Authentisierung (benötigt twitter_consumer_key und twitter_consumer_secret)." - twitter_consumer_key: "Consumer Key für Twitter Authentisierung, registriert auf http://dev.twitter.com" - twitter_consumer_secret: "Consumer Secret für Twitter Authentisierung, registriert auf http://dev.twitter.com" - enable_facebook_logins: "Aktiviere Facebook Authentisierung (benötigt facebook_app_id und facebook_app_secret)." - facebook_app_id: "App-ID für Facebook Authentisierung, registriert auf https://developers.facebook.com/apps" - facebook_app_secret: "App Secret für Facebook Authentisierung, registriert auf https://developers.facebook.com/apps" - enable_github_logins: "Aktiviere Github Authentisierung (benötigt github_client_id und github_client_secret)." - github_client_id: "Client-ID für Github Authentisierung, registriert auf https://github.com/settings/applications" - github_client_secret: "Client Secret für Github Authentisierung, registriert auf https://github.com/settings/applications" + enable_google_logins: "(Veraltet) Google-Authentifizierung aktivieren. Dies verwendet OpenID zur Authentifizierung und wurde von Google für veraltet erklärt. Neue Installationen werden hiermit NICHT funktionieren; benutze statt dessen Google Oauth2. Existierende Installationen müssen bis 20. April 2015 auf Google Oauth2 umsteigen." + enable_yahoo_logins: "Aktiviere Yahoo Authentifizierung." + enable_google_oauth2_logins: "Google Oauth2-Authentifizierung aktivieren. Dies ist der momentan von Google unterstützte Authentifizierungs-Mechanismus. Benötigt Client-ID und Secret." + google_oauth2_client_id: "Client-ID deiner Google-Anwendung." + google_oauth2_client_secret: "Client-Secret deiner Google-Anwendung." + enable_twitter_logins: "Aktiviere Twitter Authentifizierung (benötigt twitter_consumer_key und twitter_consumer_secret)." + twitter_consumer_key: "Consumer Key für Twitter Authentifizierung, registriert auf http://dev.twitter.com" + twitter_consumer_secret: "Consumer Secret für Twitter Authentifizierung, registriert auf http://dev.twitter.com" + enable_facebook_logins: "Aktiviere Facebook Authentifizierung (benötigt facebook_app_id und facebook_app_secret)." + facebook_app_id: "App-ID für Facebook Authentifizierung, registriert auf https://developers.facebook.com/apps" + facebook_app_secret: "App Secret für Facebook Authentifizierung, registriert auf https://developers.facebook.com/apps" + enable_github_logins: "Aktiviere Github Authentifizierung (benötigt github_client_id und github_client_secret)." + github_client_id: "Client-ID für Github Authentifizierung, registriert auf https://github.com/settings/applications" + github_client_secret: "Client Secret für Github Authentifizierung, registriert auf https://github.com/settings/applications" allow_restore: "Wiederherstellung zulassen, welche ALLE vorhandenen Daten überschreiben kann! Auf 'false' lassen, sofern Sie nicht planen, eine Sicherung wiederherzustellen." maximum_backups: "Die maximale Anzahl an Sicherungen, die auf dem Server gespeichert werden. Ältere Sicherungen werden automatisch gelöscht." backup_daily: "Jeden Tag automatisch eine Sicherung erstellen." @@ -746,11 +793,13 @@ de: max_invites_per_day: "Maximale Zahl an Einladungen, die ein Nutzer pro Tag verschicken kann." suggested_topics: "Anzahl der empfohlenen Themen am Ende eines Themas." limit_suggested_to_category: "Zeige nur Themen der aktuellen Kategorie in vorgeschlagenen Themen." - clean_up_uploads: "Lösche verwaiste Uploads, um illegales Hosting zu vermeiden. ACHTUNG: Du solltest ein Backup deines /uploads Verzeichnisses erstellen, bevor Du diese Funktion aktivierst." + clean_up_uploads: "Lösche verwaiste Uploads, um illegales Hosting zu vermeiden. ACHTUNG: du solltest ein Backup deines /uploads-Verzeichnis erstellen, bevor du diese Funktion aktivierst." clean_orphan_uploads_grace_period_hours: "Schonfrist (in Stunden), bevor ein verwaister Upload entfernt wird." purge_deleted_uploads_grace_period_days: "Schonfrist (in Tagen), bevor ein entfernter Upload endgültig gelöscht wird." purge_unactivated_users_grace_period_days: "Schonfrist (in Tagen), bevor ein Benutzer, der sein Konto nicht aktiviert hat, gelöscht wird." + enable_s3_uploads: "Speichere hochgeladene Dateien auf Amazon S3. WICHTIG: benötigt gültige S3 Anmeldedaten (sowohl access_key_id als auch secret_access_key)." s3_use_iam_profile: 'Benutze die AWS EC2 IAM Rolle zum Abrufen von Keys. ANMERKUNG: Das Aktivieren überschreibt die Einstellungen „s3 access key id“ und „s3 secret access key“.' + s3_upload_bucket: "Der Name des Amazon S3 Buckets, in dem hochgeladene Dateien gespeichert werden sollen. ACHTUNG: nur Kleinbuchstaben, keine Punkte, keine Unterstriche." s3_access_key_id: "The Amazon S3 access key id that will be used to upload images" s3_secret_access_key: "Der geheime Schlüssel von Amazon S3 welcher für das Hochladen verwendet wird" s3_region: "Der Name der Amazon S3 Region welche für das Hochladen verwendet wird" @@ -773,6 +822,11 @@ de: tl3_requires_posts_read: "Prozentualer Anteil aller Beiträge der letzten 100 Tage, die ein Nutzer mindestens gelesen haben muss, um die Vertrauensstufe Anführer (3) erreichen zu können. (0 bis 100)" tl3_requires_topics_viewed_all_time: "Mindestanzahl Themen, die ein Nutzer gelesen haben muss, um die Vertrauensstufe Anführer (3) erreichen zu können." tl3_requires_posts_read_all_time: "Mindestanzahl Beiträge, die ein Nutzer gelesen haben muss, um die Vertrauensstufe Anführer (3) erreichen zu können." + tl3_requires_max_flagged: "Um die Vertrauensstufe 3 erhalten zu können dürfen in den letzten 100 Tagen höchstens X Beiträge eines Nutzers von X verschiedenen anderen Nutzern gemeldet worden sein, wobei X diesem Wert entspricht. (0 oder mehr)" + tl3_promotion_min_duration: "Mindestanzahl an Tagen, die ein Benutzer auf Vertrauensstufe 3 beförderter Nutzer auf dieser Stufe verbleibt, bevor er automatisch wieder auf Vertrauensstufe 2 heruntergestuft werden kann." + tl3_requires_likes_given: "Die Mindestanzahl an \"Likes\" die Sie in den letzten 100 Tagen gegeben haben müssen um für Vertrauenslevel 3 zu qualifizieren." + tl3_requires_likes_received: "Die Mindestanzahl an \"Likes\" die Sie in den letzten 100 Tagen erhalten haben müssen um für Vertrauenslevel 3 zu qualifizieren." + tl3_links_no_follow: "rel=nofollow nicht von Links entfernen, die von Benutzern mit Vertrauensstufe 3 erstellt wurden." min_trust_to_create_topic: "Die minimale Vertrauensstufe wird benötigt um eine neues Thema zu erstellen." min_trust_to_edit_wiki_post: "Die minimal benötigte Vertrauensstufe, um als Wiki markierte Beiträge bearbeiten zu können." newuser_max_links: "Maximale Anzahl der Links, die neue Benutzer Beiträgen hinzufügen dürfen." @@ -792,24 +846,46 @@ de: min_title_similar_length: "Minimale Länge eines Titels, bevor nach ähnlichen Titeln gesucht wird." min_body_similar_length: "Minimale Länge eines Beitragstextes, bevor nach ähnlichen Themen gesucht wird." category_colors: "Liste hexadezimaler Farbwerte, die als Kategoriefarben erlaubt sind." + category_style: "Visueller Stil für Kategorie-Abzeichen." max_image_size_kb: "Maximale Größe eines hochgeladenen Bilds in kB. Dieser Wert muss auch in Nginx (client_max_body_size), Apache oder anderen Proxies entsprechend konfiguriert werden." max_attachment_size_kb: "Maximale Größe hochgeladener Dateianhänge in kB. Dieser Wert muss auch in Nginx (client_max_body_size), Apache oder anderen Proxies entsprechend konfiguriert werden." authorized_extensions: "Liste von erlaubten Dateiendungen für hochgeladene Dateien ('*' um alle Dateiendungen zu erlauben)" max_similar_results: "Anzahl ähnlicher Themen, die beim Erstellen eines neuen Themas über dem Editor angezeigt werden. Ähnlichkeit wird an Hand des Titels und Inhalts bestimmt." title_prettify: "Verhindert gängige Fehler im Titel, wie reine Grossschreibung, Kleinbuchstaben am Anfang, mehrere ! und ?, überflüssiger . am Ende, etc." - faq_url: "URL zu einer externen FAQ welche Du gerne verwenden möchtest." + topic_views_heat_low: "Aufrufe-Feld leicht hervorheben, sobald das Thema so oft gelesen wurde." + topic_views_heat_medium: "Aufrufe-Feld mäßig hervorheben, sobald das Thema so oft gelesen wurde." + topic_views_heat_high: "Aufrufe-Feld stark hervorheben, sobald das Thema so oft gelesen wurde." + cold_age_days_low: "Aktivitäts-Feld leicht hervorheben, wenn das Thema so viele Tage alt ist." + cold_age_days_medium: "Aktivitäts-Feld mäßig hervorheben, wenn das Thema so viele Tage alt ist." + cold_age_days_high: "Aktivitäts-Feld stark hervorheben, wenn das Thema so viele Tage alt ist." + history_hours_low: "Bearbeitungs-Symbol leicht hervorheben, wenn der Beitrag innerhalb so vieler Stunden nach Erstellen bearbeitet wird." + history_hours_medium: "Bearbeitungs-Symbol mäßig hervorheben, wenn der Beitrag innerhalb so vieler Stunden nach Erstellen bearbeitet wird." + history_hours_high: "Bearbeitungs-Symbol stark hervorheben, wenn der Beitrag innerhalb so vieler Stunden nach Erstellen bearbeitet wird." + topic_post_like_heat_low: "Feld für Anzahl der Antworten leicht hervorheben, wenn das Verhältnis von Likes zu Antworten diesen Wert übersteigt." + topic_post_like_heat_medium: "Feld für Anzahl der Antworten mäßig hervorheben, wenn das Verhältnis von Likes zu Antworten diesen Wert übersteigt." + topic_post_like_heat_high: "Feld für Anzahl der Antworten stark hervorheben, wenn das Verhältnis von Likes zu Antworten diesen Wert übersteigt." + faq_url: "Vollständige URL zu einer externen FAQ, welche du gerne verwenden möchtest." tos_url: "Die vollständige URL zu Deinen extern gehosteten Nutzungsbedingungen, sofern vorhanden." privacy_policy_url: "Die vollständige URL zu Deinen extern gehosteten Datenschutzrichtlinien, sofern vorhanden." newuser_spam_host_threshold: "Die Anzahl welche ein Frischling Beiträge mit Links auf die gleiche Seite innerhalb ihrer `newuser_spam_host_posts` veröffentlichen, bevor der Beitrag als Spam klassifiziert wird." white_listed_spam_host_domains: "Liste von Domänen, die keinem Spam-Host Test unterzogen werden. Neue Benutzer werden niemals daran gehindert, Beiträge mit Links zu diesen Domains zu erstellen." staff_like_weight: "Zusätzlicher Gewichtungsfaktor für \"Gefällt mir\" Wertungen von Mitarbeitern." + topic_view_duration_hours: "Alle N Stunden einen Themenaufruf pro IP/Benutzer zählen." levenshtein_distance_spammer_emails: "E-Mail-Adressen, die sich um so viele Zeichen unterscheiden, werden beim Vergleich von Adressen von Spam-Nutzern dennoch als identisch betrachtet." + max_new_accounts_per_registration_ip: "Keine neuen Registrierungen von einer IP-Adresse annehmen, zu der bereits (n) Benutzerkonten mit Vertrauensstufe 0 (und keine Konten von Mitarbeitern oder mit Vertrauensstufe 2 oder höher) gehören." + max_age_unmatched_emails: "Gefilterte E-Mail-Adressen nach (N) Tagen ohne Treffer löschen." + max_age_unmatched_ips: "Gefilterte IP-Adressen nach (N) Tagen ohne Treffer löschen." + num_flaggers_to_close_topic: "Mindestanzahl unabhängiger Mitglieder die ein Thema \"flaggen\" damit es automatisch pausiert wird bis es geprüft wurde." + num_flags_to_close_topic: "Mindestanzahl aktiver \"Flags\" die notwendig sind um ein Thema automatisch zu pausieren bis es geprüft wird." + auto_respond_to_flag_actions: "Automatische Antwort auf abgearbeitete Meldungen aktivieren." reply_by_email_enabled: "Aktviere das Antworten auf Themen via E-Mail." reply_by_email_address: "Vorgabe der Antwort-Mail Adresse in der Form von: %{reply_key}@reply.myforum.com" disable_emails: "Discourse daran hindern, jegliche Art von Emails zu verschicken" + strip_images_from_short_emails: "Entferne Bilder aus E-Mails kleiner als 2800 Bytes." short_email_length: "Kurze E-Mail-Länge in Bytes" pop3_polling_enabled: "E-Mail-Antworten über POP3 abholen." pop3_polling_ssl: "SSL für die Verbindung zum POP3-Server verwenden. (Empfohlen)" + pop3_polling_period_mins: "Intervall in Minuten zum Abholen neuer E-Mails vom POP3-Konto. HINWEIS: benötigt Neustart." pop3_polling_port: "Der Port für die POP3-Anfrage." pop3_polling_host: "Der Host für die POP3-Anfrage nach E-Mails." pop3_polling_username: "Der Benutzername für das POP3-Konto zum Abfragen von E-Mails." @@ -826,28 +902,36 @@ de: email_editable: "Erlaube Benutzern ihre E-Mail-Adresse nach der Registrierung zu ändern." logout_redirect: "Ziel für Weiterleitung nach einem Logout (z. B.: http://somesite.com/logout)" allow_uploaded_avatars: "Erlaube das Hochladen benutzerdefinierter Avatare." - allow_animated_avatars: "Erlaube den Benutzern animierte GIFs als Avatar zu benutzen. ACHTUNG: Wenn Du diese Einstellung änderst, solltest Du den Rake-Task avatars:refresh ausführen." + allow_animated_avatars: "Erlaube den Benutzern animierte GIFs als Avatar zu benutzen. ACHTUNG: Wenn du diese Einstellung änderst, solltest du den Rake-Task avatars:refresh ausführen." allow_animated_thumbnails: "Generiert animierte Vorschaubilder von animierten gifs." + default_avatars: "URLs zu Bildern, die als Standard-Avatare verwendet werden sollen, bis neue Nutzer ihren Avatar geändert haben." automatically_download_gravatars: "Avatare von Gravatar herunterladen, wenn ein Nutzer sich registriert oder seine E-Mail-Adresse ändert." digest_topics: "Maximale Anzahl von Themen, die in der E-Mail-Zusammenfassung angezeigt werden." digest_min_excerpt_length: "Minimale Länge des Auszugs aus einem Beitrag in der E-Mail-Zusammenfassung, in Zeichen." default_digest_email_frequency: "Wie oft man Zusammenfassungen per Mail standardmässig erhält. Diese Einstellung kann von jedem geändert werden." + suppress_digest_email_after_days: "Sende keine E-Mail-Zusammenfassungen an Benutzer, die die Seite seit mehr als (n) Tagen nicht mehr besucht haben." + disable_digest_emails: "E-Mail-Zusammenfassungen für alle Benutzer deaktivieren." default_external_links_in_new_tab: "Öffne externe Links in einem neuen Tab. Benutzer können dies in ihren Einstellungen ändern." detect_custom_avatars: "Ob überprüft wird, dass Benutzer benutzerdefinierte Avatare hochgeladen haben." max_daily_gravatar_crawls: "Wie oft pro Tag Discourse höchstens auf Gravatar nach benuterdefinierten Avataren suchen soll." + public_user_custom_fields: "Liste selbst definierter Profil-Felder, die öffentlich angezeigt werden dürfen." + staff_user_custom_fields: "Liste selbst definierter Profil-Felder, die Mitarbeitern angezeigt werden dürfen." allow_profile_backgrounds: "Erlaube Benutzern Profilhintergründe hochzuladen." sequential_replies_threshold: "Anzahl von Beiträgen, die ein Benutzer in einem Thema am Stück schreiben darf, bevor er eine Erinnerung bezüglich zu vieler aufeinanderfolgender Antworten erhält." enable_mobile_theme: "Mobilgeräte verwenden eine mobile Darstellung mit der Möglichkeit zur vollständigen Seite zu wechseln. Deaktiviere diese Option, wenn du ein eigenes Full-Responsive-Stylesheet verwenden möchtest." dominating_topic_minimum_percent: "Anteil der Nachrichten eines Themas in Prozent, die ein einzelner Nutzer verfassen darf, bevor dieser Nutzer darauf hingewiesen wird, dass er dieses Thema dominiert." suppress_uncategorized_badge: "Zeige kein Abzeichen für unkategorisierte Themen in der Themenliste." global_notice: "Zeigt allen Besuchern eine DRINGENDE NOTFALL-NACHRICHT als global sichtbares Banner an. Deaktiviert bei leerer Nachricht. (HTML ist erlaubt.)" + disable_edit_notifications: "Unterdrückt Bearbeitungshinweise durch den System-Nutzer, wenn die 'download_remote_images_to_local' Einstellung aktiviert ist." + enable_names: "Zeigt den vollen Namen eines Benutzers auf dem Profil, der Benutzerkarte und in E-Mails an. Wenn deaktiviert wird der volle Name überall ausgeblendet." display_name_on_posts: "Zeige zusätzlich zum @Benutzernamen auch den vollen Namen des Benutzers bei seinen Beiträgen." invites_per_page: "Anzahl an Einladungen, die auf der Benutzerseite angezeigt werden." short_progress_text_threshold: "Sobald die Anzahl an Beiträgen in einem Thema diese Nummer übersteigt, zeigt der Fortschrittsbalken nur noch die aktuelle Beitragsnummer. Dieser Wert sollte angepasst werden, falls die die Breite des Fortschrittsbalkens verändert wird." default_code_lang: "Standard Syntax Highlighting, dass auf GitHub Code Blöcke angewendet wird. (lang-auto, ruby, python etc.)" warn_reviving_old_topic_age: "Wenn jemand beginnt auf ein Thema zu antworten, dessen letzte Antwort älter als diese Anzahl an Tagen ist, wird eine Warnung angezeigt. Deaktiviere dies durch setzen auf 0." autohighlight_all_code: "Erzwinge Syntaxhervorhebung für alle Quellcode-Blöcke, auch dann wenn keine Sprache angeben wurde." - embeddable_host: "Host der Kommentare aus diesem Discourse Forum einbetten kann." + highlighted_languages: "Es wurden Syntaxregeln zur Hervorhebung von Textstellen hinzugefügt. (Achtung: Werden zu viele Sprachen hinzugefügt, kann das die Performance beeinflussen) siehe: https://highlightjs.org/static/demo/ für eine Demo." + embeddable_host: "Host, der Kommentare aus diesem Discourse Forum einbetten darf. Nur Hostname ohne http://" feed_polling_enabled: "NUR WENN EINGEBETTET: Bestimmt, ob Inhalte eines RSS-/ATOM-Feeds als zusätzliche Beiträge dargestellt werden." feed_polling_url: "NUR WENN EINGEBETTET: URL des einzubettenden RSS-/ATOM-Feeds." embed_by_username: "Discourse-Benutzername des Benutzers, der die eingebetteten Themen erstellt." @@ -861,8 +945,10 @@ de: enable_cdn_js_debugging: "Ermöglicht die Anzeige vollständiger Fehler auf /logs, indem alle eingebetteten JavaScripts Cross-Origin Zugriffsberechtigungen erhalten." show_create_topics_notice: "Administratoren eine Warnmeldung anzeigen, wenn im Forum weniger als 5 öffentlich sichtbare Themen existieren." vacuum_db_days: "Führe VACUUM FULL ANALYZE aus, um nach Migrationen Speicher in der Datenbank zurückzugewinnen (zum Deaktivieren auf 0 setzen)" + prevent_anons_from_downloading_files: "Nichtangemeldeten Benutzern das Herunterladen von Anhängen verbieten. WARNUNG: dies verhindert auch das Herunterladen jeglicher Ressourcen für Website-Anpassungen, die als Anhänge gespeichert wurden." enable_emoji: "Aktiviere emoji" emoji_set: "Wie magst du dein emoji?" + enforce_square_emoji: "Emojis immer mit quadratischem Seitenverhältnis darstellen." errors: invalid_email: "Ungültige E-Mail-Ad­res­se" invalid_username: "Es gibt keinen Benutzer mit diesem Nutzernamen." @@ -871,10 +957,12 @@ de: invalid_integer_max: "Der Wert kann nicht höher als %{max} sein." invalid_integer: "Der Wert muss eine Ganzzahl sein." regex_mismatch: "Wert entspricht nicht dem erforderlichen Muster." + must_include_latest: "Hauptmenü muss immer den Tab 'latest' enthalten." invalid_string: "Ungültiger Wert." invalid_string_min_max: "Anzahl der Zeichen muss zwischen %{min} und %{max} liegen." invalid_string_min: "Muss mindestens %{min} Zeichen lang sein." invalid_string_max: "Darf nicht länger als %{max} Zeichen sein." + invalid_reply_by_email_address: "Adresse muss '%{reply_key}' enthalten und sich von der Benachrichtigungs E-Mail-Adresse unterscheiden." notification_types: mentioned: "%{display_username} hat Dich in %{link} erwähnt." liked: "%{display_username} gefällt deinen Beitrag in %{link}." @@ -885,7 +973,7 @@ de: moved_post: "%{display_username} hat deinen Beitrag nach %{link} verschoben." private_message: "%{display_username} hat Dir eine private Nachricht geschickt: %{link}" invited_to_private_message: "%{display_username} hat Dich zu einem privaten Gespräch eingeladen: %{link}" - invitee_accepted: "%{display_username} hat Deine Einladung angenommen." + invitee_accepted: "%{display_username} hat deine Einladung angenommen." linked: "%{display_username} hat dich auf %{link} verlinkt" granted_badge: "Sie haben %{link} verdient" search: @@ -955,13 +1043,16 @@ de: incorrect_username_email_or_password: "Benutzername, Mailadresse oder Passwort falsch" wait_approval: "Danke fürs Registrieren. Wir werden dich benachrichtigen, sobald dein Benutzerkonto freigeschaltet wurde." active: "Dein Konto ist nun freigeschaltet und einsatzbereit." - activate_email: "

    Fast fertig! Eine E-Mail mit einem Aktivierungscode wurde an Deine Mailadresse %{email} gesendet.
    Dort findest Du die Anleitung, um Deinen Zugang zu aktivieren.

    Solltest Du die Mail nicht vorfinden, kontrolliere bitte auch den Spamverdachts-Ordner. Gegebenenfalls kannst Du Dir von hier eine weitere Aktivierungs-Mail zusenden lassen.

    " - not_activated: "Du kannst Dich noch nicht anmelden. Wir haben dir eine Aktivierungs-E-Mail geschickt. Bitte folge zunächst den Anweisungen in dieser E-Mail, um dein Konto zu aktivieren." - suspended: "Du kannst Dich bis zum %{date} nicht anmelden." - suspended_with_reason: "Du kannst Dich bis zum %{date} nicht mehr anmelden. Grund des Ausschlusses: %{reason}" + activate_email: "

    Fast fertig! Eine E-Mail mit einem Aktivierungscode wurde an Deine E-Mail-Adresse %{email} gesendet.
    Dort findest du die Anleitung, um deinen Zugang zu aktivieren.

    Solltest du die Mail nicht vorfinden, kontrolliere bitte auch den Spamverdachts-Ordner. Gegebenenfalls kannst du dir von hier eine weitere Aktivierungs-E-Mail zusenden lassen.

    " + not_activated: "Du kannst dich noch nicht anmelden. Wir haben dir eine Aktivierungs-E-Mail geschickt. Bitte folge zunächst den Anweisungen in dieser E-Mail, um dein Konto zu aktivieren." + not_allowed_from_ip_address: "Du kannst dich von dieser IP-Adresse aus nicht als %{username} anmelden." + admin_not_allowed_from_ip_address: "Du kannst dich von dieser IP-Adresse aus nicht als Administrator anmelden." + suspended: "Du kannst dich bis zum %{date} nicht anmelden." + suspended_with_reason: "Du kannst dich bis zum %{date} nicht mehr anmelden. Grund des Ausschlusses: %{reason}" errors: "%{errors}" not_available: " Nicht verfügbar. Versuche %{suggestion}?" something_already_taken: "Etwas ist schief gelaufen. Möglicherweise ist der Benutzername bereits registriert. Probiere den 'Passwort vergessen'-Link." + omniauth_error: "Entschuldigung, bei der Autorisierung deines Kontos ist ein Fehler aufgetreten. Hast du die Autorisierung möglicherweise abgelehnt?" omniauth_error_unknown: "Während des Anmeldens ist etwas schief gelaufen, bitte versuche es noch einmal." new_registrations_disabled: "Leider können derzeit keine neuen Konten registriert werden." password_too_long: "Passwörter sind beschränkt auf 200 Zeichen." @@ -984,7 +1075,7 @@ de: invite_mailer: subject_template: "%{invitee_name} hat dich zum Thema '%{topic_title}' auf %{site_domain_name} eingeladen" text_body_template: | - %{invitee_name} hat Dich dazu eingeladen, an einer Diskussion teilzunehmen: + %{invitee_name} hat dich dazu eingeladen, an einer Diskussion teilzunehmen: > **%{topic_title}** > @@ -1016,7 +1107,7 @@ de: text_body_template: | Danke, dass du der Einladung zu %{site_name} gefolgt bist - herzlich willkommen! - Klicke auf den folgenden Link und wähle ein passwort um dich wieder anzumelden: + Klicke auf den folgenden Link und wähle ein Passwort um dich wieder anzumelden: %{base_url}/users/password-reset/%{email_token} test_mailer: subject_template: "[%{site_name}] Test der Mailzustellbarkeit" @@ -1065,6 +1156,8 @@ de: one: "Eine Markierung wartet auf Bearbeitung" other: "%{count} Markierungen warten auf Bearbeitung" flag_reasons: + off_topic: "Dein Beitrag wurde als **Thema verfehlt** gemeldet: Die Community glaubt, dass er nicht zum Thema passt, wie es durch den Titel und den ersten Beitrag definiert wurde." + inappropriate: "Dein Beitrag wurde als **unangemessen** gemeldet: die Community glaubt, dass er anstößig oder beleidigend ist oder einen Verstoß gegen [die Community Richtlinien](/guidelines) darstellt." spam: "Dein Beitrag wurde als **Spam** geflaggt: Die Community denkt, dass es sich um Werbung handelt und nicht nützlich oder für das Diskussionsthema relevant ist." notify_moderators: "Die Community denkt, dass etwas an deinem Beitrag das Eingreifen eines Moderator erfordert." flags_dispositions: @@ -1077,12 +1170,37 @@ de: system_messages: post_hidden: subject_template: "Beitrag wegen Meldungen aus der Community versteckt" + text_body_template: | + Hallo, + + dies ist eine automatisch erzeugte Nachricht von %{site_name}, um dich darüber zu informieren, dass einer deiner Beiträge ausgeblendet wurde. + + %{base_url}%{url} + + %{flag_reason} + + Der Beitrag wurde ausgeblendet, da er von mehreren Mitgliedern der Community gemeldet wurde. Überlege dir daher, wie du deinen Beitrag unter Berücksichtigung dieses Feedbacks überarbeiten könntest. **Du kannst deinen Beitrag nach %{edit_delay} Minuten bearbeiten, wodurch er automatisch wieder sichtbar wird.** Dadurch erhöht sich auch deine Vertrauensstufe. + + Wird der Beitrag jedoch ein zweites Mal auf Grund von Meldungen aus der Community ausgeblendet, dann muss ein Mitarbeiter sich um diesen Fall kümmern. Dies kann weitere Konsequenzen haben, unter anderem auch eine Sperrung deines Kontos. + + Weitere Hilfestellung findest du in unseren [Community Richtlinien](%{base_url}/guidelines). welcome_user: subject_template: "Willkommen bei %{site_name}!" + text_body_template: | + Danke fürs Anmelden bei %{site_name}, sei willkommen! + + %{new_user_tips} + + Wir wünschen uns ein stets [zivilisiertes Verhalten in unserer Community](%{base_url}/guidelines). + + Viel Spaß! + + (Wenn du als neuer Benutzer unter vier Augen mit einem unserer [Mitarbeiter](%{base_url}/about) reden möchtest, antworte einfach auf diese private Nachricht.) welcome_invite: subject_template: "Willkommen bei %{site_name}!" backup_succeeded: subject_template: "Sicherung erfolgreich abgeschlossen" + text_body_template: "Backup erfolgreich durchgeführt.\nDu kannst das neue Backup unter [Admin > Backups](/admin/backups) herunterladen." backup_failed: subject_template: "Sicherung fehlgeschlagen" text_body_template: | @@ -1108,7 +1226,7 @@ de: ``` bulk_invite_succeeded: subject_template: "Masseneinladung von Benutzern erfolgreich verarbeitet" - text_body_template: "Deine Masseneinladung von Benutzern wurde erfolgreich verarbeitet, insgesamt wurden %{sent} Einladungen per Mail verschickt." + text_body_template: "Deine Masseneinladung von Benutzern wurde erfolgreich verarbeitet, insgesamt wurden %{sent} Einladungen E-per Mail verschickt." bulk_invite_failed: subject_template: "Bei der Verarbeitung der Masseneinladung von Benutzern sind Fehler aufgetreten" text_body_template: | @@ -1121,32 +1239,49 @@ de: ``` csv_export_succeeded: subject_template: "Datenexport abgeschlossen" + text_body_template: | + Deine Daten wurden erfolgreich exportiert! :dvd: + + %{file_name} (%{file_size}) + + Dieser Download-Link ist für die nächsten 48 Stunden gültig. csv_export_failed: subject_template: "Datenexport fehlgeschlagen" + text_body_template: "Entschuldigung, beim Exportieren deiner Daten trat ein Fehler auf. Bitte kontaktiere einen Mitarbeiter oder sieh in die Logs." email_reject_trust_level: - subject_template: "E-Mail-Problem -- Ungenügende Vertrauensstufe" + subject_template: "E-Mail Problem -- Vertrauensstufe nicht ausreichend" text_body_template: | Es tut uns leid, aber deine E-Mail-Nachricht an %{destination} (titled %{former_title}) hat nicht funktioniert. Du hast nicht die notwendige Vertrauensstufe, um neue Themen über diese E-Mail-Adresse zu erstellen. Wenn du glaubst, dass das ein Irrtum ist, dann kontaktiere einen Mitarbeiter. email_reject_no_account: - subject_template: "E-Mail-Problem -- Unbekannter Account" + subject_template: "E-Mail Problem -- Nutzerkonto unbekannt" text_body_template: | Es tut uns leid, aber deine E-Mail-Nachricht an %{destination} (titled %{former_title}) konnte nicht verarbeitet werden! Es ist kein Account mit dieser E-Mail-Adresse bekannt. Versuche die Nachricht von einer anderen, m Forum registrierten E-Mail-Adresse zu verschicken oder kontaktiere einen Mitarbeiter. email_reject_empty: - subject_template: "E-Mail-Problem -- Kein Inhalt" + subject_template: "E-Mail Problem -- kein Inhalt" + text_body_template: | + Entschuldigung, aber mit deiner E-Mail-Nachricht an %{destination} (mit dem Titel %{former_title}) gab es ein Problem. + + Wir konnten in deiner E-Mail keinen Inhalt finden. Bitte stelle sicher, dass deine Antwort am Beginn der E-Mail steht -- Inline-Antworten können wir leider nicht verarbeiten. + + Wenn du diese Fehlermeldung erhälst obwohl die E-Mail einen gültigen Inhalt hatte, versuche es bitte noch einmal und sende die E-Mail dabei als HTML (nicht als "Nur Text"). email_reject_parsing: - subject_template: "E-Mail-Problem -- Inhalt nicht erkannt" + subject_template: "E-Mail Problem -- Inhalt nicht erkennbar" + text_body_template: | + Entschuldigung, aber mit deiner E-Mail-Nachricht an %{destination} (mit dem Titel %{former_title}) gab es ein Problem. + + Wir konnten in der eingesandten E-Mail deine Antwort nicht finden. **Bitte stelle sicher, dass deine gesamte Antwort zu Beginn der E-Mail steht** -- Inline-Antworten können wir leider nicht verarbeiten. email_reject_post_error: - subject_template: "E-Mail-Problem -- Fehler beim Posten." + subject_template: "E-Mail Problem -- Fehler beim Posten" text_body_template: | Es tut uns leid, aber deine E-Mail-Nachricht an %{destination} (Titel: %{former_title}) hat nicht funktioniert. Mögliche Gründe sind: komplexe Formatierung, Nachricht zu lang oder zu kurz. Bitte versuche es erneut oder erstelle deinen Beitrag auf der Website, wenn der Fehler weiterhin auftritt. email_reject_post_error_specified: - subject_template: "E-Mail-Problem -- Fehler beim Posten" + subject_template: "E-Mail Problem -- Fehler beim Posten" text_body_template: | Es tut uns leid, aber deine E-Mail-Nachricht an %{destination} (Titel: %{former_title}) hat nicht funktioniert. @@ -1156,22 +1291,40 @@ de: Bitte versuch es erneut, wenn du das Problem beheben kannst. email_reject_reply_key: - subject_template: "E-Mail Problem -- Unbekannter Reply Key" + subject_template: "E-Mail Problem -- Antwort-Schlüssel unbekannt" text_body_template: | Es tut uns leid, aber die E-Mail-Nachricht an %{destination} (Titel: „%{former_title}“) hat nicht geklappt. Der angegebene Antwort-Schlüssel ist ungültig oder unbekannt. Wir wissen daher nicht auf welchen Beitrag diese E-Mail antwortet. Kontaktiere einen Mitarbeiter. email_reject_destination: - subject_template: "E-Mail Problem -- Unbekannte Adresse" + subject_template: "E-Mail Problem -- To: Adresse unbekannt" + text_body_template: | + Entschuldigung, aber mit deiner E-Mail-Nachricht an %{destination} (mit dem Title %{former_title}) gab es ein Problem. + + Keine der Empfänger-Adressen ist uns bekannt. Bitte stelle sicher, dass die Ziel-Adresse in einer "An:" Zeile steht (nicht "Cc:" oder "Bcc:") und dass du die E-Mail an die richtige Adresse schickst, die dir von unseren Mitarbeitern genannt wurde. email_reject_topic_not_found: subject_template: "E-Mail Problem -- Thema nicht gefunden" + text_body_template: | + Entschuldigung, aber mit deiner E-Mail-Nachricht an %{destination} (mit dem Title %{former_title}) gab es ein Problem. + + Das Thema ist uns nicht bekannt oder es wurde gelöscht. Wenn du glaubst, dass dies ein Irrtum ist, nimm bitte Kontakt mit einem unserer Mitarbeiter auf. email_reject_topic_closed: subject_template: "E-Mail Problem -- Thema geschlossen" + text_body_template: | + Entschuldigung, aber mit deiner E-Mail-Nachricht an %{destination} (mit dem Title %{former_title}) gab es ein Problem. + + Das Thema wurde geschlossen. Wenn du glaubst das dies ein Irrtum ist, nimm bitte Kontakt mit einem unserer Mitarbeiter auf. + email_reject_auto_generated: + subject_template: "E-Mail Problem -- automatisch erzeugte Antwort" + text_body_template: | + Entschuldigung, aber deine E-Mail-Nachricht an %{destination} (Titel: %{former_title}) hat nicht funktioniert. + + Wir nehmen keine automatisch generierten Antworten an. Wenn du glaubst dass dies ein Irrtum ist, dann kontaktiere bitte einen unserer Mitarbeiter. email_error_notification: - subject_template: "E-Mail-Problem -- POP-Authentifizierungsfehler" + subject_template: "E-Mail Problem -- Fehler bei POP-Authentifizierung" text_body_template: | Es gab einen Authentifizierungsfehler beim Abrufen von Mails vom POP-Server. - Bitte stell' sicher, dass du die POP-Zugangsdaten in [den Seiteneinstellungen](%{base_url}/admin/site_settings/category/email) korrekt konfiguriert hast. + Bitte stelle sicher, dass du die POP-Zugangsdaten in [den Seiteneinstellungen](%{base_url}/admin/site_settings/category/email) korrekt konfiguriert hast. too_many_spam_flags: subject_template: "Neues Benutzerkonto gesperrt" text_body_template: | @@ -1229,7 +1382,7 @@ de: download_remote_images_disabled: subject_template: "Download von externen Bildern deaktiviert" text_body_template: "Die `download_remote_images_to_local` Einstellung wurde deaktiviert, da das Speicherplatz Limit von `download_remote_images_threshold` erreicht wurde." - unsubscribe_link: "Wenn Du diese Mails nicht mehr erhalten möchtest, verändere deine [Benutzereinstellungen](%{user_preferences_url})." + unsubscribe_link: "Wenn du diese E-Mails nicht mehr erhalten möchtest, verändere deine [Benutzereinstellungen](%{user_preferences_url})." subject_re: "Re: " subject_pm: "[PN]" user_notifications: @@ -1309,9 +1462,9 @@ de: forgot_password: subject_template: "[%{site_name}] Passwort zurückgesetzt" text_body_template: | - Jemand hat darum gebeten, Dein Passwort auf [%{site_name}](%{base_url}) zurückzusetzen. + Jemand hat darum gebeten, dein Passwort auf [%{site_name}](%{base_url}) zurückzusetzen. - Wenn Du es nicht warst, kannst Du diese Mail einfach ignorieren. + Wenn du es nicht selbst warst, kannst du diese E-Mail einfach ignorieren. Andernfalls, besuche den folgenden Link, um ein neues Passwort zu wählen: %{base_url}/users/password-reset/%{email_token} @@ -1320,7 +1473,7 @@ de: text_body_template: | Jemand hat ein Passwort für deinen Account auf [%{site_name}](%{base_url}) beantragt. Alternativ kannst du dich mit einem unterstützen Online-Service (Google, Facebook, etc), das mit dieser validierten Emailadresse verknüpft ist, anmelden. - Wenn diese Anfrage nicht von dir kam, kannst du diese Email einfach ignorieren. + Wenn diese Anfrage nicht von dir kam, kannst du diese E-Mail einfach ignorieren. Klicke auf den folgenden Link um ein Passwort auszuwählen: %{base_url}/users/password-reset/%{email_token} @@ -1339,6 +1492,23 @@ de: %{base_url}/users/authorize-email/%{email_token} signup_after_approval: subject_template: "You've been approved on %{site_name}!" + text_body_template: | + Willkommen bei %{site_name}! + + Ein Mitarbeiter von %{site_name} hat die Registrierung deines Nutzerkontos genehmigt. + + Klicke auf den folgenden Link, um dein neues Konto zu bestätigen und zu aktivieren: + %{base_url}/users/activate-account/%{email_token} + + Wenn der obige Link nicht klickbar ist, kopiere ihn in die Adresszeile deines Web-Browsers. + + %{new_user_tips} + + Wir wünschen uns ein stets [zivilisiertes Verhalten in unserer Community](%{base_url}/guidelines). + + Viel Spaß! + + (Wenn du als neuer Benutzer unter vier Augen mit einem unserer [Mitarbeiter](%{base_url}/about) reden möchtest, antworte einfach auf diese private Nachricht.) signup: subject_template: "[%{site_name}] Aktiviere deinen neues Konto" text_body_template: | @@ -1365,12 +1535,15 @@ de: deleted: 'gelöscht' upload: edit_reason: "lokale Kopien von Bildern heruntergeladen" - unauthorized: "Entschuldigung, die Datei die Du hochladen möchtest ist nicht erlaubt (erlaubte Dateiendungen sind: %{authorized_extensions})." + unauthorized: "Entschuldigung, die Datei die du hochladen möchtest ist nicht erlaubt (erlaubte Dateiendungen sind: %{authorized_extensions})." pasted_image_filename: "Hinzugefügtes Bild" store_failure: "Hochladen von #%{upload_id} für Benutzer #%{user_id} ist fehlgeschlagen." + attachments: + too_large: "Entschuldigung, die Datei die du hochladen möchtest ist zu groß (maximale Dateigröße ist %{max_size_kb}KB)." images: + too_large: "Entschuldigung, das Bild das du hochladen möchtest ist zu groß (maximale Dateigröße ist %{max_size_kb}KB). Bitte verkleinere es und versuche es erneut." fetch_failure: "Sorry, there has been an error while fetching the image." - unknown_image_type: "Entschuldigung, aber die Datei die Du hochladen möchtest scheint kein Bild zu sein." + unknown_image_type: "Entschuldigung, aber die Datei die du hochladen möchtest scheint kein Bild zu sein." size_not_found: "Entschuldige, aber wir konnten die Grösse des Bildes nicht feststellen. Vielleicht ist das Bild defekt?" flag_reason: sockpuppet: "Ein neuer Benutzer hat ein Thema erstellt und ein anderer neuer Benutzer mit der selben IP Adresse hat darauf geantwortet. Beachte die flag_sockpuppets Einstellung." @@ -1391,6 +1564,7 @@ de: body_blank: "body ist leer" color_schemes: base_theme_name: "Basis" + about: "Über uns" guidelines: "Richtlinien" privacy: "Datenschutz" edit_this_page: "Diese Seite bearbeiten" diff --git a/config/locales/server.es.yml b/config/locales/server.es.yml index 6c2251ab21..f3b53226db 100644 --- a/config/locales/server.es.yml +++ b/config/locales/server.es.yml @@ -112,6 +112,7 @@ es: other: "Lo sentimos, los nuevos usuarios solo pueden poner %{count} enlaces en un post." spamming_host: "Lo sentimos, no puedes publicar un enlace a esa web." user_is_suspended: "A los usuarios suspendidos no se les permite publicar." + topic_not_found: "Algo ha salido mal. Tal vez este tema fue cerrado o eliminado mientras estabas mirando en él?" just_posted_that: "es demasiado parecido a lo que has publicado recientemente" has_already_been_used: "ya ha sido utilizado" invalid_characters: "contiene caracteres no válidos" @@ -599,7 +600,7 @@ es: sidekiq_warning: 'Sidekiq no está funcionando. Muchas tareas, por ejemplo el envío de correos, están realizadas desincronizadamente por sidekiq. Por favor asegúrate de que por lo menos un proceso de sidekiq está funcionando. Learn about Sidekiq here.' queue_size_warning: 'El número de tareas en espera es %{queue_size}, que es elevado. Esto podría indicar un problema con el proceso(s) de Sidekiq, o tal vez necesitas añadir más trabajadores de Sidekiq.' memory_warning: 'Tu servidor está funcionando con menos de 1 GB de memoria total. Por lo menos 1 GB de memoria es recomendado.' - enable_google_logins_warning: "Estás usando una versión próximamente obsoleta de la autenticación con OpenID de Google. Google dejará de dar soporte a OpenID el 20 de abril de 2015. Empieza a usar Google Oauth2 tan pronto como sea posible. Mira esta guía para saber más" + enable_google_logins_warning: "¡ADVERTENCIA! El soporte técnico de su actual método de autenticación de Google finalizará el 20 de abril 2015! ¡Cámbiate al nuevo método ahora!" both_googles_warning: "Has habilitado tanto enable_google_logins como enable_google_oauth2_logins en las opciones del sitio. Deshabilita enable_google_logins." google_oauth2_config_warning: 'El servidor está configurado para permitir el registro e inicio de sesión con Google OAuth2 (enable_google_oauth2_logins), pero los valores client id y client secret están vacíos. Ve a Ajustes del sitio y actualiza la configuración. Mira esta guía para saber más.' facebook_config_warning: 'El servidor está configurado para permitir crear una cuenta e ingresar utilizando Facebook (enable_facebook_logins), pero los valores id y secreto de la app no están configurados. Ingresa a la Configuración del Sitio y actualiza la configuración. Revisa la guía para aprender más.' @@ -950,7 +951,8 @@ es: default_code_lang: "Lenguaje de programación por defecto para aplicar el resaltado de la sintaxis en los bloques de código de GitHub (lang-auto, ruby, python etc.)" warn_reviving_old_topic_age: "Cuando alguien publica en un tema cuya última respuesta fue hace este número de días o más, se le mostrará un aviso para desalentar el hecho de resucitar una antigua discusión. Deshabilita esta opción introduciendo el valor 0." autohighlight_all_code: "Forzar el resaltado de código a los bloques de código preformateado cuando no se especifique el lenguaje del código." - embeddable_host: "Host que pueden embeber los comentarios desde este foro Discourse." + highlighted_languages: "Incluye reglas resaltadas de sintaxis. (Advertencia: incluyendo demasiadas lenguages puede afectar al rendimiento) ver: https://highlightjs.org/static/demo/ para una demostración" + embeddable_host: "Host que puede incrustar los comentarios de este foro Discourse. Nombre de host solamente, no comienzan con http://" feed_polling_enabled: "SOLO PARA EMBEBER: embeber feeds RSS/ATOM como posts." feed_polling_url: "SOLO PARA EMBEBER: URL de los feeds RSS/ATOM a embeber." embed_by_username: "Nombre de usuario en Discourse del que crea los temas embebidos." diff --git a/config/locales/server.fi.yml b/config/locales/server.fi.yml index 0ef26e81c0..5fd30aaf15 100644 --- a/config/locales/server.fi.yml +++ b/config/locales/server.fi.yml @@ -583,7 +583,6 @@ fi: sidekiq_warning: 'Sidekiq ei ole käynnissä. Monet tehtävät, kuten sähköpostien lähettäminen, suoritetaan asynkronisesti sidekiqin avulla. Varmista, että vähintään yksi sidekiq prosessi on käynnissä. Opiskele lisää Sidekiqista täältä.' queue_size_warning: 'Jonossa olevien tehtävien määrä on %{queue_size}, joka on suuri. Tämä voi viitata ongelmaan Sidekiq prosess(e)issa, tai sinun voi olla järkevää lisätä Sidekiq workerien määrää.' memory_warning: 'Palvelimella on alle 1GB muistia. Vähintään 1 GB muistia on suositeltavaa.' - enable_google_logins_warning: "Käytät vanhentunutta versiota Googlen OpenID autentikaatiosta. Google lopettaa OpenID:n tuen 20.4.2015. Vaihda käyttämään OAuth2 autentikointia mahdollisimman nopeasti. Lue lisää tästä englanninkielisestä ketjusta" both_googles_warning: "Olet ottanut käyttöön sekä enable_google_logins että enable_google_oauth2_logins sivun asetuksissa. Ota enable_google_logins pois käytöstä." google_oauth2_config_warning: 'Palvelin on konfiguroitu hyväksymään kirjautuminen Google OAuth2:n kautta (enable_google_oauth2_logins), mutta client id ja client secret arvoja ei ole asetettu. Päivitä arvot sivuston asetuksissa.Voit lukea lisätietoja tästä oppaasta.' facebook_config_warning: 'Palvelin on konfiguroitu hyväksymään kirjautuminen Facebookin kautta (enable_facebook_logins), mutta app id ja app secret arvoja ei ole asetettu. Päivitä arvot sivuston asetuksissa.Voit lukea lisätietoja tästä oppaasta.' @@ -926,7 +925,6 @@ fi: default_code_lang: "Oletusarvoinen ohjelmointikieli syntaksin korostukseen Github koodiblokeissa (lang-auto, ruby, python etc.)" warn_reviving_old_topic_age: "Kun käyttäjä alkaa kirjoittamaan vastausta ketjuun, jonka uusin viesti on tätä vanhempi päivissä, näytetään varoitus. Poista käytöstä asettamalla arvoksi 0." autohighlight_all_code: "Pakota koodin korostus kaikkiin esimuotoiltuihin tekstiblokkeihin, vaikka käyttäjä ei määrittelisi kieltä." - embeddable_host: "Host, joka voi upottaa kommentteja tältä Discourse-palstalta." feed_polling_enabled: "VAIN UPOTUS: Upotetaanko RSS/ATOM syöte viesteinä." feed_polling_url: "VAIN UPOTUS: RSS/ATOM syötteen URL." embed_by_username: "Sen käyttäjän Discourse käyttäjänimi, joka luo upotetut ketjut." @@ -1104,45 +1102,6 @@ fi: %{base_url}/users/password-reset/%{email_token} test_mailer: subject_template: "[%{site_name}] Sähköpostin toimitettavuustesti" - text_body_template: | - Tämä on testisähköposti sivustolta - - [**%{base_url}**][0] - - Sähköpostin toimitus on monimutkaista. Tässä on muutama tärkeä asia, jotka kannattaa tarkistaa ensin: - - - *Varmista,* että `ilmoitusten sähköpostiosoitteen` from: kenttä on asetettu oikein sivuston asetuksissa. **Sähköpostin varmennus tapahtuu "from"-kentän sähköpostiosoitteen verkkotunnusta vastaan**. - - - Selvitä, miten sähköpostiohjelmassasi saa näkyville *sähköpostin raakadatan,* jotta voit tutkia viestin tunnistetiedot. Gmailissa tämä tapahtuu "näytä kokonaan" valinnalla viestin oikeassa yläkulmassa olevasta valikosta. - - - **TÄRKEÄÄ:** Onko palveluntarjoajasi syöttänyt reverse DNS kentän verkkotunnuksille ja IP osoitteille, joists lähetät sähköpostia? [Kokeile Reverse PTR tietuetta][2] täällä. Jos palveluntarjoajasi ei tarjoa kunnollista reverse DNS pointer tietuetta, on hyvin epätodennäköistä, että mikään sähköposti menee perille. - - - Onko verkkotunnuksesi [SPF record][8] oikein? [Kokeile SPF tietuetta][1] täällä. Huomaa, että TXT oikea tietuetyyppi SPF tietueelle. - - - Onko verkkotunnuksesi [DKIM tietue][3] oikein? Tämä vaikuttaa merkittävästi sähköpostin toimitettavuuteen. [Kokeile DKIM tietuetta][7] täällä. - - - Jos käytät omaa sähköpostipalvelinta, tarkista että palvelimen IP osoite [ei ole millään sähköpostin mustalla listalla][4]. - - - Tarkista myös, että se varmasti lähettää oikean muotoisen isäntänimen HELO viestissään, joka palauttaa oikean DNS tietueen. Jos näin ei ole, sähköposti hylätään monissa sähköpostipalveluissa. - - (Helpoin tapa on luoda ilmainen tili [Mandrilliin][md], [Mailguniin][mg] tai [Mailjetiin][mj], joide ilmaiset palvelut riittävät hyvin piemen palstan käyttöön. Muista silti asettaa SPF ja DKIM tietueet DNS:ään!) - - Toivottavasti tämä testisähköposti meni perille OK! - - Onnea matkaan, - - Ystäväsi [Discourselta](http://www.discourse.org) - - [0]: %{base_url} - [1]: http://www.kitterman.com/spf/validate.html - [2]: http://mxtoolbox.com/ReverseLookup.aspx - [3]: http://www.dkim.org/ - [4]: http://whatismyipaddress.com/blacklist-check - [7]: http://dkimcore.org/tools/dkimrecordcheck.html - [8]: http://www.openspf.org/SPF_Record_Syntax - [md]: http://mandrill.com - [mg]: http://www.mailgun.com/ - [mj]: https://www.mailjet.com/pricing new_version_mailer: subject_template: "[%{site_name}] Uusi Discourse versio, päivitys saatavilla" text_body_template: |+ diff --git a/config/locales/server.fr.yml b/config/locales/server.fr.yml index 6b06edd78c..e08980fc21 100644 --- a/config/locales/server.fr.yml +++ b/config/locales/server.fr.yml @@ -112,6 +112,7 @@ fr: other: "Désolé, les nouveaux utilisateurs ne peuvent insérer que %{count} liens." spamming_host: "Désolé, vous ne pouvez pas insérer de lien vers ce domaine." user_is_suspended: "Les utilisateurs suspendus ne sont pas autorisés à poster de messages." + topic_not_found: "Une erreur est survenue. Peut-être que ce sujet a été fermé ou supprimé pendant que vous le regardiez?" just_posted_that: "est trop similaire à ce que vous avez récemment posté" has_already_been_used: "a déjà été utilisé" invalid_characters: "contient des caractères invalides" @@ -594,7 +595,7 @@ fr: sidekiq_warning: 'Sidekiq n''est pas lancé. De nombreuses tâches, comme l''envoi des courriels, sont exécutées de manière asynchrone par sidekiq. Assurez-vous d''avoir au moins un processus sidekiq de lancé. En savoir plus sur sidekiq.' queue_size_warning: 'Il y a %{queue_size} tâches dans la file d''attente, ce qui est beaucoup. Cela peut provenir d''un problème avec les processus Sidekiq, ou à un manque de processus Sidekiq travailleurs.' memory_warning: 'Votre serveur dispose de moins de 1 Go de mémoire vive. Au moins 1 Go de RAM est recommandé.' - enable_google_logins_warning: "Vous utilisez une version obsolète d'authentification via Google OpenID. Google ne supportera plus cette authentification à partir du 20 avril 2015. Veuillez commencer à utiliser l'authentification via Google Oauth2 le plus tôt possible. Voir le guide pour en savoir plus" + enable_google_logins_warning: "AVERTISSEMENT! Votre méthode actuelle d'authentication Google ne fonctionnera plus à partir du 20 avril 2015! Veuillez passer à la nouvelle méthode dès maintenant!" both_googles_warning: "Vous avez les options enable_google_logins et enable_google_oauth2_logins d'activer en même temps. Veuillez désactiver l'option enable_google_logins (obsolète)." google_oauth2_config_warning: 'Le serveur est configuré pour permettre l''authentification via Google Oauth2 (enable_google_oauth2_logins), mais les paramètres client id et client secret ne sont pas renseignés. Allez dans les Paramètres du Site et mettez les à jour. Voir le guide pour en savoir plus.' facebook_config_warning: 'Le serveur est configuré pour permettre l''authentification par Facebook (enable_facebook_logins), mais les paramètres facebook_app_id et facebook_app_secret ne sont pas renseignés. Allez dans les Paramètres et mettez les à jour. Voir le guide pour en savoir plus.' @@ -891,6 +892,7 @@ fr: max_age_unmatched_ips: "Effacer les adresses IP sous surveillenace sans correspondance après (N) jours" num_flaggers_to_close_topic: "Nombre minimum de signalements uniques requis pour automatiquement suspendre un sujet pour intervention" num_flags_to_close_topic: "Nombre minimum de signalements uniques requis pour automatiquement suspendre un sujet pour intervention" + auto_respond_to_flag_actions: "Activer réponse automatique lors du traitement d'un signalement." reply_by_email_enabled: "Activer les réponses aux sujets via courriel." reply_by_email_address: "Modèle pour la réponse par courriel entrant; exemple : %{reply_key}@reply.example.com ou replies+%{reply_key}@example.com" disable_emails: "Désactiver l'envoi de les courriels depuis Discourse." @@ -943,7 +945,8 @@ fr: default_code_lang: "Coloration syntaxique par défaut appliquée à la syntaxe des langages de programmation des blocs de code GitHub (lang-auto, Ruby, Python, etc)" warn_reviving_old_topic_age: "Lorsque quelqu'un commence à répondre à un sujet dont la dernière réponse est vielle de plusieurs jours, un avertissement sera affiché. Désactiver la fonctionnalité en indiquant: 0." autohighlight_all_code: "Forcer la mise en évidence de tout les textes dans les balises code, même si ils ne correspondent à aucun langage de programmation." - embeddable_host: "Hôte pouvant embarqué les commentaires de ce forum Discourse." + highlighted_languages: "Include les règles de mise en surbrillance de syntaxe. (Avertissement: l'ajout de trop de langages peut impacter les performances) voir l'exemple https://highlightjs.org/static/demo/" + embeddable_host: "Hôte qui peut incorporer des messages de ce forum Discourse. Nom d'hôte seulement, sans http://" feed_polling_enabled: "EMBARQUER UNIQUEMENT: Embarqué le flux RSS/ATOM en tant que messages." feed_polling_url: "EMBARQUER UNIQUEMENT: Url du flux RSS/ATOM à embarqué." embed_by_username: "Pseudo de l'utilisateur Discourse qui crée les sujets embarqués." diff --git a/config/locales/server.he.yml b/config/locales/server.he.yml index 52def2096e..7d8a4f9bf2 100644 --- a/config/locales/server.he.yml +++ b/config/locales/server.he.yml @@ -581,7 +581,6 @@ he: sidekiq_warning: 'Sidekiq is not running. Many tasks, like sending emails, are executed asynchronously by sidekiq. Please ensure at least one sidekiq process is running. Learn about Sidekiq here.' queue_size_warning: 'The number of queued jobs is %{queue_size}, which is high. This could indicate a problem with the Sidekiq process(es), or you may need to add more Sidekiq workers.' memory_warning: 'Your server is running with less than 1 GB of total memory. At least 1 GB of memory is recommended.' - enable_google_logins_warning: "את/ה משתמשים בגרסא מיושנת של אימות ה-OpenID של גוגל. גוגל תפסיק לתמוך ב-OpenID ב-25 לאפריל, 2015. התחילו להשתמש ב-OAuth2 של גוגל מוקדם ככל הניתן. ראו מדריך זה כדי ללמוד עוד " both_googles_warning: "שתי האפשרויות, enable_google_logins וגם enable_google_oauth2_logins מסומנים הגדרות האתר. בטלו את enable_google_logins." google_oauth2_config_warning: 'השרת מכוון לאפשר הרשמות והתחברות עם OAuth2 של גוגל (enable_google_oauth2_logins), אבל ערכי זהות הלקוח (client id) וסיסאת הלקוח (client secret) אינם מוגדרים. לכו ל הגדרות האתר ועדכנו את הגדרות האתר. ראו מדריך זה כדי ללמוד עוד.' facebook_config_warning: 'The server is configured to allow signup and log in with Facebook (enable_facebook_logins), but the app id and app secret values are not set. Go to the Site Settings and update the settings. See this guide to learn more.' @@ -912,7 +911,6 @@ he: default_code_lang: "Default programming language syntax highlighting applied to GitHub code blocks (lang-auto, ruby, python etc.)" warn_reviving_old_topic_age: "כאשר מישהו/מישהי מתחילים להגיב לנושא שבו התגובה האחרונה היא בת יותר מכמה ימים, אזהרה תוצג. בטלו אפשרות זו באמצעות הזנה של 0." autohighlight_all_code: "לחייב שימוש בקוד הדגשה לכל קוד מעוצב מראש (preformatted code blocks) אפילו אם הם אינם מציינים את השפה." - embeddable_host: "מארח (Host) אשר יכול להטמיע את התגובות מפורוסם זה של Discourse." feed_polling_enabled: "הטמעה בלבד: האם לעמבד פידים של RSS/ATOM כפרסומים." feed_polling_url: "הטמעה בלבד: URL של פיד RSS/ATOM להטמעה." embed_by_username: "שם המשתמש של המשתמש/ת שיוצר את הנושאים המוטמעים." diff --git a/config/locales/server.it.yml b/config/locales/server.it.yml index 0df0775232..972b8de905 100644 --- a/config/locales/server.it.yml +++ b/config/locales/server.it.yml @@ -565,7 +565,6 @@ it: sidekiq_warning: 'Sidekiq non è in esecuzione. Molte attività, come l''invio di email, sono eseguite in maniera asincrona da sidekiq. Assicurati che almeno un processo sidekiq sia in esecuzione. Leggi altro su sidekiq qui.' queue_size_warning: 'Il numero di job in coda è %{queue_size}, troppo alto. Potrebbe esserci un problema con i processi Sidekiq, oppure potresti dover aggiungere altri Sidekiq worker.' memory_warning: 'Il tuo server gira con meno di 1 GB di memoria. Si raccomanda almeno 1 GB di memoria.' - enable_google_logins_warning: "Stai utilizzando una versione obsoleta dell'autenticazione Google OpenID. Google terminerà il supporto ad OpenID il 20 aprile 2015. Inizia ad usare Google OAuth2 al più presto. Leggi questa guida per saperne di più" both_googles_warning: "Hai entrambe le impostazioni enable_google_logins e enable_google_oauth2_logins attivate. Disabilita enable_google_logins." google_oauth2_config_warning: 'Il server è configurato per permettere registrazioni e login con Google Oauth2 (enable_google_oauth2_logins), ma il client id e il client secret non sono impostati. Vai nelle Impostazioni del sito e aggiorna le impostazioni. Leggi questa guida per saperne di più.' facebook_config_warning: 'Il server è configurato per accettare registrazioni e login con Facebook (enable_facebook_logins), tuttavia i parametri app id e secret non sono stati impostati. Vai alle Impostazioni e aggiorna i campi interessati. Leggi questa guida per saperne di più.' diff --git a/config/locales/server.ja.yml b/config/locales/server.ja.yml index bf89c691b7..e6948433f3 100644 --- a/config/locales/server.ja.yml +++ b/config/locales/server.ja.yml @@ -21,6 +21,7 @@ ja: purge_reason: "アクティブでないアカウントは放棄されたとして削除されました" disable_remote_images_download_reason: "ディスク容量が不足しているため、リモートでの画像ダウンロードは無効になっています。" errors: + format: '%{attribute} %{message}' messages: too_long_validation: "は、最大文字数(%{max}文字)を超えています。(入力したのは%{length}文字 ) " invalid_boolean: "無効なboolean." @@ -78,6 +79,7 @@ ja: other: "%{count} 以上の返信" loading: "会話をロードしています…" permalink: "パーマリンク" + imported_from: "これは、オリジナルエントリ%{link}に対するディスカッショントピックです" in_reply_to: "▶ %{username}" replies: other: "%{count} 通の返信" @@ -103,6 +105,7 @@ ja: other: "申し訳ありませんが、新規ユーザはこのポストにリンクを%{count}個しか貼れません。" spamming_host: "申し訳ありませんが、このホストへのリンクを貼ることはできません。" user_is_suspended: "サスペンド中のユーザーは投稿ができません。" + topic_not_found: "何かがおかしいです。トピックが終了したか、閲覧してる間に削除された可能性があります" just_posted_that: "はあなたが最近投稿したポストと内容がほぼ一緒です" has_already_been_used: "は既に使用中です" invalid_characters: "は不正なキャラクターを含んでいます" @@ -122,6 +125,7 @@ ja: latest: "最新トピック" hot: "ホットトピック" too_late_to_edit: "この投稿の編集・削除期間が過ぎまして、編集・削除が出来ません。" + excerpt_image: "画像" groups: errors: can_not_modify_automatic: "自動作成グループの変更はできません" @@ -130,47 +134,90 @@ ja: admins: "管理者" moderators: "モデレータ" staff: "スタッフ" - trust_level_1: "trust_level_1" - trust_level_2: "trust_level_2" - trust_level_3: "trust_level_3" - trust_level_4: "trust_level_4" + trust_level_0: "トラストレベル0" + trust_level_1: "トラストレベル1" + trust_level_2: "トラストレベル2" + trust_level_3: "トラストレベル3" + trust_level_4: "トラストレベル4" education: until_posts: other: "%{count} 投稿" + new-topic: "%{site_name} へようこそ — **\n新たなトピックの作成ありがとうございます!** \n- タイトルはトピックの内容を正しく説明していますか? 他の人にとって興味深いタイトルになっていますか? \n- このトピックは何をカバーするものですか? このトピックに興味を示しそうなのは誰でしょう? なぜこのトピックは重要なのでしょうか? コミュニティよりどのような回答を期待していますか?\n - トピックに適切な検索用ワードを含めると、他の人がトピックを *発見* しやすくなります。適切なカテゴリを選択すると、他の関連トピックとのグルーピングができます。\n詳細は[コミュニティガイドライン](/guidelines)を参照してください。 このパネルは最初の %{education_posts_text} のみに表示されます。\n" + new-reply: "%{site_name} へようこそ — **コミュニティへの貢献ありがとうございます!** \n- あなたの回答は議論に何らかの形で貢献していますか?\n - コミュニティメンバー同士のやりとりは礼儀正しく、マナーを保ちましょう。\n - 建設的な批判は歓迎します。ただし批判は「人」に対してではなく「アイデア」に対して行いましょう。 \n詳細は[コミュニティガイドライン](/guidelines)を参照してください。このパネルは最初の %{education_posts_text} のみに表示されます。\n" avatar: | ### アカウント用の画像を用意してみては? コミュニティへの貢献ありがとうございます。アバターがデフォルトのままのようですが、**[ユーザプロファイル](%{profile_path})** にてアバター画像をアップロードしてみてはいかがでしょう? ユニークなアバターは、コミュニティにおける議論の活性化にもつながりますので、ぜひご検討ください! + sequential_replies: | + ### 一度に複数のポストに回答する + + トピックに数多くの回答を投稿する代わりに、以前のポストへの @name 参照や引用などを活用して回答を一つのポストにまとめられないか検討してください。 + + テキストをハイライトし、表示された引用返信ボタンを選択することで、前回の回答を引用を追加するために編集することができます。 + + 細かい回答を数多く投稿するより、掘り下げた内容をカバーした数少ない回答を投稿した方がトピックの議論を追いやすくなります。 dominating_topic: | ### 他のユーザも議論に参加させてあげましょう このトピックはあなたにとても重要なもののようですね – ここの回答のうち %{percent}% 以上があなたによってなされています。 他のユーザが回答するために十分な時間的猶予を与えているか、ちょっと振り返ってみませんか? + too_many_replies: | + ### このトピックに回答出来る制限を超えました + + 申し訳ありません。新しいユーザーの同じトピックへの返信は%{newuser_max_replies_per_topic} 回に一時的に制限されています。 + + 回答を追加する代わりに、以前の回答を編集するか、別のトピックを訪れる事を検討してください。 + reviving_old_topic: | + ### このトピックを復活させますか? + + このトピックの最後の回答は%{days}日前です。あなたの回答はトピックを一覧のトップに上げて、以前回答した誰がか気付きます。 + + 本当に過去の議論を続けますか? activerecord: attributes: category: name: "カテゴリ名" post: raw: "本文" + user_profile: + bio_raw: "About Me" errors: messages: is_invalid: "は不正です。もう少し説明を追加してください" has_already_been_used: "は既に使用中です" models: + topic: + attributes: + base: + warning_requires_pm: "プライベートメッセージでのみ警告を送ることができます" + too_many_users: "1度に1ユーザにしか警告を送る事はできません" + cant_send_pm: "申し訳ありません。このユーザにはプライベートメッセージを送る事ができません" + no_user_selected: "有効なユーザを選択してください" user: attributes: password: common: "は10000最も一般的なパスワードのいずれかである。より安全なパスワードを使用してください。" + same_as_username: "はあなたのユーザ名と同じです。より安全なパスワードを使用してください" + same_as_email: "はあなたのメールアドレスと同じです。より安全なパスワードを使用してください" ip_address: signup_not_allowed: "このアカウントからのサインアップできません。" + color_scheme_color: + attributes: + hex: + invalid: "は有効なカラーではありません" user_profile: no_info_me: "
    プロフィールの自己紹介フィールドが空欄のようです。自己紹介をしてみませんか?
    " no_info_other: "
    %{name} は、まだプロフィールの自己紹介フィールドに何も書いていません
    " vip_category_name: "ラウンジ" + vip_category_description: "トラストレベル3以上のメンバーのみが参加できるカテゴリ" + meta_category_name: "Meta" + meta_category_description: "Discussion about this site, its organization, how it works, and how we can improve it." staff_category_name: "スタッフ" + staff_category_description: "スタッフのためのプライベートカテゴリです。トピックは管理者とモデレータのみが閲覧できます" + assets_topic_body: "これはパーマネントトピックです。スタッフのみが閲覧でき、サイトデザインに使用する画像とファイルを保存するために使用します。削除しないでください!\n\n利用方法:\n\n\n1. このトピックに回答\n2. ロゴやファビコンなどに使用する全ての画像をアップロード(エディタのアップロードアイコンか、ドラッグアンドドロップで画像を貼付ける)\n3. 回答を投稿\n4. 新しい投稿の画像を右クリックしてアップロード済み画像のパスを取得するか、編集アイコンをクリックして画像のパスを探し、画像パスをコピーする\n5. 画像パスを[基本設定](/admin/site_settings/category/required)に貼付ける\n\nもし、別のファイルタイプが必要な場合、[ファイル設定](/admin/site_settings/category/files)の`サポートするファイルの拡張` を編集してください" lounge_welcome: title: "ラウンジへようこそ" category: @@ -179,8 +226,14 @@ ja: post_template: "%{replace_paragraph}\n\nこれ以降のパラグラフに、カテゴリのガイドライン等を書いてください。\n\nいくつかのヒント:\n\n- このカテゴリは何か? どのようなトピックをこのカテゴリに入れるべきか?\n\n- 既に存在するカテゴリとの違いは何か?\n\n- このカテゴリはなぜ必要か?\n\n- 他のカテゴリとの統合や、複数カテゴリへの分割をするべきか?\n" errors: uncategorized_parent: "未分類カテゴリは親カテゴリに設定出来ません。" + self_parent: "自分自身がサブカテゴリの親になることはできません" + depth: "他のサブカテゴリの下にサブカテゴリを作成することはできません" cannot_delete: uncategorized: "未分類カテゴリは削除出来ません" + has_subcategories: "サブカテゴリを持っているため、カテゴリを削除できません" + topic_exists: + other: "%{count}個のトピックを持っているため、カテゴリを削除できません。一番古いトピックは%{topic_link}です" + topic_exists_no_oldest: "%{count}個のトピックを持っているため、カテゴリを削除できません" trust_levels: newuser: title: "新規ユーザ" @@ -190,7 +243,11 @@ ja: title: "メンバー" leader: title: "レギュラー" + elder: + title: "リーダー" + change_failed_explanation: "%{user_name} を '%{new_trust_level}' に格下げしようとしましたが、既にトラストレベルが '%{current_trust_level}' です。%{user_name} は '%{current_trust_level}' のままになります - もしユーザーを降格させたい場合は、トラストレベルをロックしてください" rate_limiter: + slow_down: "多すぎるアクションが実行されました。時間を置いてから試してください" too_many_requests: "このアクションを一日の間に実施可能な回数が決まっています。%{time_left}待ってから再度試してください。" hours: other: "%{count} 時間" @@ -264,26 +321,35 @@ ja: activation: action: "アカウントを有効する" already_done: "申し訳ありませんが、このアカウント認証リンクは無効です。既にアカウントがアクティブになっていませんか?" + please_continue: "あなたのアカウントは確認されました。ホームにリダイレクトされます" continue_button: "%{site_name} へ" welcome_to: "%{site_name} へようこそ!" approval_required: "このフォーラムにアクセスするにはモデレータによる承認が必要です。承認されるとメールにて通知されます!" post_action_types: off_topic: title: '関係ない話題' + description: 'このポストはタイトルと投稿で定義される現在の議論に関連しておらず、どこかに移動させる必要があります' long_form: '「関係ない話題」としてフラグを立つ' spam: title: 'スパム' description: 'この投稿は、営利目的、宣伝目的の書き込みの可能性がある。' long_form: 'スパムフラグをたてる' + email_title: '"%{title}"はスパムとしてフラグされています' + email_body: "%{link}\n\n%{message}" inappropriate: title: '不適切' description: 'この投稿は、誹謗中傷、恫喝、名誉毀損、わいせつ、犯罪行為など他人を不快にさせる内容を含んでいる。' long_form: '不適切フラグをたてる' notify_user: + title: 'プライベートメッセージ @{{username}}' description: 'この投稿やトピックを書いた人に、直接メッセージを送る。(フラグを付けません)' + long_form: 'プライベートメッセージを送ったユーザ' email_title: '「%{title}」にの投稿' email_body: "%{link}\n\n%{message}" notify_moderators: + title: "その他" + description: 'このポストは、記載されていない別の理由でモデレータの注意が必要です' + long_form: 'モデレータへの注意としてフラグを立てる' email_title: '"%{title}" のポストに関する管理人の確認が必要とする' email_body: "%{link}\n\n%{message}" bookmark: @@ -308,7 +374,9 @@ ja: description: 'この投稿は、誹謗中傷、恫喝、名誉毀損、わいせつ、犯罪行為など他人を不快にさせる内容を含んでいる。' long_form: '不適切フラグをたてる' notify_moderators: + title: "その他" description: 'この投稿やトピックは不適切な可能性があるため、管理人による確認を必要とする。' + long_form: 'モデレータへの注意としてフラグを立てる' email_title: 'トピック"%{title}" は不適切な可能性があるため、管理人による確認を必要とする。' email_body: "%{link}\n\n%{message}" flagging: @@ -317,11 +385,17 @@ ja: archetypes: regular: title: "通常のトピック" + banner: + message: + make: "このトピックはバナートピックに設定されています。ユーザが解除しない限り、ページ毎の一番上に表示されます" + remove: "このトピックはバナーではなくなりました。トップページには表示されなくなります" unsubscribed: title: '購読解除' description: "購読解除されました。メールの送信をストップしました。" oops: "誤って購読解除した場合は、下をクリックしてください。" error: "購読エラー" + preferences_link: "あなたの 設定画面からの確認メールでも解除することができます" + different_user_description: "確認メールを送ったユーザとは別のユーザでログインしています。ログアウトしてから試してください" not_found_description: "申し訳ありませんが購読解除に失敗しました。メール内のリンクの有効期限が切れているのかもしれません。" resubscribe: action: "再購読" @@ -333,6 +407,7 @@ ja: xaxis: "日" yaxis: "訪問者数" signups: + title: "新規ユーザ" xaxis: "日" yaxis: "新規ユーザ数" topics: @@ -358,6 +433,7 @@ ja: starred: title: "お気に入り" xaxis: "日" + yaxis: "お気に入りされたトピックの数" users_by_trust_level: title: "トラストレベル毎のユーザ" xaxis: "トラストレベル" @@ -402,7 +478,45 @@ ja: xaxis: "トピック" num_clicks: "クリック" page_view_anon_reqs: + title: "匿名ユーザ" xaxis: "日" + yaxis: "Anonymous API Requests" + page_view_logged_in_reqs: + title: "ログイン" + xaxis: "日" + yaxis: "Logged In API Requests" + page_view_crawler_reqs: + title: "クローラー" + xaxis: "日" + yaxis: "クローラーAPI Requests" + page_view_total_reqs: + title: "全体" + xaxis: "日" + yaxis: "Total API Requests" + http_background_reqs: + title: "背景" + xaxis: "日" + yaxis: "Requests used for live update and tracking" + http_2xx_reqs: + title: "Status 2xx (OK)" + xaxis: "日" + yaxis: "成功 (Status 2xx)" + http_3xx_reqs: + title: "HTTP 3xx (リダイレクト)" + xaxis: "日" + yaxis: "リダイレクト (Status 3xx)" + http_4xx_reqs: + title: "HTTP 4xx (クライアントエラー)" + xaxis: "日" + yaxis: "クライアントエラー (Status 4xx)" + http_5xx_reqs: + title: "HTTP 5xx (サーバーエラー)" + xaxis: "日" + yaxis: "サーバーエラー (Status 5xx)" + http_total_reqs: + title: "全体" + xaxis: "日" + yaxis: "全リクエスト" dashboard: rails_env_warning: "サーバは %{env} モードで起動中です。" ruby_version_warning: "現在起動中の Ruby 2.0.0 にはいくつか問題があります。パッチレベル p247 以降にアップグレードしてください。" @@ -411,13 +525,22 @@ ja: sidekiq_warning: 'Sidekiq が起動していません。メール送信等、多くのタスクが sidekiq により非同期に実行されます。少なくとも sidekiq のプロセスを1つは起動してください。Sidekiq についてはこちらを参考にしてください。' queue_size_warning: 'キューに入っているジョブの数が多すぎます (%{queue_size})。Sidekiq プロセスに問題があるか、Sidekiq ワーカを追加する必要がある可能性があります。' memory_warning: '現在サーバが 1GB 未満の総メモリで起動しています。推奨メモリサイズは 1GB 以上です。' + enable_google_logins_warning: "WARNING! Support is ending for your current method of Google authentication on April 20, 2015! Please switch to the new method now!" facebook_config_warning: 'サーバが Facebook アカウントによるサインアップ・ログイン可能な設定 (enable_facebook_logins) になっていますが、app id と app secret が設定されていません。サイトの設定 にて設定を更新してください。詳しくはこちらを参考にしてください。' twitter_config_warning: 'サーバが Twitter アカウントによるサインアップ・ログイン可能な設定 (enable_twitter_logins) になっていますが、key と secret が設定されていません。サイトの設定 にて設定を更新してください。詳しくはこちらを参考にしてください。' github_config_warning: 'サーバが Github アカウントによるサインアップ・ログイン可能な設定 (enable_github_logins) になっていますが、client id と secret が設定されていません。サイトの設定 にて設定を更新してください。詳しくはこちらを参考にしてください。' s3_config_warning: 'サーバが S3 にファイルをアップロードするように設定されていますが、次のうち少なくとも1つが設定されていません: s3_access_key_id, s3_secret_access_key or s3_upload_bucket。サイトの設定 にて設定を更新してください。詳しくは "How to set up image uploads to S3?" を参考にしてください。' + s3_backup_config_warning: 'サーバが S3 にバックアップをアップロードするように設定されていますが、次のうち少なくとも1つが設定されていません: s3_access_key_id, s3_secret_access_key or s3_upload_bucket。サイトの設定 にて設定を更新してください。詳しくは "How to set up image uploads to S3?" を参考にしてください' image_magick_warning: 'サーバが大きな画像のサムネイルを作成する設定になっていますが、ImageMagick がインストールされていません。お好きなパッケージマネージャを使って ImageMagick をインストールするか、最新のリリースをダウンロードしてください。' failing_emails_warning: '%{num_failed_jobs}個のメールジョブが失敗しています。config/environments/production.rb ファイルを確認して config.action_mailer の設定が正しいか確認してください。Sidekiq で失敗したジョブを確認。' + default_logo_warning: "あなたのサイトのロゴを設定しましょう。サイトの設定で logo_url, logo_small_url, favicon_url を更新してください。" + contact_email_missing: "サイトに関する緊急連絡が行えるように、連絡先メールアドレスを入力してください。サイトの設定で更新できます" + contact_email_invalid: "サイトの連絡先メールアドレスが正しくありません。サイトの設定で更新してください" + title_nag: "サイトの名前が正しくありません。サイトの設定で更新してください" + site_description_missing: "検索結果に表示される説明文を入力してください。サイトの設定で更新してください" consumer_email_warning: "サイトはメール送信に Gmail (または他のカスタムメールサービス) を利用するように設定されています。Gmail で送信可能なメール数には制限があります。メールを確実に送信するために mandrill.com などのメールサービスプロバイダーのり用を検討してください。" + site_contact_username_warning: "重要な自動的に送信されるプライベートメッセージを送信するために、フレンドリーなスタッフ名を入力してください。サイトの設定で更新してください" + notification_email_warning: "通知用メールがあなたのドメインで有効なメールアドレスから送信されていません。メール配信が不安定になり、信頼性が低くなります。\nサイトの設定で更新してください" content_types: education_new_reply: title: "新規ユーザ支援: 初めての回答" @@ -425,6 +548,9 @@ ja: education_new_topic: title: "新規ユーザ支援: 初めてのポスト" description: "新規ユーザが新規トピックの作成を行った際に自動的にポップアップするガイダンスに内容 (最初の2回のみ表示)。" + usage_tips: + title: "新規ユーザガイダンス" + description: "新規ユーザのための重要な情報とガイダンス" welcome_user: title: "ウェルカムメッセージ: 新規ユーザ" description: "サインアップした全ての新規ユーザに自動送信されるプライベートメッセージの内容。" @@ -437,38 +563,145 @@ ja: login_required: title: "ホームページ: 要ログイン" description: "要ログイン設定の際に、未ログインユーザに対して表示されるメッセージの内容。" + head: + title: "HTML head" + description: " タグの中に挿入されるHTML" top: title: "ページトップ" description: "全ページのトップに追加される HTML (ヘッダとナビゲーション/トピックタイトルの間に表示されます)" bottom: title: "ページボトム" + description: "タグの前に挿入されるHTML" site_settings: + censored_words: "自動的に ■■■■ で置換されます" + delete_old_hidden_posts: "30日以上非表示になっているポストを自動で削除します" default_locale: "この Discourse インスタンスのデフォルト言語 (ISO 639-1 Code)" + allow_user_locale: "ユーザーが各自の言語設定を選択できるようにする" + min_post_length: "投稿を許可する最少の文字数" + min_private_message_post_length: "プライベートメッセージの投稿を許可する最少の文字数" + max_post_length: "投稿を許可する最大の文字数" + min_topic_title_length: "トピックタイトルとして許可する最小の文字数" + max_topic_title_length: "トピックタイトルとして許可する最大の文字数" + min_private_message_title_length: "プライベートメッセージのタイトルとして許可する最少の文字数" + min_search_term_length: "検索ワードとして有効にする最小の文字数" allow_uncategorized_topics: "カテゴリなしのトピック作成を許可するか。" + uncategorized_description: "未分類カテゴリについての説明。存在しない場合は空白のままにします" + allow_duplicate_topic_titles: "トピックタイトルの重複を許可" unique_posts_mins: "同じ内容のポストを再投稿可能にする時間 (分)" + educate_until_posts: "最初(または複数)の投稿でタイピングを開始したら、ポップアップでガイダンスを表示させるか" + title: "サイトの名前です。titleタグで使用されます" + site_description: "1文でこのサイトを説明してください。descriptionタグで使用されます" + contact_email: "このサイトへの問い合わせに責任を持つメールアドレス。問い合わせフォームからの緊急事項、回収していないフラグなど、緊急の通知に使用します" + contact_url: "このサイトの問い合わせURL。緊急連絡用問い合わせフォームに使用されます" queue_jobs: "開発者ONLY! 警告! デフォルトでキューは sidekiq により処理されます。これを無効にするとサイトが動作不能になります。" + crawl_images: "正しい幅と高さを取得するためにURLから画像を取得する" + download_remote_images_to_local: "リモート画像をダウンロードしてローカル画像に変換する。破損した画像を防ぎます" + download_remote_images_threshold: "リモート画像をダウンロードするために必要なディスクスペースの最低残容量 (パーセント)" + disabled_image_download_domains: "これらのドメインからは、リモート画像のダウンロードを行いません。パイプ区切りのリスト" + ninja_edit_window: "投稿から(N)秒間は、ポストの新しいバージョンを作成しない" + post_edit_time_limit: "作者は投稿から(N)分間、編集と削除が可能。0を設定すると無期限です" + edit_history_visible_to_public: "すべてのユーザに対してポストの編集履歴を許可する。無効の場合はスタッフメンバーのみが確認できます" + delete_removed_posts_after: "投稿は作者が削除してから(N)時間後に削除されます。0を設定すると、すぐに削除されます" + max_image_width: "ポスト内画像サムネイルの最大の幅" + max_image_height: "ポスト内画像サムネイルの最大の高さ" category_featured_topics: "/categories ページに表示されるカテゴリ毎のトピック数" + show_subcategory_list: "カテゴリを表示する際にトピック一覧の代わりにサブカテゴリ一覧を表示" + fixed_category_positions: "チェックすると、カテゴリの表示順をコントロールできます。チェックしない場合、アクティビティ順に表示されます" + add_rel_nofollow_to_user_content: " 内部リンク(親ドメインを含む)を除き、投稿されたすべてのユーザコンテンツに rel nofollow を追加する。この設定を反映するには \"rake posts:rebake\" を実行して baked markdown をすべて更新する必要があります" exclude_rel_nofollow_domains: "nofollow を設定しないドメイン一覧 (カンマ区切り) (tld.com を設定すると、自動的に sub.tld.com も対象になります)" + post_excerpt_maxlength: "投稿の引用/サマリの最大文字数" + post_onebox_maxlength: "Discourse OneBoxポストの最大文字数" + onebox_domains_whitelist: "OneBoxを許可するドメインのリスト。これらのドメインはOpenGraphかoEmbedをサポートしている必要があります。http://iframely.com/debug でテストできます" + logo_url: "トップ左上のロゴ画像です。空白の場合、サイトタイトルが表示されます" + digest_logo_url: "サイトのメールに使用されるロゴです。空白の場合`logo_url`が使用されます。 eg: http://example.com/logo.png" + logo_small_url: "スクロールしたときに表示されるトップ左上のロゴ画像です。空白の場合、ホームグリフが表示されます" favicon_url: "サイトの favicon。参照: http://en.wikipedia.org/wiki/Favicon" + mobile_logo_url: "モバイルサイトでトップ左上に固定で表示されるロゴです。空白の場合、サイトタイトルが表示されます" apple_touch_icon_url: "Apple のタッチデバイス用のアイコン。推奨サイズは 144px x 144px" + 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: "ユーザに送信するデータが存在しないとき、サーバが待機する時間(ログインユーザーのみ)" + polling_interval: "ロングポーリングではないときの、ログイン済みクライアントのポーリング間隔(ミリ秒)" anon_polling_interval: "匿名ユーザのクライアントのポーリング間隔 (ミリ秒)" + background_polling_interval: "ウィンドウがバックグラウンド時のクライアントのポーリング間隔(ミリ秒)" auto_track_topics_after: "トピックが自動的にトラックされるまでのデフォルト時間 (ミリ秒)。なお、ユーザはこの設定をカスタマイズできます。(0で常にトラック、-1で常にトラックしない)" new_topic_duration_minutes: "トピックが新規と見なされるデフォルト時間 (分)。なお、ユーザはこの設定をカスタマイズできます。(-1で常に新規とみなす、-2で最終訪問したものを新規とみなす)" flags_required_to_hide_post: "ポストが自動的に非表示状態になりユーザにプライベートメッセージが送信されるフラグ数 (0で無効)" + cooldown_minutes_after_hiding_posts: "フラグにより非表示状態になったポストをユーザが編集可能になるまでの時間 (分)" max_topics_in_first_day: "サイト利用初日にユーザが作成することのできるトピックの最大数" max_replies_in_first_day: "サイト利用日にユーザが作成することのできる回答の最大数" + num_flags_to_block_new_user: "新規ユーザのポストに対して、何人のユーザによりここで指定した数のスパムフラグが立てられたら、全てのポストを非表示状態にした上でこのユーザからのポストを拒否するか。0 で無効化" + num_users_to_block_new_user: "新規ユーザのポストに対して、ここで指定した数のユーザにより何個のスパムフラグが立てられたら、全てのポストを非表示状態にした上でこのユーザからのポストを拒否するか。0 で無効化" notify_mods_when_user_blocked: "ユーザが自動的にブロックされた際に、すべてのモデレータにメッセージを送信する。" + flag_sockpuppets: "トピックを作成したユーザーと同じIPアドレスで、新規ユーザーがトピックに回答した場合、両者を潜在的なスパムとしてフラグを立てるか" + traditional_markdown_linebreaks: "Markdown の従来形式のラインブレーク (行の終わりにダブルスペース) を使う" + post_undo_action_window_mins: "ポストに対するアクション (「いいね!」、フラグ等) 取り消しを許可する時間 (秒)" + must_approve_users: "ユーザがサイトにアクセスするには、スタッフの承認が必要" ga_tracking_code: "Google analytics のトラッキングコード。例: UA-12345678-9; 参考 http://google.com/analytics" ga_domain_name: "Google analytics のドメイン名。例: mysite.com; 参考 http://google.com/analytics" + ga_universal_tracking_code: "Google Universal Analytics(analytics.js) のトラッキングコード。例: UA-12345678-9; 参考 http://google.com/analytics" + ga_universal_domain_name: "Google Universal Analytics (analytics.js) のドメイン名。例: mysite.com; 参考 http://google.com/analytics" + enable_escaped_fragments: "古いサーチエンジンクローラがあなたのサイトのインデックスを構築するのをサポートするワークアラウンドを有効にする。詳細はhttps://support.google.com/webmasters/answer/174992?hl=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" post_menu: "ポストメニューに表示する項目を指定。例 like|edit|flag|delete|share|bookmark|reply" + post_menu_hidden_items: "展開記号がクリックされない限り、ポストのメニュー項目を隠します" + share_links: "シェアダイアログに表示する項目、表示順を指定" track_external_right_clicks: "右クリックされた外部リンクをトラックする (例: 新しいタブで開く)。URL のリライトを要するためデフォルトでは無効化されています" + site_contact_username: "自動送信されるプライベートメッセージを送信する有効なスタッフユーザ名。空白の場合、システムアカウントが使用されます" + send_welcome_message: "全ての新規ユーザにクイックスタートガイド付きのウェルカムプライベートメッセージを送信する" + suppress_reply_directly_below: "ポストに回答が1つしかない場合、ポストの回答数を表示しない" + suppress_reply_directly_above: "ポストに回答が1つしかない場合、ポストのin-reply-toを表示しない" + suppress_reply_when_quoting: "ポストが引用返信だった場合、ポストのin-reply-toを表示しない" + max_reply_history: "回答のin-reply-toを展開する最大数" + topics_per_period_in_top_summary: "デフォルトのトピックサマリに表示されるトップトピックの数" + topics_per_period_in_top_page: "'もっと見る'を展開したときに表示するトップトピックの数" + redirect_users_to_top_page: "新規ユーザーと長く不在のユーザーをトップページに自動的にリダイレクトさせる" + show_email_on_profile: "プロフィールのメールアドレスを表示(自分とスタッフのみ閲覧できます)" + email_token_valid_hours: "パスワードリマインダ、アカウントアクティベート時のトークンを何時間有効にするか" + email_token_grace_period_hours: "パスワードリマインダ、アカウントアクティベート時のトークンを無効するときに、何時間猶予を与えるか" + 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 ダッシュボードにバージョンメッセージを表示する" + new_version_emails: "Discourseの新しいバージョンが利用可能になった際に contact_email アドレスにメールで通知する" port: "開発者用! 警告! デフォルトの80番ポートではなく、ここで指定した HTTP ポートを利用する。空欄でデフォルトの80番ポートを利用。" force_hostname: "開発者用! 警告! URL 内のホスト名を指定。空欄でデフォルト値を利用。" invite_expiry_days: "招待キーの有効期間 (日)" + invite_passthrough_hours: "ユーザーが、以前の招待キーを使う事ができる時間" + invite_only: "パブリックなユーザー登録を無効化し、全てのユーザは他のメンバーかスタッフの招待を必要とする" + login_required: "サイトのコンテンツを閲覧するには認証を必須にして、匿名アクセスを拒否する" + min_username_length: "ユーザ名の最小の文字数。 警告: !!これより短いユーザ名を持つ既存のユーザはログインできなくなります!!" + max_username_length: "ユーザ名の最大の文字数。 警告: !!これより長いユーザ名を持つ既存のユーザはログインできなくなります!!" + min_password_length: "パスワードの最小の長さ" + block_common_passwords: "最もよく使われている10,000個のパスワードはパスワードとして許可しない" + enable_sso: "外部サイトを経由したシングルサインオンを有効にします(警告:適切に設定されていない場合、あなたを含む誰もログインできなくなります。また、招待も無効にします)" + enable_sso_provider: "Discourse SSO provider プロトコルを /session/sso_provider エンドポイントに実装し、sso_secretの設定が必須です" + sso_url: "シングルサインオンエンドポイントのURL" + sso_secret: "SSO認証情報の暗号化に利用する秘密の文字列。10文字以上である必要があります" + sso_overrides_email: "SSOペイロードから取得した外部サイトのメールアドレスでローカルのメールアドレスを上書きする(警告: 不一致が原因でローカルのメールアドレスの正規化が発生する可能性があります)" + sso_overrides_username: "SSOペイロードから取得した外部サイトのユーザ名でローカルのユーザ名を上書きする(警告: 不一致が原因でユーザ名の長さ/要件に違いがでる可能性があります) " + sso_overrides_name: "SSOペイロードから取得した外部サイトの名前でローカルの名前を上書きする(警告: 不一致が原因でユーザの正規化が発生する可能性があります) " + sso_overrides_avatar: "SSOペイロードから取得した外部サイトのプロフィール画像でローカルのプロフィール画像を上書きする。有効にする場合、プロフィール画像のアップデートを無効にする事を強く薦めます" + enable_local_logins: "ローカルのユーザ名、パスワードでのログインを有効にする (注意: 招待を使用するには有効にする必要があります)" + allow_new_registrations: "新規ユーザー登録を許可。誰でもユーザーを作れるのを防ぐには、チェックを外してください。" enable_yahoo_logins: "Yahoo 認証を有効にする" + google_oauth2_client_id: "あなたのGoogleアプリケーションのクライアントID" enable_twitter_logins: "Twitter 認証を有効にする (twitter_consumer_key と twitter_consumer_secret の設定が必要)" twitter_consumer_key: "Twitter 認証用の consumer key。http://dev.twitter.com で入手可能" twitter_consumer_secret: "Twitter 認証用の consumer secret。http://dev.twitter.com で入手可能" @@ -478,25 +711,156 @@ ja: enable_github_logins: "Github 認証を有効にする (github_client_id と github_client_secret の設定が必要)" github_client_id: "Github 認証用の client id。https://github.com/settings/applications で入手可能" github_client_secret: "Github 認証用の client secret。https://github.com/settings/applications で入手可能" + allow_restore: "全てのサイトのデータをリプレイスするリストアを許可! バックアップからのリストアを行うとき以外はfalseのままにしてください" + maximum_backups: "ディスクに保存するバックアップの最大数。古いバックアップは自動的に削除されます" + backup_daily: "毎日自動的にサイトのバックアップを作成します" + enable_s3_backups: "完了時にS3にバックアップをアップロードします。重要: 有効なS3 credentialsがファイル設定に必要です" + s3_backup_bucket: "バックアップを保持するバケット。 警告: 必ずプライベートバケットになっていることを確認してください" active_user_rate_limit_secs: "'last_seen_at' フィールドを更新する頻度 (秒)" 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: "ポスト投稿後、次のポストを投稿するまでに新規ユーザが待たなければならない時間 (秒)" + max_likes_per_day: "ユーザが一日に「いいね!」できる最大数" + max_flags_per_day: "ユーザーが一日にフラグを立てる最大数" + max_bookmarks_per_day: "ユーザが一日にブックマークできる最大数" + max_edits_per_day: "ユーザが一日に編集できる最大数" + max_topics_per_day: "ユーザが一日に作成できるトピックの最大数" + max_private_messages_per_day: "ユーザが一日に作成できるプライベートメッセージの最大数" + max_invites_per_day: "ユーザが一日に招待できる最大数" + suggested_topics: "トピック下部に表示されるおすすめトピックの数" + limit_suggested_to_category: "現在参照しているトピックのカテゴリからトピックをサジェストする" + clean_up_uploads: "不正アップロードを防ぐためにどこからも参照されていないアップロードファイルを削除する。警告: この設定を有効にする前に /uploads ディレクトリのバックアップを取ることをおすすめします" clean_orphan_uploads_grace_period_hours: "どこからもリンクされていないアップロードファイルを削除するまでの猶予期間 (単位:時間)。" purge_deleted_uploads_grace_period_days: "削除されたアップロードファイルが完全削除されるまでの猶予期間 (単位:日)。" + purge_unactivated_users_grace_period_days: "アクティベートしていないユーザが削除されるまでの猶予期間 (日)" + enable_s3_uploads: "Amazon S3にアップロードします。重要: 有効なS3 credentials(access key id & secret access key)が必要です" + s3_use_iam_profile: 'キーの取得にAWS EC2 IAM roleを使用する 注意: 有効にすると、s3 access key id" と "s3 secret access key"の設定を上書きします' + s3_upload_bucket: "ファイルをアップロードする Amazon S3のバケット名。 警告: 小文字である必要があり、ピリオドとアンダースコアを含むことはできません" + s3_access_key_id: "画像をアップロードするAmazonS3のaccess key id" + s3_secret_access_key: "画像をアップロードする Amazon S3 の secret access key" + s3_region: "画像をアップロードする Amazon S3 のリージョン名" + enable_flash_video_onebox: "onebox で、swf の埋め込みと flv(Adobe Flash) リンクを許可する。注意: セキュリティリスクになる可能性があります" + default_invitee_trust_level: "招待したユーザのデフォルトトラストレベル(0-4)" + default_trust_level: "新規ユーザのデフォルトトラストレベル(0-4)" + tl1_requires_topics_entered: "新規ユーザがトラストレベル1に昇格するために作成しなければならないトピックの数" + tl1_requires_read_posts: "新規ユーザがトラストレベル1に昇格するために閲覧しなければらないポストの数" + tl1_requires_time_spent_mins: "新規ユーザがトラストレベル1に昇格するためにポストを読まなければならない時間 (分)" + tl2_requires_topics_entered: "トラストレベル2に昇格するために作成しなければならないトピックの数" + tl2_requires_read_posts: "トラストレベル2に昇格するために閲覧しなければならないポストの数" + tl2_requires_time_spent_mins: "トラストレベル2に昇格するためにポストを読まなければならない時間(分)" + tl2_requires_days_visited: "トラストレベル2に昇格するためにサイトを訪問しなければない日数" + tl2_requires_likes_received: "トラストレベル2に昇格するためにもらわなければならない「いいね!」の数" + tl2_requires_likes_given: "トラストレベル2に昇格するためにしなければならない「いいね!」の数" + tl2_requires_topic_reply_count: "トラストレベル2に昇格するために回答しなければいけないトピックの数" + tl3_requires_days_visited: "トラストレベル3に昇格するために必要な、最後の100日の間にサイトを訪れた日数 (0-100)" + tl3_requires_topics_replied_to: "トラストレベル3に昇格するために必要な最後の100日の間に返信したトピックの数(0 or higher)" + tl3_requires_topics_viewed: "トラストレベル3に昇格するために必要な、最後の100日の間に作成されたトピックを閲覧した割合(0 to 100)" + tl3_requires_posts_read: "トラストレベル3に昇格するために必要な、最後の100日の間に作成されたポストを閲覧した割合(0 to 100)" + tl3_requires_topics_viewed_all_time: "トラストレベル3に昇格するために必要な、トピックを閲覧した合計" + tl3_requires_posts_read_all_time: "トラストレベル3に昇格するために必要なユーザが閲覧したポストの合計" + tl3_requires_max_flagged: "トラストレベル3に昇格するためには、 最後の100日の間に投稿がx個以上x人の違うユーザにフラグを立てられてはいけない。xが設定値です(0 or higher)" + tl3_promotion_min_duration: "トラストレベル3に昇格したユーザが、トラストレベル2に降格しない日数" + tl3_requires_likes_given: "トラストレベル3に昇格するために、最後の100日の間にしなければならない「いいね!」の数" + tl3_requires_likes_received: "トラストレベル3に昇格するために、最後の100日の間にもらわなければならない「いいね!」の数" + 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つのトピックで誰かがそれに回答するまでに回答できる最大数" + max_mentions_per_post: "ユーザがポスト内で@name で通知できる最大数" + create_thumbnails: "大きすぎる画像はポストにフィットするように、サムネイルを作成しlightbox 画像を作成する" + email_time_window_mins: "ユーザによるポストの最終編集チャンスを与えるために、通知用メール送信までに待つ時間 (分)" + email_posts_context: "通知メールのコンテンツに含める回答の数" + flush_timings_secs: "サーバにタイミングデータを送信する頻度 (秒)" + max_word_length: "トピックタイトルの最大文字数" + title_min_entropy: "トピックタイトルの最小許容エントロピー (ユニークキャラクターや英語以外の単語を含むとより大きな値になります)" + body_min_entropy: "ポスト本文の最小許容エントロピー (ユニークキャラクターや英語以外の単語を含むとより大きな値になります)" title_fancy_entities: "トピックタイトルの一般的な ASCII 文字をファンシーな HTML エンティティに変換する; SmartyPants http://daringfireball.net/projects/smartypants/" + min_title_similar_length: "類似トピックのチェックに必要な最小タイトル長" + min_body_similar_length: "類似トピックのチェックに必要なポスト本文の最小長" + category_colors: "カテゴリに利用可能な色 (16進数指定) のリスト" + category_style: "カテゴリバッジのスタイル" + max_image_size_kb: "アップロード可能な画像の最大サイズ (kB) nginx 側での設定 (client_max_body_size) / apache または proxy における設定も同時に行う必要があります" + max_attachment_size_kb: "添付可能なファイルの最大サイズ (kB) nginx 側での設定 (client_max_body_size) / apache または proxy における設定も同時に行う必要があります" + authorized_extensions: "アップロード可能なファイルの拡張子のリスト('*'で全ての拡張子が有効になります)" + max_similar_results: "新規トピック編集中に類似トピックをいくつ表示するか。比較はタイトルと本文に基づきます" title_prettify: "よくあるタイトルのミススペルや文法エラー (例: 最初の文字が小文字、文の最後で ! や ? や . などが重複) を防止する" + topic_views_heat_low: "多くの閲覧があると、このフィールドはやや強調されます" + topic_views_heat_medium: "多くの閲覧があると、このフィールドは適度に強調されます" + topic_views_heat_high: "多くの閲覧があると、このフィールドは強く強調されます" + cold_age_days_low: "議論が何日も続くと、更新日がやや強調されます" + cold_age_days_medium: "議論が何日も続くと、更新日が適度に強調されます" + cold_age_days_high: "議論が何日も続くと、更新日が強く強調されます" + history_hours_low: "数時間以内に編集したポストは、編集インジケーターがやや強調されます" + history_hours_medium: "数時間以内に編集したポストは、編集インジケーターが適度に強調されます" + history_hours_high: "数時間以内に編集したポストは、編集インジケーターが強く強調されます" + topic_post_like_heat_low: "いいね数/ ポスト数の比率がこの比率を超えると、ポスト数のフィールドがやや強調されます" + topic_post_like_heat_medium: "いいね数/ ポスト数の比率がこの比率を超えると、ポスト数のフィールドが適度に強調されます" + topic_post_like_heat_high: "いいね数/ ポスト数の比率がこの比率を超えると、ポスト数のフィールドが強く強調されます" faq_url: "他サイトに FAQ をホストしている場合は、フル URL をここに指定。" tos_url: "他サイトに利用規約をホストしている場合は、フル URL をここに指定。" privacy_policy_url: "他サイトにプライバシーポリシーをホストしている場合は、フル URL を個々に指定。" newuser_spam_host_threshold: "新規ユーザが、スパム認定されることなく `newuser_spam_host_posts` ポスト内にに同一ホストへのリンクを貼ることができる数。" + white_listed_spam_host_domains: "スパムホスト検査から除外するドメインのリスト。新規ユーザはこれらのドメインでポスト内にリンクを作成することを制限されません" + staff_like_weight: "スタッフにより「いいね!」された場合、どのくらい重み付けをするか" + topic_view_duration_hours: "N時間毎にトピックを参照したIP/ユーザをカウント" + levenshtein_distance_spammer_emails: "スパマーのメールアドレスとマッチさせるとき、数文字違いの曖昧な一致でも許可する" + max_new_accounts_per_registration_ip: "もし既にトラストレベル0のユーザーがそのIPから(N)個作成されていたら、そのIPから登録できないようにする(スタッフメンバー、トラストレベル2以上は除く)" + num_flaggers_to_close_topic: "介入するため、自動的にトピックを停止するために必要なフラグを付けたユニークユーザの数" + num_flags_to_close_topic: "トピックの介入のため、自動的にトピックを停止するために必要なフラグの数" + auto_respond_to_flag_actions: "フラグを解除時の自動返信を有効にする" + reply_by_email_enabled: "メールでのトピックへの返信を有効化する" reply_by_email_address: "メールアドレスによる回答のテンプレート。例: %{reply_key}@reply.myforum.com" + disable_emails: "Discourseからの全ての種類のメール送信を止める" + strip_images_from_short_emails: "メールのサイズが2800 Bytesを超えないように画像を削除する" + short_email_length: "ショートメールのバイト数" + pop3_polling_enabled: "メール回答のために POP3 をポーリングする" + pop3_polling_ssl: "POP3サーバへSSL接続する(推奨)" + pop3_polling_period_mins: "メールのためのPOP3アカウントを確認する期間(分) 注意: 再起動が必要" + pop3_polling_port: "ポーリングを行うPOP3アカウントのポート" + pop3_polling_host: "ポーリングを行うPOP3のホスト" + pop3_polling_username: "ポーリングを行うPOS3アカウントのユーザ名" + pop3_polling_password: "ポーリングを行うPOS3アカウントのパスワード" + email_in: "ユーザにメールでのトピック作成を許可する(POP3ポーリングが必須) 。設定タブでカテゴリ毎に設定してください" + email_in_min_trust: "メールでのトピック作成を許可する最低トラストレベル" + email_prefix: "メールのタイトルに使用される[ラベル]。空白の場合、タイトルがデフォルトで使用されます" + email_site_title: "サイトからのメールの送信者として使用されるタイトル。 空白の場合、タイトルがデフォルトで使用されます。タイトルにメールの送信者として使用できない文字列が含まれている場合、この設定を使用します" + minimum_topics_similar: "類似トピック表示のために存在しなければならないトピック数" + relative_date_duration: "ポスト投稿後、ポスト投稿日が相対表示 (例: 7d)から絶対表示(例: Feb 20)に変わるまでの日数" + delete_user_max_post_age: "最初のポストが(x)日よりも古いユーザは削除しない" delete_all_posts_max: "すべてのポストを削除ボタンで一度に削除可能な最大ポスト数。ユーザがここで指定した以上のポストを投稿していた場合は、一度に全ポストを削除することができません。またユーザも削除されません。" username_change_period: "ユーザ名の変更が可能になるまでの登録日からの日数 (0を指定でユーザ名の変更自体を無効化)。" email_editable: "登録後、ユーザによるメールアドレスの変更を許可する。" + logout_redirect: "ログアウト後にリダイレクトするページ eg: (http://somesite.com/logout)" + allow_uploaded_avatars: "プロフィール画像のアップロードを許可" + allow_animated_avatars: "プロフィール画像としてアニメgifをアップロードするのを許可。警告: この設定を変更した場合 avatars:refresh rakeタスクを実行すること" + allow_animated_thumbnails: "アニメgifからアニメーションサムネイルを生成する" + default_avatars: "新規ユーザが変更するまで使用されるデフォルトのプロフィール画像URL" + automatically_download_gravatars: "アカウントの生成時、メールアドレスの変更時にGravatarをダウンロード" + digest_topics: "ダイジェストメールに表示されるトピックの最大数" + digest_min_excerpt_length: "ダイジェストメール内の投稿の抜粋の最小文字数" default_digest_email_frequency: "ユーザがダイジェストメールを受け取る頻度のデフォルト値。ユーザは設定画面でこの値をカスタマイズできます。" + suppress_digest_email_after_days: "(n)日以上ユーザが参照していなければダイジェストメールを抑制します" + disable_digest_emails: "全てのユーザのダイジェストメールを無効にする" + default_external_links_in_new_tab: "外部リンクは新しいタブで開きます。ユーザーはこの設定を変更する事が出来ます" + detect_custom_avatars: "ユーザがプロフィール画像をアップロードしたか確認する" + max_daily_gravatar_crawls: "Discourseがプロフィール画像の確認をgravastarに行う回数の上限" + public_user_custom_fields: "パブリックに公開されるカスタムフィールドのホワイトリスト" + staff_user_custom_fields: "スタッフが参照できるカスタムフィールドのホワイトリスト" + allow_profile_backgrounds: "プロフィール背景のアップロードを許可" + sequential_replies_threshold: "ユーザに連続回答が多すぎることをリマインドする、連続ポスト投稿のしきい値" enable_mobile_theme: "モバイル端末にモバイル向けテーマ (通常サイト用テーマにスイッチ可能) を利用する。レスポンシブなスタイルシートを使用する場合はこの設定を無効にしてください。" + dominating_topic_minimum_percent: "ユーザがトピックを占拠しているとリマインドを行う、ポスト投稿支配率 " + suppress_uncategorized_badge: "トピック一覧でカテゴライズされていないトピックのバッジは表示しない" + global_notice: "緊急の内容を表示します。全ての訪問者の緊急バナーで注意を行います。隠すには空白に変更してください(HTMLが許可されています)" short_progress_text_threshold: "プログレスバーが現在のポスト番号のみを表示するようになるポスト数のしきい値。プログレスバーの幅を変更した際には、この値を変更することをおすすめします。" default_code_lang: "Github コードブロックにデフォルトで適用されるプログラム言語シンタックスハイライト (lang-auto, ruby, python 等)" + enable_emoji: "絵文字を有効にする" notification_types: mentioned: "%{link} で %{display_username} があなたをタグ付けしました" liked: "%{link} で %{display_username} があなたのポストを「いいね!」しました" @@ -557,6 +921,11 @@ ja: subject_template: "%{site_name} へようこそ!" welcome_invite: subject_template: "%{site_name}へようこそ!" + restore_succeeded: + subject_template: "復元が正常に完了しました" + text_body_template: "復元に成功しました" + restore_failed: + subject_template: "復元に失敗しました" too_many_spam_flags: subject_template: "新規アカウントのブロック" blocked_by_staff: @@ -577,6 +946,7 @@ ja: [管理者セクションで確認する](/admin/users/list/pending). unsubscribe_link: "メール解除は [ユーザ設定画面](%{user_preferences_url}) で行ってください。" + subject_re: "Re:" user_notifications: previous_discussion: "以前の回答" unsubscribe: diff --git a/config/locales/server.ko.yml b/config/locales/server.ko.yml index 875572ceee..3d0593028b 100644 --- a/config/locales/server.ko.yml +++ b/config/locales/server.ko.yml @@ -463,7 +463,6 @@ ko: sidekiq_warning: 'Sidekiq 이 현재 실행되고 있지 않습니다. Sidekiq는 이메일 전송 같은 많은 작업들을 비동기식으로 처리합니다. 적어도 하나의 sidekiq 프로세서를 실행시켜 주세요. Sidekiq 배우기.' queue_size_warning: '큐 작업의 수가 %{queue_size} 개 입니다. 너무 많습니다. Sidekqi에 문제가 있을 수 있습니다. Sidekiq Worker를 더 추가하세요.' memory_warning: '당신의 서버는 1GB 이하 메모리로 실행되고 있습니다. 적어도 1GB 이상의 메모리를 사용하세요.' - enable_google_logins_warning: "곧 서비스 종료될 Google OpenID 인증 버젼을 사용 중입니다. Google은 해당 OpenID인증 서비스를 2015sus 4월 20일 부로 종료합니다. 가능한 빨리 Google OAuth2 인증을 사용해주세요. 자세히 알아보기" both_googles_warning: "이 사이트 세팅에서 Google OpenID 인증과 Google OAuth2 인증을 동시에 사용하기로 체크하였습니다. Google OpenID인증 설정(enable_google_logins)을 비활성화 해주세요." google_oauth2_config_warning: 'Google OAuth2 인증을 통한 로그인과 회원가입(enable_google_oauth2_logins)을 설정하였습니다. 하지만, 아직 Client ID와 Client Secret을 입력하지 않았습니다. the Site Settings and update the settings. 자세히 알아보기.' facebook_config_warning: '당신의 서버는 페이스북을 통한 가입을 설정하였습니다(enable_facebook_logins), 그러나 app id와 app secret 값을 입력하지 않았습니다. 사이트 설정 에서 업데이트 해주세요. 가이드 읽어보기.' diff --git a/config/locales/server.nl.yml b/config/locales/server.nl.yml index dea1e7acc2..8c0e167331 100644 --- a/config/locales/server.nl.yml +++ b/config/locales/server.nl.yml @@ -18,6 +18,8 @@ nl: log_in: "Inloggen" via: "%{username} via %{site_name}" is_reserved: "is gereserveerd" + purge_reason: "Automatisch verwijderd, account is nooit geactiveerd" + disable_remote_images_download_reason: "Het downloaden van plaatjes is uitgeschakeld omdat er niet genoeg schijfruimte beschikbaar is." errors: format: '%{attribute} %{message}' messages: @@ -34,6 +36,7 @@ nl: exclusion: is gereserveerd greater_than: moet groter zijn dan %{count} greater_than_or_equal_to: moet groter zijn dan of gelijk zijn aan %{count} + inclusion: komt niet voor in de lijst invalid: is ongeldig less_than: moet minder zijn dan %{count} less_than_or_equal_to: moet minder zijn dan of gelijk zijn aan %{count} @@ -41,6 +44,9 @@ nl: not_an_integer: moet een integer zijn odd: moet oneven zijn record_invalid: 'Validatie mislukt: %{errors}' + restrict_dependent_destroy: + one: "Kan record niet verwijderen omdat %{record} hiervan afhankelijk is" + many: "Kan record niet verwijderen omdat %{record} hiervan afhankelijk is" too_long: one: is te lang (maximum is één teken) other: is te lang (maximum is %{count} tekens) @@ -50,6 +56,12 @@ nl: wrong_length: one: is de verkeerde lengte (moet één teken zijn) other: is de verkeerde lengte (moet %{count} tekens zijn) + other_than: "moet anders zijn dan %{count}" + template: + body: 'De volgende velden bevatten fouten:' + header: + one: 1 fout voorkomt dat deze %{model} opgeslagen kan worden + other: '%{count} fouten voorkomen dat deze %{model} opgeslagen kan worden' embed: load_from_remote: "Er ging iets mis bij het laden van dat bericht." bulk_invite: @@ -59,6 +71,8 @@ nl: backup_file_should_be_tar_gz: "Het backupbestand moet een .tar.gz archief zijn." not_enough_space_on_disk: "Er is niet voldoende ruimte op de schijf vrij om deze backup te uploaden." not_logged_in: "Om dat te kunnen doen moet je ingelogd zijn." + not_found: "De opgevraagde URL of resource kan niet gevonden worden." + invalid_access: "Je hebt geen permissie om de opgevraagde resource te bekijken." read_only_mode_enabled: "De site is in read only modus. Interactie is niet mogelijk." too_many_replies: one: "Sorry, nieuwe gebruikers mogen één reactie plaatsen in hetzelfde topic." @@ -98,6 +112,7 @@ nl: other: "Sorry, nieuwe leden kunnen %{count} links in een bericht opnemen." spamming_host: "Sorry, je kan niet linken naar die host." user_is_suspended: "Geschorste gebruikers mogen geen berichten meer plaatsen." + topic_not_found: "Er is iets fout gegaan. Wellicht is het topic gesloten of verwijderd terwijl je er naar keek?" just_posted_that: "lijkt teveel op het bericht dat je net geschreven hebt" has_already_been_used: "is al eens gebruikt" invalid_characters: "bevat ongeldige tekens" @@ -163,6 +178,14 @@ nl: Heb je al overwogen **[om naar je profielpagina te gaan](%{profile_path})** om een nieuwe afbeelding van jou te uploaden? Het is makkelijker om conversaties te volgen en interessante mensen te vinden als iedereen een unieke avatar heeft! + sequential_replies: | + ### Overweeg om op meerdere berichten ineens te reageren + + In plaatst van een reactie per bericht te plaatsten, kan je ook meerdere berichten ineens citeren en @namen noemen in je reactie. + + Je kan je vorige reactie wijzigen en er een citaat aan toevoegen door de betreffende tekst te selecteren en op de citeer knop te drukken die dan verschijnt. + + Het is voor iedereen makkelijker om topics te lezen met minder losstaande reacties. dominating_topic: | ### Laat anderen meedoen in de conversatie @@ -199,11 +222,14 @@ nl: base: warning_requires_pm: "Je kunt alleen waarschuwingen aan privéberichten toevoegen." too_many_users: "Je kunt een waarschuwing per keer slechts naar één ander lid sturen." + cant_send_pm: "Sorry, je kan geen privébericht sturen naar deze persoon." no_user_selected: "Je moet een geldige gebruiker selecteren." user: attributes: password: common: "is een van de 10000 meest gebruikte wachtwoorden. Gebruik een veiliger wachtwoord." + same_as_username: "is hetzelfde als je gebruikersnaam. Gebruik een veiliger wachtwoord." + same_as_email: "is hetzelfde als je email. Gebruik een veiliger wachtwoord." ip_address: signup_not_allowed: "Inschrijven vanaf dit account is niet toegestaan." color_scheme_color: @@ -374,6 +400,8 @@ nl: email_body: "%{link}\n\n%{message}" notify_moderators: title: "Iets anders" + description: 'Dit bericht heeft de aandacht van een moderator nodig om een andere reden dan hier boven gespecificeerd.' + long_form: 'heeft dit gemarkeerd voor moderatie' email_title: 'Graag aandacht van een moderator voor een bericht in ''%{title}''' email_body: "%{link}\n\n%{message}" bookmark: @@ -400,6 +428,7 @@ nl: notify_moderators: title: "Iets anders" description: 'Dit topic moet door een moderator bekeken worden. Dit vanwege de regels, voorwaarden of vanwege een andere reden.' + long_form: 'heeft dit gemarkeerd voor moderatie' email_title: 'De topic "%{title}" moet door een moderator worden bekeken' email_body: "%{link}\n\n%{message}" flagging: diff --git a/config/locales/server.pl_PL.yml b/config/locales/server.pl_PL.yml index 54d66c354a..f7a7cc78f2 100644 --- a/config/locales/server.pl_PL.yml +++ b/config/locales/server.pl_PL.yml @@ -602,7 +602,6 @@ pl_PL: sidekiq_warning: 'Sidekiq nie działa. Wiele zadań, takich jak wysyłanie emaili, jest wykonywane asynchronicznie przez sidekiqa. Zagwarantuj, że przynajmniej jeden proces sidekiqa działa. Dowiedz się więcej o Sidekiqu.' queue_size_warning: 'Długość kolejki prac to %{queue_size}. To dużo. Może to oznaczać problem z Sidekiq lub konieczność zwiększenia ilości jego procesów.' memory_warning: 'Twój serwer działa z mniej niż 1 GB pamięci całkowitej. Przynajmniej 1 GB pamięci jest zalecany.' - enable_google_logins_warning: "Używasz przestarzałej wersji uwierzytelniania: Google OpenID. Google wyłączy OpenID 20 kwietnia 2015. Zacznij używać Google OAuth2 jak najszybciej. Zobacz ten przewodnik, aby dowiedzieć się więcej" both_googles_warning: "W ustawieniach serwisu włączono zarówno enable_google_logins jak i enable_google_oauth2_logins. Wyłącz enable_google_logins." google_oauth2_config_warning: 'Serwis umożliwia rejestrację i logowanie poprzez Google OAuth2 (enable_google_oauth2_logins), ale ''client id'' oraz ''client secret'' nie są jeszcze ustawione. Przejdź do Ustawień i wprowadź te wartości. Zobacz ten przewodnik, aby dowiedzieć się więcej.' facebook_config_warning: 'Serwer jest skonfigurowany by pozwalać na rejestrację i logowanie za pomocą Facebooka (enable_facebook_logins), ale identyfikator i sekret aplikacji nie są ustawione. Przejdź do ustawień serwisu i zmień ustawienia. Zobacz ten poradnik by dowiedzieć się więcej.' diff --git a/config/locales/server.pt.yml b/config/locales/server.pt.yml index 7902c71be7..5f05aee852 100644 --- a/config/locales/server.pt.yml +++ b/config/locales/server.pt.yml @@ -492,7 +492,6 @@ pt: sidekiq_warning: 'Sidekiq não está em execução. Muitas tarefas, como envio de emails, são executadas de forma assíncrona pelo sidekiq. Por favor certifique-se de que pelo menos um processo sidekiq está em execução. Aprenda sobre Sidekiq aqui.' queue_size_warning: 'O número de tarefas agendadas é %{queue_size}, o que é alto. Isto pode indicar um problema com o(s) processo(s) Sidekiq, ou pode estar a precisar de mais "Sidekiq workers".' memory_warning: 'O seu servidor está a executar com menos de 1 GB de memória total. Pelo menos 1 GB é a quantidade de memória recomendada.' - enable_google_logins_warning: "Está a usar uma versão obsoleta da autenticação do OpenID da Google. A Google irá terminar o suporte do OpenID em 20 de Abril de 2015. Comece a usar o OAuth2 da Google assim que possível. Verifique este guia para aprender mais" both_googles_warning: "Tanto enable_google_logins e enable_google_oauth2_logins estão assinalados nas configurações do sítio. Desative enable_google_logins." google_oauth2_config_warning: 'O servidor está configurado para permitir inscrever-se e entrar com o Google OAuth2 (enable_google_oauth2_logins), mas o id e os valores privados do cliente não estão configurados. Vá às Configurações do Sítio e atualize as definições. Veja este guia para saber mais.' facebook_config_warning: 'O servidor está configurado para permitir inscrever-se e entrar com o Facebook (enable_facebook_logins), mas o id e os valores privados da aplicação não estão configurados. Vá às Configurações do Sítio e atualize as definições. Veja este guia para saber mais.' @@ -813,7 +812,6 @@ pt: default_code_lang: "Linguagem de programação por defeito a aplicar no destaque da sintaxe em blocos de código GitHub (lang-auto, ruby, python, etc.)" warn_reviving_old_topic_age: "Quando alguém começa a responder a um tópico em que a última resposta é mais antiga que estes dias, um aviso será exibido. Desativar ao configurar para 0." autohighlight_all_code: "Forçar o destaque do código a todos os blocos de código pré-formatados mesmo quando não se especifica a linguagem." - embeddable_host: "Servidor que pode incorporar os comentários deste fórum Discourse." feed_polling_enabled: "INCORPORAR APENAS: incorporar feeds RSS/ATOM como mensagens." feed_polling_url: "INCORPORAR APENAS: URL dos feeds de RSS/ATOM para embutir." embed_by_username: "Nome de utilizador Discourse do utilizador que cria tópicos embebidos." diff --git a/config/locales/server.pt_BR.yml b/config/locales/server.pt_BR.yml index 45076ebbe2..243abf5c09 100644 --- a/config/locales/server.pt_BR.yml +++ b/config/locales/server.pt_BR.yml @@ -580,7 +580,6 @@ pt_BR: sidekiq_warning: 'Sidekiq não está em execução. Muitas tarefas, como envio de emails, são executadas de forma assíncrona pelo sidekiq. Por favor certifique-se de que ao menos um processo sidekiq esteja execução. Aprenda sobre Sidekiq aqui.' queue_size_warning: 'O número de tarefas agendadas é %{queue_size}, o que é alto. Isto pode indicar um problema com o(s) processo(s) Sidekiq, ou você pode estar precisando de mais Sidekiq workers.' memory_warning: 'Seu servidor está rodando com menos de 1 GB de memória total. Pelo menos 1 GB é quantidade de memória recomendada.' - enable_google_logins_warning: "Você está usando uma versão descontinuada da autenticação Google's OpenID. Google vai parar de dar suporte para o OpenID em 20 de Abril de 2015. Comece a usar o Google OAuth2 assim que possível. Veja esse guia para entender mais" both_googles_warning: "Você tem enable_google_logins e enable_google_oauth2_logins ativados nas configurações do site. Desative o enable_google_logins." google_oauth2_config_warning: 'O servidor está configurado para permitir o signup e login com Google OAuth2 (enable_google_oauth2_logins), mas os valores de Cliend Id e Secret não estão configurados. Vá para as Configurações do Site e atualize as configurações. Veja este guia e aprenda mais.' facebook_config_warning: 'O servidor está configurado para permitir o signup e login com Facebook (enable_facebook_logins), mas os valores do App Id e App Secret não estão configurados. Vá para as Configurações do Site e atualize as configurações. Veja este guia e aprenda mais.' @@ -918,7 +917,6 @@ pt_BR: default_code_lang: "Realce de sintaxe padrão da linguagem de programação aplicada a blocos de código GitHub (lang-auto, Ruby, Python, etc)" warn_reviving_old_topic_age: "Quando alguém começa a responder a um tópico mais velho do que este número de dias, um aviso será exibido para desencorajar o usuário de reviver uma velha discussão. Desabilite definindo para 0." autohighlight_all_code: "Aplicar código destacando todos os blocos de código pré-formatados, mesmo quando não for específica o idioma" - embeddable_host: "Host que pode incorporar os comentários deste fórum do Discourse" feed_polling_enabled: "Se um feed RSS / ATOM são importados como mensagens" feed_polling_url: "URL do feed RSS / ATOM para importar" embed_by_username: "Nome de usuário Discourse para o usuário que cria os tópicos" @@ -1095,8 +1093,6 @@ pt_BR: %{base_url}/users/password-reset/%{email_token} test_mailer: subject_template: "[%{site_name}] Teste de entrega de email" - text_body_template: "Este é um email de teste de\n\n[**%{base_url}**][0]\n\nEntregabilidade de email é complicada. Aqui estão algumas poucas coisas importantes que você deve verificar primeiro:\n\n- Esteja *certo* de definir o from: do `email de notificação` corretamente nas configurações do seu site. **O domínio especificado no endereço \"from\" dos emails que você envia é o domínio contra o qual o seu email será validado**.\n\n- Aprenda como ver o código cru de email no seu cliente de email, para que assim você possa examinar os cabeçalhos de email por pistas importantes. No Gmail, isso é a opção \"exibir original\" no menu drop-down no topo à direita de cada email.\n\n- **IMPORTANTE:** O seu provedor de acesso à internet possui um record de DNS reverso configurado para associar os nomes de domínio e endereços IP dos quais você envia email? [Teste seu record de PTR Reverso][2] aqui. Se o seu provedor de acesso à internet não configurar o record de DNS reverso apropriadamente, é muito pouco provável que qualquer do seu email será entregue.\n\n- O [record SPF][8] do seu domínio é correto? [Teste seu record SPF][1] aqui. Note que TXT \n é o tipo oficialmente correto de record para SPF.\n\n- O [record DKIM][3] do seu domínio é correto? Isso melhorará significativamente a entregabilidade de email. [Teste seu record DKIM][7] aqui.\n\n- Se você roda o seu próprio servidor de emails, verifique e certifique-se que os IPs do seu servidor de emails [não estão em quaisquer blacklists de emails][4]. Também verifique que ele esteja decisivamente enviando um fully-qualified hostname que se resolve em DNS em sua mensagem HELO. Caso contrário, isso fará com que seu email seja rejeitado por muitos serviços de email. \n\n(O modo *fácil* é criar uma conta grátis no [Mandrill][md] ou [Mailgun][mg] ou [Mailjet][mj], os quais têm generosos planos grátis de email e serão suficientes para pequenas comunidades. Você ainda precisará configurar os records SPF e DKIM no seu DNS, apesar disso!) \n\nNós esperamos que você tenha recebido este teste de entregabilidade de email OK!\n\nBoa sorte,\n\nSeus amigos do [Discourse](http://www.discourse.org)\n\n\ - [0]: %{base_url}\n[1]: http://www.kitterman.com/spf/validate.html\n[2]: http://mxtoolbox.com/ReverseLookup.aspx\n[3]: http://www.dkim.org/\n[4]: http://whatismyipaddress.com/blacklist-check\n[7]: http://dkimcore.org/tools/dkimrecordcheck.html\n[8]: http://www.openspf.org/SPF_Record_Syntax\n[md]: http://mandrill.com\n[mg]: http://www.mailgun.com/\n[mj]: https://www.mailjet.com/pricing\n" new_version_mailer: subject_template: "[%{site_name}] Nova versão do Discourse, atualização disponível" text_body_template: | diff --git a/config/locales/server.ru.yml b/config/locales/server.ru.yml index 7795a5f8b8..128f04af63 100644 --- a/config/locales/server.ru.yml +++ b/config/locales/server.ru.yml @@ -43,6 +43,12 @@ ru: not_a_number: не число not_an_integer: должно быть целым odd: должно быть нечетным + record_invalid: 'Ошибка валидации: %{errors}' + restrict_dependent_destroy: + one: "Невозможно удалить запись, т.к. существует зависимая запись: %{record}" + many: "Невозможно удалить запись, т.к. существует зависимая запись: %{record}" + template: + body: 'Обнаружены ошибки в следующих полях:' embed: load_from_remote: "Произошла ошибка при загрузке сообщения." bulk_invite: @@ -52,6 +58,8 @@ ru: backup_file_should_be_tar_gz: "Файл резервной копии должен быть архивом в формате .TAR.GZ." not_enough_space_on_disk: "Не хватает места на диске сервера для загрузки этой резервной копии." not_logged_in: "Для этого действия, пожалуйста авторизуйтесь." + not_found: "Запрашиваемая страница или ресурс не найден." + invalid_access: "У вас нет прав для просмотра запрашиваемого ресурса." read_only_mode_enabled: "Сайт в режиме только для чтения. Взаимодействия отключены." too_many_replies: one: "Извините, новые пользователи могут оставлять только один ответ к теме." @@ -94,6 +102,7 @@ ru: other: "Извините, новые пользователи могут размещать только %{count} ссылок в сообщении." spamming_host: "Извините, вы не можете разместить ссылку в этом сообщении." user_is_suspended: "Заблокированным пользователям запрещено писать." + topic_not_found: "Что-то пошло не так. Возможно, эта тема была закрыта или заархивирована, пока вы ее читали?" just_posted_that: "слишком схоже с уже опубликованным Вами сообщением" has_already_been_used: "уже было использовано" invalid_characters: "содержит недопустимые символы" @@ -163,6 +172,14 @@ ru: Вы можете изменить его, загрузив изображение **[на странице настроек](%{profile_path})** Очень удобно следить за обсуждениями и запоминать новых интересных людей, когда каждый имеет уникальный аватар! + sequential_replies: | + ### Рекомендуем вам совмещать ответы в одном сообщении + + Вместо множества отдельных сообщений с ответами, пожалуйста, используйте одно сообщение, которое включает в себя цитирование предыдущих сообщений или обращения по имени участника через механизм @имя. + + Вы можете изменить свой предыдущий ответ добавив цитирование просто выделяя требуемый текст и нажимая на всплывающую кнопку ответить цитированием. + + Для большинства участников проще читать темы, где есть небольшое число больших ответов вместо большого числа маленьких индивидуальных. dominating_topic: |2 Данная тема является для вас важной – количество ваших ответов превышает %{percent}% процентов. @@ -203,6 +220,8 @@ ru: attributes: password: common: "Вы пытаетесь использовать один из 10000 самых распространенных паролей. Используйте более сложный пароль. " + same_as_username: "совпадает с вашим псевдонимом. Пожалуйста, придумайте более надежный пароль." + same_as_email: "совпадает с вашим e-mail. Пожалуйста, придумайте более надежный пароль." ip_address: signup_not_allowed: "Регистрация с данной учетной записью запрещена." color_scheme_color: @@ -388,6 +407,7 @@ ru: description: 'Это реклама! Данное сообщение не представляет особого интереса или не относится к начальной теме. ' long_form: 'отмечено как СПАМ' email_title: '"%{title}" отмечено как спам' + email_body: "%{link}\n\n%{message}" inappropriate: title: 'Неуместно' description: 'Это сообщение может быть оскорбительным или нарушает правила поведения.' @@ -536,12 +556,15 @@ ru: page_view_logged_in_reqs: title: "Пользователи" xaxis: "Дата" + yaxis: "Авторизованные запросы API" page_view_crawler_reqs: title: "Поисковики" xaxis: "Дата" + yaxis: "Запросы API поисковиков и кравлеров" page_view_total_reqs: title: "Всего" xaxis: "Дата" + yaxis: "Всего запросов API" http_background_reqs: title: "Фоновые" xaxis: "Дата" @@ -551,11 +574,17 @@ ru: xaxis: "Дата" yaxis: "Запросов" http_3xx_reqs: + title: "HTTP 3xx (Переадресация)" xaxis: "День" + yaxis: "Переадресация (статус 3xx)" http_4xx_reqs: + title: "HTTP 4xx (ошибка клиента)" xaxis: "День" + yaxis: "Ошибки клиента (статус 4xx)" http_5xx_reqs: + title: "HTTP 5xx (ошибка сервера)" xaxis: "День" + yaxis: "Ошибки сервера (статус 5xx)" http_total_reqs: title: "Всего" xaxis: "День" @@ -568,7 +597,6 @@ ru: sidekiq_warning: 'Sidekiq не запущен. Сейчас многие задачи, такие как отправка электронных писем, выполняются асинхронно. Пожалуйста, убедитесь, что хотя бы один процесс sidekiq запущен. Узнайте больше о Sidekiq здесь.' queue_size_warning: 'Количество задач в очереди достигло большого размера %{queue_size}. Это может привести к проблемам с процессом(ами) Sidekiq, или вам придется добавить больше Sidekiq workers.' memory_warning: 'Общее количество памяти, используемое вашим сервером, составляет менее 1 GB. Рекомендовано использовать минимум 1 GB.' - enable_google_logins_warning: "Вы используете устаревшую версию аутентификации Google OpenID. Google выключит эту возможность 20 апреля 2015г. Переходите на Google OAuth2 как можно скорее. Более детальная информация по этой ссылке." both_googles_warning: "Обе опции включены в настройках сайта: enable_google_logins и enable_google_oauth2_logins. Выключите enable_google_logins." s3_config_warning: 'Сервер сконфигурирован на загрузку файлов в хранилище S3, однако не указаны некоторые значения из списка: s3_access_key_id, s3_secret_access_key или s3_upload_bucket. Перейдите в Настройки сайта и установите необходимые значения. Для получения дополнительной информации перейдите по ссылке How to set up image uploads to S3?.' s3_backup_config_warning: 'Сервер сконфигурирован на загрузку резервных копий в хранилище S3, однако не заданы все необходимые настройки : s3_access_key_id, s3_secret_access_key, s3_backup_bucket. Перейдите в настройки сайта и установите необходимые значения. Для получения дополнительной информации перейдите по ссылке How to set up image uploads to S3?.' @@ -640,12 +668,13 @@ ru: max_image_height: "Максимальная высота уменьшенных версий изображений, показываемых в сообщениях" category_featured_topics: "Количество тем, отображаемых для одного разделе на странице разделов. После изменения значения потребуется около 15 минут для обновления списков." show_subcategory_list: "Показывать список подразделов вместо списка тем на страницах разделов." - fixed_category_positions: "Если влючено, разделі можно будет отсортировать в определенном порядке. Иначе разделі будут отображаться в порядке активности в них." + fixed_category_positions: "Если влючено, разделы можно будет отсортировать в определенном порядке. Иначе разделы будут отображаться в порядке активности в них." add_rel_nofollow_to_user_content: "Добавить \"rel nofollow\" для всех ссылок за исключением внутренних (включая родительский домен). Изменение данной настройки потребует обновления всех сообщений с помощью команды \"rake posts:rebake\"" exclude_rel_nofollow_domains: "Разделенный знаком \"|\" список доменов, в которых nofollow не добавлено (tld.com автоматически задействует и sub.tld.com)" post_excerpt_maxlength: "Максимальная длина краткого изложения сообщения." post_onebox_maxlength: "Максимальная длина сообщения с форума Discourse в режиме умной вставки." onebox_domains_whitelist: "Список доменов, разрешенных для умной вставки. Эти домены должны поддерживать OpenGraph или oEmbed. Проверьте их по ссылке http://iframely.com/debug" + logo_url: "Логотип сайта, отображаемый сверху слева. Если оставить пустым, будет использован текст заголовка сайта." digest_logo_url: "Альтернативный логотип для использования вверху письма-дайджеста. Если оставить пустым, будет использован логотип из настройки `logo_url`. Пример: http://example.com/logo.png" favicon_url: "favicon вашего сайта, дополнительная информация: http://en.wikipedia.org/wiki/Favicon" apple_touch_icon_url: "Иконка используемая для тач-устройств Apple. Рекомендуемый размер 144 x 144 px." @@ -803,10 +832,10 @@ ru: enable_mobile_theme: "Мобильные устройства используют адаптированную тему с возможностью переключения в обычный вид. Отключите данную настройку если вы хотите использовать собственный стиль для мобильных устройств." suppress_uncategorized_badge: "Не показывать награду в списках тем для тех тем, которые вне разделов." global_notice: "Показать СРОЧНОЕ ВАЖНОЕ объявление на сайте всем пользователям и посетителям. Удалите содержание, чтобы отменить объявление. Разрешено использование HTML." + enable_names: "Отображать полное имя пользователя на его странице пользователя, карточке пользователя и в письмах. Выключите, чтобы спрятать полное имя отовсюду." display_name_on_posts: "Показывать полные имена пользователей в их сообщениях в дополнение к их @нику." short_progress_text_threshold: "После достижения указанного числа сообщений в теме, бар будет отображать только текущий номер сообщения. Если вы измените ширину бара, вы можете изменить это значение." default_code_lang: "Подсветка синтаксиса по умолчанию для блоков кода (lang-auto, ruby, python etc.)" - embeddable_host: "Хост (домен), на котором разрешено встраивать комментарии из этого форума." embed_truncate: "Обрезать встроенные сообщения." embed_post_limit: "Максимальное количество вложенных сообщений." show_create_topics_notice: "Если общее количество тем меньше 5, показывать персоналу соощбение с просьбой создать новые темы." @@ -861,6 +890,10 @@ ru: other: "%{count} сообщений перенесены в уже существующую тему: %{topic_link}" change_owner: post_revision_text: "Владелец сменен с %{old_user} на %{new_user}" + emoji: + errors: + name_already_exists: "Название \"%{name}\" уже используется для другой иконки." + error_while_storing_emoji: "Произошла ошибка во время сохранения иконки." topic_statuses: archived_enabled: "Эта тема отправлена в Архив. Она заморожена и не может быть изменена." archived_disabled: "Эта тема разархивирована. Она более не заморожена, и может быть изменена." @@ -905,6 +938,8 @@ ru: active: "Ваша учетная запись активирована и готова к использованию." activate_email: "

    Почти готово! Мы выслали письмо на %{email}. Пожалуйста, следуйте инструкциям в этом письме для активации вашей учетной записи.

    Если письмо не пришло, пожалуйста, проверьте папку \"спам\", или попробуйте войти еще раз, чтобы выслать активационное письмо повторно.

    " not_activated: "Вы пока что не можете войти на сайт. Пожалуйста, следуйте инструкциям по активации учетной записи, которые мы отправили вам по электронной почтой." + not_allowed_from_ip_address: "Вход с этого IP в качестве пользователя %{username} запрещен." + admin_not_allowed_from_ip_address: "Вход с этого IP в качестве администратора запрещен." suspended: "Вы не можете войти до %{date}." suspended_with_reason: "Вход запрещен до %{date}. Причина блокировки вашей учетной записи: %{reason}" errors: "%{errors}" @@ -1027,6 +1062,16 @@ ru: subject_template: "Сообщение скрыто по причине поступления множественных жалоб" welcome_user: subject_template: "Добро пожаловать на %{site_name}!" + text_body_template: | + Спасибо, что зарегистрировались на сайте %{site_name} и добро пожаловать! + + %{new_user_tips} + + Пожалуйста, старайтесь придерживаться [этики и правил вежливости](%{base_url}/guidelines). + + Приятного времяпровождения! + + (Если у вас имеются вопросы к [персоналу](%{base_url}/about), то можете задать их ответив на это личное сообщение.) welcome_invite: subject_template: "Добро пожаловать на %{site_name}!" backup_succeeded: diff --git a/config/locales/server.sq.yml b/config/locales/server.sq.yml index 7d1b278de0..c4a29a23c7 100644 --- a/config/locales/server.sq.yml +++ b/config/locales/server.sq.yml @@ -502,7 +502,6 @@ sq: sidekiq_warning: 'Sidekiq is not running. Many tasks, like sending emails, are executed asynchronously by sidekiq. Please ensure at least one sidekiq process is running. Learn about Sidekiq here.' queue_size_warning: 'The number of queued jobs is %{queue_size}, which is high. This could indicate a problem with the Sidekiq process(es), or you may need to add more Sidekiq workers.' memory_warning: 'Your server is running with less than 1 GB of total memory. At least 1 GB of memory is recommended.' - enable_google_logins_warning: "You are using a deprecated version of Google's OpenID authentication. Google will be ending support for OpenID by April 20, 2015. Start using Google OAuth2 as soon as possible. See this guide to learn more" both_googles_warning: "You have both enable_google_logins and enable_google_oauth2_logins checked in the site settings. Disable enable_google_logins." google_oauth2_config_warning: 'The server is configured to allow signup and log in with Google OAuth2 (enable_google_oauth2_logins), but the client id and client secret values are not set. Go to the Site Settings and update the settings. See this guide to learn more.' facebook_config_warning: 'The server is configured to allow signup and log in with Facebook (enable_facebook_logins), but the app id and app secret values are not set. Go to the Site Settings and update the settings. See this guide to learn more.' @@ -816,7 +815,6 @@ sq: default_code_lang: "Default programming language syntax highlighting applied to GitHub code blocks (lang-auto, ruby, python etc.)" warn_reviving_old_topic_age: "When someone starts replying to a topic where the last reply is older than this many days, a warning will be displayed. Disable by setting to 0." autohighlight_all_code: "Force apply code highlighting to all preformatted code blocks even when they didn't explicitly specify the language." - embeddable_host: "Host that can embed the comments from this Discourse forum." feed_polling_enabled: "EMBEDDING ONLY: Whether to embed a RSS/ATOM feed as posts." feed_polling_url: "EMBEDDING ONLY: URL of RSS/ATOM feed to embed." embed_by_username: "Discourse username of the user who creates the embedded topics." diff --git a/config/locales/server.te.yml b/config/locales/server.te.yml index b64e4ec144..607fed1ad1 100644 --- a/config/locales/server.te.yml +++ b/config/locales/server.te.yml @@ -112,6 +112,7 @@ te: other: "క్షమించాలి. కొత్త సభ్యులు ఒక టపాలో కేవలం %[count] లంకెలు మాత్రమే ఉంచ వీలవుతుంది." spamming_host: "క్షమించాలి. ఆ అతిధికి మీరు లంకె టపా చెయ్యలేరు." user_is_suspended: "సస్పెండైన సభ్యులు టపా రాయుట వీలవదు" + topic_not_found: "ఏదో తప్పు జరిగింది. బహుశా ఈ అంశం ముగిసింది లేదా మీరు చూస్తూ ఉండగా తొలగించబడింది?" just_posted_that: "ఇది ఇప్పుడే రాసిన విషయంలా ఉంది. డూప్లికేటు టపా?" has_already_been_used: "ఇప్పటికే వాడుకలో ఉంది." invalid_characters: "చెల్లని అక్షరాలు ఉన్నాయి." @@ -494,6 +495,7 @@ te: page_view_anon_reqs: title: "అనామక" xaxis: "రోజు" + yaxis: "అనామక API అభ్యర్ధనలు" page_view_logged_in_reqs: title: "లాగిన్ అయిన" xaxis: "రోజు" @@ -563,14 +565,17 @@ te: title: "లాగిన్ అవసరం: హోమ్‌పేజ్" description: "లాగిన్ సైట్లో అవసరం ఉన్నప్పుడు టెక్స్ట్ అనధికార వినియోగదారులకు ప్రదర్శించబడుతుంది." head: + title: "HTML హెడ్" description: "ట్యాగ్‌ల లోపల HTML ప్రవేశపెట్టబడింది." top: title: "పుటల యొక్క పై భాగంలో" + description: "HTML ప్రతి పేజీ ఎగువన చేర్చబడుతుంది(హెడర్ తర్వాత , దిశా నిర్దేశనానికి ముందు లేదా శీర్షికలో)" bottom: title: "పుటల అడుగు భాగం" description: "ట్యాగ్ చెయ్యక ముందే HTML ను కలుపుతారు." site_settings: censored_words: "వీటితో పదాలు స్వయంచాలకంగా భర్తీ చేయబడతాయి ■■■■" + delete_old_hidden_posts: "30 రోజుల కంటే ఎక్కువ దాగివున్న టపాలు స్వయంసిధ్ధంగా తొలగింపబడతాయి." default_locale: "ఈ సంభాషణ సమయంలో అప్రమేయ భాష (ISO 639-1 Code)" allow_user_locale: "వినియోగదారులు వారి సొంత భాష ఇంటర్ఫేస్ ప్రాధాన్యతను ఎంచుకోవడానికి అనుమతించు" min_post_length: "టపా అనుమతించే అక్షరాల కనిష్ఠ పొడవు" @@ -582,9 +587,13 @@ te: min_search_term_length: "శోధనకు అవసరమయ్యే అక్షరాల కనీస పొడవు" allow_uncategorized_topics: "అనుమతించే విషయాలు వర్గం లేకుండా సృష్టించబడుతున్నాయి." uncategorized_description: "వర్గీకరించని వర్గం యొక్క వివరణ. ఎటువంటి వివరణ లేని వాటిని ఖాళీగా వదిలివేయండి." + allow_duplicate_topic_titles: "సమరూపమైన,నకిలీ శీర్షికలతో విషయాలను అనుమతించు." unique_posts_mins: "ఒక వినియోగదారు ఎన్ని నిమిషాల తర్వాత మళ్ళీ అదే విషయంతో ఒక టపా చేయవచ్చు " + educate_until_posts: "వినియోగదారు వారి మొదటి (n) కొత్త టపాలు చేయడం మొదలుపెట్టినప్పుడు, కంపోజర్‌లో పాప్-అప్ కొత్త యూజర్ విద్య ప్యానెల్ చూపించు." title: "ఈ సైట్ యొక్క పేరు ,టైటిల్ ట్యాగ్ లో ఉపయోగించారు." site_description: "మెటా వివరణ ట్యాగ్ ఉపయోగించి ఈ సైట్‌ని ఒక వాక్యంలో వివరించండి." + download_remote_images_threshold: "సుదూర చిత్రాలను స్థానికంగా దిగుమతి చేయడానికి అవసరమయ్యే కనీస డిస్క్ స్థలం (శాతం లో)" + ninja_edit_window: "టపా చేసిన తర్వాత (n) సెకన్లు, టపా చరిత్రలో ఒక కొత్త కధనం సృష్టించడానికి సవరింపు కుదరదు." post_edit_time_limit: "రచయిత వారు చేసిన టపా (n) నిమిషాల తర్వాత సవరించవచ్చు లేదా తొలగించవచ్చు. ఎప్పటికీ 0 అమర్చుము." max_image_width: "ఒక టపాలో థంబ్నైల్ గరిష్ట వెడల్పు" max_image_height: "ఒక టపాలో థంబ్నైల్ గరిష్ట ఎత్తు" @@ -706,15 +715,19 @@ te: unknown_image_type: "క్షమించండి, మీరు ఎగుమతి చేయడానికి ప్రయత్నించిన ఫైల్ చిత్రం వలె కనిపించడం లేదు." size_not_found: "క్షమించండి, కానీ మేము చిత్రం యొక్క పరిమాణం నిర్ణయించలేదు. బహుశా మీ చిత్రం పాడై ఉండవచ్చు?" email_log: + suspended_not_pm: "వినియోగదారుడు తొలగింపబడ్డారు, ఆంతరంగిక సందేశం కాదు" seen_recently: "వినియోగదారు కొత్తగా చూశారు" notification_already_read: "ఈ ఈమెయిల్ గురించి ప్రకటన ఇప్పటికే చదివబడింది" post_deleted: "టపా రచయితచే తొలగింపబడింది" user_suspended: "వినియోగదారు నిలిపివేయబడ్డారు" already_read: "వినియోగదారు ఇప్పటికే ఈ టపా చదివారు" + message_blank: "ఖాళీ సందేశం" body_blank: "ముఖ్యభాగం ఖాళీగా ఉంది" color_schemes: base_theme_name: "ఆధారం" + about: "గురించి" guidelines: "మార్గదర్శకాలు" + privacy: "ఆంతరంగికం" edit_this_page: "ఈ పేజిని సవరించు" csv_export: boolean_yes: "అవును" diff --git a/config/locales/server.tr_TR.yml b/config/locales/server.tr_TR.yml index c1e221e9dc..801673573e 100644 --- a/config/locales/server.tr_TR.yml +++ b/config/locales/server.tr_TR.yml @@ -105,6 +105,7 @@ tr_TR: other: "Üzgünüz, yeni kullanıcılar bir gönderiye sadece %{count} bağlantı ekleyebilirler." spamming_host: "Üzgünüz bu sunucuya bağlantı veremezsiniz." user_is_suspended: "Uzaklaştırılmış kullanıcılar gönderi yapamazlar." + topic_not_found: "Bir şeyler ters gitti. Muhtemelen siz konuya bakarken bu konu kapatıldı ya da silindi." just_posted_that: "yakın zamanda yaptığınız bir gönderiye çok benziyor" has_already_been_used: "önceden kullanıldı" invalid_characters: "geçersiz karakterler barındırıyor" @@ -203,6 +204,7 @@ tr_TR: password: common: "En çok kullanılan 10000 paroladan biri. Lütfen daha güvenli bir parola seçin." same_as_username: "kullanıcı adınızla aynı. Lütfen daha güvenli bir şifre seçiniz." + same_as_email: "bu e-posta adresinizle aynı. Lütfen daha güvenli bir şifre seçiniz." ip_address: signup_not_allowed: "Bu hesaptan yeni üyelik oluşturulmasına izin verilmiyor." color_scheme_color: @@ -547,7 +549,6 @@ tr_TR: sidekiq_warning: 'Sidekiq çalışmıyor. E-posta yollamak gibi gibi birçok asenkron görev sidekiq''in işidir. En az bir tane sidekiq süreci çalıştırdığınızdan emin olun. Sidekiq ile ilgili bilgi burada.' queue_size_warning: 'Kuyrukta çok fazla, %{queue_size} tane iş var. Bu Sidekiq süreçleriyle ilgili bir sorunu gösteriyor olabilir, daha fazla Sidekiq işçisi eklemeniz gerekebilir.' memory_warning: 'Sunucunuz toplam 1GB''tan az bellek ile çalışıyor. En az 1GB bellek tavsiye edilmektedir.' - enable_google_logins_warning: "Google OpenID kimlik doğrulama sisteminin ıskartaya çıkartılmış bir sürümünü kullanıyorsunuz. Google OpenID'den desteğini 20 Nisan 2015'te çekecek. Bir an önce Google OAuth2 kullanmaya başlayın. Daha fazlasını öğrenmek için bu rehberi okuyun" both_googles_warning: "Site ayarlarında enable_google_logins ve enable_google_oauth2_logins ayarlarından her ikisi de etkin. enable_google_logins ayarını devre dışı bırakın." google_oauth2_config_warning: 'Sunucu Google OAuth2 (enable_google_oauth2_logins) ile üyelik oluşturulması ve giriş yapılmasına elveriyor, fakat the kullanıcı IDsi and gizli kullanıcı değerleri henüz ayarlanmamış. Site Ayarları sayfasına gidin ve ayarları güncelleyin. Daha fazla bilgi için bu yönetmeliğe bakın.' facebook_config_warning: 'Sunucu Facebook (enable_facebook_logins) ile üyelik oluşturulması ve giriş yapılmasına izin veriyor, fakat app ID ve gizli app değerleri henüz ayarlanmamış. Site Ayarları sayfasına gidin ve ayarları güncelleyin. Daha fazla bilgi için bu yönetmeliğe bakın.' @@ -890,7 +891,6 @@ tr_TR: default_code_lang: "GitHub kod bloklarına (lang-auto, ruby, python vs.) uygulanacak, varsayılan programlama dili sözdizimi vurgulaması." warn_reviving_old_topic_age: "Herhangi bir kullanıcı, son cevabın burada belirtilen gün sayısından daha önce yazıldığı bir konuya cevap yazmaya başladığında, bir uyarı mesajı çıkacak. Bu özelliği devre dışı bırakmak için 0 girin. " autohighlight_all_code: "Tüm önceden formatlanan kod bloklarına, açıkça dil seçimi yapılmamış olsa da, zorla kod vurgulaması uygula." - embeddable_host: "Bu Discourse forumundan yorumların yerleştirilebileceği sunucu" feed_polling_enabled: "SADECE YERLEŞTİRME İÇİN: RSS/ATOM beslemesinin gönderi olarak yerleştirilip yerleştirilemeyeceği." feed_polling_url: "SADECE YERLEŞTİRME İÇİN: Yerleştirilecek RSS/ATOM beslemesinin URL'i." embed_by_username: "Yerleştirilmiş konuları oluşturan kullanıcıya ait Discourse kullanıcı adı. " @@ -1045,8 +1045,6 @@ tr_TR: %{base_url}/users/password-reset/%{email_token} test_mailer: subject_template: "[%{site_name}] E-posta Ulaştırma Testi" - text_body_template: "Bu aşağıdaki adresten gönderilen bir test emailidir\n\n[**%{base_url}**][0]\n\nEmailların ulaştırılması karışık bir meseledir. Öncelikle dikkat etmeniz gereken bir kaç önemli nokta:\n\n- Site ayarlarınızda 'bildiri emailları' için gönderen adresini doğru ayarladığınıza emin olun. **Yolladığınız emaillarda \"gönderen\" adresi olarak belirlediğiniz alan adı, emaillarınızın doğrulanacağı alan adıdır.**\n\n- Email başlıklarındaki önemli ipuçlarını yakalayabilmek için email istemcinizde emailların kaynak kodunu nasıl görüntüleyebileceğinizi öğrenin. Gmail'da, her emailin sağ üstündeki açılır menüden \"show original\" opsiyonuna tıklayabilirsiniz.\n\n- **ÖNEMLİ:** ISP'nizde email yollamak için kullanıdığınız alan adlarıyla IP adreslerinin eşleşmesini sağlayacak bir reverse DNS kaydı var mı? Buradan [reverse PTR kayıtlarınızı test edin][2]. Eğer ISP'niz doğru reverse DNS pointer kaydı girmezse, büyük ihtimal emaillarınızın hiç biri yerine ulaşmayacaktır.\n\n- Alan adınızın [SPF kaydı][8] doğru mu? Buradan [SPF kaydınızı test edin][1]. SPF için doğru resmi kayıt tipinin TXT olduğunu unutmayın.\n\n- Alan adınızın [DKIM kaydı][3] doğru mu? Bu emailların ulaştırılabilirliğini ciddi şekilde artıracaktır. Buradan [DKIM kaydınızı test edin][7].\n\n- Kendi email sunucunuzu kullanıyorsanız, email sunucunuzun IPlerinin [hiç bir email karalistesine][4] alınmadığına emin olun. Sunucunuzun, kesinlikle, HELLO mesajında DNS olarak çözümlenen tam tanımlanmış bilgisayar adı da gönderdiğinden emin olun. Göndermemesi, emailinizin bir çok email servisi tarafından reddedilmesine sebep olacaktır.\n\n(En kolayı, küçük topluluklar için rahat rahat yetecek sayıda bedava email yollama paketleri içeren, [Mandrill][md] veya [Mailgun][mg] veya [Mailjet][mj]'te ücretsiz hesap açmak. Tabi, gene DNS ayarlarınızda SPF ve DKIM kayıtlarını oluşturmanız gerekecek.)\n\nUmarız bu email ulaştırma testini başarıyla atlatmışsınızdır. \n\nİyi şanslar,\n\n[Discourse](http://www.discourse.org)'tan arkadaşlarınız\n\n[0]: %{base_url}\n[1]: http://www.kitterman.com/spf/validate.html\n[2]:\ - \ http://mxtoolbox.com/ReverseLookup.aspx\n[3]: http://www.dkim.org/\n[4]: http://whatismyipaddress.com/blacklist-check\n[7]: http://dkimcore.org/tools/dkimrecordcheck.html\n[8]: http://www.openspf.org/SPF_Record_Syntax\n[md]: http://mandrill.com\n[mg]: http://www.mailgun.com/\n[mj]: https://www.mailjet.com/pricing\n" new_version_mailer: subject_template: "[%{site_name}] Yeni Discourse versiyonu, güncelleme var" text_body_template: |2 diff --git a/config/locales/server.uk.yml b/config/locales/server.uk.yml index d7494b66e1..e3c7d12a2a 100644 --- a/config/locales/server.uk.yml +++ b/config/locales/server.uk.yml @@ -403,7 +403,6 @@ uk: invites_per_page: "Запрошення по замовчуванню показані на сторінці користувача." short_progress_text_threshold: "Після того, як кількість дописів в темі перевищить це число, індикатор просування по темі показуватиме тільки номер поточного допису. Якщо Ви зміните ширину індикатора, Вам, ймовірно, знадобиться змінити це значення." default_code_lang: "Мова програмування для підсвітки синтаксису, що за замовчуванням застосовуватиметься для блоків коду GitHub (lang-auto, ruby, python і т. ін.)" - embeddable_host: "Хост, що можете вставляти коментарі з цього Discourse форуму." embed_truncate: "Обрізати вбудовані повідомлення. " embed_category: "Категорія вбудованих тем. " errors: diff --git a/config/locales/server.zh_CN.yml b/config/locales/server.zh_CN.yml index 8b86ac03bb..ef174bd383 100644 --- a/config/locales/server.zh_CN.yml +++ b/config/locales/server.zh_CN.yml @@ -105,6 +105,7 @@ zh_CN: other: "抱歉,游客一次仅能贴 %{count} 条链接。" spamming_host: "抱歉,你不能添加一个链接到那个地址的链接。" user_is_suspended: "被封禁的用户不允许发贴。" + topic_not_found: "出现问题。也许这个话题被关闭或删除。" just_posted_that: "与你最近发表的帖子太过相似" has_already_been_used: "已经被使用" invalid_characters: "包含无效字符" @@ -565,7 +566,6 @@ zh_CN: sidekiq_warning: 'Sidekiq 不在运行。很多任务,例如发送电子邮件,是异步的被 sidekiq 调度执行的。请确保至少运行一个 sidekiq 进程。了解 Sidekiq。' queue_size_warning: '队列中的任务数为 %{queue_size},任务较多。这可能因为 Sidekiq 进程出问题导致,或者需要更多的 Sidekiq 进程。' memory_warning: '你的服务器环境内存少于 1GB,我们建议至少要有 1GB 内存。' - enable_google_logins_warning: "你正在使用已被废弃的 Google OpenID 验证方式。Google 将在2015年4月20日停止支持 OpenID 登录。尽早开始使用 Google Oauth2。点击了解更多" both_googles_warning: "你在站点设置中同时启用了 enable_google_logins 和 enable_google_oauth2_logins。禁用 enable_google_logins。" google_oauth2_config_warning: '服务器允许使用 Google Oauth2 登录(enable_google_oauth2_logins),但是 client id 和 client secret 没有被设定。 到站点设置更新此设定。 参考设定指南。' facebook_config_warning: '服务器允许使用 Facebook 账号登录(enable_facebook_logins),但是 app id 和 app secret 没有被设定。 到站点设置更新此设定。参考设定指南。' @@ -911,7 +911,6 @@ zh_CN: default_code_lang: "默认语法高亮语言,使用 GitHub 代码块(lang-auto、ruby、python或者其他等等。)" warn_reviving_old_topic_age: "当有人开始回复最后一贴超过一定天数前的主题时,将有一个警告显示,不鼓励他们复活一个老的讨论。将其设置为 0 以禁用。" autohighlight_all_code: "即使未显式设定语言,仍为所有预编排代码块应用语法高亮。" - embeddable_host: "能从这个 Discourse 论坛嵌入评论的主机。" feed_polling_enabled: "仅用于嵌入:是否将 RSS/ATOM 订阅为帖子。" feed_polling_url: "仅用于嵌入:RSS/ATOM 订阅的 URL。" embed_by_username: "创建嵌入主题的 Discourse 的用户名。" @@ -1083,44 +1082,6 @@ zh_CN: %{base_url}/users/password-reset/%{email_token} test_mailer: subject_template: "[%{site_name}] 电子邮件发送测试" - text_body_template: | - 这是一封测试电子邮件,发于: - - [**%{base_url}**][0] - - 电子邮件分发很复杂。以下是一些重要的您应该检查的内容: - - - 确定您设置了站点设置为 `notification email` 设置了正确的地址。**“来自”中指定的域名应和将要验证的域名一致。** - - - 确定您会使用您的邮件客户端查看*电子邮件源代码*,这样您可以通过查看邮件头来获取重要线索。在 Gmail 中,可以通过每一封邮件下拉菜单中的“显示原始消息”来查看。 - - - **重要:** 您的 ISP 是否对您发送邮件的域名和IP作了反向DNS解析?您可以在此[测试您的反向枚举指针(PTR)记录][2]。如果您的 ISP 没有正确的反向 DNS 记录,那么很可能您的任何电子邮件都不会被成功发送。 - - - 您的域名的[发件人策略框架(SPF)记录][8]是否正确?您可以在此[测试您的SPF记录][1]。注意 TXT 是一种正确的官方 SPF 记录。 - - - 您域名的[域名密钥身份识别邮件(DKIM)记录][3]正确?这将显著提高邮件分发的成功率。在此[测试您的 DKIM 记录]。 - - - 如果您自己运行邮件服务器,检查确认您发送电子邮件的服务器IP [不在任何邮件黑名单中][4]。验证您的 DNS 记录的 HELO 消息中*确定无疑地*发送了符合要求的主机名。如果没有,那么会导致很多邮件服务商拒绝您的邮件。 - - (最简单的方法是在[Mandrill][md]或[Mailgun][mg]或[Mailjet][mj]注册免费账户,他们的免费账户对一个小社群是足够的。如果您希望在中国大陆提供稳定的服务,您可以考虑[SendCloud][sc]不过您仍然需要在 DNS 设置中设定 SPF 和 DKIM 记录!) - - 我们衷心希望您收到这封邮件,成功完成邮件发送测试! - - 祝好运! - - 您的朋友,[Discourse](http://www.discourse.org) - - [0]: %{base_url} - [1]: http://www.kitterman.com/spf/validate.html - [2]: http://mxtoolbox.com/ReverseLookup.aspx - [3]: http://www.dkim.org/ - [4]: http://whatismyipaddress.com/blacklist-check - [7]: http://dkimcore.org/tools/dkimrecordcheck.html - [8]: http://www.openspf.org/SPF_Record_Syntax - [md]: http://mandrill.com - [mg]: http://www.mailgun.com/ - [mj]: https://www.mailjet.com/pricing - [sc]: http://sendcloud.sohu.com/ new_version_mailer: subject_template: "[%{site_name}] 有新的 Discourse 版本,可供升级" text_body_template: | diff --git a/config/locales/server.zh_TW.yml b/config/locales/server.zh_TW.yml index 8b00902c13..6fdf241915 100644 --- a/config/locales/server.zh_TW.yml +++ b/config/locales/server.zh_TW.yml @@ -18,10 +18,46 @@ zh_TW: log_in: "登入" via: "%{username} 自 %{site_name}" is_reserved: "保留權利" + purge_reason: "自動刪除被遺棄、未啟用賬戶" + disable_remote_images_download_reason: "磁盤空間不足,圖像下載已被禁用。" errors: + format: '%{attribute} %{message}' messages: too_long_validation: "限制 %{max} 個字元,你已經輸入了 %{length} 個字元" invalid_boolean: "無效的真假值。" + taken: "已經被採用" + accepted: 必須被接受 + blank: 不能空白 + present: 必須空白 + confirmation: "不匹配 %{attribute}" + empty: 不能空白 + equal_to: 必須等於 %{count} + even: 必須是雙數 + exclusion: 被保留 + greater_than: 必須大於 %{count} + greater_than_or_equal_to: 必須大於或等於 %{count} + inclusion: 不包括在這列表中 + invalid: 無效的 + less_than: 必須少於 %{count} + less_than_or_equal_to: 必須少於或等於 %{count} + not_a_number: 不是數字 + not_an_integer: 必須是整數 + odd: 必須是單數 + record_invalid: '驗證失敗: %{errors}' + restrict_dependent_destroy: + one: "不能刪除記錄,因為相關的 %{record} 存在" + many: "不能刪除記錄,因為相關的 %{record} 存在" + too_long: + other: 長度超過上限 (上限是 %{count} 字) + too_short: + other: 長度不足 (下限是 %{count} 字) + wrong_length: + other: 錯誤的長度 (應該為 %{count} 字) + other_than: "必須不是 %{count}" + template: + body: '以下的欄位出現問題:' + header: + other: '%{count} 個錯誤禁止 %{model} 被儲存' embed: load_from_remote: "載入文章時發生了錯誤" bulk_invite: @@ -31,6 +67,8 @@ zh_TW: backup_file_should_be_tar_gz: "備份檔案應使用 .tar.gz 歸檔" not_enough_space_on_disk: "沒有足夠的磁碟空間可供備份檔案上傳" not_logged_in: "你需要先登入才能那樣做。" + not_found: "所請求的URL或資源無法找到。" + invalid_access: "你不允許查看所請求的資源。" read_only_mode_enabled: "這個網站目前在唯讀模式,無法進行互動功能。" too_many_replies: other: "我們非常抱歉,新用戶被臨時限制在同一個主題上,只能回覆 %{count} 次" @@ -41,6 +79,7 @@ zh_TW: other: "%{count} 個更多回覆" loading: "討論串載入中⋯" permalink: "永久連結" + imported_from: "這是一個已從原 %{link} 中分離的主題" in_reply_to: "▶ %{username}" replies: other: "%{count} 個回覆" @@ -66,6 +105,7 @@ zh_TW: other: "抱歉, 訪客每次只能貼 %{count} 條連結。" spamming_host: "抱歉,你不能張貼該網站之連結。" user_is_suspended: "被停權的用戶無法張貼文章。" + topic_not_found: "出現問題。也許這個話題被關閉或刪除。" just_posted_that: "與你最近發表的內容太相似" has_already_been_used: "已經被使用" invalid_characters: "包含無效字詞" @@ -112,6 +152,16 @@ zh_TW: - 使用適合的字詞,能更容易使其他人 *找到* 你的主題,若你撰寫的內容屬於某個分類的話,應選擇張貼在該分類。 其他的說明,[請查看我們的社群守則](/guidelines)。此資訊只在你的最早的 %{education_posts_text} 顯示。 + new-reply: | + 歡迎來到%{site_name} — **感謝你的貢獻!** + + - 你的回覆是否以某種方式改善了討論? + + - 請尊重所有社群成員。 + + - 歡迎有建設性的評論,但是評論的應該是觀點,而不是人身攻擊。 + + 欲查看更多,[請查看我們的社群准則](/guidelines)。此訊息面板只會在你發表前 %{education_posts_text} 時顯示。 activerecord: attributes: category: @@ -128,6 +178,7 @@ zh_TW: topic: attributes: base: + warning_requires_pm: "你只能附加警告於私人訊息。" too_many_users: "你只能同時傳送警告給一位用戶。" cant_send_pm: "抱歉,你不能向該用戶發送私人訊息。" no_user_selected: "你必須選擇有效用戶。" @@ -135,6 +186,8 @@ zh_TW: attributes: password: common: "這個密碼是 10000 個最常用密碼之一,請使用一個更安全的密碼" + same_as_username: "與你的使用者名稱相同。請使用其他更安全的密碼。" + same_as_email: "與你的電郵相同。請使用其他更安全的密碼。" ip_address: signup_not_allowed: "不能使用這個帳戶進行登入" color_scheme_color: @@ -147,6 +200,7 @@ zh_TW: vip_category_name: "貴賓室" vip_category_description: "信任等級高於 3 的用戶討論的分類" meta_category_name: "Meta" + meta_category_description: "討論關於這個網站,它的組織,它是如何運作,以及我們如何能夠改善它。" staff_category_name: "管理員" staff_category_description: "讓工作人員進行討論的私人分類。此分類下的討論話題只有管理員與板主才看得到。" lounge_welcome: @@ -177,6 +231,7 @@ zh_TW: elder: title: "領先用戶" rate_limiter: + slow_down: "你已經執行這個動作太多次,請稍後再試" too_many_requests: "你的瀏覽速度過於頻繁,請等待 %{time_left} 後再試。" hours: other: "%{count} 小時" @@ -250,26 +305,34 @@ zh_TW: activation: action: "啟用您的帳號" already_done: "抱歉,此帳號啟用連結已經失效。可能你的帳號已經啟用了。" + please_continue: "你的新帳號已啟用;即將轉到主頁。" continue_button: "繼續連接至 %{site_name}" welcome_to: "歡迎來到%{site_name}!" approval_required: "你的論壇帳號需要由板主手動審核後才可使用。當你的帳號獲得批准,你將收到電子郵件通知。" post_action_types: off_topic: title: '離題內容' + description: '此帖與該主題標題和第一帖而言所討論的主題無關,可能需要被移動。' long_form: '投訴為離題內容' spam: title: '垃圾內容' description: '此文章內容為廣告,與當前討論話題無關,只有促銷資訊。' long_form: '投訴為垃圾內容' + email_title: '“%{title}”被標記為垃圾' + email_body: "%{link}\n\n%{message}" inappropriate: title: '不當內容' + description: '此帖內容包含對他人的攻擊、侮辱、仇視語言或違反了我們的社群准則。' long_form: '投訴為不當內容' notify_user: title: '私人訊息 @{{username}}' + description: '此帖包含一些我想與該用戶私下直接交流的內容。不能執行標記操作。' + long_form: '已私信用戶' email_title: '你的文章在"%{title}"' email_body: "%{link}\n\n%{message}" notify_moderators: title: "其他" + description: '此帖需要版主按照以上未列出的原因處理。' long_form: '向板主回報問題發文' email_title: '一篇在 "%{title}" 裡的文章需要板主注意' email_body: "%{link}\n\n%{message}" @@ -292,15 +355,24 @@ zh_TW: long_form: '投訴為垃圾內容' inappropriate: title: '不當內容' + description: '此主題內容包含對他人的攻擊、侮辱、仇視語言或違反了我們的社群准則。' long_form: '投訴為不當內容' notify_moderators: + title: "其他" + description: '該主題需要版主依據社群准則服務條款(TOS)或其它未列出的原因來給予關注。' + long_form: '標記為需版主注意' email_title: '此討論話題 "%{title}" 需要板主注意' email_body: "%{link}\n\n%{message}" flagging: you_must_edit: '

    你的文章已被社群投訴,請 閱讀你的私人訊息

    ' + user_must_edit: '

    你的帖子已經被社群標記並被臨時隱藏。

    ' archetypes: regular: title: "一般討論話題" + banner: + message: + make: "本主題現在是橫幅主題。它將出現在每頁的頂部,除非用戶將其隱藏。" + remove: "本主題已經不再是橫幅主題。它將不在每個頁面的頂部顯示。" unsubscribed: title: '取消訂閱' description: "你已經取消訂閱,我們不會再聯絡你。" @@ -319,6 +391,7 @@ zh_TW: xaxis: "天" yaxis: "瀏覽量" signups: + title: "新用戶" xaxis: "天" yaxis: "新用戶數量" topics: @@ -388,6 +461,46 @@ zh_TW: title: "最常引用的討論話題" xaxis: "討論話題" num_clicks: "點擊率" + page_view_anon_reqs: + title: "匿名" + xaxis: "天" + yaxis: "匿名的API訪問" + page_view_logged_in_reqs: + title: "已登入" + xaxis: "天" + yaxis: "已登入的API訪問" + page_view_crawler_reqs: + title: "網絡爬蟲" + xaxis: "天" + yaxis: "網絡爬蟲API請求" + page_view_total_reqs: + title: "總數" + xaxis: "天" + yaxis: "API 請求總數" + http_background_reqs: + title: "後台" + xaxis: "天" + yaxis: "實時更新和追蹤的請求" + http_2xx_reqs: + title: "狀態碼 2xx(正常)" + xaxis: "天" + yaxis: "正常的請求(狀態碼 2xx)" + http_3xx_reqs: + title: "HTTP 3xx(重新導向)" + xaxis: "天" + yaxis: "重新導向請求(狀態碼 3xx)" + http_4xx_reqs: + title: "HTTP 4xx(客戶端錯誤)" + xaxis: "天" + yaxis: "客戶端錯誤(狀態碼 4xx)" + http_5xx_reqs: + title: "HTTP 5xx(伺服器錯誤)" + xaxis: "天" + yaxis: "伺服器錯誤(狀態碼 5xx)" + http_total_reqs: + title: "總數" + xaxis: "天" + yaxis: "請求總數" dashboard: rails_env_warning: "伺服器現在運行 %{env} 模式。" ruby_version_warning: "如果你使用的 Ruby 版本是 2.0.0 ,這個版本有較多的問題,請升級至 p247 或以上的版本" @@ -396,14 +509,24 @@ zh_TW: sidekiq_warning: 'Sidekiq 未有執行。很多程序, 如發送電子郵件, 需要 sidekiq 非同步 (asynchronous) 執行的。請確保至少運行一個 sidekiq 程序。瞭解 Sidekiq。' queue_size_warning: '排定中的任務數量為%{queue_size},任務較多。這可能是因為 Sidekiq 程序出現問題, 或者需要更多的 Sidekiq 程序。' memory_warning: '伺服器記憶體少於 1GB,建議配置至少 1GB 記憶體' - enable_google_logins_warning: "你正在使用已作廢的 Google OpenID 認證方式。 Google 對於 Open ID 的支援將到 2015 年 4 月 20 日 為止。請儘早開始使用 Google Oauth2。參閱教學指南" + enable_google_logins_warning: "警告!當前的 Google 認證方法將於2015年4月20日結束!請現在切換到新方法!" both_googles_warning: "你已將網站設定中 enable_google_logins 和 enable_google_oauth2_logins 兩者皆勾選。請停用 enable_google_logins。" google_oauth2_config_warning: '伺服器設定為允許使用 Google Oauth2 註冊以及登入 (enable_google_oauth2_logins),但未設定客戶端 id 和客戶端 secret 值。請至網站設定裡更改設定。參閱教學指南。' facebook_config_warning: '伺服器允許使用 Facebook 帳號登入 (enable_facebook_logins), 但未有設定 app id 及 app secret values 。 請在 網站設定 裡更改設定。 設定教學指南。' twitter_config_warning: '伺服器允許使用 Twitter 帳號登入 (enable_twitter_logins), 但未有設定 key 和 secret values 。 請在 網站設定 裡更改設定。 設定教學指南。' github_config_warning: '伺服器允許使用 GitHub 帳號登入 (enable_github_logins), 但未有設定 client id 和 secret values。 請在 網站設定 裡更改設定。 設定教學指南。' + s3_config_warning: '伺服器被設定為上傳文件到 s3,但是至少有一個值未被設定: s3_access_key_id, s3_secret_access_key 或 s3_upload_bucket。到設定更新此設定。參考如何設置圖片上傳至 S3。' + s3_backup_config_warning: '伺服器被設置為上傳備份到 s3,但是至少有一個值未被設定: s3_access_key_id, s3_secret_access_key 或 s3_upload_bucket。到設定更新此設定。參考如何設置圖片上傳至 S3。' + image_magick_warning: '伺服器被設置為給大圖片創建縮略圖,但是 ImageMagick 沒有被安裝。使用你喜愛的包裝管理器安裝 ImageMagick 或下載最新版。' failing_emails_warning: '%{num_failed_jobs}個 email 任務失敗。請檢查 config/environments/production.rb 內 config.action_mailer 項目是否已正確設定。在 Sidekiq 中檢視失敗的任務。' + default_logo_warning: "設置你網站的圖形logo。請在設定中配置logo_url、logo_small_url和favicon_url。" + contact_email_missing: "輸入一個網站聯絡人的電郵地址,這樣在用戶在網站出現緊急狀況時能夠找到你。在設定中更新它。" + contact_email_invalid: "網站聯絡電郵不正確。在設定中修改。" + title_nag: "為網站給予一個名字。在設定中更新標題。" + site_description_missing: "輸入一句話作為網站的簡介,將出現在搜索結果中。在設定中更新 site_description。" consumer_email_warning: "您的網站正以Gmail或其他服務供應商郵件服務發送郵件。Gmail限制每日郵件發送數量. 請考慮使用其他電郵服務商來保證郵件能成功發送,例如 mandrill.com。" + site_contact_username_warning: "輸入一個友善的職員帳戶名稱,並以他的名義發送重要的自動私信。在設定中更新 site_contact_username。" + notification_email_warning: "通知郵件不是從你域名的一個有效地址發出的;電郵發送將會變得危險和不可靠。請在設定中將 notification_email 設定一個有效的本機電郵地址。" content_types: education_new_reply: title: "新用戶教學:第一個回覆" @@ -413,6 +536,7 @@ zh_TW: description: "在新用戶發表首兩個討論話題時,自動在編輯器上方彈出的說明資訊。" usage_tips: title: "新用戶指南" + description: "新用戶指引和重要信息" welcome_user: title: "歡迎: 新用戶" description: "當新用戶註冊後自動發送給他們的歡迎訊息。" @@ -424,14 +548,19 @@ zh_TW: description: "歡迎資訊只會在已啟用'login required'時向未登入的用戶顯示" login_required: title: "請登入:首頁" + description: "當要求登錄時向未授權用戶顯示的文字。" head: title: "HTML 標頭" description: "將在 標籤中插入的 HTML" top: title: "頁面頂部" + description: "將在每一個頁面頂端(在頭部之後,在導航或者主題標題前)插入的 HTML。" bottom: title: "頁面底部" + description: "將在 標簽前被插入的 HTML。" site_settings: + censored_words: "將被自動替換為 ■■■■" + delete_old_hidden_posts: "自動刪除被隱藏超過 30 天的帖子。" default_locale: "Discourse 執行個體 (instance) 的預設語言編碼 (ISO 639-1)" allow_user_locale: "允許用戶選擇自己的語言介面" min_post_length: "文章允許的最小文字數" @@ -445,52 +574,98 @@ zh_TW: uncategorized_description: "\"未分類\"的分類的描述,留空則無描述" allow_duplicate_topic_titles: "允許話題有相同,重複的標題" unique_posts_mins: "使用者再次發表包含相同內容文章的間隔時間" + educate_until_posts: "當用戶開始鍵入他們的前幾個 (n) 新帖子時,在編輯器上顯示教育面板視窗。" + title: "網站名字,用於 title 標籤。" + site_description: "用一句話描述這個網站,用於 meta description 標籤。" + contact_email: "本站管理員的電郵地址。用於緊急事項的通知,如未處理的標記,以及作為 /about 頁面中的緊急聯絡人。" + contact_url: "這個網站聯絡 URL。用作 /about 頁面中的緊急聯絡。" queue_jobs: "如果失敗佇列在排隊,使用 Sidekiq 消息引擎對不同的工作排隊" crawl_images: "允許從第三方 URL 取得圖片,來加入寬和高的數值" + download_remote_images_to_local: "下載外部鏈接的圖片到本機;以防圖片損壞。" + download_remote_images_threshold: "可用來下載外部圖片到本機最少的空間(百分比)" disabled_image_download_domains: "在此列表的網域名稱的遠端圖片將不會進行下載,用 | 分割多個域名" ninja_edit_window: "在 (n) 秒內 ,文章的編輯不產生新的文章版本歷史" post_edit_time_limit: "作者可以在發表文章後的 ( n ) 分鐘內編輯或刪除他們的文章,設 0 為永遠" + edit_history_visible_to_public: "允許任何人查看編輯過的帖子的舊版本。當禁用時,只有職員才能查看。" + delete_removed_posts_after: "帖子被作者刪除,將在 (n) 小時後被自動刪除。如果設置為 0,帖子將被立即刪除。" max_image_width: "文章中最大的縮圖寬度" max_image_height: "文章中的允許圖片最大的縮圖高度" category_featured_topics: "在分類 /categories 頁面每個分類顯示的討論話題數目。此數值的改變最多需要 15 分鐘才會反應在分類頁面上。" show_subcategory_list: "進入分類時顯示子分類列表,而非話題列表" fixed_category_positions: "若勾選,你將能調整並固定分類的順序。若不勾選,分類將會依照活躍程度來排序。" + add_rel_nofollow_to_user_content: "添加 rel nofollow 屬性到所有的用戶內容,除了內部鏈接(包括父域名)。如果你更改了這個,你必須重新調制所有帖子,而該命令為:“rake posts:rebake”" exclude_rel_nofollow_domains: "不添加 nofollow 標籤到一列逗號分割的功能變數名稱 (使用父系網域名,例如 tld.com,將自動允許子功能變數名稱,例如 sub.tld.com)" post_excerpt_maxlength: "文章摘要的最大文字長度" + post_onebox_maxlength: "Onebox 處理後的 Discourse 帖子的最大字符長度" + onebox_domains_whitelist: "對這些站點啟用 Onebox 的域名列表;這些域名應該支持 OpenGraph 或 oEmbed。在此測試它們:http://iframely.com/debug" + logo_url: "出現在你的網站左上角的標誌圖片;如果留空,將顯示網站標題。" + digest_logo_url: "電郵摘要使用的標誌。如果留空,則使用 `logo_url`。例如:http://example.com/logo.png" + logo_small_url: "出現在你網站左上角的小標誌圖片,當滾動後可見。如果留空,將顯示主頁圖標。" favicon_url: "你的網站圖示 (favicon),參考 http://zh.wikipedia.org/wiki/Favicon" + mobile_logo_url: "移動瀏覽器左上角的固定標誌圖片。如果留空,將顯示網站標題。" apple_touch_icon_url: "Apple 觸碰設備使用的圖示,建議 144 X 144px 大小" + notification_email: "這個表格:被用於發送所有重要系統郵件的郵箱地址。指定的域名必須正確設置 SPF、DKIM 和反向 PTR 記錄以發送郵件。" + email_custom_headers: "自定義的電子郵件標題的管道分隔列表" + email_subject: "標準郵件的自定義主題格式。參見 https://meta.discourse.org/t/customize-subject-format-for-standard-emails/20801" use_https: "使用 SSL 安全套接層來瀏覽本站嗎?" + summary_score_threshold: "將一個帖子包含在“概括主題”中所需的最少分數" summary_posts_required: "如果使用了\"此話題的摘用\",話題顯示時需滿足最小的文章的數量" summary_likes_required: "如果使用了\"此話題的摘用\",話題顯示時需滿足最小得到\"讚\"的數量" summary_percent_filter: "當用戶點擊 \"此話題的摘要\",顯示前面多少 % 的文章" + summary_max_results: "“概括主題”返回的最大帖子數量" enable_private_messages: "允許信任等級 1 之用戶建立私人訊息和私下交流" enable_long_polling: "啟用消息匯流排使通知功能可以使用長輪詢(long polling)" + long_polling_base_url: "長輪詢的基本 URL(當用 CDN 分發動態內容,請設置此至原始拉取地址)例如:http://origin.site.com" + long_polling_interval: "當沒有數據向客戶端發送時伺服器端應等待的時間(僅對已登錄用戶有效)" + polling_interval: "當不再長輪詢時,已登錄的客戶端應該多久輪詢一次(單位 毫秒)" anon_polling_interval: "匿名使用者用戶端輪詢時間間隔(單位 毫秒)" + background_polling_interval: "客戶端輪詢的間隔,以毫秒計(當視窗在後台時)" auto_track_topics_after: "經過多少毫秒之後一個討論話題就會被自動追蹤的全域預設值,用戶可以覆寫此設定 ( 0 為總是,-1 為永不 )" new_topic_duration_minutes: "一個討論話題在多少分鐘之內被視為新的討論話題的全域預設值,用戶可以覆寫此設定 ( -1 為總是,-2 為上一次瀏覽 )" flags_required_to_hide_post: "一篇文章累計多少個投訴之後會被自動隱藏,並向文章作者發送私人訊息通知(0為從不)" cooldown_minutes_after_hiding_posts: "如果一個文章因為標記而隱藏,用戶需要等待多少分鐘才能編輯該文章" max_topics_in_first_day: "新用戶第一天在這個站最大能建立的話題數量" max_replies_in_first_day: "新用戶第一天在這個站最大能建立的回覆數量" + num_flags_to_block_new_user: "如果一個新用戶的帖子被其他 num_users_to_block_new_user 個用戶標記為垃圾,隱藏他們的所有帖子並阻止其之後的發帖。0 表示禁用這個特性。" + num_users_to_block_new_user: "如果一個新用戶的帖子被許多其他用戶 num_flags_to_block_new_user 標記為垃圾,隱藏他們的所有帖子並阻止其之後發帖。0 表示禁用這個特性。" notify_mods_when_user_blocked: "若有用戶被自動封鎖,將發送訊息給所有板主。" + flag_sockpuppets: "如果一個新用戶開始了一個主題,並且同時另一個新用戶以同一個 IP 在該主題回復,他們所有的帖子都將被自動標記為垃圾。" traditional_markdown_linebreaks: "在 Markdown 中使用傳統的換行符號,即用兩個行末空格來換行" + post_undo_action_window_mins: "允許用戶在帖子上進行撤銷操作(讚、標記等)所需等待的時間分隔(分鐘)" must_approve_users: "新註冊用戶必須由管理員進行審核,才能進行相關操作" ga_tracking_code: "穀歌分析追蹤代碼,例如:UA-12345678-9。參考 http://google.com/analytics" ga_domain_name: "穀歌分析功能變數名稱,例如:mysite.com;參考 http://google.com/analytics" + ga_universal_tracking_code: "Google 通用 Analytics (分析) 追蹤代碼(analytics.js)追蹤代碼,例如:UA-12345678-9;參考 http://google.com/analytics" + ga_universal_domain_name: "Google 通用 Analytics (分析) 域名(analytics.js)追踪代码,例如:mysite.com;参考 http://google.com/analytics" + enable_escaped_fragments: "如未偵測到爬蟲,退回使用 Google Ajax-Crawling API。參見 https://support.google.com/webmasters/answer/174992?hl=en" enable_noscript_support: "開啟noscript來對網路爬蟲來做標準的支援" allow_moderators_to_create_categories: "允許板主建立新分類" + cors_origins: "允許跨來源資源共享(CORS)。每個來源必須包括 http:// 或 https://。DISCOURSE_ENABLE_CORS 環境選項必須設置為 true 才能啟用 CORS 。" + 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: "決定在分享對話方塊裡顯示哪些項目、以什麼順序顯示。" track_external_right_clicks: "追蹤外部連結的右鍵點擊 ( 例如:開啟於瀏覽器的新頁面 ),預設是關閉的,因為它會重寫URLs" + site_contact_username: "系統給用戶發送自動私信時所使用的用戶名;如果留空將使用默認的系統帳戶。" send_welcome_message: "給所有的新用戶發送一個快速引導的私訊" + suppress_reply_directly_below: "當帖子只有一個回覆時,不顯示帖子的回覆數量。" + suppress_reply_directly_above: "當帖子只有一個回覆時,不顯示回覆到該帖的回覆。" + suppress_reply_when_quoting: "當帖子引用回覆時,不顯示可展開的回覆到某帖的標記。" + max_reply_history: "擴展回覆到某帖時顯示的最大回覆數量" + experimental_reply_expansion: "當展開回覆到某帖時隱藏直接回覆(實驗性)" topics_per_period_in_top_summary: "預設推薦話題的顯示數量" topics_per_period_in_top_page: "在展開 \"顯示更多\" 推薦話題列表的顯示數量" redirect_users_to_top_page: "將新用戶或長時間未使用的用戶自動重新導向至熱門頁面" + show_email_on_profile: "在用戶頁面顯示用戶的電郵地址(只有用戶自己和職員可見)" email_token_valid_hours: "\"忘記密碼\" / \"重啟帳號\" token 有效的小時數 (n)" email_token_grace_period_hours: "\"忘記密碼\" / \"重啟帳號\" 的 token 在使用後仍舊有效的小時數 (n)" + enable_badges: "啟用勳章系統" allow_index_in_robots_txt: "在 robots.txt 中記錄這個網站允許被搜尋引擎索引的部分" email_domains_blacklist: "Email域名的黑名單,在此名單內的域名將無法註冊,例如:mailinator.com trashmail.net" email_domains_whitelist: "Email域名的白名單,使用者 \"必須\" 使用此帳號來註冊,注意:使用者如果使用其他Email的域名將無法註冊" + forgot_password_strict: "在找回密碼對話框中不告知用戶帳戶的存在。" + log_out_strict: "登出時,登出用戶所有設備上的所有時段" + version_checks: "訪問 Discourse Hub 來檢查版本更新,並在管理面板 /admin 顯示新版本訊息" new_version_emails: "當新版本發佈時,將會發送一封新的 EMail 至 contact_email 設定的位址" port: "使用此 HTTP 埠而不是80埠。留空為不使用,主要用於開發調試" force_hostname: "指定 URL 裡的主機名稱。留空為不使用,主要用於開發調試" @@ -498,9 +673,18 @@ zh_TW: invite_passthrough_hours: "邀請號碼如已被使用,用戶仍可使用多少小時" invite_only: "已經禁止開放註冊,新的使用者必須取得其他用戶,或是管理員的邀請" login_required: "需要登入才能進入網站,不允許匿名操作" + min_username_length: "最少帳戶名長度。警告:所有現有帳戶名少於此長度限制的用戶都將無法登入網站。" + max_username_length: "最大帳戶名長度。警告:所有現有帳戶名大於此限制長度的用戶都將無法登入網站。" min_password_length: "最小密碼長度" block_common_passwords: "不允許使用 10,000 個最常用的密碼" + enable_sso: "啟用通過外部網站單點登錄(注意:如果沒有正確設定就啟用可能會使所有人都無法登陸,包括你;同時禁用邀請功能)" + enable_sso_provider: "在 /session/sso_provider endpoint 必須設定 sso_secret 以實現 Discourse SSO 提供方協定" sso_url: "單點登入 URL 入口點" + sso_secret: "秘密字符串,用於驗證秘密的 SSO 訊息,請確保由 10 個字或以上組成" + sso_overrides_email: "用 SSO 訊息中的外部電郵地址覆蓋本機電郵地址(警告:因為對本機電郵的統一處理,這個電郵地址可能不同)" + sso_overrides_username: "用 SSO 訊息中的外部帳戶名覆蓋本機帳戶名(警告:因為對本機帳戶名的統一處理,帳戶名的長度或者要求可能不同)" + sso_overrides_name: "用 SSO 訊息中的外部網站名覆蓋本機名字(警告:因為對本機名字的統一處理,這個名字可能不同)" + sso_overrides_avatar: "用 SSO 訊息中的外部網站頭像覆蓋用戶頭像。如果啟用,建議禁用 allow_uploaded_avatars" enable_local_logins: "啟用網站用戶名稱和密碼驗證 ( 注意:這必須啟用邀請才能有動作 )" allow_new_registrations: "允許新用戶註冊,如果取消選取,則沒有人能夠註冊" enable_google_logins: "( 已作廢 ) 啟用 Google 認證。這是已經被 Google 作廢的 Open ID 認證方式,新的安裝將無法使用。請改用 Google Oauth2。現有的安裝必須在 2015 年 4 月 20 日以前移轉至 Google Oauth2。" @@ -520,8 +704,10 @@ zh_TW: allow_restore: "允許還原資料,注意此動作可能覆蓋「所有」網站資料!除非你計畫還原備份檔,否則請保持此設定為 false" maximum_backups: "磁碟備份的最大數量,舊的將會自動刪除" backup_daily: "每日自動對網站進行備份" + enable_s3_backups: "當完成備份後上傳備份到 S3。重要:需要在文件設定中填寫有效的 S3 驗證資料。" s3_backup_bucket: "遠端備份 bucket ,注意:請確定是私有的 bucket" active_user_rate_limit_secs: "更新“最後一次見到”資料的頻率,單位為秒" + verbose_localization: "在界面上顯示詳細的本地化提示" previous_visit_timeout_hours: "系統判斷一次瀏覽之後多少小時後為“上一次”瀏覽" rate_limit_create_topic: "建立新討論話題之後,用戶必須間隔多少秒 (n) 才能再建立新討論話題" rate_limit_create_post: "建立新文章之後,用戶必須間隔多少秒 (n) 才能再建立新文章" @@ -533,13 +719,40 @@ zh_TW: max_edits_per_day: "每個用戶每天最大的\"編輯次數\"的數量" max_topics_per_day: "每個用戶每天最多建立\"討論話題\"的數量" max_private_messages_per_day: "每個用戶每天最多能發\"私訊\"的數量" + max_invites_per_day: "每個用戶每天最多能邀請用戶的數量。" suggested_topics: "討論話題下的推薦話題數量" limit_suggested_to_category: "目前的話題下只顯示同分類的推薦話題" + clean_up_uploads: "移除孤立的已上傳檔案。警告:你可能想要在啟用這個設定前備份 /uploads 文件夾。" + clean_orphan_uploads_grace_period_hours: "刪除孤立的上傳檔案的寬限期(單位:小時)" + purge_deleted_uploads_grace_period_days: "徹底刪除孤立的上傳檔案的寬限期(單位:天)" + purge_unactivated_users_grace_period_days: "刪除未啓用的帳戶的寬限期(單位:天)。" + enable_s3_uploads: "上傳至 Amazon S3 存儲的地址。重要:需要有效的 S3 驗證資料(包括 access key id & secret access key)。" + s3_use_iam_profile: '使用 AWS EC2 IAM 角色來獲得鑰匙。注意:啟用這個會覆蓋“S3 access key id”和“S3 secret access key” 設定。' + s3_upload_bucket: "上傳檔案保存於 Amazon S3 的 bucket 名字。警告:必須為小寫,無句點,無下劃線。" s3_access_key_id: "上傳至 Amazon S3 的 access key id,將用於上傳圖片" s3_secret_access_key: "上傳至 Amazon S3 的 secret access key,將用於上傳圖片" s3_region: "上傳至 Amazon S3 的 region name,將用於上傳圖片" + enable_flash_video_onebox: "在 Onebox 啟用嵌入 swf 和 flv (Adobe Flash) 的鏈接。警告:可能增加安全風險。" default_invitee_trust_level: "預設的受邀用戶等級 (0-4)" default_trust_level: "所有新用戶的預設等級 (0-4)" + tl1_requires_topics_entered: "新用戶升級到信任等級1所需要進入的主題數量。" + tl1_requires_read_posts: "新用戶升級到信任等級1所需要閱讀的帖子數量。" + tl1_requires_time_spent_mins: "新用戶升級到信任等級1所需要閱讀帖子消耗的時間(分鐘)。" + tl2_requires_topics_entered: "新用戶升級到信任等級2所需要進入的主題數量。" + tl2_requires_read_posts: "新用戶升級到信任等級2所需要閱讀的帖子數量。" + tl2_requires_time_spent_mins: "新用戶升級到信任等級2所需要閱讀帖子消耗的時間。(分鐘)" + tl2_requires_days_visited: "一個初級用戶升級到信任等級2所需要訪問網站的累計天數。" + tl2_requires_likes_received: "一個初級用戶升級到信任等級2所需要獲得的讚賞數。" + tl2_requires_likes_given: "一個初級用戶升級到信任等級2所需要付出的讚賞數。" + tl2_requires_topic_reply_count: "一個初級用戶升級到信任等級2所需要回覆的主題數量。" + tl3_requires_days_visited: "在最近 100 天內升至信任等級3所需的訪問網站的天數。(0到100)" + tl3_requires_topics_replied_to: "在最近 100 天內升至信任等級3所需的回覆主題的最少數量。(0或更高)" + tl3_requires_topics_viewed: "在最近 100 天內升至信任等級3所需的創建主題的百分比。(0到100)" + tl3_requires_posts_read: "在最近 100 天內升信任等級3所需的創建帖子的百分比。(0到100)" + tl3_requires_topics_viewed_all_time: "用戶升至信任等級3所需查看的最少主題數量。" + tl3_requires_posts_read_all_time: "用戶升至信任等級3所需查看的最少帖子數量。" + tl3_requires_max_flagged: "用戶在最近 100 天內升至信任等級3所需的必須沒有超過 x 個帖子被 x 個不同的用戶標記數量,x為數量。(0或更高)" + tl3_promotion_min_duration: "信任等級3的用戶可被降級至信任等級2前最少持續天數。" tl3_links_no_follow: "禁止從信任等級 3 之用戶所發表的連結中刪除 rel=nofollow 標籤" min_trust_to_create_topic: "建立話題最低所需的信任等級" min_trust_to_edit_wiki_post: "編輯被標示為維基的文章所需之最低信任等級。" @@ -746,6 +959,10 @@ zh_TW: posted_by: "由 %{username} 張貼於 %{post_date}" user_invited_to_private_message_pm: subject_template: "[%{site_name}] %{username} 邀請你進行私人對話 '%{topic_title}'" + text_body_template: | + %{username} 邀請你在 %{site_name} 就 '%{topic_title}' 進行私下交流: + + 請訪問 %{base_url}%{url} 來查看該主題。 user_replied: subject_template: "[%{site_name}] %{username} 在 '%{topic_title}' 討論話題回覆了你的文章" text_body_template: | @@ -788,14 +1005,25 @@ zh_TW: 請瀏覽 %{base_url}%{url} 來回覆。 user_posted_pm: subject_template: "[%{site_name}] [PM] %{topic_title}" + text_body_template: | + %{message} + + %{context} + + --- + %{respond_instructions} digest: + why: "在你上一次於 %{last_seen_at} 訪問後,在 %{site_link} 上的摘要。" subject_template: "[%{site_name}] 於 %{date} 的摘要" new_activity: "在你的討論話題和文章裡的動態:" top_topics: "熱門文章" other_new_topics: "熱門討論話題" + unsubscribe: "這封來自 %{site_link} 的摘要郵件是你一段時間沒有訪問後發送給你的。點擊 %{unsubscribe_link} 取消訂閱。" click_here: "點擊此處" from: "%{site_name} 摘要" read_more: "閱讀更多" + more_topics: "有其他 %{new_topics_since_seen} 個新主題。" + more_topics_category: "更多新主題:" posts: other: "%{count} 篇文章" forgot_password: @@ -809,6 +1037,8 @@ zh_TW: %{base_url}/users/password-reset/%{email_token} set_password: subject_template: "[%{site_name}] 設定密碼" + account_created: + subject_template: "[%{site_name}] 你的新帳號" authorize_email: subject_template: "[%{site_name}] 確認你的新電子郵箱位址" text_body_template: | @@ -849,6 +1079,7 @@ zh_TW: spam_hosts: "此新用戶嘗試發表多篇含有指向相同網域之連結的文章。請見網站設定中的 newuser_spam_host_threshold。" email_log: no_user: "無法找到 ID 為 %{user_id} 的使用者" + suspended_not_pm: "用戶被封鎖,這不是私信" seen_recently: "用戶最近活躍" post_not_found: "無法找到 ID 為 %{post_id} 的文章" notification_already_read: "這封通知 EMail 已被讀取" @@ -862,12 +1093,18 @@ zh_TW: body_blank: "內容空白" color_schemes: base_theme_name: "基礎" + about: "關於" guidelines: "指導" privacy: "隱私政策" + edit_this_page: "編輯此頁" csv_export: boolean_yes: "是" boolean_no: "否" + static_topic_first_reply: | + 編輯本主題的第一帖以改變 %{page_name} 頁面的內容。 guidelines_topic: title: "FAQ / 使用守則" + tos_topic: + title: "服務條款" privacy_topic: title: "隱私政策" From e3eaa7fa7554fc8db9a43bc38c761b5c989e6567 Mon Sep 17 00:00:00 2001 From: Robin Ward Date: Tue, 24 Mar 2015 12:33:17 -0400 Subject: [PATCH 112/114] FIX: In long topics, filtering button was not always showing in card --- .../discourse/controllers/user-card.js.es6 | 45 ++++++++++--------- .../javascripts/discourse/models/user.js.es6 | 9 +--- .../discourse/templates/user-card.hbs | 2 +- app/controllers/users_controller.rb | 5 +++ app/serializers/user_serializer.rb | 10 ++++- 5 files changed, 40 insertions(+), 31 deletions(-) diff --git a/app/assets/javascripts/discourse/controllers/user-card.js.es6 b/app/assets/javascripts/discourse/controllers/user-card.js.es6 index 21c96e6460..60922c4c15 100644 --- a/app/assets/javascripts/discourse/controllers/user-card.js.es6 +++ b/app/assets/javascripts/discourse/controllers/user-card.js.es6 @@ -5,14 +5,16 @@ export default ObjectController.extend({ visible: false, user: null, username: null, - participant: null, avatar: null, userLoading: null, cardTarget: null, post: null, + // If inside a topic + topicPostCount: null, + postStream: Em.computed.alias('controllers.topic.postStream'), - enoughPostsForFiltering: Em.computed.gte('participant.post_count', 2), + enoughPostsForFiltering: Em.computed.gte('topicPostCount', 2), viewingTopic: Em.computed.match('controllers.application.currentPath', /^topic\./), viewingAdmin: Em.computed.match('controllers.application.currentPath', /^admin\./), showFilter: Em.computed.and('viewingTopic', 'postStream.hasNoFilters', 'enoughPostsForFiltering'), @@ -28,14 +30,14 @@ export default ObjectController.extend({ }.property('user.badge_count', 'user.featured_user_badges.@each'), hasCardBadgeImage: function() { - var img = this.get('user.card_badge.image'); + const img = this.get('user.card_badge.image'); return img && img.indexOf('fa-') !== 0; }.property('user.card_badge.image'), - show: function(username, postId, target) { + show(username, postId, target) { // XSS protection (should be encapsulated) username = username.toString().replace(/[^A-Za-z0-9_]/g, ""); - var url = "/users/" + username; + const url = "/users/" + username; // Don't show on mobile if (Discourse.Mobile.mobileView) { @@ -43,7 +45,7 @@ export default ObjectController.extend({ return; } - var currentUsername = this.get('username'), + const currentUsername = this.get('username'), wasVisible = this.get('visible'), post = this.get('viewingTopic') && postId ? this.get('controllers.topic.postStream').findLoadedPost(postId) : null; @@ -60,20 +62,21 @@ export default ObjectController.extend({ return; } - this.set('participant', null); - - // Retrieve their participants info - var participants = this.get('controllers.topic.details.participants'); - if (participants) { - this.set('participant', participants.findBy('username', username)); - } + this.set('topicPostCount', null); this.setProperties({ user: null, userLoading: username, cardTarget: target }); - var self = this; - return Discourse.User.findByUsername(username, { stats: false }).then(function(user) { + const args = { stats: false }; + args.include_post_count_for = this.get('controllers.topic.id'); + + const self = this; + return Discourse.User.findByUsername(username, args).then(function(user) { + + if (user.topic_post_count) { + self.set('topicPostCount', user.topic_post_count[args.include_post_count_for]); + } user = Discourse.User.create(user); - self.setProperties({ user: user, avatar: user, visible: true}); + self.setProperties({ user, avatar: user, visible: true}); self.appEvents.trigger('usercard:shown'); }).catch(function(error) { self.close(); @@ -83,19 +86,19 @@ export default ObjectController.extend({ }); }, - close: function() { + close() { this.setProperties({ visible: false, cardTarget: null }); }, actions: { - togglePosts: function(user) { - var postStream = this.get('controllers.topic.postStream'); + togglePosts(user) { + const postStream = this.get('controllers.topic.postStream'); postStream.toggleParticipant(user.get('username')); this.close(); }, - cancelFilter: function() { - var postStream = this.get('postStream'); + cancelFilter() { + const postStream = this.get('postStream'); postStream.cancelFilter(); postStream.refresh(); this.close(); diff --git a/app/assets/javascripts/discourse/models/user.js.es6 b/app/assets/javascripts/discourse/models/user.js.es6 index dc5df8c226..b458c11888 100644 --- a/app/assets/javascripts/discourse/models/user.js.es6 +++ b/app/assets/javascripts/discourse/models/user.js.es6 @@ -427,14 +427,9 @@ const User = Discourse.Model.extend({ User.reopenClass(Discourse.Singleton, { - /** - Find a `Discourse.User` for a given username. - - @method findByUsername - @returns {Promise} a promise that resolves to a `Discourse.User` - **/ + // Find a `Discourse.User` for a given username. findByUsername: function(username, options) { - var user = Discourse.User.create({username: username}); + const user = Discourse.User.create({username: username}); return user.findDetails(options); }, diff --git a/app/assets/javascripts/discourse/templates/user-card.hbs b/app/assets/javascripts/discourse/templates/user-card.hbs index 1db3b3f328..588da54eb0 100644 --- a/app/assets/javascripts/discourse/templates/user-card.hbs +++ b/app/assets/javascripts/discourse/templates/user-card.hbs @@ -28,7 +28,7 @@ {{/if}} {{#if showFilter}} -
  • {{fa-icon "filter"}}{{i18n 'topic.filter_to' username=username post_count=participant.post_count}}
  • +
  • {{fa-icon "filter"}}{{i18n 'topic.filter_to' username=username post_count=topicPostCount}}
  • {{/if}} {{#if hasUserFilters}} diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index 5f9277d121..a6950cbaaf 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -34,6 +34,11 @@ class UsersController < ApplicationController if params[:stats].to_s == "false" user_serializer.omit_stats = true end + topic_id = params[:include_post_count_for].to_i + if topic_id != 0 + user_serializer.topic_post_count = {topic_id => Post.where(topic_id: topic_id, user_id: @user.id).count } + end + respond_to do |format| format.html do @restrict_fields = guardian.restrict_user_fields?(@user) diff --git a/app/serializers/user_serializer.rb b/app/serializers/user_serializer.rb index 37d42599c8..350b026201 100644 --- a/app/serializers/user_serializer.rb +++ b/app/serializers/user_serializer.rb @@ -1,6 +1,7 @@ class UserSerializer < BasicUserSerializer - attr_accessor :omit_stats + attr_accessor :omit_stats, + :topic_post_count def self.staff_attributes(*attrs) attributes(*attrs) @@ -62,7 +63,8 @@ class UserSerializer < BasicUserSerializer :has_title_badges, :edit_history_public, :custom_fields, - :user_fields + :user_fields, + :topic_post_count has_one :invited_by, embed: :object, serializer: BasicUserSerializer has_many :custom_groups, embed: :object, serializer: BasicGroupSerializer @@ -293,6 +295,10 @@ class UserSerializer < BasicUserSerializer user_fields.present? end + def include_topic_post_count? + topic_post_count.present? + end + def custom_fields fields = nil From 298098745ee43128b18918b161f9669c04dde212 Mon Sep 17 00:00:00 2001 From: Robin Ward Date: Tue, 24 Mar 2015 14:05:08 -0400 Subject: [PATCH 113/114] Allow users to reply as new to closed topics using quote functionality Previously, only users who could reply to a topic could use the quote button. Now, if a user has the ability to reply as a new topic, that operation will be used if the user selects text in a topic they can't reply to. --- .../discourse/controllers/quote-button.js.es6 | 20 ++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/app/assets/javascripts/discourse/controllers/quote-button.js.es6 b/app/assets/javascripts/discourse/controllers/quote-button.js.es6 index e2442cc23c..fc4c759c0f 100644 --- a/app/assets/javascripts/discourse/controllers/quote-button.js.es6 +++ b/app/assets/javascripts/discourse/controllers/quote-button.js.es6 @@ -13,16 +13,14 @@ export default DiscourseController.extend({ if (this.blank('buffer')) this.set('post', null); }.observes('buffer'), - /** - Save the currently selected text and displays the - "quote reply" button - **/ + // Save the currently selected text and displays the + // "quote reply" button selectText(postId) { // anonymous users cannot "quote-reply" - if (!Discourse.User.current()) return; + if (!this.currentUser) return; - // don't display the "quote-reply" button if we can't create a post - if (!this.get('controllers.topic.model.details.can_create_post')) return; + // don't display the "quote-reply" button if we can't at least reply as a new topic + if (!this.get('controllers.topic.model.details.can_reply_as_new_topic')) return; const selection = window.getSelection(); // no selections @@ -85,7 +83,15 @@ export default DiscourseController.extend({ }, quoteText() { + const post = this.get('post'); + + // If we can't create a post, delegate to reply as new topic + if (!this.get('controllers.topic.model.details.can_create_post')) { + this.get('controllers.topic').send('replyAsNewTopic', post); + return; + } + const composerController = this.get('controllers.composer'); const composerOpts = { action: Discourse.Composer.REPLY, From 66bda5267cccbbf458e9c20e36a5c73a3caf8ffa Mon Sep 17 00:00:00 2001 From: Neil Lalonde Date: Tue, 24 Mar 2015 14:18:08 -0400 Subject: [PATCH 114/114] Version bump to v1.3.0.beta4 --- lib/version.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/version.rb b/lib/version.rb index 72adef0246..f85bc57a0c 100644 --- a/lib/version.rb +++ b/lib/version.rb @@ -5,7 +5,7 @@ module Discourse MAJOR = 1 MINOR = 3 TINY = 0 - PRE = 'beta3' + PRE = 'beta4' STRING = [MAJOR, MINOR, TINY, PRE].compact.join('.') end