commit 70b211e3553c00c571123f124b3a607a389c81f4 Author: huangjingquan Date: Thu Aug 1 10:33:49 2013 +0800 first commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..8e575ed7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,20 @@ +log/* +.bundle +test/* +tmp/bids/server.pid +tmp/* +/tmp/cache/* +/tmp/pdf/* +/tmp/sessions/* +/tmp/sockets/* +/tmp/test/* +/tmp/thumbnails/* +.project +.svn/ +.git/ +.bundle +log +/log/development.log +/log/development.scm.stderr.log +/log/delete.me +/test/* diff --git a/.hgignore b/.hgignore new file mode 100644 index 00000000..9fde4865 --- /dev/null +++ b/.hgignore @@ -0,0 +1,39 @@ +syntax: glob + +.project +.loadpath +config/additional_environment.rb +config/configuration.yml +config/database.yml +config/email.yml +config/initializers/session_store.rb +config/initializers/secret_token.rb +coverage +db/*.db +db/*.sqlite3 +db/schema.rb +files/* +lib/redmine/scm/adapters/mercurial/redminehelper.pyc +lib/redmine/scm/adapters/mercurial/redminehelper.pyo +log/*.log* +log/mongrel_debug +public/dispatch.* +public/plugin_assets +tmp/* +tmp/cache/* +tmp/pdf/* +tmp/sessions/* +tmp/sockets/* +tmp/test/* +tmp/thumbnails/* +vendor/cache +vendor/rails +*.rbc + +.svn/ +.git/ + +.bundle +Gemfile.lock +Gemfile.local + diff --git a/Gemfile b/Gemfile new file mode 100644 index 00000000..261b71b7 --- /dev/null +++ b/Gemfile @@ -0,0 +1,95 @@ +source 'https://rubygems.org' + +gem "rails", "3.2.13" +gem "jquery-rails", "~> 2.0.2" +gem "i18n", "~> 0.6.0" +gem "coderay", "~> 1.0.6" +gem "fastercsv", "~> 1.5.0", :platforms => [:mri_18, :mingw_18, :jruby] +gem "builder", "3.0.0" +gem 'acts-as-taggable-on' +# Optional gem for LDAP authentication +group :ldap do + gem "net-ldap", "~> 0.3.1" +end + +# Optional gem for OpenID authentication +group :openid do + gem "ruby-openid", "~> 2.1.4", :require => "openid" + gem "rack-openid" +end + +# Optional gem for exporting the gantt to a PNG file, not supported with jruby +platforms :mri, :mingw do + group :rmagick do + # RMagick 2 supports ruby 1.9 + # RMagick 1 would be fine for ruby 1.8 but Bundler does not support + # different requirements for the same gem on different platforms + gem "rmagick", ">= 2.0.0" + end +end + +platforms :jruby do + # jruby-openssl is bundled with JRuby 1.7.0 + gem "jruby-openssl" if Object.const_defined?(:JRUBY_VERSION) && JRUBY_VERSION < '1.7.0' + gem "activerecord-jdbc-adapter", "1.2.5" +end + +# Include database gems for the adapters found in the database +# configuration file +require 'erb' +require 'yaml' +database_file = File.join(File.dirname(__FILE__), "config/database.yml") +if File.exist?(database_file) + database_config = YAML::load(ERB.new(IO.read(database_file)).result) + adapters = database_config.values.map {|c| c['adapter']}.compact.uniq + if adapters.any? + adapters.each do |adapter| + case adapter + when 'mysql2' + gem "mysql2", "~> 0.3.11", :platforms => [:mri, :mingw] + gem "activerecord-jdbcmysql-adapter", :platforms => :jruby + when 'mysql' + gem "mysql", "~> 2.8.1", :platforms => [:mri, :mingw] + gem "activerecord-jdbcmysql-adapter", :platforms => :jruby + when /postgresql/ + gem "pg", ">= 0.11.0", :platforms => [:mri, :mingw] + gem "activerecord-jdbcpostgresql-adapter", :platforms => :jruby + when /sqlite3/ + gem "sqlite3", :platforms => [:mri, :mingw] + gem "activerecord-jdbcsqlite3-adapter", :platforms => :jruby + when /sqlserver/ + gem "tiny_tds", "~> 0.5.1", :platforms => [:mri, :mingw] + gem "activerecord-sqlserver-adapter", :platforms => [:mri, :mingw] + else + warn("Unknown database adapter `#{adapter}` found in config/database.yml, use Gemfile.local to load your own database gems") + end + end + else + warn("No adapter found in config/database.yml, please configure it first") + end +else + warn("Please configure your config/database.yml first") +end + +group :development do + gem "rdoc", ">= 2.4.2" + gem "yard" +end + +group :test do + gem "shoulda", "~> 3.3.2" + gem "mocha", "~> 0.12.3" + gem 'capybara', '~> 2.0.0' +end + +local_gemfile = File.join(File.dirname(__FILE__), "Gemfile.local") +if File.exists?(local_gemfile) + puts "Loading Gemfile.local ..." if $DEBUG # `ruby -d` or `bundle -v` + instance_eval File.read(local_gemfile) +end + +# Load plugins' Gemfiles +Dir.glob File.expand_path("../plugins/*/Gemfile", __FILE__) do |file| + puts "Loading #{file} ..." if $DEBUG # `ruby -d` or `bundle -v` + instance_eval File.read(file) +end diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 00000000..99f29e91 --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,155 @@ +GEM + remote: https://rubygems.org/ + specs: + actionmailer (3.2.13) + actionpack (= 3.2.13) + mail (~> 2.5.3) + actionpack (3.2.13) + activemodel (= 3.2.13) + activesupport (= 3.2.13) + builder (~> 3.0.0) + erubis (~> 2.7.0) + journey (~> 1.0.4) + rack (~> 1.4.5) + rack-cache (~> 1.2) + rack-test (~> 0.6.1) + sprockets (~> 2.2.1) + activemodel (3.2.13) + activesupport (= 3.2.13) + builder (~> 3.0.0) + activerecord (3.2.13) + activemodel (= 3.2.13) + activesupport (= 3.2.13) + arel (~> 3.0.2) + tzinfo (~> 0.3.29) + activeresource (3.2.13) + activemodel (= 3.2.13) + activesupport (= 3.2.13) + activesupport (3.2.13) + i18n (= 0.6.1) + multi_json (~> 1.0) + acts-as-taggable-on (2.4.1) + rails (>= 3, < 5) + arel (3.0.2) + builder (3.0.0) + capybara (2.0.3) + mime-types (>= 1.16) + nokogiri (>= 1.3.3) + rack (>= 1.0.0) + rack-test (>= 0.5.4) + selenium-webdriver (~> 2.0) + xpath (~> 1.0.0) + childprocess (0.3.9) + ffi (~> 1.0, >= 1.0.11) + coderay (1.0.9) + erubis (2.7.0) + fastercsv (1.5.5) + ffi (1.9.0-x86-mingw32) + hike (1.2.3) + i18n (0.6.1) + journey (1.0.4) + jquery-rails (2.0.3) + railties (>= 3.1.0, < 5.0) + thor (~> 0.14) + json (1.8.0) + mail (2.5.4) + mime-types (~> 1.16) + treetop (~> 1.4.8) + metaclass (0.0.1) + mime-types (1.23) + mini_portile (0.5.0) + mocha (0.12.10) + metaclass (~> 0.0.1) + multi_json (1.7.6) + mysql2 (0.3.11-x86-mingw32) + net-ldap (0.3.1) + nokogiri (1.6.0-x86-mingw32) + mini_portile (~> 0.5.0) + pg (0.14.1-x86-mingw32) + polyglot (0.3.3) + rack (1.4.5) + rack-cache (1.2) + rack (>= 0.4) + rack-openid (1.3.1) + rack (>= 1.1.0) + ruby-openid (>= 2.1.8) + rack-ssl (1.3.3) + rack + rack-test (0.6.2) + rack (>= 1.0) + rails (3.2.13) + actionmailer (= 3.2.13) + actionpack (= 3.2.13) + activerecord (= 3.2.13) + activeresource (= 3.2.13) + activesupport (= 3.2.13) + bundler (~> 1.0) + railties (= 3.2.13) + railties (3.2.13) + actionpack (= 3.2.13) + activesupport (= 3.2.13) + rack-ssl (~> 1.3.2) + rake (>= 0.8.7) + rdoc (~> 3.4) + thor (>= 0.14.6, < 2.0) + rake (10.0.4) + rdoc (3.12.2) + json (~> 1.4) + rmagick (2.13.2) + ruby-openid (2.1.8) + rubyzip (0.9.9) + selenium-webdriver (2.33.0) + childprocess (>= 0.2.5) + multi_json (~> 1.0) + rubyzip + websocket (~> 1.0.4) + shoulda (3.3.2) + shoulda-context (~> 1.0.1) + shoulda-matchers (~> 1.4.1) + shoulda-context (1.0.2) + shoulda-matchers (1.4.1) + activesupport (>= 3.0.0) + sprockets (2.2.2) + hike (~> 1.2) + multi_json (~> 1.0) + rack (~> 1.0) + tilt (~> 1.1, != 1.3.0) + sqlite3 (1.3.7-x86-mingw32) + thor (0.18.1) + tilt (1.4.1) + treetop (1.4.14) + polyglot + polyglot (>= 0.3.1) + tzinfo (0.3.37) + websocket (1.0.7) + xpath (1.0.0) + nokogiri (~> 1.3) + yard (0.8.6.1) + +PLATFORMS + x86-mingw32 + +DEPENDENCIES + activerecord-jdbc-adapter (= 1.2.5) + activerecord-jdbcmysql-adapter + activerecord-jdbcpostgresql-adapter + activerecord-jdbcsqlite3-adapter + acts-as-taggable-on + builder (= 3.0.0) + capybara (~> 2.0.0) + coderay (~> 1.0.6) + fastercsv (~> 1.5.0) + i18n (~> 0.6.0) + jquery-rails (~> 2.0.2) + mocha (~> 0.12.3) + mysql2 (~> 0.3.11) + net-ldap (~> 0.3.1) + pg (>= 0.11.0) + rack-openid + rails (= 3.2.13) + rdoc (>= 2.4.2) + rmagick (>= 2.0.0) + ruby-openid (~> 2.1.4) + shoulda (~> 3.3.2) + sqlite3 + yard diff --git a/README.rdoc b/README.rdoc new file mode 100644 index 00000000..4132fb86 --- /dev/null +++ b/README.rdoc @@ -0,0 +1,5 @@ += Redmine + +Redmine is a flexible project management web application written using Ruby on Rails framework. + +More details can be found in the doc directory or on the official website http://www.redmine.org diff --git a/Rakefile b/Rakefile new file mode 100644 index 00000000..5fbdf84c --- /dev/null +++ b/Rakefile @@ -0,0 +1,7 @@ +#!/usr/bin/env rake +# Add your own tasks in files placed in lib/tasks ending in .rake, +# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake. + +require File.expand_path('../config/application', __FILE__) + +RedmineApp::Application.load_tasks diff --git a/app/controllers/account_controller.rb b/app/controllers/account_controller.rb new file mode 100644 index 00000000..ad7443ab --- /dev/null +++ b/app/controllers/account_controller.rb @@ -0,0 +1,307 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class AccountController < ApplicationController + helper :custom_fields + include CustomFieldsHelper + + # prevents login action to be filtered by check_if_login_required application scope filter + skip_before_filter :check_if_login_required + + # Login request and validation + def login + if request.get? + if User.current.logged? + redirect_to home_url + end + else + authenticate_user + end + rescue AuthSourceException => e + logger.error "An error occured when authenticating #{params[:username]}: #{e.message}" + render_error :message => e.message + end + + # Log out current user and redirect to welcome page + def logout + if User.current.anonymous? + redirect_to home_url + elsif request.post? + logout_user + redirect_to home_url + end + # display the logout form + end + + # Lets user choose a new password + def lost_password + (redirect_to(home_url); return) unless Setting.lost_password? + if params[:token] + @token = Token.find_token("recovery", params[:token].to_s) + if @token.nil? || @token.expired? + redirect_to home_url + return + end + @user = @token.user + unless @user && @user.active? + redirect_to home_url + return + end + if request.post? + @user.password, @user.password_confirmation = params[:new_password], params[:new_password_confirmation] + if @user.save + @token.destroy + flash[:notice] = l(:notice_account_password_updated) + redirect_to signin_path + return + end + end + render :template => "account/password_recovery" + return + else + if request.post? + user = User.find_by_mail(params[:mail].to_s) + # user not found or not active + unless user && user.active? + flash.now[:error] = l(:notice_account_unknown_email) + return + end + # user cannot change its password + unless user.change_password_allowed? + flash.now[:error] = l(:notice_can_t_change_password) + return + end + # create a new token for password recovery + token = Token.new(:user => user, :action => "recovery") + if token.save + Mailer.lost_password(token).deliver + flash[:notice] = l(:notice_account_lost_email_sent) + redirect_to signin_path + return + end + end + end + end + + # User self-registration + def register + (redirect_to(home_url); return) unless Setting.self_registration? || session[:auth_source_registration] + if request.get? + session[:auth_source_registration] = nil + @user = User.new(:language => current_language.to_s) + else + user_params = params[:user] || {} + @user = User.new + @user.safe_attributes = user_params + @user.admin = false + @user.register + if session[:auth_source_registration] + @user.activate + @user.login = session[:auth_source_registration][:login] + @user.auth_source_id = session[:auth_source_registration][:auth_source_id] + if @user.save + session[:auth_source_registration] = nil + self.logged_user = @user + flash[:notice] = l(:notice_account_activated) + redirect_to my_account_path + end + else + @user.login = params[:user][:login] + unless user_params[:identity_url].present? && user_params[:password].blank? && user_params[:password_confirmation].blank? + @user.password, @user.password_confirmation = user_params[:password], user_params[:password_confirmation] + end + + case Setting.self_registration + when '1' + register_by_email_activation(@user) + when '3' + register_automatically(@user) + else + register_manually_by_administrator(@user) + end + end + end + end + + # Token based account activation + def activate + (redirect_to(home_url); return) unless Setting.self_registration? && params[:token].present? + token = Token.find_token('register', params[:token].to_s) + (redirect_to(home_url); return) unless token and !token.expired? + user = token.user + (redirect_to(home_url); return) unless user.registered? + user.activate + if user.save + token.destroy + flash[:notice] = l(:notice_account_activated) + end + redirect_to signin_path + end + + private + + def authenticate_user + if Setting.openid? && using_open_id? + open_id_authenticate(params[:openid_url]) + else + password_authentication + end + end + + def password_authentication + user = User.try_to_login(params[:username], params[:password]) + + if user.nil? + invalid_credentials + elsif user.new_record? + onthefly_creation_failed(user, {:login => user.login, :auth_source_id => user.auth_source_id }) + else + # Valid user + successful_authentication(user) + end + end + + def open_id_authenticate(openid_url) + back_url = signin_url(:autologin => params[:autologin]) + + authenticate_with_open_id(openid_url, :required => [:nickname, :fullname, :email], :return_to => back_url, :method => :post) do |result, identity_url, registration| + if result.successful? + user = User.find_or_initialize_by_identity_url(identity_url) + if user.new_record? + # Self-registration off + (redirect_to(home_url); return) unless Setting.self_registration? + + # Create on the fly + user.login = registration['nickname'] unless registration['nickname'].nil? + user.mail = registration['email'] unless registration['email'].nil? + user.firstname, user.lastname = registration['fullname'].split(' ') unless registration['fullname'].nil? + user.random_password + user.register + + case Setting.self_registration + when '1' + register_by_email_activation(user) do + onthefly_creation_failed(user) + end + when '3' + register_automatically(user) do + onthefly_creation_failed(user) + end + else + register_manually_by_administrator(user) do + onthefly_creation_failed(user) + end + end + else + # Existing record + if user.active? + successful_authentication(user) + else + account_pending + end + end + end + end + end + + def successful_authentication(user) + logger.info "Successful authentication for '#{user.login}' from #{request.remote_ip} at #{Time.now.utc}" + # Valid user + self.logged_user = user + # generate a key and set cookie if autologin + if params[:autologin] && Setting.autologin? + set_autologin_cookie(user) + end + call_hook(:controller_account_success_authentication_after, {:user => user }) + #by young +# redirect_back_or_default my_page_path + redirect_back_or_default User.current +# redirect_to User.current + end + + def set_autologin_cookie(user) + token = Token.create(:user => user, :action => 'autologin') + cookie_options = { + :value => token.value, + :expires => 1.year.from_now, + :path => (Redmine::Configuration['autologin_cookie_path'] || '/'), + :secure => (Redmine::Configuration['autologin_cookie_secure'] ? true : false), + :httponly => true + } + cookies[autologin_cookie_name] = cookie_options + end + + # Onthefly creation failed, display the registration form to fill/fix attributes + def onthefly_creation_failed(user, auth_source_options = { }) + @user = user + session[:auth_source_registration] = auth_source_options unless auth_source_options.empty? + render :action => 'register' + end + + def invalid_credentials + logger.warn "Failed login for '#{params[:username]}' from #{request.remote_ip} at #{Time.now.utc}" + flash.now[:error] = l(:notice_account_invalid_creditentials) + end + + # Register a user for email activation. + # + # Pass a block for behavior when a user fails to save + def register_by_email_activation(user, &block) + token = Token.new(:user => user, :action => "register") + if user.save and token.save + Mailer.register(token).deliver + flash[:notice] = l(:notice_account_register_done) + redirect_to signin_path + else + yield if block_given? + end + end + + # Automatically register a user + # + # Pass a block for behavior when a user fails to save + def register_automatically(user, &block) + # Automatic activation + user.activate + user.last_login_on = Time.now + if user.save + self.logged_user = user + flash[:notice] = l(:notice_account_activated) + redirect_to my_account_path + else + yield if block_given? + end + end + + # Manual activation by the administrator + # + # Pass a block for behavior when a user fails to save + def register_manually_by_administrator(user, &block) + if user.save + # Sends an email to the administrators + Mailer.account_activation_request(user).deliver + account_pending + else + yield if block_given? + end + end + + def account_pending + flash[:notice] = l(:notice_account_pending) + redirect_to signin_path + end +end diff --git a/app/controllers/activities_controller.rb b/app/controllers/activities_controller.rb new file mode 100644 index 00000000..83b97f7d --- /dev/null +++ b/app/controllers/activities_controller.rb @@ -0,0 +1,87 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class ActivitiesController < ApplicationController + menu_item :activity + before_filter :find_optional_project, :index + accept_rss_auth :index + helper :Watchers + + def index + @days = Setting.activity_days_default.to_i + + if params[:from] + begin; @date_to = params[:from].to_date + 1; rescue; end + end + + has = { + "show_issues" => true + } + @date_to ||= Date.today + 1 + @date_from = @date_to - @days + @with_subprojects = params[:with_subprojects].nil? ? Setting.display_subprojects_issues? : (params[:with_subprojects] == '1') + @author = (params[:user_id].blank? ? nil : User.active.find(params[:user_id])) +# 决定显示所用用户或单个用户活动 + @activity = Redmine::Activity::Fetcher.new(User.current, :project => @project, + :with_subprojects => @with_subprojects, + :author => @author) + @activity.scope_select {|t| !has["show_#{t}"].nil?} + #@activity.scope = (@author.nil? ? :default : :all) if @activity.scope.empty? + + events = @activity.events(@date_from, @date_to) + # Added by Nie. + @offset, @limit = api_offset_and_limit({:limit => 10}) + @activity_count = events.size + @activity_pages = Paginator.new @activity_count, @limit, params['page'] + @offset ||= @activity_pages.offset + + @project_base_tag = params[:id]?'base_projects':'base' + if events.empty? || stale?(:etag => [@activity.scope, @date_to, @date_from, @with_subprojects, @author, events.first, events.size, User.current, current_language]) + respond_to do |format| + format.html { + @events_by_day_ = events.slice(@offset,@limit) + @events_by_day = @events_by_day_.group_by {|event| User.current.time_to_date(event.event_datetime)} + #by young render :layout => false if request.xhr? + render :layout => @project_base_tag + } + format.atom { + title = l(:label_activity) + if @author + title = @author.name + elsif @activity.scope.size == 1 + title = l("label_#{@activity.scope.first.singularize}_plural") + end + render_feed(events, :title => "#{@project || Setting.app_title}: #{title}") + } + end + end + + rescue ActiveRecord::RecordNotFound + render_404 + end + + private + + # TODO: refactor, duplicated in projects_controller + def find_optional_project + return true unless params[:id] + @project = Project.find(params[:id]) + authorize + rescue ActiveRecord::RecordNotFound + render_404 + end +end diff --git a/app/controllers/admin_controller.rb b/app/controllers/admin_controller.rb new file mode 100644 index 00000000..f96cf66f --- /dev/null +++ b/app/controllers/admin_controller.rb @@ -0,0 +1,83 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class AdminController < ApplicationController + layout 'admin' + menu_item :projects, :only => :projects + menu_item :plugins, :only => :plugins + menu_item :info, :only => :info + + before_filter :require_admin + helper :sort + include SortHelper + + def index + @no_configuration_data = Redmine::DefaultData::Loader::no_data? + end + + def projects + @status = params[:status] || 1 + + scope = Project.status(@status).order('lft') + scope = scope.like(params[:name]) if params[:name].present? + @projects = scope.all + + render :action => "projects", :layout => false if request.xhr? + end + + def plugins + @plugins = Redmine::Plugin.all + end + + # Loads the default configuration + # (roles, trackers, statuses, workflow, enumerations) + def default_configuration + if request.post? + begin + Redmine::DefaultData::Loader::load(params[:lang]) + flash[:notice] = l(:notice_default_data_loaded) + rescue Exception => e + flash[:error] = l(:error_can_t_load_default_data, e.message) + end + end + redirect_to admin_path + end + + def test_email + raise_delivery_errors = ActionMailer::Base.raise_delivery_errors + # Force ActionMailer to raise delivery errors so we can catch it + ActionMailer::Base.raise_delivery_errors = true + begin + @test = Mailer.test_email(User.current).deliver + flash[:notice] = l(:notice_email_sent, User.current.mail) + rescue Exception => e + flash[:error] = l(:notice_email_error, e.message) + end + ActionMailer::Base.raise_delivery_errors = raise_delivery_errors + redirect_to settings_path(:tab => 'notifications') + end + + def info + @db_adapter_name = ActiveRecord::Base.connection.adapter_name + @checklist = [ + [:text_default_administrator_account_changed, User.default_admin_account_changed?], + [:text_file_repository_writable, File.writable?(Attachment.storage_path)], + [:text_plugin_assets_writable, File.writable?(Redmine::Plugin.public_directory)], + [:text_rmagick_available, Object.const_defined?(:Magick)] + ] + end +end diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb new file mode 100644 index 00000000..e6808510 --- /dev/null +++ b/app/controllers/application_controller.rb @@ -0,0 +1,610 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +require 'uri' +require 'cgi' + +class Unauthorized < Exception; end + +class ApplicationController < ActionController::Base + include Redmine::I18n + include Redmine::Pagination + include RoutesHelper + helper :routes + + class_attribute :accept_api_auth_actions + class_attribute :accept_rss_auth_actions + class_attribute :model_object + + layout 'base' + + protect_from_forgery + def handle_unverified_request + super + cookies.delete(autologin_cookie_name) + end + + before_filter :session_expiration, :user_setup, :check_if_login_required, :set_localization + + + rescue_from ActionController::InvalidAuthenticityToken, :with => :invalid_authenticity_token + rescue_from ::Unauthorized, :with => :deny_access + rescue_from ::ActionView::MissingTemplate, :with => :missing_template + + include Redmine::Search::Controller + include Redmine::MenuManager::MenuController + helper Redmine::MenuManager::MenuHelper + + def session_expiration + if session[:user_id] + if session_expired? && !try_to_autologin + reset_session + flash[:error] = l(:error_session_expired) + redirect_to signin_url + else + session[:atime] = Time.now.utc.to_i + end + end + end + + def session_expired? + if Setting.session_lifetime? + unless session[:ctime] && (Time.now.utc.to_i - session[:ctime].to_i <= Setting.session_lifetime.to_i * 60) + return true + end + end + if Setting.session_timeout? + unless session[:atime] && (Time.now.utc.to_i - session[:atime].to_i <= Setting.session_timeout.to_i * 60) + return true + end + end + false + end + + def start_user_session(user) + session[:user_id] = user.id + session[:ctime] = Time.now.utc.to_i + session[:atime] = Time.now.utc.to_i + end + + def user_setup + # Check the settings cache for each request + Setting.check_cache + # Find the current user + User.current = find_current_user + logger.info(" Current user: " + (User.current.logged? ? "#{User.current.login} (id=#{User.current.id})" : "anonymous")) if logger + end + + # Returns the current user or nil if no user is logged in + # and starts a session if needed + def find_current_user + user = nil + unless api_request? + if session[:user_id] + # existing session + user = (User.active.find(session[:user_id]) rescue nil) + elsif autologin_user = try_to_autologin + user = autologin_user + elsif params[:format] == 'atom' && params[:key] && request.get? && accept_rss_auth? + # RSS key authentication does not start a session + user = User.find_by_rss_key(params[:key]) + end + end + if user.nil? && Setting.rest_api_enabled? && accept_api_auth? + if (key = api_key_from_request) + # Use API key + user = User.find_by_api_key(key) + else + # HTTP Basic, either username/password or API key/random + authenticate_with_http_basic do |username, password| + user = User.try_to_login(username, password) || User.find_by_api_key(username) + end + end + # Switch user if requested by an admin user + if user && user.admin? && (username = api_switch_user_from_request) + su = User.find_by_login(username) + if su && su.active? + logger.info(" User switched by: #{user.login} (id=#{user.id})") if logger + user = su + else + render_error :message => 'Invalid X-Redmine-Switch-User header', :status => 412 + end + end + end + user + end + + def autologin_cookie_name + Redmine::Configuration['autologin_cookie_name'].presence || 'autologin' + end + + def try_to_autologin + if cookies[autologin_cookie_name] && Setting.autologin? + # auto-login feature starts a new session + user = User.try_to_autologin(cookies[autologin_cookie_name]) + if user + reset_session + start_user_session(user) + end + user + end + end + + # Sets the logged in user + def logged_user=(user) + reset_session + if user && user.is_a?(User) + User.current = user + start_user_session(user) + else + User.current = User.anonymous + end + end + + # Logs out current user + def logout_user + if User.current.logged? + cookies.delete(autologin_cookie_name) + Token.delete_all(["user_id = ? AND action = ?", User.current.id, 'autologin']) + self.logged_user = nil + end + end + + # check if login is globally required to access the application + def check_if_login_required + # no check needed if user is already logged in + return true if User.current.logged? + require_login if Setting.login_required? + end + + def set_localization + lang = nil + if User.current.logged? + lang = find_language(User.current.language) + end + if lang.nil? && request.env['HTTP_ACCEPT_LANGUAGE'] + accept_lang = parse_qvalues(request.env['HTTP_ACCEPT_LANGUAGE']).first + if !accept_lang.blank? + accept_lang = accept_lang.downcase + lang = find_language(accept_lang) || find_language(accept_lang.split('-').first) + end + end + lang ||= Setting.default_language + set_language_if_valid(lang) + end + + def require_login + if !User.current.logged? + # Extract only the basic url parameters on non-GET requests + if request.get? + url = url_for(params) + else + url = url_for(:controller => params[:controller], :action => params[:action], :id => params[:id], :project_id => params[:project_id]) + end + respond_to do |format| + format.html { redirect_to :controller => "account", :action => "login", :back_url => url } + format.atom { redirect_to :controller => "account", :action => "login", :back_url => url } + format.xml { head :unauthorized, 'WWW-Authenticate' => 'Basic realm="Redmine API"' } + format.js { head :unauthorized, 'WWW-Authenticate' => 'Basic realm="Redmine API"' } + format.json { head :unauthorized, 'WWW-Authenticate' => 'Basic realm="Redmine API"' } + end + return false + end + true + end + + def require_admin + return unless require_login + if !User.current.admin? + render_403 + return false + end + true + end + + def deny_access + User.current.logged? ? render_403 : require_login + end + + # Authorize the user for the requested action + def authorize(ctrl = params[:controller], action = params[:action], global = false) + allowed = User.current.allowed_to?({:controller => ctrl, :action => action}, @project || @projects, :global => global) + if allowed + true + else + if @project && @project.archived? + render_403 :message => :notice_not_authorized_archived_project + else + deny_access + end + end + end + + # Authorize the user for the requested action outside a project + def authorize_global(ctrl = params[:controller], action = params[:action], global = true) + authorize(ctrl, action, global) + end + + # Find project of id params[:id] + def find_project + @project = Project.find(params[:id]) + rescue ActiveRecord::RecordNotFound + render_404 + end + + # Find project of id params[:project_id] + def find_project_by_project_id + @project = Project.find(params[:project_id]) + rescue ActiveRecord::RecordNotFound + render_404 + end + + # Find a project based on params[:project_id] + # TODO: some subclasses override this, see about merging their logic + def find_optional_project + @project = Project.find(params[:project_id]) unless params[:project_id].blank? + allowed = User.current.allowed_to?({:controller => params[:controller], :action => params[:action]}, @project, :global => true) + allowed ? true : deny_access + rescue ActiveRecord::RecordNotFound + render_404 + end + + # Finds and sets @project based on @object.project + def find_project_from_association + render_404 unless @object.present? + + @project = @object.project + end + + def find_model_object + model = self.class.model_object + if model + @object = model.find(params[:id]) + self.instance_variable_set('@' + controller_name.singularize, @object) if @object + end + rescue ActiveRecord::RecordNotFound + render_404 + end + + def self.model_object(model) + self.model_object = model + end + + # Find the issue whose id is the :id parameter + # Raises a Unauthorized exception if the issue is not visible + def find_issue + # Issue.visible.find(...) can not be used to redirect user to the login form + # if the issue actually exists but requires authentication + @issue = Issue.find(params[:id]) + raise Unauthorized unless @issue.visible? + @project = @issue.project + rescue ActiveRecord::RecordNotFound + render_404 + end + + # Find issues with a single :id param or :ids array param + # Raises a Unauthorized exception if one of the issues is not visible + def find_issues + @issues = Issue.find_all_by_id(params[:id] || params[:ids]) + raise ActiveRecord::RecordNotFound if @issues.empty? + raise Unauthorized unless @issues.all?(&:visible?) + @projects = @issues.collect(&:project).compact.uniq + @project = @projects.first if @projects.size == 1 + rescue ActiveRecord::RecordNotFound + render_404 + end + + def find_attachments + if (attachments = params[:attachments]).present? + att = attachments.values.collect do |attachment| + Attachment.find_by_token( attachment[:token] ) if attachment[:token].present? + end + att.compact! + end + @attachments = att || [] + end + + # make sure that the user is a member of the project (or admin) if project is private + # used as a before_filter for actions that do not require any particular permission on the project + def check_project_privacy + if @project && !@project.archived? + if @project.visible? + true + else + deny_access + end + else + @project = nil + render_404 + false + end + end + + def back_url + url = params[:back_url] + if url.nil? && referer = request.env['HTTP_REFERER'] + url = CGI.unescape(referer.to_s) + end + url + end + + def redirect_back_or_default(default) + back_url = params[:back_url].to_s + if back_url.present? + begin + uri = URI.parse(back_url) + # do not redirect user to another host or to the login or register page + #by young + if (uri.relative? || (uri.host == request.host)) && !uri.path.match(%r{/(login|account/register)}) && (uri.path!='/') + redirect_to(back_url) + return + end + rescue URI::InvalidURIError + logger.warn("Could not redirect to invalid URL #{back_url}") + # redirect to default + end + end + redirect_to default + false + end + + # Redirects to the request referer if present, redirects to args or call block otherwise. + def redirect_to_referer_or(*args, &block) + redirect_to :back + rescue ::ActionController::RedirectBackError + if args.any? + redirect_to *args + elsif block_given? + block.call + else + raise "#redirect_to_referer_or takes arguments or a block" + end + end + + def render_403(options={}) + @project = nil + render_error({:message => :notice_not_authorized, :status => 403}.merge(options)) + return false + end + + def render_404(options={}) + render_error({:message => :notice_file_not_found, :status => 404}.merge(options)) + return false + end + + # Renders an error response + def render_error(arg) + arg = {:message => arg} unless arg.is_a?(Hash) + + @message = arg[:message] + @message = l(@message) if @message.is_a?(Symbol) + @status = arg[:status] || 500 + + respond_to do |format| + format.html { + render :template => 'common/error', :layout => use_layout, :status => @status + } + format.any { head @status } + end + end + + # Handler for ActionView::MissingTemplate exception + def missing_template + logger.warn "Missing template, responding with 404" + @project = nil + render_404 + end + + # Filter for actions that provide an API response + # but have no HTML representation for non admin users + def require_admin_or_api_request + return true if api_request? + if User.current.admin? + true + elsif User.current.logged? + render_error(:status => 406) + else + deny_access + end + end + + # Picks which layout to use based on the request + # + # @return [boolean, string] name of the layout to use or false for no layout + def use_layout + request.xhr? ? false : 'base' + end + + def invalid_authenticity_token + if api_request? + logger.error "Form authenticity token is missing or is invalid. API calls must include a proper Content-type header (text/xml or text/json)." + end + render_error "Invalid form authenticity token." + end + + def render_feed(items, options={}) + @items = items || [] + @items.sort! {|x,y| y.event_datetime <=> x.event_datetime } + @items = @items.slice(0, Setting.feeds_limit.to_i) + @title = options[:title] || Setting.app_title + render :template => "common/feed", :formats => [:atom], :layout => false, + :content_type => 'application/atom+xml' + end + + def self.accept_rss_auth(*actions) + if actions.any? + self.accept_rss_auth_actions = actions + else + self.accept_rss_auth_actions || [] + end + end + + def accept_rss_auth?(action=action_name) + self.class.accept_rss_auth.include?(action.to_sym) + end + + def self.accept_api_auth(*actions) + if actions.any? + self.accept_api_auth_actions = actions + else + self.accept_api_auth_actions || [] + end + end + + def accept_api_auth?(action=action_name) + self.class.accept_api_auth.include?(action.to_sym) + end + + # Returns the number of objects that should be displayed + # on the paginated list + def per_page_option + per_page = nil + if params[:per_page] && Setting.per_page_options_array.include?(params[:per_page].to_s.to_i) + per_page = params[:per_page].to_s.to_i + session[:per_page] = per_page + elsif session[:per_page] + per_page = session[:per_page] + else + per_page = Setting.per_page_options_array.first || 25 + end + per_page + end + + # Returns offset and limit used to retrieve objects + # for an API response based on offset, limit and page parameters + def api_offset_and_limit(options=params) + if options[:offset].present? + offset = options[:offset].to_i + if offset < 0 + offset = 0 + end + end + limit = options[:limit].to_i + if limit < 1 + limit = 25 + elsif limit > 100 + limit = 100 + end + if offset.nil? && options[:page].present? + offset = (options[:page].to_i - 1) * limit + offset = 0 if offset < 0 + offset ||= 0 + end + + + [offset, limit] + end + + # qvalues http header parser + # code taken from webrick + def parse_qvalues(value) + tmp = [] + if value + parts = value.split(/,\s*/) + parts.each {|part| + if m = %r{^([^\s,]+?)(?:;\s*q=(\d+(?:\.\d+)?))?$}.match(part) + val = m[1] + q = (m[2] or 1).to_f + tmp.push([val, q]) + end + } + tmp = tmp.sort_by{|val, q| -q} + tmp.collect!{|val, q| val} + end + return tmp + rescue + nil + end + + # Returns a string that can be used as filename value in Content-Disposition header + def filename_for_content_disposition(name) + request.env['HTTP_USER_AGENT'] =~ %r{MSIE} ? ERB::Util.url_encode(name) : name + end + + def api_request? + %w(xml json).include? params[:format] + end + + # Returns the API key present in the request + def api_key_from_request + if params[:key].present? + params[:key].to_s + elsif request.headers["X-Redmine-API-Key"].present? + request.headers["X-Redmine-API-Key"].to_s + end + end + + # Returns the API 'switch user' value if present + def api_switch_user_from_request + request.headers["X-Redmine-Switch-User"].to_s.presence + end + + # Renders a warning flash if obj has unsaved attachments + def render_attachment_warning_if_needed(obj) + flash[:warning] = l(:warning_attachments_not_saved, obj.unsaved_attachments.size) if obj.unsaved_attachments.present? + end + + # Sets the `flash` notice or error based the number of issues that did not save + # + # @param [Array, Issue] issues all of the saved and unsaved Issues + # @param [Array, Integer] unsaved_issue_ids the issue ids that were not saved + def set_flash_from_bulk_issue_save(issues, unsaved_issue_ids) + if unsaved_issue_ids.empty? + flash[:notice] = l(:notice_successful_update) unless issues.empty? + else + flash[:error] = l(:notice_failed_to_save_issues, + :count => unsaved_issue_ids.size, + :total => issues.size, + :ids => '#' + unsaved_issue_ids.join(', #')) + end + end + + # Rescues an invalid query statement. Just in case... + def query_statement_invalid(exception) + logger.error "Query::StatementInvalid: #{exception.message}" if logger + session.delete(:query) + sort_clear if respond_to?(:sort_clear) + render_error "An error occurred while executing the query and has been logged. Please report this error to your Redmine administrator." + end + + # Renders a 200 response for successfull updates or deletions via the API + def render_api_ok + render_api_head :ok + end + + # Renders a head API response + def render_api_head(status) + # #head would return a response body with one space + render :text => '', :status => status, :layout => nil + end + + # Renders API response on validation failure + def render_validation_errors(objects) + if objects.is_a?(Array) + @error_messages = objects.map {|object| object.errors.full_messages}.flatten + else + @error_messages = objects.errors.full_messages + end + render :template => 'common/error_messages.api', :status => :unprocessable_entity, :layout => nil + end + + # Overrides #_include_layout? so that #render with no arguments + # doesn't use the layout for api requests + def _include_layout?(*args) + api_request? ? false : super + end +end diff --git a/app/controllers/attachments_controller.rb b/app/controllers/attachments_controller.rb new file mode 100644 index 00000000..5a816a73 --- /dev/null +++ b/app/controllers/attachments_controller.rb @@ -0,0 +1,154 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class AttachmentsController < ApplicationController + before_filter :find_project, :except => :upload + before_filter :file_readable, :read_authorize, :only => [:show, :download, :thumbnail] + before_filter :delete_authorize, :only => :destroy + before_filter :authorize_global, :only => :upload + + accept_api_auth :show, :download, :upload + + def show + respond_to do |format| + format.html { + if @attachment.is_diff? + @diff = File.new(@attachment.diskfile, "rb").read + @diff_type = params[:type] || User.current.pref[:diff_type] || 'inline' + @diff_type = 'inline' unless %w(inline sbs).include?(@diff_type) + # Save diff type as user preference + if User.current.logged? && @diff_type != User.current.pref[:diff_type] + User.current.pref[:diff_type] = @diff_type + User.current.preference.save + end + render :action => 'diff' + elsif @attachment.is_text? && @attachment.filesize <= Setting.file_max_size_displayed.to_i.kilobyte + @content = File.new(@attachment.diskfile, "rb").read + render :action => 'file' + else + download + end + } + format.api + end + end + + def download + if @attachment.container.is_a?(Version) || @attachment.container.is_a?(Project) + @attachment.increment_download + end + + if stale?(:etag => @attachment.digest) + # images are sent inline + send_file @attachment.diskfile, :filename => filename_for_content_disposition(@attachment.filename), + :type => detect_content_type(@attachment), + :disposition => (@attachment.image? ? 'inline' : 'attachment') + end + end + + def thumbnail + if @attachment.thumbnailable? && thumbnail = @attachment.thumbnail(:size => params[:size]) + if stale?(:etag => thumbnail) + send_file thumbnail, + :filename => filename_for_content_disposition(@attachment.filename), + :type => detect_content_type(@attachment), + :disposition => 'inline' + end + else + # No thumbnail for the attachment or thumbnail could not be created + render :nothing => true, :status => 404 + end + end + + def upload + # Make sure that API users get used to set this content type + # as it won't trigger Rails' automatic parsing of the request body for parameters + unless request.content_type == 'application/octet-stream' + render :nothing => true, :status => 406 + return + end + + @attachment = Attachment.new(:file => request.raw_post) + @attachment.author = User.current + @attachment.filename = params[:filename].presence || Redmine::Utils.random_hex(16) + saved = @attachment.save + + respond_to do |format| + format.js + format.api { + if saved + render :action => 'upload', :status => :created + else + render_validation_errors(@attachment) + end + } + end + end + + def destroy + if @attachment.container.respond_to?(:init_journal) + @attachment.container.init_journal(User.current) + end + if @attachment.container + # Make sure association callbacks are called + @attachment.container.attachments.delete(@attachment) + else + @attachment.destroy + end + + respond_to do |format| + format.html { redirect_to_referer_or project_path(@project) } + format.js + end + end + +private + def find_project + @attachment = Attachment.find(params[:id]) + # Show 404 if the filename in the url is wrong + raise ActiveRecord::RecordNotFound if params[:filename] && params[:filename] != @attachment.filename + @project = @attachment.project + rescue ActiveRecord::RecordNotFound + render_404 + end + + # Checks that the file exists and is readable + def file_readable + if @attachment.readable? + true + else + logger.error "Cannot send attachment, #{@attachment.diskfile} does not exist or is unreadable." + render_404 + end + end + + def read_authorize + @attachment.visible? ? true : deny_access + end + + def delete_authorize + @attachment.deletable? ? true : deny_access + end + + def detect_content_type(attachment) + content_type = attachment.content_type + if content_type.blank? + content_type = Redmine::MimeType.of(attachment.filename) + end + content_type.to_s + end +end diff --git a/app/controllers/auth_sources_controller.rb b/app/controllers/auth_sources_controller.rb new file mode 100644 index 00000000..1ac5ca39 --- /dev/null +++ b/app/controllers/auth_sources_controller.rb @@ -0,0 +1,96 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class AuthSourcesController < ApplicationController + layout 'admin' + menu_item :ldap_authentication + + before_filter :require_admin + before_filter :find_auth_source, :only => [:edit, :update, :test_connection, :destroy] + + def index + @auth_source_pages, @auth_sources = paginate AuthSource, :per_page => 25 + end + + def new + klass_name = params[:type] || 'AuthSourceLdap' + @auth_source = AuthSource.new_subclass_instance(klass_name, params[:auth_source]) + render_404 unless @auth_source + end + + def create + @auth_source = AuthSource.new_subclass_instance(params[:type], params[:auth_source]) + if @auth_source.save + flash[:notice] = l(:notice_successful_create) + redirect_to auth_sources_path + else + render :action => 'new' + end + end + + def edit + end + + def update + if @auth_source.update_attributes(params[:auth_source]) + flash[:notice] = l(:notice_successful_update) + redirect_to auth_sources_path + else + render :action => 'edit' + end + end + + def test_connection + begin + @auth_source.test_connection + flash[:notice] = l(:notice_successful_connection) + rescue Exception => e + flash[:error] = l(:error_unable_to_connect, e.message) + end + redirect_to auth_sources_path + end + + def destroy + unless @auth_source.users.exists? + @auth_source.destroy + flash[:notice] = l(:notice_successful_delete) + end + redirect_to auth_sources_path + end + + def autocomplete_for_new_user + results = AuthSource.search(params[:term]) + + render :json => results.map {|result| { + 'value' => result[:login], + 'label' => "#{result[:login]} (#{result[:firstname]} #{result[:lastname]})", + 'login' => result[:login].to_s, + 'firstname' => result[:firstname].to_s, + 'lastname' => result[:lastname].to_s, + 'mail' => result[:mail].to_s, + 'auth_source_id' => result[:auth_source_id].to_s + }} + end + + private + + def find_auth_source + @auth_source = AuthSource.find(params[:id]) + rescue ActiveRecord::RecordNotFound + render_404 + end +end diff --git a/app/controllers/auto_completes_controller.rb b/app/controllers/auto_completes_controller.rb new file mode 100644 index 00000000..ea463e12 --- /dev/null +++ b/app/controllers/auto_completes_controller.rb @@ -0,0 +1,44 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class AutoCompletesController < ApplicationController + before_filter :find_project + + def issues + @issues = [] + q = (params[:q] || params[:term]).to_s.strip + if q.present? + scope = (params[:scope] == "all" || @project.nil? ? Issue : @project.issues).visible + if q.match(/\A#?(\d+)\z/) + @issues << scope.find_by_id($1.to_i) + end + @issues += scope.where("LOWER(#{Issue.table_name}.subject) LIKE LOWER(?)", "%#{q}%").order("#{Issue.table_name}.id DESC").limit(10).all + @issues.compact! + end + render :layout => false + end + + private + + def find_project + if params[:project_id].present? + @project = Project.find(params[:project_id]) + end + rescue ActiveRecord::RecordNotFound + render_404 + end +end diff --git a/app/controllers/avatar_controller.rb b/app/controllers/avatar_controller.rb new file mode 100644 index 00000000..0cf2014e --- /dev/null +++ b/app/controllers/avatar_controller.rb @@ -0,0 +1,78 @@ +class AvatarController < ApplicationController + + + #before_filter :set_cache_buster + include AvatarHelper + + def upload + # Make sure that API users get used to set this content type + # as it won't trigger Rails' automatic parsing of the request body for parameters + unless request.content_type == 'application/octet-stream' + render :nothing => true, :status => 406 + return + end + + unless request.raw_post.nil? + @source_type = params[:source_type] + @source_id = params[:source_id] + @temp_file = request.raw_post + if @temp_file.size > 0 + if @temp_file.respond_to?(:original_filename) + @image_file = @temp_file.original_filename + #image_file.force_encoding("UTF-8") if filename.respond_to?(:force_encoding) + else + @image_file=params[:filename] + end + end + end + if @temp_file && (@temp_file.size > 0) + diskfile=disk_filename(@source_type,@source_id) + @urlfile='/' << File.join("images","avatars",avatar_directory(@source_type),avatar_filename(@source_id,@image_file)) + logger.info("Saving avatar '#{diskfile}' (#{@temp_file.size} bytes)") + path = File.dirname(diskfile) + unless File.directory?(path) + FileUtils.mkdir_p(path) + end + md5 = Digest::MD5.new + File.open(diskfile, "wb") do |f| + if @temp_file.respond_to?(:read) + buffer = "" + while (buffer = @temp_file.read(8192)) + f.write(buffer) + md5.update(buffer) + end + else + f.write(@temp_file) + md5.update(@temp_file) + end + end +# self.digest = md5.hexdigest + end + @temp_file = nil + # @avatar = Avatar.new(:receive_file => request.raw_post) + # @avatar.source_id = User.current.id + # @avatar.image_file = params[:filename].presence || Redmine::Utils.random_hex(16) + # saved = @avatar.save + + respond_to do |format| + format.js + format.api { + if saved + render :action => 'upload', :status => :created + else + render_validation_errors(@avatar) + end + } + end + end + + private + + def set_cache_buster + response.headers["Cache-Control"] = "no-cache, no-store, max-age=0, must-revalidate" + response.headers["Pragma"] = "no-cache" + response.headers["Expires"] = "Fri, 01 Jan 1990 00:00:00 GMT" + end + + +end diff --git a/app/controllers/bids_controller.rb b/app/controllers/bids_controller.rb new file mode 100644 index 00000000..e785ff38 --- /dev/null +++ b/app/controllers/bids_controller.rb @@ -0,0 +1,154 @@ +class BidsController < ApplicationController + + before_filter :find_bid, :only => [:show, :show_project, :create, :destroy, :more, :back, :add] + + helper :watchers + def index + if params[:bid_title] + Bid.creat_bids(params[:bid_budget], params[:bid_deadline], params[:bid_title] , params[:bid_description]) + end + # @requirement_title = "4" + @offset = 0 + @limit = 20 + @bids = Bid.offset(@offset).limit(@limit).all + + end + + def show + @state = false + @user = @bid.author + @jour = @bid.journals_for_messages + @jour.each_with_index {|j,i| j.indice = i+1} + # + # @journals = @bid.journals.includes(:user, :details).reorder("#{Journal.table_name}.id ASC").all + #@journals.each_with_index {|j,i| j.indice = i+1} + respond_to do |format| + format.html { + render :layout => 'base_bids' + } + format.api + + end + end + + def show_project + @user = @bid.author + @bidding_project = @bid.biding_projects + respond_to do |format| + format.html { + render :layout => 'base_bids' + } + format.api + end + end + + def add + project_id = params[:bid_for_save][:project_id] + bid_message = params[:bid_for_save][:bid_message] + BidingProject.cerate_bidding(@bid.id, project_id, bid_message) + @bidding_project = @bid.biding_projects + respond_to do |format| + # format.html { redirect_to_referer_or {render :text => 'Watcher added.', :layout => true}} + format.js + #format.api { render_api_ok } + end + end + + def create + if params[:user_message].size>0 + message = params[:user_message] + @bid.add_jour(User.current, message) + # if a_message.size > 5 + # @message = a_message[-5, 5] + # else + # @message = a_message + # end + # @message_count = a_message.count + end + @jour = @bid.journals_for_messages + @jour.each_with_index {|j,i| j.indice = i+1} + @bid.set_commit(@jour.count) + + respond_to do |format| + # format.html { redirect_to_referer_or {render :text => 'Watcher added.', :layout => true}} + format.js + #format.api { render_api_ok } + end + end + + def destroy + JournalsForMessage.delete_message(params[:object_id]) + @jour = @bid.journals_for_messages + @jour.each_with_index {|j,i| j.indice = i+1} + @bid.set_commit(@jour.count) + # if a_message.size > 5 + # @message = a_message[-5, 5] + # else + # @message = a_message + # end + # @message_count = a_message.count + + respond_to do |format| + format.html { redirect_to :back } + format.js + #format.api { render_api_ok } + end + end + + def new + @jour = JournalsForMessage.find(params[:journal_id]) if params[:journal_id] + if @jour + user = @jour.user + text = @jour.notes + else + user = @bid.author + text = @bid.description + end + # Replaces pre blocks with [...] + text = text.to_s.strip.gsub(%r{
((.|\s)*?)
}m, '[...]') + @content = "#{ll(Setting.default_language, :text_user_wrote, user)}\n> " + @content << text.gsub(/(\r?\n|\r\n?)/, "\n> ") + "\n\n" + rescue ActiveRecord::RecordNotFound + render_404 + end + + def new_bid + + end + + def more + @jour = @bid.journals_for_messages + @jour.each_with_index {|j,i| j.indice = i+1} + @state = true + + respond_to do |format| + format.html { redirect_to :back } + format.js + #format.api { render_api_ok } + end + end + + def back + @jour = @bid.journals_for_messages + @jour.each_with_index {|j,i| j.indice = i+1} + @state = false + + respond_to do |format| + format.html { redirect_to :back } + format.js + #format.api { render_api_ok } + end + end + + private + + def find_bid + if params[:bid_id] + @bid = Bid.find(params[:bid_id]) + end + rescue + render_404 + end + +end + diff --git a/app/controllers/boards_controller.rb b/app/controllers/boards_controller.rb new file mode 100644 index 00000000..47f5c0f0 --- /dev/null +++ b/app/controllers/boards_controller.rb @@ -0,0 +1,111 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class BoardsController < ApplicationController + default_search_scope :messages + before_filter :find_project_by_project_id, :find_board_if_available, :authorize + accept_rss_auth :index, :show + + helper :sort + include SortHelper + helper :watchers + + def index + @boards = @project.boards.includes(:last_message => :author).all + # show the board if there is only one + if @boards.size == 1 + @board = @boards.first + show + end + end + + def show + respond_to do |format| + format.html { + sort_init 'updated_on', 'desc' + sort_update 'created_on' => "#{Message.table_name}.created_on", + 'replies' => "#{Message.table_name}.replies_count", + 'updated_on' => "COALESCE(last_replies_messages.created_on, #{Message.table_name}.created_on)" + + @topic_count = @board.topics.count + @topic_pages = Paginator.new @topic_count, per_page_option, params['page'] + @topics = @board.topics. + reorder("#{Message.table_name}.sticky DESC"). + includes(:last_reply). + limit(@topic_pages.per_page). + offset(@topic_pages.offset). + order(sort_clause). + preload(:author, {:last_reply => :author}). + all + @message = Message.new(:board => @board) + render :action => 'show', :layout => !request.xhr? + } + format.atom { + @messages = @board.messages. + reorder('created_on DESC'). + includes(:author, :board). + limit(Setting.feeds_limit.to_i). + all + render_feed(@messages, :title => "#{@project}: #{@board}") + } + end + end + + def new + @board = @project.boards.build + @board.safe_attributes = params[:board] + end + + def create + @board = @project.boards.build + @board.safe_attributes = params[:board] + if @board.save + flash[:notice] = l(:notice_successful_create) + redirect_to_settings_in_projects + else + render :action => 'new' + end + end + + def edit + end + + def update + @board.safe_attributes = params[:board] + if @board.save + redirect_to_settings_in_projects + else + render :action => 'edit' + end + end + + def destroy + @board.destroy + redirect_to_settings_in_projects + end + +private + def redirect_to_settings_in_projects + redirect_to settings_project_path(@project, :tab => 'boards') + end + + def find_board_if_available + @board = @project.boards.find(params[:id]) if params[:id] + rescue ActiveRecord::RecordNotFound + render_404 + end +end diff --git a/app/controllers/calendars_controller.rb b/app/controllers/calendars_controller.rb new file mode 100644 index 00000000..c8f8bbbd --- /dev/null +++ b/app/controllers/calendars_controller.rb @@ -0,0 +1,56 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class CalendarsController < ApplicationController + menu_item :calendar + before_filter :find_optional_project + + rescue_from Query::StatementInvalid, :with => :query_statement_invalid + + helper :issues + helper :projects + helper :queries + include QueriesHelper + helper :sort + include SortHelper + + def show + if params[:year] and params[:year].to_i > 1900 + @year = params[:year].to_i + if params[:month] and params[:month].to_i > 0 and params[:month].to_i < 13 + @month = params[:month].to_i + end + end + @year ||= Date.today.year + @month ||= Date.today.month + + @calendar = Redmine::Helpers::Calendar.new(Date.civil(@year, @month, 1), current_language, :month) + retrieve_query + @query.group_by = nil + if @query.valid? + events = [] + events += @query.issues(:include => [:tracker, :assigned_to, :priority], + :conditions => ["((start_date BETWEEN ? AND ?) OR (due_date BETWEEN ? AND ?))", @calendar.startdt, @calendar.enddt, @calendar.startdt, @calendar.enddt] + ) + events += @query.versions(:conditions => ["effective_date BETWEEN ? AND ?", @calendar.startdt, @calendar.enddt]) + + @calendar.events = events + end + + render :action => 'show', :layout => 'base_projects' + end +end diff --git a/app/controllers/comments_controller.rb b/app/controllers/comments_controller.rb new file mode 100644 index 00000000..b2689d0c --- /dev/null +++ b/app/controllers/comments_controller.rb @@ -0,0 +1,53 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class CommentsController < ApplicationController + default_search_scope :news + model_object News + before_filter :find_model_object + before_filter :find_project_from_association + before_filter :authorize + + def create + raise Unauthorized unless @news.commentable? + + @comment = Comment.new + @comment.safe_attributes = params[:comment] + @comment.author = User.current + if @news.comments << @comment + flash[:notice] = l(:label_comment_added) + end + + redirect_to news_path(@news) + end + + def destroy + @news.comments.find(params[:comment_id]).destroy + redirect_to news_path(@news) + end + + private + + # ApplicationController's find_model_object sets it based on the controller + # name so it needs to be overriden and set to @news instead + def find_model_object + super + @news = @object + @comment = nil + @news + end +end diff --git a/app/controllers/context_menus_controller.rb b/app/controllers/context_menus_controller.rb new file mode 100644 index 00000000..bc434ea1 --- /dev/null +++ b/app/controllers/context_menus_controller.rb @@ -0,0 +1,89 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class ContextMenusController < ApplicationController + helper :watchers + helper :issues + + def issues + @issues = Issue.visible.all(:conditions => {:id => params[:ids]}, :include => :project) + (render_404; return) unless @issues.present? + if (@issues.size == 1) + @issue = @issues.first + end + @issue_ids = @issues.map(&:id).sort + + @allowed_statuses = @issues.map(&:new_statuses_allowed_to).reduce(:&) + @projects = @issues.collect(&:project).compact.uniq + @project = @projects.first if @projects.size == 1 + + @can = {:edit => User.current.allowed_to?(:edit_issues, @projects), + :log_time => (@project && User.current.allowed_to?(:log_time, @project)), + :update => (User.current.allowed_to?(:edit_issues, @projects) || (User.current.allowed_to?(:change_status, @projects) && !@allowed_statuses.blank?)), + :move => (@project && User.current.allowed_to?(:move_issues, @project)), + :copy => (@issue && @project.trackers.include?(@issue.tracker) && User.current.allowed_to?(:add_issues, @project)), + :delete => User.current.allowed_to?(:delete_issues, @projects) + } + if @project + if @issue + @assignables = @issue.assignable_users + else + @assignables = @project.assignable_users + end + @trackers = @project.trackers + else + #when multiple projects, we only keep the intersection of each set + @assignables = @projects.map(&:assignable_users).reduce(:&) + @trackers = @projects.map(&:trackers).reduce(:&) + end + @versions = @projects.map {|p| p.shared_versions.open}.reduce(:&) + + @priorities = IssuePriority.active.reverse + @back = back_url + + @options_by_custom_field = {} + if @can[:edit] + custom_fields = @issues.map(&:available_custom_fields).reduce(:&).select do |f| + %w(bool list user version).include?(f.field_format) && !f.multiple? + end + custom_fields.each do |field| + values = field.possible_values_options(@projects) + if values.any? + @options_by_custom_field[field] = values + end + end + end + + @safe_attributes = @issues.map(&:safe_attribute_names).reduce(:&) + render :layout => false + end + + def time_entries + @time_entries = TimeEntry.all( + :conditions => {:id => params[:ids]}, :include => :project) + (render_404; return) unless @time_entries.present? + + @projects = @time_entries.collect(&:project).compact.uniq + @project = @projects.first if @projects.size == 1 + @activities = TimeEntryActivity.shared.active + @can = {:edit => User.current.allowed_to?(:edit_time_entries, @projects), + :delete => User.current.allowed_to?(:edit_time_entries, @projects) + } + @back = back_url + render :layout => false + end +end diff --git a/app/controllers/custom_fields_controller.rb b/app/controllers/custom_fields_controller.rb new file mode 100644 index 00000000..c20516a1 --- /dev/null +++ b/app/controllers/custom_fields_controller.rb @@ -0,0 +1,81 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class CustomFieldsController < ApplicationController + layout 'admin' + + before_filter :require_admin + before_filter :build_new_custom_field, :only => [:new, :create] + before_filter :find_custom_field, :only => [:edit, :update, :destroy] + + def index + @custom_fields_by_type = CustomField.all.group_by {|f| f.class.name } + @tab = params[:tab] || 'IssueCustomField' + end + + def new + end + + def create + if @custom_field.save + flash[:notice] = l(:notice_successful_create) + call_hook(:controller_custom_fields_new_after_save, :params => params, :custom_field => @custom_field) + redirect_to custom_fields_path(:tab => @custom_field.class.name) + else + render :action => 'new' + end + end + + def edit + end + + def update + if @custom_field.update_attributes(params[:custom_field]) + flash[:notice] = l(:notice_successful_update) + call_hook(:controller_custom_fields_edit_after_save, :params => params, :custom_field => @custom_field) + redirect_to custom_fields_path(:tab => @custom_field.class.name) + else + render :action => 'edit' + end + end + + def destroy + begin + @custom_field.destroy + rescue + flash[:error] = l(:error_can_not_delete_custom_field) + end + redirect_to custom_fields_path(:tab => @custom_field.class.name) + end + + private + + def build_new_custom_field + @custom_field = CustomField.new_subclass_instance(params[:type], params[:custom_field]) + if @custom_field.nil? + render_404 + else + @custom_field.default_value = nil + end + end + + def find_custom_field + @custom_field = CustomField.find(params[:id]) + rescue ActiveRecord::RecordNotFound + render_404 + end +end diff --git a/app/controllers/documents_controller.rb b/app/controllers/documents_controller.rb new file mode 100644 index 00000000..8daba49c --- /dev/null +++ b/app/controllers/documents_controller.rb @@ -0,0 +1,95 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class DocumentsController < ApplicationController + layout 'base_projects' + default_search_scope :documents + model_object Document + before_filter :find_project_by_project_id, :only => [:index, :new, :create] + before_filter :find_model_object, :except => [:index, :new, :create] + before_filter :find_project_from_association, :except => [:index, :new, :create] + before_filter :authorize + + helper :attachments + + def index + @sort_by = %w(category date title author).include?(params[:sort_by]) ? params[:sort_by] : 'category' + documents = @project.documents.includes(:attachments, :category).all + case @sort_by + when 'date' + @grouped = documents.group_by {|d| d.updated_on.to_date } + when 'title' + @grouped = documents.group_by {|d| d.title.first.upcase} + when 'author' + @grouped = documents.select{|d| d.attachments.any?}.group_by {|d| d.attachments.last.author} + else + @grouped = documents.group_by(&:category) + end + @document = @project.documents.build + render :layout => false if request.xhr? + end + + def show + @attachments = @document.attachments.all + end + + def new + @document = @project.documents.build + @document.safe_attributes = params[:document] + end + + def create + @document = @project.documents.build + @document.safe_attributes = params[:document] + @document.save_attachments(params[:attachments]) + if @document.save + render_attachment_warning_if_needed(@document) + flash[:notice] = l(:notice_successful_create) + redirect_to project_documents_path(@project) + else + render :action => 'new' + end + end + + def edit + end + + def update + @document.safe_attributes = params[:document] + if request.put? and @document.save + flash[:notice] = l(:notice_successful_update) + redirect_to document_path(@document) + else + render :action => 'edit' + end + end + + def destroy + @document.destroy if request.delete? + redirect_to project_documents_path(@project) + end + + def add_attachment + attachments = Attachment.attach_files(@document, params[:attachments]) + render_attachment_warning_if_needed(@document) + + if attachments.present? && attachments[:files].present? && Setting.notified_events.include?('document_added') + Mailer.attachments_added(attachments[:files]).deliver + end + redirect_to document_path(@document) + end +end diff --git a/app/controllers/enumerations_controller.rb b/app/controllers/enumerations_controller.rb new file mode 100644 index 00000000..4e5475be --- /dev/null +++ b/app/controllers/enumerations_controller.rb @@ -0,0 +1,98 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class EnumerationsController < ApplicationController + layout 'admin' + + before_filter :require_admin, :except => :index + before_filter :require_admin_or_api_request, :only => :index + before_filter :build_new_enumeration, :only => [:new, :create] + before_filter :find_enumeration, :only => [:edit, :update, :destroy] + accept_api_auth :index + + helper :custom_fields + + def index + respond_to do |format| + format.html + format.api { + @klass = Enumeration.get_subclass(params[:type]) + if @klass + @enumerations = @klass.shared.sorted.all + else + render_404 + end + } + end + end + + def new + end + + def create + if request.post? && @enumeration.save + flash[:notice] = l(:notice_successful_create) + redirect_to enumerations_path + else + render :action => 'new' + end + end + + def edit + end + + def update + if request.put? && @enumeration.update_attributes(params[:enumeration]) + flash[:notice] = l(:notice_successful_update) + redirect_to enumerations_path + else + render :action => 'edit' + end + end + + def destroy + if !@enumeration.in_use? + # No associated objects + @enumeration.destroy + redirect_to enumerations_path + return + elsif params[:reassign_to_id] + if reassign_to = @enumeration.class.find_by_id(params[:reassign_to_id]) + @enumeration.destroy(reassign_to) + redirect_to enumerations_path + return + end + end + @enumerations = @enumeration.class.all - [@enumeration] + end + + private + + def build_new_enumeration + class_name = params[:enumeration] && params[:enumeration][:type] || params[:type] + @enumeration = Enumeration.new_subclass_instance(class_name, params[:enumeration]) + if @enumeration.nil? + render_404 + end + end + + def find_enumeration + @enumeration = Enumeration.find(params[:id]) + rescue ActiveRecord::RecordNotFound + render_404 + end +end diff --git a/app/controllers/files_controller.rb b/app/controllers/files_controller.rb new file mode 100644 index 00000000..468ad72e --- /dev/null +++ b/app/controllers/files_controller.rb @@ -0,0 +1,54 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class FilesController < ApplicationController + layout 'base_projects' + menu_item :files + + before_filter :find_project_by_project_id + before_filter :authorize + + helper :sort + include SortHelper + + def index + sort_init 'filename', 'asc' + sort_update 'filename' => "#{Attachment.table_name}.filename", + 'created_on' => "#{Attachment.table_name}.created_on", + 'size' => "#{Attachment.table_name}.filesize", + 'downloads' => "#{Attachment.table_name}.downloads" + + @containers = [ Project.includes(:attachments).reorder(sort_clause).find(@project.id)] + @containers += @project.versions.includes(:attachments).reorder(sort_clause).all.sort.reverse + render :layout => !request.xhr? + end + + def new + @versions = @project.versions.sort + end + + def create + container = (params[:version_id].blank? ? @project : @project.versions.find_by_id(params[:version_id])) + attachments = Attachment.attach_files(container, params[:attachments]) + render_attachment_warning_if_needed(container) + + if !attachments.empty? && !attachments[:files].blank? && Setting.notified_events.include?('file_added') + Mailer.attachments_added(attachments[:files]).deliver + end + redirect_to project_files_path(@project) + end +end diff --git a/app/controllers/gantts_controller.rb b/app/controllers/gantts_controller.rb new file mode 100644 index 00000000..a7d4039d --- /dev/null +++ b/app/controllers/gantts_controller.rb @@ -0,0 +1,48 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class GanttsController < ApplicationController + menu_item :gantt + before_filter :find_optional_project + + rescue_from Query::StatementInvalid, :with => :query_statement_invalid + + helper :gantt + helper :issues + helper :projects + helper :queries + include QueriesHelper + helper :sort + include SortHelper + include Redmine::Export::PDF + + def show + @gantt = Redmine::Helpers::Gantt.new(params) + @gantt.project = @project + retrieve_query + @query.group_by = nil + @gantt.query = @query if @query.valid? + + basename = (@project ? "#{@project.identifier}-" : '') + 'gantt' + + respond_to do |format| + format.html { render :action => "show", :layout => 'base_projects' } + format.png { send_data(@gantt.to_image, :disposition => 'inline', :type => 'image/png', :filename => "#{basename}.png") } if @gantt.respond_to?('to_image') + format.pdf { send_data(@gantt.to_pdf, :type => 'application/pdf', :filename => "#{basename}.pdf") } + end + end +end diff --git a/app/controllers/groups_controller.rb b/app/controllers/groups_controller.rb new file mode 100644 index 00000000..b2f9d6af --- /dev/null +++ b/app/controllers/groups_controller.rb @@ -0,0 +1,141 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class GroupsController < ApplicationController + layout 'admin' + + before_filter :require_admin + before_filter :find_group, :except => [:index, :new, :create] + accept_api_auth :index, :show, :create, :update, :destroy, :add_users, :remove_user + + helper :custom_fields + + def index + @groups = Group.sorted.all + + respond_to do |format| + format.html + format.api + end + end + + def show + respond_to do |format| + format.html + format.api + end + end + + def new + @group = Group.new + end + + def create + @group = Group.new + @group.safe_attributes = params[:group] + + respond_to do |format| + if @group.save + format.html { + flash[:notice] = l(:notice_successful_create) + redirect_to(params[:continue] ? new_group_path : groups_path) + } + format.api { render :action => 'show', :status => :created, :location => group_url(@group) } + else + format.html { render :action => "new" } + format.api { render_validation_errors(@group) } + end + end + end + + def edit + end + + def update + @group.safe_attributes = params[:group] + + respond_to do |format| + if @group.save + flash[:notice] = l(:notice_successful_update) + format.html { redirect_to(groups_path) } + format.api { render_api_ok } + else + format.html { render :action => "edit" } + format.api { render_validation_errors(@group) } + end + end + end + + def destroy + @group.destroy + + respond_to do |format| + format.html { redirect_to(groups_path) } + format.api { render_api_ok } + end + end + + def add_users + @users = User.find_all_by_id(params[:user_id] || params[:user_ids]) + @group.users << @users if request.post? + respond_to do |format| + format.html { redirect_to edit_group_path(@group, :tab => 'users') } + format.js + format.api { render_api_ok } + end + end + + def remove_user + @group.users.delete(User.find(params[:user_id])) if request.delete? + respond_to do |format| + format.html { redirect_to edit_group_path(@group, :tab => 'users') } + format.js + format.api { render_api_ok } + end + end + + def autocomplete_for_user + respond_to do |format| + format.js + end + end + + def edit_membership + @membership = Member.edit_membership(params[:membership_id], params[:membership], @group) + @membership.save if request.post? + respond_to do |format| + format.html { redirect_to edit_group_path(@group, :tab => 'memberships') } + format.js + end + end + + def destroy_membership + Member.find(params[:membership_id]).destroy if request.post? + respond_to do |format| + format.html { redirect_to edit_group_path(@group, :tab => 'memberships') } + format.js + end + end + + private + + def find_group + @group = Group.find(params[:id]) + rescue ActiveRecord::RecordNotFound + render_404 + end +end diff --git a/app/controllers/issue_categories_controller.rb b/app/controllers/issue_categories_controller.rb new file mode 100644 index 00000000..371d9379 --- /dev/null +++ b/app/controllers/issue_categories_controller.rb @@ -0,0 +1,122 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class IssueCategoriesController < ApplicationController + menu_item :settings + model_object IssueCategory + before_filter :find_model_object, :except => [:index, :new, :create] + before_filter :find_project_from_association, :except => [:index, :new, :create] + before_filter :find_project_by_project_id, :only => [:index, :new, :create] + before_filter :authorize + accept_api_auth :index, :show, :create, :update, :destroy + + def index + respond_to do |format| + format.html { redirect_to_settings_in_projects } + format.api { @categories = @project.issue_categories.all } + end + end + + def show + respond_to do |format| + format.html { redirect_to_settings_in_projects } + format.api + end + end + + def new + @category = @project.issue_categories.build + @category.safe_attributes = params[:issue_category] + + respond_to do |format| + format.html{render :layout => 'base_projects'} + format.js + end + end + + def create + @category = @project.issue_categories.build + @category.safe_attributes = params[:issue_category] + if @category.save + respond_to do |format| + format.html do + flash[:notice] = l(:notice_successful_create) + redirect_to_settings_in_projects + end + format.js + format.api { render :action => 'show', :status => :created, :location => issue_category_path(@category) } + end + else + respond_to do |format| + format.html { render :action => 'new'} + format.js { render :action => 'new'} + format.api { render_validation_errors(@category) } + end + end + end + + def edit + end + + def update + @category.safe_attributes = params[:issue_category] + if @category.save + respond_to do |format| + format.html { + flash[:notice] = l(:notice_successful_update) + redirect_to_settings_in_projects + } + format.api { render_api_ok } + end + else + respond_to do |format| + format.html { render :action => 'edit' } + format.api { render_validation_errors(@category) } + end + end + end + + def destroy + @issue_count = @category.issues.size + if @issue_count == 0 || params[:todo] || api_request? + reassign_to = nil + if params[:reassign_to_id] && (params[:todo] == 'reassign' || params[:todo].blank?) + reassign_to = @project.issue_categories.find_by_id(params[:reassign_to_id]) + end + @category.destroy(reassign_to) + respond_to do |format| + format.html { redirect_to_settings_in_projects } + format.api { render_api_ok } + end + return + end + @categories = @project.issue_categories - [@category] + end + + private + + def redirect_to_settings_in_projects + redirect_to settings_project_path(@project, :tab => 'categories') + end + + # Wrap ApplicationController's find_model_object method to set + # @category instead of just @issue_category + def find_model_object + super + @category = @object + end +end diff --git a/app/controllers/issue_relations_controller.rb b/app/controllers/issue_relations_controller.rb new file mode 100644 index 00000000..cd008529 --- /dev/null +++ b/app/controllers/issue_relations_controller.rb @@ -0,0 +1,88 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class IssueRelationsController < ApplicationController + before_filter :find_issue, :find_project_from_association, :authorize, :only => [:index, :create] + before_filter :find_relation, :except => [:index, :create] + + accept_api_auth :index, :show, :create, :destroy + + def index + @relations = @issue.relations + + respond_to do |format| + format.html { render :nothing => true } + format.api + end + end + + def show + raise Unauthorized unless @relation.visible? + + respond_to do |format| + format.html { render :nothing => true } + format.api + end + end + + def create + @relation = IssueRelation.new(params[:relation]) + @relation.issue_from = @issue + if params[:relation] && m = params[:relation][:issue_to_id].to_s.strip.match(/^#?(\d+)$/) + @relation.issue_to = Issue.visible.find_by_id(m[1].to_i) + end + saved = @relation.save + + respond_to do |format| + format.html { redirect_to issue_path(@issue) } + format.js { + @relations = @issue.reload.relations.select {|r| r.other_issue(@issue) && r.other_issue(@issue).visible? } + } + format.api { + if saved + render :action => 'show', :status => :created, :location => relation_url(@relation) + else + render_validation_errors(@relation) + end + } + end + end + + def destroy + raise Unauthorized unless @relation.deletable? + @relation.destroy + + respond_to do |format| + format.html { redirect_to issue_path(@relation.issue_from) } + format.js + format.api { render_api_ok } + end + end + +private + def find_issue + @issue = @object = Issue.find(params[:issue_id]) + rescue ActiveRecord::RecordNotFound + render_404 + end + + def find_relation + @relation = IssueRelation.find(params[:id]) + rescue ActiveRecord::RecordNotFound + render_404 + end +end diff --git a/app/controllers/issue_statuses_controller.rb b/app/controllers/issue_statuses_controller.rb new file mode 100644 index 00000000..cedd6a9f --- /dev/null +++ b/app/controllers/issue_statuses_controller.rb @@ -0,0 +1,81 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class IssueStatusesController < ApplicationController + layout 'admin' + + before_filter :require_admin, :except => :index + before_filter :require_admin_or_api_request, :only => :index + accept_api_auth :index + + def index + respond_to do |format| + format.html { + @issue_status_pages, @issue_statuses = paginate IssueStatus.sorted, :per_page => 25 + render :action => "index", :layout => false if request.xhr? + } + format.api { + @issue_statuses = IssueStatus.all(:order => 'position') + } + end + end + + def new + @issue_status = IssueStatus.new + end + + def create + @issue_status = IssueStatus.new(params[:issue_status]) + if request.post? && @issue_status.save + flash[:notice] = l(:notice_successful_create) + redirect_to issue_statuses_path + else + render :action => 'new' + end + end + + def edit + @issue_status = IssueStatus.find(params[:id]) + end + + def update + @issue_status = IssueStatus.find(params[:id]) + if request.put? && @issue_status.update_attributes(params[:issue_status]) + flash[:notice] = l(:notice_successful_update) + redirect_to issue_statuses_path + else + render :action => 'edit' + end + end + + def destroy + IssueStatus.find(params[:id]).destroy + redirect_to issue_statuses_path + rescue + flash[:error] = l(:error_unable_delete_issue_status) + redirect_to issue_statuses_path + end + + def update_issue_done_ratio + if request.post? && IssueStatus.update_issue_done_ratios + flash[:notice] = l(:notice_issue_done_ratios_updated) + else + flash[:error] = l(:error_issue_done_ratios_not_updated) + end + redirect_to issue_statuses_path + end +end diff --git a/app/controllers/issues_controller.rb b/app/controllers/issues_controller.rb new file mode 100644 index 00000000..4d0ea759 --- /dev/null +++ b/app/controllers/issues_controller.rb @@ -0,0 +1,443 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class IssuesController < ApplicationController + menu_item :new_issue, :only => [:new, :create] + default_search_scope :issues + + before_filter :find_issue, :only => [:show, :edit, :update] + before_filter :find_issues, :only => [:bulk_edit, :bulk_update, :destroy] + before_filter :find_project, :only => [:new, :create, :update_form] + before_filter :authorize, :except => [:index] + before_filter :find_optional_project, :only => [:index] + before_filter :check_for_default_issue_status, :only => [:new, :create] + before_filter :build_new_issue_from_params, :only => [:new, :create, :update_form] + accept_rss_auth :index, :show + accept_api_auth :index, :show, :create, :update, :destroy + + rescue_from Query::StatementInvalid, :with => :query_statement_invalid + + helper :journals + helper :projects + include ProjectsHelper + helper :custom_fields + include CustomFieldsHelper + helper :issue_relations + include IssueRelationsHelper + helper :watchers + include WatchersHelper + helper :attachments + include AttachmentsHelper + helper :queries + include QueriesHelper + helper :repositories + include RepositoriesHelper + helper :sort + include SortHelper + include IssuesHelper + helper :timelog + include Redmine::Export::PDF + + def index + retrieve_query + sort_init(@query.sort_criteria.empty? ? [['id', 'desc']] : @query.sort_criteria) + sort_update(@query.sortable_columns) + @query.sort_criteria = sort_criteria.to_a + + @project_base_tag = (params[:project_id] || @issue.project)?'base_projects':'base'#by young + + if @query.valid? + case params[:format] + when 'csv', 'pdf' + @limit = Setting.issues_export_limit.to_i + when 'atom' + @limit = Setting.feeds_limit.to_i + when 'xml', 'json' + @offset, @limit = api_offset_and_limit + else + @limit = per_page_option + end + + @issue_count = @query.issue_count + @issue_pages = Paginator.new @issue_count, @limit, params['page'] + @offset ||= @issue_pages.offset + @issues = @query.issues(:include => [:assigned_to, :tracker, :priority, :category, :fixed_version], + :order => sort_clause, + :offset => @offset, + :limit => @limit) + @issue_count_by_group = @query.issue_count_by_group + + respond_to do |format| + format.html { render :template => 'issues/index', :layout => @project_base_tag }#by young + format.api { + Issue.load_visible_relations(@issues) if include_in_api_response?('relations') + } + format.atom { render_feed(@issues, :title => "#{@project || Setting.app_title}: #{l(:label_issue_plural)}") } + format.csv { send_data(query_to_csv(@issues, @query, params), :type => 'text/csv; header=present', :filename => 'issues.csv') } + format.pdf { send_data(issues_to_pdf(@issues, @project, @query), :type => 'application/pdf', :filename => 'issues.pdf') } + end + else + respond_to do |format| + format.html { render(:template => 'issues/index', :layout => @project_base_tag) }#by young + format.any(:atom, :csv, :pdf) { render(:nothing => true) } + format.api { render_validation_errors(@query) } + end + end + rescue ActiveRecord::RecordNotFound + render_404 + end + + def show + @journals = @issue.journals.includes(:user, :details).reorder("#{Journal.table_name}.id ASC").all + @journals.each_with_index {|j,i| j.indice = i+1} + @journals.reject!(&:private_notes?) unless User.current.allowed_to?(:view_private_notes, @issue.project) + @journals.reverse! if User.current.wants_comments_in_reverse_order? + + @changesets = @issue.changesets.visible.all + @changesets.reverse! if User.current.wants_comments_in_reverse_order? + + @relations = @issue.relations.select {|r| r.other_issue(@issue) && r.other_issue(@issue).visible? } + @allowed_statuses = @issue.new_statuses_allowed_to(User.current) + @edit_allowed = User.current.allowed_to?(:edit_issues, @project) + @priorities = IssuePriority.active + @time_entry = TimeEntry.new(:issue => @issue, :project => @issue.project) + + @project_base_tag = (params[:project_id] || @issue.project)?'base_projects':'base'#by young + respond_to do |format| + format.html { + retrieve_previous_and_next_issue_ids + render :template => 'issues/show', :layout => @project_base_tag#by young + } + format.api + format.atom { render :template => 'journals/index', :layout => false, :content_type => 'application/atom+xml' } + format.pdf { + pdf = issue_to_pdf(@issue, :journals => @journals) + send_data(pdf, :type => 'application/pdf', :filename => "#{@project.identifier}-#{@issue.id}.pdf") + } + end + end + + # Add a new issue + # The new issue will be created from an existing one if copy_from parameter is given + def new + respond_to do |format| + format.html { render :action => 'new', :layout => 'base_projects' } + end + end + + def create + call_hook(:controller_issues_new_before_save, { :params => params, :issue => @issue }) + @issue.save_attachments(params[:attachments] || (params[:issue] && params[:issue][:uploads])) + if @issue.save + call_hook(:controller_issues_new_after_save, { :params => params, :issue => @issue}) + respond_to do |format| + format.html { + render_attachment_warning_if_needed(@issue) + flash[:notice] = l(:notice_issue_successful_create, :id => view_context.link_to("##{@issue.id}", issue_path(@issue), :title => @issue.subject)) + if params[:continue] + attrs = {:tracker_id => @issue.tracker, :parent_issue_id => @issue.parent_issue_id}.reject {|k,v| v.nil?} + redirect_to new_project_issue_path(@issue.project, :issue => attrs) + else + redirect_to issue_path(@issue) + end + } + format.api { render :action => 'show', :status => :created, :location => issue_url(@issue) } + end + return + else + respond_to do |format| + format.html { render :action => 'new' } + format.api { render_validation_errors(@issue) } + end + end + end + + def edit + return unless update_issue_from_params + + respond_to do |format| + format.html { } + format.xml { } + end + end + + def update + return unless update_issue_from_params + @issue.save_attachments(params[:attachments] || (params[:issue] && params[:issue][:uploads])) + saved = false + begin + saved = @issue.save_issue_with_child_records(params, @time_entry) + rescue ActiveRecord::StaleObjectError + @conflict = true + if params[:last_journal_id] + @conflict_journals = @issue.journals_after(params[:last_journal_id]).all + @conflict_journals.reject!(&:private_notes?) unless User.current.allowed_to?(:view_private_notes, @issue.project) + end + end + + if saved + render_attachment_warning_if_needed(@issue) + flash[:notice] = l(:notice_successful_update) unless @issue.current_journal.new_record? + + respond_to do |format| + format.html { redirect_back_or_default issue_path(@issue) } + format.api { render_api_ok } + end + else + respond_to do |format| + format.html { render :action => 'edit' } + format.api { render_validation_errors(@issue) } + end + end + end + + # Updates the issue form when changing the project, status or tracker + # on issue creation/update + def update_form + end + + # Bulk edit/copy a set of issues + def bulk_edit + @issues.sort! + @copy = params[:copy].present? + @notes = params[:notes] + + if User.current.allowed_to?(:move_issues, @projects) + @allowed_projects = Issue.allowed_target_projects_on_move + if params[:issue] + @target_project = @allowed_projects.detect {|p| p.id.to_s == params[:issue][:project_id].to_s} + if @target_project + target_projects = [@target_project] + end + end + end + target_projects ||= @projects + + if @copy + @available_statuses = [IssueStatus.default] + else + @available_statuses = @issues.map(&:new_statuses_allowed_to).reduce(:&) + end + @custom_fields = target_projects.map{|p|p.all_issue_custom_fields}.reduce(:&) + @assignables = target_projects.map(&:assignable_users).reduce(:&) + @trackers = target_projects.map(&:trackers).reduce(:&) + @versions = target_projects.map {|p| p.shared_versions.open}.reduce(:&) + @categories = target_projects.map {|p| p.issue_categories}.reduce(:&) + if @copy + @attachments_present = @issues.detect {|i| i.attachments.any?}.present? + @subtasks_present = @issues.detect {|i| !i.leaf?}.present? + end + + @safe_attributes = @issues.map(&:safe_attribute_names).reduce(:&) + render :layout => false if request.xhr? + end + + def bulk_update + @issues.sort! + @copy = params[:copy].present? + attributes = parse_params_for_bulk_issue_attributes(params) + + unsaved_issue_ids = [] + moved_issues = [] + + if @copy && params[:copy_subtasks].present? + # Descendant issues will be copied with the parent task + # Don't copy them twice + @issues.reject! {|issue| @issues.detect {|other| issue.is_descendant_of?(other)}} + end + + @issues.each do |issue| + issue.reload + if @copy + issue = issue.copy({}, + :attachments => params[:copy_attachments].present?, + :subtasks => params[:copy_subtasks].present? + ) + end + journal = issue.init_journal(User.current, params[:notes]) + issue.safe_attributes = attributes + call_hook(:controller_issues_bulk_edit_before_save, { :params => params, :issue => issue }) + if issue.save + moved_issues << issue + else + # Keep unsaved issue ids to display them in flash error + unsaved_issue_ids << issue.id + end + end + set_flash_from_bulk_issue_save(@issues, unsaved_issue_ids) + + if params[:follow] + if @issues.size == 1 && moved_issues.size == 1 + redirect_to issue_path(moved_issues.first) + elsif moved_issues.map(&:project).uniq.size == 1 + redirect_to project_issues_path(moved_issues.map(&:project).first) + end + else + redirect_back_or_default _project_issues_path(@project) + end + end + + def destroy + @hours = TimeEntry.sum(:hours, :conditions => ['issue_id IN (?)', @issues]).to_f + if @hours > 0 + case params[:todo] + when 'destroy' + # nothing to do + when 'nullify' + TimeEntry.update_all('issue_id = NULL', ['issue_id IN (?)', @issues]) + when 'reassign' + reassign_to = @project.issues.find_by_id(params[:reassign_to_id]) + if reassign_to.nil? + flash.now[:error] = l(:error_issue_not_found_in_project) + return + else + TimeEntry.update_all("issue_id = #{reassign_to.id}", ['issue_id IN (?)', @issues]) + end + else + # display the destroy form if it's a user request + return unless api_request? + end + end + @issues.each do |issue| + begin + issue.reload.destroy + rescue ::ActiveRecord::RecordNotFound # raised by #reload if issue no longer exists + # nothing to do, issue was already deleted (eg. by a parent) + end + end + respond_to do |format| + format.html { redirect_back_or_default _project_issues_path(@project) } + format.api { render_api_ok } + end + end + + private + + def find_project + project_id = params[:project_id] || (params[:issue] && params[:issue][:project_id]) + @project = Project.find(project_id) + rescue ActiveRecord::RecordNotFound + render_404 + end + + def retrieve_previous_and_next_issue_ids + retrieve_query_from_session + if @query + sort_init(@query.sort_criteria.empty? ? [['id', 'desc']] : @query.sort_criteria) + sort_update(@query.sortable_columns, 'issues_index_sort') + limit = 500 + issue_ids = @query.issue_ids(:order => sort_clause, :limit => (limit + 1), :include => [:assigned_to, :tracker, :priority, :category, :fixed_version]) + if (idx = issue_ids.index(@issue.id)) && idx < limit + if issue_ids.size < 500 + @issue_position = idx + 1 + @issue_count = issue_ids.size + end + @prev_issue_id = issue_ids[idx - 1] if idx > 0 + @next_issue_id = issue_ids[idx + 1] if idx < (issue_ids.size - 1) + end + end + end + + # Used by #edit and #update to set some common instance variables + # from the params + # TODO: Refactor, not everything in here is needed by #edit + def update_issue_from_params + @edit_allowed = User.current.allowed_to?(:edit_issues, @project) + @time_entry = TimeEntry.new(:issue => @issue, :project => @issue.project) + @time_entry.attributes = params[:time_entry] + + @issue.init_journal(User.current) + + issue_attributes = params[:issue] + if issue_attributes && params[:conflict_resolution] + case params[:conflict_resolution] + when 'overwrite' + issue_attributes = issue_attributes.dup + issue_attributes.delete(:lock_version) + when 'add_notes' + issue_attributes = issue_attributes.slice(:notes) + when 'cancel' + redirect_to issue_path(@issue) + return false + end + end + @issue.safe_attributes = issue_attributes + @priorities = IssuePriority.active + @allowed_statuses = @issue.new_statuses_allowed_to(User.current) + true + end + + # TODO: Refactor, lots of extra code in here + # TODO: Changing tracker on an existing issue should not trigger this + def build_new_issue_from_params + if params[:id].blank? + @issue = Issue.new + if params[:copy_from] + begin + @copy_from = Issue.visible.find(params[:copy_from]) + @copy_attachments = params[:copy_attachments].present? || request.get? + @copy_subtasks = params[:copy_subtasks].present? || request.get? + @issue.copy_from(@copy_from, :attachments => @copy_attachments, :subtasks => @copy_subtasks) + rescue ActiveRecord::RecordNotFound + render_404 + return + end + end + @issue.project = @project + else + @issue = @project.issues.visible.find(params[:id]) + end + + @issue.project = @project + @issue.author ||= User.current + # Tracker must be set before custom field values + @issue.tracker ||= @project.trackers.find((params[:issue] && params[:issue][:tracker_id]) || params[:tracker_id] || :first) + if @issue.tracker.nil? + render_error l(:error_no_tracker_in_project) + return false + end + @issue.start_date ||= Date.today if Setting.default_issue_start_date_to_creation_date? + @issue.safe_attributes = params[:issue] + + @priorities = IssuePriority.active + @allowed_statuses = @issue.new_statuses_allowed_to(User.current, true) + @available_watchers = (@issue.project.users.sort + @issue.watcher_users).uniq + end + + def check_for_default_issue_status + if IssueStatus.default.nil? + render_error l(:error_no_default_issue_status) + return false + end + end + + def parse_params_for_bulk_issue_attributes(params) + attributes = (params[:issue] || {}).reject {|k,v| v.blank?} + attributes.keys.each {|k| attributes[k] = '' if attributes[k] == 'none'} + if custom = attributes[:custom_field_values] + custom.reject! {|k,v| v.blank?} + custom.keys.each do |k| + if custom[k].is_a?(Array) + custom[k] << '' if custom[k].delete('__none__') + else + custom[k] = '' if custom[k] == '__none__' + end + end + end + attributes + end +end diff --git a/app/controllers/journals_controller.rb b/app/controllers/journals_controller.rb new file mode 100644 index 00000000..ad6728e3 --- /dev/null +++ b/app/controllers/journals_controller.rb @@ -0,0 +1,105 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class JournalsController < ApplicationController + before_filter :find_journal, :only => [:edit, :diff] + before_filter :find_issue, :only => [:new] + before_filter :find_optional_project, :only => [:index] + before_filter :authorize, :only => [:new, :edit, :diff] + accept_rss_auth :index + menu_item :issues + + helper :issues + helper :custom_fields + helper :queries + include QueriesHelper + helper :sort + include SortHelper + + def index + retrieve_query + sort_init 'id', 'desc' + sort_update(@query.sortable_columns) + + if @query.valid? + @journals = @query.journals(:order => "#{Journal.table_name}.created_on DESC", + :limit => 25) + end + @title = (@project ? @project.name : Setting.app_title) + ": " + (@query.new_record? ? l(:label_changes_details) : @query.name) + render :layout => false, :content_type => 'application/atom+xml' + rescue ActiveRecord::RecordNotFound + render_404 + end + + def diff + @issue = @journal.issue + if params[:detail_id].present? + @detail = @journal.details.find_by_id(params[:detail_id]) + else + @detail = @journal.details.detect {|d| d.prop_key == 'description'} + end + (render_404; return false) unless @issue && @detail + @diff = Redmine::Helpers::Diff.new(@detail.value, @detail.old_value) + end + + def new + @journal = Journal.visible.find(params[:journal_id]) if params[:journal_id] + if @journal + user = @journal.user + text = @journal.notes + else + user = @issue.author + text = @issue.description + end + # Replaces pre blocks with [...] + text = text.to_s.strip.gsub(%r{
((.|\s)*?)
}m, '[...]') + @content = "#{ll(Setting.default_language, :text_user_wrote, user)}\n> " + @content << text.gsub(/(\r?\n|\r\n?)/, "\n> ") + "\n\n" + rescue ActiveRecord::RecordNotFound + render_404 + end + + def edit + (render_403; return false) unless @journal.editable_by?(User.current) + if request.post? + @journal.update_attributes(:notes => params[:notes]) if params[:notes] + @journal.destroy if @journal.details.empty? && @journal.notes.blank? + call_hook(:controller_journals_edit_post, { :journal => @journal, :params => params}) + respond_to do |format| + format.html { redirect_to issue_path(@journal.journalized) } + format.js { render :action => 'update' } + end + else + respond_to do |format| + format.html { + # TODO: implement non-JS journal update + render :nothing => true + } + format.js + end + end + end + + private + + def find_journal + @journal = Journal.visible.find(params[:id]) + @project = @journal.journalized.project + rescue ActiveRecord::RecordNotFound + render_404 + end +end diff --git a/app/controllers/list_controller.rb b/app/controllers/list_controller.rb new file mode 100644 index 00000000..f99982d4 --- /dev/null +++ b/app/controllers/list_controller.rb @@ -0,0 +1,5 @@ +class ListController < ApplicationController + def members + + end +end \ No newline at end of file diff --git a/app/controllers/mail_handler_controller.rb b/app/controllers/mail_handler_controller.rb new file mode 100644 index 00000000..3a4b219b --- /dev/null +++ b/app/controllers/mail_handler_controller.rb @@ -0,0 +1,40 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class MailHandlerController < ActionController::Base + before_filter :check_credential + + # Submits an incoming email to MailHandler + def index + options = params.dup + email = options.delete(:email) + if MailHandler.receive(email, options) + render :nothing => true, :status => :created + else + render :nothing => true, :status => :unprocessable_entity + end + end + + private + + def check_credential + User.current = nil + unless Setting.mail_handler_api_enabled? && params[:key].to_s == Setting.mail_handler_api_key + render :text => 'Access denied. Incoming emails WS is disabled or key is invalid.', :status => 403 + end + end +end diff --git a/app/controllers/members_controller.rb b/app/controllers/members_controller.rb new file mode 100644 index 00000000..c46b6287 --- /dev/null +++ b/app/controllers/members_controller.rb @@ -0,0 +1,125 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class MembersController < ApplicationController + model_object Member + before_filter :find_model_object, :except => [:index, :create, :autocomplete] + before_filter :find_project_from_association, :except => [:index, :create, :autocomplete] + before_filter :find_project_by_project_id, :only => [:index, :create, :autocomplete] + before_filter :authorize + accept_api_auth :index, :show, :create, :update, :destroy + + def index + @offset, @limit = api_offset_and_limit + @member_count = @project.member_principals.count + @member_pages = Paginator.new @member_count, @limit, params['page'] + @offset ||= @member_pages.offset + @members = @project.member_principals.all( + :order => "#{Member.table_name}.id", + :limit => @limit, + :offset => @offset + ) + + respond_to do |format| + format.html { head 406 } + format.api + end + end + + def show + respond_to do |format| + format.html { head 406 } + format.api + end + end + + def create + members = [] + if params[:membership] + if params[:membership][:user_ids] + attrs = params[:membership].dup + user_ids = attrs.delete(:user_ids) + user_ids.each do |user_id| + members << Member.new(:role_ids => params[:membership][:role_ids], :user_id => user_id) + end + else + members << Member.new(:role_ids => params[:membership][:role_ids], :user_id => params[:membership][:user_id]) + end + @project.members << members + end + + respond_to do |format| + format.html { redirect_to_settings_in_projects } + format.js { @members = members } + format.api { + @member = members.first + if @member.valid? + render :action => 'show', :status => :created, :location => membership_url(@member) + else + render_validation_errors(@member) + end + } + end + end + + def update + if params[:membership] + @member.role_ids = params[:membership][:role_ids] + end + saved = @member.save + respond_to do |format| + format.html { redirect_to_settings_in_projects } + format.js + format.api { + if saved + render_api_ok + else + render_validation_errors(@member) + end + } + end + end + + def destroy + if request.delete? && @member.deletable? + @member.destroy + end + respond_to do |format| + format.html { redirect_to_settings_in_projects } + format.js + format.api { + if @member.destroyed? + render_api_ok + else + head :unprocessable_entity + end + } + end + end + + def autocomplete + respond_to do |format| + format.js + end + end + + private + + def redirect_to_settings_in_projects + redirect_to settings_project_path(@project, :tab => 'members') + end +end diff --git a/app/controllers/messages_controller.rb b/app/controllers/messages_controller.rb new file mode 100644 index 00000000..ad910763 --- /dev/null +++ b/app/controllers/messages_controller.rb @@ -0,0 +1,142 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class MessagesController < ApplicationController + menu_item :boards + default_search_scope :messages + before_filter :find_board, :only => [:new, :preview] + before_filter :find_attachments, :only => [:preview] + before_filter :find_message, :except => [:new, :preview] + before_filter :authorize, :except => [:preview, :edit, :destroy] + + helper :boards + helper :watchers + helper :attachments + include AttachmentsHelper + + REPLIES_PER_PAGE = 25 unless const_defined?(:REPLIES_PER_PAGE) + + # Show a topic and its replies + def show + page = params[:page] + # Find the page of the requested reply + if params[:r] && page.nil? + offset = @topic.children.count(:conditions => ["#{Message.table_name}.id < ?", params[:r].to_i]) + page = 1 + offset / REPLIES_PER_PAGE + end + + @reply_count = @topic.children.count + @reply_pages = Paginator.new @reply_count, REPLIES_PER_PAGE, page + @replies = @topic.children. + includes(:author, :attachments, {:board => :project}). + reorder("#{Message.table_name}.created_on ASC"). + limit(@reply_pages.per_page). + offset(@reply_pages.offset). + all + + @reply = Message.new(:subject => "RE: #{@message.subject}") + render :action => "show", :layout => false if request.xhr? + end + + # Create a new topic + def new + @message = Message.new + @message.author = User.current + @message.board = @board + @message.safe_attributes = params[:message] + if request.post? + @message.save_attachments(params[:attachments]) + if @message.save + call_hook(:controller_messages_new_after_save, { :params => params, :message => @message}) + render_attachment_warning_if_needed(@message) + redirect_to board_message_path(@board, @message) + end + end + end + + # Reply to a topic + def reply + @reply = Message.new + @reply.author = User.current + @reply.board = @board + @reply.safe_attributes = params[:reply] + @topic.children << @reply + if !@reply.new_record? + call_hook(:controller_messages_reply_after_save, { :params => params, :message => @reply}) + attachments = Attachment.attach_files(@reply, params[:attachments]) + render_attachment_warning_if_needed(@reply) + end + redirect_to board_message_path(@board, @topic, :r => @reply) + end + + # Edit a message + def edit + (render_403; return false) unless @message.editable_by?(User.current) + @message.safe_attributes = params[:message] + if request.post? && @message.save + attachments = Attachment.attach_files(@message, params[:attachments]) + render_attachment_warning_if_needed(@message) + flash[:notice] = l(:notice_successful_update) + @message.reload + redirect_to board_message_path(@message.board, @message.root, :r => (@message.parent_id && @message.id)) + end + end + + # Delete a messages + def destroy + (render_403; return false) unless @message.destroyable_by?(User.current) + r = @message.to_param + @message.destroy + if @message.parent + redirect_to board_message_path(@board, @message.parent, :r => r) + else + redirect_to project_board_path(@project, @board) + end + end + + def quote + @subject = @message.subject + @subject = "RE: #{@subject}" unless @subject.starts_with?('RE:') + + @content = "#{ll(Setting.default_language, :text_user_wrote, @message.author)}\n> " + @content << @message.content.to_s.strip.gsub(%r{
((.|\s)*?)
}m, '[...]').gsub(/(\r?\n|\r\n?)/, "\n> ") + "\n\n" + end + + def preview + message = @board.messages.find_by_id(params[:id]) + @text = (params[:message] || params[:reply])[:content] + @previewed = message + render :partial => 'common/preview' + end + +private + def find_message + return unless find_board + @message = @board.messages.find(params[:id], :include => :parent) + @topic = @message.root + rescue ActiveRecord::RecordNotFound + render_404 + end + + def find_board + @board = Board.find(params[:board_id], :include => :project) + @project = @board.project + rescue ActiveRecord::RecordNotFound + render_404 + nil + end +end diff --git a/app/controllers/my_controller.rb b/app/controllers/my_controller.rb new file mode 100644 index 00000000..84f5b20c --- /dev/null +++ b/app/controllers/my_controller.rb @@ -0,0 +1,198 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class MyController < ApplicationController + before_filter :require_login + + helper :issues + helper :users + helper :custom_fields + + BLOCKS = { 'issuesassignedtome' => :label_assigned_to_me_issues, + 'issuesreportedbyme' => :label_reported_issues, + 'issueswatched' => :label_watched_issues, + 'news' => :label_news_latest, + 'calendar' => :label_calendar, + 'documents' => :label_document_plural, + 'timelog' => :label_spent_time + }.merge(Redmine::Views::MyPage::Block.additional_blocks).freeze + + DEFAULT_LAYOUT = { 'left' => ['issuesassignedtome'], + 'right' => ['issuesreportedbyme'] + }.freeze + + def index + page + render :action => 'page' + end + + # Show user's page + def page + @user = User.current + @blocks = @user.pref[:my_page_layout] || DEFAULT_LAYOUT + end + + # Edit user's account + def account + @user = User.current + @pref = @user.pref + if request.post? + @user.safe_attributes = params[:user] + @user.pref.attributes = params[:pref] + @user.pref[:no_self_notified] = (params[:no_self_notified] == '1') + if @user.save + @user.pref.save + @user.notified_project_ids = (@user.mail_notification == 'selected' ? params[:notified_project_ids] : []) + set_language_if_valid @user.language + flash[:notice] = l(:notice_account_updated) + redirect_to my_account_path + return + end + end + end + + # Destroys user's account + def destroy + @user = User.current + unless @user.own_account_deletable? + redirect_to my_account_path + return + end + + if request.post? && params[:confirm] + @user.destroy + if @user.destroyed? + logout_user + flash[:notice] = l(:notice_account_deleted) + end + redirect_to home_path + end + end + + # Manage user's password + def password + @user = User.current + unless @user.change_password_allowed? + flash[:error] = l(:notice_can_t_change_password) + redirect_to my_account_path + return + end + if request.post? + if @user.check_password?(params[:password]) + @user.password, @user.password_confirmation = params[:new_password], params[:new_password_confirmation] + if @user.save + flash[:notice] = l(:notice_account_password_updated) + redirect_to my_account_path + end + else + flash[:error] = l(:notice_account_wrong_password) + end + end + end + + # Create a new feeds key + def reset_rss_key + if request.post? + if User.current.rss_token + User.current.rss_token.destroy + User.current.reload + end + User.current.rss_key + flash[:notice] = l(:notice_feeds_access_key_reseted) + end + redirect_to my_account_path + end + + # Create a new API key + def reset_api_key + if request.post? + if User.current.api_token + User.current.api_token.destroy + User.current.reload + end + User.current.api_key + flash[:notice] = l(:notice_api_access_key_reseted) + end + redirect_to my_account_path + end + + # User's page layout configuration + def page_layout + @user = User.current + @blocks = @user.pref[:my_page_layout] || DEFAULT_LAYOUT.dup + @block_options = [] + BLOCKS.each do |k, v| + unless %w(top left right).detect {|f| (@blocks[f] ||= []).include?(k)} + @block_options << [l("my.blocks.#{v}", :default => [v, v.to_s.humanize]), k.dasherize] + end + end + end + + # Add a block to user's page + # The block is added on top of the page + # params[:block] : id of the block to add + def add_block + block = params[:block].to_s.underscore + if block.present? && BLOCKS.key?(block) + @user = User.current + layout = @user.pref[:my_page_layout] || {} + # remove if already present in a group + %w(top left right).each {|f| (layout[f] ||= []).delete block } + # add it on top + layout['top'].unshift block + @user.pref[:my_page_layout] = layout + @user.pref.save + end + redirect_to my_page_layout_path + end + + # Remove a block to user's page + # params[:block] : id of the block to remove + def remove_block + block = params[:block].to_s.underscore + @user = User.current + # remove block in all groups + layout = @user.pref[:my_page_layout] || {} + %w(top left right).each {|f| (layout[f] ||= []).delete block } + @user.pref[:my_page_layout] = layout + @user.pref.save + redirect_to my_page_layout_path + end + + # Change blocks order on user's page + # params[:group] : group to order (top, left or right) + # params[:list-(top|left|right)] : array of block ids of the group + def order_blocks + group = params[:group] + @user = User.current + if group.is_a?(String) + group_items = (params["blocks"] || []).collect(&:underscore) + group_items.each {|s| s.sub!(/^block_/, '')} + if group_items and group_items.is_a? Array + layout = @user.pref[:my_page_layout] || {} + # remove group blocks if they are presents in other groups + %w(top left right).each {|f| + layout[f] = (layout[f] || []) - group_items + } + layout[group] = group_items + @user.pref[:my_page_layout] = layout + @user.pref.save + end + end + render :nothing => true + end +end diff --git a/app/controllers/news_controller.rb b/app/controllers/news_controller.rb new file mode 100644 index 00000000..1002438b --- /dev/null +++ b/app/controllers/news_controller.rb @@ -0,0 +1,112 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class NewsController < ApplicationController + layout 'base_projects' + default_search_scope :news + model_object News + before_filter :find_model_object, :except => [:new, :create, :index] + before_filter :find_project_from_association, :except => [:new, :create, :index] + before_filter :find_project_by_project_id, :only => [:new, :create] + before_filter :authorize, :except => [:index] + before_filter :find_optional_project, :only => :index + accept_rss_auth :index + accept_api_auth :index + + helper :watchers + helper :attachments + + def index + case params[:format] + when 'xml', 'json' + @offset, @limit = api_offset_and_limit + else + @limit = 10 + end + + scope = @project ? @project.news.visible : News.visible + + @news_count = scope.count + @news_pages = Paginator.new @news_count, @limit, params['page'] + @offset ||= @news_pages.offset + @newss = scope.all(:include => [:author, :project], + :order => "#{News.table_name}.created_on DESC", + :offset => @offset, + :limit => @limit) + + respond_to do |format| + format.html { + @news = News.new # for adding news inline + render :layout => false if request.xhr? + } + format.api + format.atom { render_feed(@newss, :title => (@project ? @project.name : Setting.app_title) + ": #{l(:label_news_plural)}") } + end + end + + def show + @comments = @news.comments + @comments.reverse! if User.current.wants_comments_in_reverse_order? + end + + def new + @news = News.new(:project => @project, :author => User.current) + end + + def create + @news = News.new(:project => @project, :author => User.current) + @news.safe_attributes = params[:news] + @news.save_attachments(params[:attachments]) + if @news.save + render_attachment_warning_if_needed(@news) + flash[:notice] = l(:notice_successful_create) + redirect_to project_news_index_path(@project) + else + render :action => 'new' + end + end + + def edit + end + + def update + @news.safe_attributes = params[:news] + @news.save_attachments(params[:attachments]) + if @news.save + render_attachment_warning_if_needed(@news) + flash[:notice] = l(:notice_successful_update) + redirect_to news_path(@news) + else + render :action => 'edit' + end + end + + def destroy + @news.destroy + redirect_to project_news_index_path(@project) + end + + private + + def find_optional_project + return true unless params[:project_id] + @project = Project.find(params[:project_id]) + authorize + rescue ActiveRecord::RecordNotFound + render_404 + end +end diff --git a/app/controllers/previews_controller.rb b/app/controllers/previews_controller.rb new file mode 100644 index 00000000..d19a7fcd --- /dev/null +++ b/app/controllers/previews_controller.rb @@ -0,0 +1,53 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class PreviewsController < ApplicationController + before_filter :find_project, :find_attachments + + def issue + @issue = @project.issues.find_by_id(params[:id]) unless params[:id].blank? + if @issue + @description = params[:issue] && params[:issue][:description] + if @description && @description.gsub(/(\r?\n|\n\r?)/, "\n") == @issue.description.to_s.gsub(/(\r?\n|\n\r?)/, "\n") + @description = nil + end + # params[:notes] is useful for preview of notes in issue history + @notes = params[:notes] || (params[:issue] ? params[:issue][:notes] : nil) + else + @description = (params[:issue] ? params[:issue][:description] : nil) + end + render :layout => false + end + + def news + if params[:id].present? && news = News.visible.find_by_id(params[:id]) + @previewed = news + end + @text = (params[:news] ? params[:news][:description] : nil) + render :partial => 'common/preview' + end + + private + + def find_project + project_id = (params[:issue] && params[:issue][:project_id]) || params[:project_id] + @project = Project.find(project_id) + rescue ActiveRecord::RecordNotFound + render_404 + end + +end diff --git a/app/controllers/project_enumerations_controller.rb b/app/controllers/project_enumerations_controller.rb new file mode 100644 index 00000000..c473102a --- /dev/null +++ b/app/controllers/project_enumerations_controller.rb @@ -0,0 +1,42 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class ProjectEnumerationsController < ApplicationController + before_filter :find_project_by_project_id + before_filter :authorize + + def update + if request.put? && params[:enumerations] + Project.transaction do + params[:enumerations].each do |id, activity| + @project.update_or_create_time_entry_activity(id, activity) + end + end + flash[:notice] = l(:notice_successful_update) + end + + redirect_to settings_project_path(@project, :tab => 'activities') + end + + def destroy + @project.time_entry_activities.each do |time_entry_activity| + time_entry_activity.destroy(time_entry_activity.parent) + end + flash[:notice] = l(:notice_successful_update) + redirect_to settings_project_path(@project, :tab => 'activities') + end +end diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb new file mode 100644 index 00000000..ccd90474 --- /dev/null +++ b/app/controllers/projects_controller.rb @@ -0,0 +1,365 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class ProjectsController < ApplicationController + layout 'base_projects' + menu_item :overview + menu_item :roadmap, :only => :roadmap +# menu_item :settings, :only => :settings + + before_filter :find_project, :except => [ :index, :list, :new, :create, :copy ] + before_filter :authorize, :except => [ :index, :list, :new, :create, :copy, :archive, :unarchive, :destroy, :member, :focus, :investor, :issue, :mission, :on, :file] + before_filter :authorize_global, :only => [:new, :create] + before_filter :require_admin, :only => [ :copy, :archive, :unarchive, :destroy ] + #by young + before_filter :member, :focus, :mission, :issue, :on, :file, :investor + # + accept_rss_auth :index + accept_api_auth :index, :show, :create, :update, :destroy + + after_filter :only => [:create, :edit, :update, :archive, :unarchive, :destroy] do |controller| + if controller.request.post? + controller.send :expire_action, :controller => 'welcome', :action => 'robots' + end + end + + helper :sort + include SortHelper + helper :custom_fields + include CustomFieldsHelper + helper :issues + helper :queries + include QueriesHelper + helper :repositories + include RepositoriesHelper + include ProjectsHelper + helper :members + helper :activities + helper :documents + helper :watchers + + + # Lists visible projects +# def index +# respond_to do |format| +# format.html { +# scope = Project +# unless params[:closed] +# scope = scope.active +# end +# @projects = scope.visible.order('lft').all +# } +# format.api { +# @offset, @limit = api_offset_and_limit +# @project_count = Project.visible.count +# @projects = Project.visible.offset(@offset).limit(@limit).order('lft').all +# } +# format.atom { +# projects = Project.visible.order('created_on DESC').limit(Setting.feeds_limit.to_i).all +# render_feed(projects, :title => "#{Setting.app_title}: #{l(:label_project_latest)}") +# } +# end +# end + + def index + @offset, @limit = api_offset_and_limit({:limit => 10}) + @project_count = Project.visible.count + @project_pages = Paginator.new @project_count, @limit, params['page'] + @offset ||= @project_pages.offset + @projects = Project.visible.offset(@offset).limit(@limit).order('lft').all + respond_to do |format| + format.html { + render :layout => 'base' + scope = Project + unless params[:closed] + scope = scope.active + end + @projects = scope.visible.offset(@offset).limit(@limit).order('lft').all + } + format.api { +# @offset, @limit = api_offset_and_limit +# @project_count = Project.visible.count +# @projects = Project.visible.offset(@offset).limit(@limit).order('lft').all + } + format.atom { + projects = Project.visible.order('created_on DESC').limit(Setting.feeds_limit.to_i).all + render_feed(projects, :title => "#{Setting.app_title}: #{l(:label_project_latest)}") + } + end + end + + def new + @issue_custom_fields = IssueCustomField.sorted.all + @trackers = Tracker.sorted.all + @project = Project.new + @project.safe_attributes = params[:project] + end + + def create + @issue_custom_fields = IssueCustomField.sorted.all + @trackers = Tracker.sorted.all + @project = Project.new + @project.safe_attributes = params[:project] + + if validate_parent_id && @project.save + @project.set_allowed_parent!(params[:project]['parent_id']) if params[:project].has_key?('parent_id') + # Add current user as a project member if he is not admin + unless User.current.admin? + r = Role.givable.find_by_id(Setting.new_project_user_role_id.to_i) || Role.givable.first + m = Member.new(:user => User.current, :roles => [r]) + @project.members << m + end + respond_to do |format| + format.html { + flash[:notice] = l(:notice_successful_create) + if params[:continue] + attrs = {:parent_id => @project.parent_id}.reject {|k,v| v.nil?} + redirect_to new_project_path(attrs) + else + redirect_to settings_project_path(@project) + end + } + format.api { render :action => 'show', :status => :created, :location => url_for(:controller => 'projects', :action => 'show', :id => @project.id) } + end + else + respond_to do |format| + format.html { render :action => 'new' } + format.api { render_validation_errors(@project) } + end + end + end + + def copy + @issue_custom_fields = IssueCustomField.sorted.all + @trackers = Tracker.sorted.all + @source_project = Project.find(params[:id]) + if request.get? + @project = Project.copy_from(@source_project) + @project.identifier = Project.next_identifier if Setting.sequential_project_identifiers? + else + Mailer.with_deliveries(params[:notifications] == '1') do + @project = Project.new + @project.safe_attributes = params[:project] + if validate_parent_id && @project.copy(@source_project, :only => params[:only]) + @project.set_allowed_parent!(params[:project]['parent_id']) if params[:project].has_key?('parent_id') + flash[:notice] = l(:notice_successful_create) + redirect_to settings_project_path(@project) + elsif !@project.new_record? + # Project was created + # But some objects were not copied due to validation failures + # (eg. issues from disabled trackers) + # TODO: inform about that + redirect_to settings_project_path(@project) + end + end + end + rescue ActiveRecord::RecordNotFound + # source_project not found + render_404 + end + + # Show @project + def show + # try to redirect to the requested menu item + if params[:jump] && redirect_to_project_menu_item(@project, params[:jump]) + return + end + + @users_by_role = @project.users_by_role + @subprojects = @project.children.visible.all + @news = @project.news.limit(5).includes(:author, :project).reorder("#{News.table_name}.created_on DESC").all + @trackers = @project.rolled_up_trackers + + cond = @project.project_condition(Setting.display_subprojects_issues?) + + @open_issues_by_tracker = Issue.visible.open.where(cond).count(:group => :tracker) + @total_issues_by_tracker = Issue.visible.where(cond).count(:group => :tracker) + + if User.current.allowed_to?(:view_time_entries, @project) + @total_hours = TimeEntry.visible.sum(:hours, :include => :project, :conditions => cond).to_f + end + + @key = User.current.rss_key + #新增内容 + @days = Setting.activity_days_default.to_i + + if params[:from] + begin; @date_to = params[:from].to_date + 1; rescue; end + end + + has = { + "show_issues" => true + } + @date_to ||= Date.today + 1 + @date_from = @date_to - @days + @with_subprojects = params[:with_subprojects].nil? ? Setting.display_subprojects_issues? : (params[:with_subprojects] == '1') + @author = (params[:user_id].blank? ? nil : User.active.find(params[:user_id])) +# 决定显示所用用户或单个用户活动 + @activity = Redmine::Activity::Fetcher.new(User.current, :project => @project, + :with_subprojects => @with_subprojects, + :author => @author) + @activity.scope_select {|t| !has["show_#{t}"].nil?} + # @activity.scope = (@author.nil? ? :default : :all) if @activity.scope.empty? + + events = @activity.events(@date_from, @date_to, {:limit=>15}) + @events_by_day = events.group_by {|event| User.current.time_to_date(event.event_datetime)} + # documents + @sort_by = %w(category date title author).include?(params[:sort_by]) ? params[:sort_by] : 'category' + documents = @project.documents.includes(:attachments, :category).all + case @sort_by + when 'date' + @grouped = documents.group_by {|d| d.updated_on.to_date } + when 'title' + @grouped = documents.group_by {|d| d.title.first.upcase} + when 'author' + @grouped = documents.select{|d| d.attachments.any?}.group_by {|d| d.attachments.last.author} + else + @grouped = documents.group_by(&:category) + end + @document = @project.documents.build +# + respond_to do |format| + format.html + format.api + end + end + + + def settings + @issue_custom_fields = IssueCustomField.sorted.all + @issue_category ||= IssueCategory.new + @member ||= @project.members.new + @trackers = Tracker.sorted.all + @wiki ||= @project.wiki + end + + def edit + end + + #by young + def member + session[:project_member_num] = 12 + end + + def focus + session[:project_focus_num] = 2508 + end + + def investor + session[:project_investor_num] = 8 + end + + def issue + session[:project_issue_num] = 1 + end + + def mission + session[:project_mission_num] = 225 + end + + def on + session[:project_on_num] = 1208 + end + + def file + session[:project_file_num] = 125 + end + #end + + def update + @project.safe_attributes = params[:project] + if validate_parent_id && @project.save + @project.set_allowed_parent!(params[:project]['parent_id']) if params[:project].has_key?('parent_id') + respond_to do |format| + format.html { + flash[:notice] = l(:notice_successful_update) + redirect_to settings_project_path(@project) + } + format.api { render_api_ok } + end + else + respond_to do |format| + format.html { + settings + render :action => 'settings' + } + format.api { render_validation_errors(@project) } + end + end + end + + def modules + @project.enabled_module_names = params[:enabled_module_names] + flash[:notice] = l(:notice_successful_update) + redirect_to settings_project_path(@project, :tab => 'modules') + end + + def archive + if request.post? + unless @project.archive + flash[:error] = l(:error_can_not_archive_project) + end + end + redirect_to admin_projects_path(:status => params[:status]) + end + + def unarchive + @project.unarchive if request.post? && !@project.active? + redirect_to admin_projects_path(:status => params[:status]) + end + + def close + @project.close + redirect_to project_path(@project) + end + + def reopen + @project.reopen + redirect_to project_path(@project) + end + + # Delete @project + def destroy + @project_to_destroy = @project + if api_request? || params[:confirm] + @project_to_destroy.destroy + respond_to do |format| + format.html { redirect_to admin_projects_path } + format.api { render_api_ok } + end + end + # hide project in layout + @project = nil + end + + private + + # Validates parent_id param according to user's permissions + # TODO: move it to Project model in a validation that depends on User.current + def validate_parent_id + return true if User.current.admin? + parent_id = params[:project] && params[:project][:parent_id] + if parent_id || @project.new_record? + parent = parent_id.blank? ? nil : Project.find_by_id(parent_id.to_i) + unless @project.allowed_parents.include?(parent) + @project.errors.add :parent_id, :invalid + return false + end + end + true + end +end diff --git a/app/controllers/queries_controller.rb b/app/controllers/queries_controller.rb new file mode 100644 index 00000000..63925512 --- /dev/null +++ b/app/controllers/queries_controller.rb @@ -0,0 +1,106 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class QueriesController < ApplicationController + menu_item :issues + before_filter :find_query, :except => [:new, :create, :index] + before_filter :find_optional_project, :only => [:new, :create] + + accept_api_auth :index + + include QueriesHelper + + def index + case params[:format] + when 'xml', 'json' + @offset, @limit = api_offset_and_limit + else + @limit = per_page_option + end + + @query_count = IssueQuery.visible.count + @query_pages = Paginator.new @query_count, @limit, params['page'] + @queries = IssueQuery.visible.all(:limit => @limit, :offset => @offset, :order => "#{Query.table_name}.name") + + respond_to do |format| + format.api + end + end + + def new + @query = IssueQuery.new + @query.user = User.current + @query.project = @project + @query.is_public = false unless User.current.allowed_to?(:manage_public_queries, @project) || User.current.admin? + @query.build_from_params(params) + end + + def create + @query = IssueQuery.new(params[:query]) + @query.user = User.current + @query.project = params[:query_is_for_all] ? nil : @project + @query.is_public = false unless User.current.allowed_to?(:manage_public_queries, @project) || User.current.admin? + @query.build_from_params(params) + @query.column_names = nil if params[:default_columns] + + if @query.save + flash[:notice] = l(:notice_successful_create) + redirect_to _project_issues_path(@project, :query_id => @query) + else + render :action => 'new', :layout => !request.xhr? + end + end + + def edit + end + + def update + @query.attributes = params[:query] + @query.project = nil if params[:query_is_for_all] + @query.is_public = false unless User.current.allowed_to?(:manage_public_queries, @project) || User.current.admin? + @query.build_from_params(params) + @query.column_names = nil if params[:default_columns] + + if @query.save + flash[:notice] = l(:notice_successful_update) + redirect_to _project_issues_path(@project, :query_id => @query) + else + render :action => 'edit' + end + end + + def destroy + @query.destroy + redirect_to _project_issues_path(@project, :set_filter => 1) + end + +private + def find_query + @query = IssueQuery.find(params[:id]) + @project = @query.project + render_403 unless @query.editable_by?(User.current) + rescue ActiveRecord::RecordNotFound + render_404 + end + + def find_optional_project + @project = Project.find(params[:project_id]) if params[:project_id] + render_403 unless User.current.allowed_to?(:save_queries, @project, :global => true) + rescue ActiveRecord::RecordNotFound + render_404 + end +end diff --git a/app/controllers/reports_controller.rb b/app/controllers/reports_controller.rb new file mode 100644 index 00000000..dbdf4454 --- /dev/null +++ b/app/controllers/reports_controller.rb @@ -0,0 +1,95 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class ReportsController < ApplicationController + menu_item :issues + before_filter :find_project, :authorize, :find_issue_statuses + + def issue_report + @trackers = @project.trackers + @versions = @project.shared_versions.sort + @priorities = IssuePriority.all.reverse + @categories = @project.issue_categories + @assignees = (Setting.issue_group_assignment? ? @project.principals : @project.users).sort + @authors = @project.users.sort + @subprojects = @project.descendants.visible + + @issues_by_tracker = Issue.by_tracker(@project) + @issues_by_version = Issue.by_version(@project) + @issues_by_priority = Issue.by_priority(@project) + @issues_by_category = Issue.by_category(@project) + @issues_by_assigned_to = Issue.by_assigned_to(@project) + @issues_by_author = Issue.by_author(@project) + @issues_by_subproject = Issue.by_subproject(@project) || [] + + render :template => "reports/issue_report" + end + + def issue_report_details + case params[:detail] + when "tracker" + @field = "tracker_id" + @rows = @project.trackers + @data = Issue.by_tracker(@project) + @report_title = l(:field_tracker) + when "version" + @field = "fixed_version_id" + @rows = @project.shared_versions.sort + @data = Issue.by_version(@project) + @report_title = l(:field_version) + when "priority" + @field = "priority_id" + @rows = IssuePriority.all.reverse + @data = Issue.by_priority(@project) + @report_title = l(:field_priority) + when "category" + @field = "category_id" + @rows = @project.issue_categories + @data = Issue.by_category(@project) + @report_title = l(:field_category) + when "assigned_to" + @field = "assigned_to_id" + @rows = (Setting.issue_group_assignment? ? @project.principals : @project.users).sort + @data = Issue.by_assigned_to(@project) + @report_title = l(:field_assigned_to) + when "author" + @field = "author_id" + @rows = @project.users.sort + @data = Issue.by_author(@project) + @report_title = l(:field_author) + when "subproject" + @field = "project_id" + @rows = @project.descendants.visible + @data = Issue.by_subproject(@project) || [] + @report_title = l(:field_subproject) + end + + respond_to do |format| + if @field + format.html {} + else + format.html { redirect_to :action => 'issue_report', :id => @project } + end + end + end + + private + + def find_issue_statuses + @statuses = IssueStatus.sorted.all + end +end diff --git a/app/controllers/repositories_controller.rb b/app/controllers/repositories_controller.rb new file mode 100644 index 00000000..03b5967f --- /dev/null +++ b/app/controllers/repositories_controller.rb @@ -0,0 +1,435 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +require 'SVG/Graph/Bar' +require 'SVG/Graph/BarHorizontal' +require 'digest/sha1' +require 'redmine/scm/adapters/abstract_adapter' + +class ChangesetNotFound < Exception; end +class InvalidRevisionParam < Exception; end + +class RepositoriesController < ApplicationController + layout 'base_projects' + menu_item :repository + menu_item :settings, :only => [:new, :create, :edit, :update, :destroy, :committers] + default_search_scope :changesets + + before_filter :find_project_by_project_id, :only => [:new, :create] + before_filter :find_repository, :only => [:edit, :update, :destroy, :committers] + before_filter :find_project_repository, :except => [:new, :create, :edit, :update, :destroy, :committers] + before_filter :find_changeset, :only => [:revision, :add_related_issue, :remove_related_issue] + before_filter :authorize + accept_rss_auth :revisions + + rescue_from Redmine::Scm::Adapters::CommandFailed, :with => :show_error_command_failed + + def new + scm = params[:repository_scm] || (Redmine::Scm::Base.all & Setting.enabled_scm).first + @repository = Repository.factory(scm) + @repository.is_default = @project.repository.nil? + @repository.project = @project + end + + def create + attrs = pickup_extra_info + @repository = Repository.factory(params[:repository_scm]) + @repository.safe_attributes = params[:repository] + if attrs[:attrs_extra].keys.any? + @repository.merge_extra_info(attrs[:attrs_extra]) + end + @repository.project = @project + if request.post? && @repository.save + redirect_to settings_project_path(@project, :tab => 'repositories') + else + render :action => 'new' + end + end + + def edit + end + + def update + attrs = pickup_extra_info + @repository.safe_attributes = attrs[:attrs] + if attrs[:attrs_extra].keys.any? + @repository.merge_extra_info(attrs[:attrs_extra]) + end + @repository.project = @project + if request.put? && @repository.save + redirect_to settings_project_path(@project, :tab => 'repositories') + else + render :action => 'edit' + end + end + + def pickup_extra_info + p = {} + p_extra = {} + params[:repository].each do |k, v| + if k =~ /^extra_/ + p_extra[k] = v + else + p[k] = v + end + end + {:attrs => p, :attrs_extra => p_extra} + end + private :pickup_extra_info + + def committers + @committers = @repository.committers + @users = @project.users + additional_user_ids = @committers.collect(&:last).collect(&:to_i) - @users.collect(&:id) + @users += User.find_all_by_id(additional_user_ids) unless additional_user_ids.empty? + @users.compact! + @users.sort! + if request.post? && params[:committers].is_a?(Hash) + # Build a hash with repository usernames as keys and corresponding user ids as values + @repository.committer_ids = params[:committers].values.inject({}) {|h, c| h[c.first] = c.last; h} + flash[:notice] = l(:notice_successful_update) + redirect_to settings_project_path(@project, :tab => 'repositories') + end + end + + def destroy + @repository.destroy if request.delete? + redirect_to settings_project_path(@project, :tab => 'repositories') + end + + def show + @repository.fetch_changesets if Setting.autofetch_changesets? && @path.empty? + + @entries = @repository.entries(@path, @rev) + @changeset = @repository.find_changeset_by_name(@rev) + if request.xhr? + @entries ? render(:partial => 'dir_list_content') : render(:nothing => true) + else + (show_error_not_found; return) unless @entries + @changesets = @repository.latest_changesets(@path, @rev) + @properties = @repository.properties(@path, @rev) + @repositories = @project.repositories + render :action => 'show' + end + end + + alias_method :browse, :show + + def changes + @entry = @repository.entry(@path, @rev) + (show_error_not_found; return) unless @entry + @changesets = @repository.latest_changesets(@path, @rev, Setting.repository_log_display_limit.to_i) + @properties = @repository.properties(@path, @rev) + @changeset = @repository.find_changeset_by_name(@rev) + end + + def revisions + @changeset_count = @repository.changesets.count + @changeset_pages = Paginator.new @changeset_count, + per_page_option, + params['page'] + @changesets = @repository.changesets. + limit(@changeset_pages.per_page). + offset(@changeset_pages.offset). + includes(:user, :repository, :parents). + all + + respond_to do |format| + format.html { render :layout => false if request.xhr? } + format.atom { render_feed(@changesets, :title => "#{@project.name}: #{l(:label_revision_plural)}") } + end + end + + def raw + entry_and_raw(true) + end + + def entry + entry_and_raw(false) + end + + def entry_and_raw(is_raw) + @entry = @repository.entry(@path, @rev) + (show_error_not_found; return) unless @entry + + # If the entry is a dir, show the browser + (show; return) if @entry.is_dir? + + @content = @repository.cat(@path, @rev) + (show_error_not_found; return) unless @content + if is_raw || + (@content.size && @content.size > Setting.file_max_size_displayed.to_i.kilobyte) || + ! is_entry_text_data?(@content, @path) + # Force the download + send_opt = { :filename => filename_for_content_disposition(@path.split('/').last) } + send_type = Redmine::MimeType.of(@path) + send_opt[:type] = send_type.to_s if send_type + send_opt[:disposition] = (Redmine::MimeType.is_type?('image', @path) && !is_raw ? 'inline' : 'attachment') + send_data @content, send_opt + else + # Prevent empty lines when displaying a file with Windows style eol + # TODO: UTF-16 + # Is this needs? AttachmentsController reads file simply. + @content.gsub!("\r\n", "\n") + @changeset = @repository.find_changeset_by_name(@rev) + end + end + private :entry_and_raw + + def is_entry_text_data?(ent, path) + # UTF-16 contains "\x00". + # It is very strict that file contains less than 30% of ascii symbols + # in non Western Europe. + return true if Redmine::MimeType.is_type?('text', path) + # Ruby 1.8.6 has a bug of integer divisions. + # http://apidock.com/ruby/v1_8_6_287/String/is_binary_data%3F + return false if ent.is_binary_data? + true + end + private :is_entry_text_data? + + def annotate + @entry = @repository.entry(@path, @rev) + (show_error_not_found; return) unless @entry + + @annotate = @repository.scm.annotate(@path, @rev) + if @annotate.nil? || @annotate.empty? + (render_error l(:error_scm_annotate); return) + end + ann_buf_size = 0 + @annotate.lines.each do |buf| + ann_buf_size += buf.size + end + if ann_buf_size > Setting.file_max_size_displayed.to_i.kilobyte + (render_error l(:error_scm_annotate_big_text_file); return) + end + @changeset = @repository.find_changeset_by_name(@rev) + end + + def revision + respond_to do |format| + format.html + format.js {render :layout => false} + end + end + + # Adds a related issue to a changeset + # POST /projects/:project_id/repository/(:repository_id/)revisions/:rev/issues + def add_related_issue + @issue = @changeset.find_referenced_issue_by_id(params[:issue_id]) + if @issue && (!@issue.visible? || @changeset.issues.include?(@issue)) + @issue = nil + end + + if @issue + @changeset.issues << @issue + end + end + + # Removes a related issue from a changeset + # DELETE /projects/:project_id/repository/(:repository_id/)revisions/:rev/issues/:issue_id + def remove_related_issue + @issue = Issue.visible.find_by_id(params[:issue_id]) + if @issue + @changeset.issues.delete(@issue) + end + end + + def diff + if params[:format] == 'diff' + @diff = @repository.diff(@path, @rev, @rev_to) + (show_error_not_found; return) unless @diff + filename = "changeset_r#{@rev}" + filename << "_r#{@rev_to}" if @rev_to + send_data @diff.join, :filename => "#{filename}.diff", + :type => 'text/x-patch', + :disposition => 'attachment' + else + @diff_type = params[:type] || User.current.pref[:diff_type] || 'inline' + @diff_type = 'inline' unless %w(inline sbs).include?(@diff_type) + + # Save diff type as user preference + if User.current.logged? && @diff_type != User.current.pref[:diff_type] + User.current.pref[:diff_type] = @diff_type + User.current.preference.save + end + @cache_key = "repositories/diff/#{@repository.id}/" + + Digest::MD5.hexdigest("#{@path}-#{@rev}-#{@rev_to}-#{@diff_type}-#{current_language}") + unless read_fragment(@cache_key) + @diff = @repository.diff(@path, @rev, @rev_to) + show_error_not_found unless @diff + end + + @changeset = @repository.find_changeset_by_name(@rev) + @changeset_to = @rev_to ? @repository.find_changeset_by_name(@rev_to) : nil + @diff_format_revisions = @repository.diff_format_revisions(@changeset, @changeset_to) + end + end + + def stats + end + + def graph + data = nil + case params[:graph] + when "commits_per_month" + data = graph_commits_per_month(@repository) + when "commits_per_author" + data = graph_commits_per_author(@repository) + end + if data + headers["Content-Type"] = "image/svg+xml" + send_data(data, :type => "image/svg+xml", :disposition => "inline") + else + render_404 + end + end + + private + + def find_repository + @repository = Repository.find(params[:id]) + @project = @repository.project + rescue ActiveRecord::RecordNotFound + render_404 + end + + REV_PARAM_RE = %r{\A[a-f0-9]*\Z}i + + def find_project_repository + @project = Project.find(params[:id]) + if params[:repository_id].present? + @repository = @project.repositories.find_by_identifier_param(params[:repository_id]) + else + @repository = @project.repository + end + (render_404; return false) unless @repository + @path = params[:path].is_a?(Array) ? params[:path].join('/') : params[:path].to_s + @rev = params[:rev].blank? ? @repository.default_branch : params[:rev].to_s.strip + @rev_to = params[:rev_to] + + unless @rev.to_s.match(REV_PARAM_RE) && @rev_to.to_s.match(REV_PARAM_RE) + if @repository.branches.blank? + raise InvalidRevisionParam + end + end + rescue ActiveRecord::RecordNotFound + render_404 + rescue InvalidRevisionParam + show_error_not_found + end + + def find_changeset + if @rev.present? + @changeset = @repository.find_changeset_by_name(@rev) + end + show_error_not_found unless @changeset + end + + def show_error_not_found + render_error :message => l(:error_scm_not_found), :status => 404 + end + + # Handler for Redmine::Scm::Adapters::CommandFailed exception + def show_error_command_failed(exception) + render_error l(:error_scm_command_failed, exception.message) + end + + def graph_commits_per_month(repository) + @date_to = Date.today + @date_from = @date_to << 11 + @date_from = Date.civil(@date_from.year, @date_from.month, 1) + commits_by_day = Changeset.count( + :all, :group => :commit_date, + :conditions => ["repository_id = ? AND commit_date BETWEEN ? AND ?", repository.id, @date_from, @date_to]) + commits_by_month = [0] * 12 + commits_by_day.each {|c| commits_by_month[(@date_to.month - c.first.to_date.month) % 12] += c.last } + + changes_by_day = Change.count( + :all, :group => :commit_date, :include => :changeset, + :conditions => ["#{Changeset.table_name}.repository_id = ? AND #{Changeset.table_name}.commit_date BETWEEN ? AND ?", repository.id, @date_from, @date_to]) + changes_by_month = [0] * 12 + changes_by_day.each {|c| changes_by_month[(@date_to.month - c.first.to_date.month) % 12] += c.last } + + fields = [] + 12.times {|m| fields << month_name(((Date.today.month - 1 - m) % 12) + 1)} + + graph = SVG::Graph::Bar.new( + :height => 300, + :width => 650, + :fields => fields.reverse, + :stack => :side, + :scale_integers => true, + :step_x_labels => 2, + :show_data_values => false, + :graph_title => l(:label_commits_per_month), + :show_graph_title => true + ) + + graph.add_data( + :data => commits_by_month[0..11].reverse, + :title => l(:label_revision_plural) + ) + + graph.add_data( + :data => changes_by_month[0..11].reverse, + :title => l(:label_change_plural) + ) + + graph.burn + end + + def graph_commits_per_author(repository) + commits_by_author = Changeset.count(:all, :group => :committer, :conditions => ["repository_id = ?", repository.id]) + commits_by_author.to_a.sort! {|x, y| x.last <=> y.last} + + changes_by_author = Change.count(:all, :group => :committer, :include => :changeset, :conditions => ["#{Changeset.table_name}.repository_id = ?", repository.id]) + h = changes_by_author.inject({}) {|o, i| o[i.first] = i.last; o} + + fields = commits_by_author.collect {|r| r.first} + commits_data = commits_by_author.collect {|r| r.last} + changes_data = commits_by_author.collect {|r| h[r.first] || 0} + + fields = fields + [""]*(10 - fields.length) if fields.length<10 + commits_data = commits_data + [0]*(10 - commits_data.length) if commits_data.length<10 + changes_data = changes_data + [0]*(10 - changes_data.length) if changes_data.length<10 + + # Remove email adress in usernames + fields = fields.collect {|c| c.gsub(%r{<.+@.+>}, '') } + + graph = SVG::Graph::BarHorizontal.new( + :height => 400, + :width => 650, + :fields => fields, + :stack => :side, + :scale_integers => true, + :show_data_values => false, + :rotate_y_labels => false, + :graph_title => l(:label_commits_per_author), + :show_graph_title => true + ) + graph.add_data( + :data => commits_data, + :title => l(:label_revision_plural) + ) + graph.add_data( + :data => changes_data, + :title => l(:label_change_plural) + ) + graph.burn + end +end diff --git a/app/controllers/roles_controller.rb b/app/controllers/roles_controller.rb new file mode 100644 index 00000000..f4bae1e8 --- /dev/null +++ b/app/controllers/roles_controller.rb @@ -0,0 +1,108 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class RolesController < ApplicationController + layout 'admin' + + before_filter :require_admin, :except => [:index, :show] + before_filter :require_admin_or_api_request, :only => [:index, :show] + before_filter :find_role, :only => [:show, :edit, :update, :destroy] + accept_api_auth :index, :show + + def index + respond_to do |format| + format.html { + @role_pages, @roles = paginate Role.sorted, :per_page => 25 + render :action => "index", :layout => false if request.xhr? + } + format.api { + @roles = Role.givable.all + } + end + end + + def show + respond_to do |format| + format.api + end + end + + def new + # Prefills the form with 'Non member' role permissions by default + @role = Role.new(params[:role] || {:permissions => Role.non_member.permissions}) + if params[:copy].present? && @copy_from = Role.find_by_id(params[:copy]) + @role.copy_from(@copy_from) + end + @roles = Role.sorted.all + end + + def create + @role = Role.new(params[:role]) + if request.post? && @role.save + # workflow copy + if !params[:copy_workflow_from].blank? && (copy_from = Role.find_by_id(params[:copy_workflow_from])) + @role.workflow_rules.copy(copy_from) + end + flash[:notice] = l(:notice_successful_create) + redirect_to roles_path + else + @roles = Role.sorted.all + render :action => 'new' + end + end + + def edit + end + + def update + if request.put? and @role.update_attributes(params[:role]) + flash[:notice] = l(:notice_successful_update) + redirect_to roles_path + else + render :action => 'edit' + end + end + + def destroy + @role.destroy + redirect_to roles_path + rescue + flash[:error] = l(:error_can_not_remove_role) + redirect_to roles_path + end + + def permissions + @roles = Role.sorted.all + @permissions = Redmine::AccessControl.permissions.select { |p| !p.public? } + if request.post? + @roles.each do |role| + role.permissions = params[:permissions][role.id.to_s] + role.save + end + flash[:notice] = l(:notice_successful_update) + redirect_to roles_path + end + end + + private + + def find_role + @role = Role.find(params[:id]) + rescue ActiveRecord::RecordNotFound + render_404 + end +end diff --git a/app/controllers/search_controller.rb b/app/controllers/search_controller.rb new file mode 100644 index 00000000..66a9b674 --- /dev/null +++ b/app/controllers/search_controller.rb @@ -0,0 +1,111 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class SearchController < ApplicationController + before_filter :find_optional_project + + def index + @question = params[:q] || "" + @question.strip! + @all_words = params[:all_words] ? params[:all_words].present? : true + @titles_only = params[:titles_only] ? params[:titles_only].present? : false + + projects_to_search = + case params[:scope] + when 'all' + nil + when 'my_projects' + User.current.memberships.collect(&:project) + when 'subprojects' + @project ? (@project.self_and_descendants.active.all) : nil + else + @project + end + + offset = nil + begin; offset = params[:offset].to_time if params[:offset]; rescue; end + + # quick jump to an issue + if (m = @question.match(/^#?(\d+)$/)) && (issue = Issue.visible.find_by_id(m[1].to_i)) + redirect_to issue_path(issue) + return + end + + @object_types = Redmine::Search.available_search_types.dup + if projects_to_search.is_a? Project + # don't search projects + @object_types.delete('projects') + # only show what the user is allowed to view + @object_types = @object_types.select {|o| User.current.allowed_to?("view_#{o}".to_sym, projects_to_search)} + end + + @scope = @object_types.select {|t| params[t]} + @scope = @object_types if @scope.empty? + + # extract tokens from the question + # eg. hello "bye bye" => ["hello", "bye bye"] + @tokens = @question.scan(%r{((\s|^)"[\s\w]+"(\s|$)|\S+)}).collect {|m| m.first.gsub(%r{(^\s*"\s*|\s*"\s*$)}, '')} + # tokens must be at least 2 characters long + @tokens = @tokens.uniq.select {|w| w.length > 1 } + + if !@tokens.empty? + # no more than 5 tokens to search for + @tokens.slice! 5..-1 if @tokens.size > 5 + + @results = [] + @results_by_type = Hash.new {|h,k| h[k] = 0} + + limit = 10 + @scope.each do |s| + r, c = s.singularize.camelcase.constantize.search(@tokens, projects_to_search, + :all_words => @all_words, + :titles_only => @titles_only, + :limit => (limit+1), + :offset => offset, + :before => params[:previous].nil?) + @results += r + @results_by_type[s] += c + end + @results = @results.sort {|a,b| b.event_datetime <=> a.event_datetime} + if params[:previous].nil? + @pagination_previous_date = @results[0].event_datetime if offset && @results[0] + if @results.size > limit + @pagination_next_date = @results[limit-1].event_datetime + @results = @results[0, limit] + end + else + @pagination_next_date = @results[-1].event_datetime if offset && @results[-1] + if @results.size > limit + @pagination_previous_date = @results[-(limit)].event_datetime + @results = @results[-(limit), limit] + end + end + else + @question = "" + end + render :layout => false if request.xhr? + end + +private + def find_optional_project + return true unless params[:id] + @project = Project.find(params[:id]) + check_project_privacy + rescue ActiveRecord::RecordNotFound + render_404 + end +end diff --git a/app/controllers/settings_controller.rb b/app/controllers/settings_controller.rb new file mode 100644 index 00000000..586c2395 --- /dev/null +++ b/app/controllers/settings_controller.rb @@ -0,0 +1,73 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class SettingsController < ApplicationController + layout 'admin' + menu_item :plugins, :only => :plugin + + helper :queries + + before_filter :require_admin + + def index + edit + render :action => 'edit' + end + + def edit + @notifiables = Redmine::Notifiable.all + if request.post? && params[:settings] && params[:settings].is_a?(Hash) + settings = (params[:settings] || {}).dup.symbolize_keys + settings.each do |name, value| + # remove blank values in array settings + value.delete_if {|v| v.blank? } if value.is_a?(Array) + Setting[name] = value + end + flash[:notice] = l(:notice_successful_update) + redirect_to settings_path(:tab => params[:tab]) + else + @options = {} + user_format = User::USER_FORMATS.collect{|key, value| [key, value[:setting_order]]}.sort{|a, b| a[1] <=> b[1]} + @options[:user_format] = user_format.collect{|f| [User.current.name(f[0]), f[0].to_s]} + @deliveries = ActionMailer::Base.perform_deliveries + + @guessed_host_and_path = request.host_with_port.dup + @guessed_host_and_path << ('/'+ Redmine::Utils.relative_url_root.gsub(%r{^\/}, '')) unless Redmine::Utils.relative_url_root.blank? + + Redmine::Themes.rescan + end + end + + def plugin + @plugin = Redmine::Plugin.find(params[:id]) + unless @plugin.configurable? + render_404 + return + end + + if request.post? + Setting.send "plugin_#{@plugin.id}=", params[:settings] + flash[:notice] = l(:notice_successful_update) + redirect_to plugin_settings_path(@plugin) + else + @partial = @plugin.settings[:partial] + @settings = Setting.send "plugin_#{@plugin.id}" + end + rescue Redmine::PluginNotFound + render_404 + end +end diff --git a/app/controllers/sys_controller.rb b/app/controllers/sys_controller.rb new file mode 100644 index 00000000..b822c5c1 --- /dev/null +++ b/app/controllers/sys_controller.rb @@ -0,0 +1,84 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class SysController < ActionController::Base + before_filter :check_enabled + + def projects + p = Project.active.has_module(:repository).find( + :all, + :include => :repository, + :order => "#{Project.table_name}.identifier" + ) + # extra_info attribute from repository breaks activeresource client + render :xml => p.to_xml( + :only => [:id, :identifier, :name, :is_public, :status], + :include => {:repository => {:only => [:id, :url]}} + ) + end + + def create_project_repository + project = Project.find(params[:id]) + if project.repository + render :nothing => true, :status => 409 + else + logger.info "Repository for #{project.name} was reported to be created by #{request.remote_ip}." + repository = Repository.factory(params[:vendor], params[:repository]) + repository.project = project + if repository.save + render :xml => {repository.class.name.underscore.gsub('/', '-') => {:id => repository.id, :url => repository.url}}, :status => 201 + else + render :nothing => true, :status => 422 + end + end + end + + def fetch_changesets + projects = [] + scope = Project.active.has_module(:repository) + if params[:id] + project = nil + if params[:id].to_s =~ /^\d*$/ + project = scope.find(params[:id]) + else + project = scope.find_by_identifier(params[:id]) + end + raise ActiveRecord::RecordNotFound unless project + projects << project + else + projects = scope.all + end + projects.each do |project| + project.repositories.each do |repository| + repository.fetch_changesets + end + end + render :nothing => true, :status => 200 + rescue ActiveRecord::RecordNotFound + render :nothing => true, :status => 404 + end + + protected + + def check_enabled + User.current = nil + unless Setting.sys_api_enabled? && params[:key].to_s == Setting.sys_api_key + render :text => 'Access denied. Repository management WS is disabled or key is invalid.', :status => 403 + return false + end + end +end diff --git a/app/controllers/tags_controller.rb b/app/controllers/tags_controller.rb new file mode 100644 index 00000000..229fc67a --- /dev/null +++ b/app/controllers/tags_controller.rb @@ -0,0 +1,77 @@ +# This controller was added by william +class TagsController < ApplicationController + + before_filter :require_admin,:only => :show + include ProjectsHelper + include IssuesHelper + include UsersHelper + include ActsAsTaggableOn::TagsHelper + + $selected_tags = Array.new + $related_tags = Array.new + def index + + $selected_tags = [] + $related_tags = [] + $selected_tags << params[:q] + + @issues_tags_num = Issue.tag_counts.size + @projects_tags_num = Project.tag_counts.size + @users_tags_num = User.tag_counts.size + + @issues_results = get_issues_by_tag($selected_tags) + @projects_results = get_projects_by_tag($selected_tags) + @users_results = get_users_by_tag($selected_tags) + + @obj_id = params[:obj_id] + case params[:object_flag] + when '1' then + @obj = User.find_by_id(@obj_id) + when '2' then + @obj = Project.find_by_id(@obj_id) + when '3' then + @obj = Issue.find_by_id(@obj_id) + else + @obj = nil + end + + unless @obj.nil? + @tags = @obj.tag_list + $selected_tags.each do |i| + @tags.delete(i) + end + $related_tags = @tags + else + return + end + + end + + def add_tag + @tag = params[:tag] + $selected_tags << @tag + $related_tags.delete(@tag) + + @issues_results = get_issues_by_tag($selected_tags) + @projects_results = get_projects_by_tag($selected_tags) + @users_results = get_users_by_tag($selected_tags) + end + + def delete_tag + @tag = params[:tag] + $related_tags << @tag + $selected_tags.delete(@tag) + + @issues_results = get_issues_by_tag($selected_tags) + @projects_results = get_projects_by_tag($selected_tags) + @users_results = get_users_by_tag($selected_tags) + end + + def count(name) + end + + def show + + end + +end diff --git a/app/controllers/test_controller.rb b/app/controllers/test_controller.rb new file mode 100644 index 00000000..2aa5599e --- /dev/null +++ b/app/controllers/test_controller.rb @@ -0,0 +1,126 @@ +class TestController < ApplicationController + + before_filter :find_user, :only => [:new, :create, :destroy] + + +def index + #@watchers_of_projects = WatchersOfProjects.new + #@watchers_of_projects.user_id = 1 + #@watchers_of_projects.project_id = 1 + #@watchers_of_projects.save + + #测试user表与watch_project表之间的关联是否成功 + #@user = User.find(params[:id]) + #@watch_table = @user.watch_projects.to_a.first + + #@watch = WatchProject.find(1) + #@watcher = @watch.user + + #测试通过watch_project表使user表可以访问project表 + #@watch_project = @user.projects + #watch_project_path(@watch) + + #@project = Project.find(11) + #project_path(@project) + #@member = @project.users + #@watched = @project.watch_projects + #@issue = Issue.find(6) + + + #user_path(@user) + #issue_path(@issue) + + #@watcher2=WatchProject.where("#{WatchProject.table_name}.project_id = ?" , temp) + + #测试where语句 + #temp = 1 + #@watcher2=WatchProject.where(:project_id => temp).to_a + + #测试新建记录 + #@watch_new = WatchProject.new + #@watch_new.user_id = 4 + #@watch_new.project_id = 1 + #@watch_new.save + #@id = params[:id] + + #测试添加关注项目功能 + #WatchersOfProjects.watch(3,10) + #Project.find(50) + #测试统计关注该项目的用户数 + #@count = WatchersOfProjects.watcher_count(@watch_project.to_a.first) + #测试取消关注功能 + #WatchersOfProjects.watch_cancle(10,35) + + #测试关注用户功能 + #测试关注功能 + #WatchersOfUser.watch_user(7,7) + #测试取消关注功能 + #WatchersOfUser.cancel_watching_user(1,2) + #测试查找关注的人功能 + #@user = WatchersOfUser.find_users(1) + #测试查找被关注的人功能 + #@user = WatchersOfUser.find_watchers(10) + + #测试用户留言功能 + #测试留言功能 + MessagesForUser.leave_message(User.current.id, 6, 'test') + #测试查找留言功能 + #@message_table = MessagesForUser.find_message(3) + #测试查找留言用户功能 + #@messager=@message_table.first.find_messager + + + #测试需求 + #测试新建需求 + #bids = Bid.creat_bids(10000, '2013.7.25', 'test', 'sfsadgfag') + #测试修改需求 + #bids.update_bids(10, '2014.7.222', 'asdf') + #测试删除需求 + # bids = Bid.where('id = ?', 5) + # bids.each do |bid| + # bid.delete_bids + # end + end + + ##########留言功能 message by fq + def new + end + + def create + + if params[:user_search].size>0 + unless params[:user_id].nil? + message = params[:user_search] + MessagesForUser.leave_message(User.current.id, params[:user_id], message) + @message = MessagesForUser.find_message(@user.id) + end + end + + respond_to do |format| + # format.html { redirect_to_referer_or {render :text => 'Watcher added.', :layout => true}} + format.js + #format.api { render_api_ok } + end + end + + def destroy + MessagesForUser.delete_message(params[:object_id]) + @message = MessagesForUser.find_message(@user.id) + respond_to do |format| + format.html { redirect_to :back } + format.js + #format.api { render_api_ok } + end + end + + private + + def find_user + if params[:user_id] + @user = User.find(params[:user_id]) + end + rescue + render_404 + end + #######end of message +end \ No newline at end of file diff --git a/app/controllers/timelog_controller.rb b/app/controllers/timelog_controller.rb new file mode 100644 index 00000000..92210fff --- /dev/null +++ b/app/controllers/timelog_controller.rb @@ -0,0 +1,314 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class TimelogController < ApplicationController + menu_item :issues + + before_filter :find_project_for_new_time_entry, :only => [:create] + before_filter :find_time_entry, :only => [:show, :edit, :update] + before_filter :find_time_entries, :only => [:bulk_edit, :bulk_update, :destroy] + before_filter :authorize, :except => [:new, :index, :report] + + before_filter :find_optional_project, :only => [:index, :report] + before_filter :find_optional_project_for_new_time_entry, :only => [:new] + before_filter :authorize_global, :only => [:new, :index, :report] + + accept_rss_auth :index + accept_api_auth :index, :show, :create, :update, :destroy + + rescue_from Query::StatementInvalid, :with => :query_statement_invalid + + helper :sort + include SortHelper + helper :issues + include TimelogHelper + helper :custom_fields + include CustomFieldsHelper + helper :queries + include QueriesHelper + + def index + @query = TimeEntryQuery.build_from_params(params, :project => @project, :name => '_') + scope = time_entry_scope + + sort_init(@query.sort_criteria.empty? ? [['spent_on', 'desc']] : @query.sort_criteria) + sort_update(@query.sortable_columns) + + respond_to do |format| + format.html { + # Paginate results + @entry_count = scope.count + @entry_pages = Paginator.new @entry_count, per_page_option, params['page'] + @entries = scope.all( + :include => [:project, :activity, :user, {:issue => :tracker}], + :order => sort_clause, + :limit => @entry_pages.per_page, + :offset => @entry_pages.offset + ) + @total_hours = scope.sum(:hours).to_f + + render :layout => !request.xhr? + } + format.api { + @entry_count = scope.count + @offset, @limit = api_offset_and_limit + @entries = scope.all( + :include => [:project, :activity, :user, {:issue => :tracker}], + :order => sort_clause, + :limit => @limit, + :offset => @offset + ) + } + format.atom { + entries = scope.all( + :include => [:project, :activity, :user, {:issue => :tracker}], + :order => "#{TimeEntry.table_name}.created_on DESC", + :limit => Setting.feeds_limit.to_i + ) + render_feed(entries, :title => l(:label_spent_time)) + } + format.csv { + # Export all entries + @entries = scope.all( + :include => [:project, :activity, :user, {:issue => [:tracker, :assigned_to, :priority]}], + :order => sort_clause + ) + send_data(query_to_csv(@entries, @query, params), :type => 'text/csv; header=present', :filename => 'timelog.csv') + } + end + end + + def report + @query = TimeEntryQuery.build_from_params(params, :project => @project, :name => '_') + scope = time_entry_scope + + @report = Redmine::Helpers::TimeReport.new(@project, @issue, params[:criteria], params[:columns], scope) + + respond_to do |format| + format.html { render :layout => !request.xhr? } + format.csv { send_data(report_to_csv(@report), :type => 'text/csv; header=present', :filename => 'timelog.csv') } + end + end + + def show + respond_to do |format| + # TODO: Implement html response + format.html { render :nothing => true, :status => 406 } + format.api + end + end + + def new + @time_entry ||= TimeEntry.new(:project => @project, :issue => @issue, :user => User.current, :spent_on => User.current.today) + @time_entry.safe_attributes = params[:time_entry] + end + + def create + @time_entry ||= TimeEntry.new(:project => @project, :issue => @issue, :user => User.current, :spent_on => User.current.today) + @time_entry.safe_attributes = params[:time_entry] + + call_hook(:controller_timelog_edit_before_save, { :params => params, :time_entry => @time_entry }) + + if @time_entry.save + respond_to do |format| + format.html { + flash[:notice] = l(:notice_successful_create) + if params[:continue] + if params[:project_id] + options = { + :time_entry => {:issue_id => @time_entry.issue_id, :activity_id => @time_entry.activity_id}, + :back_url => params[:back_url] + } + if @time_entry.issue + redirect_to new_project_issue_time_entry_path(@time_entry.project, @time_entry.issue, options) + else + redirect_to new_project_time_entry_path(@time_entry.project, options) + end + else + options = { + :time_entry => {:project_id => @time_entry.project_id, :issue_id => @time_entry.issue_id, :activity_id => @time_entry.activity_id}, + :back_url => params[:back_url] + } + redirect_to new_time_entry_path(options) + end + else + redirect_back_or_default project_time_entries_path(@time_entry.project) + end + } + format.api { render :action => 'show', :status => :created, :location => time_entry_url(@time_entry) } + end + else + respond_to do |format| + format.html { render :action => 'new' } + format.api { render_validation_errors(@time_entry) } + end + end + end + + def edit + @time_entry.safe_attributes = params[:time_entry] + end + + def update + @time_entry.safe_attributes = params[:time_entry] + + call_hook(:controller_timelog_edit_before_save, { :params => params, :time_entry => @time_entry }) + + if @time_entry.save + respond_to do |format| + format.html { + flash[:notice] = l(:notice_successful_update) + redirect_back_or_default project_time_entries_path(@time_entry.project) + } + format.api { render_api_ok } + end + else + respond_to do |format| + format.html { render :action => 'edit' } + format.api { render_validation_errors(@time_entry) } + end + end + end + + def bulk_edit + @available_activities = TimeEntryActivity.shared.active + @custom_fields = TimeEntry.first.available_custom_fields + end + + def bulk_update + attributes = parse_params_for_bulk_time_entry_attributes(params) + + unsaved_time_entry_ids = [] + @time_entries.each do |time_entry| + time_entry.reload + time_entry.safe_attributes = attributes + call_hook(:controller_time_entries_bulk_edit_before_save, { :params => params, :time_entry => time_entry }) + unless time_entry.save + # Keep unsaved time_entry ids to display them in flash error + unsaved_time_entry_ids << time_entry.id + end + end + set_flash_from_bulk_time_entry_save(@time_entries, unsaved_time_entry_ids) + redirect_back_or_default project_time_entries_path(@projects.first) + end + + def destroy + destroyed = TimeEntry.transaction do + @time_entries.each do |t| + unless t.destroy && t.destroyed? + raise ActiveRecord::Rollback + end + end + end + + respond_to do |format| + format.html { + if destroyed + flash[:notice] = l(:notice_successful_delete) + else + flash[:error] = l(:notice_unable_delete_time_entry) + end + redirect_back_or_default project_time_entries_path(@projects.first) + } + format.api { + if destroyed + render_api_ok + else + render_validation_errors(@time_entries) + end + } + end + end + +private + def find_time_entry + @time_entry = TimeEntry.find(params[:id]) + unless @time_entry.editable_by?(User.current) + render_403 + return false + end + @project = @time_entry.project + rescue ActiveRecord::RecordNotFound + render_404 + end + + def find_time_entries + @time_entries = TimeEntry.find_all_by_id(params[:id] || params[:ids]) + raise ActiveRecord::RecordNotFound if @time_entries.empty? + @projects = @time_entries.collect(&:project).compact.uniq + @project = @projects.first if @projects.size == 1 + rescue ActiveRecord::RecordNotFound + render_404 + end + + def set_flash_from_bulk_time_entry_save(time_entries, unsaved_time_entry_ids) + if unsaved_time_entry_ids.empty? + flash[:notice] = l(:notice_successful_update) unless time_entries.empty? + else + flash[:error] = l(:notice_failed_to_save_time_entries, + :count => unsaved_time_entry_ids.size, + :total => time_entries.size, + :ids => '#' + unsaved_time_entry_ids.join(', #')) + end + end + + def find_optional_project_for_new_time_entry + if (project_id = (params[:project_id] || params[:time_entry] && params[:time_entry][:project_id])).present? + @project = Project.find(project_id) + end + if (issue_id = (params[:issue_id] || params[:time_entry] && params[:time_entry][:issue_id])).present? + @issue = Issue.find(issue_id) + @project ||= @issue.project + end + rescue ActiveRecord::RecordNotFound + render_404 + end + + def find_project_for_new_time_entry + find_optional_project_for_new_time_entry + if @project.nil? + render_404 + end + end + + def find_optional_project + if !params[:issue_id].blank? + @issue = Issue.find(params[:issue_id]) + @project = @issue.project + elsif !params[:project_id].blank? + @project = Project.find(params[:project_id]) + end + end + + # Returns the TimeEntry scope for index and report actions + def time_entry_scope + scope = TimeEntry.visible.where(@query.statement) + if @issue + scope = scope.on_issue(@issue) + elsif @project + scope = scope.on_project(@project, Setting.display_subprojects_issues?) + end + scope + end + + def parse_params_for_bulk_time_entry_attributes(params) + attributes = (params[:time_entry] || {}).reject {|k,v| v.blank?} + attributes.keys.each {|k| attributes[k] = '' if attributes[k] == 'none'} + attributes[:custom_field_values].reject! {|k,v| v.blank?} if attributes[:custom_field_values] + attributes + end +end diff --git a/app/controllers/trackers_controller.rb b/app/controllers/trackers_controller.rb new file mode 100644 index 00000000..94131a2e --- /dev/null +++ b/app/controllers/trackers_controller.rb @@ -0,0 +1,101 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class TrackersController < ApplicationController + layout 'admin' + + before_filter :require_admin, :except => :index + before_filter :require_admin_or_api_request, :only => :index + accept_api_auth :index + + def index + respond_to do |format| + format.html { + @tracker_pages, @trackers = paginate Tracker.sorted, :per_page => 25 + render :action => "index", :layout => false if request.xhr? + } + format.api { + @trackers = Tracker.sorted.all + } + end + end + + def new + @tracker ||= Tracker.new(params[:tracker]) + @trackers = Tracker.sorted.all + @projects = Project.all + end + + def create + @tracker = Tracker.new(params[:tracker]) + if @tracker.save + # workflow copy + if !params[:copy_workflow_from].blank? && (copy_from = Tracker.find_by_id(params[:copy_workflow_from])) + @tracker.workflow_rules.copy(copy_from) + end + flash[:notice] = l(:notice_successful_create) + redirect_to trackers_path + return + end + new + render :action => 'new' + end + + def edit + @tracker ||= Tracker.find(params[:id]) + @projects = Project.all + end + + def update + @tracker = Tracker.find(params[:id]) + if @tracker.update_attributes(params[:tracker]) + flash[:notice] = l(:notice_successful_update) + redirect_to trackers_path + return + end + edit + render :action => 'edit' + end + + def destroy + @tracker = Tracker.find(params[:id]) + unless @tracker.issues.empty? + flash[:error] = l(:error_can_not_delete_tracker) + else + @tracker.destroy + end + redirect_to trackers_path + end + + def fields + if request.post? && params[:trackers] + params[:trackers].each do |tracker_id, tracker_params| + tracker = Tracker.find_by_id(tracker_id) + if tracker + tracker.core_fields = tracker_params[:core_fields] + tracker.custom_field_ids = tracker_params[:custom_field_ids] + tracker.save + end + end + flash[:notice] = l(:notice_successful_update) + redirect_to fields_trackers_path + return + end + @trackers = Tracker.sorted.all + @custom_fields = IssueCustomField.all.sort + end +end diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb new file mode 100644 index 00000000..31960871 --- /dev/null +++ b/app/controllers/users_controller.rb @@ -0,0 +1,320 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +class UsersController < ApplicationController + layout 'base_users' + + before_filter :require_admin, :except => [:show, :index,:tag_save] + before_filter :find_user, :only => [:show, :edit, :update, :destroy, :edit_membership, :destroy_membership, :user_activities, :user_projects, :user_newfeedback, :user_comments] + accept_api_auth :index, :show, :create, :update, :destroy + + helper :sort + include SortHelper + helper :custom_fields + include CustomFieldsHelper + include AvatarHelper + + # added by liuping 关注 + + helper :watchers + helper :activities + + ### added by william + include ActsAsTaggableOn::TagsHelper + + + helper :watchers + helper :activities + + # fq + helper :words + #added by young + def user_projects + @message = MessagesForUser.find_message(@user.id) + @memberships = @user.memberships.all(:conditions => Project.visible_condition(User.current)) + + events = Redmine::Activity::Fetcher.new(User.current, :author => @user).events(nil, nil, :limit => 20) + @events_by_day = events.group_by(&:event_date) + + unless User.current.admin? + if !@user.active? || (@user != User.current && @memberships.empty? && events.empty?) + render_404 + return + end + end + + respond_to do |format| + format.html + format.api + end + end + + + def user_activities + #####fq +# @message = MessagesForUser.find_message(@user.id) + # show projects based on current user visibility +# @memberships = @user.memberships.all(:conditions => Project.visible_condition(User.current)) + + events = Redmine::Activity::Fetcher.new(User.current, :author => @user).events(nil, nil, :limit => 30) + @events_by_day = events.group_by(&:event_date) + + unless User.current.admin? + if !@user.active? || (@user != User.current && @memberships.empty? && events.empty?) + render_404 + return + end + end + + respond_to do |format| + format.html + format.api + end + end + + def user_newfeedback + @jour = @user.journals_for_messages + @jour.each_with_index {|j,i| j.indice = i+1} + @state = false + + end + + def user_comments + + end + #end + def index + sort_init 'login', 'asc' + sort_update %w(login firstname lastname mail admin created_on last_login_on) + + case params[:format] + when 'xml', 'json' + @offset, @limit = api_offset_and_limit + else + @limit = per_page_option + end + + @status = params[:status] || 1 + has = { + "show_changesets" => true + } + # @count = Redmine::Activity::Fetcher.new(User.current, :author => @user).scope_select {|t| !has["show_#{t}"].nil?}.events(nil, nil).count + + + scope = User.logged.status(@status) + scope = scope.like(params[:name]) if params[:name].present? + scope = scope.in_group(params[:group_id]) if params[:group_id].present? + + @user_count = scope.count + @user_pages = Paginator.new @user_count, @limit, params['page'] + @offset ||= @user_pages.offset + @users = scope.order(sort_clause).limit(@limit).offset(@offset).all + @user_base_tag = params[:id]?'base_users':'base' + respond_to do |format| + format.html { + @groups = Group.all.sort + render :layout => @user_base_tag + } + format.api + end + end + + def show + #####fq + @message = MessagesForUser.find_message(@user.id) + # show projects based on current user visibility + @memberships = @user.memberships.all(:conditions => Project.visible_condition(User.current)) + + events = Redmine::Activity::Fetcher.new(User.current, :author => @user).events(nil, nil, :limit => 10) + @events_by_day = events.group_by(&:event_date) + + unless User.current.admin? + if !@user.active? || (@user != User.current && @memberships.empty? && events.empty?) + render_404 + return + end + end + + respond_to do |format| + format.html + format.api + end + end + + def new + @user = User.new(:language => Setting.default_language, :mail_notification => Setting.default_notification_option) + @auth_sources = AuthSource.all + end + + def create + @user = User.new(:language => Setting.default_language, :mail_notification => Setting.default_notification_option) + @user.safe_attributes = params[:user] + @user.admin = params[:user][:admin] || false + @user.login = params[:user][:login] + @user.password, @user.password_confirmation = params[:user][:password], params[:user][:password_confirmation] unless @user.auth_source_id + + if @user.save + @user.pref.attributes = params[:pref] + @user.pref[:no_self_notified] = (params[:no_self_notified] == '1') + @user.pref.save + @user.notified_project_ids = (@user.mail_notification == 'selected' ? params[:notified_project_ids] : []) + + Mailer.account_information(@user, params[:user][:password]).deliver if params[:send_information] + + respond_to do |format| + format.html { + flash[:notice] = l(:notice_user_successful_create, :id => view_context.link_to(@user.login, user_path(@user))) + if params[:continue] + redirect_to new_user_path + else + redirect_to edit_user_path(@user) + end + } + format.api { render :action => 'show', :status => :created, :location => user_url(@user) } + end + else + @auth_sources = AuthSource.all + # Clear password input + @user.password = @user.password_confirmation = nil + + respond_to do |format| + format.html { render :action => 'new' } + format.api { render_validation_errors(@user) } + end + end + end + + def edit + @auth_sources = AuthSource.all + @membership ||= Member.new + end + + def update + @user.admin = params[:user][:admin] if params[:user][:admin] + @user.login = params[:user][:login] if params[:user][:login] + if params[:user][:password].present? && (@user.auth_source_id.nil? || params[:user][:auth_source_id].blank?) + @user.password, @user.password_confirmation = params[:user][:password], params[:user][:password_confirmation] + end + @user.safe_attributes = params[:user] + # Was the account actived ? (do it before User#save clears the change) + was_activated = (@user.status_change == [User::STATUS_REGISTERED, User::STATUS_ACTIVE]) + # TODO: Similar to My#account + @user.pref.attributes = params[:pref] + @user.pref[:no_self_notified] = (params[:no_self_notified] == '1') + + if @user.save + @user.pref.save + @user.notified_project_ids = (@user.mail_notification == 'selected' ? params[:notified_project_ids] : []) + + if was_activated + Mailer.account_activated(@user).deliver + elsif @user.active? && params[:send_information] && !params[:user][:password].blank? && @user.auth_source_id.nil? + Mailer.account_information(@user, params[:user][:password]).deliver + end + + respond_to do |format| + format.html { + flash[:notice] = l(:notice_successful_update) + redirect_to_referer_or edit_user_path(@user) + } + format.api { render_api_ok } + end + else + @auth_sources = AuthSource.all + @membership ||= Member.new + # Clear password input + @user.password = @user.password_confirmation = nil + + respond_to do |format| + format.html { render :action => :edit } + format.api { render_validation_errors(@user) } + end + end + end + + def destroy + @user.destroy + respond_to do |format| + format.html { redirect_back_or_default(users_path) } + format.api { render_api_ok } + end + end + + def edit_membership + @membership = Member.edit_membership(params[:membership_id], params[:membership], @user) + @membership.save + respond_to do |format| + format.html { redirect_to edit_user_path(@user, :tab => 'memberships') } + format.js + end + end + + def destroy_membership + @membership = Member.find(params[:membership_id]) + if @membership.deletable? + @membership.destroy + end + respond_to do |format| + format.html { redirect_to edit_user_path(@user, :tab => 'memberships') } + format.js + end + end + + ################# added by william + def tag_save + @tags = params[:tag_for_save][:name] + @obj_id = params[:tag_for_save][:object_id] + @obj_flag = params[:tag_for_save][:object_flag] + + case @obj_flag + when '1' then + @obj = User.find_by_id(@obj_id) + when '2' then + @obj = Project.find_by_id(@obj_id) + when '3' then + @obj = Issue.find_by_id(@obj_id) + else + @obj = nil + end + unless @obj.nil? + @obj.tag_list.add(@tags.split(",")) + else + return + end + if @obj.save + ## 执行成功的操作。 + else + #捕获异常 + end + respond_to do |format| + format.html + format.js + end + end + + private + + def find_user + if params[:id] == 'current' + require_login || return + @user = User.current + else + @user = User.find(params[:id]) + end + rescue ActiveRecord::RecordNotFound + render_404 + end +end diff --git a/app/controllers/versions_controller.rb b/app/controllers/versions_controller.rb new file mode 100644 index 00000000..f159f7ec --- /dev/null +++ b/app/controllers/versions_controller.rb @@ -0,0 +1,182 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class VersionsController < ApplicationController + menu_item :roadmap + model_object Version + before_filter :find_model_object, :except => [:index, :new, :create, :close_completed] + before_filter :find_project_from_association, :except => [:index, :new, :create, :close_completed] + before_filter :find_project_by_project_id, :only => [:index, :new, :create, :close_completed] + before_filter :authorize + + accept_api_auth :index, :show, :create, :update, :destroy + + helper :custom_fields + helper :projects + + def index + respond_to do |format| + format.html { + @trackers = @project.trackers.sorted.all + retrieve_selected_tracker_ids(@trackers, @trackers.select {|t| t.is_in_roadmap?}) + @with_subprojects = params[:with_subprojects].nil? ? Setting.display_subprojects_issues? : (params[:with_subprojects] == '1') + project_ids = @with_subprojects ? @project.self_and_descendants.collect(&:id) : [@project.id] + + @versions = @project.shared_versions || [] + @versions += @project.rolled_up_versions.visible if @with_subprojects + @versions = @versions.uniq.sort + unless params[:completed] + @completed_versions = @versions.select {|version| version.closed? || version.completed? } + @versions -= @completed_versions + end + + @issues_by_version = {} + if @selected_tracker_ids.any? && @versions.any? + issues = Issue.visible.all( + :include => [:project, :status, :tracker, :priority, :fixed_version], + :conditions => {:tracker_id => @selected_tracker_ids, :project_id => project_ids, :fixed_version_id => @versions.map(&:id)}, + :order => "#{Project.table_name}.lft, #{Tracker.table_name}.position, #{Issue.table_name}.id" + ) + @issues_by_version = issues.group_by(&:fixed_version) + end + @versions.reject! {|version| !project_ids.include?(version.project_id) && @issues_by_version[version].blank?} + } + format.api { + @versions = @project.shared_versions.all + } + end + end + + def show + respond_to do |format| + format.html { + @issues = @version.fixed_issues.visible. + includes(:status, :tracker, :priority). + reorder("#{Tracker.table_name}.position, #{Issue.table_name}.id"). + all + } + format.api + end + end + + def new + @version = @project.versions.build + @version.safe_attributes = params[:version] + + respond_to do |format| + format.html + format.js + end + end + + def create + @version = @project.versions.build + if params[:version] + attributes = params[:version].dup + attributes.delete('sharing') unless attributes.nil? || @version.allowed_sharings.include?(attributes['sharing']) + @version.safe_attributes = attributes + end + + if request.post? + if @version.save + respond_to do |format| + format.html do + flash[:notice] = l(:notice_successful_create) + redirect_back_or_default settings_project_path(@project, :tab => 'versions') + end + format.js + format.api do + render :action => 'show', :status => :created, :location => version_url(@version) + end + end + else + respond_to do |format| + format.html { render :action => 'new' } + format.js { render :action => 'new' } + format.api { render_validation_errors(@version) } + end + end + end + end + + def edit + end + + def update + if request.put? && params[:version] + attributes = params[:version].dup + attributes.delete('sharing') unless @version.allowed_sharings.include?(attributes['sharing']) + @version.safe_attributes = attributes + if @version.save + respond_to do |format| + format.html { + flash[:notice] = l(:notice_successful_update) + redirect_back_or_default settings_project_path(@project, :tab => 'versions') + } + format.api { render_api_ok } + end + else + respond_to do |format| + format.html { render :action => 'edit' } + format.api { render_validation_errors(@version) } + end + end + end + end + + def close_completed + if request.put? + @project.close_completed_versions + end + redirect_to settings_project_path(@project, :tab => 'versions') + end + + def destroy + if @version.fixed_issues.empty? + @version.destroy + respond_to do |format| + format.html { redirect_back_or_default settings_project_path(@project, :tab => 'versions') } + format.api { render_api_ok } + end + else + respond_to do |format| + format.html { + flash[:error] = l(:notice_unable_delete_version) + redirect_to settings_project_path(@project, :tab => 'versions') + } + format.api { head :unprocessable_entity } + end + end + end + + def status_by + respond_to do |format| + format.html { render :action => 'show' } + format.js + end + end + + private + + def retrieve_selected_tracker_ids(selectable_trackers, default_trackers=nil) + if ids = params[:tracker_ids] + @selected_tracker_ids = (ids.is_a? Array) ? ids.collect { |id| id.to_i.to_s } : ids.split('/').collect { |id| id.to_i.to_s } + else + @selected_tracker_ids = (default_trackers || selectable_trackers).collect {|t| t.id.to_s } + end + end +end diff --git a/app/controllers/watchers_controller.rb b/app/controllers/watchers_controller.rb new file mode 100644 index 00000000..2f55de2f --- /dev/null +++ b/app/controllers/watchers_controller.rb @@ -0,0 +1,109 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class WatchersController < ApplicationController + before_filter :require_login, :find_watchables, :only => [:watch, :unwatch] + + def watch + set_watcher(@watchables, User.current, true) + end + + def unwatch + set_watcher(@watchables, User.current, false) + end + + before_filter :find_project, :authorize, :only => [:new, :create, :append, :destroy, :autocomplete_for_user] + accept_api_auth :create, :destroy + + def new + end + + def create + user_ids = [] + if params[:watcher].is_a?(Hash) + user_ids << (params[:watcher][:user_ids] || params[:watcher][:user_id]) + else + user_ids << params[:user_id] + end + user_ids.flatten.compact.uniq.each do |user_id| + Watcher.create(:watchable => @watched, :user_id => user_id) + end + respond_to do |format| + format.html { redirect_to_referer_or {render :text => 'Watcher added.', :layout => true}} + format.js + format.api { render_api_ok } + end + end + + def append + if params[:watcher].is_a?(Hash) + user_ids = params[:watcher][:user_ids] || [params[:watcher][:user_id]] + @users = User.active.find_all_by_id(user_ids) + end + end + + def destroy + @watched.set_watcher(User.find(params[:user_id]), false) + respond_to do |format| + format.html { redirect_to :back } + format.js + format.api { render_api_ok } + end + end + + def autocomplete_for_user + @users = User.active.sorted.like(params[:q]).limit(100).all + if @watched + @users -= @watched.watcher_users + end + render :layout => false + end + + private + + def find_project + if params[:object_type] && params[:object_id] + klass = Object.const_get(params[:object_type].camelcase) + return false unless klass.respond_to?('watched_by') + @watched = klass.find(params[:object_id]) + @project = @watched.project + elsif params[:project_id] + @project = Project.visible.find_by_param(params[:project_id]) + end + rescue + render_404 + end + + def find_watchables + klass = Object.const_get(params[:object_type].camelcase) rescue nil + if klass && klass.respond_to?('watched_by') + @watchables = klass.find_all_by_id(Array.wrap(params[:object_id])) + raise Unauthorized if @watchables.any? {|w| w.respond_to?(:visible?) && !w.visible?} + end + render_404 unless @watchables.present? + end + + def set_watcher(watchables, user, watching) + watchables.each do |watchable| + watchable.set_watcher(user, watching) + end + respond_to do |format| + format.html { redirect_to_referer_or {render :text => (watching ? 'Watcher added.' : 'Watcher removed.'), :layout => true}} + format.js { render :partial => 'set_watcher', :locals => {:user => user, :watched => watchables} } + end + end +end diff --git a/app/controllers/welcome_controller.rb b/app/controllers/welcome_controller.rb new file mode 100644 index 00000000..23808a27 --- /dev/null +++ b/app/controllers/welcome_controller.rb @@ -0,0 +1,68 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class WelcomeController < ApplicationController + caches_action :robots + + def index + @news = News.latest User.current + @projects = Project.latest User.current + #by young + (redirect_to(home_url); return) unless Setting.self_registration? || session[:auth_source_registration] + if request.get? + session[:auth_source_registration] = nil + @user = User.new(:language => current_language.to_s) + else + user_params = params[:user] || {} + @user = User.new + @user.safe_attributes = user_params + @user.admin = false + @user.register + if session[:auth_source_registration] + @user.activate + @user.login = session[:auth_source_registration][:login] + @user.auth_source_id = session[:auth_source_registration][:auth_source_id] + if @user.save + session[:auth_source_registration] = nil + self.logged_user = @user + flash[:notice] = l(:notice_account_activated) + redirect_to my_account_path + end + else + @user.login = params[:user][:login] + unless user_params[:identity_url].present? && user_params[:password].blank? && user_params[:password_confirmation].blank? + @user.password, @user.password_confirmation = user_params[:password], user_params[:password_confirmation] + end + + case Setting.self_registration + when '1' + register_by_email_activation(@user) + when '3' + register_automatically(@user) + else + register_manually_by_administrator(@user) + end + end + end + # + end + + def robots + @projects = Project.all_public.active + render :layout => false, :content_type => 'text/plain' + end +end diff --git a/app/controllers/wiki_controller.rb b/app/controllers/wiki_controller.rb new file mode 100644 index 00000000..2b7d485f --- /dev/null +++ b/app/controllers/wiki_controller.rb @@ -0,0 +1,357 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +require 'diff' + +# The WikiController follows the Rails REST controller pattern but with +# a few differences +# +# * index - shows a list of WikiPages grouped by page or date +# * new - not used +# * create - not used +# * show - will also show the form for creating a new wiki page +# * edit - used to edit an existing or new page +# * update - used to save a wiki page update to the database, including new pages +# * destroy - normal +# +# Other member and collection methods are also used +# +# TODO: still being worked on +class WikiController < ApplicationController + layout 'base_projects' + default_search_scope :wiki_pages + before_filter :find_wiki, :authorize + before_filter :find_existing_or_new_page, :only => [:show, :edit, :update] + before_filter :find_existing_page, :only => [:rename, :protect, :history, :diff, :annotate, :add_attachment, :destroy, :destroy_version] + accept_api_auth :index, :show, :update, :destroy + before_filter :find_attachments, :only => [:preview] + + helper :attachments + include AttachmentsHelper + helper :watchers + include Redmine::Export::PDF + + # List of pages, sorted alphabetically and by parent (hierarchy) + def index + load_pages_for_index + + respond_to do |format| + format.html { + @pages_by_parent_id = @pages.group_by(&:parent_id) + } + format.api + end + end + + # List of page, by last update + def date_index + load_pages_for_index + @pages_by_date = @pages.group_by {|p| p.updated_on.to_date} + end + + # display a page (in editing mode if it doesn't exist) + def show + if @page.new_record? + if User.current.allowed_to?(:edit_wiki_pages, @project) && editable? && !api_request? + edit + render :action => 'edit' + else + render_404 + end + return + end + if params[:version] && !User.current.allowed_to?(:view_wiki_edits, @project) + deny_access + return + end + @content = @page.content_for_version(params[:version]) + if User.current.allowed_to?(:export_wiki_pages, @project) + if params[:format] == 'pdf' + send_data(wiki_page_to_pdf(@page, @project), :type => 'application/pdf', :filename => "#{@page.title}.pdf") + return + elsif params[:format] == 'html' + export = render_to_string :action => 'export', :layout => false + send_data(export, :type => 'text/html', :filename => "#{@page.title}.html") + return + elsif params[:format] == 'txt' + send_data(@content.text, :type => 'text/plain', :filename => "#{@page.title}.txt") + return + end + end + @editable = editable? + @sections_editable = @editable && User.current.allowed_to?(:edit_wiki_pages, @page.project) && + @content.current_version? && + Redmine::WikiFormatting.supports_section_edit? + + respond_to do |format| + format.html + format.api + end + end + + # edit an existing page or a new one + def edit + return render_403 unless editable? + if @page.new_record? + @page.content = WikiContent.new(:page => @page) + if params[:parent].present? + @page.parent = @page.wiki.find_page(params[:parent].to_s) + end + end + + @content = @page.content_for_version(params[:version]) + @content.text = initial_page_content(@page) if @content.text.blank? + # don't keep previous comment + @content.comments = nil + + # To prevent StaleObjectError exception when reverting to a previous version + @content.version = @page.content.version + + @text = @content.text + if params[:section].present? && Redmine::WikiFormatting.supports_section_edit? + @section = params[:section].to_i + @text, @section_hash = Redmine::WikiFormatting.formatter.new(@text).get_section(@section) + render_404 if @text.blank? + end + end + + # Creates a new page or updates an existing one + def update + return render_403 unless editable? + was_new_page = @page.new_record? + @page.content = WikiContent.new(:page => @page) if @page.new_record? + @page.safe_attributes = params[:wiki_page] + + @content = @page.content + content_params = params[:content] + if content_params.nil? && params[:wiki_page].is_a?(Hash) + content_params = params[:wiki_page].slice(:text, :comments, :version) + end + content_params ||= {} + + @content.comments = content_params[:comments] + @text = content_params[:text] + if params[:section].present? && Redmine::WikiFormatting.supports_section_edit? + @section = params[:section].to_i + @section_hash = params[:section_hash] + @content.text = Redmine::WikiFormatting.formatter.new(@content.text).update_section(params[:section].to_i, @text, @section_hash) + else + @content.version = content_params[:version] if content_params[:version] + @content.text = @text + end + @content.author = User.current + + if @page.save_with_content + attachments = Attachment.attach_files(@page, params[:attachments]) + render_attachment_warning_if_needed(@page) + call_hook(:controller_wiki_edit_after_save, { :params => params, :page => @page}) + + respond_to do |format| + format.html { redirect_to project_wiki_page_path(@project, @page.title) } + format.api { + if was_new_page + render :action => 'show', :status => :created, :location => project_wiki_page_path(@project, @page.title) + else + render_api_ok + end + } + end + else + respond_to do |format| + format.html { render :action => 'edit' } + format.api { render_validation_errors(@content) } + end + end + + rescue ActiveRecord::StaleObjectError, Redmine::WikiFormatting::StaleSectionError + # Optimistic locking exception + respond_to do |format| + format.html { + flash.now[:error] = l(:notice_locking_conflict) + render :action => 'edit' + } + format.api { render_api_head :conflict } + end + rescue ActiveRecord::RecordNotSaved + respond_to do |format| + format.html { render :action => 'edit' } + format.api { render_validation_errors(@content) } + end + end + + # rename a page + def rename + return render_403 unless editable? + @page.redirect_existing_links = true + # used to display the *original* title if some AR validation errors occur + @original_title = @page.pretty_title + if request.post? && @page.update_attributes(params[:wiki_page]) + flash[:notice] = l(:notice_successful_update) + redirect_to project_wiki_page_path(@project, @page.title) + end + end + + def protect + @page.update_attribute :protected, params[:protected] + redirect_to project_wiki_page_path(@project, @page.title) + end + + # show page history + def history + @version_count = @page.content.versions.count + @version_pages = Paginator.new @version_count, per_page_option, params['page'] + # don't load text + @versions = @page.content.versions. + select("id, author_id, comments, updated_on, version"). + reorder('version DESC'). + limit(@version_pages.per_page + 1). + offset(@version_pages.offset). + all + + render :layout => false if request.xhr? + end + + def diff + @diff = @page.diff(params[:version], params[:version_from]) + render_404 unless @diff + end + + def annotate + @annotate = @page.annotate(params[:version]) + render_404 unless @annotate + end + + # Removes a wiki page and its history + # Children can be either set as root pages, removed or reassigned to another parent page + def destroy + return render_403 unless editable? + + @descendants_count = @page.descendants.size + if @descendants_count > 0 + case params[:todo] + when 'nullify' + # Nothing to do + when 'destroy' + # Removes all its descendants + @page.descendants.each(&:destroy) + when 'reassign' + # Reassign children to another parent page + reassign_to = @wiki.pages.find_by_id(params[:reassign_to_id].to_i) + return unless reassign_to + @page.children.each do |child| + child.update_attribute(:parent, reassign_to) + end + else + @reassignable_to = @wiki.pages - @page.self_and_descendants + # display the destroy form if it's a user request + return unless api_request? + end + end + @page.destroy + respond_to do |format| + format.html { redirect_to project_wiki_index_path(@project) } + format.api { render_api_ok } + end + end + + def destroy_version + return render_403 unless editable? + + @content = @page.content_for_version(params[:version]) + @content.destroy + redirect_to_referer_or history_project_wiki_page_path(@project, @page.title) + end + + # Export wiki to a single pdf or html file + def export + @pages = @wiki.pages.all(:order => 'title', :include => [:content, {:attachments => :author}]) + respond_to do |format| + format.html { + export = render_to_string :action => 'export_multiple', :layout => false + send_data(export, :type => 'text/html', :filename => "wiki.html") + } + format.pdf { + send_data(wiki_pages_to_pdf(@pages, @project), :type => 'application/pdf', :filename => "#{@project.identifier}.pdf") + } + end + end + + def preview + page = @wiki.find_page(params[:id]) + # page is nil when previewing a new page + return render_403 unless page.nil? || editable?(page) + if page + @attachments += page.attachments + @previewed = page.content + end + @text = params[:content][:text] + render :partial => 'common/preview' + end + + def add_attachment + return render_403 unless editable? + attachments = Attachment.attach_files(@page, params[:attachments]) + render_attachment_warning_if_needed(@page) + redirect_to :action => 'show', :id => @page.title, :project_id => @project + end + +private + + def find_wiki + @project = Project.find(params[:project_id]) + @wiki = @project.wiki + render_404 unless @wiki + rescue ActiveRecord::RecordNotFound + render_404 + end + + # Finds the requested page or a new page if it doesn't exist + def find_existing_or_new_page + @page = @wiki.find_or_new_page(params[:id]) + if @wiki.page_found_with_redirect? + redirect_to params.update(:id => @page.title) + end + end + + # Finds the requested page and returns a 404 error if it doesn't exist + def find_existing_page + @page = @wiki.find_page(params[:id]) + if @page.nil? + render_404 + return + end + if @wiki.page_found_with_redirect? + redirect_to params.update(:id => @page.title) + end + end + + # Returns true if the current user is allowed to edit the page, otherwise false + def editable?(page = @page) + page.editable_by?(User.current) + end + + # Returns the default content of a new wiki page + def initial_page_content(page) + helper = Redmine::WikiFormatting.helper_for(Setting.text_formatting) + extend helper unless self.instance_of?(helper) + helper.instance_method(:initial_page_content).bind(self).call(page) + end + + def load_pages_for_index + @pages = @wiki.pages.with_updated_on.reorder("#{WikiPage.table_name}.title").includes(:wiki => :project).includes(:parent).all + end +end diff --git a/app/controllers/wikis_controller.rb b/app/controllers/wikis_controller.rb new file mode 100644 index 00000000..cdd778e4 --- /dev/null +++ b/app/controllers/wikis_controller.rb @@ -0,0 +1,36 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class WikisController < ApplicationController + menu_item :settings + before_filter :find_project, :authorize + + # Create or update a project's wiki + def edit + @wiki = @project.wiki || Wiki.new(:project => @project) + @wiki.safe_attributes = params[:wiki] + @wiki.save if request.post? + end + + # Delete a project's wiki + def destroy + if request.post? && params[:confirm] && @project.wiki + @project.wiki.destroy + redirect_to settings_project_path(@project, :tab => 'wiki') + end + end +end diff --git a/app/controllers/words_controller.rb b/app/controllers/words_controller.rb new file mode 100644 index 00000000..ab7d7f9a --- /dev/null +++ b/app/controllers/words_controller.rb @@ -0,0 +1,99 @@ +#####leave message fq +class WordsController < ApplicationController + + before_filter :find_user, :only => [:new, :create, :destroy, :more, :back] + + def create + if params[:new_form][:user_message].size>0 + unless params[:user_id].nil? + message = params[:new_form][:user_message] + @user.add_jour(User.current, message) + # if a_message.size > 5 + # @message = a_message[-5, 5] + # else + # @message = a_message + # end + # @message_count = a_message.count + end + end + @jour = @user.journals_for_messages + @jour.each_with_index {|j,i| j.indice = i+1} + + respond_to do |format| + # format.html { redirect_to_referer_or {render :text => 'Watcher added.', :layout => true}} + format.js + #format.api { render_api_ok } + end + end + + def destroy + JournalsForMessage.delete_message(params[:object_id]) + @jour = @user.journals_for_messages + @jour.each_with_index {|j,i| j.indice = i+1} + # if a_message.size > 5 + # @message = a_message[-5, 5] + # else + # @message = a_message + # end + # @message_count = a_message.count + + respond_to do |format| + format.html { redirect_to :back } + format.js + #format.api { render_api_ok } + end + end + + def new + @jour = JournalsForMessage.find(params[:journal_id]) if params[:journal_id] + if @jour + user = @jour.user + text = @jour.notes + else + user = @user + text = [] + end + # Replaces pre blocks with [...] + text = text.to_s.strip.gsub(%r{
((.|\s)*?)
}m, '[...]') + @content = "#{ll(Setting.default_language, :text_user_wrote, user)}\n> " + @content << text.gsub(/(\r?\n|\r\n?)/, "\n> ") + "\n\n" + rescue ActiveRecord::RecordNotFound + render_404 + end + + def more + @jour = @user.journals_for_messages + @jour.each_with_index {|j,i| j.indice = i+1} + @state = true + + respond_to do |format| + format.html { redirect_to :back } + format.js + #format.api { render_api_ok } + end + end + + def back + @jour = @user.journals_for_messages + @jour.each_with_index {|j,i| j.indice = i+1} + @state = false + + respond_to do |format| + format.html { redirect_to :back } + format.js + #format.api { render_api_ok } + end + end + + private + + def find_user + if params[:user_id] + @user = User.find(params[:user_id]) + end + rescue + render_404 + end + + #######end of message +end \ No newline at end of file diff --git a/app/controllers/workflows_controller.rb b/app/controllers/workflows_controller.rb new file mode 100644 index 00000000..06ae30e2 --- /dev/null +++ b/app/controllers/workflows_controller.rb @@ -0,0 +1,128 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class WorkflowsController < ApplicationController + layout 'admin' + + before_filter :require_admin, :find_roles, :find_trackers + + def index + @workflow_counts = WorkflowTransition.count_by_tracker_and_role + end + + def edit + @role = Role.find_by_id(params[:role_id]) if params[:role_id] + @tracker = Tracker.find_by_id(params[:tracker_id]) if params[:tracker_id] + + if request.post? + WorkflowTransition.destroy_all( ["role_id=? and tracker_id=?", @role.id, @tracker.id]) + (params[:issue_status] || []).each { |status_id, transitions| + transitions.each { |new_status_id, options| + author = options.is_a?(Array) && options.include?('author') && !options.include?('always') + assignee = options.is_a?(Array) && options.include?('assignee') && !options.include?('always') + WorkflowTransition.create(:role_id => @role.id, :tracker_id => @tracker.id, :old_status_id => status_id, :new_status_id => new_status_id, :author => author, :assignee => assignee) + } + } + if @role.save + redirect_to workflows_edit_path(:role_id => @role, :tracker_id => @tracker, :used_statuses_only => params[:used_statuses_only]) + return + end + end + + @used_statuses_only = (params[:used_statuses_only] == '0' ? false : true) + if @tracker && @used_statuses_only && @tracker.issue_statuses.any? + @statuses = @tracker.issue_statuses + end + @statuses ||= IssueStatus.sorted.all + + if @tracker && @role && @statuses.any? + workflows = WorkflowTransition.where(:role_id => @role.id, :tracker_id => @tracker.id).all + @workflows = {} + @workflows['always'] = workflows.select {|w| !w.author && !w.assignee} + @workflows['author'] = workflows.select {|w| w.author} + @workflows['assignee'] = workflows.select {|w| w.assignee} + end + end + + def permissions + @role = Role.find_by_id(params[:role_id]) if params[:role_id] + @tracker = Tracker.find_by_id(params[:tracker_id]) if params[:tracker_id] + + if request.post? && @role && @tracker + WorkflowPermission.replace_permissions(@tracker, @role, params[:permissions] || {}) + redirect_to workflows_permissions_path(:role_id => @role, :tracker_id => @tracker, :used_statuses_only => params[:used_statuses_only]) + return + end + + @used_statuses_only = (params[:used_statuses_only] == '0' ? false : true) + if @tracker && @used_statuses_only && @tracker.issue_statuses.any? + @statuses = @tracker.issue_statuses + end + @statuses ||= IssueStatus.sorted.all + + if @role && @tracker + @fields = (Tracker::CORE_FIELDS_ALL - @tracker.disabled_core_fields).map {|field| [field, l("field_"+field.sub(/_id$/, ''))]} + @custom_fields = @tracker.custom_fields + + @permissions = WorkflowPermission.where(:tracker_id => @tracker.id, :role_id => @role.id).all.inject({}) do |h, w| + h[w.old_status_id] ||= {} + h[w.old_status_id][w.field_name] = w.rule + h + end + @statuses.each {|status| @permissions[status.id] ||= {}} + end + end + + def copy + + if params[:source_tracker_id].blank? || params[:source_tracker_id] == 'any' + @source_tracker = nil + else + @source_tracker = Tracker.find_by_id(params[:source_tracker_id].to_i) + end + if params[:source_role_id].blank? || params[:source_role_id] == 'any' + @source_role = nil + else + @source_role = Role.find_by_id(params[:source_role_id].to_i) + end + + @target_trackers = params[:target_tracker_ids].blank? ? nil : Tracker.find_all_by_id(params[:target_tracker_ids]) + @target_roles = params[:target_role_ids].blank? ? nil : Role.find_all_by_id(params[:target_role_ids]) + + if request.post? + if params[:source_tracker_id].blank? || params[:source_role_id].blank? || (@source_tracker.nil? && @source_role.nil?) + flash.now[:error] = l(:error_workflow_copy_source) + elsif @target_trackers.blank? || @target_roles.blank? + flash.now[:error] = l(:error_workflow_copy_target) + else + WorkflowRule.copy(@source_tracker, @source_role, @target_trackers, @target_roles) + flash[:notice] = l(:notice_successful_update) + redirect_to workflows_copy_path(:source_tracker_id => @source_tracker, :source_role_id => @source_role) + end + end + end + + private + + def find_roles + @roles = Role.sorted.all + end + + def find_trackers + @trackers = Tracker.sorted.all + end +end diff --git a/app/helpers/account_helper.rb b/app/helpers/account_helper.rb new file mode 100644 index 00000000..8beeac36 --- /dev/null +++ b/app/helpers/account_helper.rb @@ -0,0 +1,21 @@ +# encoding: utf-8 +# +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +module AccountHelper +end diff --git a/app/helpers/activities_helper.rb b/app/helpers/activities_helper.rb new file mode 100644 index 00000000..a5aa247d --- /dev/null +++ b/app/helpers/activities_helper.rb @@ -0,0 +1,33 @@ +# encoding: utf-8 +# +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +module ActivitiesHelper + def sort_activity_events(events) + events_by_group = events.group_by(&:event_group) + sorted_events = [] + events.sort {|x, y| y.event_datetime <=> x.event_datetime}.each do |event| + if group_events = events_by_group.delete(event.event_group) + group_events.sort {|x, y| y.event_datetime <=> x.event_datetime}.each_with_index do |e, i| + sorted_events << [e, i > 0] + end + end + end + sorted_events + end +end diff --git a/app/helpers/admin_helper.rb b/app/helpers/admin_helper.rb new file mode 100644 index 00000000..1f766afa --- /dev/null +++ b/app/helpers/admin_helper.rb @@ -0,0 +1,27 @@ +# encoding: utf-8 +# +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +module AdminHelper + def project_status_options_for_select(selected) + options_for_select([[l(:label_all), ''], + [l(:project_status_active), '1'], + [l(:project_status_closed), '5'], + [l(:project_status_archived), '9']], selected.to_s) + end +end diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb new file mode 100644 index 00000000..fedefeb7 --- /dev/null +++ b/app/helpers/application_helper.rb @@ -0,0 +1,1287 @@ +# encoding: utf-8 +# +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +require 'forwardable' +require 'cgi' + +module ApplicationHelper + include Redmine::WikiFormatting::Macros::Definitions + include Redmine::I18n + include GravatarHelper::PublicMethods + include Redmine::Pagination::Helper + include AvatarHelper + + extend Forwardable + def_delegators :wiki_helper, :wikitoolbar_for, :heads_for_wiki_formatter + + # Return true if user is authorized for controller/action, otherwise false + def authorize_for(controller, action) + User.current.allowed_to?({:controller => controller, :action => action}, @project) + end + + # Display a link if user is authorized + # + # @param [String] name Anchor text (passed to link_to) + # @param [Hash] options Hash params. This will checked by authorize_for to see if the user is authorized + # @param [optional, Hash] html_options Options passed to link_to + # @param [optional, Hash] parameters_for_method_reference Extra parameters for link_to + def link_to_if_authorized(name, options = {}, html_options = nil, *parameters_for_method_reference) + link_to(name, options, html_options, *parameters_for_method_reference) if authorize_for(options[:controller] || params[:controller], options[:action]) + end + + # Displays a link to user's account page if active + def link_to_user(user, options={}) + if user.is_a?(User) + name = h(user.name(options[:format])) + if user.active? || (User.current.admin? && user.logged?) + link_to name, user_path(user), :class => user.css_classes + else + name + end + else + h(user.to_s) + end + end + + # Displays a link to +issue+ with its subject. + # Examples: + # + # link_to_issue(issue) # => Defect #6: This is the subject + # link_to_issue(issue, :truncate => 6) # => Defect #6: This i... + # link_to_issue(issue, :subject => false) # => Defect #6 + # link_to_issue(issue, :project => true) # => Foo - Defect #6 + # link_to_issue(issue, :subject => false, :tracker => false) # => #6 + # + def link_to_issue(issue, options={}) + title = nil + subject = nil + text = options[:tracker] == false ? "##{issue.id}" : "#{issue.tracker} ##{issue.id}" + if options[:subject] == false + title = truncate(issue.subject, :length => 60) + else + subject = issue.subject + if options[:truncate] + subject = truncate(subject, :length => options[:truncate]) + end + end + s = link_to text, issue_path(issue), :class => issue.css_classes, :title => title + s << h(": #{subject}") if subject + s = h("#{issue.project} - ") + s if options[:project] + s + end + + # Generates a link to an attachment. + # Options: + # * :text - Link text (default to attachment filename) + # * :download - Force download (default: false) + def link_to_attachment(attachment, options={}) + text = options.delete(:text) || attachment.filename + route_method = options.delete(:download) ? :download_named_attachment_path : :named_attachment_path + html_options = options.slice!(:only_path) + url = send(route_method, attachment, attachment.filename, options) + link_to text, url, html_options + end + + # Generates a link to a SCM revision + # Options: + # * :text - Link text (default to the formatted revision) + def link_to_revision(revision, repository, options={}) + if repository.is_a?(Project) + repository = repository.repository + end + text = options.delete(:text) || format_revision(revision) + rev = revision.respond_to?(:identifier) ? revision.identifier : revision + link_to( + h(text), + {:controller => 'repositories', :action => 'revision', :id => repository.project, :repository_id => repository.identifier_param, :rev => rev}, + :title => l(:label_revision_id, format_revision(revision)) + ) + end + + # Generates a link to a message + def link_to_message(message, options={}, html_options = nil) + link_to( + truncate(message.subject, :length => 60), + board_message_path(message.board_id, message.parent_id || message.id, { + :r => (message.parent_id && message.id), + :anchor => (message.parent_id ? "message-#{message.id}" : nil) + }.merge(options)), + html_options + ) + end + + # Generates a link to a project if active + # Examples: + # + # link_to_project(project) # => link to the specified project overview + # link_to_project(project, {:only_path => false}, :class => "project") # => 3rd arg adds html options + # link_to_project(project, {}, :class => "project") # => html options with default url (project overview) + # + def link_to_project(project, options={}, html_options = nil) + if project.archived? + h(project.name) + elsif options.key?(:action) + ActiveSupport::Deprecation.warn "#link_to_project with :action option is deprecated and will be removed in Redmine 3.0." + url = {:controller => 'projects', :action => 'show', :id => project}.merge(options) + link_to project.name, url, html_options + else + link_to project.name, project_path(project, options), html_options + end + end + + # Generates a link to a project settings if active + def link_to_project_settings(project, options={}, html_options=nil) + if project.active? + link_to project.name, settings_project_path(project, options), html_options + elsif project.archived? + h(project.name) + else + link_to project.name, project_path(project, options), html_options + end + end + + def wiki_page_path(page, options={}) + url_for({:controller => 'wiki', :action => 'show', :project_id => page.project, :id => page.title}.merge(options)) + end + + def thumbnail_tag(attachment) + link_to image_tag(thumbnail_path(attachment)), + named_attachment_path(attachment, attachment.filename), + :title => attachment.filename + end + + def toggle_link(name, id, options={}) + onclick = "$('##{id}').toggle(); " + onclick << (options[:focus] ? "$('##{options[:focus]}').focus(); " : "this.blur(); ") + onclick << "return false;" + link_to(name, "#", :onclick => onclick) + end + + def image_to_function(name, function, html_options = {}) + html_options.symbolize_keys! + tag(:input, html_options.merge({ + :type => "image", :src => image_path(name), + :onclick => (html_options[:onclick] ? "#{html_options[:onclick]}; " : "") + "#{function};" + })) + end + + def format_activity_title(text) + h(truncate_single_line(text, :length => 100)) + end + + def format_activity_day(date) + date == User.current.today ? l(:label_today).titleize : format_date(date) + end + + def format_activity_description(text) + h(truncate(text.to_s, :length => 120).gsub(%r{[\r\n]*<(pre|code)>.*$}m, '...') + ).gsub(/[\r\n]+/, "
").html_safe + end + + def format_version_name(version) + if version.project == @project + h(version) + else + h("#{version.project} - #{version}") + end + end + + def due_date_distance_in_words(date) + if date + l((date < Date.today ? :label_roadmap_overdue : :label_roadmap_due_in), distance_of_date_in_words(Date.today, date)) + end + end + + # Renders a tree of projects as a nested set of unordered lists + # The given collection may be a subset of the whole project tree + # (eg. some intermediate nodes are private and can not be seen) + #Modified by nie. + def render_project_nested_lists(projects) + s = '' + if projects.any? + ancestors = [] + original_project = @project + projects.sort_by(&:lft).each do |project| + # set the project environment to please macros. + @project = project + if (ancestors.empty? || project.is_descendant_of?(ancestors.last)) +# s << "\n" * ancestors.size) + @project = original_project + end + s.html_safe + end + #added by young + def render_project_nested_lists_new(projects) + s = '' + if projects.any? + ancestors = [] + original_project = @project + projects.sort_by(&:lft).each do |project| + # set the project environment to please macros. + @project = project + if (ancestors.empty? || project.is_descendant_of?(ancestors.last)) +# s << "\n" * ancestors.size) + @project = original_project + end + s.html_safe + end + #end + def render_page_hierarchy(pages, node=nil, options={}) + content = '' + if pages[node] + content << "\n" + end + content.html_safe + end + + # Renders flash messages + def render_flash_messages + s = '' + flash.each do |k,v| + s << content_tag('div', v.html_safe, :class => "flash #{k}", :id => "flash_#{k}") + end + s.html_safe + end + + # Renders tabs and their content + def render_tabs(tabs) + if tabs.any? + render :partial => 'common/tabs', :locals => {:tabs => tabs} + else + content_tag 'p', l(:label_no_data), :class => "nodata" + end + end + + # Renders the project quick-jump box + def render_project_jump_box + return unless User.current.logged? + projects = User.current.memberships.collect(&:project).compact.select(&:active?).uniq + if projects.any? + options = + ("" + + '').html_safe + + options << project_tree_options_for_select(projects, :selected => @project) do |p| + { :value => project_path(:id => p, :jump => current_menu_item) } + end + + select_tag('project_quick_jump_box', options, :onchange => 'if (this.value != \'\') { window.location = this.value; }') + end + end + + def project_tree_options_for_select(projects, options = {}) + s = '' + project_tree(projects) do |project, level| + name_prefix = (level > 0 ? ' ' * 2 * level + '» ' : '').html_safe + tag_options = {:value => project.id} + if project == options[:selected] || (options[:selected].respond_to?(:include?) && options[:selected].include?(project)) + tag_options[:selected] = 'selected' + else + tag_options[:selected] = nil + end + tag_options.merge!(yield(project)) if block_given? + s << content_tag('option', name_prefix + h(project), tag_options) + end + s.html_safe + end + + # Yields the given block for each project with its level in the tree + # + # Wrapper for Project#project_tree + def project_tree(projects, &block) + Project.project_tree(projects, &block) + end + + def principals_check_box_tags(name, principals) + s = '' + principals.each do |principal| + s << "\n" + end + s.html_safe + end + + # Returns a string for users/groups option tags + def principals_options_for_select(collection, selected=nil) + s = '' + if collection.include?(User.current) + s << content_tag('option', "<< #{l(:label_me)} >>", :value => User.current.id) + end + groups = '' + collection.sort.each do |element| + selected_attribute = ' selected="selected"' if option_value_selected?(element, selected) + (element.is_a?(Group) ? groups : s) << %() + end + unless groups.empty? + s << %(#{groups}) + end + s.html_safe + end + + # Options for the new membership projects combo-box + def options_for_membership_project_select(principal, projects) + options = content_tag('option', "--- #{l(:actionview_instancetag_blank_option)} ---") + options << project_tree_options_for_select(projects) do |p| + {:disabled => principal.projects.to_a.include?(p)} + end + options + end + + # Truncates and returns the string as a single line + def truncate_single_line(string, *args) + truncate(string.to_s, *args).gsub(%r{[\r\n]+}m, ' ') + end + + # Truncates at line break after 250 characters or options[:length] + def truncate_lines(string, options={}) + length = options[:length] || 250 + if string.to_s =~ /\A(.{#{length}}.*?)$/m + "#{$1}..." + else + string + end + end + + def anchor(text) + text.to_s.gsub(' ', '_') + end + + def html_hours(text) + text.gsub(%r{(\d+)\.(\d+)}, '\1.\2').html_safe + end + + def authoring(created, author, options={}) + l(options[:label] || :label_added_time_by, :author => link_to_user(author), :age => time_tag(created)).html_safe + end + + def time_tag(time) + text = distance_of_time_in_words(Time.now, time) + if @project + link_to(text, {:controller => 'activities', :action => 'index', :id => @project, :from => User.current.time_to_date(time)}, :title => format_time(time)) + else + content_tag('acronym', text, :title => format_time(time)) + end + end + + def syntax_highlight_lines(name, content) + lines = [] + syntax_highlight(name, content).each_line { |line| lines << line } + lines + end + + def syntax_highlight(name, content) + Redmine::SyntaxHighlighting.highlight_by_filename(content, name) + end + + def to_path_param(path) + str = path.to_s.split(%r{[/\\]}).select{|p| !p.blank?}.join("/") + str.blank? ? nil : str + end + + def reorder_links(name, url, method = :post) + link_to(image_tag('2uparrow.png', :alt => l(:label_sort_highest)), + url.merge({"#{name}[move_to]" => 'highest'}), + :method => method, :title => l(:label_sort_highest)) + + link_to(image_tag('1uparrow.png', :alt => l(:label_sort_higher)), + url.merge({"#{name}[move_to]" => 'higher'}), + :method => method, :title => l(:label_sort_higher)) + + link_to(image_tag('1downarrow.png', :alt => l(:label_sort_lower)), + url.merge({"#{name}[move_to]" => 'lower'}), + :method => method, :title => l(:label_sort_lower)) + + link_to(image_tag('2downarrow.png', :alt => l(:label_sort_lowest)), + url.merge({"#{name}[move_to]" => 'lowest'}), + :method => method, :title => l(:label_sort_lowest)) + end + + def breadcrumb(*args) + elements = args.flatten + elements.any? ? content_tag('p', (args.join(" \xc2\xbb ") + " \xc2\xbb ").html_safe, :class => 'breadcrumb') : nil + end + + def other_formats_links(&block) + concat('

'.html_safe + l(:label_export_to)) + yield Redmine::Views::OtherFormatsBuilder.new(self) + concat('

'.html_safe) + end + + def page_header_title + if @project.nil? || @project.new_record? + h(Setting.app_title) + else + b = [] + ancestors = (@project.root? ? [] : @project.ancestors.visible.all) + if ancestors.any? + root = ancestors.shift + b << link_to_project(root, {:jump => current_menu_item}, :class => 'root') + if ancestors.size > 2 + b << "\xe2\x80\xa6" + ancestors = ancestors[-2, 2] + end + b += ancestors.collect {|p| link_to_project(p, {:jump => current_menu_item}, :class => 'ancestor') } + end + b << h(@project) + b.join(" \xc2\xbb ").html_safe + end + end + + def html_title(*args) + if args.empty? + title = @html_title || [] + title << @project.name if @project + title << Setting.app_title unless Setting.app_title == title.last + title.select {|t| !t.blank? }.join(' - ') + else + @html_title ||= [] + @html_title += args + end + end + + # Returns the theme, controller name, and action as css classes for the + # HTML body. + def body_css_classes + css = [] + if theme = Redmine::Themes.theme(Setting.ui_theme) + css << 'theme-' + theme.name + end + + css << 'controller-' + controller_name + css << 'action-' + action_name + css.join(' ') + end + + def accesskey(s) + @used_accesskeys ||= [] + key = Redmine::AccessKeys.key_for(s) + return nil if @used_accesskeys.include?(key) + @used_accesskeys << key + key + end + + # Formats text according to system settings. + # 2 ways to call this method: + # * with a String: textilizable(text, options) + # * with an object and one of its attribute: textilizable(issue, :description, options) + def textilizable(*args) + options = args.last.is_a?(Hash) ? args.pop : {} + case args.size + when 1 + obj = options[:object] + text = args.shift + when 2 + obj = args.shift + attr = args.shift + text = obj.send(attr).to_s + else + raise ArgumentError, 'invalid arguments to textilizable' + end + return '' if text.blank? + project = options[:project] || @project || (obj && obj.respond_to?(:project) ? obj.project : nil) + only_path = options.delete(:only_path) == false ? false : true + + text = text.dup + macros = catch_macros(text) + text = Redmine::WikiFormatting.to_html(Setting.text_formatting, text, :object => obj, :attribute => attr) + + @parsed_headings = [] + @heading_anchors = {} + @current_section = 0 if options[:edit_section_links] + + parse_sections(text, project, obj, attr, only_path, options) + text = parse_non_pre_blocks(text, obj, macros) do |text| + [:parse_inline_attachments, :parse_wiki_links, :parse_redmine_links].each do |method_name| + send method_name, text, project, obj, attr, only_path, options + end + end + parse_headings(text, project, obj, attr, only_path, options) + + if @parsed_headings.any? + replace_toc(text, @parsed_headings) + end + + text.html_safe + end + + def parse_non_pre_blocks(text, obj, macros) + s = StringScanner.new(text) + tags = [] + parsed = '' + while !s.eos? + s.scan(/(.*?)(<(\/)?(pre|code)(.*?)>|\z)/im) + text, full_tag, closing, tag = s[1], s[2], s[3], s[4] + if tags.empty? + yield text + inject_macros(text, obj, macros) if macros.any? + else + inject_macros(text, obj, macros, false) if macros.any? + end + parsed << text + if tag + if closing + if tags.last == tag.downcase + tags.pop + end + else + tags << tag.downcase + end + parsed << full_tag + end + end + # Close any non closing tags + while tag = tags.pop + parsed << "" + end + parsed + end + + def parse_inline_attachments(text, project, obj, attr, only_path, options) + # when using an image link, try to use an attachment, if possible + attachments = options[:attachments] || [] + attachments += obj.attachments if obj.respond_to?(:attachments) + if attachments.present? + text.gsub!(/src="([^\/"]+\.(bmp|gif|jpg|jpe|jpeg|png))"(\s+alt="([^"]*)")?/i) do |m| + filename, ext, alt, alttext = $1.downcase, $2, $3, $4 + # search for the picture in attachments + if found = Attachment.latest_attach(attachments, filename) + image_url = download_named_attachment_path(found, found.filename, :only_path => only_path) + desc = found.description.to_s.gsub('"', '') + if !desc.blank? && alttext.blank? + alt = " title=\"#{desc}\" alt=\"#{desc}\"" + end + "src=\"#{image_url}\"#{alt}" + else + m + end + end + end + end + + # Wiki links + # + # Examples: + # [[mypage]] + # [[mypage|mytext]] + # wiki links can refer other project wikis, using project name or identifier: + # [[project:]] -> wiki starting page + # [[project:|mytext]] + # [[project:mypage]] + # [[project:mypage|mytext]] + def parse_wiki_links(text, project, obj, attr, only_path, options) + text.gsub!(/(!)?(\[\[([^\]\n\|]+)(\|([^\]\n\|]+))?\]\])/) do |m| + link_project = project + esc, all, page, title = $1, $2, $3, $5 + if esc.nil? + if page =~ /^([^\:]+)\:(.*)$/ + identifier, page = $1, $2 + link_project = Project.find_by_identifier(identifier) || Project.find_by_name(identifier) + title ||= identifier if page.blank? + end + + if link_project && link_project.wiki + # extract anchor + anchor = nil + if page =~ /^(.+?)\#(.+)$/ + page, anchor = $1, $2 + end + anchor = sanitize_anchor_name(anchor) if anchor.present? + # check if page exists + wiki_page = link_project.wiki.find_page(page) + url = if anchor.present? && wiki_page.present? && (obj.is_a?(WikiContent) || obj.is_a?(WikiContent::Version)) && obj.page == wiki_page + "##{anchor}" + else + case options[:wiki_links] + when :local; "#{page.present? ? Wiki.titleize(page) : ''}.html" + (anchor.present? ? "##{anchor}" : '') + when :anchor; "##{page.present? ? Wiki.titleize(page) : title}" + (anchor.present? ? "_#{anchor}" : '') # used for single-file wiki export + else + wiki_page_id = page.present? ? Wiki.titleize(page) : nil + parent = wiki_page.nil? && obj.is_a?(WikiContent) && obj.page && project == link_project ? obj.page.title : nil + url_for(:only_path => only_path, :controller => 'wiki', :action => 'show', :project_id => link_project, + :id => wiki_page_id, :version => nil, :anchor => anchor, :parent => parent) + end + end + link_to(title.present? ? title.html_safe : h(page), url, :class => ('wiki-page' + (wiki_page ? '' : ' new'))) + else + # project or wiki doesn't exist + all + end + else + all + end + end + end + + # Redmine links + # + # Examples: + # Issues: + # #52 -> Link to issue #52 + # Changesets: + # r52 -> Link to revision 52 + # commit:a85130f -> Link to scmid starting with a85130f + # Documents: + # document#17 -> Link to document with id 17 + # document:Greetings -> Link to the document with title "Greetings" + # document:"Some document" -> Link to the document with title "Some document" + # Versions: + # version#3 -> Link to version with id 3 + # version:1.0.0 -> Link to version named "1.0.0" + # version:"1.0 beta 2" -> Link to version named "1.0 beta 2" + # Attachments: + # attachment:file.zip -> Link to the attachment of the current object named file.zip + # Source files: + # source:some/file -> Link to the file located at /some/file in the project's repository + # source:some/file@52 -> Link to the file's revision 52 + # source:some/file#L120 -> Link to line 120 of the file + # source:some/file@52#L120 -> Link to line 120 of the file's revision 52 + # export:some/file -> Force the download of the file + # Forum messages: + # message#1218 -> Link to message with id 1218 + # + # Links can refer other objects from other projects, using project identifier: + # identifier:r52 + # identifier:document:"Some document" + # identifier:version:1.0.0 + # identifier:source:some/file + def parse_redmine_links(text, default_project, obj, attr, only_path, options) + text.gsub!(%r{([\s\(,\-\[\>]|^)(!)?(([a-z0-9\-_]+):)?(attachment|document|version|forum|news|message|project|commit|source|export)?(((#)|((([a-z0-9\-_]+)\|)?(r)))((\d+)((#note)?-(\d+))?)|(:)([^"\s<>][^\s<>]*?|"[^"]+?"))(?=(?=[[:punct:]][^A-Za-z0-9_/])|,|\s|\]|<|$)}) do |m| + leading, esc, project_prefix, project_identifier, prefix, repo_prefix, repo_identifier, sep, identifier, comment_suffix, comment_id = $1, $2, $3, $4, $5, $10, $11, $8 || $12 || $18, $14 || $19, $15, $17 + link = nil + project = default_project + if project_identifier + project = Project.visible.find_by_identifier(project_identifier) + end + if esc.nil? + if prefix.nil? && sep == 'r' + if project + repository = nil + if repo_identifier + repository = project.repositories.detect {|repo| repo.identifier == repo_identifier} + else + repository = project.repository + end + # project.changesets.visible raises an SQL error because of a double join on repositories + if repository && (changeset = Changeset.visible.find_by_repository_id_and_revision(repository.id, identifier)) + link = link_to(h("#{project_prefix}#{repo_prefix}r#{identifier}"), {:only_path => only_path, :controller => 'repositories', :action => 'revision', :id => project, :repository_id => repository.identifier_param, :rev => changeset.revision}, + :class => 'changeset', + :title => truncate_single_line(changeset.comments, :length => 100)) + end + end + elsif sep == '#' + oid = identifier.to_i + case prefix + when nil + if oid.to_s == identifier && issue = Issue.visible.find_by_id(oid, :include => :status) + anchor = comment_id ? "note-#{comment_id}" : nil + link = link_to("##{oid}", {:only_path => only_path, :controller => 'issues', :action => 'show', :id => oid, :anchor => anchor}, + :class => issue.css_classes, + :title => "#{truncate(issue.subject, :length => 100)} (#{issue.status.name})") + end + when 'document' + if document = Document.visible.find_by_id(oid) + link = link_to h(document.title), {:only_path => only_path, :controller => 'documents', :action => 'show', :id => document}, + :class => 'document' + end + when 'version' + if version = Version.visible.find_by_id(oid) + link = link_to h(version.name), {:only_path => only_path, :controller => 'versions', :action => 'show', :id => version}, + :class => 'version' + end + when 'message' + if message = Message.visible.find_by_id(oid, :include => :parent) + link = link_to_message(message, {:only_path => only_path}, :class => 'message') + end + when 'forum' + if board = Board.visible.find_by_id(oid) + link = link_to h(board.name), {:only_path => only_path, :controller => 'boards', :action => 'show', :id => board, :project_id => board.project}, + :class => 'board' + end + when 'news' + if news = News.visible.find_by_id(oid) + link = link_to h(news.title), {:only_path => only_path, :controller => 'news', :action => 'show', :id => news}, + :class => 'news' + end + when 'project' + if p = Project.visible.find_by_id(oid) + link = link_to_project(p, {:only_path => only_path}, :class => 'project') + end + end + elsif sep == ':' + # removes the double quotes if any + name = identifier.gsub(%r{^"(.*)"$}, "\\1") + case prefix + when 'document' + if project && document = project.documents.visible.find_by_title(name) + link = link_to h(document.title), {:only_path => only_path, :controller => 'documents', :action => 'show', :id => document}, + :class => 'document' + end + when 'version' + if project && version = project.versions.visible.find_by_name(name) + link = link_to h(version.name), {:only_path => only_path, :controller => 'versions', :action => 'show', :id => version}, + :class => 'version' + end + when 'forum' + if project && board = project.boards.visible.find_by_name(name) + link = link_to h(board.name), {:only_path => only_path, :controller => 'boards', :action => 'show', :id => board, :project_id => board.project}, + :class => 'board' + end + when 'news' + if project && news = project.news.visible.find_by_title(name) + link = link_to h(news.title), {:only_path => only_path, :controller => 'news', :action => 'show', :id => news}, + :class => 'news' + end + when 'commit', 'source', 'export' + if project + repository = nil + if name =~ %r{^(([a-z0-9\-_]+)\|)(.+)$} + repo_prefix, repo_identifier, name = $1, $2, $3 + repository = project.repositories.detect {|repo| repo.identifier == repo_identifier} + else + repository = project.repository + end + if prefix == 'commit' + if repository && (changeset = Changeset.visible.where("repository_id = ? AND scmid LIKE ?", repository.id, "#{name}%").first) + link = link_to h("#{project_prefix}#{repo_prefix}#{name}"), {:only_path => only_path, :controller => 'repositories', :action => 'revision', :id => project, :repository_id => repository.identifier_param, :rev => changeset.identifier}, + :class => 'changeset', + :title => truncate_single_line(changeset.comments, :length => 100) + end + else + if repository && User.current.allowed_to?(:browse_repository, project) + name =~ %r{^[/\\]*(.*?)(@([^/\\@]+?))?(#(L\d+))?$} + path, rev, anchor = $1, $3, $5 + link = link_to h("#{project_prefix}#{prefix}:#{repo_prefix}#{name}"), {:controller => 'repositories', :action => (prefix == 'export' ? 'raw' : 'entry'), :id => project, :repository_id => repository.identifier_param, + :path => to_path_param(path), + :rev => rev, + :anchor => anchor}, + :class => (prefix == 'export' ? 'source download' : 'source') + end + end + repo_prefix = nil + end + when 'attachment' + attachments = options[:attachments] || (obj && obj.respond_to?(:attachments) ? obj.attachments : nil) + if attachments && attachment = Attachment.latest_attach(attachments, name) + link = link_to_attachment(attachment, :only_path => only_path, :download => true, :class => 'attachment') + end + when 'project' + if p = Project.visible.where("identifier = :s OR LOWER(name) = :s", :s => name.downcase).first + link = link_to_project(p, {:only_path => only_path}, :class => 'project') + end + end + end + end + (leading + (link || "#{project_prefix}#{prefix}#{repo_prefix}#{sep}#{identifier}#{comment_suffix}")) + end + end + + HEADING_RE = /(]+)?>(.+?)<\/h(\d)>)/i unless const_defined?(:HEADING_RE) + + def parse_sections(text, project, obj, attr, only_path, options) + return unless options[:edit_section_links] + text.gsub!(HEADING_RE) do + heading = $1 + @current_section += 1 + if @current_section > 1 + content_tag('div', + link_to(image_tag('edit.png'), options[:edit_section_links].merge(:section => @current_section)), + :class => 'contextual', + :title => l(:button_edit_section)) + heading.html_safe + else + heading + end + end + end + + # Headings and TOC + # Adds ids and links to headings unless options[:headings] is set to false + def parse_headings(text, project, obj, attr, only_path, options) + return if options[:headings] == false + + text.gsub!(HEADING_RE) do + level, attrs, content = $2.to_i, $3, $4 + item = strip_tags(content).strip + anchor = sanitize_anchor_name(item) + # used for single-file wiki export + anchor = "#{obj.page.title}_#{anchor}" if options[:wiki_links] == :anchor && (obj.is_a?(WikiContent) || obj.is_a?(WikiContent::Version)) + @heading_anchors[anchor] ||= 0 + idx = (@heading_anchors[anchor] += 1) + if idx > 1 + anchor = "#{anchor}-#{idx}" + end + @parsed_headings << [level, anchor, item] + "\n#{content}" + end + end + + MACROS_RE = /( + (!)? # escaping + ( + \{\{ # opening tag + ([\w]+) # macro name + (\(([^\n\r]*?)\))? # optional arguments + ([\n\r].*?[\n\r])? # optional block of text + \}\} # closing tag + ) + )/mx unless const_defined?(:MACROS_RE) + + MACRO_SUB_RE = /( + \{\{ + macro\((\d+)\) + \}\} + )/x unless const_defined?(:MACRO_SUB_RE) + + # Extracts macros from text + def catch_macros(text) + macros = {} + text.gsub!(MACROS_RE) do + all, macro = $1, $4.downcase + if macro_exists?(macro) || all =~ MACRO_SUB_RE + index = macros.size + macros[index] = all + "{{macro(#{index})}}" + else + all + end + end + macros + end + + # Executes and replaces macros in text + def inject_macros(text, obj, macros, execute=true) + text.gsub!(MACRO_SUB_RE) do + all, index = $1, $2.to_i + orig = macros.delete(index) + if execute && orig && orig =~ MACROS_RE + esc, all, macro, args, block = $2, $3, $4.downcase, $6.to_s, $7.try(:strip) + if esc.nil? + h(exec_macro(macro, obj, args, block) || all) + else + h(all) + end + elsif orig + h(orig) + else + h(all) + end + end + end + + TOC_RE = /

\{\{([<>]?)toc\}\}<\/p>/i unless const_defined?(:TOC_RE) + + # Renders the TOC with given headings + def replace_toc(text, headings) + text.gsub!(TOC_RE) do + # Keep only the 4 first levels + headings = headings.select{|level, anchor, item| level <= 4} + if headings.empty? + '' + else + div_class = 'toc' + div_class << ' right' if $1 == '>' + div_class << ' left' if $1 == '<' + out = "

' * (current - root) + out << '' + end + end + end + + # Same as Rails' simple_format helper without using paragraphs + def simple_format_without_paragraph(text) + text.to_s. + gsub(/\r\n?/, "\n"). # \r\n and \r -> \n + gsub(/\n\n+/, "

"). # 2+ newline -> 2 br + gsub(/([^\n]\n)(?=[^\n])/, '\1
'). # 1 newline -> br + html_safe + end + + def lang_options_for_select(blank=true) + (blank ? [["(auto)", ""]] : []) + languages_options + end + + def label_tag_for(name, option_tags = nil, options = {}) + label_text = l(("field_"+field.to_s.gsub(/\_id$/, "")).to_sym) + (options.delete(:required) ? @template.content_tag("span", " *", :class => "required"): "") + content_tag("label", label_text) + end + + def labelled_form_for(*args, &proc) + args << {} unless args.last.is_a?(Hash) + options = args.last + if args.first.is_a?(Symbol) + options.merge!(:as => args.shift) + end + options.merge!({:builder => Redmine::Views::LabelledFormBuilder}) + form_for(*args, &proc) + end + + def labelled_fields_for(*args, &proc) + args << {} unless args.last.is_a?(Hash) + options = args.last + options.merge!({:builder => Redmine::Views::LabelledFormBuilder}) + fields_for(*args, &proc) + end + + def labelled_remote_form_for(*args, &proc) + ActiveSupport::Deprecation.warn "ApplicationHelper#labelled_remote_form_for is deprecated and will be removed in Redmine 2.2." + args << {} unless args.last.is_a?(Hash) + options = args.last + options.merge!({:builder => Redmine::Views::LabelledFormBuilder, :remote => true}) + form_for(*args, &proc) + end + + def error_messages_for(*objects) + html = "" + objects = objects.map {|o| o.is_a?(String) ? instance_variable_get("@#{o}") : o}.compact + errors = objects.map {|o| o.errors.full_messages}.flatten + if errors.any? + html << "
    \n" + errors.each do |error| + html << "
  • #{h error}
  • \n" + end + html << "
\n" + end + html.html_safe + end + + def delete_link(url, options={}) + options = { + :method => :delete, + :data => {:confirm => l(:text_are_you_sure)}, + :class => 'icon icon-del' + }.merge(options) + + link_to l(:button_delete), url, options + end + + def preview_link(url, form, target='preview', options={}) + content_tag 'a', l(:label_preview), { + :href => "#", + :onclick => %|submitPreview("#{escape_javascript url_for(url)}", "#{escape_javascript form}", "#{escape_javascript target}"); return false;|, + :accesskey => accesskey(:preview) + }.merge(options) + end + + def link_to_function(name, function, html_options={}) + content_tag(:a, name, {:href => '#', :onclick => "#{function}; return false;"}.merge(html_options)) + end + + # Helper to render JSON in views + def raw_json(arg) + arg.to_json.to_s.gsub('/', '\/').html_safe + end + + def back_url + url = params[:back_url] + if url.nil? && referer = request.env['HTTP_REFERER'] + url = CGI.unescape(referer.to_s) + end + url + end + + def back_url_hidden_field_tag + url = back_url + hidden_field_tag('back_url', url, :id => nil) unless url.blank? + end + + def check_all_links(form_name) + link_to_function(l(:button_check_all), "checkAll('#{form_name}', true)") + + " | ".html_safe + + link_to_function(l(:button_uncheck_all), "checkAll('#{form_name}', false)") + end + + def progress_bar(pcts, options={}) + pcts = [pcts, pcts] unless pcts.is_a?(Array) + pcts = pcts.collect(&:round) + pcts[1] = pcts[1] - pcts[0] + pcts << (100 - pcts[1] - pcts[0]) + width = options[:width] || '100px;' + legend = options[:legend] || '' + content_tag('table', + content_tag('tr', + (pcts[0] > 0 ? content_tag('td', '', :style => "width: #{pcts[0]}%;", :class => 'closed') : ''.html_safe) + + (pcts[1] > 0 ? content_tag('td', '', :style => "width: #{pcts[1]}%;", :class => 'done') : ''.html_safe) + + (pcts[2] > 0 ? content_tag('td', '', :style => "width: #{pcts[2]}%;", :class => 'todo') : ''.html_safe) + ), :class => 'progress', :style => "width: #{width};").html_safe + + content_tag('p', legend, :class => 'percent').html_safe + end + + def checked_image(checked=true) + if checked + image_tag 'toggle_check.png' + end + end + + def context_menu(url) + unless @context_menu_included + content_for :header_tags do + javascript_include_tag('context_menu') + + stylesheet_link_tag('context_menu') + end + if l(:direction) == 'rtl' + content_for :header_tags do + stylesheet_link_tag('context_menu_rtl') + end + end + @context_menu_included = true + end + javascript_tag "contextMenuInit('#{ url_for(url) }')" + end + + def calendar_for(field_id) + include_calendar_headers_tags + javascript_tag("$(function() { $('##{field_id}').datepicker(datepickerOptions); });") + end + + def include_calendar_headers_tags + unless @calendar_headers_tags_included + @calendar_headers_tags_included = true + content_for :header_tags do + start_of_week = Setting.start_of_week + start_of_week = l(:general_first_day_of_week, :default => '1') if start_of_week.blank? + # Redmine uses 1..7 (monday..sunday) in settings and locales + # JQuery uses 0..6 (sunday..saturday), 7 needs to be changed to 0 + start_of_week = start_of_week.to_i % 7 + + tags = javascript_tag( + "var datepickerOptions={dateFormat: 'yy-mm-dd', firstDay: #{start_of_week}, " + + "showOn: 'button', buttonImageOnly: true, buttonImage: '" + + path_to_image('/images/calendar.png') + + "', showButtonPanel: true, showWeek: true, showOtherMonths: true, selectOtherMonths: true};") + jquery_locale = l('jquery.locale', :default => current_language.to_s) + unless jquery_locale == 'en' + tags << javascript_include_tag("i18n/jquery.ui.datepicker-#{jquery_locale}.js") + end + tags + end + end + end + + # Overrides Rails' stylesheet_link_tag with themes and plugins support. + # Examples: + # stylesheet_link_tag('styles') # => picks styles.css from the current theme or defaults + # stylesheet_link_tag('styles', :plugin => 'foo) # => picks styles.css from plugin's assets + # + def stylesheet_link_tag(*sources) + options = sources.last.is_a?(Hash) ? sources.pop : {} + plugin = options.delete(:plugin) + sources = sources.map do |source| + if plugin + "/plugin_assets/#{plugin}/stylesheets/#{source}" + elsif current_theme && current_theme.stylesheets.include?(source) + current_theme.stylesheet_path(source) + else + source + end + end + super sources, options + end + + # Overrides Rails' image_tag with themes and plugins support. + # Examples: + # image_tag('image.png') # => picks image.png from the current theme or defaults + # image_tag('image.png', :plugin => 'foo) # => picks image.png from plugin's assets + # + def image_tag(source, options={}) + if plugin = options.delete(:plugin) + source = "/plugin_assets/#{plugin}/images/#{source}" + elsif current_theme && current_theme.images.include?(source) + source = current_theme.image_path(source) + end + super source, options + end + + # Overrides Rails' javascript_include_tag with plugins support + # Examples: + # javascript_include_tag('scripts') # => picks scripts.js from defaults + # javascript_include_tag('scripts', :plugin => 'foo) # => picks scripts.js from plugin's assets + # + def javascript_include_tag(*sources) + options = sources.last.is_a?(Hash) ? sources.pop : {} + if plugin = options.delete(:plugin) + sources = sources.map do |source| + if plugin + "/plugin_assets/#{plugin}/javascripts/#{source}" + else + source + end + end + end + super sources, options + end + + def content_for(name, content = nil, &block) + @has_content ||= {} + @has_content[name] = true + super(name, content, &block) + end + + def has_content?(name) + (@has_content && @has_content[name]) || false + end + + def sidebar_content? + has_content?(:sidebar) || view_layouts_base_sidebar_hook_response.present? + end + + def view_layouts_base_sidebar_hook_response + @view_layouts_base_sidebar_hook_response ||= call_hook(:view_layouts_base_sidebar) + end + + def email_delivery_enabled? + !!ActionMailer::Base.perform_deliveries + end + + # Returns the avatar image tag for the given +user+ if avatars are enabled + # +user+ can be a User or a string that will be scanned for an email address (eg. 'joe ') + def avatar(user, options = { }) + if Setting.gravatar_enabled? + options.merge!({:ssl => (request && request.ssl?), :default => Setting.gravatar_default}) + email = nil + if user.respond_to?(:mail) + email = user.mail + elsif user.to_s =~ %r{<(.+?)>} + email = $1 + end + return gravatar(email.to_s.downcase, options) unless email.blank? rescue nil + else + '' + end + end + + def sanitize_anchor_name(anchor) + if ''.respond_to?(:encoding) || RUBY_PLATFORM == 'java' + anchor.gsub(%r{[^\s\-\p{Word}]}, '').gsub(%r{\s+(\-+\s*)?}, '-') + else + # TODO: remove when ruby1.8 is no longer supported + anchor.gsub(%r{[^\w\s\-]}, '').gsub(%r{\s+(\-+\s*)?}, '-') + end + end + + # Returns the javascript tags that are included in the html layout head + def javascript_heads + tags = javascript_include_tag('jquery-1.8.3-ui-1.9.2-ujs-2.0.3', 'application') + unless User.current.pref.warn_on_leaving_unsaved == '0' + tags << "\n".html_safe + javascript_tag("$(window).load(function(){ warnLeavingUnsaved('#{escape_javascript l(:text_warn_on_leaving_unsaved)}'); });") + end + tags + end + + def favicon + "".html_safe + end + + def robot_exclusion_tag + ''.html_safe + end + + # Returns true if arg is expected in the API response + def include_in_api_response?(arg) + unless @included_in_api_response + param = params[:include] + @included_in_api_response = param.is_a?(Array) ? param.collect(&:to_s) : param.to_s.split(',') + @included_in_api_response.collect!(&:strip) + end + @included_in_api_response.include?(arg.to_s) + end + + # Returns options or nil if nometa param or X-Redmine-Nometa header + # was set in the request + def api_meta(options) + if params[:nometa].present? || request.headers['X-Redmine-Nometa'] + # compatibility mode for activeresource clients that raise + # an error when unserializing an array with attributes + nil + else + options + end + end + + # Add by Tao + def url_to_avatar(source) + get_avatar(source) + end + # Endof Tao's code + + def date_format_local(time) + date = time.strftime("%Y年%m月%d日") + end + + private + + def wiki_helper + helper = Redmine::WikiFormatting.helper_for(Setting.text_formatting) + extend helper + return self + end + + def link_to_content_update(text, url_params = {}, html_options = {}) + link_to(text, url_params, html_options) + end +end diff --git a/app/helpers/attachments_helper.rb b/app/helpers/attachments_helper.rb new file mode 100644 index 00000000..a4925343 --- /dev/null +++ b/app/helpers/attachments_helper.rb @@ -0,0 +1,47 @@ +# encoding: utf-8 +# +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +module AttachmentsHelper + # Displays view/delete links to the attachments of the given object + # Options: + # :author -- author names are not displayed if set to false + # :thumbails -- display thumbnails if enabled in settings + def link_to_attachments(container, options = {}) + options.assert_valid_keys(:author, :thumbnails) + + if container.attachments.any? + options = {:deletable => container.attachments_deletable?, :author => true}.merge(options) + render :partial => 'attachments/links', + :locals => {:attachments => container.attachments, :options => options, :thumbnails => (options[:thumbnails] && Setting.thumbnails_enabled?)} + end + end + + def render_api_attachment(attachment, api) + api.attachment do + api.id attachment.id + api.filename attachment.filename + api.filesize attachment.filesize + api.content_type attachment.content_type + api.description attachment.description + api.content_url url_for(:controller => 'attachments', :action => 'download', :id => attachment, :filename => attachment.filename, :only_path => false) + api.author(:id => attachment.author.id, :name => attachment.author.name) if attachment.author + api.created_on attachment.created_on + end + end +end diff --git a/app/helpers/auth_sources_helper.rb b/app/helpers/auth_sources_helper.rb new file mode 100644 index 00000000..2fa87d5c --- /dev/null +++ b/app/helpers/auth_sources_helper.rb @@ -0,0 +1,24 @@ +# encoding: utf-8 +# +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +module AuthSourcesHelper + def auth_source_partial_name(auth_source) + "form_#{auth_source.class.name.underscore}" + end +end diff --git a/app/helpers/avatar_helper.rb b/app/helpers/avatar_helper.rb new file mode 100644 index 00000000..c17ccadf --- /dev/null +++ b/app/helpers/avatar_helper.rb @@ -0,0 +1,52 @@ +module AvatarHelper + + AVATAR_SIZE="50x50" + + def avatar_image(source) + File.join(relative_path, avatar_directory(source.class), source.id.to_s) + end + + def relative_path + "avatars" #File.join("images","avatars") + end + + def storage_path + File.join(Rails.root, "public", "images", relative_path) + end + + def avatar_directory(source_type) + "#{source_type}" + end + + def avatar_filename(source_id,image_file) + "#{source_id}" #<< file_extension(image_file) + end + + def disk_filename(source_type,source_id,image_file=nil) + File.join(storage_path,avatar_directory(source_type),avatar_filename(source_id,image_file)) + end + + def file_extension(filename=nil) + $1 if filename =~ %r{(\.[a-zA-Z0-9]+)$} + end + + def get_avatar(source) + if source.nil? + return File.join(relative_path,'AnonymousUser','0') + end + if File.exist?(disk_filename(source.class,source.id)) + avatar_image(source) + else + File.join(relative_path,avatar_directory(source.class),'0') + end + end + + def get_avatar?(source) + if File.exist?(disk_filename(source.class,source.id)) + return true + else + return false + end + end + +end diff --git a/app/helpers/bids_helper.rb b/app/helpers/bids_helper.rb new file mode 100644 index 00000000..2f284074 --- /dev/null +++ b/app/helpers/bids_helper.rb @@ -0,0 +1,32 @@ +module BidsHelper + def render_notes(bid, journal, options={}) + content = '' + removable = User.current == journal.user || User.current == bid.author + links = [] + if !journal.notes.blank? + links << link_to(image_tag('comment.png'), + {:controller => 'bids', :action => 'new', :id => bid, :journal_id => journal}, + :remote => true, + :method => 'post', + :title => l(:button_quote)) if options[:reply_links] + if removable + url = {:controller => 'bids', + :action => 'destroy', + :object_id => journal, + :bid_id => bid} + links << ' ' + links << link_to(image_tag('delete.png'), url, + :remote => true, :method => 'delete', :class => "delete", :title => l(:button_delete)) + end + end + content << content_tag('div', links.join(' ').html_safe, :class => 'contextual') unless links.empty? + content << textilizable(journal.notes) + css_classes = "wiki" + content_tag('div', content.html_safe, :id => "journal-#{journal.id}-notes", :class => css_classes) + end + + def link_to_in_place_notes_editor(text, field_id, url, options={}) + onclick = "$.ajax({url: '#{url_for(url)}', type: 'get'}); return false;" + link_to text, '#', options.merge(:onclick => onclick) + end +end \ No newline at end of file diff --git a/app/helpers/boards_helper.rb b/app/helpers/boards_helper.rb new file mode 100644 index 00000000..84b979c4 --- /dev/null +++ b/app/helpers/boards_helper.rb @@ -0,0 +1,41 @@ +# encoding: utf-8 +# +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +module BoardsHelper + def board_breadcrumb(item) + board = item.is_a?(Message) ? item.board : item + links = [link_to(l(:label_board_plural), project_boards_path(item.project))] + boards = board.ancestors.reverse + if item.is_a?(Message) + boards << board + end + links += boards.map {|ancestor| link_to(h(ancestor.name), project_board_path(ancestor.project, ancestor))} + breadcrumb links + end + + def boards_options_for_select(boards) + options = [] + Board.board_tree(boards) do |board, level| + label = (level > 0 ? ' ' * 2 * level + '» ' : '').html_safe + label << board.name + options << [label, board.id] + end + options + end +end diff --git a/app/helpers/calendars_helper.rb b/app/helpers/calendars_helper.rb new file mode 100644 index 00000000..e57d9e53 --- /dev/null +++ b/app/helpers/calendars_helper.rb @@ -0,0 +1,58 @@ +# encoding: utf-8 +# +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +module CalendarsHelper + def link_to_previous_month(year, month, options={}) + target_year, target_month = if month == 1 + [year - 1, 12] + else + [year, month - 1] + end + + name = if target_month == 12 + "#{month_name(target_month)} #{target_year}" + else + "#{month_name(target_month)}" + end + + # \xc2\xab(utf-8) = « + link_to_month(("\xc2\xab " + name), target_year, target_month, options) + end + + def link_to_next_month(year, month, options={}) + target_year, target_month = if month == 12 + [year + 1, 1] + else + [year, month + 1] + end + + name = if target_month == 1 + "#{month_name(target_month)} #{target_year}" + else + "#{month_name(target_month)}" + end + + # \xc2\xbb(utf-8) = » + link_to_month((name + " \xc2\xbb"), target_year, target_month, options) + end + + def link_to_month(link_name, year, month, options={}) + link_to_content_update(h(link_name), params.merge(:year => year, :month => month)) + end +end diff --git a/app/helpers/context_menus_helper.rb b/app/helpers/context_menus_helper.rb new file mode 100644 index 00000000..85f88fbe --- /dev/null +++ b/app/helpers/context_menus_helper.rb @@ -0,0 +1,43 @@ +# encoding: utf-8 +# +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +module ContextMenusHelper + def context_menu_link(name, url, options={}) + options[:class] ||= '' + if options.delete(:selected) + options[:class] << ' icon-checked disabled' + options[:disabled] = true + end + if options.delete(:disabled) + options.delete(:method) + options.delete(:data) + options[:onclick] = 'return false;' + options[:class] << ' disabled' + url = '#' + end + link_to h(name), url, options + end + + def bulk_update_custom_field_context_menu_link(field, text, value) + context_menu_link h(text), + bulk_update_issues_path(:ids => @issue_ids, :issue => {'custom_field_values' => {field.id => value}}, :back_url => @back), + :method => :post, + :selected => (@issue && @issue.custom_field_value(field) == value) + end +end diff --git a/app/helpers/custom_fields_helper.rb b/app/helpers/custom_fields_helper.rb new file mode 100644 index 00000000..803dbb6d --- /dev/null +++ b/app/helpers/custom_fields_helper.rb @@ -0,0 +1,149 @@ +# encoding: utf-8 +# +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +module CustomFieldsHelper + + def custom_fields_tabs + CustomField::CUSTOM_FIELDS_TABS + end + + # Return custom field html tag corresponding to its format + def custom_field_tag(name, custom_value) + custom_field = custom_value.custom_field + field_name = "#{name}[custom_field_values][#{custom_field.id}]" + field_name << "[]" if custom_field.multiple? + field_id = "#{name}_custom_field_values_#{custom_field.id}" + + tag_options = {:id => field_id, :class => "#{custom_field.field_format}_cf"} + + field_format = Redmine::CustomFieldFormat.find_by_name(custom_field.field_format) + case field_format.try(:edit_as) + when "date" + text_field_tag(field_name, custom_value.value, tag_options.merge(:size => 10)) + + calendar_for(field_id) + when "text" + text_area_tag(field_name, custom_value.value, tag_options.merge(:rows => 3)) + when "bool" + hidden_field_tag(field_name, '0') + check_box_tag(field_name, '1', custom_value.true?, tag_options) + when "list" + blank_option = ''.html_safe + unless custom_field.multiple? + if custom_field.is_required? + unless custom_field.default_value.present? + blank_option = content_tag('option', "--- #{l(:actionview_instancetag_blank_option)} ---", :value => '') + end + else + blank_option = content_tag('option') + end + end + s = select_tag(field_name, blank_option + options_for_select(custom_field.possible_values_options(custom_value.customized), custom_value.value), + tag_options.merge(:multiple => custom_field.multiple?)) + if custom_field.multiple? + s << hidden_field_tag(field_name, '') + end + s + else + text_field_tag(field_name, custom_value.value, tag_options) + end + end + + # Return custom field label tag + def custom_field_label_tag(name, custom_value, options={}) + required = options[:required] || custom_value.custom_field.is_required? + + content_tag "label", h(custom_value.custom_field.name) + + (required ? " *".html_safe : ""), + :for => "#{name}_custom_field_values_#{custom_value.custom_field.id}" + end + + # Return custom field tag with its label tag + def custom_field_tag_with_label(name, custom_value, options={}) + custom_field_label_tag(name, custom_value, options) + custom_field_tag(name, custom_value) + end + + def custom_field_tag_for_bulk_edit(name, custom_field, projects=nil) + field_name = "#{name}[custom_field_values][#{custom_field.id}]" + field_name << "[]" if custom_field.multiple? + field_id = "#{name}_custom_field_values_#{custom_field.id}" + + tag_options = {:id => field_id, :class => "#{custom_field.field_format}_cf"} + + field_format = Redmine::CustomFieldFormat.find_by_name(custom_field.field_format) + case field_format.try(:edit_as) + when "date" + text_field_tag(field_name, '', tag_options.merge(:size => 10)) + + calendar_for(field_id) + when "text" + text_area_tag(field_name, '', tag_options.merge(:rows => 3)) + when "bool" + select_tag(field_name, options_for_select([[l(:label_no_change_option), ''], + [l(:general_text_yes), '1'], + [l(:general_text_no), '0']]), tag_options) + when "list" + options = [] + options << [l(:label_no_change_option), ''] unless custom_field.multiple? + options << [l(:label_none), '__none__'] unless custom_field.is_required? + options += custom_field.possible_values_options(projects) + select_tag(field_name, options_for_select(options), tag_options.merge(:multiple => custom_field.multiple?)) + else + text_field_tag(field_name, '', tag_options) + end + end + + # Return a string used to display a custom value + def show_value(custom_value) + return "" unless custom_value + format_value(custom_value.value, custom_value.custom_field.field_format) + end + + # Return a string used to display a custom value + def format_value(value, field_format) + if value.is_a?(Array) + value.collect {|v| format_value(v, field_format)}.compact.sort.join(', ') + else + Redmine::CustomFieldFormat.format_value(value, field_format) + end + end + + # Return an array of custom field formats which can be used in select_tag + def custom_field_formats_for_select(custom_field) + Redmine::CustomFieldFormat.as_select(custom_field.class.customized_class.name) + end + + # Renders the custom_values in api views + def render_api_custom_values(custom_values, api) + api.array :custom_fields do + custom_values.each do |custom_value| + attrs = {:id => custom_value.custom_field_id, :name => custom_value.custom_field.name} + attrs.merge!(:multiple => true) if custom_value.custom_field.multiple? + api.custom_field attrs do + if custom_value.value.is_a?(Array) + api.array :value do + custom_value.value.each do |value| + api.value value unless value.blank? + end + end + else + api.value custom_value.value + end + end + end + end unless custom_values.empty? + end +end diff --git a/app/helpers/documents_helper.rb b/app/helpers/documents_helper.rb new file mode 100644 index 00000000..487ddafd --- /dev/null +++ b/app/helpers/documents_helper.rb @@ -0,0 +1,21 @@ +# encoding: utf-8 +# +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +module DocumentsHelper +end diff --git a/app/helpers/enumerations_helper.rb b/app/helpers/enumerations_helper.rb new file mode 100644 index 00000000..bb276429 --- /dev/null +++ b/app/helpers/enumerations_helper.rb @@ -0,0 +1,21 @@ +# encoding: utf-8 +# +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +module EnumerationsHelper +end diff --git a/app/helpers/gantt_helper.rb b/app/helpers/gantt_helper.rb new file mode 100644 index 00000000..4f65884a --- /dev/null +++ b/app/helpers/gantt_helper.rb @@ -0,0 +1,43 @@ +# encoding: utf-8 +# +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +module GanttHelper + + def gantt_zoom_link(gantt, in_or_out) + case in_or_out + when :in + if gantt.zoom < 4 + link_to_content_update l(:text_zoom_in), + params.merge(gantt.params.merge(:zoom => (gantt.zoom + 1))), + :class => 'icon icon-zoom-in' + else + content_tag(:span, l(:text_zoom_in), :class => 'icon icon-zoom-in').html_safe + end + + when :out + if gantt.zoom > 1 + link_to_content_update l(:text_zoom_out), + params.merge(gantt.params.merge(:zoom => (gantt.zoom - 1))), + :class => 'icon icon-zoom-out' + else + content_tag(:span, l(:text_zoom_out), :class => 'icon icon-zoom-out').html_safe + end + end + end +end diff --git a/app/helpers/groups_helper.rb b/app/helpers/groups_helper.rb new file mode 100644 index 00000000..aa58eb57 --- /dev/null +++ b/app/helpers/groups_helper.rb @@ -0,0 +1,42 @@ +# encoding: utf-8 +# +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +module GroupsHelper + def group_settings_tabs + tabs = [{:name => 'general', :partial => 'groups/general', :label => :label_general}, + {:name => 'users', :partial => 'groups/users', :label => :label_user_plural}, + {:name => 'memberships', :partial => 'groups/memberships', :label => :label_project_plural} + ] + end + + def render_principals_for_new_group_users(group) + scope = User.active.sorted.not_in_group(group).like(params[:q]) + principal_count = scope.count + principal_pages = Redmine::Pagination::Paginator.new principal_count, 100, params['page'] + principals = scope.offset(principal_pages.offset).limit(principal_pages.per_page).all + + s = content_tag('div', principals_check_box_tags('user_ids[]', principals), :id => 'principals') + + links = pagination_links_full(principal_pages, principal_count, :per_page_links => false) {|text, parameters, options| + link_to text, autocomplete_for_user_group_path(group, parameters.merge(:q => params[:q], :format => 'js')), :remote => true + } + + s + content_tag('p', links, :class => 'pagination') + end +end diff --git a/app/helpers/issue_categories_helper.rb b/app/helpers/issue_categories_helper.rb new file mode 100644 index 00000000..9189025c --- /dev/null +++ b/app/helpers/issue_categories_helper.rb @@ -0,0 +1,21 @@ +# encoding: utf-8 +# +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +module IssueCategoriesHelper +end diff --git a/app/helpers/issue_relations_helper.rb b/app/helpers/issue_relations_helper.rb new file mode 100644 index 00000000..24ae7e36 --- /dev/null +++ b/app/helpers/issue_relations_helper.rb @@ -0,0 +1,25 @@ +# encoding: utf-8 +# +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +module IssueRelationsHelper + def collection_for_relation_type_select + values = IssueRelation::TYPES + values.keys.sort{|x,y| values[x][:order] <=> values[y][:order]}.collect{|k| [l(values[k][:name]), k]} + end +end diff --git a/app/helpers/issue_statuses_helper.rb b/app/helpers/issue_statuses_helper.rb new file mode 100644 index 00000000..b3876865 --- /dev/null +++ b/app/helpers/issue_statuses_helper.rb @@ -0,0 +1,21 @@ +# encoding: utf-8 +# +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +module IssueStatusesHelper +end diff --git a/app/helpers/issues_helper.rb b/app/helpers/issues_helper.rb new file mode 100644 index 00000000..4ecc3369 --- /dev/null +++ b/app/helpers/issues_helper.rb @@ -0,0 +1,383 @@ +# encoding: utf-8 +# +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +module IssuesHelper + include ApplicationHelper + + def issue_list(issues, &block) + ancestors = [] + issues.each do |issue| + while (ancestors.any? && !issue.is_descendant_of?(ancestors.last)) + ancestors.pop + end + yield issue, ancestors.size + ancestors << issue unless issue.leaf? + end + end + + # Renders a HTML/CSS tooltip + # + # To use, a trigger div is needed. This is a div with the class of "tooltip" + # that contains this method wrapped in a span with the class of "tip" + # + #
<%= link_to_issue(issue) %> + # <%= render_issue_tooltip(issue) %> + #
+ # + def render_issue_tooltip(issue) + @cached_label_status ||= l(:field_status) + @cached_label_start_date ||= l(:field_start_date) + @cached_label_due_date ||= l(:field_due_date) + @cached_label_assigned_to ||= l(:field_assigned_to) + @cached_label_priority ||= l(:field_priority) + @cached_label_project ||= l(:field_project) + + link_to_issue(issue) + "

".html_safe + + "#{@cached_label_project}: #{link_to_project(issue.project)}
".html_safe + + "#{@cached_label_status}: #{h(issue.status.name)}
".html_safe + + "#{@cached_label_start_date}: #{format_date(issue.start_date)}
".html_safe + + "#{@cached_label_due_date}: #{format_date(issue.due_date)}
".html_safe + + "#{@cached_label_assigned_to}: #{h(issue.assigned_to)}
".html_safe + + "#{@cached_label_priority}: #{h(issue.priority.name)}".html_safe + end + + def issue_heading(issue) + h("#{issue.tracker} ##{issue.id}") + end + + def render_issue_subject_with_tree(issue) + s = '' + ancestors = issue.root? ? [] : issue.ancestors.visible.all + ancestors.each do |ancestor| + s << '
' + content_tag('p', link_to_issue(ancestor, :project => (issue.project_id != ancestor.project_id))) + end + s << '
' + subject = h(issue.subject) + if issue.is_private? + subject = content_tag('span', l(:field_is_private), :class => 'private') + ' ' + subject + end + s << content_tag('h3', subject) + s << '
' * (ancestors.size + 1) + s.html_safe + end + + def render_descendants_tree(issue) + s = '
' + issue_list(issue.descendants.visible.sort_by(&:lft)) do |child, level| + css = "issue issue-#{child.id} hascontextmenu" + css << " idnt idnt-#{level}" if level > 0 + s << content_tag('tr', + content_tag('td', check_box_tag("ids[]", child.id, false, :id => nil), :class => 'checkbox') + + content_tag('td', link_to_issue(child, :truncate => 60, :project => (issue.project_id != child.project_id)), :class => 'subject') + + content_tag('td', h(child.status)) + + content_tag('td', link_to_user(child.assigned_to)) + + content_tag('td', progress_bar(child.done_ratio, :width => '80px')), + :class => css) + end + s << '
' + s.html_safe + end + + # Returns a link for adding a new subtask to the given issue + def link_to_new_subtask(issue) + attrs = { + :tracker_id => issue.tracker, + :parent_issue_id => issue + } + link_to(l(:button_add), new_project_issue_path(issue.project, :issue => attrs)) + end + + class IssueFieldsRows + include ActionView::Helpers::TagHelper + + def initialize + @left = [] + @right = [] + end + + def left(*args) + args.any? ? @left << cells(*args) : @left + end + + def right(*args) + args.any? ? @right << cells(*args) : @right + end + + def size + @left.size > @right.size ? @left.size : @right.size + end + + def to_html + html = ''.html_safe + blank = content_tag('th', '') + content_tag('td', '') + size.times do |i| + left = @left[i] || blank + right = @right[i] || blank + html << content_tag('tr', left + right) + end + html + end + + def cells(label, text, options={}) + content_tag('th', "#{label}:", options) + content_tag('td', text, options) + end + end + + def issue_fields_rows + r = IssueFieldsRows.new + yield r + r.to_html + end + + def render_custom_fields_rows(issue) + return if issue.custom_field_values.empty? + ordered_values = [] + half = (issue.custom_field_values.size / 2.0).ceil + half.times do |i| + ordered_values << issue.custom_field_values[i] + ordered_values << issue.custom_field_values[i + half] + end + s = "\n" + n = 0 + ordered_values.compact.each do |value| + s << "\n\n" if n > 0 && (n % 2) == 0 + s << "\t#{ h(value.custom_field.name) }:#{ simple_format_without_paragraph(h(show_value(value))) }\n" + n += 1 + end + s << "\n" + s.html_safe + end + + def issues_destroy_confirmation_message(issues) + issues = [issues] unless issues.is_a?(Array) + message = l(:text_issues_destroy_confirmation) + descendant_count = issues.inject(0) {|memo, i| memo += (i.right - i.left - 1)/2} + if descendant_count > 0 + issues.each do |issue| + next if issue.root? + issues.each do |other_issue| + descendant_count -= 1 if issue.is_descendant_of?(other_issue) + end + end + if descendant_count > 0 + message << "\n" + l(:text_issues_destroy_descendants_confirmation, :count => descendant_count) + end + end + message + end + + def sidebar_queries + unless @sidebar_queries + @sidebar_queries = IssueQuery.visible.all( + :order => "#{Query.table_name}.name ASC", + # Project specific queries and global queries + :conditions => (@project.nil? ? ["project_id IS NULL"] : ["project_id IS NULL OR project_id = ?", @project.id]) + ) + end + @sidebar_queries + end + + def query_links(title, queries) + # links to #index on issues/show + url_params = controller_name == 'issues' ? {:controller => 'issues', :action => 'index', :project_id => @project} : params + + content_tag('h3', h(title)) + + queries.collect {|query| + css = 'query' + css << ' selected' if query == @query + link_to(h(query.name), url_params.merge(:query_id => query), :class => css) + }.join('
').html_safe + end + + def render_sidebar_queries + out = ''.html_safe + queries = sidebar_queries.select {|q| !q.is_public?} + out << query_links(l(:label_my_queries), queries) if queries.any? + queries = sidebar_queries.select {|q| q.is_public?} + out << query_links(l(:label_query_plural), queries) if queries.any? + out + end + + # Returns the textual representation of a journal details + # as an array of strings + def details_to_strings(details, no_html=false, options={}) + options[:only_path] = (options[:only_path] == false ? false : true) + strings = [] + values_by_field = {} + details.each do |detail| + if detail.property == 'cf' + field_id = detail.prop_key + field = CustomField.find_by_id(field_id) + if field && field.multiple? + values_by_field[field_id] ||= {:added => [], :deleted => []} + if detail.old_value + values_by_field[field_id][:deleted] << detail.old_value + end + if detail.value + values_by_field[field_id][:added] << detail.value + end + next + end + end + strings << show_detail(detail, no_html, options) + end + values_by_field.each do |field_id, changes| + detail = JournalDetail.new(:property => 'cf', :prop_key => field_id) + if changes[:added].any? + detail.value = changes[:added] + strings << show_detail(detail, no_html, options) + elsif changes[:deleted].any? + detail.old_value = changes[:deleted] + strings << show_detail(detail, no_html, options) + end + end + strings + end + + # Returns the textual representation of a single journal detail + def show_detail(detail, no_html=false, options={}) + multiple = false + case detail.property + when 'attr' + field = detail.prop_key.to_s.gsub(/\_id$/, "") + label = l(("field_" + field).to_sym) + case detail.prop_key + when 'due_date', 'start_date' + value = format_date(detail.value.to_date) if detail.value + old_value = format_date(detail.old_value.to_date) if detail.old_value + + when 'project_id', 'status_id', 'tracker_id', 'assigned_to_id', + 'priority_id', 'category_id', 'fixed_version_id' + value = find_name_by_reflection(field, detail.value) + old_value = find_name_by_reflection(field, detail.old_value) + + when 'estimated_hours' + value = "%0.02f" % detail.value.to_f unless detail.value.blank? + old_value = "%0.02f" % detail.old_value.to_f unless detail.old_value.blank? + + when 'parent_id' + label = l(:field_parent_issue) + value = "##{detail.value}" unless detail.value.blank? + old_value = "##{detail.old_value}" unless detail.old_value.blank? + + when 'is_private' + value = l(detail.value == "0" ? :general_text_No : :general_text_Yes) unless detail.value.blank? + old_value = l(detail.old_value == "0" ? :general_text_No : :general_text_Yes) unless detail.old_value.blank? + end + when 'cf' + custom_field = CustomField.find_by_id(detail.prop_key) + if custom_field + multiple = custom_field.multiple? + label = custom_field.name + value = format_value(detail.value, custom_field.field_format) if detail.value + old_value = format_value(detail.old_value, custom_field.field_format) if detail.old_value + end + when 'attachment' + label = l(:label_attachment) + end + call_hook(:helper_issues_show_detail_after_setting, + {:detail => detail, :label => label, :value => value, :old_value => old_value }) + + label ||= detail.prop_key + value ||= detail.value + old_value ||= detail.old_value + + unless no_html + label = content_tag('strong', label) + old_value = content_tag("i", h(old_value)) if detail.old_value + old_value = content_tag("del", old_value) if detail.old_value and detail.value.blank? + if detail.property == 'attachment' && !value.blank? && atta = Attachment.find_by_id(detail.prop_key) + # Link to the attachment if it has not been removed + value = link_to_attachment(atta, :download => true, :only_path => options[:only_path]) + if options[:only_path] != false && atta.is_text? + value += link_to( + image_tag('magnifier.png'), + :controller => 'attachments', :action => 'show', + :id => atta, :filename => atta.filename + ) + end + else + value = content_tag("i", h(value)) if value + end + end + + if detail.property == 'attr' && detail.prop_key == 'description' + s = l(:text_journal_changed_no_detail, :label => label) + unless no_html + diff_link = link_to 'diff', + {:controller => 'journals', :action => 'diff', :id => detail.journal_id, + :detail_id => detail.id, :only_path => options[:only_path]}, + :title => l(:label_view_diff) + s << " (#{ diff_link })" + end + s.html_safe + elsif detail.value.present? + case detail.property + when 'attr', 'cf' + if detail.old_value.present? + l(:text_journal_changed, :label => label, :old => old_value, :new => value).html_safe + elsif multiple + l(:text_journal_added, :label => label, :value => value).html_safe + else + l(:text_journal_set_to, :label => label, :value => value).html_safe + end + when 'attachment' + l(:text_journal_added, :label => label, :value => value).html_safe + end + else + l(:text_journal_deleted, :label => label, :old => old_value).html_safe + end + end + + # Find the name of an associated record stored in the field attribute + def find_name_by_reflection(field, id) + unless id.present? + return nil + end + association = Issue.reflect_on_association(field.to_sym) + if association + record = association.class_name.constantize.find_by_id(id) + if record + record.name.force_encoding('UTF-8') if record.name.respond_to?(:force_encoding) + return record.name + end + end + end + + # Renders issue children recursively + def render_api_issue_children(issue, api) + return if issue.leaf? + api.array :children do + issue.children.each do |child| + api.issue(:id => child.id) do + api.tracker(:id => child.tracker_id, :name => child.tracker.name) unless child.tracker.nil? + api.subject child.subject + render_api_issue_children(child, api) + end + end + end + end + + # this method is used to get all projects that tagged one tag + # added by william + def get_issues_by_tag(tag_name) + Issue.tagged_with(tag_name) + end + +end diff --git a/app/helpers/journals_helper.rb b/app/helpers/journals_helper.rb new file mode 100644 index 00000000..b8e7f8bf --- /dev/null +++ b/app/helpers/journals_helper.rb @@ -0,0 +1,46 @@ +# encoding: utf-8 +# +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +module JournalsHelper + def render_notes(issue, journal, options={}) + content = '' + editable = User.current.logged? && (User.current.allowed_to?(:edit_issue_notes, issue.project) || (journal.user == User.current && User.current.allowed_to?(:edit_own_issue_notes, issue.project))) + links = [] + if !journal.notes.blank? + links << link_to(image_tag('comment.png'), + {:controller => 'journals', :action => 'new', :id => issue, :journal_id => journal}, + :remote => true, + :method => 'post', + :title => l(:button_quote)) if options[:reply_links] + links << link_to_in_place_notes_editor(image_tag('edit.png'), "journal-#{journal.id}-notes", + { :controller => 'journals', :action => 'edit', :id => journal, :format => 'js' }, + :title => l(:button_edit)) if editable + end + content << content_tag('div', links.join(' ').html_safe, :class => 'contextual') unless links.empty? + content << textilizable(journal, :notes) + css_classes = "wiki" + css_classes << " editable" if editable + content_tag('div', content.html_safe, :id => "journal-#{journal.id}-notes", :class => css_classes) + end + + def link_to_in_place_notes_editor(text, field_id, url, options={}) + onclick = "$.ajax({url: '#{url_for(url)}', type: 'get'}); return false;" + link_to text, '#', options.merge(:onclick => onclick) + end +end diff --git a/app/helpers/mail_handler_helper.rb b/app/helpers/mail_handler_helper.rb new file mode 100644 index 00000000..037ea57e --- /dev/null +++ b/app/helpers/mail_handler_helper.rb @@ -0,0 +1,21 @@ +# encoding: utf-8 +# +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +module MailHandlerHelper +end diff --git a/app/helpers/members_helper.rb b/app/helpers/members_helper.rb new file mode 100644 index 00000000..fcaa62db --- /dev/null +++ b/app/helpers/members_helper.rb @@ -0,0 +1,35 @@ +# encoding: utf-8 +# +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +module MembersHelper + def render_principals_for_new_members(project) + scope = Principal.active.sorted.not_member_of(project).like(params[:q]) + principal_count = scope.count + principal_pages = Redmine::Pagination::Paginator.new principal_count, 10, params['page']#by young + principals = scope.offset(principal_pages.offset).limit(principal_pages.per_page).all + + s = content_tag('div', principals_check_box_tags('membership[user_ids][]', principals), :id => 'principals') + + links = pagination_links_full(principal_pages, principal_count, :per_page_links => false) {|text, parameters, options| + link_to text, autocomplete_project_memberships_path(project, parameters.merge(:q => params[:q], :format => 'js')), :remote => true + } + + s + content_tag('div', content_tag('ul', links), :class => 'pagination') + end +end diff --git a/app/helpers/messages_helper.rb b/app/helpers/messages_helper.rb new file mode 100644 index 00000000..bd2b20a8 --- /dev/null +++ b/app/helpers/messages_helper.rb @@ -0,0 +1,21 @@ +# encoding: utf-8 +# +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +module MessagesHelper +end diff --git a/app/helpers/my_helper.rb b/app/helpers/my_helper.rb new file mode 100644 index 00000000..9017e924 --- /dev/null +++ b/app/helpers/my_helper.rb @@ -0,0 +1,72 @@ +# encoding: utf-8 +# +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +module MyHelper + include AvatarHelper + def calendar_items(startdt, enddt) + Issue.visible. + where(:project_id => User.current.projects.map(&:id)). + where("(start_date>=? and start_date<=?) or (due_date>=? and due_date<=?)", startdt, enddt, startdt, enddt). + includes(:project, :tracker, :priority, :assigned_to). + all + end + + def documents_items + Document.visible.order("#{Document.table_name}.created_on DESC").limit(10).all + end + + def issuesassignedtome_items + Issue.visible.open. + where(:assigned_to_id => ([User.current.id] + User.current.group_ids)). + limit(10). + includes(:status, :project, :tracker, :priority). + order("#{IssuePriority.table_name}.position DESC, #{Issue.table_name}.updated_on DESC"). + all + end + + def issuesreportedbyme_items + Issue.visible. + where(:author_id => User.current.id). + limit(10). + includes(:status, :project, :tracker). + order("#{Issue.table_name}.updated_on DESC"). + all + end + + def issueswatched_items + Issue.visible.on_active_project.watched_by(User.current.id).recently_updated.limit(10).all + end + + def news_items + News.visible. + where(:project_id => User.current.projects.map(&:id)). + limit(10). + includes(:project, :author). + order("#{News.table_name}.created_on DESC"). + all + end + + def timelog_items + TimeEntry. + where("#{TimeEntry.table_name}.user_id = ? AND #{TimeEntry.table_name}.spent_on BETWEEN ? AND ?", User.current.id, Date.today - 6, Date.today). + includes(:activity, :project, {:issue => [:tracker, :status]}). + order("#{TimeEntry.table_name}.spent_on DESC, #{Project.table_name}.name ASC, #{Tracker.table_name}.position ASC, #{Issue.table_name}.id ASC"). + all + end +end diff --git a/app/helpers/news_helper.rb b/app/helpers/news_helper.rb new file mode 100644 index 00000000..a5b8888a --- /dev/null +++ b/app/helpers/news_helper.rb @@ -0,0 +1,21 @@ +# encoding: utf-8 +# +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +module NewsHelper +end diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb new file mode 100644 index 00000000..cbe57d1c --- /dev/null +++ b/app/helpers/projects_helper.rb @@ -0,0 +1,91 @@ +# encoding: utf-8 +# +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +module ProjectsHelper + def link_to_version(version, options = {}) + return '' unless version && version.is_a?(Version) + link_to_if version.visible?, format_version_name(version), { :controller => 'versions', :action => 'show', :id => version }, options + end + + def project_settings_tabs + tabs = [{:name => 'info', :action => :edit_project, :partial => 'projects/edit', :label => :label_information_plural}, + {:name => 'modules', :action => :select_project_modules, :partial => 'projects/settings/modules', :label => :label_module_plural}, + {:name => 'members', :action => :manage_members, :partial => 'projects/settings/members', :label => :label_member_plural}, + {:name => 'versions', :action => :manage_versions, :partial => 'projects/settings/versions', :label => :label_version_plural}, + {:name => 'categories', :action => :manage_categories, :partial => 'projects/settings/issue_categories', :label => :label_issue_category_plural}, + {:name => 'wiki', :action => :manage_wiki, :partial => 'projects/settings/wiki', :label => :label_wiki}, + {:name => 'repositories', :action => :manage_repository, :partial => 'projects/settings/repositories', :label => :label_repository_plural}, + {:name => 'boards', :action => :manage_boards, :partial => 'projects/settings/boards', :label => :label_board_plural}, + {:name => 'activities', :action => :manage_project_activities, :partial => 'projects/settings/activities', :label => :enumeration_activities} + ] + tabs.select {|tab| User.current.allowed_to?(tab[:action], @project)} + end + + def parent_project_select_tag(project) + selected = project.parent + # retrieve the requested parent project + parent_id = (params[:project] && params[:project][:parent_id]) || params[:parent_id] + if parent_id + selected = (parent_id.blank? ? nil : Project.find(parent_id)) + end + + options = '' + options << "" if project.allowed_parents.include?(nil) + options << project_tree_options_for_select(project.allowed_parents.compact, :selected => selected) + content_tag('select', options.html_safe, :name => 'project[parent_id]', :id => 'project_parent_id') + end + + # Renders the projects index + def render_project_hierarchy(projects) + render_project_nested_lists(projects) do |project| + s = link_to_project(project, {}, :class => "#{project.css_classes} #{User.current.member_of?(project) ? 'my-project' : nil}") + if project.description.present? + #Delete by nie. + # s << content_tag('td', textilizable(project.short_description, :project => project), :class => 'wiki description') + end + s + end + end + + # Returns a set of options for a select field, grouped by project. + def version_options_for_select(versions, selected=nil) + grouped = Hash.new {|h,k| h[k] = []} + versions.each do |version| + grouped[version.project.name] << [version.name, version.id] + end + + if grouped.keys.size > 1 + grouped_options_for_select(grouped, selected && selected.id) + else + options_for_select((grouped.values.first || []), selected && selected.id) + end + end + + def format_version_sharing(sharing) + sharing = 'none' unless Version::VERSION_SHARINGS.include?(sharing) + l("label_version_sharing_#{sharing}") + end + + # this method is used to get all projects that tagged one tag + # added by william + def get_projects_by_tag(tag_name) + Project.tagged_with(tag_name) + end + +end diff --git a/app/helpers/queries_helper.rb b/app/helpers/queries_helper.rb new file mode 100644 index 00000000..2de6b0c9 --- /dev/null +++ b/app/helpers/queries_helper.rb @@ -0,0 +1,223 @@ +# encoding: utf-8 +# +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +module QueriesHelper + def filters_options_for_select(query) + options_for_select(filters_options(query)) + end + + def filters_options(query) + options = [[]] + options += query.available_filters.map do |field, field_options| + [field_options[:name], field] + end + end + + def query_filters_hidden_tags(query) + tags = ''.html_safe + query.filters.each do |field, options| + tags << hidden_field_tag("f[]", field, :id => nil) + tags << hidden_field_tag("op[#{field}]", options[:operator], :id => nil) + options[:values].each do |value| + tags << hidden_field_tag("v[#{field}][]", value, :id => nil) + end + end + tags + end + + def query_columns_hidden_tags(query) + tags = ''.html_safe + query.columns.each do |column| + tags << hidden_field_tag("c[]", column.name, :id => nil) + end + tags + end + + def query_hidden_tags(query) + query_filters_hidden_tags(query) + query_columns_hidden_tags(query) + end + + def available_block_columns_tags(query) + tags = ''.html_safe + query.available_block_columns.each do |column| + tags << content_tag('label', check_box_tag('c[]', column.name.to_s, query.has_column?(column)) + " #{column.caption}", :class => 'inline') + end + tags + end + + def query_available_inline_columns_options(query) + (query.available_inline_columns - query.columns).reject(&:frozen?).collect {|column| [column.caption, column.name]} + end + + def query_selected_inline_columns_options(query) + (query.inline_columns & query.available_inline_columns).reject(&:frozen?).collect {|column| [column.caption, column.name]} + end + + def render_query_columns_selection(query, options={}) + tag_name = (options[:name] || 'c') + '[]' + render :partial => 'queries/columns', :locals => {:query => query, :tag_name => tag_name} + end + + def column_header(column) + column.sortable ? sort_header_tag(column.name.to_s, :caption => column.caption, + :default_order => column.default_order) : + content_tag('th', h(column.caption)) + end + + def column_content(column, issue) + value = column.value(issue) + if value.is_a?(Array) + value.collect {|v| column_value(column, issue, v)}.compact.join(', ').html_safe + else + column_value(column, issue, value) + end + end + + def column_value(column, issue, value) + case value.class.name + when 'String' + if column.name == :subject + link_to(h(value), :controller => 'issues', :action => 'show', :id => issue) + elsif column.name == :description + issue.description? ? content_tag('div', textilizable(issue, :description), :class => "wiki") : '' + else + h(value) + end + when 'Time' + format_time(value) + when 'Date' + format_date(value) + when 'Fixnum' + if column.name == :id + link_to value, issue_path(issue) + elsif column.name == :done_ratio + progress_bar(value, :width => '80px') + else + value.to_s + end + when 'Float' + sprintf "%.2f", value + when 'User' + link_to_user value + when 'Project' + link_to_project value + when 'Version' + link_to(h(value), :controller => 'versions', :action => 'show', :id => value) + when 'TrueClass' + l(:general_text_Yes) + when 'FalseClass' + l(:general_text_No) + when 'Issue' + value.visible? ? link_to_issue(value) : "##{value.id}" + when 'IssueRelation' + other = value.other_issue(issue) + content_tag('span', + (l(value.label_for(issue)) + " " + link_to_issue(other, :subject => false, :tracker => false)).html_safe, + :class => value.css_classes_for(issue)) + else + h(value) + end + end + + def csv_content(column, issue) + value = column.value(issue) + if value.is_a?(Array) + value.collect {|v| csv_value(column, issue, v)}.compact.join(', ') + else + csv_value(column, issue, value) + end + end + + def csv_value(column, issue, value) + case value.class.name + when 'Time' + format_time(value) + when 'Date' + format_date(value) + when 'Float' + sprintf("%.2f", value).gsub('.', l(:general_csv_decimal_separator)) + when 'IssueRelation' + other = value.other_issue(issue) + l(value.label_for(issue)) + " ##{other.id}" + else + value.to_s + end + end + + def query_to_csv(items, query, options={}) + encoding = l(:general_csv_encoding) + columns = (options[:columns] == 'all' ? query.available_inline_columns : query.inline_columns) + query.available_block_columns.each do |column| + if options[column.name].present? + columns << column + end + end + + export = FCSV.generate(:col_sep => l(:general_csv_separator)) do |csv| + # csv header fields + csv << columns.collect {|c| Redmine::CodesetUtil.from_utf8(c.caption.to_s, encoding) } + # csv lines + items.each do |item| + csv << columns.collect {|c| Redmine::CodesetUtil.from_utf8(csv_content(c, item), encoding) } + end + end + export + end + + # Retrieve query from session or build a new query + def retrieve_query + if !params[:query_id].blank? + cond = "project_id IS NULL" + cond << " OR project_id = #{@project.id}" if @project + @query = IssueQuery.find(params[:query_id], :conditions => cond) + raise ::Unauthorized unless @query.visible? + @query.project = @project + session[:query] = {:id => @query.id, :project_id => @query.project_id} + sort_clear + elsif api_request? || params[:set_filter] || session[:query].nil? || session[:query][:project_id] != (@project ? @project.id : nil) + # Give it a name, required to be valid + @query = IssueQuery.new(:name => "_") + @query.project = @project + @query.build_from_params(params) + session[:query] = {:project_id => @query.project_id, :filters => @query.filters, :group_by => @query.group_by, :column_names => @query.column_names} + else + # retrieve from session + @query = IssueQuery.find_by_id(session[:query][:id]) if session[:query][:id] + @query ||= IssueQuery.new(:name => "_", :filters => session[:query][:filters], :group_by => session[:query][:group_by], :column_names => session[:query][:column_names]) + @query.project = @project + end + end + + def retrieve_query_from_session + if session[:query] + if session[:query][:id] + @query = IssueQuery.find_by_id(session[:query][:id]) + return unless @query + else + @query = IssueQuery.new(:name => "_", :filters => session[:query][:filters], :group_by => session[:query][:group_by], :column_names => session[:query][:column_names]) + end + if session[:query].has_key?(:project_id) + @query.project_id = session[:query][:project_id] + else + @query.project = @project + end + @query + end + end +end diff --git a/app/helpers/reports_helper.rb b/app/helpers/reports_helper.rb new file mode 100644 index 00000000..9d52b673 --- /dev/null +++ b/app/helpers/reports_helper.rb @@ -0,0 +1,43 @@ +# encoding: utf-8 +# +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +module ReportsHelper + + def aggregate(data, criteria) + a = 0 + data.each { |row| + match = 1 + criteria.each { |k, v| + match = 0 unless (row[k].to_s == v.to_s) || (k == 'closed' && row[k] == (v == 0 ? "f" : "t")) + } unless criteria.nil? + a = a + row["total"].to_i if match == 1 + } unless data.nil? + a + end + + def aggregate_link(data, criteria, *args) + a = aggregate data, criteria + a > 0 ? link_to(h(a), *args) : '-' + end + + def aggregate_path(project, field, row, options={}) + parameters = {:set_filter => 1, :subproject_id => '!*', field => row.id}.merge(options) + project_issues_path(row.is_a?(Project) ? row : project, parameters) + end +end diff --git a/app/helpers/repositories_helper.rb b/app/helpers/repositories_helper.rb new file mode 100644 index 00000000..ae45d2a5 --- /dev/null +++ b/app/helpers/repositories_helper.rb @@ -0,0 +1,297 @@ +# encoding: utf-8 +# +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +module RepositoriesHelper + def format_revision(revision) + if revision.respond_to? :format_identifier + revision.format_identifier + else + revision.to_s + end + end + + def truncate_at_line_break(text, length = 255) + if text + text.gsub(%r{^(.{#{length}}[^\n]*)\n.+$}m, '\\1...') + end + end + + def render_properties(properties) + unless properties.nil? || properties.empty? + content = '' + properties.keys.sort.each do |property| + content << content_tag('li', "#{h property}: #{h properties[property]}".html_safe) + end + content_tag('ul', content.html_safe, :class => 'properties') + end + end + + def render_changeset_changes + changes = @changeset.filechanges.limit(1000).reorder('path').all.collect do |change| + case change.action + when 'A' + # Detects moved/copied files + if !change.from_path.blank? + change.action = + @changeset.filechanges.detect {|c| c.action == 'D' && c.path == change.from_path} ? 'R' : 'C' + end + change + when 'D' + @changeset.filechanges.detect {|c| c.from_path == change.path} ? nil : change + else + change + end + end.compact + + tree = { } + changes.each do |change| + p = tree + dirs = change.path.to_s.split('/').select {|d| !d.blank?} + path = '' + dirs.each do |dir| + path += '/' + dir + p[:s] ||= {} + p = p[:s] + p[path] ||= {} + p = p[path] + end + p[:c] = change + end + render_changes_tree(tree[:s]) + end + + def render_changes_tree(tree) + return '' if tree.nil? + output = '' + output << '
    ' + tree.keys.sort.each do |file| + style = 'change' + text = File.basename(h(file)) + if s = tree[file][:s] + style << ' folder' + path_param = to_path_param(@repository.relative_path(file)) + text = link_to(h(text), :controller => 'repositories', + :action => 'show', + :id => @project, + :repository_id => @repository.identifier_param, + :path => path_param, + :rev => @changeset.identifier) + output << "
  • #{text}" + output << render_changes_tree(s) + output << "
  • " + elsif c = tree[file][:c] + style << " change-#{c.action}" + path_param = to_path_param(@repository.relative_path(c.path)) + text = link_to(h(text), :controller => 'repositories', + :action => 'entry', + :id => @project, + :repository_id => @repository.identifier_param, + :path => path_param, + :rev => @changeset.identifier) unless c.action == 'D' + text << " - #{h(c.revision)}" unless c.revision.blank? + text << ' ('.html_safe + link_to(l(:label_diff), :controller => 'repositories', + :action => 'diff', + :id => @project, + :repository_id => @repository.identifier_param, + :path => path_param, + :rev => @changeset.identifier) + ') '.html_safe if c.action == 'M' + text << ' '.html_safe + content_tag('span', h(c.from_path), :class => 'copied-from') unless c.from_path.blank? + output << "
  • #{text}
  • " + end + end + output << '
' + output.html_safe + end + + def repository_field_tags(form, repository) + method = repository.class.name.demodulize.underscore + "_field_tags" + if repository.is_a?(Repository) && + respond_to?(method) && method != 'repository_field_tags' + send(method, form, repository) + end + end + + def scm_select_tag(repository) + scm_options = [["--- #{l(:actionview_instancetag_blank_option)} ---", '']] + Redmine::Scm::Base.all.each do |scm| + if Setting.enabled_scm.include?(scm) || + (repository && repository.class.name.demodulize == scm) + scm_options << ["Repository::#{scm}".constantize.scm_name, scm] + end + end + select_tag('repository_scm', + options_for_select(scm_options, repository.class.name.demodulize), + :disabled => (repository && !repository.new_record?), + :data => {:remote => true, :method => 'get'}) + end + + def with_leading_slash(path) + path.to_s.starts_with?('/') ? path : "/#{path}" + end + + def without_leading_slash(path) + path.gsub(%r{^/+}, '') + end + + def subversion_field_tags(form, repository) + content_tag('p', form.text_field(:url, :size => 60, :required => true, + :disabled => !repository.safe_attribute?('url')) + + '
'.html_safe + + '(file:///, http://, https://, svn://, svn+[tunnelscheme]://)') + + content_tag('p', form.text_field(:login, :size => 30)) + + content_tag('p', form.password_field( + :password, :size => 30, :name => 'ignore', + :value => ((repository.new_record? || repository.password.blank?) ? '' : ('x'*15)), + :onfocus => "this.value=''; this.name='repository[password]';", + :onchange => "this.name='repository[password]';")) + end + + def darcs_field_tags(form, repository) + content_tag('p', form.text_field( + :url, :label => l(:field_path_to_repository), + :size => 60, :required => true, + :disabled => !repository.safe_attribute?('url'))) + + content_tag('p', form.select( + :log_encoding, [nil] + Setting::ENCODINGS, + :label => l(:field_commit_logs_encoding), :required => true)) + end + + def mercurial_field_tags(form, repository) + content_tag('p', form.text_field( + :url, :label => l(:field_path_to_repository), + :size => 60, :required => true, + :disabled => !repository.safe_attribute?('url') + ) + + '
'.html_safe + l(:text_mercurial_repository_note)) + + content_tag('p', form.select( + :path_encoding, [nil] + Setting::ENCODINGS, + :label => l(:field_scm_path_encoding) + ) + + '
'.html_safe + l(:text_scm_path_encoding_note)) + end + + def git_field_tags(form, repository) + content_tag('p', form.text_field( + :url, :label => l(:field_path_to_repository), + :size => 60, :required => true, + :disabled => !repository.safe_attribute?('url') + ) + + '
'.html_safe + + l(:text_git_repository_note)) + + content_tag('p', form.select( + :path_encoding, [nil] + Setting::ENCODINGS, + :label => l(:field_scm_path_encoding) + ) + + '
'.html_safe + l(:text_scm_path_encoding_note)) + + content_tag('p', form.check_box( + :extra_report_last_commit, + :label => l(:label_git_report_last_commit) + )) + end + + def cvs_field_tags(form, repository) + content_tag('p', form.text_field( + :root_url, + :label => l(:field_cvsroot), + :size => 60, :required => true, + :disabled => !repository.safe_attribute?('root_url'))) + + content_tag('p', form.text_field( + :url, + :label => l(:field_cvs_module), + :size => 30, :required => true, + :disabled => !repository.safe_attribute?('url'))) + + content_tag('p', form.select( + :log_encoding, [nil] + Setting::ENCODINGS, + :label => l(:field_commit_logs_encoding), :required => true)) + + content_tag('p', form.select( + :path_encoding, [nil] + Setting::ENCODINGS, + :label => l(:field_scm_path_encoding) + ) + + '
'.html_safe + l(:text_scm_path_encoding_note)) + end + + def bazaar_field_tags(form, repository) + content_tag('p', form.text_field( + :url, :label => l(:field_path_to_repository), + :size => 60, :required => true, + :disabled => !repository.safe_attribute?('url'))) + + content_tag('p', form.select( + :log_encoding, [nil] + Setting::ENCODINGS, + :label => l(:field_commit_logs_encoding), :required => true)) + end + + def filesystem_field_tags(form, repository) + content_tag('p', form.text_field( + :url, :label => l(:field_root_directory), + :size => 60, :required => true, + :disabled => !repository.safe_attribute?('url'))) + + content_tag('p', form.select( + :path_encoding, [nil] + Setting::ENCODINGS, + :label => l(:field_scm_path_encoding) + ) + + '
'.html_safe + l(:text_scm_path_encoding_note)) + end + + def index_commits(commits, heads) + return nil if commits.nil? or commits.first.parents.nil? + refs_map = {} + heads.each do |head| + refs_map[head.scmid] ||= [] + refs_map[head.scmid] << head + end + commits_by_scmid = {} + commits.reverse.each_with_index do |commit, commit_index| + commits_by_scmid[commit.scmid] = { + :parent_scmids => commit.parents.collect { |parent| parent.scmid }, + :rdmid => commit_index, + :refs => refs_map.include?(commit.scmid) ? refs_map[commit.scmid].join(" ") : nil, + :scmid => commit.scmid, + :href => block_given? ? yield(commit.scmid) : commit.scmid + } + end + heads.sort! { |head1, head2| head1.to_s <=> head2.to_s } + space = nil + heads.each do |head| + if commits_by_scmid.include? head.scmid + space = index_head((space || -1) + 1, head, commits_by_scmid) + end + end + # when no head matched anything use first commit + space ||= index_head(0, commits.first, commits_by_scmid) + return commits_by_scmid, space + end + + def index_head(space, commit, commits_by_scmid) + stack = [[space, commits_by_scmid[commit.scmid]]] + max_space = space + until stack.empty? + space, commit = stack.pop + commit[:space] = space if commit[:space].nil? + space -= 1 + commit[:parent_scmids].each_with_index do |parent_scmid, parent_index| + parent_commit = commits_by_scmid[parent_scmid] + if parent_commit and parent_commit[:space].nil? + stack.unshift [space += 1, parent_commit] + end + end + max_space = space if max_space < space + end + max_space + end +end diff --git a/app/helpers/roles_helper.rb b/app/helpers/roles_helper.rb new file mode 100644 index 00000000..44fea58d --- /dev/null +++ b/app/helpers/roles_helper.rb @@ -0,0 +1,21 @@ +# encoding: utf-8 +# +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +module RolesHelper +end diff --git a/app/helpers/routes_helper.rb b/app/helpers/routes_helper.rb new file mode 100644 index 00000000..15c80996 --- /dev/null +++ b/app/helpers/routes_helper.rb @@ -0,0 +1,39 @@ +# encoding: utf-8 +# +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +module RoutesHelper + + # Returns the path to project issues or to the cross-project + # issue list if project is nil + def _project_issues_path(project, *args) + if project + project_issues_path(project, *args) + else + issues_path(*args) + end + end + + def _project_calendar_path(project, *args) + project ? project_calendar_path(project, *args) : issues_calendar_path(*args) + end + + def _project_gantt_path(project, *args) + project ? project_gantt_path(project, *args) : issues_gantt_path(*args) + end +end diff --git a/app/helpers/search_helper.rb b/app/helpers/search_helper.rb new file mode 100644 index 00000000..e44c5f8a --- /dev/null +++ b/app/helpers/search_helper.rb @@ -0,0 +1,70 @@ +# encoding: utf-8 +# +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +module SearchHelper + def highlight_tokens(text, tokens) + return text unless text && tokens && !tokens.empty? + re_tokens = tokens.collect {|t| Regexp.escape(t)} + regexp = Regexp.new "(#{re_tokens.join('|')})", Regexp::IGNORECASE + result = '' + text.split(regexp).each_with_index do |words, i| + if result.length > 1200 + # maximum length of the preview reached + result << '...' + break + end + words = words.mb_chars + if i.even? + result << h(words.length > 100 ? "#{words.slice(0..44)} ... #{words.slice(-45..-1)}" : words) + else + t = (tokens.index(words.downcase) || 0) % 4 + result << content_tag('span', h(words), :class => "highlight token-#{t}") + end + end + result.html_safe + end + + def type_label(t) + l("label_#{t.singularize}_plural", :default => t.to_s.humanize) + end + + def project_select_tag + options = [[l(:label_project_all), 'all']] + options << [l(:label_my_projects), 'my_projects'] unless User.current.memberships.empty? + options << [l(:label_and_its_subprojects, @project.name), 'subprojects'] unless @project.nil? || @project.descendants.active.empty? + options << [@project.name, ''] unless @project.nil? + label_tag("scope", l(:description_project_scope), :class => "hidden-for-sighted") + + select_tag('scope', options_for_select(options, params[:scope].to_s)) if options.size > 1 + end + + def render_results_by_type(results_by_type) + links = [] + # Sorts types by results count + results_by_type.keys.sort {|a, b| results_by_type[b] <=> results_by_type[a]}.each do |t| + c = results_by_type[t] + next if c == 0 + text = "#{type_label(t)} (#{c})" + links << link_to(h(text), :q => params[:q], :titles_only => params[:titles_only], + :all_words => params[:all_words], :scope => params[:scope], t => 1) + end + ('
    '.html_safe + + links.map {|link| content_tag('li', link)}.join(' ').html_safe + + '
'.html_safe) unless links.empty? + end +end diff --git a/app/helpers/settings_helper.rb b/app/helpers/settings_helper.rb new file mode 100644 index 00000000..a01e29a3 --- /dev/null +++ b/app/helpers/settings_helper.rb @@ -0,0 +1,106 @@ +# encoding: utf-8 +# +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +module SettingsHelper + def administration_settings_tabs + tabs = [{:name => 'general', :partial => 'settings/general', :label => :label_general}, + {:name => 'display', :partial => 'settings/display', :label => :label_display}, + {:name => 'authentication', :partial => 'settings/authentication', :label => :label_authentication}, + {:name => 'projects', :partial => 'settings/projects', :label => :label_project_plural}, + {:name => 'issues', :partial => 'settings/issues', :label => :label_issue_tracking}, + {:name => 'notifications', :partial => 'settings/notifications', :label => :field_mail_notification}, + {:name => 'mail_handler', :partial => 'settings/mail_handler', :label => :label_incoming_emails}, + {:name => 'repositories', :partial => 'settings/repositories', :label => :label_repository_plural} + ] + end + + def setting_select(setting, choices, options={}) + if blank_text = options.delete(:blank) + choices = [[blank_text.is_a?(Symbol) ? l(blank_text) : blank_text, '']] + choices + end + setting_label(setting, options).html_safe + + select_tag("settings[#{setting}]", + options_for_select(choices, Setting.send(setting).to_s), + options).html_safe + end + + def setting_multiselect(setting, choices, options={}) + setting_values = Setting.send(setting) + setting_values = [] unless setting_values.is_a?(Array) + + content_tag("label", l(options[:label] || "setting_#{setting}")) + + hidden_field_tag("settings[#{setting}][]", '').html_safe + + choices.collect do |choice| + text, value = (choice.is_a?(Array) ? choice : [choice, choice]) + content_tag( + 'label', + check_box_tag( + "settings[#{setting}][]", + value, + setting_values.include?(value), + :id => nil + ) + text.to_s, + :class => (options[:inline] ? 'inline' : 'block') + ) + end.join.html_safe + end + + def setting_text_field(setting, options={}) + setting_label(setting, options).html_safe + + text_field_tag("settings[#{setting}]", Setting.send(setting), options).html_safe + end + + def setting_text_area(setting, options={}) + setting_label(setting, options).html_safe + + text_area_tag("settings[#{setting}]", Setting.send(setting), options).html_safe + end + + def setting_check_box(setting, options={}) + setting_label(setting, options).html_safe + + hidden_field_tag("settings[#{setting}]", 0, :id => nil).html_safe + + check_box_tag("settings[#{setting}]", 1, Setting.send("#{setting}?"), options).html_safe + end + + def setting_label(setting, options={}) + label = options.delete(:label) + label != false ? label_tag("settings_#{setting}", l(label || "setting_#{setting}")).html_safe : '' + end + + # Renders a notification field for a Redmine::Notifiable option + def notification_field(notifiable) + return content_tag(:label, + check_box_tag('settings[notified_events][]', + notifiable.name, + Setting.notified_events.include?(notifiable.name), :id => nil).html_safe + + l_or_humanize(notifiable.name, :prefix => 'label_').html_safe, + :class => notifiable.parent.present? ? "parent" : '').html_safe + end + + def cross_project_subtasks_options + options = [ + [:label_disabled, ''], + [:label_cross_project_system, 'system'], + [:label_cross_project_tree, 'tree'], + [:label_cross_project_hierarchy, 'hierarchy'], + [:label_cross_project_descendants, 'descendants'] + ] + + options.map {|label, value| [l(label), value.to_s]} + end +end diff --git a/app/helpers/sort_helper.rb b/app/helpers/sort_helper.rb new file mode 100644 index 00000000..13beed3c --- /dev/null +++ b/app/helpers/sort_helper.rb @@ -0,0 +1,243 @@ +# encoding: utf-8 +# +# Helpers to sort tables using clickable column headers. +# +# Author: Stuart Rackham , March 2005. +# Jean-Philippe Lang, 2009 +# License: This source code is released under the MIT license. +# +# - Consecutive clicks toggle the column's sort order. +# - Sort state is maintained by a session hash entry. +# - CSS classes identify sort column and state. +# - Typically used in conjunction with the Pagination module. +# +# Example code snippets: +# +# Controller: +# +# helper :sort +# include SortHelper +# +# def list +# sort_init 'last_name' +# sort_update %w(first_name last_name) +# @items = Contact.find_all nil, sort_clause +# end +# +# Controller (using Pagination module): +# +# helper :sort +# include SortHelper +# +# def list +# sort_init 'last_name' +# sort_update %w(first_name last_name) +# @contact_pages, @items = paginate :contacts, +# :order_by => sort_clause, +# :per_page => 10 +# end +# +# View (table header in list.rhtml): +# +# +# +# <%= sort_header_tag('id', :title => 'Sort by contact ID') %> +# <%= sort_header_tag('last_name', :caption => 'Name') %> +# <%= sort_header_tag('phone') %> +# <%= sort_header_tag('address', :width => 200) %> +# +# +# +# - Introduces instance variables: @sort_default, @sort_criteria +# - Introduces param :sort +# + +module SortHelper + class SortCriteria + + def initialize + @criteria = [] + end + + def available_criteria=(criteria) + unless criteria.is_a?(Hash) + criteria = criteria.inject({}) {|h,k| h[k] = k; h} + end + @available_criteria = criteria + end + + def from_param(param) + @criteria = param.to_s.split(',').collect {|s| s.split(':')[0..1]} + normalize! + end + + def criteria=(arg) + @criteria = arg + normalize! + end + + def to_param + @criteria.collect {|k,o| k + (o ? '' : ':desc')}.join(',') + end + + # Returns an array of SQL fragments used to sort the list + def to_sql + sql = @criteria.collect do |k,o| + if s = @available_criteria[k] + (o ? s.to_a : s.to_a.collect {|c| append_desc(c)}) + end + end.flatten.compact + sql.blank? ? nil : sql + end + + def to_a + @criteria.dup + end + + def add!(key, asc) + @criteria.delete_if {|k,o| k == key} + @criteria = [[key, asc]] + @criteria + normalize! + end + + def add(*args) + r = self.class.new.from_param(to_param) + r.add!(*args) + r + end + + def first_key + @criteria.first && @criteria.first.first + end + + def first_asc? + @criteria.first && @criteria.first.last + end + + def empty? + @criteria.empty? + end + + private + + def normalize! + @criteria ||= [] + @criteria = @criteria.collect {|s| s = s.to_a; [s.first, (s.last == false || s.last == 'desc') ? false : true]} + @criteria = @criteria.select {|k,o| @available_criteria.has_key?(k)} if @available_criteria + @criteria.slice!(3) + self + end + + # Appends DESC to the sort criterion unless it has a fixed order + def append_desc(criterion) + if criterion =~ / (asc|desc)$/i + criterion + else + "#{criterion} DESC" + end + end + end + + def sort_name + controller_name + '_' + action_name + '_sort' + end + + # Initializes the default sort. + # Examples: + # + # sort_init 'name' + # sort_init 'id', 'desc' + # sort_init ['name', ['id', 'desc']] + # sort_init [['name', 'desc'], ['id', 'desc']] + # + def sort_init(*args) + case args.size + when 1 + @sort_default = args.first.is_a?(Array) ? args.first : [[args.first]] + when 2 + @sort_default = [[args.first, args.last]] + else + raise ArgumentError + end + end + + # Updates the sort state. Call this in the controller prior to calling + # sort_clause. + # - criteria can be either an array or a hash of allowed keys + # + def sort_update(criteria, sort_name=nil) + sort_name ||= self.sort_name + @sort_criteria = SortCriteria.new + @sort_criteria.available_criteria = criteria + @sort_criteria.from_param(params[:sort] || session[sort_name]) + @sort_criteria.criteria = @sort_default if @sort_criteria.empty? + session[sort_name] = @sort_criteria.to_param + end + + # Clears the sort criteria session data + # + def sort_clear + session[sort_name] = nil + end + + # Returns an SQL sort clause corresponding to the current sort state. + # Use this to sort the controller's table items collection. + # + def sort_clause() + @sort_criteria.to_sql + end + + def sort_criteria + @sort_criteria + end + + # Returns a link which sorts by the named column. + # + # - column is the name of an attribute in the sorted record collection. + # - the optional caption explicitly specifies the displayed link text. + # - 2 CSS classes reflect the state of the link: sort and asc or desc + # + def sort_link(column, caption, default_order) + css, order = nil, default_order + + if column.to_s == @sort_criteria.first_key + if @sort_criteria.first_asc? + css = 'sort asc' + order = 'desc' + else + css = 'sort desc' + order = 'asc' + end + end + caption = column.to_s.humanize unless caption + + sort_options = { :sort => @sort_criteria.add(column.to_s, order).to_param } + url_options = params.merge(sort_options) + + # Add project_id to url_options + url_options = url_options.merge(:project_id => params[:project_id]) if params.has_key?(:project_id) + + link_to_content_update(h(caption), url_options, :class => css) + end + + # Returns a table header tag with a sort link for the named column + # attribute. + # + # Options: + # :caption The displayed link name (defaults to titleized column name). + # :title The tag's 'title' attribute (defaults to 'Sort by :caption'). + # + # Other options hash entries generate additional table header tag attributes. + # + # Example: + # + # <%= sort_header_tag('id', :title => 'Sort by contact ID', :width => 40) %> + # + def sort_header_tag(column, options = {}) + caption = options.delete(:caption) || column.to_s.humanize + default_order = options.delete(:default_order) || 'asc' + options[:title] = l(:label_sort_by, "\"#{caption}\"") unless options[:title] + content_tag('th', sort_link(column, caption, default_order), options) + end +end + diff --git a/app/helpers/test_helper.rb b/app/helpers/test_helper.rb new file mode 100644 index 00000000..38f67911 --- /dev/null +++ b/app/helpers/test_helper.rb @@ -0,0 +1,31 @@ +########fq +module TestHelper + def message_list(object) + object = object.reverse + remove_allowed = (User.current.id == object.first.user_id) + content = ''.html_safe + lis = object.each do |t_object| + s = ''.html_safe + s << avatar(t_object.user, :size => "16").to_s + s << link_to_user(t_object.find_messager.first, :class => 'user') + s << ':' + t_object.message + #time = '更新于' + time_tag(t_object.created_at) + '之前' + time = time_tag(t_object.created_at) + #s << content_tag('p', l(:field_add, time)) + s << content_tag('div', time) + if remove_allowed + url = {:controller => 'test', + :action => 'destroy', + :object_id => t_object.id, + :user_id => User.current.id} + s << ' ' + s << link_to(image_tag('delete.png'), url, + :remote => true, :method => 'delete', :class => "delete") + end + content << content_tag('li', s, :class => "user-#{t_object.messager_id}") + end + # content.present? ? content_tag('ul', content, :class => 'watchers') : content + content + end +end + \ No newline at end of file diff --git a/app/helpers/timelog_helper.rb b/app/helpers/timelog_helper.rb new file mode 100644 index 00000000..cf5629f5 --- /dev/null +++ b/app/helpers/timelog_helper.rb @@ -0,0 +1,154 @@ +# encoding: utf-8 +# +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +module TimelogHelper + include ApplicationHelper + + def render_timelog_breadcrumb + links = [] + links << link_to(l(:label_project_all), {:project_id => nil, :issue_id => nil}) + links << link_to(h(@project), {:project_id => @project, :issue_id => nil}) if @project + if @issue + if @issue.visible? + links << link_to_issue(@issue, :subject => false) + else + links << "##{@issue.id}" + end + end + breadcrumb links + end + + # Returns a collection of activities for a select field. time_entry + # is optional and will be used to check if the selected TimeEntryActivity + # is active. + def activity_collection_for_select_options(time_entry=nil, project=nil) + project ||= @project + if project.nil? + activities = TimeEntryActivity.shared.active + else + activities = project.activities + end + + collection = [] + if time_entry && time_entry.activity && !time_entry.activity.active? + collection << [ "--- #{l(:actionview_instancetag_blank_option)} ---", '' ] + else + collection << [ "--- #{l(:actionview_instancetag_blank_option)} ---", '' ] unless activities.detect(&:is_default) + end + activities.each { |a| collection << [a.name, a.id] } + collection + end + + def select_hours(data, criteria, value) + if value.to_s.empty? + data.select {|row| row[criteria].blank? } + else + data.select {|row| row[criteria].to_s == value.to_s} + end + end + + def sum_hours(data) + sum = 0 + data.each do |row| + sum += row['hours'].to_f + end + sum + end + + def options_for_period_select(value) + options_for_select([[l(:label_all_time), 'all'], + [l(:label_today), 'today'], + [l(:label_yesterday), 'yesterday'], + [l(:label_this_week), 'current_week'], + [l(:label_last_week), 'last_week'], + [l(:label_last_n_weeks, 2), 'last_2_weeks'], + [l(:label_last_n_days, 7), '7_days'], + [l(:label_this_month), 'current_month'], + [l(:label_last_month), 'last_month'], + [l(:label_last_n_days, 30), '30_days'], + [l(:label_this_year), 'current_year']], + value) + end + + def format_criteria_value(criteria_options, value) + if value.blank? + "[#{l(:label_none)}]" + elsif k = criteria_options[:klass] + obj = k.find_by_id(value.to_i) + if obj.is_a?(Issue) + obj.visible? ? "#{obj.tracker} ##{obj.id}: #{obj.subject}" : "##{obj.id}" + else + obj + end + else + format_value(value, criteria_options[:format]) + end + end + + def report_to_csv(report) + decimal_separator = l(:general_csv_decimal_separator) + export = FCSV.generate(:col_sep => l(:general_csv_separator)) do |csv| + # Column headers + headers = report.criteria.collect {|criteria| l(report.available_criteria[criteria][:label]) } + headers += report.periods + headers << l(:label_total_time) + csv << headers.collect {|c| Redmine::CodesetUtil.from_utf8( + c.to_s, + l(:general_csv_encoding) ) } + # Content + report_criteria_to_csv(csv, report.available_criteria, report.columns, report.criteria, report.periods, report.hours) + # Total row + str_total = Redmine::CodesetUtil.from_utf8(l(:label_total_time), l(:general_csv_encoding)) + row = [ str_total ] + [''] * (report.criteria.size - 1) + total = 0 + report.periods.each do |period| + sum = sum_hours(select_hours(report.hours, report.columns, period.to_s)) + total += sum + row << (sum > 0 ? ("%.2f" % sum).gsub('.',decimal_separator) : '') + end + row << ("%.2f" % total).gsub('.',decimal_separator) + csv << row + end + export + end + + def report_criteria_to_csv(csv, available_criteria, columns, criteria, periods, hours, level=0) + decimal_separator = l(:general_csv_decimal_separator) + hours.collect {|h| h[criteria[level]].to_s}.uniq.each do |value| + hours_for_value = select_hours(hours, criteria[level], value) + next if hours_for_value.empty? + row = [''] * level + row << Redmine::CodesetUtil.from_utf8( + format_criteria_value(available_criteria[criteria[level]], value).to_s, + l(:general_csv_encoding) ) + row += [''] * (criteria.length - level - 1) + total = 0 + periods.each do |period| + sum = sum_hours(select_hours(hours_for_value, columns, period.to_s)) + total += sum + row << (sum > 0 ? ("%.2f" % sum).gsub('.',decimal_separator) : '') + end + row << ("%.2f" % total).gsub('.',decimal_separator) + csv << row + if criteria.length > level + 1 + report_criteria_to_csv(csv, available_criteria, columns, criteria, periods, hours_for_value, level + 1) + end + end + end +end diff --git a/app/helpers/trackers_helper.rb b/app/helpers/trackers_helper.rb new file mode 100644 index 00000000..6b0e7b61 --- /dev/null +++ b/app/helpers/trackers_helper.rb @@ -0,0 +1,21 @@ +# encoding: utf-8 +# +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +module TrackersHelper +end diff --git a/app/helpers/users_helper.rb b/app/helpers/users_helper.rb new file mode 100644 index 00000000..9b6f85d2 --- /dev/null +++ b/app/helpers/users_helper.rb @@ -0,0 +1,64 @@ +# encoding: utf-8 +# +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + + +include AvatarHelper +module UsersHelper + def users_status_options_for_select(selected) + user_count_by_status = User.count(:group => 'status').to_hash + options_for_select([[l(:label_all), ''], + ["#{l(:status_active)} (#{user_count_by_status[1].to_i})", '1'], + ["#{l(:status_registered)} (#{user_count_by_status[2].to_i})", '2'], + ["#{l(:status_locked)} (#{user_count_by_status[3].to_i})", '3']], selected.to_s) + end + + def user_mail_notification_options(user) + user.valid_notification_options.collect {|o| [l(o.last), o.first]} + end + + def change_status_link(user) + url = {:controller => 'users', :action => 'update', :id => user, :page => params[:page], :status => params[:status], :tab => nil} + + if user.locked? + link_to l(:button_unlock), url.merge(:user => {:status => User::STATUS_ACTIVE}), :method => :put, :class => 'icon icon-unlock' + elsif user.registered? + link_to l(:button_activate), url.merge(:user => {:status => User::STATUS_ACTIVE}), :method => :put, :class => 'icon icon-unlock' + elsif user != User.current + link_to l(:button_lock), url.merge(:user => {:status => User::STATUS_LOCKED}), :method => :put, :class => 'icon icon-lock' + end + end + + def user_settings_tabs + tabs = [{:name => 'general', :partial => 'users/general', :label => :label_general}, + {:name => 'memberships', :partial => 'users/memberships', :label => :label_project_plural} + ] + if Group.all.any? + tabs.insert 1, {:name => 'groups', :partial => 'users/groups', :label => :label_group_plural} + end + tabs + end + + # this method is used to get all projects that tagged one tag + # added by william + def get_users_by_tag(tag_name) + User.tagged_with(tag_name) + end + +end diff --git a/app/helpers/versions_helper.rb b/app/helpers/versions_helper.rb new file mode 100644 index 00000000..61cb382c --- /dev/null +++ b/app/helpers/versions_helper.rb @@ -0,0 +1,57 @@ +# encoding: utf-8 +# +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +module VersionsHelper + + def version_anchor(version) + if @project == version.project + anchor version.name + else + anchor "#{version.project.try(:identifier)}-#{version.name}" + end + end + + STATUS_BY_CRITERIAS = %w(tracker status priority author assigned_to category) + + def render_issue_status_by(version, criteria) + criteria = 'tracker' unless STATUS_BY_CRITERIAS.include?(criteria) + + h = Hash.new {|k,v| k[v] = [0, 0]} + begin + # Total issue count + Issue.count(:group => criteria, + :conditions => ["#{Issue.table_name}.fixed_version_id = ?", version.id]).each {|c,s| h[c][0] = s} + # Open issues count + Issue.count(:group => criteria, + :include => :status, + :conditions => ["#{Issue.table_name}.fixed_version_id = ? AND #{IssueStatus.table_name}.is_closed = ?", version.id, false]).each {|c,s| h[c][1] = s} + rescue ActiveRecord::RecordNotFound + # When grouping by an association, Rails throws this exception if there's no result (bug) + end + # Sort with nil keys in last position + counts = h.keys.sort {|a,b| a.nil? ? 1 : (b.nil? ? -1 : a <=> b)}.collect {|k| {:group => k, :total => h[k][0], :open => h[k][1], :closed => (h[k][0] - h[k][1])}} + max = counts.collect {|c| c[:total]}.max + + render :partial => 'issue_counts', :locals => {:version => version, :criteria => criteria, :counts => counts, :max => max} + end + + def status_by_options_for_select(value) + options_for_select(STATUS_BY_CRITERIAS.collect {|criteria| [l("field_#{criteria}".to_sym), criteria]}, value) + end +end diff --git a/app/helpers/watchers_helper.rb b/app/helpers/watchers_helper.rb new file mode 100644 index 00000000..eef4ab73 --- /dev/null +++ b/app/helpers/watchers_helper.rb @@ -0,0 +1,86 @@ +# encoding: utf-8 +# +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +module WatchersHelper + + def watcher_tag(object, user, options={}) + ActiveSupport::Deprecation.warn "#watcher_tag is deprecated and will be removed in Redmine 3.0. Use #watcher_link instead." + watcher_link(object, user) + end + + ###################modified by liuping + def watcher_link(objects, user) + return '' unless user && user.logged? + objects = Array.wrap(objects) + + watched = objects.any? {|object| object.watched_by?(user)} + css = [watcher_css(objects), watched ? 'icon icon-fav' : 'icon icon-fav-off'].join(' ') + + text = (objects.first.instance_of?(User) or objects.first.instance_of?(Project)) ? + (watched ? l(:button_unfollow) : l(:button_follow)) : (watched ? l(:button_unwatch) : l(:button_watch)) + + url = watch_path( + :object_type => objects.first.class.to_s.underscore, + :object_id => (objects.size == 1 ? objects.first.id : objects.map(&:id).sort) + ) + method = watched ? 'delete' : 'post' + + link_to text, url, :remote => true, :method => method, :class => css + end + + # Returns the css class used to identify watch links for a given +object+ + def watcher_css(objects) + objects = Array.wrap(objects) + id = (objects.size == 1 ? objects.first.id : 'bulk') + "#{objects.first.class.to_s.underscore}-#{id}-watcher" + end + + # Returns a comma separated list of users watching the given object + def watchers_list(object) + remove_allowed = User.current.allowed_to?("delete_#{object.class.name.underscore}_watchers".to_sym, object.project) + content = ''.html_safe + lis = object.watcher_users.collect do |user| + s = ''.html_safe + s << avatar(user, :size => "16").to_s + s << link_to_user(user, :class => 'user') + if remove_allowed + url = {:controller => 'watchers', + :action => 'destroy', + :object_type => object.class.to_s.underscore, + :object_id => object.id, + :user_id => user} + s << ' ' + s << link_to(image_tag('delete.png'), url, + :remote => true, :method => 'delete', :class => "delete") + end + content << content_tag('li', s, :class => "user-#{user.id}") + end + content.present? ? content_tag('ul', content, :class => 'watchers') : content + end + + def watchers_checkboxes(object, users, checked=nil) + users.map do |user| + c = checked.nil? ? object.watched_by?(user) : checked + tag = check_box_tag 'issue[watcher_user_ids][]', user.id, c, :id => nil + content_tag 'label', "#{tag} #{h(user)}".html_safe, + :id => "issue_watcher_user_ids_#{user.id}", + :class => "floating" + end.join.html_safe + end +end diff --git a/app/helpers/welcome_helper.rb b/app/helpers/welcome_helper.rb new file mode 100644 index 00000000..002bc470 --- /dev/null +++ b/app/helpers/welcome_helper.rb @@ -0,0 +1,21 @@ +# encoding: utf-8 +# +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +module WelcomeHelper +end diff --git a/app/helpers/wiki_helper.rb b/app/helpers/wiki_helper.rb new file mode 100644 index 00000000..c6cb3b39 --- /dev/null +++ b/app/helpers/wiki_helper.rb @@ -0,0 +1,43 @@ +# encoding: utf-8 +# +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +module WikiHelper + + def wiki_page_options_for_select(pages, selected = nil, parent = nil, level = 0) + pages = pages.group_by(&:parent) unless pages.is_a?(Hash) + s = ''.html_safe + if pages.has_key?(parent) + pages[parent].each do |page| + attrs = "value='#{page.id}'" + attrs << " selected='selected'" if selected == page + indent = (level > 0) ? (' ' * level * 2 + '» ') : '' + + s << content_tag('option', (indent + h(page.pretty_title)).html_safe, :value => page.id.to_s, :selected => selected == page) + + wiki_page_options_for_select(pages, selected, page, level + 1) + end + end + s + end + + def wiki_page_breadcrumb(page) + breadcrumb(page.ancestors.reverse.collect {|parent| + link_to(h(parent.pretty_title), {:controller => 'wiki', :action => 'show', :id => parent.title, :project_id => parent.project, :version => nil}) + }) + end +end diff --git a/app/helpers/words_helper.rb b/app/helpers/words_helper.rb new file mode 100644 index 00000000..167c78e2 --- /dev/null +++ b/app/helpers/words_helper.rb @@ -0,0 +1,47 @@ +########fq +module WordsHelper + def message_list(object, state, user) + unless state + if object.size > 5 + object = object[-5, 5] + end + end + object = object.reverse + remove_allowed = (User.current.id == object.first.user_id) + content = ''.html_safe + lis = object.each do |t_object| + s = ''.html_safe + s << link_to(t_object.indice, {}, :class => "journal-link") + s << avatar(t_object.user, :size => "16").to_s + s << link_to_user(t_object.user, :class => 'user') + time = time_tag(t_object.created_at) + s << l(:field_add, :time => time).html_safe + if !t_object.notes.blank? + s << link_to(image_tag('comment.png'), + {:controller => 'words', :action => 'new', :id => user, :journal_id => t_object}, + :remote => true, + :method => 'post', + :title => l(:button_quote)) + if remove_allowed || t_object.jour_id == User.current.id + url = {:controller => 'words', + :action => 'destroy', + :object_id => t_object, + :user_id => user} + s << ' ' + s << link_to(image_tag('delete.png'), url, + :remote => true, :method => 'delete', :class => "delete", :title => l(:button_delete)) + end + end + #time = '更新于' + time_tag(t_object.created_at) + '之前' + + + # s << content_tag('div', time) + + content << content_tag('li', s, :class => "user-#{t_object.jour_id}") + content << textilizable(t_object.notes) + end + # content.present? ? content_tag('ul', content, :class => 'watchers') : content + content + end +end + \ No newline at end of file diff --git a/app/helpers/workflows_helper.rb b/app/helpers/workflows_helper.rb new file mode 100644 index 00000000..1cec67a8 --- /dev/null +++ b/app/helpers/workflows_helper.rb @@ -0,0 +1,32 @@ +# encoding: utf-8 +# +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +module WorkflowsHelper + def field_required?(field) + field.is_a?(CustomField) ? field.is_required? : %w(project_id tracker_id subject priority_id is_private).include?(field) + end + + def field_permission_tag(permissions, status, field) + name = field.is_a?(CustomField) ? field.id.to_s : field + options = [["", ""], [l(:label_readonly), "readonly"]] + options << [l(:label_required), "required"] unless field_required?(field) + + select_tag("permissions[#{name}][#{status.id}]", options_for_select(options, permissions[status.id][name])) + end +end diff --git a/app/models/attachment.rb b/app/models/attachment.rb new file mode 100644 index 00000000..eeab5624 --- /dev/null +++ b/app/models/attachment.rb @@ -0,0 +1,326 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +require "digest/md5" +require "fileutils" + +class Attachment < ActiveRecord::Base + belongs_to :container, :polymorphic => true + belongs_to :author, :class_name => "User", :foreign_key => "author_id" + + validates_presence_of :filename, :author + validates_length_of :filename, :maximum => 255 + validates_length_of :disk_filename, :maximum => 255 + validates_length_of :description, :maximum => 255 + validate :validate_max_file_size + + acts_as_event :title => :filename, + :url => Proc.new {|o| {:controller => 'attachments', :action => 'download', :id => o.id, :filename => o.filename}} + + acts_as_activity_provider :type => 'files', + :permission => :view_files, + :author_key => :author_id, + :find_options => {:select => "#{Attachment.table_name}.*", + :joins => "LEFT JOIN #{Version.table_name} ON #{Attachment.table_name}.container_type='Version' AND #{Version.table_name}.id = #{Attachment.table_name}.container_id " + + "LEFT JOIN #{Project.table_name} ON #{Version.table_name}.project_id = #{Project.table_name}.id OR ( #{Attachment.table_name}.container_type='Project' AND #{Attachment.table_name}.container_id = #{Project.table_name}.id )"} + + acts_as_activity_provider :type => 'documents', + :permission => :view_documents, + :author_key => :author_id, + :find_options => {:select => "#{Attachment.table_name}.*", + :joins => "LEFT JOIN #{Document.table_name} ON #{Attachment.table_name}.container_type='Document' AND #{Document.table_name}.id = #{Attachment.table_name}.container_id " + + "LEFT JOIN #{Project.table_name} ON #{Document.table_name}.project_id = #{Project.table_name}.id"} + + cattr_accessor :storage_path + @@storage_path = Redmine::Configuration['attachments_storage_path'] || File.join(Rails.root, "files") + + cattr_accessor :thumbnails_storage_path + @@thumbnails_storage_path = File.join(Rails.root, "tmp", "thumbnails") + + before_save :files_to_final_location + after_destroy :delete_from_disk + + # Returns an unsaved copy of the attachment + def copy(attributes=nil) + copy = self.class.new + copy.attributes = self.attributes.dup.except("id", "downloads") + copy.attributes = attributes if attributes + copy + end + + def validate_max_file_size + if @temp_file && self.filesize > Setting.attachment_max_size.to_i.kilobytes + errors.add(:base, l(:error_attachment_too_big, :max_size => Setting.attachment_max_size.to_i.kilobytes)) + end + end + + def file=(incoming_file) + unless incoming_file.nil? + @temp_file = incoming_file + if @temp_file.size > 0 + if @temp_file.respond_to?(:original_filename) + self.filename = @temp_file.original_filename + self.filename.force_encoding("UTF-8") if filename.respond_to?(:force_encoding) + end + if @temp_file.respond_to?(:content_type) + self.content_type = @temp_file.content_type.to_s.chomp + end + if content_type.blank? && filename.present? + self.content_type = Redmine::MimeType.of(filename) + end + self.filesize = @temp_file.size + end + end + end + + def file + nil + end + + def filename=(arg) + write_attribute :filename, sanitize_filename(arg.to_s) + filename + end + + # Copies the temporary file to its final location + # and computes its MD5 hash + def files_to_final_location + if @temp_file && (@temp_file.size > 0) + self.disk_directory = target_directory + self.disk_filename = Attachment.disk_filename(filename, disk_directory) + logger.info("Saving attachment '#{self.diskfile}' (#{@temp_file.size} bytes)") + path = File.dirname(diskfile) + unless File.directory?(path) + FileUtils.mkdir_p(path) + end + md5 = Digest::MD5.new + File.open(diskfile, "wb") do |f| + if @temp_file.respond_to?(:read) + buffer = "" + while (buffer = @temp_file.read(8192)) + f.write(buffer) + md5.update(buffer) + end + else + f.write(@temp_file) + md5.update(@temp_file) + end + end + self.digest = md5.hexdigest + end + @temp_file = nil + # Don't save the content type if it's longer than the authorized length + if self.content_type && self.content_type.length > 255 + self.content_type = nil + end + end + + # Deletes the file from the file system if it's not referenced by other attachments + def delete_from_disk + if Attachment.where("disk_filename = ? AND id <> ?", disk_filename, id).empty? + delete_from_disk! + end + end + + # Returns file's location on disk + def diskfile + File.join(self.class.storage_path, disk_directory.to_s, disk_filename.to_s) + end + + def title + title = filename.to_s + if description.present? + title << " (#{description})" + end + title + end + + def increment_download + increment!(:downloads) + end + + def project + container.try(:project) + end + + def visible?(user=User.current) + if container_id + container && container.attachments_visible?(user) + else + author == user + end + end + + def deletable?(user=User.current) + if container_id + container && container.attachments_deletable?(user) + else + author == user + end + end + + def image? + !!(self.filename =~ /\.(bmp|gif|jpg|jpe|jpeg|png)$/i) + end + + def thumbnailable? + image? + end + + # Returns the full path the attachment thumbnail, or nil + # if the thumbnail cannot be generated. + def thumbnail(options={}) + if thumbnailable? && readable? + size = options[:size].to_i + if size > 0 + # Limit the number of thumbnails per image + size = (size / 50) * 50 + # Maximum thumbnail size + size = 800 if size > 800 + else + size = Setting.thumbnails_size.to_i + end + size = 100 unless size > 0 + target = File.join(self.class.thumbnails_storage_path, "#{id}_#{digest}_#{size}.thumb") + + begin + Redmine::Thumbnail.generate(self.diskfile, target, size) + rescue => e + logger.error "An error occured while generating thumbnail for #{disk_filename} to #{target}\nException was: #{e.message}" if logger + return nil + end + end + end + + # Deletes all thumbnails + def self.clear_thumbnails + Dir.glob(File.join(thumbnails_storage_path, "*.thumb")).each do |file| + File.delete file + end + end + + def is_text? + Redmine::MimeType.is_type?('text', filename) + end + + def is_diff? + self.filename =~ /\.(patch|diff)$/i + end + + # Returns true if the file is readable + def readable? + File.readable?(diskfile) + end + + # Returns the attachment token + def token + "#{id}.#{digest}" + end + + # Finds an attachment that matches the given token and that has no container + def self.find_by_token(token) + if token.to_s =~ /^(\d+)\.([0-9a-f]+)$/ + attachment_id, attachment_digest = $1, $2 + attachment = Attachment.where(:id => attachment_id, :digest => attachment_digest).first + if attachment && attachment.container.nil? + attachment + end + end + end + + # Bulk attaches a set of files to an object + # + # Returns a Hash of the results: + # :files => array of the attached files + # :unsaved => array of the files that could not be attached + def self.attach_files(obj, attachments) + result = obj.save_attachments(attachments, User.current) + obj.attach_saved_attachments + result + end + + def self.latest_attach(attachments, filename) + attachments.sort_by(&:created_on).reverse.detect { + |att| att.filename.downcase == filename.downcase + } + end + + def self.prune(age=1.day) + Attachment.where("created_on < ? AND (container_type IS NULL OR container_type = '')", Time.now - age).destroy_all + end + + # Moves an existing attachment to its target directory + def move_to_target_directory! + if !new_record? & readable? + src = diskfile + self.disk_directory = target_directory + dest = diskfile + if src != dest && FileUtils.mkdir_p(File.dirname(dest)) && FileUtils.mv(src, dest) + update_column :disk_directory, disk_directory + end + end + end + + # Moves existing attachments that are stored at the root of the files + # directory (ie. created before Redmine 2.3) to their target subdirectories + def self.move_from_root_to_target_directory + Attachment.where("disk_directory IS NULL OR disk_directory = ''").find_each do |attachment| + attachment.move_to_target_directory! + end + end + + private + + # Physically deletes the file from the file system + def delete_from_disk! + if disk_filename.present? && File.exist?(diskfile) + File.delete(diskfile) + end + end + + def sanitize_filename(value) + # get only the filename, not the whole path + just_filename = value.gsub(/^.*(\\|\/)/, '') + + # Finally, replace invalid characters with underscore + @filename = just_filename.gsub(/[\/\?\%\*\:\|\"\'<>]+/, '_') + end + + # Returns the subdirectory in which the attachment will be saved + def target_directory + time = created_on || DateTime.now + time.strftime("%Y/%m") + end + + # Returns an ASCII or hashed filename that do not + # exists yet in the given subdirectory + def self.disk_filename(filename, directory=nil) + timestamp = DateTime.now.strftime("%y%m%d%H%M%S") + ascii = '' + if filename =~ %r{^[a-zA-Z0-9_\.\-]*$} + ascii = filename + else + ascii = Digest::MD5.hexdigest(filename) + # keep the extension if any + ascii << $1 if filename =~ %r{(\.[a-zA-Z0-9]+)$} + end + while File.exist?(File.join(storage_path, directory.to_s, "#{timestamp}_#{ascii}")) + timestamp.succ! + end + "#{timestamp}_#{ascii}" + end +end diff --git a/app/models/auth_source.rb b/app/models/auth_source.rb new file mode 100644 index 00000000..0b4db9bc --- /dev/null +++ b/app/models/auth_source.rb @@ -0,0 +1,92 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +# Generic exception for when the AuthSource can not be reached +# (eg. can not connect to the LDAP) +class AuthSourceException < Exception; end +class AuthSourceTimeoutException < AuthSourceException; end + +class AuthSource < ActiveRecord::Base + include Redmine::SubclassFactory + include Redmine::Ciphering + + has_many :users + + validates_presence_of :name + validates_uniqueness_of :name + validates_length_of :name, :maximum => 60 + + def authenticate(login, password) + end + + def test_connection + end + + def auth_method_name + "Abstract" + end + + def account_password + read_ciphered_attribute(:account_password) + end + + def account_password=(arg) + write_ciphered_attribute(:account_password, arg) + end + + def searchable? + false + end + + def self.search(q) + results = [] + AuthSource.all.each do |source| + begin + if source.searchable? + results += source.search(q) + end + rescue AuthSourceException => e + logger.error "Error while searching users in #{source.name}: #{e.message}" + end + end + results + end + + def allow_password_changes? + self.class.allow_password_changes? + end + + # Does this auth source backend allow password changes? + def self.allow_password_changes? + false + end + + # Try to authenticate a user not yet registered against available sources + def self.authenticate(login, password) + AuthSource.where(:onthefly_register => true).all.each do |source| + begin + logger.debug "Authenticating '#{login}' against '#{source.name}'" if logger && logger.debug? + attrs = source.authenticate(login, password) + rescue => e + logger.error "Error during authentication: #{e.message}" + attrs = nil + end + return attrs if attrs + end + return nil + end +end diff --git a/app/models/auth_source_ldap.rb b/app/models/auth_source_ldap.rb new file mode 100644 index 00000000..25cdc6f1 --- /dev/null +++ b/app/models/auth_source_ldap.rb @@ -0,0 +1,200 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +require 'net/ldap' +require 'net/ldap/dn' +require 'timeout' + +class AuthSourceLdap < AuthSource + validates_presence_of :host, :port, :attr_login + validates_length_of :name, :host, :maximum => 60, :allow_nil => true + validates_length_of :account, :account_password, :base_dn, :filter, :maximum => 255, :allow_blank => true + validates_length_of :attr_login, :attr_firstname, :attr_lastname, :attr_mail, :maximum => 30, :allow_nil => true + validates_numericality_of :port, :only_integer => true + validates_numericality_of :timeout, :only_integer => true, :allow_blank => true + validate :validate_filter + + before_validation :strip_ldap_attributes + + def initialize(attributes=nil, *args) + super + self.port = 389 if self.port == 0 + end + + def authenticate(login, password) + return nil if login.blank? || password.blank? + + with_timeout do + attrs = get_user_dn(login, password) + if attrs && attrs[:dn] && authenticate_dn(attrs[:dn], password) + logger.debug "Authentication successful for '#{login}'" if logger && logger.debug? + return attrs.except(:dn) + end + end + rescue Net::LDAP::LdapError => e + raise AuthSourceException.new(e.message) + end + + # test the connection to the LDAP + def test_connection + with_timeout do + ldap_con = initialize_ldap_con(self.account, self.account_password) + ldap_con.open { } + end + rescue Net::LDAP::LdapError => e + raise AuthSourceException.new(e.message) + end + + def auth_method_name + "LDAP" + end + + # Returns true if this source can be searched for users + def searchable? + !account.to_s.include?("$login") && %w(login firstname lastname mail).all? {|a| send("attr_#{a}?")} + end + + # Searches the source for users and returns an array of results + def search(q) + q = q.to_s.strip + return [] unless searchable? && q.present? + + results = [] + search_filter = base_filter & Net::LDAP::Filter.begins(self.attr_login, q) + ldap_con = initialize_ldap_con(self.account, self.account_password) + ldap_con.search(:base => self.base_dn, + :filter => search_filter, + :attributes => ['dn', self.attr_login, self.attr_firstname, self.attr_lastname, self.attr_mail], + :size => 10) do |entry| + attrs = get_user_attributes_from_ldap_entry(entry) + attrs[:login] = AuthSourceLdap.get_attr(entry, self.attr_login) + results << attrs + end + results + rescue Net::LDAP::LdapError => e + raise AuthSourceException.new(e.message) + end + + private + + def with_timeout(&block) + timeout = self.timeout + timeout = 20 unless timeout && timeout > 0 + Timeout.timeout(timeout) do + return yield + end + rescue Timeout::Error => e + raise AuthSourceTimeoutException.new(e.message) + end + + def ldap_filter + if filter.present? + Net::LDAP::Filter.construct(filter) + end + rescue Net::LDAP::LdapError + nil + end + + def base_filter + filter = Net::LDAP::Filter.eq("objectClass", "*") + if f = ldap_filter + filter = filter & f + end + filter + end + + def validate_filter + if filter.present? && ldap_filter.nil? + errors.add(:filter, :invalid) + end + end + + def strip_ldap_attributes + [:attr_login, :attr_firstname, :attr_lastname, :attr_mail].each do |attr| + write_attribute(attr, read_attribute(attr).strip) unless read_attribute(attr).nil? + end + end + + def initialize_ldap_con(ldap_user, ldap_password) + options = { :host => self.host, + :port => self.port, + :encryption => (self.tls ? :simple_tls : nil) + } + options.merge!(:auth => { :method => :simple, :username => ldap_user, :password => ldap_password }) unless ldap_user.blank? && ldap_password.blank? + Net::LDAP.new options + end + + def get_user_attributes_from_ldap_entry(entry) + { + :dn => entry.dn, + :firstname => AuthSourceLdap.get_attr(entry, self.attr_firstname), + :lastname => AuthSourceLdap.get_attr(entry, self.attr_lastname), + :mail => AuthSourceLdap.get_attr(entry, self.attr_mail), + :auth_source_id => self.id + } + end + + # Return the attributes needed for the LDAP search. It will only + # include the user attributes if on-the-fly registration is enabled + def search_attributes + if onthefly_register? + ['dn', self.attr_firstname, self.attr_lastname, self.attr_mail] + else + ['dn'] + end + end + + # Check if a DN (user record) authenticates with the password + def authenticate_dn(dn, password) + if dn.present? && password.present? + initialize_ldap_con(dn, password).bind + end + end + + # Get the user's dn and any attributes for them, given their login + def get_user_dn(login, password) + ldap_con = nil + if self.account && self.account.include?("$login") + ldap_con = initialize_ldap_con(self.account.sub("$login", Net::LDAP::DN.escape(login)), password) + else + ldap_con = initialize_ldap_con(self.account, self.account_password) + end + attrs = {} + search_filter = base_filter & Net::LDAP::Filter.eq(self.attr_login, login) + + ldap_con.search( :base => self.base_dn, + :filter => search_filter, + :attributes=> search_attributes) do |entry| + + if onthefly_register? + attrs = get_user_attributes_from_ldap_entry(entry) + else + attrs = {:dn => entry.dn} + end + + logger.debug "DN found for #{login}: #{attrs[:dn]}" if logger && logger.debug? + end + + attrs + end + + def self.get_attr(entry, attr_name) + if !attr_name.blank? + entry[attr_name].is_a?(Array) ? entry[attr_name].first : entry[attr_name] + end + end +end diff --git a/app/models/bid.rb b/app/models/bid.rb new file mode 100644 index 00000000..f7c599c9 --- /dev/null +++ b/app/models/bid.rb @@ -0,0 +1,58 @@ +####by fq +class Bid < ActiveRecord::Base + #attr_accessible :author_id, :budget, :deadline, :name, :description + + belongs_to :author, :class_name => 'User', :foreign_key => :author_id + has_many :biding_projects, :dependent => :destroy + has_many :projects, :through => :biding_projects + has_many :journals_for_messages, :as => :jour, :dependent => :destroy + + NAME_LENGTH_LIMIT = 60 + DESCRIPTION_LENGTH_LIMIT = 250 + + validates_length_of :name, :maximum => NAME_LENGTH_LIMIT + validates_length_of :description, :maximum => DESCRIPTION_LENGTH_LIMIT + validates_presence_of :author_id, :name + validate :validate_user + + acts_as_watchable + acts_as_taggable + + + def add_jour(user, notes) + self.journals_for_messages << JournalsForMessage.new(:user_id => user.id, :notes => notes) + end + + def self.creat_bids(budget, deadline, name, description=nil) + self.create(:author_id => User.current.id, :budget => budget, + :deadline => deadline, :name => name, :description => description, :commit => 0) + end + + def update_bids(budget, deadline, name, description=nil) + if(User.current.id == self.author_id) + self.name = name + self.budget = budget + self.deadline = deadline + self.description = description + self.save + end + end + + def delete_bids + unless self.nil? + if User.current.id == self.author_id + self.destroy + end + end + end + + def set_commit(commit) + self.update_attribute(:commit, commit) + end + + private + + def validate_user + errors.add :author_id, :invalid if author.nil? || !author.active? + end +end diff --git a/app/models/biding_project.rb b/app/models/biding_project.rb new file mode 100644 index 00000000..e9cd6560 --- /dev/null +++ b/app/models/biding_project.rb @@ -0,0 +1,44 @@ +class BidingProject < ActiveRecord::Base + attr_accessible :bid_id, :project_id, :user_id, :description + + belongs_to :bid + belongs_to :project + belongs_to :user + + DESCRIPTION_LENGTH_LIMIT = 500 + + validates_length_of :description, :maximum => DESCRIPTION_LENGTH_LIMIT + validates_presence_of :user_id, :bid_id, :project_id + validate :validate_user + validate :validate_bid + validate :validate_project + validates_uniqueness_of :bid_id, :scope => :project_id + + def self.cerate_bidding(bid_id, project_id, description = nil) + self.create(:user_id => User.current.id, :bid_id => bid_id, + :project_id => project_id, :description => description) + end + + def cancel_bidding + unless self.nil? + if User.current.id == self.user_id + self.destroy + end + end + end + + private + + def validate_user + errors.add :user_id, :invalid if user.nil? || !user.active? + end + + def validate_bid + errors.add :bid_id, :invalid if bid.nil? + end + + def validate_project + errors.add :project_id, :invalid if project.nil? + end + +end diff --git a/app/models/board.rb b/app/models/board.rb new file mode 100644 index 00000000..cb81e0a5 --- /dev/null +++ b/app/models/board.rb @@ -0,0 +1,90 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class Board < ActiveRecord::Base + include Redmine::SafeAttributes + belongs_to :project + has_many :topics, :class_name => 'Message', :conditions => "#{Message.table_name}.parent_id IS NULL", :order => "#{Message.table_name}.created_on DESC" + has_many :messages, :dependent => :destroy, :order => "#{Message.table_name}.created_on DESC" + belongs_to :last_message, :class_name => 'Message', :foreign_key => :last_message_id + acts_as_tree :dependent => :nullify + acts_as_list :scope => '(project_id = #{project_id} AND parent_id #{parent_id ? "= #{parent_id}" : "IS NULL"})' + acts_as_watchable + + validates_presence_of :name, :description + validates_length_of :name, :maximum => 30 + validates_length_of :description, :maximum => 255 + validate :validate_board + + scope :visible, lambda {|*args| + includes(:project).where(Project.allowed_to_condition(args.shift || User.current, :view_messages, *args)) + } + + safe_attributes 'name', 'description', 'parent_id', 'move_to' + + def visible?(user=User.current) + !user.nil? && user.allowed_to?(:view_messages, project) + end + + def reload(*args) + @valid_parents = nil + super + end + + def to_s + name + end + + def valid_parents + @valid_parents ||= project.boards - self_and_descendants + end + + def reset_counters! + self.class.reset_counters!(id) + end + + # Updates topics_count, messages_count and last_message_id attributes for +board_id+ + def self.reset_counters!(board_id) + board_id = board_id.to_i + update_all("topics_count = (SELECT COUNT(*) FROM #{Message.table_name} WHERE board_id=#{board_id} AND parent_id IS NULL)," + + " messages_count = (SELECT COUNT(*) FROM #{Message.table_name} WHERE board_id=#{board_id})," + + " last_message_id = (SELECT MAX(id) FROM #{Message.table_name} WHERE board_id=#{board_id})", + ["id = ?", board_id]) + end + + def self.board_tree(boards, parent_id=nil, level=0) + tree = [] + boards.select {|board| board.parent_id == parent_id}.sort_by(&:position).each do |board| + tree << [board, level] + tree += board_tree(boards, board.id, level+1) + end + if block_given? + tree.each do |board, level| + yield board, level + end + end + tree + end + + protected + + def validate_board + if parent_id && parent_id_changed? + errors.add(:parent_id, :invalid) unless valid_parents.include?(parent) + end + end +end diff --git a/app/models/change.rb b/app/models/change.rb new file mode 100644 index 00000000..b80b96eb --- /dev/null +++ b/app/models/change.rb @@ -0,0 +1,37 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class Change < ActiveRecord::Base + belongs_to :changeset + + validates_presence_of :changeset_id, :action, :path + before_save :init_path + before_validation :replace_invalid_utf8_of_path + + def relative_path + changeset.repository.relative_path(path) + end + + def replace_invalid_utf8_of_path + self.path = Redmine::CodesetUtil.replace_invalid_utf8(self.path) + self.from_path = Redmine::CodesetUtil.replace_invalid_utf8(self.from_path) + end + + def init_path + self.path ||= "" + end +end diff --git a/app/models/changeset.rb b/app/models/changeset.rb new file mode 100644 index 00000000..d3fa8ab2 --- /dev/null +++ b/app/models/changeset.rb @@ -0,0 +1,278 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class Changeset < ActiveRecord::Base + belongs_to :repository + belongs_to :user + has_many :filechanges, :class_name => 'Change', :dependent => :delete_all + has_and_belongs_to_many :issues + has_and_belongs_to_many :parents, + :class_name => "Changeset", + :join_table => "#{table_name_prefix}changeset_parents#{table_name_suffix}", + :association_foreign_key => 'parent_id', :foreign_key => 'changeset_id' + has_and_belongs_to_many :children, + :class_name => "Changeset", + :join_table => "#{table_name_prefix}changeset_parents#{table_name_suffix}", + :association_foreign_key => 'changeset_id', :foreign_key => 'parent_id' + + acts_as_event :title => Proc.new {|o| o.title}, + :description => :long_comments, + :datetime => :committed_on, + :url => Proc.new {|o| {:controller => 'repositories', :action => 'revision', :id => o.repository.project, :repository_id => o.repository.identifier_param, :rev => o.identifier}} + + acts_as_searchable :columns => 'comments', + :include => {:repository => :project}, + :project_key => "#{Repository.table_name}.project_id", + :date_column => 'committed_on' + + acts_as_activity_provider :timestamp => "#{table_name}.committed_on", + :author_key => :user_id, + :find_options => {:include => [:user, {:repository => :project}]} + + validates_presence_of :repository_id, :revision, :committed_on, :commit_date + validates_uniqueness_of :revision, :scope => :repository_id + validates_uniqueness_of :scmid, :scope => :repository_id, :allow_nil => true + + scope :visible, lambda {|*args| + includes(:repository => :project).where(Project.allowed_to_condition(args.shift || User.current, :view_changesets, *args)) + } + + after_create :scan_for_issues + before_create :before_create_cs + + def revision=(r) + write_attribute :revision, (r.nil? ? nil : r.to_s) + end + + # Returns the identifier of this changeset; depending on repository backends + def identifier + if repository.class.respond_to? :changeset_identifier + repository.class.changeset_identifier self + else + revision.to_s + end + end + + def committed_on=(date) + self.commit_date = date + super + end + + # Returns the readable identifier + def format_identifier + if repository.class.respond_to? :format_changeset_identifier + repository.class.format_changeset_identifier self + else + identifier + end + end + + def project + repository.project + end + + def author + user || committer.to_s.split('<').first + end + + def before_create_cs + self.committer = self.class.to_utf8(self.committer, repository.repo_log_encoding) + self.comments = self.class.normalize_comments( + self.comments, repository.repo_log_encoding) + self.user = repository.find_committer_user(self.committer) + end + + def scan_for_issues + scan_comment_for_issue_ids + end + + TIMELOG_RE = / + ( + ((\d+)(h|hours?))((\d+)(m|min)?)? + | + ((\d+)(h|hours?|m|min)) + | + (\d+):(\d+) + | + (\d+([\.,]\d+)?)h? + ) + /x + + def scan_comment_for_issue_ids + return if comments.blank? + # keywords used to reference issues + ref_keywords = Setting.commit_ref_keywords.downcase.split(",").collect(&:strip) + ref_keywords_any = ref_keywords.delete('*') + # keywords used to fix issues + fix_keywords = Setting.commit_fix_keywords.downcase.split(",").collect(&:strip) + + kw_regexp = (ref_keywords + fix_keywords).collect{|kw| Regexp.escape(kw)}.join("|") + + referenced_issues = [] + + comments.scan(/([\s\(\[,-]|^)((#{kw_regexp})[\s:]+)?(#\d+(\s+@#{TIMELOG_RE})?([\s,;&]+#\d+(\s+@#{TIMELOG_RE})?)*)(?=[[:punct:]]|\s|<|$)/i) do |match| + action, refs = match[2], match[3] + next unless action.present? || ref_keywords_any + + refs.scan(/#(\d+)(\s+@#{TIMELOG_RE})?/).each do |m| + issue, hours = find_referenced_issue_by_id(m[0].to_i), m[2] + if issue + referenced_issues << issue + fix_issue(issue) if fix_keywords.include?(action.to_s.downcase) + log_time(issue, hours) if hours && Setting.commit_logtime_enabled? + end + end + end + + referenced_issues.uniq! + self.issues = referenced_issues unless referenced_issues.empty? + end + + def short_comments + @short_comments || split_comments.first + end + + def long_comments + @long_comments || split_comments.last + end + + def text_tag(ref_project=nil) + tag = if scmid? + "commit:#{scmid}" + else + "r#{revision}" + end + if repository && repository.identifier.present? + tag = "#{repository.identifier}|#{tag}" + end + if ref_project && project && ref_project != project + tag = "#{project.identifier}:#{tag}" + end + tag + end + + # Returns the title used for the changeset in the activity/search results + def title + repo = (repository && repository.identifier.present?) ? " (#{repository.identifier})" : '' + comm = short_comments.blank? ? '' : (': ' + short_comments) + "#{l(:label_revision)} #{format_identifier}#{repo}#{comm}" + end + + # Returns the previous changeset + def previous + @previous ||= Changeset.where(["id < ? AND repository_id = ?", id, repository_id]).order('id DESC').first + end + + # Returns the next changeset + def next + @next ||= Changeset.where(["id > ? AND repository_id = ?", id, repository_id]).order('id ASC').first + end + + # Creates a new Change from it's common parameters + def create_change(change) + Change.create(:changeset => self, + :action => change[:action], + :path => change[:path], + :from_path => change[:from_path], + :from_revision => change[:from_revision]) + end + + # Finds an issue that can be referenced by the commit message + def find_referenced_issue_by_id(id) + return nil if id.blank? + issue = Issue.find_by_id(id.to_i, :include => :project) + if Setting.commit_cross_project_ref? + # all issues can be referenced/fixed + elsif issue + # issue that belong to the repository project, a subproject or a parent project only + unless issue.project && + (project == issue.project || project.is_ancestor_of?(issue.project) || + project.is_descendant_of?(issue.project)) + issue = nil + end + end + issue + end + + private + + def fix_issue(issue) + status = IssueStatus.find_by_id(Setting.commit_fix_status_id.to_i) + if status.nil? + logger.warn("No status matches commit_fix_status_id setting (#{Setting.commit_fix_status_id})") if logger + return issue + end + + # the issue may have been updated by the closure of another one (eg. duplicate) + issue.reload + # don't change the status is the issue is closed + return if issue.status && issue.status.is_closed? + + journal = issue.init_journal(user || User.anonymous, ll(Setting.default_language, :text_status_changed_by_changeset, text_tag(issue.project))) + issue.status = status + unless Setting.commit_fix_done_ratio.blank? + issue.done_ratio = Setting.commit_fix_done_ratio.to_i + end + Redmine::Hook.call_hook(:model_changeset_scan_commit_for_issue_ids_pre_issue_update, + { :changeset => self, :issue => issue }) + unless issue.save + logger.warn("Issue ##{issue.id} could not be saved by changeset #{id}: #{issue.errors.full_messages}") if logger + end + issue + end + + def log_time(issue, hours) + time_entry = TimeEntry.new( + :user => user, + :hours => hours, + :issue => issue, + :spent_on => commit_date, + :comments => l(:text_time_logged_by_changeset, :value => text_tag(issue.project), + :locale => Setting.default_language) + ) + time_entry.activity = log_time_activity unless log_time_activity.nil? + + unless time_entry.save + logger.warn("TimeEntry could not be created by changeset #{id}: #{time_entry.errors.full_messages}") if logger + end + time_entry + end + + def log_time_activity + if Setting.commit_logtime_activity_id.to_i > 0 + TimeEntryActivity.find_by_id(Setting.commit_logtime_activity_id.to_i) + end + end + + def split_comments + comments =~ /\A(.+?)\r?\n(.*)$/m + @short_comments = $1 || comments + @long_comments = $2.to_s.strip + return @short_comments, @long_comments + end + + public + + # Strips and reencodes a commit log before insertion into the database + def self.normalize_comments(str, encoding) + Changeset.to_utf8(str.to_s.strip, encoding) + end + + def self.to_utf8(str, encoding) + Redmine::CodesetUtil.to_utf8(str, encoding) + end +end diff --git a/app/models/comment.rb b/app/models/comment.rb new file mode 100644 index 00000000..577afe94 --- /dev/null +++ b/app/models/comment.rb @@ -0,0 +1,26 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class Comment < ActiveRecord::Base + include Redmine::SafeAttributes + belongs_to :commented, :polymorphic => true, :counter_cache => true + belongs_to :author, :class_name => 'User', :foreign_key => 'author_id' + + validates_presence_of :commented, :author, :comments + + safe_attributes 'comments' +end diff --git a/app/models/comment_observer.rb b/app/models/comment_observer.rb new file mode 100644 index 00000000..e7c12c4b --- /dev/null +++ b/app/models/comment_observer.rb @@ -0,0 +1,24 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class CommentObserver < ActiveRecord::Observer + def after_create(comment) + if comment.commented.is_a?(News) && Setting.notified_events.include?('news_comment_added') + Mailer.news_comment_added(comment).deliver + end + end +end diff --git a/app/models/custom_field.rb b/app/models/custom_field.rb new file mode 100644 index 00000000..c1519238 --- /dev/null +++ b/app/models/custom_field.rb @@ -0,0 +1,355 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class CustomField < ActiveRecord::Base + include Redmine::SubclassFactory + + has_many :custom_values, :dependent => :delete_all + acts_as_list :scope => 'type = \'#{self.class}\'' + serialize :possible_values + + validates_presence_of :name, :field_format + validates_uniqueness_of :name, :scope => :type + validates_length_of :name, :maximum => 30 + validates_inclusion_of :field_format, :in => Redmine::CustomFieldFormat.available_formats + + validate :validate_custom_field + before_validation :set_searchable + after_save :handle_multiplicity_change + + scope :sorted, lambda { order("#{table_name}.position ASC") } + + CUSTOM_FIELDS_TABS = [ + {:name => 'IssueCustomField', :partial => 'custom_fields/index', + :label => :label_issue_plural}, + {:name => 'TimeEntryCustomField', :partial => 'custom_fields/index', + :label => :label_spent_time}, + {:name => 'ProjectCustomField', :partial => 'custom_fields/index', + :label => :label_project_plural}, + {:name => 'VersionCustomField', :partial => 'custom_fields/index', + :label => :label_version_plural}, + {:name => 'UserCustomField', :partial => 'custom_fields/index', + :label => :label_user_plural}, + {:name => 'GroupCustomField', :partial => 'custom_fields/index', + :label => :label_group_plural}, + {:name => 'TimeEntryActivityCustomField', :partial => 'custom_fields/index', + :label => TimeEntryActivity::OptionName}, + {:name => 'IssuePriorityCustomField', :partial => 'custom_fields/index', + :label => IssuePriority::OptionName}, + {:name => 'DocumentCategoryCustomField', :partial => 'custom_fields/index', + :label => DocumentCategory::OptionName} + ] + + CUSTOM_FIELDS_NAMES = CUSTOM_FIELDS_TABS.collect{|v| v[:name]} + + def field_format=(arg) + # cannot change format of a saved custom field + super if new_record? + end + + def set_searchable + # make sure these fields are not searchable + self.searchable = false if %w(int float date bool).include?(field_format) + # make sure only these fields can have multiple values + self.multiple = false unless %w(list user version).include?(field_format) + true + end + + def validate_custom_field + if self.field_format == "list" + errors.add(:possible_values, :blank) if self.possible_values.nil? || self.possible_values.empty? + errors.add(:possible_values, :invalid) unless self.possible_values.is_a? Array + end + + if regexp.present? + begin + Regexp.new(regexp) + rescue + errors.add(:regexp, :invalid) + end + end + + if default_value.present? && !valid_field_value?(default_value) + errors.add(:default_value, :invalid) + end + end + + def possible_values_options(obj=nil) + case field_format + when 'user', 'version' + if obj.respond_to?(:project) && obj.project + case field_format + when 'user' + obj.project.users.sort.collect {|u| [u.to_s, u.id.to_s]} + when 'version' + obj.project.shared_versions.sort.collect {|u| [u.to_s, u.id.to_s]} + end + elsif obj.is_a?(Array) + obj.collect {|o| possible_values_options(o)}.reduce(:&) + else + [] + end + when 'bool' + [[l(:general_text_Yes), '1'], [l(:general_text_No), '0']] + else + possible_values || [] + end + end + + def possible_values(obj=nil) + case field_format + when 'user', 'version' + possible_values_options(obj).collect(&:last) + when 'bool' + ['1', '0'] + else + values = super() + if values.is_a?(Array) + values.each do |value| + value.force_encoding('UTF-8') if value.respond_to?(:force_encoding) + end + end + values || [] + end + end + + # Makes possible_values accept a multiline string + def possible_values=(arg) + if arg.is_a?(Array) + super(arg.compact.collect(&:strip).select {|v| !v.blank?}) + else + self.possible_values = arg.to_s.split(/[\n\r]+/) + end + end + + def cast_value(value) + casted = nil + unless value.blank? + case field_format + when 'string', 'text', 'list' + casted = value + when 'date' + casted = begin; value.to_date; rescue; nil end + when 'bool' + casted = (value == '1' ? true : false) + when 'int' + casted = value.to_i + when 'float' + casted = value.to_f + when 'user', 'version' + casted = (value.blank? ? nil : field_format.classify.constantize.find_by_id(value.to_i)) + end + end + casted + end + + def value_from_keyword(keyword, customized) + possible_values_options = possible_values_options(customized) + if possible_values_options.present? + keyword = keyword.to_s.downcase + if v = possible_values_options.detect {|text, id| text.downcase == keyword} + if v.is_a?(Array) + v.last + else + v + end + end + else + keyword + end + end + + # Returns a ORDER BY clause that can used to sort customized + # objects by their value of the custom field. + # Returns nil if the custom field can not be used for sorting. + def order_statement + return nil if multiple? + case field_format + when 'string', 'text', 'list', 'date', 'bool' + # COALESCE is here to make sure that blank and NULL values are sorted equally + "COALESCE(#{join_alias}.value, '')" + when 'int', 'float' + # Make the database cast values into numeric + # Postgresql will raise an error if a value can not be casted! + # CustomValue validations should ensure that it doesn't occur + "CAST(CASE #{join_alias}.value WHEN '' THEN '0' ELSE #{join_alias}.value END AS decimal(30,3))" + when 'user', 'version' + value_class.fields_for_order_statement(value_join_alias) + else + nil + end + end + + # Returns a GROUP BY clause that can used to group by custom value + # Returns nil if the custom field can not be used for grouping. + def group_statement + return nil if multiple? + case field_format + when 'list', 'date', 'bool', 'int' + order_statement + when 'user', 'version' + "COALESCE(#{join_alias}.value, '')" + else + nil + end + end + + def join_for_order_statement + case field_format + when 'user', 'version' + "LEFT OUTER JOIN #{CustomValue.table_name} #{join_alias}" + + " ON #{join_alias}.customized_type = '#{self.class.customized_class.base_class.name}'" + + " AND #{join_alias}.customized_id = #{self.class.customized_class.table_name}.id" + + " AND #{join_alias}.custom_field_id = #{id}" + + " AND #{join_alias}.value <> ''" + + " AND #{join_alias}.id = (SELECT max(#{join_alias}_2.id) FROM #{CustomValue.table_name} #{join_alias}_2" + + " WHERE #{join_alias}_2.customized_type = #{join_alias}.customized_type" + + " AND #{join_alias}_2.customized_id = #{join_alias}.customized_id" + + " AND #{join_alias}_2.custom_field_id = #{join_alias}.custom_field_id)" + + " LEFT OUTER JOIN #{value_class.table_name} #{value_join_alias}" + + " ON CAST(CASE #{join_alias}.value WHEN '' THEN '0' ELSE #{join_alias}.value END AS decimal(30,0)) = #{value_join_alias}.id" + when 'int', 'float' + "LEFT OUTER JOIN #{CustomValue.table_name} #{join_alias}" + + " ON #{join_alias}.customized_type = '#{self.class.customized_class.base_class.name}'" + + " AND #{join_alias}.customized_id = #{self.class.customized_class.table_name}.id" + + " AND #{join_alias}.custom_field_id = #{id}" + + " AND #{join_alias}.value <> ''" + + " AND #{join_alias}.id = (SELECT max(#{join_alias}_2.id) FROM #{CustomValue.table_name} #{join_alias}_2" + + " WHERE #{join_alias}_2.customized_type = #{join_alias}.customized_type" + + " AND #{join_alias}_2.customized_id = #{join_alias}.customized_id" + + " AND #{join_alias}_2.custom_field_id = #{join_alias}.custom_field_id)" + when 'string', 'text', 'list', 'date', 'bool' + "LEFT OUTER JOIN #{CustomValue.table_name} #{join_alias}" + + " ON #{join_alias}.customized_type = '#{self.class.customized_class.base_class.name}'" + + " AND #{join_alias}.customized_id = #{self.class.customized_class.table_name}.id" + + " AND #{join_alias}.custom_field_id = #{id}" + + " AND #{join_alias}.id = (SELECT max(#{join_alias}_2.id) FROM #{CustomValue.table_name} #{join_alias}_2" + + " WHERE #{join_alias}_2.customized_type = #{join_alias}.customized_type" + + " AND #{join_alias}_2.customized_id = #{join_alias}.customized_id" + + " AND #{join_alias}_2.custom_field_id = #{join_alias}.custom_field_id)" + else + nil + end + end + + def join_alias + "cf_#{id}" + end + + def value_join_alias + join_alias + "_" + field_format + end + + def <=>(field) + position <=> field.position + end + + # Returns the class that values represent + def value_class + case field_format + when 'user', 'version' + field_format.classify.constantize + else + nil + end + end + + def self.customized_class + self.name =~ /^(.+)CustomField$/ + begin; $1.constantize; rescue nil; end + end + + # to move in project_custom_field + def self.for_all + where(:is_for_all => true).order('position').all + end + + def type_name + nil + end + + # Returns the error messages for the given value + # or an empty array if value is a valid value for the custom field + def validate_field_value(value) + errs = [] + if value.is_a?(Array) + if !multiple? + errs << ::I18n.t('activerecord.errors.messages.invalid') + end + if is_required? && value.detect(&:present?).nil? + errs << ::I18n.t('activerecord.errors.messages.blank') + end + value.each {|v| errs += validate_field_value_format(v)} + else + if is_required? && value.blank? + errs << ::I18n.t('activerecord.errors.messages.blank') + end + errs += validate_field_value_format(value) + end + errs + end + + # Returns true if value is a valid value for the custom field + def valid_field_value?(value) + validate_field_value(value).empty? + end + + def format_in?(*args) + args.include?(field_format) + end + + protected + + # Returns the error message for the given value regarding its format + def validate_field_value_format(value) + errs = [] + if value.present? + errs << ::I18n.t('activerecord.errors.messages.invalid') unless regexp.blank? or value =~ Regexp.new(regexp) + errs << ::I18n.t('activerecord.errors.messages.too_short', :count => min_length) if min_length > 0 and value.length < min_length + errs << ::I18n.t('activerecord.errors.messages.too_long', :count => max_length) if max_length > 0 and value.length > max_length + + # Format specific validations + case field_format + when 'int' + errs << ::I18n.t('activerecord.errors.messages.not_a_number') unless value =~ /^[+-]?\d+$/ + when 'float' + begin; Kernel.Float(value); rescue; errs << ::I18n.t('activerecord.errors.messages.invalid') end + when 'date' + errs << ::I18n.t('activerecord.errors.messages.not_a_date') unless value =~ /^\d{4}-\d{2}-\d{2}$/ && begin; value.to_date; rescue; false end + when 'list' + errs << ::I18n.t('activerecord.errors.messages.inclusion') unless possible_values.include?(value) + end + end + errs + end + + # Removes multiple values for the custom field after setting the multiple attribute to false + # We kepp the value with the highest id for each customized object + def handle_multiplicity_change + if !new_record? && multiple_was && !multiple + ids = custom_values. + where("EXISTS(SELECT 1 FROM #{CustomValue.table_name} cve WHERE cve.custom_field_id = #{CustomValue.table_name}.custom_field_id" + + " AND cve.customized_type = #{CustomValue.table_name}.customized_type AND cve.customized_id = #{CustomValue.table_name}.customized_id" + + " AND cve.id > #{CustomValue.table_name}.id)"). + pluck(:id) + + if ids.any? + custom_values.where(:id => ids).delete_all + end + end + end +end diff --git a/app/models/custom_field_value.rb b/app/models/custom_field_value.rb new file mode 100644 index 00000000..04288b11 --- /dev/null +++ b/app/models/custom_field_value.rb @@ -0,0 +1,50 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class CustomFieldValue + attr_accessor :custom_field, :customized, :value + + def custom_field_id + custom_field.id + end + + def true? + self.value == '1' + end + + def editable? + custom_field.editable? + end + + def visible? + custom_field.visible? + end + + def required? + custom_field.is_required? + end + + def to_s + value.to_s + end + + def validate_value + custom_field.validate_field_value(value).each do |message| + customized.errors.add(:base, custom_field.name + ' ' + message) + end + end +end diff --git a/app/models/custom_value.rb b/app/models/custom_value.rb new file mode 100644 index 00000000..62bbc810 --- /dev/null +++ b/app/models/custom_value.rb @@ -0,0 +1,49 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class CustomValue < ActiveRecord::Base + belongs_to :custom_field + belongs_to :customized, :polymorphic => true + + def initialize(attributes=nil, *args) + super + if new_record? && custom_field && (customized_type.blank? || (customized && customized.new_record?)) + self.value ||= custom_field.default_value + end + end + + # Returns true if the boolean custom value is true + def true? + self.value == '1' + end + + def editable? + custom_field.editable? + end + + def visible? + custom_field.visible? + end + + def required? + custom_field.is_required? + end + + def to_s + value.to_s + end +end diff --git a/app/models/document.rb b/app/models/document.rb new file mode 100644 index 00000000..0c2ce173 --- /dev/null +++ b/app/models/document.rb @@ -0,0 +1,57 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class Document < ActiveRecord::Base + include Redmine::SafeAttributes + belongs_to :project + belongs_to :category, :class_name => "DocumentCategory", :foreign_key => "category_id" + acts_as_attachable :delete_permission => :delete_documents + + acts_as_searchable :columns => ['title', "#{table_name}.description"], :include => :project + acts_as_event :title => Proc.new {|o| "#{l(:label_document)}: #{o.title}"}, + :author => Proc.new {|o| o.attachments.reorder("#{Attachment.table_name}.created_on ASC").first.try(:author) }, + :url => Proc.new {|o| {:controller => 'documents', :action => 'show', :id => o.id}} + acts_as_activity_provider :find_options => {:include => :project} + + validates_presence_of :project, :title, :category + validates_length_of :title, :maximum => 60 + + scope :visible, lambda {|*args| + includes(:project).where(Project.allowed_to_condition(args.shift || User.current, :view_documents, *args)) + } + + safe_attributes 'category_id', 'title', 'description' + + def visible?(user=User.current) + !user.nil? && user.allowed_to?(:view_documents, project) + end + + def initialize(attributes=nil, *args) + super + if new_record? + self.category ||= DocumentCategory.default + end + end + + def updated_on + unless @updated_on + a = attachments.last + @updated_on = (a && a.created_on) || created_on + end + @updated_on + end +end diff --git a/app/models/document_category.rb b/app/models/document_category.rb new file mode 100644 index 00000000..95aa5730 --- /dev/null +++ b/app/models/document_category.rb @@ -0,0 +1,40 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class DocumentCategory < Enumeration + has_many :documents, :foreign_key => 'category_id' + + OptionName = :enumeration_doc_categories + + def option_name + OptionName + end + + def objects_count + documents.count + end + + def transfer_relations(to) + documents.update_all("category_id = #{to.id}") + end + + def self.default + d = super + d = first if d.nil? + d + end +end diff --git a/app/models/document_category_custom_field.rb b/app/models/document_category_custom_field.rb new file mode 100644 index 00000000..a95c55a4 --- /dev/null +++ b/app/models/document_category_custom_field.rb @@ -0,0 +1,22 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class DocumentCategoryCustomField < CustomField + def type_name + :enumeration_doc_categories + end +end diff --git a/app/models/document_observer.rb b/app/models/document_observer.rb new file mode 100644 index 00000000..4a61f118 --- /dev/null +++ b/app/models/document_observer.rb @@ -0,0 +1,22 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class DocumentObserver < ActiveRecord::Observer + def after_create(document) + Mailer.document_added(document).deliver if Setting.notified_events.include?('document_added') + end +end diff --git a/app/models/enabled_module.rb b/app/models/enabled_module.rb new file mode 100644 index 00000000..94539ec0 --- /dev/null +++ b/app/models/enabled_module.rb @@ -0,0 +1,38 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class EnabledModule < ActiveRecord::Base + belongs_to :project + + validates_presence_of :name + validates_uniqueness_of :name, :scope => :project_id + + after_create :module_enabled + + private + + # after_create callback used to do things when a module is enabled + def module_enabled + case name + when 'wiki' + # Create a wiki with a default start page + if project && project.wiki.nil? + Wiki.create(:project => project, :start_page => 'Wiki') + end + end + end +end diff --git a/app/models/enumeration.rb b/app/models/enumeration.rb new file mode 100644 index 00000000..1946735e --- /dev/null +++ b/app/models/enumeration.rb @@ -0,0 +1,141 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class Enumeration < ActiveRecord::Base + include Redmine::SubclassFactory + + default_scope :order => "#{Enumeration.table_name}.position ASC" + + belongs_to :project + + acts_as_list :scope => 'type = \'#{type}\'' + acts_as_customizable + acts_as_tree :order => "#{Enumeration.table_name}.position ASC" + + before_destroy :check_integrity + before_save :check_default + + attr_protected :type + + validates_presence_of :name + validates_uniqueness_of :name, :scope => [:type, :project_id] + validates_length_of :name, :maximum => 30 + + scope :shared, lambda { where(:project_id => nil) } + scope :sorted, lambda { order("#{table_name}.position ASC") } + scope :active, lambda { where(:active => true) } + scope :named, lambda {|arg| where("LOWER(#{table_name}.name) = LOWER(?)", arg.to_s.strip)} + + def self.default + # Creates a fake default scope so Enumeration.default will check + # it's type. STI subclasses will automatically add their own + # types to the finder. + if self.descends_from_active_record? + where(:is_default => true, :type => 'Enumeration').first + else + # STI classes are + where(:is_default => true).first + end + end + + # Overloaded on concrete classes + def option_name + nil + end + + def check_default + if is_default? && is_default_changed? + Enumeration.update_all({:is_default => false}, {:type => type}) + end + end + + # Overloaded on concrete classes + def objects_count + 0 + end + + def in_use? + self.objects_count != 0 + end + + # Is this enumeration overiding a system level enumeration? + def is_override? + !self.parent.nil? + end + + alias :destroy_without_reassign :destroy + + # Destroy the enumeration + # If a enumeration is specified, objects are reassigned + def destroy(reassign_to = nil) + if reassign_to && reassign_to.is_a?(Enumeration) + self.transfer_relations(reassign_to) + end + destroy_without_reassign + end + + def <=>(enumeration) + position <=> enumeration.position + end + + def to_s; name end + + # Returns the Subclasses of Enumeration. Each Subclass needs to be + # required in development mode. + # + # Note: subclasses is protected in ActiveRecord + def self.get_subclasses + subclasses + end + + # Does the +new+ Hash override the previous Enumeration? + def self.overridding_change?(new, previous) + if (same_active_state?(new['active'], previous.active)) && same_custom_values?(new,previous) + return false + else + return true + end + end + + # Does the +new+ Hash have the same custom values as the previous Enumeration? + def self.same_custom_values?(new, previous) + previous.custom_field_values.each do |custom_value| + if custom_value.value != new["custom_field_values"][custom_value.custom_field_id.to_s] + return false + end + end + + return true + end + + # Are the new and previous fields equal? + def self.same_active_state?(new, previous) + new = (new == "1" ? true : false) + return new == previous + end + +private + def check_integrity + raise "Can't delete enumeration" if self.in_use? + end + +end + +# Force load the subclasses in development mode +require_dependency 'time_entry_activity' +require_dependency 'document_category' +require_dependency 'issue_priority' diff --git a/app/models/group.rb b/app/models/group.rb new file mode 100644 index 00000000..d1b2cb96 --- /dev/null +++ b/app/models/group.rb @@ -0,0 +1,90 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class Group < Principal + include Redmine::SafeAttributes + + has_and_belongs_to_many :users, :after_add => :user_added, + :after_remove => :user_removed + + acts_as_customizable + + validates_presence_of :lastname + validates_uniqueness_of :lastname, :case_sensitive => false + validates_length_of :lastname, :maximum => 255 + + before_destroy :remove_references_before_destroy + + scope :sorted, lambda { order("#{table_name}.lastname ASC") } + scope :named, lambda {|arg| where("LOWER(#{table_name}.lastname) = LOWER(?)", arg.to_s.strip)} + + safe_attributes 'name', + 'user_ids', + 'custom_field_values', + 'custom_fields', + :if => lambda {|group, user| user.admin?} + + def to_s + lastname.to_s + end + + def name + lastname + end + + def name=(arg) + self.lastname = arg + end + + def user_added(user) + members.each do |member| + next if member.project.nil? + user_member = Member.find_by_project_id_and_user_id(member.project_id, user.id) || Member.new(:project_id => member.project_id, :user_id => user.id) + member.member_roles.each do |member_role| + user_member.member_roles << MemberRole.new(:role => member_role.role, :inherited_from => member_role.id) + end + user_member.save! + end + end + + def user_removed(user) + members.each do |member| + MemberRole. + includes(:member). + where("#{Member.table_name}.user_id = ? AND #{MemberRole.table_name}.inherited_from IN (?)", user.id, member.member_role_ids). + all. + each(&:destroy) + end + end + + def self.human_attribute_name(attribute_key_name, *args) + attr_name = attribute_key_name.to_s + if attr_name == 'lastname' + attr_name = "name" + end + super(attr_name, *args) + end + + private + + # Removes references that are not handled by associations + def remove_references_before_destroy + return if self.id.nil? + + Issue.update_all 'assigned_to_id = NULL', ['assigned_to_id = ?', id] + end +end diff --git a/app/models/group_custom_field.rb b/app/models/group_custom_field.rb new file mode 100644 index 00000000..98274138 --- /dev/null +++ b/app/models/group_custom_field.rb @@ -0,0 +1,22 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class GroupCustomField < CustomField + def type_name + :label_group_plural + end +end diff --git a/app/models/issue.rb b/app/models/issue.rb new file mode 100644 index 00000000..5ecadb67 --- /dev/null +++ b/app/models/issue.rb @@ -0,0 +1,1443 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class Issue < ActiveRecord::Base + include Redmine::SafeAttributes + include Redmine::Utils::DateCalculation + + belongs_to :project + belongs_to :tracker + belongs_to :status, :class_name => 'IssueStatus', :foreign_key => 'status_id' + belongs_to :author, :class_name => 'User', :foreign_key => 'author_id' + belongs_to :assigned_to, :class_name => 'Principal', :foreign_key => 'assigned_to_id' + belongs_to :fixed_version, :class_name => 'Version', :foreign_key => 'fixed_version_id' + belongs_to :priority, :class_name => 'IssuePriority', :foreign_key => 'priority_id' + belongs_to :category, :class_name => 'IssueCategory', :foreign_key => 'category_id' + + has_many :journals, :as => :journalized, :dependent => :destroy + has_many :visible_journals, + :class_name => 'Journal', + :as => :journalized, + :conditions => Proc.new { + ["(#{Journal.table_name}.private_notes = ? OR (#{Project.allowed_to_condition(User.current, :view_private_notes)}))", false] + }, + :readonly => true + + has_many :time_entries, :dependent => :delete_all + has_and_belongs_to_many :changesets, :order => "#{Changeset.table_name}.committed_on ASC, #{Changeset.table_name}.id ASC" + + has_many :relations_from, :class_name => 'IssueRelation', :foreign_key => 'issue_from_id', :dependent => :delete_all + has_many :relations_to, :class_name => 'IssueRelation', :foreign_key => 'issue_to_id', :dependent => :delete_all + + acts_as_nested_set :scope => 'root_id', :dependent => :destroy + acts_as_attachable :after_add => :attachment_added, :after_remove => :attachment_removed + acts_as_customizable + acts_as_watchable + acts_as_searchable :columns => ['subject', "#{table_name}.description", "#{Journal.table_name}.notes"], + :include => [:project, :visible_journals], + # sort by id so that limited eager loading doesn't break with postgresql + :order_column => "#{table_name}.id" + acts_as_event :title => Proc.new {|o| "#{o.tracker.name} ##{o.id} (#{o.status}): #{o.subject}"}, + :url => Proc.new {|o| {:controller => 'issues', :action => 'show', :id => o.id}}, + :type => Proc.new {|o| 'issue' + (o.closed? ? ' closed' : '') } + + acts_as_activity_provider :find_options => {:include => [:project, :author, :tracker]}, + :author_key => :author_id + +###########################added by william + acts_as_taggable + + DONE_RATIO_OPTIONS = %w(issue_field issue_status) + + attr_reader :current_journal + delegate :notes, :notes=, :private_notes, :private_notes=, :to => :current_journal, :allow_nil => true + + validates_presence_of :subject, :priority, :project, :tracker, :author, :status + + validates_length_of :subject, :maximum => 255 + validates_inclusion_of :done_ratio, :in => 0..100 + validates :estimated_hours, :numericality => {:greater_than_or_equal_to => 0, :allow_nil => true, :message => :invalid} + validates :start_date, :date => true + validates :due_date, :date => true + validate :validate_issue, :validate_required_fields + + scope :visible, lambda {|*args| + includes(:project).where(Issue.visible_condition(args.shift || User.current, *args)) + } + + scope :open, lambda {|*args| + is_closed = args.size > 0 ? !args.first : false + includes(:status).where("#{IssueStatus.table_name}.is_closed = ?", is_closed) + } + + scope :recently_updated, lambda { order("#{Issue.table_name}.updated_on DESC") } + scope :on_active_project, lambda { + includes(:status, :project, :tracker).where("#{Project.table_name}.status = ?", Project::STATUS_ACTIVE) + } + scope :fixed_version, lambda {|versions| + ids = [versions].flatten.compact.map {|v| v.is_a?(Version) ? v.id : v} + ids.any? ? where(:fixed_version_id => ids) : where('1=0') + } + + before_create :default_assign + before_save :close_duplicates, :update_done_ratio_from_issue_status, :force_updated_on_change, :update_closed_on + after_save {|issue| issue.send :after_project_change if !issue.id_changed? && issue.project_id_changed?} + after_save :reschedule_following_issues, :update_nested_set_attributes, :update_parent_attributes, :create_journal + # Should be after_create but would be called before previous after_save callbacks + after_save :after_create_from_copy + after_destroy :update_parent_attributes + + # Returns a SQL conditions string used to find all issues visible by the specified user + def self.visible_condition(user, options={}) + Project.allowed_to_condition(user, :view_issues, options) do |role, user| + if user.logged? + case role.issues_visibility + when 'all' + nil + when 'default' + user_ids = [user.id] + user.groups.map(&:id) + "(#{table_name}.is_private = #{connection.quoted_false} OR #{table_name}.author_id = #{user.id} OR #{table_name}.assigned_to_id IN (#{user_ids.join(',')}))" + when 'own' + user_ids = [user.id] + user.groups.map(&:id) + "(#{table_name}.author_id = #{user.id} OR #{table_name}.assigned_to_id IN (#{user_ids.join(',')}))" + else + '1=0' + end + else + "(#{table_name}.is_private = #{connection.quoted_false})" + end + end + end + + # Returns true if usr or current user is allowed to view the issue + def visible?(usr=nil) + (usr || User.current).allowed_to?(:view_issues, self.project) do |role, user| + if user.logged? + case role.issues_visibility + when 'all' + true + when 'default' + !self.is_private? || (self.author == user || user.is_or_belongs_to?(assigned_to)) + when 'own' + self.author == user || user.is_or_belongs_to?(assigned_to) + else + false + end + else + !self.is_private? + end + end + end + + # Returns true if user or current user is allowed to edit or add a note to the issue + def editable?(user=User.current) + user.allowed_to?(:edit_issues, project) || user.allowed_to?(:add_issue_notes, project) + end + + def initialize(attributes=nil, *args) + super + if new_record? + # set default values for new records only + self.status ||= IssueStatus.default + self.priority ||= IssuePriority.default + self.watcher_user_ids = [] + end + end + + def create_or_update + super + ensure + @status_was = nil + end + private :create_or_update + + # AR#Persistence#destroy would raise and RecordNotFound exception + # if the issue was already deleted or updated (non matching lock_version). + # This is a problem when bulk deleting issues or deleting a project + # (because an issue may already be deleted if its parent was deleted + # first). + # The issue is reloaded by the nested_set before being deleted so + # the lock_version condition should not be an issue but we handle it. + def destroy + super + rescue ActiveRecord::RecordNotFound + # Stale or already deleted + begin + reload + rescue ActiveRecord::RecordNotFound + # The issue was actually already deleted + @destroyed = true + return freeze + end + # The issue was stale, retry to destroy + super + end + + alias :base_reload :reload + def reload(*args) + @workflow_rule_by_attribute = nil + @assignable_versions = nil + @relations = nil + base_reload(*args) + end + + # Overrides Redmine::Acts::Customizable::InstanceMethods#available_custom_fields + def available_custom_fields + (project && tracker) ? (project.all_issue_custom_fields & tracker.custom_fields.all) : [] + end + + # Copies attributes from another issue, arg can be an id or an Issue + def copy_from(arg, options={}) + issue = arg.is_a?(Issue) ? arg : Issue.visible.find(arg) + self.attributes = issue.attributes.dup.except("id", "root_id", "parent_id", "lft", "rgt", "created_on", "updated_on") + self.custom_field_values = issue.custom_field_values.inject({}) {|h,v| h[v.custom_field_id] = v.value; h} + self.status = issue.status + self.author = User.current + unless options[:attachments] == false + self.attachments = issue.attachments.map do |attachement| + attachement.copy(:container => self) + end + end + @copied_from = issue + @copy_options = options + self + end + + # Returns an unsaved copy of the issue + def copy(attributes=nil, copy_options={}) + copy = self.class.new.copy_from(self, copy_options) + copy.attributes = attributes if attributes + copy + end + + # Returns true if the issue is a copy + def copy? + @copied_from.present? + end + + # Moves/copies an issue to a new project and tracker + # Returns the moved/copied issue on success, false on failure + def move_to_project(new_project, new_tracker=nil, options={}) + ActiveSupport::Deprecation.warn "Issue#move_to_project is deprecated, use #project= instead." + + if options[:copy] + issue = self.copy + else + issue = self + end + + issue.init_journal(User.current, options[:notes]) + + # Preserve previous behaviour + # #move_to_project doesn't change tracker automatically + issue.send :project=, new_project, true + if new_tracker + issue.tracker = new_tracker + end + # Allow bulk setting of attributes on the issue + if options[:attributes] + issue.attributes = options[:attributes] + end + + issue.save ? issue : false + end + + def status_id=(sid) + self.status = nil + result = write_attribute(:status_id, sid) + @workflow_rule_by_attribute = nil + result + end + + def priority_id=(pid) + self.priority = nil + write_attribute(:priority_id, pid) + end + + def category_id=(cid) + self.category = nil + write_attribute(:category_id, cid) + end + + def fixed_version_id=(vid) + self.fixed_version = nil + write_attribute(:fixed_version_id, vid) + end + + def tracker_id=(tid) + self.tracker = nil + result = write_attribute(:tracker_id, tid) + @custom_field_values = nil + @workflow_rule_by_attribute = nil + result + end + + def project_id=(project_id) + if project_id.to_s != self.project_id.to_s + self.project = (project_id.present? ? Project.find_by_id(project_id) : nil) + end + end + + def project=(project, keep_tracker=false) + project_was = self.project + write_attribute(:project_id, project ? project.id : nil) + association_instance_set('project', project) + if project_was && project && project_was != project + @assignable_versions = nil + + unless keep_tracker || project.trackers.include?(tracker) + self.tracker = project.trackers.first + end + # Reassign to the category with same name if any + if category + self.category = project.issue_categories.find_by_name(category.name) + end + # Keep the fixed_version if it's still valid in the new_project + if fixed_version && fixed_version.project != project && !project.shared_versions.include?(fixed_version) + self.fixed_version = nil + end + # Clear the parent task if it's no longer valid + unless valid_parent_project? + self.parent_issue_id = nil + end + @custom_field_values = nil + end + end + + def description=(arg) + if arg.is_a?(String) + arg = arg.gsub(/(\r\n|\n|\r)/, "\r\n") + end + write_attribute(:description, arg) + end + + # Overrides assign_attributes so that project and tracker get assigned first + def assign_attributes_with_project_and_tracker_first(new_attributes, *args) + return if new_attributes.nil? + attrs = new_attributes.dup + attrs.stringify_keys! + + %w(project project_id tracker tracker_id).each do |attr| + if attrs.has_key?(attr) + send "#{attr}=", attrs.delete(attr) + end + end + send :assign_attributes_without_project_and_tracker_first, attrs, *args + end + # Do not redefine alias chain on reload (see #4838) + alias_method_chain(:assign_attributes, :project_and_tracker_first) unless method_defined?(:assign_attributes_without_project_and_tracker_first) + + def estimated_hours=(h) + write_attribute :estimated_hours, (h.is_a?(String) ? h.to_hours : h) + end + + safe_attributes 'project_id', + :if => lambda {|issue, user| + if issue.new_record? + issue.copy? + elsif user.allowed_to?(:move_issues, issue.project) + projects = Issue.allowed_target_projects_on_move(user) + projects.include?(issue.project) && projects.size > 1 + end + } + + safe_attributes 'tracker_id', + 'status_id', + 'category_id', + 'assigned_to_id', + 'priority_id', + 'fixed_version_id', + 'subject', + 'description', + 'start_date', + 'due_date', + 'done_ratio', + 'estimated_hours', + 'custom_field_values', + 'custom_fields', + 'lock_version', + 'notes', + :if => lambda {|issue, user| issue.new_record? || user.allowed_to?(:edit_issues, issue.project) } + + safe_attributes 'status_id', + 'assigned_to_id', + 'fixed_version_id', + 'done_ratio', + 'lock_version', + 'notes', + :if => lambda {|issue, user| issue.new_statuses_allowed_to(user).any? } + + safe_attributes 'notes', + :if => lambda {|issue, user| user.allowed_to?(:add_issue_notes, issue.project)} + + safe_attributes 'private_notes', + :if => lambda {|issue, user| !issue.new_record? && user.allowed_to?(:set_notes_private, issue.project)} + + safe_attributes 'watcher_user_ids', + :if => lambda {|issue, user| issue.new_record? && user.allowed_to?(:add_issue_watchers, issue.project)} + + safe_attributes 'is_private', + :if => lambda {|issue, user| + user.allowed_to?(:set_issues_private, issue.project) || + (issue.author == user && user.allowed_to?(:set_own_issues_private, issue.project)) + } + + safe_attributes 'parent_issue_id', + :if => lambda {|issue, user| (issue.new_record? || user.allowed_to?(:edit_issues, issue.project)) && + user.allowed_to?(:manage_subtasks, issue.project)} + + def safe_attribute_names(user=nil) + names = super + names -= disabled_core_fields + names -= read_only_attribute_names(user) + names + end + + # Safely sets attributes + # Should be called from controllers instead of #attributes= + # attr_accessible is too rough because we still want things like + # Issue.new(:project => foo) to work + def safe_attributes=(attrs, user=User.current) + return unless attrs.is_a?(Hash) + + attrs = attrs.dup + + # Project and Tracker must be set before since new_statuses_allowed_to depends on it. + if (p = attrs.delete('project_id')) && safe_attribute?('project_id') + if allowed_target_projects(user).collect(&:id).include?(p.to_i) + self.project_id = p + end + end + + if (t = attrs.delete('tracker_id')) && safe_attribute?('tracker_id') + self.tracker_id = t + end + + if (s = attrs.delete('status_id')) && safe_attribute?('status_id') + if new_statuses_allowed_to(user).collect(&:id).include?(s.to_i) + self.status_id = s + end + end + + attrs = delete_unsafe_attributes(attrs, user) + return if attrs.empty? + + unless leaf? + attrs.reject! {|k,v| %w(priority_id done_ratio start_date due_date estimated_hours).include?(k)} + end + + if attrs['parent_issue_id'].present? + s = attrs['parent_issue_id'].to_s + unless (m = s.match(%r{\A#?(\d+)\z})) && (m[1] == parent_id.to_s || Issue.visible(user).exists?(m[1])) + @invalid_parent_issue_id = attrs.delete('parent_issue_id') + end + end + + if attrs['custom_field_values'].present? + attrs['custom_field_values'] = attrs['custom_field_values'].reject {|k, v| read_only_attribute_names(user).include? k.to_s} + end + + if attrs['custom_fields'].present? + attrs['custom_fields'] = attrs['custom_fields'].reject {|c| read_only_attribute_names(user).include? c['id'].to_s} + end + + # mass-assignment security bypass + assign_attributes attrs, :without_protection => true + end + + def disabled_core_fields + tracker ? tracker.disabled_core_fields : [] + end + + # Returns the custom_field_values that can be edited by the given user + def editable_custom_field_values(user=nil) + custom_field_values.reject do |value| + read_only_attribute_names(user).include?(value.custom_field_id.to_s) + end + end + + # Returns the names of attributes that are read-only for user or the current user + # For users with multiple roles, the read-only fields are the intersection of + # read-only fields of each role + # The result is an array of strings where sustom fields are represented with their ids + # + # Examples: + # issue.read_only_attribute_names # => ['due_date', '2'] + # issue.read_only_attribute_names(user) # => [] + def read_only_attribute_names(user=nil) + workflow_rule_by_attribute(user).reject {|attr, rule| rule != 'readonly'}.keys + end + + # Returns the names of required attributes for user or the current user + # For users with multiple roles, the required fields are the intersection of + # required fields of each role + # The result is an array of strings where sustom fields are represented with their ids + # + # Examples: + # issue.required_attribute_names # => ['due_date', '2'] + # issue.required_attribute_names(user) # => [] + def required_attribute_names(user=nil) + workflow_rule_by_attribute(user).reject {|attr, rule| rule != 'required'}.keys + end + + # Returns true if the attribute is required for user + def required_attribute?(name, user=nil) + required_attribute_names(user).include?(name.to_s) + end + + # Returns a hash of the workflow rule by attribute for the given user + # + # Examples: + # issue.workflow_rule_by_attribute # => {'due_date' => 'required', 'start_date' => 'readonly'} + def workflow_rule_by_attribute(user=nil) + return @workflow_rule_by_attribute if @workflow_rule_by_attribute && user.nil? + + user_real = user || User.current + roles = user_real.admin ? Role.all : user_real.roles_for_project(project) + return {} if roles.empty? + + result = {} + workflow_permissions = WorkflowPermission.where(:tracker_id => tracker_id, :old_status_id => status_id, :role_id => roles.map(&:id)).all + if workflow_permissions.any? + workflow_rules = workflow_permissions.inject({}) do |h, wp| + h[wp.field_name] ||= [] + h[wp.field_name] << wp.rule + h + end + workflow_rules.each do |attr, rules| + next if rules.size < roles.size + uniq_rules = rules.uniq + if uniq_rules.size == 1 + result[attr] = uniq_rules.first + else + result[attr] = 'required' + end + end + end + @workflow_rule_by_attribute = result if user.nil? + result + end + private :workflow_rule_by_attribute + + def done_ratio + if Issue.use_status_for_done_ratio? && status && status.default_done_ratio + status.default_done_ratio + else + read_attribute(:done_ratio) + end + end + + def self.use_status_for_done_ratio? + Setting.issue_done_ratio == 'issue_status' + end + + def self.use_field_for_done_ratio? + Setting.issue_done_ratio == 'issue_field' + end + + def validate_issue + if due_date && start_date && due_date < start_date + errors.add :due_date, :greater_than_start_date + end + + if start_date && soonest_start && start_date < soonest_start + errors.add :start_date, :invalid + end + + if fixed_version + if !assignable_versions.include?(fixed_version) + errors.add :fixed_version_id, :inclusion + elsif reopened? && fixed_version.closed? + errors.add :base, I18n.t(:error_can_not_reopen_issue_on_closed_version) + end + end + + # Checks that the issue can not be added/moved to a disabled tracker + if project && (tracker_id_changed? || project_id_changed?) + unless project.trackers.include?(tracker) + errors.add :tracker_id, :inclusion + end + end + + # Checks parent issue assignment + if @invalid_parent_issue_id.present? + errors.add :parent_issue_id, :invalid + elsif @parent_issue + if !valid_parent_project?(@parent_issue) + errors.add :parent_issue_id, :invalid + elsif (@parent_issue != parent) && (all_dependent_issues.include?(@parent_issue) || @parent_issue.all_dependent_issues.include?(self)) + errors.add :parent_issue_id, :invalid + elsif !new_record? + # moving an existing issue + if @parent_issue.root_id != root_id + # we can always move to another tree + elsif move_possible?(@parent_issue) + # move accepted inside tree + else + errors.add :parent_issue_id, :invalid + end + end + end + end + + # Validates the issue against additional workflow requirements + def validate_required_fields + user = new_record? ? author : current_journal.try(:user) + + required_attribute_names(user).each do |attribute| + if attribute =~ /^\d+$/ + attribute = attribute.to_i + v = custom_field_values.detect {|v| v.custom_field_id == attribute } + if v && v.value.blank? + errors.add :base, v.custom_field.name + ' ' + l('activerecord.errors.messages.blank') + end + else + if respond_to?(attribute) && send(attribute).blank? + errors.add attribute, :blank + end + end + end + end + + # Set the done_ratio using the status if that setting is set. This will keep the done_ratios + # even if the user turns off the setting later + def update_done_ratio_from_issue_status + if Issue.use_status_for_done_ratio? && status && status.default_done_ratio + self.done_ratio = status.default_done_ratio + end + end + + def init_journal(user, notes = "") + @current_journal ||= Journal.new(:journalized => self, :user => user, :notes => notes) + if new_record? + @current_journal.notify = false + else + @attributes_before_change = attributes.dup + @custom_values_before_change = {} + self.custom_field_values.each {|c| @custom_values_before_change.store c.custom_field_id, c.value } + end + @current_journal + end + + # Returns the id of the last journal or nil + def last_journal_id + if new_record? + nil + else + journals.maximum(:id) + end + end + + # Returns a scope for journals that have an id greater than journal_id + def journals_after(journal_id) + scope = journals.reorder("#{Journal.table_name}.id ASC") + if journal_id.present? + scope = scope.where("#{Journal.table_name}.id > ?", journal_id.to_i) + end + scope + end + + # Returns the initial status of the issue + # Returns nil for a new issue + def status_was + if status_id_was && status_id_was.to_i > 0 + @status_was ||= IssueStatus.find_by_id(status_id_was) + end + end + + # Return true if the issue is closed, otherwise false + def closed? + self.status.is_closed? + end + + # Return true if the issue is being reopened + def reopened? + if !new_record? && status_id_changed? + status_was = IssueStatus.find_by_id(status_id_was) + status_new = IssueStatus.find_by_id(status_id) + if status_was && status_new && status_was.is_closed? && !status_new.is_closed? + return true + end + end + false + end + + # Return true if the issue is being closed + def closing? + if !new_record? && status_id_changed? + if status_was && status && !status_was.is_closed? && status.is_closed? + return true + end + end + false + end + + # Returns true if the issue is overdue + def overdue? + !due_date.nil? && (due_date < Date.today) && !status.is_closed? + end + + # Is the amount of work done less than it should for the due date + def behind_schedule? + return false if start_date.nil? || due_date.nil? + done_date = start_date + ((due_date - start_date+1)* done_ratio/100).floor + return done_date <= Date.today + end + + # Does this issue have children? + def children? + !leaf? + end + + # Users the issue can be assigned to + def assignable_users + users = project.assignable_users + users << author if author + users << assigned_to if assigned_to + users.uniq.sort + end + + # Versions that the issue can be assigned to + def assignable_versions + return @assignable_versions if @assignable_versions + + versions = project.shared_versions.open.all + if fixed_version + if fixed_version_id_changed? + # nothing to do + elsif project_id_changed? + if project.shared_versions.include?(fixed_version) + versions << fixed_version + end + else + versions << fixed_version + end + end + @assignable_versions = versions.uniq.sort + end + + # Returns true if this issue is blocked by another issue that is still open + def blocked? + !relations_to.detect {|ir| ir.relation_type == 'blocks' && !ir.issue_from.closed?}.nil? + end + + # Returns an array of statuses that user is able to apply + def new_statuses_allowed_to(user=User.current, include_default=false) + if new_record? && @copied_from + [IssueStatus.default, @copied_from.status].compact.uniq.sort + else + initial_status = nil + if new_record? + initial_status = IssueStatus.default + elsif status_id_was + initial_status = IssueStatus.find_by_id(status_id_was) + end + initial_status ||= status + + statuses = initial_status.find_new_statuses_allowed_to( + user.admin ? Role.all : user.roles_for_project(project), + tracker, + author == user, + assigned_to_id_changed? ? assigned_to_id_was == user.id : assigned_to_id == user.id + ) + statuses << initial_status unless statuses.empty? + statuses << IssueStatus.default if include_default + statuses = statuses.compact.uniq.sort + blocked? ? statuses.reject {|s| s.is_closed?} : statuses + end + end + + def assigned_to_was + if assigned_to_id_changed? && assigned_to_id_was.present? + @assigned_to_was ||= User.find_by_id(assigned_to_id_was) + end + end + + # Returns the users that should be notified + def notified_users + notified = [] + # Author and assignee are always notified unless they have been + # locked or don't want to be notified + notified << author if author + if assigned_to + notified += (assigned_to.is_a?(Group) ? assigned_to.users : [assigned_to]) + end + if assigned_to_was + notified += (assigned_to_was.is_a?(Group) ? assigned_to_was.users : [assigned_to_was]) + end + notified = notified.select {|u| u.active? && u.notify_about?(self)} + + notified += project.notified_users + notified.uniq! + # Remove users that can not view the issue + notified.reject! {|user| !visible?(user)} + notified + end + + # Returns the email addresses that should be notified + def recipients + notified_users.collect(&:mail) + end + + # Returns the number of hours spent on this issue + def spent_hours + @spent_hours ||= time_entries.sum(:hours) || 0 + end + + # Returns the total number of hours spent on this issue and its descendants + # + # Example: + # spent_hours => 0.0 + # spent_hours => 50.2 + def total_spent_hours + @total_spent_hours ||= self_and_descendants.sum("#{TimeEntry.table_name}.hours", + :joins => "LEFT JOIN #{TimeEntry.table_name} ON #{TimeEntry.table_name}.issue_id = #{Issue.table_name}.id").to_f || 0.0 + end + + def relations + @relations ||= IssueRelation::Relations.new(self, (relations_from + relations_to).sort) + end + + # Preloads relations for a collection of issues + def self.load_relations(issues) + if issues.any? + relations = IssueRelation.all(:conditions => ["issue_from_id IN (:ids) OR issue_to_id IN (:ids)", {:ids => issues.map(&:id)}]) + issues.each do |issue| + issue.instance_variable_set "@relations", relations.select {|r| r.issue_from_id == issue.id || r.issue_to_id == issue.id} + end + end + end + + # Preloads visible spent time for a collection of issues + def self.load_visible_spent_hours(issues, user=User.current) + if issues.any? + hours_by_issue_id = TimeEntry.visible(user).sum(:hours, :group => :issue_id) + issues.each do |issue| + issue.instance_variable_set "@spent_hours", (hours_by_issue_id[issue.id] || 0) + end + end + end + + # Preloads visible relations for a collection of issues + def self.load_visible_relations(issues, user=User.current) + if issues.any? + issue_ids = issues.map(&:id) + # Relations with issue_from in given issues and visible issue_to + relations_from = IssueRelation.includes(:issue_to => [:status, :project]).where(visible_condition(user)).where(:issue_from_id => issue_ids).all + # Relations with issue_to in given issues and visible issue_from + relations_to = IssueRelation.includes(:issue_from => [:status, :project]).where(visible_condition(user)).where(:issue_to_id => issue_ids).all + + issues.each do |issue| + relations = + relations_from.select {|relation| relation.issue_from_id == issue.id} + + relations_to.select {|relation| relation.issue_to_id == issue.id} + + issue.instance_variable_set "@relations", IssueRelation::Relations.new(issue, relations.sort) + end + end + end + + # Finds an issue relation given its id. + def find_relation(relation_id) + IssueRelation.find(relation_id, :conditions => ["issue_to_id = ? OR issue_from_id = ?", id, id]) + end + + # Returns all the other issues that depend on the issue + def all_dependent_issues(except=[]) + except << self + dependencies = [] + dependencies += relations_from.map(&:issue_to) + dependencies += children unless leaf? + dependencies.compact! + dependencies -= except + dependencies += dependencies.map {|issue| issue.all_dependent_issues(except)}.flatten + if parent + dependencies << parent + dependencies += parent.all_dependent_issues(except + parent.descendants) + end + dependencies + end + + # Returns an array of issues that duplicate this one + def duplicates + relations_to.select {|r| r.relation_type == IssueRelation::TYPE_DUPLICATES}.collect {|r| r.issue_from} + end + + # Returns the due date or the target due date if any + # Used on gantt chart + def due_before + due_date || (fixed_version ? fixed_version.effective_date : nil) + end + + # Returns the time scheduled for this issue. + # + # Example: + # Start Date: 2/26/09, End Date: 3/04/09 + # duration => 6 + def duration + (start_date && due_date) ? due_date - start_date : 0 + end + + # Returns the duration in working days + def working_duration + (start_date && due_date) ? working_days(start_date, due_date) : 0 + end + + def soonest_start(reload=false) + @soonest_start = nil if reload + @soonest_start ||= ( + relations_to(reload).collect{|relation| relation.successor_soonest_start} + + [(@parent_issue || parent).try(:soonest_start)] + ).compact.max + end + + # Sets start_date on the given date or the next working day + # and changes due_date to keep the same working duration. + def reschedule_on(date) + wd = working_duration + date = next_working_date(date) + self.start_date = date + self.due_date = add_working_days(date, wd) + end + + # Reschedules the issue on the given date or the next working day and saves the record. + # If the issue is a parent task, this is done by rescheduling its subtasks. + def reschedule_on!(date) + return if date.nil? + if leaf? + if start_date.nil? || start_date != date + if start_date && start_date > date + # Issue can not be moved earlier than its soonest start date + date = [soonest_start(true), date].compact.max + end + reschedule_on(date) + begin + save + rescue ActiveRecord::StaleObjectError + reload + reschedule_on(date) + save + end + end + else + leaves.each do |leaf| + if leaf.start_date + # Only move subtask if it starts at the same date as the parent + # or if it starts before the given date + if start_date == leaf.start_date || date > leaf.start_date + leaf.reschedule_on!(date) + end + else + leaf.reschedule_on!(date) + end + end + end + end + + def <=>(issue) + if issue.nil? + -1 + elsif root_id != issue.root_id + (root_id || 0) <=> (issue.root_id || 0) + else + (lft || 0) <=> (issue.lft || 0) + end + end + + def to_s + "#{tracker} ##{id}: #{subject}" + end + + # Returns a string of css classes that apply to the issue + def css_classes + s = "issue tracker-#{tracker_id} status-#{status_id} #{priority.try(:css_classes)}" + s << ' closed' if closed? + s << ' overdue' if overdue? + s << ' child' if child? + s << ' parent' unless leaf? + s << ' private' if is_private? + s << ' created-by-me' if User.current.logged? && author_id == User.current.id + s << ' assigned-to-me' if User.current.logged? && assigned_to_id == User.current.id + s + end + + # Saves an issue and a time_entry from the parameters + def save_issue_with_child_records(params, existing_time_entry=nil) + Issue.transaction do + if params[:time_entry] && (params[:time_entry][:hours].present? || params[:time_entry][:comments].present?) && User.current.allowed_to?(:log_time, project) + @time_entry = existing_time_entry || TimeEntry.new + @time_entry.project = project + @time_entry.issue = self + @time_entry.user = User.current + @time_entry.spent_on = User.current.today + @time_entry.attributes = params[:time_entry] + self.time_entries << @time_entry + end + + # TODO: Rename hook + Redmine::Hook.call_hook(:controller_issues_edit_before_save, { :params => params, :issue => self, :time_entry => @time_entry, :journal => @current_journal}) + if save + # TODO: Rename hook + Redmine::Hook.call_hook(:controller_issues_edit_after_save, { :params => params, :issue => self, :time_entry => @time_entry, :journal => @current_journal}) + else + raise ActiveRecord::Rollback + end + end + end + + # Unassigns issues from +version+ if it's no longer shared with issue's project + def self.update_versions_from_sharing_change(version) + # Update issues assigned to the version + update_versions(["#{Issue.table_name}.fixed_version_id = ?", version.id]) + end + + # Unassigns issues from versions that are no longer shared + # after +project+ was moved + def self.update_versions_from_hierarchy_change(project) + moved_project_ids = project.self_and_descendants.reload.collect(&:id) + # Update issues of the moved projects and issues assigned to a version of a moved project + Issue.update_versions(["#{Version.table_name}.project_id IN (?) OR #{Issue.table_name}.project_id IN (?)", moved_project_ids, moved_project_ids]) + end + + def parent_issue_id=(arg) + s = arg.to_s.strip.presence + if s && (m = s.match(%r{\A#?(\d+)\z})) && (@parent_issue = Issue.find_by_id(m[1])) + @parent_issue.id + else + @parent_issue = nil + @invalid_parent_issue_id = arg + end + end + + def parent_issue_id + if @invalid_parent_issue_id + @invalid_parent_issue_id + elsif instance_variable_defined? :@parent_issue + @parent_issue.nil? ? nil : @parent_issue.id + else + parent_id + end + end + + # Returns true if issue's project is a valid + # parent issue project + def valid_parent_project?(issue=parent) + return true if issue.nil? || issue.project_id == project_id + + case Setting.cross_project_subtasks + when 'system' + true + when 'tree' + issue.project.root == project.root + when 'hierarchy' + issue.project.is_or_is_ancestor_of?(project) || issue.project.is_descendant_of?(project) + when 'descendants' + issue.project.is_or_is_ancestor_of?(project) + else + false + end + end + + # Extracted from the ReportsController. + def self.by_tracker(project) + count_and_group_by(:project => project, + :field => 'tracker_id', + :joins => Tracker.table_name) + end + + def self.by_version(project) + count_and_group_by(:project => project, + :field => 'fixed_version_id', + :joins => Version.table_name) + end + + def self.by_priority(project) + count_and_group_by(:project => project, + :field => 'priority_id', + :joins => IssuePriority.table_name) + end + + def self.by_category(project) + count_and_group_by(:project => project, + :field => 'category_id', + :joins => IssueCategory.table_name) + end + + def self.by_assigned_to(project) + count_and_group_by(:project => project, + :field => 'assigned_to_id', + :joins => User.table_name) + end + + def self.by_author(project) + count_and_group_by(:project => project, + :field => 'author_id', + :joins => User.table_name) + end + + def self.by_subproject(project) + ActiveRecord::Base.connection.select_all("select s.id as status_id, + s.is_closed as closed, + #{Issue.table_name}.project_id as project_id, + count(#{Issue.table_name}.id) as total + from + #{Issue.table_name}, #{Project.table_name}, #{IssueStatus.table_name} s + where + #{Issue.table_name}.status_id=s.id + and #{Issue.table_name}.project_id = #{Project.table_name}.id + and #{visible_condition(User.current, :project => project, :with_subprojects => true)} + and #{Issue.table_name}.project_id <> #{project.id} + group by s.id, s.is_closed, #{Issue.table_name}.project_id") if project.descendants.active.any? + end + # End ReportsController extraction + + # Returns an array of projects that user can assign the issue to + def allowed_target_projects(user=User.current) + if new_record? + Project.all(:conditions => Project.allowed_to_condition(user, :add_issues)) + else + self.class.allowed_target_projects_on_move(user) + end + end + + # Returns an array of projects that user can move issues to + def self.allowed_target_projects_on_move(user=User.current) + Project.all(:conditions => Project.allowed_to_condition(user, :move_issues)) + end + + private + + def after_project_change + # Update project_id on related time entries + TimeEntry.update_all(["project_id = ?", project_id], {:issue_id => id}) + + # Delete issue relations + unless Setting.cross_project_issue_relations? + relations_from.clear + relations_to.clear + end + + # Move subtasks that were in the same project + children.each do |child| + next unless child.project_id == project_id_was + # Change project and keep project + child.send :project=, project, true + unless child.save + raise ActiveRecord::Rollback + end + end + end + + # Callback for after the creation of an issue by copy + # * adds a "copied to" relation with the copied issue + # * copies subtasks from the copied issue + def after_create_from_copy + return unless copy? && !@after_create_from_copy_handled + + if (@copied_from.project_id == project_id || Setting.cross_project_issue_relations?) && @copy_options[:link] != false + relation = IssueRelation.new(:issue_from => @copied_from, :issue_to => self, :relation_type => IssueRelation::TYPE_COPIED_TO) + unless relation.save + logger.error "Could not create relation while copying ##{@copied_from.id} to ##{id} due to validation errors: #{relation.errors.full_messages.join(', ')}" if logger + end + end + + unless @copied_from.leaf? || @copy_options[:subtasks] == false + copy_options = (@copy_options || {}).merge(:subtasks => false) + copied_issue_ids = {@copied_from.id => self.id} + @copied_from.reload.descendants.reorder("#{Issue.table_name}.lft").each do |child| + # Do not copy self when copying an issue as a descendant of the copied issue + next if child == self + # Do not copy subtasks of issues that were not copied + next unless copied_issue_ids[child.parent_id] + # Do not copy subtasks that are not visible to avoid potential disclosure of private data + unless child.visible? + logger.error "Subtask ##{child.id} was not copied during ##{@copied_from.id} copy because it is not visible to the current user" if logger + next + end + copy = Issue.new.copy_from(child, copy_options) + copy.author = author + copy.project = project + copy.parent_issue_id = copied_issue_ids[child.parent_id] + unless copy.save + logger.error "Could not copy subtask ##{child.id} while copying ##{@copied_from.id} to ##{id} due to validation errors: #{copy.errors.full_messages.join(', ')}" if logger + next + end + copied_issue_ids[child.id] = copy.id + end + end + @after_create_from_copy_handled = true + end + + def update_nested_set_attributes + if root_id.nil? + # issue was just created + self.root_id = (@parent_issue.nil? ? id : @parent_issue.root_id) + set_default_left_and_right + Issue.update_all("root_id = #{root_id}, lft = #{lft}, rgt = #{rgt}", ["id = ?", id]) + if @parent_issue + move_to_child_of(@parent_issue) + end + reload + elsif parent_issue_id != parent_id + former_parent_id = parent_id + # moving an existing issue + if @parent_issue && @parent_issue.root_id == root_id + # inside the same tree + move_to_child_of(@parent_issue) + else + # to another tree + unless root? + move_to_right_of(root) + reload + end + old_root_id = root_id + self.root_id = (@parent_issue.nil? ? id : @parent_issue.root_id ) + target_maxright = nested_set_scope.maximum(right_column_name) || 0 + offset = target_maxright + 1 - lft + Issue.update_all("root_id = #{root_id}, lft = lft + #{offset}, rgt = rgt + #{offset}", + ["root_id = ? AND lft >= ? AND rgt <= ? ", old_root_id, lft, rgt]) + self[left_column_name] = lft + offset + self[right_column_name] = rgt + offset + if @parent_issue + move_to_child_of(@parent_issue) + end + end + reload + # delete invalid relations of all descendants + self_and_descendants.each do |issue| + issue.relations.each do |relation| + relation.destroy unless relation.valid? + end + end + # update former parent + recalculate_attributes_for(former_parent_id) if former_parent_id + end + remove_instance_variable(:@parent_issue) if instance_variable_defined?(:@parent_issue) + end + + def update_parent_attributes + recalculate_attributes_for(parent_id) if parent_id + end + + def recalculate_attributes_for(issue_id) + if issue_id && p = Issue.find_by_id(issue_id) + # priority = highest priority of children + if priority_position = p.children.maximum("#{IssuePriority.table_name}.position", :joins => :priority) + p.priority = IssuePriority.find_by_position(priority_position) + end + + # start/due dates = lowest/highest dates of children + p.start_date = p.children.minimum(:start_date) + p.due_date = p.children.maximum(:due_date) + if p.start_date && p.due_date && p.due_date < p.start_date + p.start_date, p.due_date = p.due_date, p.start_date + end + + # done ratio = weighted average ratio of leaves + unless Issue.use_status_for_done_ratio? && p.status && p.status.default_done_ratio + leaves_count = p.leaves.count + if leaves_count > 0 + average = p.leaves.average(:estimated_hours).to_f + if average == 0 + average = 1 + end + done = p.leaves.sum("COALESCE(estimated_hours, #{average}) * (CASE WHEN is_closed = #{connection.quoted_true} THEN 100 ELSE COALESCE(done_ratio, 0) END)", :joins => :status).to_f + progress = done / (average * leaves_count) + p.done_ratio = progress.round + end + end + + # estimate = sum of leaves estimates + p.estimated_hours = p.leaves.sum(:estimated_hours).to_f + p.estimated_hours = nil if p.estimated_hours == 0.0 + + # ancestors will be recursively updated + p.save(:validate => false) + end + end + + # Update issues so their versions are not pointing to a + # fixed_version that is not shared with the issue's project + def self.update_versions(conditions=nil) + # Only need to update issues with a fixed_version from + # a different project and that is not systemwide shared + Issue.scoped(:conditions => conditions).all( + :conditions => "#{Issue.table_name}.fixed_version_id IS NOT NULL" + + " AND #{Issue.table_name}.project_id <> #{Version.table_name}.project_id" + + " AND #{Version.table_name}.sharing <> 'system'", + :include => [:project, :fixed_version] + ).each do |issue| + next if issue.project.nil? || issue.fixed_version.nil? + unless issue.project.shared_versions.include?(issue.fixed_version) + issue.init_journal(User.current) + issue.fixed_version = nil + issue.save + end + end + end + + # Callback on file attachment + def attachment_added(obj) + if @current_journal && !obj.new_record? + @current_journal.details << JournalDetail.new(:property => 'attachment', :prop_key => obj.id, :value => obj.filename) + end + end + + # Callback on attachment deletion + def attachment_removed(obj) + if @current_journal && !obj.new_record? + @current_journal.details << JournalDetail.new(:property => 'attachment', :prop_key => obj.id, :old_value => obj.filename) + @current_journal.save + end + end + + # Default assignment based on category + def default_assign + if assigned_to.nil? && category && category.assigned_to + self.assigned_to = category.assigned_to + end + end + + # Updates start/due dates of following issues + def reschedule_following_issues + if start_date_changed? || due_date_changed? + relations_from.each do |relation| + relation.set_issue_to_dates + end + end + end + + # Closes duplicates if the issue is being closed + def close_duplicates + if closing? + duplicates.each do |duplicate| + # Reload is need in case the duplicate was updated by a previous duplicate + duplicate.reload + # Don't re-close it if it's already closed + next if duplicate.closed? + # Same user and notes + if @current_journal + duplicate.init_journal(@current_journal.user, @current_journal.notes) + end + duplicate.update_attribute :status, self.status + end + end + end + + # Make sure updated_on is updated when adding a note and set updated_on now + # so we can set closed_on with the same value on closing + def force_updated_on_change + if @current_journal || changed? + self.updated_on = current_time_from_proper_timezone + if new_record? + self.created_on = updated_on + end + end + end + + # Callback for setting closed_on when the issue is closed. + # The closed_on attribute stores the time of the last closing + # and is preserved when the issue is reopened. + def update_closed_on + if closing? || (new_record? && closed?) + self.closed_on = updated_on + end + end + + # Saves the changes in a Journal + # Called after_save + def create_journal + if @current_journal + # attributes changes + if @attributes_before_change + (Issue.column_names - %w(id root_id lft rgt lock_version created_on updated_on closed_on)).each {|c| + before = @attributes_before_change[c] + after = send(c) + next if before == after || (before.blank? && after.blank?) + @current_journal.details << JournalDetail.new(:property => 'attr', + :prop_key => c, + :old_value => before, + :value => after) + } + end + if @custom_values_before_change + # custom fields changes + custom_field_values.each {|c| + before = @custom_values_before_change[c.custom_field_id] + after = c.value + next if before == after || (before.blank? && after.blank?) + + if before.is_a?(Array) || after.is_a?(Array) + before = [before] unless before.is_a?(Array) + after = [after] unless after.is_a?(Array) + + # values removed + (before - after).reject(&:blank?).each do |value| + @current_journal.details << JournalDetail.new(:property => 'cf', + :prop_key => c.custom_field_id, + :old_value => value, + :value => nil) + end + # values added + (after - before).reject(&:blank?).each do |value| + @current_journal.details << JournalDetail.new(:property => 'cf', + :prop_key => c.custom_field_id, + :old_value => nil, + :value => value) + end + else + @current_journal.details << JournalDetail.new(:property => 'cf', + :prop_key => c.custom_field_id, + :old_value => before, + :value => after) + end + } + end + @current_journal.save + # reset current journal + init_journal @current_journal.user, @current_journal.notes + end + end + + # Query generator for selecting groups of issue counts for a project + # based on specific criteria + # + # Options + # * project - Project to search in. + # * field - String. Issue field to key off of in the grouping. + # * joins - String. The table name to join against. + def self.count_and_group_by(options) + project = options.delete(:project) + select_field = options.delete(:field) + joins = options.delete(:joins) + + where = "#{Issue.table_name}.#{select_field}=j.id" + + ActiveRecord::Base.connection.select_all("select s.id as status_id, + s.is_closed as closed, + j.id as #{select_field}, + count(#{Issue.table_name}.id) as total + from + #{Issue.table_name}, #{Project.table_name}, #{IssueStatus.table_name} s, #{joins} j + where + #{Issue.table_name}.status_id=s.id + and #{where} + and #{Issue.table_name}.project_id=#{Project.table_name}.id + and #{visible_condition(User.current, :project => project)} + group by s.id, s.is_closed, j.id") + end +end diff --git a/app/models/issue_category.rb b/app/models/issue_category.rb new file mode 100644 index 00000000..6efec6a5 --- /dev/null +++ b/app/models/issue_category.rb @@ -0,0 +1,48 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class IssueCategory < ActiveRecord::Base + include Redmine::SafeAttributes + belongs_to :project + belongs_to :assigned_to, :class_name => 'Principal', :foreign_key => 'assigned_to_id' + has_many :issues, :foreign_key => 'category_id', :dependent => :nullify + + validates_presence_of :name + validates_uniqueness_of :name, :scope => [:project_id] + validates_length_of :name, :maximum => 30 + + safe_attributes 'name', 'assigned_to_id' + + scope :named, lambda {|arg| where("LOWER(#{table_name}.name) = LOWER(?)", arg.to_s.strip)} + + alias :destroy_without_reassign :destroy + + # Destroy the category + # If a category is specified, issues are reassigned to this category + def destroy(reassign_to = nil) + if reassign_to && reassign_to.is_a?(IssueCategory) && reassign_to.project == self.project + Issue.update_all({:category_id => reassign_to.id}, {:category_id => id}) + end + destroy_without_reassign + end + + def <=>(category) + name <=> category.name + end + + def to_s; name end +end diff --git a/app/models/issue_custom_field.rb b/app/models/issue_custom_field.rb new file mode 100644 index 00000000..e7ea9c0b --- /dev/null +++ b/app/models/issue_custom_field.rb @@ -0,0 +1,27 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class IssueCustomField < CustomField + has_and_belongs_to_many :projects, :join_table => "#{table_name_prefix}custom_fields_projects#{table_name_suffix}", :foreign_key => "custom_field_id" + has_and_belongs_to_many :trackers, :join_table => "#{table_name_prefix}custom_fields_trackers#{table_name_suffix}", :foreign_key => "custom_field_id" + has_many :issues, :through => :issue_custom_values + + def type_name + :label_issue_plural + end +end + diff --git a/app/models/issue_observer.rb b/app/models/issue_observer.rb new file mode 100644 index 00000000..a7519428 --- /dev/null +++ b/app/models/issue_observer.rb @@ -0,0 +1,22 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class IssueObserver < ActiveRecord::Observer + def after_create(issue) + Mailer.issue_add(issue).deliver if Setting.notified_events.include?('issue_added') + end +end diff --git a/app/models/issue_priority.rb b/app/models/issue_priority.rb new file mode 100644 index 00000000..fa5a29c8 --- /dev/null +++ b/app/models/issue_priority.rb @@ -0,0 +1,68 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class IssuePriority < Enumeration + has_many :issues, :foreign_key => 'priority_id' + + after_destroy {|priority| priority.class.compute_position_names} + after_save {|priority| priority.class.compute_position_names if priority.position_changed? && priority.position} + + OptionName = :enumeration_issue_priorities + + def option_name + OptionName + end + + def objects_count + issues.count + end + + def transfer_relations(to) + issues.update_all("priority_id = #{to.id}") + end + + def css_classes + "priority-#{id} priority-#{position_name}" + end + + # Clears position_name for all priorities + # Called from migration 20121026003537_populate_enumerations_position_name + def self.clear_position_names + update_all :position_name => nil + end + + # Updates position_name for active priorities + # Called from migration 20121026003537_populate_enumerations_position_name + def self.compute_position_names + priorities = where(:active => true).all.sort_by(&:position) + if priorities.any? + default = priorities.detect(&:is_default?) || priorities[(priorities.size - 1) / 2] + priorities.each_with_index do |priority, index| + name = case + when priority.position == default.position + "default" + when priority.position < default.position + index == 0 ? "lowest" : "low#{index+1}" + else + index == (priorities.size - 1) ? "highest" : "high#{priorities.size - index}" + end + + update_all({:position_name => name}, :id => priority.id) + end + end + end +end diff --git a/app/models/issue_priority_custom_field.rb b/app/models/issue_priority_custom_field.rb new file mode 100644 index 00000000..5a691175 --- /dev/null +++ b/app/models/issue_priority_custom_field.rb @@ -0,0 +1,23 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class IssuePriorityCustomField < CustomField + def type_name + :enumeration_issue_priorities + end +end + diff --git a/app/models/issue_query.rb b/app/models/issue_query.rb new file mode 100644 index 00000000..5b818cc2 --- /dev/null +++ b/app/models/issue_query.rb @@ -0,0 +1,405 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class IssueQuery < Query + + self.queried_class = Issue + + self.available_columns = [ + QueryColumn.new(:id, :sortable => "#{Issue.table_name}.id", :default_order => 'desc', :caption => '#', :frozen => true), + QueryColumn.new(:project, :sortable => "#{Project.table_name}.name", :groupable => true), + QueryColumn.new(:tracker, :sortable => "#{Tracker.table_name}.position", :groupable => true), + QueryColumn.new(:parent, :sortable => ["#{Issue.table_name}.root_id", "#{Issue.table_name}.lft ASC"], :default_order => 'desc', :caption => :field_parent_issue), + QueryColumn.new(:status, :sortable => "#{IssueStatus.table_name}.position", :groupable => true), + QueryColumn.new(:priority, :sortable => "#{IssuePriority.table_name}.position", :default_order => 'desc', :groupable => true), + QueryColumn.new(:subject, :sortable => "#{Issue.table_name}.subject"), + QueryColumn.new(:author, :sortable => lambda {User.fields_for_order_statement("authors")}, :groupable => true), + QueryColumn.new(:assigned_to, :sortable => lambda {User.fields_for_order_statement}, :groupable => true), + QueryColumn.new(:updated_on, :sortable => "#{Issue.table_name}.updated_on", :default_order => 'desc'), + QueryColumn.new(:category, :sortable => "#{IssueCategory.table_name}.name", :groupable => true), + QueryColumn.new(:fixed_version, :sortable => lambda {Version.fields_for_order_statement}, :groupable => true), + QueryColumn.new(:start_date, :sortable => "#{Issue.table_name}.start_date"), + QueryColumn.new(:due_date, :sortable => "#{Issue.table_name}.due_date"), + QueryColumn.new(:estimated_hours, :sortable => "#{Issue.table_name}.estimated_hours"), + QueryColumn.new(:done_ratio, :sortable => "#{Issue.table_name}.done_ratio", :groupable => true), + QueryColumn.new(:created_on, :sortable => "#{Issue.table_name}.created_on", :default_order => 'desc'), + QueryColumn.new(:closed_on, :sortable => "#{Issue.table_name}.closed_on", :default_order => 'desc'), + QueryColumn.new(:relations, :caption => :label_related_issues), + QueryColumn.new(:description, :inline => false) + ] + + scope :visible, lambda {|*args| + user = args.shift || User.current + base = Project.allowed_to_condition(user, :view_issues, *args) + user_id = user.logged? ? user.id : 0 + + includes(:project).where("(#{table_name}.project_id IS NULL OR (#{base})) AND (#{table_name}.is_public = ? OR #{table_name}.user_id = ?)", true, user_id) + } + + def initialize(attributes=nil, *args) + super attributes + self.filters ||= { 'status_id' => {:operator => "o", :values => [""]} } + end + + # Returns true if the query is visible to +user+ or the current user. + def visible?(user=User.current) + (project.nil? || user.allowed_to?(:view_issues, project)) && (self.is_public? || self.user_id == user.id) + end + + def initialize_available_filters + principals = [] + subprojects = [] + versions = [] + categories = [] + issue_custom_fields = [] + + if project + principals += project.principals.sort + unless project.leaf? + subprojects = project.descendants.visible.all + principals += Principal.member_of(subprojects) + end + versions = project.shared_versions.all + categories = project.issue_categories.all + issue_custom_fields = project.all_issue_custom_fields + else + if all_projects.any? + principals += Principal.member_of(all_projects) + end + versions = Version.visible.find_all_by_sharing('system') + issue_custom_fields = IssueCustomField.where(:is_filter => true, :is_for_all => true).all + end + principals.uniq! + principals.sort! + users = principals.select {|p| p.is_a?(User)} + + + add_available_filter "status_id", + :type => :list_status, :values => IssueStatus.sorted.all.collect{|s| [s.name, s.id.to_s] } + + if project.nil? + project_values = [] + if User.current.logged? && User.current.memberships.any? + project_values << ["<< #{l(:label_my_projects).downcase} >>", "mine"] + end + project_values += all_projects_values + add_available_filter("project_id", + :type => :list, :values => project_values + ) unless project_values.empty? + end + + add_available_filter "tracker_id", + :type => :list, :values => trackers.collect{|s| [s.name, s.id.to_s] } + add_available_filter "priority_id", + :type => :list, :values => IssuePriority.all.collect{|s| [s.name, s.id.to_s] } + + author_values = [] + author_values << ["<< #{l(:label_me)} >>", "me"] if User.current.logged? + author_values += users.collect{|s| [s.name, s.id.to_s] } + add_available_filter("author_id", + :type => :list, :values => author_values + ) unless author_values.empty? + + assigned_to_values = [] + assigned_to_values << ["<< #{l(:label_me)} >>", "me"] if User.current.logged? + assigned_to_values += (Setting.issue_group_assignment? ? + principals : users).collect{|s| [s.name, s.id.to_s] } + add_available_filter("assigned_to_id", + :type => :list_optional, :values => assigned_to_values + ) unless assigned_to_values.empty? + + group_values = Group.all.collect {|g| [g.name, g.id.to_s] } + add_available_filter("member_of_group", + :type => :list_optional, :values => group_values + ) unless group_values.empty? + + role_values = Role.givable.collect {|r| [r.name, r.id.to_s] } + add_available_filter("assigned_to_role", + :type => :list_optional, :values => role_values + ) unless role_values.empty? + + if versions.any? + add_available_filter "fixed_version_id", + :type => :list_optional, + :values => versions.sort.collect{|s| ["#{s.project.name} - #{s.name}", s.id.to_s] } + end + + if categories.any? + add_available_filter "category_id", + :type => :list_optional, + :values => categories.collect{|s| [s.name, s.id.to_s] } + end + + add_available_filter "subject", :type => :text + add_available_filter "created_on", :type => :date_past + add_available_filter "updated_on", :type => :date_past + add_available_filter "closed_on", :type => :date_past + add_available_filter "start_date", :type => :date + add_available_filter "due_date", :type => :date + add_available_filter "estimated_hours", :type => :float + add_available_filter "done_ratio", :type => :integer + + if User.current.allowed_to?(:set_issues_private, nil, :global => true) || + User.current.allowed_to?(:set_own_issues_private, nil, :global => true) + add_available_filter "is_private", + :type => :list, + :values => [[l(:general_text_yes), "1"], [l(:general_text_no), "0"]] + end + + if User.current.logged? + add_available_filter "watcher_id", + :type => :list, :values => [["<< #{l(:label_me)} >>", "me"]] + end + + if subprojects.any? + add_available_filter "subproject_id", + :type => :list_subprojects, + :values => subprojects.collect{|s| [s.name, s.id.to_s] } + end + + add_custom_fields_filters(issue_custom_fields) + + add_associations_custom_fields_filters :project, :author, :assigned_to, :fixed_version + + IssueRelation::TYPES.each do |relation_type, options| + add_available_filter relation_type, :type => :relation, :label => options[:name] + end + + Tracker.disabled_core_fields(trackers).each {|field| + delete_available_filter field + } + end + + def available_columns + return @available_columns if @available_columns + @available_columns = self.class.available_columns.dup + @available_columns += (project ? + project.all_issue_custom_fields : + IssueCustomField.all + ).collect {|cf| QueryCustomFieldColumn.new(cf) } + + if User.current.allowed_to?(:view_time_entries, project, :global => true) + index = nil + @available_columns.each_with_index {|column, i| index = i if column.name == :estimated_hours} + index = (index ? index + 1 : -1) + # insert the column after estimated_hours or at the end + @available_columns.insert index, QueryColumn.new(:spent_hours, + :sortable => "COALESCE((SELECT SUM(hours) FROM #{TimeEntry.table_name} WHERE #{TimeEntry.table_name}.issue_id = #{Issue.table_name}.id), 0)", + :default_order => 'desc', + :caption => :label_spent_time + ) + end + + if User.current.allowed_to?(:set_issues_private, nil, :global => true) || + User.current.allowed_to?(:set_own_issues_private, nil, :global => true) + @available_columns << QueryColumn.new(:is_private, :sortable => "#{Issue.table_name}.is_private") + end + + disabled_fields = Tracker.disabled_core_fields(trackers).map {|field| field.sub(/_id$/, '')} + @available_columns.reject! {|column| + disabled_fields.include?(column.name.to_s) + } + + @available_columns + end + + def default_columns_names + @default_columns_names ||= begin + default_columns = Setting.issue_list_default_columns.map(&:to_sym) + + project.present? ? default_columns : [:project] | default_columns + end + end + + # Returns the issue count + def issue_count + Issue.visible.count(:include => [:status, :project], :conditions => statement) + rescue ::ActiveRecord::StatementInvalid => e + raise StatementInvalid.new(e.message) + end + + # Returns the issue count by group or nil if query is not grouped + def issue_count_by_group + r = nil + if grouped? + begin + # Rails3 will raise an (unexpected) RecordNotFound if there's only a nil group value + r = Issue.visible.count(:joins => joins_for_order_statement(group_by_statement), :group => group_by_statement, :include => [:status, :project], :conditions => statement) + rescue ActiveRecord::RecordNotFound + r = {nil => issue_count} + end + c = group_by_column + if c.is_a?(QueryCustomFieldColumn) + r = r.keys.inject({}) {|h, k| h[c.custom_field.cast_value(k)] = r[k]; h} + end + end + r + rescue ::ActiveRecord::StatementInvalid => e + raise StatementInvalid.new(e.message) + end + + # Returns the issues + # Valid options are :order, :offset, :limit, :include, :conditions + def issues(options={}) + order_option = [group_by_sort_order, options[:order]].flatten.reject(&:blank?) + + issues = Issue.visible.where(options[:conditions]).all( + :include => ([:status, :project] + (options[:include] || [])).uniq, + :conditions => statement, + :order => order_option, + :joins => joins_for_order_statement(order_option.join(',')), + :limit => options[:limit], + :offset => options[:offset] + ) + + if has_column?(:spent_hours) + Issue.load_visible_spent_hours(issues) + end + if has_column?(:relations) + Issue.load_visible_relations(issues) + end + issues + rescue ::ActiveRecord::StatementInvalid => e + raise StatementInvalid.new(e.message) + end + + # Returns the issues ids + def issue_ids(options={}) + order_option = [group_by_sort_order, options[:order]].flatten.reject(&:blank?) + + Issue.visible.scoped(:conditions => options[:conditions]).scoped(:include => ([:status, :project] + (options[:include] || [])).uniq, + :conditions => statement, + :order => order_option, + :joins => joins_for_order_statement(order_option.join(',')), + :limit => options[:limit], + :offset => options[:offset]).find_ids + rescue ::ActiveRecord::StatementInvalid => e + raise StatementInvalid.new(e.message) + end + + # Returns the journals + # Valid options are :order, :offset, :limit + def journals(options={}) + Journal.visible.all( + :include => [:details, :user, {:issue => [:project, :author, :tracker, :status]}], + :conditions => statement, + :order => options[:order], + :limit => options[:limit], + :offset => options[:offset] + ) + rescue ::ActiveRecord::StatementInvalid => e + raise StatementInvalid.new(e.message) + end + + # Returns the versions + # Valid options are :conditions + def versions(options={}) + Version.visible.where(options[:conditions]).all( + :include => :project, + :conditions => project_statement + ) + rescue ::ActiveRecord::StatementInvalid => e + raise StatementInvalid.new(e.message) + end + + def sql_for_watcher_id_field(field, operator, value) + db_table = Watcher.table_name + "#{Issue.table_name}.id #{ operator == '=' ? 'IN' : 'NOT IN' } (SELECT #{db_table}.watchable_id FROM #{db_table} WHERE #{db_table}.watchable_type='Issue' AND " + + sql_for_field(field, '=', value, db_table, 'user_id') + ')' + end + + def sql_for_member_of_group_field(field, operator, value) + if operator == '*' # Any group + groups = Group.all + operator = '=' # Override the operator since we want to find by assigned_to + elsif operator == "!*" + groups = Group.all + operator = '!' # Override the operator since we want to find by assigned_to + else + groups = Group.find_all_by_id(value) + end + groups ||= [] + + members_of_groups = groups.inject([]) {|user_ids, group| + user_ids + group.user_ids + [group.id] + }.uniq.compact.sort.collect(&:to_s) + + '(' + sql_for_field("assigned_to_id", operator, members_of_groups, Issue.table_name, "assigned_to_id", false) + ')' + end + + def sql_for_assigned_to_role_field(field, operator, value) + case operator + when "*", "!*" # Member / Not member + sw = operator == "!*" ? 'NOT' : '' + nl = operator == "!*" ? "#{Issue.table_name}.assigned_to_id IS NULL OR" : '' + "(#{nl} #{Issue.table_name}.assigned_to_id #{sw} IN (SELECT DISTINCT #{Member.table_name}.user_id FROM #{Member.table_name}" + + " WHERE #{Member.table_name}.project_id = #{Issue.table_name}.project_id))" + when "=", "!" + role_cond = value.any? ? + "#{MemberRole.table_name}.role_id IN (" + value.collect{|val| "'#{connection.quote_string(val)}'"}.join(",") + ")" : + "1=0" + + sw = operator == "!" ? 'NOT' : '' + nl = operator == "!" ? "#{Issue.table_name}.assigned_to_id IS NULL OR" : '' + "(#{nl} #{Issue.table_name}.assigned_to_id #{sw} IN (SELECT DISTINCT #{Member.table_name}.user_id FROM #{Member.table_name}, #{MemberRole.table_name}" + + " WHERE #{Member.table_name}.project_id = #{Issue.table_name}.project_id AND #{Member.table_name}.id = #{MemberRole.table_name}.member_id AND #{role_cond}))" + end + end + + def sql_for_is_private_field(field, operator, value) + op = (operator == "=" ? 'IN' : 'NOT IN') + va = value.map {|v| v == '0' ? connection.quoted_false : connection.quoted_true}.uniq.join(',') + + "#{Issue.table_name}.is_private #{op} (#{va})" + end + + def sql_for_relations(field, operator, value, options={}) + relation_options = IssueRelation::TYPES[field] + return relation_options unless relation_options + + relation_type = field + join_column, target_join_column = "issue_from_id", "issue_to_id" + if relation_options[:reverse] || options[:reverse] + relation_type = relation_options[:reverse] || relation_type + join_column, target_join_column = target_join_column, join_column + end + + sql = case operator + when "*", "!*" + op = (operator == "*" ? 'IN' : 'NOT IN') + "#{Issue.table_name}.id #{op} (SELECT DISTINCT #{IssueRelation.table_name}.#{join_column} FROM #{IssueRelation.table_name} WHERE #{IssueRelation.table_name}.relation_type = '#{connection.quote_string(relation_type)}')" + when "=", "!" + op = (operator == "=" ? 'IN' : 'NOT IN') + "#{Issue.table_name}.id #{op} (SELECT DISTINCT #{IssueRelation.table_name}.#{join_column} FROM #{IssueRelation.table_name} WHERE #{IssueRelation.table_name}.relation_type = '#{connection.quote_string(relation_type)}' AND #{IssueRelation.table_name}.#{target_join_column} = #{value.first.to_i})" + when "=p", "=!p", "!p" + op = (operator == "!p" ? 'NOT IN' : 'IN') + comp = (operator == "=!p" ? '<>' : '=') + "#{Issue.table_name}.id #{op} (SELECT DISTINCT #{IssueRelation.table_name}.#{join_column} FROM #{IssueRelation.table_name}, #{Issue.table_name} relissues WHERE #{IssueRelation.table_name}.relation_type = '#{connection.quote_string(relation_type)}' AND #{IssueRelation.table_name}.#{target_join_column} = relissues.id AND relissues.project_id #{comp} #{value.first.to_i})" + end + + if relation_options[:sym] == field && !options[:reverse] + sqls = [sql, sql_for_relations(field, operator, value, :reverse => true)] + sqls.join(["!", "!*", "!p"].include?(operator) ? " AND " : " OR ") + else + sql + end + end + + IssueRelation::TYPES.keys.each do |relation_type| + alias_method "sql_for_#{relation_type}_field".to_sym, :sql_for_relations + end +end diff --git a/app/models/issue_relation.rb b/app/models/issue_relation.rb new file mode 100644 index 00000000..9e501564 --- /dev/null +++ b/app/models/issue_relation.rb @@ -0,0 +1,182 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class IssueRelation < ActiveRecord::Base + # Class used to represent the relations of an issue + class Relations < Array + include Redmine::I18n + + def initialize(issue, *args) + @issue = issue + super(*args) + end + + def to_s(*args) + map {|relation| "#{l(relation.label_for(@issue))} ##{relation.other_issue(@issue).id}"}.join(', ') + end + end + + belongs_to :issue_from, :class_name => 'Issue', :foreign_key => 'issue_from_id' + belongs_to :issue_to, :class_name => 'Issue', :foreign_key => 'issue_to_id' + + TYPE_RELATES = "relates" + TYPE_DUPLICATES = "duplicates" + TYPE_DUPLICATED = "duplicated" + TYPE_BLOCKS = "blocks" + TYPE_BLOCKED = "blocked" + TYPE_PRECEDES = "precedes" + TYPE_FOLLOWS = "follows" + TYPE_COPIED_TO = "copied_to" + TYPE_COPIED_FROM = "copied_from" + + TYPES = { + TYPE_RELATES => { :name => :label_relates_to, :sym_name => :label_relates_to, + :order => 1, :sym => TYPE_RELATES }, + TYPE_DUPLICATES => { :name => :label_duplicates, :sym_name => :label_duplicated_by, + :order => 2, :sym => TYPE_DUPLICATED }, + TYPE_DUPLICATED => { :name => :label_duplicated_by, :sym_name => :label_duplicates, + :order => 3, :sym => TYPE_DUPLICATES, :reverse => TYPE_DUPLICATES }, + TYPE_BLOCKS => { :name => :label_blocks, :sym_name => :label_blocked_by, + :order => 4, :sym => TYPE_BLOCKED }, + TYPE_BLOCKED => { :name => :label_blocked_by, :sym_name => :label_blocks, + :order => 5, :sym => TYPE_BLOCKS, :reverse => TYPE_BLOCKS }, + TYPE_PRECEDES => { :name => :label_precedes, :sym_name => :label_follows, + :order => 6, :sym => TYPE_FOLLOWS }, + TYPE_FOLLOWS => { :name => :label_follows, :sym_name => :label_precedes, + :order => 7, :sym => TYPE_PRECEDES, :reverse => TYPE_PRECEDES }, + TYPE_COPIED_TO => { :name => :label_copied_to, :sym_name => :label_copied_from, + :order => 8, :sym => TYPE_COPIED_FROM }, + TYPE_COPIED_FROM => { :name => :label_copied_from, :sym_name => :label_copied_to, + :order => 9, :sym => TYPE_COPIED_TO, :reverse => TYPE_COPIED_TO } + }.freeze + + validates_presence_of :issue_from, :issue_to, :relation_type + validates_inclusion_of :relation_type, :in => TYPES.keys + validates_numericality_of :delay, :allow_nil => true + validates_uniqueness_of :issue_to_id, :scope => :issue_from_id + validate :validate_issue_relation + + attr_protected :issue_from_id, :issue_to_id + before_save :handle_issue_order + + def visible?(user=User.current) + (issue_from.nil? || issue_from.visible?(user)) && (issue_to.nil? || issue_to.visible?(user)) + end + + def deletable?(user=User.current) + visible?(user) && + ((issue_from.nil? || user.allowed_to?(:manage_issue_relations, issue_from.project)) || + (issue_to.nil? || user.allowed_to?(:manage_issue_relations, issue_to.project))) + end + + def initialize(attributes=nil, *args) + super + if new_record? + if relation_type.blank? + self.relation_type = IssueRelation::TYPE_RELATES + end + end + end + + def validate_issue_relation + if issue_from && issue_to + errors.add :issue_to_id, :invalid if issue_from_id == issue_to_id + unless issue_from.project_id == issue_to.project_id || + Setting.cross_project_issue_relations? + errors.add :issue_to_id, :not_same_project + end + # detect circular dependencies depending wether the relation should be reversed + if TYPES.has_key?(relation_type) && TYPES[relation_type][:reverse] + errors.add :base, :circular_dependency if issue_from.all_dependent_issues.include? issue_to + else + errors.add :base, :circular_dependency if issue_to.all_dependent_issues.include? issue_from + end + if issue_from.is_descendant_of?(issue_to) || issue_from.is_ancestor_of?(issue_to) + errors.add :base, :cant_link_an_issue_with_a_descendant + end + end + end + + def other_issue(issue) + (self.issue_from_id == issue.id) ? issue_to : issue_from + end + + # Returns the relation type for +issue+ + def relation_type_for(issue) + if TYPES[relation_type] + if self.issue_from_id == issue.id + relation_type + else + TYPES[relation_type][:sym] + end + end + end + + def label_for(issue) + TYPES[relation_type] ? + TYPES[relation_type][(self.issue_from_id == issue.id) ? :name : :sym_name] : + :unknow + end + + def css_classes_for(issue) + "rel-#{relation_type_for(issue)}" + end + + def handle_issue_order + reverse_if_needed + + if TYPE_PRECEDES == relation_type + self.delay ||= 0 + else + self.delay = nil + end + set_issue_to_dates + end + + def set_issue_to_dates + soonest_start = self.successor_soonest_start + if soonest_start && issue_to + issue_to.reschedule_on!(soonest_start) + end + end + + def successor_soonest_start + if (TYPE_PRECEDES == self.relation_type) && delay && issue_from && + (issue_from.start_date || issue_from.due_date) + (issue_from.due_date || issue_from.start_date) + 1 + delay + end + end + + def <=>(relation) + r = TYPES[self.relation_type][:order] <=> TYPES[relation.relation_type][:order] + r == 0 ? id <=> relation.id : r + end + + private + + # Reverses the relation if needed so that it gets stored in the proper way + # Should not be reversed before validation so that it can be displayed back + # as entered on new relation form + def reverse_if_needed + if TYPES.has_key?(relation_type) && TYPES[relation_type][:reverse] + issue_tmp = issue_to + self.issue_to = issue_from + self.issue_from = issue_tmp + self.relation_type = TYPES[relation_type][:reverse] + end + end +end diff --git a/app/models/issue_status.rb b/app/models/issue_status.rb new file mode 100644 index 00000000..0e8c9ea9 --- /dev/null +++ b/app/models/issue_status.rb @@ -0,0 +1,105 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class IssueStatus < ActiveRecord::Base + before_destroy :check_integrity + has_many :workflows, :class_name => 'WorkflowTransition', :foreign_key => "old_status_id" + acts_as_list + + before_destroy :delete_workflow_rules + after_save :update_default + + validates_presence_of :name + validates_uniqueness_of :name + validates_length_of :name, :maximum => 30 + validates_inclusion_of :default_done_ratio, :in => 0..100, :allow_nil => true + + scope :sorted, lambda { order("#{table_name}.position ASC") } + scope :named, lambda {|arg| where("LOWER(#{table_name}.name) = LOWER(?)", arg.to_s.strip)} + + def update_default + IssueStatus.update_all({:is_default => false}, ['id <> ?', id]) if self.is_default? + end + + # Returns the default status for new issues + def self.default + where(:is_default => true).first + end + + # Update all the +Issues+ setting their done_ratio to the value of their +IssueStatus+ + def self.update_issue_done_ratios + if Issue.use_status_for_done_ratio? + IssueStatus.where("default_done_ratio >= 0").all.each do |status| + Issue.update_all({:done_ratio => status.default_done_ratio}, {:status_id => status.id}) + end + end + + return Issue.use_status_for_done_ratio? + end + + # Returns an array of all statuses the given role can switch to + # Uses association cache when called more than one time + def new_statuses_allowed_to(roles, tracker, author=false, assignee=false) + if roles && tracker + role_ids = roles.collect(&:id) + transitions = workflows.select do |w| + role_ids.include?(w.role_id) && + w.tracker_id == tracker.id && + ((!w.author && !w.assignee) || (author && w.author) || (assignee && w.assignee)) + end + transitions.map(&:new_status).compact.sort + else + [] + end + end + + # Same thing as above but uses a database query + # More efficient than the previous method if called just once + def find_new_statuses_allowed_to(roles, tracker, author=false, assignee=false) + if roles.present? && tracker + conditions = "(author = :false AND assignee = :false)" + conditions << " OR author = :true" if author + conditions << " OR assignee = :true" if assignee + + workflows. + includes(:new_status). + where(["role_id IN (:role_ids) AND tracker_id = :tracker_id AND (#{conditions})", + {:role_ids => roles.collect(&:id), :tracker_id => tracker.id, :true => true, :false => false} + ]).all. + map(&:new_status).compact.sort + else + [] + end + end + + def <=>(status) + position <=> status.position + end + + def to_s; name end + + private + + def check_integrity + raise "Can't delete status" if Issue.where(:status_id => id).any? + end + + # Deletes associated workflows + def delete_workflow_rules + WorkflowRule.delete_all(["old_status_id = :id OR new_status_id = :id", {:id => id}]) + end +end diff --git a/app/models/journal.rb b/app/models/journal.rb new file mode 100644 index 00000000..a75c112d --- /dev/null +++ b/app/models/journal.rb @@ -0,0 +1,132 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class Journal < ActiveRecord::Base + belongs_to :journalized, :polymorphic => true + # added as a quick fix to allow eager loading of the polymorphic association + # since always associated to an issue, for now + belongs_to :issue, :foreign_key => :journalized_id + + belongs_to :user + has_many :details, :class_name => "JournalDetail", :dependent => :delete_all + attr_accessor :indice + + acts_as_event :title => Proc.new {|o| status = ((s = o.new_status) ? " (#{s})" : nil); "#{o.issue.tracker} ##{o.issue.id}#{status}: #{o.issue.subject}" }, + :description => :notes, + :author => :user, + :group => :issue, + :type => Proc.new {|o| (s = o.new_status) ? (s.is_closed? ? 'issue-closed' : 'issue-edit') : 'issue-note' }, + :url => Proc.new {|o| {:controller => 'issues', :action => 'show', :id => o.issue.id, :anchor => "change-#{o.id}"}} + + acts_as_activity_provider :type => 'issues', + :author_key => :user_id, + :find_options => {:include => [{:issue => :project}, :details, :user], + :conditions => "#{Journal.table_name}.journalized_type = 'Issue' AND" + + " (#{JournalDetail.table_name}.prop_key = 'status_id' OR #{Journal.table_name}.notes <> '')"} + + before_create :split_private_notes + + scope :visible, lambda {|*args| + user = args.shift || User.current + + includes(:issue => :project). + where(Issue.visible_condition(user, *args)). + where("(#{Journal.table_name}.private_notes = ? OR (#{Project.allowed_to_condition(user, :view_private_notes, *args)}))", false) + } + + def save(*args) + # Do not save an empty journal + (details.empty? && notes.blank?) ? false : super + end + + # Returns the new status if the journal contains a status change, otherwise nil + def new_status + c = details.detect {|detail| detail.prop_key == 'status_id'} + (c && c.value) ? IssueStatus.find_by_id(c.value.to_i) : nil + end + + def new_value_for(prop) + c = details.detect {|detail| detail.prop_key == prop} + c ? c.value : nil + end + + def editable_by?(usr) + usr && usr.logged? && (usr.allowed_to?(:edit_issue_notes, project) || (self.user == usr && usr.allowed_to?(:edit_own_issue_notes, project))) + end + + def project + journalized.respond_to?(:project) ? journalized.project : nil + end + + def attachments + journalized.respond_to?(:attachments) ? journalized.attachments : nil + end + + # Returns a string of css classes + def css_classes + s = 'journal' + s << ' has-notes' unless notes.blank? + s << ' has-details' unless details.blank? + s << ' private-notes' if private_notes? + s + end + + def notify? + @notify != false + end + + def notify=(arg) + @notify = arg + end + + def recipients + notified = journalized.notified_users + if private_notes? + notified = notified.select {|user| user.allowed_to?(:view_private_notes, journalized.project)} + end + notified.map(&:mail) + end + + def watcher_recipients + notified = journalized.notified_watchers + if private_notes? + notified = notified.select {|user| user.allowed_to?(:view_private_notes, journalized.project)} + end + notified.map(&:mail) + end + + private + + def split_private_notes + if private_notes? + if notes.present? + if details.any? + # Split the journal (notes/changes) so we don't have half-private journals + journal = Journal.new(:journalized => journalized, :user => user, :notes => nil, :private_notes => false) + journal.details = details + journal.save + self.details = [] + self.created_on = journal.created_on + end + else + # Blank notes should not be private + self.private_notes = false + end + end + true + end +end diff --git a/app/models/journal_detail.rb b/app/models/journal_detail.rb new file mode 100644 index 00000000..1ec19573 --- /dev/null +++ b/app/models/journal_detail.rb @@ -0,0 +1,41 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class JournalDetail < ActiveRecord::Base + belongs_to :journal + before_save :normalize_values + + private + + def normalize_values + self.value = normalize(value) + self.old_value = normalize(old_value) + end + + def normalize(v) + case v + when true + "1" + when false + "0" + when Date + v.strftime("%Y-%m-%d") + else + v + end + end +end diff --git a/app/models/journal_observer.rb b/app/models/journal_observer.rb new file mode 100644 index 00000000..fe937de0 --- /dev/null +++ b/app/models/journal_observer.rb @@ -0,0 +1,29 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class JournalObserver < ActiveRecord::Observer + def after_create(journal) + if journal.notify? && + (Setting.notified_events.include?('issue_updated') || + (Setting.notified_events.include?('issue_note_added') && journal.notes.present?) || + (Setting.notified_events.include?('issue_status_updated') && journal.new_status.present?) || + (Setting.notified_events.include?('issue_priority_updated') && journal.new_value_for('priority_id').present?) + ) + Mailer.issue_edit(journal).deliver + end + end +end diff --git a/app/models/journals_for_message.rb b/app/models/journals_for_message.rb new file mode 100644 index 00000000..8b99b989 --- /dev/null +++ b/app/models/journals_for_message.rb @@ -0,0 +1,12 @@ +class JournalsForMessage < ActiveRecord::Base + attr_accessible :jour_id, :jour_type, :notes, :reply_id, :status, :user_id + attr_accessor :indice + + belongs_to :jour, :polymorphic => true + belongs_to :user + + def self.delete_message(message_id) + self.delete_all "id = #{message_id}" + end + +end diff --git a/app/models/mail_handler.rb b/app/models/mail_handler.rb new file mode 100644 index 00000000..8421fb67 --- /dev/null +++ b/app/models/mail_handler.rb @@ -0,0 +1,490 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class MailHandler < ActionMailer::Base + include ActionView::Helpers::SanitizeHelper + include Redmine::I18n + + class UnauthorizedAction < StandardError; end + class MissingInformation < StandardError; end + + attr_reader :email, :user + + def self.receive(email, options={}) + @@handler_options = options.dup + + @@handler_options[:issue] ||= {} + + if @@handler_options[:allow_override].is_a?(String) + @@handler_options[:allow_override] = @@handler_options[:allow_override].split(',').collect(&:strip) + end + @@handler_options[:allow_override] ||= [] + # Project needs to be overridable if not specified + @@handler_options[:allow_override] << 'project' unless @@handler_options[:issue].has_key?(:project) + # Status overridable by default + @@handler_options[:allow_override] << 'status' unless @@handler_options[:issue].has_key?(:status) + + @@handler_options[:no_account_notice] = (@@handler_options[:no_account_notice].to_s == '1') + @@handler_options[:no_notification] = (@@handler_options[:no_notification].to_s == '1') + @@handler_options[:no_permission_check] = (@@handler_options[:no_permission_check].to_s == '1') + + email.force_encoding('ASCII-8BIT') if email.respond_to?(:force_encoding) + super(email) + end + + def logger + Rails.logger + end + + cattr_accessor :ignored_emails_headers + @@ignored_emails_headers = { + 'X-Auto-Response-Suppress' => 'oof', + 'Auto-Submitted' => /^auto-/ + } + + # Processes incoming emails + # Returns the created object (eg. an issue, a message) or false + def receive(email) + @email = email + sender_email = email.from.to_a.first.to_s.strip + # Ignore emails received from the application emission address to avoid hell cycles + if sender_email.downcase == Setting.mail_from.to_s.strip.downcase + if logger && logger.info + logger.info "MailHandler: ignoring email from Redmine emission address [#{sender_email}]" + end + return false + end + # Ignore auto generated emails + self.class.ignored_emails_headers.each do |key, ignored_value| + value = email.header[key] + if value + value = value.to_s.downcase + if (ignored_value.is_a?(Regexp) && value.match(ignored_value)) || value == ignored_value + if logger && logger.info + logger.info "MailHandler: ignoring email with #{key}:#{value} header" + end + return false + end + end + end + @user = User.find_by_mail(sender_email) if sender_email.present? + if @user && !@user.active? + if logger && logger.info + logger.info "MailHandler: ignoring email from non-active user [#{@user.login}]" + end + return false + end + if @user.nil? + # Email was submitted by an unknown user + case @@handler_options[:unknown_user] + when 'accept' + @user = User.anonymous + when 'create' + @user = create_user_from_email + if @user + if logger && logger.info + logger.info "MailHandler: [#{@user.login}] account created" + end + add_user_to_group(@@handler_options[:default_group]) + unless @@handler_options[:no_account_notice] + Mailer.account_information(@user, @user.password).deliver + end + else + if logger && logger.error + logger.error "MailHandler: could not create account for [#{sender_email}]" + end + return false + end + else + # Default behaviour, emails from unknown users are ignored + if logger && logger.info + logger.info "MailHandler: ignoring email from unknown user [#{sender_email}]" + end + return false + end + end + User.current = @user + dispatch + end + + private + + MESSAGE_ID_RE = %r{^ e + # TODO: send a email to the user + logger.error e.message if logger + false + rescue MissingInformation => e + logger.error "MailHandler: missing information from #{user}: #{e.message}" if logger + false + rescue UnauthorizedAction => e + logger.error "MailHandler: unauthorized attempt from #{user}" if logger + false + end + + def dispatch_to_default + receive_issue + end + + # Creates a new issue + def receive_issue + project = target_project + # check permission + unless @@handler_options[:no_permission_check] + raise UnauthorizedAction unless user.allowed_to?(:add_issues, project) + end + + issue = Issue.new(:author => user, :project => project) + issue.safe_attributes = issue_attributes_from_keywords(issue) + issue.safe_attributes = {'custom_field_values' => custom_field_values_from_keywords(issue)} + issue.subject = cleaned_up_subject + if issue.subject.blank? + issue.subject = '(no subject)' + end + issue.description = cleaned_up_text_body + + # add To and Cc as watchers before saving so the watchers can reply to Redmine + add_watchers(issue) + issue.save! + add_attachments(issue) + logger.info "MailHandler: issue ##{issue.id} created by #{user}" if logger && logger.info + issue + end + + # Adds a note to an existing issue + def receive_issue_reply(issue_id, from_journal=nil) + issue = Issue.find_by_id(issue_id) + return unless issue + # check permission + unless @@handler_options[:no_permission_check] + unless user.allowed_to?(:add_issue_notes, issue.project) || + user.allowed_to?(:edit_issues, issue.project) + raise UnauthorizedAction + end + end + + # ignore CLI-supplied defaults for new issues + @@handler_options[:issue].clear + + journal = issue.init_journal(user) + if from_journal && from_journal.private_notes? + # If the received email was a reply to a private note, make the added note private + issue.private_notes = true + end + issue.safe_attributes = issue_attributes_from_keywords(issue) + issue.safe_attributes = {'custom_field_values' => custom_field_values_from_keywords(issue)} + journal.notes = cleaned_up_text_body + add_attachments(issue) + issue.save! + if logger && logger.info + logger.info "MailHandler: issue ##{issue.id} updated by #{user}" + end + journal + end + + # Reply will be added to the issue + def receive_journal_reply(journal_id) + journal = Journal.find_by_id(journal_id) + if journal && journal.journalized_type == 'Issue' + receive_issue_reply(journal.journalized_id, journal) + end + end + + # Receives a reply to a forum message + def receive_message_reply(message_id) + message = Message.find_by_id(message_id) + if message + message = message.root + + unless @@handler_options[:no_permission_check] + raise UnauthorizedAction unless user.allowed_to?(:add_messages, message.project) + end + + if !message.locked? + reply = Message.new(:subject => cleaned_up_subject.gsub(%r{^.*msg\d+\]}, '').strip, + :content => cleaned_up_text_body) + reply.author = user + reply.board = message.board + message.children << reply + add_attachments(reply) + reply + else + if logger && logger.info + logger.info "MailHandler: ignoring reply from [#{sender_email}] to a locked topic" + end + end + end + end + + def add_attachments(obj) + if email.attachments && email.attachments.any? + email.attachments.each do |attachment| + obj.attachments << Attachment.create(:container => obj, + :file => attachment.decoded, + :filename => attachment.filename, + :author => user, + :content_type => attachment.mime_type) + end + end + end + + # Adds To and Cc as watchers of the given object if the sender has the + # appropriate permission + def add_watchers(obj) + if user.allowed_to?("add_#{obj.class.name.underscore}_watchers".to_sym, obj.project) + addresses = [email.to, email.cc].flatten.compact.uniq.collect {|a| a.strip.downcase} + unless addresses.empty? + watchers = User.active.where('LOWER(mail) IN (?)', addresses).all + watchers.each {|w| obj.add_watcher(w)} + end + end + end + + def get_keyword(attr, options={}) + @keywords ||= {} + if @keywords.has_key?(attr) + @keywords[attr] + else + @keywords[attr] = begin + if (options[:override] || @@handler_options[:allow_override].include?(attr.to_s)) && + (v = extract_keyword!(plain_text_body, attr, options[:format])) + v + elsif !@@handler_options[:issue][attr].blank? + @@handler_options[:issue][attr] + end + end + end + end + + # Destructively extracts the value for +attr+ in +text+ + # Returns nil if no matching keyword found + def extract_keyword!(text, attr, format=nil) + keys = [attr.to_s.humanize] + if attr.is_a?(Symbol) + if user && user.language.present? + keys << l("field_#{attr}", :default => '', :locale => user.language) + end + if Setting.default_language.present? + keys << l("field_#{attr}", :default => '', :locale => Setting.default_language) + end + end + keys.reject! {|k| k.blank?} + keys.collect! {|k| Regexp.escape(k)} + format ||= '.+' + keyword = nil + regexp = /^(#{keys.join('|')})[ \t]*:[ \t]*(#{format})\s*$/i + if m = text.match(regexp) + keyword = m[2].strip + text.gsub!(regexp, '') + end + keyword + end + + def target_project + # TODO: other ways to specify project: + # * parse the email To field + # * specific project (eg. Setting.mail_handler_target_project) + target = Project.find_by_identifier(get_keyword(:project)) + raise MissingInformation.new('Unable to determine target project') if target.nil? + target + end + + # Returns a Hash of issue attributes extracted from keywords in the email body + def issue_attributes_from_keywords(issue) + assigned_to = (k = get_keyword(:assigned_to, :override => true)) && find_assignee_from_keyword(k, issue) + + attrs = { + 'tracker_id' => (k = get_keyword(:tracker)) && issue.project.trackers.named(k).first.try(:id), + 'status_id' => (k = get_keyword(:status)) && IssueStatus.named(k).first.try(:id), + 'priority_id' => (k = get_keyword(:priority)) && IssuePriority.named(k).first.try(:id), + 'category_id' => (k = get_keyword(:category)) && issue.project.issue_categories.named(k).first.try(:id), + 'assigned_to_id' => assigned_to.try(:id), + 'fixed_version_id' => (k = get_keyword(:fixed_version, :override => true)) && + issue.project.shared_versions.named(k).first.try(:id), + 'start_date' => get_keyword(:start_date, :override => true, :format => '\d{4}-\d{2}-\d{2}'), + 'due_date' => get_keyword(:due_date, :override => true, :format => '\d{4}-\d{2}-\d{2}'), + 'estimated_hours' => get_keyword(:estimated_hours, :override => true), + 'done_ratio' => get_keyword(:done_ratio, :override => true, :format => '(\d|10)?0') + }.delete_if {|k, v| v.blank? } + + if issue.new_record? && attrs['tracker_id'].nil? + attrs['tracker_id'] = issue.project.trackers.first.try(:id) + end + + attrs + end + + # Returns a Hash of issue custom field values extracted from keywords in the email body + def custom_field_values_from_keywords(customized) + customized.custom_field_values.inject({}) do |h, v| + if keyword = get_keyword(v.custom_field.name, :override => true) + h[v.custom_field.id.to_s] = v.custom_field.value_from_keyword(keyword, customized) + end + h + end + end + + # Returns the text/plain part of the email + # If not found (eg. HTML-only email), returns the body with tags removed + def plain_text_body + return @plain_text_body unless @plain_text_body.nil? + + part = email.text_part || email.html_part || email + @plain_text_body = Redmine::CodesetUtil.to_utf8(part.body.decoded, part.charset) + + # strip html tags and remove doctype directive + @plain_text_body = strip_tags(@plain_text_body.strip) + @plain_text_body.sub! %r{^$/) + addr, name = m[2], m[1] + end + if addr.present? + user = self.class.new_user_from_attributes(addr, name) + if @@handler_options[:no_notification] + user.mail_notification = 'none' + end + if user.save + user + else + logger.error "MailHandler: failed to create User: #{user.errors.full_messages}" if logger + nil + end + else + logger.error "MailHandler: failed to create User: no FROM address found" if logger + nil + end + end + + # Adds the newly created user to default group + def add_user_to_group(default_group) + if default_group.present? + default_group.split(',').each do |group_name| + if group = Group.named(group_name).first + group.users << @user + elsif logger + logger.warn "MailHandler: could not add user to [#{group_name}], group not found" + end + end + end + end + + # Removes the email body of text after the truncation configurations. + def cleanup_body(body) + delimiters = Setting.mail_handler_body_delimiters.to_s.split(/[\r\n]+/).reject(&:blank?).map {|s| Regexp.escape(s)} + unless delimiters.empty? + regex = Regexp.new("^[> ]*(#{ delimiters.join('|') })\s*[\r\n].*", Regexp::MULTILINE) + body = body.gsub(regex, '') + end + body.strip + end + + def find_assignee_from_keyword(keyword, issue) + keyword = keyword.to_s.downcase + assignable = issue.assignable_users + assignee = nil + assignee ||= assignable.detect {|a| + a.mail.to_s.downcase == keyword || + a.login.to_s.downcase == keyword + } + if assignee.nil? && keyword.match(/ /) + firstname, lastname = *(keyword.split) # "First Last Throwaway" + assignee ||= assignable.detect {|a| + a.is_a?(User) && a.firstname.to_s.downcase == firstname && + a.lastname.to_s.downcase == lastname + } + end + if assignee.nil? + assignee ||= assignable.detect {|a| a.name.downcase == keyword} + end + assignee + end +end diff --git a/app/models/mailer.rb b/app/models/mailer.rb new file mode 100644 index 00000000..7166025c --- /dev/null +++ b/app/models/mailer.rb @@ -0,0 +1,474 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class Mailer < ActionMailer::Base + layout 'mailer' + helper :application + helper :issues + helper :custom_fields + + include Redmine::I18n + + def self.default_url_options + { :host => Setting.host_name, :protocol => Setting.protocol } + end + + # Builds a Mail::Message object used to email recipients of the added issue. + # + # Example: + # issue_add(issue) => Mail::Message object + # Mailer.issue_add(issue).deliver => sends an email to issue recipients + def issue_add(issue) + redmine_headers 'Project' => issue.project.identifier, + 'Issue-Id' => issue.id, + 'Issue-Author' => issue.author.login + redmine_headers 'Issue-Assignee' => issue.assigned_to.login if issue.assigned_to + message_id issue + @author = issue.author + @issue = issue + @issue_url = url_for(:controller => 'issues', :action => 'show', :id => issue) + recipients = issue.recipients + cc = issue.watcher_recipients - recipients + mail :to => recipients, + :cc => cc, + :subject => "[#{issue.project.name} - #{issue.tracker.name} ##{issue.id}] (#{issue.status.name}) #{issue.subject}" + end + + # Builds a Mail::Message object used to email recipients of the edited issue. + # + # Example: + # issue_edit(journal) => Mail::Message object + # Mailer.issue_edit(journal).deliver => sends an email to issue recipients + def issue_edit(journal) + issue = journal.journalized.reload + redmine_headers 'Project' => issue.project.identifier, + 'Issue-Id' => issue.id, + 'Issue-Author' => issue.author.login + redmine_headers 'Issue-Assignee' => issue.assigned_to.login if issue.assigned_to + message_id journal + references issue + @author = journal.user + recipients = journal.recipients + # Watchers in cc + cc = journal.watcher_recipients - recipients + s = "[#{issue.project.name} - #{issue.tracker.name} ##{issue.id}] " + s << "(#{issue.status.name}) " if journal.new_value_for('status_id') + s << issue.subject + @issue = issue + @journal = journal + @issue_url = url_for(:controller => 'issues', :action => 'show', :id => issue, :anchor => "change-#{journal.id}") + mail :to => recipients, + :cc => cc, + :subject => s + end + + def reminder(user, issues, days) + set_language_if_valid user.language + @issues = issues + @days = days + @issues_url = url_for(:controller => 'issues', :action => 'index', + :set_filter => 1, :assigned_to_id => user.id, + :sort => 'due_date:asc') + mail :to => user.mail, + :subject => l(:mail_subject_reminder, :count => issues.size, :days => days) + end + + # Builds a Mail::Message object used to email users belonging to the added document's project. + # + # Example: + # document_added(document) => Mail::Message object + # Mailer.document_added(document).deliver => sends an email to the document's project recipients + def document_added(document) + redmine_headers 'Project' => document.project.identifier + @author = User.current + @document = document + @document_url = url_for(:controller => 'documents', :action => 'show', :id => document) + mail :to => document.recipients, + :subject => "[#{document.project.name}] #{l(:label_document_new)}: #{document.title}" + end + + # Builds a Mail::Message object used to email recipients of a project when an attachements are added. + # + # Example: + # attachments_added(attachments) => Mail::Message object + # Mailer.attachments_added(attachments).deliver => sends an email to the project's recipients + def attachments_added(attachments) + container = attachments.first.container + added_to = '' + added_to_url = '' + @author = attachments.first.author + case container.class.name + when 'Project' + added_to_url = url_for(:controller => 'files', :action => 'index', :project_id => container) + added_to = "#{l(:label_project)}: #{container}" + recipients = container.project.notified_users.select {|user| user.allowed_to?(:view_files, container.project)}.collect {|u| u.mail} + when 'Version' + added_to_url = url_for(:controller => 'files', :action => 'index', :project_id => container.project) + added_to = "#{l(:label_version)}: #{container.name}" + recipients = container.project.notified_users.select {|user| user.allowed_to?(:view_files, container.project)}.collect {|u| u.mail} + when 'Document' + added_to_url = url_for(:controller => 'documents', :action => 'show', :id => container.id) + added_to = "#{l(:label_document)}: #{container.title}" + recipients = container.recipients + end + redmine_headers 'Project' => container.project.identifier + @attachments = attachments + @added_to = added_to + @added_to_url = added_to_url + mail :to => recipients, + :subject => "[#{container.project.name}] #{l(:label_attachment_new)}" + end + + # Builds a Mail::Message object used to email recipients of a news' project when a news item is added. + # + # Example: + # news_added(news) => Mail::Message object + # Mailer.news_added(news).deliver => sends an email to the news' project recipients + def news_added(news) + redmine_headers 'Project' => news.project.identifier + @author = news.author + message_id news + @news = news + @news_url = url_for(:controller => 'news', :action => 'show', :id => news) + mail :to => news.recipients, + :subject => "[#{news.project.name}] #{l(:label_news)}: #{news.title}" + end + + # Builds a Mail::Message object used to email recipients of a news' project when a news comment is added. + # + # Example: + # news_comment_added(comment) => Mail::Message object + # Mailer.news_comment_added(comment) => sends an email to the news' project recipients + def news_comment_added(comment) + news = comment.commented + redmine_headers 'Project' => news.project.identifier + @author = comment.author + message_id comment + @news = news + @comment = comment + @news_url = url_for(:controller => 'news', :action => 'show', :id => news) + mail :to => news.recipients, + :cc => news.watcher_recipients, + :subject => "Re: [#{news.project.name}] #{l(:label_news)}: #{news.title}" + end + + # Builds a Mail::Message object used to email the recipients of the specified message that was posted. + # + # Example: + # message_posted(message) => Mail::Message object + # Mailer.message_posted(message).deliver => sends an email to the recipients + def message_posted(message) + redmine_headers 'Project' => message.project.identifier, + 'Topic-Id' => (message.parent_id || message.id) + @author = message.author + message_id message + references message.parent unless message.parent.nil? + recipients = message.recipients + cc = ((message.root.watcher_recipients + message.board.watcher_recipients).uniq - recipients) + @message = message + @message_url = url_for(message.event_url) + mail :to => recipients, + :cc => cc, + :subject => "[#{message.board.project.name} - #{message.board.name} - msg#{message.root.id}] #{message.subject}" + end + + # Builds a Mail::Message object used to email the recipients of a project of the specified wiki content was added. + # + # Example: + # wiki_content_added(wiki_content) => Mail::Message object + # Mailer.wiki_content_added(wiki_content).deliver => sends an email to the project's recipients + def wiki_content_added(wiki_content) + redmine_headers 'Project' => wiki_content.project.identifier, + 'Wiki-Page-Id' => wiki_content.page.id + @author = wiki_content.author + message_id wiki_content + recipients = wiki_content.recipients + cc = wiki_content.page.wiki.watcher_recipients - recipients + @wiki_content = wiki_content + @wiki_content_url = url_for(:controller => 'wiki', :action => 'show', + :project_id => wiki_content.project, + :id => wiki_content.page.title) + mail :to => recipients, + :cc => cc, + :subject => "[#{wiki_content.project.name}] #{l(:mail_subject_wiki_content_added, :id => wiki_content.page.pretty_title)}" + end + + # Builds a Mail::Message object used to email the recipients of a project of the specified wiki content was updated. + # + # Example: + # wiki_content_updated(wiki_content) => Mail::Message object + # Mailer.wiki_content_updated(wiki_content).deliver => sends an email to the project's recipients + def wiki_content_updated(wiki_content) + redmine_headers 'Project' => wiki_content.project.identifier, + 'Wiki-Page-Id' => wiki_content.page.id + @author = wiki_content.author + message_id wiki_content + recipients = wiki_content.recipients + cc = wiki_content.page.wiki.watcher_recipients + wiki_content.page.watcher_recipients - recipients + @wiki_content = wiki_content + @wiki_content_url = url_for(:controller => 'wiki', :action => 'show', + :project_id => wiki_content.project, + :id => wiki_content.page.title) + @wiki_diff_url = url_for(:controller => 'wiki', :action => 'diff', + :project_id => wiki_content.project, :id => wiki_content.page.title, + :version => wiki_content.version) + mail :to => recipients, + :cc => cc, + :subject => "[#{wiki_content.project.name}] #{l(:mail_subject_wiki_content_updated, :id => wiki_content.page.pretty_title)}" + end + + # Builds a Mail::Message object used to email the specified user their account information. + # + # Example: + # account_information(user, password) => Mail::Message object + # Mailer.account_information(user, password).deliver => sends account information to the user + def account_information(user, password) + set_language_if_valid user.language + @user = user + @password = password + @login_url = url_for(:controller => 'account', :action => 'login') + mail :to => user.mail, + :subject => l(:mail_subject_register, Setting.app_title) + end + + # Builds a Mail::Message object used to email all active administrators of an account activation request. + # + # Example: + # account_activation_request(user) => Mail::Message object + # Mailer.account_activation_request(user).deliver => sends an email to all active administrators + def account_activation_request(user) + # Send the email to all active administrators + recipients = User.active.where(:admin => true).all.collect { |u| u.mail }.compact + @user = user + @url = url_for(:controller => 'users', :action => 'index', + :status => User::STATUS_REGISTERED, + :sort_key => 'created_on', :sort_order => 'desc') + mail :to => recipients, + :subject => l(:mail_subject_account_activation_request, Setting.app_title) + end + + # Builds a Mail::Message object used to email the specified user that their account was activated by an administrator. + # + # Example: + # account_activated(user) => Mail::Message object + # Mailer.account_activated(user).deliver => sends an email to the registered user + def account_activated(user) + set_language_if_valid user.language + @user = user + @login_url = url_for(:controller => 'account', :action => 'login') + mail :to => user.mail, + :subject => l(:mail_subject_register, Setting.app_title) + end + + def lost_password(token) + set_language_if_valid(token.user.language) + @token = token + @url = url_for(:controller => 'account', :action => 'lost_password', :token => token.value) + mail :to => token.user.mail, + :subject => l(:mail_subject_lost_password, Setting.app_title) + end + + def register(token) + set_language_if_valid(token.user.language) + @token = token + @url = url_for(:controller => 'account', :action => 'activate', :token => token.value) + mail :to => token.user.mail, + :subject => l(:mail_subject_register, Setting.app_title) + end + + def test_email(user) + set_language_if_valid(user.language) + @url = url_for(:controller => 'welcome') + mail :to => user.mail, + :subject => 'Redmine test' + end + + # Overrides default deliver! method to prevent from sending an email + # with no recipient, cc or bcc + def deliver!(mail = @mail) + set_language_if_valid @initial_language + return false if (recipients.nil? || recipients.empty?) && + (cc.nil? || cc.empty?) && + (bcc.nil? || bcc.empty?) + + + # Log errors when raise_delivery_errors is set to false, Rails does not + raise_errors = self.class.raise_delivery_errors + self.class.raise_delivery_errors = true + begin + return super(mail) + rescue Exception => e + if raise_errors + raise e + elsif mylogger + mylogger.error "The following error occured while sending email notification: \"#{e.message}\". Check your configuration in config/configuration.yml." + end + ensure + self.class.raise_delivery_errors = raise_errors + end + end + + # Sends reminders to issue assignees + # Available options: + # * :days => how many days in the future to remind about (defaults to 7) + # * :tracker => id of tracker for filtering issues (defaults to all trackers) + # * :project => id or identifier of project to process (defaults to all projects) + # * :users => array of user/group ids who should be reminded + def self.reminders(options={}) + days = options[:days] || 7 + project = options[:project] ? Project.find(options[:project]) : nil + tracker = options[:tracker] ? Tracker.find(options[:tracker]) : nil + user_ids = options[:users] + + scope = Issue.open.where("#{Issue.table_name}.assigned_to_id IS NOT NULL" + + " AND #{Project.table_name}.status = #{Project::STATUS_ACTIVE}" + + " AND #{Issue.table_name}.due_date <= ?", days.day.from_now.to_date + ) + scope = scope.where(:assigned_to_id => user_ids) if user_ids.present? + scope = scope.where(:project_id => project.id) if project + scope = scope.where(:tracker_id => tracker.id) if tracker + + issues_by_assignee = scope.includes(:status, :assigned_to, :project, :tracker).all.group_by(&:assigned_to) + issues_by_assignee.keys.each do |assignee| + if assignee.is_a?(Group) + assignee.users.each do |user| + issues_by_assignee[user] ||= [] + issues_by_assignee[user] += issues_by_assignee[assignee] + end + end + end + + issues_by_assignee.each do |assignee, issues| + reminder(assignee, issues, days).deliver if assignee.is_a?(User) && assignee.active? + end + end + + # Activates/desactivates email deliveries during +block+ + def self.with_deliveries(enabled = true, &block) + was_enabled = ActionMailer::Base.perform_deliveries + ActionMailer::Base.perform_deliveries = !!enabled + yield + ensure + ActionMailer::Base.perform_deliveries = was_enabled + end + + # Sends emails synchronously in the given block + def self.with_synched_deliveries(&block) + saved_method = ActionMailer::Base.delivery_method + if m = saved_method.to_s.match(%r{^async_(.+)$}) + synched_method = m[1] + ActionMailer::Base.delivery_method = synched_method.to_sym + ActionMailer::Base.send "#{synched_method}_settings=", ActionMailer::Base.send("async_#{synched_method}_settings") + end + yield + ensure + ActionMailer::Base.delivery_method = saved_method + end + + def mail(headers={}) + headers.merge! 'X-Mailer' => 'Redmine', + 'X-Redmine-Host' => Setting.host_name, + 'X-Redmine-Site' => Setting.app_title, + 'X-Auto-Response-Suppress' => 'OOF', + 'Auto-Submitted' => 'auto-generated', + 'From' => Setting.mail_from, + 'List-Id' => "<#{Setting.mail_from.to_s.gsub('@', '.')}>" + + # Removes the author from the recipients and cc + # if he doesn't want to receive notifications about what he does + if @author && @author.logged? && @author.pref[:no_self_notified] + headers[:to].delete(@author.mail) if headers[:to].is_a?(Array) + headers[:cc].delete(@author.mail) if headers[:cc].is_a?(Array) + end + + if @author && @author.logged? + redmine_headers 'Sender' => @author.login + end + + # Blind carbon copy recipients + if Setting.bcc_recipients? + headers[:bcc] = [headers[:to], headers[:cc]].flatten.uniq.reject(&:blank?) + headers[:to] = nil + headers[:cc] = nil + end + + if @message_id_object + headers[:message_id] = "<#{self.class.message_id_for(@message_id_object)}>" + end + if @references_objects + headers[:references] = @references_objects.collect {|o| "<#{self.class.message_id_for(o)}>"}.join(' ') + end + + super headers do |format| + format.text + format.html unless Setting.plain_text_mail? + end + + set_language_if_valid @initial_language + end + + def initialize(*args) + @initial_language = current_language + set_language_if_valid Setting.default_language + super + end + + def self.deliver_mail(mail) + return false if mail.to.blank? && mail.cc.blank? && mail.bcc.blank? + super + end + + def self.method_missing(method, *args, &block) + if m = method.to_s.match(%r{^deliver_(.+)$}) + ActiveSupport::Deprecation.warn "Mailer.deliver_#{m[1]}(*args) is deprecated. Use Mailer.#{m[1]}(*args).deliver instead." + send(m[1], *args).deliver + else + super + end + end + + private + + # Appends a Redmine header field (name is prepended with 'X-Redmine-') + def redmine_headers(h) + h.each { |k,v| headers["X-Redmine-#{k}"] = v.to_s } + end + + # Returns a predictable Message-Id for the given object + def self.message_id_for(object) + # id + timestamp should reduce the odds of a collision + # as far as we don't send multiple emails for the same object + timestamp = object.send(object.respond_to?(:created_on) ? :created_on : :updated_on) + hash = "redmine.#{object.class.name.demodulize.underscore}-#{object.id}.#{timestamp.strftime("%Y%m%d%H%M%S")}" + host = Setting.mail_from.to_s.gsub(%r{^.*@}, '') + host = "#{::Socket.gethostname}.redmine" if host.empty? + "#{hash}@#{host}" + end + + def message_id(object) + @message_id_object = object + end + + def references(object) + @references_objects ||= [] + @references_objects << object + end + + def mylogger + Rails.logger + end +end diff --git a/app/models/member.rb b/app/models/member.rb new file mode 100644 index 00000000..b1108606 --- /dev/null +++ b/app/models/member.rb @@ -0,0 +1,113 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class Member < ActiveRecord::Base + belongs_to :user + belongs_to :principal, :foreign_key => 'user_id' + has_many :member_roles, :dependent => :destroy + has_many :roles, :through => :member_roles + belongs_to :project + + validates_presence_of :principal, :project + validates_uniqueness_of :user_id, :scope => :project_id + validate :validate_role + + before_destroy :set_issue_category_nil + + def role + end + + def role= + end + + def name + self.user.name + end + + alias :base_role_ids= :role_ids= + def role_ids=(arg) + ids = (arg || []).collect(&:to_i) - [0] + # Keep inherited roles + ids += member_roles.select {|mr| !mr.inherited_from.nil?}.collect(&:role_id) + + new_role_ids = ids - role_ids + # Add new roles + new_role_ids.each {|id| member_roles << MemberRole.new(:role_id => id) } + # Remove roles (Rails' #role_ids= will not trigger MemberRole#on_destroy) + member_roles_to_destroy = member_roles.select {|mr| !ids.include?(mr.role_id)} + if member_roles_to_destroy.any? + member_roles_to_destroy.each(&:destroy) + end + end + + def <=>(member) + a, b = roles.sort.first, member.roles.sort.first + if a == b + if principal + principal <=> member.principal + else + 1 + end + elsif a + a <=> b + else + 1 + end + end + + def deletable? + member_roles.detect {|mr| mr.inherited_from}.nil? + end + + def include?(user) + if principal.is_a?(Group) + !user.nil? && user.groups.include?(principal) + else + self.user == user + end + end + + def set_issue_category_nil + if user + # remove category based auto assignments for this member + IssueCategory.update_all "assigned_to_id = NULL", ["project_id = ? AND assigned_to_id = ?", project.id, user.id] + end + end + + # Find or initilize a Member with an id, attributes, and for a Principal + def self.edit_membership(id, new_attributes, principal=nil) + @membership = id.present? ? Member.find(id) : Member.new(:principal => principal) + @membership.attributes = new_attributes + @membership + end + + # Finds or initilizes a Member for the given project and principal + def self.find_or_new(project, principal) + project_id = project.is_a?(Project) ? project.id : project + principal_id = principal.is_a?(Principal) ? principal.id : principal + + member = Member.find_by_project_id_and_user_id(project_id, principal_id) + member ||= Member.new(:project_id => project_id, :user_id => principal_id) + member + end + + protected + + def validate_role + errors.add_on_empty :role if member_roles.empty? && roles.empty? + end +end diff --git a/app/models/member_role.rb b/app/models/member_role.rb new file mode 100644 index 00000000..29ad6563 --- /dev/null +++ b/app/models/member_role.rb @@ -0,0 +1,71 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class MemberRole < ActiveRecord::Base + belongs_to :member + belongs_to :role + + after_destroy :remove_member_if_empty + + after_create :add_role_to_group_users, :add_role_to_subprojects + after_destroy :remove_inherited_roles + + validates_presence_of :role + validate :validate_role_member + + def validate_role_member + errors.add :role_id, :invalid if role && !role.member? + end + + def inherited? + !inherited_from.nil? + end + + private + + def remove_member_if_empty + if member.roles.empty? + member.destroy + end + end + + def add_role_to_group_users + if member.principal.is_a?(Group) && !inherited? + member.principal.users.each do |user| + user_member = Member.find_or_new(member.project_id, user.id) + user_member.member_roles << MemberRole.new(:role => role, :inherited_from => id) + user_member.save! + end + end + end + + def add_role_to_subprojects + member.project.children.each do |subproject| + if subproject.inherit_members? + child_member = Member.find_or_new(subproject.id, member.user_id) + child_member.member_roles << MemberRole.new(:role => role, :inherited_from => id) + child_member.save! + end + end + end + + def remove_inherited_roles + MemberRole.where(:inherited_from => id).all.group_by(&:member).each do |member, member_roles| + member_roles.each(&:destroy) + end + end +end diff --git a/app/models/message.rb b/app/models/message.rb new file mode 100644 index 00000000..76722374 --- /dev/null +++ b/app/models/message.rb @@ -0,0 +1,108 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class Message < ActiveRecord::Base + include Redmine::SafeAttributes + belongs_to :board + belongs_to :author, :class_name => 'User', :foreign_key => 'author_id' + acts_as_tree :counter_cache => :replies_count, :order => "#{Message.table_name}.created_on ASC" + acts_as_attachable + belongs_to :last_reply, :class_name => 'Message', :foreign_key => 'last_reply_id' + + acts_as_searchable :columns => ['subject', 'content'], + :include => {:board => :project}, + :project_key => "#{Board.table_name}.project_id", + :date_column => "#{table_name}.created_on" + acts_as_event :title => Proc.new {|o| "#{o.board.name}: #{o.subject}"}, + :description => :content, + :group => :parent, + :type => Proc.new {|o| o.parent_id.nil? ? 'message' : 'reply'}, + :url => Proc.new {|o| {:controller => 'messages', :action => 'show', :board_id => o.board_id}.merge(o.parent_id.nil? ? {:id => o.id} : + {:id => o.parent_id, :r => o.id, :anchor => "message-#{o.id}"})} + + acts_as_activity_provider :find_options => {:include => [{:board => :project}, :author]}, + :author_key => :author_id + acts_as_watchable + + validates_presence_of :board, :subject, :content + validates_length_of :subject, :maximum => 255 + validate :cannot_reply_to_locked_topic, :on => :create + + after_create :add_author_as_watcher, :reset_counters! + after_update :update_messages_board + after_destroy :reset_counters! + + scope :visible, lambda {|*args| + includes(:board => :project).where(Project.allowed_to_condition(args.shift || User.current, :view_messages, *args)) + } + + safe_attributes 'subject', 'content' + safe_attributes 'locked', 'sticky', 'board_id', + :if => lambda {|message, user| + user.allowed_to?(:edit_messages, message.project) + } + + def visible?(user=User.current) + !user.nil? && user.allowed_to?(:view_messages, project) + end + + def cannot_reply_to_locked_topic + # Can not reply to a locked topic + errors.add :base, 'Topic is locked' if root.locked? && self != root + end + + def update_messages_board + if board_id_changed? + Message.update_all({:board_id => board_id}, ["id = ? OR parent_id = ?", root.id, root.id]) + Board.reset_counters!(board_id_was) + Board.reset_counters!(board_id) + end + end + + def reset_counters! + if parent && parent.id + Message.update_all({:last_reply_id => parent.children.maximum(:id)}, {:id => parent.id}) + end + board.reset_counters! + end + + def sticky=(arg) + write_attribute :sticky, (arg == true || arg.to_s == '1' ? 1 : 0) + end + + def sticky? + sticky == 1 + end + + def project + board.project + end + + def editable_by?(usr) + usr && usr.logged? && (usr.allowed_to?(:edit_messages, project) || (self.author == usr && usr.allowed_to?(:edit_own_messages, project))) + end + + def destroyable_by?(usr) + usr && usr.logged? && (usr.allowed_to?(:delete_messages, project) || (self.author == usr && usr.allowed_to?(:delete_own_messages, project))) + end + + private + + def add_author_as_watcher + Watcher.create(:watchable => self.root, :user => author) + end +end diff --git a/app/models/message_observer.rb b/app/models/message_observer.rb new file mode 100644 index 00000000..9ef52b6b --- /dev/null +++ b/app/models/message_observer.rb @@ -0,0 +1,22 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class MessageObserver < ActiveRecord::Observer + def after_create(message) + Mailer.message_posted(message).deliver if Setting.notified_events.include?('message_posted') + end +end diff --git a/app/models/messages_for_bids.rb b/app/models/messages_for_bids.rb new file mode 100644 index 00000000..d3355553 --- /dev/null +++ b/app/models/messages_for_bids.rb @@ -0,0 +1,3 @@ +class MessagesForBids < ActiveRecord::Base + attr_accessible :bid_id, :message, :user_id +end diff --git a/app/models/messages_for_user.rb b/app/models/messages_for_user.rb new file mode 100644 index 00000000..af3b6863 --- /dev/null +++ b/app/models/messages_for_user.rb @@ -0,0 +1,50 @@ +class MessagesForUser < ActiveRecord::Base + attr_accessible :message, :messager_id, :user_id + belongs_to :user + + MESSAGE_LENGTH_LIMIT = 60 + + validate :validate_user + validate :validate_messager + validates_presence_of :messager_id, :user_id, :message + validates_length_of :message, :maximum => MESSAGE_LENGTH_LIMIT + + def self.leave_message(messager_id, user_id, message) + unless messager_id == user_id + @messages_for_user = self.new + @messages_for_user.messager_id = messager_id + @messages_for_user.user_id = user_id + @messages_for_user.message = message + @messages_for_user.save + true + else + false + end + end + + def self.find_message(user_id) + user = User.find(user_id) + @message_table_for_user = user.messages_for_users.to_a + @message_table_for_user + end + + def find_messager + @messager = User.where(:id =>messager_id) + @messager + end + + def self.delete_message(message_id) + MessagesForUser.delete_all "id = #{message_id}" + end + + #验证user是否存在 + def validate_user + errors.add :user_id, :invalid if user.nil? || !user.active? + end + + #验证messager是否存在 + def validate_messager + user = User.where("id = ?", messager_id).to_a.first + errors.add :messager_id, :invalid if user.nil? || !user.active? + end +end diff --git a/app/models/news.rb b/app/models/news.rb new file mode 100644 index 00000000..c8a4112c --- /dev/null +++ b/app/models/news.rb @@ -0,0 +1,66 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class News < ActiveRecord::Base + include Redmine::SafeAttributes + belongs_to :project + belongs_to :author, :class_name => 'User', :foreign_key => 'author_id' + has_many :comments, :as => :commented, :dependent => :delete_all, :order => "created_on" + + validates_presence_of :title, :description + validates_length_of :title, :maximum => 60 + validates_length_of :summary, :maximum => 255 + + acts_as_attachable :delete_permission => :manage_news + acts_as_searchable :columns => ['title', 'summary', "#{table_name}.description"], :include => :project + acts_as_event :url => Proc.new {|o| {:controller => 'news', :action => 'show', :id => o.id}} + acts_as_activity_provider :find_options => {:include => [:project, :author]}, + :author_key => :author_id + acts_as_watchable + + after_create :add_author_as_watcher + + scope :visible, lambda {|*args| + includes(:project).where(Project.allowed_to_condition(args.shift || User.current, :view_news, *args)) + } + + safe_attributes 'title', 'summary', 'description' + + def visible?(user=User.current) + !user.nil? && user.allowed_to?(:view_news, project) + end + + # Returns true if the news can be commented by user + def commentable?(user=User.current) + user.allowed_to?(:comment_news, project) + end + + def recipients + project.users.select {|user| user.notify_about?(self)}.map(&:mail) + end + + # returns latest news for projects visible by user + def self.latest(user = User.current, count = 5) + visible(user).includes([:author, :project]).order("#{News.table_name}.created_on DESC").limit(count).all + end + + private + + def add_author_as_watcher + Watcher.create(:watchable => self, :user => author) + end +end diff --git a/app/models/news_observer.rb b/app/models/news_observer.rb new file mode 100644 index 00000000..8ba3894f --- /dev/null +++ b/app/models/news_observer.rb @@ -0,0 +1,22 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class NewsObserver < ActiveRecord::Observer + def after_create(news) + Mailer.news_added(news).deliver if Setting.notified_events.include?('news_added') + end +end diff --git a/app/models/principal.rb b/app/models/principal.rb new file mode 100644 index 00000000..b6f41d53 --- /dev/null +++ b/app/models/principal.rb @@ -0,0 +1,112 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class Principal < ActiveRecord::Base + self.table_name = "#{table_name_prefix}users#{table_name_suffix}" + + # Account statuses + STATUS_ANONYMOUS = 0 + STATUS_ACTIVE = 1 + STATUS_REGISTERED = 2 + STATUS_LOCKED = 3 + + has_many :members, :foreign_key => 'user_id', :dependent => :destroy + has_many :memberships, :class_name => 'Member', :foreign_key => 'user_id', :include => [ :project, :roles ], :conditions => "#{Project.table_name}.status<>#{Project::STATUS_ARCHIVED}", :order => "#{Project.table_name}.name" + has_many :projects, :through => :memberships + has_many :issue_categories, :foreign_key => 'assigned_to_id', :dependent => :nullify + + # Groups and active users + scope :active, lambda { where(:status => STATUS_ACTIVE) } + + scope :like, lambda {|q| + q = q.to_s + if q.blank? + where({}) + else + pattern = "%#{q}%" + sql = %w(login firstname lastname mail).map {|column| "LOWER(#{table_name}.#{column}) LIKE LOWER(:p)"}.join(" OR ") + params = {:p => pattern} + if q =~ /^(.+)\s+(.+)$/ + a, b = "#{$1}%", "#{$2}%" + sql << " OR (LOWER(#{table_name}.firstname) LIKE LOWER(:a) AND LOWER(#{table_name}.lastname) LIKE LOWER(:b))" + sql << " OR (LOWER(#{table_name}.firstname) LIKE LOWER(:b) AND LOWER(#{table_name}.lastname) LIKE LOWER(:a))" + params.merge!(:a => a, :b => b) + end + where(sql, params) + end + } + + # Principals that are members of a collection of projects + scope :member_of, lambda {|projects| + projects = [projects] unless projects.is_a?(Array) + if projects.empty? + where("1=0") + else + ids = projects.map(&:id) + active.uniq.joins(:members).where("#{Member.table_name}.project_id IN (?)", ids) + end + } + # Principals that are not members of projects + scope :not_member_of, lambda {|projects| + projects = [projects] unless projects.is_a?(Array) + if projects.empty? + where("1=0") + else + ids = projects.map(&:id) + where("#{Principal.table_name}.id NOT IN (SELECT DISTINCT user_id FROM #{Member.table_name} WHERE project_id IN (?))", ids) + end + } + scope :sorted, lambda { order(*Principal.fields_for_order_statement)} + + before_create :set_default_empty_values + + def name(formatter = nil) + to_s + end + + def <=>(principal) + if principal.nil? + -1 + elsif self.class.name == principal.class.name + self.to_s.downcase <=> principal.to_s.downcase + else + # groups after users + principal.class.name <=> self.class.name + end + end + + # Returns an array of fields names than can be used to make an order statement for principals. + # Users are sorted before Groups. + # Examples: + def self.fields_for_order_statement(table=nil) + table ||= table_name + columns = ['type DESC'] + (User.name_formatter[:order] - ['id']) + ['lastname', 'id'] + columns.uniq.map {|field| "#{table}.#{field}"} + end + + protected + + # Make sure we don't try to insert NULL values (see #4632) + def set_default_empty_values + self.login ||= '' + self.hashed_password ||= '' + self.firstname ||= '' + self.lastname ||= '' + self.mail ||= '' + true + end +end diff --git a/app/models/project.rb b/app/models/project.rb new file mode 100644 index 00000000..7cc3100e --- /dev/null +++ b/app/models/project.rb @@ -0,0 +1,1040 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class Project < ActiveRecord::Base + include Redmine::SafeAttributes + + # Project statuses + STATUS_ACTIVE = 1 + STATUS_CLOSED = 5 + STATUS_ARCHIVED = 9 + + # Maximum length for project identifiers + IDENTIFIER_MAX_LENGTH = 100 + + # Specific overidden Activities + + has_many :time_entry_activities + has_many :members, :include => [:principal, :roles], :conditions => "#{Principal.table_name}.type='User' AND #{Principal.table_name}.status=#{Principal::STATUS_ACTIVE}" + has_many :memberships, :class_name => 'Member' + has_many :member_principals, :class_name => 'Member', + :include => :principal, + :conditions => "#{Principal.table_name}.type='Group' OR (#{Principal.table_name}.type='User' AND #{Principal.table_name}.status=#{Principal::STATUS_ACTIVE})" + has_many :users, :through => :members + has_many :principals, :through => :member_principals, :source => :principal + + has_many :enabled_modules, :dependent => :delete_all + has_and_belongs_to_many :trackers, :order => "#{Tracker.table_name}.position" + has_many :issues, :dependent => :destroy, :include => [:status, :tracker] + has_many :issue_changes, :through => :issues, :source => :journals + has_many :versions, :dependent => :destroy, :order => "#{Version.table_name}.effective_date DESC, #{Version.table_name}.name DESC" + has_many :time_entries, :dependent => :delete_all + has_many :queries, :class_name => 'IssueQuery', :dependent => :delete_all + has_many :documents, :dependent => :destroy + has_many :news, :dependent => :destroy, :include => :author + has_many :issue_categories, :dependent => :delete_all, :order => "#{IssueCategory.table_name}.name" + has_many :boards, :dependent => :destroy, :order => "position ASC" + has_one :repository, :conditions => ["is_default = ?", true] + has_many :repositories, :dependent => :destroy + has_many :changesets, :through => :repository + has_one :wiki, :dependent => :destroy + # Custom field for the project issues + has_and_belongs_to_many :issue_custom_fields, + :class_name => 'IssueCustomField', + :order => "#{CustomField.table_name}.position", + :join_table => "#{table_name_prefix}custom_fields_projects#{table_name_suffix}", + :association_foreign_key => 'custom_field_id' + + #添加用户关注项目功能 fq + has_many :watchers, :through => :watchers_of_projects, :class_name => 'User' + has_many :watchers_of_projects, :class_name => 'WatchersOfProjects' + #end + + has_many :tags, :through => :project_tags, :class_name => 'Tag' + has_many :project_tags, :class_name => 'ProjectTags' + + acts_as_nested_set :order => 'name', :dependent => :destroy + acts_as_attachable :view_permission => :view_files, + :delete_permission => :manage_files + + acts_as_customizable + acts_as_searchable :columns => ['name', 'identifier', 'description'], :project_key => 'id', :permission => nil + acts_as_event :title => Proc.new {|o| "#{l(:label_project)}: #{o.name}"}, + :url => Proc.new {|o| {:controller => 'projects', :action => 'show', :id => o}}, + :author => nil + ############################added by william + acts_as_taggable + + ###################added by liuping 关注 + acts_as_watchable + + attr_protected :status + + validates_presence_of :name, :identifier + validates_uniqueness_of :identifier + validates_associated :repository, :wiki + validates_length_of :name, :maximum => 255 + validates_length_of :homepage, :maximum => 255 + validates_length_of :identifier, :in => 1..IDENTIFIER_MAX_LENGTH + # donwcase letters, digits, dashes but not digits only + validates_format_of :identifier, :with => /\A(?!\d+$)[a-z0-9\-_]*\z/, :if => Proc.new { |p| p.identifier_changed? } + # reserved words + validates_exclusion_of :identifier, :in => %w( new ) + + after_save :update_position_under_parent, :if => Proc.new {|project| project.name_changed?} + after_save :update_inherited_members, :if => Proc.new {|project| project.inherit_members_changed?} + before_destroy :delete_all_members + + scope :has_module, lambda {|mod| + where("#{Project.table_name}.id IN (SELECT em.project_id FROM #{EnabledModule.table_name} em WHERE em.name=?)", mod.to_s) + } + scope :active, lambda { where(:status => STATUS_ACTIVE) } + scope :status, lambda {|arg| where(arg.blank? ? nil : {:status => arg.to_i}) } + scope :all_public, lambda { where(:is_public => true) } + scope :visible, lambda {|*args| where(Project.visible_condition(args.shift || User.current, *args)) } + scope :allowed_to, lambda {|*args| + user = User.current + permission = nil + if args.first.is_a?(Symbol) + permission = args.shift + else + user = args.shift + permission = args.shift + end + where(Project.allowed_to_condition(user, permission, *args)) + } + scope :like, lambda {|arg| + if arg.blank? + where(nil) + else + pattern = "%#{arg.to_s.strip.downcase}%" + where("LOWER(identifier) LIKE :p OR LOWER(name) LIKE :p", :p => pattern) + end + } + + def initialize(attributes=nil, *args) + super + + initialized = (attributes || {}).stringify_keys + if !initialized.key?('identifier') && Setting.sequential_project_identifiers? + self.identifier = Project.next_identifier + end + if !initialized.key?('is_public') + self.is_public = Setting.default_projects_public? + end + if !initialized.key?('enabled_module_names') + self.enabled_module_names = Setting.default_projects_modules + end + if !initialized.key?('trackers') && !initialized.key?('tracker_ids') + default = Setting.default_projects_tracker_ids + if default.is_a?(Array) + self.trackers = Tracker.where(:id => default.map(&:to_i)).sorted.all + else + self.trackers = Tracker.sorted.all + end + end + end + + def identifier=(identifier) + super unless identifier_frozen? + end + + def identifier_frozen? + errors[:identifier].blank? && !(new_record? || identifier.blank?) + end + + # returns latest created projects + # non public projects will be returned only if user is a member of those + def self.latest(user=nil, count=5) + visible(user).limit(count).order("created_on DESC").all + end + + # Returns true if the project is visible to +user+ or to the current user. + def visible?(user=User.current) + user.allowed_to?(:view_project, self) + end + + # Returns a SQL conditions string used to find all projects visible by the specified user. + # + # Examples: + # Project.visible_condition(admin) => "projects.status = 1" + # Project.visible_condition(normal_user) => "((projects.status = 1) AND (projects.is_public = 1 OR projects.id IN (1,3,4)))" + # Project.visible_condition(anonymous) => "((projects.status = 1) AND (projects.is_public = 1))" + def self.visible_condition(user, options={}) + allowed_to_condition(user, :view_project, options) + end + + # Returns a SQL conditions string used to find all projects for which +user+ has the given +permission+ + # + # Valid options: + # * :project => limit the condition to project + # * :with_subprojects => limit the condition to project and its subprojects + # * :member => limit the condition to the user projects + def self.allowed_to_condition(user, permission, options={}) + perm = Redmine::AccessControl.permission(permission) + base_statement = (perm && perm.read? ? "#{Project.table_name}.status <> #{Project::STATUS_ARCHIVED}" : "#{Project.table_name}.status = #{Project::STATUS_ACTIVE}") + if perm && perm.project_module + # If the permission belongs to a project module, make sure the module is enabled + base_statement << " AND #{Project.table_name}.id IN (SELECT em.project_id FROM #{EnabledModule.table_name} em WHERE em.name='#{perm.project_module}')" + end + if options[:project] + project_statement = "#{Project.table_name}.id = #{options[:project].id}" + project_statement << " OR (#{Project.table_name}.lft > #{options[:project].lft} AND #{Project.table_name}.rgt < #{options[:project].rgt})" if options[:with_subprojects] + base_statement = "(#{project_statement}) AND (#{base_statement})" + end + + if user.admin? + base_statement + else + statement_by_role = {} + unless options[:member] + role = user.logged? ? Role.non_member : Role.anonymous + if role.allowed_to?(permission) + statement_by_role[role] = "#{Project.table_name}.is_public = #{connection.quoted_true}" + end + end + if user.logged? + user.projects_by_role.each do |role, projects| + if role.allowed_to?(permission) && projects.any? + statement_by_role[role] = "#{Project.table_name}.id IN (#{projects.collect(&:id).join(',')})" + end + end + end + if statement_by_role.empty? + "1=0" + else + if block_given? + statement_by_role.each do |role, statement| + if s = yield(role, user) + statement_by_role[role] = "(#{statement} AND (#{s}))" + end + end + end + "((#{base_statement}) AND (#{statement_by_role.values.join(' OR ')}))" + end + end + end + + # Returns the Systemwide and project specific activities + def activities(include_inactive=false) + if include_inactive + return all_activities + else + return active_activities + end + end + + # Will create a new Project specific Activity or update an existing one + # + # This will raise a ActiveRecord::Rollback if the TimeEntryActivity + # does not successfully save. + def update_or_create_time_entry_activity(id, activity_hash) + if activity_hash.respond_to?(:has_key?) && activity_hash.has_key?('parent_id') + self.create_time_entry_activity_if_needed(activity_hash) + else + activity = project.time_entry_activities.find_by_id(id.to_i) + activity.update_attributes(activity_hash) if activity + end + end + + # Create a new TimeEntryActivity if it overrides a system TimeEntryActivity + # + # This will raise a ActiveRecord::Rollback if the TimeEntryActivity + # does not successfully save. + def create_time_entry_activity_if_needed(activity) + if activity['parent_id'] + + parent_activity = TimeEntryActivity.find(activity['parent_id']) + activity['name'] = parent_activity.name + activity['position'] = parent_activity.position + + if Enumeration.overridding_change?(activity, parent_activity) + project_activity = self.time_entry_activities.create(activity) + + if project_activity.new_record? + raise ActiveRecord::Rollback, "Overridding TimeEntryActivity was not successfully saved" + else + self.time_entries.update_all("activity_id = #{project_activity.id}", ["activity_id = ?", parent_activity.id]) + end + end + end + end + + # Returns a :conditions SQL string that can be used to find the issues associated with this project. + # + # Examples: + # project.project_condition(true) => "(projects.id = 1 OR (projects.lft > 1 AND projects.rgt < 10))" + # project.project_condition(false) => "projects.id = 1" + def project_condition(with_subprojects) + cond = "#{Project.table_name}.id = #{id}" + cond = "(#{cond} OR (#{Project.table_name}.lft > #{lft} AND #{Project.table_name}.rgt < #{rgt}))" if with_subprojects + cond + end + + def self.find(*args) + if args.first && args.first.is_a?(String) && !args.first.match(/^\d*$/) + project = find_by_identifier(*args) + raise ActiveRecord::RecordNotFound, "Couldn't find Project with identifier=#{args.first}" if project.nil? + project + else + super + end + end + + def self.find_by_param(*args) + self.find(*args) + end + + alias :base_reload :reload + def reload(*args) + @shared_versions = nil + @rolled_up_versions = nil + @rolled_up_trackers = nil + @all_issue_custom_fields = nil + @all_time_entry_custom_fields = nil + @to_param = nil + @allowed_parents = nil + @allowed_permissions = nil + @actions_allowed = nil + @start_date = nil + @due_date = nil + base_reload(*args) + end + + def to_param + # id is used for projects with a numeric identifier (compatibility) + @to_param ||= (identifier.to_s =~ %r{^\d*$} ? id.to_s : identifier) + end + + def active? + self.status == STATUS_ACTIVE + end + + def archived? + self.status == STATUS_ARCHIVED + end + + # Archives the project and its descendants + def archive + # Check that there is no issue of a non descendant project that is assigned + # to one of the project or descendant versions + v_ids = self_and_descendants.collect {|p| p.version_ids}.flatten + if v_ids.any? && + Issue. + includes(:project). + where("#{Project.table_name}.lft < ? OR #{Project.table_name}.rgt > ?", lft, rgt). + where("#{Issue.table_name}.fixed_version_id IN (?)", v_ids). + exists? + return false + end + Project.transaction do + archive! + end + true + end + + # Unarchives the project + # All its ancestors must be active + def unarchive + return false if ancestors.detect {|a| !a.active?} + update_attribute :status, STATUS_ACTIVE + end + + def close + self_and_descendants.status(STATUS_ACTIVE).update_all :status => STATUS_CLOSED + end + + def reopen + self_and_descendants.status(STATUS_CLOSED).update_all :status => STATUS_ACTIVE + end + + # Returns an array of projects the project can be moved to + # by the current user + def allowed_parents + return @allowed_parents if @allowed_parents + @allowed_parents = Project.where(Project.allowed_to_condition(User.current, :add_subprojects)).all + @allowed_parents = @allowed_parents - self_and_descendants + if User.current.allowed_to?(:add_project, nil, :global => true) || (!new_record? && parent.nil?) + @allowed_parents << nil + end + unless parent.nil? || @allowed_parents.empty? || @allowed_parents.include?(parent) + @allowed_parents << parent + end + @allowed_parents + end + + # Sets the parent of the project with authorization check + def set_allowed_parent!(p) + unless p.nil? || p.is_a?(Project) + if p.to_s.blank? + p = nil + else + p = Project.find_by_id(p) + return false unless p + end + end + if p.nil? + if !new_record? && allowed_parents.empty? + return false + end + elsif !allowed_parents.include?(p) + return false + end + set_parent!(p) + end + + # Sets the parent of the project + # Argument can be either a Project, a String, a Fixnum or nil + def set_parent!(p) + unless p.nil? || p.is_a?(Project) + if p.to_s.blank? + p = nil + else + p = Project.find_by_id(p) + return false unless p + end + end + if p == parent && !p.nil? + # Nothing to do + true + elsif p.nil? || (p.active? && move_possible?(p)) + set_or_update_position_under(p) + Issue.update_versions_from_hierarchy_change(self) + true + else + # Can not move to the given target + false + end + end + + # Recalculates all lft and rgt values based on project names + # Unlike Project.rebuild!, these values are recalculated even if the tree "looks" valid + # Used in BuildProjectsTree migration + def self.rebuild_tree! + transaction do + update_all "lft = NULL, rgt = NULL" + rebuild!(false) + end + end + + # Returns an array of the trackers used by the project and its active sub projects + def rolled_up_trackers + @rolled_up_trackers ||= + Tracker. + joins(:projects). + joins("JOIN #{EnabledModule.table_name} ON #{EnabledModule.table_name}.project_id = #{Project.table_name}.id AND #{EnabledModule.table_name}.name = 'issue_tracking'"). + select("DISTINCT #{Tracker.table_name}.*"). + where("#{Project.table_name}.lft >= ? AND #{Project.table_name}.rgt <= ? AND #{Project.table_name}.status <> #{STATUS_ARCHIVED}", lft, rgt). + sorted. + all + end + + # Closes open and locked project versions that are completed + def close_completed_versions + Version.transaction do + versions.where(:status => %w(open locked)).all.each do |version| + if version.completed? + version.update_attribute(:status, 'closed') + end + end + end + end + + # Returns a scope of the Versions on subprojects + def rolled_up_versions + @rolled_up_versions ||= + Version.scoped(:include => :project, + :conditions => ["#{Project.table_name}.lft >= ? AND #{Project.table_name}.rgt <= ? AND #{Project.table_name}.status <> #{STATUS_ARCHIVED}", lft, rgt]) + end + + # Returns a scope of the Versions used by the project + def shared_versions + if new_record? + Version.scoped(:include => :project, + :conditions => "#{Project.table_name}.status <> #{Project::STATUS_ARCHIVED} AND #{Version.table_name}.sharing = 'system'") + else + @shared_versions ||= begin + r = root? ? self : root + Version.scoped(:include => :project, + :conditions => "#{Project.table_name}.id = #{id}" + + " OR (#{Project.table_name}.status <> #{Project::STATUS_ARCHIVED} AND (" + + " #{Version.table_name}.sharing = 'system'" + + " OR (#{Project.table_name}.lft >= #{r.lft} AND #{Project.table_name}.rgt <= #{r.rgt} AND #{Version.table_name}.sharing = 'tree')" + + " OR (#{Project.table_name}.lft < #{lft} AND #{Project.table_name}.rgt > #{rgt} AND #{Version.table_name}.sharing IN ('hierarchy', 'descendants'))" + + " OR (#{Project.table_name}.lft > #{lft} AND #{Project.table_name}.rgt < #{rgt} AND #{Version.table_name}.sharing = 'hierarchy')" + + "))") + end + end + end + + # Returns a hash of project users grouped by role + def users_by_role + members.includes(:user, :roles).all.inject({}) do |h, m| + m.roles.each do |r| + h[r] ||= [] + h[r] << m.user + end + h + end + end + + # Deletes all project's members + def delete_all_members + me, mr = Member.table_name, MemberRole.table_name + connection.delete("DELETE FROM #{mr} WHERE #{mr}.member_id IN (SELECT #{me}.id FROM #{me} WHERE #{me}.project_id = #{id})") + Member.delete_all(['project_id = ?', id]) + end + + # Users/groups issues can be assigned to + def assignable_users + assignable = Setting.issue_group_assignment? ? member_principals : members + assignable.select {|m| m.roles.detect {|role| role.assignable?}}.collect {|m| m.principal}.sort + end + + # Returns the mail adresses of users that should be always notified on project events + def recipients + notified_users.collect {|user| user.mail} + end + + # Returns the users that should be notified on project events + def notified_users + # TODO: User part should be extracted to User#notify_about? + members.select {|m| m.principal.present? && (m.mail_notification? || m.principal.mail_notification == 'all')}.collect {|m| m.principal} + end + + # Returns an array of all custom fields enabled for project issues + # (explictly associated custom fields and custom fields enabled for all projects) + def all_issue_custom_fields + @all_issue_custom_fields ||= (IssueCustomField.for_all + issue_custom_fields).uniq.sort + end + + # Returns an array of all custom fields enabled for project time entries + # (explictly associated custom fields and custom fields enabled for all projects) + def all_time_entry_custom_fields + @all_time_entry_custom_fields ||= (TimeEntryCustomField.for_all + time_entry_custom_fields).uniq.sort + end + + def project + self + end + + def <=>(project) + name.downcase <=> project.name.downcase + end + + def to_s + name + end + + # Returns a short description of the projects (first lines) + def short_description(length = 255) + description.gsub(/^(.{#{length}}[^\n\r]*).*$/m, '\1...').strip if description + end + + def css_classes + s = 'project' + s << ' root' if root? + s << ' child' if child? + s << (leaf? ? ' leaf' : ' parent') + unless active? + if archived? + s << ' archived' + else + s << ' closed' + end + end + s + end + + # The earliest start date of a project, based on it's issues and versions + def start_date + @start_date ||= [ + issues.minimum('start_date'), + shared_versions.minimum('effective_date'), + Issue.fixed_version(shared_versions).minimum('start_date') + ].compact.min + end + + # The latest due date of an issue or version + def due_date + @due_date ||= [ + issues.maximum('due_date'), + shared_versions.maximum('effective_date'), + Issue.fixed_version(shared_versions).maximum('due_date') + ].compact.max + end + + def overdue? + active? && !due_date.nil? && (due_date < Date.today) + end + + # Returns the percent completed for this project, based on the + # progress on it's versions. + def completed_percent(options={:include_subprojects => false}) + if options.delete(:include_subprojects) + total = self_and_descendants.collect(&:completed_percent).sum + + total / self_and_descendants.count + else + if versions.count > 0 + total = versions.collect(&:completed_percent).sum + + total / versions.count + else + 100 + end + end + end + + # Return true if this project allows to do the specified action. + # action can be: + # * a parameter-like Hash (eg. :controller => 'projects', :action => 'edit') + # * a permission Symbol (eg. :edit_project) + def allows_to?(action) + if archived? + # No action allowed on archived projects + return false + end + unless active? || Redmine::AccessControl.read_action?(action) + # No write action allowed on closed projects + return false + end + # No action allowed on disabled modules + if action.is_a? Hash + allowed_actions.include? "#{action[:controller]}/#{action[:action]}" + else + allowed_permissions.include? action + end + end + + def module_enabled?(module_name) + module_name = module_name.to_s + enabled_modules.detect {|m| m.name == module_name} + end + + def enabled_module_names=(module_names) + if module_names && module_names.is_a?(Array) + module_names = module_names.collect(&:to_s).reject(&:blank?) + self.enabled_modules = module_names.collect {|name| enabled_modules.detect {|mod| mod.name == name} || EnabledModule.new(:name => name)} + else + enabled_modules.clear + end + end + + # Returns an array of the enabled modules names + def enabled_module_names + enabled_modules.collect(&:name) + end + + # Enable a specific module + # + # Examples: + # project.enable_module!(:issue_tracking) + # project.enable_module!("issue_tracking") + def enable_module!(name) + enabled_modules << EnabledModule.new(:name => name.to_s) unless module_enabled?(name) + end + + # Disable a module if it exists + # + # Examples: + # project.disable_module!(:issue_tracking) + # project.disable_module!("issue_tracking") + # project.disable_module!(project.enabled_modules.first) + def disable_module!(target) + target = enabled_modules.detect{|mod| target.to_s == mod.name} unless enabled_modules.include?(target) + target.destroy unless target.blank? + end + + safe_attributes 'name', + 'description', + 'homepage', + 'is_public', + 'identifier', + 'custom_field_values', + 'custom_fields', + 'tracker_ids', + 'issue_custom_field_ids' + + safe_attributes 'enabled_module_names', + :if => lambda {|project, user| project.new_record? || user.allowed_to?(:select_project_modules, project) } + + safe_attributes 'inherit_members', + :if => lambda {|project, user| project.parent.nil? || project.parent.visible?(user)} + + # Returns an array of projects that are in this project's hierarchy + # + # Example: parents, children, siblings + def hierarchy + parents = project.self_and_ancestors || [] + descendants = project.descendants || [] + project_hierarchy = parents | descendants # Set union + end + + # Returns an auto-generated project identifier based on the last identifier used + def self.next_identifier + p = Project.order('created_on DESC').first + p.nil? ? nil : p.identifier.to_s.succ + end + + # Copies and saves the Project instance based on the +project+. + # Duplicates the source project's: + # * Wiki + # * Versions + # * Categories + # * Issues + # * Members + # * Queries + # + # Accepts an +options+ argument to specify what to copy + # + # Examples: + # project.copy(1) # => copies everything + # project.copy(1, :only => 'members') # => copies members only + # project.copy(1, :only => ['members', 'versions']) # => copies members and versions + def copy(project, options={}) + project = project.is_a?(Project) ? project : Project.find(project) + + to_be_copied = %w(wiki versions issue_categories issues members queries boards) + to_be_copied = to_be_copied & options[:only].to_a unless options[:only].nil? + + Project.transaction do + if save + reload + to_be_copied.each do |name| + send "copy_#{name}", project + end + Redmine::Hook.call_hook(:model_project_copy_before_save, :source_project => project, :destination_project => self) + save + end + end + end + + # Returns a new unsaved Project instance with attributes copied from +project+ + def self.copy_from(project) + project = project.is_a?(Project) ? project : Project.find(project) + # clear unique attributes + attributes = project.attributes.dup.except('id', 'name', 'identifier', 'status', 'parent_id', 'lft', 'rgt') + copy = Project.new(attributes) + copy.enabled_modules = project.enabled_modules + copy.trackers = project.trackers + copy.custom_values = project.custom_values.collect {|v| v.clone} + copy.issue_custom_fields = project.issue_custom_fields + copy + end + + # Yields the given block for each project with its level in the tree + def self.project_tree(projects, &block) + ancestors = [] + projects.sort_by(&:lft).each do |project| + while (ancestors.any? && !project.is_descendant_of?(ancestors.last)) + ancestors.pop + end + yield project, ancestors.size + ancestors << project + end + end + + private + + def after_parent_changed(parent_was) + remove_inherited_member_roles + add_inherited_member_roles + end + + def update_inherited_members + if parent + if inherit_members? && !inherit_members_was + remove_inherited_member_roles + add_inherited_member_roles + elsif !inherit_members? && inherit_members_was + remove_inherited_member_roles + end + end + end + + def remove_inherited_member_roles + member_roles = memberships.map(&:member_roles).flatten + member_role_ids = member_roles.map(&:id) + member_roles.each do |member_role| + if member_role.inherited_from && !member_role_ids.include?(member_role.inherited_from) + member_role.destroy + end + end + end + + def add_inherited_member_roles + if inherit_members? && parent + parent.memberships.each do |parent_member| + member = Member.find_or_new(self.id, parent_member.user_id) + parent_member.member_roles.each do |parent_member_role| + member.member_roles << MemberRole.new(:role => parent_member_role.role, :inherited_from => parent_member_role.id) + end + member.save! + end + end + end + + # Copies wiki from +project+ + def copy_wiki(project) + # Check that the source project has a wiki first + unless project.wiki.nil? + wiki = self.wiki || Wiki.new + wiki.attributes = project.wiki.attributes.dup.except("id", "project_id") + wiki_pages_map = {} + project.wiki.pages.each do |page| + # Skip pages without content + next if page.content.nil? + new_wiki_content = WikiContent.new(page.content.attributes.dup.except("id", "page_id", "updated_on")) + new_wiki_page = WikiPage.new(page.attributes.dup.except("id", "wiki_id", "created_on", "parent_id")) + new_wiki_page.content = new_wiki_content + wiki.pages << new_wiki_page + wiki_pages_map[page.id] = new_wiki_page + end + + self.wiki = wiki + wiki.save + # Reproduce page hierarchy + project.wiki.pages.each do |page| + if page.parent_id && wiki_pages_map[page.id] + wiki_pages_map[page.id].parent = wiki_pages_map[page.parent_id] + wiki_pages_map[page.id].save + end + end + end + end + + # Copies versions from +project+ + def copy_versions(project) + project.versions.each do |version| + new_version = Version.new + new_version.attributes = version.attributes.dup.except("id", "project_id", "created_on", "updated_on") + self.versions << new_version + end + end + + # Copies issue categories from +project+ + def copy_issue_categories(project) + project.issue_categories.each do |issue_category| + new_issue_category = IssueCategory.new + new_issue_category.attributes = issue_category.attributes.dup.except("id", "project_id") + self.issue_categories << new_issue_category + end + end + + # Copies issues from +project+ + def copy_issues(project) + # Stores the source issue id as a key and the copied issues as the + # value. Used to map the two togeather for issue relations. + issues_map = {} + + # Store status and reopen locked/closed versions + version_statuses = versions.reject(&:open?).map {|version| [version, version.status]} + version_statuses.each do |version, status| + version.update_attribute :status, 'open' + end + + # Get issues sorted by root_id, lft so that parent issues + # get copied before their children + project.issues.reorder('root_id, lft').all.each do |issue| + new_issue = Issue.new + new_issue.copy_from(issue, :subtasks => false, :link => false) + new_issue.project = self + # Reassign fixed_versions by name, since names are unique per project + if issue.fixed_version && issue.fixed_version.project == project + new_issue.fixed_version = self.versions.detect {|v| v.name == issue.fixed_version.name} + end + # Reassign the category by name, since names are unique per project + if issue.category + new_issue.category = self.issue_categories.detect {|c| c.name == issue.category.name} + end + # Parent issue + if issue.parent_id + if copied_parent = issues_map[issue.parent_id] + new_issue.parent_issue_id = copied_parent.id + end + end + + self.issues << new_issue + if new_issue.new_record? + logger.info "Project#copy_issues: issue ##{issue.id} could not be copied: #{new_issue.errors.full_messages}" if logger && logger.info + else + issues_map[issue.id] = new_issue unless new_issue.new_record? + end + end + + # Restore locked/closed version statuses + version_statuses.each do |version, status| + version.update_attribute :status, status + end + + # Relations after in case issues related each other + project.issues.each do |issue| + new_issue = issues_map[issue.id] + unless new_issue + # Issue was not copied + next + end + + # Relations + issue.relations_from.each do |source_relation| + new_issue_relation = IssueRelation.new + new_issue_relation.attributes = source_relation.attributes.dup.except("id", "issue_from_id", "issue_to_id") + new_issue_relation.issue_to = issues_map[source_relation.issue_to_id] + if new_issue_relation.issue_to.nil? && Setting.cross_project_issue_relations? + new_issue_relation.issue_to = source_relation.issue_to + end + new_issue.relations_from << new_issue_relation + end + + issue.relations_to.each do |source_relation| + new_issue_relation = IssueRelation.new + new_issue_relation.attributes = source_relation.attributes.dup.except("id", "issue_from_id", "issue_to_id") + new_issue_relation.issue_from = issues_map[source_relation.issue_from_id] + if new_issue_relation.issue_from.nil? && Setting.cross_project_issue_relations? + new_issue_relation.issue_from = source_relation.issue_from + end + new_issue.relations_to << new_issue_relation + end + end + end + + # Copies members from +project+ + def copy_members(project) + # Copy users first, then groups to handle members with inherited and given roles + members_to_copy = [] + members_to_copy += project.memberships.select {|m| m.principal.is_a?(User)} + members_to_copy += project.memberships.select {|m| !m.principal.is_a?(User)} + + members_to_copy.each do |member| + new_member = Member.new + new_member.attributes = member.attributes.dup.except("id", "project_id", "created_on") + # only copy non inherited roles + # inherited roles will be added when copying the group membership + role_ids = member.member_roles.reject(&:inherited?).collect(&:role_id) + next if role_ids.empty? + new_member.role_ids = role_ids + new_member.project = self + self.members << new_member + end + end + + # Copies queries from +project+ + def copy_queries(project) + project.queries.each do |query| + new_query = IssueQuery.new + new_query.attributes = query.attributes.dup.except("id", "project_id", "sort_criteria") + new_query.sort_criteria = query.sort_criteria if query.sort_criteria + new_query.project = self + new_query.user_id = query.user_id + self.queries << new_query + end + end + + # Copies boards from +project+ + def copy_boards(project) + project.boards.each do |board| + new_board = Board.new + new_board.attributes = board.attributes.dup.except("id", "project_id", "topics_count", "messages_count", "last_message_id") + new_board.project = self + self.boards << new_board + end + end + + def allowed_permissions + @allowed_permissions ||= begin + module_names = enabled_modules.all(:select => :name).collect {|m| m.name} + Redmine::AccessControl.modules_permissions(module_names).collect {|p| p.name} + end + end + + def allowed_actions + @actions_allowed ||= allowed_permissions.inject([]) { |actions, permission| actions += Redmine::AccessControl.allowed_actions(permission) }.flatten + end + + # Returns all the active Systemwide and project specific activities + def active_activities + overridden_activity_ids = self.time_entry_activities.collect(&:parent_id) + + if overridden_activity_ids.empty? + return TimeEntryActivity.shared.active + else + return system_activities_and_project_overrides + end + end + + # Returns all the Systemwide and project specific activities + # (inactive and active) + def all_activities + overridden_activity_ids = self.time_entry_activities.collect(&:parent_id) + + if overridden_activity_ids.empty? + return TimeEntryActivity.shared + else + return system_activities_and_project_overrides(true) + end + end + + # Returns the systemwide active activities merged with the project specific overrides + def system_activities_and_project_overrides(include_inactive=false) + if include_inactive + return TimeEntryActivity.shared. + where("id NOT IN (?)", self.time_entry_activities.collect(&:parent_id)).all + + self.time_entry_activities + else + return TimeEntryActivity.shared.active. + where("id NOT IN (?)", self.time_entry_activities.collect(&:parent_id)).all + + self.time_entry_activities.active + end + end + + # Archives subprojects recursively + def archive! + children.each do |subproject| + subproject.send :archive! + end + update_attribute :status, STATUS_ARCHIVED + end + + def update_position_under_parent + set_or_update_position_under(parent) + end + + # Inserts/moves the project so that target's children or root projects stay alphabetically sorted + def set_or_update_position_under(target_parent) + parent_was = parent + sibs = (target_parent.nil? ? self.class.roots : target_parent.children) + to_be_inserted_before = sibs.sort_by {|c| c.name.to_s.downcase}.detect {|c| c.name.to_s.downcase > name.to_s.downcase } + + if to_be_inserted_before + move_to_left_of(to_be_inserted_before) + elsif target_parent.nil? + if sibs.empty? + # move_to_root adds the project in first (ie. left) position + move_to_root + else + move_to_right_of(sibs.last) unless self == sibs.last + end + else + # move_to_child_of adds the project in last (ie.right) position + move_to_child_of(target_parent) + end + if parent_was != target_parent + after_parent_changed(parent_was) + end + end +end diff --git a/app/models/project_custom_field.rb b/app/models/project_custom_field.rb new file mode 100644 index 00000000..0c56a25f --- /dev/null +++ b/app/models/project_custom_field.rb @@ -0,0 +1,22 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class ProjectCustomField < CustomField + def type_name + :label_project_plural + end +end diff --git a/app/models/project_tags.rb b/app/models/project_tags.rb new file mode 100644 index 00000000..16de1ea4 --- /dev/null +++ b/app/models/project_tags.rb @@ -0,0 +1,45 @@ +#添加代码 +class ProjectTags < ActiveRecord::Base + attr_accessible :description, :project_id, :tag_id, :user_id +####################################################################################################添加代码 + belongs_to :project + belongs_to :tag + belongs_to :user + + validates_uniqueness_of :project_id, :scope => :tag_id + validates_presence_of :project_id, :tag_id, :user_id + validate :validate_user + + + #新建project_tag的内容 + def self.add_tag(project_id, content, description=nil, user_id) + if Tag.add_content(content) #tag表里新建一条记录和内容字段 + @new_tag = self.new #相应的在project_tags表里新建一条对应的记录 + @new_tag.project_id = project_id + @new_tag.description = description + @t_tag = Tag.where("content = ?", content).to_a #把新添加content的那条记录的数组返回 + @new_tag.tag_id = @t_tag.first.id #必须用first来调用数组第一个元素 + @new_tag.user_id = user_id + @new_tag.save + true + end + end + + #根据project_id查询tag + def self.find_tag(project_id) + @project = Project.find(project_id) + @project_tags = @project.project_tags + @project_tags + end + + def find_tag + @tag = self.tags + @tag + end + + def validate_user + errors.add :user_id, :invalid unless user.nil? || user.active? + end + +end +##################################################################################################### 添加结束 diff --git a/app/models/query.rb b/app/models/query.rb new file mode 100644 index 00000000..db6ca07a --- /dev/null +++ b/app/models/query.rb @@ -0,0 +1,828 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class QueryColumn + attr_accessor :name, :sortable, :groupable, :default_order + include Redmine::I18n + + def initialize(name, options={}) + self.name = name + self.sortable = options[:sortable] + self.groupable = options[:groupable] || false + if groupable == true + self.groupable = name.to_s + end + self.default_order = options[:default_order] + @inline = options.key?(:inline) ? options[:inline] : true + @caption_key = options[:caption] || "field_#{name}".to_sym + @frozen = options[:frozen] + end + + def caption + @caption_key.is_a?(Symbol) ? l(@caption_key) : @caption_key + end + + # Returns true if the column is sortable, otherwise false + def sortable? + !@sortable.nil? + end + + def sortable + @sortable.is_a?(Proc) ? @sortable.call : @sortable + end + + def inline? + @inline + end + + def frozen? + @frozen + end + + def value(object) + object.send name + end + + def css_classes + name + end +end + +class QueryCustomFieldColumn < QueryColumn + + def initialize(custom_field) + self.name = "cf_#{custom_field.id}".to_sym + self.sortable = custom_field.order_statement || false + self.groupable = custom_field.group_statement || false + @inline = true + @cf = custom_field + end + + def caption + @cf.name + end + + def custom_field + @cf + end + + def value(object) + cv = object.custom_values.select {|v| v.custom_field_id == @cf.id}.collect {|v| @cf.cast_value(v.value)} + cv.size > 1 ? cv.sort {|a,b| a.to_s <=> b.to_s} : cv.first + end + + def css_classes + @css_classes ||= "#{name} #{@cf.field_format}" + end +end + +class QueryAssociationCustomFieldColumn < QueryCustomFieldColumn + + def initialize(association, custom_field) + super(custom_field) + self.name = "#{association}.cf_#{custom_field.id}".to_sym + # TODO: support sorting/grouping by association custom field + self.sortable = false + self.groupable = false + @association = association + end + + def value(object) + if assoc = object.send(@association) + super(assoc) + end + end + + def css_classes + @css_classes ||= "#{@association}_cf_#{@cf.id} #{@cf.field_format}" + end +end + +class Query < ActiveRecord::Base + class StatementInvalid < ::ActiveRecord::StatementInvalid + end + + belongs_to :project + belongs_to :user + serialize :filters + serialize :column_names + serialize :sort_criteria, Array + + attr_protected :project_id, :user_id + + validates_presence_of :name + validates_length_of :name, :maximum => 255 + validate :validate_query_filters + + class_attribute :operators + self.operators = { + "=" => :label_equals, + "!" => :label_not_equals, + "o" => :label_open_issues, + "c" => :label_closed_issues, + "!*" => :label_none, + "*" => :label_any, + ">=" => :label_greater_or_equal, + "<=" => :label_less_or_equal, + "><" => :label_between, + " :label_in_less_than, + ">t+" => :label_in_more_than, + "> :label_in_the_next_days, + "t+" => :label_in, + "t" => :label_today, + "ld" => :label_yesterday, + "w" => :label_this_week, + "lw" => :label_last_week, + "l2w" => [:label_last_n_weeks, {:count => 2}], + "m" => :label_this_month, + "lm" => :label_last_month, + "y" => :label_this_year, + ">t-" => :label_less_than_ago, + " :label_more_than_ago, + "> :label_in_the_past_days, + "t-" => :label_ago, + "~" => :label_contains, + "!~" => :label_not_contains, + "=p" => :label_any_issues_in_project, + "=!p" => :label_any_issues_not_in_project, + "!p" => :label_no_issues_in_project + } + + class_attribute :operators_by_filter_type + self.operators_by_filter_type = { + :list => [ "=", "!" ], + :list_status => [ "o", "=", "!", "c", "*" ], + :list_optional => [ "=", "!", "!*", "*" ], + :list_subprojects => [ "*", "!*", "=" ], + :date => [ "=", ">=", "<=", "><", "t+", ">t-", " [ "=", ">=", "<=", "><", ">t-", " [ "=", "~", "!", "!~", "!*", "*" ], + :text => [ "~", "!~", "!*", "*" ], + :integer => [ "=", ">=", "<=", "><", "!*", "*" ], + :float => [ "=", ">=", "<=", "><", "!*", "*" ], + :relation => ["=", "=p", "=!p", "!p", "!*", "*"] + } + + class_attribute :available_columns + self.available_columns = [] + + class_attribute :queried_class + + def queried_table_name + @queried_table_name ||= self.class.queried_class.table_name + end + + def initialize(attributes=nil, *args) + super attributes + @is_for_all = project.nil? + end + + # Builds the query from the given params + def build_from_params(params) + if params[:fields] || params[:f] + self.filters = {} + add_filters(params[:fields] || params[:f], params[:operators] || params[:op], params[:values] || params[:v]) + else + available_filters.keys.each do |field| + add_short_filter(field, params[field]) if params[field] + end + end + self.group_by = params[:group_by] || (params[:query] && params[:query][:group_by]) + self.column_names = params[:c] || (params[:query] && params[:query][:column_names]) + self + end + + # Builds a new query from the given params and attributes + def self.build_from_params(params, attributes={}) + new(attributes).build_from_params(params) + end + + def validate_query_filters + filters.each_key do |field| + if values_for(field) + case type_for(field) + when :integer + add_filter_error(field, :invalid) if values_for(field).detect {|v| v.present? && !v.match(/^[+-]?\d+$/) } + when :float + add_filter_error(field, :invalid) if values_for(field).detect {|v| v.present? && !v.match(/^[+-]?\d+(\.\d*)?$/) } + when :date, :date_past + case operator_for(field) + when "=", ">=", "<=", "><" + add_filter_error(field, :invalid) if values_for(field).detect {|v| v.present? && (!v.match(/^\d{4}-\d{2}-\d{2}$/) || (Date.parse(v) rescue nil).nil?) } + when ">t-", "t+", " 'activerecord.errors.messages') + errors.add(:base, m) + end + + def editable_by?(user) + return false unless user + # Admin can edit them all and regular users can edit their private queries + return true if user.admin? || (!is_public && self.user_id == user.id) + # Members can not edit public queries that are for all project (only admin is allowed to) + is_public && !@is_for_all && user.allowed_to?(:manage_public_queries, project) + end + + def trackers + @trackers ||= project.nil? ? Tracker.sorted.all : project.rolled_up_trackers + end + + # Returns a hash of localized labels for all filter operators + def self.operators_labels + operators.inject({}) {|h, operator| h[operator.first] = l(*operator.last); h} + end + + # Returns a representation of the available filters for JSON serialization + def available_filters_as_json + json = {} + available_filters.each do |field, options| + json[field] = options.slice(:type, :name, :values).stringify_keys + end + json + end + + def all_projects + @all_projects ||= Project.visible.all + end + + def all_projects_values + return @all_projects_values if @all_projects_values + + values = [] + Project.project_tree(all_projects) do |p, level| + prefix = (level > 0 ? ('--' * level + ' ') : '') + values << ["#{prefix}#{p.name}", p.id.to_s] + end + @all_projects_values = values + end + + # Adds available filters + def initialize_available_filters + # implemented by sub-classes + end + protected :initialize_available_filters + + # Adds an available filter + def add_available_filter(field, options) + @available_filters ||= ActiveSupport::OrderedHash.new + @available_filters[field] = options + @available_filters + end + + # Removes an available filter + def delete_available_filter(field) + if @available_filters + @available_filters.delete(field) + end + end + + # Return a hash of available filters + def available_filters + unless @available_filters + initialize_available_filters + @available_filters.each do |field, options| + options[:name] ||= l(options[:label] || "field_#{field}".gsub(/_id$/, '')) + end + end + @available_filters + end + + def add_filter(field, operator, values=nil) + # values must be an array + return unless values.nil? || values.is_a?(Array) + # check if field is defined as an available filter + if available_filters.has_key? field + filter_options = available_filters[field] + filters[field] = {:operator => operator, :values => (values || [''])} + end + end + + def add_short_filter(field, expression) + return unless expression && available_filters.has_key?(field) + field_type = available_filters[field][:type] + operators_by_filter_type[field_type].sort.reverse.detect do |operator| + next unless expression =~ /^#{Regexp.escape(operator)}(.*)$/ + values = $1 + add_filter field, operator, values.present? ? values.split('|') : [''] + end || add_filter(field, '=', expression.split('|')) + end + + # Add multiple filters using +add_filter+ + def add_filters(fields, operators, values) + if fields.is_a?(Array) && operators.is_a?(Hash) && (values.nil? || values.is_a?(Hash)) + fields.each do |field| + add_filter(field, operators[field], values && values[field]) + end + end + end + + def has_filter?(field) + filters and filters[field] + end + + def type_for(field) + available_filters[field][:type] if available_filters.has_key?(field) + end + + def operator_for(field) + has_filter?(field) ? filters[field][:operator] : nil + end + + def values_for(field) + has_filter?(field) ? filters[field][:values] : nil + end + + def value_for(field, index=0) + (values_for(field) || [])[index] + end + + def label_for(field) + label = available_filters[field][:name] if available_filters.has_key?(field) + label ||= l("field_#{field.to_s.gsub(/_id$/, '')}", :default => field) + end + + def self.add_available_column(column) + self.available_columns << (column) if column.is_a?(QueryColumn) + end + + # Returns an array of columns that can be used to group the results + def groupable_columns + available_columns.select {|c| c.groupable} + end + + # Returns a Hash of columns and the key for sorting + def sortable_columns + available_columns.inject({}) {|h, column| + h[column.name.to_s] = column.sortable + h + } + end + + def columns + # preserve the column_names order + cols = (has_default_columns? ? default_columns_names : column_names).collect do |name| + available_columns.find { |col| col.name == name } + end.compact + available_columns.select(&:frozen?) | cols + end + + def inline_columns + columns.select(&:inline?) + end + + def block_columns + columns.reject(&:inline?) + end + + def available_inline_columns + available_columns.select(&:inline?) + end + + def available_block_columns + available_columns.reject(&:inline?) + end + + def default_columns_names + [] + end + + def column_names=(names) + if names + names = names.select {|n| n.is_a?(Symbol) || !n.blank? } + names = names.collect {|n| n.is_a?(Symbol) ? n : n.to_sym } + # Set column_names to nil if default columns + if names == default_columns_names + names = nil + end + end + write_attribute(:column_names, names) + end + + def has_column?(column) + column_names && column_names.include?(column.is_a?(QueryColumn) ? column.name : column) + end + + def has_default_columns? + column_names.nil? || column_names.empty? + end + + def sort_criteria=(arg) + c = [] + if arg.is_a?(Hash) + arg = arg.keys.sort.collect {|k| arg[k]} + end + c = arg.select {|k,o| !k.to_s.blank?}.slice(0,3).collect {|k,o| [k.to_s, (o == 'desc' || o == false) ? 'desc' : 'asc']} + write_attribute(:sort_criteria, c) + end + + def sort_criteria + read_attribute(:sort_criteria) || [] + end + + def sort_criteria_key(arg) + sort_criteria && sort_criteria[arg] && sort_criteria[arg].first + end + + def sort_criteria_order(arg) + sort_criteria && sort_criteria[arg] && sort_criteria[arg].last + end + + def sort_criteria_order_for(key) + sort_criteria.detect {|k, order| key.to_s == k}.try(:last) + end + + # Returns the SQL sort order that should be prepended for grouping + def group_by_sort_order + if grouped? && (column = group_by_column) + order = sort_criteria_order_for(column.name) || column.default_order + column.sortable.is_a?(Array) ? + column.sortable.collect {|s| "#{s} #{order}"}.join(',') : + "#{column.sortable} #{order}" + end + end + + # Returns true if the query is a grouped query + def grouped? + !group_by_column.nil? + end + + def group_by_column + groupable_columns.detect {|c| c.groupable && c.name.to_s == group_by} + end + + def group_by_statement + group_by_column.try(:groupable) + end + + def project_statement + project_clauses = [] + if project && !project.descendants.active.empty? + ids = [project.id] + if has_filter?("subproject_id") + case operator_for("subproject_id") + when '=' + # include the selected subprojects + ids += values_for("subproject_id").each(&:to_i) + when '!*' + # main project only + else + # all subprojects + ids += project.descendants.collect(&:id) + end + elsif Setting.display_subprojects_issues? + ids += project.descendants.collect(&:id) + end + project_clauses << "#{Project.table_name}.id IN (%s)" % ids.join(',') + elsif project + project_clauses << "#{Project.table_name}.id = %d" % project.id + end + project_clauses.any? ? project_clauses.join(' AND ') : nil + end + + def statement + # filters clauses + filters_clauses = [] + filters.each_key do |field| + next if field == "subproject_id" + v = values_for(field).clone + next unless v and !v.empty? + operator = operator_for(field) + + # "me" value subsitution + if %w(assigned_to_id author_id user_id watcher_id).include?(field) + if v.delete("me") + if User.current.logged? + v.push(User.current.id.to_s) + v += User.current.group_ids.map(&:to_s) if field == 'assigned_to_id' + else + v.push("0") + end + end + end + + if field == 'project_id' + if v.delete('mine') + v += User.current.memberships.map(&:project_id).map(&:to_s) + end + end + + if field =~ /cf_(\d+)$/ + # custom field + filters_clauses << sql_for_custom_field(field, operator, v, $1) + elsif respond_to?("sql_for_#{field}_field") + # specific statement + filters_clauses << send("sql_for_#{field}_field", field, operator, v) + else + # regular field + filters_clauses << '(' + sql_for_field(field, operator, v, queried_table_name, field) + ')' + end + end if filters and valid? + + filters_clauses << project_statement + filters_clauses.reject!(&:blank?) + + filters_clauses.any? ? filters_clauses.join(' AND ') : nil + end + + private + + def sql_for_custom_field(field, operator, value, custom_field_id) + db_table = CustomValue.table_name + db_field = 'value' + filter = @available_filters[field] + return nil unless filter + if filter[:format] == 'user' + if value.delete('me') + value.push User.current.id.to_s + end + end + not_in = nil + if operator == '!' + # Makes ! operator work for custom fields with multiple values + operator = '=' + not_in = 'NOT' + end + customized_key = "id" + customized_class = queried_class + if field =~ /^(.+)\.cf_/ + assoc = $1 + customized_key = "#{assoc}_id" + customized_class = queried_class.reflect_on_association(assoc.to_sym).klass.base_class rescue nil + raise "Unknown #{queried_class.name} association #{assoc}" unless customized_class + end + "#{queried_table_name}.#{customized_key} #{not_in} IN (SELECT #{customized_class.table_name}.id FROM #{customized_class.table_name} LEFT OUTER JOIN #{db_table} ON #{db_table}.customized_type='#{customized_class}' AND #{db_table}.customized_id=#{customized_class.table_name}.id AND #{db_table}.custom_field_id=#{custom_field_id} WHERE " + + sql_for_field(field, operator, value, db_table, db_field, true) + ')' + end + + # Helper method to generate the WHERE sql for a +field+, +operator+ and a +value+ + def sql_for_field(field, operator, value, db_table, db_field, is_custom_filter=false) + sql = '' + case operator + when "=" + if value.any? + case type_for(field) + when :date, :date_past + sql = date_clause(db_table, db_field, (Date.parse(value.first) rescue nil), (Date.parse(value.first) rescue nil)) + when :integer + if is_custom_filter + sql = "(#{db_table}.#{db_field} <> '' AND CAST(CASE #{db_table}.#{db_field} WHEN '' THEN '0' ELSE #{db_table}.#{db_field} END AS decimal(30,3)) = #{value.first.to_i})" + else + sql = "#{db_table}.#{db_field} = #{value.first.to_i}" + end + when :float + if is_custom_filter + sql = "(#{db_table}.#{db_field} <> '' AND CAST(CASE #{db_table}.#{db_field} WHEN '' THEN '0' ELSE #{db_table}.#{db_field} END AS decimal(30,3)) BETWEEN #{value.first.to_f - 1e-5} AND #{value.first.to_f + 1e-5})" + else + sql = "#{db_table}.#{db_field} BETWEEN #{value.first.to_f - 1e-5} AND #{value.first.to_f + 1e-5}" + end + else + sql = "#{db_table}.#{db_field} IN (" + value.collect{|val| "'#{connection.quote_string(val)}'"}.join(",") + ")" + end + else + # IN an empty set + sql = "1=0" + end + when "!" + if value.any? + sql = "(#{db_table}.#{db_field} IS NULL OR #{db_table}.#{db_field} NOT IN (" + value.collect{|val| "'#{connection.quote_string(val)}'"}.join(",") + "))" + else + # NOT IN an empty set + sql = "1=1" + end + when "!*" + sql = "#{db_table}.#{db_field} IS NULL" + sql << " OR #{db_table}.#{db_field} = ''" if is_custom_filter + when "*" + sql = "#{db_table}.#{db_field} IS NOT NULL" + sql << " AND #{db_table}.#{db_field} <> ''" if is_custom_filter + when ">=" + if [:date, :date_past].include?(type_for(field)) + sql = date_clause(db_table, db_field, (Date.parse(value.first) rescue nil), nil) + else + if is_custom_filter + sql = "(#{db_table}.#{db_field} <> '' AND CAST(CASE #{db_table}.#{db_field} WHEN '' THEN '0' ELSE #{db_table}.#{db_field} END AS decimal(30,3)) >= #{value.first.to_f})" + else + sql = "#{db_table}.#{db_field} >= #{value.first.to_f}" + end + end + when "<=" + if [:date, :date_past].include?(type_for(field)) + sql = date_clause(db_table, db_field, nil, (Date.parse(value.first) rescue nil)) + else + if is_custom_filter + sql = "(#{db_table}.#{db_field} <> '' AND CAST(CASE #{db_table}.#{db_field} WHEN '' THEN '0' ELSE #{db_table}.#{db_field} END AS decimal(30,3)) <= #{value.first.to_f})" + else + sql = "#{db_table}.#{db_field} <= #{value.first.to_f}" + end + end + when "><" + if [:date, :date_past].include?(type_for(field)) + sql = date_clause(db_table, db_field, (Date.parse(value[0]) rescue nil), (Date.parse(value[1]) rescue nil)) + else + if is_custom_filter + sql = "(#{db_table}.#{db_field} <> '' AND CAST(CASE #{db_table}.#{db_field} WHEN '' THEN '0' ELSE #{db_table}.#{db_field} END AS decimal(30,3)) BETWEEN #{value[0].to_f} AND #{value[1].to_f})" + else + sql = "#{db_table}.#{db_field} BETWEEN #{value[0].to_f} AND #{value[1].to_f}" + end + end + when "o" + sql = "#{queried_table_name}.status_id IN (SELECT id FROM #{IssueStatus.table_name} WHERE is_closed=#{connection.quoted_false})" if field == "status_id" + when "c" + sql = "#{queried_table_name}.status_id IN (SELECT id FROM #{IssueStatus.table_name} WHERE is_closed=#{connection.quoted_true})" if field == "status_id" + when ">t-" + # >= today - n days + sql = relative_date_clause(db_table, db_field, - value.first.to_i, nil) + when "t+" + # >= today + n days + sql = relative_date_clause(db_table, db_field, value.first.to_i, nil) + when "= first_day_of_week ? day_of_week - first_day_of_week : day_of_week + 7 - first_day_of_week) + sql = relative_date_clause(db_table, db_field, - days_ago, - days_ago + 6) + when "lw" + # = last week + first_day_of_week = l(:general_first_day_of_week).to_i + day_of_week = Date.today.cwday + days_ago = (day_of_week >= first_day_of_week ? day_of_week - first_day_of_week : day_of_week + 7 - first_day_of_week) + sql = relative_date_clause(db_table, db_field, - days_ago - 7, - days_ago - 1) + when "l2w" + # = last 2 weeks + first_day_of_week = l(:general_first_day_of_week).to_i + day_of_week = Date.today.cwday + days_ago = (day_of_week >= first_day_of_week ? day_of_week - first_day_of_week : day_of_week + 7 - first_day_of_week) + sql = relative_date_clause(db_table, db_field, - days_ago - 14, - days_ago - 1) + when "m" + # = this month + date = Date.today + sql = date_clause(db_table, db_field, date.beginning_of_month, date.end_of_month) + when "lm" + # = last month + date = Date.today.prev_month + sql = date_clause(db_table, db_field, date.beginning_of_month, date.end_of_month) + when "y" + # = this year + date = Date.today + sql = date_clause(db_table, db_field, date.beginning_of_year, date.end_of_year) + when "~" + sql = "LOWER(#{db_table}.#{db_field}) LIKE '%#{connection.quote_string(value.first.to_s.downcase)}%'" + when "!~" + sql = "LOWER(#{db_table}.#{db_field}) NOT LIKE '%#{connection.quote_string(value.first.to_s.downcase)}%'" + else + raise "Unknown query operator #{operator}" + end + + return sql + end + + def add_custom_fields_filters(custom_fields, assoc=nil) + return unless custom_fields.present? + + custom_fields.select(&:is_filter?).sort.each do |field| + case field.field_format + when "text" + options = { :type => :text } + when "list" + options = { :type => :list_optional, :values => field.possible_values } + when "date" + options = { :type => :date } + when "bool" + options = { :type => :list, :values => [[l(:general_text_yes), "1"], [l(:general_text_no), "0"]] } + when "int" + options = { :type => :integer } + when "float" + options = { :type => :float } + when "user", "version" + next unless project + values = field.possible_values_options(project) + if User.current.logged? && field.field_format == 'user' + values.unshift ["<< #{l(:label_me)} >>", "me"] + end + options = { :type => :list_optional, :values => values } + else + options = { :type => :string } + end + filter_id = "cf_#{field.id}" + filter_name = field.name + if assoc.present? + filter_id = "#{assoc}.#{filter_id}" + filter_name = l("label_attribute_of_#{assoc}", :name => filter_name) + end + add_available_filter filter_id, options.merge({ + :name => filter_name, + :format => field.field_format, + :field => field + }) + end + end + + def add_associations_custom_fields_filters(*associations) + fields_by_class = CustomField.where(:is_filter => true).group_by(&:class) + associations.each do |assoc| + association_klass = queried_class.reflect_on_association(assoc).klass + fields_by_class.each do |field_class, fields| + if field_class.customized_class <= association_klass + add_custom_fields_filters(fields, assoc) + end + end + end + end + + # Returns a SQL clause for a date or datetime field. + def date_clause(table, field, from, to) + s = [] + if from + from_yesterday = from - 1 + from_yesterday_time = Time.local(from_yesterday.year, from_yesterday.month, from_yesterday.day) + if self.class.default_timezone == :utc + from_yesterday_time = from_yesterday_time.utc + end + s << ("#{table}.#{field} > '%s'" % [connection.quoted_date(from_yesterday_time.end_of_day)]) + end + if to + to_time = Time.local(to.year, to.month, to.day) + if self.class.default_timezone == :utc + to_time = to_time.utc + end + s << ("#{table}.#{field} <= '%s'" % [connection.quoted_date(to_time.end_of_day)]) + end + s.join(' AND ') + end + + # Returns a SQL clause for a date or datetime field using relative dates. + def relative_date_clause(table, field, days_from, days_to) + date_clause(table, field, (days_from ? Date.today + days_from : nil), (days_to ? Date.today + days_to : nil)) + end + + # Additional joins required for the given sort options + def joins_for_order_statement(order_options) + joins = [] + + if order_options + if order_options.include?('authors') + joins << "LEFT OUTER JOIN #{User.table_name} authors ON authors.id = #{queried_table_name}.author_id" + end + order_options.scan(/cf_\d+/).uniq.each do |name| + column = available_columns.detect {|c| c.name.to_s == name} + join = column && column.custom_field.join_for_order_statement + if join + joins << join + end + end + end + + joins.any? ? joins.join(' ') : nil + end +end diff --git a/app/models/repository.rb b/app/models/repository.rb new file mode 100644 index 00000000..b0e94636 --- /dev/null +++ b/app/models/repository.rb @@ -0,0 +1,438 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class ScmFetchError < Exception; end + +class Repository < ActiveRecord::Base + include Redmine::Ciphering + include Redmine::SafeAttributes + + # Maximum length for repository identifiers + IDENTIFIER_MAX_LENGTH = 255 + + belongs_to :project + has_many :changesets, :order => "#{Changeset.table_name}.committed_on DESC, #{Changeset.table_name}.id DESC" + has_many :filechanges, :class_name => 'Change', :through => :changesets + + serialize :extra_info + + before_save :check_default + + # Raw SQL to delete changesets and changes in the database + # has_many :changesets, :dependent => :destroy is too slow for big repositories + before_destroy :clear_changesets + + validates_length_of :password, :maximum => 255, :allow_nil => true + validates_length_of :identifier, :maximum => IDENTIFIER_MAX_LENGTH, :allow_blank => true + validates_presence_of :identifier, :unless => Proc.new { |r| r.is_default? || r.set_as_default? } + validates_uniqueness_of :identifier, :scope => :project_id, :allow_blank => true + validates_exclusion_of :identifier, :in => %w(show entry raw changes annotate diff show stats graph) + # donwcase letters, digits, dashes, underscores but not digits only + validates_format_of :identifier, :with => /\A(?!\d+$)[a-z0-9\-_]*\z/, :allow_blank => true + # Checks if the SCM is enabled when creating a repository + validate :repo_create_validation, :on => :create + + safe_attributes 'identifier', + 'login', + 'password', + 'path_encoding', + 'log_encoding', + 'is_default' + + safe_attributes 'url', + :if => lambda {|repository, user| repository.new_record?} + + def repo_create_validation + unless Setting.enabled_scm.include?(self.class.name.demodulize) + errors.add(:type, :invalid) + end + end + + def self.human_attribute_name(attribute_key_name, *args) + attr_name = attribute_key_name.to_s + if attr_name == "log_encoding" + attr_name = "commit_logs_encoding" + end + super(attr_name, *args) + end + + # Removes leading and trailing whitespace + def url=(arg) + write_attribute(:url, arg ? arg.to_s.strip : nil) + end + + # Removes leading and trailing whitespace + def root_url=(arg) + write_attribute(:root_url, arg ? arg.to_s.strip : nil) + end + + def password + read_ciphered_attribute(:password) + end + + def password=(arg) + write_ciphered_attribute(:password, arg) + end + + def scm_adapter + self.class.scm_adapter_class + end + + def scm + unless @scm + @scm = self.scm_adapter.new(url, root_url, + login, password, path_encoding) + if root_url.blank? && @scm.root_url.present? + update_attribute(:root_url, @scm.root_url) + end + end + @scm + end + + def scm_name + self.class.scm_name + end + + def name + if identifier.present? + identifier + elsif is_default? + l(:field_repository_is_default) + else + scm_name + end + end + + def identifier=(identifier) + super unless identifier_frozen? + end + + def identifier_frozen? + errors[:identifier].blank? && !(new_record? || identifier.blank?) + end + + def identifier_param + if is_default? + nil + elsif identifier.present? + identifier + else + id.to_s + end + end + + def <=>(repository) + if is_default? + -1 + elsif repository.is_default? + 1 + else + identifier.to_s <=> repository.identifier.to_s + end + end + + def self.find_by_identifier_param(param) + if param.to_s =~ /^\d+$/ + find_by_id(param) + else + find_by_identifier(param) + end + end + + def merge_extra_info(arg) + h = extra_info || {} + return h if arg.nil? + h.merge!(arg) + write_attribute(:extra_info, h) + end + + def report_last_commit + true + end + + def supports_cat? + scm.supports_cat? + end + + def supports_annotate? + scm.supports_annotate? + end + + def supports_all_revisions? + true + end + + def supports_directory_revisions? + false + end + + def supports_revision_graph? + false + end + + def entry(path=nil, identifier=nil) + scm.entry(path, identifier) + end + + def entries(path=nil, identifier=nil) + entries = scm.entries(path, identifier) + load_entries_changesets(entries) + entries + end + + def branches + scm.branches + end + + def tags + scm.tags + end + + def default_branch + nil + end + + def properties(path, identifier=nil) + scm.properties(path, identifier) + end + + def cat(path, identifier=nil) + scm.cat(path, identifier) + end + + def diff(path, rev, rev_to) + scm.diff(path, rev, rev_to) + end + + def diff_format_revisions(cs, cs_to, sep=':') + text = "" + text << cs_to.format_identifier + sep if cs_to + text << cs.format_identifier if cs + text + end + + # Returns a path relative to the url of the repository + def relative_path(path) + path + end + + # Finds and returns a revision with a number or the beginning of a hash + def find_changeset_by_name(name) + return nil if name.blank? + s = name.to_s + if s.match(/^\d*$/) + changesets.where("revision = ?", s).first + else + changesets.where("revision LIKE ?", s + '%').first + end + end + + def latest_changeset + @latest_changeset ||= changesets.first + end + + # Returns the latest changesets for +path+ + # Default behaviour is to search in cached changesets + def latest_changesets(path, rev, limit=10) + if path.blank? + changesets.find( + :all, + :include => :user, + :order => "#{Changeset.table_name}.committed_on DESC, #{Changeset.table_name}.id DESC", + :limit => limit) + else + filechanges.find( + :all, + :include => {:changeset => :user}, + :conditions => ["path = ?", path.with_leading_slash], + :order => "#{Changeset.table_name}.committed_on DESC, #{Changeset.table_name}.id DESC", + :limit => limit + ).collect(&:changeset) + end + end + + def scan_changesets_for_issue_ids + self.changesets.each(&:scan_comment_for_issue_ids) + end + + # Returns an array of committers usernames and associated user_id + def committers + @committers ||= Changeset.connection.select_rows( + "SELECT DISTINCT committer, user_id FROM #{Changeset.table_name} WHERE repository_id = #{id}") + end + + # Maps committers username to a user ids + def committer_ids=(h) + if h.is_a?(Hash) + committers.each do |committer, user_id| + new_user_id = h[committer] + if new_user_id && (new_user_id.to_i != user_id.to_i) + new_user_id = (new_user_id.to_i > 0 ? new_user_id.to_i : nil) + Changeset.update_all( + "user_id = #{ new_user_id.nil? ? 'NULL' : new_user_id }", + ["repository_id = ? AND committer = ?", id, committer]) + end + end + @committers = nil + @found_committer_users = nil + true + else + false + end + end + + # Returns the Redmine User corresponding to the given +committer+ + # It will return nil if the committer is not yet mapped and if no User + # with the same username or email was found + def find_committer_user(committer) + unless committer.blank? + @found_committer_users ||= {} + return @found_committer_users[committer] if @found_committer_users.has_key?(committer) + + user = nil + c = changesets.where(:committer => committer).includes(:user).first + if c && c.user + user = c.user + elsif committer.strip =~ /^([^<]+)(<(.*)>)?$/ + username, email = $1.strip, $3 + u = User.find_by_login(username) + u ||= User.find_by_mail(email) unless email.blank? + user = u + end + @found_committer_users[committer] = user + user + end + end + + def repo_log_encoding + encoding = log_encoding.to_s.strip + encoding.blank? ? 'UTF-8' : encoding + end + + # Fetches new changesets for all repositories of active projects + # Can be called periodically by an external script + # eg. ruby script/runner "Repository.fetch_changesets" + def self.fetch_changesets + Project.active.has_module(:repository).all.each do |project| + project.repositories.each do |repository| + begin + repository.fetch_changesets + rescue Redmine::Scm::Adapters::CommandFailed => e + logger.error "scm: error during fetching changesets: #{e.message}" + end + end + end + end + + # scan changeset comments to find related and fixed issues for all repositories + def self.scan_changesets_for_issue_ids + all.each(&:scan_changesets_for_issue_ids) + end + + def self.scm_name + 'Abstract' + end + + def self.available_scm + subclasses.collect {|klass| [klass.scm_name, klass.name]} + end + + def self.factory(klass_name, *args) + klass = "Repository::#{klass_name}".constantize + klass.new(*args) + rescue + nil + end + + def self.scm_adapter_class + nil + end + + def self.scm_command + ret = "" + begin + ret = self.scm_adapter_class.client_command if self.scm_adapter_class + rescue Exception => e + logger.error "scm: error during get command: #{e.message}" + end + ret + end + + def self.scm_version_string + ret = "" + begin + ret = self.scm_adapter_class.client_version_string if self.scm_adapter_class + rescue Exception => e + logger.error "scm: error during get version string: #{e.message}" + end + ret + end + + def self.scm_available + ret = false + begin + ret = self.scm_adapter_class.client_available if self.scm_adapter_class + rescue Exception => e + logger.error "scm: error during get scm available: #{e.message}" + end + ret + end + + def set_as_default? + new_record? && project && !Repository.first(:conditions => {:project_id => project.id}) + end + + protected + + def check_default + if !is_default? && set_as_default? + self.is_default = true + end + if is_default? && is_default_changed? + Repository.update_all(["is_default = ?", false], ["project_id = ?", project_id]) + end + end + + def load_entries_changesets(entries) + if entries + entries.each do |entry| + if entry.lastrev && entry.lastrev.identifier + entry.changeset = find_changeset_by_name(entry.lastrev.identifier) + end + end + end + end + + private + + # Deletes repository data + def clear_changesets + cs = Changeset.table_name + ch = Change.table_name + ci = "#{table_name_prefix}changesets_issues#{table_name_suffix}" + cp = "#{table_name_prefix}changeset_parents#{table_name_suffix}" + + connection.delete("DELETE FROM #{ch} WHERE #{ch}.changeset_id IN (SELECT #{cs}.id FROM #{cs} WHERE #{cs}.repository_id = #{id})") + connection.delete("DELETE FROM #{ci} WHERE #{ci}.changeset_id IN (SELECT #{cs}.id FROM #{cs} WHERE #{cs}.repository_id = #{id})") + connection.delete("DELETE FROM #{cp} WHERE #{cp}.changeset_id IN (SELECT #{cs}.id FROM #{cs} WHERE #{cs}.repository_id = #{id})") + connection.delete("DELETE FROM #{cs} WHERE #{cs}.repository_id = #{id}") + clear_extra_info_of_changesets + end + + def clear_extra_info_of_changesets + end +end diff --git a/app/models/repository/bazaar.rb b/app/models/repository/bazaar.rb new file mode 100644 index 00000000..ea20fe37 --- /dev/null +++ b/app/models/repository/bazaar.rb @@ -0,0 +1,128 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +require 'redmine/scm/adapters/bazaar_adapter' + +class Repository::Bazaar < Repository + attr_protected :root_url + validates_presence_of :url, :log_encoding + + def self.human_attribute_name(attribute_key_name, *args) + attr_name = attribute_key_name.to_s + if attr_name == "url" + attr_name = "path_to_repository" + end + super(attr_name, *args) + end + + def self.scm_adapter_class + Redmine::Scm::Adapters::BazaarAdapter + end + + def self.scm_name + 'Bazaar' + end + + def entry(path=nil, identifier=nil) + scm.bzr_path_encodig = log_encoding + scm.entry(path, identifier) + end + + def cat(path, identifier=nil) + scm.bzr_path_encodig = log_encoding + scm.cat(path, identifier) + end + + def annotate(path, identifier=nil) + scm.bzr_path_encodig = log_encoding + scm.annotate(path, identifier) + end + + def diff(path, rev, rev_to) + scm.bzr_path_encodig = log_encoding + scm.diff(path, rev, rev_to) + end + + def entries(path=nil, identifier=nil) + scm.bzr_path_encodig = log_encoding + entries = scm.entries(path, identifier) + if entries + entries.each do |e| + next if e.lastrev.revision.blank? + # Set the filesize unless browsing a specific revision + if identifier.nil? && e.is_file? + full_path = File.join(root_url, e.path) + e.size = File.stat(full_path).size if File.file?(full_path) + end + c = Change.find( + :first, + :include => :changeset, + :conditions => [ + "#{Change.table_name}.revision = ? and #{Changeset.table_name}.repository_id = ?", + e.lastrev.revision, + id + ], + :order => "#{Changeset.table_name}.revision DESC") + if c + e.lastrev.identifier = c.changeset.revision + e.lastrev.name = c.changeset.revision + e.lastrev.author = c.changeset.committer + end + end + end + load_entries_changesets(entries) + entries + end + + def fetch_changesets + scm.bzr_path_encodig = log_encoding + scm_info = scm.info + if scm_info + # latest revision found in database + db_revision = latest_changeset ? latest_changeset.revision.to_i : 0 + # latest revision in the repository + scm_revision = scm_info.lastrev.identifier.to_i + if db_revision < scm_revision + logger.debug "Fetching changesets for repository #{url}" if logger && logger.debug? + identifier_from = db_revision + 1 + while (identifier_from <= scm_revision) + # loads changesets by batches of 200 + identifier_to = [identifier_from + 199, scm_revision].min + revisions = scm.revisions('', identifier_to, identifier_from) + transaction do + revisions.reverse_each do |revision| + changeset = Changeset.create(:repository => self, + :revision => revision.identifier, + :committer => revision.author, + :committed_on => revision.time, + :scmid => revision.scmid, + :comments => revision.message) + + revision.paths.each do |change| + Change.create(:changeset => changeset, + :action => change[:action], + :path => change[:path], + :revision => change[:revision]) + end + end + end unless revisions.nil? + identifier_from = identifier_to + 1 + end + end + end + end +end diff --git a/app/models/repository/cvs.rb b/app/models/repository/cvs.rb new file mode 100644 index 00000000..155ac10e --- /dev/null +++ b/app/models/repository/cvs.rb @@ -0,0 +1,208 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +require 'redmine/scm/adapters/cvs_adapter' +require 'digest/sha1' + +class Repository::Cvs < Repository + validates_presence_of :url, :root_url, :log_encoding + + safe_attributes 'root_url', + :if => lambda {|repository, user| repository.new_record?} + + def self.human_attribute_name(attribute_key_name, *args) + attr_name = attribute_key_name.to_s + if attr_name == "root_url" + attr_name = "cvsroot" + elsif attr_name == "url" + attr_name = "cvs_module" + end + super(attr_name, *args) + end + + def self.scm_adapter_class + Redmine::Scm::Adapters::CvsAdapter + end + + def self.scm_name + 'CVS' + end + + def entry(path=nil, identifier=nil) + rev = identifier.nil? ? nil : changesets.find_by_revision(identifier) + scm.entry(path, rev.nil? ? nil : rev.committed_on) + end + + def entries(path=nil, identifier=nil) + rev = nil + if ! identifier.nil? + rev = changesets.find_by_revision(identifier) + return nil if rev.nil? + end + entries = scm.entries(path, rev.nil? ? nil : rev.committed_on) + if entries + entries.each() do |entry| + if ( ! entry.lastrev.nil? ) && ( ! entry.lastrev.revision.nil? ) + change = filechanges.find_by_revision_and_path( + entry.lastrev.revision, + scm.with_leading_slash(entry.path) ) + if change + entry.lastrev.identifier = change.changeset.revision + entry.lastrev.revision = change.changeset.revision + entry.lastrev.author = change.changeset.committer + # entry.lastrev.branch = change.branch + end + end + end + end + load_entries_changesets(entries) + entries + end + + def cat(path, identifier=nil) + rev = nil + if ! identifier.nil? + rev = changesets.find_by_revision(identifier) + return nil if rev.nil? + end + scm.cat(path, rev.nil? ? nil : rev.committed_on) + end + + def annotate(path, identifier=nil) + rev = nil + if ! identifier.nil? + rev = changesets.find_by_revision(identifier) + return nil if rev.nil? + end + scm.annotate(path, rev.nil? ? nil : rev.committed_on) + end + + def diff(path, rev, rev_to) + # convert rev to revision. CVS can't handle changesets here + diff=[] + changeset_from = changesets.find_by_revision(rev) + if rev_to.to_i > 0 + changeset_to = changesets.find_by_revision(rev_to) + end + changeset_from.filechanges.each() do |change_from| + revision_from = nil + revision_to = nil + if path.nil? || (change_from.path.starts_with? scm.with_leading_slash(path)) + revision_from = change_from.revision + end + if revision_from + if changeset_to + changeset_to.filechanges.each() do |change_to| + revision_to = change_to.revision if change_to.path == change_from.path + end + end + unless revision_to + revision_to = scm.get_previous_revision(revision_from) + end + file_diff = scm.diff(change_from.path, revision_from, revision_to) + diff = diff + file_diff unless file_diff.nil? + end + end + return diff + end + + def fetch_changesets + # some nifty bits to introduce a commit-id with cvs + # natively cvs doesn't provide any kind of changesets, + # there is only a revision per file. + # we now take a guess using the author, the commitlog and the commit-date. + + # last one is the next step to take. the commit-date is not equal for all + # commits in one changeset. cvs update the commit-date when the *,v file was touched. so + # we use a small delta here, to merge all changes belonging to _one_ changeset + time_delta = 10.seconds + fetch_since = latest_changeset ? latest_changeset.committed_on : nil + transaction do + tmp_rev_num = 1 + scm.revisions('', fetch_since, nil, :log_encoding => repo_log_encoding) do |revision| + # only add the change to the database, if it doen't exists. the cvs log + # is not exclusive at all. + tmp_time = revision.time.clone + unless filechanges.find_by_path_and_revision( + scm.with_leading_slash(revision.paths[0][:path]), + revision.paths[0][:revision] + ) + cmt = Changeset.normalize_comments(revision.message, repo_log_encoding) + author_utf8 = Changeset.to_utf8(revision.author, repo_log_encoding) + cs = changesets.find( + :first, + :conditions => { + :committed_on => tmp_time - time_delta .. tmp_time + time_delta, + :committer => author_utf8, + :comments => cmt + } + ) + # create a new changeset.... + unless cs + # we use a temporaray revision number here (just for inserting) + # later on, we calculate a continous positive number + tmp_time2 = tmp_time.clone.gmtime + branch = revision.paths[0][:branch] + scmid = branch + "-" + tmp_time2.strftime("%Y%m%d-%H%M%S") + cs = Changeset.create(:repository => self, + :revision => "tmp#{tmp_rev_num}", + :scmid => scmid, + :committer => revision.author, + :committed_on => tmp_time, + :comments => revision.message) + tmp_rev_num += 1 + end + # convert CVS-File-States to internal Action-abbrevations + # default action is (M)odified + action = "M" + if revision.paths[0][:action] == "Exp" && revision.paths[0][:revision] == "1.1" + action = "A" # add-action always at first revision (= 1.1) + elsif revision.paths[0][:action] == "dead" + action = "D" # dead-state is similar to Delete + end + Change.create( + :changeset => cs, + :action => action, + :path => scm.with_leading_slash(revision.paths[0][:path]), + :revision => revision.paths[0][:revision], + :branch => revision.paths[0][:branch] + ) + end + end + + # Renumber new changesets in chronological order + Changeset.all( + :order => 'committed_on ASC, id ASC', + :conditions => ["repository_id = ? AND revision LIKE 'tmp%'", id] + ).each do |changeset| + changeset.update_attribute :revision, next_revision_number + end + end # transaction + @current_revision_number = nil + end + + private + + # Returns the next revision number to assign to a CVS changeset + def next_revision_number + # Need to retrieve existing revision numbers to sort them as integers + sql = "SELECT revision FROM #{Changeset.table_name} " + sql << "WHERE repository_id = #{id} AND revision NOT LIKE 'tmp%'" + @current_revision_number ||= (connection.select_values(sql).collect(&:to_i).max || 0) + @current_revision_number += 1 + end +end diff --git a/app/models/repository/darcs.rb b/app/models/repository/darcs.rb new file mode 100644 index 00000000..49cbb0e8 --- /dev/null +++ b/app/models/repository/darcs.rb @@ -0,0 +1,114 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +require 'redmine/scm/adapters/darcs_adapter' + +class Repository::Darcs < Repository + validates_presence_of :url, :log_encoding + + def self.human_attribute_name(attribute_key_name, *args) + attr_name = attribute_key_name.to_s + if attr_name == "url" + attr_name = "path_to_repository" + end + super(attr_name, *args) + end + + def self.scm_adapter_class + Redmine::Scm::Adapters::DarcsAdapter + end + + def self.scm_name + 'Darcs' + end + + def supports_directory_revisions? + true + end + + def entry(path=nil, identifier=nil) + patch = identifier.nil? ? nil : changesets.find_by_revision(identifier) + scm.entry(path, patch.nil? ? nil : patch.scmid) + end + + def entries(path=nil, identifier=nil) + patch = nil + if ! identifier.nil? + patch = changesets.find_by_revision(identifier) + return nil if patch.nil? + end + entries = scm.entries(path, patch.nil? ? nil : patch.scmid) + if entries + entries.each do |entry| + # Search the DB for the entry's last change + if entry.lastrev && !entry.lastrev.scmid.blank? + changeset = changesets.find_by_scmid(entry.lastrev.scmid) + end + if changeset + entry.lastrev.identifier = changeset.revision + entry.lastrev.name = changeset.revision + entry.lastrev.time = changeset.committed_on + entry.lastrev.author = changeset.committer + end + end + end + load_entries_changesets(entries) + entries + end + + def cat(path, identifier=nil) + patch = identifier.nil? ? nil : changesets.find_by_revision(identifier.to_s) + scm.cat(path, patch.nil? ? nil : patch.scmid) + end + + def diff(path, rev, rev_to) + patch_from = changesets.find_by_revision(rev) + return nil if patch_from.nil? + patch_to = changesets.find_by_revision(rev_to) if rev_to + if path.blank? + path = patch_from.filechanges.collect{|change| change.path}.join(' ') + end + patch_from ? scm.diff(path, patch_from.scmid, patch_to ? patch_to.scmid : nil) : nil + end + + def fetch_changesets + scm_info = scm.info + if scm_info + db_last_id = latest_changeset ? latest_changeset.scmid : nil + next_rev = latest_changeset ? latest_changeset.revision.to_i + 1 : 1 + # latest revision in the repository + scm_revision = scm_info.lastrev.scmid + unless changesets.find_by_scmid(scm_revision) + revisions = scm.revisions('', db_last_id, nil, :with_path => true) + transaction do + revisions.reverse_each do |revision| + changeset = Changeset.create(:repository => self, + :revision => next_rev, + :scmid => revision.scmid, + :committer => revision.author, + :committed_on => revision.time, + :comments => revision.message) + revision.paths.each do |change| + changeset.create_change(change) + end + next_rev += 1 + end if revisions + end + end + end + end +end diff --git a/app/models/repository/filesystem.rb b/app/models/repository/filesystem.rb new file mode 100644 index 00000000..bb5092e3 --- /dev/null +++ b/app/models/repository/filesystem.rb @@ -0,0 +1,50 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# FileSystem adapter +# File written by Paul Rivier, at Demotera. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +require 'redmine/scm/adapters/filesystem_adapter' + +class Repository::Filesystem < Repository + attr_protected :root_url + validates_presence_of :url + + def self.human_attribute_name(attribute_key_name, *args) + attr_name = attribute_key_name.to_s + if attr_name == "url" + attr_name = "root_directory" + end + super(attr_name, *args) + end + + def self.scm_adapter_class + Redmine::Scm::Adapters::FilesystemAdapter + end + + def self.scm_name + 'Filesystem' + end + + def supports_all_revisions? + false + end + + def fetch_changesets + nil + end +end diff --git a/app/models/repository/git.rb b/app/models/repository/git.rb new file mode 100644 index 00000000..c1f0020e --- /dev/null +++ b/app/models/repository/git.rb @@ -0,0 +1,268 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# Copyright (C) 2007 Patrick Aljord patcito@ŋmail.com +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +require 'redmine/scm/adapters/git_adapter' + +class Repository::Git < Repository + attr_protected :root_url + validates_presence_of :url + + def self.human_attribute_name(attribute_key_name, *args) + attr_name = attribute_key_name.to_s + if attr_name == "url" + attr_name = "path_to_repository" + end + super(attr_name, *args) + end + + def self.scm_adapter_class + Redmine::Scm::Adapters::GitAdapter + end + + def self.scm_name + 'Git' + end + + def report_last_commit + extra_report_last_commit + end + + def extra_report_last_commit + return false if extra_info.nil? + v = extra_info["extra_report_last_commit"] + return false if v.nil? + v.to_s != '0' + end + + def supports_directory_revisions? + true + end + + def supports_revision_graph? + true + end + + def repo_log_encoding + 'UTF-8' + end + + # Returns the identifier for the given git changeset + def self.changeset_identifier(changeset) + changeset.scmid + end + + # Returns the readable identifier for the given git changeset + def self.format_changeset_identifier(changeset) + changeset.revision[0, 8] + end + + def branches + scm.branches + end + + def tags + scm.tags + end + + def default_branch + scm.default_branch + rescue Exception => e + logger.error "git: error during get default branch: #{e.message}" + nil + end + + def find_changeset_by_name(name) + if name.present? + changesets.where(:revision => name.to_s).first || + changesets.where('scmid LIKE ?', "#{name}%").first + end + end + + def entries(path=nil, identifier=nil) + entries = scm.entries(path, identifier, :report_last_commit => extra_report_last_commit) + load_entries_changesets(entries) + entries + end + + # With SCMs that have a sequential commit numbering, + # such as Subversion and Mercurial, + # Redmine is able to be clever and only fetch changesets + # going forward from the most recent one it knows about. + # + # However, Git does not have a sequential commit numbering. + # + # In order to fetch only new adding revisions, + # Redmine needs to save "heads". + # + # In Git and Mercurial, revisions are not in date order. + # Redmine Mercurial fixed issues. + # * Redmine Takes Too Long On Large Mercurial Repository + # http://www.redmine.org/issues/3449 + # * Sorting for changesets might go wrong on Mercurial repos + # http://www.redmine.org/issues/3567 + # + # Database revision column is text, so Redmine can not sort by revision. + # Mercurial has revision number, and revision number guarantees revision order. + # Redmine Mercurial model stored revisions ordered by database id to database. + # So, Redmine Mercurial model can use correct ordering revisions. + # + # Redmine Mercurial adapter uses "hg log -r 0:tip --limit 10" + # to get limited revisions from old to new. + # But, Git 1.7.3.4 does not support --reverse with -n or --skip. + # + # The repository can still be fully reloaded by calling #clear_changesets + # before fetching changesets (eg. for offline resync) + def fetch_changesets + scm_brs = branches + return if scm_brs.nil? || scm_brs.empty? + + h1 = extra_info || {} + h = h1.dup + repo_heads = scm_brs.map{ |br| br.scmid } + h["heads"] ||= [] + prev_db_heads = h["heads"].dup + if prev_db_heads.empty? + prev_db_heads += heads_from_branches_hash + end + return if prev_db_heads.sort == repo_heads.sort + + h["db_consistent"] ||= {} + if changesets.count == 0 + h["db_consistent"]["ordering"] = 1 + merge_extra_info(h) + self.save + elsif ! h["db_consistent"].has_key?("ordering") + h["db_consistent"]["ordering"] = 0 + merge_extra_info(h) + self.save + end + save_revisions(prev_db_heads, repo_heads) + end + + def save_revisions(prev_db_heads, repo_heads) + h = {} + opts = {} + opts[:reverse] = true + opts[:excludes] = prev_db_heads + opts[:includes] = repo_heads + + revisions = scm.revisions('', nil, nil, opts) + return if revisions.blank? + + # Make the search for existing revisions in the database in a more sufficient manner + # + # Git branch is the reference to the specific revision. + # Git can *delete* remote branch and *re-push* branch. + # + # $ git push remote :branch + # $ git push remote branch + # + # After deleting branch, revisions remain in repository until "git gc". + # On git 1.7.2.3, default pruning date is 2 weeks. + # So, "git log --not deleted_branch_head_revision" return code is 0. + # + # After re-pushing branch, "git log" returns revisions which are saved in database. + # So, Redmine needs to scan revisions and database every time. + # + # This is replacing the one-after-one queries. + # Find all revisions, that are in the database, and then remove them from the revision array. + # Then later we won't need any conditions for db existence. + # Query for several revisions at once, and remove them from the revisions array, if they are there. + # Do this in chunks, to avoid eventual memory problems (in case of tens of thousands of commits). + # If there are no revisions (because the original code's algorithm filtered them), + # then this part will be stepped over. + # We make queries, just if there is any revision. + limit = 100 + offset = 0 + revisions_copy = revisions.clone # revisions will change + while offset < revisions_copy.size + recent_changesets_slice = changesets.find( + :all, + :conditions => [ + 'scmid IN (?)', + revisions_copy.slice(offset, limit).map{|x| x.scmid} + ] + ) + # Subtract revisions that redmine already knows about + recent_revisions = recent_changesets_slice.map{|c| c.scmid} + revisions.reject!{|r| recent_revisions.include?(r.scmid)} + offset += limit + end + + revisions.each do |rev| + transaction do + # There is no search in the db for this revision, because above we ensured, + # that it's not in the db. + save_revision(rev) + end + end + h["heads"] = repo_heads.dup + merge_extra_info(h) + self.save + end + private :save_revisions + + def save_revision(rev) + parents = (rev.parents || []).collect{|rp| find_changeset_by_name(rp)}.compact + changeset = Changeset.create( + :repository => self, + :revision => rev.identifier, + :scmid => rev.scmid, + :committer => rev.author, + :committed_on => rev.time, + :comments => rev.message, + :parents => parents + ) + unless changeset.new_record? + rev.paths.each { |change| changeset.create_change(change) } + end + changeset + end + private :save_revision + + def heads_from_branches_hash + h1 = extra_info || {} + h = h1.dup + h["branches"] ||= {} + h['branches'].map{|br, hs| hs['last_scmid']} + end + + def latest_changesets(path,rev,limit=10) + revisions = scm.revisions(path, nil, rev, :limit => limit, :all => false) + return [] if revisions.nil? || revisions.empty? + + changesets.find( + :all, + :conditions => [ + "scmid IN (?)", + revisions.map!{|c| c.scmid} + ] + ) + end + + def clear_extra_info_of_changesets + return if extra_info.nil? + v = extra_info["extra_report_last_commit"] + write_attribute(:extra_info, nil) + h = {} + h["extra_report_last_commit"] = v + merge_extra_info(h) + self.save + end + private :clear_extra_info_of_changesets +end diff --git a/app/models/repository/mercurial.rb b/app/models/repository/mercurial.rb new file mode 100644 index 00000000..79a001e4 --- /dev/null +++ b/app/models/repository/mercurial.rb @@ -0,0 +1,159 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +require 'redmine/scm/adapters/mercurial_adapter' + +class Repository::Mercurial < Repository + # sort changesets by revision number + has_many :changesets, + :order => "#{Changeset.table_name}.id DESC", + :foreign_key => 'repository_id' + + attr_protected :root_url + validates_presence_of :url + + # number of changesets to fetch at once + FETCH_AT_ONCE = 100 + + def self.human_attribute_name(attribute_key_name, *args) + attr_name = attribute_key_name.to_s + if attr_name == "url" + attr_name = "path_to_repository" + end + super(attr_name, *args) + end + + def self.scm_adapter_class + Redmine::Scm::Adapters::MercurialAdapter + end + + def self.scm_name + 'Mercurial' + end + + def supports_directory_revisions? + true + end + + def supports_revision_graph? + true + end + + def repo_log_encoding + 'UTF-8' + end + + # Returns the readable identifier for the given mercurial changeset + def self.format_changeset_identifier(changeset) + "#{changeset.revision}:#{changeset.scmid}" + end + + # Returns the identifier for the given Mercurial changeset + def self.changeset_identifier(changeset) + changeset.scmid + end + + def diff_format_revisions(cs, cs_to, sep=':') + super(cs, cs_to, ' ') + end + + # Finds and returns a revision with a number or the beginning of a hash + def find_changeset_by_name(name) + return nil if name.blank? + s = name.to_s + if /[^\d]/ =~ s or s.size > 8 + cs = changesets.where(:scmid => s).first + else + cs = changesets.where(:revision => s).first + end + return cs if cs + changesets.where('scmid LIKE ?', "#{s}%").first + end + + # Returns the latest changesets for +path+; sorted by revision number + # + # Because :order => 'id DESC' is defined at 'has_many', + # there is no need to set 'order'. + # But, MySQL test fails. + # Sqlite3 and PostgreSQL pass. + # Is this MySQL bug? + def latest_changesets(path, rev, limit=10) + changesets. + includes(:user). + where(latest_changesets_cond(path, rev, limit)). + limit(limit). + order("#{Changeset.table_name}.id DESC"). + all + end + + def latest_changesets_cond(path, rev, limit) + cond, args = [], [] + if scm.branchmap.member? rev + # Mercurial named branch is *stable* in each revision. + # So, named branch can be stored in database. + # Mercurial provides *bookmark* which is equivalent with git branch. + # But, bookmark is not implemented. + cond << "#{Changeset.table_name}.scmid IN (?)" + # Revisions in root directory and sub directory are not equal. + # So, in order to get correct limit, we need to get all revisions. + # But, it is very heavy. + # Mercurial does not treat direcotry. + # So, "hg log DIR" is very heavy. + branch_limit = path.blank? ? limit : ( limit * 5 ) + args << scm.nodes_in_branch(rev, :limit => branch_limit) + elsif last = rev ? find_changeset_by_name(scm.tagmap[rev] || rev) : nil + cond << "#{Changeset.table_name}.id <= ?" + args << last.id + end + unless path.blank? + cond << "EXISTS (SELECT * FROM #{Change.table_name} + WHERE #{Change.table_name}.changeset_id = #{Changeset.table_name}.id + AND (#{Change.table_name}.path = ? + OR #{Change.table_name}.path LIKE ? ESCAPE ?))" + args << path.with_leading_slash + args << "#{path.with_leading_slash.gsub(%r{[%_\\]}) { |s| "\\#{s}" }}/%" << '\\' + end + [cond.join(' AND '), *args] unless cond.empty? + end + private :latest_changesets_cond + + def fetch_changesets + return if scm.info.nil? + scm_rev = scm.info.lastrev.revision.to_i + db_rev = latest_changeset ? latest_changeset.revision.to_i : -1 + return unless db_rev < scm_rev # already up-to-date + + logger.debug "Fetching changesets for repository #{url}" if logger + (db_rev + 1).step(scm_rev, FETCH_AT_ONCE) do |i| + scm.each_revision('', i, [i + FETCH_AT_ONCE - 1, scm_rev].min) do |re| + transaction do + parents = (re.parents || []).collect{|rp| find_changeset_by_name(rp)}.compact + cs = Changeset.create(:repository => self, + :revision => re.revision, + :scmid => re.scmid, + :committer => re.author, + :committed_on => re.time, + :comments => re.message, + :parents => parents) + unless cs.new_record? + re.paths.each { |e| cs.create_change(e) } + end + end + end + end + end +end diff --git a/app/models/repository/subversion.rb b/app/models/repository/subversion.rb new file mode 100644 index 00000000..68853a3c --- /dev/null +++ b/app/models/repository/subversion.rb @@ -0,0 +1,116 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +require 'redmine/scm/adapters/subversion_adapter' + +class Repository::Subversion < Repository + attr_protected :root_url + validates_presence_of :url + validates_format_of :url, :with => /\A(http|https|svn(\+[^\s:\/\\]+)?|file):\/\/.+/i + + def self.scm_adapter_class + Redmine::Scm::Adapters::SubversionAdapter + end + + def self.scm_name + 'Subversion' + end + + def supports_directory_revisions? + true + end + + def repo_log_encoding + 'UTF-8' + end + + def latest_changesets(path, rev, limit=10) + revisions = scm.revisions(path, rev, nil, :limit => limit) + if revisions + identifiers = revisions.collect(&:identifier).compact + changesets.where(:revision => identifiers).reorder("committed_on DESC").includes(:repository, :user).all + else + [] + end + end + + # Returns a path relative to the url of the repository + def relative_path(path) + path.gsub(Regexp.new("^\/?#{Regexp.escape(relative_url)}"), '') + end + + def fetch_changesets + scm_info = scm.info + if scm_info + # latest revision found in database + db_revision = latest_changeset ? latest_changeset.revision.to_i : 0 + # latest revision in the repository + scm_revision = scm_info.lastrev.identifier.to_i + if db_revision < scm_revision + logger.debug "Fetching changesets for repository #{url}" if logger && logger.debug? + identifier_from = db_revision + 1 + while (identifier_from <= scm_revision) + # loads changesets by batches of 200 + identifier_to = [identifier_from + 199, scm_revision].min + revisions = scm.revisions('', identifier_to, identifier_from, :with_paths => true) + revisions.reverse_each do |revision| + transaction do + changeset = Changeset.create(:repository => self, + :revision => revision.identifier, + :committer => revision.author, + :committed_on => revision.time, + :comments => revision.message) + + revision.paths.each do |change| + changeset.create_change(change) + end unless changeset.new_record? + end + end unless revisions.nil? + identifier_from = identifier_to + 1 + end + end + end + end + + protected + + def load_entries_changesets(entries) + return unless entries + + entries_with_identifier = entries.select {|entry| entry.lastrev && entry.lastrev.identifier.present?} + identifiers = entries_with_identifier.map {|entry| entry.lastrev.identifier}.compact.uniq + + if identifiers.any? + changesets_by_identifier = changesets.where(:revision => identifiers).includes(:user, :repository).all.group_by(&:revision) + entries_with_identifier.each do |entry| + if m = changesets_by_identifier[entry.lastrev.identifier] + entry.changeset = m.first + end + end + end + end + + private + + # Returns the relative url of the repository + # Eg: root_url = file:///var/svn/foo + # url = file:///var/svn/foo/bar + # => returns /bar + def relative_url + @relative_url ||= url.gsub(Regexp.new("^#{Regexp.escape(root_url || scm.root_url)}", Regexp::IGNORECASE), '') + end +end diff --git a/app/models/role.rb b/app/models/role.rb new file mode 100644 index 00000000..c7f9306b --- /dev/null +++ b/app/models/role.rb @@ -0,0 +1,208 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class Role < ActiveRecord::Base + # Custom coder for the permissions attribute that should be an + # array of symbols. Rails 3 uses Psych which can be *unbelievably* + # slow on some platforms (eg. mingw32). + class PermissionsAttributeCoder + def self.load(str) + str.to_s.scan(/:([a-z0-9_]+)/).flatten.map(&:to_sym) + end + + def self.dump(value) + YAML.dump(value) + end + end + + # Built-in roles + BUILTIN_NON_MEMBER = 1 + BUILTIN_ANONYMOUS = 2 + + ISSUES_VISIBILITY_OPTIONS = [ + ['all', :label_issues_visibility_all], + ['default', :label_issues_visibility_public], + ['own', :label_issues_visibility_own] + ] + + scope :sorted, lambda { order("#{table_name}.builtin ASC, #{table_name}.position ASC") } + scope :givable, lambda { order("#{table_name}.position ASC").where(:builtin => 0) } + scope :builtin, lambda { |*args| + compare = (args.first == true ? 'not' : '') + where("#{compare} builtin = 0") + } + + before_destroy :check_deletable + has_many :workflow_rules, :dependent => :delete_all do + def copy(source_role) + WorkflowRule.copy(nil, source_role, nil, proxy_association.owner) + end + end + + has_many :member_roles, :dependent => :destroy + has_many :members, :through => :member_roles + acts_as_list + + serialize :permissions, ::Role::PermissionsAttributeCoder + attr_protected :builtin + + validates_presence_of :name + validates_uniqueness_of :name + validates_length_of :name, :maximum => 30 + validates_inclusion_of :issues_visibility, + :in => ISSUES_VISIBILITY_OPTIONS.collect(&:first), + :if => lambda {|role| role.respond_to?(:issues_visibility)} + + # Copies attributes from another role, arg can be an id or a Role + def copy_from(arg, options={}) + return unless arg.present? + role = arg.is_a?(Role) ? arg : Role.find_by_id(arg.to_s) + self.attributes = role.attributes.dup.except("id", "name", "position", "builtin", "permissions") + self.permissions = role.permissions.dup + self + end + + def permissions=(perms) + perms = perms.collect {|p| p.to_sym unless p.blank? }.compact.uniq if perms + write_attribute(:permissions, perms) + end + + def add_permission!(*perms) + self.permissions = [] unless permissions.is_a?(Array) + + permissions_will_change! + perms.each do |p| + p = p.to_sym + permissions << p unless permissions.include?(p) + end + save! + end + + def remove_permission!(*perms) + return unless permissions.is_a?(Array) + permissions_will_change! + perms.each { |p| permissions.delete(p.to_sym) } + save! + end + + # Returns true if the role has the given permission + def has_permission?(perm) + !permissions.nil? && permissions.include?(perm.to_sym) + end + + def <=>(role) + if role + if builtin == role.builtin + position <=> role.position + else + builtin <=> role.builtin + end + else + -1 + end + end + + def to_s + name + end + + def name + case builtin + when 1; l(:label_role_non_member, :default => read_attribute(:name)) + when 2; l(:label_role_anonymous, :default => read_attribute(:name)) + else; read_attribute(:name) + end + end + + # Return true if the role is a builtin role + def builtin? + self.builtin != 0 + end + + # Return true if the role is the anonymous role + def anonymous? + builtin == 2 + end + + # Return true if the role is a project member role + def member? + !self.builtin? + end + + # Return true if role is allowed to do the specified action + # action can be: + # * a parameter-like Hash (eg. :controller => 'projects', :action => 'edit') + # * a permission Symbol (eg. :edit_project) + def allowed_to?(action) + if action.is_a? Hash + allowed_actions.include? "#{action[:controller]}/#{action[:action]}" + else + allowed_permissions.include? action + end + end + + # Return all the permissions that can be given to the role + def setable_permissions + setable_permissions = Redmine::AccessControl.permissions - Redmine::AccessControl.public_permissions + setable_permissions -= Redmine::AccessControl.members_only_permissions if self.builtin == BUILTIN_NON_MEMBER + setable_permissions -= Redmine::AccessControl.loggedin_only_permissions if self.builtin == BUILTIN_ANONYMOUS + setable_permissions + end + + # Find all the roles that can be given to a project member + def self.find_all_givable + Role.givable.all + end + + # Return the builtin 'non member' role. If the role doesn't exist, + # it will be created on the fly. + def self.non_member + find_or_create_system_role(BUILTIN_NON_MEMBER, 'Non member') + end + + # Return the builtin 'anonymous' role. If the role doesn't exist, + # it will be created on the fly. + def self.anonymous + find_or_create_system_role(BUILTIN_ANONYMOUS, 'Anonymous') + end + +private + + def allowed_permissions + @allowed_permissions ||= permissions + Redmine::AccessControl.public_permissions.collect {|p| p.name} + end + + def allowed_actions + @actions_allowed ||= allowed_permissions.inject([]) { |actions, permission| actions += Redmine::AccessControl.allowed_actions(permission) }.flatten + end + + def check_deletable + raise "Can't delete role" if members.any? + raise "Can't delete builtin role" if builtin? + end + + def self.find_or_create_system_role(builtin, name) + role = where(:builtin => builtin).first + if role.nil? + role = create(:name => name, :position => 0) do |r| + r.builtin = builtin + end + raise "Unable to create the #{name} role." if role.new_record? + end + role + end +end diff --git a/app/models/setting.rb b/app/models/setting.rb new file mode 100644 index 00000000..dab6ceaa --- /dev/null +++ b/app/models/setting.rb @@ -0,0 +1,178 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class Setting < ActiveRecord::Base + + DATE_FORMATS = [ + '%Y-%m-%d', + '%d/%m/%Y', + '%d.%m.%Y', + '%d-%m-%Y', + '%m/%d/%Y', + '%d %b %Y', + '%d %B %Y', + '%b %d, %Y', + '%B %d, %Y' + ] + + TIME_FORMATS = [ + '%H:%M', + '%I:%M %p' + ] + + ENCODINGS = %w(US-ASCII + windows-1250 + windows-1251 + windows-1252 + windows-1253 + windows-1254 + windows-1255 + windows-1256 + windows-1257 + windows-1258 + windows-31j + ISO-2022-JP + ISO-2022-KR + ISO-8859-1 + ISO-8859-2 + ISO-8859-3 + ISO-8859-4 + ISO-8859-5 + ISO-8859-6 + ISO-8859-7 + ISO-8859-8 + ISO-8859-9 + ISO-8859-13 + ISO-8859-15 + KOI8-R + UTF-8 + UTF-16 + UTF-16BE + UTF-16LE + EUC-JP + Shift_JIS + CP932 + GB18030 + GBK + ISCII91 + EUC-KR + Big5 + Big5-HKSCS + TIS-620) + + cattr_accessor :available_settings + @@available_settings = YAML::load(File.open("#{Rails.root}/config/settings.yml")) + Redmine::Plugin.all.each do |plugin| + next unless plugin.settings + @@available_settings["plugin_#{plugin.id}"] = {'default' => plugin.settings[:default], 'serialized' => true} + end + + validates_uniqueness_of :name + validates_inclusion_of :name, :in => @@available_settings.keys + validates_numericality_of :value, :only_integer => true, :if => Proc.new { |setting| @@available_settings[setting.name]['format'] == 'int' } + + # Hash used to cache setting values + @cached_settings = {} + @cached_cleared_on = Time.now + + def value + v = read_attribute(:value) + # Unserialize serialized settings + v = YAML::load(v) if @@available_settings[name]['serialized'] && v.is_a?(String) + v = v.to_sym if @@available_settings[name]['format'] == 'symbol' && !v.blank? + v + end + + def value=(v) + v = v.to_yaml if v && @@available_settings[name] && @@available_settings[name]['serialized'] + write_attribute(:value, v.to_s) + end + + # Returns the value of the setting named name + def self.[](name) + v = @cached_settings[name] + v ? v : (@cached_settings[name] = find_or_default(name).value) + end + + def self.[]=(name, v) + setting = find_or_default(name) + setting.value = (v ? v : "") + @cached_settings[name] = nil + setting.save + setting.value + end + + # Defines getter and setter for each setting + # Then setting values can be read using: Setting.some_setting_name + # or set using Setting.some_setting_name = "some value" + @@available_settings.each do |name, params| + src = <<-END_SRC + def self.#{name} + self[:#{name}] + end + + def self.#{name}? + self[:#{name}].to_i > 0 + end + + def self.#{name}=(value) + self[:#{name}] = value + end + END_SRC + class_eval src, __FILE__, __LINE__ + end + + # Helper that returns an array based on per_page_options setting + def self.per_page_options_array + per_page_options.split(%r{[\s,]}).collect(&:to_i).select {|n| n > 0}.sort + end + + def self.openid? + Object.const_defined?(:OpenID) && self[:openid].to_i > 0 + end + + # Checks if settings have changed since the values were read + # and clears the cache hash if it's the case + # Called once per request + def self.check_cache + settings_updated_on = Setting.maximum(:updated_on) + if settings_updated_on && @cached_cleared_on <= settings_updated_on + clear_cache + end + end + + # Clears the settings cache + def self.clear_cache + @cached_settings.clear + @cached_cleared_on = Time.now + logger.info "Settings cache cleared." if logger + end + +private + # Returns the Setting instance for the setting named name + # (record found in database or new record with default value) + def self.find_or_default(name) + name = name.to_s + raise "There's no setting named #{name}" unless @@available_settings.has_key?(name) + setting = find_by_name(name) + unless setting + setting = new(:name => name) + setting.value = @@available_settings[name]['default'] + end + setting + end +end diff --git a/app/models/tag.rb b/app/models/tag.rb new file mode 100644 index 00000000..b6faeda5 --- /dev/null +++ b/app/models/tag.rb @@ -0,0 +1,19 @@ +class Tag < ActiveRecord::Base + attr_accessible :content +#添加代码 + has_many :projects, :through => :project_tags + has_many :project_tags, :class_name => 'ProjectTags' + + #确定content不会被重复写入 + validates_uniqueness_of :content + validates_presence_of :content + + #添加tag内容 + def self.add_content(content) + @tag=Tag.new + @tag.content = content + @tag.save + true + end +end +#添加结束 \ No newline at end of file diff --git a/app/models/time_entry.rb b/app/models/time_entry.rb new file mode 100644 index 00000000..76200e09 --- /dev/null +++ b/app/models/time_entry.rb @@ -0,0 +1,119 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class TimeEntry < ActiveRecord::Base + include Redmine::SafeAttributes + # could have used polymorphic association + # project association here allows easy loading of time entries at project level with one database trip + belongs_to :project + belongs_to :issue + belongs_to :user + belongs_to :activity, :class_name => 'TimeEntryActivity', :foreign_key => 'activity_id' + + attr_protected :project_id, :user_id, :tyear, :tmonth, :tweek + + acts_as_customizable + acts_as_event :title => Proc.new {|o| "#{l_hours(o.hours)} (#{(o.issue || o.project).event_title})"}, + :url => Proc.new {|o| {:controller => 'timelog', :action => 'index', :project_id => o.project, :issue_id => o.issue}}, + :author => :user, + :group => :issue, + :description => :comments + + acts_as_activity_provider :timestamp => "#{table_name}.created_on", + :author_key => :user_id, + :find_options => {:include => :project} + + validates_presence_of :user_id, :activity_id, :project_id, :hours, :spent_on + validates_numericality_of :hours, :allow_nil => true, :message => :invalid + validates_length_of :comments, :maximum => 255, :allow_nil => true + validates :spent_on, :date => true + before_validation :set_project_if_nil + validate :validate_time_entry + + scope :visible, lambda {|*args| + includes(:project).where(Project.allowed_to_condition(args.shift || User.current, :view_time_entries, *args)) + } + scope :on_issue, lambda {|issue| + includes(:issue).where("#{Issue.table_name}.root_id = #{issue.root_id} AND #{Issue.table_name}.lft >= #{issue.lft} AND #{Issue.table_name}.rgt <= #{issue.rgt}") + } + scope :on_project, lambda {|project, include_subprojects| + includes(:project).where(project.project_condition(include_subprojects)) + } + scope :spent_between, lambda {|from, to| + if from && to + where("#{TimeEntry.table_name}.spent_on BETWEEN ? AND ?", from, to) + elsif from + where("#{TimeEntry.table_name}.spent_on >= ?", from) + elsif to + where("#{TimeEntry.table_name}.spent_on <= ?", to) + else + where(nil) + end + } + + safe_attributes 'hours', 'comments', 'issue_id', 'activity_id', 'spent_on', 'custom_field_values', 'custom_fields' + + def initialize(attributes=nil, *args) + super + if new_record? && self.activity.nil? + if default_activity = TimeEntryActivity.default + self.activity_id = default_activity.id + end + self.hours = nil if hours == 0 + end + end + + def set_project_if_nil + self.project = issue.project if issue && project.nil? + end + + def validate_time_entry + errors.add :hours, :invalid if hours && (hours < 0 || hours >= 1000) + errors.add :project_id, :invalid if project.nil? + errors.add :issue_id, :invalid if (issue_id && !issue) || (issue && project!=issue.project) + end + + def hours=(h) + write_attribute :hours, (h.is_a?(String) ? (h.to_hours || h) : h) + end + + def hours + h = read_attribute(:hours) + if h.is_a?(Float) + h.round(2) + else + h + end + end + + # tyear, tmonth, tweek assigned where setting spent_on attributes + # these attributes make time aggregations easier + def spent_on=(date) + super + if spent_on.is_a?(Time) + self.spent_on = spent_on.to_date + end + self.tyear = spent_on ? spent_on.year : nil + self.tmonth = spent_on ? spent_on.month : nil + self.tweek = spent_on ? Date.civil(spent_on.year, spent_on.month, spent_on.day).cweek : nil + end + + # Returns true if the time entry can be edited by usr, otherwise false + def editable_by?(usr) + (usr == user && usr.allowed_to?(:edit_own_time_entries, project)) || usr.allowed_to?(:edit_time_entries, project) + end +end diff --git a/app/models/time_entry_activity.rb b/app/models/time_entry_activity.rb new file mode 100644 index 00000000..f2a18d1d --- /dev/null +++ b/app/models/time_entry_activity.rb @@ -0,0 +1,34 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class TimeEntryActivity < Enumeration + has_many :time_entries, :foreign_key => 'activity_id' + + OptionName = :enumeration_activities + + def option_name + OptionName + end + + def objects_count + time_entries.count + end + + def transfer_relations(to) + time_entries.update_all("activity_id = #{to.id}") + end +end diff --git a/app/models/time_entry_activity_custom_field.rb b/app/models/time_entry_activity_custom_field.rb new file mode 100644 index 00000000..9e68526d --- /dev/null +++ b/app/models/time_entry_activity_custom_field.rb @@ -0,0 +1,22 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class TimeEntryActivityCustomField < CustomField + def type_name + :enumeration_activities + end +end diff --git a/app/models/time_entry_custom_field.rb b/app/models/time_entry_custom_field.rb new file mode 100644 index 00000000..df3aed62 --- /dev/null +++ b/app/models/time_entry_custom_field.rb @@ -0,0 +1,23 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class TimeEntryCustomField < CustomField + def type_name + :label_spent_time + end +end + diff --git a/app/models/time_entry_query.rb b/app/models/time_entry_query.rb new file mode 100644 index 00000000..f0301ce3 --- /dev/null +++ b/app/models/time_entry_query.rb @@ -0,0 +1,115 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class TimeEntryQuery < Query + + self.queried_class = TimeEntry + + self.available_columns = [ + QueryColumn.new(:project, :sortable => "#{Project.table_name}.name", :groupable => true), + QueryColumn.new(:spent_on, :sortable => ["#{TimeEntry.table_name}.spent_on", "#{TimeEntry.table_name}.created_on"], :default_order => 'desc', :groupable => true), + QueryColumn.new(:user, :sortable => lambda {User.fields_for_order_statement}, :groupable => true), + QueryColumn.new(:activity, :sortable => "#{TimeEntryActivity.table_name}.position", :groupable => true), + QueryColumn.new(:issue, :sortable => "#{Issue.table_name}.id"), + QueryColumn.new(:comments), + QueryColumn.new(:hours, :sortable => "#{TimeEntry.table_name}.hours"), + ] + + def initialize(attributes=nil, *args) + super attributes + self.filters ||= {} + add_filter('spent_on', '*') unless filters.present? + end + + def initialize_available_filters + add_available_filter "spent_on", :type => :date_past + + principals = [] + if project + principals += project.principals.sort + unless project.leaf? + subprojects = project.descendants.visible.all + if subprojects.any? + add_available_filter "subproject_id", + :type => :list_subprojects, + :values => subprojects.collect{|s| [s.name, s.id.to_s] } + principals += Principal.member_of(subprojects) + end + end + else + if all_projects.any? + # members of visible projects + principals += Principal.member_of(all_projects) + # project filter + project_values = [] + if User.current.logged? && User.current.memberships.any? + project_values << ["<< #{l(:label_my_projects).downcase} >>", "mine"] + end + project_values += all_projects_values + add_available_filter("project_id", + :type => :list, :values => project_values + ) unless project_values.empty? + end + end + principals.uniq! + principals.sort! + users = principals.select {|p| p.is_a?(User)} + + users_values = [] + users_values << ["<< #{l(:label_me)} >>", "me"] if User.current.logged? + users_values += users.collect{|s| [s.name, s.id.to_s] } + add_available_filter("user_id", + :type => :list_optional, :values => users_values + ) unless users_values.empty? + + activities = (project ? project.activities : TimeEntryActivity.shared.active) + add_available_filter("activity_id", + :type => :list, :values => activities.map {|a| [a.name, a.id.to_s]} + ) unless activities.empty? + + add_available_filter "comments", :type => :text + add_available_filter "hours", :type => :float + + add_custom_fields_filters(TimeEntryCustomField.where(:is_filter => true).all) + add_associations_custom_fields_filters :project, :issue, :user + end + + def available_columns + return @available_columns if @available_columns + @available_columns = self.class.available_columns.dup + @available_columns += TimeEntryCustomField.all.map {|cf| QueryCustomFieldColumn.new(cf) } + @available_columns += IssueCustomField.all.map {|cf| QueryAssociationCustomFieldColumn.new(:issue, cf) } + @available_columns + end + + def default_columns_names + @default_columns_names ||= [:project, :spent_on, :user, :activity, :issue, :comments, :hours] + end + + # Accepts :from/:to params as shortcut filters + def build_from_params(params) + super + if params[:from].present? && params[:to].present? + add_filter('spent_on', '><', [params[:from], params[:to]]) + elsif params[:from].present? + add_filter('spent_on', '>=', [params[:from]]) + elsif params[:to].present? + add_filter('spent_on', '<=', [params[:to]]) + end + self + end +end diff --git a/app/models/token.rb b/app/models/token.rb new file mode 100644 index 00000000..3131bce8 --- /dev/null +++ b/app/models/token.rb @@ -0,0 +1,83 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class Token < ActiveRecord::Base + belongs_to :user + validates_uniqueness_of :value + + before_create :delete_previous_tokens, :generate_new_token + + @@validity_time = 1.day + + def generate_new_token + self.value = Token.generate_token_value + end + + # Return true if token has expired + def expired? + return Time.now > self.created_on + @@validity_time + end + + # Delete all expired tokens + def self.destroy_expired + Token.delete_all ["action NOT IN (?) AND created_on < ?", ['feeds', 'api'], Time.now - @@validity_time] + end + + # Returns the active user who owns the key for the given action + def self.find_active_user(action, key, validity_days=nil) + user = find_user(action, key, validity_days) + if user && user.active? + user + end + end + + # Returns the user who owns the key for the given action + def self.find_user(action, key, validity_days=nil) + token = find_token(action, key, validity_days) + if token + token.user + end + end + + # Returns the token for action and key with an optional + # validity duration (in number of days) + def self.find_token(action, key, validity_days=nil) + action = action.to_s + key = key.to_s + return nil unless action.present? && key =~ /\A[a-z0-9]+\z/i + + token = Token.where(:action => action, :value => key).first + if token && (token.action == action) && (token.value == key) && token.user + if validity_days.nil? || (token.created_on > validity_days.days.ago) + token + end + end + end + + def self.generate_token_value + Redmine::Utils.random_hex(20) + end + + private + + # Removes obsolete tokens (same user and action) + def delete_previous_tokens + if user + Token.delete_all(['user_id = ? AND action = ?', user.id, action]) + end + end +end diff --git a/app/models/tracker.rb b/app/models/tracker.rb new file mode 100644 index 00000000..d487de67 --- /dev/null +++ b/app/models/tracker.rb @@ -0,0 +1,115 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class Tracker < ActiveRecord::Base + + CORE_FIELDS_UNDISABLABLE = %w(project_id tracker_id subject description priority_id is_private).freeze + # Fields that can be disabled + # Other (future) fields should be appended, not inserted! + CORE_FIELDS = %w(assigned_to_id category_id fixed_version_id parent_issue_id start_date due_date estimated_hours done_ratio).freeze + CORE_FIELDS_ALL = (CORE_FIELDS_UNDISABLABLE + CORE_FIELDS).freeze + + before_destroy :check_integrity + has_many :issues + has_many :workflow_rules, :dependent => :delete_all do + def copy(source_tracker) + WorkflowRule.copy(source_tracker, nil, proxy_association.owner, nil) + end + end + + has_and_belongs_to_many :projects + has_and_belongs_to_many :custom_fields, :class_name => 'IssueCustomField', :join_table => "#{table_name_prefix}custom_fields_trackers#{table_name_suffix}", :association_foreign_key => 'custom_field_id' + acts_as_list + + attr_protected :fields_bits + + validates_presence_of :name + validates_uniqueness_of :name + validates_length_of :name, :maximum => 30 + + scope :sorted, lambda { order("#{table_name}.position ASC") } + scope :named, lambda {|arg| where("LOWER(#{table_name}.name) = LOWER(?)", arg.to_s.strip)} + + def to_s; name end + + def <=>(tracker) + position <=> tracker.position + end + + # Returns an array of IssueStatus that are used + # in the tracker's workflows + def issue_statuses + if @issue_statuses + return @issue_statuses + elsif new_record? + return [] + end + + ids = WorkflowTransition. + connection.select_rows("SELECT DISTINCT old_status_id, new_status_id FROM #{WorkflowTransition.table_name} WHERE tracker_id = #{id} AND type = 'WorkflowTransition'"). + flatten. + uniq + + @issue_statuses = IssueStatus.find_all_by_id(ids).sort + end + + def disabled_core_fields + i = -1 + @disabled_core_fields ||= CORE_FIELDS.select { i += 1; (fields_bits || 0) & (2 ** i) != 0} + end + + def core_fields + CORE_FIELDS - disabled_core_fields + end + + def core_fields=(fields) + raise ArgumentError.new("Tracker.core_fields takes an array") unless fields.is_a?(Array) + + bits = 0 + CORE_FIELDS.each_with_index do |field, i| + unless fields.include?(field) + bits |= 2 ** i + end + end + self.fields_bits = bits + @disabled_core_fields = nil + core_fields + end + + # Returns the fields that are disabled for all the given trackers + def self.disabled_core_fields(trackers) + if trackers.present? + trackers.uniq.map(&:disabled_core_fields).reduce(:&) + else + [] + end + end + + # Returns the fields that are enabled for one tracker at least + def self.core_fields(trackers) + if trackers.present? + trackers.uniq.map(&:core_fields).reduce(:|) + else + CORE_FIELDS.dup + end + end + +private + def check_integrity + raise Exception.new("Can't delete tracker") if Issue.where(:tracker_id => self.id).any? + end +end diff --git a/app/models/user.rb b/app/models/user.rb new file mode 100644 index 00000000..e4667f72 --- /dev/null +++ b/app/models/user.rb @@ -0,0 +1,737 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +require "digest/sha1" + +class User < Principal + include Redmine::SafeAttributes + + # Different ways of displaying/sorting users + USER_FORMATS = { + :firstname_lastname => { + :string => '#{firstname} #{lastname}', + :order => %w(firstname lastname id), + :setting_order => 1 + }, + :firstname_lastinitial => { + :string => '#{firstname} #{lastname.to_s.chars.first}.', + :order => %w(firstname lastname id), + :setting_order => 2 + }, + :firstname => { + :string => '#{firstname}', + :order => %w(firstname id), + :setting_order => 3 + }, + :lastname_firstname => { + :string => '#{lastname} #{firstname}', + :order => %w(lastname firstname id), + :setting_order => 4 + }, + :lastname_coma_firstname => { + :string => '#{lastname}, #{firstname}', + :order => %w(lastname firstname id), + :setting_order => 5 + }, + :lastname => { + :string => '#{lastname}', + :order => %w(lastname id), + :setting_order => 6 + }, + :username => { + :string => '#{login}', + :order => %w(login id), + :setting_order => 7 + }, + } + + MAIL_NOTIFICATION_OPTIONS = [ + ['all', :label_user_mail_option_all], + ['selected', :label_user_mail_option_selected], + ['only_my_events', :label_user_mail_option_only_my_events], + ['only_assigned', :label_user_mail_option_only_assigned], + ['only_owner', :label_user_mail_option_only_owner], + ['none', :label_user_mail_option_none] + ] + + has_and_belongs_to_many :groups, :after_add => Proc.new {|user, group| group.user_added(user)}, + :after_remove => Proc.new {|user, group| group.user_removed(user)} + has_many :changesets, :dependent => :nullify + has_one :preference, :dependent => :destroy, :class_name => 'UserPreference' + has_one :rss_token, :class_name => 'Token', :conditions => "action='feeds'" + has_one :api_token, :class_name => 'Token', :conditions => "action='api'" + belongs_to :auth_source + + # 添加用户关注项目功能 fq + has_many :projects, :through => :watchers_of_projects + has_many :watchers_of_projects, :class_name => 'WatchersOfProjects' + # end of + + # 添加关注用户功能 fq + has_many :watchers_of_users + # end of + + #添加用户留言功能 fq + has_many :messages_for_users + #end +#####fq + has_many :jours, :class_name => 'JournalsForMessage', :dependent => :destroy + has_many :bids, :dependent => :destroy + has_many :journals_for_messages, :as => :jour, :dependent => :destroy + ##### + + + scope :logged, lambda { where("#{User.table_name}.status <> #{STATUS_ANONYMOUS}") } + scope :status, lambda {|arg| where(arg.blank? ? nil : {:status => arg.to_i}) } + + + + acts_as_customizable + ############################added by william + acts_as_taggable + + ############################# added by liuping 关注 + acts_as_watchable + + attr_accessor :password, :password_confirmation + attr_accessor :last_before_login_on + # Prevents unauthorized assignments + attr_protected :login, :admin, :password, :password_confirmation, :hashed_password + + LOGIN_LENGTH_LIMIT = 60 + MAIL_LENGTH_LIMIT = 60 + + validates_presence_of :login, :firstname, :lastname, :mail, :if => Proc.new { |user| !user.is_a?(AnonymousUser) } + validates_uniqueness_of :login, :if => Proc.new { |user| user.login_changed? && user.login.present? }, :case_sensitive => false + validates_uniqueness_of :mail, :if => Proc.new { |user| user.mail_changed? && user.mail.present? }, :case_sensitive => false + # Login must contain letters, numbers, underscores only + validates_format_of :login, :with => /\A[a-z0-9_\-@\.]*\z/i + validates_length_of :login, :maximum => LOGIN_LENGTH_LIMIT + validates_length_of :firstname, :lastname, :maximum => 30 + validates_format_of :mail, :with => /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i, :allow_blank => true + validates_length_of :mail, :maximum => MAIL_LENGTH_LIMIT, :allow_nil => true + validates_confirmation_of :password, :allow_nil => true + validates_inclusion_of :mail_notification, :in => MAIL_NOTIFICATION_OPTIONS.collect(&:first), :allow_blank => true + validate :validate_password_length + + before_create :set_mail_notification + before_save :update_hashed_password + before_destroy :remove_references_before_destroy + + scope :in_group, lambda {|group| + group_id = group.is_a?(Group) ? group.id : group.to_i + where("#{User.table_name}.id IN (SELECT gu.user_id FROM #{table_name_prefix}groups_users#{table_name_suffix} gu WHERE gu.group_id = ?)", group_id) + } + scope :not_in_group, lambda {|group| + group_id = group.is_a?(Group) ? group.id : group.to_i + where("#{User.table_name}.id NOT IN (SELECT gu.user_id FROM #{table_name_prefix}groups_users#{table_name_suffix} gu WHERE gu.group_id = ?)", group_id) + } + scope :sorted, lambda { order(*User.fields_for_order_statement)} + + + ###添加留言 + def add_jour(user, notes) + self.journals_for_messages << JournalsForMessage.new(:user_id => user.id, :notes => notes) + end + + def set_mail_notification + self.mail_notification = Setting.default_notification_option if self.mail_notification.blank? + true + end + + def update_hashed_password + # update hashed_password if password was set + if self.password && self.auth_source_id.blank? + salt_password(password) + end + end + + alias :base_reload :reload + def reload(*args) + @name = nil + @projects_by_role = nil + @membership_by_project_id = nil + base_reload(*args) + end + + def mail=(arg) + write_attribute(:mail, arg.to_s.strip) + end + + def identity_url=(url) + if url.blank? + write_attribute(:identity_url, '') + else + begin + write_attribute(:identity_url, OpenIdAuthentication.normalize_identifier(url)) + rescue OpenIdAuthentication::InvalidOpenId + # Invalid url, don't save + end + end + self.read_attribute(:identity_url) + end + + # Returns the user that matches provided login and password, or nil + #登录,返回用户名与密码匹配的用户 + def self.try_to_login(login, password) + login = login.to_s + password = password.to_s + + # Make sure no one can sign in with an empty login or password + return nil if login.empty? || password.empty? + user = find_by_login(login) + if user + # user is already in local database + return nil unless user.active? + return nil unless user.check_password?(password) + else + # user is not yet registered, try to authenticate with available sources + attrs = AuthSource.authenticate(login, password) + if attrs + user = new(attrs) + user.login = login + user.language = Setting.default_language + if user.save + user.reload + logger.info("User '#{user.login}' created from external auth source: #{user.auth_source.type} - #{user.auth_source.name}") if logger && user.auth_source + end + end + end + user.update_column(:last_login_on, Time.now) if user && !user.new_record? + user + rescue => text + raise text + end + + # Returns the user who matches the given autologin +key+ or nil + def self.try_to_autologin(key) + user = Token.find_active_user('autologin', key, Setting.autologin.to_i) + if user + user.update_column(:last_login_on, Time.now) + user + end + end + + def self.name_formatter(formatter = nil) + USER_FORMATS[formatter || Setting.user_format] || USER_FORMATS[:firstname_lastname] + end + + # Returns an array of fields names than can be used to make an order statement for users + # according to how user names are displayed + # Examples: + # + # User.fields_for_order_statement => ['users.login', 'users.id'] + # User.fields_for_order_statement('authors') => ['authors.login', 'authors.id'] + def self.fields_for_order_statement(table=nil) + table ||= table_name + name_formatter[:order].map {|field| "#{table}.#{field}"} + end + + # Return user's full name for display + def name(formatter = nil) + f = self.class.name_formatter(formatter) + if formatter + eval('"' + f[:string] + '"') + else + @name ||= eval('"' + f[:string] + '"') + end + end + + def active? + self.status == STATUS_ACTIVE + end + + def registered? + self.status == STATUS_REGISTERED + end + + def locked? + self.status == STATUS_LOCKED + end + + def activate + self.status = STATUS_ACTIVE + end + + def register + self.status = STATUS_REGISTERED + end + + def lock + self.status = STATUS_LOCKED + end + + def activate! + update_attribute(:status, STATUS_ACTIVE) + end + + def register! + update_attribute(:status, STATUS_REGISTERED) + end + + def lock! + update_attribute(:status, STATUS_LOCKED) + end + + # Returns true if +clear_password+ is the correct user's password, otherwise false + def check_password?(clear_password) + if auth_source_id.present? + auth_source.authenticate(self.login, clear_password) + else + User.hash_password("#{salt}#{User.hash_password clear_password}") == hashed_password + end + end + + # Generates a random salt and computes hashed_password for +clear_password+ + # The hashed password is stored in the following form: SHA1(salt + SHA1(password)) + def salt_password(clear_password) + self.salt = User.generate_salt + self.hashed_password = User.hash_password("#{salt}#{User.hash_password clear_password}") + end + + # Does the backend storage allow this user to change their password? + def change_password_allowed? + return true if auth_source.nil? + return auth_source.allow_password_changes? + end + + # Generate and set a random password. Useful for automated user creation + # Based on Token#generate_token_value + # + def random_password + chars = ("a".."z").to_a + ("A".."Z").to_a + ("0".."9").to_a + password = '' + 40.times { |i| password << chars[rand(chars.size-1)] } + self.password = password + self.password_confirmation = password + self + end + + def pref + self.preference ||= UserPreference.new(:user => self) + end + + def time_zone + @time_zone ||= (self.pref.time_zone.blank? ? nil : ActiveSupport::TimeZone[self.pref.time_zone]) + end + + def wants_comments_in_reverse_order? + self.pref[:comments_sorting] == 'desc' + end + + # Return user's RSS key (a 40 chars long string), used to access feeds + def rss_key + if rss_token.nil? + create_rss_token(:action => 'feeds') + end + rss_token.value + end + + # Return user's API key (a 40 chars long string), used to access the API + def api_key + if api_token.nil? + create_api_token(:action => 'api') + end + api_token.value + end + + # Return an array of project ids for which the user has explicitly turned mail notifications on + def notified_projects_ids + @notified_projects_ids ||= memberships.select {|m| m.mail_notification?}.collect(&:project_id) + end + + def notified_project_ids=(ids) + Member.update_all("mail_notification = #{connection.quoted_false}", ['user_id = ?', id]) + Member.update_all("mail_notification = #{connection.quoted_true}", ['user_id = ? AND project_id IN (?)', id, ids]) if ids && !ids.empty? + @notified_projects_ids = nil + notified_projects_ids + end + + def valid_notification_options + self.class.valid_notification_options(self) + end + + # Only users that belong to more than 1 project can select projects for which they are notified + def self.valid_notification_options(user=nil) + # Note that @user.membership.size would fail since AR ignores + # :include association option when doing a count + if user.nil? || user.memberships.length < 1 + MAIL_NOTIFICATION_OPTIONS.reject {|option| option.first == 'selected'} + else + MAIL_NOTIFICATION_OPTIONS + end + end + + # Find a user account by matching the exact login and then a case-insensitive + # version. Exact matches will be given priority. + #通过用户名查找相应的用户,若没有匹配到,则不区分大小写进行查询 + def self.find_by_login(login) + if login.present? + login = login.to_s + # First look for an exact match + user = where(:login => login).all.detect {|u| u.login == login} + unless user + # Fail over to case-insensitive if none was found + user = where("LOWER(login) = ?", login.downcase).first + end + user + end + end + + def self.find_by_rss_key(key) + Token.find_active_user('feeds', key) + end + + def self.find_by_api_key(key) + Token.find_active_user('api', key) + end + + # Makes find_by_mail case-insensitive + def self.find_by_mail(mail) + where("LOWER(mail) = ?", mail.to_s.downcase).first + end + + # Returns true if the default admin account can no longer be used + def self.default_admin_account_changed? + !User.active.find_by_login("admin").try(:check_password?, "admin") + end + + def to_s + name + end + + CSS_CLASS_BY_STATUS = { + STATUS_ANONYMOUS => 'anon', + STATUS_ACTIVE => 'active', + STATUS_REGISTERED => 'registered', + STATUS_LOCKED => 'locked' + } + + def css_classes + "user #{CSS_CLASS_BY_STATUS[status]}" + end + + # Returns the current day according to user's time zone + def today + if time_zone.nil? + Date.today + else + Time.now.in_time_zone(time_zone).to_date + end + end + + # Returns the day of +time+ according to user's time zone + def time_to_date(time) + if time_zone.nil? + time.to_date + else + time.in_time_zone(time_zone).to_date + end + end + + def logged? + true + end + + def anonymous? + !logged? + end + + # Returns user's membership for the given project + # or nil if the user is not a member of project + def membership(project) + project_id = project.is_a?(Project) ? project.id : project + + @membership_by_project_id ||= Hash.new {|h, project_id| + h[project_id] = memberships.where(:project_id => project_id).first + } + @membership_by_project_id[project_id] + end + + # Return user's roles for project + def roles_for_project(project) + roles = [] + # No role on archived projects + return roles if project.nil? || project.archived? + if logged? + # Find project membership + membership = membership(project) + if membership + roles = membership.roles + else + @role_non_member ||= Role.non_member + roles << @role_non_member + end + else + @role_anonymous ||= Role.anonymous + roles << @role_anonymous + end + roles + end + + # Return true if the user is a member of project + def member_of?(project) + projects.to_a.include?(project) + end + + # Returns a hash of user's projects grouped by roles + def projects_by_role + return @projects_by_role if @projects_by_role + + @projects_by_role = Hash.new([]) + memberships.each do |membership| + if membership.project + membership.roles.each do |role| + @projects_by_role[role] = [] unless @projects_by_role.key?(role) + @projects_by_role[role] << membership.project + end + end + end + @projects_by_role.each do |role, projects| + projects.uniq! + end + + @projects_by_role + end + + # Returns true if user is arg or belongs to arg + def is_or_belongs_to?(arg) + if arg.is_a?(User) + self == arg + elsif arg.is_a?(Group) + arg.users.include?(self) + else + false + end + end + + # Return true if the user is allowed to do the specified action on a specific context + # Action can be: + # * a parameter-like Hash (eg. :controller => 'projects', :action => 'edit') + # * a permission Symbol (eg. :edit_project) + # Context can be: + # * a project : returns true if user is allowed to do the specified action on this project + # * an array of projects : returns true if user is allowed on every project + # * nil with options[:global] set : check if user has at least one role allowed for this action, + # or falls back to Non Member / Anonymous permissions depending if the user is logged + def allowed_to?(action, context, options={}, &block) + if context && context.is_a?(Project) + return false unless context.allows_to?(action) + # Admin users are authorized for anything else + return true if admin? + + roles = roles_for_project(context) + return false unless roles + roles.any? {|role| + (context.is_public? || role.member?) && + role.allowed_to?(action) && + (block_given? ? yield(role, self) : true) + } + elsif context && context.is_a?(Array) + if context.empty? + false + else + # Authorize if user is authorized on every element of the array + context.map {|project| allowed_to?(action, project, options, &block)}.reduce(:&) + end + elsif options[:global] + # Admin users are always authorized + return true if admin? + + # authorize if user has at least one role that has this permission + roles = memberships.collect {|m| m.roles}.flatten.uniq + roles << (self.logged? ? Role.non_member : Role.anonymous) + roles.any? {|role| + role.allowed_to?(action) && + (block_given? ? yield(role, self) : true) + } + else + false + end + end + + # Is the user allowed to do the specified action on any project? + # See allowed_to? for the actions and valid options. + def allowed_to_globally?(action, options, &block) + allowed_to?(action, nil, options.reverse_merge(:global => true), &block) + end + + # Returns true if the user is allowed to delete his own account + def own_account_deletable? + Setting.unsubscribe? && + (!admin? || User.active.where("admin = ? AND id <> ?", true, id).exists?) + end + + safe_attributes 'login', + 'firstname', + 'lastname', + 'mail', + 'mail_notification', + 'language', + 'custom_field_values', + 'custom_fields', + 'identity_url' + + safe_attributes 'status', + 'auth_source_id', + :if => lambda {|user, current_user| current_user.admin?} + + safe_attributes 'group_ids', + :if => lambda {|user, current_user| current_user.admin? && !user.new_record?} + + # Utility method to help check if a user should be notified about an + # event. + # + # TODO: only supports Issue events currently + def notify_about?(object) + if mail_notification == 'all' + true + elsif mail_notification.blank? || mail_notification == 'none' + false + else + case object + when Issue + case mail_notification + when 'selected', 'only_my_events' + # user receives notifications for created/assigned issues on unselected projects + object.author == self || is_or_belongs_to?(object.assigned_to) || is_or_belongs_to?(object.assigned_to_was) + when 'only_assigned' + is_or_belongs_to?(object.assigned_to) || is_or_belongs_to?(object.assigned_to_was) + when 'only_owner' + object.author == self + end + when News + # always send to project members except when mail_notification is set to 'none' + true + end + end + end + + def self.current=(user) + Thread.current[:current_user] = user + end + + def self.current + Thread.current[:current_user] ||= User.anonymous + end + + # Returns the anonymous user. If the anonymous user does not exist, it is created. There can be only + # one anonymous user per database. + def self.anonymous + anonymous_user = AnonymousUser.first + if anonymous_user.nil? + anonymous_user = AnonymousUser.create(:lastname => 'Anonymous', :firstname => '', :mail => '', :login => '', :status => 0) + raise 'Unable to create the anonymous user.' if anonymous_user.new_record? + end + anonymous_user + end + + # Salts all existing unsalted passwords + # It changes password storage scheme from SHA1(password) to SHA1(salt + SHA1(password)) + # This method is used in the SaltPasswords migration and is to be kept as is + def self.salt_unsalted_passwords! + transaction do + User.where("salt IS NULL OR salt = ''").find_each do |user| + next if user.hashed_password.blank? + salt = User.generate_salt + hashed_password = User.hash_password("#{salt}#{user.hashed_password}") + User.where(:id => user.id).update_all(:salt => salt, :hashed_password => hashed_password) + end + end + end + + protected + + def validate_password_length + # Password length validation based on setting + if !password.nil? && password.size < Setting.password_min_length.to_i + errors.add(:password, :too_short, :count => Setting.password_min_length.to_i) + end + end + + private + + # Removes references that are not handled by associations + # Things that are not deleted are reassociated with the anonymous user + def remove_references_before_destroy + return if self.id.nil? + + substitute = User.anonymous + Attachment.update_all ['author_id = ?', substitute.id], ['author_id = ?', id] + Comment.update_all ['author_id = ?', substitute.id], ['author_id = ?', id] + Issue.update_all ['author_id = ?', substitute.id], ['author_id = ?', id] + Issue.update_all 'assigned_to_id = NULL', ['assigned_to_id = ?', id] + Journal.update_all ['user_id = ?', substitute.id], ['user_id = ?', id] + JournalDetail.update_all ['old_value = ?', substitute.id.to_s], ["property = 'attr' AND prop_key = 'assigned_to_id' AND old_value = ?", id.to_s] + JournalDetail.update_all ['value = ?', substitute.id.to_s], ["property = 'attr' AND prop_key = 'assigned_to_id' AND value = ?", id.to_s] + Message.update_all ['author_id = ?', substitute.id], ['author_id = ?', id] + News.update_all ['author_id = ?', substitute.id], ['author_id = ?', id] + # Remove private queries and keep public ones + ::Query.delete_all ['user_id = ? AND is_public = ?', id, false] + ::Query.update_all ['user_id = ?', substitute.id], ['user_id = ?', id] + TimeEntry.update_all ['user_id = ?', substitute.id], ['user_id = ?', id] + Token.delete_all ['user_id = ?', id] + Watcher.delete_all ['user_id = ?', id] + WikiContent.update_all ['author_id = ?', substitute.id], ['author_id = ?', id] + WikiContent::Version.update_all ['author_id = ?', substitute.id], ['author_id = ?', id] + end + + # Return password digest + def self.hash_password(clear_password) + Digest::SHA1.hexdigest(clear_password || "") + end + + # Returns a 128bits random salt as a hex string (32 chars long) + def self.generate_salt + Redmine::Utils.random_hex(16) + end + +end + +class AnonymousUser < User + validate :validate_anonymous_uniqueness, :on => :create + + def validate_anonymous_uniqueness + # There should be only one AnonymousUser in the database + errors.add :base, 'An anonymous user already exists.' if AnonymousUser.exists? + end + + def available_custom_fields + [] + end + + # Overrides a few properties + def logged?; false end + def admin; false end + def name(*args); I18n.t(:label_user_anonymous) end + def mail; nil end + def time_zone; nil end + def rss_key; nil end + + def pref + UserPreference.new(:user => self) + end + + # def member_of?(project) + # false + # end + + # Anonymous user can not be destroyed + def destroy + false + end +end diff --git a/app/models/user_custom_field.rb b/app/models/user_custom_field.rb new file mode 100644 index 00000000..bbcb957d --- /dev/null +++ b/app/models/user_custom_field.rb @@ -0,0 +1,23 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class UserCustomField < CustomField + def type_name + :label_user_plural + end +end + diff --git a/app/models/user_extension.rb b/app/models/user_extension.rb new file mode 100644 index 00000000..cdfad28c --- /dev/null +++ b/app/models/user_extension.rb @@ -0,0 +1,11 @@ +class UserExtension < ActiveRecord::Base + attr_accessible :birthday, :brief_introduction, :fans_num, :finish_project_num, :follow_num, :gender, :good_num, :location, :occupation, :publish_requirement_num, :user_id, :work_experience, :zip_code + + belongs_to :user + validate :validate_user + + def validate_user + errors.add :user_id, :invalid if user.nil? || !user.active? || User.current != user_id + end + +end diff --git a/app/models/user_preference.rb b/app/models/user_preference.rb new file mode 100644 index 00000000..5b95386b --- /dev/null +++ b/app/models/user_preference.rb @@ -0,0 +1,59 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class UserPreference < ActiveRecord::Base + belongs_to :user + serialize :others + + attr_protected :others, :user_id + + before_save :set_others_hash + + def initialize(attributes=nil, *args) + super + self.others ||= {} + end + + def set_others_hash + self.others ||= {} + end + + def [](attr_name) + if attribute_present? attr_name + super + else + others ? others[attr_name] : nil + end + end + + def []=(attr_name, value) + if attribute_present? attr_name + super + else + h = (read_attribute(:others) || {}).dup + h.update(attr_name => value) + write_attribute(:others, h) + value + end + end + + def comments_sorting; self[:comments_sorting] end + def comments_sorting=(order); self[:comments_sorting]=order end + + def warn_on_leaving_unsaved; self[:warn_on_leaving_unsaved] || '1'; end + def warn_on_leaving_unsaved=(value); self[:warn_on_leaving_unsaved]=value; end +end diff --git a/app/models/version.rb b/app/models/version.rb new file mode 100644 index 00000000..0e11371a --- /dev/null +++ b/app/models/version.rb @@ -0,0 +1,289 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class Version < ActiveRecord::Base + include Redmine::SafeAttributes + after_update :update_issues_from_sharing_change + belongs_to :project + has_many :fixed_issues, :class_name => 'Issue', :foreign_key => 'fixed_version_id', :dependent => :nullify + acts_as_customizable + acts_as_attachable :view_permission => :view_files, + :delete_permission => :manage_files + + VERSION_STATUSES = %w(open locked closed) + VERSION_SHARINGS = %w(none descendants hierarchy tree system) + + validates_presence_of :name + validates_uniqueness_of :name, :scope => [:project_id] + validates_length_of :name, :maximum => 60 + validates :effective_date, :date => true + validates_inclusion_of :status, :in => VERSION_STATUSES + validates_inclusion_of :sharing, :in => VERSION_SHARINGS + + scope :named, lambda {|arg| where("LOWER(#{table_name}.name) = LOWER(?)", arg.to_s.strip)} + scope :open, lambda { where(:status => 'open') } + scope :visible, lambda {|*args| + includes(:project).where(Project.allowed_to_condition(args.first || User.current, :view_issues)) + } + + safe_attributes 'name', + 'description', + 'effective_date', + 'due_date', + 'wiki_page_title', + 'status', + 'sharing', + 'custom_field_values' + + # Returns true if +user+ or current user is allowed to view the version + def visible?(user=User.current) + user.allowed_to?(:view_issues, self.project) + end + + # Version files have same visibility as project files + def attachments_visible?(*args) + project.present? && project.attachments_visible?(*args) + end + + def start_date + @start_date ||= fixed_issues.minimum('start_date') + end + + def due_date + effective_date + end + + def due_date=(arg) + self.effective_date=(arg) + end + + # Returns the total estimated time for this version + # (sum of leaves estimated_hours) + def estimated_hours + @estimated_hours ||= fixed_issues.leaves.sum(:estimated_hours).to_f + end + + # Returns the total reported time for this version + def spent_hours + @spent_hours ||= TimeEntry.joins(:issue).where("#{Issue.table_name}.fixed_version_id = ?", id).sum(:hours).to_f + end + + def closed? + status == 'closed' + end + + def open? + status == 'open' + end + + # Returns true if the version is completed: due date reached and no open issues + def completed? + effective_date && (effective_date < Date.today) && (open_issues_count == 0) + end + + def behind_schedule? + if completed_percent == 100 + return false + elsif due_date && start_date + done_date = start_date + ((due_date - start_date+1)* completed_percent/100).floor + return done_date <= Date.today + else + false # No issues so it's not late + end + end + + # Returns the completion percentage of this version based on the amount of open/closed issues + # and the time spent on the open issues. + def completed_percent + if issues_count == 0 + 0 + elsif open_issues_count == 0 + 100 + else + issues_progress(false) + issues_progress(true) + end + end + + # TODO: remove in Redmine 3.0 + def completed_pourcent + ActiveSupport::Deprecation.warn "Version#completed_pourcent is deprecated and will be removed in Redmine 3.0. Please use #completed_percent instead." + completed_percent + end + + # Returns the percentage of issues that have been marked as 'closed'. + def closed_percent + if issues_count == 0 + 0 + else + issues_progress(false) + end + end + + # TODO: remove in Redmine 3.0 + def closed_pourcent + ActiveSupport::Deprecation.warn "Version#closed_pourcent is deprecated and will be removed in Redmine 3.0. Please use #closed_percent instead." + closed_percent + end + + # Returns true if the version is overdue: due date reached and some open issues + def overdue? + effective_date && (effective_date < Date.today) && (open_issues_count > 0) + end + + # Returns assigned issues count + def issues_count + load_issue_counts + @issue_count + end + + # Returns the total amount of open issues for this version. + def open_issues_count + load_issue_counts + @open_issues_count + end + + # Returns the total amount of closed issues for this version. + def closed_issues_count + load_issue_counts + @closed_issues_count + end + + def wiki_page + if project.wiki && !wiki_page_title.blank? + @wiki_page ||= project.wiki.find_page(wiki_page_title) + end + @wiki_page + end + + def to_s; name end + + def to_s_with_project + "#{project} - #{name}" + end + + # Versions are sorted by effective_date and name + # Those with no effective_date are at the end, sorted by name + def <=>(version) + if self.effective_date + if version.effective_date + if self.effective_date == version.effective_date + name == version.name ? id <=> version.id : name <=> version.name + else + self.effective_date <=> version.effective_date + end + else + -1 + end + else + if version.effective_date + 1 + else + name == version.name ? id <=> version.id : name <=> version.name + end + end + end + + def self.fields_for_order_statement(table=nil) + table ||= table_name + ["(CASE WHEN #{table}.effective_date IS NULL THEN 1 ELSE 0 END)", "#{table}.effective_date", "#{table}.name", "#{table}.id"] + end + + scope :sorted, order(fields_for_order_statement) + + # Returns the sharings that +user+ can set the version to + def allowed_sharings(user = User.current) + VERSION_SHARINGS.select do |s| + if sharing == s + true + else + case s + when 'system' + # Only admin users can set a systemwide sharing + user.admin? + when 'hierarchy', 'tree' + # Only users allowed to manage versions of the root project can + # set sharing to hierarchy or tree + project.nil? || user.allowed_to?(:manage_versions, project.root) + else + true + end + end + end + end + + private + + def load_issue_counts + unless @issue_count + @open_issues_count = 0 + @closed_issues_count = 0 + fixed_issues.count(:all, :group => :status).each do |status, count| + if status.is_closed? + @closed_issues_count += count + else + @open_issues_count += count + end + end + @issue_count = @open_issues_count + @closed_issues_count + end + end + + # Update the issue's fixed versions. Used if a version's sharing changes. + def update_issues_from_sharing_change + if sharing_changed? + if VERSION_SHARINGS.index(sharing_was).nil? || + VERSION_SHARINGS.index(sharing).nil? || + VERSION_SHARINGS.index(sharing_was) > VERSION_SHARINGS.index(sharing) + Issue.update_versions_from_sharing_change self + end + end + end + + # Returns the average estimated time of assigned issues + # or 1 if no issue has an estimated time + # Used to weigth unestimated issues in progress calculation + def estimated_average + if @estimated_average.nil? + average = fixed_issues.average(:estimated_hours).to_f + if average == 0 + average = 1 + end + @estimated_average = average + end + @estimated_average + end + + # Returns the total progress of open or closed issues. The returned percentage takes into account + # the amount of estimated time set for this version. + # + # Examples: + # issues_progress(true) => returns the progress percentage for open issues. + # issues_progress(false) => returns the progress percentage for closed issues. + def issues_progress(open) + @issues_progress ||= {} + @issues_progress[open] ||= begin + progress = 0 + if issues_count > 0 + ratio = open ? 'done_ratio' : 100 + + done = fixed_issues.open(open).sum("COALESCE(estimated_hours, #{estimated_average}) * #{ratio}").to_f + progress = done / (estimated_average * issues_count) + end + progress + end + end +end diff --git a/app/models/version_custom_field.rb b/app/models/version_custom_field.rb new file mode 100644 index 00000000..12bdbdf3 --- /dev/null +++ b/app/models/version_custom_field.rb @@ -0,0 +1,22 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class VersionCustomField < CustomField + def type_name + :label_version_plural + end +end diff --git a/app/models/watcher.rb b/app/models/watcher.rb new file mode 100644 index 00000000..1cea711b --- /dev/null +++ b/app/models/watcher.rb @@ -0,0 +1,66 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class Watcher < ActiveRecord::Base + belongs_to :watchable, :polymorphic => true + belongs_to :user + + validates_presence_of :user + validates_uniqueness_of :user_id, :scope => [:watchable_type, :watchable_id] + validate :validate_user + + # Unwatch things that users are no longer allowed to view + def self.prune(options={}) + if options.has_key?(:user) + prune_single_user(options[:user], options) + else + pruned = 0 + User.where("id IN (SELECT DISTINCT user_id FROM #{table_name})").all.each do |user| + pruned += prune_single_user(user, options) + end + pruned + end + end + + protected + + def validate_user + errors.add :user_id, :invalid unless user.nil? || user.active? + end + + private + + def self.prune_single_user(user, options={}) + return unless user.is_a?(User) + pruned = 0 + where(:user_id => user.id).all.each do |watcher| + next if watcher.watchable.nil? + + if options.has_key?(:project) + next unless watcher.watchable.respond_to?(:project) && watcher.watchable.project == options[:project] + end + + if watcher.watchable.respond_to?(:visible?) + unless watcher.watchable.visible?(user) + watcher.destroy + pruned += 1 + end + end + end + pruned + end +end diff --git a/app/models/watchers_of_projects.rb b/app/models/watchers_of_projects.rb new file mode 100644 index 00000000..53aca680 --- /dev/null +++ b/app/models/watchers_of_projects.rb @@ -0,0 +1,46 @@ +class WatchersOfProjects < ActiveRecord::Base + attr_accessible :project_id, :user_id + belongs_to :project + belongs_to :user + + validate :validate_user + validate :validate_project + validates_uniqueness_of :user_id, :scope => :project_id + validates_presence_of :user_id, :project_id + + def self.watch(user_id, project_id) + @new_watch = WatchersOfProjects.new + @new_watch.user_id = user_id + @new_watch.project_id = project_id + @new_watch.save + true + end + + def self.watcher_count(project) + @project = project + @count = @project.watchers_of_projects.count + @count + end + + def self.is_watched(user_id, project_id) + @is_watched = self.where("user_id = ? and project_id = ?", user_id, project_id).to_a.first + if @is_watched.nil? + false + else + true + end + end + + def self.watch_cancle(user_id, project_id) + self.delete_all(["user_id = ? and project_id = ?", user_id, project_id]) + true + end + + def validate_user + errors.add :user_id, :invalid if user.nil? || !user.active? + end + + def validate_project + errors.add :project_id, :invalid if project.nil? + end +end diff --git a/app/models/watchers_of_user.rb b/app/models/watchers_of_user.rb new file mode 100644 index 00000000..cf205b1d --- /dev/null +++ b/app/models/watchers_of_user.rb @@ -0,0 +1,65 @@ +class WatchersOfUser < ActiveRecord::Base + attr_accessible :user_id, :watcher_id + belongs_to :user + + validates_uniqueness_of :watcher_id, :scope => :user_id + validate :validate_user + validate :validate_watcher + validates_presence_of :watcher_id, :user_id + + def self.watch_user(watcher_id, user_id) + unless user_id == watcher_id + @watchers_of_user = WatchersOfUser.new + @watchers_of_user.watcher_id = watcher_id + @watchers_of_user.user_id = user_id + @watchers_of_user.save + true + else + false + end + end + + def cancel_watching_user + self.class.cancel_watching_user(self.watcher_id, self.user_id) + end + + def self.cancel_watching_user(watcher_id, user_id) + self.delete_all(["user_id = ? and watcher_id = ?", user_id, watcher_id]) + true + end + + def self.find_users(watcher_id) + @user = WatchersOfUser.find_by_sql("select * from users where id in (select user_id from #{WatchersOfUser.table_name} where watcher_id = #{watcher_id})") + @user + # @watch_table_for_user=WatchersOfUser.where(:watcher_id => watcher_id) + # @user = [] + # @watch_table_for_user.each do |watch| + # @user.push(watch.user) + # end + # @user + end + + def self.find_watchers(user_id) + @watcher = WatchersOfUser.find_by_sql("select * from users where id in (select watcher_id from #{WatchersOfUser.table_name} where user_id = #{user_id})") + @watcher + # user = User.find(user_id) + # @watch_table_for_watcher = user.watchers_of_users + # @watcher = [] + # @watch_table_for_watcher.each do |watch| + # user_temp = User.find(watch.watcher_id) + # @watcher.push(user_temp) + # end + # @watcher + end + + #验证user是否存在 + def validate_user + errors.add :user_id, :invalid if user.nil? || !user.active? + end + + #验证watcher是否存在 + def validate_watcher + user = User.where("id = ?", watcher_id).to_a.first + errors.add :watcher_id, :invalid if user.nil? || !user.active? + end +end diff --git a/app/models/wiki.rb b/app/models/wiki.rb new file mode 100644 index 00000000..d58212d6 --- /dev/null +++ b/app/models/wiki.rb @@ -0,0 +1,97 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class Wiki < ActiveRecord::Base + include Redmine::SafeAttributes + belongs_to :project + has_many :pages, :class_name => 'WikiPage', :dependent => :destroy, :order => 'title' + has_many :redirects, :class_name => 'WikiRedirect', :dependent => :delete_all + + acts_as_watchable + + validates_presence_of :start_page + validates_format_of :start_page, :with => /\A[^,\.\/\?\;\|\:]*\z/ + + safe_attributes 'start_page' + + def visible?(user=User.current) + !user.nil? && user.allowed_to?(:view_wiki_pages, project) + end + + # Returns the wiki page that acts as the sidebar content + # or nil if no such page exists + def sidebar + @sidebar ||= find_page('Sidebar', :with_redirect => false) + end + + # find the page with the given title + # if page doesn't exist, return a new page + def find_or_new_page(title) + title = start_page if title.blank? + find_page(title) || WikiPage.new(:wiki => self, :title => Wiki.titleize(title)) + end + + # find the page with the given title + def find_page(title, options = {}) + @page_found_with_redirect = false + title = start_page if title.blank? + title = Wiki.titleize(title) + page = pages.first(:conditions => ["LOWER(title) = LOWER(?)", title]) + if !page && !(options[:with_redirect] == false) + # search for a redirect + redirect = redirects.first(:conditions => ["LOWER(title) = LOWER(?)", title]) + if redirect + page = find_page(redirect.redirects_to, :with_redirect => false) + @page_found_with_redirect = true + end + end + page + end + + # Returns true if the last page was found with a redirect + def page_found_with_redirect? + @page_found_with_redirect + end + + # Finds a page by title + # The given string can be of one of the forms: "title" or "project:title" + # Examples: + # Wiki.find_page("bar", project => foo) + # Wiki.find_page("foo:bar") + def self.find_page(title, options = {}) + project = options[:project] + if title.to_s =~ %r{^([^\:]+)\:(.*)$} + project_identifier, title = $1, $2 + project = Project.find_by_identifier(project_identifier) || Project.find_by_name(project_identifier) + end + if project && project.wiki + page = project.wiki.find_page(title) + if page && page.content + page + end + end + end + + # turn a string into a valid page title + def self.titleize(title) + # replace spaces with _ and remove unwanted caracters + title = title.gsub(/\s+/, '_').delete(',./?;|:') if title + # upcase the first letter + title = (title.slice(0..0).upcase + (title.slice(1..-1) || '')) if title + title + end +end diff --git a/app/models/wiki_content.rb b/app/models/wiki_content.rb new file mode 100644 index 00000000..a9ed005b --- /dev/null +++ b/app/models/wiki_content.rb @@ -0,0 +1,148 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +require 'zlib' + +class WikiContent < ActiveRecord::Base + self.locking_column = 'version' + belongs_to :page, :class_name => 'WikiPage', :foreign_key => 'page_id' + belongs_to :author, :class_name => 'User', :foreign_key => 'author_id' + validates_presence_of :text + validates_length_of :comments, :maximum => 255, :allow_nil => true + + acts_as_versioned + + def visible?(user=User.current) + page.visible?(user) + end + + def project + page.project + end + + def attachments + page.nil? ? [] : page.attachments + end + + # Returns the mail adresses of users that should be notified + def recipients + notified = project.notified_users + notified.reject! {|user| !visible?(user)} + notified.collect(&:mail) + end + + # Return true if the content is the current page content + def current_version? + true + end + + class Version + belongs_to :page, :class_name => '::WikiPage', :foreign_key => 'page_id' + belongs_to :author, :class_name => '::User', :foreign_key => 'author_id' + attr_protected :data + + acts_as_event :title => Proc.new {|o| "#{l(:label_wiki_edit)}: #{o.page.title} (##{o.version})"}, + :description => :comments, + :datetime => :updated_on, + :type => 'wiki-page', + :group => :page, + :url => Proc.new {|o| {:controller => 'wiki', :action => 'show', :project_id => o.page.wiki.project, :id => o.page.title, :version => o.version}} + + acts_as_activity_provider :type => 'wiki_edits', + :timestamp => "#{WikiContent.versioned_table_name}.updated_on", + :author_key => "#{WikiContent.versioned_table_name}.author_id", + :permission => :view_wiki_edits, + :find_options => {:select => "#{WikiContent.versioned_table_name}.updated_on, #{WikiContent.versioned_table_name}.comments, " + + "#{WikiContent.versioned_table_name}.#{WikiContent.version_column}, #{WikiPage.table_name}.title, " + + "#{WikiContent.versioned_table_name}.page_id, #{WikiContent.versioned_table_name}.author_id, " + + "#{WikiContent.versioned_table_name}.id", + :joins => "LEFT JOIN #{WikiPage.table_name} ON #{WikiPage.table_name}.id = #{WikiContent.versioned_table_name}.page_id " + + "LEFT JOIN #{Wiki.table_name} ON #{Wiki.table_name}.id = #{WikiPage.table_name}.wiki_id " + + "LEFT JOIN #{Project.table_name} ON #{Project.table_name}.id = #{Wiki.table_name}.project_id"} + + after_destroy :page_update_after_destroy + + def text=(plain) + case Setting.wiki_compression + when 'gzip' + begin + self.data = Zlib::Deflate.deflate(plain, Zlib::BEST_COMPRESSION) + self.compression = 'gzip' + rescue + self.data = plain + self.compression = '' + end + else + self.data = plain + self.compression = '' + end + plain + end + + def text + @text ||= begin + str = case compression + when 'gzip' + Zlib::Inflate.inflate(data) + else + # uncompressed data + data + end + str.force_encoding("UTF-8") if str.respond_to?(:force_encoding) + str + end + end + + def project + page.project + end + + # Return true if the content is the current page content + def current_version? + page.content.version == self.version + end + + # Returns the previous version or nil + def previous + @previous ||= WikiContent::Version. + reorder('version DESC'). + includes(:author). + where("wiki_content_id = ? AND version < ?", wiki_content_id, version).first + end + + # Returns the next version or nil + def next + @next ||= WikiContent::Version. + reorder('version ASC'). + includes(:author). + where("wiki_content_id = ? AND version > ?", wiki_content_id, version).first + end + + private + + # Updates page's content if the latest version is removed + # or destroys the page if it was the only version + def page_update_after_destroy + latest = page.content.versions.reorder("#{self.class.table_name}.version DESC").first + if latest && page.content.version != latest.version + raise ActiveRecord::Rollback unless page.content.revert_to!(latest) + elsif latest.nil? + raise ActiveRecord::Rollback unless page.destroy + end + end + end +end diff --git a/app/models/wiki_content_observer.rb b/app/models/wiki_content_observer.rb new file mode 100644 index 00000000..6219f407 --- /dev/null +++ b/app/models/wiki_content_observer.rb @@ -0,0 +1,28 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class WikiContentObserver < ActiveRecord::Observer + def after_create(wiki_content) + Mailer.wiki_content_added(wiki_content).deliver if Setting.notified_events.include?('wiki_content_added') + end + + def after_update(wiki_content) + if wiki_content.text_changed? + Mailer.wiki_content_updated(wiki_content).deliver if Setting.notified_events.include?('wiki_content_updated') + end + end +end diff --git a/app/models/wiki_page.rb b/app/models/wiki_page.rb new file mode 100644 index 00000000..c17fa75d --- /dev/null +++ b/app/models/wiki_page.rb @@ -0,0 +1,251 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +require 'diff' +require 'enumerator' + +class WikiPage < ActiveRecord::Base + include Redmine::SafeAttributes + + belongs_to :wiki + has_one :content, :class_name => 'WikiContent', :foreign_key => 'page_id', :dependent => :destroy + acts_as_attachable :delete_permission => :delete_wiki_pages_attachments + acts_as_tree :dependent => :nullify, :order => 'title' + + acts_as_watchable + acts_as_event :title => Proc.new {|o| "#{l(:label_wiki)}: #{o.title}"}, + :description => :text, + :datetime => :created_on, + :url => Proc.new {|o| {:controller => 'wiki', :action => 'show', :project_id => o.wiki.project, :id => o.title}} + + acts_as_searchable :columns => ['title', "#{WikiContent.table_name}.text"], + :include => [{:wiki => :project}, :content], + :permission => :view_wiki_pages, + :project_key => "#{Wiki.table_name}.project_id" + + attr_accessor :redirect_existing_links + + validates_presence_of :title + validates_format_of :title, :with => /\A[^,\.\/\?\;\|\s]*\z/ + validates_uniqueness_of :title, :scope => :wiki_id, :case_sensitive => false + validates_associated :content + + validate :validate_parent_title + before_destroy :remove_redirects + before_save :handle_redirects + + # eager load information about last updates, without loading text + scope :with_updated_on, lambda { + select("#{WikiPage.table_name}.*, #{WikiContent.table_name}.updated_on, #{WikiContent.table_name}.version"). + joins("LEFT JOIN #{WikiContent.table_name} ON #{WikiContent.table_name}.page_id = #{WikiPage.table_name}.id") + } + + # Wiki pages that are protected by default + DEFAULT_PROTECTED_PAGES = %w(sidebar) + + safe_attributes 'parent_id', 'parent_title', + :if => lambda {|page, user| page.new_record? || user.allowed_to?(:rename_wiki_pages, page.project)} + + def initialize(attributes=nil, *args) + super + if new_record? && DEFAULT_PROTECTED_PAGES.include?(title.to_s.downcase) + self.protected = true + end + end + + def visible?(user=User.current) + !user.nil? && user.allowed_to?(:view_wiki_pages, project) + end + + def title=(value) + value = Wiki.titleize(value) + @previous_title = read_attribute(:title) if @previous_title.blank? + write_attribute(:title, value) + end + + def handle_redirects + self.title = Wiki.titleize(title) + # Manage redirects if the title has changed + if !@previous_title.blank? && (@previous_title != title) && !new_record? + # Update redirects that point to the old title + wiki.redirects.find_all_by_redirects_to(@previous_title).each do |r| + r.redirects_to = title + r.title == r.redirects_to ? r.destroy : r.save + end + # Remove redirects for the new title + wiki.redirects.find_all_by_title(title).each(&:destroy) + # Create a redirect to the new title + wiki.redirects << WikiRedirect.new(:title => @previous_title, :redirects_to => title) unless redirect_existing_links == "0" + @previous_title = nil + end + end + + def remove_redirects + # Remove redirects to this page + wiki.redirects.find_all_by_redirects_to(title).each(&:destroy) + end + + def pretty_title + WikiPage.pretty_title(title) + end + + def content_for_version(version=nil) + result = content.versions.find_by_version(version.to_i) if version + result ||= content + result + end + + def diff(version_to=nil, version_from=nil) + version_to = version_to ? version_to.to_i : self.content.version + content_to = content.versions.find_by_version(version_to) + content_from = version_from ? content.versions.find_by_version(version_from.to_i) : content_to.try(:previous) + return nil unless content_to && content_from + + if content_from.version > content_to.version + content_to, content_from = content_from, content_to + end + + (content_to && content_from) ? WikiDiff.new(content_to, content_from) : nil + end + + def annotate(version=nil) + version = version ? version.to_i : self.content.version + c = content.versions.find_by_version(version) + c ? WikiAnnotate.new(c) : nil + end + + def self.pretty_title(str) + (str && str.is_a?(String)) ? str.tr('_', ' ') : str + end + + def project + wiki.project + end + + def text + content.text if content + end + + def updated_on + unless @updated_on + if time = read_attribute(:updated_on) + # content updated_on was eager loaded with the page + begin + @updated_on = (self.class.default_timezone == :utc ? Time.parse(time.to_s).utc : Time.parse(time.to_s).localtime) + rescue + end + else + @updated_on = content && content.updated_on + end + end + @updated_on + end + + # Returns true if usr is allowed to edit the page, otherwise false + def editable_by?(usr) + !protected? || usr.allowed_to?(:protect_wiki_pages, wiki.project) + end + + def attachments_deletable?(usr=User.current) + editable_by?(usr) && super(usr) + end + + def parent_title + @parent_title || (self.parent && self.parent.pretty_title) + end + + def parent_title=(t) + @parent_title = t + parent_page = t.blank? ? nil : self.wiki.find_page(t) + self.parent = parent_page + end + + # Saves the page and its content if text was changed + def save_with_content + ret = nil + transaction do + if new_record? + # Rails automatically saves associated content + ret = save + else + ret = save && (content.text_changed? ? content.save : true) + end + raise ActiveRecord::Rollback unless ret + end + ret + end + + protected + + def validate_parent_title + errors.add(:parent_title, :invalid) if !@parent_title.blank? && parent.nil? + errors.add(:parent_title, :circular_dependency) if parent && (parent == self || parent.ancestors.include?(self)) + errors.add(:parent_title, :not_same_project) if parent && (parent.wiki_id != wiki_id) + end +end + +class WikiDiff < Redmine::Helpers::Diff + attr_reader :content_to, :content_from + + def initialize(content_to, content_from) + @content_to = content_to + @content_from = content_from + super(content_to.text, content_from.text) + end +end + +class WikiAnnotate + attr_reader :lines, :content + + def initialize(content) + @content = content + current = content + current_lines = current.text.split(/\r?\n/) + @lines = current_lines.collect {|t| [nil, nil, t]} + positions = [] + current_lines.size.times {|i| positions << i} + while (current.previous) + d = current.previous.text.split(/\r?\n/).diff(current.text.split(/\r?\n/)).diffs.flatten + d.each_slice(3) do |s| + sign, line = s[0], s[1] + if sign == '+' && positions[line] && positions[line] != -1 + if @lines[positions[line]][0].nil? + @lines[positions[line]][0] = current.version + @lines[positions[line]][1] = current.author + end + end + end + d.each_slice(3) do |s| + sign, line = s[0], s[1] + if sign == '-' + positions.insert(line, -1) + else + positions[line] = nil + end + end + positions.compact! + # Stop if every line is annotated + break unless @lines.detect { |line| line[0].nil? } + current = current.previous + end + @lines.each { |line| + line[0] ||= current.version + # if the last known version is > 1 (eg. history was cleared), we don't know the author + line[1] ||= current.author if current.version == 1 + } + end +end diff --git a/app/models/wiki_redirect.rb b/app/models/wiki_redirect.rb new file mode 100644 index 00000000..da92abb9 --- /dev/null +++ b/app/models/wiki_redirect.rb @@ -0,0 +1,23 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class WikiRedirect < ActiveRecord::Base + belongs_to :wiki + + validates_presence_of :title, :redirects_to + validates_length_of :title, :redirects_to, :maximum => 255 +end diff --git a/app/models/workflow_permission.rb b/app/models/workflow_permission.rb new file mode 100644 index 00000000..c6c0f19d --- /dev/null +++ b/app/models/workflow_permission.rb @@ -0,0 +1,45 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class WorkflowPermission < WorkflowRule + validates_inclusion_of :rule, :in => %w(readonly required) + validate :validate_field_name + + # Replaces the workflow permissions for the given tracker and role + # + # Example: + # WorkflowPermission.replace_permissions role, tracker, {'due_date' => {'1' => 'readonly', '2' => 'required'}} + def self.replace_permissions(tracker, role, permissions) + destroy_all(:tracker_id => tracker.id, :role_id => role.id) + + permissions.each { |field, rule_by_status_id| + rule_by_status_id.each { |status_id, rule| + if rule.present? + WorkflowPermission.create(:role_id => role.id, :tracker_id => tracker.id, :old_status_id => status_id, :field_name => field, :rule => rule) + end + } + } + end + + protected + + def validate_field_name + unless Tracker::CORE_FIELDS_ALL.include?(field_name) || field_name.to_s.match(/^\d+$/) + errors.add :field_name, :invalid + end + end +end diff --git a/app/models/workflow_rule.rb b/app/models/workflow_rule.rb new file mode 100644 index 00000000..14e186f1 --- /dev/null +++ b/app/models/workflow_rule.rb @@ -0,0 +1,73 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class WorkflowRule < ActiveRecord::Base + self.table_name = "#{table_name_prefix}workflows#{table_name_suffix}" + + belongs_to :role + belongs_to :tracker + belongs_to :old_status, :class_name => 'IssueStatus', :foreign_key => 'old_status_id' + belongs_to :new_status, :class_name => 'IssueStatus', :foreign_key => 'new_status_id' + + validates_presence_of :role, :tracker, :old_status + + # Copies workflows from source to targets + def self.copy(source_tracker, source_role, target_trackers, target_roles) + unless source_tracker.is_a?(Tracker) || source_role.is_a?(Role) + raise ArgumentError.new("source_tracker or source_role must be specified") + end + + target_trackers = [target_trackers].flatten.compact + target_roles = [target_roles].flatten.compact + + target_trackers = Tracker.sorted.all if target_trackers.empty? + target_roles = Role.all if target_roles.empty? + + target_trackers.each do |target_tracker| + target_roles.each do |target_role| + copy_one(source_tracker || target_tracker, + source_role || target_role, + target_tracker, + target_role) + end + end + end + + # Copies a single set of workflows from source to target + def self.copy_one(source_tracker, source_role, target_tracker, target_role) + unless source_tracker.is_a?(Tracker) && !source_tracker.new_record? && + source_role.is_a?(Role) && !source_role.new_record? && + target_tracker.is_a?(Tracker) && !target_tracker.new_record? && + target_role.is_a?(Role) && !target_role.new_record? + + raise ArgumentError.new("arguments can not be nil or unsaved objects") + end + + if source_tracker == target_tracker && source_role == target_role + false + else + transaction do + delete_all :tracker_id => target_tracker.id, :role_id => target_role.id + connection.insert "INSERT INTO #{WorkflowRule.table_name} (tracker_id, role_id, old_status_id, new_status_id, author, assignee, field_name, #{connection.quote_column_name 'rule'}, type)" + + " SELECT #{target_tracker.id}, #{target_role.id}, old_status_id, new_status_id, author, assignee, field_name, #{connection.quote_column_name 'rule'}, type" + + " FROM #{WorkflowRule.table_name}" + + " WHERE tracker_id = #{source_tracker.id} AND role_id = #{source_role.id}" + end + true + end + end +end diff --git a/app/models/workflow_transition.rb b/app/models/workflow_transition.rb new file mode 100644 index 00000000..a8fd545a --- /dev/null +++ b/app/models/workflow_transition.rb @@ -0,0 +1,39 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class WorkflowTransition < WorkflowRule + validates_presence_of :new_status + + # Returns workflow transitions count by tracker and role + def self.count_by_tracker_and_role + counts = connection.select_all("SELECT role_id, tracker_id, count(id) AS c FROM #{table_name} WHERE type = 'WorkflowTransition' GROUP BY role_id, tracker_id") + roles = Role.sorted.all + trackers = Tracker.sorted.all + + result = [] + trackers.each do |tracker| + t = [] + roles.each do |role| + row = counts.detect {|c| c['role_id'].to_s == role.id.to_s && c['tracker_id'].to_s == tracker.id.to_s} + t << [role, (row.nil? ? 0 : row['c'].to_i)] + end + result << [tracker, t] + end + + result + end +end diff --git a/app/sweepers/NOTEMPTY b/app/sweepers/NOTEMPTY new file mode 100644 index 00000000..e69de29b diff --git a/app/views/account/login.html.erb b/app/views/account/login.html.erb new file mode 100644 index 00000000..05a9f61f --- /dev/null +++ b/app/views/account/login.html.erb @@ -0,0 +1,47 @@ +<%= call_hook :view_account_login_top %> +
+<%= form_tag(signin_path) do %> +<%= back_url_hidden_field_tag %> + + + + + + + + + +<% if Setting.openid? %> + + + + +<% end %> + + + + + + + + +
<%= text_field_tag 'username', params[:username], :tabindex => '1' %>
<%= password_field_tag 'password', nil, :tabindex => '2' %>
<%= text_field_tag "openid_url", nil, :tabindex => '3' %>
+ <% if Setting.autologin? %> + + <% end %> +
+ <% if Setting.lost_password? %> + <%= link_to l(:label_password_lost), lost_password_path %> + <% end %> + + +
+<% end %> +
+<%= call_hook :view_account_login_bottom %> + +<% if params[:username].present? %> +<%= javascript_tag "$('#password').focus();" %> +<% else %> +<%= javascript_tag "$('#username').focus();" %> +<% end %> diff --git a/app/views/account/logout.html.erb b/app/views/account/logout.html.erb new file mode 100644 index 00000000..30959760 --- /dev/null +++ b/app/views/account/logout.html.erb @@ -0,0 +1,3 @@ +<%= form_tag(signout_path) do %> +

<%= submit_tag l(:label_logout) %>

+<% end %> diff --git a/app/views/account/lost_password.html.erb b/app/views/account/lost_password.html.erb new file mode 100644 index 00000000..ceb387e0 --- /dev/null +++ b/app/views/account/lost_password.html.erb @@ -0,0 +1,11 @@ +

<%=l(:label_password_lost)%>

+ +<%= form_tag(lost_password_path) do %> +
+

+ + <%= text_field_tag 'mail', nil, :size => 40 %> + <%= submit_tag l(:button_submit) %> +

+
+<% end %> diff --git a/app/views/account/password_recovery.html.erb b/app/views/account/password_recovery.html.erb new file mode 100644 index 00000000..ff455f32 --- /dev/null +++ b/app/views/account/password_recovery.html.erb @@ -0,0 +1,20 @@ +

<%=l(:label_password_lost)%>

+ +<%= error_messages_for 'user' %> + +<%= form_tag(lost_password_path) do %> + <%= hidden_field_tag 'token', @token.value %> +
+

+ + <%= password_field_tag 'new_password', nil, :size => 25 %> + <%= l(:text_caracters_minimum, :count => Setting.password_min_length) %> +

+ +

+ + <%= password_field_tag 'new_password_confirmation', nil, :size => 25 %> +

+
+

<%= submit_tag l(:button_save) %>

+<% end %> diff --git a/app/views/account/register.html.erb b/app/views/account/register.html.erb new file mode 100644 index 00000000..6928f617 --- /dev/null +++ b/app/views/account/register.html.erb @@ -0,0 +1,31 @@ +

<%=l(:label_register)%> <%=link_to l(:label_login_with_open_id_option), signin_url if Setting.openid? %>

+ +<%= labelled_form_for @user, :url => register_path do |f| %> +<%= error_messages_for 'user' %> + +
+<% if @user.auth_source_id.nil? %> +

<%= f.text_field :login, :size => 25, :required => true %>

+ +

<%= f.password_field :password, :size => 25, :required => true %> + <%= l(:text_caracters_minimum, :count => Setting.password_min_length) %>

+ +

<%= f.password_field :password_confirmation, :size => 25, :required => true %>

+<% end %> + +

<%= f.text_field :firstname, :required => true %>

+

<%= f.text_field :lastname, :required => true %>

+

<%= f.text_field :mail, :required => true %>

+

<%= f.select :language, lang_options_for_select %>

+ +<% if Setting.openid? %> +

<%= f.text_field :identity_url %>

+<% end %> + +<% @user.custom_field_values.select {|v| v.editable? || v.required?}.each do |value| %> +

<%= custom_field_tag_with_label :user, value %>

+<% end %> +
+ +<%= submit_tag l(:button_submit) %> +<% end %> diff --git a/app/views/activities/index.html.erb b/app/views/activities/index.html.erb new file mode 100644 index 00000000..6cc8282e --- /dev/null +++ b/app/views/activities/index.html.erb @@ -0,0 +1,142 @@ +

<%= @author.nil? ? l(:label_activity) : l(:label_user_activity, link_to_user(@author)).html_safe %>

+

+ <%= l(:label_date_from_to, :start => format_date(@date_to - @days), :end => format_date(@date_to-1)) %> +

+ + + + + + +
+ <% @events_by_day.keys.sort.reverse.each do |day| %> +

+
+ <% sort_activity_events(@events_by_day[day]).each do |e, in_group| -%> +
+ + + + + +
+ + + + + + + + + + +
<%= h(e.project) if @project.nil? || @project != e.project %> 有了最新动态 <%= link_to format_activity_title(e.event_title), e.event_url %>

<%= format_activity_description(e.event_description) %>

<%= format_activity_day(day) %> <%= format_time(e.event_datetime, false) %><%= link_to_user(e.event_author) if e.respond_to?(:event_author) %>
+
+ <% end -%> +
+ <% end -%> +
+ + + + + + + + +<%= content_tag('p', l(:label_no_data), :class => 'nodata') if @events_by_day.empty? %> + +
+ <%= link_to_content_update("\xc2\xab " + l(:label_previous), + params.merge(:from => @date_to - @days - 1), + :title => l(:label_date_from_to, :start => format_date(@date_to - 2*@days), :end => format_date(@date_to - @days - 1))) %> +
+
+ <%= link_to_content_update(l(:label_next) + " \xc2\xbb", + params.merge(:from => @date_to + @days - 1), + :title => l(:label_date_from_to, :start => format_date(@date_to), :end => format_date(@date_to + @days - 1))) unless @date_to >= Date.today %> +
+<% other_formats_links do |f| %> +<%= f.link_to 'Atom', :url => params.merge(:from => nil, :key => User.current.rss_key) %> +<% end %> + +<% content_for :header_tags do %> +<%= auto_discovery_link_tag(:atom, params.merge(:format => 'atom', :from => nil, :key => User.current.rss_key)) %> +<% end %> + +<% content_for :sidebar do %> +<%= form_tag({}, :method => :get) do %> +

<%= l(:label_activity) %>

+

+ <% @activity.event_types.each do |t| %> + <%= check_box_tag "show_#{t}", 1, @activity.scope.include?(t) %> + +
+ <% end %> +

+<% if @project && @project.descendants.active.any? %> +<%= hidden_field_tag 'with_subprojects', 0 %> +

+ +

+<% end %> +<%= hidden_field_tag('user_id', params[:user_id]) unless params[:user_id].blank? %> +

+ <%= submit_tag l(:button_apply), :class => 'button-small', :name => nil %> +

+<% end %> +<% end %> + +<% html_title(l(:label_activity), @author) -%> diff --git a/app/views/admin/_menu.html.erb b/app/views/admin/_menu.html.erb new file mode 100644 index 00000000..2ac62c2f --- /dev/null +++ b/app/views/admin/_menu.html.erb @@ -0,0 +1,3 @@ +
+ <%= render_menu :admin_menu %> +
diff --git a/app/views/admin/_no_data.html.erb b/app/views/admin/_no_data.html.erb new file mode 100644 index 00000000..8ad39b19 --- /dev/null +++ b/app/views/admin/_no_data.html.erb @@ -0,0 +1,8 @@ +
+<%= form_tag({:action => 'default_configuration'}) do %> + <%= simple_format(l(:text_no_configuration_data)) %> +

<%= l(:field_language) %>: + <%= select_tag 'lang', options_for_select(lang_options_for_select(false), current_language.to_s) %> + <%= submit_tag l(:text_load_default_configuration) %>

+<% end %> +
diff --git a/app/views/admin/index.html.erb b/app/views/admin/index.html.erb new file mode 100644 index 00000000..8c7ca2b9 --- /dev/null +++ b/app/views/admin/index.html.erb @@ -0,0 +1,8 @@ +

<%=l(:label_administration)%>

+ +
+ <%= render :partial => 'no_data' if @no_configuration_data %> + <%= render :partial => 'menu' %> +
+ +<% html_title(l(:label_administration)) -%> diff --git a/app/views/admin/info.html.erb b/app/views/admin/info.html.erb new file mode 100644 index 00000000..1148efb5 --- /dev/null +++ b/app/views/admin/info.html.erb @@ -0,0 +1,19 @@ +

<%=l(:label_information_plural)%>

+ +

<%= Redmine::Info.versioned_name %>

+ + +<% @checklist.each do |label, result| %> + + + + +<% end %> +
<%= l(label) %><%= image_tag((result ? 'true.png' : 'exclamation.png'), + :style => "vertical-align:bottom;") %>
+
+
+
<%= Redmine::Info.environment %>
+
+ +<% html_title(l(:label_information_plural)) -%> diff --git a/app/views/admin/plugins.html.erb b/app/views/admin/plugins.html.erb new file mode 100644 index 00000000..a573ae63 --- /dev/null +++ b/app/views/admin/plugins.html.erb @@ -0,0 +1,19 @@ +

<%= l(:label_plugins) %>

+ +<% if @plugins.any? %> + + <% @plugins.each do |plugin| %> + + + + + + + <% end %> +
<%=h plugin.name %> + <%= content_tag('span', h(plugin.description), :class => 'description') unless plugin.description.blank? %> + <%= content_tag('span', link_to(h(plugin.url), plugin.url), :class => 'url') unless plugin.url.blank? %> + <%= plugin.author_url.blank? ? h(plugin.author) : link_to(h(plugin.author), plugin.author_url) %><%=h plugin.version %><%= link_to(l(:button_configure), plugin_settings_path(plugin)) if plugin.configurable? %>
+<% else %> +

<%= l(:label_no_data) %>

+<% end %> diff --git a/app/views/admin/projects.html.erb b/app/views/admin/projects.html.erb new file mode 100644 index 00000000..2f520a23 --- /dev/null +++ b/app/views/admin/projects.html.erb @@ -0,0 +1,45 @@ +
+<%= link_to l(:label_project_new), {:controller => 'projects', :action => 'new'}, :class => 'icon icon-add' %> +
+ +

<%=l(:label_project_plural)%>

+ +<%= form_tag({}, :method => :get) do %> +
<%= l(:label_filter_plural) %> + +<%= select_tag 'status', project_status_options_for_select(@status), :class => "small", :onchange => "this.form.submit(); return false;" %> + +<%= text_field_tag 'name', params[:name], :size => 30 %> +<%= submit_tag l(:button_apply), :class => "small", :name => nil %> +<%= link_to l(:button_clear), {:controller => 'admin', :action => 'projects'}, :class => 'icon icon-reload' %> +
+<% end %> +  + +
+ + + + + + + + +<% project_tree(@projects) do |project, level| %> + <%= project.css_classes %> <%= level > 0 ? "idnt idnt-#{level}" : nil %>"> + + + + + +<% end %> + +
<%=l(:label_project)%><%=l(:field_is_public)%><%=l(:field_created_on)%>
<%= link_to_project_settings(project, {}, :title => project.short_description) %><%= checked_image project.is_public? %><%= format_date(project.created_on) %> + <%= link_to(l(:button_archive), { :controller => 'projects', :action => 'archive', :id => project, :status => params[:status] }, :data => {:confirm => l(:text_are_you_sure)}, :method => :post, :class => 'icon icon-lock') unless project.archived? %> + <%= link_to(l(:button_unarchive), { :controller => 'projects', :action => 'unarchive', :id => project, :status => params[:status] }, :method => :post, :class => 'icon icon-unlock') if project.archived? && (project.parent.nil? || !project.parent.archived?) %> + <%= link_to(l(:button_copy), { :controller => 'projects', :action => 'copy', :id => project }, :class => 'icon icon-copy') %> + <%= link_to(l(:button_delete), project_path(project), :method => :delete, :class => 'icon icon-del') %> +
+
+ +<% html_title(l(:label_project_plural)) -%> diff --git a/app/views/attachments/_form.html.erb b/app/views/attachments/_form.html.erb new file mode 100644 index 00000000..65ad8804 --- /dev/null +++ b/app/views/attachments/_form.html.erb @@ -0,0 +1,31 @@ + +<% if defined?(container) && container && container.saved_attachments %> + <% container.saved_attachments.each_with_index do |attachment, i| %> + + <%= text_field_tag("attachments[p#{i}][filename]", attachment.filename, :class => 'filename') + + text_field_tag("attachments[p#{i}][description]", attachment.description, :maxlength => 255, :placeholder => l(:label_optional_description), :class => 'description') + + link_to(' '.html_safe, attachment_path(attachment, :attachment_id => "p#{i}", :format => 'js'), :method => 'delete', :remote => true, :class => 'remove-upload') %> + <%= hidden_field_tag "attachments[p#{i}][token]", "#{attachment.token}" %> + + <% end %> +<% end %> + + +<%= file_field_tag 'attachments[dummy][file]', + :id => nil, + :class => 'file_selector', + :multiple => true, + :onchange => 'addInputFiles(this);', + :data => { + :max_file_size => Setting.attachment_max_size.to_i.kilobytes, + :max_file_size_message => l(:error_attachment_too_big, :max_size => number_to_human_size(Setting.attachment_max_size.to_i.kilobytes)), + :max_concurrent_uploads => Redmine::Configuration['max_concurrent_ajax_uploads'].to_i, + :upload_path => uploads_path(:format => 'js'), + :description_placeholder => l(:label_optional_description) + } %> +(<%= l(:label_max_size) %>: <%= number_to_human_size(Setting.attachment_max_size.to_i.kilobytes) %>) + + +<% content_for :header_tags do %> + <%= javascript_include_tag 'attachments' %> +<% end %> diff --git a/app/views/attachments/_links.html.erb b/app/views/attachments/_links.html.erb new file mode 100644 index 00000000..d2ab22ce --- /dev/null +++ b/app/views/attachments/_links.html.erb @@ -0,0 +1,33 @@ +
+<% for attachment in attachments %> +

<%= link_to_attachment attachment, :class => 'icon icon-attachment', :download => true -%> + <% if attachment.is_text? %> + <%= link_to image_tag('magnifier.png'), + :controller => 'attachments', :action => 'show', + :id => attachment, :filename => attachment.filename %> + <% end %> + <%= h(" - #{attachment.description}") unless attachment.description.blank? %> + (<%= number_to_human_size attachment.filesize %>) + <% if options[:deletable] %> + <%= link_to image_tag('delete.png'), attachment_path(attachment), + :data => {:confirm => l(:text_are_you_sure)}, + :method => :delete, + :class => 'delete', + :title => l(:button_delete) %> + <% end %> + <% if options[:author] %> + <%= h(attachment.author) %>, <%= format_time(attachment.created_on) %> + <% end %> +

+<% end %> +<% if defined?(thumbnails) && thumbnails %> + <% images = attachments.select(&:thumbnailable?) %> + <% if images.any? %> +
+ <% images.each do |attachment| %> +
<%= thumbnail_tag(attachment) %>
+ <% end %> +
+ <% end %> +<% end %> +
diff --git a/app/views/attachments/destroy.js.erb b/app/views/attachments/destroy.js.erb new file mode 100644 index 00000000..3cfb5845 --- /dev/null +++ b/app/views/attachments/destroy.js.erb @@ -0,0 +1 @@ +$('#attachments_<%= j params[:attachment_id] %>').remove(); diff --git a/app/views/attachments/diff.html.erb b/app/views/attachments/diff.html.erb new file mode 100644 index 00000000..8361bcb5 --- /dev/null +++ b/app/views/attachments/diff.html.erb @@ -0,0 +1,22 @@ +

<%=h @attachment.filename %>

+ +
+

<%= h("#{@attachment.description} - ") unless @attachment.description.blank? %> + <%= link_to_user(@attachment.author) %>, <%= format_time(@attachment.created_on) %>

+

<%= link_to_attachment @attachment, :text => l(:button_download), :download => true -%> + (<%= number_to_human_size @attachment.filesize %>)

+
+<%= form_tag({}, :method => 'get') do %> +

+ <%= l(:label_view_diff) %>: + + +

+<% end %> +<%= render :partial => 'common/diff', :locals => {:diff => @diff, :diff_type => @diff_type, :diff_style => nil} %> + +<% html_title @attachment.filename %> + +<% content_for :header_tags do -%> + <%= stylesheet_link_tag "scm" -%> +<% end -%> diff --git a/app/views/attachments/file.html.erb b/app/views/attachments/file.html.erb new file mode 100644 index 00000000..57393b81 --- /dev/null +++ b/app/views/attachments/file.html.erb @@ -0,0 +1,17 @@ +

<%=h @attachment.filename %>

+ +
+

<%= h("#{@attachment.description} - ") unless @attachment.description.blank? %> + <%= link_to_user(@attachment.author) %>, <%= format_time(@attachment.created_on) %>

+

<%= link_to_attachment @attachment, :text => l(:button_download), :download => true -%> + (<%= number_to_human_size @attachment.filesize %>)

+ +
+  +<%= render :partial => 'common/file', :locals => {:content => @content, :filename => @attachment.filename} %> + +<% html_title @attachment.filename %> + +<% content_for :header_tags do -%> + <%= stylesheet_link_tag "scm" -%> +<% end -%> diff --git a/app/views/attachments/show.api.rsb b/app/views/attachments/show.api.rsb new file mode 100644 index 00000000..5a9f74a9 --- /dev/null +++ b/app/views/attachments/show.api.rsb @@ -0,0 +1 @@ +render_api_attachment(@attachment, api) diff --git a/app/views/attachments/upload.api.rsb b/app/views/attachments/upload.api.rsb new file mode 100644 index 00000000..edd0b0af --- /dev/null +++ b/app/views/attachments/upload.api.rsb @@ -0,0 +1,3 @@ +api.upload do + api.token @attachment.token +end diff --git a/app/views/attachments/upload.js.erb b/app/views/attachments/upload.js.erb new file mode 100644 index 00000000..04e30b56 --- /dev/null +++ b/app/views/attachments/upload.js.erb @@ -0,0 +1,9 @@ +var fileSpan = $('#attachments_<%= j params[:attachment_id] %>'); +$('', { type: 'hidden', name: 'attachments[<%= j params[:attachment_id] %>][token]' } ).val('<%= j @attachment.token %>').appendTo(fileSpan); +fileSpan.find('a.remove-upload') + .attr({ + "data-remote": true, + "data-method": 'delete', + href: '<%= j attachment_path(@attachment, :attachment_id => params[:attachment_id], :format => 'js') %>' + }) + .off('click'); diff --git a/app/views/auth_sources/_form.html.erb b/app/views/auth_sources/_form.html.erb new file mode 100644 index 00000000..05c6ca9e --- /dev/null +++ b/app/views/auth_sources/_form.html.erb @@ -0,0 +1,6 @@ +<%= error_messages_for 'auth_source' %> + +
+

<%= f.text_field :name, :required => true %>

+

<%= f.check_box :onthefly_register, :label => :field_onthefly %>

+
diff --git a/app/views/auth_sources/_form_auth_source_ldap.html.erb b/app/views/auth_sources/_form_auth_source_ldap.html.erb new file mode 100644 index 00000000..2ffd4d43 --- /dev/null +++ b/app/views/auth_sources/_form_auth_source_ldap.html.erb @@ -0,0 +1,24 @@ +<%= error_messages_for 'auth_source' %> + +
+

<%= f.text_field :name, :required => true %>

+

<%= f.text_field :host, :required => true %>

+

<%= f.text_field :port, :required => true, :size => 6 %> <%= f.check_box :tls, :no_label => true %> LDAPS

+

<%= f.text_field :account %>

+

<%= f.password_field :account_password, :label => :field_password, + :name => 'dummy_password', + :value => ((@auth_source.new_record? || @auth_source.account_password.blank?) ? '' : ('x'*15)), + :onfocus => "this.value=''; this.name='auth_source[account_password]';", + :onchange => "this.name='auth_source[account_password]';" %>

+

<%= f.text_field :base_dn, :required => true, :size => 60 %>

+

<%= f.text_field :filter, :size => 60, :label => :field_auth_source_ldap_filter %>

+

<%= f.text_field :timeout, :size => 4 %>

+

<%= f.check_box :onthefly_register, :label => :field_onthefly %>

+
+ +
<%=l(:label_attribute_plural)%> +

<%= f.text_field :attr_login, :required => true, :size => 20 %>

+

<%= f.text_field :attr_firstname, :size => 20 %>

+

<%= f.text_field :attr_lastname, :size => 20 %>

+

<%= f.text_field :attr_mail, :size => 20 %>

+
diff --git a/app/views/auth_sources/edit.html.erb b/app/views/auth_sources/edit.html.erb new file mode 100644 index 00000000..fb43d3f9 --- /dev/null +++ b/app/views/auth_sources/edit.html.erb @@ -0,0 +1,6 @@ +

<%=l(:label_auth_source)%> (<%= h(@auth_source.auth_method_name) %>)

+ +<%= labelled_form_for @auth_source, :as => :auth_source, :url => auth_source_path(@auth_source), :html => {:id => 'auth_source_form'} do |f| %> + <%= render :partial => auth_source_partial_name(@auth_source), :locals => { :f => f } %> + <%= submit_tag l(:button_save) %> +<% end %> diff --git a/app/views/auth_sources/index.html.erb b/app/views/auth_sources/index.html.erb new file mode 100644 index 00000000..ba1bd629 --- /dev/null +++ b/app/views/auth_sources/index.html.erb @@ -0,0 +1,31 @@ +
+<%= link_to l(:label_auth_source_new), {:action => 'new'}, :class => 'icon icon-add' %> +
+ +

<%=l(:label_auth_source_plural)%>

+ + + + + + + + + + +<% for source in @auth_sources %> + "> + + + + + + +<% end %> + +
<%=l(:field_name)%><%=l(:field_type)%><%=l(:field_host)%><%=l(:label_user_plural)%>
<%= link_to(h(source.name), :action => 'edit', :id => source)%><%= h source.auth_method_name %><%= h source.host %><%= h source.users.count %> + <%= link_to l(:button_test), try_connection_auth_source_path(source), :class => 'icon icon-test' %> + <%= delete_link auth_source_path(source) %> +
+ +

<%= pagination_links_full @auth_source_pages %>

diff --git a/app/views/auth_sources/new.html.erb b/app/views/auth_sources/new.html.erb new file mode 100644 index 00000000..3938b910 --- /dev/null +++ b/app/views/auth_sources/new.html.erb @@ -0,0 +1,7 @@ +

<%=l(:label_auth_source_new)%> (<%= h(@auth_source.auth_method_name) %>)

+ +<%= labelled_form_for @auth_source, :as => :auth_source, :url => auth_sources_path, :html => {:id => 'auth_source_form'} do |f| %> + <%= hidden_field_tag 'type', @auth_source.type %> + <%= render :partial => auth_source_partial_name(@auth_source), :locals => { :f => f } %> + <%= submit_tag l(:button_create) %> +<% end %> diff --git a/app/views/auto_completes/issues.html.erb b/app/views/auto_completes/issues.html.erb new file mode 100644 index 00000000..e292bbae --- /dev/null +++ b/app/views/auto_completes/issues.html.erb @@ -0,0 +1,7 @@ +<%= raw @issues.map {|issue| { + 'id' => issue.id, + 'label' => "#{issue.tracker} ##{issue.id}: #{truncate issue.subject.to_s, :length => 60}", + 'value' => issue.id + } + }.to_json +%> diff --git a/app/views/avatar/_avatar_form.html.erb b/app/views/avatar/_avatar_form.html.erb new file mode 100644 index 00000000..6e0df038 --- /dev/null +++ b/app/views/avatar/_avatar_form.html.erb @@ -0,0 +1,27 @@ + + <%= image_tag(url_to_avatar(source), id: "avatar_image", size: AvatarHelper::AVATAR_SIZE)%> + + + + + +<%= file_field_tag 'avatar[image]', + :id => nil, + :class => 'file_selector', + :multiple => false, + :onchange => 'addInputAvatar(this);', + :data => { + :max_file_size => Setting.attachment_max_size.to_i.kilobytes, + :max_file_size_message => l(:error_attachment_too_big, :max_size => number_to_human_size(Setting.attachment_max_size.to_i.kilobytes)), + :max_concurrent_uploads => Redmine::Configuration['max_concurrent_ajax_uploads'].to_i, + :upload_path => upload_avatar_path(:format => 'js'), + :description_placeholder => nil ,# l(:label_optional_description) + :source_type => source.class.to_s, + :source_id => source.id.to_s + } %> +(<%= l(:label_max_size) %>: <%= number_to_human_size(Setting.attachment_max_size.to_i.kilobytes) %>) + + +<% content_for :header_tags do %> + <%= javascript_include_tag 'avatars' %> +<% end %> diff --git a/app/views/avatar/upload.js.erb b/app/views/avatar/upload.js.erb new file mode 100644 index 00000000..a7a341f1 --- /dev/null +++ b/app/views/avatar/upload.js.erb @@ -0,0 +1,4 @@ +var imgSpan = $('#avatar_image'); + +imgSpan.attr({"src":'<%= @urlfile.to_s << "?" << Time.now.to_s%>'}); + diff --git a/app/views/bids/_history.html.erb b/app/views/bids/_history.html.erb new file mode 100644 index 00000000..4135208a --- /dev/null +++ b/app/views/bids/_history.html.erb @@ -0,0 +1,37 @@ + + +<% if journals.size > 5 %> +<% unless state%> +
+<%= link_to l(:button_more), + {:controller => 'bids', :action => 'more', :bid_id => bid}, + :remote => true, + :method => 'get' %> +
+<% else %> +
+<%= link_to l(:button_back), + {:controller => 'bids', :action => 'back', :bid_id => bid}, + :remote => true, + :method => 'get' %> +
+<% end %> +<% end %> + +

<%=l(:label_user_response)%>(<%= journals.count%>)

+<% unless state%> + <% if journals.size > 5 %> + <% journals = journals[0, 5] %> + <% end %> +<% end %> +<% for journal in journals %> +
+
+

<%= link_to "##{journal.indice}", {}, :class => "journal-link" %> + <%= avatar(journal.user, :size => "24") %> + <%= l(:label_updated_time_by, :author => journal.user, :age => time_tag(journal.created_at)).html_safe%>

+ <%= render_notes(bid, journal, :reply_links => true) unless journal.notes.blank? %> +
+
+ <%= call_hook(:view_issues_history_journal_bottom, { :journal => journal }) %> +<% end %> diff --git a/app/views/bids/_new.html.erb b/app/views/bids/_new.html.erb new file mode 100644 index 00000000..1e395814 --- /dev/null +++ b/app/views/bids/_new.html.erb @@ -0,0 +1,13 @@ +<%= form_tag({:controller => 'bids', + :action => 'create', + :bid_id => bid, + :sta => sta}, + :remote => true, + :method => :post) do %> + +

<%= label_tag 'user_message', l(:label_leave_message) %><%= text_area_tag 'user_message', nil %>

+

+ <%= submit_tag l(:button_leave_meassge), :name => nil %> + <%= submit_tag l(:button_clear), :name => nil, :onclick => "clearMessage('user_message');", :type => 'button' %> +

+<% end %> diff --git a/app/views/bids/_project_list.html.erb b/app/views/bids/_project_list.html.erb new file mode 100644 index 00000000..53eda2b0 --- /dev/null +++ b/app/views/bids/_project_list.html.erb @@ -0,0 +1,35 @@ +<% @bidding_project.each do |b_project|%> +
  • + + + + + + + +
    + + + + + + +
    + + + + + + + +
    <%= link_to(b_project.project.name, project_path(b_project.project)) %>
    <%= b_project.project.description %>
    + + + + + + + +
    应标人:<%= link_to(b_project.user.name, user_path(b_project.user)) %>
    应标宣言:<%= b_project.description %>
     
    +
  • +<% end %> diff --git a/app/views/bids/add.js.erb b/app/views/bids/add.js.erb new file mode 100644 index 00000000..9a6d1515 --- /dev/null +++ b/app/views/bids/add.js.erb @@ -0,0 +1,4 @@ +$('#bidding_project_list').html('<%= escape_javascript(render(:partial => 'project_list', :locals => {:bidding_project => @bidding_project})) %>'); +$("#project_id").val("请选择项目"); +$("#project_id").val("请输入应标理由"); +$("#put-bid-form").hide(); \ No newline at end of file diff --git a/app/views/bids/back.js.erb b/app/views/bids/back.js.erb new file mode 100644 index 00000000..b2d3c515 --- /dev/null +++ b/app/views/bids/back.js.erb @@ -0,0 +1 @@ +$('#history').html('<%= escape_javascript(render(:partial => 'history', :locals => {:bid => @bid, :journals => @jour, :state => @state})) %>'); diff --git a/app/views/bids/create.js.erb b/app/views/bids/create.js.erb new file mode 100644 index 00000000..a524d9dd --- /dev/null +++ b/app/views/bids/create.js.erb @@ -0,0 +1,2 @@ +$('#history').html('<%= escape_javascript(render(:partial => 'history', :locals => {:bid => @bid, :journals => @jour, :state => true})) %>'); +$('#user_message').val(""); diff --git a/app/views/bids/destroy.js.erb b/app/views/bids/destroy.js.erb new file mode 100644 index 00000000..c5e1516b --- /dev/null +++ b/app/views/bids/destroy.js.erb @@ -0,0 +1 @@ +$('#history').html('<%= escape_javascript(render(:partial => 'history', :locals => {:bid => @bid, :journals => @jour, :state => false})) %>'); diff --git a/app/views/bids/index.html.erb b/app/views/bids/index.html.erb new file mode 100644 index 00000000..74c0531f --- /dev/null +++ b/app/views/bids/index.html.erb @@ -0,0 +1,37 @@ +
    + <%= link_to("新建需求", {:controller => 'bids', :action => 'new_bid'}, :class => 'icon icon-add') %> +
    +

    需求列表

    + +
      + <% @bids.each do |bid|%> +
    • + + 悬赏:¥<%= bid.budget%> + <%= link_to bid.name, :controller => 'bids', :action => 'show', :bid_id => bid.id %> + <%= bid.author.name%> 发布 39投标 +
    • + <% end %> + +
    • + + 悬赏:¥1000 + <%= link_to "宣传展示型网站开发_企业网站中英文", :controller => 'bids', :action => 'show', :bid_id => "2" %> + tellmey 发布 24投标 +
    • + +
    • + + 悬赏:¥1000 + <%= link_to "移动应用终端无线支付停车场开发", :controller => 'bids', :action => 'show', :bid_id => "3" %> + 奥美特电子 发布 2投标 +
    • + +
    • + + 悬赏:¥1500 + <%= link_to "需要一个印刷类的erp系统", :controller => 'bids', :action => 'show', :bid_id => "4" %> + 海彩印刷有限公司 发布 17投标 +
    • + +
    \ No newline at end of file diff --git a/app/views/bids/more.js.erb b/app/views/bids/more.js.erb new file mode 100644 index 00000000..b2d3c515 --- /dev/null +++ b/app/views/bids/more.js.erb @@ -0,0 +1 @@ +$('#history').html('<%= escape_javascript(render(:partial => 'history', :locals => {:bid => @bid, :journals => @jour, :state => @state})) %>'); diff --git a/app/views/bids/new.js.erb b/app/views/bids/new.js.erb new file mode 100644 index 00000000..d2cdeaae --- /dev/null +++ b/app/views/bids/new.js.erb @@ -0,0 +1,2 @@ +$('#user_message').val("<%= raw escape_javascript(@content) %>"); +showAndScrollTo("user_message", "user_message"); diff --git a/app/views/bids/new_bid.html.erb b/app/views/bids/new_bid.html.erb new file mode 100644 index 00000000..bfda9073 --- /dev/null +++ b/app/views/bids/new_bid.html.erb @@ -0,0 +1,14 @@ +
    +<%= form_tag({:controller => 'bids', + :action => 'index', + :remote => true, + :method => :post, + :id => 'new-bid-form'}) do %> +

    需求名称:<%= text_field_tag 'bid_title' %>

    +

    需求描述:

    +

    <%= text_area_tag 'bid_description' %>

    +

    投资预算:<%= text_field_tag 'bid_budget' %>

    +

    投资时限:<%= text_field_tag 'bid_deadline' %>

    + <%= submit_tag l(:button_submit) %> + <%end%> +
    diff --git a/app/views/bids/show.html.erb b/app/views/bids/show.html.erb new file mode 100644 index 00000000..a8271108 --- /dev/null +++ b/app/views/bids/show.html.erb @@ -0,0 +1,17 @@ +

    <%= link_to(@bid.author.name, user_path(@bid.author))%>:<%= @bid.name %>

    + + + + + + +

    需求描述

    <%= @bid.description %>
    + +
    +<%= render :partial => 'history', :locals => { :bid => @bid, :journals => @jour, :state => false} %> +
    + +
    + <%= render :partial => 'new', :locals => {:bid => @bid, :sta => @state} %> +
    + diff --git a/app/views/bids/show_project.html.erb b/app/views/bids/show_project.html.erb new file mode 100644 index 00000000..c1af73b3 --- /dev/null +++ b/app/views/bids/show_project.html.erb @@ -0,0 +1,32 @@ +
    +
    +
    +<%= toggle_link "我要应标", 'put-bid-form', {:focus => 'project_id'} %> +
    + + +

    应标项目列表

    +
      +
      + <%= render :partial => 'project_list', :locals => {:bidding_project => @bidding_project} %> +
      +
    + diff --git a/app/views/boards/_form.html.erb b/app/views/boards/_form.html.erb new file mode 100644 index 00000000..daaecee5 --- /dev/null +++ b/app/views/boards/_form.html.erb @@ -0,0 +1,9 @@ +<%= error_messages_for @board %> + +
    +

    <%= f.text_field :name, :required => true %>

    +

    <%= f.text_field :description, :required => true, :size => 80 %>

    +<% if @board.valid_parents.any? %> +

    <%= f.select :parent_id, boards_options_for_select(@board.valid_parents), :include_blank => true, :label => :field_board_parent %>

    +<% end %> +
    diff --git a/app/views/boards/edit.html.erb b/app/views/boards/edit.html.erb new file mode 100644 index 00000000..21730e96 --- /dev/null +++ b/app/views/boards/edit.html.erb @@ -0,0 +1,6 @@ +

    <%= l(:label_board) %>

    + +<%= labelled_form_for @board, :url => project_board_path(@project, @board) do |f| %> + <%= render :partial => 'form', :locals => {:f => f} %> + <%= submit_tag l(:button_save) %> +<% end %> diff --git a/app/views/boards/index.html.erb b/app/views/boards/index.html.erb new file mode 100644 index 00000000..71aba48b --- /dev/null +++ b/app/views/boards/index.html.erb @@ -0,0 +1,38 @@ +

    <%= l(:label_board_plural) %>

    + + + + + + + + + +<% Board.board_tree(@boards) do |board, level| %> + + + + + + +<% end %> + +
    <%= l(:label_board) %><%= l(:label_topic_plural) %><%= l(:label_message_plural) %><%= l(:label_message_last) %>
    + <%= link_to h(board.name), project_board_path(board.project, board), :class => "board" %>
    + <%=h board.description %> +
    <%= board.topics_count %><%= board.messages_count %> + <% if board.last_message %> + <%= authoring board.last_message.created_on, board.last_message.author %>
    + <%= link_to_message board.last_message %> + <% end %> +
    + +<% other_formats_links do |f| %> + <%= f.link_to 'Atom', :url => {:controller => 'activities', :action => 'index', :id => @project, :show_messages => 1, :key => User.current.rss_key} %> +<% end %> + +<% content_for :header_tags do %> + <%= auto_discovery_link_tag(:atom, {:controller => 'activities', :action => 'index', :id => @project, :format => 'atom', :show_messages => 1, :key => User.current.rss_key}) %> +<% end %> + +<% html_title l(:label_board_plural) %> diff --git a/app/views/boards/new.html.erb b/app/views/boards/new.html.erb new file mode 100644 index 00000000..509910ca --- /dev/null +++ b/app/views/boards/new.html.erb @@ -0,0 +1,6 @@ +

    <%= l(:label_board_new) %>

    + +<%= labelled_form_for @board, :url => project_boards_path(@project) do |f| %> + <%= render :partial => 'form', :locals => {:f => f} %> + <%= submit_tag l(:button_create) %> +<% end %> diff --git a/app/views/boards/show.html.erb b/app/views/boards/show.html.erb new file mode 100644 index 00000000..bababcc3 --- /dev/null +++ b/app/views/boards/show.html.erb @@ -0,0 +1,66 @@ +<%= board_breadcrumb(@board) %> + +
    +<%= link_to l(:label_message_new), + new_board_message_path(@board), + :class => 'icon icon-add', + :onclick => 'showAndScrollTo("add-message", "message_subject"); return false;' if User.current.allowed_to?(:add_messages, @board.project) %> +<%= watcher_link(@board, User.current) %> +
    + + + +

    <%=h @board.name %>

    +

    <%=h @board.description %>

    + +<% if @topics.any? %> + + + + + <%= sort_header_tag('created_on', :caption => l(:field_created_on)) %> + <%= sort_header_tag('replies', :caption => l(:label_reply_plural)) %> + <%= sort_header_tag('updated_on', :caption => l(:label_message_last)) %> + + + <% @topics.each do |topic| %> + + + + + + + + <% end %> + +
    <%= l(:field_subject) %><%= l(:field_author) %>
    <%= link_to h(topic.subject), board_message_path(@board, topic) %><%= link_to_user(topic.author) %><%= format_time(topic.created_on) %><%= topic.replies_count %> + <% if topic.last_reply %> + <%= authoring topic.last_reply.created_on, topic.last_reply.author %>
    + <%= link_to_message topic.last_reply %> + <% end %> +
    +

    <%= pagination_links_full @topic_pages, @topic_count %>

    +<% else %> +

    <%= l(:label_no_data) %>

    +<% end %> + +<% other_formats_links do |f| %> + <%= f.link_to 'Atom', :url => {:key => User.current.rss_key} %> +<% end %> + +<% html_title @board.name %> + +<% content_for :header_tags do %> + <%= auto_discovery_link_tag(:atom, {:format => 'atom', :key => User.current.rss_key}, :title => "#{@project}: #{@board}") %> +<% end %> diff --git a/app/views/calendars/show.html.erb b/app/views/calendars/show.html.erb new file mode 100644 index 00000000..9166974f --- /dev/null +++ b/app/views/calendars/show.html.erb @@ -0,0 +1,43 @@ +

    <%= @query.new_record? ? l(:label_calendar) : h(@query.name) %>

    + +<%= form_tag({:controller => 'calendars', :action => 'show', :project_id => @project}, + :method => :get, :id => 'query_form') do %> +<%= hidden_field_tag 'set_filter', '1' %> +
    "> + <%= l(:label_filter_plural) %> +
    "> + <%= render :partial => 'queries/filters', :locals => {:query => @query} %> +
    +
    + +

    + <%= link_to_previous_month(@year, @month) %> | <%= link_to_next_month(@year, @month) %> +

    + +

    +<%= label_tag('month', l(:label_month)) %> +<%= select_month(@month, :prefix => "month", :discard_type => true) %> +<%= label_tag('year', l(:label_year)) %> +<%= select_year(@year, :prefix => "year", :discard_type => true) %> + +<%= link_to_function l(:button_apply), '$("#query_form").submit()', :class => 'icon icon-checked' %> +<%= link_to l(:button_clear), { :project_id => @project, :set_filter => 1 }, :class => 'icon icon-reload' %> +

    +<% end %> + +<%= error_messages_for 'query' %> +<% if @query.valid? %> +<%= render :partial => 'common/calendar', :locals => {:calendar => @calendar} %> + +

    + <%= l(:text_tip_issue_begin_day) %> + <%= l(:text_tip_issue_end_day) %> + <%= l(:text_tip_issue_begin_end_day) %> +

    +<% end %> + +<% content_for :sidebar do %> + <%= render :partial => 'issues/sidebar' %> +<% end %> + +<% html_title(l(:label_calendar)) -%> diff --git a/app/views/common/_calendar.html.erb b/app/views/common/_calendar.html.erb new file mode 100644 index 00000000..7951b68c --- /dev/null +++ b/app/views/common/_calendar.html.erb @@ -0,0 +1,32 @@ + + +<% 7.times do |i| %><% end %> + + + +<% day = calendar.startdt +while day <= calendar.enddt %> +<%= ("".html_safe) if day.cwday == calendar.first_wday %> + +<%= ''.html_safe if day.cwday==calendar.last_wday and day!=calendar.enddt %> +<% day = day + 1 +end %> + + +
    <%= day_name( (calendar.first_wday+i)%7 ) %>
    #{(day+(11-day.cwday)%7).cweek} +

    <%= day.day %>

    +<% calendar.events_on(day).each do |i| %> + <% if i.is_a? Issue %> +
    + <%= h("#{i.project} -") unless @project && @project == i.project %> + <%= link_to_issue i, :truncate => 30 %> + <%= render_issue_tooltip i %> +
    + <% else %> + + <%= h("#{i.project} -") unless @project && @project == i.project %> + <%= link_to_version i%> + + <% end %> +<% end %> +
    diff --git a/app/views/common/_diff.html.erb b/app/views/common/_diff.html.erb new file mode 100644 index 00000000..0d30bedd --- /dev/null +++ b/app/views/common/_diff.html.erb @@ -0,0 +1,68 @@ +<% diff = Redmine::UnifiedDiff.new( + diff, :type => diff_type, + :max_lines => Setting.diff_max_lines_displayed.to_i, + :style => diff_style) -%> + +<% diff.each do |table_file| -%> +
    +<% if diff.diff_type == 'sbs' -%> + + + + + + + +<% table_file.each_line do |spacing, line| -%> +<% if spacing -%> + + + +<% end -%> + + + + + + +<% end -%> + +
    + <%= table_file.file_name %> +
    ......
    <%= line.nb_line_left %> +
    <%= line.html_line_left.html_safe %>
    +
    <%= line.nb_line_right %> +
    <%= line.html_line_right.html_safe %>
    +
    + +<% else -%> + + + + + + + +<% table_file.each_line do |spacing, line| %> +<% if spacing -%> + + + +<% end -%> + + + + + +<% end -%> + +
    + <%= table_file.file_name %> +
    ......
    <%= line.nb_line_left %><%= line.nb_line_right %> +
    <%= line.html_line.html_safe %>
    +
    +<% end -%> +
    +<% end -%> + +<%= l(:text_diff_truncated) if diff.truncated? %> diff --git a/app/views/common/_file.html.erb b/app/views/common/_file.html.erb new file mode 100644 index 00000000..22126b94 --- /dev/null +++ b/app/views/common/_file.html.erb @@ -0,0 +1,18 @@ +
    + + +<% line_num = 1 %> +<% syntax_highlight_lines(filename, Redmine::CodesetUtil.to_utf8_by_setting(content)).each do |line| %> + + + + + <% line_num += 1 %> +<% end %> + +
    + <%= line_num %> + +
    <%= line.html_safe %>
    +
    +
    diff --git a/app/views/common/_preview.html.erb b/app/views/common/_preview.html.erb new file mode 100644 index 00000000..90d83ce8 --- /dev/null +++ b/app/views/common/_preview.html.erb @@ -0,0 +1,3 @@ +
    <%= l(:label_preview) %> +<%= textilizable @text, :attachments => @attachments, :object => @previewed %> +
    diff --git a/app/views/common/_project.html.erb b/app/views/common/_project.html.erb new file mode 100644 index 00000000..516ed0f5 --- /dev/null +++ b/app/views/common/_project.html.erb @@ -0,0 +1,58 @@ +
    +
    + <%= content_tag('div', tag('img', {:src => '../images/logo-only_med.png', :class => 'img_ta'}, false, false), :class => 'img-tag') %> +
    +
    +

    + Claimed by <%= content_tag('a', project.name) %> | Analyzed about 11 hours ago +

    +

    + <%= textilizable(project.short_description, :project => project) %> +

    +
    +
    +

    + <%= content_tag('a', "9.23M") %><%= content_tag('span', "lines of codes") %> +

    +

    + <%= content_tag('a', "963") %><%= content_tag('span', "current contributors") %> +

    +

    + <%= content_tag('a', "1 day") %><%= content_tag('span', "since last commits") %> +

    +

    + <%= content_tag('a', "12,169") %><%= content_tag('span', "users on trustie2") %> +

    +
    +
    + <%= content_tag('a', tag('img', {:src => '../images/pai.png', :class => 'img-ta'}, false, false), :class => 'img-tag3') %> + <%= content_tag('div', "Vert High Activity", :class => 'img-tag4') %> + <%= content_tag('div', tag('img', {:src => '../images/stars_ro.png', :class => 'img-ta'}, false, false), :class => 'img-tag2') %> + <%= content_tag('div', "#{WatchersOfProjects.watcher_count(project)}Reviews", :class => 'img-tag1') %> +
    +
    +
    +
    + <%= content_tag('a', 'Mostly written in C++') %> +
    +
    + <%= content_tag('a', 'Licenses:') %><%= content_tag('span', 'GPL-2.0+, LGPL, MPL-1.1') %> +
    +
    +
    + <%= tag('img', {:src => "../images/user.png"}, false, false) %> + <% tags = ProjectTags.find_tag(project.id) + tags.each do |t_tag| + content = t_tag.tag.content + description = t_tag.description -%> + <%= content_tag('a', content, :class => 'tag', :title => description) %> + <% end -%> + <%= content_tag('a', 'css', :class => 'tag') %> + <%= content_tag('a', 'web_browser', :class => 'tag') %> + <%= content_tag('a', 'development', :class => 'tag') %> + <%= content_tag('a', 'client', :class => 'tag') %> + <%= content_tag('a', 'web', :class => 'tag') %> + <%= content_tag('a', 'xhtml', :class => 'tag') %> + <%= content_tag('a', 'tabbed', :class => 'tag') %> + <%= content_tag('a', 'and more') %> +
    diff --git a/app/views/common/_tabs.html.erb b/app/views/common/_tabs.html.erb new file mode 100644 index 00000000..2cf90135 --- /dev/null +++ b/app/views/common/_tabs.html.erb @@ -0,0 +1,28 @@ +<% selected_tab = params[:tab] ? params[:tab].to_s : tabs.first[:name] %> + +
    +
      + <% tabs.each do |tab| -%> +
    • <%= link_to l(tab[:label]), { :tab => tab[:name] }, + :id => "tab-#{tab[:name]}", + :class => (tab[:name] != selected_tab ? nil : 'selected'), + :onclick => "showTab('#{tab[:name]}'); this.blur(); return false;" %>
    • + <% end -%> +
    + +
    + + + +<% tabs.each do |tab| -%> + <%= content_tag('div', render(:partial => tab[:partial], :locals => {:tab => tab} ), + :id => "tab-content-#{tab[:name]}", + :style => (tab[:name] != selected_tab ? 'display:none' : nil), + :class => 'tab-content') %> +<% end -%> diff --git a/app/views/common/error.html.erb b/app/views/common/error.html.erb new file mode 100644 index 00000000..20a524bd --- /dev/null +++ b/app/views/common/error.html.erb @@ -0,0 +1,8 @@ +

    <%=h @status %>

    + +<% if @message.present? %> +

    <%=h @message %>

    +<% end %> +

    <%= l(:button_back) %>

    + +<% html_title @status %> diff --git a/app/views/common/error_messages.api.rsb b/app/views/common/error_messages.api.rsb new file mode 100644 index 00000000..811d2a86 --- /dev/null +++ b/app/views/common/error_messages.api.rsb @@ -0,0 +1,5 @@ +api.array :errors do + @error_messages.each do |message| + api.error message + end +end diff --git a/app/views/common/feed.atom.builder b/app/views/common/feed.atom.builder new file mode 100644 index 00000000..70dacc75 --- /dev/null +++ b/app/views/common/feed.atom.builder @@ -0,0 +1,31 @@ +xml.instruct! +xml.feed "xmlns" => "http://www.w3.org/2005/Atom" do + xml.title truncate_single_line(@title, :length => 100) + xml.link "rel" => "self", "href" => url_for(params.merge(:only_path => false)) + xml.link "rel" => "alternate", "href" => url_for(params.merge(:only_path => false, :format => nil, :key => nil)) + xml.id url_for(:controller => 'welcome', :only_path => false) + xml.updated((@items.first ? @items.first.event_datetime : Time.now).xmlschema) + xml.author { xml.name "#{Setting.app_title}" } + xml.generator(:uri => Redmine::Info.url) { xml.text! Redmine::Info.app_name; } + @items.each do |item| + xml.entry do + url = url_for(item.event_url(:only_path => false)) + if @project + xml.title truncate_single_line(item.event_title, :length => 100) + else + xml.title truncate_single_line("#{item.project} - #{item.event_title}", :length => 100) + end + xml.link "rel" => "alternate", "href" => url + xml.id url + xml.updated item.event_datetime.xmlschema + author = item.event_author if item.respond_to?(:event_author) + xml.author do + xml.name(author) + xml.email(author.mail) if author.is_a?(User) && !author.mail.blank? && !author.pref.hide_mail + end if author + xml.content "type" => "html" do + xml.text! textilizable(item, :event_description, :only_path => false) + end + end + end +end diff --git a/app/views/context_menus/issues.html.erb b/app/views/context_menus/issues.html.erb new file mode 100644 index 00000000..b30c3a81 --- /dev/null +++ b/app/views/context_menus/issues.html.erb @@ -0,0 +1,139 @@ +
      + <%= call_hook(:view_issues_context_menu_start, {:issues => @issues, :can => @can, :back => @back }) %> + + <% if @issue -%> +
    • <%= context_menu_link l(:button_edit), edit_issue_path(@issue), + :class => 'icon-edit', :disabled => !@can[:edit] %>
    • + <% else %> +
    • <%= context_menu_link l(:button_edit), bulk_edit_issues_path(:ids => @issue_ids), + :class => 'icon-edit', :disabled => !@can[:edit] %>
    • + <% end %> + + <% if @allowed_statuses.present? %> +
    • + <%= l(:field_status) %> +
        + <% @allowed_statuses.each do |s| -%> +
      • <%= context_menu_link h(s.name), bulk_update_issues_path(:ids => @issue_ids, :issue => {:status_id => s}, :back_url => @back), :method => :post, + :selected => (@issue && s == @issue.status), :disabled => !@can[:update] %>
      • + <% end -%> +
      +
    • + <% end %> + + <% if @trackers.present? %> +
    • + <%= l(:field_tracker) %> +
        + <% @trackers.each do |t| -%> +
      • <%= context_menu_link h(t.name), bulk_update_issues_path(:ids => @issue_ids, :issue => {'tracker_id' => t}, :back_url => @back), :method => :post, + :selected => (@issue && t == @issue.tracker), :disabled => !@can[:edit] %>
      • + <% end -%> +
      +
    • + <% end %> + + <% if @safe_attributes.include?('priority_id') && @priorities.present? -%> +
    • + <%= l(:field_priority) %> +
        + <% @priorities.each do |p| -%> +
      • <%= context_menu_link h(p.name), bulk_update_issues_path(:ids => @issue_ids, :issue => {'priority_id' => p}, :back_url => @back), :method => :post, + :selected => (@issue && p == @issue.priority), :disabled => (!@can[:edit] || @issues.detect {|i| !i.leaf?}) %>
      • + <% end -%> +
      +
    • + <% end %> + + <% if @safe_attributes.include?('fixed_version_id') && @versions.present? -%> +
    • + <%= l(:field_fixed_version) %> +
        + <% @versions.sort.each do |v| -%> +
      • <%= context_menu_link format_version_name(v), bulk_update_issues_path(:ids => @issue_ids, :issue => {'fixed_version_id' => v}, :back_url => @back), :method => :post, + :selected => (@issue && v == @issue.fixed_version), :disabled => !@can[:update] %>
      • + <% end -%> +
      • <%= context_menu_link l(:label_none), bulk_update_issues_path(:ids => @issue_ids, :issue => {'fixed_version_id' => 'none'}, :back_url => @back), :method => :post, + :selected => (@issue && @issue.fixed_version.nil?), :disabled => !@can[:update] %>
      • +
      +
    • + <% end %> + + <% if @safe_attributes.include?('assigned_to_id') && @assignables.present? -%> +
    • + <%= l(:field_assigned_to) %> +
        + <% if @assignables.include?(User.current) %> +
      • <%= context_menu_link "<< #{l(:label_me)} >>", bulk_update_issues_path(:ids => @issue_ids, :issue => {'assigned_to_id' => User.current}, :back_url => @back), :method => :post, + :disabled => !@can[:update] %>
      • + <% end %> + <% @assignables.each do |u| -%> +
      • <%= context_menu_link h(u.name), bulk_update_issues_path(:ids => @issue_ids, :issue => {'assigned_to_id' => u}, :back_url => @back), :method => :post, + :selected => (@issue && u == @issue.assigned_to), :disabled => !@can[:update] %>
      • + <% end -%> +
      • <%= context_menu_link l(:label_nobody), bulk_update_issues_path(:ids => @issue_ids, :issue => {'assigned_to_id' => 'none'}, :back_url => @back), :method => :post, + :selected => (@issue && @issue.assigned_to.nil?), :disabled => !@can[:update] %>
      • +
      +
    • + <% end %> + + <% if @safe_attributes.include?('category_id') && @project && @project.issue_categories.any? -%> +
    • + <%= l(:field_category) %> +
        + <% @project.issue_categories.each do |u| -%> +
      • <%= context_menu_link h(u.name), bulk_update_issues_path(:ids => @issue_ids, :issue => {'category_id' => u}, :back_url => @back), :method => :post, + :selected => (@issue && u == @issue.category), :disabled => !@can[:update] %>
      • + <% end -%> +
      • <%= context_menu_link l(:label_none), bulk_update_issues_path(:ids => @issue_ids, :issue => {'category_id' => 'none'}, :back_url => @back), :method => :post, + :selected => (@issue && @issue.category.nil?), :disabled => !@can[:update] %>
      • +
      +
    • + <% end -%> + + <% if @safe_attributes.include?('done_ratio') && Issue.use_field_for_done_ratio? %> +
    • + <%= l(:field_done_ratio) %> +
        + <% (0..10).map{|x|x*10}.each do |p| -%> +
      • <%= context_menu_link "#{p}%", bulk_update_issues_path(:ids => @issue_ids, :issue => {'done_ratio' => p}, :back_url => @back), :method => :post, + :selected => (@issue && p == @issue.done_ratio), :disabled => (!@can[:edit] || @issues.detect {|i| !i.leaf?}) %>
      • + <% end -%> +
      +
    • + <% end %> + + <% @options_by_custom_field.each do |field, options| %> +
    • + <%= h(field.name) %> +
        + <% options.each do |text, value| %> +
      • <%= bulk_update_custom_field_context_menu_link(field, text, value || text) %>
      • + <% end %> + <% unless field.is_required? %> +
      • <%= bulk_update_custom_field_context_menu_link(field, l(:label_none), '__none__') %>
      • + <% end %> +
      +
    • + <% end %> + +<% if User.current.logged? %> +
    • <%= watcher_link(@issues, User.current) %>
    • +<% end %> + +<% if @issue.present? %> + <% if @can[:log_time] -%> +
    • <%= context_menu_link l(:button_log_time), new_issue_time_entry_path(@issue), + :class => 'icon-time-add' %>
    • + <% end %> +
    • <%= context_menu_link l(:button_copy), project_copy_issue_path(@project, @issue), + :class => 'icon-copy', :disabled => !@can[:copy] %>
    • +<% else %> +
    • <%= context_menu_link l(:button_copy), bulk_edit_issues_path(:ids => @issue_ids, :copy => '1'), + :class => 'icon-copy', :disabled => !@can[:move] %>
    • +<% end %> +
    • <%= context_menu_link l(:button_delete), issues_path(:ids => @issue_ids, :back_url => @back), + :method => :delete, :data => {:confirm => issues_destroy_confirmation_message(@issues)}, :class => 'icon-del', :disabled => !@can[:delete] %>
    • + + <%= call_hook(:view_issues_context_menu_end, {:issues => @issues, :can => @can, :back => @back }) %> +
    diff --git a/app/views/context_menus/time_entries.html.erb b/app/views/context_menus/time_entries.html.erb new file mode 100644 index 00000000..10dbcafd --- /dev/null +++ b/app/views/context_menus/time_entries.html.erb @@ -0,0 +1,33 @@ +
      + <% if !@time_entry.nil? -%> +
    • <%= context_menu_link l(:button_edit), {:controller => 'timelog', :action => 'edit', :id => @time_entry}, + :class => 'icon-edit', :disabled => !@can[:edit] %>
    • + <% else %> +
    • <%= context_menu_link l(:button_edit), {:controller => 'timelog', :action => 'bulk_edit', :ids => @time_entries.collect(&:id)}, + :class => 'icon-edit', :disabled => !@can[:edit] %>
    • + <% end %> + + <%= call_hook(:view_time_entries_context_menu_start, {:time_entries => @time_entries, :can => @can, :back => @back }) %> + + <% if @activities.present? -%> +
    • + <%= l(:field_activity) %> +
        + <% @activities.each do |u| -%> +
      • <%= context_menu_link h(u.name), {:controller => 'timelog', :action => 'bulk_update', :ids => @time_entries.collect(&:id), :time_entry => {'activity_id' => u}, :back_url => @back}, :method => :post, + :selected => (@time_entry && u == @time_entry.activity), :disabled => !@can[:edit] %>
      • + <% end -%> +
      • <%= context_menu_link l(:label_none), {:controller => 'timelog', :action => 'bulk_update', :ids => @time_entries.collect(&:id), :time_entry => {'activity_id' => 'none'}, :back_url => @back}, :method => :post, + :selected => (@time_entry && @time_entry.activity.nil?), :disabled => !@can[:edit] %>
      • +
      +
    • + <% end %> + + <%= call_hook(:view_time_entries_context_menu_end, {:time_entries => @time_entries, :can => @can, :back => @back }) %> + +
    • + <%= context_menu_link l(:button_delete), + {:controller => 'timelog', :action => 'destroy', :ids => @time_entries.collect(&:id), :back_url => @back}, + :method => :delete, :data => {:confirm => l(:text_time_entries_destroy_confirmation)}, :class => 'icon-del', :disabled => !@can[:delete] %> +
    • +
    diff --git a/app/views/custom_fields/_form.html.erb b/app/views/custom_fields/_form.html.erb new file mode 100644 index 00000000..b6f7ddb1 --- /dev/null +++ b/app/views/custom_fields/_form.html.erb @@ -0,0 +1,99 @@ +<%= error_messages_for 'custom_field' %> + +
    +

    <%= f.text_field :name, :required => true %>

    +

    <%= f.select :field_format, custom_field_formats_for_select(@custom_field), {}, :disabled => !@custom_field.new_record? %>

    + +<% if @custom_field.format_in? 'list', 'user', 'version' %> +

    + <%= f.check_box :multiple %> + <% if !@custom_field.new_record? && @custom_field.multiple %> + <%= l(:text_turning_multiple_off) %> + <% end %> +

    +<% end %> + +<% unless @custom_field.format_in? 'list', 'bool', 'date', 'user', 'version' %> +

    + <%= f.text_field :min_length, :size => 5, :no_label => true %> - + <%= f.text_field :max_length, :size => 5, :no_label => true %>
    (<%=l(:text_min_max_length_info)%>)

    +

    <%= f.text_field :regexp, :size => 50 %>
    (<%=l(:text_regexp_info)%>)

    +<% end %> + +<% if @custom_field.format_in? 'list' %> +

    + <%= f.text_area :possible_values, :value => @custom_field.possible_values.to_a.join("\n"), :rows => 15 %> + <%= l(:text_custom_field_possible_values_info) %> +

    +<% end %> + +<% case @custom_field.field_format %> +<% when 'bool' %> +

    <%= f.check_box(:default_value) %>

    +<% when 'text' %> +

    <%= f.text_area(:default_value, :rows => 8) %>

    +<% when 'date' %> +

    <%= f.text_field(:default_value, :size => 10) %>

    + <%= calendar_for('custom_field_default_value') %> +<% when 'user', 'version' %> +<% else %> +

    <%= f.text_field(:default_value) %>

    +<% end %> + +<%= call_hook(:view_custom_fields_form_upper_box, :custom_field => @custom_field, :form => f) %> +
    + +
    +<% case @custom_field.class.name +when "IssueCustomField" %> + +
    <%=l(:label_tracker_plural)%> + <% Tracker.sorted.all.each do |tracker| %> + <%= check_box_tag "custom_field[tracker_ids][]", + tracker.id, + (@custom_field.trackers.include? tracker), + :id => "custom_field_tracker_ids_#{tracker.id}" %> + + <% end %> + <%= hidden_field_tag "custom_field[tracker_ids][]", '' %> +
    +   +

    <%= f.check_box :is_required %>

    +

    <%= f.check_box :is_for_all %>

    +

    <%= f.check_box :is_filter %>

    +

    <%= f.check_box :searchable %>

    + +<% when "UserCustomField" %> +

    <%= f.check_box :is_required %>

    +

    <%= f.check_box :visible %>

    +

    <%= f.check_box :editable %>

    +

    <%= f.check_box :is_filter %>

    + +<% when "ProjectCustomField" %> +

    <%= f.check_box :is_required %>

    +

    <%= f.check_box :visible %>

    +

    <%= f.check_box :searchable %>

    +

    <%= f.check_box :is_filter %>

    + +<% when "VersionCustomField" %> +

    <%= f.check_box :is_required %>

    +

    <%= f.check_box :is_filter %>

    + +<% when "GroupCustomField" %> +

    <%= f.check_box :is_required %>

    +

    <%= f.check_box :is_filter %>

    + +<% when "TimeEntryCustomField" %> +

    <%= f.check_box :is_required %>

    +

    <%= f.check_box :is_filter %>

    + +<% else %> +

    <%= f.check_box :is_required %>

    + +<% end %> +<%= call_hook(:"view_custom_fields_form_#{@custom_field.type.to_s.underscore}", :custom_field => @custom_field, :form => f) %> +
    + +<% include_calendar_headers_tags %> diff --git a/app/views/custom_fields/_index.html.erb b/app/views/custom_fields/_index.html.erb new file mode 100644 index 00000000..79fc09ae --- /dev/null +++ b/app/views/custom_fields/_index.html.erb @@ -0,0 +1,32 @@ + + + + + + <% if tab[:name] == 'IssueCustomField' %> + + + <% end %> + + + + + <% (@custom_fields_by_type[tab[:name]] || []).sort.each do |custom_field| -%> + "> + + + + <% if tab[:name] == 'IssueCustomField' %> + + + <% end %> + + + + <% end; reset_cycle %> + +
    <%=l(:field_name)%><%=l(:field_field_format)%><%=l(:field_is_required)%><%=l(:field_is_for_all)%><%=l(:label_used_by)%><%=l(:button_sort)%>
    <%= link_to h(custom_field.name), edit_custom_field_path(custom_field) %><%= l(Redmine::CustomFieldFormat.label_for(custom_field.field_format)) %><%= checked_image custom_field.is_required? %><%= checked_image custom_field.is_for_all? %><%= l(:label_x_projects, :count => custom_field.projects.count) if custom_field.is_a? IssueCustomField and !custom_field.is_for_all? %><%= reorder_links('custom_field', {:action => 'update', :id => custom_field}, :put) %> + <%= delete_link custom_field_path(custom_field) %> +
    + +

    <%= link_to l(:label_custom_field_new), new_custom_field_path(:type => tab[:name]), :class => 'icon icon-add' %>

    diff --git a/app/views/custom_fields/edit.html.erb b/app/views/custom_fields/edit.html.erb new file mode 100644 index 00000000..7f62c037 --- /dev/null +++ b/app/views/custom_fields/edit.html.erb @@ -0,0 +1,8 @@ +

    <%= link_to l(:label_custom_field_plural), :controller => 'custom_fields', :action => 'index' %> + » <%= link_to l(@custom_field.type_name), :controller => 'custom_fields', :action => 'index', :tab => @custom_field.class.name %> + » <%=h @custom_field.name %>

    + +<%= labelled_form_for :custom_field, @custom_field, :url => custom_field_path(@custom_field), :html => {:method => :put, :id => 'custom_field_form'} do |f| %> +<%= render :partial => 'form', :locals => { :f => f } %> +<%= submit_tag l(:button_save) %> +<% end %> diff --git a/app/views/custom_fields/index.html.erb b/app/views/custom_fields/index.html.erb new file mode 100644 index 00000000..fd43ea82 --- /dev/null +++ b/app/views/custom_fields/index.html.erb @@ -0,0 +1,5 @@ +

    <%=l(:label_custom_field_plural)%>

    + +<%= render_tabs custom_fields_tabs %> + +<% html_title(l(:label_custom_field_plural)) -%> diff --git a/app/views/custom_fields/new.html.erb b/app/views/custom_fields/new.html.erb new file mode 100644 index 00000000..a0c8ac08 --- /dev/null +++ b/app/views/custom_fields/new.html.erb @@ -0,0 +1,19 @@ +

    <%= link_to l(:label_custom_field_plural), :controller => 'custom_fields', :action => 'index' %> + » <%= link_to l(@custom_field.type_name), :controller => 'custom_fields', :action => 'index', :tab => @custom_field.class.name %> + » <%= l(:label_custom_field_new) %>

    + +<%= labelled_form_for :custom_field, @custom_field, :url => custom_fields_path, :html => {:id => 'custom_field_form'} do |f| %> +<%= render :partial => 'form', :locals => { :f => f } %> +<%= hidden_field_tag 'type', @custom_field.type %> +<%= submit_tag l(:button_save) %> +<% end %> + +<%= javascript_tag do %> +$('#custom_field_field_format').change(function(){ + $.ajax({ + url: '<%= new_custom_field_path(:format => 'js') %>', + type: 'get', + data: $('#custom_field_form').serialize() + }); +}); +<% end %> diff --git a/app/views/custom_fields/new.js.erb b/app/views/custom_fields/new.js.erb new file mode 100644 index 00000000..d77c97f0 --- /dev/null +++ b/app/views/custom_fields/new.js.erb @@ -0,0 +1 @@ +$('#content').html('<%= escape_javascript(render :template => 'custom_fields/new', :layout => nil, :formats => [:html]) %>') diff --git a/app/views/documents/_document.html.erb b/app/views/documents/_document.html.erb new file mode 100644 index 00000000..e14d880a --- /dev/null +++ b/app/views/documents/_document.html.erb @@ -0,0 +1,6 @@ +

    <%= link_to h(document.title), document_path(document) %>

    +

    <%= format_time(document.updated_on) %>

    + +
    + <%= textilizable(truncate_lines(document.description), :object => document) %> +
    diff --git a/app/views/documents/_form.html.erb b/app/views/documents/_form.html.erb new file mode 100644 index 00000000..53d8fc3b --- /dev/null +++ b/app/views/documents/_form.html.erb @@ -0,0 +1,15 @@ +<%= error_messages_for @document %> + +
    +

    <%= f.select :category_id, DocumentCategory.active.collect {|c| [c.name, c.id]} %>

    +

    <%= f.text_field :title, :required => true, :size => 60 %>

    +

    <%= f.text_area :description, :cols => 60, :rows => 15, :class => 'wiki-edit' %>

    +
    + +<%= wikitoolbar_for 'document_description' %> + +<% if @document.new_record? %> +
    +

    <%= render :partial => 'attachments/form', :locals => {:container => @document} %>

    +
    +<% end %> diff --git a/app/views/documents/edit.html.erb b/app/views/documents/edit.html.erb new file mode 100644 index 00000000..8a6122f8 --- /dev/null +++ b/app/views/documents/edit.html.erb @@ -0,0 +1,8 @@ +

    <%=l(:label_document)%>

    + +<%= labelled_form_for @document do |f| %> + <%= render :partial => 'form', :locals => {:f => f} %> +

    <%= submit_tag l(:button_save) %>

    +<% end %> + + diff --git a/app/views/documents/index.html.erb b/app/views/documents/index.html.erb new file mode 100644 index 00000000..28b52456 --- /dev/null +++ b/app/views/documents/index.html.erb @@ -0,0 +1,34 @@ +
    +<%= link_to l(:label_document_new), new_project_document_path(@project), :class => 'icon icon-add', + :onclick => 'showAndScrollTo("add-document", "document_title"); return false;' if User.current.allowed_to?(:add_documents, @project) %> +
    + + + +

    <%=l(:label_document_plural)%>

    + +<% if @grouped.empty? %>

    <%= l(:label_no_data) %>

    <% end %> + +<% @grouped.keys.sort.each do |group| %> +

    <%= group %>

    + <%= render :partial => 'documents/document', :collection => @grouped[group] %> +<% end %> + +<% content_for :sidebar do %> +

    <%= l(:label_sort_by, '') %>

    + <%= link_to l(:field_category), {:sort_by => 'category'}, :class => (@sort_by == 'category' ? 'selected' :nil) %>
    + <%= link_to l(:label_date), {:sort_by => 'date'}, :class => (@sort_by == 'date' ? 'selected' :nil) %>
    + <%= link_to l(:field_title), {:sort_by => 'title'}, :class => (@sort_by == 'title' ? 'selected' :nil) %>
    + <%= link_to l(:field_author), {:sort_by => 'author'}, :class => (@sort_by == 'author' ? 'selected' :nil) %> +<% end %> + +<% html_title(l(:label_document_plural)) -%> diff --git a/app/views/documents/new.html.erb b/app/views/documents/new.html.erb new file mode 100644 index 00000000..e90bf7e2 --- /dev/null +++ b/app/views/documents/new.html.erb @@ -0,0 +1,6 @@ +

    <%=l(:label_document_new)%>

    + +<%= labelled_form_for @document, :url => project_documents_path(@project), :html => {:multipart => true} do |f| %> + <%= render :partial => 'form', :locals => {:f => f} %> +

    <%= submit_tag l(:button_create) %>

    +<% end %> diff --git a/app/views/documents/show.html.erb b/app/views/documents/show.html.erb new file mode 100644 index 00000000..99bcc2a0 --- /dev/null +++ b/app/views/documents/show.html.erb @@ -0,0 +1,32 @@ +
    +<% if User.current.allowed_to?(:edit_documents, @project) %> +<%= link_to l(:button_edit), edit_document_path(@document), :class => 'icon icon-edit', :accesskey => accesskey(:edit) %> +<% end %> +<% if User.current.allowed_to?(:delete_documents, @project) %> +<%= delete_link document_path(@document) %> +<% end %> +
    + +

    <%=h @document.title %>

    + +

    <%=h @document.category.name %>
    +<%= format_date @document.created_on %>

    +
    +<%= textilizable @document.description, :attachments => @document.attachments %> +
    + +

    <%= l(:label_attachment_plural) %>

    +<%= link_to_attachments @document %> + +<% if authorize_for('documents', 'add_attachment') %> +

    <%= link_to l(:label_attachment_new), {}, :onclick => "$('#add_attachment_form').show(); return false;", + :id => 'attach_files_link' %>

    + <%= form_tag({ :controller => 'documents', :action => 'add_attachment', :id => @document }, :multipart => true, :id => "add_attachment_form", :style => "display:none;") do %> +
    +

    <%= render :partial => 'attachments/form' %>

    +
    + <%= submit_tag l(:button_add) %> + <% end %> +<% end %> + +<% html_title @document.title -%> diff --git a/app/views/enumerations/_form.html.erb b/app/views/enumerations/_form.html.erb new file mode 100644 index 00000000..8ff774d9 --- /dev/null +++ b/app/views/enumerations/_form.html.erb @@ -0,0 +1,11 @@ +<%= error_messages_for 'enumeration' %> + +
    +

    <%= f.text_field :name %>

    +

    <%= f.check_box :active %>

    +

    <%= f.check_box :is_default %>

    + + <% @enumeration.custom_field_values.each do |value| %> +

    <%= custom_field_tag_with_label :enumeration, value %>

    + <% end %> +
    diff --git a/app/views/enumerations/destroy.html.erb b/app/views/enumerations/destroy.html.erb new file mode 100644 index 00000000..3c595e03 --- /dev/null +++ b/app/views/enumerations/destroy.html.erb @@ -0,0 +1,12 @@ +

    <%= l(@enumeration.option_name) %>: <%=h @enumeration %>

    + +<%= form_tag({}, :method => :delete) do %> +
    +

    <%= l(:text_enumeration_destroy_question, @enumeration.objects_count) %>

    +

    +<%= select_tag 'reassign_to_id', (content_tag('option', "--- #{l(:actionview_instancetag_blank_option)} ---") + options_from_collection_for_select(@enumerations, 'id', 'name')) %>

    +
    + +<%= submit_tag l(:button_apply) %> +<%= link_to l(:button_cancel), enumerations_path %> +<% end %> diff --git a/app/views/enumerations/edit.html.erb b/app/views/enumerations/edit.html.erb new file mode 100644 index 00000000..c3c0b895 --- /dev/null +++ b/app/views/enumerations/edit.html.erb @@ -0,0 +1,6 @@ +

    <%= link_to l(@enumeration.option_name), enumerations_path %> » <%=h @enumeration %>

    + +<%= labelled_form_for :enumeration, @enumeration, :url => enumeration_path(@enumeration), :html => {:method => :put} do |f| %> + <%= render :partial => 'form', :locals => {:f => f} %> + <%= submit_tag l(:button_save) %> +<% end %> diff --git a/app/views/enumerations/index.api.rsb b/app/views/enumerations/index.api.rsb new file mode 100644 index 00000000..2fc70b98 --- /dev/null +++ b/app/views/enumerations/index.api.rsb @@ -0,0 +1,9 @@ +api.array @klass.name.underscore.pluralize do + @enumerations.each do |enumeration| + api.__send__ @klass.name.underscore do + api.id enumeration.id + api.name enumeration.name + api.is_default enumeration.is_default + end + end +end diff --git a/app/views/enumerations/index.html.erb b/app/views/enumerations/index.html.erb new file mode 100644 index 00000000..fe7634bf --- /dev/null +++ b/app/views/enumerations/index.html.erb @@ -0,0 +1,34 @@ +

    <%=l(:label_enumerations)%>

    + +<% Enumeration.get_subclasses.each do |klass| %> +

    <%= l(klass::OptionName) %>

    + +<% enumerations = klass.shared %> +<% if enumerations.any? %> + + + + + + + + +<% enumerations.each do |enumeration| %> + + + + + + + +<% end %> +
    <%= l(:field_name) %><%= l(:field_is_default) %><%= l(:field_active) %>
    <%= link_to h(enumeration), edit_enumeration_path(enumeration) %><%= checked_image enumeration.is_default? %><%= checked_image enumeration.active? %><%= reorder_links('enumeration', {:action => 'update', :id => enumeration}, :put) %> + <%= delete_link enumeration_path(enumeration) %> +
    +<% reset_cycle %> +<% end %> + +

    <%= link_to l(:label_enumeration_new), new_enumeration_path(:type => klass.name) %>

    +<% end %> + +<% html_title(l(:label_enumerations)) -%> diff --git a/app/views/enumerations/new.html.erb b/app/views/enumerations/new.html.erb new file mode 100644 index 00000000..216b4929 --- /dev/null +++ b/app/views/enumerations/new.html.erb @@ -0,0 +1,7 @@ +

    <%= link_to l(@enumeration.option_name), enumerations_path %> » <%=l(:label_enumeration_new)%>

    + +<%= labelled_form_for :enumeration, @enumeration, :url => enumerations_path do |f| %> + <%= f.hidden_field :type %> + <%= render :partial => 'form', :locals => {:f => f} %> + <%= submit_tag l(:button_create) %> +<% end %> diff --git a/app/views/files/index.html.erb b/app/views/files/index.html.erb new file mode 100644 index 00000000..e83ddc87 --- /dev/null +++ b/app/views/files/index.html.erb @@ -0,0 +1,46 @@ +
    +<%= link_to(l(:label_attachment_new), new_project_file_path(@project), :class => 'icon icon-add') if User.current.allowed_to?(:manage_files, @project) %> +
    + +

    <%=l(:label_attachment_plural)%>

    + +<% delete_allowed = User.current.allowed_to?(:manage_files, @project) %> + + + + <%= sort_header_tag('filename', :caption => l(:field_filename)) %> + <%= sort_header_tag('created_on', :caption => l(:label_date), :default_order => 'desc') %> + <%= sort_header_tag('size', :caption => l(:field_filesize), :default_order => 'desc') %> + <%= sort_header_tag('downloads', :caption => l(:label_downloads_abbr), :default_order => 'desc') %> + + + + +<% @containers.each do |container| %> + <% next if container.attachments.empty? -%> + <% if container.is_a?(Version) -%> + + + + <% end -%> + <% container.attachments.each do |file| %> + "> + + + + + + + + <% end + reset_cycle %> +<% end %> + +
    MD5
    + <%= link_to(h(container), {:controller => 'versions', :action => 'show', :id => container}, :class => "icon icon-package") %> +
    <%= link_to_attachment file, :download => true, :title => file.description %><%= format_time(file.created_on) %><%= number_to_human_size(file.filesize) %><%= file.downloads %><%= file.digest %> + <%= link_to(image_tag('delete.png'), attachment_path(file), + :data => {:confirm => l(:text_are_you_sure)}, :method => :delete) if delete_allowed %> +
    + +<% html_title(l(:label_attachment_plural)) -%> diff --git a/app/views/files/new.html.erb b/app/views/files/new.html.erb new file mode 100644 index 00000000..2558d8b1 --- /dev/null +++ b/app/views/files/new.html.erb @@ -0,0 +1,16 @@ +

    <%=l(:label_attachment_new)%>

    + +<%= error_messages_for 'attachment' %> +<%= form_tag(project_files_path(@project), :multipart => true, :class => "tabular") do %> +
    + +<% if @versions.any? %> +

    +<%= select_tag "version_id", content_tag('option', '') + + options_from_collection_for_select(@versions, "id", "name") %>

    +<% end %> + +

    <%= render :partial => 'attachments/form' %>

    +
    +<%= submit_tag l(:button_add) %> +<% end %> diff --git a/app/views/gantts/show.html.erb b/app/views/gantts/show.html.erb new file mode 100644 index 00000000..6ec18925 --- /dev/null +++ b/app/views/gantts/show.html.erb @@ -0,0 +1,319 @@ +<% @gantt.view = self %> +

    <%= @query.new_record? ? l(:label_gantt) : h(@query.name) %>

    + +<%= form_tag({:controller => 'gantts', :action => 'show', + :project_id => @project, :month => params[:month], + :year => params[:year], :months => params[:months]}, + :method => :get, :id => 'query_form') do %> +<%= hidden_field_tag 'set_filter', '1' %> +
    "> + <%= l(:label_filter_plural) %> +
    "> + <%= render :partial => 'queries/filters', :locals => {:query => @query} %> +
    +
    + + +

    + <%= gantt_zoom_link(@gantt, :in) %> + <%= gantt_zoom_link(@gantt, :out) %> +

    + +

    +<%= text_field_tag 'months', @gantt.months, :size => 2 %> +<%= l(:label_months_from) %> +<%= select_month(@gantt.month_from, :prefix => "month", :discard_type => true) %> +<%= select_year(@gantt.year_from, :prefix => "year", :discard_type => true) %> +<%= hidden_field_tag 'zoom', @gantt.zoom %> + +<%= link_to_function l(:button_apply), '$("#query_form").submit()', + :class => 'icon icon-checked' %> +<%= link_to l(:button_clear), { :project_id => @project, :set_filter => 1 }, + :class => 'icon icon-reload' %> +

    +<% end %> + +<%= error_messages_for 'query' %> +<% if @query.valid? %> +<% + zoom = 1 + @gantt.zoom.times { zoom = zoom * 2 } + + subject_width = 330 + header_height = 18 + + headers_height = header_height + show_weeks = false + show_days = false + + if @gantt.zoom > 1 + show_weeks = true + headers_height = 2 * header_height + if @gantt.zoom > 2 + show_days = true + headers_height = 3 * header_height + end + end + + # Width of the entire chart + g_width = ((@gantt.date_to - @gantt.date_from + 1) * zoom).to_i + @gantt.render(:top => headers_height + 8, + :zoom => zoom, + :g_width => g_width, + :subject_width => subject_width) + g_height = [(20 * (@gantt.number_of_rows + 6)) + 150, 206].max + t_height = g_height + headers_height +%> + +<% if @gantt.truncated %> +

    <%= l(:notice_gantt_chart_truncated, :max => @gantt.max_rows) %>

    +<% end %> + + + + + + + +
    + <% + style = "" + style += "position:relative;" + style += "height: #{t_height + 24}px;" + style += "width: #{subject_width + 1}px;" + %> + <%= content_tag(:div, :style => style) do %> + <% + style = "" + style += "right:-2px;" + style += "width: #{subject_width}px;" + style += "height: #{headers_height}px;" + style += 'background: #eee;' + %> + <%= content_tag(:div, "", :style => style, :class => "gantt_hdr") %> + <% + style = "" + style += "right:-2px;" + style += "width: #{subject_width}px;" + style += "height: #{t_height}px;" + style += 'border-left: 1px solid #c0c0c0;' + style += 'overflow: hidden;' + %> + <%= content_tag(:div, "", :style => style, :class => "gantt_hdr") %> + <%= content_tag(:div, :class => "gantt_subjects") do %> + <%= @gantt.subjects.html_safe %> + <% end %> + <% end %> + +
    +<% + style = "" + style += "width: #{g_width - 1}px;" + style += "height: #{headers_height}px;" + style += 'background: #eee;' +%> +<%= content_tag(:div, ' '.html_safe, :style => style, :class => "gantt_hdr") %> + +<% ###### Months headers ###### %> +<% + month_f = @gantt.date_from + left = 0 + height = (show_weeks ? header_height : header_height + g_height) +%> +<% @gantt.months.times do %> + <% + width = (((month_f >> 1) - month_f) * zoom - 1).to_i + style = "" + style += "left: #{left}px;" + style += "width: #{width}px;" + style += "height: #{height}px;" + %> + <%= content_tag(:div, :style => style, :class => "gantt_hdr") do %> + <%= link_to h("#{month_f.year}-#{month_f.month}"), + @gantt.params.merge(:year => month_f.year, :month => month_f.month), + :title => "#{month_name(month_f.month)} #{month_f.year}" %> + <% end %> + <% + left = left + width + 1 + month_f = month_f >> 1 + %> +<% end %> + +<% ###### Weeks headers ###### %> +<% if show_weeks %> + <% + left = 0 + height = (show_days ? header_height - 1 : header_height - 1 + g_height) + %> + <% if @gantt.date_from.cwday == 1 %> + <% + # @date_from is monday + week_f = @gantt.date_from + %> + <% else %> + <% + # find next monday after @date_from + week_f = @gantt.date_from + (7 - @gantt.date_from.cwday + 1) + width = (7 - @gantt.date_from.cwday + 1) * zoom - 1 + style = "" + style += "left: #{left}px;" + style += "top: 19px;" + style += "width: #{width}px;" + style += "height: #{height}px;" + %> + <%= content_tag(:div, ' '.html_safe, + :style => style, :class => "gantt_hdr") %> + <% left = left + width + 1 %> + <% end %> + <% while week_f <= @gantt.date_to %> + <% + width = ((week_f + 6 <= @gantt.date_to) ? + 7 * zoom - 1 : + (@gantt.date_to - week_f + 1) * zoom - 1).to_i + style = "" + style += "left: #{left}px;" + style += "top: 19px;" + style += "width: #{width}px;" + style += "height: #{height}px;" + %> + <%= content_tag(:div, :style => style, :class => "gantt_hdr") do %> + <%= content_tag(:small) do %> + <%= week_f.cweek if width >= 16 %> + <% end %> + <% end %> + <% + left = left + width + 1 + week_f = week_f + 7 + %> + <% end %> +<% end %> + +<% ###### Days headers ####### %> +<% if show_days %> + <% + left = 0 + height = g_height + header_height - 1 + wday = @gantt.date_from.cwday + %> + <% (@gantt.date_to - @gantt.date_from + 1).to_i.times do %> + <% + width = zoom - 1 + style = "" + style += "left: #{left}px;" + style += "top:37px;" + style += "width: #{width}px;" + style += "height: #{height}px;" + style += "font-size:0.7em;" + clss = "gantt_hdr" + clss << " nwday" if @gantt.non_working_week_days.include?(wday) + %> + <%= content_tag(:div, :style => style, :class => clss) do %> + <%= day_letter(wday) %> + <% end %> + <% + left = left + width + 1 + wday = wday + 1 + wday = 1 if wday > 7 + %> + <% end %> +<% end %> + +<%= @gantt.lines.html_safe %> + +<% ###### Today red line (excluded from cache) ###### %> +<% if Date.today >= @gantt.date_from and Date.today <= @gantt.date_to %> + <% + today_left = (((Date.today - @gantt.date_from + 1) * zoom).floor() - 1).to_i + style = "" + style += "position: absolute;" + style += "height: #{g_height}px;" + style += "top: #{headers_height + 1}px;" + style += "left: #{today_left}px;" + style += "width:10px;" + style += "border-left: 1px dashed red;" + %> + <%= content_tag(:div, ' '.html_safe, :style => style, :id => 'today_line') %> +<% end %> +<% + style = "" + style += "position: absolute;" + style += "height: #{g_height}px;" + style += "top: #{headers_height + 1}px;" + style += "left: 0px;" + style += "width: #{g_width - 1}px;" +%> +<%= content_tag(:div, '', :style => style, :id => "gantt_draw_area") %> +
    +
    + + + + + + +
    + <%= link_to_content_update("\xc2\xab " + l(:label_previous), + params.merge(@gantt.params_previous)) %> + + <%= link_to_content_update(l(:label_next) + " \xc2\xbb", + params.merge(@gantt.params_next)) %> +
    + +<% other_formats_links do |f| %> + <%= f.link_to 'PDF', :url => params.merge(@gantt.params) %> + <%= f.link_to('PNG', :url => params.merge(@gantt.params)) if @gantt.respond_to?('to_image') %> +<% end %> +<% end # query.valid? %> + +<% content_for :sidebar do %> + <%= render :partial => 'issues/sidebar' %> +<% end %> + +<% html_title(l(:label_gantt)) -%> + +<% content_for :header_tags do %> + <%= javascript_include_tag 'raphael' %> + <%= javascript_include_tag 'gantt' %> +<% end %> + +<%= javascript_tag do %> + var issue_relation_type = <%= raw Redmine::Helpers::Gantt::DRAW_TYPES.to_json %>; + $(document).ready(drawGanttHandler); + $(window).resize(drawGanttHandler); + $(function() { + $("#draw_rels").change(drawGanttHandler); + $("#draw_progress_line").change(drawGanttHandler); + }); +<% end %> diff --git a/app/views/groups/_form.html.erb b/app/views/groups/_form.html.erb new file mode 100644 index 00000000..7dc22406 --- /dev/null +++ b/app/views/groups/_form.html.erb @@ -0,0 +1,8 @@ +<%= error_messages_for @group %> + +
    +

    <%= f.text_field :name, :required => true, :size => 60 %>

    + <% @group.custom_field_values.each do |value| %> +

    <%= custom_field_tag_with_label :group, value %>

    + <% end %> +
    diff --git a/app/views/groups/_general.html.erb b/app/views/groups/_general.html.erb new file mode 100644 index 00000000..8c720c3e --- /dev/null +++ b/app/views/groups/_general.html.erb @@ -0,0 +1,4 @@ +<%= labelled_form_for @group do |f| %> +<%= render :partial => 'form', :locals => { :f => f } %> +<%= submit_tag l(:button_save) %> +<% end %> diff --git a/app/views/groups/_memberships.html.erb b/app/views/groups/_memberships.html.erb new file mode 100644 index 00000000..b21958e2 --- /dev/null +++ b/app/views/groups/_memberships.html.erb @@ -0,0 +1,65 @@ +<% roles = Role.find_all_givable %> +<% projects = Project.active.all %> + +
    +<% if @group.memberships.any? %> + + + + + + + + <% @group.memberships.each do |membership| %> + <% next if membership.new_record? %> + + + + + +<% end; reset_cycle %> + +
    <%= l(:label_project) %><%= l(:label_role_plural) %>
    <%= link_to_project membership.project %> + <%=h membership.roles.sort.collect(&:to_s).join(', ') %> + <%= form_for(:membership, :remote => true, + :url => { :action => 'edit_membership', :id => @group, :membership_id => membership }, + :html => { :id => "member-#{membership.id}-roles-form", :style => 'display:none;'}) do %> +

    <% roles.each do |role| %> +
    + <% end %>

    +

    <%= submit_tag l(:button_change) %> + <%= link_to_function( + l(:button_cancel), + "$('#member-#{membership.id}-roles').show(); $('#member-#{membership.id}-roles-form').hide(); return false;" + ) %>

    + <% end %> +
    + <%= link_to_function( + l(:button_edit), + "$('#member-#{membership.id}-roles').hide(); $('#member-#{membership.id}-roles-form').show(); return false;", + :class => 'icon icon-edit' + ) %> + <%= delete_link({:controller => 'groups', :action => 'destroy_membership', :id => @group, :membership_id => membership}, + :remote => true, + :method => :post) %> +
    +<% else %> +

    <%= l(:label_no_data) %>

    +<% end %> +
    + +
    +<% if projects.any? %> +
    <%=l(:label_project_new)%> +<%= form_for(:membership, :remote => true, :url => { :action => 'edit_membership', :id => @group }) do %> +<%= label_tag "membership_project_id", l(:description_choose_project), :class => "hidden-for-sighted" %> +<%= select_tag 'membership[project_id]', options_for_membership_project_select(@group, projects) %> +

    <%= l(:label_role_plural) %>: +<% roles.each do |role| %> + +<% end %>

    +

    <%= submit_tag l(:button_add) %>

    +<% end %> +
    +<% end %> +
    diff --git a/app/views/groups/_users.html.erb b/app/views/groups/_users.html.erb new file mode 100644 index 00000000..a0f89d76 --- /dev/null +++ b/app/views/groups/_users.html.erb @@ -0,0 +1,39 @@ +
    +<% if @group.users.any? %> + + + + + + + <% @group.users.sort.each do |user| %> + + + + + <% end %> + +
    <%= l(:label_user) %>
    <%= link_to_user user %> + <%= delete_link group_user_path(@group, :user_id => user), :remote => true %> +
    +<% else %> +

    <%= l(:label_no_data) %>

    +<% end %> +
    + +
    + <%= form_for(@group, :remote => true, :url => group_users_path(@group), + :html => {:method => :post}) do |f| %> +
    <%=l(:label_user_new)%> + +

    <%= label_tag "user_search", l(:label_user_search) %><%= text_field_tag 'user_search', nil %>

    + <%= javascript_tag "observeSearchfield('user_search', null, '#{ escape_javascript autocomplete_for_user_group_path(@group) }')" %> + +
    + <%= render_principals_for_new_group_users(@group) %> +
    + +

    <%= submit_tag l(:button_add) %>

    +
    + <% end %> +
    diff --git a/app/views/groups/add_users.js.erb b/app/views/groups/add_users.js.erb new file mode 100644 index 00000000..460527b6 --- /dev/null +++ b/app/views/groups/add_users.js.erb @@ -0,0 +1,4 @@ +$('#tab-content-users').html('<%= escape_javascript(render :partial => 'groups/users') %>'); +<% @users.each do |user| %> + $('#user-<%= user.id %>').effect("highlight"); +<% end %> diff --git a/app/views/groups/autocomplete_for_user.js.erb b/app/views/groups/autocomplete_for_user.js.erb new file mode 100644 index 00000000..9bb569ea --- /dev/null +++ b/app/views/groups/autocomplete_for_user.js.erb @@ -0,0 +1 @@ +$('#users').html('<%= escape_javascript(render_principals_for_new_group_users(@group)) %>'); diff --git a/app/views/groups/destroy_membership.js.erb b/app/views/groups/destroy_membership.js.erb new file mode 100644 index 00000000..30ab3b08 --- /dev/null +++ b/app/views/groups/destroy_membership.js.erb @@ -0,0 +1 @@ +$('#tab-content-memberships').html('<%= escape_javascript(render :partial => 'groups/memberships') %>'); diff --git a/app/views/groups/edit.html.erb b/app/views/groups/edit.html.erb new file mode 100644 index 00000000..2dd5c643 --- /dev/null +++ b/app/views/groups/edit.html.erb @@ -0,0 +1,5 @@ +

    <%= link_to l(:label_group_plural), groups_path %> » <%= h(@group) %>

    + +<%= render_tabs group_settings_tabs %> + +<% html_title(l(:label_group), @group, l(:label_administration)) -%> diff --git a/app/views/groups/edit_membership.js.erb b/app/views/groups/edit_membership.js.erb new file mode 100644 index 00000000..679c9986 --- /dev/null +++ b/app/views/groups/edit_membership.js.erb @@ -0,0 +1,6 @@ +<% if @membership.valid? %> + $('#tab-content-memberships').html('<%= escape_javascript(render :partial => 'groups/memberships') %>'); + $('#member-<%= @membership.id %>').effect("highlight"); +<% else %> + alert('<%= raw(escape_javascript(l(:notice_failed_to_save_members, :errors => @membership.errors.full_messages.join(', ')))) %>'); +<% end %> diff --git a/app/views/groups/index.api.rsb b/app/views/groups/index.api.rsb new file mode 100644 index 00000000..6a4efeaf --- /dev/null +++ b/app/views/groups/index.api.rsb @@ -0,0 +1,10 @@ +api.array :groups do + @groups.each do |group| + api.group do + api.id group.id + api.name group.lastname + + render_api_custom_values group.visible_custom_field_values, api + end + end +end diff --git a/app/views/groups/index.html.erb b/app/views/groups/index.html.erb new file mode 100644 index 00000000..a93354ba --- /dev/null +++ b/app/views/groups/index.html.erb @@ -0,0 +1,26 @@ +
    +<%= link_to l(:label_group_new), new_group_path, :class => 'icon icon-add' %> +
    + +

    <%= l(:label_group_plural) %>

    + +<% if @groups.any? %> + + + + + + + +<% @groups.each do |group| %> + + + + + +<% end %> + +
    <%=l(:label_group)%><%=l(:label_user_plural)%>
    <%= link_to h(group), edit_group_path(group) %><%= group.users.size %><%= delete_link group %>
    +<% else %> +

    <%= l(:label_no_data) %>

    +<% end %> diff --git a/app/views/groups/new.html.erb b/app/views/groups/new.html.erb new file mode 100644 index 00000000..20ef7a2a --- /dev/null +++ b/app/views/groups/new.html.erb @@ -0,0 +1,9 @@ +

    <%= link_to l(:label_group_plural), groups_path %> » <%= l(:label_group_new) %>

    + +<%= labelled_form_for @group do |f| %> +<%= render :partial => 'form', :locals => { :f => f } %> +

    + <%= f.submit l(:button_create) %> + <%= f.submit l(:button_create_and_continue), :name => 'continue' %> +

    +<% end %> diff --git a/app/views/groups/remove_user.js.erb b/app/views/groups/remove_user.js.erb new file mode 100644 index 00000000..88daa8f5 --- /dev/null +++ b/app/views/groups/remove_user.js.erb @@ -0,0 +1 @@ +$('#tab-content-users').html('<%= escape_javascript(render :partial => 'groups/users') %>'); diff --git a/app/views/groups/show.api.rsb b/app/views/groups/show.api.rsb new file mode 100644 index 00000000..62647441 --- /dev/null +++ b/app/views/groups/show.api.rsb @@ -0,0 +1,30 @@ +api.group do + api.id @group.id + api.name @group.lastname + + render_api_custom_values @group.visible_custom_field_values, api + + api.array :users do + @group.users.each do |user| + api.user :id => user.id, :name => user.name + end + end if include_in_api_response?('users') + + api.array :memberships do + @group.memberships.each do |membership| + api.membership do + api.id membership.id + api.project :id => membership.project.id, :name => membership.project.name + api.array :roles do + membership.member_roles.each do |member_role| + if member_role.role + attrs = {:id => member_role.role.id, :name => member_role.role.name} + attrs.merge!(:inherited => true) if member_role.inherited_from.present? + api.role attrs + end + end + end + end if membership.project + end + end if include_in_api_response?('memberships') +end diff --git a/app/views/groups/show.html.erb b/app/views/groups/show.html.erb new file mode 100644 index 00000000..4b067454 --- /dev/null +++ b/app/views/groups/show.html.erb @@ -0,0 +1,7 @@ +

    <%= link_to l(:label_group_plural), groups_path %> » <%=h @group %>

    + +
      +<% @group.users.each do |user| %> +
    • <%=h user %>
    • +<% end %> +
    diff --git a/app/views/issue_categories/_form.html.erb b/app/views/issue_categories/_form.html.erb new file mode 100644 index 00000000..c3b20936 --- /dev/null +++ b/app/views/issue_categories/_form.html.erb @@ -0,0 +1,6 @@ +<%= error_messages_for 'category' %> + +
    +

    <%= f.text_field :name, :size => 30, :required => true %>

    +

    <%= f.select :assigned_to_id, principals_options_for_select(@project.assignable_users, @category.assigned_to), :include_blank => true %>

    +
    diff --git a/app/views/issue_categories/_new_modal.html.erb b/app/views/issue_categories/_new_modal.html.erb new file mode 100644 index 00000000..07cc289f --- /dev/null +++ b/app/views/issue_categories/_new_modal.html.erb @@ -0,0 +1,9 @@ +

    <%=l(:label_issue_category_new)%>

    + +<%= labelled_form_for @category, :as => 'issue_category', :url => project_issue_categories_path(@project), :remote => true do |f| %> +<%= render :partial => 'issue_categories/form', :locals => { :f => f } %> +

    + <%= submit_tag l(:button_create), :name => nil %> + <%= submit_tag l(:button_cancel), :name => nil, :onclick => "hideModal(this);", :type => 'button' %> +

    +<% end %> diff --git a/app/views/issue_categories/create.js.erb b/app/views/issue_categories/create.js.erb new file mode 100644 index 00000000..c4253b98 --- /dev/null +++ b/app/views/issue_categories/create.js.erb @@ -0,0 +1,3 @@ +hideModal(); +<% select = content_tag('select', content_tag('option') + options_from_collection_for_select(@project.issue_categories, 'id', 'name', @category.id), :id => 'issue_category_id', :name => 'issue[category_id]') %> +$('#issue_category_id').replaceWith('<%= escape_javascript(select) %>'); diff --git a/app/views/issue_categories/destroy.html.erb b/app/views/issue_categories/destroy.html.erb new file mode 100644 index 00000000..ae14c5ec --- /dev/null +++ b/app/views/issue_categories/destroy.html.erb @@ -0,0 +1,16 @@ +

    <%=l(:label_issue_category)%>: <%=h @category.name %>

    + +<%= form_tag(issue_category_path(@category), :method => :delete) do %> +
    +

    <%= l(:text_issue_category_destroy_question, @issue_count) %>

    +


    +<% if @categories.size > 0 %> +: +<%= label_tag "reassign_to_id", l(:description_issue_category_reassign), :class => "hidden-for-sighted" %> +<%= select_tag 'reassign_to_id', options_from_collection_for_select(@categories, 'id', 'name') %>

    +<% end %> +
    + +<%= submit_tag l(:button_apply) %> +<%= link_to l(:button_cancel), :controller => 'projects', :action => 'settings', :id => @project, :tab => 'categories' %> +<% end %> diff --git a/app/views/issue_categories/edit.html.erb b/app/views/issue_categories/edit.html.erb new file mode 100644 index 00000000..fd5f7cc8 --- /dev/null +++ b/app/views/issue_categories/edit.html.erb @@ -0,0 +1,7 @@ +

    <%=l(:label_issue_category)%>

    + +<%= labelled_form_for @category, :as => :issue_category, + :url => issue_category_path(@category), :html => {:method => :put} do |f| %> +<%= render :partial => 'issue_categories/form', :locals => { :f => f } %> +<%= submit_tag l(:button_save) %> +<% end %> diff --git a/app/views/issue_categories/index.api.rsb b/app/views/issue_categories/index.api.rsb new file mode 100644 index 00000000..685d8a56 --- /dev/null +++ b/app/views/issue_categories/index.api.rsb @@ -0,0 +1,10 @@ +api.array :issue_categories, api_meta(:total_count => @categories.size) do + @categories.each do |category| + api.issue_category do + api.id category.id + api.project(:id => category.project_id, :name => category.project.name) unless category.project.nil? + api.name category.name + api.assigned_to(:id => category.assigned_to_id, :name => category.assigned_to.name) unless category.assigned_to.nil? + end + end +end diff --git a/app/views/issue_categories/new.html.erb b/app/views/issue_categories/new.html.erb new file mode 100644 index 00000000..e042b892 --- /dev/null +++ b/app/views/issue_categories/new.html.erb @@ -0,0 +1,7 @@ +

    <%=l(:label_issue_category_new)%>

    + +<%= labelled_form_for @category, :as => :issue_category, + :url => project_issue_categories_path(@project) do |f| %> +<%= render :partial => 'issue_categories/form', :locals => { :f => f } %> +<%= submit_tag l(:button_create) %> +<% end %> diff --git a/app/views/issue_categories/new.js.erb b/app/views/issue_categories/new.js.erb new file mode 100644 index 00000000..0d623495 --- /dev/null +++ b/app/views/issue_categories/new.js.erb @@ -0,0 +1,2 @@ +$('#ajax-modal').html('<%= escape_javascript(render :partial => 'issue_categories/new_modal') %>'); +showModal('ajax-modal', '600px'); diff --git a/app/views/issue_categories/show.api.rsb b/app/views/issue_categories/show.api.rsb new file mode 100644 index 00000000..cefa7c8b --- /dev/null +++ b/app/views/issue_categories/show.api.rsb @@ -0,0 +1,6 @@ +api.issue_category do + api.id @category.id + api.project(:id => @category.project_id, :name => @category.project.name) unless @category.project.nil? + api.name @category.name + api.assigned_to(:id => @category.assigned_to_id, :name => @category.assigned_to.name) unless @category.assigned_to.nil? +end diff --git a/app/views/issue_relations/_form.html.erb b/app/views/issue_relations/_form.html.erb new file mode 100644 index 00000000..29b7f0f1 --- /dev/null +++ b/app/views/issue_relations/_form.html.erb @@ -0,0 +1,14 @@ +<%= error_messages_for 'relation' %> + +

    <%= f.select :relation_type, collection_for_relation_type_select, {}, :onchange => "setPredecessorFieldsVisibility();" %> +<%= l(:label_issue) %> #<%= f.text_field :issue_to_id, :size => 10 %> + +<%= submit_tag l(:button_add) %> +<%= link_to_function l(:button_cancel), '$("#new-relation-form").hide();'%> +

    + +<%= javascript_tag "observeAutocompleteField('relation_issue_to_id', '#{escape_javascript auto_complete_issues_path(:project_id => @project, :scope => (Setting.cross_project_issue_relations? ? 'all' : nil))}')" %> + +<%= javascript_tag "setPredecessorFieldsVisibility();" %> diff --git a/app/views/issue_relations/create.js.erb b/app/views/issue_relations/create.js.erb new file mode 100644 index 00000000..03ba2197 --- /dev/null +++ b/app/views/issue_relations/create.js.erb @@ -0,0 +1,6 @@ +$('#relations').html('<%= escape_javascript(render :partial => 'issues/relations') %>'); +<% if @relation.errors.empty? %> + $('#relation_delay').val(''); + $('#relation_issue_to_id').val(''); + $('#relation_issue_to_id').focus(); +<% end %> diff --git a/app/views/issue_relations/destroy.js.erb b/app/views/issue_relations/destroy.js.erb new file mode 100644 index 00000000..f5f29d31 --- /dev/null +++ b/app/views/issue_relations/destroy.js.erb @@ -0,0 +1 @@ +$('#relation-<%= @relation.id %>').remove(); diff --git a/app/views/issue_relations/index.api.rsb b/app/views/issue_relations/index.api.rsb new file mode 100644 index 00000000..11ff3094 --- /dev/null +++ b/app/views/issue_relations/index.api.rsb @@ -0,0 +1,11 @@ +api.array :relations do + @relations.each do |relation| + api.relation do + api.id relation.id + api.issue_id relation.issue_from_id + api.issue_to_id relation.issue_to_id + api.relation_type relation.relation_type + api.delay relation.delay + end + end +end diff --git a/app/views/issue_relations/show.api.rsb b/app/views/issue_relations/show.api.rsb new file mode 100644 index 00000000..bffad94a --- /dev/null +++ b/app/views/issue_relations/show.api.rsb @@ -0,0 +1,7 @@ +api.relation do + api.id @relation.id + api.issue_id @relation.issue_from_id + api.issue_to_id @relation.issue_to_id + api.relation_type @relation.relation_type + api.delay @relation.delay +end diff --git a/app/views/issue_statuses/_form.html.erb b/app/views/issue_statuses/_form.html.erb new file mode 100644 index 00000000..37898737 --- /dev/null +++ b/app/views/issue_statuses/_form.html.erb @@ -0,0 +1,12 @@ +<%= error_messages_for 'issue_status' %> + +
    +

    <%= f.text_field :name, :required => true %>

    +<% if Issue.use_status_for_done_ratio? %> +

    <%= f.select :default_done_ratio, ((0..10).to_a.collect {|r| ["#{r*10} %", r*10] }), :include_blank => true, :label => :field_done_ratio %>

    +<% end %> +

    <%= f.check_box :is_closed %>

    +

    <%= f.check_box :is_default %>

    + +<%= call_hook(:view_issue_statuses_form, :issue_status => @issue_status) %> +
    diff --git a/app/views/issue_statuses/edit.html.erb b/app/views/issue_statuses/edit.html.erb new file mode 100644 index 00000000..c2eace1c --- /dev/null +++ b/app/views/issue_statuses/edit.html.erb @@ -0,0 +1,6 @@ +

    <%= link_to l(:label_issue_status_plural), issue_statuses_path %> » <%=h @issue_status %>

    + +<%= labelled_form_for @issue_status do |f| %> + <%= render :partial => 'form', :locals => {:f => f} %> + <%= submit_tag l(:button_save) %> +<% end %> diff --git a/app/views/issue_statuses/index.api.rsb b/app/views/issue_statuses/index.api.rsb new file mode 100644 index 00000000..8a51674d --- /dev/null +++ b/app/views/issue_statuses/index.api.rsb @@ -0,0 +1,10 @@ +api.array :issue_statuses do + @issue_statuses.each do |status| + api.issue_status do + api.id status.id + api.name status.name + api.is_default status.is_default + api.is_closed status.is_closed + end + end +end diff --git a/app/views/issue_statuses/index.html.erb b/app/views/issue_statuses/index.html.erb new file mode 100644 index 00000000..f0a5e850 --- /dev/null +++ b/app/views/issue_statuses/index.html.erb @@ -0,0 +1,39 @@ +
    +<%= link_to l(:label_issue_status_new), new_issue_status_path, :class => 'icon icon-add' %> +<%= link_to(l(:label_update_issue_done_ratios), update_issue_done_ratio_issue_statuses_path, :class => 'icon icon-multiple', :method => 'post', :data => {:confirm => l(:text_are_you_sure)}) if Issue.use_status_for_done_ratio? %> +
    + +

    <%=l(:label_issue_status_plural)%>

    + + + + + <% if Issue.use_status_for_done_ratio? %> + + <% end %> + + + + + + +<% for status in @issue_statuses %> + "> + + <% if Issue.use_status_for_done_ratio? %> + + <% end %> + + + + + +<% end %> + +
    <%=l(:field_status)%><%=l(:field_done_ratio)%><%=l(:field_is_default)%><%=l(:field_is_closed)%><%=l(:button_sort)%>
    <%= link_to h(status.name), edit_issue_status_path(status) %><%= h status.default_done_ratio %><%= checked_image status.is_default? %><%= checked_image status.is_closed? %><%= reorder_links('issue_status', {:action => 'update', :id => status}, :put) %> + <%= delete_link issue_status_path(status) %> +
    + +

    <%= pagination_links_full @issue_status_pages %>

    + +<% html_title(l(:label_issue_status_plural)) -%> diff --git a/app/views/issue_statuses/new.html.erb b/app/views/issue_statuses/new.html.erb new file mode 100644 index 00000000..a5730e6b --- /dev/null +++ b/app/views/issue_statuses/new.html.erb @@ -0,0 +1,6 @@ +

    <%= link_to l(:label_issue_status_plural), issue_statuses_path %> » <%=l(:label_issue_status_new)%>

    + +<%= labelled_form_for @issue_status do |f| %> + <%= render :partial => 'form', :locals => {:f => f} %> + <%= submit_tag l(:button_create) %> +<% end %> diff --git a/app/views/issues/_action_menu.html.erb b/app/views/issues/_action_menu.html.erb new file mode 100644 index 00000000..4757ebcb --- /dev/null +++ b/app/views/issues/_action_menu.html.erb @@ -0,0 +1,7 @@ +
    +<%= link_to l(:button_update), edit_issue_path(@issue), :onclick => 'showAndScrollTo("update", "issue_notes"); return false;', :class => 'icon icon-edit', :accesskey => accesskey(:edit) if @issue.editable? %> +<%= link_to l(:button_log_time), new_issue_time_entry_path(@issue), :class => 'icon icon-time-add' if User.current.allowed_to?(:log_time, @project) %> +<%= watcher_link(@issue, User.current) %> +<%= link_to l(:button_copy), project_copy_issue_path(@project, @issue), :class => 'icon icon-copy' if User.current.allowed_to?(:add_issues, @project) %> +<%= link_to l(:button_delete), issue_path(@issue), :data => {:confirm => issues_destroy_confirmation_message(@issue)}, :method => :delete, :class => 'icon icon-del' if User.current.allowed_to?(:delete_issues, @project) %> +
    diff --git a/app/views/issues/_attributes.html.erb b/app/views/issues/_attributes.html.erb new file mode 100644 index 00000000..9b4c508c --- /dev/null +++ b/app/views/issues/_attributes.html.erb @@ -0,0 +1,73 @@ +<%= labelled_fields_for :issue, @issue do |f| %> + +
    +
    +<% if @issue.safe_attribute?('status_id') && @allowed_statuses.present? %> +

    <%= f.select :status_id, (@allowed_statuses.collect {|p| [p.name, p.id]}), {:required => true}, + :onchange => "updateIssueFrom('#{escape_javascript project_issue_form_path(@project, :id => @issue, :format => 'js')}')" %>

    + +<% else %> +

    <%= h(@issue.status.name) %>

    +<% end %> + +<% if @issue.safe_attribute? 'priority_id' %> +

    <%= f.select :priority_id, (@priorities.collect {|p| [p.name, p.id]}), {:required => true}, :disabled => !@issue.leaf? %>

    +<% end %> + +<% if @issue.safe_attribute? 'assigned_to_id' %> +

    <%= f.select :assigned_to_id, principals_options_for_select(@issue.assignable_users, @issue.assigned_to), :include_blank => true, :required => @issue.required_attribute?('assigned_to_id') %>

    +<% end %> + +<% if @issue.safe_attribute?('category_id') && @issue.project.issue_categories.any? %> +

    <%= f.select :category_id, (@issue.project.issue_categories.collect {|c| [c.name, c.id]}), :include_blank => true, :required => @issue.required_attribute?('category_id') %> +<%= link_to(image_tag('add.png', :style => 'vertical-align: middle;'), + new_project_issue_category_path(@issue.project), + :remote => true, + :method => 'get', + :title => l(:label_issue_category_new), + :tabindex => 200) if User.current.allowed_to?(:manage_categories, @issue.project) %>

    +<% end %> + +<% if @issue.safe_attribute?('fixed_version_id') && @issue.assignable_versions.any? %> +

    <%= f.select :fixed_version_id, version_options_for_select(@issue.assignable_versions, @issue.fixed_version), :include_blank => true, :required => @issue.required_attribute?('fixed_version_id') %> +<%= link_to(image_tag('add.png', :style => 'vertical-align: middle;'), + new_project_version_path(@issue.project), + :remote => true, + :method => 'get', + :title => l(:label_version_new), + :tabindex => 200) if User.current.allowed_to?(:manage_versions, @issue.project) %> +

    +<% end %> +
    + +
    +<% if @issue.safe_attribute? 'parent_issue_id' %> +

    <%= f.text_field :parent_issue_id, :size => 10, :required => @issue.required_attribute?('parent_issue_id') %>

    +<%= javascript_tag "observeAutocompleteField('issue_parent_issue_id', '#{escape_javascript auto_complete_issues_path}')" %> +<% end %> + +<% if @issue.safe_attribute? 'start_date' %> +

    <%= f.text_field :start_date, :size => 10, :disabled => !@issue.leaf?, :required => @issue.required_attribute?('start_date') %><%= calendar_for('issue_start_date') if @issue.leaf? %>

    +<% end %> + +<% if @issue.safe_attribute? 'due_date' %> +

    <%= f.text_field :due_date, :size => 10, :disabled => !@issue.leaf?, :required => @issue.required_attribute?('due_date') %><%= calendar_for('issue_due_date') if @issue.leaf? %>

    +<% end %> + +<% if @issue.safe_attribute? 'estimated_hours' %> +

    <%= f.text_field :estimated_hours, :size => 3, :disabled => !@issue.leaf?, :required => @issue.required_attribute?('estimated_hours') %> <%= l(:field_hours) %>

    +<% end %> + +<% if @issue.safe_attribute?('done_ratio') && @issue.leaf? && Issue.use_field_for_done_ratio? %> +

    <%= f.select :done_ratio, ((0..10).to_a.collect {|r| ["#{r*10} %", r*10] }), :required => @issue.required_attribute?('done_ratio') %>

    +<% end %> +
    +
    + +<% if @issue.safe_attribute? 'custom_field_values' %> +<%= render :partial => 'issues/form_custom_fields' %> +<% end %> + +<% end %> + +<% include_calendar_headers_tags %> diff --git a/app/views/issues/_changesets.html.erb b/app/views/issues/_changesets.html.erb new file mode 100644 index 00000000..beab6553 --- /dev/null +++ b/app/views/issues/_changesets.html.erb @@ -0,0 +1,10 @@ +<% changesets.each do |changeset| %> +
    +

    <%= link_to_revision(changeset, changeset.repository, + :text => "#{l(:label_revision)} #{changeset.format_identifier}") %>
    + <%= authoring(changeset.committed_on, changeset.author) %>

    +
    + <%= textilizable(changeset, :comments) %> +
    +
    +<% end %> diff --git a/app/views/issues/_conflict.html.erb b/app/views/issues/_conflict.html.erb new file mode 100644 index 00000000..01d66882 --- /dev/null +++ b/app/views/issues/_conflict.html.erb @@ -0,0 +1,26 @@ +
    + <%= l(:notice_issue_update_conflict) %> + <% if @conflict_journals.present? %> +
    + <% @conflict_journals.sort_by(&:id).each do |journal| %> +

    <%= authoring journal.created_on, journal.user, :label => :label_updated_time_by %>

    + <% if journal.details.any? %> +
      + <% details_to_strings(journal.details).each do |string| %> +
    • <%= string %>
    • + <% end %> +
    + <% end %> + <%= textilizable(journal, :notes) unless journal.notes.blank? %> + <% end %> +
    + <% end %> +
    +

    +
    + <% if @issue.notes.present? %> +
    + <% end %> + +

    +

    <%= submit_tag l(:button_submit) %>

    diff --git a/app/views/issues/_edit.html.erb b/app/views/issues/_edit.html.erb new file mode 100644 index 00000000..f2052a27 --- /dev/null +++ b/app/views/issues/_edit.html.erb @@ -0,0 +1,51 @@ +<%= labelled_form_for @issue, :html => {:id => 'issue-form', :multipart => true} do |f| %> + <%= error_messages_for 'issue', 'time_entry' %> + <%= render :partial => 'conflict' if @conflict %> +
    + <% if @edit_allowed || !@allowed_statuses.empty? %> +
    <%= l(:label_change_properties) %> +
    + <%= render :partial => 'form', :locals => {:f => f} %> +
    +
    + <% end %> + <% if User.current.allowed_to?(:log_time, @project) %> +
    <%= l(:button_log_time) %> + <%= labelled_fields_for :time_entry, @time_entry do |time_entry| %> +
    +

    <%= time_entry.text_field :hours, :size => 6, :label => :label_spent_time %> <%= l(:field_hours) %>

    +
    +
    +

    <%= time_entry.select :activity_id, activity_collection_for_select_options %>

    +
    +

    <%= time_entry.text_field :comments, :size => 60 %>

    + <% @time_entry.custom_field_values.each do |value| %> +

    <%= custom_field_tag_with_label :time_entry, value %>

    + <% end %> + <% end %> +
    + <% end %> + +
    <%= l(:field_notes) %> + <%= f.text_area :notes, :cols => 60, :rows => 10, :class => 'wiki-edit', :no_label => true %> + <%= wikitoolbar_for 'issue_notes' %> + + <% if @issue.safe_attribute? 'private_notes' %> + + <% end %> + + <%= call_hook(:view_issues_edit_notes_bottom, { :issue => @issue, :notes => @notes, :form => f }) %> +
    + +
    <%= l(:label_attachment_plural) %> +

    <%= render :partial => 'attachments/form', :locals => {:container => @issue} %>

    +
    +
    + + <%= f.hidden_field :lock_version %> + <%= hidden_field_tag 'last_journal_id', params[:last_journal_id] || @issue.last_journal_id %> + <%= submit_tag l(:button_submit) %> + <%= preview_link preview_edit_issue_path(:project_id => @project, :id => @issue), 'issue-form' %> +<% end %> + +
    diff --git a/app/views/issues/_form.html.erb b/app/views/issues/_form.html.erb new file mode 100644 index 00000000..6a79d1e5 --- /dev/null +++ b/app/views/issues/_form.html.erb @@ -0,0 +1,45 @@ +<%= labelled_fields_for :issue, @issue do |f| %> +<%= call_hook(:view_issues_form_details_top, { :issue => @issue, :form => f }) %> + +<% if @issue.safe_attribute? 'is_private' %> +

    + <%= f.check_box :is_private, :no_label => true %> +

    +<% end %> + +<% if @issue.safe_attribute? 'project_id' %> +

    <%= f.select :project_id, project_tree_options_for_select(@issue.allowed_target_projects, :selected => @issue.project), {:required => true}, + :onchange => "updateIssueFrom('#{escape_javascript project_issue_form_path(@project, :id => @issue, :format => 'js')}')" %>

    +<% end %> + +<% if @issue.safe_attribute? 'tracker_id' %> +

    <%= f.select :tracker_id, @issue.project.trackers.collect {|t| [t.name, t.id]}, {:required => true}, + :onchange => "updateIssueFrom('#{escape_javascript project_issue_form_path(@project, :id => @issue, :format => 'js')}')" %>

    +<% end %> + +<% if @issue.safe_attribute? 'subject' %> +

    <%= f.text_field :subject, :size => 80, :maxlength => 255, :required => true %>

    +<% end %> + +<% if @issue.safe_attribute? 'description' %> +

    + <%= f.label_for_field :description, :required => @issue.required_attribute?('description') %> + <%= link_to_function image_tag('edit.png'), '$(this).hide(); $("#issue_description_and_toolbar").show()' unless @issue.new_record? %> + <%= content_tag 'span', :id => "issue_description_and_toolbar", :style => (@issue.new_record? ? nil : 'display:none') do %> + <%= f.text_area :description, + :cols => 60, + :rows => (@issue.description.blank? ? 10 : [[10, @issue.description.length / 50].max, 100].min), + :accesskey => accesskey(:edit), + :class => 'wiki-edit', + :no_label => true %> + <% end %> +

    +<%= wikitoolbar_for 'issue_description' %> +<% end %> + +
    + <%= render :partial => 'issues/attributes' %> +
    + +<%= call_hook(:view_issues_form_details_bottom, { :issue => @issue, :form => f }) %> +<% end %> diff --git a/app/views/issues/_form_custom_fields.html.erb b/app/views/issues/_form_custom_fields.html.erb new file mode 100644 index 00000000..4da98eb1 --- /dev/null +++ b/app/views/issues/_form_custom_fields.html.erb @@ -0,0 +1,13 @@ +
    +
    +<% i = 0 %> +<% split_on = (@issue.custom_field_values.size / 2.0).ceil - 1 %> +<% @issue.editable_custom_field_values.each do |value| %> +

    <%= custom_field_tag_with_label :issue, value, :required => @issue.required_attribute?(value.custom_field_id) %>

    +<% if i == split_on -%> +
    +<% end -%> +<% i += 1 -%> +<% end -%> +
    +
    diff --git a/app/views/issues/_history.html.erb b/app/views/issues/_history.html.erb new file mode 100644 index 00000000..470a55ac --- /dev/null +++ b/app/views/issues/_history.html.erb @@ -0,0 +1,22 @@ +<% reply_links = authorize_for('issues', 'edit') -%> +<% for journal in journals %> +
    +
    +

    <%= link_to "##{journal.indice}", {:anchor => "note-#{journal.indice}"}, :class => "journal-link" %> + <%= avatar(journal.user, :size => "24") %> + <%= authoring journal.created_on, journal.user, :label => :label_updated_time_by %>

    + + <% if journal.details.any? %> +
      + <% details_to_strings(journal.details).each do |string| %> +
    • <%= string %>
    • + <% end %> +
    + <% end %> + <%= render_notes(issue, journal, :reply_links => reply_links) unless journal.notes.blank? %> +
    +
    + <%= call_hook(:view_issues_history_journal_bottom, { :journal => journal }) %> +<% end %> + +<% heads_for_wiki_formatter if User.current.allowed_to?(:edit_issue_notes, issue.project) || User.current.allowed_to?(:edit_own_issue_notes, issue.project) %> diff --git a/app/views/issues/_list.html.erb b/app/views/issues/_list.html.erb new file mode 100644 index 00000000..f323e378 --- /dev/null +++ b/app/views/issues/_list.html.erb @@ -0,0 +1,108 @@ +<%= form_tag({}) do -%> +<%= hidden_field_tag 'back_url', url_for(params), :id => nil %> +
    + + + + + + +
      + + <% issue_list(issues) do |issue, level| -%> + <% if @query.grouped? && (group = @query.group_by_column.value(issue)) != previous_group %> + <% reset_cycle %> + + +   + <%= group.blank? ? l(:label_none) : column_content(@query.group_by_column, issue) %> <%= @issue_count_by_group[group] %> + <%= link_to_function("#{l(:button_collapse_all)}/#{l(:button_expand_all)}", + "toggleAllRowGroups(this)", :class => 'toggle-all') %> + + + <% previous_group = group %> + <% end %> + +
    • "> + <% column_content = ( query.inline_columns.map {|column| "
    • #{column_content(column, issue)}
    • "}) %> +
        + <%= raw column_content[0] %> + <%= raw column_content[4] %> +
          + <%= l(:label_type_as)%><%= raw column_content[1] %> + <%= l(:label_status_as)%><%= raw column_content[2] %> + <%= l(:label_priority_as)%><%= raw column_content[3] %> + <% unless issue.assigned_to_id.nil? %> + <%= l(:field_assigned_to)%><%= raw column_content[5] %> + <% end %> + + <%= l(:label_updated_time, time_tag(issue.updated_on)).html_safe %> +
        +
      + + + <% @query.block_columns.each do |column| + if (text = column_content(column, issue)) && text.present? -%> + + <%= text %> + + <% end -%> + <% end -%> + <% end -%> + +
    +
    +<% end -%> diff --git a/app/views/issues/_list_simple.html.erb b/app/views/issues/_list_simple.html.erb new file mode 100644 index 00000000..0e4aa073 --- /dev/null +++ b/app/views/issues/_list_simple.html.erb @@ -0,0 +1,29 @@ +<% if issues && issues.any? %> +<%= form_tag({}) do %> + + + + + + + + + <% for issue in issues %> + + + + + + + <% end %> + +
    #<%=l(:field_project)%><%=l(:field_tracker)%><%=l(:field_subject)%>
    + <%= check_box_tag("ids[]", issue.id, false, :style => 'display:none;', :id => nil) %> + <%= link_to issue.id, issue_path(issue) %> + <%= link_to_project(issue.project) %><%=h issue.tracker %> + <%= link_to truncate(issue.subject, :length => 60), issue_path(issue) %> (<%=h issue.status %>) +
    +<% end %> +<% else %> +

    <%= l(:label_no_data) %>

    +<% end %> diff --git a/app/views/issues/_relations.html.erb b/app/views/issues/_relations.html.erb new file mode 100644 index 00000000..0cffa8f5 --- /dev/null +++ b/app/views/issues/_relations.html.erb @@ -0,0 +1,44 @@ +
    +<% if User.current.allowed_to?(:manage_issue_relations, @project) %> + <%= toggle_link l(:button_add), 'new-relation-form', {:focus => 'relation_issue_to_id'} %> +<% end %> +
    + +

    <%=l(:label_related_issues)%>

    + +<% if @relations.present? %> +
    + +<% @relations.each do |relation| %> + <% other_issue = relation.other_issue(@issue) -%> + + + + + + + + +<% end %> +
    <%= check_box_tag("ids[]", other_issue.id, false, :id => nil) %> + <%= l(relation.label_for(@issue)) %> + <%= "(#{l('datetime.distance_in_words.x_days', :count => relation.delay)})" if relation.delay && relation.delay != 0 %> + <%= h(other_issue.project) + ' - ' if Setting.cross_project_issue_relations? %> + <%= link_to_issue(other_issue, :truncate => 60) %> + <%=h other_issue.status.name %><%= format_date(other_issue.start_date) %><%= format_date(other_issue.due_date) %><%= link_to image_tag('link_break.png'), + relation_path(relation), + :remote => true, + :method => :delete, + :data => {:confirm => l(:text_are_you_sure)}, + :title => l(:label_relation_delete) if User.current.allowed_to?(:manage_issue_relations, @project) %>
    +
    +<% end %> + +<%= form_for @relation, { + :as => :relation, :remote => true, + :url => issue_relations_path(@issue), + :method => :post, + :html => {:id => 'new-relation-form', :style => (@relation ? '' : 'display: none;')} + } do |f| %> +<%= render :partial => 'issue_relations/form', :locals => {:f => f}%> +<% end %> diff --git a/app/views/issues/_sidebar.html.erb b/app/views/issues/_sidebar.html.erb new file mode 100644 index 00000000..24b8a4fa --- /dev/null +++ b/app/views/issues/_sidebar.html.erb @@ -0,0 +1,17 @@ +

    <%= l(:label_issue_plural) %>

    +<%= link_to l(:label_issue_view_all), _project_issues_path(@project, :set_filter => 1) %>
    +<% if @project %> +<%= link_to l(:field_summary), project_issues_report_path(@project) %>
    +<% end %> +<%= call_hook(:view_issues_sidebar_issues_bottom) %> + +<% if User.current.allowed_to?(:view_calendar, @project, :global => true) %> + <%= link_to l(:label_calendar), _project_calendar_path(@project) %>
    +<% end %> +<% if User.current.allowed_to?(:view_gantt, @project, :global => true) %> + <%= link_to l(:label_gantt), _project_gantt_path(@project) %>
    +<% end %> +<%= call_hook(:view_issues_sidebar_planning_bottom) %> + +<%= render_sidebar_queries %> +<%= call_hook(:view_issues_sidebar_queries_bottom) %> diff --git a/app/views/issues/bulk_edit.html.erb b/app/views/issues/bulk_edit.html.erb new file mode 100644 index 00000000..281c7a30 --- /dev/null +++ b/app/views/issues/bulk_edit.html.erb @@ -0,0 +1,150 @@ +

    <%= @copy ? l(:button_copy) : l(:label_bulk_edit_selected_issues) %>

    + +
      +<% @issues.each do |issue| %> + <%= content_tag 'li', link_to_issue(issue) %> +<% end %> +
    + +<%= form_tag(bulk_update_issues_path, :id => 'bulk_edit_form') do %> +<%= @issues.collect {|i| hidden_field_tag('ids[]', i.id)}.join("\n").html_safe %> +
    +
    +<%= l(:label_change_properties) %> + +
    +<% if @allowed_projects.present? %> +

    + + <%= select_tag('issue[project_id]', content_tag('option', l(:label_no_change_option), :value => '') + project_tree_options_for_select(@allowed_projects, :selected => @target_project), + :onchange => "updateBulkEditFrom('#{escape_javascript url_for(:action => 'bulk_edit', :format => 'js')}')") %> +

    +<% end %> +

    + + <%= select_tag('issue[tracker_id]', content_tag('option', l(:label_no_change_option), :value => '') + options_from_collection_for_select(@trackers, :id, :name)) %> +

    +<% if @available_statuses.any? %> +

    + + <%= select_tag('issue[status_id]',content_tag('option', l(:label_no_change_option), :value => '') + options_from_collection_for_select(@available_statuses, :id, :name)) %> +

    +<% end %> + +<% if @safe_attributes.include?('priority_id') -%> +

    + + <%= select_tag('issue[priority_id]', content_tag('option', l(:label_no_change_option), :value => '') + options_from_collection_for_select(IssuePriority.active, :id, :name)) %> +

    +<% end %> + +<% if @safe_attributes.include?('assigned_to_id') -%> +

    + + <%= select_tag('issue[assigned_to_id]', content_tag('option', l(:label_no_change_option), :value => '') + + content_tag('option', l(:label_nobody), :value => 'none') + + principals_options_for_select(@assignables)) %> +

    +<% end %> + +<% if @safe_attributes.include?('category_id') -%> +

    + + <%= select_tag('issue[category_id]', content_tag('option', l(:label_no_change_option), :value => '') + + content_tag('option', l(:label_none), :value => 'none') + + options_from_collection_for_select(@categories, :id, :name)) %> +

    +<% end %> + +<% if @safe_attributes.include?('fixed_version_id') -%> +

    + + <%= select_tag('issue[fixed_version_id]', content_tag('option', l(:label_no_change_option), :value => '') + + content_tag('option', l(:label_none), :value => 'none') + + version_options_for_select(@versions.sort)) %> +

    +<% end %> + +<% @custom_fields.each do |custom_field| %> +

    <%= custom_field_tag_for_bulk_edit('issue', custom_field, @projects) %>

    +<% end %> + +<% if @copy && @attachments_present %> +

    + + <%= check_box_tag 'copy_attachments', '1', true %> +

    +<% end %> + +<% if @copy && @subtasks_present %> +

    + + <%= check_box_tag 'copy_subtasks', '1', true %> +

    +<% end %> + +<%= call_hook(:view_issues_bulk_edit_details_bottom, { :issues => @issues }) %> +
    + +
    +<% if @safe_attributes.include?('is_private') %> +

    + + <%= select_tag('issue[is_private]', content_tag('option', l(:label_no_change_option), :value => '') + + content_tag('option', l(:general_text_Yes), :value => '1') + + content_tag('option', l(:general_text_No), :value => '0')) %> +

    +<% end %> + +<% if @safe_attributes.include?('parent_issue_id') && @project %> +

    + + <%= text_field_tag 'issue[parent_issue_id]', '', :size => 10 %> +

    +<%= javascript_tag "observeAutocompleteField('issue_parent_issue_id', '#{escape_javascript auto_complete_issues_path(:project_id => @project)}')" %> +<% end %> + +<% if @safe_attributes.include?('start_date') %> +

    + + <%= text_field_tag 'issue[start_date]', '', :size => 10 %><%= calendar_for('issue_start_date') %> +

    +<% end %> + +<% if @safe_attributes.include?('due_date') %> +

    + + <%= text_field_tag 'issue[due_date]', '', :size => 10 %><%= calendar_for('issue_due_date') %> +

    +<% end %> + +<% if @safe_attributes.include?('done_ratio') && Issue.use_field_for_done_ratio? %> +

    + + <%= select_tag 'issue[done_ratio]', options_for_select([[l(:label_no_change_option), '']] + (0..10).to_a.collect {|r| ["#{r*10} %", r*10] }) %> +

    +<% end %> +
    + +
    + +
    <%= l(:field_notes) %> +<%= text_area_tag 'notes', @notes, :cols => 60, :rows => 10, :class => 'wiki-edit' %> +<%= wikitoolbar_for 'notes' %> +
    +
    + +

    + <% if @copy %> + <%= hidden_field_tag 'copy', '1' %> + <%= submit_tag l(:button_copy) %> + <%= submit_tag l(:button_copy_and_follow), :name => 'follow' %> + <% elsif @target_project %> + <%= submit_tag l(:button_move) %> + <%= submit_tag l(:button_move_and_follow), :name => 'follow' %> + <% else %> + <%= submit_tag l(:button_submit) %> + <% end %> +

    + +<% end %> diff --git a/app/views/issues/bulk_edit.js.erb b/app/views/issues/bulk_edit.js.erb new file mode 100644 index 00000000..ac84ad1d --- /dev/null +++ b/app/views/issues/bulk_edit.js.erb @@ -0,0 +1 @@ +$('#content').html('<%= escape_javascript(render :template => 'issues/bulk_edit', :formats => [:html]) %>'); diff --git a/app/views/issues/destroy.html.erb b/app/views/issues/destroy.html.erb new file mode 100644 index 00000000..cffea742 --- /dev/null +++ b/app/views/issues/destroy.html.erb @@ -0,0 +1,15 @@ +

    <%= l(:label_confirmation) %>

    + +<%= form_tag({}, :method => :delete) do %> +<%= @issues.collect {|i| hidden_field_tag('ids[]', i.id)}.join("\n").html_safe %> +
    +

    <%= l(:text_destroy_time_entries_question, :hours => number_with_precision(@hours, :precision => 2)) %>

    +

    +
    +
    + +<%= text_field_tag 'reassign_to_id', params[:reassign_to_id], :size => 6, :onfocus => '$("#todo_reassign").attr("checked", true);' %> +

    +
    +<%= submit_tag l(:button_apply) %> +<% end %> diff --git a/app/views/issues/edit.html.erb b/app/views/issues/edit.html.erb new file mode 100644 index 00000000..83f02051 --- /dev/null +++ b/app/views/issues/edit.html.erb @@ -0,0 +1,6 @@ +

    <%=h "#{@issue.tracker.name} ##{@issue.id}" %>

    + +<%= render :partial => 'edit' %> +<% content_for :header_tags do %> + <%= robot_exclusion_tag %> +<% end %> diff --git a/app/views/issues/index.api.rsb b/app/views/issues/index.api.rsb new file mode 100644 index 00000000..5009ffa7 --- /dev/null +++ b/app/views/issues/index.api.rsb @@ -0,0 +1,35 @@ +api.array :issues, api_meta(:total_count => @issue_count, :offset => @offset, :limit => @limit) do + @issues.each do |issue| + api.issue do + api.id issue.id + api.project(:id => issue.project_id, :name => issue.project.name) unless issue.project.nil? + api.tracker(:id => issue.tracker_id, :name => issue.tracker.name) unless issue.tracker.nil? + api.status(:id => issue.status_id, :name => issue.status.name) unless issue.status.nil? + api.priority(:id => issue.priority_id, :name => issue.priority.name) unless issue.priority.nil? + api.author(:id => issue.author_id, :name => issue.author.name) unless issue.author.nil? + api.assigned_to(:id => issue.assigned_to_id, :name => issue.assigned_to.name) unless issue.assigned_to.nil? + api.category(:id => issue.category_id, :name => issue.category.name) unless issue.category.nil? + api.fixed_version(:id => issue.fixed_version_id, :name => issue.fixed_version.name) unless issue.fixed_version.nil? + api.parent(:id => issue.parent_id) unless issue.parent.nil? + + api.subject issue.subject + api.description issue.description + api.start_date issue.start_date + api.due_date issue.due_date + api.done_ratio issue.done_ratio + api.estimated_hours issue.estimated_hours + + render_api_custom_values issue.custom_field_values, api + + api.created_on issue.created_on + api.updated_on issue.updated_on + api.closed_on issue.closed_on + + api.array :relations do + issue.relations.each do |relation| + api.relation(:id => relation.id, :issue_id => relation.issue_from_id, :issue_to_id => relation.issue_to_id, :relation_type => relation.relation_type, :delay => relation.delay) + end + end if include_in_api_response?('relations') + end + end +end diff --git a/app/views/issues/index.html.erb b/app/views/issues/index.html.erb new file mode 100644 index 00000000..3d54e9cb --- /dev/null +++ b/app/views/issues/index.html.erb @@ -0,0 +1,121 @@ +
    + <% if !@query.new_record? && @query.editable_by?(User.current) %> + <%= link_to l(:button_edit), edit_query_path(@query), :class => 'icon icon-edit' %> + <%= delete_link query_path(@query) %> + <% end %> +
    + +<% html_title(@query.new_record? ? l(:label_issue_plural) : @query.name) %> + +<%= form_tag({ :controller => 'issues', :action => 'index', :project_id => @project }, +:method => :get, :id => 'query_form') do %> +<%= hidden_field_tag 'set_filter', '1' %> +
    +
    "> + + <%= l(:label_filter_plural) %> + +
    "> + <%= render :partial => 'queries/filters', :locals => {:query => @query} %> +
    +
    + +
    +

    + + <%= link_to_function l(:button_apply), 'submit_query_form("query_form")', :class => 'icon icon-checked' %> + <%= link_to l(:button_clear), { :set_filter => 1, :project_id => @project }, :class => 'icon icon-reload' %> + <%= link_to l(:label_issue_new), { :controller => 'issues', :action => 'new', :copy_from => nil }, :param => :project_id, :caption => :label_issue_new, + :html => { :accesskey => Redmine::AccessKeys.key_for(:new_issue) }, :class => 'icon icon-add' %> + <% if @query.new_record? && User.current.allowed_to?(:save_queries, @project, :global => true) %> + <%= link_to_function l(:button_save), + "$('#query_form').attr('action', '#{ @project ? new_project_query_path(@project) : new_query_path }'); submit_query_form('query_form')", + :class => 'icon icon-save' %> + <% end %> +

    +<% end %> + +<%= error_messages_for 'query' %> +<% if @query.valid? %> +<% if @issues.empty? %> +

    + <%= l(:label_no_data) %> +

    +<% else %> +<%= render :partial => 'issues/list', :locals => {:issues => @issues, :query => @query} %> + + +<% end %> + +<% other_formats_links do |f| %> +<%= f.link_to 'Atom', :url => params.merge(:key => User.current.rss_key) %> +<%= f.link_to 'CSV', :url => params, :onclick => "showModal('csv-export-options', '330px'); return false;" %> +<%= f.link_to 'PDF', :url => params %> +<% end %> + + + +<% end %> +<%= call_hook(:view_issues_index_bottom, { :issues => @issues, :project => @project, :query => @query }) %> + +<% content_for :sidebar do %> +<%= render :partial => 'issues/sidebar' %> +<% end %> + +<% content_for :header_tags do %> +<%= auto_discovery_link_tag(:atom, +{:query_id => @query, :format => 'atom', +:page => nil, :key => User.current.rss_key}, +:title => l(:label_issue_plural)) %> +<%= auto_discovery_link_tag(:atom, +{:controller => 'journals', :action => 'index', +:query_id => @query, :format => 'atom', +:page => nil, :key => User.current.rss_key}, +:title => l(:label_changes_details)) %> +<% end %> + +<%= context_menu issues_context_menu_path %> diff --git a/app/views/issues/new.html.erb b/app/views/issues/new.html.erb new file mode 100644 index 00000000..82b3f6f9 --- /dev/null +++ b/app/views/issues/new.html.erb @@ -0,0 +1,53 @@ +<%= call_hook(:view_issues_new_top, {:issue => @issue}) %> + +<%= labelled_form_for @issue, :url => project_issues_path(@project), + :html => {:id => 'issue-form', :multipart => true} do |f| %> + <%= error_messages_for 'issue' %> + <%= hidden_field_tag 'copy_from', params[:copy_from] if params[:copy_from] %> +
    +
    + <%= render :partial => 'issues/form', :locals => {:f => f} %> +
    + + <% if @copy_from && @copy_from.attachments.any? %> +

    + + <%= check_box_tag 'copy_attachments', '1', @copy_attachments %> +

    + <% end %> + <% if @copy_from && !@copy_from.leaf? %> +

    + + <%= check_box_tag 'copy_subtasks', '1', @copy_subtasks %> +

    + <% end %> + +

    <%= render :partial => 'attachments/form', :locals => {:container => @issue} %>

    + + <% if @issue.safe_attribute? 'watcher_user_ids' -%> +

    + + <%= watchers_checkboxes(@issue, @available_watchers) %> + + + <%= link_to l(:label_search_for_watchers), + {:controller => 'watchers', :action => 'new', :project_id => @issue.project}, + :remote => true, + :method => 'get' %> + +

    + <% end %> +
    + + <%= submit_tag l(:button_create) %> + <%= submit_tag l(:button_create_and_continue), :name => 'continue' %> + <%= preview_link preview_new_issue_path(:project_id => @project), 'issue-form' %> + + <%= javascript_tag "$('#issue_subject').focus();" %> +<% end %> + +
    + +<% content_for :header_tags do %> + <%= robot_exclusion_tag %> +<% end %> diff --git a/app/views/issues/show.api.rsb b/app/views/issues/show.api.rsb new file mode 100644 index 00000000..ce788a72 --- /dev/null +++ b/app/views/issues/show.api.rsb @@ -0,0 +1,74 @@ +api.issue do + api.id @issue.id + api.project(:id => @issue.project_id, :name => @issue.project.name) unless @issue.project.nil? + api.tracker(:id => @issue.tracker_id, :name => @issue.tracker.name) unless @issue.tracker.nil? + api.status(:id => @issue.status_id, :name => @issue.status.name) unless @issue.status.nil? + api.priority(:id => @issue.priority_id, :name => @issue.priority.name) unless @issue.priority.nil? + api.author(:id => @issue.author_id, :name => @issue.author.name) unless @issue.author.nil? + api.assigned_to(:id => @issue.assigned_to_id, :name => @issue.assigned_to.name) unless @issue.assigned_to.nil? + api.category(:id => @issue.category_id, :name => @issue.category.name) unless @issue.category.nil? + api.fixed_version(:id => @issue.fixed_version_id, :name => @issue.fixed_version.name) unless @issue.fixed_version.nil? + api.parent(:id => @issue.parent_id) unless @issue.parent.nil? + + api.subject @issue.subject + api.description @issue.description + api.start_date @issue.start_date + api.due_date @issue.due_date + api.done_ratio @issue.done_ratio + api.estimated_hours @issue.estimated_hours + api.spent_hours(@issue.spent_hours) if User.current.allowed_to?(:view_time_entries, @project) + + render_api_custom_values @issue.custom_field_values, api + + api.created_on @issue.created_on + api.updated_on @issue.updated_on + api.closed_on @issue.closed_on + + render_api_issue_children(@issue, api) if include_in_api_response?('children') + + api.array :attachments do + @issue.attachments.each do |attachment| + render_api_attachment(attachment, api) + end + end if include_in_api_response?('attachments') + + api.array :relations do + @relations.each do |relation| + api.relation(:id => relation.id, :issue_id => relation.issue_from_id, :issue_to_id => relation.issue_to_id, :relation_type => relation.relation_type, :delay => relation.delay) + end + end if include_in_api_response?('relations') && @relations.present? + + api.array :changesets do + @issue.changesets.each do |changeset| + api.changeset :revision => changeset.revision do + api.user(:id => changeset.user_id, :name => changeset.user.name) unless changeset.user.nil? + api.comments changeset.comments + api.committed_on changeset.committed_on + end + end + end if include_in_api_response?('changesets') && User.current.allowed_to?(:view_changesets, @project) + + api.array :journals do + @journals.each do |journal| + api.journal :id => journal.id do + api.user(:id => journal.user_id, :name => journal.user.name) unless journal.user.nil? + api.notes journal.notes + api.created_on journal.created_on + api.array :details do + journal.details.each do |detail| + api.detail :property => detail.property, :name => detail.prop_key do + api.old_value detail.old_value + api.new_value detail.value + end + end + end + end + end + end if include_in_api_response?('journals') + + api.array :watchers do + @issue.watcher_users.each do |user| + api.user :id => user.id, :name => user.name + end + end if include_in_api_response?('watchers') && User.current.allowed_to?(:view_issue_watchers, @issue.project) +end diff --git a/app/views/issues/show.html.erb b/app/views/issues/show.html.erb new file mode 100644 index 00000000..c7ce9a23 --- /dev/null +++ b/app/views/issues/show.html.erb @@ -0,0 +1,164 @@ +<%= render :partial => 'action_menu' %> + +

    <%= issue_heading(@issue) %>

    + +
    + <% if @prev_issue_id || @next_issue_id %> + + <% end %> + + <%= avatar(@issue.author, :size => "50") %> + + +
    +<%= render_issue_subject_with_tree(@issue) %> +
    +

    + <%= authoring @issue.created_on, @issue.author %>. + <% if @issue.created_on != @issue.updated_on %> + <%= l(:label_updated_time, time_tag(@issue.updated_on)).html_safe %>. + <% end %> + +

    + +
    + <%= render :partial => 'layouts/tag', :locals => {:obj => @issue,:object_flag => "3" }%> +
    + + +<%= issue_fields_rows do |rows| + rows.left l(:field_status), h(@issue.status.name), :class => 'status' + rows.left l(:field_priority), h(@issue.priority.name), :class => 'priority' + + unless @issue.disabled_core_fields.include?('assigned_to_id') + rows.left l(:field_assigned_to), avatar(@issue.assigned_to, :size => "14").to_s.html_safe + (@issue.assigned_to ? link_to_user(@issue.assigned_to) : "-"), :class => 'assigned-to' + end + unless @issue.disabled_core_fields.include?('category_id') + rows.left l(:field_category), h(@issue.category ? @issue.category.name : "-"), :class => 'category' + end + unless @issue.disabled_core_fields.include?('fixed_version_id') + rows.left l(:field_fixed_version), (@issue.fixed_version ? link_to_version(@issue.fixed_version) : "-"), :class => 'fixed-version' + end + + unless @issue.disabled_core_fields.include?('start_date') + rows.right l(:field_start_date), format_date(@issue.start_date), :class => 'start-date' + end + unless @issue.disabled_core_fields.include?('due_date') + rows.right l(:field_due_date), format_date(@issue.due_date), :class => 'due-date' + end + unless @issue.disabled_core_fields.include?('done_ratio') + rows.right l(:field_done_ratio), progress_bar(@issue.done_ratio, :width => '80px', :legend => "#{@issue.done_ratio}%"), :class => 'progress' + end + unless @issue.disabled_core_fields.include?('estimated_hours') + unless @issue.estimated_hours.nil? + rows.right l(:field_estimated_hours), l_hours(@issue.estimated_hours), :class => 'estimated-hours' + end + end + if User.current.allowed_to?(:view_time_entries, @project) + rows.right l(:label_spent_time), (@issue.total_spent_hours > 0 ? link_to(l_hours(@issue.total_spent_hours), project_issue_time_entries_path(@project, @issue)) : "-"), :class => 'spent-time' + end +end %> +<%= render_custom_fields_rows(@issue) %> +<%= call_hook(:view_issues_show_details_bottom, :issue => @issue) %> +
    + +<% if @issue.description? || @issue.attachments.any? -%> +
    +<% if @issue.description? %> +
    +
    + <%= link_to l(:button_quote), quoted_issue_path(@issue), :remote => true, :method => 'post', :class => 'icon icon-comment' if authorize_for('issues', 'edit') %> +
    + +

    <%=l(:field_description)%>

    +
    + <%= textilizable @issue, :description, :attachments => @issue.attachments %> +
    +
    +<% end %> +<%= link_to_attachments @issue, :thumbnails => true %> +<% end -%> + +<%= call_hook(:view_issues_show_description_bottom, :issue => @issue) %> + +<% if !@issue.leaf? || User.current.allowed_to?(:manage_subtasks, @project) %> +
    +
    +
    + <%= link_to_new_subtask(@issue) if User.current.allowed_to?(:manage_subtasks, @project) %> +
    +

    <%=l(:label_subtask_plural)%>

    +<%= render_descendants_tree(@issue) unless @issue.leaf? %> +
    +<% end %> + +<% if @relations.present? || User.current.allowed_to?(:manage_issue_relations, @project) %> +
    +
    +<%= render :partial => 'relations' %> +
    +<% end %> + +
    + +<% if @changesets.present? %> +
    +

    <%=l(:label_associated_revisions)%>

    +<%= render :partial => 'changesets', :locals => { :changesets => @changesets} %> +
    +<% end %> + +<% if @journals.present? %> +
    +

    <%=l(:label_history)%>

    +<%= render :partial => 'history', :locals => { :issue => @issue, :journals => @journals } %> +
    +<% end %> + + +
    +<%= render :partial => 'action_menu' %> + +
    +<% if @issue.editable? %> + +<% end %> + +<% other_formats_links do |f| %> + <%= f.link_to 'Atom', :url => {:key => User.current.rss_key} %> + <%= f.link_to 'PDF' %> +<% end %> + +<% html_title "#{@issue.tracker.name} ##{@issue.id}: #{@issue.subject}" %> + +<% content_for :sidebar do %> + <%= render :partial => 'issues/sidebar' %> + + <% if User.current.allowed_to?(:add_issue_watchers, @project) || + (@issue.watchers.present? && User.current.allowed_to?(:view_issue_watchers, @project)) %> +
    + <%= render :partial => 'watchers/watchers', :locals => {:watched => @issue} %> +
    + <% end %> +<% end %> + +<% content_for :header_tags do %> + <%= auto_discovery_link_tag(:atom, {:format => 'atom', :key => User.current.rss_key}, :title => "#{@issue.project} - #{@issue.tracker} ##{@issue.id}: #{@issue.subject}") %> +<% end %> + +<%= context_menu issues_context_menu_path %> diff --git a/app/views/issues/update_form.js.erb b/app/views/issues/update_form.js.erb new file mode 100644 index 00000000..46fc9722 --- /dev/null +++ b/app/views/issues/update_form.js.erb @@ -0,0 +1,7 @@ +$('#all_attributes').html('<%= escape_javascript(render :partial => 'form') %>'); + +<% if User.current.allowed_to?(:log_time, @issue.project) %> + $('#log_time').show(); +<% else %> + $('#log_time').hide(); +<% end %> diff --git a/app/views/journals/_notes_form.html.erb b/app/views/journals/_notes_form.html.erb new file mode 100644 index 00000000..63b87883 --- /dev/null +++ b/app/views/journals/_notes_form.html.erb @@ -0,0 +1,18 @@ +<%= form_tag({:controller => 'journals', :action => 'edit', :id => @journal}, + :remote => true, + :id => "journal-#{@journal.id}-form") do %> + <%= label_tag "notes", l(:description_notes), :class => "hidden-for-sighted" %> + <%= text_area_tag :notes, @journal.notes, + :id => "journal_#{@journal.id}_notes", + :class => 'wiki-edit', + :rows => (@journal.notes.blank? ? 10 : [[10, @journal.notes.length / 50].max, 100].min) %> + <%= call_hook(:view_journals_notes_form_after_notes, { :journal => @journal}) %> +

    <%= submit_tag l(:button_save) %> + <%= preview_link preview_edit_issue_path(:project_id => @project, :id => @journal.issue), + "journal-#{@journal.id}-form", + "journal_#{@journal.id}_preview" %> | + <%= link_to l(:button_cancel), '#', :onclick => "$('#journal-#{@journal.id}-form').remove(); $('#journal-#{@journal.id}-notes').show(); return false;" %>

    + +
    +<% end %> +<%= wikitoolbar_for "journal_#{@journal.id}_notes" %> diff --git a/app/views/journals/diff.html.erb b/app/views/journals/diff.html.erb new file mode 100644 index 00000000..d846b9d1 --- /dev/null +++ b/app/views/journals/diff.html.erb @@ -0,0 +1,10 @@ +

    <%=h @issue.tracker %> #<%= @issue.id %>

    +

    <%= authoring @journal.created_on, @journal.user, :label => :label_updated_time_by %>

    + +
    +<%= simple_format_without_paragraph @diff.to_html %> +
    + +

    <%= link_to l(:button_back), issue_path(@issue), :onclick => 'history.back(); return false;' %>

    + +<% html_title "#{@issue.tracker.name} ##{@issue.id}: #{@issue.subject}" %> diff --git a/app/views/journals/edit.js.erb b/app/views/journals/edit.js.erb new file mode 100644 index 00000000..96cf6b4f --- /dev/null +++ b/app/views/journals/edit.js.erb @@ -0,0 +1,8 @@ +$("#journal-<%= @journal.id %>-notes").hide(); + +if ($("form#journal-<%= @journal.id %>-form").length > 0) { + // journal edit form already loaded + $("#journal-<%= @journal.id %>-form").show(); +} else { + $("#journal-<%= @journal.id %>-notes").after('<%= escape_javascript(render :partial => 'notes_form') %>'); +} diff --git a/app/views/journals/index.builder b/app/views/journals/index.builder new file mode 100644 index 00000000..a81ff98a --- /dev/null +++ b/app/views/journals/index.builder @@ -0,0 +1,30 @@ +xml.instruct! +xml.feed "xmlns" => "http://www.w3.org/2005/Atom" do + xml.title @title + xml.link "rel" => "self", "href" => url_for(:format => 'atom', :key => User.current.rss_key, :only_path => false) + xml.link "rel" => "alternate", "href" => home_url(:only_path => false) + xml.id url_for(:controller => 'welcome', :only_path => false) + xml.updated((@journals.first ? @journals.first.event_datetime : Time.now).xmlschema) + xml.author { xml.name "#{Setting.app_title}" } + @journals.each do |change| + issue = change.issue + xml.entry do + xml.title "#{issue.project.name} - #{issue.tracker.name} ##{issue.id}: #{issue.subject}" + xml.link "rel" => "alternate", "href" => url_for(:controller => 'issues' , :action => 'show', :id => issue, :only_path => false) + xml.id url_for(:controller => 'issues' , :action => 'show', :id => issue, :journal_id => change, :only_path => false) + xml.updated change.created_on.xmlschema + xml.author do + xml.name change.user.name + xml.email(change.user.mail) if change.user.is_a?(User) && !change.user.mail.blank? && !change.user.pref.hide_mail + end + xml.content "type" => "html" do + xml.text! '
      ' + details_to_strings(change.details, false).each do |string| + xml.text! '
    • ' + string + '
    • ' + end + xml.text! '
    ' + xml.text! textilizable(change, :notes, :only_path => false) unless change.notes.blank? + end + end + end +end diff --git a/app/views/journals/new.js.erb b/app/views/journals/new.js.erb new file mode 100644 index 00000000..78ec5f36 --- /dev/null +++ b/app/views/journals/new.js.erb @@ -0,0 +1,10 @@ +$('#issue_notes').val("<%= raw escape_javascript(@content) %>"); +<% + # when quoting a private journal, check the private checkbox + if @journal && @journal.private_notes? +%> +$('#issue_private_notes').attr('checked', true); +<% end %> + +showAndScrollTo("update", "notes"); +$('#notes').scrollTop = $('#notes').scrollHeight - $('#notes').clientHeight; diff --git a/app/views/journals/update.js.erb b/app/views/journals/update.js.erb new file mode 100644 index 00000000..65c198d5 --- /dev/null +++ b/app/views/journals/update.js.erb @@ -0,0 +1,9 @@ +<% if @journal.frozen? %> + $("#change-<%= @journal.id %>").remove(); +<% else %> + $("#journal-<%= @journal.id %>-notes").replaceWith('<%= escape_javascript(render_notes(@journal.issue, @journal, :reply_links => authorize_for('issues', 'edit'))) %>'); + $("#journal-<%= @journal.id %>-notes").show(); + $("#journal-<%= @journal.id %>-form").remove(); +<% end %> + +<%= call_hook(:view_journals_update_js_bottom, { :journal => @journal }) %> diff --git a/app/views/layouts/_base_header.html.erb b/app/views/layouts/_base_header.html.erb new file mode 100644 index 00000000..093ee934 --- /dev/null +++ b/app/views/layouts/_base_header.html.erb @@ -0,0 +1,7 @@ +
    +
    + <%= render_menu :account_menu -%> +
    + <%= content_tag('div', "#{l(:label_logged_as)} #{link_to_user(User.current, :format => :username)}".html_safe, :id => 'loggedas') if User.current.logged? %> + <%= render_menu :top_menu if User.current.logged? || !Setting.login_required? -%> +
    \ No newline at end of file diff --git a/app/views/layouts/_tag.html.erb b/app/views/layouts/_tag.html.erb new file mode 100644 index 00000000..04c62fd1 --- /dev/null +++ b/app/views/layouts/_tag.html.erb @@ -0,0 +1,20 @@ + + + + +<%= toggle_link (image_tag "/images/add.png"), 'put-tag-form', {:focus => 'name'} %> +
    + <%= render :partial => "layouts/tag_name",:locals => {:obj => obj,:non_list_all => false ,:object_flag => object_flag} %> +
    + + diff --git a/app/views/layouts/_tag_name.html.erb b/app/views/layouts/_tag_name.html.erb new file mode 100644 index 00000000..d510e003 --- /dev/null +++ b/app/views/layouts/_tag_name.html.erb @@ -0,0 +1,55 @@ + + +<% @tags = obj.reload.tag_list %> + +<% if non_list_all and (@tags.size > 0) %> + + <% if @tags.size > Setting.show_tags_length.to_i then %> + <% i = 0 %> + <% until i>Setting.show_tags_length.to_i do %> +
    + <%= link_to @tags[i], :controller => "tags",:action => "index",:q => @tags[i],:object_flag => object_flag,:obj_id => obj.id %> +
    + <% i += 1%> + <% end %> + <%= link_to l(:label_more_tags),:action => "show",:id => obj.id %> + + <% else %> + + <% @tags.each do |tag| %> +
    + <%= link_to tag,:controller => "tags",:action => "index",:q=>tag,:object_flag => object_flag,:obj_id => obj.id + %> +
    + <% end %> + <% end %> + +<% else %> + + <% if @tags.size > 0 %> + <% @tags.each do |tag| %> +
    + <%= link_to tag,:controller => "tags",:action => "index",:q=>tag ,:object_flag => object_flag,:obj_id => obj.id %> +
    + <% end %> + <% end %> + +<% end %> \ No newline at end of file diff --git a/app/views/layouts/admin.html.erb b/app/views/layouts/admin.html.erb new file mode 100644 index 00000000..8f23129b --- /dev/null +++ b/app/views/layouts/admin.html.erb @@ -0,0 +1,8 @@ +<% unless controller_name == 'admin' && action_name == 'index' %> + <% content_for :sidebar do %> +

    <%=l(:label_administration)%>

    + <%= render :partial => 'admin/menu' %> + <% end %> +<% end %> + +<%= render :file => "layouts/base" %> diff --git a/app/views/layouts/base.html.erb b/app/views/layouts/base.html.erb new file mode 100644 index 00000000..5925253b --- /dev/null +++ b/app/views/layouts/base.html.erb @@ -0,0 +1,43 @@ + + + + +<%=h html_title %> + + +<%= csrf_meta_tag %> +<%= favicon %> +<%= stylesheet_link_tag 'jquery/jquery-ui-1.9.2', 'application', :media => 'all' %> +<%= stylesheet_link_tag 'rtl', :media => 'all' if l(:direction) == 'rtl' %> +<%= javascript_heads %> +<%= heads_for_theme %> +<%= call_hook :view_layouts_base_html_head %> + +<%= yield :header_tags -%> + + +
    +
    +
    + +<%=render :partial => 'layouts/base_header'%> + +
    +
    + <%= render_flash_messages %> + <%= yield %> + <%= call_hook :view_layouts_base_content %> +
    +
    +
    +
    + + + + + +
    +
    +<%= call_hook :view_layouts_base_body_bottom %> + + diff --git a/app/views/layouts/base.html_old.erb b/app/views/layouts/base.html_old.erb new file mode 100644 index 00000000..90cf1e88 --- /dev/null +++ b/app/views/layouts/base.html_old.erb @@ -0,0 +1,80 @@ + + + + +<%=h html_title %> + + +<%= csrf_meta_tag %> +<%= favicon %> +<%= stylesheet_link_tag 'jquery/jquery-ui-1.9.2', 'application', :media => 'all' %> +<%= stylesheet_link_tag 'rtl', :media => 'all' if l(:direction) == 'rtl' %> +<%= javascript_heads %> +<%= heads_for_theme %> +<%= call_hook :view_layouts_base_html_head %> + +<%= yield :header_tags -%> + + +
    +
    +
    +
    +
    + <%= render_menu :account_menu -%> +
    + <%= content_tag('div', "#{l(:label_logged_as)} #{link_to_user(User.current, :format => :username)}".html_safe, :id => 'loggedas') if User.current.logged? %> + <%= render_menu :top_menu if User.current.logged? || !Setting.login_required? -%> +
    + + + + +
    + + + + + +
    +
    +<%= call_hook :view_layouts_base_body_bottom %> + + diff --git a/app/views/layouts/base_.html.erb b/app/views/layouts/base_.html.erb new file mode 100644 index 00000000..7798eda3 --- /dev/null +++ b/app/views/layouts/base_.html.erb @@ -0,0 +1,75 @@ + + + + +<%=h html_title %> + + +<%= csrf_meta_tag %> +<%= favicon %> +<%= stylesheet_link_tag 'jquery/jquery-ui-1.9.2', 'application', :media => 'all' %> +<%= stylesheet_link_tag 'rtl', :media => 'all' if l(:direction) == 'rtl' %> +<%= javascript_heads %> +<%= heads_for_theme %> +<%= call_hook :view_layouts_base_html_head %> + +<%= yield :header_tags -%> + + +
    +
    +
    +
    +
    + <%= render_menu :account_menu -%> +
    + <%= content_tag('div', "#{l(:label_logged_as_new)}: #{link_to_user(User.current, :format => :username)}".html_safe, :id => 'loggedas') if User.current.logged? %> + <%= render_menu :top_menu if User.current.logged? || !Setting.login_required? -%> +
    +<% if display_main_menu?(@project) %> + +<% end %> + +
    + + + + + +
    +
    +<%= call_hook :view_layouts_base_body_bottom %> + + diff --git a/app/views/layouts/base_bids.html.erb b/app/views/layouts/base_bids.html.erb new file mode 100644 index 00000000..f61d1d1c --- /dev/null +++ b/app/views/layouts/base_bids.html.erb @@ -0,0 +1,159 @@ + + + + + <%= h html_title %> + + + <%= csrf_meta_tag %> + <%= favicon %> + <%= stylesheet_link_tag 'jquery/jquery-ui-1.9.2', 'application', :media => 'all' %> + <%= stylesheet_link_tag 'rtl', :media => 'all' if l(:direction) == 'rtl' %> + <%= javascript_heads %> + <%= heads_for_theme %> + <%= call_hook :view_layouts_base_html_head %> + + <%= yield :header_tags -%> + + +
    +
    +
    + + <%=render :partial => 'layouts/base_header'%> + +
    + +
    + <% if display_main_menu?(@bid) %> +
    + <%= render_menu :bid_menu %> +
    + <% end %> + <%= render_flash_messages %> + <%= yield %> + <%= call_hook :view_layouts_base_content %> +
    +
    +
    +
    +
    + + + + + +
    +
    + <%= call_hook :view_layouts_base_body_bottom %> + + diff --git a/app/views/layouts/base_old.html.erb b/app/views/layouts/base_old.html.erb new file mode 100644 index 00000000..32da883f --- /dev/null +++ b/app/views/layouts/base_old.html.erb @@ -0,0 +1,156 @@ + + + + + <%= h html_title %> + + + <%= csrf_meta_tag %> + <%= favicon %> + <%= stylesheet_link_tag 'jquery/jquery-ui-1.9.2', 'application', :media => 'all' %> + <%= stylesheet_link_tag 'rtl', :media => 'all' if l(:direction) == 'rtl' %> + <%= javascript_heads %> + <%= heads_for_theme %> + <%= call_hook :view_layouts_base_html_head %> + + <%= yield :header_tags -%> + + +
    +
    +
    +
    +
    + <%= render_menu :account_menu -%> +
    + <%= content_tag('div', "#{l(:label_logged_as)} #{link_to_user(User.current, :format => :username)}".html_safe, :id => 'loggedas') if User.current.logged? %> + <%= render_menu :top_menu if User.current.logged? || !Setting.login_required? -%> +
    + + + + + + + + + + +
    +
    + <%= call_hook :view_layouts_base_body_bottom %> + + diff --git a/app/views/layouts/base_projects.html.erb b/app/views/layouts/base_projects.html.erb new file mode 100644 index 00000000..ca7c2ddf --- /dev/null +++ b/app/views/layouts/base_projects.html.erb @@ -0,0 +1,135 @@ + + + + + <%= h html_title %> + + + <%= csrf_meta_tag %> + <%= favicon %> + <%= stylesheet_link_tag 'jquery/jquery-ui-1.9.2', 'application', :media => 'all' %> + <%= stylesheet_link_tag 'rtl', :media => 'all' if l(:direction) == 'rtl' %> + <%= javascript_heads %> + <%= heads_for_theme %> + <%= call_hook :view_layouts_base_html_head %> + + <%= yield :header_tags -%> + + +
    +
    +
    + + <%=render :partial => 'layouts/base_header'%> + +
    + + + +
    +
    + <%= render_main_menu(@project) %> +
    + <%= yield %> + <%= call_hook :view_layouts_base_content %> +
    + <%= render_flash_messages %> +
    +
    + + + + + +
    +
    + <%= call_hook :view_layouts_base_body_bottom %> + + diff --git a/app/views/layouts/base_users.html.erb b/app/views/layouts/base_users.html.erb new file mode 100644 index 00000000..f9c4c8c2 --- /dev/null +++ b/app/views/layouts/base_users.html.erb @@ -0,0 +1,155 @@ + + + + + <%= h html_title %> + + + <%= csrf_meta_tag %> + <%= favicon %> + <%= stylesheet_link_tag 'jquery/jquery-ui-1.9.2', 'application', :media => 'all' %> + <%= stylesheet_link_tag 'rtl', :media => 'all' if l(:direction) == 'rtl' %> + <%= javascript_heads %> + <%= heads_for_theme %> + <%= call_hook :view_layouts_base_html_head %> + + <%= yield :header_tags -%> + + +
    +
    +
    +
    +
    +
    + <%= render_menu :account_menu -%> +
    + <%= content_tag('div', "#{l(:label_logged_as)} #{link_to_user(User.current, :format => :username)}".html_safe, :id => 'loggedas') if User.current.logged? %> + <%= render_menu :top_menu if User.current.logged? || !Setting.login_required? -%> +
    + +
    + + + +
    +
    + <%= render_menu :user_menu %> +
    + <%= yield %> + <%= call_hook :view_layouts_base_content %> +
    + <%= render_flash_messages %> +
    +
    + + + + + +
    +
    + <%= call_hook :view_layouts_base_body_bottom %> + + diff --git a/app/views/layouts/mailer.html.erb b/app/views/layouts/mailer.html.erb new file mode 100644 index 00000000..b95dc8ac --- /dev/null +++ b/app/views/layouts/mailer.html.erb @@ -0,0 +1,33 @@ + + + + + +<%= Redmine::WikiFormatting.to_html(Setting.text_formatting, Setting.emails_header).html_safe %> +<%= yield %> +
    +<%= Redmine::WikiFormatting.to_html(Setting.text_formatting, Setting.emails_footer).html_safe %> + + diff --git a/app/views/layouts/mailer.text.erb b/app/views/layouts/mailer.text.erb new file mode 100644 index 00000000..4b8c0b4f --- /dev/null +++ b/app/views/layouts/mailer.text.erb @@ -0,0 +1,4 @@ +<%= Setting.emails_header %> +<%= yield %> +-- +<%= Setting.emails_footer %> diff --git a/app/views/list/members.html.erb b/app/views/list/members.html.erb new file mode 100644 index 00000000..e7b36763 --- /dev/null +++ b/app/views/list/members.html.erb @@ -0,0 +1,8 @@ + + + Hello, Rails! + + +

    Hello from Rails!

    + + \ No newline at end of file diff --git a/app/views/mailer/_issue.html.erb b/app/views/mailer/_issue.html.erb new file mode 100644 index 00000000..3d851d44 --- /dev/null +++ b/app/views/mailer/_issue.html.erb @@ -0,0 +1,15 @@ +

    <%= link_to(h("#{issue.tracker.name} ##{issue.id}: #{issue.subject}"), issue_url) %>

    + +
      +
    • <%=l(:field_author)%>: <%=h issue.author %>
    • +
    • <%=l(:field_status)%>: <%=h issue.status %>
    • +
    • <%=l(:field_priority)%>: <%=h issue.priority %>
    • +
    • <%=l(:field_assigned_to)%>: <%=h issue.assigned_to %>
    • +
    • <%=l(:field_category)%>: <%=h issue.category %>
    • +
    • <%=l(:field_fixed_version)%>: <%=h issue.fixed_version %>
    • +<% issue.custom_field_values.each do |c| %> +
    • <%=h c.custom_field.name %>: <%=h show_value(c) %>
    • +<% end %> +
    + +<%= textilizable(issue, :description, :only_path => false) %> diff --git a/app/views/mailer/_issue.text.erb b/app/views/mailer/_issue.text.erb new file mode 100644 index 00000000..427b6a89 --- /dev/null +++ b/app/views/mailer/_issue.text.erb @@ -0,0 +1,13 @@ +<%= "#{issue.tracker.name} ##{issue.id}: #{issue.subject}" %> +<%= issue_url %> + +* <%=l(:field_author)%>: <%= issue.author %> +* <%=l(:field_status)%>: <%= issue.status %> +* <%=l(:field_priority)%>: <%= issue.priority %> +* <%=l(:field_assigned_to)%>: <%= issue.assigned_to %> +* <%=l(:field_category)%>: <%= issue.category %> +* <%=l(:field_fixed_version)%>: <%= issue.fixed_version %> +<% issue.custom_field_values.each do |c| %>* <%= c.custom_field.name %>: <%= show_value(c) %> +<% end -%> +---------------------------------------- +<%= issue.description %> diff --git a/app/views/mailer/account_activated.html.erb b/app/views/mailer/account_activated.html.erb new file mode 100644 index 00000000..cb8d8caa --- /dev/null +++ b/app/views/mailer/account_activated.html.erb @@ -0,0 +1,2 @@ +

    <%= l(:notice_account_activated) %>

    +

    <%= l(:label_login) %>: <%= link_to h(@login_url), @login_url %>

    diff --git a/app/views/mailer/account_activated.text.erb b/app/views/mailer/account_activated.text.erb new file mode 100644 index 00000000..4dac4fb8 --- /dev/null +++ b/app/views/mailer/account_activated.text.erb @@ -0,0 +1,2 @@ +<%= l(:notice_account_activated) %> +<%= l(:label_login) %>: <%= @login_url %> diff --git a/app/views/mailer/account_activation_request.html.erb b/app/views/mailer/account_activation_request.html.erb new file mode 100644 index 00000000..4450631b --- /dev/null +++ b/app/views/mailer/account_activation_request.html.erb @@ -0,0 +1,2 @@ +

    <%= l(:mail_body_account_activation_request, h(@user.login)) %>

    +

    <%= link_to h(@url), @url %>

    diff --git a/app/views/mailer/account_activation_request.text.erb b/app/views/mailer/account_activation_request.text.erb new file mode 100644 index 00000000..f431e22d --- /dev/null +++ b/app/views/mailer/account_activation_request.text.erb @@ -0,0 +1,2 @@ +<%= l(:mail_body_account_activation_request, @user.login) %> +<%= @url %> diff --git a/app/views/mailer/account_information.html.erb b/app/views/mailer/account_information.html.erb new file mode 100644 index 00000000..426aacee --- /dev/null +++ b/app/views/mailer/account_information.html.erb @@ -0,0 +1,11 @@ +<% if @user.auth_source %> +

    <%= l(:mail_body_account_information_external, h(@user.auth_source.name)) %>

    +<% else %> +

    <%= l(:mail_body_account_information) %>:

    +
      +
    • <%= l(:field_login) %>: <%=h @user.login %>
    • +
    • <%= l(:field_password) %>: <%=h @password %>
    • +
    +<% end %> + +

    <%= l(:label_login) %>: <%= link_to h(@login_url), @login_url %>

    diff --git a/app/views/mailer/account_information.text.erb b/app/views/mailer/account_information.text.erb new file mode 100644 index 00000000..0a02566d --- /dev/null +++ b/app/views/mailer/account_information.text.erb @@ -0,0 +1,6 @@ +<% if @user.auth_source %><%= l(:mail_body_account_information_external, @user.auth_source.name) %> +<% else %><%= l(:mail_body_account_information) %>: +* <%= l(:field_login) %>: <%= @user.login %> +* <%= l(:field_password) %>: <%= @password %> +<% end %> +<%= l(:label_login) %>: <%= @login_url %> diff --git a/app/views/mailer/attachments_added.html.erb b/app/views/mailer/attachments_added.html.erb new file mode 100644 index 00000000..11d1cf54 --- /dev/null +++ b/app/views/mailer/attachments_added.html.erb @@ -0,0 +1,5 @@ +<%= link_to h(@added_to), @added_to_url %>
    + +
      <% @attachments.each do |attachment | %> +
    • <%=h attachment.filename %>
    • +<% end %>
    diff --git a/app/views/mailer/attachments_added.text.erb b/app/views/mailer/attachments_added.text.erb new file mode 100644 index 00000000..28cb8285 --- /dev/null +++ b/app/views/mailer/attachments_added.text.erb @@ -0,0 +1,4 @@ +<%= @added_to %><% @attachments.each do |attachment | %> +- <%= attachment.filename %><% end %> + +<%= @added_to_url %> diff --git a/app/views/mailer/document_added.html.erb b/app/views/mailer/document_added.html.erb new file mode 100644 index 00000000..8606dd78 --- /dev/null +++ b/app/views/mailer/document_added.html.erb @@ -0,0 +1,3 @@ +<%= link_to(h(@document.title), @document_url) %> (<%=h @document.category.name %>)
    +
    +<%= textilizable(@document, :description, :only_path => false) %> diff --git a/app/views/mailer/document_added.text.erb b/app/views/mailer/document_added.text.erb new file mode 100644 index 00000000..a6a72829 --- /dev/null +++ b/app/views/mailer/document_added.text.erb @@ -0,0 +1,4 @@ +<%= @document.title %> (<%= @document.category.name %>) +<%= @document_url %> + +<%= @document.description %> diff --git a/app/views/mailer/issue_add.html.erb b/app/views/mailer/issue_add.html.erb new file mode 100644 index 00000000..fb4a2dab --- /dev/null +++ b/app/views/mailer/issue_add.html.erb @@ -0,0 +1,3 @@ +<%= l(:text_issue_added, :id => "##{@issue.id}", :author => h(@issue.author)) %> +
    +<%= render :partial => 'issue', :formats => [:html], :locals => { :issue => @issue, :issue_url => @issue_url } %> diff --git a/app/views/mailer/issue_add.text.erb b/app/views/mailer/issue_add.text.erb new file mode 100644 index 00000000..e990ff0d --- /dev/null +++ b/app/views/mailer/issue_add.text.erb @@ -0,0 +1,4 @@ +<%= l(:text_issue_added, :id => "##{@issue.id}", :author => @issue.author) %> + +---------------------------------------- +<%= render :partial => 'issue', :formats => [:text], :locals => { :issue => @issue, :issue_url => @issue_url } %> diff --git a/app/views/mailer/issue_edit.html.erb b/app/views/mailer/issue_edit.html.erb new file mode 100644 index 00000000..720cfea6 --- /dev/null +++ b/app/views/mailer/issue_edit.html.erb @@ -0,0 +1,11 @@ +<%= l(:text_issue_updated, :id => "##{@issue.id}", :author => h(@journal.user)) %> + +
      +<% details_to_strings(@journal.details, false, :only_path => false).each do |string| %> +
    • <%= string %>
    • +<% end %> +
    + +<%= textilizable(@journal, :notes, :only_path => false) %> +
    +<%= render :partial => 'issue', :formats => [:html], :locals => { :issue => @issue, :issue_url => @issue_url } %> diff --git a/app/views/mailer/issue_edit.text.erb b/app/views/mailer/issue_edit.text.erb new file mode 100644 index 00000000..e0f10811 --- /dev/null +++ b/app/views/mailer/issue_edit.text.erb @@ -0,0 +1,12 @@ +<%= l(:text_issue_updated, :id => "##{@issue.id}", :author => @journal.user) %> + +<% details_to_strings(@journal.details, true).each do |string| -%> +<%= string %> +<% end -%> + +<% if @journal.notes? -%> +<%= @journal.notes %> + +<% end -%> +---------------------------------------- +<%= render :partial => 'issue', :formats => [:text], :locals => { :issue => @issue, :issue_url => @issue_url } %> diff --git a/app/views/mailer/lost_password.html.erb b/app/views/mailer/lost_password.html.erb new file mode 100644 index 00000000..d740480a --- /dev/null +++ b/app/views/mailer/lost_password.html.erb @@ -0,0 +1,4 @@ +

    <%= l(:mail_body_lost_password) %>
    +<%= link_to h(@url), @url %>

    + +

    <%= l(:field_login) %>: <%=h @token.user.login %>

    diff --git a/app/views/mailer/lost_password.text.erb b/app/views/mailer/lost_password.text.erb new file mode 100644 index 00000000..f5000ed7 --- /dev/null +++ b/app/views/mailer/lost_password.text.erb @@ -0,0 +1,4 @@ +<%= l(:mail_body_lost_password) %> +<%= @url %> + +<%= l(:field_login) %>: <%= @token.user.login %> diff --git a/app/views/mailer/message_posted.html.erb b/app/views/mailer/message_posted.html.erb new file mode 100644 index 00000000..f43a8cf0 --- /dev/null +++ b/app/views/mailer/message_posted.html.erb @@ -0,0 +1,4 @@ +

    <%=h @message.board.project.name %> - <%=h @message.board.name %>: <%= link_to(h(@message.subject), @message_url) %>

    +<%=h @message.author %> + +<%= textilizable(@message, :content, :only_path => false) %> diff --git a/app/views/mailer/message_posted.text.erb b/app/views/mailer/message_posted.text.erb new file mode 100644 index 00000000..ef6a3b3a --- /dev/null +++ b/app/views/mailer/message_posted.text.erb @@ -0,0 +1,4 @@ +<%= @message_url %> +<%= @message.author %> + +<%= @message.content %> diff --git a/app/views/mailer/news_added.html.erb b/app/views/mailer/news_added.html.erb new file mode 100644 index 00000000..758ebccb --- /dev/null +++ b/app/views/mailer/news_added.html.erb @@ -0,0 +1,4 @@ +

    <%= link_to(h(@news.title), @news_url) %>

    +<%=h @news.author.name %> + +<%= textilizable(@news, :description, :only_path => false) %> diff --git a/app/views/mailer/news_added.text.erb b/app/views/mailer/news_added.text.erb new file mode 100644 index 00000000..c8ae3035 --- /dev/null +++ b/app/views/mailer/news_added.text.erb @@ -0,0 +1,5 @@ +<%= @news.title %> +<%= @news_url %> +<%= @news.author.name %> + +<%= @news.description %> diff --git a/app/views/mailer/news_comment_added.html.erb b/app/views/mailer/news_comment_added.html.erb new file mode 100644 index 00000000..ef2be0f6 --- /dev/null +++ b/app/views/mailer/news_comment_added.html.erb @@ -0,0 +1,5 @@ +

    <%= link_to(h(@news.title), @news_url) %>

    + +

    <%= l(:text_user_wrote, :value => h(@comment.author)) %>

    + +<%= textilizable @comment, :comments, :only_path => false %> diff --git a/app/views/mailer/news_comment_added.text.erb b/app/views/mailer/news_comment_added.text.erb new file mode 100644 index 00000000..aadbc37c --- /dev/null +++ b/app/views/mailer/news_comment_added.text.erb @@ -0,0 +1,6 @@ +<%= @news.title %> +<%= @news_url %> + +<%= l(:text_user_wrote, :value => @comment.author) %> + +<%= @comment.comments %> diff --git a/app/views/mailer/register.html.erb b/app/views/mailer/register.html.erb new file mode 100644 index 00000000..282deca9 --- /dev/null +++ b/app/views/mailer/register.html.erb @@ -0,0 +1,2 @@ +

    <%= l(:mail_body_register) %>
    +<%= link_to h(@url), @url %>

    diff --git a/app/views/mailer/register.text.erb b/app/views/mailer/register.text.erb new file mode 100644 index 00000000..102a15ee --- /dev/null +++ b/app/views/mailer/register.text.erb @@ -0,0 +1,2 @@ +<%= l(:mail_body_register) %> +<%= @url %> diff --git a/app/views/mailer/reminder.html.erb b/app/views/mailer/reminder.html.erb new file mode 100644 index 00000000..f011da3e --- /dev/null +++ b/app/views/mailer/reminder.html.erb @@ -0,0 +1,9 @@ +

    <%= l(:mail_body_reminder, :count => @issues.size, :days => @days) %>

    + +
      +<% @issues.each do |issue| -%> +
    • <%=h issue.project %> - <%=link_to(h("#{issue.tracker} ##{issue.id}"), :controller => 'issues', :action => 'show', :id => issue, :only_path => false)%>: <%=h issue.subject %>
    • +<% end -%> +
    + +

    <%= link_to l(:label_issue_view_all), @issues_url %>

    diff --git a/app/views/mailer/reminder.text.erb b/app/views/mailer/reminder.text.erb new file mode 100644 index 00000000..c9e27dc8 --- /dev/null +++ b/app/views/mailer/reminder.text.erb @@ -0,0 +1,7 @@ +<%= l(:mail_body_reminder, :count => @issues.size, :days => @days) %>: + +<% @issues.each do |issue| -%> +* <%= "#{issue.project} - #{issue.tracker} ##{issue.id}: #{issue.subject}" %> +<% end -%> + +<%= @issues_url %> diff --git a/app/views/mailer/test_email.html.erb b/app/views/mailer/test_email.html.erb new file mode 100644 index 00000000..1e81b3bf --- /dev/null +++ b/app/views/mailer/test_email.html.erb @@ -0,0 +1,2 @@ +

    This is a test email sent by Redmine.
    +Redmine URL: <%= link_to h(@url), @url %>

    diff --git a/app/views/mailer/test_email.text.erb b/app/views/mailer/test_email.text.erb new file mode 100644 index 00000000..790d6ab2 --- /dev/null +++ b/app/views/mailer/test_email.text.erb @@ -0,0 +1,2 @@ +This is a test email sent by Redmine. +Redmine URL: <%= @url %> diff --git a/app/views/mailer/wiki_content_added.html.erb b/app/views/mailer/wiki_content_added.html.erb new file mode 100644 index 00000000..8c83f62c --- /dev/null +++ b/app/views/mailer/wiki_content_added.html.erb @@ -0,0 +1,3 @@ +

    <%= l(:mail_body_wiki_content_added, :id => link_to(h(@wiki_content.page.pretty_title), @wiki_content_url), + :author => h(@wiki_content.author)).html_safe %>
    +<%=h @wiki_content.comments %>

    diff --git a/app/views/mailer/wiki_content_added.text.erb b/app/views/mailer/wiki_content_added.text.erb new file mode 100644 index 00000000..5e8c77fd --- /dev/null +++ b/app/views/mailer/wiki_content_added.text.erb @@ -0,0 +1,5 @@ +<%= l(:mail_body_wiki_content_added, :id => h(@wiki_content.page.pretty_title), + :author => h(@wiki_content.author)) %> +<%= @wiki_content.comments %> + +<%= @wiki_content_url %> diff --git a/app/views/mailer/wiki_content_updated.html.erb b/app/views/mailer/wiki_content_updated.html.erb new file mode 100644 index 00000000..f1f3857b --- /dev/null +++ b/app/views/mailer/wiki_content_updated.html.erb @@ -0,0 +1,6 @@ +

    <%= l(:mail_body_wiki_content_updated, :id => link_to(h(@wiki_content.page.pretty_title), @wiki_content_url), + :author => h(@wiki_content.author)).html_safe %>
    +<%=h @wiki_content.comments %>

    + +

    <%= l(:label_view_diff) %>:
    +<%= link_to h(@wiki_diff_url), @wiki_diff_url %>

    diff --git a/app/views/mailer/wiki_content_updated.text.erb b/app/views/mailer/wiki_content_updated.text.erb new file mode 100644 index 00000000..4b3a9736 --- /dev/null +++ b/app/views/mailer/wiki_content_updated.text.erb @@ -0,0 +1,8 @@ +<%= l(:mail_body_wiki_content_updated, :id => h(@wiki_content.page.pretty_title), + :author => h(@wiki_content.author)) %> +<%= @wiki_content.comments %> + +<%= @wiki_content.page.pretty_title %>: +<%= @wiki_content_url %> +<%= l(:label_view_diff) %>: +<%= @wiki_diff_url %> diff --git a/app/views/members/autocomplete.js.erb b/app/views/members/autocomplete.js.erb new file mode 100644 index 00000000..ba98983d --- /dev/null +++ b/app/views/members/autocomplete.js.erb @@ -0,0 +1 @@ +$('#principals_for_new_member').html('<%= escape_javascript(render_principals_for_new_members(@project)) %>'); diff --git a/app/views/members/create.js.erb b/app/views/members/create.js.erb new file mode 100644 index 00000000..11c468a7 --- /dev/null +++ b/app/views/members/create.js.erb @@ -0,0 +1,11 @@ +$('#tab-content-members').html('<%= escape_javascript(render :partial => 'projects/settings/members') %>'); +hideOnLoad(); + +<% if @members.present? && @members.all? {|m| m.valid? } %> + <% @members.each do |member| %> + $("#member-<%= member.id %>").effect("highlight"); + <% end %> +<% else %> + <% errors = @members.collect {|m| m.errors.full_messages}.flatten.uniq.join(', ') %> + alert('<%= raw(escape_javascript(l(:notice_failed_to_save_members, :errors => errors))) %>'); +<% end %> diff --git a/app/views/members/destroy.js.erb b/app/views/members/destroy.js.erb new file mode 100644 index 00000000..17beff44 --- /dev/null +++ b/app/views/members/destroy.js.erb @@ -0,0 +1,2 @@ +$('#tab-content-members').html('<%= escape_javascript(render :partial => 'projects/settings/members') %>'); +hideOnLoad(); diff --git a/app/views/members/index.api.rsb b/app/views/members/index.api.rsb new file mode 100644 index 00000000..dd591ea7 --- /dev/null +++ b/app/views/members/index.api.rsb @@ -0,0 +1,18 @@ +api.array :memberships, api_meta(:total_count => @member_count, :offset => @offset, :limit => @limit) do + @members.each do |membership| + api.membership do + api.id membership.id + api.project :id => membership.project.id, :name => membership.project.name + api.__send__ membership.principal.class.name.underscore, :id => membership.principal.id, :name => membership.principal.name + api.array :roles do + membership.member_roles.each do |member_role| + if member_role.role + attrs = {:id => member_role.role.id, :name => member_role.role.name} + attrs.merge!(:inherited => true) if member_role.inherited_from.present? + api.role attrs + end + end + end + end + end +end diff --git a/app/views/members/show.api.rsb b/app/views/members/show.api.rsb new file mode 100644 index 00000000..55def9ea --- /dev/null +++ b/app/views/members/show.api.rsb @@ -0,0 +1,14 @@ +api.membership do + api.id @member.id + api.project :id => @member.project.id, :name => @member.project.name + api.__send__ @member.principal.class.name.underscore, :id => @member.principal.id, :name => @member.principal.name + api.array :roles do + @member.member_roles.each do |member_role| + if member_role.role + attrs = {:id => member_role.role.id, :name => member_role.role.name} + attrs.merge!(:inherited => true) if member_role.inherited_from.present? + api.role attrs + end + end + end +end diff --git a/app/views/members/update.js.erb b/app/views/members/update.js.erb new file mode 100644 index 00000000..245828aa --- /dev/null +++ b/app/views/members/update.js.erb @@ -0,0 +1,3 @@ +$('#tab-content-members').html('<%= escape_javascript(render :partial => 'projects/settings/members') %>'); +hideOnLoad(); +$("#member-<%= @member.id %>").effect("highlight"); diff --git a/app/views/messages/_form.html.erb b/app/views/messages/_form.html.erb new file mode 100644 index 00000000..d9f48af5 --- /dev/null +++ b/app/views/messages/_form.html.erb @@ -0,0 +1,32 @@ +<%= error_messages_for 'message' %> +<% replying ||= false %> + +
    + +


    +<%= f.text_field :subject, :size => 120, :id => "message_subject" %> + +<% unless replying %> + <% if @message.safe_attribute? 'sticky' %> + <%= f.check_box :sticky %> <%= label_tag 'message_sticky', l(:label_board_sticky) %> + <% end %> + <% if @message.safe_attribute? 'locked' %> + <%= f.check_box :locked %> <%= label_tag 'message_locked', l(:label_board_locked) %> + <% end %> +<% end %> +

    + +<% if !replying && !@message.new_record? && @message.safe_attribute?('board_id') %> +


    + <%= f.select :board_id, boards_options_for_select(@message.project.boards) %>

    +<% end %> + +

    +<%= label_tag "message_content", l(:description_message_content), :class => "hidden-for-sighted" %> +<%= f.text_area :content, :cols => 80, :rows => 15, :class => 'wiki-edit', :id => 'message_content' %>

    +<%= wikitoolbar_for 'message_content' %> + + +

    <%= l(:label_attachment_plural) %>
    +<%= render :partial => 'attachments/form', :locals => {:container => @message} %>

    +
    diff --git a/app/views/messages/edit.html.erb b/app/views/messages/edit.html.erb new file mode 100644 index 00000000..b7f59129 --- /dev/null +++ b/app/views/messages/edit.html.erb @@ -0,0 +1,17 @@ +<%= board_breadcrumb(@message) %> + +

    <%= avatar(@topic.author, :size => "24") %><%=h @topic.subject %>

    + +<%= form_for @message, { + :as => :message, + :url => {:action => 'edit'}, + :html => {:multipart => true, + :id => 'message-form', + :method => :post} + } do |f| %> + <%= render :partial => 'form', + :locals => {:f => f, :replying => !@message.parent.nil?} %> + <%= submit_tag l(:button_save) %> + <%= preview_link({:controller => 'messages', :action => 'preview', :board_id => @board, :id => @message}, 'message-form') %> +<% end %> +
    diff --git a/app/views/messages/new.html.erb b/app/views/messages/new.html.erb new file mode 100644 index 00000000..f2137b98 --- /dev/null +++ b/app/views/messages/new.html.erb @@ -0,0 +1,9 @@ +

    <%= link_to h(@board.name), :controller => 'boards', :action => 'show', :project_id => @project, :id => @board %> » <%= l(:label_message_new) %>

    + +<%= form_for @message, :url => {:action => 'new'}, :html => {:multipart => true, :id => 'message-form'} do |f| %> + <%= render :partial => 'form', :locals => {:f => f} %> + <%= submit_tag l(:button_create) %> + <%= preview_link({:controller => 'messages', :action => 'preview', :board_id => @board}, 'message-form') %> +<% end %> + +
    diff --git a/app/views/messages/quote.js.erb b/app/views/messages/quote.js.erb new file mode 100644 index 00000000..fe4bed91 --- /dev/null +++ b/app/views/messages/quote.js.erb @@ -0,0 +1,4 @@ +$('#message_subject').val("<%= raw escape_javascript(@subject) %>"); +$('#message_content').val("<%= raw escape_javascript(@content) %>"); +showAndScrollTo("reply", "message_content"); +$('#message_content').scrollTop = $('#message_content').scrollHeight - $('#message_content').clientHeight; diff --git a/app/views/messages/show.html.erb b/app/views/messages/show.html.erb new file mode 100644 index 00000000..25ee3be0 --- /dev/null +++ b/app/views/messages/show.html.erb @@ -0,0 +1,86 @@ +<%= board_breadcrumb(@message) %> + +
    + <%= watcher_link(@topic, User.current) %> + <%= link_to( + l(:button_quote), + {:action => 'quote', :id => @topic}, + :remote => true, + :method => 'get', + :class => 'icon icon-comment', + :remote => true) if !@topic.locked? && authorize_for('messages', 'reply') %> + <%= link_to( + l(:button_edit), + {:action => 'edit', :id => @topic}, + :class => 'icon icon-edit' + ) if @message.editable_by?(User.current) %> + <%= link_to( + l(:button_delete), + {:action => 'destroy', :id => @topic}, + :method => :post, + :data => {:confirm => l(:text_are_you_sure)}, + :class => 'icon icon-del' + ) if @message.destroyable_by?(User.current) %> +
    + +

    <%= avatar(@topic.author, :size => "24") %><%=h @topic.subject %>

    + +
    +

    <%= authoring @topic.created_on, @topic.author %>

    +
    +<%= textilizable(@topic, :content) %> +
    +<%= link_to_attachments @topic, :author => false %> +
    +
    + +<% unless @replies.empty? %> +

    <%= l(:label_reply_plural) %> (<%= @reply_count %>)

    +<% @replies.each do |message| %> +
    "> +
    + <%= link_to( + image_tag('comment.png'), + {:action => 'quote', :id => message}, + :remote => true, + :method => 'get', + :title => l(:button_quote)) if !@topic.locked? && authorize_for('messages', 'reply') %> + <%= link_to( + image_tag('edit.png'), + {:action => 'edit', :id => message}, + :title => l(:button_edit) + ) if message.editable_by?(User.current) %> + <%= link_to( + image_tag('delete.png'), + {:action => 'destroy', :id => message}, + :method => :post, + :data => {:confirm => l(:text_are_you_sure)}, + :title => l(:button_delete) + ) if message.destroyable_by?(User.current) %> +
    +

    + <%= avatar(message.author, :size => "24") %> + <%= link_to h(message.subject), { :controller => 'messages', :action => 'show', :board_id => @board, :id => @topic, :r => message, :anchor => "message-#{message.id}" } %> + - + <%= authoring message.created_on, message.author %> +

    +
    <%= textilizable message, :content, :attachments => message.attachments %>
    + <%= link_to_attachments message, :author => false %> +
    +<% end %> +

    <%= pagination_links_full @reply_pages, @reply_count, :per_page_links => false %>

    +<% end %> + +<% if !@topic.locked? && authorize_for('messages', 'reply') %> +

    <%= toggle_link l(:button_reply), "reply", :focus => 'message_content' %>

    + +<% end %> + +<% html_title @topic.subject %> diff --git a/app/views/my/_block.html.erb b/app/views/my/_block.html.erb new file mode 100644 index 00000000..813eb2b8 --- /dev/null +++ b/app/views/my/_block.html.erb @@ -0,0 +1,10 @@ +
    + +
    + <%= link_to "", {:action => "remove_block", :block => block_name}, :method => 'post', :class => "close-icon" %> +
    + +
    + <%= render :partial => "my/blocks/#{block_name}", :locals => { :user => user } %> +
    +
    diff --git a/app/views/my/_sidebar.html.erb b/app/views/my/_sidebar.html.erb new file mode 100644 index 00000000..4c9270fc --- /dev/null +++ b/app/views/my/_sidebar.html.erb @@ -0,0 +1,36 @@ +

    <%=l(:label_my_account)%>

    + +

    <%=l(:field_login)%>: <%= link_to_user(@user, :format => :username) %>
    +<%=l(:field_created_on)%>: <%= format_time(@user.created_on) %>

    + +<% if @user.own_account_deletable? %> +

    <%= link_to(l(:button_delete_my_account), {:action => 'destroy'}, :class => 'icon icon-del') %>

    +<% end %> + +

    <%= l(:label_feeds_access_key) %>

    + +

    +<% if @user.rss_token %> +<%= l(:label_feeds_access_key_created_on, distance_of_time_in_words(Time.now, @user.rss_token.created_on)) %> +<% else %> +<%= l(:label_missing_feeds_access_key) %> +<% end %> +(<%= link_to l(:button_reset), {:action => 'reset_rss_key'}, :method => :post %>) +

    + +<% if Setting.rest_api_enabled? %> +

    <%= l(:label_api_access_key) %>

    +
    + <%= link_to_function(l(:button_show), "$('#api-access-key').toggle();")%> +
    <%= h(@user.api_key) %>
    +
    +<%= javascript_tag("$('#api-access-key').hide();") %> +

    +<% if @user.api_token %> +<%= l(:label_api_access_key_created_on, distance_of_time_in_words(Time.now, @user.api_token.created_on)) %> +<% else %> +<%= l(:label_missing_api_access_key) %> +<% end %> +(<%= link_to l(:button_reset), {:action => 'reset_api_key'}, :method => :post %>) +

    +<% end %> diff --git a/app/views/my/account.html.erb b/app/views/my/account.html.erb new file mode 100644 index 00000000..63ae8dc9 --- /dev/null +++ b/app/views/my/account.html.erb @@ -0,0 +1,75 @@ +
    + <%= link_to(l(:button_change_password), {:action => 'password'}, :class => 'icon icon-passwd') if @user.change_password_allowed? %> + <%= call_hook(:view_my_account_contextual, :user => @user)%> +
    + +

    <%= l(:label_my_account)%>

    + + +<%= labelled_form_for :user, @user, +:url => { :action => "account" }, +:html => { :id => 'my_account_form', +:method => :post } do |f| %> + +
    + + + <%= submit_tag l(:button_save) %> +
    +<% end %> +<%= error_messages_for 'user' %> +<% html_title(l(:label_my_account)) -%> diff --git a/app/views/my/blocks/_calendar.html.erb b/app/views/my/blocks/_calendar.html.erb new file mode 100644 index 00000000..41ca18a1 --- /dev/null +++ b/app/views/my/blocks/_calendar.html.erb @@ -0,0 +1,6 @@ +

    <%= l(:label_calendar) %>

    + +<% calendar = Redmine::Helpers::Calendar.new(Date.today, current_language, :week) + calendar.events = calendar_items(calendar.startdt, calendar.enddt) %> + +<%= render :partial => 'common/calendar', :locals => {:calendar => calendar } %> diff --git a/app/views/my/blocks/_documents.html.erb b/app/views/my/blocks/_documents.html.erb new file mode 100644 index 00000000..a55094cf --- /dev/null +++ b/app/views/my/blocks/_documents.html.erb @@ -0,0 +1,3 @@ +

    <%=l(:label_document_plural)%>

    + +<%= render :partial => 'documents/document', :collection => documents_items %> diff --git a/app/views/my/blocks/_issuesassignedtome.html.erb b/app/views/my/blocks/_issuesassignedtome.html.erb new file mode 100644 index 00000000..02d8c9aa --- /dev/null +++ b/app/views/my/blocks/_issuesassignedtome.html.erb @@ -0,0 +1,18 @@ +

    <%=l(:label_assigned_to_me_issues)%> (<%= Issue.visible.open.count(:conditions => {:assigned_to_id => ([User.current.id] + User.current.group_ids)})%>)

    + +<% assigned_issues = issuesassignedtome_items %> +<%= render :partial => 'issues/list_simple', :locals => { :issues => assigned_issues } %> +<% if assigned_issues.length > 0 %> +

    <%= link_to l(:label_issue_view_all), :controller => 'issues', + :action => 'index', + :set_filter => 1, + :assigned_to_id => 'me', + :sort => 'priority:desc,updated_on:desc' %>

    +<% end %> + +<% content_for :header_tags do %> +<%= auto_discovery_link_tag(:atom, + {:controller => 'issues', :action => 'index', :set_filter => 1, + :assigned_to_id => 'me', :format => 'atom', :key => User.current.rss_key}, + {:title => l(:label_assigned_to_me_issues)}) %> +<% end %> diff --git a/app/views/my/blocks/_issuesreportedbyme.html.erb b/app/views/my/blocks/_issuesreportedbyme.html.erb new file mode 100644 index 00000000..06bbda7f --- /dev/null +++ b/app/views/my/blocks/_issuesreportedbyme.html.erb @@ -0,0 +1,19 @@ +

    <%=l(:label_reported_issues)%> (<%= Issue.visible.count(:conditions => { :author_id => User.current.id }) %>)

    + +<% reported_issues = issuesreportedbyme_items %> +<%= render :partial => 'issues/list_simple', :locals => { :issues => reported_issues } %> +<% if reported_issues.length > 0 %> +

    <%= link_to l(:label_issue_view_all), :controller => 'issues', + :action => 'index', + :set_filter => 1, + :status_id => '*', + :author_id => 'me', + :sort => 'updated_on:desc' %>

    +<% end %> + +<% content_for :header_tags do %> +<%= auto_discovery_link_tag(:atom, + {:controller => 'issues', :action => 'index', :set_filter => 1, + :author_id => 'me', :format => 'atom', :key => User.current.rss_key}, + {:title => l(:label_reported_issues)}) %> +<% end %> diff --git a/app/views/my/blocks/_issueswatched.html.erb b/app/views/my/blocks/_issueswatched.html.erb new file mode 100644 index 00000000..510920a0 --- /dev/null +++ b/app/views/my/blocks/_issueswatched.html.erb @@ -0,0 +1,11 @@ +

    <%=l(:label_watched_issues)%> (<%= Issue.visible.watched_by(user.id).count %>)

    +<% watched_issues = issueswatched_items %> + +<%= render :partial => 'issues/list_simple', :locals => { :issues => watched_issues } %> +<% if watched_issues.length > 0 %> +

    <%= link_to l(:label_issue_view_all), :controller => 'issues', + :action => 'index', + :set_filter => 1, + :watcher_id => 'me', + :sort => 'updated_on:desc' %>

    +<% end %> diff --git a/app/views/my/blocks/_news.html.erb b/app/views/my/blocks/_news.html.erb new file mode 100644 index 00000000..c478e419 --- /dev/null +++ b/app/views/my/blocks/_news.html.erb @@ -0,0 +1,3 @@ +

    <%=l(:label_news_latest)%>

    + +<%= render :partial => 'news/news', :collection => news_items %> diff --git a/app/views/my/blocks/_timelog.html.erb b/app/views/my/blocks/_timelog.html.erb new file mode 100644 index 00000000..be8e05e3 --- /dev/null +++ b/app/views/my/blocks/_timelog.html.erb @@ -0,0 +1,49 @@ +

    <%=l(:label_spent_time)%> (<%= l(:label_last_n_days, 7) %>)

    +<% +entries = timelog_items +entries_by_day = entries.group_by(&:spent_on) +%> + +
    +

    <%= l(:label_total_time) %>: <%= html_hours("%.2f" % entries.sum(&:hours).to_f) %>

    +
    + +<% if entries.any? %> + + + + + + + + + +<% entries_by_day.keys.sort.reverse.each do |day| %> + + + + + + + <% entries_by_day[day].each do |entry| -%> + + + + + + + + <% end -%> +<% end -%> + +
    <%= l(:label_activity) %><%= l(:label_project) %><%= l(:field_comments) %><%= l(:field_hours) %>
    <%= day == Date.today ? l(:label_today).titleize : format_date(day) %><%= html_hours("%.2f" % entries_by_day[day].sum(&:hours).to_f) %>
    <%=h entry.activity %><%=h entry.project %> <%= h(' - ') + link_to_issue(entry.issue, :truncate => 50) if entry.issue %><%=h entry.comments %><%= html_hours("%.2f" % entry.hours) %> + <% if entry.editable_by?(@user) -%> + <%= link_to image_tag('edit.png'), {:controller => 'timelog', :action => 'edit', :id => entry}, + :title => l(:button_edit) %> + <%= link_to image_tag('delete.png'), {:controller => 'timelog', :action => 'destroy', :id => entry}, + :data => {:confirm => l(:text_are_you_sure)}, + :method => :delete, + :title => l(:button_delete) %> + <% end -%> +
    +<% end %> diff --git a/app/views/my/destroy.html.erb b/app/views/my/destroy.html.erb new file mode 100644 index 00000000..96e21cf2 --- /dev/null +++ b/app/views/my/destroy.html.erb @@ -0,0 +1,11 @@ +

    <%=l(:label_confirmation)%>

    +
    +

    <%= simple_format l(:text_account_destroy_confirmation)%>

    +

    + <%= form_tag({}) do %> + + <%= submit_tag l(:button_delete_my_account) %> | + <%= link_to l(:button_cancel), :action => 'account' %> + <% end %> +

    +
    diff --git a/app/views/my/page.html.erb b/app/views/my/page.html.erb new file mode 100644 index 00000000..dd66f84a --- /dev/null +++ b/app/views/my/page.html.erb @@ -0,0 +1,36 @@ +
    + <%= link_to l(:label_personalize_page), :action => 'page_layout' %> +
    + +

    <%=l(:label_my_page)%>

    + +
    + <% @blocks['top'].each do |b| + next unless MyController::BLOCKS.keys.include? b %> +
    + <%= render :partial => "my/blocks/#{b}", :locals => { :user => @user } %> +
    + <% end if @blocks['top'] %> +
    + +
    + <% @blocks['left'].each do |b| + next unless MyController::BLOCKS.keys.include? b %> +
    + <%= render :partial => "my/blocks/#{b}", :locals => { :user => @user } %> +
    + <% end if @blocks['left'] %> +
    + +
    + <% @blocks['right'].each do |b| + next unless MyController::BLOCKS.keys.include? b %> +
    + <%= render :partial => "my/blocks/#{b}", :locals => { :user => @user } %> +
    + <% end if @blocks['right'] %> +
    + +<%= context_menu issues_context_menu_path %> + +<% html_title(l(:label_my_page)) -%> diff --git a/app/views/my/page_layout.html.erb b/app/views/my/page_layout.html.erb new file mode 100644 index 00000000..a1cdb2d1 --- /dev/null +++ b/app/views/my/page_layout.html.erb @@ -0,0 +1,41 @@ +
    +<% if @block_options.present? %> + <%= form_tag({:action => "add_block"}, :id => "block-form") do %> + <%= label_tag('block-select', l(:label_my_page_block)) %>: + <%= select_tag 'block', + content_tag('option') + options_for_select(@block_options), + :id => "block-select" %> + <%= link_to l(:button_add), '#', :onclick => '$("#block-form").submit()', :class => 'icon icon-add' %> + <% end %> +<% end %> +<%= link_to l(:button_back), {:action => 'page'}, :class => 'icon icon-cancel' %> +
    + +

    <%=l(:label_my_page)%>

    + +
    + <% @blocks['top'].each do |b| + next unless MyController::BLOCKS.keys.include? b %> + <%= render :partial => 'block', :locals => {:user => @user, :block_name => b} %> + <% end if @blocks['top'] %> +
    + +
    + <% @blocks['left'].each do |b| + next unless MyController::BLOCKS.keys.include? b %> + <%= render :partial => 'block', :locals => {:user => @user, :block_name => b} %> + <% end if @blocks['left'] %> +
    + +
    + <% @blocks['right'].each do |b| + next unless MyController::BLOCKS.keys.include? b %> + <%= render :partial => 'block', :locals => {:user => @user, :block_name => b} %> + <% end if @blocks['right'] %> +
    + +<%= javascript_tag "initMyPageSortable('top', '#{ escape_javascript url_for(:action => "order_blocks", :group => "top") }');" %> +<%= javascript_tag "initMyPageSortable('left', '#{ escape_javascript url_for(:action => "order_blocks", :group => "left") }');" %> +<%= javascript_tag "initMyPageSortable('right', '#{ escape_javascript url_for(:action => "order_blocks", :group => "right") }');" %> + +<% html_title(l(:label_my_page)) -%> diff --git a/app/views/my/password.html.erb b/app/views/my/password.html.erb new file mode 100644 index 00000000..5e2b1989 --- /dev/null +++ b/app/views/my/password.html.erb @@ -0,0 +1,23 @@ +

    <%=l(:button_change_password)%>

    + +<%= error_messages_for 'user' %> + +<%= form_tag({}, :class => "tabular") do %> +
    +

    +<%= password_field_tag 'password', nil, :size => 25 %>

    + +

    +<%= password_field_tag 'new_password', nil, :size => 25 %> +<%= l(:text_caracters_minimum, :count => Setting.password_min_length) %>

    + +

    +<%= password_field_tag 'new_password_confirmation', nil, :size => 25 %>

    +<%= submit_tag l(:button_apply) %> +
    + +<% end %> + +<% content_for :sidebar do %> +<%= render :partial => 'sidebar' %> +<% end %> diff --git a/app/views/news/_form.html.erb b/app/views/news/_form.html.erb new file mode 100644 index 00000000..3f48d21d --- /dev/null +++ b/app/views/news/_form.html.erb @@ -0,0 +1,10 @@ +<%= error_messages_for @news %> + +
    +

    <%= f.text_field :title, :required => true, :size => 60 %>

    +

    <%= f.text_area :summary, :cols => 60, :rows => 2 %>

    +

    <%= f.text_area :description, :required => true, :cols => 60, :rows => 15, :class => 'wiki-edit' %>

    +

    <%= render :partial => 'attachments/form', :locals => {:container => @news} %>

    +
    + +<%= wikitoolbar_for 'news_description' %> diff --git a/app/views/news/_news.html.erb b/app/views/news/_news.html.erb new file mode 100644 index 00000000..001ad817 --- /dev/null +++ b/app/views/news/_news.html.erb @@ -0,0 +1,27 @@ + + + + + + + + + + +
    + + + + + + + + + + +
    <%=link_to news.author,news_path(news)%> 分享了 <%= link_to h(news.title), news_path(news) %>

    <%=h news.description%>

    <%= news.created_on %><%= link_to"查看其他评论",news_path(news)%><%= "(#{l(:label_x_comments, :count => news.comments_count)})" if news.comments_count > 0 %>
    diff --git a/app/views/news/edit.html.erb b/app/views/news/edit.html.erb new file mode 100644 index 00000000..e5e5221b --- /dev/null +++ b/app/views/news/edit.html.erb @@ -0,0 +1,12 @@ +

    <%=l(:label_news)%>

    + +<%= labelled_form_for @news, :html => { :id => 'news-form', :multipart => true, :method => :put } do |f| %> +<%= render :partial => 'form', :locals => { :f => f } %> +<%= submit_tag l(:button_save) %> +<%= preview_link preview_news_path(:project_id => @project, :id => @news), 'news-form' %> +<% end %> +
    + +<% content_for :header_tags do %> + <%= stylesheet_link_tag 'scm' %> +<% end %> diff --git a/app/views/news/index.api.rsb b/app/views/news/index.api.rsb new file mode 100644 index 00000000..5786cee3 --- /dev/null +++ b/app/views/news/index.api.rsb @@ -0,0 +1,14 @@ +api.array :news, api_meta(:total_count => @news_count, :offset => @offset, :limit => @limit) do + @newss.each do |news| + api.news do + api.id news.id + api.project(:id => news.project_id, :name => news.project.name) unless news.project.nil? + api.author(:id => news.author_id, :name => news.author.name) unless news.author.nil? + + api.title news.title + api.summary news.summary + api.description news.description + api.created_on news.created_on + end + end +end diff --git a/app/views/news/index.html.erb b/app/views/news/index.html.erb new file mode 100644 index 00000000..8381fb99 --- /dev/null +++ b/app/views/news/index.html.erb @@ -0,0 +1,78 @@ +
    +<%= link_to(l(:label_news_new), + new_project_news_path(@project), + :class => 'icon icon-add', + :onclick => 'showAndScrollTo("add-news", "news_title"); return false;') if @project && User.current.allowed_to?(:manage_news, @project) %> +
    + + + + + + +
    + + +<% if @newss.empty? %> +

    <%= l(:label_no_data) %>

    +<% else %> +<% @newss.each do |news| %> + + + + + +
    <%= link_to image_tag(url_to_avatar(@user), :class => 'avatar2'), :class => "avatar" %> + + + + + + + + + + +
    <%=link_to news.author%> 分享了 <%= link_to h(news.title), news_path(news) %>

    <%= textilizable(news, :description) %>

    <%= news.created_on %><%= link_to"查看其他评论",news_path(news)%><%= "(#{l(:label_x_comments, :count => news.comments_count)})" if news.comments_count > 0 %>
    +<% end %> +<% end %>
    + + + +
    +

    <%= pagination_links_full @news_pages %>

    + +<% other_formats_links do |f| %> + <%= f.link_to 'Atom', :url => {:project_id => @project, :key => User.current.rss_key} %> +<% end %> + +<% content_for :header_tags do %> + <%= auto_discovery_link_tag(:atom, params.merge({:format => 'atom', :page => nil, :key => User.current.rss_key})) %> + <%= stylesheet_link_tag 'scm' %> +<% end %> + +<% html_title(l(:label_news_plural)) -%>
    diff --git a/app/views/news/new.html.erb b/app/views/news/new.html.erb new file mode 100644 index 00000000..05a0afa6 --- /dev/null +++ b/app/views/news/new.html.erb @@ -0,0 +1,9 @@ +

    <%=l(:label_news_new)%>

    + +<%= labelled_form_for @news, :url => project_news_index_path(@project), + :html => { :id => 'news-form', :multipart => true } do |f| %> + <%= render :partial => 'news/form', :locals => { :f => f } %> + <%= submit_tag l(:button_create) %> + <%= preview_link preview_news_path(:project_id => @project), 'news-form' %> +<% end %> +
    diff --git a/app/views/news/show.html.erb b/app/views/news/show.html.erb new file mode 100644 index 00000000..a73447a8 --- /dev/null +++ b/app/views/news/show.html.erb @@ -0,0 +1,78 @@ +
    +<%= watcher_link(@news, User.current) %> +<%= link_to(l(:button_edit), + edit_news_path(@news), + :class => 'icon icon-edit', + :accesskey => accesskey(:edit), + :onclick => '$("#edit-news").show(); return false;') if User.current.allowed_to?(:manage_news, @project) %> +<%= delete_link news_path(@news) if User.current.allowed_to?(:manage_news, @project) %> +
    + +

    <%= link_to image_tag(url_to_avatar(@user), :class => 'avatar2'), :class => "avatar" %><%=h @news.title %>

    + +<% if authorize_for('news', 'edit') %> + +<% end %> + + + + + + + + +
    <%= link_to image_tag(url_to_avatar(@user), :class => 'avatar2'), :class => "avatar" %> + + + + + + + + + + +
    <%=link_to @news.author%> 分享了

    <% unless @news.summary.blank? %><%=h @news.summary %>
    <% end %>

    <%= textilizable(@news, :description) %>

    <%= @news.created_on %>dd
    + + + + + +
    +

    <%= l(:label_comment_plural) %>

    +<% @comments.each do |comment| %> + <% next if comment.new_record? %> +
    + <%= link_to_if_authorized image_tag('delete.png'), {:controller => 'comments', :action => 'destroy', :id => @news, :comment_id => comment}, + :data => {:confirm => l(:text_are_you_sure)}, :method => :delete, :title => l(:button_delete) %> +
    +

    <%= avatar(comment.author, :size => "24") %><%= authoring comment.created_on, comment.author %>

    + <%= textilizable(comment.comments) %> +<% end if @comments.any? %> +
    + +<% if @news.commentable? %> +

    <%= toggle_link l(:label_comment_add), "add_comment_form", :focus => "comment_comments" %>

    +<%= form_tag({:controller => 'comments', :action => 'create', :id => @news}, :id => "add_comment_form", :style => "display:none;") do %> +
    + <%= text_area 'comment', 'comments', :cols => 80, :rows => 15, :class => 'wiki-edit' %> + <%= wikitoolbar_for 'comment_comments' %> +
    +

    <%= submit_tag l(:button_add) %>

    +<% end %> +<% end %> + +<% html_title @news.title -%> + +<% content_for :header_tags do %> + <%= stylesheet_link_tag 'scm' %> +<% end %> diff --git a/app/views/newsold/_form.html.erb b/app/views/newsold/_form.html.erb new file mode 100644 index 00000000..3f48d21d --- /dev/null +++ b/app/views/newsold/_form.html.erb @@ -0,0 +1,10 @@ +<%= error_messages_for @news %> + +
    +

    <%= f.text_field :title, :required => true, :size => 60 %>

    +

    <%= f.text_area :summary, :cols => 60, :rows => 2 %>

    +

    <%= f.text_area :description, :required => true, :cols => 60, :rows => 15, :class => 'wiki-edit' %>

    +

    <%= render :partial => 'attachments/form', :locals => {:container => @news} %>

    +
    + +<%= wikitoolbar_for 'news_description' %> diff --git a/app/views/newsold/_news.html.erb b/app/views/newsold/_news.html.erb new file mode 100644 index 00000000..ddbaecab --- /dev/null +++ b/app/views/newsold/_news.html.erb @@ -0,0 +1,6 @@ +

    <%= link_to_project(news.project) + ': ' unless @project %> +<%= link_to h(news.title), news_path(news) %> +<%= "(#{l(:label_x_comments, :count => news.comments_count)})" if news.comments_count > 0 %> +
    +<% unless news.summary.blank? %><%=h news.summary %>
    <% end %> +<%= authoring news.created_on, news.author %>

    diff --git a/app/views/newsold/edit.html.erb b/app/views/newsold/edit.html.erb new file mode 100644 index 00000000..4e4cf2e2 --- /dev/null +++ b/app/views/newsold/edit.html.erb @@ -0,0 +1,12 @@ +

    <%=l(:label_news)%>

    + +<%= labelled_form_for @news, :html => { :id => 'news-form', :multipart => true, :method => :put } do |f| %> +<%= render :partial => 'form', :locals => { :f => f } %> +<%= submit_tag l(:button_save) %> +<%= preview_link preview_news_path(:project_id => @project, :id => @news), 'news-form' %> +<% end %> +
    + +<% content_for :header_tags do %> + <%= stylesheet_link_tag 'scm' %> +<% end %> diff --git a/app/views/newsold/index.api.rsb b/app/views/newsold/index.api.rsb new file mode 100644 index 00000000..5786cee3 --- /dev/null +++ b/app/views/newsold/index.api.rsb @@ -0,0 +1,14 @@ +api.array :news, api_meta(:total_count => @news_count, :offset => @offset, :limit => @limit) do + @newss.each do |news| + api.news do + api.id news.id + api.project(:id => news.project_id, :name => news.project.name) unless news.project.nil? + api.author(:id => news.author_id, :name => news.author.name) unless news.author.nil? + + api.title news.title + api.summary news.summary + api.description news.description + api.created_on news.created_on + end + end +end diff --git a/app/views/newsold/index.html.erb b/app/views/newsold/index.html.erb new file mode 100644 index 00000000..38eecd26 --- /dev/null +++ b/app/views/newsold/index.html.erb @@ -0,0 +1,46 @@ +
    +<%= link_to(l(:label_news_new), + new_project_news_path(@project), + :class => 'icon icon-add', + :onclick => 'showAndScrollTo("add-news", "news_title"); return false;') if @project && User.current.allowed_to?(:manage_news, @project) %> +
    + + + +

    <%=l(:label_news_plural)%>

    + +<% if @newss.empty? %> +

    <%= l(:label_no_data) %>

    +<% else %> +<% @newss.each do |news| %> +

    <%= avatar(news.author, :size => "24") %><%= link_to_project(news.project) + ': ' unless news.project == @project %> + <%= link_to h(news.title), news_path(news) %> + <%= "(#{l(:label_x_comments, :count => news.comments_count)})" if news.comments_count > 0 %>

    +

    <%= authoring news.created_on, news.author %>

    +
    + <%= textilizable(news, :description) %> +
    +<% end %> +<% end %> +

    <%= pagination_links_full @news_pages %>

    + +<% other_formats_links do |f| %> + <%= f.link_to 'Atom', :url => {:project_id => @project, :key => User.current.rss_key} %> +<% end %> + +<% content_for :header_tags do %> + <%= auto_discovery_link_tag(:atom, params.merge({:format => 'atom', :page => nil, :key => User.current.rss_key})) %> + <%= stylesheet_link_tag 'scm' %> +<% end %> + +<% html_title(l(:label_news_plural)) -%> diff --git a/app/views/newsold/new.html.erb b/app/views/newsold/new.html.erb new file mode 100644 index 00000000..f96dd5c5 --- /dev/null +++ b/app/views/newsold/new.html.erb @@ -0,0 +1,9 @@ +

    <%=l(:label_news_new)%>

    + +<%= labelled_form_for @news, :url => project_news_index_path(@project), + :html => { :id => 'news-form', :multipart => true } do |f| %> + <%= render :partial => 'news/form', :locals => { :f => f } %> + <%= submit_tag l(:button_create) %> + <%= preview_link preview_news_path(:project_id => @project), 'news-form' %> +<% end %> +
    diff --git a/app/views/newsold/show.html.erb b/app/views/newsold/show.html.erb new file mode 100644 index 00000000..d359e90b --- /dev/null +++ b/app/views/newsold/show.html.erb @@ -0,0 +1,62 @@ +
    +<%= watcher_link(@news, User.current) %> +<%= link_to(l(:button_edit), + edit_news_path(@news), + :class => 'icon icon-edit', + :accesskey => accesskey(:edit), + :onclick => '$("#edit-news").show(); return false;') if User.current.allowed_to?(:manage_news, @project) %> +<%= delete_link news_path(@news) if User.current.allowed_to?(:manage_news, @project) %> +
    + +

    <%= avatar(@news.author, :size => "24") %><%=h @news.title %>

    + +<% if authorize_for('news', 'edit') %> + +<% end %> + +

    <% unless @news.summary.blank? %><%=h @news.summary %>
    <% end %> +<%= authoring @news.created_on, @news.author %>

    +
    +<%= textilizable(@news, :description) %> +
    +<%= link_to_attachments @news %> +
    + +
    +

    <%= l(:label_comment_plural) %>

    +<% @comments.each do |comment| %> + <% next if comment.new_record? %> +
    + <%= link_to_if_authorized image_tag('delete.png'), {:controller => 'comments', :action => 'destroy', :id => @news, :comment_id => comment}, + :data => {:confirm => l(:text_are_you_sure)}, :method => :delete, :title => l(:button_delete) %> +
    +

    <%= avatar(comment.author, :size => "24") %><%= authoring comment.created_on, comment.author %>

    + <%= textilizable(comment.comments) %> +<% end if @comments.any? %> +
    + +<% if @news.commentable? %> +

    <%= toggle_link l(:label_comment_add), "add_comment_form", :focus => "comment_comments" %>

    +<%= form_tag({:controller => 'comments', :action => 'create', :id => @news}, :id => "add_comment_form", :style => "display:none;") do %> +
    + <%= text_area 'comment', 'comments', :cols => 80, :rows => 15, :class => 'wiki-edit' %> + <%= wikitoolbar_for 'comment_comments' %> +
    +

    <%= submit_tag l(:button_add) %>

    +<% end %> +<% end %> + +<% html_title @news.title -%> + +<% content_for :header_tags do %> + <%= stylesheet_link_tag 'scm' %> +<% end %> diff --git a/app/views/previews/issue.html.erb b/app/views/previews/issue.html.erb new file mode 100644 index 00000000..a88bec6f --- /dev/null +++ b/app/views/previews/issue.html.erb @@ -0,0 +1,11 @@ +<% if @notes %> +
    <%= l(:field_notes) %> + <%= textilizable @notes, :attachments => @attachments, :object => @issue %> +
    +<% end %> + +<% if @description %> +
    <%= l(:field_description) %> + <%= textilizable @description, :attachments => @attachments, :object => @issue %> +
    +<% end %> diff --git a/app/views/projects/Copy of show.html.erb b/app/views/projects/Copy of show.html.erb new file mode 100644 index 00000000..7dfa9e70 --- /dev/null +++ b/app/views/projects/Copy of show.html.erb @@ -0,0 +1,53 @@ + + + +

    <%=link_to l(:label_news), project_news_index_path(@project) %>

    +
    + + <% if @news.any? && authorize_for('news', 'index') %> +
    + + <%= render :partial => 'news/news', :collection => @news %> +
    <%= link_to"更多",:contoller=>'project',:action=>'index'%>
    +
    + <% end %> + <%= call_hook(:view_projects_show_right, :project => @project) %> + +

    <%=link_to @author.nil? ? l(:label_activity) : l(:label_user_activity, link_to_user(@author)).html_safe %>

    +
    + + +
    +<% @events_by_day.keys.sort.reverse.each do |day| %> + +
      +<% sort_activity_events(@events_by_day[day]).each do |e, in_group| -%> + + +
    • + +
      <%= format_activity_day(day) %> + <%= format_time(e.event_datetime, false) %> + <%= content_tag('span', h(e.project), :class => 'project') if @project.nil? || @project != e.project %> + <%= link_to format_activity_title(e.event_title), e.event_url %> + + <%= link_to_user(e.event_author ,:class=>"author") if e.respond_to?(:event_author) %>
      +
    • <% end -%> +
    +<% end -%> +
    <%= link_to"更多",:contoller=>'project',:action=>'index'%>
    +
    + + diff --git a/app/views/projects/_edit.html.erb b/app/views/projects/_edit.html.erb new file mode 100644 index 00000000..21176290 --- /dev/null +++ b/app/views/projects/_edit.html.erb @@ -0,0 +1,4 @@ +<%= labelled_form_for @project do |f| %> +<%= render :partial => 'form', :locals => { :f => f } %> +<%= submit_tag l(:button_save) %> +<% end %> diff --git a/app/views/projects/_form.html.erb b/app/views/projects/_form.html.erb new file mode 100644 index 00000000..da5db62c --- /dev/null +++ b/app/views/projects/_form.html.erb @@ -0,0 +1,90 @@ +<%= error_messages_for 'project' %> + +
    + +

    <%= render :partial=>"avatar/avatar_form",:locals=> {source:@project}%>

    +

    <%= f.text_field :name, :required => true, :size => 60 %>

    + +

    <%= f.text_area :description, :rows => 8, :class => 'wiki-edit' %>

    +

    <%= f.text_field :identifier, :required => true, :size => 60, :disabled => @project.identifier_frozen?, :maxlength => Project::IDENTIFIER_MAX_LENGTH %> +<% unless @project.identifier_frozen? %> + <%= l(:text_length_between, :min => 1, :max => Project::IDENTIFIER_MAX_LENGTH) %> <%= l(:text_project_identifier_info).html_safe %> +<% end %>

    +

    <%= f.text_field :homepage, :size => 60 %>

    +

    <%= f.check_box :is_public %>

    + +<% unless @project.allowed_parents.compact.empty? %> +

    <%= label(:project, :parent_id, l(:field_parent)) %><%= parent_project_select_tag(@project) %>

    +<% end %> + +<% if @project.safe_attribute? 'inherit_members' %> +

    <%= f.check_box :inherit_members %>

    +<% end %> + +<%= wikitoolbar_for 'project_description' %> + +<% @project.custom_field_values.each do |value| %> +

    <%= custom_field_tag_with_label :project, value %>

    +<% end %> +<%= call_hook(:view_projects_form, :project => @project, :form => f) %> +
    + +<% if @project.new_record? %> +
    <%= l(:label_module_plural) %> +<% Redmine::AccessControl.available_project_modules.each do |m| %> + +<% end %> +<%= hidden_field_tag 'project[enabled_module_names][]', '' %> +<%= javascript_tag 'observeProjectModules()' %> +
    +<% end %> + +<% if @project.new_record? || @project.module_enabled?('issue_tracking') %> +<% unless @trackers.empty? %> +
    <%=l(:label_tracker_plural)%> +<% @trackers.each do |tracker| %> + +<% end %> +<%= hidden_field_tag 'project[tracker_ids][]', '' %> +
    +<% end %> + +<% unless @issue_custom_fields.empty? %> +
    <%=l(:label_custom_field_plural)%> +<% @issue_custom_fields.each do |custom_field| %> + +<% end %> +<%= hidden_field_tag 'project[issue_custom_field_ids][]', '' %> +
    +<% end %> +<% end %> + + +<% unless @project.identifier_frozen? %> + <% content_for :header_tags do %> + <%= javascript_include_tag 'project_identifier' %> + <% end %> +<% end %> + +<% if !User.current.admin? && @project.inherit_members? && @project.parent && User.current.member_of?(@project.parent) %> + <%= javascript_tag do %> + $(document).ready(function() { + $("#project_inherit_members").change(function(){ + if (!$(this).is(':checked')) { + if (!confirm("<%= escape_javascript(l(:text_own_membership_delete_confirmation)) %>")) { + $("#project_inherit_members").attr("checked", true); + } + } + }); + }); + <% end %> +<% end %> diff --git a/app/views/projects/_members_box.html.erb b/app/views/projects/_members_box.html.erb new file mode 100644 index 00000000..4e3a1cb9 --- /dev/null +++ b/app/views/projects/_members_box.html.erb @@ -0,0 +1,8 @@ + <% if @users_by_role.any? %> +
    +

    <%=l(:label_member_plural)%>

    +

    <% @users_by_role.keys.sort.each do |role| %> + <%=h role %>: <%= @users_by_role[role].sort.collect{|u| link_to_user u}.join(", ").html_safe %>
    + <% end %>

    +
    + <% end %> diff --git a/app/views/projects/_project.html.erb b/app/views/projects/_project.html.erb new file mode 100644 index 00000000..2bd9c333 --- /dev/null +++ b/app/views/projects/_project.html.erb @@ -0,0 +1,58 @@ +
    +
    + <%= tag('img', {:src => '../images/logo-only_med.png', :class => 'img_ta'}, false, false) %> +
    +
    +

    + Claimed by <%= content_tag('a', project.name) %> | Analyzed about 11 hours ago +

    +

    + <%= textilizable(project.short_description, :project => project) %> +

    +
    +
    +

    + <%= content_tag('a', @project.watcher_users.count) %><%= content_tag('span', l(:label_follow_people)) %> +

    +

    + <%= content_tag('a', "#{@project.users.count}") %><%= content_tag('span', l(:label_current_contributors)) %> +

    +

    + <%= content_tag('a', "#{(@project.repository.nil? || @project.repository.changesets[0].nil?) ? '0' : distance_of_time_in_words(Time.now, @project.repository.changesets[0].committed_on)}") %><%= content_tag('span', l(:label_since_last_commits)) %> +

    +

    + <%= content_tag('a', "#{@project.repository.nil? ? '0' : @project.repository.changesets.count }") %><%= content_tag('span', l(:label_commit_on)) %> +

    +
    + +
    +
    +
    + <%= content_tag('span', "#{l(:default_role_manager)}: ") %> + <% @admin = @project.users_by_role[Role.find(3)]%> + <% unless @admin.nil?%> + <%= content_tag('a', @admin.sort.collect{|u| link_to_user u}.join(", ").html_safe) %> + <% end %> +
    +
    + <%= content_tag('span', "#{l(:label_create_time)}: ") %><%= content_tag('span', format_time(@project.created_on)) %> +
    + + <% unless User.current.member_of?(@project) %> + <%= watcher_link(@project, User.current) %> + <% end %> + +
    +
    + +
    + <%= tag('img', {:src => "../images/user.png"}, false, false) %> + <%= render :partial => 'layouts/tag_name', :locals => {:obj => @project,:object_flag => "2",:non_list_all => true }%> + +
    +
    diff --git a/app/views/projects/copy.html.erb b/app/views/projects/copy.html.erb new file mode 100644 index 00000000..93185349 --- /dev/null +++ b/app/views/projects/copy.html.erb @@ -0,0 +1,20 @@ +

    <%=l(:label_project_new)%>

    + +<%= labelled_form_for @project, :url => { :action => "copy" } do |f| %> +<%= render :partial => 'form', :locals => { :f => f } %> + +
    <%= l(:button_copy) %> + + + + + + + + <%= hidden_field_tag 'only[]', '' %> +
    + +
    + +<%= submit_tag l(:button_copy) %> +<% end %> diff --git a/app/views/projects/destroy.html.erb b/app/views/projects/destroy.html.erb new file mode 100644 index 00000000..49d5babf --- /dev/null +++ b/app/views/projects/destroy.html.erb @@ -0,0 +1,17 @@ +

    <%=l(:label_confirmation)%>

    +
    +

    <%=h @project_to_destroy %>
    +<%=l(:text_project_destroy_confirmation)%> + +<% if @project_to_destroy.descendants.any? %> +
    <%= l(:text_subprojects_destroy_warning, + content_tag('strong', h(@project_to_destroy.descendants.collect{|p| p.to_s}.join(', ')))).html_safe %> +<% end %> +

    +

    + <%= form_tag(project_path(@project_to_destroy), :method => :delete) do %> + + <%= submit_tag l(:button_delete) %> + <% end %> +

    +
    diff --git a/app/views/projects/file.html.erb b/app/views/projects/file.html.erb new file mode 100644 index 00000000..3ea34516 --- /dev/null +++ b/app/views/projects/file.html.erb @@ -0,0 +1 @@ +

    文件列表

    \ No newline at end of file diff --git a/app/views/projects/focus.html.erb b/app/views/projects/focus.html.erb new file mode 100644 index 00000000..e3f45a48 --- /dev/null +++ b/app/views/projects/focus.html.erb @@ -0,0 +1 @@ +

    关注列表

    \ No newline at end of file diff --git a/app/views/projects/index.api.rsb b/app/views/projects/index.api.rsb new file mode 100644 index 00000000..8fdea9ba --- /dev/null +++ b/app/views/projects/index.api.rsb @@ -0,0 +1,16 @@ +api.array :projects, api_meta(:total_count => @project_count, :offset => @offset, :limit => @limit) do + @projects.each do |project| + api.project do + api.id project.id + api.name project.name + api.identifier project.identifier + api.description project.description + api.parent(:id => project.parent.id, :name => project.parent.name) if project.parent && project.parent.visible? + + render_api_custom_values project.visible_custom_field_values, api + + api.created_on project.created_on + api.updated_on project.updated_on + end + end +end diff --git a/app/views/projects/index.html.erb b/app/views/projects/index.html.erb new file mode 100644 index 00000000..0124f1f3 --- /dev/null +++ b/app/views/projects/index.html.erb @@ -0,0 +1,35 @@ +<% content_for :header_tags do %> + <%= auto_discovery_link_tag(:atom, {:action => 'index', :format => 'atom', :key => User.current.rss_key}) %> +<% end %> + +

    <%=l(:label_project_plural)%>

    + +
    +<%= render_project_hierarchy(@projects)%> +
    + + + +<% if User.current.logged? %> +

    +<%= l(:label_my_projects) %> +

    +<% end %> + +<% other_formats_links do |f| %> + <%= f.link_to 'Atom', :url => {:key => User.current.rss_key} %> +<% end %> + +<% content_for :sidebar do %> + <%= form_tag({}, :method => :get) do %> +

    <%= l(:label_project_plural) %>

    + +

    <%= submit_tag l(:button_apply), :class => 'button-small', :name => nil %>

    + <% end %> +<% end %> + +<% html_title(l(:label_project_plural)) -%> diff --git a/app/views/projects/investor.html.erb b/app/views/projects/investor.html.erb new file mode 100644 index 00000000..aa9d2ad6 --- /dev/null +++ b/app/views/projects/investor.html.erb @@ -0,0 +1 @@ +

    投资者列表

    \ No newline at end of file diff --git a/app/views/projects/issue.html.erb b/app/views/projects/issue.html.erb new file mode 100644 index 00000000..67e41351 --- /dev/null +++ b/app/views/projects/issue.html.erb @@ -0,0 +1 @@ +

    缺陷列表

    \ No newline at end of file diff --git a/app/views/projects/list_members.html.erb b/app/views/projects/list_members.html.erb new file mode 100644 index 00000000..715f689e --- /dev/null +++ b/app/views/projects/list_members.html.erb @@ -0,0 +1,13 @@ +

    <%=l(:label_member_plural)%>

    + +<% if @members.empty? %>

    <%= l(:label_no_data) %>

    <% end %> + +<% members = @members.group_by {|m| m.role } %> +<% members.keys.sort{|x,y| x.position <=> y.position}.each do |role| %> +

    <%= h(role.name) %>

    +
      +<% members[role].each do |m| %> +
    • <%= link_to_user m.user %> (<%= format_date m.created_on %>)
    • +<% end %> +
    +<% end %> diff --git a/app/views/projects/member.html.erb b/app/views/projects/member.html.erb new file mode 100644 index 00000000..2be9a2da --- /dev/null +++ b/app/views/projects/member.html.erb @@ -0,0 +1,27 @@ + +

    <%= l(:label_member_list)%>

    +
    +<%= error_messages_for 'member' %> +<% roles = Role.find_all_givable + members = @project.member_principals.includes(:roles, :principal).all.sort %> +<% if members.any? %> +<% members.each do |member| %> +
    + + <% next if member.new_record? %> + <% unless member.created_on.nil? %> + <%= content_tag "p", "#{format_time(member.created_on)}#{l(:label_member_since)}", :class => "float_right member_since" %> + <% end %> + <%= member.user.nil? ? '' : (link_to image_tag(url_to_avatar(member.user), :class => 'avatar'), :class => "avatar") %> + <%= content_tag "div", link_to_user(member.principal), :class => "nomargin avatar_name" %> + <%= content_tag "div", content_tag("p", member.roles.sort.collect(&:to_s).join(', ')), :class => "clear avatar_name" %> + <%= call_hook(:view_projects_settings_members_table_row, { :project => @project, :member => member}) %> + +
    +<% end; reset_cycle %> +<% else %> +

    + <%= l(:label_no_data) %> +

    + <% end %> +
    \ No newline at end of file diff --git a/app/views/projects/mission.html.erb b/app/views/projects/mission.html.erb new file mode 100644 index 00000000..1b996ec4 --- /dev/null +++ b/app/views/projects/mission.html.erb @@ -0,0 +1 @@ +

    任务列表

    \ No newline at end of file diff --git a/app/views/projects/new.html.erb b/app/views/projects/new.html.erb new file mode 100644 index 00000000..95b233f4 --- /dev/null +++ b/app/views/projects/new.html.erb @@ -0,0 +1,8 @@ +

    <%=l(:label_project_new)%>

    + +<%= labelled_form_for @project do |f| %> +<%= render :partial => 'form', :locals => { :f => f } %> +<%= submit_tag l(:button_create) %> +<%= submit_tag l(:button_create_and_continue), :name => 'continue' %> +<%= javascript_tag "$('#project_name').focus();" %> +<% end %> diff --git a/app/views/projects/on.html.erb b/app/views/projects/on.html.erb new file mode 100644 index 00000000..d9dac658 --- /dev/null +++ b/app/views/projects/on.html.erb @@ -0,0 +1 @@ +

    提交列表

    \ No newline at end of file diff --git a/app/views/projects/settings.html.erb b/app/views/projects/settings.html.erb new file mode 100644 index 00000000..ed8215ba --- /dev/null +++ b/app/views/projects/settings.html.erb @@ -0,0 +1,5 @@ +

    <%=l(:label_settings)%>

    + +<%= render_tabs project_settings_tabs %> + +<% html_title(l(:label_settings)) -%> diff --git a/app/views/projects/settings/_activities.html.erb b/app/views/projects/settings/_activities.html.erb new file mode 100644 index 00000000..8c9a6121 --- /dev/null +++ b/app/views/projects/settings/_activities.html.erb @@ -0,0 +1,42 @@ +<%= form_tag(project_enumerations_path(@project), :method => :put, :class => "tabular") do %> + + + + + + <% TimeEntryActivity.new.available_custom_fields.each do |value| %> + + <% end %> + + + + <% @project.activities(true).each do |enumeration| %> + <%= fields_for "enumerations[#{enumeration.id}]", enumeration do |ff| %> + + + + <% enumeration.custom_field_values.each do |value| %> + + <% end %> + + + <% end %> + <% end %> +
    <%= l(:field_name) %><%= l(:enumeration_system_activity) %><%= h value.name %><%= l(:field_active) %>
    + <%= ff.hidden_field :parent_id, :value => enumeration.id unless enumeration.project %> + <%= h(enumeration) %> + <%= checked_image !enumeration.project %> + <%= custom_field_tag "enumerations[#{enumeration.id}]", value %> + + <%= ff.check_box :active %> +
    + +
    +<%= link_to(l(:button_reset), project_enumerations_path(@project), + :method => :delete, + :data => {:confirm => l(:text_are_you_sure)}, + :class => 'icon icon-del') %> +
    + +<%= submit_tag l(:button_save) %> +<% end %> diff --git a/app/views/projects/settings/_boards.html.erb b/app/views/projects/settings/_boards.html.erb new file mode 100644 index 00000000..1050ef70 --- /dev/null +++ b/app/views/projects/settings/_boards.html.erb @@ -0,0 +1,36 @@ +<% if @project.boards.any? %> + + + + + + + + +<% Board.board_tree(@project.boards) do |board, level| + next if board.new_record? %> + + + + + + +<% end %> + +
    <%= l(:label_board) %><%= l(:field_description) %>
    <%= link_to board.name, project_board_path(@project, board) %><%=h board.description %> + <% if authorize_for("boards", "edit") %> + <%= reorder_links('board', {:controller => 'boards', :action => 'update', :project_id => @project, :id => board}, :put) %> + <% end %> + + <% if User.current.allowed_to?(:manage_boards, @project) %> + <%= link_to l(:button_edit), edit_project_board_path(@project, board), :class => 'icon icon-edit' %> + <%= delete_link project_board_path(@project, board) %> + <% end %> +
    +<% else %> +

    <%= l(:label_no_data) %>

    +<% end %> + +<% if User.current.allowed_to?(:manage_boards, @project) %> +

    <%= link_to l(:label_board_new), new_project_board_path(@project), :class => 'icon icon-add' %>

    +<% end %> diff --git a/app/views/projects/settings/_issue_categories.html.erb b/app/views/projects/settings/_issue_categories.html.erb new file mode 100644 index 00000000..e88a85d5 --- /dev/null +++ b/app/views/projects/settings/_issue_categories.html.erb @@ -0,0 +1,29 @@ +<% if @project.issue_categories.any? %> + + + + + + + +<% for category in @project.issue_categories %> + <% unless category.new_record? %> + + + + + + <% end %> +<% end %> + +
    <%= l(:label_issue_category) %><%= l(:field_assigned_to) %>
    <%=h(category.name) %><%=h(category.assigned_to.name) if category.assigned_to %> + <% if User.current.allowed_to?(:manage_categories, @project) %> + <%= link_to l(:button_edit), edit_issue_category_path(category), :class => 'icon icon-edit' %> + <%= delete_link issue_category_path(category) %> + <% end %> +
    +<% else %> +

    <%= l(:label_no_data) %>

    +<% end %> + +

    <%= link_to l(:label_issue_category_new), new_project_issue_category_path(@project), :class => 'icon icon-add' if User.current.allowed_to?(:manage_categories, @project) %>

    diff --git a/app/views/projects/settings/_members.html.erb b/app/views/projects/settings/_members.html.erb new file mode 100644 index 00000000..edd7a27f --- /dev/null +++ b/app/views/projects/settings/_members.html.erb @@ -0,0 +1,77 @@ +<%= error_messages_for 'member' %> +<% roles = Role.find_all_givable + members = @project.member_principals.includes(:roles, :principal).all.sort %> + +
    +<% if roles.any? %> + <%= form_for(@member, {:as => :membership, :url => project_memberships_path(@project), :remote => true, :method => :post}) do |f| %> +
    <%=l(:label_member_new)%> + +

    <%= label_tag "principal_search", l(:label_principal_search) %><%= text_field_tag 'principal_search', nil %>

    + <%= javascript_tag "observeSearchfield('principal_search', null, '#{ escape_javascript autocomplete_project_memberships_path(@project, :format => 'js') }')" %> + +
    + <%= render_principals_for_new_members(@project) %> +
    + +

    <%= l(:label_role_plural) %>: + <% roles.each do |role| %> + + <% end %>

    + +

    <%= submit_tag l(:button_add), :id => 'member-add-submit' %>

    +
    + <% end %> +<% end %> +
    + +
    +<% if members.any? %> + + + + + + <%= call_hook(:view_projects_settings_members_table_header, :project => @project) %> + + + <% members.each do |member| %> + <% next if member.new_record? %> + + + + + <%= call_hook(:view_projects_settings_members_table_row, { :project => @project, :member => member}) %> + +<% end; reset_cycle %> + +
    <%= l(:label_user) %> / <%= l(:label_group) %><%= l(:label_role_plural) %>
    <%= link_to_user member.principal %> + <%=h member.roles.sort.collect(&:to_s).join(', ') %> + <%= form_for(member, {:as => :membership, :remote => true, :url => membership_path(member), + :method => :put, + :html => { :id => "member-#{member.id}-roles-form", :class => 'hol' }} + ) do |f| %> +

    <% roles.each do |role| %> +
    + <% end %>

    + <%= hidden_field_tag 'membership[role_ids][]', '' %> +

    <%= submit_tag l(:button_change), :class => "small" %> + <%= link_to_function l(:button_cancel), + "$('#member-#{member.id}-roles').show(); $('#member-#{member.id}-roles-form').hide(); return false;" + %>

    + <% end %> +
    + <%= link_to_function l(:button_edit), + "$('#member-#{member.id}-roles').hide(); $('#member-#{member.id}-roles-form').show(); return false;", + :class => 'icon icon-edit' %> + <%= delete_link membership_path(member), + :remote => true, + :data => (!User.current.admin? && member.include?(User.current) ? {:confirm => l(:text_own_membership_delete_confirmation)} : {}) if member.deletable? %> +
    +<% else %> +

    <%= l(:label_no_data) %>

    +<% end %> +
    + + diff --git a/app/views/projects/settings/_modules.html.erb b/app/views/projects/settings/_modules.html.erb new file mode 100644 index 00000000..d151a04b --- /dev/null +++ b/app/views/projects/settings/_modules.html.erb @@ -0,0 +1,18 @@ +<%= form_for @project, + :url => { :action => 'modules', :id => @project }, + :html => {:id => 'modules-form', + :method => :post} do |f| %> + +
    +<%= l(:text_select_project_modules) %> + +<% Redmine::AccessControl.available_project_modules.each do |m| %> +

    +<% end %> +
    +

    <%= check_all_links 'modules-form' %>

    + +

    <%= submit_tag l(:button_save) %>

    + +<% end %> diff --git a/app/views/projects/settings/_repositories.html.erb b/app/views/projects/settings/_repositories.html.erb new file mode 100644 index 00000000..4492165c --- /dev/null +++ b/app/views/projects/settings/_repositories.html.erb @@ -0,0 +1,41 @@ +<% if @project.repositories.any? %> + + + + + + + + + + + + <% @project.repositories.sort.each do |repository| %> + + + + + + + + <% end %> + +
    <%= l(:field_identifier) %><%= l(:field_repository_is_default) %><%= l(:label_scm) %><%= l(:label_repository) %>
    + <%= link_to repository.identifier, + {:controller => 'repositories', :action => 'show',:id => @project, :repository_id => repository.identifier_param} if repository.identifier.present? %> + <%= checked_image repository.is_default? %><%=h repository.scm_name %><%=h repository.url %> + <% if User.current.allowed_to?(:manage_repository, @project) %> + <%= link_to(l(:label_user_plural), committers_repository_path(repository), + :class => 'icon icon-user') %> + <%= link_to(l(:button_edit), edit_repository_path(repository), + :class => 'icon icon-edit') %> + <%= delete_link repository_path(repository) %> + <% end %> +
    +<% else %> +

    <%= l(:label_no_data) %>

    +<% end %> + +<% if User.current.allowed_to?(:manage_repository, @project) %> +

    <%= link_to l(:label_repository_new), new_project_repository_path(@project), :class => 'icon icon-add' %>

    +<% end %> diff --git a/app/views/projects/settings/_versions.html.erb b/app/views/projects/settings/_versions.html.erb new file mode 100644 index 00000000..778803bf --- /dev/null +++ b/app/views/projects/settings/_versions.html.erb @@ -0,0 +1,41 @@ +<% if @project.shared_versions.any? %> + + + + + + + + + + + +<% for version in @project.shared_versions.sort %> + + + + + + + + + +<% end; reset_cycle %> + +
    <%= l(:label_version) %><%= l(:field_effective_date) %><%= l(:field_description) %><%= l(:field_status) %><%= l(:field_sharing) %><%= l(:label_wiki_page) %>
    <%= link_to_version version %><%= format_date(version.effective_date) %><%=h version.description %><%= l("version_status_#{version.status}") %><%= link_to_if_authorized(h(version.wiki_page_title), {:controller => 'wiki', :action => 'show', :project_id => version.project, :id => Wiki.titleize(version.wiki_page_title)}) || h(version.wiki_page_title) unless version.wiki_page_title.blank? || version.project.wiki.nil? %> + <% if version.project == @project && User.current.allowed_to?(:manage_versions, @project) %> + <%= link_to l(:button_edit), edit_version_path(version), :class => 'icon icon-edit' %> + <%= delete_link version_path(version) %> + <% end %> +
    +<% else %> +

    <%= l(:label_no_data) %>

    +<% end %> + +
    +<% if @project.versions.any? %> + <%= link_to l(:label_close_versions), close_completed_project_versions_path(@project), :method => :put %> +<% end %> +
    + +

    <%= link_to l(:label_version_new), new_project_version_path(@project, :back_url => ''), :class => 'icon icon-add' if User.current.allowed_to?(:manage_versions, @project) %>

    diff --git a/app/views/projects/settings/_wiki.html.erb b/app/views/projects/settings/_wiki.html.erb new file mode 100644 index 00000000..8374abb3 --- /dev/null +++ b/app/views/projects/settings/_wiki.html.erb @@ -0,0 +1,19 @@ +<%= labelled_form_for @wiki, + :as => :wiki, + :url => { :controller => 'wikis', :action => 'edit', :id => @project }, + :remote => true, :method => 'post' do |f| %> + +<%= error_messages_for 'wiki' %> + +
    +

    <%= f.text_field :start_page, :size => 60, :required => true %> +<%= l(:text_unallowed_characters) %>: , . / ? ; : |

    +
    + +
    +<%= link_to(l(:button_delete), {:controller => 'wikis', :action => 'destroy', :id => @project}, + :class => 'icon icon-del') if @wiki && !@wiki.new_record? %> +
    + +<%= submit_tag((@wiki.nil? || @wiki.new_record?) ? l(:button_create) : l(:button_save)) %> +<% end %> diff --git a/app/views/projects/show-old.html.erb b/app/views/projects/show-old.html.erb new file mode 100644 index 00000000..4c8ae87a --- /dev/null +++ b/app/views/projects/show-old.html.erb @@ -0,0 +1,97 @@ +
    + <% if User.current.allowed_to?(:add_subprojects, @project) %> + <%= link_to l(:label_subproject_new), new_project_path(:parent_id => @project), :class => 'icon icon-add' %> + <% end %> + <% if User.current.allowed_to?(:close_project, @project) %> + <% if @project.active? %> + <%= link_to l(:button_close), close_project_path(@project), :data => {:confirm => l(:text_are_you_sure)}, :method => :post, :class => 'icon icon-lock' %> + <% else %> + <%= link_to l(:button_reopen), reopen_project_path(@project), :data => {:confirm => l(:text_are_you_sure)}, :method => :post, :class => 'icon icon-unlock' %> + <% end %> + <% end %> +
    + +

    <%=l(:label_overview)%>

    + +<% unless @project.active? %> +

    <%= l(:text_project_closed) %>

    +<% end %> + +
    + <% if @project.description.present? %> +
    + <%= textilizable @project.description %> +
    + <% end %> +
      + <% unless @project.homepage.blank? %> +
    • <%=l(:field_homepage)%>: <%= link_to h(@project.homepage), @project.homepage %>
    • + <% end %> + <% if @subprojects.any? %> +
    • <%=l(:label_subproject_plural)%>: + <%= @subprojects.collect{|p| link_to p, project_path(p)}.join(", ").html_safe %>
    • + <% end %> + <% @project.visible_custom_field_values.each do |custom_value| %> + <% if !custom_value.value.blank? %> +
    • <%=h custom_value.custom_field.name %>: <%=h show_value(custom_value) %>
    • + <% end %> + <% end %> +
    + + <% if User.current.allowed_to?(:view_issues, @project) %> +
    +

    <%=l(:label_issue_tracking)%>

    +
      + <% for tracker in @trackers %> +
    • <%= link_to h(tracker.name), project_issues_path(@project, :set_filter => 1, :tracker_id => tracker.id) %>: + <%= l(:label_x_open_issues_abbr_on_total, :count => @open_issues_by_tracker[tracker].to_i, + :total => @total_issues_by_tracker[tracker].to_i) %> +
    • + <% end %> +
    +

    + <%= link_to l(:label_issue_view_all), project_issues_path(@project, :set_filter => 1) %> + <% if User.current.allowed_to?(:view_calendar, @project, :global => true) %> + | <%= link_to l(:label_calendar), project_calendar_path(@project) %> + <% end %> + <% if User.current.allowed_to?(:view_gantt, @project, :global => true) %> + | <%= link_to l(:label_gantt), project_gantt_path(@project) %> + <% end %> +

    +
    + <% end %> + <%= call_hook(:view_projects_show_left, :project => @project) %> +
    + +
    + <%= render :partial => 'members_box' %> + + <% if @news.any? && authorize_for('news', 'index') %> +
    +

    <%=l(:label_news_latest)%>

    + <%= render :partial => 'news/news', :collection => @news %> +

    <%= link_to l(:label_news_view_all), project_news_index_path(@project) %>

    +
    + <% end %> + <%= call_hook(:view_projects_show_right, :project => @project) %> +
    + +<% content_for :sidebar do %> + <% if @total_hours.present? %> +

    <%= l(:label_spent_time) %>

    +

    <%= l_hours(@total_hours) %>

    +

    + <% if User.current.allowed_to?(:log_time, @project) %> + <%= link_to l(:button_log_time), new_project_time_entry_path(@project) %> | + <% end %> + <%= link_to(l(:label_details), project_time_entries_path(@project)) %> | + <%= link_to(l(:label_report), report_project_time_entries_path(@project)) %>

    + <% end %> + <%= call_hook(:view_projects_show_sidebar_bottom, :project => @project) %> +<% end %> + +<% content_for :header_tags do %> +<%= auto_discovery_link_tag(:atom, {:controller => 'activities', :action => 'index', :id => @project, :format => 'atom', :key => User.current.rss_key}) %> +<% end %> + +<% html_title(l(:label_overview)) -%> \ No newline at end of file diff --git a/app/views/projects/show.api.rsb b/app/views/projects/show.api.rsb new file mode 100644 index 00000000..a6f26f89 --- /dev/null +++ b/app/views/projects/show.api.rsb @@ -0,0 +1,25 @@ +api.project do + api.id @project.id + api.name @project.name + api.identifier @project.identifier + api.description @project.description + api.homepage @project.homepage + api.parent(:id => @project.parent.id, :name => @project.parent.name) if @project.parent && @project.parent.visible? + + render_api_custom_values @project.visible_custom_field_values, api + + api.created_on @project.created_on + api.updated_on @project.updated_on + + api.array :trackers do + @project.trackers.each do |tracker| + api.tracker(:id => tracker.id, :name => tracker.name) + end + end if include_in_api_response?('trackers') + + api.array :issue_categories do + @project.issue_categories.each do |category| + api.issue_category(:id => category.id, :name => category.name) + end + end if include_in_api_response?('issue_categories') +end diff --git a/app/views/projects/show.html.erb b/app/views/projects/show.html.erb new file mode 100644 index 00000000..4d9a70b2 --- /dev/null +++ b/app/views/projects/show.html.erb @@ -0,0 +1,97 @@ + +
    +

    <%= @author.nil? ? l(:label_activity) : l(:label_user_activity, link_to_user(@author)).html_safe %>

    +

    + <%= l(:label_date_from_to, :start => format_date(@date_to - @days), :end => format_date(@date_to-1)) %> +

    +
    + <% @events_by_day.keys.sort.reverse.each do |day| %> +

    +
    + <% sort_activity_events(@events_by_day[day]).each do |e, in_group| -%> +
    + + + + + +
    <%= image_tag(url_to_avatar(e.event_author), :class => "avatar")%> + + + + + + + + + + +
    <%= h(e.project) if @project.nil? || @project != e.project %> 有了最新动态 <%= link_to format_activity_title(e.event_title), e.event_url %>

    <%= format_activity_description(e.event_description) %>

    <%= format_activity_day(day) %> <%= format_time(e.event_datetime, false) %><%= link_to_user(e.event_author) if e.respond_to?(:event_author) %>
    +
    + <% end -%> +
    + <% end -%> +
    +
    + + + + + + + diff --git a/app/views/projects/show_new.html.erb b/app/views/projects/show_new.html.erb new file mode 100644 index 00000000..8ab657b0 --- /dev/null +++ b/app/views/projects/show_new.html.erb @@ -0,0 +1,97 @@ +
    + <% if User.current.allowed_to?(:add_subprojects, @project) %> + <%= link_to l(:label_subproject_new), new_project_path(:parent_id => @project), :class => 'icon icon-add' %> + <% end %> + <% if User.current.allowed_to?(:close_project, @project) %> + <% if @project.active? %> + <%= link_to l(:button_close), close_project_path(@project), :data => {:confirm => l(:text_are_you_sure)}, :method => :post, :class => 'icon icon-lock' %> + <% else %> + <%= link_to l(:button_reopen), reopen_project_path(@project), :data => {:confirm => l(:text_are_you_sure)}, :method => :post, :class => 'icon icon-unlock' %> + <% end %> + <% end %> +
    + +

    <%=l(:label_overview)%>

    + +<% unless @project.active? %> +

    <%= l(:text_project_closed) %>

    +<% end %> + +
    + <% if @project.description.present? %> +
    + <%= textilizable @project.description %> +
    + <% end %> +
      + <% unless @project.homepage.blank? %> +
    • <%=l(:field_homepage)%>: <%= link_to h(@project.homepage), @project.homepage %>
    • + <% end %> + <% if @subprojects.any? %> +
    • <%=l(:label_subproject_plural)%>: + <%= @subprojects.collect{|p| link_to p, project_path(p)}.join(", ").html_safe %>
    • + <% end %> + <% @project.visible_custom_field_values.each do |custom_value| %> + <% if !custom_value.value.blank? %> +
    • <%=h custom_value.custom_field.name %>: <%=h show_value(custom_value) %>
    • + <% end %> + <% end %> +
    + + <% if User.current.allowed_to?(:view_issues, @project) %> +
    +

    <%=l(:label_issue_tracking)%>

    +
      + <% for tracker in @trackers %> +
    • <%= link_to h(tracker.name), project_issues_path(@project, :set_filter => 1, :tracker_id => tracker.id) %>: + <%= l(:label_x_open_issues_abbr_on_total, :count => @open_issues_by_tracker[tracker].to_i, + :total => @total_issues_by_tracker[tracker].to_i) %> +
    • + <% end %> +
    +

    + <%= link_to l(:label_issue_view_all), project_issues_path(@project, :set_filter => 1) %> + <% if User.current.allowed_to?(:view_calendar, @project, :global => true) %> + | <%= link_to l(:label_calendar), project_calendar_path(@project) %> + <% end %> + <% if User.current.allowed_to?(:view_gantt, @project, :global => true) %> + | <%= link_to l(:label_gantt), project_gantt_path(@project) %> + <% end %> +

    +
    + <% end %> + <%= call_hook(:view_projects_show_left, :project => @project) %> +
    + +
    + <%= render :partial => 'members_box' %> + + <% if @news.any? && authorize_for('news', 'index') %> +
    +

    <%=l(:label_news_latest)%>

    + <%= render :partial => 'news/news', :collection => @news %> +

    <%= link_to l(:label_news_view_all), project_news_index_path(@project) %>

    +
    + <% end %> + <%= call_hook(:view_projects_show_right, :project => @project) %> +
    + +<% content_for :sidebar do %> + <% if @total_hours.present? %> +

    <%= l(:label_spent_time) %>

    +

    <%= l_hours(@total_hours) %>

    +

    + <% if User.current.allowed_to?(:log_time, @project) %> + <%= link_to l(:button_log_time), new_project_time_entry_path(@project) %> | + <% end %> + <%= link_to(l(:label_details), project_time_entries_path(@project)) %> | + <%= link_to(l(:label_report), report_project_time_entries_path(@project)) %>

    + <% end %> + <%= call_hook(:view_projects_show_sidebar_bottom, :project => @project) %> +<% end %> + +<% content_for :header_tags do %> +<%= auto_discovery_link_tag(:atom, {:controller => 'activities', :action => 'index', :id => @project, :format => 'atom', :key => User.current.rss_key}) %> +<% end %> + +<% html_title(l(:label_overview)) -%> diff --git a/app/views/queries/_columns.html.erb b/app/views/queries/_columns.html.erb new file mode 100644 index 00000000..0d624d98 --- /dev/null +++ b/app/views/queries/_columns.html.erb @@ -0,0 +1,34 @@ + + + + + + + +
    + <%= label_tag "available_columns", l(:description_available_columns) %> +
    + <%= select_tag 'available_columns', + options_for_select(query_available_inline_columns_options(query)), + :multiple => true, :size => 10, :style => "width:150px", + :ondblclick => "moveOptions(this.form.available_columns, this.form.selected_columns);" %> +
    +
    + +
    + <%= label_tag "selected_columns", l(:description_selected_columns) %> +
    + <%= select_tag tag_name, + options_for_select(query_selected_inline_columns_options(query)), + :id => 'selected_columns', :multiple => true, :size => 10, :style => "width:150px", + :ondblclick => "moveOptions(this.form.selected_columns, this.form.available_columns);" %> +
    +
    + +
    + +<% content_for :header_tags do %> +<%= javascript_include_tag 'select_list_move' %> +<% end %> diff --git a/app/views/queries/_filters.html.erb b/app/views/queries/_filters.html.erb new file mode 100644 index 00000000..795f8075 --- /dev/null +++ b/app/views/queries/_filters.html.erb @@ -0,0 +1,28 @@ +<%= javascript_tag do %> +var operatorLabels = <%= raw_json Query.operators_labels %>; +var operatorByType = <%= raw_json Query.operators_by_filter_type %>; +var availableFilters = <%= raw_json query.available_filters_as_json %>; +var labelDayPlural = <%= raw_json l(:label_day_plural) %>; +var allProjects = <%= raw query.all_projects_values.to_json %>; +$(document).ready(function(){ + initFilters(); + <% query.filters.each do |field, options| %> + addFilter("<%= field %>", <%= raw_json query.operator_for(field) %>, <%= raw_json query.values_for(field) %>); + <% end %> +}); +<% end %> + + + + + + +
    + +
    +
    +<%= label_tag('add_filter_select', l(:label_filter_add)) %> +<%= select_tag 'add_filter_select', filters_options_for_select(query), :name => nil %> +
    +<%= hidden_field_tag 'f[]', '' %> +<% include_calendar_headers_tags %> diff --git a/app/views/queries/_form.html.erb b/app/views/queries/_form.html.erb new file mode 100644 index 00000000..1070b471 --- /dev/null +++ b/app/views/queries/_form.html.erb @@ -0,0 +1,55 @@ +<%= error_messages_for 'query' %> + +
    +
    +

    +<%= text_field 'query', 'name', :size => 80 %>

    + +<% if User.current.admin? || User.current.allowed_to?(:manage_public_queries, @project) %> +

    +<%= check_box 'query', 'is_public', + :onchange => (User.current.admin? ? nil : 'if (this.checked) {$("#query_is_for_all").removeAttr("checked"); $("#query_is_for_all").attr("disabled", true);} else {$("#query_is_for_all").removeAttr("disabled");}') %>

    +<% end %> + +

    +<%= check_box_tag 'query_is_for_all', 1, @query.project.nil?, + :disabled => (!@query.new_record? && (@query.project.nil? || (@query.is_public? && !User.current.admin?))) %>

    + +

    +<%= check_box_tag 'default_columns', 1, @query.has_default_columns?, :id => 'query_default_columns', + :onclick => 'if (this.checked) {$("#columns").hide();} else {$("#columns").show();}' %>

    + +

    +<%= select 'query', 'group_by', @query.groupable_columns.collect {|c| [c.caption, c.name.to_s]}, :include_blank => true %>

    + +

    +<%= available_block_columns_tags(@query) %>

    +
    + +
    <%= l(:label_filter_plural) %> +<%= render :partial => 'queries/filters', :locals => {:query => query}%> +
    + +
    <%= l(:label_sort) %> +<% 3.times do |i| %> +<%= i+1 %>: +<%= label_tag "query_sort_criteria_attribute_" + i.to_s, + l(:description_query_sort_criteria_attribute), :class => "hidden-for-sighted" %> +<%= select_tag("query[sort_criteria][#{i}][]", + options_for_select([[]] + query.available_columns.select(&:sortable?).collect {|column| [column.caption, column.name.to_s]}, @query.sort_criteria_key(i)), + :id => "query_sort_criteria_attribute_" + i.to_s)%> +<%= label_tag "query_sort_criteria_direction_" + i.to_s, + l(:description_query_sort_criteria_direction), :class => "hidden-for-sighted" %> +<%= select_tag("query[sort_criteria][#{i}][]", + options_for_select([[], [l(:label_ascending), 'asc'], [l(:label_descending), 'desc']], @query.sort_criteria_order(i)), + :id => "query_sort_criteria_direction_" + i.to_s) %> +
    +<% end %> +
    + +<%= content_tag 'fieldset', :id => 'columns', :style => (query.has_default_columns? ? 'display:none;' : nil) do %> +<%= l(:field_column_names) %> +<%= render_query_columns_selection(query) %> +<% end %> + +
    diff --git a/app/views/queries/edit.html.erb b/app/views/queries/edit.html.erb new file mode 100644 index 00000000..422e95c4 --- /dev/null +++ b/app/views/queries/edit.html.erb @@ -0,0 +1,6 @@ +

    <%= l(:label_query) %>

    + +<%= form_tag(query_path(@query), :onsubmit => 'selectAllOptions("selected_columns");', :method => :put) do %> + <%= render :partial => 'form', :locals => {:query => @query} %> + <%= submit_tag l(:button_save) %> +<% end %> diff --git a/app/views/queries/index.api.rsb b/app/views/queries/index.api.rsb new file mode 100644 index 00000000..800b4964 --- /dev/null +++ b/app/views/queries/index.api.rsb @@ -0,0 +1,10 @@ +api.array :queries, api_meta(:total_count => @query_count, :offset => @offset, :limit => @limit) do + @queries.each do |query| + api.query do + api.id query.id + api.name query.name + api.is_public query.is_public + api.project_id query.project_id + end + end +end diff --git a/app/views/queries/index.html.erb b/app/views/queries/index.html.erb new file mode 100644 index 00000000..573a9918 --- /dev/null +++ b/app/views/queries/index.html.erb @@ -0,0 +1,27 @@ +
    +<%= link_to_if_authorized l(:label_query_new), new_project_query_path(:project_id => @project), :class => 'icon icon-add' %> +
    + +

    <%= l(:label_query_plural) %>

    + +<% if @queries.empty? %> +

    <%=l(:label_no_data)%>

    +<% else %> + + <% @queries.each do |query| %> + + + + + <% end %> +
    + <%= link_to h(query.name), :controller => 'issues', :action => 'index', :project_id => @project, :query_id => query %> + + + <% if query.editable_by?(User.current) %> + <%= link_to l(:button_edit), edit_query_path(query), :class => 'icon icon-edit' %> + <%= delete_link query_path(query) %> + + <% end %> +
    +<% end %> diff --git a/app/views/queries/new.html.erb b/app/views/queries/new.html.erb new file mode 100644 index 00000000..4d03768d --- /dev/null +++ b/app/views/queries/new.html.erb @@ -0,0 +1,6 @@ +

    <%= l(:label_query_new) %>

    + +<%= form_tag(@project ? project_queries_path(@project) : queries_path, :onsubmit => 'selectAllOptions("selected_columns");') do %> + <%= render :partial => 'form', :locals => {:query => @query} %> + <%= submit_tag l(:button_save) %> +<% end %> diff --git a/app/views/reports/_details.html.erb b/app/views/reports/_details.html.erb new file mode 100644 index 00000000..4a01c733 --- /dev/null +++ b/app/views/reports/_details.html.erb @@ -0,0 +1,30 @@ +<% if @statuses.empty? or rows.empty? %> +

    <%=l(:label_no_data)%>

    +<% else %> +<% col_width = 70 / (@statuses.length+3) %> + + + +<% for status in @statuses %> + +<% end %> + + + + + +<% for row in rows %> +"> + + <% for status in @statuses %> + + <% end %> + + + + +<% end %> + +
    <%=h status.name %><%=l(:label_open_issues_plural)%><%=l(:label_closed_issues_plural)%><%=l(:label_total)%>
    <%= link_to h(row.name), aggregate_path(@project, field_name, row) %><%= aggregate_link data, { field_name => row.id, "status_id" => status.id }, aggregate_path(@project, field_name, row, :status_id => status.id) %><%= aggregate_link data, { field_name => row.id, "closed" => 0 }, aggregate_path(@project, field_name, row, :status_id => "o") %><%= aggregate_link data, { field_name => row.id, "closed" => 1 }, aggregate_path(@project, field_name, row, :status_id => "c") %><%= aggregate_link data, { field_name => row.id }, aggregate_path(@project, field_name, row, :status_id => "*") %>
    +<% end + reset_cycle %> diff --git a/app/views/reports/_simple.html.erb b/app/views/reports/_simple.html.erb new file mode 100644 index 00000000..8ea18f16 --- /dev/null +++ b/app/views/reports/_simple.html.erb @@ -0,0 +1,23 @@ +<% if @statuses.empty? or rows.empty? %> +

    <%=l(:label_no_data)%>

    +<% else %> + + + + + + + + +<% for row in rows %> +"> + + + + + +<% end %> + +
    <%=l(:label_open_issues_plural)%><%=l(:label_closed_issues_plural)%><%=l(:label_total)%>
    <%= link_to h(row.name), aggregate_path(@project, field_name, row) %><%= aggregate_link data, { field_name => row.id, "closed" => 0 }, aggregate_path(@project, field_name, row, :status_id => "o") %><%= aggregate_link data, { field_name => row.id, "closed" => 1 }, aggregate_path(@project, field_name, row, :status_id => "c") %><%= aggregate_link data, { field_name => row.id }, aggregate_path(@project, field_name, row, :status_id => "*") %>
    +<% end + reset_cycle %> diff --git a/app/views/reports/issue_report.html.erb b/app/views/reports/issue_report.html.erb new file mode 100644 index 00000000..771c1a68 --- /dev/null +++ b/app/views/reports/issue_report.html.erb @@ -0,0 +1,33 @@ +

    <%=l(:label_report_plural)%>

    + +
    +

    <%=l(:field_tracker)%>  <%= link_to image_tag('zoom_in.png'), project_issues_report_details_path(@project, :detail => 'tracker') %>

    +<%= render :partial => 'simple', :locals => { :data => @issues_by_tracker, :field_name => "tracker_id", :rows => @trackers } %> +
    +

    <%=l(:field_priority)%>  <%= link_to image_tag('zoom_in.png'), project_issues_report_details_path(@project, :detail => 'priority') %>

    +<%= render :partial => 'simple', :locals => { :data => @issues_by_priority, :field_name => "priority_id", :rows => @priorities } %> +
    +

    <%=l(:field_assigned_to)%>  <%= link_to image_tag('zoom_in.png'), project_issues_report_details_path(@project, :detail => 'assigned_to') %>

    +<%= render :partial => 'simple', :locals => { :data => @issues_by_assigned_to, :field_name => "assigned_to_id", :rows => @assignees } %> +
    +

    <%=l(:field_author)%>  <%= link_to image_tag('zoom_in.png'), project_issues_report_details_path(@project, :detail => 'author') %>

    +<%= render :partial => 'simple', :locals => { :data => @issues_by_author, :field_name => "author_id", :rows => @authors } %> +
    +<%= call_hook(:view_reports_issue_report_split_content_left, :project => @project) %> +
    + +
    +

    <%=l(:field_version)%>  <%= link_to image_tag('zoom_in.png'), project_issues_report_details_path(@project, :detail => 'version') %>

    +<%= render :partial => 'simple', :locals => { :data => @issues_by_version, :field_name => "fixed_version_id", :rows => @versions } %> +
    +<% if @project.children.any? %> +

    <%=l(:field_subproject)%>  <%= link_to image_tag('zoom_in.png'), project_issues_report_details_path(@project, :detail => 'subproject') %>

    +<%= render :partial => 'simple', :locals => { :data => @issues_by_subproject, :field_name => "project_id", :rows => @subprojects } %> +
    +<% end %> +

    <%=l(:field_category)%>  <%= link_to image_tag('zoom_in.png'), project_issues_report_details_path(@project, :detail => 'category') %>

    +<%= render :partial => 'simple', :locals => { :data => @issues_by_category, :field_name => "category_id", :rows => @categories } %> +
    +<%= call_hook(:view_reports_issue_report_split_content_right, :project => @project) %> +
    + diff --git a/app/views/reports/issue_report_details.html.erb b/app/views/reports/issue_report_details.html.erb new file mode 100644 index 00000000..958fc3a9 --- /dev/null +++ b/app/views/reports/issue_report_details.html.erb @@ -0,0 +1,7 @@ +

    <%=l(:label_report_plural)%>

    + +

    <%=@report_title%>

    +<%= render :partial => 'details', :locals => { :data => @data, :field_name => @field, :rows => @rows } %> +
    +<%= link_to l(:button_back), project_issues_report_path(@project) %> + diff --git a/app/views/repositories/_breadcrumbs.html.erb b/app/views/repositories/_breadcrumbs.html.erb new file mode 100644 index 00000000..86fe28cb --- /dev/null +++ b/app/views/repositories/_breadcrumbs.html.erb @@ -0,0 +1,31 @@ +<%= link_to(@repository.identifier.present? ? h(@repository.identifier) : 'root', + :action => 'show', :id => @project, + :repository_id => @repository.identifier_param, + :path => nil, :rev => @rev) %> +<% +dirs = path.split('/') +if 'file' == kind + filename = dirs.pop +end +link_path = '' +dirs.each do |dir| + next if dir.blank? + link_path << '/' unless link_path.empty? + link_path << "#{dir}" + %> + / <%= link_to h(dir), :action => 'show', :id => @project, :repository_id => @repository.identifier_param, + :path => to_path_param(link_path), :rev => @rev %> +<% end %> +<% if filename %> + / <%= link_to h(filename), + :action => 'changes', :id => @project, :repository_id => @repository.identifier_param, + :path => to_path_param("#{link_path}/#{filename}"), :rev => @rev %> +<% end %> +<% + # @rev is revsion or Git and Mercurial branch or tag. + # For Mercurial *tip*, @rev and @changeset are nil. + rev_text = @changeset.nil? ? @rev : format_revision(@changeset) +%> +<%= "@ #{h rev_text}" unless rev_text.blank? %> + +<% html_title(with_leading_slash(path)) -%> diff --git a/app/views/repositories/_dir_list.html.erb b/app/views/repositories/_dir_list.html.erb new file mode 100644 index 00000000..26ba05bb --- /dev/null +++ b/app/views/repositories/_dir_list.html.erb @@ -0,0 +1,19 @@ +
    + + + + + +<% if @repository.report_last_commit %> + + + + +<% end %> + + + +<%= render :partial => 'dir_list_content' %> + +
    <%= l(:field_name) %><%= l(:field_filesize) %><%= l(:label_revision) %><%= l(:label_age) %><%= l(:field_author) %><%= l(:field_comments) %>
    +
    diff --git a/app/views/repositories/_dir_list_content.html.erb b/app/views/repositories/_dir_list_content.html.erb new file mode 100644 index 00000000..e595a77d --- /dev/null +++ b/app/views/repositories/_dir_list_content.html.erb @@ -0,0 +1,31 @@ +<% @entries.each do |entry| %> +<% tr_id = Digest::MD5.hexdigest(entry.path) + depth = params[:depth].to_i %> +<% ent_path = Redmine::CodesetUtil.replace_invalid_utf8(entry.path) %> +<% ent_name = Redmine::CodesetUtil.replace_invalid_utf8(entry.name) %> + +"> +<% if entry.is_dir? %> +  +<% end %> +<%= link_to h(ent_name), + {:action => (entry.is_dir? ? 'show' : 'changes'), :id => @project, :repository_id => @repository.identifier_param, :path => to_path_param(ent_path), :rev => @rev}, + :class => (entry.is_dir? ? 'icon icon-folder' : "icon icon-file #{Redmine::MimeType.css_class_of(ent_name)}")%> + +<%= (entry.size ? number_to_human_size(entry.size) : "?") unless entry.is_dir? %> +<% if @repository.report_last_commit %> +<%= link_to_revision(entry.changeset, @repository) if entry.changeset %> +<%= distance_of_time_in_words(entry.lastrev.time, Time.now) if entry.lastrev && entry.lastrev.time %> +<%= entry.author %> +<%=h truncate(entry.changeset.comments, :length => 50) if entry.changeset %> +<% end %> + +<% end %> diff --git a/app/views/repositories/_form.html.erb b/app/views/repositories/_form.html.erb new file mode 100644 index 00000000..1554eb56 --- /dev/null +++ b/app/views/repositories/_form.html.erb @@ -0,0 +1,27 @@ +<%= error_messages_for 'repository' %> + +
    +

    +<%= label_tag('repository_scm', l(:label_scm)) %><%= scm_select_tag(@repository) %> +<% if @repository && ! @repository.class.scm_available %> + <%= l(:text_scm_command_not_available) %> +<% end %> +

    + +

    <%= f.check_box :is_default, :label => :field_repository_is_default %>

    +

    <%= f.text_field :identifier, :disabled => @repository.identifier_frozen? %> +<% unless @repository.identifier_frozen? %> + <%= l(:text_length_between, :min => 1, :max => Repository::IDENTIFIER_MAX_LENGTH) %> <%= l(:text_repository_identifier_info).html_safe %> +<% end %>

    + +<% button_disabled = true %> +<% if @repository %> +<% button_disabled = ! @repository.class.scm_available %> +<%= repository_field_tags(f, @repository)%> +<% end %> +
    + +

    + <%= submit_tag(@repository.new_record? ? l(:button_create) : l(:button_save), :disabled => button_disabled) %> + <%= link_to l(:button_cancel), settings_project_path(@project, :tab => 'repositories') %> +

    diff --git a/app/views/repositories/_link_to_functions.html.erb b/app/views/repositories/_link_to_functions.html.erb new file mode 100644 index 00000000..f75a7ce5 --- /dev/null +++ b/app/views/repositories/_link_to_functions.html.erb @@ -0,0 +1,19 @@ +<% if @entry && @entry.kind == 'file' %> + +

    +<%= link_to_if action_name != 'changes', l(:label_history), {:action => 'changes', :id => @project, :repository_id => @repository.identifier_param, :path => to_path_param(@path), :rev => @rev } %> | +<% if @repository.supports_cat? %> + <%= link_to_if action_name != 'entry', l(:button_view), {:action => 'entry', :id => @project, :repository_id => @repository.identifier_param, :path => to_path_param(@path), :rev => @rev } %> | +<% end %> +<% if @repository.supports_annotate? %> + <%= link_to_if action_name != 'annotate', l(:button_annotate), {:action => 'annotate', :id => @project, :repository_id => @repository.identifier_param, :path => to_path_param(@path), :rev => @rev } %> | +<% end %> +<%= link_to(l(:button_download), + {:action => 'raw', :id => @project, + :repository_id => @repository.identifier_param, + :path => to_path_param(@path), + :rev => @rev}) if @repository.supports_cat? %> +<%= "(#{number_to_human_size(@entry.size)})" if @entry.size %> +

    + +<% end %> diff --git a/app/views/repositories/_navigation.html.erb b/app/views/repositories/_navigation.html.erb new file mode 100644 index 00000000..a42daa8f --- /dev/null +++ b/app/views/repositories/_navigation.html.erb @@ -0,0 +1,34 @@ +<% content_for :header_tags do %> + <%= javascript_include_tag 'repository_navigation' %> +<% end %> + +<%= link_to l(:label_statistics), + {:action => 'stats', :id => @project, :repository_id => @repository.identifier_param}, + :class => 'icon icon-stats' if @repository.supports_all_revisions? %> + +<%= form_tag({:action => controller.action_name, + :id => @project, + :repository_id => @repository.identifier_param, + :path => to_path_param(@path), + :rev => nil}, + {:method => :get, :id => 'revision_selector'}) do -%> + + <% if !@repository.branches.nil? && @repository.branches.length > 0 -%> + | <%= l(:label_branch) %>: + <%= select_tag :branch, + options_for_select([''] + @repository.branches, @rev), + :id => 'branch' %> + <% end -%> + + <% if !@repository.tags.nil? && @repository.tags.length > 0 -%> + | <%= l(:label_tag) %>: + <%= select_tag :tag, + options_for_select([''] + @repository.tags, @rev), + :id => 'tag' %> + <% end -%> + + <% if @repository.supports_all_revisions? %> + | <%= l(:label_revision) %>: + <%= text_field_tag 'rev', @rev, :size => 8 %> + <% end %> +<% end -%> diff --git a/app/views/repositories/_related_issues.html.erb b/app/views/repositories/_related_issues.html.erb new file mode 100644 index 00000000..ee814c9f --- /dev/null +++ b/app/views/repositories/_related_issues.html.erb @@ -0,0 +1,40 @@ +<% manage_allowed = User.current.allowed_to?(:manage_related_issues, @repository.project) %> + + + +<%= javascript_tag "observeAutocompleteField('issue_id', '#{escape_javascript auto_complete_issues_path(:project_id => @project, :scope => 'all')}')" %> diff --git a/app/views/repositories/_revision_graph.html.erb b/app/views/repositories/_revision_graph.html.erb new file mode 100644 index 00000000..ebda63ba --- /dev/null +++ b/app/views/repositories/_revision_graph.html.erb @@ -0,0 +1,18 @@ +<%= javascript_tag do %> +function revisionGraphHandler(){ + drawRevisionGraph( + document.getElementById('holder'), + <%= commits.to_json.html_safe %>, + <%= space %> + ); +} +$(document).ready(revisionGraphHandler); +$(window).resize(revisionGraphHandler); +<% end %> + +
    + +<% content_for :header_tags do %> + <%= javascript_include_tag 'raphael' %> + <%= javascript_include_tag 'revision_graph' %> +<% end %> diff --git a/app/views/repositories/_revisions.html.erb b/app/views/repositories/_revisions.html.erb new file mode 100644 index 00000000..844c0650 --- /dev/null +++ b/app/views/repositories/_revisions.html.erb @@ -0,0 +1,51 @@ +<% show_revision_graph = ( @repository.supports_revision_graph? && path.blank? ) %> +<%= if show_revision_graph && revisions && revisions.any? + indexed_commits, graph_space = index_commits(revisions, @repository.branches) do |scmid| + url_for( + :controller => 'repositories', + :action => 'revision', + :id => project, + :repository_id => @repository.identifier_param, + :rev => scmid) + end + render :partial => 'revision_graph', + :locals => { + :commits => indexed_commits, + :space => graph_space + } +end %> +<%= form_tag( + {:controller => 'repositories', :action => 'diff', :id => project, + :repository_id => @repository.identifier_param, :path => to_path_param(path)}, + :method => :get + ) do %> + + + + + + + + + + +<% show_diff = revisions.size > 1 %> +<% line_num = 1 %> +<% revisions.each do |changeset| %> + +<% id_style = (show_revision_graph ? "padding-left:#{(graph_space + 1) * 20}px" : nil) %> +<%= content_tag(:td, :class => 'id', :style => id_style) do %> + <%= link_to_revision(changeset, @repository) %> +<% end %> + + + + + + +<% line_num += 1 %> +<% end %> + +
    #<%= l(:label_date) %><%= l(:field_author) %><%= l(:field_comments) %>
    <%= radio_button_tag('rev', changeset.identifier, (line_num==1), :id => "cb-#{line_num}", :onclick => "$('#cbto-#{line_num+1}').attr('checked',true);") if show_diff && (line_num < revisions.size) %><%= radio_button_tag('rev_to', changeset.identifier, (line_num==2), :id => "cbto-#{line_num}", :onclick => "if ($('#cb-#{line_num}').attr('checked')) {$('#cb-#{line_num-1}').attr('checked',true);}") if show_diff && (line_num > 1) %><%= format_time(changeset.committed_on) %><%= h truncate(changeset.author.to_s, :length => 30) %><%= textilizable(truncate_at_line_break(changeset.comments)) %>
    +<%= submit_tag(l(:label_view_diff), :name => nil) if show_diff %> +<% end %> diff --git a/app/views/repositories/add_related_issue.js.erb b/app/views/repositories/add_related_issue.js.erb new file mode 100644 index 00000000..f3864d3b --- /dev/null +++ b/app/views/repositories/add_related_issue.js.erb @@ -0,0 +1,7 @@ +<% if @issue %> + $('#related-issues').html('<%= escape_javascript(render :partial => "related_issues") %>'); + $('#related-issue-<%= @issue.id %>').effect("highlight"); + $('#issue_id').focus(); +<% else %> + alert("<%= raw(escape_javascript(l(:label_issue) + ' ' + l('activerecord.errors.messages.invalid'))) %>"); +<% end %> diff --git a/app/views/repositories/annotate.html.erb b/app/views/repositories/annotate.html.erb new file mode 100644 index 00000000..7658cd17 --- /dev/null +++ b/app/views/repositories/annotate.html.erb @@ -0,0 +1,36 @@ +<%= call_hook(:view_repositories_show_contextual, { :repository => @repository, :project => @project }) %> + +
    + <%= render :partial => 'navigation' %> +
    + +

    <%= render :partial => 'breadcrumbs', :locals => { :path => @path, :kind => 'file', :revision => @rev } %>

    + +<%= render :partial => 'link_to_functions' %> + +<% colors = Hash.new {|k,v| k[v] = (k.size % 12) } %> + +
    + + + <% line_num = 1; previous_revision = nil %> + <% syntax_highlight_lines(@path, Redmine::CodesetUtil.to_utf8_by_setting(@annotate.content)).each do |line| %> + <% revision = @annotate.revisions[line_num - 1] %> + + + + + + + <% line_num += 1; previous_revision = revision %> + <% end %> + +
    <%= line_num %> + <%= (revision.identifier ? link_to_revision(revision, @repository) : format_revision(revision)) if revision && revision != previous_revision %><%= h(revision.author.to_s.split('<').first) if revision && revision != previous_revision %>
    <%= line.html_safe %>
    +
    + +<% html_title(l(:button_annotate)) -%> + +<% content_for :header_tags do %> +<%= stylesheet_link_tag 'scm' %> +<% end %> diff --git a/app/views/repositories/changes.html.erb b/app/views/repositories/changes.html.erb new file mode 100644 index 00000000..9d7c4aa3 --- /dev/null +++ b/app/views/repositories/changes.html.erb @@ -0,0 +1,20 @@ +<%= call_hook(:view_repositories_show_contextual, { :repository => @repository, :project => @project }) %> + +
    + <%= render :partial => 'navigation' %> +
    + +

    <%= render :partial => 'breadcrumbs', :locals => { :path => @path, :kind => (@entry ? @entry.kind : nil), :revision => @rev } %>

    + +<%= render :partial => 'link_to_functions' %> + +<%= render_properties(@properties) %> + +<%= render(:partial => 'revisions', + :locals => {:project => @project, :path => @path, :revisions => @changesets, :entry => @entry }) unless @changesets.empty? %> + +<% content_for :header_tags do %> +<%= stylesheet_link_tag "scm" %> +<% end %> + +<% html_title(l(:label_change_plural)) -%> diff --git a/app/views/repositories/committers.html.erb b/app/views/repositories/committers.html.erb new file mode 100644 index 00000000..ccb037e0 --- /dev/null +++ b/app/views/repositories/committers.html.erb @@ -0,0 +1,42 @@ +

    <%= l(:label_repository) %>

    + +<%= simple_format(l(:text_repository_usernames_mapping)) %> + +<% if @committers.empty? %> +

    <%= l(:label_no_data) %>

    +<% else %> + +<%= form_tag({}) do %> + + + + + + + + +<% i = 0 -%> +<% @committers.each do |committer, user_id| -%> + + + + + <% i += 1 -%> +<% end -%> + +
    <%= l(:field_login) %><%= l(:label_user) %>
    <%=h committer %> + <%= hidden_field_tag "committers[#{i}][]", committer %> + <%= select_tag "committers[#{i}][]", + content_tag( + 'option', + "-- #{l :actionview_instancetag_blank_option} --", + :value => '' + ) + + options_from_collection_for_select( + @users, 'id', 'name', user_id.to_i + ) %> +
    +

    <%= submit_tag(l(:button_update)) %>

    +<% end %> + +<% end %> diff --git a/app/views/repositories/diff.html.erb b/app/views/repositories/diff.html.erb new file mode 100644 index 00000000..9416e551 --- /dev/null +++ b/app/views/repositories/diff.html.erb @@ -0,0 +1,27 @@ +

    <%= l(:label_revision) %> <%= @diff_format_revisions %> <%=h @path %>

    + + +<%= form_tag({:action => 'diff', :id => @project, + :repository_id => @repository.identifier_param, + :path => to_path_param(@path), :rev=> @rev}, :method => 'get') do %> + <%= hidden_field_tag('rev_to', params[:rev_to]) if params[:rev_to] %> +

    + <%= l(:label_view_diff) %>: + + +

    +<% end %> + +<% cache(@cache_key) do -%> +<%= render :partial => 'common/diff', :locals => {:diff => @diff, :diff_type => @diff_type, :diff_style => @repository.class.scm_name} %> +<% end -%> + +<% other_formats_links do |f| %> + <%= f.link_to 'Diff', :url => params, :caption => 'Unified diff' %> +<% end %> + +<% html_title(with_leading_slash(@path), 'Diff') -%> + +<% content_for :header_tags do %> +<%= stylesheet_link_tag "scm" %> +<% end %> diff --git a/app/views/repositories/edit.html.erb b/app/views/repositories/edit.html.erb new file mode 100644 index 00000000..f0eafcf3 --- /dev/null +++ b/app/views/repositories/edit.html.erb @@ -0,0 +1,5 @@ +

    <%= l(:label_repository) %>

    + +<%= labelled_form_for :repository, @repository, :url => repository_path(@repository), :html => {:method => :put, :id => 'repository-form'} do |f| %> + <%= render :partial => 'form', :locals => {:f => f} %> +<% end %> diff --git a/app/views/repositories/entry.html.erb b/app/views/repositories/entry.html.erb new file mode 100644 index 00000000..5aea99dc --- /dev/null +++ b/app/views/repositories/entry.html.erb @@ -0,0 +1,15 @@ +<%= call_hook(:view_repositories_show_contextual, { :repository => @repository, :project => @project }) %> + +
    + <%= render :partial => 'navigation' %> +
    + +

    <%= render :partial => 'breadcrumbs', :locals => { :path => @path, :kind => 'file', :revision => @rev } %>

    + +<%= render :partial => 'link_to_functions' %> + +<%= render :partial => 'common/file', :locals => {:filename => @path, :content => @content} %> + +<% content_for :header_tags do %> +<%= stylesheet_link_tag "scm" %> +<% end %> diff --git a/app/views/repositories/new.html.erb b/app/views/repositories/new.html.erb new file mode 100644 index 00000000..fae1e3b9 --- /dev/null +++ b/app/views/repositories/new.html.erb @@ -0,0 +1,5 @@ +

    <%= l(:label_repository_new) %>

    + +<%= labelled_form_for :repository, @repository, :url => project_repositories_path(@project), :html => {:id => 'repository-form'} do |f| %> + <%= render :partial => 'form', :locals => {:f => f} %> +<% end %> diff --git a/app/views/repositories/new.js.erb b/app/views/repositories/new.js.erb new file mode 100644 index 00000000..00fd9cf8 --- /dev/null +++ b/app/views/repositories/new.js.erb @@ -0,0 +1 @@ +$('#content').html('<%= escape_javascript(render :template => 'repositories/new', :formats => [:html]) %>'); diff --git a/app/views/repositories/remove_related_issue.js.erb b/app/views/repositories/remove_related_issue.js.erb new file mode 100644 index 00000000..c4dc0e97 --- /dev/null +++ b/app/views/repositories/remove_related_issue.js.erb @@ -0,0 +1 @@ +$('#related-issue-<%= @issue.id %>').remove(); diff --git a/app/views/repositories/revision.html.erb b/app/views/repositories/revision.html.erb new file mode 100644 index 00000000..0de0cfee --- /dev/null +++ b/app/views/repositories/revision.html.erb @@ -0,0 +1,97 @@ +
    + « + <% unless @changeset.previous.nil? -%> + <%= link_to_revision(@changeset.previous, @repository, :text => l(:label_previous)) %> + <% else -%> + <%= l(:label_previous) %> + <% end -%> +| + <% unless @changeset.next.nil? -%> + <%= link_to_revision(@changeset.next, @repository, :text => l(:label_next)) %> + <% else -%> + <%= l(:label_next) %> + <% end -%> + »  + + <%= form_tag({:controller => 'repositories', + :action => 'revision', + :id => @project, + :repository_id => @repository.identifier_param, + :rev => nil}, + :method => :get) do %> + <%= text_field_tag 'rev', @rev, :size => 8 %> + <%= submit_tag 'OK', :name => nil %> + <% end %> +
    + +

    <%= avatar(@changeset.user, :size => "24") %><%= l(:label_revision) %> <%= format_revision(@changeset) %>

    + +<% if @changeset.scmid.present? || @changeset.parents.present? || @changeset.children.present? %> + + <% if @changeset.scmid.present? %> + + + + <% end %> + <% if @changeset.parents.present? %> + + + + + <% end %> + <% if @changeset.children.present? %> + + + + + <% end %> +
    ID<%= h(@changeset.scmid) %>
    <%= l(:label_parent_revision) %> + <%= @changeset.parents.collect{ + |p| link_to_revision(p, @repository, :text => format_revision(p)) + }.join(", ").html_safe %> +
    <%= l(:label_child_revision) %> + <%= @changeset.children.collect{ + |p| link_to_revision(p, @repository, :text => format_revision(p)) + }.join(", ").html_safe %> +
    +<% end %> + +

    + +<%= authoring(@changeset.committed_on, @changeset.author) %> + +

    + +<%= textilizable @changeset.comments %> + +<% if @changeset.issues.visible.any? || User.current.allowed_to?(:manage_related_issues, @repository.project) %> + <%= render :partial => 'related_issues' %> +<% end %> + +<% if User.current.allowed_to?(:browse_repository, @project) %> +

    <%= l(:label_attachment_plural) %>

    +
      +
    • <%= l(:label_added) %>
    • +
    • <%= l(:label_modified) %>
    • +
    • <%= l(:label_copied) %>
    • +
    • <%= l(:label_renamed) %>
    • +
    • <%= l(:label_deleted) %>
    • +
    + +

    <%= link_to(l(:label_view_diff), + :action => 'diff', + :id => @project, + :repository_id => @repository.identifier_param, + :path => "", + :rev => @changeset.identifier) if @changeset.filechanges.any? %>

    + +
    +<%= render_changeset_changes %> +
    +<% end %> + +<% content_for :header_tags do %> +<%= stylesheet_link_tag "scm" %> +<% end %> + +<% html_title("#{l(:label_revision)} #{format_revision(@changeset)}") -%> diff --git a/app/views/repositories/revisions.html.erb b/app/views/repositories/revisions.html.erb new file mode 100644 index 00000000..7a733809 --- /dev/null +++ b/app/views/repositories/revisions.html.erb @@ -0,0 +1,34 @@ +
    +<%= form_tag( + {:controller => 'repositories', :action => 'revision', :id => @project, + :repository_id => @repository.identifier_param}, + :method => :get + ) do %> + <%= l(:label_revision) %>: <%= text_field_tag 'rev', nil, :size => 8 %> + <%= submit_tag 'OK' %> +<% end %> +
    + +

    <%= l(:label_revision_plural) %>

    + +<%= render :partial => 'revisions', + :locals => {:project => @project, + :path => '', + :revisions => @changesets, + :entry => nil } %> + +

    <%= pagination_links_full @changeset_pages,@changeset_count %>

    + +<% content_for :header_tags do %> + <%= stylesheet_link_tag "scm" %> + <%= auto_discovery_link_tag( + :atom, + params.merge( + {:format => 'atom', :page => nil, :key => User.current.rss_key})) %> +<% end %> + +<% other_formats_links do |f| %> + <%= f.link_to 'Atom', :url => {:key => User.current.rss_key} %> +<% end %> + +<% html_title(l(:label_revision_plural)) -%> diff --git a/app/views/repositories/show.html.erb b/app/views/repositories/show.html.erb new file mode 100644 index 00000000..35e6dadc --- /dev/null +++ b/app/views/repositories/show.html.erb @@ -0,0 +1,77 @@ +<%= call_hook(:view_repositories_show_contextual, { :repository => @repository, :project => @project }) %> + +
    + <%= render :partial => 'navigation' %> +
    + +

    <%= render :partial => 'breadcrumbs', + :locals => { :path => @path, :kind => 'dir', :revision => @rev } %>

    + +<% if !@entries.nil? && authorize_for('repositories', 'browse') %> + <%= render :partial => 'dir_list' %> +<% end %> + +<%= render_properties(@properties) %> + +<% if authorize_for('repositories', 'revisions') %> + <% if @changesets && !@changesets.empty? %> +

    <%= l(:label_latest_revision_plural) %>

    + <%= render :partial => 'revisions', + :locals => {:project => @project, :path => @path, + :revisions => @changesets, :entry => nil }%> + <% end %> +

    + <% has_branches = (!@repository.branches.nil? && @repository.branches.length > 0) + sep = '' %> + <% if @repository.supports_all_revisions? && @path.blank? %> + <%= link_to l(:label_view_all_revisions), :action => 'revisions', :id => @project, + :repository_id => @repository.identifier_param %> + <% sep = '|' %> + <% end %> + <% if @repository.supports_directory_revisions? && + ( has_branches || !@path.blank? || !@rev.blank? ) %> + <%= sep %> + <%= link_to l(:label_view_revisions), + :action => 'changes', + :path => to_path_param(@path), + :id => @project, + :repository_id => @repository.identifier_param, + :rev => @rev %> + <% end %> +

    + <% if @repository.supports_all_revisions? %> + <% content_for :header_tags do %> + <%= auto_discovery_link_tag( + :atom, params.merge( + {:format => 'atom', :action => 'revisions', + :id => @project, :page => nil, :key => User.current.rss_key})) %> + <% end %> + + <% other_formats_links do |f| %> + <%= f.link_to 'Atom', + :url => {:action => 'revisions', :id => @project, + :repository_id => @repository.identifier_param, + :key => User.current.rss_key} %> + <% end %> + <% end %> +<% end %> + +<% if @repositories.size > 1 %> + <% content_for :sidebar do %> +

    <%= l(:label_repository_plural) %>

    +

    + <%= @repositories.sort.collect {|repo| + link_to h(repo.name), + {:controller => 'repositories', :action => 'show', + :id => @project, :repository_id => repo.identifier_param, :rev => nil, :path => nil}, + :class => 'repository' + (repo == @repository ? ' selected' : '') + }.join('
    ').html_safe %> +

    + <% end %> +<% end %> + +<% content_for :header_tags do %> + <%= stylesheet_link_tag "scm" %> +<% end %> + +<% html_title(l(:label_repository)) -%> diff --git a/app/views/repositories/stats.html.erb b/app/views/repositories/stats.html.erb new file mode 100644 index 00000000..50648f66 --- /dev/null +++ b/app/views/repositories/stats.html.erb @@ -0,0 +1,12 @@ +

    <%= l(:label_statistics) %>

    + +

    +<%= tag("embed", :width => 670, :height => 300, :type => "image/svg+xml", :src => url_for(:controller => 'repositories', :action => 'graph', :id => @project, :repository_id => @repository.identifier_param, :graph => "commits_per_month")) %> +

    +

    +<%= tag("embed", :width => 670, :height => 400, :type => "image/svg+xml", :src => url_for(:controller => 'repositories', :action => 'graph', :id => @project, :repository_id => @repository.identifier_param, :graph => "commits_per_author")) %> +

    + +

    <%= link_to l(:button_back), :action => 'show', :id => @project %>

    + +<% html_title(l(:label_repository), l(:label_statistics)) -%> diff --git a/app/views/roles/_form.html.erb b/app/views/roles/_form.html.erb new file mode 100644 index 00000000..d028c2f1 --- /dev/null +++ b/app/views/roles/_form.html.erb @@ -0,0 +1,32 @@ +<%= error_messages_for 'role' %> + +<% unless @role.anonymous? %> +
    +<% unless @role.builtin? %> +

    <%= f.text_field :name, :required => true %>

    +

    <%= f.check_box :assignable %>

    +<% end %> +

    <%= f.select :issues_visibility, Role::ISSUES_VISIBILITY_OPTIONS.collect {|v| [l(v.last), v.first]} %>

    +<% if @role.new_record? && @roles.any? %> +

    +<%= select_tag(:copy_workflow_from, content_tag("option") + options_from_collection_for_select(@roles, :id, :name, params[:copy_workflow_from] || @copy_from.try(:id))) %>

    +<% end %> +
    +<% end %> + +

    <%= l(:label_permissions) %>

    +
    +<% perms_by_module = @role.setable_permissions.group_by {|p| p.project_module.to_s} %> +<% perms_by_module.keys.sort.each do |mod| %> +
    <%= mod.blank? ? l(:label_project) : l_or_humanize(mod, :prefix => 'project_module_') %> + <% perms_by_module[mod].each do |permission| %> + + <% end %> +
    +<% end %> +
    <%= check_all_links 'permissions' %> +<%= hidden_field_tag 'role[permissions][]', '' %> +
    diff --git a/app/views/roles/edit.html.erb b/app/views/roles/edit.html.erb new file mode 100644 index 00000000..a932a169 --- /dev/null +++ b/app/views/roles/edit.html.erb @@ -0,0 +1,6 @@ +

    <%= link_to l(:label_role_plural), roles_path %> » <%=h @role.name %>

    + +<%= labelled_form_for @role do |f| %> +<%= render :partial => 'form', :locals => { :f => f } %> +<%= submit_tag l(:button_save) %> +<% end %> diff --git a/app/views/roles/index.api.rsb b/app/views/roles/index.api.rsb new file mode 100644 index 00000000..56adc767 --- /dev/null +++ b/app/views/roles/index.api.rsb @@ -0,0 +1,8 @@ +api.array :roles do + @roles.each do |role| + api.role do + api.id role.id + api.name role.name + end + end +end diff --git a/app/views/roles/index.html.erb b/app/views/roles/index.html.erb new file mode 100644 index 00000000..6b35200c --- /dev/null +++ b/app/views/roles/index.html.erb @@ -0,0 +1,34 @@ +
    +<%= link_to l(:label_role_new), new_role_path, :class => 'icon icon-add' %> +<%= link_to l(:label_permissions_report), permissions_roles_path, :class => 'icon icon-summary' %> +
    + +

    <%=l(:label_role_plural)%>

    + + + + + + + + +<% for role in @roles %> + "> + + + + +<% end %> + +
    <%=l(:label_role)%><%=l(:button_sort)%>
    <%= content_tag(role.builtin? ? 'em' : 'span', link_to(h(role.name), edit_role_path(role))) %> + <% unless role.builtin? %> + <%= reorder_links('role', {:action => 'update', :id => role}, :put) %> + <% end %> + + <%= link_to l(:button_copy), new_role_path(:copy => role), :class => 'icon icon-copy' %> + <%= delete_link role_path(role) unless role.builtin? %> +
    + +

    <%= pagination_links_full @role_pages %>

    + +<% html_title(l(:label_role_plural)) -%> diff --git a/app/views/roles/new.html.erb b/app/views/roles/new.html.erb new file mode 100644 index 00000000..d597bc09 --- /dev/null +++ b/app/views/roles/new.html.erb @@ -0,0 +1,6 @@ +

    <%= link_to l(:label_role_plural), roles_path %> » <%=l(:label_role_new)%>

    + +<%= labelled_form_for @role do |f| %> +<%= render :partial => 'form', :locals => { :f => f } %> +<%= submit_tag l(:button_create) %> +<% end %> diff --git a/app/views/roles/permissions.html.erb b/app/views/roles/permissions.html.erb new file mode 100644 index 00000000..1942092c --- /dev/null +++ b/app/views/roles/permissions.html.erb @@ -0,0 +1,55 @@ +

    <%= link_to l(:label_role_plural), roles_path %> » <%=l(:label_permissions_report)%>

    + +<%= form_tag(permissions_roles_path, :id => 'permissions_form') do %> +<%= hidden_field_tag 'permissions[0]', '', :id => nil %> +
    + + + + + <% @roles.each do |role| %> + + <% end %> + + + +<% perms_by_module = @permissions.group_by {|p| p.project_module.to_s} %> +<% perms_by_module.keys.sort.each do |mod| %> + <% unless mod.blank? %> + + + <% @roles.each do |role| %> + + <% end %> + + <% end %> + <% perms_by_module[mod].each do |permission| %> + + + <% @roles.each do |role| %> + + <% end %> + + <% end %> +<% end %> + +
    <%=l(:label_permissions)%> + <%= content_tag(role.builtin? ? 'em' : 'span', h(role.name)) %> + <%= link_to_function(image_tag('toggle_check.png'), "toggleCheckboxesBySelector('input.role-#{role.id}')", + :title => "#{l(:button_check_all)}/#{l(:button_uncheck_all)}") %> +
    +   + <%= l_or_humanize(mod, :prefix => 'project_module_') %> + <%= h(role.name) %>
    + <%= link_to_function(image_tag('toggle_check.png'), "toggleCheckboxesBySelector('.permission-#{permission.name} input')", + :title => "#{l(:button_check_all)}/#{l(:button_uncheck_all)}") %> + <%= l_or_humanize(permission.name, :prefix => 'permission_') %> + + <% if role.setable_permissions.include? permission %> + <%= check_box_tag "permissions[#{role.id}][]", permission.name, (role.permissions.include? permission.name), :id => nil, :class => "role-#{role.id}" %> + <% end %> +
    +
    +

    <%= check_all_links 'permissions_form' %>

    +

    <%= submit_tag l(:button_save) %>

    +<% end %> diff --git a/app/views/roles/show.api.rsb b/app/views/roles/show.api.rsb new file mode 100644 index 00000000..4e81819c --- /dev/null +++ b/app/views/roles/show.api.rsb @@ -0,0 +1,9 @@ +api.role do + api.id @role.id + api.name @role.name + api.array :permissions do + @role.permissions.each do |perm| + api.permission(perm.to_s) + end + end +end diff --git a/app/views/search/index.html.erb b/app/views/search/index.html.erb new file mode 100644 index 00000000..936735a7 --- /dev/null +++ b/app/views/search/index.html.erb @@ -0,0 +1,52 @@ +

    <%= l(:label_search) %>

    + +
    +<%= form_tag({}, :method => :get) do %> +<%= label_tag "search-input", l(:description_search), :class => "hidden-for-sighted" %> +

    <%= text_field_tag 'q', @question, :size => 60, :id => 'search-input' %> +<%= javascript_tag "$('#search-input').focus()" %> +<%= project_select_tag %> +<%= hidden_field_tag 'all_words', '', :id => nil %> + +<%= hidden_field_tag 'titles_only', '', :id => nil %> + +

    +

    +<% @object_types.each do |t| %> + +<% end %> +

    + +

    <%= submit_tag l(:button_submit), :name => 'submit' %>

    +<% end %> +
    + +<% if @results %> +
    + <%= render_results_by_type(@results_by_type) unless @scope.size == 1 %> +
    + +

    <%= l(:label_result_plural) %> (<%= @results_by_type.values.sum %>)

    +
    + <% @results.each do |e| %> +
    <%= content_tag('span', h(e.project), :class => 'project') unless @project == e.project %> <%= link_to highlight_tokens(truncate(e.event_title, :length => 255), @tokens), e.event_url %>
    +
    <%= highlight_tokens(e.event_description, @tokens) %> + <%= format_time(e.event_datetime) %>
    + <% end %> +
    +<% end %> + +

    +<% if @pagination_previous_date %> +<%= link_to_content_update("\xc2\xab " + l(:label_previous), + params.merge(:previous => 1, + :offset => @pagination_previous_date.strftime("%Y%m%d%H%M%S"))) %>  +<% end %> +<% if @pagination_next_date %> +<%= link_to_content_update(l(:label_next) + " \xc2\xbb", + params.merge(:previous => nil, + :offset => @pagination_next_date.strftime("%Y%m%d%H%M%S"))) %> +<% end %> +

    + +<% html_title(l(:label_search)) -%> diff --git a/app/views/settings/_authentication.html.erb b/app/views/settings/_authentication.html.erb new file mode 100644 index 00000000..d190fab6 --- /dev/null +++ b/app/views/settings/_authentication.html.erb @@ -0,0 +1,38 @@ +<%= form_tag({:action => 'edit', :tab => 'authentication'}) do %> + +
    +

    <%= setting_check_box :login_required %>

    + +

    <%= setting_select :autologin, [[l(:label_disabled), 0]] + [1, 7, 30, 365].collect{|days| [l('datetime.distance_in_words.x_days', :count => days), days.to_s]} %>

    + +

    <%= setting_select :self_registration, [[l(:label_disabled), "0"], + [l(:label_registration_activation_by_email), "1"], + [l(:label_registration_manual_activation), "2"], + [l(:label_registration_automatic_activation), "3"]] %>

    + +

    <%= setting_check_box :unsubscribe %>

    + +

    <%= setting_text_field :password_min_length, :size => 6 %>

    + +

    <%= setting_check_box :lost_password, :label => :label_password_lost %>

    + +

    <%= setting_check_box :openid, :disabled => !Object.const_defined?(:OpenID) %>

    + +

    <%= setting_check_box :rest_api_enabled %>

    + +

    <%= setting_check_box :jsonp_enabled %>

    +
    + +
    + <%= l(:label_session_expiration) %> + +
    +

    <%= setting_select :session_lifetime, [[l(:label_disabled), 0]] + [1, 7, 30, 60, 365].collect{|days| [l('datetime.distance_in_words.x_days', :count => days), (days * 60 * 24).to_s]} %>

    +

    <%= setting_select :session_timeout, [[l(:label_disabled), 0]] + [1, 2, 4, 8, 12, 24, 48].collect{|hours| [l('datetime.distance_in_words.x_hours', :count => hours), (hours * 60).to_s]} %>

    +
    + +

    <%= l(:text_session_expiration_settings) %>

    +
    + +<%= submit_tag l(:button_save) %> +<% end %> diff --git a/app/views/settings/_display.html.erb b/app/views/settings/_display.html.erb new file mode 100644 index 00000000..1ae5a351 --- /dev/null +++ b/app/views/settings/_display.html.erb @@ -0,0 +1,26 @@ +<%= form_tag({:action => 'edit', :tab => 'display'}) do %> + +
    +

    <%= setting_select :ui_theme, Redmine::Themes.themes.collect {|t| [t.name, t.id]}, :blank => :label_default, :label => :label_theme %>

    + +

    <%= setting_select :default_language, lang_options_for_select(false) %>

    + +

    <%= setting_select :start_of_week, [[day_name(1),'1'], [day_name(6),'6'], [day_name(7),'7']], :blank => :label_language_based %>

    +<% locale = User.current.language.blank? ? ::I18n.locale : User.current.language %> +

    <%= setting_select :date_format, Setting::DATE_FORMATS.collect {|f| [::I18n.l(Date.today, :locale => locale, :format => f), f]}, :blank => :label_language_based %>

    + +

    <%= setting_select :time_format, Setting::TIME_FORMATS.collect {|f| [::I18n.l(Time.now, :locale => locale, :format => f), f]}, :blank => :label_language_based %>

    + +

    <%= setting_select :user_format, @options[:user_format] %>

    + +

    <%= setting_check_box :gravatar_enabled %>

    + +

    <%= setting_select :gravatar_default, [["Wavatars", 'wavatar'], ["Identicons", 'identicon'], ["Monster ids", 'monsterid'], ["Retro", 'retro'], ["Mystery man", 'mm']], :blank => :label_none %>

    + +

    <%= setting_check_box :thumbnails_enabled %>

    + +

    <%= setting_text_field :thumbnails_size, :size => 6 %>

    +
    + +<%= submit_tag l(:button_save) %> +<% end %> diff --git a/app/views/settings/_general.html.erb b/app/views/settings/_general.html.erb new file mode 100644 index 00000000..4ec01995 --- /dev/null +++ b/app/views/settings/_general.html.erb @@ -0,0 +1,40 @@ +<%= form_tag({:action => 'edit'}) do %> + +
    +

    <%= setting_text_field :app_title, :size => 30 %>

    + +

    <%= setting_text_area :welcome_text, :cols => 60, :rows => 5, :class => 'wiki-edit' %>

    +<%= wikitoolbar_for 'settings_welcome_text' %> + +

    <%= setting_text_field :attachment_max_size, :size => 6 %> <%= l(:"number.human.storage_units.units.kb") %>

    + +

    <%= setting_text_field :per_page_options, :size => 20 %> +<%= l(:text_comma_separated) %>

    + +

    <%= setting_text_field :activity_days_default, :size => 6 %> <%= l(:label_day_plural) %>

    + +

    <%= setting_text_field :host_name, :size => 60 %> +<%= l(:label_example) %>: <%= @guessed_host_and_path %>

    + +

    <%= setting_select :protocol, [['HTTP', 'http'], ['HTTPS', 'https']] %>

    + +

    <%= setting_select :text_formatting, Redmine::WikiFormatting.format_names.collect{|name| [name, name.to_s]}, :blank => :label_none %>

    + +

    <%= setting_check_box :cache_formatted_text %>

    + +

    <%= setting_select :wiki_compression, [['Gzip', 'gzip']], :blank => :label_none %>

    + +

    <%= setting_text_field :feeds_limit, :size => 6 %>

    + +

    <%= setting_text_field :file_max_size_displayed, :size => 6 %> <%= l(:"number.human.storage_units.units.kb") %>

    + +

    <%= setting_text_field :diff_max_lines_displayed, :size => 6 %>

    + +

    <%= setting_text_field :repositories_encodings, :size => 60 %> +<%= l(:text_comma_separated) %>

    + +<%= call_hook(:view_settings_general_form) %> +
    + +<%= submit_tag l(:button_save) %> +<% end %> diff --git a/app/views/settings/_issues.html.erb b/app/views/settings/_issues.html.erb new file mode 100644 index 00000000..2efc6e8c --- /dev/null +++ b/app/views/settings/_issues.html.erb @@ -0,0 +1,31 @@ +<%= form_tag({:action => 'edit', :tab => 'issues'}, :onsubmit => 'selectAllOptions("selected_columns");') do %> + +
    +

    <%= setting_check_box :cross_project_issue_relations %>

    + +

    <%= setting_select :cross_project_subtasks, cross_project_subtasks_options %>

    + +

    <%= setting_check_box :issue_group_assignment %>

    + +

    <%= setting_check_box :default_issue_start_date_to_creation_date %>

    + +

    <%= setting_check_box :display_subprojects_issues %>

    + +

    <%= setting_select :issue_done_ratio, Issue::DONE_RATIO_OPTIONS.collect {|i| [l("setting_issue_done_ratio_#{i}"), i]} %>

    + +

    <%= setting_multiselect :non_working_week_days, (1..7).map {|d| [day_name(d), d.to_s]}, :inline => true %>

    + +

    <%= setting_text_field :issues_export_limit, :size => 6 %>

    + +

    <%= setting_text_field :gantt_items_limit, :size => 6 %>

    +
    + +
    + <%= l(:setting_issue_list_default_columns) %> + <%= render_query_columns_selection( + IssueQuery.new(:column_names => Setting.issue_list_default_columns), + :name => 'settings[issue_list_default_columns]') %> +
    + +<%= submit_tag l(:button_save) %> +<% end %> diff --git a/app/views/settings/_mail_handler.html.erb b/app/views/settings/_mail_handler.html.erb new file mode 100644 index 00000000..1051436b --- /dev/null +++ b/app/views/settings/_mail_handler.html.erb @@ -0,0 +1,23 @@ +<%= form_tag({:action => 'edit', :tab => 'mail_handler'}) do %> + +
    +

    + <%= setting_text_area :mail_handler_body_delimiters, :rows => 5 %> + <%= l(:text_line_separated) %> +

    +
    + +
    +

    <%= setting_check_box :mail_handler_api_enabled, + :onclick => "if (this.checked) { $('#settings_mail_handler_api_key').removeAttr('disabled'); } else { $('#settings_mail_handler_api_key').attr('disabled', true); }"%>

    + +

    <%= setting_text_field :mail_handler_api_key, :size => 30, + :id => 'settings_mail_handler_api_key', + :disabled => !Setting.mail_handler_api_enabled? %> + <%= link_to_function l(:label_generate_key), "if (!$('#settings_mail_handler_api_key').attr('disabled')) { $('#settings_mail_handler_api_key').val(randomKey(20)) }" %> +

    +
    + +<%= submit_tag l(:button_save) %> + +<% end %> diff --git a/app/views/settings/_notifications.html.erb b/app/views/settings/_notifications.html.erb new file mode 100644 index 00000000..f746f7ce --- /dev/null +++ b/app/views/settings/_notifications.html.erb @@ -0,0 +1,42 @@ +<% if @deliveries %> +<%= form_tag({:action => 'edit', :tab => 'notifications'}) do %> + +
    +

    <%= setting_text_field :mail_from, :size => 60 %>

    + +

    <%= setting_check_box :bcc_recipients %>

    + +

    <%= setting_check_box :plain_text_mail %>

    + +

    <%= setting_select(:default_notification_option, User.valid_notification_options.collect {|o| [l(o.last), o.first.to_s]}) %>

    + +
    + +
    <%=l(:text_select_mail_notifications)%> +<%= hidden_field_tag 'settings[notified_events][]', '' %> +<% @notifiables.each do |notifiable| %> +<%= notification_field notifiable %> +
    +<% end %> +

    <%= check_all_links('notified_events') %>

    +
    + +
    <%= l(:setting_emails_header) %> +<%= setting_text_area :emails_header, :label => false, :class => 'wiki-edit', :rows => 5 %> +
    + +
    <%= l(:setting_emails_footer) %> +<%= setting_text_area :emails_footer, :label => false, :class => 'wiki-edit', :rows => 5 %> +
    + +
    +<%= link_to l(:label_send_test_email), :controller => 'admin', :action => 'test_email' %> +
    + +<%= submit_tag l(:button_save) %> +<% end %> +<% else %> +
    +<%= simple_format(l(:text_email_delivery_not_configured)) %> +
    +<% end %> diff --git a/app/views/settings/_projects.html.erb b/app/views/settings/_projects.html.erb new file mode 100644 index 00000000..28fd9b57 --- /dev/null +++ b/app/views/settings/_projects.html.erb @@ -0,0 +1,20 @@ +<%= form_tag({:action => 'edit', :tab => 'projects'}) do %> + +
    +

    <%= setting_check_box :default_projects_public %>

    + +

    <%= setting_multiselect(:default_projects_modules, + Redmine::AccessControl.available_project_modules.collect {|m| [l_or_humanize(m, :prefix => "project_module_"), m.to_s]}) %>

    + +

    <%= setting_multiselect(:default_projects_tracker_ids, + Tracker.sorted.all.collect {|t| [t.name, t.id.to_s]}) %>

    + +

    <%= setting_check_box :sequential_project_identifiers %>

    + +

    <%= setting_select :new_project_user_role_id, + Role.find_all_givable.collect {|r| [r.name, r.id.to_s]}, + :blank => "--- #{l(:actionview_instancetag_blank_option)} ---" %>

    +
    + +<%= submit_tag l(:button_save) %> +<% end %> diff --git a/app/views/settings/_repositories.html.erb b/app/views/settings/_repositories.html.erb new file mode 100644 index 00000000..5c8ba243 --- /dev/null +++ b/app/views/settings/_repositories.html.erb @@ -0,0 +1,94 @@ +<%= form_tag({:action => 'edit', :tab => 'repositories'}) do %> + +
    +<%= l(:setting_enabled_scm) %> +<%= hidden_field_tag 'settings[enabled_scm][]', '' %> + + + + + + + <% Redmine::Scm::Base.all.collect do |choice| %> + <% scm_class = "Repository::#{choice}".constantize %> + <% text, value = (choice.is_a?(Array) ? choice : [choice, choice]) %> + <% setting = :enabled_scm %> + <% enabled = Setting.send(setting).include?(value) %> + + + + + + <% end %> +
    <%= l(:text_scm_command) %><%= l(:text_scm_command_version) %>
    + + + <% if enabled %> + <%= + image_tag( + (scm_class.scm_available ? 'true.png' : 'exclamation.png'), + :style => "vertical-align:bottom;" + ) + %> + <%= scm_class.scm_command %> + <% end %> + + <%= scm_class.scm_version_string if enabled %> +
    +

    <%= l(:text_scm_config) %>

    +
    + +
    +

    <%= setting_check_box :autofetch_changesets %>

    + +

    <%= setting_check_box :sys_api_enabled, + :onclick => + "if (this.checked) { $('#settings_sys_api_key').removeAttr('disabled'); } else { $('#settings_sys_api_key').attr('disabled', true); }" %>

    + +

    <%= setting_text_field :sys_api_key, + :size => 30, + :id => 'settings_sys_api_key', + :disabled => !Setting.sys_api_enabled?, + :label => :setting_mail_handler_api_key %> + <%= link_to_function l(:label_generate_key), + "if (!$('#settings_sys_api_key').attr('disabled')) { $('#settings_sys_api_key').val(randomKey(20)) }" %> +

    + +

    <%= setting_text_field :repository_log_display_limit, :size => 6 %>

    +
    + +
    +<%= l(:text_issues_ref_in_commit_messages) %> +

    <%= setting_text_field :commit_ref_keywords, :size => 30 %> +<%= l(:text_comma_separated) %>

    + +

    <%= setting_text_field :commit_fix_keywords, :size => 30 %> + <%= l(:label_applied_status) %>: <%= setting_select :commit_fix_status_id, + [["", 0]] + + IssueStatus.sorted.all.collect{ + |status| [status.name, status.id.to_s] + }, + :label => false %> + <%= l(:field_done_ratio) %>: <%= setting_select :commit_fix_done_ratio, + (0..10).to_a.collect {|r| ["#{r*10} %", "#{r*10}"] }, + :blank => :label_no_change_option, + :label => false %> +<%= l(:text_comma_separated) %>

    + +

    <%= setting_check_box :commit_cross_project_ref %>

    + +

    <%= setting_check_box :commit_logtime_enabled, + :onclick => + "if (this.checked) { $('#settings_commit_logtime_activity_id').removeAttr('disabled'); } else { $('#settings_commit_logtime_activity_id').attr('disabled', true); }"%>

    + +

    <%= setting_select :commit_logtime_activity_id, + [[l(:label_default), 0]] + + TimeEntryActivity.shared.active.collect{|activity| [activity.name, activity.id.to_s]}, + :disabled => !Setting.commit_logtime_enabled?%>

    +
    + +<%= submit_tag l(:button_save) %> +<% end %> diff --git a/app/views/settings/edit.html.erb b/app/views/settings/edit.html.erb new file mode 100644 index 00000000..8de53f55 --- /dev/null +++ b/app/views/settings/edit.html.erb @@ -0,0 +1,5 @@ +

    <%= l(:label_settings) %>

    + +<%= render_tabs administration_settings_tabs %> + +<% html_title(l(:label_settings), l(:label_administration)) -%> diff --git a/app/views/settings/plugin.html.erb b/app/views/settings/plugin.html.erb new file mode 100644 index 00000000..46c4678a --- /dev/null +++ b/app/views/settings/plugin.html.erb @@ -0,0 +1,10 @@ +

    <%= l(:label_settings) %>: <%=h @plugin.name %>

    + +
    +<%= form_tag({:action => 'plugin'}) do %> +
    +<%= render :partial => @partial, :locals => {:settings => @settings}%> +
    +<%= submit_tag l(:button_apply) %> +<% end %> +
    diff --git a/app/views/tags/_related_tags.html.erb b/app/views/tags/_related_tags.html.erb new file mode 100644 index 00000000..08c588a1 --- /dev/null +++ b/app/views/tags/_related_tags.html.erb @@ -0,0 +1,14 @@ +<% if related_tags %> +
      + <% for rt in related_tags %> +
    • + <%= link_to image_tag("/images/add.png"),:action => "add_tag",:remote => true,:tag => rt %> + <%= rt %> + <% @issue_size = Issue.tagged_with("#{rt}").size %> + <% @project_size = Project.tagged_with(rt).size %> + <% @user_size = User.tagged_with("#{rt}").size %> + (<%= @user_size + @project_size + @issue_size %>) +
    • + <% end %> +
    +<% end %> diff --git a/app/views/tags/_selected_tags.html.erb b/app/views/tags/_selected_tags.html.erb new file mode 100644 index 00000000..0eacecd3 --- /dev/null +++ b/app/views/tags/_selected_tags.html.erb @@ -0,0 +1,15 @@ +<% if selected_tags %> +
      + <% for sg in selected_tags %> +
    • + <%= link_to image_tag("/images/delete.png"),:action => "delete_tag",:remote=>true,:tag => sg %> + <%= sg %> + <% @issue_size = Issue.tagged_with("#{sg}").size %> + <% @project_size = Project.tagged_with(sg).size %> + <% @user_size = User.tagged_with("#{sg}").size %> + (<%= @user_size + @project_size + @issue_size %>) +
    • + <% end %> +
    +<% end %> + diff --git a/app/views/tags/_show_results.html.erb b/app/views/tags/_show_results.html.erb new file mode 100644 index 00000000..e69de29b diff --git a/app/views/tags/_tag_search_results.html.erb b/app/views/tags/_tag_search_results.html.erb new file mode 100644 index 00000000..7fba1397 --- /dev/null +++ b/app/views/tags/_tag_search_results.html.erb @@ -0,0 +1,37 @@ +
      + <% if issues_results.size > 0 %> +
      +

      Issues:

      + <% issues_results.each do |issue| %> +
    • + 问题:<%= link_to "#{issue.subject}",:controller => "issues",:action => "show",:id => issue.id %> +
    • + <% end %> + <% end %> + + <% if users_results.size > 0 %> +
      +

      Users:

      + <% users_results.each do |user| %> +
    • + 用户名:<%= link_to ("#{user.firstname+user.lastname}"), + :controller => "users",:action => "show",:id => user.id %> +
      + 用户邮箱:<%= mail_to(h(user.mail)) %> +
    • + <% end %> + <% end %> + + <% if projects_results.size > 0 %> +
      +

      Projects:

      + <% projects_results.each do |project| %> +
    • + 项目名称:<%= link_to project.name,:controller => "projects",:action => "show",:id => project.id %> +
      + 项目描述:<%= project.description %>; + +
    • + <% end %> + <% end %> +
    \ No newline at end of file diff --git a/app/views/tags/add_tag.js.erb b/app/views/tags/add_tag.js.erb new file mode 100644 index 00000000..610fb12c --- /dev/null +++ b/app/views/tags/add_tag.js.erb @@ -0,0 +1,9 @@ +$('#selected_tags').html('<%= j(render :partial => "selected_tags", +:locals => {:selected_tags => $selected_tags })%>'); +$('#related_tags').html('<%= j(render :partial => "related_tags", + :locals => {:related_tags => $related_tags })%>') + +$('#show_results').html('<%= j(render :partial => "tag_search_results",:locals => {:issues_results => @issues_results, + :projects_results => @projects_results,:users_results => @users_results })%>') + + \ No newline at end of file diff --git a/app/views/tags/delete_tag.js.erb b/app/views/tags/delete_tag.js.erb new file mode 100644 index 00000000..ca714ccf --- /dev/null +++ b/app/views/tags/delete_tag.js.erb @@ -0,0 +1,8 @@ +$('#selected_tags').html('<%= j(render :partial => "selected_tags", +:locals => {:selected_tags => $selected_tags })%>'); +$('#related_tags').html('<%= j(render :partial => "related_tags", +:locals => {:related_tags => $related_tags })%>') + +$('#show_results').html('<%= j(render :partial => "tag_search_results",:locals => {:issues_results => @issues_results, +:projects_results => @projects_results,:users_results => @users_results })%>') + diff --git a/app/views/tags/index.html.erb b/app/views/tags/index.html.erb new file mode 100644 index 00000000..7b489083 --- /dev/null +++ b/app/views/tags/index.html.erb @@ -0,0 +1,31 @@ +
    +
      +
    • + Selected Tags +
    • +
      + <%= render :partial => "selected_tags",:locals => {:selected_tags => $selected_tags }%> +
      +
    • + Related Tags +
    • + +
    +
    + +
    +

    Search Results

    +
    + <%= link_to "Issue",:action => "index"%>(<%= @issues_tags_num %>)| + <%= link_to "Project",:action => "index"%>(<%= @projects_tags_num %>) | + <%= link_to "User",:action => "index"%>(<%= @users_tags_num %>) +
    +
    + <%= render :partial => "tag_search_results",:locals => {:issues_results => @issues_results, + :projects_results => @projects_results,:users_results => @users_results }%> +
    +
    + + diff --git a/app/views/test/_message.html.erb b/app/views/test/_message.html.erb new file mode 100644 index 00000000..a8c3cfac --- /dev/null +++ b/app/views/test/_message.html.erb @@ -0,0 +1,9 @@ +
    +
    + +

    <%= l(:label_message) %> (<%= message.size %>)

    +<% if message.size > 0 %> + <%= message_list(message) %> +<% else %> + <%= l(:label_none) %> +<% end %> \ No newline at end of file diff --git a/app/views/test/_new.html.erb b/app/views/test/_new.html.erb new file mode 100644 index 00000000..e589a3a0 --- /dev/null +++ b/app/views/test/_new.html.erb @@ -0,0 +1,16 @@ +

    <%= l(:label_leave_message_to, :name => "user") %>

    + +<%= form_tag({:controller => 'test', + :action => 'create', + :user_id => user.id}, + :remote => true, + :method => :post, + :id => 'new-watcher-form') do %> + +

    <%= label_tag 'user_search', l(:label_leave_message) %><%= text_field_tag 'user_search', nil %>

    + +

    + <%= submit_tag l(:button_add), :name => nil, :onclick => "hideModal(this);" %> + <%= submit_tag l(:button_cancel), :name => nil, :onclick => "hideModal(this);", :type => 'button' %> +

    +<% end %> diff --git a/app/views/test/create.js.erb b/app/views/test/create.js.erb new file mode 100644 index 00000000..f662bdb5 --- /dev/null +++ b/app/views/test/create.js.erb @@ -0,0 +1 @@ +$('#message').html('<%= escape_javascript(render(:partial => 'test/message', :locals => {:message => @message})) %>'); diff --git a/app/views/test/destroy.js.erb b/app/views/test/destroy.js.erb new file mode 100644 index 00000000..f662bdb5 --- /dev/null +++ b/app/views/test/destroy.js.erb @@ -0,0 +1 @@ +$('#message').html('<%= escape_javascript(render(:partial => 'test/message', :locals => {:message => @message})) %>'); diff --git a/app/views/test/index.html.erb b/app/views/test/index.html.erb new file mode 100644 index 00000000..97634e96 --- /dev/null +++ b/app/views/test/index.html.erb @@ -0,0 +1,3 @@ +

    test

    + + \ No newline at end of file diff --git a/app/views/test/new.js.erb b/app/views/test/new.js.erb new file mode 100644 index 00000000..bd3da2e2 --- /dev/null +++ b/app/views/test/new.js.erb @@ -0,0 +1,3 @@ +$('#ajax-modal').html('<%= escape_javascript(render :partial => 'test/new', :locals => {:user => @user}) %>'); +showModal('ajax-modal', '400px'); +$('#ajax-modal').addClass('new-watcher'); diff --git a/app/views/timelog/_date_range.html.erb b/app/views/timelog/_date_range.html.erb new file mode 100644 index 00000000..a889f160 --- /dev/null +++ b/app/views/timelog/_date_range.html.erb @@ -0,0 +1,34 @@ +
    +
    "> + <%= l(:label_filter_plural) %> +
    "> + <%= render :partial => 'queries/filters', :locals => {:query => @query} %> +
    +
    + +
    + +

    + <%= link_to_function l(:button_apply), 'submit_query_form("query_form")', :class => 'icon icon-checked' %> + <%= link_to l(:button_clear), {:project_id => @project, :issue_id => @issue}, :class => 'icon icon-reload' %> +

    + +
    +<% query_params = params.slice(:f, :op, :v, :sort) %> +
      +
    • <%= link_to(l(:label_details), query_params.merge({:controller => 'timelog', :action => 'index', :project_id => @project, :issue_id => @issue }), + :class => (action_name == 'index' ? 'selected' : nil)) %>
    • +
    • <%= link_to(l(:label_report), query_params.merge({:controller => 'timelog', :action => 'report', :project_id => @project, :issue_id => @issue}), + :class => (action_name == 'report' ? 'selected' : nil)) %>
    • +
    +
    diff --git a/app/views/timelog/_form.html.erb b/app/views/timelog/_form.html.erb new file mode 100644 index 00000000..3256feaa --- /dev/null +++ b/app/views/timelog/_form.html.erb @@ -0,0 +1,32 @@ +<%= error_messages_for 'time_entry' %> +<%= back_url_hidden_field_tag %> + +
    + <% if @time_entry.new_record? %> + <% if params[:project_id] || @time_entry.issue %> + <%= f.hidden_field :project_id %> + <% else %> +

    <%= f.select :project_id, project_tree_options_for_select(Project.allowed_to(:log_time).all, :selected => @time_entry.project), :required => true %>

    + <% end %> + <% end %> +

    + <%= f.text_field :issue_id, :size => 6 %> + <%= h("#{@time_entry.issue.tracker.name} ##{@time_entry.issue.id}: #{@time_entry.issue.subject}") if @time_entry.issue %> +

    +

    <%= f.text_field :spent_on, :size => 10, :required => true %><%= calendar_for('time_entry_spent_on') %>

    +

    <%= f.text_field :hours, :size => 6, :required => true %>

    +

    <%= f.text_field :comments, :size => 100, :maxlength => 255 %>

    +

    <%= f.select :activity_id, activity_collection_for_select_options(@time_entry), :required => true %>

    + <% @time_entry.custom_field_values.each do |value| %> +

    <%= custom_field_tag_with_label :time_entry, value %>

    + <% end %> + <%= call_hook(:view_timelog_edit_form_bottom, { :time_entry => @time_entry, :form => f }) %> +
    + +<%= javascript_tag do %> + observeAutocompleteField('time_entry_issue_id', '<%= escape_javascript auto_complete_issues_path(:project_id => @project, :scope => (@project ? nil : 'all'))%>', { + select: function(event, ui) { + $('#time_entry_issue').text(ui.item.label); + } + }); +<% end %> diff --git a/app/views/timelog/_list.html.erb b/app/views/timelog/_list.html.erb new file mode 100644 index 00000000..522b1303 --- /dev/null +++ b/app/views/timelog/_list.html.erb @@ -0,0 +1,41 @@ +<%= form_tag({}) do -%> +<%= hidden_field_tag 'back_url', url_for(params) %> +
    + + + + + <% @query.inline_columns.each do |column| %> + <%= column_header(column) %> + <% end %> + + + + +<% entries.each do |entry| -%> + hascontextmenu"> + + <%= raw @query.inline_columns.map {|column| ""}.join %> + + +<% end -%> + +
    + <%= link_to image_tag('toggle_check.png'), + {}, + :onclick => 'toggleIssuesSelection(this); return false;', + :title => "#{l(:button_check_all)}/#{l(:button_uncheck_all)}" %> +
    <%= check_box_tag("ids[]", entry.id, false, :id => nil) %>#{column_content(column, entry)} + <% if entry.editable_by?(User.current) -%> + <%= link_to image_tag('edit.png'), edit_time_entry_path(entry), + :title => l(:button_edit) %> + <%= link_to image_tag('delete.png'), time_entry_path(entry), + :data => {:confirm => l(:text_are_you_sure)}, + :method => :delete, + :title => l(:button_delete) %> + <% end -%> +
    +
    +<% end -%> + +<%= context_menu time_entries_context_menu_path %> diff --git a/app/views/timelog/_report_criteria.html.erb b/app/views/timelog/_report_criteria.html.erb new file mode 100644 index 00000000..9a5d142f --- /dev/null +++ b/app/views/timelog/_report_criteria.html.erb @@ -0,0 +1,19 @@ +<% @report.hours.collect {|h| h[criterias[level]].to_s}.uniq.each do |value| %> +<% hours_for_value = select_hours(hours, criterias[level], value) -%> +<% next if hours_for_value.empty? -%> + +<%= ("" * level).html_safe %> +<%= h(format_criteria_value(@report.available_criteria[criterias[level]], value)) %> +<%= ("" * (criterias.length - level - 1)).html_safe -%> + <% total = 0 -%> + <% @report.periods.each do |period| -%> + <% sum = sum_hours(select_hours(hours_for_value, @report.columns, period.to_s)); total += sum -%> + <%= html_hours("%.2f" % sum) if sum > 0 %> + <% end -%> + <%= html_hours("%.2f" % total) if total > 0 %> + +<% if criterias.length > level+1 -%> + <%= render(:partial => 'report_criteria', :locals => {:criterias => criterias, :hours => hours_for_value, :level => (level + 1)}) %> +<% end -%> + +<% end %> diff --git a/app/views/timelog/bulk_edit.html.erb b/app/views/timelog/bulk_edit.html.erb new file mode 100644 index 00000000..caabc18a --- /dev/null +++ b/app/views/timelog/bulk_edit.html.erb @@ -0,0 +1,50 @@ +

    <%= l(:label_bulk_edit_selected_time_entries) %>

    + +
      +<% @time_entries.each do |entry| %> + <%= content_tag 'li', + link_to("#{format_date(entry.spent_on)} - #{entry.project}: #{l(:label_f_hour_plural, :value => entry.hours)}", edit_time_entry_path(entry)) %> +<% end %> +
    + +<%= form_tag(bulk_update_time_entries_path, :id => 'bulk_edit_form') do %> +<%= @time_entries.collect {|i| hidden_field_tag('ids[]', i.id)}.join.html_safe %> +
    +
    +

    + + <%= text_field :time_entry, :issue_id, :size => 6 %> +

    + +

    + + <%= text_field :time_entry, :spent_on, :size => 10 %><%= calendar_for('time_entry_spent_on') %> +

    + +

    + + <%= text_field :time_entry, :hours, :size => 6 %> +

    + + <% if @available_activities.any? %> +

    + + <%= select_tag('time_entry[activity_id]', content_tag('option', l(:label_no_change_option), :value => '') + options_from_collection_for_select(@available_activities, :id, :name)) %> +

    + <% end %> + +

    + + <%= text_field(:time_entry, :comments, :size => 100) %> +

    + + <% @custom_fields.each do |custom_field| %> +

    <%= custom_field_tag_for_bulk_edit('time_entry', custom_field, @projects) %>

    + <% end %> + + <%= call_hook(:view_time_entries_bulk_edit_details_bottom, { :time_entries => @time_entries }) %> +
    +
    + +

    <%= submit_tag l(:button_submit) %>

    +<% end %> diff --git a/app/views/timelog/edit.html.erb b/app/views/timelog/edit.html.erb new file mode 100644 index 00000000..7c6ac5b8 --- /dev/null +++ b/app/views/timelog/edit.html.erb @@ -0,0 +1,6 @@ +

    <%= l(:label_spent_time) %>

    + +<%= labelled_form_for @time_entry, :url => project_time_entry_path(@time_entry.project, @time_entry) do |f| %> + <%= render :partial => 'form', :locals => {:f => f} %> + <%= submit_tag l(:button_save) %> +<% end %> diff --git a/app/views/timelog/index.api.rsb b/app/views/timelog/index.api.rsb new file mode 100644 index 00000000..d281e89b --- /dev/null +++ b/app/views/timelog/index.api.rsb @@ -0,0 +1,18 @@ +api.array :time_entries, api_meta(:total_count => @entry_count, :offset => @offset, :limit => @limit) do + @entries.each do |time_entry| + api.time_entry do + api.id time_entry.id + api.project(:id => time_entry.project_id, :name => time_entry.project.name) unless time_entry.project.nil? + api.issue(:id => time_entry.issue_id) unless time_entry.issue.nil? + api.user(:id => time_entry.user_id, :name => time_entry.user.name) unless time_entry.user.nil? + api.activity(:id => time_entry.activity_id, :name => time_entry.activity.name) unless time_entry.activity.nil? + api.hours time_entry.hours + api.comments time_entry.comments + api.spent_on time_entry.spent_on + api.created_on time_entry.created_on + api.updated_on time_entry.updated_on + + render_api_custom_values time_entry.custom_field_values, api + end + end +end diff --git a/app/views/timelog/index.html.erb b/app/views/timelog/index.html.erb new file mode 100644 index 00000000..d73bd130 --- /dev/null +++ b/app/views/timelog/index.html.erb @@ -0,0 +1,48 @@ +
    +<%= link_to l(:button_log_time), + {:controller => 'timelog', :action => 'new', :project_id => @project, :issue_id => @issue}, + :class => 'icon icon-time-add' if User.current.allowed_to?(:log_time, @project, :global => true) %> +
    + +<%= render_timelog_breadcrumb %> + +

    <%= l(:label_spent_time) %>

    + +<%= form_tag({:controller => 'timelog', :action => 'index', :project_id => @project, :issue_id => @issue}, :method => :get, :id => 'query_form') do %> +<%= render :partial => 'date_range' %> +<% end %> + +
    +

    <%= l(:label_total_time) %>: <%= html_hours(l_hours(@total_hours)) %>

    +
    + +<% unless @entries.empty? %> +<%= render :partial => 'list', :locals => { :entries => @entries }%> +

    <%= pagination_links_full @entry_pages, @entry_count %>

    + +<% other_formats_links do |f| %> + <%= f.link_to 'Atom', :url => params.merge({:issue_id => @issue, :key => User.current.rss_key}) %> + <%= f.link_to 'CSV', :url => params, :onclick => "showModal('csv-export-options', '330px'); return false;" %> +<% end %> + + +<% end %> + +<% html_title l(:label_spent_time), l(:label_details) %> + +<% content_for :header_tags do %> + <%= auto_discovery_link_tag(:atom, {:issue_id => @issue, :format => 'atom', :key => User.current.rss_key}, :title => l(:label_spent_time)) %> +<% end %> diff --git a/app/views/timelog/new.html.erb b/app/views/timelog/new.html.erb new file mode 100644 index 00000000..c740e6df --- /dev/null +++ b/app/views/timelog/new.html.erb @@ -0,0 +1,8 @@ +

    <%= l(:label_spent_time) %>

    + +<%= labelled_form_for @time_entry, :url => time_entries_path do |f| %> + <%= hidden_field_tag 'project_id', params[:project_id] if params[:project_id] %> + <%= render :partial => 'form', :locals => {:f => f} %> + <%= submit_tag l(:button_create) %> + <%= submit_tag l(:button_create_and_continue), :name => 'continue' %> +<% end %> diff --git a/app/views/timelog/report.html.erb b/app/views/timelog/report.html.erb new file mode 100644 index 00000000..30a58a73 --- /dev/null +++ b/app/views/timelog/report.html.erb @@ -0,0 +1,74 @@ +
    +<%= link_to_if_authorized l(:button_log_time), {:controller => 'timelog', :action => 'new', :project_id => @project, :issue_id => @issue}, :class => 'icon icon-time-add' %> +
    + +<%= render_timelog_breadcrumb %> + +

    <%= l(:label_spent_time) %>

    + +<%= form_tag({:controller => 'timelog', :action => 'report', + :project_id => @project, :issue_id => @issue}, + :method => :get, :id => 'query_form') do %> + <% @report.criteria.each do |criterion| %> + <%= hidden_field_tag 'criteria[]', criterion, :id => nil %> + <% end %> + <%= render :partial => 'timelog/date_range' %> + +

    : <%= select_tag 'columns', options_for_select([[l(:label_year), 'year'], + [l(:label_month), 'month'], + [l(:label_week), 'week'], + [l(:label_day_plural).titleize, 'day']], @report.columns), + :onchange => "this.form.submit();" %> + + : <%= select_tag('criteria[]', options_for_select([[]] + (@report.available_criteria.keys - @report.criteria).collect{|k| [l_or_humanize(@report.available_criteria[k][:label]), k]}), + :onchange => "this.form.submit();", + :style => 'width: 200px', + :id => nil, + :disabled => (@report.criteria.length >= 3), :id => "criterias") %> + <%= link_to l(:button_clear), {:project_id => @project, :issue_id => @issue, :period_type => params[:period_type], :period => params[:period], :from => @from, :to => @to, :columns => @report.columns}, :class => 'icon icon-reload' %>

    +<% end %> + +<% unless @report.criteria.empty? %> +
    +

    <%= l(:label_total_time) %>: <%= html_hours(l_hours(@report.total_hours)) %>

    +
    + +<% unless @report.hours.empty? %> +
    + + + +<% @report.criteria.each do |criteria| %> + +<% end %> +<% columns_width = (40 / (@report.periods.length+1)).to_i %> +<% @report.periods.each do |period| %> + +<% end %> + + + + +<%= render :partial => 'report_criteria', :locals => {:criterias => @report.criteria, :hours => @report.hours, :level => 0} %> + + + <%= ('' * (@report.criteria.size - 1)).html_safe %> + <% total = 0 -%> + <% @report.periods.each do |period| -%> + <% sum = sum_hours(select_hours(@report.hours, @report.columns, period.to_s)); total += sum -%> + + <% end -%> + + + +
    <%= l_or_humanize(@report.available_criteria[criteria][:label]) %><%= period %><%= l(:label_total_time) %>
    <%= l(:label_total_time) %><%= html_hours("%.2f" % sum) if sum > 0 %><%= html_hours("%.2f" % total) if total > 0 %>
    +
    + +<% other_formats_links do |f| %> + <%= f.link_to 'CSV', :url => params %> +<% end %> +<% end %> +<% end %> + +<% html_title l(:label_spent_time), l(:label_report) %> + diff --git a/app/views/timelog/show.api.rsb b/app/views/timelog/show.api.rsb new file mode 100644 index 00000000..7fce2529 --- /dev/null +++ b/app/views/timelog/show.api.rsb @@ -0,0 +1,14 @@ +api.time_entry do + api.id @time_entry.id + api.project(:id => @time_entry.project_id, :name => @time_entry.project.name) unless @time_entry.project.nil? + api.issue(:id => @time_entry.issue_id) unless @time_entry.issue.nil? + api.user(:id => @time_entry.user_id, :name => @time_entry.user.name) unless @time_entry.user.nil? + api.activity(:id => @time_entry.activity_id, :name => @time_entry.activity.name) unless @time_entry.activity.nil? + api.hours @time_entry.hours + api.comments @time_entry.comments + api.spent_on @time_entry.spent_on + api.created_on @time_entry.created_on + api.updated_on @time_entry.updated_on + + render_api_custom_values @time_entry.custom_field_values, api +end diff --git a/app/views/trackers/_form.html.erb b/app/views/trackers/_form.html.erb new file mode 100644 index 00000000..9039bba6 --- /dev/null +++ b/app/views/trackers/_form.html.erb @@ -0,0 +1,52 @@ +<%= error_messages_for 'tracker' %> + +
    +
    + +

    <%= f.text_field :name, :required => true %>

    +

    <%= f.check_box :is_in_roadmap %>

    + +

    + + <% Tracker::CORE_FIELDS.each do |field| %> + + <% end %> +

    +<%= hidden_field_tag 'tracker[core_fields][]', '' %> + +<% if IssueCustomField.all.any? %> +

    + + <% IssueCustomField.all.each do |field| %> + + <% end %> +

    +<%= hidden_field_tag 'tracker[custom_field_ids][]', '' %> +<% end %> + +<% if @tracker.new_record? && @trackers.any? %> +

    +<%= select_tag(:copy_workflow_from, content_tag("option") + options_from_collection_for_select(@trackers, :id, :name)) %>

    +<% end %> + +
    +<%= submit_tag l(@tracker.new_record? ? :button_create : :button_save) %> +
    + +
    +<% if @projects.any? %> +
    <%= l(:label_project_plural) %> +<%= render_project_nested_lists(@projects) do |p| + content_tag('label', check_box_tag('tracker[project_ids][]', p.id, @tracker.projects.include?(p), :id => nil) + ' ' + h(p)) +end %> +<%= hidden_field_tag('tracker[project_ids][]', '', :id => nil) %> +

    <%= check_all_links 'tracker_project_ids' %>

    +
    +<% end %> +
    diff --git a/app/views/trackers/edit.html.erb b/app/views/trackers/edit.html.erb new file mode 100644 index 00000000..343e53fe --- /dev/null +++ b/app/views/trackers/edit.html.erb @@ -0,0 +1,5 @@ +

    <%= link_to l(:label_tracker_plural), trackers_path %> » <%=h @tracker %>

    + +<%= labelled_form_for @tracker do |f| %> +<%= render :partial => 'form', :locals => { :f => f } %> +<% end %> diff --git a/app/views/trackers/fields.html.erb b/app/views/trackers/fields.html.erb new file mode 100644 index 00000000..48cfb17a --- /dev/null +++ b/app/views/trackers/fields.html.erb @@ -0,0 +1,77 @@ +

    <%= link_to l(:label_tracker_plural), trackers_path %> » <%= l(:field_summary) %>

    + +<% if @trackers.any? %> + <%= form_tag fields_trackers_path do %> +
    + + + + + <% @trackers.each do |tracker| %> + + <% end %> + + + + + + + <% Tracker::CORE_FIELDS.each do |field| %> + "> + + <% @trackers.each do |tracker| %> + + <% end %> + + <% end %> + <% if @custom_fields.any? %> + + + + <% @custom_fields.each do |field| %> + "> + + <% @trackers.each do |tracker| %> + + <% end %> + + <% end %> + <% end %> + +
    + <%= tracker.name %> + <%= link_to_function(image_tag('toggle_check.png'), "toggleCheckboxesBySelector('input.tracker-#{tracker.id}')", + :title => "#{l(:button_check_all)}/#{l(:button_uncheck_all)}") %> +
    +   + <%= l(:field_core_fields) %> +
    + <%= link_to_function(image_tag('toggle_check.png'), "toggleCheckboxesBySelector('input.core-field-#{field}')", + :title => "#{l(:button_check_all)}/#{l(:button_uncheck_all)}") %> + <%= l("field_#{field}".sub(/_id$/, '')) %> + + <%= check_box_tag "trackers[#{tracker.id}][core_fields][]", field, tracker.core_fields.include?(field), + :class => "tracker-#{tracker.id} core-field-#{field}" %> +
    +   + <%= l(:label_custom_field_plural) %> +
    + <%= link_to_function(image_tag('toggle_check.png'), "toggleCheckboxesBySelector('input.custom-field-#{field.id}')", + :title => "#{l(:button_check_all)}/#{l(:button_uncheck_all)}") %> + <%= field.name %> + + <%= check_box_tag "trackers[#{tracker.id}][custom_field_ids][]", field.id, tracker.custom_fields.include?(field), + :class => "tracker-#{tracker.id} custom-field-#{field.id}" %> +
    +
    +

    <%= submit_tag l(:button_save) %>

    + <% @trackers.each do |tracker| %> + <%= hidden_field_tag "trackers[#{tracker.id}][core_fields][]", '' %> + <%= hidden_field_tag "trackers[#{tracker.id}][custom_field_ids][]", '' %> + <% end %> + <% end %> +<% else %> +

    <%= l(:label_no_data) %>

    +<% end %> + +<% html_title l(:field_summary) %> diff --git a/app/views/trackers/index.api.rsb b/app/views/trackers/index.api.rsb new file mode 100644 index 00000000..a37c552a --- /dev/null +++ b/app/views/trackers/index.api.rsb @@ -0,0 +1,8 @@ +api.array :trackers do + @trackers.each do |tracker| + api.tracker do + api.id tracker.id + api.name tracker.name + end + end +end diff --git a/app/views/trackers/index.html.erb b/app/views/trackers/index.html.erb new file mode 100644 index 00000000..abcf84d8 --- /dev/null +++ b/app/views/trackers/index.html.erb @@ -0,0 +1,39 @@ +
    +<%= link_to l(:label_tracker_new), new_tracker_path, :class => 'icon icon-add' %> +<%= link_to l(:field_summary), fields_trackers_path, :class => 'icon icon-summary' %> +
    + +

    <%=l(:label_tracker_plural)%>

    + + + + + + + + + +<% for tracker in @trackers %> + "> + + + + + +<% end %> + +
    <%=l(:label_tracker)%><%=l(:button_sort)%>
    <%= link_to h(tracker.name), edit_tracker_path(tracker) %> + <% unless tracker.workflow_rules.count > 0 %> + + <%= l(:text_tracker_no_workflow) %> (<%= link_to l(:button_edit), workflows_edit_path(:tracker_id => tracker) %>) + + <% end %> + + <%= reorder_links('tracker', {:action => 'update', :id => tracker}, :put) %> + + <%= delete_link tracker_path(tracker) %> +
    + +

    <%= pagination_links_full @tracker_pages %>

    + +<% html_title(l(:label_tracker_plural)) -%> diff --git a/app/views/trackers/new.html.erb b/app/views/trackers/new.html.erb new file mode 100644 index 00000000..d636499a --- /dev/null +++ b/app/views/trackers/new.html.erb @@ -0,0 +1,5 @@ +

    <%= link_to l(:label_tracker_plural), trackers_path %> » <%=l(:label_tracker_new)%>

    + +<%= labelled_form_for @tracker do |f| %> +<%= render :partial => 'form', :locals => { :f => f } %> +<% end %> diff --git a/app/views/users/_form.html.erb b/app/views/users/_form.html.erb new file mode 100644 index 00000000..ddc826fa --- /dev/null +++ b/app/views/users/_form.html.erb @@ -0,0 +1,51 @@ +<%= error_messages_for 'user' %> + +
    + +
    +
    + <%=l(:label_information_plural)%> +

    <%= f.text_field :login, :required => true, :size => 25 %>

    +

    <%= f.text_field :firstname, :required => true %>

    +

    <%= f.text_field :lastname, :required => true %>

    +

    <%= f.text_field :mail, :required => true %>

    +

    <%= f.select :language, lang_options_for_select %>

    + <% if Setting.openid? %> +

    <%= f.text_field :identity_url %>

    + <% end %> + + <% @user.custom_field_values.each do |value| %> +

    <%= custom_field_tag_with_label :user, value %>

    + <% end %> + +

    <%= f.check_box :admin, :disabled => (@user == User.current) %>

    + <%= call_hook(:view_users_form, :user => @user, :form => f) %> +
    + +
    + <%=l(:label_authentication)%> + <% unless @auth_sources.empty? %> +

    <%= f.select :auth_source_id, ([[l(:label_internal), ""]] + @auth_sources.collect { |a| [a.name, a.id] }), {}, :onchange => "if (this.value=='') {$('#password_fields').show();} else {$('#password_fields').hide();}" %>

    + <% end %> +
    +

    <%= f.password_field :password, :required => true, :size => 25 %> + <%= l(:text_caracters_minimum, :count => Setting.password_min_length) %>

    +

    <%= f.password_field :password_confirmation, :required => true, :size => 25 %>

    +
    +
    +
    + +
    +
    + <%=l(:field_mail_notification)%> + <%= render :partial => 'users/mail_notifications' %> +
    + +
    + <%=l(:label_preferences)%> + <%= render :partial => 'users/preferences' %> +
    +
    +
    +
    + diff --git a/app/views/users/_general.html.erb b/app/views/users/_general.html.erb new file mode 100644 index 00000000..0daa421c --- /dev/null +++ b/app/views/users/_general.html.erb @@ -0,0 +1,7 @@ +<%= labelled_form_for @user do |f| %> + <%= render :partial => 'form', :locals => { :f => f } %> + <% if @user.active? && email_delivery_enabled? -%> +

    + <% end -%> +

    <%= submit_tag l(:button_save) %>

    +<% end %> diff --git a/app/views/users/_groups.html.erb b/app/views/users/_groups.html.erb new file mode 100644 index 00000000..e24296ef --- /dev/null +++ b/app/views/users/_groups.html.erb @@ -0,0 +1,9 @@ +<%= form_for(:user, :url => { :action => 'update' }, :html => {:method => :put}) do %> +
    +<% Group.all.sort.each do |group| %> +
    +<% end %> +<%= hidden_field_tag 'user[group_ids][]', '' %> +
    +<%= submit_tag l(:button_save) %> +<% end %> diff --git a/app/views/users/_leave_message.html.erb b/app/views/users/_leave_message.html.erb new file mode 100644 index 00000000..5c2780ad --- /dev/null +++ b/app/views/users/_leave_message.html.erb @@ -0,0 +1,27 @@ +

    <%= l(:permission_add_issue_watchers) %>

    + +<%= form_tag({:controller => 'users', + :action => (user ? 'create' : 'append'), + :object_type => (user && user.class.name.underscore), + :object_id => user, + :project_id => @project}, + :remote => true, + :method => :post, + :id => 'new-watcher-form') do %> + +

    <%= label_tag 'user_search', l(:label_user_search) %><%= text_field_tag 'user_search', nil %>

    + <%= javascript_tag "observeSearchfield('user_search', 'users_for_watcher', '#{ escape_javascript url_for(:controller => 'watchers', + :action => 'autocomplete_for_user', + :object_type => (watched && watched.class.name.underscore), + :object_id => watched, + :project_id => @project) }')" %> + +
    + <%= principals_check_box_tags 'watcher[user_ids][]', (watched ? watched.addable_watcher_users : User.active.all(:limit => 100)) %> +
    + +

    + <%= submit_tag l(:button_add), :name => nil, :onclick => "hideModal(this);" %> + <%= submit_tag l(:button_cancel), :name => nil, :onclick => "hideModal(this);", :type => 'button' %> +

    +<% end %> diff --git a/app/views/users/_mail_notifications.html.erb b/app/views/users/_mail_notifications.html.erb new file mode 100644 index 00000000..ee6ccb00 --- /dev/null +++ b/app/views/users/_mail_notifications.html.erb @@ -0,0 +1,27 @@ +

    +<%= label_tag "user_mail_notification", l(:description_user_mail_notification), :class => "hidden-for-sighted" %> +<%= select_tag( + 'user[mail_notification]', + options_for_select( + user_mail_notification_options(@user), @user.mail_notification), + :onchange => 'if (this.value == "selected") {$("#notified-projects").show();} else {$("#notified-projects").hide();}' + ) %> +

    +<%= content_tag 'div', :id => 'notified-projects', :style => (@user.mail_notification == 'selected' ? '' : 'display:none;') do %> + <%= render_project_nested_lists_new(@user.projects) do |project| + content_tag('label', + check_box_tag( + 'notified_project_ids[]', + project.id, + @user.notified_projects_ids.include?(project.id) + ) + ' ' + h(project.name) + ) + end %> +

    <%= l(:text_user_mail_option) %>

    +<% end %> +

    + +

    diff --git a/app/views/users/_memberships.html.erb b/app/views/users/_memberships.html.erb new file mode 100644 index 00000000..5f61d2ce --- /dev/null +++ b/app/views/users/_memberships.html.erb @@ -0,0 +1,67 @@ +<% roles = Role.find_all_givable %> +<% projects = Project.active.all %> + +
    +<% if @user.memberships.any? %> + + + + + + <%= call_hook(:view_users_memberships_table_header, :user => @user )%> + + + <% @user.memberships.each do |membership| %> + <% next if membership.new_record? %> + + + + + <%= call_hook(:view_users_memberships_table_row, :user => @user, :membership => membership, :roles => roles, :projects => projects )%> + + <% end; reset_cycle %> + +
    <%= l(:label_project) %><%= l(:label_role_plural) %>
    + <%= link_to_project membership.project %> + + <%=h membership.roles.sort.collect(&:to_s).join(', ') %> + <%= form_for(:membership, :remote => true, + :url => user_membership_path(@user, membership), :method => :put, + :html => {:id => "member-#{membership.id}-roles-form", + :style => 'display:none;'}) do %> +

    <% roles.each do |role| %> +
    + <% end %>

    + <%= hidden_field_tag 'membership[role_ids][]', '' %> +

    <%= submit_tag l(:button_change) %> + <%= link_to_function l(:button_cancel), + "$('#member-#{membership.id}-roles').show(); $('#member-#{membership.id}-roles-form').hide(); return false;" + %>

    + <% end %> +
    + <%= link_to_function l(:button_edit), + "$('#member-#{membership.id}-roles').hide(); $('#member-#{membership.id}-roles-form').show(); return false;", + :class => 'icon icon-edit' + %> + <%= delete_link user_membership_path(@user, membership), :remote => true if membership.deletable? %> +
    +<% else %> +

    <%= l(:label_no_data) %>

    +<% end %> +
    + +
    +<% if projects.any? %> +
    <%=l(:label_project_new)%> +<%= form_for(:membership, :remote => true, :url => user_memberships_path(@user)) do %> +<%= select_tag 'membership[project_id]', options_for_membership_project_select(@user, projects) %> +

    <%= l(:label_role_plural) %>: +<% roles.each do |role| %> + +<% end %>

    +

    <%= submit_tag l(:button_add) %>

    +<% end %> +
    +<% end %> +
    diff --git a/app/views/users/_preferences.html.erb b/app/views/users/_preferences.html.erb new file mode 100644 index 00000000..fb72d475 --- /dev/null +++ b/app/views/users/_preferences.html.erb @@ -0,0 +1,6 @@ +<%= labelled_fields_for :pref, @user.pref do |pref_fields| %> +

    <%= pref_fields.check_box :hide_mail %>

    +

    <%= pref_fields.time_zone_select :time_zone, nil, :include_blank => true %>

    +

    <%= pref_fields.select :comments_sorting, [[l(:label_chronological_order), 'asc'], [l(:label_reverse_chronological_order), 'desc']] %>

    +

    <%= pref_fields.check_box :warn_on_leaving_unsaved %>

    +<% end %> diff --git a/app/views/users/blocks/_calendar.html.erb b/app/views/users/blocks/_calendar.html.erb new file mode 100644 index 00000000..41ca18a1 --- /dev/null +++ b/app/views/users/blocks/_calendar.html.erb @@ -0,0 +1,6 @@ +

    <%= l(:label_calendar) %>

    + +<% calendar = Redmine::Helpers::Calendar.new(Date.today, current_language, :week) + calendar.events = calendar_items(calendar.startdt, calendar.enddt) %> + +<%= render :partial => 'common/calendar', :locals => {:calendar => calendar } %> diff --git a/app/views/users/blocks/_issuesassignedtome.html.erb b/app/views/users/blocks/_issuesassignedtome.html.erb new file mode 100644 index 00000000..02d8c9aa --- /dev/null +++ b/app/views/users/blocks/_issuesassignedtome.html.erb @@ -0,0 +1,18 @@ +

    <%=l(:label_assigned_to_me_issues)%> (<%= Issue.visible.open.count(:conditions => {:assigned_to_id => ([User.current.id] + User.current.group_ids)})%>)

    + +<% assigned_issues = issuesassignedtome_items %> +<%= render :partial => 'issues/list_simple', :locals => { :issues => assigned_issues } %> +<% if assigned_issues.length > 0 %> +

    <%= link_to l(:label_issue_view_all), :controller => 'issues', + :action => 'index', + :set_filter => 1, + :assigned_to_id => 'me', + :sort => 'priority:desc,updated_on:desc' %>

    +<% end %> + +<% content_for :header_tags do %> +<%= auto_discovery_link_tag(:atom, + {:controller => 'issues', :action => 'index', :set_filter => 1, + :assigned_to_id => 'me', :format => 'atom', :key => User.current.rss_key}, + {:title => l(:label_assigned_to_me_issues)}) %> +<% end %> diff --git a/app/views/users/destroy_membership.js.erb b/app/views/users/destroy_membership.js.erb new file mode 100644 index 00000000..53b769a7 --- /dev/null +++ b/app/views/users/destroy_membership.js.erb @@ -0,0 +1 @@ +$('#tab-content-memberships').html('<%= escape_javascript(render :partial => 'users/memberships') %>'); diff --git a/app/views/users/edit.html.erb b/app/views/users/edit.html.erb new file mode 100644 index 00000000..01875ab6 --- /dev/null +++ b/app/views/users/edit.html.erb @@ -0,0 +1,11 @@ +
    +<%= link_to l(:label_profile), user_path(@user), :class => 'icon icon-user' %> +<%= change_status_link(@user) %> +<%= delete_link user_path(@user) if User.current != @user %> +
    + +

    <%= link_to l(:label_user_plural), users_path %> » <%=h @user.login %>

    + +<%= render_tabs user_settings_tabs %> + +<% html_title(l(:label_user), @user.login, l(:label_administration)) -%> diff --git a/app/views/users/edit_membership.js.erb b/app/views/users/edit_membership.js.erb new file mode 100644 index 00000000..d9ad2f35 --- /dev/null +++ b/app/views/users/edit_membership.js.erb @@ -0,0 +1,6 @@ +<% if @membership.valid? %> + $('#tab-content-memberships').html('<%= escape_javascript(render :partial => 'users/memberships') %>'); + $("#member-<%= @membership.id %>").effect("highlight"); +<% else %> + alert('<%= raw(escape_javascript(l(:notice_failed_to_save_members, :errors => @membership.errors.full_messages.join(', ')))) %>'); +<% end %> diff --git a/app/views/users/index.api.rsb b/app/views/users/index.api.rsb new file mode 100644 index 00000000..4265a4be --- /dev/null +++ b/app/views/users/index.api.rsb @@ -0,0 +1,15 @@ +api.array :users, api_meta(:total_count => @user_count, :offset => @offset, :limit => @limit) do + @users.each do |user| + api.user do + api.id user.id + api.login user.login + api.firstname user.firstname + api.lastname user.lastname + api.mail user.mail + api.created_on user.created_on + api.last_login_on user.last_login_on + + render_api_custom_values user.visible_custom_field_values, api + end + end +end diff --git a/app/views/users/index.html.erb b/app/views/users/index.html.erb new file mode 100644 index 00000000..99b26aba --- /dev/null +++ b/app/views/users/index.html.erb @@ -0,0 +1,155 @@ +<% if User.current.admin? %> +
    + <%= link_to l(:label_user_new), new_user_path, :class => 'icon icon-add' %> +
    + +

    <%= l(:label_user_plural)%>

    + +<%= form_tag(users_path, :method => :get) do %> +
    + + <%= l(:label_filter_plural) %> + + + <%= select_tag 'status', users_status_options_for_select(@status), :class => "small", :onchange => "this.form.submit(); return false;" %> + + <% if @groups.present? %> + + <%= select_tag 'group_id', content_tag('option') + options_from_collection_for_select(@groups, :id, :name, params[:group_id].to_i), :onchange => "this.form.submit(); return false;" %> + <% end %> + + + <%= text_field_tag 'name', params[:name], :size => 30 %> + <%= submit_tag l(:button_apply), :class => "small", :name => nil %> + <%= link_to l(:button_clear), users_path, :class => 'icon icon-reload' %> +
    +<% end %> +  + +
    + + + + <%= sort_header_tag('login', :caption => l(:field_login)) %> + <%= sort_header_tag('firstname', :caption => l(:field_firstname)) %> + <%= sort_header_tag('lastname', :caption => l(:field_lastname)) %> + <%= sort_header_tag('mail', :caption => l(:field_mail)) %> + <%= sort_header_tag('admin', :caption => l(:field_admin), :default_order => 'desc') %> + <%= sort_header_tag('created_on', :caption => l(:field_created_on), :default_order => 'desc') %> + <%= sort_header_tag('last_login_on', :caption => l(:field_last_login_on), :default_order => 'desc') %> + + + + + <% for user in @users -%> + "> + + + + + + + + + + <% end -%> + +
    <%= avatar(user, :size => "14") %><%= link_to h(user.login), edit_user_path(user) %><%= h(user.firstname) %><%= h(user.lastname) %><%= checked_image user.admin? %><%= format_time(user.created_on) %> <%= change_status_link(user) %> + <%= delete_link user_path(user, :back_url => users_path(params)) unless User.current == user %>
    +
    + + +<% html_title(l(:label_user_plural)) -%> + +<% else %> +
    + <%= link_to l(:label_user_new), new_user_path, :class => 'icon icon-add' %> +
    + +

    <%= l(:label_user_plural)%>

    + +<%= form_tag(users_path, :method => :get) do %> +
    + + <%= l(:label_filter_plural) %> + + + <%= select_tag 'status', users_status_options_for_select(@status), :class => "small", :onchange => "this.form.submit(); return false;" %> + + <% if @groups.present? %> + + <%= select_tag 'group_id', content_tag('option') + options_from_collection_for_select(@groups, :id, :name, params[:group_id].to_i), :onchange => "this.form.submit(); return false;" %> + <% end %> + + + <%= text_field_tag 'name', params[:name], :size => 30 %> + <%= submit_tag l(:button_apply), :class => "small", :name => nil %> + <%= link_to l(:button_clear), users_path, :class => 'icon icon-reload' %> +
    +<% end %> +  + +
    + + + <% for user in @users -%> +
    + <%= content_tag "p", "#{date_format_local(user.created_on)}#{l(:label_member_since)}", :class => "float_right member_since" %> + <%= get_avatar?(user) ? (link_to image_tag(avatar_image(user), :class => 'avatar'), :class => "avatar") : (link_to image_tag("/images/12_50.png", :class => 'avatar'), :class => "avatar") %> + <%= content_tag "div", link_to_user(user), :class => "nomargin avatar_name" %> + <%= content_tag "div", content_tag("p", user.firstname), :class => "clear avatar_name" %> +

    + <% unless user.memberships.empty? %> + <%= l(:label_contribute_to, :project_count => "#{user.memberships.count}") %> + <% for member in user.memberships %> + <%= link_to_project(member.project) %><%= (user.memberships.last == member) ? '' : ',' %> + <% end %> + <% end %> +

    +

    + <%= user.changesets.count == 0 ? '' : "#{l(:label_total_commit, :total_commit => user.changesets.count)}" %> | managed 7 projects | Most experience in c++ +

    +
    + <% end -%> +
    + + + +<% html_title(l(:label_user_plural)) -%> +<% end -%> diff --git a/app/views/users/leave_message.js.erb b/app/views/users/leave_message.js.erb new file mode 100644 index 00000000..f4a8ac7a --- /dev/null +++ b/app/views/users/leave_message.js.erb @@ -0,0 +1,3 @@ +$('#ajax-modal').html('<%= escape_javascript(render :partial => 'users/leave_message', :locals => {:user => @user}) %>'); +showModal('ajax-modal', '400px'); +$('#ajax-modal').addClass('new-watcher'); diff --git a/app/views/users/list.api.rsb b/app/views/users/list.api.rsb new file mode 100644 index 00000000..4265a4be --- /dev/null +++ b/app/views/users/list.api.rsb @@ -0,0 +1,15 @@ +api.array :users, api_meta(:total_count => @user_count, :offset => @offset, :limit => @limit) do + @users.each do |user| + api.user do + api.id user.id + api.login user.login + api.firstname user.firstname + api.lastname user.lastname + api.mail user.mail + api.created_on user.created_on + api.last_login_on user.last_login_on + + render_api_custom_values user.visible_custom_field_values, api + end + end +end diff --git a/app/views/users/list.html.erb b/app/views/users/list.html.erb new file mode 100644 index 00000000..4cceaee3 --- /dev/null +++ b/app/views/users/list.html.erb @@ -0,0 +1,81 @@ +
    + <%= link_to l(:label_user_new), new_user_path, :class => 'icon icon-add' %> +
    + +

    <%= l(:label_user_plural)%>

    + +<%= form_tag(users_path, :method => :get) do %> +
    + + <%= l(:label_filter_plural) %> + + + <%= select_tag 'status', users_status_options_for_select(@status), :class => "small", :onchange => "this.form.submit(); return false;" %> + + <% if @groups.present? %> + + <%= select_tag 'group_id', content_tag('option') + options_from_collection_for_select(@groups, :id, :name, params[:group_id].to_i), :onchange => "this.form.submit(); return false;" %> + <% end %> + + + <%= text_field_tag 'name', params[:name], :size => 30 %> + <%= submit_tag l(:button_apply), :class => "small", :name => nil %> + <%= link_to l(:button_clear), users_path, :class => 'icon icon-reload' %> +
    +<% end %> +  + +
    + + + <% for user in @users -%> +
    + <%= content_tag "p", "Trustie2 member since #{format_time(user.created_on)}", :class => "float_right member_since" %> + <%= link_to image_tag(avatar_image(user), :class => 'avatar'), :class => "avatar" %> + <%= content_tag "div", link_to_user(user), :class => "nomargin avatar_name" %> + <%= content_tag "div", content_tag("p", user.firstname), :class => "clear avatar_name" %> +

    + Contributes to <%= user.id%> projects including +

    +

    + 14168 total commits to 18 projects | managed 7 projects | Most experience in c++ +

    +
    + <% end -%> +
    + + + +<% html_title(l(:label_user_plural)) -%> diff --git a/app/views/users/new.html.erb b/app/views/users/new.html.erb new file mode 100644 index 00000000..e2112914 --- /dev/null +++ b/app/views/users/new.html.erb @@ -0,0 +1,30 @@ +

    <%= link_to l(:label_user_plural), users_path %> » <%=l(:label_user_new)%>

    + +<%= labelled_form_for @user do |f| %> + <%= render :partial => 'form', :locals => { :f => f } %> + <% if email_delivery_enabled? %> +

    + <% end %> +

    + <%= submit_tag l(:button_create) %> + <%= submit_tag l(:button_create_and_continue), :name => 'continue' %> +

    +<% end %> + +<% if @auth_sources.present? && @auth_sources.any?(&:searchable?) %> + <%= javascript_tag do %> + observeAutocompleteField('user_login', '<%= escape_javascript autocomplete_for_new_user_auth_sources_path %>', { + select: function(event, ui) { + $('input#user_firstname').val(ui.item.firstname); + $('input#user_lastname').val(ui.item.lastname); + $('input#user_mail').val(ui.item.mail); + $('select#user_auth_source_id option').each(function(){ + if ($(this).attr('value') == ui.item.auth_source_id) { + $(this).attr('selected', true); + $('select#user_auth_source_id').trigger('change'); + } + }); + } + }); + <% end %> +<% end %> diff --git a/app/views/users/show.api.rsb b/app/views/users/show.api.rsb new file mode 100644 index 00000000..7168cb94 --- /dev/null +++ b/app/views/users/show.api.rsb @@ -0,0 +1,36 @@ +api.user do + api.id @user.id + api.login @user.login if User.current.admin? || (User.current == @user) + api.firstname @user.firstname + api.lastname @user.lastname + api.mail @user.mail if User.current.admin? || !@user.pref.hide_mail + api.created_on @user.created_on + api.last_login_on @user.last_login_on + api.api_key @user.api_key if User.current.admin? || (User.current == @user) + + render_api_custom_values @user.visible_custom_field_values, api + + api.array :groups do |groups| + @user.groups.each do |group| + api.group :id => group.id, :name => group.name + end + end if User.current.admin? && include_in_api_response?('groups') + + api.array :memberships do + @memberships.each do |membership| + api.membership do + api.id membership.id + api.project :id => membership.project.id, :name => membership.project.name + api.array :roles do + membership.member_roles.each do |member_role| + if member_role.role + attrs = {:id => member_role.role.id, :name => member_role.role.name} + attrs.merge!(:inherited => true) if member_role.inherited_from.present? + api.role attrs + end + end + end + end if membership.project + end + end if include_in_api_response?('memberships') && @memberships +end diff --git a/app/views/users/show.html.erb b/app/views/users/show.html.erb new file mode 100644 index 00000000..8c58dd7f --- /dev/null +++ b/app/views/users/show.html.erb @@ -0,0 +1,26 @@ + +<% unless @events_by_day.empty? %> +
    +<% @events_by_day.keys.sort.reverse.each do |day| %> +<% @events_by_day[day].sort {|x,y| y.event_datetime <=> x.event_datetime }.each do |e| -%> + + + + + + <% end %> +
    + + + + + + + + + + + +
    <%= content_tag('span', h(e.project), :class => 'project') %> 有了最新动态 <%= link_to format_activity_title(e.event_title), e.event_url %>

    <%= format_activity_description(e.event_description) %>

    <%= format_activity_day(day) %>
    <% end %> +
    +<% end %> diff --git a/app/views/users/show_old.html.erb b/app/views/users/show_old.html.erb new file mode 100644 index 00000000..1f75b8d6 --- /dev/null +++ b/app/views/users/show_old.html.erb @@ -0,0 +1,343 @@ + + +
    + <%= link_to(l(:button_edit), edit_user_path(@user), :class => 'icon icon-edit') if User.current.admin? %> +
    + +

    <%= h @user.name %>

    + + +
    +
    + +
    + + + + + + + + + + + + + +
    关注 <%= link_to User.watched_by(@user.id).count, home_path %> 粉丝 <%= link_to @user.watcher_users.count, home_path %>
    <%= link_to image_tag(avatar_image(@user), :class => 'avatar'), :class => "avatar" %>
    <% unless User.current == @user %> + <%= watcher_link(@user, User.current) %><% end %>
    +
    + + + +
    +
    +
      +
    • +

      <%= h @user.name %>

      +
    • +
    • +

      <%= mail_to(h(@user.mail), nil, :encode => 'javascript') %>

      +
    • +
    • + <%= l(:field_last_login_on)%>: <%= format_date(@user.last_login_on) %> +
    • +
    • + 贡献指数: +
    • +
    +
    + +
    +
    + +
    +
    +
    +

    <%= link_to l(:label_user_watcher), home_path %>

    +
    +
    +
    +
    +
      +
    • +
    • +
    +
    +
    +
    + + + <% unless User.current == @user %> +
    + <%= render :partial => 'words/new', :locals => {:user => @user, :sta => @state}%> +
    + <% end %> + + +
    + +
    + <%= render :partial => 'layouts/tag', :locals => {:obj => @user,:object_flag => "1"}%> +
    +
    +
    + + + +
    + <%= render :partial => 'words/message', :locals => {:message => @message, :state => @state} %> +
    + + +
    +   + +
    +
    +

    <%= link_to l(:label_project_plural),home_path %>

    +
    + <% unless @memberships.empty? %> + +
      + <% for membership in @memberships %> +
    • + + + + + + + + + +
      + +
      +
      + <%= link_to_project(membership.project) %> +
      +
      + <%= membership.project.description%> +
      +
      + <%= l(:label_user_watcher)%><%= link_to"999",home_path%> <%= l(:label_user_commits)%><%= link_to"12",home_path%> +
      +
      + ( + <%= format_date(membership.created_on) %>) +
      +
      +
    • + <% end %> +
    +
    + <%= link_to"更多",:controller=>'projects',:action=>'index'%> +
    + <% else %> + 暂无项目,赶快去<%= link_to"新建",:controller=>'projects',:action=>'new'%>吧 + <% end %> + <%= call_hook :view_account_left_bottom, :user => @user %> +
    + +   + + +************************** +<% unless @memberships.empty? %> +
      + <% for membership in @memberships %> +
    • + + + + + +
      + + + + + + + + + + +
      <%= link_to_project(membership.project) %> 创建了 <%= link_to_project(membership.project) %>

      <%= membership.project.description%>

      <%= format_date(membership.created_on) %><%= link_to"查看其他评论",news_path(news)%><%= "(#{l(:label_x_comments, :count => news.comments_count)})" if news.comments_count > 0 %>
    • + <% end %> +
    +
    + <%= link_to"更多",:controller=>'projects',:action=>'index'%> +
    + <% else %> + 暂无项目,赶快去<%= link_to"新建",:controller=>'projects',:action=>'new'%>吧 + <% end %> + <%= call_hook :view_account_left_bottom, :user => @user %> + +*************************** + + + + + + + +
    +
    + + + + +

    <%= link_to l(:label_user_newfeedback), home_path %>

    start a...
    +
    +
    + +
      +
    • + + + + + +
      +
      + <%= link_to "huang",home_path%>对我评价了:  +
      +
      + 新建问题的时候存在一个bug,需要解决卡涵盖的垃圾卡拉格德国的萨嘎... +
       
      +
    • +
    +
    +
    + <%= link_to"更多",:contoller=>'project',:action=>'index'%> +
    + + +
    +
    +

    <%= link_to l(:label_activity), :controller => 'activities', + :action => 'index', :id => nil, :user_id => @user, + :from => @events_by_day.keys.first %>

    +
    +
    + + +
    + <% @events_by_day.keys.sort.reverse.each do |day| %> + +
      + <% @events_by_day[day].sort {|x,y| y.event_datetime <=> x.event_datetime }.each do |e| -%> +
    • + + + + + + + +
      +
      + <%= content_tag('span', h(e.project), :class => 'project') %> +
      +
      + <%= link_to format_activity_title(e.event_title), e.event_url %> + <%= format_activity_description(e.event_description) %> +
      +
    • + <% end -%> +
    + <% end -%> +
    + + + <% other_formats_links do |f| %> + <%= f.link_to 'Atom', :url => {:controller => 'activities', :action => 'index', :id => nil, :user_id => @user, :key => User.current.rss_key} %> + <% end %> + + <% content_for :header_tags do %> + <%= auto_discovery_link_tag(:atom, :controller => 'activities', :action => 'index', :user_id => @user, :format => :atom, :key => User.current.rss_key) %> + <% end %> + <% end %> + + <%= call_hook :view_account_right_bottom, :user => @user %> + +
    +
    +<% html_title @user.name %> + + + + diff --git a/app/views/users/tag_save.js.erb b/app/views/users/tag_save.js.erb new file mode 100644 index 00000000..da977c14 --- /dev/null +++ b/app/views/users/tag_save.js.erb @@ -0,0 +1,4 @@ +$('#tags_show').html('<%= escape_javascript(render :partial => 'layouts/tag_name',:locals => {:obj => @obj,:non_list_all => false,:object_flag => @obj_flag}) %>'); +$('#put-tag-form').hide(); +$('#name').val(""); + diff --git a/app/views/users/user_activities.html.erb b/app/views/users/user_activities.html.erb new file mode 100644 index 00000000..c70896dc --- /dev/null +++ b/app/views/users/user_activities.html.erb @@ -0,0 +1,45 @@ + + + +<% unless @events_by_day.empty? %> +
    +<% @events_by_day.keys.sort.reverse.each do |day| %> +<% @events_by_day[day].sort {|x,y| y.event_datetime <=> x.event_datetime }.each do |e| -%> + + + + + + <% end %> +
    + + + + + + + + + + + +
    <%= content_tag('span', h(e.project), :class => 'project') %> 有了最新动态 <%= link_to format_activity_title(e.event_title), e.event_url %>

    <%= format_activity_description(e.event_description) %>

    <%= format_activity_day(day) %>
    <% end %> +
    +<% end %> diff --git a/app/views/users/user_comments.html.erb b/app/views/users/user_comments.html.erb new file mode 100644 index 00000000..e69de29b diff --git a/app/views/users/user_newfeedback.html.erb b/app/views/users/user_newfeedback.html.erb new file mode 100644 index 00000000..e2979388 --- /dev/null +++ b/app/views/users/user_newfeedback.html.erb @@ -0,0 +1,8 @@ +
    +
    + <%= render :partial => 'words/message', :locals => {:jour => @jour, :state => @state, :user => @user} %> +
    +
    + <%= render :partial => 'words/new', :locals => {:user => @user, :sta => @state} %> +
    + \ No newline at end of file diff --git a/app/views/users/user_projects.html.erb b/app/views/users/user_projects.html.erb new file mode 100644 index 00000000..b7e0ad2f --- /dev/null +++ b/app/views/users/user_projects.html.erb @@ -0,0 +1,39 @@ +
    +<% unless @memberships.empty? %> +
      + <% for membership in @memberships %> +
    • + + + + + + +
      + + + + + + + + + + + +
      <%= link_to_project(membership.project) %>创建了 <%= link_to_project(membership.project) %>
      +

      + <%= membership.project.description%> +

      <%= format_date(membership.created_on) %><%= h membership.roles.sort.collect(&:to_s).join(', ') %>
      + +
    • + <% end %> +
    + +
    + <%= link_to"更多",:controller=>'projects',:action=>'index'%> +
    +<% else %> +暂无项目,赶快去<%= link_to"新建",:controller=>'projects',:action=>'new'%>吧 +<% end %> +<%= call_hook :view_account_left_bottom, :user => @user %>
    \ No newline at end of file diff --git a/app/views/versions/_form.html.erb b/app/views/versions/_form.html.erb new file mode 100644 index 00000000..db84f07e --- /dev/null +++ b/app/views/versions/_form.html.erb @@ -0,0 +1,16 @@ +<%= back_url_hidden_field_tag %> +<%= error_messages_for 'version' %> + +
    +

    <%= f.text_field :name, :size => 60, :required => true %>

    +

    <%= f.text_field :description, :size => 60 %>

    +

    <%= f.select :status, Version::VERSION_STATUSES.collect {|s| [l("version_status_#{s}"), s]} %>

    +

    <%= f.text_field :wiki_page_title, :label => :label_wiki_page, :size => 60, :disabled => @project.wiki.nil? %>

    +

    <%= f.text_field :effective_date, :size => 10 %><%= calendar_for('version_effective_date') %>

    +

    <%= f.select :sharing, @version.allowed_sharings.collect {|v| [format_version_sharing(v), v]} %>

    + +<% @version.custom_field_values.each do |value| %> +

    <%= custom_field_tag_with_label :version, value %>

    +<% end %> + +
    diff --git a/app/views/versions/_issue_counts.html.erb b/app/views/versions/_issue_counts.html.erb new file mode 100644 index 00000000..002be493 --- /dev/null +++ b/app/views/versions/_issue_counts.html.erb @@ -0,0 +1,33 @@ +<%= form_tag({}, :id => "status_by_form") do -%> +
    + +<%= l(:label_issues_by, + select_tag('status_by', + status_by_options_for_select(criteria), + :id => 'status_by_select', + :data => {:remote => true, :method => 'post', :url => status_by_version_path(version)})).html_safe %> + +<% if counts.empty? %> +

    <%= l(:label_no_data) %>

    +<% else %> + + <% counts.each do |count| %> + + + + + <% end %> +
    + <% if count[:group] -%> + <%= link_to(h(count[:group]), project_issues_path(version.project, :set_filter => 1, :status_id => '*', :fixed_version_id => version, "#{criteria}_id" => count[:group])) %> + <% else -%> + <%= link_to(l(:label_none), project_issues_path(version.project, :set_filter => 1, :status_id => '*', :fixed_version_id => version, "#{criteria}_id" => "!*")) %> + <% end %> + + <%= progress_bar((count[:closed].to_f / count[:total])*100, + :legend => "#{count[:closed]}/#{count[:total]}", + :width => "#{(count[:total].to_f / max * 200).floor}px;") %> +
    +<% end %> +
    +<% end %> diff --git a/app/views/versions/_new_modal.html.erb b/app/views/versions/_new_modal.html.erb new file mode 100644 index 00000000..99fef84e --- /dev/null +++ b/app/views/versions/_new_modal.html.erb @@ -0,0 +1,9 @@ +

    <%=l(:label_version_new)%>

    + +<%= labelled_form_for @version, :url => project_versions_path(@project), :remote => true do |f| %> +<%= render :partial => 'versions/form', :locals => { :f => f } %> +

    + <%= submit_tag l(:button_create), :name => nil %> + <%= submit_tag l(:button_cancel), :name => nil, :onclick => "hideModal(this);", :type => 'button' %> +

    +<% end %> diff --git a/app/views/versions/_overview.html.erb b/app/views/versions/_overview.html.erb new file mode 100644 index 00000000..4203a846 --- /dev/null +++ b/app/views/versions/_overview.html.erb @@ -0,0 +1,32 @@ +<% if version.completed? %> +

    <%= format_date(version.effective_date) %>

    +<% elsif version.effective_date %> +

    <%= due_date_distance_in_words(version.effective_date) %> (<%= format_date(version.effective_date) %>)

    +<% end %> + +

    <%=h version.description %>

    +<% if version.custom_field_values.any? %> +
      + <% version.custom_field_values.each do |custom_value| %> + <% if custom_value.value.present? %> +
    • <%=h custom_value.custom_field.name %>: <%=h show_value(custom_value) %>
    • + <% end %> + <% end %> +
    +<% end %> + +<% if version.issues_count > 0 %> + <%= progress_bar([version.closed_percent, version.completed_percent], :width => '40em', :legend => ('%0.0f%' % version.completed_percent)) %> +

    + <%= link_to(l(:label_x_issues, :count => version.issues_count), + project_issues_path(version.project, :status_id => '*', :fixed_version_id => version, :set_filter => 1)) %> +   + (<%= link_to_if(version.closed_issues_count > 0, l(:label_x_closed_issues_abbr, :count => version.closed_issues_count), + project_issues_path(version.project, :status_id => 'c', :fixed_version_id => version, :set_filter => 1)) %> + — + <%= link_to_if(version.open_issues_count > 0, l(:label_x_open_issues_abbr, :count => version.open_issues_count), + project_issues_path(version.project, :status_id => 'o', :fixed_version_id => version, :set_filter => 1)) %>) +

    +<% else %> +

    <%= l(:label_roadmap_no_issues) %>

    +<% end %> diff --git a/app/views/versions/create.js.erb b/app/views/versions/create.js.erb new file mode 100644 index 00000000..e6e0bec4 --- /dev/null +++ b/app/views/versions/create.js.erb @@ -0,0 +1,3 @@ +hideModal(); +<% select = content_tag('select', content_tag('option') + version_options_for_select(@project.shared_versions.open, @version), :id => 'issue_fixed_version_id', :name => 'issue[fixed_version_id]') %> +$('#issue_fixed_version_id').replaceWith('<%= escape_javascript(select) %>'); diff --git a/app/views/versions/edit.html.erb b/app/views/versions/edit.html.erb new file mode 100644 index 00000000..39db07c9 --- /dev/null +++ b/app/views/versions/edit.html.erb @@ -0,0 +1,7 @@ +

    <%=l(:label_version)%>

    + +<%= labelled_form_for @version do |f| %> +<%= render :partial => 'form', :locals => { :f => f } %> +<%= submit_tag l(:button_save) %> +<% end %> + diff --git a/app/views/versions/index.api.rsb b/app/views/versions/index.api.rsb new file mode 100644 index 00000000..3adde2b9 --- /dev/null +++ b/app/views/versions/index.api.rsb @@ -0,0 +1,19 @@ +api.array :versions, api_meta(:total_count => @versions.size) do + @versions.each do |version| + api.version do + api.id version.id + api.project(:id => version.project_id, :name => version.project.name) unless version.project.nil? + + api.name version.name + api.description version.description + api.status version.status + api.due_date version.effective_date + api.sharing version.sharing + + render_api_custom_values version.custom_field_values, api + + api.created_on version.created_on + api.updated_on version.updated_on + end + end +end diff --git a/app/views/versions/index.html.erb b/app/views/versions/index.html.erb new file mode 100644 index 00000000..e1b29fa9 --- /dev/null +++ b/app/views/versions/index.html.erb @@ -0,0 +1,68 @@ +
    + <%= link_to l(:label_version_new), new_project_version_path(@project), :class => 'icon icon-add' if User.current.allowed_to?(:manage_versions, @project) %> +
    + +

    <%=l(:label_roadmap)%>

    + +<% if @versions.empty? %> +

    <%= l(:label_no_data) %>

    +<% else %> +
    +<% @versions.each do |version| %> +

    <%= link_to_version version, :name => version_anchor(version) %>

    + <%= render :partial => 'versions/overview', :locals => {:version => version} %> + <%= render(:partial => "wiki/content", :locals => {:content => version.wiki_page.content}) if version.wiki_page %> + + <% if (issues = @issues_by_version[version]) && issues.size > 0 %> + <%= form_tag({}) do -%> + + + <% issues.each do |issue| -%> + + + + + <% end -%> + + <% end %> + <% end %> + <%= call_hook :view_projects_roadmap_version_bottom, :version => version %> +<% end %> +
    +<% end %> + +<% content_for :sidebar do %> +<%= form_tag({}, :method => :get) do %> +

    <%= l(:label_roadmap) %>

    +<% @trackers.each do |tracker| %> +
    +<% end %> +
    + +<% if @project.descendants.active.any? %> + <%= hidden_field_tag 'with_subprojects', 0 %> +
    +<% end %> +

    <%= submit_tag l(:button_apply), :class => 'button-small', :name => nil %>

    +<% end %> + +

    <%= l(:label_version_plural) %>

    +<% @versions.each do |version| %> +<%= link_to format_version_name(version), "##{version_anchor(version)}" %>
    +<% end %> +<% if @completed_versions.present? %> +

    + <%= link_to_function l(:label_completed_versions), + '$("#toggle-completed-versions").toggleClass("collapsed"); $("#completed-versions").toggle()', + :id => 'toggle-completed-versions', :class => 'collapsible collapsed' %>
    + +

    +<% end %> +<% end %> + +<% html_title(l(:label_roadmap)) %> + +<%= context_menu issues_context_menu_path %> diff --git a/app/views/versions/new.html.erb b/app/views/versions/new.html.erb new file mode 100644 index 00000000..a4b6a114 --- /dev/null +++ b/app/views/versions/new.html.erb @@ -0,0 +1,6 @@ +

    <%=l(:label_version_new)%>

    + +<%= labelled_form_for @version, :url => project_versions_path(@project) do |f| %> +<%= render :partial => 'versions/form', :locals => { :f => f } %> +<%= submit_tag l(:button_create) %> +<% end %> diff --git a/app/views/versions/new.js.erb b/app/views/versions/new.js.erb new file mode 100644 index 00000000..114b9c7c --- /dev/null +++ b/app/views/versions/new.js.erb @@ -0,0 +1,2 @@ +$('#ajax-modal').html('<%= escape_javascript(render :partial => 'versions/new_modal') %>'); +showModal('ajax-modal', '600px'); diff --git a/app/views/versions/show.api.rsb b/app/views/versions/show.api.rsb new file mode 100644 index 00000000..63bf2d37 --- /dev/null +++ b/app/views/versions/show.api.rsb @@ -0,0 +1,15 @@ +api.version do + api.id @version.id + api.project(:id => @version.project_id, :name => @version.project.name) unless @version.project.nil? + + api.name @version.name + api.description @version.description + api.status @version.status + api.due_date @version.effective_date + api.sharing @version.sharing + + render_api_custom_values @version.custom_field_values, api + + api.created_on @version.created_on + api.updated_on @version.updated_on +end diff --git a/app/views/versions/show.html.erb b/app/views/versions/show.html.erb new file mode 100644 index 00000000..2a0fdcc1 --- /dev/null +++ b/app/views/versions/show.html.erb @@ -0,0 +1,55 @@ +
    +<%= link_to(l(:button_edit), edit_version_path(@version), :class => 'icon icon-edit') if User.current.allowed_to?(:manage_versions, @version.project) %> +<%= link_to_if_authorized(l(:button_edit_associated_wikipage, :page_title => @version.wiki_page_title), {:controller => 'wiki', :action => 'edit', :project_id => @version.project, :id => Wiki.titleize(@version.wiki_page_title)}, :class => 'icon icon-edit') unless @version.wiki_page_title.blank? || @version.project.wiki.nil? %> +<%= delete_link version_path(@version, :back_url => url_for(:controller => 'versions', :action => 'index', :project_id => @version.project)) if User.current.allowed_to?(:manage_versions, @version.project) %> +<%= call_hook(:view_versions_show_contextual, { :version => @version, :project => @project }) %> +
    + +

    <%= h(@version.name) %>

    + +
    +<%= render :partial => 'versions/overview', :locals => {:version => @version} %> +<%= render(:partial => "wiki/content", :locals => {:content => @version.wiki_page.content}) if @version.wiki_page %> + +
    +<% if @version.estimated_hours > 0 || User.current.allowed_to?(:view_time_entries, @project) %> +
    <%= l(:label_time_tracking) %> + + + + + +<% if User.current.allowed_to?(:view_time_entries, @project) %> + + + + +<% end %> +
    <%= l(:field_estimated_hours) %><%= html_hours(l_hours(@version.estimated_hours)) %>
    <%= l(:label_spent_time) %><%= html_hours(l_hours(@version.spent_hours)) %>
    +
    +<% end %> + +
    +<%= render_issue_status_by(@version, params[:status_by]) if @version.fixed_issues.count > 0 %> +
    +
    + +<% if @issues.present? %> +<%= form_tag({}) do -%> + + + <%- @issues.each do |issue| -%> + + + + + <% end %> + +<% end %> +<%= context_menu issues_context_menu_path %> +<% end %> +
    + +<%= call_hook :view_versions_show_bottom, :version => @version %> + +<% html_title @version.name %> diff --git a/app/views/versions/status_by.js.erb b/app/views/versions/status_by.js.erb new file mode 100644 index 00000000..94e01279 --- /dev/null +++ b/app/views/versions/status_by.js.erb @@ -0,0 +1 @@ +$('#status_by').html('<%= escape_javascript(render_issue_status_by(@version, params[:status_by])) %>'); diff --git a/app/views/watchers/_new.html.erb b/app/views/watchers/_new.html.erb new file mode 100644 index 00000000..9fdf7926 --- /dev/null +++ b/app/views/watchers/_new.html.erb @@ -0,0 +1,27 @@ +

    <%= l(:permission_add_issue_watchers) %>

    + +<%= form_tag({:controller => 'watchers', + :action => (watched ? 'create' : 'append'), + :object_type => (watched && watched.class.name.underscore), + :object_id => watched, + :project_id => @project}, + :remote => true, + :method => :post, + :id => 'new-watcher-form') do %> + +

    <%= label_tag 'user_search', l(:label_user_search) %><%= text_field_tag 'user_search', nil %>

    + <%= javascript_tag "observeSearchfield('user_search', 'users_for_watcher', '#{ escape_javascript url_for(:controller => 'watchers', + :action => 'autocomplete_for_user', + :object_type => (watched && watched.class.name.underscore), + :object_id => watched, + :project_id => @project) }')" %> + +
    + <%= principals_check_box_tags 'watcher[user_ids][]', (watched ? watched.addable_watcher_users : User.active.all(:limit => 100)) %> +
    + +

    + <%= submit_tag l(:button_add), :name => nil, :onclick => "hideModal(this);" %> + <%= submit_tag l(:button_cancel), :name => nil, :onclick => "hideModal(this);", :type => 'button' %> +

    +<% end %> diff --git a/app/views/watchers/_set_watcher.js.erb b/app/views/watchers/_set_watcher.js.erb new file mode 100644 index 00000000..e5cdc4f3 --- /dev/null +++ b/app/views/watchers/_set_watcher.js.erb @@ -0,0 +1,2 @@ +<% selector = ".#{watcher_css(watched)}" %> +$("<%= selector %>").each(function(){$(this).replaceWith("<%= escape_javascript watcher_link(watched, user) %>")}); diff --git a/app/views/watchers/_watchers.html.erb b/app/views/watchers/_watchers.html.erb new file mode 100644 index 00000000..697d0bd8 --- /dev/null +++ b/app/views/watchers/_watchers.html.erb @@ -0,0 +1,12 @@ +<% if User.current.allowed_to?(:add_issue_watchers, @project) %> +
    +<%= link_to l(:button_add), + {:controller => 'watchers', :action => 'new', :object_type => watched.class.name.underscore, :object_id => watched}, + :remote => true, + :method => 'get' %> +
    +<% end %> + +

    <%= l(:label_issue_watchers) %> (<%= watched.watcher_users.size %>)

    + +<%= watchers_list(watched) %> diff --git a/app/views/watchers/append.js.erb b/app/views/watchers/append.js.erb new file mode 100644 index 00000000..934865df --- /dev/null +++ b/app/views/watchers/append.js.erb @@ -0,0 +1,4 @@ +<% @users.each do |user| %> + $("#issue_watcher_user_ids_<%= user.id %>").remove(); +<% end %> +$('#watchers_inputs').append('<%= escape_javascript(watchers_checkboxes(nil, @users, true)) %>'); diff --git a/app/views/watchers/autocomplete_for_user.html.erb b/app/views/watchers/autocomplete_for_user.html.erb new file mode 100644 index 00000000..a24d28eb --- /dev/null +++ b/app/views/watchers/autocomplete_for_user.html.erb @@ -0,0 +1 @@ +<%= principals_check_box_tags 'watcher[user_ids][]', @users %> diff --git a/app/views/watchers/create.js.erb b/app/views/watchers/create.js.erb new file mode 100644 index 00000000..0f7e15a0 --- /dev/null +++ b/app/views/watchers/create.js.erb @@ -0,0 +1,2 @@ +$('#ajax-modal').html('<%= escape_javascript(render(:partial => 'watchers/new', :locals => {:watched => @watched})) %>'); +$('#watchers').html('<%= escape_javascript(render(:partial => 'watchers/watchers', :locals => {:watched => @watched})) %>'); diff --git a/app/views/watchers/destroy.js.erb b/app/views/watchers/destroy.js.erb new file mode 100644 index 00000000..e4d85654 --- /dev/null +++ b/app/views/watchers/destroy.js.erb @@ -0,0 +1 @@ +$('#watchers').html('<%= escape_javascript(render(:partial => 'watchers/watchers', :locals => {:watched => @watched})) %>'); diff --git a/app/views/watchers/new.js.erb b/app/views/watchers/new.js.erb new file mode 100644 index 00000000..6b99f657 --- /dev/null +++ b/app/views/watchers/new.js.erb @@ -0,0 +1,3 @@ +$('#ajax-modal').html('<%= escape_javascript(render :partial => 'watchers/new', :locals => {:watched => @watched}) %>'); +showModal('ajax-modal', '400px'); +$('#ajax-modal').addClass('new-watcher'); diff --git a/app/views/welcome/index.html.erb b/app/views/welcome/index.html.erb new file mode 100644 index 00000000..59f356d9 --- /dev/null +++ b/app/views/welcome/index.html.erb @@ -0,0 +1,69 @@ +
    + + + + +
    + <%= call_hook :view_account_login_top %> +
    + <%= form_tag(signin_path) do %> + <%= back_url_hidden_field_tag %> + + + + + + + + + + <% if Setting.openid? %> + + + + + <% end %> + + + + + + + + +
    <%= text_field_tag 'username', params[:username], :tabindex => '1' %>
    <%= password_field_tag 'password', nil, :tabindex => '2' %>
    <%= text_field_tag "openid_url", nil, :tabindex => '3' %>
    + <% if Setting.autologin? %> + + <% end %> +
    + <% if Setting.lost_password? %> + <%= link_to l(:label_password_lost), lost_password_path %> + <% end %> + + +
    +<% end %> +
    +<%= call_hook :view_account_login_bottom %> + +<% if params[:username].present? %> +<%= javascript_tag "$('#password').focus();" %> +<% else %> +<%= javascript_tag "$('#username').focus();" %> +<% end %> + +
    + + + + + + +
    +

    <%=link_to "发布需求",home_path %>

    +
    +

    <%=link_to "发现开源",home_path %>

    +
    +

    <%=link_to "创建项目",:controller=>'projects',:action=>'index' %>

    +
    +
    diff --git a/app/views/welcome/robots.html.erb b/app/views/welcome/robots.html.erb new file mode 100644 index 00000000..10b54093 --- /dev/null +++ b/app/views/welcome/robots.html.erb @@ -0,0 +1,10 @@ +User-agent: * +<% @projects.each do |p| -%> +Disallow: /projects/<%= p.to_param %>/repository +Disallow: /projects/<%= p.to_param %>/issues +Disallow: /projects/<%= p.to_param %>/activity +<% end -%> +Disallow: /issues/gantt +Disallow: /issues/calendar +Disallow: /activity +Disallow: /search diff --git a/app/views/wiki/_content.html.erb b/app/views/wiki/_content.html.erb new file mode 100644 index 00000000..60b6a745 --- /dev/null +++ b/app/views/wiki/_content.html.erb @@ -0,0 +1,4 @@ +
    + <%= textilizable content, :text, :attachments => content.page.attachments, + :edit_section_links => (@sections_editable && {:controller => 'wiki', :action => 'edit', :project_id => @page.project, :id => @page.title}) %> +
    diff --git a/app/views/wiki/_sidebar.html.erb b/app/views/wiki/_sidebar.html.erb new file mode 100644 index 00000000..b4034d88 --- /dev/null +++ b/app/views/wiki/_sidebar.html.erb @@ -0,0 +1,9 @@ +<% if @wiki && @wiki.sidebar -%> + <%= textilizable @wiki.sidebar.content, :text %> +<% end -%> + +

    <%= l(:label_wiki) %>

    + +<%= link_to l(:field_start_page), {:action => 'show', :id => nil} %>
    +<%= link_to l(:label_index_by_title), {:action => 'index'} %>
    +<%= link_to l(:label_index_by_date), {:controller => 'wiki', :project_id => @project, :action => 'date_index'} %>
    diff --git a/app/views/wiki/annotate.html.erb b/app/views/wiki/annotate.html.erb new file mode 100644 index 00000000..e3c2acd0 --- /dev/null +++ b/app/views/wiki/annotate.html.erb @@ -0,0 +1,41 @@ +
    +<%= link_to(l(:button_edit), {:action => 'edit', :id => @page.title}, :class => 'icon icon-edit') %> +<%= link_to(l(:label_history), + {:action => 'history', :id => @page.title}, :class => 'icon icon-history') %> +
    + +<%= wiki_page_breadcrumb(@page) %> + +

    <%=h @page.pretty_title %>

    + +

    +<%= l(:label_version) %> <%= link_to h(@annotate.content.version), + :action => 'show', :project_id => @project, + :id => @page.title, :version => @annotate.content.version %> +(<%= h(@annotate.content.author ? + @annotate.content.author.name : l(:label_user_anonymous)) + %>, <%= format_time(@annotate.content.updated_on) %>) +

    + +<% colors = Hash.new {|k,v| k[v] = (k.size % 12) } %> + + + +<% line_num = 1 %> +<% @annotate.lines.each do |line| -%> + + + + + + +<% line_num += 1 %> +<% end -%> + +
    <%= line_num %><%= link_to line[0], :controller => 'wiki', + :action => 'show', :project_id => @project, + :id => @page.title, :version => line[0] %><%= h(line[1]) %>
    <%=h line[2] %>
    + +<% content_for :header_tags do %> +<%= stylesheet_link_tag 'scm' %> +<% end %> diff --git a/app/views/wiki/date_index.html.erb b/app/views/wiki/date_index.html.erb new file mode 100644 index 00000000..708e122c --- /dev/null +++ b/app/views/wiki/date_index.html.erb @@ -0,0 +1,36 @@ +
    +<%= watcher_link(@wiki, User.current) %> +
    + +

    <%= l(:label_index_by_date) %>

    + +<% if @pages.empty? %> +

    <%= l(:label_no_data) %>

    +<% end %> + +<% @pages_by_date.keys.sort.reverse.each do |date| %> +

    <%= format_date(date) %>

    +
      +<% @pages_by_date[date].each do |page| %> +
    • <%= link_to h(page.pretty_title), :action => 'show', :id => page.title, :project_id => page.project %>
    • +<% end %> +
    +<% end %> + +<% content_for :sidebar do %> + <%= render :partial => 'sidebar' %> +<% end %> + +<% unless @pages.empty? %> +<% other_formats_links do |f| %> + <%= f.link_to 'Atom', :url => {:controller => 'activities', :action => 'index', :id => @project, :show_wiki_edits => 1, :key => User.current.rss_key} %> + <% if User.current.allowed_to?(:export_wiki_pages, @project) %> + <%= f.link_to('PDF', :url => {:action => 'export', :format => 'pdf'}) %> + <%= f.link_to('HTML', :url => {:action => 'export'}) %> + <% end %> +<% end %> +<% end %> + +<% content_for :header_tags do %> +<%= auto_discovery_link_tag(:atom, :controller => 'activities', :action => 'index', :id => @project, :show_wiki_edits => 1, :format => 'atom', :key => User.current.rss_key) %> +<% end %> diff --git a/app/views/wiki/destroy.html.erb b/app/views/wiki/destroy.html.erb new file mode 100644 index 00000000..6fb19980 --- /dev/null +++ b/app/views/wiki/destroy.html.erb @@ -0,0 +1,22 @@ +<%= wiki_page_breadcrumb(@page) %> + +

    <%=h @page.pretty_title %>

    + +<%= form_tag({}, :method => :delete) do %> +
    +

    <%= l(:text_wiki_page_destroy_question, :descendants => @descendants_count) %>

    +


    + +<% if @reassignable_to.any? %> +
    +: +<%= label_tag "reassign_to_id", l(:description_wiki_subpages_reassign), :class => "hidden-for-sighted" %> +<%= select_tag 'reassign_to_id', wiki_page_options_for_select(@reassignable_to), + :onclick => "$('#todo_reassign').attr('checked', true);" %> +<% end %> +

    +
    + +<%= submit_tag l(:button_apply) %> +<%= link_to l(:button_cancel), :controller => 'wiki', :action => 'show', :project_id => @project, :id => @page.title %> +<% end %> diff --git a/app/views/wiki/diff.html.erb b/app/views/wiki/diff.html.erb new file mode 100644 index 00000000..c1062924 --- /dev/null +++ b/app/views/wiki/diff.html.erb @@ -0,0 +1,27 @@ +
    +<%= link_to(l(:label_history), {:action => 'history', :id => @page.title}, + :class => 'icon icon-history') %> +
    + +<%= wiki_page_breadcrumb(@page) %> + +

    <%= h(@page.pretty_title) %>

    + +

    +<%= l(:label_version) %> <%= link_to @diff.content_from.version, :action => 'show', :id => @page.title, :project_id => @page.project, :version => @diff.content_from.version %> +(<%= @diff.content_from.author ? + @diff.content_from.author.name : l(:label_user_anonymous) + %>, <%= format_time(@diff.content_from.updated_on) %>) +→ +<%= l(:label_version) %> <%= link_to @diff.content_to.version, :action => 'show', + :id => @page.title, :project_id => @page.project, + :version => @diff.content_to.version + %>/<%= @page.content.version %> +(<%= @diff.content_to.author ? + link_to_user(@diff.content_to.author.name) : l(:label_user_anonymous) + %>, <%= format_time(@diff.content_to.updated_on) %>) +

    + +
    +<%= simple_format_without_paragraph @diff.to_html %> +
    diff --git a/app/views/wiki/edit.html.erb b/app/views/wiki/edit.html.erb new file mode 100644 index 00000000..14b863f5 --- /dev/null +++ b/app/views/wiki/edit.html.erb @@ -0,0 +1,46 @@ +<%= wiki_page_breadcrumb(@page) %> + +

    <%= h @page.pretty_title %>

    + +<%= form_for @content, :as => :content, + :url => {:action => 'update', :id => @page.title}, + :html => {:method => :put, :multipart => true, :id => 'wiki_form'} do |f| %> +<%= f.hidden_field :version %> +<% if @section %> +<%= hidden_field_tag 'section', @section %> +<%= hidden_field_tag 'section_hash', @section_hash %> +<% end %> +<%= error_messages_for 'content' %> + +
    +<%= text_area_tag 'content[text]', @text, :cols => 100, :rows => 25, + :class => 'wiki-edit', :accesskey => accesskey(:edit) %> + +<% if @page.safe_attribute_names.include?('parent_id') && @wiki.pages.any? %> + <%= fields_for @page do |fp| %> +

    + + <%= fp.select :parent_id, + content_tag('option', '', :value => '') + + wiki_page_options_for_select(@wiki.pages.all(:include => :parent) - + @page.self_and_descendants, @page.parent) %> +

    + <% end %> +<% end %> + +

    <%= f.text_field :comments, :size => 120 %>

    +

    <%= render :partial => 'attachments/form' %>

    +
    + +

    <%= submit_tag l(:button_save) %> + <%= preview_link({:controller => 'wiki', :action => 'preview', :project_id => @project, :id => @page.title }, 'wiki_form') %>

    +<%= wikitoolbar_for 'content_text' %> +<% end %> + +
    + +<% content_for :header_tags do %> + <%= robot_exclusion_tag %> +<% end %> + +<% html_title @page.pretty_title %> diff --git a/app/views/wiki/export.html.erb b/app/views/wiki/export.html.erb new file mode 100644 index 00000000..7e8d072d --- /dev/null +++ b/app/views/wiki/export.html.erb @@ -0,0 +1,21 @@ + + + +<%=h @page.pretty_title %> + + + + +<%= textilizable @content, :text, :wiki_links => :local %> + + diff --git a/app/views/wiki/export_multiple.html.erb b/app/views/wiki/export_multiple.html.erb new file mode 100644 index 00000000..24b1ad3e --- /dev/null +++ b/app/views/wiki/export_multiple.html.erb @@ -0,0 +1,34 @@ + + + +<%=h @wiki.project.name %> + + + + + +<%= l(:label_index_by_title) %> + + +<% @pages.each do |page| %> +
    + +<%= textilizable page.content ,:text, :wiki_links => :anchor %> +<% end %> + + + diff --git a/app/views/wiki/history.html.erb b/app/views/wiki/history.html.erb new file mode 100644 index 00000000..17cb1911 --- /dev/null +++ b/app/views/wiki/history.html.erb @@ -0,0 +1,42 @@ +<%= wiki_page_breadcrumb(@page) %> + +

    <%= h(@page.pretty_title) %>

    + +

    <%= l(:label_history) %>

    + +<%= form_tag({:controller => 'wiki', :action => 'diff', + :project_id => @page.project, :id => @page.title}, + :method => :get) do %> + + + + + + + + + + + +<% show_diff = @versions.size > 1 %> +<% line_num = 1 %> +<% @versions.each do |ver| %> +"> + + + + + + + + +<% line_num += 1 %> +<% end %> + +
    #<%= l(:field_updated_on) %><%= l(:field_author) %><%= l(:field_comments) %>
    <%= link_to h(ver.version), :action => 'show', :id => @page.title, :project_id => @page.project, :version => ver.version %><%= radio_button_tag('version', ver.version, (line_num==1), :id => "cb-#{line_num}", :onclick => "$('#cbto-#{line_num+1}').attr('checked', true);") if show_diff && (line_num < @versions.size) %><%= radio_button_tag('version_from', ver.version, (line_num==2), :id => "cbto-#{line_num}") if show_diff && (line_num > 1) %><%= format_time(ver.updated_on) %><%= link_to_user ver.author %><%=h ver.comments %> + <%= link_to l(:button_annotate), :action => 'annotate', :id => @page.title, :version => ver.version %> + <%= delete_link wiki_page_path(@page, :version => ver.version) if User.current.allowed_to?(:delete_wiki_pages, @page.project) && @version_count > 1 %> +
    +<%= submit_tag l(:label_view_diff), :class => 'small' if show_diff %> +<%= pagination_links_full @version_pages, @version_count %> +<% end %> diff --git a/app/views/wiki/index.api.rsb b/app/views/wiki/index.api.rsb new file mode 100644 index 00000000..f1035c89 --- /dev/null +++ b/app/views/wiki/index.api.rsb @@ -0,0 +1,13 @@ +api.array :wiki_pages do + @pages.each do |page| + api.wiki_page do + api.title page.title + if page.parent + api.parent :title => page.parent.title + end + api.version page.version + api.created_on page.created_on + api.updated_on page.updated_on + end + end +end diff --git a/app/views/wiki/index.html.erb b/app/views/wiki/index.html.erb new file mode 100644 index 00000000..463c6be9 --- /dev/null +++ b/app/views/wiki/index.html.erb @@ -0,0 +1,35 @@ +
    +<%= watcher_link(@wiki, User.current) %> +
    + +

    <%= l(:label_index_by_title) %>

    + +<% if @pages.empty? %> +

    <%= l(:label_no_data) %>

    +<% end %> + +<%= render_page_hierarchy(@pages_by_parent_id, nil, :timestamp => true) %> + +<% content_for :sidebar do %> + <%= render :partial => 'sidebar' %> +<% end %> + +<% unless @pages.empty? %> +<% other_formats_links do |f| %> + <%= f.link_to 'Atom', + :url => {:controller => 'activities', :action => 'index', + :id => @project, :show_wiki_edits => 1, + :key => User.current.rss_key} %> + <% if User.current.allowed_to?(:export_wiki_pages, @project) %> + <%= f.link_to('PDF', :url => {:action => 'export', :format => 'pdf'}) %> + <%= f.link_to('HTML', :url => {:action => 'export'}) %> + <% end %> +<% end %> +<% end %> + +<% content_for :header_tags do %> +<%= auto_discovery_link_tag( + :atom, :controller => 'activities', :action => 'index', + :id => @project, :show_wiki_edits => 1, :format => 'atom', + :key => User.current.rss_key) %> +<% end %> diff --git a/app/views/wiki/rename.html.erb b/app/views/wiki/rename.html.erb new file mode 100644 index 00000000..ee0e4959 --- /dev/null +++ b/app/views/wiki/rename.html.erb @@ -0,0 +1,21 @@ +<%= wiki_page_breadcrumb(@page) %> + +

    <%= h @original_title %>

    + +<%= error_messages_for 'page' %> + +<%= labelled_form_for :wiki_page, @page, + :url => { :action => 'rename' }, + :html => { :method => :post } do |f| %> +
    +

    <%= f.text_field :title, :required => true, :size => 100 %>

    +

    <%= f.check_box :redirect_existing_links %>

    +

    <%= f.select :parent_id, + content_tag('option', '', :value => '') + + wiki_page_options_for_select( + @wiki.pages.all(:include => :parent) - @page.self_and_descendants, + @page.parent), + :label => :field_parent_title %>

    +
    +<%= submit_tag l(:button_rename) %> +<% end %> diff --git a/app/views/wiki/show.api.rsb b/app/views/wiki/show.api.rsb new file mode 100644 index 00000000..c3531610 --- /dev/null +++ b/app/views/wiki/show.api.rsb @@ -0,0 +1,18 @@ +api.wiki_page do + api.title @page.title + if @page.parent + api.parent :title => @page.parent.title + end + api.text @content.text + api.version @content.version + api.author(:id => @content.author_id, :name => @content.author.name) + api.comments @page.content.comments + api.created_on @page.created_on + api.updated_on @content.updated_on + + api.array :attachments do + @page.attachments.each do |attachment| + render_api_attachment(attachment, api) + end + end if include_in_api_response?('attachments') +end diff --git a/app/views/wiki/show.html.erb b/app/views/wiki/show.html.erb new file mode 100644 index 00000000..b4386b75 --- /dev/null +++ b/app/views/wiki/show.html.erb @@ -0,0 +1,71 @@ +
    +<% if @editable %> +<% if @content.current_version? %> + <%= link_to_if_authorized(l(:button_edit), {:action => 'edit', :id => @page.title}, :class => 'icon icon-edit', :accesskey => accesskey(:edit)) %> + <%= watcher_link(@page, User.current) %> + <%= link_to_if_authorized(l(:button_lock), {:action => 'protect', :id => @page.title, :protected => 1}, :method => :post, :class => 'icon icon-lock') if !@page.protected? %> + <%= link_to_if_authorized(l(:button_unlock), {:action => 'protect', :id => @page.title, :protected => 0}, :method => :post, :class => 'icon icon-unlock') if @page.protected? %> + <%= link_to_if_authorized(l(:button_rename), {:action => 'rename', :id => @page.title}, :class => 'icon icon-move') %> + <%= link_to_if_authorized(l(:button_delete), {:action => 'destroy', :id => @page.title}, :method => :delete, :data => {:confirm => l(:text_are_you_sure)}, :class => 'icon icon-del') %> +<% else %> + <%= link_to_if_authorized(l(:button_rollback), {:action => 'edit', :id => @page.title, :version => @content.version }, :class => 'icon icon-cancel') %> +<% end %> +<% end %> +<%= link_to_if_authorized(l(:label_history), {:action => 'history', :id => @page.title}, :class => 'icon icon-history') %> +
    + +<%= wiki_page_breadcrumb(@page) %> + +<% unless @content.current_version? %> +

    + <%= link_to(("\xc2\xab " + l(:label_previous)), + :action => 'show', :id => @page.title, :project_id => @page.project, + :version => @content.previous.version) + " - " if @content.previous %> + <%= "#{l(:label_version)} #{@content.version}/#{@page.content.version}" %> + <%= '('.html_safe + link_to(l(:label_diff), :controller => 'wiki', :action => 'diff', + :id => @page.title, :project_id => @page.project, + :version => @content.version) + ')'.html_safe if @content.previous %> - + <%= link_to((l(:label_next) + " \xc2\xbb"), :action => 'show', + :id => @page.title, :project_id => @page.project, + :version => @content.next.version) + " - " if @content.next %> + <%= link_to(l(:label_current_version), :action => 'show', :id => @page.title, :project_id => @page.project, :version => nil) %> +
    + <%= @content.author ? link_to_user(@content.author) : l(:label_user_anonymous) + %>, <%= format_time(@content.updated_on) %>
    + <%=h @content.comments %> +

    +
    +<% end %> + +<%= render(:partial => "wiki/content", :locals => {:content => @content}) %> + +<%= link_to_attachments @page %> + +<% if @editable && authorize_for('wiki', 'add_attachment') %> +
    +

    <%= link_to l(:label_attachment_new), {}, :onclick => "$('#add_attachment_form').show(); return false;", + :id => 'attach_files_link' %>

    +<%= form_tag({:controller => 'wiki', :action => 'add_attachment', + :project_id => @project, :id => @page.title}, + :multipart => true, :id => "add_attachment_form", + :style => "display:none;") do %> +
    +

    <%= render :partial => 'attachments/form' %>

    +
    +<%= submit_tag l(:button_add) %> +<%= link_to l(:button_cancel), {}, :onclick => "$('#add_attachment_form').hide(); return false;" %> +<% end %> +
    +<% end %> + +<% other_formats_links do |f| %> + <%= f.link_to 'PDF', :url => {:id => @page.title, :version => params[:version]} %> + <%= f.link_to 'HTML', :url => {:id => @page.title, :version => params[:version]} %> + <%= f.link_to 'TXT', :url => {:id => @page.title, :version => params[:version]} %> +<% end if User.current.allowed_to?(:export_wiki_pages, @project) %> + +<% content_for :sidebar do %> + <%= render :partial => 'sidebar' %> +<% end %> + +<% html_title @page.pretty_title %> diff --git a/app/views/wikis/destroy.html.erb b/app/views/wikis/destroy.html.erb new file mode 100644 index 00000000..04988d86 --- /dev/null +++ b/app/views/wikis/destroy.html.erb @@ -0,0 +1,10 @@ +

    <%=l(:label_confirmation)%>

    + +
    +

    <%= h(@project.name) %>
    <%=l(:text_wiki_destroy_confirmation)%>

    + +<%= form_tag({:controller => 'wikis', :action => 'destroy', :id => @project}) do %> +<%= hidden_field_tag "confirm", 1 %> +<%= submit_tag l(:button_delete) %> +<% end %> +
    diff --git a/app/views/wikis/edit.js.erb b/app/views/wikis/edit.js.erb new file mode 100644 index 00000000..2c765d15 --- /dev/null +++ b/app/views/wikis/edit.js.erb @@ -0,0 +1 @@ +$('#tab-content-wiki').html('<%= escape_javascript(render :partial => 'projects/settings/wiki') %>'); diff --git a/app/views/words/_message.html.erb b/app/views/words/_message.html.erb new file mode 100644 index 00000000..85d30c88 --- /dev/null +++ b/app/views/words/_message.html.erb @@ -0,0 +1,26 @@ +<% if jour.size >0 %> +<% remove_allowed = (User.current.id == jour.first.user_id) %> +<% for journal in jour%> + + + + + +
    + + + + + + + + + + +
    <%=link_to journal.user, user_path(journal.user)%> 给我留言了

    <%= textilizable journal.notes%>

    <%= journal.created_at %><%= link_to(image_tag('comment.png'), {:controller => 'words', :action => 'new', :id => user, :journal_id => journal}, :remote => true, + :method => 'post', :title => l(:button_quote))%><%= link_to(image_tag('delete.png'), {:controller => 'words', :action => 'destroy', :object_id => journal, :user_id => user}, + :remote => true, :method => 'delete', :class => "delete", :title => l(:button_delete)) if remove_allowed || journal.jour_id == User.current.id %>
    +<% end %> +<% end %> + + diff --git a/app/views/words/_new.html.erb b/app/views/words/_new.html.erb new file mode 100644 index 00000000..925ebefa --- /dev/null +++ b/app/views/words/_new.html.erb @@ -0,0 +1,13 @@ +

    <%= l(:label_leave_message_to, :name => "user") %>

    + +<%= form_for("new_form", :remote => true, :url => {:controller => 'words', + :action => 'create', + :user_id => user.id, + :sta => sta}) do |f| %> + +

    <%= label_tag 'user_message', l(:label_leave_message) %><%= f.text_area 'user_message', :rows => 3 %>

    +

    + <%= submit_tag l(:button_leave_meassge), :name => nil %> + <%= submit_tag l(:button_clear), :name => nil, :onclick => "clearMessage('user_message');", :type => 'button' %> +

    +<% end %> diff --git a/app/views/words/back.js.erb b/app/views/words/back.js.erb new file mode 100644 index 00000000..17c8aa9b --- /dev/null +++ b/app/views/words/back.js.erb @@ -0,0 +1 @@ +$('#message').html('<%= escape_javascript(render(:partial => 'words/message', :locals => {:jour => @jour, :state => @state, :user => @user})) %>'); diff --git a/app/views/words/create.js.erb b/app/views/words/create.js.erb new file mode 100644 index 00000000..fa0798a5 --- /dev/null +++ b/app/views/words/create.js.erb @@ -0,0 +1,2 @@ +$('#message').html('<%= escape_javascript(render(:partial => 'words/message', :locals => {:jour => @jour, :state => false, :user => @user})) %>'); +$('#new_form_user_message').val(""); \ No newline at end of file diff --git a/app/views/words/destroy.js.erb b/app/views/words/destroy.js.erb new file mode 100644 index 00000000..d1eeb4d5 --- /dev/null +++ b/app/views/words/destroy.js.erb @@ -0,0 +1 @@ +$('#message').html('<%= escape_javascript(render(:partial => 'words/message', :locals => {:jour => @jour, :state => false, :user => @user})) %>'); diff --git a/app/views/words/more.js.erb b/app/views/words/more.js.erb new file mode 100644 index 00000000..17c8aa9b --- /dev/null +++ b/app/views/words/more.js.erb @@ -0,0 +1 @@ +$('#message').html('<%= escape_javascript(render(:partial => 'words/message', :locals => {:jour => @jour, :state => @state, :user => @user})) %>'); diff --git a/app/views/words/new.js.erb b/app/views/words/new.js.erb new file mode 100644 index 00000000..16fabe66 --- /dev/null +++ b/app/views/words/new.js.erb @@ -0,0 +1,2 @@ +$('#new_form_user_message').val("<%= raw escape_javascript(@content) %>"); +showAndScrollTo("new_form_user_message", "new_form_user_message"); diff --git a/app/views/workflows/_action_menu.html.erb b/app/views/workflows/_action_menu.html.erb new file mode 100644 index 00000000..57728112 --- /dev/null +++ b/app/views/workflows/_action_menu.html.erb @@ -0,0 +1,5 @@ +
    +<%= link_to l(:button_edit), {:action => 'edit'}, :class => 'icon icon-edit' %> +<%= link_to l(:button_copy), {:action => 'copy'}, :class => 'icon icon-copy' %> +<%= link_to l(:field_summary), {:action => 'index'}, :class => 'icon icon-summary' %> +
    diff --git a/app/views/workflows/_form.html.erb b/app/views/workflows/_form.html.erb new file mode 100644 index 00000000..ec015a99 --- /dev/null +++ b/app/views/workflows/_form.html.erb @@ -0,0 +1,41 @@ + + + + + + + + + <% for new_status in @statuses %> + + <% end %> + + + + <% for old_status in @statuses %> + "> + + <% for new_status in @statuses -%> + <% checked = workflows.detect {|w| w.old_status_id == old_status.id && w.new_status_id == new_status.id} %> + + <% end -%> + + <% end %> + +
    + <%= link_to_function(image_tag('toggle_check.png'), "toggleCheckboxesBySelector('table.transitions-#{name} input')", + :title => "#{l(:button_check_all)}/#{l(:button_uncheck_all)}") %> + <%=l(:label_current_status)%> + <%=l(:label_new_statuses_allowed)%>
    + <%= link_to_function(image_tag('toggle_check.png'), "toggleCheckboxesBySelector('table.transitions-#{name} input.new-status-#{new_status.id}')", + :title => "#{l(:button_check_all)}/#{l(:button_uncheck_all)}") %> + <%=h new_status.name %> +
    + <%= link_to_function(image_tag('toggle_check.png'), "toggleCheckboxesBySelector('table.transitions-#{name} input.old-status-#{old_status.id}')", + :title => "#{l(:button_check_all)}/#{l(:button_uncheck_all)}") %> + + <%=h old_status.name %> + + <%= check_box_tag "issue_status[#{ old_status.id }][#{new_status.id}][]", name, checked, + :class => "old-status-#{old_status.id} new-status-#{new_status.id}" %> +
    diff --git a/app/views/workflows/copy.html.erb b/app/views/workflows/copy.html.erb new file mode 100644 index 00000000..64bb5a55 --- /dev/null +++ b/app/views/workflows/copy.html.erb @@ -0,0 +1,40 @@ +<%= render :partial => 'action_menu' %> + +

    <%=l(:label_workflow)%>

    + +<%= form_tag({}, :id => 'workflow_copy_form') do %> +
    +<%= l(:label_copy_source) %> +

    + + <%= select_tag('source_tracker_id', + content_tag('option', "--- #{l(:actionview_instancetag_blank_option)} ---", :value => '') + + content_tag('option', "--- #{ l(:label_copy_same_as_target) } ---", :value => 'any') + + options_from_collection_for_select(@trackers, 'id', 'name', @source_tracker && @source_tracker.id)) %> +

    +

    + + <%= select_tag('source_role_id', + content_tag('option', "--- #{l(:actionview_instancetag_blank_option)} ---", :value => '') + + content_tag('option', "--- #{ l(:label_copy_same_as_target) } ---", :value => 'any') + + options_from_collection_for_select(@roles, 'id', 'name', @source_role && @source_role.id)) %> +

    +
    + +
    +<%= l(:label_copy_target) %> +

    + + <%= select_tag 'target_tracker_ids', + content_tag('option', "--- #{l(:actionview_instancetag_blank_option)} ---", :value => '', :disabled => true) + + options_from_collection_for_select(@trackers, 'id', 'name', @target_trackers && @target_trackers.map(&:id)), :multiple => true %> +

    +

    + + <%= select_tag 'target_role_ids', + content_tag('option', "--- #{l(:actionview_instancetag_blank_option)} ---", :value => '', :disabled => true) + + options_from_collection_for_select(@roles, 'id', 'name', @target_roles && @target_roles.map(&:id)), :multiple => true %> +

    +
    +<%= submit_tag l(:button_copy) %> +<% end %> diff --git a/app/views/workflows/edit.html.erb b/app/views/workflows/edit.html.erb new file mode 100644 index 00000000..9b5e986c --- /dev/null +++ b/app/views/workflows/edit.html.erb @@ -0,0 +1,58 @@ +<%= render :partial => 'action_menu' %> + +

    <%=l(:label_workflow)%>

    + +
    +
      +
    • <%= link_to l(:label_status_transitions), {:action => 'edit', :role_id => @role, :tracker_id => @tracker}, :class => 'selected' %>
    • +
    • <%= link_to l(:label_fields_permissions), {:action => 'permissions', :role_id => @role, :tracker_id => @tracker} %>
    • +
    +
    + +

    <%=l(:text_workflow_edit)%>:

    + +<%= form_tag({}, :method => 'get') do %> +

    + + + + + <%= submit_tag l(:button_edit), :name => nil %> + + <%= hidden_field_tag 'used_statuses_only', '0' %> + + +

    +<% end %> + +<% if @tracker && @role && @statuses.any? %> + <%= form_tag({}, :id => 'workflow_form' ) do %> + <%= hidden_field_tag 'tracker_id', @tracker.id %> + <%= hidden_field_tag 'role_id', @role.id %> + <%= hidden_field_tag 'used_statuses_only', params[:used_statuses_only] %> +
    + <%= render :partial => 'form', :locals => {:name => 'always', :workflows => @workflows['always']} %> + +
    + <%= l(:label_additional_workflow_transitions_for_author) %> +
    + <%= render :partial => 'form', :locals => {:name => 'author', :workflows => @workflows['author']} %> +
    +
    + <%= javascript_tag "hideFieldset($('#author_workflows'))" unless @workflows['author'].present? %> + +
    + <%= l(:label_additional_workflow_transitions_for_assignee) %> +
    + <%= render :partial => 'form', :locals => {:name => 'assignee', :workflows => @workflows['assignee']} %> +
    +
    + <%= javascript_tag "hideFieldset($('#assignee_workflows'))" unless @workflows['assignee'].present? %> +
    + <%= submit_tag l(:button_save) %> + <% end %> +<% end %> + +<% html_title(l(:label_workflow)) -%> diff --git a/app/views/workflows/index.html.erb b/app/views/workflows/index.html.erb new file mode 100644 index 00000000..a1544186 --- /dev/null +++ b/app/views/workflows/index.html.erb @@ -0,0 +1,35 @@ +<%= render :partial => 'action_menu' %> + +

    <%=l(:label_workflow)%>

    + +<% if @workflow_counts.empty? %> +

    <%= l(:label_no_data) %>

    +<% else %> +
    + + + + + <% @workflow_counts.first.last.each do |role, count| %> + + + <% end %> + + + +<% @workflow_counts.each do |tracker, roles| -%> + + + <% roles.each do |role, count| -%> + + <% end -%> + +<% end -%> + +
    + <%= content_tag(role.builtin? ? 'em' : 'span', h(role.name)) %> +
    <%= h tracker %> + <%= link_to((count > 0 ? count : image_tag('false.png')), {:action => 'edit', :role_id => role, :tracker_id => tracker}, :title => l(:button_edit)) %> +
    +
    +<% end %> diff --git a/app/views/workflows/permissions.html.erb b/app/views/workflows/permissions.html.erb new file mode 100644 index 00000000..71339cc1 --- /dev/null +++ b/app/views/workflows/permissions.html.erb @@ -0,0 +1,95 @@ +<%= render :partial => 'action_menu' %> + +

    <%=l(:label_workflow)%>

    + +
    +
      +
    • <%= link_to l(:label_status_transitions), {:action => 'edit', :role_id => @role, :tracker_id => @tracker} %>
    • +
    • <%= link_to l(:label_fields_permissions), {:action => 'permissions', :role_id => @role, :tracker_id => @tracker}, :class => 'selected' %>
    • +
    +
    + +

    <%=l(:text_workflow_edit)%>:

    + +<%= form_tag({}, :method => 'get') do %> +

    + + + + + <%= submit_tag l(:button_edit), :name => nil %> + + <%= hidden_field_tag 'used_statuses_only', '0' %> + +

    +<% end %> + +<% if @tracker && @role && @statuses.any? %> + <%= form_tag({}, :id => 'workflow_form' ) do %> + <%= hidden_field_tag 'tracker_id', @tracker.id %> + <%= hidden_field_tag 'role_id', @role.id %> + <%= hidden_field_tag 'used_statuses_only', params[:used_statuses_only] %> +
    + + + + + + + + + <% for status in @statuses %> + + <% end %> + + + + + + + <% @fields.each do |field, name| %> + "> + + <% for status in @statuses -%> + + <% end -%> + + <% end %> + <% if @custom_fields.any? %> + + + + <% @custom_fields.each do |field| %> + "> + + <% for status in @statuses -%> + + <% end -%> + + <% end %> + <% end %> + +
    + <%=l(:label_issue_status)%>
    + <%=h status.name %> +
    +   + <%= l(:field_core_fields) %> +
    + <%=h name %> <%= content_tag('span', '*', :class => 'required') if field_required?(field) %> + + <%= field_permission_tag(@permissions, status, field) %> +
    +   + <%= l(:label_custom_field_plural) %> +
    + <%=h field.name %> <%= content_tag('span', '*', :class => 'required') if field_required?(field) %> + + <%= field_permission_tag(@permissions, status, field) %> +
    +
    + <%= submit_tag l(:button_save) %> + <% end %> +<% end %> diff --git a/config.ru b/config.ru new file mode 100644 index 00000000..2a89752d --- /dev/null +++ b/config.ru @@ -0,0 +1,4 @@ +# This file is used by Rack-based servers to start the application. + +require ::File.expand_path('../config/environment', __FILE__) +run RedmineApp::Application diff --git a/config/additional_environment.rb b/config/additional_environment.rb new file mode 100644 index 00000000..2a317a39 --- /dev/null +++ b/config/additional_environment.rb @@ -0,0 +1,10 @@ +# Copy this file to additional_environment.rb and add any statements +# that need to be passed to the Rails::Initializer. `config` is +# available in this context. +# +# Example: +# +# config.log_level = :debug +# ... +# + diff --git a/config/additional_environment.rb.example b/config/additional_environment.rb.example new file mode 100644 index 00000000..2a317a39 --- /dev/null +++ b/config/additional_environment.rb.example @@ -0,0 +1,10 @@ +# Copy this file to additional_environment.rb and add any statements +# that need to be passed to the Rails::Initializer. `config` is +# available in this context. +# +# Example: +# +# config.log_level = :debug +# ... +# + diff --git a/config/application.rb b/config/application.rb new file mode 100644 index 00000000..e434bd2a --- /dev/null +++ b/config/application.rb @@ -0,0 +1,62 @@ +require File.expand_path('../boot', __FILE__) + +require 'rails/all' + +if defined?(Bundler) + # If you precompile assets before deploying to production, use this line + Bundler.require(*Rails.groups(:assets => %w(development test))) + # If you want your assets lazily compiled in production, use this line + # Bundler.require(:default, :assets, Rails.env) +end + +module RedmineApp + class Application < Rails::Application + # Settings in config/environments/* take precedence over those specified here. + # Application configuration should go into files in config/initializers + # -- all .rb files in that directory are automatically loaded. + + # Custom directories with classes and modules you want to be autoloadable. + config.autoload_paths += %W(#{config.root}/lib) + + # Only load the plugins named here, in the order given (default is alphabetical). + # :all can be used as a placeholder for all plugins not explicitly named. + # config.plugins = [ :exception_notification, :ssl_requirement, :all ] + + # Activate observers that should always be running. + config.active_record.observers = :message_observer, :issue_observer, :journal_observer, :news_observer, :document_observer, :wiki_content_observer, :comment_observer + + config.active_record.store_full_sti_class = true + config.active_record.default_timezone = :local + + # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone. + # Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC. + # config.time_zone = 'Central Time (US & Canada)' + + # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded. + # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s] + # config.i18n.default_locale = :de + + # Configure the default encoding used in templates for Ruby 1.9. + config.encoding = "utf-8" + + # Configure sensitive parameters which will be filtered from the log file. + config.filter_parameters += [:password] + + # Enable the asset pipeline + config.assets.enabled = false + + # Version of your assets, change this if you want to expire all your assets + config.assets.version = '1.0' + + config.action_mailer.perform_deliveries = false + + # Do not include all helpers + config.action_controller.include_all_helpers = false + + config.session_store :cookie_store, :key => '_redmine_session' + + if File.exists?(File.join(File.dirname(__FILE__), 'additional_environment.rb')) + instance_eval File.read(File.join(File.dirname(__FILE__), 'additional_environment.rb')) + end + end +end diff --git a/config/boot.rb b/config/boot.rb new file mode 100644 index 00000000..4489e586 --- /dev/null +++ b/config/boot.rb @@ -0,0 +1,6 @@ +require 'rubygems' + +# Set up gems listed in the Gemfile. +ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__) + +require 'bundler/setup' if File.exists?(ENV['BUNDLE_GEMFILE']) diff --git a/config/configuration.yml b/config/configuration.yml new file mode 100644 index 00000000..27eb86f6 --- /dev/null +++ b/config/configuration.yml @@ -0,0 +1,206 @@ +# = Redmine configuration file +# +# Each environment has it's own configuration options. If you are only +# running in production, only the production block needs to be configured. +# Environment specific configuration options override the default ones. +# +# Note that this file needs to be a valid YAML file. +# DO NOT USE TABS! Use 2 spaces instead of tabs for identation. +# +# == Outgoing email settings (email_delivery setting) +# +# === Common configurations +# +# ==== Sendmail command +# +# production: +# email_delivery: +# delivery_method: :sendmail +# +# ==== Simple SMTP server at localhost +# +# production: +# email_delivery: +# delivery_method: :smtp +# smtp_settings: +# address: "localhost" +# port: 25 +# +# ==== SMTP server at example.com using LOGIN authentication and checking HELO for foo.com +# +# production: +# email_delivery: +# delivery_method: :smtp +# smtp_settings: +# address: "example.com" +# port: 25 +# authentication: :login +# domain: 'foo.com' +# user_name: 'myaccount' +# password: 'password' +# +# ==== SMTP server at example.com using PLAIN authentication +# +# production: +# email_delivery: +# delivery_method: :smtp +# smtp_settings: +# address: "example.com" +# port: 25 +# authentication: :plain +# domain: 'example.com' +# user_name: 'myaccount' +# password: 'password' +# +# ==== SMTP server at using TLS (GMail) +# +# This might require some additional configuration. See the guides at: +# http://www.redmine.org/projects/redmine/wiki/EmailConfiguration +# +# production: +# email_delivery: +# delivery_method: :smtp +# smtp_settings: +# enable_starttls_auto: true +# address: "smtp.gmail.com" +# port: 587 +# domain: "smtp.gmail.com" # 'your.domain.com' for GoogleApps +# authentication: :plain +# user_name: "your_email@gmail.com" +# password: "your_password" +# +# +# === More configuration options +# +# See the "Configuration options" at the following website for a list of the +# full options allowed: +# +# http://wiki.rubyonrails.org/rails/pages/HowToSendEmailsWithActionMailer + + +# default configuration options for all environments +default: + # Outgoing emails configuration (see examples above) + email_delivery: + delivery_method: :smtp + smtp_settings: + address: smtp.example.net + port: 25 + domain: example.net + authentication: :login + user_name: "redmine@example.net" + password: "redmine" + + # Absolute path to the directory where attachments are stored. + # The default is the 'files' directory in your Redmine instance. + # Your Redmine instance needs to have write permission on this + # directory. + # Examples: + # attachments_storage_path: /var/redmine/files + # attachments_storage_path: D:/redmine/files + attachments_storage_path: + + # Configuration of the autologin cookie. + # autologin_cookie_name: the name of the cookie (default: autologin) + # autologin_cookie_path: the cookie path (default: /) + # autologin_cookie_secure: true sets the cookie secure flag (default: false) + autologin_cookie_name: + autologin_cookie_path: + autologin_cookie_secure: + + # Configuration of SCM executable command. + # + # Absolute path (e.g. /usr/local/bin/hg) or command name (e.g. hg.exe, bzr.exe) + # On Windows + CRuby, *.cmd, *.bat (e.g. hg.cmd, bzr.bat) does not work. + # + # On Windows + JRuby 1.6.2, path which contains spaces does not work. + # For example, "C:\Program Files\TortoiseHg\hg.exe". + # If you want to this feature, you need to install to the path which does not contains spaces. + # For example, "C:\TortoiseHg\hg.exe". + # + # Examples: + # scm_subversion_command: svn # (default: svn) + # scm_mercurial_command: C:\Program Files\TortoiseHg\hg.exe # (default: hg) + # scm_git_command: /usr/local/bin/git # (default: git) + # scm_cvs_command: cvs # (default: cvs) + # scm_bazaar_command: bzr.exe # (default: bzr) + # scm_darcs_command: darcs-1.0.9-i386-linux # (default: darcs) + # + scm_subversion_command: + scm_mercurial_command: + scm_git_command: + scm_cvs_command: + scm_bazaar_command: + scm_darcs_command: + + # Absolute path to the SCM commands errors (stderr) log file. + # The default is to log in the 'log' directory of your Redmine instance. + # Example: + # scm_stderr_log_file: /var/log/redmine_scm_stderr.log + scm_stderr_log_file: + + # Key used to encrypt sensitive data in the database (SCM and LDAP passwords). + # If you don't want to enable data encryption, just leave it blank. + # WARNING: losing/changing this key will make encrypted data unreadable. + # + # If you want to encrypt existing passwords in your database: + # * set the cipher key here in your configuration file + # * encrypt data using 'rake db:encrypt RAILS_ENV=production' + # + # If you have encrypted data and want to change this key, you have to: + # * decrypt data using 'rake db:decrypt RAILS_ENV=production' first + # * change the cipher key here in your configuration file + # * encrypt data using 'rake db:encrypt RAILS_ENV=production' + database_cipher_key: + + # Set this to false to disable plugins' assets mirroring on startup. + # You can use `rake redmine:plugins:assets` to manually mirror assets + # to public/plugin_assets when you install/upgrade a Redmine plugin. + # + #mirror_plugins_assets_on_startup: false + + # Your secret key for verifying cookie session data integrity. If you + # change this key, all old sessions will become invalid! Make sure the + # secret is at least 30 characters and all random, no regular words or + # you'll be exposed to dictionary attacks. + # + # If you have a load-balancing Redmine cluster, you have to use the + # same secret token on each machine. + #secret_token: 'change it to a long random string' + + # Absolute path (e.g. /usr/bin/convert, c:/im/convert.exe) to + # the ImageMagick's `convert` binary. Used to generate attachment thumbnails. + #imagemagick_convert_command: + + # Configuration of RMagcik font. + # + # Redmine uses RMagcik in order to export gantt png. + # You don't need this setting if you don't install RMagcik. + # + # In CJK (Chinese, Japanese and Korean), + # in order to show CJK characters correctly, + # you need to set this configuration. + # + # Because there is no standard font across platforms in CJK, + # you need to set a font installed in your server. + # + # This setting is not necessary in non CJK. + # + # Examples for Japanese: + # Windows: + # rmagick_font_path: C:\windows\fonts\msgothic.ttc + # Linux: + # rmagick_font_path: /usr/share/fonts/ipa-mincho/ipam.ttf + # + rmagick_font_path: + + # Maximum number of simultaneous AJAX uploads + #max_concurrent_ajax_uploads: 2 + +# specific configuration options for production environment +# that overrides the default ones +production: + +# specific configuration options for development environment +# that overrides the default ones +development: diff --git a/config/configuration.yml.example b/config/configuration.yml.example new file mode 100644 index 00000000..27eb86f6 --- /dev/null +++ b/config/configuration.yml.example @@ -0,0 +1,206 @@ +# = Redmine configuration file +# +# Each environment has it's own configuration options. If you are only +# running in production, only the production block needs to be configured. +# Environment specific configuration options override the default ones. +# +# Note that this file needs to be a valid YAML file. +# DO NOT USE TABS! Use 2 spaces instead of tabs for identation. +# +# == Outgoing email settings (email_delivery setting) +# +# === Common configurations +# +# ==== Sendmail command +# +# production: +# email_delivery: +# delivery_method: :sendmail +# +# ==== Simple SMTP server at localhost +# +# production: +# email_delivery: +# delivery_method: :smtp +# smtp_settings: +# address: "localhost" +# port: 25 +# +# ==== SMTP server at example.com using LOGIN authentication and checking HELO for foo.com +# +# production: +# email_delivery: +# delivery_method: :smtp +# smtp_settings: +# address: "example.com" +# port: 25 +# authentication: :login +# domain: 'foo.com' +# user_name: 'myaccount' +# password: 'password' +# +# ==== SMTP server at example.com using PLAIN authentication +# +# production: +# email_delivery: +# delivery_method: :smtp +# smtp_settings: +# address: "example.com" +# port: 25 +# authentication: :plain +# domain: 'example.com' +# user_name: 'myaccount' +# password: 'password' +# +# ==== SMTP server at using TLS (GMail) +# +# This might require some additional configuration. See the guides at: +# http://www.redmine.org/projects/redmine/wiki/EmailConfiguration +# +# production: +# email_delivery: +# delivery_method: :smtp +# smtp_settings: +# enable_starttls_auto: true +# address: "smtp.gmail.com" +# port: 587 +# domain: "smtp.gmail.com" # 'your.domain.com' for GoogleApps +# authentication: :plain +# user_name: "your_email@gmail.com" +# password: "your_password" +# +# +# === More configuration options +# +# See the "Configuration options" at the following website for a list of the +# full options allowed: +# +# http://wiki.rubyonrails.org/rails/pages/HowToSendEmailsWithActionMailer + + +# default configuration options for all environments +default: + # Outgoing emails configuration (see examples above) + email_delivery: + delivery_method: :smtp + smtp_settings: + address: smtp.example.net + port: 25 + domain: example.net + authentication: :login + user_name: "redmine@example.net" + password: "redmine" + + # Absolute path to the directory where attachments are stored. + # The default is the 'files' directory in your Redmine instance. + # Your Redmine instance needs to have write permission on this + # directory. + # Examples: + # attachments_storage_path: /var/redmine/files + # attachments_storage_path: D:/redmine/files + attachments_storage_path: + + # Configuration of the autologin cookie. + # autologin_cookie_name: the name of the cookie (default: autologin) + # autologin_cookie_path: the cookie path (default: /) + # autologin_cookie_secure: true sets the cookie secure flag (default: false) + autologin_cookie_name: + autologin_cookie_path: + autologin_cookie_secure: + + # Configuration of SCM executable command. + # + # Absolute path (e.g. /usr/local/bin/hg) or command name (e.g. hg.exe, bzr.exe) + # On Windows + CRuby, *.cmd, *.bat (e.g. hg.cmd, bzr.bat) does not work. + # + # On Windows + JRuby 1.6.2, path which contains spaces does not work. + # For example, "C:\Program Files\TortoiseHg\hg.exe". + # If you want to this feature, you need to install to the path which does not contains spaces. + # For example, "C:\TortoiseHg\hg.exe". + # + # Examples: + # scm_subversion_command: svn # (default: svn) + # scm_mercurial_command: C:\Program Files\TortoiseHg\hg.exe # (default: hg) + # scm_git_command: /usr/local/bin/git # (default: git) + # scm_cvs_command: cvs # (default: cvs) + # scm_bazaar_command: bzr.exe # (default: bzr) + # scm_darcs_command: darcs-1.0.9-i386-linux # (default: darcs) + # + scm_subversion_command: + scm_mercurial_command: + scm_git_command: + scm_cvs_command: + scm_bazaar_command: + scm_darcs_command: + + # Absolute path to the SCM commands errors (stderr) log file. + # The default is to log in the 'log' directory of your Redmine instance. + # Example: + # scm_stderr_log_file: /var/log/redmine_scm_stderr.log + scm_stderr_log_file: + + # Key used to encrypt sensitive data in the database (SCM and LDAP passwords). + # If you don't want to enable data encryption, just leave it blank. + # WARNING: losing/changing this key will make encrypted data unreadable. + # + # If you want to encrypt existing passwords in your database: + # * set the cipher key here in your configuration file + # * encrypt data using 'rake db:encrypt RAILS_ENV=production' + # + # If you have encrypted data and want to change this key, you have to: + # * decrypt data using 'rake db:decrypt RAILS_ENV=production' first + # * change the cipher key here in your configuration file + # * encrypt data using 'rake db:encrypt RAILS_ENV=production' + database_cipher_key: + + # Set this to false to disable plugins' assets mirroring on startup. + # You can use `rake redmine:plugins:assets` to manually mirror assets + # to public/plugin_assets when you install/upgrade a Redmine plugin. + # + #mirror_plugins_assets_on_startup: false + + # Your secret key for verifying cookie session data integrity. If you + # change this key, all old sessions will become invalid! Make sure the + # secret is at least 30 characters and all random, no regular words or + # you'll be exposed to dictionary attacks. + # + # If you have a load-balancing Redmine cluster, you have to use the + # same secret token on each machine. + #secret_token: 'change it to a long random string' + + # Absolute path (e.g. /usr/bin/convert, c:/im/convert.exe) to + # the ImageMagick's `convert` binary. Used to generate attachment thumbnails. + #imagemagick_convert_command: + + # Configuration of RMagcik font. + # + # Redmine uses RMagcik in order to export gantt png. + # You don't need this setting if you don't install RMagcik. + # + # In CJK (Chinese, Japanese and Korean), + # in order to show CJK characters correctly, + # you need to set this configuration. + # + # Because there is no standard font across platforms in CJK, + # you need to set a font installed in your server. + # + # This setting is not necessary in non CJK. + # + # Examples for Japanese: + # Windows: + # rmagick_font_path: C:\windows\fonts\msgothic.ttc + # Linux: + # rmagick_font_path: /usr/share/fonts/ipa-mincho/ipam.ttf + # + rmagick_font_path: + + # Maximum number of simultaneous AJAX uploads + #max_concurrent_ajax_uploads: 2 + +# specific configuration options for production environment +# that overrides the default ones +production: + +# specific configuration options for development environment +# that overrides the default ones +development: diff --git a/config/database.yml b/config/database.yml new file mode 100644 index 00000000..dd814a4e --- /dev/null +++ b/config/database.yml @@ -0,0 +1,45 @@ +# Default setup is given for MySQL with ruby1.8. If you're running Redmine +# with MySQL and ruby1.9, replace the adapter name with `mysql2`. +# Examples for PostgreSQL and SQLite3 can be found at the end. + +production: + adapter: mysql2 + database: bitnami_redmine + host: 10.0.47.245 + port: 3306 + username: root + password: "bitnami" + encoding: utf8 + +development: + adapter: mysql2 + database: bitnami_redmine + host: 10.0.47.245 + port: 3306 + username: root + password: "bitnami" + encoding: utf8 + +# Warning: The database defined as "test" will be erased and +# re-generated from your development database when you run "rake". +# Do not set this db to the same as development or production. +test: + adapter: mysql2 + database: bitnami_redmine + host: 10.0.47.121 + port: 3306 + username: root + password: "7a9dca93e6" + encoding: utf8 + +test_pgsql: + adapter: postgresql + database: bitnami_redmine + host: 10.0.47.121 + port: 3306 + username: root + password: "1234" + +test_sqlite3: + adapter: sqlite3 + database: bitnami_redmine diff --git a/config/database.yml.example b/config/database.yml.example new file mode 100644 index 00000000..5bcf17bd --- /dev/null +++ b/config/database.yml.example @@ -0,0 +1,52 @@ +# Default setup is given for MySQL with ruby1.9. If you're running Redmine +# with MySQL and ruby1.8, replace the adapter name with `mysql`. +# Examples for PostgreSQL, SQLite3 and SQL Server can be found at the end. +# Line indentation must be 2 spaces (no tabs). + +production: + adapter: mysql2 + database: redmine + host: localhost + username: root + password: "" + encoding: utf8 + +development: + adapter: mysql2 + database: redmine_development + host: localhost + username: root + password: "" + encoding: utf8 + +# Warning: The database defined as "test" will be erased and +# re-generated from your development database when you run "rake". +# Do not set this db to the same as development or production. +test: + adapter: mysql2 + database: redmine_test + host: localhost + username: root + password: "" + encoding: utf8 + +# PostgreSQL configuration example +#production: +# adapter: postgresql +# database: redmine +# host: localhost +# username: postgres +# password: "postgres" + +# SQLite3 configuration example +#production: +# adapter: sqlite3 +# database: db/redmine.sqlite3 + +# SQL Server configuration example +#production: +# adapter: sqlserver +# database: redmine +# host: localhost +# username: jenkins +# password: jenkins diff --git a/config/environment.rb b/config/environment.rb new file mode 100644 index 00000000..1d9a3966 --- /dev/null +++ b/config/environment.rb @@ -0,0 +1,14 @@ +# Load the rails application +require File.expand_path('../application', __FILE__) + +# Make sure there's no plugin in vendor/plugin before starting +vendor_plugins_dir = File.join(Rails.root, "vendor", "plugins") +if Dir.glob(File.join(vendor_plugins_dir, "*")).any? + $stderr.puts "Plugins in vendor/plugins (#{vendor_plugins_dir}) are no longer allowed. " + + "Please, put your Redmine plugins in the `plugins` directory at the root of your " + + "Redmine directory (#{File.join(Rails.root, "plugins")})" + exit 1 +end + +# Initialize the rails application +RedmineApp::Application.initialize! diff --git a/config/environments/development.rb b/config/environments/development.rb new file mode 100644 index 00000000..bd92c555 --- /dev/null +++ b/config/environments/development.rb @@ -0,0 +1,19 @@ +# Settings specified here will take precedence over those in config/application.rb +RedmineApp::Application.configure do + # In the development environment your application's code is reloaded on + # every request. This slows down response time but is perfect for development + # since you don't have to restart the webserver when you make code changes. + config.cache_classes = false + + # Log error messages when you accidentally call methods on nil. + config.whiny_nils = true + + # Show full error reports and disable caching + #config.action_controller.consider_all_requests_local = true + config.action_controller.perform_caching = false + + # Don't care if the mailer can't send + config.action_mailer.raise_delivery_errors = false + + config.active_support.deprecation = :log +end diff --git a/config/environments/production.rb b/config/environments/production.rb new file mode 100644 index 00000000..ab4cd401 --- /dev/null +++ b/config/environments/production.rb @@ -0,0 +1,32 @@ +# Settings specified here will take precedence over those in config/application.rb +RedmineApp::Application.configure do + # The production environment is meant for finished, "live" apps. + # Code is not reloaded between requests + config.cache_classes = true + + ##### + # Customize the default logger (http://ruby-doc.org/core/classes/Logger.html) + # + # Use a different logger for distributed setups + # config.logger = SyslogLogger.new + # + # Rotate logs bigger than 1MB, keeps no more than 7 rotated logs around. + # When setting a new Logger, make sure to set it's log level too. + # + # config.logger = Logger.new(config.log_path, 7, 1048576) + # config.logger.level = Logger::INFO + + # Full error reports are disabled and caching is turned on + config.action_controller.perform_caching = true + + # Enable serving of images, stylesheets, and javascripts from an asset server + # config.action_controller.asset_host = "http://assets.example.com" + + # Disable delivery errors if you bad email addresses should just be ignored + config.action_mailer.raise_delivery_errors = false + + # No email in production log + config.action_mailer.logger = nil + + config.active_support.deprecation = :log +end diff --git a/config/environments/test.rb b/config/environments/test.rb new file mode 100644 index 00000000..b4696385 --- /dev/null +++ b/config/environments/test.rb @@ -0,0 +1,30 @@ +# Settings specified here will take precedence over those in config/application.rb +RedmineApp::Application.configure do + # The test environment is used exclusively to run your application's + # test suite. You never need to work with it otherwise. Remember that + # your test database is "scratch space" for the test suite and is wiped + # and recreated between test runs. Don't rely on the data there! + config.cache_classes = true + + # Log error messages when you accidentally call methods on nil. + config.whiny_nils = true + + # Show full error reports and disable caching + #config.action_controller.consider_all_requests_local = true + config.action_controller.perform_caching = false + + config.action_mailer.perform_deliveries = true + + # Tell Action Mailer not to deliver emails to the real world. + # The :test delivery method accumulates sent emails in the + # ActionMailer::Base.deliveries array. + config.action_mailer.delivery_method = :test + + # Skip protect_from_forgery in requests + # http://m.onkey.org/2007/9/28/csrf-protection-for-your-existing-rails-application + config.action_controller.allow_forgery_protection = false + + config.active_support.deprecation = :log + + config.secret_token = 'a secret token for running the tests' +end diff --git a/config/environments/test_pgsql.rb b/config/environments/test_pgsql.rb new file mode 100644 index 00000000..45cb09bd --- /dev/null +++ b/config/environments/test_pgsql.rb @@ -0,0 +1 @@ +instance_eval File.read(File.join(File.dirname(__FILE__), 'test.rb')) diff --git a/config/environments/test_sqlite3.rb b/config/environments/test_sqlite3.rb new file mode 100644 index 00000000..45cb09bd --- /dev/null +++ b/config/environments/test_sqlite3.rb @@ -0,0 +1 @@ +instance_eval File.read(File.join(File.dirname(__FILE__), 'test.rb')) diff --git a/config/initializers/00-core_plugins.rb b/config/initializers/00-core_plugins.rb new file mode 100644 index 00000000..004c2a1f --- /dev/null +++ b/config/initializers/00-core_plugins.rb @@ -0,0 +1,15 @@ +# Loads the core plugins located in lib/plugins +Dir.glob(File.join(Rails.root, "lib/plugins/*")).sort.each do |directory| + if File.directory?(directory) + lib = File.join(directory, "lib") + if File.directory?(lib) + $:.unshift lib + ActiveSupport::Dependencies.autoload_paths += [lib] + end + initializer = File.join(directory, "init.rb") + if File.file?(initializer) + config = config = RedmineApp::Application.config + eval(File.read(initializer), binding, initializer) + end + end +end diff --git a/config/initializers/10-patches.rb b/config/initializers/10-patches.rb new file mode 100644 index 00000000..79641513 --- /dev/null +++ b/config/initializers/10-patches.rb @@ -0,0 +1,167 @@ +require 'active_record' + +module ActiveRecord + class Base + include Redmine::I18n + # Translate attribute names for validation errors display + def self.human_attribute_name(attr, *args) + attr = attr.to_s.sub(/_id$/, '') + + l("field_#{name.underscore.gsub('/', '_')}_#{attr}", :default => ["field_#{attr}".to_sym, attr]) + end + end + + # Undefines private Kernel#open method to allow using `open` scopes in models. + # See Defect #11545 (http://www.redmine.org/issues/11545) for details. + class Base + class << self + undef open + end + end + class Relation ; undef open ; end +end + +module ActionView + module Helpers + module DateHelper + # distance_of_time_in_words breaks when difference is greater than 30 years + def distance_of_date_in_words(from_date, to_date = 0, options = {}) + from_date = from_date.to_date if from_date.respond_to?(:to_date) + to_date = to_date.to_date if to_date.respond_to?(:to_date) + distance_in_days = (to_date - from_date).abs + + I18n.with_options :locale => options[:locale], :scope => :'datetime.distance_in_words' do |locale| + case distance_in_days + when 0..60 then locale.t :x_days, :count => distance_in_days.round + when 61..720 then locale.t :about_x_months, :count => (distance_in_days / 30).round + else locale.t :over_x_years, :count => (distance_in_days / 365).floor + end + end + end + end + end + + class Resolver + def find_all(name, prefix=nil, partial=false, details={}, key=nil, locals=[]) + cached(key, [name, prefix, partial], details, locals) do + if details[:formats] & [:xml, :json] + details = details.dup + details[:formats] = details[:formats].dup + [:api] + end + find_templates(name, prefix, partial, details) + end + end + end +end + +# Do not HTML escape text templates +module ActionView + class Template + module Handlers + class ERB + def call(template) + if template.source.encoding_aware? + # First, convert to BINARY, so in case the encoding is + # wrong, we can still find an encoding tag + # (<%# encoding %>) inside the String using a regular + # expression + template_source = template.source.dup.force_encoding("BINARY") + + erb = template_source.gsub(ENCODING_TAG, '') + encoding = $2 + + erb.force_encoding valid_encoding(template.source.dup, encoding) + + # Always make sure we return a String in the default_internal + erb.encode! + else + erb = template.source.dup + end + + self.class.erb_implementation.new( + erb, + :trim => (self.class.erb_trim_mode == "-"), + :escape => template.identifier =~ /\.text/ # only escape HTML templates + ).src + end + end + end + end +end + +ActionView::Base.field_error_proc = Proc.new{ |html_tag, instance| html_tag || ''.html_safe } + +require 'mail' + +module DeliveryMethods + class AsyncSMTP < ::Mail::SMTP + def deliver!(*args) + Thread.start do + super *args + end + end + end + + class AsyncSendmail < ::Mail::Sendmail + def deliver!(*args) + Thread.start do + super *args + end + end + end + + class TmpFile + def initialize(*args); end + + def deliver!(mail) + dest_dir = File.join(Rails.root, 'tmp', 'emails') + Dir.mkdir(dest_dir) unless File.directory?(dest_dir) + File.open(File.join(dest_dir, mail.message_id.gsub(/[<>]/, '') + '.eml'), 'wb') {|f| f.write(mail.encoded) } + end + end +end + +ActionMailer::Base.add_delivery_method :async_smtp, DeliveryMethods::AsyncSMTP +ActionMailer::Base.add_delivery_method :async_sendmail, DeliveryMethods::AsyncSendmail +ActionMailer::Base.add_delivery_method :tmp_file, DeliveryMethods::TmpFile + +# Changes how sent emails are logged +# Rails doesn't log cc and bcc which is misleading when using bcc only (#12090) +module ActionMailer + class LogSubscriber < ActiveSupport::LogSubscriber + def deliver(event) + recipients = [:to, :cc, :bcc].inject("") do |s, header| + r = Array.wrap(event.payload[header]) + if r.any? + s << "\n #{header}: #{r.join(', ')}" + end + s + end + info("\nSent email \"#{event.payload[:subject]}\" (%1.fms)#{recipients}" % event.duration) + debug(event.payload[:mail]) + end + end +end + +module ActionController + module MimeResponds + class Collector + def api(&block) + any(:xml, :json, &block) + end + end + end +end + +module ActionController + class Base + # Displays an explicit message instead of a NoMethodError exception + # when trying to start Redmine with an old session_store.rb + # TODO: remove it in a later version + def self.session=(*args) + $stderr.puts "Please remove config/initializers/session_store.rb and run `rake generate_secret_token`.\n" + + "Setting the session secret with ActionController.session= is no longer supported in Rails 3." + exit 1 + end + end +end diff --git a/config/initializers/20-mime_types.rb b/config/initializers/20-mime_types.rb new file mode 100644 index 00000000..cfd35a3e --- /dev/null +++ b/config/initializers/20-mime_types.rb @@ -0,0 +1,4 @@ +# Add new mime types for use in respond_to blocks: + +Mime::SET << Mime::CSV unless Mime::SET.include?(Mime::CSV) + diff --git a/config/initializers/30-redmine.rb b/config/initializers/30-redmine.rb new file mode 100644 index 00000000..1018ca18 --- /dev/null +++ b/config/initializers/30-redmine.rb @@ -0,0 +1,15 @@ +I18n.default_locale = 'en' +I18n.backend = Redmine::I18n::Backend.new + +require 'redmine' + +# Load the secret token from the Redmine configuration file +secret = Redmine::Configuration['secret_token'] +if secret.present? + RedmineApp::Application.config.secret_token = secret +end + +Redmine::Plugin.load +unless Redmine::Configuration['mirror_plugins_assets_on_startup'] == false + Redmine::Plugin.mirror_assets +end diff --git a/config/initializers/backtrace_silencers.rb b/config/initializers/backtrace_silencers.rb new file mode 100644 index 00000000..370315de --- /dev/null +++ b/config/initializers/backtrace_silencers.rb @@ -0,0 +1,7 @@ +# Be sure to restart your server when you modify this file. + +# You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces. +# Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ } + +# You can also remove all the silencers if you're trying do debug a problem that might steem from framework code. +# Rails.backtrace_cleaner.remove_silencers! diff --git a/config/initializers/inflections.rb b/config/initializers/inflections.rb new file mode 100644 index 00000000..d531b8bb --- /dev/null +++ b/config/initializers/inflections.rb @@ -0,0 +1,10 @@ +# Be sure to restart your server when you modify this file. + +# Add new inflection rules using the following format +# (all these examples are active by default): +# ActiveSupport::Inflector.inflections do |inflect| +# inflect.plural /^(ox)$/i, '\1en' +# inflect.singular /^(ox)en/i, '\1' +# inflect.irregular 'person', 'people' +# inflect.uncountable %w( fish sheep ) +# end diff --git a/config/initializers/secret_token.rb b/config/initializers/secret_token.rb new file mode 100644 index 00000000..68cbf0ae --- /dev/null +++ b/config/initializers/secret_token.rb @@ -0,0 +1,11 @@ +# This file was generated by 'rake generate_secret_token', and should +# not be made visible to public. +# If you have a load-balancing Redmine cluster, you will need to use the +# same version of this file on each machine. And be sure to restart your +# server when you modify this file. +# +# Your secret key for verifying cookie session data integrity. If you +# change this key, all old sessions will become invalid! Make sure the +# secret is at least 30 characters and all random, no regular words or +# you'll be exposed to dictionary attacks. +RedmineApp::Application.config.secret_token = '8109e793d9c8233f79ebe3aa09c756d54bf6bffe7043ce1c4bd73928864c72a0b323bc3ccc82493e' diff --git a/config/locales/ar.yml b/config/locales/ar.yml new file mode 100644 index 00000000..52e49492 --- /dev/null +++ b/config/locales/ar.yml @@ -0,0 +1,1089 @@ +ar: + # Text direction: Left-to-Right (ltr) or Right-to-Left (rtl) + direction: rtl + date: + formats: + # Use the strftime parameters for formats. + # When no format has been given, it uses default. + # You can provide other formats here if you like! + default: "%m/%d/%Y" + short: "%b %d" + long: "%B %d, %Y" + + day_names: [الاحد, الاثنين, الثلاثاء, الاربعاء, الخميس, الجمعة, السبت] + abbr_day_names: [أح, اث, ث, ار, خ, ج, س] + + # Don't forget the nil at the beginning; there's no such thing as a 0th month + month_names: [~, كانون الثاني, شباط, آذار, نيسان, أيار, حزيران, تموز, آب, أيلول, تشرين الأول, تشرين الثاني, كانون الأول] + abbr_month_names: [~, كانون الثاني, شباط, آذار, نيسان, أيار, حزيران, تموز, آب, أيلول, تشرين الأول, تشرين الثاني, كانون الأول] + # Used in date_select and datime_select. + order: + - :السنة + - :الشهر + - :اليوم + + time: + formats: + default: "%m/%d/%Y %I:%M %p" + time: "%I:%M %p" + short: "%d %b %H:%M" + long: "%B %d, %Y %H:%M" + am: "صباحا" + pm: "مساءا" + + datetime: + distance_in_words: + half_a_minute: "نصف دقيقة" + less_than_x_seconds: + one: "أقل من ثانية" + other: "ثواني %{count}أقل من " + x_seconds: + one: "ثانية" + other: "%{count}ثواني " + less_than_x_minutes: + one: "أقل من دقيقة" + other: "دقائق%{count}أقل من " + x_minutes: + one: "دقيقة" + other: "%{count} دقائق" + about_x_hours: + one: "حوالي ساعة" + other: "ساعات %{count}حوالي " + x_hours: + one: "1 hour" + other: "%{count} hours" + x_days: + one: "يوم" + other: "%{count} أيام" + about_x_months: + one: "حوالي شهر" + other: "أشهر %{count} حوالي" + x_months: + one: "شهر" + other: "%{count} أشهر" + about_x_years: + one: "حوالي سنة" + other: "سنوات %{count}حوالي " + over_x_years: + one: "اكثر من سنة" + other: "سنوات %{count}أكثر من " + almost_x_years: + one: "تقريبا سنة" + other: "سنوات %{count} نقريبا" + number: + format: + separator: "." + delimiter: "" + precision: 3 + + human: + format: + delimiter: "" + precision: 3 + storage_units: + format: "%n %u" + units: + byte: + one: "Byte" + other: "Bytes" + kb: "KB" + mb: "MB" + gb: "GB" + tb: "TB" + +# Used in array.to_sentence. + support: + array: + sentence_connector: "و" + skip_last_comma: خطأ + + activerecord: + errors: + template: + header: + one: " %{model} خطأ يمنع تخزين" + other: " %{model} يمنع تخزين%{count}خطأ رقم " + messages: + inclusion: "غير مدرجة على القائمة" + exclusion: "محجوز" + invalid: "غير صالح" + confirmation: "غير متطابق" + accepted: "مقبولة" + empty: "لا يمكن ان تكون فارغة" + blank: "لا يمكن ان تكون فارغة" + too_long: " %{count}طويلة جدا، الحد الاقصى هو )" + too_short: " %{count}قصيرة جدا، الحد الادنى هو)" + wrong_length: " %{count}خطأ في الطول، يجب ان يكون )" + taken: "لقد اتخذت سابقا" + not_a_number: "ليس رقما" + not_a_date: "ليس تاريخا صالحا" + greater_than: "%{count}يجب ان تكون اكثر من " + greater_than_or_equal_to: "%{count}يجب ان تكون اكثر من او تساوي" + equal_to: "%{count}يجب ان تساوي" + less_than: " %{count}يجب ان تكون اقل من" + less_than_or_equal_to: " %{count}يجب ان تكون اقل من او تساوي" + odd: "must be odd" + even: "must be even" + greater_than_start_date: "يجب ان تكون اكثر من تاريخ البداية" + not_same_project: "لا ينتمي الى نفس المشروع" + circular_dependency: "هذه العلاقة سوف تخلق علاقة تبعية دائرية" + cant_link_an_issue_with_a_descendant: "لا يمكن ان تكون المشكلة مرتبطة بواحدة من المهام الفرعية" + + actionview_instancetag_blank_option: الرجاء التحديد + + general_text_No: 'لا' + general_text_Yes: 'نعم' + general_text_no: 'لا' + general_text_yes: 'نعم' + general_lang_name: 'Arabic (عربي)' + general_csv_separator: ',' + general_csv_decimal_separator: '.' + general_csv_encoding: ISO-8859-1 + general_pdf_encoding: UTF-8 + general_first_day_of_week: '7' + + notice_account_updated: لقد تم تجديد الحساب بنجاح. + notice_account_invalid_creditentials: اسم المستخدم او كلمة المرور غير صحيحة + notice_account_password_updated: لقد تم تجديد كلمة المرور بنجاح. + notice_account_wrong_password: كلمة المرور غير صحيحة + notice_account_register_done: لقد تم انشاء حسابك بنجاح، الرجاء تأكيد الطلب من البريد الالكتروني + notice_account_unknown_email: مستخدم غير معروف. + notice_can_t_change_password: هذا الحساب يستخدم جهاز خارجي غير مصرح به لا يمكن تغير كلمة المرور + notice_account_lost_email_sent: لقد تم ارسال رسالة على بريدك بالتعليمات اللازمة لتغير كلمة المرور + notice_account_activated: لقد تم تفعيل حسابك، يمكنك الدخول الان + notice_successful_create: لقد تم الانشاء بنجاح + notice_successful_update: لقد تم التحديث بنجاح + notice_successful_delete: لقد تم الحذف بنجاح + notice_successful_connection: لقد تم الربط بنجاح + notice_file_not_found: الصفحة التي تحاول الدخول اليها غير موجوده او تم حذفها + notice_locking_conflict: تم تحديث البيانات عن طريق مستخدم آخر. + notice_not_authorized: غير مصرح لك الدخول الى هذه المنطقة. + notice_not_authorized_archived_project: المشروع الذي تحاول الدخول اليه تم ارشفته + notice_email_sent: "%{value}تم ارسال رسالة الى " + notice_email_error: " (%{value})لقد حدث خطأ ما اثناء ارسال الرسالة الى " + notice_feeds_access_key_reseted: كلمة الدخول RSSلقد تم تعديل . + notice_api_access_key_reseted: كلمة الدخولAPIلقد تم تعديل . + notice_failed_to_save_issues: "فشل في حفظ الملف" + notice_failed_to_save_members: "فشل في حفظ الاعضاء: %{errors}." + notice_no_issue_selected: "لم يتم تحديد شيء، الرجاء تحديد المسألة التي تريد" + notice_account_pending: "لقد تم انشاء حسابك، الرجاء الانتظار حتى تتم الموافقة" + notice_default_data_loaded: تم تحميل التكوين الافتراضي بنجاح + notice_unable_delete_version: غير قادر على مسح النسخة. + notice_unable_delete_time_entry: غير قادر على مسح وقت الدخول. + notice_issue_done_ratios_updated: لقد تم تحديث النسب. + notice_gantt_chart_truncated: " (%{max})لقد تم اقتطاع الرسم البياني لانه تجاوز الاحد الاقصى لعدد العناصر المسموح عرضها " + notice_issue_successful_create: "%{id}لقد تم انشاء " + + + error_can_t_load_default_data: "لم يتم تحميل التكوين الافتراضي كاملا %{value}" + error_scm_not_found: "لم يتم العثور على ادخال في المستودع" + error_scm_command_failed: "حدث خطأ عند محاولة الوصول الى المستودع: %{value}" + error_scm_annotate: "الادخال غير موجود." + error_scm_annotate_big_text_file: "لا يمكن حفظ الادخال لانه تجاوز الحد الاقصى لحجم الملف." + error_issue_not_found_in_project: 'لم يتم العثور على المخرج او انه ينتمي الى مشروع اخر' + error_no_tracker_in_project: 'لا يوجد متتبع لهذا المشروع، الرجاء التحقق من إعدادات المشروع. ' + error_no_default_issue_status: 'لم يتم التعرف على اي وضع افتراضي، الرجاء التحقق من التكوين الخاص بك (اذهب الى إدارة-إصدار الحالات)' + error_can_not_delete_custom_field: غير قادر على حذف الحقل المظلل + error_can_not_delete_tracker: "هذا المتتبع يحتوي على مسائل نشطة ولا يمكن حذفه" + error_can_not_remove_role: "هذا الدور قيد الاستخدام، لا يمكن حذفه" + error_can_not_reopen_issue_on_closed_version: 'لا يمكن إعادة فتح قضية معينه لاصدار مقفل' + error_can_not_archive_project: لا يمكن ارشفة هذا المشروع + error_issue_done_ratios_not_updated: "لم يتم تحديث النسب" + error_workflow_copy_source: 'الرجاء اختيار المتتبع او الادوار' + error_workflow_copy_target: 'الرجاء اختيار هدف المتتبع او هدف الادوار' + error_unable_delete_issue_status: 'غير قادر على حذف حالة القضية' + error_unable_to_connect: "تعذر الاتصال(%{value})" + error_attachment_too_big: " (%{max_size})لا يمكن تحميل هذا الملف، لقد تجاوز الحد الاقصى المسموح به " + warning_attachments_not_saved: "%{count}تعذر حفظ الملف" + + mail_subject_lost_password: " %{value}كلمة المرور الخاصة بك " + mail_body_lost_password: 'لتغير كلمة المرور، انقر على الروابط التالية:' + mail_subject_register: " %{value}تفعيل حسابك " + mail_body_register: 'لتفعيل حسابك، انقر على الروابط التالية:' + mail_body_account_information_external: " %{value}اصبح بامكانك استخدام حسابك للدخول" + mail_body_account_information: معلومات حسابك + mail_subject_account_activation_request: "%{value}طلب تفعيل الحساب " + mail_body_account_activation_request: " (%{value})تم تسجيل حساب جديد، بانتظار الموافقة:" + mail_subject_reminder: "%{count}تم تأجيل المهام التالية " + mail_body_reminder: "%{count}يجب ان تقوم بتسليم المهام التالية :" + mail_subject_wiki_content_added: "'%{id}' تم اضافة صفحة ويكي" + mail_body_wiki_content_added: "The '%{id}' تم اضافة صفحة ويكي من قبل %{author}." + mail_subject_wiki_content_updated: "'%{id}' تم تحديث صفحة ويكي" + mail_body_wiki_content_updated: "The '%{id}'تم تحديث صفحة ويكي من قبل %{author}." + + + field_name: الاسم + field_description: الوصف + field_summary: الملخص + field_is_required: مطلوب + field_firstname: الاسم الاول + field_lastname: الاسم الاخير + field_mail: البريد الالكتروني + field_filename: اسم الملف + field_filesize: حجم الملف + field_downloads: التنزيل + field_author: المؤلف + field_created_on: تم الانشاء في + field_updated_on: تم التحديث + field_field_format: تنسيق الحقل + field_is_for_all: لكل المشروعات + field_possible_values: قيم محتملة + field_regexp: التعبير العادي + field_min_length: الحد الادنى للطول + field_max_length: الحد الاعلى للطول + field_value: القيمة + field_category: الفئة + field_title: العنوان + field_project: المشروع + field_issue: القضية + field_status: الحالة + field_notes: ملاحظات + field_is_closed: القضية مغلقة + field_is_default: القيمة الافتراضية + field_tracker: المتتبع + field_subject: الموضوع + field_due_date: تاريخ الاستحقاق + field_assigned_to: المحال اليه + field_priority: الأولوية + field_fixed_version: الاصدار المستهدف + field_user: المستخدم + field_principal: الرئيسي + field_role: دور + field_homepage: الصفحة الرئيسية + field_is_public: عام + field_parent: مشروع فرعي من + field_is_in_roadmap: القضايا المعروضة في خارطة الطريق + field_login: تسجيل الدخول + field_mail_notification: ملاحظات على البريد الالكتروني + field_admin: المدير + field_last_login_on: اخر اتصال + field_language: لغة + field_effective_date: تاريخ + field_password: كلمة المرور + field_new_password: كلمة المرور الجديدة + field_password_confirmation: تأكيد + field_version: إصدار + field_type: نوع + field_host: المضيف + field_port: المنفذ + field_account: الحساب + field_base_dn: DN قاعدة + field_attr_login: سمة الدخول + field_attr_firstname: سمة الاسم الاول + field_attr_lastname: سمة الاسم الاخير + field_attr_mail: سمة البريد الالكتروني + field_onthefly: إنشاء حساب مستخدم على تحرك + field_start_date: تاريخ البدية + field_done_ratio: "% تم" + field_auth_source: وضع المصادقة + field_hide_mail: إخفاء بريدي الإلكتروني + field_comments: تعليق + field_url: رابط + field_start_page: صفحة البداية + field_subproject: المشروع الفرعي + field_hours: ساعات + field_activity: النشاط + field_spent_on: تاريخ + field_identifier: المعرف + field_is_filter: استخدم كتصفية + field_issue_to: القضايا المتصلة + field_delay: تأخير + field_assignable: يمكن ان تستند القضايا الى هذا الدور + field_redirect_existing_links: إعادة توجيه الروابط الموجودة + field_estimated_hours: الوقت المتوقع + field_column_names: أعمدة + field_time_entries: وقت الدخول + field_time_zone: المنطقة الزمنية + field_searchable: يمكن البحث فيه + field_default_value: القيمة الافتراضية + field_comments_sorting: اعرض التعليقات + field_parent_title: صفحة الوالدين + field_editable: يمكن اعادة تحريره + field_watcher: مراقب + field_identity_url: افتح الرابط الخاص بالهوية الشخصية + field_content: المحتويات + field_group_by: مجموعة النتائج عن طريق + field_sharing: مشاركة + field_parent_issue: مهمة الوالدين + field_member_of_group: "مجموعة المحال" + field_assigned_to_role: "دور المحال" + field_text: حقل نصي + field_visible: غير مرئي + field_warn_on_leaving_unsaved: "الرجاء التحذير عند مغادرة صفحة والنص غير محفوظ" + field_issues_visibility: القضايا المرئية + field_is_private: خاص + field_commit_logs_encoding: رسائل الترميز + field_scm_path_encoding: ترميز المسار + field_path_to_repository: مسار المستودع + field_root_directory: دليل الجذر + field_cvsroot: CVSجذر + field_cvs_module: وحدة + + setting_app_title: عنوان التطبيق + setting_app_subtitle: العنوان الفرعي للتطبيق + setting_welcome_text: نص الترحيب + setting_default_language: اللغة الافتراضية + setting_login_required: مطلوب المصادقة + setting_self_registration: التسجيل الذاتي + setting_attachment_max_size: الحد الاقصى للملفات المرفقة + setting_issues_export_limit: الحد الاقصى لقضايا التصدير + setting_mail_from: انبعاثات عنوان بريدك + setting_bcc_recipients: مستلمين النسخ المخفية (bcc) + setting_plain_text_mail: نص عادي (no HTML) + setting_host_name: اسم ومسار المستخدم + setting_text_formatting: تنسيق النص + setting_wiki_compression: ضغط تاريخ الويكي + setting_feeds_limit: Atom feeds الحد الاقصى لعدد البنود في + setting_default_projects_public: المشاريع الجديده متاحة للجميع افتراضيا + setting_autofetch_changesets: الإحضار التلقائي + setting_sys_api_enabled: من ادارة المستودع WS تمكين + setting_commit_ref_keywords: مرجعية الكلمات المفتاحية + setting_commit_fix_keywords: تصحيح الكلمات المفتاحية + setting_autologin: الدخول التلقائي + setting_date_format: تنسيق التاريخ + setting_time_format: تنسيق الوقت + setting_cross_project_issue_relations: السماح بادارج القضايا في هذا المشروع + setting_issue_list_default_columns: الاعمدة الافتراضية المعروضة في قائمة القضية + setting_repositories_encodings: ترميز المرفقات والمستودعات + setting_emails_header: رأس رسائل البريد الإلكتروني + setting_emails_footer: ذيل رسائل البريد الإلكتروني + setting_protocol: بروتوكول + setting_per_page_options: الكائنات لكل خيارات الصفحة + setting_user_format: تنسيق عرض المستخدم + setting_activity_days_default: الايام المعروضة على نشاط المشروع + setting_display_subprojects_issues: عرض القضايا الفرعية للمشارع الرئيسية بشكل افتراضي + setting_enabled_scm: SCM تمكين + setting_mail_handler_body_delimiters: "اقتطاع رسائل البريد الإلكتروني بعد هذه الخطوط" + setting_mail_handler_api_enabled: للرسائل الواردةWS تمكين + setting_mail_handler_api_key: API مفتاح + setting_sequential_project_identifiers: انشاء معرفات المشروع المتسلسلة + setting_gravatar_enabled: كأيقونة مستخدمGravatar استخدام + setting_gravatar_default: الافتراضيةGravatar صورة + setting_diff_max_lines_displayed: الحد الاقصى لعدد الخطوط + setting_file_max_size_displayed: الحد الأقصى لحجم النص المعروض على الملفات المرفقة + setting_repository_log_display_limit: الحد الاقصى لعدد التنقيحات المعروضة على ملف السجل + setting_openid: السماح بدخول اسم المستخدم المفتوح والتسجيل + setting_password_min_length: الحد الادني لطول كلمة المرور + setting_new_project_user_role_id: الدور المسند الى المستخدم غير المسؤول الذي يقوم بإنشاء المشروع + setting_default_projects_modules: تمكين الوحدات النمطية للمشاريع الجديدة بشكل افتراضي + setting_issue_done_ratio: حساب نسبة القضية المنتهية + setting_issue_done_ratio_issue_field: استخدم حقل القضية + setting_issue_done_ratio_issue_status: استخدم وضع القضية + setting_start_of_week: بدأ التقويم + setting_rest_api_enabled: تمكين باقي خدمات الويب + setting_cache_formatted_text: النص المسبق تنسيقه في ذاكرة التخزين المؤقت + setting_default_notification_option: خيار الاعلام الافتراضي + setting_commit_logtime_enabled: تميكن وقت الدخول + setting_commit_logtime_activity_id: النشاط في وقت الدخول + setting_gantt_items_limit: الحد الاقصى لعدد العناصر المعروضة على المخطط + setting_issue_group_assignment: السماح للإحالة الى المجموعات + setting_default_issue_start_date_to_creation_date: استخدام التاريخ الحالي كتاريخ بدأ للقضايا الجديدة + + permission_add_project: إنشاء مشروع + permission_add_subprojects: إنشاء مشاريع فرعية + permission_edit_project: تعديل مشروع + permission_select_project_modules: تحديد شكل المشروع + permission_manage_members: إدارة الاعضاء + permission_manage_project_activities: ادارة اصدارات المشروع + permission_manage_versions: ادارة الاصدارات + permission_manage_categories: ادارة انواع القضايا + permission_view_issues: عرض القضايا + permission_add_issues: اضافة القضايا + permission_edit_issues: تعديل القضايا + permission_manage_issue_relations: ادارة علاقات القضايا + permission_set_issues_private: تعين قضايا عامة او خاصة + permission_set_own_issues_private: تعين القضايا الخاصة بك كقضايا عامة او خاصة + permission_add_issue_notes: اضافة ملاحظات + permission_edit_issue_notes: تعديل ملاحظات + permission_edit_own_issue_notes: تعديل ملاحظاتك + permission_move_issues: تحريك القضايا + permission_delete_issues: حذف القضايا + permission_manage_public_queries: ادارة الاستعلامات العامة + permission_save_queries: حفظ الاستعلامات + permission_view_gantt: عرض طريقة"جانت" + permission_view_calendar: عرض التقويم + permission_view_issue_watchers: عرض قائمة المراقبين + permission_add_issue_watchers: اضافة مراقبين + permission_delete_issue_watchers: حذف مراقبين + permission_log_time: الوقت المستغرق بالدخول + permission_view_time_entries: عرض الوقت المستغرق + permission_edit_time_entries: تعديل الدخولات الزمنية + permission_edit_own_time_entries: تعديل الدخولات الشخصية + permission_manage_news: ادارة الاخبار + permission_comment_news: اخبار التعليقات + permission_view_documents: عرض المستندات + permission_manage_files: ادارة الملفات + permission_view_files: عرض الملفات + permission_manage_wiki: ادارة ويكي + permission_rename_wiki_pages: اعادة تسمية صفحات ويكي + permission_delete_wiki_pages: حذق صفحات ويكي + permission_view_wiki_pages: عرض ويكي + permission_view_wiki_edits: عرض تاريخ ويكي + permission_edit_wiki_pages: تعديل صفحات ويكي + permission_delete_wiki_pages_attachments: حذف المرفقات + permission_protect_wiki_pages: حماية صفحات ويكي + permission_manage_repository: ادارة المستودعات + permission_browse_repository: استعراض المستودعات + permission_view_changesets: عرض طاقم التغيير + permission_commit_access: الوصول + permission_manage_boards: ادارة المنتديات + permission_view_messages: عرض الرسائل + permission_add_messages: نشر الرسائل + permission_edit_messages: تحرير الرسائل + permission_edit_own_messages: تحرير الرسائل الخاصة + permission_delete_messages: حذف الرسائل + permission_delete_own_messages: حذف الرسائل الخاصة + permission_export_wiki_pages: تصدير صفحات ويكي + permission_manage_subtasks: ادارة المهام الفرعية + + project_module_issue_tracking: تعقب القضايا + project_module_time_tracking: التعقب الزمني + project_module_news: الاخبار + project_module_documents: المستندات + project_module_files: الملفات + project_module_wiki: ويكي + project_module_repository: المستودع + project_module_boards: المنتديات + project_module_calendar: التقويم + project_module_gantt: جانت + + label_user: المستخدم + label_user_plural: المستخدمين + label_user_new: مستخدم جديد + label_user_anonymous: مجهول الهوية + label_project: مشروع + label_project_new: مشروع جديد + label_project_plural: مشاريع + label_x_projects: + zero: لا يوجد مشاريع + one: مشروع واحد + other: "%{count} مشاريع" + label_project_all: كل المشاريع + label_project_latest: احدث المشاريع + label_issue: قضية + label_issue_new: قضية جديدة + label_issue_plural: قضايا + label_issue_view_all: عرض كل القضايا + label_issues_by: " %{value}القضية لصحابها" + label_issue_added: تم اضافة القضية + label_issue_updated: تم تحديث القضية + label_issue_note_added: تم اضافة الملاحظة + label_issue_status_updated: تم تحديث الحالة + label_issue_priority_updated: تم تحديث الاولويات + label_document: مستند + label_document_new: مستند جديد + label_document_plural: مستندات + label_document_added: تم اضافة مستند + label_role: دور + label_role_plural: ادوار + label_role_new: دور جديد + label_role_and_permissions: الادوار والاذن + label_role_anonymous: مجهول الهوية + label_role_non_member: ليس عضو + label_member: عضو + label_member_new: عضو جديد + label_member_plural: اعضاء + label_tracker: المتتبع + label_tracker_plural: المتتبعين + label_tracker_new: متتبع جديد + label_workflow: سير العمل + label_issue_status: وضع القضية + label_issue_status_plural: اوضاع القضية + label_issue_status_new: وضع جديد + label_issue_category: نوع القضية + label_issue_category_plural: انواع القضايا + label_issue_category_new: نوع جديد + label_custom_field: تخصيص حقل + label_custom_field_plural: تخصيص حقول + label_custom_field_new: حقل مخصص جديد + label_enumerations: التعدادات + label_enumeration_new: قيمة جديدة + label_information: معلومة + label_information_plural: معلومات + label_please_login: برجى تسجيل الدخول + label_register: تسجيل + label_login_with_open_id_option: او الدخول بهوية مفتوحة + label_password_lost: فقدت كلمة السر + label_home: الصفحة الرئيسية + label_my_page: الصفحة الخاصة بي + label_my_account: حسابي + label_my_projects: مشاريعي الخاصة + label_my_page_block: حجب صفحتي الخاصة + label_administration: الإدارة + label_login: تسجيل الدخول + label_logout: تسجيل الخروج + label_help: مساعدة + label_reported_issues: أبلغ القضايا + label_assigned_to_me_issues: المسائل المعنية إلى + label_last_login: آخر اتصال + label_registered_on: مسجل على + label_activity: النشاط + label_overall_activity: النشاط العام + label_user_activity: "قيمة النشاط" + label_new: جديدة + label_logged_as: تم تسجيل دخولك + label_environment: البيئة + label_authentication: المصادقة + label_auth_source: وضع المصادقة + label_auth_source_new: وضع مصادقة جديدة + label_auth_source_plural: أوضاع المصادقة + label_subproject_plural: مشاريع فرعية + label_subproject_new: مشروع فرعي جديد + label_and_its_subprojects: "قيمةالمشاريع الفرعية الخاصة بك" + label_min_max_length: الحد الاقصى والادنى للطول + label_list: قائمة + label_date: تاريخ + label_integer: عدد صحيح + label_float: تعويم + label_boolean: منطقية + label_string: النص + label_text: نص طويل + label_attribute: سمة + label_attribute_plural: السمات + label_no_data: لا توجد بيانات للعرض + label_change_status: تغيير الوضع + label_history: التاريخ + label_attachment: الملف + label_attachment_new: ملف جديد + label_attachment_delete: حذف الملف + label_attachment_plural: الملفات + label_file_added: الملف المضاف + label_report: تقرير + label_report_plural: التقارير + label_news: الأخبار + label_news_new: إضافة الأخبار + label_news_plural: الأخبار + label_news_latest: آخر الأخبار + label_news_view_all: عرض كل الأخبار + label_news_added: الأخبار المضافة + label_news_comment_added: إضافة التعليقات على أخبار + label_settings: إعدادات + label_overview: لمحة عامة + label_version: الإصدار + label_version_new: الإصدار الجديد + label_version_plural: الإصدارات + label_close_versions: أكملت إغلاق الإصدارات + label_confirmation: تأكيد + label_export_to: 'متوفرة أيضا في:' + label_read: القراءة... + label_public_projects: المشاريع العامة + label_open_issues: فتح قضية + label_open_issues_plural: فتح قضايا + label_closed_issues: قضية مغلقة + label_closed_issues_plural: قضايا مغلقة + label_x_open_issues_abbr_on_total: + zero: 0 مفتوح / %{total} + one: 1 مفتوح / %{total} + other: "%{count} مفتوح / %{total}" + label_x_open_issues_abbr: + zero: 0 مفتوح + one: 1 مقتوح + other: "%{count} مفتوح" + label_x_closed_issues_abbr: + zero: 0 مغلق + one: 1 مغلق + other: "%{count} مغلق" + label_total: الإجمالي + label_permissions: أذونات + label_current_status: الوضع الحالي + label_new_statuses_allowed: يسمح بادراج حالات جديدة + label_all: جميع + label_none: لا شيء + label_nobody: لا أحد + label_next: القادم + label_previous: السابق + label_used_by: التي يستخدمها + label_details: التفاصيل + label_add_note: إضافة ملاحظة + label_per_page: كل صفحة + label_calendar: التقويم + label_months_from: بعد أشهر من + label_gantt: جانت + label_internal: الداخلية + label_last_changes: "آخر التغييرات %{count}" + label_change_view_all: عرض كافة التغييرات + label_personalize_page: تخصيص هذه الصفحة + label_comment: تعليق + label_comment_plural: تعليقات + label_x_comments: + zero: لا يوجد تعليقات + one: تعليق واحد + other: "%{count} تعليقات" + label_comment_add: إضافة تعليق + label_comment_added: تم إضافة التعليق + label_comment_delete: حذف التعليقات + label_query: استعلام مخصص + label_query_plural: استعلامات مخصصة + label_query_new: استعلام جديد + label_my_queries: استعلاماتي المخصصة + label_filter_add: إضافة عامل تصفية + label_filter_plural: عوامل التصفية + label_equals: يساوي + label_not_equals: لا يساوي + label_in_less_than: في أقل من + label_in_more_than: في أكثر من + label_greater_or_equal: '>=' + label_less_or_equal: '< =' + label_between: بين + label_in: في + label_today: اليوم + label_all_time: كل الوقت + label_yesterday: بالأمس + label_this_week: هذا الأسبوع + label_last_week: الأسبوع الماضي + label_last_n_days: "ايام %{count} اخر" + label_this_month: هذا الشهر + label_last_month: الشهر الماضي + label_this_year: هذا العام + label_date_range: نطاق التاريخ + label_less_than_ago: أقل من قبل أيام + label_more_than_ago: أكثر من قبل أيام + label_ago: منذ أيام + label_contains: يحتوي على + label_not_contains: لا يحتوي على + label_day_plural: أيام + label_repository: المستودع + label_repository_plural: المستودعات + label_browse: تصفح + label_branch: فرع + label_tag: ربط + label_revision: مراجعة + label_revision_plural: تنقيحات + label_revision_id: " %{value}مراجعة" + label_associated_revisions: التنقيحات المرتبطة + label_added: إضافة + label_modified: تعديل + label_copied: نسخ + label_renamed: إعادة تسمية + label_deleted: حذف + label_latest_revision: آخر تنقيح + label_latest_revision_plural: أحدث المراجعات + label_view_revisions: عرض التنقيحات + label_view_all_revisions: عرض كافة المراجعات + label_max_size: الحد الأقصى للحجم + label_sort_highest: التحرك إلى أعلى + label_sort_higher: تحريك لأعلى + label_sort_lower: تحريك لأسفل + label_sort_lowest: الانتقال إلى أسفل + label_roadmap: خارطة الطريق + label_roadmap_due_in: " %{value}تستحق في " + label_roadmap_overdue: "%{value}تأخير" + label_roadmap_no_issues: لا يوجد قضايا لهذا الإصدار + label_search: البحث + label_result_plural: النتائج + label_all_words: كل الكلمات + label_wiki: ويكي + label_wiki_edit: تحرير ويكي + label_wiki_edit_plural: عمليات تحرير ويكي + label_wiki_page: صفحة ويكي + label_wiki_page_plural: ويكي صفحات + label_index_by_title: الفهرس حسب العنوان + label_index_by_date: الفهرس حسب التاريخ + label_current_version: الإصدار الحالي + label_preview: معاينة + label_feed_plural: موجز ويب + label_changes_details: تفاصيل جميع التغييرات + label_issue_tracking: تعقب القضايا + label_spent_time: أمضى بعض الوقت + label_overall_spent_time: الوقت الذي تم انفاقه كاملا + label_f_hour: "%{value} ساعة" + label_f_hour_plural: "%{value} ساعات" + label_time_tracking: تعقب الوقت + label_change_plural: التغييرات + label_statistics: إحصاءات + label_commits_per_month: يثبت في الشهر + label_commits_per_author: يثبت لكل مؤلف + label_diff: الاختلافات + label_view_diff: عرض الاختلافات + label_diff_inline: مضمنة + label_diff_side_by_side: جنبا إلى جنب + label_options: خيارات + label_copy_workflow_from: نسخ سير العمل من + label_permissions_report: تقرير أذونات + label_watched_issues: شاهد القضايا + label_related_issues: القضايا ذات الصلة + label_applied_status: تطبيق مركز + label_loading: تحميل... + label_relation_new: علاقة جديدة + label_relation_delete: حذف العلاقة + label_relates_to: ذات الصلة إلى + label_duplicates: التكرارات + label_duplicated_by: ازدواج + label_blocks: حظر + label_blocked_by: حظر بواسطة + label_precedes: يسبق + label_follows: يتبع + label_end_to_start: نهاية لبدء + label_end_to_end: نهاية إلى نهاية + label_start_to_start: بدء إلى بدء + label_start_to_end: بداية لنهاية + label_stay_logged_in: تسجيل الدخول في + label_disabled: تعطيل + label_show_completed_versions: أكملت إظهار إصدارات + label_me: لي + label_board: المنتدى + label_board_new: منتدى جديد + label_board_plural: المنتديات + label_board_locked: تأمين + label_board_sticky: لزجة + label_topic_plural: المواضيع + label_message_plural: رسائل + label_message_last: آخر رسالة + label_message_new: رسالة جديدة + label_message_posted: تم اضافة الرسالة + label_reply_plural: الردود + label_send_information: إرسال معلومات الحساب للمستخدم + label_year: سنة + label_month: شهر + label_week: أسبوع + label_date_from: من + label_date_to: إلى + label_language_based: استناداً إلى لغة المستخدم + label_sort_by: " %{value}الترتيب حسب " + label_send_test_email: ارسل رسالة الكترونية كاختبار + label_feeds_access_key: RSS مفتاح دخول + label_missing_feeds_access_key: مفقودRSS مفتاح دخول + label_feeds_access_key_created_on: "RSS تم انشاء مفتاح %{value} منذ" + label_module_plural: الوحدات النمطية + label_added_time_by: " تم اضافته من قبل%{author} %{age} منذ" + label_updated_time_by: " تم تحديثه من قبل%{author} %{age} منذ" + label_updated_time: "تم التحديث %{value} منذ" + label_jump_to_a_project: الانتقال إلى مشروع... + label_file_plural: الملفات + label_changeset_plural: اعدادات التغير + label_default_columns: الاعمدة الافتراضية + label_no_change_option: (أي تغيير) + label_bulk_edit_selected_issues: تحرير القضايا المظللة + label_bulk_edit_selected_time_entries: تعديل كل الإدخالات في كل الاوقات + label_theme: الموضوع + label_default: الافتراضي + label_search_titles_only: البحث في العناوين فقط + label_user_mail_option_all: "جميع الخيارات" + label_user_mail_option_selected: "الخيارات المظللة فقط" + label_user_mail_option_none: "لم يتم تحديد اي خيارات" + label_user_mail_option_only_my_events: "السماح لي فقط بمشاهدة الاحداث الخاصة" + label_user_mail_option_only_assigned: "فقط الخيارات التي تم تعيينها" + label_user_mail_option_only_owner: "فقط للخيارات التي املكها" + label_user_mail_no_self_notified: "لا تريد اعلامك بالتغيرات التي تجريها بنفسك" + label_registration_activation_by_email: حساب التنشيط عبر البريد الإلكتروني + label_registration_manual_activation: تنشيط الحساب اليدوي + label_registration_automatic_activation: تنشيط الحساب التلقائي + label_display_per_page: "لكل صفحة: %{value}" + label_age: العمر + label_change_properties: تغيير الخصائص + label_general: عامة + label_more: أكثر + label_scm: scm + label_plugins: الإضافات + label_ldap_authentication: مصادقة LDAP + label_downloads_abbr: D/L + label_optional_description: وصف اختياري + label_add_another_file: إضافة ملف آخر + label_preferences: تفضيلات + label_chronological_order: في ترتيب زمني + label_reverse_chronological_order: في ترتيب زمني عكسي + label_planning: التخطيط + label_incoming_emails: رسائل البريد الإلكتروني الوارد + label_generate_key: إنشاء مفتاح + label_issue_watchers: المراقبون + label_example: مثال + label_display: العرض + label_sort: فرز + label_ascending: تصاعدي + label_descending: تنازلي + label_date_from_to: من %{start} الى %{end} + label_wiki_content_added: إضافة صفحة ويكي + label_wiki_content_updated: تحديث صفحة ويكي + label_group: مجموعة + label_group_plural: المجموعات + label_group_new: مجموعة جديدة + label_time_entry_plural: أمضى بعض الوقت + label_version_sharing_none: لم يشارك + label_version_sharing_descendants: يشارك + label_version_sharing_hierarchy: مع التسلسل الهرمي للمشروع + label_version_sharing_tree: مع شجرة المشروع + label_version_sharing_system: مع جميع المشاريع + label_update_issue_done_ratios: تحديث قضيةالنسب + label_copy_source: مصدر + label_copy_target: الهدف + label_copy_same_as_target: نفس الهدف + label_display_used_statuses_only: عرض الحالات المستخدمة من قبل هذا "تعقب" فقط + label_api_access_key: مفتاح الوصول إلى API + label_missing_api_access_key: API لم يتم الحصول على مفتاح الوصول + label_api_access_key_created_on: " API إنشاء مفتاح الوصول إلى" + label_profile: الملف الشخصي + label_subtask_plural: المهام الفرعية + label_project_copy_notifications: إرسال إشعار الى البريد الإلكتروني عند نسخ المشروع + label_principal_search: "البحث عن مستخدم أو مجموعة:" + label_user_search: "البحث عن المستخدم:" + label_additional_workflow_transitions_for_author: الانتقالات الإضافية المسموح بها عند المستخدم صاحب البلاغ + label_additional_workflow_transitions_for_assignee: الانتقالات الإضافية المسموح بها عند المستخدم المحال إليه + label_issues_visibility_all: جميع القضايا + label_issues_visibility_public: جميع القضايا الخاصة + label_issues_visibility_own: القضايا التي أنشأها المستخدم + label_git_report_last_commit: اعتماد التقرير الأخير للملفات والدلائل + label_parent_revision: الوالدين + label_child_revision: الطفل + label_export_options: "%{export_format} خيارات التصدير" + + button_login: دخول + button_submit: تثبيت + button_save: حفظ + button_check_all: نحديد الكل + button_uncheck_all: عدم تحديد الكل + button_collapse_all: تقليص الكل + button_expand_all: عرض الكل + button_delete: حذف + button_create: انشاء + button_create_and_continue: انشاء واستمرار + button_test: اختبار + button_edit: تعديل + button_edit_associated_wikipage: "تغير صفحة ويكي: %{page_title}" + button_add: اضافة + button_change: تغير + button_apply: تطبيق + button_clear: واضح + button_lock: قفل + button_unlock: الغاء القفل + button_download: تنزيل + button_list: قائمة + button_view: عرض + button_move: تحرك + button_move_and_follow: تحرك واتبع + button_back: رجوع + button_cancel: إلغاء + button_activate: تنشيط + button_sort: ترتيب + button_log_time: وقت الدخول + button_rollback: الرجوع الى هذا الاصدار + button_watch: يشاهد + button_unwatch: إلغاء المشاهدة + button_reply: رد + button_archive: الارشيف + button_unarchive: إلغاء الارشفة + button_reset: إعادة + button_rename: إعادة التسمية + button_change_password: تغير كلمة المرور + button_copy: نسخ + button_copy_and_follow: نسخ واتباع + button_annotate: تعليق + button_update: تحديث + button_configure: تكوين + button_quote: يقتبس + button_duplicate: يضاعف + button_show: يظهر + button_edit_section: يعدل هذا الجزء + button_export: يستورد + + status_active: نشيط + status_registered: مسجل + status_locked: مقفل + + version_status_open: مفتوح + version_status_locked: مقفل + version_status_closed: مغلق + + field_active: فعال + + text_select_mail_notifications: حدد الامور التي يجب ابلاغك بها عن طريق البريد الالكتروني + text_regexp_info: مثال. ^[A-Z0-9]+$ + text_min_max_length_info: الحد الاقصى والادني لطول المعلومات + text_project_destroy_confirmation: هل أنت متأكد من أنك تريد حذف هذا المشروع والبيانات ذات الصلة؟ + text_subprojects_destroy_warning: "subproject(s): سيتم حذف أيضا." + text_workflow_edit: حدد دوراً وتعقب لتحرير سير العمل + text_are_you_sure: هل أنت متأكد؟ + text_journal_changed: "%{label} تغير %{old} الى %{new}" + text_journal_changed_no_detail: "%{label} تم التحديث" + text_journal_set_to: "%{label} تغير الى %{value}" + text_journal_deleted: "%{label} تم الحذف (%{old})" + text_journal_added: "%{label} %{value} تم الاضافة" + text_tip_issue_begin_day: قضية بدأت اليوم + text_tip_issue_end_day: قضية انتهت اليوم + text_tip_issue_begin_end_day: قضية بدأت وانتهت اليوم + text_caracters_maximum: "%{count} الحد الاقصى." + text_caracters_minimum: "الحد الادنى %{count}" + text_length_between: "الطول %{min} بين %{max} رمز" + text_tracker_no_workflow: لم يتم تحديد سير العمل لهذا المتتبع + text_unallowed_characters: رموز غير مسموحة + text_comma_separated: مسموح رموز متنوعة يفصلها فاصلة . + text_line_separated: مسموح رموز متنوعة يفصلها سطور + text_issues_ref_in_commit_messages: الرجوع واصلاح القضايا في رسائل المشتكين + text_issue_added: "القضية %{id} تم ابلاغها عن طريق %{author}." + text_issue_updated: "القضية %{id} تم تحديثها عن طريق %{author}." + text_wiki_destroy_confirmation: هل انت متأكد من رغبتك في حذف هذا الويكي ومحتوياته؟ + text_issue_category_destroy_question: "بعض القضايا (%{count}) مرتبطة بهذه الفئة، ماذا تريد ان تفعل بها؟" + text_issue_category_destroy_assignments: حذف الفئة + text_issue_category_reassign_to: اعادة تثبيت البنود في الفئة + text_user_mail_option: "بالنسبة للمشاريع غير المحددة، سوف يتم ابلاغك عن المشاريع التي تشاهدها او تشارك بها فقط!" + text_no_configuration_data: "الادوار والمتتبع وحالات القضية ومخطط سير العمل لم يتم تحديد وضعها الافتراضي بعد. " + text_load_default_configuration: احمل الاعدادات الافتراضية + text_status_changed_by_changeset: " طبق التغيرات المعينة على %{value}." + text_time_logged_by_changeset: "تم تطبيق التغيرات المعينة على %{value}." + text_issues_destroy_confirmation: هل انت متأكد من حذف البنود المظللة؟' + text_issues_destroy_descendants_confirmation: "سوف يؤدي هذا الى حذف %{count} المهام الفرعية ايضا." + text_time_entries_destroy_confirmation: "هل انت متأكد من رغبتك في حذف الادخالات الزمنية المحددة؟" + text_select_project_modules: قم بتحديد الوضع المناسب لهذا المشروع:' + text_default_administrator_account_changed: تم تعديل الاعدادات الافتراضية لحساب المدير + text_file_repository_writable: المرفقات قابلة للكتابة + text_plugin_assets_writable: الدليل المساعد قابل للكتابة + text_destroy_time_entries_question: " ساعة على القضية التي تود حذفها، ماذا تريد ان تفعل؟ %{hours} تم تثبيت" + text_destroy_time_entries: قم بحذف الساعات المسجلة + text_assign_time_entries_to_project: ثبت الساعات المسجلة على التقرير + text_reassign_time_entries: 'اعادة تثبيت الساعات المسجلة لهذه القضية:' + text_user_wrote: "%{value} كتب:" + text_enumeration_destroy_question: "%{count} الكائنات المعنية لهذه القيمة" + text_enumeration_category_reassign_to: اعادة تثبيت الكائنات التالية لهذه القيمة:' + text_email_delivery_not_configured: "لم يتم تسليم البريد الالكتروني" + text_diff_truncated: '... لقد تم اقتطلع هذا الجزء لانه تجاوز الحد الاقصى المسموح بعرضه' + text_custom_field_possible_values_info: 'سطر لكل قيمة' + text_wiki_page_nullify_children: "الاحتفاظ بصفحات الطفل كصفحات جذر" + text_wiki_page_destroy_children: "حذف صفحات الطفل وجميع أولادهم" + text_wiki_page_reassign_children: "إعادة تعيين صفحات تابعة لهذه الصفحة الأصلية" + text_own_membership_delete_confirmation: "انت على وشك إزالة بعض أو كافة الأذونات الخاصة بك، لن تكون قادراً على تحرير هذا المشروع بعد ذلك. هل أنت متأكد من أنك تريد المتابعة؟" + text_zoom_in: تصغير + text_zoom_out: تكبير + text_warn_on_leaving_unsaved: "الصفحة تحتوي على نص غير مخزن، سوف يفقد النص اذا تم الخروج من الصفحة." + text_scm_path_encoding_note: "الافتراضي: UTF-8" + text_git_repository_note: مستودع فارغ ومحلي + text_mercurial_repository_note: مستودع محلي + text_scm_command: امر + text_scm_command_version: اصدار + text_scm_config: الرجاء اعادة تشغيل التطبيق + text_scm_command_not_available: الامر غير متوفر، الرجاء التحقق من لوحة التحكم + + default_role_manager: مدير + default_role_developer: مطور + default_role_reporter: مراسل + default_tracker_bug: الشوائب + default_tracker_feature: خاصية + default_tracker_support: دعم + default_issue_status_new: جديد + default_issue_status_in_progress: جاري التحميل + default_issue_status_resolved: الحل + default_issue_status_feedback: التغذية الراجعة + default_issue_status_closed: مغلق + default_issue_status_rejected: مرفوض + default_doc_category_user: مستندات المستخدم + default_doc_category_tech: المستندات التقنية + default_priority_low: قليل + default_priority_normal: عادي + default_priority_high: عالي + default_priority_urgent: طارئ + default_priority_immediate: مباشرة + default_activity_design: تصميم + default_activity_development: تطوير + + enumeration_issue_priorities: الاولويات + enumeration_doc_categories: تصنيف المستندات + enumeration_activities: الانشطة + enumeration_system_activity: نشاط النظام + description_filter: فلترة + description_search: حقل البحث + description_choose_project: مشاريع + description_project_scope: مجال البحث + description_notes: ملاحظات + description_message_content: محتويات الرسالة + description_query_sort_criteria_attribute: نوع الترتيب + description_query_sort_criteria_direction: اتجاه الترتيب + description_user_mail_notification: إعدادات البريد الالكتروني + description_available_columns: الاعمدة المتوفرة + description_selected_columns: الاعمدة المحددة + description_all_columns: كل الاعمدة + description_issue_category_reassign: اختر التصنيف + description_wiki_subpages_reassign: اختر صفحة جديدة + description_date_range_list: اختر المجال من القائمة + description_date_range_interval: اختر المدة عن طريق اختيار تاريخ البداية والنهاية + description_date_from: ادخل تاريخ البداية + description_date_to: ادخل تاريخ الانتهاء + text_rmagick_available: RMagick available (optional) + text_wiki_page_destroy_question: This page has %{descendants} child page(s) and descendant(s). What do you want to do? + text_repository_usernames_mapping: |- + Select or update the Redmine user mapped to each username found in the repository log. + Users with the same Redmine and repository username or email are automatically mapped. + notice_failed_to_save_time_entries: "Failed to save %{count} time entrie(s) on %{total} selected: %{ids}." + label_x_issues: + zero: 0 قضية + one: 1 قضية + other: "%{count} قضايا" + label_repository_new: New repository + field_repository_is_default: Main repository + label_copy_attachments: Copy attachments + label_item_position: "%{position}/%{count}" + label_completed_versions: Completed versions + text_project_identifier_info: Only lower case letters (a-z), numbers, dashes and underscores are allowed.
    Once saved, the identifier cannot be changed. + field_multiple: Multiple values + setting_commit_cross_project_ref: Allow issues of all the other projects to be referenced and fixed + text_issue_conflict_resolution_add_notes: Add my notes and discard my other changes + text_issue_conflict_resolution_overwrite: Apply my changes anyway (previous notes will be kept but some changes may be overwritten) + notice_issue_update_conflict: The issue has been updated by an other user while you were editing it. + text_issue_conflict_resolution_cancel: Discard all my changes and redisplay %{link} + permission_manage_related_issues: Manage related issues + field_auth_source_ldap_filter: LDAP filter + label_search_for_watchers: Search for watchers to add + notice_account_deleted: Your account has been permanently deleted. + setting_unsubscribe: Allow users to delete their own account + button_delete_my_account: Delete my account + text_account_destroy_confirmation: |- + Are you sure you want to proceed? + Your account will be permanently deleted, with no way to reactivate it. + error_session_expired: Your session has expired. Please login again. + text_session_expiration_settings: "Warning: changing these settings may expire the current sessions including yours." + setting_session_lifetime: Session maximum lifetime + setting_session_timeout: Session inactivity timeout + label_session_expiration: Session expiration + permission_close_project: Close / reopen the project + label_show_closed_projects: View closed projects + button_close: Close + button_reopen: Reopen + project_status_active: active + project_status_closed: closed + project_status_archived: archived + text_project_closed: This project is closed and read-only. + notice_user_successful_create: User %{id} created. + field_core_fields: Standard fields + field_timeout: Timeout (in seconds) + setting_thumbnails_enabled: Display attachment thumbnails + setting_thumbnails_size: Thumbnails size (in pixels) + label_status_transitions: Status transitions + label_fields_permissions: Fields permissions + label_readonly: Read-only + label_required: Required + text_repository_identifier_info: Only lower case letters (a-z), numbers, dashes and underscores are allowed.
    Once saved, the identifier cannot be changed. + field_board_parent: Parent forum + label_attribute_of_project: Project's %{name} + label_attribute_of_author: Author's %{name} + label_attribute_of_assigned_to: Assignee's %{name} + label_attribute_of_fixed_version: Target version's %{name} + label_copy_subtasks: Copy subtasks + label_copied_to: copied to + label_copied_from: copied from + label_any_issues_in_project: any issues in project + label_any_issues_not_in_project: any issues not in project + field_private_notes: Private notes + permission_view_private_notes: View private notes + permission_set_notes_private: Set notes as private + label_no_issues_in_project: no issues in project + label_any: جميع + label_last_n_weeks: last %{count} weeks + setting_cross_project_subtasks: Allow cross-project subtasks + label_cross_project_descendants: يشارك + label_cross_project_tree: مع شجرة المشروع + label_cross_project_hierarchy: مع التسلسل الهرمي للمشروع + label_cross_project_system: مع جميع المشاريع + button_hide: Hide + setting_non_working_week_days: Non-working days + label_in_the_next_days: in the next + label_in_the_past_days: in the past + label_attribute_of_user: User's %{name} + text_turning_multiple_off: If you disable multiple values, multiple values will be + removed in order to preserve only one value per item. + label_attribute_of_issue: Issue's %{name} + permission_add_documents: Add documents + permission_edit_documents: Edit documents + permission_delete_documents: Delete documents + label_gantt_progress_line: Progress line + setting_jsonp_enabled: Enable JSONP support + field_inherit_members: Inherit members + field_closed_on: Closed + setting_default_projects_tracker_ids: Default trackers for new projects + label_total_time: الإجمالي diff --git a/config/locales/az.yml b/config/locales/az.yml new file mode 100644 index 00000000..901df197 --- /dev/null +++ b/config/locales/az.yml @@ -0,0 +1,1186 @@ +# +# Translated by Saadat Mutallimova +# Data Processing Center of the Ministry of Communication and Information Technologies +# +az: + direction: ltr + date: + formats: + default: "%d.%m.%Y" + short: "%d %b" + long: "%d %B %Y" + + day_names: [bazar, bazar ertəsi, çərşənbə axşamı, çərşənbə, cümə axşamı, cümə, şənbə] + standalone_day_names: [Bazar, Bazar ertəsi, Çərşənbə axşamı, Çərşənbə, Cümə axşamı, Cümə, Şənbə] + abbr_day_names: [B, Be, Ça, Ç, Ca, C, Ş] + + month_names: [~, yanvar, fevral, mart, aprel, may, iyun, iyul, avqust, sentyabr, oktyabr, noyabr, dekabr] + # see russian gem for info on "standalone" day names + standalone_month_names: [~, Yanvar, Fevral, Mart, Aprel, May, İyun, İyul, Avqust, Sentyabr, Oktyabr, Noyabr, Dekabr] + abbr_month_names: [~, yan., fev., mart, apr., may, iyun, iyul, avq., sent., okt., noy., dek.] + standalone_abbr_month_names: [~, yan., fev., mart, apr., may, iyun, iyul, avq., sent., okt., noy., dek.] + + order: + - :day + - :month + - :year + + time: + formats: + default: "%a, %d %b %Y, %H:%M:%S %z" + time: "%H:%M" + short: "%d %b, %H:%M" + long: "%d %B %Y, %H:%M" + + am: "səhər" + pm: "axşam" + + number: + format: + separator: "," + delimiter: " " + precision: 3 + + currency: + format: + format: "%n %u" + unit: "man." + separator: "." + delimiter: " " + precision: 2 + + percentage: + format: + delimiter: "" + + precision: + format: + delimiter: "" + + human: + format: + delimiter: "" + precision: 3 + # Rails 2.2 + # storage_units: [байт, КБ, МБ, ГБ, ТБ] + + # Rails 2.3 + storage_units: + # Storage units output formatting. + # %u is the storage unit, %n is the number (default: 2 MB) + format: "%n %u" + units: + byte: + one: "bayt" + few: "bayt" + many: "bayt" + other: "bayt" + kb: "KB" + mb: "MB" + gb: "GB" + tb: "TB" + + datetime: + distance_in_words: + half_a_minute: "bir dəqiqədən az" + less_than_x_seconds: + one: "%{count} saniyədən az" + few: "%{count} saniyədən az" + many: "%{count} saniyədən az" + other: "%{count} saniyədən az" + x_seconds: + one: "%{count} saniyə" + few: "%{count} saniyə" + many: "%{count} saniyə" + other: "%{count} saniyə" + less_than_x_minutes: + one: "%{count} dəqiqədən az" + few: "%{count} dəqiqədən az" + many: "%{count} dəqiqədən az" + other: "%{count} dəqiqədən az" + x_minutes: + one: "%{count} dəqiqə" + few: "%{count} dəqiqə" + many: "%{count} dəqiqə" + other: "%{count} dəqiqə" + about_x_hours: + one: "təxminən %{count} saat" + few: "təxminən %{count} saat" + many: "təxminən %{count} saat" + other: "təxminən %{count} saat" + x_hours: + one: "1 hour" + other: "%{count} hours" + x_days: + one: "%{count} gün" + few: "%{count} gün" + many: "%{count} gün" + other: "%{count} gün" + about_x_months: + one: "təxminən %{count} ay" + few: "təxminən %{count} ay" + many: "təxminən %{count} ay" + other: "təxminən %{count} ay" + x_months: + one: "%{count} ay" + few: "%{count} ay" + many: "%{count} ay" + other: "%{count} ay" + about_x_years: + one: "təxminən %{count} il" + few: "təxminən %{count} il" + many: "təxminən %{count} il" + other: "təxminən %{count} il" + over_x_years: + one: "%{count} ildən çox" + few: "%{count} ildən çox" + many: "%{count} ildən çox" + other: "%{count} ildən çox" + almost_x_years: + one: "təxminən 1 il" + few: "təxminən %{count} il" + many: "təxminən %{count} il" + other: "təxminən %{count} il" + prompts: + year: "İl" + month: "Ay" + day: "Gün" + hour: "Saat" + minute: "Dəqiqə" + second: "Saniyə" + + activerecord: + errors: + template: + header: + one: "%{model}: %{count} səhvə görə yadda saxlamaq mümkün olmadı" + few: "%{model}: %{count} səhvlərə görə yadda saxlamaq mümkün olmadı" + many: "%{model}: %{count} səhvlərə görə yadda saxlamaq mümkün olmadı" + other: "%{model}: %{count} səhvə görə yadda saxlamaq mümkün olmadı" + + body: "Problemlər aşağıdakı sahələrdə yarandı:" + + messages: + inclusion: "nəzərdə tutulmamış təyinata malikdir" + exclusion: "ehtiyata götürülməmiş təyinata malikdir" + invalid: "düzgün təyinat deyildir" + confirmation: "təsdiq ilə üst-üstə düşmür" + accepted: "təsdiq etmək lazımdır" + empty: "boş saxlanıla bilməz" + blank: "boş saxlanıla bilməz" + too_long: + one: "çox böyük uzunluq (%{count} simvoldan çox ola bilməz)" + few: "çox böyük uzunluq (%{count} simvoldan çox ola bilməz)" + many: "çox böyük uzunluq (%{count} simvoldan çox ola bilməz)" + other: "çox böyük uzunluq (%{count} simvoldan çox ola bilməz)" + too_short: + one: "uzunluq kifayət qədər deyildir (%{count} simvoldan az ola bilməz)" + few: "uzunluq kifayət qədər deyildir (%{count} simvoldan az ola bilməz)" + many: "uzunluq kifayət qədər deyildir (%{count} simvoldan az ola bilməz)" + other: "uzunluq kifayət qədər deyildir (%{count} simvoldan az ola bilməz)" + wrong_length: + one: "düzgün olmayan uzunluq (tam %{count} simvol ola bilər)" + few: "düzgün olmayan uzunluq (tam %{count} simvol ola bilər)" + many: "düzgün olmayan uzunluq (tam %{count} simvol ola bilər)" + other: "düzgün olmayan uzunluq (tam %{count} simvol ola bilər)" + taken: "artıq mövcuddur" + not_a_number: "say kimi hesab edilmir" + greater_than: "%{count} çox təyinata malik ola bilər" + greater_than_or_equal_to: "%{count} çox və ya ona bərabər təyinata malik ola bilər" + equal_to: "yalnız %{count} bərabər təyinata malik ola bilər" + less_than: "%{count} az təyinata malik ola bilər" + less_than_or_equal_to: "%{count} az və ya ona bərabər təyinata malik ola bilər" + odd: "yalnız tək təyinata malik ola bilər" + even: "yalnız cüt təyinata malik ola bilər" + greater_than_start_date: "başlanğıc tarixindən sonra olmalıdır" + not_same_project: "təkcə bir layihəyə aid deyildir" + circular_dependency: "Belə əlaqə dövri asılılığa gətirib çıxaracaq" + cant_link_an_issue_with_a_descendant: "Tapşırıq özünün alt tapşırığı ilə əlaqəli ola bilməz" + + support: + array: + # Rails 2.2 + sentence_connector: "və" + skip_last_comma: true + + # Rails 2.3 + words_connector: ", " + two_words_connector: " və" + last_word_connector: " və " + + actionview_instancetag_blank_option: Seçim edin + + button_activate: Aktivləşdirmək + button_add: Əlavə etmək + button_annotate: Müəlliflik + button_apply: Tətbiq etmək + button_archive: Arxivləşdirmək + button_back: Geriyə + button_cancel: İmtina + button_change_password: Parolu dəyişmək + button_change: Dəyişmək + button_check_all: Hamını qeyd etmək + button_clear: Təmizləmək + button_configure: Parametlər + button_copy: Sürətini çıxarmaq + button_create: Yaratmaq + button_create_and_continue: Yaratmaq və davam etmək + button_delete: Silmək + button_download: Yükləmək + button_edit: Redaktə etmək + button_edit_associated_wikipage: "Əlaqəli wiki-səhifəni redaktə etmək: %{page_title}" + button_list: Siyahı + button_lock: Bloka salmaq + button_login: Giriş + button_log_time: Sərf olunan vaxt + button_move: Yerini dəyişmək + button_quote: Sitat gətirmək + button_rename: Adını dəyişmək + button_reply: Cavablamaq + button_reset: Sıfırlamaq + button_rollback: Bu versiyaya qayıtmaq + button_save: Yadda saxlamaq + button_sort: Çeşidləmək + button_submit: Qəbul etmək + button_test: Yoxlamaq + button_unarchive: Arxivdən çıxarmaq + button_uncheck_all: Təmizləmək + button_unlock: Blokdan çıxarmaq + button_unwatch: İzləməmək + button_update: Yeniləmək + button_view: Baxmaq + button_watch: İzləmək + + default_activity_design: Layihənin hazırlanması + default_activity_development: Hazırlanma prosesi + default_doc_category_tech: Texniki sənədləşmə + default_doc_category_user: İstifadəçi sənədi + default_issue_status_in_progress: İşlənməkdədir + default_issue_status_closed: Bağlanıb + default_issue_status_feedback: Əks əlaqə + default_issue_status_new: Yeni + default_issue_status_rejected: Rədd etmə + default_issue_status_resolved: Həll edilib + default_priority_high: Yüksək + default_priority_immediate: Təxirsiz + default_priority_low: Aşağı + default_priority_normal: Normal + default_priority_urgent: Təcili + default_role_developer: Hazırlayan + default_role_manager: Menecer + default_role_reporter: Reportyor + default_tracker_bug: Səhv + default_tracker_feature: Təkmilləşmə + default_tracker_support: Dəstək + + enumeration_activities: Hərəkətlər (vaxtın uçotu) + enumeration_doc_categories: Sənədlərin kateqoriyası + enumeration_issue_priorities: Tapşırıqların prioriteti + + error_can_not_remove_role: Bu rol istifadə edilir və silinə bilməz. + error_can_not_delete_custom_field: Sazlanmış sahəni silmək mümkün deyildir + error_can_not_delete_tracker: Bu treker tapşırıqlardan ibarət olduğu üçün silinə bilməz. + error_can_t_load_default_data: "Susmaya görə konfiqurasiya yüklənməmişdir: %{value}" + error_issue_not_found_in_project: Tapşırıq tapılmamışdır və ya bu layihəyə bərkidilməmişdir + error_scm_annotate: "Verilənlər mövcud deyildir və ya imzalana bilməz." + error_scm_command_failed: "Saxlayıcıya giriş imkanı səhvi: %{value}" + error_scm_not_found: Saxlayıcıda yazı və/ və ya düzəliş yoxdur. + error_unable_to_connect: Qoşulmaq mümkün deyildir (%{value}) + error_unable_delete_issue_status: Tapşırığın statusunu silmək mümkün deyildir + + field_account: İstifadəçi hesabı + field_activity: Fəaliyyət + field_admin: İnzibatçı + field_assignable: Tapşırıq bu rola təyin edilə bilər + field_assigned_to: Təyin edilib + field_attr_firstname: Ad + field_attr_lastname: Soyad + field_attr_login: Atribut Login + field_attr_mail: e-poçt + field_author: Müəllif + field_auth_source: Autentifikasiya rejimi + field_base_dn: BaseDN + field_category: Kateqoriya + field_column_names: Sütunlar + field_comments: Şərhlər + field_comments_sorting: Şərhlərin təsviri + field_content: Content + field_created_on: Yaradılıb + field_default_value: Susmaya görə təyinat + field_delay: Təxirə salmaq + field_description: Təsvir + field_done_ratio: Hazırlıq + field_downloads: Yükləmələr + field_due_date: Yerinə yetirilmə tarixi + field_editable: Redaktə edilən + field_effective_date: Tarix + field_estimated_hours: Vaxtın dəyərləndirilməsi + field_field_format: Format + field_filename: Fayl + field_filesize: Ölçü + field_firstname: Ad + field_fixed_version: Variant + field_hide_mail: E-poçtumu gizlət + field_homepage: Başlanğıc səhifə + field_host: Kompyuter + field_hours: saat + field_identifier: Unikal identifikator + field_identity_url: OpenID URL + field_is_closed: Tapşırıq bağlanıb + field_is_default: Susmaya görə tapşırıq + field_is_filter: Filtr kimi istifadə edilir + field_is_for_all: Bütün layihələr üçün + field_is_in_roadmap: Operativ planda əks olunan tapşırıqlar + field_is_public: Ümümaçıq + field_is_required: Mütləq + field_issue_to: Əlaqəli tapşırıqlar + field_issue: Tapşırıq + field_language: Dil + field_last_login_on: Son qoşulma + field_lastname: Soyad + field_login: İstifadəçi + field_mail: e-poçt + field_mail_notification: e-poçt ilə bildiriş + field_max_length: maksimal uzunluq + field_min_length: minimal uzunluq + field_name: Ad + field_new_password: Yeni parol + field_notes: Qeyd + field_onthefly: Tez bir zamanda istifadəçinin yaradılması + field_parent_title: Valideyn səhifə + field_parent: Valideyn layihə + field_parent_issue: Valideyn tapşırıq + field_password_confirmation: Təsdiq + field_password: Parol + field_port: Port + field_possible_values: Mümkün olan təyinatlar + field_priority: Prioritet + field_project: Layihə + field_redirect_existing_links: Mövcud olan istinadları istiqamətləndirmək + field_regexp: Müntəzəm ifadə + field_role: Rol + field_searchable: Axtarış üçün açıqdır + field_spent_on: Tarix + field_start_date: Başlanıb + field_start_page: Başlanğıc səhifə + field_status: Status + field_subject: Mövzu + field_subproject: Altlayihə + field_summary: Qısa təsvir + field_text: Mətn sahəsi + field_time_entries: Sərf olunan zaman + field_time_zone: Saat qurşağı + field_title: Başlıq + field_tracker: Treker + field_type: Tip + field_updated_on: Yenilənib + field_url: URL + field_user: İstifadəçi + field_value: Təyinat + field_version: Variant + field_watcher: Nəzarətçi + + general_csv_decimal_separator: ',' + general_csv_encoding: UTF-8 + general_csv_separator: ';' + general_first_day_of_week: '1' + general_lang_name: 'Azerbaijanian (Azeri)' + general_pdf_encoding: UTF-8 + general_text_no: 'xeyr' + general_text_No: 'Xeyr' + general_text_yes: 'bəli' + general_text_Yes: 'Bəli' + + label_activity: Görülən işlər + label_add_another_file: Bir fayl daha əlavə etmək + label_added_time_by: "Əlavə etdi %{author} %{age} əvvəl" + label_added: əlavə edilib + label_add_note: Qeydi əlavə etmək + label_administration: İnzibatçılıq + label_age: Yaş + label_ago: gün əvvəl + label_all_time: hər zaman + label_all_words: Bütün sözlər + label_all: hamı + label_and_its_subprojects: "%{value} və bütün altlayihələr" + label_applied_status: Tətbiq olunan status + label_ascending: Artmaya görə + label_assigned_to_me_issues: Mənim tapşırıqlarım + label_associated_revisions: Əlaqəli redaksiyalar + label_attachment: Fayl + label_attachment_delete: Faylı silmək + label_attachment_new: Yeni fayl + label_attachment_plural: Fayllar + label_attribute: Atribut + label_attribute_plural: Atributlar + label_authentication: Autentifikasiya + label_auth_source: Autentifikasiyanın rejimi + label_auth_source_new: Autentifikasiyanın yeni rejimi + label_auth_source_plural: Autentifikasiyanın rejimləri + label_blocked_by: bloklanır + label_blocks: bloklayır + label_board: Forum + label_board_new: Yeni forum + label_board_plural: Forumlar + label_boolean: Məntiqi + label_browse: Baxış + label_bulk_edit_selected_issues: Seçilən bütün tapşırıqları redaktə etmək + label_calendar: Təqvim + label_calendar_filter: O cümlədən + label_calendar_no_assigned: Mənim deyil + label_change_plural: Dəyişikliklər + label_change_properties: Xassələri dəyişmək + label_change_status: Statusu dəyişmək + label_change_view_all: Bütün dəyişikliklərə baxmaq + label_changes_details: Bütün dəyişikliklərə görə təfsilatlar + label_changeset_plural: Dəyişikliklər + label_chronological_order: Xronoloji ardıcıllıq ilə + label_closed_issues: Bağlıdır + label_closed_issues_plural: bağlıdır + label_closed_issues_plural2: bağlıdır + label_closed_issues_plural5: bağlıdır + label_comment: şərhlər + label_comment_add: Şərhləri qeyd etmək + label_comment_added: Əlavə olunmuş şərhlər + label_comment_delete: Şərhi silmək + label_comment_plural: Şərhlər + label_comment_plural2: Şərhlər + label_comment_plural5: şərhlərin + label_commits_per_author: İstifadəçi üzərində dəyişikliklər + label_commits_per_month: Ay üzərində dəyişikliklər + label_confirmation: Təsdiq + label_contains: tərkibi + label_copied: surəti köçürülüb + label_copy_workflow_from: görülən işlərin ardıcıllığının surətini köçürmək + label_current_status: Cari status + label_current_version: Cari variant + label_custom_field: Sazlanan sahə + label_custom_field_new: Yeni sazlanan sahə + label_custom_field_plural: Sazlanan sahələr + label_date_from: С + label_date_from_to: С %{start} по %{end} + label_date_range: vaxt intervalı + label_date_to: üzrə + label_date: Tarix + label_day_plural: gün + label_default: Susmaya görə + label_default_columns: Susmaya görə sütunlar + label_deleted: silinib + label_descending: Azalmaya görə + label_details: Təfsilatlar + label_diff_inline: mətndə + label_diff_side_by_side: Yanaşı + label_disabled: söndürülüb + label_display: Təsvir + label_display_per_page: "Səhifəyə: %{value}" + label_document: Sənəd + label_document_added: Sənəd əlavə edilib + label_document_new: Yeni sənəd + label_document_plural: Sənədlər + label_downloads_abbr: Yükləmələr + label_duplicated_by: çoxaldılır + label_duplicates: çoxaldır + label_end_to_end: sondan sona doğru + label_end_to_start: sondan əvvələ doğru + label_enumeration_new: Yeni qiymət + label_enumerations: Qiymətlərin siyahısı + label_environment: Mühit + label_equals: sayılır + label_example: Nümunə + label_export_to: ixrac etmək + label_feed_plural: RSS + label_feeds_access_key_created_on: "RSS-ə giriş açarı %{value} əvvəl yaradılıb" + label_f_hour: "%{value} saat" + label_f_hour_plural: "%{value} saat" + label_file_added: Fayl əlavə edilib + label_file_plural: Fayllar + label_filter_add: Filtr əlavə etmək + label_filter_plural: Filtrlər + label_float: Həqiqi ədəd + label_follows: Əvvəlki + label_gantt: Qant diaqramması + label_general: Ümumi + label_generate_key: Açarı generasiya etmək + label_greater_or_equal: ">=" + label_help: Kömək + label_history: Tarixçə + label_home: Ana səhifə + label_incoming_emails: Məlumatların qəbulu + label_index_by_date: Səhifələrin tarixçəsi + label_index_by_title: Başlıq + label_information_plural: İnformasiya + label_information: İnformasiya + label_in_less_than: az + label_in_more_than: çox + label_integer: Tam + label_internal: Daxili + label_in: da (də) + label_issue: Tapşırıq + label_issue_added: Tapşırıq əlavə edilib + label_issue_category_new: Yeni kateqoriya + label_issue_category_plural: Tapşırığın kateqoriyası + label_issue_category: Tapşırığın kateqoriyası + label_issue_new: Yeni tapşırıq + label_issue_plural: Tapşırıqlar + label_issues_by: "%{value} üzrə çeşidləmək" + label_issue_status_new: Yeni status + label_issue_status_plural: Tapşırıqların statusu + label_issue_status: Tapşırığın statusu + label_issue_tracking: Tapşırıqlar + label_issue_updated: Tapşırıq yenilənib + label_issue_view_all: Bütün tapşırıqlara baxmaq + label_issue_watchers: Nəzarətçilər + label_jump_to_a_project: ... layihəyə keçid + label_language_based: Dilin əsasında + label_last_changes: "%{count} az dəyişiklik" + label_last_login: Sonuncu qoşulma + label_last_month: sonuncu ay + label_last_n_days: "son %{count} gün" + label_last_week: sonuncu həftə + label_latest_revision: Sonuncu redaksiya + label_latest_revision_plural: Sonuncu redaksiyalar + label_ldap_authentication: LDAP vasitəsilə avtorizasiya + label_less_or_equal: <= + label_less_than_ago: gündən az + label_list: Siyahı + label_loading: Yükləmə... + label_logged_as: Daxil olmusunuz + label_login: Daxil olmaq + label_login_with_open_id_option: və ya OpenID vasitəsilə daxil olmaq + label_logout: Çıxış + label_max_size: Maksimal ölçü + label_member_new: Yeni iştirakçı + label_member: İştirakçı + label_member_plural: İştirakçılar + label_message_last: Sonuncu məlumat + label_message_new: Yeni məlumat + label_message_plural: Məlumatlar + label_message_posted: Məlumat əlavə olunub + label_me: mənə + label_min_max_length: Minimal - maksimal uzunluq + label_modified: dəyişilib + label_module_plural: Modullar + label_months_from: ay + label_month: Ay + label_more_than_ago: gündən əvvəl + label_more: Çox + label_my_account: Mənim hesabım + label_my_page: Mənim səhifəm + label_my_page_block: Mənim səhifəmin bloku + label_my_projects: Mənim layihələrim + label_new: Yeni + label_new_statuses_allowed: İcazə verilən yeni statuslar + label_news_added: Xəbər əlavə edilib + label_news_latest: Son xəbərlər + label_news_new: Xəbər əlavə etmək + label_news_plural: Xəbərlər + label_news_view_all: Bütün xəbərlərə baxmaq + label_news: Xəbərlər + label_next: Növbəti + label_nobody: heç kim + label_no_change_option: (Dəyişiklik yoxdur) + label_no_data: Təsvir üçün verilənlər yoxdur + label_none: yoxdur + label_not_contains: mövcud deyil + label_not_equals: sayılmır + label_open_issues: açıqdır + label_open_issues_plural: açıqdır + label_open_issues_plural2: açıqdır + label_open_issues_plural5: açıqdır + label_optional_description: Təsvir (vacib deyil) + label_options: Opsiyalar + label_overall_activity: Görülən işlərin toplu hesabatı + label_overview: Baxış + label_password_lost: Parolun bərpası + label_permissions_report: Giriş hüquqları üzrə hesabat + label_permissions: Giriş hüquqları + label_per_page: Səhifəyə + label_personalize_page: bu səhifəni fərdiləşdirmək + label_planning: Planlaşdırma + label_please_login: Xahiş edirik, daxil olun. + label_plugins: Modullar + label_precedes: növbəti + label_preferences: Üstünlük + label_preview: İlkin baxış + label_previous: Əvvəlki + label_profile: Profil + label_project: Layihə + label_project_all: Bütün layihələr + label_project_copy_notifications: Layihənin surətinin çıxarılması zamanı elektron poçt ilə bildiriş göndərmək + label_project_latest: Son layihələr + label_project_new: Yeni layihə + label_project_plural: Layihələr + label_project_plural2: layihəni + label_project_plural5: layihələri + label_public_projects: Ümumi layihələr + label_query: Yadda saxlanılmış sorğu + label_query_new: Yeni sorğu + label_query_plural: Yadda saxlanılmış sorğular + label_read: Oxu... + label_register: Qeydiyyat + label_registered_on: Qeydiyyatdan keçib + label_registration_activation_by_email: e-poçt üzrə hesabımın aktivləşdirilməsi + label_registration_automatic_activation: uçot qeydlərinin avtomatik aktivləşdirilməsi + label_registration_manual_activation: uçot qeydlərini əl ilə aktivləşdirmək + label_related_issues: Əlaqəli tapşırıqlar + label_relates_to: əlaqəlidir + label_relation_delete: Əlaqəni silmək + label_relation_new: Yeni münasibət + label_renamed: adını dəyişmək + label_reply_plural: Cavablar + label_report: Hesabat + label_report_plural: Hesabatlar + label_reported_issues: Yaradılan tapşırıqlar + label_repository: Saxlayıcı + label_repository_plural: Saxlayıcı + label_result_plural: Nəticələr + label_reverse_chronological_order: Əks ardıcıllıqda + label_revision: Redaksiya + label_revision_plural: Redaksiyalar + label_roadmap: Operativ plan + label_roadmap_due_in: "%{value} müddətində" + label_roadmap_no_issues: bu versiya üçün tapşırıq yoxdur + label_roadmap_overdue: "gecikmə %{value}" + label_role: Rol + label_role_and_permissions: Rollar və giriş hüquqları + label_role_new: Yeni rol + label_role_plural: Rollar + label_scm: Saxlayıcının tipi + label_search: Axtarış + label_search_titles_only: Ancaq adlarda axtarmaq + label_send_information: İstifadəçiyə uçot qeydləri üzrə informasiyanı göndərmək + label_send_test_email: Yoxlama üçün email göndərmək + label_settings: Sazlamalar + label_show_completed_versions: Bitmiş variantları göstərmək + label_sort: Çeşidləmək + label_sort_by: "%{value} üzrə çeşidləmək" + label_sort_higher: Yuxarı + label_sort_highest: Əvvələ qayıt + label_sort_lower: Aşağı + label_sort_lowest: Sona qayıt + label_spent_time: Sərf olunan vaxt + label_start_to_end: əvvəldən axıra doğru + label_start_to_start: əvvəldən əvvələ doğru + label_statistics: Statistika + label_stay_logged_in: Sistemdə qalmaq + label_string: Mətn + label_subproject_plural: Altlayihələr + label_subtask_plural: Alt tapşırıqlar + label_text: Uzun mətn + label_theme: Mövzu + label_this_month: bu ay + label_this_week: bu həftə + label_this_year: bu il + label_time_tracking: Vaxtın uçotu + label_timelog_today: Bu günə sərf olunan vaxt + label_today: bu gün + label_topic_plural: Mövzular + label_total: Cəmi + label_tracker: Treker + label_tracker_new: Yeni treker + label_tracker_plural: Trekerlər + label_updated_time: "%{value} əvvəl yenilənib" + label_updated_time_by: "%{author} %{age} əvvəl yenilənib" + label_used_by: İstifadə olunur + label_user: İstifasdəçi + label_user_activity: "İstifadəçinin gördüyü işlər %{value}" + label_user_mail_no_self_notified: "Tərəfimdən edilən dəyişikliklər haqqında məni xəbərdar etməmək" + label_user_mail_option_all: "Mənim layihələrimdəki bütün hadisələr haqqında" + label_user_mail_option_selected: "Yalnız seçilən layihədəki bütün hadisələr haqqında..." + label_user_mail_option_only_owner: Yalnız sahibi olduğum obyektlər üçün + label_user_mail_option_only_my_events: Yalnız izlədiyim və ya iştirak etdiyim obyektlər üçün + label_user_mail_option_only_assigned: Yalnız mənə təyin edilən obyektlər üçün + label_user_new: Yeni istifadəçi + label_user_plural: İstifadəçilər + label_version: Variant + label_version_new: Yeni variant + label_version_plural: Variantlar + label_view_diff: Fərqlərə baxmaq + label_view_revisions: Redaksiyalara baxmaq + label_watched_issues: Tapşırığın izlənilməsi + label_week: Həftə + label_wiki: Wiki + label_wiki_edit: Wiki-nin redaktəsi + label_wiki_edit_plural: Wiki + label_wiki_page: Wiki səhifəsi + label_wiki_page_plural: Wiki səhifələri + label_workflow: Görülən işlərin ardıcıllığı + label_x_closed_issues_abbr: + zero: "0 bağlıdır" + one: "1 bağlanıb" + few: "%{count} bağlıdır" + many: "%{count} bağlıdır" + other: "%{count} bağlıdır" + label_x_comments: + zero: "şərh yoxdur" + one: "1 şərh" + few: "%{count} şərhlər" + many: "%{count} şərh" + other: "%{count} şərh" + label_x_open_issues_abbr: + zero: "0 açıqdır" + one: "1 açıq" + few: "%{count} açıqdır" + many: "%{count} açıqdır" + other: "%{count} açıqdır" + label_x_open_issues_abbr_on_total: + zero: "0 açıqdır / %{total}" + one: "1 açıqdır / %{total}" + few: "%{count} açıqdır / %{total}" + many: "%{count} açıqdır / %{total}" + other: "%{count} açıqdır / %{total}" + label_x_projects: + zero: "layihələr yoxdur" + one: "1 layihə" + few: "%{count} layihə" + many: "%{count} layihə" + other: "%{count} layihə" + label_year: İl + label_yesterday: dünən + + mail_body_account_activation_request: "Yeni istifadəçi qeydiyyatdan keçib (%{value}). Uçot qeydi Sizin təsdiqinizi gözləyir:" + mail_body_account_information: Sizin uçot qeydiniz haqqında informasiya + mail_body_account_information_external: "Siz özünüzün %{value} uçot qeydinizi giriş üçün istifadə edə bilərsiniz." + mail_body_lost_password: 'Parolun dəyişdirilməsi üçün aşağıdakı linkə keçin:' + mail_body_register: 'Uçot qeydinin aktivləşdirilməsi üçün aşağıdakı linkə keçin:' + mail_body_reminder: "növbəti %{days} gün üçün Sizə təyin olunan %{count}:" + mail_subject_account_activation_request: "Sistemdə istifadəçinin aktivləşdirilməsi üçün sorğu %{value}" + mail_subject_lost_password: "Sizin %{value} parolunuz" + mail_subject_register: "Uçot qeydinin aktivləşdirilməsi %{value}" + mail_subject_reminder: "yaxın %{days} gün üçün Sizə təyin olunan %{count}" + + notice_account_activated: Sizin uçot qeydiniz aktivləşdirilib. Sistemə daxil ola bilərsiniz. + notice_account_invalid_creditentials: İstifadəçi adı və ya parolu düzgün deyildir + notice_account_lost_email_sent: Sizə yeni parolun seçimi ilə bağlı təlimatı əks etdirən məktub göndərilmişdir. + notice_account_password_updated: Parol müvəffəqiyyətlə yeniləndi. + notice_account_pending: "Sizin uçot qeydiniz yaradıldı və inzibatçının təsdiqini gözləyir." + notice_account_register_done: Uçot qeydi müvəffəqiyyətlə yaradıldı. Sizin uçot qeydinizin aktivləşdirilməsi üçün elektron poçtunuza göndərilən linkə keçin. + notice_account_unknown_email: Naməlum istifadəçi. + notice_account_updated: Uçot qeydi müvəffəqiyyətlə yeniləndi. + notice_account_wrong_password: Parol düzgün deyildir + notice_can_t_change_password: Bu uçot qeydi üçün xarici autentifikasiya mənbəyi istifadə olunur. Parolu dəyişmək mümkün deyildir. + notice_default_data_loaded: Susmaya görə konfiqurasiya yüklənilmişdir. + notice_email_error: "Məktubun göndərilməsi zamanı səhv baş vermişdi (%{value})" + notice_email_sent: "Məktub göndərilib %{value}" + notice_failed_to_save_issues: "Seçilən %{total} içərisindən %{count} bəndləri saxlamaq mümkün olmadı: %{ids}." + notice_failed_to_save_members: "İştirakçını (ları) yadda saxlamaq mümkün olmadı: %{errors}." + notice_feeds_access_key_reseted: Sizin RSS giriş açarınız sıfırlanmışdır. + notice_file_not_found: Daxil olmağa çalışdığınız səhifə mövcud deyildir və ya silinib. + notice_locking_conflict: İnformasiya digər istifadəçi tərəfindən yenilənib. + notice_no_issue_selected: "Heç bir tapşırıq seçilməyib! Xahiş edirik, redaktə etmək istədiyiniz tapşırığı qeyd edin." + notice_not_authorized: Sizin bu səhifəyə daxil olmaq hüququnuz yoxdur. + notice_successful_connection: Qoşulma müvəffəqiyyətlə yerinə yetirilib. + notice_successful_create: Yaratma müvəffəqiyyətlə yerinə yetirildi. + notice_successful_delete: Silinmə müvəffəqiyyətlə yerinə yetirildi. + notice_successful_update: Yeniləmə müvəffəqiyyətlə yerinə yetirildi. + notice_unable_delete_version: Variantı silmək mümkün olmadı. + + permission_add_issues: Tapşırıqların əlavə edilməsi + permission_add_issue_notes: Qeydlərin əlavə edilməsi + permission_add_issue_watchers: Nəzarətçilərin əlavə edilməsi + permission_add_messages: Məlumatların göndərilməsi + permission_browse_repository: Saxlayıcıya baxış + permission_comment_news: Xəbərlərə şərh + permission_commit_access: Saxlayıcıda faylların dəyişdirilməsi + permission_delete_issues: Tapşırıqların silinməsi + permission_delete_messages: Məlumatların silinməsi + permission_delete_own_messages: Şəxsi məlumatların silinməsi + permission_delete_wiki_pages: Wiki-səhifələrin silinməsi + permission_delete_wiki_pages_attachments: Bərkidilən faylların silinməsi + permission_edit_issue_notes: Qeydlərin redaktə edilməsi + permission_edit_issues: Tapşırıqların redaktə edilməsi + permission_edit_messages: Məlumatların redaktə edilməsi + permission_edit_own_issue_notes: Şəxsi qeydlərin redaktə edilməsi + permission_edit_own_messages: Şəxsi məlumatların redaktə edilməsi + permission_edit_own_time_entries: Şəxsi vaxt uçotunun redaktə edilməsi + permission_edit_project: Layihələrin redaktə edilməsi + permission_edit_time_entries: Vaxt uçotunun redaktə edilməsi + permission_edit_wiki_pages: Wiki-səhifənin redaktə edilməsi + permission_export_wiki_pages: Wiki-səhifənin ixracı + permission_log_time: Sərf olunan vaxtın uçotu + permission_view_changesets: Saxlayıcı dəyişikliklərinə baxış + permission_view_time_entries: Sərf olunan vaxta baxış + permission_manage_project_activities: Layihə üçün hərəkət tiplərinin idarə edilməsi + permission_manage_boards: Forumların idarə edilməsi + permission_manage_categories: Tapşırıq kateqoriyalarının idarə edilməsi + permission_manage_files: Faylların idarə edilməsi + permission_manage_issue_relations: Tapşırıq bağlantılarının idarə edilməsi + permission_manage_members: İştirakçıların idarə edilməsi + permission_manage_news: Xəbərlərin idarə edilməsi + permission_manage_public_queries: Ümumi sorğuların idarə edilməsi + permission_manage_repository: Saxlayıcının idarə edilməsi + permission_manage_subtasks: Alt tapşırıqların idarə edilməsi + permission_manage_versions: Variantların idarə edilməsi + permission_manage_wiki: Wiki-nin idarə edilməsi + permission_move_issues: Tapşırıqların köçürülməsi + permission_protect_wiki_pages: Wiki-səhifələrin bloklanması + permission_rename_wiki_pages: Wiki-səhifələrin adının dəyişdirilməsi + permission_save_queries: Sorğuların yadda saxlanılması + permission_select_project_modules: Layihə modulunun seçimi + permission_view_calendar: Təqvimə baxış + permission_view_documents: Sənədlərə baxış + permission_view_files: Fayllara baxış + permission_view_gantt: Qant diaqramına baxış + permission_view_issue_watchers: Nəzarətçilərin siyahılarına baxış + permission_view_messages: Məlumatlara baxış + permission_view_wiki_edits: Wiki tarixçəsinə baxış + permission_view_wiki_pages: Wiki-yə baxış + + project_module_boards: Forumlar + project_module_documents: Sənədlər + project_module_files: Fayllar + project_module_issue_tracking: Tapşırıqlar + project_module_news: Xəbərlər + project_module_repository: Saxlayıcı + project_module_time_tracking: Vaxtın uçotu + project_module_wiki: Wiki + project_module_gantt: Qant diaqramı + project_module_calendar: Təqvim + + setting_activity_days_default: Görülən işlərdə əks olunan günlərin sayı + setting_app_subtitle: Əlavənin sərlövhəsi + setting_app_title: Əlavənin adı + setting_attachment_max_size: Yerləşdirmənin maksimal ölçüsü + setting_autofetch_changesets: Saxlayıcının dəyişikliklərini avtomatik izləmək + setting_autologin: Avtomatik giriş + setting_bcc_recipients: Gizli surətləri istifadə etmək (BCC) + setting_cache_formatted_text: Formatlaşdırılmış mətnin heşlənməsi + setting_commit_fix_keywords: Açar sözlərin təyini + setting_commit_ref_keywords: Axtarış üçün açar sözlər + setting_cross_project_issue_relations: Layihələr üzrə tapşırıqların kəsişməsinə icazə vermək + setting_date_format: Tarixin formatı + setting_default_language: Susmaya görə dil + setting_default_notification_option: Susmaya görə xəbərdarlıq üsulu + setting_default_projects_public: Yeni layihələr ümumaçıq hesab edilir + setting_diff_max_lines_displayed: diff üçün sətirlərin maksimal sayı + setting_display_subprojects_issues: Susmaya görə altlayihələrin əks olunması + setting_emails_footer: Məktubun sətiraltı qeydləri + setting_enabled_scm: Daxil edilən SCM + setting_feeds_limit: RSS axını üçün başlıqların sayının məhdudlaşdırılması + setting_file_max_size_displayed: Əks olunma üçün mətn faylının maksimal ölçüsü + setting_gravatar_enabled: İstifadəçi avatarını Gravatar-dan istifadə etmək + setting_host_name: Kompyuterin adı + setting_issue_list_default_columns: Susmaya görə tapşırıqların siyahısında əks oluna sütunlar + setting_issues_export_limit: İxrac olunan tapşırıqlar üzrə məhdudiyyətlər + setting_login_required: Autentifikasiya vacibdir + setting_mail_from: Çıxan e-poçt ünvanı + setting_mail_handler_api_enabled: Daxil olan məlumatlar üçün veb-servisi qoşmaq + setting_mail_handler_api_key: API açar + setting_openid: Giriş və qeydiyyat üçün OpenID izacə vermək + setting_per_page_options: Səhifə üçün qeydlərin sayı + setting_plain_text_mail: Yalnız sadə mətn (HTML olmadan) + setting_protocol: Protokol + setting_repository_log_display_limit: Dəyişikliklər jurnalında əks olunan redaksiyaların maksimal sayı + setting_self_registration: Özünüqeydiyyat + setting_sequential_project_identifiers: Layihələrin ardıcıl identifikatorlarını generasiya etmək + setting_sys_api_enabled: Saxlayıcının idarə edilməsi üçün veb-servisi qoşmaq + setting_text_formatting: Mətnin formatlaşdırılması + setting_time_format: Vaxtın formatı + setting_user_format: Adın əks olunma formatı + setting_welcome_text: Salamlama mətni + setting_wiki_compression: Wiki tarixçəsinin sıxlaşdırılması + + status_active: aktivdir + status_locked: bloklanıb + status_registered: qeydiyyatdan keçib + + text_are_you_sure: Siz əminsinizmi? + text_assign_time_entries_to_project: Qeydiyyata alınmış vaxtı layihəyə bərkitmək + text_caracters_maximum: "Maksimum %{count} simvol." + text_caracters_minimum: "%{count} simvoldan az olmamalıdır." + text_comma_separated: Bir neçə qiymət mümkündür (vergül vasitəsilə). + text_custom_field_possible_values_info: 'Hər sətirə bir qiymət' + text_default_administrator_account_changed: İnzibatçının uçot qeydi susmaya görə dəyişmişdir + text_destroy_time_entries_question: "Bu tapşırıq üçün sərf olunan vaxta görə %{hours} saat qeydiyyata alınıb. Siz nə etmək istəyirsiniz?" + text_destroy_time_entries: Qeydiyyata alınmış vaxtı silmək + text_diff_truncated: '... Bu diff məhduddur, çünki əks olunan maksimal ölçünü keçir.' + text_email_delivery_not_configured: "Poçt serveri ilə işin parametrləri sazlanmayıb və e-poçt ilə bildiriş funksiyası aktiv deyildir.\nSizin SMTP-server üçün parametrləri config/configuration.yml faylından sazlaya bilərsiniz. Dəyişikliklərin tətbiq edilməsi üçün əlavəni yenidən başladın." + text_enumeration_category_reassign_to: 'Onlara aşağıdakı qiymətləri təyin etmək:' + text_enumeration_destroy_question: "%{count} obyekt bu qiymətlə bağlıdır." + text_file_repository_writable: Qeydə giriş imkanı olan saxlayıcı + text_issue_added: "Yeni tapşırıq yaradılıb %{id} (%{author})." + text_issue_category_destroy_assignments: Kateqoriyanın təyinatını silmək + text_issue_category_destroy_question: "Bir neçə tapşırıq (%{count}) bu kateqoriya üçün təyin edilib. Siz nə etmək istəyirsiniz?" + text_issue_category_reassign_to: Bu kateqoriya üçün tapşırığı yenidən təyin etmək + text_issues_destroy_confirmation: 'Seçilən tapşırıqları silmək istədiyinizə əminsinizmi?' + text_issues_ref_in_commit_messages: Məlumatın mətnindən çıxış edərək tapşırıqların statuslarının tutuşdurulması və dəyişdirilməsi + text_issue_updated: "Tapşırıq %{id} yenilənib (%{author})." + text_journal_changed: "Parametr %{label} %{old} - %{new} dəyişib" + text_journal_deleted: "Parametrin %{old} qiyməti %{label} silinib" + text_journal_set_to: "%{label} parametri %{value} dəyişib" + text_length_between: "%{min} və %{max} simvollar arasındakı uzunluq." + text_load_default_configuration: Susmaya görə konfiqurasiyanı yükləmək + text_min_max_length_info: 0 məhdudiyyətlərin olmadığını bildirir + text_no_configuration_data: "Rollar, trekerlər, tapşırıqların statusları və operativ plan konfiqurasiya olunmayıblar.\nSusmaya görə konfiqurasiyanın yüklənməsi təkidlə xahiş olunur. Siz onu sonradan dəyişə bilərsiniz." + text_plugin_assets_writable: Modullar kataloqu qeyd üçün açıqdır + text_project_destroy_confirmation: Siz bu layihə və ona aid olan bütün informasiyanı silmək istədiyinizə əminsinizmi? + text_reassign_time_entries: 'Qeydiyyata alınmış vaxtı aşağıdakı tapşırığa keçir:' + text_regexp_info: "məsələn: ^[A-Z0-9]+$" + text_repository_usernames_mapping: "Saxlayıcının jurnalında tapılan adlarla bağlı olan Redmine istifadəçisini seçin və ya yeniləyin.\nEyni ad və e-poçta sahib olan istifadəçilər Redmine və saxlayıcıda avtomatik əlaqələndirilir." + text_rmagick_available: RMagick istifadəsi mümkündür (opsional olaraq) + text_select_mail_notifications: Elektron poçta bildirişlərin göndərilməsi seçim edəcəyiniz hərəkətlərdən asılıdır. + text_select_project_modules: 'Layihədə istifadə olunacaq modulları seçin:' + text_status_changed_by_changeset: "%{value} redaksiyada reallaşdırılıb." + text_subprojects_destroy_warning: "Altlayihələr: %{value} həmçinin silinəcək." + text_tip_issue_begin_day: tapşırığın başlanğıc tarixi + text_tip_issue_begin_end_day: elə həmin gün tapşırığın başlanğıc və bitmə tarixi + text_tip_issue_end_day: tapşırığın başa çatma tarixi + text_tracker_no_workflow: Bu treker üçün hərəkətlərin ardıcıllığı müəyyən ediməyib + text_unallowed_characters: Qadağan edilmiş simvollar + text_user_mail_option: "Seçilməyən layihələr üçün Siz yalnız baxdığınız və ya iştirak etdiyiniz layihələr barədə bildiriş alacaqsınız məsələn, müəllifi olduğunuz layihələr və ya o layihələr ki, Sizə təyin edilib)." + text_user_wrote: "%{value} yazıb:" + text_wiki_destroy_confirmation: Siz bu Wiki və onun tərkibindəkiləri silmək istədiyinizə əminsinizmi? + text_workflow_edit: Vəziyyətlərin ardıcıllığını redaktə etmək üçün rol və trekeri seçin + + warning_attachments_not_saved: "faylın (ların) %{count} yadda saxlamaq mümkün deyildir." + text_wiki_page_destroy_question: Bu səhifə %{descendants} yaxın və çox yaxın səhifələrə malikdir. Siz nə etmək istəyirsiniz? + text_wiki_page_reassign_children: Cari səhifə üçün yaxın səhifələri yenidən təyin etmək + text_wiki_page_nullify_children: Yaxın səhifələri baş səhifələr etmək + text_wiki_page_destroy_children: Yaxın və çox yaxın səhifələri silmək + setting_password_min_length: Parolun minimal uzunluğu + field_group_by: Nəticələri qruplaşdırmaq + mail_subject_wiki_content_updated: "Wiki-səhifə '%{id}' yenilənmişdir" + label_wiki_content_added: Wiki-səhifə əlavə olunub + mail_subject_wiki_content_added: "Wiki-səhifə '%{id}' əlavə edilib" + mail_body_wiki_content_added: "%{author} Wiki-səhifəni '%{id}' əlavə edib." + label_wiki_content_updated: Wiki-səhifə yenilənib + mail_body_wiki_content_updated: "%{author} Wiki-səhifəni '%{id}' yeniləyib." + permission_add_project: Layihənin yaradılması + setting_new_project_user_role_id: Layihəni yaradan istifadəçiyə təyin olunan rol + label_view_all_revisions: Bütün yoxlamaları göstərmək + label_tag: Nişan + label_branch: Şöbə + error_no_tracker_in_project: Bu layihə ilə heç bir treker assosiasiya olunmayıb. Layihənin sazlamalarını yoxlayın. + error_no_default_issue_status: Susmaya görə tapşırıqların statusu müəyyən edilməyib. Sazlamaları yoxlayın (bax. "İnzibatçılıq -> Tapşırıqların statusu"). + label_group_plural: Qruplar + label_group: Qrup + label_group_new: Yeni qrup + label_time_entry_plural: Sərf olunan vaxt + text_journal_added: "%{label} %{value} əlavə edilib" + field_active: Aktiv + enumeration_system_activity: Sistemli + permission_delete_issue_watchers: Nəzarətçilərin silinməsi + version_status_closed: Bağlanıb + version_status_locked: bloklanıb + version_status_open: açıqdır + error_can_not_reopen_issue_on_closed_version: Bağlı varianta təyin edilən tapşırıq yenidən açıq ola bilməz + label_user_anonymous: Anonim + button_move_and_follow: Yerləşdirmək və keçid + setting_default_projects_modules: Yeni layihələr üçün susmaya görə daxil edilən modullar + setting_gravatar_default: Susmaya görə Gravatar təsviri + field_sharing: Birgə istifadə + label_version_sharing_hierarchy: Layihələrin iyerarxiyasına görə + label_version_sharing_system: bütün layihələr ilə + label_version_sharing_descendants: Alt layihələr ilə + label_version_sharing_tree: Layihələrin iyerarxiyası ilə + label_version_sharing_none: Birgə istifadə olmadan + error_can_not_archive_project: Bu layihə arxivləşdirilə bilməz + button_duplicate: Təkrarlamaq + button_copy_and_follow: Surətini çıxarmaq və davam etmək + label_copy_source: Mənbə + setting_issue_done_ratio: Sahənin köməyi ilə tapşırığın hazırlığını nəzərə almaq + setting_issue_done_ratio_issue_status: Tapşırığın statusu + error_issue_done_ratios_not_updated: Tapşırıqların hazırlıq parametri yenilənməyib + error_workflow_copy_target: Məqsədə uyğun trekerləri və rolları seçin + setting_issue_done_ratio_issue_field: Tapşırığın hazırlıq səviyyəsi + label_copy_same_as_target: Məqsəddə olduğu kimi + label_copy_target: Məqsəd + notice_issue_done_ratios_updated: Parametr «hazırlıq» yenilənib. + error_workflow_copy_source: Cari trekeri və ya rolu seçin + label_update_issue_done_ratios: Tapşırığın hazırlıq səviyyəsini yeniləmək + setting_start_of_week: Həftənin birinci günü + label_api_access_key: API-yə giriş açarı + text_line_separated: Bİr neçə qiymət icazə verilib (hər sətirə bir qiymət). + label_revision_id: Yoxlama %{value} + permission_view_issues: Tapşırıqlara baxış + label_display_used_statuses_only: Yalnız bu trekerdə istifadə olunan statusları əks etdirmək + label_api_access_key_created_on: API-yə giriş açarı %{value} əvvəl aradılıb + label_feeds_access_key: RSS giriş açarı + notice_api_access_key_reseted: Sizin API giriş açarınız sıfırlanıb. + setting_rest_api_enabled: REST veb-servisini qoşmaq + button_show: Göstərmək + label_missing_api_access_key: API-yə giriş açarı mövcud deyildir + label_missing_feeds_access_key: RSS-ə giriş açarı mövcud deyildir + setting_mail_handler_body_delimiters: Bu sətirlərin birindən sonra məktubu qısaltmaq + permission_add_subprojects: Alt layihələrin yaradılması + label_subproject_new: Yeni alt layihə + text_own_membership_delete_confirmation: |- + Siz bəzi və ya bütün hüquqları silməyə çalışırsınız, nəticədə bu layihəni redaktə etmək hüququnu da itirə bilərsiniz. Davam etmək istədiyinizə əminsinizmi? + + label_close_versions: Başa çatmış variantları bağlamaq + label_board_sticky: Bərkidilib + label_board_locked: Bloklanıb + field_principal: Ad + text_zoom_out: Uzaqlaşdırmaq + text_zoom_in: Yaxınlaşdırmaq + notice_unable_delete_time_entry: Jurnalın qeydini silmək mümkün deyildir. + label_overall_spent_time: Cəmi sərf olunan vaxt + label_user_mail_option_none: Hadisə yoxdur + field_member_of_group: Təyin olunmuş qrup + field_assigned_to_role: Təyin olunmuş rol + notice_not_authorized_archived_project: Sorğulanan layihə arxivləşdirilib. + label_principal_search: "İstifadəçini və ya qrupu tapmaq:" + label_user_search: "İstifadəçini tapmaq:" + field_visible: Görünmə dərəcəsi + setting_emails_header: Məktubun başlığı + + setting_commit_logtime_activity_id: Vaxtın uçotu üçün görülən hərəkətlər + text_time_logged_by_changeset: "%{value} redaksiyada nəzərə alınıb." + setting_commit_logtime_enabled: Vaxt uçotunu qoşmaq + notice_gantt_chart_truncated: Əks oluna biləcək elementlərin maksimal sayı artdığına görə diaqram kəsiləcək (%{max}) + setting_gantt_items_limit: Qant diaqramında əks olunan elementlərin maksimal sayı + field_warn_on_leaving_unsaved: Yadda saxlanılmayan mətnin səhifəsi bağlanan zaman xəbərdarlıq etmək + text_warn_on_leaving_unsaved: Tərk etmək istədiyiniz cari səhifədə yadda saxlanılmayan və itə biləcək mətn vardır. + label_my_queries: Mənim yadda saxlanılan sorğularım + text_journal_changed_no_detail: "%{label} yenilənib" + label_news_comment_added: Xəbərə şərh əlavə olunub + button_expand_all: Hamısını aç + button_collapse_all: Hamısını çevir + label_additional_workflow_transitions_for_assignee: İstifadəçi icraçı olduğu zaman əlavə keçidlər + label_additional_workflow_transitions_for_author: İstifadəçi müəllif olduğu zaman əlavə keçidlər + label_bulk_edit_selected_time_entries: Sərf olunan vaxtın seçilən qeydlərinin kütləvi şəkildə dəyişdirilməsi + text_time_entries_destroy_confirmation: Siz sərf olunan vaxtın seçilən qeydlərini silmək istədiyinizə əminsinizmi? + label_role_anonymous: Anonim + label_role_non_member: İştirakçı deyil + label_issue_note_added: Qeyd əlavə olunub + label_issue_status_updated: Status yenilənib + label_issue_priority_updated: Prioritet yenilənib + label_issues_visibility_own: İstifadəçi üçün yaradılan və ya ona təyin olunan tapşırıqlar + field_issues_visibility: Tapşırıqların görünmə dərəcəsi + label_issues_visibility_all: Bütün tapşırıqlar + permission_set_own_issues_private: Şəxsi tapşırıqlar üçün görünmə dərəcəsinin (ümumi/şəxsi) qurulması + field_is_private: Şəxsi + permission_set_issues_private: Tapşırıqlar üçün görünmə dərəcəsinin (ümumi/şəxsi) qurulması + label_issues_visibility_public: Yalnız ümumi tapşırıqlar + text_issues_destroy_descendants_confirmation: Həmçinin %{count} tapşırıq (lar) silinəcək. + field_commit_logs_encoding: Saxlayıcıda şərhlərin kodlaşdırılması + field_scm_path_encoding: Yolun kodlaşdırılması + text_scm_path_encoding_note: "Susmaya görə: UTF-8" + field_path_to_repository: Saxlayıcıya yol + field_root_directory: Kök direktoriya + field_cvs_module: Modul + field_cvsroot: CVSROOT + text_mercurial_repository_note: Lokal saxlayıcı (məsələn, /hgrepo, c:\hgrepo) + text_scm_command: Komanda + text_scm_command_version: Variant + label_git_report_last_commit: Fayllar və direktoriyalar üçün son dəyişiklikləri göstərmək + text_scm_config: Siz config/configuration.yml faylında SCM komandasını sazlaya bilərsiniz. Xahiş olunur, bu faylın redaktəsindən sonra əlavəni işə salın. + text_scm_command_not_available: Variantların nəzarət sisteminin komandasına giriş mümkün deyildir. Xahiş olunur, inzibatçı panelindəki sazlamaları yoxlayın. + notice_issue_successful_create: Tapşırıq %{id} yaradılıb. + label_between: arasında + setting_issue_group_assignment: İstifadəçi qruplarına təyinata icazə vermək + label_diff: Fərq(diff) + text_git_repository_note: "Saxlama yerini göstərin (məs: /gitrepo, c:\\gitrepo)" + description_query_sort_criteria_direction: Çeşidləmə qaydası + description_project_scope: Layihənin həcmi + description_filter: Filtr + description_user_mail_notification: E-poçt Mail xəbərdarlıqlarının sazlaması + description_date_from: Başlama tarixini daxil edin + description_message_content: Mesajın kontenti + description_available_columns: Mövcud sütunlar + description_date_range_interval: Tarixlər diapazonunu seçin + description_issue_category_reassign: Məsələnin kateqoriyasını seçin + description_search: Axtarış sahəsi + description_notes: Qeyd + description_date_range_list: Siyahıdan diapazonu seçin + description_choose_project: Layihələr + description_date_to: Yerinə yetirilmə tarixini daxil edin + description_query_sort_criteria_attribute: Çeşidləmə meyarları + description_wiki_subpages_reassign: Yeni valideyn səhifəsini seçmək + description_selected_columns: Seçilmiş sütunlar + label_parent_revision: Valideyn + label_child_revision: Əsas + error_scm_annotate_big_text_file: Mətn faylının maksimal ölçüsü artdığına görə şərh mümkün deyildir. + setting_default_issue_start_date_to_creation_date: Yeni tapşırıqlar üçün cari tarixi başlanğıc tarixi kimi istifadə etmək + button_edit_section: Bu bölməni redaktə etmək + setting_repositories_encodings: Əlavələrin və saxlayıcıların kodlaşdırılması + description_all_columns: Bütün sütunlar + button_export: İxrac + label_export_options: "%{export_format} ixracın parametrləri" + error_attachment_too_big: Faylın maksimal ölçüsü artdığına görə bu faylı yükləmək mümkün deyildir (%{max_size}) + notice_failed_to_save_time_entries: "Səhv N %{ids}. %{total} girişdən %{count} yaddaşa saxlanıla bilmədi." + label_x_issues: + zero: 0 Tapşırıq + one: 1 Tapşırıq + few: "%{count} Tapşırıq" + many: "%{count} Tapşırıq" + other: "%{count} Tapşırıq" + label_repository_new: Yeni saxlayıcı + field_repository_is_default: Susmaya görə saxlayıcı + label_copy_attachments: Əlavənin surətini çıxarmaq + label_item_position: "%{position}/%{count}" + label_completed_versions: Başa çatdırılmış variantlar + text_project_identifier_info: Yalnız kiçik latın hərflərinə (a-z), rəqəmlərə, tire və çicgilərə icazə verilir.
    Yadda saxladıqdan sonra identifikatoru dəyişmək olmaz. + field_multiple: Çoxsaylı qiymətlər + setting_commit_cross_project_ref: Digər bütün layihələrdə tapşırıqları düzəltmək və istinad etmək + text_issue_conflict_resolution_add_notes: Qeydlərimi əlavə etmək və mənim dəyişikliklərimdən imtina etmək + text_issue_conflict_resolution_overwrite: Dəyişikliklərimi tətbiq etmək (əvvəlki bütün qeydlər yadda saxlanacaq, lakin bəzi qeydlər yenidən yazıla bilər) + notice_issue_update_conflict: Tapşırığı redaktə etdiyiniz zaman kimsə onu artıq dəyişib. + text_issue_conflict_resolution_cancel: Mənim dəyişikliklərimi ləğv etmək və tapşırığı yenidən göstərmək %{link} + permission_manage_related_issues: Əlaqəli tapşırıqların idarə edilməsi + field_auth_source_ldap_filter: LDAP filtri + label_search_for_watchers: Nəzarətçiləri axtarmaq + notice_account_deleted: "Sizin uçot qeydiniz tam olaraq silinib" + setting_unsubscribe: "İstifadəçilərə şəxsi uçot qeydlərini silməyə icazə vermək" + button_delete_my_account: "Mənim uçot qeydlərimi silmək" + text_account_destroy_confirmation: "Sizin uçot qeydiniz bir daha bərpa edilmədən tam olaraq silinəcək.\nDavam etmək istədiyinizə əminsinizmi?" + error_session_expired: Sizin sessiya bitmişdir. Xahiş edirik yenidən daxil olun. + text_session_expiration_settings: "Diqqət: bu sazlamaların dəyişməyi cari sessiyanın bağlanmasına çıxara bilər." + setting_session_lifetime: Sessiyanın maksimal Session maximum həyat müddəti + setting_session_timeout: Sessiyanın qeyri aktivlik müddəti + label_session_expiration: Sessiyanın bitməsi + permission_close_project: Layihəni bağla / yenidən aç + label_show_closed_projects: Bağlı layihələrə baxmaq + button_close: Bağla + button_reopen: Yenidən aç + project_status_active: aktiv + project_status_closed: bağlı + project_status_archived: arxiv + text_project_closed: Bu layihə bağlıdı və yalnız oxuma olar. + notice_user_successful_create: İstifadəçi %{id} yaradıldı. + field_core_fields: Standart sahələr + field_timeout: Zaman aşımı (saniyə ilə) + setting_thumbnails_enabled: Əlavələrin kiçik şəklini göstər + setting_thumbnails_size: Kiçik şəkillərin ölçüsü (piksel ilə) + label_status_transitions: Status keçidləri + label_fields_permissions: Sahələrin icazələri + label_readonly: Ancaq oxumaq üçün + label_required: Tələb olunur + text_repository_identifier_info: Yalnız kiçik latın hərflərinə (a-z), rəqəmlərə, tire və çicgilərə icazə verilir.
    Yadda saxladıqdan sonra identifikatoru dəyişmək olmaz. + field_board_parent: Ana forum + label_attribute_of_project: Layihə %{name} + label_attribute_of_author: Müəllif %{name} + label_attribute_of_assigned_to: Təyin edilib %{name} + label_attribute_of_fixed_version: Əsas versiya %{name} + label_copy_subtasks: Alt tapşırığın surətini çıxarmaq + label_cross_project_hierarchy: With project hierarchy + permission_edit_documents: Edit documents + button_hide: Hide + text_turning_multiple_off: If you disable multiple values, multiple values will be removed in order to preserve only one value per item. + label_any: any + label_cross_project_system: With all projects + label_last_n_weeks: last %{count} weeks + label_in_the_past_days: in the past + label_copied_to: Copied to + permission_set_notes_private: Set notes as private + label_in_the_next_days: in the next + label_attribute_of_issue: Issue's %{name} + label_any_issues_in_project: any issues in project + label_cross_project_descendants: With subprojects + field_private_notes: Private notes + setting_jsonp_enabled: Enable JSONP support + label_gantt_progress_line: Progress line + permission_add_documents: Add documents + permission_view_private_notes: View private notes + label_attribute_of_user: User's %{name} + permission_delete_documents: Delete documents + field_inherit_members: Inherit members + setting_cross_project_subtasks: Allow cross-project subtasks + label_no_issues_in_project: no issues in project + label_copied_from: Copied from + setting_non_working_week_days: Non-working days + label_any_issues_not_in_project: any issues not in project + label_cross_project_tree: With project tree + field_closed_on: Closed + setting_default_projects_tracker_ids: Default trackers for new projects + label_total_time: Cəmi diff --git a/config/locales/bg.yml b/config/locales/bg.yml new file mode 100644 index 00000000..78fb6fe3 --- /dev/null +++ b/config/locales/bg.yml @@ -0,0 +1,1086 @@ +# Bulgarian translation by Nikolay Solakov and Ivan Cenov +bg: + # Text direction: Left-to-Right (ltr) or Right-to-Left (rtl) + direction: ltr + date: + formats: + # Use the strftime parameters for formats. + # When no format has been given, it uses default. + # You can provide other formats here if you like! + default: "%d-%m-%Y" + short: "%b %d" + long: "%B %d, %Y" + + day_names: [Неделя, Понеделник, Вторник, Сряда, Четвъртък, Петък, Събота] + abbr_day_names: [Нед, Пон, Вто, Сря, Чет, Пет, Съб] + + # Don't forget the nil at the beginning; there's no such thing as a 0th month + month_names: [~, Януари, Февруари, Март, Април, Май, Юни, Юли, Август, Септември, Октомври, Ноември, Декември] + abbr_month_names: [~, Яну, Фев, Мар, Апр, Май, Юни, Юли, Авг, Сеп, Окт, Ное, Дек] + # Used in date_select and datime_select. + order: + - :year + - :month + - :day + + time: + formats: + default: "%a, %d %b %Y %H:%M:%S %z" + time: "%H:%M" + short: "%d %b %H:%M" + long: "%B %d, %Y %H:%M" + am: "am" + pm: "pm" + + datetime: + distance_in_words: + half_a_minute: "half a minute" + less_than_x_seconds: + one: "по-малко от 1 секунда" + other: "по-малко от %{count} секунди" + x_seconds: + one: "1 секунда" + other: "%{count} секунди" + less_than_x_minutes: + one: "по-малко от 1 минута" + other: "по-малко от %{count} минути" + x_minutes: + one: "1 минута" + other: "%{count} минути" + about_x_hours: + one: "около 1 час" + other: "около %{count} часа" + x_hours: + one: "1 hour" + other: "%{count} hours" + x_days: + one: "1 ден" + other: "%{count} дена" + about_x_months: + one: "около 1 месец" + other: "около %{count} месеца" + x_months: + one: "1 месец" + other: "%{count} месеца" + about_x_years: + one: "около 1 година" + other: "около %{count} години" + over_x_years: + one: "над 1 година" + other: "над %{count} години" + almost_x_years: + one: "почти 1 година" + other: "почти %{count} години" + + number: + format: + separator: "." + delimiter: "" + precision: 3 + + human: + format: + delimiter: "" + precision: 3 + storage_units: + format: "%n %u" + units: + byte: + one: байт + other: байта + kb: "KB" + mb: "MB" + gb: "GB" + tb: "TB" + +# Used in array.to_sentence. + support: + array: + sentence_connector: "и" + skip_last_comma: false + + activerecord: + errors: + template: + header: + one: "1 грешка попречи този %{model} да бъде записан" + other: "%{count} грешки попречиха този %{model} да бъде записан" + messages: + inclusion: "не съществува в списъка" + exclusion: "е запазено" + invalid: "е невалидно" + confirmation: "липсва одобрение" + accepted: "трябва да се приеме" + empty: "не може да е празно" + blank: "не може да е празно" + too_long: "е прекалено дълго" + too_short: "е прекалено късо" + wrong_length: "е с грешна дължина" + taken: "вече съществува" + not_a_number: "не е число" + not_a_date: "е невалидна дата" + greater_than: "трябва да бъде по-голям[a/о] от %{count}" + greater_than_or_equal_to: "трябва да бъде по-голям[a/о] от или равен[a/o] на %{count}" + equal_to: "трябва да бъде равен[a/o] на %{count}" + less_than: "трябва да бъде по-малък[a/o] от %{count}" + less_than_or_equal_to: "трябва да бъде по-малък[a/o] от или равен[a/o] на %{count}" + odd: "трябва да бъде нечетен[a/o]" + even: "трябва да бъде четен[a/o]" + greater_than_start_date: "трябва да е след началната дата" + not_same_project: "не е от същия проект" + circular_dependency: "Тази релация ще доведе до безкрайна зависимост" + cant_link_an_issue_with_a_descendant: "Една задача не може да бъде свързвана към своя подзадача" + + actionview_instancetag_blank_option: Изберете + + general_text_No: 'Не' + general_text_Yes: 'Да' + general_text_no: 'не' + general_text_yes: 'да' + general_lang_name: 'Bulgarian (Български)' + general_csv_separator: ',' + general_csv_decimal_separator: '.' + general_csv_encoding: UTF-8 + general_pdf_encoding: UTF-8 + general_first_day_of_week: '1' + + notice_account_updated: Профилът е обновен успешно. + notice_account_invalid_creditentials: Невалиден потребител или парола. + notice_account_password_updated: Паролата е успешно променена. + notice_account_wrong_password: Грешна парола + notice_account_register_done: Профилът е създаден успешно. + notice_account_unknown_email: Непознат e-mail. + notice_can_t_change_password: Този профил е с външен метод за оторизация. Невъзможна смяна на паролата. + notice_account_lost_email_sent: Изпратен ви е e-mail с инструкции за избор на нова парола. + notice_account_activated: Профилът ви е активиран. Вече може да влезете в системата. + notice_successful_create: Успешно създаване. + notice_successful_update: Успешно обновяване. + notice_successful_delete: Успешно изтриване. + notice_successful_connection: Успешно свързване. + notice_file_not_found: Несъществуваща или преместена страница. + notice_locking_conflict: Друг потребител променя тези данни в момента. + notice_not_authorized: Нямате право на достъп до тази страница. + notice_not_authorized_archived_project: Проектът, който се опитвате да видите е архивиран. Ако смятате, че това не е правилно, обърнете се към администратора за разархивиране. + notice_email_sent: "Изпратен e-mail на %{value}" + notice_email_error: "Грешка при изпращане на e-mail (%{value})" + notice_feeds_access_key_reseted: Вашия ключ за RSS достъп беше променен. + notice_api_access_key_reseted: Вашият API ключ за достъп беше изчистен. + notice_failed_to_save_issues: "Неуспешен запис на %{count} задачи от %{total} избрани: %{ids}." + notice_failed_to_save_time_entries: "Невъзможност за запис на %{count} записа за използвано време от %{total} избрани: %{ids}." + notice_failed_to_save_members: "Невъзможност за запис на член(ове): %{errors}." + notice_no_issue_selected: "Няма избрани задачи." + notice_account_pending: "Профилът Ви е създаден и очаква одобрение от администратор." + notice_default_data_loaded: Примерната информация е заредена успешно. + notice_unable_delete_version: Невъзможност за изтриване на версия + notice_unable_delete_time_entry: Невъзможност за изтриване на запис за използвано време. + notice_issue_done_ratios_updated: Обновен процент на завършените задачи. + notice_gantt_chart_truncated: Мрежовият график е съкратен, понеже броят на обектите, които могат да бъдат показани е твърде голям (%{max}) + notice_issue_successful_create: Задача %{id} е създадена. + notice_issue_update_conflict: Задачата е била променена от друг потребител, докато вие сте я редактирали. + notice_account_deleted: Вашият профил беше премахнат без възможност за възстановяване. + notice_user_successful_create: Потребител %{id} е създаден. + + error_can_t_load_default_data: "Грешка при зареждане на началната информация: %{value}" + error_scm_not_found: Несъществуващ обект в хранилището. + error_scm_command_failed: "Грешка при опит за комуникация с хранилище: %{value}" + error_scm_annotate: "Обектът не съществува или не може да бъде анотиран." + error_scm_annotate_big_text_file: "Файлът не може да бъде анотиран, понеже надхвърля максималния размер за текстови файлове." + error_issue_not_found_in_project: 'Задачата не е намерена или не принадлежи на този проект' + error_no_tracker_in_project: Няма асоциирани тракери с този проект. Проверете настройките на проекта. + error_no_default_issue_status: Няма установено подразбиращо се състояние за задачите. Моля проверете вашата конфигурация (Вижте "Администрация -> Състояния на задачи"). + error_can_not_delete_custom_field: Невъзможност за изтриване на потребителско поле + error_can_not_delete_tracker: Този тракер съдържа задачи и не може да бъде изтрит. + error_can_not_remove_role: Тази роля се използва и не може да бъде изтрита. + error_can_not_reopen_issue_on_closed_version: Задача, асоциирана със затворена версия не може да бъде отворена отново + error_can_not_archive_project: Този проект не може да бъде архивиран + error_issue_done_ratios_not_updated: Процентът на завършените задачи не е обновен. + error_workflow_copy_source: Моля изберете source тракер или роля + error_workflow_copy_target: Моля изберете тракер(и) и роля (роли). + error_unable_delete_issue_status: Невъзможност за изтриване на състояние на задача + error_unable_to_connect: Невъзможност за свързване с (%{value}) + error_attachment_too_big: Този файл не може да бъде качен, понеже надхвърля максималната възможна големина (%{max_size}) + error_session_expired: Вашата сесия е изтекла. Моля влезете в Redmine отново. + warning_attachments_not_saved: "%{count} файла не бяха записани." + + mail_subject_lost_password: "Вашата парола (%{value})" + mail_body_lost_password: 'За да смените паролата си, използвайте следния линк:' + mail_subject_register: "Активация на профил (%{value})" + mail_body_register: 'За да активирате профила си използвайте следния линк:' + mail_body_account_information_external: "Можете да използвате вашия %{value} профил за вход." + mail_body_account_information: Информацията за профила ви + mail_subject_account_activation_request: "Заявка за активиране на профил в %{value}" + mail_body_account_activation_request: "Има новорегистриран потребител (%{value}), очакващ вашето одобрение:" + mail_subject_reminder: "%{count} задачи с краен срок с следващите %{days} дни" + mail_body_reminder: "%{count} задачи, назначени на вас са с краен срок в следващите %{days} дни:" + mail_subject_wiki_content_added: "Wiki страницата '%{id}' беше добавена" + mail_body_wiki_content_added: Wiki страницата '%{id}' беше добавена от %{author}. + mail_subject_wiki_content_updated: "Wiki страницата '%{id}' беше обновена" + mail_body_wiki_content_updated: Wiki страницата '%{id}' беше обновена от %{author}. + + field_name: Име + field_description: Описание + field_summary: Анотация + field_is_required: Задължително + field_firstname: Име + field_lastname: Фамилия + field_mail: Email + field_filename: Файл + field_filesize: Големина + field_downloads: Изтеглени файлове + field_author: Автор + field_created_on: От дата + field_updated_on: Обновена + field_closed_on: Затворена + field_field_format: Тип + field_is_for_all: За всички проекти + field_possible_values: Възможни стойности + field_regexp: Регулярен израз + field_min_length: Мин. дължина + field_max_length: Макс. дължина + field_value: Стойност + field_category: Категория + field_title: Заглавие + field_project: Проект + field_issue: Задача + field_status: Състояние + field_notes: Бележка + field_is_closed: Затворена задача + field_is_default: Състояние по подразбиране + field_tracker: Тракер + field_subject: Заглавие + field_due_date: Крайна дата + field_assigned_to: Възложена на + field_priority: Приоритет + field_fixed_version: Планувана версия + field_user: Потребител + field_principal: Principal + field_role: Роля + field_homepage: Начална страница + field_is_public: Публичен + field_parent: Подпроект на + field_is_in_roadmap: Да се вижда ли в Пътна карта + field_login: Потребител + field_mail_notification: Известия по пощата + field_admin: Администратор + field_last_login_on: Последно свързване + field_language: Език + field_effective_date: Дата + field_password: Парола + field_new_password: Нова парола + field_password_confirmation: Потвърждение + field_version: Версия + field_type: Тип + field_host: Хост + field_port: Порт + field_account: Профил + field_base_dn: Base DN + field_attr_login: Атрибут Login + field_attr_firstname: Атрибут Първо име (Firstname) + field_attr_lastname: Атрибут Фамилия (Lastname) + field_attr_mail: Атрибут Email + field_onthefly: Динамично създаване на потребител + field_start_date: Начална дата + field_done_ratio: "% Прогрес" + field_auth_source: Начин на оторизация + field_hide_mail: Скрий e-mail адреса ми + field_comments: Коментар + field_url: Адрес + field_start_page: Начална страница + field_subproject: Подпроект + field_hours: Часове + field_activity: Дейност + field_spent_on: Дата + field_identifier: Идентификатор + field_is_filter: Използва се за филтър + field_issue_to: Свързана задача + field_delay: Отместване + field_assignable: Възможно е възлагане на задачи за тази роля + field_redirect_existing_links: Пренасочване на съществуващи линкове + field_estimated_hours: Изчислено време + field_column_names: Колони + field_time_entries: Log time + field_time_zone: Часова зона + field_searchable: С възможност за търсене + field_default_value: Стойност по подразбиране + field_comments_sorting: Сортиране на коментарите + field_parent_title: Родителска страница + field_editable: Editable + field_watcher: Наблюдател + field_identity_url: OpenID URL + field_content: Съдържание + field_group_by: Групиране на резултатите по + field_sharing: Sharing + field_parent_issue: Родителска задача + field_member_of_group: Член на група + field_assigned_to_role: Assignee's role + field_text: Текстово поле + field_visible: Видим + field_warn_on_leaving_unsaved: Предупреди ме, когато напускам страница с незаписано съдържание + field_issues_visibility: Видимост на задачите + field_is_private: Лична + field_commit_logs_encoding: Кодова таблица на съобщенията при поверяване + field_scm_path_encoding: Кодова таблица на пътищата (path) + field_path_to_repository: Път до хранилището + field_root_directory: Коренна директория (папка) + field_cvsroot: CVSROOT + field_cvs_module: Модул + field_repository_is_default: Главно хранилище + field_multiple: Избор на повече от една стойност + field_auth_source_ldap_filter: LDAP филтър + field_core_fields: Стандартни полета + field_timeout: Таймаут (в секунди) + field_board_parent: Родителски форум + field_private_notes: Лични бележки + field_inherit_members: Наследяване на членовете на родителския проект + + setting_app_title: Заглавие + setting_app_subtitle: Описание + setting_welcome_text: Допълнителен текст + setting_default_language: Език по подразбиране + setting_login_required: Изискване за вход в системата + setting_self_registration: Регистрация от потребители + setting_attachment_max_size: Максимална големина на прикачен файл + setting_issues_export_limit: Максимален брой задачи за експорт + setting_mail_from: E-mail адрес за емисии + setting_bcc_recipients: Получатели на скрито копие (bcc) + setting_plain_text_mail: само чист текст (без HTML) + setting_host_name: Хост + setting_text_formatting: Форматиране на текста + setting_wiki_compression: Компресиране на Wiki историята + setting_feeds_limit: Максимален брой записи в ATOM емисии + setting_default_projects_public: Новите проекти са публични по подразбиране + setting_autofetch_changesets: Автоматично извличане на ревизиите + setting_sys_api_enabled: Разрешаване на WS за управление + setting_commit_ref_keywords: Отбелязващи ключови думи + setting_commit_fix_keywords: Приключващи ключови думи + setting_autologin: Автоматичен вход + setting_date_format: Формат на датата + setting_time_format: Формат на часа + setting_cross_project_issue_relations: Релации на задачи между проекти + setting_cross_project_subtasks: Подзадачи от други проекти + setting_issue_list_default_columns: Показвани колони по подразбиране + setting_repositories_encodings: Кодова таблица на прикачените файлове и хранилищата + setting_emails_header: Email header + setting_emails_footer: Подтекст за e-mail + setting_protocol: Протокол + setting_per_page_options: Опции за страниране + setting_user_format: Потребителски формат + setting_activity_days_default: Брой дни показвани на таб Дейност + setting_display_subprojects_issues: Задачите от подпроектите по подразбиране се показват в главните проекти + setting_enabled_scm: Разрешена SCM + setting_mail_handler_body_delimiters: Отрязване на e-mail-ите след един от тези редове + setting_mail_handler_api_enabled: Разрешаване на WS за входящи e-mail-и + setting_mail_handler_api_key: API ключ + setting_sequential_project_identifiers: Генериране на последователни проектни идентификатори + setting_gravatar_enabled: Използване на портребителски икони от Gravatar + setting_gravatar_default: Подразбиращо се изображение от Gravatar + setting_diff_max_lines_displayed: Максимален брой показвани diff редове + setting_file_max_size_displayed: Максимален размер на текстовите файлове, показвани inline + setting_repository_log_display_limit: Максимален брой на показванете ревизии в лог файла + setting_openid: Рарешаване на OpenID вход и регистрация + setting_password_min_length: Минимална дължина на парола + setting_new_project_user_role_id: Роля, давана на потребител, създаващ проекти, който не е администратор + setting_default_projects_modules: Активирани модули по подразбиране за нов проект + setting_issue_done_ratio: Изчисление на процента на готови задачи с + setting_issue_done_ratio_issue_field: Използване на поле '% Прогрес' + setting_issue_done_ratio_issue_status: Използване на състоянието на задачите + setting_start_of_week: Първи ден на седмицата + setting_rest_api_enabled: Разрешаване на REST web сървис + setting_cache_formatted_text: Кеширане на форматираните текстове + setting_default_notification_option: Подразбиращ се начин за известяване + setting_commit_logtime_enabled: Разрешаване на отчитането на работното време + setting_commit_logtime_activity_id: Дейност при отчитане на работното време + setting_gantt_items_limit: Максимален брой обекти, които да се показват в мрежов график + setting_issue_group_assignment: Разрешено назначаването на задачи на групи + setting_default_issue_start_date_to_creation_date: Начална дата на новите задачи по подразбиране да бъде днешната дата + setting_commit_cross_project_ref: Отбелязване и приключване на задачи от други проекти, несвързани с конкретното хранилище + setting_unsubscribe: Потребителите могат да премахват профилите си + setting_session_lifetime: Максимален живот на сесиите + setting_session_timeout: Таймаут за неактивност преди прекратяване на сесиите + setting_thumbnails_enabled: Показване на миниатюри на прикачените изображения + setting_thumbnails_size: Размер на миниатюрите (в пиксели) + setting_non_working_week_days: Не работни дни + setting_jsonp_enabled: Разрешаване на поддръжка на JSONP + setting_default_projects_tracker_ids: Тракери по подразбиране за нови проекти + + permission_add_project: Създаване на проект + permission_add_subprojects: Създаване на подпроекти + permission_edit_project: Редактиране на проект + permission_close_project: Затваряне / отваряне на проект + permission_select_project_modules: Избор на проектни модули + permission_manage_members: Управление на членовете (на екип) + permission_manage_project_activities: Управление на дейностите на проекта + permission_manage_versions: Управление на версиите + permission_manage_categories: Управление на категориите + permission_view_issues: Разглеждане на задачите + permission_add_issues: Добавяне на задачи + permission_edit_issues: Редактиране на задачи + permission_manage_issue_relations: Управление на връзките между задачите + permission_set_own_issues_private: Установяване на собствените задачи публични или лични + permission_set_issues_private: Установяване на задачите публични или лични + permission_add_issue_notes: Добавяне на бележки + permission_edit_issue_notes: Редактиране на бележки + permission_edit_own_issue_notes: Редактиране на собствени бележки + permission_view_private_notes: Разглеждане на лични бележки + permission_set_notes_private: Установяване на бележките лични + permission_move_issues: Преместване на задачи + permission_delete_issues: Изтриване на задачи + permission_manage_public_queries: Управление на публичните заявки + permission_save_queries: Запис на запитвания (queries) + permission_view_gantt: Разглеждане на мрежов график + permission_view_calendar: Разглеждане на календари + permission_view_issue_watchers: Разглеждане на списък с наблюдатели + permission_add_issue_watchers: Добавяне на наблюдатели + permission_delete_issue_watchers: Изтриване на наблюдатели + permission_log_time: Log spent time + permission_view_time_entries: Разглеждане на изразходваното време + permission_edit_time_entries: Редактиране на time logs + permission_edit_own_time_entries: Редактиране на собствените time logs + permission_manage_news: Управление на новини + permission_comment_news: Коментиране на новини + permission_view_documents: Разглеждане на документи + permission_add_documents: Добавяне на документи + permission_edit_documents: Редактиране на документи + permission_delete_documents: Изтриване на документи + permission_manage_files: Управление на файлове + permission_view_files: Разглеждане на файлове + permission_manage_wiki: Управление на wiki + permission_rename_wiki_pages: Преименуване на wiki страници + permission_delete_wiki_pages: Изтриване на wiki страници + permission_view_wiki_pages: Разглеждане на wiki + permission_view_wiki_edits: Разглеждане на wiki история + permission_edit_wiki_pages: Редактиране на wiki страници + permission_delete_wiki_pages_attachments: Изтриване на прикачени файлове към wiki страници + permission_protect_wiki_pages: Заключване на wiki страници + permission_manage_repository: Управление на хранилища + permission_browse_repository: Разглеждане на хранилища + permission_view_changesets: Разглеждане на changesets + permission_commit_access: Поверяване + permission_manage_boards: Управление на boards + permission_view_messages: Разглеждане на съобщения + permission_add_messages: Публикуване на съобщения + permission_edit_messages: Редактиране на съобщения + permission_edit_own_messages: Редактиране на собствени съобщения + permission_delete_messages: Изтриване на съобщения + permission_delete_own_messages: Изтриване на собствени съобщения + permission_export_wiki_pages: Експорт на wiki страници + permission_manage_subtasks: Управление на подзадачите + permission_manage_related_issues: Управление на връзките между задачи и ревизии + + project_module_issue_tracking: Тракинг + project_module_time_tracking: Отделяне на време + project_module_news: Новини + project_module_documents: Документи + project_module_files: Файлове + project_module_wiki: Wiki + project_module_repository: Хранилище + project_module_boards: Форуми + project_module_calendar: Календар + project_module_gantt: Мрежов график + + label_user: Потребител + label_user_plural: Потребители + label_user_new: Нов потребител + label_user_anonymous: Анонимен + label_project: Проект + label_project_new: Нов проект + label_project_plural: Проекти + label_x_projects: + zero: 0 проекта + one: 1 проект + other: "%{count} проекта" + label_project_all: Всички проекти + label_project_latest: Последни проекти + label_issue: Задача + label_issue_new: Нова задача + label_issue_plural: Задачи + label_issue_view_all: Всички задачи + label_issues_by: "Задачи по %{value}" + label_issue_added: Добавена задача + label_issue_updated: Обновена задача + label_issue_note_added: Добавена бележка + label_issue_status_updated: Обновено състояние + label_issue_priority_updated: Обновен приоритет + label_document: Документ + label_document_new: Нов документ + label_document_plural: Документи + label_document_added: Добавен документ + label_role: Роля + label_role_plural: Роли + label_role_new: Нова роля + label_role_and_permissions: Роли и права + label_role_anonymous: Анонимен + label_role_non_member: Не член + label_member: Член + label_member_new: Нов член + label_member_plural: Членове + label_tracker: Тракер + label_tracker_plural: Тракери + label_tracker_new: Нов тракер + label_workflow: Работен процес + label_issue_status: Състояние на задача + label_issue_status_plural: Състояния на задачи + label_issue_status_new: Ново състояние + label_issue_category: Категория задача + label_issue_category_plural: Категории задачи + label_issue_category_new: Нова категория + label_custom_field: Потребителско поле + label_custom_field_plural: Потребителски полета + label_custom_field_new: Ново потребителско поле + label_enumerations: Списъци + label_enumeration_new: Нова стойност + label_information: Информация + label_information_plural: Информация + label_please_login: Вход + label_register: Регистрация + label_login_with_open_id_option: или вход чрез OpenID + label_password_lost: Забравена парола + label_home: Начало + label_my_page: Лична страница + label_my_account: Профил + label_my_projects: Проекти, в които участвам + label_my_page_block: Блокове в личната страница + label_administration: Администрация + label_login: Вход + label_logout: Изход + label_help: Помощ + label_reported_issues: Публикувани задачи + label_assigned_to_me_issues: Възложени на мен + label_last_login: Последно свързване + label_registered_on: Регистрация + label_activity: Дейност + label_overall_activity: Цялостна дейност + label_user_activity: "Активност на %{value}" + label_new: Нов + label_logged_as: Здравейте, + label_environment: Среда + label_authentication: Оторизация + label_auth_source: Начин на оторозация + label_auth_source_new: Нов начин на оторизация + label_auth_source_plural: Начини на оторизация + label_subproject_plural: Подпроекти + label_subproject_new: Нов подпроект + label_and_its_subprojects: "%{value} и неговите подпроекти" + label_min_max_length: Минимална - максимална дължина + label_list: Списък + label_date: Дата + label_integer: Целочислен + label_float: Дробно + label_boolean: Чекбокс + label_string: Текст + label_text: Дълъг текст + label_attribute: Атрибут + label_attribute_plural: Атрибути + label_no_data: Няма изходни данни + label_change_status: Промяна на състоянието + label_history: История + label_attachment: Файл + label_attachment_new: Нов файл + label_attachment_delete: Изтриване + label_attachment_plural: Файлове + label_file_added: Добавен файл + label_report: Справка + label_report_plural: Справки + label_news: Новини + label_news_new: Добави + label_news_plural: Новини + label_news_latest: Последни новини + label_news_view_all: Виж всички + label_news_added: Добавена новина + label_news_comment_added: Добавен коментар към новина + label_settings: Настройки + label_overview: Общ изглед + label_version: Версия + label_version_new: Нова версия + label_version_plural: Версии + label_close_versions: Затваряне на завършените версии + label_confirmation: Одобрение + label_export_to: Експорт към + label_read: Read... + label_public_projects: Публични проекти + label_open_issues: отворена + label_open_issues_plural: отворени + label_closed_issues: затворена + label_closed_issues_plural: затворени + label_x_open_issues_abbr_on_total: + zero: 0 отворени / %{total} + one: 1 отворена / %{total} + other: "%{count} отворени / %{total}" + label_x_open_issues_abbr: + zero: 0 отворени + one: 1 отворена + other: "%{count} отворени" + label_x_closed_issues_abbr: + zero: 0 затворени + one: 1 затворена + other: "%{count} затворени" + label_x_issues: + zero: 0 задачи + one: 1 задача + other: "%{count} задачи" + label_total: Общо + label_total_time: Общо + label_permissions: Права + label_current_status: Текущо състояние + label_new_statuses_allowed: Позволени състояния + label_all: всички + label_any: без значение + label_none: никакви + label_nobody: никой + label_next: Следващ + label_previous: Предишен + label_used_by: Използва се от + label_details: Детайли + label_add_note: Добавяне на бележка + label_per_page: На страница + label_calendar: Календар + label_months_from: месеца от + label_gantt: Мрежов график + label_internal: Вътрешен + label_last_changes: "последни %{count} промени" + label_change_view_all: Виж всички промени + label_personalize_page: Персонализиране + label_comment: Коментар + label_comment_plural: Коментари + label_x_comments: + zero: 0 коментара + one: 1 коментар + other: "%{count} коментара" + label_comment_add: Добавяне на коментар + label_comment_added: Добавен коментар + label_comment_delete: Изтриване на коментари + label_query: Потребителска справка + label_query_plural: Потребителски справки + label_query_new: Нова заявка + label_my_queries: Моите заявки + label_filter_add: Добави филтър + label_filter_plural: Филтри + label_equals: е + label_not_equals: не е + label_in_less_than: след по-малко от + label_in_more_than: след повече от + label_in_the_next_days: в следващите + label_in_the_past_days: в предишните + label_greater_or_equal: ">=" + label_less_or_equal: <= + label_between: между + label_in: в следващите + label_today: днес + label_all_time: всички + label_yesterday: вчера + label_this_week: тази седмица + label_last_week: последната седмица + label_last_n_weeks: последните %{count} седмици + label_last_n_days: "последните %{count} дни" + label_this_month: текущия месец + label_last_month: последния месец + label_this_year: текущата година + label_date_range: Период + label_less_than_ago: преди по-малко от + label_more_than_ago: преди повече от + label_ago: преди + label_contains: съдържа + label_not_contains: не съдържа + label_any_issues_in_project: задачи от проект + label_any_issues_not_in_project: задачи, които не са в проект + label_no_issues_in_project: никакви задачи в проект + label_day_plural: дни + label_repository: Хранилище + label_repository_new: Ново хранилище + label_repository_plural: Хранилища + label_browse: Разглеждане + label_branch: работен вариант + label_tag: Версия + label_revision: Ревизия + label_revision_plural: Ревизии + label_revision_id: Ревизия %{value} + label_associated_revisions: Асоциирани ревизии + label_added: добавено + label_modified: променено + label_copied: копирано + label_renamed: преименувано + label_deleted: изтрито + label_latest_revision: Последна ревизия + label_latest_revision_plural: Последни ревизии + label_view_revisions: Виж ревизиите + label_view_all_revisions: Разглеждане на всички ревизии + label_max_size: Максимална големина + label_sort_highest: Премести най-горе + label_sort_higher: Премести по-горе + label_sort_lower: Премести по-долу + label_sort_lowest: Премести най-долу + label_roadmap: Пътна карта + label_roadmap_due_in: "Излиза след %{value}" + label_roadmap_overdue: "%{value} закъснение" + label_roadmap_no_issues: Няма задачи за тази версия + label_search: Търсене + label_result_plural: Pезултати + label_all_words: Всички думи + label_wiki: Wiki + label_wiki_edit: Wiki редакция + label_wiki_edit_plural: Wiki редакции + label_wiki_page: Wiki страница + label_wiki_page_plural: Wiki страници + label_index_by_title: Индекс + label_index_by_date: Индекс по дата + label_current_version: Текуща версия + label_preview: Преглед + label_feed_plural: Емисии + label_changes_details: Подробни промени + label_issue_tracking: Тракинг + label_spent_time: Отделено време + label_overall_spent_time: Общо употребено време + label_f_hour: "%{value} час" + label_f_hour_plural: "%{value} часа" + label_time_tracking: Отделяне на време + label_change_plural: Промени + label_statistics: Статистики + label_commits_per_month: Ревизии по месеци + label_commits_per_author: Ревизии по автор + label_diff: diff + label_view_diff: Виж разликите + label_diff_inline: хоризонтално + label_diff_side_by_side: вертикално + label_options: Опции + label_copy_workflow_from: Копирай работния процес от + label_permissions_report: Справка за права + label_watched_issues: Наблюдавани задачи + label_related_issues: Свързани задачи + label_applied_status: Установено състояние + label_loading: Зареждане... + label_relation_new: Нова релация + label_relation_delete: Изтриване на релация + label_relates_to: свързана със + label_duplicates: дублира + label_duplicated_by: дублирана от + label_blocks: блокира + label_blocked_by: блокирана от + label_precedes: предшества + label_follows: изпълнява се след + label_copied_to: копирана в + label_copied_from: копирана от + label_end_to_start: край към начало + label_end_to_end: край към край + label_start_to_start: начало към начало + label_start_to_end: начало към край + label_stay_logged_in: Запомни ме + label_disabled: забранено + label_show_completed_versions: Показване на реализирани версии + label_me: аз + label_board: Форум + label_board_new: Нов форум + label_board_plural: Форуми + label_board_locked: Заключена + label_board_sticky: Sticky + label_topic_plural: Теми + label_message_plural: Съобщения + label_message_last: Последно съобщение + label_message_new: Нова тема + label_message_posted: Добавено съобщение + label_reply_plural: Отговори + label_send_information: Изпращане на информацията до потребителя + label_year: Година + label_month: Месец + label_week: Седмица + label_date_from: От + label_date_to: До + label_language_based: В зависимост от езика + label_sort_by: "Сортиране по %{value}" + label_send_test_email: Изпращане на тестов e-mail + label_feeds_access_key: RSS access ключ + label_missing_feeds_access_key: Липсващ RSS ключ за достъп + label_feeds_access_key_created_on: "%{value} от създаването на RSS ключа" + label_module_plural: Модули + label_added_time_by: "Публикувана от %{author} преди %{age}" + label_updated_time_by: "Обновена от %{author} преди %{age}" + label_updated_time: "Обновена преди %{value}" + label_jump_to_a_project: Проект... + label_file_plural: Файлове + label_changeset_plural: Ревизии + label_default_columns: По подразбиране + label_no_change_option: (Без промяна) + label_bulk_edit_selected_issues: Групово редактиране на задачи + label_bulk_edit_selected_time_entries: Групово редактиране на записи за използвано време + label_theme: Тема + label_default: По подразбиране + label_search_titles_only: Само в заглавията + label_user_mail_option_all: "За всяко събитие в проектите, в които участвам" + label_user_mail_option_selected: "За всички събития само в избраните проекти..." + label_user_mail_option_none: "Само за наблюдавани или в които участвам (автор или назначени на мен)" + label_user_mail_option_only_my_events: Само за неща, в които съм включен/а + label_user_mail_option_only_assigned: Само за неща, назначени на мен + label_user_mail_option_only_owner: Само за неща, на които аз съм собственик + label_user_mail_no_self_notified: "Не искам известия за извършени от мен промени" + label_registration_activation_by_email: активиране на профила по email + label_registration_manual_activation: ръчно активиране + label_registration_automatic_activation: автоматично активиране + label_display_per_page: "На страница по: %{value}" + label_age: Възраст + label_change_properties: Промяна на настройки + label_general: Основни + label_more: Още + label_scm: SCM (Система за контрол на версиите) + label_plugins: Плъгини + label_ldap_authentication: LDAP оторизация + label_downloads_abbr: D/L + label_optional_description: Незадължително описание + label_add_another_file: Добавяне на друг файл + label_preferences: Предпочитания + label_chronological_order: Хронологичен ред + label_reverse_chronological_order: Обратен хронологичен ред + label_planning: Планиране + label_incoming_emails: Входящи e-mail-и + label_generate_key: Генериране на ключ + label_issue_watchers: Наблюдатели + label_example: Пример + label_display: Показване + label_sort: Сортиране + label_ascending: Нарастващ + label_descending: Намаляващ + label_date_from_to: От %{start} до %{end} + label_wiki_content_added: Wiki страница беше добавена + label_wiki_content_updated: Wiki страница беше обновена + label_group: Група + label_group_plural: Групи + label_group_new: Нова група + label_time_entry_plural: Използвано време + label_version_sharing_none: Не споделен + label_version_sharing_descendants: С подпроекти + label_version_sharing_hierarchy: С проектна йерархия + label_version_sharing_tree: С дърво на проектите + label_version_sharing_system: С всички проекти + label_update_issue_done_ratios: Обновяване на процента на завършените задачи + label_copy_source: Източник + label_copy_target: Цел + label_copy_same_as_target: Също като целта + label_display_used_statuses_only: Показване само на състоянията, използвани от този тракер + label_api_access_key: API ключ за достъп + label_missing_api_access_key: Липсващ API ключ + label_api_access_key_created_on: API ключ за достъп е създаден преди %{value} + label_profile: Профил + label_subtask_plural: Подзадачи + label_project_copy_notifications: Изпращане на Send e-mail известия по време на копирането на проекта + label_principal_search: "Търсене на потребител или група:" + label_user_search: "Търсене на потребител:" + label_additional_workflow_transitions_for_author: Позволени са допълнителни преходи, когато потребителят е авторът + label_additional_workflow_transitions_for_assignee: Позволени са допълнителни преходи, когато потребителят е назначеният към задачата + label_issues_visibility_all: Всички задачи + label_issues_visibility_public: Всички не-лични задачи + label_issues_visibility_own: Задачи, създадени от или назначени на потребителя + label_git_report_last_commit: Извеждане на последното поверяване за файлове и папки + label_parent_revision: Ревизия родител + label_child_revision: Ревизия наследник + label_export_options: "%{export_format} опции за експорт" + label_copy_attachments: Копиране на прикачените файлове + label_copy_subtasks: Копиране на подзадачите + label_item_position: "%{position}/%{count}" + label_completed_versions: Завършени версии + label_search_for_watchers: Търсене на потребители за наблюдатели + label_session_expiration: Изтичане на сесиите + label_show_closed_projects: Разглеждане на затворени проекти + label_status_transitions: Преходи между състоянията + label_fields_permissions: Видимост на полетата + label_readonly: Само за четене + label_required: Задължително + label_attribute_of_project: Project's %{name} + label_attribute_of_issue: Issue's %{name} + label_attribute_of_author: Author's %{name} + label_attribute_of_assigned_to: Assignee's %{name} + label_attribute_of_user: User's %{name} + label_attribute_of_fixed_version: Target version's %{name} + label_cross_project_descendants: С подпроекти + label_cross_project_tree: С дърво на проектите + label_cross_project_hierarchy: С проектна йерархия + label_cross_project_system: С всички проекти + label_gantt_progress_line: Линия на изпълнението + + button_login: Вход + button_submit: Изпращане + button_save: Запис + button_check_all: Избор на всички + button_uncheck_all: Изчистване на всички + button_collapse_all: Скриване всички + button_expand_all: Разгъване всички + button_delete: Изтриване + button_create: Създаване + button_create_and_continue: Създаване и продължаване + button_test: Тест + button_edit: Редакция + button_edit_associated_wikipage: "Редактиране на асоциираната Wiki страница: %{page_title}" + button_add: Добавяне + button_change: Промяна + button_apply: Приложи + button_clear: Изчисти + button_lock: Заключване + button_unlock: Отключване + button_download: Изтегляне + button_list: Списък + button_view: Преглед + button_move: Преместване + button_move_and_follow: Преместване и продължаване + button_back: Назад + button_cancel: Отказ + button_activate: Активация + button_sort: Сортиране + button_log_time: Отделяне на време + button_rollback: Върни се към тази ревизия + button_watch: Наблюдаване + button_unwatch: Край на наблюдението + button_reply: Отговор + button_archive: Архивиране + button_unarchive: Разархивиране + button_reset: Генериране наново + button_rename: Преименуване + button_change_password: Промяна на парола + button_copy: Копиране + button_copy_and_follow: Копиране и продължаване + button_annotate: Анотация + button_update: Обновяване + button_configure: Конфигуриране + button_quote: Цитат + button_duplicate: Дублиране + button_show: Показване + button_hide: Скриване + button_edit_section: Редактиране на тази секция + button_export: Експорт + button_delete_my_account: Премахване на моя профил + button_close: Затваряне + button_reopen: Отваряне + + status_active: активен + status_registered: регистриран + status_locked: заключен + + project_status_active: активен + project_status_closed: затворен + project_status_archived: архивиран + + version_status_open: отворена + version_status_locked: заключена + version_status_closed: затворена + + field_active: Активен + + text_select_mail_notifications: Изберете събития за изпращане на e-mail. + text_regexp_info: пр. ^[A-Z0-9]+$ + text_min_max_length_info: 0 - без ограничения + text_project_destroy_confirmation: Сигурни ли сте, че искате да изтриете проекта и данните в него? + text_subprojects_destroy_warning: "Неговите подпроекти: %{value} също ще бъдат изтрити." + text_workflow_edit: Изберете роля и тракер за да редактирате работния процес + text_are_you_sure: Сигурни ли сте? + text_journal_changed: "%{label} променен от %{old} на %{new}" + text_journal_changed_no_detail: "%{label} променен" + text_journal_set_to: "%{label} установен на %{value}" + text_journal_deleted: "%{label} изтрит (%{old})" + text_journal_added: "Добавено %{label} %{value}" + text_tip_issue_begin_day: задача, започваща този ден + text_tip_issue_end_day: задача, завършваща този ден + text_tip_issue_begin_end_day: задача, започваща и завършваща този ден + text_project_identifier_info: 'Позволени са малки букви (a-z), цифри, тирета и _.
    Промяна след създаването му не е възможна.' + text_caracters_maximum: "До %{count} символа." + text_caracters_minimum: "Минимум %{count} символа." + text_length_between: "От %{min} до %{max} символа." + text_tracker_no_workflow: Няма дефиниран работен процес за този тракер + text_unallowed_characters: Непозволени символи + text_comma_separated: Позволено е изброяване (с разделител запетая). + text_line_separated: Позволени са много стойности (по едно на ред). + text_issues_ref_in_commit_messages: Отбелязване и приключване на задачи от ревизии + text_issue_added: "Публикувана е нова задача с номер %{id} (от %{author})." + text_issue_updated: "Задача %{id} е обновена (от %{author})." + text_wiki_destroy_confirmation: Сигурни ли сте, че искате да изтриете това Wiki и цялото му съдържание? + text_issue_category_destroy_question: "Има задачи (%{count}) обвързани с тази категория. Какво ще изберете?" + text_issue_category_destroy_assignments: Премахване на връзките с категорията + text_issue_category_reassign_to: Преобвързване с категория + text_user_mail_option: "За неизбраните проекти, ще получавате известия само за наблюдавани дейности или в които участвате (т.е. автор или назначени на мен)." + text_no_configuration_data: "Все още не са конфигурирани Роли, тракери, състояния на задачи и работен процес.\nСтрого се препоръчва зареждането на примерната информация. Веднъж заредена ще имате възможност да я редактирате." + text_load_default_configuration: Зареждане на примерна информация + text_status_changed_by_changeset: "Приложено с ревизия %{value}." + text_time_logged_by_changeset: Приложено в ревизия %{value}. + text_issues_destroy_confirmation: 'Сигурни ли сте, че искате да изтриете избраните задачи?' + text_issues_destroy_descendants_confirmation: Тази операция ще премахне и %{count} подзадача(и). + text_time_entries_destroy_confirmation: Сигурен ли сте, че изтриете избраните записи за изразходвано време? + text_select_project_modules: 'Изберете активните модули за този проект:' + text_default_administrator_account_changed: Сменен фабричния администраторски профил + text_file_repository_writable: Възможност за писане в хранилището с файлове + text_plugin_assets_writable: Папката на приставките е разрешена за запис + text_rmagick_available: Наличен RMagick (по избор) + text_destroy_time_entries_question: "%{hours} часа са отделени на задачите, които искате да изтриете. Какво избирате?" + text_destroy_time_entries: Изтриване на отделеното време + text_assign_time_entries_to_project: Прехвърляне на отделеното време към проект + text_reassign_time_entries: 'Прехвърляне на отделеното време към задача:' + text_user_wrote: "%{value} написа:" + text_enumeration_destroy_question: "%{count} обекта са свързани с тази стойност." + text_enumeration_category_reassign_to: 'Пресвържете ги към тази стойност:' + text_email_delivery_not_configured: "Изпращането на e-mail-и не е конфигурирано и известията не са разрешени.\nКонфигурирайте вашия SMTP сървър в config/configuration.yml и рестартирайте Redmine, за да ги разрешите." + text_repository_usernames_mapping: "Изберете или променете потребителите в Redmine, съответстващи на потребителите в дневника на хранилището (repository).\nПотребителите с еднакви имена в Redmine и хранилищата се съвместяват автоматично." + text_diff_truncated: '... Този diff не е пълен, понеже е надхвърля максималния размер, който може да бъде показан.' + text_custom_field_possible_values_info: 'Една стойност на ред' + text_wiki_page_destroy_question: Тази страница има %{descendants} страници деца и descendant(s). Какво желаете да правите? + text_wiki_page_nullify_children: Запазване на тези страници като коренни страници + text_wiki_page_destroy_children: Изтриване на страниците деца и всички техни descendants + text_wiki_page_reassign_children: Преназначаване на страниците деца на тази родителска страница + text_own_membership_delete_confirmation: "Вие сте на път да премахнете някои или всички ваши разрешения и е възможно след това да не можете да редактирате този проект.\nСигурен ли сте, че искате да продължите?" + text_zoom_in: Увеличаване + text_zoom_out: Намаляване + text_warn_on_leaving_unsaved: Страницата съдържа незаписано съдържание, което може да бъде загубено, ако я напуснете. + text_scm_path_encoding_note: "По подразбиране: UTF-8" + text_git_repository_note: Празно и локално хранилище (например /gitrepo, c:\gitrepo) + text_mercurial_repository_note: Локално хранилище (например /hgrepo, c:\hgrepo) + text_scm_command: SCM команда + text_scm_command_version: Версия + text_scm_config: Можете да конфигурирате SCM командите в config/configuration.yml. За да активирате промените, рестартирайте Redmine. + text_scm_command_not_available: SCM командата не е налична или достъпна. Проверете конфигурацията в административния панел. + text_issue_conflict_resolution_overwrite: Прилагане на моите промени (предишните коментари ще бъдат запазени, но някои други промени може да бъдат презаписани) + text_issue_conflict_resolution_add_notes: Добавяне на моите коментари и отхвърляне на другите мои промени + text_issue_conflict_resolution_cancel: Отхвърляне на всички мои промени и презареждане на %{link} + text_account_destroy_confirmation: "Сигурен/на ли сте, че желаете да продължите?\nВашият профил ще бъде премахнат без възможност за възстановяване." + text_session_expiration_settings: "Внимание: промяната на тези установяваноя може да прекрати всички активни сесии, включително и вашата." + text_project_closed: Този проект е затворен и е само за четене. + text_turning_multiple_off: Ако забраните възможността за повече от една стойност, повечето стойности ще бъдат + премахнати с цел да остане само по една стойност за поле. + + default_role_manager: Мениджър + default_role_developer: Разработчик + default_role_reporter: Публикуващ + default_tracker_bug: Грешка + default_tracker_feature: Функционалност + default_tracker_support: Поддръжка + default_issue_status_new: Нова + default_issue_status_in_progress: Изпълнение + default_issue_status_resolved: Приключена + default_issue_status_feedback: Обратна връзка + default_issue_status_closed: Затворена + default_issue_status_rejected: Отхвърлена + default_doc_category_user: Документация за потребителя + default_doc_category_tech: Техническа документация + default_priority_low: Нисък + default_priority_normal: Нормален + default_priority_high: Висок + default_priority_urgent: Спешен + default_priority_immediate: Веднага + default_activity_design: Дизайн + default_activity_development: Разработка + + enumeration_issue_priorities: Приоритети на задачи + enumeration_doc_categories: Категории документи + enumeration_activities: Дейности (time tracking) + enumeration_system_activity: Системна активност + description_filter: Филтър + description_search: Търсене + description_choose_project: Проекти + description_project_scope: Обхват на търсенето + description_notes: Бележки + description_message_content: Съдържание на съобщението + description_query_sort_criteria_attribute: Атрибут на сортиране + description_query_sort_criteria_direction: Посока на сортиране + description_user_mail_notification: Конфигурация известията по пощата + description_available_columns: Налични колони + description_selected_columns: Избрани колони + description_issue_category_reassign: Изберете категория + description_wiki_subpages_reassign: Изберете нова родителска страница + description_all_columns: Всички колони + description_date_range_list: Изберете диапазон от списъка + description_date_range_interval: Изберете диапазон чрез задаване на начална и крайна дати + description_date_from: Въведете начална дата + description_date_to: Въведете крайна дата + text_repository_identifier_info: 'Позволени са малки букви (a-z), цифри, тирета и _.
    Промяна след създаването му не е възможна.' diff --git a/config/locales/bs.yml b/config/locales/bs.yml new file mode 100644 index 00000000..50f23001 --- /dev/null +++ b/config/locales/bs.yml @@ -0,0 +1,1102 @@ +#Ernad Husremovic hernad@bring.out.ba + +bs: + direction: ltr + date: + formats: + default: "%d.%m.%Y" + short: "%e. %b" + long: "%e. %B %Y" + only_day: "%e" + + + day_names: [Nedjelja, Ponedjeljak, Utorak, Srijeda, Četvrtak, Petak, Subota] + abbr_day_names: [Ned, Pon, Uto, Sri, Čet, Pet, Sub] + + month_names: [~, Januar, Februar, Mart, April, Maj, Jun, Jul, Avgust, Septembar, Oktobar, Novembar, Decembar] + abbr_month_names: [~, Jan, Feb, Mar, Apr, Maj, Jun, Jul, Avg, Sep, Okt, Nov, Dec] + order: + - :day + - :month + - :year + + time: + formats: + default: "%A, %e. %B %Y, %H:%M" + short: "%e. %B, %H:%M Uhr" + long: "%A, %e. %B %Y, %H:%M" + time: "%H:%M" + + am: "prijepodne" + pm: "poslijepodne" + + datetime: + distance_in_words: + half_a_minute: "pola minute" + less_than_x_seconds: + one: "manje od 1 sekunde" + other: "manje od %{count} sekudni" + x_seconds: + one: "1 sekunda" + other: "%{count} sekundi" + less_than_x_minutes: + one: "manje od 1 minute" + other: "manje od %{count} minuta" + x_minutes: + one: "1 minuta" + other: "%{count} minuta" + about_x_hours: + one: "oko 1 sahat" + other: "oko %{count} sahata" + x_hours: + one: "1 hour" + other: "%{count} hours" + x_days: + one: "1 dan" + other: "%{count} dana" + about_x_months: + one: "oko 1 mjesec" + other: "oko %{count} mjeseci" + x_months: + one: "1 mjesec" + other: "%{count} mjeseci" + about_x_years: + one: "oko 1 godine" + other: "oko %{count} godina" + over_x_years: + one: "preko 1 godine" + other: "preko %{count} godina" + almost_x_years: + one: "almost 1 year" + other: "almost %{count} years" + + + number: + format: + precision: 2 + separator: ',' + delimiter: '.' + currency: + format: + unit: 'KM' + format: '%u %n' + negative_format: '%u -%n' + delimiter: '' + percentage: + format: + delimiter: "" + precision: + format: + delimiter: "" + human: + format: + delimiter: "" + precision: 3 + storage_units: + format: "%n %u" + units: + byte: + one: "Byte" + other: "Bytes" + kb: "KB" + mb: "MB" + gb: "GB" + tb: "TB" + +# Used in array.to_sentence. + support: + array: + sentence_connector: "i" + skip_last_comma: false + + activerecord: + errors: + template: + header: + one: "1 error prohibited this %{model} from being saved" + other: "%{count} errors prohibited this %{model} from being saved" + messages: + inclusion: "nije uključeno u listu" + exclusion: "je rezervisano" + invalid: "nije ispravno" + confirmation: "ne odgovara potvrdi" + accepted: "mora se prihvatiti" + empty: "ne može biti prazno" + blank: "ne može biti znak razmaka" + too_long: "je predugačko" + too_short: "je prekratko" + wrong_length: "je pogrešne dužine" + taken: "već je zauzeto" + not_a_number: "nije broj" + not_a_date: "nije ispravan datum" + greater_than: "mora bit veći od %{count}" + greater_than_or_equal_to: "mora bit veći ili jednak %{count}" + equal_to: "mora biti jednak %{count}" + less_than: "mora biti manji od %{count}" + less_than_or_equal_to: "mora bit manji ili jednak %{count}" + odd: "mora biti neparan" + even: "mora biti paran" + greater_than_start_date: "mora biti veći nego početni datum" + not_same_project: "ne pripada istom projektu" + circular_dependency: "Ova relacija stvar cirkularnu zavisnost" + cant_link_an_issue_with_a_descendant: "An issue can not be linked to one of its subtasks" + + actionview_instancetag_blank_option: Molimo odaberite + + general_text_No: 'Da' + general_text_Yes: 'Ne' + general_text_no: 'ne' + general_text_yes: 'da' + general_lang_name: 'Bosanski' + general_csv_separator: ',' + general_csv_decimal_separator: '.' + general_csv_encoding: UTF-8 + general_pdf_encoding: UTF-8 + general_first_day_of_week: '7' + + notice_account_activated: Vaš nalog je aktiviran. Možete se prijaviti. + notice_account_invalid_creditentials: Pogrešan korisnik ili lozinka + notice_account_lost_email_sent: Email sa uputstvima o izboru nove šifre je poslat na vašu adresu. + notice_account_password_updated: Lozinka je uspješno promjenjena. + notice_account_pending: "Vaš nalog je kreiran i čeka odobrenje administratora." + notice_account_register_done: Nalog je uspješno kreiran. Da bi ste aktivirali vaš nalog kliknite na link koji vam je poslat. + notice_account_unknown_email: Nepoznati korisnik. + notice_account_updated: Nalog je uspješno promjenen. + notice_account_wrong_password: Pogrešna lozinka + notice_can_t_change_password: Ovaj nalog koristi eksterni izvor prijavljivanja. Ne mogu da promjenim šifru. + notice_default_data_loaded: Podrazumjevana konfiguracija uspječno učitana. + notice_email_error: Došlo je do greške pri slanju emaila (%{value}) + notice_email_sent: "Email je poslan %{value}" + notice_failed_to_save_issues: "Neuspješno snimanje %{count} aktivnosti na %{total} izabrano: %{ids}." + notice_feeds_access_key_reseted: Vaš RSS pristup je resetovan. + notice_file_not_found: Stranica kojoj pokušavate da pristupite ne postoji ili je uklonjena. + notice_locking_conflict: "Konflikt: podaci su izmjenjeni od strane drugog korisnika." + notice_no_issue_selected: "Nijedna aktivnost nije izabrana! Molim, izaberite aktivnosti koje želite za ispravljate." + notice_not_authorized: Niste ovlašćeni da pristupite ovoj stranici. + notice_successful_connection: Uspješna konekcija. + notice_successful_create: Uspješno kreiranje. + notice_successful_delete: Brisanje izvršeno. + notice_successful_update: Promjene uspješno izvršene. + + error_can_t_load_default_data: "Podrazumjevane postavke se ne mogu učitati %{value}" + error_scm_command_failed: "Desila se greška pri pristupu repozitoriju: %{value}" + error_scm_not_found: "Unos i/ili revizija ne postoji u repozitoriju." + + error_scm_annotate: "Ova stavka ne postoji ili nije označena." + error_issue_not_found_in_project: 'Aktivnost nije nađena ili ne pripada ovom projektu' + + warning_attachments_not_saved: "%{count} fajl(ovi) ne mogu biti snimljen(i)." + + mail_subject_lost_password: "Vaša %{value} lozinka" + mail_body_lost_password: 'Za promjenu lozinke, kliknite na sljedeći link:' + mail_subject_register: "Aktivirajte %{value} vaš korisnički račun" + mail_body_register: 'Za aktivaciju vašeg korisničkog računa, kliknite na sljedeći link:' + mail_body_account_information_external: "Možete koristiti vaš %{value} korisnički račun za prijavu na sistem." + mail_body_account_information: Informacija o vašem korisničkom računu + mail_subject_account_activation_request: "%{value} zahtjev za aktivaciju korisničkog računa" + mail_body_account_activation_request: "Novi korisnik (%{value}) se registrovao. Korisnički račun čeka vaše odobrenje za aktivaciju:" + mail_subject_reminder: "%{count} aktivnost(i) u kašnjenju u narednim %{days} danima" + mail_body_reminder: "%{count} aktivnost(i) koje su dodjeljenje vama u narednim %{days} danima:" + + + field_name: Ime + field_description: Opis + field_summary: Pojašnjenje + field_is_required: Neophodno popuniti + field_firstname: Ime + field_lastname: Prezime + field_mail: Email + field_filename: Fajl + field_filesize: Veličina + field_downloads: Downloadi + field_author: Autor + field_created_on: Kreirano + field_updated_on: Izmjenjeno + field_field_format: Format + field_is_for_all: Za sve projekte + field_possible_values: Moguće vrijednosti + field_regexp: '"Regularni izraz"' + field_min_length: Minimalna veličina + field_max_length: Maksimalna veličina + field_value: Vrijednost + field_category: Kategorija + field_title: Naslov + field_project: Projekat + field_issue: Aktivnost + field_status: Status + field_notes: Bilješke + field_is_closed: Aktivnost zatvorena + field_is_default: Podrazumjevana vrijednost + field_tracker: Područje aktivnosti + field_subject: Subjekat + field_due_date: Završiti do + field_assigned_to: Dodijeljeno + field_priority: Prioritet + field_fixed_version: Ciljna verzija + field_user: Korisnik + field_role: Uloga + field_homepage: Naslovna strana + field_is_public: Javni + field_parent: Podprojekt od + field_is_in_roadmap: Aktivnosti prikazane u planu realizacije + field_login: Prijava + field_mail_notification: Email notifikacije + field_admin: Administrator + field_last_login_on: Posljednja konekcija + field_language: Jezik + field_effective_date: Datum + field_password: Lozinka + field_new_password: Nova lozinka + field_password_confirmation: Potvrda + field_version: Verzija + field_type: Tip + field_host: Host + field_port: Port + field_account: Korisnički račun + field_base_dn: Base DN + field_attr_login: Attribut za prijavu + field_attr_firstname: Attribut za ime + field_attr_lastname: Atribut za prezime + field_attr_mail: Atribut za email + field_onthefly: 'Kreiranje korisnika "On-the-fly"' + field_start_date: Početak + field_done_ratio: "% Realizovano" + field_auth_source: Mod za authentifikaciju + field_hide_mail: Sakrij moju email adresu + field_comments: Komentar + field_url: URL + field_start_page: Početna stranica + field_subproject: Podprojekat + field_hours: Sahata + field_activity: Operacija + field_spent_on: Datum + field_identifier: Identifikator + field_is_filter: Korišteno kao filter + field_issue_to: Povezana aktivnost + field_delay: Odgađanje + field_assignable: Aktivnosti dodijeljene ovoj ulozi + field_redirect_existing_links: Izvrši redirekciju postojećih linkova + field_estimated_hours: Procjena vremena + field_column_names: Kolone + field_time_zone: Vremenska zona + field_searchable: Pretraživo + field_default_value: Podrazumjevana vrijednost + field_comments_sorting: Prikaži komentare + field_parent_title: 'Stranica "roditelj"' + field_editable: Može se mijenjati + field_watcher: Posmatrač + field_identity_url: OpenID URL + field_content: Sadržaj + + setting_app_title: Naslov aplikacije + setting_app_subtitle: Podnaslov aplikacije + setting_welcome_text: Tekst dobrodošlice + setting_default_language: Podrazumjevani jezik + setting_login_required: Authentifikacija neophodna + setting_self_registration: Samo-registracija + setting_attachment_max_size: Maksimalna veličina prikačenog fajla + setting_issues_export_limit: Limit za eksport aktivnosti + setting_mail_from: Mail adresa - pošaljilac + setting_bcc_recipients: '"BCC" (blind carbon copy) primaoci ' + setting_plain_text_mail: Email sa običnim tekstom (bez HTML-a) + setting_host_name: Ime hosta i putanja + setting_text_formatting: Formatiranje teksta + setting_wiki_compression: Kompresija Wiki istorije + + setting_feeds_limit: 'Limit za "RSS" feed-ove' + setting_default_projects_public: Podrazumjeva se da je novi projekat javni + setting_autofetch_changesets: 'Automatski kupi "commit"-e' + setting_sys_api_enabled: 'Omogući "WS" za upravljanje repozitorijom' + setting_commit_ref_keywords: Ključne riječi za reference + setting_commit_fix_keywords: 'Ključne riječi za status "zatvoreno"' + setting_autologin: Automatski login + setting_date_format: Format datuma + setting_time_format: Format vremena + setting_cross_project_issue_relations: Omogući relacije između aktivnosti na različitim projektima + setting_issue_list_default_columns: Podrazumjevane koleone za prikaz na listi aktivnosti + setting_emails_footer: Potpis na email-ovima + setting_protocol: Protokol + setting_per_page_options: Broj objekata po stranici + setting_user_format: Format korisničkog prikaza + setting_activity_days_default: Prikaz promjena na projektu - opseg dana + setting_display_subprojects_issues: Prikaz podprojekata na glavnom projektima (podrazumjeva se) + setting_enabled_scm: Omogući SCM (source code management) + setting_mail_handler_api_enabled: Omogući automatsku obradu ulaznih emailova + setting_mail_handler_api_key: API ključ (obrada ulaznih mailova) + setting_sequential_project_identifiers: Generiši identifikatore projekta sekvencijalno + setting_gravatar_enabled: 'Koristi "gravatar" korisničke ikone' + setting_diff_max_lines_displayed: Maksimalan broj linija za prikaz razlika između dva fajla + setting_file_max_size_displayed: Maksimalna veličina fajla kod prikaza razlika unutar fajla (inline) + setting_repository_log_display_limit: Maksimalna veličina revizija prikazanih na log fajlu + setting_openid: Omogući OpenID prijavu i registraciju + + permission_edit_project: Ispravke projekta + permission_select_project_modules: Odaberi module projekta + permission_manage_members: Upravljanje članovima + permission_manage_versions: Upravljanje verzijama + permission_manage_categories: Upravljanje kategorijama aktivnosti + permission_add_issues: Dodaj aktivnosti + permission_edit_issues: Ispravka aktivnosti + permission_manage_issue_relations: Upravljaj relacijama među aktivnostima + permission_add_issue_notes: Dodaj bilješke + permission_edit_issue_notes: Ispravi bilješke + permission_edit_own_issue_notes: Ispravi sopstvene bilješke + permission_move_issues: Pomjeri aktivnosti + permission_delete_issues: Izbriši aktivnosti + permission_manage_public_queries: Upravljaj javnim upitima + permission_save_queries: Snimi upite + permission_view_gantt: Pregled gantograma + permission_view_calendar: Pregled kalendara + permission_view_issue_watchers: Pregled liste korisnika koji prate aktivnost + permission_add_issue_watchers: Dodaj onoga koji prati aktivnost + permission_log_time: Evidentiraj utrošak vremena + permission_view_time_entries: Pregled utroška vremena + permission_edit_time_entries: Ispravka utroška vremena + permission_edit_own_time_entries: Ispravka svog utroška vremena + permission_manage_news: Upravljaj novostima + permission_comment_news: Komentiraj novosti + permission_view_documents: Pregled dokumenata + permission_manage_files: Upravljaj fajlovima + permission_view_files: Pregled fajlova + permission_manage_wiki: Upravljaj wiki stranicama + permission_rename_wiki_pages: Ispravi wiki stranicu + permission_delete_wiki_pages: Izbriši wiki stranicu + permission_view_wiki_pages: Pregled wiki sadržaja + permission_view_wiki_edits: Pregled wiki istorije + permission_edit_wiki_pages: Ispravka wiki stranica + permission_delete_wiki_pages_attachments: Brisanje fajlova prikačenih wiki-ju + permission_protect_wiki_pages: Zaštiti wiki stranicu + permission_manage_repository: Upravljaj repozitorijem + permission_browse_repository: Pregled repozitorija + permission_view_changesets: Pregled setova promjena + permission_commit_access: 'Pristup "commit"-u' + permission_manage_boards: Upravljaj forumima + permission_view_messages: Pregled poruka + permission_add_messages: Šalji poruke + permission_edit_messages: Ispravi poruke + permission_edit_own_messages: Ispravka sopstvenih poruka + permission_delete_messages: Prisanje poruka + permission_delete_own_messages: Brisanje sopstvenih poruka + + project_module_issue_tracking: Praćenje aktivnosti + project_module_time_tracking: Praćenje vremena + project_module_news: Novosti + project_module_documents: Dokumenti + project_module_files: Fajlovi + project_module_wiki: Wiki stranice + project_module_repository: Repozitorij + project_module_boards: Forumi + + label_user: Korisnik + label_user_plural: Korisnici + label_user_new: Novi korisnik + label_project: Projekat + label_project_new: Novi projekat + label_project_plural: Projekti + label_x_projects: + zero: 0 projekata + one: 1 projekat + other: "%{count} projekata" + label_project_all: Svi projekti + label_project_latest: Posljednji projekti + label_issue: Aktivnost + label_issue_new: Nova aktivnost + label_issue_plural: Aktivnosti + label_issue_view_all: Vidi sve aktivnosti + label_issues_by: "Aktivnosti po %{value}" + label_issue_added: Aktivnost je dodana + label_issue_updated: Aktivnost je izmjenjena + label_document: Dokument + label_document_new: Novi dokument + label_document_plural: Dokumenti + label_document_added: Dokument je dodan + label_role: Uloga + label_role_plural: Uloge + label_role_new: Nove uloge + label_role_and_permissions: Uloge i dozvole + label_member: Izvršilac + label_member_new: Novi izvršilac + label_member_plural: Izvršioci + label_tracker: Područje aktivnosti + label_tracker_plural: Područja aktivnosti + label_tracker_new: Novo područje aktivnosti + label_workflow: Tok promjena na aktivnosti + label_issue_status: Status aktivnosti + label_issue_status_plural: Statusi aktivnosti + label_issue_status_new: Novi status + label_issue_category: Kategorija aktivnosti + label_issue_category_plural: Kategorije aktivnosti + label_issue_category_new: Nova kategorija + label_custom_field: Proizvoljno polje + label_custom_field_plural: Proizvoljna polja + label_custom_field_new: Novo proizvoljno polje + label_enumerations: Enumeracije + label_enumeration_new: Nova vrijednost + label_information: Informacija + label_information_plural: Informacije + label_please_login: Molimo prijavite se + label_register: Registracija + label_login_with_open_id_option: ili prijava sa OpenID-om + label_password_lost: Izgubljena lozinka + label_home: Početna stranica + label_my_page: Moja stranica + label_my_account: Moj korisnički račun + label_my_projects: Moji projekti + label_administration: Administracija + label_login: Prijavi se + label_logout: Odjavi se + label_help: Pomoć + label_reported_issues: Prijavljene aktivnosti + label_assigned_to_me_issues: Aktivnosti dodjeljene meni + label_last_login: Posljednja konekcija + label_registered_on: Registrovan na + label_activity_plural: Promjene + label_activity: Operacija + label_overall_activity: Pregled svih promjena + label_user_activity: "Promjene izvršene od: %{value}" + label_new: Novi + label_logged_as: Prijavljen kao + label_environment: Sistemsko okruženje + label_authentication: Authentifikacija + label_auth_source: Mod authentifikacije + label_auth_source_new: Novi mod authentifikacije + label_auth_source_plural: Modovi authentifikacije + label_subproject_plural: Podprojekti + label_and_its_subprojects: "%{value} i njegovi podprojekti" + label_min_max_length: Min - Maks dužina + label_list: Lista + label_date: Datum + label_integer: Cijeli broj + label_float: Float + label_boolean: Logička varijabla + label_string: Tekst + label_text: Dugi tekst + label_attribute: Atribut + label_attribute_plural: Atributi + label_no_data: Nema podataka za prikaz + label_change_status: Promjeni status + label_history: Istorija + label_attachment: Fajl + label_attachment_new: Novi fajl + label_attachment_delete: Izbriši fajl + label_attachment_plural: Fajlovi + label_file_added: Fajl je dodan + label_report: Izvještaj + label_report_plural: Izvještaji + label_news: Novosti + label_news_new: Dodaj novosti + label_news_plural: Novosti + label_news_latest: Posljednje novosti + label_news_view_all: Pogledaj sve novosti + label_news_added: Novosti su dodane + label_settings: Postavke + label_overview: Pregled + label_version: Verzija + label_version_new: Nova verzija + label_version_plural: Verzije + label_confirmation: Potvrda + label_export_to: 'Takođe dostupno u:' + label_read: Čitaj... + label_public_projects: Javni projekti + label_open_issues: otvoren + label_open_issues_plural: otvoreni + label_closed_issues: zatvoren + label_closed_issues_plural: zatvoreni + label_x_open_issues_abbr_on_total: + zero: 0 otvoreno / %{total} + one: 1 otvorena / %{total} + other: "%{count} otvorene / %{total}" + label_x_open_issues_abbr: + zero: 0 otvoreno + one: 1 otvorena + other: "%{count} otvorene" + label_x_closed_issues_abbr: + zero: 0 zatvoreno + one: 1 zatvorena + other: "%{count} zatvorene" + label_total: Ukupno + label_permissions: Dozvole + label_current_status: Tekući status + label_new_statuses_allowed: Novi statusi dozvoljeni + label_all: sve + label_none: ništa + label_nobody: niko + label_next: Sljedeće + label_previous: Predhodno + label_used_by: Korišteno od + label_details: Detalji + label_add_note: Dodaj bilješku + label_per_page: Po stranici + label_calendar: Kalendar + label_months_from: mjeseci od + label_gantt: Gantt + label_internal: Interno + label_last_changes: "posljednjih %{count} promjena" + label_change_view_all: Vidi sve promjene + label_personalize_page: Personaliziraj ovu stranicu + label_comment: Komentar + label_comment_plural: Komentari + label_x_comments: + zero: bez komentara + one: 1 komentar + other: "%{count} komentari" + label_comment_add: Dodaj komentar + label_comment_added: Komentar je dodan + label_comment_delete: Izbriši komentar + label_query: Proizvoljan upit + label_query_plural: Proizvoljni upiti + label_query_new: Novi upit + label_filter_add: Dodaj filter + label_filter_plural: Filteri + label_equals: je + label_not_equals: nije + label_in_less_than: je manji nego + label_in_more_than: je više nego + label_in: u + label_today: danas + label_all_time: sve vrijeme + label_yesterday: juče + label_this_week: ova hefta + label_last_week: zadnja hefta + label_last_n_days: "posljednjih %{count} dana" + label_this_month: ovaj mjesec + label_last_month: posljednji mjesec + label_this_year: ova godina + label_date_range: Datumski opseg + label_less_than_ago: ranije nego (dana) + label_more_than_ago: starije nego (dana) + label_ago: prije (dana) + label_contains: sadrži + label_not_contains: ne sadrži + label_day_plural: dani + label_repository: Repozitorij + label_repository_plural: Repozitoriji + label_browse: Listaj + label_revision: Revizija + label_revision_plural: Revizije + label_associated_revisions: Doddjeljene revizije + label_added: dodano + label_modified: izmjenjeno + label_copied: kopirano + label_renamed: preimenovano + label_deleted: izbrisano + label_latest_revision: Posljednja revizija + label_latest_revision_plural: Posljednje revizije + label_view_revisions: Vidi revizije + label_max_size: Maksimalna veličina + label_sort_highest: Pomjeri na vrh + label_sort_higher: Pomjeri gore + label_sort_lower: Pomjeri dole + label_sort_lowest: Pomjeri na dno + label_roadmap: Plan realizacije + label_roadmap_due_in: "Obavezan do %{value}" + label_roadmap_overdue: "%{value} kasni" + label_roadmap_no_issues: Nema aktivnosti za ovu verziju + label_search: Traži + label_result_plural: Rezultati + label_all_words: Sve riječi + label_wiki: Wiki stranice + label_wiki_edit: ispravka wiki-ja + label_wiki_edit_plural: ispravke wiki-ja + label_wiki_page: Wiki stranica + label_wiki_page_plural: Wiki stranice + label_index_by_title: Indeks prema naslovima + label_index_by_date: Indeks po datumima + label_current_version: Tekuća verzija + label_preview: Pregled + label_feed_plural: Feeds + label_changes_details: Detalji svih promjena + label_issue_tracking: Evidencija aktivnosti + label_spent_time: Utrošak vremena + label_f_hour: "%{value} sahat" + label_f_hour_plural: "%{value} sahata" + label_time_tracking: Evidencija vremena + label_change_plural: Promjene + label_statistics: Statistika + label_commits_per_month: '"Commit"-a po mjesecu' + label_commits_per_author: '"Commit"-a po autoru' + label_view_diff: Pregled razlika + label_diff_inline: zajedno + label_diff_side_by_side: jedna pored druge + label_options: Opcije + label_copy_workflow_from: Kopiraj tok promjena statusa iz + label_permissions_report: Izvještaj + label_watched_issues: Aktivnosti koje pratim + label_related_issues: Korelirane aktivnosti + label_applied_status: Status je primjenjen + label_loading: Učitavam... + label_relation_new: Nova relacija + label_relation_delete: Izbriši relaciju + label_relates_to: korelira sa + label_duplicates: duplikat + label_duplicated_by: duplicirano od + label_blocks: blokira + label_blocked_by: blokirano on + label_precedes: predhodi + label_follows: slijedi + label_end_to_start: 'kraj -> početak' + label_end_to_end: 'kraja -> kraj' + label_start_to_start: 'početak -> početak' + label_start_to_end: 'početak -> kraj' + label_stay_logged_in: Ostani prijavljen + label_disabled: onemogućen + label_show_completed_versions: Prikaži završene verzije + label_me: ja + label_board: Forum + label_board_new: Novi forum + label_board_plural: Forumi + label_topic_plural: Teme + label_message_plural: Poruke + label_message_last: Posljednja poruka + label_message_new: Nova poruka + label_message_posted: Poruka je dodana + label_reply_plural: Odgovori + label_send_information: Pošalji informaciju o korisničkom računu + label_year: Godina + label_month: Mjesec + label_week: Hefta + label_date_from: Od + label_date_to: Do + label_language_based: Bazirano na korisnikovom jeziku + label_sort_by: "Sortiraj po %{value}" + label_send_test_email: Pošalji testni email + label_feeds_access_key_created_on: "RSS pristupni ključ kreiran prije %{value} dana" + label_module_plural: Moduli + label_added_time_by: "Dodano od %{author} prije %{age}" + label_updated_time_by: "Izmjenjeno od %{author} prije %{age}" + label_updated_time: "Izmjenjeno prije %{value}" + label_jump_to_a_project: Skoči na projekat... + label_file_plural: Fajlovi + label_changeset_plural: Setovi promjena + label_default_columns: Podrazumjevane kolone + label_no_change_option: (Bez promjene) + label_bulk_edit_selected_issues: Ispravi odjednom odabrane aktivnosti + label_theme: Tema + label_default: Podrazumjevano + label_search_titles_only: Pretraži samo naslove + label_user_mail_option_all: "Za bilo koji događaj na svim mojim projektima" + label_user_mail_option_selected: "Za bilo koji događaj na odabranim projektima..." + label_user_mail_no_self_notified: "Ne želim notifikaciju za promjene koje sam ja napravio" + label_registration_activation_by_email: aktivacija korisničkog računa email-om + label_registration_manual_activation: ručna aktivacija korisničkog računa + label_registration_automatic_activation: automatska kreacija korisničkog računa + label_display_per_page: "Po stranici: %{value}" + label_age: Starost + label_change_properties: Promjena osobina + label_general: Generalno + label_more: Više + label_scm: SCM + label_plugins: Plugin-ovi + label_ldap_authentication: LDAP authentifikacija + label_downloads_abbr: D/L + label_optional_description: Opis (opciono) + label_add_another_file: Dodaj još jedan fajl + label_preferences: Postavke + label_chronological_order: Hronološki poredak + label_reverse_chronological_order: Reverzni hronološki poredak + label_planning: Planiranje + label_incoming_emails: Dolazni email-ovi + label_generate_key: Generiši ključ + label_issue_watchers: Praćeno od + label_example: Primjer + label_display: Prikaz + + button_apply: Primjeni + button_add: Dodaj + button_archive: Arhiviranje + button_back: Nazad + button_cancel: Odustani + button_change: Izmjeni + button_change_password: Izmjena lozinke + button_check_all: Označi sve + button_clear: Briši + button_copy: Kopiraj + button_create: Novi + button_delete: Briši + button_download: Download + button_edit: Ispravka + button_list: Lista + button_lock: Zaključaj + button_log_time: Utrošak vremena + button_login: Prijava + button_move: Pomjeri + button_rename: Promjena imena + button_reply: Odgovor + button_reset: Resetuj + button_rollback: Vrati predhodno stanje + button_save: Snimi + button_sort: Sortiranje + button_submit: Pošalji + button_test: Testiraj + button_unarchive: Otpakuj arhivu + button_uncheck_all: Isključi sve + button_unlock: Otključaj + button_unwatch: Prekini notifikaciju + button_update: Promjena na aktivnosti + button_view: Pregled + button_watch: Notifikacija + button_configure: Konfiguracija + button_quote: Citat + + status_active: aktivan + status_registered: registrovan + status_locked: zaključan + + text_select_mail_notifications: Odaberi događaje za koje će se slati email notifikacija. + text_regexp_info: npr. ^[A-Z0-9]+$ + text_min_max_length_info: 0 znači bez restrikcije + text_project_destroy_confirmation: Sigurno želite izbrisati ovaj projekat i njegove podatke ? + text_subprojects_destroy_warning: "Podprojekt(i): %{value} će takođe biti izbrisani." + text_workflow_edit: Odaberite ulogu i područje aktivnosti za ispravku toka promjena na aktivnosti + text_are_you_sure: Da li ste sigurni ? + text_tip_issue_begin_day: zadatak počinje danas + text_tip_issue_end_day: zadatak završava danas + text_tip_issue_begin_end_day: zadatak započinje i završava danas + text_caracters_maximum: "maksimum %{count} karaktera." + text_caracters_minimum: "Dužina mora biti najmanje %{count} znakova." + text_length_between: "Broj znakova između %{min} i %{max}." + text_tracker_no_workflow: Tok statusa nije definisan za ovo područje aktivnosti + text_unallowed_characters: Nedozvoljeni znakovi + text_comma_separated: Višestruke vrijednosti dozvoljene (odvojiti zarezom). + text_issues_ref_in_commit_messages: 'Referenciranje i zatvaranje aktivnosti putem "commit" poruka' + text_issue_added: "Aktivnost %{id} je prijavljena od %{author}." + text_issue_updated: "Aktivnost %{id} je izmjenjena od %{author}." + text_wiki_destroy_confirmation: Sigurno želite izbrisati ovaj wiki i čitav njegov sadržaj ? + text_issue_category_destroy_question: "Neke aktivnosti (%{count}) pripadaju ovoj kategoriji. Sigurno to želite uraditi ?" + text_issue_category_destroy_assignments: Ukloni kategoriju + text_issue_category_reassign_to: Ponovo dodijeli ovu kategoriju + text_user_mail_option: "Za projekte koje niste odabrali, primićete samo notifikacije o stavkama koje pratite ili ste u njih uključeni (npr. vi ste autor ili su vama dodjeljenje)." + text_no_configuration_data: "Uloge, područja aktivnosti, statusi aktivnosti i tok promjena statusa nisu konfigurisane.\nKrajnje je preporučeno da učitate tekuđe postavke. Kasnije ćete ih moći mjenjati po svojim potrebama." + text_load_default_configuration: Učitaj tekuću konfiguraciju + text_status_changed_by_changeset: "Primjenjeno u setu promjena %{value}." + text_issues_destroy_confirmation: 'Sigurno želite izbrisati odabranu/e aktivnost/i ?' + text_select_project_modules: 'Odaberi module koje želite u ovom projektu:' + text_default_administrator_account_changed: Tekući administratorski račun je promjenjen + text_file_repository_writable: U direktorij sa fajlovima koji su prilozi se može pisati + text_plugin_assets_writable: U direktorij plugin-ova se može pisati + text_rmagick_available: RMagick je dostupan (opciono) + text_destroy_time_entries_question: "%{hours} sahata je prijavljeno na aktivnostima koje želite brisati. Želite li to učiniti ?" + text_destroy_time_entries: Izbriši prijavljeno vrijeme + text_assign_time_entries_to_project: Dodaj prijavljenoo vrijeme projektu + text_reassign_time_entries: 'Preraspodjeli prijavljeno vrijeme na ovu aktivnost:' + text_user_wrote: "%{value} je napisao/la:" + text_enumeration_destroy_question: "Za %{count} objekata je dodjeljenja ova vrijednost." + text_enumeration_category_reassign_to: 'Ponovo im dodjeli ovu vrijednost:' + text_email_delivery_not_configured: "Email dostava nije konfiguraisana, notifikacija je onemogućena.\nKonfiguriši SMTP server u config/configuration.yml i restartuj aplikaciju nakon toga." + text_repository_usernames_mapping: "Odaberi ili ispravi redmine korisnika mapiranog za svako korisničko ima nađeno u logu repozitorija.\nKorisnici sa istim imenom u redmineu i u repozitoruju se automatski mapiraju." + text_diff_truncated: '... Ovaj prikaz razlike je odsječen pošto premašuje maksimalnu veličinu za prikaz' + text_custom_field_possible_values_info: 'Jedna linija za svaku vrijednost' + + default_role_manager: Menadžer + default_role_developer: Programer + default_role_reporter: Reporter + default_tracker_bug: Greška + default_tracker_feature: Nova funkcija + default_tracker_support: Podrška + default_issue_status_new: Novi + default_issue_status_in_progress: In Progress + default_issue_status_resolved: Riješen + default_issue_status_feedback: Čeka se povratna informacija + default_issue_status_closed: Zatvoren + default_issue_status_rejected: Odbijen + default_doc_category_user: Korisnička dokumentacija + default_doc_category_tech: Tehnička dokumentacija + default_priority_low: Nizak + default_priority_normal: Normalan + default_priority_high: Visok + default_priority_urgent: Urgentno + default_priority_immediate: Odmah + default_activity_design: Dizajn + default_activity_development: Programiranje + + enumeration_issue_priorities: Prioritet aktivnosti + enumeration_doc_categories: Kategorije dokumenata + enumeration_activities: Operacije (utrošak vremena) + notice_unable_delete_version: Ne mogu izbrisati verziju. + button_create_and_continue: Kreiraj i nastavi + button_annotate: Zabilježi + button_activate: Aktiviraj + label_sort: Sortiranje + label_date_from_to: Od %{start} do %{end} + label_ascending: Rastuće + label_descending: Opadajuće + label_greater_or_equal: ">=" + label_less_or_equal: <= + text_wiki_page_destroy_question: This page has %{descendants} child page(s) and descendant(s). What do you want to do? + text_wiki_page_reassign_children: Reassign child pages to this parent page + text_wiki_page_nullify_children: Keep child pages as root pages + text_wiki_page_destroy_children: Delete child pages and all their descendants + setting_password_min_length: Minimum password length + field_group_by: Group results by + mail_subject_wiki_content_updated: "'%{id}' wiki page has been updated" + label_wiki_content_added: Wiki page added + mail_subject_wiki_content_added: "'%{id}' wiki page has been added" + mail_body_wiki_content_added: The '%{id}' wiki page has been added by %{author}. + label_wiki_content_updated: Wiki page updated + mail_body_wiki_content_updated: The '%{id}' wiki page has been updated by %{author}. + permission_add_project: Create project + setting_new_project_user_role_id: Role given to a non-admin user who creates a project + label_view_all_revisions: View all revisions + label_tag: Tag + label_branch: Branch + error_no_tracker_in_project: No tracker is associated to this project. Please check the Project settings. + error_no_default_issue_status: No default issue status is defined. Please check your configuration (Go to "Administration -> Issue statuses"). + text_journal_changed: "%{label} changed from %{old} to %{new}" + text_journal_set_to: "%{label} set to %{value}" + text_journal_deleted: "%{label} deleted (%{old})" + label_group_plural: Groups + label_group: Group + label_group_new: New group + label_time_entry_plural: Spent time + text_journal_added: "%{label} %{value} added" + field_active: Active + enumeration_system_activity: System Activity + permission_delete_issue_watchers: Delete watchers + version_status_closed: closed + version_status_locked: locked + version_status_open: open + error_can_not_reopen_issue_on_closed_version: An issue assigned to a closed version can not be reopened + label_user_anonymous: Anonymous + button_move_and_follow: Move and follow + setting_default_projects_modules: Default enabled modules for new projects + setting_gravatar_default: Default Gravatar image + field_sharing: Sharing + label_version_sharing_hierarchy: With project hierarchy + label_version_sharing_system: With all projects + label_version_sharing_descendants: With subprojects + label_version_sharing_tree: With project tree + label_version_sharing_none: Not shared + error_can_not_archive_project: This project can not be archived + button_duplicate: Duplicate + button_copy_and_follow: Copy and follow + label_copy_source: Source + setting_issue_done_ratio: Calculate the issue done ratio with + setting_issue_done_ratio_issue_status: Use the issue status + error_issue_done_ratios_not_updated: Issue done ratios not updated. + error_workflow_copy_target: Please select target tracker(s) and role(s) + setting_issue_done_ratio_issue_field: Use the issue field + label_copy_same_as_target: Same as target + label_copy_target: Target + notice_issue_done_ratios_updated: Issue done ratios updated. + error_workflow_copy_source: Please select a source tracker or role + label_update_issue_done_ratios: Update issue done ratios + setting_start_of_week: Start calendars on + permission_view_issues: View Issues + label_display_used_statuses_only: Only display statuses that are used by this tracker + label_revision_id: Revision %{value} + label_api_access_key: API access key + label_api_access_key_created_on: API access key created %{value} ago + label_feeds_access_key: RSS access key + notice_api_access_key_reseted: Your API access key was reset. + setting_rest_api_enabled: Enable REST web service + label_missing_api_access_key: Missing an API access key + label_missing_feeds_access_key: Missing a RSS access key + button_show: Show + text_line_separated: Multiple values allowed (one line for each value). + setting_mail_handler_body_delimiters: Truncate emails after one of these lines + permission_add_subprojects: Create subprojects + label_subproject_new: New subproject + text_own_membership_delete_confirmation: |- + You are about to remove some or all of your permissions and may no longer be able to edit this project after that. + Are you sure you want to continue? + label_close_versions: Close completed versions + label_board_sticky: Sticky + label_board_locked: Locked + permission_export_wiki_pages: Export wiki pages + setting_cache_formatted_text: Cache formatted text + permission_manage_project_activities: Manage project activities + error_unable_delete_issue_status: Unable to delete issue status + label_profile: Profile + permission_manage_subtasks: Manage subtasks + field_parent_issue: Parent task + label_subtask_plural: Subtasks + label_project_copy_notifications: Send email notifications during the project copy + error_can_not_delete_custom_field: Unable to delete custom field + error_unable_to_connect: Unable to connect (%{value}) + error_can_not_remove_role: This role is in use and can not be deleted. + error_can_not_delete_tracker: This tracker contains issues and can't be deleted. + field_principal: Principal + label_my_page_block: My page block + notice_failed_to_save_members: "Failed to save member(s): %{errors}." + text_zoom_out: Zoom out + text_zoom_in: Zoom in + notice_unable_delete_time_entry: Unable to delete time log entry. + label_overall_spent_time: Overall spent time + field_time_entries: Log time + project_module_gantt: Gantt + project_module_calendar: Calendar + button_edit_associated_wikipage: "Edit associated Wiki page: %{page_title}" + field_text: Text field + label_user_mail_option_only_owner: Only for things I am the owner of + setting_default_notification_option: Default notification option + label_user_mail_option_only_my_events: Only for things I watch or I'm involved in + label_user_mail_option_only_assigned: Only for things I am assigned to + label_user_mail_option_none: No events + field_member_of_group: Assignee's group + field_assigned_to_role: Assignee's role + notice_not_authorized_archived_project: The project you're trying to access has been archived. + label_principal_search: "Search for user or group:" + label_user_search: "Search for user:" + field_visible: Visible + setting_commit_logtime_activity_id: Activity for logged time + text_time_logged_by_changeset: Applied in changeset %{value}. + setting_commit_logtime_enabled: Enable time logging + notice_gantt_chart_truncated: The chart was truncated because it exceeds the maximum number of items that can be displayed (%{max}) + setting_gantt_items_limit: Maximum number of items displayed on the gantt chart + field_warn_on_leaving_unsaved: Warn me when leaving a page with unsaved text + text_warn_on_leaving_unsaved: The current page contains unsaved text that will be lost if you leave this page. + label_my_queries: My custom queries + text_journal_changed_no_detail: "%{label} updated" + label_news_comment_added: Comment added to a news + button_expand_all: Expand all + button_collapse_all: Collapse all + label_additional_workflow_transitions_for_assignee: Additional transitions allowed when the user is the assignee + label_additional_workflow_transitions_for_author: Additional transitions allowed when the user is the author + label_bulk_edit_selected_time_entries: Bulk edit selected time entries + text_time_entries_destroy_confirmation: Are you sure you want to delete the selected time entr(y/ies)? + label_role_anonymous: Anonymous + label_role_non_member: Non member + label_issue_note_added: Note added + label_issue_status_updated: Status updated + label_issue_priority_updated: Priority updated + label_issues_visibility_own: Issues created by or assigned to the user + field_issues_visibility: Issues visibility + label_issues_visibility_all: All issues + permission_set_own_issues_private: Set own issues public or private + field_is_private: Private + permission_set_issues_private: Set issues public or private + label_issues_visibility_public: All non private issues + text_issues_destroy_descendants_confirmation: This will also delete %{count} subtask(s). + field_commit_logs_encoding: 'Enkodiranje "commit" poruka' + field_scm_path_encoding: Path encoding + text_scm_path_encoding_note: "Default: UTF-8" + field_path_to_repository: Path to repository + field_root_directory: Root directory + field_cvs_module: Module + field_cvsroot: CVSROOT + text_mercurial_repository_note: Local repository (e.g. /hgrepo, c:\hgrepo) + text_scm_command: Command + text_scm_command_version: Version + label_git_report_last_commit: Report last commit for files and directories + notice_issue_successful_create: Issue %{id} created. + label_between: between + setting_issue_group_assignment: Allow issue assignment to groups + label_diff: diff + text_git_repository_note: Repository is bare and local (e.g. /gitrepo, c:\gitrepo) + description_query_sort_criteria_direction: Sort direction + description_project_scope: Search scope + description_filter: Filter + description_user_mail_notification: Mail notification settings + description_date_from: Enter start date + description_message_content: Message content + description_available_columns: Available Columns + description_date_range_interval: Choose range by selecting start and end date + description_issue_category_reassign: Choose issue category + description_search: Searchfield + description_notes: Notes + description_date_range_list: Choose range from list + description_choose_project: Projects + description_date_to: Enter end date + description_query_sort_criteria_attribute: Sort attribute + description_wiki_subpages_reassign: Choose new parent page + description_selected_columns: Selected Columns + label_parent_revision: Parent + label_child_revision: Child + error_scm_annotate_big_text_file: The entry cannot be annotated, as it exceeds the maximum text file size. + setting_default_issue_start_date_to_creation_date: Use current date as start date for new issues + button_edit_section: Edit this section + setting_repositories_encodings: Attachments and repositories encodings + description_all_columns: All Columns + button_export: Export + label_export_options: "%{export_format} export options" + error_attachment_too_big: This file cannot be uploaded because it exceeds the maximum allowed file size (%{max_size}) + notice_failed_to_save_time_entries: "Failed to save %{count} time entrie(s) on %{total} selected: %{ids}." + label_x_issues: + zero: 0 aktivnost + one: 1 aktivnost + other: "%{count} aktivnosti" + label_repository_new: New repository + field_repository_is_default: Main repository + label_copy_attachments: Copy attachments + label_item_position: "%{position}/%{count}" + label_completed_versions: Completed versions + text_project_identifier_info: Only lower case letters (a-z), numbers, dashes and underscores are allowed.
    Once saved, the identifier cannot be changed. + field_multiple: Multiple values + setting_commit_cross_project_ref: Allow issues of all the other projects to be referenced and fixed + text_issue_conflict_resolution_add_notes: Add my notes and discard my other changes + text_issue_conflict_resolution_overwrite: Apply my changes anyway (previous notes will be kept but some changes may be overwritten) + notice_issue_update_conflict: The issue has been updated by an other user while you were editing it. + text_issue_conflict_resolution_cancel: Discard all my changes and redisplay %{link} + permission_manage_related_issues: Manage related issues + field_auth_source_ldap_filter: LDAP filter + label_search_for_watchers: Search for watchers to add + notice_account_deleted: Your account has been permanently deleted. + setting_unsubscribe: Allow users to delete their own account + button_delete_my_account: Delete my account + text_account_destroy_confirmation: |- + Are you sure you want to proceed? + Your account will be permanently deleted, with no way to reactivate it. + error_session_expired: Your session has expired. Please login again. + text_session_expiration_settings: "Warning: changing these settings may expire the current sessions including yours." + setting_session_lifetime: Session maximum lifetime + setting_session_timeout: Session inactivity timeout + label_session_expiration: Session expiration + permission_close_project: Close / reopen the project + label_show_closed_projects: View closed projects + button_close: Close + button_reopen: Reopen + project_status_active: active + project_status_closed: closed + project_status_archived: archived + text_project_closed: This project is closed and read-only. + notice_user_successful_create: User %{id} created. + field_core_fields: Standard fields + field_timeout: Timeout (in seconds) + setting_thumbnails_enabled: Display attachment thumbnails + setting_thumbnails_size: Thumbnails size (in pixels) + label_status_transitions: Status transitions + label_fields_permissions: Fields permissions + label_readonly: Read-only + label_required: Required + text_repository_identifier_info: Only lower case letters (a-z), numbers, dashes and underscores are allowed.
    Once saved, the identifier cannot be changed. + field_board_parent: Parent forum + label_attribute_of_project: Project's %{name} + label_attribute_of_author: Author's %{name} + label_attribute_of_assigned_to: Assignee's %{name} + label_attribute_of_fixed_version: Target version's %{name} + label_copy_subtasks: Copy subtasks + label_copied_to: copied to + label_copied_from: copied from + label_any_issues_in_project: any issues in project + label_any_issues_not_in_project: any issues not in project + field_private_notes: Private notes + permission_view_private_notes: View private notes + permission_set_notes_private: Set notes as private + label_no_issues_in_project: no issues in project + label_any: sve + label_last_n_weeks: last %{count} weeks + setting_cross_project_subtasks: Allow cross-project subtasks + label_cross_project_descendants: With subprojects + label_cross_project_tree: With project tree + label_cross_project_hierarchy: With project hierarchy + label_cross_project_system: With all projects + button_hide: Hide + setting_non_working_week_days: Non-working days + label_in_the_next_days: in the next + label_in_the_past_days: in the past + label_attribute_of_user: User's %{name} + text_turning_multiple_off: If you disable multiple values, multiple values will be + removed in order to preserve only one value per item. + label_attribute_of_issue: Issue's %{name} + permission_add_documents: Add documents + permission_edit_documents: Edit documents + permission_delete_documents: Delete documents + label_gantt_progress_line: Progress line + setting_jsonp_enabled: Enable JSONP support + field_inherit_members: Inherit members + field_closed_on: Closed + setting_default_projects_tracker_ids: Default trackers for new projects + label_total_time: Ukupno + text_scm_config: You can configure your SCM commands in config/configuration.yml. Please restart the application after editing it. + text_scm_command_not_available: SCM command is not available. Please check settings on the administration panel. + setting_emails_header: Email header diff --git a/config/locales/ca.yml b/config/locales/ca.yml new file mode 100644 index 00000000..f9e6a40f --- /dev/null +++ b/config/locales/ca.yml @@ -0,0 +1,1091 @@ +# Redmine catalan translation: +# by Joan Duran + +ca: + # Text direction: Left-to-Right (ltr) or Right-to-Left (rtl) + direction: ltr + date: + formats: + # Use the strftime parameters for formats. + # When no format has been given, it uses default. + # You can provide other formats here if you like! + default: "%d-%m-%Y" + short: "%e de %b" + long: "%a, %e de %b de %Y" + + day_names: [Diumenge, Dilluns, Dimarts, Dimecres, Dijous, Divendres, Dissabte] + abbr_day_names: [dg, dl, dt, dc, dj, dv, ds] + + # Don't forget the nil at the beginning; there's no such thing as a 0th month + month_names: [~, Gener, Febrer, Març, Abril, Maig, Juny, Juliol, Agost, Setembre, Octubre, Novembre, Desembre] + abbr_month_names: [~, Gen, Feb, Mar, Abr, Mai, Jun, Jul, Ago, Set, Oct, Nov, Des] + # Used in date_select and datime_select. + order: + - :year + - :month + - :day + + time: + formats: + default: "%d-%m-%Y %H:%M" + time: "%H:%M" + short: "%e de %b, %H:%M" + long: "%a, %e de %b de %Y, %H:%M" + am: "am" + pm: "pm" + + datetime: + distance_in_words: + half_a_minute: "mig minut" + less_than_x_seconds: + one: "menys d'un segon" + other: "menys de %{count} segons" + x_seconds: + one: "1 segons" + other: "%{count} segons" + less_than_x_minutes: + one: "menys d'un minut" + other: "menys de %{count} minuts" + x_minutes: + one: "1 minut" + other: "%{count} minuts" + about_x_hours: + one: "aproximadament 1 hora" + other: "aproximadament %{count} hores" + x_hours: + one: "1 hour" + other: "%{count} hours" + x_days: + one: "1 dia" + other: "%{count} dies" + about_x_months: + one: "aproximadament 1 mes" + other: "aproximadament %{count} mesos" + x_months: + one: "1 mes" + other: "%{count} mesos" + about_x_years: + one: "aproximadament 1 any" + other: "aproximadament %{count} anys" + over_x_years: + one: "més d'un any" + other: "més de %{count} anys" + almost_x_years: + one: "almost 1 year" + other: "almost %{count} years" + + number: + # Default format for numbers + format: + separator: "." + delimiter: "" + precision: 3 + human: + format: + delimiter: "" + precision: 3 + storage_units: + format: "%n %u" + units: + byte: + one: "Byte" + other: "Bytes" + kb: "KB" + mb: "MB" + gb: "GB" + tb: "TB" + +# Used in array.to_sentence. + support: + array: + sentence_connector: "i" + skip_last_comma: false + + activerecord: + errors: + template: + header: + one: "1 error prohibited this %{model} from being saved" + other: "%{count} errors prohibited this %{model} from being saved" + messages: + inclusion: "no està inclòs a la llista" + exclusion: "està reservat" + invalid: "no és vàlid" + confirmation: "la confirmació no coincideix" + accepted: "s'ha d'acceptar" + empty: "no pot estar buit" + blank: "no pot estar en blanc" + too_long: "és massa llarg" + too_short: "és massa curt" + wrong_length: "la longitud és incorrecta" + taken: "ja s'està utilitzant" + not_a_number: "no és un número" + not_a_date: "no és una data vàlida" + greater_than: "ha de ser més gran que %{count}" + greater_than_or_equal_to: "ha de ser més gran o igual a %{count}" + equal_to: "ha de ser igual a %{count}" + less_than: "ha de ser menys que %{count}" + less_than_or_equal_to: "ha de ser menys o igual a %{count}" + odd: "ha de ser senar" + even: "ha de ser parell" + greater_than_start_date: "ha de ser superior que la data inicial" + not_same_project: "no pertany al mateix projecte" + circular_dependency: "Aquesta relació crearia una dependència circular" + cant_link_an_issue_with_a_descendant: "Un assumpte no es pot enllaçar a una de les seves subtasques" + + actionview_instancetag_blank_option: Seleccioneu + + general_text_No: 'No' + general_text_Yes: 'Si' + general_text_no: 'no' + general_text_yes: 'si' + general_lang_name: 'Català' + general_csv_separator: ';' + general_csv_decimal_separator: ',' + general_csv_encoding: ISO-8859-15 + general_pdf_encoding: UTF-8 + general_first_day_of_week: '1' + + notice_account_updated: "El compte s'ha actualitzat correctament." + notice_account_invalid_creditentials: Usuari o contrasenya invàlid + notice_account_password_updated: "La contrasenya s'ha modificat correctament." + notice_account_wrong_password: Contrasenya incorrecta + notice_account_register_done: "El compte s'ha creat correctament. Per a activar el compte, feu clic en l'enllaç que us han enviat per correu electrònic." + notice_account_unknown_email: Usuari desconegut. + notice_can_t_change_password: "Aquest compte utilitza una font d'autenticació externa. No és possible canviar la contrasenya." + notice_account_lost_email_sent: "S'ha enviat un correu electrònic amb instruccions per a seleccionar una contrasenya nova." + notice_account_activated: "El compte s'ha activat. Ara podeu entrar." + notice_successful_create: "S'ha creat correctament." + notice_successful_update: "S'ha modificat correctament." + notice_successful_delete: "S'ha suprimit correctament." + notice_successful_connection: "S'ha connectat correctament." + notice_file_not_found: "La pàgina a la que intenteu accedir no existeix o s'ha suprimit." + notice_locking_conflict: Un altre usuari ha actualitzat les dades. + notice_not_authorized: No teniu permís per a accedir a aquesta pàgina. + notice_email_sent: "S'ha enviat un correu electrònic a %{value}" + notice_email_error: "S'ha produït un error en enviar el correu (%{value})" + notice_feeds_access_key_reseted: "S'ha reiniciat la clau d'accés del RSS." + notice_api_access_key_reseted: "S'ha reiniciat la clau d'accés a l'API." + notice_failed_to_save_issues: "No s'han pogut desar %{count} assumptes de %{total} seleccionats: %{ids}." + notice_failed_to_save_members: "No s'han pogut desar els membres: %{errors}." + notice_no_issue_selected: "No s'ha seleccionat cap assumpte. Activeu els assumptes que voleu editar." + notice_account_pending: "S'ha creat el compte i ara està pendent de l'aprovació de l'administrador." + notice_default_data_loaded: "S'ha carregat correctament la configuració predeterminada." + notice_unable_delete_version: "No s'ha pogut suprimir la versió." + notice_unable_delete_time_entry: "No s'ha pogut suprimir l'entrada del registre de temps." + notice_issue_done_ratios_updated: "S'ha actualitzat el tant per cent dels assumptes." + + error_can_t_load_default_data: "No s'ha pogut carregar la configuració predeterminada: %{value} " + error_scm_not_found: "No s'ha trobat l'entrada o la revisió en el dipòsit." + error_scm_command_failed: "S'ha produït un error en intentar accedir al dipòsit: %{value}" + error_scm_annotate: "L'entrada no existeix o no s'ha pogut anotar." + error_issue_not_found_in_project: "No s'ha trobat l'assumpte o no pertany a aquest projecte" + error_no_tracker_in_project: "Aquest projecte no té seguidor associat. Comproveu els paràmetres del projecte." + error_no_default_issue_status: "No s'ha definit cap estat d'assumpte predeterminat. Comproveu la configuració (aneu a «Administració -> Estats de l'assumpte»)." + error_can_not_delete_custom_field: "No s'ha pogut suprimir el camp personalitat" + error_can_not_delete_tracker: "Aquest seguidor conté assumptes i no es pot suprimir." + error_can_not_remove_role: "Aquest rol s'està utilitzant i no es pot suprimir." + error_can_not_reopen_issue_on_closed_version: "Un assumpte assignat a una versió tancada no es pot tornar a obrir" + error_can_not_archive_project: "Aquest projecte no es pot arxivar" + error_issue_done_ratios_not_updated: "No s'ha actualitza el tant per cent dels assumptes." + error_workflow_copy_source: "Seleccioneu un seguidor o rol font" + error_workflow_copy_target: "Seleccioneu seguidors i rols objectiu" + error_unable_delete_issue_status: "No s'ha pogut suprimir l'estat de l'assumpte" + error_unable_to_connect: "No s'ha pogut connectar (%{value})" + warning_attachments_not_saved: "No s'han pogut desar %{count} fitxers." + + mail_subject_lost_password: "Contrasenya de %{value}" + mail_body_lost_password: "Per a canviar la contrasenya, feu clic en l'enllaç següent:" + mail_subject_register: "Activació del compte de %{value}" + mail_body_register: "Per a activar el compte, feu clic en l'enllaç següent:" + mail_body_account_information_external: "Podeu utilitzar el compte «%{value}» per a entrar." + mail_body_account_information: Informació del compte + mail_subject_account_activation_request: "Sol·licitud d'activació del compte de %{value}" + mail_body_account_activation_request: "S'ha registrat un usuari nou (%{value}). El seu compte està pendent d'aprovació:" + mail_subject_reminder: "%{count} assumptes venceran els següents %{days} dies" + mail_body_reminder: "%{count} assumptes que teniu assignades venceran els següents %{days} dies:" + mail_subject_wiki_content_added: "S'ha afegit la pàgina wiki «%{id}»" + mail_body_wiki_content_added: "En %{author} ha afegit la pàgina wiki «%{id}»." + mail_subject_wiki_content_updated: "S'ha actualitzat la pàgina wiki «%{id}»" + mail_body_wiki_content_updated: "En %{author} ha actualitzat la pàgina wiki «%{id}»." + + + field_name: Nom + field_description: Descripció + field_summary: Resum + field_is_required: Necessari + field_firstname: Nom + field_lastname: Cognom + field_mail: Correu electrònic + field_filename: Fitxer + field_filesize: Mida + field_downloads: Baixades + field_author: Autor + field_created_on: Creat + field_updated_on: Actualitzat + field_field_format: Format + field_is_for_all: Per a tots els projectes + field_possible_values: Valores possibles + field_regexp: Expressió regular + field_min_length: Longitud mínima + field_max_length: Longitud màxima + field_value: Valor + field_category: Categoria + field_title: Títol + field_project: Projecte + field_issue: Assumpte + field_status: Estat + field_notes: Notes + field_is_closed: Assumpte tancat + field_is_default: Estat predeterminat + field_tracker: Seguidor + field_subject: Tema + field_due_date: Data de venciment + field_assigned_to: Assignat a + field_priority: Prioritat + field_fixed_version: Versió objectiu + field_user: Usuari + field_principal: Principal + field_role: Rol + field_homepage: Pàgina web + field_is_public: Públic + field_parent: Subprojecte de + field_is_in_roadmap: Assumptes mostrats en la planificació + field_login: Entrada + field_mail_notification: Notificacions per correu electrònic + field_admin: Administrador + field_last_login_on: Última connexió + field_language: Idioma + field_effective_date: Data + field_password: Contrasenya + field_new_password: Contrasenya nova + field_password_confirmation: Confirmació + field_version: Versió + field_type: Tipus + field_host: Ordinador + field_port: Port + field_account: Compte + field_base_dn: Base DN + field_attr_login: "Atribut d'entrada" + field_attr_firstname: Atribut del nom + field_attr_lastname: Atribut del cognom + field_attr_mail: Atribut del correu electrònic + field_onthefly: "Creació de l'usuari «al vol»" + field_start_date: Inici + field_done_ratio: "% realitzat" + field_auth_source: "Mode d'autenticació" + field_hide_mail: "Oculta l'adreça de correu electrònic" + field_comments: Comentari + field_url: URL + field_start_page: Pàgina inicial + field_subproject: Subprojecte + field_hours: Hores + field_activity: Activitat + field_spent_on: Data + field_identifier: Identificador + field_is_filter: "S'ha utilitzat com a filtre" + field_issue_to: Assumpte relacionat + field_delay: Retard + field_assignable: Es poden assignar assumptes a aquest rol + field_redirect_existing_links: Redirigeix els enllaços existents + field_estimated_hours: Temps previst + field_column_names: Columnes + field_time_entries: "Registre de temps" + field_time_zone: Zona horària + field_searchable: Es pot cercar + field_default_value: Valor predeterminat + field_comments_sorting: Mostra els comentaris + field_parent_title: Pàgina pare + field_editable: Es pot editar + field_watcher: Vigilància + field_identity_url: URL OpenID + field_content: Contingut + field_group_by: "Agrupa els resultats per" + field_sharing: Compartició + field_parent_issue: "Tasca pare" + + setting_app_title: "Títol de l'aplicació" + setting_app_subtitle: "Subtítol de l'aplicació" + setting_welcome_text: Text de benvinguda + setting_default_language: Idioma predeterminat + setting_login_required: Es necessita autenticació + setting_self_registration: Registre automàtic + setting_attachment_max_size: Mida màxima dels adjunts + setting_issues_export_limit: "Límit d'exportació d'assumptes" + setting_mail_from: "Adreça de correu electrònic d'emissió" + setting_bcc_recipients: Vincula els destinataris de les còpies amb carbó (bcc) + setting_plain_text_mail: només text pla (no HTML) + setting_host_name: "Nom de l'ordinador" + setting_text_formatting: Format del text + setting_wiki_compression: "Comprimeix l'historial del wiki" + setting_feeds_limit: Límit de contingut del canal + setting_default_projects_public: Els projectes nous són públics per defecte + setting_autofetch_changesets: Omple automàticament les publicacions + setting_sys_api_enabled: Habilita el WS per a la gestió del dipòsit + setting_commit_ref_keywords: Paraules claus per a la referència + setting_commit_fix_keywords: Paraules claus per a la correcció + setting_autologin: Entrada automàtica + setting_date_format: Format de la data + setting_time_format: Format de hora + setting_cross_project_issue_relations: "Permet les relacions d'assumptes entre projectes" + setting_issue_list_default_columns: "Columnes mostrades per defecte en la llista d'assumptes" + setting_emails_footer: Peu dels correus electrònics + setting_protocol: Protocol + setting_per_page_options: Opcions dels objectes per pàgina + setting_user_format: "Format de com mostrar l'usuari" + setting_activity_days_default: "Dies a mostrar l'activitat del projecte" + setting_display_subprojects_issues: "Mostra els assumptes d'un subprojecte en el projecte pare per defecte" + setting_enabled_scm: "Habilita l'SCM" + setting_mail_handler_body_delimiters: "Trunca els correus electrònics després d'una d'aquestes línies" + setting_mail_handler_api_enabled: "Habilita el WS per correus electrònics d'entrada" + setting_mail_handler_api_key: Clau API + setting_sequential_project_identifiers: Genera identificadors de projecte seqüencials + setting_gravatar_enabled: "Utilitza les icones d'usuari Gravatar" + setting_gravatar_default: "Imatge Gravatar predeterminada" + setting_diff_max_lines_displayed: Número màxim de línies amb diferències mostrades + setting_file_max_size_displayed: Mida màxima dels fitxers de text mostrats en línia + setting_repository_log_display_limit: Número màxim de revisions que es mostren al registre de fitxers + setting_openid: "Permet entrar i registrar-se amb l'OpenID" + setting_password_min_length: "Longitud mínima de la contrasenya" + setting_new_project_user_role_id: "Aquest rol es dóna a un usuari no administrador per a crear projectes" + setting_default_projects_modules: "Mòduls activats per defecte en els projectes nous" + setting_issue_done_ratio: "Calcula tant per cent realitzat de l'assumpte amb" + setting_issue_done_ratio_issue_status: "Utilitza l'estat de l'assumpte" + setting_issue_done_ratio_issue_field: "Utilitza el camp de l'assumpte" + setting_start_of_week: "Inicia les setmanes en" + setting_rest_api_enabled: "Habilita el servei web REST" + setting_cache_formatted_text: Cache formatted text + + permission_add_project: "Crea projectes" + permission_add_subprojects: "Crea subprojectes" + permission_edit_project: Edita el projecte + permission_select_project_modules: Selecciona els mòduls del projecte + permission_manage_members: Gestiona els membres + permission_manage_project_activities: "Gestiona les activitats del projecte" + permission_manage_versions: Gestiona les versions + permission_manage_categories: Gestiona les categories dels assumptes + permission_view_issues: "Visualitza els assumptes" + permission_add_issues: Afegeix assumptes + permission_edit_issues: Edita els assumptes + permission_manage_issue_relations: Gestiona les relacions dels assumptes + permission_add_issue_notes: Afegeix notes + permission_edit_issue_notes: Edita les notes + permission_edit_own_issue_notes: Edita les notes pròpies + permission_move_issues: Mou els assumptes + permission_delete_issues: Suprimeix els assumptes + permission_manage_public_queries: Gestiona les consultes públiques + permission_save_queries: Desa les consultes + permission_view_gantt: Visualitza la gràfica de Gantt + permission_view_calendar: Visualitza el calendari + permission_view_issue_watchers: Visualitza la llista de vigilàncies + permission_add_issue_watchers: Afegeix vigilàncies + permission_delete_issue_watchers: Suprimeix els vigilants + permission_log_time: Registra el temps invertit + permission_view_time_entries: Visualitza el temps invertit + permission_edit_time_entries: Edita els registres de temps + permission_edit_own_time_entries: Edita els registres de temps propis + permission_manage_news: Gestiona les noticies + permission_comment_news: Comenta les noticies + permission_view_documents: Visualitza els documents + permission_manage_files: Gestiona els fitxers + permission_view_files: Visualitza els fitxers + permission_manage_wiki: Gestiona el wiki + permission_rename_wiki_pages: Canvia el nom de les pàgines wiki + permission_delete_wiki_pages: Suprimeix les pàgines wiki + permission_view_wiki_pages: Visualitza el wiki + permission_view_wiki_edits: "Visualitza l'historial del wiki" + permission_edit_wiki_pages: Edita les pàgines wiki + permission_delete_wiki_pages_attachments: Suprimeix adjunts + permission_protect_wiki_pages: Protegeix les pàgines wiki + permission_manage_repository: Gestiona el dipòsit + permission_browse_repository: Navega pel dipòsit + permission_view_changesets: Visualitza els canvis realitzats + permission_commit_access: Accés a les publicacions + permission_manage_boards: Gestiona els taulers + permission_view_messages: Visualitza els missatges + permission_add_messages: Envia missatges + permission_edit_messages: Edita els missatges + permission_edit_own_messages: Edita els missatges propis + permission_delete_messages: Suprimeix els missatges + permission_delete_own_messages: Suprimeix els missatges propis + permission_export_wiki_pages: "Exporta les pàgines wiki" + permission_manage_subtasks: "Gestiona subtasques" + + project_module_issue_tracking: "Seguidor d'assumptes" + project_module_time_tracking: Seguidor de temps + project_module_news: Noticies + project_module_documents: Documents + project_module_files: Fitxers + project_module_wiki: Wiki + project_module_repository: Dipòsit + project_module_boards: Taulers + project_module_calendar: Calendari + project_module_gantt: Gantt + + label_user: Usuari + label_user_plural: Usuaris + label_user_new: Usuari nou + label_user_anonymous: Anònim + label_project: Projecte + label_project_new: Projecte nou + label_project_plural: Projectes + label_x_projects: + zero: cap projecte + one: 1 projecte + other: "%{count} projectes" + label_project_all: Tots els projectes + label_project_latest: Els últims projectes + label_issue: Assumpte + label_issue_new: Assumpte nou + label_issue_plural: Assumptes + label_issue_view_all: Visualitza tots els assumptes + label_issues_by: "Assumptes per %{value}" + label_issue_added: Assumpte afegit + label_issue_updated: Assumpte actualitzat + label_document: Document + label_document_new: Document nou + label_document_plural: Documents + label_document_added: Document afegit + label_role: Rol + label_role_plural: Rols + label_role_new: Rol nou + label_role_and_permissions: Rols i permisos + label_member: Membre + label_member_new: Membre nou + label_member_plural: Membres + label_tracker: Seguidor + label_tracker_plural: Seguidors + label_tracker_new: Seguidor nou + label_workflow: Flux de treball + label_issue_status: "Estat de l'assumpte" + label_issue_status_plural: "Estats de l'assumpte" + label_issue_status_new: Estat nou + label_issue_category: "Categoria de l'assumpte" + label_issue_category_plural: "Categories de l'assumpte" + label_issue_category_new: Categoria nova + label_custom_field: Camp personalitzat + label_custom_field_plural: Camps personalitzats + label_custom_field_new: Camp personalitzat nou + label_enumerations: Enumeracions + label_enumeration_new: Valor nou + label_information: Informació + label_information_plural: Informació + label_please_login: Entreu + label_register: Registre + label_login_with_open_id_option: "o entra amb l'OpenID" + label_password_lost: Contrasenya perduda + label_home: Inici + label_my_page: La meva pàgina + label_my_account: El meu compte + label_my_projects: Els meus projectes + label_my_page_block: "Els meus blocs de pàgina" + label_administration: Administració + label_login: Entra + label_logout: Surt + label_help: Ajuda + label_reported_issues: Assumptes informats + label_assigned_to_me_issues: Assumptes assignats a mi + label_last_login: Última connexió + label_registered_on: Informat el + label_activity: Activitat + label_overall_activity: Activitat global + label_user_activity: "Activitat de %{value}" + label_new: Nou + label_logged_as: Heu entrat com a + label_environment: Entorn + label_authentication: Autenticació + label_auth_source: "Mode d'autenticació" + label_auth_source_new: "Mode d'autenticació nou" + label_auth_source_plural: "Modes d'autenticació" + label_subproject_plural: Subprojectes + label_subproject_new: "Subprojecte nou" + label_and_its_subprojects: "%{value} i els seus subprojectes" + label_min_max_length: Longitud mín - max + label_list: Llist + label_date: Data + label_integer: Enter + label_float: Flotant + label_boolean: Booleà + label_string: Text + label_text: Text llarg + label_attribute: Atribut + label_attribute_plural: Atributs + label_no_data: Sense dades a mostrar + label_change_status: "Canvia l'estat" + label_history: Historial + label_attachment: Fitxer + label_attachment_new: Fitxer nou + label_attachment_delete: Suprimeix el fitxer + label_attachment_plural: Fitxers + label_file_added: Fitxer afegit + label_report: Informe + label_report_plural: Informes + label_news: Noticies + label_news_new: Afegeix noticies + label_news_plural: Noticies + label_news_latest: Últimes noticies + label_news_view_all: Visualitza totes les noticies + label_news_added: Noticies afegides + label_settings: Paràmetres + label_overview: Resum + label_version: Versió + label_version_new: Versió nova + label_version_plural: Versions + label_close_versions: "Tanca les versions completades" + label_confirmation: Confirmació + label_export_to: "També disponible a:" + label_read: Llegeix... + label_public_projects: Projectes públics + label_open_issues: obert + label_open_issues_plural: oberts + label_closed_issues: tancat + label_closed_issues_plural: tancats + label_x_open_issues_abbr_on_total: + zero: 0 oberts / %{total} + one: 1 obert / %{total} + other: "%{count} oberts / %{total}" + label_x_open_issues_abbr: + zero: 0 oberts + one: 1 obert + other: "%{count} oberts" + label_x_closed_issues_abbr: + zero: 0 tancats + one: 1 tancat + other: "%{count} tancats" + label_total: Total + label_permissions: Permisos + label_current_status: Estat actual + label_new_statuses_allowed: Nous estats autoritzats + label_all: tots + label_none: cap + label_nobody: ningú + label_next: Següent + label_previous: Anterior + label_used_by: Utilitzat per + label_details: Detalls + label_add_note: Afegeix una nota + label_per_page: Per pàgina + label_calendar: Calendari + label_months_from: mesos des de + label_gantt: Gantt + label_internal: Intern + label_last_changes: "últims %{count} canvis" + label_change_view_all: Visualitza tots els canvis + label_personalize_page: Personalitza aquesta pàgina + label_comment: Comentari + label_comment_plural: Comentaris + label_x_comments: + zero: sense comentaris + one: 1 comentari + other: "%{count} comentaris" + label_comment_add: Afegeix un comentari + label_comment_added: Comentari afegit + label_comment_delete: Suprimeix comentaris + label_query: Consulta personalitzada + label_query_plural: Consultes personalitzades + label_query_new: Consulta nova + label_filter_add: Afegeix un filtre + label_filter_plural: Filtres + label_equals: és + label_not_equals: no és + label_in_less_than: en menys de + label_in_more_than: en més de + label_greater_or_equal: ">=" + label_less_or_equal: <= + label_in: en + label_today: avui + label_all_time: tot el temps + label_yesterday: ahir + label_this_week: aquesta setmana + label_last_week: "l'última setmana" + label_last_n_days: "els últims %{count} dies" + label_this_month: aquest més + label_last_month: "l'últim més" + label_this_year: aquest any + label_date_range: Abast de les dates + label_less_than_ago: fa menys de + label_more_than_ago: fa més de + label_ago: fa + label_contains: conté + label_not_contains: no conté + label_day_plural: dies + label_repository: Dipòsit + label_repository_plural: Dipòsits + label_browse: Navega + label_branch: Branca + label_tag: Etiqueta + label_revision: Revisió + label_revision_plural: Revisions + label_revision_id: "Revisió %{value}" + label_associated_revisions: Revisions associades + label_added: afegit + label_modified: modificat + label_copied: copiat + label_renamed: reanomenat + label_deleted: suprimit + label_latest_revision: Última revisió + label_latest_revision_plural: Últimes revisions + label_view_revisions: Visualitza les revisions + label_view_all_revisions: "Visualitza totes les revisions" + label_max_size: Mida màxima + label_sort_highest: Mou a la part superior + label_sort_higher: Mou cap amunt + label_sort_lower: Mou cap avall + label_sort_lowest: Mou a la part inferior + label_roadmap: Planificació + label_roadmap_due_in: "Venç en %{value}" + label_roadmap_overdue: "%{value} tard" + label_roadmap_no_issues: No hi ha assumptes per a aquesta versió + label_search: Cerca + label_result_plural: Resultats + label_all_words: Totes les paraules + label_wiki: Wiki + label_wiki_edit: Edició wiki + label_wiki_edit_plural: Edicions wiki + label_wiki_page: Pàgina wiki + label_wiki_page_plural: Pàgines wiki + label_index_by_title: Índex per títol + label_index_by_date: Índex per data + label_current_version: Versió actual + label_preview: Previsualització + label_feed_plural: Canals + label_changes_details: Detalls de tots els canvis + label_issue_tracking: "Seguiment d'assumptes" + label_spent_time: Temps invertit + label_overall_spent_time: "Temps total invertit" + label_f_hour: "%{value} hora" + label_f_hour_plural: "%{value} hores" + label_time_tracking: Temps de seguiment + label_change_plural: Canvis + label_statistics: Estadístiques + label_commits_per_month: Publicacions per mes + label_commits_per_author: Publicacions per autor + label_view_diff: Visualitza les diferències + label_diff_inline: en línia + label_diff_side_by_side: costat per costat + label_options: Opcions + label_copy_workflow_from: Copia el flux de treball des de + label_permissions_report: Informe de permisos + label_watched_issues: Assumptes vigilats + label_related_issues: Assumptes relacionats + label_applied_status: Estat aplicat + label_loading: "S'està carregant..." + label_relation_new: Relació nova + label_relation_delete: Suprimeix la relació + label_relates_to: relacionat amb + label_duplicates: duplicats + label_duplicated_by: duplicat per + label_blocks: bloqueja + label_blocked_by: bloquejats per + label_precedes: anterior a + label_follows: posterior a + label_end_to_start: final al començament + label_end_to_end: final al final + label_start_to_start: començament al començament + label_start_to_end: començament al final + label_stay_logged_in: "Manté l'entrada" + label_disabled: inhabilitat + label_show_completed_versions: Mostra les versions completes + label_me: jo mateix + label_board: Fòrum + label_board_new: Fòrum nou + label_board_plural: Fòrums + label_board_locked: Bloquejat + label_board_sticky: Sticky + label_topic_plural: Temes + label_message_plural: Missatges + label_message_last: Últim missatge + label_message_new: Missatge nou + label_message_posted: Missatge afegit + label_reply_plural: Respostes + label_send_information: "Envia la informació del compte a l'usuari" + label_year: Any + label_month: Mes + label_week: Setmana + label_date_from: Des de + label_date_to: A + label_language_based: "Basat en l'idioma de l'usuari" + label_sort_by: "Ordena per %{value}" + label_send_test_email: Envia un correu electrònic de prova + label_feeds_access_key: "Clau d'accés del RSS" + label_missing_feeds_access_key: "Falta una clau d'accés del RSS" + label_feeds_access_key_created_on: "Clau d'accés del RSS creada fa %{value}" + label_module_plural: Mòduls + label_added_time_by: "Afegit per %{author} fa %{age}" + label_updated_time_by: "Actualitzat per %{author} fa %{age}" + label_updated_time: "Actualitzat fa %{value}" + label_jump_to_a_project: Salta al projecte... + label_file_plural: Fitxers + label_changeset_plural: Conjunt de canvis + label_default_columns: Columnes predeterminades + label_no_change_option: (sense canvis) + label_bulk_edit_selected_issues: Edita en bloc els assumptes seleccionats + label_theme: Tema + label_default: Predeterminat + label_search_titles_only: Cerca només en els títols + label_user_mail_option_all: "Per qualsevol esdeveniment en tots els meus projectes" + label_user_mail_option_selected: "Per qualsevol esdeveniment en els projectes seleccionats..." + label_user_mail_no_self_notified: "No vull ser notificat pels canvis que faig jo mateix" + label_registration_activation_by_email: activació del compte per correu electrònic + label_registration_manual_activation: activació del compte manual + label_registration_automatic_activation: activació del compte automàtica + label_display_per_page: "Per pàgina: %{value}" + label_age: Edat + label_change_properties: Canvia les propietats + label_general: General + label_more: Més + label_scm: SCM + label_plugins: Connectors + label_ldap_authentication: Autenticació LDAP + label_downloads_abbr: Baixades + label_optional_description: Descripció opcional + label_add_another_file: Afegeix un altre fitxer + label_preferences: Preferències + label_chronological_order: En ordre cronològic + label_reverse_chronological_order: En ordre cronològic invers + label_planning: Planificació + label_incoming_emails: "Correu electrònics d'entrada" + label_generate_key: Genera una clau + label_issue_watchers: Vigilàncies + label_example: Exemple + label_display: Mostra + label_sort: Ordena + label_ascending: Ascendent + label_descending: Descendent + label_date_from_to: Des de %{start} a %{end} + label_wiki_content_added: "S'ha afegit la pàgina wiki" + label_wiki_content_updated: "S'ha actualitzat la pàgina wiki" + label_group: Grup + label_group_plural: Grups + label_group_new: Grup nou + label_time_entry_plural: Temps invertit + label_version_sharing_hierarchy: "Amb la jerarquia del projecte" + label_version_sharing_system: "Amb tots els projectes" + label_version_sharing_descendants: "Amb tots els subprojectes" + label_version_sharing_tree: "Amb l'arbre del projecte" + label_version_sharing_none: "Sense compartir" + label_update_issue_done_ratios: "Actualitza el tant per cent dels assumptes realitzats" + label_copy_source: Font + label_copy_target: Objectiu + label_copy_same_as_target: "El mateix que l'objectiu" + label_display_used_statuses_only: "Mostra només els estats que utilitza aquest seguidor" + label_api_access_key: "Clau d'accés a l'API" + label_missing_api_access_key: "Falta una clau d'accés de l'API" + label_api_access_key_created_on: "Clau d'accés de l'API creada fa %{value}" + label_profile: Perfil + label_subtask_plural: Subtasques + label_project_copy_notifications: "Envia notificacions de correu electrònic durant la còpia del projecte" + + button_login: Entra + button_submit: Tramet + button_save: Desa + button_check_all: Activa-ho tot + button_uncheck_all: Desactiva-ho tot + button_delete: Suprimeix + button_create: Crea + button_create_and_continue: Crea i continua + button_test: Test + button_edit: Edit + button_add: Afegeix + button_change: Canvia + button_apply: Aplica + button_clear: Neteja + button_lock: Bloca + button_unlock: Desbloca + button_download: Baixa + button_list: Llista + button_view: Visualitza + button_move: Mou + button_move_and_follow: "Mou i segueix" + button_back: Enrere + button_cancel: Cancel·la + button_activate: Activa + button_sort: Ordena + button_log_time: "Registre de temps" + button_rollback: Torna a aquesta versió + button_watch: Vigila + button_unwatch: No vigilis + button_reply: Resposta + button_archive: Arxiva + button_unarchive: Desarxiva + button_reset: Reinicia + button_rename: Reanomena + button_change_password: Canvia la contrasenya + button_copy: Copia + button_copy_and_follow: "Copia i segueix" + button_annotate: Anota + button_update: Actualitza + button_configure: Configura + button_quote: Cita + button_duplicate: Duplica + button_show: Mostra + + status_active: actiu + status_registered: informat + status_locked: bloquejat + + version_status_open: oberta + version_status_locked: bloquejada + version_status_closed: tancada + + field_active: Actiu + + text_select_mail_notifications: "Seleccioneu les accions per les quals s'hauria d'enviar una notificació per correu electrònic." + text_regexp_info: ex. ^[A-Z0-9]+$ + text_min_max_length_info: 0 significa sense restricció + text_project_destroy_confirmation: Segur que voleu suprimir aquest projecte i les dades relacionades? + text_subprojects_destroy_warning: "També seran suprimits els seus subprojectes: %{value}." + text_workflow_edit: Seleccioneu un rol i un seguidor per a editar el flux de treball + text_are_you_sure: Segur? + text_journal_changed: "%{label} ha canviat de %{old} a %{new}" + text_journal_set_to: "%{label} s'ha establert a %{value}" + text_journal_deleted: "%{label} s'ha suprimit (%{old})" + text_journal_added: "S'ha afegit %{label} %{value}" + text_tip_issue_begin_day: "tasca que s'inicia aquest dia" + text_tip_issue_end_day: tasca que finalitza aquest dia + text_tip_issue_begin_end_day: "tasca que s'inicia i finalitza aquest dia" + text_caracters_maximum: "%{count} caràcters com a màxim." + text_caracters_minimum: "Com a mínim ha de tenir %{count} caràcters." + text_length_between: "Longitud entre %{min} i %{max} caràcters." + text_tracker_no_workflow: "No s'ha definit cap flux de treball per a aquest seguidor" + text_unallowed_characters: Caràcters no permesos + text_comma_separated: Es permeten valors múltiples (separats per una coma). + text_line_separated: "Es permeten diversos valors (una línia per cada valor)." + text_issues_ref_in_commit_messages: Referència i soluciona els assumptes en els missatges publicats + text_issue_added: "L'assumpte %{id} ha sigut informat per %{author}." + text_issue_updated: "L'assumpte %{id} ha sigut actualitzat per %{author}." + text_wiki_destroy_confirmation: Segur que voleu suprimir aquest wiki i tots els seus continguts? + text_issue_category_destroy_question: "Alguns assumptes (%{count}) estan assignats a aquesta categoria. Què voleu fer?" + text_issue_category_destroy_assignments: Suprimeix les assignacions de la categoria + text_issue_category_reassign_to: Torna a assignar els assumptes a aquesta categoria + text_user_mail_option: "Per als projectes no seleccionats, només rebreu notificacions sobre les coses que vigileu o que hi esteu implicat (ex. assumptes que en sou l'autor o hi esteu assignat)." + text_no_configuration_data: "Encara no s'han configurat els rols, seguidors, estats de l'assumpte i flux de treball.\nÉs altament recomanable que carregueu la configuració predeterminada. Podreu modificar-la un cop carregada." + text_load_default_configuration: Carrega la configuració predeterminada + text_status_changed_by_changeset: "Aplicat en el conjunt de canvis %{value}." + text_issues_destroy_confirmation: "Segur que voleu suprimir els assumptes seleccionats?" + text_select_project_modules: "Seleccioneu els mòduls a habilitar per a aquest projecte:" + text_default_administrator_account_changed: "S'ha canviat el compte d'administrador predeterminat" + text_file_repository_writable: Es pot escriure en el dipòsit de fitxers + text_plugin_assets_writable: Es pot escriure als connectors actius + text_rmagick_available: RMagick disponible (opcional) + text_destroy_time_entries_question: "S'han informat %{hours} hores en els assumptes que aneu a suprimir. Què voleu fer?" + text_destroy_time_entries: Suprimeix les hores informades + text_assign_time_entries_to_project: Assigna les hores informades al projecte + text_reassign_time_entries: "Torna a assignar les hores informades a aquest assumpte:" + text_user_wrote: "%{value} va escriure:" + text_enumeration_destroy_question: "%{count} objectes estan assignats a aquest valor." + text_enumeration_category_reassign_to: "Torna a assignar-los a aquest valor:" + text_email_delivery_not_configured: "El lliurament per correu electrònic no està configurat i les notificacions estan inhabilitades.\nConfigureu el servidor SMTP a config/configuration.yml i reinicieu l'aplicació per habilitar-lo." + text_repository_usernames_mapping: "Seleccioneu l'assignació entre els usuaris del Redmine i cada nom d'usuari trobat al dipòsit.\nEls usuaris amb el mateix nom d'usuari o correu del Redmine i del dipòsit s'assignaran automàticament." + text_diff_truncated: "... Aquestes diferències s'han trucat perquè excedeixen la mida màxima que es pot mostrar." + text_custom_field_possible_values_info: "Una línia per a cada valor" + text_wiki_page_destroy_question: "Aquesta pàgina té %{descendants} pàgines fill i descendents. Què voleu fer?" + text_wiki_page_nullify_children: "Deixa les pàgines fill com a pàgines arrel" + text_wiki_page_destroy_children: "Suprimeix les pàgines fill i tots els seus descendents" + text_wiki_page_reassign_children: "Reasigna les pàgines fill a aquesta pàgina pare" + text_own_membership_delete_confirmation: "Esteu a punt de suprimir algun o tots els vostres permisos i potser no podreu editar més aquest projecte.\nSegur que voleu continuar?" + text_zoom_in: Redueix + text_zoom_out: Amplia + + default_role_manager: Gestor + default_role_developer: Desenvolupador + default_role_reporter: Informador + default_tracker_bug: Error + default_tracker_feature: Característica + default_tracker_support: Suport + default_issue_status_new: Nou + default_issue_status_in_progress: In Progress + default_issue_status_resolved: Resolt + default_issue_status_feedback: Comentaris + default_issue_status_closed: Tancat + default_issue_status_rejected: Rebutjat + default_doc_category_user: "Documentació d'usuari" + default_doc_category_tech: Documentació tècnica + default_priority_low: Baixa + default_priority_normal: Normal + default_priority_high: Alta + default_priority_urgent: Urgent + default_priority_immediate: Immediata + default_activity_design: Disseny + default_activity_development: Desenvolupament + + enumeration_issue_priorities: Prioritat dels assumptes + enumeration_doc_categories: Categories del document + enumeration_activities: Activitats (seguidor de temps) + enumeration_system_activity: Activitat del sistema + + button_edit_associated_wikipage: "Edit associated Wiki page: %{page_title}" + field_text: Text field + label_user_mail_option_only_owner: Only for things I am the owner of + setting_default_notification_option: Default notification option + label_user_mail_option_only_my_events: Only for things I watch or I'm involved in + label_user_mail_option_only_assigned: Only for things I am assigned to + label_user_mail_option_none: No events + field_member_of_group: Assignee's group + field_assigned_to_role: Assignee's role + notice_not_authorized_archived_project: The project you're trying to access has been archived. + label_principal_search: "Search for user or group:" + label_user_search: "Search for user:" + field_visible: Visible + setting_commit_logtime_activity_id: Activity for logged time + text_time_logged_by_changeset: Applied in changeset %{value}. + setting_commit_logtime_enabled: Enable time logging + notice_gantt_chart_truncated: The chart was truncated because it exceeds the maximum number of items that can be displayed (%{max}) + setting_gantt_items_limit: Maximum number of items displayed on the gantt chart + field_warn_on_leaving_unsaved: Warn me when leaving a page with unsaved text + text_warn_on_leaving_unsaved: The current page contains unsaved text that will be lost if you leave this page. + label_my_queries: My custom queries + text_journal_changed_no_detail: "%{label} updated" + label_news_comment_added: Comment added to a news + button_expand_all: Expand all + button_collapse_all: Collapse all + label_additional_workflow_transitions_for_assignee: Additional transitions allowed when the user is the assignee + label_additional_workflow_transitions_for_author: Additional transitions allowed when the user is the author + label_bulk_edit_selected_time_entries: Bulk edit selected time entries + text_time_entries_destroy_confirmation: Are you sure you want to delete the selected time entr(y/ies)? + label_role_anonymous: Anonymous + label_role_non_member: Non member + label_issue_note_added: Note added + label_issue_status_updated: Status updated + label_issue_priority_updated: Priority updated + label_issues_visibility_own: Issues created by or assigned to the user + field_issues_visibility: Issues visibility + label_issues_visibility_all: All issues + permission_set_own_issues_private: Set own issues public or private + field_is_private: Private + permission_set_issues_private: Set issues public or private + label_issues_visibility_public: All non private issues + text_issues_destroy_descendants_confirmation: This will also delete %{count} subtask(s). + field_commit_logs_encoding: Codificació dels missatges publicats + field_scm_path_encoding: Path encoding + text_scm_path_encoding_note: "Default: UTF-8" + field_path_to_repository: Path to repository + field_root_directory: Root directory + field_cvs_module: Module + field_cvsroot: CVSROOT + text_mercurial_repository_note: Local repository (e.g. /hgrepo, c:\hgrepo) + text_scm_command: Command + text_scm_command_version: Version + label_git_report_last_commit: Report last commit for files and directories + notice_issue_successful_create: Issue %{id} created. + label_between: between + setting_issue_group_assignment: Allow issue assignment to groups + label_diff: diff + text_git_repository_note: Repository is bare and local (e.g. /gitrepo, c:\gitrepo) + description_query_sort_criteria_direction: Sort direction + description_project_scope: Search scope + description_filter: Filter + description_user_mail_notification: Mail notification settings + description_date_from: Enter start date + description_message_content: Message content + description_available_columns: Available Columns + description_date_range_interval: Choose range by selecting start and end date + description_issue_category_reassign: Choose issue category + description_search: Searchfield + description_notes: Notes + description_date_range_list: Choose range from list + description_choose_project: Projects + description_date_to: Enter end date + description_query_sort_criteria_attribute: Sort attribute + description_wiki_subpages_reassign: Choose new parent page + description_selected_columns: Selected Columns + label_parent_revision: Parent + label_child_revision: Child + error_scm_annotate_big_text_file: The entry cannot be annotated, as it exceeds the maximum text file size. + setting_default_issue_start_date_to_creation_date: Use current date as start date for new issues + button_edit_section: Edit this section + setting_repositories_encodings: Attachments and repositories encodings + description_all_columns: All Columns + button_export: Export + label_export_options: "%{export_format} export options" + error_attachment_too_big: This file cannot be uploaded because it exceeds the maximum allowed file size (%{max_size}) + notice_failed_to_save_time_entries: "Failed to save %{count} time entrie(s) on %{total} selected: %{ids}." + label_x_issues: + zero: 0 assumpte + one: 1 assumpte + other: "%{count} assumptes" + label_repository_new: New repository + field_repository_is_default: Main repository + label_copy_attachments: Copy attachments + label_item_position: "%{position}/%{count}" + label_completed_versions: Completed versions + text_project_identifier_info: Only lower case letters (a-z), numbers, dashes and underscores are allowed.
    Once saved, the identifier cannot be changed. + field_multiple: Multiple values + setting_commit_cross_project_ref: Allow issues of all the other projects to be referenced and fixed + text_issue_conflict_resolution_add_notes: Add my notes and discard my other changes + text_issue_conflict_resolution_overwrite: Apply my changes anyway (previous notes will be kept but some changes may be overwritten) + notice_issue_update_conflict: The issue has been updated by an other user while you were editing it. + text_issue_conflict_resolution_cancel: Discard all my changes and redisplay %{link} + permission_manage_related_issues: Manage related issues + field_auth_source_ldap_filter: LDAP filter + label_search_for_watchers: Search for watchers to add + notice_account_deleted: Your account has been permanently deleted. + setting_unsubscribe: Allow users to delete their own account + button_delete_my_account: Delete my account + text_account_destroy_confirmation: |- + Are you sure you want to proceed? + Your account will be permanently deleted, with no way to reactivate it. + error_session_expired: Your session has expired. Please login again. + text_session_expiration_settings: "Warning: changing these settings may expire the current sessions including yours." + setting_session_lifetime: Session maximum lifetime + setting_session_timeout: Session inactivity timeout + label_session_expiration: Session expiration + permission_close_project: Close / reopen the project + label_show_closed_projects: View closed projects + button_close: Close + button_reopen: Reopen + project_status_active: active + project_status_closed: closed + project_status_archived: archived + text_project_closed: This project is closed and read-only. + notice_user_successful_create: User %{id} created. + field_core_fields: Standard fields + field_timeout: Timeout (in seconds) + setting_thumbnails_enabled: Display attachment thumbnails + setting_thumbnails_size: Thumbnails size (in pixels) + label_status_transitions: Status transitions + label_fields_permissions: Fields permissions + label_readonly: Read-only + label_required: Required + text_repository_identifier_info: Only lower case letters (a-z), numbers, dashes and underscores are allowed.
    Once saved, the identifier cannot be changed. + field_board_parent: Parent forum + label_attribute_of_project: Project's %{name} + label_attribute_of_author: Author's %{name} + label_attribute_of_assigned_to: Assignee's %{name} + label_attribute_of_fixed_version: Target version's %{name} + label_copy_subtasks: Copy subtasks + label_copied_to: copied to + label_copied_from: copied from + label_any_issues_in_project: any issues in project + label_any_issues_not_in_project: any issues not in project + field_private_notes: Private notes + permission_view_private_notes: View private notes + permission_set_notes_private: Set notes as private + label_no_issues_in_project: no issues in project + label_any: tots + label_last_n_weeks: last %{count} weeks + setting_cross_project_subtasks: Allow cross-project subtasks + label_cross_project_descendants: "Amb tots els subprojectes" + label_cross_project_tree: "Amb l'arbre del projecte" + label_cross_project_hierarchy: "Amb la jerarquia del projecte" + label_cross_project_system: "Amb tots els projectes" + button_hide: Hide + setting_non_working_week_days: Non-working days + label_in_the_next_days: in the next + label_in_the_past_days: in the past + label_attribute_of_user: User's %{name} + text_turning_multiple_off: If you disable multiple values, multiple values will be + removed in order to preserve only one value per item. + label_attribute_of_issue: Issue's %{name} + permission_add_documents: Add documents + permission_edit_documents: Edit documents + permission_delete_documents: Delete documents + label_gantt_progress_line: Progress line + setting_jsonp_enabled: Enable JSONP support + field_inherit_members: Inherit members + field_closed_on: Closed + setting_default_projects_tracker_ids: Default trackers for new projects + label_total_time: Total + text_scm_config: You can configure your SCM commands in config/configuration.yml. Please restart the application after editing it. + text_scm_command_not_available: SCM command is not available. Please check settings on the administration panel. + setting_emails_header: Email header diff --git a/config/locales/cs.yml b/config/locales/cs.yml new file mode 100644 index 00000000..81870f83 --- /dev/null +++ b/config/locales/cs.yml @@ -0,0 +1,1093 @@ +# Update to 2.2 by Karel Picman +# Update to 1.1 by Michal Gebauer +# Updated by Josef Liška +# CZ translation by Maxim Krušina | Massimo Filippi, s.r.o. | maxim@mxm.cz +# Based on original CZ translation by Jan Kadleček +cs: + # Text direction: Left-to-Right (ltr) or Right-to-Left (rtl) + direction: ltr + date: + formats: + # Use the strftime parameters for formats. + # When no format has been given, it uses default. + # You can provide other formats here if you like! + default: "%Y-%m-%d" + short: "%b %d" + long: "%B %d, %Y" + + day_names: [Neděle, Pondělí, Úterý, Středa, Čtvrtek, Pátek, Sobota] + abbr_day_names: [Ne, Po, Út, St, Čt, Pá, So] + + # Don't forget the nil at the beginning; there's no such thing as a 0th month + month_names: [~, Leden, Únor, Březen, Duben, Květen, Červen, Červenec, Srpen, Září, Říjen, Listopad, Prosinec] + abbr_month_names: [~, Led, Úno, Bře, Dub, Kvě, Čer, Čec, Srp, Zář, Říj, Lis, Pro] + # Used in date_select and datime_select. + order: + - :year + - :month + - :day + + time: + formats: + default: "%a, %d %b %Y %H:%M:%S %z" + time: "%H:%M" + short: "%d %b %H:%M" + long: "%B %d, %Y %H:%M" + am: "dop." + pm: "odp." + + datetime: + distance_in_words: + half_a_minute: "půl minuty" + less_than_x_seconds: + one: "méně než sekunda" + other: "méně než %{count} sekund" + x_seconds: + one: "1 sekunda" + other: "%{count} sekund" + less_than_x_minutes: + one: "méně než minuta" + other: "méně než %{count} minut" + x_minutes: + one: "1 minuta" + other: "%{count} minut" + about_x_hours: + one: "asi 1 hodina" + other: "asi %{count} hodin" + x_hours: + one: "1 hour" + other: "%{count} hours" + x_days: + one: "1 den" + other: "%{count} dnů" + about_x_months: + one: "asi 1 měsíc" + other: "asi %{count} měsíců" + x_months: + one: "1 měsíc" + other: "%{count} měsíců" + about_x_years: + one: "asi 1 rok" + other: "asi %{count} let" + over_x_years: + one: "více než 1 rok" + other: "více než %{count} roky" + almost_x_years: + one: "témeř 1 rok" + other: "téměř %{count} roky" + + number: + # Výchozí formát pro čísla + format: + separator: "." + delimiter: "" + precision: 3 + human: + format: + delimiter: "" + precision: 3 + storage_units: + format: "%n %u" + units: + byte: + one: "Bajt" + other: "Bajtů" + kb: "KB" + mb: "MB" + gb: "GB" + tb: "TB" + +# Used in array.to_sentence. + support: + array: + sentence_connector: "a" + skip_last_comma: false + + activerecord: + errors: + template: + header: + one: "1 chyba zabránila uložení %{model}" + other: "%{count} chyb zabránilo uložení %{model}" + messages: + inclusion: "není zahrnuto v seznamu" + exclusion: "je rezervováno" + invalid: "je neplatné" + confirmation: "se neshoduje s potvrzením" + accepted: "musí být akceptováno" + empty: "nemůže být prázdný" + blank: "nemůže být prázdný" + too_long: "je příliš dlouhý" + too_short: "je příliš krátký" + wrong_length: "má chybnou délku" + taken: "je již použito" + not_a_number: "není číslo" + not_a_date: "není platné datum" + greater_than: "musí být větší než %{count}" + greater_than_or_equal_to: "musí být větší nebo rovno %{count}" + equal_to: "musí být přesně %{count}" + less_than: "musí být méně než %{count}" + less_than_or_equal_to: "musí být méně nebo rovno %{count}" + odd: "musí být liché" + even: "musí být sudé" + greater_than_start_date: "musí být větší než počáteční datum" + not_same_project: "nepatří stejnému projektu" + circular_dependency: "Tento vztah by vytvořil cyklickou závislost" + cant_link_an_issue_with_a_descendant: "Úkol nemůže být spojen s jedním z jeho dílčích úkolů" + + actionview_instancetag_blank_option: Prosím vyberte + + general_text_No: 'Ne' + general_text_Yes: 'Ano' + general_text_no: 'ne' + general_text_yes: 'ano' + general_lang_name: 'Czech (Čeština)' + general_csv_separator: ',' + general_csv_decimal_separator: '.' + general_csv_encoding: UTF-8 + general_pdf_encoding: UTF-8 + general_first_day_of_week: '1' + + notice_account_updated: Účet byl úspěšně změněn. + notice_account_invalid_creditentials: Chybné jméno nebo heslo + notice_account_password_updated: Heslo bylo úspěšně změněno. + notice_account_wrong_password: Chybné heslo + notice_account_register_done: Účet byl úspěšně vytvořen. Pro aktivaci účtu klikněte na odkaz v emailu, který vám byl zaslán. + notice_account_unknown_email: Neznámý uživatel. + notice_can_t_change_password: Tento účet používá externí autentifikaci. Zde heslo změnit nemůžete. + notice_account_lost_email_sent: Byl vám zaslán email s intrukcemi jak si nastavíte nové heslo. + notice_account_activated: Váš účet byl aktivován. Nyní se můžete přihlásit. + notice_successful_create: Úspěšně vytvořeno. + notice_successful_update: Úspěšně aktualizováno. + notice_successful_delete: Úspěšně odstraněno. + notice_successful_connection: Úspěšné připojení. + notice_file_not_found: Stránka, kterou se snažíte zobrazit, neexistuje nebo byla smazána. + notice_locking_conflict: Údaje byly změněny jiným uživatelem. + notice_not_authorized: Nemáte dostatečná práva pro zobrazení této stránky. + notice_not_authorized_archived_project: Projekt, ke kterému se snažíte přistupovat, byl archivován. + notice_email_sent: "Na adresu %{value} byl odeslán email" + notice_email_error: "Při odesílání emailu nastala chyba (%{value})" + notice_feeds_access_key_reseted: Váš klíč pro přístup k RSS byl resetován. + notice_api_access_key_reseted: Váš API přístupový klíč byl resetován. + notice_failed_to_save_issues: "Chyba při uložení %{count} úkolu(ů) z %{total} vybraných: %{ids}." + notice_failed_to_save_members: "Nepodařilo se uložit člena(y): %{errors}." + notice_no_issue_selected: "Nebyl zvolen žádný úkol. Prosím, zvolte úkoly, které chcete editovat" + notice_account_pending: "Váš účet byl vytvořen, nyní čeká na schválení administrátorem." + notice_default_data_loaded: Výchozí konfigurace úspěšně nahrána. + notice_unable_delete_version: Nemohu odstanit verzi + notice_unable_delete_time_entry: Nelze smazat záznam času. + notice_issue_done_ratios_updated: Koeficienty dokončení úkolu byly aktualizovány. + notice_gantt_chart_truncated: Graf byl oříznut, počet položek přesáhl limit pro zobrazení (%{max}) + + error_can_t_load_default_data: "Výchozí konfigurace nebyla nahrána: %{value}" + error_scm_not_found: "Položka a/nebo revize neexistují v repozitáři." + error_scm_command_failed: "Při pokusu o přístup k repozitáři došlo k chybě: %{value}" + error_scm_annotate: "Položka neexistuje nebo nemůže být komentována." + error_issue_not_found_in_project: 'Úkol nebyl nalezen nebo nepatří k tomuto projektu' + error_no_tracker_in_project: Žádná fronta nebyla přiřazena tomuto projektu. Prosím zkontroluje nastavení projektu. + error_no_default_issue_status: Není nastaven výchozí stav úkolů. Prosím zkontrolujte nastavení ("Administrace -> Stavy úkolů"). + error_can_not_delete_custom_field: Nelze smazat volitelné pole + error_can_not_delete_tracker: Tato fronta obsahuje úkoly a nemůže být smazána. + error_can_not_remove_role: Tato role je právě používaná a nelze ji smazat. + error_can_not_reopen_issue_on_closed_version: Úkol přiřazený k uzavřené verzi nemůže být znovu otevřen + error_can_not_archive_project: Tento projekt nemůže být archivován + error_issue_done_ratios_not_updated: Koeficient dokončení úkolu nebyl aktualizován. + error_workflow_copy_source: Prosím vyberte zdrojovou frontu nebo roli + error_workflow_copy_target: Prosím vyberte cílovou frontu(y) a roli(e) + error_unable_delete_issue_status: Nelze smazat stavy úkolů + error_unable_to_connect: Nelze se připojit (%{value}) + warning_attachments_not_saved: "%{count} soubor(ů) nebylo možné uložit." + + mail_subject_lost_password: "Vaše heslo (%{value})" + mail_body_lost_password: 'Pro změnu vašeho hesla klikněte na následující odkaz:' + mail_subject_register: "Aktivace účtu (%{value})" + mail_body_register: 'Pro aktivaci vašeho účtu klikněte na následující odkaz:' + mail_body_account_information_external: "Pomocí vašeho účtu %{value} se můžete přihlásit." + mail_body_account_information: Informace o vašem účtu + mail_subject_account_activation_request: "Aktivace %{value} účtu" + mail_body_account_activation_request: "Byl zaregistrován nový uživatel %{value}. Aktivace jeho účtu závisí na vašem potvrzení." + mail_subject_reminder: "%{count} úkol(ů) má termín během několik dní (%{days})" + mail_body_reminder: "%{count} úkol(ů), které máte přiřazeny má termín během několika dní (%{days}):" + mail_subject_wiki_content_added: "'%{id}' Wiki stránka byla přidána" + mail_body_wiki_content_added: "'%{id}' Wiki stránka byla přidána od %{author}." + mail_subject_wiki_content_updated: "'%{id}' Wiki stránka byla aktualizována" + mail_body_wiki_content_updated: "'%{id}' Wiki stránka byla aktualizována od %{author}." + + + field_name: Název + field_description: Popis + field_summary: Přehled + field_is_required: Povinné pole + field_firstname: Jméno + field_lastname: Příjmení + field_mail: Email + field_filename: Soubor + field_filesize: Velikost + field_downloads: Staženo + field_author: Autor + field_created_on: Vytvořeno + field_updated_on: Aktualizováno + field_field_format: Formát + field_is_for_all: Pro všechny projekty + field_possible_values: Možné hodnoty + field_regexp: Regulární výraz + field_min_length: Minimální délka + field_max_length: Maximální délka + field_value: Hodnota + field_category: Kategorie + field_title: Název + field_project: Projekt + field_issue: Úkol + field_status: Stav + field_notes: Poznámka + field_is_closed: Úkol uzavřen + field_is_default: Výchozí stav + field_tracker: Fronta + field_subject: Předmět + field_due_date: Uzavřít do + field_assigned_to: Přiřazeno + field_priority: Priorita + field_fixed_version: Cílová verze + field_user: Uživatel + field_principal: Hlavní + field_role: Role + field_homepage: Domovská stránka + field_is_public: Veřejný + field_parent: Nadřazený projekt + field_is_in_roadmap: Úkoly zobrazené v plánu + field_login: Přihlášení + field_mail_notification: Emailová oznámení + field_admin: Administrátor + field_last_login_on: Poslední přihlášení + field_language: Jazyk + field_effective_date: Datum + field_password: Heslo + field_new_password: Nové heslo + field_password_confirmation: Potvrzení + field_version: Verze + field_type: Typ + field_host: Host + field_port: Port + field_account: Účet + field_base_dn: Base DN + field_attr_login: Přihlášení (atribut) + field_attr_firstname: Jméno (atribut) + field_attr_lastname: Příjemní (atribut) + field_attr_mail: Email (atribut) + field_onthefly: Automatické vytváření uživatelů + field_start_date: Začátek + field_done_ratio: "% Hotovo" + field_auth_source: Autentifikační mód + field_hide_mail: Nezobrazovat můj email + field_comments: Komentář + field_url: URL + field_start_page: Výchozí stránka + field_subproject: Podprojekt + field_hours: Hodiny + field_activity: Aktivita + field_spent_on: Datum + field_identifier: Identifikátor + field_is_filter: Použít jako filtr + field_issue_to: Související úkol + field_delay: Zpoždění + field_assignable: Úkoly mohou být přiřazeny této roli + field_redirect_existing_links: Přesměrovat stávající odkazy + field_estimated_hours: Odhadovaná doba + field_column_names: Sloupce + field_time_entries: Zaznamenaný čas + field_time_zone: Časové pásmo + field_searchable: Umožnit vyhledávání + field_default_value: Výchozí hodnota + field_comments_sorting: Zobrazit komentáře + field_parent_title: Rodičovská stránka + field_editable: Editovatelný + field_watcher: Sleduje + field_identity_url: OpenID URL + field_content: Obsah + field_group_by: Seskupovat výsledky podle + field_sharing: Sdílení + field_parent_issue: Rodičovský úkol + field_member_of_group: Skupina přiřaditele + field_assigned_to_role: Role přiřaditele + field_text: Textové pole + field_visible: Viditelný + + setting_app_title: Název aplikace + setting_app_subtitle: Podtitulek aplikace + setting_welcome_text: Uvítací text + setting_default_language: Výchozí jazyk + setting_login_required: Autentifikace vyžadována + setting_self_registration: Povolena automatická registrace + setting_attachment_max_size: Maximální velikost přílohy + setting_issues_export_limit: Limit pro export úkolů + setting_mail_from: Odesílat emaily z adresy + setting_bcc_recipients: Příjemci jako skrytá kopie (bcc) + setting_plain_text_mail: pouze prostý text (ne HTML) + setting_host_name: Jméno serveru + setting_text_formatting: Formátování textu + setting_wiki_compression: Komprese historie Wiki + setting_feeds_limit: Limit obsahu příspěvků + setting_default_projects_public: Nové projekty nastavovat jako veřejné + setting_autofetch_changesets: Automaticky stahovat commity + setting_sys_api_enabled: Povolit WS pro správu repozitory + setting_commit_ref_keywords: Klíčová slova pro odkazy + setting_commit_fix_keywords: Klíčová slova pro uzavření + setting_autologin: Automatické přihlašování + setting_date_format: Formát data + setting_time_format: Formát času + setting_cross_project_issue_relations: Povolit vazby úkolů napříč projekty + setting_issue_list_default_columns: Výchozí sloupce zobrazené v seznamu úkolů + setting_emails_header: Záhlaví emailů + setting_emails_footer: Zápatí emailů + setting_protocol: Protokol + setting_per_page_options: Povolené počty řádků na stránce + setting_user_format: Formát zobrazení uživatele + setting_activity_days_default: Dny zobrazené v činnosti projektu + setting_display_subprojects_issues: Automaticky zobrazit úkoly podprojektu v hlavním projektu + setting_enabled_scm: Povolené SCM + setting_mail_handler_body_delimiters: Zkrátit e-maily po jednom z těchto řádků + setting_mail_handler_api_enabled: Povolit WS pro příchozí e-maily + setting_mail_handler_api_key: API klíč + setting_sequential_project_identifiers: Generovat sekvenční identifikátory projektů + setting_gravatar_enabled: Použít uživatelské ikony Gravatar + setting_gravatar_default: Výchozí Gravatar + setting_diff_max_lines_displayed: Maximální počet zobrazených řádků rozdílu + setting_file_max_size_displayed: Maximální velikost textových souborů zobrazených přímo na stránce + setting_repository_log_display_limit: Maximální počet revizí zobrazených v logu souboru + setting_openid: Umožnit přihlašování a registrace s OpenID + setting_password_min_length: Minimální délka hesla + setting_new_project_user_role_id: Role přiřazená uživateli bez práv administrátora, který projekt vytvořil + setting_default_projects_modules: Výchozí zapnutné moduly pro nový projekt + setting_issue_done_ratio: Spočítat koeficient dokončení úkolu s + setting_issue_done_ratio_issue_field: Použít pole úkolu + setting_issue_done_ratio_issue_status: Použít stav úkolu + setting_start_of_week: Začínat kalendáře + setting_rest_api_enabled: Zapnout službu REST + setting_cache_formatted_text: Ukládat formátovaný text do vyrovnávací paměti + setting_default_notification_option: Výchozí nastavení oznámení + setting_commit_logtime_enabled: Povolit zapisování času + setting_commit_logtime_activity_id: Aktivita pro zapsaný čas + setting_gantt_items_limit: Maximální počet položek zobrazený na ganttově diagramu + + permission_add_project: Vytvořit projekt + permission_add_subprojects: Vytvořit podprojekty + permission_edit_project: Úprava projektů + permission_select_project_modules: Výběr modulů projektu + permission_manage_members: Spravování členství + permission_manage_project_activities: Spravovat aktivity projektu + permission_manage_versions: Spravování verzí + permission_manage_categories: Spravování kategorií úkolů + permission_view_issues: Zobrazit úkoly + permission_add_issues: Přidávání úkolů + permission_edit_issues: Upravování úkolů + permission_manage_issue_relations: Spravování vztahů mezi úkoly + permission_add_issue_notes: Přidávání poznámek + permission_edit_issue_notes: Upravování poznámek + permission_edit_own_issue_notes: Upravování vlastních poznámek + permission_move_issues: Přesouvání úkolů + permission_delete_issues: Mazání úkolů + permission_manage_public_queries: Správa veřejných dotazů + permission_save_queries: Ukládání dotazů + permission_view_gantt: Zobrazení ganttova diagramu + permission_view_calendar: Prohlížení kalendáře + permission_view_issue_watchers: Zobrazení seznamu sledujících uživatelů + permission_add_issue_watchers: Přidání sledujících uživatelů + permission_delete_issue_watchers: Smazat sledující uživatele + permission_log_time: Zaznamenávání stráveného času + permission_view_time_entries: Zobrazení stráveného času + permission_edit_time_entries: Upravování záznamů o stráveném času + permission_edit_own_time_entries: Upravování vlastních zázamů o stráveném čase + permission_manage_news: Spravování novinek + permission_comment_news: Komentování novinek + permission_view_documents: Prohlížení dokumentů + permission_manage_files: Spravování souborů + permission_view_files: Prohlížení souborů + permission_manage_wiki: Spravování Wiki + permission_rename_wiki_pages: Přejmenovávání Wiki stránek + permission_delete_wiki_pages: Mazání stránek na Wiki + permission_view_wiki_pages: Prohlížení Wiki + permission_view_wiki_edits: Prohlížení historie Wiki + permission_edit_wiki_pages: Upravování stránek Wiki + permission_delete_wiki_pages_attachments: Mazání příloh + permission_protect_wiki_pages: Zabezpečení Wiki stránek + permission_manage_repository: Spravování repozitáře + permission_browse_repository: Procházení repozitáře + permission_view_changesets: Zobrazování sady změn + permission_commit_access: Commit přístup + permission_manage_boards: Správa diskusních fór + permission_view_messages: Prohlížení zpráv + permission_add_messages: Posílání zpráv + permission_edit_messages: Upravování zpráv + permission_edit_own_messages: Upravit vlastní zprávy + permission_delete_messages: Mazání zpráv + permission_delete_own_messages: Smazat vlastní zprávy + permission_export_wiki_pages: Exportovat Wiki stránky + permission_manage_subtasks: Spravovat dílčí úkoly + + project_module_issue_tracking: Sledování úkolů + project_module_time_tracking: Sledování času + project_module_news: Novinky + project_module_documents: Dokumenty + project_module_files: Soubory + project_module_wiki: Wiki + project_module_repository: Repozitář + project_module_boards: Diskuse + project_module_calendar: Kalendář + project_module_gantt: Gantt + + label_user: Uživatel + label_user_plural: Uživatelé + label_user_new: Nový uživatel + label_user_anonymous: Anonymní + label_project: Projekt + label_project_new: Nový projekt + label_project_plural: Projekty + label_x_projects: + zero: žádné projekty + one: 1 projekt + other: "%{count} projekty(ů)" + label_project_all: Všechny projekty + label_project_latest: Poslední projekty + label_issue: Úkol + label_issue_new: Nový úkol + label_issue_plural: Úkoly + label_issue_view_all: Všechny úkoly + label_issues_by: "Úkoly podle %{value}" + label_issue_added: Úkol přidán + label_issue_updated: Úkol aktualizován + label_document: Dokument + label_document_new: Nový dokument + label_document_plural: Dokumenty + label_document_added: Dokument přidán + label_role: Role + label_role_plural: Role + label_role_new: Nová role + label_role_and_permissions: Role a práva + label_member: Člen + label_member_new: Nový člen + label_member_plural: Členové + label_tracker: Fronta + label_tracker_plural: Fronty + label_tracker_new: Nová fronta + label_workflow: Průběh práce + label_issue_status: Stav úkolu + label_issue_status_plural: Stavy úkolů + label_issue_status_new: Nový stav + label_issue_category: Kategorie úkolu + label_issue_category_plural: Kategorie úkolů + label_issue_category_new: Nová kategorie + label_custom_field: Uživatelské pole + label_custom_field_plural: Uživatelská pole + label_custom_field_new: Nové uživatelské pole + label_enumerations: Seznamy + label_enumeration_new: Nová hodnota + label_information: Informace + label_information_plural: Informace + label_please_login: Přihlašte se, prosím + label_register: Registrovat + label_login_with_open_id_option: nebo se přihlašte s OpenID + label_password_lost: Zapomenuté heslo + label_home: Úvodní + label_my_page: Moje stránka + label_my_account: Můj účet + label_my_projects: Moje projekty + label_my_page_block: Bloky na mé stránce + label_administration: Administrace + label_login: Přihlášení + label_logout: Odhlášení + label_help: Nápověda + label_reported_issues: Nahlášené úkoly + label_assigned_to_me_issues: Mé úkoly + label_last_login: Poslední přihlášení + label_registered_on: Registrován + label_activity: Aktivita + label_overall_activity: Celková aktivita + label_user_activity: "Aktivita uživatele: %{value}" + label_new: Nový + label_logged_as: Přihlášen jako + label_environment: Prostředí + label_authentication: Autentifikace + label_auth_source: Mód autentifikace + label_auth_source_new: Nový mód autentifikace + label_auth_source_plural: Módy autentifikace + label_subproject_plural: Podprojekty + label_subproject_new: Nový podprojekt + label_and_its_subprojects: "%{value} a jeho podprojekty" + label_min_max_length: Min - Max délka + label_list: Seznam + label_date: Datum + label_integer: Celé číslo + label_float: Desetinné číslo + label_boolean: Ano/Ne + label_string: Text + label_text: Dlouhý text + label_attribute: Atribut + label_attribute_plural: Atributy + label_no_data: Žádné položky + label_change_status: Změnit stav + label_history: Historie + label_attachment: Soubor + label_attachment_new: Nový soubor + label_attachment_delete: Odstranit soubor + label_attachment_plural: Soubory + label_file_added: Soubor přidán + label_report: Přehled + label_report_plural: Přehledy + label_news: Novinky + label_news_new: Přidat novinku + label_news_plural: Novinky + label_news_latest: Poslední novinky + label_news_view_all: Zobrazit všechny novinky + label_news_added: Novinka přidána + label_settings: Nastavení + label_overview: Přehled + label_version: Verze + label_version_new: Nová verze + label_version_plural: Verze + label_close_versions: Zavřít dokončené verze + label_confirmation: Potvrzení + label_export_to: 'Také k dispozici:' + label_read: Načítá se... + label_public_projects: Veřejné projekty + label_open_issues: otevřený + label_open_issues_plural: otevřené + label_closed_issues: uzavřený + label_closed_issues_plural: uzavřené + label_x_open_issues_abbr_on_total: + zero: 0 otevřených / %{total} + one: 1 otevřený / %{total} + other: "%{count} otevřených / %{total}" + label_x_open_issues_abbr: + zero: 0 otevřených + one: 1 otevřený + other: "%{count} otevřených" + label_x_closed_issues_abbr: + zero: 0 uzavřených + one: 1 uzavřený + other: "%{count} uzavřených" + label_total: Celkem + label_permissions: Práva + label_current_status: Aktuální stav + label_new_statuses_allowed: Nové povolené stavy + label_all: vše + label_none: nic + label_nobody: nikdo + label_next: Další + label_previous: Předchozí + label_used_by: Použito + label_details: Detaily + label_add_note: Přidat poznámku + label_per_page: Na stránku + label_calendar: Kalendář + label_months_from: měsíců od + label_gantt: Ganttův diagram + label_internal: Interní + label_last_changes: "posledních %{count} změn" + label_change_view_all: Zobrazit všechny změny + label_personalize_page: Přizpůsobit tuto stránku + label_comment: Komentář + label_comment_plural: Komentáře + label_x_comments: + zero: žádné komentáře + one: 1 komentář + other: "%{count} komentářů" + label_comment_add: Přidat komentáře + label_comment_added: Komentář přidán + label_comment_delete: Odstranit komentář + label_query: Uživatelský dotaz + label_query_plural: Uživatelské dotazy + label_query_new: Nový dotaz + label_filter_add: Přidat filtr + label_filter_plural: Filtry + label_equals: je + label_not_equals: není + label_in_less_than: je měší než + label_in_more_than: je větší než + label_greater_or_equal: '>=' + label_less_or_equal: '<=' + label_in: v + label_today: dnes + label_all_time: vše + label_yesterday: včera + label_this_week: tento týden + label_last_week: minulý týden + label_last_n_days: "posledních %{count} dnů" + label_this_month: tento měsíc + label_last_month: minulý měsíc + label_this_year: tento rok + label_date_range: Časový rozsah + label_less_than_ago: před méně jak (dny) + label_more_than_ago: před více jak (dny) + label_ago: před (dny) + label_contains: obsahuje + label_not_contains: neobsahuje + label_day_plural: dny + label_repository: Repozitář + label_repository_plural: Repozitáře + label_browse: Procházet + label_branch: Větev + label_tag: Tag + label_revision: Revize + label_revision_plural: Revizí + label_revision_id: "Revize %{value}" + label_associated_revisions: Související verze + label_added: přidáno + label_modified: změněno + label_copied: zkopírováno + label_renamed: přejmenováno + label_deleted: odstraněno + label_latest_revision: Poslední revize + label_latest_revision_plural: Poslední revize + label_view_revisions: Zobrazit revize + label_view_all_revisions: Zobrazit všechny revize + label_max_size: Maximální velikost + label_sort_highest: Přesunout na začátek + label_sort_higher: Přesunout nahoru + label_sort_lower: Přesunout dolů + label_sort_lowest: Přesunout na konec + label_roadmap: Plán + label_roadmap_due_in: "Zbývá %{value}" + label_roadmap_overdue: "%{value} pozdě" + label_roadmap_no_issues: Pro tuto verzi nejsou žádné úkoly + label_search: Hledat + label_result_plural: Výsledky + label_all_words: Všechna slova + label_wiki: Wiki + label_wiki_edit: Wiki úprava + label_wiki_edit_plural: Wiki úpravy + label_wiki_page: Wiki stránka + label_wiki_page_plural: Wiki stránky + label_index_by_title: Index dle názvu + label_index_by_date: Index dle data + label_current_version: Aktuální verze + label_preview: Náhled + label_feed_plural: Příspěvky + label_changes_details: Detail všech změn + label_issue_tracking: Sledování úkolů + label_spent_time: Strávený čas + label_overall_spent_time: Celkem strávený čas + label_f_hour: "%{value} hodina" + label_f_hour_plural: "%{value} hodin" + label_time_tracking: Sledování času + label_change_plural: Změny + label_statistics: Statistiky + label_commits_per_month: Commitů za měsíc + label_commits_per_author: Commitů za autora + label_view_diff: Zobrazit rozdíly + label_diff_inline: uvnitř + label_diff_side_by_side: vedle sebe + label_options: Nastavení + label_copy_workflow_from: Kopírovat průběh práce z + label_permissions_report: Přehled práv + label_watched_issues: Sledované úkoly + label_related_issues: Související úkoly + label_applied_status: Použitý stav + label_loading: Nahrávám... + label_relation_new: Nová souvislost + label_relation_delete: Odstranit souvislost + label_relates_to: související s + label_duplicates: duplikuje + label_duplicated_by: duplikován + label_blocks: blokuje + label_blocked_by: blokován + label_precedes: předchází + label_follows: následuje + label_end_to_start: od konce do začátku + label_end_to_end: od konce do konce + label_start_to_start: od začátku do začátku + label_start_to_end: od začátku do konce + label_stay_logged_in: Zůstat přihlášený + label_disabled: zakázán + label_show_completed_versions: Zobrazit dokončené verze + label_me: já + label_board: Fórum + label_board_new: Nové fórum + label_board_plural: Fóra + label_board_locked: Zamčeno + label_board_sticky: Nálepka + label_topic_plural: Témata + label_message_plural: Zprávy + label_message_last: Poslední zpráva + label_message_new: Nová zpráva + label_message_posted: Zpráva přidána + label_reply_plural: Odpovědi + label_send_information: Zaslat informace o účtu uživateli + label_year: Rok + label_month: Měsíc + label_week: Týden + label_date_from: Od + label_date_to: Do + label_language_based: Podle výchozího jazyka + label_sort_by: "Seřadit podle %{value}" + label_send_test_email: Poslat testovací email + label_feeds_access_key: Přístupový klíč pro RSS + label_missing_feeds_access_key: Postrádá přístupový klíč pro RSS + label_feeds_access_key_created_on: "Přístupový klíč pro RSS byl vytvořen před %{value}" + label_module_plural: Moduly + label_added_time_by: "Přidáno uživatelem %{author} před %{age}" + label_updated_time_by: "Aktualizováno uživatelem %{author} před %{age}" + label_updated_time: "Aktualizováno před %{value}" + label_jump_to_a_project: Vyberte projekt... + label_file_plural: Soubory + label_changeset_plural: Sady změn + label_default_columns: Výchozí sloupce + label_no_change_option: (beze změny) + label_bulk_edit_selected_issues: Hromadná úprava vybraných úkolů + label_theme: Téma + label_default: Výchozí + label_search_titles_only: Vyhledávat pouze v názvech + label_user_mail_option_all: "Pro všechny události všech mých projektů" + label_user_mail_option_selected: "Pro všechny události vybraných projektů..." + label_user_mail_option_none: "Žádné události" + label_user_mail_option_only_my_events: "Jen pro věci, co sleduji nebo jsem v nich zapojen" + label_user_mail_option_only_assigned: "Jen pro věci, ke kterým sem přiřazen" + label_user_mail_option_only_owner: "Jen pro věci, které vlastním" + label_user_mail_no_self_notified: "Nezasílat informace o mnou vytvořených změnách" + label_registration_activation_by_email: aktivace účtu emailem + label_registration_manual_activation: manuální aktivace účtu + label_registration_automatic_activation: automatická aktivace účtu + label_display_per_page: "%{value} na stránku" + label_age: Věk + label_change_properties: Změnit vlastnosti + label_general: Obecné + label_more: Více + label_scm: SCM + label_plugins: Doplňky + label_ldap_authentication: Autentifikace LDAP + label_downloads_abbr: Staž. + label_optional_description: Volitelný popis + label_add_another_file: Přidat další soubor + label_preferences: Nastavení + label_chronological_order: V chronologickém pořadí + label_reverse_chronological_order: V obrácaném chronologickém pořadí + label_planning: Plánování + label_incoming_emails: Příchozí e-maily + label_generate_key: Generovat klíč + label_issue_watchers: Sledování + label_example: Příklad + label_display: Zobrazit + label_sort: Řazení + label_ascending: Vzestupně + label_descending: Sestupně + label_date_from_to: Od %{start} do %{end} + label_wiki_content_added: Wiki stránka přidána + label_wiki_content_updated: Wiki stránka aktualizována + label_group: Skupina + label_group_plural: Skupiny + label_group_new: Nová skupina + label_time_entry_plural: Strávený čas + label_version_sharing_none: Nesdíleno + label_version_sharing_descendants: S podprojekty + label_version_sharing_hierarchy: S hierarchií projektu + label_version_sharing_tree: Se stromem projektu + label_version_sharing_system: Se všemi projekty + label_update_issue_done_ratios: Aktualizovat koeficienty dokončení úkolů + label_copy_source: Zdroj + label_copy_target: Cíl + label_copy_same_as_target: Stejný jako cíl + label_display_used_statuses_only: Zobrazit pouze stavy které jsou použité touto frontou + label_api_access_key: API přístupový klíč + label_missing_api_access_key: Chybějící přístupový klíč API + label_api_access_key_created_on: API přístupový klíč vytvořen %{value} + label_profile: Profil + label_subtask_plural: Dílčí úkoly + label_project_copy_notifications: Odeslat email oznámení v průběhu kopie projektu + label_principal_search: "Hledat uživatele nebo skupinu:" + label_user_search: "Hledat uživatele:" + + button_login: Přihlásit + button_submit: Potvrdit + button_save: Uložit + button_check_all: Zašrtnout vše + button_uncheck_all: Odšrtnout vše + button_delete: Odstranit + button_create: Vytvořit + button_create_and_continue: Vytvořit a pokračovat + button_test: Testovat + button_edit: Upravit + button_edit_associated_wikipage: "Upravit přiřazenou Wiki stránku: %{page_title}" + button_add: Přidat + button_change: Změnit + button_apply: Použít + button_clear: Smazat + button_lock: Zamknout + button_unlock: Odemknout + button_download: Stáhnout + button_list: Vypsat + button_view: Zobrazit + button_move: Přesunout + button_move_and_follow: Přesunout a následovat + button_back: Zpět + button_cancel: Storno + button_activate: Aktivovat + button_sort: Seřadit + button_log_time: Přidat čas + button_rollback: Zpět k této verzi + button_watch: Sledovat + button_unwatch: Nesledovat + button_reply: Odpovědět + button_archive: Archivovat + button_unarchive: Dearchivovat + button_reset: Resetovat + button_rename: Přejmenovat + button_change_password: Změnit heslo + button_copy: Kopírovat + button_copy_and_follow: Kopírovat a následovat + button_annotate: Komentovat + button_update: Aktualizovat + button_configure: Konfigurovat + button_quote: Citovat + button_duplicate: Duplikovat + button_show: Zobrazit + + status_active: aktivní + status_registered: registrovaný + status_locked: zamčený + + version_status_open: otevřený + version_status_locked: zamčený + version_status_closed: zavřený + + field_active: Aktivní + + text_select_mail_notifications: Vyberte akci, při které bude zasláno upozornění emailem. + text_regexp_info: např. ^[A-Z0-9]+$ + text_min_max_length_info: 0 znamená bez limitu + text_project_destroy_confirmation: Jste si jisti, že chcete odstranit tento projekt a všechna související data? + text_subprojects_destroy_warning: "Jeho podprojek(y): %{value} budou také smazány." + text_workflow_edit: Vyberte roli a frontu k editaci průběhu práce + text_are_you_sure: Jste si jisti? + text_journal_changed: "%{label} změněn z %{old} na %{new}" + text_journal_set_to: "%{label} nastaven na %{value}" + text_journal_deleted: "%{label} smazán (%{old})" + text_journal_added: "%{label} %{value} přidán" + text_tip_issue_begin_day: úkol začíná v tento den + text_tip_issue_end_day: úkol končí v tento den + text_tip_issue_begin_end_day: úkol začíná a končí v tento den + text_caracters_maximum: "%{count} znaků maximálně." + text_caracters_minimum: "Musí být alespoň %{count} znaků dlouhé." + text_length_between: "Délka mezi %{min} a %{max} znaky." + text_tracker_no_workflow: Pro tuto frontu není definován žádný průběh práce + text_unallowed_characters: Nepovolené znaky + text_comma_separated: Povoleno více hodnot (oddělěné čárkou). + text_line_separated: Více hodnot povoleno (jeden řádek pro každou hodnotu). + text_issues_ref_in_commit_messages: Odkazování a opravování úkolů v poznámkách commitů + text_issue_added: "Úkol %{id} byl vytvořen uživatelem %{author}." + text_issue_updated: "Úkol %{id} byl aktualizován uživatelem %{author}." + text_wiki_destroy_confirmation: Opravdu si přejete odstranit tuto Wiki a celý její obsah? + text_issue_category_destroy_question: "Některé úkoly (%{count}) jsou přiřazeny k této kategorii. Co s nimi chtete udělat?" + text_issue_category_destroy_assignments: Zrušit přiřazení ke kategorii + text_issue_category_reassign_to: Přiřadit úkoly do této kategorie + text_user_mail_option: "U projektů, které nebyly vybrány, budete dostávat oznámení pouze o vašich či o sledovaných položkách (např. o položkách jejichž jste autor nebo ke kterým jste přiřazen(a))." + text_no_configuration_data: "Role, fronty, stavy úkolů ani průběh práce nebyly zatím nakonfigurovány.\nVelice doporučujeme nahrát výchozí konfiguraci. Po té si můžete vše upravit" + text_load_default_configuration: Nahrát výchozí konfiguraci + text_status_changed_by_changeset: "Použito v sadě změn %{value}." + text_time_logged_by_changeset: Aplikováno v sadě změn %{value}. + text_issues_destroy_confirmation: 'Opravdu si přejete odstranit všechny zvolené úkoly?' + text_select_project_modules: 'Aktivní moduly v tomto projektu:' + text_default_administrator_account_changed: Výchozí nastavení administrátorského účtu změněno + text_file_repository_writable: Povolen zápis do adresáře ukládání souborů + text_plugin_assets_writable: Možnost zápisu do adresáře plugin assets + text_rmagick_available: RMagick k dispozici (volitelné) + text_destroy_time_entries_question: "U úkolů, které chcete odstranit, je evidováno %{hours} práce. Co chete udělat?" + text_destroy_time_entries: Odstranit zaznamenané hodiny. + text_assign_time_entries_to_project: Přiřadit zaznamenané hodiny projektu + text_reassign_time_entries: 'Přeřadit zaznamenané hodiny k tomuto úkolu:' + text_user_wrote: "%{value} napsal:" + text_enumeration_destroy_question: "Několik (%{count}) objektů je přiřazeno k této hodnotě." + text_enumeration_category_reassign_to: 'Přeřadit je do této:' + text_email_delivery_not_configured: "Doručování e-mailů není nastaveno a odesílání notifikací je zakázáno.\nNastavte Váš SMTP server v souboru config/configuration.yml a restartujte aplikaci." + text_repository_usernames_mapping: "Vybrat nebo upravit mapování mezi Redmine uživateli a uživatelskými jmény nalezenými v logu repozitáře.\nUživatelé se shodným Redmine uživatelským jménem a uživatelským jménem v repozitáři jsou mapováni automaticky." + text_diff_truncated: '... Rozdílový soubor je zkrácen, protože jeho délka přesahuje max. limit.' + text_custom_field_possible_values_info: 'Každá hodnota na novém řádku' + text_wiki_page_destroy_question: Tato stránka má %{descendants} podstránek a potomků. Co chcete udělat? + text_wiki_page_nullify_children: Ponechat podstránky jako kořenové stránky + text_wiki_page_destroy_children: Smazat podstránky a všechny jejich potomky + text_wiki_page_reassign_children: Přiřadit podstránky k tomuto rodiči + text_own_membership_delete_confirmation: "Chystáte se odebrat si některá nebo všechna svá oprávnění, potom již nemusíte být schopni upravit tento projekt.\nOpravdu chcete pokračovat?" + text_zoom_in: Přiblížit + text_zoom_out: Oddálit + + default_role_manager: Manažer + default_role_developer: Vývojář + default_role_reporter: Reportér + default_tracker_bug: Chyba + default_tracker_feature: Požadavek + default_tracker_support: Podpora + default_issue_status_new: Nový + default_issue_status_in_progress: Ve vývoji + default_issue_status_resolved: Vyřešený + default_issue_status_feedback: Čeká se + default_issue_status_closed: Uzavřený + default_issue_status_rejected: Odmítnutý + default_doc_category_user: Uživatelská dokumentace + default_doc_category_tech: Technická dokumentace + default_priority_low: Nízká + default_priority_normal: Normální + default_priority_high: Vysoká + default_priority_urgent: Urgentní + default_priority_immediate: Okamžitá + default_activity_design: Návhr + default_activity_development: Vývoj + + enumeration_issue_priorities: Priority úkolů + enumeration_doc_categories: Kategorie dokumentů + enumeration_activities: Aktivity (sledování času) + enumeration_system_activity: Systémová aktivita + + field_warn_on_leaving_unsaved: Varuj mě před opuštěním stránky s neuloženým textem + text_warn_on_leaving_unsaved: Aktuální stránka obsahuje neuložený text, který bude ztracen, když opustíte stránku. + label_my_queries: Moje vlastní dotazy + text_journal_changed_no_detail: "%{label} aktualizován" + label_news_comment_added: K novince byl přidán komentář + button_expand_all: Rozbal vše + button_collapse_all: Sbal vše + label_additional_workflow_transitions_for_assignee: Další změna stavu povolena, jestliže je uživatel přiřazen + label_additional_workflow_transitions_for_author: Další změna stavu povolena, jestliže je uživatel autorem + label_bulk_edit_selected_time_entries: Hromadná změna záznamů času + text_time_entries_destroy_confirmation: Jste si jistí, že chcete smazat vybraný záznam(y) času? + label_role_anonymous: Anonymní + label_role_non_member: Není členem + label_issue_note_added: Přidána poznámka + label_issue_status_updated: Aktualizován stav + label_issue_priority_updated: Aktualizována priorita + label_issues_visibility_own: Úkol vytvořen nebo přiřazen uživatel(i/em) + field_issues_visibility: Viditelnost úkolů + label_issues_visibility_all: Všechny úkoly + permission_set_own_issues_private: Nastavit vlastní úkoly jako veřejné nebo soukromé + field_is_private: Soukromý + permission_set_issues_private: Nastavit úkoly jako veřejné nebo soukromé + label_issues_visibility_public: Všechny úkoly, které nejsou soukromé + text_issues_destroy_descendants_confirmation: "%{count} dílčí(ch) úkol(ů) bude rovněž smazán(o)." + field_commit_logs_encoding: Kódování zpráv při commitu + field_scm_path_encoding: Kódování cesty SCM + text_scm_path_encoding_note: "Výchozí: UTF-8" + field_path_to_repository: Cesta k repositáři + field_root_directory: Kořenový adresář + field_cvs_module: Modul + field_cvsroot: CVSROOT + text_mercurial_repository_note: Lokální repositář (např. /hgrepo, c:\hgrepo) + text_scm_command: Příkaz + text_scm_command_version: Verze + label_git_report_last_commit: Reportovat poslední commit pro soubory a adresáře + text_scm_config: Můžete si nastavit vaše SCM příkazy v config/configuration.yml. Restartujte, prosím, aplikaci po jejich úpravě. + text_scm_command_not_available: SCM příkaz není k dispozici. Zkontrolujte, prosím, nastavení v panelu Administrace. + notice_issue_successful_create: Úkol %{id} vytvořen. + label_between: mezi + setting_issue_group_assignment: Povolit přiřazení úkolu skupině + label_diff: rozdíl + text_git_repository_note: Repositář je "bare and local" (např. /gitrepo, c:\gitrepo) + description_query_sort_criteria_direction: Směr třídění + description_project_scope: Rozsah vyhledávání + description_filter: Filtr + description_user_mail_notification: Nastavení emailových notifikací + description_date_from: Zadejte počáteční datum + description_message_content: Obsah zprávy + description_available_columns: Dostupné sloupce + description_date_range_interval: Zvolte rozsah výběrem počátečního a koncového data + description_issue_category_reassign: Zvolte kategorii úkolu + description_search: Vyhledávací pole + description_notes: Poznámky + description_date_range_list: Zvolte rozsah ze seznamu + description_choose_project: Projekty + description_date_to: Zadejte datum + description_query_sort_criteria_attribute: Třídící atribut + description_wiki_subpages_reassign: Zvolte novou rodičovskou stránku + description_selected_columns: Vybraný sloupec + label_parent_revision: Rodič + label_child_revision: Potomek + error_scm_annotate_big_text_file: Vstup nemůže být komentován, protože překračuje povolenou velikost textového souboru + setting_default_issue_start_date_to_creation_date: Použij aktuální datum jako počáteční datum pro nové úkoly + button_edit_section: Uprav tuto část + setting_repositories_encodings: Kódování příloh a repositářů + description_all_columns: Všechny sloupce + button_export: Export + label_export_options: "nastavení exportu %{export_format}" + error_attachment_too_big: Soubor nemůže být nahrán, protože jeho velikost je větší než maximální (%{max_size}) + notice_failed_to_save_time_entries: "Chyba při ukládání %{count} časov(ých/ého) záznam(ů) z %{total} vybraného: %{ids}." + label_x_issues: + zero: 0 Úkol + one: 1 Úkol + other: "%{count} Úkoly" + label_repository_new: Nový repositář + field_repository_is_default: Hlavní repositář + label_copy_attachments: Kopírovat přílohy + label_item_position: "%{position}/%{count}" + label_completed_versions: Dokončené verze + text_project_identifier_info: Jsou povolena pouze malá písmena (a-z), číslice, pomlčky a podtržítka.
    Po uložení již nelze identifikátor měnit. + field_multiple: Více hodnot + setting_commit_cross_project_ref: Povolit reference a opravy úkolů ze všech ostatních projektů + text_issue_conflict_resolution_add_notes: Přidat moje poznámky a zahodit ostatní změny + text_issue_conflict_resolution_overwrite: Přesto přijmout moje úpravy (předchozí poznámky budou zachovány, ale některé změny mohou být přepsány) + notice_issue_update_conflict: Během vašich úprav byl úkol aktualizován jiným uživatelem. + text_issue_conflict_resolution_cancel: Zahoď všechny moje změny a znovu zobraz %{link} + permission_manage_related_issues: Spravuj související úkoly + field_auth_source_ldap_filter: LDAP filtr + label_search_for_watchers: Hledej sledující pro přidání + notice_account_deleted: Váš účet byl trvale smazán. + setting_unsubscribe: Povolit uživatelům smazání jejich vlastního účtu + button_delete_my_account: Smazat můj účet + text_account_destroy_confirmation: |- + Skutečně chcete pokračovat? + Váš účet bude nenávratně smazán. + error_session_expired: Vaše sezení vypršelo. Znovu se přihlaste, prosím. + text_session_expiration_settings: "Varování: změnou tohoto nastavení mohou vypršet aktuální sezení včetně toho vašeho." + setting_session_lifetime: Maximální čas sezení + setting_session_timeout: Vypršení sezení bez aktivity + label_session_expiration: Vypršení sezení + permission_close_project: Zavřít / Otevřít projekt + label_show_closed_projects: Zobrazit zavřené projekty + button_close: Zavřít + button_reopen: Znovu otevřít + project_status_active: aktivní + project_status_closed: zavřený + project_status_archived: archivovaný + text_project_closed: Tento projekt je uzevřený a je pouze pro čtení. + notice_user_successful_create: Uživatel %{id} vytvořen. + field_core_fields: Standardní pole + field_timeout: Vypršení (v sekundách) + setting_thumbnails_enabled: Zobrazit náhled přílohy + setting_thumbnails_size: Velikost náhledu (v pixelech) + label_status_transitions: Změna stavu + label_fields_permissions: Práva k polím + label_readonly: Pouze pro čtení + label_required: Vyžadováno + text_repository_identifier_info: Jou povoleny pouze malá písmena (a-z), číslice, pomlčky a podtržítka.
    Po uložení již nelze identifikátor změnit. + field_board_parent: Rodičovské fórum + label_attribute_of_project: Projektové %{name} + label_attribute_of_author: Autorovo %{name} + label_attribute_of_assigned_to: "%{name} přiřazené(ho)" + label_attribute_of_fixed_version: Cílová verze %{name} + label_copy_subtasks: Kopírovat dílčí úkoly + label_copied_to: zkopírováno do + label_copied_from: zkopírováno z + label_any_issues_in_project: jakékoli úkoly v projektu + label_any_issues_not_in_project: jakékoli úkoly mimo projekt + field_private_notes: Soukromé poznámky + permission_view_private_notes: Zobrazit soukromé poznámky + permission_set_notes_private: Nastavit poznámky jako soukromé + label_no_issues_in_project: žádné úkoly v projektu + label_any: vše + label_last_n_weeks: poslední %{count} týdny + setting_cross_project_subtasks: Povolit dílčí úkoly napříč projekty + label_cross_project_descendants: S podprojekty + label_cross_project_tree: Se stromem projektu + label_cross_project_hierarchy: S hierarchií projektu + label_cross_project_system: Se všemi projekty + button_hide: Skrýt + setting_non_working_week_days: Dny pracovního volna/klidu + label_in_the_next_days: v přístích + label_in_the_past_days: v minulých + label_attribute_of_user: "%{name} uživatel(e/ky)" + text_turning_multiple_off: Jestliže zakážete více hodnot, + hodnoty budou smazány za účelem rezervace pouze jediné hodnoty na položku. + label_attribute_of_issue: "%{name} úkolu" + permission_add_documents: Přidat dokument + permission_edit_documents: Upravit dokumenty + permission_delete_documents: Smazet dokumenty + label_gantt_progress_line: Vývojová čára + setting_jsonp_enabled: Povolit podporu JSONP + field_inherit_members: Zdědit členy + field_closed_on: Uzavřeno + setting_default_projects_tracker_ids: Výchozí fronta pro nové projekty + label_total_time: Celkem diff --git a/config/locales/da.yml b/config/locales/da.yml new file mode 100644 index 00000000..48a94fec --- /dev/null +++ b/config/locales/da.yml @@ -0,0 +1,1106 @@ +# Danish translation file for standard Ruby on Rails internationalization +# by Lars Hoeg (http://www.lenio.dk/) +# updated and upgraded to 0.9 by Morten Krogh Andersen (http://www.krogh.net) + +da: + direction: ltr + date: + formats: + default: "%d.%m.%Y" + short: "%e. %b %Y" + long: "%e. %B %Y" + + day_names: [søndag, mandag, tirsdag, onsdag, torsdag, fredag, lørdag] + abbr_day_names: [sø, ma, ti, 'on', to, fr, lø] + month_names: [~, januar, februar, marts, april, maj, juni, juli, august, september, oktober, november, december] + abbr_month_names: [~, jan, feb, mar, apr, maj, jun, jul, aug, sep, okt, nov, dec] + order: + - :day + - :month + - :year + + time: + formats: + default: "%e. %B %Y, %H:%M" + time: "%H:%M" + short: "%e. %b %Y, %H:%M" + long: "%A, %e. %B %Y, %H:%M" + am: "" + pm: "" + + support: + array: + sentence_connector: "og" + skip_last_comma: true + + datetime: + distance_in_words: + half_a_minute: "et halvt minut" + less_than_x_seconds: + one: "mindre end et sekund" + other: "mindre end %{count} sekunder" + x_seconds: + one: "et sekund" + other: "%{count} sekunder" + less_than_x_minutes: + one: "mindre end et minut" + other: "mindre end %{count} minutter" + x_minutes: + one: "et minut" + other: "%{count} minutter" + about_x_hours: + one: "cirka en time" + other: "cirka %{count} timer" + x_hours: + one: "1 hour" + other: "%{count} hours" + x_days: + one: "en dag" + other: "%{count} dage" + about_x_months: + one: "cirka en måned" + other: "cirka %{count} måneder" + x_months: + one: "en måned" + other: "%{count} måneder" + about_x_years: + one: "cirka et år" + other: "cirka %{count} år" + over_x_years: + one: "mere end et år" + other: "mere end %{count} år" + almost_x_years: + one: "næsten 1 år" + other: "næsten %{count} år" + + number: + format: + separator: "," + delimiter: "." + precision: 3 + currency: + format: + format: "%u %n" + unit: "DKK" + separator: "," + delimiter: "." + precision: 2 + precision: + format: + # separator: + delimiter: "" + # precision: + human: + format: + # separator: + delimiter: "" + precision: 3 + storage_units: + format: "%n %u" + units: + byte: + one: "Byte" + other: "Bytes" + kb: "KB" + mb: "MB" + gb: "GB" + tb: "TB" + percentage: + format: + # separator: + delimiter: "" + # precision: + + activerecord: + errors: + template: + header: + one: "1 error prohibited this %{model} from being saved" + other: "%{count} errors prohibited this %{model} from being saved" + messages: + inclusion: "er ikke i listen" + exclusion: "er reserveret" + invalid: "er ikke gyldig" + confirmation: "stemmer ikke overens" + accepted: "skal accepteres" + empty: "må ikke udelades" + blank: "skal udfyldes" + too_long: "er for lang (højst %{count} tegn)" + too_short: "er for kort (mindst %{count} tegn)" + wrong_length: "har forkert længde (skulle være %{count} tegn)" + taken: "er allerede anvendt" + not_a_number: "er ikke et tal" + greater_than: "skal være større end %{count}" + greater_than_or_equal_to: "skal være større end eller lig med %{count}" + equal_to: "skal være lig med %{count}" + less_than: "skal være mindre end %{count}" + less_than_or_equal_to: "skal være mindre end eller lig med %{count}" + odd: "skal være ulige" + even: "skal være lige" + greater_than_start_date: "skal være senere end startdatoen" + not_same_project: "hører ikke til samme projekt" + circular_dependency: "Denne relation vil skabe et afhængighedsforhold" + cant_link_an_issue_with_a_descendant: "En sag kan ikke relateres til en af dens underopgaver" + + template: + header: + one: "En fejl forhindrede %{model} i at blive gemt" + other: "%{count} fejl forhindrede denne %{model} i at blive gemt" + body: "Der var problemer med følgende felter:" + + actionview_instancetag_blank_option: Vælg venligst + + general_text_No: 'Nej' + general_text_Yes: 'Ja' + general_text_no: 'nej' + general_text_yes: 'ja' + general_lang_name: 'Danish (Dansk)' + general_csv_separator: ',' + general_csv_encoding: ISO-8859-1 + general_pdf_encoding: UTF-8 + general_first_day_of_week: '1' + + notice_account_updated: Kontoen er opdateret. + notice_account_invalid_creditentials: Ugyldig bruger og/eller kodeord + notice_account_password_updated: Kodeordet er opdateret. + notice_account_wrong_password: Forkert kodeord + notice_account_register_done: Kontoen er oprettet. For at aktivere kontoen skal du klikke på linket i den tilsendte email. + notice_account_unknown_email: Ukendt bruger. + notice_can_t_change_password: Denne konto benytter en ekstern sikkerhedsgodkendelse. Det er ikke muligt at skifte kodeord. + notice_account_lost_email_sent: En email med instruktioner til at vælge et nyt kodeord er afsendt til dig. + notice_account_activated: Din konto er aktiveret. Du kan nu logge ind. + notice_successful_create: Succesfuld oprettelse. + notice_successful_update: Succesfuld opdatering. + notice_successful_delete: Succesfuld sletning. + notice_successful_connection: Succesfuld forbindelse. + notice_file_not_found: Siden du forsøger at tilgå eksisterer ikke eller er blevet fjernet. + notice_locking_conflict: Data er opdateret af en anden bruger. + notice_not_authorized: Du har ikke adgang til denne side. + notice_email_sent: "En email er sendt til %{value}" + notice_email_error: "En fejl opstod under afsendelse af email (%{value})" + notice_feeds_access_key_reseted: Din adgangsnøgle til RSS er nulstillet. + notice_failed_to_save_issues: "Det mislykkedes at gemme %{count} sage(r) på %{total} valgt: %{ids}." + notice_no_issue_selected: "Ingen sag er valgt! Vælg venligst hvilke emner du vil rette." + notice_account_pending: "Din konto er oprettet, og afventer administrators godkendelse." + notice_default_data_loaded: Standardopsætningen er indlæst. + + error_can_t_load_default_data: "Standardopsætning kunne ikke indlæses: %{value}" + error_scm_not_found: "Adgang nægtet og/eller revision blev ikke fundet i det valgte repository." + error_scm_command_failed: "En fejl opstod under forbindelsen til det valgte repository: %{value}" + + mail_subject_lost_password: "Dit %{value} kodeord" + mail_body_lost_password: 'Klik på dette link for at ændre dit kodeord:' + mail_subject_register: "%{value} kontoaktivering" + mail_body_register: 'Klik på dette link for at aktivere din konto:' + mail_body_account_information_external: "Du kan bruge din %{value} konto til at logge ind." + mail_body_account_information: Din kontoinformation + mail_subject_account_activation_request: "%{value} kontoaktivering" + mail_body_account_activation_request: "En ny bruger (%{value}) er registreret. Godkend venligst kontoen:" + + + field_name: Navn + field_description: Beskrivelse + field_summary: Sammenfatning + field_is_required: Skal udfyldes + field_firstname: Fornavn + field_lastname: Efternavn + field_mail: Email + field_filename: Fil + field_filesize: Størrelse + field_downloads: Downloads + field_author: Forfatter + field_created_on: Oprettet + field_updated_on: Opdateret + field_field_format: Format + field_is_for_all: For alle projekter + field_possible_values: Mulige værdier + field_regexp: Regulære udtryk + field_min_length: Mindste længde + field_max_length: Største længde + field_value: Værdi + field_category: Kategori + field_title: Titel + field_project: Projekt + field_issue: Sag + field_status: Status + field_notes: Noter + field_is_closed: Sagen er lukket + field_is_default: Standardværdi + field_tracker: Type + field_subject: Emne + field_due_date: Deadline + field_assigned_to: Tildelt til + field_priority: Prioritet + field_fixed_version: Udgave + field_user: Bruger + field_role: Rolle + field_homepage: Hjemmeside + field_is_public: Offentlig + field_parent: Underprojekt af + field_is_in_roadmap: Sager vist i roadmap + field_login: Login + field_mail_notification: Email-påmindelser + field_admin: Administrator + field_last_login_on: Sidste forbindelse + field_language: Sprog + field_effective_date: Dato + field_password: Kodeord + field_new_password: Nyt kodeord + field_password_confirmation: Bekræft + field_version: Version + field_type: Type + field_host: Vært + field_port: Port + field_account: Kode + field_base_dn: Base DN + field_attr_login: Login attribut + field_attr_firstname: Fornavn attribut + field_attr_lastname: Efternavn attribut + field_attr_mail: Email attribut + field_onthefly: løbende brugeroprettelse + field_start_date: Start dato + field_done_ratio: "% færdig" + field_auth_source: Sikkerhedsmetode + field_hide_mail: Skjul min email + field_comments: Kommentar + field_url: URL + field_start_page: Startside + field_subproject: Underprojekt + field_hours: Timer + field_activity: Aktivitet + field_spent_on: Dato + field_identifier: Identifikator + field_is_filter: Brugt som et filter + field_issue_to: Beslægtede sag + field_delay: Udsættelse + field_assignable: Sager kan tildeles denne rolle + field_redirect_existing_links: Videresend eksisterende links + field_estimated_hours: Anslået tid + field_column_names: Kolonner + field_time_zone: Tidszone + field_searchable: Søgbar + field_default_value: Standardværdi + + setting_app_title: Applikationstitel + setting_app_subtitle: Applikationsundertekst + setting_welcome_text: Velkomsttekst + setting_default_language: Standardsporg + setting_login_required: Sikkerhed påkrævet + setting_self_registration: Brugeroprettelse + setting_attachment_max_size: Vedhæftede filers max størrelse + setting_issues_export_limit: Sagseksporteringsbegrænsning + setting_mail_from: Afsender-email + setting_bcc_recipients: Skjult modtager (bcc) + setting_host_name: Værtsnavn + setting_text_formatting: Tekstformatering + setting_wiki_compression: Komprimering af wiki-historik + setting_feeds_limit: Feed indholdsbegrænsning + setting_autofetch_changesets: Hent automatisk commits + setting_sys_api_enabled: Aktiver webservice for automatisk administration af repository + setting_commit_ref_keywords: Referencenøgleord + setting_commit_fix_keywords: Afslutningsnøgleord + setting_autologin: Automatisk login + setting_date_format: Datoformat + setting_time_format: Tidsformat + setting_cross_project_issue_relations: Tillad sagsrelationer på tværs af projekter + setting_issue_list_default_columns: Standardkolonner på sagslisten + setting_emails_footer: Email-fodnote + setting_protocol: Protokol + setting_user_format: Brugervisningsformat + + project_module_issue_tracking: Sagssøgning + project_module_time_tracking: Tidsstyring + project_module_news: Nyheder + project_module_documents: Dokumenter + project_module_files: Filer + project_module_wiki: Wiki + project_module_repository: Repository + project_module_boards: Fora + + label_user: Bruger + label_user_plural: Brugere + label_user_new: Ny bruger + label_project: Projekt + label_project_new: Nyt projekt + label_project_plural: Projekter + label_x_projects: + zero: Ingen projekter + one: 1 projekt + other: "%{count} projekter" + label_project_all: Alle projekter + label_project_latest: Seneste projekter + label_issue: Sag + label_issue_new: Opret sag + label_issue_plural: Sager + label_issue_view_all: Vis alle sager + label_issues_by: "Sager fra %{value}" + label_issue_added: Sagen er oprettet + label_issue_updated: Sagen er opdateret + label_document: Dokument + label_document_new: Nyt dokument + label_document_plural: Dokumenter + label_document_added: Dokument tilføjet + label_role: Rolle + label_role_plural: Roller + label_role_new: Ny rolle + label_role_and_permissions: Roller og rettigheder + label_member: Medlem + label_member_new: Nyt medlem + label_member_plural: Medlemmer + label_tracker: Type + label_tracker_plural: Typer + label_tracker_new: Ny type + label_workflow: Arbejdsgang + label_issue_status: Sagsstatus + label_issue_status_plural: Sagsstatusser + label_issue_status_new: Ny status + label_issue_category: Sagskategori + label_issue_category_plural: Sagskategorier + label_issue_category_new: Ny kategori + label_custom_field: Brugerdefineret felt + label_custom_field_plural: Brugerdefinerede felter + label_custom_field_new: Nyt brugerdefineret felt + label_enumerations: Værdier + label_enumeration_new: Ny værdi + label_information: Information + label_information_plural: Information + label_please_login: Login + label_register: Registrér + label_password_lost: Glemt kodeord + label_home: Forside + label_my_page: Min side + label_my_account: Min konto + label_my_projects: Mine projekter + label_administration: Administration + label_login: Log ind + label_logout: Log ud + label_help: Hjælp + label_reported_issues: Rapporterede sager + label_assigned_to_me_issues: Sager tildelt til mig + label_last_login: Sidste logintidspunkt + label_registered_on: Registreret den + label_activity: Aktivitet + label_new: Ny + label_logged_as: Registreret som + label_environment: Miljø + label_authentication: Sikkerhed + label_auth_source: Sikkerhedsmetode + label_auth_source_new: Ny sikkerhedsmetode + label_auth_source_plural: Sikkerhedsmetoder + label_subproject_plural: Underprojekter + label_min_max_length: Min - Max længde + label_list: Liste + label_date: Dato + label_integer: Heltal + label_float: Kommatal + label_boolean: Sand/falsk + label_string: Tekst + label_text: Lang tekst + label_attribute: Attribut + label_attribute_plural: Attributter + label_no_data: Ingen data at vise + label_change_status: Ændringsstatus + label_history: Historik + label_attachment: Fil + label_attachment_new: Ny fil + label_attachment_delete: Slet fil + label_attachment_plural: Filer + label_file_added: Fil tilføjet + label_report: Rapport + label_report_plural: Rapporter + label_news: Nyheder + label_news_new: Tilføj nyheder + label_news_plural: Nyheder + label_news_latest: Seneste nyheder + label_news_view_all: Vis alle nyheder + label_news_added: Nyhed tilføjet + label_settings: Indstillinger + label_overview: Oversigt + label_version: Udgave + label_version_new: Ny udgave + label_version_plural: Udgaver + label_confirmation: Bekræftelser + label_export_to: Eksporter til + label_read: Læs... + label_public_projects: Offentlige projekter + label_open_issues: åben + label_open_issues_plural: åbne + label_closed_issues: lukket + label_closed_issues_plural: lukkede + label_x_open_issues_abbr_on_total: + zero: 0 åbne / %{total} + one: 1 åben / %{total} + other: "%{count} åbne / %{total}" + label_x_open_issues_abbr: + zero: 0 åbne + one: 1 åben + other: "%{count} åbne" + label_x_closed_issues_abbr: + zero: 0 lukkede + one: 1 lukket + other: "%{count} lukkede" + label_total: Total + label_permissions: Rettigheder + label_current_status: Nuværende status + label_new_statuses_allowed: Ny status tilladt + label_all: alle + label_none: intet + label_nobody: ingen + label_next: Næste + label_previous: Forrige + label_used_by: Brugt af + label_details: Detaljer + label_add_note: Tilføj note + label_per_page: Pr. side + label_calendar: Kalender + label_months_from: måneder frem + label_gantt: Gantt + label_internal: Intern + label_last_changes: "sidste %{count} ændringer" + label_change_view_all: Vis alle ændringer + label_personalize_page: Tilret denne side + label_comment: Kommentar + label_comment_plural: Kommentarer + label_x_comments: + zero: ingen kommentarer + one: 1 kommentar + other: "%{count} kommentarer" + label_comment_add: Tilføj en kommentar + label_comment_added: Kommentaren er tilføjet + label_comment_delete: Slet kommentar + label_query: Brugerdefineret forespørgsel + label_query_plural: Brugerdefinerede forespørgsler + label_query_new: Ny forespørgsel + label_filter_add: Tilføj filter + label_filter_plural: Filtre + label_equals: er + label_not_equals: er ikke + label_in_less_than: er mindre end + label_in_more_than: er større end + label_in: indeholdt i + label_today: i dag + label_all_time: altid + label_yesterday: i går + label_this_week: denne uge + label_last_week: sidste uge + label_last_n_days: "sidste %{count} dage" + label_this_month: denne måned + label_last_month: sidste måned + label_this_year: dette år + label_date_range: Dato interval + label_less_than_ago: mindre end dage siden + label_more_than_ago: mere end dage siden + label_ago: dage siden + label_contains: indeholder + label_not_contains: ikke indeholder + label_day_plural: dage + label_repository: Repository + label_repository_plural: Repositories + label_browse: Gennemse + label_revision: Revision + label_revision_plural: Revisioner + label_associated_revisions: Tilknyttede revisioner + label_added: tilføjet + label_modified: ændret + label_deleted: slettet + label_latest_revision: Seneste revision + label_latest_revision_plural: Seneste revisioner + label_view_revisions: Se revisioner + label_max_size: Maksimal størrelse + label_sort_highest: Flyt til toppen + label_sort_higher: Flyt op + label_sort_lower: Flyt ned + label_sort_lowest: Flyt til bunden + label_roadmap: Roadmap + label_roadmap_due_in: Deadline + label_roadmap_overdue: "%{value} forsinket" + label_roadmap_no_issues: Ingen sager i denne version + label_search: Søg + label_result_plural: Resultater + label_all_words: Alle ord + label_wiki: Wiki + label_wiki_edit: Wiki ændring + label_wiki_edit_plural: Wiki ændringer + label_wiki_page: Wiki side + label_wiki_page_plural: Wiki sider + label_index_by_title: Indhold efter titel + label_index_by_date: Indhold efter dato + label_current_version: Nuværende version + label_preview: Forhåndsvisning + label_feed_plural: Feeds + label_changes_details: Detaljer for alle ændringer + label_issue_tracking: Sagssøgning + label_spent_time: Anvendt tid + label_f_hour: "%{value} time" + label_f_hour_plural: "%{value} timer" + label_time_tracking: Tidsstyring + label_change_plural: Ændringer + label_statistics: Statistik + label_commits_per_month: Commits pr. måned + label_commits_per_author: Commits pr. bruger + label_view_diff: Vis forskelle + label_diff_inline: inline + label_diff_side_by_side: side om side + label_options: Formatering + label_copy_workflow_from: Kopier arbejdsgang fra + label_permissions_report: Godkendelsesrapport + label_watched_issues: Overvågede sager + label_related_issues: Relaterede sager + label_applied_status: Anvendte statusser + label_loading: Indlæser... + label_relation_new: Ny relation + label_relation_delete: Slet relation + label_relates_to: relaterer til + label_duplicates: duplikater + label_blocks: blokerer + label_blocked_by: blokeret af + label_precedes: kommer før + label_follows: følger + label_end_to_start: slut til start + label_end_to_end: slut til slut + label_start_to_start: start til start + label_start_to_end: start til slut + label_stay_logged_in: Forbliv indlogget + label_disabled: deaktiveret + label_show_completed_versions: Vis færdige versioner + label_me: mig + label_board: Forum + label_board_new: Nyt forum + label_board_plural: Fora + label_topic_plural: Emner + label_message_plural: Beskeder + label_message_last: Sidste besked + label_message_new: Ny besked + label_message_posted: Besked tilføjet + label_reply_plural: Besvarer + label_send_information: Send konto information til bruger + label_year: År + label_month: Måned + label_week: Uge + label_date_from: Fra + label_date_to: Til + label_language_based: Baseret på brugerens sprog + label_sort_by: "Sortér efter %{value}" + label_send_test_email: Send en test email + label_feeds_access_key_created_on: "RSS adgangsnøgle dannet for %{value} siden" + label_module_plural: Moduler + label_added_time_by: "Tilføjet af %{author} for %{age} siden" + label_updated_time: "Opdateret for %{value} siden" + label_jump_to_a_project: Skift til projekt... + label_file_plural: Filer + label_changeset_plural: Ændringer + label_default_columns: Standardkolonner + label_no_change_option: (Ingen ændringer) + label_bulk_edit_selected_issues: Masse-ret de valgte sager + label_theme: Tema + label_default: standard + label_search_titles_only: Søg kun i titler + label_user_mail_option_all: "For alle hændelser på mine projekter" + label_user_mail_option_selected: "For alle hændelser på de valgte projekter..." + label_user_mail_no_self_notified: "Jeg ønsker ikke besked om ændring foretaget af mig selv" + label_registration_activation_by_email: kontoaktivering på email + label_registration_manual_activation: manuel kontoaktivering + label_registration_automatic_activation: automatisk kontoaktivering + label_display_per_page: "Per side: %{value}" + label_age: Alder + label_change_properties: Ændre indstillinger + label_general: Generelt + label_more: Mere + label_scm: SCM + label_plugins: Plugins + label_ldap_authentication: LDAP-godkendelse + label_downloads_abbr: D/L + + button_login: Login + button_submit: Send + button_save: Gem + button_check_all: Vælg alt + button_uncheck_all: Fravælg alt + button_delete: Slet + button_create: Opret + button_test: Test + button_edit: Ret + button_add: Tilføj + button_change: Ændre + button_apply: Anvend + button_clear: Nulstil + button_lock: Lås + button_unlock: Lås op + button_download: Download + button_list: List + button_view: Vis + button_move: Flyt + button_back: Tilbage + button_cancel: Annullér + button_activate: Aktivér + button_sort: Sortér + button_log_time: Log tid + button_rollback: Tilbagefør til denne version + button_watch: Overvåg + button_unwatch: Stop overvågning + button_reply: Besvar + button_archive: Arkivér + button_unarchive: Fjern fra arkiv + button_reset: Nulstil + button_rename: Omdøb + button_change_password: Skift kodeord + button_copy: Kopiér + button_annotate: Annotér + button_update: Opdatér + button_configure: Konfigurér + + status_active: aktiv + status_registered: registreret + status_locked: låst + + text_select_mail_notifications: Vælg handlinger der skal sendes email besked for. + text_regexp_info: f.eks. ^[A-ZÆØÅ0-9]+$ + text_min_max_length_info: 0 betyder ingen begrænsninger + text_project_destroy_confirmation: Er du sikker på at du vil slette dette projekt og alle relaterede data? + text_workflow_edit: Vælg en rolle samt en type, for at redigere arbejdsgangen + text_are_you_sure: Er du sikker? + text_tip_issue_begin_day: opgaven begynder denne dag + text_tip_issue_end_day: opaven slutter denne dag + text_tip_issue_begin_end_day: opgaven begynder og slutter denne dag + text_caracters_maximum: "max %{count} karakterer." + text_caracters_minimum: "Skal være mindst %{count} karakterer lang." + text_length_between: "Længde skal være mellem %{min} og %{max} karakterer." + text_tracker_no_workflow: Ingen arbejdsgang defineret for denne type + text_unallowed_characters: Ikke-tilladte karakterer + text_comma_separated: Adskillige værdier tilladt (adskilt med komma). + text_issues_ref_in_commit_messages: Referer og løser sager i commit-beskeder + text_issue_added: "Sag %{id} er rapporteret af %{author}." + text_issue_updated: "Sag %{id} er blevet opdateret af %{author}." + text_wiki_destroy_confirmation: Er du sikker på at du vil slette denne wiki og dens indhold? + text_issue_category_destroy_question: "Nogle sager (%{count}) er tildelt denne kategori. Hvad ønsker du at gøre?" + text_issue_category_destroy_assignments: Slet tildelinger af kategori + text_issue_category_reassign_to: Tildel sager til denne kategori + text_user_mail_option: "For ikke-valgte projekter vil du kun modtage beskeder omhandlende ting du er involveret i eller overvåger (f.eks. sager du har indberettet eller ejer)." + text_no_configuration_data: "Roller, typer, sagsstatusser og arbejdsgange er endnu ikke konfigureret.\nDet er anbefalet at indlæse standardopsætningen. Du vil kunne ændre denne når den er indlæst." + text_load_default_configuration: Indlæs standardopsætningen + text_status_changed_by_changeset: "Anvendt i ændring %{value}." + text_issues_destroy_confirmation: 'Er du sikker på du ønsker at slette den/de valgte sag(er)?' + text_select_project_modules: 'Vælg moduler er skal være aktiveret for dette projekt:' + text_default_administrator_account_changed: Standardadministratorkonto ændret + text_file_repository_writable: Filarkiv er skrivbar + text_rmagick_available: RMagick tilgængelig (valgfri) + + default_role_manager: Leder + default_role_developer: Udvikler + default_role_reporter: Rapportør + default_tracker_bug: Fejl + default_tracker_feature: Funktion + default_tracker_support: Support + default_issue_status_new: Ny + default_issue_status_in_progress: Igangværende + default_issue_status_resolved: Løst + default_issue_status_feedback: Feedback + default_issue_status_closed: Lukket + default_issue_status_rejected: Afvist + default_doc_category_user: Brugerdokumentation + default_doc_category_tech: Teknisk dokumentation + default_priority_low: Lav + default_priority_normal: Normal + default_priority_high: Høj + default_priority_urgent: Akut + default_priority_immediate: Omgående + default_activity_design: Design + default_activity_development: Udvikling + + enumeration_issue_priorities: Sagsprioriteter + enumeration_doc_categories: Dokumentkategorier + enumeration_activities: Aktiviteter (tidsstyring) + + label_add_another_file: Tilføj endnu en fil + label_chronological_order: I kronologisk rækkefølge + setting_activity_days_default: Antal dage der vises under projektaktivitet + text_destroy_time_entries_question: "%{hours} timer er registreret på denne sag som du er ved at slette. Hvad vil du gøre?" + error_issue_not_found_in_project: 'Sagen blev ikke fundet eller tilhører ikke dette projekt' + text_assign_time_entries_to_project: Tildel raporterede timer til projektet + setting_display_subprojects_issues: Vis sager for underprojekter på hovedprojektet som standard + label_optional_description: Valgfri beskrivelse + text_destroy_time_entries: Slet registrerede timer + field_comments_sorting: Vis kommentar + text_reassign_time_entries: 'Tildel registrerede timer til denne sag igen' + label_reverse_chronological_order: I omvendt kronologisk rækkefølge + label_preferences: Præferencer + label_overall_activity: Overordnet aktivitet + setting_default_projects_public: Nye projekter er offentlige som standard + error_scm_annotate: "Filen findes ikke, eller kunne ikke annoteres." + label_planning: Planlægning + text_subprojects_destroy_warning: "Dets underprojekter(er): %{value} vil også blive slettet." + permission_edit_issues: Redigér sager + setting_diff_max_lines_displayed: Højeste antal forskelle der vises + permission_edit_own_issue_notes: Redigér egne noter + setting_enabled_scm: Aktiveret SCM + button_quote: Citér + permission_view_files: Se filer + permission_add_issues: Tilføj sager + permission_edit_own_messages: Redigér egne beskeder + permission_delete_own_messages: Slet egne beskeder + permission_manage_public_queries: Administrér offentlig forespørgsler + permission_log_time: Registrér anvendt tid + label_renamed: omdøbt + label_incoming_emails: Indkommende emails + permission_view_changesets: Se ændringer + permission_manage_versions: Administrér versioner + permission_view_time_entries: Se anvendt tid + label_generate_key: Generér en nøglefil + permission_manage_categories: Administrér sagskategorier + permission_manage_wiki: Administrér wiki + setting_sequential_project_identifiers: Generér sekventielle projekt-identifikatorer + setting_plain_text_mail: Emails som almindelig tekst (ingen HTML) + field_parent_title: Siden over + text_email_delivery_not_configured: "Email-afsendelse er ikke indstillet og notifikationer er defor slået fra.\nKonfigurér din SMTP server i config/configuration.yml og genstart applikationen for at aktivere email-afsendelse." + permission_protect_wiki_pages: Beskyt wiki sider + permission_add_issue_watchers: Tilføj overvågere + warning_attachments_not_saved: "der var %{count} fil(er), som ikke kunne gemmes." + permission_comment_news: Kommentér nyheder + text_enumeration_category_reassign_to: 'Flyt dem til denne værdi:' + permission_select_project_modules: Vælg projektmoduler + permission_view_gantt: Se Gantt diagram + permission_delete_messages: Slet beskeder + permission_move_issues: Flyt sager + permission_edit_wiki_pages: Redigér wiki sider + label_user_activity: "%{value}'s aktivitet" + permission_manage_issue_relations: Administrér sags-relationer + label_issue_watchers: Overvågere + permission_delete_wiki_pages: Slet wiki sider + notice_unable_delete_version: Kan ikke slette versionen. + permission_view_wiki_edits: Se wiki historik + field_editable: Redigérbar + label_duplicated_by: dubleret af + permission_manage_boards: Administrér fora + permission_delete_wiki_pages_attachments: Slet filer vedhæftet wiki sider + permission_view_messages: Se beskeder + text_enumeration_destroy_question: "%{count} objekter er tildelt denne værdi." + permission_manage_files: Administrér filer + permission_add_messages: Opret beskeder + permission_edit_issue_notes: Redigér noter + permission_manage_news: Administrér nyheder + text_plugin_assets_writable: Der er skriverettigheder til plugin assets folderen + label_display: Vis + label_and_its_subprojects: "%{value} og dets underprojekter" + permission_view_calendar: Se kalender + button_create_and_continue: Opret og fortsæt + setting_gravatar_enabled: Anvend Gravatar brugerikoner + label_updated_time_by: "Opdateret af %{author} for %{age} siden" + text_diff_truncated: '... Listen over forskelle er blevet afkortet da den overstiger den maksimale størrelse der kan vises.' + text_user_wrote: "%{value} skrev:" + setting_mail_handler_api_enabled: Aktiver webservice for indkomne emails + permission_delete_issues: Slet sager + permission_view_documents: Se dokumenter + permission_browse_repository: Gennemse repository + permission_manage_repository: Administrér repository + permission_manage_members: Administrér medlemmer + mail_subject_reminder: "%{count} sag(er) har deadline i de kommende dage (%{days})" + permission_add_issue_notes: Tilføj noter + permission_edit_messages: Redigér beskeder + permission_view_issue_watchers: Se liste over overvågere + permission_commit_access: Commit adgang + setting_mail_handler_api_key: API nøgle + label_example: Eksempel + permission_rename_wiki_pages: Omdøb wiki sider + text_custom_field_possible_values_info: 'En linje for hver værdi' + permission_view_wiki_pages: Se wiki + permission_edit_project: Redigér projekt + permission_save_queries: Gem forespørgsler + label_copied: kopieret + text_repository_usernames_mapping: "Vælg eller opdatér de Redmine brugere der svarer til de enkelte brugere fundet i repository loggen.\nBrugere med samme brugernavn eller email adresse i både Redmine og det valgte repository bliver automatisk koblet sammen." + permission_edit_time_entries: Redigér tidsregistreringer + general_csv_decimal_separator: ',' + permission_edit_own_time_entries: Redigér egne tidsregistreringer + setting_repository_log_display_limit: Højeste antal revisioner vist i fil-log + setting_file_max_size_displayed: Maksimale størrelse på tekstfiler vist inline + field_watcher: Overvåger + setting_openid: Tillad OpenID login og registrering + field_identity_url: OpenID URL + label_login_with_open_id_option: eller login med OpenID + setting_per_page_options: Enheder per side muligheder + mail_body_reminder: "%{count} sage(er) som er tildelt dig har deadline indenfor de næste %{days} dage:" + field_content: Indhold + label_descending: Aftagende + label_sort: Sortér + label_ascending: Tiltagende + label_date_from_to: Fra %{start} til %{end} + label_greater_or_equal: ">=" + label_less_or_equal: <= + text_wiki_page_destroy_question: Denne side har %{descendants} underside(r) og afledte. Hvad vil du gøre? + text_wiki_page_reassign_children: Flyt undersider til denne side + text_wiki_page_nullify_children: Behold undersider som rod-sider + text_wiki_page_destroy_children: Slet undersider ogalle deres afledte sider. + setting_password_min_length: Mindste længde på kodeord + field_group_by: Gruppér resultater efter + mail_subject_wiki_content_updated: "'%{id}' wikisiden er blevet opdateret" + label_wiki_content_added: Wiki side tilføjet + mail_subject_wiki_content_added: "'%{id}' wikisiden er blevet tilføjet" + mail_body_wiki_content_added: The '%{id}' wikiside er blevet tilføjet af %{author}. + label_wiki_content_updated: Wikiside opdateret + mail_body_wiki_content_updated: Wikisiden '%{id}' er blevet opdateret af %{author}. + permission_add_project: Opret projekt + setting_new_project_user_role_id: Denne rolle gives til en bruger, som ikke er administrator, og som opretter et projekt + label_view_all_revisions: Se alle revisioner + label_tag: Tag + label_branch: Branch + error_no_tracker_in_project: Der er ingen sagshåndtering for dette projekt. Kontrollér venligst projektindstillingerne. + error_no_default_issue_status: Der er ikke defineret en standardstatus. Kontrollér venligst indstillingerne (gå til "Administration -> Sagsstatusser"). + text_journal_changed: "%{label} ændret fra %{old} til %{new}" + text_journal_set_to: "%{label} sat til %{value}" + text_journal_deleted: "%{label} slettet (%{old})" + label_group_plural: Grupper + label_group: Grupper + label_group_new: Ny gruppe + label_time_entry_plural: Anvendt tid + text_journal_added: "%{label} %{value} tilføjet" + field_active: Aktiv + enumeration_system_activity: System Aktivitet + permission_delete_issue_watchers: Slet overvågere + version_status_closed: lukket + version_status_locked: låst + version_status_open: åben + error_can_not_reopen_issue_on_closed_version: En sag tildelt en lukket version kan ikke genåbnes + label_user_anonymous: Anonym + button_move_and_follow: Flyt og overvåg + setting_default_projects_modules: Standard moduler, aktiveret for nye projekter + setting_gravatar_default: Standard Gravatar billede + field_sharing: Delning + label_version_sharing_hierarchy: Med projekthierarki + label_version_sharing_system: Med alle projekter + label_version_sharing_descendants: Med underprojekter + label_version_sharing_tree: Med projekttræ + label_version_sharing_none: Ikke delt + error_can_not_archive_project: Dette projekt kan ikke arkiveres + button_duplicate: Duplikér + button_copy_and_follow: Kopiér og overvåg + label_copy_source: Kilde + setting_issue_done_ratio: Beregn sagsløsning ratio + setting_issue_done_ratio_issue_status: Benyt sagsstatus + error_issue_done_ratios_not_updated: Sagsløsnings ratio, ikke opdateret. + error_workflow_copy_target: Vælg venligst måltracker og rolle(r) + setting_issue_done_ratio_issue_field: Benyt sagsfelt + label_copy_same_as_target: Samme som mål + label_copy_target: Mål + notice_issue_done_ratios_updated: Sagsløsningsratio opdateret. + error_workflow_copy_source: Vælg venligst en kildetracker eller rolle + label_update_issue_done_ratios: Opdater sagsløsningsratio + setting_start_of_week: Start kalendre på + permission_view_issues: Vis sager + label_display_used_statuses_only: Vis kun statusser der er benyttet af denne tracker + label_revision_id: Revision %{value} + label_api_access_key: API nøgle + label_api_access_key_created_on: API nøgle genereret %{value} siden + label_feeds_access_key: RSS nøgle + notice_api_access_key_reseted: Din API nøgle er nulstillet. + setting_rest_api_enabled: Aktiver REST web service + label_missing_api_access_key: Mangler en API nøgle + label_missing_feeds_access_key: Mangler en RSS nøgle + button_show: Vis + text_line_separated: Flere væredier tilladt (en linje for hver værdi). + setting_mail_handler_body_delimiters: Trunkér emails efter en af disse linjer + permission_add_subprojects: Lav underprojekter + label_subproject_new: Nyt underprojekt + text_own_membership_delete_confirmation: |- + Du er ved at fjerne en eller flere af dine rettigheder, og kan muligvis ikke redigere projektet bagefter. + Er du sikker på du ønsker at fortsætte? + label_close_versions: Luk færdige versioner + label_board_sticky: Klistret + label_board_locked: Låst + permission_export_wiki_pages: Eksporter wiki sider + setting_cache_formatted_text: Cache formatteret tekst + permission_manage_project_activities: Administrer projektaktiviteter + error_unable_delete_issue_status: Det var ikke muligt at slette sagsstatus + label_profile: Profil + permission_manage_subtasks: Administrer underopgaver + field_parent_issue: Hovedopgave + label_subtask_plural: Underopgaver + label_project_copy_notifications: Send email notifikationer, mens projektet kopieres + error_can_not_delete_custom_field: Kan ikke slette brugerdefineret felt + error_unable_to_connect: Kan ikke forbinde (%{value}) + error_can_not_remove_role: Denne rolle er i brug og kan ikke slettes. + error_can_not_delete_tracker: Denne type indeholder sager og kan ikke slettes. + field_principal: Principal + label_my_page_block: blok + notice_failed_to_save_members: "Fejl under lagring af medlem(mer): %{errors}." + text_zoom_out: Zoom ud + text_zoom_in: Zoom ind + notice_unable_delete_time_entry: Kan ikke slette tidsregistrering. + label_overall_spent_time: Overordnet forbrug af tid + field_time_entries: Log tid + project_module_gantt: Gantt + project_module_calendar: Kalender + button_edit_associated_wikipage: "Redigér tilknyttet Wiki side: %{page_title}" + field_text: Tekstfelt + label_user_mail_option_only_owner: Kun for ting jeg er ejer af + setting_default_notification_option: Standardpåmindelsesmulighed + label_user_mail_option_only_my_events: Kun for ting jeg overvåger eller er involveret i + label_user_mail_option_only_assigned: Kun for ting jeg er tildelt + label_user_mail_option_none: Ingen hændelser + field_member_of_group: Medlem af gruppe + field_assigned_to_role: Medlem af rolle + notice_not_authorized_archived_project: Projektet du prøver at tilgå, er blevet arkiveret. + label_principal_search: "Søg efter bruger eller gruppe:" + label_user_search: "Søg efter bruger:" + field_visible: Synlig + setting_commit_logtime_activity_id: Aktivitet for registreret tid + text_time_logged_by_changeset: Anvendt i changeset %{value}. + setting_commit_logtime_enabled: Aktiver tidsregistrering + notice_gantt_chart_truncated: Kortet er blevet afkortet, fordi det overstiger det maksimale antal elementer, der kan vises (%{max}) + setting_gantt_items_limit: Maksimalt antal af elementer der kan vises på gantt kortet + + field_warn_on_leaving_unsaved: Warn me when leaving a page with unsaved text + text_warn_on_leaving_unsaved: The current page contains unsaved text that will be lost if you leave this page. + label_my_queries: My custom queries + text_journal_changed_no_detail: "%{label} updated" + label_news_comment_added: Comment added to a news + button_expand_all: Expand all + button_collapse_all: Collapse all + label_additional_workflow_transitions_for_assignee: Additional transitions allowed when the user is the assignee + label_additional_workflow_transitions_for_author: Additional transitions allowed when the user is the author + label_bulk_edit_selected_time_entries: Bulk edit selected time entries + text_time_entries_destroy_confirmation: Are you sure you want to delete the selected time entr(y/ies)? + label_role_anonymous: Anonymous + label_role_non_member: Non member + label_issue_note_added: Note added + label_issue_status_updated: Status updated + label_issue_priority_updated: Priority updated + label_issues_visibility_own: Issues created by or assigned to the user + field_issues_visibility: Issues visibility + label_issues_visibility_all: All issues + permission_set_own_issues_private: Set own issues public or private + field_is_private: Private + permission_set_issues_private: Set issues public or private + label_issues_visibility_public: All non private issues + text_issues_destroy_descendants_confirmation: This will also delete %{count} subtask(s). + field_commit_logs_encoding: Kodning af Commit beskeder + field_scm_path_encoding: Path encoding + text_scm_path_encoding_note: "Default: UTF-8" + field_path_to_repository: Path to repository + field_root_directory: Root directory + field_cvs_module: Module + field_cvsroot: CVSROOT + text_mercurial_repository_note: Local repository (e.g. /hgrepo, c:\hgrepo) + text_scm_command: Command + text_scm_command_version: Version + label_git_report_last_commit: Report last commit for files and directories + notice_issue_successful_create: Issue %{id} created. + label_between: between + setting_issue_group_assignment: Allow issue assignment to groups + label_diff: diff + text_git_repository_note: Repository is bare and local (e.g. /gitrepo, c:\gitrepo) + description_query_sort_criteria_direction: Sort direction + description_project_scope: Search scope + description_filter: Filter + description_user_mail_notification: Mail notification settings + description_date_from: Enter start date + description_message_content: Message content + description_available_columns: Available Columns + description_date_range_interval: Choose range by selecting start and end date + description_issue_category_reassign: Choose issue category + description_search: Searchfield + description_notes: Notes + description_date_range_list: Choose range from list + description_choose_project: Projects + description_date_to: Enter end date + description_query_sort_criteria_attribute: Sort attribute + description_wiki_subpages_reassign: Choose new parent page + description_selected_columns: Selected Columns + label_parent_revision: Parent + label_child_revision: Child + error_scm_annotate_big_text_file: The entry cannot be annotated, as it exceeds the maximum text file size. + setting_default_issue_start_date_to_creation_date: Use current date as start date for new issues + button_edit_section: Edit this section + setting_repositories_encodings: Attachments and repositories encodings + description_all_columns: All Columns + button_export: Export + label_export_options: "%{export_format} export options" + error_attachment_too_big: This file cannot be uploaded because it exceeds the maximum allowed file size (%{max_size}) + notice_failed_to_save_time_entries: "Failed to save %{count} time entrie(s) on %{total} selected: %{ids}." + label_x_issues: + zero: 0 sag + one: 1 sag + other: "%{count} sager" + label_repository_new: New repository + field_repository_is_default: Main repository + label_copy_attachments: Copy attachments + label_item_position: "%{position}/%{count}" + label_completed_versions: Completed versions + text_project_identifier_info: Only lower case letters (a-z), numbers, dashes and underscores are allowed.
    Once saved, the identifier cannot be changed. + field_multiple: Multiple values + setting_commit_cross_project_ref: Allow issues of all the other projects to be referenced and fixed + text_issue_conflict_resolution_add_notes: Add my notes and discard my other changes + text_issue_conflict_resolution_overwrite: Apply my changes anyway (previous notes will be kept but some changes may be overwritten) + notice_issue_update_conflict: The issue has been updated by an other user while you were editing it. + text_issue_conflict_resolution_cancel: Discard all my changes and redisplay %{link} + permission_manage_related_issues: Manage related issues + field_auth_source_ldap_filter: LDAP filter + label_search_for_watchers: Search for watchers to add + notice_account_deleted: Your account has been permanently deleted. + setting_unsubscribe: Allow users to delete their own account + button_delete_my_account: Delete my account + text_account_destroy_confirmation: |- + Are you sure you want to proceed? + Your account will be permanently deleted, with no way to reactivate it. + error_session_expired: Your session has expired. Please login again. + text_session_expiration_settings: "Warning: changing these settings may expire the current sessions including yours." + setting_session_lifetime: Session maximum lifetime + setting_session_timeout: Session inactivity timeout + label_session_expiration: Session expiration + permission_close_project: Close / reopen the project + label_show_closed_projects: View closed projects + button_close: Close + button_reopen: Reopen + project_status_active: active + project_status_closed: closed + project_status_archived: archived + text_project_closed: This project is closed and read-only. + notice_user_successful_create: User %{id} created. + field_core_fields: Standard fields + field_timeout: Timeout (in seconds) + setting_thumbnails_enabled: Display attachment thumbnails + setting_thumbnails_size: Thumbnails size (in pixels) + label_status_transitions: Status transitions + label_fields_permissions: Fields permissions + label_readonly: Read-only + label_required: Required + text_repository_identifier_info: Only lower case letters (a-z), numbers, dashes and underscores are allowed.
    Once saved, the identifier cannot be changed. + field_board_parent: Parent forum + label_attribute_of_project: Project's %{name} + label_attribute_of_author: Author's %{name} + label_attribute_of_assigned_to: Assignee's %{name} + label_attribute_of_fixed_version: Target version's %{name} + label_copy_subtasks: Copy subtasks + label_copied_to: copied to + label_copied_from: copied from + label_any_issues_in_project: any issues in project + label_any_issues_not_in_project: any issues not in project + field_private_notes: Private notes + permission_view_private_notes: View private notes + permission_set_notes_private: Set notes as private + label_no_issues_in_project: no issues in project + label_any: alle + label_last_n_weeks: last %{count} weeks + setting_cross_project_subtasks: Allow cross-project subtasks + label_cross_project_descendants: Med underprojekter + label_cross_project_tree: Med projekttræ + label_cross_project_hierarchy: Med projekthierarki + label_cross_project_system: Med alle projekter + button_hide: Hide + setting_non_working_week_days: Non-working days + label_in_the_next_days: in the next + label_in_the_past_days: in the past + label_attribute_of_user: User's %{name} + text_turning_multiple_off: If you disable multiple values, multiple values will be + removed in order to preserve only one value per item. + label_attribute_of_issue: Issue's %{name} + permission_add_documents: Add documents + permission_edit_documents: Edit documents + permission_delete_documents: Delete documents + label_gantt_progress_line: Progress line + setting_jsonp_enabled: Enable JSONP support + field_inherit_members: Inherit members + field_closed_on: Closed + setting_default_projects_tracker_ids: Default trackers for new projects + label_total_time: Total + text_scm_config: You can configure your SCM commands in config/configuration.yml. Please restart the application after editing it. + text_scm_command_not_available: SCM command is not available. Please check settings on the administration panel. + setting_emails_header: Email header diff --git a/config/locales/de.yml b/config/locales/de.yml new file mode 100644 index 00000000..4fffdd85 --- /dev/null +++ b/config/locales/de.yml @@ -0,0 +1,1101 @@ +# German translations for Ruby on Rails +# by Clemens Kofler (clemens@railway.at) +# additions for Redmine 1.2 by Jens Martsch (jmartsch@gmail.com) + +de: + direction: ltr + date: + formats: + # Use the strftime parameters for formats. + # When no format has been given, it uses default. + # You can provide other formats here if you like! + default: "%d.%m.%Y" + short: "%e. %b" + long: "%e. %B %Y" + + day_names: [Sonntag, Montag, Dienstag, Mittwoch, Donnerstag, Freitag, Samstag] + abbr_day_names: [So, Mo, Di, Mi, Do, Fr, Sa] + + # Don't forget the nil at the beginning; there's no such thing as a 0th month + month_names: [~, Januar, Februar, März, April, Mai, Juni, Juli, August, September, Oktober, November, Dezember] + abbr_month_names: [~, Jan, Feb, Mär, Apr, Mai, Jun, Jul, Aug, Sep, Okt, Nov, Dez] + # Used in date_select and datime_select. + order: + - :day + - :month + - :year + + time: + formats: + default: "%d.%m.%Y %H:%M" + time: "%H:%M" + short: "%e. %b %H:%M" + long: "%A, %e. %B %Y, %H:%M Uhr" + am: "vormittags" + pm: "nachmittags" + + datetime: + distance_in_words: + half_a_minute: 'eine halbe Minute' + less_than_x_seconds: + one: 'weniger als 1 Sekunde' + other: 'weniger als %{count} Sekunden' + x_seconds: + one: '1 Sekunde' + other: '%{count} Sekunden' + less_than_x_minutes: + one: 'weniger als 1 Minute' + other: 'weniger als %{count} Minuten' + x_minutes: + one: '1 Minute' + other: '%{count} Minuten' + about_x_hours: + one: 'etwa 1 Stunde' + other: 'etwa %{count} Stunden' + x_hours: + one: "1 hour" + other: "%{count} hours" + x_days: + one: '1 Tag' + other: '%{count} Tagen' + about_x_months: + one: 'etwa 1 Monat' + other: 'etwa %{count} Monaten' + x_months: + one: '1 Monat' + other: '%{count} Monaten' + about_x_years: + one: 'etwa 1 Jahr' + other: 'etwa %{count} Jahren' + over_x_years: + one: 'mehr als 1 Jahr' + other: 'mehr als %{count} Jahren' + almost_x_years: + one: "fast 1 Jahr" + other: "fast %{count} Jahren" + + number: + # Default format for numbers + format: + separator: ',' + delimiter: '.' + precision: 2 + currency: + format: + unit: '€' + format: '%n %u' + delimiter: '' + percentage: + format: + delimiter: "" + precision: + format: + delimiter: "" + human: + format: + delimiter: "" + precision: 3 + storage_units: + format: "%n %u" + units: + byte: + one: "Byte" + other: "Bytes" + kb: "KB" + mb: "MB" + gb: "GB" + tb: "TB" + +# Used in array.to_sentence. + support: + array: + sentence_connector: "und" + skip_last_comma: true + + activerecord: + errors: + template: + header: + one: "Dieses %{model}-Objekt konnte nicht gespeichert werden: %{count} Fehler." + other: "Dieses %{model}-Objekt konnte nicht gespeichert werden: %{count} Fehler." + body: "Bitte überprüfen Sie die folgenden Felder:" + + messages: + inclusion: "ist kein gültiger Wert" + exclusion: "ist nicht verfügbar" + invalid: "ist nicht gültig" + confirmation: "stimmt nicht mit der Bestätigung überein" + accepted: "muss akzeptiert werden" + empty: "muss ausgefüllt werden" + blank: "muss ausgefüllt werden" + too_long: "ist zu lang (nicht mehr als %{count} Zeichen)" + too_short: "ist zu kurz (nicht weniger als %{count} Zeichen)" + wrong_length: "hat die falsche Länge (muss genau %{count} Zeichen haben)" + taken: "ist bereits vergeben" + not_a_number: "ist keine Zahl" + not_a_date: "is kein gültiges Datum" + greater_than: "muss größer als %{count} sein" + greater_than_or_equal_to: "muss größer oder gleich %{count} sein" + equal_to: "muss genau %{count} sein" + less_than: "muss kleiner als %{count} sein" + less_than_or_equal_to: "muss kleiner oder gleich %{count} sein" + odd: "muss ungerade sein" + even: "muss gerade sein" + greater_than_start_date: "muss größer als Anfangsdatum sein" + not_same_project: "gehört nicht zum selben Projekt" + circular_dependency: "Diese Beziehung würde eine zyklische Abhängigkeit erzeugen" + cant_link_an_issue_with_a_descendant: "Ein Ticket kann nicht mit einer Ihrer Unteraufgaben verlinkt werden" + + actionview_instancetag_blank_option: Bitte auswählen + + button_activate: Aktivieren + button_add: Hinzufügen + button_annotate: Annotieren + button_apply: Anwenden + button_archive: Archivieren + button_back: Zurück + button_cancel: Abbrechen + button_change: Wechseln + button_change_password: Kennwort ändern + button_check_all: Alles auswählen + button_clear: Zurücksetzen + button_close: Schließen + button_collapse_all: Alle einklappen + button_configure: Konfigurieren + button_copy: Kopieren + button_copy_and_follow: Kopieren und Ticket anzeigen + button_create: Anlegen + button_create_and_continue: Anlegen und weiter + button_delete: Löschen + button_delete_my_account: Mein Benutzerkonto löschen + button_download: Download + button_duplicate: Duplizieren + button_edit: Bearbeiten + button_edit_associated_wikipage: "Zugehörige Wikiseite bearbeiten: %{page_title}" + button_edit_section: Diesen Bereich bearbeiten + button_expand_all: Alle ausklappen + button_export: Exportieren + button_hide: Verstecken + button_list: Liste + button_lock: Sperren + button_log_time: Aufwand buchen + button_login: Anmelden + button_move: Verschieben + button_move_and_follow: Verschieben und Ticket anzeigen + button_quote: Zitieren + button_rename: Umbenennen + button_reopen: Öffnen + button_reply: Antworten + button_reset: Zurücksetzen + button_rollback: Auf diese Version zurücksetzen + button_save: Speichern + button_show: Anzeigen + button_sort: Sortieren + button_submit: OK + button_test: Testen + button_unarchive: Entarchivieren + button_uncheck_all: Alles abwählen + button_unlock: Entsperren + button_unwatch: Nicht beobachten + button_update: Bearbeiten + button_view: Anzeigen + button_watch: Beobachten + + default_activity_design: Design + default_activity_development: Entwicklung + default_doc_category_tech: Technische Dokumentation + default_doc_category_user: Benutzerdokumentation + default_issue_status_closed: Erledigt + default_issue_status_feedback: Feedback + default_issue_status_in_progress: In Bearbeitung + default_issue_status_new: Neu + default_issue_status_rejected: Abgewiesen + default_issue_status_resolved: Gelöst + default_priority_high: Hoch + default_priority_immediate: Sofort + default_priority_low: Niedrig + default_priority_normal: Normal + default_priority_urgent: Dringend + default_role_developer: Entwickler + default_role_manager: Manager + default_role_reporter: Reporter + default_tracker_bug: Fehler + default_tracker_feature: Feature + default_tracker_support: Unterstützung + + description_all_columns: Alle Spalten + description_available_columns: Verfügbare Spalten + description_choose_project: Projekte + description_date_from: Startdatum eintragen + description_date_range_interval: Zeitraum durch Start- und Enddatum festlegen + description_date_range_list: Zeitraum aus einer Liste wählen + description_date_to: Enddatum eintragen + description_filter: Filter + description_issue_category_reassign: Neue Kategorie wählen + description_message_content: Nachrichteninhalt + description_notes: Kommentare + description_project_scope: Suchbereich + description_query_sort_criteria_attribute: Sortierattribut + description_query_sort_criteria_direction: Sortierrichtung + description_search: Suchfeld + description_selected_columns: Ausgewählte Spalten + description_user_mail_notification: Mailbenachrichtigungseinstellung + description_wiki_subpages_reassign: Neue Elternseite wählen + + enumeration_activities: Aktivitäten (Zeiterfassung) + enumeration_doc_categories: Dokumentenkategorien + enumeration_issue_priorities: Ticket-Prioritäten + enumeration_system_activity: System-Aktivität + + error_attachment_too_big: Diese Datei kann nicht hochgeladen werden, da sie die maximale Dateigröße von (%{max_size}) überschreitet. + error_can_not_archive_project: Dieses Projekt kann nicht archiviert werden. + error_can_not_delete_custom_field: Kann das benutzerdefinierte Feld nicht löschen. + error_can_not_delete_tracker: Dieser Tracker enthält Tickets und kann nicht gelöscht werden. + error_can_not_remove_role: Diese Rolle wird verwendet und kann nicht gelöscht werden. + error_can_not_reopen_issue_on_closed_version: Das Ticket ist einer abgeschlossenen Version zugeordnet und kann daher nicht wieder geöffnet werden. + error_can_t_load_default_data: "Die Standard-Konfiguration konnte nicht geladen werden: %{value}" + error_issue_done_ratios_not_updated: Der Ticket-Fortschritt wurde nicht aktualisiert. + error_issue_not_found_in_project: 'Das Ticket wurde nicht gefunden oder gehört nicht zu diesem Projekt.' + error_no_default_issue_status: Es ist kein Status als Standard definiert. Bitte überprüfen Sie Ihre Konfiguration (unter "Administration -> Ticket-Status"). + error_no_tracker_in_project: Diesem Projekt ist kein Tracker zugeordnet. Bitte überprüfen Sie die Projekteinstellungen. + error_scm_annotate: "Der Eintrag existiert nicht oder kann nicht annotiert werden." + error_scm_annotate_big_text_file: Der Eintrag kann nicht umgesetzt werden, da er die maximale Textlänge überschreitet. + error_scm_command_failed: "Beim Zugriff auf das Projektarchiv ist ein Fehler aufgetreten: %{value}" + error_scm_not_found: Eintrag und/oder Revision existiert nicht im Projektarchiv. + error_session_expired: Ihre Sitzung ist abgelaufen. Bitte melden Sie sich erneut an. + error_unable_delete_issue_status: "Der Ticket-Status konnte nicht gelöscht werden." + error_unable_to_connect: Fehler beim Verbinden (%{value}) + error_workflow_copy_source: Bitte wählen Sie einen Quell-Tracker und eine Quell-Rolle. + error_workflow_copy_target: Bitte wählen Sie die Ziel-Tracker und -Rollen. + + field_account: Konto + field_active: Aktiv + field_activity: Aktivität + field_admin: Administrator + field_assignable: Tickets können dieser Rolle zugewiesen werden + field_assigned_to: Zugewiesen an + field_assigned_to_role: Zuständigkeitsrolle + field_attr_firstname: Vorname-Attribut + field_attr_lastname: Name-Attribut + field_attr_login: Mitgliedsname-Attribut + field_attr_mail: E-Mail-Attribut + field_auth_source: Authentifizierungs-Modus + field_auth_source_ldap_filter: LDAP-Filter + field_author: Autor + field_base_dn: Base DN + field_board_parent: Übergeordnetes Forum + field_category: Kategorie + field_column_names: Spalten + field_closed_on: Geschlossen am + field_comments: Kommentar + field_comments_sorting: Kommentare anzeigen + field_commit_logs_encoding: Kodierung der Commit-Log-Meldungen + field_content: Inhalt + field_core_fields: Standardwerte + field_created_on: Angelegt + field_cvs_module: Modul + field_cvsroot: CVSROOT + field_default_value: Standardwert + field_delay: Pufferzeit + field_description: Beschreibung + field_done_ratio: "% erledigt" + field_downloads: Downloads + field_due_date: Abgabedatum + field_editable: Bearbeitbar + field_effective_date: Datum + field_estimated_hours: Geschätzter Aufwand + field_field_format: Format + field_filename: Datei + field_filesize: Größe + field_firstname: Vorname + field_fixed_version: Zielversion + field_group_by: Gruppiere Ergebnisse nach + field_hide_mail: E-Mail-Adresse nicht anzeigen + field_homepage: Projekt-Homepage + field_host: Host + field_hours: Stunden + field_identifier: Kennung + field_identity_url: OpenID-URL + field_inherit_members: Benutzer vererben + field_is_closed: Ticket geschlossen + field_is_default: Standardeinstellung + field_is_filter: Als Filter benutzen + field_is_for_all: Für alle Projekte + field_is_in_roadmap: In der Roadmap anzeigen + field_is_private: Privat + field_is_public: Öffentlich + field_is_required: Erforderlich + field_issue: Ticket + field_issue_to: Zugehöriges Ticket + field_issues_visibility: Ticket Sichtbarkeit + field_language: Sprache + field_last_login_on: Letzte Anmeldung + field_lastname: Nachname + field_login: Mitgliedsname + field_mail: E-Mail + field_mail_notification: Mailbenachrichtigung + field_max_length: Maximale Länge + field_member_of_group: Zuständigkeitsgruppe + field_min_length: Minimale Länge + field_multiple: Mehrere Werte + field_name: Name + field_new_password: Neues Kennwort + field_notes: Kommentare + field_onthefly: On-the-fly-Benutzererstellung + field_parent: Unterprojekt von + field_parent_issue: Übergeordnete Aufgabe + field_parent_title: Übergeordnete Seite + field_password: Kennwort + field_password_confirmation: Bestätigung + field_path_to_repository: Pfad zum Repository + field_port: Port + field_possible_values: Mögliche Werte + field_principal: Auftraggeber + field_priority: Priorität + field_private_notes: Privater Kommentar + field_project: Projekt + field_redirect_existing_links: Existierende Links umleiten + field_regexp: Regulärer Ausdruck + field_repository_is_default: Haupt-Repository + field_role: Rolle + field_root_directory: Wurzelverzeichnis + field_scm_path_encoding: Pfad-Kodierung + field_searchable: Durchsuchbar + field_sharing: Gemeinsame Verwendung + field_spent_on: Datum + field_start_date: Beginn + field_start_page: Hauptseite + field_status: Status + field_subject: Thema + field_subproject: Unterprojekt von + field_summary: Zusammenfassung + field_text: Textfeld + field_time_entries: Logzeit + field_time_zone: Zeitzone + field_timeout: Auszeit (in Sekunden) + field_title: Titel + field_tracker: Tracker + field_type: Typ + field_updated_on: Aktualisiert + field_url: URL + field_user: Benutzer + field_value: Wert + field_version: Version + field_visible: Sichtbar + field_warn_on_leaving_unsaved: Vor dem Verlassen einer Seite mit ungesichertem Text im Editor warnen + field_watcher: Beobachter + + general_csv_decimal_separator: ',' + general_csv_encoding: ISO-8859-1 + general_csv_separator: ';' + general_first_day_of_week: '1' + general_lang_name: 'Deutsch' + general_pdf_encoding: UTF-8 + general_text_No: 'Nein' + general_text_Yes: 'Ja' + general_text_no: 'nein' + general_text_yes: 'ja' + + label_activity: Aktivität + label_add_another_file: Eine weitere Datei hinzufügen + label_add_note: Kommentar hinzufügen + label_added: hinzugefügt + label_added_time_by: "Von %{author} vor %{age} hinzugefügt" + label_additional_workflow_transitions_for_assignee: Zusätzliche Berechtigungen wenn der Benutzer der Zugewiesene ist + label_additional_workflow_transitions_for_author: Zusätzliche Berechtigungen wenn der Benutzer der Autor ist + label_administration: Administration + label_age: Geändert vor + label_ago: vor + label_all: alle + label_all_time: gesamter Zeitraum + label_all_words: Alle Wörter + label_and_its_subprojects: "%{value} und dessen Unterprojekte" + label_any: alle + label_any_issues_in_project: irgendein Ticket im Projekt + label_any_issues_not_in_project: irgendein Ticket nicht im Projekt + label_api_access_key: API-Zugriffsschlüssel + label_api_access_key_created_on: Der API-Zugriffsschlüssel wurde vor %{value} erstellt + label_applied_status: Zugewiesener Status + label_ascending: Aufsteigend + label_assigned_to_me_issues: Mir zugewiesene Tickets + label_associated_revisions: Zugehörige Revisionen + label_attachment: Datei + label_attachment_delete: Anhang löschen + label_attachment_new: Neue Datei + label_attachment_plural: Dateien + label_attribute: Attribut + label_attribute_of_assigned_to: "%{name} des Bearbeiters" + label_attribute_of_author: "%{name} des Autors" + label_attribute_of_fixed_version: "%{name} der Zielversion" + label_attribute_of_issue: "%{name} des Tickets" + label_attribute_of_project: "%{name} des Projekts" + label_attribute_of_user: "%{name} des Benutzers" + label_attribute_plural: Attribute + label_auth_source: Authentifizierungs-Modus + label_auth_source_new: Neuer Authentifizierungs-Modus + label_auth_source_plural: Authentifizierungs-Arten + label_authentication: Authentifizierung + label_between: zwischen + label_blocked_by: Blockiert durch + label_blocks: Blockiert + label_board: Forum + label_board_locked: Gesperrt + label_board_new: Neues Forum + label_board_plural: Foren + label_board_sticky: Wichtig (immer oben) + label_boolean: Boolean + label_branch: Zweig + label_browse: Codebrowser + label_bulk_edit_selected_issues: Alle ausgewählten Tickets bearbeiten + label_bulk_edit_selected_time_entries: Ausgewählte Zeitaufwände bearbeiten + label_calendar: Kalender + label_change_plural: Änderungen + label_change_properties: Eigenschaften ändern + label_change_status: Statuswechsel + label_change_view_all: Alle Änderungen anzeigen + label_changes_details: Details aller Änderungen + label_changeset_plural: Changesets + label_child_revision: Nachfolger + label_chronological_order: in zeitlicher Reihenfolge + label_close_versions: Vollständige Versionen schließen + label_closed_issues: geschlossen + label_closed_issues_plural: geschlossen + label_comment: Kommentar + label_comment_add: Kommentar hinzufügen + label_comment_added: Kommentar hinzugefügt + label_comment_delete: Kommentar löschen + label_comment_plural: Kommentare + label_commits_per_author: Übertragungen pro Autor + label_commits_per_month: Übertragungen pro Monat + label_completed_versions: Abgeschlossene Versionen + label_confirmation: Bestätigung + label_contains: enthält + label_copied: kopiert + label_copied_from: Kopiert von + label_copied_to: Kopiert nach + label_copy_attachments: Anhänge kopieren + label_copy_same_as_target: So wie das Ziel + label_copy_source: Quelle + label_copy_subtasks: Unteraufgaben kopieren + label_copy_target: Ziel + label_copy_workflow_from: Workflow kopieren von + label_cross_project_descendants: Mit Unterprojekten + label_cross_project_hierarchy: Mit Projekthierarchie + label_cross_project_system: Mit allen Projekten + label_cross_project_tree: Mit Projektbaum + label_current_status: Gegenwärtiger Status + label_current_version: Gegenwärtige Version + label_custom_field: Benutzerdefiniertes Feld + label_custom_field_new: Neues Feld + label_custom_field_plural: Benutzerdefinierte Felder + label_date: Datum + label_date_from: Von + label_date_from_to: von %{start} bis %{end} + label_date_range: Zeitraum + label_date_to: Bis + label_day_plural: Tage + label_default: Standard + label_default_columns: Standard-Spalten + label_deleted: gelöscht + label_descending: Absteigend + label_details: Details + label_diff: diff + label_diff_inline: einspaltig + label_diff_side_by_side: nebeneinander + label_disabled: gesperrt + label_display: Anzeige + label_display_per_page: "Pro Seite: %{value}" + label_display_used_statuses_only: Zeige nur Status an, die von diesem Tracker verwendet werden + label_document: Dokument + label_document_added: Dokument hinzugefügt + label_document_new: Neues Dokument + label_document_plural: Dokumente + label_downloads_abbr: D/L + label_duplicated_by: Dupliziert durch + label_duplicates: Duplikat von + label_end_to_end: Ende - Ende + label_end_to_start: Ende - Anfang + label_enumeration_new: Neuer Wert + label_enumerations: Aufzählungen + label_environment: Umgebung + label_equals: ist + label_example: Beispiel + label_export_options: "%{export_format} Export-Eigenschaften" + label_export_to: "Auch abrufbar als:" + label_f_hour: "%{value} Stunde" + label_f_hour_plural: "%{value} Stunden" + label_feed_plural: Feeds + label_feeds_access_key: Atom-Zugriffsschlüssel + label_feeds_access_key_created_on: "Atom-Zugriffsschlüssel vor %{value} erstellt" + label_fields_permissions: Feldberechtigungen + label_file_added: Datei hinzugefügt + label_file_plural: Dateien + label_filter_add: Filter hinzufügen + label_filter_plural: Filter + label_float: Fließkommazahl + label_follows: Nachfolger von + label_gantt: Gantt-Diagramm + label_gantt_progress_line: Fortschrittslinie + label_general: Allgemein + label_generate_key: Generieren + label_git_report_last_commit: Bericht des letzten Commits für Dateien und Verzeichnisse + label_greater_or_equal: ">=" + label_group: Gruppe + label_group_new: Neue Gruppe + label_group_plural: Gruppen + label_help: Hilfe + label_history: Historie + label_home: Hauptseite + label_in: in + label_in_less_than: in weniger als + label_in_more_than: in mehr als + label_in_the_next_days: in den nächsten + label_in_the_past_days: in den letzten + label_incoming_emails: Eingehende E-Mails + label_index_by_date: Seiten nach Datum sortiert + label_index_by_title: Seiten nach Titel sortiert + label_information: Information + label_information_plural: Informationen + label_integer: Zahl + label_internal: Intern + label_issue: Ticket + label_issue_added: Ticket hinzugefügt + label_issue_category: Ticket-Kategorie + label_issue_category_new: Neue Kategorie + label_issue_category_plural: Ticket-Kategorien + label_issue_new: Neues Ticket + label_issue_note_added: Notiz hinzugefügt + label_issue_plural: Tickets + label_issue_priority_updated: Priorität aktualisiert + label_issue_status: Ticket-Status + label_issue_status_new: Neuer Status + label_issue_status_plural: Ticket-Status + label_issue_status_updated: Status aktualisiert + label_issue_tracking: Tickets + label_issue_updated: Ticket aktualisiert + label_issue_view_all: Alle Tickets anzeigen + label_issue_watchers: Beobachter + label_issues_by: "Tickets pro %{value}" + label_issues_visibility_all: Alle Tickets + label_issues_visibility_own: Tickets die folgender Benutzer erstellt hat oder die ihm zugewiesen sind + label_issues_visibility_public: Alle öffentlichen Tickets + label_item_position: "%{position}/%{count}" + label_jump_to_a_project: Zu einem Projekt springen... + label_language_based: Sprachabhängig + label_last_changes: "%{count} letzte Änderungen" + label_last_login: Letzte Anmeldung + label_last_month: voriger Monat + label_last_n_days: "die letzten %{count} Tage" + label_last_n_weeks: letzte %{count} Wochen + label_last_week: vorige Woche + label_latest_revision: Aktuellste Revision + label_latest_revision_plural: Aktuellste Revisionen + label_ldap_authentication: LDAP-Authentifizierung + label_less_or_equal: "<=" + label_less_than_ago: vor weniger als + label_list: Liste + label_loading: Lade... + label_logged_as: Angemeldet als + label_login: Anmelden + label_login_with_open_id_option: oder mit OpenID anmelden + label_logout: Abmelden + label_max_size: Maximale Größe + label_me: ich + label_member: Mitglied + label_member_new: Neues Mitglied + label_member_plural: Mitglieder + label_message_last: Letzter Forenbeitrag + label_message_new: Neues Thema + label_message_plural: Forenbeiträge + label_message_posted: Forenbeitrag hinzugefügt + label_min_max_length: Länge (Min. - Max.) + label_missing_api_access_key: Der API-Zugriffsschlüssel fehlt. + label_missing_feeds_access_key: Der Atom-Zugriffsschlüssel fehlt. + label_modified: geändert + label_module_plural: Module + label_month: Monat + label_months_from: Monate ab + label_more: Mehr + label_more_than_ago: vor mehr als + label_my_account: Mein Konto + label_my_page: Meine Seite + label_my_page_block: Verfügbare Widgets + label_my_projects: Meine Projekte + label_my_queries: Meine eigenen Abfragen + label_new: Neu + label_new_statuses_allowed: Neue Berechtigungen + label_news: News + label_news_added: News hinzugefügt + label_news_comment_added: Kommentar zu einer News hinzugefügt + label_news_latest: Letzte News + label_news_new: News hinzufügen + label_news_plural: News + label_news_view_all: Alle News anzeigen + label_next: Weiter + label_no_change_option: (Keine Änderung) + label_no_data: Nichts anzuzeigen + label_no_issues_in_project: keine Tickets im Projekt + label_nobody: Niemand + label_none: kein + label_not_contains: enthält nicht + label_not_equals: ist nicht + label_open_issues: offen + label_open_issues_plural: offen + label_optional_description: Beschreibung (optional) + label_options: Optionen + label_overall_activity: Aktivitäten aller Projekte anzeigen + label_overall_spent_time: Aufgewendete Zeit aller Projekte anzeigen + label_overview: Übersicht + label_parent_revision: Vorgänger + label_password_lost: Kennwort vergessen + label_per_page: Pro Seite + label_permissions: Berechtigungen + label_permissions_report: Berechtigungsübersicht + label_personalize_page: Diese Seite anpassen + label_planning: Terminplanung + label_please_login: Anmelden + label_plugins: Plugins + label_precedes: Vorgänger von + label_preferences: Präferenzen + label_preview: Vorschau + label_previous: Zurück + label_principal_search: "Nach Benutzer oder Gruppe suchen:" + label_profile: Profil + label_project: Projekt + label_project_all: Alle Projekte + label_project_copy_notifications: Sende Mailbenachrichtigungen beim Kopieren des Projekts. + label_project_latest: Neueste Projekte + label_project_new: Neues Projekt + label_project_plural: Projekte + label_public_projects: Öffentliche Projekte + label_query: Benutzerdefinierte Abfrage + label_query_new: Neue Abfrage + label_query_plural: Benutzerdefinierte Abfragen + label_read: Lesen... + label_readonly: Nur-Lese-Zugriff + label_register: Registrieren + label_registered_on: Angemeldet am + label_registration_activation_by_email: Kontoaktivierung durch E-Mail + label_registration_automatic_activation: Automatische Kontoaktivierung + label_registration_manual_activation: Manuelle Kontoaktivierung + label_related_issues: Zugehörige Tickets + label_relates_to: Beziehung mit + label_relation_delete: Beziehung löschen + label_relation_new: Neue Beziehung + label_renamed: umbenannt + label_reply_plural: Antworten + label_report: Bericht + label_report_plural: Berichte + label_reported_issues: Erstellte Tickets + label_repository: Projektarchiv + label_repository_new: Neues Repository + label_repository_plural: Projektarchive + label_required: Erforderlich + label_result_plural: Resultate + label_reverse_chronological_order: in umgekehrter zeitlicher Reihenfolge + label_revision: Revision + label_revision_id: Revision %{value} + label_revision_plural: Revisionen + label_roadmap: Roadmap + label_roadmap_due_in: "Fällig in %{value}" + label_roadmap_no_issues: Keine Tickets für diese Version + label_roadmap_overdue: "%{value} verspätet" + label_role: Rolle + label_role_and_permissions: Rollen und Rechte + label_role_anonymous: Anonymous + label_role_new: Neue Rolle + label_role_non_member: Nichtmitglied + label_role_plural: Rollen + label_scm: Versionskontrollsystem + label_search: Suche + label_search_for_watchers: Nach hinzufügbaren Beobachtern suchen + label_search_titles_only: Nur Titel durchsuchen + label_send_information: Sende Kontoinformationen an Benutzer + label_send_test_email: Test-E-Mail senden + label_session_expiration: Ende einer Sitzung + label_settings: Konfiguration + label_show_closed_projects: Geschlossene Projekte anzeigen + label_show_completed_versions: Abgeschlossene Versionen anzeigen + label_sort: Sortierung + label_sort_by: "Sortiert nach %{value}" + label_sort_higher: Eins höher + label_sort_highest: An den Anfang + label_sort_lower: Eins tiefer + label_sort_lowest: Ans Ende + label_spent_time: Aufgewendete Zeit + label_start_to_end: Anfang - Ende + label_start_to_start: Anfang - Anfang + label_statistics: Statistiken + label_status_transitions: Statusänderungen + label_stay_logged_in: Angemeldet bleiben + label_string: Text + label_subproject_new: Neues Unterprojekt + label_subproject_plural: Unterprojekte + label_subtask_plural: Unteraufgaben + label_tag: Markierung + label_text: Langer Text + label_theme: Stil + label_this_month: aktueller Monat + label_this_week: aktuelle Woche + label_this_year: aktuelles Jahr + label_time_entry_plural: Benötigte Zeit + label_time_tracking: Zeiterfassung + label_today: heute + label_topic_plural: Themen + label_total: Gesamtzahl + label_tracker: Tracker + label_tracker_new: Neuer Tracker + label_tracker_plural: Tracker + label_update_issue_done_ratios: Ticket-Fortschritt aktualisieren + label_updated_time: "Vor %{value} aktualisiert" + label_updated_time_by: "Von %{author} vor %{age} aktualisiert" + label_used_by: Benutzt von + label_user: Benutzer + label_user_activity: "Aktivität von %{value}" + label_user_anonymous: Anonym + label_user_mail_no_self_notified: "Ich möchte nicht über Änderungen benachrichtigt werden, die ich selbst durchführe." + label_user_mail_option_all: "Für alle Ereignisse in all meinen Projekten" + label_user_mail_option_none: Keine Ereignisse + label_user_mail_option_only_assigned: Nur für Aufgaben für die ich zuständig bin + label_user_mail_option_only_my_events: Nur für Aufgaben die ich beobachte oder an welchen ich mitarbeite + label_user_mail_option_only_owner: Nur für Aufgaben die ich angelegt habe + label_user_mail_option_selected: "Für alle Ereignisse in den ausgewählten Projekten..." + label_user_new: Neuer Benutzer + label_user_plural: Benutzer + label_user_search: "Nach Benutzer suchen:" + label_version: Version + label_version_new: Neue Version + label_version_plural: Versionen + label_version_sharing_descendants: Mit Unterprojekten + label_version_sharing_hierarchy: Mit Projekthierarchie + label_version_sharing_none: Nicht gemeinsam verwenden + label_version_sharing_system: Mit allen Projekten + label_version_sharing_tree: Mit Projektbaum + label_view_all_revisions: Alle Revisionen anzeigen + label_view_diff: Unterschiede anzeigen + label_view_revisions: Revisionen anzeigen + label_watched_issues: Beobachtete Tickets + label_week: Woche + label_wiki: Wiki + label_wiki_content_added: Wiki-Seite hinzugefügt + label_wiki_content_updated: Wiki-Seite aktualisiert + label_wiki_edit: Wiki-Bearbeitung + label_wiki_edit_plural: Wiki-Bearbeitungen + label_wiki_page: Wiki-Seite + label_wiki_page_plural: Wiki-Seiten + label_workflow: Workflow + label_x_closed_issues_abbr: + zero: 0 geschlossen + one: 1 geschlossen + other: "%{count} geschlossen" + label_x_comments: + zero: keine Kommentare + one: 1 Kommentar + other: "%{count} Kommentare" + label_x_issues: + zero: 0 Tickets + one: 1 Ticket + other: "%{count} Tickets" + label_x_open_issues_abbr: + zero: 0 offen + one: 1 offen + other: "%{count} offen" + label_x_open_issues_abbr_on_total: + zero: 0 offen / %{total} + one: 1 offen / %{total} + other: "%{count} offen / %{total}" + label_x_projects: + zero: keine Projekte + one: 1 Projekt + other: "%{count} Projekte" + label_year: Jahr + label_yesterday: gestern + + mail_body_account_activation_request: "Ein neuer Benutzer (%{value}) hat sich registriert. Sein Konto wartet auf Ihre Genehmigung:" + mail_body_account_information: Ihre Konto-Informationen + mail_body_account_information_external: "Sie können sich mit Ihrem Konto %{value} anmelden." + mail_body_lost_password: 'Benutzen Sie den folgenden Link, um Ihr Kennwort zu ändern:' + mail_body_register: 'Um Ihr Konto zu aktivieren, benutzen Sie folgenden Link:' + mail_body_reminder: "%{count} Tickets, die Ihnen zugewiesen sind, müssen in den nächsten %{days} Tagen abgegeben werden:" + mail_body_wiki_content_added: "Die Wiki-Seite '%{id}' wurde von %{author} hinzugefügt." + mail_body_wiki_content_updated: "Die Wiki-Seite '%{id}' wurde von %{author} aktualisiert." + mail_subject_account_activation_request: "Antrag auf %{value} Kontoaktivierung" + mail_subject_lost_password: "Ihr %{value} Kennwort" + mail_subject_register: "%{value} Kontoaktivierung" + mail_subject_reminder: "%{count} Tickets müssen in den nächsten %{days} Tagen abgegeben werden" + mail_subject_wiki_content_added: "Wiki-Seite '%{id}' hinzugefügt" + mail_subject_wiki_content_updated: "Wiki-Seite '%{id}' erfolgreich aktualisiert" + + notice_account_activated: Ihr Konto ist aktiviert. Sie können sich jetzt anmelden. + notice_account_deleted: Ihr Benutzerkonto wurde unwiderruflich gelöscht. + notice_account_invalid_creditentials: Benutzer oder Kennwort ist ungültig. + notice_account_lost_email_sent: Eine E-Mail mit Anweisungen, ein neues Kennwort zu wählen, wurde Ihnen geschickt. + notice_account_password_updated: Kennwort wurde erfolgreich aktualisiert. + notice_account_pending: "Ihr Konto wurde erstellt und wartet jetzt auf die Genehmigung des Administrators." + notice_account_register_done: Konto wurde erfolgreich angelegt. + notice_account_unknown_email: Unbekannter Benutzer. + notice_account_updated: Konto wurde erfolgreich aktualisiert. + notice_account_wrong_password: Falsches Kennwort. + notice_api_access_key_reseted: Ihr API-Zugriffsschlüssel wurde zurückgesetzt. + notice_can_t_change_password: Dieses Konto verwendet eine externe Authentifizierungs-Quelle. Unmöglich, das Kennwort zu ändern. + notice_default_data_loaded: Die Standard-Konfiguration wurde erfolgreich geladen. + notice_email_error: "Beim Senden einer E-Mail ist ein Fehler aufgetreten (%{value})." + notice_email_sent: "Eine E-Mail wurde an %{value} gesendet." + notice_failed_to_save_issues: "%{count} von %{total} ausgewählten Tickets konnte(n) nicht gespeichert werden: %{ids}." + notice_failed_to_save_members: "Benutzer konnte nicht gespeichert werden: %{errors}." + notice_failed_to_save_time_entries: "Gescheitert %{count} Zeiteinträge für %{total} von ausgewählten: %{ids} zu speichern." + notice_feeds_access_key_reseted: Ihr Atom-Zugriffsschlüssel wurde zurückgesetzt. + notice_file_not_found: Anhang existiert nicht oder ist gelöscht worden. + notice_gantt_chart_truncated: Die Grafik ist unvollständig, da das Maximum der anzeigbaren Aufgaben überschritten wurde (%{max}) + notice_issue_done_ratios_updated: Der Ticket-Fortschritt wurde aktualisiert. + notice_issue_successful_create: Ticket %{id} erstellt. + notice_issue_update_conflict: Das Ticket wurde von einem anderen Nutzer überarbeitet während Ihrer Bearbeitung. + notice_locking_conflict: Datum wurde von einem anderen Benutzer geändert. + notice_no_issue_selected: "Kein Ticket ausgewählt! Bitte wählen Sie die Tickets, die Sie bearbeiten möchten." + notice_not_authorized: Sie sind nicht berechtigt, auf diese Seite zuzugreifen. + notice_not_authorized_archived_project: Das Projekt wurde archiviert und ist daher nicht nicht verfügbar. + notice_successful_connection: Verbindung erfolgreich. + notice_successful_create: Erfolgreich angelegt + notice_successful_delete: Erfolgreich gelöscht. + notice_successful_update: Erfolgreich aktualisiert. + notice_unable_delete_time_entry: Der Zeiterfassungseintrag konnte nicht gelöscht werden. + notice_unable_delete_version: Die Version konnte nicht gelöscht werden. + notice_user_successful_create: Benutzer %{id} angelegt. + + permission_add_issue_notes: Kommentare hinzufügen + permission_add_issue_watchers: Beobachter hinzufügen + permission_add_issues: Tickets hinzufügen + permission_add_messages: Forenbeiträge hinzufügen + permission_add_project: Projekt erstellen + permission_add_subprojects: Unterprojekte erstellen + permission_add_documents: Dokumente hinzufügen + permission_browse_repository: Projektarchiv ansehen + permission_close_project: Schließen / erneutes Öffnen eines Projekts + permission_comment_news: News kommentieren + permission_commit_access: Commit-Zugriff + permission_delete_issue_watchers: Beobachter löschen + permission_delete_issues: Tickets löschen + permission_delete_messages: Forenbeiträge löschen + permission_delete_own_messages: Eigene Forenbeiträge löschen + permission_delete_wiki_pages: Wiki-Seiten löschen + permission_delete_wiki_pages_attachments: Anhänge löschen + permission_delete_documents: Dokumente löschen + permission_edit_issue_notes: Kommentare bearbeiten + permission_edit_issues: Tickets bearbeiten + permission_edit_messages: Forenbeiträge bearbeiten + permission_edit_own_issue_notes: Eigene Kommentare bearbeiten + permission_edit_own_messages: Eigene Forenbeiträge bearbeiten + permission_edit_own_time_entries: Selbst gebuchte Aufwände bearbeiten + permission_edit_project: Projekt bearbeiten + permission_edit_time_entries: Gebuchte Aufwände bearbeiten + permission_edit_wiki_pages: Wiki-Seiten bearbeiten + permission_edit_documents: Dokumente bearbeiten + permission_export_wiki_pages: Wiki-Seiten exportieren + permission_log_time: Aufwände buchen + permission_manage_boards: Foren verwalten + permission_manage_categories: Ticket-Kategorien verwalten + permission_manage_files: Dateien verwalten + permission_manage_issue_relations: Ticket-Beziehungen verwalten + permission_manage_members: Mitglieder verwalten + permission_manage_news: News verwalten + permission_manage_project_activities: Aktivitäten (Zeiterfassung) verwalten + permission_manage_public_queries: Öffentliche Filter verwalten + permission_manage_related_issues: Zugehörige Tickets verwalten + permission_manage_repository: Projektarchiv verwalten + permission_manage_subtasks: Unteraufgaben verwalten + permission_manage_versions: Versionen verwalten + permission_manage_wiki: Wiki verwalten + permission_move_issues: Tickets verschieben + permission_protect_wiki_pages: Wiki-Seiten schützen + permission_rename_wiki_pages: Wiki-Seiten umbenennen + permission_save_queries: Filter speichern + permission_select_project_modules: Projektmodule auswählen + permission_set_issues_private: Tickets privat oder öffentlich markieren + permission_set_notes_private: Kommentar als privat markieren + permission_set_own_issues_private: Eigene Tickets privat oder öffentlich markieren + permission_view_calendar: Kalender ansehen + permission_view_changesets: Changesets ansehen + permission_view_documents: Dokumente ansehen + permission_view_files: Dateien ansehen + permission_view_gantt: Gantt-Diagramm ansehen + permission_view_issue_watchers: Liste der Beobachter ansehen + permission_view_issues: Tickets anzeigen + permission_view_messages: Forenbeiträge ansehen + permission_view_private_notes: Private Kommentare sehen + permission_view_time_entries: Gebuchte Aufwände ansehen + permission_view_wiki_edits: Wiki-Versionsgeschichte ansehen + permission_view_wiki_pages: Wiki ansehen + + project_module_boards: Foren + project_module_calendar: Kalender + project_module_documents: Dokumente + project_module_files: Dateien + project_module_gantt: Gantt + project_module_issue_tracking: Ticket-Verfolgung + project_module_news: News + project_module_repository: Projektarchiv + project_module_time_tracking: Zeiterfassung + project_module_wiki: Wiki + project_status_active: aktiv + project_status_archived: archiviert + project_status_closed: geschlossen + + setting_activity_days_default: Anzahl Tage pro Seite der Projekt-Aktivität + setting_app_subtitle: Applikations-Untertitel + setting_app_title: Applikations-Titel + setting_attachment_max_size: Max. Dateigröße + setting_autofetch_changesets: Changesets automatisch abrufen + setting_autologin: Automatische Anmeldung + setting_bcc_recipients: E-Mails als Blindkopie (BCC) senden + setting_cache_formatted_text: Formatierten Text im Cache speichern + setting_commit_cross_project_ref: Erlauben auf Tickets aller anderen Projekte zu referenzieren + setting_commit_fix_keywords: Schlüsselwörter (Status) + setting_commit_logtime_activity_id: Aktivität für die Zeiterfassung + setting_commit_logtime_enabled: Aktiviere Zeitlogging + setting_commit_ref_keywords: Schlüsselwörter (Beziehungen) + setting_cross_project_issue_relations: Ticket-Beziehungen zwischen Projekten erlauben + setting_cross_project_subtasks: Projektübergreifende Unteraufgaben erlauben + setting_date_format: Datumsformat + setting_default_issue_start_date_to_creation_date: Aktuelles Datum als Beginn für neue Tickets verwenden + setting_default_language: Standardsprache + setting_default_notification_option: Standard Benachrichtigungsoptionen + setting_default_projects_modules: Standardmäßig aktivierte Module für neue Projekte + setting_default_projects_public: Neue Projekte sind standardmäßig öffentlich + setting_diff_max_lines_displayed: Maximale Anzahl anzuzeigender Diff-Zeilen + setting_display_subprojects_issues: Tickets von Unterprojekten im Hauptprojekt anzeigen + setting_emails_footer: E-Mail-Fußzeile + setting_emails_header: E-Mail-Kopfzeile + setting_enabled_scm: Aktivierte Versionskontrollsysteme + setting_feeds_limit: Max. Anzahl Einträge pro Atom-Feed + setting_file_max_size_displayed: Maximale Größe inline angezeigter Textdateien + setting_gantt_items_limit: Maximale Anzahl von Aufgaben die im Gantt-Chart angezeigt werden + setting_gravatar_default: Standard-Gravatar-Bild + setting_gravatar_enabled: Gravatar-Benutzerbilder benutzen + setting_host_name: Hostname + setting_issue_done_ratio: Berechne den Ticket-Fortschritt mittels + setting_issue_done_ratio_issue_field: Ticket-Feld %-erledigt + setting_issue_done_ratio_issue_status: Ticket-Status + setting_issue_group_assignment: Ticketzuweisung an Gruppen erlauben + setting_issue_list_default_columns: Standard-Spalten in der Ticket-Auflistung + setting_issues_export_limit: Max. Anzahl Tickets bei CSV/PDF-Export + setting_jsonp_enabled: JSONP Unterstützung aktivieren + setting_login_required: Authentifizierung erforderlich + setting_mail_from: E-Mail-Absender + setting_mail_handler_api_enabled: Abruf eingehender E-Mails aktivieren + setting_mail_handler_api_key: API-Schlüssel + setting_mail_handler_body_delimiters: "Schneide E-Mails nach einer dieser Zeilen ab" + setting_new_project_user_role_id: Rolle, die einem Nicht-Administrator zugeordnet wird, der ein Projekt erstellt + setting_non_working_week_days: Arbeitsfreie Tage + setting_openid: Erlaube OpenID-Anmeldung und -Registrierung + setting_password_min_length: Mindestlänge des Kennworts + setting_per_page_options: Objekte pro Seite + setting_plain_text_mail: Nur reinen Text (kein HTML) senden + setting_protocol: Protokoll + setting_repositories_encodings: Enkodierung von Anhängen und Repositories + setting_repository_log_display_limit: Maximale Anzahl anzuzeigender Revisionen in der Historie einer Datei + setting_rest_api_enabled: REST-Schnittstelle aktivieren + setting_self_registration: Anmeldung ermöglicht + setting_sequential_project_identifiers: Fortlaufende Projektkennungen generieren + setting_session_lifetime: Längste Dauer einer Sitzung + setting_session_timeout: Zeitüberschreitung bei Inaktivität + setting_start_of_week: Wochenanfang + setting_sys_api_enabled: Webservice zur Verwaltung der Projektarchive benutzen + setting_text_formatting: Textformatierung + setting_thumbnails_enabled: Vorschaubilder von Dateianhängen anzeigen + setting_thumbnails_size: Größe der Vorschaubilder (in Pixel) + setting_time_format: Zeitformat + setting_unsubscribe: Erlaubt Benutzern das eigene Benutzerkonto zu löschen + setting_user_format: Benutzer-Anzeigeformat + setting_welcome_text: Willkommenstext + setting_wiki_compression: Wiki-Historie komprimieren + setting_default_projects_tracker_ids: Standardmäßig aktivierte Tracker für neue Projekte + + status_active: aktiv + status_locked: gesperrt + status_registered: nicht aktivierte + + text_account_destroy_confirmation: Möchten Sie wirklich fortfahren?\nIhr Benutzerkonto wird für immer gelöscht und kann nicht wiederhergestellt werden. + text_are_you_sure: Sind Sie sicher? + text_assign_time_entries_to_project: Gebuchte Aufwände dem Projekt zuweisen + text_caracters_maximum: "Max. %{count} Zeichen." + text_caracters_minimum: "Muss mindestens %{count} Zeichen lang sein." + text_comma_separated: Mehrere Werte erlaubt (durch Komma getrennt). + text_custom_field_possible_values_info: 'Eine Zeile pro Wert' + text_default_administrator_account_changed: Administrator-Kennwort geändert + text_destroy_time_entries: Gebuchte Aufwände löschen + text_destroy_time_entries_question: Es wurden bereits %{hours} Stunden auf dieses Ticket gebucht. Was soll mit den Aufwänden geschehen? + text_diff_truncated: '... Dieser Diff wurde abgeschnitten, weil er die maximale Anzahl anzuzeigender Zeilen überschreitet.' + text_email_delivery_not_configured: "Der SMTP-Server ist nicht konfiguriert und Mailbenachrichtigungen sind ausgeschaltet.\nNehmen Sie die Einstellungen für Ihren SMTP-Server in config/configuration.yml vor und starten Sie die Applikation neu." + text_enumeration_category_reassign_to: 'Die Objekte stattdessen diesem Wert zuordnen:' + text_enumeration_destroy_question: "%{count} Objekt(e) sind diesem Wert zugeordnet." + text_file_repository_writable: Verzeichnis für Dateien beschreibbar + text_git_repository_note: Repository steht für sich alleine (bare) und liegt lokal (z.B. /gitrepo, c:\gitrepo) + text_issue_added: "Ticket %{id} wurde erstellt von %{author}." + text_issue_category_destroy_assignments: Kategorie-Zuordnung entfernen + text_issue_category_destroy_question: "Einige Tickets (%{count}) sind dieser Kategorie zugeodnet. Was möchten Sie tun?" + text_issue_category_reassign_to: Tickets dieser Kategorie zuordnen + text_issue_conflict_resolution_add_notes: Meine Änderungen übernehmen und alle anderen Änderungen verwerfen + text_issue_conflict_resolution_cancel: Meine Änderungen verwerfen und %{link} neu anzeigen + text_issue_conflict_resolution_overwrite: Meine Änderungen trotzdem übernehmen (vorherige Notizen bleiben erhalten aber manche können überschrieben werden) + text_issue_updated: "Ticket %{id} wurde aktualisiert von %{author}." + text_issues_destroy_confirmation: 'Sind Sie sicher, dass Sie die ausgewählten Tickets löschen möchten?' + text_issues_destroy_descendants_confirmation: Dies wird auch %{count} Unteraufgabe/n löschen. + text_issues_ref_in_commit_messages: Ticket-Beziehungen und -Status in Commit-Log-Meldungen + text_journal_added: "%{label} %{value} wurde hinzugefügt" + text_journal_changed: "%{label} wurde von %{old} zu %{new} geändert" + text_journal_changed_no_detail: "%{label} aktualisiert" + text_journal_deleted: "%{label} %{old} wurde gelöscht" + text_journal_set_to: "%{label} wurde auf %{value} gesetzt" + text_length_between: "Länge zwischen %{min} und %{max} Zeichen." + text_line_separated: Mehrere Werte sind erlaubt (eine Zeile pro Wert). + text_load_default_configuration: Standard-Konfiguration laden + text_mercurial_repository_note: Lokales repository (e.g. /hgrepo, c:\hgrepo) + text_min_max_length_info: 0 heißt keine Beschränkung + text_no_configuration_data: "Rollen, Tracker, Ticket-Status und Workflows wurden noch nicht konfiguriert.\nEs ist sehr zu empfehlen, die Standard-Konfiguration zu laden. Sobald sie geladen ist, können Sie sie abändern." + text_own_membership_delete_confirmation: "Sie sind dabei, einige oder alle Ihre Berechtigungen zu entfernen. Es ist möglich, dass Sie danach das Projekt nicht mehr ansehen oder bearbeiten dürfen.\nSind Sie sicher, dass Sie dies tun möchten?" + text_plugin_assets_writable: Verzeichnis für Plugin-Assets beschreibbar + text_project_closed: Dieses Projekt ist geschlossen und kann nicht bearbeitet werden. + text_project_destroy_confirmation: Sind Sie sicher, dass Sie das Projekt löschen wollen? + text_project_identifier_info: 'Kleinbuchstaben (a-z), Ziffern, Binde- und Unterstriche erlaubt, muss mit einem Kleinbuchstaben beginnen.
    Einmal gespeichert, kann die Kennung nicht mehr geändert werden.' + text_reassign_time_entries: 'Gebuchte Aufwände diesem Ticket zuweisen:' + text_regexp_info: z. B. ^[A-Z0-9]+$ + text_repository_identifier_info: 'Kleinbuchstaben (a-z), Ziffern, Binde- und Unterstriche erlaubt.
    Einmal gespeichert, kann die Kennung nicht mehr geändert werden.' + text_repository_usernames_mapping: "Bitte legen Sie die Zuordnung der Redmine-Benutzer zu den Benutzernamen der Commit-Log-Meldungen des Projektarchivs fest.\nBenutzer mit identischen Redmine- und Projektarchiv-Benutzernamen oder -E-Mail-Adressen werden automatisch zugeordnet." + text_rmagick_available: RMagick verfügbar (optional) + text_scm_command: Kommando + text_scm_command_not_available: SCM-Kommando ist nicht verfügbar. Bitte prüfen Sie die Einstellungen im Administrationspanel. + text_scm_command_version: Version + text_scm_config: Die SCM-Kommandos können in der in config/configuration.yml konfiguriert werden. Redmine muss anschließend neu gestartet werden. + text_scm_path_encoding_note: "Standard: UTF-8" + text_select_mail_notifications: Bitte wählen Sie die Aktionen aus, für die eine Mailbenachrichtigung gesendet werden soll. + text_select_project_modules: 'Bitte wählen Sie die Module aus, die in diesem Projekt aktiviert sein sollen:' + text_session_expiration_settings: "Achtung: Änderungen können aktuelle Sitzungen beenden, Ihre eingeschlossen!" + text_status_changed_by_changeset: "Status geändert durch Changeset %{value}." + text_subprojects_destroy_warning: "Dessen Unterprojekte (%{value}) werden ebenfalls gelöscht." + text_time_entries_destroy_confirmation: Sind Sie sicher, dass Sie die ausgewählten Zeitaufwände löschen möchten? + text_time_logged_by_changeset: Angewendet in Changeset %{value}. + text_tip_issue_begin_day: Aufgabe, die an diesem Tag beginnt + text_tip_issue_begin_end_day: Aufgabe, die an diesem Tag beginnt und endet + text_tip_issue_end_day: Aufgabe, die an diesem Tag endet + text_tracker_no_workflow: Kein Workflow für diesen Tracker definiert. + text_turning_multiple_off: Wenn Sie die Mehrfachauswahl deaktivieren, werden Felder mit Mehrfachauswahl bereinigt. + Dadurch wird sichergestellt, dass lediglich ein Wert pro Feld ausgewählt ist. + text_unallowed_characters: Nicht erlaubte Zeichen + text_user_mail_option: "Für nicht ausgewählte Projekte werden Sie nur Benachrichtigungen für Dinge erhalten, die Sie beobachten oder an denen Sie beteiligt sind (z. B. Tickets, deren Autor Sie sind oder die Ihnen zugewiesen sind)." + text_user_wrote: "%{value} schrieb:" + text_warn_on_leaving_unsaved: Die aktuellen Änderungen gehen verloren, wenn Sie diese Seite verlassen. + text_wiki_destroy_confirmation: Sind Sie sicher, dass Sie dieses Wiki mit sämtlichem Inhalt löschen möchten? + text_wiki_page_destroy_children: Lösche alle Unterseiten + text_wiki_page_destroy_question: "Diese Seite hat %{descendants} Unterseite(n). Was möchten Sie tun?" + text_wiki_page_nullify_children: Verschiebe die Unterseiten auf die oberste Ebene + text_wiki_page_reassign_children: Ordne die Unterseiten dieser Seite zu + text_workflow_edit: Workflow zum Bearbeiten auswählen + text_zoom_in: Ansicht vergrößern + text_zoom_out: Ansicht verkleinern + + version_status_closed: abgeschlossen + version_status_locked: gesperrt + version_status_open: offen + + warning_attachments_not_saved: "%{count} Datei(en) konnten nicht gespeichert werden." + label_total_time: Gesamtzeit diff --git a/config/locales/el.yml b/config/locales/el.yml new file mode 100644 index 00000000..ba00cae2 --- /dev/null +++ b/config/locales/el.yml @@ -0,0 +1,1089 @@ +# Greek translations for Ruby on Rails +# by Vaggelis Typaldos (vtypal@gmail.com), Spyros Raptis (spirosrap@gmail.com) + +el: + direction: ltr + date: + formats: + # Use the strftime parameters for formats. + # When no format has been given, it uses default. + # You can provide other formats here if you like! + default: "%m/%d/%Y" + short: "%b %d" + long: "%B %d, %Y" + + day_names: [Κυριακή, Δευτέρα, Τρίτη, Τετάρτη, Πέμπτη, Παρασκευή, Σάββατο] + abbr_day_names: [Κυρ, Δευ, Τρι, Τετ, Πεμ, Παρ, Σαβ] + + # Don't forget the nil at the beginning; there's no such thing as a 0th month + month_names: [~, Ιανουάριος, Φεβρουάριος, Μάρτιος, Απρίλιος, Μάϊος, Ιούνιος, Ιούλιος, Αύγουστος, Σεπτέμβριος, Οκτώβριος, Νοέμβριος, Δεκέμβριος] + abbr_month_names: [~, Ιαν, Φεβ, Μαρ, Απρ, Μαϊ, Ιον, Ιολ, Αυγ, Σεπ, Οκτ, Νοε, Δεκ] + # Used in date_select and datime_select. + order: + - :year + - :month + - :day + + time: + formats: + default: "%m/%d/%Y %I:%M %p" + time: "%I:%M %p" + short: "%d %b %H:%M" + long: "%B %d, %Y %H:%M" + am: "πμ" + pm: "μμ" + + datetime: + distance_in_words: + half_a_minute: "μισό λεπτό" + less_than_x_seconds: + one: "λιγότερο από 1 δευτερόλεπτο" + other: "λιγότερο από %{count} δευτερόλεπτα" + x_seconds: + one: "1 δευτερόλεπτο" + other: "%{count} δευτερόλεπτα" + less_than_x_minutes: + one: "λιγότερο από ένα λεπτό" + other: "λιγότερο από %{count} λεπτά" + x_minutes: + one: "1 λεπτό" + other: "%{count} λεπτά" + about_x_hours: + one: "περίπου 1 ώρα" + other: "περίπου %{count} ώρες" + x_hours: + one: "1 hour" + other: "%{count} hours" + x_days: + one: "1 ημέρα" + other: "%{count} ημέρες" + about_x_months: + one: "περίπου 1 μήνα" + other: "περίπου %{count} μήνες" + x_months: + one: "1 μήνα" + other: "%{count} μήνες" + about_x_years: + one: "περίπου 1 χρόνο" + other: "περίπου %{count} χρόνια" + over_x_years: + one: "πάνω από 1 χρόνο" + other: "πάνω από %{count} χρόνια" + almost_x_years: + one: "almost 1 year" + other: "almost %{count} years" + + number: + format: + separator: "." + delimiter: "" + precision: 3 + human: + format: + precision: 3 + delimiter: "" + storage_units: + format: "%n %u" + units: + kb: KB + tb: TB + gb: GB + byte: + one: Byte + other: Bytes + mb: MB + +# Used in array.to_sentence. + support: + array: + sentence_connector: "and" + skip_last_comma: false + + activerecord: + errors: + template: + header: + one: "1 error prohibited this %{model} from being saved" + other: "%{count} errors prohibited this %{model} from being saved" + messages: + inclusion: "δεν περιέχεται στη λίστα" + exclusion: "έχει κατοχυρωθεί" + invalid: "είναι άκυρο" + confirmation: "δεν αντιστοιχεί με την επιβεβαίωση" + accepted: "πρέπει να γίνει αποδοχή" + empty: "δε μπορεί να είναι άδειο" + blank: "δε μπορεί να είναι κενό" + too_long: "έχει πολλούς (μέγ.επιτρ. %{count} χαρακτήρες)" + too_short: "έχει λίγους (ελάχ.επιτρ. %{count} χαρακτήρες)" + wrong_length: "δεν είναι σωστός ο αριθμός χαρακτήρων (πρέπει να έχει %{count} χαρακτήρες)" + taken: "έχει ήδη κατοχυρωθεί" + not_a_number: "δεν είναι αριθμός" + not_a_date: "δεν είναι σωστή ημερομηνία" + greater_than: "πρέπει να είναι μεγαλύτερο από %{count}" + greater_than_or_equal_to: "πρέπει να είναι μεγαλύτερο από ή ίσο με %{count}" + equal_to: "πρέπει να είναι ίσον με %{count}" + less_than: "πρέπει να είναι μικρότερη από %{count}" + less_than_or_equal_to: "πρέπει να είναι μικρότερο από ή ίσο με %{count}" + odd: "πρέπει να είναι μονός" + even: "πρέπει να είναι ζυγός" + greater_than_start_date: "πρέπει να είναι αργότερα από την ημερομηνία έναρξης" + not_same_project: "δεν ανήκει στο ίδιο έργο" + circular_dependency: "Αυτή η σχέση θα δημιουργήσει κυκλικές εξαρτήσεις" + cant_link_an_issue_with_a_descendant: "An issue can not be linked to one of its subtasks" + + actionview_instancetag_blank_option: Παρακαλώ επιλέξτε + + general_text_No: 'Όχι' + general_text_Yes: 'Ναι' + general_text_no: 'όχι' + general_text_yes: 'ναι' + general_lang_name: 'Greek (Ελληνικά)' + general_csv_separator: ',' + general_csv_decimal_separator: '.' + general_csv_encoding: UTF-8 + general_pdf_encoding: UTF-8 + general_first_day_of_week: '7' + + notice_account_updated: Ο λογαριασμός ενημερώθηκε επιτυχώς. + notice_account_invalid_creditentials: Άκυρο όνομα χρήστη ή κωδικού πρόσβασης + notice_account_password_updated: Ο κωδικός πρόσβασης ενημερώθηκε επιτυχώς. + notice_account_wrong_password: Λάθος κωδικός πρόσβασης + notice_account_register_done: Ο λογαριασμός δημιουργήθηκε επιτυχώς. Για να ενεργοποιήσετε το λογαριασμό σας, πατήστε το σύνδεσμο που σας έχει αποσταλεί με email. + notice_account_unknown_email: Άγνωστος χρήστης. + notice_can_t_change_password: Αυτός ο λογαριασμός χρησιμοποιεί εξωτερική πηγή πιστοποίησης. Δεν είναι δυνατόν να αλλάξετε τον κωδικό πρόσβασης. + notice_account_lost_email_sent: Σας έχει αποσταλεί email με οδηγίες για την επιλογή νέου κωδικού πρόσβασης. + notice_account_activated: Ο λογαριασμός σας έχει ενεργοποιηθεί. Τώρα μπορείτε να συνδεθείτε. + notice_successful_create: Επιτυχής δημιουργία. + notice_successful_update: Επιτυχής ενημέρωση. + notice_successful_delete: Επιτυχής διαγραφή. + notice_successful_connection: Επιτυχής σύνδεση. + notice_file_not_found: Η σελίδα που ζητήσατε δεν υπάρχει ή έχει αφαιρεθεί. + notice_locking_conflict: Τα δεδομένα έχουν ενημερωθεί από άλλο χρήστη. + notice_not_authorized: Δεν έχετε δικαίωμα πρόσβασης σε αυτή τη σελίδα. + notice_email_sent: "Ένα μήνυμα ηλεκτρονικού ταχυδρομείου εστάλη στο %{value}" + notice_email_error: "Σφάλμα κατά την αποστολή του μηνύματος στο (%{value})" + notice_feeds_access_key_reseted: Έγινε επαναφορά στο κλειδί πρόσβασης RSS. + notice_failed_to_save_issues: "Αποτυχία αποθήκευσης %{count} θεμα(των) από τα %{total} επιλεγμένα: %{ids}." + notice_no_issue_selected: "Κανένα θέμα δεν είναι επιλεγμένο! Παρακαλούμε, ελέγξτε τα θέματα που θέλετε να επεξεργαστείτε." + notice_account_pending: "Ο λογαριασμός σας έχει δημιουργηθεί και είναι σε στάδιο έγκρισης από τον διαχειριστή." + notice_default_data_loaded: Οι προεπιλεγμένες ρυθμίσεις φορτώθηκαν επιτυχώς. + notice_unable_delete_version: Αδύνατον να διαγραφεί η έκδοση. + + error_can_t_load_default_data: "Οι προεπιλεγμένες ρυθμίσεις δεν μπόρεσαν να φορτωθούν:: %{value}" + error_scm_not_found: "Η εγγραφή ή η αναθεώρηση δεν βρέθηκε στο αποθετήριο." + error_scm_command_failed: "Παρουσιάστηκε σφάλμα κατά την προσπάθεια πρόσβασης στο αποθετήριο: %{value}" + error_scm_annotate: "Η καταχώριση δεν υπάρχει ή δεν μπορεί να σχολιαστεί." + error_issue_not_found_in_project: 'Το θέμα δεν βρέθηκε ή δεν ανήκει σε αυτό το έργο' + error_no_tracker_in_project: 'Δεν υπάρχει ανιχνευτής για αυτό το έργο. Παρακαλώ ελέγξτε τις ρυθμίσεις του έργου.' + error_no_default_issue_status: 'Δεν έχει οριστεί η προεπιλογή κατάστασης θεμάτων. Παρακαλώ ελέγξτε τις ρυθμίσεις σας (Μεταβείτε στην "Διαχείριση -> Κατάσταση θεμάτων").' + + warning_attachments_not_saved: "%{count} αρχείο(α) δε μπορούν να αποθηκευτούν." + + mail_subject_lost_password: "Ο κωδικός σας %{value}" + mail_body_lost_password: 'Για να αλλάξετε τον κωδικό πρόσβασης, πατήστε τον ακόλουθο σύνδεσμο:' + mail_subject_register: "Ενεργοποίηση του λογαριασμού χρήστη %{value} " + mail_body_register: 'Για να ενεργοποιήσετε το λογαριασμό σας, επιλέξτε τον ακόλουθο σύνδεσμο:' + mail_body_account_information_external: "Μπορείτε να χρησιμοποιήσετε τον λογαριασμό %{value} για να συνδεθείτε." + mail_body_account_information: Πληροφορίες του λογαριασμού σας + mail_subject_account_activation_request: "αίτημα ενεργοποίησης λογαριασμού %{value}" + mail_body_account_activation_request: "'Ένας νέος χρήστης (%{value}) έχει εγγραφεί. Ο λογαριασμός είναι σε στάδιο αναμονής της έγκρισης σας:" + mail_subject_reminder: "%{count} θέμα(τα) με προθεσμία στις επόμενες %{days} ημέρες" + mail_body_reminder: "%{count}θέμα(τα) που έχουν ανατεθεί σε σας, με προθεσμία στις επόμενες %{days} ημέρες:" + mail_subject_wiki_content_added: "'προστέθηκε η σελίδα wiki %{id}' " + mail_body_wiki_content_added: "Η σελίδα wiki '%{id}' προστέθηκε από τον %{author}." + mail_subject_wiki_content_updated: "'ενημερώθηκε η σελίδα wiki %{id}' " + mail_body_wiki_content_updated: "Η σελίδα wiki '%{id}' ενημερώθηκε από τον %{author}." + + + field_name: Όνομα + field_description: Περιγραφή + field_summary: Συνοπτικά + field_is_required: Απαιτείται + field_firstname: Όνομα + field_lastname: Επώνυμο + field_mail: Email + field_filename: Αρχείο + field_filesize: Μέγεθος + field_downloads: Μεταφορτώσεις + field_author: Συγγραφέας + field_created_on: Δημιουργήθηκε + field_updated_on: Ενημερώθηκε + field_field_format: Μορφοποίηση + field_is_for_all: Για όλα τα έργα + field_possible_values: Πιθανές τιμές + field_regexp: Κανονική παράσταση + field_min_length: Ελάχιστο μήκος + field_max_length: Μέγιστο μήκος + field_value: Τιμή + field_category: Κατηγορία + field_title: Τίτλος + field_project: Έργο + field_issue: Θέμα + field_status: Κατάσταση + field_notes: Σημειώσεις + field_is_closed: Κλειστά θέματα + field_is_default: Προεπιλεγμένη τιμή + field_tracker: Ανιχνευτής + field_subject: Θέμα + field_due_date: Προθεσμία + field_assigned_to: Ανάθεση σε + field_priority: Προτεραιότητα + field_fixed_version: Στόχος έκδοσης + field_user: Χρήστης + field_role: Ρόλος + field_homepage: Αρχική σελίδα + field_is_public: Δημόσιο + field_parent: Επιμέρους έργο του + field_is_in_roadmap: Προβολή θεμάτων στο χάρτη πορείας + field_login: Όνομα χρήστη + field_mail_notification: Ειδοποιήσεις email + field_admin: Διαχειριστής + field_last_login_on: Τελευταία σύνδεση + field_language: Γλώσσα + field_effective_date: Ημερομηνία + field_password: Κωδικός πρόσβασης + field_new_password: Νέος κωδικός πρόσβασης + field_password_confirmation: Επιβεβαίωση + field_version: Έκδοση + field_type: Τύπος + field_host: Κόμβος + field_port: Θύρα + field_account: Λογαριασμός + field_base_dn: Βάση DN + field_attr_login: Ιδιότητα εισόδου + field_attr_firstname: Ιδιότητα ονόματος + field_attr_lastname: Ιδιότητα επωνύμου + field_attr_mail: Ιδιότητα email + field_onthefly: Άμεση δημιουργία χρήστη + field_start_date: Εκκίνηση + field_done_ratio: "% επιτεύχθη" + field_auth_source: Τρόπος πιστοποίησης + field_hide_mail: Απόκρυψη διεύθυνσης email + field_comments: Σχόλιο + field_url: URL + field_start_page: Πρώτη σελίδα + field_subproject: Επιμέρους έργο + field_hours: Ώρες + field_activity: Δραστηριότητα + field_spent_on: Ημερομηνία + field_identifier: Στοιχείο αναγνώρισης + field_is_filter: Χρήση ως φίλτρο + field_issue_to: Σχετικά θέματα + field_delay: Καθυστέρηση + field_assignable: Θέματα που μπορούν να ανατεθούν σε αυτό το ρόλο + field_redirect_existing_links: Ανακατεύθυνση των τρεχόντων συνδέσμων + field_estimated_hours: Εκτιμώμενος χρόνος + field_column_names: Στήλες + field_time_zone: Ωριαία ζώνη + field_searchable: Ερευνήσιμο + field_default_value: Προκαθορισμένη τιμή + field_comments_sorting: Προβολή σχολίων + field_parent_title: Γονική σελίδα + field_editable: Επεξεργάσιμο + field_watcher: Παρατηρητής + field_identity_url: OpenID URL + field_content: Περιεχόμενο + field_group_by: Ομαδικά αποτελέσματα από + + setting_app_title: Τίτλος εφαρμογής + setting_app_subtitle: Υπότιτλος εφαρμογής + setting_welcome_text: Κείμενο υποδοχής + setting_default_language: Προεπιλεγμένη γλώσσα + setting_login_required: Απαιτείται πιστοποίηση + setting_self_registration: Αυτο-εγγραφή + setting_attachment_max_size: Μέγ. μέγεθος συνημμένου + setting_issues_export_limit: Θέματα περιορισμού εξαγωγής + setting_mail_from: Μετάδοση διεύθυνσης email + setting_bcc_recipients: Αποδέκτες κρυφής κοινοποίησης (bcc) + setting_plain_text_mail: Email απλού κειμένου (όχι HTML) + setting_host_name: Όνομα κόμβου και διαδρομή + setting_text_formatting: Μορφοποίηση κειμένου + setting_wiki_compression: Συμπίεση ιστορικού wiki + setting_feeds_limit: Feed περιορισμού περιεχομένου + setting_default_projects_public: Τα νέα έργα έχουν προεπιλεγεί ως δημόσια + setting_autofetch_changesets: Αυτόματη λήψη commits + setting_sys_api_enabled: Ενεργοποίηση WS για διαχείριση αποθετηρίου + setting_commit_ref_keywords: Αναφορά σε λέξεις-κλειδιά + setting_commit_fix_keywords: Καθορισμός σε λέξεις-κλειδιά + setting_autologin: Αυτόματη σύνδεση + setting_date_format: Μορφή ημερομηνίας + setting_time_format: Μορφή ώρας + setting_cross_project_issue_relations: Επιτρέψτε συσχετισμό θεμάτων σε διασταύρωση-έργων + setting_issue_list_default_columns: Προκαθορισμένες εμφανιζόμενες στήλες στη λίστα θεμάτων + setting_emails_footer: Υποσέλιδο στα email + setting_protocol: Πρωτόκολο + setting_per_page_options: Αντικείμενα ανά σελίδα επιλογών + setting_user_format: Μορφή εμφάνισης χρηστών + setting_activity_days_default: Ημέρες που εμφανίζεται στη δραστηριότητα έργου + setting_display_subprojects_issues: Εμφάνιση από προεπιλογή θεμάτων επιμέρους έργων στα κύρια έργα + setting_enabled_scm: Ενεργοποίηση SCM + setting_mail_handler_api_enabled: Ενεργοποίηση WS για εισερχόμενα email + setting_mail_handler_api_key: κλειδί API + setting_sequential_project_identifiers: Δημιουργία διαδοχικών αναγνωριστικών έργου + setting_gravatar_enabled: Χρήση Gravatar εικονιδίων χρηστών + setting_diff_max_lines_displayed: Μεγ.αριθμός εμφάνισης γραμμών diff + setting_file_max_size_displayed: Μεγ.μέγεθος των αρχείων απλού κειμένου που εμφανίζονται σε σειρά + setting_repository_log_display_limit: Μέγιστος αριθμός αναθεωρήσεων που εμφανίζονται στο ιστορικό αρχείου + setting_openid: Επιτρέψτε συνδέσεις OpenID και εγγραφή + setting_password_min_length: Ελάχιστο μήκος κωδικού πρόσβασης + setting_new_project_user_role_id: Απόδοση ρόλου σε χρήστη μη-διαχειριστή όταν δημιουργεί ένα έργο + + permission_add_project: Δημιουργία έργου + permission_edit_project: Επεξεργασία έργου + permission_select_project_modules: Επιλογή μονάδων έργου + permission_manage_members: Διαχείριση μελών + permission_manage_versions: Διαχείριση εκδόσεων + permission_manage_categories: Διαχείριση κατηγοριών θεμάτων + permission_add_issues: Προσθήκη θεμάτων + permission_edit_issues: Επεξεργασία θεμάτων + permission_manage_issue_relations: Διαχείριση συσχετισμών θεμάτων + permission_add_issue_notes: Προσθήκη σημειώσεων + permission_edit_issue_notes: Επεξεργασία σημειώσεων + permission_edit_own_issue_notes: Επεξεργασία δικών μου σημειώσεων + permission_move_issues: Μεταφορά θεμάτων + permission_delete_issues: Διαγραφή θεμάτων + permission_manage_public_queries: Διαχείριση δημόσιων αναζητήσεων + permission_save_queries: Αποθήκευση αναζητήσεων + permission_view_gantt: Προβολή διαγράμματος gantt + permission_view_calendar: Προβολή ημερολογίου + permission_view_issue_watchers: Προβολή λίστας παρατηρητών + permission_add_issue_watchers: Προσθήκη παρατηρητών + permission_log_time: Ιστορικό χρόνου που δαπανήθηκε + permission_view_time_entries: Προβολή χρόνου που δαπανήθηκε + permission_edit_time_entries: Επεξεργασία ιστορικού χρόνου + permission_edit_own_time_entries: Επεξεργασία δικού μου ιστορικού χρόνου + permission_manage_news: Διαχείριση νέων + permission_comment_news: Σχολιασμός νέων + permission_view_documents: Προβολή εγγράφων + permission_manage_files: Διαχείριση αρχείων + permission_view_files: Προβολή αρχείων + permission_manage_wiki: Διαχείριση wiki + permission_rename_wiki_pages: Μετονομασία σελίδων wiki + permission_delete_wiki_pages: Διαγραφή σελίδων wiki + permission_view_wiki_pages: Προβολή wiki + permission_view_wiki_edits: Προβολή ιστορικού wiki + permission_edit_wiki_pages: Επεξεργασία σελίδων wiki + permission_delete_wiki_pages_attachments: Διαγραφή συνημμένων + permission_protect_wiki_pages: Προστασία σελίδων wiki + permission_manage_repository: Διαχείριση αποθετηρίου + permission_browse_repository: Διαχείριση εγγράφων + permission_view_changesets: Προβολή changesets + permission_commit_access: Πρόσβαση commit + permission_manage_boards: Διαχείριση πινάκων συζητήσεων + permission_view_messages: Προβολή μηνυμάτων + permission_add_messages: Αποστολή μηνυμάτων + permission_edit_messages: Επεξεργασία μηνυμάτων + permission_edit_own_messages: Επεξεργασία δικών μου μηνυμάτων + permission_delete_messages: Διαγραφή μηνυμάτων + permission_delete_own_messages: Διαγραφή δικών μου μηνυμάτων + + project_module_issue_tracking: Ανίχνευση θεμάτων + project_module_time_tracking: Ανίχνευση χρόνου + project_module_news: Νέα + project_module_documents: Έγγραφα + project_module_files: Αρχεία + project_module_wiki: Wiki + project_module_repository: Αποθετήριο + project_module_boards: Πίνακες συζητήσεων + + label_user: Χρήστης + label_user_plural: Χρήστες + label_user_new: Νέος Χρήστης + label_project: Έργο + label_project_new: Νέο έργο + label_project_plural: Έργα + label_x_projects: + zero: κανένα έργο + one: 1 έργο + other: "%{count} έργα" + label_project_all: Όλα τα έργα + label_project_latest: Τελευταία έργα + label_issue: Θέμα + label_issue_new: Νέο θέμα + label_issue_plural: Θέματα + label_issue_view_all: Προβολή όλων των θεμάτων + label_issues_by: "Θέματα του %{value}" + label_issue_added: Το θέμα προστέθηκε + label_issue_updated: Το θέμα ενημερώθηκε + label_document: Έγγραφο + label_document_new: Νέο έγγραφο + label_document_plural: Έγγραφα + label_document_added: Έγγραφο προστέθηκε + label_role: Ρόλος + label_role_plural: Ρόλοι + label_role_new: Νέος ρόλος + label_role_and_permissions: Ρόλοι και άδειες + label_member: Μέλος + label_member_new: Νέο μέλος + label_member_plural: Μέλη + label_tracker: Ανιχνευτής + label_tracker_plural: Ανιχνευτές + label_tracker_new: Νέος Ανιχνευτής + label_workflow: Ροή εργασίας + label_issue_status: Κατάσταση θέματος + label_issue_status_plural: Κατάσταση θέματος + label_issue_status_new: Νέα κατάσταση + label_issue_category: Κατηγορία θέματος + label_issue_category_plural: Κατηγορίες θεμάτων + label_issue_category_new: Νέα κατηγορία + label_custom_field: Προσαρμοσμένο πεδίο + label_custom_field_plural: Προσαρμοσμένα πεδία + label_custom_field_new: Νέο προσαρμοσμένο πεδίο + label_enumerations: Απαριθμήσεις + label_enumeration_new: Νέα τιμή + label_information: Πληροφορία + label_information_plural: Πληροφορίες + label_please_login: Παρακαλώ συνδεθείτε + label_register: Εγγραφή + label_login_with_open_id_option: ή συνδεθείτε με OpenID + label_password_lost: Ανάκτηση κωδικού πρόσβασης + label_home: Αρχική σελίδα + label_my_page: Η σελίδα μου + label_my_account: Ο λογαριασμός μου + label_my_projects: Τα έργα μου + label_administration: Διαχείριση + label_login: Σύνδεση + label_logout: Αποσύνδεση + label_help: Βοήθεια + label_reported_issues: Εισηγμένα θέματα + label_assigned_to_me_issues: Θέματα που έχουν ανατεθεί σε μένα + label_last_login: Τελευταία σύνδεση + label_registered_on: Εγγράφηκε την + label_activity: Δραστηριότητα + label_overall_activity: Συνολική δραστηριότητα + label_user_activity: "δραστηριότητα του %{value}" + label_new: Νέο + label_logged_as: Σύνδεδεμένος ως + label_environment: Περιβάλλον + label_authentication: Πιστοποίηση + label_auth_source: Τρόπος πιστοποίησης + label_auth_source_new: Νέος τρόπος πιστοποίησης + label_auth_source_plural: Τρόποι πιστοποίησης + label_subproject_plural: Επιμέρους έργα + label_and_its_subprojects: "%{value} και τα επιμέρους έργα του" + label_min_max_length: Ελάχ. - Μέγ. μήκος + label_list: Λίστα + label_date: Ημερομηνία + label_integer: Ακέραιος + label_float: Αριθμός κινητής υποδιαστολής + label_boolean: Λογικός + label_string: Κείμενο + label_text: Μακροσκελές κείμενο + label_attribute: Ιδιότητα + label_attribute_plural: Ιδιότητες + label_no_data: Δεν υπάρχουν δεδομένα + label_change_status: Αλλαγή κατάστασης + label_history: Ιστορικό + label_attachment: Αρχείο + label_attachment_new: Νέο αρχείο + label_attachment_delete: Διαγραφή αρχείου + label_attachment_plural: Αρχεία + label_file_added: Το αρχείο προστέθηκε + label_report: Αναφορά + label_report_plural: Αναφορές + label_news: Νέα + label_news_new: Προσθήκη νέων + label_news_plural: Νέα + label_news_latest: Τελευταία νέα + label_news_view_all: Προβολή όλων των νέων + label_news_added: Τα νέα προστέθηκαν + label_settings: Ρυθμίσεις + label_overview: Επισκόπηση + label_version: Έκδοση + label_version_new: Νέα έκδοση + label_version_plural: Εκδόσεις + label_confirmation: Επιβεβαίωση + label_export_to: 'Επίσης διαθέσιμο σε:' + label_read: Διάβασε... + label_public_projects: Δημόσια έργα + label_open_issues: Ανοικτό + label_open_issues_plural: Ανοικτά + label_closed_issues: Κλειστό + label_closed_issues_plural: Κλειστά + label_x_open_issues_abbr_on_total: + zero: 0 ανοικτά / %{total} + one: 1 ανοικτό / %{total} + other: "%{count} ανοικτά / %{total}" + label_x_open_issues_abbr: + zero: 0 ανοικτά + one: 1 ανοικτό + other: "%{count} ανοικτά" + label_x_closed_issues_abbr: + zero: 0 κλειστά + one: 1 κλειστό + other: "%{count} κλειστά" + label_total: Σύνολο + label_permissions: Άδειες + label_current_status: Τρέχουσα κατάσταση + label_new_statuses_allowed: Νέες καταστάσεις επιτρέπονται + label_all: όλα + label_none: κανένα + label_nobody: κανείς + label_next: Επόμενο + label_previous: Προηγούμενο + label_used_by: Χρησιμοποιήθηκε από + label_details: Λεπτομέρειες + label_add_note: Προσθήκη σημείωσης + label_per_page: Ανά σελίδα + label_calendar: Ημερολόγιο + label_months_from: μηνών από + label_gantt: Gantt + label_internal: Εσωτερικό + label_last_changes: "Τελευταίες %{count} αλλαγές" + label_change_view_all: Προβολή όλων των αλλαγών + label_personalize_page: Προσαρμογή σελίδας + label_comment: Σχόλιο + label_comment_plural: Σχόλια + label_x_comments: + zero: δεν υπάρχουν σχόλια + one: 1 σχόλιο + other: "%{count} σχόλια" + label_comment_add: Προσθήκη σχολίου + label_comment_added: Τα σχόλια προστέθηκαν + label_comment_delete: Διαγραφή σχολίων + label_query: Προσαρμοσμένη αναζήτηση + label_query_plural: Προσαρμοσμένες αναζητήσεις + label_query_new: Νέα αναζήτηση + label_filter_add: Προσθήκη φίλτρου + label_filter_plural: Φίλτρα + label_equals: είναι + label_not_equals: δεν είναι + label_in_less_than: μικρότερο από + label_in_more_than: περισσότερο από + label_greater_or_equal: '>=' + label_less_or_equal: '<=' + label_in: σε + label_today: σήμερα + label_all_time: συνέχεια + label_yesterday: χθες + label_this_week: αυτή την εβδομάδα + label_last_week: την προηγούμενη εβδομάδα + label_last_n_days: "τελευταίες %{count} μέρες" + label_this_month: αυτό το μήνα + label_last_month: τον προηγούμενο μήνα + label_this_year: αυτό το χρόνο + label_date_range: Χρονικό διάστημα + label_less_than_ago: σε λιγότερο από ημέρες πριν + label_more_than_ago: σε περισσότερο από ημέρες πριν + label_ago: ημέρες πριν + label_contains: περιέχει + label_not_contains: δεν περιέχει + label_day_plural: μέρες + label_repository: Αποθετήριο + label_repository_plural: Αποθετήρια + label_browse: Πλοήγηση + label_branch: Branch + label_tag: Tag + label_revision: Αναθεώρηση + label_revision_plural: Αναθεωρήσεις + label_associated_revisions: Συνεταιρικές αναθεωρήσεις + label_added: προστέθηκε + label_modified: τροποποιήθηκε + label_copied: αντιγράφηκε + label_renamed: μετονομάστηκε + label_deleted: διαγράφηκε + label_latest_revision: Τελευταία αναθεώριση + label_latest_revision_plural: Τελευταίες αναθεωρήσεις + label_view_revisions: Προβολή αναθεωρήσεων + label_view_all_revisions: Προβολή όλων των αναθεωρήσεων + label_max_size: Μέγιστο μέγεθος + label_sort_highest: Μετακίνηση στην κορυφή + label_sort_higher: Μετακίνηση προς τα πάνω + label_sort_lower: Μετακίνηση προς τα κάτω + label_sort_lowest: Μετακίνηση στο κατώτατο μέρος + label_roadmap: Χάρτης πορείας + label_roadmap_due_in: "Προθεσμία σε %{value}" + label_roadmap_overdue: "%{value} καθυστερημένο" + label_roadmap_no_issues: Δεν υπάρχουν θέματα για αυτή την έκδοση + label_search: Αναζήτηση + label_result_plural: Αποτελέσματα + label_all_words: Όλες οι λέξεις + label_wiki: Wiki + label_wiki_edit: Επεξεργασία wiki + label_wiki_edit_plural: Επεξεργασία wiki + label_wiki_page: Σελίδα Wiki + label_wiki_page_plural: Σελίδες Wiki + label_index_by_title: Δείκτης ανά τίτλο + label_index_by_date: Δείκτης ανά ημερομηνία + label_current_version: Τρέχουσα έκδοση + label_preview: Προεπισκόπηση + label_feed_plural: Feeds + label_changes_details: Λεπτομέρειες όλων των αλλαγών + label_issue_tracking: Ανίχνευση θεμάτων + label_spent_time: Δαπανημένος χρόνος + label_f_hour: "%{value} ώρα" + label_f_hour_plural: "%{value} ώρες" + label_time_tracking: Ανίχνευση χρόνου + label_change_plural: Αλλαγές + label_statistics: Στατιστικά + label_commits_per_month: Commits ανά μήνα + label_commits_per_author: Commits ανά συγγραφέα + label_view_diff: Προβολή διαφορών + label_diff_inline: σε σειρά + label_diff_side_by_side: αντικρυστά + label_options: Επιλογές + label_copy_workflow_from: Αντιγραφή ροής εργασίας από + label_permissions_report: Συνοπτικός πίνακας αδειών + label_watched_issues: Θέματα υπό παρακολούθηση + label_related_issues: Σχετικά θέματα + label_applied_status: Εφαρμογή κατάστασης + label_loading: Φορτώνεται... + label_relation_new: Νέα συσχέτιση + label_relation_delete: Διαγραφή συσχέτισης + label_relates_to: σχετικό με + label_duplicates: αντίγραφα + label_duplicated_by: αντιγράφηκε από + label_blocks: φραγές + label_blocked_by: φραγή από τον + label_precedes: προηγείται + label_follows: ακολουθεί + label_end_to_start: από το τέλος στην αρχή + label_end_to_end: από το τέλος στο τέλος + label_start_to_start: από την αρχή στην αρχή + label_start_to_end: από την αρχή στο τέλος + label_stay_logged_in: Παραμονή σύνδεσης + label_disabled: απενεργοποιημένη + label_show_completed_versions: Προβολή ολοκληρωμένων εκδόσεων + label_me: εγώ + label_board: Φόρουμ + label_board_new: Νέο φόρουμ + label_board_plural: Φόρουμ + label_topic_plural: Θέματα + label_message_plural: Μηνύματα + label_message_last: Τελευταίο μήνυμα + label_message_new: Νέο μήνυμα + label_message_posted: Το μήνυμα προστέθηκε + label_reply_plural: Απαντήσεις + label_send_information: Αποστολή πληροφοριών λογαριασμού στο χρήστη + label_year: Έτος + label_month: Μήνας + label_week: Εβδομάδα + label_date_from: Από + label_date_to: Έως + label_language_based: Με βάση τη γλώσσα του χρήστη + label_sort_by: "Ταξινόμηση ανά %{value}" + label_send_test_email: Αποστολή δοκιμαστικού email + label_feeds_access_key_created_on: "το κλειδί πρόσβασης RSS δημιουργήθηκε πριν από %{value}" + label_module_plural: Μονάδες + label_added_time_by: "Προστέθηκε από τον %{author} πριν από %{age}" + label_updated_time_by: "Ενημερώθηκε από τον %{author} πριν από %{age}" + label_updated_time: "Ενημερώθηκε πριν από %{value}" + label_jump_to_a_project: Μεταβείτε σε ένα έργο... + label_file_plural: Αρχεία + label_changeset_plural: Changesets + label_default_columns: Προεπιλεγμένες στήλες + label_no_change_option: (Δεν υπάρχουν αλλαγές) + label_bulk_edit_selected_issues: Μαζική επεξεργασία επιλεγμένων θεμάτων + label_theme: Θέμα + label_default: Προεπιλογή + label_search_titles_only: Αναζήτηση τίτλων μόνο + label_user_mail_option_all: "Για όλες τις εξελίξεις σε όλα τα έργα μου" + label_user_mail_option_selected: "Για όλες τις εξελίξεις μόνο στα επιλεγμένα έργα..." + label_user_mail_no_self_notified: "Δεν θέλω να ειδοποιούμαι για τις δικές μου αλλαγές" + label_registration_activation_by_email: ενεργοποίηση λογαριασμού με email + label_registration_manual_activation: χειροκίνητη ενεργοποίηση λογαριασμού + label_registration_automatic_activation: αυτόματη ενεργοποίηση λογαριασμού + label_display_per_page: "Ανά σελίδα: %{value}" + label_age: Ηλικία + label_change_properties: Αλλαγή ιδιοτήτων + label_general: Γενικά + label_more: Περισσότερα + label_scm: SCM + label_plugins: Plugins + label_ldap_authentication: Πιστοποίηση LDAP + label_downloads_abbr: Μ/Φ + label_optional_description: Προαιρετική περιγραφή + label_add_another_file: Προσθήκη άλλου αρχείου + label_preferences: Προτιμήσεις + label_chronological_order: Κατά χρονολογική σειρά + label_reverse_chronological_order: Κατά αντίστροφη χρονολογική σειρά + label_planning: Σχεδιασμός + label_incoming_emails: Εισερχόμενα email + label_generate_key: Δημιουργία κλειδιού + label_issue_watchers: Παρατηρητές + label_example: Παράδειγμα + label_display: Προβολή + label_sort: Ταξινόμηση + label_ascending: Αύξουσα + label_descending: Φθίνουσα + label_date_from_to: Από %{start} έως %{end} + label_wiki_content_added: Η σελίδα Wiki προστέθηκε + label_wiki_content_updated: Η σελίδα Wiki ενημερώθηκε + + button_login: Σύνδεση + button_submit: Αποστολή + button_save: Αποθήκευση + button_check_all: Επιλογή όλων + button_uncheck_all: Αποεπιλογή όλων + button_delete: Διαγραφή + button_create: Δημιουργία + button_create_and_continue: Δημιουργία και συνέχεια + button_test: Τεστ + button_edit: Επεξεργασία + button_add: Προσθήκη + button_change: Αλλαγή + button_apply: Εφαρμογή + button_clear: Καθαρισμός + button_lock: Κλείδωμα + button_unlock: Ξεκλείδωμα + button_download: Μεταφόρτωση + button_list: Λίστα + button_view: Προβολή + button_move: Μετακίνηση + button_back: Πίσω + button_cancel: Ακύρωση + button_activate: Ενεργοποίηση + button_sort: Ταξινόμηση + button_log_time: Ιστορικό χρόνου + button_rollback: Επαναφορά σε αυτή την έκδοση + button_watch: Παρακολούθηση + button_unwatch: Αναίρεση παρακολούθησης + button_reply: Απάντηση + button_archive: Αρχειοθέτηση + button_unarchive: Αναίρεση αρχειοθέτησης + button_reset: Επαναφορά + button_rename: Μετονομασία + button_change_password: Αλλαγή κωδικού πρόσβασης + button_copy: Αντιγραφή + button_annotate: Σχολιασμός + button_update: Ενημέρωση + button_configure: Ρύθμιση + button_quote: Παράθεση + + status_active: ενεργό(ς)/ή + status_registered: εγεγγραμμένο(ς)/η + status_locked: κλειδωμένο(ς)/η + + text_select_mail_notifications: Επιλογή ενεργειών για τις οποίες θα πρέπει να αποσταλεί ειδοποίηση με email. + text_regexp_info: eg. ^[A-Z0-9]+$ + text_min_max_length_info: 0 σημαίνει ότι δεν υπάρχουν περιορισμοί + text_project_destroy_confirmation: Είστε σίγουροι ότι θέλετε να διαγράψετε αυτό το έργο και τα σχετικά δεδομένα του; + text_subprojects_destroy_warning: "Επίσης το(α) επιμέρους έργο(α): %{value} θα διαγραφούν." + text_workflow_edit: Επιλέξτε ένα ρόλο και έναν ανιχνευτή για να επεξεργαστείτε τη ροή εργασίας + text_are_you_sure: Είστε σίγουρος ; + text_tip_issue_begin_day: καθήκοντα που ξεκινάνε σήμερα + text_tip_issue_end_day: καθήκοντα που τελειώνουν σήμερα + text_tip_issue_begin_end_day: καθήκοντα που ξεκινάνε και τελειώνουν σήμερα + text_caracters_maximum: "μέγιστος αριθμός %{count} χαρακτήρες." + text_caracters_minimum: "Πρέπει να περιέχει τουλάχιστον %{count} χαρακτήρες." + text_length_between: "Μήκος μεταξύ %{min} και %{max} χαρακτήρες." + text_tracker_no_workflow: Δεν έχει οριστεί ροή εργασίας για αυτό τον ανιχνευτή + text_unallowed_characters: Μη επιτρεπόμενοι χαρακτήρες + text_comma_separated: Επιτρέπονται πολλαπλές τιμές (χωρισμένες με κόμμα). + text_issues_ref_in_commit_messages: Αναφορά και καθορισμός θεμάτων σε μηνύματα commit + text_issue_added: "Το θέμα %{id} παρουσιάστηκε από τον %{author}." + text_issue_updated: "Το θέμα %{id} ενημερώθηκε από τον %{author}." + text_wiki_destroy_confirmation: Είστε σίγουροι ότι θέλετε να διαγράψετε αυτό το wiki και όλο το περιεχόμενο του ; + text_issue_category_destroy_question: "Κάποια θέματα (%{count}) έχουν εκχωρηθεί σε αυτή την κατηγορία. Τι θέλετε να κάνετε ;" + text_issue_category_destroy_assignments: Αφαίρεση εκχωρήσεων κατηγορίας + text_issue_category_reassign_to: Επανεκχώρηση θεμάτων σε αυτή την κατηγορία + text_user_mail_option: "Για μη επιλεγμένα έργα, θα λάβετε ειδοποιήσεις μόνο για πράγματα που παρακολουθείτε ή στα οποία συμμετέχω ενεργά (π.χ. θέματα των οποίων είστε συγγραφέας ή σας έχουν ανατεθεί)." + text_no_configuration_data: "Οι ρόλοι, οι ανιχνευτές, η κατάσταση των θεμάτων και η ροή εργασίας δεν έχουν ρυθμιστεί ακόμα.\nΣυνιστάται ιδιαίτερα να φορτώσετε τις προεπιλεγμένες ρυθμίσεις. Θα είστε σε θέση να τις τροποποιήσετε μετά τη φόρτωση τους." + text_load_default_configuration: Φόρτωση προεπιλεγμένων ρυθμίσεων + text_status_changed_by_changeset: "Εφαρμόστηκε στο changeset %{value}." + text_issues_destroy_confirmation: 'Είστε σίγουρος ότι θέλετε να διαγράψετε το επιλεγμένο θέμα(τα);' + text_select_project_modules: 'Επιλέξτε ποιες μονάδες θα ενεργοποιήσετε για αυτό το έργο:' + text_default_administrator_account_changed: Ο προκαθορισμένος λογαριασμός του διαχειριστή άλλαξε + text_file_repository_writable: Εγγράψιμος κατάλογος συνημμένων + text_plugin_assets_writable: Εγγράψιμος κατάλογος plugin assets + text_rmagick_available: Διαθέσιμο RMagick (προαιρετικό) + text_destroy_time_entries_question: "%{hours} δαπανήθηκαν σχετικά με τα θέματα που πρόκειται να διαγράψετε. Τι θέλετε να κάνετε ;" + text_destroy_time_entries: Διαγραφή αναφερόμενων ωρών + text_assign_time_entries_to_project: Ανάθεση αναφερόμενων ωρών στο έργο + text_reassign_time_entries: 'Ανάθεση εκ νέου των αναφερόμενων ωρών στο θέμα:' + text_user_wrote: "%{value} έγραψε:" + text_enumeration_destroy_question: "%{count} αντικείμενα έχουν τεθεί σε αυτή την τιμή." + text_enumeration_category_reassign_to: 'Επανεκχώρηση τους στην παρούσα αξία:' + text_email_delivery_not_configured: "Δεν έχουν γίνει ρυθμίσεις παράδοσης email, και οι ειδοποιήσεις είναι απενεργοποιημένες.\nΔηλώστε τον εξυπηρετητή SMTP στο config/configuration.yml και κάντε επανακκίνηση την εφαρμογή για να τις ρυθμίσεις." + text_repository_usernames_mapping: "Επιλέξτε ή ενημερώστε τον χρήστη Redmine που αντιστοιχεί σε κάθε όνομα χρήστη στο ιστορικό του αποθετηρίου.\nΧρήστες με το ίδιο όνομα χρήστη ή email στο Redmine και στο αποθετηρίο αντιστοιχίζονται αυτόματα." + text_diff_truncated: '... Αυτό το diff εχεί κοπεί επειδή υπερβαίνει το μέγιστο μέγεθος που μπορεί να προβληθεί.' + text_custom_field_possible_values_info: 'Μία γραμμή για κάθε τιμή' + text_wiki_page_destroy_question: "Αυτή η σελίδα έχει %{descendants} σελίδες τέκνων και απογόνων. Τι θέλετε να κάνετε ;" + text_wiki_page_nullify_children: "Διατηρήστε τις σελίδες τέκνων ως σελίδες root" + text_wiki_page_destroy_children: "Διαγράψτε όλες τις σελίδες τέκνων και των απογόνων τους" + text_wiki_page_reassign_children: "Επανεκχώριση των σελίδων τέκνων στη γονική σελίδα" + + default_role_manager: Manager + default_role_developer: Developer + default_role_reporter: Reporter + default_tracker_bug: Σφάλματα + default_tracker_feature: Λειτουργίες + default_tracker_support: Υποστήριξη + default_issue_status_new: Νέα + default_issue_status_in_progress: In Progress + default_issue_status_resolved: Επιλυμένο + default_issue_status_feedback: Σχόλια + default_issue_status_closed: Κλειστό + default_issue_status_rejected: Απορριπτέο + default_doc_category_user: Τεκμηρίωση χρήστη + default_doc_category_tech: Τεχνική τεκμηρίωση + default_priority_low: Χαμηλή + default_priority_normal: Κανονική + default_priority_high: Υψηλή + default_priority_urgent: Επείγον + default_priority_immediate: Άμεση + default_activity_design: Σχεδιασμός + default_activity_development: Ανάπτυξη + + enumeration_issue_priorities: Προτεραιότητα θέματος + enumeration_doc_categories: Κατηγορία εγγράφων + enumeration_activities: Δραστηριότητες (κατακερματισμός χρόνου) + text_journal_changed: "%{label} άλλαξε από %{old} σε %{new}" + text_journal_set_to: "%{label} ορίζεται σε %{value}" + text_journal_deleted: "%{label} διαγράφηκε (%{old})" + label_group_plural: Ομάδες + label_group: Ομάδα + label_group_new: Νέα ομάδα + label_time_entry_plural: Χρόνος που δαπανήθηκε + text_journal_added: "%{label} %{value} added" + field_active: Active + enumeration_system_activity: System Activity + permission_delete_issue_watchers: Delete watchers + version_status_closed: closed + version_status_locked: locked + version_status_open: open + error_can_not_reopen_issue_on_closed_version: An issue assigned to a closed version can not be reopened + label_user_anonymous: Anonymous + button_move_and_follow: Move and follow + setting_default_projects_modules: Default enabled modules for new projects + setting_gravatar_default: Default Gravatar image + field_sharing: Sharing + label_version_sharing_hierarchy: With project hierarchy + label_version_sharing_system: With all projects + label_version_sharing_descendants: With subprojects + label_version_sharing_tree: With project tree + label_version_sharing_none: Not shared + error_can_not_archive_project: This project can not be archived + button_duplicate: Duplicate + button_copy_and_follow: Copy and follow + label_copy_source: Source + setting_issue_done_ratio: Calculate the issue done ratio with + setting_issue_done_ratio_issue_status: Use the issue status + error_issue_done_ratios_not_updated: Issue done ratios not updated. + error_workflow_copy_target: Please select target tracker(s) and role(s) + setting_issue_done_ratio_issue_field: Use the issue field + label_copy_same_as_target: Same as target + label_copy_target: Target + notice_issue_done_ratios_updated: Issue done ratios updated. + error_workflow_copy_source: Please select a source tracker or role + label_update_issue_done_ratios: Update issue done ratios + setting_start_of_week: Start calendars on + permission_view_issues: View Issues + label_display_used_statuses_only: Only display statuses that are used by this tracker + label_revision_id: Revision %{value} + label_api_access_key: API access key + label_api_access_key_created_on: API access key created %{value} ago + label_feeds_access_key: RSS access key + notice_api_access_key_reseted: Your API access key was reset. + setting_rest_api_enabled: Enable REST web service + label_missing_api_access_key: Missing an API access key + label_missing_feeds_access_key: Missing a RSS access key + button_show: Show + text_line_separated: Multiple values allowed (one line for each value). + setting_mail_handler_body_delimiters: Truncate emails after one of these lines + permission_add_subprojects: Create subprojects + label_subproject_new: New subproject + text_own_membership_delete_confirmation: |- + You are about to remove some or all of your permissions and may no longer be able to edit this project after that. + Are you sure you want to continue? + label_close_versions: Close completed versions + label_board_sticky: Sticky + label_board_locked: Locked + permission_export_wiki_pages: Export wiki pages + setting_cache_formatted_text: Cache formatted text + permission_manage_project_activities: Manage project activities + error_unable_delete_issue_status: Unable to delete issue status + label_profile: Profile + permission_manage_subtasks: Manage subtasks + field_parent_issue: Parent task + label_subtask_plural: Subtasks + label_project_copy_notifications: Send email notifications during the project copy + error_can_not_delete_custom_field: Unable to delete custom field + error_unable_to_connect: Unable to connect (%{value}) + error_can_not_remove_role: This role is in use and can not be deleted. + error_can_not_delete_tracker: This tracker contains issues and can't be deleted. + field_principal: Principal + label_my_page_block: My page block + notice_failed_to_save_members: "Failed to save member(s): %{errors}." + text_zoom_out: Zoom out + text_zoom_in: Zoom in + notice_unable_delete_time_entry: Unable to delete time log entry. + label_overall_spent_time: Overall spent time + field_time_entries: Log time + project_module_gantt: Gantt + project_module_calendar: Calendar + button_edit_associated_wikipage: "Edit associated Wiki page: %{page_title}" + field_text: Text field + label_user_mail_option_only_owner: Only for things I am the owner of + setting_default_notification_option: Default notification option + label_user_mail_option_only_my_events: Only for things I watch or I'm involved in + label_user_mail_option_only_assigned: Only for things I am assigned to + label_user_mail_option_none: No events + field_member_of_group: Assignee's group + field_assigned_to_role: Assignee's role + notice_not_authorized_archived_project: The project you're trying to access has been archived. + label_principal_search: "Search for user or group:" + label_user_search: "Search for user:" + field_visible: Visible + setting_commit_logtime_activity_id: Activity for logged time + text_time_logged_by_changeset: Applied in changeset %{value}. + setting_commit_logtime_enabled: Enable time logging + notice_gantt_chart_truncated: The chart was truncated because it exceeds the maximum number of items that can be displayed (%{max}) + setting_gantt_items_limit: Maximum number of items displayed on the gantt chart + field_warn_on_leaving_unsaved: Warn me when leaving a page with unsaved text + text_warn_on_leaving_unsaved: The current page contains unsaved text that will be lost if you leave this page. + label_my_queries: My custom queries + text_journal_changed_no_detail: "%{label} updated" + label_news_comment_added: Comment added to a news + button_expand_all: Expand all + button_collapse_all: Collapse all + label_additional_workflow_transitions_for_assignee: Additional transitions allowed when the user is the assignee + label_additional_workflow_transitions_for_author: Additional transitions allowed when the user is the author + label_bulk_edit_selected_time_entries: Bulk edit selected time entries + text_time_entries_destroy_confirmation: Are you sure you want to delete the selected time entr(y/ies)? + label_role_anonymous: Anonymous + label_role_non_member: Non member + label_issue_note_added: Note added + label_issue_status_updated: Status updated + label_issue_priority_updated: Priority updated + label_issues_visibility_own: Issues created by or assigned to the user + field_issues_visibility: Issues visibility + label_issues_visibility_all: All issues + permission_set_own_issues_private: Set own issues public or private + field_is_private: Private + permission_set_issues_private: Set issues public or private + label_issues_visibility_public: All non private issues + text_issues_destroy_descendants_confirmation: This will also delete %{count} subtask(s). + field_commit_logs_encoding: Κωδικοποίηση μηνυμάτων commit + field_scm_path_encoding: Path encoding + text_scm_path_encoding_note: "Default: UTF-8" + field_path_to_repository: Path to repository + field_root_directory: Root directory + field_cvs_module: Module + field_cvsroot: CVSROOT + text_mercurial_repository_note: Local repository (e.g. /hgrepo, c:\hgrepo) + text_scm_command: Command + text_scm_command_version: Version + label_git_report_last_commit: Report last commit for files and directories + notice_issue_successful_create: Issue %{id} created. + label_between: between + setting_issue_group_assignment: Allow issue assignment to groups + label_diff: diff + text_git_repository_note: Repository is bare and local (e.g. /gitrepo, c:\gitrepo) + description_query_sort_criteria_direction: Sort direction + description_project_scope: Search scope + description_filter: Filter + description_user_mail_notification: Mail notification settings + description_date_from: Enter start date + description_message_content: Message content + description_available_columns: Available Columns + description_date_range_interval: Choose range by selecting start and end date + description_issue_category_reassign: Choose issue category + description_search: Searchfield + description_notes: Notes + description_date_range_list: Choose range from list + description_choose_project: Projects + description_date_to: Enter end date + description_query_sort_criteria_attribute: Sort attribute + description_wiki_subpages_reassign: Choose new parent page + description_selected_columns: Selected Columns + label_parent_revision: Parent + label_child_revision: Child + error_scm_annotate_big_text_file: The entry cannot be annotated, as it exceeds the maximum text file size. + setting_default_issue_start_date_to_creation_date: Use current date as start date for new issues + button_edit_section: Edit this section + setting_repositories_encodings: Attachments and repositories encodings + description_all_columns: All Columns + button_export: Export + label_export_options: "%{export_format} export options" + error_attachment_too_big: This file cannot be uploaded because it exceeds the maximum allowed file size (%{max_size}) + notice_failed_to_save_time_entries: "Failed to save %{count} time entrie(s) on %{total} selected: %{ids}." + label_x_issues: + zero: 0 Θέμα + one: 1 Θέμα + other: "%{count} Θέματα" + label_repository_new: New repository + field_repository_is_default: Main repository + label_copy_attachments: Copy attachments + label_item_position: "%{position}/%{count}" + label_completed_versions: Completed versions + text_project_identifier_info: Only lower case letters (a-z), numbers, dashes and underscores are allowed.
    Once saved, the identifier cannot be changed. + field_multiple: Multiple values + setting_commit_cross_project_ref: Allow issues of all the other projects to be referenced and fixed + text_issue_conflict_resolution_add_notes: Add my notes and discard my other changes + text_issue_conflict_resolution_overwrite: Apply my changes anyway (previous notes will be kept but some changes may be overwritten) + notice_issue_update_conflict: The issue has been updated by an other user while you were editing it. + text_issue_conflict_resolution_cancel: Discard all my changes and redisplay %{link} + permission_manage_related_issues: Manage related issues + field_auth_source_ldap_filter: LDAP filter + label_search_for_watchers: Search for watchers to add + notice_account_deleted: Your account has been permanently deleted. + setting_unsubscribe: Allow users to delete their own account + button_delete_my_account: Delete my account + text_account_destroy_confirmation: |- + Are you sure you want to proceed? + Your account will be permanently deleted, with no way to reactivate it. + error_session_expired: Your session has expired. Please login again. + text_session_expiration_settings: "Warning: changing these settings may expire the current sessions including yours." + setting_session_lifetime: Session maximum lifetime + setting_session_timeout: Session inactivity timeout + label_session_expiration: Session expiration + permission_close_project: Close / reopen the project + label_show_closed_projects: View closed projects + button_close: Close + button_reopen: Reopen + project_status_active: active + project_status_closed: closed + project_status_archived: archived + text_project_closed: This project is closed and read-only. + notice_user_successful_create: User %{id} created. + field_core_fields: Standard fields + field_timeout: Timeout (in seconds) + setting_thumbnails_enabled: Display attachment thumbnails + setting_thumbnails_size: Thumbnails size (in pixels) + label_status_transitions: Status transitions + label_fields_permissions: Fields permissions + label_readonly: Read-only + label_required: Required + text_repository_identifier_info: Only lower case letters (a-z), numbers, dashes and underscores are allowed.
    Once saved, the identifier cannot be changed. + field_board_parent: Parent forum + label_attribute_of_project: Project's %{name} + label_attribute_of_author: Author's %{name} + label_attribute_of_assigned_to: Assignee's %{name} + label_attribute_of_fixed_version: Target version's %{name} + label_copy_subtasks: Copy subtasks + label_copied_to: copied to + label_copied_from: copied from + label_any_issues_in_project: any issues in project + label_any_issues_not_in_project: any issues not in project + field_private_notes: Private notes + permission_view_private_notes: View private notes + permission_set_notes_private: Set notes as private + label_no_issues_in_project: no issues in project + label_any: όλα + label_last_n_weeks: last %{count} weeks + setting_cross_project_subtasks: Allow cross-project subtasks + label_cross_project_descendants: With subprojects + label_cross_project_tree: With project tree + label_cross_project_hierarchy: With project hierarchy + label_cross_project_system: With all projects + button_hide: Hide + setting_non_working_week_days: Non-working days + label_in_the_next_days: in the next + label_in_the_past_days: in the past + label_attribute_of_user: User's %{name} + text_turning_multiple_off: If you disable multiple values, multiple values will be + removed in order to preserve only one value per item. + label_attribute_of_issue: Issue's %{name} + permission_add_documents: Add documents + permission_edit_documents: Edit documents + permission_delete_documents: Delete documents + label_gantt_progress_line: Progress line + setting_jsonp_enabled: Enable JSONP support + field_inherit_members: Inherit members + field_closed_on: Closed + setting_default_projects_tracker_ids: Default trackers for new projects + label_total_time: Σύνολο + text_scm_config: You can configure your SCM commands in config/configuration.yml. Please restart the application after editing it. + text_scm_command_not_available: SCM command is not available. Please check settings on the administration panel. + setting_emails_header: Email header diff --git a/config/locales/en-GB.yml b/config/locales/en-GB.yml new file mode 100644 index 00000000..ceaba1ed --- /dev/null +++ b/config/locales/en-GB.yml @@ -0,0 +1,1091 @@ +en-GB: + direction: ltr + date: + formats: + # Use the strftime parameters for formats. + # When no format has been given, it uses default. + # You can provide other formats here if you like! + default: "%d/%m/%Y" + short: "%d %b" + long: "%d %B, %Y" + + day_names: [Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday] + abbr_day_names: [Sun, Mon, Tue, Wed, Thu, Fri, Sat] + + # Don't forget the nil at the beginning; there's no such thing as a 0th month + month_names: [~, January, February, March, April, May, June, July, August, September, October, November, December] + abbr_month_names: [~, Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec] + # Used in date_select and datime_select. + order: + - :year + - :month + - :day + + time: + formats: + default: "%d/%m/%Y %I:%M %p" + time: "%I:%M %p" + short: "%d %b %H:%M" + long: "%d %B, %Y %H:%M" + am: "am" + pm: "pm" + + datetime: + distance_in_words: + half_a_minute: "half a minute" + less_than_x_seconds: + one: "less than 1 second" + other: "less than %{count} seconds" + x_seconds: + one: "1 second" + other: "%{count} seconds" + less_than_x_minutes: + one: "less than a minute" + other: "less than %{count} minutes" + x_minutes: + one: "1 minute" + other: "%{count} minutes" + about_x_hours: + one: "about 1 hour" + other: "about %{count} hours" + x_hours: + one: "1 hour" + other: "%{count} hours" + x_days: + one: "1 day" + other: "%{count} days" + about_x_months: + one: "about 1 month" + other: "about %{count} months" + x_months: + one: "1 month" + other: "%{count} months" + about_x_years: + one: "about 1 year" + other: "about %{count} years" + over_x_years: + one: "over 1 year" + other: "over %{count} years" + almost_x_years: + one: "almost 1 year" + other: "almost %{count} years" + + number: + format: + separator: "." + delimiter: " " + precision: 3 + + currency: + format: + format: "%u%n" + unit: "£" + + human: + format: + delimiter: "" + precision: 3 + storage_units: + format: "%n %u" + units: + byte: + one: "Byte" + other: "Bytes" + kb: "KB" + mb: "MB" + gb: "GB" + tb: "TB" + +# Used in array.to_sentence. + support: + array: + sentence_connector: "and" + skip_last_comma: false + + activerecord: + errors: + template: + header: + one: "1 error prohibited this %{model} from being saved" + other: "%{count} errors prohibited this %{model} from being saved" + messages: + inclusion: "is not included in the list" + exclusion: "is reserved" + invalid: "is invalid" + confirmation: "doesn't match confirmation" + accepted: "must be accepted" + empty: "can't be empty" + blank: "can't be blank" + too_long: "is too long (maximum is %{count} characters)" + too_short: "is too short (minimum is %{count} characters)" + wrong_length: "is the wrong length (should be %{count} characters)" + taken: "has already been taken" + not_a_number: "is not a number" + not_a_date: "is not a valid date" + greater_than: "must be greater than %{count}" + greater_than_or_equal_to: "must be greater than or equal to %{count}" + equal_to: "must be equal to %{count}" + less_than: "must be less than %{count}" + less_than_or_equal_to: "must be less than or equal to %{count}" + odd: "must be odd" + even: "must be even" + greater_than_start_date: "must be greater than start date" + not_same_project: "doesn't belong to the same project" + circular_dependency: "This relation would create a circular dependency" + cant_link_an_issue_with_a_descendant: "An issue cannot be linked to one of its subtasks" + + actionview_instancetag_blank_option: Please select + + general_text_No: 'No' + general_text_Yes: 'Yes' + general_text_no: 'no' + general_text_yes: 'yes' + general_lang_name: 'English (British)' + general_csv_separator: ',' + general_csv_decimal_separator: '.' + general_csv_encoding: ISO-8859-1 + general_pdf_encoding: UTF-8 + general_first_day_of_week: '1' + + notice_account_updated: Account was successfully updated. + notice_account_invalid_creditentials: Invalid user or password + notice_account_password_updated: Password was successfully updated. + notice_account_wrong_password: Wrong password + notice_account_register_done: Account was successfully created. To activate your account, click on the link that was emailed to you. + notice_account_unknown_email: Unknown user. + notice_can_t_change_password: This account uses an external authentication source. Impossible to change the password. + notice_account_lost_email_sent: An email with instructions to choose a new password has been sent to you. + notice_account_activated: Your account has been activated. You can now log in. + notice_successful_create: Successful creation. + notice_successful_update: Successful update. + notice_successful_delete: Successful deletion. + notice_successful_connection: Successful connection. + notice_file_not_found: The page you were trying to access doesn't exist or has been removed. + notice_locking_conflict: Data has been updated by another user. + notice_not_authorized: You are not authorised to access this page. + notice_not_authorized_archived_project: The project you're trying to access has been archived. + notice_email_sent: "An email was sent to %{value}" + notice_email_error: "An error occurred while sending mail (%{value})" + notice_feeds_access_key_reseted: Your RSS access key was reset. + notice_api_access_key_reseted: Your API access key was reset. + notice_failed_to_save_issues: "Failed to save %{count} issue(s) on %{total} selected: %{ids}." + notice_failed_to_save_members: "Failed to save member(s): %{errors}." + notice_no_issue_selected: "No issue is selected! Please, check the issues you want to edit." + notice_account_pending: "Your account was created and is now pending administrator approval." + notice_default_data_loaded: Default configuration successfully loaded. + notice_unable_delete_version: Unable to delete version. + notice_unable_delete_time_entry: Unable to delete time log entry. + notice_issue_done_ratios_updated: Issue done ratios updated. + notice_gantt_chart_truncated: "The chart was truncated because it exceeds the maximum number of items that can be displayed (%{max})" + + error_can_t_load_default_data: "Default configuration could not be loaded: %{value}" + error_scm_not_found: "The entry or revision was not found in the repository." + error_scm_command_failed: "An error occurred when trying to access the repository: %{value}" + error_scm_annotate: "The entry does not exist or cannot be annotated." + error_scm_annotate_big_text_file: "The entry cannot be annotated, as it exceeds the maximum text file size." + error_issue_not_found_in_project: 'The issue was not found or does not belong to this project' + error_no_tracker_in_project: 'No tracker is associated to this project. Please check the Project settings.' + error_no_default_issue_status: 'No default issue status is defined. Please check your configuration (Go to "Administration -> Issue statuses").' + error_can_not_delete_custom_field: Unable to delete custom field + error_can_not_delete_tracker: "This tracker contains issues and cannot be deleted." + error_can_not_remove_role: "This role is in use and cannot be deleted." + error_can_not_reopen_issue_on_closed_version: 'An issue assigned to a closed version cannot be reopened' + error_can_not_archive_project: This project cannot be archived + error_issue_done_ratios_not_updated: "Issue done ratios not updated." + error_workflow_copy_source: 'Please select a source tracker or role' + error_workflow_copy_target: 'Please select target tracker(s) and role(s)' + error_unable_delete_issue_status: 'Unable to delete issue status' + error_unable_to_connect: "Unable to connect (%{value})" + warning_attachments_not_saved: "%{count} file(s) could not be saved." + + mail_subject_lost_password: "Your %{value} password" + mail_body_lost_password: 'To change your password, click on the following link:' + mail_subject_register: "Your %{value} account activation" + mail_body_register: 'To activate your account, click on the following link:' + mail_body_account_information_external: "You can use your %{value} account to log in." + mail_body_account_information: Your account information + mail_subject_account_activation_request: "%{value} account activation request" + mail_body_account_activation_request: "A new user (%{value}) has registered. The account is pending your approval:" + mail_subject_reminder: "%{count} issue(s) due in the next %{days} days" + mail_body_reminder: "%{count} issue(s) that are assigned to you are due in the next %{days} days:" + mail_subject_wiki_content_added: "'%{id}' wiki page has been added" + mail_body_wiki_content_added: "The '%{id}' wiki page has been added by %{author}." + mail_subject_wiki_content_updated: "'%{id}' wiki page has been updated" + mail_body_wiki_content_updated: "The '%{id}' wiki page has been updated by %{author}." + + + field_name: Name + field_description: Description + field_summary: Summary + field_is_required: Required + field_firstname: First name + field_lastname: Last name + field_mail: Email + field_filename: File + field_filesize: Size + field_downloads: Downloads + field_author: Author + field_created_on: Created + field_updated_on: Updated + field_field_format: Format + field_is_for_all: For all projects + field_possible_values: Possible values + field_regexp: Regular expression + field_min_length: Minimum length + field_max_length: Maximum length + field_value: Value + field_category: Category + field_title: Title + field_project: Project + field_issue: Issue + field_status: Status + field_notes: Notes + field_is_closed: Issue closed + field_is_default: Default value + field_tracker: Tracker + field_subject: Subject + field_due_date: Due date + field_assigned_to: Assignee + field_priority: Priority + field_fixed_version: Target version + field_user: User + field_principal: Principal + field_role: Role + field_homepage: Homepage + field_is_public: Public + field_parent: Subproject of + field_is_in_roadmap: Issues displayed in roadmap + field_login: Login + field_mail_notification: Email notifications + field_admin: Administrator + field_last_login_on: Last connection + field_language: Language + field_effective_date: Date + field_password: Password + field_new_password: New password + field_password_confirmation: Confirmation + field_version: Version + field_type: Type + field_host: Host + field_port: Port + field_account: Account + field_base_dn: Base DN + field_attr_login: Login attribute + field_attr_firstname: Firstname attribute + field_attr_lastname: Lastname attribute + field_attr_mail: Email attribute + field_onthefly: On-the-fly user creation + field_start_date: Start date + field_done_ratio: "% Done" + field_auth_source: Authentication mode + field_hide_mail: Hide my email address + field_comments: Comment + field_url: URL + field_start_page: Start page + field_subproject: Subproject + field_hours: Hours + field_activity: Activity + field_spent_on: Date + field_identifier: Identifier + field_is_filter: Used as a filter + field_issue_to: Related issue + field_delay: Delay + field_assignable: Issues can be assigned to this role + field_redirect_existing_links: Redirect existing links + field_estimated_hours: Estimated time + field_column_names: Columns + field_time_entries: Log time + field_time_zone: Time zone + field_searchable: Searchable + field_default_value: Default value + field_comments_sorting: Display comments + field_parent_title: Parent page + field_editable: Editable + field_watcher: Watcher + field_identity_url: OpenID URL + field_content: Content + field_group_by: Group results by + field_sharing: Sharing + field_parent_issue: Parent task + field_member_of_group: "Assignee's group" + field_assigned_to_role: "Assignee's role" + field_text: Text field + field_visible: Visible + field_warn_on_leaving_unsaved: "Warn me when leaving a page with unsaved text" + + setting_app_title: Application title + setting_app_subtitle: Application subtitle + setting_welcome_text: Welcome text + setting_default_language: Default language + setting_login_required: Authentication required + setting_self_registration: Self-registration + setting_attachment_max_size: Attachment max. size + setting_issues_export_limit: Issues export limit + setting_mail_from: Emission email address + setting_bcc_recipients: Blind carbon copy recipients (bcc) + setting_plain_text_mail: Plain text mail (no HTML) + setting_host_name: Host name and path + setting_text_formatting: Text formatting + setting_wiki_compression: Wiki history compression + setting_feeds_limit: Feed content limit + setting_default_projects_public: New projects are public by default + setting_autofetch_changesets: Autofetch commits + setting_sys_api_enabled: Enable WS for repository management + setting_commit_ref_keywords: Referencing keywords + setting_commit_fix_keywords: Fixing keywords + setting_autologin: Autologin + setting_date_format: Date format + setting_time_format: Time format + setting_cross_project_issue_relations: Allow cross-project issue relations + setting_issue_list_default_columns: Default columns displayed on the issue list + setting_emails_header: Email header + setting_emails_footer: Email footer + setting_protocol: Protocol + setting_per_page_options: Objects per page options + setting_user_format: Users display format + setting_activity_days_default: Days displayed on project activity + setting_display_subprojects_issues: Display subprojects issues on main projects by default + setting_enabled_scm: Enabled SCM + setting_mail_handler_body_delimiters: "Truncate emails after one of these lines" + setting_mail_handler_api_enabled: Enable WS for incoming emails + setting_mail_handler_api_key: API key + setting_sequential_project_identifiers: Generate sequential project identifiers + setting_gravatar_enabled: Use Gravatar user icons + setting_gravatar_default: Default Gravatar image + setting_diff_max_lines_displayed: Max number of diff lines displayed + setting_file_max_size_displayed: Max size of text files displayed inline + setting_repository_log_display_limit: Maximum number of revisions displayed on file log + setting_openid: Allow OpenID login and registration + setting_password_min_length: Minimum password length + setting_new_project_user_role_id: Role given to a non-admin user who creates a project + setting_default_projects_modules: Default enabled modules for new projects + setting_issue_done_ratio: Calculate the issue done ratio with + setting_issue_done_ratio_issue_field: Use the issue field + setting_issue_done_ratio_issue_status: Use the issue status + setting_start_of_week: Start calendars on + setting_rest_api_enabled: Enable REST web service + setting_cache_formatted_text: Cache formatted text + setting_default_notification_option: Default notification option + setting_commit_logtime_enabled: Enable time logging + setting_commit_logtime_activity_id: Activity for logged time + setting_gantt_items_limit: Maximum number of items displayed on the gantt chart + setting_issue_group_assignment: Allow issue assignment to groups + setting_default_issue_start_date_to_creation_date: Use current date as start date for new issues + + permission_add_project: Create project + permission_add_subprojects: Create subprojects + permission_edit_project: Edit project + permission_select_project_modules: Select project modules + permission_manage_members: Manage members + permission_manage_project_activities: Manage project activities + permission_manage_versions: Manage versions + permission_manage_categories: Manage issue categories + permission_view_issues: View Issues + permission_add_issues: Add issues + permission_edit_issues: Edit issues + permission_manage_issue_relations: Manage issue relations + permission_add_issue_notes: Add notes + permission_edit_issue_notes: Edit notes + permission_edit_own_issue_notes: Edit own notes + permission_move_issues: Move issues + permission_delete_issues: Delete issues + permission_manage_public_queries: Manage public queries + permission_save_queries: Save queries + permission_view_gantt: View gantt chart + permission_view_calendar: View calendar + permission_view_issue_watchers: View watchers list + permission_add_issue_watchers: Add watchers + permission_delete_issue_watchers: Delete watchers + permission_log_time: Log spent time + permission_view_time_entries: View spent time + permission_edit_time_entries: Edit time logs + permission_edit_own_time_entries: Edit own time logs + permission_manage_news: Manage news + permission_comment_news: Comment news + permission_view_documents: View documents + permission_manage_files: Manage files + permission_view_files: View files + permission_manage_wiki: Manage wiki + permission_rename_wiki_pages: Rename wiki pages + permission_delete_wiki_pages: Delete wiki pages + permission_view_wiki_pages: View wiki + permission_view_wiki_edits: View wiki history + permission_edit_wiki_pages: Edit wiki pages + permission_delete_wiki_pages_attachments: Delete attachments + permission_protect_wiki_pages: Protect wiki pages + permission_manage_repository: Manage repository + permission_browse_repository: Browse repository + permission_view_changesets: View changesets + permission_commit_access: Commit access + permission_manage_boards: Manage forums + permission_view_messages: View messages + permission_add_messages: Post messages + permission_edit_messages: Edit messages + permission_edit_own_messages: Edit own messages + permission_delete_messages: Delete messages + permission_delete_own_messages: Delete own messages + permission_export_wiki_pages: Export wiki pages + permission_manage_subtasks: Manage subtasks + + project_module_issue_tracking: Issue tracking + project_module_time_tracking: Time tracking + project_module_news: News + project_module_documents: Documents + project_module_files: Files + project_module_wiki: Wiki + project_module_repository: Repository + project_module_boards: Forums + project_module_calendar: Calendar + project_module_gantt: Gantt + + label_user: User + label_user_plural: Users + label_user_new: New user + label_user_anonymous: Anonymous + label_project: Project + label_project_new: New project + label_project_plural: Projects + label_x_projects: + zero: no projects + one: 1 project + other: "%{count} projects" + label_project_all: All Projects + label_project_latest: Latest projects + label_issue: Issue + label_issue_new: New issue + label_issue_plural: Issues + label_issue_view_all: View all issues + label_issues_by: "Issues by %{value}" + label_issue_added: Issue added + label_issue_updated: Issue updated + label_document: Document + label_document_new: New document + label_document_plural: Documents + label_document_added: Document added + label_role: Role + label_role_plural: Roles + label_role_new: New role + label_role_and_permissions: Roles and permissions + label_role_anonymous: Anonymous + label_role_non_member: Non member + label_member: Member + label_member_new: New member + label_member_plural: Members + label_tracker: Tracker + label_tracker_plural: Trackers + label_tracker_new: New tracker + label_workflow: Workflow + label_issue_status: Issue status + label_issue_status_plural: Issue statuses + label_issue_status_new: New status + label_issue_category: Issue category + label_issue_category_plural: Issue categories + label_issue_category_new: New category + label_custom_field: Custom field + label_custom_field_plural: Custom fields + label_custom_field_new: New custom field + label_enumerations: Enumerations + label_enumeration_new: New value + label_information: Information + label_information_plural: Information + label_please_login: Please log in + label_register: Register + label_login_with_open_id_option: or login with OpenID + label_password_lost: Lost password + label_home: Home + label_my_page: My page + label_my_account: My account + label_my_projects: My projects + label_my_page_block: My page block + label_administration: Administration + label_login: Sign in + label_logout: Sign out + label_help: Help + label_reported_issues: Reported issues + label_assigned_to_me_issues: Issues assigned to me + label_last_login: Last connection + label_registered_on: Registered on + label_activity: Activity + label_overall_activity: Overall activity + label_user_activity: "%{value}'s activity" + label_new: New + label_logged_as: Logged in as + label_environment: Environment + label_authentication: Authentication + label_auth_source: Authentication mode + label_auth_source_new: New authentication mode + label_auth_source_plural: Authentication modes + label_subproject_plural: Subprojects + label_subproject_new: New subproject + label_and_its_subprojects: "%{value} and its subprojects" + label_min_max_length: Min - Max length + label_list: List + label_date: Date + label_integer: Integer + label_float: Float + label_boolean: Boolean + label_string: Text + label_text: Long text + label_attribute: Attribute + label_attribute_plural: Attributes + label_no_data: No data to display + label_change_status: Change status + label_history: History + label_attachment: File + label_attachment_new: New file + label_attachment_delete: Delete file + label_attachment_plural: Files + label_file_added: File added + label_report: Report + label_report_plural: Reports + label_news: News + label_news_new: Add news + label_news_plural: News + label_news_latest: Latest news + label_news_view_all: View all news + label_news_added: News added + label_news_comment_added: Comment added to a news + label_settings: Settings + label_overview: Overview + label_version: Version + label_version_new: New version + label_version_plural: Versions + label_close_versions: Close completed versions + label_confirmation: Confirmation + label_export_to: 'Also available in:' + label_read: Read... + label_public_projects: Public projects + label_open_issues: open + label_open_issues_plural: open + label_closed_issues: closed + label_closed_issues_plural: closed + label_x_open_issues_abbr_on_total: + zero: 0 open / %{total} + one: 1 open / %{total} + other: "%{count} open / %{total}" + label_x_open_issues_abbr: + zero: 0 open + one: 1 open + other: "%{count} open" + label_x_closed_issues_abbr: + zero: 0 closed + one: 1 closed + other: "%{count} closed" + label_total: Total + label_permissions: Permissions + label_current_status: Current status + label_new_statuses_allowed: New statuses allowed + label_all: all + label_none: none + label_nobody: nobody + label_next: Next + label_previous: Previous + label_used_by: Used by + label_details: Details + label_add_note: Add a note + label_per_page: Per page + label_calendar: Calendar + label_months_from: months from + label_gantt: Gantt + label_internal: Internal + label_last_changes: "last %{count} changes" + label_change_view_all: View all changes + label_personalize_page: Personalise this page + label_comment: Comment + label_comment_plural: Comments + label_x_comments: + zero: no comments + one: 1 comment + other: "%{count} comments" + label_comment_add: Add a comment + label_comment_added: Comment added + label_comment_delete: Delete comments + label_query: Custom query + label_query_plural: Custom queries + label_query_new: New query + label_my_queries: My custom queries + label_filter_add: Add filter + label_filter_plural: Filters + label_equals: is + label_not_equals: is not + label_in_less_than: in less than + label_in_more_than: in more than + label_greater_or_equal: '>=' + label_less_or_equal: '<=' + label_in: in + label_today: today + label_all_time: all time + label_yesterday: yesterday + label_this_week: this week + label_last_week: last week + label_last_n_days: "last %{count} days" + label_this_month: this month + label_last_month: last month + label_this_year: this year + label_date_range: Date range + label_less_than_ago: less than days ago + label_more_than_ago: more than days ago + label_ago: days ago + label_contains: contains + label_not_contains: doesn't contain + label_day_plural: days + label_repository: Repository + label_repository_plural: Repositories + label_browse: Browse + label_branch: Branch + label_tag: Tag + label_revision: Revision + label_revision_plural: Revisions + label_revision_id: "Revision %{value}" + label_associated_revisions: Associated revisions + label_added: added + label_modified: modified + label_copied: copied + label_renamed: renamed + label_deleted: deleted + label_latest_revision: Latest revision + label_latest_revision_plural: Latest revisions + label_view_revisions: View revisions + label_view_all_revisions: View all revisions + label_max_size: Maximum size + label_sort_highest: Move to top + label_sort_higher: Move up + label_sort_lower: Move down + label_sort_lowest: Move to bottom + label_roadmap: Roadmap + label_roadmap_due_in: "Due in %{value}" + label_roadmap_overdue: "%{value} late" + label_roadmap_no_issues: No issues for this version + label_search: Search + label_result_plural: Results + label_all_words: All words + label_wiki: Wiki + label_wiki_edit: Wiki edit + label_wiki_edit_plural: Wiki edits + label_wiki_page: Wiki page + label_wiki_page_plural: Wiki pages + label_index_by_title: Index by title + label_index_by_date: Index by date + label_current_version: Current version + label_preview: Preview + label_feed_plural: Feeds + label_changes_details: Details of all changes + label_issue_tracking: Issue tracking + label_spent_time: Spent time + label_overall_spent_time: Overall spent time + label_f_hour: "%{value} hour" + label_f_hour_plural: "%{value} hours" + label_time_tracking: Time tracking + label_change_plural: Changes + label_statistics: Statistics + label_commits_per_month: Commits per month + label_commits_per_author: Commits per author + label_view_diff: View differences + label_diff_inline: inline + label_diff_side_by_side: side by side + label_options: Options + label_copy_workflow_from: Copy workflow from + label_permissions_report: Permissions report + label_watched_issues: Watched issues + label_related_issues: Related issues + label_applied_status: Applied status + label_loading: Loading... + label_relation_new: New relation + label_relation_delete: Delete relation + label_relates_to: related to + label_duplicates: duplicates + label_duplicated_by: duplicated by + label_blocks: blocks + label_blocked_by: blocked by + label_precedes: precedes + label_follows: follows + label_end_to_start: end to start + label_end_to_end: end to end + label_start_to_start: start to start + label_start_to_end: start to end + label_stay_logged_in: Stay logged in + label_disabled: disabled + label_show_completed_versions: Show completed versions + label_me: me + label_board: Forum + label_board_new: New forum + label_board_plural: Forums + label_board_locked: Locked + label_board_sticky: Sticky + label_topic_plural: Topics + label_message_plural: Messages + label_message_last: Last message + label_message_new: New message + label_message_posted: Message added + label_reply_plural: Replies + label_send_information: Send account information to the user + label_year: Year + label_month: Month + label_week: Week + label_date_from: From + label_date_to: To + label_language_based: Based on user's language + label_sort_by: "Sort by %{value}" + label_send_test_email: Send a test email + label_feeds_access_key: RSS access key + label_missing_feeds_access_key: Missing a RSS access key + label_feeds_access_key_created_on: "RSS access key created %{value} ago" + label_module_plural: Modules + label_added_time_by: "Added by %{author} %{age} ago" + label_updated_time_by: "Updated by %{author} %{age} ago" + label_updated_time: "Updated %{value} ago" + label_jump_to_a_project: Jump to a project... + label_file_plural: Files + label_changeset_plural: Changesets + label_default_columns: Default columns + label_no_change_option: (No change) + label_bulk_edit_selected_issues: Bulk edit selected issues + label_theme: Theme + label_default: Default + label_search_titles_only: Search titles only + label_user_mail_option_all: "For any event on all my projects" + label_user_mail_option_selected: "For any event on the selected projects only..." + label_user_mail_option_none: "No events" + label_user_mail_option_only_my_events: "Only for things I watch or I'm involved in" + label_user_mail_option_only_assigned: "Only for things I am assigned to" + label_user_mail_option_only_owner: "Only for things I am the owner of" + label_user_mail_no_self_notified: "I don't want to be notified of changes that I make myself" + label_registration_activation_by_email: account activation by email + label_registration_manual_activation: manual account activation + label_registration_automatic_activation: automatic account activation + label_display_per_page: "Per page: %{value}" + label_age: Age + label_change_properties: Change properties + label_general: General + label_more: More + label_scm: SCM + label_plugins: Plugins + label_ldap_authentication: LDAP authentication + label_downloads_abbr: D/L + label_optional_description: Optional description + label_add_another_file: Add another file + label_preferences: Preferences + label_chronological_order: In chronological order + label_reverse_chronological_order: In reverse chronological order + label_planning: Planning + label_incoming_emails: Incoming emails + label_generate_key: Generate a key + label_issue_watchers: Watchers + label_example: Example + label_display: Display + label_sort: Sort + label_ascending: Ascending + label_descending: Descending + label_date_from_to: From %{start} to %{end} + label_wiki_content_added: Wiki page added + label_wiki_content_updated: Wiki page updated + label_group: Group + label_group_plural: Groups + label_group_new: New group + label_time_entry_plural: Spent time + label_version_sharing_none: Not shared + label_version_sharing_descendants: With subprojects + label_version_sharing_hierarchy: With project hierarchy + label_version_sharing_tree: With project tree + label_version_sharing_system: With all projects + label_update_issue_done_ratios: Update issue done ratios + label_copy_source: Source + label_copy_target: Target + label_copy_same_as_target: Same as target + label_display_used_statuses_only: Only display statuses that are used by this tracker + label_api_access_key: API access key + label_missing_api_access_key: Missing an API access key + label_api_access_key_created_on: "API access key created %{value} ago" + label_profile: Profile + label_subtask_plural: Subtasks + label_project_copy_notifications: Send email notifications during the project copy + label_principal_search: "Search for user or group:" + label_user_search: "Search for user:" + + button_login: Login + button_submit: Submit + button_save: Save + button_check_all: Check all + button_uncheck_all: Uncheck all + button_collapse_all: Collapse all + button_expand_all: Expand all + button_delete: Delete + button_create: Create + button_create_and_continue: Create and continue + button_test: Test + button_edit: Edit + button_edit_associated_wikipage: "Edit associated Wiki page: %{page_title}" + button_add: Add + button_change: Change + button_apply: Apply + button_clear: Clear + button_lock: Lock + button_unlock: Unlock + button_download: Download + button_list: List + button_view: View + button_move: Move + button_move_and_follow: Move and follow + button_back: Back + button_cancel: Cancel + button_activate: Activate + button_sort: Sort + button_log_time: Log time + button_rollback: Rollback to this version + button_watch: Watch + button_unwatch: Unwatch + button_reply: Reply + button_archive: Archive + button_unarchive: Unarchive + button_reset: Reset + button_rename: Rename + button_change_password: Change password + button_copy: Copy + button_copy_and_follow: Copy and follow + button_annotate: Annotate + button_update: Update + button_configure: Configure + button_quote: Quote + button_duplicate: Duplicate + button_show: Show + + status_active: active + status_registered: registered + status_locked: locked + + version_status_open: open + version_status_locked: locked + version_status_closed: closed + + field_active: Active + + text_select_mail_notifications: Select actions for which email notifications should be sent. + text_regexp_info: eg. ^[A-Z0-9]+$ + text_min_max_length_info: 0 means no restriction + text_project_destroy_confirmation: Are you sure you want to delete this project and related data? + text_subprojects_destroy_warning: "Its subproject(s): %{value} will be also deleted." + text_workflow_edit: Select a role and a tracker to edit the workflow + text_are_you_sure: Are you sure? + text_journal_changed: "%{label} changed from %{old} to %{new}" + text_journal_changed_no_detail: "%{label} updated" + text_journal_set_to: "%{label} set to %{value}" + text_journal_deleted: "%{label} deleted (%{old})" + text_journal_added: "%{label} %{value} added" + text_tip_issue_begin_day: task beginning this day + text_tip_issue_end_day: task ending this day + text_tip_issue_begin_end_day: task beginning and ending this day + text_project_identifier_info: 'Only lower case letters (a-z), numbers, dashes and underscores are allowed, must start with a lower case letter.
    Once saved, the identifier cannot be changed.' + text_caracters_maximum: "%{count} characters maximum." + text_caracters_minimum: "Must be at least %{count} characters long." + text_length_between: "Length between %{min} and %{max} characters." + text_tracker_no_workflow: No workflow defined for this tracker + text_unallowed_characters: Unallowed characters + text_comma_separated: Multiple values allowed (comma separated). + text_line_separated: Multiple values allowed (one line for each value). + text_issues_ref_in_commit_messages: Referencing and fixing issues in commit messages + text_issue_added: "Issue %{id} has been reported by %{author}." + text_issue_updated: "Issue %{id} has been updated by %{author}." + text_wiki_destroy_confirmation: Are you sure you want to delete this wiki and all its content? + text_issue_category_destroy_question: "Some issues (%{count}) are assigned to this category. What do you want to do?" + text_issue_category_destroy_assignments: Remove category assignments + text_issue_category_reassign_to: Reassign issues to this category + text_user_mail_option: "For unselected projects, you will only receive notifications about things you watch or you're involved in (eg. issues you're the author or assignee)." + text_no_configuration_data: "Roles, trackers, issue statuses and workflow have not been configured yet.\nIt is highly recommended to load the default configuration. You will be able to modify it once loaded." + text_load_default_configuration: Load the default configuration + text_status_changed_by_changeset: "Applied in changeset %{value}." + text_time_logged_by_changeset: "Applied in changeset %{value}." + text_issues_destroy_confirmation: 'Are you sure you want to delete the selected issue(s)?' + text_select_project_modules: 'Select modules to enable for this project:' + text_default_administrator_account_changed: Default administrator account changed + text_file_repository_writable: Attachments directory writable + text_plugin_assets_writable: Plugin assets directory writable + text_rmagick_available: RMagick available (optional) + text_destroy_time_entries_question: "%{hours} hours were reported on the issues you are about to delete. What do you want to do?" + text_destroy_time_entries: Delete reported hours + text_assign_time_entries_to_project: Assign reported hours to the project + text_reassign_time_entries: 'Reassign reported hours to this issue:' + text_user_wrote: "%{value} wrote:" + text_enumeration_destroy_question: "%{count} objects are assigned to this value." + text_enumeration_category_reassign_to: 'Reassign them to this value:' + text_email_delivery_not_configured: "Email delivery is not configured, and notifications are disabled.\nConfigure your SMTP server in config/configuration.yml and restart the application to enable them." + text_repository_usernames_mapping: "Select or update the Redmine user mapped to each username found in the repository log.\nUsers with the same Redmine and repository username or email are automatically mapped." + text_diff_truncated: '... This diff was truncated because it exceeds the maximum size that can be displayed.' + text_custom_field_possible_values_info: 'One line for each value' + text_wiki_page_destroy_question: "This page has %{descendants} child page(s) and descendant(s). What do you want to do?" + text_wiki_page_nullify_children: "Keep child pages as root pages" + text_wiki_page_destroy_children: "Delete child pages and all their descendants" + text_wiki_page_reassign_children: "Reassign child pages to this parent page" + text_own_membership_delete_confirmation: "You are about to remove some or all of your permissions and may no longer be able to edit this project after that.\nAre you sure you want to continue?" + text_zoom_in: Zoom in + text_zoom_out: Zoom out + text_warn_on_leaving_unsaved: "The current page contains unsaved text that will be lost if you leave this page." + + default_role_manager: Manager + default_role_developer: Developer + default_role_reporter: Reporter + default_tracker_bug: Bug + default_tracker_feature: Feature + default_tracker_support: Support + default_issue_status_new: New + default_issue_status_in_progress: In Progress + default_issue_status_resolved: Resolved + default_issue_status_feedback: Feedback + default_issue_status_closed: Closed + default_issue_status_rejected: Rejected + default_doc_category_user: User documentation + default_doc_category_tech: Technical documentation + default_priority_low: Low + default_priority_normal: Normal + default_priority_high: High + default_priority_urgent: Urgent + default_priority_immediate: Immediate + default_activity_design: Design + default_activity_development: Development + + enumeration_issue_priorities: Issue priorities + enumeration_doc_categories: Document categories + enumeration_activities: Activities (time tracking) + enumeration_system_activity: System Activity + label_additional_workflow_transitions_for_assignee: Additional transitions allowed when the user is the assignee + label_additional_workflow_transitions_for_author: Additional transitions allowed when the user is the author + label_bulk_edit_selected_time_entries: Bulk edit selected time entries + text_time_entries_destroy_confirmation: Are you sure you want to delete the selected time entr(y/ies)? + label_issue_note_added: Note added + label_issue_status_updated: Status updated + label_issue_priority_updated: Priority updated + label_issues_visibility_own: Issues created by or assigned to the user + field_issues_visibility: Issues visibility + label_issues_visibility_all: All issues + permission_set_own_issues_private: Set own issues public or private + field_is_private: Private + permission_set_issues_private: Set issues public or private + label_issues_visibility_public: All non private issues + text_issues_destroy_descendants_confirmation: This will also delete %{count} subtask(s). + field_commit_logs_encoding: Commit messages encoding + field_scm_path_encoding: Path encoding + text_scm_path_encoding_note: "Default: UTF-8" + field_path_to_repository: Path to repository + field_root_directory: Root directory + field_cvs_module: Module + field_cvsroot: CVSROOT + text_mercurial_repository_note: Local repository (e.g. /hgrepo, c:\hgrepo) + text_scm_command: Command + text_scm_command_version: Version + label_git_report_last_commit: Report last commit for files and directories + text_scm_config: You can configure your SCM commands in config/configuration.yml. Please restart the application after editing it. + text_scm_command_not_available: SCM command is not available. Please check settings on the administration panel. + notice_issue_successful_create: Issue %{id} created. + label_between: between + label_diff: diff + text_git_repository_note: Repository is bare and local (e.g. /gitrepo, c:\gitrepo) + description_query_sort_criteria_direction: Sort direction + description_project_scope: Search scope + description_filter: Filter + description_user_mail_notification: Mail notification settings + description_date_from: Enter start date + description_message_content: Message content + description_available_columns: Available Columns + description_date_range_interval: Choose range by selecting start and end date + description_issue_category_reassign: Choose issue category + description_search: Searchfield + description_notes: Notes + description_date_range_list: Choose range from list + description_choose_project: Projects + description_date_to: Enter end date + description_query_sort_criteria_attribute: Sort attribute + description_wiki_subpages_reassign: Choose new parent page + description_selected_columns: Selected Columns + label_parent_revision: Parent + label_child_revision: Child + button_edit_section: Edit this section + setting_repositories_encodings: Attachments and repositories encodings + description_all_columns: All Columns + button_export: Export + label_export_options: "%{export_format} export options" + error_attachment_too_big: This file cannot be uploaded because it exceeds the maximum allowed file size (%{max_size}) + notice_failed_to_save_time_entries: "Failed to save %{count} time entrie(s) on %{total} selected: %{ids}." + label_x_issues: + zero: 0 issue + one: 1 issue + other: "%{count} issues" + label_repository_new: New repository + field_repository_is_default: Main repository + label_copy_attachments: Copy attachments + label_item_position: "%{position} of %{count}" + label_completed_versions: Completed versions + field_multiple: Multiple values + setting_commit_cross_project_ref: Allow issues of all the other projects to be referenced and fixed + text_issue_conflict_resolution_add_notes: Add my notes and discard my other changes + text_issue_conflict_resolution_overwrite: Apply my changes anyway (previous notes will be kept but some changes may be overwritten) + notice_issue_update_conflict: The issue has been updated by an other user while you were editing it. + text_issue_conflict_resolution_cancel: Discard all my changes and redisplay %{link} + permission_manage_related_issues: Manage related issues + field_auth_source_ldap_filter: LDAP filter + label_search_for_watchers: Search for watchers to add + notice_account_deleted: Your account has been permanently deleted. + setting_unsubscribe: Allow users to delete their own account + button_delete_my_account: Delete my account + text_account_destroy_confirmation: |- + Are you sure you want to proceed? + Your account will be permanently deleted, with no way to reactivate it. + error_session_expired: Your session has expired. Please login again. + text_session_expiration_settings: "Warning: changing these settings may expire the current sessions including yours." + setting_session_lifetime: Session maximum lifetime + setting_session_timeout: Session inactivity timeout + label_session_expiration: Session expiration + permission_close_project: Close / reopen the project + label_show_closed_projects: View closed projects + button_close: Close + button_reopen: Reopen + project_status_active: active + project_status_closed: closed + project_status_archived: archived + text_project_closed: This project is closed and read-only. + notice_user_successful_create: User %{id} created. + field_core_fields: Standard fields + field_timeout: Timeout (in seconds) + setting_thumbnails_enabled: Display attachment thumbnails + setting_thumbnails_size: Thumbnails size (in pixels) + label_status_transitions: Status transitions + label_fields_permissions: Fields permissions + label_readonly: Read-only + label_required: Required + text_repository_identifier_info: 'Only lower case letters (a-z), numbers, dashes and underscores are allowed.
    Once saved, the identifier cannot be changed.' + field_board_parent: Parent forum + label_attribute_of_project: Project's %{name} + label_attribute_of_author: Author's %{name} + label_attribute_of_assigned_to: Assignee's %{name} + label_attribute_of_fixed_version: Target version's %{name} + label_copy_subtasks: Copy subtasks + label_copied_to: copied to + label_copied_from: copied from + label_any_issues_in_project: any issues in project + label_any_issues_not_in_project: any issues not in project + field_private_notes: Private notes + permission_view_private_notes: View private notes + permission_set_notes_private: Set notes as private + label_no_issues_in_project: no issues in project + label_any: all + label_last_n_weeks: last %{count} weeks + setting_cross_project_subtasks: Allow cross-project subtasks + label_cross_project_descendants: With subprojects + label_cross_project_tree: With project tree + label_cross_project_hierarchy: With project hierarchy + label_cross_project_system: With all projects + button_hide: Hide + setting_non_working_week_days: Non-working days + label_in_the_next_days: in the next + label_in_the_past_days: in the past + label_attribute_of_user: User's %{name} + text_turning_multiple_off: If you disable multiple values, multiple values will be + removed in order to preserve only one value per item. + label_attribute_of_issue: Issue's %{name} + permission_add_documents: Add documents + permission_edit_documents: Edit documents + permission_delete_documents: Delete documents + label_gantt_progress_line: Progress line + setting_jsonp_enabled: Enable JSONP support + field_inherit_members: Inherit members + field_closed_on: Closed + setting_default_projects_tracker_ids: Default trackers for new projects + label_total_time: Total diff --git a/config/locales/en.yml b/config/locales/en.yml new file mode 100644 index 00000000..135d078d --- /dev/null +++ b/config/locales/en.yml @@ -0,0 +1,1084 @@ +en: + # Text direction: Left-to-Right (ltr) or Right-to-Left (rtl) + direction: ltr + date: + formats: + # Use the strftime parameters for formats. + # When no format has been given, it uses default. + # You can provide other formats here if you like! + default: "%m/%d/%Y" + short: "%b %d" + long: "%B %d, %Y" + + day_names: [Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday] + abbr_day_names: [Sun, Mon, Tue, Wed, Thu, Fri, Sat] + + # Don't forget the nil at the beginning; there's no such thing as a 0th month + month_names: [~, January, February, March, April, May, June, July, August, September, October, November, December] + abbr_month_names: [~, Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec] + # Used in date_select and datime_select. + order: + - :year + - :month + - :day + + time: + formats: + default: "%m/%d/%Y %I:%M %p" + time: "%I:%M %p" + short: "%d %b %H:%M" + long: "%B %d, %Y %H:%M" + am: "am" + pm: "pm" + + datetime: + distance_in_words: + half_a_minute: "half a minute" + less_than_x_seconds: + one: "less than 1 second" + other: "less than %{count} seconds" + x_seconds: + one: "1 second" + other: "%{count} seconds" + less_than_x_minutes: + one: "less than a minute" + other: "less than %{count} minutes" + x_minutes: + one: "1 minute" + other: "%{count} minutes" + about_x_hours: + one: "about 1 hour" + other: "about %{count} hours" + x_hours: + one: "1 hour" + other: "%{count} hours" + x_days: + one: "1 day" + other: "%{count} days" + about_x_months: + one: "about 1 month" + other: "about %{count} months" + x_months: + one: "1 month" + other: "%{count} months" + about_x_years: + one: "about 1 year" + other: "about %{count} years" + over_x_years: + one: "over 1 year" + other: "over %{count} years" + almost_x_years: + one: "almost 1 year" + other: "almost %{count} years" + + number: + format: + separator: "." + delimiter: "" + precision: 3 + + human: + format: + delimiter: "" + precision: 3 + storage_units: + format: "%n %u" + units: + byte: + one: "Byte" + other: "Bytes" + kb: "KB" + mb: "MB" + gb: "GB" + tb: "TB" + +# Used in array.to_sentence. + support: + array: + sentence_connector: "and" + skip_last_comma: false + + activerecord: + errors: + template: + header: + one: "1 error prohibited this %{model} from being saved" + other: "%{count} errors prohibited this %{model} from being saved" + messages: + inclusion: "is not included in the list" + exclusion: "is reserved" + invalid: "is invalid" + confirmation: "doesn't match confirmation" + accepted: "must be accepted" + empty: "can't be empty" + blank: "can't be blank" + too_long: "is too long (maximum is %{count} characters)" + too_short: "is too short (minimum is %{count} characters)" + wrong_length: "is the wrong length (should be %{count} characters)" + taken: "has already been taken" + not_a_number: "is not a number" + not_a_date: "is not a valid date" + greater_than: "must be greater than %{count}" + greater_than_or_equal_to: "must be greater than or equal to %{count}" + equal_to: "must be equal to %{count}" + less_than: "must be less than %{count}" + less_than_or_equal_to: "must be less than or equal to %{count}" + odd: "must be odd" + even: "must be even" + greater_than_start_date: "must be greater than start date" + not_same_project: "doesn't belong to the same project" + circular_dependency: "This relation would create a circular dependency" + cant_link_an_issue_with_a_descendant: "An issue cannot be linked to one of its subtasks" + + actionview_instancetag_blank_option: Please select + + general_text_No: 'No' + general_text_Yes: 'Yes' + general_text_no: 'no' + general_text_yes: 'yes' + general_lang_name: 'English' + general_csv_separator: ',' + general_csv_decimal_separator: '.' + general_csv_encoding: ISO-8859-1 + general_pdf_encoding: UTF-8 + general_first_day_of_week: '7' + + notice_account_updated: Account was successfully updated. + notice_account_invalid_creditentials: Invalid user or password + notice_account_password_updated: Password was successfully updated. + notice_account_wrong_password: Wrong password + notice_account_register_done: Account was successfully created. To activate your account, click on the link that was emailed to you. + notice_account_unknown_email: Unknown user. + notice_can_t_change_password: This account uses an external authentication source. Impossible to change the password. + notice_account_lost_email_sent: An email with instructions to choose a new password has been sent to you. + notice_account_activated: Your account has been activated. You can now log in. + notice_successful_create: Successful creation. + notice_successful_update: Successful update. + notice_successful_delete: Successful deletion. + notice_successful_connection: Successful connection. + notice_file_not_found: The page you were trying to access doesn't exist or has been removed. + notice_locking_conflict: Data has been updated by another user. + notice_not_authorized: You are not authorized to access this page. + notice_not_authorized_archived_project: The project you're trying to access has been archived. + notice_email_sent: "An email was sent to %{value}" + notice_email_error: "An error occurred while sending mail (%{value})" + notice_feeds_access_key_reseted: Your RSS access key was reset. + notice_api_access_key_reseted: Your API access key was reset. + notice_failed_to_save_issues: "Failed to save %{count} issue(s) on %{total} selected: %{ids}." + notice_failed_to_save_time_entries: "Failed to save %{count} time entrie(s) on %{total} selected: %{ids}." + notice_failed_to_save_members: "Failed to save member(s): %{errors}." + notice_no_issue_selected: "No issue is selected! Please, check the issues you want to edit." + notice_account_pending: "Your account was created and is now pending administrator approval." + notice_default_data_loaded: Default configuration successfully loaded. + notice_unable_delete_version: Unable to delete version. + notice_unable_delete_time_entry: Unable to delete time log entry. + notice_issue_done_ratios_updated: Issue done ratios updated. + notice_gantt_chart_truncated: "The chart was truncated because it exceeds the maximum number of items that can be displayed (%{max})" + notice_issue_successful_create: "Issue %{id} created." + notice_issue_update_conflict: "The issue has been updated by an other user while you were editing it." + notice_account_deleted: "Your account has been permanently deleted." + notice_user_successful_create: "User %{id} created." + + error_can_t_load_default_data: "Default configuration could not be loaded: %{value}" + error_scm_not_found: "The entry or revision was not found in the repository." + error_scm_command_failed: "An error occurred when trying to access the repository: %{value}" + error_scm_annotate: "The entry does not exist or cannot be annotated." + error_scm_annotate_big_text_file: "The entry cannot be annotated, as it exceeds the maximum text file size." + error_issue_not_found_in_project: 'The issue was not found or does not belong to this project' + error_no_tracker_in_project: 'No tracker is associated to this project. Please check the Project settings.' + error_no_default_issue_status: 'No default issue status is defined. Please check your configuration (Go to "Administration -> Issue statuses").' + error_can_not_delete_custom_field: Unable to delete custom field + error_can_not_delete_tracker: "This tracker contains issues and cannot be deleted." + error_can_not_remove_role: "This role is in use and cannot be deleted." + error_can_not_reopen_issue_on_closed_version: 'An issue assigned to a closed version cannot be reopened' + error_can_not_archive_project: This project cannot be archived + error_issue_done_ratios_not_updated: "Issue done ratios not updated." + error_workflow_copy_source: 'Please select a source tracker or role' + error_workflow_copy_target: 'Please select target tracker(s) and role(s)' + error_unable_delete_issue_status: 'Unable to delete issue status' + error_unable_to_connect: "Unable to connect (%{value})" + error_attachment_too_big: "This file cannot be uploaded because it exceeds the maximum allowed file size (%{max_size})" + error_session_expired: "Your session has expired. Please login again." + warning_attachments_not_saved: "%{count} file(s) could not be saved." + + mail_subject_lost_password: "Your %{value} password" + mail_body_lost_password: 'To change your password, click on the following link:' + mail_subject_register: "Your %{value} account activation" + mail_body_register: 'To activate your account, click on the following link:' + mail_body_account_information_external: "You can use your %{value} account to log in." + mail_body_account_information: Your account information + mail_subject_account_activation_request: "%{value} account activation request" + mail_body_account_activation_request: "A new user (%{value}) has registered. The account is pending your approval:" + mail_subject_reminder: "%{count} issue(s) due in the next %{days} days" + mail_body_reminder: "%{count} issue(s) that are assigned to you are due in the next %{days} days:" + mail_subject_wiki_content_added: "'%{id}' wiki page has been added" + mail_body_wiki_content_added: "The '%{id}' wiki page has been added by %{author}." + mail_subject_wiki_content_updated: "'%{id}' wiki page has been updated" + mail_body_wiki_content_updated: "The '%{id}' wiki page has been updated by %{author}." + + field_name: Name + field_description: Description + field_summary: Summary + field_is_required: Required + field_firstname: First name + field_lastname: Last name + field_mail: Email + field_filename: File + field_filesize: Size + field_downloads: Downloads + field_author: Author + field_created_on: Created + field_updated_on: Updated + field_closed_on: Closed + field_field_format: Format + field_is_for_all: For all projects + field_possible_values: Possible values + field_regexp: Regular expression + field_min_length: Minimum length + field_max_length: Maximum length + field_value: Value + field_category: Category + field_title: Title + field_project: Project + field_issue: Issue + field_status: Status + field_notes: Notes + field_is_closed: Issue closed + field_is_default: Default value + field_tracker: Tracker + field_subject: Subject + field_due_date: Due date + field_assigned_to: Assignee + field_priority: Priority + field_fixed_version: Target version + field_user: User + field_principal: Principal + field_role: Role + field_homepage: Homepage + field_is_public: Public + field_parent: Subproject of + field_is_in_roadmap: Issues displayed in roadmap + field_login: Login + field_mail_notification: Email notifications + field_admin: Administrator + field_last_login_on: Last connection + field_language: Language + field_effective_date: Date + field_password: Password + field_new_password: New password + field_password_confirmation: Confirmation + field_version: Version + field_type: Type + field_host: Host + field_port: Port + field_account: Account + field_base_dn: Base DN + field_attr_login: Login attribute + field_attr_firstname: Firstname attribute + field_attr_lastname: Lastname attribute + field_attr_mail: Email attribute + field_onthefly: On-the-fly user creation + field_start_date: Start date + field_done_ratio: "% Done" + field_auth_source: Authentication mode + field_hide_mail: Hide my email address + field_comments: Comment + field_url: URL + field_start_page: Start page + field_subproject: Subproject + field_hours: Hours + field_activity: Activity + field_spent_on: Date + field_identifier: Identifier + field_is_filter: Used as a filter + field_issue_to: Related issue + field_delay: Delay + field_assignable: Issues can be assigned to this role + field_redirect_existing_links: Redirect existing links + field_estimated_hours: Estimated time + field_column_names: Columns + field_time_entries: Log time + field_time_zone: Time zone + field_searchable: Searchable + field_default_value: Default value + field_comments_sorting: Display comments + field_parent_title: Parent page + field_editable: Editable + field_watcher: Watcher + field_identity_url: OpenID URL + field_content: Content + field_group_by: Group results by + field_sharing: Sharing + field_parent_issue: Parent task + field_member_of_group: "Assignee's group" + field_assigned_to_role: "Assignee's role" + field_text: Text field + field_visible: Visible + field_warn_on_leaving_unsaved: "Warn me when leaving a page with unsaved text" + field_issues_visibility: Issues visibility + field_is_private: Private + field_commit_logs_encoding: Commit messages encoding + field_scm_path_encoding: Path encoding + field_path_to_repository: Path to repository + field_root_directory: Root directory + field_cvsroot: CVSROOT + field_cvs_module: Module + field_repository_is_default: Main repository + field_multiple: Multiple values + field_auth_source_ldap_filter: LDAP filter + field_core_fields: Standard fields + field_timeout: "Timeout (in seconds)" + field_board_parent: Parent forum + field_private_notes: Private notes + field_inherit_members: Inherit members + + setting_app_title: Application title + setting_app_subtitle: Application subtitle + setting_welcome_text: Welcome text + setting_default_language: Default language + setting_login_required: Authentication required + setting_self_registration: Self-registration + setting_attachment_max_size: Maximum attachment size + setting_issues_export_limit: Issues export limit + setting_mail_from: Emission email address + setting_bcc_recipients: Blind carbon copy recipients (bcc) + setting_plain_text_mail: Plain text mail (no HTML) + setting_host_name: Host name and path + setting_text_formatting: Text formatting + setting_wiki_compression: Wiki history compression + setting_feeds_limit: Maximum number of items in Atom feeds + setting_default_projects_public: New projects are public by default + setting_autofetch_changesets: Fetch commits automatically + setting_sys_api_enabled: Enable WS for repository management + setting_commit_ref_keywords: Referencing keywords + setting_commit_fix_keywords: Fixing keywords + setting_autologin: Autologin + setting_date_format: Date format + setting_time_format: Time format + setting_cross_project_issue_relations: Allow cross-project issue relations + setting_cross_project_subtasks: Allow cross-project subtasks + setting_issue_list_default_columns: Default columns displayed on the issue list + setting_repositories_encodings: Attachments and repositories encodings + setting_emails_header: Email header + setting_emails_footer: Email footer + setting_protocol: Protocol + setting_per_page_options: Objects per page options + setting_user_format: Users display format + setting_activity_days_default: Days displayed on project activity + setting_display_subprojects_issues: Display subprojects issues on main projects by default + setting_enabled_scm: Enabled SCM + setting_mail_handler_body_delimiters: "Truncate emails after one of these lines" + setting_mail_handler_api_enabled: Enable WS for incoming emails + setting_mail_handler_api_key: API key + setting_sequential_project_identifiers: Generate sequential project identifiers + setting_gravatar_enabled: Use Gravatar user icons + setting_gravatar_default: Default Gravatar image + setting_diff_max_lines_displayed: Maximum number of diff lines displayed + setting_file_max_size_displayed: Maximum size of text files displayed inline + setting_repository_log_display_limit: Maximum number of revisions displayed on file log + setting_openid: Allow OpenID login and registration + setting_password_min_length: Minimum password length + setting_new_project_user_role_id: Role given to a non-admin user who creates a project + setting_default_projects_modules: Default enabled modules for new projects + setting_issue_done_ratio: Calculate the issue done ratio with + setting_issue_done_ratio_issue_field: Use the issue field + setting_issue_done_ratio_issue_status: Use the issue status + setting_start_of_week: Start calendars on + setting_rest_api_enabled: Enable REST web service + setting_cache_formatted_text: Cache formatted text + setting_default_notification_option: Default notification option + setting_commit_logtime_enabled: Enable time logging + setting_commit_logtime_activity_id: Activity for logged time + setting_gantt_items_limit: Maximum number of items displayed on the gantt chart + setting_issue_group_assignment: Allow issue assignment to groups + setting_default_issue_start_date_to_creation_date: Use current date as start date for new issues + setting_commit_cross_project_ref: Allow issues of all the other projects to be referenced and fixed + setting_unsubscribe: Allow users to delete their own account + setting_session_lifetime: Session maximum lifetime + setting_session_timeout: Session inactivity timeout + setting_thumbnails_enabled: Display attachment thumbnails + setting_thumbnails_size: Thumbnails size (in pixels) + setting_non_working_week_days: Non-working days + setting_jsonp_enabled: Enable JSONP support + setting_default_projects_tracker_ids: Default trackers for new projects + + permission_add_project: Create project + permission_add_subprojects: Create subprojects + permission_edit_project: Edit project + permission_close_project: Close / reopen the project + permission_select_project_modules: Select project modules + permission_manage_members: Manage members + permission_manage_project_activities: Manage project activities + permission_manage_versions: Manage versions + permission_manage_categories: Manage issue categories + permission_view_issues: View Issues + permission_add_issues: Add issues + permission_edit_issues: Edit issues + permission_manage_issue_relations: Manage issue relations + permission_set_issues_private: Set issues public or private + permission_set_own_issues_private: Set own issues public or private + permission_add_issue_notes: Add notes + permission_edit_issue_notes: Edit notes + permission_edit_own_issue_notes: Edit own notes + permission_view_private_notes: View private notes + permission_set_notes_private: Set notes as private + permission_move_issues: Move issues + permission_delete_issues: Delete issues + permission_manage_public_queries: Manage public queries + permission_save_queries: Save queries + permission_view_gantt: View gantt chart + permission_view_calendar: View calendar + permission_view_issue_watchers: View watchers list + permission_add_issue_watchers: Add watchers + permission_delete_issue_watchers: Delete watchers + permission_log_time: Log spent time + permission_view_time_entries: View spent time + permission_edit_time_entries: Edit time logs + permission_edit_own_time_entries: Edit own time logs + permission_manage_news: Manage news + permission_comment_news: Comment news + permission_view_documents: View documents + permission_add_documents: Add documents + permission_edit_documents: Edit documents + permission_delete_documents: Delete documents + permission_manage_files: Manage files + permission_view_files: View files + permission_manage_wiki: Manage wiki + permission_rename_wiki_pages: Rename wiki pages + permission_delete_wiki_pages: Delete wiki pages + permission_view_wiki_pages: View wiki + permission_view_wiki_edits: View wiki history + permission_edit_wiki_pages: Edit wiki pages + permission_delete_wiki_pages_attachments: Delete attachments + permission_protect_wiki_pages: Protect wiki pages + permission_manage_repository: Manage repository + permission_browse_repository: Browse repository + permission_view_changesets: View changesets + permission_commit_access: Commit access + permission_manage_boards: Manage forums + permission_view_messages: View messages + permission_add_messages: Post messages + permission_edit_messages: Edit messages + permission_edit_own_messages: Edit own messages + permission_delete_messages: Delete messages + permission_delete_own_messages: Delete own messages + permission_export_wiki_pages: Export wiki pages + permission_manage_subtasks: Manage subtasks + permission_manage_related_issues: Manage related issues + + project_module_issue_tracking: Issue tracking + project_module_time_tracking: Time tracking + project_module_news: News + project_module_documents: Documents + project_module_files: Files + project_module_wiki: Wiki + project_module_repository: Repository + project_module_boards: Forums + project_module_calendar: Calendar + project_module_gantt: Gantt + + label_user: User + label_user_plural: Users + label_user_new: New user + label_user_anonymous: Anonymous + label_project: Project + label_project_new: New project + label_project_plural: Projects + label_x_projects: + zero: no projects + one: 1 project + other: "%{count} projects" + label_project_all: All Projects + label_project_latest: Latest projects + label_issue: Issue + label_issue_new: New issue + label_issue_plural: Issues + label_issue_view_all: View all issues + label_issues_by: "Issues by %{value}" + label_issue_added: Issue added + label_issue_updated: Issue updated + label_issue_note_added: Note added + label_issue_status_updated: Status updated + label_issue_priority_updated: Priority updated + label_document: Document + label_document_new: New document + label_document_plural: Documents + label_document_added: Document added + label_role: Role + label_role_plural: Roles + label_role_new: New role + label_role_and_permissions: Roles and permissions + label_role_anonymous: Anonymous + label_role_non_member: Non member + label_member: Member + label_member_new: New member + label_member_plural: Members + label_tracker: Tracker + label_tracker_plural: Trackers + label_tracker_new: New tracker + label_workflow: Workflow + label_issue_status: Issue status + label_issue_status_plural: Issue statuses + label_issue_status_new: New status + label_issue_category: Issue category + label_issue_category_plural: Issue categories + label_issue_category_new: New category + label_custom_field: Custom field + label_custom_field_plural: Custom fields + label_custom_field_new: New custom field + label_enumerations: Enumerations + label_enumeration_new: New value + label_information: Information + label_information_plural: Information + label_please_login: Please log in + label_register: Register + label_login_with_open_id_option: or login with OpenID + label_password_lost: Lost password + label_home: Home + label_my_page: My page + label_my_account: My account + label_my_projects: My projects + label_my_page_block: My page block + label_administration: Administration + label_login: Sign in + label_logout: Sign out + label_help: Help + label_reported_issues: Reported issues + label_assigned_to_me_issues: Issues assigned to me + label_last_login: Last connection + label_registered_on: Registered on + label_activity: Activity + label_overall_activity: Overall activity + label_user_activity: "%{value}'s activity" + label_new: New + label_logged_as: Logged in as + label_environment: Environment + label_authentication: Authentication + label_auth_source: Authentication mode + label_auth_source_new: New authentication mode + label_auth_source_plural: Authentication modes + label_subproject_plural: Subprojects + label_subproject_new: New subproject + label_and_its_subprojects: "%{value} and its subprojects" + label_min_max_length: Min - Max length + label_list: List + label_date: Date + label_integer: Integer + label_float: Float + label_boolean: Boolean + label_string: Text + label_text: Long text + label_attribute: Attribute + label_attribute_plural: Attributes + label_no_data: No data to display + label_change_status: Change status + label_history: History + label_attachment: File + label_attachment_new: New file + label_attachment_delete: Delete file + label_attachment_plural: Files + label_file_added: File added + label_report: Report + label_report_plural: Reports + label_news: News + label_news_new: Add news + label_news_plural: News + label_news_latest: Latest news + label_news_view_all: View all news + label_news_added: News added + label_news_comment_added: Comment added to a news + label_settings: Settings + label_overview: Overview + label_version: Version + label_version_new: New version + label_version_plural: Versions + label_close_versions: Close completed versions + label_confirmation: Confirmation + label_export_to: 'Also available in:' + label_read: Read... + label_public_projects: Public projects + label_open_issues: open + label_open_issues_plural: open + label_closed_issues: closed + label_closed_issues_plural: closed + label_x_open_issues_abbr_on_total: + zero: 0 open / %{total} + one: 1 open / %{total} + other: "%{count} open / %{total}" + label_x_open_issues_abbr: + zero: 0 open + one: 1 open + other: "%{count} open" + label_x_closed_issues_abbr: + zero: 0 closed + one: 1 closed + other: "%{count} closed" + label_x_issues: + zero: 0 issues + one: 1 issue + other: "%{count} issues" + label_total: Total + label_total_time: Total time + label_permissions: Permissions + label_current_status: Current status + label_new_statuses_allowed: New statuses allowed + label_all: all + label_any: any + label_none: none + label_nobody: nobody + label_next: Next + label_previous: Previous + label_used_by: Used by + label_details: Details + label_add_note: Add a note + label_per_page: Per page + label_calendar: Calendar + label_months_from: months from + label_gantt: Gantt + label_internal: Internal + label_last_changes: "last %{count} changes" + label_change_view_all: View all changes + label_personalize_page: Personalize this page + label_comment: Comment + label_comment_plural: Comments + label_x_comments: + zero: no comments + one: 1 comment + other: "%{count} comments" + label_comment_add: Add a comment + label_comment_added: Comment added + label_comment_delete: Delete comments + label_query: Custom query + label_query_plural: Custom queries + label_query_new: New query + label_my_queries: My custom queries + label_filter_add: Add filter + label_filter_plural: Filters + label_equals: is + label_not_equals: is not + label_in_less_than: in less than + label_in_more_than: in more than + label_in_the_next_days: in the next + label_in_the_past_days: in the past + label_greater_or_equal: '>=' + label_less_or_equal: '<=' + label_between: between + label_in: in + label_today: today + label_all_time: all time + label_yesterday: yesterday + label_this_week: this week + label_last_week: last week + label_last_n_weeks: "last %{count} weeks" + label_last_n_days: "last %{count} days" + label_this_month: this month + label_last_month: last month + label_this_year: this year + label_date_range: Date range + label_less_than_ago: less than days ago + label_more_than_ago: more than days ago + label_ago: days ago + label_contains: contains + label_not_contains: doesn't contain + label_any_issues_in_project: any issues in project + label_any_issues_not_in_project: any issues not in project + label_no_issues_in_project: no issues in project + label_day_plural: days + label_repository: Repository + label_repository_new: New repository + label_repository_plural: Repositories + label_browse: Browse + label_branch: Branch + label_tag: Tag + label_revision: Revision + label_revision_plural: Revisions + label_revision_id: "Revision %{value}" + label_associated_revisions: Associated revisions + label_added: added + label_modified: modified + label_copied: copied + label_renamed: renamed + label_deleted: deleted + label_latest_revision: Latest revision + label_latest_revision_plural: Latest revisions + label_view_revisions: View revisions + label_view_all_revisions: View all revisions + label_max_size: Maximum size + label_sort_highest: Move to top + label_sort_higher: Move up + label_sort_lower: Move down + label_sort_lowest: Move to bottom + label_roadmap: Roadmap + label_roadmap_due_in: "Due in %{value}" + label_roadmap_overdue: "%{value} late" + label_roadmap_no_issues: No issues for this version + label_search: Search + label_result_plural: Results + label_all_words: All words + label_wiki: Wiki + label_wiki_edit: Wiki edit + label_wiki_edit_plural: Wiki edits + label_wiki_page: Wiki page + label_wiki_page_plural: Wiki pages + label_index_by_title: Index by title + label_index_by_date: Index by date + label_current_version: Current version + label_preview: Preview + label_feed_plural: Feeds + label_changes_details: Details of all changes + label_issue_tracking: Issue tracking + label_spent_time: Spent time + label_overall_spent_time: Overall spent time + label_f_hour: "%{value} hour" + label_f_hour_plural: "%{value} hours" + label_time_tracking: Time tracking + label_change_plural: Changes + label_statistics: Statistics + label_commits_per_month: Commits per month + label_commits_per_author: Commits per author + label_diff: diff + label_view_diff: View differences + label_diff_inline: inline + label_diff_side_by_side: side by side + label_options: Options + label_copy_workflow_from: Copy workflow from + label_permissions_report: Permissions report + label_watched_issues: Watched issues + label_related_issues: Related issues + label_applied_status: Applied status + label_loading: Loading... + label_relation_new: New relation + label_relation_delete: Delete relation + label_relates_to: Related to + label_duplicates: Duplicates + label_duplicated_by: Duplicated by + label_blocks: Blocks + label_blocked_by: Blocked by + label_precedes: Precedes + label_follows: Follows + label_copied_to: Copied to + label_copied_from: Copied from + label_end_to_start: end to start + label_end_to_end: end to end + label_start_to_start: start to start + label_start_to_end: start to end + label_stay_logged_in: Stay logged in + label_disabled: disabled + label_show_completed_versions: Show completed versions + label_me: me + label_board: Forum + label_board_new: New forum + label_board_plural: Forums + label_board_locked: Locked + label_board_sticky: Sticky + label_topic_plural: Topics + label_message_plural: Messages + label_message_last: Last message + label_message_new: New message + label_message_posted: Message added + label_reply_plural: Replies + label_send_information: Send account information to the user + label_year: Year + label_month: Month + label_week: Week + label_date_from: From + label_date_to: To + label_language_based: Based on user's language + label_sort_by: "Sort by %{value}" + label_send_test_email: Send a test email + label_feeds_access_key: RSS access key + label_missing_feeds_access_key: Missing a RSS access key + label_feeds_access_key_created_on: "RSS access key created %{value} ago" + label_module_plural: Modules + label_added_time_by: "Added by %{author} %{age} ago" + label_updated_time_by: "Updated by %{author} %{age} ago" + label_updated_time: "Updated %{value} ago" + label_jump_to_a_project: Jump to a project... + label_file_plural: Files + label_changeset_plural: Changesets + label_default_columns: Default columns + label_no_change_option: (No change) + label_bulk_edit_selected_issues: Bulk edit selected issues + label_bulk_edit_selected_time_entries: Bulk edit selected time entries + label_theme: Theme + label_default: Default + label_search_titles_only: Search titles only + label_user_mail_option_all: "For any event on all my projects" + label_user_mail_option_selected: "For any event on the selected projects only..." + label_user_mail_option_none: "No events" + label_user_mail_option_only_my_events: "Only for things I watch or I'm involved in" + label_user_mail_option_only_assigned: "Only for things I am assigned to" + label_user_mail_option_only_owner: "Only for things I am the owner of" + label_user_mail_no_self_notified: "I don't want to be notified of changes that I make myself" + label_registration_activation_by_email: account activation by email + label_registration_manual_activation: manual account activation + label_registration_automatic_activation: automatic account activation + label_display_per_page: "Per page: %{value}" + label_age: Age + label_change_properties: Change properties + label_general: General + label_more: More + label_scm: SCM + label_plugins: Plugins + label_ldap_authentication: LDAP authentication + label_downloads_abbr: D/L + label_optional_description: Optional description + label_add_another_file: Add another file + label_preferences: Preferences + label_chronological_order: In chronological order + label_reverse_chronological_order: In reverse chronological order + label_planning: Planning + label_incoming_emails: Incoming emails + label_generate_key: Generate a key + label_issue_watchers: Watchers + label_example: Example + label_display: Display + label_sort: Sort + label_ascending: Ascending + label_descending: Descending + label_date_from_to: From %{start} to %{end} + label_wiki_content_added: Wiki page added + label_wiki_content_updated: Wiki page updated + label_group: Group + label_group_plural: Groups + label_group_new: New group + label_time_entry_plural: Spent time + label_version_sharing_none: Not shared + label_version_sharing_descendants: With subprojects + label_version_sharing_hierarchy: With project hierarchy + label_version_sharing_tree: With project tree + label_version_sharing_system: With all projects + label_update_issue_done_ratios: Update issue done ratios + label_copy_source: Source + label_copy_target: Target + label_copy_same_as_target: Same as target + label_display_used_statuses_only: Only display statuses that are used by this tracker + label_api_access_key: API access key + label_missing_api_access_key: Missing an API access key + label_api_access_key_created_on: "API access key created %{value} ago" + label_profile: Profile + label_subtask_plural: Subtasks + label_project_copy_notifications: Send email notifications during the project copy + label_principal_search: "Search for user or group:" + label_user_search: "Search for user:" + label_additional_workflow_transitions_for_author: Additional transitions allowed when the user is the author + label_additional_workflow_transitions_for_assignee: Additional transitions allowed when the user is the assignee + label_issues_visibility_all: All issues + label_issues_visibility_public: All non private issues + label_issues_visibility_own: Issues created by or assigned to the user + label_git_report_last_commit: Report last commit for files and directories + label_parent_revision: Parent + label_child_revision: Child + label_export_options: "%{export_format} export options" + label_copy_attachments: Copy attachments + label_copy_subtasks: Copy subtasks + label_item_position: "%{position} of %{count}" + label_completed_versions: Completed versions + label_search_for_watchers: Search for watchers to add + label_session_expiration: Session expiration + label_show_closed_projects: View closed projects + label_status_transitions: Status transitions + label_fields_permissions: Fields permissions + label_readonly: Read-only + label_required: Required + label_attribute_of_project: "Project's %{name}" + label_attribute_of_issue: "Issue's %{name}" + label_attribute_of_author: "Author's %{name}" + label_attribute_of_assigned_to: "Assignee's %{name}" + label_attribute_of_user: "User's %{name}" + label_attribute_of_fixed_version: "Target version's %{name}" + label_cross_project_descendants: With subprojects + label_cross_project_tree: With project tree + label_cross_project_hierarchy: With project hierarchy + label_cross_project_system: With all projects + label_gantt_progress_line: Progress line + + button_login: Login + button_submit: Submit + button_save: Save + button_check_all: Check all + button_uncheck_all: Uncheck all + button_collapse_all: Collapse all + button_expand_all: Expand all + button_delete: Delete + button_create: Create + button_create_and_continue: Create and continue + button_test: Test + button_edit: Edit + button_edit_associated_wikipage: "Edit associated Wiki page: %{page_title}" + button_add: Add + button_change: Change + button_apply: Apply + button_clear: Clear + button_lock: Lock + button_unlock: Unlock + button_download: Download + button_list: List + button_view: View + button_move: Move + button_move_and_follow: Move and follow + button_back: Back + button_cancel: Cancel + button_activate: Activate + button_sort: Sort + button_log_time: Log time + button_rollback: Rollback to this version + button_watch: Watch + button_unwatch: Unwatch + button_reply: Reply + button_archive: Archive + button_unarchive: Unarchive + button_reset: Reset + button_rename: Rename + button_change_password: Change password + button_copy: Copy + button_copy_and_follow: Copy and follow + button_annotate: Annotate + button_update: Update + button_configure: Configure + button_quote: Quote + button_duplicate: Duplicate + button_show: Show + button_hide: Hide + button_edit_section: Edit this section + button_export: Export + button_delete_my_account: Delete my account + button_close: Close + button_reopen: Reopen + + status_active: active + status_registered: registered + status_locked: locked + + project_status_active: active + project_status_closed: closed + project_status_archived: archived + + version_status_open: open + version_status_locked: locked + version_status_closed: closed + + field_active: Active + + text_select_mail_notifications: Select actions for which email notifications should be sent. + text_regexp_info: eg. ^[A-Z0-9]+$ + text_min_max_length_info: 0 means no restriction + text_project_destroy_confirmation: Are you sure you want to delete this project and related data? + text_subprojects_destroy_warning: "Its subproject(s): %{value} will be also deleted." + text_workflow_edit: Select a role and a tracker to edit the workflow + text_are_you_sure: Are you sure? + text_journal_changed: "%{label} changed from %{old} to %{new}" + text_journal_changed_no_detail: "%{label} updated" + text_journal_set_to: "%{label} set to %{value}" + text_journal_deleted: "%{label} deleted (%{old})" + text_journal_added: "%{label} %{value} added" + text_tip_issue_begin_day: issue beginning this day + text_tip_issue_end_day: issue ending this day + text_tip_issue_begin_end_day: issue beginning and ending this day + text_project_identifier_info: 'Only lower case letters (a-z), numbers, dashes and underscores are allowed, must start with a lower case letter.
    Once saved, the identifier cannot be changed.' + text_caracters_maximum: "%{count} characters maximum." + text_caracters_minimum: "Must be at least %{count} characters long." + text_length_between: "Length between %{min} and %{max} characters." + text_tracker_no_workflow: No workflow defined for this tracker + text_unallowed_characters: Unallowed characters + text_comma_separated: Multiple values allowed (comma separated). + text_line_separated: Multiple values allowed (one line for each value). + text_issues_ref_in_commit_messages: Referencing and fixing issues in commit messages + text_issue_added: "Issue %{id} has been reported by %{author}." + text_issue_updated: "Issue %{id} has been updated by %{author}." + text_wiki_destroy_confirmation: Are you sure you want to delete this wiki and all its content? + text_issue_category_destroy_question: "Some issues (%{count}) are assigned to this category. What do you want to do?" + text_issue_category_destroy_assignments: Remove category assignments + text_issue_category_reassign_to: Reassign issues to this category + text_user_mail_option: "For unselected projects, you will only receive notifications about things you watch or you're involved in (eg. issues you're the author or assignee)." + text_no_configuration_data: "Roles, trackers, issue statuses and workflow have not been configured yet.\nIt is highly recommended to load the default configuration. You will be able to modify it once loaded." + text_load_default_configuration: Load the default configuration + text_status_changed_by_changeset: "Applied in changeset %{value}." + text_time_logged_by_changeset: "Applied in changeset %{value}." + text_issues_destroy_confirmation: 'Are you sure you want to delete the selected issue(s)?' + text_issues_destroy_descendants_confirmation: "This will also delete %{count} subtask(s)." + text_time_entries_destroy_confirmation: 'Are you sure you want to delete the selected time entr(y/ies)?' + text_select_project_modules: 'Select modules to enable for this project:' + text_default_administrator_account_changed: Default administrator account changed + text_file_repository_writable: Attachments directory writable + text_plugin_assets_writable: Plugin assets directory writable + text_rmagick_available: RMagick available (optional) + text_destroy_time_entries_question: "%{hours} hours were reported on the issues you are about to delete. What do you want to do?" + text_destroy_time_entries: Delete reported hours + text_assign_time_entries_to_project: Assign reported hours to the project + text_reassign_time_entries: 'Reassign reported hours to this issue:' + text_user_wrote: "%{value} wrote:" + text_enumeration_destroy_question: "%{count} objects are assigned to this value." + text_enumeration_category_reassign_to: 'Reassign them to this value:' + text_email_delivery_not_configured: "Email delivery is not configured, and notifications are disabled.\nConfigure your SMTP server in config/configuration.yml and restart the application to enable them." + text_repository_usernames_mapping: "Select or update the Redmine user mapped to each username found in the repository log.\nUsers with the same Redmine and repository username or email are automatically mapped." + text_diff_truncated: '... This diff was truncated because it exceeds the maximum size that can be displayed.' + text_custom_field_possible_values_info: 'One line for each value' + text_wiki_page_destroy_question: "This page has %{descendants} child page(s) and descendant(s). What do you want to do?" + text_wiki_page_nullify_children: "Keep child pages as root pages" + text_wiki_page_destroy_children: "Delete child pages and all their descendants" + text_wiki_page_reassign_children: "Reassign child pages to this parent page" + text_own_membership_delete_confirmation: "You are about to remove some or all of your permissions and may no longer be able to edit this project after that.\nAre you sure you want to continue?" + text_zoom_in: Zoom in + text_zoom_out: Zoom out + text_warn_on_leaving_unsaved: "The current page contains unsaved text that will be lost if you leave this page." + text_scm_path_encoding_note: "Default: UTF-8" + text_git_repository_note: Repository is bare and local (e.g. /gitrepo, c:\gitrepo) + text_mercurial_repository_note: Local repository (e.g. /hgrepo, c:\hgrepo) + text_scm_command: Command + text_scm_command_version: Version + text_scm_config: You can configure your SCM commands in config/configuration.yml. Please restart the application after editing it. + text_scm_command_not_available: SCM command is not available. Please check settings on the administration panel. + text_issue_conflict_resolution_overwrite: "Apply my changes anyway (previous notes will be kept but some changes may be overwritten)" + text_issue_conflict_resolution_add_notes: "Add my notes and discard my other changes" + text_issue_conflict_resolution_cancel: "Discard all my changes and redisplay %{link}" + text_account_destroy_confirmation: "Are you sure you want to proceed?\nYour account will be permanently deleted, with no way to reactivate it." + text_session_expiration_settings: "Warning: changing these settings may expire the current sessions including yours." + text_project_closed: This project is closed and read-only. + text_turning_multiple_off: "If you disable multiple values, multiple values will be removed in order to preserve only one value per item." + + default_role_manager: Manager + default_role_developer: Developer + default_role_reporter: Reporter + default_tracker_bug: Bug + default_tracker_feature: Feature + default_tracker_support: Support + default_issue_status_new: New + default_issue_status_in_progress: In Progress + default_issue_status_resolved: Resolved + default_issue_status_feedback: Feedback + default_issue_status_closed: Closed + default_issue_status_rejected: Rejected + default_doc_category_user: User documentation + default_doc_category_tech: Technical documentation + default_priority_low: Low + default_priority_normal: Normal + default_priority_high: High + default_priority_urgent: Urgent + default_priority_immediate: Immediate + default_activity_design: Design + default_activity_development: Development + + enumeration_issue_priorities: Issue priorities + enumeration_doc_categories: Document categories + enumeration_activities: Activities (time tracking) + enumeration_system_activity: System Activity + description_filter: Filter + description_search: Searchfield + description_choose_project: Projects + description_project_scope: Search scope + description_notes: Notes + description_message_content: Message content + description_query_sort_criteria_attribute: Sort attribute + description_query_sort_criteria_direction: Sort direction + description_user_mail_notification: Mail notification settings + description_available_columns: Available Columns + description_selected_columns: Selected Columns + description_all_columns: All Columns + description_issue_category_reassign: Choose issue category + description_wiki_subpages_reassign: Choose new parent page + description_date_range_list: Choose range from list + description_date_range_interval: Choose range by selecting start and end date + description_date_from: Enter start date + description_date_to: Enter end date + text_repository_identifier_info: 'Only lower case letters (a-z), numbers, dashes and underscores are allowed.
    Once saved, the identifier cannot be changed.' diff --git a/config/locales/es.yml b/config/locales/es.yml new file mode 100644 index 00000000..2ec4fef2 --- /dev/null +++ b/config/locales/es.yml @@ -0,0 +1,1125 @@ +# Spanish translations for Rails +# by Francisco Fernando García Nieto (ffgarcianieto@gmail.com) +# Redmine spanish translation: +# by J. Cayetano Delgado (Cayetano _dot_ Delgado _at_ ioko _dot_ com) + +es: + number: + # Used in number_with_delimiter() + # These are also the defaults for 'currency', 'percentage', 'precision', and 'human' + format: + # Sets the separator between the units, for more precision (e.g. 1.0 / 2.0 == 0.5) + separator: "," + # Delimets thousands (e.g. 1,000,000 is a million) (always in groups of three) + delimiter: "." + # Number of decimals, behind the separator (1 with a precision of 2 gives: 1.00) + precision: 3 + + # Used in number_to_currency() + currency: + format: + # Where is the currency sign? %u is the currency unit, %n the number (default: $5.00) + format: "%n %u" + unit: "€" + # These three are to override number.format and are optional + separator: "," + delimiter: "." + precision: 2 + + # Used in number_to_percentage() + percentage: + format: + # These three are to override number.format and are optional + # separator: + delimiter: "" + # precision: + + # Used in number_to_precision() + precision: + format: + # These three are to override number.format and are optional + # separator: + delimiter: "" + # precision: + + # Used in number_to_human_size() + human: + format: + # These three are to override number.format and are optional + # separator: + delimiter: "" + precision: 3 + storage_units: + format: "%n %u" + units: + byte: + one: "Byte" + other: "Bytes" + kb: "KB" + mb: "MB" + gb: "GB" + tb: "TB" + + # Used in distance_of_time_in_words(), distance_of_time_in_words_to_now(), time_ago_in_words() + datetime: + distance_in_words: + half_a_minute: "medio minuto" + less_than_x_seconds: + one: "menos de 1 segundo" + other: "menos de %{count} segundos" + x_seconds: + one: "1 segundo" + other: "%{count} segundos" + less_than_x_minutes: + one: "menos de 1 minuto" + other: "menos de %{count} minutos" + x_minutes: + one: "1 minuto" + other: "%{count} minutos" + about_x_hours: + one: "alrededor de 1 hora" + other: "alrededor de %{count} horas" + x_hours: + one: "1 hour" + other: "%{count} hours" + x_days: + one: "1 día" + other: "%{count} días" + about_x_months: + one: "alrededor de 1 mes" + other: "alrededor de %{count} meses" + x_months: + one: "1 mes" + other: "%{count} meses" + about_x_years: + one: "alrededor de 1 año" + other: "alrededor de %{count} años" + over_x_years: + one: "más de 1 año" + other: "más de %{count} años" + almost_x_years: + one: "casi 1 año" + other: "casi %{count} años" + + activerecord: + errors: + template: + header: + one: "no se pudo guardar este %{model} porque se encontró 1 error" + other: "no se pudo guardar este %{model} porque se encontraron %{count} errores" + # The variable :count is also available + body: "Se encontraron problemas con los siguientes campos:" + + # The values :model, :attribute and :value are always available for interpolation + # The value :count is available when applicable. Can be used for pluralization. + messages: + inclusion: "no está incluido en la lista" + exclusion: "está reservado" + invalid: "no es válido" + confirmation: "no coincide con la confirmación" + accepted: "debe ser aceptado" + empty: "no puede estar vacío" + blank: "no puede estar en blanco" + too_long: "es demasiado largo (%{count} caracteres máximo)" + too_short: "es demasiado corto (%{count} caracteres mínimo)" + wrong_length: "no tiene la longitud correcta (%{count} caracteres exactos)" + taken: "ya está en uso" + not_a_number: "no es un número" + greater_than: "debe ser mayor que %{count}" + greater_than_or_equal_to: "debe ser mayor que o igual a %{count}" + equal_to: "debe ser igual a %{count}" + less_than: "debe ser menor que %{count}" + less_than_or_equal_to: "debe ser menor que o igual a %{count}" + odd: "debe ser impar" + even: "debe ser par" + greater_than_start_date: "debe ser posterior a la fecha de comienzo" + not_same_project: "no pertenece al mismo proyecto" + circular_dependency: "Esta relación podría crear una dependencia circular" + cant_link_an_issue_with_a_descendant: "Esta petición no puede ser ligada a una de estas tareas" + + # Append your own errors here or at the model/attributes scope. + + models: + # Overrides default messages + + attributes: + # Overrides model and default messages. + + direction: ltr + date: + formats: + # Use the strftime parameters for formats. + # When no format has been given, it uses default. + # You can provide other formats here if you like! + default: "%Y-%m-%d" + short: "%d de %b" + long: "%d de %B de %Y" + + day_names: [Domingo, Lunes, Martes, Miércoles, Jueves, Viernes, Sábado] + abbr_day_names: [Dom, Lun, Mar, Mie, Jue, Vie, Sab] + + # Don't forget the nil at the beginning; there's no such thing as a 0th month + month_names: [~, Enero, Febrero, Marzo, Abril, Mayo, Junio, Julio, Agosto, Septiembre, Octubre, Noviembre, Diciembre] + abbr_month_names: [~, Ene, Feb, Mar, Abr, May, Jun, Jul, Ago, Sep, Oct, Nov, Dic] + # Used in date_select and datime_select. + order: + - :year + - :month + - :day + + time: + formats: + default: "%A, %d de %B de %Y %H:%M:%S %z" + time: "%H:%M" + short: "%d de %b %H:%M" + long: "%d de %B de %Y %H:%M" + am: "am" + pm: "pm" + +# Used in array.to_sentence. + support: + array: + sentence_connector: "y" + + actionview_instancetag_blank_option: Por favor seleccione + + button_activate: Activar + button_add: Añadir + button_annotate: Anotar + button_apply: Aceptar + button_archive: Archivar + button_back: Atrás + button_cancel: Cancelar + button_change: Cambiar + button_change_password: Cambiar contraseña + button_check_all: Seleccionar todo + button_clear: Anular + button_configure: Configurar + button_copy: Copiar + button_create: Crear + button_delete: Borrar + button_download: Descargar + button_edit: Modificar + button_list: Listar + button_lock: Bloquear + button_log_time: Tiempo dedicado + button_login: Acceder + button_move: Mover + button_quote: Citar + button_rename: Renombrar + button_reply: Responder + button_reset: Reestablecer + button_rollback: Volver a esta versión + button_save: Guardar + button_sort: Ordenar + button_submit: Aceptar + button_test: Probar + button_unarchive: Desarchivar + button_uncheck_all: No seleccionar nada + button_unlock: Desbloquear + button_unwatch: No monitorizar + button_update: Actualizar + button_view: Ver + button_watch: Monitorizar + default_activity_design: Diseño + default_activity_development: Desarrollo + default_doc_category_tech: Documentación técnica + default_doc_category_user: Documentación de usuario + default_issue_status_in_progress: En curso + default_issue_status_closed: Cerrada + default_issue_status_feedback: Comentarios + default_issue_status_new: Nueva + default_issue_status_rejected: Rechazada + default_issue_status_resolved: Resuelta + default_priority_high: Alta + default_priority_immediate: Inmediata + default_priority_low: Baja + default_priority_normal: Normal + default_priority_urgent: Urgente + default_role_developer: Desarrollador + default_role_manager: Jefe de proyecto + default_role_reporter: Informador + default_tracker_bug: Errores + default_tracker_feature: Tareas + default_tracker_support: Soporte + enumeration_activities: Actividades (tiempo dedicado) + enumeration_doc_categories: Categorías del documento + enumeration_issue_priorities: Prioridad de las peticiones + error_can_t_load_default_data: "No se ha podido cargar la configuración por defecto: %{value}" + error_issue_not_found_in_project: 'La petición no se encuentra o no está asociada a este proyecto' + error_scm_annotate: "No existe la entrada o no ha podido ser anotada" + error_scm_annotate_big_text_file: "La entrada no puede anotarse, al superar el tamaño máximo para ficheros de texto." + error_scm_command_failed: "Se produjo un error al acceder al repositorio: %{value}" + error_scm_not_found: "La entrada y/o la revisión no existe en el repositorio." + field_account: Cuenta + field_activity: Actividad + field_admin: Administrador + field_assignable: Se pueden asignar peticiones a este perfil + field_assigned_to: Asignado a + field_attr_firstname: Cualidad del nombre + field_attr_lastname: Cualidad del apellido + field_attr_login: Cualidad del identificador + field_attr_mail: Cualidad del Email + field_auth_source: Modo de identificación + field_author: Autor + field_base_dn: DN base + field_category: Categoría + field_column_names: Columnas + field_comments: Comentario + field_comments_sorting: Mostrar comentarios + field_created_on: Creado + field_default_value: Estado por defecto + field_delay: Retraso + field_description: Descripción + field_done_ratio: "% Realizado" + field_downloads: Descargas + field_due_date: Fecha fin + field_effective_date: Fecha + field_estimated_hours: Tiempo estimado + field_field_format: Formato + field_filename: Fichero + field_filesize: Tamaño + field_firstname: Nombre + field_fixed_version: Versión prevista + field_hide_mail: Ocultar mi dirección de correo + field_homepage: Sitio web + field_host: Anfitrión + field_hours: Horas + field_identifier: Identificador + field_is_closed: Petición resuelta + field_is_default: Estado por defecto + field_is_filter: Usado como filtro + field_is_for_all: Para todos los proyectos + field_is_in_roadmap: Consultar las peticiones en la planificación + field_is_public: Público + field_is_required: Obligatorio + field_issue: Petición + field_issue_to: Petición relacionada + field_language: Idioma + field_last_login_on: Última conexión + field_lastname: Apellido + field_login: Identificador + field_mail: Correo electrónico + field_mail_notification: Notificaciones por correo + field_max_length: Longitud máxima + field_min_length: Longitud mínima + field_name: Nombre + field_new_password: Nueva contraseña + field_notes: Notas + field_onthefly: Creación del usuario "al vuelo" + field_parent: Proyecto padre + field_parent_title: Página padre + field_password: Contraseña + field_password_confirmation: Confirmación + field_port: Puerto + field_possible_values: Valores posibles + field_priority: Prioridad + field_project: Proyecto + field_redirect_existing_links: Redireccionar enlaces existentes + field_regexp: Expresión regular + field_role: Perfil + field_searchable: Incluir en las búsquedas + field_spent_on: Fecha + field_start_date: Fecha de inicio + field_start_page: Página principal + field_status: Estado + field_subject: Asunto + field_subproject: Proyecto secundario + field_summary: Resumen + field_time_zone: Zona horaria + field_title: Título + field_tracker: Tipo + field_type: Tipo + field_updated_on: Actualizado + field_url: URL + field_user: Usuario + field_value: Valor + field_version: Versión + general_csv_decimal_separator: ',' + general_csv_encoding: ISO-8859-15 + general_csv_separator: ';' + general_first_day_of_week: '1' + general_lang_name: 'Español' + general_pdf_encoding: UTF-8 + general_text_No: 'No' + general_text_Yes: 'Sí' + general_text_no: 'no' + general_text_yes: 'sí' + label_activity: Actividad + label_add_another_file: Añadir otro fichero + label_add_note: Añadir una nota + label_added: añadido + label_added_time_by: "Añadido por %{author} hace %{age}" + label_administration: Administración + label_age: Edad + label_ago: hace + label_all: todos + label_all_time: todo el tiempo + label_all_words: Todas las palabras + label_and_its_subprojects: "%{value} y proyectos secundarios" + label_applied_status: Aplicar estado + label_assigned_to_me_issues: Peticiones que me están asignadas + label_associated_revisions: Revisiones asociadas + label_attachment: Fichero + label_attachment_delete: Borrar el fichero + label_attachment_new: Nuevo fichero + label_attachment_plural: Ficheros + label_attribute: Cualidad + label_attribute_plural: Cualidades + label_auth_source: Modo de autenticación + label_auth_source_new: Nuevo modo de autenticación + label_auth_source_plural: Modos de autenticación + label_authentication: Autenticación + label_blocked_by: bloqueado por + label_blocks: bloquea a + label_board: Foro + label_board_new: Nuevo foro + label_board_plural: Foros + label_boolean: Booleano + label_browse: Hojear + label_bulk_edit_selected_issues: Editar las peticiones seleccionadas + label_calendar: Calendario + label_change_plural: Cambios + label_change_properties: Cambiar propiedades + label_change_status: Cambiar el estado + label_change_view_all: Ver todos los cambios + label_changes_details: Detalles de todos los cambios + label_changeset_plural: Cambios + label_chronological_order: En orden cronológico + label_closed_issues: cerrada + label_closed_issues_plural: cerradas + label_x_open_issues_abbr_on_total: + zero: 0 abiertas / %{total} + one: 1 abierta / %{total} + other: "%{count} abiertas / %{total}" + label_x_open_issues_abbr: + zero: 0 abiertas + one: 1 abierta + other: "%{count} abiertas" + label_x_closed_issues_abbr: + zero: 0 cerradas + one: 1 cerrada + other: "%{count} cerradas" + label_comment: Comentario + label_comment_add: Añadir un comentario + label_comment_added: Comentario añadido + label_comment_delete: Borrar comentarios + label_comment_plural: Comentarios + label_x_comments: + zero: sin comentarios + one: 1 comentario + other: "%{count} comentarios" + label_commits_per_author: Commits por autor + label_commits_per_month: Commits por mes + label_confirmation: Confirmación + label_contains: contiene + label_copied: copiado + label_copy_workflow_from: Copiar flujo de trabajo desde + label_current_status: Estado actual + label_current_version: Versión actual + label_custom_field: Campo personalizado + label_custom_field_new: Nuevo campo personalizado + label_custom_field_plural: Campos personalizados + label_date: Fecha + label_date_from: Desde + label_date_range: Rango de fechas + label_date_to: Hasta + label_day_plural: días + label_default: Por defecto + label_default_columns: Columnas por defecto + label_deleted: suprimido + label_details: Detalles + label_diff_inline: en línea + label_diff_side_by_side: cara a cara + label_disabled: deshabilitado + label_display_per_page: "Por página: %{value}" + label_document: Documento + label_document_added: Documento añadido + label_document_new: Nuevo documento + label_document_plural: Documentos + label_downloads_abbr: D/L + label_duplicated_by: duplicada por + label_duplicates: duplicada de + label_end_to_end: fin a fin + label_end_to_start: fin a principio + label_enumeration_new: Nuevo valor + label_enumerations: Listas de valores + label_environment: Entorno + label_equals: igual + label_example: Ejemplo + label_export_to: 'Exportar a:' + label_f_hour: "%{value} hora" + label_f_hour_plural: "%{value} horas" + label_feed_plural: Feeds + label_feeds_access_key_created_on: "Clave de acceso por RSS creada hace %{value}" + label_file_added: Fichero añadido + label_file_plural: Archivos + label_filter_add: Añadir el filtro + label_filter_plural: Filtros + label_float: Flotante + label_follows: posterior a + label_gantt: Gantt + label_general: General + label_generate_key: Generar clave + label_help: Ayuda + label_history: Histórico + label_home: Inicio + label_in: en + label_in_less_than: en menos que + label_in_more_than: en más que + label_incoming_emails: Correos entrantes + label_index_by_date: Índice por fecha + label_index_by_title: Índice por título + label_information: Información + label_information_plural: Información + label_integer: Número + label_internal: Interno + label_issue: Petición + label_issue_added: Petición añadida + label_issue_category: Categoría de las peticiones + label_issue_category_new: Nueva categoría + label_issue_category_plural: Categorías de las peticiones + label_issue_new: Nueva petición + label_issue_plural: Peticiones + label_issue_status: Estado de la petición + label_issue_status_new: Nuevo estado + label_issue_status_plural: Estados de las peticiones + label_issue_tracking: Peticiones + label_issue_updated: Petición actualizada + label_issue_view_all: Ver todas las peticiones + label_issue_watchers: Seguidores + label_issues_by: "Peticiones por %{value}" + label_jump_to_a_project: Ir al proyecto... + label_language_based: Basado en el idioma + label_last_changes: "últimos %{count} cambios" + label_last_login: Última conexión + label_last_month: último mes + label_last_n_days: "últimos %{count} días" + label_last_week: última semana + label_latest_revision: Última revisión + label_latest_revision_plural: Últimas revisiones + label_ldap_authentication: Autenticación LDAP + label_less_than_ago: hace menos de + label_list: Lista + label_loading: Cargando... + label_logged_as: Conectado como + label_login: Iniciar sesión + label_logout: Terminar sesión + label_max_size: Tamaño máximo + label_me: yo mismo + label_member: Miembro + label_member_new: Nuevo miembro + label_member_plural: Miembros + label_message_last: Último mensaje + label_message_new: Nuevo mensaje + label_message_plural: Mensajes + label_message_posted: Mensaje añadido + label_min_max_length: Longitud mín - máx + label_modified: modificado + label_module_plural: Módulos + label_month: Mes + label_months_from: meses de + label_more: Más + label_more_than_ago: hace más de + label_my_account: Mi cuenta + label_my_page: Mi página + label_my_projects: Mis proyectos + label_new: Nuevo + label_new_statuses_allowed: Nuevos estados autorizados + label_news: Noticia + label_news_added: Noticia añadida + label_news_latest: Últimas noticias + label_news_new: Nueva noticia + label_news_plural: Noticias + label_news_view_all: Ver todas las noticias + label_next: Siguiente + label_no_change_option: (Sin cambios) + label_no_data: Ningún dato disponible + label_nobody: nadie + label_none: ninguno + label_not_contains: no contiene + label_not_equals: no igual + label_open_issues: abierta + label_open_issues_plural: abiertas + label_optional_description: Descripción opcional + label_options: Opciones + label_overall_activity: Actividad global + label_overview: Vistazo + label_password_lost: ¿Olvidaste la contraseña? + label_per_page: Por página + label_permissions: Permisos + label_permissions_report: Informe de permisos + label_personalize_page: Personalizar esta página + label_planning: Planificación + label_please_login: Por favor, inicie sesión + label_plugins: Extensiones + label_precedes: anterior a + label_preferences: Preferencias + label_preview: Previsualizar + label_previous: Anterior + label_project: Proyecto + label_project_all: Todos los proyectos + label_project_latest: Últimos proyectos + label_project_new: Nuevo proyecto + label_project_plural: Proyectos + label_x_projects: + zero: sin proyectos + one: 1 proyecto + other: "%{count} proyectos" + label_public_projects: Proyectos públicos + label_query: Consulta personalizada + label_query_new: Nueva consulta + label_query_plural: Consultas personalizadas + label_read: Leer... + label_register: Registrar + label_registered_on: Inscrito el + label_registration_activation_by_email: activación de cuenta por correo + label_registration_automatic_activation: activación automática de cuenta + label_registration_manual_activation: activación manual de cuenta + label_related_issues: Peticiones relacionadas + label_relates_to: relacionada con + label_relation_delete: Eliminar relación + label_relation_new: Nueva relación + label_renamed: renombrado + label_reply_plural: Respuestas + label_report: Informe + label_report_plural: Informes + label_reported_issues: Peticiones registradas por mí + label_repository: Repositorio + label_repository_plural: Repositorios + label_result_plural: Resultados + label_reverse_chronological_order: En orden cronológico inverso + label_revision: Revisión + label_revision_plural: Revisiones + label_roadmap: Planificación + label_roadmap_due_in: "Finaliza en %{value}" + label_roadmap_no_issues: No hay peticiones para esta versión + label_roadmap_overdue: "%{value} tarde" + label_role: Perfil + label_role_and_permissions: Perfiles y permisos + label_role_new: Nuevo perfil + label_role_plural: Perfiles + label_scm: SCM + label_search: Búsqueda + label_search_titles_only: Buscar sólo en títulos + label_send_information: Enviar información de la cuenta al usuario + label_send_test_email: Enviar un correo de prueba + label_settings: Configuración + label_show_completed_versions: Muestra las versiones terminadas + label_sort_by: "Ordenar por %{value}" + label_sort_higher: Subir + label_sort_highest: Primero + label_sort_lower: Bajar + label_sort_lowest: Último + label_spent_time: Tiempo dedicado + label_start_to_end: principio a fin + label_start_to_start: principio a principio + label_statistics: Estadísticas + label_stay_logged_in: Mantener la sesión abierta + label_string: Texto + label_subproject_plural: Proyectos secundarios + label_text: Texto largo + label_theme: Tema + label_this_month: este mes + label_this_week: esta semana + label_this_year: este año + label_time_tracking: Control de tiempo + label_today: hoy + label_topic_plural: Temas + label_total: Total + label_tracker: Tipo + label_tracker_new: Nuevo tipo + label_tracker_plural: Tipos de peticiones + label_updated_time: "Actualizado hace %{value}" + label_updated_time_by: "Actualizado por %{author} hace %{age}" + label_used_by: Utilizado por + label_user: Usuario + label_user_activity: "Actividad de %{value}" + label_user_mail_no_self_notified: "No quiero ser avisado de cambios hechos por mí" + label_user_mail_option_all: "Para cualquier evento en todos mis proyectos" + label_user_mail_option_selected: "Para cualquier evento de los proyectos seleccionados..." + label_user_new: Nuevo usuario + label_user_plural: Usuarios + label_version: Versión + label_version_new: Nueva versión + label_version_plural: Versiones + label_view_diff: Ver diferencias + label_view_revisions: Ver las revisiones + label_watched_issues: Peticiones monitorizadas + label_week: Semana + label_wiki: Wiki + label_wiki_edit: Modificación Wiki + label_wiki_edit_plural: Modificaciones Wiki + label_wiki_page: Página Wiki + label_wiki_page_plural: Páginas Wiki + label_workflow: Flujo de trabajo + label_year: Año + label_yesterday: ayer + mail_body_account_activation_request: "Se ha inscrito un nuevo usuario (%{value}). La cuenta está pendiende de aprobación:" + mail_body_account_information: Información sobre su cuenta + mail_body_account_information_external: "Puede usar su cuenta %{value} para conectarse." + mail_body_lost_password: 'Para cambiar su contraseña, haga clic en el siguiente enlace:' + mail_body_register: 'Para activar su cuenta, haga clic en el siguiente enlace:' + mail_body_reminder: "%{count} peticion(es) asignadas a tí finalizan en los próximos %{days} días:" + mail_subject_account_activation_request: "Petición de activación de cuenta %{value}" + mail_subject_lost_password: "Tu contraseña del %{value}" + mail_subject_register: "Activación de la cuenta del %{value}" + mail_subject_reminder: "%{count} peticion(es) finalizan en los próximos %{days} días" + notice_account_activated: Su cuenta ha sido activada. Ya puede conectarse. + notice_account_invalid_creditentials: Usuario o contraseña inválido. + notice_account_lost_email_sent: Se le ha enviado un correo con instrucciones para elegir una nueva contraseña. + notice_account_password_updated: Contraseña modificada correctamente. + notice_account_pending: "Su cuenta ha sido creada y está pendiende de la aprobación por parte del administrador." + notice_account_register_done: Cuenta creada correctamente. Para activarla, haga clic sobre el enlace que le ha sido enviado por correo. + notice_account_unknown_email: Usuario desconocido. + notice_account_updated: Cuenta actualizada correctamente. + notice_account_wrong_password: Contraseña incorrecta. + notice_can_t_change_password: Esta cuenta utiliza una fuente de autenticación externa. No es posible cambiar la contraseña. + notice_default_data_loaded: Configuración por defecto cargada correctamente. + notice_email_error: "Ha ocurrido un error mientras enviando el correo (%{value})" + notice_email_sent: "Se ha enviado un correo a %{value}" + notice_failed_to_save_issues: "Imposible grabar %{count} peticion(es) de %{total} seleccionada(s): %{ids}." + notice_feeds_access_key_reseted: Su clave de acceso para RSS ha sido reiniciada. + notice_file_not_found: La página a la que intenta acceder no existe. + notice_locking_conflict: Los datos han sido modificados por otro usuario. + notice_no_issue_selected: "Ninguna petición seleccionada. Por favor, compruebe la petición que quiere modificar" + notice_not_authorized: No tiene autorización para acceder a esta página. + notice_successful_connection: Conexión correcta. + notice_successful_create: Creación correcta. + notice_successful_delete: Borrado correcto. + notice_successful_update: Modificación correcta. + notice_unable_delete_version: No se puede borrar la versión + permission_add_issue_notes: Añadir notas + permission_add_issue_watchers: Añadir seguidores + permission_add_issues: Añadir peticiones + permission_add_messages: Enviar mensajes + permission_browse_repository: Hojear repositiorio + permission_comment_news: Comentar noticias + permission_commit_access: Acceso de escritura + permission_delete_issues: Borrar peticiones + permission_delete_messages: Borrar mensajes + permission_delete_own_messages: Borrar mensajes propios + permission_delete_wiki_pages: Borrar páginas wiki + permission_delete_wiki_pages_attachments: Borrar ficheros + permission_edit_issue_notes: Modificar notas + permission_edit_issues: Modificar peticiones + permission_edit_messages: Modificar mensajes + permission_edit_own_issue_notes: Modificar notas propias + permission_edit_own_messages: Editar mensajes propios + permission_edit_own_time_entries: Modificar tiempos dedicados propios + permission_edit_project: Modificar proyecto + permission_edit_time_entries: Modificar tiempos dedicados + permission_edit_wiki_pages: Modificar páginas wiki + permission_log_time: Anotar tiempo dedicado + permission_manage_boards: Administrar foros + permission_manage_categories: Administrar categorías de peticiones + permission_manage_files: Administrar ficheros + permission_manage_issue_relations: Administrar relación con otras peticiones + permission_manage_members: Administrar miembros + permission_manage_news: Administrar noticias + permission_manage_public_queries: Administrar consultas públicas + permission_manage_repository: Administrar repositorio + permission_manage_versions: Administrar versiones + permission_manage_wiki: Administrar wiki + permission_move_issues: Mover peticiones + permission_protect_wiki_pages: Proteger páginas wiki + permission_rename_wiki_pages: Renombrar páginas wiki + permission_save_queries: Grabar consultas + permission_select_project_modules: Seleccionar módulos del proyecto + permission_view_calendar: Ver calendario + permission_view_changesets: Ver cambios + permission_view_documents: Ver documentos + permission_view_files: Ver ficheros + permission_view_gantt: Ver diagrama de Gantt + permission_view_issue_watchers: Ver lista de seguidores + permission_view_messages: Ver mensajes + permission_view_time_entries: Ver tiempo dedicado + permission_view_wiki_edits: Ver histórico del wiki + permission_view_wiki_pages: Ver wiki + project_module_boards: Foros + project_module_documents: Documentos + project_module_files: Ficheros + project_module_issue_tracking: Peticiones + project_module_news: Noticias + project_module_repository: Repositorio + project_module_time_tracking: Control de tiempo + project_module_wiki: Wiki + setting_activity_days_default: Días a mostrar en la actividad de proyecto + setting_app_subtitle: Subtítulo de la aplicación + setting_app_title: Título de la aplicación + setting_attachment_max_size: Tamaño máximo del fichero + setting_autofetch_changesets: Autorellenar los commits del repositorio + setting_autologin: Inicio de sesión automático + setting_bcc_recipients: Ocultar las copias de carbón (bcc) + setting_commit_fix_keywords: Palabras clave para la corrección + setting_commit_ref_keywords: Palabras clave para la referencia + setting_cross_project_issue_relations: Permitir relacionar peticiones de distintos proyectos + setting_date_format: Formato de fecha + setting_default_language: Idioma por defecto + setting_default_projects_public: Los proyectos nuevos son públicos por defecto + setting_diff_max_lines_displayed: Número máximo de diferencias mostradas + setting_display_subprojects_issues: Mostrar por defecto peticiones de proy. secundarios en el principal + setting_emails_footer: Pie de mensajes + setting_enabled_scm: Activar SCM + setting_feeds_limit: Límite de contenido para sindicación + setting_gravatar_enabled: Usar iconos de usuario (Gravatar) + setting_host_name: Nombre y ruta del servidor + setting_issue_list_default_columns: Columnas por defecto para la lista de peticiones + setting_issues_export_limit: Límite de exportación de peticiones + setting_login_required: Se requiere identificación + setting_mail_from: Correo desde el que enviar mensajes + setting_mail_handler_api_enabled: Activar SW para mensajes entrantes + setting_mail_handler_api_key: Clave de la API + setting_per_page_options: Objetos por página + setting_plain_text_mail: sólo texto plano (no HTML) + setting_protocol: Protocolo + setting_self_registration: Registro permitido + setting_sequential_project_identifiers: Generar identificadores de proyecto + setting_sys_api_enabled: Habilitar SW para la gestión del repositorio + setting_text_formatting: Formato de texto + setting_time_format: Formato de hora + setting_user_format: Formato de nombre de usuario + setting_welcome_text: Texto de bienvenida + setting_wiki_compression: Compresión del historial del Wiki + status_active: activo + status_locked: bloqueado + status_registered: registrado + text_are_you_sure: ¿Está seguro? + text_assign_time_entries_to_project: Asignar las horas al proyecto + text_caracters_maximum: "%{count} caracteres como máximo." + text_caracters_minimum: "%{count} caracteres como mínimo." + text_comma_separated: Múltiples valores permitidos (separados por coma). + text_default_administrator_account_changed: Cuenta de administrador por defecto modificada + text_destroy_time_entries: Borrar las horas + text_destroy_time_entries_question: Existen %{hours} horas asignadas a la petición que quiere borrar. ¿Qué quiere hacer? + text_diff_truncated: '... Diferencia truncada por exceder el máximo tamaño visualizable.' + text_email_delivery_not_configured: "Las notificaciones están desactivadas porque el servidor de correo no está configurado.\nConfigure el servidor de SMTP en config/configuration.yml y reinicie la aplicación para activar los cambios." + text_enumeration_category_reassign_to: 'Reasignar al siguiente valor:' + text_enumeration_destroy_question: "%{count} objetos con este valor asignado." + text_file_repository_writable: Se puede escribir en el repositorio + text_issue_added: "Petición %{id} añadida por %{author}." + text_issue_category_destroy_assignments: Dejar las peticiones sin categoría + text_issue_category_destroy_question: "Algunas peticiones (%{count}) están asignadas a esta categoría. ¿Qué desea hacer?" + text_issue_category_reassign_to: Reasignar las peticiones a la categoría + text_issue_updated: "La petición %{id} ha sido actualizada por %{author}." + text_issues_destroy_confirmation: '¿Seguro que quiere borrar las peticiones seleccionadas?' + text_issues_ref_in_commit_messages: Referencia y petición de corrección en los mensajes + text_length_between: "Longitud entre %{min} y %{max} caracteres." + text_load_default_configuration: Cargar la configuración por defecto + text_min_max_length_info: 0 para ninguna restricción + text_no_configuration_data: "Todavía no se han configurado perfiles, ni tipos, estados y flujo de trabajo asociado a peticiones. Se recomiendo encarecidamente cargar la configuración por defecto. Una vez cargada, podrá modificarla." + text_project_destroy_confirmation: ¿Estás seguro de querer eliminar el proyecto? + text_reassign_time_entries: 'Reasignar las horas a esta petición:' + text_regexp_info: ej. ^[A-Z0-9]+$ + text_repository_usernames_mapping: "Establezca la correspondencia entre los usuarios de Redmine y los presentes en el log del repositorio.\nLos usuarios con el mismo nombre o correo en Redmine y en el repositorio serán asociados automáticamente." + text_rmagick_available: RMagick disponible (opcional) + text_select_mail_notifications: Seleccionar los eventos a notificar + text_select_project_modules: 'Seleccione los módulos a activar para este proyecto:' + text_status_changed_by_changeset: "Aplicado en los cambios %{value}" + text_subprojects_destroy_warning: "Los proyectos secundarios: %{value} también se eliminarán" + text_tip_issue_begin_day: tarea que comienza este día + text_tip_issue_begin_end_day: tarea que comienza y termina este día + text_tip_issue_end_day: tarea que termina este día + text_tracker_no_workflow: No hay ningún flujo de trabajo definido para este tipo de petición + text_unallowed_characters: Caracteres no permitidos + text_user_mail_option: "De los proyectos no seleccionados, sólo recibirá notificaciones sobre elementos monitorizados o elementos en los que esté involucrado (por ejemplo, peticiones de las que usted sea autor o asignadas a usted)." + text_user_wrote: "%{value} escribió:" + text_wiki_destroy_confirmation: ¿Seguro que quiere borrar el wiki y todo su contenido? + text_workflow_edit: Seleccionar un flujo de trabajo para actualizar + text_plugin_assets_writable: Se puede escribir en el directorio público de las extensiones + warning_attachments_not_saved: "No se han podido grabar %{count} ficheros." + button_create_and_continue: Crear y continuar + text_custom_field_possible_values_info: 'Un valor en cada línea' + label_display: Mostrar + field_editable: Modificable + setting_repository_log_display_limit: Número máximo de revisiones mostradas en el fichero de trazas + setting_file_max_size_displayed: Tamaño máximo de los ficheros de texto mostrados + field_watcher: Seguidor + setting_openid: Permitir identificación y registro por OpenID + field_identity_url: URL de OpenID + label_login_with_open_id_option: o identifíquese con OpenID + field_content: Contenido + label_descending: Descendente + label_sort: Ordenar + label_ascending: Ascendente + label_date_from_to: Desde %{start} hasta %{end} + label_greater_or_equal: ">=" + label_less_or_equal: <= + text_wiki_page_destroy_question: Esta página tiene %{descendants} página(s) hija(s) y descendiente(s). ¿Qué desea hacer? + text_wiki_page_reassign_children: Reasignar páginas hijas a esta página + text_wiki_page_nullify_children: Dejar páginas hijas como páginas raíz + text_wiki_page_destroy_children: Eliminar páginas hijas y todos sus descendientes + setting_password_min_length: Longitud mínima de la contraseña + field_group_by: Agrupar resultados por + mail_subject_wiki_content_updated: "La página wiki '%{id}' ha sido actualizada" + label_wiki_content_added: Página wiki añadida + mail_subject_wiki_content_added: "Se ha añadido la página wiki '%{id}'." + mail_body_wiki_content_added: "%{author} ha añadido la página wiki '%{id}'." + label_wiki_content_updated: Página wiki actualizada + mail_body_wiki_content_updated: La página wiki '%{id}' ha sido actualizada por %{author}. + permission_add_project: Crear proyecto + setting_new_project_user_role_id: Permiso asignado a un usuario no-administrador para crear proyectos + label_view_all_revisions: Ver todas las revisiones + label_tag: Etiqueta + label_branch: Rama + error_no_tracker_in_project: Este proyecto no tiene asociados tipos de peticiones. Por favor, revise la configuración. + error_no_default_issue_status: No se ha definido un estado de petición por defecto. Por favor, revise la configuración (en "Administración" -> "Estados de las peticiones"). + text_journal_changed: "%{label} cambiado %{old} por %{new}" + text_journal_set_to: "%{label} establecido a %{value}" + text_journal_deleted: "%{label} eliminado (%{old})" + label_group_plural: Grupos + label_group: Grupo + label_group_new: Nuevo grupo + label_time_entry_plural: Tiempo dedicado + text_journal_added: "Añadido %{label} %{value}" + field_active: Activo + enumeration_system_activity: Actividad del sistema + permission_delete_issue_watchers: Borrar seguidores + version_status_closed: cerrado + version_status_locked: bloqueado + version_status_open: abierto + error_can_not_reopen_issue_on_closed_version: No se puede reabrir una petición asignada a una versión cerrada + + label_user_anonymous: Anónimo + button_move_and_follow: Mover y seguir + setting_default_projects_modules: Módulos activados por defecto en proyectos nuevos + setting_gravatar_default: Imagen Gravatar por defecto + field_sharing: Compartir + button_copy_and_follow: Copiar y seguir + label_version_sharing_hierarchy: Con la jerarquía del proyecto + label_version_sharing_tree: Con el árbol del proyecto + label_version_sharing_descendants: Con proyectos hijo + label_version_sharing_system: Con todos los proyectos + label_version_sharing_none: No compartir + button_duplicate: Duplicar + error_can_not_archive_project: Este proyecto no puede ser archivado + label_copy_source: Fuente + setting_issue_done_ratio: Calcular el ratio de tareas realizadas con + setting_issue_done_ratio_issue_status: Usar el estado de tareas + error_issue_done_ratios_not_updated: Ratios de tareas realizadas no actualizado. + error_workflow_copy_target: Por favor, elija categoría(s) y perfil(es) destino + setting_issue_done_ratio_issue_field: Utilizar el campo de petición + label_copy_same_as_target: El mismo que el destino + label_copy_target: Destino + notice_issue_done_ratios_updated: Ratios de tareas realizadas actualizados. + error_workflow_copy_source: Por favor, elija una categoría o rol de origen + label_update_issue_done_ratios: Actualizar ratios de tareas realizadas + setting_start_of_week: Comenzar las semanas en + permission_view_issues: Ver peticiones + label_display_used_statuses_only: Sólo mostrar los estados usados por este tipo de petición + label_revision_id: Revisión %{value} + label_api_access_key: Clave de acceso de la API + label_api_access_key_created_on: Clave de acceso de la API creada hace %{value} + label_feeds_access_key: Clave de acceso RSS + notice_api_access_key_reseted: Clave de acceso a la API regenerada. + setting_rest_api_enabled: Activar servicio web REST + label_missing_api_access_key: Clave de acceso a la API ausente + label_missing_feeds_access_key: Clave de accesso RSS ausente + button_show: Mostrar + text_line_separated: Múltiples valores permitidos (un valor en cada línea). + setting_mail_handler_body_delimiters: Truncar correos tras una de estas líneas + permission_add_subprojects: Crear subproyectos + label_subproject_new: Nuevo subproyecto + text_own_membership_delete_confirmation: |- + Está a punto de eliminar algún o todos sus permisos y podría perder la posibilidad de modificar este proyecto tras hacerlo. + ¿Está seguro de querer continuar? + label_close_versions: Cerrar versiones completadas + label_board_sticky: Pegajoso + label_board_locked: Bloqueado + permission_export_wiki_pages: Exportar páginas wiki + setting_cache_formatted_text: Cachear texto formateado + permission_manage_project_activities: Gestionar actividades del proyecto + error_unable_delete_issue_status: Fue imposible eliminar el estado de la petición + label_profile: Perfil + permission_manage_subtasks: Gestionar subtareas + field_parent_issue: Tarea padre + label_subtask_plural: Subtareas + label_project_copy_notifications: Enviar notificaciones por correo electrónico durante la copia del proyecto + error_can_not_delete_custom_field: Fue imposible eliminar el campo personalizado + error_unable_to_connect: Fue imposible conectar con (%{value}) + error_can_not_remove_role: Este rol está en uso y no puede ser eliminado. + error_can_not_delete_tracker: Este tipo contiene peticiones y no puede ser eliminado. + field_principal: Principal + label_my_page_block: Bloque Mi página + notice_failed_to_save_members: "Fallo al guardar miembro(s): %{errors}." + text_zoom_out: Alejar + text_zoom_in: Acercar + notice_unable_delete_time_entry: Fue imposible eliminar la entrada de tiempo dedicado. + label_overall_spent_time: Tiempo total dedicado + field_time_entries: Log time + project_module_gantt: Gantt + project_module_calendar: Calendario + button_edit_associated_wikipage: "Editar paginas Wiki asociadas: %{page_title}" + field_text: Campo de texto + label_user_mail_option_only_owner: Solo para objetos que soy propietario + setting_default_notification_option: Opcion de notificacion por defecto + label_user_mail_option_only_my_events: Solo para objetos que soy seguidor o estoy involucrado + label_user_mail_option_only_assigned: Solo para objetos que estoy asignado + label_user_mail_option_none: Sin eventos + field_member_of_group: Asignado al grupo + field_assigned_to_role: Asignado al perfil + notice_not_authorized_archived_project: El proyecto al que intenta acceder ha sido archivado. + label_principal_search: "Buscar por usuario o grupo:" + label_user_search: "Buscar por usuario:" + field_visible: Visible + setting_emails_header: Encabezado de Correos + + setting_commit_logtime_activity_id: Actividad de los tiempos registrados + text_time_logged_by_changeset: Aplicado en los cambios %{value}. + setting_commit_logtime_enabled: Habilitar registro de horas + notice_gantt_chart_truncated: Se recortó el diagrama porque excede el número máximo de elementos que pueden ser mostrados (%{max}) + setting_gantt_items_limit: Número máximo de elementos mostrados en el diagrama de Gantt + field_warn_on_leaving_unsaved: Avisarme cuando vaya a abandonar una página con texto no guardado + text_warn_on_leaving_unsaved: Esta página contiene texto no guardado y si la abandona sus cambios se perderán + label_my_queries: Mis consultas personalizadas + text_journal_changed_no_detail: "Se actualizó %{label}" + label_news_comment_added: Comentario añadido a noticia + button_expand_all: Expandir todo + button_collapse_all: Contraer todo + label_additional_workflow_transitions_for_assignee: Transiciones adicionales permitidas cuando la petición está asignada al usuario + label_additional_workflow_transitions_for_author: Transiciones adicionales permitidas cuando el usuario es autor de la petición + label_bulk_edit_selected_time_entries: Editar en bloque las horas seleccionadas + text_time_entries_destroy_confirmation: ¿Está seguro de querer eliminar (la hora seleccionada/las horas seleccionadas)? + label_role_anonymous: Anónimo + label_role_non_member: No miembro + label_issue_note_added: Nota añadida + label_issue_status_updated: Estado actualizado + label_issue_priority_updated: Prioridad actualizada + label_issues_visibility_own: Peticiones creadas por el usuario o asignadas a él + field_issues_visibility: Visibilidad de las peticiones + label_issues_visibility_all: Todas las peticiones + permission_set_own_issues_private: Poner las peticiones propias como públicas o privadas + field_is_private: Privada + permission_set_issues_private: Poner peticiones como públicas o privadas + label_issues_visibility_public: Todas las peticiones no privadas + text_issues_destroy_descendants_confirmation: Se procederá a borrar también %{count} subtarea(s). + field_commit_logs_encoding: Codificación de los mensajes de commit + field_scm_path_encoding: Codificación de las rutas + text_scm_path_encoding_note: "Por defecto: UTF-8" + field_path_to_repository: Ruta al repositorio + field_root_directory: Directorio raíz + field_cvs_module: Módulo + field_cvsroot: CVSROOT + text_mercurial_repository_note: Repositorio local (e.g. /hgrepo, c:\hgrepo) + text_scm_command: Orden + text_scm_command_version: Versión + label_git_report_last_commit: Informar del último commit para ficheros y directorios + text_scm_config: Puede configurar las órdenes de cada scm en configuration/configuration.yml. Por favor, reinicie la aplicación después de editarlo + text_scm_command_not_available: La orden para el Scm no está disponible. Por favor, compruebe la configuración en el panel de administración. + notice_issue_successful_create: Petición %{id} creada. + label_between: entre + setting_issue_group_assignment: Permitir asignar peticiones a grupos + label_diff: diferencias + text_git_repository_note: El repositorio es básico y local (p.e. /gitrepo, c:\gitrepo) + description_query_sort_criteria_direction: Dirección de ordenación + description_project_scope: Ámbito de búsqueda + description_filter: Filtro + description_user_mail_notification: Configuración de notificaciones por correo + description_date_from: Introduzca la fecha de inicio + description_message_content: Contenido del mensaje + description_available_columns: Columnas disponibles + description_date_range_interval: Elija el rango seleccionando la fecha de inicio y fin + description_issue_category_reassign: Elija la categoría de la petición + description_search: Campo de búsqueda + description_notes: Notas + description_date_range_list: Elija el rango en la lista + description_choose_project: Proyectos + description_date_to: Introduzca la fecha fin + description_query_sort_criteria_attribute: Atributo de ordenación + description_wiki_subpages_reassign: Elija la nueva página padre + description_selected_columns: Columnas seleccionadas + label_parent_revision: Padre + label_child_revision: Hijo + setting_default_issue_start_date_to_creation_date: Utilizar la fecha actual como fecha de inicio para nuevas peticiones + button_edit_section: Editar esta sección + setting_repositories_encodings: Codificación de adjuntos y repositorios + description_all_columns: Todas las columnas + button_export: Exportar + label_export_options: "%{export_format} opciones de exportación" + error_attachment_too_big: Este fichero no se puede adjuntar porque excede el tamaño máximo de fichero (%{max_size}) + notice_failed_to_save_time_entries: "Error al guardar %{count} entradas de tiempo de las %{total} seleccionadas: %{ids}." + label_x_issues: + zero: 0 petición + one: 1 petición + other: "%{count} peticiones" + label_repository_new: Nuevo repositorio + field_repository_is_default: Repositorio principal + label_copy_attachments: Copiar adjuntos + label_item_position: "%{position}/%{count}" + label_completed_versions: Versiones completadas + text_project_identifier_info: Solo se permiten letras en minúscula (a-z), números, guiones y barras bajas.
    Una vez guardado, el identificador no se puede cambiar. + field_multiple: Valores múltiples + setting_commit_cross_project_ref: Permitir referenciar y resolver peticiones de todos los demás proyectos + text_issue_conflict_resolution_add_notes: Añadir mis notas y descartar mis otros cambios + text_issue_conflict_resolution_overwrite: Aplicar mis campos de todas formas (las notas anteriores se mantendrán pero algunos cambios podrían ser sobreescritos) + notice_issue_update_conflict: La petición ha sido actualizada por otro usuario mientras la editaba. + text_issue_conflict_resolution_cancel: Descartar todos mis cambios y mostrar de nuevo %{link} + permission_manage_related_issues: Gestionar peticiones relacionadas + field_auth_source_ldap_filter: Filtro LDAP + label_search_for_watchers: Buscar seguidores para añadirlos + notice_account_deleted: Su cuenta ha sido eliminada + setting_unsubscribe: Permitir a los usuarios borrar sus propias cuentas + button_delete_my_account: Borrar mi cuenta + text_account_destroy_confirmation: |- + ¿Está seguro de querer proceder? + Su cuenta quedará borrada permanentemente, sin la posibilidad de reactivarla. + error_session_expired: Su sesión ha expirado. Por favor, vuelva a identificarse. + text_session_expiration_settings: "Advertencia: el cambio de estas opciones podría hacer expirar las sesiones activas, incluyendo la suya." + setting_session_lifetime: Tiempo de vida máximo de las sesiones + setting_session_timeout: Tiempo máximo de inactividad de las sesiones + label_session_expiration: Expiración de sesiones + permission_close_project: Cerrar / reabrir el proyecto + label_show_closed_projects: Ver proyectos cerrados + button_close: Cerrar + button_reopen: Reabrir + project_status_active: activo + project_status_closed: cerrado + project_status_archived: archivado + text_project_closed: Este proyecto está cerrado y es de sólo lectura + notice_user_successful_create: Usuario %{id} creado. + field_core_fields: Campos básicos + field_timeout: Tiempo de inactividad (en segundos) + setting_thumbnails_enabled: Mostrar miniaturas de los adjuntos + setting_thumbnails_size: Tamaño de las miniaturas (en píxeles) + label_status_transitions: Transiciones de estado + label_fields_permissions: Permisos sobre los campos + label_readonly: Sólo lectura + label_required: Requerido + text_repository_identifier_info: Solo se permiten letras en minúscula (a-z), números, guiones y barras bajas.
    Una vez guardado, el identificador no se puede cambiar. + field_board_parent: Foro padre + label_attribute_of_project: "%{name} del proyecto" + label_attribute_of_author: "%{name} del autor" + label_attribute_of_assigned_to: "%{name} de la persona asignada" + label_attribute_of_fixed_version: "%{name} de la versión indicada" + label_copy_subtasks: Copiar subtareas + label_copied_to: copiada a + label_copied_from: copiada desde + label_any_issues_in_project: cualquier petición del proyecto + label_any_issues_not_in_project: cualquier petición que no sea del proyecto + field_private_notes: Notas privadas + permission_view_private_notes: Ver notas privadas + permission_set_notes_private: Poner notas como privadas + label_no_issues_in_project: no hay peticiones en el proyecto + label_any: todos + label_last_n_weeks: en las últimas %{count} semanas + setting_cross_project_subtasks: Permitir subtareas cruzadas entre proyectos + label_cross_project_descendants: Con proyectos hijo + label_cross_project_tree: Con el árbol del proyecto + label_cross_project_hierarchy: Con la jerarquía del proyecto + label_cross_project_system: Con todos los proyectos + button_hide: Ocultar + setting_non_working_week_days: Días no laborables + label_in_the_next_days: en los próximos + label_in_the_past_days: en los anteriores + label_attribute_of_user: "%{name} del usuario" + text_turning_multiple_off: Si desactiva los valores múltiples, éstos serán eliminados para dejar un único valor por elemento. + label_attribute_of_issue: "%{name} de la petición" + permission_add_documents: Añadir documentos + permission_edit_documents: Editar documentos + permission_delete_documents: Borrar documentos + label_gantt_progress_line: Línea de progreso + setting_jsonp_enabled: Enable JSONP support + field_inherit_members: Inherit members + field_closed_on: Closed + setting_default_projects_tracker_ids: Default trackers for new projects + label_total_time: Total diff --git a/config/locales/et.yml b/config/locales/et.yml new file mode 100644 index 00000000..0764b47c --- /dev/null +++ b/config/locales/et.yml @@ -0,0 +1,1102 @@ +# Estonian localization for Redmine +# Copyright (C) 2012 Kaitseministeerium +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +et: + # Text direction: Left-to-Right (ltr) or Right-to-Left (rtl) + direction: ltr + date: + formats: + # Use the strftime parameters for formats. + # When no format has been given, it uses default. + # You can provide other formats here if you like! + default: "%d.%m.%Y" + short: "%d.%b" + long: "%d. %B %Y" + + day_names: [Pühapäev, Esmaspäev, Teisipäev, Kolmapäev, Neljapäev, Reede, Laupäev] + abbr_day_names: [P, E, T, K, N, R, L] + + # Don't forget the nil at the beginning; there's no such thing as a 0th month + month_names: [~, Jaanuar, Veebruar, Märts, Aprill, Mai, Juuni, Juuli, August, September, Oktoober, November, Detsember] + abbr_month_names: [~, jaan, veebr, märts, apr, mai, juuni, juuli, aug, sept, okt, nov, dets] + # Used in date_select and datime_select. + order: + - :year + - :month + - :day + + time: + formats: + default: "%d.%m.%Y %H:%M" + time: "%H:%M" + short: "%d.%b %H:%M" + long: "%d. %B %Y %H:%M %z" + am: "enne lõunat" + pm: "peale lõunat" + + datetime: + distance_in_words: + half_a_minute: "pool minutit" + less_than_x_seconds: + one: "vähem kui sekund" + other: "vähem kui %{count} sekundit" + x_seconds: + one: "1 sekund" + other: "%{count} sekundit" + less_than_x_minutes: + one: "vähem kui minut" + other: "vähem kui %{count} minutit" + x_minutes: + one: "1 minut" + other: "%{count} minutit" + about_x_hours: + one: "umbes tund" + other: "umbes %{count} tundi" + x_hours: + one: "1 hour" + other: "%{count} hours" + x_days: + one: "1 päev" + other: "%{count} päeva" + about_x_months: + one: "umbes kuu" + other: "umbes %{count} kuud" + x_months: + one: "1 kuu" + other: "%{count} kuud" + about_x_years: + one: "umbes aasta" + other: "umbes %{count} aastat" + over_x_years: + one: "rohkem kui aasta" + other: "rohkem kui %{count} aastat" + almost_x_years: + one: "peaaegu aasta" + other: "peaaegu %{count} aastat" + + number: + format: + separator: "." + delimiter: "" + precision: 3 + + human: + format: + delimiter: "" + precision: 3 + storage_units: + format: "%n %u" + units: + byte: + one: "bait" + other: "baiti" + kb: "KB" + mb: "MB" + gb: "GB" + tb: "TB" + +# Used in array.to_sentence. + support: + array: + sentence_connector: "ja" + skip_last_comma: false + + activerecord: + errors: + template: + header: + one: "1 viga ei võimaldanud selle %{model} salvestamist" + other: "%{count} viga ei võimaldanud selle %{model} salvestamist" + messages: + inclusion: "ei ole nimekirjas" + exclusion: "on reserveeritud" + invalid: "ei sobi" + confirmation: "ei lange kinnitusega kokku" + accepted: "peab olema aktsepteeritud" + empty: "ei või olla tühi" + blank: "ei või olla täitmata" + too_long: "on liiga pikk (lubatud on kuni %{count} märki)" + too_short: "on liiga lühike (vaja on vähemalt %{count} märki)" + wrong_length: "on vale pikkusega (peaks olema %{count} märki)" + taken: "on juba võetud" + not_a_number: "ei ole arv" + not_a_date: "ei ole korrektne kuupäev" + greater_than: "peab olema suurem kui %{count}" + greater_than_or_equal_to: "peab olema võrdne või suurem kui %{count}" + equal_to: "peab võrduma %{count}-ga" + less_than: "peab olema väiksem kui %{count}" + less_than_or_equal_to: "peab olema võrdne või väiksem kui %{count}" + odd: "peab olema paaritu arv" + even: "peab olema paarisarv" + greater_than_start_date: "peab olema suurem kui alguskuupäev" + not_same_project: "ei kuulu sama projekti juurde" + circular_dependency: "See suhe looks vastastikuse sõltuvuse" + cant_link_an_issue_with_a_descendant: "Teemat ei saa sidustada tema enda alamteemaga" + + actionview_instancetag_blank_option: "Palun vali" + + general_text_No: "Ei" + general_text_Yes: "Jah" + general_text_no: "ei" + general_text_yes: "jah" + general_lang_name: "Eesti" + general_csv_separator: "," + general_csv_decimal_separator: "." + general_csv_encoding: ISO-8859-13 + general_pdf_encoding: UTF-8 + general_first_day_of_week: "1" + + notice_account_updated: "Konto uuendamine õnnestus." + notice_account_invalid_creditentials: "Sobimatu kasutajanimi või parool" + notice_account_password_updated: "Parooli uuendamine õnnestus." + notice_account_wrong_password: "Vale parool" + notice_account_register_done: "Konto loomine õnnestus. Konto aktiveerimiseks vajuta vastaval lingil Sulle saadetud e-kirjas." + notice_account_unknown_email: "Tundmatu kasutaja." + notice_can_t_change_password: "See konto kasutab välist autentimisallikat. Siin ei saa selle konto parooli vahetada." + notice_account_lost_email_sent: "Sulle saadeti e-kiri parooli vahetamise juhistega." + notice_account_activated: "Su konto on aktiveeritud. Saad nüüd sisse logida." + notice_successful_create: "Loomine õnnestus." + notice_successful_update: "Uuendamine õnnestus." + notice_successful_delete: "Kustutamine õnnestus." + notice_successful_connection: "Ühenduse loomine õnnestus." + notice_file_not_found: "Sellist lehte ei leitud." + notice_locking_conflict: "Teine kasutaja uuendas vahepeal neid andmeid." + notice_not_authorized: "Sul ei ole sellele lehele ligipääsuks õigusi." + notice_not_authorized_archived_project: "See projekt on arhiveeritud." + notice_email_sent: "%{value}-le saadeti kiri" + notice_email_error: "Kirja saatmisel tekkis viga (%{value})" + notice_feeds_access_key_reseted: "Sinu RSS juurdepääsuvõti nulliti." + notice_api_access_key_reseted: "Sinu API juurdepääsuvõti nulliti." + notice_failed_to_save_issues: "%{count} teemat %{total}-st ei õnnestunud salvestada: %{ids}." + notice_failed_to_save_time_entries: "%{count} ajakulu kannet %{total}-st ei õnnestunud salvestada: %{ids}." + notice_failed_to_save_members: "Liiget/liikmeid ei õnnestunud salvestada: %{errors}." + notice_no_issue_selected: "Ühtegi teemat ei ole valitud! Palun vali teema(d), mida soovid muuta." + notice_account_pending: "Sinu konto on loodud ja ootab nüüd administraatori kinnitust." + notice_default_data_loaded: "Algseadistuste laadimine õnnestus." + notice_unable_delete_version: "Versiooni kustutamine ei õnnestunud." + notice_unable_delete_time_entry: "Ajakulu kande kustutamine ei õnnestunud." + notice_issue_done_ratios_updated: "Teema edenemise astmed on uuendatud." + notice_gantt_chart_truncated: "Diagrammi kärbiti kuna ületati kuvatavate objektide suurim hulk (%{max})" + notice_issue_successful_create: "Teema %{id} loodud." + notice_issue_update_conflict: "Teine kasutaja uuendas seda teemat Sinuga samaaegselt." + notice_account_deleted: "Sinu konto on lõplikult kustutatud." + + error_can_t_load_default_data: "Algseadistusi ei saanud laadida: %{value}" + error_scm_not_found: "Seda sissekannet hoidlast ei leitud." + error_scm_command_failed: "Hoidla poole pöördumisel tekkis viga: %{value}" + error_scm_annotate: "Sissekannet ei eksisteeri või ei saa annoteerida." + error_scm_annotate_big_text_file: "Sissekannet ei saa annoteerida, kuna see on liiga pikk." + error_issue_not_found_in_project: "Teemat ei leitud või see ei kuulu siia projekti" + error_no_tracker_in_project: "Selle projektiga ei ole seostatud ühtegi valdkonda. Palun vaata üle projekti seaded." + error_no_default_issue_status: 'Teema algolek on määramata. Palun vaata asetused üle ("Seadistused -> Olekud").' + error_can_not_delete_custom_field: "Omaloodud välja kustutamine ei õnnestunud" + error_can_not_delete_tracker: "See valdkond on mõnes teemas kasutusel ja seda ei saa kustutada." + error_can_not_remove_role: "See roll on mõnes projektis kasutusel ja seda ei saa kustutada." + error_can_not_reopen_issue_on_closed_version: "Suletud versiooni juurde kuulunud teemat ei saa taasavada" + error_can_not_archive_project: "Seda projekti ei saa arhiveerida" + error_issue_done_ratios_not_updated: "Teema edenemise astmed jäid uuendamata." + error_workflow_copy_source: "Palun vali algne valdkond või roll" + error_workflow_copy_target: "Palun vali sihtvaldkon(na)d või -roll(id)" + error_unable_delete_issue_status: "Oleku kustutamine ei õnnestunud" + error_unable_to_connect: "Ühenduse loomine ei õnnestunud (%{value})" + error_attachment_too_big: "Faili ei saa üles laadida, sest see on lubatust (%{max_size}) pikem" + warning_attachments_not_saved: "%{count} faili salvestamine ei õnnestunud." + + mail_subject_lost_password: "Sinu %{value} parool" + mail_body_lost_password: "Et vahetada oma parooli, vajuta järgmisele lingile:" + mail_subject_register: "Sinu %{value} konto aktiveerimine" + mail_body_register: "Et aktiveerida oma kontot, vajuta järgmisele lingile:" + mail_body_account_information_external: "Sisse logimiseks saad kasutada oma %{value} kontot." + mail_body_account_information: "Sinu konto teave" + mail_subject_account_activation_request: "%{value} konto aktiveerimise nõue" + mail_body_account_activation_request: "Registreerus uus kasutaja (%{value}). Konto avamine ootab Sinu kinnitust:" + mail_subject_reminder: "%{count} teema tähtaeg jõuab kätte järgmise %{days} päeva jooksul" + mail_body_reminder: "%{count} Sulle määratud teema tähtaeg jõuab kätte järgmise %{days} päeva jooksul:" + mail_subject_wiki_content_added: "Lisati '%{id}' vikileht" + mail_body_wiki_content_added: "'%{id}' vikileht lisati %{author} poolt." + mail_subject_wiki_content_updated: "Uuendati '%{id}' vikilehte" + mail_body_wiki_content_updated: "'%{id}' vikilehte uuendati %{author} poolt." + + + field_name: "Nimi" + field_description: "Kirjeldus" + field_summary: "Kokkuvõte" + field_is_required: "Kohustuslik" + field_firstname: "Eesnimi" + field_lastname: "Perekonnanimi" + field_mail: "E-post" + field_filename: "Fail" + field_filesize: "Pikkus" + field_downloads: "Allalaadimist" + field_author: "Autor" + field_created_on: "Loodud" + field_updated_on: "Uuendatud" + field_field_format: "Tüüp" + field_is_for_all: "Kõigile projektidele" + field_possible_values: "Võimalikud väärtused" + field_regexp: "Regulaarne avaldis" + field_min_length: "Vähim pikkus" + field_max_length: "Suurim pikkus" + field_value: "Väärtus" + field_category: "Kategooria" + field_title: "Pealkiri" + field_project: "Projekt" + field_issue: "Teema" + field_status: "Olek" + field_notes: "Märkused" + field_is_closed: "Sulgeb teema" + field_is_default: "Algolek" + field_tracker: "Valdkond" + field_subject: "Teema" + field_due_date: "Tähtaeg" + field_assigned_to: "Tegeleja" + field_priority: "Prioriteet" + field_fixed_version: "Sihtversioon" + field_user: "Kasutaja" + field_principal: "Vastutav isik" + field_role: "Roll" + field_homepage: "Koduleht" + field_is_public: "Avalik" + field_parent: "Emaprojekt" + field_is_in_roadmap: "Teemad on teekaardil näha" + field_login: "Kasutajanimi" + field_mail_notification: "Teated e-kirjaga" + field_admin: "Admin" + field_last_login_on: "Viimane ühendus" + field_language: "Keel" + field_effective_date: "Tähtaeg" + field_password: "Parool" + field_new_password: "Uus parool" + field_password_confirmation: "Kinnitus" + field_version: "Versioon" + field_type: "Tüüp" + field_host: "Server" + field_port: "Port" + field_account: "Konto" + field_base_dn: "Baas DN" + field_attr_login: "Kasutajanime atribuut" + field_attr_firstname: "Eesnime atribuut" + field_attr_lastname: "Perekonnanime atribuut" + field_attr_mail: "E-posti atribuut" + field_onthefly: "Kasutaja automaatne loomine" + field_start_date: "Alguskuupäev" + field_done_ratio: "% tehtud" + field_auth_source: "Autentimise viis" + field_hide_mail: "Peida e-posti aadress" + field_comments: "Kommentaar" + field_url: "URL" + field_start_page: "Esileht" + field_subproject: "Alamprojekt" + field_hours: "tundi" + field_activity: "Tegevus" + field_spent_on: "Kuupäev" + field_identifier: "Tunnus" + field_is_filter: "Kasutatakse filtrina" + field_issue_to: "Seotud teema" + field_delay: "Viivitus" + field_assignable: "Saab määrata teemadega tegelema" + field_redirect_existing_links: "Suuna olemasolevad lingid ringi" + field_estimated_hours: "Eeldatav ajakulu" + field_column_names: "Veerud" + field_time_entries: "Ajakulu" + field_time_zone: "Ajatsoon" + field_searchable: "Otsitav" + field_default_value: "Vaikimisi" + field_comments_sorting: "Kommentaaride järjestus" + field_parent_title: "Pärineb lehest" + field_editable: "Muudetav" + field_watcher: "Jälgija" + field_identity_url: "OpenID URL" + field_content: "Sisu" + field_group_by: "Grupeeri tulemus" + field_sharing: "Teemade jagamine" + field_parent_issue: "Pärineb teemast" + field_member_of_group: "Tegeleja grupp" + field_assigned_to_role: "Tegeleja roll" + field_text: "Tekstiväli" + field_visible: "Nähtav" + field_warn_on_leaving_unsaved: "Hoiata salvestamata sisuga lehtedelt lahkumisel" + field_issues_visibility: "See roll näeb" + field_is_private: "Privaatne" + field_commit_logs_encoding: "Sissekannete kodeering" + field_scm_path_encoding: "Teeraja märkide kodeering" + field_path_to_repository: "Hoidla teerada" + field_root_directory: "Juurkataloog" + field_cvsroot: "CVSROOT" + field_cvs_module: "Moodul" + field_repository_is_default: "Peamine hoidla" + field_multiple: "Korraga mitu väärtust" + field_auth_source_ldap_filter: "LDAP filter" + + setting_app_title: "Veebilehe pealkiri" + setting_app_subtitle: "Veebilehe alampealkiri" + setting_welcome_text: "Tervitustekst" + setting_default_language: "Vaikimisi keel" + setting_login_required: "Autentimine kohustuslik" + setting_self_registration: "Omaloodud konto aktiveerimine" + setting_attachment_max_size: "Manuse suurim pikkus" + setting_issues_export_limit: "Teemade ekspordi limiit" + setting_mail_from: "Saatja e-posti aadress" + setting_bcc_recipients: "Saajaid ei näidata (lähevad BCC reale)" + setting_plain_text_mail: "E-kiri tavalise tekstina (ilma HTML-ta)" + setting_host_name: "Serveri nimi ja teerada" + setting_text_formatting: "Vormindamise abi" + setting_wiki_compression: "Viki ajaloo pakkimine" + setting_feeds_limit: "Atom voogude suurim objektide arv" + setting_default_projects_public: "Uued projektid on vaikimisi avalikud" + setting_autofetch_changesets: "Lae uuendused automaatselt" + setting_sys_api_enabled: "Hoidlate haldamine veebiteenuse kaudu" + setting_commit_ref_keywords: "Viitade võtmesõnad" + setting_commit_fix_keywords: "Paranduste võtmesõnad" + setting_autologin: "Automaatne sisselogimine" + setting_date_format: "Kuupäevaformaat" + setting_time_format: "Ajaformaat" + setting_cross_project_issue_relations: "Luba siduda eri projektide teemasid" + setting_issue_list_default_columns: "Teemade nimekirja vaikimisi veerud" + setting_repositories_encodings: "Manuste ja hoidlate kodeering" + setting_emails_header: "E-kirja päis" + setting_emails_footer: "E-kirja jalus" + setting_protocol: "Protokoll" + setting_per_page_options: "Objekte lehe kohta variandid" + setting_user_format: "Kasutaja nime esitamise vorm" + setting_activity_days_default: "Projektide ajalugu näidatakse" + setting_display_subprojects_issues: "Näita projektis vaikimisi ka alamprojektide teemasid" + setting_enabled_scm: "Kasutatavad lähtekoodi haldusvahendid" + setting_mail_handler_body_delimiters: "Kärbi e-kirja lõpp peale sellist rida" + setting_mail_handler_api_enabled: "E-kirjade vastuvõtt veebiteenuse kaudu" + setting_mail_handler_api_key: "Veebiteenuse API võti" + setting_sequential_project_identifiers: "Genereeri järjestikused projektitunnused" + setting_gravatar_enabled: "Kasuta Gravatari kasutajaikoone" + setting_gravatar_default: "Vaikimisi kasutatav ikoon" + setting_diff_max_lines_displayed: "Enim korraga näidatavaid erinevusi" + setting_file_max_size_displayed: "Kuvatava tekstifaili suurim pikkus" + setting_repository_log_display_limit: "Enim ajaloos näidatavaid sissekandeid" + setting_openid: "Luba OpenID-ga registreerimine ja sisselogimine" + setting_password_min_length: "Lühima lubatud parooli pikkus" + setting_new_project_user_role_id: "Projekti looja roll oma projektis" + setting_default_projects_modules: "Vaikimisi moodulid uutes projektides" + setting_issue_done_ratio: "Määra teema edenemise aste" + setting_issue_done_ratio_issue_field: "kasutades vastavat välja" + setting_issue_done_ratio_issue_status: "kasutades teema olekut" + setting_start_of_week: "Nädala alguspäev" + setting_rest_api_enabled: "Luba REST API kasutamine" + setting_cache_formatted_text: "Puhverda vormindatud teksti" + setting_default_notification_option: "Vaikimisi teavitatakse" + setting_commit_logtime_enabled: "Luba ajakulu sisestamine" + setting_commit_logtime_activity_id: "Tegevus kulunud ajal" + setting_gantt_items_limit: "Gantti diagrammi objektide suurim hulk" + setting_issue_group_assignment: "Luba teemade andmine gruppidele" + setting_default_issue_start_date_to_creation_date: "Uute teemade alguskuupäevaks teema loomise päev" + setting_commit_cross_project_ref: "Luba viiteid ja parandusi ka kõigi teiste projektide teemadele" + setting_unsubscribe: "Luba kasutajal oma konto kustutada" + + permission_add_project: "Projekte luua" + permission_add_subprojects: "Alamprojekte luua" + permission_edit_project: "Projekte muuta" + permission_select_project_modules: "Projektimooduleid valida" + permission_manage_members: "Liikmeid hallata" + permission_manage_project_activities: "Projekti tegevusi hallata" + permission_manage_versions: "Versioone hallata" + permission_manage_categories: "Kategooriaid hallata" + permission_view_issues: "Teemasid näha" + permission_add_issues: "Teemasid lisada" + permission_edit_issues: "Teemasid uuendada" + permission_manage_issue_relations: "Teemade seoseid hallata" + permission_set_issues_private: "Teemasid avalikeks või privaatseiks seada" + permission_set_own_issues_private: "Omi teemasid avalikeks või privaatseiks seada" + permission_add_issue_notes: "Märkusi lisada" + permission_edit_issue_notes: "Märkusi muuta" + permission_edit_own_issue_notes: "Omi märkusi muuta" + permission_move_issues: "Teemasid teise projekti tõsta" + permission_delete_issues: "Teemasid kustutada" + permission_manage_public_queries: "Avalikke päringuid hallata" + permission_save_queries: "Päringuid salvestada" + permission_view_gantt: "Gantti diagramme näha" + permission_view_calendar: "Kalendrit näha" + permission_view_issue_watchers: "Jälgijate nimekirja näha" + permission_add_issue_watchers: "Jälgijaid lisada" + permission_delete_issue_watchers: "Jälgijaid kustutada" + permission_log_time: "Ajakulu sisestada" + permission_view_time_entries: "Ajakulu näha" + permission_edit_time_entries: "Ajakulu kandeid muuta" + permission_edit_own_time_entries: "Omi ajakulu kandeid muuta" + permission_manage_news: "Uudiseid hallata" + permission_comment_news: "Uudiseid kommenteerida" + permission_view_documents: "Dokumente näha" + permission_manage_files: "Faile hallata" + permission_view_files: "Faile näha" + permission_manage_wiki: "Vikit hallata" + permission_rename_wiki_pages: "Vikilehti ümber nimetada" + permission_delete_wiki_pages: "Vikilehti kustutada" + permission_view_wiki_pages: "Vikit näha" + permission_view_wiki_edits: "Viki ajalugu näha" + permission_edit_wiki_pages: "Vikilehti muuta" + permission_delete_wiki_pages_attachments: "Manuseid kustutada" + permission_protect_wiki_pages: "Vikilehti kaitsta" + permission_manage_repository: "Hoidlaid hallata" + permission_browse_repository: "Hoidlaid sirvida" + permission_view_changesets: "Sissekandeid näha" + permission_commit_access: "Sissekandeid teha" + permission_manage_boards: "Foorumeid hallata" + permission_view_messages: "Postitusi näha" + permission_add_messages: "Postitusi lisada" + permission_edit_messages: "Postitusi muuta" + permission_edit_own_messages: "Omi postitusi muuta" + permission_delete_messages: "Postitusi kustutada" + permission_delete_own_messages: "Omi postitusi kustutada" + permission_export_wiki_pages: "Vikilehti eksportida" + permission_manage_subtasks: "Alamteemasid hallata" + permission_manage_related_issues: "Seotud teemasid hallata" + + project_module_issue_tracking: "Teemade jälgimine" + project_module_time_tracking: "Ajakulu arvestus" + project_module_news: "Uudised" + project_module_documents: "Dokumendid" + project_module_files: "Failid" + project_module_wiki: "Viki" + project_module_repository: "Hoidlad" + project_module_boards: "Foorumid" + project_module_calendar: "Kalender" + project_module_gantt: "Gantt" + + label_user: "Kasutaja" + label_user_plural: "Kasutajad" + label_user_new: "Uus kasutaja" + label_user_anonymous: "Anonüümne" + label_project: "Projekt" + label_project_new: "Uus projekt" + label_project_plural: "Projektid" + label_x_projects: + zero: "pole projekte" + one: "1 projekt" + other: "%{count} projekti" + label_project_all: "Kõik projektid" + label_project_latest: "Viimased projektid" + label_issue: "Teema" + label_issue_new: "Uus teema" + label_issue_plural: "Teemad" + label_issue_view_all: "Teemade nimekiri" + label_issues_by: "Teemad %{value} järgi" + label_issue_added: "Teema lisatud" + label_issue_updated: "Teema uuendatud" + label_issue_note_added: "Märkus lisatud" + label_issue_status_updated: "Olek uuendatud" + label_issue_priority_updated: "Prioriteet uuendatud" + label_document: "Dokument" + label_document_new: "Uus dokument" + label_document_plural: "Dokumendid" + label_document_added: "Dokument lisatud" + label_role: "Roll" + label_role_plural: "Rollid" + label_role_new: "Uus roll" + label_role_and_permissions: "Rollid ja õigused" + label_role_anonymous: "Anonüümne" + label_role_non_member: "Mitteliige" + label_member: "Liige" + label_member_new: "Uus liige" + label_member_plural: "Liikmed" + label_tracker: "Valdkond" + label_tracker_plural: "Valdkonnad" + label_tracker_new: "Uus valdkond" + label_workflow: "Töövood" + label_issue_status: "Olek" + label_issue_status_plural: "Olekud" + label_issue_status_new: "Uus olek" + label_issue_category: "Kategooria" + label_issue_category_plural: "Kategooriad" + label_issue_category_new: "Uus kategooria" + label_custom_field: "Omaloodud väli" + label_custom_field_plural: "Omaloodud väljad" + label_custom_field_new: "Uus väli" + label_enumerations: "Loetelud" + label_enumeration_new: "Uus väärtus" + label_information: "Teave" + label_information_plural: "Teave" + label_please_login: "Palun logi sisse" + label_register: "Registreeru" + label_login_with_open_id_option: "või logi sisse OpenID-ga" + label_password_lost: "Kui parool on ununud..." + label_home: "Kodu" + label_my_page: "Oma leht" + label_my_account: "Oma konto" + label_my_projects: "Oma projektid" + label_my_page_block: "Uus blokk" + label_administration: "Seadistused" + label_login: "Logi sisse" + label_logout: "Logi välja" + label_help: "Abi" + label_reported_issues: "Minu poolt lisatud teemad" + label_assigned_to_me_issues: "Minu teha olevad teemad" + label_last_login: "Viimane ühendus" + label_registered_on: "Registreeritud" + label_activity: "Ajalugu" + label_overall_activity: "Üldine tegevuste ajalugu" + label_user_activity: "%{value} tegevuste ajalugu" + label_new: "Uus" + label_logged_as: "Sisse logitud kui" + label_environment: "Keskkond" + label_authentication: "Autentimine" + label_auth_source: "Autentimisallikas" + label_auth_source_new: "Uus autentimisallikas" + label_auth_source_plural: "Autentimisallikad" + label_subproject_plural: "Alamprojektid" + label_subproject_new: "Uus alamprojekt" + label_and_its_subprojects: "%{value} ja selle alamprojektid" + label_min_max_length: "Min.-maks. pikkus" + label_list: "Nimekiri" + label_date: "Kuupäev" + label_integer: "Täisarv" + label_float: "Ujukomaarv" + label_boolean: "Tõeväärtus" + label_string: "Tekst" + label_text: "Pikk tekst" + label_attribute: "Atribuut" + label_attribute_plural: "Atribuudid" + label_no_data: "Pole" + label_change_status: "Muuda olekut" + label_history: "Ajalugu" + label_attachment: "Fail" + label_attachment_new: "Uus fail" + label_attachment_delete: "Kustuta fail" + label_attachment_plural: "Failid" + label_file_added: "Fail lisatud" + label_report: "Aruanne" + label_report_plural: "Aruanded" + label_news: "Uudised" + label_news_new: "Lisa uudis" + label_news_plural: "Uudised" + label_news_latest: "Viimased uudised" + label_news_view_all: "Kõik uudised" + label_news_added: "Uudis lisatud" + label_news_comment_added: "Kommentaar uudisele lisatud" + label_settings: "Seaded" + label_overview: "Ülevaade" + label_version: "Versioon" + label_version_new: "Uus versioon" + label_version_plural: "Versioonid" + label_close_versions: "Sulge lõpetatud versioonid" + label_confirmation: "Kinnitus" + label_export_to: "Samuti saadaval kujul:" + label_read: "Loe..." + label_public_projects: "Avalikud projektid" + label_open_issues: "avatud" + label_open_issues_plural: "avatud" + label_closed_issues: "suletud" + label_closed_issues_plural: "suletud" + label_x_open_issues_abbr_on_total: + zero: "0 avatud / %{total}" + one: "1 avatud / %{total}" + other: "%{count} avatud / %{total}" + label_x_open_issues_abbr: + zero: "0 avatud" + one: "1 avatud" + other: "%{count} avatud" + label_x_closed_issues_abbr: + zero: "0 suletud" + one: "1 suletud" + other: "%{count} suletud" + label_x_issues: + zero: "0 teemat" + one: "1 teema" + other: "%{count} teemat" + label_total: "Kokku" + label_permissions: "Õigused" + label_current_status: "Praegune olek" + label_new_statuses_allowed: "Uued lubatud olekud" + label_all: "kõik" + label_none: "pole" + label_nobody: "eikeegi" + label_next: "Järgmine" + label_previous: "Eelmine" + label_used_by: "Kasutab" + label_details: "Üksikasjad" + label_add_note: "Lisa märkus" + label_per_page: "Lehe kohta" + label_calendar: "Kalender" + label_months_from: "kuu kaugusel" + label_gantt: "Gantt" + label_internal: "Sisemine" + label_last_changes: "viimased %{count} muudatust" + label_change_view_all: "Kõik muudatused" + label_personalize_page: "Kujunda leht ümber" + label_comment: "Kommentaar" + label_comment_plural: "Kommentaarid" + label_x_comments: + zero: "kommentaare pole" + one: "1 kommentaar" + other: "%{count} kommentaari" + label_comment_add: "Lisa kommentaar" + label_comment_added: "Kommentaar lisatud" + label_comment_delete: "Kustuta kommentaar" + label_query: "Omaloodud päring" + label_query_plural: "Omaloodud päringud" + label_query_new: "Uus päring" + label_my_queries: "Mu omaloodud päringud" + label_filter_add: "Lisa filter" + label_filter_plural: "Filtrid" + label_equals: "on" + label_not_equals: "ei ole" + label_in_less_than: "on väiksem kui" + label_in_more_than: "on suurem kui" + label_greater_or_equal: "suurem-võrdne" + label_less_or_equal: "väiksem-võrdne" + label_between: "vahemikus" + label_in: "sisaldub hulgas" + label_today: "täna" + label_all_time: "piirideta" + label_yesterday: "eile" + label_this_week: "sel nädalal" + label_last_week: "eelmisel nädalal" + label_last_n_days: "viimase %{count} päeva jooksul" + label_this_month: "sel kuul" + label_last_month: "eelmisel kuul" + label_this_year: "sel aastal" + label_date_range: "Kuupäevavahemik" + label_less_than_ago: "uuem kui" + label_more_than_ago: "vanem kui" + label_ago: "vanus" + label_contains: "sisaldab" + label_not_contains: "ei sisalda" + label_day_plural: "päeva" + label_repository: "Hoidla" + label_repository_new: "Uus hoidla" + label_repository_plural: "Hoidlad" + label_browse: "Sirvi" + label_branch: "Haru" + label_tag: "Sildiga" + label_revision: "Sissekanne" + label_revision_plural: "Sissekanded" + label_revision_id: "Sissekande kood %{value}" + label_associated_revisions: "Seotud sissekanded" + label_added: "lisatud" + label_modified: "muudetud" + label_copied: "kopeeritud" + label_renamed: "ümber nimetatud" + label_deleted: "kustutatud" + label_latest_revision: "Viimane sissekanne" + label_latest_revision_plural: "Viimased sissekanded" + label_view_revisions: "Haru ajalugu" + label_view_all_revisions: "Kogu ajalugu" + label_max_size: "Suurim pikkus" + label_sort_highest: "Nihuta esimeseks" + label_sort_higher: "Nihuta üles" + label_sort_lower: "Nihuta alla" + label_sort_lowest: "Nihuta viimaseks" + label_roadmap: "Teekaart" + label_roadmap_due_in: "Tähtaeg %{value}" + label_roadmap_overdue: "%{value} hiljaks jäänud" + label_roadmap_no_issues: "Selles versioonis ei ole teemasid" + label_search: "Otsi" + label_result_plural: "Tulemused" + label_all_words: "Kõik sõnad" + label_wiki: "Viki" + label_wiki_edit: "Viki muutmine" + label_wiki_edit_plural: "Viki muutmised" + label_wiki_page: "Vikileht" + label_wiki_page_plural: "Vikilehed" + label_index_by_title: "Järjesta pealkirja järgi" + label_index_by_date: "Järjesta kuupäeva järgi" + label_current_version: "Praegune versioon" + label_preview: "Eelvaade" + label_feed_plural: "Vood" + label_changes_details: "Kõigi muudatuste üksikasjad" + label_issue_tracking: "Teemade jälgimine" + label_spent_time: "Kulutatud aeg" + label_overall_spent_time: "Kokku kulutatud aeg" + label_f_hour: "%{value} tund" + label_f_hour_plural: "%{value} tundi" + label_time_tracking: "Ajakulu arvestus" + label_change_plural: "Muudatused" + label_statistics: "Statistika" + label_commits_per_month: "Sissekandeid kuu kohta" + label_commits_per_author: "Sissekandeid autori kohta" + label_diff: "erinevused" + label_view_diff: "Vaata erinevusi" + label_diff_inline: "teksti sees" + label_diff_side_by_side: "kõrvuti" + label_options: "Valikud" + label_copy_workflow_from: "Kopeeri see töövoog" + label_permissions_report: "Õiguste aruanne" + label_watched_issues: "Jälgitud teemad" + label_related_issues: "Seotud teemad" + label_applied_status: "Kehtestatud olek" + label_loading: "Laadimas..." + label_relation_new: "Uus seos" + label_relation_delete: "Kustuta seos" + label_relates_to: "seostub" + label_duplicates: "duplitseerib" + label_duplicated_by: "duplitseerija" + label_blocks: "blokeerib" + label_blocked_by: "blokeerija" + label_precedes: "eelneb" + label_follows: "järgneb" + label_end_to_start: "lõpust alguseni" + label_end_to_end: "lõpust lõpuni" + label_start_to_start: "algusest alguseni" + label_start_to_end: "algusest lõpuni" + label_stay_logged_in: "Püsi sisselogituna" + label_disabled: "pole võimalik" + label_show_completed_versions: "Näita lõpetatud versioone" + label_me: "mina" + label_board: "Foorum" + label_board_new: "Uus foorum" + label_board_plural: "Foorumid" + label_board_locked: "Lukus" + label_board_sticky: "Püsiteema" + label_topic_plural: "Teemad" + label_message_plural: "Postitused" + label_message_last: "Viimane postitus" + label_message_new: "Uus postitus" + label_message_posted: "Postitus lisatud" + label_reply_plural: "Vastused" + label_send_information: "Saada teave konto kasutajale" + label_year: "Aasta" + label_month: "Kuu" + label_week: "Nädal" + label_date_from: "Alates" + label_date_to: "Kuni" + label_language_based: "Kasutaja keele põhjal" + label_sort_by: "Sorteeri %{value} järgi" + label_send_test_email: "Saada kontrollkiri" + label_feeds_access_key: "RSS juurdepääsuvõti" + label_missing_feeds_access_key: "RSS juurdepääsuvõti on puudu" + label_feeds_access_key_created_on: "RSS juurdepääsuvõti loodi %{value} tagasi" + label_module_plural: "Moodulid" + label_added_time_by: "Lisatud %{author} poolt %{age} tagasi" + label_updated_time_by: "Uuendatud %{author} poolt %{age} tagasi" + label_updated_time: "Uuendatud %{value} tagasi" + label_jump_to_a_project: "Ava projekt..." + label_file_plural: "Failid" + label_changeset_plural: "Muudatused" + label_default_columns: "Vaikimisi veerud" + label_no_change_option: "(Ei muutu)" + label_bulk_edit_selected_issues: "Muuda valitud teemasid korraga" + label_bulk_edit_selected_time_entries: "Muuda valitud ajakandeid korraga" + label_theme: "Visuaalne teema" + label_default: "Tavaline" + label_search_titles_only: "Ainult pealkirjadest" + label_user_mail_option_all: "Kõigist tegevustest kõigis mu projektides" + label_user_mail_option_selected: "Kõigist tegevustest ainult valitud projektides..." + label_user_mail_option_none: "Teavitusi ei saadeta" + label_user_mail_option_only_my_events: "Ainult mu jälgitavatest või minuga seotud tegevustest" + label_user_mail_option_only_assigned: "Ainult minu teha olevate asjade kohta" + label_user_mail_option_only_owner: "Ainult mu oma asjade kohta" + label_user_mail_no_self_notified: "Ära teavita mind mu enda tehtud muudatustest" + label_registration_activation_by_email: "e-kirjaga" + label_registration_manual_activation: "käsitsi" + label_registration_automatic_activation: "automaatselt" + label_display_per_page: "Lehe kohta: %{value}" + label_age: "Vanus" + label_change_properties: "Muuda omadusi" + label_general: "Üldine" + label_more: "Rohkem" + label_scm: "Lähtekoodi haldusvahend" + label_plugins: "Lisamoodulid" + label_ldap_authentication: "LDAP autentimine" + label_downloads_abbr: "A/L" + label_optional_description: "Teave" + label_add_another_file: "Lisa veel üks fail" + label_preferences: "Eelistused" + label_chronological_order: "kronoloogiline" + label_reverse_chronological_order: "tagurpidi kronoloogiline" + label_planning: "Planeerimine" + label_incoming_emails: "Sissetulevad e-kirjad" + label_generate_key: "Genereeri võti" + label_issue_watchers: "Jälgijad" + label_example: "Näide" + label_display: "Kujundus" + label_sort: "Sorteeri" + label_ascending: "Kasvavalt" + label_descending: "Kahanevalt" + label_date_from_to: "Alates %{start} kuni %{end}" + label_wiki_content_added: "Vikileht lisatud" + label_wiki_content_updated: "Vikileht uuendatud" + label_group: "Grupp" + label_group_plural: "Grupid" + label_group_new: "Uus grupp" + label_time_entry_plural: "Kulutatud aeg" + label_version_sharing_none: "ei toimu" + label_version_sharing_descendants: "alamprojektidega" + label_version_sharing_hierarchy: "projektihierarhiaga" + label_version_sharing_tree: "projektipuuga" + label_version_sharing_system: "kõigi projektidega" + label_update_issue_done_ratios: "Uuenda edenemise astmeid" + label_copy_source: "Allikas" + label_copy_target: "Sihtkoht" + label_copy_same_as_target: "Sama mis sihtkoht" + label_display_used_statuses_only: "Näita ainult selles valdkonnas kasutusel olekuid" + label_api_access_key: "API juurdepääsuvõti" + label_missing_api_access_key: "API juurdepääsuvõti on puudu" + label_api_access_key_created_on: "API juurdepääsuvõti loodi %{value} tagasi" + label_profile: "Profiil" + label_subtask_plural: "Alamteemad" + label_project_copy_notifications: "Saada projekti kopeerimise kohta teavituskiri" + label_principal_search: "Otsi kasutajat või gruppi:" + label_user_search: "Otsi kasutajat:" + label_additional_workflow_transitions_for_author: "Luba ka järgmisi üleminekuid kui kasutaja on teema looja" + label_additional_workflow_transitions_for_assignee: "Luba ka järgmisi üleminekuid kui kasutaja on teemaga tegeleja" + label_issues_visibility_all: "kõiki teemasid" + label_issues_visibility_public: "kõiki mitteprivaatseid teemasid" + label_issues_visibility_own: "enda poolt loodud või enda teha teemasid" + label_git_report_last_commit: "Viimase sissekande teave otse failinimekirja" + label_parent_revision: "Eellane" + label_child_revision: "Järglane" + label_export_options: "%{export_format} ekspordivalikud" + label_copy_attachments: "Kopeeri manused" + label_item_position: "%{position}/%{count}" + label_completed_versions: "Lõpetatud versioonid" + label_search_for_watchers: "Otsi lisamiseks jälgijaid" + + button_login: "Logi sisse" + button_submit: "Sisesta" + button_save: "Salvesta" + button_check_all: "Märgi kõik" + button_uncheck_all: "Nulli valik" + button_collapse_all: "Voldi kõik kokku" + button_expand_all: "Voldi kõik lahti" + button_delete: "Kustuta" + button_create: "Loo" + button_create_and_continue: "Loo ja jätka" + button_test: "Testi" + button_edit: "Muuda" + button_edit_associated_wikipage: "Muuda seotud vikilehte: %{page_title}" + button_add: "Lisa" + button_change: "Muuda" + button_apply: "Lae" + button_clear: "Puhasta" + button_lock: "Lukusta" + button_unlock: "Ava lukust" + button_download: "Lae alla" + button_list: "Listi" + button_view: "Vaata" + button_move: "Tõsta" + button_move_and_follow: "Tõsta ja järgne" + button_back: "Tagasi" + button_cancel: "Katkesta" + button_activate: "Aktiveeri" + button_sort: "Sorteeri" + button_log_time: "Ajakulu" + button_rollback: "Rulli tagasi sellesse versiooni" + button_watch: "Jälgi" + button_unwatch: "Ära jälgi" + button_reply: "Vasta" + button_archive: "Arhiveeri" + button_unarchive: "Arhiivist tagasi" + button_reset: "Nulli" + button_rename: "Nimeta ümber" + button_change_password: "Vaheta parool" + button_copy: "Kopeeri" + button_copy_and_follow: "Kopeeri ja järgne" + button_annotate: "Annoteeri" + button_update: "Muuda" + button_configure: "Konfigureeri" + button_quote: "Tsiteeri" + button_duplicate: "Duplitseeri" + button_show: "Näita" + button_edit_section: "Muuda seda sektsiooni" + button_export: "Ekspordi" + button_delete_my_account: "Kustuta oma konto" + + status_active: "aktiivne" + status_registered: "registreeritud" + status_locked: "lukus" + + version_status_open: "avatud" + version_status_locked: "lukus" + version_status_closed: "suletud" + + field_active: "Aktiivne" + + text_select_mail_notifications: "Tegevused, millest peaks e-kirjaga teavitama" + text_regexp_info: "nt. ^[A-Z0-9]+$" + text_min_max_length_info: "0 tähendab, et piiranguid ei ole" + text_project_destroy_confirmation: "Oled Sa kindel oma soovis see projekt täielikult kustutada?" + text_subprojects_destroy_warning: "Alamprojekt(id) - %{value} - kustutatakse samuti." + text_workflow_edit: "Töövoo muutmiseks vali roll ja valdkond" + text_are_you_sure: "Oled Sa kindel?" + text_journal_changed: "%{label} muudetud %{old} -> %{new}" + text_journal_changed_no_detail: "%{label} uuendatud" + text_journal_set_to: "%{label} uus väärtus on %{value}" + text_journal_deleted: "%{label} kustutatud (%{old})" + text_journal_added: "%{label} %{value} lisatud" + text_tip_issue_begin_day: "teema avamise päev" + text_tip_issue_end_day: "teema sulgemise päev" + text_tip_issue_begin_end_day: "teema avati ja sulgeti samal päeval" + text_project_identifier_info: "Lubatud on ainult väikesed tähed (a-z), numbrid ja kriipsud.
    Peale salvestamist ei saa tunnust enam muuta." + text_caracters_maximum: "%{count} märki kõige rohkem." + text_caracters_minimum: "Peab olema vähemalt %{count} märki pikk." + text_length_between: "Pikkus %{min} kuni %{max} märki." + text_tracker_no_workflow: "Selle valdkonna jaoks ei ole ühtegi töövoogu kirjeldatud" + text_unallowed_characters: "Lubamatud märgid" + text_comma_separated: "Lubatud erinevad väärtused (komaga eraldatult)." + text_line_separated: "Lubatud erinevad väärtused (igaüks eraldi real)." + text_issues_ref_in_commit_messages: "Teemadele ja parandustele viitamine sissekannete märkustes" + text_issue_added: "%{author} lisas uue teema %{id}." + text_issue_updated: "%{author} uuendas teemat %{id}." + text_wiki_destroy_confirmation: "Oled Sa kindel oma soovis kustutada see Viki koos kogu sisuga?" + text_issue_category_destroy_question: "Kustutatavat kategooriat kasutab %{count} teema(t). Mis Sa soovid nendega ette võtta?" + text_issue_category_destroy_assignments: "Jäta teemadel kategooria määramata" + text_issue_category_reassign_to: "Määra teemad teise kategooriasse" + text_user_mail_option: "Valimata projektidest saad teavitusi ainult jälgitavate või Sinuga seotud asjade kohta (nt. Sinu loodud või teha teemad)." + text_no_configuration_data: "Rollid, valdkonnad, olekud ja töövood ei ole veel seadistatud.\nVäga soovitav on laadida vaikeasetused. Peale laadimist saad neid ise muuta." + text_load_default_configuration: "Lae vaikeasetused" + text_status_changed_by_changeset: "Kehtestatakse muudatuses %{value}." + text_time_logged_by_changeset: "Kehtestatakse muudatuses %{value}." + text_issues_destroy_confirmation: "Oled Sa kindel oma soovis valitud teema(d) kustutada?" + text_issues_destroy_descendants_confirmation: "See kustutab samuti %{count} alamteemat." + text_time_entries_destroy_confirmation: "Oled Sa kindel oma soovis valitud ajakulu kanne/kanded kustutada?" + text_select_project_modules: "Projektis kasutatavad moodulid" + text_default_administrator_account_changed: "Algne administraatori konto on muudetud" + text_file_repository_writable: "Manuste kataloog on kirjutatav" + text_plugin_assets_writable: "Lisamoodulite abifailide kataloog on kirjutatav" + text_rmagick_available: "RMagick on kasutatav (mittekohustuslik)" + text_destroy_time_entries_question: "Kustutatavatele teemadele oli kirja pandud %{hours} tundi. Mis Sa soovid ette võtta?" + text_destroy_time_entries: "Kustuta need tunnid" + text_assign_time_entries_to_project: "Vii tunnid üle teise projekti" + text_reassign_time_entries: "Määra tunnid sellele teemale:" + text_user_wrote: "%{value} kirjutas:" + text_enumeration_destroy_question: "Selle väärtusega on seotud %{count} objekt(i)." + text_enumeration_category_reassign_to: "Seo nad teise väärtuse külge:" + text_email_delivery_not_configured: "E-kirjade saatmine ei ole seadistatud ja teavitusi ei saadeta.\nKonfigureeri oma SMTP server failis config/configuration.yml ja taaskäivita Redmine." + text_repository_usernames_mapping: "Seosta Redmine kasutaja hoidlasse sissekannete tegijaga.\nSama nime või e-postiga kasutajad seostatakse automaatselt." + text_diff_truncated: "... Osa erinevusi jäi välja, sest neid on näitamiseks liiga palju." + text_custom_field_possible_values_info: "Üks rida iga väärtuse jaoks" + text_wiki_page_destroy_question: "Sel lehel on %{descendants} järglasleht(e) ja järeltulija(t). Mis Sa soovid ette võtta?" + text_wiki_page_nullify_children: "Muuda järglaslehed uuteks juurlehtedeks" + text_wiki_page_destroy_children: "Kustuta järglaslehed ja kõik nende järglased" + text_wiki_page_reassign_children: "Määra järglaslehed teise lehe külge" + text_own_membership_delete_confirmation: "Sa võtad endalt ära osa või kõik õigused ega saa edaspidi seda projekti võib-olla enam muuta.\nOled Sa jätkamises kindel?" + text_zoom_in: "Vaata lähemalt" + text_zoom_out: "Vaata kaugemalt" + text_warn_on_leaving_unsaved: "Sel lehel on salvestamata teksti, mis läheb kaduma, kui siit lehelt lahkud." + text_scm_path_encoding_note: "Vaikimisi UTF-8" + text_git_repository_note: "Hoidla peab olema paljas (bare) ja kohalik (nt. /gitrepo, c:\\gitrepo)" + text_mercurial_repository_note: "Hoidla peab olema kohalik (nt. /hgrepo, c:\\hgrepo)" + text_scm_command: "Hoidla poole pöördumise käsk" + text_scm_command_version: "Versioon" + text_scm_config: "Hoidlate poole pöördumist saab konfigureerida failis config/configuration.yml. Peale selle muutmist taaskäivita Redmine." + text_scm_command_not_available: "Hoidla poole pöördumine ebaõnnestus. Palun kontrolli seadistusi." + text_issue_conflict_resolution_overwrite: "Kehtesta oma muudatused (kõik märkused jäävad, ent muu võidakse üle kirjutada)" + text_issue_conflict_resolution_add_notes: "Lisa oma märkused, aga loobu teistest muudatustest" + text_issue_conflict_resolution_cancel: "Loobu kõigist muudatustest ja lae %{link} uuesti" + text_account_destroy_confirmation: "Oled Sa kindel?\nSu konto kustutatakse jäädavalt ja seda pole võimalik taastada." + + default_role_manager: "Haldaja" + default_role_developer: "Arendaja" + default_role_reporter: "Edastaja" + default_tracker_bug: "Veaparandus" + default_tracker_feature: "Täiendus" + default_tracker_support: "Klienditugi" + default_issue_status_new: "Avatud" + default_issue_status_in_progress: "Töös" + default_issue_status_resolved: "Lahendatud" + default_issue_status_feedback: "Tagasiside" + default_issue_status_closed: "Suletud" + default_issue_status_rejected: "Tagasi lükatud" + default_doc_category_user: "Juhend lõppkasutajale" + default_doc_category_tech: "Tehniline dokumentatsioon" + default_priority_low: "Aega on" + default_priority_normal: "Tavaline" + default_priority_high: "Pakiline" + default_priority_urgent: "Täna vaja" + default_priority_immediate: "Kohe vaja" + default_activity_design: "Kavandamine" + default_activity_development: "Arendamine" + + enumeration_issue_priorities: "Teemade prioriteedid" + enumeration_doc_categories: "Dokumentide kategooriad" + enumeration_activities: "Tegevused (ajakulu)" + enumeration_system_activity: "Süsteemi aktiivsus" + description_filter: "Filter" + description_search: "Otsinguväli" + description_choose_project: "Projektid" + description_project_scope: "Otsingu ulatus" + description_notes: "Märkused" + description_message_content: "Postituse sisu" + description_query_sort_criteria_attribute: "Sorteerimise kriteerium" + description_query_sort_criteria_direction: "Sorteerimise suund" + description_user_mail_notification: "E-kirjaga teavitamise seaded" + description_available_columns: "Kasutatavad veerud" + description_selected_columns: "Valitud veerud" + description_all_columns: "Kõik veerud" + description_issue_category_reassign: "Vali uus kategooria" + description_wiki_subpages_reassign: "Vali lehele uus vanem" + description_date_range_list: "Vali vahemik nimekirjast" + description_date_range_interval: "Vali vahemik algus- ja lõpukuupäeva abil" + description_date_from: "Sisesta alguskuupäev" + description_date_to: "Sisesta lõpukuupäev" + error_session_expired: Your session has expired. Please login again. + text_session_expiration_settings: "Warning: changing these settings may expire the current sessions including yours." + setting_session_lifetime: Session maximum lifetime + setting_session_timeout: Session inactivity timeout + label_session_expiration: Session expiration + permission_close_project: Close / reopen the project + label_show_closed_projects: View closed projects + button_close: Close + button_reopen: Reopen + project_status_active: active + project_status_closed: closed + project_status_archived: archived + text_project_closed: This project is closed and read-only. + notice_user_successful_create: User %{id} created. + field_core_fields: Standard fields + field_timeout: Timeout (in seconds) + setting_thumbnails_enabled: Display attachment thumbnails + setting_thumbnails_size: Thumbnails size (in pixels) + label_status_transitions: Status transitions + label_fields_permissions: Fields permissions + label_readonly: Read-only + label_required: Required + text_repository_identifier_info: "Lubatud on ainult väikesed tähed (a-z), numbrid ja kriipsud.
    Peale salvestamist ei saa tunnust enam muuta." + field_board_parent: Parent forum + label_attribute_of_project: Project's %{name} + label_attribute_of_author: Author's %{name} + label_attribute_of_assigned_to: Assignee's %{name} + label_attribute_of_fixed_version: Target version's %{name} + label_copy_subtasks: Copy subtasks + label_copied_to: copied to + label_copied_from: copied from + label_any_issues_in_project: any issues in project + label_any_issues_not_in_project: any issues not in project + field_private_notes: Private notes + permission_view_private_notes: View private notes + permission_set_notes_private: Set notes as private + label_no_issues_in_project: no issues in project + label_any: "kõik" + label_last_n_weeks: last %{count} weeks + setting_cross_project_subtasks: Allow cross-project subtasks + label_cross_project_descendants: "alamprojektidega" + label_cross_project_tree: "projektipuuga" + label_cross_project_hierarchy: "projektihierarhiaga" + label_cross_project_system: "kõigi projektidega" + button_hide: Hide + setting_non_working_week_days: Non-working days + label_in_the_next_days: in the next + label_in_the_past_days: in the past + label_attribute_of_user: User's %{name} + text_turning_multiple_off: If you disable multiple values, multiple values will be + removed in order to preserve only one value per item. + label_attribute_of_issue: Issue's %{name} + permission_add_documents: Add documents + permission_edit_documents: Edit documents + permission_delete_documents: Delete documents + label_gantt_progress_line: Progress line + setting_jsonp_enabled: Enable JSONP support + field_inherit_members: Inherit members + field_closed_on: Closed + setting_default_projects_tracker_ids: Default trackers for new projects + label_total_time: "Kokku" diff --git a/config/locales/eu.yml b/config/locales/eu.yml new file mode 100644 index 00000000..e0aa8315 --- /dev/null +++ b/config/locales/eu.yml @@ -0,0 +1,1090 @@ +# Redmine EU language +# Author: Ales Zabala Alava (Shagi), +# 2010-01-25 +# Distributed under the same terms as the Redmine itself. +eu: + direction: ltr + date: + formats: + # Use the strftime parameters for formats. + # When no format has been given, it uses default. + # You can provide other formats here if you like! + default: "%Y/%m/%d" + short: "%b %d" + long: "%Y %B %d" + + day_names: [Igandea, Astelehena, Asteartea, Asteazkena, Osteguna, Ostirala, Larunbata] + abbr_day_names: [Ig., Al., Ar., Az., Og., Or., La.] + + # Don't forget the nil at the beginning; there's no such thing as a 0th month + month_names: [~, Urtarrila, Otsaila, Martxoa, Apirila, Maiatza, Ekaina, Uztaila, Abuztua, Iraila, Urria, Azaroa, Abendua] + abbr_month_names: [~, Urt, Ots, Mar, Api, Mai, Eka, Uzt, Abu, Ira, Urr, Aza, Abe] + # Used in date_select and datime_select. + order: + - :year + - :month + - :day + + time: + formats: + default: "%Y/%m/%d %H:%M" + time: "%H:%M" + short: "%b %d %H:%M" + long: "%Y %B %d %H:%M" + am: "am" + pm: "pm" + + datetime: + distance_in_words: + half_a_minute: "minutu erdi" + less_than_x_seconds: + one: "segundu bat baino gutxiago" + other: "%{count} segundu baino gutxiago" + x_seconds: + one: "segundu 1" + other: "%{count} segundu" + less_than_x_minutes: + one: "minutu bat baino gutxiago" + other: "%{count} minutu baino gutxiago" + x_minutes: + one: "minutu 1" + other: "%{count} minutu" + about_x_hours: + one: "ordu 1 inguru" + other: "%{count} ordu inguru" + x_hours: + one: "1 hour" + other: "%{count} hours" + x_days: + one: "egun 1" + other: "%{count} egun" + about_x_months: + one: "hilabete 1 inguru" + other: "%{count} hilabete inguru" + x_months: + one: "hilabete 1" + other: "%{count} hilabete" + about_x_years: + one: "urte 1 inguru" + other: "%{count} urte inguru" + over_x_years: + one: "urte 1 baino gehiago" + other: "%{count} urte baino gehiago" + almost_x_years: + one: "ia urte 1" + other: "ia %{count} urte" + + number: + format: + separator: "." + delimiter: "" + precision: 3 + human: + format: + delimiter: "" + precision: 3 + storage_units: + format: "%n %u" + units: + byte: + one: "Byte" + other: "Byte" + kb: "KB" + mb: "MB" + gb: "GB" + tb: "TB" + +# Used in array.to_sentence. + support: + array: + sentence_connector: "eta" + skip_last_comma: false + + activerecord: + errors: + template: + header: + one: "Errore batek %{model} hau godetzea galarazi du." + other: "%{count} errorek %{model} hau gordetzea galarazi dute." + messages: + inclusion: "ez dago zerrendan" + exclusion: "erreserbatuta dago" + invalid: "baliogabea da" + confirmation: "ez du berrespenarekin bat egiten" + accepted: "onartu behar da" + empty: "ezin da hutsik egon" + blank: "ezin da hutsik egon" + too_long: "luzeegia da (maximoa %{count} karaktere dira)" + too_short: "laburregia da (minimoa %{count} karaktere dira)" + wrong_length: "luzera ezegokia da (%{count} karakter izan beharko litzake)" + taken: "dagoeneko hartuta dago" + not_a_number: "ez da zenbaki bat" + not_a_date: "ez da baliozko data" + greater_than: "%{count} baino handiagoa izan behar du" + greater_than_or_equal_to: "%{count} edo handiagoa izan behar du" + equal_to: "%{count} izan behar du" + less_than: "%{count} baino gutxiago izan behar du" + less_than_or_equal_to: "%{count} edo gutxiago izan behar du" + odd: "bakoitia izan behar du" + even: "bikoitia izan behar du" + greater_than_start_date: "hasiera data baino handiagoa izan behar du" + not_same_project: "ez dago proiektu berdinean" + circular_dependency: "Erlazio honek mendekotasun zirkular bat sortuko luke" + cant_link_an_issue_with_a_descendant: "Zeregin bat ezin da bere azpiataza batekin estekatu." + + actionview_instancetag_blank_option: Hautatu mesedez + + general_text_No: 'Ez' + general_text_Yes: 'Bai' + general_text_no: 'ez' + general_text_yes: 'bai' + general_lang_name: 'Euskara' + general_csv_separator: ',' + general_csv_decimal_separator: '.' + general_csv_encoding: UTF-8 + general_pdf_encoding: UTF-8 + general_first_day_of_week: '1' + + notice_account_updated: Kontua ongi eguneratu da. + notice_account_invalid_creditentials: Erabiltzaile edo pasahitz ezegokia + notice_account_password_updated: Pasahitza ongi eguneratu da. + notice_account_wrong_password: Pasahitz ezegokia. + notice_account_register_done: Kontua ongi sortu da. Kontua gaitzeko klikatu epostan adierazi zaizun estekan. + notice_account_unknown_email: Erabiltzaile ezezaguna. + notice_can_t_change_password: Kontu honek kanpoko autentikazio bat erabiltzen du. Ezinezkoa da pasahitza aldatzea. + notice_account_lost_email_sent: Pasahitz berria aukeratzeko jarraibideak dituen eposta bat bidali zaizu. + notice_account_activated: Zure kontua gaituta dago. Orain saioa has dezakezu + notice_successful_create: Sortze arrakastatsua. + notice_successful_update: Eguneratze arrakastatsua. + notice_successful_delete: Ezabaketa arrakastatsua. + notice_successful_connection: Konexio arrakastatsua. + notice_file_not_found: Atzitu nahi duzun orria ez da exisitzen edo ezabatua izan da. + notice_locking_conflict: Beste erabiltzaile batek datuak eguneratu ditu. + notice_not_authorized: Ez duzu orri hau atzitzeko baimenik. + notice_email_sent: "%{value} helbidera eposta bat bidali da" + notice_email_error: "Errorea eposta bidaltzean (%{value})" + notice_feeds_access_key_reseted: Zure RSS atzipen giltza berrezarri da. + notice_api_access_key_reseted: Zure API atzipen giltza berrezarri da. + notice_failed_to_save_issues: "Hautatutako %{total} zereginetatik %{count} ezin izan dira konpondu: %{ids}." + notice_no_issue_selected: "Ez da zereginik hautatu! Mesedez, editatu nahi dituzun arazoak markatu." + notice_account_pending: "Zure kontua sortu da, orain kudeatzailearen onarpenaren zain dago." + notice_default_data_loaded: Lehenetsitako konfigurazioa ongi kargatu da. + notice_unable_delete_version: Ezin da bertsioa ezabatu. + notice_issue_done_ratios_updated: Burututako zereginen erlazioa eguneratu da. + + error_can_t_load_default_data: "Ezin izan da lehenetsitako konfigurazioa kargatu: %{value}" + error_scm_not_found: "Sarrera edo berrikuspena ez da biltegian topatu." + error_scm_command_failed: "Errorea gertatu da biltegia atzitzean: %{value}" + error_scm_annotate: "Sarrera ez da existitzen edo ezin da anotatu." + error_issue_not_found_in_project: 'Zeregina ez da topatu edo ez da proiektu honetakoa' + error_no_tracker_in_project: 'Proiektu honek ez du aztarnaririk esleituta. Mesedez egiaztatu Proiektuaren ezarpenak.' + error_no_default_issue_status: 'Zereginek ez dute lehenetsitako egoerarik. Mesedez egiaztatu zure konfigurazioa ("Kudeaketa -> Arazoen egoerak" atalera joan).' + error_can_not_reopen_issue_on_closed_version: 'Itxitako bertsio batera esleitutako zereginak ezin dira berrireki' + error_can_not_archive_project: Proiektu hau ezin da artxibatu + error_issue_done_ratios_not_updated: "Burututako zereginen erlazioa ez da eguneratu." + error_workflow_copy_source: 'Mesedez hautatu iturburuko aztarnari edo rola' + error_workflow_copy_target: 'Mesedez hautatu helburuko aztarnari(ak) edo rola(k)' + + warning_attachments_not_saved: "%{count} fitxategi ezin izan d(ir)a gorde." + + mail_subject_lost_password: "Zure %{value} pasahitza" + mail_body_lost_password: 'Zure pasahitza aldatzeko hurrengo estekan klikatu:' + mail_subject_register: "Zure %{value} kontuaren gaitzea" + mail_body_register: 'Zure kontua gaitzeko hurrengo estekan klikatu:' + mail_body_account_information_external: "Zure %{value} kontua erabil dezakezu saioa hasteko." + mail_body_account_information: Zure kontuaren informazioa + mail_subject_account_activation_request: "%{value} kontu gaitzeko eskaera" + mail_body_account_activation_request: "Erabiltzaile berri bat (%{value}) erregistratu da. Kontua zure onarpenaren zain dago:" + mail_subject_reminder: "%{count} arazo hurrengo %{days} egunetan amaitzen d(ir)a" + mail_body_reminder: "Zuri esleituta dauden %{count} arazo hurrengo %{days} egunetan amaitzen d(ir)a:" + mail_subject_wiki_content_added: "'%{id}' wiki orria gehitu da" + mail_body_wiki_content_added: "%{author}-(e)k '%{id}' wiki orria gehitu du." + mail_subject_wiki_content_updated: "'%{id}' wiki orria eguneratu da" + mail_body_wiki_content_updated: "%{author}-(e)k '%{id}' wiki orria eguneratu du." + + + field_name: Izena + field_description: Deskribapena + field_summary: Laburpena + field_is_required: Beharrezkoa + field_firstname: Izena + field_lastname: Abizenak + field_mail: Eposta + field_filename: Fitxategia + field_filesize: Tamaina + field_downloads: Deskargak + field_author: Egilea + field_created_on: Sortuta + field_updated_on: Eguneratuta + field_field_format: Formatua + field_is_for_all: Proiektu guztietarako + field_possible_values: Balio posibleak + field_regexp: Expresio erregularra + field_min_length: Luzera minimoa + field_max_length: Luzera maxioma + field_value: Balioa + field_category: Kategoria + field_title: Izenburua + field_project: Proiektua + field_issue: Zeregina + field_status: Egoera + field_notes: Oharrak + field_is_closed: Itxitako arazoa + field_is_default: Lehenetsitako balioa + field_tracker: Aztarnaria + field_subject: Gaia + field_due_date: Amaiera data + field_assigned_to: Esleituta + field_priority: Lehentasuna + field_fixed_version: Helburuko bertsioa + field_user: Erabiltzilea + field_role: Rola + field_homepage: Orri nagusia + field_is_public: Publikoa + field_parent: "Honen azpiproiektua:" + field_is_in_roadmap: Arazoak ibilbide-mapan erakutsi + field_login: Erabiltzaile izena + field_mail_notification: Eposta jakinarazpenak + field_admin: Kudeatzailea + field_last_login_on: Azken konexioa + field_language: Hizkuntza + field_effective_date: Data + field_password: Pasahitza + field_new_password: Pasahitz berria + field_password_confirmation: Berrespena + field_version: Bertsioa + field_type: Mota + field_host: Ostalaria + field_port: Portua + field_account: Kontua + field_base_dn: Base DN + field_attr_login: Erabiltzaile atributua + field_attr_firstname: Izena atributua + field_attr_lastname: Abizenak atributua + field_attr_mail: Eposta atributua + field_onthefly: Zuzeneko erabiltzaile sorrera + field_start_date: Hasiera + field_done_ratio: Egindako % + field_auth_source: Autentikazio modua + field_hide_mail: Nire eposta helbidea ezkutatu + field_comments: Iruzkina + field_url: URL + field_start_page: Hasierako orria + field_subproject: Azpiproiektua + field_hours: Ordu + field_activity: Jarduera + field_spent_on: Data + field_identifier: Identifikatzailea + field_is_filter: Iragazki moduan erabilita + field_issue_to: Erlazionatutako zereginak + field_delay: Atzerapena + field_assignable: Arazoak rol honetara esleitu daitezke + field_redirect_existing_links: Existitzen diren estekak berbideratu + field_estimated_hours: Estimatutako denbora + field_column_names: Zutabeak + field_time_zone: Ordu zonaldea + field_searchable: Bilagarria + field_default_value: Lehenetsitako balioa + field_comments_sorting: Iruzkinak erakutsi + field_parent_title: Orri gurasoa + field_editable: Editagarria + field_watcher: Behatzailea + field_identity_url: OpenID URLa + field_content: Edukia + field_group_by: Emaitzak honegatik taldekatu + field_sharing: Partekatzea + + setting_app_title: Aplikazioaren izenburua + setting_app_subtitle: Aplikazioaren azpizenburua + setting_welcome_text: Ongietorriko testua + setting_default_language: Lehenetsitako hizkuntza + setting_login_required: Autentikazioa derrigorrezkoa + setting_self_registration: Norberak erregistratu + setting_attachment_max_size: Eranskinen tamaina max. + setting_issues_export_limit: Zereginen esportatze limitea + setting_mail_from: Igorlearen eposta helbidea + setting_bcc_recipients: Hartzaileak ezkutuko kopian (bcc) + setting_plain_text_mail: Testu soileko epostak (HTML-rik ez) + setting_host_name: Ostalari izena eta bidea + setting_text_formatting: Testu formatua + setting_wiki_compression: Wikiaren historia konprimitu + setting_feeds_limit: Jarioaren edukiera limitea + setting_default_projects_public: Proiektu berriak defektuz publikoak dira + setting_autofetch_changesets: Commit-ak automatikoki hartu + setting_sys_api_enabled: Biltegien kudeaketarako WS gaitu + setting_commit_ref_keywords: Erreferentzien gako-hitzak + setting_commit_fix_keywords: Konpontze gako-hitzak + setting_autologin: Saioa automatikoki hasi + setting_date_format: Data formatua + setting_time_format: Ordu formatua + setting_cross_project_issue_relations: Zereginak proiektuen artean erlazionatzea baimendu + setting_issue_list_default_columns: Zereginen zerrendan defektuz ikusten diren zutabeak + setting_emails_footer: Eposten oina + setting_protocol: Protokoloa + setting_per_page_options: Orriko objektuen aukerak + setting_user_format: Erabiltzaileak erakusteko formatua + setting_activity_days_default: Proiektuen jardueran erakusteko egunak + setting_display_subprojects_issues: Azpiproiektuen zereginak proiektu nagusian erakutsi defektuz + setting_enabled_scm: Gaitutako IKKak + setting_mail_handler_body_delimiters: "Lerro hauteko baten ondoren epostak moztu" + setting_mail_handler_api_enabled: Sarrerako epostentzako WS gaitu + setting_mail_handler_api_key: API giltza + setting_sequential_project_identifiers: Proiektuen identifikadore sekuentzialak sortu + setting_gravatar_enabled: Erabili Gravatar erabiltzaile ikonoak + setting_gravatar_default: Lehenetsitako Gravatar irudia + setting_diff_max_lines_displayed: Erakutsiko diren diff lerro kopuru maximoa + setting_file_max_size_displayed: Barnean erakuzten diren testu fitxategien tamaina maximoa + setting_repository_log_display_limit: Egunkari fitxategian erakutsiko diren berrikuspen kopuru maximoa. + setting_openid: Baimendu OpenID saio hasiera eta erregistatzea + setting_password_min_length: Pasahitzen luzera minimoa + setting_new_project_user_role_id: Proiektu berriak sortzerakoan kudeatzaile ez diren erabiltzaileei esleitutako rola + setting_default_projects_modules: Proiektu berrientzako defektuz gaitutako moduluak + setting_issue_done_ratio: "Zereginen burututako tasa kalkulatzean erabili:" + setting_issue_done_ratio_issue_field: Zeregin eremua erabili + setting_issue_done_ratio_issue_status: Zeregin egoera erabili + setting_start_of_week: "Egutegiak noiz hasi:" + setting_rest_api_enabled: Gaitu REST web zerbitzua + + permission_add_project: Proiektua sortu + permission_add_subprojects: Azpiproiektuak sortu + permission_edit_project: Proiektua editatu + permission_select_project_modules: Proiektuaren moduluak hautatu + permission_manage_members: Kideak kudeatu + permission_manage_versions: Bertsioak kudeatu + permission_manage_categories: Arazoen kategoriak kudeatu + permission_view_issues: Zereginak ikusi + permission_add_issues: Zereginak gehitu + permission_edit_issues: Zereginak aldatu + permission_manage_issue_relations: Zereginen erlazioak kudeatu + permission_add_issue_notes: Oharrak gehitu + permission_edit_issue_notes: Oharrak aldatu + permission_edit_own_issue_notes: Nork bere oharrak aldatu + permission_move_issues: Zereginak mugitu + permission_delete_issues: Zereginak ezabatu + permission_manage_public_queries: Galdera publikoak kudeatu + permission_save_queries: Galderak gorde + permission_view_gantt: Gantt grafikoa ikusi + permission_view_calendar: Egutegia ikusi + permission_view_issue_watchers: Behatzaileen zerrenda ikusi + permission_add_issue_watchers: Behatzaileak gehitu + permission_delete_issue_watchers: Behatzaileak ezabatu + permission_log_time: Igarotako denbora erregistratu + permission_view_time_entries: Igarotako denbora ikusi + permission_edit_time_entries: Denbora egunkariak editatu + permission_edit_own_time_entries: Nork bere denbora egunkariak editatu + permission_manage_news: Berriak kudeatu + permission_comment_news: Berrien iruzkinak egin + permission_view_documents: Dokumentuak ikusi + permission_manage_files: Fitxategiak kudeatu + permission_view_files: Fitxategiak ikusi + permission_manage_wiki: Wikia kudeatu + permission_rename_wiki_pages: Wiki orriak berrizendatu + permission_delete_wiki_pages: Wiki orriak ezabatu + permission_view_wiki_pages: Wikia ikusi + permission_view_wiki_edits: Wikiaren historia ikusi + permission_edit_wiki_pages: Wiki orriak editatu + permission_delete_wiki_pages_attachments: Eranskinak ezabatu + permission_protect_wiki_pages: Wiki orriak babestu + permission_manage_repository: Biltegiak kudeatu + permission_browse_repository: Biltegia arakatu + permission_view_changesets: Aldaketak ikusi + permission_commit_access: Commit atzipena + permission_manage_boards: Foroak kudeatu + permission_view_messages: Mezuak ikusi + permission_add_messages: Mezuak bidali + permission_edit_messages: Mezuak aldatu + permission_edit_own_messages: Nork bere mezuak aldatu + permission_delete_messages: Mezuak ezabatu + permission_delete_own_messages: Nork bere mezuak ezabatu + + project_module_issue_tracking: Zereginen jarraipena + project_module_time_tracking: Denbora jarraipena + project_module_news: Berriak + project_module_documents: Dokumentuak + project_module_files: Fitxategiak + project_module_wiki: Wiki + project_module_repository: Biltegia + project_module_boards: Foroak + + label_user: Erabiltzailea + label_user_plural: Erabiltzaileak + label_user_new: Erabiltzaile berria + label_user_anonymous: Ezezaguna + label_project: Proiektua + label_project_new: Proiektu berria + label_project_plural: Proiektuak + label_x_projects: + zero: proiekturik ez + one: proiektu bat + other: "%{count} proiektu" + label_project_all: Proiektu guztiak + label_project_latest: Azken proiektuak + label_issue: Zeregina + label_issue_new: Zeregin berria + label_issue_plural: Zereginak + label_issue_view_all: Zeregin guztiak ikusi + label_issues_by: "Zereginak honengatik: %{value}" + label_issue_added: Zeregina gehituta + label_issue_updated: Zeregina eguneratuta + label_document: Dokumentua + label_document_new: Dokumentu berria + label_document_plural: Dokumentuak + label_document_added: Dokumentua gehituta + label_role: Rola + label_role_plural: Rolak + label_role_new: Rol berria + label_role_and_permissions: Rolak eta baimenak + label_member: Kidea + label_member_new: Kide berria + label_member_plural: Kideak + label_tracker: Aztarnaria + label_tracker_plural: Aztarnariak + label_tracker_new: Aztarnari berria + label_workflow: Lan-fluxua + label_issue_status: Zeregin egoera + label_issue_status_plural: Zeregin egoerak + label_issue_status_new: Egoera berria + label_issue_category: Zeregin kategoria + label_issue_category_plural: Zeregin kategoriak + label_issue_category_new: Kategoria berria + label_custom_field: Eremu pertsonalizatua + label_custom_field_plural: Eremu pertsonalizatuak + label_custom_field_new: Eremu pertsonalizatu berria + label_enumerations: Enumerazioak + label_enumeration_new: Balio berria + label_information: Informazioa + label_information_plural: Informazioa + label_please_login: Saioa hasi mesedez + label_register: Erregistratu + label_login_with_open_id_option: edo OpenID-rekin saioa hasi + label_password_lost: Pasahitza galduta + label_home: Hasiera + label_my_page: Nire orria + label_my_account: Nire kontua + label_my_projects: Nire proiektuak + label_administration: Kudeaketa + label_login: Saioa hasi + label_logout: Saioa bukatu + label_help: Laguntza + label_reported_issues: Berri emandako zereginak + label_assigned_to_me_issues: Niri esleitutako arazoak + label_last_login: Azken konexioa + label_registered_on: Noiz erregistratuta + label_activity: Jarduerak + label_overall_activity: Jarduera guztiak + label_user_activity: "%{value}-(r)en jarduerak" + label_new: Berria + label_logged_as: "Sartutako erabiltzailea:" + label_environment: Ingurune + label_authentication: Autentikazioa + label_auth_source: Autentikazio modua + label_auth_source_new: Autentikazio modu berria + label_auth_source_plural: Autentikazio moduak + label_subproject_plural: Azpiproiektuak + label_subproject_new: Azpiproiektu berria + label_and_its_subprojects: "%{value} eta bere azpiproiektuak" + label_min_max_length: Luzera min - max + label_list: Zerrenda + label_date: Data + label_integer: Osokoa + label_float: Koma higikorrekoa + label_boolean: Boolearra + label_string: Testua + label_text: Testu luzea + label_attribute: Atributua + label_attribute_plural: Atributuak + label_no_data: Ez dago erakusteko daturik + label_change_status: Egoera aldatu + label_history: Historikoa + label_attachment: Fitxategia + label_attachment_new: Fitxategi berria + label_attachment_delete: Fitxategia ezabatu + label_attachment_plural: Fitxategiak + label_file_added: Fitxategia gehituta + label_report: Berri ematea + label_report_plural: Berri emateak + label_news: Berria + label_news_new: Berria gehitu + label_news_plural: Berriak + label_news_latest: Azken berriak + label_news_view_all: Berri guztiak ikusi + label_news_added: Berria gehituta + label_settings: Ezarpenak + label_overview: Gainbegirada + label_version: Bertsioa + label_version_new: Bertsio berria + label_version_plural: Bertsioak + label_close_versions: Burututako bertsioak itxi + label_confirmation: Baieztapena + label_export_to: 'Eskuragarri baita:' + label_read: Irakurri... + label_public_projects: Proiektu publikoak + label_open_issues: irekita + label_open_issues_plural: irekiak + label_closed_issues: itxita + label_closed_issues_plural: itxiak + label_x_open_issues_abbr_on_total: + zero: 0 irekita / %{total} + one: 1 irekita / %{total} + other: "%{count} irekiak / %{total}" + label_x_open_issues_abbr: + zero: 0 irekita + one: 1 irekita + other: "%{count} irekiak" + label_x_closed_issues_abbr: + zero: 0 itxita + one: 1 itxita + other: "%{count} itxiak" + label_total: Guztira + label_permissions: Baimenak + label_current_status: Uneko egoera + label_new_statuses_allowed: Baimendutako egoera berriak + label_all: guztiak + label_none: ezer + label_nobody: inor + label_next: Hurrengoa + label_previous: Aurrekoak + label_used_by: Erabilita + label_details: Xehetasunak + label_add_note: Oharra gehitu + label_per_page: Orriko + label_calendar: Egutegia + label_months_from: hilabete noiztik + label_gantt: Gantt + label_internal: Barnekoa + label_last_changes: "azken %{count} aldaketak" + label_change_view_all: Aldaketa guztiak ikusi + label_personalize_page: Orri hau pertsonalizatu + label_comment: Iruzkin + label_comment_plural: Iruzkinak + label_x_comments: + zero: iruzkinik ez + one: iruzkin 1 + other: "%{count} iruzkin" + label_comment_add: Iruzkina gehitu + label_comment_added: Iruzkina gehituta + label_comment_delete: Iruzkinak ezabatu + label_query: Galdera pertsonalizatua + label_query_plural: Pertsonalizatutako galderak + label_query_new: Galdera berria + label_filter_add: Iragazkia gehitu + label_filter_plural: Iragazkiak + label_equals: da + label_not_equals: ez da + label_in_less_than: baino gutxiagotan + label_in_more_than: baino gehiagotan + label_greater_or_equal: '>=' + label_less_or_equal: '<=' + label_in: hauetan + label_today: gaur + label_all_time: denbora guztia + label_yesterday: atzo + label_this_week: aste honetan + label_last_week: pasadan astean + label_last_n_days: "azken %{count} egunetan" + label_this_month: hilabete hau + label_last_month: pasadan hilabetea + label_this_year: urte hau + label_date_range: Data tartea + label_less_than_ago: egun hauek baino gutxiago + label_more_than_ago: egun hauek baino gehiago + label_ago: orain dela + label_contains: dauka + label_not_contains: ez dauka + label_day_plural: egun + label_repository: Biltegia + label_repository_plural: Biltegiak + label_browse: Arakatu + label_branch: Adarra + label_tag: Etiketa + label_revision: Berrikuspena + label_revision_plural: Berrikuspenak + label_revision_id: "%{value} berrikuspen" + label_associated_revisions: Elkartutako berrikuspenak + label_added: gehituta + label_modified: aldatuta + label_copied: kopiatuta + label_renamed: berrizendatuta + label_deleted: ezabatuta + label_latest_revision: Azken berrikuspena + label_latest_revision_plural: Azken berrikuspenak + label_view_revisions: Berrikuspenak ikusi + label_view_all_revisions: Berrikuspen guztiak ikusi + label_max_size: Tamaina maximoa + label_sort_highest: Goraino mugitu + label_sort_higher: Gora mugitu + label_sort_lower: Behera mugitu + label_sort_lowest: Beheraino mugitu + label_roadmap: Ibilbide-mapa + label_roadmap_due_in: "Epea: %{value}" + label_roadmap_overdue: "%{value} berandu" + label_roadmap_no_issues: Ez dago zereginik bertsio honetan + label_search: Bilatu + label_result_plural: Emaitzak + label_all_words: hitz guztiak + label_wiki: Wikia + label_wiki_edit: Wiki edizioa + label_wiki_edit_plural: Wiki edizioak + label_wiki_page: Wiki orria + label_wiki_page_plural: Wiki orriak + label_index_by_title: Izenburuaren araberako indizea + label_index_by_date: Dataren araberako indizea + label_current_version: Uneko bertsioa + label_preview: Aurreikusi + label_feed_plural: Jarioak + label_changes_details: Aldaketa guztien xehetasunak + label_issue_tracking: Zeregin jarraipena + label_spent_time: Igarotako denbora + label_f_hour: "ordu %{value}" + label_f_hour_plural: "%{value} ordu" + label_time_tracking: Denbora jarraipena + label_change_plural: Aldaketak + label_statistics: Estatistikak + label_commits_per_month: Commit-ak hilabeteka + label_commits_per_author: Commit-ak egileka + label_view_diff: Ezberdintasunak ikusi + label_diff_inline: barnean + label_diff_side_by_side: aldez alde + label_options: Aukerak + label_copy_workflow_from: Kopiatu workflow-a hemendik + label_permissions_report: Baimenen txostena + label_watched_issues: Behatutako zereginak + label_related_issues: Erlazionatutako zereginak + label_applied_status: Aplikatutako egoera + label_loading: Kargatzen... + label_relation_new: Erlazio berria + label_relation_delete: Erlazioa ezabatu + label_relates_to: erlazionatuta dago + label_duplicates: bikoizten du + label_duplicated_by: honek bikoiztuta + label_blocks: blokeatzen du + label_blocked_by: honek blokeatuta + label_precedes: aurretik doa + label_follows: jarraitzen du + label_end_to_start: bukaeratik hasierara + label_end_to_end: bukaeratik bukaerara + label_start_to_start: hasieratik hasierhasieratik bukaerara + label_start_to_end: hasieratik bukaerara + label_stay_logged_in: Saioa mantendu + label_disabled: ezgaituta + label_show_completed_versions: Bukatutako bertsioak ikusi + label_me: ni + label_board: Foroa + label_board_new: Foro berria + label_board_plural: Foroak + label_topic_plural: Gaiak + label_message_plural: Mezuak + label_message_last: Azken mezua + label_message_new: Mezu berria + label_message_posted: Mezua gehituta + label_reply_plural: Erantzunak + label_send_information: Erabiltzaileai kontuaren informazioa bidali + label_year: Urtea + label_month: Hilabetea + label_week: Astea + label_date_from: Nork + label_date_to: Nori + label_language_based: Erabiltzailearen hizkuntzaren arabera + label_sort_by: "Ordenazioa: %{value}" + label_send_test_email: Frogako mezua bidali + label_feeds_access_key: RSS atzipen giltza + label_missing_feeds_access_key: RSS atzipen giltza falta da + label_feeds_access_key_created_on: "RSS atzipen giltza orain dela %{value} sortuta" + label_module_plural: Moduluak + label_added_time_by: "%{author}, orain dela %{age} gehituta" + label_updated_time_by: "%{author}, orain dela %{age} eguneratuta" + label_updated_time: "Orain dela %{value} eguneratuta" + label_jump_to_a_project: Joan proiektura... + label_file_plural: Fitxategiak + label_changeset_plural: Aldaketak + label_default_columns: Lehenetsitako zutabeak + label_no_change_option: (Aldaketarik ez) + label_bulk_edit_selected_issues: Hautatutako zereginak batera editatu + label_theme: Itxura + label_default: Lehenetsia + label_search_titles_only: Izenburuetan bakarrik bilatu + label_user_mail_option_all: "Nire proiektu guztietako gertakari guztientzat" + label_user_mail_option_selected: "Hautatutako proiektuetako edozein gertakarientzat..." + label_user_mail_no_self_notified: "Ez dut nik egiten ditudan aldeketen jakinarazpenik jaso nahi" + label_registration_activation_by_email: kontuak epostaz gaitu + label_registration_manual_activation: kontuak eskuz gaitu + label_registration_automatic_activation: kontuak automatikoki gaitu + label_display_per_page: "Orriko: %{value}" + label_age: Adina + label_change_properties: Propietateak aldatu + label_general: Orokorra + label_more: Gehiago + label_scm: IKK + label_plugins: Pluginak + label_ldap_authentication: LDAP autentikazioa + label_downloads_abbr: Desk. + label_optional_description: Aukerako deskribapena + label_add_another_file: Beste fitxategia gehitu + label_preferences: Hobespenak + label_chronological_order: Orden kronologikoan + label_reverse_chronological_order: Alderantzizko orden kronologikoan + label_planning: Planifikazioa + label_incoming_emails: Sarrerako epostak + label_generate_key: Giltza sortu + label_issue_watchers: Behatzaileak + label_example: Adibidea + label_display: Bistaratzea + label_sort: Ordenatu + label_ascending: Gorantz + label_descending: Beherantz + label_date_from_to: "%{start}-tik %{end}-ra" + label_wiki_content_added: Wiki orria gehituta + label_wiki_content_updated: Wiki orria eguneratuta + label_group: Taldea + label_group_plural: Taldeak + label_group_new: Talde berria + label_time_entry_plural: Igarotako denbora + label_version_sharing_none: Ez partekatuta + label_version_sharing_descendants: Azpiproiektuekin + label_version_sharing_hierarchy: Proiektu Hierarkiarekin + label_version_sharing_tree: Proiektu zuhaitzarekin + label_version_sharing_system: Proiektu guztiekin + label_update_issue_done_ratios: Zereginen burututako erlazioa eguneratu + label_copy_source: Iturburua + label_copy_target: Helburua + label_copy_same_as_target: Helburuaren berdina + label_display_used_statuses_only: Aztarnari honetan erabiltzen diren egoerak bakarrik erakutsi + label_api_access_key: API atzipen giltza + label_missing_api_access_key: API atzipen giltza falta da + label_api_access_key_created_on: "API atzipen giltza sortuta orain dela %{value}" + + button_login: Saioa hasi + button_submit: Bidali + button_save: Gorde + button_check_all: Guztiak markatu + button_uncheck_all: Guztiak desmarkatu + button_delete: Ezabatu + button_create: Sortu + button_create_and_continue: Sortu eta jarraitu + button_test: Frogatu + button_edit: Editatu + button_add: Gehitu + button_change: Aldatu + button_apply: Aplikatu + button_clear: Garbitu + button_lock: Blokeatu + button_unlock: Desblokeatu + button_download: Deskargatu + button_list: Zerrenda + button_view: Ikusi + button_move: Mugitu + button_move_and_follow: Mugitu eta jarraitu + button_back: Atzera + button_cancel: Ezeztatu + button_activate: Gahitu + button_sort: Ordenatu + button_log_time: Denbora erregistratu + button_rollback: Itzuli bertsio honetara + button_watch: Behatu + button_unwatch: Behatzen utzi + button_reply: Erantzun + button_archive: Artxibatu + button_unarchive: Desartxibatu + button_reset: Berrezarri + button_rename: Berrizendatu + button_change_password: Pasahitza aldatu + button_copy: Kopiatu + button_copy_and_follow: Kopiatu eta jarraitu + button_annotate: Anotatu + button_update: Eguneratu + button_configure: Konfiguratu + button_quote: Aipatu + button_duplicate: Bikoiztu + button_show: Ikusi + + status_active: gaituta + status_registered: izena emanda + status_locked: blokeatuta + + version_status_open: irekita + version_status_locked: blokeatuta + version_status_closed: itxita + + field_active: Gaituta + + text_select_mail_notifications: Jakinarazpenak zein ekintzetarako bidaliko diren hautatu. + text_regexp_info: adib. ^[A-Z0-9]+$ + text_min_max_length_info: 0k mugarik gabe esan nahi du + text_project_destroy_confirmation: Ziur zaude proiektu hau eta erlazionatutako datu guztiak ezabatu nahi dituzula? + text_subprojects_destroy_warning: "%{value} azpiproiektuak ere ezabatuko dira." + text_workflow_edit: Hautatu rola eta aztarnaria workflow-a editatzeko + text_are_you_sure: Ziur zaude? + text_journal_changed: "%{label} %{old}-(e)tik %{new}-(e)ra aldatuta" + text_journal_set_to: "%{label}-k %{value} balioa hartu du" + text_journal_deleted: "%{label} ezabatuta (%{old})" + text_journal_added: "%{label} %{value} gehituta" + text_tip_issue_begin_day: gaur hasten diren zereginak + text_tip_issue_end_day: gaur bukatzen diren zereginak + text_tip_issue_begin_end_day: gaur hasi eta bukatzen diren zereginak + text_caracters_maximum: "%{count} karaktere gehienez." + text_caracters_minimum: "Gutxienez %{count} karaktereetako luzerakoa izan behar du." + text_length_between: "Luzera %{min} eta %{max} karaktereen artekoa." + text_tracker_no_workflow: Ez da workflow-rik definitu aztarnari honentzako + text_unallowed_characters: Debekatutako karaktereak + text_comma_separated: Balio anitz izan daitezke (komaz banatuta). + text_line_separated: Balio anitz izan daitezke (balio bakoitza lerro batean). + text_issues_ref_in_commit_messages: Commit-en mezuetan zereginak erlazionatu eta konpontzen + text_issue_added: "%{id} zeregina %{author}-(e)k jakinarazi du." + text_issue_updated: "%{id} zeregina %{author}-(e)k eguneratu du." + text_wiki_destroy_confirmation: Ziur zaude wiki hau eta bere eduki guztiak ezabatu nahi dituzula? + text_issue_category_destroy_question: "Zeregin batzuk (%{count}) kategoria honetara esleituta daude. Zer egin nahi duzu?" + text_issue_category_destroy_assignments: Kategoria esleipenak kendu + text_issue_category_reassign_to: Zereginak kategoria honetara esleitu + text_user_mail_option: "Hautatu gabeko proiektuetan, behatzen edo parte hartzen duzun gauzei buruzko jakinarazpenak jasoko dituzu (adib. zu egile zaren edo esleituta dituzun zereginak)." + text_no_configuration_data: "Rolak, aztarnariak, zeregin egoerak eta workflow-ak ez dira oraindik konfiguratu.\nOso gomendagarria de lehenetsitako kkonfigurazioa kargatzea. Kargatu eta gero aldatu ahalko duzu." + text_load_default_configuration: Lehenetsitako konfigurazioa kargatu + text_status_changed_by_changeset: "%{value} aldaketan aplikatuta." + text_issues_destroy_confirmation: 'Ziur zaude hautatutako zeregina(k) ezabatu nahi dituzula?' + text_select_project_modules: 'Hautatu proiektu honetan gaitu behar diren moduluak:' + text_default_administrator_account_changed: Lehenetsitako kudeatzaile kontua aldatuta + text_file_repository_writable: Eranskinen direktorioan idatz daiteke + text_plugin_assets_writable: Pluginen baliabideen direktorioan idatz daiteke + text_rmagick_available: RMagick eskuragarri (aukerazkoa) + text_destroy_time_entries_question: "%{hours} orduei buruz berri eman zen zuk ezabatzera zoazen zereginean. Zer egin nahi duzu?" + text_destroy_time_entries: Ezabatu berri emandako orduak + text_assign_time_entries_to_project: Berri emandako orduak proiektura esleitu + text_reassign_time_entries: 'Berri emandako orduak zeregin honetara esleitu:' + text_user_wrote: "%{value}-(e)k idatzi zuen:" + text_enumeration_destroy_question: "%{count} objetu balio honetara esleituta daude." + text_enumeration_category_reassign_to: 'Beste balio honetara esleitu:' + text_email_delivery_not_configured: "Eposta bidalketa ez dago konfiguratuta eta jakinarazpenak ezgaituta daude.\nKonfiguratu zure SMTP zerbitzaria config/configuration.yml-n eta aplikazioa berrabiarazi hauek gaitzeko." + text_repository_usernames_mapping: "Hautatu edo eguneratu Redmineko erabiltzailea biltegiko egunkarietan topatzen diren erabiltzaile izenekin erlazionatzeko.\nRedmine-n eta biltegian erabiltzaile izen edo eposta berdina duten erabiltzaileak automatikoki erlazionatzen dira." + text_diff_truncated: '... Diff hau moztua izan da erakus daitekeen tamaina maximoa gainditu duelako.' + text_custom_field_possible_values_info: 'Lerro bat balio bakoitzeko' + text_wiki_page_destroy_question: "Orri honek %{descendants} orri seme eta ondorengo ditu. Zer egin nahi duzu?" + text_wiki_page_nullify_children: "Orri semeak erro orri moduan mantendu" + text_wiki_page_destroy_children: "Orri semeak eta beraien ondorengo guztiak ezabatu" + text_wiki_page_reassign_children: "Orri semeak orri guraso honetara esleitu" + text_own_membership_delete_confirmation: "Zure baimen batzuk (edo guztiak) kentzera zoaz eta baliteke horren ondoren proiektu hau ezin editatzea.\n Ziur zaude jarraitu nahi duzula?" + + default_role_manager: Kudeatzailea + default_role_developer: Garatzailea + default_role_reporter: Berriemailea + default_tracker_bug: Errorea + default_tracker_feature: Eginbidea + default_tracker_support: Laguntza + default_issue_status_new: Berria + default_issue_status_in_progress: Lanean + default_issue_status_resolved: Ebatzita + default_issue_status_feedback: Berrelikadura + default_issue_status_closed: Itxita + default_issue_status_rejected: Baztertua + default_doc_category_user: Erabiltzaile dokumentazioa + default_doc_category_tech: Dokumentazio teknikoa + default_priority_low: Baxua + default_priority_normal: Normala + default_priority_high: Altua + default_priority_urgent: Larria + default_priority_immediate: Berehalakoa + default_activity_design: Diseinua + default_activity_development: Garapena + + enumeration_issue_priorities: Zeregin lehentasunak + enumeration_doc_categories: Dokumentu kategoriak + enumeration_activities: Jarduerak (denbora kontrola)) + enumeration_system_activity: Sistemako Jarduera + label_board_sticky: Itsaskorra + label_board_locked: Blokeatuta + permission_export_wiki_pages: Wiki orriak esportatu + setting_cache_formatted_text: Formatudun testua katxeatu + permission_manage_project_activities: Proiektuaren jarduerak kudeatu + error_unable_delete_issue_status: Ezine da zereginaren egoera ezabatu + label_profile: Profila + permission_manage_subtasks: Azpiatazak kudeatu + field_parent_issue: Zeregin gurasoa + label_subtask_plural: Azpiatazak + label_project_copy_notifications: Proiektua kopiatzen den bitartean eposta jakinarazpenak bidali + error_can_not_delete_custom_field: Ezin da eremu pertsonalizatua ezabatu + error_unable_to_connect: Ezin da konektatu (%{value}) + error_can_not_remove_role: Rol hau erabiltzen hari da eta ezin da ezabatu. + error_can_not_delete_tracker: Aztarnari honek zereginak ditu eta ezin da ezabatu. + field_principal: Ekintzaile + label_my_page_block: "Nire orriko blokea" + notice_failed_to_save_members: "Kidea(k) gordetzean errorea: %{errors}." + text_zoom_out: Zooma txikiagotu + text_zoom_in: Zooma handiagotu + notice_unable_delete_time_entry: "Ezin da hautatutako denbora erregistroa ezabatu." + label_overall_spent_time: Igarotako denbora guztira + field_time_entries: "Denbora erregistratu" + project_module_gantt: Gantt + project_module_calendar: Egutegia + button_edit_associated_wikipage: "Esleitutako wiki orria editatu: %{page_title}" + field_text: Testu eremua + label_user_mail_option_only_owner: "Jabea naizen gauzetarako barrarik" + setting_default_notification_option: "Lehenetsitako ohartarazpen aukera" + label_user_mail_option_only_my_events: "Behatzen ditudan edo partaide naizen gauzetarako bakarrik" + label_user_mail_option_only_assigned: "Niri esleitutako gauzentzat bakarrik" + label_user_mail_option_none: "Gertakaririk ez" + field_member_of_group: "Esleituta duenaren taldea" + field_assigned_to_role: "Esleituta duenaren rola" + notice_not_authorized_archived_project: "Atzitu nahi duzun proiektua artxibatua izan da." + label_principal_search: "Bilatu erabiltzaile edo taldea:" + label_user_search: "Erabiltzailea bilatu:" + field_visible: Ikusgai + setting_emails_header: "Eposten goiburua" + setting_commit_logtime_activity_id: "Erregistratutako denboraren jarduera" + text_time_logged_by_changeset: "%{value} aldaketan egindakoa." + setting_commit_logtime_enabled: "Erregistrutako denbora gaitu" + notice_gantt_chart_truncated: Grafikoa moztu da bistara daitekeen elementuen kopuru maximoa gainditu delako (%{max}) + setting_gantt_items_limit: "Gantt grafikoan bistara daitekeen elementu kopuru maximoa" + field_warn_on_leaving_unsaved: Gorde gabeko testua duen orri batetik ateratzen naizenean ohartarazi + text_warn_on_leaving_unsaved: Uneko orritik joaten bazara gorde gabeko testua galduko da. + label_my_queries: Nire galdera pertsonalizatuak + text_journal_changed_no_detail: "%{label} eguneratuta" + label_news_comment_added: Berri batera iruzkina gehituta + button_expand_all: Guztia zabaldu + button_collapse_all: Guztia tolestu + label_additional_workflow_transitions_for_assignee: Erabiltzaileak esleitua duenean baimendutako transtsizio gehigarriak + label_additional_workflow_transitions_for_author: Erabiltzailea egilea denean baimendutako transtsizio gehigarriak + label_bulk_edit_selected_time_entries: Hautatutako denbora egunkariak batera editatu + text_time_entries_destroy_confirmation: Ziur zaude hautatutako denbora egunkariak ezabatu nahi dituzula? + label_role_anonymous: Ezezaguna + label_role_non_member: Ez kidea + label_issue_note_added: Oharra gehituta + label_issue_status_updated: Egoera eguneratuta + label_issue_priority_updated: Lehentasuna eguneratuta + label_issues_visibility_own: Erabiltzaileak sortu edo esleituta dituen zereginak + field_issues_visibility: Zeregin ikusgarritasuna + label_issues_visibility_all: Zeregin guztiak + permission_set_own_issues_private: Nork bere zereginak publiko edo pribatu jarri + field_is_private: Pribatu + permission_set_issues_private: Zereginak publiko edo pribatu jarri + label_issues_visibility_public: Pribatu ez diren zeregin guztiak + text_issues_destroy_descendants_confirmation: Honek %{count} azpiataza ezabatuko ditu baita ere. + field_commit_logs_encoding: Commit-en egunkarien kodetzea + field_scm_path_encoding: Bidearen kodeketa + text_scm_path_encoding_note: "Lehentsita: UTF-8" + field_path_to_repository: Biltegirako bidea + field_root_directory: Erro direktorioa + field_cvs_module: Modulua + field_cvsroot: CVSROOT + text_mercurial_repository_note: Biltegi locala (adib. /hgrepo, c:\hgrepo) + text_scm_command: Komandoa + text_scm_command_version: Bertsioa + label_git_report_last_commit: Report last commit for files and directories + notice_issue_successful_create: Issue %{id} created. + label_between: between + setting_issue_group_assignment: Allow issue assignment to groups + label_diff: diff + text_git_repository_note: Repository is bare and local (e.g. /gitrepo, c:\gitrepo) + description_query_sort_criteria_direction: Sort direction + description_project_scope: Search scope + description_filter: Filter + description_user_mail_notification: Mail notification settings + description_date_from: Enter start date + description_message_content: Message content + description_available_columns: Available Columns + description_date_range_interval: Choose range by selecting start and end date + description_issue_category_reassign: Choose issue category + description_search: Searchfield + description_notes: Notes + description_date_range_list: Choose range from list + description_choose_project: Projects + description_date_to: Enter end date + description_query_sort_criteria_attribute: Sort attribute + description_wiki_subpages_reassign: Choose new parent page + description_selected_columns: Selected Columns + label_parent_revision: Parent + label_child_revision: Child + error_scm_annotate_big_text_file: The entry cannot be annotated, as it exceeds the maximum text file size. + setting_default_issue_start_date_to_creation_date: Use current date as start date for new issues + button_edit_section: Edit this section + setting_repositories_encodings: Attachments and repositories encodings + description_all_columns: All Columns + button_export: Export + label_export_options: "%{export_format} export options" + error_attachment_too_big: This file cannot be uploaded because it exceeds the maximum allowed file size (%{max_size}) + notice_failed_to_save_time_entries: "Failed to save %{count} time entrie(s) on %{total} selected: %{ids}." + label_x_issues: + zero: 0 zeregina + one: 1 zeregina + other: "%{count} zereginak" + label_repository_new: New repository + field_repository_is_default: Main repository + label_copy_attachments: Copy attachments + label_item_position: "%{position}/%{count}" + label_completed_versions: Completed versions + text_project_identifier_info: Only lower case letters (a-z), numbers, dashes and underscores are allowed.
    Once saved, the identifier cannot be changed. + field_multiple: Multiple values + setting_commit_cross_project_ref: Allow issues of all the other projects to be referenced and fixed + text_issue_conflict_resolution_add_notes: Add my notes and discard my other changes + text_issue_conflict_resolution_overwrite: Apply my changes anyway (previous notes will be kept but some changes may be overwritten) + notice_issue_update_conflict: The issue has been updated by an other user while you were editing it. + text_issue_conflict_resolution_cancel: Discard all my changes and redisplay %{link} + permission_manage_related_issues: Manage related issues + field_auth_source_ldap_filter: LDAP filter + label_search_for_watchers: Search for watchers to add + notice_account_deleted: Your account has been permanently deleted. + setting_unsubscribe: Allow users to delete their own account + button_delete_my_account: Delete my account + text_account_destroy_confirmation: |- + Are you sure you want to proceed? + Your account will be permanently deleted, with no way to reactivate it. + error_session_expired: Your session has expired. Please login again. + text_session_expiration_settings: "Warning: changing these settings may expire the current sessions including yours." + setting_session_lifetime: Session maximum lifetime + setting_session_timeout: Session inactivity timeout + label_session_expiration: Session expiration + permission_close_project: Close / reopen the project + label_show_closed_projects: View closed projects + button_close: Close + button_reopen: Reopen + project_status_active: active + project_status_closed: closed + project_status_archived: archived + text_project_closed: This project is closed and read-only. + notice_user_successful_create: User %{id} created. + field_core_fields: Standard fields + field_timeout: Timeout (in seconds) + setting_thumbnails_enabled: Display attachment thumbnails + setting_thumbnails_size: Thumbnails size (in pixels) + label_status_transitions: Status transitions + label_fields_permissions: Fields permissions + label_readonly: Read-only + label_required: Required + text_repository_identifier_info: Only lower case letters (a-z), numbers, dashes and underscores are allowed.
    Once saved, the identifier cannot be changed. + field_board_parent: Parent forum + label_attribute_of_project: Project's %{name} + label_attribute_of_author: Author's %{name} + label_attribute_of_assigned_to: Assignee's %{name} + label_attribute_of_fixed_version: Target version's %{name} + label_copy_subtasks: Copy subtasks + label_copied_to: copied to + label_copied_from: copied from + label_any_issues_in_project: any issues in project + label_any_issues_not_in_project: any issues not in project + field_private_notes: Private notes + permission_view_private_notes: View private notes + permission_set_notes_private: Set notes as private + label_no_issues_in_project: no issues in project + label_any: guztiak + label_last_n_weeks: last %{count} weeks + setting_cross_project_subtasks: Allow cross-project subtasks + label_cross_project_descendants: Azpiproiektuekin + label_cross_project_tree: Proiektu zuhaitzarekin + label_cross_project_hierarchy: Proiektu Hierarkiarekin + label_cross_project_system: Proiektu guztiekin + button_hide: Hide + setting_non_working_week_days: Non-working days + label_in_the_next_days: in the next + label_in_the_past_days: in the past + label_attribute_of_user: User's %{name} + text_turning_multiple_off: If you disable multiple values, multiple values will be + removed in order to preserve only one value per item. + label_attribute_of_issue: Issue's %{name} + permission_add_documents: Add documents + permission_edit_documents: Edit documents + permission_delete_documents: Delete documents + label_gantt_progress_line: Progress line + setting_jsonp_enabled: Enable JSONP support + field_inherit_members: Inherit members + field_closed_on: Closed + setting_default_projects_tracker_ids: Default trackers for new projects + label_total_time: Guztira + text_scm_config: You can configure your SCM commands in config/configuration.yml. Please restart the application after editing it. + text_scm_command_not_available: SCM command is not available. Please check settings on the administration panel. diff --git a/config/locales/fa.yml b/config/locales/fa.yml new file mode 100644 index 00000000..d31c1f70 --- /dev/null +++ b/config/locales/fa.yml @@ -0,0 +1,1091 @@ +fa: + # Text direction: Left-to-Right (ltr) or Right-to-Left (rtl) + direction: rtl + date: + formats: + # Use the strftime parameters for formats. + # When no format has been given, it uses default. + # You can provide other formats here if you like! + default: "%Y/%m/%d" + short: "%b %d" + long: "%B %d, %Y" + + day_names: [یک‌شنبه, دوشنبه, سه‌شنبه, چهارشنبه, پنج‌شنبه, آدینه, شنبه] + abbr_day_names: [یک, دو, سه, چهار, پنج, آدینه, شنبه] + + # Don't forget the nil at the beginning; there's no such thing as a 0th month + month_names: [~, ژانویه, فوریه, مارس, آوریل, مه, ژوئن, ژوئیه, اوت, سپتامبر, اکتبر, نوامبر, دسامبر] + abbr_month_names: [~, ژان, فور, مار, آور, مه, ژوئن, ژوئیه, اوت, سپت, اکت, نوا, دسا] + # Used in date_select and datime_select. + order: + - :year + - :month + - :day + + time: + formats: + default: "%Y/%m/%d - %H:%M" + time: "%H:%M" + short: "%d %b %H:%M" + long: "%d %B %Y ساعت %H:%M" + am: "صبح" + pm: "عصر" + + datetime: + distance_in_words: + half_a_minute: "نیم دقیقه" + less_than_x_seconds: + one: "کمتر از 1 ثانیه" + other: "کمتر از %{count} ثانیه" + x_seconds: + one: "1 ثانیه" + other: "%{count} ثانیه" + less_than_x_minutes: + one: "کمتر از 1 دقیقه" + other: "کمتر از %{count} دقیقه" + x_minutes: + one: "1 دقیقه" + other: "%{count} دقیقه" + about_x_hours: + one: "نزدیک 1 ساعت" + other: "نزدیک %{count} ساعت" + x_hours: + one: "1 hour" + other: "%{count} hours" + x_days: + one: "1 روز" + other: "%{count} روز" + about_x_months: + one: "نزدیک 1 ماه" + other: "نزدیک %{count} ماه" + x_months: + one: "1 ماه" + other: "%{count} ماه" + about_x_years: + one: "نزدیک 1 سال" + other: "نزدیک %{count} سال" + over_x_years: + one: "بیش از 1 سال" + other: "بیش از %{count} سال" + almost_x_years: + one: "نزدیک 1 سال" + other: "نزدیک %{count} سال" + + number: + # Default format for numbers + format: + separator: "٫" + delimiter: "" + precision: 3 + human: + format: + delimiter: "" + precision: 3 + storage_units: + format: "%n %u" + units: + byte: + one: "بایت" + other: "بایت" + kb: "کیلوبایت" + mb: "مگابایت" + gb: "گیگابایت" + tb: "ترابایت" + +# Used in array.to_sentence. + support: + array: + sentence_connector: "و" + skip_last_comma: false + + activerecord: + errors: + template: + header: + one: "1 ایراد از ذخیره سازی این %{model} جلوگیری کرد" + other: "%{count} ایراد از ذخیره سازی این %{model} جلوگیری کرد" + messages: + inclusion: "در فهرست نیامده است" + exclusion: "رزرو شده است" + invalid: "نادرست است" + confirmation: "با بررسی سازگاری ندارد" + accepted: "باید پذیرفته شود" + empty: "نمی‌تواند تهی باشد" + blank: "نمی‌تواند تهی باشد" + too_long: "خیلی بلند است (بیشترین اندازه %{count} نویسه است)" + too_short: "خیلی کوتاه است (کمترین اندازه %{count} نویسه است)" + wrong_length: "اندازه نادرست است (باید %{count} نویسه باشد)" + taken: "پیش از این گرفته شده است" + not_a_number: "شماره درستی نیست" + not_a_date: "تاریخ درستی نیست" + greater_than: "باید بزرگتر از %{count} باشد" + greater_than_or_equal_to: "باید بزرگتر از یا برابر با %{count} باشد" + equal_to: "باید برابر با %{count} باشد" + less_than: "باید کمتر از %{count} باشد" + less_than_or_equal_to: "باید کمتر از یا برابر با %{count} باشد" + odd: "باید فرد باشد" + even: "باید زوج باشد" + greater_than_start_date: "باید از تاریخ آغاز بزرگتر باشد" + not_same_project: "به همان پروژه وابسته نیست" + circular_dependency: "این وابستگی یک وابستگی دایره وار خواهد ساخت" + cant_link_an_issue_with_a_descendant: "یک پیامد نمی‌تواند به یکی از زیر کارهایش پیوند بخورد" + + actionview_instancetag_blank_option: گزینش کنید + + general_text_No: 'خیر' + general_text_Yes: 'آری' + general_text_no: 'خیر' + general_text_yes: 'آری' + general_lang_name: 'Persian (پارسی)' + general_csv_separator: ',' + general_csv_decimal_separator: '.' + general_csv_encoding: UTF-8 + general_pdf_encoding: UTF-8 + general_first_day_of_week: '6' + + notice_account_updated: حساب شما بروز شد. + notice_account_invalid_creditentials: نام کاربری یا گذرواژه نادرست است + notice_account_password_updated: گذرواژه بروز شد + notice_account_wrong_password: گذرواژه نادرست است + notice_account_register_done: حساب ساخته شد. برای فعال نمودن آن، روی پیوندی که به شما ایمیل شده کلیک کنید. + notice_account_unknown_email: کاربر شناخته نشد. + notice_can_t_change_password: این حساب یک روش شناسایی بیرونی را به کار گرفته است. گذرواژه را نمی‌توان جایگزین کرد. + notice_account_lost_email_sent: یک ایمیل با راهنمایی درباره گزینش گذرواژه تازه برای شما فرستاده شد. + notice_account_activated: حساب شما فعال شده است. اکنون می‌توانید وارد شوید. + notice_successful_create: با موفقیت ساخته شد. + notice_successful_update: با موفقیت بروز شد. + notice_successful_delete: با موفقیت برداشته شد. + notice_successful_connection: با موفقیت متصل شد. + notice_file_not_found: برگه درخواستی شما در دسترس نیست یا پاک شده است. + notice_locking_conflict: داده‌ها را کاربر دیگری بروز کرده است. + notice_not_authorized: شما به این برگه دسترسی ندارید. + notice_not_authorized_archived_project: پروژه درخواستی شما بایگانی شده است. + notice_email_sent: "یک ایمیل به %{value} فرستاده شد." + notice_email_error: "یک ایراد در فرستادن ایمیل پیش آمد (%{value})." + notice_feeds_access_key_reseted: کلید دسترسی RSS شما بازنشانی شد. + notice_api_access_key_reseted: کلید دسترسی API شما بازنشانی شد. + notice_failed_to_save_issues: "ذخیره سازی %{count} پیامد از %{total} پیامد گزینش شده شکست خورد: %{ids}." + notice_failed_to_save_members: "ذخیره سازی اعضا شکست خورد: %{errors}." + notice_no_issue_selected: "هیچ پیامدی برگزیده نشده است! پیامدهایی که می‌خواهید ویرایش کنید را برگزینید." + notice_account_pending: "حساب شما ساخته شد و اکنون چشم به راه روادید سرپرست است." + notice_default_data_loaded: پیکربندی پیش‌گزیده با موفقیت بار شد. + notice_unable_delete_version: نگارش را نمی‌توان پاک کرد. + notice_unable_delete_time_entry: زمان گزارش شده را نمی‌توان پاک کرد. + notice_issue_done_ratios_updated: اندازه انجام شده پیامد بروز شد. + notice_gantt_chart_truncated: "نمودار بریده شد چون از بیشترین شماری که می‌توان نشان داد بزگتر است (%{max})." + + error_can_t_load_default_data: "پیکربندی پیش‌گزیده نمی‌تواند بار شود: %{value}" + error_scm_not_found: "بخش یا نگارش در انباره پیدا نشد." + error_scm_command_failed: "ایرادی در دسترسی به انباره پیش آمد: %{value}" + error_scm_annotate: "بخش پیدا نشد یا نمی‌توان برای آن یادداشت نوشت." + error_issue_not_found_in_project: 'پیامد پیدا نشد یا به این پروژه وابسته نیست.' + error_no_tracker_in_project: 'هیچ پیگردی به این پروژه پیوسته نشده است. پیکربندی پروژه را بررسی کنید.' + error_no_default_issue_status: 'هیچ وضعیت پیامد پیش‌گزیده‌ای مشخص نشده است. پیکربندی را بررسی کنید (به «پیکربندی -> وضعیت‌های پیامد» بروید).' + error_can_not_delete_custom_field: فیلد سفارشی را نمی‌توان پاک کرد. + error_can_not_delete_tracker: "این پیگرد دارای پیامد است و نمی‌توان آن را پاک کرد." + error_can_not_remove_role: "این نقش به کار گرفته شده است و نمی‌توان آن را پاک کرد." + error_can_not_reopen_issue_on_closed_version: 'یک پیامد که به یک نگارش بسته شده وابسته است را نمی‌توان باز کرد.' + error_can_not_archive_project: این پروژه را نمی‌توان بایگانی کرد. + error_issue_done_ratios_not_updated: "اندازه انجام شده پیامد بروز نشد." + error_workflow_copy_source: 'یک پیگرد یا نقش منبع را برگزینید.' + error_workflow_copy_target: 'پیگردها یا نقش‌های مقصد را برگزینید.' + error_unable_delete_issue_status: 'وضعیت پیامد را نمی‌توان پاک کرد.' + error_unable_to_connect: "نمی‌توان متصل شد (%{value})" + warning_attachments_not_saved: "%{count} پرونده ذخیره نشد." + + mail_subject_lost_password: "گذرواژه حساب %{value} شما" + mail_body_lost_password: 'برای جایگزینی گذرواژه خود، بر روی پیوند زیر کلیک کنید:' + mail_subject_register: "فعالسازی حساب %{value} شما" + mail_body_register: 'برای فعالسازی حساب خود، بر روی پیوند زیر کلیک کنید:' + mail_body_account_information_external: "شما می‌توانید حساب %{value} خود را برای ورود به کار برید." + mail_body_account_information: داده‌های حساب شما + mail_subject_account_activation_request: "درخواست فعالسازی حساب %{value}" + mail_body_account_activation_request: "یک کاربر تازه (%{value}) نامنویسی کرده است. این حساب چشم به راه روادید شماست:" + mail_subject_reminder: "زمان رسیدگی به %{count} پیامد در %{days} روز آینده سر می‌رسد" + mail_body_reminder: "زمان رسیدگی به %{count} پیامد که به شما واگذار شده است، در %{days} روز آینده سر می‌رسد:" + mail_subject_wiki_content_added: "برگه ویکی «%{id}» افزوده شد" + mail_body_wiki_content_added: "برگه ویکی «%{id}» به دست %{author} افزوده شد." + mail_subject_wiki_content_updated: "برگه ویکی «%{id}» بروز شد" + mail_body_wiki_content_updated: "برگه ویکی «%{id}» به دست %{author} بروز شد." + + + field_name: نام + field_description: یادداشت + field_summary: خلاصه + field_is_required: الزامی + field_firstname: نام کوچک + field_lastname: نام خانوادگی + field_mail: ایمیل + field_filename: پرونده + field_filesize: اندازه + field_downloads: دریافت‌ها + field_author: نویسنده + field_created_on: ساخته شده در + field_updated_on: بروز شده در + field_field_format: قالب + field_is_for_all: برای همه پروژه‌ها + field_possible_values: مقادیر ممکن + field_regexp: عبارت منظم + field_min_length: کمترین اندازه + field_max_length: بیشترین اندازه + field_value: مقدار + field_category: دسته + field_title: عنوان + field_project: پروژه + field_issue: پیامد + field_status: وضعیت + field_notes: یادداشت + field_is_closed: پیامد بسته شده + field_is_default: مقدار پیش‌گزیده + field_tracker: پیگرد + field_subject: موضوع + field_due_date: زمان سررسید + field_assigned_to: واگذار شده به + field_priority: برتری + field_fixed_version: نگارش هدف + field_user: کاربر + field_principal: دستور دهنده + field_role: نقش + field_homepage: برگه خانه + field_is_public: همگانی + field_parent: پروژه پدر + field_is_in_roadmap: این پیامدها در چشم‌انداز نشان داده شوند + field_login: ورود + field_mail_notification: آگاه سازی‌های ایمیلی + field_admin: سرپرست + field_last_login_on: آخرین ورود + field_language: زبان + field_effective_date: تاریخ + field_password: گذرواژه + field_new_password: گذرواژه تازه + field_password_confirmation: بررسی گذرواژه + field_version: نگارش + field_type: گونه + field_host: میزبان + field_port: درگاه + field_account: حساب + field_base_dn: DN پایه + field_attr_login: نشانه ورود + field_attr_firstname: نشانه نام کوچک + field_attr_lastname: نشانه نام خانوادگی + field_attr_mail: نشانه ایمیل + field_onthefly: ساخت کاربر بیدرنگ + field_start_date: تاریخ آغاز + field_done_ratio: ٪ انجام شده + field_auth_source: روش شناسایی + field_hide_mail: ایمیل من پنهان شود + field_comments: دیدگاه + field_url: نشانی + field_start_page: برگه آغاز + field_subproject: زیر پروژه + field_hours: ساعت‌ + field_activity: گزارش + field_spent_on: در تاریخ + field_identifier: شناسه + field_is_filter: پالایش پذیر + field_issue_to: پیامد وابسته + field_delay: دیرکرد + field_assignable: پیامدها می‌توانند به این نقش واگذار شوند + field_redirect_existing_links: پیوندهای پیشین به پیوند تازه راهنمایی شوند + field_estimated_hours: زمان برآورد شده + field_column_names: ستون‌ها + field_time_entries: زمان نوشتن + field_time_zone: پهنه زمانی + field_searchable: جستجو پذیر + field_default_value: مقدار پیش‌گزیده + field_comments_sorting: نمایش دیدگاه‌ها + field_parent_title: برگه پدر + field_editable: ویرایش پذیر + field_watcher: دیده‌بان + field_identity_url: نشانی OpenID + field_content: محتوا + field_group_by: دسته بندی با + field_sharing: اشتراک گذاری + field_parent_issue: کار پدر + field_member_of_group: "دسته واگذار شونده" + field_assigned_to_role: "نقش واگذار شونده" + field_text: فیلد متنی + field_visible: آشکار + + setting_app_title: نام برنامه + setting_app_subtitle: زیرنام برنامه + setting_welcome_text: نوشتار خوش‌آمد گویی + setting_default_language: زبان پیش‌گزیده + setting_login_required: الزامی بودن ورود + setting_self_registration: خود نام نویسی + setting_attachment_max_size: بیشترین اندازه پیوست + setting_issues_export_limit: کرانه صدور پییامدها + setting_mail_from: نشانی فرستنده ایمیل + setting_bcc_recipients: گیرندگان ایمیل دیده نشوند (bcc) + setting_plain_text_mail: ایمیل نوشته ساده (بدون HTML) + setting_host_name: نام میزبان و نشانی + setting_text_formatting: قالب بندی نوشته + setting_wiki_compression: فشرده‌سازی پیشینه ویکی + setting_feeds_limit: کرانه محتوای خوراک + setting_default_projects_public: حالت پیش‌گزیده پروژه‌های تازه، همگانی است + setting_autofetch_changesets: دریافت خودکار تغییرات + setting_sys_api_enabled: فعال سازی وب سرویس برای سرپرستی انباره + setting_commit_ref_keywords: کلیدواژه‌های نشانه + setting_commit_fix_keywords: کلیدواژه‌های انجام + setting_autologin: ورود خودکار + setting_date_format: قالب تاریخ + setting_time_format: قالب زمان + setting_cross_project_issue_relations: توانایی وابستگی میان پروژه‌ای پیامدها + setting_issue_list_default_columns: ستون‌های پیش‌گزیده نمایش داده شده در فهرست پیامدها + setting_emails_header: سرنویس ایمیل‌ها + setting_emails_footer: پانویس ایمیل‌ها + setting_protocol: پیوندنامه + setting_per_page_options: گزینه‌های اندازه داده‌های هر برگ + setting_user_format: قالب نمایشی کاربران + setting_activity_days_default: روزهای نمایش داده شده در گزارش پروژه + setting_display_subprojects_issues: پیش‌گزیده نمایش پیامدهای زیرپروژه در پروژه پدر + setting_enabled_scm: فعالسازی SCM + setting_mail_handler_body_delimiters: "بریدن ایمیل‌ها پس از یکی از این ردیف‌ها" + setting_mail_handler_api_enabled: فعالسازی وب سرویس برای ایمیل‌های آمده + setting_mail_handler_api_key: کلید API + setting_sequential_project_identifiers: ساخت پشت سر هم شناسه پروژه + setting_gravatar_enabled: کاربرد Gravatar برای عکس کاربر + setting_gravatar_default: عکس Gravatar پیش‌گزیده + setting_diff_max_lines_displayed: بیشترین اندازه ردیف‌های تفاوت نشان داده شده + setting_file_max_size_displayed: بیشترین اندازه پرونده‌های نمایش داده شده درون خطی + setting_repository_log_display_limit: بیشترین شمار نگارش‌های نمایش داده شده در گزارش پرونده + setting_openid: پذیرش ورود و نام نویسی با OpenID + setting_password_min_length: کمترین اندازه گذرواژه + setting_new_project_user_role_id: نقش داده شده به کاربری که سرپرست نیست و پروژه می‌سازد + setting_default_projects_modules: پیمانه‌های پیش‌گزیده فعال برای پروژه‌های تازه + setting_issue_done_ratio: برآورد اندازه انجام شده پیامد با + setting_issue_done_ratio_issue_field: کاربرد فیلد پیامد + setting_issue_done_ratio_issue_status: کاربرد وضعیت پیامد + setting_start_of_week: آغاز گاهشمار از + setting_rest_api_enabled: فعالسازی وب سرویس‌های REST + setting_cache_formatted_text: نهان سازی نوشته‌های قالب بندی شده + setting_default_notification_option: آگاه سازی پیش‌گزیده + setting_commit_logtime_enabled: فعالسازی زمان گذاشته شده + setting_commit_logtime_activity_id: کار زمان گذاشته شده + setting_gantt_items_limit: بیشترین شمار بخش‌های نمایش داده شده در نمودار گانت + + permission_add_project: ساخت پروژه + permission_add_subprojects: ساخت زیرپروژه + permission_edit_project: ویرایش پروژه + permission_select_project_modules: گزینش پیمانه‌های پروژه + permission_manage_members: سرپرستی اعضا + permission_manage_project_activities: سرپرستی کارهای پروژه + permission_manage_versions: سرپرستی نگارش‌ها + permission_manage_categories: سرپرستی دسته‌های پیامد + permission_view_issues: دیدن پیامدها + permission_add_issues: افزودن پیامدها + permission_edit_issues: ویرایش پیامدها + permission_manage_issue_relations: سرپرستی وابستگی پیامدها + permission_add_issue_notes: افزودن یادداشت + permission_edit_issue_notes: ویرایش یادداشت + permission_edit_own_issue_notes: ویرایش یادداشت خود + permission_move_issues: جابجایی پیامدها + permission_delete_issues: پاک کردن پیامدها + permission_manage_public_queries: سرپرستی پرس‌وجوهای همگانی + permission_save_queries: ذخیره سازی پرس‌وجوها + permission_view_gantt: دیدن نمودار گانت + permission_view_calendar: دیدن گاهشمار + permission_view_issue_watchers: دیدن فهرست دیده‌بان‌ها + permission_add_issue_watchers: افزودن دیده‌بان‌ها + permission_delete_issue_watchers: پاک کردن دیده‌بان‌ها + permission_log_time: نوشتن زمان گذاشته شده + permission_view_time_entries: دیدن زمان گذاشته شده + permission_edit_time_entries: ویرایش زمان گذاشته شده + permission_edit_own_time_entries: ویرایش زمان گذاشته شده خود + permission_manage_news: سرپرستی رویدادها + permission_comment_news: گذاشتن دیدگاه روی رویدادها + permission_view_documents: دیدن نوشتارها + permission_manage_files: سرپرستی پرونده‌ها + permission_view_files: دیدن پرونده‌ها + permission_manage_wiki: سرپرستی ویکی + permission_rename_wiki_pages: نامگذاری برگه ویکی + permission_delete_wiki_pages: پاک کردن برگه ویکی + permission_view_wiki_pages: دیدن ویکی + permission_view_wiki_edits: دیدن پیشینه ویکی + permission_edit_wiki_pages: ویرایش برگه‌های ویکی + permission_delete_wiki_pages_attachments: پاک کردن پیوست‌های برگه ویکی + permission_protect_wiki_pages: نگه‌داری برگه‌های ویکی + permission_manage_repository: سرپرستی انباره + permission_browse_repository: چریدن در انباره + permission_view_changesets: دیدن تغییرات + permission_commit_access: دسترسی تغییر انباره + permission_manage_boards: سرپرستی انجمن‌ها + permission_view_messages: دیدن پیام‌ها + permission_add_messages: فرستادن پیام‌ها + permission_edit_messages: ویرایش پیام‌ها + permission_edit_own_messages: ویرایش پیام خود + permission_delete_messages: پاک کردن پیام‌ها + permission_delete_own_messages: پاک کردن پیام خود + permission_export_wiki_pages: صدور برگه‌های ویکی + permission_manage_subtasks: سرپرستی زیرکارها + + project_module_issue_tracking: پیگیری پیامدها + project_module_time_tracking: پیگیری زمان + project_module_news: رویدادها + project_module_documents: نوشتارها + project_module_files: پرونده‌ها + project_module_wiki: ویکی + project_module_repository: انباره + project_module_boards: انجمن‌ها + project_module_calendar: گاهشمار + project_module_gantt: گانت + + label_user: کاربر + label_user_plural: کاربر + label_user_new: کاربر تازه + label_user_anonymous: ناشناس + label_project: پروژه + label_project_new: پروژه تازه + label_project_plural: پروژه + label_x_projects: + zero: بدون پروژه + one: "1 پروژه" + other: "%{count} پروژه" + label_project_all: همه پروژه‌ها + label_project_latest: آخرین پروژه‌ها + label_issue: پیامد + label_issue_new: پیامد تازه + label_issue_plural: پیامد + label_issue_view_all: دیدن همه پیامدها + label_issues_by: "دسته‌بندی پیامدها با %{value}" + label_issue_added: پیامد افزوده شد + label_issue_updated: پیامد بروز شد + label_document: نوشتار + label_document_new: نوشتار تازه + label_document_plural: نوشتار + label_document_added: نوشتار افزوده شد + label_role: نقش + label_role_plural: نقش + label_role_new: نقش تازه + label_role_and_permissions: نقش‌ها و پروانه‌ها + label_member: عضو + label_member_new: عضو تازه + label_member_plural: عضو + label_tracker: پیگرد + label_tracker_plural: پیگرد + label_tracker_new: پیگرد تازه + label_workflow: گردش کار + label_issue_status: وضعیت پیامد + label_issue_status_plural: وضعیت پیامد + label_issue_status_new: وضعیت تازه + label_issue_category: دسته پیامد + label_issue_category_plural: دسته پیامد + label_issue_category_new: دسته تازه + label_custom_field: فیلد سفارشی + label_custom_field_plural: فیلد سفارشی + label_custom_field_new: فیلد سفارشی تازه + label_enumerations: برشمردنی‌ها + label_enumeration_new: مقدار تازه + label_information: داده + label_information_plural: داده + label_please_login: وارد شوید + label_register: نام نویسی کنید + label_login_with_open_id_option: یا با OpenID وارد شوید + label_password_lost: بازیافت گذرواژه + label_home: سرآغاز + label_my_page: برگه من + label_my_account: حساب من + label_my_projects: پروژه‌های من + label_my_page_block: بخش برگه من + label_administration: سرپرستی + label_login: ورود + label_logout: خروج + label_help: راهنما + label_reported_issues: پیامدهای گزارش شده + label_assigned_to_me_issues: پیامدهای واگذار شده به من + label_last_login: آخرین ورود + label_registered_on: نام نویسی شده در + label_activity: گزارش + label_overall_activity: گزارش روی هم رفته + label_user_activity: "گزارش %{value}" + label_new: تازه + label_logged_as: "نام کاربری:" + label_environment: محیط + label_authentication: شناسایی + label_auth_source: روش شناسایی + label_auth_source_new: روش شناسایی تازه + label_auth_source_plural: روش شناسایی + label_subproject_plural: زیرپروژه + label_subproject_new: زیرپروژه تازه + label_and_its_subprojects: "%{value} و زیرپروژه‌هایش" + label_min_max_length: کمترین و بیشترین اندازه + label_list: فهرست + label_date: تاریخ + label_integer: شماره درست + label_float: شماره شناور + label_boolean: درست/نادرست + label_string: نوشته + label_text: نوشته بلند + label_attribute: نشانه + label_attribute_plural: نشانه + label_no_data: هیچ داده‌ای برای نمایش نیست + label_change_status: جایگزینی وضعیت + label_history: پیشینه + label_attachment: پرونده + label_attachment_new: پرونده تازه + label_attachment_delete: پاک کردن پرونده + label_attachment_plural: پرونده + label_file_added: پرونده افزوده شد + label_report: گزارش + label_report_plural: گزارش + label_news: رویداد + label_news_new: افزودن رویداد + label_news_plural: رویداد + label_news_latest: آخرین رویدادها + label_news_view_all: دیدن همه رویدادها + label_news_added: رویداد افزوده شد + label_settings: پیکربندی + label_overview: در یک نگاه + label_version: نگارش + label_version_new: نگارش تازه + label_version_plural: نگارش + label_close_versions: بستن نگارش‌های انجام شده + label_confirmation: بررسی + label_export_to: 'قالب‌های دیگر:' + label_read: خواندن... + label_public_projects: پروژه‌های همگانی + label_open_issues: باز + label_open_issues_plural: باز + label_closed_issues: بسته + label_closed_issues_plural: بسته + label_x_open_issues_abbr_on_total: + zero: 0 باز از %{total} + one: 1 باز از %{total} + other: "%{count} باز از %{total}" + label_x_open_issues_abbr: + zero: 0 باز + one: 1 باز + other: "%{count} باز" + label_x_closed_issues_abbr: + zero: 0 بسته + one: 1 بسته + other: "%{count} بسته" + label_total: جمله + label_permissions: پروانه‌ها + label_current_status: وضعیت کنونی + label_new_statuses_allowed: وضعیت‌های پذیرفتنی تازه + label_all: همه + label_none: هیچ + label_nobody: هیچکس + label_next: پسین + label_previous: پیشین + label_used_by: به کار رفته در + label_details: ریزه‌کاری + label_add_note: افزودن یادداشت + label_per_page: ردیف‌ها در هر برگه + label_calendar: گاهشمار + label_months_from: از ماه + label_gantt: گانت + label_internal: درونی + label_last_changes: "%{count} تغییر آخر" + label_change_view_all: دیدن همه تغییرات + label_personalize_page: سفارشی نمودن این برگه + label_comment: دیدگاه + label_comment_plural: دیدگاه + label_x_comments: + zero: بدون دیدگاه + one: 1 دیدگاه + other: "%{count} دیدگاه" + label_comment_add: افزودن دیدگاه + label_comment_added: دیدگاه افزوده شد + label_comment_delete: پاک کردن دیدگاه‌ها + label_query: پرس‌وجوی سفارشی + label_query_plural: پرس‌وجوی سفارشی + label_query_new: پرس‌وجوی تازه + label_filter_add: افزودن پالایه + label_filter_plural: پالایه + label_equals: برابر است با + label_not_equals: برابر نیست با + label_in_less_than: کمتر است از + label_in_more_than: بیشتر است از + label_greater_or_equal: بیشتر یا برابر است با + label_less_or_equal: کمتر یا برابر است با + label_in: در + label_today: امروز + label_all_time: همیشه + label_yesterday: دیروز + label_this_week: این هفته + label_last_week: هفته پیشین + label_last_n_days: "%{count} روز گذشته" + label_this_month: این ماه + label_last_month: ماه پیشین + label_this_year: امسال + label_date_range: بازه تاریخ + label_less_than_ago: کمتر از چند روز پیشین + label_more_than_ago: بیشتر از چند روز پیشین + label_ago: روز پیشین + label_contains: دارد + label_not_contains: ندارد + label_day_plural: روز + label_repository: انباره + label_repository_plural: انباره + label_browse: چریدن + label_branch: شاخه + label_tag: برچسب + label_revision: بازبینی + label_revision_plural: بازبینی + label_revision_id: "بازبینی %{value}" + label_associated_revisions: بازبینی‌های وابسته + label_added: افزوده شده + label_modified: پیراسته شده + label_copied: رونویسی شده + label_renamed: نامگذاری شده + label_deleted: پاکسازی شده + label_latest_revision: آخرین بازبینی + label_latest_revision_plural: آخرین بازبینی + label_view_revisions: دیدن بازبینی‌ها + label_view_all_revisions: دیدن همه بازبینی‌ها + label_max_size: بیشترین اندازه + label_sort_highest: بردن به آغاز + label_sort_higher: بردن به بالا + label_sort_lower: بردن به پایین + label_sort_lowest: بردن به پایان + label_roadmap: چشم‌انداز + label_roadmap_due_in: "سررسید در %{value}" + label_roadmap_overdue: "%{value} دیرکرد" + label_roadmap_no_issues: هیچ پیامدی برای این نگارش نیست + label_search: جستجو + label_result_plural: دست‌آورد + label_all_words: همه واژه‌ها + label_wiki: ویکی + label_wiki_edit: ویرایش ویکی + label_wiki_edit_plural: ویرایش ویکی + label_wiki_page: برگه ویکی + label_wiki_page_plural: برگه ویکی + label_index_by_title: شاخص بر اساس نام + label_index_by_date: شاخص بر اساس تاریخ + label_current_version: نگارش کنونی + label_preview: پیش‌نمایش + label_feed_plural: خوراک + label_changes_details: ریز همه جایگذاری‌ها + label_issue_tracking: پیگیری پیامد + label_spent_time: زمان گذاشته شده + label_overall_spent_time: زمان گذاشته شده روی هم + label_f_hour: "%{value} ساعت" + label_f_hour_plural: "%{value} ساعت" + label_time_tracking: پیگیری زمان + label_change_plural: جایگذاری + label_statistics: سرشماری + label_commits_per_month: تغییر در هر ماه + label_commits_per_author: تغییر هر نویسنده + label_view_diff: دیدن تفاوت‌ها + label_diff_inline: همراستا + label_diff_side_by_side: کنار به کنار + label_options: گزینه‌ها + label_copy_workflow_from: رونویسی گردش کار از روی + label_permissions_report: گزارش پروانه‌ها + label_watched_issues: پیامدهای دیده‌بانی شده + label_related_issues: پیامدهای وابسته + label_applied_status: وضعیت به کار رفته + label_loading: بار گذاری... + label_relation_new: وابستگی تازه + label_relation_delete: پاک کردن وابستگی + label_relates_to: وابسته به + label_duplicates: نگارش دیگری از + label_duplicated_by: نگارشی دیگر در + label_blocks: بازداشت‌ها + label_blocked_by: بازداشت به دست + label_precedes: جلوتر است از + label_follows: پستر است از + label_end_to_start: پایان به آغاز + label_end_to_end: پایان به پایان + label_start_to_start: آغاز به آغاز + label_start_to_end: آغاز به پایان + label_stay_logged_in: وارد شده بمانید + label_disabled: غیرفعال + label_show_completed_versions: نمایش نگارش‌های انجام شده + label_me: من + label_board: انجمن + label_board_new: انجمن تازه + label_board_plural: انجمن + label_board_locked: قفل شده + label_board_sticky: چسبناک + label_topic_plural: سرفصل + label_message_plural: پیام + label_message_last: آخرین پیام + label_message_new: پیام تازه + label_message_posted: پیام افزوده شد + label_reply_plural: پاسخ + label_send_information: فرستادن داده‌های حساب به کاربر + label_year: سال + label_month: ماه + label_week: هفته + label_date_from: از + label_date_to: تا + label_language_based: بر اساس زبان کاربر + label_sort_by: "جور کرد با %{value}" + label_send_test_email: فرستادن ایمیل آزمایشی + label_feeds_access_key: کلید دسترسی RSS + label_missing_feeds_access_key: کلید دسترسی RSS در دسترس نیست + label_feeds_access_key_created_on: "کلید دسترسی RSS %{value} پیش ساخته شده است" + label_module_plural: پیمانه + label_added_time_by: "افزوده شده به دست %{author} در %{age} پیش" + label_updated_time_by: "بروز شده به دست %{author} در %{age} پیش" + label_updated_time: "بروز شده در %{value} پیش" + label_jump_to_a_project: پرش به یک پروژه... + label_file_plural: پرونده + label_changeset_plural: تغییر + label_default_columns: ستون‌های پیش‌گزیده + label_no_change_option: (بدون تغییر) + label_bulk_edit_selected_issues: ویرایش دسته‌ای پیامدهای گزینش شده + label_theme: پوسته + label_default: پیش‌گزیده + label_search_titles_only: تنها نام‌ها جستجو شود + label_user_mail_option_all: "برای هر رویداد در همه پروژه‌ها" + label_user_mail_option_selected: "برای هر رویداد تنها در پروژه‌های گزینش شده..." + label_user_mail_option_none: "هیچ رویدادی" + label_user_mail_option_only_my_events: "تنها برای چیزهایی که دیده‌بان هستم یا در آن‌ها درگیر هستم" + label_user_mail_option_only_assigned: "تنها برای چیزهایی که به من واگذار شده" + label_user_mail_option_only_owner: "تنها برای چیزهایی که من دارنده آن‌ها هستم" + label_user_mail_no_self_notified: "نمی‌خواهم از تغییراتی که خودم می‌دهم آگاه شوم" + label_registration_activation_by_email: فعالسازی حساب با ایمیل + label_registration_manual_activation: فعالسازی حساب دستی + label_registration_automatic_activation: فعالسازی حساب خودکار + label_display_per_page: "ردیف‌ها در هر برگه: %{value}" + label_age: سن + label_change_properties: ویرایش ویژگی‌ها + label_general: همگانی + label_more: بیشتر + label_scm: SCM + label_plugins: افزونه‌ها + label_ldap_authentication: شناساییLDAP + label_downloads_abbr: دریافت + label_optional_description: یادداشت دلخواه + label_add_another_file: افزودن پرونده دیگر + label_preferences: پسندها + label_chronological_order: به ترتیب تاریخ + label_reverse_chronological_order: برعکس ترتیب تاریخ + label_planning: برنامه ریزی + label_incoming_emails: ایمیل‌های آمده + label_generate_key: ساخت کلید + label_issue_watchers: دیده‌بان‌ها + label_example: نمونه + label_display: نمایش + label_sort: جور کرد + label_ascending: افزایشی + label_descending: کاهشی + label_date_from_to: از %{start} تا %{end} + label_wiki_content_added: برگه ویکی افزوده شد + label_wiki_content_updated: برگه ویکی بروز شد + label_group: دسته + label_group_plural: دسته + label_group_new: دسته تازه + label_time_entry_plural: زمان گذاشته شده + label_version_sharing_none: بدون اشتراک + label_version_sharing_descendants: با زیر پروژه‌ها + label_version_sharing_hierarchy: با رشته پروژه‌ها + label_version_sharing_tree: با درخت پروژه + label_version_sharing_system: با همه پروژه‌ها + label_update_issue_done_ratios: بروز رسانی اندازه انجام شده پیامد + label_copy_source: منبع + label_copy_target: مقصد + label_copy_same_as_target: مانند مقصد + label_display_used_statuses_only: تنها وضعیت‌هایی نشان داده شوند که در این پیگرد به کار رفته‌اند + label_api_access_key: کلید دسترسی API + label_missing_api_access_key: کلید دسترسی API در دسترس نیست + label_api_access_key_created_on: "کلید دسترسی API %{value} پیش ساخته شده است" + label_profile: نمایه + label_subtask_plural: زیرکار + label_project_copy_notifications: در هنگام رونویسی پروژه ایمیل‌های آگاه‌سازی را بفرست + label_principal_search: "جستجو برای کاربر یا دسته:" + label_user_search: "جستجو برای کاربر:" + + button_login: ورود + button_submit: واگذاری + button_save: نگهداری + button_check_all: گزینش همه + button_uncheck_all: گزینش هیچ + button_delete: پاک + button_create: ساخت + button_create_and_continue: ساخت و ادامه + button_test: آزمایش + button_edit: ویرایش + button_edit_associated_wikipage: "ویرایش برگه ویکی وابسته: %{page_title}" + button_add: افزودن + button_change: ویرایش + button_apply: انجام + button_clear: پاک + button_lock: گذاشتن قفل + button_unlock: برداشتن قفل + button_download: دریافت + button_list: فهرست + button_view: دیدن + button_move: جابجایی + button_move_and_follow: جابجایی و ادامه + button_back: برگشت + button_cancel: بازگشت + button_activate: فعالسازی + button_sort: جور کرد + button_log_time: زمان‌نویسی + button_rollback: برگرد به این نگارش + button_watch: دیده‌بانی + button_unwatch: نا‌دیده‌بانی + button_reply: پاسخ + button_archive: بایگانی + button_unarchive: برگشت از بایگانی + button_reset: بازنشانی + button_rename: نامگذاری + button_change_password: جایگزینی گذرواژه + button_copy: رونوشت + button_copy_and_follow: رونوشت و ادامه + button_annotate: یادداشت + button_update: بروز رسانی + button_configure: پیکربندی + button_quote: نقل قول + button_duplicate: نگارش دیگر + button_show: نمایش + + status_active: فعال + status_registered: نام‌نویسی شده + status_locked: قفل + + version_status_open: باز + version_status_locked: قفل + version_status_closed: بسته + + field_active: فعال + + text_select_mail_notifications: فرمان‌هایی که برای آن‌ها باید ایمیل فرستاده شود را برگزینید. + text_regexp_info: برای نمونه ^[A-Z0-9]+$ + text_min_max_length_info: 0 یعنی بدون کران + text_project_destroy_confirmation: آیا براستی می‌خواهید این پروژه و همه داده‌های آن را پاک کنید؟ + text_subprojects_destroy_warning: "زیرپروژه‌های آن: %{value} هم پاک خواهند شد." + text_workflow_edit: یک نقش و یک پیگرد را برای ویرایش گردش کار برگزینید + text_are_you_sure: آیا این کار انجام شود؟ + text_journal_changed: "«%{label}» از «%{old}» به «%{new}» جایگزین شد" + text_journal_set_to: "«%{label}» به «%{value}» نشانده شد" + text_journal_deleted: "«%{label}» پاک شد (%{old})" + text_journal_added: "«%{label}»، «%{value}» را افزود" + text_tip_task_begin_day: روز آغاز پیامد + text_tip_task_end_day: روز پایان پیامد + text_tip_task_begin_end_day: روز آغاز و پایان پیامد + text_caracters_maximum: "بیشترین اندازه %{count} است." + text_caracters_minimum: "کمترین اندازه %{count} است." + text_length_between: "باید میان %{min} و %{max} نویسه باشد." + text_tracker_no_workflow: هیچ گردش کاری برای این پیگرد مشخص نشده است + text_unallowed_characters: نویسه‌های ناپسند + text_comma_separated: چند مقدار پذیرفتنی است (با «,» از هم جدا شوند). + text_line_separated: چند مقدار پذیرفتنی است (هر مقدار در یک خط). + text_issues_ref_in_commit_messages: نشانه روی و بستن پیامدها در پیام‌های انباره + text_issue_added: "پیامد %{id} به دست %{author} گزارش شد." + text_issue_updated: "پیامد %{id} به دست %{author} بروز شد." + text_wiki_destroy_confirmation: آیا براستی می‌خواهید این ویکی و همه محتوای آن را پاک کنید؟ + text_issue_category_destroy_question: "برخی پیامدها (%{count}) به این دسته واگذار شده‌اند. می‌خواهید چه کنید؟" + text_issue_category_destroy_assignments: پاک کردن واگذاری به دسته + text_issue_category_reassign_to: واگذاری دوباره پیامدها به این دسته + text_user_mail_option: "برای پروژه‌های گزینش نشده، تنها ایمیل‌هایی درباره چیزهایی که دیده‌بان یا درگیر آن‌ها هستید دریافت خواهید کرد (مانند پیامدهایی که نویسنده آن‌ها هستید یا به شما واگذار شده‌اند)." + text_no_configuration_data: "نقش‌ها، پیگردها، وضعیت‌های پیامد و گردش کار هنوز پیکربندی نشده‌اند. \nبه سختی پیشنهاد می‌شود که پیکربندی پیش‌گزیده را بار کنید. سپس می‌توانید آن را ویرایش کنید." + text_load_default_configuration: بارگذاری پیکربندی پیش‌گزیده + text_status_changed_by_changeset: "در تغییر %{value} بروز شده است." + text_time_logged_by_changeset: "در تغییر %{value} نوشته شده است." + text_issues_destroy_confirmation: 'آیا براستی می‌خواهید پیامدهای گزینش شده را پاک کنید؟' + text_select_project_modules: 'پیمانه‌هایی که باید برای این پروژه فعال شوند را برگزینید:' + text_default_administrator_account_changed: حساب سرپرستی پیش‌گزیده جایگزین شد + text_file_repository_writable: پوشه پیوست‌ها نوشتنی است + text_plugin_assets_writable: پوشه دارایی‌های افزونه‌ها نوشتنی است + text_rmagick_available: RMagick در دسترس است (اختیاری) + text_destroy_time_entries_question: "%{hours} ساعت روی پیامدهایی که می‌خواهید پاک کنید کار گزارش شده است. می‌خواهید چه کنید؟" + text_destroy_time_entries: ساعت‌های گزارش شده پاک شوند + text_assign_time_entries_to_project: ساعت‌های گزارش شده به پروژه واگذار شوند + text_reassign_time_entries: 'ساعت‌های گزارش شده به این پیامد واگذار شوند:' + text_user_wrote: "%{value} نوشت:" + text_enumeration_destroy_question: "%{count} داده به این برشمردنی وابسته شده‌اند." + text_enumeration_category_reassign_to: 'به این برشمردنی وابسته شوند:' + text_email_delivery_not_configured: "دریافت ایمیل پیکربندی نشده است و آگاه‌سازی‌ها غیر فعال هستند.\nکارگزار SMTP خود را در config/configuration.yml پیکربندی کنید و برنامه را بازنشانی کنید تا فعال شوند." + text_repository_usernames_mapping: "کاربر Redmine که به هر نام کاربری پیام‌های انباره نگاشت می‌شود را برگزینید.\nکاربرانی که نام کاربری یا ایمیل همسان دارند، خود به خود نگاشت می‌شوند." + text_diff_truncated: '... این تفاوت بریده شده چون بیشتر از بیشترین اندازه نمایش دادنی است.' + text_custom_field_possible_values_info: 'یک خط برای هر مقدار' + text_wiki_page_destroy_question: "این برگه %{descendants} زیربرگه دارد.می‌خواهید چه کنید؟" + text_wiki_page_nullify_children: "زیربرگه‌ها برگه ریشه شوند" + text_wiki_page_destroy_children: "زیربرگه‌ها و زیربرگه‌های آن‌ها پاک شوند" + text_wiki_page_reassign_children: "زیربرگه‌ها به زیر این برگه پدر بروند" + text_own_membership_delete_confirmation: "شما دارید برخی یا همه پروانه‌های خود را برمی‌دارید و شاید پس از این دیگر نتوانید این پروژه را ویرایش کنید.\nآیا می‌خواهید این کار را بکنید؟" + text_zoom_in: درشتنمایی + text_zoom_out: ریزنمایی + + default_role_manager: سرپرست + default_role_developer: برنامه‌نویس + default_role_reporter: گزارش‌دهنده + default_tracker_bug: ایراد + default_tracker_feature: ویژگی + default_tracker_support: پشتیبانی + default_issue_status_new: تازه + default_issue_status_in_progress: در گردش + default_issue_status_resolved: درست شده + default_issue_status_feedback: بازخورد + default_issue_status_closed: بسته + default_issue_status_rejected: برگشت خورده + default_doc_category_user: نوشتار کاربر + default_doc_category_tech: نوشتار فنی + default_priority_low: پایین + default_priority_normal: میانه + default_priority_high: بالا + default_priority_urgent: زود + default_priority_immediate: بیدرنگ + default_activity_design: طراحی + default_activity_development: ساخت + + enumeration_issue_priorities: برتری‌های پیامد + enumeration_doc_categories: دسته‌های نوشتار + enumeration_activities: کارها (پیگیری زمان) + enumeration_system_activity: کار سامانه + + text_tip_issue_begin_day: پیامد در این روز آغاز می‌شود + field_warn_on_leaving_unsaved: هنگام ترک برگه‌ای که نوشته‌های آن نگهداری نشده، به من هشدار بده + text_tip_issue_begin_end_day: پیامد در این روز آغاز می‌شود و پایان می‌پذیرد + text_tip_issue_end_day: پیامد در این روز پایان می‌پذیرد + text_warn_on_leaving_unsaved: این برگه دارای نوشته‌های نگهداری نشده است که اگر آن را ترک کنید، از میان می‌روند. + label_my_queries: جستارهای سفارشی من + text_journal_changed_no_detail: "%{label} بروز شد" + label_news_comment_added: دیدگاه به یک رویداد افزوده شد + button_expand_all: باز کردن همه + button_collapse_all: بستن همه + label_additional_workflow_transitions_for_assignee: زمانی که به کاربر واگذار شده، گذارهای بیشتر پذیرفته می‌شود + label_additional_workflow_transitions_for_author: زمانی که کاربر نویسنده است، گذارهای بیشتر پذیرفته می‌شود + label_bulk_edit_selected_time_entries: ویرایش دسته‌ای زمان‌های گزارش شده گزینش شده + text_time_entries_destroy_confirmation: آیا می‌خواهید زمان‌های گزارش شده گزینش شده پاک شوند؟ + label_role_anonymous: ناشناس + label_role_non_member: غیر عضو + label_issue_note_added: یادداشت افزوده شد + label_issue_status_updated: وضعیت بروز شد + label_issue_priority_updated: برتری بروز شد + label_issues_visibility_own: Issues created by or assigned to the user + field_issues_visibility: Issues visibility + label_issues_visibility_all: All issues + permission_set_own_issues_private: Set own issues public or private + field_is_private: Private + permission_set_issues_private: Set issues public or private + label_issues_visibility_public: All non private issues + text_issues_destroy_descendants_confirmation: This will also delete %{count} subtask(s). + field_commit_logs_encoding: کدگذاری پیام‌های انباره + field_scm_path_encoding: Path encoding + text_scm_path_encoding_note: "Default: UTF-8" + field_path_to_repository: Path to repository + field_root_directory: Root directory + field_cvs_module: Module + field_cvsroot: CVSROOT + text_mercurial_repository_note: Local repository (e.g. /hgrepo, c:\hgrepo) + text_scm_command: Command + text_scm_command_version: Version + label_git_report_last_commit: Report last commit for files and directories + notice_issue_successful_create: Issue %{id} created. + label_between: between + setting_issue_group_assignment: Allow issue assignment to groups + label_diff: diff + text_git_repository_note: Repository is bare and local (e.g. /gitrepo, c:\gitrepo) + description_query_sort_criteria_direction: Sort direction + description_project_scope: Search scope + description_filter: Filter + description_user_mail_notification: Mail notification settings + description_date_from: Enter start date + description_message_content: Message content + description_available_columns: Available Columns + description_date_range_interval: Choose range by selecting start and end date + description_issue_category_reassign: Choose issue category + description_search: Searchfield + description_notes: Notes + description_date_range_list: Choose range from list + description_choose_project: Projects + description_date_to: Enter end date + description_query_sort_criteria_attribute: Sort attribute + description_wiki_subpages_reassign: Choose new parent page + description_selected_columns: Selected Columns + label_parent_revision: Parent + label_child_revision: Child + error_scm_annotate_big_text_file: The entry cannot be annotated, as it exceeds the maximum text file size. + setting_default_issue_start_date_to_creation_date: Use current date as start date for new issues + button_edit_section: Edit this section + setting_repositories_encodings: Attachments and repositories encodings + description_all_columns: All Columns + button_export: Export + label_export_options: "%{export_format} export options" + error_attachment_too_big: This file cannot be uploaded because it exceeds the maximum allowed file size (%{max_size}) + notice_failed_to_save_time_entries: "Failed to save %{count} time entrie(s) on %{total} selected: %{ids}." + label_x_issues: + zero: 0 پیامد + one: 1 پیامد + other: "%{count} پیامد" + label_repository_new: New repository + field_repository_is_default: Main repository + label_copy_attachments: Copy attachments + label_item_position: "%{position}/%{count}" + label_completed_versions: Completed versions + text_project_identifier_info: Only lower case letters (a-z), numbers, dashes and underscores are allowed.
    Once saved, the identifier cannot be changed. + field_multiple: Multiple values + setting_commit_cross_project_ref: Allow issues of all the other projects to be referenced and fixed + text_issue_conflict_resolution_add_notes: Add my notes and discard my other changes + text_issue_conflict_resolution_overwrite: Apply my changes anyway (previous notes will be kept but some changes may be overwritten) + notice_issue_update_conflict: The issue has been updated by an other user while you were editing it. + text_issue_conflict_resolution_cancel: Discard all my changes and redisplay %{link} + permission_manage_related_issues: Manage related issues + field_auth_source_ldap_filter: LDAP filter + label_search_for_watchers: Search for watchers to add + notice_account_deleted: Your account has been permanently deleted. + setting_unsubscribe: Allow users to delete their own account + button_delete_my_account: Delete my account + text_account_destroy_confirmation: |- + Are you sure you want to proceed? + Your account will be permanently deleted, with no way to reactivate it. + error_session_expired: Your session has expired. Please login again. + text_session_expiration_settings: "Warning: changing these settings may expire the current sessions including yours." + setting_session_lifetime: Session maximum lifetime + setting_session_timeout: Session inactivity timeout + label_session_expiration: Session expiration + permission_close_project: Close / reopen the project + label_show_closed_projects: View closed projects + button_close: Close + button_reopen: Reopen + project_status_active: active + project_status_closed: closed + project_status_archived: archived + text_project_closed: This project is closed and read-only. + notice_user_successful_create: User %{id} created. + field_core_fields: Standard fields + field_timeout: Timeout (in seconds) + setting_thumbnails_enabled: Display attachment thumbnails + setting_thumbnails_size: Thumbnails size (in pixels) + label_status_transitions: Status transitions + label_fields_permissions: Fields permissions + label_readonly: Read-only + label_required: Required + text_repository_identifier_info: Only lower case letters (a-z), numbers, dashes and underscores are allowed.
    Once saved, the identifier cannot be changed. + field_board_parent: Parent forum + label_attribute_of_project: Project's %{name} + label_attribute_of_author: Author's %{name} + label_attribute_of_assigned_to: Assignee's %{name} + label_attribute_of_fixed_version: Target version's %{name} + label_copy_subtasks: Copy subtasks + label_copied_to: copied to + label_copied_from: copied from + label_any_issues_in_project: any issues in project + label_any_issues_not_in_project: any issues not in project + field_private_notes: Private notes + permission_view_private_notes: View private notes + permission_set_notes_private: Set notes as private + label_no_issues_in_project: no issues in project + label_any: همه + label_last_n_weeks: last %{count} weeks + setting_cross_project_subtasks: Allow cross-project subtasks + label_cross_project_descendants: با زیر پروژه‌ها + label_cross_project_tree: با درخت پروژه + label_cross_project_hierarchy: با رشته پروژه‌ها + label_cross_project_system: با همه پروژه‌ها + button_hide: Hide + setting_non_working_week_days: Non-working days + label_in_the_next_days: in the next + label_in_the_past_days: in the past + label_attribute_of_user: User's %{name} + text_turning_multiple_off: If you disable multiple values, multiple values will be + removed in order to preserve only one value per item. + label_attribute_of_issue: Issue's %{name} + permission_add_documents: Add documents + permission_edit_documents: Edit documents + permission_delete_documents: Delete documents + label_gantt_progress_line: Progress line + setting_jsonp_enabled: Enable JSONP support + field_inherit_members: Inherit members + field_closed_on: Closed + setting_default_projects_tracker_ids: Default trackers for new projects + label_total_time: جمله + text_scm_config: You can configure your SCM commands in config/configuration.yml. Please restart the application after editing it. + text_scm_command_not_available: SCM command is not available. Please check settings on the administration panel. diff --git a/config/locales/fi.yml b/config/locales/fi.yml new file mode 100644 index 00000000..97564e79 --- /dev/null +++ b/config/locales/fi.yml @@ -0,0 +1,1110 @@ +# Finnish translations for Ruby on Rails +# by Marko Seppä (marko.seppa@gmail.com) + +fi: + direction: ltr + date: + formats: + default: "%e. %Bta %Y" + long: "%A%e. %Bta %Y" + short: "%e.%m.%Y" + + day_names: [Sunnuntai, Maanantai, Tiistai, Keskiviikko, Torstai, Perjantai, Lauantai] + abbr_day_names: [Su, Ma, Ti, Ke, To, Pe, La] + month_names: [~, Tammikuu, Helmikuu, Maaliskuu, Huhtikuu, Toukokuu, Kesäkuu, Heinäkuu, Elokuu, Syyskuu, Lokakuu, Marraskuu, Joulukuu] + abbr_month_names: [~, Tammi, Helmi, Maalis, Huhti, Touko, Kesä, Heinä, Elo, Syys, Loka, Marras, Joulu] + order: + - :day + - :month + - :year + + time: + formats: + default: "%a, %e. %b %Y %H:%M:%S %z" + time: "%H:%M" + short: "%e. %b %H:%M" + long: "%B %d, %Y %H:%M" + am: "aamupäivä" + pm: "iltapäivä" + + support: + array: + words_connector: ", " + two_words_connector: " ja " + last_word_connector: " ja " + + + + number: + format: + separator: "," + delimiter: "." + precision: 3 + + currency: + format: + format: "%n %u" + unit: "€" + separator: "," + delimiter: "." + precision: 2 + + percentage: + format: + # separator: + delimiter: "" + # precision: + + precision: + format: + # separator: + delimiter: "" + # precision: + + human: + format: + delimiter: "" + precision: 3 + storage_units: + format: "%n %u" + units: + byte: + one: "Tavua" + other: "Tavua" + kb: "KB" + mb: "MB" + gb: "GB" + tb: "TB" + + datetime: + distance_in_words: + half_a_minute: "puoli minuuttia" + less_than_x_seconds: + one: "aiemmin kuin sekunti" + other: "aiemmin kuin %{count} sekuntia" + x_seconds: + one: "sekunti" + other: "%{count} sekuntia" + less_than_x_minutes: + one: "aiemmin kuin minuutti" + other: "aiemmin kuin %{count} minuuttia" + x_minutes: + one: "minuutti" + other: "%{count} minuuttia" + about_x_hours: + one: "noin tunti" + other: "noin %{count} tuntia" + x_hours: + one: "1 hour" + other: "%{count} hours" + x_days: + one: "päivä" + other: "%{count} päivää" + about_x_months: + one: "noin kuukausi" + other: "noin %{count} kuukautta" + x_months: + one: "kuukausi" + other: "%{count} kuukautta" + about_x_years: + one: "vuosi" + other: "noin %{count} vuotta" + over_x_years: + one: "yli vuosi" + other: "yli %{count} vuotta" + almost_x_years: + one: "almost 1 year" + other: "almost %{count} years" + prompts: + year: "Vuosi" + month: "Kuukausi" + day: "Päivä" + hour: "Tunti" + minute: "Minuutti" + second: "Sekuntia" + + activerecord: + errors: + template: + header: + one: "1 virhe esti tämän %{model} mallinteen tallentamisen" + other: "%{count} virhettä esti tämän %{model} mallinteen tallentamisen" + body: "Seuraavat kentät aiheuttivat ongelmia:" + messages: + inclusion: "ei löydy listauksesta" + exclusion: "on jo varattu" + invalid: "on kelvoton" + confirmation: "ei vastaa varmennusta" + accepted: "täytyy olla hyväksytty" + empty: "ei voi olla tyhjä" + blank: "ei voi olla sisällötön" + too_long: "on liian pitkä (maksimi on %{count} merkkiä)" + too_short: "on liian lyhyt (minimi on %{count} merkkiä)" + wrong_length: "on väärän pituinen (täytyy olla täsmälleen %{count} merkkiä)" + taken: "on jo käytössä" + not_a_number: "ei ole numero" + greater_than: "täytyy olla suurempi kuin %{count}" + greater_than_or_equal_to: "täytyy olla suurempi tai yhtä suuri kuin%{count}" + equal_to: "täytyy olla yhtä suuri kuin %{count}" + less_than: "täytyy olla pienempi kuin %{count}" + less_than_or_equal_to: "täytyy olla pienempi tai yhtä suuri kuin %{count}" + odd: "täytyy olla pariton" + even: "täytyy olla parillinen" + greater_than_start_date: "tulee olla aloituspäivän jälkeinen" + not_same_project: "ei kuulu samaan projektiin" + circular_dependency: "Tämä suhde loisi kehän." + cant_link_an_issue_with_a_descendant: "An issue can not be linked to one of its subtasks" + + actionview_instancetag_blank_option: Valitse, ole hyvä + + general_text_No: 'Ei' + general_text_Yes: 'Kyllä' + general_text_no: 'ei' + general_text_yes: 'kyllä' + general_lang_name: 'Finnish (Suomi)' + general_csv_separator: ',' + general_csv_decimal_separator: '.' + general_csv_encoding: ISO-8859-15 + general_pdf_encoding: UTF-8 + general_first_day_of_week: '1' + + notice_account_updated: Tilin päivitys onnistui. + notice_account_invalid_creditentials: Virheellinen käyttäjätunnus tai salasana + notice_account_password_updated: Salasanan päivitys onnistui. + notice_account_wrong_password: Väärä salasana + notice_account_register_done: Tilin luonti onnistui. Aktivoidaksesi tilin seuraa linkkiä joka välitettiin sähköpostiisi. + notice_account_unknown_email: Tuntematon käyttäjä. + notice_can_t_change_password: Tämä tili käyttää ulkoista tunnistautumisjärjestelmää. Salasanaa ei voi muuttaa. + notice_account_lost_email_sent: Sinulle on lähetetty sähköposti jossa on ohje kuinka vaihdat salasanasi. + notice_account_activated: Tilisi on nyt aktivoitu, voit kirjautua sisälle. + notice_successful_create: Luonti onnistui. + notice_successful_update: Päivitys onnistui. + notice_successful_delete: Poisto onnistui. + notice_successful_connection: Yhteyden muodostus onnistui. + notice_file_not_found: Hakemaasi sivua ei löytynyt tai se on poistettu. + notice_locking_conflict: Toinen käyttäjä on päivittänyt tiedot. + notice_not_authorized: Sinulla ei ole oikeutta näyttää tätä sivua. + notice_email_sent: "Sähköposti on lähetty osoitteeseen %{value}" + notice_email_error: "Sähköpostilähetyksessä tapahtui virhe (%{value})" + notice_feeds_access_key_reseted: RSS salasana on nollaantunut. + notice_failed_to_save_issues: "%{count} Tapahtum(an/ien) tallennus epäonnistui %{total} valitut: %{ids}." + notice_no_issue_selected: "Tapahtumia ei ole valittu! Valitse tapahtumat joita haluat muokata." + notice_account_pending: "Tilisi on luotu ja odottaa ylläpitäjän hyväksyntää." + notice_default_data_loaded: Vakioasetusten palautus onnistui. + + error_can_t_load_default_data: "Vakioasetuksia ei voitu ladata: %{value}" + error_scm_not_found: "Syötettä ja/tai versiota ei löydy tietovarastosta." + error_scm_command_failed: "Tietovarastoon pääsyssä tapahtui virhe: %{value}" + + mail_subject_lost_password: "Sinun %{value} salasanasi" + mail_body_lost_password: 'Vaihtaaksesi salasanasi, napsauta seuraavaa linkkiä:' + mail_subject_register: "%{value} tilin aktivointi" + mail_body_register: 'Aktivoidaksesi tilisi, napsauta seuraavaa linkkiä:' + mail_body_account_information_external: "Voit nyt käyttää %{value} tiliäsi kirjautuaksesi järjestelmään." + mail_body_account_information: Sinun tilin tiedot + mail_subject_account_activation_request: "%{value} tilin aktivointi pyyntö" + mail_body_account_activation_request: "Uusi käyttäjä (%{value}) on rekisteröitynyt. Hänen tili odottaa hyväksyntääsi:" + + + field_name: Nimi + field_description: Kuvaus + field_summary: Yhteenveto + field_is_required: Vaaditaan + field_firstname: Etunimi + field_lastname: Sukunimi + field_mail: Sähköposti + field_filename: Tiedosto + field_filesize: Koko + field_downloads: Latausta + field_author: Tekijä + field_created_on: Luotu + field_updated_on: Päivitetty + field_field_format: Muoto + field_is_for_all: Kaikille projekteille + field_possible_values: Mahdolliset arvot + field_regexp: Säännöllinen lauseke (reg exp) + field_min_length: Minimipituus + field_max_length: Maksimipituus + field_value: Arvo + field_category: Luokka + field_title: Otsikko + field_project: Projekti + field_issue: Tapahtuma + field_status: Tila + field_notes: Muistiinpanot + field_is_closed: Tapahtuma suljettu + field_is_default: Vakioarvo + field_tracker: Tapahtuma + field_subject: Aihe + field_due_date: Määräaika + field_assigned_to: Nimetty + field_priority: Prioriteetti + field_fixed_version: Kohdeversio + field_user: Käyttäjä + field_role: Rooli + field_homepage: Kotisivu + field_is_public: Julkinen + field_parent: Aliprojekti + field_is_in_roadmap: Tapahtumat näytetään roadmap näkymässä + field_login: Kirjautuminen + field_mail_notification: Sähköposti muistutukset + field_admin: Ylläpitäjä + field_last_login_on: Viimeinen yhteys + field_language: Kieli + field_effective_date: Päivä + field_password: Salasana + field_new_password: Uusi salasana + field_password_confirmation: Vahvistus + field_version: Versio + field_type: Tyyppi + field_host: Verkko-osoite + field_port: Portti + field_account: Tili + field_base_dn: Base DN + field_attr_login: Kirjautumismääre + field_attr_firstname: Etuminenmääre + field_attr_lastname: Sukunimenmääre + field_attr_mail: Sähköpostinmääre + field_onthefly: Automaattinen käyttäjien luonti + field_start_date: Alku + field_done_ratio: "% Tehty" + field_auth_source: Varmennusmuoto + field_hide_mail: Piiloita sähköpostiosoitteeni + field_comments: Kommentti + field_url: URL + field_start_page: Aloitussivu + field_subproject: Aliprojekti + field_hours: Tuntia + field_activity: Historia + field_spent_on: Päivä + field_identifier: Tunniste + field_is_filter: Käytetään suodattimena + field_issue_to: Liittyvä tapahtuma + field_delay: Viive + field_assignable: Tapahtumia voidaan nimetä tälle roolille + field_redirect_existing_links: Uudelleenohjaa olemassa olevat linkit + field_estimated_hours: Arvioitu aika + field_column_names: Saraketta + field_time_zone: Aikavyöhyke + field_searchable: Haettava + field_default_value: Vakioarvo + + setting_app_title: Ohjelman otsikko + setting_app_subtitle: Ohjelman alaotsikko + setting_welcome_text: Tervehdysteksti + setting_default_language: Vakiokieli + setting_login_required: Pakollinen kirjautuminen + setting_self_registration: Itserekisteröinti + setting_attachment_max_size: Liitteen maksimikoko + setting_issues_export_limit: Tapahtumien vientirajoite + setting_mail_from: Lähettäjän sähköpostiosoite + setting_bcc_recipients: Vastaanottajat piilokopiona (bcc) + setting_host_name: Verkko-osoite + setting_text_formatting: Tekstin muotoilu + setting_wiki_compression: Wiki historian pakkaus + setting_feeds_limit: Syötteen sisällön raja + setting_autofetch_changesets: Automaattisten muutosjoukkojen haku + setting_sys_api_enabled: Salli WS tietovaraston hallintaan + setting_commit_ref_keywords: Viittaavat hakusanat + setting_commit_fix_keywords: Korjaavat hakusanat + setting_autologin: Automaatinen kirjautuminen + setting_date_format: Päivän muoto + setting_time_format: Ajan muoto + setting_cross_project_issue_relations: Salli projektien väliset tapahtuminen suhteet + setting_issue_list_default_columns: Vakiosarakkeiden näyttö tapahtumalistauksessa + setting_emails_footer: Sähköpostin alatunniste + setting_protocol: Protokolla + setting_per_page_options: Sivun objektien määrän asetukset + + label_user: Käyttäjä + label_user_plural: Käyttäjät + label_user_new: Uusi käyttäjä + label_project: Projekti + label_project_new: Uusi projekti + label_project_plural: Projektit + label_x_projects: + zero: no projects + one: 1 project + other: "%{count} projects" + label_project_all: Kaikki projektit + label_project_latest: Uusimmat projektit + label_issue: Tapahtuma + label_issue_new: Uusi tapahtuma + label_issue_plural: Tapahtumat + label_issue_view_all: Näytä kaikki tapahtumat + label_issues_by: "Tapahtumat %{value}" + label_document: Dokumentti + label_document_new: Uusi dokumentti + label_document_plural: Dokumentit + label_role: Rooli + label_role_plural: Roolit + label_role_new: Uusi rooli + label_role_and_permissions: Roolit ja oikeudet + label_member: Jäsen + label_member_new: Uusi jäsen + label_member_plural: Jäsenet + label_tracker: Tapahtuma + label_tracker_plural: Tapahtumat + label_tracker_new: Uusi tapahtuma + label_workflow: Työnkulku + label_issue_status: Tapahtuman tila + label_issue_status_plural: Tapahtumien tilat + label_issue_status_new: Uusi tila + label_issue_category: Tapahtumaluokka + label_issue_category_plural: Tapahtumaluokat + label_issue_category_new: Uusi luokka + label_custom_field: Räätälöity kenttä + label_custom_field_plural: Räätälöidyt kentät + label_custom_field_new: Uusi räätälöity kenttä + label_enumerations: Lista + label_enumeration_new: Uusi arvo + label_information: Tieto + label_information_plural: Tiedot + label_please_login: Kirjaudu ole hyvä + label_register: Rekisteröidy + label_password_lost: Hukattu salasana + label_home: Koti + label_my_page: Omasivu + label_my_account: Oma tili + label_my_projects: Omat projektit + label_administration: Ylläpito + label_login: Kirjaudu sisään + label_logout: Kirjaudu ulos + label_help: Ohjeet + label_reported_issues: Raportoidut tapahtumat + label_assigned_to_me_issues: Minulle nimetyt tapahtumat + label_last_login: Viimeinen yhteys + label_registered_on: Rekisteröity + label_activity: Historia + label_new: Uusi + label_logged_as: Kirjauduttu nimellä + label_environment: Ympäristö + label_authentication: Varmennus + label_auth_source: Varmennustapa + label_auth_source_new: Uusi varmennustapa + label_auth_source_plural: Varmennustavat + label_subproject_plural: Aliprojektit + label_min_max_length: Min - Max pituudet + label_list: Lista + label_date: Päivä + label_integer: Kokonaisluku + label_float: Liukuluku + label_boolean: Totuusarvomuuttuja + label_string: Merkkijono + label_text: Pitkä merkkijono + label_attribute: Määre + label_attribute_plural: Määreet + label_no_data: Ei tietoa näytettäväksi + label_change_status: Muutos tila + label_history: Historia + label_attachment: Tiedosto + label_attachment_new: Uusi tiedosto + label_attachment_delete: Poista tiedosto + label_attachment_plural: Tiedostot + label_report: Raportti + label_report_plural: Raportit + label_news: Uutinen + label_news_new: Lisää uutinen + label_news_plural: Uutiset + label_news_latest: Viimeisimmät uutiset + label_news_view_all: Näytä kaikki uutiset + label_settings: Asetukset + label_overview: Yleiskatsaus + label_version: Versio + label_version_new: Uusi versio + label_version_plural: Versiot + label_confirmation: Vahvistus + label_export_to: Vie + label_read: Lukee... + label_public_projects: Julkiset projektit + label_open_issues: avoin, yhteensä + label_open_issues_plural: avointa, yhteensä + label_closed_issues: suljettu + label_closed_issues_plural: suljettua + label_x_open_issues_abbr_on_total: + zero: 0 open / %{total} + one: 1 open / %{total} + other: "%{count} open / %{total}" + label_x_open_issues_abbr: + zero: 0 open + one: 1 open + other: "%{count} open" + label_x_closed_issues_abbr: + zero: 0 closed + one: 1 closed + other: "%{count} closed" + label_total: Yhteensä + label_permissions: Oikeudet + label_current_status: Nykyinen tila + label_new_statuses_allowed: Uudet tilat sallittu + label_all: kaikki + label_none: ei mitään + label_nobody: ei kukaan + label_next: Seuraava + label_previous: Edellinen + label_used_by: Käytetty + label_details: Yksityiskohdat + label_add_note: Lisää muistiinpano + label_per_page: Per sivu + label_calendar: Kalenteri + label_months_from: kuukauden päässä + label_gantt: Gantt + label_internal: Sisäinen + label_last_changes: "viimeiset %{count} muutokset" + label_change_view_all: Näytä kaikki muutokset + label_personalize_page: Personoi tämä sivu + label_comment: Kommentti + label_comment_plural: Kommentit + label_x_comments: + zero: no comments + one: 1 comment + other: "%{count} comments" + label_comment_add: Lisää kommentti + label_comment_added: Kommentti lisätty + label_comment_delete: Poista kommentti + label_query: Räätälöity haku + label_query_plural: Räätälöidyt haut + label_query_new: Uusi haku + label_filter_add: Lisää suodatin + label_filter_plural: Suodattimet + label_equals: sama kuin + label_not_equals: eri kuin + label_in_less_than: pienempi kuin + label_in_more_than: suurempi kuin + label_today: tänään + label_this_week: tällä viikolla + label_less_than_ago: vähemmän kuin päivää sitten + label_more_than_ago: enemän kuin päivää sitten + label_ago: päiviä sitten + label_contains: sisältää + label_not_contains: ei sisällä + label_day_plural: päivää + label_repository: Tietovarasto + label_repository_plural: Tietovarastot + label_browse: Selaus + label_revision: Versio + label_revision_plural: Versiot + label_added: lisätty + label_modified: muokattu + label_deleted: poistettu + label_latest_revision: Viimeisin versio + label_latest_revision_plural: Viimeisimmät versiot + label_view_revisions: Näytä versiot + label_max_size: Suurin koko + label_sort_highest: Siirrä ylimmäiseksi + label_sort_higher: Siirrä ylös + label_sort_lower: Siirrä alas + label_sort_lowest: Siirrä alimmaiseksi + label_roadmap: Roadmap + label_roadmap_due_in: "Määräaika %{value}" + label_roadmap_overdue: "%{value} myöhässä" + label_roadmap_no_issues: Ei tapahtumia tälle versiolle + label_search: Haku + label_result_plural: Tulokset + label_all_words: kaikki sanat + label_wiki: Wiki + label_wiki_edit: Wiki muokkaus + label_wiki_edit_plural: Wiki muokkaukset + label_wiki_page: Wiki sivu + label_wiki_page_plural: Wiki sivut + label_index_by_title: Hakemisto otsikoittain + label_index_by_date: Hakemisto päivittäin + label_current_version: Nykyinen versio + label_preview: Esikatselu + label_feed_plural: Syötteet + label_changes_details: Kaikkien muutosten yksityiskohdat + label_issue_tracking: Tapahtumien seuranta + label_spent_time: Käytetty aika + label_f_hour: "%{value} tunti" + label_f_hour_plural: "%{value} tuntia" + label_time_tracking: Ajan seuranta + label_change_plural: Muutokset + label_statistics: Tilastot + label_commits_per_month: Tapahtumaa per kuukausi + label_commits_per_author: Tapahtumaa per tekijä + label_view_diff: Näytä erot + label_diff_inline: sisällössä + label_diff_side_by_side: vierekkäin + label_options: Valinnat + label_copy_workflow_from: Kopioi työnkulku + label_permissions_report: Oikeuksien raportti + label_watched_issues: Seurattavat tapahtumat + label_related_issues: Liittyvät tapahtumat + label_applied_status: Lisätty tila + label_loading: Lataa... + label_relation_new: Uusi suhde + label_relation_delete: Poista suhde + label_relates_to: liittyy + label_duplicates: kopio + label_blocks: estää + label_blocked_by: estetty + label_precedes: edeltää + label_follows: seuraa + label_end_to_start: lopusta alkuun + label_end_to_end: lopusta loppuun + label_start_to_start: alusta alkuun + label_start_to_end: alusta loppuun + label_stay_logged_in: Pysy kirjautuneena + label_disabled: poistettu käytöstä + label_show_completed_versions: Näytä valmiit versiot + label_me: minä + label_board: Keskustelupalsta + label_board_new: Uusi keskustelupalsta + label_board_plural: Keskustelupalstat + label_topic_plural: Aiheet + label_message_plural: Viestit + label_message_last: Viimeisin viesti + label_message_new: Uusi viesti + label_reply_plural: Vastaukset + label_send_information: Lähetä tilin tiedot käyttäjälle + label_year: Vuosi + label_month: Kuukausi + label_week: Viikko + label_language_based: Pohjautuen käyttäjän kieleen + label_sort_by: "Lajittele %{value}" + label_send_test_email: Lähetä testi sähköposti + label_feeds_access_key_created_on: "RSS salasana luotiin %{value} sitten" + label_module_plural: Moduulit + label_added_time_by: "Lisännyt %{author} %{age} sitten" + label_updated_time: "Päivitetty %{value} sitten" + label_jump_to_a_project: Siirry projektiin... + label_file_plural: Tiedostot + label_changeset_plural: Muutosryhmät + label_default_columns: Vakiosarakkeet + label_no_change_option: (Ei muutosta) + label_bulk_edit_selected_issues: Perusmuotoile valitut tapahtumat + label_theme: Teema + label_default: Vakio + label_search_titles_only: Hae vain otsikot + label_user_mail_option_all: "Kaikista tapahtumista kaikissa projekteistani" + label_user_mail_option_selected: "Kaikista tapahtumista vain valitsemistani projekteista..." + label_user_mail_no_self_notified: "En halua muistutusta muutoksista joita itse teen" + label_registration_activation_by_email: tilin aktivointi sähköpostitse + label_registration_manual_activation: tilin aktivointi käsin + label_registration_automatic_activation: tilin aktivointi automaattisesti + label_display_per_page: "Per sivu: %{value}" + label_age: Ikä + label_change_properties: Vaihda asetuksia + label_general: Yleinen + + button_login: Kirjaudu + button_submit: Lähetä + button_save: Tallenna + button_check_all: Valitse kaikki + button_uncheck_all: Poista valinnat + button_delete: Poista + button_create: Luo + button_test: Testaa + button_edit: Muokkaa + button_add: Lisää + button_change: Muuta + button_apply: Ota käyttöön + button_clear: Tyhjää + button_lock: Lukitse + button_unlock: Vapauta + button_download: Lataa + button_list: Lista + button_view: Näytä + button_move: Siirrä + button_back: Takaisin + button_cancel: Peruuta + button_activate: Aktivoi + button_sort: Järjestä + button_log_time: Seuraa aikaa + button_rollback: Siirry takaisin tähän versioon + button_watch: Seuraa + button_unwatch: Älä seuraa + button_reply: Vastaa + button_archive: Arkistoi + button_unarchive: Palauta + button_reset: Nollaus + button_rename: Uudelleen nimeä + button_change_password: Vaihda salasana + button_copy: Kopioi + button_annotate: Lisää selitys + button_update: Päivitä + + status_active: aktiivinen + status_registered: rekisteröity + status_locked: lukittu + + text_select_mail_notifications: Valitse tapahtumat joista tulisi lähettää sähköpostimuistutus. + text_regexp_info: esim. ^[A-Z0-9]+$ + text_min_max_length_info: 0 tarkoittaa, ei rajoitusta + text_project_destroy_confirmation: Oletko varma että haluat poistaa tämän projektin ja kaikki siihen kuuluvat tiedot? + text_workflow_edit: Valitse rooli ja tapahtuma muokataksesi työnkulkua + text_are_you_sure: Oletko varma? + text_tip_issue_begin_day: tehtävä joka alkaa tänä päivänä + text_tip_issue_end_day: tehtävä joka loppuu tänä päivänä + text_tip_issue_begin_end_day: tehtävä joka alkaa ja loppuu tänä päivänä + text_caracters_maximum: "%{count} merkkiä enintään." + text_caracters_minimum: "Täytyy olla vähintään %{count} merkkiä pitkä." + text_length_between: "Pituus välillä %{min} ja %{max} merkkiä." + text_tracker_no_workflow: Työnkulkua ei määritelty tälle tapahtumalle + text_unallowed_characters: Kiellettyjä merkkejä + text_comma_separated: Useat arvot sallittu (pilkku eroteltuna). + text_issues_ref_in_commit_messages: Liitän ja korjaan ongelmia syötetyssä viestissä + text_issue_added: "Issue %{id} has been reported by %{author}." + text_issue_updated: "Issue %{id} has been updated by %{author}." + text_wiki_destroy_confirmation: Oletko varma että haluat poistaa tämän wiki:n ja kaikki sen sisältämän tiedon? + text_issue_category_destroy_question: "Jotkut tapahtumat (%{count}) ovat nimetty tälle luokalle. Mitä haluat tehdä?" + text_issue_category_destroy_assignments: Poista luokan tehtävät + text_issue_category_reassign_to: Vaihda tapahtuma tähän luokkaan + text_user_mail_option: "Valitsemattomille projekteille, saat vain muistutuksen asioista joita seuraat tai olet mukana (esim. tapahtumat joissa olet tekijä tai nimettynä)." + text_no_configuration_data: "Rooleja, tapahtumien tiloja ja työnkulkua ei vielä olla määritelty.\nOn erittäin suotavaa ladata vakioasetukset. Voit muuttaa sitä latauksen jälkeen." + text_load_default_configuration: Lataa vakioasetukset + + default_role_manager: Päälikkö + default_role_developer: Kehittäjä + default_role_reporter: Tarkastelija + default_tracker_bug: Ohjelmointivirhe + default_tracker_feature: Ominaisuus + default_tracker_support: Tuki + default_issue_status_new: Uusi + default_issue_status_in_progress: In Progress + default_issue_status_resolved: Hyväksytty + default_issue_status_feedback: Palaute + default_issue_status_closed: Suljettu + default_issue_status_rejected: Hylätty + default_doc_category_user: Käyttäjä dokumentaatio + default_doc_category_tech: Tekninen dokumentaatio + default_priority_low: Matala + default_priority_normal: Normaali + default_priority_high: Korkea + default_priority_urgent: Kiireellinen + default_priority_immediate: Valitön + default_activity_design: Suunnittelu + default_activity_development: Kehitys + + enumeration_issue_priorities: Tapahtuman tärkeysjärjestys + enumeration_doc_categories: Dokumentin luokat + enumeration_activities: Historia (ajan seuranta) + label_associated_revisions: Liittyvät versiot + setting_user_format: Käyttäjien esitysmuoto + text_status_changed_by_changeset: "Päivitetty muutosversioon %{value}." + text_issues_destroy_confirmation: 'Oletko varma että haluat poistaa valitut tapahtumat ?' + label_more: Lisää + label_issue_added: Tapahtuma lisätty + label_issue_updated: Tapahtuma päivitetty + label_document_added: Dokumentti lisätty + label_message_posted: Viesti lisätty + label_file_added: Tiedosto lisätty + label_scm: SCM + text_select_project_modules: 'Valitse modulit jotka haluat käyttöön tähän projektiin:' + label_news_added: Uutinen lisätty + project_module_boards: Keskustelupalsta + project_module_issue_tracking: Tapahtuman seuranta + project_module_wiki: Wiki + project_module_files: Tiedostot + project_module_documents: Dokumentit + project_module_repository: Tietovarasto + project_module_news: Uutiset + project_module_time_tracking: Ajan seuranta + text_file_repository_writable: Kirjoitettava tiedostovarasto + text_default_administrator_account_changed: Vakio hallinoijan tunnus muutettu + text_rmagick_available: RMagick saatavilla (valinnainen) + button_configure: Asetukset + label_plugins: Lisäosat + label_ldap_authentication: LDAP tunnistautuminen + label_downloads_abbr: D/L + label_add_another_file: Lisää uusi tiedosto + label_this_month: tässä kuussa + text_destroy_time_entries_question: "%{hours} tuntia on raportoitu tapahtumasta jonka aiot poistaa. Mitä haluat tehdä ?" + label_last_n_days: "viimeiset %{count} päivää" + label_all_time: koko ajalta + error_issue_not_found_in_project: 'Tapahtumaa ei löytynyt tai se ei kuulu tähän projektiin' + label_this_year: tänä vuonna + text_assign_time_entries_to_project: Määritä tunnit projektille + label_date_range: Aikaväli + label_last_week: viime viikolla + label_yesterday: eilen + label_optional_description: Lisäkuvaus + label_last_month: viime kuussa + text_destroy_time_entries: Poista raportoidut tunnit + text_reassign_time_entries: 'Siirrä raportoidut tunnit tälle tapahtumalle:' + label_chronological_order: Aikajärjestyksessä + label_date_to: '' + setting_activity_days_default: Päivien esittäminen projektien historiassa + label_date_from: '' + label_in: '' + setting_display_subprojects_issues: Näytä aliprojektien tapahtumat pääprojektissa oletusarvoisesti + field_comments_sorting: Näytä kommentit + label_reverse_chronological_order: Käänteisessä aikajärjestyksessä + label_preferences: Asetukset + setting_default_projects_public: Uudet projektit ovat oletuksena julkisia + label_overall_activity: Kokonaishistoria + error_scm_annotate: "Merkintää ei ole tai siihen ei voi lisätä selityksiä." + label_planning: Suunnittelu + text_subprojects_destroy_warning: "Tämän aliprojekti(t): %{value} tullaan myös poistamaan." + label_and_its_subprojects: "%{value} ja aliprojektit" + mail_body_reminder: "%{count} sinulle nimettyä tapahtuma(a) erääntyy %{days} päivä sisään:" + mail_subject_reminder: "%{count} tapahtuma(a) erääntyy %{days} lähipäivinä" + text_user_wrote: "%{value} kirjoitti:" + label_duplicated_by: kopioinut + setting_enabled_scm: Versionhallinta käytettävissä + text_enumeration_category_reassign_to: 'Siirrä täksi arvoksi:' + text_enumeration_destroy_question: "%{count} kohdetta on sijoitettu tälle arvolle." + label_incoming_emails: Saapuvat sähköpostiviestit + label_generate_key: Luo avain + setting_mail_handler_api_enabled: Ota käyttöön WS saapuville sähköposteille + setting_mail_handler_api_key: API avain + text_email_delivery_not_configured: "Sähköpostin jakelu ei ole määritelty ja sähköpostimuistutukset eivät ole käytössä.\nKonfiguroi sähköpostipalvelinasetukset (SMTP) config/configuration.yml tiedostosta ja uudelleenkäynnistä sovellus jotta asetukset astuvat voimaan." + field_parent_title: Aloitussivu + label_issue_watchers: Tapahtuman seuraajat + button_quote: Vastaa + setting_sequential_project_identifiers: Luo peräkkäiset projektien tunnisteet + notice_unable_delete_version: Version poisto epäonnistui + label_renamed: uudelleennimetty + label_copied: kopioitu + setting_plain_text_mail: vain muotoilematonta tekstiä (ei HTML) + permission_view_files: Näytä tiedostot + permission_edit_issues: Muokkaa tapahtumia + permission_edit_own_time_entries: Muokka omia aikamerkintöjä + permission_manage_public_queries: Hallinnoi julkisia hakuja + permission_add_issues: Lisää tapahtumia + permission_log_time: Lokita käytettyä aikaa + permission_view_changesets: Näytä muutosryhmät + permission_view_time_entries: Näytä käytetty aika + permission_manage_versions: Hallinnoi versioita + permission_manage_wiki: Hallinnoi wikiä + permission_manage_categories: Hallinnoi tapahtumien luokkia + permission_protect_wiki_pages: Suojaa wiki sivut + permission_comment_news: Kommentoi uutisia + permission_delete_messages: Poista viestit + permission_select_project_modules: Valitse projektin modulit + permission_edit_wiki_pages: Muokkaa wiki sivuja + permission_add_issue_watchers: Lisää seuraajia + permission_view_gantt: Näytä gantt kaavio + permission_move_issues: Siirrä tapahtuma + permission_manage_issue_relations: Hallinoi tapahtuman suhteita + permission_delete_wiki_pages: Poista wiki sivuja + permission_manage_boards: Hallinnoi keskustelupalstaa + permission_delete_wiki_pages_attachments: Poista liitteitä + permission_view_wiki_edits: Näytä wiki historia + permission_add_messages: Jätä viesti + permission_view_messages: Näytä viestejä + permission_manage_files: Hallinnoi tiedostoja + permission_edit_issue_notes: Muokkaa muistiinpanoja + permission_manage_news: Hallinnoi uutisia + permission_view_calendar: Näytä kalenteri + permission_manage_members: Hallinnoi jäseniä + permission_edit_messages: Muokkaa viestejä + permission_delete_issues: Poista tapahtumia + permission_view_issue_watchers: Näytä seuraaja lista + permission_manage_repository: Hallinnoi tietovarastoa + permission_commit_access: Tee pääsyoikeus + permission_browse_repository: Selaa tietovarastoa + permission_view_documents: Näytä dokumentit + permission_edit_project: Muokkaa projektia + permission_add_issue_notes: Lisää muistiinpanoja + permission_save_queries: Tallenna hakuja + permission_view_wiki_pages: Näytä wiki + permission_rename_wiki_pages: Uudelleennimeä wiki sivuja + permission_edit_time_entries: Muokkaa aika lokeja + permission_edit_own_issue_notes: Muokkaa omia muistiinpanoja + setting_gravatar_enabled: Käytä Gravatar käyttäjä ikoneita + label_example: Esimerkki + text_repository_usernames_mapping: "Valitse päivittääksesi Redmine käyttäjä jokaiseen käyttäjään joka löytyy tietovaraston lokista.\nKäyttäjät joilla on sama Redmine ja tietovaraston käyttäjänimi tai sähköpostiosoite, yhdistetään automaattisesti." + permission_edit_own_messages: Muokkaa omia viestejä + permission_delete_own_messages: Poista omia viestejä + label_user_activity: "Käyttäjän %{value} historia" + label_updated_time_by: "Updated by %{author} %{age} ago" + text_diff_truncated: '... This diff was truncated because it exceeds the maximum size that can be displayed.' + setting_diff_max_lines_displayed: Max number of diff lines displayed + text_plugin_assets_writable: Plugin assets directory writable + warning_attachments_not_saved: "%{count} file(s) could not be saved." + button_create_and_continue: Create and continue + text_custom_field_possible_values_info: 'One line for each value' + label_display: Display + field_editable: Editable + setting_repository_log_display_limit: Maximum number of revisions displayed on file log + setting_file_max_size_displayed: Max size of text files displayed inline + field_watcher: Watcher + setting_openid: Allow OpenID login and registration + field_identity_url: OpenID URL + label_login_with_open_id_option: or login with OpenID + field_content: Content + label_descending: Descending + label_sort: Sort + label_ascending: Ascending + label_date_from_to: From %{start} to %{end} + label_greater_or_equal: ">=" + label_less_or_equal: <= + text_wiki_page_destroy_question: This page has %{descendants} child page(s) and descendant(s). What do you want to do? + text_wiki_page_reassign_children: Reassign child pages to this parent page + text_wiki_page_nullify_children: Keep child pages as root pages + text_wiki_page_destroy_children: Delete child pages and all their descendants + setting_password_min_length: Minimum password length + field_group_by: Group results by + mail_subject_wiki_content_updated: "'%{id}' wiki page has been updated" + label_wiki_content_added: Wiki page added + mail_subject_wiki_content_added: "'%{id}' wiki page has been added" + mail_body_wiki_content_added: The '%{id}' wiki page has been added by %{author}. + label_wiki_content_updated: Wiki page updated + mail_body_wiki_content_updated: The '%{id}' wiki page has been updated by %{author}. + permission_add_project: Create project + setting_new_project_user_role_id: Role given to a non-admin user who creates a project + label_view_all_revisions: View all revisions + label_tag: Tag + label_branch: Branch + error_no_tracker_in_project: No tracker is associated to this project. Please check the Project settings. + error_no_default_issue_status: No default issue status is defined. Please check your configuration (Go to "Administration -> Issue statuses"). + text_journal_changed: "%{label} changed from %{old} to %{new}" + text_journal_set_to: "%{label} set to %{value}" + text_journal_deleted: "%{label} deleted (%{old})" + label_group_plural: Groups + label_group: Group + label_group_new: New group + label_time_entry_plural: Spent time + text_journal_added: "%{label} %{value} added" + field_active: Active + enumeration_system_activity: System Activity + permission_delete_issue_watchers: Delete watchers + version_status_closed: closed + version_status_locked: locked + version_status_open: open + error_can_not_reopen_issue_on_closed_version: An issue assigned to a closed version can not be reopened + label_user_anonymous: Anonymous + button_move_and_follow: Move and follow + setting_default_projects_modules: Default enabled modules for new projects + setting_gravatar_default: Default Gravatar image + field_sharing: Sharing + label_version_sharing_hierarchy: With project hierarchy + label_version_sharing_system: With all projects + label_version_sharing_descendants: With subprojects + label_version_sharing_tree: With project tree + label_version_sharing_none: Not shared + error_can_not_archive_project: This project can not be archived + button_duplicate: Duplicate + button_copy_and_follow: Copy and follow + label_copy_source: Source + setting_issue_done_ratio: Calculate the issue done ratio with + setting_issue_done_ratio_issue_status: Use the issue status + error_issue_done_ratios_not_updated: Issue done ratios not updated. + error_workflow_copy_target: Please select target tracker(s) and role(s) + setting_issue_done_ratio_issue_field: Use the issue field + label_copy_same_as_target: Same as target + label_copy_target: Target + notice_issue_done_ratios_updated: Issue done ratios updated. + error_workflow_copy_source: Please select a source tracker or role + label_update_issue_done_ratios: Update issue done ratios + setting_start_of_week: Start calendars on + permission_view_issues: View Issues + label_display_used_statuses_only: Only display statuses that are used by this tracker + label_revision_id: Revision %{value} + label_api_access_key: API access key + label_api_access_key_created_on: API access key created %{value} ago + label_feeds_access_key: RSS access key + notice_api_access_key_reseted: Your API access key was reset. + setting_rest_api_enabled: Enable REST web service + label_missing_api_access_key: Missing an API access key + label_missing_feeds_access_key: Missing a RSS access key + button_show: Show + text_line_separated: Multiple values allowed (one line for each value). + setting_mail_handler_body_delimiters: Truncate emails after one of these lines + permission_add_subprojects: Create subprojects + label_subproject_new: New subproject + text_own_membership_delete_confirmation: |- + You are about to remove some or all of your permissions and may no longer be able to edit this project after that. + Are you sure you want to continue? + label_close_versions: Close completed versions + label_board_sticky: Sticky + label_board_locked: Locked + permission_export_wiki_pages: Export wiki pages + setting_cache_formatted_text: Cache formatted text + permission_manage_project_activities: Manage project activities + error_unable_delete_issue_status: Unable to delete issue status + label_profile: Profile + permission_manage_subtasks: Manage subtasks + field_parent_issue: Parent task + label_subtask_plural: Subtasks + label_project_copy_notifications: Send email notifications during the project copy + error_can_not_delete_custom_field: Unable to delete custom field + error_unable_to_connect: Unable to connect (%{value}) + error_can_not_remove_role: This role is in use and can not be deleted. + error_can_not_delete_tracker: This tracker contains issues and can't be deleted. + field_principal: Principal + label_my_page_block: My page block + notice_failed_to_save_members: "Failed to save member(s): %{errors}." + text_zoom_out: Zoom out + text_zoom_in: Zoom in + notice_unable_delete_time_entry: Unable to delete time log entry. + label_overall_spent_time: Overall spent time + field_time_entries: Log time + project_module_gantt: Gantt + project_module_calendar: Calendar + button_edit_associated_wikipage: "Edit associated Wiki page: %{page_title}" + field_text: Text field + label_user_mail_option_only_owner: Only for things I am the owner of + setting_default_notification_option: Default notification option + label_user_mail_option_only_my_events: Only for things I watch or I'm involved in + label_user_mail_option_only_assigned: Only for things I am assigned to + label_user_mail_option_none: No events + field_member_of_group: Assignee's group + field_assigned_to_role: Assignee's role + notice_not_authorized_archived_project: The project you're trying to access has been archived. + label_principal_search: "Search for user or group:" + label_user_search: "Search for user:" + field_visible: Visible + setting_commit_logtime_activity_id: Activity for logged time + text_time_logged_by_changeset: Applied in changeset %{value}. + setting_commit_logtime_enabled: Enable time logging + notice_gantt_chart_truncated: The chart was truncated because it exceeds the maximum number of items that can be displayed (%{max}) + setting_gantt_items_limit: Maximum number of items displayed on the gantt chart + field_warn_on_leaving_unsaved: Warn me when leaving a page with unsaved text + text_warn_on_leaving_unsaved: The current page contains unsaved text that will be lost if you leave this page. + label_my_queries: My custom queries + text_journal_changed_no_detail: "%{label} updated" + label_news_comment_added: Comment added to a news + button_expand_all: Expand all + button_collapse_all: Collapse all + label_additional_workflow_transitions_for_assignee: Additional transitions allowed when the user is the assignee + label_additional_workflow_transitions_for_author: Additional transitions allowed when the user is the author + label_bulk_edit_selected_time_entries: Bulk edit selected time entries + text_time_entries_destroy_confirmation: Are you sure you want to delete the selected time entr(y/ies)? + label_role_anonymous: Anonymous + label_role_non_member: Non member + label_issue_note_added: Note added + label_issue_status_updated: Status updated + label_issue_priority_updated: Priority updated + label_issues_visibility_own: Issues created by or assigned to the user + field_issues_visibility: Issues visibility + label_issues_visibility_all: All issues + permission_set_own_issues_private: Set own issues public or private + field_is_private: Private + permission_set_issues_private: Set issues public or private + label_issues_visibility_public: All non private issues + text_issues_destroy_descendants_confirmation: This will also delete %{count} subtask(s). + field_commit_logs_encoding: Tee viestien koodaus + field_scm_path_encoding: Path encoding + text_scm_path_encoding_note: "Default: UTF-8" + field_path_to_repository: Path to repository + field_root_directory: Root directory + field_cvs_module: Module + field_cvsroot: CVSROOT + text_mercurial_repository_note: Local repository (e.g. /hgrepo, c:\hgrepo) + text_scm_command: Command + text_scm_command_version: Version + label_git_report_last_commit: Report last commit for files and directories + notice_issue_successful_create: Issue %{id} created. + label_between: between + setting_issue_group_assignment: Allow issue assignment to groups + label_diff: diff + text_git_repository_note: Repository is bare and local (e.g. /gitrepo, c:\gitrepo) + description_query_sort_criteria_direction: Sort direction + description_project_scope: Search scope + description_filter: Filter + description_user_mail_notification: Mail notification settings + description_date_from: Enter start date + description_message_content: Message content + description_available_columns: Available Columns + description_date_range_interval: Choose range by selecting start and end date + description_issue_category_reassign: Choose issue category + description_search: Searchfield + description_notes: Notes + description_date_range_list: Choose range from list + description_choose_project: Projects + description_date_to: Enter end date + description_query_sort_criteria_attribute: Sort attribute + description_wiki_subpages_reassign: Choose new parent page + description_selected_columns: Selected Columns + label_parent_revision: Parent + label_child_revision: Child + error_scm_annotate_big_text_file: The entry cannot be annotated, as it exceeds the maximum text file size. + setting_default_issue_start_date_to_creation_date: Use current date as start date for new issues + button_edit_section: Edit this section + setting_repositories_encodings: Attachments and repositories encodings + description_all_columns: All Columns + button_export: Export + label_export_options: "%{export_format} export options" + error_attachment_too_big: This file cannot be uploaded because it exceeds the maximum allowed file size (%{max_size}) + notice_failed_to_save_time_entries: "Failed to save %{count} time entrie(s) on %{total} selected: %{ids}." + label_x_issues: + zero: 0 tapahtuma + one: 1 tapahtuma + other: "%{count} tapahtumat" + label_repository_new: New repository + field_repository_is_default: Main repository + label_copy_attachments: Copy attachments + label_item_position: "%{position}/%{count}" + label_completed_versions: Completed versions + text_project_identifier_info: Only lower case letters (a-z), numbers, dashes and underscores are allowed.
    Once saved, the identifier cannot be changed. + field_multiple: Multiple values + setting_commit_cross_project_ref: Allow issues of all the other projects to be referenced and fixed + text_issue_conflict_resolution_add_notes: Add my notes and discard my other changes + text_issue_conflict_resolution_overwrite: Apply my changes anyway (previous notes will be kept but some changes may be overwritten) + notice_issue_update_conflict: The issue has been updated by an other user while you were editing it. + text_issue_conflict_resolution_cancel: Discard all my changes and redisplay %{link} + permission_manage_related_issues: Manage related issues + field_auth_source_ldap_filter: LDAP filter + label_search_for_watchers: Search for watchers to add + notice_account_deleted: Your account has been permanently deleted. + setting_unsubscribe: Allow users to delete their own account + button_delete_my_account: Delete my account + text_account_destroy_confirmation: |- + Are you sure you want to proceed? + Your account will be permanently deleted, with no way to reactivate it. + error_session_expired: Your session has expired. Please login again. + text_session_expiration_settings: "Warning: changing these settings may expire the current sessions including yours." + setting_session_lifetime: Session maximum lifetime + setting_session_timeout: Session inactivity timeout + label_session_expiration: Session expiration + permission_close_project: Close / reopen the project + label_show_closed_projects: View closed projects + button_close: Close + button_reopen: Reopen + project_status_active: active + project_status_closed: closed + project_status_archived: archived + text_project_closed: This project is closed and read-only. + notice_user_successful_create: User %{id} created. + field_core_fields: Standard fields + field_timeout: Timeout (in seconds) + setting_thumbnails_enabled: Display attachment thumbnails + setting_thumbnails_size: Thumbnails size (in pixels) + label_status_transitions: Status transitions + label_fields_permissions: Fields permissions + label_readonly: Read-only + label_required: Required + text_repository_identifier_info: Only lower case letters (a-z), numbers, dashes and underscores are allowed.
    Once saved, the identifier cannot be changed. + field_board_parent: Parent forum + label_attribute_of_project: Project's %{name} + label_attribute_of_author: Author's %{name} + label_attribute_of_assigned_to: Assignee's %{name} + label_attribute_of_fixed_version: Target version's %{name} + label_copy_subtasks: Copy subtasks + label_copied_to: copied to + label_copied_from: copied from + label_any_issues_in_project: any issues in project + label_any_issues_not_in_project: any issues not in project + field_private_notes: Private notes + permission_view_private_notes: View private notes + permission_set_notes_private: Set notes as private + label_no_issues_in_project: no issues in project + label_any: kaikki + label_last_n_weeks: last %{count} weeks + setting_cross_project_subtasks: Allow cross-project subtasks + label_cross_project_descendants: With subprojects + label_cross_project_tree: With project tree + label_cross_project_hierarchy: With project hierarchy + label_cross_project_system: With all projects + button_hide: Hide + setting_non_working_week_days: Non-working days + label_in_the_next_days: in the next + label_in_the_past_days: in the past + label_attribute_of_user: User's %{name} + text_turning_multiple_off: If you disable multiple values, multiple values will be + removed in order to preserve only one value per item. + label_attribute_of_issue: Issue's %{name} + permission_add_documents: Add documents + permission_edit_documents: Edit documents + permission_delete_documents: Delete documents + label_gantt_progress_line: Progress line + setting_jsonp_enabled: Enable JSONP support + field_inherit_members: Inherit members + field_closed_on: Closed + setting_default_projects_tracker_ids: Default trackers for new projects + label_total_time: Yhteensä + text_scm_config: You can configure your SCM commands in config/configuration.yml. Please restart the application after editing it. + text_scm_command_not_available: SCM command is not available. Please check settings on the administration panel. + setting_emails_header: Email header diff --git a/config/locales/fr.yml b/config/locales/fr.yml new file mode 100644 index 00000000..dcd8cf15 --- /dev/null +++ b/config/locales/fr.yml @@ -0,0 +1,1102 @@ +# French translations for Ruby on Rails +# by Christian Lescuyer (christian@flyingcoders.com) +# contributor: Sebastien Grosjean - ZenCocoon.com +# contributor: Thibaut Cuvelier - Developpez.com + +fr: + direction: ltr + date: + formats: + default: "%d/%m/%Y" + short: "%e %b" + long: "%e %B %Y" + long_ordinal: "%e %B %Y" + only_day: "%e" + + day_names: [dimanche, lundi, mardi, mercredi, jeudi, vendredi, samedi] + abbr_day_names: [dim, lun, mar, mer, jeu, ven, sam] + month_names: [~, janvier, février, mars, avril, mai, juin, juillet, août, septembre, octobre, novembre, décembre] + abbr_month_names: [~, jan., fév., mar., avr., mai, juin, juil., août, sept., oct., nov., déc.] + order: + - :day + - :month + - :year + + time: + formats: + default: "%d/%m/%Y %H:%M" + time: "%H:%M" + short: "%d %b %H:%M" + long: "%A %d %B %Y %H:%M:%S %Z" + long_ordinal: "%A %d %B %Y %H:%M:%S %Z" + only_second: "%S" + am: 'am' + pm: 'pm' + + datetime: + distance_in_words: + half_a_minute: "30 secondes" + less_than_x_seconds: + zero: "moins d'une seconde" + one: "moins d'une seconde" + other: "moins de %{count} secondes" + x_seconds: + one: "1 seconde" + other: "%{count} secondes" + less_than_x_minutes: + zero: "moins d'une minute" + one: "moins d'une minute" + other: "moins de %{count} minutes" + x_minutes: + one: "1 minute" + other: "%{count} minutes" + about_x_hours: + one: "environ une heure" + other: "environ %{count} heures" + x_hours: + one: "une heure" + other: "%{count} heures" + x_days: + one: "un jour" + other: "%{count} jours" + about_x_months: + one: "environ un mois" + other: "environ %{count} mois" + x_months: + one: "un mois" + other: "%{count} mois" + about_x_years: + one: "environ un an" + other: "environ %{count} ans" + over_x_years: + one: "plus d'un an" + other: "plus de %{count} ans" + almost_x_years: + one: "presqu'un an" + other: "presque %{count} ans" + prompts: + year: "Année" + month: "Mois" + day: "Jour" + hour: "Heure" + minute: "Minute" + second: "Seconde" + + number: + format: + precision: 3 + separator: ',' + delimiter: ' ' + currency: + format: + unit: '€' + precision: 2 + format: '%n %u' + human: + format: + precision: 3 + storage_units: + format: "%n %u" + units: + byte: + one: "octet" + other: "octet" + kb: "ko" + mb: "Mo" + gb: "Go" + tb: "To" + + support: + array: + sentence_connector: 'et' + skip_last_comma: true + word_connector: ", " + two_words_connector: " et " + last_word_connector: " et " + + activerecord: + errors: + template: + header: + one: "Impossible d'enregistrer %{model} : une erreur" + other: "Impossible d'enregistrer %{model} : %{count} erreurs." + body: "Veuillez vérifier les champs suivants :" + messages: + inclusion: "n'est pas inclus(e) dans la liste" + exclusion: "n'est pas disponible" + invalid: "n'est pas valide" + confirmation: "ne concorde pas avec la confirmation" + accepted: "doit être accepté(e)" + empty: "doit être renseigné(e)" + blank: "doit être renseigné(e)" + too_long: "est trop long (pas plus de %{count} caractères)" + too_short: "est trop court (au moins %{count} caractères)" + wrong_length: "ne fait pas la bonne longueur (doit comporter %{count} caractères)" + taken: "est déjà utilisé" + not_a_number: "n'est pas un nombre" + not_a_date: "n'est pas une date valide" + greater_than: "doit être supérieur à %{count}" + greater_than_or_equal_to: "doit être supérieur ou égal à %{count}" + equal_to: "doit être égal à %{count}" + less_than: "doit être inférieur à %{count}" + less_than_or_equal_to: "doit être inférieur ou égal à %{count}" + odd: "doit être impair" + even: "doit être pair" + greater_than_start_date: "doit être postérieure à la date de début" + not_same_project: "n'appartient pas au même projet" + circular_dependency: "Cette relation créerait une dépendance circulaire" + cant_link_an_issue_with_a_descendant: "Une demande ne peut pas être liée à l'une de ses sous-tâches" + + actionview_instancetag_blank_option: Choisir + + general_text_No: 'Non' + general_text_Yes: 'Oui' + general_text_no: 'non' + general_text_yes: 'oui' + general_lang_name: 'Français' + general_csv_separator: ';' + general_csv_decimal_separator: ',' + general_csv_encoding: ISO-8859-1 + general_pdf_encoding: UTF-8 + general_first_day_of_week: '1' + + notice_account_updated: Le compte a été mis à jour avec succès. + notice_account_invalid_creditentials: Identifiant ou mot de passe invalide. + notice_account_password_updated: Mot de passe mis à jour avec succès. + notice_account_wrong_password: Mot de passe incorrect + notice_account_register_done: Un message contenant les instructions pour activer votre compte vous a été envoyé. + notice_account_unknown_email: Aucun compte ne correspond à cette adresse. + notice_can_t_change_password: Ce compte utilise une authentification externe. Impossible de changer le mot de passe. + notice_account_lost_email_sent: Un message contenant les instructions pour choisir un nouveau mot de passe vous a été envoyé. + notice_account_activated: Votre compte a été activé. Vous pouvez à présent vous connecter. + notice_successful_create: Création effectuée avec succès. + notice_successful_update: Mise à jour effectuée avec succès. + notice_successful_delete: Suppression effectuée avec succès. + notice_successful_connection: Connexion réussie. + notice_file_not_found: "La page à laquelle vous souhaitez accéder n'existe pas ou a été supprimée." + notice_locking_conflict: Les données ont été mises à jour par un autre utilisateur. Mise à jour impossible. + notice_not_authorized: "Vous n'êtes pas autorisé à accéder à cette page." + notice_not_authorized_archived_project: Le projet auquel vous tentez d'accéder a été archivé. + notice_email_sent: "Un email a été envoyé à %{value}" + notice_email_error: "Erreur lors de l'envoi de l'email (%{value})" + notice_feeds_access_key_reseted: "Votre clé d'accès aux flux RSS a été réinitialisée." + notice_failed_to_save_issues: "%{count} demande(s) sur les %{total} sélectionnées n'ont pas pu être mise(s) à jour : %{ids}." + notice_failed_to_save_time_entries: "%{count} temps passé(s) sur les %{total} sélectionnés n'ont pas pu être mis à jour: %{ids}." + notice_no_issue_selected: "Aucune demande sélectionnée ! Cochez les demandes que vous voulez mettre à jour." + notice_account_pending: "Votre compte a été créé et attend l'approbation de l'administrateur." + notice_default_data_loaded: Paramétrage par défaut chargé avec succès. + notice_unable_delete_version: Impossible de supprimer cette version. + notice_issue_done_ratios_updated: L'avancement des demandes a été mis à jour. + notice_api_access_key_reseted: Votre clé d'accès API a été réinitialisée. + notice_gantt_chart_truncated: "Le diagramme a été tronqué car il excède le nombre maximal d'éléments pouvant être affichés (%{max})" + notice_issue_successful_create: "Demande %{id} créée." + notice_issue_update_conflict: "La demande a été mise à jour par un autre utilisateur pendant que vous la modifiez." + notice_account_deleted: "Votre compte a été définitivement supprimé." + notice_user_successful_create: "Utilisateur %{id} créé." + + error_can_t_load_default_data: "Une erreur s'est produite lors du chargement du paramétrage : %{value}" + error_scm_not_found: "L'entrée et/ou la révision demandée n'existe pas dans le dépôt." + error_scm_command_failed: "Une erreur s'est produite lors de l'accès au dépôt : %{value}" + error_scm_annotate: "L'entrée n'existe pas ou ne peut pas être annotée." + error_issue_not_found_in_project: "La demande n'existe pas ou n'appartient pas à ce projet" + error_can_not_reopen_issue_on_closed_version: 'Une demande assignée à une version fermée ne peut pas être réouverte' + error_can_not_archive_project: "Ce projet ne peut pas être archivé" + error_workflow_copy_source: 'Veuillez sélectionner un tracker et/ou un rôle source' + error_workflow_copy_target: 'Veuillez sélectionner les trackers et rôles cibles' + error_issue_done_ratios_not_updated: L'avancement des demandes n'a pas pu être mis à jour. + error_attachment_too_big: Ce fichier ne peut pas être attaché car il excède la taille maximale autorisée (%{max_size}) + error_session_expired: "Votre session a expiré. Veuillez vous reconnecter." + + warning_attachments_not_saved: "%{count} fichier(s) n'ont pas pu être sauvegardés." + + mail_subject_lost_password: "Votre mot de passe %{value}" + mail_body_lost_password: 'Pour changer votre mot de passe, cliquez sur le lien suivant :' + mail_subject_register: "Activation de votre compte %{value}" + mail_body_register: 'Pour activer votre compte, cliquez sur le lien suivant :' + mail_body_account_information_external: "Vous pouvez utiliser votre compte %{value} pour vous connecter." + mail_body_account_information: Paramètres de connexion de votre compte + mail_subject_account_activation_request: "Demande d'activation d'un compte %{value}" + mail_body_account_activation_request: "Un nouvel utilisateur (%{value}) s'est inscrit. Son compte nécessite votre approbation :" + mail_subject_reminder: "%{count} demande(s) arrivent à échéance (%{days})" + mail_body_reminder: "%{count} demande(s) qui vous sont assignées arrivent à échéance dans les %{days} prochains jours :" + mail_subject_wiki_content_added: "Page wiki '%{id}' ajoutée" + mail_body_wiki_content_added: "La page wiki '%{id}' a été ajoutée par %{author}." + mail_subject_wiki_content_updated: "Page wiki '%{id}' mise à jour" + mail_body_wiki_content_updated: "La page wiki '%{id}' a été mise à jour par %{author}." + + + field_name: Nom + field_description: Description + field_summary: Résumé + field_is_required: Obligatoire + field_firstname: Prénom + field_lastname: Nom + field_mail: "Email " + field_filename: Fichier + field_filesize: Taille + field_downloads: Téléchargements + field_author: Auteur + field_created_on: "Créé " + field_updated_on: "Mis-à-jour " + field_closed_on: Fermé + field_field_format: Format + field_is_for_all: Pour tous les projets + field_possible_values: Valeurs possibles + field_regexp: Expression régulière + field_min_length: Longueur minimum + field_max_length: Longueur maximum + field_value: Valeur + field_category: Catégorie + field_title: Titre + field_project: Projet + field_issue: Demande + field_status: Statut + field_notes: Notes + field_is_closed: Demande fermée + field_is_default: Valeur par défaut + field_tracker: Tracker + field_subject: Sujet + field_due_date: Echéance + field_assigned_to: Assigné à + field_priority: Priorité + field_fixed_version: Version cible + field_user: Utilisateur + field_role: Rôle + field_homepage: "Site web " + field_is_public: Public + field_parent: Sous-projet de + field_is_in_roadmap: Demandes affichées dans la roadmap + field_login: "Identifiant " + field_mail_notification: Notifications par mail + field_admin: Administrateur + field_last_login_on: "Dernière connexion " + field_language: Langue + field_effective_date: Date + field_password: Mot de passe + field_new_password: Nouveau mot de passe + field_password_confirmation: Confirmation + field_version: Version + field_type: Type + field_host: Hôte + field_port: Port + field_account: Compte + field_base_dn: Base DN + field_attr_login: Attribut Identifiant + field_attr_firstname: Attribut Prénom + field_attr_lastname: Attribut Nom + field_attr_mail: Attribut Email + field_onthefly: Création des utilisateurs à la volée + field_start_date: Début + field_done_ratio: "% réalisé" + field_auth_source: Mode d'authentification + field_hide_mail: Cacher mon adresse mail + field_comments: Commentaire + field_url: URL + field_start_page: Page de démarrage + field_subproject: Sous-projet + field_hours: Heures + field_activity: Activité + field_spent_on: Date + field_identifier: Identifiant + field_is_filter: Utilisé comme filtre + field_issue_to: Demande liée + field_delay: Retard + field_assignable: Demandes assignables à ce rôle + field_redirect_existing_links: Rediriger les liens existants + field_estimated_hours: Temps estimé + field_column_names: Colonnes + field_time_zone: Fuseau horaire + field_searchable: Utilisé pour les recherches + field_default_value: Valeur par défaut + field_comments_sorting: Afficher les commentaires + field_parent_title: Page parent + field_editable: Modifiable + field_watcher: Observateur + field_identity_url: URL OpenID + field_content: Contenu + field_group_by: Grouper par + field_sharing: Partage + field_active: Actif + field_parent_issue: Tâche parente + field_visible: Visible + field_warn_on_leaving_unsaved: "M'avertir lorsque je quitte une page contenant du texte non sauvegardé" + field_issues_visibility: Visibilité des demandes + field_is_private: Privée + field_commit_logs_encoding: Encodage des messages de commit + field_repository_is_default: Dépôt principal + field_multiple: Valeurs multiples + field_auth_source_ldap_filter: Filtre LDAP + field_core_fields: Champs standards + field_timeout: "Timeout (en secondes)" + field_board_parent: Forum parent + field_private_notes: Notes privées + field_inherit_members: Hériter les membres + + setting_app_title: Titre de l'application + setting_app_subtitle: Sous-titre de l'application + setting_welcome_text: Texte d'accueil + setting_default_language: Langue par défaut + setting_login_required: Authentification obligatoire + setting_self_registration: Inscription des nouveaux utilisateurs + setting_attachment_max_size: Taille maximale des fichiers + setting_issues_export_limit: Limite d'exportation des demandes + setting_mail_from: Adresse d'émission + setting_bcc_recipients: Destinataires en copie cachée (cci) + setting_plain_text_mail: Mail en texte brut (non HTML) + setting_host_name: Nom d'hôte et chemin + setting_text_formatting: Formatage du texte + setting_wiki_compression: Compression de l'historique des pages wiki + setting_feeds_limit: Nombre maximal d'éléments dans les flux Atom + setting_default_projects_public: Définir les nouveaux projets comme publics par défaut + setting_autofetch_changesets: Récupération automatique des commits + setting_sys_api_enabled: Activer les WS pour la gestion des dépôts + setting_commit_ref_keywords: Mots-clés de référencement + setting_commit_fix_keywords: Mots-clés de résolution + setting_autologin: Durée maximale de connexion automatique + setting_date_format: Format de date + setting_time_format: Format d'heure + setting_cross_project_issue_relations: Autoriser les relations entre demandes de différents projets + setting_cross_project_subtasks: Autoriser les sous-tâches dans des projets différents + setting_issue_list_default_columns: Colonnes affichées par défaut sur la liste des demandes + setting_emails_footer: Pied-de-page des emails + setting_protocol: Protocole + setting_per_page_options: Options d'objets affichés par page + setting_user_format: Format d'affichage des utilisateurs + setting_activity_days_default: Nombre de jours affichés sur l'activité des projets + setting_display_subprojects_issues: Afficher par défaut les demandes des sous-projets sur les projets principaux + setting_enabled_scm: SCM activés + setting_mail_handler_body_delimiters: "Tronquer les emails après l'une de ces lignes" + setting_mail_handler_api_enabled: "Activer le WS pour la réception d'emails" + setting_mail_handler_api_key: Clé de protection de l'API + setting_sequential_project_identifiers: Générer des identifiants de projet séquentiels + setting_gravatar_enabled: Afficher les Gravatar des utilisateurs + setting_diff_max_lines_displayed: Nombre maximum de lignes de diff affichées + setting_file_max_size_displayed: Taille maximum des fichiers texte affichés en ligne + setting_repository_log_display_limit: "Nombre maximum de révisions affichées sur l'historique d'un fichier" + setting_openid: "Autoriser l'authentification et l'enregistrement OpenID" + setting_password_min_length: Longueur minimum des mots de passe + setting_new_project_user_role_id: Rôle donné à un utilisateur non-administrateur qui crée un projet + setting_default_projects_modules: Modules activés par défaut pour les nouveaux projets + setting_issue_done_ratio: Calcul de l'avancement des demandes + setting_issue_done_ratio_issue_status: Utiliser le statut + setting_issue_done_ratio_issue_field: 'Utiliser le champ % effectué' + setting_rest_api_enabled: Activer l'API REST + setting_gravatar_default: Image Gravatar par défaut + setting_start_of_week: Jour de début des calendriers + setting_cache_formatted_text: Mettre en cache le texte formaté + setting_commit_logtime_enabled: Permettre la saisie de temps + setting_commit_logtime_activity_id: Activité pour le temps saisi + setting_gantt_items_limit: Nombre maximum d'éléments affichés sur le gantt + setting_issue_group_assignment: Permettre l'assignement des demandes aux groupes + setting_default_issue_start_date_to_creation_date: Donner à la date de début d'une nouvelle demande la valeur de la date du jour + setting_commit_cross_project_ref: Permettre le référencement et la résolution des demandes de tous les autres projets + setting_unsubscribe: Permettre aux utilisateurs de supprimer leur propre compte + setting_session_lifetime: Durée de vie maximale des sessions + setting_session_timeout: Durée maximale d'inactivité + setting_thumbnails_enabled: Afficher les vignettes des images + setting_thumbnails_size: Taille des vignettes (en pixels) + setting_non_working_week_days: Jours non travaillés + setting_jsonp_enabled: Activer le support JSONP + setting_default_projects_tracker_ids: Trackers par défaut pour les nouveaux projets + + permission_add_project: Créer un projet + permission_add_subprojects: Créer des sous-projets + permission_edit_project: Modifier le projet + permission_close_project: Fermer / réouvrir le projet + permission_select_project_modules: Choisir les modules + permission_manage_members: Gérer les membres + permission_manage_versions: Gérer les versions + permission_manage_categories: Gérer les catégories de demandes + permission_view_issues: Voir les demandes + permission_add_issues: Créer des demandes + permission_edit_issues: Modifier les demandes + permission_manage_issue_relations: Gérer les relations + permission_set_issues_private: Rendre les demandes publiques ou privées + permission_set_own_issues_private: Rendre ses propres demandes publiques ou privées + permission_add_issue_notes: Ajouter des notes + permission_edit_issue_notes: Modifier les notes + permission_edit_own_issue_notes: Modifier ses propres notes + permission_view_private_notes: Voir les notes privées + permission_set_notes_private: Rendre les notes privées + permission_move_issues: Déplacer les demandes + permission_delete_issues: Supprimer les demandes + permission_manage_public_queries: Gérer les requêtes publiques + permission_save_queries: Sauvegarder les requêtes + permission_view_gantt: Voir le gantt + permission_view_calendar: Voir le calendrier + permission_view_issue_watchers: Voir la liste des observateurs + permission_add_issue_watchers: Ajouter des observateurs + permission_delete_issue_watchers: Supprimer des observateurs + permission_log_time: Saisir le temps passé + permission_view_time_entries: Voir le temps passé + permission_edit_time_entries: Modifier les temps passés + permission_edit_own_time_entries: Modifier son propre temps passé + permission_manage_news: Gérer les annonces + permission_comment_news: Commenter les annonces + permission_view_documents: Voir les documents + permission_add_documents: Ajouter des documents + permission_edit_documents: Modifier les documents + permission_delete_documents: Supprimer les documents + permission_manage_files: Gérer les fichiers + permission_view_files: Voir les fichiers + permission_manage_wiki: Gérer le wiki + permission_rename_wiki_pages: Renommer les pages + permission_delete_wiki_pages: Supprimer les pages + permission_view_wiki_pages: Voir le wiki + permission_view_wiki_edits: "Voir l'historique des modifications" + permission_edit_wiki_pages: Modifier les pages + permission_delete_wiki_pages_attachments: Supprimer les fichiers joints + permission_protect_wiki_pages: Protéger les pages + permission_manage_repository: Gérer le dépôt de sources + permission_browse_repository: Parcourir les sources + permission_view_changesets: Voir les révisions + permission_commit_access: Droit de commit + permission_manage_boards: Gérer les forums + permission_view_messages: Voir les messages + permission_add_messages: Poster un message + permission_edit_messages: Modifier les messages + permission_edit_own_messages: Modifier ses propres messages + permission_delete_messages: Supprimer les messages + permission_delete_own_messages: Supprimer ses propres messages + permission_export_wiki_pages: Exporter les pages + permission_manage_project_activities: Gérer les activités + permission_manage_subtasks: Gérer les sous-tâches + permission_manage_related_issues: Gérer les demandes associées + + project_module_issue_tracking: Suivi des demandes + project_module_time_tracking: Suivi du temps passé + project_module_news: Publication d'annonces + project_module_documents: Publication de documents + project_module_files: Publication de fichiers + project_module_wiki: Wiki + project_module_repository: Dépôt de sources + project_module_boards: Forums de discussion + + label_user: Utilisateur + label_user_plural: Utilisateurs + label_user_new: Nouvel utilisateur + label_user_anonymous: Anonyme + label_project: Projet + label_project_new: Nouveau projet + label_project_plural: Projets + label_x_projects: + zero: aucun projet + one: un projet + other: "%{count} projets" + label_project_all: Tous les projets + label_project_latest: Derniers projets + label_issue: Demande + label_issue_new: Nouvelle demande + label_issue_plural: Demandes + label_issue_view_all: Voir toutes les demandes + label_issue_added: Demande ajoutée + label_issue_updated: Demande mise à jour + label_issue_note_added: Note ajoutée + label_issue_status_updated: Statut changé + label_issue_priority_updated: Priorité changée + label_issues_by: "Demandes par %{value}" + label_document: Document + label_document_new: Nouveau document + label_document_plural: Documents + label_document_added: Document ajouté + label_role: Rôle + label_role_plural: Rôles + label_role_new: Nouveau rôle + label_role_and_permissions: Rôles et permissions + label_role_anonymous: Anonyme + label_role_non_member: Non membre + label_member: Membre + label_member_new: Nouveau membre + label_member_plural: Membres + label_tracker: Tracker + label_tracker_plural: Trackers + label_tracker_new: Nouveau tracker + label_workflow: Workflow + label_issue_status: Statut de demandes + label_issue_status_plural: Statuts de demandes + label_issue_status_new: Nouveau statut + label_issue_category: Catégorie de demandes + label_issue_category_plural: Catégories de demandes + label_issue_category_new: Nouvelle catégorie + label_custom_field: Champ personnalisé + label_custom_field_plural: Champs personnalisés + label_custom_field_new: Nouveau champ personnalisé + label_enumerations: Listes de valeurs + label_enumeration_new: Nouvelle valeur + label_information: Information + label_information_plural: Informations + label_please_login: Identification + label_register: S'enregistrer + label_login_with_open_id_option: S'authentifier avec OpenID + label_password_lost: Mot de passe perdu + label_home: Accueil + label_my_page: Ma page + label_my_account: Mon compte + label_my_projects: Mes projets + label_my_page_block: Blocs disponibles + label_administration: Administration + label_login: Connexion + label_logout: Déconnexion + label_help: Aide + label_reported_issues: "Demandes soumises " + label_assigned_to_me_issues: Demandes qui me sont assignées + label_last_login: "Dernière connexion " + label_registered_on: "Inscrit le " + label_activity: Activité + label_overall_activity: Activité globale + label_user_activity: "Activité de %{value}" + label_new: Nouveau + label_logged_as: Connecté en tant que + label_environment: Environnement + label_authentication: Authentification + label_auth_source: Mode d'authentification + label_auth_source_new: Nouveau mode d'authentification + label_auth_source_plural: Modes d'authentification + label_subproject_plural: Sous-projets + label_subproject_new: Nouveau sous-projet + label_and_its_subprojects: "%{value} et ses sous-projets" + label_min_max_length: Longueurs mini - maxi + label_list: Liste + label_date: Date + label_integer: Entier + label_float: Nombre décimal + label_boolean: Booléen + label_string: Texte + label_text: Texte long + label_attribute: Attribut + label_attribute_plural: Attributs + label_no_data: Aucune donnée à afficher + label_change_status: Changer le statut + label_history: Historique + label_attachment: Fichier + label_attachment_new: Nouveau fichier + label_attachment_delete: Supprimer le fichier + label_attachment_plural: Fichiers + label_file_added: Fichier ajouté + label_report: Rapport + label_report_plural: Rapports + label_news: Annonce + label_news_new: Nouvelle annonce + label_news_plural: Annonces + label_news_latest: Dernières annonces + label_news_view_all: Voir toutes les annonces + label_news_added: Annonce ajoutée + label_news_comment_added: Commentaire ajouté à une annonce + label_settings: Configuration + label_overview: Aperçu + label_version: Version + label_version_new: Nouvelle version + label_version_plural: Versions + label_confirmation: Confirmation + label_export_to: 'Formats disponibles :' + label_read: Lire... + label_public_projects: Projets publics + label_open_issues: ouvert + label_open_issues_plural: ouverts + label_closed_issues: fermé + label_closed_issues_plural: fermés + label_x_open_issues_abbr_on_total: + zero: 0 ouverte sur %{total} + one: 1 ouverte sur %{total} + other: "%{count} ouvertes sur %{total}" + label_x_open_issues_abbr: + zero: 0 ouverte + one: 1 ouverte + other: "%{count} ouvertes" + label_x_closed_issues_abbr: + zero: 0 fermée + one: 1 fermée + other: "%{count} fermées" + label_x_issues: + zero: 0 demande + one: 1 demande + other: "%{count} demandes" + label_total: Total + label_total_time: Temps total + label_permissions: Permissions + label_current_status: Statut actuel + label_new_statuses_allowed: Nouveaux statuts autorisés + label_all: tous + label_any: tous + label_none: aucun + label_nobody: personne + label_next: Suivant + label_previous: Précédent + label_used_by: Utilisé par + label_details: Détails + label_add_note: Ajouter une note + label_per_page: Par page + label_calendar: Calendrier + label_months_from: mois depuis + label_gantt: Gantt + label_internal: Interne + label_last_changes: "%{count} derniers changements" + label_change_view_all: Voir tous les changements + label_personalize_page: Personnaliser cette page + label_comment: Commentaire + label_comment_plural: Commentaires + label_x_comments: + zero: aucun commentaire + one: un commentaire + other: "%{count} commentaires" + label_comment_add: Ajouter un commentaire + label_comment_added: Commentaire ajouté + label_comment_delete: Supprimer les commentaires + label_query: Rapport personnalisé + label_query_plural: Rapports personnalisés + label_query_new: Nouveau rapport + label_my_queries: Mes rapports personnalisés + label_filter_add: "Ajouter le filtre " + label_filter_plural: Filtres + label_equals: égal + label_not_equals: différent + label_in_less_than: dans moins de + label_in_more_than: dans plus de + label_in_the_next_days: dans les prochains jours + label_in_the_past_days: dans les derniers jours + label_in: dans + label_today: aujourd'hui + label_all_time: toute la période + label_yesterday: hier + label_this_week: cette semaine + label_last_week: la semaine dernière + label_last_n_weeks: "les %{count} dernières semaines" + label_last_n_days: "les %{count} derniers jours" + label_this_month: ce mois-ci + label_last_month: le mois dernier + label_this_year: cette année + label_date_range: Période + label_less_than_ago: il y a moins de + label_more_than_ago: il y a plus de + label_ago: il y a + label_contains: contient + label_not_contains: ne contient pas + label_any_issues_in_project: une demande du projet + label_any_issues_not_in_project: une demande hors du projet + label_no_issues_in_project: aucune demande du projet + label_day_plural: jours + label_repository: Dépôt + label_repository_new: Nouveau dépôt + label_repository_plural: Dépôts + label_browse: Parcourir + label_revision: "Révision " + label_revision_plural: Révisions + label_associated_revisions: Révisions associées + label_added: ajouté + label_modified: modifié + label_copied: copié + label_renamed: renommé + label_deleted: supprimé + label_latest_revision: Dernière révision + label_latest_revision_plural: Dernières révisions + label_view_revisions: Voir les révisions + label_max_size: Taille maximale + label_sort_highest: Remonter en premier + label_sort_higher: Remonter + label_sort_lower: Descendre + label_sort_lowest: Descendre en dernier + label_roadmap: Roadmap + label_roadmap_due_in: "Échéance dans %{value}" + label_roadmap_overdue: "En retard de %{value}" + label_roadmap_no_issues: Aucune demande pour cette version + label_search: "Recherche " + label_result_plural: Résultats + label_all_words: Tous les mots + label_wiki: Wiki + label_wiki_edit: Révision wiki + label_wiki_edit_plural: Révisions wiki + label_wiki_page: Page wiki + label_wiki_page_plural: Pages wiki + label_index_by_title: Index par titre + label_index_by_date: Index par date + label_current_version: Version actuelle + label_preview: Prévisualisation + label_feed_plural: Flux RSS + label_changes_details: Détails de tous les changements + label_issue_tracking: Suivi des demandes + label_spent_time: Temps passé + label_f_hour: "%{value} heure" + label_f_hour_plural: "%{value} heures" + label_time_tracking: Suivi du temps + label_change_plural: Changements + label_statistics: Statistiques + label_commits_per_month: Commits par mois + label_commits_per_author: Commits par auteur + label_view_diff: Voir les différences + label_diff_inline: en ligne + label_diff_side_by_side: côte à côte + label_options: Options + label_copy_workflow_from: Copier le workflow de + label_permissions_report: Synthèse des permissions + label_watched_issues: Demandes surveillées + label_related_issues: Demandes liées + label_applied_status: Statut appliqué + label_loading: Chargement... + label_relation_new: Nouvelle relation + label_relation_delete: Supprimer la relation + label_relates_to: Lié à + label_duplicates: Duplique + label_duplicated_by: Dupliqué par + label_blocks: Bloque + label_blocked_by: Bloqué par + label_precedes: Précède + label_follows: Suit + label_copied_to: Copié vers + label_copied_from: Copié depuis + label_end_to_start: fin à début + label_end_to_end: fin à fin + label_start_to_start: début à début + label_start_to_end: début à fin + label_stay_logged_in: Rester connecté + label_disabled: désactivé + label_show_completed_versions: Voir les versions passées + label_me: moi + label_board: Forum + label_board_new: Nouveau forum + label_board_plural: Forums + label_topic_plural: Discussions + label_message_plural: Messages + label_message_last: Dernier message + label_message_new: Nouveau message + label_message_posted: Message ajouté + label_reply_plural: Réponses + label_send_information: Envoyer les informations à l'utilisateur + label_year: Année + label_month: Mois + label_week: Semaine + label_date_from: Du + label_date_to: Au + label_language_based: Basé sur la langue de l'utilisateur + label_sort_by: "Trier par %{value}" + label_send_test_email: Envoyer un email de test + label_feeds_access_key_created_on: "Clé d'accès RSS créée il y a %{value}" + label_module_plural: Modules + label_added_time_by: "Ajouté par %{author} il y a %{age}" + label_updated_time_by: "Mis à jour par %{author} il y a %{age}" + label_updated_time: "Mis à jour il y a %{value}" + label_jump_to_a_project: Aller à un projet... + label_file_plural: Fichiers + label_changeset_plural: Révisions + label_default_columns: Colonnes par défaut + label_no_change_option: (Pas de changement) + label_bulk_edit_selected_issues: Modifier les demandes sélectionnées + label_theme: Thème + label_default: Défaut + label_search_titles_only: Uniquement dans les titres + label_user_mail_option_all: "Pour tous les événements de tous mes projets" + label_user_mail_option_selected: "Pour tous les événements des projets sélectionnés..." + label_user_mail_no_self_notified: "Je ne veux pas être notifié des changements que j'effectue" + label_registration_activation_by_email: activation du compte par email + label_registration_manual_activation: activation manuelle du compte + label_registration_automatic_activation: activation automatique du compte + label_display_per_page: "Par page : %{value}" + label_age: Âge + label_change_properties: Changer les propriétés + label_general: Général + label_more: Plus + label_scm: SCM + label_plugins: Plugins + label_ldap_authentication: Authentification LDAP + label_downloads_abbr: D/L + label_optional_description: Description facultative + label_add_another_file: Ajouter un autre fichier + label_preferences: Préférences + label_chronological_order: Dans l'ordre chronologique + label_reverse_chronological_order: Dans l'ordre chronologique inverse + label_planning: Planning + label_incoming_emails: Emails entrants + label_generate_key: Générer une clé + label_issue_watchers: Observateurs + label_example: Exemple + label_display: Affichage + label_sort: Tri + label_ascending: Croissant + label_descending: Décroissant + label_date_from_to: Du %{start} au %{end} + label_wiki_content_added: Page wiki ajoutée + label_wiki_content_updated: Page wiki mise à jour + label_group_plural: Groupes + label_group: Groupe + label_group_new: Nouveau groupe + label_time_entry_plural: Temps passé + label_version_sharing_none: Non partagé + label_version_sharing_descendants: Avec les sous-projets + label_version_sharing_hierarchy: Avec toute la hiérarchie + label_version_sharing_tree: Avec tout l'arbre + label_version_sharing_system: Avec tous les projets + label_copy_source: Source + label_copy_target: Cible + label_copy_same_as_target: Comme la cible + label_update_issue_done_ratios: Mettre à jour l'avancement des demandes + label_display_used_statuses_only: N'afficher que les statuts utilisés dans ce tracker + label_api_access_key: Clé d'accès API + label_api_access_key_created_on: Clé d'accès API créée il y a %{value} + label_feeds_access_key: Clé d'accès RSS + label_missing_api_access_key: Clé d'accès API manquante + label_missing_feeds_access_key: Clé d'accès RSS manquante + label_close_versions: Fermer les versions terminées + label_revision_id: Révision %{value} + label_profile: Profil + label_subtask_plural: Sous-tâches + label_project_copy_notifications: Envoyer les notifications durant la copie du projet + label_principal_search: "Rechercher un utilisateur ou un groupe :" + label_user_search: "Rechercher un utilisateur :" + label_additional_workflow_transitions_for_author: Autorisations supplémentaires lorsque l'utilisateur a créé la demande + label_additional_workflow_transitions_for_assignee: Autorisations supplémentaires lorsque la demande est assignée à l'utilisateur + label_issues_visibility_all: Toutes les demandes + label_issues_visibility_public: Toutes les demandes non privées + label_issues_visibility_own: Demandes créées par ou assignées à l'utilisateur + label_export_options: Options d'exportation %{export_format} + label_copy_attachments: Copier les fichiers + label_copy_subtasks: Copier les sous-tâches + label_item_position: "%{position} sur %{count}" + label_completed_versions: Versions passées + label_session_expiration: Expiration des sessions + label_show_closed_projects: Voir les projets fermés + label_status_transitions: Changements de statut + label_fields_permissions: Permissions sur les champs + label_readonly: Lecture + label_required: Obligatoire + label_attribute_of_project: "%{name} du projet" + label_attribute_of_issue: "%{name} de la demande" + label_attribute_of_author: "%{name} de l'auteur" + label_attribute_of_assigned_to: "%{name} de l'assigné" + label_attribute_of_user: "%{name} de l'utilisateur" + label_attribute_of_fixed_version: "%{name} de la version cible" + label_cross_project_descendants: Avec les sous-projets + label_cross_project_tree: Avec tout l'arbre + label_cross_project_hierarchy: Avec toute la hiérarchie + label_cross_project_system: Avec tous les projets + label_gantt_progress_line: Ligne de progression + + button_login: Connexion + button_submit: Soumettre + button_save: Sauvegarder + button_check_all: Tout cocher + button_uncheck_all: Tout décocher + button_collapse_all: Plier tout + button_expand_all: Déplier tout + button_delete: Supprimer + button_create: Créer + button_create_and_continue: Créer et continuer + button_test: Tester + button_edit: Modifier + button_add: Ajouter + button_change: Changer + button_apply: Appliquer + button_clear: Effacer + button_lock: Verrouiller + button_unlock: Déverrouiller + button_download: Télécharger + button_list: Lister + button_view: Voir + button_move: Déplacer + button_move_and_follow: Déplacer et suivre + button_back: Retour + button_cancel: Annuler + button_activate: Activer + button_sort: Trier + button_log_time: Saisir temps + button_rollback: Revenir à cette version + button_watch: Surveiller + button_unwatch: Ne plus surveiller + button_reply: Répondre + button_archive: Archiver + button_unarchive: Désarchiver + button_reset: Réinitialiser + button_rename: Renommer + button_change_password: Changer de mot de passe + button_copy: Copier + button_copy_and_follow: Copier et suivre + button_annotate: Annoter + button_update: Mettre à jour + button_configure: Configurer + button_quote: Citer + button_duplicate: Dupliquer + button_show: Afficher + button_hide: Cacher + button_edit_section: Modifier cette section + button_export: Exporter + button_delete_my_account: Supprimer mon compte + button_close: Fermer + button_reopen: Réouvrir + + status_active: actif + status_registered: enregistré + status_locked: verrouillé + + project_status_active: actif + project_status_closed: fermé + project_status_archived: archivé + + version_status_open: ouvert + version_status_locked: verrouillé + version_status_closed: fermé + + text_select_mail_notifications: Actions pour lesquelles une notification par e-mail est envoyée + text_regexp_info: ex. ^[A-Z0-9]+$ + text_min_max_length_info: 0 pour aucune restriction + text_project_destroy_confirmation: Êtes-vous sûr de vouloir supprimer ce projet et toutes ses données ? + text_subprojects_destroy_warning: "Ses sous-projets : %{value} seront également supprimés." + text_workflow_edit: Sélectionner un tracker et un rôle pour éditer le workflow + text_are_you_sure: Êtes-vous sûr ? + text_tip_issue_begin_day: tâche commençant ce jour + text_tip_issue_end_day: tâche finissant ce jour + text_tip_issue_begin_end_day: tâche commençant et finissant ce jour + text_project_identifier_info: 'Seuls les lettres minuscules (a-z), chiffres, tirets et underscore sont autorisés, doit commencer par une minuscule.
    Un fois sauvegardé, l''identifiant ne pourra plus être modifié.' + text_caracters_maximum: "%{count} caractères maximum." + text_caracters_minimum: "%{count} caractères minimum." + text_length_between: "Longueur comprise entre %{min} et %{max} caractères." + text_tracker_no_workflow: Aucun worflow n'est défini pour ce tracker + text_unallowed_characters: Caractères non autorisés + text_comma_separated: Plusieurs valeurs possibles (séparées par des virgules). + text_line_separated: Plusieurs valeurs possibles (une valeur par ligne). + text_issues_ref_in_commit_messages: Référencement et résolution des demandes dans les commentaires de commits + text_issue_added: "La demande %{id} a été soumise par %{author}." + text_issue_updated: "La demande %{id} a été mise à jour par %{author}." + text_wiki_destroy_confirmation: Etes-vous sûr de vouloir supprimer ce wiki et tout son contenu ? + text_issue_category_destroy_question: "%{count} demandes sont affectées à cette catégorie. Que voulez-vous faire ?" + text_issue_category_destroy_assignments: N'affecter les demandes à aucune autre catégorie + text_issue_category_reassign_to: Réaffecter les demandes à cette catégorie + text_user_mail_option: "Pour les projets non sélectionnés, vous recevrez seulement des notifications pour ce que vous surveillez ou à quoi vous participez (exemple: demandes dont vous êtes l'auteur ou la personne assignée)." + text_no_configuration_data: "Les rôles, trackers, statuts et le workflow ne sont pas encore paramétrés.\nIl est vivement recommandé de charger le paramétrage par defaut. Vous pourrez le modifier une fois chargé." + text_load_default_configuration: Charger le paramétrage par défaut + text_status_changed_by_changeset: "Appliqué par commit %{value}." + text_time_logged_by_changeset: "Appliqué par commit %{value}" + text_issues_destroy_confirmation: 'Êtes-vous sûr de vouloir supprimer la ou les demandes(s) selectionnée(s) ?' + text_issues_destroy_descendants_confirmation: "Cela entrainera également la suppression de %{count} sous-tâche(s)." + text_select_project_modules: 'Sélectionner les modules à activer pour ce projet :' + text_default_administrator_account_changed: Compte administrateur par défaut changé + text_file_repository_writable: Répertoire de stockage des fichiers accessible en écriture + text_plugin_assets_writable: Répertoire public des plugins accessible en écriture + text_rmagick_available: Bibliothèque RMagick présente (optionnelle) + text_destroy_time_entries_question: "%{hours} heures ont été enregistrées sur les demandes à supprimer. Que voulez-vous faire ?" + text_destroy_time_entries: Supprimer les heures + text_assign_time_entries_to_project: Reporter les heures sur le projet + text_reassign_time_entries: 'Reporter les heures sur cette demande:' + text_user_wrote: "%{value} a écrit :" + text_enumeration_destroy_question: "Cette valeur est affectée à %{count} objets." + text_enumeration_category_reassign_to: 'Réaffecter les objets à cette valeur:' + text_email_delivery_not_configured: "L'envoi de mail n'est pas configuré, les notifications sont désactivées.\nConfigurez votre serveur SMTP dans config/configuration.yml et redémarrez l'application pour les activer." + text_repository_usernames_mapping: "Vous pouvez sélectionner ou modifier l'utilisateur Redmine associé à chaque nom d'utilisateur figurant dans l'historique du dépôt.\nLes utilisateurs avec le même identifiant ou la même adresse mail seront automatiquement associés." + text_diff_truncated: '... Ce différentiel a été tronqué car il excède la taille maximale pouvant être affichée.' + text_custom_field_possible_values_info: 'Une ligne par valeur' + text_wiki_page_destroy_question: "Cette page possède %{descendants} sous-page(s) et descendante(s). Que voulez-vous faire ?" + text_wiki_page_nullify_children: "Conserver les sous-pages en tant que pages racines" + text_wiki_page_destroy_children: "Supprimer les sous-pages et toutes leurs descedantes" + text_wiki_page_reassign_children: "Réaffecter les sous-pages à cette page" + text_own_membership_delete_confirmation: "Vous allez supprimer tout ou partie de vos permissions sur ce projet et ne serez peut-être plus autorisé à modifier ce projet.\nEtes-vous sûr de vouloir continuer ?" + text_warn_on_leaving_unsaved: "Cette page contient du texte non sauvegardé qui sera perdu si vous quittez la page." + text_issue_conflict_resolution_overwrite: "Appliquer quand même ma mise à jour (les notes précédentes seront conservées mais des changements pourront être écrasés)" + text_issue_conflict_resolution_add_notes: "Ajouter mes notes et ignorer mes autres changements" + text_issue_conflict_resolution_cancel: "Annuler ma mise à jour et réafficher %{link}" + text_account_destroy_confirmation: "Êtes-vous sûr de vouloir continuer ?\nVotre compte sera définitivement supprimé, sans aucune possibilité de le réactiver." + text_session_expiration_settings: "Attention : le changement de ces paramètres peut entrainer l'expiration des sessions utilisateurs en cours, y compris la vôtre." + text_project_closed: Ce projet est fermé et accessible en lecture seule. + text_turning_multiple_off: "Si vous désactivez les valeurs multiples, les valeurs multiples seront supprimées pour n'en conserver qu'une par objet." + + default_role_manager: "Manager " + default_role_developer: "Développeur " + default_role_reporter: "Rapporteur " + default_tracker_bug: Anomalie + default_tracker_feature: Evolution + default_tracker_support: Assistance + default_issue_status_new: Nouveau + default_issue_status_in_progress: En cours + default_issue_status_resolved: Résolu + default_issue_status_feedback: Commentaire + default_issue_status_closed: Fermé + default_issue_status_rejected: Rejeté + default_doc_category_user: Documentation utilisateur + default_doc_category_tech: Documentation technique + default_priority_low: Bas + default_priority_normal: Normal + default_priority_high: Haut + default_priority_urgent: Urgent + default_priority_immediate: Immédiat + default_activity_design: Conception + default_activity_development: Développement + + enumeration_issue_priorities: Priorités des demandes + enumeration_doc_categories: Catégories des documents + enumeration_activities: Activités (suivi du temps) + label_greater_or_equal: ">=" + label_less_or_equal: "<=" + label_between: entre + label_view_all_revisions: Voir toutes les révisions + label_tag: Tag + label_branch: Branche + error_no_tracker_in_project: "Aucun tracker n'est associé à ce projet. Vérifier la configuration du projet." + error_no_default_issue_status: "Aucun statut de demande n'est défini par défaut. Vérifier votre configuration (Administration -> Statuts de demandes)." + text_journal_changed: "%{label} changé de %{old} à %{new}" + text_journal_changed_no_detail: "%{label} mis à jour" + text_journal_set_to: "%{label} mis à %{value}" + text_journal_deleted: "%{label} %{old} supprimé" + text_journal_added: "%{label} %{value} ajouté" + enumeration_system_activity: Activité système + label_board_sticky: Sticky + label_board_locked: Verrouillé + error_unable_delete_issue_status: Impossible de supprimer le statut de demande + error_can_not_delete_custom_field: Impossible de supprimer le champ personnalisé + error_unable_to_connect: Connexion impossible (%{value}) + error_can_not_remove_role: Ce rôle est utilisé et ne peut pas être supprimé. + error_can_not_delete_tracker: Ce tracker contient des demandes et ne peut pas être supprimé. + field_principal: Principal + notice_failed_to_save_members: "Erreur lors de la sauvegarde des membres: %{errors}." + text_zoom_out: Zoom arrière + text_zoom_in: Zoom avant + notice_unable_delete_time_entry: Impossible de supprimer le temps passé. + label_overall_spent_time: Temps passé global + field_time_entries: Temps passé + project_module_gantt: Gantt + project_module_calendar: Calendrier + button_edit_associated_wikipage: "Modifier la page wiki associée: %{page_title}" + field_text: Champ texte + label_user_mail_option_only_owner: Seulement pour ce que j'ai créé + setting_default_notification_option: Option de notification par défaut + label_user_mail_option_only_my_events: Seulement pour ce que je surveille + label_user_mail_option_only_assigned: Seulement pour ce qui m'est assigné + label_user_mail_option_none: Aucune notification + field_member_of_group: Groupe de l'assigné + field_assigned_to_role: Rôle de l'assigné + setting_emails_header: En-tête des emails + label_bulk_edit_selected_time_entries: Modifier les temps passés sélectionnés + text_time_entries_destroy_confirmation: "Etes-vous sûr de vouloir supprimer les temps passés sélectionnés ?" + field_scm_path_encoding: Encodage des chemins + text_scm_path_encoding_note: "Défaut : UTF-8" + field_path_to_repository: Chemin du dépôt + field_root_directory: Répertoire racine + field_cvs_module: Module + field_cvsroot: CVSROOT + text_mercurial_repository_note: "Dépôt local (exemples : /hgrepo, c:\\hgrepo)" + text_scm_command: Commande + text_scm_command_version: Version + label_git_report_last_commit: Afficher le dernier commit des fichiers et répertoires + text_scm_config: Vous pouvez configurer les commandes des SCM dans config/configuration.yml. Redémarrer l'application après modification. + text_scm_command_not_available: Ce SCM n'est pas disponible. Vérifier les paramètres dans la section administration. + label_diff: diff + text_git_repository_note: Repository is bare and local (e.g. /gitrepo, c:\gitrepo) + description_query_sort_criteria_direction: Ordre de tri + description_project_scope: Périmètre de recherche + description_filter: Filtre + description_user_mail_notification: Option de notification + description_date_from: Date de début + description_message_content: Contenu du message + description_available_columns: Colonnes disponibles + description_all_columns: Toutes les colonnes + description_date_range_interval: Choisir une période + description_issue_category_reassign: Choisir une catégorie + description_search: Champ de recherche + description_notes: Notes + description_date_range_list: Choisir une période prédéfinie + description_choose_project: Projets + description_date_to: Date de fin + description_query_sort_criteria_attribute: Critère de tri + description_wiki_subpages_reassign: Choisir une nouvelle page parent + description_selected_columns: Colonnes sélectionnées + label_parent_revision: Parent + label_child_revision: Enfant + error_scm_annotate_big_text_file: Cette entrée ne peut pas être annotée car elle excède la taille maximale. + setting_repositories_encodings: Encodages des fichiers et des dépôts + label_search_for_watchers: Rechercher des observateurs + text_repository_identifier_info: 'Seuls les lettres minuscules (a-z), chiffres, tirets et underscore sont autorisés.
    Un fois sauvegardé, l''identifiant ne pourra plus être modifié.' diff --git a/config/locales/gl.yml b/config/locales/gl.yml new file mode 100644 index 00000000..ca14126f --- /dev/null +++ b/config/locales/gl.yml @@ -0,0 +1,1100 @@ +# Galician (Spain) for Ruby on Rails +# by Marcos Arias Pena (markus@agil-e.com) + +gl: + number: + format: + separator: "," + delimiter: "." + precision: 3 + + currency: + format: + format: "%n %u" + unit: "€" + separator: "," + delimiter: "." + precision: 2 + + percentage: + format: + # separator: + delimiter: "" + # precision: + + precision: + format: + # separator: + delimiter: "" + # precision: + + human: + format: + # separator: + delimiter: "" + precision: 3 + storage_units: + format: "%n %u" + units: + byte: + one: "Byte" + other: "Bytes" + kb: "KB" + mb: "MB" + gb: "GB" + tb: "TB" + + direction: ltr + date: + formats: + default: "%e/%m/%Y" + short: "%e %b" + long: "%A %e de %B de %Y" + day_names: [Domingo, Luns, Martes, Mércores, Xoves, Venres, Sábado] + abbr_day_names: [Dom, Lun, Mar, Mer, Xov, Ven, Sab] + month_names: [~, Xaneiro, Febreiro, Marzo, Abril, Maio, Xunio, Xullo, Agosto, Setembro, Outubro, Novembro, Decembro] + abbr_month_names: [~, Xan, Feb, Maz, Abr, Mai, Xun, Xul, Ago, Set, Out, Nov, Dec] + order: + - :day + - :month + - :year + + time: + formats: + default: "%A, %e de %B de %Y, %H:%M hs" + time: "%H:%M hs" + short: "%e/%m, %H:%M hs" + long: "%A %e de %B de %Y ás %H:%M horas" + + am: '' + pm: '' + + datetime: + distance_in_words: + half_a_minute: 'medio minuto' + less_than_x_seconds: + zero: 'menos dun segundo' + one: '1 segundo' + few: 'poucos segundos' + other: '%{count} segundos' + x_seconds: + one: '1 segundo' + other: '%{count} segundos' + less_than_x_minutes: + zero: 'menos dun minuto' + one: '1 minuto' + other: '%{count} minutos' + x_minutes: + one: '1 minuto' + other: '%{count} minuto' + about_x_hours: + one: 'aproximadamente unha hora' + other: '%{count} horas' + x_hours: + one: "1 hour" + other: "%{count} hours" + x_days: + one: '1 día' + other: '%{count} días' + x_weeks: + one: '1 semana' + other: '%{count} semanas' + about_x_months: + one: 'aproximadamente 1 mes' + other: '%{count} meses' + x_months: + one: '1 mes' + other: '%{count} meses' + about_x_years: + one: 'aproximadamente 1 ano' + other: '%{count} anos' + over_x_years: + one: 'máis dun ano' + other: '%{count} anos' + almost_x_years: + one: "almost 1 year" + other: "almost %{count} years" + now: 'agora' + today: 'hoxe' + tomorrow: 'mañá' + in: 'dentro de' + + support: + array: + sentence_connector: e + + activerecord: + models: + attributes: + errors: + template: + header: + one: "1 erro evitou que se poidese gardar o %{model}" + other: "%{count} erros evitaron que se poidese gardar o %{model}" + body: "Atopáronse os seguintes problemas:" + messages: + inclusion: "non está incluido na lista" + exclusion: "xa existe" + invalid: "non é válido" + confirmation: "non coincide coa confirmación" + accepted: "debe ser aceptado" + empty: "non pode estar valeiro" + blank: "non pode estar en blanco" + too_long: "é demasiado longo (non máis de %{count} carácteres)" + too_short: "é demasiado curto (non menos de %{count} carácteres)" + wrong_length: "non ten a lonxitude correcta (debe ser de %{count} carácteres)" + taken: "non está dispoñible" + not_a_number: "non é un número" + greater_than: "debe ser maior que %{count}" + greater_than_or_equal_to: "debe ser maior ou igual que %{count}" + equal_to: "debe ser igual a %{count}" + less_than: "debe ser menor que %{count}" + less_than_or_equal_to: "debe ser menor ou igual que %{count}" + odd: "debe ser par" + even: "debe ser impar" + greater_than_start_date: "debe ser posterior á data de comezo" + not_same_project: "non pertence ao mesmo proxecto" + circular_dependency: "Esta relación podería crear unha dependencia circular" + cant_link_an_issue_with_a_descendant: "An issue can not be linked to one of its subtasks" + + actionview_instancetag_blank_option: Por favor seleccione + + button_activate: Activar + button_add: Engadir + button_annotate: Anotar + button_apply: Aceptar + button_archive: Arquivar + button_back: Atrás + button_cancel: Cancelar + button_change: Cambiar + button_change_password: Cambiar contrasinal + button_check_all: Seleccionar todo + button_clear: Anular + button_configure: Configurar + button_copy: Copiar + button_create: Crear + button_delete: Borrar + button_download: Descargar + button_edit: Modificar + button_list: Listar + button_lock: Bloquear + button_log_time: Tempo dedicado + button_login: Conexión + button_move: Mover + button_quote: Citar + button_rename: Renomear + button_reply: Respostar + button_reset: Restablecer + button_rollback: Volver a esta versión + button_save: Gardar + button_sort: Ordenar + button_submit: Aceptar + button_test: Probar + button_unarchive: Desarquivar + button_uncheck_all: Non seleccionar nada + button_unlock: Desbloquear + button_unwatch: Non monitorizar + button_update: Actualizar + button_view: Ver + button_watch: Monitorizar + default_activity_design: Deseño + default_activity_development: Desenvolvemento + default_doc_category_tech: Documentación técnica + default_doc_category_user: Documentación de usuario + default_issue_status_in_progress: In Progress + default_issue_status_closed: Pechada + default_issue_status_feedback: Comentarios + default_issue_status_new: Nova + default_issue_status_rejected: Rexeitada + default_issue_status_resolved: Resolta + default_priority_high: Alta + default_priority_immediate: Inmediata + default_priority_low: Baixa + default_priority_normal: Normal + default_priority_urgent: Urxente + default_role_developer: Desenvolvedor + default_role_manager: Xefe de proxecto + default_role_reporter: Informador + default_tracker_bug: Erros + default_tracker_feature: Tarefas + default_tracker_support: Soporte + enumeration_activities: Actividades (tempo dedicado) + enumeration_doc_categories: Categorías do documento + enumeration_issue_priorities: Prioridade das peticións + error_can_t_load_default_data: "Non se puido cargar a configuración por defecto: %{value}" + error_issue_not_found_in_project: 'A petición non se atopa ou non está asociada a este proxecto' + error_scm_annotate: "Non existe a entrada ou non se puido anotar" + error_scm_command_failed: "Aconteceu un erro ao acceder ó repositorio: %{value}" + error_scm_not_found: "A entrada e/ou revisión non existe no repositorio." + field_account: Conta + field_activity: Actividade + field_admin: Administrador + field_assignable: Pódense asignar peticións a este perfil + field_assigned_to: Asignado a + field_attr_firstname: Atributo do nome + field_attr_lastname: Atributo do apelido + field_attr_login: Atributo do identificador + field_attr_mail: Atributo do Email + field_auth_source: Modo de identificación + field_author: Autor + field_base_dn: DN base + field_category: Categoría + field_column_names: Columnas + field_comments: Comentario + field_comments_sorting: Mostrar comentarios + field_created_on: Creado + field_default_value: Estado por defecto + field_delay: Retraso + field_description: Descrición + field_done_ratio: "% Realizado" + field_downloads: Descargas + field_due_date: Data fin + field_effective_date: Data + field_estimated_hours: Tempo estimado + field_field_format: Formato + field_filename: Arquivo + field_filesize: Tamaño + field_firstname: Nome + field_fixed_version: Versión prevista + field_hide_mail: Ocultar a miña dirección de correo + field_homepage: Sitio web + field_host: Anfitrión + field_hours: Horas + field_identifier: Identificador + field_is_closed: Petición resolta + field_is_default: Estado por defecto + field_is_filter: Usado como filtro + field_is_for_all: Para todos os proxectos + field_is_in_roadmap: Consultar as peticións na planificación + field_is_public: Público + field_is_required: Obrigatorio + field_issue: Petición + field_issue_to: Petición relacionada + field_language: Idioma + field_last_login_on: Última conexión + field_lastname: Apelido + field_login: Identificador + field_mail: Correo electrónico + field_mail_notification: Notificacións por correo + field_max_length: Lonxitude máxima + field_min_length: Lonxitude mínima + field_name: Nome + field_new_password: Novo contrasinal + field_notes: Notas + field_onthefly: Creación do usuario "ao voo" + field_parent: Proxecto pai + field_parent_title: Páxina pai + field_password: Contrasinal + field_password_confirmation: Confirmación + field_port: Porto + field_possible_values: Valores posibles + field_priority: Prioridade + field_project: Proxecto + field_redirect_existing_links: Redireccionar enlaces existentes + field_regexp: Expresión regular + field_role: Perfil + field_searchable: Incluír nas búsquedas + field_spent_on: Data + field_start_date: Data de inicio + field_start_page: Páxina principal + field_status: Estado + field_subject: Tema + field_subproject: Proxecto secundario + field_summary: Resumo + field_time_zone: Zona horaria + field_title: Título + field_tracker: Tipo + field_type: Tipo + field_updated_on: Actualizado + field_url: URL + field_user: Usuario + field_value: Valor + field_version: Versión + general_csv_decimal_separator: ',' + general_csv_encoding: ISO-8859-15 + general_csv_separator: ';' + general_first_day_of_week: '1' + general_lang_name: 'Galego' + general_pdf_encoding: UTF-8 + general_text_No: 'Non' + general_text_Yes: 'Si' + general_text_no: 'non' + general_text_yes: 'si' + label_activity: Actividade + label_add_another_file: Engadir outro arquivo + label_add_note: Engadir unha nota + label_added: engadido + label_added_time_by: "Engadido por %{author} fai %{age}" + label_administration: Administración + label_age: Idade + label_ago: fai + label_all: todos + label_all_time: todo o tempo + label_all_words: Tódalas palabras + label_and_its_subprojects: "%{value} e proxectos secundarios" + label_applied_status: Aplicar estado + label_assigned_to_me_issues: Peticións asignadas a min + label_associated_revisions: Revisións asociadas + label_attachment: Arquivo + label_attachment_delete: Borrar o arquivo + label_attachment_new: Novo arquivo + label_attachment_plural: Arquivos + label_attribute: Atributo + label_attribute_plural: Atributos + label_auth_source: Modo de autenticación + label_auth_source_new: Novo modo de autenticación + label_auth_source_plural: Modos de autenticación + label_authentication: Autenticación + label_blocked_by: bloqueado por + label_blocks: bloquea a + label_board: Foro + label_board_new: Novo foro + label_board_plural: Foros + label_boolean: Booleano + label_browse: Ollar + label_bulk_edit_selected_issues: Editar as peticións seleccionadas + label_calendar: Calendario + label_change_plural: Cambios + label_change_properties: Cambiar propiedades + label_change_status: Cambiar o estado + label_change_view_all: Ver tódolos cambios + label_changes_details: Detalles de tódolos cambios + label_changeset_plural: Cambios + label_chronological_order: En orde cronolóxica + label_closed_issues: pechada + label_closed_issues_plural: pechadas + label_x_open_issues_abbr_on_total: + zero: 0 open / %{total} + one: 1 open / %{total} + other: "%{count} open / %{total}" + label_x_open_issues_abbr: + zero: 0 open + one: 1 open + other: "%{count} open" + label_x_closed_issues_abbr: + zero: 0 closed + one: 1 closed + other: "%{count} closed" + label_comment: Comentario + label_comment_add: Engadir un comentario + label_comment_added: Comentario engadido + label_comment_delete: Borrar comentarios + label_comment_plural: Comentarios + label_x_comments: + zero: no comments + one: 1 comment + other: "%{count} comments" + label_commits_per_author: Commits por autor + label_commits_per_month: Commits por mes + label_confirmation: Confirmación + label_contains: conten + label_copied: copiado + label_copy_workflow_from: Copiar fluxo de traballo dende + label_current_status: Estado actual + label_current_version: Versión actual + label_custom_field: Campo personalizado + label_custom_field_new: Novo campo personalizado + label_custom_field_plural: Campos personalizados + label_date: Data + label_date_from: Dende + label_date_range: Rango de datas + label_date_to: Ata + label_day_plural: días + label_default: Por defecto + label_default_columns: Columnas por defecto + label_deleted: suprimido + label_details: Detalles + label_diff_inline: en liña + label_diff_side_by_side: cara a cara + label_disabled: deshabilitado + label_display_per_page: "Por páxina: %{value}" + label_document: Documento + label_document_added: Documento engadido + label_document_new: Novo documento + label_document_plural: Documentos + label_downloads_abbr: D/L + label_duplicated_by: duplicada por + label_duplicates: duplicada de + label_end_to_end: fin a fin + label_end_to_start: fin a principio + label_enumeration_new: Novo valor + label_enumerations: Listas de valores + label_environment: Entorno + label_equals: igual + label_example: Exemplo + label_export_to: 'Exportar a:' + label_f_hour: "%{value} hora" + label_f_hour_plural: "%{value} horas" + label_feed_plural: Feeds + label_feeds_access_key_created_on: "Clave de acceso por RSS creada fai %{value}" + label_file_added: Arquivo engadido + label_file_plural: Arquivos + label_filter_add: Engadir o filtro + label_filter_plural: Filtros + label_float: Flotante + label_follows: posterior a + label_gantt: Gantt + label_general: Xeral + label_generate_key: Xerar clave + label_help: Axuda + label_history: Histórico + label_home: Inicio + label_in: en + label_in_less_than: en menos que + label_in_more_than: en mais que + label_incoming_emails: Correos entrantes + label_index_by_date: Índice por data + label_index_by_title: Índice por título + label_information: Información + label_information_plural: Información + label_integer: Número + label_internal: Interno + label_issue: Petición + label_issue_added: Petición engadida + label_issue_category: Categoría das peticións + label_issue_category_new: Nova categoría + label_issue_category_plural: Categorías das peticións + label_issue_new: Nova petición + label_issue_plural: Peticións + label_issue_status: Estado da petición + label_issue_status_new: Novo estado + label_issue_status_plural: Estados das peticións + label_issue_tracking: Peticións + label_issue_updated: Petición actualizada + label_issue_view_all: Ver tódalas peticións + label_issue_watchers: Seguidores + label_issues_by: "Peticións por %{value}" + label_jump_to_a_project: Ir ao proxecto... + label_language_based: Baseado no idioma + label_last_changes: "últimos %{count} cambios" + label_last_login: Última conexión + label_last_month: último mes + label_last_n_days: "últimos %{count} días" + label_last_week: última semana + label_latest_revision: Última revisión + label_latest_revision_plural: Últimas revisións + label_ldap_authentication: Autenticación LDAP + label_less_than_ago: fai menos de + label_list: Lista + label_loading: Cargando... + label_logged_as: Conectado como + label_login: Conexión + label_logout: Desconexión + label_max_size: Tamaño máximo + label_me: eu mesmo + label_member: Membro + label_member_new: Novo membro + label_member_plural: Membros + label_message_last: Última mensaxe + label_message_new: Nova mensaxe + label_message_plural: Mensaxes + label_message_posted: Mensaxe engadida + label_min_max_length: Lonxitude mín - máx + label_modified: modificado + label_module_plural: Módulos + label_month: Mes + label_months_from: meses de + label_more: Mais + label_more_than_ago: fai mais de + label_my_account: A miña conta + label_my_page: A miña páxina + label_my_projects: Os meus proxectos + label_new: Novo + label_new_statuses_allowed: Novos estados autorizados + label_news: Noticia + label_news_added: Noticia engadida + label_news_latest: Últimas noticias + label_news_new: Nova noticia + label_news_plural: Noticias + label_news_view_all: Ver tódalas noticias + label_next: Seguinte + label_no_change_option: (Sen cambios) + label_no_data: Ningún dato a mostrar + label_nobody: ninguén + label_none: ningún + label_not_contains: non conten + label_not_equals: non igual + label_open_issues: aberta + label_open_issues_plural: abertas + label_optional_description: Descrición opcional + label_options: Opcións + label_overall_activity: Actividade global + label_overview: Vistazo + label_password_lost: ¿Esqueciches o contrasinal? + label_per_page: Por páxina + label_permissions: Permisos + label_permissions_report: Informe de permisos + label_personalize_page: Personalizar esta páxina + label_planning: Planificación + label_please_login: Conexión + label_plugins: Extensións + label_precedes: anterior a + label_preferences: Preferencias + label_preview: Previsualizar + label_previous: Anterior + label_project: Proxecto + label_project_all: Tódolos proxectos + label_project_latest: Últimos proxectos + label_project_new: Novo proxecto + label_project_plural: Proxectos + label_x_projects: + zero: no projects + one: 1 project + other: "%{count} projects" + label_public_projects: Proxectos públicos + label_query: Consulta personalizada + label_query_new: Nova consulta + label_query_plural: Consultas personalizadas + label_read: Ler... + label_register: Rexistrar + label_registered_on: Inscrito o + label_registration_activation_by_email: activación de conta por correo + label_registration_automatic_activation: activación automática de conta + label_registration_manual_activation: activación manual de conta + label_related_issues: Peticións relacionadas + label_relates_to: relacionada con + label_relation_delete: Eliminar relación + label_relation_new: Nova relación + label_renamed: renomeado + label_reply_plural: Respostas + label_report: Informe + label_report_plural: Informes + label_reported_issues: Peticións rexistradas por min + label_repository: Repositorio + label_repository_plural: Repositorios + label_result_plural: Resultados + label_reverse_chronological_order: En orde cronolóxica inversa + label_revision: Revisión + label_revision_plural: Revisións + label_roadmap: Planificación + label_roadmap_due_in: "Remata en %{value}" + label_roadmap_no_issues: Non hai peticións para esta versión + label_roadmap_overdue: "%{value} tarde" + label_role: Perfil + label_role_and_permissions: Perfiles e permisos + label_role_new: Novo perfil + label_role_plural: Perfiles + label_scm: SCM + label_search: Búsqueda + label_search_titles_only: Buscar só en títulos + label_send_information: Enviar información da conta ó usuario + label_send_test_email: Enviar un correo de proba + label_settings: Configuración + label_show_completed_versions: Mostra as versións rematadas + label_sort_by: "Ordenar por %{value}" + label_sort_higher: Subir + label_sort_highest: Primeiro + label_sort_lower: Baixar + label_sort_lowest: Último + label_spent_time: Tempo dedicado + label_start_to_end: comezo a fin + label_start_to_start: comezo a comezo + label_statistics: Estatísticas + label_stay_logged_in: Lembrar contrasinal + label_string: Texto + label_subproject_plural: Proxectos secundarios + label_text: Texto largo + label_theme: Tema + label_this_month: este mes + label_this_week: esta semana + label_this_year: este ano + label_time_tracking: Control de tempo + label_today: hoxe + label_topic_plural: Temas + label_total: Total + label_tracker: Tipo + label_tracker_new: Novo tipo + label_tracker_plural: Tipos de peticións + label_updated_time: "Actualizado fai %{value}" + label_updated_time_by: "Actualizado por %{author} fai %{age}" + label_used_by: Utilizado por + label_user: Usuario + label_user_activity: "Actividade de %{value}" + label_user_mail_no_self_notified: "Non quero ser avisado de cambios feitos por min" + label_user_mail_option_all: "Para calquera evento en tódolos proxectos" + label_user_mail_option_selected: "Para calquera evento dos proxectos seleccionados..." + label_user_new: Novo usuario + label_user_plural: Usuarios + label_version: Versión + label_version_new: Nova versión + label_version_plural: Versións + label_view_diff: Ver diferencias + label_view_revisions: Ver as revisións + label_watched_issues: Peticións monitorizadas + label_week: Semana + label_wiki: Wiki + label_wiki_edit: Wiki edición + label_wiki_edit_plural: Wiki edicións + label_wiki_page: Wiki páxina + label_wiki_page_plural: Wiki páxinas + label_workflow: Fluxo de traballo + label_year: Ano + label_yesterday: onte + mail_body_account_activation_request: "Inscribiuse un novo usuario (%{value}). A conta está pendente de aprobación:" + mail_body_account_information: Información sobre a súa conta + mail_body_account_information_external: "Pode usar a súa conta %{value} para conectarse." + mail_body_lost_password: 'Para cambiar o seu contrasinal, faga clic no seguinte enlace:' + mail_body_register: 'Para activar a súa conta, faga clic no seguinte enlace:' + mail_body_reminder: "%{count} petición(s) asignadas a ti rematan nos próximos %{days} días:" + mail_subject_account_activation_request: "Petición de activación de conta %{value}" + mail_subject_lost_password: "O teu contrasinal de %{value}" + mail_subject_register: "Activación da conta de %{value}" + mail_subject_reminder: "%{count} petición(s) rematarán nos próximos %{days} días" + notice_account_activated: A súa conta foi activada. Xa pode conectarse. + notice_account_invalid_creditentials: Usuario ou contrasinal inválido. + notice_account_lost_email_sent: Enviouse un correo con instrucións para elixir un novo contrasinal. + notice_account_password_updated: Contrasinal modificado correctamente. + notice_account_pending: "A súa conta creouse e está pendente da aprobación por parte do administrador." + notice_account_register_done: Conta creada correctamente. Para activala, faga clic sobre o enlace que se lle enviou por correo. + notice_account_unknown_email: Usuario descoñecido. + notice_account_updated: Conta actualizada correctamente. + notice_account_wrong_password: Contrasinal incorrecto. + notice_can_t_change_password: Esta conta utiliza unha fonte de autenticación externa. Non é posible cambiar o contrasinal. + notice_default_data_loaded: Configuración por defecto cargada correctamente. + notice_email_error: "Ocorreu un error enviando o correo (%{value})" + notice_email_sent: "Enviouse un correo a %{value}" + notice_failed_to_save_issues: "Imposible gravar %{count} petición(s) de %{total} seleccionada(s): %{ids}." + notice_feeds_access_key_reseted: A súa clave de acceso para RSS reiniciouse. + notice_file_not_found: A páxina á que tenta acceder non existe. + notice_locking_conflict: Os datos modificáronse por outro usuario. + notice_no_issue_selected: "Ningunha petición seleccionada. Por favor, comprobe a petición que quere modificar" + notice_not_authorized: Non ten autorización para acceder a esta páxina. + notice_successful_connection: Conexión correcta. + notice_successful_create: Creación correcta. + notice_successful_delete: Borrado correcto. + notice_successful_update: Modificación correcta. + notice_unable_delete_version: Non se pode borrar a versión + permission_add_issue_notes: Engadir notas + permission_add_issue_watchers: Engadir seguidores + permission_add_issues: Engadir peticións + permission_add_messages: Enviar mensaxes + permission_browse_repository: Ollar repositorio + permission_comment_news: Comentar noticias + permission_commit_access: Acceso de escritura + permission_delete_issues: Borrar peticións + permission_delete_messages: Borrar mensaxes + permission_delete_own_messages: Borrar mensaxes propios + permission_delete_wiki_pages: Borrar páxinas wiki + permission_delete_wiki_pages_attachments: Borrar arquivos + permission_edit_issue_notes: Modificar notas + permission_edit_issues: Modificar peticións + permission_edit_messages: Modificar mensaxes + permission_edit_own_issue_notes: Modificar notas propias + permission_edit_own_messages: Editar mensaxes propios + permission_edit_own_time_entries: Modificar tempos dedicados propios + permission_edit_project: Modificar proxecto + permission_edit_time_entries: Modificar tempos dedicados + permission_edit_wiki_pages: Modificar páxinas wiki + permission_log_time: Anotar tempo dedicado + permission_manage_boards: Administrar foros + permission_manage_categories: Administrar categorías de peticións + permission_manage_files: Administrar arquivos + permission_manage_issue_relations: Administrar relación con outras peticións + permission_manage_members: Administrar membros + permission_manage_news: Administrar noticias + permission_manage_public_queries: Administrar consultas públicas + permission_manage_repository: Administrar repositorio + permission_manage_versions: Administrar versións + permission_manage_wiki: Administrar wiki + permission_move_issues: Mover peticións + permission_protect_wiki_pages: Protexer páxinas wiki + permission_rename_wiki_pages: Renomear páxinas wiki + permission_save_queries: Gravar consultas + permission_select_project_modules: Seleccionar módulos do proxecto + permission_view_calendar: Ver calendario + permission_view_changesets: Ver cambios + permission_view_documents: Ver documentos + permission_view_files: Ver arquivos + permission_view_gantt: Ver diagrama de Gantt + permission_view_issue_watchers: Ver lista de seguidores + permission_view_messages: Ver mensaxes + permission_view_time_entries: Ver tempo dedicado + permission_view_wiki_edits: Ver histórico do wiki + permission_view_wiki_pages: Ver wiki + project_module_boards: Foros + project_module_documents: Documentos + project_module_files: Arquivos + project_module_issue_tracking: Peticións + project_module_news: Noticias + project_module_repository: Repositorio + project_module_time_tracking: Control de tempo + project_module_wiki: Wiki + setting_activity_days_default: Días a mostrar na actividade do proxecto + setting_app_subtitle: Subtítulo da aplicación + setting_app_title: Título da aplicación + setting_attachment_max_size: Tamaño máximo do arquivo + setting_autofetch_changesets: Autorechear os commits do repositorio + setting_autologin: Conexión automática + setting_bcc_recipients: Ocultar as copias de carbón (bcc) + setting_commit_fix_keywords: Palabras clave para a corrección + setting_commit_ref_keywords: Palabras clave para a referencia + setting_cross_project_issue_relations: Permitir relacionar peticións de distintos proxectos + setting_date_format: Formato da data + setting_default_language: Idioma por defecto + setting_default_projects_public: Os proxectos novos son públicos por defecto + setting_diff_max_lines_displayed: Número máximo de diferencias mostradas + setting_display_subprojects_issues: Mostrar por defecto peticións de prox. secundarios no principal + setting_emails_footer: Pe de mensaxes + setting_enabled_scm: Activar SCM + setting_feeds_limit: Límite de contido para sindicación + setting_gravatar_enabled: Usar iconas de usuario (Gravatar) + setting_host_name: Nome e ruta do servidor + setting_issue_list_default_columns: Columnas por defecto para a lista de peticións + setting_issues_export_limit: Límite de exportación de peticións + setting_login_required: Requírese identificación + setting_mail_from: Correo dende o que enviar mensaxes + setting_mail_handler_api_enabled: Activar SW para mensaxes entrantes + setting_mail_handler_api_key: Clave da API + setting_per_page_options: Obxectos por páxina + setting_plain_text_mail: só texto plano (non HTML) + setting_protocol: Protocolo + setting_self_registration: Rexistro permitido + setting_sequential_project_identifiers: Xerar identificadores de proxecto + setting_sys_api_enabled: Habilitar SW para a xestión do repositorio + setting_text_formatting: Formato de texto + setting_time_format: Formato de hora + setting_user_format: Formato de nome de usuario + setting_welcome_text: Texto de benvida + setting_wiki_compression: Compresión do historial do Wiki + status_active: activo + status_locked: bloqueado + status_registered: rexistrado + text_are_you_sure: ¿Está seguro? + text_assign_time_entries_to_project: Asignar as horas ó proxecto + text_caracters_maximum: "%{count} caracteres como máximo." + text_caracters_minimum: "%{count} caracteres como mínimo" + text_comma_separated: Múltiples valores permitidos (separados por coma). + text_default_administrator_account_changed: Conta de administrador por defecto modificada + text_destroy_time_entries: Borrar as horas + text_destroy_time_entries_question: Existen %{hours} horas asignadas á petición que quere borrar. ¿Que quere facer ? + text_diff_truncated: '... Diferencia truncada por exceder o máximo tamaño visualizable.' + text_email_delivery_not_configured: "O envío de correos non está configurado, e as notificacións desactiváronse. \n Configure o servidor de SMTP en config/configuration.yml e reinicie a aplicación para activar os cambios." + text_enumeration_category_reassign_to: 'Reasignar ó seguinte valor:' + text_enumeration_destroy_question: "%{count} obxectos con este valor asignado." + text_file_repository_writable: Pódese escribir no repositorio + text_issue_added: "Petición %{id} engadida por %{author}." + text_issue_category_destroy_assignments: Deixar as peticións sen categoría + text_issue_category_destroy_question: "Algunhas peticións (%{count}) están asignadas a esta categoría. ¿Que desexa facer?" + text_issue_category_reassign_to: Reasignar as peticións á categoría + text_issue_updated: "A petición %{id} actualizouse por %{author}." + text_issues_destroy_confirmation: '¿Seguro que quere borrar as peticións seleccionadas?' + text_issues_ref_in_commit_messages: Referencia e petición de corrección nas mensaxes + text_length_between: "Lonxitude entre %{min} e %{max} caracteres." + text_load_default_configuration: Cargar a configuración por defecto + text_min_max_length_info: 0 para ningunha restrición + text_no_configuration_data: "Inda non se configuraron perfiles, nin tipos, estados e fluxo de traballo asociado a peticións. Recoméndase encarecidamente cargar a configuración por defecto. Unha vez cargada, poderá modificala." + text_project_destroy_confirmation: ¿Estás seguro de querer eliminar o proxecto? + text_reassign_time_entries: 'Reasignar as horas a esta petición:' + text_regexp_info: ex. ^[A-Z0-9]+$ + text_repository_usernames_mapping: "Estableza a correspondencia entre os usuarios de Redmine e os presentes no log do repositorio.\nOs usuarios co mesmo nome ou correo en Redmine e no repositorio serán asociados automaticamente." + text_rmagick_available: RMagick dispoñible (opcional) + text_select_mail_notifications: Seleccionar os eventos a notificar + text_select_project_modules: 'Seleccione os módulos a activar para este proxecto:' + text_status_changed_by_changeset: "Aplicado nos cambios %{value}" + text_subprojects_destroy_warning: "Os proxectos secundarios: %{value} tamén se eliminarán" + text_tip_issue_begin_day: tarefa que comeza este día + text_tip_issue_begin_end_day: tarefa que comeza e remata este día + text_tip_issue_end_day: tarefa que remata este día + text_tracker_no_workflow: Non hai ningún fluxo de traballo definido para este tipo de petición + text_unallowed_characters: Caracteres non permitidos + text_user_mail_option: "Dos proxectos non seleccionados, só recibirá notificacións sobre elementos monitorizados ou elementos nos que estea involucrado (por exemplo, peticións das que vostede sexa autor ou asignadas a vostede)." + text_user_wrote: "%{value} escribiu:" + text_wiki_destroy_confirmation: ¿Seguro que quere borrar o wiki e todo o seu contido? + text_workflow_edit: Seleccionar un fluxo de traballo para actualizar + warning_attachments_not_saved: "%{count} file(s) could not be saved." + field_editable: Editable + text_plugin_assets_writable: Plugin assets directory writable + label_display: Display + button_create_and_continue: Create and continue + text_custom_field_possible_values_info: 'One line for each value' + setting_repository_log_display_limit: Maximum number of revisions displayed on file log + setting_file_max_size_displayed: Max size of text files displayed inline + field_watcher: Watcher + setting_openid: Allow OpenID login and registration + field_identity_url: OpenID URL + label_login_with_open_id_option: or login with OpenID + field_content: Content + label_descending: Descending + label_sort: Sort + label_ascending: Ascending + label_date_from_to: From %{start} to %{end} + label_greater_or_equal: ">=" + label_less_or_equal: <= + text_wiki_page_destroy_question: This page has %{descendants} child page(s) and descendant(s). What do you want to do? + text_wiki_page_reassign_children: Reassign child pages to this parent page + text_wiki_page_nullify_children: Keep child pages as root pages + text_wiki_page_destroy_children: Delete child pages and all their descendants + setting_password_min_length: Minimum password length + field_group_by: Group results by + mail_subject_wiki_content_updated: "'%{id}' wiki page has been updated" + label_wiki_content_added: Wiki page added + mail_subject_wiki_content_added: "'%{id}' wiki page has been added" + mail_body_wiki_content_added: The '%{id}' wiki page has been added by %{author}. + label_wiki_content_updated: Wiki page updated + mail_body_wiki_content_updated: The '%{id}' wiki page has been updated by %{author}. + permission_add_project: Create project + setting_new_project_user_role_id: Role given to a non-admin user who creates a project + label_view_all_revisions: View all revisions + label_tag: Tag + label_branch: Branch + error_no_tracker_in_project: No tracker is associated to this project. Please check the Project settings. + error_no_default_issue_status: No default issue status is defined. Please check your configuration (Go to "Administration -> Issue statuses"). + text_journal_changed: "%{label} changed from %{old} to %{new}" + text_journal_set_to: "%{label} set to %{value}" + text_journal_deleted: "%{label} deleted (%{old})" + label_group_plural: Groups + label_group: Group + label_group_new: New group + label_time_entry_plural: Spent time + text_journal_added: "%{label} %{value} added" + field_active: Active + enumeration_system_activity: System Activity + permission_delete_issue_watchers: Delete watchers + version_status_closed: closed + version_status_locked: locked + version_status_open: open + error_can_not_reopen_issue_on_closed_version: An issue assigned to a closed version can not be reopened + label_user_anonymous: Anonymous + button_move_and_follow: Move and follow + setting_default_projects_modules: Default enabled modules for new projects + setting_gravatar_default: Default Gravatar image + field_sharing: Sharing + label_version_sharing_hierarchy: With project hierarchy + label_version_sharing_system: With all projects + label_version_sharing_descendants: With subprojects + label_version_sharing_tree: With project tree + label_version_sharing_none: Not shared + error_can_not_archive_project: This project can not be archived + button_duplicate: Duplicate + button_copy_and_follow: Copy and follow + label_copy_source: Source + setting_issue_done_ratio: Calculate the issue done ratio with + setting_issue_done_ratio_issue_status: Use the issue status + error_issue_done_ratios_not_updated: Issue done ratios not updated. + error_workflow_copy_target: Please select target tracker(s) and role(s) + setting_issue_done_ratio_issue_field: Use the issue field + label_copy_same_as_target: Same as target + label_copy_target: Target + notice_issue_done_ratios_updated: Issue done ratios updated. + error_workflow_copy_source: Please select a source tracker or role + label_update_issue_done_ratios: Update issue done ratios + setting_start_of_week: Start calendars on + permission_view_issues: View Issues + label_display_used_statuses_only: Only display statuses that are used by this tracker + label_revision_id: Revision %{value} + label_api_access_key: API access key + label_api_access_key_created_on: API access key created %{value} ago + label_feeds_access_key: RSS access key + notice_api_access_key_reseted: Your API access key was reset. + setting_rest_api_enabled: Enable REST web service + label_missing_api_access_key: Missing an API access key + label_missing_feeds_access_key: Missing a RSS access key + button_show: Show + text_line_separated: Multiple values allowed (one line for each value). + setting_mail_handler_body_delimiters: Truncate emails after one of these lines + permission_add_subprojects: Create subprojects + label_subproject_new: New subproject + text_own_membership_delete_confirmation: |- + You are about to remove some or all of your permissions and may no longer be able to edit this project after that. + Are you sure you want to continue? + label_close_versions: Close completed versions + label_board_sticky: Sticky + label_board_locked: Locked + permission_export_wiki_pages: Export wiki pages + setting_cache_formatted_text: Cache formatted text + permission_manage_project_activities: Manage project activities + error_unable_delete_issue_status: Unable to delete issue status + label_profile: Profile + permission_manage_subtasks: Manage subtasks + field_parent_issue: Parent task + label_subtask_plural: Subtasks + label_project_copy_notifications: Send email notifications during the project copy + error_can_not_delete_custom_field: Unable to delete custom field + error_unable_to_connect: Unable to connect (%{value}) + error_can_not_remove_role: This role is in use and can not be deleted. + error_can_not_delete_tracker: This tracker contains issues and can't be deleted. + field_principal: Principal + label_my_page_block: My page block + notice_failed_to_save_members: "Failed to save member(s): %{errors}." + text_zoom_out: Zoom out + text_zoom_in: Zoom in + notice_unable_delete_time_entry: Unable to delete time log entry. + label_overall_spent_time: Overall spent time + field_time_entries: Log time + project_module_gantt: Gantt + project_module_calendar: Calendar + button_edit_associated_wikipage: "Edit associated Wiki page: %{page_title}" + field_text: Text field + label_user_mail_option_only_owner: Only for things I am the owner of + setting_default_notification_option: Default notification option + label_user_mail_option_only_my_events: Only for things I watch or I'm involved in + label_user_mail_option_only_assigned: Only for things I am assigned to + label_user_mail_option_none: No events + field_member_of_group: Assignee's group + field_assigned_to_role: Assignee's role + notice_not_authorized_archived_project: The project you're trying to access has been archived. + label_principal_search: "Search for user or group:" + label_user_search: "Search for user:" + field_visible: Visible + setting_commit_logtime_activity_id: Activity for logged time + text_time_logged_by_changeset: Applied in changeset %{value}. + setting_commit_logtime_enabled: Enable time logging + notice_gantt_chart_truncated: The chart was truncated because it exceeds the maximum number of items that can be displayed (%{max}) + setting_gantt_items_limit: Maximum number of items displayed on the gantt chart + field_warn_on_leaving_unsaved: Warn me when leaving a page with unsaved text + text_warn_on_leaving_unsaved: The current page contains unsaved text that will be lost if you leave this page. + label_my_queries: My custom queries + text_journal_changed_no_detail: "%{label} updated" + label_news_comment_added: Comment added to a news + button_expand_all: Expand all + button_collapse_all: Collapse all + label_additional_workflow_transitions_for_assignee: Additional transitions allowed when the user is the assignee + label_additional_workflow_transitions_for_author: Additional transitions allowed when the user is the author + label_bulk_edit_selected_time_entries: Bulk edit selected time entries + text_time_entries_destroy_confirmation: Are you sure you want to delete the selected time entr(y/ies)? + label_role_anonymous: Anonymous + label_role_non_member: Non member + label_issue_note_added: Note added + label_issue_status_updated: Status updated + label_issue_priority_updated: Priority updated + label_issues_visibility_own: Issues created by or assigned to the user + field_issues_visibility: Issues visibility + label_issues_visibility_all: All issues + permission_set_own_issues_private: Set own issues public or private + field_is_private: Private + permission_set_issues_private: Set issues public or private + label_issues_visibility_public: All non private issues + text_issues_destroy_descendants_confirmation: This will also delete %{count} subtask(s). + field_commit_logs_encoding: Codificación das mensaxes de commit + field_scm_path_encoding: Path encoding + text_scm_path_encoding_note: "Default: UTF-8" + field_path_to_repository: Path to repository + field_root_directory: Root directory + field_cvs_module: Module + field_cvsroot: CVSROOT + text_mercurial_repository_note: Local repository (e.g. /hgrepo, c:\hgrepo) + text_scm_command: Command + text_scm_command_version: Version + label_git_report_last_commit: Report last commit for files and directories + notice_issue_successful_create: Issue %{id} created. + label_between: between + setting_issue_group_assignment: Allow issue assignment to groups + label_diff: diff + text_git_repository_note: Repository is bare and local (e.g. /gitrepo, c:\gitrepo) + description_query_sort_criteria_direction: Sort direction + description_project_scope: Search scope + description_filter: Filter + description_user_mail_notification: Mail notification settings + description_date_from: Enter start date + description_message_content: Message content + description_available_columns: Available Columns + description_date_range_interval: Choose range by selecting start and end date + description_issue_category_reassign: Choose issue category + description_search: Searchfield + description_notes: Notes + description_date_range_list: Choose range from list + description_choose_project: Projects + description_date_to: Enter end date + description_query_sort_criteria_attribute: Sort attribute + description_wiki_subpages_reassign: Choose new parent page + description_selected_columns: Selected Columns + label_parent_revision: Parent + label_child_revision: Child + error_scm_annotate_big_text_file: The entry cannot be annotated, as it exceeds the maximum text file size. + setting_default_issue_start_date_to_creation_date: Use current date as start date for new issues + button_edit_section: Edit this section + setting_repositories_encodings: Attachments and repositories encodings + description_all_columns: All Columns + button_export: Export + label_export_options: "%{export_format} export options" + error_attachment_too_big: This file cannot be uploaded because it exceeds the maximum allowed file size (%{max_size}) + notice_failed_to_save_time_entries: "Failed to save %{count} time entrie(s) on %{total} selected: %{ids}." + label_x_issues: + zero: 0 petición + one: 1 petición + other: "%{count} peticións" + label_repository_new: New repository + field_repository_is_default: Main repository + label_copy_attachments: Copy attachments + label_item_position: "%{position}/%{count}" + label_completed_versions: Completed versions + text_project_identifier_info: Only lower case letters (a-z), numbers, dashes and underscores are allowed.
    Once saved, the identifier cannot be changed. + field_multiple: Multiple values + setting_commit_cross_project_ref: Allow issues of all the other projects to be referenced and fixed + text_issue_conflict_resolution_add_notes: Add my notes and discard my other changes + text_issue_conflict_resolution_overwrite: Apply my changes anyway (previous notes will be kept but some changes may be overwritten) + notice_issue_update_conflict: The issue has been updated by an other user while you were editing it. + text_issue_conflict_resolution_cancel: Discard all my changes and redisplay %{link} + permission_manage_related_issues: Manage related issues + field_auth_source_ldap_filter: LDAP filter + label_search_for_watchers: Search for watchers to add + notice_account_deleted: Your account has been permanently deleted. + setting_unsubscribe: Allow users to delete their own account + button_delete_my_account: Delete my account + text_account_destroy_confirmation: |- + Are you sure you want to proceed? + Your account will be permanently deleted, with no way to reactivate it. + error_session_expired: Your session has expired. Please login again. + text_session_expiration_settings: "Warning: changing these settings may expire the current sessions including yours." + setting_session_lifetime: Session maximum lifetime + setting_session_timeout: Session inactivity timeout + label_session_expiration: Session expiration + permission_close_project: Close / reopen the project + label_show_closed_projects: View closed projects + button_close: Close + button_reopen: Reopen + project_status_active: active + project_status_closed: closed + project_status_archived: archived + text_project_closed: This project is closed and read-only. + notice_user_successful_create: User %{id} created. + field_core_fields: Standard fields + field_timeout: Timeout (in seconds) + setting_thumbnails_enabled: Display attachment thumbnails + setting_thumbnails_size: Thumbnails size (in pixels) + label_status_transitions: Status transitions + label_fields_permissions: Fields permissions + label_readonly: Read-only + label_required: Required + text_repository_identifier_info: Only lower case letters (a-z), numbers, dashes and underscores are allowed.
    Once saved, the identifier cannot be changed. + field_board_parent: Parent forum + label_attribute_of_project: Project's %{name} + label_attribute_of_author: Author's %{name} + label_attribute_of_assigned_to: Assignee's %{name} + label_attribute_of_fixed_version: Target version's %{name} + label_copy_subtasks: Copy subtasks + label_copied_to: copied to + label_copied_from: copied from + label_any_issues_in_project: any issues in project + label_any_issues_not_in_project: any issues not in project + field_private_notes: Private notes + permission_view_private_notes: View private notes + permission_set_notes_private: Set notes as private + label_no_issues_in_project: no issues in project + label_any: todos + label_last_n_weeks: last %{count} weeks + setting_cross_project_subtasks: Allow cross-project subtasks + label_cross_project_descendants: With subprojects + label_cross_project_tree: With project tree + label_cross_project_hierarchy: With project hierarchy + label_cross_project_system: With all projects + button_hide: Hide + setting_non_working_week_days: Non-working days + label_in_the_next_days: in the next + label_in_the_past_days: in the past + label_attribute_of_user: User's %{name} + text_turning_multiple_off: If you disable multiple values, multiple values will be + removed in order to preserve only one value per item. + label_attribute_of_issue: Issue's %{name} + permission_add_documents: Add documents + permission_edit_documents: Edit documents + permission_delete_documents: Delete documents + label_gantt_progress_line: Progress line + setting_jsonp_enabled: Enable JSONP support + field_inherit_members: Inherit members + field_closed_on: Closed + setting_default_projects_tracker_ids: Default trackers for new projects + label_total_time: Total + text_scm_config: You can configure your SCM commands in config/configuration.yml. Please restart the application after editing it. + text_scm_command_not_available: SCM command is not available. Please check settings on the administration panel. + setting_emails_header: Email header diff --git a/config/locales/he.yml b/config/locales/he.yml new file mode 100644 index 00000000..c7ace5a9 --- /dev/null +++ b/config/locales/he.yml @@ -0,0 +1,1094 @@ +# Hebrew translation for Redmine +# Initiated by Dotan Nahum (dipidi@gmail.com) +# Jul 2010 - Updated by Orgad Shaneh (orgads@gmail.com) + +he: + direction: rtl + date: + formats: + default: "%d/%m/%Y" + short: "%d/%m" + long: "%d/%m/%Y" + only_day: "%e" + + day_names: [ראשון, שני, שלישי, רביעי, חמישי, שישי, שבת] + abbr_day_names: ["א'", "ב'", "ג'", "ד'", "ה'", "ו'", "ש'"] + month_names: [~, ינואר, פברואר, מרץ, אפריל, מאי, יוני, יולי, אוגוסט, ספטמבר, אוקטובר, נובמבר, דצמבר] + abbr_month_names: [~, יאנ, פבר, מרץ, אפר, מאי, יונ, יול, אוג, ספט, אוק, נוב, דצמ] + order: + - :day + - :month + - :year + + time: + formats: + default: "%a %d/%m/%Y %H:%M:%S" + time: "%H:%M" + short: "%d %b %H:%M" + long: "%B %d, %Y %H:%M" + only_second: "%S" + + datetime: + formats: + default: "%d-%m-%YT%H:%M:%S%Z" + + am: 'am' + pm: 'pm' + + datetime: + distance_in_words: + half_a_minute: 'חצי דקה' + less_than_x_seconds: + zero: 'פחות משניה' + one: 'פחות משניה' + other: 'פחות מ־%{count} שניות' + x_seconds: + one: 'שניה אחת' + other: '%{count} שניות' + less_than_x_minutes: + zero: 'פחות מדקה אחת' + one: 'פחות מדקה אחת' + other: 'פחות מ־%{count} דקות' + x_minutes: + one: 'דקה אחת' + other: '%{count} דקות' + about_x_hours: + one: 'בערך שעה אחת' + other: 'בערך %{count} שעות' + x_hours: + one: "1 hour" + other: "%{count} hours" + x_days: + one: 'יום אחד' + other: '%{count} ימים' + about_x_months: + one: 'בערך חודש אחד' + other: 'בערך %{count} חודשים' + x_months: + one: 'חודש אחד' + other: '%{count} חודשים' + about_x_years: + one: 'בערך שנה אחת' + other: 'בערך %{count} שנים' + over_x_years: + one: 'מעל שנה אחת' + other: 'מעל %{count} שנים' + almost_x_years: + one: "כמעט שנה" + other: "כמעט %{count} שנים" + + number: + format: + precision: 3 + separator: '.' + delimiter: ',' + currency: + format: + unit: 'ש"ח' + precision: 2 + format: '%u %n' + human: + storage_units: + format: "%n %u" + units: + byte: + one: "בייט" + other: "בתים" + kb: "KB" + mb: "MB" + gb: "GB" + tb: "TB" + + support: + array: + sentence_connector: "וגם" + skip_last_comma: true + + activerecord: + errors: + template: + header: + one: "1 error prohibited this %{model} from being saved" + other: "%{count} errors prohibited this %{model} from being saved" + messages: + inclusion: "לא נכלל ברשימה" + exclusion: "לא זמין" + invalid: "לא ולידי" + confirmation: "לא תואם לאישור" + accepted: "חייב באישור" + empty: "חייב להכלל" + blank: "חייב להכלל" + too_long: "ארוך מדי (לא יותר מ־%{count} תוים)" + too_short: "קצר מדי (לא יותר מ־%{count} תוים)" + wrong_length: "לא באורך הנכון (חייב להיות %{count} תוים)" + taken: "לא זמין" + not_a_number: "הוא לא מספר" + greater_than: "חייב להיות גדול מ־%{count}" + greater_than_or_equal_to: "חייב להיות גדול או שווה ל־%{count}" + equal_to: "חייב להיות שווה ל־%{count}" + less_than: "חייב להיות קטן מ־%{count}" + less_than_or_equal_to: "חייב להיות קטן או שווה ל־%{count}" + odd: "חייב להיות אי זוגי" + even: "חייב להיות זוגי" + greater_than_start_date: "חייב להיות מאוחר יותר מתאריך ההתחלה" + not_same_project: "לא שייך לאותו הפרויקט" + circular_dependency: "קשר זה יצור תלות מעגלית" + cant_link_an_issue_with_a_descendant: "לא ניתן לקשר נושא לתת־משימה שלו" + + actionview_instancetag_blank_option: בחר בבקשה + + general_text_No: 'לא' + general_text_Yes: 'כן' + general_text_no: 'לא' + general_text_yes: 'כן' + general_lang_name: 'Hebrew (עברית)' + general_csv_separator: ',' + general_csv_decimal_separator: '.' + general_csv_encoding: ISO-8859-8 + general_pdf_encoding: UTF-8 + general_first_day_of_week: '7' + + notice_account_updated: החשבון עודכן בהצלחה! + notice_account_invalid_creditentials: שם משתמש או סיסמה שגויים + notice_account_password_updated: הסיסמה עודכנה בהצלחה! + notice_account_wrong_password: סיסמה שגויה + notice_account_register_done: החשבון נוצר בהצלחה. להפעלת החשבון לחץ על הקישור שנשלח לדוא"ל שלך. + notice_account_unknown_email: משתמש לא מוכר. + notice_can_t_change_password: החשבון הזה משתמש במקור הזדהות חיצוני. שינוי סיסמה הינו בילתי אפשר + notice_account_lost_email_sent: דוא"ל עם הוראות לבחירת סיסמה חדשה נשלח אליך. + notice_account_activated: חשבונך הופעל. אתה יכול להתחבר כעת. + notice_successful_create: יצירה מוצלחת. + notice_successful_update: עידכון מוצלח. + notice_successful_delete: מחיקה מוצלחת. + notice_successful_connection: חיבור מוצלח. + notice_file_not_found: הדף שאתה מנסה לגשת אליו אינו קיים או שהוסר. + notice_locking_conflict: המידע עודכן על ידי משתמש אחר. + notice_not_authorized: אינך מורשה לראות דף זה. + notice_not_authorized_archived_project: הפרויקט שאתה מנסה לגשת אליו נמצא בארכיון. + notice_email_sent: "דואל נשלח לכתובת %{value}" + notice_email_error: "ארעה שגיאה בעת שליחת הדואל (%{value})" + notice_feeds_access_key_reseted: מפתח ה־RSS שלך אופס. + notice_api_access_key_reseted: מפתח הגישה שלך ל־API אופס. + notice_failed_to_save_issues: "נכשרת בשמירת %{count} נושאים ב %{total} נבחרו: %{ids}." + notice_failed_to_save_members: "כשלון בשמירת חבר(ים): %{errors}." + notice_no_issue_selected: "לא נבחר אף נושא! בחר בבקשה את הנושאים שברצונך לערוך." + notice_account_pending: "החשבון שלך נוצר ועתה מחכה לאישור מנהל המערכת." + notice_default_data_loaded: אפשרויות ברירת מחדל מופעלות. + notice_unable_delete_version: לא ניתן למחוק גירסה + notice_unable_delete_time_entry: לא ניתן למחוק רשומת זמן. + notice_issue_done_ratios_updated: אחוזי התקדמות לנושא עודכנו. + + error_can_t_load_default_data: "אפשרויות ברירת המחדל לא הצליחו להיטען: %{value}" + error_scm_not_found: כניסה ו\או מהדורה אינם קיימים במאגר. + error_scm_command_failed: "ארעה שגיאה בעת ניסון גישה למאגר: %{value}" + error_scm_annotate: "הכניסה לא קיימת או שלא ניתן לתאר אותה." + error_issue_not_found_in_project: 'הנושאים לא נמצאו או אינם שיכים לפרויקט' + error_no_tracker_in_project: לא הוגדר סיווג לפרויקט זה. נא בדוק את הגדרות הפרויקט. + error_no_default_issue_status: לא מוגדר מצב ברירת מחדל לנושאים. נא בדוק את התצורה ("ניהול -> מצבי נושא"). + error_can_not_delete_custom_field: לא ניתן למחוק שדה מותאם אישית + error_can_not_delete_tracker: קיימים נושאים בסיווג זה, ולא ניתן למחוק אותו. + error_can_not_remove_role: תפקיד זה נמצא בשימוש, ולא ניתן למחוק אותו. + error_can_not_reopen_issue_on_closed_version: לא ניתן לפתוח מחדש נושא שמשויך לגירסה סגורה + error_can_not_archive_project: לא ניתן לארכב פרויקט זה + error_issue_done_ratios_not_updated: אחוז התקדמות לנושא לא עודכן. + error_workflow_copy_source: נא בחר סיווג או תפקיד מקור + error_workflow_copy_target: נא בחר תפקיד(ים) וסיווג(ים) + error_unable_delete_issue_status: לא ניתן למחוק מצב נושא + error_unable_to_connect: לא ניתן להתחבר (%{value}) + warning_attachments_not_saved: "כשלון בשמירת %{count} קבצים." + + mail_subject_lost_password: "סיסמת ה־%{value} שלך" + mail_body_lost_password: 'לשינו סיסמת ה־Redmine שלך, לחץ על הקישור הבא:' + mail_subject_register: "הפעלת חשבון %{value}" + mail_body_register: 'להפעלת חשבון ה־Redmine שלך, לחץ על הקישור הבא:' + mail_body_account_information_external: "אתה יכול להשתמש בחשבון %{value} כדי להתחבר" + mail_body_account_information: פרטי החשבון שלך + mail_subject_account_activation_request: "בקשת הפעלה לחשבון %{value}" + mail_body_account_activation_request: "משתמש חדש (%{value}) נרשם. החשבון שלו מחכה לאישור שלך:" + mail_subject_reminder: "%{count} נושאים מיועדים להגשה בימים הקרובים (%{days})" + mail_body_reminder: "%{count} נושאים שמיועדים אליך מיועדים להגשה בתוך %{days} ימים:" + mail_subject_wiki_content_added: "דף ה־wiki ‏'%{id}' נוסף" + mail_body_wiki_content_added: דף ה־wiki ‏'%{id}' נוסף ע"י %{author}. + mail_subject_wiki_content_updated: "דף ה־wiki ‏'%{id}' עודכן" + mail_body_wiki_content_updated: דף ה־wiki ‏'%{id}' עודכן ע"י %{author}. + + + field_name: שם + field_description: תיאור + field_summary: תקציר + field_is_required: נדרש + field_firstname: שם פרטי + field_lastname: שם משפחה + field_mail: דוא"ל + field_filename: קובץ + field_filesize: גודל + field_downloads: הורדות + field_author: כותב + field_created_on: נוצר + field_updated_on: עודכן + field_field_format: פורמט + field_is_for_all: לכל הפרויקטים + field_possible_values: ערכים אפשריים + field_regexp: ביטוי רגיל + field_min_length: אורך מינימאלי + field_max_length: אורך מקסימאלי + field_value: ערך + field_category: קטגוריה + field_title: כותרת + field_project: פרויקט + field_issue: נושא + field_status: מצב + field_notes: הערות + field_is_closed: נושא סגור + field_is_default: ערך ברירת מחדל + field_tracker: סיווג + field_subject: שם נושא + field_due_date: תאריך סיום + field_assigned_to: אחראי + field_priority: עדיפות + field_fixed_version: גירסת יעד + field_user: מתשמש + field_principal: מנהל + field_role: תפקיד + field_homepage: דף הבית + field_is_public: פומבי + field_parent: תת פרויקט של + field_is_in_roadmap: נושאים המוצגים במפת הדרכים + field_login: שם משתמש + field_mail_notification: הודעות דוא"ל + field_admin: ניהול + field_last_login_on: התחברות אחרונה + field_language: שפה + field_effective_date: תאריך + field_password: סיסמה + field_new_password: סיסמה חדשה + field_password_confirmation: אישור + field_version: גירסה + field_type: סוג + field_host: שרת + field_port: פורט + field_account: חשבון + field_base_dn: בסיס DN + field_attr_login: תכונת התחברות + field_attr_firstname: תכונת שם פרטים + field_attr_lastname: תכונת שם משפחה + field_attr_mail: תכונת דוא"ל + field_onthefly: יצירת משתמשים זריזה + field_start_date: תאריך התחלה + field_done_ratio: "% גמור" + field_auth_source: מקור הזדהות + field_hide_mail: החבא את כתובת הדוא"ל שלי + field_comments: הערות + field_url: URL + field_start_page: דף התחלתי + field_subproject: תת־פרויקט + field_hours: שעות + field_activity: פעילות + field_spent_on: תאריך + field_identifier: מזהה + field_is_filter: משמש כמסנן + field_issue_to: נושאים קשורים + field_delay: עיקוב + field_assignable: ניתן להקצות נושאים לתפקיד זה + field_redirect_existing_links: העבר קישורים קיימים + field_estimated_hours: זמן משוער + field_column_names: עמודות + field_time_entries: רישום זמנים + field_time_zone: איזור זמן + field_searchable: ניתן לחיפוש + field_default_value: ערך ברירת מחדל + field_comments_sorting: הצג הערות + field_parent_title: דף אב + field_editable: ניתן לעריכה + field_watcher: צופה + field_identity_url: כתובת OpenID + field_content: תוכן + field_group_by: קבץ את התוצאות לפי + field_sharing: שיתוף + field_parent_issue: משימת אב + field_text: שדה טקסט + + setting_app_title: כותרת ישום + setting_app_subtitle: תת־כותרת ישום + setting_welcome_text: טקסט "ברוך הבא" + setting_default_language: שפת ברירת מחדל + setting_login_required: דרושה הזדהות + setting_self_registration: אפשר הרשמה עצמית + setting_attachment_max_size: גודל דבוקה מקסימאלי + setting_issues_export_limit: גבול יצוא נושאים + setting_mail_from: כתובת שליחת דוא"ל + setting_bcc_recipients: מוסתר (bcc) + setting_plain_text_mail: טקסט פשוט בלבד (ללא HTML) + setting_host_name: שם שרת + setting_text_formatting: עיצוב טקסט + setting_wiki_compression: כיווץ היסטורית wiki + setting_feeds_limit: גבול תוכן הזנות + setting_default_projects_public: פרויקטים חדשים הינם פומביים כברירת מחדל + setting_autofetch_changesets: משיכה אוטומטית של שינויים + setting_sys_api_enabled: אפשר שירות רשת לניהול המאגר + setting_commit_ref_keywords: מילות מפתח מקשרות + setting_commit_fix_keywords: מילות מפתח מתקנות + setting_autologin: התחברות אוטומטית + setting_date_format: פורמט תאריך + setting_time_format: פורמט זמן + setting_cross_project_issue_relations: הרשה קישור נושאים בין פרויקטים + setting_issue_list_default_columns: עמודות ברירת מחדל המוצגות ברשימת הנושאים + setting_emails_footer: תחתית דוא"ל + setting_protocol: פרוטוקול + setting_per_page_options: אפשרויות אוביקטים לפי דף + setting_user_format: פורמט הצגת משתמשים + setting_activity_days_default: ימים המוצגים על פעילות הפרויקט + setting_display_subprojects_issues: הצג נושאים של תתי־פרויקטים כברירת מחדל + setting_enabled_scm: אפשר ניהול תצורה + setting_mail_handler_body_delimiters: חתוך כתובות דואר אחרי אחת משורות אלה + setting_mail_handler_api_enabled: אפשר שירות רשת לדואר נכנס + setting_mail_handler_api_key: מפתח API + setting_sequential_project_identifiers: השתמש במספרים עוקבים למזהי פרויקט + setting_gravatar_enabled: שימוש בצלמיות משתמשים מ־Gravatar + setting_gravatar_default: תמונת Gravatar ברירת מחדל + setting_diff_max_lines_displayed: מספר מירבי של שורות בתצוגת שינויים + setting_file_max_size_displayed: גודל מירבי של מלל המוצג בתוך השורה + setting_repository_log_display_limit: מספר מירבי של מהדורות המוצגות ביומן קובץ + setting_openid: אפשר התחברות ורישום באמצעות OpenID + setting_password_min_length: אורך סיסמה מינימאלי + setting_new_project_user_role_id: התפקיד שמוגדר למשתמש פשוט אשר יוצר פרויקט + setting_default_projects_modules: מודולים מאופשרים בברירת מחדל עבור פרויקטים חדשים + setting_issue_done_ratio: חשב אחוז התקדמות בנושא עם + setting_issue_done_ratio_issue_field: השתמש בשדה הנושא + setting_issue_done_ratio_issue_status: השתמש במצב הנושא + setting_start_of_week: השבוע מתחיל ביום + setting_rest_api_enabled: אפשר שירות רשת REST + setting_cache_formatted_text: שמור טקסט מעוצב במטמון + setting_default_notification_option: אפשרות התראה ברירת־מחדל + + permission_add_project: יצירת פרויקט + permission_add_subprojects: יצירת תתי־פרויקט + permission_edit_project: עריכת פרויקט + permission_select_project_modules: בחירת מודולי פרויקט + permission_manage_members: ניהול חברים + permission_manage_project_activities: נהל פעילויות פרויקט + permission_manage_versions: ניהול גירסאות + permission_manage_categories: ניהול קטגוריות נושאים + permission_view_issues: צפיה בנושאים + permission_add_issues: הוספת נושא + permission_edit_issues: עריכת נושאים + permission_manage_issue_relations: ניהול קשרים בין נושאים + permission_add_issue_notes: הוספת הערות לנושאים + permission_edit_issue_notes: עריכת רשימות + permission_edit_own_issue_notes: עריכת הערות של עצמו + permission_move_issues: הזזת נושאים + permission_delete_issues: מחיקת נושאים + permission_manage_public_queries: ניהול שאילתות פומביות + permission_save_queries: שמירת שאילתות + permission_view_gantt: צפיה בגאנט + permission_view_calendar: צפיה בלוח השנה + permission_view_issue_watchers: צפיה ברשימת צופים + permission_add_issue_watchers: הוספת צופים + permission_delete_issue_watchers: הסרת צופים + permission_log_time: תיעוד זמן שהושקע + permission_view_time_entries: צפיה ברישום זמנים + permission_edit_time_entries: עריכת רישום זמנים + permission_edit_own_time_entries: עריכת רישום הזמנים של עצמו + permission_manage_news: ניהול חדשות + permission_comment_news: תגובה לחדשות + permission_view_documents: צפיה במסמכים + permission_manage_files: ניהול קבצים + permission_view_files: צפיה בקבצים + permission_manage_wiki: ניהול wiki + permission_rename_wiki_pages: שינוי שם של דפי wiki + permission_delete_wiki_pages: מחיקת דפי wiki + permission_view_wiki_pages: צפיה ב־wiki + permission_view_wiki_edits: צפיה בהיסטורית wiki + permission_edit_wiki_pages: עריכת דפי wiki + permission_delete_wiki_pages_attachments: מחיקת דבוקות + permission_protect_wiki_pages: הגנה על כל דפי wiki + permission_manage_repository: ניהול מאגר + permission_browse_repository: סיור במאגר + permission_view_changesets: צפיה בסדרות שינויים + permission_commit_access: אישור הפקדות + permission_manage_boards: ניהול לוחות + permission_view_messages: צפיה בהודעות + permission_add_messages: הצבת הודעות + permission_edit_messages: עריכת הודעות + permission_edit_own_messages: עריכת הודעות של עצמו + permission_delete_messages: מחיקת הודעות + permission_delete_own_messages: מחיקת הודעות של עצמו + permission_export_wiki_pages: יצא דפי wiki + permission_manage_subtasks: נהל תתי־משימות + + project_module_issue_tracking: מעקב נושאים + project_module_time_tracking: מעקב אחר זמנים + project_module_news: חדשות + project_module_documents: מסמכים + project_module_files: קבצים + project_module_wiki: Wiki + project_module_repository: מאגר + project_module_boards: לוחות + project_module_calendar: לוח שנה + project_module_gantt: גאנט + + label_user: משתמש + label_user_plural: משתמשים + label_user_new: משתמש חדש + label_user_anonymous: אלמוני + label_project: פרויקט + label_project_new: פרויקט חדש + label_project_plural: פרויקטים + label_x_projects: + zero: ללא פרויקטים + one: פרויקט אחד + other: "%{count} פרויקטים" + label_project_all: כל הפרויקטים + label_project_latest: הפרויקטים החדשים ביותר + label_issue: נושא + label_issue_new: נושא חדש + label_issue_plural: נושאים + label_issue_view_all: צפה בכל הנושאים + label_issues_by: "נושאים לפי %{value}" + label_issue_added: נושא נוסף + label_issue_updated: נושא עודכן + label_document: מסמך + label_document_new: מסמך חדש + label_document_plural: מסמכים + label_document_added: מסמך נוסף + label_role: תפקיד + label_role_plural: תפקידים + label_role_new: תפקיד חדש + label_role_and_permissions: תפקידים והרשאות + label_member: חבר + label_member_new: חבר חדש + label_member_plural: חברים + label_tracker: סיווג + label_tracker_plural: סיווגים + label_tracker_new: סיווג חדש + label_workflow: זרימת עבודה + label_issue_status: מצב נושא + label_issue_status_plural: מצבי נושא + label_issue_status_new: מצב חדש + label_issue_category: קטגורית נושא + label_issue_category_plural: קטגוריות נושא + label_issue_category_new: קטגוריה חדשה + label_custom_field: שדה אישי + label_custom_field_plural: שדות אישיים + label_custom_field_new: שדה אישי חדש + label_enumerations: אינומרציות + label_enumeration_new: ערך חדש + label_information: מידע + label_information_plural: מידע + label_please_login: נא התחבר + label_register: הרשמה + label_login_with_open_id_option: או התחבר באמצעות OpenID + label_password_lost: אבדה הסיסמה? + label_home: דף הבית + label_my_page: הדף שלי + label_my_account: החשבון שלי + label_my_projects: הפרויקטים שלי + label_my_page_block: בלוק הדף שלי + label_administration: ניהול + label_login: התחבר + label_logout: התנתק + label_help: עזרה + label_reported_issues: נושאים שדווחו + label_assigned_to_me_issues: נושאים שהוצבו לי + label_last_login: התחברות אחרונה + label_registered_on: נרשם בתאריך + label_activity: פעילות + label_overall_activity: פעילות כוללת + label_user_activity: "הפעילות של %{value}" + label_new: חדש + label_logged_as: מחובר כ + label_environment: סביבה + label_authentication: הזדהות + label_auth_source: מקור הזדהות + label_auth_source_new: מקור הזדהות חדש + label_auth_source_plural: מקורות הזדהות + label_subproject_plural: תת־פרויקטים + label_subproject_new: תת־פרויקט חדש + label_and_its_subprojects: "%{value} וכל תתי־הפרויקטים שלו" + label_min_max_length: אורך מינימאלי - מקסימאלי + label_list: רשימה + label_date: תאריך + label_integer: מספר שלם + label_float: צף + label_boolean: ערך בוליאני + label_string: טקסט + label_text: טקסט ארוך + label_attribute: תכונה + label_attribute_plural: תכונות + label_no_data: אין מידע להציג + label_change_status: שנה מצב + label_history: היסטוריה + label_attachment: קובץ + label_attachment_new: קובץ חדש + label_attachment_delete: מחק קובץ + label_attachment_plural: קבצים + label_file_added: קובץ נוסף + label_report: דו"ח + label_report_plural: דו"חות + label_news: חדשות + label_news_new: הוסף חדשות + label_news_plural: חדשות + label_news_latest: חדשות אחרונות + label_news_view_all: צפה בכל החדשות + label_news_added: חדשות נוספו + label_settings: הגדרות + label_overview: מבט רחב + label_version: גירסה + label_version_new: גירסה חדשה + label_version_plural: גירסאות + label_close_versions: סגור גירסאות שהושלמו + label_confirmation: אישור + label_export_to: יצא ל + label_read: קרא... + label_public_projects: פרויקטים פומביים + label_open_issues: פתוח + label_open_issues_plural: פתוחים + label_closed_issues: סגור + label_closed_issues_plural: סגורים + label_x_open_issues_abbr_on_total: + zero: 0 פתוחים / %{total} + one: 1 פתוח / %{total} + other: "%{count} פתוחים / %{total}" + label_x_open_issues_abbr: + zero: 0 פתוחים + one: 1 פתוח + other: "%{count} פתוחים" + label_x_closed_issues_abbr: + zero: 0 סגורים + one: 1 סגור + other: "%{count} סגורים" + label_total: סה"כ + label_permissions: הרשאות + label_current_status: מצב נוכחי + label_new_statuses_allowed: מצבים חדשים אפשריים + label_all: הכל + label_none: כלום + label_nobody: אף אחד + label_next: הבא + label_previous: הקודם + label_used_by: בשימוש ע"י + label_details: פרטים + label_add_note: הוסף הערה + label_per_page: לכל דף + label_calendar: לוח שנה + label_months_from: חודשים מ + label_gantt: גאנט + label_internal: פנימי + label_last_changes: "%{count} שינוים אחרונים" + label_change_view_all: צפה בכל השינוים + label_personalize_page: התאם אישית דף זה + label_comment: תגובה + label_comment_plural: תגובות + label_x_comments: + zero: אין הערות + one: הערה אחת + other: "%{count} הערות" + label_comment_add: הוסף תגובה + label_comment_added: תגובה נוספה + label_comment_delete: מחק תגובות + label_query: שאילתה אישית + label_query_plural: שאילתות אישיות + label_query_new: שאילתה חדשה + label_filter_add: הוסף מסנן + label_filter_plural: מסננים + label_equals: הוא + label_not_equals: הוא לא + label_in_less_than: בפחות מ + label_in_more_than: ביותר מ + label_greater_or_equal: ">=" + label_less_or_equal: <= + label_in: ב + label_today: היום + label_all_time: תמיד + label_yesterday: אתמול + label_this_week: השבוע + label_last_week: השבוע שעבר + label_last_n_days: "ב־%{count} ימים אחרונים" + label_this_month: החודש + label_last_month: חודש שעבר + label_this_year: השנה + label_date_range: טווח תאריכים + label_less_than_ago: פחות מ + label_more_than_ago: יותר מ + label_ago: לפני + label_contains: מכיל + label_not_contains: לא מכיל + label_day_plural: ימים + label_repository: מאגר + label_repository_plural: מאגרים + label_browse: סייר + label_branch: ענף + label_tag: סימון + label_revision: מהדורה + label_revision_plural: מהדורות + label_revision_id: מהדורה %{value} + label_associated_revisions: מהדורות קשורות + label_added: נוסף + label_modified: שונה + label_copied: הועתק + label_renamed: השם שונה + label_deleted: נמחק + label_latest_revision: מהדורה אחרונה + label_latest_revision_plural: מהדורות אחרונות + label_view_revisions: צפה במהדורות + label_view_all_revisions: צפה בכל המהדורות + label_max_size: גודל מקסימאלי + label_sort_highest: הזז לראשית + label_sort_higher: הזז למעלה + label_sort_lower: הזז למטה + label_sort_lowest: הזז לתחתית + label_roadmap: מפת הדרכים + label_roadmap_due_in: "נגמר בעוד %{value}" + label_roadmap_overdue: "%{value} מאחר" + label_roadmap_no_issues: אין נושאים לגירסה זו + label_search: חפש + label_result_plural: תוצאות + label_all_words: כל המילים + label_wiki: Wiki + label_wiki_edit: ערוך wiki + label_wiki_edit_plural: עריכות wiki + label_wiki_page: דף Wiki + label_wiki_page_plural: דפי wiki + label_index_by_title: סדר על פי כותרת + label_index_by_date: סדר על פי תאריך + label_current_version: גירסה נוכחית + label_preview: תצוגה מקדימה + label_feed_plural: הזנות + label_changes_details: פירוט כל השינויים + label_issue_tracking: מעקב אחר נושאים + label_spent_time: זמן שהושקע + label_overall_spent_time: זמן שהושקע סה"כ + label_f_hour: "%{value} שעה" + label_f_hour_plural: "%{value} שעות" + label_time_tracking: מעקב זמנים + label_change_plural: שינויים + label_statistics: סטטיסטיקות + label_commits_per_month: הפקדות לפי חודש + label_commits_per_author: הפקדות לפי כותב + label_view_diff: צפה בשינויים + label_diff_inline: בתוך השורה + label_diff_side_by_side: צד לצד + label_options: אפשרויות + label_copy_workflow_from: העתק זירמת עבודה מ + label_permissions_report: דו"ח הרשאות + label_watched_issues: נושאים שנצפו + label_related_issues: נושאים קשורים + label_applied_status: מצב מוחל + label_loading: טוען... + label_relation_new: קשר חדש + label_relation_delete: מחק קשר + label_relates_to: קשור ל + label_duplicates: מכפיל את + label_duplicated_by: שוכפל ע"י + label_blocks: חוסם את + label_blocked_by: חסום ע"י + label_precedes: מקדים את + label_follows: עוקב אחרי + label_end_to_start: מהתחלה לסוף + label_end_to_end: מהסוף לסוף + label_start_to_start: מהתחלה להתחלה + label_start_to_end: מהתחלה לסוף + label_stay_logged_in: השאר מחובר + label_disabled: מבוטל + label_show_completed_versions: הצג גירסאות גמורות + label_me: אני + label_board: פורום + label_board_new: פורום חדש + label_board_plural: פורומים + label_board_locked: נעול + label_board_sticky: דביק + label_topic_plural: נושאים + label_message_plural: הודעות + label_message_last: הודעה אחרונה + label_message_new: הודעה חדשה + label_message_posted: הודעה נוספה + label_reply_plural: השבות + label_send_information: שלח מידע על חשבון למשתמש + label_year: שנה + label_month: חודש + label_week: שבוע + label_date_from: מתאריך + label_date_to: עד + label_language_based: מבוסס שפה + label_sort_by: "מיין לפי %{value}" + label_send_test_email: שלח דוא"ל בדיקה + label_feeds_access_key: מפתח גישה ל־RSS + label_missing_feeds_access_key: חסר מפתח גישה ל־RSS + label_feeds_access_key_created_on: "מפתח הזנת RSS נוצר לפני%{value}" + label_module_plural: מודולים + label_added_time_by: 'נוסף ע"י %{author} לפני %{age}' + label_updated_time_by: 'עודכן ע"י %{author} לפני %{age}' + label_updated_time: "עודכן לפני %{value} " + label_jump_to_a_project: קפוץ לפרויקט... + label_file_plural: קבצים + label_changeset_plural: סדרות שינויים + label_default_columns: עמודת ברירת מחדל + label_no_change_option: (אין שינוים) + label_bulk_edit_selected_issues: ערוך את הנושאים המסומנים + label_theme: ערכת נושא + label_default: ברירת מחדל + label_search_titles_only: חפש בכותרות בלבד + label_user_mail_option_all: "לכל אירוע בכל הפרויקטים שלי" + label_user_mail_option_selected: "לכל אירוע בפרויקטים שבחרתי בלבד..." + label_user_mail_option_only_my_events: עבור דברים שאני צופה או מעורב בהם בלבד + label_user_mail_option_only_assigned: עבור דברים שאני אחראי עליהם בלבד + label_user_mail_option_only_owner: עבור דברים שאני הבעלים שלהם בלבד + label_user_mail_no_self_notified: "אני לא רוצה שיודיעו לי על שינויים שאני מבצע" + label_registration_activation_by_email: הפעל חשבון באמצעות דוא"ל + label_registration_manual_activation: הפעלת חשבון ידנית + label_registration_automatic_activation: הפעלת חשבון אוטומטית + label_display_per_page: "בכל דף: %{value} תוצאות" + label_age: גיל + label_change_properties: שנה מאפיינים + label_general: כללי + label_more: עוד + label_scm: מערכת ניהול תצורה + label_plugins: תוספים + label_ldap_authentication: הזדהות LDAP + label_downloads_abbr: D/L + label_optional_description: תיאור רשות + label_add_another_file: הוסף עוד קובץ + label_preferences: העדפות + label_chronological_order: בסדר כרונולוגי + label_reverse_chronological_order: בסדר כרונולוגי הפוך + label_planning: תכנון + label_incoming_emails: דוא"ל נכנס + label_generate_key: צור מפתח + label_issue_watchers: צופים + label_example: דוגמא + label_display: תצוגה + label_sort: מיון + label_ascending: בסדר עולה + label_descending: בסדר יורד + label_date_from_to: 'מתאריך %{start} ועד תאריך %{end}' + label_wiki_content_added: נוסף דף ל־wiki + label_wiki_content_updated: דף wiki עודכן + label_group: קבוצה + label_group_plural: קבוצות + label_group_new: קבוצה חדשה + label_time_entry_plural: זמן שהושקע + label_version_sharing_none: לא משותף + label_version_sharing_descendants: עם פרויקטים בנים + label_version_sharing_hierarchy: עם היררכית הפרויקטים + label_version_sharing_tree: עם עץ הפרויקט + label_version_sharing_system: עם כל הפרויקטים + label_update_issue_done_ratios: עדכן אחוז התקדמות לנושא + label_copy_source: מקור + label_copy_target: יעד + label_copy_same_as_target: זהה ליעד + label_display_used_statuses_only: הצג רק את המצבים בשימוש לסיווג זה + label_api_access_key: מפתח גישה ל־API + label_missing_api_access_key: חסר מפתח גישה ל־API + label_api_access_key_created_on: 'מפתח גישה ל־API נוצר לפני %{value}' + label_profile: פרופיל + label_subtask_plural: תתי־משימות + label_project_copy_notifications: שלח התראות דואר במהלך העתקת הפרויקט + + button_login: התחבר + button_submit: אשר + button_save: שמור + button_check_all: בחר הכל + button_uncheck_all: בחר כלום + button_delete: מחק + button_create: צור + button_create_and_continue: צור ופתח חדש + button_test: בדוק + button_edit: ערוך + button_edit_associated_wikipage: "ערוך דף wiki מקושר: %{page_title}" + button_add: הוסף + button_change: שנה + button_apply: החל + button_clear: נקה + button_lock: נעל + button_unlock: בטל נעילה + button_download: הורד + button_list: רשימה + button_view: צפה + button_move: הזז + button_move_and_follow: העבר ועקוב + button_back: הקודם + button_cancel: בטל + button_activate: הפעל + button_sort: מיין + button_log_time: רישום זמנים + button_rollback: חזור למהדורה זו + button_watch: צפה + button_unwatch: בטל צפיה + button_reply: השב + button_archive: ארכיון + button_unarchive: הוצא מהארכיון + button_reset: אפס + button_rename: שנה שם + button_change_password: שנה סיסמה + button_copy: העתק + button_copy_and_follow: העתק ועקוב + button_annotate: הוסף תיאור מסגרת + button_update: עדכן + button_configure: אפשרויות + button_quote: צטט + button_duplicate: שכפל + button_show: הצג + + status_active: פעיל + status_registered: רשום + status_locked: נעול + + version_status_open: פתוח + version_status_locked: נעול + version_status_closed: סגור + + field_active: פעיל + + text_select_mail_notifications: בחר פעולת שבגללן ישלח דוא"ל. + text_regexp_info: כגון. ^[A-Z0-9]+$ + text_min_max_length_info: 0 משמעו ללא הגבלות + text_project_destroy_confirmation: האם אתה בטוח שברצונך למחוק את הפרויקט ואת כל המידע הקשור אליו? + text_subprojects_destroy_warning: "תת־הפרויקטים: %{value} ימחקו גם כן." + text_workflow_edit: בחר תפקיד וסיווג כדי לערוך את זרימת העבודה + text_are_you_sure: האם אתה בטוח? + text_journal_changed: "%{label} השתנה מ%{old} ל%{new}" + text_journal_set_to: "%{label} נקבע ל%{value}" + text_journal_deleted: "%{label} נמחק (%{old})" + text_journal_added: "%{label} %{value} נוסף" + text_tip_issue_begin_day: מטלה המתחילה היום + text_tip_issue_end_day: מטלה המסתיימת היום + text_tip_issue_begin_end_day: מטלה המתחילה ומסתיימת היום + text_caracters_maximum: "מקסימום %{count} תווים." + text_caracters_minimum: "חייב להיות לפחות באורך של %{count} תווים." + text_length_between: "אורך בין %{min} ל %{max} תווים." + text_tracker_no_workflow: זרימת עבודה לא הוגדרה עבור סיווג זה + text_unallowed_characters: תווים לא מורשים + text_comma_separated: הכנסת ערכים מרובים מותרת (מופרדים בפסיקים). + text_line_separated: ניתן להזין מספר ערכים (שורה אחת לכל ערך). + text_issues_ref_in_commit_messages: קישור ותיקום נושאים בהודעות הפקדה + text_issue_added: "הנושא %{id} דווח (בידי %{author})." + text_issue_updated: "הנושא %{id} עודכן (בידי %{author})." + text_wiki_destroy_confirmation: האם אתה בטוח שברצונך למחוק את הWIKI הזה ואת כל תוכנו? + text_issue_category_destroy_question: "כמה נושאים (%{count}) מוצבים לקטגוריה הזו. מה ברצונך לעשות?" + text_issue_category_destroy_assignments: הסר הצבת קטגוריה + text_issue_category_reassign_to: הצב מחדש את הקטגוריה לנושאים + text_user_mail_option: "בפרויקטים שלא בחרת, אתה רק תקבל התרעות על שאתה צופה או קשור אליהם (לדוגמא:נושאים שאתה היוצר שלהם או אחראי עליהם)." + text_no_configuration_data: "לא הוגדרה תצורה עבור תפקידים, סיווגים, מצבי נושא וזרימת עבודה.\nמומלץ מאד לטעון את תצורת ברירת המחדל. תוכל לשנותה מאוחר יותר." + text_load_default_configuration: טען את אפשרויות ברירת המחדל + text_status_changed_by_changeset: "הוחל בסדרת השינויים %{value}." + text_issues_destroy_confirmation: 'האם אתה בטוח שברצונך למחוק את הנושאים?' + text_select_project_modules: 'בחר מודולים להחיל על פרויקט זה:' + text_default_administrator_account_changed: מנהל המערכת ברירת המחדל שונה + text_file_repository_writable: מאגר הקבצים ניתן לכתיבה + text_plugin_assets_writable: ספרית נכסי תוספים ניתנת לכתיבה + text_rmagick_available: RMagick זמין (רשות) + text_destroy_time_entries_question: "%{hours} שעות דווחו על הנושאים שאתה עומד למחוק. מה ברצונך לעשות?" + text_destroy_time_entries: מחק שעות שדווחו + text_assign_time_entries_to_project: הצב שעות שדווחו לפרויקט הזה + text_reassign_time_entries: 'הצב מחדש שעות שדווחו לפרויקט הזה:' + text_user_wrote: "%{value} כתב:" + text_enumeration_destroy_question: "%{count} אוביקטים מוצבים לערך זה." + text_enumeration_category_reassign_to: 'הצב מחדש לערך הזה:' + text_email_delivery_not_configured: 'לא נקבעה תצורה לשליחת דואר, וההתראות כבויות.\nקבע את תצורת שרת ה־SMTP בקובץ /etc/redmine/<instance>/configuration.yml והתחל את האפליקציה מחדש ע"מ לאפשר אותם.' + text_repository_usernames_mapping: "בחר או עדכן את משתמש Redmine הממופה לכל שם משתמש ביומן המאגר.\nמשתמשים בעלי שם או כתובת דואר זהה ב־Redmine ובמאגר ממופים באופן אוטומטי." + text_diff_truncated: '... השינויים עוברים את מספר השורות המירבי לתצוגה, ולכן הם קוצצו.' + text_custom_field_possible_values_info: שורה אחת לכל ערך + text_wiki_page_destroy_question: לדף זה יש %{descendants} דפים בנים ותלויים. מה ברצונך לעשות? + text_wiki_page_nullify_children: השאר דפים בנים כדפים ראשיים + text_wiki_page_destroy_children: מחק את הדפים הבנים ואת כל התלויים בהם + text_wiki_page_reassign_children: הצב מחדש דפים בנים לדף האב הנוכחי + text_own_membership_delete_confirmation: |- + בכוונתך למחוק חלק או את כל ההרשאות שלך. לאחר מכן לא תוכל יותר לערוך פרויקט זה. + האם אתה בטוח שברצונך להמשיך? + text_zoom_in: התקרב + text_zoom_out: התרחק + + default_role_manager: מנהל + default_role_developer: מפתח + default_role_reporter: מדווח + default_tracker_bug: תקלה + default_tracker_feature: יכולת + default_tracker_support: תמיכה + default_issue_status_new: חדש + default_issue_status_in_progress: בעבודה + default_issue_status_resolved: נפתר + default_issue_status_feedback: משוב + default_issue_status_closed: סגור + default_issue_status_rejected: נדחה + default_doc_category_user: תיעוד משתמש + default_doc_category_tech: תיעוד טכני + default_priority_low: נמוכה + default_priority_normal: רגילה + default_priority_high: גבוהה + default_priority_urgent: דחופה + default_priority_immediate: מידית + default_activity_design: עיצוב + default_activity_development: פיתוח + + enumeration_issue_priorities: עדיפות נושאים + enumeration_doc_categories: קטגוריות מסמכים + enumeration_activities: פעילויות (מעקב אחר זמנים) + enumeration_system_activity: פעילות מערכת + label_user_mail_option_none: No events + field_member_of_group: Assignee's group + field_assigned_to_role: Assignee's role + label_principal_search: "Search for user or group:" + label_user_search: "Search for user:" + field_visible: Visible + setting_commit_logtime_activity_id: Activity for logged time + text_time_logged_by_changeset: Applied in changeset %{value}. + setting_commit_logtime_enabled: Enable time logging + notice_gantt_chart_truncated: The chart was truncated because it exceeds the maximum number of items that can be displayed (%{max}) + setting_gantt_items_limit: Maximum number of items displayed on the gantt chart + field_warn_on_leaving_unsaved: Warn me when leaving a page with unsaved text + text_warn_on_leaving_unsaved: The current page contains unsaved text that will be lost if you leave this page. + label_my_queries: My custom queries + text_journal_changed_no_detail: "%{label} updated" + label_news_comment_added: Comment added to a news + button_expand_all: Expand all + button_collapse_all: Collapse all + label_additional_workflow_transitions_for_assignee: Additional transitions allowed when the user is the assignee + label_additional_workflow_transitions_for_author: Additional transitions allowed when the user is the author + label_bulk_edit_selected_time_entries: Bulk edit selected time entries + text_time_entries_destroy_confirmation: Are you sure you want to delete the selected time entr(y/ies)? + label_role_anonymous: Anonymous + label_role_non_member: Non member + label_issue_note_added: Note added + label_issue_status_updated: Status updated + label_issue_priority_updated: Priority updated + label_issues_visibility_own: Issues created by or assigned to the user + field_issues_visibility: Issues visibility + label_issues_visibility_all: All issues + permission_set_own_issues_private: Set own issues public or private + field_is_private: Private + permission_set_issues_private: Set issues public or private + label_issues_visibility_public: All non private issues + text_issues_destroy_descendants_confirmation: This will also delete %{count} subtask(s). + field_commit_logs_encoding: קידוד הודעות הפקדה + field_scm_path_encoding: Path encoding + text_scm_path_encoding_note: "Default: UTF-8" + field_path_to_repository: Path to repository + field_root_directory: Root directory + field_cvs_module: Module + field_cvsroot: CVSROOT + text_mercurial_repository_note: Local repository (e.g. /hgrepo, c:\hgrepo) + text_scm_command: Command + text_scm_command_version: Version + label_git_report_last_commit: Report last commit for files and directories + notice_issue_successful_create: Issue %{id} created. + label_between: between + setting_issue_group_assignment: Allow issue assignment to groups + label_diff: diff + text_git_repository_note: Repository is bare and local (e.g. /gitrepo, c:\gitrepo) + description_query_sort_criteria_direction: Sort direction + description_project_scope: Search scope + description_filter: Filter + description_user_mail_notification: Mail notification settings + description_date_from: Enter start date + description_message_content: Message content + description_available_columns: Available Columns + description_date_range_interval: Choose range by selecting start and end date + description_issue_category_reassign: Choose issue category + description_search: Searchfield + description_notes: Notes + description_date_range_list: Choose range from list + description_choose_project: Projects + description_date_to: Enter end date + description_query_sort_criteria_attribute: Sort attribute + description_wiki_subpages_reassign: Choose new parent page + description_selected_columns: Selected Columns + label_parent_revision: Parent + label_child_revision: Child + error_scm_annotate_big_text_file: The entry cannot be annotated, as it exceeds the maximum text file size. + setting_default_issue_start_date_to_creation_date: Use current date as start date for new issues + button_edit_section: Edit this section + setting_repositories_encodings: Attachments and repositories encodings + description_all_columns: All Columns + button_export: Export + label_export_options: "%{export_format} export options" + error_attachment_too_big: This file cannot be uploaded because it exceeds the maximum allowed file size (%{max_size}) + notice_failed_to_save_time_entries: "Failed to save %{count} time entrie(s) on %{total} selected: %{ids}." + label_x_issues: + zero: 0 נושא + one: 1 נושא + other: "%{count} נושאים" + label_repository_new: New repository + field_repository_is_default: Main repository + label_copy_attachments: Copy attachments + label_item_position: "%{position}/%{count}" + label_completed_versions: Completed versions + text_project_identifier_info: Only lower case letters (a-z), numbers, dashes and underscores are allowed.
    Once saved, the identifier cannot be changed. + field_multiple: Multiple values + setting_commit_cross_project_ref: Allow issues of all the other projects to be referenced and fixed + text_issue_conflict_resolution_add_notes: Add my notes and discard my other changes + text_issue_conflict_resolution_overwrite: Apply my changes anyway (previous notes will be kept but some changes may be overwritten) + notice_issue_update_conflict: The issue has been updated by an other user while you were editing it. + text_issue_conflict_resolution_cancel: Discard all my changes and redisplay %{link} + permission_manage_related_issues: Manage related issues + field_auth_source_ldap_filter: LDAP filter + label_search_for_watchers: Search for watchers to add + notice_account_deleted: Your account has been permanently deleted. + setting_unsubscribe: Allow users to delete their own account + button_delete_my_account: Delete my account + text_account_destroy_confirmation: |- + Are you sure you want to proceed? + Your account will be permanently deleted, with no way to reactivate it. + error_session_expired: Your session has expired. Please login again. + text_session_expiration_settings: "Warning: changing these settings may expire the current sessions including yours." + setting_session_lifetime: Session maximum lifetime + setting_session_timeout: Session inactivity timeout + label_session_expiration: Session expiration + permission_close_project: Close / reopen the project + label_show_closed_projects: View closed projects + button_close: Close + button_reopen: Reopen + project_status_active: active + project_status_closed: closed + project_status_archived: archived + text_project_closed: This project is closed and read-only. + notice_user_successful_create: User %{id} created. + field_core_fields: Standard fields + field_timeout: Timeout (in seconds) + setting_thumbnails_enabled: Display attachment thumbnails + setting_thumbnails_size: Thumbnails size (in pixels) + label_status_transitions: Status transitions + label_fields_permissions: Fields permissions + label_readonly: Read-only + label_required: Required + text_repository_identifier_info: Only lower case letters (a-z), numbers, dashes and underscores are allowed.
    Once saved, the identifier cannot be changed. + field_board_parent: Parent forum + label_attribute_of_project: Project's %{name} + label_attribute_of_author: Author's %{name} + label_attribute_of_assigned_to: Assignee's %{name} + label_attribute_of_fixed_version: Target version's %{name} + label_copy_subtasks: Copy subtasks + label_copied_to: copied to + label_copied_from: copied from + label_any_issues_in_project: any issues in project + label_any_issues_not_in_project: any issues not in project + field_private_notes: Private notes + permission_view_private_notes: View private notes + permission_set_notes_private: Set notes as private + label_no_issues_in_project: no issues in project + label_any: הכל + label_last_n_weeks: last %{count} weeks + setting_cross_project_subtasks: Allow cross-project subtasks + label_cross_project_descendants: עם פרויקטים בנים + label_cross_project_tree: עם עץ הפרויקט + label_cross_project_hierarchy: עם היררכית הפרויקטים + label_cross_project_system: עם כל הפרויקטים + button_hide: Hide + setting_non_working_week_days: Non-working days + label_in_the_next_days: in the next + label_in_the_past_days: in the past + label_attribute_of_user: User's %{name} + text_turning_multiple_off: If you disable multiple values, multiple values will be + removed in order to preserve only one value per item. + label_attribute_of_issue: Issue's %{name} + permission_add_documents: Add documents + permission_edit_documents: Edit documents + permission_delete_documents: Delete documents + label_gantt_progress_line: Progress line + setting_jsonp_enabled: Enable JSONP support + field_inherit_members: Inherit members + field_closed_on: Closed + setting_default_projects_tracker_ids: Default trackers for new projects + label_total_time: סה"כ + text_scm_config: You can configure your SCM commands in config/configuration.yml. Please restart the application after editing it. + text_scm_command_not_available: SCM command is not available. Please check settings on the administration panel. + setting_emails_header: Email header diff --git a/config/locales/hr.yml b/config/locales/hr.yml new file mode 100644 index 00000000..26274f77 --- /dev/null +++ b/config/locales/hr.yml @@ -0,0 +1,1090 @@ +hr: + direction: ltr + date: + formats: + # Use the strftime parameters for formats. + # When no format has been given, it uses default. + # You can provide other formats here if you like! + default: "%m/%d/%Y" + short: "%b %d" + long: "%B %d, %Y" + + day_names: [Ponedjeljak, Utorak, Srijeda, Četvrtak, Petak, Subota, Nedjelja] + abbr_day_names: [Ned, Pon, Uto, Sri, Čet, Pet, Sub] + + # Don't forget the nil at the beginning; there's no such thing as a 0th month + month_names: [~, Sijecanj, Veljaca, Ožujak, Travanj, Svibanj, Lipanj, Srpanj, Kolovoz, Rujan, Listopad, Studeni, Prosinac] + abbr_month_names: [~, Sij, Velj, Ožu, Tra, Svi, Lip, Srp, Kol, Ruj, List, Stu, Pro] + # Used in date_select and datime_select. + order: + - :year + - :month + - :day + + time: + formats: + default: "%m/%d/%Y %I:%M %p" + time: "%I:%M %p" + short: "%d %b %H:%M" + long: "%B %d, %Y %H:%M" + am: "am" + pm: "pm" + + datetime: + distance_in_words: + half_a_minute: "pola minute" + less_than_x_seconds: + one: "manje od sekunde" + other: "manje od %{count} sekundi" + x_seconds: + one: "1 sekunda" + other: "%{count} sekundi" + less_than_x_minutes: + one: "manje od minute" + other: "manje od %{count} minuta" + x_minutes: + one: "1 minuta" + other: "%{count} minuta" + about_x_hours: + one: "oko sat vremena" + other: "oko %{count} sati" + x_hours: + one: "1 hour" + other: "%{count} hours" + x_days: + one: "1 dan" + other: "%{count} dana" + about_x_months: + one: "oko 1 mjesec" + other: "oko %{count} mjeseci" + x_months: + one: "mjesec" + other: "%{count} mjeseci" + about_x_years: + one: "1 godina" + other: "%{count} godina" + over_x_years: + one: "preko 1 godine" + other: "preko %{count} godina" + + number: + format: + separator: "." + delimiter: "" + precision: 3 + human: + format: + delimiter: "" + precision: 3 + storage_units: + format: "%n %u" + units: + byte: + one: "Byte" + other: "Bytes" + kb: "KB" + mb: "MB" + gb: "GB" + tb: "TB" + +# Used in array.to_sentence. + support: + array: + sentence_connector: "i" + skip_last_comma: false + + activerecord: + errors: + template: + header: + one: "1 error prohibited this %{model} from being saved" + other: "%{count} errors prohibited this %{model} from being saved" + messages: + inclusion: "nije ukljuceno u listu" + exclusion: "je rezervirano" + invalid: "nije ispravno" + confirmation: "ne odgovara za potvrdu" + accepted: "mora biti prihvaćen" + empty: "ne može biti prazno" + blank: "ne može biti razmaka" + too_long: "je predug (maximum is %{count} characters)" + too_short: "je prekratak (minimum is %{count} characters)" + wrong_length: "je pogrešne dužine (should be %{count} characters)" + taken: "već je zauzeto" + not_a_number: "nije broj" + not_a_date: "nije ispravan datum" + greater_than: "mora biti veći od %{count}" + greater_than_or_equal_to: "mora biti veći ili jednak %{count}" + equal_to: "mora biti jednak %{count}" + less_than: "mora biti manji od %{count}" + less_than_or_equal_to: "mora bit manji ili jednak%{count}" + odd: "mora biti neparan" + even: "mora biti paran" + greater_than_start_date: "mora biti veci nego pocetni datum" + not_same_project: "ne pripada istom projektu" + circular_dependency: "Ovaj relacija stvara kružnu ovisnost" + cant_link_an_issue_with_a_descendant: "An issue can not be linked to one of its subtasks" + + actionview_instancetag_blank_option: Molimo odaberite + + general_text_No: 'Ne' + general_text_Yes: 'Da' + general_text_no: 'ne' + general_text_yes: 'da' + general_lang_name: 'Hrvatski' + general_csv_separator: ',' + general_csv_decimal_separator: '.' + general_csv_encoding: UTF-8 + general_pdf_encoding: UTF-8 + general_first_day_of_week: '7' + + notice_account_updated: Vaš profil je uspješno promijenjen. + notice_account_invalid_creditentials: Neispravno korisničko ime ili zaporka. + notice_account_password_updated: Zaporka je uspješno promijenjena. + notice_account_wrong_password: Pogrešna zaporka + notice_account_register_done: Racun je uspješno napravljen. Da biste aktivirali svoj račun, kliknite na link koji vam je poslan na e-mail. + notice_account_unknown_email: Nepoznati korisnik. + notice_can_t_change_password: Ovaj račun koristi eksterni izvor prijavljivanja. Nemoguće je promijeniti zaporku. + notice_account_lost_email_sent: E-mail s uputama kako bi odabrali novu zaporku je poslan na na vašu e-mail adresu. + notice_account_activated: Vaš racun je aktiviran. Možete se prijaviti. + notice_successful_create: Uspješno napravljeno. + notice_successful_update: Uspješna promjena. + notice_successful_delete: Uspješno brisanje. + notice_successful_connection: Uspješna veza. + notice_file_not_found: Stranica kojoj ste pokušali pristupiti ne postoji ili je uklonjena. + notice_locking_conflict: Podataci su ažurirani od strane drugog korisnika. + notice_not_authorized: Niste ovlašteni za pristup ovoj stranici. + notice_email_sent: E-mail je poslan %{value}" + notice_email_error: Dogodila se pogreška tijekom slanja E-maila (%{value})" + notice_feeds_access_key_reseted: Vaš RSS pristup je resetovan. + notice_api_access_key_reseted: Vaš API pristup je resetovan. + notice_failed_to_save_issues: "Neuspjelo spremanje %{count} predmeta na %{total} odabrane: %{ids}." + notice_no_issue_selected: "Niti jedan predmet nije odabran! Molim, odaberite predmete koje želite urediti." + notice_account_pending: "Vaš korisnicki račun je otvoren, čeka odobrenje administratora." + notice_default_data_loaded: Konfiguracija je uspješno učitana. + notice_unable_delete_version: Nije moguće izbrisati verziju. + notice_issue_done_ratios_updated: Issue done ratios updated. + + error_can_t_load_default_data: "Zadanu konfiguracija nije učitana: %{value}" + error_scm_not_found: "Unos i/ili revizija nije pronađen." + error_scm_command_failed: "Dogodila se pogreška prilikom pokušaja pristupa: %{value}" + error_scm_annotate: "Ne postoji ili ne može biti obilježen." + error_issue_not_found_in_project: 'Nije pronađen ili ne pripada u ovaj projekt' + error_no_tracker_in_project: 'No tracker is associated to this project. Please check the Project settings.' + error_no_default_issue_status: 'No default issue status is defined. Please check your configuration (Go to "Administration -> Issue statuses").' + error_can_not_reopen_issue_on_closed_version: 'An issue assigned to a closed version can not be reopened' + error_can_not_archive_project: This project can not be archived + error_issue_done_ratios_not_updated: "Issue done ratios not updated." + error_workflow_copy_source: 'Please select a source tracker or role' + error_workflow_copy_target: 'Please select target tracker(s) and role(s)' + + warning_attachments_not_saved: "%{count} Datoteka/e nije mogla biti spremljena." + + mail_subject_lost_password: "Vaša %{value} zaporka" + mail_body_lost_password: 'Kako biste promijenili Vašu zaporku slijedite poveznicu:' + mail_subject_register: "Aktivacija korisničog računa %{value}" + mail_body_register: 'Da biste aktivirali svoj račun, kliknite na sljedeci link:' + mail_body_account_information_external: "Možete koristiti vaš račun %{value} za prijavu." + mail_body_account_information: Vaši korisnički podaci + mail_subject_account_activation_request: "%{value} predmet za aktivaciju korisničkog računa" + mail_body_account_activation_request: "Novi korisnik (%{value}) je registriran. Njegov korisnički račun čeka vaše odobrenje:" + mail_subject_reminder: "%{count} predmet(a) dospijeva sljedećih %{days} dana" + mail_body_reminder: "%{count} vama dodijeljen(ih) predmet(a) dospijeva u sljedećih %{days} dana:" + mail_subject_wiki_content_added: "'%{id}' wiki page has been added" + mail_body_wiki_content_added: "The '%{id}' wiki page has been added by %{author}." + mail_subject_wiki_content_updated: "'%{id}' wiki page has been updated" + mail_body_wiki_content_updated: "The '%{id}' wiki page has been updated by %{author}." + + + field_name: Ime + field_description: Opis + field_summary: Sažetak + field_is_required: Obavezno + field_firstname: Ime + field_lastname: Prezime + field_mail: E-pošta + field_filename: Datoteka + field_filesize: Veličina + field_downloads: Preuzimanja + field_author: Autor + field_created_on: Napravljen + field_updated_on: Promijenjen + field_field_format: Format + field_is_for_all: Za sve projekte + field_possible_values: Moguće vrijednosti + field_regexp: Regularni izraz + field_min_length: Minimalna dužina + field_max_length: Maksimalna dužina + field_value: Vrijednost + field_category: Kategorija + field_title: Naslov + field_project: Projekt + field_issue: Predmet + field_status: Status + field_notes: Napomene + field_is_closed: Predmet je zatvoren + field_is_default: Zadana vrijednost + field_tracker: Tracker + field_subject: Predmet + field_due_date: Do datuma + field_assigned_to: Dodijeljeno + field_priority: Prioritet + field_fixed_version: Verzija + field_user: Korisnik + field_role: Uloga + field_homepage: Naslovnica + field_is_public: Javni projekt + field_parent: Potprojekt od + field_is_in_roadmap: Predmeti se prikazuju u Putokazu + field_login: Korisničko ime + field_mail_notification: Obavijest putem e-pošte + field_admin: Administrator + field_last_login_on: Zadnja prijava + field_language: Primarni jezik + field_effective_date: Datum + field_password: Zaporka + field_new_password: Nova zaporka + field_password_confirmation: Potvrda zaporke + field_version: Verzija + field_type: Tip + field_host: Host + field_port: Port + field_account: Racun + field_base_dn: Osnovni DN + field_attr_login: Login atribut + field_attr_firstname: Atribut imena + field_attr_lastname: Atribut prezimena + field_attr_mail: Atribut e-pošte + field_onthefly: "Izrada korisnika \"u hodu\"" + field_start_date: Pocetak + field_done_ratio: "% Učinjeno" + field_auth_source: Vrsta prijavljivanja + field_hide_mail: Sakrij moju adresu e-pošte + field_comments: Komentar + field_url: URL + field_start_page: Početna stranica + field_subproject: Potprojekt + field_hours: Sati + field_activity: Aktivnost + field_spent_on: Datum + field_identifier: Identifikator + field_is_filter: Korišteno kao filtar + field_issue_to_id: Povezano s predmetom + field_delay: Odgodeno + field_assignable: Predmeti mogu biti dodijeljeni ovoj ulozi + field_redirect_existing_links: Preusmjeravanje postojećih linkova + field_estimated_hours: Procijenjeno vrijeme + field_column_names: Stupci + field_time_zone: Vremenska zona + field_searchable: Pretraživo + field_default_value: Zadana vrijednost + field_comments_sorting: Prikaz komentara + field_parent_title: Parent page + field_editable: Editable + field_watcher: Watcher + field_identity_url: OpenID URL + field_content: Content + field_group_by: Group results by + + setting_app_title: Naziv aplikacije + setting_app_subtitle: Podnaslov aplikacije + setting_welcome_text: Tekst dobrodošlice + setting_default_language: Zadani jezik + setting_login_required: Potrebna je prijava + setting_self_registration: Samoregistracija je dozvoljena + setting_attachment_max_size: Maksimalna veličina privitka + setting_issues_export_limit: Ograničenje izvoza predmeta + setting_mail_from: Izvorna adresa e-pošte + setting_bcc_recipients: Blind carbon copy primatelja (bcc) + setting_plain_text_mail: obični tekst pošte (bez HTML-a) + setting_host_name: Naziv domaćina (host) + setting_text_formatting: Oblikovanje teksta + setting_wiki_compression: Sažimanje + setting_feeds_limit: Ogranicenje unosa sadržaja + setting_default_projects_public: Novi projekti su javni po defaultu + setting_autofetch_changesets: Autofetch commits + setting_sys_api_enabled: Omogući WS za upravljanje skladištem + setting_commit_ref_keywords: Referentne ključne riječi + setting_commit_fix_keywords: Fiksne ključne riječi + setting_autologin: Automatska prijava + setting_date_format: Format datuma + setting_time_format: Format vremena + setting_cross_project_issue_relations: Dozvoli povezivanje predmeta izmedu različitih projekata + setting_issue_list_default_columns: Stupci prikazani na listi predmeta + setting_emails_footer: Zaglavlje e-pošte + setting_protocol: Protokol + setting_per_page_options: Objekata po stranici opcija + setting_user_format: Oblik prikaza korisnika + setting_activity_days_default: Dani prikazane aktivnosti na projektu + setting_display_subprojects_issues: Prikaz predmeta potprojekta na glavnom projektu po defaultu + setting_enabled_scm: Omogućen SCM + setting_mail_handler_body_delimiters: "Truncate emails after one of these lines" + setting_mail_handler_api_enabled: Omoguci WS za dolaznu e-poštu + setting_mail_handler_api_key: API ključ + setting_sequential_project_identifiers: Generiraj slijedne identifikatore projekta + setting_gravatar_enabled: Koristi Gravatar korisničke ikone + setting_gravatar_default: Default Gravatar image + setting_diff_max_lines_displayed: Maksimalni broj diff linija za prikazati + setting_file_max_size_displayed: Max size of text files displayed inline + setting_repository_log_display_limit: Maximum number of revisions displayed on file log + setting_openid: Allow OpenID login and registration + setting_password_min_length: Minimum password length + setting_new_project_user_role_id: Role given to a non-admin user who creates a project + setting_default_projects_modules: Default enabled modules for new projects + setting_issue_done_ratio: Calculate the issue done ratio with + setting_issue_done_ratio_issue_field: Use the issue field + setting_issue_done_ratio_issue_status: Use the issue status + setting_start_of_week: Start calendars on + setting_rest_api_enabled: Enable REST web service + + permission_add_project: Dodaj projekt + permission_add_subprojects: Dodaj potprojekt + permission_edit_project: Uredi projekt + permission_select_project_modules: Odaberi projektne module + permission_manage_members: Upravljaj članovima + permission_manage_versions: Upravljaj verzijama + permission_manage_categories: Upravljaj kategorijama predmeta + permission_view_issues: Pregledaj zahtjeve + permission_add_issues: Dodaj predmete + permission_edit_issues: Uredi predmete + permission_manage_issue_relations: Upravljaj relacijama predmeta + permission_add_issue_notes: Dodaj bilješke + permission_edit_issue_notes: Uredi bilješke + permission_edit_own_issue_notes: Uredi vlastite bilješke + permission_move_issues: Premjesti predmete + permission_delete_issues: Brisanje predmeta + permission_manage_public_queries: Upravljaj javnim upitima + permission_save_queries: Spremi upite + permission_view_gantt: Pregledaj gantt grafikon + permission_view_calendar: Pregledaj kalendar + permission_view_issue_watchers: Pregledaj listu promatraca + permission_add_issue_watchers: Dodaj promatrača + permission_delete_issue_watchers: Delete watchers + permission_log_time: Dnevnik utrošenog vremena + permission_view_time_entries: Pregledaj utrošeno vrijeme + permission_edit_time_entries: Uredi vremenske dnevnike + permission_edit_own_time_entries: Edit own time logs + permission_manage_news: Upravljaj novostima + permission_comment_news: Komentiraj novosti + permission_view_documents: Pregledaj dokumente + permission_manage_files: Upravljaj datotekama + permission_view_files: Pregledaj datoteke + permission_manage_wiki: Upravljaj wikijem + permission_rename_wiki_pages: Promijeni ime wiki stranicama + permission_delete_wiki_pages: Obriši wiki stranice + permission_view_wiki_pages: Pregledaj wiki + permission_view_wiki_edits: Pregledaj povijest wikija + permission_edit_wiki_pages: Uredi wiki stranice + permission_delete_wiki_pages_attachments: Obriši privitke + permission_protect_wiki_pages: Zaštiti wiki stranice + permission_manage_repository: Upravljaj skladištem + permission_browse_repository: Browse repository + permission_view_changesets: View changesets + permission_commit_access: Mogućnost pohranjivanja + permission_manage_boards: Manage boards + permission_view_messages: Pregledaj poruke + permission_add_messages: Objavi poruke + permission_edit_messages: Uredi poruke + permission_edit_own_messages: Uredi vlastite poruke + permission_delete_messages: Obriši poruke + permission_delete_own_messages: Obriši vlastite poruke + + project_module_issue_tracking: Praćenje predmeta + project_module_time_tracking: Praćenje vremena + project_module_news: Novosti + project_module_documents: Dokumenti + project_module_files: Datoteke + project_module_wiki: Wiki + project_module_repository: Skladište + project_module_boards: Boards + + label_user: Korisnik + label_user_plural: Korisnici + label_user_new: Novi korisnik + label_user_anonymous: Anonymous + label_project: Projekt + label_project_new: Novi projekt + label_project_plural: Projekti + label_x_projects: + zero: no projects + one: 1 project + other: "%{count} projects" + label_project_all: Svi Projekti + label_project_latest: Najnoviji projekt + label_issue: Predmet + label_issue_new: Novi predmet + label_issue_plural: Predmeti + label_issue_view_all: Pregled svih predmeta + label_issues_by: "Predmeti od %{value}" + label_issue_added: Predmet dodan + label_issue_updated: Predmet promijenjen + label_document: Dokument + label_document_new: Novi dokument + label_document_plural: Dokumenti + label_document_added: Dokument dodan + label_role: Uloga + label_role_plural: Uloge + label_role_new: Nova uloga + label_role_and_permissions: Uloge i ovlasti + label_member: Član + label_member_new: Novi član + label_member_plural: Članovi + label_tracker: Vrsta + label_tracker_plural: Vrste predmeta + label_tracker_new: Nova vrsta + label_workflow: Tijek rada + label_issue_status: Status predmeta + label_issue_status_plural: Status predmeta + label_issue_status_new: Novi status + label_issue_category: Kategorija predmeta + label_issue_category_plural: Kategorije predmeta + label_issue_category_new: Nova kategorija + label_custom_field: Korisnički definirano polje + label_custom_field_plural: Korisnički definirana polja + label_custom_field_new: Novo korisnički definirano polje + label_enumerations: Pobrojenice + label_enumeration_new: Nova vrijednost + label_information: Informacija + label_information_plural: Informacije + label_please_login: Molim prijavite se + label_register: Registracija + label_login_with_open_id_option: or login with OpenID + label_password_lost: Izgubljena zaporka + label_home: Početna stranica + label_my_page: Moja stranica + label_my_account: Moj profil + label_my_projects: Moji projekti + label_administration: Administracija + label_login: Korisnik + label_logout: Odjava + label_help: Pomoć + label_reported_issues: Prijavljeni predmeti + label_assigned_to_me_issues: Moji predmeti + label_last_login: Last connection + label_registered_on: Registrirano + label_activity: Aktivnosti + label_overall_activity: Aktivnosti + label_user_activity: "%{value} ova/ina aktivnost" + label_new: Novi + label_logged_as: Prijavljeni ste kao + label_environment: Okolina + label_authentication: Autentikacija + label_auth_source: Način prijavljivanja + label_auth_source_new: Novi način prijavljivanja + label_auth_source_plural: Načini prijavljivanja + label_subproject_plural: Potprojekti + label_subproject_new: Novi potprojekt + label_and_its_subprojects: "%{value} i njegovi potprojekti" + label_min_max_length: Min - Maks veličina + label_list: Liste + label_date: Datum + label_integer: Integer + label_float: Float + label_boolean: Boolean + label_string: Text + label_text: Long text + label_attribute: Atribut + label_attribute_plural: Atributi + label_no_data: Nema podataka za prikaz + label_change_status: Promjena statusa + label_history: Povijest + label_attachment: Datoteka + label_attachment_new: Nova datoteka + label_attachment_delete: Brisanje datoteke + label_attachment_plural: Datoteke + label_file_added: Datoteka dodana + label_report: Izvješće + label_report_plural: Izvješća + label_news: Novosti + label_news_new: Dodaj novost + label_news_plural: Novosti + label_news_latest: Novosti + label_news_view_all: Pregled svih novosti + label_news_added: Novosti dodane + label_settings: Postavke + label_overview: Pregled + label_version: Verzija + label_version_new: Nova verzija + label_version_plural: Verzije + label_confirmation: Potvrda + label_export_to: 'Izvoz u:' + label_read: Čitaj... + label_public_projects: Javni projekti + label_open_issues: Otvoren + label_open_issues_plural: Otvoreno + label_closed_issues: Zatvoren + label_closed_issues_plural: Zatvoreno + label_x_open_issues_abbr_on_total: + zero: 0 open / %{total} + one: 1 open / %{total} + other: "%{count} open / %{total}" + label_x_open_issues_abbr: + zero: 0 open + one: 1 open + other: "%{count} open" + label_x_closed_issues_abbr: + zero: 0 closed + one: 1 closed + other: "%{count} closed" + label_total: Ukupno + label_permissions: Dozvole + label_current_status: Trenutni status + label_new_statuses_allowed: Novi status je dozvoljen + label_all: Svi + label_none: nema + label_nobody: nitko + label_next: Naredni + label_previous: Prethodni + label_used_by: Korišten od + label_details: Detalji + label_add_note: Dodaj napomenu + label_per_page: Po stranici + label_calendar: Kalendar + label_months_from: Mjeseci od + label_gantt: Gantt + label_internal: Interno + label_last_changes: "Posljednjih %{count} promjena" + label_change_view_all: Prikaz svih promjena + label_personalize_page: Prilagodite ovu stranicu + label_comment: Komentar + label_comment_plural: Komentari + label_x_comments: + zero: no comments + one: 1 comment + other: "%{count} comments" + label_comment_add: Dodaj komentar + label_comment_added: Komentar dodan + label_comment_delete: Brisanje komentara + label_query: Korisnički upit + label_query_plural: Korisnički upiti + label_query_new: Novi upit + label_filter_add: Dodaj filtar + label_filter_plural: Filtri + label_equals: je + label_not_equals: nije + label_in_less_than: za manje od + label_in_more_than: za više od + label_greater_or_equal: '>=' + label_less_or_equal: '<=' + label_in: za točno + label_today: danas + label_all_time: sva vremena + label_yesterday: jučer + label_this_week: ovog tjedna + label_last_week: prošlog tjedna + label_last_n_days: "zadnjih %{count} dana" + label_this_month: ovog mjeseca + label_last_month: prošlog mjeseca + label_this_year: ove godine + label_date_range: vremenski raspon + label_less_than_ago: manje od + label_more_than_ago: više od + label_ago: prije + label_contains: Sadrži + label_not_contains: ne sadrži + label_day_plural: dana + label_repository: Skladište + label_repository_plural: Skladišta + label_browse: Pregled + label_branch: Branch + label_tag: Tag + label_revision: Revizija + label_revision_plural: Revizije + label_revision_id: "Revision %{value}" + label_associated_revisions: Dodijeljene revizije + label_added: dodano + label_modified: promijenjen + label_copied: kopirano + label_renamed: preimenovano + label_deleted: obrisano + label_latest_revision: Posljednja revizija + label_latest_revision_plural: Posljednje revizije + label_view_revisions: Pregled revizija + label_view_all_revisions: View all revisions + label_max_size: Maksimalna veličina + label_sort_highest: Premjesti na vrh + label_sort_higher: Premjesti prema gore + label_sort_lower: Premjesti prema dolje + label_sort_lowest: Premjesti na dno + label_roadmap: Putokaz + label_roadmap_due_in: "Završava se za %{value}" + label_roadmap_overdue: "%{value} kasni" + label_roadmap_no_issues: Nema predmeta za ovu verziju + label_search: Traži + label_result_plural: Rezultati + label_all_words: Sve riječi + label_wiki: Wiki + label_wiki_edit: Wiki promjena + label_wiki_edit_plural: Wiki promjene + label_wiki_page: Wiki stranica + label_wiki_page_plural: Wiki stranice + label_index_by_title: Indeks po naslovima + label_index_by_date: Indeks po datumu + label_current_version: Trenutna verzija + label_preview: Brzi pregled + label_feed_plural: Feeds + label_changes_details: Detalji svih promjena + label_issue_tracking: Praćenje predmeta + label_spent_time: Utrošeno vrijeme + label_f_hour: "%{value} sata" + label_f_hour_plural: "%{value} sati" + label_time_tracking: Praćenje vremena + label_change_plural: Promjene + label_statistics: Statistika + label_commits_per_month: Pohrana po mjesecu + label_commits_per_author: Pohrana po autoru + label_view_diff: Pregled razlika + label_diff_inline: uvučeno + label_diff_side_by_side: paralelno + label_options: Opcije + label_copy_workflow_from: Kopiraj tijek rada od + label_permissions_report: Izvješće o dozvolama + label_watched_issues: Praćeni predmeti + label_related_issues: Povezani predmeti + label_applied_status: Primijenjen status + label_loading: Učitavam... + label_relation_new: Nova relacija + label_relation_delete: Brisanje relacije + label_relates_to: u relaciji sa + label_duplicates: Duplira + label_duplicated_by: ponovljen kao + label_blocks: blokira + label_blocked_by: blokiran od strane + label_precedes: prethodi + label_follows: slijedi + label_end_to_start: od kraja do početka + label_end_to_end: od kraja do kraja + label_end_to_start: od kraja do početka + label_end_to_end: od kraja do kraja + label_stay_logged_in: Ostanite prijavljeni + label_disabled: Isključen + label_show_completed_versions: Prikaži završene verzije + label_me: ja + label_board: Forum + label_board_new: Novi forum + label_board_plural: Forumi + label_topic_plural: Teme + label_message_plural: Poruke + label_message_last: Posljednja poruka + label_message_new: Nova poruka + label_message_posted: Poruka dodana + label_reply_plural: Odgovori + label_send_information: Pošalji korisniku informaciju o profilu + label_year: Godina + label_month: Mjesec + label_week: Tjedan + label_date_from: Od + label_date_to: Do + label_language_based: Zasnovano na jeziku + label_sort_by: "Uredi po %{value}" + label_send_test_email: Pošalji testno E-pismo + label_feeds_access_key: RSS access key + label_missing_feeds_access_key: Missing a RSS access key + label_feeds_access_key_created_on: "RSS kljuc za pristup je napravljen prije %{value}" + label_module_plural: Moduli + label_added_time_by: "Promijenio %{author} prije %{age}" + label_updated_time_by: "Dodao/la %{author} prije %{age}" + label_updated_time: "Promijenjeno prije %{value}" + label_jump_to_a_project: Prebaci se na projekt... + label_file_plural: Datoteke + label_changeset_plural: Promjene + label_default_columns: Zadani stupci + label_no_change_option: (Bez promjene) + label_bulk_edit_selected_issues: Zajednička promjena izabranih predmeta + label_theme: Tema + label_default: Zadana + label_search_titles_only: Pretraživanje samo naslova + label_user_mail_option_all: "Za bilo koji događaj na svim mojim projektima" + label_user_mail_option_selected: "Za bilo koji događaj samo za izabrane projekte..." + label_user_mail_no_self_notified: "Ne želim primati obavijesti o promjenama koje sam napravim" + label_registration_activation_by_email: aktivacija putem e-pošte + label_registration_manual_activation: ručna aktivacija + label_registration_automatic_activation: automatska aktivacija + label_display_per_page: "Po stranici: %{value}" + label_age: Starost + label_change_properties: Promijeni svojstva + label_general: Općenito + label_more: Još + label_scm: SCM + label_plugins: Plugins + label_ldap_authentication: LDAP autentikacija + label_downloads_abbr: D/L + label_optional_description: Opcije + label_add_another_file: Dodaj još jednu datoteku + label_preferences: Preferences + label_chronological_order: U kronološkom redoslijedu + label_reverse_chronological_order: U obrnutom kronološkom redoslijedu + label_planning: Planiranje + label_incoming_emails: Dolazne poruke e-pošte + label_generate_key: Generiraj ključ + label_issue_watchers: Promatrači + label_example: Primjer + label_display: Display + label_sort: Sort + label_ascending: Ascending + label_descending: Descending + label_date_from_to: From %{start} to %{end} + label_wiki_content_added: Wiki page added + label_wiki_content_updated: Wiki page updated + label_group: Group + label_group_plural: Grupe + label_group_new: Nova grupa + label_time_entry_plural: Spent time + label_version_sharing_none: Not shared + label_version_sharing_descendants: With subprojects + label_version_sharing_hierarchy: With project hierarchy + label_version_sharing_tree: With project tree + label_version_sharing_system: With all projects + label_update_issue_done_ratios: Update issue done ratios + label_copy_source: Source + label_copy_target: Target + label_copy_same_as_target: Same as target + label_display_used_statuses_only: Only display statuses that are used by this tracker + label_api_access_key: API access key + label_missing_api_access_key: Missing an API access key + label_api_access_key_created_on: "API access key created %{value} ago" + + button_login: Prijavi + button_submit: Pošalji + button_save: Spremi + button_check_all: Označi sve + button_uncheck_all: Isključi sve + button_delete: Obriši + button_create: Napravi + button_create_and_continue: Napravi i nastavi + button_test: Test + button_edit: Uredi + button_add: Dodaj + button_change: Promijeni + button_apply: Primijeni + button_clear: Ukloni + button_lock: Zaključaj + button_unlock: Otključaj + button_download: Preuzmi + button_list: Spisak + button_view: Pregled + button_move: Premjesti + button_move_and_follow: Move and follow + button_back: Nazad + button_cancel: Odustani + button_activate: Aktiviraj + button_sort: Redoslijed + button_log_time: Zapiši vrijeme + button_rollback: Izvrši rollback na ovu verziju + button_watch: Prati + button_unwatch: Prekini pracenje + button_reply: Odgovori + button_archive: Arhiviraj + button_rollback: Dearhiviraj + button_reset: Poništi + button_rename: Promijeni ime + button_change_password: Promjena zaporke + button_copy: Kopiraj + button_copy_and_follow: Copy and follow + button_annotate: Annotate + button_update: Promijeni + button_configure: Konfiguracija + button_quote: Navod + button_duplicate: Duplicate + button_show: Show + + status_active: aktivan + status_registered: Registriran + status_locked: zaključan + + version_status_open: open + version_status_locked: locked + version_status_closed: closed + + field_active: Active + + text_select_mail_notifications: Izbor akcija za koje će biti poslana obavijest e-poštom. + text_regexp_info: eg. ^[A-Z0-9]+$ + text_min_max_length_info: 0 znači bez ograničenja + text_project_destroy_confirmation: Da li ste sigurni da želite izbrisati ovaj projekt i sve njegove podatke? + text_subprojects_destroy_warning: "Njegov(i) potprojekt(i): %{value} će također biti obrisan." + text_workflow_edit: Select a role and a tracker to edit the workflow + text_are_you_sure: Da li ste sigurni? + text_journal_changed: "%{label} promijenjen iz %{old} u %{new}" + text_journal_set_to: "%{label} postavi na %{value}" + text_journal_deleted: "%{label} izbrisano (%{old})" + text_journal_added: "%{label} %{value} added" + text_tip_issue_begin_day: Zadaci koji počinju ovog dana + text_tip_issue_end_day: zadaci koji se završavaju ovog dana + text_tip_issue_begin_end_day: Zadaci koji počinju i završavaju se ovog dana + text_caracters_maximum: "Najviše %{count} znakova." + text_caracters_minimum: "Mora biti dugačko najmanje %{count} znakova." + text_length_between: "Dužina izmedu %{min} i %{max} znakova." + text_tracker_no_workflow: Tijek rada nije definiran za ovaj tracker + text_unallowed_characters: Nedozvoljeni znakovi + text_comma_separated: Višestruke vrijednosti su dozvoljene (razdvojene zarezom). + text_issues_ref_in_commit_messages: Referencing and fixing issues in commit messages + text_tracker_no_workflow: No workflow defined for this tracker + text_issues_ref_in_commit_messages: Referencing and fixing issues in commit messages + text_issue_added: "Predmet %{id} je prijavljen (prijavio %{author})." + text_issue_updated: "Predmet %{id} je promijenjen %{author})." + text_wiki_destroy_confirmation: Da li ste sigurni da želite izbrisati ovaj wiki i njegov sadržaj? + text_issue_category_destroy_question: "Neke predmeti (%{count}) su dodijeljeni ovoj kategoriji. Što želite uraditi?" + text_issue_category_destroy_assignments: Ukloni dodjeljivanje kategorija + text_issue_category_reassign_to: Ponovo dodijeli predmete ovoj kategoriji + text_user_mail_option: "Za neizabrane projekte, primit ćete obavjesti samo o stvarima koje pratite ili u kojima sudjelujete (npr. predmete koje ste vi napravili ili koje su vama dodjeljeni)." + text_no_configuration_data: "Roles, trackers, issue statuses and workflow have not been configured yet.\nIt is highly recommended to load the default configuration. You will be able to modify it once loaded." + text_load_default_configuration: Učitaj početnu konfiguraciju + text_status_changed_by_changeset: "Applied in changeset %{value}." + text_issues_destroy_confirmation: 'Jeste li sigurni da želite obrisati izabrani/e predmet(e)?' + text_select_project_modules: 'Odaberite module koji će biti omogućeni za ovaj projekt:' + text_default_administrator_account_changed: Default administrator account changed + text_file_repository_writable: Dozvoljeno pisanje u direktorij za privitke + text_plugin_assets_writable: Plugin assets directory writable + text_rmagick_available: RMagick dostupan (nije obavezno) + text_destroy_time_entries_question: "%{hours} sati je prijavljeno za predmete koje želite obrisati. Što ćete učiniti?" + text_destroy_time_entries: Obriši prijavljene sate + text_assign_time_entries_to_project: Pridruži prijavljene sate projektu + text_reassign_time_entries: 'Premjesti prijavljene sate ovom predmetu:' + text_user_wrote: "%{value} je napisao/la:" + text_enumeration_destroy_question: "%{count} objekata je pridruženo toj vrijednosti." + text_enumeration_category_reassign_to: 'Premjesti ih ovoj vrijednosti:' + text_email_delivery_not_configured: "Email delivery is not configured, and notifications are disabled.\nConfigure your SMTP server in config/configuration.yml and restart the application to enable them." + text_repository_usernames_mapping: "Select or update the Redmine user mapped to each username found in the repository log.\nUsers with the same Redmine and repository username or email are automatically mapped." + text_diff_truncated: '... Ovaj diff je odrezan zato što prelazi maksimalnu veličinu koja može biti prikazana.' + text_custom_field_possible_values_info: 'One line for each value' + text_wiki_page_destroy_question: "This page has %{descendants} child page(s) and descendant(s). What do you want to do?" + text_wiki_page_nullify_children: "Keep child pages as root pages" + text_wiki_page_destroy_children: "Delete child pages and all their descendants" + text_wiki_page_reassign_children: "Reassign child pages to this parent page" + default_role_manager: Upravitelj + default_role_developer: Razvojni inženjer + default_role_reporter: Korisnik + default_tracker_bug: Pogreška + default_tracker_feature: Funkcionalnost + default_tracker_support: Podrška + default_issue_status_new: Novo + default_issue_status_assigned: Dodijeljeno + default_issue_status_resolved: Riješeno + default_issue_status_feedback: Povratna informacija + default_issue_status_closed: Zatvoreno + default_issue_status_rejected: Odbaceno + default_doc_category_user: Korisnička dokumentacija + default_doc_category_tech: Tehnička dokumentacija + default_priority_low: Nizak + default_priority_normal: Redovan + default_priority_high: Visok + default_priority_urgent: Hitan + default_priority_immediate: Odmah + default_activity_design: Dizajn + default_activity_development: Razvoj + enumeration_issue_priorities: Prioriteti predmeta + enumeration_doc_categories: Kategorija dokumenata + enumeration_activities: Aktivnosti (po vremenu) + enumeration_system_activity: System Activity + field_sharing: Sharing + text_line_separated: Multiple values allowed (one line for each value). + label_close_versions: Close completed versions + button_unarchive: Unarchive + label_start_to_end: start to end + label_start_to_start: start to start + field_issue_to: Related issue + default_issue_status_in_progress: In Progress + text_own_membership_delete_confirmation: |- + You are about to remove some or all of your permissions and may no longer be able to edit this project after that. + Are you sure you want to continue? + label_board_sticky: Sticky + label_board_locked: Locked + permission_export_wiki_pages: Export wiki pages + setting_cache_formatted_text: Cache formatted text + permission_manage_project_activities: Manage project activities + error_unable_delete_issue_status: Unable to delete issue status + label_profile: Profile + permission_manage_subtasks: Manage subtasks + field_parent_issue: Parent task + label_subtask_plural: Subtasks + label_project_copy_notifications: Send email notifications during the project copy + error_can_not_delete_custom_field: Unable to delete custom field + error_unable_to_connect: Unable to connect (%{value}) + error_can_not_remove_role: This role is in use and can not be deleted. + error_can_not_delete_tracker: This tracker contains issues and can't be deleted. + field_principal: Principal + label_my_page_block: My page block + notice_failed_to_save_members: "Failed to save member(s): %{errors}." + text_zoom_out: Zoom out + text_zoom_in: Zoom in + notice_unable_delete_time_entry: Unable to delete time log entry. + label_overall_spent_time: Overall spent time + field_time_entries: Log time + project_module_gantt: Gantt + project_module_calendar: Calendar + button_edit_associated_wikipage: "Edit associated Wiki page: %{page_title}" + field_text: Text field + label_user_mail_option_only_owner: Only for things I am the owner of + setting_default_notification_option: Default notification option + label_user_mail_option_only_my_events: Only for things I watch or I'm involved in + label_user_mail_option_only_assigned: Only for things I am assigned to + label_user_mail_option_none: No events + field_member_of_group: Assignee's group + field_assigned_to_role: Assignee's role + notice_not_authorized_archived_project: The project you're trying to access has been archived. + label_principal_search: "Search for user or group:" + label_user_search: "Search for user:" + field_visible: Visible + setting_commit_logtime_activity_id: Activity for logged time + text_time_logged_by_changeset: Applied in changeset %{value}. + setting_commit_logtime_enabled: Enable time logging + notice_gantt_chart_truncated: The chart was truncated because it exceeds the maximum number of items that can be displayed (%{max}) + setting_gantt_items_limit: Maximum number of items displayed on the gantt chart + field_warn_on_leaving_unsaved: Warn me when leaving a page with unsaved text + text_warn_on_leaving_unsaved: The current page contains unsaved text that will be lost if you leave this page. + label_my_queries: My custom queries + text_journal_changed_no_detail: "%{label} updated" + label_news_comment_added: Comment added to a news + button_expand_all: Expand all + button_collapse_all: Collapse all + label_additional_workflow_transitions_for_assignee: Additional transitions allowed when the user is the assignee + label_additional_workflow_transitions_for_author: Additional transitions allowed when the user is the author + label_bulk_edit_selected_time_entries: Bulk edit selected time entries + text_time_entries_destroy_confirmation: Are you sure you want to delete the selected time entr(y/ies)? + label_role_anonymous: Anonymous + label_role_non_member: Non member + label_issue_note_added: Note added + label_issue_status_updated: Status updated + label_issue_priority_updated: Priority updated + label_issues_visibility_own: Issues created by or assigned to the user + field_issues_visibility: Issues visibility + label_issues_visibility_all: All issues + permission_set_own_issues_private: Set own issues public or private + field_is_private: Private + permission_set_issues_private: Set issues public or private + label_issues_visibility_public: All non private issues + text_issues_destroy_descendants_confirmation: This will also delete %{count} subtask(s). + field_commit_logs_encoding: Commit messages encoding + field_scm_path_encoding: Path encoding + text_scm_path_encoding_note: "Default: UTF-8" + field_path_to_repository: Path to repository + field_root_directory: Root directory + field_cvs_module: Module + field_cvsroot: CVSROOT + text_mercurial_repository_note: Local repository (e.g. /hgrepo, c:\hgrepo) + text_scm_command: Command + text_scm_command_version: Version + label_git_report_last_commit: Report last commit for files and directories + notice_issue_successful_create: Issue %{id} created. + label_between: between + setting_issue_group_assignment: Allow issue assignment to groups + label_diff: diff + text_git_repository_note: Repository is bare and local (e.g. /gitrepo, c:\gitrepo) + description_query_sort_criteria_direction: Sort direction + description_project_scope: Search scope + description_filter: Filter + description_user_mail_notification: Mail notification settings + description_date_from: Enter start date + description_message_content: Message content + description_available_columns: Available Columns + description_date_range_interval: Choose range by selecting start and end date + description_issue_category_reassign: Choose issue category + description_search: Searchfield + description_notes: Notes + description_date_range_list: Choose range from list + description_choose_project: Projects + description_date_to: Enter end date + description_query_sort_criteria_attribute: Sort attribute + description_wiki_subpages_reassign: Choose new parent page + description_selected_columns: Selected Columns + label_parent_revision: Parent + label_child_revision: Child + error_scm_annotate_big_text_file: The entry cannot be annotated, as it exceeds the maximum text file size. + setting_default_issue_start_date_to_creation_date: Use current date as start date for new issues + button_edit_section: Edit this section + setting_repositories_encodings: Attachments and repositories encodings + description_all_columns: All Columns + button_export: Export + label_export_options: "%{export_format} export options" + error_attachment_too_big: This file cannot be uploaded because it exceeds the maximum allowed file size (%{max_size}) + notice_failed_to_save_time_entries: "Failed to save %{count} time entrie(s) on %{total} selected: %{ids}." + label_x_issues: + zero: 0 predmet + one: 1 predmet + other: "%{count} predmeti" + label_repository_new: New repository + field_repository_is_default: Main repository + label_copy_attachments: Copy attachments + label_item_position: "%{position}/%{count}" + label_completed_versions: Completed versions + text_project_identifier_info: Only lower case letters (a-z), numbers, dashes and underscores are allowed.
    Once saved, the identifier cannot be changed. + field_multiple: Multiple values + setting_commit_cross_project_ref: Allow issues of all the other projects to be referenced and fixed + text_issue_conflict_resolution_add_notes: Add my notes and discard my other changes + text_issue_conflict_resolution_overwrite: Apply my changes anyway (previous notes will be kept but some changes may be overwritten) + notice_issue_update_conflict: The issue has been updated by an other user while you were editing it. + text_issue_conflict_resolution_cancel: Discard all my changes and redisplay %{link} + permission_manage_related_issues: Manage related issues + field_auth_source_ldap_filter: LDAP filter + label_search_for_watchers: Search for watchers to add + notice_account_deleted: Your account has been permanently deleted. + setting_unsubscribe: Allow users to delete their own account + button_delete_my_account: Delete my account + text_account_destroy_confirmation: |- + Are you sure you want to proceed? + Your account will be permanently deleted, with no way to reactivate it. + error_session_expired: Your session has expired. Please login again. + text_session_expiration_settings: "Warning: changing these settings may expire the current sessions including yours." + setting_session_lifetime: Session maximum lifetime + setting_session_timeout: Session inactivity timeout + label_session_expiration: Session expiration + permission_close_project: Close / reopen the project + label_show_closed_projects: View closed projects + button_close: Close + button_reopen: Reopen + project_status_active: active + project_status_closed: closed + project_status_archived: archived + text_project_closed: This project is closed and read-only. + notice_user_successful_create: User %{id} created. + field_core_fields: Standard fields + field_timeout: Timeout (in seconds) + setting_thumbnails_enabled: Display attachment thumbnails + setting_thumbnails_size: Thumbnails size (in pixels) + label_status_transitions: Status transitions + label_fields_permissions: Fields permissions + label_readonly: Read-only + label_required: Required + text_repository_identifier_info: Only lower case letters (a-z), numbers, dashes and underscores are allowed.
    Once saved, the identifier cannot be changed. + field_board_parent: Parent forum + label_attribute_of_project: Project's %{name} + label_attribute_of_author: Author's %{name} + label_attribute_of_assigned_to: Assignee's %{name} + label_attribute_of_fixed_version: Target version's %{name} + label_copy_subtasks: Copy subtasks + label_copied_to: copied to + label_copied_from: copied from + label_any_issues_in_project: any issues in project + label_any_issues_not_in_project: any issues not in project + field_private_notes: Private notes + permission_view_private_notes: View private notes + permission_set_notes_private: Set notes as private + label_no_issues_in_project: no issues in project + label_any: Svi + label_last_n_weeks: last %{count} weeks + setting_cross_project_subtasks: Allow cross-project subtasks + label_cross_project_descendants: With subprojects + label_cross_project_tree: With project tree + label_cross_project_hierarchy: With project hierarchy + label_cross_project_system: With all projects + button_hide: Hide + setting_non_working_week_days: Non-working days + label_in_the_next_days: in the next + label_in_the_past_days: in the past + label_attribute_of_user: User's %{name} + text_turning_multiple_off: If you disable multiple values, multiple values will be + removed in order to preserve only one value per item. + label_attribute_of_issue: Issue's %{name} + permission_add_documents: Add documents + permission_edit_documents: Edit documents + permission_delete_documents: Delete documents + label_gantt_progress_line: Progress line + setting_jsonp_enabled: Enable JSONP support + field_inherit_members: Inherit members + field_closed_on: Closed + setting_default_projects_tracker_ids: Default trackers for new projects + label_total_time: Ukupno + text_scm_config: You can configure your SCM commands in config/configuration.yml. Please restart the application after editing it. + text_scm_command_not_available: SCM command is not available. Please check settings on the administration panel. + setting_emails_header: Email header diff --git a/config/locales/hu.yml b/config/locales/hu.yml new file mode 100644 index 00000000..4ffe7516 --- /dev/null +++ b/config/locales/hu.yml @@ -0,0 +1,1108 @@ +# Hungarian translations for Ruby on Rails +# by Richard Abonyi (richard.abonyi@gmail.com) +# thanks to KKata, replaced and #hup.hu +# Cleaned up by László Bácsi (http://lackac.hu) +# updated by kfl62 kfl62g@gmail.com +# updated by Gábor Takács (taky77@gmail.com) + +"hu": + direction: ltr + date: + formats: + default: "%Y.%m.%d." + short: "%b %e." + long: "%Y. %B %e." + day_names: [vasárnap, hétfő, kedd, szerda, csütörtök, péntek, szombat] + abbr_day_names: [v., h., k., sze., cs., p., szo.] + month_names: [~, január, február, március, április, május, június, július, augusztus, szeptember, október, november, december] + abbr_month_names: [~, jan., febr., márc., ápr., máj., jún., júl., aug., szept., okt., nov., dec.] + order: + - :year + - :month + - :day + + time: + formats: + default: "%Y. %b %d., %H:%M" + time: "%H:%M" + short: "%b %e., %H:%M" + long: "%Y. %B %e., %A, %H:%M" + am: "de." + pm: "du." + + datetime: + distance_in_words: + half_a_minute: 'fél perc' + less_than_x_seconds: +# zero: 'kevesebb, mint 1 másodperce' + one: 'kevesebb, mint 1 másodperce' + other: 'kevesebb, mint %{count} másodperce' + x_seconds: + one: '1 másodperce' + other: '%{count} másodperce' + less_than_x_minutes: +# zero: 'kevesebb, mint 1 perce' + one: 'kevesebb, mint 1 perce' + other: 'kevesebb, mint %{count} perce' + x_minutes: + one: '1 perce' + other: '%{count} perce' + about_x_hours: + one: 'csaknem 1 órája' + other: 'csaknem %{count} órája' + x_hours: + one: "1 hour" + other: "%{count} hours" + x_days: + one: '1 napja' + other: '%{count} napja' + about_x_months: + one: 'csaknem 1 hónapja' + other: 'csaknem %{count} hónapja' + x_months: + one: '1 hónapja' + other: '%{count} hónapja' + about_x_years: + one: 'csaknem 1 éve' + other: 'csaknem %{count} éve' + over_x_years: + one: 'több, mint 1 éve' + other: 'több, mint %{count} éve' + almost_x_years: + one: "csaknem 1 éve" + other: "csaknem %{count} éve" + prompts: + year: "Év" + month: "Hónap" + day: "Nap" + hour: "Óra" + minute: "Perc" + second: "Másodperc" + + number: + format: + precision: 2 + separator: ',' + delimiter: ' ' + currency: + format: + unit: 'Ft' + precision: 0 + format: '%n %u' + separator: "," + delimiter: "" + percentage: + format: + delimiter: "" + precision: + format: + delimiter: "" + human: + format: + delimiter: "" + precision: 3 + storage_units: + format: "%n %u" + units: + byte: + one: "bájt" + other: "bájt" + kb: "KB" + mb: "MB" + gb: "GB" + tb: "TB" + + support: + array: +# sentence_connector: "és" +# skip_last_comma: true + words_connector: ", " + two_words_connector: " és " + last_word_connector: " és " + activerecord: + errors: + template: + header: + one: "1 hiba miatt nem menthető a következő: %{model}" + other: "%{count} hiba miatt nem menthető a következő: %{model}" + body: "Problémás mezők:" + messages: + inclusion: "nincs a listában" + exclusion: "nem elérhető" + invalid: "nem megfelelő" + confirmation: "nem egyezik" + accepted: "nincs elfogadva" + empty: "nincs megadva" + blank: "nincs megadva" + too_long: "túl hosszú (nem lehet több %{count} karakternél)" + too_short: "túl rövid (legalább %{count} karakter kell legyen)" + wrong_length: "nem megfelelő hosszúságú (%{count} karakter szükséges)" + taken: "már foglalt" + not_a_number: "nem szám" + greater_than: "nagyobb kell legyen, mint %{count}" + greater_than_or_equal_to: "legalább %{count} kell legyen" + equal_to: "pontosan %{count} kell legyen" + less_than: "kevesebb, mint %{count} kell legyen" + less_than_or_equal_to: "legfeljebb %{count} lehet" + odd: "páratlan kell legyen" + even: "páros kell legyen" + greater_than_start_date: "nagyobbnak kell lennie, mint az indítás dátuma" + not_same_project: "nem azonos projekthez tartozik" + circular_dependency: "Ez a kapcsolat egy körkörös függőséget eredményez" + cant_link_an_issue_with_a_descendant: "An issue can not be linked to one of its subtasks" + + actionview_instancetag_blank_option: Kérem válasszon + + general_text_No: 'Nem' + general_text_Yes: 'Igen' + general_text_no: 'nem' + general_text_yes: 'igen' + general_lang_name: 'Magyar' + general_csv_separator: ',' + general_csv_decimal_separator: '.' + general_csv_encoding: ISO-8859-2 + general_pdf_encoding: UTF-8 + general_first_day_of_week: '1' + + notice_account_updated: A fiók adatai sikeresen frissítve. + notice_account_invalid_creditentials: Hibás felhasználói név, vagy jelszó + notice_account_password_updated: A jelszó módosítása megtörtént. + notice_account_wrong_password: Hibás jelszó + notice_account_register_done: A fiók sikeresen létrehozva. Aktiválásához kattints az e-mailben kapott linkre + notice_account_unknown_email: Ismeretlen felhasználó. + notice_can_t_change_password: A fiók külső azonosítási forrást használ. A jelszó megváltoztatása nem lehetséges. + notice_account_lost_email_sent: Egy e-mail üzenetben postáztunk Önnek egy leírást az új jelszó beállításáról. + notice_account_activated: Fiókját aktiváltuk. Most már be tud jelentkezni a rendszerbe. + notice_successful_create: Sikeres létrehozás. + notice_successful_update: Sikeres módosítás. + notice_successful_delete: Sikeres törlés. + notice_successful_connection: Sikeres bejelentkezés. + notice_file_not_found: Az oldal, amit meg szeretne nézni nem található, vagy átkerült egy másik helyre. + notice_locking_conflict: Az adatot egy másik felhasználó idő közben módosította. + notice_not_authorized: Nincs hozzáférési engedélye ehhez az oldalhoz. + notice_email_sent: "Egy e-mail üzenetet küldtünk a következő címre %{value}" + notice_email_error: "Hiba történt a levél küldése közben (%{value})" + notice_feeds_access_key_reseted: Az RSS hozzáférési kulcsát újra generáltuk. + notice_failed_to_save_issues: "Nem sikerült a %{count} feladat(ok) mentése a %{total} -ban kiválasztva: %{ids}." + notice_no_issue_selected: "Nincs feladat kiválasztva! Kérem jelölje meg melyik feladatot szeretné szerkeszteni!" + notice_account_pending: "A fiókja létrejött, és adminisztrátori jóváhagyásra vár." + notice_default_data_loaded: Az alapértelmezett konfiguráció betöltése sikeresen megtörtént. + + error_can_t_load_default_data: "Az alapértelmezett konfiguráció betöltése nem lehetséges: %{value}" + error_scm_not_found: "A bejegyzés, vagy revízió nem található a tárolóban." + error_scm_command_failed: "A tároló elérése közben hiba lépett fel: %{value}" + error_scm_annotate: "A bejegyzés nem létezik, vagy nics jegyzetekkel ellátva." + error_issue_not_found_in_project: 'A feladat nem található, vagy nem ehhez a projekthez tartozik' + + mail_subject_lost_password: Az Ön Redmine jelszava + mail_body_lost_password: 'A Redmine jelszó megváltoztatásához, kattintson a következő linkre:' + mail_subject_register: Redmine azonosító aktiválása + mail_body_register: 'A Redmine azonosítója aktiválásához, kattintson a következő linkre:' + mail_body_account_information_external: "A %{value} azonosító használatával bejelentkezhet a Redmine-ba." + mail_body_account_information: Az Ön Redmine azonosítójának információi + mail_subject_account_activation_request: Redmine azonosító aktiválási kérelem + mail_body_account_activation_request: "Egy új felhasználó (%{value}) regisztrált, azonosítója jóváhasgyásra várakozik:" + + + field_name: Név + field_description: Leírás + field_summary: Összegzés + field_is_required: Kötelező + field_firstname: Keresztnév + field_lastname: Vezetéknév + field_mail: E-mail + field_filename: Fájl + field_filesize: Méret + field_downloads: Letöltések + field_author: Szerző + field_created_on: Létrehozva + field_updated_on: Módosítva + field_field_format: Formátum + field_is_for_all: Minden projekthez + field_possible_values: Lehetséges értékek + field_regexp: Reguláris kifejezés + field_min_length: Minimum hossz + field_max_length: Maximum hossz + field_value: Érték + field_category: Kategória + field_title: Cím + field_project: Projekt + field_issue: Feladat + field_status: Státusz + field_notes: Feljegyzések + field_is_closed: Feladat lezárva + field_is_default: Alapértelmezett érték + field_tracker: Típus + field_subject: Tárgy + field_due_date: Befejezés dátuma + field_assigned_to: Felelős + field_priority: Prioritás + field_fixed_version: Cél verzió + field_user: Felhasználó + field_role: Szerepkör + field_homepage: Weboldal + field_is_public: Nyilvános + field_parent: Szülő projekt + field_is_in_roadmap: Feladatok látszanak az életútban + field_login: Azonosító + field_mail_notification: E-mail értesítések + field_admin: Adminisztrátor + field_last_login_on: Utolsó bejelentkezés + field_language: Nyelv + field_effective_date: Dátum + field_password: Jelszó + field_new_password: Új jelszó + field_password_confirmation: Megerősítés + field_version: Verzió + field_type: Típus + field_host: Kiszolgáló + field_port: Port + field_account: Felhasználói fiók + field_base_dn: Base DN + field_attr_login: Bejelentkezési tulajdonság + field_attr_firstname: Keresztnév + field_attr_lastname: Vezetéknév + field_attr_mail: E-mail + field_onthefly: On-the-fly felhasználó létrehozás + field_start_date: Kezdés dátuma + field_done_ratio: Készültség (%) + field_auth_source: Azonosítási mód + field_hide_mail: Rejtse el az e-mail címem + field_comments: Megjegyzés + field_url: URL + field_start_page: Kezdőlap + field_subproject: Alprojekt + field_hours: Óra + field_activity: Aktivitás + field_spent_on: Dátum + field_identifier: Azonosító + field_is_filter: Szűrőként használható + field_issue_to: Kapcsolódó feladat + field_delay: Késés + field_assignable: Feladat rendelhető ehhez a szerepkörhöz + field_redirect_existing_links: Létező linkek átirányítása + field_estimated_hours: Becsült időigény + field_column_names: Oszlopok + field_time_zone: Időzóna + field_searchable: Kereshető + field_default_value: Alapértelmezett érték + field_comments_sorting: Feljegyzések megjelenítése + + setting_app_title: Alkalmazás címe + setting_app_subtitle: Alkalmazás alcíme + setting_welcome_text: Üdvözlő üzenet + setting_default_language: Alapértelmezett nyelv + setting_login_required: Azonosítás szükséges + setting_self_registration: Regisztráció + setting_attachment_max_size: Melléklet max. mérete + setting_issues_export_limit: Feladatok exportálásának korlátja + setting_mail_from: Kibocsátó e-mail címe + setting_bcc_recipients: Titkos másolat címzet (bcc) + setting_host_name: Kiszolgáló neve + setting_text_formatting: Szöveg formázás + setting_wiki_compression: Wiki történet tömörítés + setting_feeds_limit: RSS tartalom korlát + setting_default_projects_public: Az új projektek alapértelmezés szerint nyilvánosak + setting_autofetch_changesets: Commitok automatikus lehúzása + setting_sys_api_enabled: WS engedélyezése a tárolók kezeléséhez + setting_commit_ref_keywords: Hivatkozó kulcsszavak + setting_commit_fix_keywords: Javítások kulcsszavai + setting_autologin: Automatikus bejelentkezés + setting_date_format: Dátum formátum + setting_time_format: Idő formátum + setting_cross_project_issue_relations: Kereszt-projekt feladat hivatkozások engedélyezése + setting_issue_list_default_columns: Az alapértelmezésként megjelenített oszlopok a feladat listában + setting_emails_footer: E-mail lábléc + setting_protocol: Protokol + setting_per_page_options: Objektum / oldal opciók + setting_user_format: Felhasználók megjelenítésének formája + setting_activity_days_default: Napok megjelenítése a project aktivitásnál + setting_display_subprojects_issues: Alapértelmezettként mutassa az alprojektek feladatait is a projekteken + setting_start_of_week: A hét első napja + + project_module_issue_tracking: Feladat követés + project_module_time_tracking: Idő rögzítés + project_module_news: Hírek + project_module_documents: Dokumentumok + project_module_files: Fájlok + project_module_wiki: Wiki + project_module_repository: Forráskód + project_module_boards: Fórumok + + label_user: Felhasználó + label_user_plural: Felhasználók + label_user_new: Új felhasználó + label_project: Projekt + label_project_new: Új projekt + label_project_plural: Projektek + label_x_projects: + zero: nincsenek projektek + one: 1 projekt + other: "%{count} projekt" + label_project_all: Az összes projekt + label_project_latest: Legutóbbi projektek + label_issue: Feladat + label_issue_new: Új feladat + label_issue_plural: Feladatok + label_issue_view_all: Minden feladat + label_issues_by: "%{value} feladatai" + label_issue_added: Feladat hozzáadva + label_issue_updated: Feladat frissítve + label_document: Dokumentum + label_document_new: Új dokumentum + label_document_plural: Dokumentumok + label_document_added: Dokumentum hozzáadva + label_role: Szerepkör + label_role_plural: Szerepkörök + label_role_new: Új szerepkör + label_role_and_permissions: Szerepkörök, és jogosultságok + label_member: Résztvevő + label_member_new: Új résztvevő + label_member_plural: Résztvevők + label_tracker: Feladat típus + label_tracker_plural: Feladat típusok + label_tracker_new: Új feladat típus + label_workflow: Workflow + label_issue_status: Feladat státusz + label_issue_status_plural: Feladat státuszok + label_issue_status_new: Új státusz + label_issue_category: Feladat kategória + label_issue_category_plural: Feladat kategóriák + label_issue_category_new: Új kategória + label_custom_field: Egyéni mező + label_custom_field_plural: Egyéni mezők + label_custom_field_new: Új egyéni mező + label_enumerations: Felsorolások + label_enumeration_new: Új érték + label_information: Információ + label_information_plural: Információk + label_please_login: Jelentkezzen be + label_register: Regisztráljon + label_password_lost: Elfelejtett jelszó + label_home: Kezdőlap + label_my_page: Saját kezdőlapom + label_my_account: Fiókom adatai + label_my_projects: Saját projektem + label_administration: Adminisztráció + label_login: Bejelentkezés + label_logout: Kijelentkezés + label_help: Súgó + label_reported_issues: Bejelentett feladatok + label_assigned_to_me_issues: A nekem kiosztott feladatok + label_last_login: Utolsó bejelentkezés + label_registered_on: Regisztrált + label_activity: Történések + label_overall_activity: Teljes aktivitás + label_new: Új + label_logged_as: Bejelentkezve, mint + label_environment: Környezet + label_authentication: Azonosítás + label_auth_source: Azonosítás módja + label_auth_source_new: Új azonosítási mód + label_auth_source_plural: Azonosítási módok + label_subproject_plural: Alprojektek + label_and_its_subprojects: "%{value} és alprojektjei" + label_min_max_length: Min - Max hossz + label_list: Lista + label_date: Dátum + label_integer: Egész + label_float: Lebegőpontos + label_boolean: Logikai + label_string: Szöveg + label_text: Hosszú szöveg + label_attribute: Tulajdonság + label_attribute_plural: Tulajdonságok + label_no_data: Nincs megjeleníthető adat + label_change_status: Státusz módosítása + label_history: Történet + label_attachment: Fájl + label_attachment_new: Új fájl + label_attachment_delete: Fájl törlése + label_attachment_plural: Fájlok + label_file_added: Fájl hozzáadva + label_report: Jelentés + label_report_plural: Jelentések + label_news: Hírek + label_news_new: Hír hozzáadása + label_news_plural: Hírek + label_news_latest: Legutóbbi hírek + label_news_view_all: Minden hír megtekintése + label_news_added: Hír hozzáadva + label_settings: Beállítások + label_overview: Áttekintés + label_version: Verzió + label_version_new: Új verzió + label_version_plural: Verziók + label_confirmation: Jóváhagyás + label_export_to: Exportálás + label_read: Olvas... + label_public_projects: Nyilvános projektek + label_open_issues: nyitott + label_open_issues_plural: nyitott + label_closed_issues: lezárt + label_closed_issues_plural: lezárt + label_x_open_issues_abbr_on_total: + zero: nyitott 0 / %{total} + one: nyitott 1 / %{total} + other: "nyitott %{count} / %{total}" + label_x_open_issues_abbr: + zero: 0 nyitott + one: 1 nyitott + other: "%{count} nyitott" + label_x_closed_issues_abbr: + zero: 0 lezárt + one: 1 lezárt + other: "%{count} lezárt" + label_total: Összesen + label_permissions: Jogosultságok + label_current_status: Jelenlegi státusz + label_new_statuses_allowed: Státusz változtatások engedélyei + label_all: mind + label_none: nincs + label_nobody: senki + label_next: Következő + label_previous: Előző + label_used_by: Használja + label_details: Részletek + label_add_note: Jegyzet hozzáadása + label_per_page: Oldalanként + label_calendar: Naptár + label_months_from: hónap, kezdve + label_gantt: Gantt + label_internal: Belső + label_last_changes: "utolsó %{count} változás" + label_change_view_all: Minden változás megtekintése + label_personalize_page: Az oldal testreszabása + label_comment: Megjegyzés + label_comment_plural: Megjegyzés + label_x_comments: + zero: nincs megjegyzés + one: 1 megjegyzés + other: "%{count} megjegyzés" + label_comment_add: Megjegyzés hozzáadása + label_comment_added: Megjegyzés hozzáadva + label_comment_delete: Megjegyzések törlése + label_query: Egyéni lekérdezés + label_query_plural: Egyéni lekérdezések + label_query_new: Új lekérdezés + label_filter_add: Szűrő hozzáadása + label_filter_plural: Szűrők + label_equals: egyenlő + label_not_equals: nem egyenlő + label_in_less_than: kevesebb, mint + label_in_more_than: több, mint + label_in: in + label_today: ma + label_all_time: mindenkor + label_yesterday: tegnap + label_this_week: aktuális hét + label_last_week: múlt hét + label_last_n_days: "az elmúlt %{count} nap" + label_this_month: aktuális hónap + label_last_month: múlt hónap + label_this_year: aktuális év + label_date_range: Dátum intervallum + label_less_than_ago: kevesebb, mint nappal ezelőtt + label_more_than_ago: több, mint nappal ezelőtt + label_ago: nappal ezelőtt + label_contains: tartalmazza + label_not_contains: nem tartalmazza + label_day_plural: nap + label_repository: Forráskód + label_repository_plural: Forráskódok + label_browse: Tallóz + label_revision: Revízió + label_revision_plural: Revíziók + label_associated_revisions: Kapcsolt revíziók + label_added: hozzáadva + label_modified: módosítva + label_deleted: törölve + label_latest_revision: Legutolsó revízió + label_latest_revision_plural: Legutolsó revíziók + label_view_revisions: Revíziók megtekintése + label_max_size: Maximális méret + label_sort_highest: Az elejére + label_sort_higher: Eggyel feljebb + label_sort_lower: Eggyel lejjebb + label_sort_lowest: Az aljára + label_roadmap: Életút + label_roadmap_due_in: "Elkészültéig várhatóan még %{value}" + label_roadmap_overdue: "%{value} késésben" + label_roadmap_no_issues: Nincsenek feladatok ehhez a verzióhoz + label_search: Keresés + label_result_plural: Találatok + label_all_words: Minden szó + label_wiki: Wiki + label_wiki_edit: Wiki szerkesztés + label_wiki_edit_plural: Wiki szerkesztések + label_wiki_page: Wiki oldal + label_wiki_page_plural: Wiki oldalak + label_index_by_title: Cím szerint indexelve + label_index_by_date: Dátum szerint indexelve + label_current_version: Jelenlegi verzió + label_preview: Előnézet + label_feed_plural: Visszajelzések + label_changes_details: Változások részletei + label_issue_tracking: Feladat követés + label_spent_time: Ráfordított idő + label_f_hour: "%{value} óra" + label_f_hour_plural: "%{value} óra" + label_time_tracking: Idő rögzítés + label_change_plural: Változások + label_statistics: Statisztikák + label_commits_per_month: Commitok havonta + label_commits_per_author: Commitok szerzőnként + label_view_diff: Különbségek megtekintése + label_diff_inline: soronként + label_diff_side_by_side: egymás mellett + label_options: Opciók + label_copy_workflow_from: Workflow másolása innen + label_permissions_report: Jogosultsági riport + label_watched_issues: Megfigyelt feladatok + label_related_issues: Kapcsolódó feladatok + label_applied_status: Alkalmazandó státusz + label_loading: Betöltés... + label_relation_new: Új kapcsolat + label_relation_delete: Kapcsolat törlése + label_relates_to: kapcsolódik + label_duplicates: duplikálja + label_blocks: zárolja + label_blocked_by: zárolta + label_precedes: megelőzi + label_follows: követi + label_end_to_start: végétől indulásig + label_end_to_end: végétől végéig + label_start_to_start: indulástól indulásig + label_start_to_end: indulástól végéig + label_stay_logged_in: Emlékezzen rám + label_disabled: kikapcsolva + label_show_completed_versions: A kész verziók mutatása + label_me: én + label_board: Fórum + label_board_new: Új fórum + label_board_plural: Fórumok + label_topic_plural: Témák + label_message_plural: Üzenetek + label_message_last: Utolsó üzenet + label_message_new: Új üzenet + label_message_posted: Üzenet hozzáadva + label_reply_plural: Válaszok + label_send_information: Fiók infomációk küldése a felhasználónak + label_year: Év + label_month: Hónap + label_week: Hét + label_date_from: 'Kezdet:' + label_date_to: 'Vége:' + label_language_based: A felhasználó nyelve alapján + label_sort_by: "%{value} szerint rendezve" + label_send_test_email: Teszt e-mail küldése + label_feeds_access_key_created_on: "RSS hozzáférési kulcs létrehozva %{value}" + label_module_plural: Modulok + label_added_time_by: "%{author} adta hozzá %{age}" + label_updated_time: "Utolsó módosítás %{value}" + label_jump_to_a_project: Ugrás projekthez... + label_file_plural: Fájlok + label_changeset_plural: Changesets + label_default_columns: Alapértelmezett oszlopok + label_no_change_option: (Nincs változás) + label_bulk_edit_selected_issues: A kiválasztott feladatok kötegelt szerkesztése + label_theme: Téma + label_default: Alapértelmezett + label_search_titles_only: Keresés csak a címekben + label_user_mail_option_all: "Minden eseményről minden saját projektemben" + label_user_mail_option_selected: "Minden eseményről a kiválasztott projektekben..." + label_user_mail_no_self_notified: "Nem kérek értesítést az általam végzett módosításokról" + label_registration_activation_by_email: Fiók aktiválása e-mailben + label_registration_manual_activation: Manuális fiók aktiválás + label_registration_automatic_activation: Automatikus fiók aktiválás + label_display_per_page: "Oldalanként: %{value}" + label_age: Kor + label_change_properties: Tulajdonságok változtatása + label_general: Általános + label_more: továbbiak + label_scm: SCM + label_plugins: Pluginek + label_ldap_authentication: LDAP azonosítás + label_downloads_abbr: D/L + label_optional_description: Opcionális leírás + label_add_another_file: Újabb fájl hozzáadása + label_preferences: Tulajdonságok + label_chronological_order: Időrendben + label_reverse_chronological_order: Fordított időrendben + label_planning: Tervezés + + button_login: Bejelentkezés + button_submit: Elfogad + button_save: Mentés + button_check_all: Mindent kijelöl + button_uncheck_all: Kijelölés törlése + button_delete: Töröl + button_create: Létrehoz + button_test: Teszt + button_edit: Szerkeszt + button_add: Hozzáad + button_change: Változtat + button_apply: Alkalmaz + button_clear: Töröl + button_lock: Zárol + button_unlock: Felold + button_download: Letöltés + button_list: Lista + button_view: Megnéz + button_move: Mozgat + button_back: Vissza + button_cancel: Mégse + button_activate: Aktivál + button_sort: Rendezés + button_log_time: Idő rögzítés + button_rollback: Visszaáll erre a verzióra + button_watch: Megfigyel + button_unwatch: Megfigyelés törlése + button_reply: Válasz + button_archive: Archivál + button_unarchive: Dearchivál + button_reset: Reset + button_rename: Átnevez + button_change_password: Jelszó megváltoztatása + button_copy: Másol + button_annotate: Jegyzetel + button_update: Módosít + button_configure: Konfigurál + + status_active: aktív + status_registered: regisztrált + status_locked: zárolt + + text_select_mail_notifications: Válasszon eseményeket, amelyekről e-mail értesítést kell küldeni. + text_regexp_info: pl. ^[A-Z0-9]+$ + text_min_max_length_info: 0 = nincs korlátozás + text_project_destroy_confirmation: Biztosan törölni szeretné a projektet és vele együtt minden kapcsolódó adatot ? + text_subprojects_destroy_warning: "Az alprojekt(ek): %{value} szintén törlésre kerülnek." + text_workflow_edit: Válasszon egy szerepkört, és egy feladat típust a workflow szerkesztéséhez + text_are_you_sure: Biztos benne ? + text_tip_issue_begin_day: a feladat ezen a napon kezdődik + text_tip_issue_end_day: a feladat ezen a napon ér véget + text_tip_issue_begin_end_day: a feladat ezen a napon kezdődik és ér véget + text_caracters_maximum: "maximum %{count} karakter." + text_caracters_minimum: "Legkevesebb %{count} karakter hosszúnek kell lennie." + text_length_between: "Legalább %{min} és legfeljebb %{max} hosszú karakter." + text_tracker_no_workflow: Nincs workflow definiálva ehhez a feladat típushoz + text_unallowed_characters: Tiltott karakterek + text_comma_separated: Több érték megengedett (vesszővel elválasztva) + text_issues_ref_in_commit_messages: Hivatkozás feladatokra, feladatok javítása a commit üzenetekben + text_issue_added: "%{author} új feladatot hozott létre %{id} sorszámmal." + text_issue_updated: "%{author} módosította a %{id} sorszámú feladatot." + text_wiki_destroy_confirmation: Biztosan törölni szeretné ezt a wiki-t minden tartalmával együtt ? + text_issue_category_destroy_question: "Néhány feladat (%{count}) hozzá van rendelve ehhez a kategóriához. Mit szeretne tenni?" + text_issue_category_destroy_assignments: Kategória hozzárendelés megszüntetése + text_issue_category_reassign_to: Feladatok újra hozzárendelése másik kategóriához + text_user_mail_option: "A nem kiválasztott projektekről csak akkor kap értesítést, ha figyelést kér rá, vagy részt vesz benne (pl. Ön a létrehozó, vagy a hozzárendelő)" + text_no_configuration_data: "Szerepkörök, feladat típusok, feladat státuszok, és workflow adatok még nincsenek konfigurálva.\nErősen ajánlott, az alapértelmezett konfiguráció betöltése, és utána módosíthatja azt." + text_load_default_configuration: Alapértelmezett konfiguráció betöltése + text_status_changed_by_changeset: "Applied in changeset %{value}." + text_issues_destroy_confirmation: 'Biztos benne, hogy törölni szeretné a kijelölt feladato(ka)t ?' + text_select_project_modules: 'Válassza ki az engedélyezett modulokat ehhez a projekthez:' + text_default_administrator_account_changed: Alapértelmezett adminisztrátor fiók megváltoztatva + text_file_repository_writable: Fájl tároló írható + text_rmagick_available: RMagick elérhető (nem kötelező) + text_destroy_time_entries_question: "%{hours} órányi munka van rögzítve a feladatokon, amiket törölni szeretne. Mit szeretne tenni?" + text_destroy_time_entries: A rögzített órák törlése + text_assign_time_entries_to_project: A rögzített órák hozzárendelése a projekthez + text_reassign_time_entries: 'A rögzített órák újra hozzárendelése másik feladathoz:' + + default_role_manager: Vezető + default_role_developer: Fejlesztő + default_role_reporter: Bejelentő + default_tracker_bug: Hiba + default_tracker_feature: Fejlesztés + default_tracker_support: Támogatás + default_issue_status_new: Új + default_issue_status_in_progress: Folyamatban + default_issue_status_resolved: Megoldva + default_issue_status_feedback: Visszajelzés + default_issue_status_closed: Lezárt + default_issue_status_rejected: Elutasított + default_doc_category_user: Felhasználói dokumentáció + default_doc_category_tech: Technikai dokumentáció + default_priority_low: Alacsony + default_priority_normal: Normál + default_priority_high: Magas + default_priority_urgent: Sürgős + default_priority_immediate: Azonnal + default_activity_design: Tervezés + default_activity_development: Fejlesztés + + enumeration_issue_priorities: Feladat prioritások + enumeration_doc_categories: Dokumentum kategóriák + enumeration_activities: Tevékenységek (idő rögzítés) + mail_body_reminder: "%{count} neked kiosztott feladat határidős az elkövetkező %{days} napban:" + mail_subject_reminder: "%{count} feladat határidős az elkövetkező %{days} napban" + text_user_wrote: "%{value} írta:" + label_duplicated_by: duplikálta + setting_enabled_scm: Forráskódkezelő (SCM) engedélyezése + text_enumeration_category_reassign_to: 'Újra hozzárendelés ehhez:' + text_enumeration_destroy_question: "%{count} objektum van hozzárendelve ehhez az értékhez." + label_incoming_emails: Beérkezett levelek + label_generate_key: Kulcs generálása + setting_mail_handler_api_enabled: Web Service engedélyezése a beérkezett levelekhez + setting_mail_handler_api_key: API kulcs + text_email_delivery_not_configured: "Az E-mail küldés nincs konfigurálva, és az értesítések ki vannak kapcsolva.\nÁllítsd be az SMTP szervert a config/configuration.yml fájlban és indítsd újra az alkalmazást, hogy érvénybe lépjen." + field_parent_title: Szülő oldal + label_issue_watchers: Megfigyelők + button_quote: Hozzászólás / Idézet + setting_sequential_project_identifiers: Szekvenciális projekt azonosítók generálása + notice_unable_delete_version: A verziót nem lehet törölni + label_renamed: átnevezve + label_copied: lemásolva + setting_plain_text_mail: csak szöveg (nem HTML) + permission_view_files: Fájlok megtekintése + permission_edit_issues: Feladatok szerkesztése + permission_edit_own_time_entries: Saját időnapló szerkesztése + permission_manage_public_queries: Nyilvános kérések kezelése + permission_add_issues: Feladat felvétele + permission_log_time: Idő rögzítése + permission_view_changesets: Változáskötegek megtekintése + permission_view_time_entries: Időrögzítések megtekintése + permission_manage_versions: Verziók kezelése + permission_manage_wiki: Wiki kezelése + permission_manage_categories: Feladat kategóriák kezelése + permission_protect_wiki_pages: Wiki oldalak védelme + permission_comment_news: Hírek kommentelése + permission_delete_messages: Üzenetek törlése + permission_select_project_modules: Projekt modulok kezelése + permission_edit_wiki_pages: Wiki oldalak szerkesztése + permission_add_issue_watchers: Megfigyelők felvétele + permission_view_gantt: Gannt diagramm megtekintése + permission_move_issues: Feladatok mozgatása + permission_manage_issue_relations: Feladat kapcsolatok kezelése + permission_delete_wiki_pages: Wiki oldalak törlése + permission_manage_boards: Fórumok kezelése + permission_delete_wiki_pages_attachments: Csatolmányok törlése + permission_view_wiki_edits: Wiki történet megtekintése + permission_add_messages: Üzenet beküldése + permission_view_messages: Üzenetek megtekintése + permission_manage_files: Fájlok kezelése + permission_edit_issue_notes: Jegyzetek szerkesztése + permission_manage_news: Hírek kezelése + permission_view_calendar: Naptár megtekintése + permission_manage_members: Tagok kezelése + permission_edit_messages: Üzenetek szerkesztése + permission_delete_issues: Feladatok törlése + permission_view_issue_watchers: Megfigyelők listázása + permission_manage_repository: Tárolók kezelése + permission_commit_access: Commit hozzáférés + permission_browse_repository: Tároló böngészése + permission_view_documents: Dokumetumok megtekintése + permission_edit_project: Projekt szerkesztése + permission_add_issue_notes: Jegyzet rögzítése + permission_save_queries: Kérések mentése + permission_view_wiki_pages: Wiki megtekintése + permission_rename_wiki_pages: Wiki oldalak átnevezése + permission_edit_time_entries: Időnaplók szerkesztése + permission_edit_own_issue_notes: Saját jegyzetek szerkesztése + setting_gravatar_enabled: Felhasználói fényképek engedélyezése + label_example: Példa + text_repository_usernames_mapping: "Állítsd be a felhasználó összerendeléseket a Redmine, és a tároló logban található felhasználók között.\nAz azonos felhasználó nevek összerendelése automatikusan megtörténik." + permission_edit_own_messages: Saját üzenetek szerkesztése + permission_delete_own_messages: Saját üzenetek törlése + label_user_activity: "%{value} tevékenységei" + label_updated_time_by: "Módosította %{author} %{age}" + text_diff_truncated: '... A diff fájl vége nem jelenik meg, mert hosszab, mint a megjeleníthető sorok száma.' + setting_diff_max_lines_displayed: A megjelenítendő sorok száma (maximum) a diff fájloknál + text_plugin_assets_writable: Plugin eszközök könyvtár írható + warning_attachments_not_saved: "%{count} fájl mentése nem sikerült." + button_create_and_continue: Létrehozás és folytatás + text_custom_field_possible_values_info: 'Értékenként egy sor' + label_display: Megmutat + field_editable: Szerkeszthető + setting_repository_log_display_limit: Maximum hány revíziót mutasson meg a log megjelenítésekor + setting_file_max_size_displayed: Maximum mekkora szövegfájlokat jelenítsen meg soronkénti összehasonlításnál + field_watcher: Megfigyelő + setting_openid: OpenID regisztráció és bejelentkezés engedélyezése + field_identity_url: OpenID URL + label_login_with_open_id_option: bejelentkezés OpenID használatával + field_content: Tartalom + label_descending: Csökkenő + label_sort: Rendezés + label_ascending: Növekvő + label_date_from_to: "%{start} -tól %{end} -ig" + label_greater_or_equal: ">=" + label_less_or_equal: "<=" + text_wiki_page_destroy_question: Ennek az oldalnak %{descendants} gyermek-, és leszármazott oldala van. Mit szeretne tenni? + text_wiki_page_reassign_children: Aloldalak hozzárendelése ehhez a szülő oldalhoz + text_wiki_page_nullify_children: Aloldalak átalakítása főoldallá + text_wiki_page_destroy_children: Minden aloldal és leszármazottjának törlése + setting_password_min_length: Minimum jelszó hosszúság + field_group_by: Szerint csoportosítva + mail_subject_wiki_content_updated: "'%{id}' wiki oldal frissítve" + label_wiki_content_added: Wiki oldal hozzáadva + mail_subject_wiki_content_added: "Új wiki oldal: '%{id}'" + mail_body_wiki_content_added: "%{author} létrehozta a '%{id}' wiki oldalt." + label_wiki_content_updated: Wiki oldal frissítve + mail_body_wiki_content_updated: "%{author} frissítette a '%{id}' wiki oldalt." + permission_add_project: Projekt létrehozása + setting_new_project_user_role_id: Projekt létrehozási jog nem adminisztrátor felhasználóknak + label_view_all_revisions: Összes verzió + label_tag: Tag + label_branch: Branch + error_no_tracker_in_project: Nincs feladat típus hozzárendelve ehhez a projekthez. Kérem ellenőrizze a projekt beállításait. + error_no_default_issue_status: Nincs alapértelmezett feladat státusz beállítva. Kérem ellenőrizze a beállításokat (Itt találja "Adminisztráció -> Feladat státuszok"). + text_journal_changed: "%{label} megváltozott, %{old} helyett %{new} lett" + text_journal_set_to: "%{label} új értéke: %{value}" + text_journal_deleted: "%{label} törölve lett (%{old})" + label_group_plural: Csoportok + label_group: Csoport + label_group_new: Új csoport + label_time_entry_plural: Időráfordítás + text_journal_added: "%{label} %{value} hozzáadva" + field_active: Aktív + enumeration_system_activity: Rendszertevékenység + permission_delete_issue_watchers: Megfigyelők törlése + version_status_closed: lezárt + version_status_locked: zárolt + version_status_open: nyitott + error_can_not_reopen_issue_on_closed_version: Lezárt verzióhoz rendelt feladatot nem lehet újranyitni + label_user_anonymous: Névtelen + button_move_and_follow: Mozgatás és követés + setting_default_projects_modules: Alapértelmezett modulok az új projektekhez + setting_gravatar_default: Alapértelmezett Gravatar kép + field_sharing: Megosztás + label_version_sharing_hierarchy: Projekt hierarchiával + label_version_sharing_system: Minden projekttel + label_version_sharing_descendants: Alprojektekkel + label_version_sharing_tree: Projekt fával + label_version_sharing_none: Nincs megosztva + error_can_not_archive_project: A projektet nem lehet archiválni + button_duplicate: Duplikálás + button_copy_and_follow: Másolás és követés + label_copy_source: Forrás + setting_issue_done_ratio: Feladat készültségi szint számolása a következő alapján + setting_issue_done_ratio_issue_status: Feladat státusz alapján + error_issue_done_ratios_not_updated: A feladat készültségi szintek nem lettek frissítve. + error_workflow_copy_target: Kérem válasszon cél feladat típus(oka)t és szerepkör(öke)t. + setting_issue_done_ratio_issue_field: A feladat mező alapján + label_copy_same_as_target: A céllal egyező + label_copy_target: Cél + notice_issue_done_ratios_updated: Feladat készültségi szintek frissítve. + error_workflow_copy_source: Kérem válasszon forrás feladat típust vagy szerepkört + label_update_issue_done_ratios: Feladat készültségi szintek frissítése + setting_start_of_week: A hét első napja + permission_view_issues: Feladatok megtekintése + label_display_used_statuses_only: Csak olyan feladat státuszok megjelenítése, amit ez a feladat típus használ + label_revision_id: Revízió %{value} + label_api_access_key: API hozzáférési kulcs + label_api_access_key_created_on: API hozzáférési kulcs létrehozva %{value} ezelőtt + label_feeds_access_key: RSS hozzáférési kulcs + notice_api_access_key_reseted: Az API hozzáférési kulcsa újragenerálva. + setting_rest_api_enabled: REST web service engedélyezése + label_missing_api_access_key: Egy API hozzáférési kulcs hiányzik + label_missing_feeds_access_key: RSS hozzáférési kulcs hiányzik + button_show: Megmutat + text_line_separated: Több érték megadása lehetséges (soronként 1 érték). + setting_mail_handler_body_delimiters: E-mailek levágása a következő sorok valamelyike esetén + permission_add_subprojects: Alprojektek létrehozása + label_subproject_new: Új alprojekt + text_own_membership_delete_confirmation: |- + Arra készül, hogy eltávolítja egyes vagy minden jogosultságát! Ezt követően lehetséges, hogy nem fogja tudni szerkeszteni ezt a projektet! + Biztosan folyatni szeretné? + label_close_versions: Kész verziók lezárása + label_board_sticky: Sticky + setting_cache_formatted_text: Formázott szöveg gyorsítótárazása (Cache) + permission_export_wiki_pages: Wiki oldalak exportálása + permission_manage_project_activities: Projekt tevékenységek kezelése + label_board_locked: Zárolt + error_can_not_delete_custom_field: Nem lehet törölni az egyéni mezőt + permission_manage_subtasks: Alfeladatok kezelése + label_profile: Profil + error_unable_to_connect: Nem lehet csatlakozni (%{value}) + error_can_not_remove_role: Ez a szerepkör használatban van és ezért nem törölhető- + field_parent_issue: Szülő feladat + error_unable_delete_issue_status: Nem lehet törölni a feladat állapotát + label_subtask_plural: Alfeladatok + error_can_not_delete_tracker: Ebbe a kategóriába feladatok tartoznak és ezért nem törölhető. + label_project_copy_notifications: Küldjön e-mail értesítéseket projektmásolás közben. + field_principal: Felelős + label_my_page_block: Saját kezdőlap-blokk + notice_failed_to_save_members: "Nem sikerült menteni a tago(ka)t: %{errors}." + text_zoom_out: Kicsinyít + text_zoom_in: Nagyít + notice_unable_delete_time_entry: Az időrögzítés nem törölhető + label_overall_spent_time: Összes ráfordított idő + field_time_entries: Idő rögzítés + project_module_gantt: Gantt + project_module_calendar: Naptár + button_edit_associated_wikipage: "Hozzárendelt Wiki oldal szerkesztése: %{page_title}" + field_text: Szöveg mező + label_user_mail_option_only_owner: Csak arról, aminek én vagyok a tulajdonosa + setting_default_notification_option: Alapértelmezett értesítési beállítások + label_user_mail_option_only_my_events: Csak az általam megfigyelt dolgokról vagy amiben részt veszek + label_user_mail_option_only_assigned: Csak a hozzámrendelt dolgokról + label_user_mail_option_none: Semilyen eseményről + field_member_of_group: Hozzárendelt csoport + field_assigned_to_role: Hozzárendelt szerepkör + notice_not_authorized_archived_project: A projekt, amihez hozzá szeretnél férni archiválva lett. + label_principal_search: "Felhasználó vagy csoport keresése:" + label_user_search: "Felhasználó keresése:" + field_visible: Látható + setting_emails_header: Emailek fejléce + setting_commit_logtime_activity_id: A rögzített időhöz tartozó tevékenység + text_time_logged_by_changeset: Alkalmazva a %{value} changeset-ben. + setting_commit_logtime_enabled: Időrögzítés engedélyezése + notice_gantt_chart_truncated: A diagram le lett vágva, mert elérte a maximálisan megjeleníthető elemek számát (%{max}) + setting_gantt_items_limit: A gantt diagrammon megjeleníthető maximális elemek száma + field_warn_on_leaving_unsaved: Figyelmeztessen, nem mentett módosításokat tartalmazó oldal elhagyásakor + text_warn_on_leaving_unsaved: A jelenlegi oldal nem mentett módosításokat tartalmaz, ami elvész, ha elhagyja az oldalt. + label_my_queries: Egyéni lekérdezéseim + text_journal_changed_no_detail: "%{label} módosítva" + label_news_comment_added: Megjegyzés hozzáadva a hírhez + button_expand_all: Mindet kibont + button_collapse_all: Mindet összecsuk + label_additional_workflow_transitions_for_assignee: További átmenetek engedélyezettek, ha a felhasználó a hozzárendelt + label_additional_workflow_transitions_for_author: További átmenetek engedélyezettek, ha a felhasználó a szerző + label_bulk_edit_selected_time_entries: A kiválasztott idő bejegyzések csoportos szerkesztése + text_time_entries_destroy_confirmation: Biztos benne, hogy törölni szeretné a kiválasztott idő bejegyzés(eke)t? + label_role_anonymous: Anonymous + label_role_non_member: Nem tag + label_issue_note_added: Jegyzet hozzáadva + label_issue_status_updated: Állapot módosítva + label_issue_priority_updated: Prioritás módosítva + label_issues_visibility_own: A felhasználó által létrehozott vagy hozzárendelt feladatok + field_issues_visibility: Feladatok láthatósága + label_issues_visibility_all: Minden feladat + permission_set_own_issues_private: Saját feladatok beállítása nyilvánosra vagy privátra + field_is_private: Privát + permission_set_issues_private: Feladatok beállítása nyilvánosra vagy privátra + label_issues_visibility_public: Minden nem privát feladat + text_issues_destroy_descendants_confirmation: Ezzel törölni fog %{count} alfeladatot is. + field_commit_logs_encoding: Commit üzenetek kódlapja + field_scm_path_encoding: Elérési útvonal kódlapja + text_scm_path_encoding_note: "Alapértelmezett: UTF-8" + field_path_to_repository: A repository elérési útja + field_root_directory: Gyökér könyvtár + field_cvs_module: Modul + field_cvsroot: CVSROOT + text_mercurial_repository_note: Helyi repository (e.g. /hgrepo, c:\hgrepo) + text_scm_command: Parancs + text_scm_command_version: Verzió + label_git_report_last_commit: Report last commit for files and directories + notice_issue_successful_create: Issue %{id} created. + label_between: between + setting_issue_group_assignment: Allow issue assignment to groups + label_diff: diff + text_git_repository_note: Repository is bare and local (e.g. /gitrepo, c:\gitrepo) + description_query_sort_criteria_direction: Sort direction + description_project_scope: Search scope + description_filter: Filter + description_user_mail_notification: Mail notification settings + description_date_from: Enter start date + description_message_content: Message content + description_available_columns: Available Columns + description_date_range_interval: Choose range by selecting start and end date + description_issue_category_reassign: Choose issue category + description_search: Searchfield + description_notes: Notes + description_date_range_list: Choose range from list + description_choose_project: Projects + description_date_to: Enter end date + description_query_sort_criteria_attribute: Sort attribute + description_wiki_subpages_reassign: Choose new parent page + description_selected_columns: Selected Columns + label_parent_revision: Parent + label_child_revision: Child + error_scm_annotate_big_text_file: The entry cannot be annotated, as it exceeds the maximum text file size. + setting_default_issue_start_date_to_creation_date: Use current date as start date for new issues + button_edit_section: Edit this section + setting_repositories_encodings: Attachments and repositories encodings + description_all_columns: All Columns + button_export: Export + label_export_options: "%{export_format} export options" + error_attachment_too_big: This file cannot be uploaded because it exceeds the maximum allowed file size (%{max_size}) + notice_failed_to_save_time_entries: "Failed to save %{count} time entrie(s) on %{total} selected: %{ids}." + label_x_issues: + zero: 0 feladat + one: 1 feladat + other: "%{count} feladatok" + label_repository_new: New repository + field_repository_is_default: Main repository + label_copy_attachments: Copy attachments + label_item_position: "%{position}/%{count}" + label_completed_versions: Completed versions + text_project_identifier_info: Only lower case letters (a-z), numbers, dashes and underscores are allowed.
    Once saved, the identifier cannot be changed. + field_multiple: Multiple values + setting_commit_cross_project_ref: Allow issues of all the other projects to be referenced and fixed + text_issue_conflict_resolution_add_notes: Add my notes and discard my other changes + text_issue_conflict_resolution_overwrite: Apply my changes anyway (previous notes will be kept but some changes may be overwritten) + notice_issue_update_conflict: The issue has been updated by an other user while you were editing it. + text_issue_conflict_resolution_cancel: Discard all my changes and redisplay %{link} + permission_manage_related_issues: Manage related issues + field_auth_source_ldap_filter: LDAP filter + label_search_for_watchers: Search for watchers to add + notice_account_deleted: Your account has been permanently deleted. + setting_unsubscribe: Allow users to delete their own account + button_delete_my_account: Delete my account + text_account_destroy_confirmation: |- + Are you sure you want to proceed? + Your account will be permanently deleted, with no way to reactivate it. + error_session_expired: Your session has expired. Please login again. + text_session_expiration_settings: "Warning: changing these settings may expire the current sessions including yours." + setting_session_lifetime: Session maximum lifetime + setting_session_timeout: Session inactivity timeout + label_session_expiration: Session expiration + permission_close_project: Close / reopen the project + label_show_closed_projects: View closed projects + button_close: Close + button_reopen: Reopen + project_status_active: active + project_status_closed: closed + project_status_archived: archived + text_project_closed: This project is closed and read-only. + notice_user_successful_create: User %{id} created. + field_core_fields: Standard fields + field_timeout: Timeout (in seconds) + setting_thumbnails_enabled: Display attachment thumbnails + setting_thumbnails_size: Thumbnails size (in pixels) + label_status_transitions: Status transitions + label_fields_permissions: Fields permissions + label_readonly: Read-only + label_required: Required + text_repository_identifier_info: Only lower case letters (a-z), numbers, dashes and underscores are allowed.
    Once saved, the identifier cannot be changed. + field_board_parent: Parent forum + label_attribute_of_project: Project's %{name} + label_attribute_of_author: Author's %{name} + label_attribute_of_assigned_to: Assignee's %{name} + label_attribute_of_fixed_version: Target version's %{name} + label_copy_subtasks: Copy subtasks + label_copied_to: copied to + label_copied_from: copied from + label_any_issues_in_project: any issues in project + label_any_issues_not_in_project: any issues not in project + field_private_notes: Private notes + permission_view_private_notes: View private notes + permission_set_notes_private: Set notes as private + label_no_issues_in_project: no issues in project + label_any: mind + label_last_n_weeks: last %{count} weeks + setting_cross_project_subtasks: Allow cross-project subtasks + label_cross_project_descendants: Alprojektekkel + label_cross_project_tree: Projekt fával + label_cross_project_hierarchy: Projekt hierarchiával + label_cross_project_system: Minden projekttel + button_hide: Hide + setting_non_working_week_days: Non-working days + label_in_the_next_days: in the next + label_in_the_past_days: in the past + label_attribute_of_user: User's %{name} + text_turning_multiple_off: If you disable multiple values, multiple values will be + removed in order to preserve only one value per item. + label_attribute_of_issue: Issue's %{name} + permission_add_documents: Add documents + permission_edit_documents: Edit documents + permission_delete_documents: Delete documents + label_gantt_progress_line: Progress line + setting_jsonp_enabled: Enable JSONP support + field_inherit_members: Inherit members + field_closed_on: Closed + setting_default_projects_tracker_ids: Default trackers for new projects + label_total_time: Összesen + text_scm_config: You can configure your SCM commands in config/configuration.yml. Please restart the application after editing it. + text_scm_command_not_available: SCM command is not available. Please check settings on the administration panel. diff --git a/config/locales/id.yml b/config/locales/id.yml new file mode 100644 index 00000000..5dc5afeb --- /dev/null +++ b/config/locales/id.yml @@ -0,0 +1,1093 @@ +# Indonesian translations +# by Raden Prabowo (cakbowo@gmail.com) + +id: + direction: ltr + date: + formats: + default: "%d-%m-%Y" + short: "%d %b" + long: "%d %B %Y" + + day_names: [Minggu, Senin, Selasa, Rabu, Kamis, Jumat, Sabtu] + abbr_day_names: [Ming, Sen, Sel, Rab, Kam, Jum, Sab] + + month_names: [~, Januari, Februari, Maret, April, Mei, Juni, Juli, Agustus, September, Oktober, November, Desember] + abbr_month_names: [~, Jan, Feb, Mar, Apr, Mei, Jun, Jul, Agu, Sep, Okt, Nov, Des] + order: + - :day + - :month + - :year + + time: + formats: + default: "%a %d %b %Y, %H:%M:%S" + time: "%H:%M" + short: "%d %b %H:%M" + long: "%d %B %Y %H:%M" + am: "am" + pm: "pm" + + datetime: + distance_in_words: + half_a_minute: "setengah menit" + less_than_x_seconds: + one: "kurang dari sedetik" + other: "kurang dari %{count} detik" + x_seconds: + one: "sedetik" + other: "%{count} detik" + less_than_x_minutes: + one: "kurang dari semenit" + other: "kurang dari %{count} menit" + x_minutes: + one: "semenit" + other: "%{count} menit" + about_x_hours: + one: "sekitar sejam" + other: "sekitar %{count} jam" + x_hours: + one: "1 hour" + other: "%{count} hours" + x_days: + one: "sehari" + other: "%{count} hari" + about_x_months: + one: "sekitar sebulan" + other: "sekitar %{count} bulan" + x_months: + one: "sebulan" + other: "%{count} bulan" + about_x_years: + one: "sekitar setahun" + other: "sekitar %{count} tahun" + over_x_years: + one: "lebih dari setahun" + other: "lebih dari %{count} tahun" + almost_x_years: + one: "almost 1 year" + other: "almost %{count} years" + + number: + format: + precision: 3 + separator: ',' + delimiter: '.' + currency: + format: + unit: 'Rp' + precision: 2 + format: '%n %u' + human: + format: + delimiter: "" + precision: 3 + storage_units: + format: "%n %u" + units: + byte: + one: "Byte" + other: "Bytes" + kb: "KB" + mb: "MB" + gb: "GB" + tb: "TB" + + support: + array: + sentence_connector: "dan" + skip_last_comma: false + + activerecord: + errors: + template: + header: + one: "1 error prohibited this %{model} from being saved" + other: "%{count} errors prohibited this %{model} from being saved" + messages: + inclusion: "tidak termasuk dalam daftar" + exclusion: "sudah dicadangkan" + invalid: "salah" + confirmation: "tidak sesuai konfirmasi" + accepted: "harus disetujui" + empty: "tidak boleh kosong" + blank: "tidak boleh kosong" + too_long: "terlalu panjang (maksimum %{count} karakter)" + too_short: "terlalu pendek (minimum %{count} karakter)" + wrong_length: "panjangnya salah (seharusnya %{count} karakter)" + taken: "sudah diambil" + not_a_number: "bukan angka" + not_a_date: "bukan tanggal" + greater_than: "harus lebih besar dari %{count}" + greater_than_or_equal_to: "harus lebih besar atau sama dengan %{count}" + equal_to: "harus sama dengan %{count}" + less_than: "harus kurang dari %{count}" + less_than_or_equal_to: "harus kurang atau sama dengan %{count}" + odd: "harus ganjil" + even: "harus genap" + greater_than_start_date: "harus lebih besar dari tanggal mulai" + not_same_project: "tidak tergabung dalam proyek yang sama" + circular_dependency: "kaitan ini akan menghasilkan circular dependency" + cant_link_an_issue_with_a_descendant: "An issue can not be linked to one of its subtasks" + + actionview_instancetag_blank_option: Silakan pilih + + general_text_No: 'Tidak' + general_text_Yes: 'Ya' + general_text_no: 'tidak' + general_text_yes: 'ya' + general_lang_name: 'Indonesia' + general_csv_separator: ',' + general_csv_decimal_separator: '.' + general_csv_encoding: ISO-8859-1 + general_pdf_encoding: UTF-8 + general_first_day_of_week: '7' + + notice_account_updated: Akun sudah berhasil diperbarui. + notice_account_invalid_creditentials: Pengguna atau kata sandi salah + notice_account_password_updated: Kata sandi sudah berhasil diperbarui. + notice_account_wrong_password: Kata sandi salah. + notice_account_register_done: Akun sudah berhasil dibuat. Untuk mengaktifkan akun anda, silakan klik tautan (link) yang dikirim kepada anda melalui e-mail. + notice_account_unknown_email: Pengguna tidak dikenal. + notice_can_t_change_password: Akun ini menggunakan sumber otentikasi eksternal yang tidak dikenal. Kata sandi tidak bisa diubah. + notice_account_lost_email_sent: Email berisi instruksi untuk memilih kata sandi baru sudah dikirimkan kepada anda. + notice_account_activated: Akun anda sudah diaktifasi. Sekarang anda bisa login. + notice_successful_create: Berhasil dibuat. + notice_successful_update: Berhasil diperbarui. + notice_successful_delete: Berhasil dihapus. + notice_successful_connection: Berhasil terhubung. + notice_file_not_found: Berkas yang anda buka tidak ada atau sudah dihapus. + notice_locking_conflict: Data sudah diubah oleh pengguna lain. + notice_not_authorized: Anda tidak memiliki akses ke halaman ini. + notice_email_sent: "Email sudah dikirim ke %{value}" + notice_email_error: "Terjadi kesalahan pada saat pengiriman email (%{value})" + notice_feeds_access_key_reseted: RSS access key anda sudah direset. + notice_failed_to_save_issues: "Gagal menyimpan %{count} masalah dari %{total} yang dipilih: %{ids}." + notice_no_issue_selected: "Tidak ada masalah yang dipilih! Silakan pilih masalah yang akan anda sunting." + notice_account_pending: "Akun anda sudah dibuat dan sekarang sedang menunggu persetujuan administrator." + notice_default_data_loaded: Konfigurasi default sudah berhasil dimuat. + notice_unable_delete_version: Tidak bisa menghapus versi. + + error_can_t_load_default_data: "Konfigurasi default tidak bisa dimuat: %{value}" + error_scm_not_found: "Entri atau revisi tidak terdapat pada repositori." + error_scm_command_failed: "Terjadi kesalahan pada saat mengakses repositori: %{value}" + error_scm_annotate: "Entri tidak ada, atau tidak dapat di anotasi." + error_issue_not_found_in_project: 'Masalah tidak ada atau tidak tergabung dalam proyek ini.' + error_no_tracker_in_project: 'Tidak ada pelacak yang diasosiasikan pada proyek ini. Silakan pilih Pengaturan Proyek.' + error_no_default_issue_status: 'Nilai default untuk Status masalah belum didefinisikan. Periksa kembali konfigurasi anda (Pilih "Administrasi --> Status masalah").' + error_can_not_reopen_issue_on_closed_version: 'Masalah yang ditujukan pada versi tertutup tidak bisa dibuka kembali' + error_can_not_archive_project: Proyek ini tidak bisa diarsipkan + + warning_attachments_not_saved: "%{count} berkas tidak bisa disimpan." + + mail_subject_lost_password: "Kata sandi %{value} anda" + mail_body_lost_password: 'Untuk mengubah kata sandi anda, klik tautan berikut::' + mail_subject_register: "Aktivasi akun %{value} anda" + mail_body_register: 'Untuk mengaktifkan akun anda, klik tautan berikut:' + mail_body_account_information_external: "Anda dapat menggunakan akun %{value} anda untuk login." + mail_body_account_information: Informasi akun anda + mail_subject_account_activation_request: "Permintaan aktivasi akun %{value} " + mail_body_account_activation_request: "Pengguna baru (%{value}) sudan didaftarkan. Akun tersebut menunggu persetujuan anda:" + mail_subject_reminder: "%{count} masalah harus selesai pada hari berikutnya (%{days})" + mail_body_reminder: "%{count} masalah yang ditugaskan pada anda harus selesai dalam %{days} hari kedepan:" + mail_subject_wiki_content_added: "'%{id}' halaman wiki sudah ditambahkan" + mail_body_wiki_content_added: "The '%{id}' halaman wiki sudah ditambahkan oleh %{author}." + mail_subject_wiki_content_updated: "'%{id}' halaman wiki sudah diperbarui" + mail_body_wiki_content_updated: "The '%{id}' halaman wiki sudah diperbarui oleh %{author}." + + + field_name: Nama + field_description: Deskripsi + field_summary: Ringkasan + field_is_required: Dibutuhkan + field_firstname: Nama depan + field_lastname: Nama belakang + field_mail: Email + field_filename: Berkas + field_filesize: Ukuran + field_downloads: Unduhan + field_author: Pengarang + field_created_on: Dibuat + field_updated_on: Diperbarui + field_field_format: Format + field_is_for_all: Untuk semua proyek + field_possible_values: Nilai yang mungkin + field_regexp: Regular expression + field_min_length: Panjang minimum + field_max_length: Panjang maksimum + field_value: Nilai + field_category: Kategori + field_title: Judul + field_project: Proyek + field_issue: Masalah + field_status: Status + field_notes: Catatan + field_is_closed: Masalah ditutup + field_is_default: Nilai default + field_tracker: Pelacak + field_subject: Perihal + field_due_date: Harus selesai + field_assigned_to: Ditugaskan ke + field_priority: Prioritas + field_fixed_version: Versi target + field_user: Pengguna + field_role: Peran + field_homepage: Halaman web + field_is_public: Publik + field_parent: Subproyek dari + field_is_in_roadmap: Masalah ditampilkan di rencana kerja + field_login: Login + field_mail_notification: Notifikasi email + field_admin: Administrator + field_last_login_on: Terakhir login + field_language: Bahasa + field_effective_date: Tanggal + field_password: Kata sandi + field_new_password: Kata sandi baru + field_password_confirmation: Konfirmasi + field_version: Versi + field_type: Tipe + field_host: Host + field_port: Port + field_account: Akun + field_base_dn: Base DN + field_attr_login: Atribut login + field_attr_firstname: Atribut nama depan + field_attr_lastname: Atribut nama belakang + field_attr_mail: Atribut email + field_onthefly: Pembuatan pengguna seketika + field_start_date: Mulai + field_done_ratio: "% Selesai" + field_auth_source: Mode otentikasi + field_hide_mail: Sembunyikan email saya + field_comments: Komentar + field_url: URL + field_start_page: Halaman awal + field_subproject: Subproyek + field_hours: Jam + field_activity: Kegiatan + field_spent_on: Tanggal + field_identifier: Pengenal + field_is_filter: Digunakan sebagai penyaring + field_issue_to: Masalah terkait + field_delay: Tertunday + field_assignable: Masalah dapat ditugaskan pada peran ini + field_redirect_existing_links: Alihkan tautan yang ada + field_estimated_hours: Perkiraan waktu + field_column_names: Kolom + field_time_zone: Zona waktu + field_searchable: Dapat dicari + field_default_value: Nilai default + field_comments_sorting: Tampilkan komentar + field_parent_title: Halaman induk + field_editable: Dapat disunting + field_watcher: Pemantau + field_identity_url: OpenID URL + field_content: Isi + field_group_by: Dikelompokkan berdasar + field_sharing: Berbagi + + setting_app_title: Judul aplikasi + setting_app_subtitle: Subjudul aplikasi + setting_welcome_text: Teks sambutan + setting_default_language: Bahasa Default + setting_login_required: Butuhkan otentikasi + setting_self_registration: Swa-pendaftaran + setting_attachment_max_size: Ukuran maksimum untuk lampiran + setting_issues_export_limit: Batasan ukuran export masalah + setting_mail_from: Emisi alamat email + setting_bcc_recipients: Blind carbon copy recipients (bcc) + setting_plain_text_mail: Plain text mail (no HTML) + setting_host_name: Nama host dan path + setting_text_formatting: Format teks + setting_wiki_compression: Kompresi untuk riwayat wiki + setting_feeds_limit: Batasan isi feed + setting_default_projects_public: Proyek baru defaultnya adalah publik + setting_autofetch_changesets: Autofetch commits + setting_sys_api_enabled: Aktifkan WS untuk pengaturan repositori + setting_commit_ref_keywords: Referensi kaca kunci + setting_commit_fix_keywords: Pembetulan kaca kunci + setting_autologin: Autologin + setting_date_format: Format tanggal + setting_time_format: Format waktu + setting_cross_project_issue_relations: Perbolehkan kaitan masalah proyek berbeda + setting_issue_list_default_columns: Kolom default ditampilkan di daftar masalah + setting_emails_footer: Footer untuk email + setting_protocol: Protokol + setting_per_page_options: Pilihan obyek per halaman + setting_user_format: Format tampilan untuk pengguna + setting_activity_days_default: Hari tertampil pada kegiatan proyek + setting_display_subprojects_issues: Secara default, tampilkan masalah subproyek pada proyek utama + setting_enabled_scm: Enabled SCM + setting_mail_handler_api_enabled: Enable WS for incoming emails + setting_mail_handler_api_key: API key + setting_sequential_project_identifiers: Buat pengenal proyek terurut + setting_gravatar_enabled: Gunakan icon pengguna dari Gravatar + setting_gravatar_default: Gambar default untuk Gravatar + setting_diff_max_lines_displayed: Maksimum perbedaan baris tertampil + setting_file_max_size_displayed: Maksimum berkas tertampil secara inline + setting_repository_log_display_limit: Nilai maksimum dari revisi ditampilkan di log berkas + setting_openid: Perbolehkan Login dan pendaftaran melalui OpenID + setting_password_min_length: Panjang minimum untuk kata sandi + setting_new_project_user_role_id: Peran diberikan pada pengguna non-admin yang membuat proyek + setting_default_projects_modules: Modul yang diaktifkan pada proyek baru + + permission_add_project: Tambahkan proyek + permission_edit_project: Sunting proyek + permission_select_project_modules: Pilih modul proyek + permission_manage_members: Atur anggota + permission_manage_versions: Atur versi + permission_manage_categories: Atur kategori masalah + permission_add_issues: Tambahkan masalah + permission_edit_issues: Sunting masalah + permission_manage_issue_relations: Atur kaitan masalah + permission_add_issue_notes: Tambahkan catatan + permission_edit_issue_notes: Sunting catatan + permission_edit_own_issue_notes: Sunting catatan saya + permission_move_issues: Pindahkan masalah + permission_delete_issues: Hapus masalah + permission_manage_public_queries: Atur query publik + permission_save_queries: Simpan query + permission_view_gantt: Tampilkan gantt chart + permission_view_calendar: Tampilkan kalender + permission_view_issue_watchers: Tampilkan daftar pemantau + permission_add_issue_watchers: Tambahkan pemantau + permission_delete_issue_watchers: Hapus pemantau + permission_log_time: Log waktu terpakai + permission_view_time_entries: Tampilkan waktu terpakai + permission_edit_time_entries: Sunting catatan waktu + permission_edit_own_time_entries: Sunting catatan waktu saya + permission_manage_news: Atur berita + permission_comment_news: Komentari berita + permission_view_documents: Tampilkan dokumen + permission_manage_files: Atur berkas + permission_view_files: Tampilkan berkas + permission_manage_wiki: Atur wiki + permission_rename_wiki_pages: Ganti nama halaman wiki + permission_delete_wiki_pages: Hapus halaman wiki + permission_view_wiki_pages: Tampilkan wiki + permission_view_wiki_edits: Tampilkan riwayat wiki + permission_edit_wiki_pages: Sunting halaman wiki + permission_delete_wiki_pages_attachments: Hapus lampiran + permission_protect_wiki_pages: Proteksi halaman wiki + permission_manage_repository: Atur repositori + permission_browse_repository: Jelajah repositori + permission_view_changesets: Tampilkan set perubahan + permission_commit_access: Commit akses + permission_manage_boards: Atur forum + permission_view_messages: Tampilkan pesan + permission_add_messages: Tambahkan pesan + permission_edit_messages: Sunting pesan + permission_edit_own_messages: Sunting pesan saya + permission_delete_messages: Hapus pesan + permission_delete_own_messages: Hapus pesan saya + + project_module_issue_tracking: Pelacak masalah + project_module_time_tracking: Pelacak waktu + project_module_news: Berita + project_module_documents: Dokumen + project_module_files: Berkas + project_module_wiki: Wiki + project_module_repository: Repositori + project_module_boards: Forum + + label_user: Pengguna + label_user_plural: Pengguna + label_user_new: Pengguna baru + label_user_anonymous: Anonymous + label_project: Proyek + label_project_new: Proyek baru + label_project_plural: Proyek + label_x_projects: + zero: tidak ada proyek + one: 1 proyek + other: "%{count} proyek" + label_project_all: Semua Proyek + label_project_latest: Proyek terakhir + label_issue: Masalah + label_issue_new: Masalah baru + label_issue_plural: Masalah + label_issue_view_all: tampilkan semua masalah + label_issues_by: "Masalah ditambahkan oleh %{value}" + label_issue_added: Masalah ditambahan + label_issue_updated: Masalah diperbarui + label_document: Dokumen + label_document_new: Dokumen baru + label_document_plural: Dokumen + label_document_added: Dokumen ditambahkan + label_role: Peran + label_role_plural: Peran + label_role_new: Peran baru + label_role_and_permissions: Peran dan perijinan + label_member: Anggota + label_member_new: Anggota baru + label_member_plural: Anggota + label_tracker: Pelacak + label_tracker_plural: Pelacak + label_tracker_new: Pelacak baru + label_workflow: Alur kerja + label_issue_status: Status masalah + label_issue_status_plural: Status masalah + label_issue_status_new: Status baru + label_issue_category: Kategori masalah + label_issue_category_plural: Kategori masalah + label_issue_category_new: Kategori baru + label_custom_field: Field kustom + label_custom_field_plural: Field kustom + label_custom_field_new: Field kustom + label_enumerations: Enumerasi + label_enumeration_new: Buat baru + label_information: Informasi + label_information_plural: Informasi + label_please_login: Silakan login + label_register: mendaftar + label_login_with_open_id_option: atau login menggunakan OpenID + label_password_lost: Lupa password + label_home: Halaman depan + label_my_page: Beranda + label_my_account: Akun saya + label_my_projects: Proyek saya + label_administration: Administrasi + label_login: Login + label_logout: Keluar + label_help: Bantuan + label_reported_issues: Masalah terlapor + label_assigned_to_me_issues: Masalah yang ditugaskan pada saya + label_last_login: Terakhir login + label_registered_on: Terdaftar pada + label_activity: Kegiatan + label_overall_activity: Kegiatan umum + label_user_activity: "kegiatan %{value}" + label_new: Baru + label_logged_as: Login sebagai + label_environment: Lingkungan + label_authentication: Otentikasi + label_auth_source: Mode Otentikasi + label_auth_source_new: Mode otentikasi baru + label_auth_source_plural: Mode Otentikasi + label_subproject_plural: Subproyek + label_and_its_subprojects: "%{value} dan subproyeknya" + label_min_max_length: Panjang Min - Maks + label_list: Daftar + label_date: Tanggal + label_integer: Integer + label_float: Float + label_boolean: Boolean + label_string: Text + label_text: Long text + label_attribute: Atribut + label_attribute_plural: Atribut + label_no_data: Tidak ada data untuk ditampilkan + label_change_status: Status perubahan + label_history: Riwayat + label_attachment: Berkas + label_attachment_new: Berkas baru + label_attachment_delete: Hapus Berkas + label_attachment_plural: Berkas + label_file_added: Berkas ditambahkan + label_report: Laporan + label_report_plural: Laporan + label_news: Berita + label_news_new: Tambahkan berita + label_news_plural: Berita + label_news_latest: Berita terakhir + label_news_view_all: Tampilkan semua berita + label_news_added: Berita ditambahkan + label_settings: Pengaturan + label_overview: Umum + label_version: Versi + label_version_new: Versi baru + label_version_plural: Versi + label_confirmation: Konfirmasi + label_export_to: 'Juga tersedia dalam:' + label_read: Baca... + label_public_projects: Proyek publik + label_open_issues: belum selesai + label_open_issues_plural: belum selesai + label_closed_issues: selesai + label_closed_issues_plural: selesai + label_x_open_issues_abbr_on_total: + zero: 0 belum selesai / %{total} + one: 1 belum selesai / %{total} + other: "%{count} terbuka / %{total}" + label_x_open_issues_abbr: + zero: 0 belum selesai + one: 1 belum selesai + other: "%{count} belum selesai" + label_x_closed_issues_abbr: + zero: 0 selesai + one: 1 selesai + other: "%{count} selesai" + label_total: Total + label_permissions: Perijinan + label_current_status: Status sekarang + label_new_statuses_allowed: Status baru yang diijinkan + label_all: semua + label_none: tidak ada + label_nobody: tidak ada + label_next: Berikut + label_previous: Sebelum + label_used_by: Digunakan oleh + label_details: Rincian + label_add_note: Tambahkan catatan + label_per_page: Per halaman + label_calendar: Kalender + label_months_from: dari bulan + label_gantt: Gantt + label_internal: Internal + label_last_changes: "%{count} perubahan terakhir" + label_change_view_all: Tampilkan semua perubahan + label_personalize_page: Personalkan halaman ini + label_comment: Komentar + label_comment_plural: Komentar + label_x_comments: + zero: tak ada komentar + one: 1 komentar + other: "%{count} komentar" + label_comment_add: Tambahkan komentar + label_comment_added: Komentar ditambahkan + label_comment_delete: Hapus komentar + label_query: Custom query + label_query_plural: Custom queries + label_query_new: Query baru + label_filter_add: Tambahkan filter + label_filter_plural: Filter + label_equals: sama dengan + label_not_equals: tidak sama dengan + label_in_less_than: kurang dari + label_in_more_than: lebih dari + label_greater_or_equal: '>=' + label_less_or_equal: '<=' + label_in: pada + label_today: hari ini + label_all_time: semua waktu + label_yesterday: kemarin + label_this_week: minggu ini + label_last_week: minggu lalu + label_last_n_days: "%{count} hari terakhir" + label_this_month: bulan ini + label_last_month: bulan lalu + label_this_year: this year + label_date_range: Jangkauan tanggal + label_less_than_ago: kurang dari hari yang lalu + label_more_than_ago: lebih dari hari yang lalu + label_ago: hari yang lalu + label_contains: berisi + label_not_contains: tidak berisi + label_day_plural: hari + label_repository: Repositori + label_repository_plural: Repositori + label_browse: Jelajah + label_branch: Cabang + label_tag: Tag + label_revision: Revisi + label_revision_plural: Revisi + label_associated_revisions: Revisi terkait + label_added: ditambahkan + label_modified: diubah + label_copied: disalin + label_renamed: diganti nama + label_deleted: dihapus + label_latest_revision: Revisi terakhir + label_latest_revision_plural: Revisi terakhir + label_view_revisions: Tampilkan revisi + label_view_all_revisions: Tampilkan semua revisi + label_max_size: Ukuran maksimum + label_sort_highest: Ke paling atas + label_sort_higher: Ke atas + label_sort_lower: Ke bawah + label_sort_lowest: Ke paling bawah + label_roadmap: Rencana kerja + label_roadmap_due_in: "Harus selesai dalam %{value}" + label_roadmap_overdue: "%{value} terlambat" + label_roadmap_no_issues: Tak ada masalah pada versi ini + label_search: Cari + label_result_plural: Hasil + label_all_words: Semua kata + label_wiki: Wiki + label_wiki_edit: Sunting wiki + label_wiki_edit_plural: Sunting wiki + label_wiki_page: Halaman wiki + label_wiki_page_plural: Halaman wiki + label_index_by_title: Indeks menurut judul + label_index_by_date: Indeks menurut tanggal + label_current_version: Versi sekarang + label_preview: Tinjauan + label_feed_plural: Feeds + label_changes_details: Rincian semua perubahan + label_issue_tracking: Pelacak masalah + label_spent_time: Waktu terpakai + label_f_hour: "%{value} jam" + label_f_hour_plural: "%{value} jam" + label_time_tracking: Pelacak waktu + label_change_plural: Perubahan + label_statistics: Statistik + label_commits_per_month: Komit per bulan + label_commits_per_author: Komit per pengarang + label_view_diff: Tampilkan perbedaan + label_diff_inline: inline + label_diff_side_by_side: berdampingan + label_options: Pilihan + label_copy_workflow_from: Salin alur kerja dari + label_permissions_report: Laporan perijinan + label_watched_issues: Masalah terpantau + label_related_issues: Masalah terkait + label_applied_status: Status teraplikasi + label_loading: Memuat... + label_relation_new: Kaitan baru + label_relation_delete: Hapus kaitan + label_relates_to: terkait pada + label_duplicates: salinan + label_duplicated_by: disalin oleh + label_blocks: blok + label_blocked_by: diblok oleh + label_precedes: mendahului + label_follows: mengikuti + label_end_to_start: akhir ke awal + label_end_to_end: akhir ke akhir + label_start_to_start: awal ke awal + label_start_to_end: awal ke akhir + label_stay_logged_in: Tetap login + label_disabled: tidak diaktifkan + label_show_completed_versions: Tampilkan versi lengkap + label_me: saya + label_board: Forum + label_board_new: Forum baru + label_board_plural: Forum + label_topic_plural: Topik + label_message_plural: Pesan + label_message_last: Pesan terakhir + label_message_new: Pesan baru + label_message_posted: Pesan ditambahkan + label_reply_plural: Balasan + label_send_information: Kirim informasi akun ke pengguna + label_year: Tahun + label_month: Bulan + label_week: Minggu + label_date_from: Dari + label_date_to: Sampai + label_language_based: Berdasarkan bahasa pengguna + label_sort_by: "Urut berdasarkan %{value}" + label_send_test_email: Kirim email percobaan + label_feeds_access_key_created_on: "RSS access key dibuat %{value} yang lalu" + label_module_plural: Modul + label_added_time_by: "Ditambahkan oleh %{author} %{age} yang lalu" + label_updated_time_by: "Diperbarui oleh %{author} %{age} yang lalu" + label_updated_time: "Diperbarui oleh %{value} yang lalu" + label_jump_to_a_project: Pilih proyek... + label_file_plural: Berkas + label_changeset_plural: Set perubahan + label_default_columns: Kolom default + label_no_change_option: (Tak ada perubahan) + label_bulk_edit_selected_issues: Ubah masalah terpilih secara masal + label_theme: Tema + label_default: Default + label_search_titles_only: Cari judul saja + label_user_mail_option_all: "Untuk semua kejadian pada semua proyek saya" + label_user_mail_option_selected: "Hanya untuk semua kejadian pada proyek yang saya pilih ..." + label_user_mail_no_self_notified: "Saya tak ingin diberitahu untuk perubahan yang saya buat sendiri" + label_user_mail_assigned_only_mail_notification: "Kirim email hanya bila saya ditugaskan untuk masalah terkait" + label_user_mail_block_mail_notification: "Saya tidak ingin menerima email. Terima kasih." + label_registration_activation_by_email: aktivasi akun melalui email + label_registration_manual_activation: aktivasi akun secara manual + label_registration_automatic_activation: aktivasi akun secara otomatis + label_display_per_page: "Per halaman: %{value}" + label_age: Umur + label_change_properties: Rincian perubahan + label_general: Umum + label_more: Lanjut + label_scm: SCM + label_plugins: Plugin + label_ldap_authentication: Otentikasi LDAP + label_downloads_abbr: Unduh + label_optional_description: Deskripsi optional + label_add_another_file: Tambahkan berkas lain + label_preferences: Preferensi + label_chronological_order: Urut sesuai kronologis + label_reverse_chronological_order: Urut dari yang terbaru + label_planning: Perencanaan + label_incoming_emails: Email masuk + label_generate_key: Buat kunci + label_issue_watchers: Pemantau + label_example: Contoh + label_display: Tampilan + label_sort: Urut + label_ascending: Menaik + label_descending: Menurun + label_date_from_to: Dari %{start} sampai %{end} + label_wiki_content_added: Halaman wiki ditambahkan + label_wiki_content_updated: Halaman wiki diperbarui + label_group: Kelompok + label_group_plural: Kelompok + label_group_new: Kelompok baru + label_time_entry_plural: Waktu terpakai + label_version_sharing_none: Tidak dibagi + label_version_sharing_descendants: Dengan subproyek + label_version_sharing_hierarchy: Dengan hirarki proyek + label_version_sharing_tree: Dengan pohon proyek + label_version_sharing_system: Dengan semua proyek + + + button_login: Login + button_submit: Kirim + button_save: Simpan + button_check_all: Contreng semua + button_uncheck_all: Hilangkan semua contreng + button_delete: Hapus + button_create: Buat + button_create_and_continue: Buat dan lanjutkan + button_test: Test + button_edit: Sunting + button_add: Tambahkan + button_change: Ubah + button_apply: Terapkan + button_clear: Bersihkan + button_lock: Kunci + button_unlock: Buka kunci + button_download: Unduh + button_list: Daftar + button_view: Tampilkan + button_move: Pindah + button_move_and_follow: Pindah dan ikuti + button_back: Kembali + button_cancel: Batal + button_activate: Aktifkan + button_sort: Urut + button_log_time: Rekam waktu + button_rollback: Kembali ke versi ini + button_watch: Pantau + button_unwatch: Tidak Memantau + button_reply: Balas + button_archive: Arsip + button_unarchive: Batalkan arsip + button_reset: Reset + button_rename: Ganti nama + button_change_password: Ubah kata sandi + button_copy: Salin + button_copy_and_follow: Salin dan ikuti + button_annotate: Anotasi + button_update: Perbarui + button_configure: Konfigur + button_quote: Kutip + button_duplicate: Duplikat + + status_active: aktif + status_registered: terdaftar + status_locked: terkunci + + version_status_open: terbuka + version_status_locked: terkunci + version_status_closed: tertutup + + field_active: Aktif + + text_select_mail_notifications: Pilih aksi dimana email notifikasi akan dikirimkan. + text_regexp_info: mis. ^[A-Z0-9]+$ + text_min_max_length_info: 0 berarti tidak ada pembatasan + text_project_destroy_confirmation: Apakah anda benar-benar akan menghapus proyek ini beserta data terkait ? + text_subprojects_destroy_warning: "Subproyek: %{value} juga akan dihapus." + text_workflow_edit: Pilih peran dan pelacak untuk menyunting alur kerja + text_are_you_sure: Anda yakin ? + text_journal_changed: "%{label} berubah dari %{old} menjadi %{new}" + text_journal_set_to: "%{label} di set ke %{value}" + text_journal_deleted: "%{label} dihapus (%{old})" + text_journal_added: "%{label} %{value} ditambahkan" + text_tip_issue_begin_day: tugas dimulai hari itu + text_tip_issue_end_day: tugas berakhir hari itu + text_tip_issue_begin_end_day: tugas dimulai dan berakhir hari itu + text_caracters_maximum: "maximum %{count} karakter." + text_caracters_minimum: "Setidaknya harus sepanjang %{count} karakter." + text_length_between: "Panjang diantara %{min} dan %{max} karakter." + text_tracker_no_workflow: Tidak ada alur kerja untuk pelacak ini + text_unallowed_characters: Karakter tidak diperbolehkan + text_comma_separated: Beberapa nilai diperbolehkan (dipisahkan koma). + text_issues_ref_in_commit_messages: Mereferensikan dan membetulkan masalah pada pesan komit + text_issue_added: "Masalah %{id} sudah dilaporkan oleh %{author}." + text_issue_updated: "Masalah %{id} sudah diperbarui oleh %{author}." + text_wiki_destroy_confirmation: Apakah anda benar-benar akan menghapus wiki ini beserta semua isinya ? + text_issue_category_destroy_question: "Beberapa masalah (%{count}) ditugaskan pada kategori ini. Apa yang anda lakukan ?" + text_issue_category_destroy_assignments: Hapus kategori penugasan + text_issue_category_reassign_to: Tugaskan kembali masalah untuk kategori ini + text_user_mail_option: "Untuk proyek yang tidak dipilih, anda hanya akan menerima notifikasi hal-hal yang anda pantau atau anda terlibat di dalamnya (misalnya masalah yang anda tulis atau ditugaskan pada anda)." + text_no_configuration_data: "Peran, pelacak, status masalah dan alur kerja belum dikonfigur.\nSangat disarankan untuk memuat konfigurasi default. Anda akan bisa mengubahnya setelah konfigurasi dimuat." + text_load_default_configuration: Muat konfigurasi default + text_status_changed_by_changeset: "Diterapkan di set perubahan %{value}." + text_issues_destroy_confirmation: 'Apakah anda yakin untuk menghapus masalah terpilih ?' + text_select_project_modules: 'Pilih modul untuk diaktifkan pada proyek ini:' + text_default_administrator_account_changed: Akun administrator default sudah berubah + text_file_repository_writable: Direktori yang bisa ditulisi untuk lampiran + text_plugin_assets_writable: Direktori yang bisa ditulisi untuk plugin asset + text_rmagick_available: RMagick tersedia (optional) + text_destroy_time_entries_question: "%{hours} jam sudah dilaporkan pada masalah yang akan anda hapus. Apa yang akan anda lakukan ?" + text_destroy_time_entries: Hapus jam yang terlapor + text_assign_time_entries_to_project: Tugaskan jam terlapor pada proyek + text_reassign_time_entries: 'Tugaskan kembali jam terlapor pada masalah ini:' + text_user_wrote: "%{value} menulis:" + text_enumeration_destroy_question: "%{count} obyek ditugaskan untuk nilai ini." + text_enumeration_category_reassign_to: 'Tugaskan kembali untuk nilai ini:' + text_email_delivery_not_configured: "Pengiriman email belum dikonfigurasi, notifikasi tidak diaktifkan.\nAnda harus mengkonfigur SMTP server anda pada config/configuration.yml dan restart kembali aplikasi untuk mengaktifkan." + text_repository_usernames_mapping: "Pilih atau perbarui pengguna Redmine yang terpetakan ke setiap nama pengguna yang ditemukan di log repositori.\nPengguna dengan nama pengguna dan repositori atau email yang sama secara otomasit akan dipetakan." + text_diff_truncated: '... Perbedaan terpotong karena melebihi batas maksimum yang bisa ditampilkan.' + text_custom_field_possible_values_info: 'Satu baris untuk setiap nilai' + text_wiki_page_destroy_question: "Halaman ini mempunyai %{descendants} halaman anak dan turunannya. Apa yang akan anda lakukan ?" + text_wiki_page_nullify_children: "Biarkan halaman anak sebagai halaman teratas (root)" + text_wiki_page_destroy_children: "Hapus halaman anak dan semua turunannya" + text_wiki_page_reassign_children: "Tujukan halaman anak ke halaman induk yang ini" + + default_role_manager: Manager + default_role_developer: Pengembang + default_role_reporter: Pelapor + default_tracker_bug: Bug + default_tracker_feature: Fitur + default_tracker_support: Dukungan + default_issue_status_new: Baru + default_issue_status_in_progress: Dalam proses + default_issue_status_resolved: Resolved + default_issue_status_feedback: Umpan balik + default_issue_status_closed: Ditutup + default_issue_status_rejected: Ditolak + default_doc_category_user: Dokumentasi pengguna + default_doc_category_tech: Dokumentasi teknis + default_priority_low: Rendah + default_priority_normal: Normal + default_priority_high: Tinggi + default_priority_urgent: Penting + default_priority_immediate: Segera + default_activity_design: Rancangan + default_activity_development: Pengembangan + + enumeration_issue_priorities: Prioritas masalah + enumeration_doc_categories: Kategori dokumen + enumeration_activities: Kegiatan + enumeration_system_activity: Kegiatan Sistem + label_copy_source: Source + label_update_issue_done_ratios: Update issue done ratios + setting_issue_done_ratio: Calculate the issue done ratio with + label_api_access_key: API access key + text_line_separated: Multiple values allowed (one line for each value). + label_revision_id: Revision %{value} + permission_view_issues: View Issues + setting_issue_done_ratio_issue_status: Use the issue status + error_issue_done_ratios_not_updated: Issue done ratios not updated. + label_display_used_statuses_only: Only display statuses that are used by this tracker + error_workflow_copy_target: Please select target tracker(s) and role(s) + label_api_access_key_created_on: API access key created %{value} ago + label_feeds_access_key: RSS access key + notice_api_access_key_reseted: Your API access key was reset. + setting_rest_api_enabled: Enable REST web service + label_copy_same_as_target: Same as target + button_show: Show + setting_issue_done_ratio_issue_field: Use the issue field + label_missing_api_access_key: Missing an API access key + label_copy_target: Target + label_missing_feeds_access_key: Missing a RSS access key + notice_issue_done_ratios_updated: Issue done ratios updated. + error_workflow_copy_source: Please select a source tracker or role + setting_start_of_week: Start calendars on + setting_mail_handler_body_delimiters: Truncate emails after one of these lines + permission_add_subprojects: Create subprojects + label_subproject_new: New subproject + text_own_membership_delete_confirmation: |- + You are about to remove some or all of your permissions and may no longer be able to edit this project after that. + Are you sure you want to continue? + label_close_versions: Close completed versions + label_board_sticky: Sticky + label_board_locked: Locked + permission_export_wiki_pages: Export wiki pages + setting_cache_formatted_text: Cache formatted text + permission_manage_project_activities: Manage project activities + error_unable_delete_issue_status: Unable to delete issue status + label_profile: Profile + permission_manage_subtasks: Manage subtasks + field_parent_issue: Parent task + label_subtask_plural: Subtasks + label_project_copy_notifications: Send email notifications during the project copy + error_can_not_delete_custom_field: Unable to delete custom field + error_unable_to_connect: Unable to connect (%{value}) + error_can_not_remove_role: This role is in use and can not be deleted. + error_can_not_delete_tracker: This tracker contains issues and can't be deleted. + field_principal: Principal + label_my_page_block: My page block + notice_failed_to_save_members: "Failed to save member(s): %{errors}." + text_zoom_out: Zoom out + text_zoom_in: Zoom in + notice_unable_delete_time_entry: Unable to delete time log entry. + label_overall_spent_time: Overall spent time + field_time_entries: Log time + project_module_gantt: Gantt + project_module_calendar: Calendar + button_edit_associated_wikipage: "Edit associated Wiki page: %{page_title}" + field_text: Text field + label_user_mail_option_only_owner: Only for things I am the owner of + setting_default_notification_option: Default notification option + label_user_mail_option_only_my_events: Only for things I watch or I'm involved in + label_user_mail_option_only_assigned: Only for things I am assigned to + label_user_mail_option_none: No events + field_member_of_group: Assignee's group + field_assigned_to_role: Assignee's role + notice_not_authorized_archived_project: The project you're trying to access has been archived. + label_principal_search: "Search for user or group:" + label_user_search: "Search for user:" + field_visible: Visible + setting_commit_logtime_activity_id: Activity for logged time + text_time_logged_by_changeset: Applied in changeset %{value}. + setting_commit_logtime_enabled: Enable time logging + notice_gantt_chart_truncated: The chart was truncated because it exceeds the maximum number of items that can be displayed (%{max}) + setting_gantt_items_limit: Maximum number of items displayed on the gantt chart + field_warn_on_leaving_unsaved: Warn me when leaving a page with unsaved text + text_warn_on_leaving_unsaved: The current page contains unsaved text that will be lost if you leave this page. + label_my_queries: My custom queries + text_journal_changed_no_detail: "%{label} updated" + label_news_comment_added: Comment added to a news + button_expand_all: Expand all + button_collapse_all: Collapse all + label_additional_workflow_transitions_for_assignee: Additional transitions allowed when the user is the assignee + label_additional_workflow_transitions_for_author: Additional transitions allowed when the user is the author + label_bulk_edit_selected_time_entries: Bulk edit selected time entries + text_time_entries_destroy_confirmation: Are you sure you want to delete the selected time entr(y/ies)? + label_role_anonymous: Anonymous + label_role_non_member: Non member + label_issue_note_added: Note added + label_issue_status_updated: Status updated + label_issue_priority_updated: Priority updated + label_issues_visibility_own: Issues created by or assigned to the user + field_issues_visibility: Issues visibility + label_issues_visibility_all: All issues + permission_set_own_issues_private: Set own issues public or private + field_is_private: Private + permission_set_issues_private: Set issues public or private + label_issues_visibility_public: All non private issues + text_issues_destroy_descendants_confirmation: This will also delete %{count} subtask(s). + field_commit_logs_encoding: Commit messages encoding + field_scm_path_encoding: Path encoding + text_scm_path_encoding_note: "Default: UTF-8" + field_path_to_repository: Path to repository + field_root_directory: Root directory + field_cvs_module: Module + field_cvsroot: CVSROOT + text_mercurial_repository_note: Local repository (e.g. /hgrepo, c:\hgrepo) + text_scm_command: Command + text_scm_command_version: Version + label_git_report_last_commit: Report last commit for files and directories + notice_issue_successful_create: Issue %{id} created. + label_between: between + setting_issue_group_assignment: Allow issue assignment to groups + label_diff: diff + text_git_repository_note: Repository is bare and local (e.g. /gitrepo, c:\gitrepo) + description_query_sort_criteria_direction: Sort direction + description_project_scope: Search scope + description_filter: Filter + description_user_mail_notification: Mail notification settings + description_date_from: Enter start date + description_message_content: Message content + description_available_columns: Available Columns + description_date_range_interval: Choose range by selecting start and end date + description_issue_category_reassign: Choose issue category + description_search: Searchfield + description_notes: Notes + description_date_range_list: Choose range from list + description_choose_project: Projects + description_date_to: Enter end date + description_query_sort_criteria_attribute: Sort attribute + description_wiki_subpages_reassign: Choose new parent page + description_selected_columns: Selected Columns + label_parent_revision: Parent + label_child_revision: Child + error_scm_annotate_big_text_file: The entry cannot be annotated, as it exceeds the maximum text file size. + setting_default_issue_start_date_to_creation_date: Use current date as start date for new issues + button_edit_section: Edit this section + setting_repositories_encodings: Attachments and repositories encodings + description_all_columns: All Columns + button_export: Export + label_export_options: "%{export_format} export options" + error_attachment_too_big: This file cannot be uploaded because it exceeds the maximum allowed file size (%{max_size}) + notice_failed_to_save_time_entries: "Failed to save %{count} time entrie(s) on %{total} selected: %{ids}." + label_x_issues: + zero: 0 masalah + one: 1 masalah + other: "%{count} masalah" + label_repository_new: New repository + field_repository_is_default: Main repository + label_copy_attachments: Copy attachments + label_item_position: "%{position}/%{count}" + label_completed_versions: Completed versions + text_project_identifier_info: Only lower case letters (a-z), numbers, dashes and underscores are allowed.
    Once saved, the identifier cannot be changed. + field_multiple: Multiple values + setting_commit_cross_project_ref: Allow issues of all the other projects to be referenced and fixed + text_issue_conflict_resolution_add_notes: Add my notes and discard my other changes + text_issue_conflict_resolution_overwrite: Apply my changes anyway (previous notes will be kept but some changes may be overwritten) + notice_issue_update_conflict: The issue has been updated by an other user while you were editing it. + text_issue_conflict_resolution_cancel: Discard all my changes and redisplay %{link} + permission_manage_related_issues: Manage related issues + field_auth_source_ldap_filter: LDAP filter + label_search_for_watchers: Search for watchers to add + notice_account_deleted: Your account has been permanently deleted. + setting_unsubscribe: Allow users to delete their own account + button_delete_my_account: Delete my account + text_account_destroy_confirmation: |- + Are you sure you want to proceed? + Your account will be permanently deleted, with no way to reactivate it. + error_session_expired: Your session has expired. Please login again. + text_session_expiration_settings: "Warning: changing these settings may expire the current sessions including yours." + setting_session_lifetime: Session maximum lifetime + setting_session_timeout: Session inactivity timeout + label_session_expiration: Session expiration + permission_close_project: Close / reopen the project + label_show_closed_projects: View closed projects + button_close: Close + button_reopen: Reopen + project_status_active: active + project_status_closed: closed + project_status_archived: archived + text_project_closed: This project is closed and read-only. + notice_user_successful_create: User %{id} created. + field_core_fields: Standard fields + field_timeout: Timeout (in seconds) + setting_thumbnails_enabled: Display attachment thumbnails + setting_thumbnails_size: Thumbnails size (in pixels) + label_status_transitions: Status transitions + label_fields_permissions: Fields permissions + label_readonly: Read-only + label_required: Required + text_repository_identifier_info: Only lower case letters (a-z), numbers, dashes and underscores are allowed.
    Once saved, the identifier cannot be changed. + field_board_parent: Parent forum + label_attribute_of_project: Project's %{name} + label_attribute_of_author: Author's %{name} + label_attribute_of_assigned_to: Assignee's %{name} + label_attribute_of_fixed_version: Target version's %{name} + label_copy_subtasks: Copy subtasks + label_copied_to: copied to + label_copied_from: copied from + label_any_issues_in_project: any issues in project + label_any_issues_not_in_project: any issues not in project + field_private_notes: Private notes + permission_view_private_notes: View private notes + permission_set_notes_private: Set notes as private + label_no_issues_in_project: no issues in project + label_any: semua + label_last_n_weeks: last %{count} weeks + setting_cross_project_subtasks: Allow cross-project subtasks + label_cross_project_descendants: Dengan subproyek + label_cross_project_tree: Dengan pohon proyek + label_cross_project_hierarchy: Dengan hirarki proyek + label_cross_project_system: Dengan semua proyek + button_hide: Hide + setting_non_working_week_days: Non-working days + label_in_the_next_days: in the next + label_in_the_past_days: in the past + label_attribute_of_user: User's %{name} + text_turning_multiple_off: If you disable multiple values, multiple values will be + removed in order to preserve only one value per item. + label_attribute_of_issue: Issue's %{name} + permission_add_documents: Add documents + permission_edit_documents: Edit documents + permission_delete_documents: Delete documents + label_gantt_progress_line: Progress line + setting_jsonp_enabled: Enable JSONP support + field_inherit_members: Inherit members + field_closed_on: Closed + setting_default_projects_tracker_ids: Default trackers for new projects + label_total_time: Total + text_scm_config: You can configure your SCM commands in config/configuration.yml. Please restart the application after editing it. + text_scm_command_not_available: SCM command is not available. Please check settings on the administration panel. + setting_emails_header: Email header diff --git a/config/locales/it.yml b/config/locales/it.yml new file mode 100644 index 00000000..5ea2631a --- /dev/null +++ b/config/locales/it.yml @@ -0,0 +1,1090 @@ +# Italian translations for Ruby on Rails +# by Claudio Poli (masterkain@gmail.com) +# by Diego Pierotto (ita.translations@tiscali.it) +# by Emidio Stani (emidiostani@gmail.com) + +it: + direction: ltr + date: + formats: + default: "%d-%m-%Y" + short: "%d %b" + long: "%d %B %Y" + only_day: "%e" + + day_names: [Domenica, Lunedì, Martedì, Mercoledì, Giovedì, Venerdì, Sabato] + abbr_day_names: [Dom, Lun, Mar, Mer, Gio, Ven, Sab] + month_names: [~, Gennaio, Febbraio, Marzo, Aprile, Maggio, Giugno, Luglio, Agosto, Settembre, Ottobre, Novembre, Dicembre] + abbr_month_names: [~, Gen, Feb, Mar, Apr, Mag, Giu, Lug, Ago, Set, Ott, Nov, Dic] + order: + - :day + - :month + - :year + + time: + formats: + default: "%a %d %b %Y, %H:%M:%S %z" + time: "%H:%M" + short: "%d %b %H:%M" + long: "%d %B %Y %H:%M" + only_second: "%S" + + datetime: + formats: + default: "%d-%m-%YT%H:%M:%S%Z" + + am: 'am' + pm: 'pm' + + datetime: + distance_in_words: + half_a_minute: "mezzo minuto" + less_than_x_seconds: + one: "meno di un secondo" + other: "meno di %{count} secondi" + x_seconds: + one: "1 secondo" + other: "%{count} secondi" + less_than_x_minutes: + one: "meno di un minuto" + other: "meno di %{count} minuti" + x_minutes: + one: "1 minuto" + other: "%{count} minuti" + about_x_hours: + one: "circa un'ora" + other: "circa %{count} ore" + x_hours: + one: "1 hour" + other: "%{count} hours" + x_days: + one: "1 giorno" + other: "%{count} giorni" + about_x_months: + one: "circa un mese" + other: "circa %{count} mesi" + x_months: + one: "1 mese" + other: "%{count} mesi" + about_x_years: + one: "circa un anno" + other: "circa %{count} anni" + over_x_years: + one: "oltre un anno" + other: "oltre %{count} anni" + almost_x_years: + one: "quasi 1 anno" + other: "quasi %{count} anni" + + number: + format: + precision: 3 + separator: ',' + delimiter: '.' + currency: + format: + unit: '€' + precision: 2 + format: '%n %u' + human: + storage_units: + format: "%n %u" + units: + byte: + one: "Byte" + other: "Bytes" + kb: "KB" + mb: "MB" + gb: "GB" + tb: "TB" + + support: + array: + sentence_connector: "e" + skip_last_comma: false + + activerecord: + errors: + template: + header: + one: "Non posso salvare questo %{model}: 1 errore" + other: "Non posso salvare questo %{model}: %{count} errori." + body: "Per favore ricontrolla i seguenti campi:" + messages: + inclusion: "non è incluso nella lista" + exclusion: "è riservato" + invalid: "non è valido" + confirmation: "non coincide con la conferma" + accepted: "deve essere accettata" + empty: "non può essere vuoto" + blank: "non può essere lasciato in bianco" + too_long: "è troppo lungo (il massimo è %{count} lettere)" + too_short: "è troppo corto (il minimo è %{count} lettere)" + wrong_length: "è della lunghezza sbagliata (deve essere di %{count} lettere)" + taken: "è già in uso" + not_a_number: "non è un numero" + greater_than: "deve essere superiore a %{count}" + greater_than_or_equal_to: "deve essere superiore o uguale a %{count}" + equal_to: "deve essere uguale a %{count}" + less_than: "deve essere meno di %{count}" + less_than_or_equal_to: "deve essere meno o uguale a %{count}" + odd: "deve essere dispari" + even: "deve essere pari" + greater_than_start_date: "deve essere maggiore della data di partenza" + not_same_project: "non appartiene allo stesso progetto" + circular_dependency: "Questa relazione creerebbe una dipendenza circolare" + cant_link_an_issue_with_a_descendant: "Una segnalazione non può essere collegata a una delle sue discendenti" + + actionview_instancetag_blank_option: Scegli + + general_text_No: 'No' + general_text_Yes: 'Sì' + general_text_no: 'no' + general_text_yes: 'sì' + general_lang_name: 'Italiano' + general_csv_separator: ';' + general_csv_decimal_separator: ',' + general_csv_encoding: ISO-8859-1 + general_pdf_encoding: UTF-8 + general_first_day_of_week: '1' + + notice_account_updated: L'utente è stato aggiornato. + notice_account_invalid_creditentials: Nome utente o password non validi. + notice_account_password_updated: La password è stata aggiornata. + notice_account_wrong_password: Password errata + notice_account_register_done: L'utente è stato creato. + notice_account_unknown_email: Utente sconosciuto. + notice_can_t_change_password: Questo utente utilizza un metodo di autenticazione esterno. Impossibile cambiare la password. + notice_account_lost_email_sent: Ti è stata spedita una email con le istruzioni per cambiare la password. + notice_account_activated: Il tuo account è stato attivato. Ora puoi effettuare l'accesso. + notice_successful_create: Creazione effettuata. + notice_successful_update: Modifica effettuata. + notice_successful_delete: Eliminazione effettuata. + notice_successful_connection: Connessione effettuata. + notice_file_not_found: La pagina desiderata non esiste o è stata rimossa. + notice_locking_conflict: Le informazioni sono state modificate da un altro utente. + notice_not_authorized: Non sei autorizzato ad accedere a questa pagina. + notice_email_sent: "Una email è stata spedita a %{value}" + notice_email_error: "Si è verificato un errore durante l'invio di una email (%{value})" + notice_feeds_access_key_reseted: La tua chiave di accesso RSS è stata reimpostata. + + error_scm_not_found: "La risorsa e/o la versione non esistono nel repository." + error_scm_command_failed: "Si è verificato un errore durante l'accesso al repository: %{value}" + + mail_subject_lost_password: "Password %{value}" + mail_body_lost_password: 'Per cambiare la password, usa il seguente collegamento:' + mail_subject_register: "Attivazione utente %{value}" + mail_body_register: "Per attivare l'utente, usa il seguente collegamento:" + + + field_name: Nome + field_description: Descrizione + field_summary: Sommario + field_is_required: Richiesto + field_firstname: Nome + field_lastname: Cognome + field_mail: Email + field_filename: File + field_filesize: Dimensione + field_downloads: Download + field_author: Autore + field_created_on: Creato + field_updated_on: Aggiornato + field_field_format: Formato + field_is_for_all: Per tutti i progetti + field_possible_values: Valori possibili + field_regexp: Espressione regolare + field_min_length: Lunghezza minima + field_max_length: Lunghezza massima + field_value: Valore + field_category: Categoria + field_title: Titolo + field_project: Progetto + field_issue: Segnalazione + field_status: Stato + field_notes: Note + field_is_closed: Chiudi la segnalazione + field_is_default: Stato predefinito + field_tracker: Tracker + field_subject: Oggetto + field_due_date: Scadenza + field_assigned_to: Assegnato a + field_priority: Priorità + field_fixed_version: Versione prevista + field_user: Utente + field_role: Ruolo + field_homepage: Homepage + field_is_public: Pubblico + field_parent: Sottoprogetto di + field_is_in_roadmap: Segnalazioni mostrate nella roadmap + field_login: Utente + field_mail_notification: Notifiche via email + field_admin: Amministratore + field_last_login_on: Ultima connessione + field_language: Lingua + field_effective_date: Data + field_password: Password + field_new_password: Nuova password + field_password_confirmation: Conferma + field_version: Versione + field_type: Tipo + field_host: Host + field_port: Porta + field_account: Utente + field_base_dn: DN base + field_attr_login: Attributo connessione + field_attr_firstname: Attributo nome + field_attr_lastname: Attributo cognome + field_attr_mail: Attributo email + field_onthefly: Creazione utente "al volo" + field_start_date: Inizio + field_done_ratio: "% completato" + field_auth_source: Modalità di autenticazione + field_hide_mail: Nascondi il mio indirizzo email + field_comments: Commento + field_url: URL + field_start_page: Pagina principale + field_subproject: Sottoprogetto + field_hours: Ore + field_activity: Attività + field_spent_on: Data + field_identifier: Identificativo + field_is_filter: Usato come filtro + field_issue_to: Segnalazioni correlate + field_delay: Ritardo + field_assignable: E' possibile assegnare segnalazioni a questo ruolo + field_redirect_existing_links: Redirige i collegamenti esistenti + field_estimated_hours: Tempo stimato + field_default_value: Stato predefinito + + setting_app_title: Titolo applicazione + setting_app_subtitle: Sottotitolo applicazione + setting_welcome_text: Testo di benvenuto + setting_default_language: Lingua predefinita + setting_login_required: Autenticazione richiesta + setting_self_registration: Auto-registrazione abilitata + setting_attachment_max_size: Dimensione massima allegati + setting_issues_export_limit: Limite esportazione segnalazioni + setting_mail_from: Indirizzo sorgente email + setting_host_name: Nome host + setting_text_formatting: Formattazione testo + setting_wiki_compression: Comprimi cronologia wiki + setting_feeds_limit: Limite contenuti del feed + setting_autofetch_changesets: Acquisisci automaticamente le commit + setting_sys_api_enabled: Abilita WS per la gestione del repository + setting_commit_ref_keywords: Parole chiave riferimento + setting_commit_fix_keywords: Parole chiave chiusura + setting_autologin: Connessione automatica + setting_date_format: Formato data + setting_cross_project_issue_relations: Consenti la creazione di relazioni tra segnalazioni in progetti differenti + + label_user: Utente + label_user_plural: Utenti + label_user_new: Nuovo utente + label_project: Progetto + label_project_new: Nuovo progetto + label_project_plural: Progetti + label_x_projects: + zero: nessun progetto + one: 1 progetto + other: "%{count} progetti" + label_project_all: Tutti i progetti + label_project_latest: Ultimi progetti registrati + label_issue: Segnalazione + label_issue_new: Nuova segnalazione + label_issue_plural: Segnalazioni + label_issue_view_all: Mostra tutte le segnalazioni + label_document: Documento + label_document_new: Nuovo documento + label_document_plural: Documenti + label_role: Ruolo + label_role_plural: Ruoli + label_role_new: Nuovo ruolo + label_role_and_permissions: Ruoli e permessi + label_member: Membro + label_member_new: Nuovo membro + label_member_plural: Membri + label_tracker: Tracker + label_tracker_plural: Tracker + label_tracker_new: Nuovo tracker + label_workflow: Workflow + label_issue_status: Stato segnalazione + label_issue_status_plural: Stati segnalazioni + label_issue_status_new: Nuovo stato + label_issue_category: Categoria segnalazione + label_issue_category_plural: Categorie segnalazioni + label_issue_category_new: Nuova categoria + label_custom_field: Campo personalizzato + label_custom_field_plural: Campi personalizzati + label_custom_field_new: Nuovo campo personalizzato + label_enumerations: Enumerazioni + label_enumeration_new: Nuovo valore + label_information: Informazione + label_information_plural: Informazioni + label_please_login: Entra + label_register: Registrati + label_password_lost: Password dimenticata + label_home: Home + label_my_page: Pagina personale + label_my_account: Il mio utente + label_my_projects: I miei progetti + label_administration: Amministrazione + label_login: Entra + label_logout: Esci + label_help: Aiuto + label_reported_issues: Segnalazioni + label_assigned_to_me_issues: Le mie segnalazioni + label_last_login: Ultimo collegamento + label_registered_on: Registrato il + label_activity: Attività + label_new: Nuovo + label_logged_as: Collegato come + label_environment: Ambiente + label_authentication: Autenticazione + label_auth_source: Modalità di autenticazione + label_auth_source_new: Nuova modalità di autenticazione + label_auth_source_plural: Modalità di autenticazione + label_subproject_plural: Sottoprogetti + label_min_max_length: Lunghezza minima - massima + label_list: Elenco + label_date: Data + label_integer: Intero + label_boolean: Booleano + label_string: Testo + label_text: Testo esteso + label_attribute: Attributo + label_attribute_plural: Attributi + label_no_data: Nessun dato disponibile + label_change_status: Cambia stato + label_history: Cronologia + label_attachment: File + label_attachment_new: Nuovo file + label_attachment_delete: Elimina file + label_attachment_plural: File + label_report: Report + label_report_plural: Report + label_news: Notizia + label_news_new: Aggiungi notizia + label_news_plural: Notizie + label_news_latest: Utime notizie + label_news_view_all: Tutte le notizie + label_settings: Impostazioni + label_overview: Panoramica + label_version: Versione + label_version_new: Nuova versione + label_version_plural: Versioni + label_confirmation: Conferma + label_export_to: Esporta su + label_read: Leggi... + label_public_projects: Progetti pubblici + label_open_issues: aperta + label_open_issues_plural: aperte + label_closed_issues: chiusa + label_closed_issues_plural: chiuse + label_x_open_issues_abbr_on_total: + zero: 0 aperte / %{total} + one: 1 aperta / %{total} + other: "%{count} aperte / %{total}" + label_x_open_issues_abbr: + zero: 0 aperte + one: 1 aperta + other: "%{count} aperte" + label_x_closed_issues_abbr: + zero: 0 chiuse + one: 1 chiusa + other: "%{count} chiuse" + label_total: Totale + label_permissions: Permessi + label_current_status: Stato attuale + label_new_statuses_allowed: Nuovi stati possibili + label_all: tutti + label_none: nessuno + label_next: Successivo + label_previous: Precedente + label_used_by: Usato da + label_details: Dettagli + label_add_note: Aggiungi una nota + label_per_page: Per pagina + label_calendar: Calendario + label_months_from: mesi da + label_gantt: Gantt + label_internal: Interno + label_last_changes: "ultime %{count} modifiche" + label_change_view_all: Tutte le modifiche + label_personalize_page: Personalizza la pagina + label_comment: Commento + label_comment_plural: Commenti + label_x_comments: + zero: nessun commento + one: 1 commento + other: "%{count} commenti" + label_comment_add: Aggiungi un commento + label_comment_added: Commento aggiunto + label_comment_delete: Elimina commenti + label_query: Query personalizzata + label_query_plural: Query personalizzate + label_query_new: Nuova query + label_filter_add: Aggiungi filtro + label_filter_plural: Filtri + label_equals: è + label_not_equals: non è + label_in_less_than: è minore di + label_in_more_than: è maggiore di + label_in: in + label_today: oggi + label_this_week: questa settimana + label_less_than_ago: meno di giorni fa + label_more_than_ago: più di giorni fa + label_ago: giorni fa + label_contains: contiene + label_not_contains: non contiene + label_day_plural: giorni + label_repository: Repository + label_browse: Sfoglia + label_revision: Versione + label_revision_plural: Versioni + label_added: aggiunto + label_modified: modificato + label_deleted: eliminato + label_latest_revision: Ultima versione + label_latest_revision_plural: Ultime versioni + label_view_revisions: Mostra versioni + label_max_size: Dimensione massima + label_sort_highest: Sposta in cima + label_sort_higher: Su + label_sort_lower: Giù + label_sort_lowest: Sposta in fondo + label_roadmap: Roadmap + label_roadmap_due_in: "Da ultimare in %{value}" + label_roadmap_overdue: "%{value} di ritardo" + label_roadmap_no_issues: Nessuna segnalazione per questa versione + label_search: Ricerca + label_result_plural: Risultati + label_all_words: Tutte le parole + label_wiki: Wiki + label_wiki_edit: Modifica wiki + label_wiki_edit_plural: Modifiche wiki + label_wiki_page: Pagina Wiki + label_wiki_page_plural: Pagine wiki + label_index_by_title: Ordina per titolo + label_index_by_date: Ordina per data + label_current_version: Versione corrente + label_preview: Anteprima + label_feed_plural: Feed + label_changes_details: Particolari di tutti i cambiamenti + label_issue_tracking: Tracking delle segnalazioni + label_spent_time: Tempo impiegato + label_f_hour: "%{value} ora" + label_f_hour_plural: "%{value} ore" + label_time_tracking: Tracking del tempo + label_change_plural: Modifiche + label_statistics: Statistiche + label_commits_per_month: Commit per mese + label_commits_per_author: Commit per autore + label_view_diff: mostra differenze + label_diff_inline: in linea + label_diff_side_by_side: fianco a fianco + label_options: Opzioni + label_copy_workflow_from: Copia workflow da + label_permissions_report: Report permessi + label_watched_issues: Segnalazioni osservate + label_related_issues: Segnalazioni correlate + label_applied_status: Stato applicato + label_loading: Caricamento... + label_relation_new: Nuova relazione + label_relation_delete: Elimina relazione + label_relates_to: correlato a + label_duplicates: duplicati + label_blocks: blocchi + label_blocked_by: bloccato da + label_precedes: precede + label_follows: segue + label_end_to_start: fine a inizio + label_end_to_end: fine a fine + label_start_to_start: inizio a inizio + label_start_to_end: inizio a fine + label_stay_logged_in: Rimani collegato + label_disabled: disabilitato + label_show_completed_versions: Mostra versioni completate + label_me: me + label_board: Forum + label_board_new: Nuovo forum + label_board_plural: Forum + label_topic_plural: Argomenti + label_message_plural: Messaggi + label_message_last: Ultimo messaggio + label_message_new: Nuovo messaggio + label_reply_plural: Risposte + label_send_information: Invia all'utente le informazioni relative all'account + label_year: Anno + label_month: Mese + label_week: Settimana + label_date_from: Da + label_date_to: A + label_language_based: Basato sul linguaggio + label_sort_by: "Ordina per %{value}" + label_send_test_email: Invia una email di prova + label_feeds_access_key_created_on: "chiave di accesso RSS creata %{value} fa" + label_module_plural: Moduli + label_added_time_by: "Aggiunto da %{author} %{age} fa" + label_updated_time: "Aggiornato %{value} fa" + label_jump_to_a_project: Vai al progetto... + + button_login: Entra + button_submit: Invia + button_save: Salva + button_check_all: Seleziona tutti + button_uncheck_all: Deseleziona tutti + button_delete: Elimina + button_create: Crea + button_test: Prova + button_edit: Modifica + button_add: Aggiungi + button_change: Cambia + button_apply: Applica + button_clear: Pulisci + button_lock: Blocca + button_unlock: Sblocca + button_download: Scarica + button_list: Elenca + button_view: Mostra + button_move: Sposta + button_back: Indietro + button_cancel: Annulla + button_activate: Attiva + button_sort: Ordina + button_log_time: Registra tempo + button_rollback: Ripristina questa versione + button_watch: Osserva + button_unwatch: Dimentica + button_reply: Rispondi + button_archive: Archivia + button_unarchive: Ripristina + button_reset: Reimposta + button_rename: Rinomina + + status_active: attivo + status_registered: registrato + status_locked: bloccato + + text_select_mail_notifications: Seleziona le azioni per cui deve essere inviata una notifica. + text_regexp_info: es. ^[A-Z0-9]+$ + text_min_max_length_info: 0 significa nessuna restrizione + text_project_destroy_confirmation: Sei sicuro di voler eliminare il progetto e tutti i dati ad esso collegati? + text_workflow_edit: Seleziona un ruolo ed un tracker per modificare il workflow + text_are_you_sure: Sei sicuro ? + text_tip_issue_begin_day: attività che iniziano in questa giornata + text_tip_issue_end_day: attività che terminano in questa giornata + text_tip_issue_begin_end_day: attività che iniziano e terminano in questa giornata + text_caracters_maximum: "massimo %{count} caratteri." + text_length_between: "Lunghezza compresa tra %{min} e %{max} caratteri." + text_tracker_no_workflow: Nessun workflow definito per questo tracker + text_unallowed_characters: Caratteri non permessi + text_comma_separated: Valori multipli permessi (separati da virgole). + text_issues_ref_in_commit_messages: Segnalazioni di riferimento e chiusura nei messaggi di commit + text_issue_added: "%{author} ha aggiunto la segnalazione %{id}." + text_issue_updated: "La segnalazione %{id} è stata aggiornata da %{author}." + text_wiki_destroy_confirmation: Sicuro di voler eliminare questo wiki e tutti i suoi contenuti? + text_issue_category_destroy_question: "Alcune segnalazioni (%{count}) risultano assegnate a questa categoria. Cosa vuoi fare ?" + text_issue_category_destroy_assignments: Rimuovi le assegnazioni a questa categoria + text_issue_category_reassign_to: Riassegna segnalazioni a questa categoria + + default_role_manager: Gestore + default_role_developer: Sviluppatore + default_role_reporter: Segnalatore + default_tracker_bug: Segnalazione + default_tracker_feature: Funzione + default_tracker_support: Supporto + default_issue_status_new: Nuovo + default_issue_status_in_progress: In elaborazione + default_issue_status_resolved: Risolto + default_issue_status_feedback: Commenti + default_issue_status_closed: Chiuso + default_issue_status_rejected: Rifiutato + default_doc_category_user: Documentazione utente + default_doc_category_tech: Documentazione tecnica + default_priority_low: Bassa + default_priority_normal: Normale + default_priority_high: Alta + default_priority_urgent: Urgente + default_priority_immediate: Immediata + default_activity_design: Progettazione + default_activity_development: Sviluppo + + enumeration_issue_priorities: Priorità segnalazioni + enumeration_doc_categories: Categorie di documenti + enumeration_activities: Attività (time tracking) + label_file_plural: File + label_changeset_plural: Changeset + field_column_names: Colonne + label_default_columns: Colonne predefinite + setting_issue_list_default_columns: Colonne predefinite mostrate nell'elenco segnalazioni + notice_no_issue_selected: "Nessuna segnalazione selezionata! Seleziona le segnalazioni che intendi modificare." + label_bulk_edit_selected_issues: Modifica massiva delle segnalazioni selezionate + label_no_change_option: (Nessuna modifica) + notice_failed_to_save_issues: "Impossibile salvare %{count} segnalazioni su %{total} selezionate: %{ids}." + label_theme: Tema + label_default: Predefinito + label_search_titles_only: Cerca solo nei titoli + label_nobody: nessuno + button_change_password: Modifica password + text_user_mail_option: "Per i progetti non selezionati, riceverai solo le notifiche riguardanti le cose che osservi o nelle quali sei coinvolto (per esempio segnalazioni che hai creato o che ti sono state assegnate)." + label_user_mail_option_selected: "Solo per gli eventi relativi ai progetti selezionati..." + label_user_mail_option_all: "Per ogni evento relativo ad uno dei miei progetti" + setting_emails_footer: Piè di pagina email + label_float: Decimale + button_copy: Copia + mail_body_account_information_external: "Puoi utilizzare il tuo account %{value} per accedere al sistema." + mail_body_account_information: Le informazioni riguardanti il tuo account + setting_protocol: Protocollo + label_user_mail_no_self_notified: "Non voglio notifiche riguardanti modifiche da me apportate" + setting_time_format: Formato ora + label_registration_activation_by_email: attivazione account via email + mail_subject_account_activation_request: "%{value} richiesta attivazione account" + mail_body_account_activation_request: "Un nuovo utente (%{value}) ha effettuato la registrazione. Il suo account è in attesa di abilitazione da parte tua:" + label_registration_automatic_activation: attivazione account automatica + label_registration_manual_activation: attivazione account manuale + notice_account_pending: "Il tuo account è stato creato ed è in attesa di attivazione da parte dell'amministratore." + field_time_zone: Fuso orario + text_caracters_minimum: "Deve essere lungo almeno %{count} caratteri." + setting_bcc_recipients: Destinatari in copia nascosta (bcc) + button_annotate: Annota + label_issues_by: "Segnalazioni di %{value}" + field_searchable: Ricercabile + label_display_per_page: "Per pagina: %{value}" + setting_per_page_options: Opzioni oggetti per pagina + label_age: Età + notice_default_data_loaded: Configurazione predefinita caricata con successo. + text_load_default_configuration: Carica la configurazione predefinita + text_no_configuration_data: "Ruoli, tracker, stati delle segnalazioni e workflow non sono stati ancora configurati.\nE' vivamente consigliato caricare la configurazione predefinita. Potrai modificarla una volta caricata." + error_can_t_load_default_data: "Non è stato possibile caricare la configurazione predefinita : %{value}" + button_update: Aggiorna + label_change_properties: Modifica le proprietà + label_general: Generale + label_repository_plural: Repository + label_associated_revisions: Revisioni associate + setting_user_format: Formato visualizzazione utenti + text_status_changed_by_changeset: "Applicata nel changeset %{value}." + label_more: Altro + text_issues_destroy_confirmation: 'Sei sicuro di voler eliminare le segnalazioni selezionate?' + label_scm: SCM + text_select_project_modules: 'Seleziona i moduli abilitati per questo progetto:' + label_issue_added: Segnalazioni aggiunte + label_issue_updated: Segnalazioni aggiornate + label_document_added: Documenti aggiunti + label_message_posted: Messaggi aggiunti + label_file_added: File aggiunti + label_news_added: Notizie aggiunte + project_module_boards: Forum + project_module_issue_tracking: Tracking delle segnalazioni + project_module_wiki: Wiki + project_module_files: File + project_module_documents: Documenti + project_module_repository: Repository + project_module_news: Notizie + project_module_time_tracking: Time tracking + text_file_repository_writable: Repository dei file scrivibile + text_default_administrator_account_changed: L'account amministrativo predefinito è stato modificato + text_rmagick_available: RMagick disponibile (opzionale) + button_configure: Configura + label_plugins: Plugin + label_ldap_authentication: Autenticazione LDAP + label_downloads_abbr: D/L + label_this_month: questo mese + label_last_n_days: "ultimi %{count} giorni" + label_all_time: sempre + label_this_year: quest'anno + label_date_range: Intervallo di date + label_last_week: ultima settimana + label_yesterday: ieri + label_last_month: ultimo mese + label_add_another_file: Aggiungi un altro file + label_optional_description: Descrizione opzionale + text_destroy_time_entries_question: "%{hours} ore risultano spese sulle segnalazioni che stai per eliminare. Cosa vuoi fare ?" + error_issue_not_found_in_project: 'La segnalazione non è stata trovata o non appartiene al progetto' + text_assign_time_entries_to_project: Assegna le ore segnalate al progetto + text_destroy_time_entries: Elimina le ore segnalate + text_reassign_time_entries: 'Riassegna le ore a questa segnalazione:' + setting_activity_days_default: Giorni mostrati sulle attività di progetto + label_chronological_order: In ordine cronologico + field_comments_sorting: Mostra commenti + label_reverse_chronological_order: In ordine cronologico inverso + label_preferences: Preferenze + setting_display_subprojects_issues: Mostra le segnalazioni dei sottoprogetti nel progetto principale in modo predefinito + label_overall_activity: Attività generale + setting_default_projects_public: I nuovi progetti sono pubblici in modo predefinito + error_scm_annotate: "L'oggetto non esiste o non può essere annotato." + label_planning: Pianificazione + text_subprojects_destroy_warning: "Anche i suoi sottoprogetti: %{value} verranno eliminati." + label_and_its_subprojects: "%{value} ed i suoi sottoprogetti" + mail_body_reminder: "%{count} segnalazioni che ti sono state assegnate scadranno nei prossimi %{days} giorni:" + mail_subject_reminder: "%{count} segnalazioni in scadenza nei prossimi %{days} giorni" + text_user_wrote: "%{value} ha scritto:" + label_duplicated_by: duplicato da + setting_enabled_scm: SCM abilitato + text_enumeration_category_reassign_to: 'Riassegnale a questo valore:' + text_enumeration_destroy_question: "%{count} oggetti hanno un assegnamento su questo valore." + label_incoming_emails: Email in arrivo + label_generate_key: Genera una chiave + setting_mail_handler_api_enabled: Abilita WS per le email in arrivo + setting_mail_handler_api_key: Chiave API + text_email_delivery_not_configured: "La consegna via email non è configurata e le notifiche sono disabilitate.\nConfigura il tuo server SMTP in config/configuration.yml e riavvia l'applicazione per abilitarle." + field_parent_title: Pagina principale + label_issue_watchers: Osservatori + button_quote: Quota + setting_sequential_project_identifiers: Genera progetti con identificativi in sequenza + notice_unable_delete_version: Impossibile eliminare la versione + label_renamed: rinominato + label_copied: copiato + setting_plain_text_mail: Solo testo (non HTML) + permission_view_files: Vedi files + permission_edit_issues: Modifica segnalazioni + permission_edit_own_time_entries: Modifica propri time logs + permission_manage_public_queries: Gestisci query pubbliche + permission_add_issues: Aggiungi segnalazioni + permission_log_time: Segna tempo impiegato + permission_view_changesets: Vedi changesets + permission_view_time_entries: Vedi tempi impiegati + permission_manage_versions: Gestisci versioni + permission_manage_wiki: Gestisci wiki + permission_manage_categories: Gestisci categorie segnalazioni + permission_protect_wiki_pages: Proteggi pagine wiki + permission_comment_news: Commenta notizie + permission_delete_messages: Elimina messaggi + permission_select_project_modules: Seleziona moduli progetto + permission_edit_wiki_pages: Modifica pagine wiki + permission_add_issue_watchers: Aggiungi osservatori + permission_view_gantt: Vedi diagrammi gantt + permission_move_issues: Muovi segnalazioni + permission_manage_issue_relations: Gestisci relazioni tra segnalazioni + permission_delete_wiki_pages: Elimina pagine wiki + permission_manage_boards: Gestisci forum + permission_delete_wiki_pages_attachments: Elimina allegati + permission_view_wiki_edits: Vedi cronologia wiki + permission_add_messages: Aggiungi messaggi + permission_view_messages: Vedi messaggi + permission_manage_files: Gestisci files + permission_edit_issue_notes: Modifica note + permission_manage_news: Gestisci notizie + permission_view_calendar: Vedi calendario + permission_manage_members: Gestisci membri + permission_edit_messages: Modifica messaggi + permission_delete_issues: Elimina segnalazioni + permission_view_issue_watchers: Vedi lista osservatori + permission_manage_repository: Gestisci repository + permission_commit_access: Permesso di commit + permission_browse_repository: Sfoglia repository + permission_view_documents: Vedi documenti + permission_edit_project: Modifica progetti + permission_add_issue_notes: Aggiungi note + permission_save_queries: Salva query + permission_view_wiki_pages: Vedi pagine wiki + permission_rename_wiki_pages: Rinomina pagine wiki + permission_edit_time_entries: Modifica time logs + permission_edit_own_issue_notes: Modifica proprie note + setting_gravatar_enabled: Usa icone utente Gravatar + label_example: Esempio + text_repository_usernames_mapping: "Seleziona per aggiornare la corrispondenza tra gli utenti Redmine e quelli presenti nel log del repository.\nGli utenti Redmine e repository con lo stesso note utente o email sono mappati automaticamente." + permission_edit_own_messages: Modifica propri messaggi + permission_delete_own_messages: Elimina propri messaggi + label_user_activity: "attività di %{value}" + label_updated_time_by: "Aggiornato da %{author} %{age} fa" + text_diff_truncated: '... Le differenze sono state troncate perchè superano il limite massimo visualizzabile.' + setting_diff_max_lines_displayed: Limite massimo di differenze (linee) mostrate + text_plugin_assets_writable: Directory attività dei plugins scrivibile + warning_attachments_not_saved: "%{count} file non possono essere salvati." + button_create_and_continue: Crea e continua + text_custom_field_possible_values_info: 'Un valore per ogni riga' + label_display: Mostra + field_editable: Modificabile + setting_repository_log_display_limit: Numero massimo di revisioni elencate nella cronologia file + setting_file_max_size_displayed: Dimensione massima dei contenuti testuali visualizzati + field_watcher: Osservatore + setting_openid: Accetta connessione e registrazione con OpenID + field_identity_url: URL OpenID + label_login_with_open_id_option: oppure autenticati usando OpenID + field_content: Contenuto + label_descending: Discendente + label_sort: Ordina + label_ascending: Ascendente + label_date_from_to: Da %{start} a %{end} + label_greater_or_equal: ">=" + label_less_or_equal: <= + text_wiki_page_destroy_question: Questa pagina ha %{descendants} pagine figlie. Cosa ne vuoi fare? + text_wiki_page_reassign_children: Riassegna le pagine figlie al padre di questa pagina + text_wiki_page_nullify_children: Mantieni le pagine figlie come pagine radice + text_wiki_page_destroy_children: Elimina le pagine figlie e tutta la discendenza + setting_password_min_length: Lunghezza minima password + field_group_by: Raggruppa risultati per + mail_subject_wiki_content_updated: "La pagina wiki '%{id}' è stata aggiornata" + label_wiki_content_added: Aggiunta pagina al wiki + mail_subject_wiki_content_added: "La pagina '%{id}' è stata aggiunta al wiki" + mail_body_wiki_content_added: La pagina '%{id}' è stata aggiunta al wiki da %{author}. + label_wiki_content_updated: Aggiornata pagina wiki + mail_body_wiki_content_updated: La pagina '%{id}' wiki è stata aggiornata da%{author}. + permission_add_project: Crea progetto + setting_new_project_user_role_id: Ruolo assegnato agli utenti non amministratori che creano un progetto + label_view_all_revisions: Mostra tutte le revisioni + label_tag: Tag + label_branch: Branch + error_no_tracker_in_project: Nessun tracker è associato a questo progetto. Per favore verifica le impostazioni del Progetto. + error_no_default_issue_status: Nessuno stato predefinito delle segnalazioni è configurato. Per favore verifica le impostazioni (Vai in "Amministrazione -> Stati segnalazioni"). + text_journal_changed: "%{label} modificata da %{old} a %{new}" + text_journal_set_to: "%{label} impostata a %{value}" + text_journal_deleted: "%{label} eliminata (%{old})" + label_group_plural: Gruppi + label_group: Gruppo + label_group_new: Nuovo gruppo + label_time_entry_plural: Tempo impiegato + text_journal_added: "%{value} %{label} aggiunto" + field_active: Attivo + enumeration_system_activity: Attività di sistema + permission_delete_issue_watchers: Elimina osservatori + version_status_closed: chiusa + version_status_locked: bloccata + version_status_open: aperta + error_can_not_reopen_issue_on_closed_version: Una segnalazione assegnata ad una versione chiusa non può essere riaperta + label_user_anonymous: Anonimo + button_move_and_follow: Sposta e segui + setting_default_projects_modules: Moduli predefiniti abilitati per i nuovi progetti + setting_gravatar_default: Immagine Gravatar predefinita + field_sharing: Condivisione + label_version_sharing_hierarchy: Con gerarchia progetto + label_version_sharing_system: Con tutti i progetti + label_version_sharing_descendants: Con sottoprogetti + label_version_sharing_tree: Con progetto padre + label_version_sharing_none: Nessuna condivisione + error_can_not_archive_project: Questo progetto non può essere archiviato + button_duplicate: Duplica + button_copy_and_follow: Copia e segui + label_copy_source: Sorgente + setting_issue_done_ratio: Calcola la percentuale di segnalazioni completate con + setting_issue_done_ratio_issue_status: Usa lo stato segnalazioni + error_issue_done_ratios_not_updated: La percentuale delle segnalazioni completate non è aggiornata. + error_workflow_copy_target: Per favore seleziona trackers finali e ruolo(i) + setting_issue_done_ratio_issue_field: Usa il campo segnalazioni + label_copy_same_as_target: Uguale a destinazione + label_copy_target: Destinazione + notice_issue_done_ratios_updated: La percentuale delle segnalazioni completate è aggiornata. + error_workflow_copy_source: Per favore seleziona un tracker sorgente o ruolo + label_update_issue_done_ratios: Aggiorna la percentuale delle segnalazioni completate + setting_start_of_week: Avvia calendari il + permission_view_issues: Mostra segnalazioni + label_display_used_statuses_only: Mostra solo stati che vengono usati per questo tracker + label_revision_id: Revisione %{value} + label_api_access_key: Chiave di accesso API + label_api_access_key_created_on: Chiave di accesso API creata %{value} fa + label_feeds_access_key: Chiave di accesso RSS + notice_api_access_key_reseted: La chiave di accesso API è stata reimpostata. + setting_rest_api_enabled: Abilita il servizio web REST + label_missing_api_access_key: Chiave di accesso API mancante + label_missing_feeds_access_key: Chiave di accesso RSS mancante + button_show: Mostra + text_line_separated: Valori multipli permessi (un valore per ogni riga). + setting_mail_handler_body_delimiters: Tronca email dopo una di queste righe + permission_add_subprojects: Crea sottoprogetti + label_subproject_new: Nuovo sottoprogetto + text_own_membership_delete_confirmation: |- + Stai per eliminare alcuni o tutti i permessi e non sarai più in grado di modificare questo progetto dopo tale azione. + Sei sicuro di voler continuare? + label_close_versions: Versioni completate chiuse + label_board_sticky: Annunci + label_board_locked: Bloccato + permission_export_wiki_pages: Esporta pagine wiki + setting_cache_formatted_text: Cache testo formattato + permission_manage_project_activities: Gestisci attività progetti + error_unable_delete_issue_status: Impossibile eliminare lo stato segnalazioni + label_profile: Profilo + permission_manage_subtasks: Gestisci sottoattività + field_parent_issue: Attività principale + label_subtask_plural: Sottoattività + label_project_copy_notifications: Invia notifiche email durante la copia del progetto + error_can_not_delete_custom_field: Impossibile eliminare il campo personalizzato + error_unable_to_connect: Impossibile connettersi (%{value}) + error_can_not_remove_role: Questo ruolo è in uso e non può essere eliminato. + error_can_not_delete_tracker: Questo tracker contiene segnalazioni e non può essere eliminato. + field_principal: Principale + label_my_page_block: La mia pagina di blocco + notice_failed_to_save_members: "Impossibile salvare il membro(i): %{errors}." + text_zoom_out: Riduci ingrandimento + text_zoom_in: Aumenta ingrandimento + notice_unable_delete_time_entry: Impossibile eliminare il valore time log. + label_overall_spent_time: Totale tempo impiegato + field_time_entries: Tempo di collegamento + project_module_gantt: Gantt + project_module_calendar: Calendario + button_edit_associated_wikipage: "Modifica la pagina wiki associata: %{page_title}" + field_text: Campo di testo + label_user_mail_option_only_owner: Solo se io sono il proprietario + setting_default_notification_option: Opzione di notifica predefinita + label_user_mail_option_only_my_events: Solo se sono un osservatore o sono coinvolto + label_user_mail_option_only_assigned: Solo quando mi assegnano attività + label_user_mail_option_none: Nessun evento + field_member_of_group: Gruppo dell'assegnatario + field_assigned_to_role: Ruolo dell'assegnatario + notice_not_authorized_archived_project: Il progetto a cui stai accedendo è stato archiviato. + label_principal_search: "Cerca utente o gruppo:" + label_user_search: "Cerca utente:" + field_visible: Visibile + setting_emails_header: Intestazione email + setting_commit_logtime_activity_id: Attività per il tempo di collegamento + text_time_logged_by_changeset: Usato nel changeset %{value}. + setting_commit_logtime_enabled: Abilita registrazione del tempo di collegamento + notice_gantt_chart_truncated: Il grafico è stato troncato perchè eccede il numero di oggetti (%{max}) da visualizzare + setting_gantt_items_limit: Massimo numero di oggetti da visualizzare sul diagramma di gantt + field_warn_on_leaving_unsaved: Avvisami quando lascio una pagina con testo non salvato + text_warn_on_leaving_unsaved: La pagina corrente contiene del testo non salvato che verrà perso se lasci questa pagina. + label_my_queries: Le mie queries personalizzate + text_journal_changed_no_detail: "%{label} aggiornato" + label_news_comment_added: Commento aggiunto a una notizia + button_expand_all: Espandi tutto + button_collapse_all: Comprimi tutto + label_additional_workflow_transitions_for_assignee: Transizioni supplementari consentite quando l'utente è l'assegnatario + label_additional_workflow_transitions_for_author: Transizioni supplementari consentite quando l'utente è l'autore + label_bulk_edit_selected_time_entries: Modifica massiva delle ore segnalate selezionate + text_time_entries_destroy_confirmation: Sei sicuro di voler eliminare l'ora\e selezionata\e? + label_role_anonymous: Anonimo + label_role_non_member: Non membro + label_issue_note_added: Nota aggiunta + label_issue_status_updated: Stato aggiornato + label_issue_priority_updated: Priorità aggiornata + label_issues_visibility_own: Segnalazioni create o assegnate all'utente + field_issues_visibility: Visibilità segnalazioni + label_issues_visibility_all: Tutte le segnalazioni + permission_set_own_issues_private: Imposta le proprie segnalazioni pubbliche o private + field_is_private: Privato + permission_set_issues_private: Imposta le segnalazioni pubbliche o private + label_issues_visibility_public: Tutte le segnalazioni non private + text_issues_destroy_descendants_confirmation: Questo eliminerà anche %{count} sottoattività. + field_commit_logs_encoding: Codifica dei messaggi di commit + field_scm_path_encoding: Codifica del percorso + text_scm_path_encoding_note: "Predefinito: UTF-8" + field_path_to_repository: Percorso del repository + field_root_directory: Directory radice + field_cvs_module: Modulo + field_cvsroot: CVSROOT + text_mercurial_repository_note: Repository locale (es. /hgrepo, c:\hgrepo) + text_scm_command: Comando + text_scm_command_version: Versione + label_git_report_last_commit: Riporta l'ultimo commit per files e directories + text_scm_config: Puoi configurare i comandi scm nel file config/configuration.yml. E' necessario riavviare l'applicazione dopo averlo modificato. + text_scm_command_not_available: Il comando scm non è disponibile. Controllare le impostazioni nel pannello di amministrazione. + notice_issue_successful_create: Segnalazione %{id} creata. + label_between: tra + setting_issue_group_assignment: Permetti di assegnare una segnalazione a gruppi + label_diff: diff + text_git_repository_note: Il repository è spoglio e locale (e.g. /gitrepo, c:\gitrepo) + description_query_sort_criteria_direction: Ordinamento + description_project_scope: Search scope + description_filter: Filtro + description_user_mail_notification: Impostazioni notifica via mail + description_date_from: Inserisci la data d'inizio + description_message_content: Contenuto del messaggio + description_available_columns: Colonne disponibili + description_date_range_interval: Scegli l'intervallo selezionando la data di inizio e di fine + description_issue_category_reassign: Scegli la categoria della segnalazione + description_search: Campo di ricerca + description_notes: Note + description_date_range_list: Scegli l'intervallo dalla lista + description_choose_project: Progetti + description_date_to: Inserisci la data di fine + description_query_sort_criteria_attribute: Attributo di ordinamento + description_wiki_subpages_reassign: Scegli la nuova pagina padre + description_selected_columns: Colonne selezionate + label_parent_revision: Padre + label_child_revision: Figlio + error_scm_annotate_big_text_file: La nota non può essere salvata, supera la dimensiona massima del campo di testo. + setting_default_issue_start_date_to_creation_date: Usa la data corrente come data d'inizio per le nuove segnalazioni + button_edit_section: Modifica questa sezione + setting_repositories_encodings: Codifica degli allegati e dei repository + description_all_columns: Tutte le colonne + button_export: Esporta + label_export_options: "%{export_format} opzioni per l'export" + error_attachment_too_big: Questo file non può essere caricato in quanto la sua dimensione supera la massima consentita (%{max_size}) + notice_failed_to_save_time_entries: "Failed to save %{count} time entrie(s) on %{total} selected: %{ids}." + label_x_issues: + zero: 0 segnalazione + one: 1 segnalazione + other: "%{count} segnalazioni" + label_repository_new: New repository + field_repository_is_default: Main repository + label_copy_attachments: Copy attachments + label_item_position: "%{position}/%{count}" + label_completed_versions: Completed versions + text_project_identifier_info: Only lower case letters (a-z), numbers, dashes and underscores are allowed.
    Once saved, the identifier cannot be changed. + field_multiple: Multiple values + setting_commit_cross_project_ref: Allow issues of all the other projects to be referenced and fixed + text_issue_conflict_resolution_add_notes: Add my notes and discard my other changes + text_issue_conflict_resolution_overwrite: Apply my changes anyway (previous notes will be kept but some changes may be overwritten) + notice_issue_update_conflict: The issue has been updated by an other user while you were editing it. + text_issue_conflict_resolution_cancel: Discard all my changes and redisplay %{link} + permission_manage_related_issues: Manage related issues + field_auth_source_ldap_filter: LDAP filter + label_search_for_watchers: Search for watchers to add + notice_account_deleted: Your account has been permanently deleted. + setting_unsubscribe: Allow users to delete their own account + button_delete_my_account: Delete my account + text_account_destroy_confirmation: |- + Are you sure you want to proceed? + Your account will be permanently deleted, with no way to reactivate it. + error_session_expired: Your session has expired. Please login again. + text_session_expiration_settings: "Warning: changing these settings may expire the current sessions including yours." + setting_session_lifetime: Session maximum lifetime + setting_session_timeout: Session inactivity timeout + label_session_expiration: Session expiration + permission_close_project: Close / reopen the project + label_show_closed_projects: View closed projects + button_close: Close + button_reopen: Reopen + project_status_active: active + project_status_closed: closed + project_status_archived: archived + text_project_closed: This project is closed and read-only. + notice_user_successful_create: User %{id} created. + field_core_fields: Standard fields + field_timeout: Timeout (in seconds) + setting_thumbnails_enabled: Display attachment thumbnails + setting_thumbnails_size: Thumbnails size (in pixels) + label_status_transitions: Status transitions + label_fields_permissions: Fields permissions + label_readonly: Read-only + label_required: Required + text_repository_identifier_info: Only lower case letters (a-z), numbers, dashes and underscores are allowed.
    Once saved, the identifier cannot be changed. + field_board_parent: Parent forum + label_attribute_of_project: Project's %{name} + label_attribute_of_author: Author's %{name} + label_attribute_of_assigned_to: Assignee's %{name} + label_attribute_of_fixed_version: Target version's %{name} + label_copy_subtasks: Copy subtasks + label_copied_to: copied to + label_copied_from: copied from + label_any_issues_in_project: any issues in project + label_any_issues_not_in_project: any issues not in project + field_private_notes: Private notes + permission_view_private_notes: View private notes + permission_set_notes_private: Set notes as private + label_no_issues_in_project: no issues in project + label_any: tutti + label_last_n_weeks: last %{count} weeks + setting_cross_project_subtasks: Allow cross-project subtasks + label_cross_project_descendants: Con sottoprogetti + label_cross_project_tree: Con progetto padre + label_cross_project_hierarchy: Con gerarchia progetto + label_cross_project_system: Con tutti i progetti + button_hide: Hide + setting_non_working_week_days: Non-working days + label_in_the_next_days: in the next + label_in_the_past_days: in the past + label_attribute_of_user: User's %{name} + text_turning_multiple_off: If you disable multiple values, multiple values will be + removed in order to preserve only one value per item. + label_attribute_of_issue: Issue's %{name} + permission_add_documents: Add documents + permission_edit_documents: Edit documents + permission_delete_documents: Delete documents + label_gantt_progress_line: Progress line + setting_jsonp_enabled: Enable JSONP support + field_inherit_members: Inherit members + field_closed_on: Closed + setting_default_projects_tracker_ids: Default trackers for new projects + label_total_time: Totale diff --git a/config/locales/ja.yml b/config/locales/ja.yml new file mode 100644 index 00000000..bbf97545 --- /dev/null +++ b/config/locales/ja.yml @@ -0,0 +1,1118 @@ +# Japanese translations for Ruby on Rails +# by Akira Matsuda (ronnie@dio.jp) +# AR error messages are basically taken from Ruby-GetText-Package. Thanks to Masao Mutoh. + +ja: + direction: ltr + date: + formats: + # Use the strftime parameters for formats. + # When no format has been given, it uses default. + # You can provide other formats here if you like! + default: "%Y/%m/%d" + short: "%m/%d" + long: "%Y年%m月%d日(%a)" + + day_names: [日曜日, 月曜日, 火曜日, 水曜日, 木曜日, 金曜日, 土曜日] + abbr_day_names: [日, 月, 火, 水, 木, 金, 土] + + # Don't forget the nil at the beginning; there's no such thing as a 0th month + month_names: [~, 1月, 2月, 3月, 4月, 5月, 6月, 7月, 8月, 9月, 10月, 11月, 12月] + abbr_month_names: [~, 1月, 2月, 3月, 4月, 5月, 6月, 7月, 8月, 9月, 10月, 11月, 12月] + # Used in date_select and datime_select. + order: + - :year + - :month + - :day + + time: + formats: + default: "%Y/%m/%d %H:%M:%S" + time: "%H:%M" + short: "%y/%m/%d %H:%M" + long: "%Y年%m月%d日(%a) %H時%M分%S秒 %Z" + am: "午前" + pm: "午後" + + datetime: + distance_in_words: + half_a_minute: "30秒前後" + less_than_x_seconds: + one: "1秒以内" + other: "%{count}秒以内" + x_seconds: + one: "1秒" + other: "%{count}秒" + less_than_x_minutes: + one: "1分以内" + other: "%{count}分以内" + x_minutes: + one: "1分" + other: "%{count}分" + about_x_hours: + one: "約1時間" + other: "約%{count}時間" + x_hours: + one: "1時間" + other: "%{count}時間" + x_days: + one: "1日" + other: "%{count}日" + about_x_months: + one: "約1ヶ月" + other: "約%{count}ヶ月" + x_months: + one: "1ヶ月" + other: "%{count}ヶ月" + about_x_years: + one: "約1年" + other: "約%{count}年" + over_x_years: + one: "1年以上" + other: "%{count}年以上" + almost_x_years: + one: "ほぼ1年" + other: "ほぼ%{count}年" + + number: + format: + separator: "." + delimiter: "," + precision: 3 + + currency: + format: + format: "%n%u" + unit: "円" + separator: "." + delimiter: "," + precision: 0 + + percentage: + format: + delimiter: "" + + precision: + format: + delimiter: "" + + human: + format: + delimiter: "" + precision: 3 + storage_units: + format: "%n %u" + units: + byte: + one: "Byte" + other: "Bytes" + kb: "KB" + mb: "MB" + gb: "GB" + tb: "TB" + +# Used in array.to_sentence. + support: + array: + sentence_connector: "及び" + skip_last_comma: true + + activerecord: + errors: + template: + header: + one: "%{model} にエラーが発生しました。" + other: "%{model} に %{count} つのエラーが発生しました。" + body: "次の項目を確認してください。" + + messages: + inclusion: "は一覧にありません。" + exclusion: "は予約されています。" + invalid: "は不正な値です。" + confirmation: "が一致しません。" + accepted: "を受諾してください。" + empty: "を入力してください。" + blank: "を入力してください。" + too_long: "は%{count}文字以内で入力してください。" + too_short: "は%{count}文字以上で入力してください。" + wrong_length: "は%{count}文字で入力してください。" + taken: "はすでに存在します。" + not_a_number: "は数値で入力してください。" + not_a_date: "は日付を入力してください。" + greater_than: "は%{count}より大きい値にしてください。" + greater_than_or_equal_to: "は%{count}以上の値にしてください。" + equal_to: "は%{count}にしてください。" + less_than: "は%{count}より小さい値にしてください。" + less_than_or_equal_to: "は%{count}以下の値にしてください。" + odd: "は奇数にしてください。" + even: "は偶数にしてください。" + greater_than_start_date: "を開始日より後にしてください" + not_same_project: "同じプロジェクトに属していません" + circular_dependency: "この関係では、循環依存になります" + cant_link_an_issue_with_a_descendant: "指定したチケットとは親子関係になっているため関連づけられません" + + actionview_instancetag_blank_option: 選んでください + + general_text_No: 'いいえ' + general_text_Yes: 'はい' + general_text_no: 'いいえ' + general_text_yes: 'はい' + general_lang_name: 'Japanese (日本語)' + general_csv_separator: ',' + general_csv_decimal_separator: '.' + general_csv_encoding: CP932 + ## Redmine 1.2.0 現在、この値によって、pdfの出力のフォントを切り替えています。 + ## CRuby では CP932 にしてください。 + ## JRuby 1.6.2 (ruby-1.8.7-p330) では、CP932 ですと + ## Iconv::InvalidEncoding例外が発生します。 + ## JRuby では、SJIS か Shift_JIS にしてください。 + ## ご存知の通り、CP932 と SJIS は別物ですが、 + ## そこまでの検証はしていません。 + # general_pdf_encoding: SJIS + general_pdf_encoding: CP932 + general_first_day_of_week: '7' + + notice_account_updated: アカウントが更新されました。 + notice_account_invalid_creditentials: ユーザー名もしくはパスワードが無効です + notice_account_password_updated: パスワードが更新されました。 + notice_account_wrong_password: パスワードが違います + notice_account_register_done: アカウントが作成されました。有効にするには送信したメールにあるリンクをクリックしてください。 + notice_account_unknown_email: ユーザーが存在しません。 + notice_can_t_change_password: このアカウントでは外部認証を使っています。パスワードは変更できません。 + notice_account_lost_email_sent: 新しいパスワードのメールを送信しました。 + notice_account_activated: アカウントが有効になりました。ログインできます。 + notice_successful_create: 作成しました。 + notice_successful_update: 更新しました。 + notice_successful_delete: 削除しました。 + notice_successful_connection: 接続しました。 + notice_file_not_found: アクセスしようとしたページは存在しないか削除されています。 + notice_locking_conflict: 別のユーザーがデータを更新しています。 + notice_not_authorized: このページにアクセスするには認証が必要です。 + notice_not_authorized_archived_project: プロジェクトはアーカイブされています。 + notice_email_sent: "%{value} 宛にメールを送信しました。" + notice_email_error: "メール送信中にエラーが発生しました (%{value})" + notice_feeds_access_key_reseted: RSSアクセスキーを初期化しました。 + notice_api_access_key_reseted: APIアクセスキーを初期化しました。 + notice_failed_to_save_issues: "全%{total}件中%{count}件のチケットが保存できませんでした: %{ids}." + notice_failed_to_save_members: "メンバーの保存に失敗しました: %{errors}." + notice_no_issue_selected: "チケットが選択されていません! 更新対象のチケットを選択してください。" + notice_account_pending: アカウントは作成済みで、システム管理者の承認待ちです。 + notice_default_data_loaded: デフォルト設定をロードしました。 + notice_unable_delete_version: バージョンを削除できません + notice_unable_delete_time_entry: 作業時間を削除できません + notice_issue_done_ratios_updated: チケットの進捗が更新されました。 + notice_gantt_chart_truncated: ガントチャートは、最大表示項目数(%{max})を超えたたため切り捨てられました。 + + error_can_t_load_default_data: "デフォルト設定がロードできませんでした: %{value}" + error_scm_not_found: リポジトリに、エントリ/リビジョンが存在しません。 + error_scm_command_failed: "リポジトリへアクセスしようとしてエラーになりました: %{value}" + error_scm_annotate: "エントリが存在しない、もしくはアノテートできません。" + error_issue_not_found_in_project: 'チケットが見つかりません、もしくはこのプロジェクトに属していません' + error_unable_delete_issue_status: "チケットのステータスを削除できませんでした。" + error_no_tracker_in_project: 'このプロジェクトにはトラッカーが登録されていません。プロジェクト設定を確認してください。' + error_no_default_issue_status: 'デフォルトのチケットステータスが定義されていません。設定を確認してください(管理→チケットのステータス)。' + error_can_not_delete_custom_field: 'カスタムフィールドを削除できません。' + error_unable_to_connect: "接続できません。 (%{value})" + error_can_not_remove_role: 'このロールは使用されています。削除できません。' + error_can_not_reopen_issue_on_closed_version: '終了したバージョンにひも付けされたチケットの再オープンはできません。' + error_can_not_archive_project: このプロジェクトはアーカイブできません + error_issue_done_ratios_not_updated: "チケットの進捗が更新できません。" + error_workflow_copy_source: 'コピー元となるトラッカーまたはロールを選択してください' + error_workflow_copy_target: 'コピー先となるトラッカーとロールを選択してください' + error_can_not_delete_tracker: 'このトラッカーは使用されています。削除できません。' + + warning_attachments_not_saved: "%{count}個の添付ファイルが保存できませんでした。" + + mail_subject_lost_password: "%{value} パスワード再発行" + mail_body_lost_password: 'パスワードを変更するには、以下のリンクをクリックしてください:' + mail_subject_register: "%{value} アカウント登録の確認" + mail_body_register: 'アカウント登録を完了するには、以下のアドレスをクリックしてください:' + mail_body_account_information_external: "%{value} アカウントを使ってにログインできます。" + mail_body_account_information: アカウント情報 + mail_subject_account_activation_request: "%{value} アカウントの承認要求" + mail_body_account_activation_request: "新しいユーザー %{value} が登録されました。このアカウントはあなたの承認待ちです:" + mail_subject_reminder: "%{count}件のチケットの期日が%{days}日以内に到来します" + mail_body_reminder: "%{count}件の担当チケットの期日が%{days}日以内に到来します:" + mail_subject_wiki_content_added: "Wikiページ %{id} が追加されました" + mail_body_wiki_content_added: "%{author} によってWikiページ %{id} が追加されました。" + mail_subject_wiki_content_updated: "Wikiページ %{id} が更新されました" + mail_body_wiki_content_updated: "%{author} によってWikiページ %{id} が更新されました。" + + + field_name: 名称 + field_description: 説明 + field_summary: サマリー + field_is_required: 必須 + field_firstname: 名前 + field_lastname: 苗字 + field_mail: メールアドレス + field_filename: ファイル + field_filesize: サイズ + field_downloads: ダウンロード + field_author: 作成者 + field_created_on: 作成日 + field_updated_on: 更新日 + field_field_format: 書式 + field_is_for_all: 全プロジェクト向け + field_possible_values: 選択肢 + field_regexp: 正規表現 + field_min_length: 最小値 + field_max_length: 最大値 + field_value: 値 + field_category: カテゴリ + field_title: タイトル + field_project: プロジェクト + field_issue: チケット + field_status: ステータス + field_notes: 注記 + field_is_closed: 終了したチケット + field_is_default: デフォルト値 + field_tracker: トラッカー + field_subject: 題名 + field_due_date: 期日 + field_assigned_to: 担当者 + field_priority: 優先度 + field_fixed_version: 対象バージョン + field_user: ユーザー + field_principal: 主体 + field_role: ロール + field_homepage: ホームページ + field_is_public: 公開 + field_parent: 親プロジェクト名 + field_is_in_roadmap: チケットをロードマップに表示する + field_login: ログイン + field_mail_notification: メール通知 + field_admin: システム管理者 + field_last_login_on: 最終接続日 + field_language: 言語 + field_effective_date: 期日 + field_password: パスワード + field_new_password: 新しいパスワード + field_password_confirmation: パスワードの確認 + field_version: バージョン + field_type: タイプ + field_host: ホスト + field_port: ポート + field_account: アカウント + field_base_dn: 検索範囲 + field_attr_login: ログイン名属性 + field_attr_firstname: 名前属性 + field_attr_lastname: 苗字属性 + field_attr_mail: メール属性 + field_onthefly: あわせてユーザーを作成 + field_start_date: 開始日 + field_done_ratio: 進捗 % + field_auth_source: 認証方式 + field_hide_mail: メールアドレスを隠す + field_comments: コメント + field_url: URL + field_start_page: メインページ + field_subproject: サブプロジェクト + field_hours: 時間 + field_activity: 活動 + field_spent_on: 日付 + field_identifier: 識別子 + field_is_filter: フィルタとして使う + field_issue_to: 関連するチケット + field_delay: 遅延 + field_assignable: このロールにチケットを割り当て可能 + field_redirect_existing_links: 既存のリンクをリダイレクトする + field_estimated_hours: 予定工数 + field_column_names: 項目 + field_time_entries: 時間を記録 + field_time_zone: タイムゾーン + field_searchable: 検索条件に設定可能とする + field_default_value: デフォルト値 + field_comments_sorting: コメントの表示順 + field_parent_title: 親ページ + field_editable: 編集可能 + field_watcher: ウォッチャー + field_identity_url: OpenID URL + field_content: 内容 + field_group_by: グループ条件 + field_sharing: 共有 + field_parent_issue: 親チケット + field_member_of_group: 担当者のグループ + field_assigned_to_role: 担当者のロール + field_text: テキスト + field_visible: 表示 + field_warn_on_leaving_unsaved: データを保存せずにページから移動するときに警告 + field_commit_logs_encoding: コミットメッセージのエンコーディング + field_scm_path_encoding: パスのエンコーディング + field_path_to_repository: リポジトリのパス + field_root_directory: ルートディレクトリ + field_cvsroot: CVSROOT + field_cvs_module: モジュール + + setting_app_title: アプリケーションのタイトル + setting_app_subtitle: アプリケーションのサブタイトル + setting_welcome_text: ウェルカムメッセージ + setting_default_language: 既定の言語 + setting_login_required: 認証が必要 + setting_self_registration: ユーザーによるアカウント登録 + setting_attachment_max_size: 添付ファイルサイズの上限 + setting_issues_export_limit: エクスポートするチケット数の上限 + setting_mail_from: 送信元メールアドレス + setting_bcc_recipients: ブラインドカーボンコピーで受信(bcc) + setting_plain_text_mail: プレインテキストのみ(HTMLなし) + setting_host_name: ホスト名 + setting_text_formatting: テキストの書式 + setting_cache_formatted_text: 書式化されたテキストをキャッシュする + setting_wiki_compression: Wiki履歴を圧縮する + setting_feeds_limit: フィード内容の上限 + setting_default_projects_public: デフォルトで新しいプロジェクトは公開にする + setting_autofetch_changesets: コミットを自動取得する + setting_sys_api_enabled: リポジトリ管理用のWebサービスを有効にする + setting_commit_ref_keywords: 参照用キーワード + setting_commit_fix_keywords: 修正用キーワード + setting_autologin: 自動ログイン + setting_date_format: 日付の形式 + setting_time_format: 時刻の形式 + setting_cross_project_issue_relations: 異なるプロジェクトのチケット間で関連の設定を許可 + setting_issue_list_default_columns: チケットの一覧で表示する項目 + setting_repositories_encodings: 添付ファイルとリポジトリのエンコーディング + setting_emails_header: メールのヘッダ + setting_emails_footer: メールのフッタ + setting_protocol: プロトコル + setting_per_page_options: ページ毎の表示件数 + setting_user_format: ユーザー名の表示書式 + setting_activity_days_default: プロジェクトの活動ページに表示される日数 + setting_display_subprojects_issues: サブプロジェクトのチケットをメインプロジェクトに表示する + setting_enabled_scm: 使用するバージョン管理システム + setting_mail_handler_body_delimiters: "メール本文から一致する行以降を切り取る" + setting_mail_handler_api_enabled: 受信メール用のWebサービスを有効にする + setting_mail_handler_api_key: APIキー + setting_sequential_project_identifiers: プロジェクト識別子を連番で生成する + setting_gravatar_enabled: Gravatarのアイコンを使用する + setting_gravatar_default: デフォルトのGravatarアイコン + setting_diff_max_lines_displayed: 差分の表示行数の上限 + setting_file_max_size_displayed: 画面表示するテキストファイルサイズの上限 + setting_repository_log_display_limit: ファイルのリビジョン表示数の上限 + setting_openid: OpenIDによるログインと登録 + setting_password_min_length: パスワードの最低必要文字数 + setting_new_project_user_role_id: システム管理者以外のユーザーが作成したプロジェクトに設定するロール + setting_default_projects_modules: 新規プロジェクトにおいてデフォルトで有効になるモジュール + setting_issue_done_ratio: 進捗の算出方法 + setting_issue_done_ratio_issue_field: 各チケットにフィールドを用意する + setting_issue_done_ratio_issue_status: チケットのステータスを使用する + setting_start_of_week: 週の開始曜日 + setting_rest_api_enabled: RESTによるWebサービスを有効にする + setting_default_notification_option: デフォルトのメール通知オプション + setting_commit_logtime_enabled: コミット時に作業時間を記録する + setting_commit_logtime_activity_id: 作業時間の作業分類 + setting_gantt_items_limit: ガントチャート最大表示項目数 + setting_default_projects_tracker_ids: 新規プロジェクトにおいてデフォルトで有効になるトラッカー + + permission_add_project: プロジェクトの追加 + permission_add_subprojects: サブプロジェクトの追加 + permission_edit_project: プロジェクトの編集 + permission_select_project_modules: モジュールの選択 + permission_manage_members: メンバーの管理 + permission_manage_versions: バージョンの管理 + permission_manage_categories: チケットのカテゴリの管理 + permission_view_issues: チケットの閲覧 + permission_add_issues: チケットの追加 + permission_edit_issues: チケットの編集 + permission_manage_issue_relations: 関連するチケットの管理 + permission_add_issue_notes: 注記の追加 + permission_edit_issue_notes: 注記の編集 + permission_edit_own_issue_notes: 自身が記入した注記の編集 + permission_move_issues: チケットの移動 + permission_delete_issues: チケットの削除 + permission_manage_public_queries: 公開クエリの管理 + permission_save_queries: クエリの保存 + permission_view_gantt: ガントチャートの閲覧 + permission_view_calendar: カレンダーの閲覧 + permission_view_issue_watchers: ウォッチャー一覧の閲覧 + permission_add_issue_watchers: ウォッチャーの追加 + permission_delete_issue_watchers: ウォッチャーの削除 + permission_log_time: 作業時間の記入 + permission_view_time_entries: 作業時間の閲覧 + permission_edit_time_entries: 作業時間の編集 + permission_edit_own_time_entries: 自身が記入した作業時間の編集 + permission_manage_project_activities: 作業分類 (時間トラッキング) の管理 + permission_manage_news: ニュースの管理 + permission_comment_news: ニュースへのコメント + permission_view_documents: 文書の閲覧 + permission_manage_files: ファイルの管理 + permission_view_files: ファイルの閲覧 + permission_manage_wiki: Wikiの管理 + permission_rename_wiki_pages: Wikiページ名の変更 + permission_delete_wiki_pages: Wikiページの削除 + permission_view_wiki_pages: Wikiの閲覧 + permission_export_wiki_pages: Wikiページを他の形式にエクスポート + permission_view_wiki_edits: Wiki履歴の閲覧 + permission_edit_wiki_pages: Wikiページの編集 + permission_delete_wiki_pages_attachments: 添付ファイルの削除 + permission_protect_wiki_pages: Wikiページの凍結 + permission_manage_repository: リポジトリの管理 + permission_browse_repository: リポジトリの閲覧 + permission_view_changesets: 更新履歴の閲覧 + permission_commit_access: コミット権限 + permission_manage_boards: フォーラムの管理 + permission_view_messages: メッセージの閲覧 + permission_add_messages: メッセージの追加 + permission_edit_messages: メッセージの編集 + permission_edit_own_messages: 自身が記入したメッセージの編集 + permission_delete_messages: メッセージの削除 + permission_delete_own_messages: 自身が記入したメッセージの削除 + permission_manage_subtasks: 子チケットの管理 + + project_module_issue_tracking: チケットトラッキング + project_module_time_tracking: 時間トラッキング + project_module_news: ニュース + project_module_documents: 文書 + project_module_files: ファイル + project_module_wiki: Wiki + project_module_repository: リポジトリ + project_module_boards: フォーラム + project_module_gantt: ガントチャート + project_module_calendar: カレンダー + + label_user: ユーザー + label_user_plural: ユーザー + label_user_new: 新しいユーザー + label_user_anonymous: 匿名ユーザー + label_profile: プロフィール + label_project: プロジェクト + label_project_new: 新しいプロジェクト + label_project_plural: プロジェクト + label_x_projects: + zero: プロジェクトはありません + one: 1プロジェクト + other: "%{count}プロジェクト" + label_project_all: 全プロジェクト + label_project_latest: 最近のプロジェクト + label_issue: チケット + label_issue_new: 新しいチケット + label_issue_plural: チケット + label_issue_view_all: すべてのチケットを見る + label_issues_by: "%{value} 別のチケット" + label_issue_added: チケットが追加されました + label_issue_updated: チケットが更新されました + label_document: 文書 + label_document_new: 新しい文書 + label_document_plural: 文書 + label_document_added: 文書が追加されました + label_role: ロール + label_role_plural: ロール + label_role_new: 新しいロール + label_role_and_permissions: ロールと権限 + label_member: メンバー + label_member_new: 新しいメンバー + label_member_plural: メンバー + label_tracker: トラッカー + label_tracker_plural: トラッカー + label_tracker_new: 新しいトラッカーを作成 + label_workflow: ワークフロー + label_issue_status: チケットのステータス + label_issue_status_plural: チケットのステータス + label_issue_status_new: 新しいステータス + label_issue_category: チケットのカテゴリ + label_issue_category_plural: チケットのカテゴリ + label_issue_category_new: 新しいカテゴリ + label_custom_field: カスタムフィールド + label_custom_field_plural: カスタムフィールド + label_custom_field_new: 新しいカスタムフィールドを作成 + label_enumerations: 列挙項目 + label_enumeration_new: 新しい値 + label_information: 情報 + label_information_plural: 情報 + label_please_login: ログインしてください + label_register: 登録する + label_login_with_open_id_option: またはOpenIDでログインする + label_password_lost: パスワードの再発行 + label_home: ホーム + label_my_page: マイページ + label_my_account: 個人設定 + label_my_projects: マイプロジェクト + label_my_page_block: マイページパーツ + label_administration: 管理 + label_login: ログイン + label_logout: ログアウト + label_help: ヘルプ + label_reported_issues: 報告したチケット + label_assigned_to_me_issues: 担当しているチケット + label_last_login: 最近の接続 + label_registered_on: 登録日 + label_activity: 活動 + label_overall_activity: すべての活動 + label_user_activity: "%{value} の活動" + label_new: 新しく作成 + label_logged_as: ログイン中: + label_environment: 環境 + label_authentication: 認証 + label_auth_source: 認証方式 + label_auth_source_new: 新しい認証方式 + label_auth_source_plural: 認証方式 + label_subproject_plural: サブプロジェクト + label_subproject_new: 新しいサブプロジェクト + label_and_its_subprojects: "%{value} とサブプロジェクト" + label_min_max_length: 最小値 - 最大値の長さ + label_list: リストから選択 + label_date: 日付 + label_integer: 整数 + label_float: 小数 + label_boolean: 真偽値 + label_string: テキスト + label_text: 長いテキスト + label_attribute: 属性 + label_attribute_plural: 属性 + label_no_data: 表示するデータがありません + label_change_status: ステータスの変更 + label_history: 履歴 + label_attachment: ファイル + label_attachment_new: 新しいファイル + label_attachment_delete: ファイルを削除 + label_attachment_plural: ファイル + label_file_added: ファイルが追加されました + label_report: レポート + label_report_plural: レポート + label_news: ニュース + label_news_new: ニュースを追加 + label_news_plural: ニュース + label_news_latest: 最新ニュース + label_news_view_all: すべてのニュースを見る + label_news_added: ニュースが追加されました + label_news_comment_added: ニュースにコメントが追加されました + label_settings: 設定 + label_overview: 概要 + label_version: バージョン + label_version_new: 新しいバージョン + label_version_plural: バージョン + label_confirmation: 確認 + label_close_versions: 完了したバージョンを終了にする + label_export_to: '他の形式にエクスポート:' + label_read: 読む... + label_public_projects: 公開プロジェクト + label_open_issues: 未完了 + label_open_issues_plural: 未完了 + label_closed_issues: 完了 + label_closed_issues_plural: 完了 + label_x_open_issues_abbr_on_total: + zero: 0件未完了 / 全%{total}件 + one: 1件未完了 / 全%{total}件 + other: "%{count}件未完了 / 全%{total}件" + label_x_open_issues_abbr: + zero: 0件未完了 + one: 1件未完了 + other: "%{count}件未完了" + label_x_closed_issues_abbr: + zero: 0件完了 + one: 1件完了 + other: "%{count}件完了" + label_total: 合計 + label_permissions: 権限 + label_current_status: 現在のステータス + label_new_statuses_allowed: ステータスの移行先 + label_all: すべて + label_none: なし + label_nobody: 無記名 + label_next: 次 + label_previous: 前 + label_used_by: 使用中 + label_details: 詳細 + label_add_note: 注記を追加 + label_per_page: ページ毎 + label_calendar: カレンダー + label_months_from: ヶ月分 + label_gantt: ガントチャート + label_internal: 内部 + label_last_changes: "最新の変更 %{count}件" + label_change_view_all: すべての変更を見る + label_personalize_page: このページをパーソナライズする + label_comment: コメント + label_comment_plural: コメント + label_x_comments: + zero: コメントがありません + one: 1コメント + other: "%{count}コメント" + label_comment_add: コメント追加 + label_comment_added: 追加されたコメント + label_comment_delete: コメント削除 + label_query: カスタムクエリ + label_query_plural: カスタムクエリ + label_query_new: 新しいクエリ + label_my_queries: マイカスタムクエリ + label_filter_add: フィルタ追加 + label_filter_plural: フィルタ + label_equals: 等しい + label_not_equals: 等しくない + label_in_less_than: 今日から○日後以前 + label_in_more_than: 今日から○日後以降 + label_greater_or_equal: 以上 + label_less_or_equal: 以下 + label_in: 今日から○日後 + label_today: 今日 + label_all_time: 全期間 + label_yesterday: 昨日 + label_this_week: 今週 + label_last_week: 先週 + label_last_n_days: "直近%{count}日間" + label_this_month: 今月 + label_last_month: 先月 + label_this_year: 今年 + label_date_range: 期間 + label_less_than_ago: 今日より○日前以降 + label_more_than_ago: 今日より○日前以前 + label_ago: ○日前 + label_contains: 含む + label_not_contains: 含まない + label_day_plural: 日 + label_repository: リポジトリ + label_repository_plural: リポジトリ + label_browse: ブラウズ + label_branch: ブランチ + label_tag: タグ + label_revision: リビジョン + label_revision_plural: リビジョン + label_revision_id: リビジョン %{value} + label_associated_revisions: 関係しているリビジョン + label_added: 追加 + label_modified: 変更 + label_copied: コピー + label_renamed: 名称変更 + label_deleted: 削除 + label_latest_revision: 最新リビジョン + label_latest_revision_plural: 最新リビジョン + label_view_revisions: リビジョンを見る + label_view_all_revisions: すべてのリビジョンを見る + label_max_size: サイズの上限 + label_sort_highest: 一番上へ + label_sort_higher: 上へ + label_sort_lower: 下へ + label_sort_lowest: 一番下へ + label_roadmap: ロードマップ + label_roadmap_due_in: "期日まで %{value}" + label_roadmap_overdue: "%{value} 遅れ" + label_roadmap_no_issues: このバージョンに関するチケットはありません + label_search: 検索 + label_result_plural: 結果 + label_all_words: すべての単語 + label_wiki: Wiki + label_wiki_edit: Wiki編集 + label_wiki_edit_plural: Wiki編集 + label_wiki_page: Wikiページ + label_wiki_page_plural: Wikiページ + label_index_by_title: 索引(名前順) + label_index_by_date: 索引(日付順) + label_current_version: 最新版 + label_preview: プレビュー + label_feed_plural: フィード + label_changes_details: 全変更の詳細 + label_issue_tracking: チケットトラッキング + label_spent_time: 作業時間の記録 + label_overall_spent_time: すべての作業時間の記録 + label_f_hour: "%{value}時間" + label_f_hour_plural: "%{value}時間" + label_time_tracking: 時間トラッキング + label_change_plural: 変更 + label_statistics: 統計 + label_commits_per_month: 月別のコミット + label_commits_per_author: 起票者別のコミット + label_diff: 差分 + label_view_diff: 差分を見る + label_diff_inline: インライン + label_diff_side_by_side: 横に並べる + label_options: オプション + label_copy_workflow_from: ワークフローをここからコピー + label_permissions_report: 権限レポート + label_watched_issues: ウォッチしているチケット + label_related_issues: 関連するチケット + label_applied_status: 適用されるステータス + label_loading: ロード中... + label_relation_new: 新しい関連 + label_relation_delete: 関連の削除 + label_relates_to: 関連している + label_duplicates: 次のチケットと重複 + label_duplicated_by: 次のチケットが重複 + label_blocks: ブロックしている + label_blocked_by: ブロックされている + label_precedes: 次のチケットに先行 + label_follows: 次のチケットに後続 + label_end_to_start: 最後-最初 + label_end_to_end: 最後-最後 + label_start_to_start: 最初-最初 + label_start_to_end: 最初-最後 + label_stay_logged_in: ログインを維持 + label_disabled: 無効 + label_show_completed_versions: 完了したバージョンを表示 + label_me: 自分 + label_board: フォーラム + label_board_new: 新しいフォーラム + label_board_plural: フォーラム + label_board_sticky: スティッキー + label_board_locked: ロック + label_topic_plural: トピック + label_message_plural: メッセージ + label_message_last: 最新のメッセージ + label_message_new: 新しいメッセージ + label_message_posted: メッセージが追加されました + label_reply_plural: 返答 + label_send_information: アカウント情報をユーザーに送信 + label_year: 年 + label_month: 月 + label_week: 週 + label_date_from: "日付指定: " + label_date_to: から + label_language_based: ユーザーの言語の設定に従う + label_sort_by: "並び替え %{value}" + label_send_test_email: テストメールを送信 + label_feeds_access_key: RSSアクセスキー + label_missing_feeds_access_key: RSSアクセスキーが見つかりません + label_feeds_access_key_created_on: "RSSアクセスキーは%{value}前に作成されました" + label_module_plural: モジュール + label_added_time_by: "%{author} が%{age}前に追加" + label_updated_time_by: "%{author} が%{age}前に更新" + label_updated_time: "%{value}前に更新" + label_jump_to_a_project: プロジェクトへ移動... + label_file_plural: ファイル + label_changeset_plural: 更新履歴 + label_default_columns: 既定の項目 + label_no_change_option: (変更無し) + label_bulk_edit_selected_issues: チケットの一括編集 + label_theme: テーマ + label_default: 既定 + label_search_titles_only: タイトルのみ + label_user_mail_option_all: "参加しているプロジェクトのすべての通知" + label_user_mail_option_selected: "選択したプロジェクトのすべての通知..." + label_user_mail_option_none: "通知しない" + label_user_mail_option_only_my_events: "ウォッチまたは関係している事柄のみ" + label_user_mail_option_only_assigned: "自分が担当している事柄のみ" + label_user_mail_option_only_owner: "自分が作成した事柄のみ" + label_user_mail_no_self_notified: 自分自身による変更の通知は不要 + label_registration_activation_by_email: メールでアカウントを有効化 + label_registration_manual_activation: 手動でアカウントを有効化 + label_registration_automatic_activation: 自動でアカウントを有効化 + label_display_per_page: "1ページに: %{value}" + label_age: 年齢 + label_change_properties: プロパティの変更 + label_general: 全般 + label_more: 続き + label_scm: バージョン管理システム + label_plugins: プラグイン + label_ldap_authentication: LDAP認証 + label_downloads_abbr: DL + label_optional_description: 任意のコメント + label_add_another_file: 別のファイルを追加 + label_preferences: 設定 + label_chronological_order: 古い順 + label_reverse_chronological_order: 新しい順 + label_planning: 計画 + label_incoming_emails: 受信メール + label_generate_key: キーの生成 + label_issue_watchers: チケットのウォッチャー + label_example: 例 + label_display: 表示 + label_sort: ソート条件 + label_ascending: 昇順 + label_descending: 降順 + label_date_from_to: "%{start}から%{end}まで" + label_wiki_content_added: Wikiページが追加されました + label_wiki_content_updated: Wikiページが更新されました + label_group: グループ + label_group_plural: グループ + label_group_new: 新しいグループ + label_time_entry_plural: 作業時間の記録 + label_version_sharing_none: 共有しない + label_version_sharing_descendants: サブプロジェクト単位 + label_version_sharing_hierarchy: プロジェクト階層単位 + label_version_sharing_tree: プロジェクトツリー単位 + label_version_sharing_system: すべてのプロジェクト + label_update_issue_done_ratios: 進捗の更新 + label_copy_source: コピー元 + label_copy_target: コピー先 + label_copy_same_as_target: 同じコピー先 + label_display_used_statuses_only: このトラッカーで使われているステータスのみ表示する + label_api_access_key: APIアクセスキー + label_missing_api_access_key: APIアクセスキーが見つかりません + label_api_access_key_created_on: "APIアクセスキーは%{value}前に作成されました" + label_subtask_plural: 子チケット + label_project_copy_notifications: コピーしたチケットのメール通知を送信する + label_principal_search: "ユーザーまたはグループの検索:" + label_user_search: "ユーザーの検索:" + label_git_report_last_commit: ファイルとディレクトリの最新コミットを表示する + label_parent_revision: 親 + label_child_revision: 子 + label_gantt_progress_line: イナズマ線 + + button_login: ログイン + button_submit: 送信 + button_save: 保存 + button_check_all: すべてにチェックをつける + button_uncheck_all: すべてのチェックを外す + button_expand_all: 展開 + button_collapse_all: 折りたたみ + button_delete: 削除 + button_create: 作成 + button_create_and_continue: 連続作成 + button_test: テスト + button_edit: 編集 + button_edit_associated_wikipage: "関連するWikiページを編集: %{page_title}" + button_add: 追加 + button_change: 変更 + button_apply: 適用 + button_clear: クリア + button_lock: ロック + button_unlock: アンロック + button_download: ダウンロード + button_list: 一覧 + button_view: 表示 + button_move: 移動 + button_move_and_follow: 移動後表示 + button_back: 戻る + button_cancel: キャンセル + button_activate: 有効にする + button_sort: ソート + button_log_time: 時間を記録 + button_rollback: このバージョンにロールバック + button_watch: ウォッチ + button_unwatch: ウォッチをやめる + button_reply: 返答 + button_archive: アーカイブ + button_unarchive: アーカイブ解除 + button_reset: リセット + button_rename: 名前変更 + button_change_password: パスワード変更 + button_copy: コピー + button_copy_and_follow: コピー後表示 + button_annotate: アノテート + button_update: 更新 + button_configure: 設定 + button_quote: 引用 + button_duplicate: 複製 + button_show: 表示 + + status_active: 有効 + status_registered: 登録 + status_locked: ロック + + version_status_open: 進行中 + version_status_locked: ロック中 + version_status_closed: 終了 + + field_active: 有効 + + text_select_mail_notifications: どのメール通知を送信するか、アクションを選択してください。 + text_regexp_info: 例) ^[A-Z0-9]+$ + text_min_max_length_info: 0だと無制限になります + text_project_destroy_confirmation: 本当にこのプロジェクトと関連データを削除しますか? + text_subprojects_destroy_warning: "サブプロジェクト %{value} も削除されます。" + text_workflow_edit: ワークフローを編集するロールとトラッカーを選んでください + text_are_you_sure: よろしいですか? + text_journal_changed: "%{label} を %{old} から %{new} に変更" + text_journal_changed_no_detail: "%{label} を更新" + text_journal_set_to: "%{label} を %{value} にセット" + text_journal_deleted: "%{label} を削除 (%{old})" + text_journal_added: "%{label} %{value} を追加" + text_tip_issue_begin_day: この日に開始するチケット + text_tip_issue_end_day: この日に終了するチケット + text_tip_issue_begin_end_day: この日に開始・終了するチケット + text_caracters_maximum: "最大%{count}文字です。" + text_caracters_minimum: "最低%{count}文字の長さが必要です" + text_length_between: "長さは%{min}から%{max}文字までです。" + text_tracker_no_workflow: このトラッカーにワークフローが定義されていません + text_unallowed_characters: 次の文字は使用できません + text_comma_separated: (カンマで区切ることで)複数の値を設定できます。 + text_line_separated: (1行ごとに書くことで)複数の値を設定できます。 + text_issues_ref_in_commit_messages: コミットメッセージ内でチケットの参照/修正 + text_issue_added: "チケット %{id} が %{author} によって報告されました。" + text_issue_updated: "チケット %{id} が %{author} によって更新されました。" + text_wiki_destroy_confirmation: 本当にこのwikiとその内容のすべてを削除しますか? + text_issue_category_destroy_question: "%{count}件のチケットがこのカテゴリに割り当てられています。" + text_issue_category_destroy_assignments: カテゴリの割り当てを削除する + text_issue_category_reassign_to: チケットをこのカテゴリに再割り当てする + text_user_mail_option: "未選択のプロジェクトでは、ウォッチまたは関係している事柄(例: 自分が報告者もしくは担当者であるチケット)のみメールが送信されます。" + text_no_configuration_data: "ロール、トラッカー、チケットのステータス、ワークフローがまだ設定されていません。\nデフォルト設定のロードを強くお勧めします。ロードした後、それを修正することができます。" + text_load_default_configuration: デフォルト設定をロード + text_status_changed_by_changeset: "更新履歴 %{value} で適用されました。" + text_time_logged_by_changeset: "更新履歴 %{value} で適用されました。" + text_issues_destroy_confirmation: '本当に選択したチケットを削除しますか?' + text_select_project_modules: 'このプロジェクトで使用するモジュールを選択してください:' + text_default_administrator_account_changed: デフォルト管理アカウントが変更済 + text_file_repository_writable: ファイルリポジトリに書き込み可能 + text_plugin_assets_writable: Plugin assetsディレクトリに書き込み可能 + text_rmagick_available: RMagickが使用可能 (オプション) + text_destroy_time_entries_question: このチケットの%{hours}時間分の作業記録の扱いを選択してください。 + text_destroy_time_entries: 記録された作業時間を含めて削除 + text_assign_time_entries_to_project: 記録された作業時間をプロジェクト自体に割り当て + text_reassign_time_entries: '記録された作業時間をこのチケットに再割り当て:' + text_user_wrote: "%{value} は書きました:" + text_enumeration_destroy_question: "%{count}個のオブジェクトがこの値に割り当てられています。" + text_enumeration_category_reassign_to: '次の値に割り当て直す:' + text_email_delivery_not_configured: "メールを送信するために必要な設定が行われていないため、メール通知は利用できません。\nconfig/configuration.ymlでSMTPサーバの設定を行い、アプリケーションを再起動してください。" + text_repository_usernames_mapping: "リポジトリのログから検出されたユーザー名をどのRedmineユーザーに関連づけるのか選択してください。\nログ上のユーザー名またはメールアドレスがRedmineのユーザーと一致する場合は自動的に関連づけられます。" + text_diff_truncated: '... 差分の行数が表示可能な上限を超えました。超過分は表示しません。' + text_custom_field_possible_values_info: '選択肢の値は1行に1個ずつ記述してください。' + text_wiki_page_destroy_question: "この親ページの配下に%{descendants}ページの子孫ページがあります。" + text_wiki_page_nullify_children: "子ページをメインページ配下に移動する" + text_wiki_page_destroy_children: "配下の子孫ページも削除する" + text_wiki_page_reassign_children: "子ページを次の親ページの配下に移動する" + text_own_membership_delete_confirmation: "一部またはすべての権限を自分自身から剥奪しようとしているため、このプロジェクトを編集できなくなる可能性があります。\n本当に続けますか?" + text_zoom_in: 拡大 + text_zoom_out: 縮小 + text_warn_on_leaving_unsaved: このページから移動すると、保存されていないデータが失われます。 + text_scm_path_encoding_note: "デフォルト: UTF-8" + text_mercurial_repository_note: "ローカルリポジトリ (例: /hgrepo, c:\\hgrepo)" + text_git_repository_note: "Bare、かつ、ローカルリポジトリ (例: /gitrepo, c:\\gitrepo)" + text_scm_command: コマンド + text_scm_command_version: バージョン + text_scm_config: バージョン管理システムのコマンドをconfig/configuration.ymlで設定できます。設定後、Redmineを再起動してください。 + text_scm_command_not_available: バージョン管理システムのコマンドが利用できません。管理画面にて設定を確認してください。 + + default_role_manager: 管理者 + default_role_developer: 開発者 + default_role_reporter: 報告者 + default_tracker_bug: バグ + default_tracker_feature: 機能 + default_tracker_support: サポート + default_issue_status_new: 新規 + default_issue_status_in_progress: 進行中 + default_issue_status_resolved: 解決 + default_issue_status_feedback: フィードバック + default_issue_status_closed: 終了 + default_issue_status_rejected: 却下 + default_doc_category_user: ユーザー文書 + default_doc_category_tech: 技術文書 + default_priority_low: 低め + default_priority_normal: 通常 + default_priority_high: 高め + default_priority_urgent: 急いで + default_priority_immediate: 今すぐ + default_activity_design: 設計作業 + default_activity_development: 開発作業 + + enumeration_issue_priorities: チケットの優先度 + enumeration_doc_categories: 文書カテゴリ + enumeration_activities: 作業分類 (時間トラッキング) + enumeration_system_activity: システム作業分類 + label_additional_workflow_transitions_for_assignee: チケット担当者に追加で許可する遷移 + label_additional_workflow_transitions_for_author: チケット作成者に追加で許可する遷移 + label_bulk_edit_selected_time_entries: 作業時間の一括編集 + text_time_entries_destroy_confirmation: 本当に選択した作業時間を削除しますか? + + label_role_anonymous: 匿名ユーザー + label_role_non_member: 非メンバー + + label_issue_note_added: 注記が追加されました + label_issue_status_updated: ステータスが更新されました + label_issue_priority_updated: 優先度が更新されました + label_issues_visibility_own: 作成者か担当者であるチケット + field_issues_visibility: 表示できるチケット + label_issues_visibility_all: すべてのチケット + permission_set_own_issues_private: 自分のチケットをプライベートに設定 + field_is_private: プライベート + permission_set_issues_private: チケットをプライベートに設定 + label_issues_visibility_public: プライベートチケット以外 + text_issues_destroy_descendants_confirmation: "%{count}個の子チケットも削除されます。" + notice_issue_successful_create: チケット %{id} が作成されました。 + label_between: 次の範囲内 + setting_issue_group_assignment: グループへのチケット割り当てを許可 + description_query_sort_criteria_direction: 順序 + description_project_scope: 検索範囲 + description_filter: Filter + description_user_mail_notification: メール通知の設定 + description_date_from: 開始日 + description_message_content: 内容 + description_available_columns: 利用できる項目 + description_date_range_interval: 日付で指定 + description_issue_category_reassign: 新しいカテゴリを選択してください + description_search: 検索キーワード + description_notes: 注記 + description_date_range_list: 一覧から選択 + description_choose_project: プロジェクト + description_date_to: 終了日 + description_query_sort_criteria_attribute: 項目 + description_wiki_subpages_reassign: 新しい親ページを選択してください + description_selected_columns: 選択された項目 + error_scm_annotate_big_text_file: テキストファイルサイズの上限を超えているためアノテートできません。 + setting_default_issue_start_date_to_creation_date: 現在の日付を新しいチケットの開始日とする + button_edit_section: このセクションを編集 + description_all_columns: すべての項目 + button_export: エクスポート + label_export_options: "%{export_format} エクスポート設定" + error_attachment_too_big: このファイルはアップロードできません。添付ファイルサイズの上限(%{max_size})を超えています。 + notice_failed_to_save_time_entries: "全%{total}件中%{count}件の作業時間が保存できませんでした: %{ids}." + label_x_issues: + zero: 0 チケット + one: 1 チケット + other: "%{count} チケット" + label_repository_new: 新しいリポジトリ + field_repository_is_default: メインリポジトリ + label_copy_attachments: 添付ファイルをコピー + label_item_position: "%{position}/%{count}" + label_completed_versions: 完了したバージョン + text_project_identifier_info: アルファベット小文字(a-z)・数字・ハイフン・アンダースコアが使えます。最初の文字はアルファベットの小文字にしてください。
    識別子は後で変更することはできません。 + field_multiple: 複数選択可 + setting_commit_cross_project_ref: 異なるプロジェクトのチケットの参照/修正を許可 + text_issue_conflict_resolution_add_notes: 自分の編集内容を破棄し注記のみ追加 + text_issue_conflict_resolution_overwrite: 自分の編集内容の保存を強行 (他のユーザーの更新内容は注記を除き上書きされます) + notice_issue_update_conflict: このチケットを編集中に他のユーザーが更新しました。 + text_issue_conflict_resolution_cancel: 自分の編集内容を破棄し %{link} を再表示 + permission_manage_related_issues: 関連するチケットの管理 + field_auth_source_ldap_filter: LDAPフィルタ + label_search_for_watchers: ウォッチャーを検索して追加 + notice_account_deleted: アカウントが削除されました。 + setting_unsubscribe: ユーザーによるアカウント削除を許可 + button_delete_my_account: 自分のアカウントを削除 + text_account_destroy_confirmation: |- + 本当にアカウントを削除しますか? + アカウントは恒久的に削除されます。削除後に再度アカウントを有効にする手段はありません。 + error_session_expired: セッションが失効しました。ログインし直してください。 + text_session_expiration_settings: "警告: この設定を変更すると現在有効なセッションが失効する可能性があります。" + setting_session_lifetime: 有効期間の最大値 + setting_session_timeout: 無操作タイムアウト + label_session_expiration: セッション有効期間 + permission_close_project: プロジェクトの終了/再開 + label_show_closed_projects: 終了したプロジェクトを表示 + button_close: 終了 + button_reopen: 再開 + project_status_active: 有効 + project_status_closed: 終了 + project_status_archived: アーカイブ + text_project_closed: このプロジェクトは終了しているため読み取り専用です。 + notice_user_successful_create: ユーザー %{id} を作成しました。 + field_core_fields: 標準フィールド + field_timeout: タイムアウト(秒単位) + setting_thumbnails_enabled: 添付ファイルのサムネイル画像を表示 + setting_thumbnails_size: サムネイル画像の大きさ(ピクセル単位) + label_status_transitions: ステータスの遷移 + label_fields_permissions: フィールドに対する権限 + label_readonly: 読み取り専用 + label_required: 必須 + text_repository_identifier_info: アルファベット小文字(a-z)・数字・ハイフン・アンダースコアが使えます。
    識別子は後で変更することはできません。 + field_board_parent: 親フォーラム + label_attribute_of_project: プロジェクトの %{name} + label_attribute_of_author: 作成者の %{name} + label_attribute_of_assigned_to: 担当者の %{name} + label_attribute_of_fixed_version: 対象バージョンの %{name} + label_copy_subtasks: 子チケットをコピー + label_copied_to: コピー先 + label_copied_from: コピー元 + label_any_issues_in_project: 次のプロジェクト内のチケット + label_any_issues_not_in_project: 次のプロジェクト外のチケット + field_private_notes: プライベート注記 + permission_view_private_notes: プライベート注記の閲覧 + permission_set_notes_private: 注記をプライベートに設定 + label_no_issues_in_project: 次のプロジェクト内のチケットを除く + label_any: すべて + label_last_n_weeks: 直近%{count}週間 + setting_cross_project_subtasks: 異なるプロジェクトのチケット間の親子関係を許可 + label_cross_project_descendants: サブプロジェクト単位 + label_cross_project_tree: プロジェクトツリー単位 + label_cross_project_hierarchy: プロジェクト階層単位 + label_cross_project_system: すべてのプロジェクト + button_hide: 隠す + setting_non_working_week_days: 休業日 + label_in_the_next_days: 今後○日 + label_in_the_past_days: 過去○日 + label_attribute_of_user: ユーザーの %{name} + text_turning_multiple_off: この設定を無効にすると、複数選択されている値のうち1個だけが保持され残りは選択解除されます。 + label_attribute_of_issue: チケットの %{name} + permission_add_documents: 文書の追加 + permission_edit_documents: 文書の編集 + permission_delete_documents: 文書の削除 + setting_jsonp_enabled: JSONPを有効にする + field_inherit_members: メンバーを継承 + field_closed_on: 終了日 + label_total_time: 合計 diff --git a/config/locales/ko.yml b/config/locales/ko.yml new file mode 100644 index 00000000..eeec637e --- /dev/null +++ b/config/locales/ko.yml @@ -0,0 +1,1138 @@ +# Korean translations for Ruby on Rails +ko: + direction: ltr + date: + formats: + # Use the strftime parameters for formats. + # When no format has been given, it uses default. + # You can provide other formats here if you like! + default: "%Y/%m/%d" + short: "%m/%d" + long: "%Y년 %m월 %d일 (%a)" + + day_names: [일요일, 월요일, 화요일, 수요일, 목요일, 금요일, 토요일] + abbr_day_names: [일, 월, 화, 수, 목, 금, 토] + + # Don't forget the nil at the beginning; there's no such thing as a 0th month + month_names: [~, 1월, 2월, 3월, 4월, 5월, 6월, 7월, 8월, 9월, 10월, 11월, 12월] + abbr_month_names: [~, 1월, 2월, 3월, 4월, 5월, 6월, 7월, 8월, 9월, 10월, 11월, 12월] + # Used in date_select and datime_select. + order: + - :year + - :month + - :day + + time: + formats: + default: "%Y/%m/%d %H:%M:%S" + time: "%H:%M" + short: "%y/%m/%d %H:%M" + long: "%Y년 %B월 %d일, %H시 %M분 %S초 %Z" + am: "오전" + pm: "오후" + + datetime: + distance_in_words: + half_a_minute: "30초" + less_than_x_seconds: + one: "일초 이하" + other: "%{count}초 이하" + x_seconds: + one: "일초" + other: "%{count}초" + less_than_x_minutes: + one: "일분 이하" + other: "%{count}분 이하" + x_minutes: + one: "일분" + other: "%{count}분" + about_x_hours: + one: "약 한시간" + other: "약 %{count}시간" + x_hours: + one: "1 hour" + other: "%{count} hours" + x_days: + one: "하루" + other: "%{count}일" + about_x_months: + one: "약 한달" + other: "약 %{count}달" + x_months: + one: "한달" + other: "%{count}달" + about_x_years: + one: "약 일년" + other: "약 %{count}년" + over_x_years: + one: "일년 이상" + other: "%{count}년 이상" + almost_x_years: + one: "약 1년" + other: "약 %{count}년" + prompts: + year: "년" + month: "월" + day: "일" + hour: "시" + minute: "분" + second: "초" + + number: + # Used in number_with_delimiter() + # These are also the defaults for 'currency', 'percentage', 'precision', and 'human' + format: + # Sets the separator between the units, for more precision (e.g. 1.0 / 2.0 == 0.5) + separator: "." + # Delimets thousands (e.g. 1,000,000 is a million) (always in groups of three) + delimiter: "," + # Number of decimals, behind the separator (the number 1 with a precision of 2 gives: 1.00) + precision: 3 + + # Used in number_to_currency() + currency: + format: + # Where is the currency sign? %u is the currency unit, %n the number (default: $5.00) + format: "%u%n" + unit: "₩" + # These three are to override number.format and are optional + separator: "." + delimiter: "," + precision: 0 + + # Used in number_to_percentage() + percentage: + format: + # These three are to override number.format and are optional + # separator: + delimiter: "" + # precision: + + # Used in number_to_precision() + precision: + format: + # These three are to override number.format and are optional + # separator: + delimiter: "" + # precision: + + # Used in number_to_human_size() + human: + format: + # These three are to override number.format and are optional + # separator: + delimiter: "" + precision: 3 + storage_units: + format: "%n %u" + units: + byte: + one: "Byte" + other: "Bytes" + kb: "KB" + mb: "MB" + gb: "GB" + tb: "TB" + +# Used in array.to_sentence. + support: + array: + words_connector: ", " + two_words_connector: "과 " + last_word_connector: ", " + sentence_connector: "그리고" + skip_last_comma: false + + activerecord: + errors: + template: + header: + one: "한개의 오류가 발생해 %{model}을(를) 저장하지 않았습니다." + other: "%{count}개의 오류가 발생해 %{model}을(를) 저장하지 않았습니다." + # The variable :count is also available + body: "다음 항목에 문제가 발견했습니다:" + + messages: + inclusion: "은 목록에 포함되어 있지 않습니다" + exclusion: "은 예약되어 있습니다" + invalid: "은 유효하지 않습니다." + confirmation: "은 확인이 되지 않았습니다" + accepted: "은 인정되어야 합니다" + empty: "은 길이가 0이어서는 안됩니다." + blank: "은 빈 값이어서는 안 됩니다" + too_long: "은 너무 깁니다 (최대 %{count}자 까지)" + too_short: "은 너무 짧습니다 (최소 %{count}자 까지)" + wrong_length: "은 길이가 틀렸습니다 (%{count}자이어야 합니다.)" + taken: "은 이미 선택된 겁니다" + not_a_number: "은 숫자가 아닙니다" + greater_than: "은 %{count}보다 커야 합니다." + greater_than_or_equal_to: "은 %{count}보다 크거나 같아야 합니다" + equal_to: "은 %{count}(와)과 같아야 합니다" + less_than: "은 %{count}보다 작어야 합니다" + less_than_or_equal_to: "은 %{count}과 같거나 이하을 요구합니다" + odd: "은 홀수여야 합니다" + even: "은 짝수여야 합니다" + greater_than_start_date: "는 시작날짜보다 커야 합니다" + not_same_project: "는 같은 프로젝트에 속해 있지 않습니다" + circular_dependency: "이 관계는 순환 의존관계를 만들 수 있습니다" + cant_link_an_issue_with_a_descendant: "일감은 하위 일감과 연결할 수 없습니다." + + actionview_instancetag_blank_option: 선택하세요 + + general_text_No: '아니오' + general_text_Yes: '예' + general_text_no: '아니오' + general_text_yes: '예' + general_lang_name: 'Korean (한국어)' + general_csv_separator: ',' + general_csv_decimal_separator: '.' + general_csv_encoding: CP949 + general_pdf_encoding: CP949 + general_first_day_of_week: '7' + + notice_account_updated: 계정이 성공적으로 변경되었습니다. + notice_account_invalid_creditentials: 잘못된 계정 또는 비밀번호 + notice_account_password_updated: 비밀번호가 잘 변경되었습니다. + notice_account_wrong_password: 잘못된 비밀번호 + notice_account_register_done: 계정이 잘 만들어졌습니다. 계정을 활성화하시려면 받은 메일의 링크를 클릭해주세요. + notice_account_unknown_email: 알려지지 않은 사용자. + notice_can_t_change_password: 이 계정은 외부 인증을 이용합니다. 비밀번호를 변경할 수 없습니다. + notice_account_lost_email_sent: 새로운 비밀번호를 위한 메일이 발송되었습니다. + notice_account_activated: 계정이 활성화되었습니다. 이제 로그인 하실수 있습니다. + notice_successful_create: 생성 성공. + notice_successful_update: 변경 성공. + notice_successful_delete: 삭제 성공. + notice_successful_connection: 연결 성공. + notice_file_not_found: 요청하신 페이지는 삭제되었거나 옮겨졌습니다. + notice_locking_conflict: 다른 사용자에 의해서 데이터가 변경되었습니다. + notice_not_authorized: 이 페이지에 접근할 권한이 없습니다. + notice_email_sent: "%{value}님에게 메일이 발송되었습니다." + notice_email_error: "메일을 전송하는 과정에 오류가 발생했습니다. (%{value})" + notice_feeds_access_key_reseted: RSS에 접근가능한 열쇠(key)가 생성되었습니다. + notice_failed_to_save_issues: "저장에 실패하였습니다: 실패 %{count}(선택 %{total}): %{ids}." + notice_no_issue_selected: "일감이 선택되지 않았습니다. 수정하기 원하는 일감을 선택하세요" + notice_account_pending: "계정이 만들어졌으며 관리자 승인 대기중입니다." + notice_default_data_loaded: 기본값을 성공적으로 읽어들였습니다. + notice_unable_delete_version: 삭제할 수 없는 버전입니다. + + error_can_t_load_default_data: "기본값을 읽어들일 수 없습니다.: %{value}" + error_scm_not_found: 항목이나 리비젼이 저장소에 존재하지 않습니다. + error_scm_command_failed: "저장소에 접근하는 도중에 오류가 발생하였습니다.: %{value}" + error_scm_annotate: "항목이 없거나 행별 이력을 볼 수 없습니다." + error_issue_not_found_in_project: '일감이 없거나 이 프로젝트의 것이 아닙니다.' + + warning_attachments_not_saved: "%{count}개 파일을 저장할 수 없습니다." + + mail_subject_lost_password: "%{value} 비밀번호" + mail_body_lost_password: '비밀번호를 변경하려면 다음 링크를 클릭하세요.' + mail_subject_register: "%{value} 계정 활성화" + mail_body_register: '계정을 활성화하려면 링크를 클릭하세요.:' + mail_body_account_information_external: "로그인할 때 %{value} 계정을 사용하실 수 있습니다." + mail_body_account_information: 계정 정보 + mail_subject_account_activation_request: "%{value} 계정 활성화 요청" + mail_body_account_activation_request: "새 사용자(%{value})가 등록되었습니다. 관리자님의 승인을 기다리고 있습니다.:" + mail_body_reminder: "당신이 맡고 있는 일감 %{count}개의 완료기한이 %{days}일 후 입니다." + mail_subject_reminder: "내일이 만기인 일감 %{count}개 (%{days})" + mail_subject_wiki_content_added: "위키페이지 '%{id}'이(가) 추가되었습니다." + mail_subject_wiki_content_updated: "'위키페이지 %{id}'이(가) 수정되었습니다." + mail_body_wiki_content_added: "%{author}이(가) 위키페이지 '%{id}'을(를) 추가하였습니다." + mail_body_wiki_content_updated: "%{author}이(가) 위키페이지 '%{id}'을(를) 수정하였습니다." + + + field_name: 이름 + field_description: 설명 + field_summary: 요약 + field_is_required: 필수 + field_firstname: 이름 + field_lastname: 성 + field_mail: 메일 + field_filename: 파일 + field_filesize: 크기 + field_downloads: 다운로드 + field_author: 저자 + field_created_on: 등록 + field_updated_on: 변경 + field_field_format: 형식 + field_is_for_all: 모든 프로젝트 + field_possible_values: 가능한 값들 + field_regexp: 정규식 + field_min_length: 최소 길이 + field_max_length: 최대 길이 + field_value: 값 + field_category: 범주 + field_title: 제목 + field_project: 프로젝트 + field_issue: 일감 + field_status: 상태 + field_notes: 덧글 + field_is_closed: 완료 상태 + field_is_default: 기본값 + field_tracker: 유형 + field_subject: 제목 + field_due_date: 완료기한 + field_assigned_to: 담당자 + field_priority: 우선순위 + field_fixed_version: 목표버전 + field_user: 사용자 + field_role: 역할 + field_homepage: 홈페이지 + field_is_public: 공개 + field_parent: 상위 프로젝트 + field_is_in_roadmap: 로드맵에 표시 + field_login: 로그인 + field_mail_notification: 메일 알림 + field_admin: 관리자 + field_last_login_on: 마지막 로그인 + field_language: 언어 + field_effective_date: 날짜 + field_password: 비밀번호 + field_new_password: 새 비밀번호 + field_password_confirmation: 비밀번호 확인 + field_version: 버전 + field_type: 방식 + field_host: 호스트 + field_port: 포트 + field_account: 계정 + field_base_dn: 기본 DN + field_attr_login: 로그인 속성 + field_attr_firstname: 이름 속성 + field_attr_lastname: 성 속성 + field_attr_mail: 메일 속성 + field_onthefly: 동적 사용자 생성 + field_start_date: 시작시간 + field_done_ratio: 진척도 + field_auth_source: 인증 공급자 + field_hide_mail: 메일 주소 숨기기 + field_comments: 설명 + field_url: URL + field_start_page: 첫 페이지 + field_subproject: 하위 프로젝트 + field_hours: 시간 + field_activity: 작업종류 + field_spent_on: 작업시간 + field_identifier: 식별자 + field_is_filter: 검색조건으로 사용됨 + field_issue_to_id: 연관된 일감 + field_delay: 지연 + field_assignable: 이 역할에게 일감을 맡길 수 있음 + field_redirect_existing_links: 기존의 링크로 돌려보냄(redirect) + field_estimated_hours: 추정시간 + field_column_names: 컬럼 + field_default_value: 기본값 + field_time_zone: 시간대 + field_searchable: 검색가능 + field_comments_sorting: 댓글 정렬 + field_parent_title: 상위 제목 + field_editable: 편집가능 + field_watcher: 일감관람자 + field_identity_url: OpenID URL + field_content: 내용 + field_group_by: 결과를 묶어 보여줄 기준 + + setting_app_title: 레드마인 제목 + setting_app_subtitle: 레드마인 부제목 + setting_welcome_text: 환영 메시지 + setting_default_language: 기본 언어 + setting_login_required: 인증이 필요함 + setting_self_registration: 사용자 직접등록 + setting_attachment_max_size: 최대 첨부파일 크기 + setting_issues_export_limit: 일감 내보내기 제한 + setting_mail_from: 발신 메일 주소 + setting_bcc_recipients: 참조자들을 bcc로 숨기기 + setting_plain_text_mail: 텍스트만 (HTML 없이) + setting_host_name: 호스트 이름과 경로 + setting_text_formatting: 본문 형식 + setting_wiki_compression: 위키 이력 압축 + setting_feeds_limit: 피드에 포함할 항목의 수 + setting_default_projects_public: 새 프로젝트를 공개로 설정 + setting_autofetch_changesets: 커밋(commit)된 변경묶음을 자동으로 가져오기 + setting_sys_api_enabled: 저장소 관리에 WS를 사용 + setting_commit_ref_keywords: 일감 참조에 사용할 키워드들 + setting_commit_fix_keywords: 일감 해결에 사용할 키워드들 + setting_autologin: 자동 로그인 + setting_date_format: 날짜 형식 + setting_time_format: 시간 형식 + setting_cross_project_issue_relations: 다른 프로젝트의 일감과 연결하는 것을 허용 + setting_issue_list_default_columns: 일감 목록에 표시할 항목 + setting_emails_footer: 메일 꼬리 + setting_protocol: 프로토콜 + setting_per_page_options: 목록에서, 한 페이지에 표시할 행 + setting_user_format: 사용자 표시 형식 + setting_activity_days_default: 프로젝트 작업내역에 표시할 기간 + setting_display_subprojects_issues: 하위 프로젝트의 일감을 함께 표시 + setting_enabled_scm: "지원할 SCM(Source Control Management)" + setting_mail_handler_api_enabled: 수신 메일에 WS를 허용 + setting_mail_handler_api_key: API 키 + setting_sequential_project_identifiers: 프로젝트 식별자를 순차적으로 생성 + setting_gravatar_enabled: 그라바타 사용자 아이콘 사용 + setting_diff_max_lines_displayed: 차이점(diff) 보기에 표시할 최대 줄수 + setting_repository_log_display_limit: 저장소 보기에 표시할 개정판 이력의 최대 갯수 + setting_file_max_size_displayed: 바로 보여줄 텍스트파일의 최대 크기 + setting_openid: OpenID 로그인과 등록 허용 + setting_password_min_length: 최소 암호 길이 + setting_new_project_user_role_id: 프로젝트를 만든 사용자에게 주어질 역할 + + permission_add_project: 프로젝트 생성 + permission_edit_project: 프로젝트 편집 + permission_select_project_modules: 프로젝트 모듈 선택 + permission_manage_members: 구성원 관리 + permission_manage_versions: 버전 관리 + permission_manage_categories: 일감 범주 관리 + permission_add_issues: 일감 추가 + permission_edit_issues: 일감 편집 + permission_manage_issue_relations: 일감 관계 관리 + permission_add_issue_notes: 덧글 추가 + permission_edit_issue_notes: 덧글 편집 + permission_edit_own_issue_notes: 내 덧글 편집 + permission_move_issues: 일감 이동 + permission_delete_issues: 일감 삭제 + permission_manage_public_queries: 공용 검색양식 관리 + permission_save_queries: 검색양식 저장 + permission_view_gantt: Gantt차트 보기 + permission_view_calendar: 달력 보기 + permission_view_issue_watchers: 일감관람자 보기 + permission_add_issue_watchers: 일감관람자 추가 + permission_log_time: 작업시간 기록 + permission_view_time_entries: 시간입력 보기 + permission_edit_time_entries: 시간입력 편집 + permission_edit_own_time_entries: 내 시간입력 편집 + permission_manage_news: 뉴스 관리 + permission_comment_news: 뉴스에 댓글달기 + permission_view_documents: 문서 보기 + permission_manage_files: 파일관리 + permission_view_files: 파일보기 + permission_manage_wiki: 위키 관리 + permission_rename_wiki_pages: 위키 페이지 이름변경 + permission_delete_wiki_pages: 위치 페이지 삭제 + permission_view_wiki_pages: 위키 보기 + permission_view_wiki_edits: 위키 기록 보기 + permission_edit_wiki_pages: 위키 페이지 편집 + permission_delete_wiki_pages_attachments: 첨부파일 삭제 + permission_protect_wiki_pages: 프로젝트 위키 페이지 + permission_manage_repository: 저장소 관리 + permission_browse_repository: 저장소 둘러보기 + permission_view_changesets: 변경묶음보기 + permission_commit_access: 변경로그 보기 + permission_manage_boards: 게시판 관리 + permission_view_messages: 메시지 보기 + permission_add_messages: 메시지 추가 + permission_edit_messages: 메시지 편집 + permission_edit_own_messages: 자기 메시지 편집 + permission_delete_messages: 메시지 삭제 + permission_delete_own_messages: 자기 메시지 삭제 + + project_module_issue_tracking: 일감관리 + project_module_time_tracking: 시간추적 + project_module_news: 뉴스 + project_module_documents: 문서 + project_module_files: 파일 + project_module_wiki: 위키 + project_module_repository: 저장소 + project_module_boards: 게시판 + + label_user: 사용자 + label_user_plural: 사용자 + label_user_new: 새 사용자 + label_project: 프로젝트 + label_project_new: 새 프로젝트 + label_project_plural: 프로젝트 + label_x_projects: + zero: 없음 + one: "한 프로젝트" + other: "%{count}개 프로젝트" + label_project_all: 모든 프로젝트 + label_project_latest: 최근 프로젝트 + label_issue: 일감 + label_issue_new: 새 일감만들기 + label_issue_plural: 일감 + label_issue_view_all: 모든 일감 보기 + label_issues_by: "%{value}별 일감" + label_issue_added: 일감 추가 + label_issue_updated: 일감 수정 + label_document: 문서 + label_document_new: 새 문서 + label_document_plural: 문서 + label_document_added: 문서 추가 + label_role: 역할 + label_role_plural: 역할 + label_role_new: 새 역할 + label_role_and_permissions: 역할 및 권한 + label_member: 구성원 + label_member_new: 새 구성원 + label_member_plural: 구성원 + label_tracker: 일감 유형 + label_tracker_plural: 일감 유형 + label_tracker_new: 새 일감 유형 + label_workflow: 업무흐름 + label_issue_status: 일감 상태 + label_issue_status_plural: 일감 상태 + label_issue_status_new: 새 일감 상태 + label_issue_category: 일감 범주 + label_issue_category_plural: 일감 범주 + label_issue_category_new: 새 일감 범주 + label_custom_field: 사용자 정의 항목 + label_custom_field_plural: 사용자 정의 항목 + label_custom_field_new: 새 사용자 정의 항목 + label_enumerations: 코드값 + label_enumeration_new: 새 코드값 + label_information: 정보 + label_information_plural: 정보 + label_please_login: 로그인하세요. + label_register: 등록 + label_login_with_open_id_option: 또는 OpenID로 로그인 + label_password_lost: 비밀번호 찾기 + label_home: 초기화면 + label_my_page: 내 페이지 + label_my_account: 내 계정 + label_my_projects: 내 프로젝트 + label_administration: 관리 + label_login: 로그인 + label_logout: 로그아웃 + label_help: 도움말 + label_reported_issues: 보고한 일감 + label_assigned_to_me_issues: 내가 맡은 일감 + label_last_login: 마지막 접속 + label_registered_on: 등록시각 + label_activity: 작업내역 + label_overall_activity: 전체 작업내역 + label_user_activity: "%{value}의 작업내역" + label_new: 새로 만들기 + label_logged_as: '로그인계정:' + label_environment: 환경 + label_authentication: 인증 + label_auth_source: 인증 공급자 + label_auth_source_new: 새 인증 공급자 + label_auth_source_plural: 인증 공급자 + label_subproject_plural: 하위 프로젝트 + label_and_its_subprojects: "%{value}와 하위 프로젝트들" + label_min_max_length: 최소 - 최대 길이 + label_list: 목록 + label_date: 날짜 + label_integer: 정수 + label_float: 부동소수 + label_boolean: 부울린 + label_string: 문자열 + label_text: 텍스트 + label_attribute: 속성 + label_attribute_plural: 속성 + label_no_data: 표시할 데이터가 없습니다. + label_change_status: 상태 변경 + label_history: 이력 + label_attachment: 파일 + label_attachment_new: 파일추가 + label_attachment_delete: 파일삭제 + label_attachment_plural: 파일 + label_file_added: 파일 추가 + label_report: 보고서 + label_report_plural: 보고서 + label_news: 뉴스 + label_news_new: 새 뉴스 + label_news_plural: 뉴스 + label_news_latest: 최근 뉴스 + label_news_view_all: 모든 뉴스 + label_news_added: 뉴스 추가 + label_settings: 설정 + label_overview: 개요 + label_version: 버전 + label_version_new: 새 버전 + label_version_plural: 버전 + label_confirmation: 확인 + label_export_to: 내보내기 + label_read: 읽기... + label_public_projects: 공개 프로젝트 + label_open_issues: 진행중 + label_open_issues_plural: 진행중 + label_closed_issues: 완료됨 + label_closed_issues_plural: 완료됨 + label_x_open_issues_abbr_on_total: + zero: "총 %{total} 건 모두 완료" + one: "한 건 진행 중 / 총 %{total} 건 중 " + other: "%{count} 건 진행 중 / 총 %{total} 건" + label_x_open_issues_abbr: + zero: 모두 완료 + one: 한 건 진행 중 + other: "%{count} 건 진행 중" + label_x_closed_issues_abbr: + zero: 모두 미완료 + one: 한 건 완료 + other: "%{count} 건 완료" + label_total: 합계 + label_permissions: 권한 + label_current_status: 일감 상태 + label_new_statuses_allowed: 허용되는 일감 상태 + label_all: 모두 + label_none: 없음 + label_nobody: 미지정 + label_next: 다음 + label_previous: 뒤로 + label_used_by: 사용됨 + label_details: 자세히 + label_add_note: 일감덧글 추가 + label_per_page: 페이지별 + label_calendar: 달력 + label_months_from: 개월 동안 | 다음부터 + label_gantt: Gantt 챠트 + label_internal: 내부 + label_last_changes: "최근 %{count}개의 변경사항" + label_change_view_all: 모든 변경 내역 보기 + label_personalize_page: 입맛대로 구성하기 + label_comment: 댓글 + label_comment_plural: 댓글 + label_x_comments: + zero: 댓글 없음 + one: 한 개의 댓글 + other: "%{count} 개의 댓글" + label_comment_add: 댓글 추가 + label_comment_added: 댓글이 추가되었습니다. + label_comment_delete: 댓글 삭제 + label_query: 검색양식 + label_query_plural: 검색양식 + label_query_new: 새 검색양식 + label_filter_add: 검색조건 추가 + label_filter_plural: 검색조건 + label_equals: 이다 + label_not_equals: 아니다 + label_in_less_than: 이내 + label_in_more_than: 이후 + label_greater_or_equal: ">=" + label_less_or_equal: "<=" + label_in: 이내 + label_today: 오늘 + label_all_time: 모든 시간 + label_yesterday: 어제 + label_this_week: 이번주 + label_last_week: 지난 주 + label_last_n_days: "지난 %{count} 일" + label_this_month: 이번 달 + label_last_month: 지난 달 + label_this_year: 올해 + label_date_range: 날짜 범위 + label_less_than_ago: 이전 + label_more_than_ago: 이후 + label_ago: 일 전 + label_contains: 포함되는 키워드 + label_not_contains: 포함하지 않는 키워드 + label_day_plural: 일 + label_repository: 저장소 + label_repository_plural: 저장소 + label_browse: 저장소 둘러보기 + label_revision: 개정판 + label_revision_plural: 개정판 + label_associated_revisions: 관련된 개정판들 + label_added: 추가됨 + label_modified: 변경됨 + label_copied: 복사됨 + label_renamed: 이름바뀜 + label_deleted: 삭제됨 + label_latest_revision: 최근 개정판 + label_latest_revision_plural: 최근 개정판 + label_view_revisions: 개정판 보기 + label_max_size: 최대 크기 + label_sort_highest: 맨 위로 + label_sort_higher: 위로 + label_sort_lower: 아래로 + label_sort_lowest: 맨 아래로 + label_roadmap: 로드맵 + label_roadmap_due_in: "기한 %{value}" + label_roadmap_overdue: "%{value} 지연" + label_roadmap_no_issues: 이 버전에 해당하는 일감 없음 + label_search: 검색 + label_result_plural: 결과 + label_all_words: 모든 단어 + label_wiki: 위키 + label_wiki_edit: 위키 편집 + label_wiki_edit_plural: 위키 편집 + label_wiki_page: 위키 페이지 + label_wiki_page_plural: 위키 페이지 + label_index_by_title: 제목별 색인 + label_index_by_date: 날짜별 색인 + label_current_version: 현재 버전 + label_preview: 미리보기 + label_feed_plural: 피드(Feeds) + label_changes_details: 모든 상세 변경 내역 + label_issue_tracking: 일감 추적 + label_spent_time: 소요 시간 + label_f_hour: "%{value} 시간" + label_f_hour_plural: "%{value} 시간" + label_time_tracking: 시간추적 + label_change_plural: 변경사항들 + label_statistics: 통계 + label_commits_per_month: 월별 커밋 내역 + label_commits_per_author: 저자별 커밋 내역 + label_view_diff: 차이점 보기 + label_diff_inline: 두줄로 + label_diff_side_by_side: 한줄로 + label_options: 옵션 + label_copy_workflow_from: 업무흐름 복사하기 + label_permissions_report: 권한 보고서 + label_watched_issues: 지켜보고 있는 일감 + label_related_issues: 연결된 일감 + label_applied_status: 적용된 상태 + label_loading: 읽는 중... + label_relation_new: 새 관계 + label_relation_delete: 관계 지우기 + label_relates_to: "다음 일감과 관련됨:" + label_duplicates: "다음 일감에 중복됨:" + label_duplicated_by: "중복된 일감:" + label_blocks: "다음 일감의 해결을 막고 있음:" + label_blocked_by: "다음 일감에게 막혀 있음:" + label_precedes: "다음에 진행할 일감:" + label_follows: "다음 일감을 우선 진행:" + label_end_to_start: "끝에서 시작" + label_end_to_end: "끝에서 끝" + label_start_to_start: "시작에서 시작" + label_start_to_end: "시작에서 끝" + label_stay_logged_in: 로그인 유지 + label_disabled: 비활성화 + label_show_completed_versions: 완료된 버전 보기 + label_me: 나 + label_board: 게시판 + label_board_new: 새 게시판 + label_board_plural: 게시판 + label_topic_plural: 주제 + label_message_plural: 글 + label_message_last: 마지막 글 + label_message_new: 새글쓰기 + label_message_posted: 글 추가 + label_reply_plural: 답글 + label_send_information: 사용자에게 계정정보를 보내기 + label_year: 년 + label_month: 월 + label_week: 주 + label_date_from: '기간:' + label_date_to: ' ~ ' + label_language_based: 언어설정에 따름 + label_sort_by: "%{value}(으)로 정렬" + label_send_test_email: 테스트 메일 보내기 + label_feeds_access_key_created_on: "피드 접근 키가 %{value} 이전에 생성되었습니다." + label_module_plural: 모듈 + label_added_time_by: "%{author}이(가) %{age} 전에 추가함" + label_updated_time_by: "%{author}이(가) %{age} 전에 변경" + label_updated_time: "%{value} 전에 수정됨" + label_jump_to_a_project: 프로젝트 바로가기 + label_file_plural: 파일 + label_changeset_plural: 변경묶음 + label_default_columns: 기본 컬럼 + label_no_change_option: (수정 안함) + label_bulk_edit_selected_issues: 선택한 일감들을 한꺼번에 수정하기 + label_theme: 테마 + label_default: 기본 + label_search_titles_only: 제목에서만 찾기 + label_user_mail_option_all: "내가 속한 프로젝트로들부터 모든 메일 받기" + label_user_mail_option_selected: "선택한 프로젝트들로부터 모든 메일 받기.." + label_user_mail_no_self_notified: "내가 만든 변경사항들에 대해서는 알림메일을 받지 않습니다." + label_registration_activation_by_email: 메일로 계정을 활성화하기 + label_registration_automatic_activation: 자동 계정 활성화 + label_registration_manual_activation: 수동 계정 활성화 + label_display_per_page: "페이지당 줄수: %{value}" + label_age: 마지막 수정일 + label_change_properties: 속성 변경 + label_general: 일반 + label_more: 제목 및 설명 수정 + label_scm: 형상관리시스템 + label_plugins: 플러그인 + label_ldap_authentication: LDAP 인증 + label_downloads_abbr: D/L + label_optional_description: 부가적인 설명 + label_add_another_file: 다른 파일 추가 + label_preferences: 설정 + label_chronological_order: 시간 순으로 정렬 + label_reverse_chronological_order: 시간 역순으로 정렬 + label_planning: 프로젝트계획 + label_incoming_emails: 수신 메일 + label_generate_key: 키 생성 + label_issue_watchers: 일감관람자 + label_example: 예 + label_display: 표시방식 + label_sort: 정렬 + label_ascending: 오름차순 + label_descending: 내림차순 + label_date_from_to: "%{start}부터 %{end}까지" + label_wiki_content_added: 위키페이지 추가 + label_wiki_content_updated: 위키페이지 수정 + + button_login: 로그인 + button_submit: 확인 + button_save: 저장 + button_check_all: 모두선택 + button_uncheck_all: 선택해제 + button_delete: 삭제 + button_create: 만들기 + button_create_and_continue: 만들고 계속하기 + button_test: 테스트 + button_edit: 편집 + button_add: 추가 + button_change: 변경 + button_apply: 적용 + button_clear: 지우기 + button_lock: 잠금 + button_unlock: 잠금해제 + button_download: 다운로드 + button_list: 목록 + button_view: 보기 + button_move: 이동 + button_back: 뒤로 + button_cancel: 취소 + button_activate: 활성화 + button_sort: 정렬 + button_log_time: 작업시간 기록 + button_rollback: 이 버전으로 되돌리기 + button_watch: 지켜보기 + button_unwatch: 관심끄기 + button_reply: 답글 + button_archive: 잠금보관 + button_unarchive: 잠금보관해제 + button_reset: 초기화 + button_rename: 이름바꾸기 + button_change_password: 비밀번호 바꾸기 + button_copy: 복사 + button_annotate: 이력해설 + button_update: 업데이트 + button_configure: 설정 + button_quote: 댓글달기 + + status_active: 사용중 + status_registered: 등록대기 + status_locked: 잠김 + + text_select_mail_notifications: 알림메일이 필요한 작업을 선택하세요. + text_regexp_info: 예) ^[A-Z0-9]+$ + text_min_max_length_info: 0 는 제한이 없음을 의미함 + text_project_destroy_confirmation: 이 프로젝트를 삭제하고 모든 데이터를 지우시겠습니까? + text_subprojects_destroy_warning: "하위 프로젝트(%{value})이(가) 자동으로 지워질 것입니다." + text_workflow_edit: 업무흐름을 수정하려면 역할과 일감 유형을 선택하세요. + text_are_you_sure: 계속 진행 하시겠습니까? + text_tip_issue_begin_day: 오늘 시작하는 업무(task) + text_tip_issue_end_day: 오늘 종료하는 업무(task) + text_tip_issue_begin_end_day: 오늘 시작하고 종료하는 업무(task) + text_caracters_maximum: "최대 %{count} 글자 가능" + text_caracters_minimum: "최소한 %{count} 글자 이상이어야 합니다." + text_length_between: "%{min} 에서 %{max} 글자" + text_tracker_no_workflow: 이 일감 유형에는 업무흐름이 정의되지 않았습니다. + text_unallowed_characters: 허용되지 않는 문자열 + text_comma_separated: "구분자','를 이용해서 여러 개의 값을 입력할 수 있습니다." + text_issues_ref_in_commit_messages: 커밋 메시지에서 일감을 참조하거나 해결하기 + text_issue_added: "%{author}이(가) 일감 %{id}을(를) 보고하였습니다." + text_issue_updated: "%{author}이(가) 일감 %{id}을(를) 수정하였습니다." + text_wiki_destroy_confirmation: 이 위키와 모든 내용을 지우시겠습니까? + text_issue_category_destroy_question: "일부 일감들(%{count}개)이 이 범주에 지정되어 있습니다. 어떻게 하시겠습니까?" + text_issue_category_destroy_assignments: 범주 지정 지우기 + text_issue_category_reassign_to: 일감을 이 범주에 다시 지정하기 + text_user_mail_option: "선택하지 않은 프로젝트에서도, 지켜보는 중이거나 속해있는 사항(일감를 발행했거나 할당된 경우)이 있으면 알림메일을 받게 됩니다." + text_no_configuration_data: "역할, 일감 유형, 일감 상태들과 업무흐름이 아직 설정되지 않았습니다.\n기본 설정을 읽어들이는 것을 권장합니다. 읽어들인 후에 수정할 수 있습니다." + text_load_default_configuration: 기본 설정을 읽어들이기 + text_status_changed_by_changeset: "변경묶음 %{value}에 의하여 변경됨" + text_issues_destroy_confirmation: '선택한 일감를 정말로 삭제하시겠습니까?' + text_select_project_modules: '이 프로젝트에서 활성화시킬 모듈을 선택하세요:' + text_default_administrator_account_changed: 기본 관리자 계정이 변경 + text_file_repository_writable: 파일 저장소 쓰기 가능 + text_plugin_assets_writable: 플러그인 전용 디렉토리가 쓰기 가능 + text_rmagick_available: RMagick 사용 가능 (선택적) + text_destroy_time_entries_question: 삭제하려는 일감에 %{hours} 시간이 보고되어 있습니다. 어떻게 하시겠습니까? + text_destroy_time_entries: 보고된 시간을 삭제하기 + text_assign_time_entries_to_project: 보고된 시간을 프로젝트에 할당하기 + text_reassign_time_entries: '이 알림에 보고된 시간을 재할당하기:' + text_user_wrote: "%{value}의 덧글:" + text_enumeration_category_reassign_to: '새로운 값을 설정:' + text_enumeration_destroy_question: "%{count} 개의 일감이 이 값을 사용하고 있습니다." + text_email_delivery_not_configured: "이메일 전달이 설정되지 않았습니다. 그래서 알림이 비활성화되었습니다.\n SMTP서버를 config/configuration.yml에서 설정하고 어플리케이션을 다시 시작하십시오. 그러면 동작합니다." + text_repository_usernames_mapping: "저장소 로그에서 발견된 각 사용자에 레드마인 사용자를 업데이트할때 선택합니다.\n레드마인과 저장소의 이름이나 이메일이 같은 사용자가 자동으로 연결됩니다." + text_diff_truncated: '... 이 차이점은 표시할 수 있는 최대 줄수를 초과해서 이 차이점은 잘렸습니다.' + text_custom_field_possible_values_info: '각 값 당 한 줄' + text_wiki_page_destroy_question: 이 페이지는 %{descendants} 개의 하위 페이지와 관련 내용이 있습니다. 이 내용을 어떻게 하시겠습니까? + text_wiki_page_nullify_children: 하위 페이지를 최상위 페이지 아래로 지정 + text_wiki_page_destroy_children: 모든 하위 페이지와 관련 내용을 삭제 + text_wiki_page_reassign_children: 하위 페이지를 이 페이지 아래로 지정 + + default_role_manager: 관리자 + default_role_developer: 개발자 + default_role_reporter: 보고자 + default_tracker_bug: 결함 + default_tracker_feature: 새기능 + default_tracker_support: 지원 + default_issue_status_new: 신규 + default_issue_status_in_progress: 진행 + default_issue_status_resolved: 해결 + default_issue_status_feedback: 의견 + default_issue_status_closed: 완료 + default_issue_status_rejected: 거절 + default_doc_category_user: 사용자 문서 + default_doc_category_tech: 기술 문서 + default_priority_low: 낮음 + default_priority_normal: 보통 + default_priority_high: 높음 + default_priority_urgent: 긴급 + default_priority_immediate: 즉시 + default_activity_design: 설계 + default_activity_development: 개발 + + enumeration_issue_priorities: 일감 우선순위 + enumeration_doc_categories: 문서 범주 + enumeration_activities: 작업분류(시간추적) + + field_issue_to: 관련 일감 + label_view_all_revisions: 모든 개정판 표시 + label_tag: 태그(Tag) + label_branch: 브랜치(Branch) + error_no_tracker_in_project: 사용할 수 있도록 설정된 일감 유형이 없습니다. 프로젝트 설정을 확인하십시오. + error_no_default_issue_status: '기본 상태가 정해져 있지 않습니다. 설정을 확인하십시오. (주 메뉴의 "관리" -> "일감 상태")' + text_journal_changed: "%{label}을(를) %{old}에서 %{new}(으)로 변경되었습니다." + text_journal_set_to: "%{label}을(를) %{value}(으)로 지정되었습니다." + text_journal_deleted: "%{label} 값이 지워졌습니다. (%{old})" + label_group_plural: 그룹 + label_group: 그룹 + label_group_new: 새 그룹 + label_time_entry_plural: 작업시간 + text_journal_added: "%{label}에 %{value}이(가) 추가되었습니다." + field_active: 사용중 + enumeration_system_activity: 시스템 작업 + permission_delete_issue_watchers: 일감관람자 지우기 + version_status_closed: 닫힘 + version_status_locked: 잠김 + version_status_open: 진행 + error_can_not_reopen_issue_on_closed_version: 닫힌 버전에 할당된 일감은 다시 재발생시킬 수 없습니다. + label_user_anonymous: 이름없음 + button_move_and_follow: 이동하고 따라가기 + setting_default_projects_modules: 새 프로젝트에 기본적으로 활성화될 모듈 + setting_gravatar_default: 기본 그라바타 이미지 + field_sharing: 공유 + label_version_sharing_hierarchy: 상위 및 하위 프로젝트 + label_version_sharing_system: 모든 프로젝트 + label_version_sharing_descendants: 하위 프로젝트 + label_version_sharing_tree: 최상위 및 모든 하위 프로젝트 + label_version_sharing_none: 공유없음 + error_can_not_archive_project: 이 프로젝트를 잠금보관할 수 없습니다. + button_duplicate: 복제 + button_copy_and_follow: 복사하고 따라가기 + label_copy_source: 원본 + setting_issue_done_ratio: 일감의 진척도 계산방법 + setting_issue_done_ratio_issue_status: 일감 상태를 사용하기 + error_issue_done_ratios_not_updated: 일감 진척도가 수정되지 않았습니다. + error_workflow_copy_target: 대상 일감의 유형과 역할을 선택하세요. + setting_issue_done_ratio_issue_field: 일감 수정에서 진척도 입력하기 + label_copy_same_as_target: 대상과 같음. + label_copy_target: 대상 + notice_issue_done_ratios_updated: 일감 진척도가 수정되었습니다. + error_workflow_copy_source: 원본 일감의 유형이나 역할을 선택하세요. + label_update_issue_done_ratios: 모든 일감 진척도 갱신하기 + setting_start_of_week: 달력 시작 요일 + permission_view_issues: 일감 보기 + label_display_used_statuses_only: 이 일감 유형에서 사용되는 상태만 보여주기 + label_revision_id: 개정판 %{value} + label_api_access_key: API 접근키 + label_api_access_key_created_on: API 접근키가 %{value} 전에 생성되었습니다. + label_feeds_access_key: RSS 접근키 + notice_api_access_key_reseted: API 접근키가 초기화되었습니다. + setting_rest_api_enabled: REST 웹서비스 활성화 + label_missing_api_access_key: API 접근키가 없습니다. + label_missing_feeds_access_key: RSS 접근키가 없습니다. + button_show: 보기 + text_line_separated: 여러 값이 허용됨(값 마다 한 줄씩) + setting_mail_handler_body_delimiters: 메일 본문 구분자 + permission_add_subprojects: 하위 프로젝트 만들기 + label_subproject_new: 새 하위 프로젝트 + text_own_membership_delete_confirmation: |- + 권한들 일부 또는 전부를 막 삭제하려고 하고 있습니다. 그렇게 되면 이 프로젝트를 더이상 수정할 수 없게 됩니다. + 계속하시겠습니까? + label_close_versions: 완료된 버전 닫기 + label_board_sticky: 붙박이 + label_board_locked: 잠금 + permission_export_wiki_pages: 위키 페이지 내보내기 + setting_cache_formatted_text: 형식을 가진 텍스트 빠른 임시 기억 + permission_manage_project_activities: 프로젝트 작업내역 관리 + error_unable_delete_issue_status: 일감 상태를 지울 수 없습니다. + label_profile: 사용자정보 + permission_manage_subtasks: 하위 일감 관리 + field_parent_issue: 상위 일감 + label_subtask_plural: 하위 일감 + label_project_copy_notifications: 프로젝트 복사 중에 이메일 알림 보내기 + error_can_not_delete_custom_field: 사용자 정의 필드를 삭제할 수 없습니다. + error_unable_to_connect: 연결할 수 없습니다((%{value}) + error_can_not_remove_role: 이 역할은 현재 사용 중이이서 삭제할 수 없습니다. + error_can_not_delete_tracker: 이 유형의 일감들이 있어서 삭제할 수 없습니다. + field_principal: 신원 + label_my_page_block: 내 페이지 출력화면 + notice_failed_to_save_members: "%{errors}:구성원을 저장 중 실패하였습니다" + text_zoom_out: 더 작게 + text_zoom_in: 더 크게 + notice_unable_delete_time_entry: 시간 기록 항목을 삭제할 수 없습니다. + label_overall_spent_time: 총 소요시간 + field_time_entries: 기록된 시간 + project_module_gantt: Gantt 챠트 + project_module_calendar: 달력 + button_edit_associated_wikipage: "연관된 위키 페이지 %{page_title} 수정" + field_text: 텍스트 영역 + label_user_mail_option_only_owner: 내가 저자인 사항만 + setting_default_notification_option: 기본 알림 옵션 + label_user_mail_option_only_my_events: 내가 지켜보거나 속해있는 사항만 + label_user_mail_option_only_assigned: 내에게 할당된 사항만 + label_user_mail_option_none: 알림 없음 + field_member_of_group: 할당된 사람의 그룹 + field_assigned_to_role: 할당된 사람의 역할 + notice_not_authorized_archived_project: 접근하려는 프로젝트는 이미 잠금보관되어 있습니다. + label_principal_search: "사용자 및 그룹 찾기:" + label_user_search: "사용자 찾기::" + field_visible: 보이기 + setting_emails_header: 이메일 헤더 + setting_commit_logtime_activity_id: 기록된 시간에 적용할 작업분류 + text_time_logged_by_changeset: "변경묶음 %{value}에서 적용되었습니다." + setting_commit_logtime_enabled: 커밋 시점에 작업 시간 기록 활성화 + notice_gantt_chart_truncated: "표시할 수 있는 최대 항목수(%{max})를 초과하여 차트가 잘렸습니다." + setting_gantt_items_limit: "Gantt 차트에 표시되는 최대 항목수" + field_warn_on_leaving_unsaved: "저장하지 않은 페이지를 빠져나갈 때 나에게 알림" + text_warn_on_leaving_unsaved: "현재 페이지는 저장되지 않은 문자가 있습니다. 이 페이지를 빠져나가면 내용을 잃을것입니다." + label_my_queries: "내 검색 양식" + text_journal_changed_no_detail: "%{label}이 변경되었습니다." + label_news_comment_added: "뉴스에 설명이 추가되었습니다." + button_expand_all: "모두 확장" + button_collapse_all: "모두 축소" + label_additional_workflow_transitions_for_assignee: "사용자가 작업자일 때 허용되는 추가 상태" + label_additional_workflow_transitions_for_author: "사용자가 저자일 때 허용되는 추가 상태" + label_bulk_edit_selected_time_entries: "선택된 소요 시간 대량 편집" + text_time_entries_destroy_confirmation: "선택한 소요 시간 항목을 삭제하시겠습니까?" + label_role_anonymous: Anonymous + label_role_non_member: Non member + + label_issue_note_added: "덧글이 추가되었습니다." + label_issue_status_updated: "상태가 변경되었습니다." + label_issue_priority_updated: "우선 순위가 변경되었습니다." + label_issues_visibility_own: "일감을 생성하거나 맡은 사용자" + field_issues_visibility: "일감 보임" + label_issues_visibility_all: "모든 일감" + permission_set_own_issues_private: "자신의 일감을 공개나 비공개로 설정" + field_is_private: "비공개" + permission_set_issues_private: "일감을 공개나 비공개로 설정" + label_issues_visibility_public: "비공개 일감 제외" + text_issues_destroy_descendants_confirmation: "%{count} 개의 하위 일감을 삭제할 것입니다." + field_commit_logs_encoding: "커밋(commit) 기록 인코딩" + field_scm_path_encoding: "경로 인코딩" + text_scm_path_encoding_note: "기본: UTF-8" + field_path_to_repository: "저장소 경로" + field_root_directory: "루트 경로" + field_cvs_module: "모듈" + field_cvsroot: "CVS 루트" + text_mercurial_repository_note: "로컬 저장소 (예: /hgrepo, c:\\hgrepo)" + text_scm_command: "명령" + text_scm_command_version: "버전" + label_git_report_last_commit: "파일이나 폴더의 마지막 커밋(commit)을 보고" + text_scm_config: "SCM 명령을 config/configuration.yml에서 수정할 수 있습니다. 수정후에는 재시작하십시오." + text_scm_command_not_available: "SCM 명령을 사용할 수 없습니다. 관리 페이지의 설정을 검사하십시오." + notice_issue_successful_create: "%{id} 일감이 생성되었습니다." + label_between: "사이" + setting_issue_group_assignment: "그룹에 일감 할당 허용" + label_diff: "비교(diff)" + text_git_repository_note: "로컬의 bare 저장소 (예: /gitrepo, c:\\gitrepo)" + description_query_sort_criteria_direction: "정렬 방향" + description_project_scope: "검색 범위" + description_filter: "검색 조건" + description_user_mail_notification: "메일 알림 설정" + description_date_from: "시작 날짜 입력" + description_message_content: "메세지 내용" + description_available_columns: "가능한 컬럼" + description_date_range_interval: "시작과 끝 날짜로 범위를 선택하십시오." + description_issue_category_reassign: "일감 범주를 선택하십시오." + description_search: "검색항목" + description_notes: "덧글" + description_date_range_list: "목록에서 범위를 선택 하십시오." + description_choose_project: "프로젝트" + description_date_to: "종료 날짜 입력" + description_query_sort_criteria_attribute: "정렬 속성" + description_wiki_subpages_reassign: "새로운 상위 페이지를 선택하십시오." + description_selected_columns: "선택된 컬럼" + label_parent_revision: "상위" + label_child_revision: "하위" + error_scm_annotate_big_text_file: "최대 텍스트 파일 크기를 초과 하면 항목은 이력화 될 수 없습니다." + setting_default_issue_start_date_to_creation_date: "새로운 일감의 시작 날짜로 오늘 날짜 사용" + button_edit_section: "이 부분 수정" + setting_repositories_encodings: "첨부파일이나 저장소 인코딩" + description_all_columns: "모든 컬럼" + button_export: "내보내기" + label_export_options: "내보내기 옵션: %{export_format}" + error_attachment_too_big: "이 파일은 제한된 크기(%{max_size})를 초과하였기 때문에 업로드 할 수 없습니다." + + notice_failed_to_save_time_entries: "%{total} 개의 시간입력중 다음 %{count} 개의 저장에 실패했습니다:: %{ids}." + label_x_issues: + zero: 0 일감 + one: 1 일감 + other: "%{count} 일감" + label_repository_new: 저장소 추가 + field_repository_is_default: 주 저장소 + label_copy_attachments: 첨부파일 복사 + label_item_position: "%{position}/%{count}" + label_completed_versions: 완료 버전 + text_project_identifier_info: "소문자(a-z),숫자,대쉬(-)와 밑줄(_)만 가능합니다.
    식별자는 저장후에는 수정할 수 없습니다." + field_multiple: 복수선택가능 + setting_commit_cross_project_ref: 다른 프로젝트의 일감 참조 및 수정 허용 + text_issue_conflict_resolution_add_notes: 변경내용은 취소하고 덧글만 추가 + text_issue_conflict_resolution_overwrite: 변경내용 강제적용 (이전 덧글을 제외하고 덮어 씁니다) + notice_issue_update_conflict: 일감이 수정되는 동안 다른 사용자에 의해서 변경되었습니다. + text_issue_conflict_resolution_cancel: "변경내용을 되돌리고 다시 표시 %{link}" + permission_manage_related_issues: 연결된 일감 관리 + field_auth_source_ldap_filter: LDAP 필터 + label_search_for_watchers: 추가할 일감관람자 검색 + notice_account_deleted: 당신의 계정이 완전히 삭제되었습니다. + setting_unsubscribe: 사용자들이 자신의 계정을 삭제토록 허용 + button_delete_my_account: 나의 계정 삭제 + text_account_destroy_confirmation: |- + 계속하시겠습니까? + 계정이 삭제되면 복구할 수 없습니다. + error_session_expired: 당신의 세션이 만료되었습니다. 다시 로그인하세요. + text_session_expiration_settings: "경고: 이 설정을 바꾸면 당신을 포함하여 현재의 세션들을 만료시킬 수 있습니다." + setting_session_lifetime: 세션 최대 시간 + setting_session_timeout: 세션 비활성화 타임아웃 + label_session_expiration: 세션 만료 + permission_close_project: 프로젝트를 닫거나 다시 열기 + label_show_closed_projects: 닫힌 프로젝트 보기 + button_close: 닫기 + button_reopen: 다시 열기 + project_status_active: 사용중 + project_status_closed: 닫힘 + project_status_archived: 잠금보관 + text_project_closed: 이 프로젝트는 닫혀 있으며 읽기 전용입니다. + notice_user_successful_create: 사용자 %{id} 이(가) 생성되었습니다. + field_core_fields: 표준 항목들 + field_timeout: 타임아웃 (초) + setting_thumbnails_enabled: 첨부파일의 썸네일을 보여줌 + setting_thumbnails_size: 썸네일 크기 (픽셀) + label_status_transitions: 일감 상태 변경 + label_fields_permissions: 항목 편집 권한 + label_readonly: 읽기 전용 + label_required: 필수 + text_repository_identifier_info: "소문자(a-z),숫자,대쉬(-)와 밑줄(_)만 가능합니다.
    식별자는 저장후에는 수정할 수 없습니다." + field_board_parent: Parent forum + label_attribute_of_project: "프로젝트의 %{name}" + label_attribute_of_author: "저자의 %{name}" + label_attribute_of_assigned_to: "담당자의 %{name}" + label_attribute_of_fixed_version: "목표버전의 %{name}" + label_copy_subtasks: 하위 일감들을 복사 + label_copied_to: "다음 일감으로 복사됨:" + label_copied_from: "다음 일감으로부터 복사됨:" + label_any_issues_in_project: 다음 프로젝트에 속한 아무 일감 + label_any_issues_not_in_project: 다음 프로젝트에 속하지 않은 아무 일감 + field_private_notes: 비공개 덧글 + permission_view_private_notes: 비공개 덧글 보기 + permission_set_notes_private: 덧글을 비공개로 설정 + label_no_issues_in_project: 다음 프로젝트의 일감 제외 + label_any: 모두 + label_last_n_weeks: 최근 %{count} 주 + setting_cross_project_subtasks: 다른 프로젝트의 일감을 상위 일감으로 지정하는 것을 허용 + label_cross_project_descendants: 하위 프로젝트 + label_cross_project_tree: 최상위 및 모든 하위 프로젝트 + label_cross_project_hierarchy: 상위 및 하위 프로젝트 + label_cross_project_system: 모든 프로젝트 + button_hide: 숨기기 + setting_non_working_week_days: 비근무일 (non-working days) + label_in_the_next_days: 다음 + label_in_the_past_days: 지난 + label_attribute_of_user: "사용자의 %{name}" + text_turning_multiple_off: 복수선택을 비활성화하면, 하나의 값을 제외한 나머지 값들이 지워집니다. + label_attribute_of_issue: "일감의 %{name}" + permission_add_documents: 문서 추가 + permission_edit_documents: 문서 편집 + permission_delete_documents: 문서 삭제 + label_gantt_progress_line: Progress line + setting_jsonp_enabled: JSONP 허용 + field_inherit_members: 상위 프로젝트로부터 구성원을 상속 + field_closed_on: 완료일 + setting_default_projects_tracker_ids: 새 프로젝트에 기본적으로 추가할 일감 유형 + label_total_time: 합계 diff --git a/config/locales/lt.yml b/config/locales/lt.yml new file mode 100644 index 00000000..1b24ccf9 --- /dev/null +++ b/config/locales/lt.yml @@ -0,0 +1,1149 @@ +# Lithuanian translations for Ruby on Rails +# by Laurynas Butkus (laurynas.butkus@gmail.com) +# Redmine translation by Gediminas Muižis gediminas.muizis@gmail.com +# and Sergej Jegorov sergej.jegorov@gmail.com +# and Gytis Gurklys gytis.gurklys@gmail.com +# and Andrius Kriučkovas andrius.kriuckovas@gmail.com + +lt: + direction: ltr + date: + formats: + # Use the strftime parameters for formats. + # When no format has been given, it uses default. + # You can provide other formats here if you like! + default: "%Y-%m-%d" + short: "%b %d" + long: "%B %d, %Y" + + day_names: [sekmadienis, pirmadienis, antradienis, trečiadienis, ketvirtadienis, penktadienis, šeštadienis] +# standalone_day_names: [Sekmadienis, Pirmadienis, Antradienis, Trečiadienis, Ketvirtadienis, Penktadienis, Šeštadienis] + abbr_day_names: [Sek, Pir, Ant, Tre, Ket, Pen, Šeš] + + # Don't forget the nil at the beginning; there's no such thing as a 0th month + month_names: [~, sausio, vasario, kovo, balandžio, gegužės, birželio, liepos, rugpjūčio, rugsėjo, spalio, lapkričio, gruodžio] + abbr_month_names: [~, Sau, Vas, Kov, Bal, Geg, Bir, Lie, Rgp, Rgs, Spa, Lap, Grd] + # Used in date_select and datime_select. + order: + - :year + - :month + - :day + + time: + formats: + default: "%a, %d %b %Y %H:%M:%S %z" + time: "%H:%M" + short: "%d %b %H:%M" + long: "%B %d, %Y %H:%M" + am: "ryto" + pm: "vakaro" + + datetime: + distance_in_words: + half_a_minute: "pusė minutės" + less_than_x_seconds: + one: "mažiau nei %{count} sekundę" + few: "mažiau nei %{count} sekundes" + many: "mažiau nei %{count} sekundžių" + other: "mažiau nei %{count} sekundžių" + x_seconds: + one: "%{count} sekundė" + few: "%{count} sekundės" + many: "%{count} sekundžių" + other: "%{count} sekundžių" + less_than_x_minutes: + one: "mažiau nei minutę" + other: "mažiau nei %{count} minutes(čių)" + x_minutes: + one: "1 minutę" + other: "%{count} minutes(čių)" + about_x_hours: + one: "apie 1 valandą" + other: "apie %{count} valandas(ų)" + x_hours: + one: "1 valandą" + other: "%{count} valandas(ų)" + x_days: + one: "1 dieną" + other: "%{count} dienas(ų)" + about_x_months: + one: "apie 1 mėnuo" + other: "apie %{count} mėn." + x_months: + one: "1 mėnuo" + other: "%{count} mėn." + about_x_years: + one: "apie 1 metus" + other: "apie %{count} metų" + over_x_years: + one: "virš 1 metų" + other: "virš %{count} metų" + almost_x_years: + one: "beveik 1 metus" + other: "beveik %{count} metai(us)" + prompts: + year: "Metai" + month: "Mėnuo" + day: "Diena" + hour: "Valanda" + minute: "Minutė" + second: "Sekundės" + + number: + format: + separator: "," + delimiter: " " + precision: 3 + + currency: + format: + format: "%n %u" + unit: "Lt" + separator: "," + delimiter: " " + precision: 2 + + percentage: + format: + delimiter: "" + + precision: + format: + delimiter: "" + + human: + format: + delimiter: "" + precision: 3 + storage_units: + # Storage units output formatting. + # %u is the storage unit, %n is the number (default: 2 MB) + format: "%n %u" + units: + byte: + one: "baitas" + few: "baitų(ai)" + many: "baitų(ai)" + other: "baitų(ai)" + kb: "KB" + mb: "MB" + gb: "GB" + tb: "TB" + +# Used in array.to_sentence. + support: + array: + # Rails 2.2 + sentence_connector: "ir" + skip_last_comma: true + # Rails 2.3 + words_connector: ", " + two_words_connector: " ir " + last_word_connector: " ir " + + activerecord: + errors: + template: + header: + one: "Išsaugant objektą %{model} rasta %{count} klaida" + few: "Išsaugant objektą %{model} rasta %{count} klaidų" + many: "Išsaugant objektą %{model} rastos %{count} klaidos" + other: "Išsaugant objektą %{model} rastos %{count} klaidos" + body: "Šiuose laukuose yra klaidų:" + + messages: + inclusion: "nenumatyta reikšmė" + exclusion: "užimtas" + invalid: "neteisingas" + confirmation: "neteisingai pakartotas" + accepted: "turi būti patvirtintas" + empty: "negali būti tuščias" + blank: "negali būti tuščias" + too_long: + one: "per ilgas (daugiausiai %{count} simbolius)" + few: "per ilgas (daugiausiai %{count} simboliu)" + many: "per ilgas (daugiausiai %{count} simboliu)" + other: "per ilgas (daugiausiai %{count} simboliai)" + too_short: + one: "per trumpas (mažiausiai %{count} simbolius)" + few: "per trumpas (mažiausiai %{count} simboliu)" + many: "per trumpas (mažiausiai %{count} simboliu)" + other: "per trumpas (mažiausiai %{count} simboliai)" + wrong_length: + one: "neteisingo ilgio (turi būti lygiai %{count} simbolius)" + few: "neteisingo ilgio (turi būti lygiai %{count} simboliu)" + many: "neteisingo ilgio (turi būti lygiai %{count} simboliu)" + other: "neteisingo ilgio (turi būti lygiai %{count} simboliai)" + taken: "jau užimtas" + not_a_number: "ne skaičius" + not_a_date: "is not a valid date" + greater_than: "turi būti didesnis už %{count}" + greater_than_or_equal_to: "turi būti didesnis arba lygus %{count}" + equal_to: "turi būti lygus %{count}" + less_than: "turi būti mažesnis už %{count}" + less_than_or_equal_to: "turi būti mažesnis arba lygus %{count}" + odd: "turi būti nelyginis" + even: "turi būti lyginis" + greater_than_start_date: "turi būti didesnė negu pradžios data" + not_same_project: "nepriklauso tam pačiam projektui" + circular_dependency: "Šis ryšys sukurtų ciklinę priklausomybę" + cant_link_an_issue_with_a_descendant: "Darbas negali būti susietas su viena iš savo darbo dalių" + + actionview_instancetag_blank_option: Prašom parinkti + + general_text_No: 'Ne' + general_text_Yes: 'Taip' + general_text_no: 'ne' + general_text_yes: 'taip' + general_lang_name: 'Lithuanian (lietuvių)' + general_csv_separator: ',' + general_csv_decimal_separator: '.' + general_csv_encoding: UTF-8 + general_pdf_encoding: UTF-8 + general_first_day_of_week: '1' + + notice_account_updated: Paskyra buvo sėkmingai atnaujinta. + notice_account_invalid_creditentials: Negaliojantis vartotojo vardas ar slaptažodis + notice_account_password_updated: Slaptažodis buvo sėkmingai atnaujintas. + notice_account_wrong_password: Neteisingas slaptažodis + notice_account_register_done: Paskyra buvo sėkmingai sukurta. Kad aktyvintumėte savo paskyrą, paspauskite nuorodą, kuri jums buvo siųsta elektroniniu paštu. + notice_account_unknown_email: Nežinomas vartotojas. + notice_can_t_change_password: Šis pranešimas naudoja išorinį autentiškumo nustatymo šaltinį. Neįmanoma pakeisti slaptažodį. + notice_account_lost_email_sent: Į Jūsų paštą išsiųstas laiškas su naujo slaptažodžio pasirinkimo instrukcija. + notice_account_activated: Jūsų paskyra aktyvuota. Galite prisijungti. + notice_successful_create: Sėkmingas sukūrimas. + notice_successful_update: Sėkmingas atnaujinimas. + notice_successful_delete: Sėkmingas panaikinimas. + notice_successful_connection: Sėkmingas susijungimas. + notice_file_not_found: Puslapis, į kurį ketinate įeiti, neegzistuoja arba yra pašalintas. + notice_locking_conflict: Duomenys atnaujinti kito vartotojo. + notice_not_authorized: Jūs neturite teisių gauti prieigą prie šio puslapio. + notice_not_authorized_archived_project: Projektas, kurį bandote atidaryti, buvo suarchyvuotas. + notice_email_sent: "Laiškas išsiųstas %{value}" + notice_email_error: "Laiško siuntimo metu įvyko klaida (%{value})" + notice_feeds_access_key_reseted: Jūsų RSS raktas buvo atnaujintas. + notice_api_access_key_reseted: Jūsų API prieigos raktas buvo atnaujintas. + notice_failed_to_save_issues: "Nepavyko išsaugoti %{count} problemos(ų) iš %{total} pasirinkto: %{ids}." + notice_failed_to_save_members: "Nepavyko išsaugoti nario(ių): %{errors}." + notice_no_issue_selected: "Nepasirinkta nė viena problema! Prašom pažymėti problemą, kurią norite redaguoti." + notice_account_pending: "Jūsų paskyra buvo sukurta ir dabar laukiama administratoriaus patvirtinimo." + notice_default_data_loaded: Numatytoji konfiguracija sėkmingai užkrauta. + notice_unable_delete_version: Neįmanoma panaikinti versiją. + notice_unable_delete_time_entry: Neįmano ištrinti laiko žurnalo įrašą. + notice_issue_done_ratios_updated: Problemos baigtumo rodikliai atnaujinti. + notice_gantt_chart_truncated: Grafikas buvo sutrumpintas, kadangi jis viršija maksimalų (%{max}) leistinų atvaizduoti elementų kiekį + notice_issue_successful_create: Darbas %{id} sukurtas. + + error_can_t_load_default_data: "Numatytoji konfiguracija negali būti užkrauta: %{value}" + error_scm_not_found: "Duomenys ir/ar pakeitimai saugykloje(repozitorojoje) neegzistuoja." + error_scm_command_failed: "Įvyko klaida jungiantis prie saugyklos: %{value}" + error_scm_annotate: "Įrašas neegzistuoja arba negalima jo atvaizduoti." + error_scm_annotate_big_text_file: "Įrašo negalima atvaizduoti, nes jis viršija maksimalų tekstinio failo dydį." + error_issue_not_found_in_project: 'Darbas nerastas arba nesurištas su šiuo projektu' + error_no_tracker_in_project: 'Joks pėdsekys nesusietas su šiuo projektu. Prašom patikrinti Projekto nustatymus.' + error_no_default_issue_status: Nenustatyta numatytoji darbų būsena. Prašome patikrinti konfigūravimą ("Administravimas -> Darbų būsenos"). + error_can_not_delete_custom_field: Negalima ištrinti kliento lauko + error_can_not_delete_tracker: "Šis pėdsekys turi įrašus ir todėl negali būti ištrintas." + error_can_not_remove_role: "Ši rolė yra naudojama ir negali būti ištrinta." + error_can_not_reopen_issue_on_closed_version: Uždarytai versijai priskirtas darbas negali būti atnaujintas. + error_can_not_archive_project: Šio projekto negalima suarchyvuoti + error_issue_done_ratios_not_updated: "Įrašo baigtumo rodikliai nebuvo atnaujinti. " + error_workflow_copy_source: 'Prašome pasirinkti pirminį šaltinio seklį arba rolę' + error_workflow_copy_target: 'Prašome pasirinkti galutinį paskirties seklį(-ius) arba rolę(-s)' + error_unable_delete_issue_status: 'Negalima ištrinti darbo statuso' + error_unable_to_connect: Negalima prisijungti (%{value}) + error_attachment_too_big: "Ši byla negali būti įkelta, nes viršija maksimalią (%{max_size}) leistiną bylos apimtį" + error_attachment_too_big: "This file cannot be uploaded because it exceeds the maximum allowed file size (%{max_size})" + warning_attachments_not_saved: "%{count} byla(ų) negali būti išsaugota." + + mail_subject_lost_password: "Jūsų %{value} slaptažodis" + mail_body_lost_password: 'Norėdami pakeisti slaptažodį, spauskite nuorodą:' + mail_subject_register: "Jūsų %{value} paskyros aktyvavimas" + mail_body_register: 'Norėdami aktyvuoti paskyrą, spauskite nuorodą:' + mail_body_account_information_external: "Jūs galite naudoti Jūsų %{value} paskyrą, norėdami prisijungti." + mail_body_account_information: Informacija apie Jūsų paskyrą + mail_subject_account_activation_request: "%{value} paskyros aktyvavimo prašymas" + mail_body_account_activation_request: "Užsiregistravo naujas vartotojas (%{value}). Jo paskyra laukia jūsų patvirtinimo:" + mail_subject_reminder: "%{count} jums priskirti darbai per artimiausias %{days} dienų(as)" + mail_body_reminder: "%{count} darbas(ai), kurie yra jums priskirti, baigiasi per artimiausias %{days} dienų(as):" + mail_subject_wiki_content_added: "'%{id}' pridėtas wiki puslapis" + mail_body_wiki_content_added: "'%{id}' wiki puslapį pridėjo %{author}." + mail_subject_wiki_content_updated: "'%{id}' atnaujintas wiki puslapis" + mail_body_wiki_content_updated: "'%{id}' wiki puslapį atnaujino %{author}." + + + field_name: Pavadinimas + field_description: Aprašas + field_summary: Santrauka + field_is_required: Reikalaujama + field_firstname: Vardas + field_lastname: Pavardė + field_mail: El. paštas + field_filename: Failas + field_filesize: Dydis + field_downloads: Atsiuntimai + field_author: Autorius + field_created_on: Sukurta + field_updated_on: Atnaujintas(a) + field_field_format: Formatas + field_is_for_all: Visiems projektams + field_possible_values: Galimos reikšmės + field_regexp: Pastovi išraiška + field_min_length: Minimalus ilgis + field_max_length: Maksimalus ilgis + field_value: Vertė + field_category: Kategorija + field_title: Pavadinimas + field_project: Projektas + field_issue: Darbas + field_status: Būsena + field_notes: Pastabos + field_is_closed: Darbas uždarytas + field_is_default: Numatytoji vertė + field_tracker: Pėdsekys + field_subject: Tema + field_due_date: Užbaigimo data + field_assigned_to: Paskirtas + field_priority: Prioritetas + field_fixed_version: Tikslinė versija + field_user: Vartotojas + field_principal: Vardas + field_role: Vaidmuo + field_homepage: Pagrindinis puslapis + field_is_public: Viešas + field_parent: Priklauso projektui + field_is_in_roadmap: Darbai rodomi veiklos grafike + field_login: Registracijos vardas + field_mail_notification: Elektroninio pašto pranešimai + field_admin: Administratorius + field_last_login_on: Paskutinis prisijungimas + field_language: Kalba + field_effective_date: Data + field_password: Slaptažodis + field_new_password: Naujas slaptažodis + field_password_confirmation: Patvirtinimas + field_version: Versija + field_type: Tipas + field_host: Pagrindinis kompiuteris + field_port: Prievadas + field_account: Paskyra + field_base_dn: Bazinis skiriamasis vardas (base DN) + field_attr_login: Registracijos vardo požymis (login) + field_attr_firstname: Vardo požymis + field_attr_lastname: Pavardės požymis + field_attr_mail: Elektroninio pašto požymis + field_onthefly: Automatinis vartotojų registravimas + field_start_date: Pradėti + field_done_ratio: "% atlikta" + field_auth_source: Autentiškumo nustatymo būdas + field_hide_mail: Slėpti mano elektroninio pašto adresą + field_comments: Komentaras + field_url: URL + field_start_page: Pradžios puslapis + field_subproject: Subprojektas + field_hours: valandos + field_activity: Veikla + field_spent_on: Data + field_identifier: Identifikuotojas + field_is_filter: Panaudotas kaip filtras + field_issue_to: Susijęs darbas + field_delay: Užlaikymas + field_assignable: Darbai gali būti paskirti šiam vaidmeniui + field_redirect_existing_links: Peradresuokite egzistuojančias sąsajas + field_estimated_hours: Numatyta trukmė + field_column_names: Skiltys + field_time_entries: Praleistas laikas + field_time_zone: Laiko juosta + field_searchable: Randamas + field_default_value: Numatytoji vertė + field_comments_sorting: Rodyti komentarus + field_parent_title: Aukštesnio lygio puslapis + field_editable: Redaguojamas + field_watcher: Stebėtojas + field_identity_url: OpenID URL + field_content: Turinys + field_group_by: Sugrupuoti pagal + field_sharing: Dalijimasis + field_parent_issue: Pagrindinė užduotis + field_member_of_group: "Priskirtojo grupė" + field_assigned_to_role: "Priskirtojo rolė" + field_text: Teksto laukas + field_visible: Matomas + field_warn_on_leaving_unsaved: "Įspėti mane, kai paliekamas puslapis su neišsaugotu tekstu" + field_issues_visibility: Darbų matomumas + field_is_private: Privatus + field_commit_logs_encoding: Commit pranešimų koduotė + field_scm_path_encoding: Kelio koduotė + field_path_to_repository: Saugyklos kelias + field_root_directory: Root directorija + field_cvsroot: CVSROOT + field_cvs_module: Modulis + + setting_app_title: Programos pavadinimas + setting_app_subtitle: Programos paantraštė + setting_welcome_text: Pasveikinimas + setting_default_language: Numatytoji kalba + setting_login_required: Reikalingas autentiškumo nustatymas + setting_self_registration: Saviregistracija + setting_attachment_max_size: Priedo maks. dydis + setting_issues_export_limit: Darbų eksportavimo riba + setting_mail_from: Išleidimo elektroninio pašto adresas + setting_bcc_recipients: Akli tikslios kopijos gavėjai (bcc) + setting_plain_text_mail: Tik tekstas (be HTML) + setting_host_name: Pagrindinio kompiuterio vardas + setting_text_formatting: Teksto formatavimas + setting_wiki_compression: Wiki istorijos suspaudimas + setting_feeds_limit: Perdavimo turinio maksimali riba + setting_default_projects_public: Nauji projektai vieši pagal nutylėjimą + setting_autofetch_changesets: Automatinis pakeitimų siuntimas + setting_sys_api_enabled: Įgalinti WS sandėlio valdymui + setting_commit_ref_keywords: Nurodymo reikšminiai žodžiai + setting_commit_fix_keywords: Fiksavimo reikšminiai žodžiai + setting_autologin: Automatinis prisijungimas + setting_date_format: Datos formatas + setting_time_format: Laiko formatas + setting_cross_project_issue_relations: Leisti tarprojektinius darbų ryšius + setting_issue_list_default_columns: Numatytosios skiltys darbų sąraše + setting_repositories_encodings: Pridėtų failų ir saugyklų šifravimas + setting_emails_header: Laiško antraštė + setting_emails_footer: Laiško poraštė + setting_protocol: Protokolas + setting_per_page_options: Įrašų puslapyje nustatymas + setting_user_format: Vartotojo atvaizdavimo formatas + setting_activity_days_default: Atvaizduojamos dienos projekto veikloje + setting_display_subprojects_issues: Pagal nutylėjimą rodyti subprojektų darbus pagrindiniame projekte + setting_enabled_scm: Įgalinti SCM + setting_mail_handler_body_delimiters: "Trumpinti laiškus po vienos iš šių eilučių" + setting_mail_handler_api_enabled: Įgalinti WS įeinantiems laiškams + setting_mail_handler_api_key: API raktas + setting_sequential_project_identifiers: Generuoti nuoseklius projekto identifikatorius + setting_gravatar_enabled: Naudoti Gravatar vartotojo paveiksliukus + setting_gravatar_default: Gravatar paveiksliukas pagal nutylėjimą + setting_diff_max_lines_displayed: Maksimalus rodomas pakeitimų eilučių skaičius + setting_file_max_size_displayed: Maksimalus testinių failų dydis rodomas vienoje eilutėje + setting_repository_log_display_limit: Maksimalus revizijų skaičius rodomas failo loge + setting_openid: Leisti OpenID prisijungimą ir registraciją + setting_password_min_length: Minimalus slaptažodžio ilgis + setting_new_project_user_role_id: Vartotojo vaidmuo, suteikiamas ne administratoriui, kuris sukuria projektą + setting_default_projects_modules: Pagal nutylėjimą naujam projektui priskirti moduliai + setting_issue_done_ratio: DArbo įvykdymo progresą skaičiuoti su + setting_issue_done_ratio_issue_field: Naudoti darbo lauką + setting_issue_done_ratio_issue_status: Naudoti darbo statusą + setting_start_of_week: Savaitės pradžios diena + setting_rest_api_enabled: Įjungti REST web service + setting_cache_formatted_text: Paslėpti formatuotą tekstą + setting_default_notification_option: Numatytosios pranešimų nuostatos + setting_commit_logtime_enabled: Įjungti laiko registravimą + setting_commit_logtime_activity_id: Laiko įrašų veikla + setting_gantt_items_limit: Maksimalus rodmenų skaičius rodomas Gantt'o grafike + setting_issue_group_assignment: Leisti darbo priskirimą grupėms + setting_default_issue_start_date_to_creation_date: Naudoti dabartinę datą kaip naujų darbų pradžios datą + + permission_add_project: Sukurti projektą + permission_add_subprojects: Kurti subprojektus + permission_edit_project: Taisyti projektą + permission_select_project_modules: Parinkti projekto modulius + permission_manage_members: Valdyti narius + permission_manage_project_activities: Valdyti projekto veiklas + permission_manage_versions: Valdyti versijas + permission_manage_categories: Valdyti darbų kategorijas + permission_view_issues: Užduočių peržiūra + permission_add_issues: Sukurti darbus + permission_edit_issues: Redaguoti darbus + permission_manage_issue_relations: Valdyti darbų ryšius + permission_set_issues_private: Nustatyti darbą viešu ar privačiu + permission_set_own_issues_private: Nustatyti savo darbus viešais ar privačiais + permission_add_issue_notes: Sukurti pastabas + permission_edit_issue_notes: Redaguoti pastabas + permission_edit_own_issue_notes: Redaguoti savo pastabas + permission_move_issues: Perkelti darbus + permission_delete_issues: Pašalinti darbus + permission_manage_public_queries: Valdyti viešas užklausas + permission_save_queries: Išsaugoti užklausas + permission_view_gantt: Matyti Gantt grafiką + permission_view_calendar: Matyti kalendorių + permission_view_issue_watchers: Matyti stebėtojų sąrašą + permission_add_issue_watchers: Pridėti stebėtojus + permission_delete_issue_watchers: Pašalinti stebėtojus + permission_log_time: Regsitruoti dirbtą laiką + permission_view_time_entries: Matyti dirbtą laiką + permission_edit_time_entries: Redaguoti laiko įrašus + permission_edit_own_time_entries: Redguoti savo laiko įrašus + permission_manage_news: Valdyti naujienas + permission_comment_news: Komentuoti naujienas + permission_view_documents: Matyti dokumentus + permission_manage_files: Valdyti failus + permission_view_files: Matyti failus + permission_manage_wiki: Valdyti wiki + permission_rename_wiki_pages: Pervadinti wiki puslapius + permission_delete_wiki_pages: Pašalinti wiki puslapius + permission_view_wiki_pages: Matyti wiki + permission_view_wiki_edits: Matyti wiki istoriją + permission_edit_wiki_pages: Redaguoti wiki puslapius + permission_delete_wiki_pages_attachments: Pašalinti priedus + permission_protect_wiki_pages: Apsaugoti wiki puslapius + permission_manage_repository: Valdyti saugyklą + permission_browse_repository: Peržiūrėti saugyklą + permission_view_changesets: Matyti pakeitimus + permission_commit_access: Prieiga prie pakeitimų + permission_manage_boards: Valdyti forumus + permission_view_messages: Matyti pranešimus + permission_add_messages: Skelbti pranešimus + permission_edit_messages: Redaguoti pranešimus + permission_edit_own_messages: Redaguoti savo pranešimus + permission_delete_messages: Pašalinti pranešimus + permission_delete_own_messages: Pašalinti savo pranešimus + permission_export_wiki_pages: Eksportuoti wiki puslapius + permission_manage_subtasks: Valdyti darbo dalis + + project_module_issue_tracking: Darbų pėdsekys + project_module_time_tracking: Laiko pėdsekys + project_module_news: Naujienos + project_module_documents: Dokumentai + project_module_files: Failai + project_module_wiki: Wiki + project_module_repository: Saugykla + project_module_boards: Forumai + project_module_calendar: Kalendorius + project_module_gantt: Gantt + + label_user: Vartotojas + label_user_plural: Vartotojai + label_user_new: Naujas vartotojas + label_user_anonymous: Anonimas + label_project: Projektas + label_project_new: Naujas projektas + label_project_plural: Projektai + label_x_projects: + zero: nėra projektų + one: 1 projektas + other: "%{count} projektų" + label_project_all: Visi Projektai + label_project_latest: Naujausi projektai + label_issue: Darbas + label_issue_new: Naujas darbas + label_issue_plural: Darbai + label_issue_view_all: Peržiūrėti visus darbus + label_issues_by: "Darbai pagal %{value}" + label_issue_added: Darbas pridėtas + label_issue_updated: Darbas atnaujintas + label_issue_note_added: Pastaba pridėta + label_issue_status_updated: Statusas atnaujintas + label_issue_priority_updated: Prioritetas atnaujintas + label_document: Dokumentas + label_document_new: Naujas dokumentas + label_document_plural: Dokumentai + label_document_added: Dokumentas pridėtas + label_role: Vaidmuo + label_role_plural: Vaidmenys + label_role_new: Naujas vaidmuo + label_role_and_permissions: Vaidmenys ir leidimai + label_role_anonymous: Anonimas + label_role_non_member: Nėra narys + label_member: Narys + label_member_new: Naujas narys + label_member_plural: Nariai + label_tracker: Pėdsekys + label_tracker_plural: Pėdsekiai + label_tracker_new: Naujas pėdsekys + label_workflow: Darbų eiga + label_issue_status: Darbo būsena + label_issue_status_plural: Darbų būsenos + label_issue_status_new: Nauja būsena + label_issue_category: Darbo kategorija + label_issue_category_plural: Darbo kategorijos + label_issue_category_new: Nauja kategorija + label_custom_field: Kliento laukas + label_custom_field_plural: Kliento laukai + label_custom_field_new: Naujas kliento laukas + label_enumerations: Išvardinimai + label_enumeration_new: Nauja vertė + label_information: Informacija + label_information_plural: Informacija + label_please_login: Prašom prisijungti + label_register: Užsiregistruoti + label_login_with_open_id_option: arba prisijunkite su OpenID + label_password_lost: Prarastas slaptažodis + label_home: Pagrindinis + label_my_page: Mano puslapis + label_my_account: Mano paskyra + label_my_projects: Mano projektai + label_my_page_block: Mano puslapio blokas + label_administration: Administravimas + label_login: Prisijungti + label_logout: Atsijungti + label_help: Pagalba + label_reported_issues: Pranešti darbai + label_assigned_to_me_issues: Darbai, priskirti man + label_last_login: Paskutinis prisijungimas + label_registered_on: Užregistruota + label_activity: Veikla + label_overall_activity: Visa veikla + label_user_activity: "%{value} veikla" + label_new: Naujas + label_logged_as: Prisijungęs kaip + label_environment: Aplinka + label_authentication: Autentiškumo nustatymas + label_auth_source: Autentiškumo nustatymo būdas + label_auth_source_new: Naujas autentiškumo nustatymo būdas + label_auth_source_plural: Autentiškumo nustatymo būdai + label_subproject_plural: Subprojektai + label_subproject_new: Naujas subprojektas + label_and_its_subprojects: "%{value} projektas ir jo subprojektai" + label_min_max_length: Min - Maks ilgis + label_list: Sąrašas + label_date: Data + label_integer: Sveikasis skaičius + label_float: Slankiojo kablelio skaičius + label_boolean: Loginis + label_string: Tekstas + label_text: Ilgas tekstas + label_attribute: Požymis + label_attribute_plural: Požymiai + label_no_data: Nėra ką atvaizduoti + label_change_status: Pakeitimo būsena + label_history: Istorija + label_attachment: Filas + label_attachment_new: Naujas failas + label_attachment_delete: Pašalinkite failą + label_attachment_plural: Failai + label_file_added: Failas pridėtas + label_report: Ataskaita + label_report_plural: Ataskaitos + label_news: Naujiena + label_news_new: Pridėti naujienas + label_news_plural: Naujienos + label_news_latest: Paskutinės naujienos + label_news_view_all: Peržiūrėti visas naujienas + label_news_added: Naujiena pridėta + label_news_comment_added: Prie naujienos pridėtas komentaras + label_settings: Nustatymai + label_overview: Apžvalga + label_version: Versija + label_version_new: Nauja versija + label_version_plural: Versijos + label_close_versions: Uždaryti užbaigtas versijas + label_confirmation: Patvirtinimas + label_export_to: 'Eksportuoti į:' + label_read: Skaitykite... + label_public_projects: Vieši projektai + label_open_issues: atidaryta + label_open_issues_plural: atidaryti + label_closed_issues: uždaryta + label_closed_issues_plural: uždaryti + label_x_open_issues_abbr_on_total: + zero: 0 atvirų / %{total} + one: 1 atviras / %{total} + other: "%{count} atviri / %{total}" + label_x_open_issues_abbr: + zero: 0 atvirų + one: 1 atviras + other: "%{count} atviri" + label_x_closed_issues_abbr: + zero: 0 uždarytų + one: 1 uždarytas + other: "%{count} uždarytų" + label_total: Iš viso + label_permissions: Leidimai + label_current_status: Dabartinė būsena + label_new_statuses_allowed: Naujos būsenos galimos + label_all: visi(os) + label_none: joks + label_nobody: niekas + label_next: Kitas + label_previous: Ankstesnis + label_used_by: Naudotas + label_details: Detalės + label_add_note: Pridėkite pastabą + label_per_page: Puslapyje + label_calendar: Kalendorius + label_months_from: mėnesiai nuo + label_gantt: Gantt + label_internal: Vidinis + label_last_changes: "paskutiniai %{count} pokyčiai(ių)" + label_change_view_all: Peržiūrėti visus pakeitimus + label_personalize_page: Suasmeninti šį puslapį + label_comment: Komentaras + label_comment_plural: Komentarai + label_x_comments: + zero: nėra komentarų + one: 1 komentaras + other: "%{count} komentarų" + label_comment_add: Pridėkite komentarą + label_comment_added: Komentaras pridėtas + label_comment_delete: Pašalinti komentarus + label_query: Užklausa + label_query_plural: Užklausos + label_query_new: Nauja užklausa + label_my_queries: Mano sukurtos užklausos + label_filter_add: Pridėti filtrą + label_filter_plural: Filtrai + label_equals: yra + label_not_equals: nėra + label_in_less_than: anksčiau nei po + label_in_more_than: vėliau nei po + label_greater_or_equal: '>=' + label_less_or_equal: '<=' + label_between: tarp + label_in: per + label_today: šiandien + label_all_time: visas laikas + label_yesterday: vakar + label_this_week: šią savaitę + label_last_week: praeita savaitė + label_last_n_days: "paskutinių %{count} dienų" + label_this_month: šis menuo + label_last_month: praeitas mėnuo + label_this_year: šiemet + label_date_range: Dienų diapazonas + label_less_than_ago: vėliau nei prieš + label_more_than_ago: anksčiau nei prieš + label_ago: prieš + label_contains: turi + label_not_contains: neturi + label_day_plural: dienų(os) + label_repository: Saugykla + label_repository_plural: Saugyklos + label_browse: Naršyti + label_branch: Šaka + label_tag: Tag + label_revision: Revizija + label_revision_plural: Revizijos + label_revision_id: Revizija %{value} + label_associated_revisions: Susijusios revizijos + label_added: pridėtas + label_modified: pakeistas + label_copied: nukopijuotas + label_renamed: pervardintas + label_deleted: pašalintas + label_latest_revision: Paskutinė revizija + label_latest_revision_plural: Paskutinės revizijos + label_view_revisions: Pežiūrėti revizijas + label_view_all_revisions: Pežiūrėti visas revizijas + label_max_size: Maksimalus dydis + label_sort_highest: Perkelti į viršūnę + label_sort_higher: Perkelti į viršų + label_sort_lower: Perkelti žemyn + label_sort_lowest: Perkelti į apačią + label_roadmap: Veiklos grafikas + label_roadmap_due_in: "Baigiasi po %{value}" + label_roadmap_overdue: "%{value} vėluojama" + label_roadmap_no_issues: Šiai versijai nepriskirtas koks darbas + label_search: Ieškoti + label_result_plural: Rezultatai + label_all_words: Visi žodžiai + label_wiki: Wiki + label_wiki_edit: Wiki redakcija + label_wiki_edit_plural: Wiki redakcijos + label_wiki_page: Wiki puslapis + label_wiki_page_plural: Wiki puslapiai + label_index_by_title: Indeksuoti pagal pavadinimą + label_index_by_date: Indeksuoti pagal datą + label_current_version: Einamoji versija + label_preview: Peržiūra + label_feed_plural: Kanalai + label_changes_details: Visų pakeitimų detalės + label_issue_tracking: Darbų sekimas + label_spent_time: Dirbtas laikas + label_overall_spent_time: Visas dirbtas laikas + label_f_hour: "%{value} valanda" + label_f_hour_plural: "%{value} valandų(os)" + label_time_tracking: Laiko sekimas + label_change_plural: Pakeitimai + label_statistics: Statistika + label_commits_per_month: Įkėlimai per mėnesį + label_commits_per_author: Įkėlimai pagal autorių + label_diff: skirt + label_view_diff: Skirtumų peržiūra + label_diff_inline: įterptas + label_diff_side_by_side: šalia + label_options: Pasirinkimai + label_copy_workflow_from: Kopijuoti darbų eiga iš + label_permissions_report: Leidimų pranešimas + label_watched_issues: Stebimi darbai + label_related_issues: Susiję darbai + label_applied_status: Taikomoji būsena + label_loading: Kraunama... + label_relation_new: Naujas ryšys + label_relation_delete: Pašalinti ryšį + label_relates_to: susietas su + label_duplicates: dubliuoja + label_duplicated_by: dubliuojasi su + label_blocks: blokuoja + label_blocked_by: blokuojamas + label_precedes: ankstesnė(is) + label_follows: seka + label_end_to_start: užbaigti, kad pradėti + label_end_to_end: užbaigti, kad pabaigti + label_start_to_start: pradėkite pradėti + label_start_to_end: pradėkite užbaigti + label_stay_logged_in: Likti prisijungus + label_disabled: išjungta(as) + label_show_completed_versions: Rodyti užbaigtas versijas + label_me: aš + label_board: Forumas + label_board_new: Naujas forumas + label_board_plural: Forumai + label_board_locked: Užrakinta + label_board_sticky: Lipnus + label_topic_plural: Temos + label_message_plural: Pranešimai + label_message_last: Paskutinis pranešimas + label_message_new: Naujas pranešimas + label_message_posted: Pranešimas pridėtas + label_reply_plural: Atsakymai + label_send_information: Nusiųsti paskyros informaciją vartotojui + label_year: Metai + label_month: Mėnuo + label_week: Savaitė + label_date_from: Nuo + label_date_to: Iki + label_language_based: Pagrįsta vartotojo kalba + label_sort_by: "Rūšiuoti pagal %{value}" + label_send_test_email: Nusiųsti bandomąjį laišką + label_feeds_access_key: RSS prieigos raktas + label_missing_feeds_access_key: TRūksta RSS prieigos rakto + label_feeds_access_key_created_on: "RSS prieigos raktas sukurtas prieš %{value}" + label_module_plural: Moduliai + label_added_time_by: "Pridėjo %{author} prieš %{age}" + label_updated_time_by: "Atnaujino %{author} prieš %{age}" + label_updated_time: "Atnaujinta prieš %{value}" + label_jump_to_a_project: Šuolis į projektą... + label_file_plural: Failai + label_changeset_plural: Pakeitimų rinkiniai + label_default_columns: Numatytieji stulpeliai + label_no_change_option: (Jokio pakeitimo) + label_bulk_edit_selected_issues: Masiškai readguoti pasirinktus darbus + label_bulk_edit_selected_time_entries: Masiškai redaguotumėte pasirinktus laiko įrašus + label_theme: Tema + label_default: Numatyta(as) + label_search_titles_only: Ieškoti tiktai pavadinimų + label_user_mail_option_all: "Bet kokiam įvykiui visuose mano projektuose" + label_user_mail_option_selected: "Bet kokiam įvykiui tiktai pasirinktuose projektuose ..." + label_user_mail_option_none: "Nėra įvykių" + label_user_mail_option_only_my_events: "Tiktai įvikiai, kuriuos stebiu arba esu įtrauktas" + label_user_mail_option_only_assigned: "Tiktai įvykiai, kuriems esu priskirtas" + label_user_mail_option_only_owner: "Tiktai įvikiai, kurių šeikininkas esu" + label_user_mail_no_self_notified: "Nenoriu būti informuotas apie pakeitimus, kuriuos pats atlieku" + label_registration_activation_by_email: paskyros aktyvacija per e-paštą + label_registration_manual_activation: rankinė paskyros aktyvacija + label_registration_automatic_activation: automatinė paskyros aktyvacija + label_display_per_page: "%{value} įrašų puslapyje" + label_age: Amžius + label_change_properties: Pakeisti nustatymus + label_general: Bendri(as) + label_more: Daugiau + label_scm: SCM + label_plugins: Įskiepiai + label_ldap_authentication: LDAP autentifikacija + label_downloads_abbr: siunt. + label_optional_description: Apibūdinimas (laisvai pasirenkamas) + label_add_another_file: Pridėti kitą failą + label_preferences: Savybės + label_chronological_order: Chronologine tvarka + label_reverse_chronological_order: Atbuline chronologine tvarka + label_planning: Planavimas + label_incoming_emails: Įeinantys laiškai + label_generate_key: Generuoti raktą + label_issue_watchers: Stebėtojai + label_example: Pavyzdys + label_display: Demonstruoti + label_sort: Rūšiuoti + label_ascending: Didėjantis + label_descending: Mažėjantis + label_date_from_to: Nuo %{start} iki %{end} + label_wiki_content_added: Wiki puslapis pridėtas + label_wiki_content_updated: Wiki puslapis atnaujintas + label_group: Grupė + label_group_plural: Grupės + label_group_new: Nauja grupė + label_time_entry_plural: Sprendimo laikas + label_version_sharing_none: Nesidalinama + label_version_sharing_descendants: Su subprojektais + label_version_sharing_hierarchy: Su projekto hierarchija + label_version_sharing_tree: Su projekto medžiu + label_version_sharing_system: Su visais projektais + label_update_issue_done_ratios: Atnaujinti darbo atlikimo progresą + label_copy_source: Šaltinis + label_copy_target: Tikslas + label_copy_same_as_target: Toks pat kaip tikslas + label_display_used_statuses_only: Rodyti tik tuos statusus, kurie naudojami šio pėdsekio + label_api_access_key: API prieigos raktas + label_missing_api_access_key: Trūksta API prieigos rakto + label_api_access_key_created_on: "API prieigos raktas sukurtas prieš %{value}" + label_profile: Profilis + label_subtask_plural: Darbo dalys + label_project_copy_notifications: Siųsti pašto pranešimus kopijuojant projektą + label_principal_search: "Ieškoti vartotojo arba grupės:" + label_user_search: "Ieškoti vartotojo:" + label_issues_visibility_all: Visi darbai + label_issues_visibility_public: Visi vieši darbai + label_issues_visibility_own: Darbai, sukurti vartotojo arba jam priskirti + label_git_report_last_commit: Nurodyti paskutinį failų ir katalogų pakeitimą + label_parent_revision: Pirminė revizija + label_child_revision: Sekanti revizija + label_export_options: "%{export_format} eksportavimo nustatymai" + + button_login: Registruotis + button_submit: Pateikti + button_save: Išsaugoti + button_check_all: Žymėti visus + button_uncheck_all: Atžymėti visus + button_collapse_all: Sutraukti visus + button_expand_all: Išskleisti visus + button_delete: Pašalinti + button_create: Sukurti + button_create_and_continue: Sukurti ir tęsti + button_test: Testas + button_edit: Redaguoti + button_edit_associated_wikipage: "Redaguoti susijusį Wiki puslapį: %{page_title}" + button_add: Pridėti + button_change: Keisti + button_apply: Pritaikyti + button_clear: Išvalyti + button_lock: Rakinti + button_unlock: Atrakinti + button_download: Atsisiųsti + button_list: Sąrašas + button_view: Žiūrėti + button_move: Perkelti + button_move_and_follow: Perkelti ir sekti + button_back: Atgal + button_cancel: Atšaukti + button_activate: Aktyvinti + button_sort: Rūšiuoti + button_log_time: Registruoti laiką + button_rollback: Grįžti į šią versiją + button_watch: Stebėti + button_unwatch: Nestebėti + button_reply: Atsakyti + button_archive: Archyvuoti + button_unarchive: Išpakuoti + button_reset: Atstatyti + button_rename: Pervadinti + button_change_password: Pakeisti slaptažodį + button_copy: Kopijuoti + button_copy_and_follow: Kopijuoti ir laikytis + button_annotate: Rašyti pastabą + button_update: Atnaujinti + button_configure: Konfigūruoti + button_quote: Cituoti + button_duplicate: Dubliuoti + button_show: Rodyti + button_edit_section: Redaguoti šį skirsnį + button_export: Eksportuoti + + status_active: aktyvus + status_registered: užregistruotas + status_locked: užrakintas + + version_status_open: atidaryta + version_status_locked: užrakinta + version_status_closed: uždaryta + + field_active: Aktyvus + + text_select_mail_notifications: Išrinkite veiksmus, apie kuriuos būtų pranešta elektroniniu paštu. + text_regexp_info: pvz. ^[A-Z0-9]+$ + text_min_max_length_info: 0 reiškia jokių apribojimų + text_project_destroy_confirmation: Ar esate įsitikinęs, kad norite pašalinti šį projektą ir visus susijusius duomenis? + text_subprojects_destroy_warning: "Šis(ie) subprojektas(ai): %{value} taip pat bus ištrintas(i)." + text_workflow_edit: Išrinkite vaidmenį ir pėdsekį, kad redaguotumėte darbų eigą + text_are_you_sure: Ar esate įsitikinęs? + text_journal_changed: "%{label} pakeistas(a) iš %{old} į %{new}" + text_journal_changed_no_detail: "%{label} atnaujintas(a)" + text_journal_set_to: "%{label} nustatytas(a) į %{value}" + text_journal_deleted: "%{label} ištrintas(a) (%{old})" + text_journal_added: "%{label} pridėtas(a) %{value}" + text_tip_issue_begin_day: užduotis, prasidedanti šią dieną + text_tip_issue_end_day: užduotis, pasibaigianti šią dieną + text_tip_issue_begin_end_day: užduotis, prasidedanti ir pasibaigianti šią dieną + text_project_identifier_info: 'Mažosios raidės (a-z), skaičiai ir brūkšniai galimi.
    Išsaugojus, identifikatorius negali būti keičiamas.' + text_caracters_maximum: "%{count} simbolių maksimumas." + text_caracters_minimum: "Turi būti mažiausiai %{count} simbolių ilgio." + text_length_between: "Ilgis tarp %{min} ir %{max} simbolių." + text_tracker_no_workflow: Jokia darbų eiga neapibrėžta šiam pėdsekiui + text_unallowed_characters: Neleistini simboliai + text_comma_separated: Leistinos kelios reikšmės (atskirtos kableliu). + text_line_separated: Galimos kelios reikšmės (viena linija vienai vertei). + text_issues_ref_in_commit_messages: Darbų susiejimas ir fiksavimas pavedimų žinutėse + text_issue_added: "Darbas %{id} buvo praneštas (by %{author})." + text_issue_updated: "Darbas %{id} buvo atnaujintas (by %{author})." + text_wiki_destroy_confirmation: Ar esate įsitikinęs, kad norite pašalinti šį wiki puslapį ir visą jo turinį? + text_issue_category_destroy_question: "Kai kurie darbai (%{count}) yra paskirti šiai kategorijai. Ką jūs norite daryti?" + text_issue_category_destroy_assignments: Pašalinti kategorijos užduotis + text_issue_category_reassign_to: Iš naujo priskirti darbus šiai kategorijai + text_user_mail_option: "Neišrinktiems projektams, jūs gausite tiktai pranešimus apie tuos įvykius, kuriuos jūs stebite, arba į kuriuos esate įtrauktas (pvz. darbai, kurių autorius jūs esate ar esate priskirtas)." + text_no_configuration_data: "Vaidmenys, pėdsekiai, darbų būsenos ir darbų eiga dar nebuvo konfigūruoti.\nGriežtai rekomenduojam užkrauti numatytąją (default) konfiguraciją. Užkrovus, galėsite ją modifikuoti." + text_load_default_configuration: Užkrauti numatytąj konfiguraciją + text_status_changed_by_changeset: "Pakeista %{value} revizijoje." + text_time_logged_by_changeset: "Applied in changeset %{value}." + text_issues_destroy_confirmation: 'Ar jūs tikrai norite sunaikinti pažymėtą(us) darbą(us)?' + text_issues_destroy_descendants_confirmation: Taip pat bus ištrinta(os) %{count} darbo dalis(ys). + text_time_entries_destroy_confirmation: 'Ar jūs tikrai norite ištrinti pasirinktą(us) laiko įrašą(us)?' + text_select_project_modules: 'Parinkite modulius, kuriuos norite naudoti šiame projekte:' + text_default_administrator_account_changed: Administratoriaus numatytoji paskyra pakeista + text_file_repository_writable: Į failų saugyklą saugoti galima (RW) + text_plugin_assets_writable: Į įskiepių aprašo punktų katalogą įrašyti galima + text_rmagick_available: RMagick pasiekiamas (pasirinktinai) + text_destroy_time_entries_question: "Naikinamam darbui priskirta %{hours} valandų. Ką norite su jomis daryti?" + text_destroy_time_entries: Ištrinti įrašytas valandas + text_assign_time_entries_to_project: Priskirti įrašytas valandas prie projekto + text_reassign_time_entries: 'Priskirti įrašytas valandas šiam darbui:' + text_user_wrote: "%{value} parašė:" + text_enumeration_destroy_question: "%{count} objektai(ų) priskirti šiai reikšmei." + text_enumeration_category_reassign_to: 'Priskirti juos šiai reikšmei:' + text_email_delivery_not_configured: "El.pašto siuntimas nesukonfigūruotas, ir perspėjimai neaktyvus.\nSukonfigūruokite savo SMTP serverį byloje config/configuration.yml ir perleiskite programą norėdami pritaikyti pakeitimus." + text_repository_usernames_mapping: "Parinkite ar atnaujinkite Redmine vartotoją, kuris paminėtas saugyklos log'e.\nVartotojai, turintys tą patį Redmine ir saugyklos vardą ar el.paštą yra automatiškai surišti." + text_diff_truncated: "... Šis diff'as nukarpytas, nes jis viršijo maksimalų rodomų eilučių skaičių." + text_custom_field_possible_values_info: 'Po vieną eilutę kiekvienai reikšmei' + text_wiki_page_destroy_question: "Šis puslapis turi %{descendants} susijusių arba išvestinių puslapių. Ką norėtumėte daryti?" + text_wiki_page_nullify_children: Laikyti child puslapius kaip pagrindinius puslapius + text_wiki_page_destroy_children: "Pašalinti child puslapius ir jų palikuonis" + text_wiki_page_reassign_children: "Priskirkite iš naujo 'child' puslapius šiam pagrindiniam puslapiui" + text_own_membership_delete_confirmation: "Jūs esate pasiruošęs panaikinti dalį arba visus leidimus ir po šio pakeitimo galite prarasti šio projekto redagavimo galimybę. \n Ar jūs esate įsitikinęs ir tęsti?" + text_zoom_in: Priartinti + text_zoom_out: Nutolinti + text_warn_on_leaving_unsaved: "Dabartinis puslapis turi neišsaugoto teksto, kuris bus prarastas, jeigu paliksite šį puslapį." + text_scm_path_encoding_note: "Numatytasis: UTF-8" + text_git_repository_note: Saugykla (repository) yra plika ir vietinė (pvz. /gitrepo, c:\gitrepo) + text_mercurial_repository_note: Vietinė saugykla (e.g. /hgrepo, c:\hgrepo) + text_scm_command: Komanda + text_scm_command_version: Versija + + default_role_manager: Vadovas + default_role_developer: Projektuotojas + default_role_reporter: Pranešėjas + default_tracker_bug: Klaida + default_tracker_feature: Ypatybė + default_tracker_support: Palaikymas + default_issue_status_new: Naujas + default_issue_status_in_progress: Vykdomas + default_issue_status_resolved: Išspręstas + default_issue_status_feedback: Grįžtamasis ryšys + default_issue_status_closed: Uždarytas + default_issue_status_rejected: Atmestas + default_doc_category_user: Vartotojo dokumentacija + default_doc_category_tech: Techninė dokumentacija + default_priority_low: Žemas + default_priority_normal: Normalus + default_priority_high: Aukštas + default_priority_urgent: Skubus + default_priority_immediate: Neatidėliotinas + default_activity_design: Projektavimas + default_activity_development: Vystymas + + enumeration_issue_priorities: Darbo prioritetai + enumeration_doc_categories: Dokumento kategorijos + enumeration_activities: Veiklos (laiko sekimas) + enumeration_system_activity: Sistemos veikla + + description_filter: Filtras + description_search: Paieškos laukas + description_choose_project: Projektai + description_project_scope: Paieškos sritis + description_notes: Pastabos + description_message_content: Žinutės turinys + description_query_sort_criteria_attribute: Rūšiuoti atributą + description_query_sort_criteria_direction: Rūšiuoti kryptį + description_user_mail_notification: Pašto pranešimų nustatymai + description_available_columns: Galimi Stulpeliai + description_selected_columns: Pasirinkti Stulpeliai + description_all_columns: Visi stulpeliai + description_issue_category_reassign: Pasirinkti darbo kategoriją + description_wiki_subpages_reassign: Pasirinkti naują pagrindinį puslapį + description_date_range_list: Pasirinkitę diapazoną iš sąrašo + description_date_range_interval: Pasirinkite diapazoną pasirinkdami pradžios ir pabaigos datas + description_date_from: Įvesti pradžios datą + description_date_to: Įvesti pabaigos datą + + label_additional_workflow_transitions_for_assignee: Papildomi darbų eigos variantai kai darbas paskirtas vartotojui + label_additional_workflow_transitions_for_author: Papildomi darbų eigos variantai kai vartotojas yra darbo autorius + notice_failed_to_save_time_entries: "Nepavyko išsaugoti %{count} laiko žurnalo įrašų iš %{total} parinktų: %{ids}." + label_x_issues: + zero: 0 darbas + one: 1 darbas + other: "%{count} darbai(ų)" + label_repository_new: Nauja saugykla + field_repository_is_default: Pagrindinė saugykla + label_copy_attachments: Kopijuoti priedus + label_item_position: "%{position}/%{count}" + label_completed_versions: Užbaigtos versijos + text_project_identifier_info: Leidžiamos tik mažosios raidės (a-z), skaitmenys, brūkšneliai ir pabraukimo simboliai.
    Kartą išsaugojus pakeitimai negalimi + field_multiple: Keletas reikšmių + setting_commit_cross_project_ref: Leisti visų kitų projektų įrašus susieti nuorodomis ir sutaisyti + text_issue_conflict_resolution_add_notes: Išsaugoti mano žinutę ir atmesti likusius mano pataisymus + text_issue_conflict_resolution_overwrite: Išsaugoti mano pakeitimus (ankstesnių pakeitimų žinutės bus išsaugotos, tačiau kai kurie pakeitimai bus perrašyti) + notice_issue_update_conflict: Darbas buvo pakoreguotas kito vartotojo kol jūs atlikote pakeitimus. + text_issue_conflict_resolution_cancel: Atmesti visus mano pakeitimus ir iš naujo rodyti %{link} + permission_manage_related_issues: Tvarkyti susietus darbus + field_auth_source_ldap_filter: LDAP filtras + label_search_for_watchers: Ieškoti vartotojų kuriuos įtraukti kaip stebėtojus + notice_account_deleted: Jūsų paskyra panaikinta. + setting_unsubscribe: Leisti vartotojams panaikinti savo paskyrą + button_delete_my_account: Panaikinti savo paskyrą + text_account_destroy_confirmation: |- + Ar tikrai norite tęsti? + Jūsų paskyra bus panaikinta ir nebus galimybės jos atkurti. + error_session_expired: Jūsų sesija pasibaigė. Prašome prisijunti iš naujo. + text_session_expiration_settings: "Įspėjimas: atlikus šiuos pakeitimus visos aktyvios sesijos gali nustoti galiojusios (įskaitant jūsų sesiją)." + setting_session_lifetime: Sesijos maksimalus galiojimas + setting_session_timeout: Sesijos neveiklumo laiko tarpas + label_session_expiration: Baigėsi sujungimo sesija + permission_close_project: Uždaryti / atnaujinti projektą + label_show_closed_projects: Matyti uždarytus projektus + button_close: Uždaryti + button_reopen: Atnaujinti + project_status_active: aktyvus + project_status_closed: uždarytas + project_status_archived: archyvuotas + text_project_closed: Šis projektas yra uždarytas, prieinamas tik peržiūrai. + notice_user_successful_create: Vartotojas %{id} sukurtas. + field_core_fields: Standartiniai laukai + field_timeout: Timeout (po sek.) + setting_thumbnails_enabled: Rodyti sumažintus priedų atvaizdus + setting_thumbnails_size: Sumažinto atvaizdo dydis (taškeliais) + label_status_transitions: Darbų eiga + label_fields_permissions: Leidimai + label_readonly: Tik peržiūra + label_required: Privaloma(s) + text_repository_identifier_info: Leidžiamos tik mažosios raidės (a-z), skaitmenys, brūkšneliai ir pabraukimo simboliai.
    Kartą išsaugojus pakeitimai negalimi + field_board_parent: Pagrindinis forumas + label_attribute_of_project: Projekto pavadinimas %{name} + label_attribute_of_author: Autorius %{name} + label_attribute_of_assigned_to: Paskirtas %{name} + label_attribute_of_fixed_version: Versijos %{name} + label_copy_subtasks: Kopijuoti darbo dalis + label_copied_to: kopijuota į + label_copied_from: kopijuota iš + label_any_issues_in_project: bet kurie projekto darbai + label_any_issues_not_in_project: bet kurie ne šio projekto darbai + field_private_notes: Privačios žinutės + permission_view_private_notes: Matyti privačias žinutes + permission_set_notes_private: Pakeisti žinutę privačia + label_no_issues_in_project: projekte nėra darbų + label_any: visi + label_last_n_weeks: prieš %{count} sav. + setting_cross_project_subtasks: Leisti susieti skirtingų projektų užduočių dalis + label_cross_project_descendants: Su subprojektais + label_cross_project_tree: Su projekto medžiu + label_cross_project_hierarchy: Su projekto hierarchija + label_cross_project_system: Su visais projektais + button_hide: Slėpti + setting_non_working_week_days: Nedarbo dienos + label_in_the_next_days: per ateinančias + label_in_the_past_days: per paskutines + label_attribute_of_user: Vartotojo %{name} + text_turning_multiple_off: Jei jūs išjungsite kelių reikšmių pasirinkimą, visos išvardintos reikšmės bus pašalintos ir palikta tik viena reikšmė kiekvienam laukui. + label_attribute_of_issue: Įrašai %{name} + permission_add_documents: Pridėti dokumentus + permission_edit_documents: Redaguoti dokumentus + permission_delete_documents: Trinti dokumentus + label_gantt_progress_line: Progreso linija + setting_jsonp_enabled: Įgalinti JSONP palaikymą + field_inherit_members: Paveldėti narius + field_closed_on: Uždarytas + setting_default_projects_tracker_ids: Sekliai pagal nutylėjimą naujiems projektams + label_total_time: Iš viso + text_scm_config: Jūs galite pakeisti SCM komandas byloje config/configuration.yml. Prašome perkrauti programą po redagavimo, idant įgalinti pakeitimus. + text_scm_command_not_available: SCM komanda nepasiekiama. Patikrinkite administravimo skydelio nustatymus. diff --git a/config/locales/lv.yml b/config/locales/lv.yml new file mode 100644 index 00000000..9c3de741 --- /dev/null +++ b/config/locales/lv.yml @@ -0,0 +1,1083 @@ +# translated by Dzintars Bergs (dzintars.bergs@gmail.com) + +lv: + direction: ltr + date: + formats: + default: "%d.%m.%Y" + short: "%d %b" + long: "%d %B %Y" + + day_names: [Svētdiena, Pirmdiena, Otrdiena, Trešdiena, Ceturtdiena, Piektdiena, Sestdiena] + abbr_day_names: [Sv, Pr, Ot, Tr, Ct, Pk, St] + + month_names: [~, Janvāris, Februāris, Marts, Aprīlis , Maijs, Jūnijs, Jūlijs, Augusts, Septembris, Oktobris, Novembris, Decembris] + abbr_month_names: [~, Jan, Feb, Mar, Apr, Mai, Jūn, Jūl, Aug, Sep, Okt, Nov, Dec] + order: + - :day + - :month + - :year + + time: + formats: + default: "%a, %d %b %Y, %H:%M:%S %z" + time: "%H:%M" + short: "%d %b, %H:%M" + long: "%B %d, %Y %H:%M" + am: "rītā" + pm: "vakarā" + + datetime: + distance_in_words: + half_a_minute: "pus minūte" + less_than_x_seconds: + one: "mazāk kā 1 sekunde" + other: "mazāk kā %{count} sekundes" + x_seconds: + one: "1 sekunde" + other: "%{count} sekundes" + less_than_x_minutes: + one: "mazāk kā minūte" + other: "mazāk kā %{count} minūtes" + x_minutes: + one: "1 minūte" + other: "%{count} minūtes" + about_x_hours: + one: "aptuveni 1 stunda" + other: "aptuveni %{count} stundas" + x_hours: + one: "1 hour" + other: "%{count} hours" + x_days: + one: "1 diena" + other: "%{count} dienas" + about_x_months: + one: "aptuveni 1 mēnesis" + other: "aptuveni %{count} mēneši" + x_months: + one: "1 mēnesis" + other: "%{count} mēneši" + about_x_years: + one: "aptuveni 1 gads" + other: "aptuveni %{count} gadi" + over_x_years: + one: "ilgāk par 1 gadu" + other: "ilgāk par %{count} gadiem" + almost_x_years: + one: "gandrīz 1 gadu" + other: "gandrīz %{count} gadus" + + number: + format: + separator: "." + delimiter: "" + precision: 3 + human: + format: + delimiter: " " + precision: 3 + storage_units: + format: "%n %u" + units: + byte: + one: "Baits" + other: "Baiti" + kb: "KB" + mb: "MB" + gb: "GB" + tb: "TB" + + support: + array: + sentence_connector: "un" + skip_last_comma: false + + activerecord: + errors: + template: + header: + one: "1 error prohibited this %{model} from being saved" + other: "%{count} errors prohibited this %{model} from being saved" + messages: + inclusion: "nav iekļauts sarakstā" + exclusion: "ir rezervēts" + invalid: "nederīgs" + confirmation: "apstiprinājums nesakrīt" + accepted: "jābūt akceptētam" + empty: "nevar būt tukšs" + blank: "nevar būt neaizpildīts" + too_long: "ir pārāk gara(š) (maksimālais garums ir %{count} simboli)" + too_short: "ir pārāk īsa(s) (minimālais garums ir %{count} simboli)" + wrong_length: "ir nepareiza garuma (vajadzētu būt %{count} simboli)" + taken: "eksistē" + not_a_number: "nav skaitlis" + not_a_date: "nav derīgs datums" + greater_than: "jābūt lielākam par %{count}" + greater_than_or_equal_to: "jābūt lielākam vai vienādam ar %{count}" + equal_to: "jābūt vienādam ar %{count}" + less_than: "jābūt mazākam kā %{count}" + less_than_or_equal_to: "jābūt mazākam vai vienādam ar %{count}" + odd: "jāatšķirās" + even: "jāsakrīt" + greater_than_start_date: "jābūt vēlākam par sākuma datumu" + not_same_project: "nepieder pie tā paša projekta" + circular_dependency: "Šī relācija radītu ciklisku atkarību" + cant_link_an_issue_with_a_descendant: "An issue can not be linked to one of its subtasks" + + actionview_instancetag_blank_option: Izvēlieties + + general_text_No: 'Nē' + general_text_Yes: 'Jā' + general_text_no: 'nē' + general_text_yes: 'jā' + general_lang_name: 'Latvian (Latviešu)' + general_csv_separator: ',' + general_csv_decimal_separator: '.' + general_csv_encoding: UTF-8 + general_pdf_encoding: UTF-8 + general_first_day_of_week: '1' + + notice_account_updated: Konts tika atjaunots veiksmīgi. + notice_account_invalid_creditentials: Nepareizs lietotāja vārds vai parole. + notice_account_password_updated: Parole tika veiksmīgi atjaunota. + notice_account_wrong_password: Nepareiza parole + notice_account_register_done: Konts veiksmīgi izveidots. Lai aktivizētu kontu, spiediet uz saites, kas Jums tika nosūtīta. + notice_account_unknown_email: Nezināms lietotājs + notice_can_t_change_password: Šis konts izmanto ārēju pilnvarošanas avotu. Nav iespējams nomainīt paroli. + notice_account_lost_email_sent: Jums tika nosūtīts e-pasts ar instrukcijām, kā izveidot jaunu paroli. + notice_account_activated: Jūsu konts ir aktivizēts. Varat pieslēgties sistēmai. + notice_successful_create: Veiksmīga izveide. + notice_successful_update: Veiksmīga atjaunošana. + notice_successful_delete: Veiksmīga dzēšana. + notice_successful_connection: Veiksmīgs savienojums. + notice_file_not_found: Lapa, ko Jūs mēģināt atvērt, neeksistē vai ir pārvietota. + notice_locking_conflict: Datus ir atjaunojis cits lietotājs. + notice_not_authorized: Jums nav tiesību piekļūt šai lapai. + notice_email_sent: "E-pasts tika nosūtīts uz %{value}" + notice_email_error: "Kļūda sūtot e-pastu (%{value})" + notice_feeds_access_key_reseted: Jūsu RSS pieejas atslēga tika iestatīta sākuma stāvoklī. + notice_api_access_key_reseted: Jūsu API pieejas atslēga tika iestatīta sākuma stāvoklī. + notice_failed_to_save_issues: "Neizdevās saglabāt %{count} uzdevumu(us) no %{total} izvēlēti: %{ids}." + notice_no_issue_selected: "Nav izvēlēts uzdevums! Lūdzu, atzīmējiet uzdevumus, kurus vēlaties rediģēt!" + notice_account_pending: "Jūsu konts tika izveidots un šobrīd gaida administratora apstiprinājumu." + notice_default_data_loaded: Noklusētā konfigurācija tika veiksmīgi ielādēta. + notice_unable_delete_version: Neizdevās dzēst versiju. + notice_issue_done_ratios_updated: Uzdevuma izpildes koeficients atjaunots. + + error_can_t_load_default_data: "Nevar ielādēt noklusētos konfigurācijas datus: %{value}" + error_scm_not_found: "Ieraksts vai versija nebija repozitorijā." + error_scm_command_failed: "Mēģinot piekļūt repozitorijam, notika kļūda: %{value}" + error_scm_annotate: "Ieraksts neeksistē vai tam nevar tikt pievienots paskaidrojums." + error_issue_not_found_in_project: 'Uzdevums netika atrasts vai nepieder šim projektam.' + error_no_tracker_in_project: 'Neviens trakeris nav saistīts ar šo projektu. Pārbaudiet projekta iestatījumus.' + error_no_default_issue_status: 'Nav definēts uzdevuma noklusētais statuss. Pārbaudiet konfigurāciju (Ejat uz: "Administrācija -> Uzdevumu statusi")!' + error_can_not_reopen_issue_on_closed_version: 'Nevar pievienot atsauksmi uzdevumam, kas saistīts ar slēgtu versiju.' + error_can_not_archive_project: Šis projekts nevar tikt arhivēts + error_issue_done_ratios_not_updated: "Uzdevuma izpildes koeficients nav atjaunots." + error_workflow_copy_source: 'Lūdzu izvēlieties avota trakeri vai lomu' + error_workflow_copy_target: 'Lūdzu izvēlēties mērķa trakeri(us) un lomu(as)' + + warning_attachments_not_saved: "%{count} datnes netika saglabātas." + + mail_subject_lost_password: "Jūsu %{value} parole" + mail_body_lost_password: 'Lai mainītu paroli, spiediet uz šīs saites:' + mail_subject_register: "Jūsu %{value} konta aktivizācija" + mail_body_register: 'Lai izveidotu kontu, spiediet uz šīs saites:' + mail_body_account_information_external: "Varat izmantot Jūsu %{value} kontu, lai pieslēgtos." + mail_body_account_information: Jūsu konta informācija + mail_subject_account_activation_request: "%{value} konta aktivizācijas pieprasījums" + mail_body_account_activation_request: "Jauns lietotājs (%{value}) ir reģistrēts. Lietotāja konts gaida Jūsu apstiprinājumu:" + mail_subject_reminder: "%{count} uzdevums(i) sagaidāms(i) tuvākajās %{days} dienās" + mail_body_reminder: "%{count} uzdevums(i), kurš(i) ir nozīmēts(i) Jums, sagaidāms(i) tuvākajās %{days} dienās:" + mail_subject_wiki_content_added: "'%{id}' Wiki lapa pievienota" + mail_body_wiki_content_added: "The '%{id}' Wiki lapu pievienojis %{author}." + mail_subject_wiki_content_updated: "'%{id}' Wiki lapa atjaunota" + mail_body_wiki_content_updated: "The '%{id}' Wiki lapu atjaunojis %{author}." + + + field_name: Nosaukums + field_description: Apraksts + field_summary: Kopsavilkums + field_is_required: Nepieciešams + field_firstname: Vārds + field_lastname: Uzvārds + field_mail: "E-pasts" + field_filename: Datne + field_filesize: Izmērs + field_downloads: Lejupielādes + field_author: Autors + field_created_on: Izveidots + field_updated_on: Atjaunots + field_field_format: Formāts + field_is_for_all: Visiem projektiem + field_possible_values: Iespējamās vērtības + field_regexp: Regulārā izteiksme + field_min_length: Minimālais garums + field_max_length: Maksimālais garums + field_value: Vērtība + field_category: Kategorija + field_title: Nosaukums + field_project: Projekts + field_issue: Uzdevums + field_status: Statuss + field_notes: Piezīmes + field_is_closed: Uzdevums slēgts + field_is_default: Noklusētā vērtība + field_tracker: Trakeris + field_subject: Temats + field_due_date: Sagaidāmais datums + field_assigned_to: Piešķirts + field_priority: Prioritāte + field_fixed_version: Mērķa versija + field_user: Lietotājs + field_role: Loma + field_homepage: Vietne + field_is_public: Publisks + field_parent: Apakšprojekts projektam + field_is_in_roadmap: Ceļvedī parādītie uzdevumi + field_login: Pieslēgties + field_mail_notification: "E-pasta paziņojumi" + field_admin: Administrators + field_last_login_on: Pēdējo reizi pieslēdzies + field_language: Valoda + field_effective_date: Datums + field_password: Parole + field_new_password: Janā parole + field_password_confirmation: Paroles apstiprinājums + field_version: Versija + field_type: Tips + field_host: Hosts + field_port: Ports + field_account: Konts + field_base_dn: Base DN + field_attr_login: Pieslēgšanās atribūts + field_attr_firstname: Vārda atribūts + field_attr_lastname: Uzvārda atribūts + field_attr_mail: "E-pasta atribūts" + field_onthefly: "Lietotāja izveidošana on-the-fly" + field_start_date: Sākuma datums + field_done_ratio: "% padarīti" + field_auth_source: Pilnvarošanas režīms + field_hide_mail: "Paslēpt manu e-pasta adresi" + field_comments: Komentārs + field_url: URL + field_start_page: Sākuma lapa + field_subproject: Apakšprojekts + field_hours: Stundas + field_activity: Aktivitāte + field_spent_on: Datums + field_identifier: Identifikators + field_is_filter: Izmantots kā filtrs + field_issue_to: Saistīts uzdevums + field_delay: Kavējums + field_assignable: Uzdevums var tikt piesaistīts šai lomai + field_redirect_existing_links: Pāradresēt eksistējošās saites + field_estimated_hours: Paredzētais laiks + field_column_names: Kolonnas + field_time_zone: Laika zona + field_searchable: Meklējams + field_default_value: Noklusētā vērtība + field_comments_sorting: Rādīt komentārus + field_parent_title: Vecāka lapa + field_editable: Rediģējams + field_watcher: Vērotājs + field_identity_url: OpenID URL + field_content: Saturs + field_group_by: Grupēt rezultātus pēc + field_sharing: Koplietošana + + setting_app_title: Programmas nosaukums + setting_app_subtitle: Programmas apakš-nosaukums + setting_welcome_text: Sveiciena teksts + setting_default_language: Noklusētā valoda + setting_login_required: Nepieciešama pilnvarošana + setting_self_registration: Pašreģistrēšanās + setting_attachment_max_size: Pielikuma maksimālais izmērs + setting_issues_export_limit: Uzdevumu eksporta ierobežojums + setting_mail_from: "E-pasta adrese informācijas nosūtīšanai" + setting_bcc_recipients: "Saņēmēju adreses neparādīsies citu saņēmēju vēstulēs (bcc)" + setting_plain_text_mail: "Vēstule brīvā tekstā (bez HTML)" + setting_host_name: Hosta nosaukums un piekļuves ceļš + setting_text_formatting: Teksta formatēšana + setting_wiki_compression: Wiki vēstures saspiešana + setting_feeds_limit: Barotnes satura ierobežojums + setting_default_projects_public: Jaunie projekti noklusēti ir publiski pieejami + setting_autofetch_changesets: "Automātiski lietot jaunāko versiju, pieslēdzoties repozitorijam (Autofetch)" + setting_sys_api_enabled: Ieslēgt WS repozitoriju menedžmentam + setting_commit_ref_keywords: Norādes atslēgvārdi + setting_commit_fix_keywords: Fiksējošie atslēgvārdi + setting_autologin: Automātiskā pieslēgšanās + setting_date_format: Datuma formāts + setting_time_format: Laika formāts + setting_cross_project_issue_relations: "Atļaut starp-projektu uzdevumu relācijas" + setting_issue_list_default_columns: Noklusēti rādītās kolonnas uzdevumu sarakstā + setting_emails_footer: "E-pastu kājene" + setting_protocol: Protokols + setting_per_page_options: Objekti vienā lapā + setting_user_format: Lietotāju rādīšanas formāts + setting_activity_days_default: Dienus skaits aktivitāšu rādīšanai aktivitāšu sadaļā + setting_display_subprojects_issues: Rādīt apakšprojekta uzdevumus galvenajā projektā pēc noklusējuma + setting_enabled_scm: Lietot SCM + setting_mail_handler_body_delimiters: "Saīsināt pēc vienas no šim rindām" + setting_mail_handler_api_enabled: "Lietot WS ienākošajiem e-pastiem" + setting_mail_handler_api_key: API atslēga + setting_sequential_project_identifiers: Ģenerēt secīgus projektu identifikatorus + setting_gravatar_enabled: Izmantot Gravatar lietotāju ikonas + setting_gravatar_default: Noklusētais Gravatar attēls + setting_diff_max_lines_displayed: Maksimālais rādīto diff rindu skaits + setting_file_max_size_displayed: Maksimālais izmērs iekļautajiem teksta failiem + setting_repository_log_display_limit: Maksimālais žurnāla datnē rādīto revīziju skaits + setting_openid: Atļaut OpenID pieslēgšanos un reģistrēšanos + setting_password_min_length: Minimālais paroles garums + setting_new_project_user_role_id: Loma, kura tiek piešķirta ne-administratora lietotājam, kurš izveido projektu + setting_default_projects_modules: Noklusētie lietotie moduļi jaunam projektam + setting_issue_done_ratio: Aprēķināt uzdevuma izpildes koeficientu ar + setting_issue_done_ratio_issue_field: uzdevuma lauku + setting_issue_done_ratio_issue_status: uzdevuma statusu + setting_start_of_week: Sākt kalendāru ar + setting_rest_api_enabled: Lietot REST web-servisu + setting_cache_formatted_text: Kešot formatētu tekstu + + permission_add_project: Izveidot projektu + permission_add_subprojects: Izveidot apakšprojektu + permission_edit_project: Rediģēt projektu + permission_select_project_modules: Izvēlēties projekta moduļus + permission_manage_members: Pārvaldīt dalībniekus + permission_manage_project_activities: Pārvaldīt projekta aktivitātes + permission_manage_versions: Pārvaldīt versijas + permission_manage_categories: Pārvaldīt uzdevumu kategorijas + permission_view_issues: Apskatīt uzdevumus + permission_add_issues: Pievienot uzdevumus + permission_edit_issues: Rediģēt uzdevumus + permission_manage_issue_relations: Pārvaldīt uzdevumu relācijas + permission_add_issue_notes: Pievienot piezīmes + permission_edit_issue_notes: Rediģēt piezīmes + permission_edit_own_issue_notes: Rediģēt paša piezīmes + permission_move_issues: Pārvietot uzdevumus + permission_delete_issues: Dzēst uzdevumus + permission_manage_public_queries: Pārvaldīt publiskos pieprasījumus + permission_save_queries: Saglabāt pieprasījumus + permission_view_gantt: Skatīt Ganta diagrammu + permission_view_calendar: Skatīt kalendāru + permission_view_issue_watchers: Skatīt vērotāju sarakstu + permission_add_issue_watchers: Pievienot vērotājus + permission_delete_issue_watchers: Dzēst vērotājus + permission_log_time: Piereģistrēt pavadīto laiku + permission_view_time_entries: Skatīt pavadīto laiku + permission_edit_time_entries: Rdiģēt laika reģistrus + permission_edit_own_time_entries: Rediģēt savus laika reģistrus + permission_manage_news: Pārvaldīt jaunumus + permission_comment_news: Komentēt jaunumus + permission_view_documents: Skatīt dokumentus + permission_manage_files: Pārvaldīt failus + permission_view_files: Skatīt failus + permission_manage_wiki: Pārvaldīt wiki + permission_rename_wiki_pages: Pārsaukt wiki lapas + permission_delete_wiki_pages: Dzēst wiki lapas + permission_view_wiki_pages: Skatīt wiki + permission_view_wiki_edits: Skatīt wiki vēsturi + permission_edit_wiki_pages: Rdiģēt wiki lapas + permission_delete_wiki_pages_attachments: Dzēst pielikumus + permission_protect_wiki_pages: Projekta wiki lapas + permission_manage_repository: Pārvaldīt repozitoriju + permission_browse_repository: Pārlūkot repozitoriju + permission_view_changesets: Skatīt izmaiņu kopumus + permission_commit_access: Atļaut piekļuvi + permission_manage_boards: Pārvaldīt ziņojumu dēļus + permission_view_messages: Skatīt ziņas + permission_add_messages: Publicēt ziņas + permission_edit_messages: Rediģēt ziņas + permission_edit_own_messages: Rediģēt savas ziņas + permission_delete_messages: Dzēst ziņas + permission_delete_own_messages: Dzēst savas ziņas + permission_export_wiki_pages: Eksportēt Wiki lapas + + project_module_issue_tracking: Uzdevumu uzskaite + project_module_time_tracking: Laika uzskaite + project_module_news: Jaunumi + project_module_documents: Dokumenti + project_module_files: Datnes + project_module_wiki: Wiki + project_module_repository: Repozitorijs + project_module_boards: Ziņojumu dēļi + + label_user: Lietotājs + label_user_plural: Lietotāji + label_user_new: Jauns lietotājs + label_user_anonymous: Anonīms + label_project: Projekts + label_project_new: Jauns projekts + label_project_plural: Projekti + label_x_projects: + zero: nav projektu + one: 1 projekts + other: "%{count} projekti" + label_project_all: Visi projekti + label_project_latest: Jaunākie projekti + label_issue: Uzdevums + label_issue_new: Jauns uzdevums + label_issue_plural: Uzdevumi + label_issue_view_all: Skatīt visus uzdevumus + label_issues_by: "Kārtot pēc %{value}" + label_issue_added: Uzdevums pievienots + label_issue_updated: Uzdevums atjaunots + label_document: Dokuments + label_document_new: Jauns dokuments + label_document_plural: Dokumenti + label_document_added: Dokuments pievienots + label_role: Loma + label_role_plural: Lomas + label_role_new: Jauna loma + label_role_and_permissions: Lomas un atļaujas + label_member: Dalībnieks + label_member_new: Jauns dalībnieks + label_member_plural: Dalībnieki + label_tracker: Trakeris + label_tracker_plural: Trakeri + label_tracker_new: Jauns trakeris + label_workflow: Darba gaita + label_issue_status: Uzdevuma statuss + label_issue_status_plural: Uzdevumu statusi + label_issue_status_new: Jauns statuss + label_issue_category: Uzdevuma kategorija + label_issue_category_plural: Uzdevumu kategorijas + label_issue_category_new: Jauna kategorija + label_custom_field: Pielāgojams lauks + label_custom_field_plural: Pielāgojami lauki + label_custom_field_new: Jauns pielāgojams lauks + label_enumerations: Uzskaitījumi + label_enumeration_new: Jauna vērtība + label_information: Informācija + label_information_plural: Informācija + label_please_login: Lūdzu pieslēdzieties + label_register: Reģistrēties + label_login_with_open_id_option: vai pieslēgties ar OpenID + label_password_lost: Nozaudēta parole + label_home: Sākums + label_my_page: Mana lapa + label_my_account: Mans konts + label_my_projects: Mani projekti + label_administration: Administrācija + label_login: Pieslēgties + label_logout: Atslēgties + label_help: Palīdzība + label_reported_issues: Ziņotie uzdevumi + label_assigned_to_me_issues: Man piesaistītie uzdevumi + label_last_login: Pēdējā pieslēgšanās + label_registered_on: Reģistrējies + label_activity: Aktivitāte + label_overall_activity: Kopējās aktivitātes + label_user_activity: "Lietotāja %{value} aktivitātes" + label_new: Jauns + label_logged_as: Pieslēdzies kā + label_environment: Vide + label_authentication: Pilnvarošana + label_auth_source: Pilnvarošanas režīms + label_auth_source_new: Jauns pilnvarošanas režīms + label_auth_source_plural: Pilnvarošanas režīmi + label_subproject_plural: Apakšprojekti + label_subproject_new: Jauns apakšprojekts + label_and_its_subprojects: "%{value} un tā apakšprojekti" + label_min_max_length: Minimālais - Maksimālais garums + label_list: Saraksts + label_date: Datums + label_integer: Vesels skaitlis + label_float: Decimālskaitlis + label_boolean: Patiesuma vērtība + label_string: Teksts + label_text: Garš teksts + label_attribute: Atribūts + label_attribute_plural: Atribūti + label_no_data: Nav datu, ko parādīt + label_change_status: Mainīt statusu + label_history: Vēsture + label_attachment: Pielikums + label_attachment_new: Jauns pielikums + label_attachment_delete: Dzēst pielikumu + label_attachment_plural: Pielikumi + label_file_added: Lauks pievienots + label_report: Atskaite + label_report_plural: Atskaites + label_news: Ziņa + label_news_new: Pievienot ziņu + label_news_plural: Ziņas + label_news_latest: Jaunākās ziņas + label_news_view_all: Skatīt visas ziņas + label_news_added: Ziņas pievienotas + label_settings: Iestatījumi + label_overview: Pārskats + label_version: Versija + label_version_new: Jauna versija + label_version_plural: Versijas + label_close_versions: Aizvērt pabeigtās versijas + label_confirmation: Apstiprinājums + label_export_to: 'Pieejams arī:' + label_read: Lasīt... + label_public_projects: Publiskie projekti + label_open_issues: atvērts + label_open_issues_plural: atvērti + label_closed_issues: slēgts + label_closed_issues_plural: slēgti + label_x_open_issues_abbr_on_total: + zero: 0 atvērti / %{total} + one: 1 atvērts / %{total} + other: "%{count} atvērti / %{total}" + label_x_open_issues_abbr: + zero: 0 atvērti + one: 1 atvērts + other: "%{count} atvērti" + label_x_closed_issues_abbr: + zero: 0 slēgti + one: 1 slēgts + other: "%{count} slēgti" + label_total: Kopā + label_permissions: Atļaujas + label_current_status: Pašreizējais statuss + label_new_statuses_allowed: Jauni statusi atļauti + label_all: visi + label_none: neviens + label_nobody: nekas + label_next: Nākošais + label_previous: Iepriekšējais + label_used_by: Izmanto + label_details: Detaļas + label_add_note: Pievienot piezīmi + label_per_page: katrā lapā + label_calendar: Kalendārs + label_months_from: mēneši no + label_gantt: Ganta diagramma + label_internal: Iekšējais + label_last_changes: "pēdējās %{count} izmaiņas" + label_change_view_all: Skatīt visas izmaiņas + label_personalize_page: Pielāgot šo lapu + label_comment: Komentārs + label_comment_plural: Komentāri + label_x_comments: + zero: nav komentāru + one: 1 komentārs + other: "%{count} komentāri" + label_comment_add: Pievienot komentāru + label_comment_added: Komentārs pievienots + label_comment_delete: Dzēst komentārus + label_query: Pielāgots pieprasījums + label_query_plural: Pielāgoti pieprasījumi + label_query_new: Jauns pieprasījums + label_filter_add: Pievienot filtru + label_filter_plural: Filtri + label_equals: ir + label_not_equals: nav + label_in_less_than: ir mazāk kā + label_in_more_than: ir vairāk kā + label_greater_or_equal: '>=' + label_less_or_equal: '<=' + label_in: iekš + label_today: šodien + label_all_time: visu laiku + label_yesterday: vakar + label_this_week: šonedēļ + label_last_week: pagājušo šonedēļ + label_last_n_days: "pēdējās %{count} dienas" + label_this_month: šomēnes + label_last_month: pagājušo mēnes + label_this_year: šogad + label_date_range: Datumu apgabals + label_less_than_ago: mazāk kā dienas iepriekš + label_more_than_ago: vairāk kā dienas iepriekš + label_ago: dienas iepriekš + label_contains: satur + label_not_contains: nesatur + label_day_plural: dienas + label_repository: Repozitorijs + label_repository_plural: Repozitoriji + label_browse: Pārlūkot + label_branch: Zars + label_tag: Birka + label_revision: Revīzija + label_revision_plural: Revīzijas + label_revision_id: "Revīzija %{value}" + label_associated_revisions: Saistītās revīzijas + label_added: pievienots + label_modified: modificēts + label_copied: nokopēts + label_renamed: pārsaukts + label_deleted: dzēsts + label_latest_revision: Pēdējā revīzija + label_latest_revision_plural: Pēdējās revīzijas + label_view_revisions: Skatīt revīzijas + label_view_all_revisions: Skatīt visas revīzijas + label_max_size: Maksimālais izmērs + label_sort_highest: Pārvietot uz augšu + label_sort_higher: Pārvietot soli augšup + label_sort_lower: Pārvietot uz leju + label_sort_lowest: Pārvietot vienu soli uz leju + label_roadmap: Ceļvedis + label_roadmap_due_in: "Sagaidāms pēc %{value}" + label_roadmap_overdue: "nokavēts %{value}" + label_roadmap_no_issues: Šai versijai nav uzdevumu + label_search: Meklēt + label_result_plural: Rezultāti + label_all_words: Visi vārdi + label_wiki: Wiki + label_wiki_edit: Wiki labojums + label_wiki_edit_plural: Wiki labojumi + label_wiki_page: Wiki lapa + label_wiki_page_plural: Wiki lapas + label_index_by_title: Indeksēt pēc nosaukuma + label_index_by_date: Indeksēt pēc datuma + label_current_version: Tekošā versija + label_preview: Priekšskatījums + label_feed_plural: Barotnes + label_changes_details: Visu izmaiņu detaļas + label_issue_tracking: Uzdevumu uzskaite + label_spent_time: Pavadītais laiks + label_f_hour: "%{value} stunda" + label_f_hour_plural: "%{value} stundas" + label_time_tracking: Laika uzskaite + label_change_plural: Izmaiņas + label_statistics: Statistika + label_commits_per_month: Nodevumi mēnesī + label_commits_per_author: Nodevumi no autora + label_view_diff: Skatīt atšķirības + label_diff_inline: iekļauts + label_diff_side_by_side: blakus + label_options: Opcijas + label_copy_workflow_from: Kopēt darba plūsmu no + label_permissions_report: Atļauju atskaite + label_watched_issues: Vērotie uzdevumi + label_related_issues: Saistītie uzdevumi + label_applied_status: Piešķirtais statuss + label_loading: Lādējas... + label_relation_new: Jauna relācija + label_relation_delete: Dzēst relāciju + label_relates_to: saistīts ar + label_duplicates: dublikāti + label_duplicated_by: dublējas ar + label_blocks: bloķē + label_blocked_by: nobloķējis + label_precedes: pirms + label_follows: seko + label_end_to_start: no beigām uz sākumu + label_end_to_end: no beigām uz beigām + label_start_to_start: no sākuma uz sākumu + label_start_to_end: no sākuma uz beigām + label_stay_logged_in: Atcerēties mani + label_disabled: izslēgts + label_show_completed_versions: Rādīt pabeigtās versijas + label_me: es + label_board: Forums + label_board_new: Jauns forums + label_board_plural: Forumi + label_board_locked: Slēgts + label_board_sticky: Svarīgs + label_topic_plural: Tēmas + label_message_plural: Ziņas + label_message_last: Pēdējā ziņa + label_message_new: Jauna ziņa + label_message_posted: Ziņa pievienota + label_reply_plural: Atbildes + label_send_information: Sūtīt konta informāciju lietotājam + label_year: Gads + label_month: Mēnesis + label_week: Nedēļa + label_date_from: No + label_date_to: Kam + label_language_based: Izmantot lietotāja valodu + label_sort_by: "Kārtot pēc %{value}" + label_send_test_email: "Sūtīt testa e-pastu" + label_feeds_access_key: RSS piekļuves atslēga + label_missing_feeds_access_key: Trūkst RSS piekļuves atslēgas + label_feeds_access_key_created_on: "RSS piekļuves atslēga izveidota pirms %{value}" + label_module_plural: Moduļi + label_added_time_by: "Pievienojis %{author} pirms %{age}" + label_updated_time_by: "Atjaunojis %{author} pirms %{age}" + label_updated_time: "Atjaunots pirms %{value}" + label_jump_to_a_project: Pāriet uz projektu... + label_file_plural: Datnes + label_changeset_plural: Izmaiņu kopumi + label_default_columns: Noklusētās kolonnas + label_no_change_option: (Nav izmaiņu) + label_bulk_edit_selected_issues: Labot visus izvēlētos uzdevumus + label_theme: Tēma + label_default: Noklusēts + label_search_titles_only: Meklēt tikai nosaukumos + label_user_mail_option_all: "Par visiem notikumiem visos manos projektos" + label_user_mail_option_selected: "Par visiem notikumiem tikai izvēlētajos projektos..." + label_user_mail_no_self_notified: "Neziņot man par izmaiņām, kuras veicu es pats" + label_registration_activation_by_email: "konta aktivizācija caur e-pastu" + label_registration_manual_activation: manuālā konta aktivizācija + label_registration_automatic_activation: automātiskā konta aktivizācija + label_display_per_page: "Rādīt vienā lapā: %{value}" + label_age: Vecums + label_change_properties: Mainīt atribūtus + label_general: Galvenais + label_more: Vēl + label_scm: SCM + label_plugins: Spraudņi + label_ldap_authentication: LDAP pilnvarošana + label_downloads_abbr: L-lād. + label_optional_description: "Apraksts (neobligāts)" + label_add_another_file: Pievienot citu failu + label_preferences: Priekšrocības + label_chronological_order: Hronoloģiskā kārtībā + label_reverse_chronological_order: Apgriezti hronoloģiskā kārtībā + label_planning: Plānošana + label_incoming_emails: "Ienākošie e-pasti" + label_generate_key: Ģenerēt atslēgu + label_issue_watchers: Vērotāji + label_example: Piemērs + label_display: Rādīt + label_sort: Kārtot + label_ascending: Augoši + label_descending: Dilstoši + label_date_from_to: "No %{start} līdz %{end}" + label_wiki_content_added: Wiki lapa pievienota + label_wiki_content_updated: Wiki lapa atjaunota + label_group: Grupa + label_group_plural: Grupas + label_group_new: Jauna grupa + label_time_entry_plural: Pavadītais laiks + label_version_sharing_none: Nav koplietošanai + label_version_sharing_descendants: Ar apakšprojektiem + label_version_sharing_hierarchy: Ar projektu hierarhiju + label_version_sharing_tree: Ar projekta koku + label_version_sharing_system: Ar visiem projektiem + label_update_issue_done_ratios: Atjaunot uzdevuma veikuma attiecību + label_copy_source: Avots + label_copy_target: Mērķis + label_copy_same_as_target: Tāds pats kā mērķis + label_display_used_statuses_only: "Rādīt tikai statusus, ko lieto šis trakeris" + label_api_access_key: API pieejas atslēga + label_missing_api_access_key: Trūkst API pieejas atslēga + label_api_access_key_created_on: "API pieejas atslēga izveidota pirms %{value}" + + button_login: Pieslēgties + button_submit: Nosūtīt + button_save: Saglabāt + button_check_all: Atzīmēt visu + button_uncheck_all: Noņemt visus atzīmējumus + button_delete: Dzēst + button_create: Izveidot + button_create_and_continue: Izveidot un turpināt + button_test: Testēt + button_edit: Labot + button_add: Pievienot + button_change: Mainīt + button_apply: Apstiprināt + button_clear: Notīrīt + button_lock: Slēgt + button_unlock: Atslēgt + button_download: Lejuplādēt + button_list: Saraksts + button_view: Skats + button_move: Pārvietot + button_move_and_follow: Pārvietot un sekot + button_back: Atpakaļ + button_cancel: Atcelt + button_activate: Aktivizēt + button_sort: Kārtot + button_log_time: Ilgs laiks + button_rollback: Atjaunot uz šo versiju + button_watch: Vērot + button_unwatch: Nevērot + button_reply: Atbildēt + button_archive: Arhivēt + button_unarchive: Atarhivēt + button_reset: Atiestatīt + button_rename: Pārsaukt + button_change_password: Mainīt paroli + button_copy: Kopēt + button_copy_and_follow: Kopēt un sekot + button_annotate: Pierakstīt paskaidrojumu + button_update: Atjaunot + button_configure: Konfigurēt + button_quote: Citāts + button_duplicate: Dublēt + button_show: Rādīt + + status_active: aktīvs + status_registered: reģistrēts + status_locked: slēgts + + version_status_open: atvērta + version_status_locked: slēgta + version_status_closed: aizvērta + + field_active: Aktīvs + + text_select_mail_notifications: "Izvēlieties darbības, par kurām vēlaties saņemt ziņojumus e-pastā" + text_regexp_info: "piem. ^[A-Z0-9]+$" + text_min_max_length_info: "0 nozīmē, ka nav ierobežojumu" + text_project_destroy_confirmation: "Vai tiešām vēlaties dzēst šo projektu un ar to saistītos datus?" + text_subprojects_destroy_warning: "Tā apakšprojekts(i): %{value} arī tiks dzēsts(i)." + text_workflow_edit: Lai labotu darba plūsmu, izvēlieties lomu un trakeri + text_are_you_sure: "Vai esat pārliecināts?" + text_journal_changed: "%{label} mainīts no %{old} uz %{new}" + text_journal_set_to: "%{label} iestatīts uz %{value}" + text_journal_deleted: "%{label} dzēsts (%{old})" + text_journal_added: "%{label} %{value} pievienots" + text_tip_issue_begin_day: uzdevums sākas šodien + text_tip_issue_end_day: uzdevums beidzas šodien + text_tip_issue_begin_end_day: uzdevums sākas un beidzas šodien + text_caracters_maximum: "%{count} simboli maksimāli." + text_caracters_minimum: "Jābūt vismaz %{count} simbolu garumā." + text_length_between: "Garums starp %{min} un %{max} simboliem." + text_tracker_no_workflow: Šim trakerim nav definēta darba plūsma + text_unallowed_characters: Neatļauti simboli + text_comma_separated: "Atļautas vairākas vērtības (atdalīt ar komatu)." + text_line_separated: "Atļautas vairākas vērtības (rakstīt katru savā rindā)." + text_issues_ref_in_commit_messages: "Izmaiņu salīdzināšana izejot no ziņojumiem" + text_issue_added: "Uzdevumu %{id} pievienojis %{author}." + text_issue_updated: "Uzdevumu %{id} atjaunojis %{author}." + text_wiki_destroy_confirmation: "Vai esat drošs, ka vēlaties dzēst šo wiki un visu tās saturu?" + text_issue_category_destroy_question: "Daži uzdevumi (%{count}) ir nozīmēti šai kategorijai. Ko Jūs vēlaties darīt?" + text_issue_category_destroy_assignments: Dzēst kategoriju nozīmējumus + text_issue_category_reassign_to: Nozīmēt uzdevumus šai kategorijai + text_user_mail_option: "No neizvēlētajiem projektiem Jūs saņemsiet ziņojumus e-pastā tikai par notikumiem, kuriem Jūs sekojat vai kuros esat iesaistīts." + text_no_configuration_data: "Lomas, trakeri, uzdevumu statusi un darba plūsmas vēl nav konfigurētas.\nĻoti ieteicams ielādēt noklusēto konfigurāciju. Pēc ielādēšanas to būs iespējams modificēt." + text_load_default_configuration: Ielādēt noklusēto konfigurāciju + text_status_changed_by_changeset: "Apstiprināts izmaiņu kopumā %{value}." + text_issues_destroy_confirmation: 'Vai tiešām vēlaties dzēst izvēlēto uzdevumu(us)?' + text_select_project_modules: 'Izvēlieties moduļus šim projektam:' + text_default_administrator_account_changed: Noklusētais administratora konts mainīts + text_file_repository_writable: Pielikumu direktorijā atļauts rakstīt + text_plugin_assets_writable: Spraudņu kataloga direktorijā atļauts rakstīt + text_rmagick_available: "RMagick pieejams (neobligāts)" + text_destroy_time_entries_question: "%{hours} stundas tika ziņotas par uzdevumu, ko vēlaties dzēst. Ko darīt?" + text_destroy_time_entries: Dzēst ziņotās stundas + text_assign_time_entries_to_project: Piešķirt ziņotās stundas projektam + text_reassign_time_entries: 'Piešķirt ziņotās stundas uzdevumam:' + text_user_wrote: "%{value} rakstīja:" + text_enumeration_destroy_question: "%{count} objekti ir piešķirti šai vērtībai." + text_enumeration_category_reassign_to: 'Piešķirt tos šai vērtībai:' + text_email_delivery_not_configured: "E-pastu nosūtīšana nav konfigurēta, un ziņojumi ir izslēgti.\nKonfigurējiet savu SMTP serveri datnē config/configuration.yml un pārstartējiet lietotni." + text_repository_usernames_mapping: "Izvēlieties vai atjaunojiet Redmine lietotāju, saistītu ar katru lietotājvārdu, kas atrodams repozitorija žurnālā.\nLietotāji ar to pašu Redmine un repozitorija lietotājvārdu būs saistīti automātiski." + text_diff_truncated: '... Šis diff tika nošķelts, jo tas pārsniedz maksimālo izmēru, ko var parādīt.' + text_custom_field_possible_values_info: 'Katra vērtības savā rindā' + text_wiki_page_destroy_question: "Šij lapai ir %{descendants} apakšlapa(as) un pēcnācēji. Ko darīt?" + text_wiki_page_nullify_children: "Paturēt apakšlapas kā pamatlapas" + text_wiki_page_destroy_children: "Dzēst apakšlapas un visus pēcnācējus" + text_wiki_page_reassign_children: "Piešķirt apakšlapas šai lapai" + text_own_membership_delete_confirmation: "Jūs tūlīt dzēsīsiet dažas vai visas atļaujas, un Jums pēc tam var nebūt atļauja labot šo projektu.\nVai turpināt?" + + default_role_manager: Menedžeris + default_role_developer: Izstrādātājs + default_role_reporter: Ziņotājs + default_tracker_bug: Kļūda + default_tracker_feature: Iezīme + default_tracker_support: Atbalsts + default_issue_status_new: Jauns + default_issue_status_in_progress: Attīstībā + default_issue_status_resolved: Atrisināts + default_issue_status_feedback: Atsauksmes + default_issue_status_closed: Slēgts + default_issue_status_rejected: Noraidīts + default_doc_category_user: Lietotāja dokumentācija + default_doc_category_tech: Tehniskā dokumentācija + default_priority_low: Zema + default_priority_normal: Normāla + default_priority_high: Augsta + default_priority_urgent: Steidzama + default_priority_immediate: Tūlītēja + default_activity_design: Dizains + default_activity_development: Izstrādāšana + + enumeration_issue_priorities: Uzdevumu prioritātes + enumeration_doc_categories: Dokumentu kategorijas + enumeration_activities: Aktivitātes (laika uzskaite) + enumeration_system_activity: Sistēmas aktivitātes + + error_can_not_delete_custom_field: Unable to delete custom field + permission_manage_subtasks: Manage subtasks + label_profile: Profile + error_unable_to_connect: Unable to connect (%{value}) + error_can_not_remove_role: This role is in use and can not be deleted. + field_parent_issue: Parent task + error_unable_delete_issue_status: Unable to delete issue status + label_subtask_plural: Subtasks + error_can_not_delete_tracker: This tracker contains issues and can't be deleted. + label_project_copy_notifications: Send email notifications during the project copy + field_principal: Principal + label_my_page_block: My page block + notice_failed_to_save_members: "Failed to save member(s): %{errors}." + text_zoom_out: Zoom out + text_zoom_in: Zoom in + notice_unable_delete_time_entry: Unable to delete time log entry. + label_overall_spent_time: Overall spent time + field_time_entries: Log time + project_module_gantt: Gantt + project_module_calendar: Calendar + button_edit_associated_wikipage: "Edit associated Wiki page: %{page_title}" + field_text: Text field + label_user_mail_option_only_owner: Only for things I am the owner of + setting_default_notification_option: Default notification option + label_user_mail_option_only_my_events: Only for things I watch or I'm involved in + label_user_mail_option_only_assigned: Only for things I am assigned to + label_user_mail_option_none: No events + field_member_of_group: Assignee's group + field_assigned_to_role: Assignee's role + notice_not_authorized_archived_project: The project you're trying to access has been archived. + label_principal_search: "Search for user or group:" + label_user_search: "Search for user:" + field_visible: Visible + setting_commit_logtime_activity_id: Activity for logged time + text_time_logged_by_changeset: Applied in changeset %{value}. + setting_commit_logtime_enabled: Enable time logging + notice_gantt_chart_truncated: The chart was truncated because it exceeds the maximum number of items that can be displayed (%{max}) + setting_gantt_items_limit: Maximum number of items displayed on the gantt chart + field_warn_on_leaving_unsaved: Warn me when leaving a page with unsaved text + text_warn_on_leaving_unsaved: The current page contains unsaved text that will be lost if you leave this page. + label_my_queries: My custom queries + text_journal_changed_no_detail: "%{label} updated" + label_news_comment_added: Comment added to a news + button_expand_all: Expand all + button_collapse_all: Collapse all + label_additional_workflow_transitions_for_assignee: Additional transitions allowed when the user is the assignee + label_additional_workflow_transitions_for_author: Additional transitions allowed when the user is the author + label_bulk_edit_selected_time_entries: Bulk edit selected time entries + text_time_entries_destroy_confirmation: Are you sure you want to delete the selected time entr(y/ies)? + label_role_anonymous: Anonymous + label_role_non_member: Non member + label_issue_note_added: Note added + label_issue_status_updated: Status updated + label_issue_priority_updated: Priority updated + label_issues_visibility_own: Issues created by or assigned to the user + field_issues_visibility: Issues visibility + label_issues_visibility_all: All issues + permission_set_own_issues_private: Set own issues public or private + field_is_private: Private + permission_set_issues_private: Set issues public or private + label_issues_visibility_public: All non private issues + text_issues_destroy_descendants_confirmation: This will also delete %{count} subtask(s). + field_commit_logs_encoding: Kodēt ziņojumus + field_scm_path_encoding: Path encoding + text_scm_path_encoding_note: "Default: UTF-8" + field_path_to_repository: Path to repository + field_root_directory: Root directory + field_cvs_module: Module + field_cvsroot: CVSROOT + text_mercurial_repository_note: Local repository (e.g. /hgrepo, c:\hgrepo) + text_scm_command: Command + text_scm_command_version: Version + label_git_report_last_commit: Report last commit for files and directories + notice_issue_successful_create: Issue %{id} created. + label_between: between + setting_issue_group_assignment: Allow issue assignment to groups + label_diff: diff + text_git_repository_note: Repository is bare and local (e.g. /gitrepo, c:\gitrepo) + description_query_sort_criteria_direction: Sort direction + description_project_scope: Search scope + description_filter: Filter + description_user_mail_notification: Mail notification settings + description_date_from: Enter start date + description_message_content: Message content + description_available_columns: Available Columns + description_date_range_interval: Choose range by selecting start and end date + description_issue_category_reassign: Choose issue category + description_search: Searchfield + description_notes: Notes + description_date_range_list: Choose range from list + description_choose_project: Projects + description_date_to: Enter end date + description_query_sort_criteria_attribute: Sort attribute + description_wiki_subpages_reassign: Choose new parent page + description_selected_columns: Selected Columns + label_parent_revision: Parent + label_child_revision: Child + error_scm_annotate_big_text_file: The entry cannot be annotated, as it exceeds the maximum text file size. + setting_default_issue_start_date_to_creation_date: Use current date as start date for new issues + button_edit_section: Edit this section + setting_repositories_encodings: Attachments and repositories encodings + description_all_columns: All Columns + button_export: Export + label_export_options: "%{export_format} export options" + error_attachment_too_big: This file cannot be uploaded because it exceeds the maximum allowed file size (%{max_size}) + notice_failed_to_save_time_entries: "Failed to save %{count} time entrie(s) on %{total} selected: %{ids}." + label_x_issues: + zero: 0 uzdevums + one: 1 uzdevums + other: "%{count} uzdevumi" + label_repository_new: New repository + field_repository_is_default: Main repository + label_copy_attachments: Copy attachments + label_item_position: "%{position}/%{count}" + label_completed_versions: Completed versions + text_project_identifier_info: Only lower case letters (a-z), numbers, dashes and underscores are allowed.
    Once saved, the identifier cannot be changed. + field_multiple: Multiple values + setting_commit_cross_project_ref: Allow issues of all the other projects to be referenced and fixed + text_issue_conflict_resolution_add_notes: Add my notes and discard my other changes + text_issue_conflict_resolution_overwrite: Apply my changes anyway (previous notes will be kept but some changes may be overwritten) + notice_issue_update_conflict: The issue has been updated by an other user while you were editing it. + text_issue_conflict_resolution_cancel: Discard all my changes and redisplay %{link} + permission_manage_related_issues: Manage related issues + field_auth_source_ldap_filter: LDAP filter + label_search_for_watchers: Search for watchers to add + notice_account_deleted: Your account has been permanently deleted. + setting_unsubscribe: Allow users to delete their own account + button_delete_my_account: Delete my account + text_account_destroy_confirmation: |- + Are you sure you want to proceed? + Your account will be permanently deleted, with no way to reactivate it. + error_session_expired: Your session has expired. Please login again. + text_session_expiration_settings: "Warning: changing these settings may expire the current sessions including yours." + setting_session_lifetime: Session maximum lifetime + setting_session_timeout: Session inactivity timeout + label_session_expiration: Session expiration + permission_close_project: Close / reopen the project + label_show_closed_projects: View closed projects + button_close: Close + button_reopen: Reopen + project_status_active: active + project_status_closed: closed + project_status_archived: archived + text_project_closed: This project is closed and read-only. + notice_user_successful_create: User %{id} created. + field_core_fields: Standard fields + field_timeout: Timeout (in seconds) + setting_thumbnails_enabled: Display attachment thumbnails + setting_thumbnails_size: Thumbnails size (in pixels) + label_status_transitions: Status transitions + label_fields_permissions: Fields permissions + label_readonly: Read-only + label_required: Required + text_repository_identifier_info: Only lower case letters (a-z), numbers, dashes and underscores are allowed.
    Once saved, the identifier cannot be changed. + field_board_parent: Parent forum + label_attribute_of_project: Project's %{name} + label_attribute_of_author: Author's %{name} + label_attribute_of_assigned_to: Assignee's %{name} + label_attribute_of_fixed_version: Target version's %{name} + label_copy_subtasks: Copy subtasks + label_copied_to: copied to + label_copied_from: copied from + label_any_issues_in_project: any issues in project + label_any_issues_not_in_project: any issues not in project + field_private_notes: Private notes + permission_view_private_notes: View private notes + permission_set_notes_private: Set notes as private + label_no_issues_in_project: no issues in project + label_any: visi + label_last_n_weeks: last %{count} weeks + setting_cross_project_subtasks: Allow cross-project subtasks + label_cross_project_descendants: Ar apakšprojektiem + label_cross_project_tree: Ar projekta koku + label_cross_project_hierarchy: Ar projektu hierarhiju + label_cross_project_system: Ar visiem projektiem + button_hide: Hide + setting_non_working_week_days: Non-working days + label_in_the_next_days: in the next + label_in_the_past_days: in the past + label_attribute_of_user: User's %{name} + text_turning_multiple_off: If you disable multiple values, multiple values will be + removed in order to preserve only one value per item. + label_attribute_of_issue: Issue's %{name} + permission_add_documents: Add documents + permission_edit_documents: Edit documents + permission_delete_documents: Delete documents + label_gantt_progress_line: Progress line + setting_jsonp_enabled: Enable JSONP support + field_inherit_members: Inherit members + field_closed_on: Closed + setting_default_projects_tracker_ids: Default trackers for new projects + label_total_time: Kopā + text_scm_config: You can configure your SCM commands in config/configuration.yml. Please restart the application after editing it. + text_scm_command_not_available: SCM command is not available. Please check settings on the administration panel. + setting_emails_header: Email header diff --git a/config/locales/mk.yml b/config/locales/mk.yml new file mode 100644 index 00000000..61b219c3 --- /dev/null +++ b/config/locales/mk.yml @@ -0,0 +1,1089 @@ +mk: + # Text direction: Left-to-Right (ltr) or Right-to-Left (rtl) + direction: ltr + date: + formats: + # Use the strftime parameters for formats. + # When no format has been given, it uses default. + # You can provide other formats here if you like! + default: "%d/%m/%Y" + short: "%d %b" + long: "%d %B, %Y" + + day_names: [недела, понеделник, вторник, среда, четврток, петок, сабота] + abbr_day_names: [нед, пон, вто, сре, чет, пет, саб] + + # Don't forget the nil at the beginning; there's no such thing as a 0th month + month_names: [~, јануари, февруари, март, април, мај, јуни, јули, август, септември, октомври, ноември, декември] + abbr_month_names: [~, јан, фев, мар, апр, мај, јун, јул, авг, сеп, окт, ное, дек] + # Used in date_select and datime_select. + order: + - :day + - :month + - :year + + time: + formats: + default: "%d/%m/%Y %H:%M" + time: "%H:%M" + short: "%d %b %H:%M" + long: "%d %B, %Y %H:%M" + am: "предпладне" + pm: "попладне" + + datetime: + distance_in_words: + half_a_minute: "пола минута" + less_than_x_seconds: + one: "помалку од 1 секунда" + other: "помалку од %{count} секунди" + x_seconds: + one: "1 секунда" + other: "%{count} секунди" + less_than_x_minutes: + one: "помалку од 1 минута" + other: "помалку од %{count} минути" + x_minutes: + one: "1 минута" + other: "%{count} минути" + about_x_hours: + one: "околу 1 час" + other: "околу %{count} часа" + x_hours: + one: "1 hour" + other: "%{count} hours" + x_days: + one: "1 ден" + other: "%{count} дена" + about_x_months: + one: "околу 1 месец" + other: "околу %{count} месеци" + x_months: + one: "1 месец" + other: "%{count} месеци" + about_x_years: + one: "околу 1 година" + other: "околу %{count} години" + over_x_years: + one: "преку 1 година" + other: "преку %{count} години" + almost_x_years: + one: "скоро 1 година" + other: "скоро %{count} години" + + number: + # Default format for numbers + format: + separator: "." + delimiter: "" + precision: 3 + human: + format: + delimiter: "" + precision: 3 + storage_units: + format: "%n %u" + units: + byte: + one: "Byte" + other: "Bytes" + kb: "KB" + mb: "MB" + gb: "GB" + tb: "TB" + + +# Used in array.to_sentence. + support: + array: + sentence_connector: "и" + skip_last_comma: false + + activerecord: + errors: + template: + header: + one: "1 error prohibited this %{model} from being saved" + other: "%{count} errors prohibited this %{model} from being saved" + messages: + inclusion: "не е вклучено во листата" + exclusion: "е резервирано" + invalid: "е невалидно" + confirmation: "не се совпаѓа со потврдата" + accepted: "мора да е прифатено" + empty: "неможе да е празно" + blank: "неможе да е празно" + too_long: "е предолго (макс. %{count} знаци)" + too_short: "е прекратко (мин. %{count} знаци)" + wrong_length: "е погрешна должина (треба да е %{count} знаци)" + taken: "е веќе зафатено" + not_a_number: "не е број" + not_a_date: "не е валидна дата" + greater_than: "мора да е поголемо од %{count}" + greater_than_or_equal_to: "мора да е поголемо или еднакво на %{count}" + equal_to: "мора да е еднакво на %{count}" + less_than: "мора да е помало од %{count}" + less_than_or_equal_to: "мора да е помало или еднакво на %{count}" + odd: "мора да е непарно" + even: "мора да е парно" + greater_than_start_date: "мора да е поголема од почетната дата" + not_same_project: "не припаѓа на истиот проект" + circular_dependency: "Оваа врска ќе креира кружна зависност" + cant_link_an_issue_with_a_descendant: "Задача неможе да се поврзе со една од нејзините подзадачи" + + actionview_instancetag_blank_option: Изберете + + general_text_No: 'Не' + general_text_Yes: 'Да' + general_text_no: 'не' + general_text_yes: 'да' + general_lang_name: 'Macedonian (Македонски)' + general_csv_separator: ',' + general_csv_decimal_separator: '.' + general_csv_encoding: UTF-8 + general_pdf_encoding: UTF-8 + general_first_day_of_week: '1' + + notice_account_updated: Профилот е успешно ажуриран. + notice_account_invalid_creditentials: Неточен корисник или лозинка + notice_account_password_updated: Лозинката е успешно ажурирана. + notice_account_wrong_password: Погрешна лозинка + notice_account_register_done: Профилот е успешно креиран. За активација, клкнете на врската што ви е пратена по е-пошта. + notice_account_unknown_email: Непознат корисник. + notice_can_t_change_password: This account uses an external authentication source. Impossible to change the password. + notice_account_lost_email_sent: An email with instructions to choose a new password has been sent to you. + notice_account_activated: Your account has been activated. You can now log in. + notice_successful_create: Успешно креирање. + notice_successful_update: Успешно ажурирање. + notice_successful_delete: Успешно бришење. + notice_successful_connection: Успешна конекција. + notice_file_not_found: The page you were trying to access doesn't exist or has been removed. + notice_locking_conflict: Data has been updated by another user. + notice_not_authorized: You are not authorized to access this page. + notice_email_sent: "Е-порака е пратена на %{value}" + notice_email_error: "Се случи грешка при праќање на е-пораката (%{value})" + notice_feeds_access_key_reseted: Вашиот RSS клуч за пристап е reset. + notice_api_access_key_reseted: Вашиот API клуч за пристап е reset. + notice_failed_to_save_issues: "Failed to save %{count} issue(s) on %{total} selected: %{ids}." + notice_failed_to_save_members: "Failed to save member(s): %{errors}." + notice_no_issue_selected: "No issue is selected! Please, check the issues you want to edit." + notice_account_pending: "Your account was created and is now pending administrator approval." + notice_default_data_loaded: Default configuration successfully loaded. + notice_unable_delete_version: Unable to delete version. + notice_unable_delete_time_entry: Unable to delete time log entry. + notice_issue_done_ratios_updated: Issue done ratios updated. + + error_can_t_load_default_data: "Default configuration could not be loaded: %{value}" + error_scm_not_found: "The entry or revision was not found in the repository." + error_scm_command_failed: "An error occurred when trying to access the repository: %{value}" + error_scm_annotate: "The entry does not exist or can not be annotated." + error_issue_not_found_in_project: 'The issue was not found or does not belong to this project' + error_no_tracker_in_project: 'No tracker is associated to this project. Please check the Project settings.' + error_no_default_issue_status: 'No default issue status is defined. Please check your configuration (Go to "Administration -> Issue statuses").' + error_can_not_delete_custom_field: Unable to delete custom field + error_can_not_delete_tracker: "This tracker contains issues and can't be deleted." + error_can_not_remove_role: "This role is in use and can not be deleted." + error_can_not_reopen_issue_on_closed_version: 'An issue assigned to a closed version can not be reopened' + error_can_not_archive_project: This project can not be archived + error_issue_done_ratios_not_updated: "Issue done ratios not updated." + error_workflow_copy_source: 'Please select a source tracker or role' + error_workflow_copy_target: 'Please select target tracker(s) and role(s)' + error_unable_delete_issue_status: 'Unable to delete issue status' + error_unable_to_connect: "Unable to connect (%{value})" + warning_attachments_not_saved: "%{count} file(s) could not be saved." + + mail_subject_lost_password: "Вашата %{value} лозинка" + mail_body_lost_password: 'To change your password, click on the following link:' + mail_subject_register: "Your %{value} account activation" + mail_body_register: 'To activate your account, click on the following link:' + mail_body_account_information_external: "You can use your %{value} account to log in." + mail_body_account_information: Your account information + mail_subject_account_activation_request: "%{value} account activation request" + mail_body_account_activation_request: "Нов корисник (%{value}) е регистриран. The account is pending your approval:" + mail_subject_reminder: "%{count} issue(s) due in the next %{days} days" + mail_body_reminder: "%{count} issue(s) that are assigned to you are due in the next %{days} days:" + mail_subject_wiki_content_added: "'%{id}' wiki page has been added" + mail_body_wiki_content_added: "The '%{id}' wiki page has been added by %{author}." + mail_subject_wiki_content_updated: "'%{id}' wiki page has been updated" + mail_body_wiki_content_updated: "The '%{id}' wiki page has been updated by %{author}." + + + field_name: Име + field_description: Опис + field_summary: Краток опис + field_is_required: Задолжително + field_firstname: Име + field_lastname: Презиме + field_mail: Е-пошта + field_filename: Датотека + field_filesize: Големина + field_downloads: Превземања + field_author: Автор + field_created_on: Креиран + field_updated_on: Ажурирано + field_field_format: Формат + field_is_for_all: За сите проекти + field_possible_values: Можни вредности + field_regexp: Regular expression + field_min_length: Минимална должина + field_max_length: Максимална должина + field_value: Вредност + field_category: Категорија + field_title: Наслов + field_project: Проект + field_issue: Задача + field_status: Статус + field_notes: Белешки + field_is_closed: Задачата е затворена + field_is_default: Default value + field_tracker: Tracker + field_subject: Наслов + field_due_date: Краен рок + field_assigned_to: Доделена на + field_priority: Приоритет + field_fixed_version: Target version + field_user: Корисник + field_principal: Principal + field_role: Улога + field_homepage: Веб страна + field_is_public: Јавен + field_parent: Подпроект на + field_is_in_roadmap: Issues displayed in roadmap + field_login: Корисник + field_mail_notification: Известувања по e-пошта + field_admin: Администратор + field_last_login_on: Последна најава + field_language: Јазик + field_effective_date: Дата + field_password: Лозинка + field_new_password: Нова лозинка + field_password_confirmation: Потврда + field_version: Верзија + field_type: Тип + field_host: Хост + field_port: Порт + field_account: Account + field_base_dn: Base DN + field_attr_login: Login attribute + field_attr_firstname: Firstname attribute + field_attr_lastname: Lastname attribute + field_attr_mail: Email attribute + field_onthefly: Моментално (On-the-fly) креирање на корисници + field_start_date: Почеток + field_done_ratio: "% Завршено" + field_auth_source: Режим на автентикација + field_hide_mail: Криј ја мојата адреса на е-пошта + field_comments: Коментар + field_url: URL + field_start_page: Почетна страна + field_subproject: Подпроект + field_hours: Часови + field_activity: Активност + field_spent_on: Дата + field_identifier: Идентификатор + field_is_filter: Користи како филтер + field_issue_to: Поврзана задача + field_delay: Доцнење + field_assignable: На оваа улога може да се доделуваат задачи + field_redirect_existing_links: Пренасочи ги постоечките врски + field_estimated_hours: Проценето време + field_column_names: Колони + field_time_entries: Бележи време + field_time_zone: Временска зона + field_searchable: Може да се пребарува + field_default_value: Default value + field_comments_sorting: Прикажувај коментари + field_parent_title: Parent page + field_editable: Може да се уредува + field_watcher: Watcher + field_identity_url: OpenID URL + field_content: Содржина + field_group_by: Групирај ги резултатите според + field_sharing: Споделување + field_parent_issue: Parent task + + setting_app_title: Наслов на апликацијата + setting_app_subtitle: Поднаслов на апликацијата + setting_welcome_text: Текст за добредојде + setting_default_language: Default јазик + setting_login_required: Задолжителна автентикација + setting_self_registration: Само-регистрација + setting_attachment_max_size: Макс. големина на прилог + setting_issues_export_limit: Issues export limit + setting_mail_from: Emission email address + setting_bcc_recipients: Blind carbon copy recipients (bcc) + setting_plain_text_mail: Текстуални е-пораки (без HTML) + setting_host_name: Име на хост и патека + setting_text_formatting: Форматирање на текст + setting_wiki_compression: Компресија на историјата на вики + setting_feeds_limit: Feed content limit + setting_default_projects_public: Новите проекти се иницијално јавни + setting_autofetch_changesets: Autofetch commits + setting_sys_api_enabled: Enable WS for repository management + setting_commit_ref_keywords: Referencing keywords + setting_commit_fix_keywords: Fixing keywords + setting_autologin: Автоматска најава + setting_date_format: Формат на дата + setting_time_format: Формат на време + setting_cross_project_issue_relations: Дозволи релации на задачи меѓу проекти + setting_issue_list_default_columns: Default columns displayed on the issue list + setting_protocol: Протокол + setting_per_page_options: Objects per page options + setting_user_format: Приказ на корисниците + setting_activity_days_default: Денови прикажана во активноста на проектот + setting_display_subprojects_issues: Прикажи ги задачите на подпроектите во главните проекти + setting_enabled_scm: Овозможи SCM + setting_mail_handler_body_delimiters: "Truncate emails after one of these lines" + setting_mail_handler_api_enabled: Enable WS for incoming emails + setting_mail_handler_api_key: API клуч + setting_sequential_project_identifiers: Генерирај последователни идентификатори на проекти + setting_gravatar_enabled: Користи Gravatar кориснички икони + setting_gravatar_default: Default Gravatar image + setting_diff_max_lines_displayed: Max number of diff lines displayed + setting_file_max_size_displayed: Max size of text files displayed inline + setting_repository_log_display_limit: Maximum number of revisions displayed on file log + setting_openid: Дозволи OpenID најава и регистрација + setting_password_min_length: Мин. должина на лозинка + setting_new_project_user_role_id: Улога доделена на неадминистраторски корисник кој креира проект + setting_default_projects_modules: Default enabled modules for new projects + setting_issue_done_ratio: Calculate the issue done ratio with + setting_issue_done_ratio_issue_field: Use the issue field + setting_issue_done_ratio_issue_status: Use the issue status + setting_start_of_week: Start calendars on + setting_rest_api_enabled: Enable REST web service + setting_cache_formatted_text: Cache formatted text + + permission_add_project: Креирај проекти + permission_add_subprojects: Креирај подпроекти + permission_edit_project: Уреди проект + permission_select_project_modules: Изберете модули за проект + permission_manage_members: Manage members + permission_manage_project_activities: Manage project activities + permission_manage_versions: Manage versions + permission_manage_categories: Manage issue categories + permission_view_issues: Прегледај задачи + permission_add_issues: Додавај задачи + permission_edit_issues: Уредувај задачи + permission_manage_issue_relations: Manage issue relations + permission_add_issue_notes: Додавај белешки + permission_edit_issue_notes: Уредувај белешки + permission_edit_own_issue_notes: Уредувај сопствени белешки + permission_move_issues: Преместувај задачи + permission_delete_issues: Бриши задачи + permission_manage_public_queries: Manage public queries + permission_save_queries: Save queries + permission_view_gantt: View gantt chart + permission_view_calendar: View calendar + permission_view_issue_watchers: View watchers list + permission_add_issue_watchers: Add watchers + permission_delete_issue_watchers: Delete watchers + permission_log_time: Бележи потрошено време + permission_view_time_entries: Прегледај потрошено време + permission_edit_time_entries: Уредувај белешки за потрошено време + permission_edit_own_time_entries: Уредувај сопствени белешки за потрошено време + permission_manage_news: Manage news + permission_comment_news: Коментирај на вести + permission_view_documents: Прегледувај документи + permission_manage_files: Manage files + permission_view_files: Прегледувај датотеки + permission_manage_wiki: Manage wiki + permission_rename_wiki_pages: Преименувај вики страници + permission_delete_wiki_pages: Бриши вики страници + permission_view_wiki_pages: Прегледувај вики + permission_view_wiki_edits: Прегледувај вики историја + permission_edit_wiki_pages: Уредувај вики страници + permission_delete_wiki_pages_attachments: Бриши прилози + permission_protect_wiki_pages: Заштитувај вики страници + permission_manage_repository: Manage repository + permission_browse_repository: Browse repository + permission_view_changesets: View changesets + permission_commit_access: Commit access + permission_manage_boards: Manage boards + permission_view_messages: View messages + permission_add_messages: Post messages + permission_edit_messages: Уредувај пораки + permission_edit_own_messages: Уредувај сопствени пораки + permission_delete_messages: Бриши пораки + permission_delete_own_messages: Бриши сопствени пораки + permission_export_wiki_pages: Export wiki pages + permission_manage_subtasks: Manage subtasks + + project_module_issue_tracking: Следење на задачи + project_module_time_tracking: Следење на време + project_module_news: Вести + project_module_documents: Документи + project_module_files: Датотеки + project_module_wiki: Вики + project_module_repository: Repository + project_module_boards: Форуми + project_module_calendar: Календар + project_module_gantt: Gantt + + label_user: Корисник + label_user_plural: Корисници + label_user_new: Нов корисник + label_user_anonymous: Анонимен + label_project: Проект + label_project_new: Нов проект + label_project_plural: Проекти + label_x_projects: + zero: нема проекти + one: 1 проект + other: "%{count} проекти" + label_project_all: Сите проекти + label_project_latest: Последните проекти + label_issue: Задача + label_issue_new: Нова задача + label_issue_plural: Задачи + label_issue_view_all: Прегледај ги сите задачи + label_issues_by: "Задачи по %{value}" + label_issue_added: Задачата е додадена + label_issue_updated: Задачата е ажурирана + label_document: Документ + label_document_new: Нов документ + label_document_plural: Документи + label_document_added: Документот е додаден + label_role: Улога + label_role_plural: Улоги + label_role_new: Нова улога + label_role_and_permissions: Улоги и овластувања + label_member: Член + label_member_new: Нов член + label_member_plural: Членови + label_tracker: Tracker + label_tracker_plural: Trackers + label_tracker_new: New tracker + label_workflow: Workflow + label_issue_status: Статус на задача + label_issue_status_plural: Статуси на задачи + label_issue_status_new: Нов статус + label_issue_category: Категорија на задача + label_issue_category_plural: Категории на задачи + label_issue_category_new: Нова категорија + label_custom_field: Прилагодено поле + label_custom_field_plural: Прилагодени полиња + label_custom_field_new: Ново прилагодено поле + label_enumerations: Enumerations + label_enumeration_new: Нова вредност + label_information: Информација + label_information_plural: Информации + label_please_login: Најави се + label_register: Регистрирај се + label_login_with_open_id_option: или најави се со OpenID + label_password_lost: Изгубена лозинка + label_home: Почетна + label_my_page: Мојата страна + label_my_account: Мојот профил + label_my_projects: Мои проекти + label_my_page_block: Блок елемент + label_administration: Администрација + label_login: Најави се + label_logout: Одјави се + label_help: Помош + label_reported_issues: Пријавени задачи + label_assigned_to_me_issues: Задачи доделени на мене + label_last_login: Последна најава + label_registered_on: Регистриран на + label_activity: Активност + label_overall_activity: Севкупна активност + label_user_activity: "Активност на %{value}" + label_new: Нова + label_logged_as: Најавени сте како + label_environment: Опкружување + label_authentication: Автентикација + label_auth_source: Режим на автентикација + label_auth_source_new: Нов режим на автентикација + label_auth_source_plural: Режими на автентикација + label_subproject_plural: Подпроекти + label_subproject_new: Нов подпроект + label_and_its_subprojects: "%{value} и неговите подпроекти" + label_min_max_length: Мин. - Макс. должина + label_list: Листа + label_date: Дата + label_integer: Integer + label_float: Float + label_boolean: Boolean + label_string: Текст + label_text: Долг текст + label_attribute: Атрибут + label_attribute_plural: Атрибути + label_no_data: Нема податоци за прикажување + label_change_status: Промени статус + label_history: Историја + label_attachment: Датотека + label_attachment_new: Нова датотека + label_attachment_delete: Избриши датотека + label_attachment_plural: Датотеки + label_file_added: Датотеката е додадена + label_report: Извештај + label_report_plural: Извештаи + label_news: Новост + label_news_new: Додади новост + label_news_plural: Новости + label_news_latest: Последни новости + label_news_view_all: Прегледај ги сите новости + label_news_added: Новостта е додадена + label_settings: Settings + label_overview: Преглед + label_version: Верзија + label_version_new: Нова верзија + label_version_plural: Верзии + label_close_versions: Затвори ги завршените врзии + label_confirmation: Потврда + label_export_to: 'Достапно и во:' + label_read: Прочитај... + label_public_projects: Јавни проекти + label_open_issues: отворена + label_open_issues_plural: отворени + label_closed_issues: затворена + label_closed_issues_plural: затворени + label_x_open_issues_abbr_on_total: + zero: 0 отворени / %{total} + one: 1 отворена / %{total} + other: "%{count} отворени / %{total}" + label_x_open_issues_abbr: + zero: 0 отворени + one: 1 отворена + other: "%{count} отворени" + label_x_closed_issues_abbr: + zero: 0 затворени + one: 1 затворена + other: "%{count} затворени" + label_total: Вкупно + label_permissions: Овластувања + label_current_status: Моментален статус + label_new_statuses_allowed: Дозволени нови статуси + label_all: сите + label_none: ниеден + label_nobody: никој + label_next: Следно + label_previous: Претходно + label_used_by: Користено од + label_details: Детали + label_add_note: Додади белешка + label_per_page: По страна + label_calendar: Календар + label_months_from: месеци од + label_gantt: Gantt + label_internal: Internal + label_last_changes: "последни %{count} промени" + label_change_view_all: Прегледај ги сите промени + label_personalize_page: Прилагоди ја странава + label_comment: Коментар + label_comment_plural: Коментари + label_x_comments: + zero: нема коментари + one: 1 коментар + other: "%{count} коментари" + label_comment_add: Додади коментар + label_comment_added: Коментарот е додаден + label_comment_delete: Избриши коментари + label_query: Custom query + label_query_plural: Custom queries + label_query_new: New query + label_filter_add: Додади филтер + label_filter_plural: Филтри + label_equals: е + label_not_equals: не е + label_in_less_than: за помалку од + label_in_more_than: за повеќе од + label_greater_or_equal: '>=' + label_less_or_equal: '<=' + label_in: во + label_today: денес + label_all_time: цело време + label_yesterday: вчера + label_this_week: оваа недела + label_last_week: минатата недела + label_last_n_days: "последните %{count} дена" + label_this_month: овој месец + label_last_month: минатиот месец + label_this_year: оваа година + label_date_range: Date range + label_less_than_ago: пред помалку од денови + label_more_than_ago: пред повеќе од денови + label_ago: пред денови + label_contains: содржи + label_not_contains: не содржи + label_day_plural: денови + label_repository: Складиште + label_repository_plural: Складишта + label_browse: Прелистувај + label_branch: Гранка + label_tag: Tag + label_revision: Ревизија + label_revision_plural: Ревизии + label_revision_id: "Ревизија %{value}" + label_associated_revisions: Associated revisions + label_added: added + label_modified: modified + label_copied: copied + label_renamed: renamed + label_deleted: deleted + label_latest_revision: Последна ревизија + label_latest_revision_plural: Последни ревизии + label_view_revisions: Прегледај ги ревизиите + label_view_all_revisions: Прегледај ги сите ревизии + label_max_size: Макс. големина + label_sort_highest: Премести најгоре + label_sort_higher: Премести нагоре + label_sort_lower: Премести надоле + label_sort_lowest: Премести најдоле + label_roadmap: Roadmap + label_roadmap_due_in: "Due in %{value}" + label_roadmap_overdue: "Касни %{value}" + label_roadmap_no_issues: Нема задачи за оваа верзија + label_search: Барај + label_result_plural: Резултати + label_all_words: Сите зборови + label_wiki: Вики + label_wiki_edit: Вики уредување + label_wiki_edit_plural: Вики уредувања + label_wiki_page: Вики страница + label_wiki_page_plural: Вики страници + label_index_by_title: Индекс по наслов + label_index_by_date: Индекс по дата + label_current_version: Current version + label_preview: Preview + label_feed_plural: Feeds + label_changes_details: Детали за сите промени + label_issue_tracking: Следење на задачи + label_spent_time: Потрошено време + label_overall_spent_time: Вкупно потрошено време + label_f_hour: "%{value} час" + label_f_hour_plural: "%{value} часа" + label_time_tracking: Следење на време + label_change_plural: Промени + label_statistics: Статистики + label_commits_per_month: Commits per month + label_commits_per_author: Commits per author + label_view_diff: View differences + label_diff_inline: inline + label_diff_side_by_side: side by side + label_options: Опции + label_copy_workflow_from: Copy workflow from + label_permissions_report: Permissions report + label_watched_issues: Watched issues + label_related_issues: Поврзани задачи + label_applied_status: Applied status + label_loading: Loading... + label_relation_new: Нова релација + label_relation_delete: Избриши релација + label_relates_to: related to + label_duplicates: дупликати + label_duplicated_by: duplicated by + label_blocks: blocks + label_blocked_by: блокирано од + label_precedes: претходи + label_follows: следи + label_end_to_start: крај до почеток + label_end_to_end: крај до крај + label_start_to_start: почеток до почеток + label_start_to_end: почеток до крај + label_stay_logged_in: Останете најавени + label_disabled: disabled + label_show_completed_versions: Show completed versions + label_me: јас + label_board: Форум + label_board_new: Нов форум + label_board_plural: Форуми + label_board_locked: Заклучен + label_board_sticky: Sticky + label_topic_plural: Теми + label_message_plural: Пораки + label_message_last: Последна порака + label_message_new: Нова порака + label_message_posted: Поракате е додадена + label_reply_plural: Одговори + label_send_information: Испрати ги информациите за профилот на корисникот + label_year: Година + label_month: Месец + label_week: Недела + label_date_from: Од + label_date_to: До + label_language_based: Според јазикот на корисникот + label_sort_by: "Подреди според %{value}" + label_send_test_email: Испрати тест е-порака + label_feeds_access_key: RSS клуч за пристап + label_missing_feeds_access_key: Недостика RSS клуч за пристап + label_feeds_access_key_created_on: "RSS клучот за пристап креиран пред %{value}" + label_module_plural: Модули + label_added_time_by: "Додадено од %{author} пред %{age}" + label_updated_time_by: "Ажурирано од %{author} пред %{age}" + label_updated_time: "Ажурирано пред %{value}" + label_jump_to_a_project: Префрли се на проект... + label_file_plural: Датотеки + label_changeset_plural: Changesets + label_default_columns: Основни колони + label_no_change_option: (Без промена) + label_bulk_edit_selected_issues: Групно уредување на задачи + label_theme: Тема + label_default: Default + label_search_titles_only: Пребарувај само наслови + label_user_mail_option_all: "За било кој настан во сите мои проекти" + label_user_mail_option_selected: "За било кој настан само во избраните проекти..." + label_user_mail_no_self_notified: "Не ме известувај за промените што јас ги правам" + label_registration_activation_by_email: активација на профил преку е-пошта + label_registration_manual_activation: мануелна активација на профил + label_registration_automatic_activation: автоматска активација на профил + label_display_per_page: "По страна: %{value}" + label_age: Age + label_change_properties: Change properties + label_general: Општо + label_more: Повеќе + label_scm: SCM + label_plugins: Додатоци + label_ldap_authentication: LDAP автентикација + label_downloads_abbr: Превземања + label_optional_description: Опис (незадолжително) + label_add_another_file: Додади уште една датотека + label_preferences: Preferences + label_chronological_order: Во хронолошки ред + label_reverse_chronological_order: In reverse chronological order + label_planning: Планирање + label_incoming_emails: Дојдовни е-пораки + label_generate_key: Генерирај клуч + label_issue_watchers: Watchers + label_example: Пример + label_display: Прикажи + label_sort: Подреди + label_ascending: Растечки + label_descending: Опаѓачки + label_date_from_to: Од %{start} до %{end} + label_wiki_content_added: Вики страница додадена + label_wiki_content_updated: Вики страница ажурирана + label_group: Група + label_group_plural: Групи + label_group_new: Нова група + label_time_entry_plural: Потрошено време + label_version_sharing_none: Не споделено + label_version_sharing_descendants: Со сите подпроекти + label_version_sharing_hierarchy: Со хиерархијата на проектот + label_version_sharing_tree: Со дрвото на проектот + label_version_sharing_system: Со сите проекти + label_update_issue_done_ratios: Update issue done ratios + label_copy_source: Извор + label_copy_target: Дестинација + label_copy_same_as_target: Исто како дестинацијата + label_display_used_statuses_only: Only display statuses that are used by this tracker + label_api_access_key: API клуч за пристап + label_missing_api_access_key: Недостига API клуч за пристап + label_api_access_key_created_on: "API клучот за пристап е креиран пред %{value}" + label_profile: Профил + label_subtask_plural: Подзадачи + label_project_copy_notifications: Праќај известувања по е-пошта при копирање на проект + + button_login: Најави се + button_submit: Испрати + button_save: Зачувај + button_check_all: Штиклирај ги сите + button_uncheck_all: Одштиклирај ги сите + button_delete: Избриши + button_create: Креирај + button_create_and_continue: Креирај и продолжи + button_test: Тест + button_edit: Уреди + button_add: Додади + button_change: Промени + button_apply: Примени + button_clear: Избриши + button_lock: Заклучи + button_unlock: Отклучи + button_download: Превземи + button_list: List + button_view: Прегледај + button_move: Премести + button_move_and_follow: Премести и следи + button_back: Back + button_cancel: Откажи + button_activate: Активирај + button_sort: Подреди + button_log_time: Бележи време + button_rollback: Rollback to this version + button_watch: Следи + button_unwatch: Не следи + button_reply: Одговори + button_archive: Архивирај + button_unarchive: Одархивирај + button_reset: Reset + button_rename: Преименувај + button_change_password: Промени лозинка + button_copy: Копирај + button_copy_and_follow: Копирај и следи + button_annotate: Annotate + button_update: Ажурирај + button_configure: Конфигурирај + button_quote: Цитирај + button_duplicate: Копирај + button_show: Show + + status_active: активни + status_registered: регистрирани + status_locked: заклучени + + version_status_open: отворени + version_status_locked: заклучени + version_status_closed: затворени + + field_active: Active + + text_select_mail_notifications: Изберете за кои настани да се праќаат известувања по е-пошта да се праќаат. + text_regexp_info: eg. ^[A-Z0-9]+$ + text_min_max_length_info: 0 значи без ограничување + text_project_destroy_confirmation: Дали сте сигурни дека сакате да го избришете проектот и сите поврзани податоци? + text_subprojects_destroy_warning: "Неговите подпроекти: %{value} исто така ќе бидат избришани." + text_workflow_edit: Select a role and a tracker to edit the workflow + text_are_you_sure: Дали сте сигурни? + text_journal_changed: "%{label} променето од %{old} во %{new}" + text_journal_set_to: "%{label} set to %{value}" + text_journal_deleted: "%{label} избришан (%{old})" + text_journal_added: "%{label} %{value} додаден" + text_tip_issue_begin_day: задачи што почнуваат овој ден + text_tip_issue_end_day: задачи што завршуваат овој ден + text_tip_issue_begin_end_day: задачи што почнуваат и завршуваат овој ден + text_caracters_maximum: "%{count} знаци максимум." + text_caracters_minimum: "Мора да е најмалку %{count} знаци долго." + text_length_between: "Должина помеѓу %{min} и %{max} знаци." + text_tracker_no_workflow: No workflow defined for this tracker + text_unallowed_characters: Недозволени знаци + text_comma_separated: Дозволени се повеќе вредности (разделени со запирка). + text_line_separated: Дозволени се повеќе вредности (една линија за секоја вредност). + text_issues_ref_in_commit_messages: Referencing and fixing issues in commit messages + text_issue_added: "Задачата %{id} е пријавена од %{author}." + text_issue_updated: "Задачата %{id} е ажурирана од %{author}." + text_wiki_destroy_confirmation: Дали сте сигурни дека сакате да го избришете ова вики и целата негова содржина? + text_issue_category_destroy_question: "Некои задачи (%{count}) се доделени на оваа категорија. Што сакате да правите?" + text_issue_category_destroy_assignments: Remove category assignments + text_issue_category_reassign_to: Додели ги задачите на оваа категорија + text_user_mail_option: "For unselected projects, you will only receive notifications about things you watch or you're involved in (eg. issues you're the author or assignee)." + text_no_configuration_data: "Roles, trackers, issue statuses and workflow have not been configured yet.\nIt is highly recommended to load the default configuration. You will be able to modify it once loaded." + text_load_default_configuration: Load the default configuration + text_status_changed_by_changeset: "Applied in changeset %{value}." + text_issues_destroy_confirmation: 'Дали сте сигурни дека сакате да ги избришете избраните задачи?' + text_select_project_modules: 'Изберете модули за овој проект:' + text_default_administrator_account_changed: Default administrator account changed + text_file_repository_writable: Во папката за прилози може да се запишува + text_plugin_assets_writable: Во папката за додатоци може да се запишува + text_rmagick_available: RMagick available (незадолжително) + text_destroy_time_entries_question: "%{hours} hours were reported on the issues you are about to delete. What do you want to do ?" + text_destroy_time_entries: Delete reported hours + text_assign_time_entries_to_project: Додели ги пријавените часови на проектот + text_reassign_time_entries: 'Reassign reported hours to this issue:' + text_user_wrote: "%{value} напиша:" + text_enumeration_destroy_question: "%{count} objects are assigned to this value." + text_enumeration_category_reassign_to: 'Reassign them to this value:' + text_email_delivery_not_configured: "Доставата по е-пошта не е конфигурирана, и известувањата се оневозможени.\nКонфигурирајте го Вашиот SMTP сервер во config/configuration.yml и рестартирајте ја апликацијата." + text_repository_usernames_mapping: "Select or update the Redmine user mapped to each username found in the repository log.\nUsers with the same Redmine and repository username or email are automatically mapped." + text_diff_truncated: '... This diff was truncated because it exceeds the maximum size that can be displayed.' + text_custom_field_possible_values_info: 'One line for each value' + text_wiki_page_destroy_question: "This page has %{descendants} child page(s) and descendant(s). What do you want to do?" + text_wiki_page_nullify_children: "Keep child pages as root pages" + text_wiki_page_destroy_children: "Delete child pages and all their descendants" + text_wiki_page_reassign_children: "Reassign child pages to this parent page" + text_own_membership_delete_confirmation: "You are about to remove some or all of your permissions and may no longer be able to edit this project after that.\nAre you sure you want to continue?" + text_zoom_in: Zoom in + text_zoom_out: Zoom out + + default_role_manager: Менаџер + default_role_developer: Developer + default_role_reporter: Reporter + default_tracker_bug: Грешка + default_tracker_feature: Функционалност + default_tracker_support: Поддршка + default_issue_status_new: Нова + default_issue_status_in_progress: Во прогрес + default_issue_status_resolved: Разрешена + default_issue_status_feedback: Feedback + default_issue_status_closed: Затворена + default_issue_status_rejected: Одбиена + default_doc_category_user: Корисничка документација + default_doc_category_tech: Техничка документација + default_priority_low: Низок + default_priority_normal: Нормален + default_priority_high: Висок + default_priority_urgent: Итно + default_priority_immediate: Веднаш + default_activity_design: Дизајн + default_activity_development: Развој + + enumeration_issue_priorities: Приоритети на задача + enumeration_doc_categories: Категории на документ + enumeration_activities: Активности (следење на време) + enumeration_system_activity: Системска активност + + button_edit_associated_wikipage: "Edit associated Wiki page: %{page_title}" + field_text: Text field + label_user_mail_option_only_owner: Only for things I am the owner of + setting_default_notification_option: Default notification option + label_user_mail_option_only_my_events: Only for things I watch or I'm involved in + label_user_mail_option_only_assigned: Only for things I am assigned to + label_user_mail_option_none: No events + field_member_of_group: Assignee's group + field_assigned_to_role: Assignee's role + notice_not_authorized_archived_project: The project you're trying to access has been archived. + label_principal_search: "Search for user or group:" + label_user_search: "Search for user:" + field_visible: Visible + setting_commit_logtime_activity_id: Activity for logged time + text_time_logged_by_changeset: Applied in changeset %{value}. + setting_commit_logtime_enabled: Enable time logging + notice_gantt_chart_truncated: The chart was truncated because it exceeds the maximum number of items that can be displayed (%{max}) + setting_gantt_items_limit: Maximum number of items displayed on the gantt chart + field_warn_on_leaving_unsaved: Warn me when leaving a page with unsaved text + text_warn_on_leaving_unsaved: The current page contains unsaved text that will be lost if you leave this page. + label_my_queries: My custom queries + text_journal_changed_no_detail: "%{label} updated" + label_news_comment_added: Comment added to a news + button_expand_all: Expand all + button_collapse_all: Collapse all + label_additional_workflow_transitions_for_assignee: Additional transitions allowed when the user is the assignee + label_additional_workflow_transitions_for_author: Additional transitions allowed when the user is the author + label_bulk_edit_selected_time_entries: Bulk edit selected time entries + text_time_entries_destroy_confirmation: Are you sure you want to delete the selected time entr(y/ies)? + label_role_anonymous: Anonymous + label_role_non_member: Non member + label_issue_note_added: Note added + label_issue_status_updated: Status updated + label_issue_priority_updated: Priority updated + label_issues_visibility_own: Issues created by or assigned to the user + field_issues_visibility: Issues visibility + label_issues_visibility_all: All issues + permission_set_own_issues_private: Set own issues public or private + field_is_private: Private + permission_set_issues_private: Set issues public or private + label_issues_visibility_public: All non private issues + text_issues_destroy_descendants_confirmation: This will also delete %{count} subtask(s). + field_commit_logs_encoding: Commit messages encoding + field_scm_path_encoding: Path encoding + text_scm_path_encoding_note: "Default: UTF-8" + field_path_to_repository: Path to repository + field_root_directory: Root directory + field_cvs_module: Module + field_cvsroot: CVSROOT + text_mercurial_repository_note: Local repository (e.g. /hgrepo, c:\hgrepo) + text_scm_command: Command + text_scm_command_version: Version + label_git_report_last_commit: Report last commit for files and directories + notice_issue_successful_create: Issue %{id} created. + label_between: between + setting_issue_group_assignment: Allow issue assignment to groups + label_diff: diff + text_git_repository_note: Repository is bare and local (e.g. /gitrepo, c:\gitrepo) + description_query_sort_criteria_direction: Sort direction + description_project_scope: Search scope + description_filter: Filter + description_user_mail_notification: Mail notification settings + description_date_from: Enter start date + description_message_content: Message content + description_available_columns: Available Columns + description_date_range_interval: Choose range by selecting start and end date + description_issue_category_reassign: Choose issue category + description_search: Searchfield + description_notes: Notes + description_date_range_list: Choose range from list + description_choose_project: Projects + description_date_to: Enter end date + description_query_sort_criteria_attribute: Sort attribute + description_wiki_subpages_reassign: Choose new parent page + description_selected_columns: Selected Columns + label_parent_revision: Parent + label_child_revision: Child + error_scm_annotate_big_text_file: The entry cannot be annotated, as it exceeds the maximum text file size. + setting_default_issue_start_date_to_creation_date: Use current date as start date for new issues + button_edit_section: Edit this section + setting_repositories_encodings: Attachments and repositories encodings + description_all_columns: All Columns + button_export: Export + label_export_options: "%{export_format} export options" + error_attachment_too_big: This file cannot be uploaded because it exceeds the maximum allowed file size (%{max_size}) + notice_failed_to_save_time_entries: "Failed to save %{count} time entrie(s) on %{total} selected: %{ids}." + label_x_issues: + zero: 0 Задача + one: 1 Задача + other: "%{count} Задачи" + label_repository_new: New repository + field_repository_is_default: Main repository + label_copy_attachments: Copy attachments + label_item_position: "%{position}/%{count}" + label_completed_versions: Completed versions + text_project_identifier_info: Only lower case letters (a-z), numbers, dashes and underscores are allowed.
    Once saved, the identifier cannot be changed. + field_multiple: Multiple values + setting_commit_cross_project_ref: Allow issues of all the other projects to be referenced and fixed + text_issue_conflict_resolution_add_notes: Add my notes and discard my other changes + text_issue_conflict_resolution_overwrite: Apply my changes anyway (previous notes will be kept but some changes may be overwritten) + notice_issue_update_conflict: The issue has been updated by an other user while you were editing it. + text_issue_conflict_resolution_cancel: Discard all my changes and redisplay %{link} + permission_manage_related_issues: Manage related issues + field_auth_source_ldap_filter: LDAP filter + label_search_for_watchers: Search for watchers to add + notice_account_deleted: Your account has been permanently deleted. + setting_unsubscribe: Allow users to delete their own account + button_delete_my_account: Delete my account + text_account_destroy_confirmation: |- + Are you sure you want to proceed? + Your account will be permanently deleted, with no way to reactivate it. + error_session_expired: Your session has expired. Please login again. + text_session_expiration_settings: "Warning: changing these settings may expire the current sessions including yours." + setting_session_lifetime: Session maximum lifetime + setting_session_timeout: Session inactivity timeout + label_session_expiration: Session expiration + permission_close_project: Close / reopen the project + label_show_closed_projects: View closed projects + button_close: Close + button_reopen: Reopen + project_status_active: active + project_status_closed: closed + project_status_archived: archived + text_project_closed: This project is closed and read-only. + notice_user_successful_create: User %{id} created. + field_core_fields: Standard fields + field_timeout: Timeout (in seconds) + setting_thumbnails_enabled: Display attachment thumbnails + setting_thumbnails_size: Thumbnails size (in pixels) + label_status_transitions: Status transitions + label_fields_permissions: Fields permissions + label_readonly: Read-only + label_required: Required + text_repository_identifier_info: Only lower case letters (a-z), numbers, dashes and underscores are allowed.
    Once saved, the identifier cannot be changed. + field_board_parent: Parent forum + label_attribute_of_project: Project's %{name} + label_attribute_of_author: Author's %{name} + label_attribute_of_assigned_to: Assignee's %{name} + label_attribute_of_fixed_version: Target version's %{name} + label_copy_subtasks: Copy subtasks + label_copied_to: copied to + label_copied_from: copied from + label_any_issues_in_project: any issues in project + label_any_issues_not_in_project: any issues not in project + field_private_notes: Private notes + permission_view_private_notes: View private notes + permission_set_notes_private: Set notes as private + label_no_issues_in_project: no issues in project + label_any: сите + label_last_n_weeks: last %{count} weeks + setting_cross_project_subtasks: Allow cross-project subtasks + label_cross_project_descendants: Со сите подпроекти + label_cross_project_tree: Со дрвото на проектот + label_cross_project_hierarchy: Со хиерархијата на проектот + label_cross_project_system: Со сите проекти + button_hide: Hide + setting_non_working_week_days: Non-working days + label_in_the_next_days: in the next + label_in_the_past_days: in the past + label_attribute_of_user: User's %{name} + text_turning_multiple_off: If you disable multiple values, multiple values will be + removed in order to preserve only one value per item. + label_attribute_of_issue: Issue's %{name} + permission_add_documents: Add documents + permission_edit_documents: Edit documents + permission_delete_documents: Delete documents + label_gantt_progress_line: Progress line + setting_jsonp_enabled: Enable JSONP support + field_inherit_members: Inherit members + field_closed_on: Closed + setting_default_projects_tracker_ids: Default trackers for new projects + label_total_time: Вкупно + text_scm_config: You can configure your SCM commands in config/configuration.yml. Please restart the application after editing it. + text_scm_command_not_available: SCM command is not available. Please check settings on the administration panel. + setting_emails_footer: Email footer + setting_emails_header: Email header diff --git a/config/locales/mn.yml b/config/locales/mn.yml new file mode 100644 index 00000000..35986937 --- /dev/null +++ b/config/locales/mn.yml @@ -0,0 +1,1090 @@ +mn: + direction: ltr + jquery: + locale: "en" + date: + formats: + # Use the strftime parameters for formats. + # When no format has been given, it uses default. + # You can provide other formats here if you like! + default: "%Y/%m/%d" + short: "%b %d" + long: "%Y, %B %d" + + day_names: [Даваа, Мягмар, Лхагва, Пүрэв, Баасан, Бямба, Ням] + abbr_day_names: [Дав, Мяг, Лха, Пүр, Бсн, Бям, Ням] + + # Don't forget the nil at the beginning; there's no such thing as a 0th month + month_names: [~, 1-р сар, 2-р сар, 3-р сар, 4-р сар, 5-р сар, 6-р сар, 7-р сар, 8-р сар, 9-р сар, 10-р сар, 11-р сар, 12-р сар] + abbr_month_names: [~, 1сар, 2сар, 3сар, 4сар, 5сар, 6сар, 7сар, 8сар, 9сар, 10сар, 11сар, 12сар] + # Used in date_select and datime_select. + order: + - :day + - :month + - :year + + time: + formats: + default: "%Y/%m/%d %I:%M %p" + time: "%I:%M %p" + short: "%d %b %H:%M" + long: "%Y, %B %d %H:%M" + am: "am" + pm: "pm" + + datetime: + distance_in_words: + half_a_minute: "хагас минут" + less_than_x_seconds: + one: "секунд орчим" + other: "%{count} секундээс бага хугацаа" + x_seconds: + one: "1 секунд" + other: "%{count} секунд" + less_than_x_minutes: + one: "минутаас бага хугацаа" + other: "%{count} минутаас бага хугацаа" + x_minutes: + one: "1 минут" + other: "%{count} минут" + about_x_hours: + one: "1 цаг орчим" + other: "ойролцоогоор %{count} цаг" + x_hours: + one: "1 hour" + other: "%{count} hours" + x_days: + one: "1 өдөр" + other: "%{count} өдөр" + about_x_months: + one: "1 сар орчим" + other: "ойролцоогоор %{count} сар" + x_months: + one: "1 сар" + other: "%{count} сар" + about_x_years: + one: "ойролцоогоор 1 жил" + other: "ойролцоогоор %{count} жил" + over_x_years: + one: "1 жилээс их" + other: "%{count} жилээс их" + almost_x_years: + one: "бараг 1 жил" + other: "бараг %{count} жил" + + number: + format: + separator: "." + delimiter: "" + precision: 3 + human: + format: + delimiter: "" + precision: 3 + storage_units: + format: "%n %u" + units: + byte: + one: "Байт" + other: "Байт" + kb: "KB" + mb: "MB" + gb: "GB" + tb: "TB" + +# Used in array.to_sentence. + support: + array: + sentence_connector: "бас" + skip_last_comma: false + + activerecord: + errors: + template: + header: + one: "1 error prohibited this %{model} from being saved" + other: "%{count} errors prohibited this %{model} from being saved" + messages: + inclusion: "жагсаалтад заагдаагүй байна" + exclusion: "нөөцлөгдсөн" + invalid: "буруу" + confirmation: "баталгаажсан өгөгдөлтэй таарахгүй байна" + accepted: "хүлээж авах ёстой" + empty: "хоосон байж болохгүй" + blank: "бланк байж болохгүй" + too_long: "дэндүү урт байна (хамгийн ихдээ %{count} тэмдэгт)" + too_short: "дэндүү богино байна (хамгийн багадаа %{count} тэмдэгт)" + wrong_length: "буруу урттай байна (заавал %{count} тэмдэгт)" + taken: "аль хэдийнэ авсан байна" + not_a_number: "тоо биш байна" + not_a_date: "зөв огноо биш байна" + greater_than: "%{count} их байх ёстой" + greater_than_or_equal_to: "must be greater than or equal to %{count}" + equal_to: "must be equal to %{count}" + less_than: "must be less than %{count}" + less_than_or_equal_to: "must be less than or equal to %{count}" + odd: "заавал сондгой" + even: "заавал тэгш" + greater_than_start_date: "must be greater than start date" + not_same_project: "нэг ижил төсөлд хамаарахгүй байна" + circular_dependency: "Энэ харьцаа нь гинжин(рекурсив) харьцаа үүсгэх юм байна" + cant_link_an_issue_with_a_descendant: "An issue can not be linked to one of its subtasks" + + actionview_instancetag_blank_option: Сонгоно уу + + general_text_No: 'Үгүй' + general_text_Yes: 'Тийм' + general_text_no: 'үгүй' + general_text_yes: 'тийм' + general_lang_name: 'Mongolian (Монгол)' + general_csv_separator: ',' + general_csv_decimal_separator: '.' + general_csv_encoding: UTF-8 + general_pdf_encoding: UTF-8 + general_first_day_of_week: '7' + + notice_account_updated: Дансыг амжилттай өөрчиллөө. + notice_account_invalid_creditentials: Хэрэглэгчийн нэр эсвэл нууц үг буруу байна + notice_account_password_updated: Нууц үгийг амжилттай өөрчиллөө. + notice_account_wrong_password: Буруу нууц үг + notice_account_register_done: Шинэ хэрэглэгч амжилттай үүсгэлээ. Идэвхжүүлэхийн тулд, бидний тань луу илгээсэн мэйл дотор байгаа холбоос дээр дараарай. + notice_account_unknown_email: Үл мэдэгдэх хэрэглэгч. + notice_can_t_change_password: Энэ эрх гадаад нэвтрэлтэд ашигладаг учраас нууц үгийг өөрчлөх боломжгүй. + notice_account_lost_email_sent: Бид таньд мэйлээр нууц үгээ өөрчлөх зааврыг илгээсэн байгаа. + notice_account_activated: Таны данс идэвхжлээ. Одоо нэвтэрч орж болно. + notice_successful_create: Амжилттай үүсгэлээ. + notice_successful_update: Амжилттай өөрчиллөө. + notice_successful_delete: Амжилттай устгалаа. + notice_successful_connection: Амжилттай холбогдлоо. + notice_file_not_found: Таны үзэх гэсэн хуудас байхгүй юмуу устгагдсан байна. + notice_locking_conflict: Өгөгдлийг өөр хүн өөрчилсөн байна. + notice_not_authorized: Танд энэ хуудсыг үзэх эрх байхгүй байна. + notice_email_sent: "%{value} - руу мэйл илгээлээ" + notice_email_error: "Мэйл илгээхэд алдаа гарлаа (%{value})" + notice_feeds_access_key_reseted: Таны RSS хандалтын түлхүүрийг дахин эхлүүллээ. + notice_api_access_key_reseted: Your API access key was reset. + notice_failed_to_save_issues: "%{total} асуудал сонгогдсоноос %{count} асуудлыг нь хадгалахад алдаа гарлаа: %{ids}." + notice_no_issue_selected: "Ямар ч асуудал сонгогдоогүй байна! Засварлах асуудлуудаа сонгоно уу." + notice_account_pending: "Таны дансыг үүсгэж дууслаа, администратор баталгаажуулах хүртэл хүлээнэ үү." + notice_default_data_loaded: Стандарт тохиргоог амжилттай ачааллаа. + notice_unable_delete_version: Хувилбарыг устгах боломжгүй. + notice_issue_done_ratios_updated: Issue done ratios updated. + + error_can_t_load_default_data: "Стандарт тохиргоог ачаалж чадсангүй: %{value}" + error_scm_not_found: "Repository дотор тухайн бичлэг эсвэл хувилбарыг олсонгүй." + error_scm_command_failed: "Repository-д хандахад алдаа гарлаа: %{value}" + error_scm_annotate: "Бичлэг байхгүй байна, эсвэл бичлэгт тайлбар хавсаргаж болохгүй." + error_issue_not_found_in_project: 'Сонгосон асуудал энэ төсөлд хамаардаггүй юм уу эсвэл системд байхгүй байна.' + error_no_tracker_in_project: 'No tracker is associated to this project. Please check the Project settings.' + error_no_default_issue_status: 'No default issue status is defined. Please check your configuration (Go to "Administration -> Issue statuses").' + error_can_not_reopen_issue_on_closed_version: 'An issue assigned to a closed version can not be reopened' + error_can_not_archive_project: This project can not be archived + error_issue_done_ratios_not_updated: "Issue done ratios not updated." + error_workflow_copy_source: 'Please select a source tracker or role' + error_workflow_copy_target: 'Please select target tracker(s) and role(s)' + + warning_attachments_not_saved: "%{count} file(s) файлыг хадгалж чадсангүй." + + mail_subject_lost_password: "Таны %{value} нууц үг" + mail_body_lost_password: 'Нууц үгээ өөрчлөхийн тулд доорх холбоос дээр дарна уу:' + mail_subject_register: "Таны %{value} дансыг идэвхжүүлэх" + mail_body_register: 'Дансаа идэвхжүүлэхийн тулд доорх холбоос дээр дарна уу:' + mail_body_account_information_external: "Та өөрийнхөө %{value} дансыг ашиглаж холбогдож болно." + mail_body_account_information: Таны дансны тухай мэдээлэл + mail_subject_account_activation_request: "%{value} дансыг идэвхжүүлэх хүсэлт" + mail_body_account_activation_request: "Шинэ хэрэглэгч (%{value}) бүртгүүлсэн байна. Таны баталгаажуулахыг хүлээж байна:" + mail_subject_reminder: "Дараагийн өдрүүдэд %{count} асуудлыг шийдэх хэрэгтэй (%{days})" + mail_body_reminder: "Танд оноогдсон %{count} асуудлуудыг дараагийн %{days} өдрүүдэд шийдэх хэрэгтэй:" + mail_subject_wiki_content_added: "'%{id}' wiki page has been added" + mail_body_wiki_content_added: "The '%{id}' wiki page has been added by %{author}." + mail_subject_wiki_content_updated: "'%{id}' wiki page has been updated" + mail_body_wiki_content_updated: "The '%{id}' wiki page has been updated by %{author}." + + + field_name: Нэр + field_description: Тайлбар + field_summary: Дүгнэлт + field_is_required: Зайлшгүй + field_firstname: Таны нэр + field_lastname: Овог + field_mail: Имэйл + field_filename: Файл + field_filesize: Хэмжээ + field_downloads: Татаж авах зүйлс + field_author: Зохиогч + field_created_on: Үүссэн + field_updated_on: Өөрчилсөн + field_field_format: Формат + field_is_for_all: Бүх төслийн хувьд + field_possible_values: Боломжтой утгууд + field_regexp: Энгийн илэрхийлэл + field_min_length: Минимум урт + field_max_length: Максимум урт + field_value: Утга + field_category: Төрөл + field_title: Гарчиг + field_project: Төсөл + field_issue: Асуудал + field_status: Төлөв + field_notes: Тэмдэглэлүүд + field_is_closed: Асуудал хаагдсан + field_is_default: Стандарт утга + field_tracker: Чиглэл + field_subject: Гарчиг + field_due_date: Дуусах огноо + field_assigned_to: Оноогдсон + field_priority: Зэрэглэл + field_fixed_version: Хувилбар + field_user: Хэрэглэгч + field_role: Хандалтын эрх + field_homepage: Нүүр хуудас + field_is_public: Олон нийтийн + field_parent: Эцэг төсөл нь + field_is_in_roadmap: Асуудлуудыг явцын зураг дээр харуулах + field_login: Нэвтрэх нэр + field_mail_notification: Имэйл мэдэгдлүүд + field_admin: Администратор + field_last_login_on: Сүүлийн холбоо + field_language: Хэл + field_effective_date: Огноо + field_password: Нууц үг + field_new_password: Шннэ нууц үг + field_password_confirmation: Баталгаажуулах + field_version: Хувилбар + field_type: Төрөл + field_host: Хост + field_port: Порт + field_account: Данс + field_base_dn: Үндсэн ДН + field_attr_login: Нэвтрэх аттрибут + field_attr_firstname: Таны нэр аттрибут + field_attr_lastname: Овог аттрибут + field_attr_mail: Имэйл аттрибут + field_onthefly: Хүссэн үедээ хэрэглэгч үүсгэх + field_start_date: Эхлэл + field_done_ratio: "%% Гүйцэтгэсэн" + field_auth_source: Нэвтрэх арга + field_hide_mail: Миний имэйл хаягийг нуу + field_comments: Тайлбар + field_url: URL Хаяг + field_start_page: Тэргүүн хуудас + field_subproject: Дэд төсөл + field_hours: Цаг + field_activity: Үйл ажиллагаа + field_spent_on: Огноо + field_identifier: Төслийн глобал нэр + field_is_filter: Шүүлтүүр болгон хэрэглэгддэг + field_issue_to: Хамаатай асуудал + field_delay: Хоцролт + field_assignable: Энэ хандалтын эрхэд асуудлуудыг оноож өгч болно + field_redirect_existing_links: Байгаа холбоосуудыг дахин чиглүүлэх + field_estimated_hours: Барагцаалсан цаг + field_column_names: Баганууд + field_time_zone: Цагын бүс + field_searchable: Хайж болох + field_default_value: Стандарт утга + field_comments_sorting: Тайлбаруудыг харуул + field_parent_title: Эцэг хуудас + field_editable: Засварлагдана + field_watcher: Харна + field_identity_url: OpenID URL + field_content: Агуулга + field_group_by: Үр дүнгээр бүлэглэх + field_sharing: Sharing + + setting_app_title: Программын гарчиг + setting_app_subtitle: Программын дэд гарчиг + setting_welcome_text: Мэндчилгээ + setting_default_language: Стандарт хэл + setting_login_required: Нэвтрэх шаардлагатай + setting_self_registration: Өөрийгөө бүртгүүлэх + setting_attachment_max_size: Хавсралт файлын дээд хэмжээ + setting_issues_export_limit: Асуудал экспортлох хязгаар + setting_mail_from: Ямар имэйл хаяг үүсгэх + setting_bcc_recipients: BCC талбарын хаягууд (bcc) + setting_plain_text_mail: дан текст мэйл (HTML биш) + setting_host_name: Хостын нэр болон зам + setting_text_formatting: Текст хэлбэржүүлэлт + setting_wiki_compression: Вики хуудсуудын түүх дээр шахалт хийх + setting_feeds_limit: Фийд агуулгын хязгаар + setting_default_projects_public: Шинэ төслүүд автоматаар олон нийтийнх байна + setting_autofetch_changesets: Комитуудыг автоматаар татаж авах + setting_sys_api_enabled: Репозитори менежментэд зориулан WS-ийг идэвхжүүлэх + setting_commit_ref_keywords: Хамааруулах түлхүүр үгс + setting_commit_fix_keywords: Зоолттой түлхүүр үгс + setting_autologin: Компьютер дээр санах + setting_date_format: Огнооны формат + setting_time_format: Цагийн формат + setting_cross_project_issue_relations: Төсөл хооронд асуудал хамааруулахыг зөвшөөрөх + setting_issue_list_default_columns: Асуудлуудыг харуулах стандарт баганууд + setting_emails_footer: Имэйлүүдийн хөл хэсэг + setting_protocol: Протокол + setting_per_page_options: Нэг хуудсанд байх обьектуудын тохиргоо + setting_user_format: Хэрэглэгчдийг харуулах формат + setting_activity_days_default: Төслийн үйл ажиллагаа хэсэгт үзүүлэх өдрийн тоо + setting_display_subprojects_issues: Дэд төслүүдийн асуудлуудыг автоматаар гол төсөл дээр харуулах + setting_enabled_scm: SCM - ийг идэвхжүүлэх + setting_mail_handler_body_delimiters: "Truncate emails after one of these lines" + setting_mail_handler_api_enabled: Ирсэн мэйлүүдийн хувьд WS-ийг идэвхжүүлэх + setting_mail_handler_api_key: API түлхүүр + setting_sequential_project_identifiers: Дэс дараалсан төслийн глобал нэр үүсгэж байх + setting_gravatar_enabled: Gravatar дүрсүүдийг хэрэглэгчдэд хэрэглэж байх + setting_gravatar_default: Default Gravatar image + setting_diff_max_lines_displayed: Ялгаатай мөрүүдийн тоо (дээд тал нь) + setting_file_max_size_displayed: Max size of text files displayed inline + setting_repository_log_display_limit: Maximum number of revisions displayed on file log + setting_openid: Allow OpenID login and registration + setting_password_min_length: Minimum password length + setting_new_project_user_role_id: Role given to a non-admin user who creates a project + setting_default_projects_modules: Default enabled modules for new projects + setting_issue_done_ratio: Calculate the issue done ratio with + setting_issue_done_ratio_issue_field: Use the issue field + setting_issue_done_ratio_issue_status: Use the issue status + setting_start_of_week: Start calendars on + setting_rest_api_enabled: Enable REST web service + setting_cache_formatted_text: Cache formatted text + + permission_add_project: Create project + permission_add_subprojects: Create subprojects + permission_edit_project: Төслийг засварлах + permission_select_project_modules: Төслийн модулуудийг сонгоно уу + permission_manage_members: Системийн хэрэглэгчид + permission_manage_project_activities: Manage project activities + permission_manage_versions: Хувилбарууд + permission_manage_categories: Асуудлын ангиллууд + permission_view_issues: Асуудлуудыг харах + permission_add_issues: Асуудлууд нэмэх + permission_edit_issues: Асуудлуудыг засварлах + permission_manage_issue_relations: Асуудлын хамаарлыг зохицуулах + permission_add_issue_notes: Тэмдэглэл нэмэх + permission_edit_issue_notes: Тэмдэглэлүүд засварлах + permission_edit_own_issue_notes: Өөрийн үлдээсэн тэмдэглэлүүдийг засварлах + permission_move_issues: Асуудлуудыг зөөх + permission_delete_issues: Асуудлуудыг устгах + permission_manage_public_queries: Олон нийтийн асуултууд + permission_save_queries: Асуултуудыг хадгалах + permission_view_gantt: Гант диаграмыг үзэх + permission_view_calendar: Календарь үзэх + permission_view_issue_watchers: Ажиглагчдын жагсаалтыг харах + permission_add_issue_watchers: Ажиглагчид нэмэх + permission_delete_issue_watchers: Ажиглагчдыг устгах + permission_log_time: Зарцуулсан хугацааг лог хийх + permission_view_time_entries: Зарцуулсан хугацааг харах + permission_edit_time_entries: Хугацааны логуудыг засварлах + permission_edit_own_time_entries: Өөрийн хугацааны логуудыг засварлах + permission_manage_news: Мэдээ мэдээллүүд + permission_comment_news: Мэдээнд тайлбар үлдээх + permission_view_documents: Бичиг баримтуудыг харах + permission_manage_files: Файлууд + permission_view_files: Файлуудыг харах + permission_manage_wiki: Вики удирдах + permission_rename_wiki_pages: Вики хуудсуудыг дахиж нэрлэх + permission_delete_wiki_pages: Вики хуудсуудыг устгах + permission_view_wiki_pages: Вики үзэх + permission_view_wiki_edits: Вики түүх үзэх + permission_edit_wiki_pages: Вики хуудсуудыг засварлах + permission_delete_wiki_pages_attachments: Хавсралтуудыг устгах + permission_protect_wiki_pages: Вики хуудсуудыг хамгаалах + permission_manage_repository: Репозитори + permission_browse_repository: Репозиторийг үзэх + permission_view_changesets: Өөрчлөлтүүдийг харах + permission_commit_access: Коммит хандалт + permission_manage_boards: Самбарууд + permission_view_messages: Зурвасуудыг харах + permission_add_messages: Зурвас илгээх + permission_edit_messages: Зурвасуудыг засварлах + permission_edit_own_messages: Өөрийн зурвасуудыг засварлах + permission_delete_messages: Зурвасуудыг устгах + permission_delete_own_messages: Өөрийн зурвасуудыг устгах + permission_export_wiki_pages: Вики хуудсуудыг экспорт хийх + + project_module_issue_tracking: Асуудал хянах + project_module_time_tracking: Хугацаа хянах + project_module_news: Мэдээ мэдээллүүд + project_module_documents: Бичиг баримтууд + project_module_files: Файлууд + project_module_wiki: Вики + project_module_repository: Репозитори + project_module_boards: Самбарууд + + label_user: Хэрэглэгч + label_user_plural: Хэрэглэгчид + label_user_new: Шинэ хэрэглэгч + label_user_anonymous: Хамаагүй хэрэглэгч + label_project: Төсөл + label_project_new: Шинэ төсөл + label_project_plural: Төслүүд + label_x_projects: + zero: төсөл байхгүй + one: 1 төсөл + other: "%{count} төслүүд" + label_project_all: Бүх Төслүүд + label_project_latest: Сүүлийн үеийн төслүүд + label_issue: Асуудал + label_issue_new: Шинэ асуудал + label_issue_plural: Асуудлууд + label_issue_view_all: Бүх асуудлуудыг харах + label_issues_by: "%{value} - н асуудлууд" + label_issue_added: Асуудал нэмэгдлээ + label_issue_updated: Асуудал өөрчлөгдлөө + label_document: Бичиг баримт + label_document_new: Шинэ бичиг баримт + label_document_plural: Бичиг баримтууд + label_document_added: Бичиг баримт нэмэгдлээ + label_role: Хандалтын эрх + label_role_plural: Хандалтын эрхүүд + label_role_new: Шинэ хандалтын эрх + label_role_and_permissions: Хандалтын эрхүүд болон зөвшөөрлүүд + label_member: Гишүүн + label_member_new: Шинэ гишүүн + label_member_plural: Гишүүд + label_tracker: Чиглэл + label_tracker_plural: Чиглэлүүд + label_tracker_new: Шинэ чиглэл + label_workflow: Ажлын дараалал + label_issue_status: Асуудлын төлөв + label_issue_status_plural: Асуудлын төлвүүд + label_issue_status_new: Шинэ төлөв + label_issue_category: Асуудлын ангилал + label_issue_category_plural: Асуудлын ангиллууд + label_issue_category_new: Шинэ ангилал + label_custom_field: Хэрэглэгчийн тодорхойлсон талбар + label_custom_field_plural: Хэрэглэгчийн тодорхойлсон талбарууд + label_custom_field_new: Шинээр хэрэглэгчийн тодорхойлсон талбар үүсгэх + label_enumerations: Ангиллууд + label_enumeration_new: Шинэ утга + label_information: Мэдээлэл + label_information_plural: Мэдээллүүд + label_please_login: Нэвтэрч орно уу + label_register: Бүртгүүлэх + label_login_with_open_id_option: or login with OpenID + label_password_lost: Нууц үгээ алдсан + label_home: Нүүр + label_my_page: Миний хуудас + label_my_account: Миний данс + label_my_projects: Миний төслүүд + label_administration: Админ хэсэг + label_login: Нэвтрэх + label_logout: Гарах + label_help: Тусламж + label_reported_issues: Мэдэгдсэн асуудлууд + label_assigned_to_me_issues: Надад оноогдсон асуудлууд + label_last_login: Сүүлийн холболт + label_registered_on: Бүртгүүлсэн огноо + label_activity: Үйл ажиллагаа + label_overall_activity: Ерөнхий үйл ажиллагаа + label_user_activity: "%{value}-ийн үйл ажиллагаа" + label_new: Шинэ + label_logged_as: Холбогдсон нэр + label_environment: Орчин + label_authentication: Нэвтрэх + label_auth_source: Нэвтрэх арга + label_auth_source_new: Шинэ нэвтрэх арга + label_auth_source_plural: Нэвтрэх аргууд + label_subproject_plural: Дэд төслүүд + label_subproject_new: Шинэ дэд төсөл + label_and_its_subprojects: "%{value} болон холбогдох дэд төслүүд" + label_min_max_length: Дээд - Доод урт + label_list: Жагсаалт + label_date: Огноо + label_integer: Бүхэл тоо + label_float: Бутархай тоо + label_boolean: Үнэн худал утга + label_string: Текст + label_text: Урт текст + label_attribute: Аттрибут + label_attribute_plural: Аттрибутууд + label_no_data: Үзүүлэх өгөгдөл байхгүй байна + label_change_status: Төлвийг өөрчлөх + label_history: Түүх + label_attachment: Файл + label_attachment_new: Шинэ файл + label_attachment_delete: Файл устгах + label_attachment_plural: Файлууд + label_file_added: Файл нэмэгдлээ + label_report: Тайлан + label_report_plural: Тайлангууд + label_news: Мэдээ + label_news_new: Шинэ мэдээ + label_news_plural: Мэдээ + label_news_latest: Сүүлийн үеийн мэдээнүүд + label_news_view_all: Бүх мэдээг харах + label_news_added: Мэдээ нэмэгдлээ + label_settings: Тохиргоо + label_overview: Эхлэл + label_version: Хувилбар + label_version_new: Шинэ хувилбар + label_version_plural: Хувилбарууд + label_close_versions: Гүйцэт хувилбаруудыг хаалаа + label_confirmation: Баталгаажуулах + label_export_to: 'Өөр авч болох формат:' + label_read: Унших... + label_public_projects: Олон нийтийн төслүүд + label_open_issues: нээлттэй + label_open_issues_plural: нээлттэй + label_closed_issues: хаалттай + label_closed_issues_plural: хаалттай + label_x_open_issues_abbr_on_total: + zero: 0 нээлттэй / %{total} + one: 1 нээлттэй / %{total} + other: "%{count} нээлттэй / %{total}" + label_x_open_issues_abbr: + zero: 0 нээлттэй + one: 1 нээлттэй + other: "%{count} нээлттэй" + label_x_closed_issues_abbr: + zero: 0 хаалттай + one: 1 хаалттай + other: "%{count} хаалттай" + label_total: Нийт + label_permissions: Зөвшөөрлүүд + label_current_status: Одоогийн төлөв + label_new_statuses_allowed: Шинээр олгож болох төлвүүд + label_all: бүгд + label_none: хоосон + label_nobody: хэн ч биш + label_next: Дараагийн + label_previous: Өмнөх + label_used_by: Хэрэглэгддэг + label_details: Дэлгэрэнгүй + label_add_note: Тэмдэглэл нэмэх + label_per_page: Нэг хуудсанд + label_calendar: Календарь + label_months_from: Саруудыг хаанаас + label_gantt: Гант диаграм + label_internal: Дотоод + label_last_changes: "сүүлийн %{count} өөрчлөлтүүд" + label_change_view_all: Бүх өөрчлөлтүүдийг харах + label_personalize_page: Энэ хуудсыг өөрт зориулан өөрчлөх + label_comment: Тайлбар + label_comment_plural: Тайлбарууд + label_x_comments: + zero: сэтгэгдэл байхгүй + one: 1 сэтгэгдэлтэй + other: "%{count} сэтгэгдэлтэй" + label_comment_add: Тайлбар нэмэх + label_comment_added: Тайлбар нэмэгдлээ + label_comment_delete: Тайлбарууд устгах + label_query: Хэрэглэгчийн тодорхойлсон асуулт + label_query_plural: Хэрэглэгчийн тодорхойлсон асуултууд + label_query_new: Шинээр хэрэглэгчийн тодорхойлсон асуулт үүсгэх + label_filter_add: Шүүлтүүр нэмэх + label_filter_plural: Шүүлтүүрүүд + label_equals: бол + label_not_equals: биш + label_in_less_than: аас бага + label_in_more_than: аас их + label_greater_or_equal: '>=' + label_less_or_equal: '<=' + label_in: дотор + label_today: өнөөдөр + label_all_time: бүх хугацаа + label_yesterday: өчигдөр + label_this_week: энэ долоо хоног + label_last_week: өнгөрсөн долоо хоног + label_last_n_days: "сүүлийн %{count} өдрүүд" + label_this_month: энэ сар + label_last_month: сүүлийн сар + label_this_year: энэ жил + label_date_range: Хязгаар огноо + label_less_than_ago: бага өдрийн дотор + label_more_than_ago: их өдрийн дотор + label_ago: өдрийн өмнө + label_contains: агуулж байгаа + label_not_contains: агуулаагүй + label_day_plural: өдрүүд + label_repository: Репозитори + label_repository_plural: Репозиторууд + label_browse: Үзэх + label_branch: Салбар + label_tag: Шошго + label_revision: Хувилбар + label_revision_plural: Хувилбарууд + label_revision_id: "%{value} Хувилбар" + label_associated_revisions: Хамааралтай хувилбарууд + label_added: нэмэгдсэн + label_modified: өөрчлөгдсөн + label_copied: хуулсан + label_renamed: нэрийг нь өөрчилсөн + label_deleted: устгасан + label_latest_revision: Сүүлийн үеийн хувилбар + label_latest_revision_plural: Сүүлийн үеийн хувилбарууд + label_view_revisions: Хувилбаруудыг харах + label_view_all_revisions: Бүх хувилбаруудыг харах + label_max_size: Maximum size + label_sort_highest: Хамгийн дээр + label_sort_higher: Дээш нь + label_sort_lower: Доош нь + label_sort_lowest: Хамгийн доор + label_roadmap: Хөтөч + label_roadmap_due_in: "%{value} дотор дуусгах" + label_roadmap_overdue: "%{value} оройтсон" + label_roadmap_no_issues: Энэ хувилбарт асуудал байхгүй байна + label_search: Хайх + label_result_plural: Үр дүн + label_all_words: Бүх үгс + label_wiki: Вики + label_wiki_edit: Вики засвар + label_wiki_edit_plural: Вики засварууд + label_wiki_page: Вики хуудас + label_wiki_page_plural: Вики хуудас + label_index_by_title: Гарчгаар эрэмбэлэх + label_index_by_date: Огноогоор эрэмбэлэх + label_current_version: Одоогийн хувилбар + label_preview: Ямар харагдахыг шалгах + label_feed_plural: Feeds + label_changes_details: Бүх өөрчлөлтүүдийн дэлгэрэнгүй + label_issue_tracking: Асуудал хянах + label_spent_time: Зарцуулсан хугацаа + label_f_hour: "%{value} цаг" + label_f_hour_plural: "%{value} цаг" + label_time_tracking: Хугацааг хянах + label_change_plural: Өөрчлөлтүүд + label_statistics: Статистик + label_commits_per_month: Сард хийсэн коммитын тоо + label_commits_per_author: Зохиогч бүрийн хувьд коммитын тоо + label_view_diff: Ялгаануудыг харах + label_diff_inline: дотор нь + label_diff_side_by_side: зэрэгцүүлж + label_options: Тохиргоо + label_copy_workflow_from: Ажлын дарааллыг хуулах + label_permissions_report: Зөвшөөрлүүдийн таблиц + label_watched_issues: Ажиглагдаж байгаа асуудлууд + label_related_issues: Хамааралтай асуудлууд + label_applied_status: Олгосон төлөв + label_loading: Ачаалж байна... + label_relation_new: Шинэ хамаарал + label_relation_delete: Хамаарлыг устгах + label_relates_to: энгийн хамааралтай + label_duplicates: хос хамааралтай + label_duplicated_by: давхардуулсан эзэн + label_blocks: шаардах хамааралтай + label_blocked_by: блоколсон эзэн + label_precedes: урьдчилах хамааралтай + label_follows: дагаж + label_end_to_start: хойноос нь урагшаа + label_end_to_end: хойноос нь хойшоо + label_start_to_start: урдаас нь урагаа + label_start_to_end: урдаас нь хойшоо + label_stay_logged_in: Энэ комьютер дээр санах + label_disabled: идэвхгүй болсон + label_show_completed_versions: Гүйцэд хувилбаруудыг харуулах + label_me: би + label_board: Форум + label_board_new: Шинэ форум + label_board_plural: Форумууд + label_board_locked: Түгжээтэй + label_board_sticky: Sticky + label_topic_plural: Сэдвүүд + label_message_plural: Зурвасууд + label_message_last: Сүүлийн зурвас + label_message_new: Шинэ зурвас + label_message_posted: Зурвас нэмэгдлээ + label_reply_plural: Хариултууд + label_send_information: Дансны мэдээллийг хэрэглэгчид илгээх + label_year: Жил + label_month: Сар + label_week: Долоо хоног + label_date_from: Хэзээнээс + label_date_to: Хэдий хүртэл + label_language_based: Хэрэглэгчийн хэлнас шалтгаалан + label_sort_by: "%{value} талбараар нь эрэмбэлэх" + label_send_test_email: Турших мэйл илгээх + label_feeds_access_key: RSS хандах түлхүүр + label_missing_feeds_access_key: RSS хандах түлхүүр алга + label_feeds_access_key_created_on: "RSS хандалтын түлхүүр %{value}-ийн өмнө үүссэн" + label_module_plural: Модулууд + label_added_time_by: "%{author} %{age}-ийн өмнө нэмсэн" + label_updated_time_by: "%{author} %{age}-ийн өмнө өөрчилсөн" + label_updated_time: "%{value} -ийн өмнө өөрчлөгдсөн" + label_jump_to_a_project: Төсөл рүү очих... + label_file_plural: Файлууд + label_changeset_plural: Өөрчлөлтүүд + label_default_columns: Стандарт баганууд + label_no_change_option: (Өөрчлөлт байхгүй) + label_bulk_edit_selected_issues: Сонгогдсон асуудлуудыг бөөнөөр засварлах + label_theme: Системийн Дизайн + label_default: Стандарт + label_search_titles_only: Зөвхөн гарчиг хайх + label_user_mail_option_all: "Миний бүх төсөл дээрх бүх үзэгдлүүдийн хувьд" + label_user_mail_option_selected: "Сонгогдсон төслүүдийн хувьд бүх үзэгдэл дээр..." + label_user_mail_no_self_notified: "Миний өөрийн хийсэн өөрчлөлтүүдийн тухай надад мэдэгдэх хэрэггүй" + label_registration_activation_by_email: дансыг имэйлээр идэвхжүүлэх + label_registration_manual_activation: дансыг гараар идэвхжүүлэх + label_registration_automatic_activation: дансыг автоматаар идэвхжүүлэх + label_display_per_page: 'Нэг хуудсанд: %{value}' + label_age: Нас + label_change_properties: Тохиргоог өөрчлөх + label_general: Ерөнхий + label_more: Цааш нь + label_scm: SCM + label_plugins: Модулууд + label_ldap_authentication: LDAP нэвтрэх горим + label_downloads_abbr: D/L + label_optional_description: Дурын тайлбар + label_add_another_file: Дахин файл нэмэх + label_preferences: Тохиргоо + label_chronological_order: Цагаан толгойн үсгийн дарааллаар + label_reverse_chronological_order: Урвуу цагаан толгойн үсгийн дарааллаар + label_planning: Төлөвлөлт + label_incoming_emails: Ирсэн мэйлүүд + label_generate_key: Түлхүүр үүсгэх + label_issue_watchers: Ажиглагчид + label_example: Жишээ + label_display: Display + label_sort: Sort + label_ascending: Ascending + label_descending: Descending + label_date_from_to: From %{start} to %{end} + label_wiki_content_added: Wiki page added + label_wiki_content_updated: Wiki page updated + label_group: Group + label_group_plural: Groups + label_group_new: New group + label_time_entry_plural: Spent time + label_version_sharing_none: Not shared + label_version_sharing_descendants: With subprojects + label_version_sharing_hierarchy: With project hierarchy + label_version_sharing_tree: With project tree + label_version_sharing_system: With all projects + label_update_issue_done_ratios: Update issue done ratios + label_copy_source: Source + label_copy_target: Target + label_copy_same_as_target: Same as target + label_display_used_statuses_only: Only display statuses that are used by this tracker + label_api_access_key: API access key + label_missing_api_access_key: Missing an API access key + label_api_access_key_created_on: "API access key created %{value} ago" + + button_login: Нэвтрэх + button_submit: Илгээх + button_save: Хадгалах + button_check_all: Бүгдийг сонго + button_uncheck_all: Бүгдийг үл сонго + button_delete: Устгах + button_create: Үүсгэх + button_create_and_continue: Үүсгээд цааш үргэлжлүүлэх + button_test: Турших + button_edit: Засварлах + button_add: Нэмэх + button_change: Өөрчлөх + button_apply: Өөрчлөлтийг хадгалах + button_clear: Цэвэрлэх + button_lock: Түгжих + button_unlock: Түгжээг тайлах + button_download: Татах + button_list: Жагсаалт + button_view: Харах + button_move: Зөөх + button_move_and_follow: Зөө бас дага + button_back: Буцах + button_cancel: Болих + button_activate: Идэвхжүүлэх + button_sort: Эрэмбэлэх + button_log_time: Лог хийсэн хугацаа + button_rollback: Энэ хувилбар руу буцах + button_watch: Ажиглах + button_unwatch: Ажиглахаа болих + button_reply: Хариулах + button_archive: Архивлах + button_unarchive: Архивыг задлах + button_reset: Анхны утгууд + button_rename: Нэрийг нь солих + button_change_password: Нууц үгээ өөрчлөх + button_copy: Хуулах + button_copy_and_follow: Зөө бас дага + button_annotate: Тайлбар хавсаргах + button_update: Шинэчлэх + button_configure: Тохируулах + button_quote: Ишлэл + button_duplicate: Хуулбар + button_show: Үзэх + + status_active: идэвхтэй + status_registered: бүртгүүлсэн + status_locked: түгжээтэй + + version_status_open: нээлттэй + version_status_locked: түгжээтэй + version_status_closed: хаалттай + + field_active: идэвхтэй + + text_select_mail_notifications: Ямар үед имэйлээр мэдэгдэл илгээхийг сонгоно уу. + text_regexp_info: eg. ^[A-Z0-9]+$ + text_min_max_length_info: 0 гэвэл ямар ч хязгааргүй гэсэн үг + text_project_destroy_confirmation: Та энэ төсөл болоод бусад мэдээллийг нь үнэхээр устгамаар байна уу ? + text_subprojects_destroy_warning: "Уг төслийн дэд төслүүд : %{value} нь бас устгагдах болно." + text_workflow_edit: Ажлын дарааллыг өөрчлөхийн тулд хандалтын эрх болон асуудлын чиглэлийг сонгоно уу + text_are_you_sure: Та итгэлтэй байна уу ? + text_journal_changed: "%{label} %{old} байсан нь %{new} болов" + text_journal_set_to: "%{label} %{value} болгож өөрчиллөө" + text_journal_deleted: "%{label} устсан (%{old})" + text_journal_added: "%{label} %{value} нэмэгдсэн" + text_tip_issue_begin_day: энэ өдөр эхлэх ажил + text_tip_issue_end_day: энэ өдөр дуусах ажил + text_tip_issue_begin_end_day: энэ өдөр эхлээд мөн дуусч байгаа ажил + text_caracters_maximum: "дээд тал нь %{count} үсэг." + text_caracters_minimum: "Хамгийн багадаа ядаж %{count} тэмдэгт байх." + text_length_between: "Урт нь багадаа %{min}, ихдээ %{max} тэмдэгт." + text_tracker_no_workflow: Энэхүү асуудлын чиглэлд ямар ч ажлын дараалал тодорхойлогдоогүй байна + text_unallowed_characters: Хэрэглэж болохгүй тэмдэгтүүд + text_comma_separated: Таслалаар зааглан олон утга оруулж болно. + text_line_separated: Multiple values allowed (one line for each value). + text_issues_ref_in_commit_messages: Коммитийн зурвасуудад хамааруулсан болон байнгын асуудлууд + text_issue_added: "Асуудал %{id} - ийг хэрэглэгч %{author} мэдэгдсэн байна." + text_issue_updated: "Асуудал %{id} - ийг хэрэглэгч %{author} өөрчилсөн байна." + text_wiki_destroy_confirmation: Та энэ вики болон холбогдох бүх мэдээллийг үнэхээр устгамаар байна уу ? + text_issue_category_destroy_question: "Энэ ангилалд зарим асуудлууд (%{count}) орсон байна. Та яах вэ ?" + text_issue_category_destroy_assignments: Асуудлуудыг энэ ангиллаас авах + text_issue_category_reassign_to: Асуудлуудыг энэ ангилалд дахин оноох + text_user_mail_option: "Сонгогдоогүй төслүүдийн хувьд, та зөвхөн өөрийнхөө ажиглаж байгаа зүйлс юмуу танд хамаатай зүйлсийн талаар мэдэгдэл авах болно (Таны оруулсан асуудал, эсвэл танд оноосон гэх мэт)." + text_no_configuration_data: "Хандалтын эрхүүд, чиглэлүүд, асуудлын төлвүүд болон ажлын дарааллын тухай мэдээллийг хараахан оруулаагүй байна.\nТа стандарт өгөгдлүүдийг даруйхан оруулахыг зөвлөж байна, оруулсан хойно та засварлаж болно." + text_load_default_configuration: Стандарт өгөгдлийг ачаалах + text_status_changed_by_changeset: "%{value} өөрчлөлтөд хийгдсэн." + text_issues_destroy_confirmation: 'Та сонгогдсон асуудлуудыг үнэхээр устгамаар байна уу ?' + text_select_project_modules: 'Энэ төслийн хувьд идэвхжүүлэх модулуудаа сонгоно уу:' + text_default_administrator_account_changed: Стандарт администраторын бүртгэл өөрчлөгдлөө + text_file_repository_writable: Хавсралт файл хадгалах хавтас руу бичих эрхтэй + text_plugin_assets_writable: Плагин модулийн ассет хавтас руу бичих эрхтэй + text_rmagick_available: RMagick суулгагдсан (заавал биш) + text_destroy_time_entries_question: "Таны устгах гэж байгаа асуудлууд дээр нийт %{hours} цаг зарцуулсан юм байна, та яах вэ ?" + text_destroy_time_entries: Мэдэгдсэн цагуудыг устгах + text_assign_time_entries_to_project: Мэдэгдсэн асуудлуудыг төсөлд оноох + text_reassign_time_entries: 'Мэдэгдсэн асуудлуудыг энэ асуудалд дахин оноо:' + text_user_wrote: "%{value} бичихдээ:" + text_enumeration_destroy_question: "Энэ утгад %{count} обьект оноогдсон байна." + text_enumeration_category_reassign_to: 'Тэдгээрийг энэ утгад дахин оноо:' + text_email_delivery_not_configured: "Имэйлийн тохиргоог хараахан тохируулаагүй байна, тиймээс имэйл мэдэгдэл явуулах боломжгүй байна.\nSMTP сервэрээ config/configuration.yml файл дотор тохируулаад төслийн менежерээ дахиад эхлүүлээрэй." + text_repository_usernames_mapping: "Репозиторийн логд байгаа бүх хэрэглэгчийн нэрүүдэд харгалзсан Төслийн Менежер системд бүртгэлтэй хэрэглэгчдийг Сонгох юмуу шинэчилнэ үү.\nТөслийн менежер болон репозиторид байгаа ижилхэн нэр юмуу имэйлтэй хэрэглэгчид харилцан харгалзна." + text_diff_truncated: '... Файлын ялгаврын хэмжээ үзүүлэхэд дэндүү урт байгаа учраас төгсгөлөөс нь хасч үзүүлэв.' + text_custom_field_possible_values_info: 'One line for each value' + text_wiki_page_destroy_question: "This page has %{descendants} child page(s) and descendant(s). What do you want to do?" + text_wiki_page_nullify_children: "Keep child pages as root pages" + text_wiki_page_destroy_children: "Delete child pages and all their descendants" + text_wiki_page_reassign_children: "Reassign child pages to this parent page" + text_own_membership_delete_confirmation: "You are about to remove some or all of your permissions and may no longer be able to edit this project after that.\nAre you sure you want to continue?" + + default_role_manager: Менежер + default_role_developer: Хөгжүүлэгч + default_role_reporter: Мэдэгдэгч + default_tracker_bug: Алдаа + default_tracker_feature: Онцлог + default_tracker_support: Тусламж + default_issue_status_new: Шинэ + default_issue_status_in_progress: Ахицтай + default_issue_status_assigned: Оноогдсон + default_issue_status_resolved: Шийдвэрлэгдсэн + default_issue_status_feedback: Feedback + default_issue_status_closed: Хаагдсан + default_issue_status_rejected: Хүлээж аваагүй + default_doc_category_user: Хэрэглэгчийн бичиг баримт + default_doc_category_tech: Техникийн бичиг баримт + default_priority_low: Бага + default_priority_normal: Хэвийн + default_priority_high: Өндөр + default_priority_urgent: Нэн яаралтай + default_priority_immediate: Нэн даруй + default_activity_design: Дизайн + default_activity_development: Хөгжүүлэлт + + enumeration_issue_priorities: Асуудлын зэрэглэлүүд + enumeration_doc_categories: Бичиг баримтын ангиллууд + enumeration_activities: Үйл ажиллагаанууд (хугацааг хянах) + enumeration_system_activity: Системийн үйл ажиллагаа + + permission_manage_subtasks: Manage subtasks + label_profile: Profile + field_parent_issue: Parent task + error_unable_delete_issue_status: Unable to delete issue status + label_subtask_plural: Subtasks + label_project_copy_notifications: Send email notifications during the project copy + error_can_not_delete_custom_field: Unable to delete custom field + error_unable_to_connect: Unable to connect (%{value}) + error_can_not_remove_role: This role is in use and can not be deleted. + error_can_not_delete_tracker: This tracker contains issues and can't be deleted. + field_principal: Principal + label_my_page_block: My page block + notice_failed_to_save_members: "Failed to save member(s): %{errors}." + text_zoom_out: Zoom out + text_zoom_in: Zoom in + notice_unable_delete_time_entry: Unable to delete time log entry. + label_overall_spent_time: Overall spent time + field_time_entries: Log time + project_module_gantt: Gantt + project_module_calendar: Calendar + button_edit_associated_wikipage: "Edit associated Wiki page: %{page_title}" + field_text: Text field + label_user_mail_option_only_owner: Only for things I am the owner of + setting_default_notification_option: Default notification option + label_user_mail_option_only_my_events: Only for things I watch or I'm involved in + label_user_mail_option_only_assigned: Only for things I am assigned to + label_user_mail_option_none: No events + field_member_of_group: Assignee's group + field_assigned_to_role: Assignee's role + notice_not_authorized_archived_project: The project you're trying to access has been archived. + label_principal_search: "Search for user or group:" + label_user_search: "Search for user:" + field_visible: Visible + setting_commit_logtime_activity_id: Activity for logged time + text_time_logged_by_changeset: Applied in changeset %{value}. + setting_commit_logtime_enabled: Enable time logging + notice_gantt_chart_truncated: The chart was truncated because it exceeds the maximum number of items that can be displayed (%{max}) + setting_gantt_items_limit: Maximum number of items displayed on the gantt chart + field_warn_on_leaving_unsaved: Warn me when leaving a page with unsaved text + text_warn_on_leaving_unsaved: The current page contains unsaved text that will be lost if you leave this page. + label_my_queries: My custom queries + text_journal_changed_no_detail: "%{label} updated" + label_news_comment_added: Comment added to a news + button_expand_all: Expand all + button_collapse_all: Collapse all + label_additional_workflow_transitions_for_assignee: Additional transitions allowed when the user is the assignee + label_additional_workflow_transitions_for_author: Additional transitions allowed when the user is the author + label_bulk_edit_selected_time_entries: Bulk edit selected time entries + text_time_entries_destroy_confirmation: Are you sure you want to delete the selected time entr(y/ies)? + label_role_anonymous: Anonymous + label_role_non_member: Non member + label_issue_note_added: Note added + label_issue_status_updated: Status updated + label_issue_priority_updated: Priority updated + label_issues_visibility_own: Issues created by or assigned to the user + field_issues_visibility: Issues visibility + label_issues_visibility_all: All issues + permission_set_own_issues_private: Set own issues public or private + field_is_private: Private + permission_set_issues_private: Set issues public or private + label_issues_visibility_public: All non private issues + text_issues_destroy_descendants_confirmation: This will also delete %{count} subtask(s). + field_commit_logs_encoding: Коммит хийх үед харуулах текстүүдийн энкодинг + field_scm_path_encoding: Path encoding + text_scm_path_encoding_note: "Default: UTF-8" + field_path_to_repository: Path to repository + field_root_directory: Root directory + field_cvs_module: Module + field_cvsroot: CVSROOT + text_mercurial_repository_note: Local repository (e.g. /hgrepo, c:\hgrepo) + text_scm_command: Command + text_scm_command_version: Version + label_git_report_last_commit: Report last commit for files and directories + notice_issue_successful_create: Issue %{id} created. + label_between: between + setting_issue_group_assignment: Allow issue assignment to groups + label_diff: diff + text_git_repository_note: Repository is bare and local (e.g. /gitrepo, c:\gitrepo) + description_query_sort_criteria_direction: Sort direction + description_project_scope: Search scope + description_filter: Filter + description_user_mail_notification: Mail notification settings + description_date_from: Enter start date + description_message_content: Message content + description_available_columns: Available Columns + description_date_range_interval: Choose range by selecting start and end date + description_issue_category_reassign: Choose issue category + description_search: Searchfield + description_notes: Notes + description_date_range_list: Choose range from list + description_choose_project: Projects + description_date_to: Enter end date + description_query_sort_criteria_attribute: Sort attribute + description_wiki_subpages_reassign: Choose new parent page + description_selected_columns: Selected Columns + label_parent_revision: Parent + label_child_revision: Child + error_scm_annotate_big_text_file: The entry cannot be annotated, as it exceeds the maximum text file size. + setting_default_issue_start_date_to_creation_date: Use current date as start date for new issues + button_edit_section: Edit this section + setting_repositories_encodings: Attachments and repositories encodings + description_all_columns: All Columns + button_export: Export + label_export_options: "%{export_format} export options" + error_attachment_too_big: This file cannot be uploaded because it exceeds the maximum allowed file size (%{max_size}) + notice_failed_to_save_time_entries: "Failed to save %{count} time entrie(s) on %{total} selected: %{ids}." + label_x_issues: + zero: 0 Асуудал + one: 1 Асуудал + other: "%{count} Асуудлууд" + label_repository_new: New repository + field_repository_is_default: Main repository + label_copy_attachments: Copy attachments + label_item_position: "%{position}/%{count}" + label_completed_versions: Completed versions + text_project_identifier_info: Only lower case letters (a-z), numbers, dashes and underscores are allowed.
    Once saved, the identifier cannot be changed. + field_multiple: Multiple values + setting_commit_cross_project_ref: Allow issues of all the other projects to be referenced and fixed + text_issue_conflict_resolution_add_notes: Add my notes and discard my other changes + text_issue_conflict_resolution_overwrite: Apply my changes anyway (previous notes will be kept but some changes may be overwritten) + notice_issue_update_conflict: The issue has been updated by an other user while you were editing it. + text_issue_conflict_resolution_cancel: Discard all my changes and redisplay %{link} + permission_manage_related_issues: Manage related issues + field_auth_source_ldap_filter: LDAP filter + label_search_for_watchers: Search for watchers to add + notice_account_deleted: Your account has been permanently deleted. + setting_unsubscribe: Allow users to delete their own account + button_delete_my_account: Delete my account + text_account_destroy_confirmation: |- + Are you sure you want to proceed? + Your account will be permanently deleted, with no way to reactivate it. + error_session_expired: Your session has expired. Please login again. + text_session_expiration_settings: "Warning: changing these settings may expire the current sessions including yours." + setting_session_lifetime: Session maximum lifetime + setting_session_timeout: Session inactivity timeout + label_session_expiration: Session expiration + permission_close_project: Close / reopen the project + label_show_closed_projects: View closed projects + button_close: Close + button_reopen: Reopen + project_status_active: active + project_status_closed: closed + project_status_archived: archived + text_project_closed: This project is closed and read-only. + notice_user_successful_create: User %{id} created. + field_core_fields: Standard fields + field_timeout: Timeout (in seconds) + setting_thumbnails_enabled: Display attachment thumbnails + setting_thumbnails_size: Thumbnails size (in pixels) + label_status_transitions: Status transitions + label_fields_permissions: Fields permissions + label_readonly: Read-only + label_required: Required + text_repository_identifier_info: Only lower case letters (a-z), numbers, dashes and underscores are allowed.
    Once saved, the identifier cannot be changed. + field_board_parent: Parent forum + label_attribute_of_project: Project's %{name} + label_attribute_of_author: Author's %{name} + label_attribute_of_assigned_to: Assignee's %{name} + label_attribute_of_fixed_version: Target version's %{name} + label_copy_subtasks: Copy subtasks + label_copied_to: copied to + label_copied_from: copied from + label_any_issues_in_project: any issues in project + label_any_issues_not_in_project: any issues not in project + field_private_notes: Private notes + permission_view_private_notes: View private notes + permission_set_notes_private: Set notes as private + label_no_issues_in_project: no issues in project + label_any: бүгд + label_last_n_weeks: last %{count} weeks + setting_cross_project_subtasks: Allow cross-project subtasks + label_cross_project_descendants: With subprojects + label_cross_project_tree: With project tree + label_cross_project_hierarchy: With project hierarchy + label_cross_project_system: With all projects + button_hide: Hide + setting_non_working_week_days: Non-working days + label_in_the_next_days: in the next + label_in_the_past_days: in the past + label_attribute_of_user: User's %{name} + text_turning_multiple_off: If you disable multiple values, multiple values will be + removed in order to preserve only one value per item. + label_attribute_of_issue: Issue's %{name} + permission_add_documents: Add documents + permission_edit_documents: Edit documents + permission_delete_documents: Delete documents + label_gantt_progress_line: Progress line + setting_jsonp_enabled: Enable JSONP support + field_inherit_members: Inherit members + field_closed_on: Closed + setting_default_projects_tracker_ids: Default trackers for new projects + label_total_time: Нийт + text_scm_config: You can configure your SCM commands in config/configuration.yml. Please restart the application after editing it. + text_scm_command_not_available: SCM command is not available. Please check settings on the administration panel. + setting_emails_header: Email header diff --git a/config/locales/nl.yml b/config/locales/nl.yml new file mode 100644 index 00000000..6afc2373 --- /dev/null +++ b/config/locales/nl.yml @@ -0,0 +1,1070 @@ +nl: + direction: ltr + date: + formats: + # Use the strftime parameters for formats. + # When no format has been given, it uses default. + # You can provide other formats here if you like! + default: "%d-%m-%Y" + short: "%e %b" + long: "%d %B, %Y" + + day_names: [zondag, maandag, dinsdag, woensdag, donderdag, vrijdag, zaterdag] + abbr_day_names: [zo, ma, di, wo, do, vr, za] + + # Don't forget the nil at the beginning; there's no such thing as a 0th month + month_names: [~, januari, februari, maart, april, mei, juni, juli, augustus, september, oktober, november, december] + abbr_month_names: [~, jan, feb, mar, apr, mei, jun, jul, aug, sep, okt, nov, dec] + # Used in date_select and datime_select. + order: + - :day + - :month + - :year + + time: + formats: + default: "%a, %d %b %Y %H:%M:%S %z" + time: "%H:%M" + short: "%e %b %H:%M" + long: "%d %B, %Y %H:%M" + am: "am" + pm: "pm" + + datetime: + distance_in_words: + half_a_minute: "halve minuut" + less_than_x_seconds: + one: "minder dan een seconde" + other: "minder dan %{count} seconden" + x_seconds: + one: "1 seconde" + other: "%{count} seconden" + less_than_x_minutes: + one: "minder dan een minuut" + other: "minder dan %{count} minuten" + x_minutes: + one: "1 minuut" + other: "%{count} minuten" + about_x_hours: + one: "ongeveer 1 uur" + other: "ongeveer %{count} uren" + x_hours: + one: "1 uur" + other: "%{count} hours" + x_days: + one: "1 dag" + other: "%{count} dagen" + about_x_months: + one: "ongeveer 1 maand" + other: "ongeveer %{count} maanden" + x_months: + one: "1 maand" + other: "%{count} maanden" + about_x_years: + one: "ongeveer 1 jaar" + other: "ongeveer %{count} jaar" + over_x_years: + one: "meer dan 1 jaar" + other: "meer dan %{count} jaar" + almost_x_years: + one: "bijna 1 jaar" + other: "bijna %{count} jaar" + + number: + format: + separator: "." + delimiter: "" + precision: 3 + human: + format: + precision: 3 + delimiter: "" + storage_units: + format: "%n %u" + units: + kb: KB + tb: TB + gb: GB + byte: + one: Byte + other: Bytes + mb: MB + +# Used in array.to_sentence. + support: + array: + sentence_connector: "en" + skip_last_comma: false + + activerecord: + errors: + template: + header: + one: "Door een fout kon dit %{model} niet worden opgeslagen" + other: "Door %{count} fouten kon dit %{model} niet worden opgeslagen" + messages: + inclusion: "staat niet in de lijst" + exclusion: "is gereserveerd" + invalid: "is ongeldig" + confirmation: "komt niet overeen met bevestiging" + accepted: "moet geaccepteerd worden" + empty: "mag niet leeg zijn" + blank: "mag niet blanco zijn" + too_long: "is te lang" + too_short: "is te kort" + wrong_length: "heeft een onjuiste lengte" + taken: "is al in gebruik" + not_a_number: "is geen getal" + not_a_date: "is geen valide datum" + greater_than: "moet groter zijn dan %{count}" + greater_than_or_equal_to: "moet groter zijn of gelijk zijn aan %{count}" + equal_to: "moet gelijk zijn aan %{count}" + less_than: "moet minder zijn dan %{count}" + less_than_or_equal_to: "moet minder dan of gelijk zijn aan %{count}" + odd: "moet oneven zijn" + even: "moet even zijn" + greater_than_start_date: "moet na de startdatum liggen" + not_same_project: "hoort niet bij hetzelfde project" + circular_dependency: "Deze relatie zou een circulaire afhankelijkheid tot gevolg hebben" + cant_link_an_issue_with_a_descendant: "Een issue kan niet gelinked worden met een subtask" + + actionview_instancetag_blank_option: Selecteer + + button_activate: Activeer + button_add: Voeg toe + button_annotate: Annoteer + button_apply: Pas toe + button_archive: Archiveer + button_back: Terug + button_cancel: Annuleer + button_change: Wijzig + button_change_password: Wijzig wachtwoord + button_check_all: Selecteer alle + button_clear: Leeg maken + button_configure: Configureer + button_copy: Kopiëer + button_create: Maak + button_delete: Verwijder + button_download: Download + button_edit: Bewerk + button_list: Lijst + button_lock: Sluit + button_log_time: Registreer tijd + button_login: Inloggen + button_move: Verplaatsen + button_quote: Citaat + button_rename: Hernoemen + button_reply: Antwoord + button_reset: Reset + button_rollback: Rollback naar deze versie + button_save: Bewaren + button_sort: Sorteer + button_submit: Toevoegen + button_test: Test + button_unarchive: Dearchiveer + button_uncheck_all: Deselecteer alle + button_unlock: Open + button_unwatch: Niet meer monitoren + button_update: Update + button_view: Bekijken + button_watch: Monitor + default_activity_design: Ontwerp + default_activity_development: Ontwikkeling + default_doc_category_tech: Technische documentatie + default_doc_category_user: Gebruikersdocumentatie + default_issue_status_in_progress: In Progress + default_issue_status_closed: Gesloten + default_issue_status_feedback: Terugkoppeling + default_issue_status_new: Nieuw + default_issue_status_rejected: Afgewezen + default_issue_status_resolved: Opgelost + default_priority_high: Hoog + default_priority_immediate: Onmiddellijk + default_priority_low: Laag + default_priority_normal: Normaal + default_priority_urgent: Spoed + default_role_developer: Ontwikkelaar + default_role_manager: Manager + default_role_reporter: Rapporteur + default_tracker_bug: Bug + default_tracker_feature: Feature + default_tracker_support: Support + enumeration_activities: Activiteiten (tijdtracking) + enumeration_doc_categories: Documentcategorieën + enumeration_issue_priorities: Issueprioriteiten + error_can_t_load_default_data: "De standaard configuratie kon niet worden geladen: %{value}" + error_issue_not_found_in_project: 'Deze issue is niet gevonden of behoort niet toe tot dit project.' + error_scm_annotate: "Er kan geen commentaar toegevoegd worden." + error_scm_command_failed: "Er trad een fout op tijdens de poging om verbinding te maken met de repository: %{value}" + error_scm_not_found: "Deze ingang of revisie bestaat niet in de repository." + field_account: Account + field_activity: Activiteit + field_admin: Beheerder + field_assignable: Issues kunnen toegewezen worden aan deze rol + field_assigned_to: Toegewezen aan + field_attr_firstname: Voornaam attribuut + field_attr_lastname: Achternaam attribuut + field_attr_login: Login attribuut + field_attr_mail: E-mail attribuut + field_auth_source: Authenticatiemethode + field_author: Auteur + field_base_dn: Base DN + field_category: Categorie + field_column_names: Kolommen + field_comments: Commentaar + field_comments_sorting: Commentaar weergeven + field_created_on: Aangemaakt + field_default_value: Standaardwaarde + field_delay: Vertraging + field_description: Beschrijving + field_done_ratio: "% Gereed" + field_downloads: Downloads + field_due_date: Verwachte datum gereed + field_effective_date: Datum + field_estimated_hours: Geschatte tijd + field_field_format: Formaat + field_filename: Bestand + field_filesize: Grootte + field_firstname: Voornaam + field_fixed_version: Versie + field_hide_mail: Verberg mijn e-mailadres + field_homepage: Homepage + field_host: Host + field_hours: Uren + field_identifier: Identificatiecode + field_is_closed: Issue gesloten + field_is_default: Standaard + field_is_filter: Gebruikt als een filter + field_is_for_all: Voor alle projecten + field_is_in_roadmap: Issues weergegeven in roadmap + field_is_public: Publiek + field_is_required: Verplicht + field_issue: Issue + field_issue_to: Gerelateerd issue + field_language: Taal + field_last_login_on: Laatste bezoek + field_lastname: Achternaam + field_login: Gebruikersnaam + field_mail: E-mail + field_mail_notification: Mail notificaties + field_max_length: Maximale lengte + field_min_length: Minimale lengte + field_name: Naam + field_new_password: Nieuw wachtwoord + field_notes: Notities + field_onthefly: On-the-fly aanmaken van een gebruiker + field_parent: Subproject van + field_parent_title: Bovenliggende pagina + field_password: Wachtwoord + field_password_confirmation: Bevestig wachtwoord + field_port: Port + field_possible_values: Mogelijke waarden + field_priority: Prioriteit + field_project: Project + field_redirect_existing_links: Verwijs bestaande links door + field_regexp: Reguliere expressie + field_role: Rol + field_searchable: Doorzoekbaar + field_spent_on: Datum + field_start_date: Startdatum + field_start_page: Startpagina + field_status: Status + field_subject: Onderwerp + field_subproject: Subproject + field_summary: Samenvatting + field_time_zone: Tijdzone + field_title: Titel + field_tracker: Tracker + field_type: Type + field_updated_on: Gewijzigd + field_url: URL + field_user: Gebruiker + field_value: Waarde + field_version: Versie + general_csv_decimal_separator: ',' + general_csv_encoding: ISO-8859-1 + general_csv_separator: ';' + general_first_day_of_week: '7' + general_lang_name: 'Nederlands' + general_pdf_encoding: UTF-8 + general_text_No: 'Nee' + general_text_Yes: 'Ja' + general_text_no: 'nee' + general_text_yes: 'ja' + label_activity: Activiteit + label_add_another_file: Ander bestand toevoegen + label_add_note: Voeg een notitie toe + label_added: toegevoegd + label_added_time_by: "Toegevoegd door %{author} %{age} geleden" + label_administration: Administratie + label_age: Leeftijd + label_ago: dagen geleden + label_all: alle + label_all_time: alles + label_all_words: Alle woorden + label_and_its_subprojects: "%{value} en zijn subprojecten." + label_applied_status: Toegekende status + label_assigned_to_me_issues: Aan mij toegewezen issues + label_associated_revisions: Geassociëerde revisies + label_attachment: Bestand + label_attachment_delete: Verwijder bestand + label_attachment_new: Nieuw bestand + label_attachment_plural: Bestanden + label_attribute: Attribuut + label_attribute_plural: Attributen + label_auth_source: Authenticatiemodus + label_auth_source_new: Nieuwe authenticatiemodus + label_auth_source_plural: Authenticatiemodi + label_authentication: Authenticatie + label_blocked_by: geblokkeerd door + label_blocks: blokkeert + label_board: Forum + label_board_new: Nieuw forum + label_board_plural: Forums + label_boolean: Boolean + label_browse: Blader + label_bulk_edit_selected_issues: Bewerk geselecteerde issues in bulk + label_calendar: Kalender + label_change_plural: Wijzigingen + label_change_properties: Eigenschappen wijzigen + label_change_status: Wijzig status + label_change_view_all: Bekijk alle wijzigingen + label_changes_details: Details van alle wijzigingen + label_changeset_plural: Changesets + label_chronological_order: In chronologische volgorde + label_closed_issues: gesloten + label_closed_issues_plural: gesloten + label_x_open_issues_abbr_on_total: + zero: 0 open / %{total} + one: 1 open / %{total} + other: "%{count} open / %{total}" + label_x_open_issues_abbr: + zero: 0 open + one: 1 open + other: "%{count} open" + label_x_closed_issues_abbr: + zero: 0 gesloten + one: 1 gesloten + other: "%{count} gesloten" + label_comment: Commentaar + label_comment_add: Voeg commentaar toe + label_comment_added: Commentaar toegevoegd + label_comment_delete: Verwijder commentaar + label_comment_plural: Commentaar + label_x_comments: + zero: geen commentaar + one: 1x commentaar + other: "%{count}x commentaar" + label_commits_per_author: Commits per auteur + label_commits_per_month: Commits per maand + label_confirmation: Bevestiging + label_contains: bevat + label_copied: gekopieerd + label_copy_workflow_from: Kopieer workflow van + label_current_status: Huidige status + label_current_version: Huidige versie + label_custom_field: Specifiek veld + label_custom_field_new: Nieuw specifiek veld + label_custom_field_plural: Specifieke velden + label_date: Datum + label_date_from: Van + label_date_range: Datumbereik + label_date_to: Tot + label_day_plural: dagen + label_default: Standaard + label_default_columns: Standaard kolommen. + label_deleted: verwijderd + label_details: Details + label_diff_inline: inline + label_diff_side_by_side: naast elkaar + label_disabled: uitgeschakeld + label_display_per_page: "Per pagina: %{value}" + label_document: Document + label_document_added: Document toegevoegd + label_document_new: Nieuw document + label_document_plural: Documenten + label_downloads_abbr: D/L + label_duplicated_by: gedupliceerd door + label_duplicates: dupliceert + label_end_to_end: eind tot eind + label_end_to_start: eind tot start + label_enumeration_new: Nieuwe waarde + label_enumerations: Enumeraties + label_environment: Omgeving + label_equals: is gelijk + label_example: Voorbeeld + label_export_to: Exporteer naar + label_f_hour: "%{value} uur" + label_f_hour_plural: "%{value} uren" + label_feed_plural: Feeds + label_feeds_access_key_created_on: "RSS toegangssleutel %{value} geleden gemaakt." + label_file_added: Bestand toegevoegd + label_file_plural: Bestanden + label_filter_add: Voeg filter toe + label_filter_plural: Filters + label_float: Float + label_follows: volgt op + label_gantt: Gantt + label_general: Algemeen + label_generate_key: Genereer een sleutel + label_help: Help + label_history: Geschiedenis + label_home: Home + label_in: in + label_in_less_than: in minder dan + label_in_more_than: in meer dan + label_incoming_emails: Inkomende e-mail + label_index_by_date: Indexeer op datum + label_index_by_title: Indexeer op titel + label_information: Informatie + label_information_plural: Informatie + label_integer: Integer + label_internal: Intern + label_issue: Incident + label_issue_added: Incident toegevoegd + label_issue_category: Incident categorie + label_issue_category_new: Nieuwe categorie + label_issue_category_plural: Issuecategorieën + label_issue_new: Nieuw incident + label_issue_plural: Incidenten + label_issue_status: Incident status + label_issue_status_new: Nieuwe status + label_issue_status_plural: Incident statussen + label_issue_tracking: Incident-tracking + label_issue_updated: Incident bijgewerkt + label_issue_view_all: Bekijk alle incidenten + label_issue_watchers: Monitoren + label_issues_by: "Issues door %{value}" + label_jump_to_a_project: Ga naar een project... + label_language_based: Taal gebaseerd + label_last_changes: "laatste %{count} wijzigingen" + label_last_login: Laatste bezoek + label_last_month: laatste maand + label_last_n_days: "%{count} dagen geleden" + label_last_week: vorige week + label_latest_revision: Meest recente revisie + label_latest_revision_plural: Meest recente revisies + label_ldap_authentication: LDAP authenticatie + label_less_than_ago: minder dan x dagen geleden + label_list: Lijst + label_loading: Laden... + label_logged_as: Ingelogd als + label_login: Inloggen + label_logout: Uitloggen + label_max_size: Maximumgrootte + label_me: mij + label_member: Lid + label_member_new: Nieuw lid + label_member_plural: Leden + label_message_last: Laatste bericht + label_message_new: Nieuw bericht + label_message_plural: Berichten + label_message_posted: Bericht toegevoegd + label_min_max_length: Min-max lengte + label_modified: gewijzigd + label_module_plural: Modules + label_month: Maand + label_months_from: maanden vanaf + label_more: Meer + label_more_than_ago: meer dan x dagen geleden + label_my_account: Mijn account + label_my_page: Mijn pagina + label_my_projects: Mijn projecten + label_new: Nieuw + label_new_statuses_allowed: Nieuwe toegestane statussen + label_news: Nieuws + label_news_added: Nieuws toegevoegd + label_news_latest: Laatste nieuws + label_news_new: Voeg nieuws toe + label_news_plural: Nieuws + label_news_view_all: Bekijk al het nieuws + label_next: Volgende + label_no_change_option: (Geen wijziging) + label_no_data: Geen gegevens om te tonen + label_nobody: niemand + label_none: geen + label_not_contains: bevat niet + label_not_equals: is niet gelijk + label_open_issues: open + label_open_issues_plural: open + label_optional_description: Optionele beschrijving + label_options: Opties + label_overall_activity: Activiteit + label_overview: Overzicht + label_password_lost: Wachtwoord verloren + label_per_page: Per pagina + label_permissions: Permissies + label_permissions_report: Permissierapport + label_personalize_page: Personaliseer deze pagina + label_planning: Planning + label_please_login: Log a.u.b. in + label_plugins: Plugins + label_precedes: gaat vooraf aan + label_preferences: Voorkeuren + label_preview: Voorbeeldweergave + label_previous: Vorige + label_project: Project + label_project_all: Alle projecten + label_project_latest: Nieuwste projecten + label_project_new: Nieuw project + label_project_plural: Projecten + label_x_projects: + zero: geen projecten + one: 1 project + other: "%{count} projecten" + label_public_projects: Publieke projecten + label_query: Eigen zoekopdracht + label_query_new: Nieuwe zoekopdracht + label_query_plural: Eigen zoekopdrachten + label_read: Lees... + label_register: Registreer + label_registered_on: Geregistreerd op + label_registration_activation_by_email: accountactivatie per e-mail + label_registration_automatic_activation: automatische accountactivatie + label_registration_manual_activation: handmatige accountactivatie + label_related_issues: Gerelateerde issues + label_relates_to: gerelateerd aan + label_relation_delete: Verwijder relatie + label_relation_new: Nieuwe relatie + label_renamed: hernoemd + label_reply_plural: Antwoorden + label_report: Rapport + label_report_plural: Rapporten + label_reported_issues: Gemelde issues + label_repository: Repository + label_repository_plural: Repositories + label_result_plural: Resultaten + label_reverse_chronological_order: In omgekeerde chronologische volgorde + label_revision: Revisie + label_revision_plural: Revisies + label_roadmap: Roadmap + label_roadmap_due_in: "Voldaan in %{value}" + label_roadmap_no_issues: Geen issues voor deze versie + label_roadmap_overdue: "%{value} over tijd" + label_role: Rol + label_role_and_permissions: Rollen en permissies + label_role_new: Nieuwe rol + label_role_plural: Rollen + label_scm: SCM + label_search: Zoeken + label_search_titles_only: Enkel titels doorzoeken + label_send_information: Stuur accountinformatie naar de gebruiker + label_send_test_email: Stuur een test e-mail + label_settings: Instellingen + label_show_completed_versions: Toon afgeronde versies + label_sort_by: "Sorteer op %{value}" + label_sort_higher: Verplaats naar boven + label_sort_highest: Verplaats naar begin + label_sort_lower: Verplaats naar beneden + label_sort_lowest: Verplaats naar eind + label_spent_time: Gespendeerde tijd + label_start_to_end: start tot eind + label_start_to_start: start tot start + label_statistics: Statistieken + label_stay_logged_in: Blijf ingelogd + label_string: Tekst + label_subproject_plural: Subprojecten + label_text: Lange tekst + label_theme: Thema + label_this_month: deze maand + label_this_week: deze week + label_this_year: dit jaar + label_time_tracking: Tijdregistratie bijhouden + label_today: vandaag + label_topic_plural: Onderwerpen + label_total: Totaal + label_tracker: Tracker + label_tracker_new: Nieuwe tracker + label_tracker_plural: Trackers + label_updated_time: "%{value} geleden bijgewerkt" + label_updated_time_by: "%{age} geleden bijgewerkt door %{author}" + label_used_by: Gebruikt door + label_user: Gebruiker + label_user_activity: "%{value}'s activiteit" + label_user_mail_no_self_notified: Ik wil niet op de hoogte gehouden worden van mijn eigen wijzigingen + label_user_mail_option_all: "Bij elk gebeurtenis in al mijn projecten..." + label_user_mail_option_selected: "Enkel bij elke gebeurtenis op het geselecteerde project..." + label_user_new: Nieuwe gebruiker + label_user_plural: Gebruikers + label_version: Versie + label_version_new: Nieuwe versie + label_version_plural: Versies + label_view_diff: Bekijk verschillen + label_view_revisions: Bekijk revisies + label_watched_issues: Gemonitorde issues + label_week: Week + label_wiki: Wiki + label_wiki_edit: Wiki edit + label_wiki_edit_plural: Wiki edits + label_wiki_page: Wikipagina + label_wiki_page_plural: Wikipagina's + label_workflow: Workflow + label_year: Jaar + label_yesterday: gisteren + mail_body_account_activation_request: "Een nieuwe gebruiker (%{value}) is geregistreerd. Zijn account wacht op uw akkoord:" + mail_body_account_information: Uw account gegevens + mail_body_account_information_external: "U kunt uw account (%{value}) gebruiken om in te loggen." + mail_body_lost_password: 'Gebruik de volgende link om uw wachtwoord te wijzigen:' + mail_body_register: 'Gebruik de volgende link om uw account te activeren:' + mail_body_reminder: "%{count} issue(s) die aan u toegewezen zijn en voldaan moeten zijn in de komende %{days} dagen:" + mail_subject_account_activation_request: "%{value} accountactivatieverzoek" + mail_subject_lost_password: "uw %{value} wachtwoord" + mail_subject_register: "uw %{value} accountactivatie" + mail_subject_reminder: "%{count} issue(s) die voldaan moeten zijn in de komende %{days} dagen." + notice_account_activated: uw account is geactiveerd. u kunt nu inloggen. + notice_account_invalid_creditentials: Incorrecte gebruikersnaam of wachtwoord + notice_account_lost_email_sent: Er is een e-mail naar u verstuurd met instructies over het kiezen van een nieuw wachtwoord. + notice_account_password_updated: Wachtwoord is met succes gewijzigd + notice_account_pending: "Uw account is aangemaakt, maar wacht nog op goedkeuring van de beheerder." + notice_account_register_done: Account is met succes aangemaakt. + notice_account_unknown_email: Onbekende gebruiker. + notice_account_updated: Account is met succes gewijzigd + notice_account_wrong_password: Incorrect wachtwoord + notice_can_t_change_password: Dit account gebruikt een externe bron voor authenticatie. Het is niet mogelijk om het wachtwoord te veranderen. + notice_default_data_loaded: Standaard configuratie succesvol geladen. + notice_email_error: "Er is een fout opgetreden tijdens het versturen van (%{value})" + notice_email_sent: "Een e-mail werd verstuurd naar %{value}" + notice_failed_to_save_issues: "Fout bij bewaren van %{count} issue(s) (%{total} geselecteerd): %{ids}." + notice_feeds_access_key_reseted: Je RSS toegangssleutel werd gereset. + notice_file_not_found: De pagina die u probeerde te benaderen bestaat niet of is verwijderd. + notice_locking_conflict: De gegevens zijn gewijzigd door een andere gebruiker. + notice_no_issue_selected: "Er is geen issue geselecteerd. Selecteer de issue die u wilt bewerken." + notice_not_authorized: Het is u niet toegestaan deze pagina te raadplegen. + notice_successful_connection: Verbinding succesvol. + notice_successful_create: Succesvol aangemaakt. + notice_successful_delete: Succesvol verwijderd. + notice_successful_update: Wijzigen succesvol. + notice_unable_delete_version: Niet mogelijk om deze versie te verwijderen. + permission_add_issue_notes: Voeg notities toe + permission_add_issue_watchers: Voeg monitors toe + permission_add_issues: Voeg issues toe + permission_add_messages: Voeg berichten toe + permission_browse_repository: Repository doorbladeren + permission_comment_news: Nieuws commentaar geven + permission_commit_access: Commit toegang + permission_delete_issues: Issues verwijderen + permission_delete_messages: Berichten verwijderen + permission_delete_own_messages: Eigen berichten verwijderen + permission_delete_wiki_pages: Wiki pagina's verwijderen + permission_delete_wiki_pages_attachments: Bijlagen verwijderen + permission_edit_issue_notes: Notities bewerken + permission_edit_issues: Issues bewerken + permission_edit_messages: Berichten bewerken + permission_edit_own_issue_notes: Eigen notities bewerken + permission_edit_own_messages: Eigen berichten bewerken + permission_edit_own_time_entries: Eigen tijdlogboek bewerken + permission_edit_project: Project bewerken + permission_edit_time_entries: Tijdlogboek bewerken + permission_edit_wiki_pages: Wiki pagina's bewerken + permission_log_time: Gespendeerde tijd loggen + permission_manage_boards: Forums beheren + permission_manage_categories: Issue-categorieën beheren + permission_manage_files: Bestanden beheren + permission_manage_issue_relations: Issuerelaties beheren + permission_manage_members: Leden beheren + permission_manage_news: Nieuws beheren + permission_manage_public_queries: Publieke queries beheren + permission_manage_repository: Repository beheren + permission_manage_versions: Versiebeheer + permission_manage_wiki: Wikibeheer + permission_move_issues: Issues verplaatsen + permission_protect_wiki_pages: Wikipagina's beschermen + permission_rename_wiki_pages: Wikipagina's hernoemen + permission_save_queries: Queries opslaan + permission_select_project_modules: Project modules selecteren + permission_view_calendar: Kalender bekijken + permission_view_changesets: Changesets bekijken + permission_view_documents: Documenten bekijken + permission_view_files: Bestanden bekijken + permission_view_gantt: Gantt grafiek bekijken + permission_view_issue_watchers: Monitorlijst bekijken + permission_view_messages: Berichten bekijken + permission_view_time_entries: Gespendeerde tijd bekijken + permission_view_wiki_edits: Wikihistorie bekijken + permission_view_wiki_pages: Wikipagina's bekijken + project_module_boards: Forums + project_module_documents: Documenten + project_module_files: Bestanden + project_module_issue_tracking: Issue tracking + project_module_news: Nieuws + project_module_repository: Repository + project_module_time_tracking: Tijd tracking + project_module_wiki: Wiki + setting_activity_days_default: Aantal dagen getoond bij het tabblad "Activiteit" + setting_app_subtitle: Applicatieondertitel + setting_app_title: Applicatietitel + setting_attachment_max_size: Attachment max. grootte + setting_autofetch_changesets: Haal commits automatisch op + setting_autologin: Automatisch inloggen + setting_bcc_recipients: Blind carbon copy ontvangers (bcc) + setting_commit_fix_keywords: Gefixeerde trefwoorden + setting_commit_ref_keywords: Refererende trefwoorden + setting_cross_project_issue_relations: Sta cross-project issuerelaties toe + setting_date_format: Datumformaat + setting_default_language: Standaard taal + setting_default_projects_public: Nieuwe projecten zijn standaard publiek + setting_diff_max_lines_displayed: Max aantal diff regels weer te geven + setting_display_subprojects_issues: Standaard issues van subproject tonen + setting_emails_footer: E-mails voettekst + setting_enabled_scm: SCM ingeschakeld + setting_feeds_limit: Feedinhoudlimiet + setting_gravatar_enabled: Gebruik Gravatar gebruikersiconen + setting_host_name: Hostnaam + setting_issue_list_default_columns: Standaardkolommen getoond op de lijst met issues + setting_issues_export_limit: Max aantal te exporteren issues + setting_login_required: Authenticatie vereist + setting_mail_from: Afzender e-mail adres + setting_mail_handler_api_enabled: Schakel WS in voor inkomende mail. + setting_mail_handler_api_key: API sleutel + setting_per_page_options: Aantal objecten per pagina (opties) + setting_plain_text_mail: platte tekst (geen HTML) + setting_protocol: Protocol + setting_self_registration: Zelfregistratie toegestaan + setting_sequential_project_identifiers: Genereer sequentiële projectidentiteiten + setting_sys_api_enabled: Gebruik WS voor repository beheer + setting_text_formatting: Tekstformaat + setting_time_format: Tijd formaat + setting_user_format: Gebruikers weergaveformaat + setting_welcome_text: Welkomsttekst + setting_wiki_compression: Wikigeschiedenis comprimeren + status_active: actief + status_locked: vergrendeld + status_registered: geregistreerd + text_are_you_sure: Weet u het zeker? + text_assign_time_entries_to_project: Gerapporteerde uren toevoegen aan dit project + text_caracters_maximum: "%{count} van maximum aantal tekens." + text_caracters_minimum: "Moet minstens %{count} karakters lang zijn." + text_comma_separated: Meerdere waarden toegestaan (kommagescheiden). + text_default_administrator_account_changed: Standaard beheerderaccount gewijzigd + text_destroy_time_entries: Verwijder gerapporteerde uren + text_destroy_time_entries_question: "%{hours} uren werden gerapporteerd op de issue(s) die u wilde verwijderen. Wat wil u doen?" + text_diff_truncated: '... Deze diff werd afgekort omdat het de maximale weer te geven karakters overschreed.' + text_email_delivery_not_configured: "E-mailbezorging is niet geconfigureerd. Mededelingen zijn uitgeschakeld.\nConfigureer uw SMTP server in config/configuration.yml en herstart de applicatie om dit te activeren." + text_enumeration_category_reassign_to: 'Wijs de volgende waarde toe:' + text_enumeration_destroy_question: "%{count} objecten zijn toegewezen aan deze waarde." + text_file_repository_writable: Bestandsrepository beschrijfbaar + text_issue_added: "Issue %{id} is gerapporteerd (door %{author})." + text_issue_category_destroy_assignments: Verwijder toewijzingen aan deze categorie + text_issue_category_destroy_question: "Er zijn issues (%{count}) aan deze categorie toegewezen. Wat wilt u hiermee doen ?" + text_issue_category_reassign_to: Issues opnieuw toewijzen aan deze categorie + text_issue_updated: "Issue %{id} is gewijzigd (door %{author})." + text_issues_destroy_confirmation: 'Weet u zeker dat u deze issue(s) wil verwijderen?' + text_issues_ref_in_commit_messages: Opzoeken en aanpassen van issues in commitberichten + text_length_between: "Lengte tussen %{min} en %{max} tekens." + text_load_default_configuration: Laad de standaardconfiguratie + text_min_max_length_info: 0 betekent geen restrictie + text_no_configuration_data: "Rollen, trackers, issue statussen en workflows zijn nog niet geconfigureerd.\nHet is ten zeerste aangeraden om de standaard configuratie in te laden. U kunt deze aanpassen nadat deze is ingeladen." + text_plugin_assets_writable: Plugin assets directory beschrijfbaar + text_project_destroy_confirmation: Weet u zeker dat u dit project en alle gerelateerde gegevens wilt verwijderen? + text_project_identifier_info: 'Alleen kleine letter (a-z), cijfers, streepjes en liggende streepjes zijn toegestaan.
    Eenmaal opgeslagen kan de identifier niet worden gewijzigd.' + text_reassign_time_entries: 'Gerapporteerde uren opnieuw toewijzen:' + text_regexp_info: bv. ^[A-Z0-9]+$ + text_repository_usernames_mapping: "Koppel de Redminegebruikers aan gebruikers in de repository log.\nGebruikers met dezelfde Redmine en repository gebruikersnaam of email worden automatisch gekoppeld." + text_rmagick_available: RMagick beschikbaar (optioneel) + text_select_mail_notifications: Selecteer acties waarvoor mededelingen via mail moeten worden verstuurd. + text_select_project_modules: 'Selecteer de modules die u wilt gebruiken voor dit project:' + text_status_changed_by_changeset: "Toegepast in changeset %{value}." + text_subprojects_destroy_warning: "De subprojecten: %{value} zullen ook verwijderd worden." + text_tip_issue_begin_day: issue die op deze dag begint + text_tip_issue_begin_end_day: issue die op deze dag begint en eindigt + text_tip_issue_end_day: issue die op deze dag eindigt + text_tracker_no_workflow: Geen workflow gedefinieerd voor deze tracker + text_unallowed_characters: Niet toegestane tekens + text_user_mail_option: "Bij niet-geselecteerde projecten zult u enkel mededelingen ontvangen voor issues die u monitort of waar u bij betrokken bent (als auteur of toegewezen persoon)." + text_user_wrote: "%{value} schreef:" + text_wiki_destroy_confirmation: Weet u zeker dat u deze wiki en zijn inhoud wenst te verwijderen? + text_workflow_edit: Selecteer een rol en een tracker om de workflow te wijzigen + warning_attachments_not_saved: "%{count} bestand(en) konden niet opgeslagen worden." + button_create_and_continue: Maak en ga verder + text_custom_field_possible_values_info: 'Per lijn een waarde' + label_display: Toon + field_editable: Bewerkbaar + setting_repository_log_display_limit: Max aantal revisies zichbaar + setting_file_max_size_displayed: Max grootte van tekst bestanden inline zichtbaar + field_watcher: Watcher + setting_openid: Sta OpenID login en registratie toe + field_identity_url: OpenID URL + label_login_with_open_id_option: of login met je OpenID + field_content: Content + label_descending: Aflopend + label_sort: Sorteer + label_ascending: Oplopend + label_date_from_to: Van %{start} tot %{end} + label_greater_or_equal: ">=" + label_less_or_equal: <= + text_wiki_page_destroy_question: Deze pagina heeft %{descendants} subpagina's en onderliggende pagina's?. Wat wilt u hiermee doen? + text_wiki_page_reassign_children: Alle subpagina's toewijzen aan deze hoofdpagina + text_wiki_page_nullify_children: Behoud subpagina's als hoofdpagina's + text_wiki_page_destroy_children: Verwijder alle subpagina's en onderliggende pagina's + setting_password_min_length: Minimum wachtwoord lengte + field_group_by: Groepeer resultaten per + mail_subject_wiki_content_updated: "'%{id}' wiki pagina is bijgewerkt" + label_wiki_content_added: Wiki pagina toegevoegd + mail_subject_wiki_content_added: "'%{id}' wiki pagina is toegevoegd" + mail_body_wiki_content_added: De '%{id}' wiki pagina is toegevoegd door %{author}. + label_wiki_content_updated: Wiki pagina bijgewerkt + mail_body_wiki_content_updated: De '%{id}' wiki pagina is bijgewerkt door %{author}. + permission_add_project: Maak project + setting_new_project_user_role_id: Rol van gebruiker die een project maakt + label_view_all_revisions: Bekijk alle revisies + label_tag: Tag + label_branch: Branch + error_no_tracker_in_project: Geen tracker is geassocieerd met dit project. Check de project instellingen. + error_no_default_issue_status: Geen standaard issue status ingesteld. Check de configuratie (Ga naar "Administratie -> Issue statussen"). + text_journal_changed: "%{label} gewijzigd van %{old} naar %{new}" + text_journal_set_to: "%{label} gewijzigd naar %{value}" + text_journal_deleted: "%{label} verwijderd (%{old})" + label_group_plural: Groepen + label_group: Groep + label_group_new: Nieuwe groep + label_time_entry_plural: Bestede tijd + text_journal_added: "%{label} %{value} toegevoegd" + field_active: Actief + enumeration_system_activity: Systeem Activiteit + permission_delete_issue_watchers: Verwijder volgers + version_status_closed: gesloten + version_status_locked: vergrendeld + version_status_open: open + error_can_not_reopen_issue_on_closed_version: Een issue toegewezen aan een gesloten versie kan niet heropend worden + label_user_anonymous: Anoniem + button_move_and_follow: Verplaats en volg + setting_default_projects_modules: Standaard geactiveerde modules voor nieuwe projecten + setting_gravatar_default: Standaard Gravatar plaatje + field_sharing: Delen + label_version_sharing_hierarchy: Met project hiërarchie + label_version_sharing_system: Met alle projecten + label_version_sharing_descendants: Met subprojecten + label_version_sharing_tree: Met project boom + label_version_sharing_none: Niet gedeeld + error_can_not_archive_project: Dit project kan niet worden gearchiveerd + button_duplicate: Dupliceer + button_copy_and_follow: Kopiëer en volg + label_copy_source: Bron + setting_issue_done_ratio: Bereken issue percentage voldaan met + setting_issue_done_ratio_issue_status: Gebruik de issue status + error_issue_done_ratios_not_updated: Issue percentage voldaan niet geupdate. + error_workflow_copy_target: Selecteer tracker(s) en rol(len) + setting_issue_done_ratio_issue_field: Gebruik het issue veld + label_copy_same_as_target: Zelfde als doel + label_copy_target: Doel + notice_issue_done_ratios_updated: Issue percentage voldaan geupdate. + error_workflow_copy_source: Selecteer een bron tracker of rol + label_update_issue_done_ratios: Update issue percentage voldaan + setting_start_of_week: Week begint op + permission_view_issues: Bekijk Issues + label_display_used_statuses_only: Laat alleen statussen zien die gebruikt worden door deze tracker + label_revision_id: Revisie %{value} + label_api_access_key: API access key + label_api_access_key_created_on: API access key gemaakt %{value} geleden + label_feeds_access_key: RSS access key + notice_api_access_key_reseted: Uw API access key was gereset. + setting_rest_api_enabled: Activeer REST web service + label_missing_api_access_key: Geen API access key + label_missing_feeds_access_key: Geen RSS access key + button_show: Laat zien + text_line_separated: Meerdere waarden toegestaan (elke regel is een waarde). + setting_mail_handler_body_delimiters: Breek email verwerking af na een van deze regels + permission_add_subprojects: Maak subprojecten + label_subproject_new: Nieuw subproject + text_own_membership_delete_confirmation: |- + U staat op punt om sommige of alle van uw permissies te verwijderen en bent mogelijk niet meer toegestaan om dit project hierna te wijzigen. + Wilt u doorgaan? + label_close_versions: Sluit complete versies + label_board_sticky: Sticky + label_board_locked: Vergrendeld + permission_export_wiki_pages: Exporteer wiki pagina's + setting_cache_formatted_text: Cache opgemaakte tekst + permission_manage_project_activities: Beheer project activiteiten + error_unable_delete_issue_status: Verwijderen van issue status niet gelukt + label_profile: Profiel + permission_manage_subtasks: Beheer subtaken + field_parent_issue: Hoofdtaak + label_subtask_plural: Subtaken + label_project_copy_notifications: Stuur email notificaties voor de project kopie + error_can_not_delete_custom_field: Verwijderen niet mogelijk van custom field + error_unable_to_connect: Geen connectie (%{value}) + error_can_not_remove_role: Deze rol is in gebruik en kan niet worden verwijderd. + error_can_not_delete_tracker: Deze tracker bevat nog issues en kan niet worden verwijderd. + field_principal: Hoofd + label_my_page_block: Mijn pagina block + notice_failed_to_save_members: "Niet gelukt om lid/leden op te slaan: %{errors}." + text_zoom_out: Zoom uit + text_zoom_in: Zoom in + notice_unable_delete_time_entry: Verwijderen niet mogelijk van tijd log invoer. + label_overall_spent_time: Totaal bestede tijd + field_time_entries: Registreer tijd + project_module_gantt: Gantt + project_module_calendar: Kalender + button_edit_associated_wikipage: "Bewerk bijbehorende wiki pagina: %{page_title}" + field_text: Tekst veld + label_user_mail_option_only_owner: Alleen voor dingen waarvan ik de auteur ben + setting_default_notification_option: Standaard instelling voor mededelingen + label_user_mail_option_only_my_events: Alleen voor dingen die ik volg of bij betrokken ben + label_user_mail_option_only_assigned: Alleen voor dingen die aan mij zijn toegewezen + label_user_mail_option_none: Bij geen enkele gebeurtenis + field_member_of_group: Groep van toegewezene + field_assigned_to_role: Rol van toegewezene + notice_not_authorized_archived_project: Het project dat u wilt bezoeken is gearchiveerd. + label_principal_search: "Zoek naar gebruiker of groep:" + label_user_search: "Zoek naar gebruiker:" + field_visible: Zichtbaar + setting_commit_logtime_activity_id: Standaard activiteit voor tijdregistratie + text_time_logged_by_changeset: Toegepast in changeset %{value}. + setting_commit_logtime_enabled: Activeer tijdregistratie + notice_gantt_chart_truncated: De gantt chart is ingekort omdat het meer objecten bevat dan kan worden weergegeven, (%{max}) + setting_gantt_items_limit: Max. aantal objecten op gantt chart + field_warn_on_leaving_unsaved: Waarschuw me wanneer ik een pagina verlaat waarvan de tekst niet opgeslagen is + text_warn_on_leaving_unsaved: De huidige pagina bevat tekst die niet is opgeslagen en dit zal verloren gaan als u deze pagina nu verlaat. + label_my_queries: Mijn aangepaste zoekopdrachten + text_journal_changed_no_detail: "%{label} updated" + label_news_comment_added: Commentaar toegevoegd aan een nieuwsitem + button_expand_all: Klap uit + button_collapse_all: Klap in + label_additional_workflow_transitions_for_assignee: Aanvullende veranderingen toegestaan wanneer de gebruiker de toegewezene is + label_additional_workflow_transitions_for_author: Aanvullende veranderingen toegestaan wanneer de gebruiker de auteur is + label_bulk_edit_selected_time_entries: Massa wijziging geselecteerd tijd-registraties? + text_time_entries_destroy_confirmation: Weet u zeker dat u de geselecteerde item(s) wilt verwijderen ? + label_role_anonymous: Anoniem + label_role_non_member: Geen lid + label_issue_note_added: Notitie toegevoegd + label_issue_status_updated: Status gewijzigd + label_issue_priority_updated: Prioriteit geupdate + label_issues_visibility_own: Probleem aangemaakt door of toegewezen aan + field_issues_visibility: Incidenten weergave + label_issues_visibility_all: Alle incidenten + permission_set_own_issues_private: Zet eigen incidenten publiekelijk of privé + field_is_private: Privé + permission_set_issues_private: Zet incidenten publiekelijk of privé + label_issues_visibility_public: Alle niet privé-incidenten + text_issues_destroy_descendants_confirmation: Dit zal ook de %{count} subtaken verwijderen. + field_commit_logs_encoding: Encodering van commit berichten + field_scm_path_encoding: Pad encodering + text_scm_path_encoding_note: "Standaard: UTF-8" + field_path_to_repository: Pad naar versie overzicht + field_root_directory: Root directorie + field_cvs_module: Module + field_cvsroot: CVSROOT + text_mercurial_repository_note: "Lokale versie overzicht (Voorbeeld: /hgrepo, c:\\hgrepo)" + text_scm_command: Commando + text_scm_command_version: Versie + label_git_report_last_commit: Rapporteer laatste toevoegen voor bestanden en directories + text_scm_config: U kan de scm commando's configureren in config/configuration.yml. Herstart de applicatie na het wijzigen ervan. + text_scm_command_not_available: Scm commando is niet beschikbaar. Controleer de instellingen in het administratiepaneel. + notice_issue_successful_create: Probleem %{id} aangemaakt. + label_between: tussen + setting_issue_group_assignment: Sta groepstoewijzingen toe + label_diff: Verschil + text_git_repository_note: "Versie overzicht lokaal is leeg (Voorbeeld: /gitrepo, c:\\gitrepo)" + description_query_sort_criteria_direction: Sortering + description_project_scope: Zoek bereik + description_filter: Filter + description_user_mail_notification: Mail notificatie instellingen + description_date_from: Vul start datum in + description_message_content: Inhoud bericht + description_available_columns: Beschikbare kolommen + description_date_range_interval: Kies een bereik bij het selecteren van een start en eind datum + description_issue_category_reassign: Kies probleem categorie + description_search: Zoekveld + description_notes: Notities + description_date_range_list: Kies bereik vanuit de lijst + description_choose_project: Projecten + description_date_to: Vul eind datum in + description_query_sort_criteria_attribute: Sorteer attribuut + description_wiki_subpages_reassign: Kies nieuwe hoofdpagina + description_selected_columns: Geselecteerde kolommen + label_parent_revision: Hoofd + label_child_revision: Sub + error_scm_annotate_big_text_file: De vermelding kan niet worden geannoteerd, omdat het groter is dan de maximale toegewezen grootte. + setting_default_issue_start_date_to_creation_date: Gebruik huidige datum als start datum voor nieuwe incidenten. + button_edit_section: Wijzig deze sectie + setting_repositories_encodings: Bijlage en opgeslagen bestanden coderingen + description_all_columns: Alle kolommen + button_export: Exporteren + label_export_options: "%{export_format} export opties" + error_attachment_too_big: Dit bestand kan niet worden geupload omdat het de maximaal toegestane grootte overschrijd (%{max_size}) + notice_failed_to_save_time_entries: "Opslaan gefaald voor %{count} tijdsnotatie(s) van %{total} geselecteerde: %{ids}." + label_x_issues: + zero: 0 incidenten + one: 1 incidenten + other: "%{count} incidenten" + label_repository_new: Nieuw repository + field_repository_is_default: Hoofd repository + label_copy_attachments: Copieer bijlage(n) + label_item_position: "%{position}/%{count}" + label_completed_versions: Versies compleet + field_multiple: Meerdere waardes + setting_commit_cross_project_ref: Sta toe om incidenten van alle projecten te refereren en oplossen + text_issue_conflict_resolution_add_notes: Voeg mijn notities toe en annuleer andere wijzigingen + text_issue_conflict_resolution_overwrite: Voeg mijn wijzigingen alsnog toe (voorgaande notities worden bewaard, maar sommige kunnen overschreden worden) + notice_issue_update_conflict: Dit incident is reeds geupdate door een andere gebruiker terwijl jij bezig was + text_issue_conflict_resolution_cancel: Annuleer mijn wijzigingen en geef pagina opnieuw weer %{link} + permission_manage_related_issues: Beheer gerelateerde incidenten + field_auth_source_ldap_filter: LDAP filter + label_search_for_watchers: Zoek om monitoorders toe te voegen + notice_account_deleted: Uw account is permanent verwijderd + setting_unsubscribe: Sta gebruikers toe hun eigen account te verwijderen + button_delete_my_account: Verwijder mijn account + text_account_destroy_confirmation: |- + Weet u zeker dat u door wilt gaan? + Uw account wordt permanent verwijderd zonder mogelijkheid deze te heractiveren. + error_session_expired: Uw sessie is verlopen. U dient opnieuw in te loggen. + text_session_expiration_settings: "Waarschuwing: door deze instelling te wijzigen kan sessies laten verlopen inclusief de uwe" + setting_session_lifetime: Maximale sessieduur + setting_session_timeout: Sessie inactiviteit timeout + label_session_expiration: Sessie verlopen + permission_close_project: Sluit / heropen project + label_show_closed_projects: Gesloten projecten weergeven + button_close: Sluiten + button_reopen: Heropen + project_status_active: actief + project_status_closed: gesloten + project_status_archived: gearchiveerd + text_project_closed: Dit project is gesloten en op alleen-lezen + notice_user_successful_create: Gebruiker %{id} aangemaakt. + field_core_fields: Standaard verleden + field_timeout: Timeout (in seconden) + setting_thumbnails_enabled: Geef bijlage miniaturen weer + setting_thumbnails_size: Grootte miniaturen (in pixels) + label_status_transitions: Status transitie + label_fields_permissions: Permissie velden + label_readonly: Alleen-lezen + label_required: Verplicht + text_repository_identifier_info: 'Alleen kleine letter (a-z), cijfers, streepjes en liggende streepjes zijn toegestaan.
    Eenmaal opgeslagen kan de identifier niet worden gewijzigd.' + field_board_parent: Hoofd forum + label_attribute_of_project: Project %{name} + label_attribute_of_author: Auteur(s) %{name} + label_attribute_of_assigned_to: Toegewezen %{name} + label_attribute_of_fixed_version: Target versions %{name} + label_copy_subtasks: Kopieer subtaken + label_copied_to: gekopieerd naar + label_copied_from: gekopieerd van + label_any_issues_in_project: any issues in project + label_any_issues_not_in_project: any issues not in project + field_private_notes: Privé notities + permission_view_private_notes: Bekijk privé notities + permission_set_notes_private: Maak notities privé + label_no_issues_in_project: geen issues in project + label_any: alle + label_last_n_weeks: afgelopen %{count} weken + setting_cross_project_subtasks: Sta subtaken in andere projecten toe + label_cross_project_descendants: Met subprojecten + label_cross_project_tree: Met project boom + label_cross_project_hierarchy: Met project hiërarchie + label_cross_project_system: Met alle projecten + button_hide: Verberg + setting_non_working_week_days: Niet-werkdagen + label_in_the_next_days: in de volgende + label_in_the_past_days: in de afgelopen + label_attribute_of_user: User's %{name} + text_turning_multiple_off: Bij het uitschakelen van meerdere waardes zal er maar een waarde bewaard blijven. + label_attribute_of_issue: Issue's %{name} + permission_add_documents: Voeg documenten toe + permission_edit_documents: Bewerk documenten + permission_delete_documents: Verwijder documenten + label_gantt_progress_line: Voortgangslijn + setting_jsonp_enabled: Schakel JSONP support in + field_inherit_members: Neem leden over + field_closed_on: Gesloten + setting_default_projects_tracker_ids: Standaard trackers voor nieuwe projecten + label_total_time: Totaal + setting_emails_header: Email header diff --git a/config/locales/no.yml b/config/locales/no.yml new file mode 100644 index 00000000..e2249c59 --- /dev/null +++ b/config/locales/no.yml @@ -0,0 +1,1079 @@ +# Norwegian, norsk bokmål, by irb.no +"no": + support: + array: + sentence_connector: "og" + direction: ltr + date: + formats: + default: "%d.%m.%Y" + short: "%e. %b" + long: "%e. %B %Y" + day_names: [søndag, mandag, tirsdag, onsdag, torsdag, fredag, lørdag] + abbr_day_names: [søn, man, tir, ons, tor, fre, lør] + month_names: [~, januar, februar, mars, april, mai, juni, juli, august, september, oktober, november, desember] + abbr_month_names: [~, jan, feb, mar, apr, mai, jun, jul, aug, sep, okt, nov, des] + order: + - :day + - :month + - :year + time: + formats: + default: "%A, %e. %B %Y, %H:%M" + time: "%H:%M" + short: "%e. %B, %H:%M" + long: "%A, %e. %B %Y, %H:%M" + am: "" + pm: "" + datetime: + distance_in_words: + half_a_minute: "et halvt minutt" + less_than_x_seconds: + one: "mindre enn 1 sekund" + other: "mindre enn %{count} sekunder" + x_seconds: + one: "1 sekund" + other: "%{count} sekunder" + less_than_x_minutes: + one: "mindre enn 1 minutt" + other: "mindre enn %{count} minutter" + x_minutes: + one: "1 minutt" + other: "%{count} minutter" + about_x_hours: + one: "rundt 1 time" + other: "rundt %{count} timer" + x_hours: + one: "1 hour" + other: "%{count} hours" + x_days: + one: "1 dag" + other: "%{count} dager" + about_x_months: + one: "rundt 1 måned" + other: "rundt %{count} måneder" + x_months: + one: "1 måned" + other: "%{count} måneder" + about_x_years: + one: "rundt 1 år" + other: "rundt %{count} år" + over_x_years: + one: "over 1 år" + other: "over %{count} år" + almost_x_years: + one: "nesten 1 år" + other: "nesten %{count} år" + number: + format: + precision: 3 + separator: "." + delimiter: "," + currency: + format: + unit: "kr" + format: "%n %u" + precision: + format: + delimiter: "" + precision: 4 + human: + storage_units: + format: "%n %u" + units: + byte: + one: "Byte" + other: "Bytes" + kb: "KB" + mb: "MB" + gb: "GB" + tb: "TB" + + activerecord: + errors: + template: + header: "kunne ikke lagre %{model} på grunn av %{count} feil." + body: "det oppstod problemer i følgende felt:" + messages: + inclusion: "er ikke inkludert i listen" + exclusion: "er reservert" + invalid: "er ugyldig" + confirmation: "passer ikke bekreftelsen" + accepted: "må være akseptert" + empty: "kan ikke være tom" + blank: "kan ikke være blank" + too_long: "er for lang (maksimum %{count} tegn)" + too_short: "er for kort (minimum %{count} tegn)" + wrong_length: "er av feil lengde (maksimum %{count} tegn)" + taken: "er allerede i bruk" + not_a_number: "er ikke et tall" + greater_than: "må være større enn %{count}" + greater_than_or_equal_to: "må være større enn eller lik %{count}" + equal_to: "må være lik %{count}" + less_than: "må være mindre enn %{count}" + less_than_or_equal_to: "må være mindre enn eller lik %{count}" + odd: "må være oddetall" + even: "må være partall" + greater_than_start_date: "må være større enn startdato" + not_same_project: "hører ikke til samme prosjekt" + circular_dependency: "Denne relasjonen ville lagd en sirkulær avhengighet" + cant_link_an_issue_with_a_descendant: "En sak kan ikke kobles mot en av sine undersaker" + + + actionview_instancetag_blank_option: Vennligst velg + + general_text_No: 'Nei' + general_text_Yes: 'Ja' + general_text_no: 'nei' + general_text_yes: 'ja' + general_lang_name: 'Norwegian (Norsk bokmål)' + general_csv_separator: ',' + general_csv_decimal_separator: '.' + general_csv_encoding: ISO-8859-1 + general_pdf_encoding: UTF-8 + general_first_day_of_week: '1' + + notice_account_updated: Kontoen er oppdatert. + notice_account_invalid_creditentials: Feil brukernavn eller passord + notice_account_password_updated: Passordet er oppdatert. + notice_account_wrong_password: Feil passord + notice_account_register_done: Kontoen er opprettet. Klikk lenken som er sendt deg i e-post for å aktivere kontoen. + notice_account_unknown_email: Ukjent bruker. + notice_can_t_change_password: Denne kontoen bruker ekstern godkjenning. Passordet kan ikke endres. + notice_account_lost_email_sent: En e-post med instruksjoner for å velge et nytt passord er sendt til deg. + notice_account_activated: Din konto er aktivert. Du kan nå logge inn. + notice_successful_create: Opprettet. + notice_successful_update: Oppdatert. + notice_successful_delete: Slettet. + notice_successful_connection: Koblet opp. + notice_file_not_found: Siden du forsøkte å vise eksisterer ikke, eller er slettet. + notice_locking_conflict: Data har blitt oppdatert av en annen bruker. + notice_not_authorized: Du har ikke adgang til denne siden. + notice_email_sent: "En e-post er sendt til %{value}" + notice_email_error: "En feil oppstod under sending av e-post (%{value})" + notice_feeds_access_key_reseted: Din RSS-tilgangsnøkkel er nullstilt. + notice_failed_to_save_issues: "Lykkes ikke å lagre %{count} sak(er) på %{total} valgt: %{ids}." + notice_no_issue_selected: "Ingen sak valgt! Vennligst merk sakene du vil endre." + notice_account_pending: "Din konto ble opprettet og avventer nå administrativ godkjenning." + notice_default_data_loaded: Standardkonfigurasjonen lastet inn. + + error_can_t_load_default_data: "Standardkonfigurasjonen kunne ikke lastes inn: %{value}" + error_scm_not_found: "Elementet og/eller revisjonen eksisterer ikke i depoet." + error_scm_command_failed: "En feil oppstod under tilkobling til depoet: %{value}" + error_scm_annotate: "Elementet eksisterer ikke, eller kan ikke noteres." + error_issue_not_found_in_project: 'Saken eksisterer ikke, eller hører ikke til dette prosjektet' + + mail_subject_lost_password: "Ditt %{value} passord" + mail_body_lost_password: 'Klikk følgende lenke for å endre ditt passord:' + mail_subject_register: "%{value} kontoaktivering" + mail_body_register: 'Klikk følgende lenke for å aktivere din konto:' + mail_body_account_information_external: "Du kan bruke din %{value}-konto for å logge inn." + mail_body_account_information: Informasjon om din konto + mail_subject_account_activation_request: "%{value} kontoaktivering" + mail_body_account_activation_request: "En ny bruker (%{value}) er registrert, og avventer din godkjenning:" + mail_subject_reminder: "%{count} sak(er) har frist de kommende %{days} dagene" + mail_body_reminder: "%{count} sak(er) som er tildelt deg har frist de kommende %{days} dager:" + + + field_name: Navn + field_description: Beskrivelse + field_summary: Oppsummering + field_is_required: Kreves + field_firstname: Fornavn + field_lastname: Etternavn + field_mail: E-post + field_filename: Fil + field_filesize: Størrelse + field_downloads: Nedlastinger + field_author: Forfatter + field_created_on: Opprettet + field_updated_on: Oppdatert + field_field_format: Format + field_is_for_all: For alle prosjekter + field_possible_values: Lovlige verdier + field_regexp: Regular expression + field_min_length: Minimum lengde + field_max_length: Maksimum lengde + field_value: Verdi + field_category: Kategori + field_title: Tittel + field_project: Prosjekt + field_issue: Sak + field_status: Status + field_notes: Notater + field_is_closed: Lukker saken + field_is_default: Standardverdi + field_tracker: Sakstype + field_subject: Emne + field_due_date: Frist + field_assigned_to: Tildelt til + field_priority: Prioritet + field_fixed_version: Mål-versjon + field_user: Bruker + field_role: Rolle + field_homepage: Hjemmeside + field_is_public: Offentlig + field_parent: Underprosjekt av + field_is_in_roadmap: Vises i veikart + field_login: Brukernavn + field_mail_notification: E-post-varsling + field_admin: Administrator + field_last_login_on: Sist innlogget + field_language: Språk + field_effective_date: Dato + field_password: Passord + field_new_password: Nytt passord + field_password_confirmation: Bekreft passord + field_version: Versjon + field_type: Type + field_host: Vert + field_port: Port + field_account: Konto + field_base_dn: Base DN + field_attr_login: Brukernavnsattributt + field_attr_firstname: Fornavnsattributt + field_attr_lastname: Etternavnsattributt + field_attr_mail: E-post-attributt + field_onthefly: On-the-fly brukeropprettelse + field_start_date: Start + field_done_ratio: "% Ferdig" + field_auth_source: Autentiseringskilde + field_hide_mail: Skjul min epost-adresse + field_comments: Kommentarer + field_url: URL + field_start_page: Startside + field_subproject: Underprosjekt + field_hours: Timer + field_activity: Aktivitet + field_spent_on: Dato + field_identifier: Identifikasjon + field_is_filter: Brukes som filter + field_issue_to: Relaterte saker + field_delay: Forsinkelse + field_assignable: Saker kan tildeles denne rollen + field_redirect_existing_links: Viderekoble eksisterende lenker + field_estimated_hours: Estimert tid + field_column_names: Kolonner + field_time_zone: Tidssone + field_searchable: Søkbar + field_default_value: Standardverdi + field_comments_sorting: Vis kommentarer + + setting_app_title: Applikasjonstittel + setting_app_subtitle: Applikasjonens undertittel + setting_welcome_text: Velkomsttekst + setting_default_language: Standardspråk + setting_login_required: Krever innlogging + setting_self_registration: Selvregistrering + setting_attachment_max_size: Maks. størrelse vedlegg + setting_issues_export_limit: Eksportgrense for saker + setting_mail_from: Avsenders epost + setting_bcc_recipients: Blindkopi (bcc) til mottakere + setting_host_name: Vertsnavn + setting_text_formatting: Tekstformattering + setting_wiki_compression: Komprimering av Wiki-historikk + setting_feeds_limit: Innholdsgrense for Feed + setting_default_projects_public: Nye prosjekter er offentlige som standard + setting_autofetch_changesets: Autohenting av endringssett + setting_sys_api_enabled: Aktiver webservice for depot-administrasjon + setting_commit_ref_keywords: Nøkkelord for referanse + setting_commit_fix_keywords: Nøkkelord for retting + setting_autologin: Autoinnlogging + setting_date_format: Datoformat + setting_time_format: Tidsformat + setting_cross_project_issue_relations: Tillat saksrelasjoner på kryss av prosjekter + setting_issue_list_default_columns: Standardkolonner vist i sakslisten + setting_emails_footer: Epost-signatur + setting_protocol: Protokoll + setting_per_page_options: Alternativer, objekter pr. side + setting_user_format: Visningsformat, brukere + setting_activity_days_default: Dager vist på prosjektaktivitet + setting_display_subprojects_issues: Vis saker fra underprosjekter på hovedprosjekt som standard + setting_enabled_scm: Aktiviserte SCM + + project_module_issue_tracking: Sakshåndtering + project_module_time_tracking: Tidsregistrering + project_module_news: Nyheter + project_module_documents: Dokumenter + project_module_files: Filer + project_module_wiki: Wiki + project_module_repository: Depot + project_module_boards: Forumer + + label_user: Bruker + label_user_plural: Brukere + label_user_new: Ny bruker + label_project: Prosjekt + label_project_new: Nytt prosjekt + label_project_plural: Prosjekter + label_x_projects: + zero: ingen prosjekter + one: 1 prosjekt + other: "%{count} prosjekter" + label_project_all: Alle prosjekter + label_project_latest: Siste prosjekter + label_issue: Sak + label_issue_new: Ny sak + label_issue_plural: Saker + label_issue_view_all: Vis alle saker + label_issues_by: "Saker etter %{value}" + label_issue_added: Sak lagt til + label_issue_updated: Sak oppdatert + label_document: Dokument + label_document_new: Nytt dokument + label_document_plural: Dokumenter + label_document_added: Dokument lagt til + label_role: Rolle + label_role_plural: Roller + label_role_new: Ny rolle + label_role_and_permissions: Roller og rettigheter + label_member: Medlem + label_member_new: Nytt medlem + label_member_plural: Medlemmer + label_tracker: Sakstype + label_tracker_plural: Sakstyper + label_tracker_new: Ny sakstype + label_workflow: Arbeidsflyt + label_issue_status: Saksstatus + label_issue_status_plural: Saksstatuser + label_issue_status_new: Ny status + label_issue_category: Sakskategori + label_issue_category_plural: Sakskategorier + label_issue_category_new: Ny kategori + label_custom_field: Eget felt + label_custom_field_plural: Egne felt + label_custom_field_new: Nytt eget felt + label_enumerations: Listeverdier + label_enumeration_new: Ny verdi + label_information: Informasjon + label_information_plural: Informasjon + label_please_login: Vennlist logg inn + label_register: Registrer + label_password_lost: Mistet passord + label_home: Hjem + label_my_page: Min side + label_my_account: Min konto + label_my_projects: Mine prosjekter + label_administration: Administrasjon + label_login: Logg inn + label_logout: Logg ut + label_help: Hjelp + label_reported_issues: Rapporterte saker + label_assigned_to_me_issues: Saker tildelt meg + label_last_login: Sist innlogget + label_registered_on: Registrert + label_activity: Aktivitet + label_overall_activity: All aktivitet + label_new: Ny + label_logged_as: Innlogget som + label_environment: Miljø + label_authentication: Autentisering + label_auth_source: Autentiseringskilde + label_auth_source_new: Ny autentiseringskilde + label_auth_source_plural: Autentiseringskilder + label_subproject_plural: Underprosjekter + label_and_its_subprojects: "%{value} og dets underprosjekter" + label_min_max_length: Min.-maks. lengde + label_list: Liste + label_date: Dato + label_integer: Heltall + label_float: Kommatall + label_boolean: Sann/usann + label_string: Tekst + label_text: Lang tekst + label_attribute: Attributt + label_attribute_plural: Attributter + label_no_data: Ingen data å vise + label_change_status: Endre status + label_history: Historikk + label_attachment: Fil + label_attachment_new: Ny fil + label_attachment_delete: Slett fil + label_attachment_plural: Filer + label_file_added: Fil lagt til + label_report: Rapport + label_report_plural: Rapporter + label_news: Nyheter + label_news_new: Legg til nyhet + label_news_plural: Nyheter + label_news_latest: Siste nyheter + label_news_view_all: Vis alle nyheter + label_news_added: Nyhet lagt til + label_settings: Innstillinger + label_overview: Oversikt + label_version: Versjon + label_version_new: Ny versjon + label_version_plural: Versjoner + label_confirmation: Bekreftelse + label_export_to: Eksporter til + label_read: Leser... + label_public_projects: Offentlige prosjekt + label_open_issues: åpen + label_open_issues_plural: åpne + label_closed_issues: lukket + label_closed_issues_plural: lukkede + label_x_open_issues_abbr_on_total: + zero: 0 åpne / %{total} + one: 1 åpen / %{total} + other: "%{count} åpne / %{total}" + label_x_open_issues_abbr: + zero: 0 åpne + one: 1 åpen + other: "%{count} åpne" + label_x_closed_issues_abbr: + zero: 0 lukket + one: 1 lukket + other: "%{count} lukket" + label_total: Totalt + label_permissions: Rettigheter + label_current_status: Nåværende status + label_new_statuses_allowed: Tillate nye statuser + label_all: alle + label_none: ingen + label_nobody: ingen + label_next: Neste + label_previous: Forrige + label_used_by: Brukt av + label_details: Detaljer + label_add_note: Legg til notat + label_per_page: Pr. side + label_calendar: Kalender + label_months_from: måneder fra + label_gantt: Gantt + label_internal: Intern + label_last_changes: "siste %{count} endringer" + label_change_view_all: Vis alle endringer + label_personalize_page: Tilpass denne siden + label_comment: Kommentar + label_comment_plural: Kommentarer + label_x_comments: + zero: ingen kommentarer + one: 1 kommentar + other: "%{count} kommentarer" + label_comment_add: Legg til kommentar + label_comment_added: Kommentar lagt til + label_comment_delete: Slett kommentar + label_query: Egen spørring + label_query_plural: Egne spørringer + label_query_new: Ny spørring + label_filter_add: Legg til filter + label_filter_plural: Filtre + label_equals: er + label_not_equals: er ikke + label_in_less_than: er mindre enn + label_in_more_than: in mer enn + label_in: i + label_today: idag + label_all_time: all tid + label_yesterday: i går + label_this_week: denne uken + label_last_week: sist uke + label_last_n_days: "siste %{count} dager" + label_this_month: denne måneden + label_last_month: siste måned + label_this_year: dette året + label_date_range: Dato-spenn + label_less_than_ago: mindre enn dager siden + label_more_than_ago: mer enn dager siden + label_ago: dager siden + label_contains: inneholder + label_not_contains: ikke inneholder + label_day_plural: dager + label_repository: Depot + label_repository_plural: Depoter + label_browse: Utforsk + label_revision: Revisjon + label_revision_plural: Revisjoner + label_associated_revisions: Assosierte revisjoner + label_added: lagt til + label_modified: endret + label_deleted: slettet + label_latest_revision: Siste revisjon + label_latest_revision_plural: Siste revisjoner + label_view_revisions: Vis revisjoner + label_max_size: Maksimum størrelse + label_sort_highest: Flytt til toppen + label_sort_higher: Flytt opp + label_sort_lower: Flytt ned + label_sort_lowest: Flytt til bunnen + label_roadmap: Veikart + label_roadmap_due_in: "Frist om %{value}" + label_roadmap_overdue: "%{value} over fristen" + label_roadmap_no_issues: Ingen saker for denne versjonen + label_search: Søk + label_result_plural: Resultater + label_all_words: Alle ord + label_wiki: Wiki + label_wiki_edit: Wiki endring + label_wiki_edit_plural: Wiki endringer + label_wiki_page: Wiki-side + label_wiki_page_plural: Wiki-sider + label_index_by_title: Indekser etter tittel + label_index_by_date: Indekser etter dato + label_current_version: Gjeldende versjon + label_preview: Forhåndsvis + label_feed_plural: Feeder + label_changes_details: Detaljer om alle endringer + label_issue_tracking: Sakshåndtering + label_spent_time: Brukt tid + label_f_hour: "%{value} time" + label_f_hour_plural: "%{value} timer" + label_time_tracking: Tidsregistrering + label_change_plural: Endringer + label_statistics: Statistikk + label_commits_per_month: Innsendinger pr. måned + label_commits_per_author: Innsendinger pr. forfatter + label_view_diff: Vis forskjeller + label_diff_inline: i teksten + label_diff_side_by_side: side ved side + label_options: Alternativer + label_copy_workflow_from: Kopier arbeidsflyt fra + label_permissions_report: Rettighetsrapport + label_watched_issues: Overvåkede saker + label_related_issues: Relaterte saker + label_applied_status: Gitt status + label_loading: Laster... + label_relation_new: Ny relasjon + label_relation_delete: Slett relasjon + label_relates_to: relatert til + label_duplicates: dupliserer + label_duplicated_by: duplisert av + label_blocks: blokkerer + label_blocked_by: blokkert av + label_precedes: kommer før + label_follows: følger + label_end_to_start: slutt til start + label_end_to_end: slutt til slutt + label_start_to_start: start til start + label_start_to_end: start til slutt + label_stay_logged_in: Hold meg innlogget + label_disabled: avslått + label_show_completed_versions: Vis ferdige versjoner + label_me: meg + label_board: Forum + label_board_new: Nytt forum + label_board_plural: Forumer + label_topic_plural: Emner + label_message_plural: Meldinger + label_message_last: Siste melding + label_message_new: Ny melding + label_message_posted: Melding lagt til + label_reply_plural: Svar + label_send_information: Send kontoinformasjon til brukeren + label_year: År + label_month: Måned + label_week: Uke + label_date_from: Fra + label_date_to: Til + label_language_based: Basert på brukerens språk + label_sort_by: "Sorter etter %{value}" + label_send_test_email: Send en epost-test + label_feeds_access_key_created_on: "RSS tilgangsnøkkel opprettet for %{value} siden" + label_module_plural: Moduler + label_added_time_by: "Lagt til av %{author} for %{age} siden" + label_updated_time: "Oppdatert for %{value} siden" + label_jump_to_a_project: Gå til et prosjekt... + label_file_plural: Filer + label_changeset_plural: Endringssett + label_default_columns: Standardkolonner + label_no_change_option: (Ingen endring) + label_bulk_edit_selected_issues: Samlet endring av valgte saker + label_theme: Tema + label_default: Standard + label_search_titles_only: Søk bare i titler + label_user_mail_option_all: "For alle hendelser på mine prosjekter" + label_user_mail_option_selected: "For alle hendelser på valgte prosjekt..." + label_user_mail_no_self_notified: "Jeg vil ikke bli varslet om endringer jeg selv gjør" + label_registration_activation_by_email: kontoaktivering pr. e-post + label_registration_manual_activation: manuell kontoaktivering + label_registration_automatic_activation: automatisk kontoaktivering + label_display_per_page: "Pr. side: %{value}" + label_age: Alder + label_change_properties: Endre egenskaper + label_general: Generell + label_more: Mer + label_scm: SCM + label_plugins: Tillegg + label_ldap_authentication: LDAP-autentisering + label_downloads_abbr: Nedl. + label_optional_description: Valgfri beskrivelse + label_add_another_file: Legg til en fil til + label_preferences: Brukerinnstillinger + label_chronological_order: I kronologisk rekkefølge + label_reverse_chronological_order: I omvendt kronologisk rekkefølge + label_planning: Planlegging + + button_login: Logg inn + button_submit: Send + button_save: Lagre + button_check_all: Merk alle + button_uncheck_all: Avmerk alle + button_delete: Slett + button_create: Opprett + button_test: Test + button_edit: Endre + button_add: Legg til + button_change: Endre + button_apply: Bruk + button_clear: Nullstill + button_lock: Lås + button_unlock: Lås opp + button_download: Last ned + button_list: Liste + button_view: Vis + button_move: Flytt + button_back: Tilbake + button_cancel: Avbryt + button_activate: Aktiver + button_sort: Sorter + button_log_time: Logg tid + button_rollback: Rull tilbake til denne versjonen + button_watch: Overvåk + button_unwatch: Stopp overvåkning + button_reply: Svar + button_archive: Arkiver + button_unarchive: Gjør om arkivering + button_reset: Nullstill + button_rename: Endre navn + button_change_password: Endre passord + button_copy: Kopier + button_annotate: Notér + button_update: Oppdater + button_configure: Konfigurer + + status_active: aktiv + status_registered: registrert + status_locked: låst + + text_select_mail_notifications: Velg hendelser som skal varsles med e-post. + text_regexp_info: f.eks. ^[A-Z0-9]+$ + text_min_max_length_info: 0 betyr ingen begrensning + text_project_destroy_confirmation: Er du sikker på at du vil slette dette prosjekter og alle relatert data ? + text_subprojects_destroy_warning: "Underprojekt(ene): %{value} vil også bli slettet." + text_workflow_edit: Velg en rolle og en sakstype for å endre arbeidsflyten + text_are_you_sure: Er du sikker ? + text_tip_issue_begin_day: oppgaven starter denne dagen + text_tip_issue_end_day: oppgaven avsluttes denne dagen + text_tip_issue_begin_end_day: oppgaven starter og avsluttes denne dagen + text_caracters_maximum: "%{count} tegn maksimum." + text_caracters_minimum: "Må være minst %{count} tegn langt." + text_length_between: "Lengde mellom %{min} og %{max} tegn." + text_tracker_no_workflow: Ingen arbeidsflyt definert for denne sakstypen + text_unallowed_characters: Ugyldige tegn + text_comma_separated: Flere verdier tillat (kommaseparert). + text_issues_ref_in_commit_messages: Referering og retting av saker i innsendingsmelding + text_issue_added: "Sak %{id} er innrapportert av %{author}." + text_issue_updated: "Sak %{id} er oppdatert av %{author}." + text_wiki_destroy_confirmation: Er du sikker på at du vil slette denne wikien og alt innholdet ? + text_issue_category_destroy_question: "Noen saker (%{count}) er lagt til i denne kategorien. Hva vil du gjøre ?" + text_issue_category_destroy_assignments: Fjern bruk av kategorier + text_issue_category_reassign_to: Overfør sakene til denne kategorien + text_user_mail_option: "For ikke-valgte prosjekter vil du bare motta varsling om ting du overvåker eller er involveret i (eks. saker du er forfatter av eller er tildelt)." + text_no_configuration_data: "Roller, arbeidsflyt, sakstyper og -statuser er ikke konfigurert enda.\nDet anbefales sterkt å laste inn standardkonfigurasjonen. Du vil kunne endre denne etter den er innlastet." + text_load_default_configuration: Last inn standardkonfigurasjonen + text_status_changed_by_changeset: "Brukt i endringssett %{value}." + text_issues_destroy_confirmation: 'Er du sikker på at du vil slette valgte sak(er) ?' + text_select_project_modules: 'Velg moduler du vil aktivere for dette prosjektet:' + text_default_administrator_account_changed: Standard administrator-konto er endret + text_file_repository_writable: Fil-arkivet er skrivbart + text_rmagick_available: RMagick er tilgjengelig (valgfritt) + text_destroy_time_entries_question: "%{hours} timer er ført på sakene du er i ferd med å slette. Hva vil du gjøre ?" + text_destroy_time_entries: Slett førte timer + text_assign_time_entries_to_project: Overfør førte timer til prosjektet + text_reassign_time_entries: 'Overfør førte timer til denne saken:' + text_user_wrote: "%{value} skrev:" + + default_role_manager: Leder + default_role_developer: Utvikler + default_role_reporter: Rapportør + default_tracker_bug: Feil + default_tracker_feature: Funksjon + default_tracker_support: Support + default_issue_status_new: Ny + default_issue_status_in_progress: Pågår + default_issue_status_resolved: Avklart + default_issue_status_feedback: Tilbakemelding + default_issue_status_closed: Lukket + default_issue_status_rejected: Avvist + default_doc_category_user: Brukerdokumentasjon + default_doc_category_tech: Teknisk dokumentasjon + default_priority_low: Lav + default_priority_normal: Normal + default_priority_high: Høy + default_priority_urgent: Haster + default_priority_immediate: Omgående + default_activity_design: Design + default_activity_development: Utvikling + + enumeration_issue_priorities: Sakssprioriteringer + enumeration_doc_categories: Dokumentkategorier + enumeration_activities: Aktiviteter (tidsregistrering) + text_enumeration_category_reassign_to: 'Endre dem til denne verdien:' + text_enumeration_destroy_question: "%{count} objekter er endret til denne verdien." + label_incoming_emails: Innkommende e-post + label_generate_key: Generer en nøkkel + setting_mail_handler_api_enabled: Skru på WS for innkommende epost + setting_mail_handler_api_key: API-nøkkel + text_email_delivery_not_configured: "Levering av epost er ikke satt opp, og varsler er skrudd av.\nStill inn din SMTP-tjener i config/configuration.yml og start programmet på nytt for å skru det på." + field_parent_title: Overordnet side + label_issue_watchers: Overvåkere + button_quote: Sitat + setting_sequential_project_identifiers: Generer sekvensielle prosjekt-IDer + notice_unable_delete_version: Kan ikke slette versjonen + label_renamed: gitt nytt navn + label_copied: kopiert + setting_plain_text_mail: kun ren tekst (ikke HTML) + permission_view_files: Vise filer + permission_edit_issues: Redigere saker + permission_edit_own_time_entries: Redigere egne timelister + permission_manage_public_queries: Administrere delte søk + permission_add_issues: Legge inn saker + permission_log_time: Loggføre timer + permission_view_changesets: Vise endringssett + permission_view_time_entries: Vise brukte timer + permission_manage_versions: Administrere versjoner + permission_manage_wiki: Administrere wiki + permission_manage_categories: Administrere kategorier for saker + permission_protect_wiki_pages: Beskytte wiki-sider + permission_comment_news: Kommentere nyheter + permission_delete_messages: Slette meldinger + permission_select_project_modules: Velge prosjektmoduler + permission_edit_wiki_pages: Redigere wiki-sider + permission_add_issue_watchers: Legge til overvåkere + permission_view_gantt: Vise gantt-diagram + permission_move_issues: Flytte saker + permission_manage_issue_relations: Administrere saksrelasjoner + permission_delete_wiki_pages: Slette wiki-sider + permission_manage_boards: Administrere forum + permission_delete_wiki_pages_attachments: Slette vedlegg + permission_view_wiki_edits: Vise wiki-historie + permission_add_messages: Sende meldinger + permission_view_messages: Vise meldinger + permission_manage_files: Administrere filer + permission_edit_issue_notes: Redigere notater + permission_manage_news: Administrere nyheter + permission_view_calendar: Vise kalender + permission_manage_members: Administrere medlemmer + permission_edit_messages: Redigere meldinger + permission_delete_issues: Slette saker + permission_view_issue_watchers: Vise liste over overvåkere + permission_manage_repository: Administrere depot + permission_commit_access: Tilgang til innsending + permission_browse_repository: Bla gjennom depot + permission_view_documents: Vise dokumenter + permission_edit_project: Redigere prosjekt + permission_add_issue_notes: Legge til notater + permission_save_queries: Lagre søk + permission_view_wiki_pages: Vise wiki + permission_rename_wiki_pages: Gi wiki-sider nytt navn + permission_edit_time_entries: Redigere timelister + permission_edit_own_issue_notes: Redigere egne notater + setting_gravatar_enabled: Bruk Gravatar-brukerikoner + label_example: Eksempel + text_repository_usernames_mapping: "Select ou update the Redmine user mapped to each username found in the repository log.\nUsers with the same Redmine and repository username or email are automatically mapped." + permission_edit_own_messages: Rediger egne meldinger + permission_delete_own_messages: Slett egne meldinger + label_user_activity: "%{value}s aktivitet" + label_updated_time_by: "Oppdatert av %{author} for %{age} siden" + text_diff_truncated: '... This diff was truncated because it exceeds the maximum size that can be displayed.' + setting_diff_max_lines_displayed: Max number of diff lines displayed + text_plugin_assets_writable: Plugin assets directory writable + warning_attachments_not_saved: "%{count} fil(er) kunne ikke lagres." + button_create_and_continue: Opprett og fortsett + text_custom_field_possible_values_info: 'En linje for hver verdi' + label_display: Visning + field_editable: Redigerbar + setting_repository_log_display_limit: Maks antall revisjoner vist i fil-loggen + setting_file_max_size_displayed: Max size of text files displayed inline + field_watcher: Overvåker + setting_openid: Tillat OpenID innlogging og registrering + field_identity_url: OpenID URL + label_login_with_open_id_option: eller logg inn med OpenID + field_content: Innhold + label_descending: Synkende + label_sort: Sorter + label_ascending: Stigende + label_date_from_to: Fra %{start} til %{end} + label_greater_or_equal: ">=" + label_less_or_equal: <= + text_wiki_page_destroy_question: Denne siden har %{descendants} underside(r). Hva ønsker du å gjøre? + text_wiki_page_reassign_children: Tilknytt undersider til denne overordnede siden + text_wiki_page_nullify_children: Behold undersider som rotsider + text_wiki_page_destroy_children: Slett undersider og alle deres underliggende sider + setting_password_min_length: Minimum passordlengde + field_group_by: Grupper resultater etter + mail_subject_wiki_content_updated: "Wiki-side '%{id}' er oppdatert" + label_wiki_content_added: Wiki-side opprettet + mail_subject_wiki_content_added: "Wiki-side '%{id}' er opprettet" + mail_body_wiki_content_added: Wiki-siden '%{id}' ble opprettet av %{author}. + label_wiki_content_updated: Wiki-side oppdatert + mail_body_wiki_content_updated: Wiki-siden '%{id}' ble oppdatert av %{author}. + permission_add_project: Opprett prosjekt + setting_new_project_user_role_id: Rolle gitt en ikke-administratorbruker som oppretter et prosjekt + label_view_all_revisions: Se alle revisjoner + label_tag: Tag + label_branch: Gren + error_no_tracker_in_project: Ingen sakstyper er tilknyttet dette prosjektet. Vennligst kontroller prosjektets innstillinger. + error_no_default_issue_status: Ingen standard saksstatus er angitt. Vennligst kontroller konfigurasjonen (Gå til "Administrasjon -> Saksstatuser"). + text_journal_changed: "%{label} endret fra %{old} til %{new}" + text_journal_set_to: "%{label} satt til %{value}" + text_journal_deleted: "%{label} slettet (%{old})" + label_group_plural: Grupper + label_group: Gruppe + label_group_new: Ny gruppe + label_time_entry_plural: Brukt tid + text_journal_added: "%{label} %{value} lagt til" + field_active: Aktiv + enumeration_system_activity: Systemaktivitet + permission_delete_issue_watchers: Slett overvåkere + version_status_closed: stengt + version_status_locked: låst + version_status_open: åpen + error_can_not_reopen_issue_on_closed_version: En sak tilknyttet en stengt versjon kan ikke gjenåpnes. + label_user_anonymous: Anonym + button_move_and_follow: Flytt og følg etter + setting_default_projects_modules: Standard aktiverte moduler for nye prosjekter + setting_gravatar_default: Standard Gravatar-bilde + field_sharing: Deling + label_version_sharing_hierarchy: Med prosjekt-hierarki + label_version_sharing_system: Med alle prosjekter + label_version_sharing_descendants: Med underprosjekter + label_version_sharing_tree: Med prosjekt-tre + label_version_sharing_none: Ikke delt + error_can_not_archive_project: Dette prosjektet kan ikke arkiveres + button_duplicate: Duplikat + button_copy_and_follow: Kopier og følg etter + label_copy_source: Kilde + setting_issue_done_ratio: Kalkuler ferdigstillingsprosent ut i fra + setting_issue_done_ratio_issue_status: Bruk saksstatuser + error_issue_done_ratios_not_updated: Ferdigstillingsprosent oppdateres ikke. + error_workflow_copy_target: Vennligst velg sakstype(r) og rolle(r) + setting_issue_done_ratio_issue_field: Bruk felt fra saker + label_copy_same_as_target: Samme som mål + label_copy_target: Mål + notice_issue_done_ratios_updated: Ferdigstillingsprosent oppdatert. + error_workflow_copy_source: Vennligst velg en kilde-sakstype eller rolle. + label_update_issue_done_ratios: Oppdatert ferdigstillingsprosent + setting_start_of_week: Start kalender på + permission_view_issues: Se på saker + label_display_used_statuses_only: Vis kun statuser som brukes av denne sakstypen + label_revision_id: Revision %{value} + label_api_access_key: API tilgangsnøkkel + label_api_access_key_created_on: API tilgangsnøkkel opprettet for %{value} siden + label_feeds_access_key: RSS tilgangsnøkkel + notice_api_access_key_reseted: Din API tilgangsnøkkel ble resatt. + setting_rest_api_enabled: Aktiver REST webservice + label_missing_api_access_key: Mangler en API tilgangsnøkkel + label_missing_feeds_access_key: Mangler en RSS tilgangsnøkkel + button_show: Vis + text_line_separated: Flere verdier er tillatt (en linje per verdi). + setting_mail_handler_body_delimiters: Avkort epost etter en av disse linjene + permission_add_subprojects: Opprett underprosjekt + label_subproject_new: Nytt underprosjekt + text_own_membership_delete_confirmation: |- + Du er i ferd med å fjerne noen eller alle rettigheter og vil kanskje ikke være i stand til å redigere dette prosjektet etterpå. + Er du sikker på at du vil fortsette? + label_close_versions: Steng fullførte versjoner + label_board_sticky: Fast + label_board_locked: Låst + permission_export_wiki_pages: Eksporter wiki-sider + setting_cache_formatted_text: Mellomlagre formattert tekst + permission_manage_project_activities: Administrere prosjektaktiviteter + error_unable_delete_issue_status: Kan ikke slette saksstatus + label_profile: Profil + permission_manage_subtasks: Administrere undersaker + field_parent_issue: Overordnet sak + label_subtask_plural: Undersaker + label_project_copy_notifications: Send epost-varslinger under prosjektkopiering + error_can_not_delete_custom_field: Kan ikke slette eget felt + error_unable_to_connect: Kunne ikke koble til (%{value}) + error_can_not_remove_role: Denne rollen er i bruk og kan ikke slettes. + error_can_not_delete_tracker: Denne sakstypen inneholder saker og kan ikke slettes. + field_principal: Principal + label_my_page_block: Min side felt + notice_failed_to_save_members: "Feil ved lagring av medlem(mer): %{errors}." + text_zoom_out: Zoom ut + text_zoom_in: Zoom inn + notice_unable_delete_time_entry: Kan ikke slette oppføring fra timeliste. + label_overall_spent_time: All tidsbruk + field_time_entries: Loggfør tid + project_module_gantt: Gantt + project_module_calendar: Kalender + button_edit_associated_wikipage: "Rediger tilhørende Wiki-side: %{page_title}" + field_text: Tekstfelt + label_user_mail_option_only_owner: Kun for ting jeg eier + setting_default_notification_option: Standardvalg for varslinger + label_user_mail_option_only_my_events: Kun for ting jeg overvåker eller er involvert i + label_user_mail_option_only_assigned: Kun for ting jeg er tildelt + label_user_mail_option_none: Ingen hendelser + field_member_of_group: Den tildeltes gruppe + field_assigned_to_role: Den tildeltes rolle + notice_not_authorized_archived_project: Prosjektet du forsøker å åpne er blitt arkivert. + label_principal_search: "Søk etter bruker eller gruppe:" + label_user_search: "Søk etter bruker:" + field_visible: Synlig + setting_emails_header: Eposthode + setting_commit_logtime_activity_id: Aktivitet for logget tid. + text_time_logged_by_changeset: Lagt til i endringssett %{value}. + setting_commit_logtime_enabled: Muliggjør loggføring av tid + notice_gantt_chart_truncated: Diagrammet ble avkortet fordi det overstiger det maksimale antall elementer som kan vises (%{max}) + setting_gantt_items_limit: Maksimalt antall elementer vist på gantt-diagrammet + field_warn_on_leaving_unsaved: Vis meg en advarsel når jeg forlater en side med ikke lagret tekst + text_warn_on_leaving_unsaved: Siden inneholder tekst som ikke er lagret og som vil bli tapt om du forlater denne siden. + label_my_queries: Mine egne spørringer + text_journal_changed_no_detail: "%{label} oppdatert" + label_news_comment_added: Kommentar lagt til en nyhet + button_expand_all: Utvid alle + button_collapse_all: Kollaps alle + label_additional_workflow_transitions_for_assignee: Ytterligere overganger tillatt når brukeren er den som er tildelt saken + label_additional_workflow_transitions_for_author: Ytterligere overganger tillatt når brukeren er den som har opprettet saken + label_bulk_edit_selected_time_entries: Masserediger valgte timeliste-oppføringer + text_time_entries_destroy_confirmation: Er du sikker på du vil slette de(n) valgte timeliste-oppføringen(e)? + label_role_anonymous: Anonym + label_role_non_member: Ikke medlem + label_issue_note_added: Notat lagt til + label_issue_status_updated: Status oppdatert + label_issue_priority_updated: Prioritet oppdatert + label_issues_visibility_own: Saker opprettet av eller tildelt brukeren + field_issues_visibility: Synlighet på saker + label_issues_visibility_all: Alle saker + permission_set_own_issues_private: Gjør egne saker offentlige eller private + field_is_private: Privat + permission_set_issues_private: Gjør saker offentlige eller private + label_issues_visibility_public: Alle ikke-private saker + text_issues_destroy_descendants_confirmation: Dette vil også slette %{count} undersak(er). + field_commit_logs_encoding: Tegnkoding for innsendingsmeldinger + field_scm_path_encoding: Koding av sti + text_scm_path_encoding_note: "Standard: UTF-8" + field_path_to_repository: Sti til depot + field_root_directory: Rotkatalog + field_cvs_module: Modul + field_cvsroot: CVSROOT + text_mercurial_repository_note: Lokalt depot (f.eks. /hgrepo, c:\hgrepo) + text_scm_command: Kommando + text_scm_command_version: Versjon + label_git_report_last_commit: Rapporter siste innsending for filer og kataloger + text_scm_config: Du kan konfigurere scm kommandoer i config/configuration.yml. Vennligst restart applikasjonen etter å ha redigert filen. + text_scm_command_not_available: Scm kommando er ikke tilgjengelig. Vennligst kontroller innstillingene i administrasjonspanelet. + + text_git_repository_note: Depot er bart og lokalt (f.eks. /gitrepo, c:\gitrepo) + + notice_issue_successful_create: Sak %{id} opprettet. + label_between: mellom + setting_issue_group_assignment: Tillat tildeling av saker til grupper + label_diff: diff + + description_query_sort_criteria_direction: Sorteringsretning + description_project_scope: Search scope + description_filter: Filter + description_user_mail_notification: Mail notification settings + description_date_from: Oppgi startdato + description_message_content: Meldingsinnhold + description_available_columns: Tilgjengelige kolonner + description_date_range_interval: Velg datointervall ved å spesifisere start- og sluttdato + description_issue_category_reassign: Choose issue category + description_search: Søkefelt + description_notes: Notes + description_date_range_list: Choose range from list + description_choose_project: Prosjekter + description_date_to: Oppgi sluttdato + description_query_sort_criteria_attribute: Sort attribute + description_wiki_subpages_reassign: Velg ny overordnet side + description_selected_columns: Valgte kolonner + label_parent_revision: Overordnet + label_child_revision: Underordnet + error_scm_annotate_big_text_file: The entry cannot be annotated, as it exceeds the maximum text file size. + setting_default_issue_start_date_to_creation_date: Bruk dagens dato som startdato for nye saker + button_edit_section: Rediger denne seksjonen + setting_repositories_encodings: Attachments and repositories encodings + description_all_columns: Alle kolonnene + button_export: Eksporter + label_export_options: "%{export_format} eksportvalg" + error_attachment_too_big: Filen overstiger maksimum filstørrelse (%{max_size}) og kan derfor ikke lastes opp + notice_failed_to_save_time_entries: "Failed to save %{count} time entrie(s) on %{total} selected: %{ids}." + label_x_issues: + zero: 0 saker + one: 1 sak + other: "%{count} saker" + label_repository_new: Nytt depot + field_repository_is_default: Hoveddepot + label_copy_attachments: Kopier vedlegg + label_item_position: "%{position}/%{count}" + label_completed_versions: Completed versions + text_project_identifier_info: Kun små bokstaver (a-z), tall, bindestrek (-) og "underscore" (_) er tillatt.
    Etter lagring er det ikke mulig å gjøre endringer. + field_multiple: Flere verdier + setting_commit_cross_project_ref: Allow issues of all the other projects to be referenced and fixed + text_issue_conflict_resolution_add_notes: Add my notes and discard my other changes + text_issue_conflict_resolution_overwrite: Apply my changes anyway (previous notes will be kept but some changes may be overwritten) + notice_issue_update_conflict: Saken ble oppdatert av en annen bruker mens du redigerte den. + text_issue_conflict_resolution_cancel: Forkast alle endringen mine og vis %{link} på nytt + permission_manage_related_issues: Manage related issues + field_auth_source_ldap_filter: LDAP filter + label_search_for_watchers: Search for watchers to add + notice_account_deleted: Din konto er ugjenkallelig slettet. + setting_unsubscribe: Tillat brukere å slette sin egen konto + button_delete_my_account: Slett kontoen min + text_account_destroy_confirmation: |- + Er du sikker på at du ønsker å fortsette? + Kontoen din vil bli ugjenkallelig slettet uten mulighet for å reaktiveres igjen. + error_session_expired: Økten har gått ut på tid. Vennligst logg på igjen. + text_session_expiration_settings: "Advarsel: ved å endre disse innstillingene kan aktive økter gå ut på tid, inkludert din egen." + setting_session_lifetime: Øktenes makslengde + setting_session_timeout: Økten er avsluttet på grunn av inaktivitet + label_session_expiration: Økten er avsluttet + permission_close_project: Close / reopen the project + label_show_closed_projects: View closed projects + button_close: Close + button_reopen: Reopen + project_status_active: active + project_status_closed: closed + project_status_archived: archived + text_project_closed: This project is closed and read-only. + notice_user_successful_create: User %{id} created. + field_core_fields: Standard fields + field_timeout: Timeout (in seconds) + setting_thumbnails_enabled: Display attachment thumbnails + setting_thumbnails_size: Thumbnails size (in pixels) + label_status_transitions: Status transitions + label_fields_permissions: Fields permissions + label_readonly: Read-only + label_required: Required + text_repository_identifier_info: Only lower case letters (a-z), numbers, dashes and underscores are allowed.
    Once saved, the identifier cannot be changed. + field_board_parent: Parent forum + label_attribute_of_project: Project's %{name} + label_attribute_of_author: Author's %{name} + label_attribute_of_assigned_to: Assignee's %{name} + label_attribute_of_fixed_version: Target version's %{name} + label_copy_subtasks: Copy subtasks + label_copied_to: copied to + label_copied_from: copied from + label_any_issues_in_project: any issues in project + label_any_issues_not_in_project: any issues not in project + field_private_notes: Private notes + permission_view_private_notes: View private notes + permission_set_notes_private: Set notes as private + label_no_issues_in_project: no issues in project + label_any: alle + label_last_n_weeks: last %{count} weeks + setting_cross_project_subtasks: Allow cross-project subtasks + label_cross_project_descendants: Med underprosjekter + label_cross_project_tree: Med prosjekt-tre + label_cross_project_hierarchy: Med prosjekt-hierarki + label_cross_project_system: Med alle prosjekter + button_hide: Hide + setting_non_working_week_days: Non-working days + label_in_the_next_days: in the next + label_in_the_past_days: in the past + label_attribute_of_user: User's %{name} + text_turning_multiple_off: If you disable multiple values, multiple values will be + removed in order to preserve only one value per item. + label_attribute_of_issue: Issue's %{name} + permission_add_documents: Add documents + permission_edit_documents: Edit documents + permission_delete_documents: Delete documents + label_gantt_progress_line: Progress line + setting_jsonp_enabled: Enable JSONP support + field_inherit_members: Inherit members + field_closed_on: Closed + setting_default_projects_tracker_ids: Default trackers for new projects + label_total_time: Totalt diff --git a/config/locales/pl.yml b/config/locales/pl.yml new file mode 100644 index 00000000..c9ff4dd5 --- /dev/null +++ b/config/locales/pl.yml @@ -0,0 +1,1110 @@ +# Polish translations for Ruby on Rails +# by Jacek Becela (jacek.becela@gmail.com, http://github.com/ncr) +# by Krzysztof Podejma (kpodejma@customprojects.pl, http://www.customprojects.pl) + +pl: + number: + format: + separator: "," + delimiter: " " + precision: 2 + currency: + format: + format: "%n %u" + unit: "PLN" + percentage: + format: + delimiter: "" + precision: + format: + delimiter: "" + human: + format: + delimiter: "" + precision: 3 + storage_units: + format: "%n %u" + units: + byte: + one: "B" + other: "B" + kb: "KB" + mb: "MB" + gb: "GB" + tb: "TB" + + direction: ltr + date: + formats: + default: "%Y-%m-%d" + short: "%d %b" + long: "%d %B %Y" + + day_names: [Niedziela, Poniedziałek, Wtorek, Środa, Czwartek, Piątek, Sobota] + abbr_day_names: [nie, pon, wto, śro, czw, pia, sob] + + month_names: [~, Styczeń, Luty, Marzec, Kwiecień, Maj, Czerwiec, Lipiec, Sierpień, Wrzesień, Październik, Listopad, Grudzień] + abbr_month_names: [~, sty, lut, mar, kwi, maj, cze, lip, sie, wrz, paź, lis, gru] + order: + - :year + - :month + - :day + + time: + formats: + default: "%a, %d %b %Y, %H:%M:%S %z" + time: "%H:%M" + short: "%d %b, %H:%M" + long: "%d %B %Y, %H:%M" + am: "przed południem" + pm: "po południu" + + datetime: + distance_in_words: + half_a_minute: "pół minuty" + less_than_x_seconds: + one: "mniej niż sekundę" + few: "mniej niż %{count} sekundy" + other: "mniej niż %{count} sekund" + x_seconds: + one: "sekundę" + few: "%{count} sekundy" + other: "%{count} sekund" + less_than_x_minutes: + one: "mniej niż minutę" + few: "mniej niż %{count} minuty" + other: "mniej niż %{count} minut" + x_minutes: + one: "minutę" + few: "%{count} minuty" + other: "%{count} minut" + about_x_hours: + one: "około godziny" + other: "około %{count} godzin" + x_hours: + one: "1 hour" + other: "%{count} hours" + x_days: + one: "1 dzień" + other: "%{count} dni" + about_x_months: + one: "około miesiąca" + other: "około %{count} miesięcy" + x_months: + one: "1 miesiąc" + few: "%{count} miesiące" + other: "%{count} miesięcy" + about_x_years: + one: "około roku" + other: "około %{count} lat" + over_x_years: + one: "ponad rok" + few: "ponad %{count} lata" + other: "ponad %{count} lat" + almost_x_years: + one: "prawie 1 rok" + few: "prawie %{count} lata" + other: "prawie %{count} lat" + + activerecord: + errors: + template: + header: + one: "%{model} nie został zachowany z powodu jednego błędu" + other: "%{model} nie został zachowany z powodu %{count} błędów" + body: "Błędy dotyczą następujących pól:" + messages: + inclusion: "nie znajduje się na liście dopuszczalnych wartości" + exclusion: "znajduje się na liście zabronionych wartości" + invalid: "jest nieprawidłowe" + confirmation: "nie zgadza się z potwierdzeniem" + accepted: "musi być zaakceptowane" + empty: "nie może być puste" + blank: "nie może być puste" + too_long: "jest za długie (maksymalnie %{count} znaków)" + too_short: "jest za krótkie (minimalnie %{count} znaków)" + wrong_length: "jest nieprawidłowej długości (powinna wynosić %{count} znaków)" + taken: "jest już zajęte" + not_a_number: "nie jest liczbą" + greater_than: "musi być większe niż %{count}" + greater_than_or_equal_to: "musi być większe lub równe %{count}" + equal_to: "musi być równe %{count}" + less_than: "musi być mniejsze niż %{count}" + less_than_or_equal_to: "musi być mniejsze lub równe %{count}" + odd: "musi być nieparzyste" + even: "musi być parzyste" + greater_than_start_date: "musi być większe niż początkowa data" + not_same_project: "nie należy do tego samego projektu" + circular_dependency: "Ta relacja może wytworzyć zapętloną zależność" + cant_link_an_issue_with_a_descendant: "Zagadnienie nie może zostać powiązane z jednym z własnych podzagadnień" + + support: + array: + sentence_connector: "i" + skip_last_comma: true + + # Keep this line in order to avoid problems with Windows Notepad UTF-8 EF-BB-BFidea... + # Best regards from Lublin@Poland :-) + # PL translation by Mariusz@Olejnik.net, + # Wiktor Wandachowicz , 2010 + + actionview_instancetag_blank_option: Proszę wybrać + actionview_instancetag_blank_option: Proszę wybierz + + button_activate: Aktywuj + button_add: Dodaj + button_annotate: Adnotuj + button_apply: Ustaw + button_archive: Archiwizuj + button_back: Wstecz + button_cancel: Anuluj + button_change: Zmień + button_change_password: Zmień hasło + button_check_all: Zaznacz wszystko + button_clear: Wyczyść + button_configure: Konfiguruj + button_copy: Kopia + button_create: Stwórz + button_delete: Usuń + button_download: Pobierz + button_edit: Edytuj + button_list: Lista + button_lock: Zablokuj + button_log_time: Dziennik + button_login: Login + button_move: Przenieś + button_quote: Cytuj + button_rename: Zmień nazwę + button_reply: Odpowiedz + button_reset: Resetuj + button_rollback: Przywróć do tej wersji + button_save: Zapisz + button_sort: Sortuj + button_submit: Wyślij + button_test: Testuj + button_unarchive: Przywróć z archiwum + button_uncheck_all: Odznacz wszystko + button_unlock: Odblokuj + button_unwatch: Nie obserwuj + button_update: Uaktualnij + button_view: Pokaż + button_watch: Obserwuj + default_activity_design: Projektowanie + default_activity_development: Rozwój + default_doc_category_tech: Dokumentacja techniczna + default_doc_category_user: Dokumentacja użytkownika + default_issue_status_in_progress: W toku + default_issue_status_closed: Zamknięty + default_issue_status_feedback: Odpowiedź + default_issue_status_new: Nowy + default_issue_status_rejected: Odrzucony + default_issue_status_resolved: Rozwiązany + default_priority_high: Wysoki + default_priority_immediate: Natychmiastowy + default_priority_low: Niski + default_priority_normal: Normalny + default_priority_urgent: Pilny + default_role_developer: Programista + default_role_manager: Kierownik + default_role_reporter: Zgłaszający + default_tracker_bug: Błąd + default_tracker_feature: Zadanie + default_tracker_support: Wsparcie + enumeration_activities: Działania (śledzenie czasu) + enumeration_doc_categories: Kategorie dokumentów + enumeration_issue_priorities: Priorytety zagadnień + error_can_t_load_default_data: "Domyślna konfiguracja nie może być załadowana: %{value}" + error_issue_not_found_in_project: 'Zagadnienie nie zostało znalezione lub nie należy do tego projektu' + error_scm_annotate: "Wpis nie istnieje lub nie można do niego dodawać adnotacji." + error_scm_command_failed: "Wystąpił błąd przy próbie dostępu do repozytorium: %{value}" + error_scm_not_found: "Obiekt lub wersja nie zostały znalezione w repozytorium." + field_account: Konto + field_activity: Aktywność + field_admin: Administrator + field_assignable: Zagadnienia mogą być przypisane do tej roli + field_assigned_to: Przypisany do + field_attr_firstname: Imię atrybut + field_attr_lastname: Nazwisko atrybut + field_attr_login: Login atrybut + field_attr_mail: E-mail atrybut + field_auth_source: Tryb identyfikacji + field_author: Autor + field_base_dn: Base DN + field_category: Kategoria + field_column_names: Nazwy kolumn + field_comments: Komentarz + field_comments_sorting: Pokazuj komentarze + field_created_on: Stworzone + field_default_value: Domyślny + field_delay: Opóźnienie + field_description: Opis + field_done_ratio: "% Wykonane" + field_downloads: Pobrań + field_due_date: Data oddania + field_effective_date: Data + field_estimated_hours: Szacowany czas + field_field_format: Format + field_filename: Plik + field_filesize: Rozmiar + field_firstname: Imię + field_fixed_version: Wersja docelowa + field_hide_mail: Ukryj mój adres e-mail + field_homepage: Strona www + field_host: Host + field_hours: Godzin + field_identifier: Identyfikator + field_is_closed: Zagadnienie zamknięte + field_is_default: Domyślny status + field_is_filter: Atrybut filtrowania + field_is_for_all: Dla wszystkich projektów + field_is_in_roadmap: Zagadnienie pokazywane na mapie + field_is_public: Publiczny + field_is_required: Wymagane + field_issue: Zagadnienie + field_issue_to: Powiązania zagadnienia + field_language: Język + field_last_login_on: Ostatnie połączenie + field_lastname: Nazwisko + field_login: Login + field_mail: E-mail + field_mail_notification: Powiadomienia e-mail + field_max_length: Maksymalna długość + field_min_length: Minimalna długość + field_name: Nazwa + field_new_password: Nowe hasło + field_notes: Notatki + field_onthefly: Tworzenie użytkownika w locie + field_parent: Projekt nadrzędny + field_parent_title: Strona rodzica + field_password: Hasło + field_password_confirmation: Potwierdzenie + field_port: Port + field_possible_values: Możliwe wartości + field_priority: Priorytet + field_project: Projekt + field_redirect_existing_links: Przekierowanie istniejących odnośników + field_regexp: Wyrażenie regularne + field_role: Rola + field_searchable: Przeszukiwalne + field_spent_on: Data + field_start_date: Data rozpoczęcia + field_start_page: Strona startowa + field_status: Status + field_subject: Temat + field_subproject: Podprojekt + field_summary: Podsumowanie + field_time_zone: Strefa czasowa + field_title: Tytuł + field_tracker: Typ zagadnienia + field_type: Typ + field_updated_on: Zmienione + field_url: URL + field_user: Użytkownik + field_value: Wartość + field_version: Wersja + field_vf_personnel: Personel + field_vf_watcher: Obserwator + general_csv_decimal_separator: ',' + general_csv_encoding: UTF-8 + general_csv_separator: ';' + general_first_day_of_week: '1' + general_lang_name: 'Polski' + general_pdf_encoding: UTF-8 + general_text_No: 'Nie' + general_text_Yes: 'Tak' + general_text_no: 'nie' + general_text_yes: 'tak' + + label_activity: Aktywność + label_add_another_file: Dodaj kolejny plik + label_add_note: Dodaj notatkę + label_added: dodane + label_added_time_by: "Dodane przez %{author} %{age} temu" + label_administration: Administracja + label_age: Wiek + label_ago: dni temu + label_all: wszystko + label_all_time: cały czas + label_all_words: Wszystkie słowa + label_and_its_subprojects: "%{value} i podprojekty" + label_applied_status: Stosowany status + label_assigned_to_me_issues: Zagadnienia przypisane do mnie + label_associated_revisions: Skojarzone rewizje + label_attachment: Plik + label_attachment_delete: Usuń plik + label_attachment_new: Nowy plik + label_attachment_plural: Pliki + label_attribute: Atrybut + label_attribute_plural: Atrybuty + label_auth_source: Tryb identyfikacji + label_auth_source_new: Nowy tryb identyfikacji + label_auth_source_plural: Tryby identyfikacji + label_authentication: Identyfikacja + label_blocked_by: blokowane przez + label_blocks: blokuje + label_board: Forum + label_board_new: Nowe forum + label_board_plural: Fora + label_boolean: Wartość logiczna + label_browse: Przegląd + label_bulk_edit_selected_issues: Zbiorowa edycja zagadnień + label_calendar: Kalendarz + label_change_plural: Zmiany + label_change_properties: Zmień właściwości + label_change_status: Status zmian + label_change_view_all: Pokaż wszystkie zmiany + label_changes_details: Szczegóły wszystkich zmian + label_changeset_plural: Zestawienia zmian + label_chronological_order: W kolejności chronologicznej + label_closed_issues: zamknięte + label_closed_issues_plural234: zamknięte + label_closed_issues_plural5: zamknięte + label_closed_issues_plural: zamknięte + label_x_open_issues_abbr_on_total: + zero: 0 otwartych / %{total} + one: 1 otwarty / %{total} + few: "%{count} otwarte / %{total}" + other: "%{count} otwartych / %{total}" + label_x_open_issues_abbr: + zero: 0 otwartych + one: 1 otwarty + few: "%{count} otwarte" + other: "%{count} otwartych" + label_x_closed_issues_abbr: + zero: 0 zamkniętych + one: 1 zamknięty + few: "%{count} zamknięte" + other: "%{count} zamkniętych" + label_comment: Komentarz + label_comment_add: Dodaj komentarz + label_comment_added: Komentarz dodany + label_comment_delete: Usuń komentarze + label_comment_plural234: Komentarze + label_comment_plural5: Komentarzy + label_comment_plural: Komentarze + label_x_comments: + zero: brak komentarzy + one: 1 komentarz + few: "%{count} komentarze" + other: "%{count} komentarzy" + label_commits_per_author: Zatwierdzenia według autorów + label_commits_per_month: Zatwierdzenia według miesięcy + label_confirmation: Potwierdzenie + label_contains: zawiera + label_copied: skopiowano + label_copy_workflow_from: Kopiuj przepływ pracy z + label_current_status: Obecny status + label_current_version: Obecna wersja + label_custom_field: Pole niestandardowe + label_custom_field_new: Nowe pole niestandardowe + label_custom_field_plural: Pola niestandardowe + label_date: Data + label_date_from: Od + label_date_range: Zakres dat + label_date_to: Do + label_day_plural: dni + label_default: Domyślne + label_default_columns: Domyślne kolumny + label_deleted: usunięte + label_details: Szczegóły + label_diff_inline: w linii + label_diff_side_by_side: obok siebie + label_disabled: zablokowany + label_display_per_page: "Na stronę: %{value}" + label_document: Dokument + label_document_added: Dodano dokument + label_document_new: Nowy dokument + label_document_plural: Dokumenty + label_downloads_abbr: Pobieranie + label_duplicated_by: zduplikowane przez + label_duplicates: duplikuje + label_end_to_end: koniec do końca + label_end_to_start: koniec do początku + label_enumeration_new: Nowa wartość + label_enumerations: Wyliczenia + label_environment: Środowisko + label_equals: równa się + label_example: Przykład + label_export_to: Eksportuj do + label_f_hour: "%{value} godzina" + label_f_hour_plural: "%{value} godzin" + label_feed_plural: Ilość Atom + label_feeds_access_key_created_on: "Klucz dostępu do kanału Atom stworzony %{value} temu" + label_file_added: Dodano plik + label_file_plural: Pliki + label_filter_add: Dodaj filtr + label_filter_plural: Filtry + label_float: Liczba zmiennoprzecinkowa + label_follows: następuje po + label_gantt: Gantt + label_general: Ogólne + label_generate_key: Wygeneruj klucz + label_help: Pomoc + label_history: Historia + label_home: Główna + label_in: w + label_in_less_than: mniejsze niż + label_in_more_than: większe niż + label_incoming_emails: Przychodząca poczta elektroniczna + label_index_by_date: Indeks wg daty + label_index_by_title: Indeks + label_information: Informacja + label_information_plural: Informacje + label_integer: Liczba całkowita + label_internal: Wewnętrzny + label_issue: Zagadnienie + label_issue_added: Dodano zagadnienie + label_issue_category: Kategoria zagadnienia + label_issue_category_new: Nowa kategoria + label_issue_category_plural: Kategorie zagadnień + label_issue_new: Nowe zagadnienie + label_issue_plural: Zagadnienia + label_issue_status: Status zagadnienia + label_issue_status_new: Nowy status + label_issue_status_plural: Statusy zagadnień + label_issue_tracking: Śledzenie zagadnień + label_issue_updated: Uaktualniono zagadnienie + label_issue_view_all: Zobacz wszystkie zagadnienia + label_issue_watchers: Obserwatorzy + label_issues_by: "Zagadnienia wprowadzone przez %{value}" + label_jump_to_a_project: Skocz do projektu... + label_language_based: Na podstawie języka + label_last_changes: "ostatnie %{count} zmian" + label_last_login: Ostatnie połączenie + label_last_month: ostatni miesiąc + label_last_n_days: "ostatnie %{count} dni" + label_last_week: ostatni tydzień + label_latest_revision: Najnowsza rewizja + label_latest_revision_plural: Najnowsze rewizje + label_ldap_authentication: Autoryzacja LDAP + label_less_than_ago: dni mniej + label_list: Lista + label_loading: Ładowanie... + label_logged_as: Zalogowany jako + label_login: Login + label_logout: Wylogowanie + label_max_size: Maksymalny rozmiar + label_me: ja + label_member: Uczestnik + label_member_new: Nowy uczestnik + label_member_plural: Uczestnicy + label_message_last: Ostatnia wiadomość + label_message_new: Nowa wiadomość + label_message_plural: Wiadomości + label_message_posted: Dodano wiadomość + label_min_max_length: Min - Maks długość + label_modified: zmodyfikowane + label_module_plural: Moduły + label_month: Miesiąc + label_months_from: miesiące od + label_more: Więcej + label_more_than_ago: dni więcej + label_my_account: Moje konto + label_my_page: Moja strona + label_my_projects: Moje projekty + label_new: Nowy + label_new_statuses_allowed: Uprawnione nowe statusy + label_news: Komunikat + label_news_added: Dodano komunikat + label_news_latest: Ostatnie komunikaty + label_news_new: Dodaj komunikat + label_news_plural: Komunikaty + label_news_view_all: Pokaż wszystkie komunikaty + label_next: Następne + label_no_change_option: (Bez zmian) + label_no_data: Brak danych do pokazania + label_nobody: nikt + label_none: brak + label_not_contains: nie zawiera + label_not_equals: różni się + label_open_issues: otwarte + label_open_issues_plural234: otwarte + label_open_issues_plural5: otwartych + label_open_issues_plural: otwarte + label_optional_description: Opcjonalny opis + label_options: Opcje + label_overall_activity: Ogólna aktywność + label_overview: Przegląd + label_password_lost: Zapomniane hasło + label_per_page: Na stronę + label_permissions: Uprawnienia + label_permissions_report: Raport uprawnień + label_personalize_page: Personalizuj tę stronę + label_planning: Planowanie + label_please_login: Zaloguj się + label_plugins: Wtyczki + label_precedes: poprzedza + label_preferences: Preferencje + label_preview: Podgląd + label_previous: Poprzednie + label_project: Projekt + label_project_all: Wszystkie projekty + label_project_latest: Ostatnie projekty + label_project_new: Nowy projekt + label_project_plural234: Projekty + label_project_plural5: Projektów + label_project_plural: Projekty + label_x_projects: + zero: brak projektów + one: 1 projekt + few: "%{count} projekty" + other: "%{count} projektów" + label_public_projects: Projekty publiczne + label_query: Kwerenda + label_query_new: Nowa kwerenda + label_query_plural: Kwerendy + label_read: Czytanie... + label_register: Rejestracja + label_registered_on: Zarejestrowany + label_registration_activation_by_email: aktywacja konta przez e-mail + label_registration_automatic_activation: automatyczna aktywacja kont + label_registration_manual_activation: manualna aktywacja kont + label_related_issues: Powiązane zagadnienia + label_relates_to: powiązane z + label_relation_delete: Usuń powiązanie + label_relation_new: Nowe powiązanie + label_renamed: zmieniono nazwę + label_reply_plural: Odpowiedzi + label_report: Raport + label_report_plural: Raporty + label_reported_issues: Wprowadzone zagadnienia + label_repository: Repozytorium + label_repository_plural: Repozytoria + label_result_plural: Rezultatów + label_reverse_chronological_order: W kolejności odwrotnej do chronologicznej + label_revision: Rewizja + label_revision_plural: Rewizje + label_roadmap: Mapa + label_roadmap_due_in: W czasie + label_roadmap_no_issues: Brak zagadnień do tej wersji + label_roadmap_overdue: "%{value} spóźnienia" + label_role: Rola + label_role_and_permissions: Role i uprawnienia + label_role_new: Nowa rola + label_role_plural: Role + label_scm: SCM + label_search: Szukaj + label_search_titles_only: Przeszukuj tylko tytuły + label_send_information: Wyślij informację użytkownikowi + label_send_test_email: Wyślij próbny e-mail + label_settings: Ustawienia + label_show_completed_versions: Pokaż kompletne wersje + label_sort_by: "Sortuj po %{value}" + label_sort_higher: Do góry + label_sort_highest: Przesuń na górę + label_sort_lower: Do dołu + label_sort_lowest: Przesuń na dół + label_spent_time: Przepracowany czas + label_start_to_end: początek do końca + label_start_to_start: początek do początku + label_statistics: Statystyki + label_stay_logged_in: Pozostań zalogowany + label_string: Tekst + label_subproject_plural: Podprojekty + label_text: Długi tekst + label_theme: Temat + label_this_month: ten miesiąc + label_this_week: ten tydzień + label_this_year: ten rok + label_time_tracking: Śledzenie czasu pracy + label_today: dzisiaj + label_topic_plural: Tematy + label_total: Ogółem + label_tracker: Typ zagadnienia + label_tracker_new: Nowy typ zagadnienia + label_tracker_plural: Typy zagadnień + label_updated_time: "Zaktualizowane %{value} temu" + label_used_by: Używane przez + label_user: Użytkownik + label_user_mail_no_self_notified: "Nie chcę powiadomień o zmianach, które sam wprowadzam." + label_user_mail_option_all: "Dla każdego zdarzenia w każdym moim projekcie" + label_user_mail_option_selected: "Dla każdego zdarzenia w wybranych projektach..." + label_user_new: Nowy użytkownik + label_user_plural: Użytkownicy + label_version: Wersja + label_version_new: Nowa wersja + label_version_plural: Wersje + label_view_diff: Pokaż różnice + label_view_revisions: Pokaż rewizje + label_watched_issues: Obserwowane zagadnienia + label_week: Tydzień + label_wiki: Wiki + label_wiki_edit: Edycja wiki + label_wiki_edit_plural: Edycje wiki + label_wiki_page: Strona wiki + label_wiki_page_plural: Strony wiki + label_workflow: Przepływ pracy + label_year: Rok + label_yesterday: wczoraj + mail_body_account_activation_request: "Zarejestrowano nowego użytkownika: (%{value}). Konto oczekuje na twoje zatwierdzenie:" + mail_body_account_information: Twoje konto + mail_body_account_information_external: "Możesz użyć Twojego konta %{value} do zalogowania." + mail_body_lost_password: 'W celu zmiany swojego hasła użyj poniższego odnośnika:' + mail_body_register: 'W celu aktywacji Twojego konta, użyj poniższego odnośnika:' + mail_body_reminder: "Wykaz przypisanych do Ciebie zagadnień, których termin wypada w ciągu następnych %{count} dni" + mail_subject_account_activation_request: "Zapytanie aktywacyjne konta %{value}" + mail_subject_lost_password: "Twoje hasło do %{value}" + mail_subject_register: "Aktywacja konta w %{value}" + mail_subject_reminder: "Uwaga na terminy, masz zagadnienia do obsłużenia w ciągu następnych %{count} dni! (%{days})" + notice_account_activated: Twoje konto zostało aktywowane. Możesz się zalogować. + notice_account_invalid_creditentials: Zły użytkownik lub hasło + notice_account_lost_email_sent: E-mail z instrukcjami zmiany hasła został wysłany do Ciebie. + notice_account_password_updated: Hasło prawidłowo zmienione. + notice_account_pending: "Twoje konto zostało utworzone i oczekuje na zatwierdzenie administratora." + notice_account_register_done: Konto prawidłowo utworzone. + notice_account_unknown_email: Nieznany użytkownik. + notice_account_updated: Konto prawidłowo zaktualizowane. + notice_account_wrong_password: Złe hasło + notice_can_t_change_password: To konto ma zewnętrzne źródło identyfikacji. Nie możesz zmienić hasła. + notice_default_data_loaded: Domyślna konfiguracja została pomyślnie załadowana. + notice_email_error: "Wystąpił błąd w trakcie wysyłania e-maila (%{value})" + notice_email_sent: "E-mail został wysłany do %{value}" + notice_failed_to_save_issues: "Błąd podczas zapisu zagadnień %{count} z %{total} zaznaczonych: %{ids}." + notice_feeds_access_key_reseted: Twój klucz dostępu do kanału Atom został zresetowany. + notice_file_not_found: Strona do której próbujesz się dostać nie istnieje lub została usunięta. + notice_locking_conflict: Dane poprawione przez innego użytkownika. + notice_no_issue_selected: "Nie wybrano zagadnienia! Zaznacz zagadnienie, które chcesz edytować." + notice_not_authorized: Nie posiadasz autoryzacji do oglądania tej strony. + notice_successful_connection: Udane nawiązanie połączenia. + notice_successful_create: Utworzenie zakończone sukcesem. + notice_successful_delete: Usunięcie zakończone sukcesem. + notice_successful_update: Uaktualnienie zakończone sukcesem. + notice_unable_delete_version: Nie można usunąć wersji + permission_add_issue_notes: Dodawanie notatek + permission_add_issue_watchers: Dodawanie obserwatorów + permission_add_issues: Dodawanie zagadnień + permission_add_messages: Dodawanie wiadomości + permission_browse_repository: Przeglądanie repozytorium + permission_comment_news: Komentowanie komunikatów + permission_commit_access: Wykonywanie zatwierdzeń + permission_delete_issues: Usuwanie zagadnień + permission_delete_messages: Usuwanie wiadomości + permission_delete_wiki_pages: Usuwanie stron wiki + permission_delete_wiki_pages_attachments: Usuwanie załączników + permission_delete_own_messages: Usuwanie własnych wiadomości + permission_edit_issue_notes: Edycja notatek + permission_edit_issues: Edycja zagadnień + permission_edit_messages: Edycja wiadomości + permission_edit_own_issue_notes: Edycja własnych notatek + permission_edit_own_messages: Edycja własnych wiadomości + permission_edit_own_time_entries: Edycja własnego dziennika + permission_edit_project: Edycja projektów + permission_edit_time_entries: Edycja wpisów dziennika + permission_edit_wiki_pages: Edycja stron wiki + permission_log_time: Zapisywanie przepracowanego czasu + permission_manage_boards: Zarządzanie forami + permission_manage_categories: Zarządzanie kategoriami zagadnień + permission_manage_files: Zarządzanie plikami + permission_manage_issue_relations: Zarządzanie powiązaniami zagadnień + permission_manage_members: Zarządzanie uczestnikami + permission_manage_news: Zarządzanie komunikatami + permission_manage_public_queries: Zarządzanie publicznymi kwerendami + permission_manage_repository: Zarządzanie repozytorium + permission_manage_versions: Zarządzanie wersjami + permission_manage_wiki: Zarządzanie wiki + permission_move_issues: Przenoszenie zagadnień + permission_protect_wiki_pages: Blokowanie stron wiki + permission_rename_wiki_pages: Zmiana nazw stron wiki + permission_save_queries: Zapisywanie kwerend + permission_select_project_modules: Wybieranie modułów projektu + permission_view_calendar: Podgląd kalendarza + permission_view_changesets: Podgląd zmian + permission_view_documents: Podgląd dokumentów + permission_view_files: Podgląd plików + permission_view_gantt: Podgląd diagramu Gantta + permission_view_issue_watchers: Podgląd listy obserwatorów + permission_view_messages: Podgląd wiadomości + permission_view_time_entries: Podgląd przepracowanego czasu + permission_view_wiki_edits: Podgląd historii wiki + permission_view_wiki_pages: Podgląd wiki + project_module_boards: Fora + project_module_documents: Dokumenty + project_module_files: Pliki + project_module_issue_tracking: Śledzenie zagadnień + project_module_news: Komunikaty + project_module_repository: Repozytorium + project_module_time_tracking: Śledzenie czasu pracy + project_module_wiki: Wiki + setting_activity_days_default: Dni wyświetlane w aktywności projektu + setting_app_subtitle: Podtytuł aplikacji + setting_app_title: Tytuł aplikacji + setting_attachment_max_size: Maks. rozm. załącznika + setting_autofetch_changesets: Automatyczne pobieranie zmian + setting_autologin: Automatyczne logowanie + setting_bcc_recipients: Odbiorcy kopii tajnej (kt/bcc) + setting_commit_fix_keywords: Słowa zmieniające status + setting_commit_ref_keywords: Słowa tworzące powiązania + setting_cross_project_issue_relations: Zezwól na powiązania zagadnień między projektami + setting_date_format: Format daty + setting_default_language: Domyślny język + setting_default_projects_public: Nowe projekty są domyślnie publiczne + setting_display_subprojects_issues: Domyślnie pokazuj zagadnienia podprojektów w głównym projekcie + setting_emails_footer: Stopka e-mail + setting_enabled_scm: Dostępny SCM + setting_feeds_limit: Limit danych Atom + setting_gravatar_enabled: Używaj ikon użytkowników Gravatar + setting_host_name: Nazwa hosta i ścieżka + setting_issue_list_default_columns: Domyślne kolumny wyświetlane na liście zagadnień + setting_issues_export_limit: Limit eksportu zagadnień + setting_login_required: Wymagane zalogowanie + setting_mail_from: Adres e-mail wysyłki + setting_mail_handler_api_enabled: Uaktywnij usługi sieciowe (WebServices) dla poczty przychodzącej + setting_mail_handler_api_key: Klucz API + setting_per_page_options: Opcje ilości obiektów na stronie + setting_plain_text_mail: tylko tekst (bez HTML) + setting_protocol: Protokół + setting_self_registration: Samodzielna rejestracja użytkowników + setting_sequential_project_identifiers: Generuj sekwencyjne identyfikatory projektów + setting_sys_api_enabled: Włączenie WS do zarządzania repozytorium + setting_text_formatting: Formatowanie tekstu + setting_time_format: Format czasu + setting_user_format: Własny format wyświetlania + setting_welcome_text: Tekst powitalny + setting_wiki_compression: Kompresja historii Wiki + status_active: aktywny + status_locked: zablokowany + status_registered: zarejestrowany + text_are_you_sure: Jesteś pewien ? + text_assign_time_entries_to_project: Przypisz wpisy dziennika do projektu + text_caracters_maximum: "%{count} znaków maksymalnie." + text_caracters_minimum: "Musi być nie krótsze niż %{count} znaków." + text_comma_separated: Dozwolone wielokrotne wartości (rozdzielone przecinkami). + text_default_administrator_account_changed: Zmieniono domyślne hasło administratora + text_destroy_time_entries: Usuń wpisy dziennika + text_destroy_time_entries_question: Przepracowano %{hours} godzin przy zagadnieniu, które chcesz usunąć. Co chcesz zrobić? + text_email_delivery_not_configured: "Dostarczanie poczty elektronicznej nie zostało skonfigurowane, więc powiadamianie jest nieaktywne.\nSkonfiguruj serwer SMTP w config/email.yml a następnie zrestartuj aplikację i uaktywnij to." + text_enumeration_category_reassign_to: 'Zmień przypisanie na tą wartość:' + text_enumeration_destroy_question: "%{count} obiektów jest przypisanych do tej wartości." + text_file_repository_writable: Zapisywalne repozytorium plików + text_issue_added: "Zagadnienie %{id} zostało wprowadzone (przez %{author})." + text_issue_category_destroy_assignments: Usuń przydziały kategorii + text_issue_category_destroy_question: "Do tej kategorii są przypisane zagadnienia (%{count}). Co chcesz zrobić?" + text_issue_category_reassign_to: Przydziel zagadnienie do tej kategorii + text_issue_updated: "Zagadnienie %{id} zostało zaktualizowane (przez %{author})." + text_issues_destroy_confirmation: 'Czy jesteś pewien, że chcesz usunąć wskazane zagadnienia?' + text_issues_ref_in_commit_messages: Odwołania do zagadnień w komentarzach zatwierdzeń + text_length_between: "Długość pomiędzy %{min} i %{max} znaków." + text_load_default_configuration: Załaduj domyślną konfigurację + text_min_max_length_info: 0 oznacza brak restrykcji + text_no_configuration_data: "Role użytkowników, typy zagadnień, statusy zagadnień oraz przepływ pracy nie zostały jeszcze skonfigurowane.\nWysoce zalecane jest by załadować domyślną konfigurację. Po załadowaniu będzie możliwość edycji tych danych." + text_project_destroy_confirmation: Jesteś pewien, że chcesz usunąć ten projekt i wszystkie powiązane dane? + text_reassign_time_entries: 'Przepnij przepracowany czas do tego zagadnienia:' + text_regexp_info: np. ^[A-Z0-9]+$ + text_repository_usernames_mapping: "Wybierz lub uaktualnij przyporządkowanie użytkowników Redmine do użytkowników repozytorium.\nUżytkownicy z taką samą nazwą lub adresem e-mail są przyporządkowani automatycznie." + text_rmagick_available: RMagick dostępne (opcjonalnie) + text_select_mail_notifications: Zaznacz czynności przy których użytkownik powinien być powiadomiony e-mailem. + text_select_project_modules: 'Wybierz moduły do aktywacji w tym projekcie:' + text_status_changed_by_changeset: "Zastosowane w zmianach %{value}." + text_subprojects_destroy_warning: "Podprojekt(y): %{value} zostaną także usunięte." + text_tip_issue_begin_day: zadanie zaczynające się dzisiaj + text_tip_issue_begin_end_day: zadanie zaczynające i kończące się dzisiaj + text_tip_issue_end_day: zadanie kończące się dzisiaj + text_tracker_no_workflow: Brak przepływu pracy zdefiniowanego dla tego typu zagadnienia + text_unallowed_characters: Niedozwolone znaki + text_user_mail_option: "W przypadku niezaznaczonych projektów, będziesz otrzymywał powiadomienia tylko na temat zagadnień które obserwujesz, lub w których bierzesz udział (np. jesteś autorem lub adresatem)." + text_user_wrote: "%{value} napisał(a):" + text_wiki_destroy_confirmation: Jesteś pewien, że chcesz usunąć to wiki i całą jego zawartość? + text_workflow_edit: Zaznacz rolę i typ zagadnienia do edycji przepływu pracy + + label_user_activity: "Aktywność: %{value}" + label_updated_time_by: "Uaktualnione przez %{author} %{age} temu" + text_diff_truncated: '... Ten plik różnic został przycięty ponieważ jest zbyt długi.' + setting_diff_max_lines_displayed: Maksymalna liczba linii różnicy do pokazania + text_plugin_assets_writable: Zapisywalny katalog zasobów wtyczek + warning_attachments_not_saved: "%{count} załącznik(ów) nie zostało zapisanych." + field_editable: Edytowalne + label_display: Wygląd + button_create_and_continue: Stwórz i dodaj kolejne + text_custom_field_possible_values_info: 'Każda wartość w osobnej linii' + setting_repository_log_display_limit: Maksymalna liczba rewizji pokazywanych w logu pliku + setting_file_max_size_displayed: Maksymalny rozmiar plików tekstowych osadzanych w stronie + field_watcher: Obserwator + setting_openid: Logowanie i rejestracja przy użyciu OpenID + field_identity_url: Identyfikator OpenID (URL) + label_login_with_open_id_option: albo użyj OpenID + field_content: Treść + label_descending: Malejąco + label_sort: Sortuj + label_ascending: Rosnąco + label_date_from_to: Od %{start} do %{end} + label_greater_or_equal: ">=" + label_less_or_equal: <= + text_wiki_page_destroy_question: Ta strona posiada podstrony (%{descendants}). Co chcesz zrobić? + text_wiki_page_reassign_children: Podepnij je do strony nadrzędnej względem usuwanej + text_wiki_page_nullify_children: Przesuń je na szczyt hierarchii + text_wiki_page_destroy_children: Usuń wszystkie podstrony + setting_password_min_length: Minimalna długość hasła + field_group_by: Grupuj wyniki wg + mail_subject_wiki_content_updated: "Strona wiki '%{id}' została uaktualniona" + label_wiki_content_added: Dodano stronę wiki + mail_subject_wiki_content_added: "Strona wiki '%{id}' została dodana" + mail_body_wiki_content_added: Strona wiki '%{id}' została dodana przez %{author}. + label_wiki_content_updated: Uaktualniono stronę wiki + mail_body_wiki_content_updated: Strona wiki '%{id}' została uaktualniona przez %{author}. + permission_add_project: Tworzenie projektu + setting_new_project_user_role_id: Rola nadawana twórcom projektów, którzy nie posiadają uprawnień administatora + label_view_all_revisions: Pokaż wszystkie rewizje + label_tag: Słowo kluczowe + label_branch: Gałąź + error_no_tracker_in_project: Projekt nie posiada powiązanych typów zagadnień. Sprawdź ustawienia projektu. + error_no_default_issue_status: Nie zdefiniowano domyślnego statusu zagadnień. Sprawdź konfigurację (Przejdź do "Administracja -> Statusy zagadnień"). + text_journal_changed: "Zmieniono %{label} z %{old} na %{new}" + text_journal_set_to: "Ustawiono %{label} na %{value}" + text_journal_deleted: "Usunięto %{label} (%{old})" + label_group_plural: Grupy + label_group: Grupa + label_group_new: Nowa grupa + label_time_entry_plural: Przepracowany czas + text_journal_added: "Dodano %{label} %{value}" + field_active: Aktywne + enumeration_system_activity: Aktywność systemowa + button_copy_and_follow: Kopiuj i przejdź do kopii zagadnienia + button_duplicate: Duplikuj + button_move_and_follow: Przenieś i przejdź do zagadnienia + button_show: Pokaż + error_can_not_archive_project: Ten projekt nie może zostać zarchiwizowany + error_can_not_reopen_issue_on_closed_version: Zagadnienie przydzielone do zakończonej wersji nie może zostać ponownie otwarte + error_issue_done_ratios_not_updated: "% wykonania zagadnienia nie został uaktualniony." + error_workflow_copy_source: Proszę wybrać źródłowy typ zagadnienia lub rolę + error_workflow_copy_target: Proszę wybrać docelowe typ(y) zagadnień i rolę(e) + field_sharing: Współdzielenie + label_api_access_key: Klucz dostępu do API + label_api_access_key_created_on: Klucz dostępu do API został utworzony %{value} temu + label_close_versions: Zamknij ukończone wersje + label_copy_same_as_target: Jak cel + label_copy_source: Źródło + label_copy_target: Cel + label_display_used_statuses_only: Wyświetlaj tylko statusy używane przez ten typ zagadnienia + label_feeds_access_key: Klucz dostępu do kanału Atom + label_missing_api_access_key: Brakuje klucza dostępu do API + label_missing_feeds_access_key: Brakuje klucza dostępu do kanału Atom + label_revision_id: Rewizja %{value} + label_subproject_new: Nowy podprojekt + label_update_issue_done_ratios: Uaktualnij % wykonania + label_user_anonymous: Anonimowy + label_version_sharing_descendants: Z podprojektami + label_version_sharing_hierarchy: Z hierarchią projektów + label_version_sharing_none: Brak współdzielenia + label_version_sharing_system: Ze wszystkimi projektami + label_version_sharing_tree: Z drzewem projektów + notice_api_access_key_reseted: Twój klucz dostępu do API został zresetowany. + notice_issue_done_ratios_updated: Uaktualnienie % wykonania zakończone sukcesem. + permission_add_subprojects: Tworzenie podprojektów + permission_delete_issue_watchers: Usuń obserwatorów + permission_view_issues: Przeglądanie zagadnień + setting_default_projects_modules: Domyślnie włączone moduły dla nowo tworzonych projektów + setting_gravatar_default: Domyślny obraz Gravatar + setting_issue_done_ratio: Obliczaj postęp realizacji zagadnień za pomocą + setting_issue_done_ratio_issue_field: "% Wykonania zagadnienia" + setting_issue_done_ratio_issue_status: Statusu zagadnienia + setting_mail_handler_body_delimiters: Przycinaj e-maile po jednej z tych linii + setting_rest_api_enabled: Uaktywnij usługę sieciową REST + setting_start_of_week: Pierwszy dzień tygodnia + text_line_separated: Dozwolone jest wiele wartości (każda wartość w osobnej linii). + text_own_membership_delete_confirmation: |- + Masz zamiar usunąć niektóre lub wszystkie swoje uprawnienia. Po wykonaniu tej czynności możesz utracić możliwości edycji tego projektu. + Czy na pewno chcesz kontynuować? + version_status_closed: zamknięta + version_status_locked: zablokowana + version_status_open: otwarta + + label_board_sticky: Przyklejona + label_board_locked: Zamknięta + permission_export_wiki_pages: Eksport stron wiki + permission_manage_project_activities: Zarządzanie aktywnościami projektu + setting_cache_formatted_text: Buforuj sformatowany tekst + error_unable_delete_issue_status: Nie można usunąć statusu zagadnienia + label_profile: Profil + permission_manage_subtasks: Zarządzanie podzagadnieniami + field_parent_issue: Zagadnienie nadrzędne + label_subtask_plural: Podzagadnienia + label_project_copy_notifications: Wyślij powiadomienia e-mailowe przy kopiowaniu projektu + error_can_not_delete_custom_field: Nie można usunąć tego pola + error_unable_to_connect: Nie można połączyć (%{value}) + error_can_not_remove_role: Ta rola przypisana jest niektórym użytkownikom i nie może zostać usunięta. + error_can_not_delete_tracker: Ten typ przypisany jest do części zagadnień i nie może zostać usunięty. + field_principal: Przełożony + label_my_page_block: Elementy + notice_failed_to_save_members: "Nie można zapisać uczestników: %{errors}." + text_zoom_out: Zmniejsz + text_zoom_in: Powiększ + notice_unable_delete_time_entry: Nie można usunąć wpisu z dziennika. + label_overall_spent_time: Przepracowany czas + field_time_entries: Dziennik + project_module_gantt: Diagram Gantta + project_module_calendar: Kalendarz + button_edit_associated_wikipage: "Edit associated Wiki page: %{page_title}" + field_text: Text field + label_user_mail_option_only_owner: Only for things I am the owner of + setting_default_notification_option: Default notification option + label_user_mail_option_only_my_events: Only for things I watch or I'm involved in + label_user_mail_option_only_assigned: Only for things I am assigned to + label_user_mail_option_none: "Tylko to, co obserwuję lub w czym biorę udział" + field_member_of_group: Assignee's group + field_assigned_to_role: Assignee's role + notice_not_authorized_archived_project: The project you're trying to access has been archived. + label_principal_search: "Szukaj użytkownika lub grupy:" + label_user_search: "Szukaj użytkownika:" + field_visible: Visible + setting_commit_logtime_activity_id: Activity for logged time + text_time_logged_by_changeset: Applied in changeset %{value}. + setting_commit_logtime_enabled: Enable time logging + notice_gantt_chart_truncated: The chart was truncated because it exceeds the maximum number of items that can be displayed (%{max}) + setting_gantt_items_limit: Maximum number of items displayed on the gantt chart + field_warn_on_leaving_unsaved: Warn me when leaving a page with unsaved text + text_warn_on_leaving_unsaved: The current page contains unsaved text that will be lost if you leave this page. + label_my_queries: My custom queries + text_journal_changed_no_detail: "%{label} updated" + label_news_comment_added: Comment added to a news + button_expand_all: Expand all + button_collapse_all: Collapse all + label_additional_workflow_transitions_for_assignee: Additional transitions allowed when the user is the assignee + label_additional_workflow_transitions_for_author: Additional transitions allowed when the user is the author + label_bulk_edit_selected_time_entries: Bulk edit selected time entries + text_time_entries_destroy_confirmation: Are you sure you want to delete the selected time entr(y/ies)? + label_role_anonymous: Anonymous + label_role_non_member: Non member + label_issue_note_added: Note added + label_issue_status_updated: Status updated + label_issue_priority_updated: Priority updated + label_issues_visibility_own: Issues created by or assigned to the user + field_issues_visibility: Issues visibility + label_issues_visibility_all: All issues + permission_set_own_issues_private: Set own issues public or private + field_is_private: Private + permission_set_issues_private: Set issues public or private + label_issues_visibility_public: All non private issues + text_issues_destroy_descendants_confirmation: This will also delete %{count} subtask(s). + field_commit_logs_encoding: Kodowanie komentarzy zatwierdzeń + field_scm_path_encoding: Path encoding + text_scm_path_encoding_note: "Default: UTF-8" + field_path_to_repository: Path to repository + field_root_directory: Root directory + field_cvs_module: Module + field_cvsroot: CVSROOT + text_mercurial_repository_note: Local repository (e.g. /hgrepo, c:\hgrepo) + text_scm_command: Command + text_scm_command_version: Version + label_git_report_last_commit: Report last commit for files and directories + notice_issue_successful_create: Issue %{id} created. + label_between: between + setting_issue_group_assignment: Allow issue assignment to groups + label_diff: diff + text_git_repository_note: Repository is bare and local (e.g. /gitrepo, c:\gitrepo) + description_query_sort_criteria_direction: Sort direction + description_project_scope: Search scope + description_filter: Filter + description_user_mail_notification: Mail notification settings + description_date_from: Enter start date + description_message_content: Message content + description_available_columns: Available Columns + description_date_range_interval: Choose range by selecting start and end date + description_issue_category_reassign: Choose issue category + description_search: Searchfield + description_notes: Notes + description_date_range_list: Choose range from list + description_choose_project: Projects + description_date_to: Enter end date + description_query_sort_criteria_attribute: Sort attribute + description_wiki_subpages_reassign: Choose new parent page + description_selected_columns: Selected Columns + label_parent_revision: Parent + label_child_revision: Child + error_scm_annotate_big_text_file: The entry cannot be annotated, as it exceeds the maximum text file size. + setting_default_issue_start_date_to_creation_date: Use current date as start date for new issues + button_edit_section: Edit this section + setting_repositories_encodings: Attachments and repositories encodings + description_all_columns: All Columns + button_export: Export + label_export_options: "%{export_format} export options" + error_attachment_too_big: This file cannot be uploaded because it exceeds the maximum allowed file size (%{max_size}) + notice_failed_to_save_time_entries: "Failed to save %{count} time entrie(s) on %{total} selected: %{ids}." + label_x_issues: + zero: 0 zagadnienie + one: 1 zagadnienie + other: "%{count} zagadnienia" + label_repository_new: New repository + field_repository_is_default: Main repository + label_copy_attachments: Copy attachments + label_item_position: "%{position}/%{count}" + label_completed_versions: Completed versions + text_project_identifier_info: 'Dozwolone małe litery (a-z), liczby i myślniki.
    Raz zapisany, identyfikator nie może być zmieniony.' + field_multiple: Multiple values + setting_commit_cross_project_ref: Allow issues of all the other projects to be referenced and fixed + text_issue_conflict_resolution_add_notes: Add my notes and discard my other changes + text_issue_conflict_resolution_overwrite: Apply my changes anyway (previous notes will be kept but some changes may be overwritten) + notice_issue_update_conflict: The issue has been updated by an other user while you were editing it. + text_issue_conflict_resolution_cancel: Discard all my changes and redisplay %{link} + permission_manage_related_issues: Manage related issues + field_auth_source_ldap_filter: LDAP filter + label_search_for_watchers: Search for watchers to add + notice_account_deleted: Your account has been permanently deleted. + setting_unsubscribe: Allow users to delete their own account + button_delete_my_account: Delete my account + text_account_destroy_confirmation: |- + Are you sure you want to proceed? + Your account will be permanently deleted, with no way to reactivate it. + error_session_expired: Your session has expired. Please login again. + text_session_expiration_settings: "Warning: changing these settings may expire the current sessions including yours." + setting_session_lifetime: Session maximum lifetime + setting_session_timeout: Session inactivity timeout + label_session_expiration: Session expiration + permission_close_project: Close / reopen the project + label_show_closed_projects: View closed projects + button_close: Close + button_reopen: Reopen + project_status_active: active + project_status_closed: closed + project_status_archived: archived + text_project_closed: This project is closed and read-only. + notice_user_successful_create: User %{id} created. + field_core_fields: Standard fields + field_timeout: Timeout (in seconds) + setting_thumbnails_enabled: Display attachment thumbnails + setting_thumbnails_size: Thumbnails size (in pixels) + label_status_transitions: Status transitions + label_fields_permissions: Fields permissions + label_readonly: Read-only + label_required: Required + text_repository_identifier_info: Only lower case letters (a-z), numbers, dashes and underscores are allowed.
    Once saved, the identifier cannot be changed. + field_board_parent: Parent forum + label_attribute_of_project: Project's %{name} + label_attribute_of_author: Author's %{name} + label_attribute_of_assigned_to: Assignee's %{name} + label_attribute_of_fixed_version: Target version's %{name} + label_copy_subtasks: Copy subtasks + label_copied_to: copied to + label_copied_from: copied from + label_any_issues_in_project: any issues in project + label_any_issues_not_in_project: any issues not in project + field_private_notes: Private notes + permission_view_private_notes: View private notes + permission_set_notes_private: Set notes as private + label_no_issues_in_project: no issues in project + label_any: wszystko + label_last_n_weeks: last %{count} weeks + setting_cross_project_subtasks: Allow cross-project subtasks + label_cross_project_descendants: Z podprojektami + label_cross_project_tree: Z drzewem projektów + label_cross_project_hierarchy: Z hierarchią projektów + label_cross_project_system: Ze wszystkimi projektami + button_hide: Hide + setting_non_working_week_days: Non-working days + label_in_the_next_days: in the next + label_in_the_past_days: in the past + label_attribute_of_user: User's %{name} + text_turning_multiple_off: If you disable multiple values, multiple values will be + removed in order to preserve only one value per item. + label_attribute_of_issue: Issue's %{name} + permission_add_documents: Add documents + permission_edit_documents: Edit documents + permission_delete_documents: Delete documents + label_gantt_progress_line: Progress line + setting_jsonp_enabled: Enable JSONP support + field_inherit_members: Inherit members + field_closed_on: Closed + setting_default_projects_tracker_ids: Default trackers for new projects + label_total_time: Ogółem + text_scm_config: You can configure your SCM commands in config/configuration.yml. Please restart the application after editing it. + text_scm_command_not_available: SCM command is not available. Please check settings on the administration panel. + setting_emails_header: Email header diff --git a/config/locales/pt-BR.yml b/config/locales/pt-BR.yml new file mode 100644 index 00000000..0752e847 --- /dev/null +++ b/config/locales/pt-BR.yml @@ -0,0 +1,1109 @@ +pt-BR: + direction: ltr + date: + formats: + default: "%d/%m/%Y" + short: "%d de %B" + long: "%d de %B de %Y" + only_day: "%d" + + day_names: [Domingo, Segunda, Terça, Quarta, Quinta, Sexta, Sábado] + abbr_day_names: [Dom, Seg, Ter, Qua, Qui, Sex, Sáb] + month_names: [~, Janeiro, Fevereiro, Março, Abril, Maio, Junho, Julho, Agosto, Setembro, Outubro, Novembro, Dezembro] + abbr_month_names: [~, Jan, Fev, Mar, Abr, Mai, Jun, Jul, Ago, Set, Out, Nov, Dez] + order: + - :day + - :month + - :year + + time: + formats: + default: "%A, %d de %B de %Y, %H:%M h" + time: "%H:%M h" + short: "%d/%m, %H:%M h" + long: "%A, %d de %B de %Y, %H:%M h" + only_second: "%S" + datetime: + formats: + default: "%Y-%m-%dT%H:%M:%S%Z" + am: '' + pm: '' + + # date helper distancia em palavras + datetime: + distance_in_words: + half_a_minute: 'meio minuto' + less_than_x_seconds: + one: 'menos de 1 segundo' + other: 'menos de %{count} segundos' + + x_seconds: + one: '1 segundo' + other: '%{count} segundos' + + less_than_x_minutes: + one: 'menos de um minuto' + other: 'menos de %{count} minutos' + + x_minutes: + one: '1 minuto' + other: '%{count} minutos' + + about_x_hours: + one: 'aproximadamente 1 hora' + other: 'aproximadamente %{count} horas' + x_hours: + one: "1 hora" + other: "%{count} horas" + + x_days: + one: '1 dia' + other: '%{count} dias' + + about_x_months: + one: 'aproximadamente 1 mês' + other: 'aproximadamente %{count} meses' + + x_months: + one: '1 mês' + other: '%{count} meses' + + about_x_years: + one: 'aproximadamente 1 ano' + other: 'aproximadamente %{count} anos' + + over_x_years: + one: 'mais de 1 ano' + other: 'mais de %{count} anos' + almost_x_years: + one: "quase 1 ano" + other: "quase %{count} anos" + + # numeros + number: + format: + precision: 3 + separator: ',' + delimiter: '.' + currency: + format: + unit: 'R$' + precision: 2 + format: '%u %n' + separator: ',' + delimiter: '.' + percentage: + format: + delimiter: '.' + precision: + format: + delimiter: '.' + human: + format: + precision: 3 + delimiter: '.' + storage_units: + format: "%n %u" + units: + byte: + one: "Byte" + other: "Bytes" + kb: "KB" + mb: "MB" + gb: "GB" + tb: "TB" + support: + array: + sentence_connector: "e" + skip_last_comma: true + + # Active Record + activerecord: + errors: + template: + header: + one: "modelo não pode ser salvo: 1 erro" + other: "modelo não pode ser salvo: %{count} erros." + body: "Por favor, verifique os seguintes campos:" + messages: + inclusion: "não está incluso na lista" + exclusion: "não está disponível" + invalid: "não é válido" + confirmation: "não está de acordo com a confirmação" + accepted: "precisa ser aceito" + empty: "não pode ficar vazio" + blank: "não pode ficar vazio" + too_long: "é muito longo (máximo: %{count} caracteres)" + too_short: "é muito curto (mínimo: %{count} caracteres)" + wrong_length: "deve ter %{count} caracteres" + taken: "não está disponível" + not_a_number: "não é um número" + greater_than: "precisa ser maior do que %{count}" + greater_than_or_equal_to: "precisa ser maior ou igual a %{count}" + equal_to: "precisa ser igual a %{count}" + less_than: "precisa ser menor do que %{count}" + less_than_or_equal_to: "precisa ser menor ou igual a %{count}" + odd: "precisa ser ímpar" + even: "precisa ser par" + greater_than_start_date: "deve ser maior que a data inicial" + not_same_project: "não pertence ao mesmo projeto" + circular_dependency: "Esta relação geraria uma dependência circular" + cant_link_an_issue_with_a_descendant: "Uma tarefa não pode ser relaciona a uma de suas subtarefas" + + actionview_instancetag_blank_option: Selecione + + general_text_No: 'Não' + general_text_Yes: 'Sim' + general_text_no: 'não' + general_text_yes: 'sim' + general_lang_name: 'Português(Brasil)' + general_csv_separator: ';' + general_csv_decimal_separator: ',' + general_csv_encoding: ISO-8859-1 + general_pdf_encoding: UTF-8 + general_first_day_of_week: '1' + + notice_account_updated: Conta atualizada com sucesso. + notice_account_invalid_creditentials: Usuário ou senha inválido. + notice_account_password_updated: Senha alterada com sucesso. + notice_account_wrong_password: Senha inválida. + notice_account_register_done: Conta criada com sucesso. Para ativar sua conta, clique no link que lhe foi enviado por e-mail. + notice_account_unknown_email: Usuário desconhecido. + notice_can_t_change_password: Esta conta utiliza autenticação externa. Não é possível alterar a senha. + notice_account_lost_email_sent: Um e-mail com instruções para escolher uma nova senha foi enviado para você. + notice_account_activated: Sua conta foi ativada. Você pode acessá-la agora. + notice_successful_create: Criado com sucesso. + notice_successful_update: Alterado com sucesso. + notice_successful_delete: Excluído com sucesso. + notice_successful_connection: Conectado com sucesso. + notice_file_not_found: A página que você está tentando acessar não existe ou foi excluída. + notice_locking_conflict: Os dados foram atualizados por outro usuário. + notice_not_authorized: Você não está autorizado a acessar esta página. + notice_email_sent: "Um e-mail foi enviado para %{value}" + notice_email_error: "Ocorreu um erro ao enviar o e-mail (%{value})" + notice_feeds_access_key_reseted: Sua chave RSS foi reconfigurada. + notice_failed_to_save_issues: "Problema ao salvar %{count} tarefa(s) de %{total} selecionadas: %{ids}." + notice_no_issue_selected: "Nenhuma tarefa selecionada! Por favor, marque as tarefas que você deseja editar." + notice_account_pending: "Sua conta foi criada e está aguardando aprovação do administrador." + notice_default_data_loaded: Configuração padrão carregada com sucesso. + + error_can_t_load_default_data: "A configuração padrão não pode ser carregada: %{value}" + error_scm_not_found: "A entrada e/ou a revisão não existe no repositório." + error_scm_command_failed: "Ocorreu um erro ao tentar acessar o repositório: %{value}" + error_scm_annotate: "Esta entrada não existe ou não pode ser anotada." + error_issue_not_found_in_project: 'A tarefa não foi encontrada ou não pertence a este projeto' + error_no_tracker_in_project: 'Não há um tipo de tarefa associado a este projeto. Favor verificar as configurações do projeto.' + error_no_default_issue_status: 'A situação padrão para tarefa não está definida. Favor verificar sua configuração (Vá em "Administração -> Situação da tarefa").' + + mail_subject_lost_password: "Sua senha do %{value}." + mail_body_lost_password: 'Para mudar sua senha, clique no link abaixo:' + mail_subject_register: "Ativação de conta do %{value}." + mail_body_register: 'Para ativar sua conta, clique no link abaixo:' + mail_body_account_information_external: "Você pode usar sua conta do %{value} para entrar." + mail_body_account_information: Informações sobre sua conta + mail_subject_account_activation_request: "%{value} - Requisição de ativação de conta" + mail_body_account_activation_request: "Um novo usuário (%{value}) se registrou. A conta está aguardando sua aprovação:" + mail_subject_reminder: "%{count} tarefa(s) com data prevista para os próximos %{days} dias" + mail_body_reminder: "%{count} tarefa(s) para você com data prevista para os próximos %{days} dias:" + + + field_name: Nome + field_description: Descrição + field_summary: Resumo + field_is_required: Obrigatório + field_firstname: Nome + field_lastname: Sobrenome + field_mail: E-mail + field_filename: Arquivo + field_filesize: Tamanho + field_downloads: Downloads + field_author: Autor + field_created_on: Criado em + field_updated_on: Alterado em + field_field_format: Formato + field_is_for_all: Para todos os projetos + field_possible_values: Possíveis valores + field_regexp: Expressão regular + field_min_length: Tamanho mínimo + field_max_length: Tamanho máximo + field_value: Valor + field_category: Categoria + field_title: Título + field_project: Projeto + field_issue: Tarefa + field_status: Situação + field_notes: Notas + field_is_closed: Tarefa fechada + field_is_default: Situação padrão + field_tracker: Tipo + field_subject: Título + field_due_date: Data prevista + field_assigned_to: Atribuído para + field_priority: Prioridade + field_fixed_version: Versão + field_user: Usuário + field_role: Cargo + field_homepage: Página do projeto + field_is_public: Público + field_parent: Sub-projeto de + field_is_in_roadmap: Exibir no planejamento + field_login: Usuário + field_mail_notification: Notificações por e-mail + field_admin: Administrador + field_last_login_on: Última conexão + field_language: Idioma + field_effective_date: Data + field_password: Senha + field_new_password: Nova senha + field_password_confirmation: Confirmação + field_version: Versão + field_type: Tipo + field_host: Servidor + field_port: Porta + field_account: Conta + field_base_dn: DN Base + field_attr_login: Atributo para nome de usuário + field_attr_firstname: Atributo para nome + field_attr_lastname: Atributo para sobrenome + field_attr_mail: Atributo para e-mail + field_onthefly: Criar usuários dinamicamente ("on-the-fly") + field_start_date: Início + field_done_ratio: "% Terminado" + field_auth_source: Modo de autenticação + field_hide_mail: Ocultar meu e-mail + field_comments: Comentário + field_url: URL + field_start_page: Página inicial + field_subproject: Sub-projeto + field_hours: Horas + field_activity: Atividade + field_spent_on: Data + field_identifier: Identificador + field_is_filter: É um filtro + field_issue_to: Tarefa relacionada + field_delay: Atraso + field_assignable: Tarefas podem ser atribuídas a este papel + field_redirect_existing_links: Redirecionar links existentes + field_estimated_hours: Tempo estimado + field_column_names: Colunas + field_time_zone: Fuso-horário + field_searchable: Pesquisável + field_default_value: Padrão + field_comments_sorting: Visualizar comentários + field_parent_title: Página pai + + setting_app_title: Título da aplicação + setting_app_subtitle: Sub-título da aplicação + setting_welcome_text: Texto de boas-vindas + setting_default_language: Idioma padrão + setting_login_required: Exigir autenticação + setting_self_registration: Permitido Auto-registro + setting_attachment_max_size: Tamanho máximo do anexo + setting_issues_export_limit: Limite de exportação das tarefas + setting_mail_from: E-mail enviado de + setting_bcc_recipients: Enviar com cópia oculta (cco) + setting_host_name: Nome do Servidor e subdomínio + setting_text_formatting: Formatação do texto + setting_wiki_compression: Compactação de histórico do Wiki + setting_feeds_limit: Número de registros por Feed + setting_default_projects_public: Novos projetos são públicos por padrão + setting_autofetch_changesets: Obter commits automaticamente + setting_sys_api_enabled: Ativa WS para gerenciamento do repositório (SVN) + setting_commit_ref_keywords: Palavras de referência + setting_commit_fix_keywords: Palavras de fechamento + setting_autologin: Auto-login + setting_date_format: Formato da data + setting_time_format: Formato de hora + setting_cross_project_issue_relations: Permitir relacionar tarefas entre projetos + setting_issue_list_default_columns: Colunas padrão visíveis na lista de tarefas + setting_emails_footer: Rodapé do e-mail + setting_protocol: Protocolo + setting_per_page_options: Número de itens exibidos por página + setting_user_format: Formato de exibição de nome de usuário + setting_activity_days_default: Dias visualizados na atividade do projeto + setting_display_subprojects_issues: Visualizar tarefas dos subprojetos nos projetos principais por padrão + setting_enabled_scm: SCM habilitados + setting_mail_handler_api_enabled: Habilitar WS para e-mails de entrada + setting_mail_handler_api_key: Chave de API + setting_sequential_project_identifiers: Gerar identificadores sequenciais de projeto + + project_module_issue_tracking: Gerenciamento de Tarefas + project_module_time_tracking: Gerenciamento de tempo + project_module_news: Notícias + project_module_documents: Documentos + project_module_files: Arquivos + project_module_wiki: Wiki + project_module_repository: Repositório + project_module_boards: Fóruns + + label_user: Usuário + label_user_plural: Usuários + label_user_new: Novo usuário + label_project: Projeto + label_project_new: Novo projeto + label_project_plural: Projetos + label_x_projects: + zero: nenhum projeto + one: 1 projeto + other: "%{count} projetos" + label_project_all: Todos os projetos + label_project_latest: Últimos projetos + label_issue: Tarefa + label_issue_new: Nova tarefa + label_issue_plural: Tarefas + label_issue_view_all: Ver todas as tarefas + label_issues_by: "Tarefas por %{value}" + label_issue_added: Tarefa adicionada + label_issue_updated: Tarefa atualizada + label_issue_note_added: Nota adicionada + label_issue_status_updated: Situação atualizada + label_issue_priority_updated: Prioridade atualizada + label_document: Documento + label_document_new: Novo documento + label_document_plural: Documentos + label_document_added: Documento adicionado + label_role: Papel + label_role_plural: Papéis + label_role_new: Novo papel + label_role_and_permissions: Papéis e permissões + label_member: Membro + label_member_new: Novo membro + label_member_plural: Membros + label_tracker: Tipo de tarefa + label_tracker_plural: Tipos de tarefas + label_tracker_new: Novo tipo + label_workflow: Fluxo de trabalho + label_issue_status: Situação da tarefa + label_issue_status_plural: Situação das tarefas + label_issue_status_new: Nova situação + label_issue_category: Categoria da tarefa + label_issue_category_plural: Categorias das tarefas + label_issue_category_new: Nova categoria + label_custom_field: Campo personalizado + label_custom_field_plural: Campos personalizados + label_custom_field_new: Novo campo personalizado + label_enumerations: 'Tipos & Categorias' + label_enumeration_new: Novo + label_information: Informação + label_information_plural: Informações + label_please_login: Efetue o login + label_register: Cadastre-se + label_password_lost: Perdi minha senha + label_home: Página inicial + label_my_page: Minha página + label_my_account: Minha conta + label_my_projects: Meus projetos + label_administration: Administração + label_login: Entrar + label_logout: Sair + label_help: Ajuda + label_reported_issues: Tarefas reportadas + label_assigned_to_me_issues: Minhas tarefas + label_last_login: Última conexão + label_registered_on: Registrado em + label_activity: Atividade + label_overall_activity: Atividades gerais + label_new: Novo + label_logged_as: "Acessando como:" + label_environment: Ambiente + label_authentication: Autenticação + label_auth_source: Modo de autenticação + label_auth_source_new: Novo modo de autenticação + label_auth_source_plural: Modos de autenticação + label_subproject_plural: Sub-projetos + label_and_its_subprojects: "%{value} e seus sub-projetos" + label_min_max_length: Tamanho mín-máx + label_list: Lista + label_date: Data + label_integer: Inteiro + label_float: Decimal + label_boolean: Boleano + label_string: Texto + label_text: Texto longo + label_attribute: Atributo + label_attribute_plural: Atributos + label_no_data: Nenhuma informação disponível + label_change_status: Alterar situação + label_history: Histórico + label_attachment: Arquivo + label_attachment_new: Novo arquivo + label_attachment_delete: Excluir arquivo + label_attachment_plural: Arquivos + label_file_added: Arquivo adicionado + label_report: Relatório + label_report_plural: Relatório + label_news: Notícia + label_news_new: Adicionar notícia + label_news_plural: Notícias + label_news_latest: Últimas notícias + label_news_view_all: Ver todas as notícias + label_news_added: Notícia adicionada + label_settings: Configurações + label_overview: Visão geral + label_version: Versão + label_version_new: Nova versão + label_version_plural: Versões + label_confirmation: Confirmação + label_export_to: Exportar para + label_read: Ler... + label_public_projects: Projetos públicos + label_open_issues: Aberta + label_open_issues_plural: Abertas + label_closed_issues: Fechada + label_closed_issues_plural: Fechadas + label_x_open_issues_abbr_on_total: + zero: 0 aberta / %{total} + one: 1 aberta / %{total} + other: "%{count} abertas / %{total}" + label_x_open_issues_abbr: + zero: 0 aberta + one: 1 aberta + other: "%{count} abertas" + label_x_closed_issues_abbr: + zero: 0 fechada + one: 1 fechada + other: "%{count} fechadas" + label_total: Total + label_permissions: Permissões + label_current_status: Situação atual + label_new_statuses_allowed: Nova situação permitida + label_all: todos + label_none: nenhum + label_nobody: ninguém + label_next: Próximo + label_previous: Anterior + label_used_by: Usado por + label_details: Detalhes + label_add_note: Adicionar nota + label_per_page: Por página + label_calendar: Calendário + label_months_from: meses a partir de + label_gantt: Gantt + label_internal: Interno + label_last_changes: "últimas %{count} alterações" + label_change_view_all: Mostrar todas as alterações + label_personalize_page: Personalizar esta página + label_comment: Comentário + label_comment_plural: Comentários + label_x_comments: + zero: nenhum comentário + one: 1 comentário + other: "%{count} comentários" + label_comment_add: Adicionar comentário + label_comment_added: Comentário adicionado + label_comment_delete: Excluir comentário + label_query: Consulta personalizada + label_query_plural: Consultas personalizadas + label_query_new: Nova consulta + label_filter_add: Adicionar filtro + label_filter_plural: Filtros + label_equals: igual a + label_not_equals: diferente de + label_in_less_than: maior que + label_in_more_than: menor que + label_in: em + label_today: hoje + label_all_time: tudo + label_yesterday: ontem + label_this_week: esta semana + label_last_week: última semana + label_last_n_days: "últimos %{count} dias" + label_this_month: este mês + label_last_month: último mês + label_this_year: este ano + label_date_range: Período + label_less_than_ago: menos de + label_more_than_ago: mais de + label_ago: dias atrás + label_contains: contém + label_not_contains: não contém + label_day_plural: dias + label_repository: Repositório + label_repository_plural: Repositórios + label_browse: Procurar + label_revision: Revisão + label_revision_plural: Revisões + label_associated_revisions: Revisões associadas + label_added: adicionada + label_modified: alterada + label_deleted: excluída + label_latest_revision: Última revisão + label_latest_revision_plural: Últimas revisões + label_view_revisions: Ver revisões + label_max_size: Tamanho máximo + label_sort_highest: Mover para o início + label_sort_higher: Mover para cima + label_sort_lower: Mover para baixo + label_sort_lowest: Mover para o fim + label_roadmap: Planejamento + label_roadmap_due_in: "Previsto para %{value}" + label_roadmap_overdue: "%{value} atrasado" + label_roadmap_no_issues: Sem tarefas para esta versão + label_search: Busca + label_result_plural: Resultados + label_all_words: Todas as palavras + label_wiki: Wiki + label_wiki_edit: Editar Wiki + label_wiki_edit_plural: Edições Wiki + label_wiki_page: Página Wiki + label_wiki_page_plural: páginas Wiki + label_index_by_title: Índice por título + label_index_by_date: Índice por data + label_current_version: Versão atual + label_preview: Pré-visualizar + label_feed_plural: Feeds + label_changes_details: Detalhes de todas as alterações + label_issue_tracking: Tarefas + label_spent_time: Tempo gasto + label_f_hour: "%{value} hora" + label_f_hour_plural: "%{value} horas" + label_time_tracking: Registro de horas + label_change_plural: Alterações + label_statistics: Estatísticas + label_commits_per_month: Commits por mês + label_commits_per_author: Commits por autor + label_view_diff: Ver diferenças + label_diff_inline: inline + label_diff_side_by_side: lado a lado + label_options: Opções + label_copy_workflow_from: Copiar fluxo de trabalho de + label_permissions_report: Relatório de permissões + label_watched_issues: Tarefas observadas + label_related_issues: Tarefas relacionadas + label_applied_status: Situação alterada + label_loading: Carregando... + label_relation_new: Nova relação + label_relation_delete: Excluir relação + label_relates_to: relacionado a + label_duplicates: duplica + label_duplicated_by: duplicado por + label_blocks: bloqueia + label_blocked_by: bloqueado por + label_precedes: precede + label_follows: segue + label_end_to_start: fim para o início + label_end_to_end: fim para fim + label_start_to_start: início para início + label_start_to_end: início para fim + label_stay_logged_in: Permanecer logado + label_disabled: desabilitado + label_show_completed_versions: Exibir versões completas + label_me: mim + label_board: Fórum + label_board_new: Novo fórum + label_board_plural: Fóruns + label_topic_plural: Tópicos + label_message_plural: Mensagens + label_message_last: Última mensagem + label_message_new: Nova mensagem + label_message_posted: Mensagem enviada + label_reply_plural: Respostas + label_send_information: Enviar informação da nova conta para o usuário + label_year: Ano + label_month: Mês + label_week: Semana + label_date_from: De + label_date_to: Para + label_language_based: Com base no idioma do usuário + label_sort_by: "Ordenar por %{value}" + label_send_test_email: Enviar um e-mail de teste + label_feeds_access_key_created_on: "chave de acesso RSS criada %{value} atrás" + label_module_plural: Módulos + label_added_time_by: "Adicionado por %{author} %{age} atrás" + label_updated_time: "Atualizado %{value} atrás" + label_jump_to_a_project: Ir para o projeto... + label_file_plural: Arquivos + label_changeset_plural: Changesets + label_default_columns: Colunas padrão + label_no_change_option: (Sem alteração) + label_bulk_edit_selected_issues: Edição em massa das tarefas selecionados. + label_theme: Tema + label_default: Padrão + label_search_titles_only: Pesquisar somente títulos + label_user_mail_option_all: "Para qualquer evento em todos os meus projetos" + label_user_mail_option_selected: "Para qualquer evento somente no(s) projeto(s) selecionado(s)..." + label_user_mail_no_self_notified: "Eu não quero ser notificado de minhas próprias modificações" + label_registration_activation_by_email: ativação de conta por e-mail + label_registration_manual_activation: ativação manual de conta + label_registration_automatic_activation: ativação automática de conta + label_display_per_page: "Por página: %{value}" + label_age: Idade + label_change_properties: Alterar propriedades + label_general: Geral + label_more: Mais + label_scm: 'Controle de versão:' + label_plugins: Plugins + label_ldap_authentication: Autenticação LDAP + label_downloads_abbr: D/L + label_optional_description: Descrição opcional + label_add_another_file: Adicionar outro arquivo + label_preferences: Preferências + label_chronological_order: Em ordem cronológica + label_reverse_chronological_order: Em ordem cronológica inversa + label_planning: Planejamento + label_incoming_emails: E-mails recebidos + label_generate_key: Gerar uma chave + label_issue_watchers: Observadores + + button_login: Entrar + button_submit: Enviar + button_save: Salvar + button_check_all: Marcar todos + button_uncheck_all: Desmarcar todos + button_delete: Excluir + button_create: Criar + button_test: Testar + button_edit: Editar + button_add: Adicionar + button_change: Alterar + button_apply: Aplicar + button_clear: Limpar + button_lock: Bloquear + button_unlock: Desbloquear + button_download: Baixar + button_list: Listar + button_view: Ver + button_move: Mover + button_back: Voltar + button_cancel: Cancelar + button_activate: Ativar + button_sort: Ordenar + button_log_time: Tempo de trabalho + button_rollback: Voltar para esta versão + button_watch: Observar + button_unwatch: Parar de observar + button_reply: Responder + button_archive: Arquivar + button_unarchive: Desarquivar + button_reset: Redefinir + button_rename: Renomear + button_change_password: Alterar senha + button_copy: Copiar + button_annotate: Anotar + button_update: Atualizar + button_configure: Configurar + button_quote: Responder + + status_active: ativo + status_registered: registrado + status_locked: bloqueado + + text_select_mail_notifications: Ações a serem notificadas por e-mail + text_regexp_info: ex. ^[A-Z0-9]+$ + text_min_max_length_info: 0 = sem restrição + text_project_destroy_confirmation: Você tem certeza que deseja excluir este projeto e todos os dados relacionados? + text_subprojects_destroy_warning: "Seu(s) subprojeto(s): %{value} também serão excluídos." + text_workflow_edit: Selecione um papel e um tipo de tarefa para editar o fluxo de trabalho + text_are_you_sure: Você tem certeza? + text_tip_issue_begin_day: tarefa inicia neste dia + text_tip_issue_end_day: tarefa termina neste dia + text_tip_issue_begin_end_day: tarefa inicia e termina neste dia + text_caracters_maximum: "máximo %{count} caracteres" + text_caracters_minimum: "deve ter ao menos %{count} caracteres." + text_length_between: "deve ter entre %{min} e %{max} caracteres." + text_tracker_no_workflow: Sem fluxo de trabalho definido para este tipo. + text_unallowed_characters: Caracteres não permitidos + text_comma_separated: Múltiplos valores são permitidos (separados por vírgula). + text_issues_ref_in_commit_messages: Referenciando tarefas nas mensagens de commit + text_issue_added: "Tarefa %{id} incluída (por %{author})." + text_issue_updated: "Tarefa %{id} alterada (por %{author})." + text_wiki_destroy_confirmation: Você tem certeza que deseja excluir este wiki e TODO o seu conteúdo? + text_issue_category_destroy_question: "Algumas tarefas (%{count}) estão atribuídas a esta categoria. O que você deseja fazer?" + text_issue_category_destroy_assignments: Remover atribuições da categoria + text_issue_category_reassign_to: Redefinir tarefas para esta categoria + text_user_mail_option: "Para projetos (não selecionados), você somente receberá notificações sobre o que você está observando ou está envolvido (ex. tarefas das quais você é o autor ou que estão atribuídas a você)" + text_no_configuration_data: "Os Papéis, tipos de tarefas, situação de tarefas e fluxos de trabalho não foram configurados ainda.\nÉ altamente recomendado carregar as configurações padrão. Você poderá modificar estas configurações assim que carregadas." + text_load_default_configuration: Carregar a configuração padrão + text_status_changed_by_changeset: "Aplicado no changeset %{value}." + text_issues_destroy_confirmation: 'Você tem certeza que deseja excluir a(s) tarefa(s) selecionada(s)?' + text_select_project_modules: 'Selecione módulos para habilitar para este projeto:' + text_default_administrator_account_changed: Conta padrão do administrador alterada + text_file_repository_writable: Repositório com permissão de escrita + text_rmagick_available: RMagick disponível (opcional) + text_destroy_time_entries_question: "%{hours} horas de trabalho foram registradas nas tarefas que você está excluindo. O que você deseja fazer?" + text_destroy_time_entries: Excluir horas de trabalho + text_assign_time_entries_to_project: Atribuir estas horas de trabalho para outro projeto + text_reassign_time_entries: 'Atribuir horas reportadas para esta tarefa:' + text_user_wrote: "%{value} escreveu:" + text_enumeration_destroy_question: "%{count} objetos estão atribuídos a este valor." + text_enumeration_category_reassign_to: 'Reatribuí-los ao valor:' + text_email_delivery_not_configured: "O envio de e-mail não está configurado, e as notificações estão inativas.\nConfigure seu servidor SMTP no arquivo config/configuration.yml e reinicie a aplicação para ativá-las." + + default_role_manager: Gerente + default_role_developer: Desenvolvedor + default_role_reporter: Informante + default_tracker_bug: Defeito + default_tracker_feature: Funcionalidade + default_tracker_support: Suporte + default_issue_status_new: Nova + default_issue_status_in_progress: Em andamento + default_issue_status_resolved: Resolvida + default_issue_status_feedback: Feedback + default_issue_status_closed: Fechada + default_issue_status_rejected: Rejeitada + default_doc_category_user: Documentação do usuário + default_doc_category_tech: Documentação técnica + default_priority_low: Baixa + default_priority_normal: Normal + default_priority_high: Alta + default_priority_urgent: Urgente + default_priority_immediate: Imediata + default_activity_design: Design + default_activity_development: Desenvolvimento + + enumeration_issue_priorities: Prioridade das tarefas + enumeration_doc_categories: Categorias de documento + enumeration_activities: Atividades (registro de horas) + notice_unable_delete_version: Não foi possível excluir a versão + label_renamed: renomeado + label_copied: copiado + setting_plain_text_mail: Usar mensagem sem formatação HTML + permission_view_files: Ver arquivos + permission_edit_issues: Editar tarefas + permission_edit_own_time_entries: Editar o próprio tempo de trabalho + permission_manage_public_queries: Gerenciar consultas publicas + permission_add_issues: Adicionar tarefas + permission_log_time: Adicionar tempo gasto + permission_view_changesets: Ver changesets + permission_view_time_entries: Ver tempo gasto + permission_manage_versions: Gerenciar versões + permission_manage_wiki: Gerenciar wiki + permission_manage_categories: Gerenciar categorias de tarefas + permission_protect_wiki_pages: Proteger páginas wiki + permission_comment_news: Comentar notícias + permission_delete_messages: Excluir mensagens + permission_select_project_modules: Selecionar módulos de projeto + permission_edit_wiki_pages: Editar páginas wiki + permission_add_issue_watchers: Adicionar observadores + permission_view_gantt: Ver gráfico gantt + permission_move_issues: Mover tarefas + permission_manage_issue_relations: Gerenciar relacionamentos de tarefas + permission_delete_wiki_pages: Excluir páginas wiki + permission_manage_boards: Gerenciar fóruns + permission_delete_wiki_pages_attachments: Excluir anexos + permission_view_wiki_edits: Ver histórico do wiki + permission_add_messages: Postar mensagens + permission_view_messages: Ver mensagens + permission_manage_files: Gerenciar arquivos + permission_edit_issue_notes: Editar notas + permission_manage_news: Gerenciar notícias + permission_view_calendar: Ver calendário + permission_manage_members: Gerenciar membros + permission_edit_messages: Editar mensagens + permission_delete_issues: Excluir tarefas + permission_view_issue_watchers: Ver lista de observadores + permission_manage_repository: Gerenciar repositório + permission_commit_access: Acesso de commit + permission_browse_repository: Pesquisar repositório + permission_view_documents: Ver documentos + permission_edit_project: Editar projeto + permission_add_issue_notes: Adicionar notas + permission_save_queries: Salvar consultas + permission_view_wiki_pages: Ver wiki + permission_rename_wiki_pages: Renomear páginas wiki + permission_edit_time_entries: Editar tempo gasto + permission_edit_own_issue_notes: Editar suas próprias notas + setting_gravatar_enabled: Usar ícones do Gravatar + label_example: Exemplo + text_repository_usernames_mapping: "Seleciona ou atualiza os usuários do Redmine mapeando para cada usuário encontrado no log do repositório.\nUsuários com o mesmo login ou e-mail no Redmine e no repositório serão mapeados automaticamente." + permission_edit_own_messages: Editar próprias mensagens + permission_delete_own_messages: Excluir próprias mensagens + label_user_activity: "Atividade de %{value}" + label_updated_time_by: "Atualizado por %{author} há %{age}" + text_diff_truncated: '... Este diff foi truncado porque excede o tamanho máximo que pode ser exibido.' + setting_diff_max_lines_displayed: Número máximo de linhas exibidas no diff + text_plugin_assets_writable: Diretório de plugins gravável + warning_attachments_not_saved: "%{count} arquivo(s) não puderam ser salvo(s)." + button_create_and_continue: Criar e continuar + text_custom_field_possible_values_info: 'Uma linha para cada valor' + label_display: Exibição + field_editable: Editável + setting_repository_log_display_limit: Número máximo de revisões exibidas no arquivo de log + setting_file_max_size_displayed: Tamanho máximo dos arquivos textos exibidos inline + field_identity_urler: Observador + setting_openid: Permitir Login e Registro via OpenID + field_identity_url: OpenID URL + label_login_with_open_id_option: ou use o OpenID + field_content: Conteúdo + label_descending: Descendente + label_sort: Ordenar + label_ascending: Ascendente + label_date_from_to: De %{start} até %{end} + label_greater_or_equal: ">=" + label_less_or_equal: <= + text_wiki_page_destroy_question: Esta página tem %{descendants} página(s) filha(s) e descendente(s). O que você quer fazer? + text_wiki_page_reassign_children: Reatribuir páginas filhas para esta página pai + text_wiki_page_nullify_children: Manter as páginas filhas como páginas raízes + text_wiki_page_destroy_children: Excluir páginas filhas e todas suas descendentes + setting_password_min_length: Comprimento mínimo para senhas + field_group_by: Agrupar por + mail_subject_wiki_content_updated: "A página wiki '%{id}' foi atualizada" + label_wiki_content_added: Página wiki adicionada + mail_subject_wiki_content_added: "A página wiki '%{id}' foi adicionada" + mail_body_wiki_content_added: A página wiki '%{id}' foi adicionada por %{author}. + label_wiki_content_updated: Página wiki atualizada + mail_body_wiki_content_updated: A página wiki '%{id}' foi atualizada por %{author}. + permission_add_project: Criar projeto + setting_new_project_user_role_id: Papel atribuído a um usuário não-administrador que cria um projeto + label_view_all_revisions: Ver todas as revisões + label_tag: Etiqueta + label_branch: Ramo + text_journal_changed: "%{label} alterado de %{old} para %{new}" + text_journal_set_to: "%{label} ajustado para %{value}" + text_journal_deleted: "%{label} excluído (%{old})" + label_group_plural: Grupos + label_group: Grupo + label_group_new: Novo grupo + label_time_entry_plural: Tempos gastos + text_journal_added: "%{label} %{value} adicionado" + field_active: Ativo + enumeration_system_activity: Atividade do sistema + permission_delete_issue_watchers: Excluir observadores + version_status_closed: fechado + version_status_locked: travado + version_status_open: aberto + error_can_not_reopen_issue_on_closed_version: Uma tarefa atribuída a uma versão fechada não pode ser reaberta + label_user_anonymous: Anônimo + button_move_and_follow: Mover e seguir + setting_default_projects_modules: Módulos habilitados por padrão para novos projetos + setting_gravatar_default: Imagem-padrão de Gravatar + field_sharing: Compartilhamento + label_version_sharing_hierarchy: Com a hierarquia do projeto + label_version_sharing_system: Com todos os projetos + label_version_sharing_descendants: Com sub-projetos + label_version_sharing_tree: Com a árvore do projeto + label_version_sharing_none: Sem compartilhamento + error_can_not_archive_project: Este projeto não pode ser arquivado + button_duplicate: Duplicar + button_copy_and_follow: Copiar e seguir + label_copy_source: Origem + setting_issue_done_ratio: Calcular o percentual de conclusão da tarefa + setting_issue_done_ratio_issue_status: Usar a situação da tarefa + error_issue_done_ratios_not_updated: O percentual de conclusão das tarefas não foi atualizado. + error_workflow_copy_target: Por favor, selecione os tipos de tarefa e os papéis alvo + setting_issue_done_ratio_issue_field: Use o campo da tarefa + label_copy_same_as_target: Mesmo alvo + label_copy_target: Alvo + notice_issue_done_ratios_updated: Percentual de conclusão atualizados. + error_workflow_copy_source: Por favor, selecione um tipo de tarefa e papel de origem + label_update_issue_done_ratios: Atualizar percentual de conclusão das tarefas + setting_start_of_week: Início da semana + field_watcher: Observador + permission_view_issues: Ver tarefas + label_display_used_statuses_only: Somente exibir situações que são usadas por este tipo de tarefa + label_revision_id: Revisão %{value} + label_api_access_key: Chave de acesso a API + button_show: Exibir + label_api_access_key_created_on: Chave de acesso a API criado a %{value} atrás + label_feeds_access_key: Chave de acesso ao RSS + notice_api_access_key_reseted: Sua chave de acesso a API foi redefinida. + setting_rest_api_enabled: Habilitar a api REST + label_missing_api_access_key: Chave de acesso a API faltando + label_missing_feeds_access_key: Chave de acesso ao RSS faltando + text_line_separated: Múltiplos valores permitidos (uma linha para cada valor). + setting_mail_handler_body_delimiters: Truncar e-mails após uma destas linhas + permission_add_subprojects: Criar subprojetos + label_subproject_new: Novo subprojeto + text_own_membership_delete_confirmation: |- + Você está para excluir algumas de suas próprias permissões e pode não mais estar apto a editar este projeto após esta operação. + Você tem certeza que deseja continuar? + label_close_versions: Fechar versões concluídas + label_board_sticky: Marcado + label_board_locked: Travado + permission_export_wiki_pages: Exportar páginas wiki + setting_cache_formatted_text: Realizar cache de texto formatado + permission_manage_project_activities: Gerenciar atividades do projeto + error_unable_delete_issue_status: Não foi possível excluir situação da tarefa + label_profile: Perfil + permission_manage_subtasks: Gerenciar sub-tarefas + field_parent_issue: Tarefa pai + label_subtask_plural: Subtarefas + label_project_copy_notifications: Enviar notificações por e-mail ao copiar projeto + error_can_not_delete_custom_field: Não foi possível excluir o campo personalizado + error_unable_to_connect: Não foi possível conectar (%{value}) + error_can_not_remove_role: Este papel está em uso e não pode ser excluído. + error_can_not_delete_tracker: Este tipo de tarefa está atribuído a alguma(s) tarefa(s) e não pode ser excluído. + field_principal: Principal + label_my_page_block: Meu bloco de página + notice_failed_to_save_members: "Falha ao gravar membro(s): %{errors}." + text_zoom_out: Afastar zoom + text_zoom_in: Aproximar zoom + notice_unable_delete_time_entry: Não foi possível excluir a entrada no registro de horas trabalhadas. + label_overall_spent_time: Tempo gasto geral + field_time_entries: Registro de horas + project_module_gantt: Gantt + project_module_calendar: Calendário + button_edit_associated_wikipage: "Editar página wiki relacionada: %{page_title}" + field_text: Campo de texto + label_user_mail_option_only_owner: Somente para as coisas que eu criei + setting_default_notification_option: Opção padrão de notificação + label_user_mail_option_only_my_events: Somente para as coisas que eu esteja observando ou esteja envolvido + label_user_mail_option_only_assigned: Somente para as coisas que estejam atribuídas a mim + label_user_mail_option_none: Sem eventos + field_member_of_group: Grupo do responsável + field_assigned_to_role: Papel do responsável + notice_not_authorized_archived_project: O projeto que você está tentando acessar foi arquivado. + label_principal_search: "Pesquisar por usuários ou grupos:" + label_user_search: "Pesquisar por usuário:" + field_visible: Visível + setting_emails_header: Cabeçalho do e-mail + setting_commit_logtime_activity_id: Atividade para registrar horas + text_time_logged_by_changeset: Aplicado no changeset %{value}. + setting_commit_logtime_enabled: Habilitar registro de horas + notice_gantt_chart_truncated: O gráfico foi cortado por exceder o tamanho máximo de linhas que podem ser exibidas (%{max}) + setting_gantt_items_limit: Número máximo de itens exibidos no gráfico gatt + field_warn_on_leaving_unsaved: Alertar-me ao sair de uma página sem salvar o texto + text_warn_on_leaving_unsaved: A página atual contem texto que não foi salvo e será perdido se você sair desta página. + label_my_queries: Minhas consultas personalizadas + text_journal_changed_no_detail: "%{label} atualizado(a)" + label_news_comment_added: Notícia recebeu um comentário + button_expand_all: Expandir tudo + button_collapse_all: Recolher tudo + label_additional_workflow_transitions_for_assignee: Transições adicionais permitidas quando o usuário é o responsável pela tarefa + label_additional_workflow_transitions_for_author: Transições adicionais permitidas quando o usuário é o autor + + label_bulk_edit_selected_time_entries: Alteração em massa do registro de horas + text_time_entries_destroy_confirmation: Tem certeza que quer excluir o(s) registro(s) de horas selecionado(s)? + label_role_anonymous: Anônimo + label_role_non_member: Não Membro + label_issues_visibility_own: Tarefas criadas ou atribuídas ao usuário + field_issues_visibility: Visibilidade das tarefas + label_issues_visibility_all: Todas as tarefas + permission_set_own_issues_private: Alterar as próprias tarefas para públicas ou privadas + field_is_private: Privado + permission_set_issues_private: Alterar tarefas para públicas ou privadas + label_issues_visibility_public: Todas as tarefas não privadas + text_issues_destroy_descendants_confirmation: Isto também irá excluir %{count} subtarefa(s). + field_commit_logs_encoding: Codificação das mensagens de commit + field_scm_path_encoding: Codificação do caminho + text_scm_path_encoding_note: "Padrão: UTF-8" + field_path_to_repository: Caminho para o repositório + field_root_directory: Diretório raiz + field_cvs_module: Módulo + field_cvsroot: CVSROOT + text_mercurial_repository_note: "Repositório local (ex.: /hgrepo, c:\\hgrepo)" + text_scm_command: Comando + text_scm_command_version: Versão + label_git_report_last_commit: Relatar última alteração para arquivos e diretórios + text_scm_config: Você pode configurar seus comandos de versionamento em config/configurations.yml. Por favor reinicie a aplicação após alterá-lo. + text_scm_command_not_available: Comando de versionamento não disponível. Por favor verifique as configurações no painel de administração. + notice_issue_successful_create: Tarefa %{id} criada. + label_between: entre + setting_issue_group_assignment: Permitir atribuições de tarefas a grupos + label_diff: diff + text_git_repository_note: "Repositório esta vazio e é local (ex: /gitrepo, c:\\gitrepo)" + + description_query_sort_criteria_direction: Direção da ordenação + description_project_scope: Escopo da pesquisa + description_filter: Filtro + description_user_mail_notification: Configuração de notificações por e-mail + description_date_from: Digita a data inicial + description_message_content: Conteúdo da mensagem + description_available_columns: Colunas disponíveis + description_date_range_interval: Escolha um período selecionando a data de início e fim + description_issue_category_reassign: Escolha uma categoria de tarefas + description_search: Searchfield + description_notes: Notas + description_date_range_list: Escolha um período a partira da lista + description_choose_project: Projetos + description_date_to: Digite a data final + description_query_sort_criteria_attribute: Atributo de ordenação + description_wiki_subpages_reassign: Escolha uma nova página pai + description_selected_columns: Colunas selecionadas + + label_parent_revision: Pais + label_child_revision: Filhos + error_scm_annotate_big_text_file: A entrada não pode ser anotada, pois excede o tamanho máximo do arquivo de texto. + setting_default_issue_start_date_to_creation_date: Usar data corrente como data inicial para novas tarefas + button_edit_section: Editar esta seção + setting_repositories_encodings: Encoding dos repositórios e anexos + description_all_columns: Todas as colunas + button_export: Exportar + label_export_options: "Opções de exportação %{export_format}" + error_attachment_too_big: Este arquivo não pode ser enviado porque excede o tamanho máximo permitido (%{max_size}) + notice_failed_to_save_time_entries: "Falha ao salvar %{count} de %{total} horas trabalhadas: %{ids}." + label_x_issues: + zero: 0 tarefa + one: 1 tarefa + other: "%{count} tarefas" + label_repository_new: Novo repositório + field_repository_is_default: Repositório principal + label_copy_attachments: Copiar anexos + label_item_position: "%{position}/%{count}" + label_completed_versions: Versões completadas + text_project_identifier_info: Somente letras minúsculas (az), números, traços e sublinhados são permitidos.
    Uma vez salvo, o identificador não pode ser alterado. + field_multiple: Multiplos valores + setting_commit_cross_project_ref: Permitir que tarefas de todos os outros projetos sejam refenciadas e resolvidas + text_issue_conflict_resolution_add_notes: Adicione minhas anotações e descartar minhas outras mudanças + text_issue_conflict_resolution_overwrite: Aplicar as minhas alterações de qualquer maneira (notas anteriores serão mantidos, mas algumas mudanças podem ser substituídos) + notice_issue_update_conflict: A tarefa foi atualizada por um outro usuário, enquanto você estava editando. + text_issue_conflict_resolution_cancel: Descartar todas as minhas mudanças e re-exibir %{link} + permission_manage_related_issues: Gerenciar tarefas relacionadas + field_auth_source_ldap_filter: Filtro LDAP + label_search_for_watchers: Procurar por outros observadores para adiconar + notice_account_deleted: Sua conta foi excluída permanentemente. + setting_unsubscribe: Permitir aos usuários excluir sua conta própria + button_delete_my_account: Excluir minha conta + text_account_destroy_confirmation: |- + Tem certeza de que quer continuar? + Sua conta será excluída permanentemente, sem qualquer forma de reativá-lo. + error_session_expired: A sua sessão expirou. Por favor, faça login novamente. + text_session_expiration_settings: "Aviso: a alteração dessas configurações pode expirar as sessões atuais, incluindo a sua." + setting_session_lifetime: duração máxima da sessão + setting_session_timeout: tempo limite de inatividade da sessão + label_session_expiration: "Expiração da sessão" + permission_close_project: Fechar / reabrir o projeto + label_show_closed_projects: Visualização de projetos fechados + button_close: Fechar + button_reopen: Reabrir + project_status_active: ativo + project_status_closed: fechado + project_status_archived: arquivado + text_project_closed: Este projeto é fechado e somente leitura. + notice_user_successful_create: Usuário %{id} criado. + field_core_fields: campos padrão + field_timeout: Tempo de espera (em segundos) + setting_thumbnails_enabled: Exibir miniaturas de anexos + setting_thumbnails_size: Tamanho das miniaturas (em pixels) + label_status_transitions: Estados das transições + label_fields_permissions: Permissões de campos + label_readonly: somente leitura + label_required: Obrigatório + text_repository_identifier_info: Somente letras minúsculas (az), números, traços e sublinhados são permitidos
    Uma vez salvo, o identificador não pode ser alterado. + field_board_parent: Fórum Pai + label_attribute_of_project: "Projeto %{name}" + label_attribute_of_author: "autor %{name}" + label_attribute_of_assigned_to: "atribuído %{name}" + label_attribute_of_fixed_version: "versão alvo %{name}" + label_copy_subtasks: Copiar sub-tarefas + label_copied_to: copiada + label_copied_from: copiado + label_any_issues_in_project: quaisquer problemas em projeto + label_any_issues_not_in_project: todas as questões que não estão em projeto + field_private_notes: notas privadas + permission_view_private_notes: Ver notas privadas + permission_set_notes_private: Permitir alterar notas para privada + label_no_issues_in_project: sem problemas em projeto + label_any: todos + label_last_n_weeks: "últimas %{count} semanas" + setting_cross_project_subtasks: Permitir cruzamento de sub-tarefas entre projetos + label_cross_project_descendants: com sub-Projetos + label_cross_project_tree: Com uma Árvore fazer o Projeto + label_cross_project_hierarchy: Com uma hierarquia fazer o Projeto + label_cross_project_system: Com de Todos os Projetos + button_hide: Esconder + setting_non_working_week_days: dias não úteis + label_in_the_next_days: na próxima + label_in_the_past_days: no passado + label_attribute_of_user: Usuário %{name} + text_turning_multiple_off: Se você desativar vários valores, vários valores serão removidas, a fim de preservar a somente um valor por item. + label_attribute_of_issue: Emissão de %{name} + permission_add_documents: Adicionar documentos + permission_edit_documents: Editar documentos + permission_delete_documents: excluir documentos + label_gantt_progress_line: Linha de progresso + setting_jsonp_enabled: Ativar suporte JSONP + field_inherit_members: Herdar membros + field_closed_on: Fechado + setting_default_projects_tracker_ids: Default trackers for new projects + label_total_time: Total diff --git a/config/locales/pt.yml b/config/locales/pt.yml new file mode 100644 index 00000000..5deff0a6 --- /dev/null +++ b/config/locales/pt.yml @@ -0,0 +1,1095 @@ +# Portuguese localization for Ruby on Rails +# by Ricardo Otero +# by Alberto Ferreira +# by Rui Rebelo +pt: + support: + array: + sentence_connector: "e" + skip_last_comma: true + + direction: ltr + date: + formats: + default: "%d/%m/%Y" + short: "%d de %B" + long: "%d de %B de %Y" + only_day: "%d" + day_names: [Domingo, Segunda, Terça, Quarta, Quinta, Sexta, Sábado] + abbr_day_names: [Dom, Seg, Ter, Qua, Qui, Sex, Sáb] + month_names: [~, Janeiro, Fevereiro, Março, Abril, Maio, Junho, Julho, Agosto, Setembro, Outubro, Novembro, Dezembro] + abbr_month_names: [~, Jan, Fev, Mar, Abr, Mai, Jun, Jul, Ago, Set, Out, Nov, Dez] + order: + - :day + - :month + - :year + + time: + formats: + default: "%A, %d de %B de %Y, %H:%Mh" + time: "%H:%M" + short: "%d/%m, %H:%M hs" + long: "%A, %d de %B de %Y, %H:%Mh" + am: '' + pm: '' + + datetime: + distance_in_words: + half_a_minute: "meio minuto" + less_than_x_seconds: + one: "menos de 1 segundo" + other: "menos de %{count} segundos" + x_seconds: + one: "1 segundo" + other: "%{count} segundos" + less_than_x_minutes: + one: "menos de um minuto" + other: "menos de %{count} minutos" + x_minutes: + one: "1 minuto" + other: "%{count} minutos" + about_x_hours: + one: "aproximadamente 1 hora" + other: "aproximadamente %{count} horas" + x_hours: + one: "1 hora" + other: "%{count} horas" + x_days: + one: "1 dia" + other: "%{count} dias" + about_x_months: + one: "aproximadamente 1 mês" + other: "aproximadamente %{count} meses" + x_months: + one: "1 mês" + other: "%{count} meses" + about_x_years: + one: "aproximadamente 1 ano" + other: "aproximadamente %{count} anos" + over_x_years: + one: "mais de 1 ano" + other: "mais de %{count} anos" + almost_x_years: + one: "quase 1 ano" + other: "quase %{count} anos" + + number: + format: + precision: 3 + separator: ',' + delimiter: '.' + currency: + format: + unit: '€' + precision: 2 + format: "%u %n" + separator: ',' + delimiter: '.' + percentage: + format: + delimiter: '' + precision: + format: + delimiter: '' + human: + format: + precision: 3 + delimiter: '' + storage_units: + format: "%n %u" + units: + byte: + one: "Byte" + other: "Bytes" + kb: "KB" + mb: "MB" + gb: "GB" + tb: "TB" + + activerecord: + errors: + template: + header: + one: "Não foi possível guardar %{model}: 1 erro" + other: "Não foi possível guardar %{model}: %{count} erros" + body: "Por favor, verifique os seguintes campos:" + messages: + inclusion: "não está incluído na lista" + exclusion: "não está disponível" + invalid: "não é válido" + confirmation: "não está de acordo com a confirmação" + accepted: "precisa de ser aceite" + empty: "não pode estar em branco" + blank: "não pode estar em branco" + too_long: "tem demasiados caracteres (máximo: %{count} caracteres)" + too_short: "tem poucos caracteres (mínimo: %{count} caracteres)" + wrong_length: "não é do tamanho correcto (necessita de ter %{count} caracteres)" + taken: "não está disponível" + not_a_number: "não é um número" + greater_than: "tem de ser maior do que %{count}" + greater_than_or_equal_to: "tem de ser maior ou igual a %{count}" + equal_to: "tem de ser igual a %{count}" + less_than: "tem de ser menor do que %{count}" + less_than_or_equal_to: "tem de ser menor ou igual a %{count}" + odd: "tem de ser ímpar" + even: "tem de ser par" + greater_than_start_date: "deve ser maior que a data inicial" + not_same_project: "não pertence ao mesmo projecto" + circular_dependency: "Esta relação iria criar uma dependência circular" + cant_link_an_issue_with_a_descendant: "Não é possível ligar uma tarefa a uma sub-tarefa que lhe é pertencente" + + ## Translated by: Pedro Araújo + actionview_instancetag_blank_option: Seleccione + + general_text_No: 'Não' + general_text_Yes: 'Sim' + general_text_no: 'não' + general_text_yes: 'sim' + general_lang_name: 'Português' + general_csv_separator: ';' + general_csv_decimal_separator: ',' + general_csv_encoding: ISO-8859-15 + general_pdf_encoding: UTF-8 + general_first_day_of_week: '1' + + notice_account_updated: A conta foi actualizada com sucesso. + notice_account_invalid_creditentials: Utilizador ou palavra-chave inválidos. + notice_account_password_updated: A palavra-chave foi alterada com sucesso. + notice_account_wrong_password: Palavra-chave errada. + notice_account_register_done: A conta foi criada com sucesso. + notice_account_unknown_email: Utilizador desconhecido. + notice_can_t_change_password: Esta conta utiliza uma fonte de autenticação externa. Não é possível alterar a palavra-chave. + notice_account_lost_email_sent: Foi-lhe enviado um e-mail com as instruções para escolher uma nova palavra-chave. + notice_account_activated: A sua conta foi activada. É agora possível autenticar-se. + notice_successful_create: Criado com sucesso. + notice_successful_update: Alterado com sucesso. + notice_successful_delete: Apagado com sucesso. + notice_successful_connection: Ligado com sucesso. + notice_file_not_found: A página que está a tentar aceder não existe ou foi removida. + notice_locking_conflict: Os dados foram actualizados por outro utilizador. + notice_not_authorized: Não está autorizado a visualizar esta página. + notice_email_sent: "Foi enviado um e-mail para %{value}" + notice_email_error: "Ocorreu um erro ao enviar o e-mail (%{value})" + notice_feeds_access_key_reseted: A sua chave de RSS foi inicializada. + notice_failed_to_save_issues: "Não foi possível guardar %{count} tarefa(s) das %{total} seleccionadas: %{ids}." + notice_no_issue_selected: "Nenhuma tarefa seleccionada! Por favor, seleccione as tarefas que quer editar." + notice_account_pending: "A sua conta foi criada e está agora à espera de aprovação do administrador." + notice_default_data_loaded: Configuração padrão carregada com sucesso. + notice_unable_delete_version: Não foi possível apagar a versão. + + error_can_t_load_default_data: "Não foi possível carregar a configuração padrão: %{value}" + error_scm_not_found: "A entrada ou revisão não foi encontrada no repositório." + error_scm_command_failed: "Ocorreu um erro ao tentar aceder ao repositório: %{value}" + error_scm_annotate: "A entrada não existe ou não pode ser anotada." + error_issue_not_found_in_project: 'A tarefa não foi encontrada ou não pertence a este projecto.' + + mail_subject_lost_password: "Palavra-chave de %{value}" + mail_body_lost_password: 'Para mudar a sua palavra-chave, clique na ligação abaixo:' + mail_subject_register: "Activação de conta de %{value}" + mail_body_register: 'Para activar a sua conta, clique na ligação abaixo:' + mail_body_account_information_external: "Pode utilizar a conta %{value} para autenticar-se." + mail_body_account_information: Informação da sua conta + mail_subject_account_activation_request: "Pedido de activação da conta %{value}" + mail_body_account_activation_request: "Um novo utilizador (%{value}) registou-se. A sua conta está à espera de aprovação:" + mail_subject_reminder: "%{count} tarefa(s) para entregar nos próximos %{days} dias" + mail_body_reminder: "%{count} tarefa(s) que estão atribuídas a si estão agendadas para estarem completas nos próximos %{days} dias:" + + + field_name: Nome + field_description: Descrição + field_summary: Sumário + field_is_required: Obrigatório + field_firstname: Nome + field_lastname: Apelido + field_mail: E-mail + field_filename: Ficheiro + field_filesize: Tamanho + field_downloads: Downloads + field_author: Autor + field_created_on: Criado + field_updated_on: Alterado + field_field_format: Formato + field_is_for_all: Para todos os projectos + field_possible_values: Valores possíveis + field_regexp: Expressão regular + field_min_length: Tamanho mínimo + field_max_length: Tamanho máximo + field_value: Valor + field_category: Categoria + field_title: Título + field_project: Projecto + field_issue: Tarefa + field_status: Estado + field_notes: Notas + field_is_closed: Tarefa fechada + field_is_default: Valor por omissão + field_tracker: Tipo + field_subject: Assunto + field_due_date: Data fim + field_assigned_to: Atribuído a + field_priority: Prioridade + field_fixed_version: Versão + field_user: Utilizador + field_role: Função + field_homepage: Página + field_is_public: Público + field_parent: Sub-projecto de + field_is_in_roadmap: Tarefas mostradas no mapa de planificação + field_login: Nome de utilizador + field_mail_notification: Notificações por e-mail + field_admin: Administrador + field_last_login_on: Última visita + field_language: Língua + field_effective_date: Data + field_password: Palavra-chave + field_new_password: Nova palavra-chave + field_password_confirmation: Confirmação + field_version: Versão + field_type: Tipo + field_host: Servidor + field_port: Porta + field_account: Conta + field_base_dn: Base DN + field_attr_login: Atributo utilizador + field_attr_firstname: Atributo nome próprio + field_attr_lastname: Atributo último nome + field_attr_mail: Atributo e-mail + field_onthefly: Criação imediata de utilizadores + field_start_date: Data início + field_done_ratio: "% Completo" + field_auth_source: Modo de autenticação + field_hide_mail: Esconder endereço de e-mail + field_comments: Comentário + field_url: URL + field_start_page: Página inicial + field_subproject: Subprojecto + field_hours: Horas + field_activity: Actividade + field_spent_on: Data + field_identifier: Identificador + field_is_filter: Usado como filtro + field_issue_to: Tarefa relacionada + field_delay: Atraso + field_assignable: As tarefas podem ser associadas a esta função + field_redirect_existing_links: Redireccionar ligações existentes + field_estimated_hours: Tempo estimado + field_column_names: Colunas + field_time_zone: Fuso horário + field_searchable: Procurável + field_default_value: Valor por omissão + field_comments_sorting: Mostrar comentários + field_parent_title: Página pai + + setting_app_title: Título da aplicação + setting_app_subtitle: Sub-título da aplicação + setting_welcome_text: Texto de boas vindas + setting_default_language: Língua por omissão + setting_login_required: Autenticação obrigatória + setting_self_registration: Auto-registo + setting_attachment_max_size: Tamanho máximo do anexo + setting_issues_export_limit: Limite de exportação das tarefas + setting_mail_from: E-mail enviado de + setting_bcc_recipients: Recipientes de BCC + setting_host_name: Hostname + setting_text_formatting: Formatação do texto + setting_wiki_compression: Compressão do histórico do Wiki + setting_feeds_limit: Limite de conteúdo do feed + setting_default_projects_public: Projectos novos são públicos por omissão + setting_autofetch_changesets: Buscar automaticamente commits + setting_sys_api_enabled: Activar Web Service para gestão do repositório + setting_commit_ref_keywords: Palavras-chave de referência + setting_commit_fix_keywords: Palavras-chave de fecho + setting_autologin: Login automático + setting_date_format: Formato da data + setting_time_format: Formato do tempo + setting_cross_project_issue_relations: Permitir relações entre tarefas de projectos diferentes + setting_issue_list_default_columns: Colunas na lista de tarefas por omissão + setting_emails_footer: Rodapé do e-mails + setting_protocol: Protocolo + setting_per_page_options: Opções de objectos por página + setting_user_format: Formato de apresentaão de utilizadores + setting_activity_days_default: Dias mostrados na actividade do projecto + setting_display_subprojects_issues: Mostrar as tarefas dos sub-projectos nos projectos principais + setting_enabled_scm: Activar SCM + setting_mail_handler_api_enabled: Activar Web Service para e-mails recebidos + setting_mail_handler_api_key: Chave da API + setting_sequential_project_identifiers: Gerar identificadores de projecto sequênciais + + project_module_issue_tracking: Tarefas + project_module_time_tracking: Registo de tempo + project_module_news: Notícias + project_module_documents: Documentos + project_module_files: Ficheiros + project_module_wiki: Wiki + project_module_repository: Repositório + project_module_boards: Forum + + label_user: Utilizador + label_user_plural: Utilizadores + label_user_new: Novo utilizador + label_project: Projecto + label_project_new: Novo projecto + label_project_plural: Projectos + label_x_projects: + zero: no projects + one: 1 project + other: "%{count} projects" + label_project_all: Todos os projectos + label_project_latest: Últimos projectos + label_issue: Tarefa + label_issue_new: Nova tarefa + label_issue_plural: Tarefas + label_issue_view_all: Ver todas as tarefas + label_issues_by: "Tarefas por %{value}" + label_issue_added: Tarefa adicionada + label_issue_updated: Tarefa actualizada + label_document: Documento + label_document_new: Novo documento + label_document_plural: Documentos + label_document_added: Documento adicionado + label_role: Função + label_role_plural: Funções + label_role_new: Nova função + label_role_and_permissions: Funções e permissões + label_member: Membro + label_member_new: Novo membro + label_member_plural: Membros + label_tracker: Tipo + label_tracker_plural: Tipos + label_tracker_new: Novo tipo + label_workflow: Fluxo de trabalho + label_issue_status: Estado da tarefa + label_issue_status_plural: Estados da tarefa + label_issue_status_new: Novo estado + label_issue_category: Categoria de tarefa + label_issue_category_plural: Categorias de tarefa + label_issue_category_new: Nova categoria + label_custom_field: Campo personalizado + label_custom_field_plural: Campos personalizados + label_custom_field_new: Novo campo personalizado + label_enumerations: Enumerações + label_enumeration_new: Novo valor + label_information: Informação + label_information_plural: Informações + label_please_login: Por favor autentique-se + label_register: Registar + label_password_lost: Perdi a palavra-chave + label_home: Página Inicial + label_my_page: Página Pessoal + label_my_account: Minha conta + label_my_projects: Meus projectos + label_administration: Administração + label_login: Entrar + label_logout: Sair + label_help: Ajuda + label_reported_issues: Tarefas criadas + label_assigned_to_me_issues: Tarefas atribuídas a mim + label_last_login: Último acesso + label_registered_on: Registado em + label_activity: Actividade + label_overall_activity: Actividade geral + label_new: Novo + label_logged_as: Ligado como + label_environment: Ambiente + label_authentication: Autenticação + label_auth_source: Modo de autenticação + label_auth_source_new: Novo modo de autenticação + label_auth_source_plural: Modos de autenticação + label_subproject_plural: Sub-projectos + label_and_its_subprojects: "%{value} e sub-projectos" + label_min_max_length: Tamanho mínimo-máximo + label_list: Lista + label_date: Data + label_integer: Inteiro + label_float: Decimal + label_boolean: Booleano + label_string: Texto + label_text: Texto longo + label_attribute: Atributo + label_attribute_plural: Atributos + label_no_data: Sem dados para mostrar + label_change_status: Mudar estado + label_history: Histórico + label_attachment: Ficheiro + label_attachment_new: Novo ficheiro + label_attachment_delete: Apagar ficheiro + label_attachment_plural: Ficheiros + label_file_added: Ficheiro adicionado + label_report: Relatório + label_report_plural: Relatórios + label_news: Notícia + label_news_new: Nova notícia + label_news_plural: Notícias + label_news_latest: Últimas notícias + label_news_view_all: Ver todas as notícias + label_news_added: Notícia adicionada + label_settings: Configurações + label_overview: Visão geral + label_version: Versão + label_version_new: Nova versão + label_version_plural: Versões + label_confirmation: Confirmação + label_export_to: 'Também disponível em:' + label_read: Ler... + label_public_projects: Projectos públicos + label_open_issues: aberto + label_open_issues_plural: abertos + label_closed_issues: fechado + label_closed_issues_plural: fechados + label_x_open_issues_abbr_on_total: + zero: 0 abertas / %{total} + one: 1 aberta / %{total} + other: "%{count} abertas / %{total}" + label_x_open_issues_abbr: + zero: 0 abertas + one: 1 aberta + other: "%{count} abertas" + label_x_closed_issues_abbr: + zero: 0 fechadas + one: 1 fechada + other: "%{count} fechadas" + label_total: Total + label_permissions: Permissões + label_current_status: Estado actual + label_new_statuses_allowed: Novos estados permitidos + label_all: todos + label_none: nenhum + label_nobody: ninguém + label_next: Próximo + label_previous: Anterior + label_used_by: Usado por + label_details: Detalhes + label_add_note: Adicionar nota + label_per_page: Por página + label_calendar: Calendário + label_months_from: meses de + label_gantt: Gantt + label_internal: Interno + label_last_changes: "últimas %{count} alterações" + label_change_view_all: Ver todas as alterações + label_personalize_page: Personalizar esta página + label_comment: Comentário + label_comment_plural: Comentários + label_x_comments: + zero: sem comentários + one: 1 comentário + other: "%{count} comentários" + label_comment_add: Adicionar comentário + label_comment_added: Comentário adicionado + label_comment_delete: Apagar comentários + label_query: Consulta personalizada + label_query_plural: Consultas personalizadas + label_query_new: Nova consulta + label_filter_add: Adicionar filtro + label_filter_plural: Filtros + label_equals: é + label_not_equals: não é + label_in_less_than: em menos de + label_in_more_than: em mais de + label_in: em + label_today: hoje + label_all_time: sempre + label_yesterday: ontem + label_this_week: esta semana + label_last_week: semana passada + label_last_n_days: "últimos %{count} dias" + label_this_month: este mês + label_last_month: mês passado + label_this_year: este ano + label_date_range: Date range + label_less_than_ago: menos de dias atrás + label_more_than_ago: mais de dias atrás + label_ago: dias atrás + label_contains: contém + label_not_contains: não contém + label_day_plural: dias + label_repository: Repositório + label_repository_plural: Repositórios + label_browse: Navegar + label_revision: Revisão + label_revision_plural: Revisões + label_associated_revisions: Revisões associadas + label_added: adicionado + label_modified: modificado + label_copied: copiado + label_renamed: renomeado + label_deleted: apagado + label_latest_revision: Última revisão + label_latest_revision_plural: Últimas revisões + label_view_revisions: Ver revisões + label_max_size: Tamanho máximo + label_sort_highest: Mover para o início + label_sort_higher: Mover para cima + label_sort_lower: Mover para baixo + label_sort_lowest: Mover para o fim + label_roadmap: Planificação + label_roadmap_due_in: "Termina em %{value}" + label_roadmap_overdue: "Atrasado %{value}" + label_roadmap_no_issues: Sem tarefas para esta versão + label_search: Procurar + label_result_plural: Resultados + label_all_words: Todas as palavras + label_wiki: Wiki + label_wiki_edit: Edição da Wiki + label_wiki_edit_plural: Edições da Wiki + label_wiki_page: Página da Wiki + label_wiki_page_plural: Páginas da Wiki + label_index_by_title: Índice por título + label_index_by_date: Índice por data + label_current_version: Versão actual + label_preview: Pré-visualizar + label_feed_plural: Feeds + label_changes_details: Detalhes de todas as mudanças + label_issue_tracking: Tarefas + label_spent_time: Tempo gasto + label_f_hour: "%{value} hora" + label_f_hour_plural: "%{value} horas" + label_time_tracking: Registo de tempo + label_change_plural: Mudanças + label_statistics: Estatísticas + label_commits_per_month: Commits por mês + label_commits_per_author: Commits por autor + label_view_diff: Ver diferenças + label_diff_inline: inline + label_diff_side_by_side: lado a lado + label_options: Opções + label_copy_workflow_from: Copiar fluxo de trabalho de + label_permissions_report: Relatório de permissões + label_watched_issues: Tarefas observadas + label_related_issues: Tarefas relacionadas + label_applied_status: Estado aplicado + label_loading: A carregar... + label_relation_new: Nova relação + label_relation_delete: Apagar relação + label_relates_to: relacionado a + label_duplicates: duplica + label_duplicated_by: duplicado por + label_blocks: bloqueia + label_blocked_by: bloqueado por + label_precedes: precede + label_follows: segue + label_end_to_start: fim a início + label_end_to_end: fim a fim + label_start_to_start: início a início + label_start_to_end: início a fim + label_stay_logged_in: Guardar sessão + label_disabled: desactivado + label_show_completed_versions: Mostrar versões acabadas + label_me: eu + label_board: Forum + label_board_new: Novo forum + label_board_plural: Forums + label_topic_plural: Tópicos + label_message_plural: Mensagens + label_message_last: Última mensagem + label_message_new: Nova mensagem + label_message_posted: Mensagem adicionada + label_reply_plural: Respostas + label_send_information: Enviar dados da conta para o utilizador + label_year: Ano + label_month: mês + label_week: Semana + label_date_from: De + label_date_to: Para + label_language_based: Baseado na língua do utilizador + label_sort_by: "Ordenar por %{value}" + label_send_test_email: enviar um e-mail de teste + label_feeds_access_key_created_on: "Chave RSS criada há %{value} atrás" + label_module_plural: Módulos + label_added_time_by: "Adicionado por %{author} há %{age} atrás" + label_updated_time: "Alterado há %{value} atrás" + label_jump_to_a_project: Ir para o projecto... + label_file_plural: Ficheiros + label_changeset_plural: Changesets + label_default_columns: Colunas por omissão + label_no_change_option: (sem alteração) + label_bulk_edit_selected_issues: Editar tarefas seleccionadas em conjunto + label_theme: Tema + label_default: Padrão + label_search_titles_only: Procurar apenas em títulos + label_user_mail_option_all: "Para qualquer evento em todos os meus projectos" + label_user_mail_option_selected: "Para qualquer evento apenas nos projectos seleccionados..." + label_user_mail_no_self_notified: "Não quero ser notificado de alterações feitas por mim" + label_registration_activation_by_email: Activação da conta por e-mail + label_registration_manual_activation: Activação manual da conta + label_registration_automatic_activation: Activação automática da conta + label_display_per_page: "Por página: %{value}" + label_age: Idade + label_change_properties: Mudar propriedades + label_general: Geral + label_more: Mais + label_scm: SCM + label_plugins: Extensões + label_ldap_authentication: Autenticação LDAP + label_downloads_abbr: D/L + label_optional_description: Descrição opcional + label_add_another_file: Adicionar outro ficheiro + label_preferences: Preferências + label_chronological_order: Em ordem cronológica + label_reverse_chronological_order: Em ordem cronológica inversa + label_planning: Planeamento + label_incoming_emails: E-mails a chegar + label_generate_key: Gerar uma chave + label_issue_watchers: Observadores + + button_login: Entrar + button_submit: Submeter + button_save: Guardar + button_check_all: Marcar tudo + button_uncheck_all: Desmarcar tudo + button_delete: Apagar + button_create: Criar + button_test: Testar + button_edit: Editar + button_add: Adicionar + button_change: Alterar + button_apply: Aplicar + button_clear: Limpar + button_lock: Bloquear + button_unlock: Desbloquear + button_download: Download + button_list: Listar + button_view: Ver + button_move: Mover + button_back: Voltar + button_cancel: Cancelar + button_activate: Activar + button_sort: Ordenar + button_log_time: Tempo de trabalho + button_rollback: Voltar para esta versão + button_watch: Observar + button_unwatch: Deixar de observar + button_reply: Responder + button_archive: Arquivar + button_unarchive: Desarquivar + button_reset: Reinicializar + button_rename: Renomear + button_change_password: Mudar palavra-chave + button_copy: Copiar + button_annotate: Anotar + button_update: Actualizar + button_configure: Configurar + button_quote: Citar + + status_active: activo + status_registered: registado + status_locked: bloqueado + + text_select_mail_notifications: Seleccionar as acções que originam uma notificação por e-mail. + text_regexp_info: ex. ^[A-Z0-9]+$ + text_min_max_length_info: 0 siginifica sem restrição + text_project_destroy_confirmation: Tem a certeza que deseja apagar o projecto e todos os dados relacionados? + text_subprojects_destroy_warning: "O(s) seu(s) sub-projecto(s): %{value} também será/serão apagado(s)." + text_workflow_edit: Seleccione uma função e um tipo de tarefa para editar o fluxo de trabalho + text_are_you_sure: Tem a certeza? + text_tip_issue_begin_day: tarefa a começar neste dia + text_tip_issue_end_day: tarefa a acabar neste dia + text_tip_issue_begin_end_day: tarefa a começar e acabar neste dia + text_caracters_maximum: "máximo %{count} caracteres." + text_caracters_minimum: "Deve ter pelo menos %{count} caracteres." + text_length_between: "Deve ter entre %{min} e %{max} caracteres." + text_tracker_no_workflow: Sem fluxo de trabalho definido para este tipo de tarefa. + text_unallowed_characters: Caracteres não permitidos + text_comma_separated: Permitidos múltiplos valores (separados por vírgula). + text_issues_ref_in_commit_messages: Referenciando e fechando tarefas em mensagens de commit + text_issue_added: "Tarefa %{id} foi criada por %{author}." + text_issue_updated: "Tarefa %{id} foi actualizada por %{author}." + text_wiki_destroy_confirmation: Tem a certeza que deseja apagar este wiki e todo o seu conteúdo? + text_issue_category_destroy_question: "Algumas tarefas (%{count}) estão atribuídas a esta categoria. O que quer fazer?" + text_issue_category_destroy_assignments: Remover as atribuições à categoria + text_issue_category_reassign_to: Re-atribuir as tarefas para esta categoria + text_user_mail_option: "Para projectos não seleccionados, apenas receberá notificações acerca de coisas que está a observar ou está envolvido (ex. tarefas das quais foi o criador ou lhes foram atribuídas)." + text_no_configuration_data: "Perfis, tipos de tarefas, estados das tarefas e workflows ainda não foram configurados.\nÉ extremamente recomendado carregar as configurações padrão. Será capaz de as modificar depois de estarem carregadas." + text_load_default_configuration: Carregar as configurações padrão + text_status_changed_by_changeset: "Aplicado no changeset %{value}." + text_issues_destroy_confirmation: 'Tem a certeza que deseja apagar a(s) tarefa(s) seleccionada(s)?' + text_select_project_modules: 'Seleccione os módulos a activar para este projecto:' + text_default_administrator_account_changed: Conta default de administrador alterada. + text_file_repository_writable: Repositório de ficheiros com permissões de escrita + text_rmagick_available: RMagick disponível (opcional) + text_destroy_time_entries_question: "%{hours} horas de trabalho foram atribuídas a estas tarefas que vai apagar. O que deseja fazer?" + text_destroy_time_entries: Apagar as horas + text_assign_time_entries_to_project: Atribuir as horas ao projecto + text_reassign_time_entries: 'Re-atribuir as horas para esta tarefa:' + text_user_wrote: "%{value} escreveu:" + text_enumeration_destroy_question: "%{count} objectos estão atribuídos a este valor." + text_enumeration_category_reassign_to: 'Re-atribuí-los para este valor:' + text_email_delivery_not_configured: "Entrega por e-mail não está configurada, e as notificação estão desactivadas.\nConfigure o seu servidor de SMTP em config/configuration.yml e reinicie a aplicação para activar estas funcionalidades." + + default_role_manager: Gestor + default_role_developer: Programador + default_role_reporter: Repórter + default_tracker_bug: Bug + default_tracker_feature: Funcionalidade + default_tracker_support: Suporte + default_issue_status_new: Novo + default_issue_status_in_progress: Em curso + default_issue_status_resolved: Resolvido + default_issue_status_feedback: Feedback + default_issue_status_closed: Fechado + default_issue_status_rejected: Rejeitado + default_doc_category_user: Documentação de utilizador + default_doc_category_tech: Documentação técnica + default_priority_low: Baixa + default_priority_normal: Normal + default_priority_high: Alta + default_priority_urgent: Urgente + default_priority_immediate: Imediata + default_activity_design: Planeamento + default_activity_development: Desenvolvimento + + enumeration_issue_priorities: Prioridade de tarefas + enumeration_doc_categories: Categorias de documentos + enumeration_activities: Actividades (Registo de tempo) + setting_plain_text_mail: Apenas texto simples (sem HTML) + permission_view_files: Ver ficheiros + permission_edit_issues: Editar tarefas + permission_edit_own_time_entries: Editar horas pessoais + permission_manage_public_queries: Gerir queries públicas + permission_add_issues: Adicionar tarefas + permission_log_time: Registar tempo gasto + permission_view_changesets: Ver changesets + permission_view_time_entries: Ver tempo gasto + permission_manage_versions: Gerir versões + permission_manage_wiki: Gerir wiki + permission_manage_categories: Gerir categorias de tarefas + permission_protect_wiki_pages: Proteger páginas de wiki + permission_comment_news: Comentar notícias + permission_delete_messages: Apagar mensagens + permission_select_project_modules: Seleccionar módulos do projecto + permission_edit_wiki_pages: Editar páginas de wiki + permission_add_issue_watchers: Adicionar observadores + permission_view_gantt: ver diagrama de Gantt + permission_move_issues: Mover tarefas + permission_manage_issue_relations: Gerir relações de tarefas + permission_delete_wiki_pages: Apagar páginas de wiki + permission_manage_boards: Gerir forums + permission_delete_wiki_pages_attachments: Apagar anexos + permission_view_wiki_edits: Ver histórico da wiki + permission_add_messages: Submeter mensagens + permission_view_messages: Ver mensagens + permission_manage_files: Gerir ficheiros + permission_edit_issue_notes: Editar notas de tarefas + permission_manage_news: Gerir notícias + permission_view_calendar: Ver calendário + permission_manage_members: Gerir membros + permission_edit_messages: Editar mensagens + permission_delete_issues: Apagar tarefas + permission_view_issue_watchers: Ver lista de observadores + permission_manage_repository: Gerir repositório + permission_commit_access: Acesso a submissão + permission_browse_repository: Navegar em repositório + permission_view_documents: Ver documentos + permission_edit_project: Editar projecto + permission_add_issue_notes: Adicionar notas a tarefas + permission_save_queries: Guardar queries + permission_view_wiki_pages: Ver wiki + permission_rename_wiki_pages: Renomear páginas de wiki + permission_edit_time_entries: Editar entradas de tempo + permission_edit_own_issue_notes: Editar as prórpias notas + setting_gravatar_enabled: Utilizar ícones Gravatar + label_example: Exemplo + text_repository_usernames_mapping: "Seleccionar ou actualizar o utilizador de Redmine mapeado a cada nome de utilizador encontrado no repositório.\nUtilizadores com o mesmo nome de utilizador ou email no Redmine e no repositório são mapeados automaticamente." + permission_edit_own_messages: Editar as próprias mensagens + permission_delete_own_messages: Apagar as próprias mensagens + label_user_activity: "Actividade de %{value}" + label_updated_time_by: "Actualizado por %{author} há %{age}" + text_diff_truncated: '... Este diff foi truncado porque excede o tamanho máximo que pode ser mostrado.' + setting_diff_max_lines_displayed: Número máximo de linhas de diff mostradas + text_plugin_assets_writable: Escrita na pasta de activos dos módulos de extensão possível + warning_attachments_not_saved: "Não foi possível gravar %{count} ficheiro(s) ." + button_create_and_continue: Criar e continuar + text_custom_field_possible_values_info: 'Uma linha para cada valor' + label_display: Mostrar + field_editable: Editável + setting_repository_log_display_limit: Número máximo de revisões exibido no relatório de ficheiro + setting_file_max_size_displayed: Tamanho máximo dos ficheiros de texto exibidos inline + field_watcher: Observador + setting_openid: Permitir início de sessão e registo com OpenID + field_identity_url: URL do OpenID + label_login_with_open_id_option: ou início de sessão com OpenID + field_content: Conteúdo + label_descending: Descendente + label_sort: Ordenar + label_ascending: Ascendente + label_date_from_to: De %{start} a %{end} + label_greater_or_equal: ">=" + label_less_or_equal: <= + text_wiki_page_destroy_question: Esta página tem %{descendants} página(s) subordinada(s) e descendente(s). O que deseja fazer? + text_wiki_page_reassign_children: Reatribuir páginas subordinadas a esta página principal + text_wiki_page_nullify_children: Manter páginas subordinadas como páginas raíz + text_wiki_page_destroy_children: Apagar as páginas subordinadas e todos os seus descendentes + setting_password_min_length: Tamanho mínimo de palavra-chave + field_group_by: Agrupar resultados por + mail_subject_wiki_content_updated: "A página Wiki '%{id}' foi actualizada" + label_wiki_content_added: Página Wiki adicionada + mail_subject_wiki_content_added: "A página Wiki '%{id}' foi adicionada" + mail_body_wiki_content_added: A página Wiki '%{id}' foi adicionada por %{author}. + label_wiki_content_updated: Página Wiki actualizada + mail_body_wiki_content_updated: A página Wiki '%{id}' foi actualizada por %{author}. + permission_add_project: Criar projecto + setting_new_project_user_role_id: Função atribuída a um utilizador não-administrador que cria um projecto + label_view_all_revisions: Ver todas as revisões + label_tag: Etiqueta + label_branch: Ramo + error_no_tracker_in_project: Este projecto não tem associado nenhum tipo de tarefas. Verifique as definições do projecto. + error_no_default_issue_status: Não está definido um estado padrão para as tarefas. Verifique a sua configuração (dirija-se a "Administração -> Estados da tarefa"). + label_group_plural: Grupos + label_group: Grupo + label_group_new: Novo grupo + label_time_entry_plural: Tempo registado + text_journal_changed: "%{label} alterado de %{old} para %{new}" + text_journal_set_to: "%{label} configurado como %{value}" + text_journal_deleted: "%{label} apagou (%{old})" + text_journal_added: "%{label} %{value} adicionado" + field_active: Activo + enumeration_system_activity: Actividade de sistema + permission_delete_issue_watchers: Apagar observadores + version_status_closed: fechado + version_status_locked: protegido + version_status_open: aberto + error_can_not_reopen_issue_on_closed_version: Não é possível voltar a abrir uma tarefa atribuída a uma versão fechada + label_user_anonymous: Anónimo + button_move_and_follow: Mover e seguir + setting_default_projects_modules: Módulos activos por predefinição para novos projectos + setting_gravatar_default: Imagem Gravatar predefinida + field_sharing: Partilha + label_version_sharing_hierarchy: Com hierarquia do projecto + label_version_sharing_system: Com todos os projectos + label_version_sharing_descendants: Com os sub-projectos + label_version_sharing_tree: Com árvore do projecto + label_version_sharing_none: Não partilhado + error_can_not_archive_project: Não é possível arquivar este projecto + button_duplicate: Duplicar + button_copy_and_follow: Copiar e seguir + label_copy_source: Origem + setting_issue_done_ratio: Calcular a percentagem de progresso da tarefa + setting_issue_done_ratio_issue_status: Através do estado da tarefa + error_issue_done_ratios_not_updated: Percentagens de progresso da tarefa não foram actualizadas. + error_workflow_copy_target: Seleccione os tipos de tarefas e funções desejadas + setting_issue_done_ratio_issue_field: Através do campo da tarefa + label_copy_same_as_target: Mesmo que o alvo + label_copy_target: Alvo + notice_issue_done_ratios_updated: Percentagens de progresso da tarefa actualizadas. + error_workflow_copy_source: Seleccione um tipo de tarefa ou função de origem + label_update_issue_done_ratios: Actualizar percentagens de progresso da tarefa + setting_start_of_week: Iniciar calendários a + permission_view_issues: Ver tarefas + label_display_used_statuses_only: Só exibir estados empregues por este tipo de tarefa + label_revision_id: Revisão %{value} + label_api_access_key: Chave de acesso API + label_api_access_key_created_on: Chave de acesso API criada há %{value} + label_feeds_access_key: Chave de acesso RSS + notice_api_access_key_reseted: A sua chave de acesso API foi reinicializada. + setting_rest_api_enabled: Activar serviço Web REST + label_missing_api_access_key: Chave de acesso API em falta + label_missing_feeds_access_key: Chave de acesso RSS em falta + button_show: Mostrar + text_line_separated: Vários valores permitidos (uma linha para cada valor). + setting_mail_handler_body_delimiters: Truncar mensagens de correio electrónico após uma destas linhas + permission_add_subprojects: Criar sub-projectos + label_subproject_new: Novo sub-projecto + text_own_membership_delete_confirmation: |- + Está prestes a eliminar parcial ou totalmente as suas permissões. É possível que não possa editar o projecto após esta acção. + Tem a certeza de que deseja continuar? + label_close_versions: Fechar versões completas + label_board_sticky: Fixar mensagem + label_board_locked: Proteger + permission_export_wiki_pages: Exportar páginas Wiki + setting_cache_formatted_text: Colocar formatação do texto na memória cache + permission_manage_project_activities: Gerir actividades do projecto + error_unable_delete_issue_status: Não foi possível apagar o estado da tarefa + label_profile: Perfil + permission_manage_subtasks: Gerir sub-tarefas + field_parent_issue: Tarefa principal + label_subtask_plural: Sub-tarefa + label_project_copy_notifications: Enviar notificações por e-mail durante a cópia do projecto + error_can_not_delete_custom_field: Não foi possível apagar o campo personalizado + error_unable_to_connect: Não foi possível ligar (%{value}) + error_can_not_remove_role: Esta função está actualmente em uso e não pode ser apagada. + error_can_not_delete_tracker: Existem ainda tarefas nesta categoria. Não é possível apagar este tipo de tarefa. + field_principal: Principal + label_my_page_block: Bloco da minha página + notice_failed_to_save_members: "Erro ao guardar o(s) membro(s): %{errors}." + text_zoom_out: Ampliar + text_zoom_in: Reduzir + notice_unable_delete_time_entry: Não foi possível apagar a entrada de tempo registado. + label_overall_spent_time: Total de tempo registado + field_time_entries: Tempo registado + project_module_gantt: Gantt + project_module_calendar: Calendário + button_edit_associated_wikipage: "Editar página Wiki associada: %{page_title}" + field_text: Campo de texto + label_user_mail_option_only_owner: Apenas para tarefas das quais sou proprietário + setting_default_notification_option: Opção predefinida de notificação + label_user_mail_option_only_my_events: Apenas para tarefas que observo ou em que estou envolvido + label_user_mail_option_only_assigned: Apenas para tarefas que me foram atribuídas + label_user_mail_option_none: Sem eventos + field_member_of_group: Grupo do detentor de atribuição + field_assigned_to_role: Papel do detentor de atribuição + notice_not_authorized_archived_project: O projecto a que tentou aceder foi arquivado. + label_principal_search: "Procurar utilizador ou grupo:" + label_user_search: "Procurar utilizador:" + field_visible: Visível + setting_emails_header: Cabeçalho dos e-mails + setting_commit_logtime_activity_id: Actividade para tempo registado + text_time_logged_by_changeset: Aplicado no conjunto de alterações %{value}. + setting_commit_logtime_enabled: Activar registo de tempo + notice_gantt_chart_truncated: O gráfico foi truncado porque excede o número máximo de itens visíveis (%{max.}) + setting_gantt_items_limit: Número máximo de itens exibidos no gráfico Gantt + field_warn_on_leaving_unsaved: Avisar-me quando deixar uma página com texto por salvar + text_warn_on_leaving_unsaved: A página actual contém texto por salvar que será perdido caso saia desta página. + label_my_queries: As minhas consultas + text_journal_changed_no_detail: "%{label} actualizada" + label_news_comment_added: Comentário adicionado a uma notícia + button_expand_all: Expandir todos + button_collapse_all: Minimizar todos + label_additional_workflow_transitions_for_assignee: Transições adicionais permitidas quando a tarefa está atribuida ao utilizador + label_additional_workflow_transitions_for_author: Transições adicionais permitidas quando o utilizador é o autor da tarefa + label_bulk_edit_selected_time_entries: Edição em massa de registos de tempo + text_time_entries_destroy_confirmation: Têm a certeza que pretende apagar o(s) registo(s) de tempo selecionado(s)? + label_role_anonymous: Anónimo + label_role_non_member: Não membro + label_issue_note_added: Nota adicionada + label_issue_status_updated: Estado actualizado + label_issue_priority_updated: Prioridade adicionada + label_issues_visibility_own: Tarefas criadas ou atribuídas ao utilizador + field_issues_visibility: Visibilidade das tarefas + label_issues_visibility_all: Todas as tarefas + permission_set_own_issues_private: Configurar as suas tarefas como públicas ou privadas + field_is_private: Privado + permission_set_issues_private: Configurar tarefas como públicas ou privadas + label_issues_visibility_public: Todas as tarefas públicas + text_issues_destroy_descendants_confirmation: Irá apagar também %{count} subtarefa(s). + field_commit_logs_encoding: Codificação das mensagens de commit + field_scm_path_encoding: Codificação do caminho + text_scm_path_encoding_note: "Por omissão: UTF-8" + field_path_to_repository: Caminho para o repositório + field_root_directory: Raíz do directório + field_cvs_module: Módulo + field_cvsroot: CVSROOT + text_mercurial_repository_note: "Repositório local (ex: /hgrepo, c:\\hgrepo)" + text_scm_command: Comando + text_scm_command_version: Versão + label_git_report_last_commit: Analisar último commit por ficheiros e pastas + text_scm_config: Pode configurar os comando SCM em config/configuration.yml. Por favor reinicie a aplicação depois de alterar o ficheiro. + text_scm_command_not_available: O comando SCM não está disponível. Por favor verifique as configurações no painel de administração. + notice_issue_successful_create: Tarefa %{id} criada. + label_between: entre + setting_issue_group_assignment: Permitir atribuir tarefas a grupos + label_diff: diferença + text_git_repository_note: O repositório é local (e.g. /gitrepo, c:\gitrepo) + description_query_sort_criteria_direction: Direcção da ordenação + description_project_scope: Âmbito da pesquisa + description_filter: Filtro + description_user_mail_notification: Configurações das notificações por email + description_date_from: Introduza data de início + description_message_content: Conteúdo da mensagem + description_available_columns: Colunas disponíveis + description_date_range_interval: Escolha o intervalo seleccionando a data de início e de fim + description_issue_category_reassign: Escolha a categoria da tarefa + description_search: Campo de pesquisa + description_notes: Notas + description_date_range_list: Escolha o intervalo da lista + description_choose_project: Projecto + description_date_to: Introduza data de fim + description_query_sort_criteria_attribute: Ordenar atributos + description_wiki_subpages_reassign: Escolha nova página pai + description_selected_columns: Colunas seleccionadas + label_parent_revision: Pai + label_child_revision: Filha + error_scm_annotate_big_text_file: Esta entrada não pode ser anotada, excede o tamanha máximo. + setting_default_issue_start_date_to_creation_date: Utilizar a data actual como data de início para novas tarefas + button_edit_section: Editar esta secção + setting_repositories_encodings: Codificação dos anexos e repositórios + description_all_columns: Todas as colunas + button_export: Exportar + label_export_options: "%{export_format} opções de exportação" + error_attachment_too_big: Este ficheiro não pode ser carregado pois excede o tamanho máximo permitido por ficheiro (%{max_size}) + notice_failed_to_save_time_entries: "Falha ao guardar %{count} registo(s) de tempo dos %{total} seleccionados: %{ids}." + label_x_issues: + zero: 0 tarefas + one: 1 tarefa + other: "%{count} tarefas" + label_repository_new: Novo repositório + field_repository_is_default: Repositório principal + label_copy_attachments: Copiar anexos + label_item_position: "%{position}/%{count}" + label_completed_versions: Versões completas + text_project_identifier_info: Apenas letras minúsculas (a-z), números, traços e sublinhados são permitidos.
    Depois de guardar não é possível alterar. + field_multiple: Múltiplos valores + setting_commit_cross_project_ref: Permitir que tarefas dos restantes projectos sejam referenciadas e resolvidas + text_issue_conflict_resolution_add_notes: Adicionar as minhas notas e descartar as minhas restantes alterações + text_issue_conflict_resolution_overwrite: Aplicar as minhas alterações (notas antigas serão mantidas mas algumas alterações podem se perder) + notice_issue_update_conflict: Esta tarefa foi actualizada por outro utilizador enquanto estava a edita-la. + text_issue_conflict_resolution_cancel: Descartar todas as minhas alterações e actualizar %{link} + permission_manage_related_issues: Gerir tarefas relacionadas + field_auth_source_ldap_filter: Filtro LDAP + label_search_for_watchers: Pesquisar por observadores para adicionar + notice_account_deleted: A sua conta foi apagada permanentemente. + setting_unsubscribe: Permitir aos utilizadores apagarem a sua própria conta + button_delete_my_account: Apagar a minha conta + text_account_destroy_confirmation: |- + Têm a certeza que pretende avançar? + A sua conta vai ser permanentemente apagada, não será possível recupera-la. + error_session_expired: A sua sessão expirou. Por-favor autentique-se novamente. + text_session_expiration_settings: "Atenção: alterar estas configurações pode fazer expirar as sessões em curso, incluíndo a sua." + setting_session_lifetime: Duração máxima da sessão + setting_session_timeout: Tempo limite de inactividade da sessão + label_session_expiration: Expiração da sessão + permission_close_project: Fechar / re-abrir o projecto + label_show_closed_projects: Ver os projectos fechados + button_close: Fechar + button_reopen: Re-abrir + project_status_active: activo + project_status_closed: fechado + project_status_archived: arquivado + text_project_closed: Este projecto está fechado e é apenas de leitura. + notice_user_successful_create: Utilizador %{id} criado. + field_core_fields: Campos padrão + field_timeout: Tempo limite (em segundos) + setting_thumbnails_enabled: Apresentar miniaturas dos anexos + setting_thumbnails_size: Tamanho das miniaturas (em pixeis) + label_status_transitions: Estado das transições + label_fields_permissions: Permissões do campo + label_readonly: Apenas de leitura + label_required: Obrigatório + text_repository_identifier_info: Apenas letras minúsculas (a-z), números, traços e sublinhados são permitidos.
    Depois de guardar não é possível alterar. + field_board_parent: Fórum pai + label_attribute_of_project: "%{name} do Projecto" + label_attribute_of_author: "%{name} do Autor" + label_attribute_of_assigned_to: "%{name} do atribuído" + label_attribute_of_fixed_version: "%{name} da Versão" + label_copy_subtasks: Copiar sub-tarefas + label_copied_to: copiado para + label_copied_from: copiado de + label_any_issues_in_project: tarefas do projecto + label_any_issues_not_in_project: tarefas sem projecto + field_private_notes: Notas privadas + permission_view_private_notes: Ver notas privadas + permission_set_notes_private: Configurar notas como privadas + label_no_issues_in_project: sem tarefas no projecto + label_any: todos + label_last_n_weeks: últimas %{count} semanas + setting_cross_project_subtasks: Permitir sub-tarefas entre projectos + label_cross_project_descendants: Com os sub-projectos + label_cross_project_tree: Com árvore do projecto + label_cross_project_hierarchy: Com hierarquia do projecto + label_cross_project_system: Com todos os projectos + button_hide: Esconder + setting_non_working_week_days: Dias não úteis + label_in_the_next_days: no futuro + label_in_the_past_days: no passado + label_attribute_of_user: Do utilizador %{name} + text_turning_multiple_off: Se desactivar a escolha múltipla, + a escolha múltipla será apagada de modo a manter apenas um valor por item. + label_attribute_of_issue: Tarefa de %{name} + permission_add_documents: Adicionar documentos + permission_edit_documents: Editar documentos + permission_delete_documents: Apagar documentos + label_gantt_progress_line: Barra de progresso + setting_jsonp_enabled: Activar suporte JSONP + field_inherit_members: Herdar membros + field_closed_on: Fechado + setting_default_projects_tracker_ids: Default trackers for new projects + label_total_time: Total diff --git a/config/locales/ro.yml b/config/locales/ro.yml new file mode 100644 index 00000000..6f72e7b8 --- /dev/null +++ b/config/locales/ro.yml @@ -0,0 +1,1084 @@ +ro: + direction: ltr + date: + formats: + default: "%d-%m-%Y" + short: "%d %b" + long: "%d %B %Y" + only_day: "%e" + + day_names: [Duminică, Luni, Marti, Miercuri, Joi, Vineri, Sâmbătă] + abbr_day_names: [Dum, Lun, Mar, Mie, Joi, Vin, Sâm] + + month_names: [~, Ianuarie, Februarie, Martie, Aprilie, Mai, Iunie, Iulie, August, Septembrie, Octombrie, Noiembrie, Decembrie] + abbr_month_names: [~, Ian, Feb, Mar, Apr, Mai, Iun, Iul, Aug, Sep, Oct, Noi, Dec] + order: + - :day + - :month + - :year + + time: + formats: + default: "%m/%d/%Y %I:%M %p" + time: "%I:%M %p" + short: "%d %b %H:%M" + long: "%B %d, %Y %H:%M" + am: "am" + pm: "pm" + + datetime: + distance_in_words: + half_a_minute: "jumătate de minut" + less_than_x_seconds: + one: "mai puțin de o secundă" + other: "mai puțin de %{count} secunde" + x_seconds: + one: "o secundă" + other: "%{count} secunde" + less_than_x_minutes: + one: "mai puțin de un minut" + other: "mai puțin de %{count} minute" + x_minutes: + one: "un minut" + other: "%{count} minute" + about_x_hours: + one: "aproximativ o oră" + other: "aproximativ %{count} ore" + x_hours: + one: "1 hour" + other: "%{count} hours" + x_days: + one: "o zi" + other: "%{count} zile" + about_x_months: + one: "aproximativ o lună" + other: "aproximativ %{count} luni" + x_months: + one: "o luna" + other: "%{count} luni" + about_x_years: + one: "aproximativ un an" + other: "aproximativ %{count} ani" + over_x_years: + one: "peste un an" + other: "peste %{count} ani" + almost_x_years: + one: "almost 1 year" + other: "almost %{count} years" + + number: + format: + separator: "." + delimiter: "" + precision: 3 + + human: + format: + precision: 3 + delimiter: "" + storage_units: + format: "%n %u" + units: + kb: KB + tb: TB + gb: GB + byte: + one: Byte + other: Bytes + mb: MB + +# Used in array.to_sentence. + support: + array: + sentence_connector: "și" + skip_last_comma: true + + activerecord: + errors: + template: + header: + one: "1 error prohibited this %{model} from being saved" + other: "%{count} errors prohibited this %{model} from being saved" + messages: + inclusion: "nu este inclus în listă" + exclusion: "este rezervat" + invalid: "nu este valid" + confirmation: "nu este identică" + accepted: "trebuie acceptat" + empty: "trebuie completat" + blank: "nu poate fi gol" + too_long: "este prea lung" + too_short: "este prea scurt" + wrong_length: "nu are lungimea corectă" + taken: "a fost luat deja" + not_a_number: "nu este un număr" + not_a_date: "nu este o dată validă" + greater_than: "trebuie să fie mai mare de %{count}" + greater_than_or_equal_to: "trebuie să fie mai mare sau egal cu %{count}" + equal_to: "trebuie să fie egal cu {count}}" + less_than: "trebuie să fie mai mic decat %{count}" + less_than_or_equal_to: "trebuie să fie mai mic sau egal cu %{count}" + odd: "trebuie să fie impar" + even: "trebuie să fie par" + greater_than_start_date: "trebuie să fie după data de început" + not_same_project: "trebuie să aparțină aceluiași proiect" + circular_dependency: "Această relație ar crea o dependență circulară" + cant_link_an_issue_with_a_descendant: "An issue can not be linked to one of its subtasks" + + actionview_instancetag_blank_option: Selectați + + general_text_No: 'Nu' + general_text_Yes: 'Da' + general_text_no: 'nu' + general_text_yes: 'da' + general_lang_name: 'Română' + general_csv_separator: '.' + general_csv_decimal_separator: ',' + general_csv_encoding: UTF-8 + general_pdf_encoding: UTF-8 + general_first_day_of_week: '2' + + notice_account_updated: Cont actualizat. + notice_account_invalid_creditentials: Utilizator sau parola nevalidă + notice_account_password_updated: Parolă actualizată. + notice_account_wrong_password: Parolă greșită + notice_account_register_done: Contul a fost creat. Pentru activare, urmați legătura trimisă prin email. + notice_account_unknown_email: Utilizator necunoscut. + notice_can_t_change_password: Acest cont folosește o sursă externă de autentificare. Nu se poate schimba parola. + notice_account_lost_email_sent: S-a trimis un email cu instrucțiuni de schimbare a parolei. + notice_account_activated: Contul a fost activat. Vă puteți autentifica acum. + notice_successful_create: Creat. + notice_successful_update: Actualizat. + notice_successful_delete: Șters. + notice_successful_connection: Conectat. + notice_file_not_found: Pagina pe care doriți să o accesați nu există sau a fost ștearsă. + notice_locking_conflict: Datele au fost actualizate de alt utilizator. + notice_not_authorized: Nu sunteți autorizat sa accesați această pagină. + notice_email_sent: "S-a trimis un email către %{value}" + notice_email_error: "A intervenit o eroare la trimiterea de email (%{value})" + notice_feeds_access_key_reseted: Cheia de acces RSS a fost resetată. + notice_failed_to_save_issues: "Nu s-au putut salva %{count} tichete din cele %{total} selectate: %{ids}." + notice_no_issue_selected: "Niciun tichet selectat! Vă rugăm să selectați tichetele pe care doriți să le editați." + notice_account_pending: "Contul dumneavoastră a fost creat și așteaptă aprobarea administratorului." + notice_default_data_loaded: S-a încărcat configurația implicită. + notice_unable_delete_version: Nu se poate șterge versiunea. + + error_can_t_load_default_data: "Nu s-a putut încărca configurația implicită: %{value}" + error_scm_not_found: "Nu s-a găsit articolul sau revizia în depozit." + error_scm_command_failed: "A intervenit o eroare la accesarea depozitului: %{value}" + error_scm_annotate: "Nu există sau nu poate fi adnotată." + error_issue_not_found_in_project: 'Tichetul nu a fost găsit sau nu aparține acestui proiect' + + warning_attachments_not_saved: "Nu s-au putut salva %{count} fișiere." + + mail_subject_lost_password: "Parola dumneavoastră: %{value}" + mail_body_lost_password: 'Pentru a schimba parola, accesați:' + mail_subject_register: "Activarea contului %{value}" + mail_body_register: 'Pentru activarea contului, accesați:' + mail_body_account_information_external: "Puteți folosi contul „{value}}” pentru a vă autentifica." + mail_body_account_information: Informații despre contul dumneavoastră + mail_subject_account_activation_request: "Cerere de activare a contului %{value}" + mail_body_account_activation_request: "S-a înregistrat un utilizator nou (%{value}). Contul așteaptă aprobarea dumneavoastră:" + mail_subject_reminder: "%{count} tichete trebuie rezolvate în următoarele %{days} zile" + mail_body_reminder: "%{count} tichete atribuite dumneavoastră trebuie rezolvate în următoarele %{days} zile:" + + + field_name: Nume + field_description: Descriere + field_summary: Rezumat + field_is_required: Obligatoriu + field_firstname: Prenume + field_lastname: Nume + field_mail: Email + field_filename: Fișier + field_filesize: Mărime + field_downloads: Descărcări + field_author: Autor + field_created_on: Creat la + field_updated_on: Actualizat la + field_field_format: Format + field_is_for_all: Pentru toate proiectele + field_possible_values: Valori posibile + field_regexp: Expresie regulară + field_min_length: lungime minimă + field_max_length: lungime maximă + field_value: Valoare + field_category: Categorie + field_title: Titlu + field_project: Proiect + field_issue: Tichet + field_status: Stare + field_notes: Note + field_is_closed: Rezolvat + field_is_default: Implicit + field_tracker: Tip de tichet + field_subject: Subiect + field_due_date: Data finalizării + field_assigned_to: Atribuit + field_priority: Prioritate + field_fixed_version: Versiune țintă + field_user: Utilizator + field_role: Rol + field_homepage: Pagina principală + field_is_public: Public + field_parent: Sub-proiect al + field_is_in_roadmap: Tichete afișate în plan + field_login: Autentificare + field_mail_notification: Notificări prin e-mail + field_admin: Administrator + field_last_login_on: Ultima autentificare în + field_language: Limba + field_effective_date: Data + field_password: Parola + field_new_password: Parola nouă + field_password_confirmation: Confirmare + field_version: Versiune + field_type: Tip + field_host: Gazdă + field_port: Port + field_account: Cont + field_base_dn: Base DN + field_attr_login: Atribut autentificare + field_attr_firstname: Atribut prenume + field_attr_lastname: Atribut nume + field_attr_mail: Atribut email + field_onthefly: Creare utilizator pe loc + field_start_date: Data începerii + field_done_ratio: Realizat (%) + field_auth_source: Mod autentificare + field_hide_mail: Nu se afișează adresa de email + field_comments: Comentariu + field_url: URL + field_start_page: Pagina de start + field_subproject: Subproiect + field_hours: Ore + field_activity: Activitate + field_spent_on: Data + field_identifier: Identificator + field_is_filter: Filtru + field_issue_to: Tichet asociat + field_delay: Întârziere + field_assignable: Se pot atribui tichete acestui rol + field_redirect_existing_links: Redirecționează legăturile existente + field_estimated_hours: Timp estimat + field_column_names: Coloane + field_time_zone: Fus orar + field_searchable: Căutare + field_default_value: Valoare implicita + field_comments_sorting: Afișează comentarii + field_parent_title: Pagina superioara + field_editable: Modificabil + field_watcher: Urmărește + field_identity_url: URL OpenID + field_content: Conținut + + setting_app_title: Titlu aplicație + setting_app_subtitle: Subtitlu aplicație + setting_welcome_text: Text de întâmpinare + setting_default_language: Limba implicita + setting_login_required: Necesita autentificare + setting_self_registration: Înregistrare automată + setting_attachment_max_size: Mărime maxima atașament + setting_issues_export_limit: Limită de tichete exportate + setting_mail_from: Adresa de email a expeditorului + setting_bcc_recipients: Alți destinatari pentru email (BCC) + setting_plain_text_mail: Mesaje text (fără HTML) + setting_host_name: Numele gazdei și calea + setting_text_formatting: Formatare text + setting_wiki_compression: Comprimare istoric Wiki + setting_feeds_limit: Limita de actualizări din feed + setting_default_projects_public: Proiectele noi sunt implicit publice + setting_autofetch_changesets: Preluare automată a modificărilor din depozit + setting_sys_api_enabled: Activare WS pentru gestionat depozitul + setting_commit_ref_keywords: Cuvinte cheie pt. referire tichet + setting_commit_fix_keywords: Cuvinte cheie pt. rezolvare tichet + setting_autologin: Autentificare automată + setting_date_format: Format dată + setting_time_format: Format oră + setting_cross_project_issue_relations: Permite legături de tichete între proiecte + setting_issue_list_default_columns: Coloane implicite afișate în lista de tichete + setting_emails_footer: Subsol email + setting_protocol: Protocol + setting_per_page_options: Număr de obiecte pe pagină + setting_user_format: Stil de afișare pentru utilizator + setting_activity_days_default: Se afișează zile în jurnalul proiectului + setting_display_subprojects_issues: Afișează implicit tichetele sub-proiectelor în proiectele principale + setting_enabled_scm: SCM activat + setting_mail_handler_api_enabled: Activare WS pentru email primit + setting_mail_handler_api_key: cheie API + setting_sequential_project_identifiers: Generează secvențial identificatoarele de proiect + setting_gravatar_enabled: Folosește poze Gravatar pentru utilizatori + setting_diff_max_lines_displayed: Număr maxim de linii de diferență afișate + setting_file_max_size_displayed: Număr maxim de fișiere text afișate în pagină (inline) + setting_repository_log_display_limit: Număr maxim de revizii afișate în istoricul fișierului + setting_openid: Permite înregistrare și autentificare cu OpenID + + permission_edit_project: Editează proiectul + permission_select_project_modules: Alege module pentru proiect + permission_manage_members: Editează membri + permission_manage_versions: Editează versiuni + permission_manage_categories: Editează categorii + permission_add_issues: Adaugă tichete + permission_edit_issues: Editează tichete + permission_manage_issue_relations: Editează relații tichete + permission_add_issue_notes: Adaugă note + permission_edit_issue_notes: Editează note + permission_edit_own_issue_notes: Editează notele proprii + permission_move_issues: Mută tichete + permission_delete_issues: Șterge tichete + permission_manage_public_queries: Editează căutările implicite + permission_save_queries: Salvează căutările + permission_view_gantt: Afișează Gantt + permission_view_calendar: Afișează calendarul + permission_view_issue_watchers: Afișează lista de persoane interesate + permission_add_issue_watchers: Adaugă persoane interesate + permission_log_time: Înregistrează timpul de lucru + permission_view_time_entries: Afișează timpul de lucru + permission_edit_time_entries: Editează jurnalele cu timp de lucru + permission_edit_own_time_entries: Editează jurnalele proprii cu timpul de lucru + permission_manage_news: Editează știri + permission_comment_news: Comentează știrile + permission_view_documents: Afișează documente + permission_manage_files: Editează fișiere + permission_view_files: Afișează fișiere + permission_manage_wiki: Editează wiki + permission_rename_wiki_pages: Redenumește pagini wiki + permission_delete_wiki_pages: Șterge pagini wiki + permission_view_wiki_pages: Afișează wiki + permission_view_wiki_edits: Afișează istoricul wiki + permission_edit_wiki_pages: Editează pagini wiki + permission_delete_wiki_pages_attachments: Șterge atașamente + permission_protect_wiki_pages: Blochează pagini wiki + permission_manage_repository: Gestionează depozitul + permission_browse_repository: Răsfoiește depozitul + permission_view_changesets: Afișează modificările din depozit + permission_commit_access: Acces commit + permission_manage_boards: Editează forum + permission_view_messages: Afișează mesaje + permission_add_messages: Scrie mesaje + permission_edit_messages: Editează mesaje + permission_edit_own_messages: Editează mesajele proprii + permission_delete_messages: Șterge mesaje + permission_delete_own_messages: Șterge mesajele proprii + + project_module_issue_tracking: Tichete + project_module_time_tracking: Timp de lucru + project_module_news: Știri + project_module_documents: Documente + project_module_files: Fișiere + project_module_wiki: Wiki + project_module_repository: Depozit + project_module_boards: Forum + + label_user: Utilizator + label_user_plural: Utilizatori + label_user_new: Utilizator nou + label_project: Proiect + label_project_new: Proiect nou + label_project_plural: Proiecte + label_x_projects: + zero: niciun proiect + one: un proiect + other: "%{count} proiecte" + label_project_all: Toate proiectele + label_project_latest: Proiecte noi + label_issue: Tichet + label_issue_new: Tichet nou + label_issue_plural: Tichete + label_issue_view_all: Afișează toate tichetele + label_issues_by: "Sortează după %{value}" + label_issue_added: Adaugat + label_issue_updated: Actualizat + label_document: Document + label_document_new: Document nou + label_document_plural: Documente + label_document_added: Adăugat + label_role: Rol + label_role_plural: Roluri + label_role_new: Rol nou + label_role_and_permissions: Roluri și permisiuni + label_member: Membru + label_member_new: membru nou + label_member_plural: Membri + label_tracker: Tip de tichet + label_tracker_plural: Tipuri de tichete + label_tracker_new: Tip nou de tichet + label_workflow: Mod de lucru + label_issue_status: Stare tichet + label_issue_status_plural: Stare tichete + label_issue_status_new: Stare nouă + label_issue_category: Categorie de tichet + label_issue_category_plural: Categorii de tichete + label_issue_category_new: Categorie nouă + label_custom_field: Câmp personalizat + label_custom_field_plural: Câmpuri personalizate + label_custom_field_new: Câmp nou personalizat + label_enumerations: Enumerări + label_enumeration_new: Valoare nouă + label_information: Informație + label_information_plural: Informații + label_please_login: Vă rugăm să vă autentificați + label_register: Înregistrare + label_login_with_open_id_option: sau autentificare cu OpenID + label_password_lost: Parolă uitată + label_home: Acasă + label_my_page: Pagina mea + label_my_account: Contul meu + label_my_projects: Proiectele mele + label_administration: Administrare + label_login: Autentificare + label_logout: Ieșire din cont + label_help: Ajutor + label_reported_issues: Tichete + label_assigned_to_me_issues: Tichetele mele + label_last_login: Ultima conectare + label_registered_on: Înregistrat la + label_activity: Activitate + label_overall_activity: Activitate - vedere de ansamblu + label_user_activity: "Activitate %{value}" + label_new: Nou + label_logged_as: Autentificat ca + label_environment: Mediu + label_authentication: Autentificare + label_auth_source: Mod de autentificare + label_auth_source_new: Nou + label_auth_source_plural: Moduri de autentificare + label_subproject_plural: Sub-proiecte + label_and_its_subprojects: "%{value} și sub-proiecte" + label_min_max_length: lungime min - max + label_list: Listă + label_date: Dată + label_integer: Întreg + label_float: Zecimal + label_boolean: Valoare logică + label_string: Text + label_text: Text lung + label_attribute: Atribut + label_attribute_plural: Atribute + label_no_data: Nu există date de afișat + label_change_status: Schimbă starea + label_history: Istoric + label_attachment: Fișier + label_attachment_new: Fișier nou + label_attachment_delete: Șterge fișier + label_attachment_plural: Fișiere + label_file_added: Adăugat + label_report: Raport + label_report_plural: Rapoarte + label_news: Știri + label_news_new: Adaugă știre + label_news_plural: Știri + label_news_latest: Ultimele știri + label_news_view_all: Afișează toate știrile + label_news_added: Adăugat + label_settings: Setări + label_overview: Pagină proiect + label_version: Versiune + label_version_new: Versiune nouă + label_version_plural: Versiuni + label_confirmation: Confirmare + label_export_to: 'Disponibil și în:' + label_read: Citește... + label_public_projects: Proiecte publice + label_open_issues: deschis + label_open_issues_plural: deschise + label_closed_issues: închis + label_closed_issues_plural: închise + label_x_open_issues_abbr_on_total: + zero: 0 deschise / %{total} + one: 1 deschis / %{total} + other: "%{count} deschise / %{total}" + label_x_open_issues_abbr: + zero: 0 deschise + one: 1 deschis + other: "%{count} deschise" + label_x_closed_issues_abbr: + zero: 0 închise + one: 1 închis + other: "%{count} închise" + label_total: Total + label_permissions: Permisiuni + label_current_status: Stare curentă + label_new_statuses_allowed: Stări noi permise + label_all: toate + label_none: niciunul + label_nobody: nimeni + label_next: Înainte + label_previous: Înapoi + label_used_by: Folosit de + label_details: Detalii + label_add_note: Adaugă o notă + label_per_page: pe pagină + label_calendar: Calendar + label_months_from: luni de la + label_gantt: Gantt + label_internal: Intern + label_last_changes: "ultimele %{count} schimbări" + label_change_view_all: Afișează toate schimbările + label_personalize_page: Personalizează aceasta pagina + label_comment: Comentariu + label_comment_plural: Comentarii + label_x_comments: + zero: fara comentarii + one: 1 comentariu + other: "%{count} comentarii" + label_comment_add: Adaugă un comentariu + label_comment_added: Adăugat + label_comment_delete: Șterge comentariul + label_query: Cautare personalizata + label_query_plural: Căutări personalizate + label_query_new: Căutare nouă + label_filter_add: Adaugă filtru + label_filter_plural: Filtre + label_equals: este + label_not_equals: nu este + label_in_less_than: în mai puțin de + label_in_more_than: în mai mult de + label_in: în + label_today: astăzi + label_all_time: oricând + label_yesterday: ieri + label_this_week: săptămâna aceasta + label_last_week: săptămâna trecută + label_last_n_days: "ultimele %{count} zile" + label_this_month: luna aceasta + label_last_month: luna trecută + label_this_year: anul acesta + label_date_range: Perioada + label_less_than_ago: mai puțin de ... zile + label_more_than_ago: mai mult de ... zile + label_ago: în urma + label_contains: conține + label_not_contains: nu conține + label_day_plural: zile + label_repository: Depozit + label_repository_plural: Depozite + label_browse: Afișează + label_revision: Revizie + label_revision_plural: Revizii + label_associated_revisions: Revizii asociate + label_added: adaugată + label_modified: modificată + label_copied: copiată + label_renamed: redenumită + label_deleted: ștearsă + label_latest_revision: Ultima revizie + label_latest_revision_plural: Ultimele revizii + label_view_revisions: Afișează revizii + label_max_size: Mărime maximă + label_sort_highest: Prima + label_sort_higher: În sus + label_sort_lower: În jos + label_sort_lowest: Ultima + label_roadmap: Planificare + label_roadmap_due_in: "De terminat în %{value}" + label_roadmap_overdue: "Întârziat cu %{value}" + label_roadmap_no_issues: Nu există tichete pentru această versiune + label_search: Caută + label_result_plural: Rezultate + label_all_words: toate cuvintele + label_wiki: Wiki + label_wiki_edit: Editare Wiki + label_wiki_edit_plural: Editări Wiki + label_wiki_page: Pagină Wiki + label_wiki_page_plural: Pagini Wiki + label_index_by_title: Sortează după titlu + label_index_by_date: Sortează după dată + label_current_version: Versiunea curentă + label_preview: Previzualizare + label_feed_plural: Feed-uri + label_changes_details: Detaliile tuturor schimbărilor + label_issue_tracking: Urmărire tichete + label_spent_time: Timp alocat + label_f_hour: "%{value} oră" + label_f_hour_plural: "%{value} ore" + label_time_tracking: Urmărire timp de lucru + label_change_plural: Schimbări + label_statistics: Statistici + label_commits_per_month: Commit pe luna + label_commits_per_author: Commit per autor + label_view_diff: Afișează diferențele + label_diff_inline: în linie + label_diff_side_by_side: una lângă alta + label_options: Opțiuni + label_copy_workflow_from: Copiază modul de lucru de la + label_permissions_report: Permisiuni + label_watched_issues: Tichete urmărite + label_related_issues: Tichete asociate + label_applied_status: Stare aplicată + label_loading: Încarcă... + label_relation_new: Asociere nouă + label_relation_delete: Șterge asocierea + label_relates_to: asociat cu + label_duplicates: duplicate + label_duplicated_by: la fel ca + label_blocks: blocări + label_blocked_by: blocat de + label_precedes: precede + label_follows: urmează + label_end_to_start: de la sfârșit la început + label_end_to_end: de la sfârșit la sfârșit + label_start_to_start: de la început la început + label_start_to_end: de la început la sfârșit + label_stay_logged_in: Păstrează autentificarea + label_disabled: dezactivat + label_show_completed_versions: Arată versiunile terminate + label_me: eu + label_board: Forum + label_board_new: Forum nou + label_board_plural: Forumuri + label_topic_plural: Subiecte + label_message_plural: Mesaje + label_message_last: Ultimul mesaj + label_message_new: Mesaj nou + label_message_posted: Adăugat + label_reply_plural: Răspunsuri + label_send_information: Trimite utilizatorului informațiile despre cont + label_year: An + label_month: Lună + label_week: Săptămână + label_date_from: De la + label_date_to: La + label_language_based: Un funcție de limba de afișare a utilizatorului + label_sort_by: "Sortează după %{value}" + label_send_test_email: Trimite email de test + label_feeds_access_key_created_on: "Cheie de acces creată acum %{value}" + label_module_plural: Module + label_added_time_by: "Adăugat de %{author} acum %{age}" + label_updated_time_by: "Actualizat de %{author} acum %{age}" + label_updated_time: "Actualizat acum %{value}" + label_jump_to_a_project: Alege proiectul... + label_file_plural: Fișiere + label_changeset_plural: Schimbări + label_default_columns: Coloane implicite + label_no_change_option: (fără schimbări) + label_bulk_edit_selected_issues: Editează toate tichetele selectate + label_theme: Tema + label_default: Implicită + label_search_titles_only: Caută numai în titluri + label_user_mail_option_all: "Pentru orice eveniment, în toate proiectele mele" + label_user_mail_option_selected: " Pentru orice eveniment, în proiectele selectate..." + label_user_mail_no_self_notified: "Nu trimite notificări pentru modificările mele" + label_registration_activation_by_email: activare cont prin email + label_registration_manual_activation: activare manuală a contului + label_registration_automatic_activation: activare automată a contului + label_display_per_page: "pe pagină: %{value}" + label_age: vechime + label_change_properties: Schimbă proprietățile + label_general: General + label_more: Mai mult + label_scm: SCM + label_plugins: Plugin-uri + label_ldap_authentication: autentificare LDAP + label_downloads_abbr: D/L + label_optional_description: Descriere (opțională) + label_add_another_file: Adaugă alt fișier + label_preferences: Preferințe + label_chronological_order: în ordine cronologică + label_reverse_chronological_order: În ordine invers cronologică + label_planning: Planificare + label_incoming_emails: Mesaje primite + label_generate_key: Generează o cheie + label_issue_watchers: Cine urmărește + label_example: Exemplu + label_display: Afișează + + label_sort: Sortează + label_ascending: Crescător + label_descending: Descrescător + label_date_from_to: De la %{start} la %{end} + + button_login: Autentificare + button_submit: Trimite + button_save: Salvează + button_check_all: Bifează tot + button_uncheck_all: Debifează tot + button_delete: Șterge + button_create: Creează + button_create_and_continue: Creează și continua + button_test: Testează + button_edit: Editează + button_add: Adaugă + button_change: Modifică + button_apply: Aplică + button_clear: Șterge + button_lock: Blochează + button_unlock: Deblochează + button_download: Descarcă + button_list: Listează + button_view: Afișează + button_move: Mută + button_back: Înapoi + button_cancel: Anulează + button_activate: Activează + button_sort: Sortează + button_log_time: Înregistrează timpul de lucru + button_rollback: Revenire la această versiune + button_watch: Urmăresc + button_unwatch: Nu urmăresc + button_reply: Răspunde + button_archive: Arhivează + button_unarchive: Dezarhivează + button_reset: Resetează + button_rename: Redenumește + button_change_password: Schimbare parolă + button_copy: Copiază + button_annotate: Adnotează + button_update: Actualizează + button_configure: Configurează + button_quote: Citează + + status_active: activ + status_registered: înregistrat + status_locked: blocat + + text_select_mail_notifications: Selectați acțiunile notificate prin email. + text_regexp_info: ex. ^[A-Z0-9]+$ + text_min_max_length_info: 0 înseamnă fără restricții + text_project_destroy_confirmation: Sigur doriți să ștergeți proiectul și toate datele asociate? + text_subprojects_destroy_warning: "Se vor șterge și sub-proiectele: %{value}." + text_workflow_edit: Selectați un rol și un tip de tichet pentru a edita modul de lucru + text_are_you_sure: Sunteți sigur(ă)? + text_tip_issue_begin_day: sarcină care începe în această zi + text_tip_issue_end_day: sarcină care se termină în această zi + text_tip_issue_begin_end_day: sarcină care începe și se termină în această zi + text_caracters_maximum: "maxim %{count} caractere." + text_caracters_minimum: "Trebuie să fie minim %{count} caractere." + text_length_between: "Lungime între %{min} și %{max} caractere." + text_tracker_no_workflow: Nu sunt moduri de lucru pentru acest tip de tichet + text_unallowed_characters: Caractere nepermise + text_comma_separated: Sunt permise mai multe valori (separate cu virgulă). + text_issues_ref_in_commit_messages: Referire la tichete și rezolvare în textul mesajului + text_issue_added: "Tichetul %{id} a fost adăugat de %{author}." + text_issue_updated: "Tichetul %{id} a fost actualizat de %{author}." + text_wiki_destroy_confirmation: Sigur doriți ștergerea Wiki și a conținutului asociat? + text_issue_category_destroy_question: "Această categorie conține (%{count}) tichete. Ce doriți să faceți?" + text_issue_category_destroy_assignments: Șterge apartenența la categorie. + text_issue_category_reassign_to: Atribuie tichetele la această categorie + text_user_mail_option: "Pentru proiectele care nu sunt selectate, veți primi notificări doar pentru ceea ce urmăriți sau în ce sunteți implicat (ex: tichete create de dumneavoastră sau care vă sunt atribuite)." + text_no_configuration_data: "Nu s-au configurat încă rolurile, stările tichetelor și modurile de lucru.\nEste recomandat să încărcați configurația implicită. O veți putea modifica ulterior." + text_load_default_configuration: Încarcă configurația implicită + text_status_changed_by_changeset: "Aplicat în setul %{value}." + text_issues_destroy_confirmation: 'Sigur doriți să ștergeți tichetele selectate?' + text_select_project_modules: 'Selectați modulele active pentru acest proiect:' + text_default_administrator_account_changed: S-a schimbat contul administratorului implicit + text_file_repository_writable: Se poate scrie în directorul de atașamente + text_plugin_assets_writable: Se poate scrie în directorul de plugin-uri + text_rmagick_available: Este disponibil RMagick (opțional) + text_destroy_time_entries_question: "%{hours} ore sunt înregistrate la tichetele pe care doriți să le ștergeți. Ce doriți sa faceți?" + text_destroy_time_entries: Șterge orele înregistrate + text_assign_time_entries_to_project: Atribuie orele la proiect + text_reassign_time_entries: 'Atribuie orele înregistrate la tichetul:' + text_user_wrote: "%{value} a scris:" + text_enumeration_destroy_question: "Această valoare are %{count} obiecte." + text_enumeration_category_reassign_to: 'Atribuie la această valoare:' + text_email_delivery_not_configured: "Trimiterea de emailuri nu este configurată și ca urmare, notificările sunt dezactivate.\nConfigurați serverul SMTP în config/configuration.yml și reporniți aplicația pentru a le activa." + text_repository_usernames_mapping: "Selectați sau modificați contul Redmine echivalent contului din istoricul depozitului.\nUtilizatorii cu un cont (sau e-mail) identic în Redmine și depozit sunt echivalate automat." + text_diff_truncated: '... Comparația a fost trunchiată pentru ca depășește lungimea maximă de text care poate fi afișat.' + text_custom_field_possible_values_info: 'O linie pentru fiecare valoare' + + default_role_manager: Manager + default_role_developer: Dezvoltator + default_role_reporter: Creator de rapoarte + default_tracker_bug: Defect + default_tracker_feature: Funcție + default_tracker_support: Suport + default_issue_status_new: Nou + default_issue_status_in_progress: In Progress + default_issue_status_resolved: Rezolvat + default_issue_status_feedback: Așteaptă reacții + default_issue_status_closed: Închis + default_issue_status_rejected: Respins + default_doc_category_user: Documentație + default_doc_category_tech: Documentație tehnică + default_priority_low: mică + default_priority_normal: normală + default_priority_high: mare + default_priority_urgent: urgentă + default_priority_immediate: imediată + default_activity_design: Design + default_activity_development: Dezvoltare + + enumeration_issue_priorities: Priorități tichete + enumeration_doc_categories: Categorii documente + enumeration_activities: Activități (timp de lucru) + label_greater_or_equal: ">=" + label_less_or_equal: <= + text_wiki_page_destroy_question: Această pagină are %{descendants} pagini anterioare și descendenți. Ce doriți să faceți? + text_wiki_page_reassign_children: Atribuie paginile la această pagină + text_wiki_page_nullify_children: Menține paginile ca și pagini inițiale (root) + text_wiki_page_destroy_children: Șterge paginile și descendenții + setting_password_min_length: Lungime minimă parolă + field_group_by: Grupează după + mail_subject_wiki_content_updated: "Pagina wiki '%{id}' a fost actualizată" + label_wiki_content_added: Adăugat + mail_subject_wiki_content_added: "Pagina wiki '%{id}' a fost adăugată" + mail_body_wiki_content_added: Pagina wiki '%{id}' a fost adăugată de %{author}. + label_wiki_content_updated: Actualizat + mail_body_wiki_content_updated: Pagina wiki '%{id}' a fost actualizată de %{author}. + permission_add_project: Crează proiect + setting_new_project_user_role_id: Rol atribuit utilizatorului non-admin care crează un proiect. + label_view_all_revisions: Arată toate reviziile + label_tag: Tag + label_branch: Branch + error_no_tracker_in_project: Nu există un tracker asociat cu proiectul. Verificați vă rog setările proiectului. + error_no_default_issue_status: Nu există un status implicit al tichetelor. Verificați vă rog configurația (Mergeți la "Administrare -> Stări tichete"). + text_journal_changed: "%{label} schimbat din %{old} în %{new}" + text_journal_set_to: "%{label} setat ca %{value}" + text_journal_deleted: "%{label} șters (%{old})" + label_group_plural: Grupuri + label_group: Grup + label_group_new: Grup nou + label_time_entry_plural: Timp alocat + text_journal_added: "%{label} %{value} added" + field_active: Active + enumeration_system_activity: System Activity + permission_delete_issue_watchers: Delete watchers + version_status_closed: closed + version_status_locked: locked + version_status_open: open + error_can_not_reopen_issue_on_closed_version: An issue assigned to a closed version can not be reopened + label_user_anonymous: Anonymous + button_move_and_follow: Move and follow + setting_default_projects_modules: Default enabled modules for new projects + setting_gravatar_default: Default Gravatar image + field_sharing: Sharing + label_version_sharing_hierarchy: With project hierarchy + label_version_sharing_system: With all projects + label_version_sharing_descendants: With subprojects + label_version_sharing_tree: With project tree + label_version_sharing_none: Not shared + error_can_not_archive_project: This project can not be archived + button_duplicate: Duplicate + button_copy_and_follow: Copy and follow + label_copy_source: Source + setting_issue_done_ratio: Calculate the issue done ratio with + setting_issue_done_ratio_issue_status: Use the issue status + error_issue_done_ratios_not_updated: Issue done ratios not updated. + error_workflow_copy_target: Please select target tracker(s) and role(s) + setting_issue_done_ratio_issue_field: Use the issue field + label_copy_same_as_target: Same as target + label_copy_target: Target + notice_issue_done_ratios_updated: Issue done ratios updated. + error_workflow_copy_source: Please select a source tracker or role + label_update_issue_done_ratios: Update issue done ratios + setting_start_of_week: Start calendars on + permission_view_issues: View Issues + label_display_used_statuses_only: Only display statuses that are used by this tracker + label_revision_id: Revision %{value} + label_api_access_key: API access key + label_api_access_key_created_on: API access key created %{value} ago + label_feeds_access_key: RSS access key + notice_api_access_key_reseted: Your API access key was reset. + setting_rest_api_enabled: Enable REST web service + label_missing_api_access_key: Missing an API access key + label_missing_feeds_access_key: Missing a RSS access key + button_show: Show + text_line_separated: Multiple values allowed (one line for each value). + setting_mail_handler_body_delimiters: Truncate emails after one of these lines + permission_add_subprojects: Create subprojects + label_subproject_new: New subproject + text_own_membership_delete_confirmation: |- + You are about to remove some or all of your permissions and may no longer be able to edit this project after that. + Are you sure you want to continue? + label_close_versions: Close completed versions + label_board_sticky: Sticky + label_board_locked: Locked + permission_export_wiki_pages: Export wiki pages + setting_cache_formatted_text: Cache formatted text + permission_manage_project_activities: Manage project activities + error_unable_delete_issue_status: Unable to delete issue status + label_profile: Profile + permission_manage_subtasks: Manage subtasks + field_parent_issue: Parent task + label_subtask_plural: Subtasks + label_project_copy_notifications: Send email notifications during the project copy + error_can_not_delete_custom_field: Unable to delete custom field + error_unable_to_connect: Unable to connect (%{value}) + error_can_not_remove_role: This role is in use and can not be deleted. + error_can_not_delete_tracker: This tracker contains issues and can't be deleted. + field_principal: Principal + label_my_page_block: My page block + notice_failed_to_save_members: "Failed to save member(s): %{errors}." + text_zoom_out: Zoom out + text_zoom_in: Zoom in + notice_unable_delete_time_entry: Unable to delete time log entry. + label_overall_spent_time: Overall spent time + field_time_entries: Log time + project_module_gantt: Gantt + project_module_calendar: Calendar + button_edit_associated_wikipage: "Edit associated Wiki page: %{page_title}" + field_text: Text field + label_user_mail_option_only_owner: Only for things I am the owner of + setting_default_notification_option: Default notification option + label_user_mail_option_only_my_events: Only for things I watch or I'm involved in + label_user_mail_option_only_assigned: Only for things I am assigned to + label_user_mail_option_none: No events + field_member_of_group: Assignee's group + field_assigned_to_role: Assignee's role + notice_not_authorized_archived_project: The project you're trying to access has been archived. + label_principal_search: "Search for user or group:" + label_user_search: "Search for user:" + field_visible: Visible + setting_commit_logtime_activity_id: Activity for logged time + text_time_logged_by_changeset: Applied in changeset %{value}. + setting_commit_logtime_enabled: Enable time logging + notice_gantt_chart_truncated: The chart was truncated because it exceeds the maximum number of items that can be displayed (%{max}) + setting_gantt_items_limit: Maximum number of items displayed on the gantt chart + field_warn_on_leaving_unsaved: Warn me when leaving a page with unsaved text + text_warn_on_leaving_unsaved: The current page contains unsaved text that will be lost if you leave this page. + label_my_queries: My custom queries + text_journal_changed_no_detail: "%{label} updated" + label_news_comment_added: Comment added to a news + button_expand_all: Expand all + button_collapse_all: Collapse all + label_additional_workflow_transitions_for_assignee: Additional transitions allowed when the user is the assignee + label_additional_workflow_transitions_for_author: Additional transitions allowed when the user is the author + label_bulk_edit_selected_time_entries: Bulk edit selected time entries + text_time_entries_destroy_confirmation: Are you sure you want to delete the selected time entr(y/ies)? + label_role_anonymous: Anonymous + label_role_non_member: Non member + label_issue_note_added: Note added + label_issue_status_updated: Status updated + label_issue_priority_updated: Priority updated + label_issues_visibility_own: Issues created by or assigned to the user + field_issues_visibility: Issues visibility + label_issues_visibility_all: All issues + permission_set_own_issues_private: Set own issues public or private + field_is_private: Private + permission_set_issues_private: Set issues public or private + label_issues_visibility_public: All non private issues + text_issues_destroy_descendants_confirmation: This will also delete %{count} subtask(s). + field_commit_logs_encoding: Codare pentru mesaje + field_scm_path_encoding: Path encoding + text_scm_path_encoding_note: "Default: UTF-8" + field_path_to_repository: Path to repository + field_root_directory: Root directory + field_cvs_module: Module + field_cvsroot: CVSROOT + text_mercurial_repository_note: Local repository (e.g. /hgrepo, c:\hgrepo) + text_scm_command: Command + text_scm_command_version: Version + label_git_report_last_commit: Report last commit for files and directories + notice_issue_successful_create: Issue %{id} created. + label_between: between + setting_issue_group_assignment: Allow issue assignment to groups + label_diff: diff + text_git_repository_note: Repository is bare and local (e.g. /gitrepo, c:\gitrepo) + description_query_sort_criteria_direction: Sort direction + description_project_scope: Search scope + description_filter: Filter + description_user_mail_notification: Mail notification settings + description_date_from: Enter start date + description_message_content: Message content + description_available_columns: Available Columns + description_date_range_interval: Choose range by selecting start and end date + description_issue_category_reassign: Choose issue category + description_search: Searchfield + description_notes: Notes + description_date_range_list: Choose range from list + description_choose_project: Projects + description_date_to: Enter end date + description_query_sort_criteria_attribute: Sort attribute + description_wiki_subpages_reassign: Choose new parent page + description_selected_columns: Selected Columns + label_parent_revision: Parent + label_child_revision: Child + error_scm_annotate_big_text_file: The entry cannot be annotated, as it exceeds the maximum text file size. + setting_default_issue_start_date_to_creation_date: Use current date as start date for new issues + button_edit_section: Edit this section + setting_repositories_encodings: Attachments and repositories encodings + description_all_columns: All Columns + button_export: Export + label_export_options: "%{export_format} export options" + error_attachment_too_big: This file cannot be uploaded because it exceeds the maximum allowed file size (%{max_size}) + notice_failed_to_save_time_entries: "Failed to save %{count} time entrie(s) on %{total} selected: %{ids}." + label_x_issues: + zero: 0 tichet + one: 1 tichet + other: "%{count} tichete" + label_repository_new: New repository + field_repository_is_default: Main repository + label_copy_attachments: Copy attachments + label_item_position: "%{position}/%{count}" + label_completed_versions: Completed versions + text_project_identifier_info: Only lower case letters (a-z), numbers, dashes and underscores are allowed.
    Once saved, the identifier cannot be changed. + field_multiple: Multiple values + setting_commit_cross_project_ref: Allow issues of all the other projects to be referenced and fixed + text_issue_conflict_resolution_add_notes: Add my notes and discard my other changes + text_issue_conflict_resolution_overwrite: Apply my changes anyway (previous notes will be kept but some changes may be overwritten) + notice_issue_update_conflict: The issue has been updated by an other user while you were editing it. + text_issue_conflict_resolution_cancel: Discard all my changes and redisplay %{link} + permission_manage_related_issues: Manage related issues + field_auth_source_ldap_filter: LDAP filter + label_search_for_watchers: Search for watchers to add + notice_account_deleted: Your account has been permanently deleted. + setting_unsubscribe: Allow users to delete their own account + button_delete_my_account: Delete my account + text_account_destroy_confirmation: |- + Are you sure you want to proceed? + Your account will be permanently deleted, with no way to reactivate it. + error_session_expired: Your session has expired. Please login again. + text_session_expiration_settings: "Warning: changing these settings may expire the current sessions including yours." + setting_session_lifetime: Session maximum lifetime + setting_session_timeout: Session inactivity timeout + label_session_expiration: Session expiration + permission_close_project: Close / reopen the project + label_show_closed_projects: View closed projects + button_close: Close + button_reopen: Reopen + project_status_active: active + project_status_closed: closed + project_status_archived: archived + text_project_closed: This project is closed and read-only. + notice_user_successful_create: User %{id} created. + field_core_fields: Standard fields + field_timeout: Timeout (in seconds) + setting_thumbnails_enabled: Display attachment thumbnails + setting_thumbnails_size: Thumbnails size (in pixels) + label_status_transitions: Status transitions + label_fields_permissions: Fields permissions + label_readonly: Read-only + label_required: Required + text_repository_identifier_info: Only lower case letters (a-z), numbers, dashes and underscores are allowed.
    Once saved, the identifier cannot be changed. + field_board_parent: Parent forum + label_attribute_of_project: Project's %{name} + label_attribute_of_author: Author's %{name} + label_attribute_of_assigned_to: Assignee's %{name} + label_attribute_of_fixed_version: Target version's %{name} + label_copy_subtasks: Copy subtasks + label_copied_to: copied to + label_copied_from: copied from + label_any_issues_in_project: any issues in project + label_any_issues_not_in_project: any issues not in project + field_private_notes: Private notes + permission_view_private_notes: View private notes + permission_set_notes_private: Set notes as private + label_no_issues_in_project: no issues in project + label_any: toate + label_last_n_weeks: last %{count} weeks + setting_cross_project_subtasks: Allow cross-project subtasks + label_cross_project_descendants: With subprojects + label_cross_project_tree: With project tree + label_cross_project_hierarchy: With project hierarchy + label_cross_project_system: With all projects + button_hide: Hide + setting_non_working_week_days: Non-working days + label_in_the_next_days: in the next + label_in_the_past_days: in the past + label_attribute_of_user: User's %{name} + text_turning_multiple_off: If you disable multiple values, multiple values will be + removed in order to preserve only one value per item. + label_attribute_of_issue: Issue's %{name} + permission_add_documents: Add documents + permission_edit_documents: Edit documents + permission_delete_documents: Delete documents + label_gantt_progress_line: Progress line + setting_jsonp_enabled: Enable JSONP support + field_inherit_members: Inherit members + field_closed_on: Closed + setting_default_projects_tracker_ids: Default trackers for new projects + label_total_time: Total + text_scm_config: You can configure your SCM commands in config/configuration.yml. Please restart the application after editing it. + text_scm_command_not_available: SCM command is not available. Please check settings on the administration panel. + setting_emails_header: Email header diff --git a/config/locales/ru.yml b/config/locales/ru.yml new file mode 100644 index 00000000..634b5777 --- /dev/null +++ b/config/locales/ru.yml @@ -0,0 +1,1199 @@ +# Russian localization for Ruby on Rails 2.2+ +# by Yaroslav Markin +# +# Be sure to check out "russian" gem (http://github.com/yaroslav/russian) for +# full Russian language support in Rails (month names, pluralization, etc). +# The following is an excerpt from that gem. +# +# Для полноценной поддержки русского языка (варианты названий месяцев, +# плюрализация и так далее) в Rails 2.2 нужно использовать gem "russian" +# (http://github.com/yaroslav/russian). Следующие данные -- выдержка их него, чтобы +# была возможность минимальной локализации приложения на русский язык. + +ru: + direction: ltr + date: + formats: + default: "%d.%m.%Y" + short: "%d %b" + long: "%d %B %Y" + + day_names: [воскресенье, понедельник, вторник, среда, четверг, пятница, суббота] + standalone_day_names: [Воскресенье, Понедельник, Вторник, Среда, Четверг, Пятница, Суббота] + abbr_day_names: [Вс, Пн, Вт, Ср, Чт, Пт, Сб] + + month_names: [~, января, февраля, марта, апреля, мая, июня, июля, августа, сентября, октября, ноября, декабря] + # see russian gem for info on "standalone" day names + standalone_month_names: [~, Январь, Февраль, Март, Апрель, Май, Июнь, Июль, Август, Сентябрь, Октябрь, Ноябрь, Декабрь] + abbr_month_names: [~, янв., февр., марта, апр., мая, июня, июля, авг., сент., окт., нояб., дек.] + standalone_abbr_month_names: [~, янв., февр., март, апр., май, июнь, июль, авг., сент., окт., нояб., дек.] + + order: + - :day + - :month + - :year + + time: + formats: + default: "%a, %d %b %Y, %H:%M:%S %z" + time: "%H:%M" + short: "%d %b, %H:%M" + long: "%d %B %Y, %H:%M" + + am: "утра" + pm: "вечера" + + number: + format: + separator: "," + delimiter: " " + precision: 3 + + currency: + format: + format: "%n %u" + unit: "руб." + separator: "." + delimiter: " " + precision: 2 + + percentage: + format: + delimiter: "" + + precision: + format: + delimiter: "" + + human: + format: + delimiter: "" + precision: 3 + # Rails 2.2 + # storage_units: [байт, КБ, МБ, ГБ, ТБ] + + # Rails 2.3 + storage_units: + # Storage units output formatting. + # %u is the storage unit, %n is the number (default: 2 MB) + format: "%n %u" + units: + byte: + one: "байт" + few: "байта" + many: "байт" + other: "байта" + kb: "КБ" + mb: "МБ" + gb: "ГБ" + tb: "ТБ" + + datetime: + distance_in_words: + half_a_minute: "меньше минуты" + less_than_x_seconds: + one: "меньше %{count} секунды" + few: "меньше %{count} секунд" + many: "меньше %{count} секунд" + other: "меньше %{count} секунды" + x_seconds: + one: "%{count} секунда" + few: "%{count} секунды" + many: "%{count} секунд" + other: "%{count} секунды" + less_than_x_minutes: + one: "меньше %{count} минуты" + few: "меньше %{count} минут" + many: "меньше %{count} минут" + other: "меньше %{count} минуты" + x_minutes: + one: "%{count} минуту" + few: "%{count} минуты" + many: "%{count} минут" + other: "%{count} минуты" + about_x_hours: + one: "около %{count} часа" + few: "около %{count} часов" + many: "около %{count} часов" + other: "около %{count} часа" + x_hours: + one: "%{count} час" + few: "%{count} часа" + many: "%{count} часов" + other: "%{count} часа" + x_days: + one: "%{count} день" + few: "%{count} дня" + many: "%{count} дней" + other: "%{count} дня" + about_x_months: + one: "около %{count} месяца" + few: "около %{count} месяцев" + many: "около %{count} месяцев" + other: "около %{count} месяца" + x_months: + one: "%{count} месяц" + few: "%{count} месяца" + many: "%{count} месяцев" + other: "%{count} месяца" + about_x_years: + one: "около %{count} года" + few: "около %{count} лет" + many: "около %{count} лет" + other: "около %{count} лет" + over_x_years: + one: "больше %{count} года" + few: "больше %{count} лет" + many: "больше %{count} лет" + other: "больше %{count} лет" + almost_x_years: + one: "почти %{count} год" + few: "почти %{count} года" + many: "почти %{count} лет" + other: "почти %{count} года" + prompts: + year: "Год" + month: "Месяц" + day: "День" + hour: "Часов" + minute: "Минут" + second: "Секунд" + + activerecord: + errors: + template: + header: + one: "%{model}: сохранение не удалось из-за %{count} ошибки" + few: "%{model}: сохранение не удалось из-за %{count} ошибок" + many: "%{model}: сохранение не удалось из-за %{count} ошибок" + other: "%{model}: сохранение не удалось из-за %{count} ошибки" + + body: "Проблемы возникли со следующими полями:" + + messages: + inclusion: "имеет непредусмотренное значение" + exclusion: "имеет зарезервированное значение" + invalid: "имеет неверное значение" + confirmation: "не совпадает с подтверждением" + accepted: "нужно подтвердить" + empty: "не может быть пустым" + blank: "не может быть пустым" + too_long: + one: "слишком большой длины (не может быть больше чем %{count} символ)" + few: "слишком большой длины (не может быть больше чем %{count} символа)" + many: "слишком большой длины (не может быть больше чем %{count} символов)" + other: "слишком большой длины (не может быть больше чем %{count} символа)" + too_short: + one: "недостаточной длины (не может быть меньше %{count} символа)" + few: "недостаточной длины (не может быть меньше %{count} символов)" + many: "недостаточной длины (не может быть меньше %{count} символов)" + other: "недостаточной длины (не может быть меньше %{count} символа)" + wrong_length: + one: "неверной длины (может быть длиной ровно %{count} символ)" + few: "неверной длины (может быть длиной ровно %{count} символа)" + many: "неверной длины (может быть длиной ровно %{count} символов)" + other: "неверной длины (может быть длиной ровно %{count} символа)" + taken: "уже существует" + not_a_number: "не является числом" + greater_than: "может иметь значение большее %{count}" + greater_than_or_equal_to: "может иметь значение большее или равное %{count}" + equal_to: "может иметь лишь значение, равное %{count}" + less_than: "может иметь значение меньшее чем %{count}" + less_than_or_equal_to: "может иметь значение меньшее или равное %{count}" + odd: "может иметь лишь нечетное значение" + even: "может иметь лишь четное значение" + greater_than_start_date: "должна быть позднее даты начала" + not_same_project: "не относится к одному проекту" + circular_dependency: "Такая связь приведет к циклической зависимости" + cant_link_an_issue_with_a_descendant: "Задача не может быть связана со своей подзадачей" + + support: + array: + # Rails 2.2 + sentence_connector: "и" + skip_last_comma: true + + # Rails 2.3 + words_connector: ", " + two_words_connector: " и " + last_word_connector: " и " + + actionview_instancetag_blank_option: Выберите + + button_activate: Активировать + button_add: Добавить + button_annotate: Авторство + button_apply: Применить + button_archive: Архивировать + button_back: Назад + button_cancel: Отмена + button_change_password: Изменить пароль + button_change: Изменить + button_check_all: Отметить все + button_clear: Очистить + button_configure: Параметры + button_copy: Копировать + button_create: Создать + button_create_and_continue: Создать и продолжить + button_delete: Удалить + button_download: Загрузить + button_edit: Редактировать + button_edit_associated_wikipage: "Редактировать связанную wiki-страницу: %{page_title}" + button_list: Список + button_lock: Заблокировать + button_login: Вход + button_log_time: Затраченное время + button_move: Переместить + button_quote: Цитировать + button_rename: Переименовать + button_reply: Ответить + button_reset: Сбросить + button_rollback: Вернуться к данной версии + button_save: Сохранить + button_sort: Сортировать + button_submit: Принять + button_test: Проверить + button_unarchive: Разархивировать + button_uncheck_all: Очистить + button_unlock: Разблокировать + button_unwatch: Не следить + button_update: Обновить + button_view: Просмотреть + button_watch: Следить + + default_activity_design: Проектирование + default_activity_development: Разработка + default_doc_category_tech: Техническая документация + default_doc_category_user: Пользовательская документация + default_issue_status_in_progress: В работе + default_issue_status_closed: Закрыта + default_issue_status_feedback: Обратная связь + default_issue_status_new: Новая + default_issue_status_rejected: Отклонена + default_issue_status_resolved: Решена + default_priority_high: Высокий + default_priority_immediate: Немедленный + default_priority_low: Низкий + default_priority_normal: Нормальный + default_priority_urgent: Срочный + default_role_developer: Разработчик + default_role_manager: Менеджер + default_role_reporter: Репортёр + default_tracker_bug: Ошибка + default_tracker_feature: Улучшение + default_tracker_support: Поддержка + + enumeration_activities: Действия (учёт времени) + enumeration_doc_categories: Категории документов + enumeration_issue_priorities: Приоритеты задач + + error_can_not_remove_role: Эта роль используется и не может быть удалена. + error_can_not_delete_custom_field: Невозможно удалить настраиваемое поле + error_can_not_delete_tracker: Этот трекер содержит задачи и не может быть удален. + error_can_t_load_default_data: "Конфигурация по умолчанию не была загружена: %{value}" + error_issue_not_found_in_project: Задача не была найдена или не прикреплена к этому проекту + error_scm_annotate: "Данные отсутствуют или не могут быть подписаны." + error_scm_command_failed: "Ошибка доступа к хранилищу: %{value}" + error_scm_not_found: Хранилище не содержит записи и/или исправления. + error_unable_to_connect: Невозможно подключиться (%{value}) + error_unable_delete_issue_status: Невозможно удалить статус задачи + + field_account: Учётная запись + field_activity: Деятельность + field_admin: Администратор + field_assignable: Задача может быть назначена этой роли + field_assigned_to: Назначена + field_attr_firstname: Имя + field_attr_lastname: Фамилия + field_attr_login: Атрибут Login + field_attr_mail: email + field_author: Автор + field_auth_source: Режим аутентификации + field_base_dn: BaseDN + field_category: Категория + field_column_names: Столбцы + field_comments: Комментарий + field_comments_sorting: Отображение комментариев + field_content: Content + field_created_on: Создано + field_default_value: Значение по умолчанию + field_delay: Отложить + field_description: Описание + field_done_ratio: Готовность + field_downloads: Загрузки + field_due_date: Дата выполнения + field_editable: Редактируемое + field_effective_date: Дата + field_estimated_hours: Оценка времени + field_field_format: Формат + field_filename: Файл + field_filesize: Размер + field_firstname: Имя + field_fixed_version: Версия + field_hide_mail: Скрывать мой email + field_homepage: Стартовая страница + field_host: Компьютер + field_hours: час(а,ов) + field_identifier: Уникальный идентификатор + field_identity_url: OpenID URL + field_is_closed: Задача закрыта + field_is_default: Значение по умолчанию + field_is_filter: Используется в качестве фильтра + field_is_for_all: Для всех проектов + field_is_in_roadmap: Задачи, отображаемые в оперативном плане + field_is_public: Общедоступный + field_is_required: Обязательное + field_issue_to: Связанные задачи + field_issue: Задача + field_language: Язык + field_last_login_on: Последнее подключение + field_lastname: Фамилия + field_login: Пользователь + field_mail: Email + field_mail_notification: Уведомления по email + field_max_length: Максимальная длина + field_min_length: Минимальная длина + field_name: Имя + field_new_password: Новый пароль + field_notes: Примечания + field_onthefly: Создание пользователя на лету + field_parent_title: Родительская страница + field_parent: Родительский проект + field_parent_issue: Родительская задача + field_password_confirmation: Подтверждение + field_password: Пароль + field_port: Порт + field_possible_values: Возможные значения + field_priority: Приоритет + field_project: Проект + field_redirect_existing_links: Перенаправить существующие ссылки + field_regexp: Регулярное выражение + field_role: Роль + field_searchable: Доступно для поиска + field_spent_on: Дата + field_start_date: Начата + field_start_page: Стартовая страница + field_status: Статус + field_subject: Тема + field_subproject: Подпроект + field_summary: Краткое описание + field_text: Текстовое поле + field_time_entries: Затраченное время + field_time_zone: Часовой пояс + field_title: Заголовок + field_tracker: Трекер + field_type: Тип + field_updated_on: Обновлено + field_url: URL + field_user: Пользователь + field_value: Значение + field_version: Версия + field_watcher: Наблюдатель + + general_csv_decimal_separator: ',' + general_csv_encoding: UTF-8 + general_csv_separator: ';' + general_first_day_of_week: '1' + general_lang_name: 'Russian (Русский)' + general_pdf_encoding: UTF-8 + general_text_no: 'нет' + general_text_No: 'Нет' + general_text_yes: 'да' + general_text_Yes: 'Да' + + label_activity: Действия + label_add_another_file: Добавить ещё один файл + label_added_time_by: "Добавил(а) %{author} %{age} назад" + label_added: добавлено + label_add_note: Добавить замечание + label_administration: Администрирование + label_age: Возраст + label_ago: дней(я) назад + label_all_time: всё время + label_all_words: Все слова + label_all: все + label_and_its_subprojects: "%{value} и все подпроекты" + label_applied_status: Применимый статус + label_ascending: По возрастанию + label_assigned_to_me_issues: Мои задачи + label_associated_revisions: Связанные редакции + label_attachment: Файл + label_attachment_delete: Удалить файл + label_attachment_new: Новый файл + label_attachment_plural: Файлы + label_attribute: Атрибут + label_attribute_plural: Атрибуты + label_authentication: Аутентификация + label_auth_source: Режим аутентификации + label_auth_source_new: Новый режим аутентификации + label_auth_source_plural: Режимы аутентификации + label_blocked_by: блокируется + label_blocks: блокирует + label_board: Форум + label_board_new: Новый форум + label_board_plural: Форумы + label_boolean: Логический + label_browse: Обзор + label_bulk_edit_selected_issues: Редактировать все выбранные задачи + label_calendar: Календарь + label_calendar_filter: Включая + label_calendar_no_assigned: не мои + label_change_plural: Правки + label_change_properties: Изменить свойства + label_change_status: Изменить статус + label_change_view_all: Просмотреть все изменения + label_changes_details: Подробности по всем изменениям + label_changeset_plural: Изменения + label_chronological_order: В хронологическом порядке + label_closed_issues: закрыто + label_closed_issues_plural: закрыто + label_closed_issues_plural2: закрыто + label_closed_issues_plural5: закрыто + label_comment: комментарий + label_comment_add: Оставить комментарий + label_comment_added: Добавленный комментарий + label_comment_delete: Удалить комментарии + label_comment_plural: Комментарии + label_comment_plural2: комментария + label_comment_plural5: комментариев + label_commits_per_author: Изменений на пользователя + label_commits_per_month: Изменений в месяц + label_confirmation: Подтверждение + label_contains: содержит + label_copied: скопировано + label_copy_workflow_from: Скопировать последовательность действий из + label_current_status: Текущий статус + label_current_version: Текущая версия + label_custom_field: Настраиваемое поле + label_custom_field_new: Новое настраиваемое поле + label_custom_field_plural: Настраиваемые поля + label_date_from: С + label_date_from_to: С %{start} по %{end} + label_date_range: временной интервал + label_date_to: по + label_date: Дата + label_day_plural: дней(я) + label_default: По умолчанию + label_default_columns: Столбцы по умолчанию + label_deleted: удалено + label_descending: По убыванию + label_details: Подробности + label_diff_inline: в тексте + label_diff_side_by_side: рядом + label_disabled: отключено + label_display: Отображение + label_display_per_page: "На страницу: %{value}" + label_document: Документ + label_document_added: Добавлен документ + label_document_new: Новый документ + label_document_plural: Документы + label_downloads_abbr: Скачиваний + label_duplicated_by: дублируется + label_duplicates: дублирует + label_end_to_end: с конца к концу + label_end_to_start: с конца к началу + label_enumeration_new: Новое значение + label_enumerations: Списки значений + label_environment: Окружение + label_equals: соответствует + label_example: Пример + label_export_to: Экспортировать в + label_feed_plural: RSS + label_feeds_access_key_created_on: "Ключ доступа RSS создан %{value} назад" + label_f_hour: "%{value} час" + label_f_hour_plural: "%{value} часов" + label_file_added: Добавлен файл + label_file_plural: Файлы + label_filter_add: Добавить фильтр + label_filter_plural: Фильтры + label_float: С плавающей точкой + label_follows: предыдущая + label_gantt: Диаграмма Ганта + label_general: Общее + label_generate_key: Сгенерировать ключ + label_greater_or_equal: ">=" + label_help: Помощь + label_history: История + label_home: Домашняя страница + label_incoming_emails: Приём сообщений + label_index_by_date: История страниц + label_index_by_title: Оглавление + label_information_plural: Информация + label_information: Информация + label_in_less_than: менее чем + label_in_more_than: более чем + label_integer: Целый + label_internal: Внутренний + label_in: в + label_issue: Задача + label_issue_added: Добавлена задача + label_issue_category_new: Новая категория + label_issue_category_plural: Категории задачи + label_issue_category: Категория задачи + label_issue_new: Новая задача + label_issue_plural: Задачи + label_issues_by: "Сортировать по %{value}" + label_issue_status_new: Новый статус + label_issue_status_plural: Статусы задач + label_issue_status: Статус задачи + label_issue_tracking: Задачи + label_issue_updated: Обновлена задача + label_issue_view_all: Просмотреть все задачи + label_issue_watchers: Наблюдатели + label_jump_to_a_project: Перейти к проекту... + label_language_based: На основе языка + label_last_changes: "менее %{count} изменений" + label_last_login: Последнее подключение + label_last_month: последний месяц + label_last_n_days: "последние %{count} дней" + label_last_week: последняя неделя + label_latest_revision: Последняя редакция + label_latest_revision_plural: Последние редакции + label_ldap_authentication: Авторизация с помощью LDAP + label_less_or_equal: <= + label_less_than_ago: менее, чем дней(я) назад + label_list: Список + label_loading: Загрузка... + label_logged_as: Вошли как + label_login: Войти + label_login_with_open_id_option: или войти с помощью OpenID + label_logout: Выйти + label_max_size: Максимальный размер + label_member_new: Новый участник + label_member: Участник + label_member_plural: Участники + label_message_last: Последнее сообщение + label_message_new: Новое сообщение + label_message_plural: Сообщения + label_message_posted: Добавлено сообщение + label_me: мне + label_min_max_length: Минимальная - максимальная длина + label_modified: изменено + label_module_plural: Модули + label_months_from: месяцев(ца) с + label_month: Месяц + label_more_than_ago: более, чем дней(я) назад + label_more: Больше + label_my_account: Моя учётная запись + label_my_page: Моя страница + label_my_page_block: Блок моей страницы + label_my_projects: Мои проекты + label_new: Новый + label_new_statuses_allowed: Разрешенные новые статусы + label_news_added: Добавлена новость + label_news_latest: Последние новости + label_news_new: Добавить новость + label_news_plural: Новости + label_news_view_all: Посмотреть все новости + label_news: Новости + label_next: Следующее + label_nobody: никто + label_no_change_option: (Нет изменений) + label_no_data: Нет данных для отображения + label_none: отсутствует + label_not_contains: не содержит + label_not_equals: не соответствует + label_open_issues: открыто + label_open_issues_plural: открыто + label_open_issues_plural2: открыто + label_open_issues_plural5: открыто + label_optional_description: Описание (необязательно) + label_options: Опции + label_overall_activity: Сводный отчёт действий + label_overview: Обзор + label_password_lost: Восстановление пароля + label_permissions_report: Отчёт по правам доступа + label_permissions: Права доступа + label_per_page: На страницу + label_personalize_page: Персонализировать данную страницу + label_planning: Планирование + label_please_login: Пожалуйста, войдите. + label_plugins: Модули + label_precedes: следующая + label_preferences: Предпочтения + label_preview: Предпросмотр + label_previous: Предыдущее + label_profile: Профиль + label_project: Проект + label_project_all: Все проекты + label_project_copy_notifications: Отправлять уведомления по электронной почте при копировании проекта + label_project_latest: Последние проекты + label_project_new: Новый проект + label_project_plural: Проекты + label_project_plural2: проекта + label_project_plural5: проектов + label_public_projects: Общие проекты + label_query: Сохранённый запрос + label_query_new: Новый запрос + label_query_plural: Сохранённые запросы + label_read: Чтение... + label_register: Регистрация + label_registered_on: Зарегистрирован(а) + label_registration_activation_by_email: активация учётных записей по email + label_registration_automatic_activation: автоматическая активация учётных записей + label_registration_manual_activation: активировать учётные записи вручную + label_related_issues: Связанные задачи + label_relates_to: связана с + label_relation_delete: Удалить связь + label_relation_new: Новое отношение + label_renamed: переименовано + label_reply_plural: Ответы + label_report: Отчёт + label_report_plural: Отчёты + label_reported_issues: Созданные задачи + label_repository: Хранилище + label_repository_plural: Хранилища + label_result_plural: Результаты + label_reverse_chronological_order: В обратном порядке + label_revision: Редакция + label_revision_plural: Редакции + label_roadmap: Оперативный план + label_roadmap_due_in: "В срок %{value}" + label_roadmap_no_issues: Нет задач для данной версии + label_roadmap_overdue: "опоздание %{value}" + label_role: Роль + label_role_and_permissions: Роли и права доступа + label_role_new: Новая роль + label_role_plural: Роли + label_scm: Тип хранилища + label_search: Поиск + label_search_titles_only: Искать только в названиях + label_send_information: Отправить пользователю информацию по учётной записи + label_send_test_email: Послать email для проверки + label_settings: Настройки + label_show_completed_versions: Показывать завершённые версии + label_sort: Сортировать + label_sort_by: "Сортировать по %{value}" + label_sort_higher: Вверх + label_sort_highest: В начало + label_sort_lower: Вниз + label_sort_lowest: В конец + label_spent_time: Затраченное время + label_start_to_end: с начала к концу + label_start_to_start: с начала к началу + label_statistics: Статистика + label_stay_logged_in: Оставаться в системе + label_string: Текст + label_subproject_plural: Подпроекты + label_subtask_plural: Подзадачи + label_text: Длинный текст + label_theme: Тема + label_this_month: этот месяц + label_this_week: на этой неделе + label_this_year: этот год + label_time_tracking: Учёт времени + label_timelog_today: Расход времени на сегодня + label_today: сегодня + label_topic_plural: Темы + label_total: Всего + label_tracker: Трекер + label_tracker_new: Новый трекер + label_tracker_plural: Трекеры + label_updated_time: "Обновлено %{value} назад" + label_updated_time_by: "Обновлено %{author} %{age} назад" + label_used_by: Используется + label_user: Пользователь + label_user_activity: "Действия пользователя %{value}" + label_user_mail_no_self_notified: "Не извещать об изменениях, которые я сделал сам" + label_user_mail_option_all: "О всех событиях во всех моих проектах" + label_user_mail_option_selected: "О всех событиях только в выбранном проекте..." + label_user_mail_option_only_owner: Только для объектов, для которых я являюсь владельцем + label_user_mail_option_only_my_events: Только для объектов, которые я отслеживаю или в которых участвую + label_user_mail_option_only_assigned: Только для объектов, которые назначены мне + label_user_new: Новый пользователь + label_user_plural: Пользователи + label_version: Версия + label_version_new: Новая версия + label_version_plural: Версии + label_view_diff: Просмотреть отличия + label_view_revisions: Просмотреть редакции + label_watched_issues: Отслеживаемые задачи + label_week: Неделя + label_wiki: Wiki + label_wiki_edit: Редактирование Wiki + label_wiki_edit_plural: Wiki + label_wiki_page: Страница Wiki + label_wiki_page_plural: Страницы Wiki + label_workflow: Последовательность действий + label_x_closed_issues_abbr: + zero: "0 закрыто" + one: "1 закрыт" + few: "%{count} закрыто" + many: "%{count} закрыто" + other: "%{count} закрыто" + label_x_comments: + zero: "нет комментариев" + one: "1 комментарий" + few: "%{count} комментария" + many: "%{count} комментариев" + other: "%{count} комментариев" + label_x_open_issues_abbr: + zero: "0 открыто" + one: "1 открыт" + few: "%{count} открыто" + many: "%{count} открыто" + other: "%{count} открыто" + label_x_open_issues_abbr_on_total: + zero: "0 открыто / %{total}" + one: "1 открыт / %{total}" + few: "%{count} открыто / %{total}" + many: "%{count} открыто / %{total}" + other: "%{count} открыто / %{total}" + label_x_projects: + zero: "нет проектов" + one: "1 проект" + few: "%{count} проекта" + many: "%{count} проектов" + other: "%{count} проектов" + label_year: Год + label_yesterday: вчера + + mail_body_account_activation_request: "Зарегистрирован новый пользователь (%{value}). Учётная запись ожидает Вашего утверждения:" + mail_body_account_information: Информация о Вашей учётной записи + mail_body_account_information_external: "Вы можете использовать Вашу %{value} учётную запись для входа." + mail_body_lost_password: 'Для изменения пароля пройдите по следующей ссылке:' + mail_body_register: 'Для активации учётной записи пройдите по следующей ссылке:' + mail_body_reminder: "%{count} назначенных на Вас задач на следующие %{days} дней:" + mail_subject_account_activation_request: "Запрос на активацию пользователя в системе %{value}" + mail_subject_lost_password: "Ваш %{value} пароль" + mail_subject_register: "Активация учётной записи %{value}" + mail_subject_reminder: "%{count} назначенных на Вас задач в ближайшие %{days} дней" + + notice_account_activated: Ваша учётная запись активирована. Вы можете войти. + notice_account_invalid_creditentials: Неправильное имя пользователя или пароль + notice_account_lost_email_sent: Вам отправлено письмо с инструкциями по выбору нового пароля. + notice_account_password_updated: Пароль успешно обновлён. + notice_account_pending: "Ваша учётная запись создана и ожидает подтверждения администратора." + notice_account_register_done: Учётная запись успешно создана. Для активации Вашей учётной записи пройдите по ссылке, которая выслана Вам по электронной почте. + notice_account_unknown_email: Неизвестный пользователь. + notice_account_updated: Учётная запись успешно обновлена. + notice_account_wrong_password: Неверный пароль + notice_can_t_change_password: Для данной учётной записи используется источник внешней аутентификации. Невозможно изменить пароль. + notice_default_data_loaded: Была загружена конфигурация по умолчанию. + notice_email_error: "Во время отправки письма произошла ошибка (%{value})" + notice_email_sent: "Отправлено письмо %{value}" + notice_failed_to_save_issues: "Не удалось сохранить %{count} пункт(ов) из %{total} выбранных: %{ids}." + notice_failed_to_save_members: "Не удалось сохранить участника(ов): %{errors}." + notice_feeds_access_key_reseted: Ваш ключ доступа RSS был сброшен. + notice_file_not_found: Страница, на которую Вы пытаетесь зайти, не существует или удалена. + notice_locking_conflict: Информация обновлена другим пользователем. + notice_no_issue_selected: "Не выбрано ни одной задачи! Пожалуйста, отметьте задачи, которые Вы хотите отредактировать." + notice_not_authorized: У Вас нет прав для посещения данной страницы. + notice_successful_connection: Подключение успешно установлено. + notice_successful_create: Создание успешно. + notice_successful_delete: Удаление успешно. + notice_successful_update: Обновление успешно. + notice_unable_delete_version: Невозможно удалить версию. + + permission_add_issues: Добавление задач + permission_add_issue_notes: Добавление примечаний + permission_add_issue_watchers: Добавление наблюдателей + permission_add_messages: Отправка сообщений + permission_browse_repository: Просмотр хранилища + permission_comment_news: Комментирование новостей + permission_commit_access: Изменение файлов в хранилище + permission_delete_issues: Удаление задач + permission_delete_messages: Удаление сообщений + permission_delete_own_messages: Удаление собственных сообщений + permission_delete_wiki_pages: Удаление wiki-страниц + permission_delete_wiki_pages_attachments: Удаление прикреплённых файлов + permission_edit_issue_notes: Редактирование примечаний + permission_edit_issues: Редактирование задач + permission_edit_messages: Редактирование сообщений + permission_edit_own_issue_notes: Редактирование собственных примечаний + permission_edit_own_messages: Редактирование собственных сообщений + permission_edit_own_time_entries: Редактирование собственного учёта времени + permission_edit_project: Редактирование проектов + permission_edit_time_entries: Редактирование учёта времени + permission_edit_wiki_pages: Редактирование wiki-страниц + permission_export_wiki_pages: Экспорт wiki-страниц + permission_log_time: Учёт затраченного времени + permission_view_changesets: Просмотр изменений хранилища + permission_view_time_entries: Просмотр затраченного времени + permission_manage_project_activities: Управление типами действий для проекта + permission_manage_boards: Управление форумами + permission_manage_categories: Управление категориями задач + permission_manage_files: Управление файлами + permission_manage_issue_relations: Управление связыванием задач + permission_manage_members: Управление участниками + permission_manage_news: Управление новостями + permission_manage_public_queries: Управление общими запросами + permission_manage_repository: Управление хранилищем + permission_manage_subtasks: Управление подзадачами + permission_manage_versions: Управление версиями + permission_manage_wiki: Управление Wiki + permission_move_issues: Перенос задач + permission_protect_wiki_pages: Блокирование wiki-страниц + permission_rename_wiki_pages: Переименование wiki-страниц + permission_save_queries: Сохранение запросов + permission_select_project_modules: Выбор модулей проекта + permission_view_calendar: Просмотр календаря + permission_view_documents: Просмотр документов + permission_view_files: Просмотр файлов + permission_view_gantt: Просмотр диаграммы Ганта + permission_view_issue_watchers: Просмотр списка наблюдателей + permission_view_messages: Просмотр сообщений + permission_view_wiki_edits: Просмотр истории Wiki + permission_view_wiki_pages: Просмотр Wiki + + project_module_boards: Форумы + project_module_documents: Документы + project_module_files: Файлы + project_module_issue_tracking: Задачи + project_module_news: Новости + project_module_repository: Хранилище + project_module_time_tracking: Учёт времени + project_module_wiki: Wiki + project_module_gantt: Диаграмма Ганта + project_module_calendar: Календарь + + setting_activity_days_default: Количество дней, отображаемых в Действиях + setting_app_subtitle: Подзаголовок приложения + setting_app_title: Название приложения + setting_attachment_max_size: Максимальный размер вложения + setting_autofetch_changesets: Автоматически следить за изменениями хранилища + setting_autologin: Автоматический вход + setting_bcc_recipients: Использовать скрытые копии (BCC) + setting_cache_formatted_text: Кешировать форматированный текст + setting_commit_fix_keywords: Назначение ключевых слов + setting_commit_ref_keywords: Ключевые слова для поиска + setting_cross_project_issue_relations: Разрешить пересечение задач по проектам + setting_date_format: Формат даты + setting_default_language: Язык по умолчанию + setting_default_notification_option: Способ оповещения по умолчанию + setting_default_projects_public: Новые проекты являются общедоступными + setting_diff_max_lines_displayed: Максимальное число строк для diff + setting_display_subprojects_issues: Отображение подпроектов по умолчанию + setting_emails_footer: Подстрочные примечания письма + setting_enabled_scm: Включённые SCM + setting_feeds_limit: Ограничение количества заголовков для RSS потока + setting_file_max_size_displayed: Максимальный размер текстового файла для отображения + setting_gravatar_enabled: Использовать аватар пользователя из Gravatar + setting_host_name: Имя компьютера + setting_issue_list_default_columns: Столбцы, отображаемые в списке задач по умолчанию + setting_issues_export_limit: Ограничение по экспортируемым задачам + setting_login_required: Необходима аутентификация + setting_mail_from: Исходящий email адрес + setting_mail_handler_api_enabled: Включить веб-сервис для входящих сообщений + setting_mail_handler_api_key: API ключ + setting_openid: Разрешить OpenID для входа и регистрации + setting_per_page_options: Количество записей на страницу + setting_plain_text_mail: Только простой текст (без HTML) + setting_protocol: Протокол + setting_repository_log_display_limit: Максимальное количество редакций, отображаемых в журнале изменений + setting_self_registration: Саморегистрация + setting_sequential_project_identifiers: Генерировать последовательные идентификаторы проектов + setting_sys_api_enabled: Включить веб-сервис для управления хранилищем + setting_text_formatting: Форматирование текста + setting_time_format: Формат времени + setting_user_format: Формат отображения имени + setting_welcome_text: Текст приветствия + setting_wiki_compression: Сжатие истории Wiki + + status_active: активен + status_locked: заблокирован + status_registered: зарегистрирован + + text_are_you_sure: Вы уверены? + text_assign_time_entries_to_project: Прикрепить зарегистрированное время к проекту + text_caracters_maximum: "Максимум %{count} символов(а)." + text_caracters_minimum: "Должно быть не менее %{count} символов." + text_comma_separated: Допустимы несколько значений (через запятую). + text_custom_field_possible_values_info: 'По одному значению в каждой строке' + text_default_administrator_account_changed: Учётная запись администратора по умолчанию изменена + text_destroy_time_entries_question: "На эту задачу зарегистрировано %{hours} часа(ов) затраченного времени. Что Вы хотите предпринять?" + text_destroy_time_entries: Удалить зарегистрированное время + text_diff_truncated: '... Этот diff ограничен, так как превышает максимальный отображаемый размер.' + text_email_delivery_not_configured: "Параметры работы с почтовым сервером не настроены и функция уведомления по email не активна.\nНастроить параметры для Вашего SMTP-сервера Вы можете в файле config/configuration.yml. Для применения изменений перезапустите приложение." + text_enumeration_category_reassign_to: 'Назначить им следующее значение:' + text_enumeration_destroy_question: "%{count} объект(а,ов) связаны с этим значением." + text_file_repository_writable: Хранилище с доступом на запись + text_issue_added: "Создана новая задача %{id} (%{author})." + text_issue_category_destroy_assignments: Удалить назначения категории + text_issue_category_destroy_question: "Несколько задач (%{count}) назначено в данную категорию. Что Вы хотите предпринять?" + text_issue_category_reassign_to: Переназначить задачи для данной категории + text_issues_destroy_confirmation: 'Вы уверены, что хотите удалить выбранные задачи?' + text_issues_ref_in_commit_messages: Сопоставление и изменение статуса задач исходя из текста сообщений + text_issue_updated: "Задача %{id} была обновлена (%{author})." + text_journal_changed: "Параметр %{label} изменился с %{old} на %{new}" + text_journal_deleted: "Значение %{old} параметра %{label} удалено" + text_journal_set_to: "Параметр %{label} изменился на %{value}" + text_length_between: "Длина между %{min} и %{max} символов." + text_load_default_configuration: Загрузить конфигурацию по умолчанию + text_min_max_length_info: 0 означает отсутствие ограничений + text_no_configuration_data: "Роли, трекеры, статусы задач и оперативный план не были сконфигурированы.\nНастоятельно рекомендуется загрузить конфигурацию по-умолчанию. Вы сможете её изменить потом." + text_plugin_assets_writable: Каталог модулей доступен для записи + text_project_destroy_confirmation: Вы настаиваете на удалении данного проекта и всей относящейся к нему информации? + text_reassign_time_entries: 'Перенести зарегистрированное время на следующую задачу:' + text_regexp_info: "например: ^[A-Z0-9]+$" + text_repository_usernames_mapping: "Выберите или обновите пользователя Redmine, связанного с найденными именами в журнале хранилища.\nПользователи с одинаковыми именами или email в Redmine и хранилище связываются автоматически." + text_rmagick_available: Доступно использование RMagick (опционально) + text_select_mail_notifications: Выберите действия, при которых будет отсылаться уведомление на электронную почту. + text_select_project_modules: 'Выберите модули, которые будут использованы в проекте:' + text_status_changed_by_changeset: "Реализовано в %{value} редакции." + text_subprojects_destroy_warning: "Подпроекты: %{value} также будут удалены." + text_tip_issue_begin_day: дата начала задачи + text_tip_issue_begin_end_day: начало задачи и окончание её в этот же день + text_tip_issue_end_day: дата завершения задачи + text_tracker_no_workflow: Для этого трекера последовательность действий не определена + text_unallowed_characters: Запрещенные символы + text_user_mail_option: "Для невыбранных проектов, Вы будете получать уведомления только о том, что просматриваете или в чем участвуете (например, задачи, автором которых Вы являетесь, или которые Вам назначены)." + text_user_wrote: "%{value} писал(а):" + text_wiki_destroy_confirmation: Вы уверены, что хотите удалить данную Wiki и все её содержимое? + text_workflow_edit: Выберите роль и трекер для редактирования последовательности состояний + + warning_attachments_not_saved: "%{count} файл(ов) невозможно сохранить." + text_wiki_page_destroy_question: Эта страница имеет %{descendants} дочерних страниц и их потомков. Что вы хотите предпринять? + text_wiki_page_reassign_children: Переопределить дочерние страницы на текущую страницу + text_wiki_page_nullify_children: Сделать дочерние страницы главными страницами + text_wiki_page_destroy_children: Удалить дочерние страницы и всех их потомков + setting_password_min_length: Минимальная длина пароля + field_group_by: Группировать результаты по + mail_subject_wiki_content_updated: "Wiki-страница '%{id}' была обновлена" + label_wiki_content_added: Добавлена wiki-страница + mail_subject_wiki_content_added: "Wiki-страница '%{id}' была добавлена" + mail_body_wiki_content_added: "%{author} добавил(а) wiki-страницу '%{id}'." + label_wiki_content_updated: Обновлена wiki-страница + mail_body_wiki_content_updated: "%{author} обновил(а) wiki-страницу '%{id}'." + permission_add_project: Создание проекта + setting_new_project_user_role_id: Роль, назначаемая пользователю, создавшему проект + label_view_all_revisions: Показать все ревизии + label_tag: Метка + label_branch: Ветвь + error_no_tracker_in_project: С этим проектом не ассоциирован ни один трекер. Проверьте настройки проекта. + error_no_default_issue_status: Не определен статус задач по умолчанию. Проверьте настройки (см. "Администрирование -> Статусы задач"). + label_group_plural: Группы + label_group: Группа + label_group_new: Новая группа + label_time_entry_plural: Затраченное время + text_journal_added: "%{label} %{value} добавлен" + field_active: Активно + enumeration_system_activity: Системное + permission_delete_issue_watchers: Удаление наблюдателей + version_status_closed: закрыт + version_status_locked: заблокирован + version_status_open: открыт + error_can_not_reopen_issue_on_closed_version: Задача, назначенная к закрытой версии, не сможет быть открыта снова + label_user_anonymous: Аноним + button_move_and_follow: Переместить и перейти + setting_default_projects_modules: Включенные по умолчанию модули для новых проектов + setting_gravatar_default: Изображение Gravatar по умолчанию + field_sharing: Совместное использование + label_version_sharing_hierarchy: С иерархией проектов + label_version_sharing_system: Со всеми проектами + label_version_sharing_descendants: С подпроектами + label_version_sharing_tree: С деревом проектов + label_version_sharing_none: Без совместного использования + error_can_not_archive_project: Этот проект не может быть заархивирован + button_duplicate: Дублировать + button_copy_and_follow: Копировать и продолжить + label_copy_source: Источник + setting_issue_done_ratio: Рассчитывать готовность задачи с помощью поля + setting_issue_done_ratio_issue_status: Статус задачи + error_issue_done_ratios_not_updated: Параметр готовность задач не обновлён + error_workflow_copy_target: Выберите целевые трекеры и роли + setting_issue_done_ratio_issue_field: Готовность задачи + label_copy_same_as_target: То же, что и у цели + label_copy_target: Цель + notice_issue_done_ratios_updated: Параметр «готовность» обновлён. + error_workflow_copy_source: Выберите исходный трекер или роль + label_update_issue_done_ratios: Обновить готовность задач + setting_start_of_week: День начала недели + label_api_access_key: Ключ доступа к API + text_line_separated: Разрешено несколько значений (по одному значению в строку). + label_revision_id: Ревизия %{value} + permission_view_issues: Просмотр задач + label_display_used_statuses_only: Отображать только те статусы, которые используются в этом трекере + label_api_access_key_created_on: Ключ доступ к API был создан %{value} назад + label_feeds_access_key: Ключ доступа к RSS + notice_api_access_key_reseted: Ваш ключ доступа к API был сброшен. + setting_rest_api_enabled: Включить веб-сервис REST + button_show: Показать + label_missing_api_access_key: Отсутствует ключ доступа к API + label_missing_feeds_access_key: Отсутствует ключ доступа к RSS + setting_mail_handler_body_delimiters: Урезать письмо после одной из этих строк + permission_add_subprojects: Создание подпроектов + label_subproject_new: Новый подпроект + text_own_membership_delete_confirmation: |- + Вы собираетесь удалить некоторые или все права, из-за чего могут пропасть права на редактирование этого проекта. + Продолжить? + label_close_versions: Закрыть завершённые версии + label_board_sticky: Прикреплена + label_board_locked: Заблокирована + field_principal: Имя + text_zoom_out: Отдалить + text_zoom_in: Приблизить + notice_unable_delete_time_entry: Невозможно удалить запись журнала. + label_overall_spent_time: Всего затрачено времени + label_user_mail_option_none: Нет событий + field_member_of_group: Группа назначенного + field_assigned_to_role: Роль назначенного + notice_not_authorized_archived_project: Запрашиваемый проект был архивирован. + label_principal_search: "Найти пользователя или группу:" + label_user_search: "Найти пользователя:" + field_visible: Видимое + setting_emails_header: Заголовок письма + + setting_commit_logtime_activity_id: Действие для учёта времени + text_time_logged_by_changeset: Учтено в редакции %{value}. + setting_commit_logtime_enabled: Включить учёт времени + notice_gantt_chart_truncated: Диаграмма будет усечена, поскольку превышено максимальное кол-во элементов, которые могут отображаться (%{max}) + setting_gantt_items_limit: Максимальное кол-во элементов отображаемых на диаграмме Ганта + field_warn_on_leaving_unsaved: Предупреждать при закрытии страницы с несохранённым текстом + text_warn_on_leaving_unsaved: Текущая страница содержит несохранённый текст, который будет потерян, если вы покинете эту страницу. + label_my_queries: Мои сохранённые запросы + text_journal_changed_no_detail: "%{label} обновлено" + label_news_comment_added: Добавлен комментарий к новости + button_expand_all: Развернуть все + button_collapse_all: Свернуть все + label_additional_workflow_transitions_for_assignee: Дополнительные переходы, когда пользователь является исполнителем + label_additional_workflow_transitions_for_author: Дополнительные переходы, когда пользователь является автором + label_bulk_edit_selected_time_entries: Массовое изменение выбранных записей затраченного времени + text_time_entries_destroy_confirmation: Вы уверены что хотите удалить выбранные записи затраченного времени? + label_role_anonymous: Аноним + label_role_non_member: Не участник + label_issue_note_added: Примечание добавлено + label_issue_status_updated: Статус обновлён + label_issue_priority_updated: Приоритет обновлён + label_issues_visibility_own: Задачи созданные или назначенные пользователю + field_issues_visibility: Видимость задач + label_issues_visibility_all: Все задачи + permission_set_own_issues_private: Установление видимости (общая/частная) для собственных задач + field_is_private: Частная + permission_set_issues_private: Установление видимости (общая/частная) для задач + label_issues_visibility_public: Только общие задачи + text_issues_destroy_descendants_confirmation: Так же будет удалено %{count} задач(и). + field_commit_logs_encoding: Кодировка комментариев в хранилище + field_scm_path_encoding: Кодировка пути + text_scm_path_encoding_note: "По умолчанию: UTF-8" + field_path_to_repository: Путь к хранилищу + field_root_directory: Корневая директория + field_cvs_module: Модуль + field_cvsroot: CVSROOT + text_mercurial_repository_note: Локальное хранилище (например, /hgrepo, c:\hgrepo) + text_scm_command: Команда + text_scm_command_version: Версия + label_git_report_last_commit: Указывать последнее изменения для файлов и директорий + text_scm_config: Вы можете настроить команды SCM в файле config/configuration.yml. Пожалуйста, перезапустите приложение после редактирования этого файла. + text_scm_command_not_available: Команда системы контроля версий недоступна. Пожалуйста, проверьте настройки в административной панели. + notice_issue_successful_create: Задача %{id} создана. + label_between: между + setting_issue_group_assignment: Разрешить назначение задач группам пользователей + label_diff: Разница(diff) + text_git_repository_note: Repository is bare and local (e.g. /gitrepo, c:\gitrepo) + description_query_sort_criteria_direction: Порядок сортировки + description_project_scope: Search scope + description_filter: Фильтр + description_user_mail_notification: Mail notification settings + description_date_from: Enter start date + description_message_content: Message content + description_available_columns: Available Columns + description_date_range_interval: Choose range by selecting start and end date + description_issue_category_reassign: Choose issue category + description_search: Searchfield + description_notes: Примечания + description_date_range_list: Выберите диапазон из списка + description_choose_project: Проекты + description_date_to: Введите дату выполнения + description_query_sort_criteria_attribute: Критерий сортировки + description_wiki_subpages_reassign: Выбрать новую родительскую страницу + description_selected_columns: Выбранные столбцы + label_parent_revision: Родительский + label_child_revision: Дочерний + error_scm_annotate_big_text_file: Комментарий невозможен из-за превышения максимального размера текстового файла. + setting_default_issue_start_date_to_creation_date: Использовать текущую дату в качестве даты начала для новых задач + button_edit_section: Редактировать эту секцию + setting_repositories_encodings: Кодировка вложений и хранилищ + description_all_columns: Все столбцы + button_export: Экспорт + label_export_options: "%{export_format} параметры экспорта" + error_attachment_too_big: Этот файл нельзя загрузить из-за превышения максимального размера файла (%{max_size}) + notice_failed_to_save_time_entries: "Невозможно сохранить %{count} затраченное время для %{total} выбранных: %{ids}." + label_x_issues: + one: "%{count} задача" + few: "%{count} задачи" + many: "%{count} задач" + other: "%{count} Задачи" + label_repository_new: Новое хранилище + field_repository_is_default: Хранилище по умолчанию + label_copy_attachments: Копировать вложения + label_item_position: "%{position}/%{count}" + label_completed_versions: Завершенные версии + text_project_identifier_info: Допускаются только строчные латинские буквы (a-z), цифры, тире и подчеркивания.
    После сохранения идентификатор изменить нельзя. + field_multiple: Множественные значения + setting_commit_cross_project_ref: Разрешить ссылаться и исправлять задачи во всех остальных проектах + text_issue_conflict_resolution_add_notes: Добавить мои примечания и отказаться от моих изменений + text_issue_conflict_resolution_overwrite: Применить мои изменения (все предыдущие замечания будут сохранены, но некоторые изменения могут быть перезаписаны) + notice_issue_update_conflict: Кто-то изменил задачу, пока вы ее редактировали. + text_issue_conflict_resolution_cancel: Отменить мои изменения и показать задачу заново %{link} + permission_manage_related_issues: Управление связанными задачами + field_auth_source_ldap_filter: Фильтр LDAP + label_search_for_watchers: Найти наблюдателей + notice_account_deleted: "Ваша учетная запись полностью удалена" + setting_unsubscribe: "Разрешить пользователям удалять свои учетные записи" + button_delete_my_account: "Удалить мою учетную запись" + text_account_destroy_confirmation: "Ваша учетная запись будет полностью удалена без возможности восстановления.\nВы уверены, что хотите продолжить?" + error_session_expired: Срок вашей сессии истек. Пожалуйста войдите еще раз + text_session_expiration_settings: "Внимание! Изменение этих настроек может привести к завершению текущих сессий, включая вашу." + setting_session_lifetime: Максимальная продолжительность сессии + setting_session_timeout: Таймут сессии + label_session_expiration: Срок истечения сессии + permission_close_project: Закрывать / открывать проекты + label_show_closed_projects: Просматривать закрытые проекты + button_close: Сделать закрытым + button_reopen: Сделать открытым + project_status_active: открытые + project_status_closed: закрытые + project_status_archived: архивированные + text_project_closed: Проект закрыт и находиться в режиме только для чтения. + notice_user_successful_create: Пользователь %{id} создан. + field_core_fields: Стандартные поля + field_timeout: Таймаут (в секундах) + setting_thumbnails_enabled: Отображать превью для приложений + setting_thumbnails_size: Размер первью (в пикселях) + label_status_transitions: Статус-переходы + label_fields_permissions: Права на изменения полей + label_readonly: Не изменяется + label_required: Обязательное + text_repository_identifier_info: Допускаются только строчные латинские буквы (a-z), цифры, тире и подчеркивания.
    После сохранения идентификатор изменить нельзя. + field_board_parent: Родительский форум + label_attribute_of_project: Проект %{name} + label_attribute_of_author: Имя автора %{name} + label_attribute_of_assigned_to: Назначена %{name} + label_attribute_of_fixed_version: Версия %{name} + label_copy_subtasks: Копировать подзадачи + label_copied_to: скопирована в + label_copied_from: скопирована с + label_any_issues_in_project: любые задачи в проекте + label_any_issues_not_in_project: любые задачи не в проекте + field_private_notes: Приватный комментарий + permission_view_private_notes: Просмотр приватных комментариев + permission_set_notes_private: Размещение приватных комментариев + label_no_issues_in_project: нет задач в проекте + label_any: все + label_last_n_weeks: + one: "последняя %{count} неделя" + few: "последние %{count} недели" + many: "последние %{count} недель" + other: "последние %{count} недели" + setting_cross_project_subtasks: Разрешить подзадачи в между проектами + label_cross_project_descendants: С подпроектами + label_cross_project_tree: С деревом проектов + label_cross_project_hierarchy: С иерархией проектов + label_cross_project_system: Со всеми проектами + button_hide: Скрыть + setting_non_working_week_days: Нерабочие дни + label_in_the_next_days: в средующие дни + label_in_the_past_days: в прошлые дни + label_attribute_of_user: Пользователь %{name} + text_turning_multiple_off: Если отключить множественные значения, лишние значения из списка будут удалены, чтобы осталось только по одному значению. + label_attribute_of_issue: Задача %{name} + permission_add_documents: Добавить документы + permission_edit_documents: Редактировать документы + permission_delete_documents: Удалить документы + label_gantt_progress_line: Линия прогресса + setting_jsonp_enabled: Поддержка JSONP + field_inherit_members: Наследовать участников + field_closed_on: Закрыта + setting_default_projects_tracker_ids: Трекеры по умолчанию для новых проектов + label_total_time: Общее время diff --git a/config/locales/sk.yml b/config/locales/sk.yml new file mode 100644 index 00000000..f8924c89 --- /dev/null +++ b/config/locales/sk.yml @@ -0,0 +1,1086 @@ +sk: + direction: ltr + date: + formats: + default: "%Y-%m-%d" + short: "%b %d" + long: "%B %d, %Y" + + day_names: [Nedeľa, Pondelok, Utorok, Streda, Štvrtok, Piatok, Sobota] + abbr_day_names: [Ne, Po, Ut, St, Št, Pi, So] + + # Don't forget the nil at the beginning; there's no such thing as a 0th month + month_names: [~, Január, Február, Marec, Apríl, Máj, Jún, Júl, August, September, Október, November, December] + abbr_month_names: [~, Jan, Feb, Mar, Apr, Máj, Jún, Júl, Aug, Sep, Okt, Nov, Dec] + # Used in date_select and datime_select. + order: + - :year + - :month + - :day + + time: + formats: + default: "%a, %d %b %Y %H:%M:%S %z" + time: "%H:%M" + short: "%d %b %H:%M" + long: "%B %d, %Y %H:%M" + am: "am" + pm: "pm" + + datetime: + distance_in_words: + half_a_minute: "pol minúty" + less_than_x_seconds: + one: "menej ako 1 sekunda" + other: "menej ako %{count} sekúnd" + x_seconds: + one: "1 sekunda" + other: "%{count} sekúnd" + less_than_x_minutes: + one: "menej ako minúta" + other: "menej ako %{count} minút" + x_minutes: + one: "1 minuta" + other: "%{count} minút" + about_x_hours: + one: "okolo 1 hodiny" + other: "okolo %{count} hodín" + x_hours: + one: "1 hour" + other: "%{count} hours" + x_days: + one: "1 deň" + other: "%{count} dní" + about_x_months: + one: "okolo 1 mesiaca" + other: "okolo %{count} mesiace/ov" + x_months: + one: "1 mesiac" + other: "%{count} mesiace/ov" + about_x_years: + one: "okolo 1 roka" + other: "okolo %{count} roky/ov" + over_x_years: + one: "cez 1 rok" + other: "cez %{count} roky/ov" + almost_x_years: + one: "almost 1 year" + other: "almost %{count} years" + + number: + format: + separator: "." + delimiter: "" + precision: 3 + + human: + format: + precision: 3 + delimiter: "" + storage_units: + format: "%n %u" + units: + kb: KB + tb: TB + gb: GB + byte: + one: Byte + other: Bytes + mb: MB + +# Used in array.to_sentence. + support: + array: + sentence_connector: "a" + skip_last_comma: false + + activerecord: + errors: + template: + header: + one: "1 error prohibited this %{model} from being saved" + other: "%{count} errors prohibited this %{model} from being saved" + messages: + inclusion: "nieje zahrnuté v zozname" + exclusion: "je rezervované" + invalid: "je neplatné" + confirmation: "sa nezhoduje s potvrdením" + accepted: "musí byť akceptované" + empty: "nemôže byť prázdne" + blank: "nemôže byť prázdne" + too_long: "je príliš dlhé" + too_short: "je príliš krátke" + wrong_length: "má chybnú dĺžku" + taken: "je už použité" + not_a_number: "nieje číslo" + not_a_date: "nieje platný dátum" + greater_than: "musí byť väčšíe ako %{count}" + greater_than_or_equal_to: "musí byť väčšie alebo rovné %{count}" + equal_to: "musí byť rovné %{count}" + less_than: "musí byť menej ako %{count}" + less_than_or_equal_to: "musí byť menej alebo rovné %{count}" + odd: "musí byť nepárne" + even: "musí byť párne" + greater_than_start_date: "musí byť neskôr ako počiatočný dátum" + not_same_project: "nepatrí rovnakému projektu" + circular_dependency: "Tento vzťah by vytvoril cyklickú závislosť" + cant_link_an_issue_with_a_descendant: "An issue can not be linked to one of its subtasks" + + # SK translation by Stanislav Pach | stano.pach@seznam.cz + + actionview_instancetag_blank_option: Prosím vyberte + + general_text_No: 'Nie' + general_text_Yes: 'Áno' + general_text_no: 'nie' + general_text_yes: 'áno' + general_lang_name: 'Slovenčina' + general_csv_separator: ',' + general_csv_decimal_separator: '.' + general_csv_encoding: UTF-8 + general_pdf_encoding: UTF-8 + general_first_day_of_week: '1' + + notice_account_updated: Účet bol úspešne zmenený. + notice_account_invalid_creditentials: Chybné meno alebo heslo + notice_account_password_updated: Heslo bolo úspešne zmenené. + notice_account_wrong_password: Chybné heslo + notice_account_register_done: Účet bol úspešne vytvorený. Pre aktiváciu účtu kliknite na odkaz v emailu, ktorý vam bol zaslaný. + notice_account_unknown_email: Neznámy užívateľ. + notice_can_t_change_password: Tento účet používa externú autentifikáciu. Tu heslo zmeniť nemôžete. + notice_account_lost_email_sent: Bol vám zaslaný email s inštrukciami ako si nastavite nové heslo. + notice_account_activated: Váš účet bol aktivovaný. Teraz se môžete prihlásiť. + notice_successful_create: Úspešne vytvorené. + notice_successful_update: Úspešne aktualizované. + notice_successful_delete: Úspešne odstránené. + notice_successful_connection: Úspešne pripojené. + notice_file_not_found: Stránka, ktorú se snažíte zobraziť, neexistuje alebo bola zmazaná. + notice_locking_conflict: Údaje boli zmenené iným užívateľom. + notice_scm_error: Položka a/alebo revízia neexistuje v repozitári. + notice_not_authorized: Nemáte dostatočné práva pre zobrazenie tejto stránky. + notice_email_sent: "Na adresu %{value} bol odeslaný email" + notice_email_error: "Pri odosielaní emailu nastala chyba (%{value})" + notice_feeds_access_key_reseted: Váš klúč pre prístup k Atomu bol resetovaný. + notice_failed_to_save_issues: "Nastala chyba pri ukládaní %{count} úloh na %{total} zvolený: %{ids}." + notice_no_issue_selected: "Nebola zvolená žiadná úloha. Prosím, zvoľte úlohy, ktoré chcete upraviť" + notice_account_pending: "Váš účet bol vytvorený, teraz čaká na schválenie administrátorom." + notice_default_data_loaded: Výchozia konfigurácia úspešne nahraná. + + error_can_t_load_default_data: "Výchozia konfigurácia nebola nahraná: %{value}" + error_scm_not_found: "Položka a/alebo revízia neexistuje v repozitári." + error_scm_command_failed: "Pri pokuse o prístup k repozitári došlo k chybe: %{value}" + error_issue_not_found_in_project: 'Úloha nebola nájdená alebo nepatrí k tomuto projektu' + + mail_subject_lost_password: "Vaše heslo (%{value})" + mail_body_lost_password: 'Pre zmenu vašeho hesla kliknite na následujúci odkaz:' + mail_subject_register: "Aktivácia účtu (%{value})" + mail_body_register: 'Pre aktiváciu vašeho účtu kliknite na následujúci odkaz:' + mail_body_account_information_external: "Pomocou vašeho účtu %{value} se môžete prihlásiť." + mail_body_account_information: Informácie o vašom účte + mail_subject_account_activation_request: "Aktivácia %{value} účtu" + mail_body_account_activation_request: "Bol zaregistrovaný nový uživateľ %{value}. Aktivácia jeho účtu závisí na vašom potvrdení." + + + field_name: Názov + field_description: Popis + field_summary: Prehľad + field_is_required: Povinné pole + field_firstname: Meno + field_lastname: Priezvisko + field_mail: Email + field_filename: Súbor + field_filesize: Veľkosť + field_downloads: Stiahnuté + field_author: Autor + field_created_on: Vytvorené + field_updated_on: Aktualizované + field_field_format: Formát + field_is_for_all: Pre všetky projekty + field_possible_values: Možné hodnoty + field_regexp: Regulérny výraz + field_min_length: Minimálna dĺžka + field_max_length: Maximálna dĺžka + field_value: Hodnota + field_category: Kategória + field_title: Názov + field_project: Projekt + field_issue: Úloha + field_status: Stav + field_notes: Poznámka + field_is_closed: Úloha uzavretá + field_is_default: Východzí stav + field_tracker: Fronta + field_subject: Predmet + field_due_date: Uzavrieť do + field_assigned_to: Priradené + field_priority: Priorita + field_fixed_version: Priradené k verzii + field_user: Užívateľ + field_role: Rola + field_homepage: Domovská stránka + field_is_public: Verejný + field_parent: Nadradený projekt + field_is_in_roadmap: Úlohy zobrazené v pláne + field_login: Login + field_mail_notification: Emailové oznámenie + field_admin: Administrátor + field_last_login_on: Posledné prihlásenie + field_language: Jazyk + field_effective_date: Dátum + field_password: Heslo + field_new_password: Nové heslo + field_password_confirmation: Potvrdenie + field_version: Verzia + field_type: Typ + field_host: Host + field_port: Port + field_account: Účet + field_base_dn: Base DN + field_attr_login: Prihlásenie (atribut) + field_attr_firstname: Meno (atribut) + field_attr_lastname: Priezvisko (atribut) + field_attr_mail: Email (atribut) + field_onthefly: Automatické vytváranie užívateľov + field_start_date: Začiatok + field_done_ratio: "% hotovo" + field_auth_source: Autentifikačný mód + field_hide_mail: Nezobrazovať môj email + field_comments: Komentár + field_url: URL + field_start_page: Výchozia stránka + field_subproject: Podprojekt + field_hours: Hodiny + field_activity: Aktivita + field_spent_on: Dátum + field_identifier: Identifikátor + field_is_filter: Použiť ako filter + field_issue_to: Súvisiaca úloha + field_delay: Oneskorenie + field_assignable: Úlohy môžu byť priradené tejto roli + field_redirect_existing_links: Presmerovať existujúce odkazy + field_estimated_hours: Odhadovaná doba + field_column_names: Stĺpce + field_time_zone: Časové pásmo + field_searchable: Umožniť vyhľadávanie + field_default_value: Východzia hodnota + field_comments_sorting: Zobraziť komentáre + + setting_app_title: Názov aplikácie + setting_app_subtitle: Podtitulok aplikácie + setting_welcome_text: Uvítací text + setting_default_language: Východzí jazyk + setting_login_required: Auten. vyžadovaná + setting_self_registration: Povolenie registrácie + setting_attachment_max_size: Maximálna veľkosť prílohy + setting_issues_export_limit: Limit pre export úloh + setting_mail_from: Odosielať emaily z adresy + setting_bcc_recipients: Príjemcovia skrytej kópie (bcc) + setting_host_name: Hostname + setting_text_formatting: Formátovanie textu + setting_wiki_compression: Kompresia histórie Wiki + setting_feeds_limit: Limit zobrazených položiek (Atom feed) + setting_default_projects_public: Nové projekty nastavovať ako verejné + setting_autofetch_changesets: Automatický prenos zmien + setting_sys_api_enabled: Povolit Webovú Službu (WS) pre správu repozitára + setting_commit_ref_keywords: Klúčové slová pre odkazy + setting_commit_fix_keywords: Klúčové slová pre uzavretie + setting_autologin: Automatické prihlasovanie + setting_date_format: Formát dátumu + setting_time_format: Formát času + setting_cross_project_issue_relations: Povoliť väzby úloh skrz projekty + setting_issue_list_default_columns: Východzie stĺpce zobrazené v zozname úloh + setting_ itories_encodings: Kódovanie + setting_emails_footer: Zapätie emailov + setting_protocol: Protokol + setting_per_page_options: Povolené množstvo riadkov na stránke + setting_user_format: Formát zobrazenia užívateľa + setting_activity_days_default: "Zobrazené dni aktivity projektu:" + setting_display_subprojects_issues: Prednastavenie zobrazenia úloh podporojektov v hlavnom projekte + + project_module_issue_tracking: Sledovanie úloh + project_module_time_tracking: Sledovanie času + project_module_news: Novinky + project_module_documents: Dokumenty + project_module_files: Súbory + project_module_wiki: Wiki + project_module_repository: Repozitár + project_module_boards: Diskusie + + label_user: Užívateľ + label_user_plural: Užívatelia + label_user_new: Nový užívateľ + label_project: Projekt + label_project_new: Nový projekt + label_project_plural: Projekty + label_x_projects: + zero: žiadne projekty + one: 1 projekt + other: "%{count} projekty/ov" + label_project_all: Všetky projekty + label_project_latest: Posledné projekty + label_issue: Úloha + label_issue_new: Nová úloha + label_issue_plural: Úlohy + label_issue_view_all: Všetky úlohy + label_issues_by: "Úlohy od užívateľa %{value}" + label_issue_added: Úloha pridaná + label_issue_updated: Úloha aktualizovaná + label_document: Dokument + label_document_new: Nový dokument + label_document_plural: Dokumenty + label_document_added: Dokument pridaný + label_role: Rola + label_role_plural: Role + label_role_new: Nová rola + label_role_and_permissions: Role a práva + label_member: Člen + label_member_new: Nový člen + label_member_plural: Členovia + label_tracker: Fronta + label_tracker_plural: Fronty + label_tracker_new: Nová fronta + label_workflow: Workflow + label_issue_status: Stav úloh + label_issue_status_plural: Stavy úloh + label_issue_status_new: Nový stav + label_issue_category: Kategória úloh + label_issue_category_plural: Kategórie úloh + label_issue_category_new: Nová kategória + label_custom_field: Užívateľské pole + label_custom_field_plural: Užívateľské polia + label_custom_field_new: Nové užívateľské pole + label_enumerations: Zoznamy + label_enumeration_new: Nová hodnota + label_information: Informácia + label_information_plural: Informácie + label_please_login: Prosím prihláste sa + label_register: Registrovať + label_password_lost: Zabudnuté heslo + label_home: Domovská stránka + label_my_page: Moja stránka + label_my_account: Môj účet + label_my_projects: Moje projekty + label_administration: Administrácia + label_login: Prihlásenie + label_logout: Odhlásenie + label_help: Nápoveda + label_reported_issues: Nahlásené úlohy + label_assigned_to_me_issues: Moje úlohy + label_last_login: Posledné prihlásenie + label_registered_on: Registrovaný + label_activity: Aktivita + label_overall_activity: Celková aktivita + label_new: Nový + label_logged_as: Prihlásený ako + label_environment: Prostredie + label_authentication: Autentifikácia + label_auth_source: Mód autentifikácie + label_auth_source_new: Nový mód autentifikácie + label_auth_source_plural: Módy autentifikácie + label_subproject_plural: Podprojekty + label_min_max_length: Min - Max dĺžka + label_list: Zoznam + label_date: Dátum + label_integer: Celé číslo + label_float: Desatinné číslo + label_boolean: Áno/Nie + label_string: Text + label_text: Dlhý text + label_attribute: Atribut + label_attribute_plural: Atributy + label_no_data: Žiadné položky + label_change_status: Zmeniť stav + label_history: História + label_attachment: Súbor + label_attachment_new: Nový súbor + label_attachment_delete: Odstrániť súbor + label_attachment_plural: Súbory + label_file_added: Súbor pridaný + label_report: Prehľad + label_report_plural: Prehľady + label_news: Novinky + label_news_new: Pridať novinku + label_news_plural: Novinky + label_news_latest: Posledné novinky + label_news_view_all: Zobrazit všetky novinky + label_news_added: Novinka pridaná + label_settings: Nastavenie + label_overview: Prehľad + label_version: Verzia + label_version_new: Nová verzia + label_version_plural: Verzie + label_confirmation: Potvrdenie + label_export_to: 'Tiež k dispozícií:' + label_read: Načíta sa... + label_public_projects: Verejné projekty + label_open_issues: Otvorený + label_open_issues_plural: Otvorené + label_closed_issues: Uzavrený + label_closed_issues_plural: Uzavrené + label_x_open_issues_abbr_on_total: + zero: 0 otvorených z celkovo %{total} + one: 1 otvorený z celkovo %{total} + other: "%{count} otvorené/ých z celkovo %{total}" + label_x_open_issues_abbr: + zero: 0 otvorených + one: 1 otvorený + other: "%{count} otvorené/ých" + label_x_closed_issues_abbr: + zero: 0 zavretých + one: 1 zavretý + other: "%{count} zavreté/ých" + label_total: Celkovo + label_permissions: Práva + label_current_status: Aktuálny stav + label_new_statuses_allowed: Nové povolené stavy + label_all: všetko + label_none: nič + label_nobody: nikto + label_next: Ďalší + label_previous: Predchádzajúci + label_used_by: Použité + label_details: Detaily + label_add_note: Pridať poznámku + label_per_page: Na stránku + label_calendar: Kalendár + label_months_from: mesiacov od + label_gantt: Ganttov graf + label_internal: Interný + label_last_changes: "posledných %{count} zmien" + label_change_view_all: Zobraziť všetky zmeny + label_personalize_page: Prispôsobiť túto stránku + label_comment: Komentár + label_comment_plural: Komentáre + label_x_comments: + zero: žiaden komentár + one: 1 komentár + other: "%{count} komentáre/ov" + label_comment_add: Pridať komentár + label_comment_added: Komentár pridaný + label_comment_delete: Odstrániť komentár + label_query: Užívateľský dotaz + label_query_plural: Užívateľské dotazy + label_query_new: Nový dotaz + label_filter_add: Pridať filter + label_filter_plural: Filtre + label_equals: je + label_not_equals: nieje + label_in_less_than: je menší ako + label_in_more_than: je väčší ako + label_in: v + label_today: dnes + label_all_time: vždy + label_yesterday: včera + label_this_week: tento týždeň + label_last_week: minulý týždeň + label_last_n_days: "posledných %{count} dní" + label_this_month: tento mesiac + label_last_month: minulý mesiac + label_this_year: tento rok + label_date_range: Časový rozsah + label_less_than_ago: pred menej ako (dňami) + label_more_than_ago: pred viac ako (dňami) + label_ago: pred (dňami) + label_contains: obsahuje + label_not_contains: neobsahuje + label_day_plural: dní + label_repository: Repozitár + label_repository_plural: Repozitáre + label_browse: Prechádzať + label_revision: Revízia + label_revision_plural: Revízií + label_associated_revisions: Súvisiace verzie + label_added: pridané + label_modified: zmenené + label_deleted: odstránené + label_latest_revision: Posledná revízia + label_latest_revision_plural: Posledné revízie + label_view_revisions: Zobraziť revízie + label_max_size: Maximálna veľkosť + label_sort_highest: Presunúť na začiatok + label_sort_higher: Presunúť navrch + label_sort_lower: Presunúť dole + label_sort_lowest: Presunúť na koniec + label_roadmap: Plán + label_roadmap_due_in: "Zostáva %{value}" + label_roadmap_overdue: "%{value} neskoro" + label_roadmap_no_issues: Pre túto verziu niesú žiadne úlohy + label_search: Hľadať + label_result_plural: Výsledky + label_all_words: Všetky slova + label_wiki: Wiki + label_wiki_edit: Wiki úprava + label_wiki_edit_plural: Wiki úpravy + label_wiki_page: Wiki stránka + label_wiki_page_plural: Wiki stránky + label_index_by_title: Index podľa názvu + label_index_by_date: Index podľa dátumu + label_current_version: Aktuálna verzia + label_preview: Náhľad + label_feed_plural: Príspevky + label_changes_details: Detail všetkých zmien + label_issue_tracking: Sledovanie úloh + label_spent_time: Strávený čas + label_f_hour: "%{value} hodina" + label_f_hour_plural: "%{value} hodín" + label_time_tracking: Sledovánie času + label_change_plural: Zmeny + label_statistics: Štatistiky + label_commits_per_month: Úkony za mesiac + label_commits_per_author: Úkony podľa autora + label_view_diff: Zobrazit rozdiely + label_diff_inline: vo vnútri + label_diff_side_by_side: vedľa seba + label_options: Nastavenie + label_copy_workflow_from: Kopírovať workflow z + label_permissions_report: Prehľad práv + label_watched_issues: Sledované úlohy + label_related_issues: Súvisiace úlohy + label_applied_status: Použitý stav + label_loading: Nahrávam ... + label_relation_new: Nová súvislosť + label_relation_delete: Odstrániť súvislosť + label_relates_to: súvisiací s + label_duplicates: duplicity + label_blocks: blokovaný + label_blocked_by: zablokovaný + label_precedes: predcháza + label_follows: následuje + label_end_to_start: od konca na začiatok + label_end_to_end: od konca do konca + label_start_to_start: od začiatku do začiatku + label_start_to_end: od začiatku do konca + label_stay_logged_in: Zostať prihlásený + label_disabled: zakazané + label_show_completed_versions: Ukázať dokončené verzie + label_me: ja + label_board: Fórum + label_board_new: Nové fórum + label_board_plural: Fóra + label_topic_plural: Témy + label_message_plural: Správy + label_message_last: Posledná správa + label_message_new: Nová správa + label_message_posted: Správa pridaná + label_reply_plural: Odpovede + label_send_information: Zaslať informácie o účte užívateľa + label_year: Rok + label_month: Mesiac + label_week: Týžden + label_date_from: Od + label_date_to: Do + label_language_based: Podľa výchozieho jazyka + label_sort_by: "Zoradenie podľa %{value}" + label_send_test_email: Poslať testovací email + label_feeds_access_key_created_on: "Prístupový klúč pre RSS bol vytvorený pred %{value}" + label_module_plural: Moduly + label_added_time_by: "Pridané užívateľom %{author} pred %{age}" + label_updated_time: "Aktualizované pred %{value}" + label_jump_to_a_project: Zvoliť projekt... + label_file_plural: Súbory + label_changeset_plural: Sady zmien + label_default_columns: Východzie stĺpce + label_no_change_option: (bez zmeny) + label_bulk_edit_selected_issues: Skupinová úprava vybraných úloh + label_theme: Téma + label_default: Východzí + label_search_titles_only: Vyhľadávať iba v názvoch + label_user_mail_option_all: "Pre všetky události všetkých mojích projektov" + label_user_mail_option_selected: "Pre všetky události vybraných projektov" + label_user_mail_no_self_notified: "Nezasielať informácie o mnou vytvorených zmenách" + label_registration_activation_by_email: aktivácia účtu emailom + label_registration_manual_activation: manuálna aktivácia účtu + label_registration_automatic_activation: automatická aktivácia účtu + label_display_per_page: "%{value} na stránku" + label_age: Vek + label_change_properties: Zmeniť vlastnosti + label_general: Všeobecné + label_more: Viac + label_scm: SCM + label_plugins: Pluginy + label_ldap_authentication: Autentifikácia LDAP + label_downloads_abbr: D/L + label_optional_description: Voliteľný popis + label_add_another_file: Pridať ďaľší súbor + label_preferences: Nastavenia + label_chronological_order: V chronologickom poradí + label_reverse_chronological_order: V obrátenom chronologickom poradí + + button_login: Prihlásiť + button_submit: Potvrdiť + button_save: Uložiť + button_check_all: Označiť všetko + button_uncheck_all: Odznačiť všetko + button_delete: Odstrániť + button_create: Vytvoriť + button_test: Test + button_edit: Upraviť + button_add: Pridať + button_change: Zmeniť + button_apply: Použiť + button_clear: Zmazať + button_lock: Zamknúť + button_unlock: Odomknúť + button_download: Stiahnúť + button_list: Vypísať + button_view: Zobraziť + button_move: Presunúť + button_back: Naspäť + button_cancel: Storno + button_activate: Aktivovať + button_sort: Zoradenie + button_log_time: Pridať čas + button_rollback: Naspäť k tejto verzii + button_watch: Sledovať + button_unwatch: Nesledovať + button_reply: Odpovedať + button_archive: Archivovať + button_unarchive: Odarchivovať + button_reset: Reset + button_rename: Premenovať + button_change_password: Zmeniť heslo + button_copy: Kopírovať + button_annotate: Komentovať + button_update: Aktualizovať + button_configure: Konfigurovať + + status_active: aktívny + status_registered: registrovaný + status_locked: uzamknutý + + text_select_mail_notifications: Vyberte akciu, pri ktorej bude zaslané upozornenie emailom + text_regexp_info: napr. ^[A-Z0-9]+$ + text_min_max_length_info: 0 znamená bez limitu + text_project_destroy_confirmation: Ste si istý, že chcete odstránit tento projekt a všetky súvisiace dáta ? + text_workflow_edit: Vyberte rolu a frontu k úprave workflow + text_are_you_sure: Ste si istý? + text_tip_issue_begin_day: úloha začína v tento deň + text_tip_issue_end_day: úloha končí v tento deň + text_tip_issue_begin_end_day: úloha začína a končí v tento deň + text_caracters_maximum: "%{count} znakov maximálne." + text_caracters_minimum: "Musí byť aspoň %{count} znaky/ov dlhé." + text_length_between: "Dĺžka medzi %{min} až %{max} znakmi." + text_tracker_no_workflow: Pre tuto frontu nieje definovaný žiadný workflow + text_unallowed_characters: Nepovolené znaky + text_comma_separated: Je povolené viacero hodnôt (oddelené navzájom čiarkou). + text_issues_ref_in_commit_messages: Odkazovať a upravovať úlohy v správach s následovnym obsahom + text_issue_added: "úloha %{id} bola vytvorená užívateľom %{author}." + text_issue_updated: "Úloha %{id} byla aktualizovaná užívateľom %{author}." + text_wiki_destroy_confirmation: Naozaj si prajete odstrániť túto Wiki a celý jej obsah? + text_issue_category_destroy_question: "Niektoré úlohy (%{count}) sú priradené k tejto kategórii. Čo chtete s nimi spraviť?" + text_issue_category_destroy_assignments: Zrušiť priradenie ku kategórii + text_issue_category_reassign_to: Priradiť úlohy do tejto kategórie + text_user_mail_option: "U projektov, které neboli vybrané, budete dostávať oznamenie iba o vašich či o sledovaných položkách (napr. o položkách, ktorých ste autor, alebo ku ktorým ste priradený/á)." + text_no_configuration_data: "Role, fronty, stavy úloh ani workflow neboli zatiaľ nakonfigurované.\nVelmi doporučujeme nahrať východziu konfiguráciu. Potom si môžete všetko upraviť" + text_load_default_configuration: Nahrať východziu konfiguráciu + text_status_changed_by_changeset: "Aktualizované v sade zmien %{value}." + text_issues_destroy_confirmation: 'Naozaj si prajete odstrániť všetky zvolené úlohy?' + text_select_project_modules: 'Aktivne moduly v tomto projekte:' + text_default_administrator_account_changed: Zmenené výchozie nastavenie administrátorského účtu + text_file_repository_writable: Povolený zápis do repozitára + text_rmagick_available: RMagick k dispozícií (voliteľné) + text_destroy_time_entries_question: U úloh, které chcete odstraniť, je evidované %.02f práce. Čo chcete vykonať? + text_destroy_time_entries: Odstrániť evidované hodiny. + text_assign_time_entries_to_project: Priradiť evidované hodiny projektu + text_reassign_time_entries: 'Preradiť evidované hodiny k tejto úlohe:' + + default_role_manager: Manažér + default_role_developer: Vývojár + default_role_reporter: Reportér + default_tracker_bug: Chyba + default_tracker_feature: Rozšírenie + default_tracker_support: Podpora + default_issue_status_new: Nový + default_issue_status_in_progress: In Progress + default_issue_status_resolved: Vyriešený + default_issue_status_feedback: Čaká sa + default_issue_status_closed: Uzavrený + default_issue_status_rejected: Odmietnutý + default_doc_category_user: Užívateľská dokumentácia + default_doc_category_tech: Technická dokumentácia + default_priority_low: Nízká + default_priority_normal: Normálna + default_priority_high: Vysoká + default_priority_urgent: Urgentná + default_priority_immediate: Okamžitá + default_activity_design: Design + default_activity_development: Vývoj + + enumeration_issue_priorities: Priority úloh + enumeration_doc_categories: Kategorie dokumentov + enumeration_activities: Aktivity (sledovanie času) + error_scm_annotate: "Položka neexistuje alebo nemôže byť komentovaná." + label_planning: Plánovanie + text_subprojects_destroy_warning: "Jeho podprojekt(y): %{value} budú takisto vymazané." + label_and_its_subprojects: "%{value} a jeho podprojekty" + mail_body_reminder: "%{count} úloha(y), ktorá(é) je(sú) vám priradený(é), ma(jú) byť hotova(é) za %{days} dní:" + mail_subject_reminder: "%{count} úloha(y) ma(jú) byť hotova(é) za pár %{days} dní" + text_user_wrote: "%{value} napísal:" + label_duplicated_by: duplikovaný + setting_enabled_scm: Zapnúť SCM + text_enumeration_category_reassign_to: 'Prenastaviť na túto hodnotu:' + text_enumeration_destroy_question: "%{count} objekty sú nastavené na túto hodnotu." + label_incoming_emails: Príchádzajúce emaily + label_generate_key: Vygenerovať kľúč + setting_mail_handler_api_enabled: Zapnúť Webovú Službu (WS) pre príchodzie emaily + setting_mail_handler_api_key: API kľúč + text_email_delivery_not_configured: "Doručenie emailov nieje nastavené, notifikácie sú vypnuté.\nNastavte váš SMTP server v config/configuration.yml a reštartnite aplikáciu pre aktiváciu funkcie." + field_parent_title: Nadradená stránka + label_issue_watchers: Pozorovatelia + button_quote: Citácia + setting_sequential_project_identifiers: Generovať sekvenčné identifikátory projektov + notice_unable_delete_version: Verzia nemôže byť zmazaná + label_renamed: premenované + label_copied: kopírované + setting_plain_text_mail: Len jednoduchý text (bez HTML) + permission_view_files: Zobrazenie súborov + permission_edit_issues: Úprava úloh + permission_edit_own_time_entries: Úprava vlastných zaznamov o strávenom čase + permission_manage_public_queries: Správa verejných otáziek + permission_add_issues: Pridanie úlohy + permission_log_time: Zaznamenávanie stráveného času + permission_view_changesets: Zobrazenie sád zmien + permission_view_time_entries: Zobrazenie stráveného času + permission_manage_versions: Správa verzií + permission_manage_wiki: Správa Wiki + permission_manage_categories: Správa kategórií úloh + permission_protect_wiki_pages: Ochrana Wiki strániek + permission_comment_news: Komentovanie noviniek + permission_delete_messages: Mazanie správ + permission_select_project_modules: Voľba projektových modulov + permission_edit_wiki_pages: Úprava Wiki strániek + permission_add_issue_watchers: Pridanie pozorovateľov + permission_view_gantt: Zobrazenie Ganttovho diagramu + permission_move_issues: Presun úloh + permission_manage_issue_relations: Správa vzťahov medzi úlohami + permission_delete_wiki_pages: Mazanie Wiki strániek + permission_manage_boards: Správa diskusií + permission_delete_wiki_pages_attachments: Mazanie Wiki príloh + permission_view_wiki_edits: Zobrazenie Wiki úprav + permission_add_messages: Pridanie správ + permission_view_messages: Zobrazenie správ + permission_manage_files: Správa súborov + permission_edit_issue_notes: Úprava poznámok úlohy + permission_manage_news: Správa noviniek + permission_view_calendar: Zobrazenie kalendára + permission_manage_members: Správa členov + permission_edit_messages: Úprava správ + permission_delete_issues: Mazanie správ + permission_view_issue_watchers: Zobrazenie zoznamu pozorovateľov + permission_manage_repository: Správa repozitára + permission_commit_access: Povoliť prístup + permission_browse_repository: Prechádzanie repozitára + permission_view_documents: Zobrazenie dokumentov + permission_edit_project: Úprava projektu + permission_add_issue_notes: Pridanie poznámky úlohy + permission_save_queries: Uloženie otáziek + permission_view_wiki_pages: Zobrazenie Wiki strániek + permission_rename_wiki_pages: Premenovanie Wiki strániek + permission_edit_time_entries: Úprava záznamov o strávenom čase + permission_edit_own_issue_notes: Úprava vlastných poznámok úlohy + setting_gravatar_enabled: Použitie užívateľských Gravatar ikon + permission_edit_own_messages: Úprava vlastných správ + permission_delete_own_messages: Mazanie vlastných správ + text_repository_usernames_mapping: "Vyberte alebo upravte mapovanie medzi užívateľmi systému Redmine a užívateľskými menami nájdenými v logu repozitára.\nUžívatelia s rovnakým prihlasovacím menom alebo emailom v systéme Redmine a repozitára sú mapovaní automaticky." + label_example: Príklad + label_user_activity: "Aktivita užívateľa %{value}" + label_updated_time_by: "Aktualizované užívateľom %{author} pred %{age}" + text_diff_truncated: '... Tento rozdielový výpis bol skratený, pretože prekračuje maximálnu veľkosť, ktorá môže byť zobrazená.' + setting_diff_max_lines_displayed: Maximálne množstvo zobrazených riadkov rozdielového výpisu + text_plugin_assets_writable: Adresár pre pluginy s možnosťou zápisu + warning_attachments_not_saved: "%{count} súbor(y) nemohol(li) byť uložené." + field_editable: Editovateľné + label_display: Zobrazenie + button_create_and_continue: Vytvoriť a pokračovať + text_custom_field_possible_values_info: 'Jeden riadok pre každú hodnotu' + setting_repository_log_display_limit: Maximálne množstvo revizií zobrazené v logu + setting_file_max_size_displayed: Maximálna veľkosť textových súborov zobrazených priamo na stránke + field_watcher: Pozorovateľ + setting_openid: Povoliť OpenID prihlasovanie a registráciu + field_identity_url: OpenID URL + label_login_with_open_id_option: alebo sa prihlásiť pomocou OpenID + field_content: Obsah + label_descending: Zostupné + label_sort: Zoradenie + label_ascending: Rastúce + label_date_from_to: Od %{start} do %{end} + label_greater_or_equal: ">=" + label_less_or_equal: <= + text_wiki_page_destroy_question: Táto stránka má %{descendants} podstránku/y a potomka/ov. Čo chcete vykonať? + text_wiki_page_reassign_children: Preradiť podstránky k tejto hlavnej stránke + text_wiki_page_nullify_children: Zachovať podstránky ako hlavné stránky + text_wiki_page_destroy_children: Vymazať podstránky a všetkých ich potomkov + setting_password_min_length: Minimálna dĺžka hesla + field_group_by: Skupinové výsledky podľa + mail_subject_wiki_content_updated: "'%{id}' Wiki stránka bola aktualizovaná" + label_wiki_content_added: Wiki stránka pridaná + mail_subject_wiki_content_added: "'%{id}' Wiki stránka bola pridaná" + mail_body_wiki_content_added: The '%{id}' Wiki stránka bola pridaná užívateľom %{author}. + permission_add_project: Vytvorenie projektu + label_wiki_content_updated: Wiki stránka aktualizovaná + mail_body_wiki_content_updated: Wiki stránka '%{id}' bola aktualizovaná užívateľom %{author}. + setting_new_project_user_role_id: Rola dána non-admin užívateľovi, ktorý vytvorí projekt + label_view_all_revisions: Zobraziť všetkz revízie + label_tag: Tag + label_branch: Vetva + error_no_tracker_in_project: K tomuto projektu nieje priradená žiadna fronta. Prosím skontrolujte nastavenie projektu. + error_no_default_issue_status: Nieje definovaný východzí stav úlohy. Prosím skontrolujte vase nastavenie (Choďte na "Administrácia -> Stavz úloh"). + text_journal_changed: "%{label} zmenené z %{old} na %{new}" + text_journal_set_to: "%{label} nastavené na %{value}" + text_journal_deleted: "%{label} zmazané (%{old})" + label_group_plural: Skupiny + label_group: Skupina + label_group_new: Nová skupina + label_time_entry_plural: Strávený čas + text_journal_added: "%{label} %{value} pridané" + field_active: Aktívne + enumeration_system_activity: Aktivita systému + permission_delete_issue_watchers: Odstrániť pozorovateľov + version_status_closed: zavreté + version_status_locked: uzavreté + version_status_open: otvorené + error_can_not_reopen_issue_on_closed_version: Úloha priradená uzavretej verzií nemôže byť znovu-otvorená + label_user_anonymous: Anonym + button_move_and_follow: Presunúť a následovať + setting_default_projects_modules: Prednastavené aktívne moduly pre nové projekty + setting_gravatar_default: Východzí Gravatar obrázok + field_sharing: Zdieľanie + label_version_sharing_hierarchy: S hierarchiou projektu + label_version_sharing_system: So všetkými projektami + label_version_sharing_descendants: S podprojektami + label_version_sharing_tree: S projektovým stromom + label_version_sharing_none: Nezdielané + error_can_not_archive_project: Tento projekt nemôže byť archivovaný + button_duplicate: Duplikovať + button_copy_and_follow: Kopírovať a následovať + label_copy_source: Zdroj + setting_issue_done_ratio: Vyrátať pomer vypracovania úlohy s + setting_issue_done_ratio_issue_status: Použiť stav úlohy + error_issue_done_ratios_not_updated: Stav vypracovania úlohy neaktualizovaný. + error_workflow_copy_target: Prosím zvoľte cieľovú frontu(y) a rolu(e) + setting_issue_done_ratio_issue_field: Použiť pole úlohy + label_copy_same_as_target: Rovnaké ako cieľ + label_copy_target: Cieľ + notice_issue_done_ratios_updated: Stav vypracovania úlohy aktualizovaný. + error_workflow_copy_source: Prosím zvoľte zdrojovú frontu alebo rolu + label_update_issue_done_ratios: Aktualizácia stavu úloh + setting_start_of_week: Štart pracovného týždňa v + permission_view_issues: Zobraziť úlohy + label_display_used_statuses_only: Zobraziť len stavy, ktoré sú priradené k tejto fronte + label_revision_id: Revízia %{value} + label_api_access_key: API prístupový kľúč + label_api_access_key_created_on: API prístupový kľúč vytvorený pred %{value} + label_feeds_access_key: RSS prístupový kľúč + notice_api_access_key_reseted: Váš API prístupový kľúč bol resetovaný. + setting_rest_api_enabled: Zapnúť REST web službu + label_missing_api_access_key: API prístupový kľuč nenájdený + label_missing_feeds_access_key: RSS prístupový kľúč nenájdený + button_show: Zobraziť + text_line_separated: Možnosť viacerých hodnôt (jeden riadok pre každú hodnotu). + setting_mail_handler_body_delimiters: Orezať emaily po následujúcich riadkoch + permission_add_subprojects: Vytváranie podprojektov + label_subproject_new: Nový podprojekt + text_own_membership_delete_confirmation: |- + Práve sa pokúšate o odstránenie niektorých alebo všetkých prístupových práv a možno nebudete mať možnost naďalej upravovať tento projekt. + Ste si istý(á), že chcete pokračovat? + label_close_versions: Uzavrieť ukončené verzie + label_board_sticky: Sticky + label_board_locked: Uzamknuté + permission_export_wiki_pages: Exportovať WiKi stránky + setting_cache_formatted_text: Cache formatted text + permission_manage_project_activities: Nastavovať aktivity projektu + error_unable_delete_issue_status: Nieje možné zmeniť stav úlohy + label_profile: Profil + permission_manage_subtasks: Nastavovať podúlohy + field_parent_issue: Nadradená úloha + label_subtask_plural: Podúlohy + label_project_copy_notifications: Zaslať emailové upozornenie behom kopírovania projektu + error_can_not_delete_custom_field: Nieje možné vymazať užívateľské pole + error_unable_to_connect: Nieje možné vymazať (%{value}) + error_can_not_remove_role: Táto roľa sa používa a nemôže byť vymazaná. + error_can_not_delete_tracker: Táto fronta obsahuje úlohy a nemôže byť vymazaná. + field_principal: Principal + label_my_page_block: My page block + notice_failed_to_save_members: "Failed to save member(s): %{errors}." + text_zoom_out: Zoom out + text_zoom_in: Zoom in + notice_unable_delete_time_entry: Unable to delete time log entry. + label_overall_spent_time: Overall spent time + field_time_entries: Log time + project_module_gantt: Gantt + project_module_calendar: Calendar + button_edit_associated_wikipage: "Edit associated Wiki page: %{page_title}" + field_text: Text field + label_user_mail_option_only_owner: Only for things I am the owner of + setting_default_notification_option: Default notification option + label_user_mail_option_only_my_events: Only for things I watch or I'm involved in + label_user_mail_option_only_assigned: Only for things I am assigned to + label_user_mail_option_none: No events + field_member_of_group: Assignee's group + field_assigned_to_role: Assignee's role + notice_not_authorized_archived_project: The project you're trying to access has been archived. + label_principal_search: "Search for user or group:" + label_user_search: "Search for user:" + field_visible: Visible + setting_commit_logtime_activity_id: Activity for logged time + text_time_logged_by_changeset: Applied in changeset %{value}. + setting_commit_logtime_enabled: Enable time logging + notice_gantt_chart_truncated: The chart was truncated because it exceeds the maximum number of items that can be displayed (%{max}) + setting_gantt_items_limit: Maximum number of items displayed on the gantt chart + field_warn_on_leaving_unsaved: Warn me when leaving a page with unsaved text + text_warn_on_leaving_unsaved: The current page contains unsaved text that will be lost if you leave this page. + label_my_queries: My custom queries + text_journal_changed_no_detail: "%{label} updated" + label_news_comment_added: Comment added to a news + button_expand_all: Expand all + button_collapse_all: Collapse all + label_additional_workflow_transitions_for_assignee: Additional transitions allowed when the user is the assignee + label_additional_workflow_transitions_for_author: Additional transitions allowed when the user is the author + label_bulk_edit_selected_time_entries: Bulk edit selected time entries + text_time_entries_destroy_confirmation: Are you sure you want to delete the selected time entr(y/ies)? + label_role_anonymous: Anonymous + label_role_non_member: Non member + label_issue_note_added: Note added + label_issue_status_updated: Status updated + label_issue_priority_updated: Priority updated + label_issues_visibility_own: Issues created by or assigned to the user + field_issues_visibility: Issues visibility + label_issues_visibility_all: All issues + permission_set_own_issues_private: Set own issues public or private + field_is_private: Private + permission_set_issues_private: Set issues public or private + label_issues_visibility_public: All non private issues + text_issues_destroy_descendants_confirmation: This will also delete %{count} subtask(s). + field_commit_logs_encoding: Kódovanie prenášaných správ + field_scm_path_encoding: Path encoding + text_scm_path_encoding_note: "Default: UTF-8" + field_path_to_repository: Path to repository + field_root_directory: Root directory + field_cvs_module: Module + field_cvsroot: CVSROOT + text_mercurial_repository_note: Local repository (e.g. /hgrepo, c:\hgrepo) + text_scm_command: Command + text_scm_command_version: Version + label_git_report_last_commit: Report last commit for files and directories + notice_issue_successful_create: Issue %{id} created. + label_between: between + setting_issue_group_assignment: Allow issue assignment to groups + label_diff: diff + text_git_repository_note: Repository is bare and local (e.g. /gitrepo, c:\gitrepo) + description_query_sort_criteria_direction: Sort direction + description_project_scope: Search scope + description_filter: Filter + description_user_mail_notification: Mail notification settings + description_date_from: Enter start date + description_message_content: Message content + description_available_columns: Available Columns + description_date_range_interval: Choose range by selecting start and end date + description_issue_category_reassign: Choose issue category + description_search: Searchfield + description_notes: Notes + description_date_range_list: Choose range from list + description_choose_project: Projects + description_date_to: Enter end date + description_query_sort_criteria_attribute: Sort attribute + description_wiki_subpages_reassign: Choose new parent page + description_selected_columns: Selected Columns + label_parent_revision: Parent + label_child_revision: Child + error_scm_annotate_big_text_file: The entry cannot be annotated, as it exceeds the maximum text file size. + setting_default_issue_start_date_to_creation_date: Use current date as start date for new issues + button_edit_section: Edit this section + setting_repositories_encodings: Attachments and repositories encodings + description_all_columns: All Columns + button_export: Export + label_export_options: "%{export_format} export options" + error_attachment_too_big: This file cannot be uploaded because it exceeds the maximum allowed file size (%{max_size}) + notice_failed_to_save_time_entries: "Failed to save %{count} time entrie(s) on %{total} selected: %{ids}." + label_x_issues: + zero: 0 Úloha + one: 1 Úloha + other: "%{count} Úlohy" + label_repository_new: New repository + field_repository_is_default: Main repository + label_copy_attachments: Copy attachments + label_item_position: "%{position}/%{count}" + label_completed_versions: Completed versions + text_project_identifier_info: Only lower case letters (a-z), numbers, dashes and underscores are allowed.
    Once saved, the identifier cannot be changed. + field_multiple: Multiple values + setting_commit_cross_project_ref: Allow issues of all the other projects to be referenced and fixed + text_issue_conflict_resolution_add_notes: Add my notes and discard my other changes + text_issue_conflict_resolution_overwrite: Apply my changes anyway (previous notes will be kept but some changes may be overwritten) + notice_issue_update_conflict: The issue has been updated by an other user while you were editing it. + text_issue_conflict_resolution_cancel: Discard all my changes and redisplay %{link} + permission_manage_related_issues: Manage related issues + field_auth_source_ldap_filter: LDAP filter + label_search_for_watchers: Search for watchers to add + notice_account_deleted: Your account has been permanently deleted. + setting_unsubscribe: Allow users to delete their own account + button_delete_my_account: Delete my account + text_account_destroy_confirmation: |- + Are you sure you want to proceed? + Your account will be permanently deleted, with no way to reactivate it. + error_session_expired: Your session has expired. Please login again. + text_session_expiration_settings: "Warning: changing these settings may expire the current sessions including yours." + setting_session_lifetime: Session maximum lifetime + setting_session_timeout: Session inactivity timeout + label_session_expiration: Session expiration + permission_close_project: Close / reopen the project + label_show_closed_projects: View closed projects + button_close: Close + button_reopen: Reopen + project_status_active: active + project_status_closed: closed + project_status_archived: archived + text_project_closed: This project is closed and read-only. + notice_user_successful_create: User %{id} created. + field_core_fields: Standard fields + field_timeout: Timeout (in seconds) + setting_thumbnails_enabled: Display attachment thumbnails + setting_thumbnails_size: Thumbnails size (in pixels) + label_status_transitions: Status transitions + label_fields_permissions: Fields permissions + label_readonly: Read-only + label_required: Required + text_repository_identifier_info: Only lower case letters (a-z), numbers, dashes and underscores are allowed.
    Once saved, the identifier cannot be changed. + field_board_parent: Parent forum + label_attribute_of_project: Project's %{name} + label_attribute_of_author: Author's %{name} + label_attribute_of_assigned_to: Assignee's %{name} + label_attribute_of_fixed_version: Target version's %{name} + label_copy_subtasks: Copy subtasks + label_copied_to: copied to + label_copied_from: copied from + label_any_issues_in_project: any issues in project + label_any_issues_not_in_project: any issues not in project + field_private_notes: Private notes + permission_view_private_notes: View private notes + permission_set_notes_private: Set notes as private + label_no_issues_in_project: no issues in project + label_any: všetko + label_last_n_weeks: last %{count} weeks + setting_cross_project_subtasks: Allow cross-project subtasks + label_cross_project_descendants: S podprojektami + label_cross_project_tree: S projektovým stromom + label_cross_project_hierarchy: S hierarchiou projektu + label_cross_project_system: So všetkými projektami + button_hide: Hide + setting_non_working_week_days: Non-working days + label_in_the_next_days: in the next + label_in_the_past_days: in the past + label_attribute_of_user: User's %{name} + text_turning_multiple_off: If you disable multiple values, multiple values will be + removed in order to preserve only one value per item. + label_attribute_of_issue: Issue's %{name} + permission_add_documents: Add documents + permission_edit_documents: Edit documents + permission_delete_documents: Delete documents + label_gantt_progress_line: Progress line + setting_jsonp_enabled: Enable JSONP support + field_inherit_members: Inherit members + field_closed_on: Closed + setting_default_projects_tracker_ids: Default trackers for new projects + label_total_time: Celkovo + text_scm_config: You can configure your SCM commands in config/configuration.yml. Please restart the application after editing it. + text_scm_command_not_available: SCM command is not available. Please check settings on the administration panel. + setting_emails_header: Email header diff --git a/config/locales/sl.yml b/config/locales/sl.yml new file mode 100644 index 00000000..8c6e22b4 --- /dev/null +++ b/config/locales/sl.yml @@ -0,0 +1,1089 @@ +sl: + # Text direction: Left-to-Right (ltr) or Right-to-Left (rtl) + direction: ltr + date: + formats: + # Use the strftime parameters for formats. + # When no format has been given, it uses default. + # You can provide other formats here if you like! + default: "%Y-%m-%d" + short: "%b %d" + long: "%B %d, %Y" + + day_names: [Nedelja, Ponedeljek, Torek, Sreda, Četrtek, Petek, Sobota] + abbr_day_names: [Ned, Pon, To, Sr, Čet, Pet, Sob] + + # Don't forget the nil at the beginning; there's no such thing as a 0th month + month_names: [~, Januar, Februar, Marec, April, Maj, Junij, Julij, Avgust, September, Oktober, November, December] + abbr_month_names: [~, Jan, Feb, Mar, Apr, Maj, Jun, Jul, Aug, Sep, Okt, Nov, Dec] + # Used in date_select and datime_select. + order: + - :year + - :month + - :day + + time: + formats: + default: "%a, %d %b %Y %H:%M:%S %z" + time: "%H:%M" + short: "%d %b %H:%M" + long: "%B %d, %Y %H:%M" + am: "am" + pm: "pm" + + datetime: + distance_in_words: + half_a_minute: "pol minute" + less_than_x_seconds: + one: "manj kot 1. sekundo" + other: "manj kot %{count} sekund" + x_seconds: + one: "1. sekunda" + other: "%{count} sekund" + less_than_x_minutes: + one: "manj kot minuto" + other: "manj kot %{count} minut" + x_minutes: + one: "1 minuta" + other: "%{count} minut" + about_x_hours: + one: "okrog 1. ure" + other: "okrog %{count} ur" + x_hours: + one: "1 hour" + other: "%{count} hours" + x_days: + one: "1 dan" + other: "%{count} dni" + about_x_months: + one: "okrog 1. mesec" + other: "okrog %{count} mesecev" + x_months: + one: "1 mesec" + other: "%{count} mesecev" + about_x_years: + one: "okrog 1. leto" + other: "okrog %{count} let" + over_x_years: + one: "več kot 1. leto" + other: "več kot %{count} let" + almost_x_years: + one: "skoraj 1. leto" + other: "skoraj %{count} let" + + number: + format: + separator: "," + delimiter: "." + precision: 3 + human: + format: + precision: 3 + delimiter: "" + storage_units: + format: "%n %u" + units: + kb: KB + tb: TB + gb: GB + byte: + one: Byte + other: Bytes + mb: MB + +# Used in array.to_sentence. + support: + array: + sentence_connector: "in" + skip_last_comma: false + + activerecord: + errors: + template: + header: + one: "1. napaka je preprečila temu %{model} da bi se shranil" + other: "%{count} napak je preprečilo temu %{model} da bi se shranil" + messages: + inclusion: "ni vključen na seznamu" + exclusion: "je rezerviran" + invalid: "je napačen" + confirmation: "ne ustreza potrdilu" + accepted: "mora biti sprejet" + empty: "ne sme biti prazen" + blank: "ne sme biti neizpolnjen" + too_long: "je predolg" + too_short: "je prekratek" + wrong_length: "je napačne dolžine" + taken: "je že zaseden" + not_a_number: "ni število" + not_a_date: "ni veljaven datum" + greater_than: "mora biti večji kot %{count}" + greater_than_or_equal_to: "mora biti večji ali enak kot %{count}" + equal_to: "mora biti enak kot %{count}" + less_than: "mora biti manjši kot %{count}" + less_than_or_equal_to: "mora biti manjši ali enak kot %{count}" + odd: "mora biti sodo" + even: "mora biti liho" + greater_than_start_date: "mora biti kasnejši kot začetni datum" + not_same_project: "ne pripada istemu projektu" + circular_dependency: "Ta odnos bi povzročil krožno odvisnost" + cant_link_an_issue_with_a_descendant: "Zahtevek ne more biti povezan s svojo podnalogo" + + actionview_instancetag_blank_option: Prosimo izberite + + general_text_No: 'Ne' + general_text_Yes: 'Da' + general_text_no: 'ne' + general_text_yes: 'da' + general_lang_name: 'Slovenščina' + general_csv_separator: ',' + general_csv_decimal_separator: '.' + general_csv_encoding: UTF-8 + general_pdf_encoding: UTF-8 + general_first_day_of_week: '1' + + notice_account_updated: Račun je bil uspešno posodobljen. + notice_account_invalid_creditentials: Napačno uporabniško ime ali geslo + notice_account_password_updated: Geslo je bilo uspešno posodobljeno. + notice_account_wrong_password: Napačno geslo + notice_account_register_done: Račun je bil uspešno ustvarjen. Za aktivacijo potrdite povezavo, ki vam je bila poslana v e-nabiralnik. + notice_account_unknown_email: Neznan uporabnik. + notice_can_t_change_password: Ta račun za overovljanje uporablja zunanji. Gesla ni mogoče spremeniti. + notice_account_lost_email_sent: Poslano vam je bilo e-pismo z navodili za izbiro novega gesla. + notice_account_activated: Vaš račun je bil aktiviran. Sedaj se lahko prijavite. + notice_successful_create: Ustvarjanje uspelo. + notice_successful_update: Posodobitev uspela. + notice_successful_delete: Izbris uspel. + notice_successful_connection: Povezava uspela. + notice_file_not_found: Stran na katero se želite povezati ne obstaja ali pa je bila umaknjena. + notice_locking_conflict: Drug uporabnik je posodobil podatke. + notice_not_authorized: Nimate privilegijev za dostop do te strani. + notice_email_sent: "E-poštno sporočilo je bilo poslano %{value}" + notice_email_error: "Ob pošiljanju e-sporočila je prišlo do napake (%{value})" + notice_feeds_access_key_reseted: Vaš RSS dostopni ključ je bil ponastavljen. + notice_failed_to_save_issues: "Neuspelo shranjevanje %{count} zahtevka na %{total} izbranem: %{ids}." + notice_no_issue_selected: "Izbran ni noben zahtevek! Prosimo preverite zahtevke, ki jih želite urediti." + notice_account_pending: "Vaš račun je bil ustvarjen in čaka na potrditev s strani administratorja." + notice_default_data_loaded: Privzete nastavitve so bile uspešno naložene. + notice_unable_delete_version: Verzije ni bilo mogoče izbrisati. + + error_can_t_load_default_data: "Privzetih nastavitev ni bilo mogoče naložiti: %{value}" + error_scm_not_found: "Vnos ali revizija v shrambi ni bila najdena ." + error_scm_command_failed: "Med vzpostavljem povezave s shrambo je prišlo do napake: %{value}" + error_scm_annotate: "Vnos ne obstaja ali pa ga ni mogoče komentirati." + error_issue_not_found_in_project: 'Zahtevek ni bil najden ali pa ne pripada temu projektu' + + mail_subject_lost_password: "Vaše %{value} geslo" + mail_body_lost_password: 'Za spremembo glesla kliknite na naslednjo povezavo:' + mail_subject_register: "Aktivacija %{value} vašega računa" + mail_body_register: 'Za aktivacijo vašega računa kliknite na naslednjo povezavo:' + mail_body_account_information_external: "Za prijavo lahko uporabite vaš %{value} račun." + mail_body_account_information: Informacije o vašem računu + mail_subject_account_activation_request: "%{value} zahtevek za aktivacijo računa" + mail_body_account_activation_request: "Registriral se je nov uporabnik (%{value}). Račun čaka na vašo odobritev:" + mail_subject_reminder: "%{count} zahtevek(zahtevki) zapadejo v naslednjih %{days} dneh" + mail_body_reminder: "%{count} zahtevek(zahtevki), ki so vam dodeljeni bodo zapadli v naslednjih %{days} dneh:" + + + field_name: Ime + field_description: Opis + field_summary: Povzetek + field_is_required: Zahtevano + field_firstname: Ime + field_lastname: Priimek + field_mail: E-naslov + field_filename: Datoteka + field_filesize: Velikost + field_downloads: Prenosi + field_author: Avtor + field_created_on: Ustvarjen + field_updated_on: Posodobljeno + field_field_format: Format + field_is_for_all: Za vse projekte + field_possible_values: Možne vrednosti + field_regexp: Regularni izraz + field_min_length: Minimalna dolžina + field_max_length: Maksimalna dolžina + field_value: Vrednost + field_category: Kategorija + field_title: Naslov + field_project: Projekt + field_issue: Zahtevek + field_status: Status + field_notes: Zabeležka + field_is_closed: Zahtevek zaprt + field_is_default: Privzeta vrednost + field_tracker: Vrsta zahtevka + field_subject: Tema + field_due_date: Do datuma + field_assigned_to: Dodeljen + field_priority: Prioriteta + field_fixed_version: Ciljna verzija + field_user: Uporabnik + field_role: Vloga + field_homepage: Domača stran + field_is_public: Javno + field_parent: Podprojekt projekta + field_is_in_roadmap: Zahtevki prikazani na zemljevidu + field_login: Prijava + field_mail_notification: E-poštna oznanila + field_admin: Administrator + field_last_login_on: Zadnjič povezan(a) + field_language: Jezik + field_effective_date: Datum + field_password: Geslo + field_new_password: Novo geslo + field_password_confirmation: Potrditev + field_version: Verzija + field_type: Tip + field_host: Gostitelj + field_port: Vrata + field_account: Račun + field_base_dn: Bazni DN + field_attr_login: Oznaka za prijavo + field_attr_firstname: Oznaka za ime + field_attr_lastname: Oznaka za priimek + field_attr_mail: Oznaka za e-naslov + field_onthefly: Sprotna izdelava uporabnikov + field_start_date: Začetek + field_done_ratio: "% Narejeno" + field_auth_source: Način overovljanja + field_hide_mail: Skrij moj e-naslov + field_comments: Komentar + field_url: URL + field_start_page: Začetna stran + field_subproject: Podprojekt + field_hours: Ur + field_activity: Aktivnost + field_spent_on: Datum + field_identifier: Identifikator + field_is_filter: Uporabljen kot filter + field_issue_to: Povezan zahtevek + field_delay: Zamik + field_assignable: Zahtevki so lahko dodeljeni tej vlogi + field_redirect_existing_links: Preusmeri obstoječe povezave + field_estimated_hours: Ocenjen čas + field_column_names: Stolpci + field_time_zone: Časovni pas + field_searchable: Zmožen iskanja + field_default_value: Privzeta vrednost + field_comments_sorting: Prikaži komentarje + field_parent_title: Matična stran + + setting_app_title: Naslov aplikacije + setting_app_subtitle: Podnaslov aplikacije + setting_welcome_text: Pozdravno besedilo + setting_default_language: Privzeti jezik + setting_login_required: Zahtevano overovljanje + setting_self_registration: Samostojna registracija + setting_attachment_max_size: Maksimalna velikost priponk + setting_issues_export_limit: Skrajna meja za izvoz zahtevkov + setting_mail_from: E-naslov za emisijo + setting_bcc_recipients: Prejemniki slepih kopij (bcc) + setting_plain_text_mail: navadno e-sporočilo (ne HTML) + setting_host_name: Ime gostitelja in pot + setting_text_formatting: Oblikovanje besedila + setting_wiki_compression: Stiskanje Wiki zgodovine + setting_feeds_limit: Meja obsega RSS virov + setting_default_projects_public: Novi projekti so privzeto javni + setting_autofetch_changesets: Samodejni izvleček zapisa sprememb + setting_sys_api_enabled: Omogoči WS za upravljanje shrambe + setting_commit_ref_keywords: Sklicne ključne besede + setting_commit_fix_keywords: Urejanje ključne besede + setting_autologin: Avtomatska prijava + setting_date_format: Oblika datuma + setting_time_format: Oblika časa + setting_cross_project_issue_relations: Dovoli povezave zahtevkov med različnimi projekti + setting_issue_list_default_columns: Privzeti stolpci prikazani na seznamu zahtevkov + setting_emails_footer: Noga e-sporočil + setting_protocol: Protokol + setting_per_page_options: Število elementov na stran + setting_user_format: Oblika prikaza uporabnikov + setting_activity_days_default: Prikaz dni na aktivnost projekta + setting_display_subprojects_issues: Privzeti prikaz zahtevkov podprojektov v glavnem projektu + setting_enabled_scm: Omogočen SCM + setting_mail_handler_api_enabled: Omogoči WS za prihajajočo e-pošto + setting_mail_handler_api_key: API ključ + setting_sequential_project_identifiers: Generiraj projektne identifikatorje sekvenčno + setting_gravatar_enabled: Uporabljaj Gravatar ikone + setting_diff_max_lines_displayed: Maksimalno število prikazanih vrstic različnosti + + permission_edit_project: Uredi projekt + permission_select_project_modules: Izberi module projekta + permission_manage_members: Uredi člane + permission_manage_versions: Uredi verzije + permission_manage_categories: Urejanje kategorij zahtevkov + permission_add_issues: Dodaj zahtevke + permission_edit_issues: Uredi zahtevke + permission_manage_issue_relations: Uredi odnose med zahtevki + permission_add_issue_notes: Dodaj zabeležke + permission_edit_issue_notes: Uredi zabeležke + permission_edit_own_issue_notes: Uredi lastne zabeležke + permission_move_issues: Premakni zahtevke + permission_delete_issues: Izbriši zahtevke + permission_manage_public_queries: Uredi javna povpraševanja + permission_save_queries: Shrani povpraševanje + permission_view_gantt: Poglej gantogram + permission_view_calendar: Poglej koledar + permission_view_issue_watchers: Oglej si listo spremeljevalcev + permission_add_issue_watchers: Dodaj spremljevalce + permission_log_time: Beleži porabljen čas + permission_view_time_entries: Poglej porabljen čas + permission_edit_time_entries: Uredi beležko časa + permission_edit_own_time_entries: Uredi beležko lastnega časa + permission_manage_news: Uredi novice + permission_comment_news: Komentiraj novice + permission_view_documents: Poglej dokumente + permission_manage_files: Uredi datoteke + permission_view_files: Poglej datoteke + permission_manage_wiki: Uredi wiki + permission_rename_wiki_pages: Preimenuj wiki strani + permission_delete_wiki_pages: Izbriši wiki strani + permission_view_wiki_pages: Poglej wiki + permission_view_wiki_edits: Poglej wiki zgodovino + permission_edit_wiki_pages: Uredi wiki strani + permission_delete_wiki_pages_attachments: Izbriši priponke + permission_protect_wiki_pages: Zaščiti wiki strani + permission_manage_repository: Uredi shrambo + permission_browse_repository: Prebrskaj shrambo + permission_view_changesets: Poglej zapis sprememb + permission_commit_access: Dostop za predajo + permission_manage_boards: Uredi table + permission_view_messages: Poglej sporočila + permission_add_messages: Objavi sporočila + permission_edit_messages: Uredi sporočila + permission_edit_own_messages: Uredi lastna sporočila + permission_delete_messages: Izbriši sporočila + permission_delete_own_messages: Izbriši lastna sporočila + + project_module_issue_tracking: Sledenje zahtevkom + project_module_time_tracking: Sledenje časa + project_module_news: Novice + project_module_documents: Dokumenti + project_module_files: Datoteke + project_module_wiki: Wiki + project_module_repository: Shramba + project_module_boards: Table + + label_user: Uporabnik + label_user_plural: Uporabniki + label_user_new: Nov uporabnik + label_project: Projekt + label_project_new: Nov projekt + label_project_plural: Projekti + label_x_projects: + zero: ni projektov + one: 1 projekt + other: "%{count} projektov" + label_project_all: Vsi projekti + label_project_latest: Zadnji projekti + label_issue: Zahtevek + label_issue_new: Nov zahtevek + label_issue_plural: Zahtevki + label_issue_view_all: Poglej vse zahtevke + label_issues_by: "Zahtevki od %{value}" + label_issue_added: Zahtevek dodan + label_issue_updated: Zahtevek posodobljen + label_document: Dokument + label_document_new: Nov dokument + label_document_plural: Dokumenti + label_document_added: Dokument dodan + label_role: Vloga + label_role_plural: Vloge + label_role_new: Nova vloga + label_role_and_permissions: Vloge in dovoljenja + label_member: Član + label_member_new: Nov član + label_member_plural: Člani + label_tracker: Vrsta zahtevka + label_tracker_plural: Vrste zahtevkov + label_tracker_new: Nova vrsta zahtevka + label_workflow: Potek dela + label_issue_status: Stanje zahtevka + label_issue_status_plural: Stanje zahtevkov + label_issue_status_new: Novo stanje + label_issue_category: Kategorija zahtevka + label_issue_category_plural: Kategorije zahtevkov + label_issue_category_new: Nova kategorija + label_custom_field: Polje po meri + label_custom_field_plural: Polja po meri + label_custom_field_new: Novo polje po meri + label_enumerations: Seznami + label_enumeration_new: Nova vrednost + label_information: Informacija + label_information_plural: Informacije + label_please_login: Prosimo prijavite se + label_register: Registracija + label_password_lost: Izgubljeno geslo + label_home: Domov + label_my_page: Moja stran + label_my_account: Moj račun + label_my_projects: Moji projekti + label_administration: Upravljanje + label_login: Prijavi se + label_logout: Odjavi se + label_help: Pomoč + label_reported_issues: Prijavljeni zahtevki + label_assigned_to_me_issues: Zahtevki dodeljeni meni + label_last_login: Zadnja povezava + label_registered_on: Registriran + label_activity: Aktivnost + label_overall_activity: Celotna aktivnost + label_user_activity: "Aktivnost %{value}" + label_new: Nov + label_logged_as: Prijavljen(a) kot + label_environment: Okolje + label_authentication: Overovitev + label_auth_source: Način overovitve + label_auth_source_new: Nov način overovitve + label_auth_source_plural: Načini overovitve + label_subproject_plural: Podprojekti + label_and_its_subprojects: "%{value} in njegovi podprojekti" + label_min_max_length: Min - Max dolžina + label_list: Seznam + label_date: Datum + label_integer: Celo število + label_float: Decimalno število + label_boolean: Boolean + label_string: Besedilo + label_text: Dolgo besedilo + label_attribute: Lastnost + label_attribute_plural: Lastnosti + label_no_data: Ni podatkov za prikaz + label_change_status: Spremeni stanje + label_history: Zgodovina + label_attachment: Datoteka + label_attachment_new: Nova datoteka + label_attachment_delete: Izbriši datoteko + label_attachment_plural: Datoteke + label_file_added: Datoteka dodana + label_report: Poročilo + label_report_plural: Poročila + label_news: Novica + label_news_new: Dodaj novico + label_news_plural: Novice + label_news_latest: Zadnje novice + label_news_view_all: Poglej vse novice + label_news_added: Dodane novice + label_settings: Nastavitve + label_overview: Pregled + label_version: Verzija + label_version_new: Nova verzija + label_version_plural: Verzije + label_confirmation: Potrditev + label_export_to: 'Na razpolago tudi v:' + label_read: Preberi... + label_public_projects: Javni projekti + label_open_issues: odprt zahtevek + label_open_issues_plural: odprti zahtevki + label_closed_issues: zaprt zahtevek + label_closed_issues_plural: zaprti zahtevki + label_x_open_issues_abbr_on_total: + zero: 0 odprtih / %{total} + one: 1 odprt / %{total} + other: "%{count} odprtih / %{total}" + label_x_open_issues_abbr: + zero: 0 odprtih + one: 1 odprt + other: "%{count} odprtih" + label_x_closed_issues_abbr: + zero: 0 zaprtih + one: 1 zaprt + other: "%{count} zaprtih" + label_total: Skupaj + label_permissions: Dovoljenja + label_current_status: Trenutno stanje + label_new_statuses_allowed: Novi zahtevki dovoljeni + label_all: vsi + label_none: noben + label_nobody: nihče + label_next: Naslednji + label_previous: Prejšnji + label_used_by: V uporabi od + label_details: Podrobnosti + label_add_note: Dodaj zabeležko + label_per_page: Na stran + label_calendar: Koledar + label_months_from: mesecev od + label_gantt: Gantogram + label_internal: Notranji + label_last_changes: "zadnjih %{count} sprememb" + label_change_view_all: Poglej vse spremembe + label_personalize_page: Individualiziraj to stran + label_comment: Komentar + label_comment_plural: Komentarji + label_x_comments: + zero: ni komentarjev + one: 1 komentar + other: "%{count} komentarjev" + label_comment_add: Dodaj komentar + label_comment_added: Komentar dodan + label_comment_delete: Izbriši komentarje + label_query: Iskanje po meri + label_query_plural: Iskanja po meri + label_query_new: Novo iskanje + label_filter_add: Dodaj filter + label_filter_plural: Filtri + label_equals: je enako + label_not_equals: ni enako + label_in_less_than: v manj kot + label_in_more_than: v več kot + label_in: v + label_today: danes + label_all_time: v vsem času + label_yesterday: včeraj + label_this_week: ta teden + label_last_week: pretekli teden + label_last_n_days: "zadnjih %{count} dni" + label_this_month: ta mesec + label_last_month: zadnji mesec + label_this_year: to leto + label_date_range: Razpon datumov + label_less_than_ago: manj kot dni nazaj + label_more_than_ago: več kot dni nazaj + label_ago: dni nazaj + label_contains: vsebuje + label_not_contains: ne vsebuje + label_day_plural: dni + label_repository: Shramba + label_repository_plural: Shrambe + label_browse: Prebrskaj + label_revision: Revizija + label_revision_plural: Revizije + label_associated_revisions: Povezane revizije + label_added: dodano + label_modified: spremenjeno + label_copied: kopirano + label_renamed: preimenovano + label_deleted: izbrisano + label_latest_revision: Zadnja revizija + label_latest_revision_plural: Zadnje revizije + label_view_revisions: Poglej revizije + label_max_size: Največja velikost + label_sort_highest: Premakni na vrh + label_sort_higher: Premakni gor + label_sort_lower: Premakni dol + label_sort_lowest: Premakni na dno + label_roadmap: Načrt + label_roadmap_due_in: "Do %{value}" + label_roadmap_overdue: "%{value} zakasnel" + label_roadmap_no_issues: Ni zahtevkov za to verzijo + label_search: Išči + label_result_plural: Rezultati + label_all_words: Vse besede + label_wiki: Wiki + label_wiki_edit: Wiki urejanje + label_wiki_edit_plural: Wiki urejanja + label_wiki_page: Wiki stran + label_wiki_page_plural: Wiki strani + label_index_by_title: Razvrsti po naslovu + label_index_by_date: Razvrsti po datumu + label_current_version: Trenutna verzija + label_preview: Predogled + label_feed_plural: RSS viri + label_changes_details: Podrobnosti o vseh spremembah + label_issue_tracking: Sledenje zahtevkom + label_spent_time: Porabljen čas + label_f_hour: "%{value} ura" + label_f_hour_plural: "%{value} ur" + label_time_tracking: Sledenje času + label_change_plural: Spremembe + label_statistics: Statistika + label_commits_per_month: Predaj na mesec + label_commits_per_author: Predaj na avtorja + label_view_diff: Preglej razlike + label_diff_inline: znotraj + label_diff_side_by_side: vzporedno + label_options: Možnosti + label_copy_workflow_from: Kopiraj potek dela od + label_permissions_report: Poročilo o dovoljenjih + label_watched_issues: Spremljani zahtevki + label_related_issues: Povezani zahtevki + label_applied_status: Uveljavljeno stanje + label_loading: Nalaganje... + label_relation_new: Nova povezava + label_relation_delete: Izbriši povezavo + label_relates_to: povezan z + label_duplicates: duplikati + label_duplicated_by: dupliciral + label_blocks: blok + label_blocked_by: blokiral + label_precedes: ima prednost pred + label_follows: sledi + label_end_to_start: konec na začetek + label_end_to_end: konec na konec + label_start_to_start: začetek na začetek + label_start_to_end: začetek na konec + label_stay_logged_in: Ostani prijavljen(a) + label_disabled: onemogoči + label_show_completed_versions: Prikaži zaključene verzije + label_me: jaz + label_board: Forum + label_board_new: Nov forum + label_board_plural: Forumi + label_topic_plural: Teme + label_message_plural: Sporočila + label_message_last: Zadnje sporočilo + label_message_new: Novo sporočilo + label_message_posted: Sporočilo dodano + label_reply_plural: Odgovori + label_send_information: Pošlji informacijo o računu uporabniku + label_year: Leto + label_month: Mesec + label_week: Teden + label_date_from: Do + label_date_to: Do + label_language_based: Glede na uporabnikov jezik + label_sort_by: "Razporedi po %{value}" + label_send_test_email: Pošlji testno e-pismo + label_feeds_access_key_created_on: "RSS dostopni ključ narejen %{value} nazaj" + label_module_plural: Moduli + label_added_time_by: "Dodan %{author} %{age} nazaj" + label_updated_time_by: "Posodobljen od %{author} %{age} nazaj" + label_updated_time: "Posodobljen %{value} nazaj" + label_jump_to_a_project: Skoči na projekt... + label_file_plural: Datoteke + label_changeset_plural: Zapisi sprememb + label_default_columns: Privzeti stolpci + label_no_change_option: (Ni spremembe) + label_bulk_edit_selected_issues: Uredi izbrane zahtevke skupaj + label_theme: Tema + label_default: Privzeto + label_search_titles_only: Preišči samo naslove + label_user_mail_option_all: "Za vsak dogodek v vseh mojih projektih" + label_user_mail_option_selected: "Za vsak dogodek samo na izbranih projektih..." + label_user_mail_no_self_notified: "Ne želim biti opozorjen(a) na spremembe, ki jih naredim sam(a)" + label_registration_activation_by_email: aktivacija računa po e-pošti + label_registration_manual_activation: ročna aktivacija računa + label_registration_automatic_activation: samodejna aktivacija računa + label_display_per_page: "Na stran: %{value}" + label_age: Starost + label_change_properties: Sprememba lastnosti + label_general: Splošno + label_more: Več + label_scm: SCM + label_plugins: Vtičniki + label_ldap_authentication: LDAP overovljanje + label_downloads_abbr: D/L + label_optional_description: Neobvezen opis + label_add_another_file: Dodaj še eno datoteko + label_preferences: Preference + label_chronological_order: Kronološko + label_reverse_chronological_order: Obrnjeno kronološko + label_planning: Načrtovanje + label_incoming_emails: Prihajajoča e-pošta + label_generate_key: Ustvari ključ + label_issue_watchers: Spremljevalci + label_example: Vzorec + + button_login: Prijavi se + button_submit: Pošlji + button_save: Shrani + button_check_all: Označi vse + button_uncheck_all: Odznači vse + button_delete: Izbriši + button_create: Ustvari + button_test: Testiraj + button_edit: Uredi + button_add: Dodaj + button_change: Spremeni + button_apply: Uporabi + button_clear: Počisti + button_lock: Zakleni + button_unlock: Odkleni + button_download: Prenesi + button_list: Seznam + button_view: Pogled + button_move: Premakni + button_back: Nazaj + button_cancel: Prekliči + button_activate: Aktiviraj + button_sort: Razvrsti + button_log_time: Beleži čas + button_rollback: Povrni na to verzijo + button_watch: Spremljaj + button_unwatch: Ne spremljaj + button_reply: Odgovori + button_archive: Arhiviraj + button_unarchive: Odarhiviraj + button_reset: Ponastavi + button_rename: Preimenuj + button_change_password: Spremeni geslo + button_copy: Kopiraj + button_annotate: Zapiši pripombo + button_update: Posodobi + button_configure: Konfiguriraj + button_quote: Citiraj + + status_active: aktivni + status_registered: registriran + status_locked: zaklenjen + + text_select_mail_notifications: Izberi dejanja za katera naj bodo poslana oznanila preko e-pošto. + text_regexp_info: npr. ^[A-Z0-9]+$ + text_min_max_length_info: 0 pomeni brez omejitev + text_project_destroy_confirmation: Ali ste prepričani da želite izbrisati izbrani projekt in vse z njim povezane podatke? + text_subprojects_destroy_warning: "Njegov(i) podprojekt(i): %{value} bodo prav tako izbrisani." + text_workflow_edit: Izberite vlogo in zahtevek za urejanje poteka dela + text_are_you_sure: Ali ste prepričani? + text_tip_issue_begin_day: naloga z začetkom na ta dan + text_tip_issue_end_day: naloga z zaključkom na ta dan + text_tip_issue_begin_end_day: naloga ki se začne in konča ta dan + text_caracters_maximum: "največ %{count} znakov." + text_caracters_minimum: "Mora biti vsaj dolg vsaj %{count} znakov." + text_length_between: "Dolžina med %{min} in %{max} znakov." + text_tracker_no_workflow: Potek dela za to vrsto zahtevka ni določen + text_unallowed_characters: Nedovoljeni znaki + text_comma_separated: Dovoljenih je več vrednosti (ločenih z vejico). + text_issues_ref_in_commit_messages: Zahtevki sklicev in popravkov v sporočilu predaje + text_issue_added: "Zahtevek %{id} je sporočil(a) %{author}." + text_issue_updated: "Zahtevek %{id} je posodobil(a) %{author}." + text_wiki_destroy_confirmation: Ali ste prepričani da želite izbrisati ta wiki in vso njegovo vsebino? + text_issue_category_destroy_question: "Nekateri zahtevki (%{count}) so dodeljeni tej kategoriji. Kaj želite storiti?" + text_issue_category_destroy_assignments: Odstrani naloge v kategoriji + text_issue_category_reassign_to: Ponovno dodeli zahtevke tej kategoriji + text_user_mail_option: "Na neizbrane projekte boste prejemali le obvestila o zadevah ki jih spremljate ali v katere ste vključeni (npr. zahtevki katerih avtor(ica) ste)" + text_no_configuration_data: "Vloge, vrste zahtevkov, statusi zahtevkov in potek dela še niso bili določeni. \nZelo priporočljivo je, da naložite privzeto konfiguracijo, ki jo lahko kasneje tudi prilagodite." + text_load_default_configuration: Naloži privzeto konfiguracijo + text_status_changed_by_changeset: "Dodano v zapis sprememb %{value}." + text_issues_destroy_confirmation: 'Ali ste prepričani, da želite izbrisati izbrani(e) zahtevek(ke)?' + text_select_project_modules: 'Izberite module, ki jih želite omogočiti za ta projekt:' + text_default_administrator_account_changed: Spremenjen privzeti administratorski račun + text_file_repository_writable: Omogočeno pisanje v shrambo datotek + text_rmagick_available: RMagick je na voljo(neobvezno) + text_destroy_time_entries_question: "%{hours} ur je bilo opravljenih na zahtevku, ki ga želite izbrisati. Kaj želite storiti?" + text_destroy_time_entries: Izbriši opravljene ure + text_assign_time_entries_to_project: Predaj opravljene ure projektu + text_reassign_time_entries: 'Prenesi opravljene ure na ta zahtevek:' + text_user_wrote: "%{value} je napisal(a):" + text_enumeration_destroy_question: "%{count} objektov je določenih tej vrednosti." + text_enumeration_category_reassign_to: 'Ponastavi jih na to vrednost:' + text_email_delivery_not_configured: "E-poštna dostava ni nastavljena in oznanila so onemogočena.\nNastavite vaš SMTP strežnik v config/configuration.yml in ponovno zaženite aplikacijo da ga omogočite.\n" + text_repository_usernames_mapping: "Izberite ali posodobite Redmine uporabnika dodeljenega vsakemu uporabniškemu imenu najdenemu v zapisniku shrambe.\n Uporabniki z enakim Redmine ali shrambinem uporabniškem imenu ali e-poštnem naslovu so samodejno dodeljeni." + text_diff_truncated: '... Ta sprememba je bila odsekana ker presega največjo velikost ki je lahko prikazana.' + + default_role_manager: Upravnik + default_role_developer: Razvijalec + default_role_reporter: Poročevalec + default_tracker_bug: Hrošč + default_tracker_feature: Funkcija + default_tracker_support: Podpora + default_issue_status_new: Nov + default_issue_status_in_progress: V teku + default_issue_status_resolved: Rešen + default_issue_status_feedback: Povratna informacija + default_issue_status_closed: Zaključen + default_issue_status_rejected: Zavrnjen + default_doc_category_user: Uporabniška dokumentacija + default_doc_category_tech: Tehnična dokumentacija + default_priority_low: Nizka + default_priority_normal: Običajna + default_priority_high: Visoka + default_priority_urgent: Urgentna + default_priority_immediate: Takojšnje ukrepanje + default_activity_design: Oblikovanje + default_activity_development: Razvoj + + enumeration_issue_priorities: Prioritete zahtevkov + enumeration_doc_categories: Kategorije dokumentov + enumeration_activities: Aktivnosti (sledenje časa) + warning_attachments_not_saved: "%{count} datotek(e) ni bilo mogoče shraniti." + field_editable: Uredljivo + text_plugin_assets_writable: Zapisljiva mapa za vtičnike + label_display: Prikaz + button_create_and_continue: Ustvari in nadaljuj + text_custom_field_possible_values_info: 'Ena vrstica za vsako vrednost' + setting_repository_log_display_limit: Največje število prikazanih revizij v log datoteki + setting_file_max_size_displayed: Največja velikost besedilnih datotek v vključenem prikazu + field_watcher: Opazovalec + setting_openid: Dovoli OpenID prijavo in registracijo + field_identity_url: OpenID URL + label_login_with_open_id_option: ali se prijavi z OpenID + field_content: Vsebina + label_descending: Padajoče + label_sort: Razvrsti + label_ascending: Naraščajoče + label_date_from_to: Od %{start} do %{end} + label_greater_or_equal: ">=" + label_less_or_equal: <= + text_wiki_page_destroy_question: Ta stran ima %{descendants} podstran(i) in naslednik(ov). Kaj želite storiti? + text_wiki_page_reassign_children: Znova dodeli podstrani tej glavni strani + text_wiki_page_nullify_children: Obdrži podstrani kot glavne strani + text_wiki_page_destroy_children: Izbriši podstrani in vse njihove naslednike + setting_password_min_length: Minimalna dolžina gesla + field_group_by: Združi rezultate po + mail_subject_wiki_content_updated: "'%{id}' wiki stran je bila posodobljena" + label_wiki_content_added: Wiki stran dodana + mail_subject_wiki_content_added: "'%{id}' wiki stran je bila dodana" + mail_body_wiki_content_added: "%{author} je dodal '%{id}' wiki stran" + label_wiki_content_updated: Wiki stran posodobljena + mail_body_wiki_content_updated: "%{author} je posodobil '%{id}' wiki stran." + permission_add_project: Ustvari projekt + setting_new_project_user_role_id: Vloga, dodeljena neadministratorskemu uporabniku, ki je ustvaril projekt + label_view_all_revisions: Poglej vse revizije + label_tag: Oznaka + label_branch: Veja + error_no_tracker_in_project: Noben sledilnik ni povezan s tem projektom. Prosimo preverite nastavitve projekta. + error_no_default_issue_status: Privzeti zahtevek ni definiran. Prosimo preverite svoje nastavitve (Pojdite na "Administracija -> Stanje zahtevkov"). + text_journal_changed: "%{label} se je spremenilo iz %{old} v %{new}" + text_journal_set_to: "%{label} nastavljeno na %{value}" + text_journal_deleted: "%{label} izbrisan (%{old})" + label_group_plural: Skupine + label_group: Skupina + label_group_new: Nova skupina + label_time_entry_plural: Porabljen čas + text_journal_added: "%{label} %{value} dodan" + field_active: Aktiven + enumeration_system_activity: Sistemska aktivnost + permission_delete_issue_watchers: Izbriši opazovalce + version_status_closed: zaprt + version_status_locked: zaklenjen + version_status_open: odprt + error_can_not_reopen_issue_on_closed_version: Zahtevek dodeljen zaprti verziji ne more biti ponovno odprt + label_user_anonymous: Anonimni + button_move_and_follow: Premakni in sledi + setting_default_projects_modules: Privzeti moduli za nove projekte + setting_gravatar_default: Privzeta Gravatar slika + field_sharing: Deljenje + label_version_sharing_hierarchy: S projektno hierarhijo + label_version_sharing_system: Z vsemi projekti + label_version_sharing_descendants: S podprojekti + label_version_sharing_tree: Z drevesom projekta + label_version_sharing_none: Ni deljeno + error_can_not_archive_project: Ta projekt ne more biti arhiviran + button_duplicate: Podvoji + button_copy_and_follow: Kopiraj in sledi + label_copy_source: Vir + setting_issue_done_ratio: Izračunaj razmerje opravljenega zahtevka z + setting_issue_done_ratio_issue_status: Uporabi stanje zahtevka + error_issue_done_ratios_not_updated: Razmerje opravljenega zahtevka ni bilo posodobljeno. + error_workflow_copy_target: Prosimo izberite ciljni(e) sledilnik(e) in vlogo(e) + setting_issue_done_ratio_issue_field: Uporabi polje zahtevka + label_copy_same_as_target: Enako kot cilj + label_copy_target: Cilj + notice_issue_done_ratios_updated: Razmerje opravljenega zahtevka posodobljeno. + error_workflow_copy_source: Prosimo izberite vir zahtevka ali vlogo + label_update_issue_done_ratios: Posodobi razmerje opravljenega zahtevka + setting_start_of_week: Začni koledarje z + permission_view_issues: Poglej zahtevke + label_display_used_statuses_only: Prikaži samo stanja ki uporabljajo ta sledilnik + label_revision_id: Revizija %{value} + label_api_access_key: API dostopni ključ + label_api_access_key_created_on: API dostopni ključ ustvarjen pred %{value} + label_feeds_access_key: RSS dostopni ključ + notice_api_access_key_reseted: Vaš API dostopni ključ je bil ponastavljen. + setting_rest_api_enabled: Omogoči REST spletni servis + label_missing_api_access_key: Manjkajoč API dostopni ključ + label_missing_feeds_access_key: Manjkajoč RSS dostopni ključ + button_show: Prikaži + text_line_separated: Dovoljenih več vrednosti (ena vrstica za vsako vrednost). + setting_mail_handler_body_delimiters: Odreži e-pošto po eni od teh vrstic + permission_add_subprojects: Ustvari podprojekte + label_subproject_new: Nov podprojekt + text_own_membership_delete_confirmation: |- + Odstranili boste nekatere ali vse od dovoljenj zaradi česar morda ne boste mogli več urejati tega projekta. + Ali ste prepričani, da želite nadaljevati? + label_close_versions: Zapri dokončane verzije + label_board_sticky: Lepljivo + label_board_locked: Zaklenjeno + permission_export_wiki_pages: Izvozi wiki strani + setting_cache_formatted_text: Predpomni oblikovano besedilo + permission_manage_project_activities: Uredi aktivnosti projekta + error_unable_delete_issue_status: Stanja zahtevka ni bilo možno spremeniti + label_profile: Profil + permission_manage_subtasks: Uredi podnaloge + field_parent_issue: Nadrejena naloga + label_subtask_plural: Podnaloge + label_project_copy_notifications: Med kopiranjem projekta pošlji e-poštno sporočilo + error_can_not_delete_custom_field: Polja po meri ni mogoče izbrisati + error_unable_to_connect: Povezava ni mogoča (%{value}) + error_can_not_remove_role: Ta vloga je v uporabi in je ni mogoče izbrisati. + error_can_not_delete_tracker: Ta sledilnik vsebuje zahtevke in se ga ne more izbrisati. + field_principal: Upravnik varnosti + label_my_page_block: Moj gradnik strani + notice_failed_to_save_members: "Shranjevanje uporabnika(ov) ni uspelo: %{errors}." + text_zoom_out: Približaj + text_zoom_in: Oddalji + notice_unable_delete_time_entry: Brisanje dnevnika porabljenaga časa ni mogoče. + label_overall_spent_time: Skupni porabljeni čas + field_time_entries: Beleži porabljeni čas + project_module_gantt: Gantogram + project_module_calendar: Koledear + button_edit_associated_wikipage: "Uredi povezano Wiki stran: %{page_title}" + field_text: Besedilno polje + label_user_mail_option_only_owner: Samo za stvari katerih lastnik sem + setting_default_notification_option: Privzeta možnost obveščanja + label_user_mail_option_only_my_events: Samo za stvari, ki jih opazujem ali sem v njih vpleten + label_user_mail_option_only_assigned: Samo za stvari, ki smo mi dodeljene + label_user_mail_option_none: Noben dogodek + field_member_of_group: Pooblaščenčeva skupina + field_assigned_to_role: Pooblaščenčeva vloga + notice_not_authorized_archived_project: Projekt, do katerega poskušate dostopati, je bil arhiviran. + label_principal_search: "Poišči uporabnika ali skupino:" + label_user_search: "Poišči uporabnikia:" + field_visible: Viden + setting_emails_header: Glava e-pošte + setting_commit_logtime_activity_id: Aktivnost zabeleženega časa + text_time_logged_by_changeset: Uporabljeno v spremembi %{value}. + setting_commit_logtime_enabled: Omogoči beleženje časa + notice_gantt_chart_truncated: Graf je bil odrezan, ker je prekoračil največje dovoljeno število elementov, ki se jih lahko prikaže (%{max}) + setting_gantt_items_limit: Največje število elementov prikazano na gantogramu + field_warn_on_leaving_unsaved: Opozori me, kadar zapuščam stran z neshranjenim besedilom + text_warn_on_leaving_unsaved: Trenutna stran vsebuje neshranjeno besedilo ki bo izgubljeno, če zapustite to stran. + label_my_queries: Moje poizvedbe po meri + text_journal_changed_no_detail: "%{label} posodobljen" + label_news_comment_added: Komentar dodan novici + button_expand_all: Razširi vse + button_collapse_all: Skrči vse + label_additional_workflow_transitions_for_assignee: Dovoljeni dodatni prehodi kadar je uporabnik pooblaščenec + label_additional_workflow_transitions_for_author: Dovoljeni dodatni prehodi kadar je uporabnik avtor + label_bulk_edit_selected_time_entries: Skupinsko urejanje izbranih časovnih zapisov + text_time_entries_destroy_confirmation: Ali ste prepričani, da želite izbristai izbran(e) časovn(i/e) zapis(e)? + label_role_anonymous: Anonimni + label_role_non_member: Nečlan + label_issue_note_added: Dodan zaznamek + label_issue_status_updated: Status posodobljen + label_issue_priority_updated: Prioriteta posodobljena + label_issues_visibility_own: Zahtevek ustvarjen s strani uporabnika ali dodeljen uporabniku + field_issues_visibility: Vidljivost zahtevkov + label_issues_visibility_all: Vsi zahtevki + permission_set_own_issues_private: Nastavi lastne zahtevke kot javne ali zasebne + field_is_private: Zaseben + permission_set_issues_private: Nastavi zahtevke kot javne ali zasebne + label_issues_visibility_public: Vsi nezasebni zahtevki + text_issues_destroy_descendants_confirmation: To bo izbrisalo tudi %{count} podnalog(o). + field_commit_logs_encoding: Kodiranje sporočil ob predaji + field_scm_path_encoding: Pot do kodiranja + text_scm_path_encoding_note: "Privzeto: UTF-8" + field_path_to_repository: Pot do shrambe + field_root_directory: Korenska mapa + field_cvs_module: Modul + field_cvsroot: CVSROOT + text_mercurial_repository_note: Lokalna shramba (npr. /hgrepo, c:\hgrepo) + text_scm_command: Ukaz + text_scm_command_version: Verzija + label_git_report_last_commit: Sporoči zadnje uveljavljanje datotek in map + text_scm_config: Svoje SCM ukaze lahko nastavite v datoteki config/configuration.yml. Po urejanju prosimo ponovno zaženite aplikacijo. + text_scm_command_not_available: SCM ukaz ni na voljo. Prosimo preverite nastavitve v upravljalskem podoknu. + + text_git_repository_note: Shramba je prazna in lokalna (npr. /gitrepo, c:\gitrepo) + + notice_issue_successful_create: Ustvarjen zahtevek %{id}. + label_between: med + setting_issue_group_assignment: Dovoli dodeljevanje zahtevka skupinam + label_diff: diff + + description_query_sort_criteria_direction: Sort direction + description_project_scope: Search scope + description_filter: Filter + description_user_mail_notification: Mail notification settings + description_date_from: Enter start date + description_message_content: Message content + description_available_columns: Available Columns + description_date_range_interval: Choose range by selecting start and end date + description_issue_category_reassign: Choose issue category + description_search: Searchfield + description_notes: Notes + description_date_range_list: Choose range from list + description_choose_project: Projects + description_date_to: Enter end date + description_query_sort_criteria_attribute: Sort attribute + description_wiki_subpages_reassign: Choose new parent page + description_selected_columns: Selected Columns + label_parent_revision: Parent + label_child_revision: Child + error_scm_annotate_big_text_file: The entry cannot be annotated, as it exceeds the maximum text file size. + setting_default_issue_start_date_to_creation_date: Use current date as start date for new issues + button_edit_section: Edit this section + setting_repositories_encodings: Attachments and repositories encodings + description_all_columns: All Columns + button_export: Export + label_export_options: "%{export_format} export options" + error_attachment_too_big: This file cannot be uploaded because it exceeds the maximum allowed file size (%{max_size}) + notice_failed_to_save_time_entries: "Failed to save %{count} time entrie(s) on %{total} selected: %{ids}." + label_x_issues: + zero: 0 zahtevek + one: 1 zahtevek + other: "%{count} zahtevki" + label_repository_new: New repository + field_repository_is_default: Main repository + label_copy_attachments: Copy attachments + label_item_position: "%{position}/%{count}" + label_completed_versions: Completed versions + text_project_identifier_info: Only lower case letters (a-z), numbers, dashes and underscores are allowed.
    Once saved, the identifier cannot be changed. + field_multiple: Multiple values + setting_commit_cross_project_ref: Allow issues of all the other projects to be referenced and fixed + text_issue_conflict_resolution_add_notes: Add my notes and discard my other changes + text_issue_conflict_resolution_overwrite: Apply my changes anyway (previous notes will be kept but some changes may be overwritten) + notice_issue_update_conflict: The issue has been updated by an other user while you were editing it. + text_issue_conflict_resolution_cancel: Discard all my changes and redisplay %{link} + permission_manage_related_issues: Manage related issues + field_auth_source_ldap_filter: LDAP filter + label_search_for_watchers: Search for watchers to add + notice_account_deleted: Your account has been permanently deleted. + setting_unsubscribe: Allow users to delete their own account + button_delete_my_account: Delete my account + text_account_destroy_confirmation: |- + Are you sure you want to proceed? + Your account will be permanently deleted, with no way to reactivate it. + error_session_expired: Your session has expired. Please login again. + text_session_expiration_settings: "Warning: changing these settings may expire the current sessions including yours." + setting_session_lifetime: Session maximum lifetime + setting_session_timeout: Session inactivity timeout + label_session_expiration: Session expiration + permission_close_project: Close / reopen the project + label_show_closed_projects: View closed projects + button_close: Close + button_reopen: Reopen + project_status_active: active + project_status_closed: closed + project_status_archived: archived + text_project_closed: This project is closed and read-only. + notice_user_successful_create: User %{id} created. + field_core_fields: Standard fields + field_timeout: Timeout (in seconds) + setting_thumbnails_enabled: Display attachment thumbnails + setting_thumbnails_size: Thumbnails size (in pixels) + label_status_transitions: Status transitions + label_fields_permissions: Fields permissions + label_readonly: Read-only + label_required: Required + text_repository_identifier_info: Only lower case letters (a-z), numbers, dashes and underscores are allowed.
    Once saved, the identifier cannot be changed. + field_board_parent: Parent forum + label_attribute_of_project: Project's %{name} + label_attribute_of_author: Author's %{name} + label_attribute_of_assigned_to: Assignee's %{name} + label_attribute_of_fixed_version: Target version's %{name} + label_copy_subtasks: Copy subtasks + label_copied_to: copied to + label_copied_from: copied from + label_any_issues_in_project: any issues in project + label_any_issues_not_in_project: any issues not in project + field_private_notes: Private notes + permission_view_private_notes: View private notes + permission_set_notes_private: Set notes as private + label_no_issues_in_project: no issues in project + label_any: vsi + label_last_n_weeks: last %{count} weeks + setting_cross_project_subtasks: Allow cross-project subtasks + label_cross_project_descendants: S podprojekti + label_cross_project_tree: Z drevesom projekta + label_cross_project_hierarchy: S projektno hierarhijo + label_cross_project_system: Z vsemi projekti + button_hide: Hide + setting_non_working_week_days: Non-working days + label_in_the_next_days: in the next + label_in_the_past_days: in the past + label_attribute_of_user: User's %{name} + text_turning_multiple_off: If you disable multiple values, multiple values will be + removed in order to preserve only one value per item. + label_attribute_of_issue: Issue's %{name} + permission_add_documents: Add documents + permission_edit_documents: Edit documents + permission_delete_documents: Delete documents + label_gantt_progress_line: Progress line + setting_jsonp_enabled: Enable JSONP support + field_inherit_members: Inherit members + field_closed_on: Closed + setting_default_projects_tracker_ids: Default trackers for new projects + label_total_time: Skupaj diff --git a/config/locales/sq.yml b/config/locales/sq.yml new file mode 100644 index 00000000..05e5a6f7 --- /dev/null +++ b/config/locales/sq.yml @@ -0,0 +1,1085 @@ +sq: + # Text direction: Left-to-Right (ltr) or Right-to-Left (rtl) + direction: ltr + date: + formats: + # Use the strftime parameters for formats. + # When no format has been given, it uses default. + # You can provide other formats here if you like! + default: "%m/%d/%Y" + short: "%b %d" + long: "%B %d, %Y" + + day_names: [Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday] + abbr_day_names: [Sun, Mon, Tue, Wed, Thu, Fri, Sat] + + # Don't forget the nil at the beginning; there's no such thing as a 0th month + month_names: [~, January, February, March, April, May, June, July, August, September, October, November, December] + abbr_month_names: [~, Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec] + # Used in date_select and datime_select. + order: + - :year + - :month + - :day + + time: + formats: + default: "%m/%d/%Y %I:%M %p" + time: "%I:%M %p" + short: "%d %b %H:%M" + long: "%B %d, %Y %H:%M" + am: "am" + pm: "pm" + + datetime: + distance_in_words: + half_a_minute: "half a minute" + less_than_x_seconds: + one: "less than 1 second" + other: "less than %{count} seconds" + x_seconds: + one: "1 second" + other: "%{count} seconds" + less_than_x_minutes: + one: "less than a minute" + other: "less than %{count} minutes" + x_minutes: + one: "1 minute" + other: "%{count} minutes" + about_x_hours: + one: "about 1 hour" + other: "about %{count} hours" + x_hours: + one: "1 hour" + other: "%{count} hours" + x_days: + one: "1 day" + other: "%{count} days" + about_x_months: + one: "about 1 month" + other: "about %{count} months" + x_months: + one: "1 month" + other: "%{count} months" + about_x_years: + one: "about 1 year" + other: "about %{count} years" + over_x_years: + one: "over 1 year" + other: "over %{count} years" + almost_x_years: + one: "almost 1 year" + other: "almost %{count} years" + + number: + format: + separator: "." + delimiter: "" + precision: 3 + + human: + format: + delimiter: "" + precision: 3 + storage_units: + format: "%n %u" + units: + byte: + one: "Byte" + other: "Bytes" + kb: "KB" + mb: "MB" + gb: "GB" + tb: "TB" + +# Used in array.to_sentence. + support: + array: + sentence_connector: "dhe" + skip_last_comma: false + + activerecord: + errors: + template: + header: + one: "1 gabim nuk lejon kete %{model} te ruhet" + other: "%{count} gabime nuk lejon kete %{model} te ruhet" + messages: + inclusion: "nuk eshte perfshire ne liste" + exclusion: "eshte i/e rezervuar" + invalid: "eshte invalid" + confirmation: "nuk perkon me konfirmimin" + accepted: "duhet pranuar" + empty: "nuk mund te jete bosh" + blank: "nuk mund te jete blank" + too_long: "eshte shume i gjate (maksimumi eshte %{count} karaktere)" + too_short: "eshte shume i gjate (minimumi eshte %{count} karaktere)" + wrong_length: "eshte gjatesi e gabuar (duhet te jete %{count} karaktere)" + taken: "eshte zene" + not_a_number: "nuk eshte numer" + not_a_date: "nuk eshte date e vlefshme" + greater_than: "duhet te jete me i/e madh(e) se %{count}" + greater_than_or_equal_to: "duhet te jete me i/e madh(e) se ose i/e barabarte me %{count}" + equal_to: "duhet te jete i/e barabarte me %{count}" + less_than: "duhet te jete me i/e vogel se %{count}" + less_than_or_equal_to: "duhet te jete me i/e vogel se ose i/e barabarte me %{count}" + odd: "duhet te jete tek" + even: "duhet te jete cift" + greater_than_start_date: "duhet te jete me i/e madh(e) se data e fillimit" + not_same_project: "nuk i perket te njejtit projekt" + circular_dependency: "Ky relacion do te krijoje nje varesi ciklike (circular dependency)" + cant_link_an_issue_with_a_descendant: "Nje ceshtje nuk mund te lidhet me nenceshtje" + + actionview_instancetag_blank_option: Zgjidhni + + general_text_No: 'Jo' + general_text_Yes: 'Po' + general_text_no: 'jo' + general_text_yes: 'po' + general_lang_name: 'Albanian (Shqip)' + general_csv_separator: ',' + general_csv_decimal_separator: '.' + general_csv_encoding: ISO-8859-1 + general_pdf_encoding: UTF-8 + general_first_day_of_week: '7' + + notice_account_updated: Llogaria u perditesua me sukses. + notice_account_invalid_creditentials: Perdorues ose Fjalekalim i gabuar. + notice_account_password_updated: Fjalekalimi u ndryshua me sukses. + notice_account_wrong_password: Fjalekalim i gabuar + notice_account_register_done: Llogaria u krijua me sukses. Per te aktivizuar Llogarine tuaj, ndiqni link-un e derguar ne email-in tuaj. + notice_account_unknown_email: Perdorues i paidentifikuar. + notice_can_t_change_password: Kjo Llogari administrohet nga nje server tjeter. E pamundur te ndryshohet Fjalekalimi. + notice_account_lost_email_sent: Ju eshte derguar nje email me instruksionet per te zgjedhur nje Fjalekalim te ri. + notice_account_activated: Llogaria juaj u Aktivizua. Tani mund te beni Login. + notice_successful_create: Krijim me sukses. + notice_successful_update: Modifikim me sukses. + notice_successful_delete: Fshirje me sukses. + notice_successful_connection: Lidhje e suksesshme. + notice_file_not_found: Faqja qe po kerkoni te aksesoni nuk ekziston ose eshte shperngulur. + notice_locking_conflict: Te dhenat jane modifikuar nga nje Perdorues tjeter. + notice_not_authorized: Nuk jeni i autorizuar te aksesoni kete faqe. + notice_not_authorized_archived_project: Projekti, qe po tentoni te te aksesoni eshte arkivuar. + notice_email_sent: "Nje email eshte derguar ne %{value}" + notice_email_error: "Pati nje gabim gjate dergimit te email-it (%{value})" + notice_feeds_access_key_reseted: Your RSS access key was reset. + notice_api_access_key_reseted: Your API access key was reset. + notice_failed_to_save_issues: "Deshtoi ne ruajtjen e %{count} ceshtje(ve) ne %{total} te zgjedhura: %{ids}." + notice_failed_to_save_time_entries: "Deshtoi ne ruajtjen e %{count} time entrie(s) ne %{total} te zgjedhura: %{ids}." + notice_failed_to_save_members: "Deshtoi ne ruajtjen e member(s): %{errors}." + notice_no_issue_selected: "Nuk eshte zgjedhur asnje Ceshtje! Zgjidh Ceshtjen qe deshironi te modifikoni." + notice_account_pending: "Llogaria juaj u krijua dhe eshte ne pritje te aprovimit nga nje administrator." + notice_default_data_loaded: Konfigurimi i paracaktuar u ngarkua me sukses. + notice_unable_delete_version: E pamundur te fshije versionin. + notice_unable_delete_time_entry: E pamundur te fshije rekordin e log-ut. + notice_issue_done_ratios_updated: Issue done ratios updated. + notice_gantt_chart_truncated: "The chart was truncated because it exceeds the maximum number of items that can be displayed (%{max})" + notice_issue_successful_create: "Ceshtja %{id} u krijua." + notice_issue_update_conflict: "Ceshtja eshte perditesuar nga Perdorues te tjere nderkohe qe ju po e modifikonit ate." + notice_account_deleted: "Llogaria juaj u fshi perfundimisht." + + error_can_t_load_default_data: "Konfigurimi i paracaktuar nuk mund te ngarkohet: %{value}" + error_scm_not_found: "The entry or revision was not found in the repository." + error_scm_command_failed: "An error occurred when trying to access the repository: %{value}" + error_scm_annotate: "The entry does not exist or cannot be annotated." + error_scm_annotate_big_text_file: "The entry cannot be annotated, as it exceeds the maximum text file size." + error_issue_not_found_in_project: 'The issue was not found or does not belong to this project' + error_no_tracker_in_project: 'No tracker is associated to this project. Please check the Project settings.' + error_no_default_issue_status: 'No default issue status is defined. Please check your configuration (Go to "Administration -> Issue statuses").' + error_can_not_delete_custom_field: Unable to delete custom field + error_can_not_delete_tracker: "This tracker contains issues and cannot be deleted." + error_can_not_remove_role: "This role is in use and cannot be deleted." + error_can_not_reopen_issue_on_closed_version: 'An issue assigned to a closed version cannot be reopened' + error_can_not_archive_project: This project cannot be archived + error_issue_done_ratios_not_updated: "Issue done ratios not updated." + error_workflow_copy_source: 'Please select a source tracker or role' + error_workflow_copy_target: 'Please select target tracker(s) and role(s)' + error_unable_delete_issue_status: 'Unable to delete issue status' + error_unable_to_connect: "Unable to connect (%{value})" + error_attachment_too_big: "This file cannot be uploaded because it exceeds the maximum allowed file size (%{max_size})" + warning_attachments_not_saved: "%{count} file(s) could not be saved." + + mail_subject_lost_password: "Fjalekalimi %{value} i juaj" + mail_body_lost_password: 'Per te ndryshuar Fjalekalimin, ndiq link-un ne vijim:' + mail_subject_register: "Aktivizimi %{value} i Llogarise tuaj" + mail_body_register: 'Per te aktivizuar Llogarine tuaj, ndiqni link-un ne vijim:' + mail_body_account_information_external: "Mund te perdorni Llogarine tuaj %{value} per Login." + mail_body_account_information: Informacioni i Llogarise suaj + mail_subject_account_activation_request: "%{value} kerkesa aktivizimi Llogarije" + mail_body_account_activation_request: "Nje Perdorues i ri (%{value}) eshte regjistruar. Llogaria pret aprovimin tuaj:" + mail_subject_reminder: "%{count} Ceshtje te pritshme ne %{days} ditet pasardhese" + mail_body_reminder: "%{count} Ceshtje qe ju jane caktuar jane te pritshme ne %{days} ditet pasardhese:" + mail_subject_wiki_content_added: "'%{id}' wiki page eshte shtuar" + mail_body_wiki_content_added: "The '%{id}' wiki page eshte shtuar nga %{author}." + mail_subject_wiki_content_updated: "'%{id}' wiki page eshte modifikuar" + mail_body_wiki_content_updated: "The '%{id}' wiki page eshte modifikuar nga %{author}." + + + field_name: Emri + field_description: Pershkrimi + field_summary: Permbledhje + field_is_required: E Detyrueshme + field_firstname: Emri + field_lastname: Mbiemri + field_mail: Email + field_filename: File + field_filesize: Madhesia + field_downloads: Shkarkime + field_author: Autori + field_created_on: Krijuar me + field_updated_on: Perditesuar me + field_field_format: Formati + field_is_for_all: Per te gjthe Projektet + field_possible_values: Vlera e Mundshme + field_regexp: Shprehja e Duhur + field_min_length: Gjatesia Minimale + field_max_length: Gjatesia Maksimale + field_value: Vlera + field_category: Kategoria + field_title: Titulli + field_project: Projekti + field_issue: Problemi + field_status: Statusi + field_notes: Shenime + field_is_closed: Problemet e Mbyllura + field_is_default: Vlera e Paracaktuar + field_tracker: Gjurmuesi + field_subject: Subjekti + field_due_date: Deri me + field_assigned_to: I Ngarkuari + field_priority: Prioriteti + field_fixed_version: Menyra e Etiketimit + field_user: Perdoruesi + field_principal: Kapitali + field_role: Roli + field_homepage: Faqja Kryesore + field_is_public: Publike + field_parent: Nenprojekti i + field_is_in_roadmap: Ceshtje e shfaqur ne roadmap + field_login: Login + field_mail_notification: Njoftim me Email + field_admin: Administratori + field_last_login_on: Lidhja e Fundit + field_language: Gjuha + field_effective_date: Data + field_password: Fjalekalimi + field_new_password: Fjalekalimi i Ri + field_password_confirmation: Konfirmim Fjalekalimi + field_version: Versioni + field_type: Type + field_host: Host + field_port: Port + field_account: Llogaria + field_base_dn: Base DN + field_attr_login: Login attribute + field_attr_firstname: Firstname attribute + field_attr_lastname: Lastname attribute + field_attr_mail: Email attribute + field_onthefly: On-the-fly user creation + field_start_date: Start date + field_done_ratio: "% Done" + field_auth_source: Authentication mode + field_hide_mail: Hide my email address + field_comments: Comment + field_url: URL + field_start_page: Start page + field_subproject: Subproject + field_hours: Hours + field_activity: Activity + field_spent_on: Date + field_identifier: Identifier + field_is_filter: Used as a filter + field_issue_to: Related issue + field_delay: Delay + field_assignable: Issues can be assigned to this role + field_redirect_existing_links: Redirect existing links + field_estimated_hours: Estimated time + field_column_names: Columns + field_time_entries: Log time + field_time_zone: Time zone + field_searchable: Searchable + field_default_value: Default value + field_comments_sorting: Display comments + field_parent_title: Parent page + field_editable: Editable + field_watcher: Watcher + field_identity_url: OpenID URL + field_content: Content + field_group_by: Group results by + field_sharing: Sharing + field_parent_issue: Parent task + field_member_of_group: "Assignee's group" + field_assigned_to_role: "Assignee's role" + field_text: Text field + field_visible: Visible + field_warn_on_leaving_unsaved: "Warn me when leaving a page with unsaved text" + field_issues_visibility: Issues visibility + field_is_private: Private + field_commit_logs_encoding: Commit messages encoding + field_scm_path_encoding: Path encoding + field_path_to_repository: Path to repository + field_root_directory: Root directory + field_cvsroot: CVSROOT + field_cvs_module: Module + field_repository_is_default: Main repository + field_multiple: Multiple values + field_auth_source_ldap_filter: LDAP filter + + setting_app_title: Application title + setting_app_subtitle: Application subtitle + setting_welcome_text: Welcome text + setting_default_language: Default language + setting_login_required: Authentication required + setting_self_registration: Self-registration + setting_attachment_max_size: Maximum attachment size + setting_issues_export_limit: Issues export limit + setting_mail_from: Emission email address + setting_bcc_recipients: Blind carbon copy recipients (bcc) + setting_plain_text_mail: Plain text mail (no HTML) + setting_host_name: Host name and path + setting_text_formatting: Text formatting + setting_wiki_compression: Wiki history compression + setting_feeds_limit: Maximum number of items in Atom feeds + setting_default_projects_public: New projects are public by default + setting_autofetch_changesets: Fetch commits automatically + setting_sys_api_enabled: Enable WS for repository management + setting_commit_ref_keywords: Referencing keywords + setting_commit_fix_keywords: Fixing keywords + setting_autologin: Autologin + setting_date_format: Date format + setting_time_format: Time format + setting_cross_project_issue_relations: Allow cross-project issue relations + setting_issue_list_default_columns: Default columns displayed on the issue list + setting_repositories_encodings: Attachments and repositories encodings + setting_protocol: Protocol + setting_per_page_options: Objects per page options + setting_user_format: Users display format + setting_activity_days_default: Days displayed on project activity + setting_display_subprojects_issues: Display subprojects issues on main projects by default + setting_enabled_scm: Enabled SCM + setting_mail_handler_body_delimiters: "Truncate emails after one of these lines" + setting_mail_handler_api_enabled: Enable WS for incoming emails + setting_mail_handler_api_key: API key + setting_sequential_project_identifiers: Generate sequential project identifiers + setting_gravatar_enabled: Use Gravatar user icons + setting_gravatar_default: Default Gravatar image + setting_diff_max_lines_displayed: Maximum number of diff lines displayed + setting_file_max_size_displayed: Maximum size of text files displayed inline + setting_repository_log_display_limit: Maximum number of revisions displayed on file log + setting_openid: Allow OpenID login and registration + setting_password_min_length: Minimum password length + setting_new_project_user_role_id: Role given to a non-admin user who creates a project + setting_default_projects_modules: Default enabled modules for new projects + setting_issue_done_ratio: Calculate the issue done ratio with + setting_issue_done_ratio_issue_field: Use the issue field + setting_issue_done_ratio_issue_status: Use the issue status + setting_start_of_week: Start calendars on + setting_rest_api_enabled: Enable REST web service + setting_cache_formatted_text: Cache formatted text + setting_default_notification_option: Default notification option + setting_commit_logtime_enabled: Enable time logging + setting_commit_logtime_activity_id: Activity for logged time + setting_gantt_items_limit: Maximum number of items displayed on the gantt chart + setting_issue_group_assignment: Allow issue assignment to groups + setting_default_issue_start_date_to_creation_date: Use current date as start date for new issues + setting_commit_cross_project_ref: Allow issues of all the other projects to be referenced and fixed + setting_unsubscribe: Allow users to delete their own account + + permission_add_project: Create project + permission_add_subprojects: Create subprojects + permission_edit_project: Edit project + permission_select_project_modules: Select project modules + permission_manage_members: Manage members + permission_manage_project_activities: Manage project activities + permission_manage_versions: Manage versions + permission_manage_categories: Manage issue categories + permission_view_issues: View Issues + permission_add_issues: Add issues + permission_edit_issues: Edit issues + permission_manage_issue_relations: Manage issue relations + permission_set_issues_private: Set issues public or private + permission_set_own_issues_private: Set own issues public or private + permission_add_issue_notes: Add notes + permission_edit_issue_notes: Edit notes + permission_edit_own_issue_notes: Edit own notes + permission_move_issues: Move issues + permission_delete_issues: Delete issues + permission_manage_public_queries: Manage public queries + permission_save_queries: Save queries + permission_view_gantt: View gantt chart + permission_view_calendar: View calendar + permission_view_issue_watchers: View watchers list + permission_add_issue_watchers: Add watchers + permission_delete_issue_watchers: Delete watchers + permission_log_time: Log spent time + permission_view_time_entries: View spent time + permission_edit_time_entries: Edit time logs + permission_edit_own_time_entries: Edit own time logs + permission_manage_news: Manage news + permission_comment_news: Comment news + permission_view_documents: View documents + permission_manage_files: Manage files + permission_view_files: View files + permission_manage_wiki: Manage wiki + permission_rename_wiki_pages: Rename wiki pages + permission_delete_wiki_pages: Delete wiki pages + permission_view_wiki_pages: View wiki + permission_view_wiki_edits: View wiki history + permission_edit_wiki_pages: Edit wiki pages + permission_delete_wiki_pages_attachments: Delete attachments + permission_protect_wiki_pages: Protect wiki pages + permission_manage_repository: Manage repository + permission_browse_repository: Browse repository + permission_view_changesets: View changesets + permission_commit_access: Commit access + permission_manage_boards: Manage forums + permission_view_messages: View messages + permission_add_messages: Post messages + permission_edit_messages: Edit messages + permission_edit_own_messages: Edit own messages + permission_delete_messages: Delete messages + permission_delete_own_messages: Delete own messages + permission_export_wiki_pages: Export wiki pages + permission_manage_subtasks: Manage subtasks + permission_manage_related_issues: Manage related issues + + project_module_issue_tracking: Issue tracking + project_module_time_tracking: Time tracking + project_module_news: News + project_module_documents: Documents + project_module_files: Files + project_module_wiki: Wiki + project_module_repository: Repository + project_module_boards: Forums + project_module_calendar: Calendar + project_module_gantt: Gantt + + label_user: Perdoruesi + label_user_plural: Perdoruesit + label_user_new: Perdorues i ri + label_user_anonymous: Anonim + label_project: Projekt + label_project_new: Projekt i ri + label_project_plural: Projekte + label_x_projects: + zero: asnje projekt + one: 1 projekt + other: "%{count} projekte" + label_project_all: Te gjithe Projektet + label_project_latest: Projektet me te fundit + label_issue: Ceshtje + label_issue_new: Ceshtje e re + label_issue_plural: Ceshtjet + label_issue_view_all: Shih te gjitha Ceshtjet + label_issues_by: "Ceshtje per %{value}" + label_issue_added: Ceshtje te shtuara + label_issue_updated: Ceshtje te modifikuara + label_issue_note_added: Shenime te shtuara + label_issue_status_updated: Statusi u modifikua + label_issue_priority_updated: Prioriteti u modifikua + label_document: Dokument + label_document_new: Dokument i ri + label_document_plural: Dokumente + label_document_added: Dokumente te shtuara + label_role: Roli + label_role_plural: Role + label_role_new: Rol i ri + label_role_and_permissions: Role dhe te Drejta + label_role_anonymous: Anonim + label_role_non_member: Jo Anetar + label_member: Anetar + label_member_new: Anetar i ri + label_member_plural: Anetare + label_tracker: Gjurmues + label_tracker_plural: Gjurmuesa + label_tracker_new: Gjurmues i ri + label_workflow: Workflow + label_issue_status: Statusi i Ceshtjes + label_issue_status_plural: Statuset e Ceshtjeve + label_issue_status_new: Statusi i ri + label_issue_category: Kategoria e Ceshtjes + label_issue_category_plural: Kategorite e Ceshtjeve + label_issue_category_new: Kategori e re + label_custom_field: Fushe e personalizuar + label_custom_field_plural: Fusha te personalizuara + label_custom_field_new: Fushe e personalizuar e re + label_enumerations: Enumerations + label_enumeration_new: Vlere e re + label_information: Informacion + label_information_plural: Informacione + label_please_login: Lutemi login + label_register: Regjistrohu + label_login_with_open_id_option: ose lidhu me OpenID + label_password_lost: Fjalekalim i humbur + label_home: Home + label_my_page: Faqja ime + label_my_account: Llogaria ime + label_my_projects: Projektet e mia + label_my_page_block: My page block + label_administration: Administrim + label_login: Login + label_logout: Dalje + label_help: Ndihme + label_reported_issues: Ceshtje te raportuara + label_assigned_to_me_issues: Ceshtje te caktuara mua + label_last_login: Hyrja e fundit + label_registered_on: Regjistruar me + label_activity: Aktiviteti + label_overall_activity: Aktiviteti i pergjithshem + label_user_activity: "Aktiviteti i %{value}" + label_new: Shto + label_logged_as: Lidhur si + label_environment: Ambienti + label_authentication: Authentikimi + label_auth_source: Menyra e Authentikimit + label_auth_source_new: Menyre e re Authentikimi + label_auth_source_plural: Menyrat e Authentikimit + label_subproject_plural: Nenprojekte + label_subproject_new: Nenprojekt i ri + label_and_its_subprojects: "%{value} dhe Nenprojektet e vet" + label_min_max_length: Gjatesia Min - Max + label_list: List + label_date: Date + label_integer: Integer + label_float: Float + label_boolean: Boolean + label_string: Text + label_text: Long text + label_attribute: Attribute + label_attribute_plural: Attributes + label_no_data: No data to display + label_change_status: Change status + label_history: Histori + label_attachment: File + label_attachment_new: File i ri + label_attachment_delete: Fshi file + label_attachment_plural: Files + label_file_added: File te shtuar + label_report: Raport + label_report_plural: Raporte + label_news: Lajm + label_news_new: Shto Lajm + label_news_plural: Lajme + label_news_latest: Lajmet e fundit + label_news_view_all: Veshtro gjithe Lajmet + label_news_added: Lajme te shtuara + label_news_comment_added: Komenti iu shtua Lajmeve + label_settings: Settings + label_overview: Overview + label_version: Version + label_version_new: Version i ri + label_version_plural: Versione + label_close_versions: Mbyll Versionet e perfunduara + label_confirmation: Konfirmim + label_export_to: 'Mund te gjendet gjithashtu ne:' + label_read: Lexim... + label_public_projects: Projekte publike + label_open_issues: e hapur + label_open_issues_plural: te hapura + label_closed_issues: e mbyllur + label_closed_issues_plural: te mbyllura + label_x_open_issues_abbr_on_total: + zero: 0 te hapura / %{total} + one: 1 e hapur / %{total} + other: "%{count} te hapura / %{total}" + label_x_open_issues_abbr: + zero: 0 te hapura + one: 1 e hapur + other: "%{count} te hapura" + label_x_closed_issues_abbr: + zero: 0 te mbyllura + one: 1 e mbyllur + other: "%{count} te mbyllura" + label_x_issues: + zero: 0 ceshtje + one: 1 ceshtje + other: "%{count} ceshtje" + label_total: Total + label_permissions: Te drejta + label_current_status: Statusi aktual + label_new_statuses_allowed: Statuse te reja te lejuara + label_all: te gjitha + label_none: asnje + label_nobody: askush + label_next: Pasardhes + label_previous: Paraardhes + label_used_by: Perdorur nga + label_details: Detaje + label_add_note: Shto nje Shenim + label_per_page: Per Faqe + label_calendar: Kalendar + label_months_from: muaj nga + label_gantt: Gantt + label_internal: I brendshem + label_last_changes: "%{count} ndryshimet e fundit" + label_change_view_all: Shih gjithe ndryshimet + label_personalize_page: Personalizo kete Faqe + label_comment: Koment + label_comment_plural: Komente + label_x_comments: + zero: asnje koment + one: 1 koment + other: "%{count} komente" + label_comment_add: Shto nje koment + label_comment_added: Komenti u shtua + label_comment_delete: Fshi komente + label_query: Custom query + label_query_plural: Custom queries + label_query_new: New query + label_my_queries: My custom queries + label_filter_add: Shto filter + label_filter_plural: Filtra + label_equals: eshte + label_not_equals: nuk eshte + label_in_less_than: ne me pak se + label_in_more_than: ne me shume se + label_greater_or_equal: '>=' + label_less_or_equal: '<=' + label_between: ndermjet + label_in: ne + label_today: sot + label_all_time: cdo kohe + label_yesterday: dje + label_this_week: kete jave + label_last_week: javen e kaluar + label_last_n_days: "%{count} ditet e fundit" + label_this_month: kete muaj + label_last_month: muajin e kaluar + label_this_year: kete vit + label_date_range: Date range + label_less_than_ago: me pak se dite para + label_more_than_ago: me shume se dite para + label_ago: dite para + label_contains: permban + label_not_contains: nuk permban + label_day_plural: dite + label_repository: Repository + label_repository_new: New repository + label_repository_plural: Repositories + label_browse: Browse + label_branch: Dege + label_tag: Tag + label_revision: Revizion + label_revision_plural: Revizione + label_revision_id: "Revizion %{value}" + label_associated_revisions: Associated revisions + label_added: te shtuara + label_modified: te modifikuara + label_copied: te kopjuara + label_renamed: te riemeruara + label_deleted: te fshira + label_latest_revision: Revizioni i fundit + label_latest_revision_plural: Revizionet e fundit + label_view_revisions: Shih Revizionet + label_view_all_revisions: Shih te gjitha Revizionet + label_max_size: Maximum size + label_sort_highest: Coje ne krye + label_sort_higher: Coje lart + label_sort_lower: Coje poshte + label_sort_lowest: Coje ne fund + label_roadmap: Roadmap + label_roadmap_due_in: "E pritshme ne %{value}" + label_roadmap_overdue: "%{value} me vonese" + label_roadmap_no_issues: Asnje Ceshtje per kete version + label_search: Kerko + label_result_plural: Rezultatet + label_all_words: Te gjitha fjalet + label_wiki: Wiki + label_wiki_edit: Wiki edit + label_wiki_edit_plural: Wiki edits + label_wiki_page: Wiki page + label_wiki_page_plural: Wiki pages + label_index_by_title: Index by title + label_index_by_date: Index by date + label_current_version: Current version + label_preview: Preview + label_feed_plural: Feeds + label_changes_details: Details of all changes + label_issue_tracking: Issue tracking + label_spent_time: Spent time + label_overall_spent_time: Overall spent time + label_f_hour: "%{value} ore" + label_f_hour_plural: "%{value} ore" + label_time_tracking: Time tracking + label_change_plural: Ndryshimet + label_statistics: Statistika + label_commits_per_month: Commits per month + label_commits_per_author: Commits per author + label_diff: diff + label_view_diff: View differences + label_diff_inline: inline + label_diff_side_by_side: side by side + label_options: Options + label_copy_workflow_from: Copy workflow from + label_permissions_report: Permissions report + label_watched_issues: Watched issues + label_related_issues: Related issues + label_applied_status: Applied status + label_loading: Loading... + label_relation_new: New relation + label_relation_delete: Delete relation + label_relates_to: related to + label_duplicates: duplicates + label_duplicated_by: duplicated by + label_blocks: blocks + label_blocked_by: blocked by + label_precedes: precedes + label_follows: follows + label_end_to_start: end to start + label_end_to_end: end to end + label_start_to_start: start to start + label_start_to_end: start to end + label_stay_logged_in: Stay logged in + label_disabled: disabled + label_show_completed_versions: Show completed versions + label_me: me + label_board: Forum + label_board_new: New forum + label_board_plural: Forums + label_board_locked: Locked + label_board_sticky: Sticky + label_topic_plural: Topics + label_message_plural: Messages + label_message_last: Last message + label_message_new: New message + label_message_posted: Message added + label_reply_plural: Replies + label_send_information: Send account information to the user + label_year: Year + label_month: Month + label_week: Week + label_date_from: From + label_date_to: To + label_language_based: Based on user's language + label_sort_by: "Sort by %{value}" + label_send_test_email: Send a test email + label_feeds_access_key: RSS access key + label_missing_feeds_access_key: Missing a RSS access key + label_feeds_access_key_created_on: "RSS access key created %{value} ago" + label_module_plural: Modules + label_added_time_by: "Added by %{author} %{age} ago" + label_updated_time_by: "Updated by %{author} %{age} ago" + label_updated_time: "Updated %{value} ago" + label_jump_to_a_project: Jump to a project... + label_file_plural: Files + label_changeset_plural: Changesets + label_default_columns: Default columns + label_no_change_option: (No change) + label_bulk_edit_selected_issues: Bulk edit selected issues + label_bulk_edit_selected_time_entries: Bulk edit selected time entries + label_theme: Theme + label_default: Default + label_search_titles_only: Search titles only + label_user_mail_option_all: "For any event on all my projects" + label_user_mail_option_selected: "For any event on the selected projects only..." + label_user_mail_option_none: "No events" + label_user_mail_option_only_my_events: "Only for things I watch or I'm involved in" + label_user_mail_option_only_assigned: "Only for things I am assigned to" + label_user_mail_option_only_owner: "Only for things I am the owner of" + label_user_mail_no_self_notified: "I don't want to be notified of changes that I make myself" + label_registration_activation_by_email: account activation by email + label_registration_manual_activation: manual account activation + label_registration_automatic_activation: automatic account activation + label_display_per_page: "Per page: %{value}" + label_age: Age + label_change_properties: Change properties + label_general: General + label_more: More + label_scm: SCM + label_plugins: Plugins + label_ldap_authentication: LDAP authentication + label_downloads_abbr: D/L + label_optional_description: Optional description + label_add_another_file: Add another file + label_preferences: Preferences + label_chronological_order: In chronological order + label_reverse_chronological_order: In reverse chronological order + label_planning: Planning + label_incoming_emails: Incoming emails + label_generate_key: Generate a key + label_issue_watchers: Watchers + label_example: Example + label_display: Display + label_sort: Sort + label_ascending: Ascending + label_descending: Descending + label_date_from_to: From %{start} to %{end} + label_wiki_content_added: Wiki page added + label_wiki_content_updated: Wiki page updated + label_group: Group + label_group_plural: Groups + label_group_new: New group + label_time_entry_plural: Spent time + label_version_sharing_none: Not shared + label_version_sharing_descendants: With subprojects + label_version_sharing_hierarchy: With project hierarchy + label_version_sharing_tree: With project tree + label_version_sharing_system: With all projects + label_update_issue_done_ratios: Update issue done ratios + label_copy_source: Source + label_copy_target: Target + label_copy_same_as_target: Same as target + label_display_used_statuses_only: Only display statuses that are used by this tracker + label_api_access_key: API access key + label_missing_api_access_key: Missing an API access key + label_api_access_key_created_on: "API access key created %{value} ago" + label_profile: Profile + label_subtask_plural: Subtasks + label_project_copy_notifications: Send email notifications during the project copy + label_principal_search: "Search for user or group:" + label_user_search: "Search for user:" + label_additional_workflow_transitions_for_author: Additional transitions allowed when the user is the author + label_additional_workflow_transitions_for_assignee: Additional transitions allowed when the user is the assignee + label_issues_visibility_all: All issues + label_issues_visibility_public: All non private issues + label_issues_visibility_own: Issues created by or assigned to the user + label_git_report_last_commit: Report last commit for files and directories + label_parent_revision: Parent + label_child_revision: Child + label_export_options: "%{export_format} export options" + label_copy_attachments: Copy attachments + label_item_position: "%{position} of %{count}" + label_completed_versions: Completed versions + label_search_for_watchers: Search for watchers to add + + button_login: Login + button_submit: Submit + button_save: Save + button_check_all: Check all + button_uncheck_all: Uncheck all + button_collapse_all: Collapse all + button_expand_all: Expand all + button_delete: Delete + button_create: Create + button_create_and_continue: Create and continue + button_test: Test + button_edit: Edit + button_edit_associated_wikipage: "Edit associated Wiki page: %{page_title}" + button_add: Add + button_change: Change + button_apply: Apply + button_clear: Clear + button_lock: Lock + button_unlock: Unlock + button_download: Download + button_list: List + button_view: View + button_move: Move + button_move_and_follow: Move and follow + button_back: Back + button_cancel: Cancel + button_activate: Activate + button_sort: Sort + button_log_time: Log time + button_rollback: Rollback to this version + button_watch: Watch + button_unwatch: Unwatch + button_reply: Reply + button_archive: Archive + button_unarchive: Unarchive + button_reset: Reset + button_rename: Rename + button_change_password: Change password + button_copy: Copy + button_copy_and_follow: Copy and follow + button_annotate: Annotate + button_update: Update + button_configure: Configure + button_quote: Quote + button_duplicate: Duplicate + button_show: Show + button_edit_section: Edit this section + button_export: Export + button_delete_my_account: Delete my account + + status_active: active + status_registered: registered + status_locked: locked + + version_status_open: open + version_status_locked: locked + version_status_closed: closed + + field_active: Active + + text_select_mail_notifications: Select actions for which email notifications should be sent. + text_regexp_info: eg. ^[A-Z0-9]+$ + text_min_max_length_info: 0 means no restriction + text_project_destroy_confirmation: Are you sure you want to delete this project and related data? + text_subprojects_destroy_warning: "Its subproject(s): %{value} will be also deleted." + text_workflow_edit: Select a role and a tracker to edit the workflow + text_are_you_sure: Are you sure? + text_journal_changed: "%{label} changed from %{old} to %{new}" + text_journal_changed_no_detail: "%{label} updated" + text_journal_set_to: "%{label} set to %{value}" + text_journal_deleted: "%{label} deleted (%{old})" + text_journal_added: "%{label} %{value} added" + text_tip_issue_begin_day: issue beginning this day + text_tip_issue_end_day: issue ending this day + text_tip_issue_begin_end_day: issue beginning and ending this day + text_project_identifier_info: 'Only lower case letters (a-z), numbers, dashes and underscores are allowed.
    Once saved, the identifier cannot be changed.' + text_caracters_maximum: "%{count} characters maximum." + text_caracters_minimum: "Must be at least %{count} characters long." + text_length_between: "Length between %{min} and %{max} characters." + text_tracker_no_workflow: No workflow defined for this tracker + text_unallowed_characters: Unallowed characters + text_comma_separated: Multiple values allowed (comma separated). + text_line_separated: Multiple values allowed (one line for each value). + text_issues_ref_in_commit_messages: Referencing and fixing issues in commit messages + text_issue_added: "Issue %{id} has been reported by %{author}." + text_issue_updated: "Issue %{id} has been updated by %{author}." + text_wiki_destroy_confirmation: Are you sure you want to delete this wiki and all its content? + text_issue_category_destroy_question: "Some issues (%{count}) are assigned to this category. What do you want to do?" + text_issue_category_destroy_assignments: Remove category assignments + text_issue_category_reassign_to: Reassign issues to this category + text_user_mail_option: "For unselected projects, you will only receive notifications about things you watch or you're involved in (eg. issues you're the author or assignee)." + text_no_configuration_data: "Roles, trackers, issue statuses and workflow have not been configured yet.\nIt is highly recommended to load the default configuration. You will be able to modify it once loaded." + text_load_default_configuration: Load the default configuration + text_status_changed_by_changeset: "Applied in changeset %{value}." + text_time_logged_by_changeset: "Applied in changeset %{value}." + text_issues_destroy_confirmation: 'Are you sure you want to delete the selected issue(s)?' + text_issues_destroy_descendants_confirmation: "This will also delete %{count} subtask(s)." + text_time_entries_destroy_confirmation: 'Are you sure you want to delete the selected time entr(y/ies)?' + text_select_project_modules: 'Select modules to enable for this project:' + text_default_administrator_account_changed: Default administrator account changed + text_file_repository_writable: Attachments directory writable + text_plugin_assets_writable: Plugin assets directory writable + text_rmagick_available: RMagick available (optional) + text_destroy_time_entries_question: "%{hours} hours were reported on the issues you are about to delete. What do you want to do?" + text_destroy_time_entries: Delete reported hours + text_assign_time_entries_to_project: Assign reported hours to the project + text_reassign_time_entries: 'Reassign reported hours to this issue:' + text_user_wrote: "%{value} wrote:" + text_enumeration_destroy_question: "%{count} objects are assigned to this value." + text_enumeration_category_reassign_to: 'Reassign them to this value:' + text_email_delivery_not_configured: "Email delivery is not configured, and notifications are disabled.\nConfigure your SMTP server in config/configuration.yml and restart the application to enable them." + text_repository_usernames_mapping: "Select or update the Redmine user mapped to each username found in the repository log.\nUsers with the same Redmine and repository username or email are automatically mapped." + text_diff_truncated: '... This diff was truncated because it exceeds the maximum size that can be displayed.' + text_custom_field_possible_values_info: 'One line for each value' + text_wiki_page_destroy_question: "This page has %{descendants} child page(s) and descendant(s). What do you want to do?" + text_wiki_page_nullify_children: "Keep child pages as root pages" + text_wiki_page_destroy_children: "Delete child pages and all their descendants" + text_wiki_page_reassign_children: "Reassign child pages to this parent page" + text_own_membership_delete_confirmation: "You are about to remove some or all of your permissions and may no longer be able to edit this project after that.\nAre you sure you want to continue?" + text_zoom_in: Zoom in + text_zoom_out: Zoom out + text_warn_on_leaving_unsaved: "The current page contains unsaved text that will be lost if you leave this page." + text_scm_path_encoding_note: "Default: UTF-8" + text_git_repository_note: Repository is bare and local (e.g. /gitrepo, c:\gitrepo) + text_mercurial_repository_note: Local repository (e.g. /hgrepo, c:\hgrepo) + text_scm_command: Command + text_scm_command_version: Version + text_issue_conflict_resolution_overwrite: "Apply my changes anyway (previous notes will be kept but some changes may be overwritten)" + text_issue_conflict_resolution_add_notes: "Add my notes and discard my other changes" + text_issue_conflict_resolution_cancel: "Discard all my changes and redisplay %{link}" + text_account_destroy_confirmation: "Are you sure you want to proceed?\nYour account will be permanently deleted, with no way to reactivate it." + + default_role_manager: Manager + default_role_developer: Developer + default_role_reporter: Reporter + default_tracker_bug: Bug + default_tracker_feature: Feature + default_tracker_support: Support + default_issue_status_new: New + default_issue_status_in_progress: In Progress + default_issue_status_resolved: Resolved + default_issue_status_feedback: Feedback + default_issue_status_closed: Closed + default_issue_status_rejected: Rejected + default_doc_category_user: User documentation + default_doc_category_tech: Technical documentation + default_priority_low: Low + default_priority_normal: Normal + default_priority_high: High + default_priority_urgent: Urgent + default_priority_immediate: Immediate + default_activity_design: Design + default_activity_development: Development + + enumeration_issue_priorities: Issue priorities + enumeration_doc_categories: Document categories + enumeration_activities: Activities (time tracking) + enumeration_system_activity: System Activity + description_filter: Filter + description_search: Searchfield + description_choose_project: Projects + description_project_scope: Search scope + description_notes: Notes + description_message_content: Message content + description_query_sort_criteria_attribute: Sort attribute + description_query_sort_criteria_direction: Sort direction + description_user_mail_notification: Mail notification settings + description_available_columns: Available Columns + description_selected_columns: Selected Columns + description_all_columns: All Columns + description_issue_category_reassign: Choose issue category + description_wiki_subpages_reassign: Choose new parent page + description_date_range_list: Choose range from list + description_date_range_interval: Choose range by selecting start and end date + description_date_from: Enter start date + description_date_to: Enter end date + error_session_expired: Your session has expired. Please login again. + text_session_expiration_settings: "Warning: changing these settings may expire the current sessions including yours." + setting_session_lifetime: Session maximum lifetime + setting_session_timeout: Session inactivity timeout + label_session_expiration: Session expiration + permission_close_project: Close / reopen the project + label_show_closed_projects: View closed projects + button_close: Close + button_reopen: Reopen + project_status_active: active + project_status_closed: closed + project_status_archived: archived + text_project_closed: This project is closed and read-only. + notice_user_successful_create: User %{id} created. + field_core_fields: Standard fields + field_timeout: Timeout (in seconds) + setting_thumbnails_enabled: Display attachment thumbnails + setting_thumbnails_size: Thumbnails size (in pixels) + label_status_transitions: Status transitions + label_fields_permissions: Fields permissions + label_readonly: Read-only + label_required: Required + text_repository_identifier_info: 'Only lower case letters (a-z), numbers, dashes and underscores are allowed.
    Once saved, the identifier cannot be changed.' + field_board_parent: Parent forum + label_attribute_of_project: Project's %{name} + label_attribute_of_author: Author's %{name} + label_attribute_of_assigned_to: Assignee's %{name} + label_attribute_of_fixed_version: Target version's %{name} + label_copy_subtasks: Copy subtasks + label_copied_to: copied to + label_copied_from: copied from + label_any_issues_in_project: any issues in project + label_any_issues_not_in_project: any issues not in project + field_private_notes: Private notes + permission_view_private_notes: View private notes + permission_set_notes_private: Set notes as private + label_no_issues_in_project: no issues in project + label_any: te gjitha + label_last_n_weeks: last %{count} weeks + setting_cross_project_subtasks: Allow cross-project subtasks + label_cross_project_descendants: With subprojects + label_cross_project_tree: With project tree + label_cross_project_hierarchy: With project hierarchy + label_cross_project_system: With all projects + button_hide: Hide + setting_non_working_week_days: Non-working days + label_in_the_next_days: in the next + label_in_the_past_days: in the past + label_attribute_of_user: User's %{name} + text_turning_multiple_off: If you disable multiple values, multiple values will be + removed in order to preserve only one value per item. + label_attribute_of_issue: Issue's %{name} + permission_add_documents: Add documents + permission_edit_documents: Edit documents + permission_delete_documents: Delete documents + label_gantt_progress_line: Progress line + setting_jsonp_enabled: Enable JSONP support + field_inherit_members: Inherit members + field_closed_on: Closed + setting_default_projects_tracker_ids: Default trackers for new projects + label_total_time: Total + text_scm_config: You can configure your SCM commands in config/configuration.yml. Please restart the application after editing it. + text_scm_command_not_available: SCM command is not available. Please check settings on the administration panel. + setting_emails_footer: Email footer + setting_emails_header: Email header diff --git a/config/locales/sr-YU.yml b/config/locales/sr-YU.yml new file mode 100644 index 00000000..3b53e6ee --- /dev/null +++ b/config/locales/sr-YU.yml @@ -0,0 +1,1091 @@ +# Serbian translations for Redmine +# by Vladimir Medarović (vlada@medarovic.com) +sr-YU: + direction: ltr + jquery: + locale: "sr" + date: + formats: + # Use the strftime parameters for formats. + # When no format has been given, it uses default. + # You can provide other formats here if you like! + default: "%d.%m.%Y." + short: "%e %b" + long: "%B %e, %Y" + + day_names: [nedelja, ponedeljak, utorak, sreda, četvrtak, petak, subota] + abbr_day_names: [ned, pon, uto, sre, čet, pet, sub] + + # Don't forget the nil at the beginning; there's no such thing as a 0th month + month_names: [~, januar, februar, mart, april, maj, jun, jul, avgust, septembar, oktobar, novembar, decembar] + abbr_month_names: [~, jan, feb, mar, apr, maj, jun, jul, avg, sep, okt, nov, dec] + # Used in date_select and datime_select. + order: + - :day + - :month + - :year + + time: + formats: + default: "%d.%m.%Y. u %H:%M" + time: "%H:%M" + short: "%d. %b u %H:%M" + long: "%d. %B %Y u %H:%M" + am: "am" + pm: "pm" + + datetime: + distance_in_words: + half_a_minute: "pola minuta" + less_than_x_seconds: + one: "manje od jedne sekunde" + other: "manje od %{count} sek." + x_seconds: + one: "jedna sekunda" + other: "%{count} sek." + less_than_x_minutes: + one: "manje od minuta" + other: "manje od %{count} min." + x_minutes: + one: "jedan minut" + other: "%{count} min." + about_x_hours: + one: "približno jedan sat" + other: "približno %{count} sati" + x_hours: + one: "1 hour" + other: "%{count} hours" + x_days: + one: "jedan dan" + other: "%{count} dana" + about_x_months: + one: "približno jedan mesec" + other: "približno %{count} meseci" + x_months: + one: "jedan mesec" + other: "%{count} meseci" + about_x_years: + one: "približno godinu dana" + other: "približno %{count} god." + over_x_years: + one: "preko godinu dana" + other: "preko %{count} god." + almost_x_years: + one: "skoro godinu dana" + other: "skoro %{count} god." + + number: + format: + separator: "," + delimiter: "" + precision: 3 + human: + format: + delimiter: "" + precision: 3 + storage_units: + format: "%n %u" + units: + byte: + one: "Byte" + other: "Bytes" + kb: "KB" + mb: "MB" + gb: "GB" + tb: "TB" + + +# Used in array.to_sentence. + support: + array: + sentence_connector: "i" + skip_last_comma: false + + activerecord: + errors: + template: + header: + one: "1 error prohibited this %{model} from being saved" + other: "%{count} errors prohibited this %{model} from being saved" + messages: + inclusion: "nije uključen u spisak" + exclusion: "je rezervisan" + invalid: "je neispravan" + confirmation: "potvrda ne odgovara" + accepted: "mora biti prihvaćen" + empty: "ne može biti prazno" + blank: "ne može biti prazno" + too_long: "je predugačka (maksimum znakova je %{count})" + too_short: "je prekratka (minimum znakova je %{count})" + wrong_length: "je pogrešne dužine (broj znakova mora biti %{count})" + taken: "je već u upotrebi" + not_a_number: "nije broj" + not_a_date: "nije ispravan datum" + greater_than: "mora biti veći od %{count}" + greater_than_or_equal_to: "mora biti veći ili jednak %{count}" + equal_to: "mora biti jednak %{count}" + less_than: "mora biti manji od %{count}" + less_than_or_equal_to: "mora biti manji ili jednak %{count}" + odd: "mora biti paran" + even: "mora biti neparan" + greater_than_start_date: "mora biti veći od početnog datuma" + not_same_project: "ne pripada istom projektu" + circular_dependency: "Ova veza će stvoriti kružnu referencu" + cant_link_an_issue_with_a_descendant: "Problem ne može biti povezan sa jednim od svojih podzadataka" + + actionview_instancetag_blank_option: Molim odaberite + + general_text_No: 'Ne' + general_text_Yes: 'Da' + general_text_no: 'ne' + general_text_yes: 'da' + general_lang_name: 'Serbian (Srpski)' + general_csv_separator: ',' + general_csv_decimal_separator: '.' + general_csv_encoding: UTF-8 + general_pdf_encoding: UTF-8 + general_first_day_of_week: '1' + + notice_account_updated: Nalog je uspešno ažuriran. + notice_account_invalid_creditentials: Neispravno korisničko ime ili lozinka. + notice_account_password_updated: Lozinka je uspešno ažurirana. + notice_account_wrong_password: Pogrešna lozinka + notice_account_register_done: Korisnički nalog je uspešno kreiran. Kliknite na link koji ste dobili u e-poruci za aktivaciju. + notice_account_unknown_email: Nepoznat korisnik. + notice_can_t_change_password: Ovaj korisnički nalog za potvrdu identiteta koristi spoljni izvor. Nemoguće je promeniti lozinku. + notice_account_lost_email_sent: Poslata vam je e-poruka sa uputstvom za izbor nove lozinke + notice_account_activated: Vaš korisnički nalog je aktiviran. Sada se možete prijaviti. + notice_successful_create: Uspešno kreiranje. + notice_successful_update: Uspešno ažuriranje. + notice_successful_delete: Uspešno brisanje. + notice_successful_connection: Uspešno povezivanje. + notice_file_not_found: Strana kojoj želite pristupiti ne postoji ili je uklonjena. + notice_locking_conflict: Podatak je ažuriran od strane drugog korisnika. + notice_not_authorized: Niste ovlašćeni za pristup ovoj strani. + notice_email_sent: "E-poruka je poslata na %{value}" + notice_email_error: "Dogodila se greška prilikom slanja e-poruke (%{value})" + notice_feeds_access_key_reseted: Vaš RSS pristupni ključ je poništen. + notice_api_access_key_reseted: Vaš API pristupni ključ je poništen. + notice_failed_to_save_issues: "Neuspešno snimanje %{count} problema od %{total} odabranih: %{ids}." + notice_failed_to_save_members: "Neuspešno snimanje člana(ova): %{errors}." + notice_no_issue_selected: "Ni jedan problem nije odabran! Molimo, odaberite problem koji želite da menjate." + notice_account_pending: "Vaš nalog je kreiran i čeka na odobrenje administratora." + notice_default_data_loaded: Podrazumevano konfigurisanje je uspešno učitano. + notice_unable_delete_version: Verziju je nemoguće izbrisati. + notice_unable_delete_time_entry: Stavku evidencije vremena je nemoguće izbrisati. + notice_issue_done_ratios_updated: Odnos rešenih problema je ažuriran. + + error_can_t_load_default_data: "Podrazumevano konfigurisanje je nemoguće učitati: %{value}" + error_scm_not_found: "Stavka ili ispravka nisu pronađene u spremištu." + error_scm_command_failed: "Greška se javila prilikom pokušaja pristupa spremištu: %{value}" + error_scm_annotate: "Stavka ne postoji ili ne može biti označena." + error_issue_not_found_in_project: 'Problem nije pronađen ili ne pripada ovom projektu.' + error_no_tracker_in_project: 'Ni jedno praćenje nije povezano sa ovim projektom. Molimo proverite podešavanja projekta.' + error_no_default_issue_status: 'Podrazumevani status problema nije definisan. Molimo proverite vaše konfigurisanje (idite na "Administracija -> Statusi problema").' + error_can_not_delete_custom_field: Nemoguće je izbrisati prilagođeno polje + error_can_not_delete_tracker: "Ovo praćenje sadrži probleme i ne može biti obrisano." + error_can_not_remove_role: "Ova uloga je u upotrebi i ne može biti obrisana." + error_can_not_reopen_issue_on_closed_version: 'Problem dodeljen zatvorenoj verziji ne može biti ponovo otvoren' + error_can_not_archive_project: Ovaj projekat se ne može arhivirati + error_issue_done_ratios_not_updated: "Odnos rešenih problema nije ažuriran." + error_workflow_copy_source: 'Molimo odaberite izvorno praćenje ili ulogu' + error_workflow_copy_target: 'Molimo odaberite odredišno praćenje i ulogu' + error_unable_delete_issue_status: 'Status problema je nemoguće obrisati' + error_unable_to_connect: "Povezivanje sa (%{value}) je nemoguće" + warning_attachments_not_saved: "%{count} datoteka ne može biti snimljena." + + mail_subject_lost_password: "Vaša %{value} lozinka" + mail_body_lost_password: 'Za promenu vaše lozinke, kliknite na sledeći link:' + mail_subject_register: "Aktivacija vašeg %{value} naloga" + mail_body_register: 'Za aktivaciju vašeg naloga, kliknite na sledeći link:' + mail_body_account_information_external: "Vaš nalog %{value} možete koristiti za prijavu." + mail_body_account_information: Informacije o vašem nalogu + mail_subject_account_activation_request: "Zahtev za aktivaciju naloga %{value}" + mail_body_account_activation_request: "Novi korisnik (%{value}) je registrovan. Nalog čeka na vaše odobrenje:" + mail_subject_reminder: "%{count} problema dospeva narednih %{days} dana" + mail_body_reminder: "%{count} problema dodeljenih vama dospeva u narednih %{days} dana:" + mail_subject_wiki_content_added: "Wiki stranica '%{id}' je dodata" + mail_body_wiki_content_added: "%{author} je dodao wiki stranicu '%{id}'." + mail_subject_wiki_content_updated: "Wiki stranica '%{id}' je ažurirana" + mail_body_wiki_content_updated: "%{author} je ažurirao wiki stranicu '%{id}'." + + + field_name: Naziv + field_description: Opis + field_summary: Rezime + field_is_required: Obavezno + field_firstname: Ime + field_lastname: Prezime + field_mail: E-adresa + field_filename: Datoteka + field_filesize: Veličina + field_downloads: Preuzimanja + field_author: Autor + field_created_on: Kreirano + field_updated_on: Ažurirano + field_field_format: Format + field_is_for_all: Za sve projekte + field_possible_values: Moguće vrednosti + field_regexp: Regularan izraz + field_min_length: Minimalna dužina + field_max_length: Maksimalna dužina + field_value: Vrednost + field_category: Kategorija + field_title: Naslov + field_project: Projekat + field_issue: Problem + field_status: Status + field_notes: Beleške + field_is_closed: Zatvoren problem + field_is_default: Podrazumevana vrednost + field_tracker: Praćenje + field_subject: Predmet + field_due_date: Krajnji rok + field_assigned_to: Dodeljeno + field_priority: Prioritet + field_fixed_version: Odredišna verzija + field_user: Korisnik + field_principal: Glavni + field_role: Uloga + field_homepage: Početna stranica + field_is_public: Javno objavljivanje + field_parent: Potprojekat od + field_is_in_roadmap: Problemi prikazani u planu rada + field_login: Korisničko ime + field_mail_notification: Obaveštenja putem e-pošte + field_admin: Administrator + field_last_login_on: Poslednje povezivanje + field_language: Jezik + field_effective_date: Datum + field_password: Lozinka + field_new_password: Nova lozinka + field_password_confirmation: Potvrda lozinke + field_version: Verzija + field_type: Tip + field_host: Glavni računar + field_port: Port + field_account: Korisnički nalog + field_base_dn: Bazni DN + field_attr_login: Atribut prijavljivanja + field_attr_firstname: Atribut imena + field_attr_lastname: Atribut prezimena + field_attr_mail: Atribut e-adrese + field_onthefly: Kreiranje korisnika u toku rada + field_start_date: Početak + field_done_ratio: "% urađeno" + field_auth_source: Režim potvrde identiteta + field_hide_mail: Sakrij moju e-adresu + field_comments: Komentar + field_url: URL + field_start_page: Početna stranica + field_subproject: Potprojekat + field_hours: sati + field_activity: Aktivnost + field_spent_on: Datum + field_identifier: Identifikator + field_is_filter: Upotrebi kao filter + field_issue_to: Srodni problemi + field_delay: Kašnjenje + field_assignable: Problem može biti dodeljen ovoj ulozi + field_redirect_existing_links: Preusmeri postojeće veze + field_estimated_hours: Procenjeno vreme + field_column_names: Kolone + field_time_zone: Vremenska zona + field_searchable: Može da se pretražuje + field_default_value: Podrazumevana vrednost + field_comments_sorting: Prikaži komentare + field_parent_title: Matična stranica + field_editable: Izmenljivo + field_watcher: Posmatrač + field_identity_url: OpenID URL + field_content: Sadržaj + field_group_by: Grupisanje rezultata po + field_sharing: Deljenje + field_parent_issue: Matični zadatak + + setting_app_title: Naslov aplikacije + setting_app_subtitle: Podnaslov aplikacije + setting_welcome_text: Tekst dobrodošlice + setting_default_language: Podrazumevani jezik + setting_login_required: Obavezna potvrda identiteta + setting_self_registration: Samoregistracija + setting_attachment_max_size: Maks. veličina priložene datoteke + setting_issues_export_limit: Ograničenje izvoza „problema“ + setting_mail_from: E-adresa pošiljaoca + setting_bcc_recipients: Primaoci „Bcc“ kopije + setting_plain_text_mail: Poruka sa čistim tekstom (bez HTML-a) + setting_host_name: Putanja i naziv glavnog računara + setting_text_formatting: Oblikovanje teksta + setting_wiki_compression: Kompresija Wiki istorije + setting_feeds_limit: Ograničenje sadržaja izvora vesti + setting_default_projects_public: Podrazumeva se javno prikazivanje novih projekata + setting_autofetch_changesets: Izvršavanje automatskog preuzimanja + setting_sys_api_enabled: Omogućavanje WS za upravljanje spremištem + setting_commit_ref_keywords: Referenciranje ključnih reči + setting_commit_fix_keywords: Popravljanje ključnih reči + setting_autologin: Automatska prijava + setting_date_format: Format datuma + setting_time_format: Format vremena + setting_cross_project_issue_relations: Dozvoli povezivanje problema iz unakrsnih projekata + setting_issue_list_default_columns: Podrazumevane kolone prikazane na spisku problema + setting_emails_footer: Podnožje stranice e-poruke + setting_protocol: Protokol + setting_per_page_options: Opcije prikaza objekata po stranici + setting_user_format: Format prikaza korisnika + setting_activity_days_default: Broj dana prikazanih na projektnoj aktivnosti + setting_display_subprojects_issues: Prikazuj probleme iz potprojekata na glavnom projektu, ukoliko nije drugačije navedeno + setting_enabled_scm: Omogućavanje SCM + setting_mail_handler_body_delimiters: "Skraćivanje e-poruke nakon jedne od ovih linija" + setting_mail_handler_api_enabled: Omogućavanje WS dolazne e-poruke + setting_mail_handler_api_key: API ključ + setting_sequential_project_identifiers: Generisanje sekvencijalnog imena projekta + setting_gravatar_enabled: Koristi Gravatar korisničke ikone + setting_gravatar_default: Podrazumevana Gravatar slika + setting_diff_max_lines_displayed: Maks. broj prikazanih različitih linija + setting_file_max_size_displayed: Maks. veličina tekst. datoteka prikazanih umetnuto + setting_repository_log_display_limit: Maks. broj revizija prikazanih u datoteci za evidenciju + setting_openid: Dozvoli OpenID prijavu i registraciju + setting_password_min_length: Minimalna dužina lozinke + setting_new_project_user_role_id: Kreatoru projekta (koji nije administrator) dodeljuje je uloga + setting_default_projects_modules: Podrazumevano omogućeni moduli za nove projekte + setting_issue_done_ratio: Izračunaj odnos rešenih problema + setting_issue_done_ratio_issue_field: koristeći polje problema + setting_issue_done_ratio_issue_status: koristeći status problema + setting_start_of_week: Prvi dan u sedmici + setting_rest_api_enabled: Omogući REST web usluge + setting_cache_formatted_text: Keširanje obrađenog teksta + + permission_add_project: Kreiranje projekta + permission_add_subprojects: Kreiranje potpojekta + permission_edit_project: Izmena projekata + permission_select_project_modules: Odabiranje modula projekta + permission_manage_members: Upravljanje članovima + permission_manage_project_activities: Upravljanje projektnim aktivnostima + permission_manage_versions: Upravljanje verzijama + permission_manage_categories: Upravljanje kategorijama problema + permission_view_issues: Pregled problema + permission_add_issues: Dodavanje problema + permission_edit_issues: Izmena problema + permission_manage_issue_relations: Upravljanje vezama između problema + permission_add_issue_notes: Dodavanje beleški + permission_edit_issue_notes: Izmena beleški + permission_edit_own_issue_notes: Izmena sopstvenih beleški + permission_move_issues: Pomeranje problema + permission_delete_issues: Brisanje problema + permission_manage_public_queries: Upravljanje javnim upitima + permission_save_queries: Snimanje upita + permission_view_gantt: Pregledanje Gantovog dijagrama + permission_view_calendar: Pregledanje kalendara + permission_view_issue_watchers: Pregledanje spiska posmatrača + permission_add_issue_watchers: Dodavanje posmatrača + permission_delete_issue_watchers: Brisanje posmatrača + permission_log_time: Beleženje utrošenog vremena + permission_view_time_entries: Pregledanje utrošenog vremena + permission_edit_time_entries: Izmena utrošenog vremena + permission_edit_own_time_entries: Izmena sopstvenog utrošenog vremena + permission_manage_news: Upravljanje vestima + permission_comment_news: Komentarisanje vesti + permission_view_documents: Pregledanje dokumenata + permission_manage_files: Upravljanje datotekama + permission_view_files: Pregledanje datoteka + permission_manage_wiki: Upravljanje wiki stranicama + permission_rename_wiki_pages: Promena imena wiki stranicama + permission_delete_wiki_pages: Brisanje wiki stranica + permission_view_wiki_pages: Pregledanje wiki stranica + permission_view_wiki_edits: Pregledanje wiki istorije + permission_edit_wiki_pages: Izmena wiki stranica + permission_delete_wiki_pages_attachments: Brisanje priloženih datoteka + permission_protect_wiki_pages: Zaštita wiki stranica + permission_manage_repository: Upravljanje spremištem + permission_browse_repository: Pregledanje spremišta + permission_view_changesets: Pregledanje skupa promena + permission_commit_access: Potvrda pristupa + permission_manage_boards: Upravljanje forumima + permission_view_messages: Pregledanje poruka + permission_add_messages: Slanje poruka + permission_edit_messages: Izmena poruka + permission_edit_own_messages: Izmena sopstvenih poruka + permission_delete_messages: Brisanje poruka + permission_delete_own_messages: Brisanje sopstvenih poruka + permission_export_wiki_pages: Izvoz wiki stranica + permission_manage_subtasks: Upravljanje podzadacima + + project_module_issue_tracking: Praćenje problema + project_module_time_tracking: Praćenje vremena + project_module_news: Vesti + project_module_documents: Dokumenti + project_module_files: Datoteke + project_module_wiki: Wiki + project_module_repository: Spremište + project_module_boards: Forumi + + label_user: Korisnik + label_user_plural: Korisnici + label_user_new: Novi korisnik + label_user_anonymous: Anoniman + label_project: Projekat + label_project_new: Novi projekat + label_project_plural: Projekti + label_x_projects: + zero: nema projekata + one: jedan projekat + other: "%{count} projekata" + label_project_all: Svi projekti + label_project_latest: Poslednji projekti + label_issue: Problem + label_issue_new: Novi problem + label_issue_plural: Problemi + label_issue_view_all: Prikaz svih problema + label_issues_by: "Problemi (%{value})" + label_issue_added: Problem je dodat + label_issue_updated: Problem je ažuriran + label_document: Dokument + label_document_new: Novi dokument + label_document_plural: Dokumenti + label_document_added: Dokument je dodat + label_role: Uloga + label_role_plural: Uloge + label_role_new: Nova uloga + label_role_and_permissions: Uloge i dozvole + label_member: Član + label_member_new: Novi član + label_member_plural: Članovi + label_tracker: Praćenje + label_tracker_plural: Praćenja + label_tracker_new: Novo praćenje + label_workflow: Tok posla + label_issue_status: Status problema + label_issue_status_plural: Statusi problema + label_issue_status_new: Novi status + label_issue_category: Kategorija problema + label_issue_category_plural: Kategorije problema + label_issue_category_new: Nova kategorija + label_custom_field: Prilagođeno polje + label_custom_field_plural: Prilagođena polja + label_custom_field_new: Novo prilagođeno polje + label_enumerations: Nabrojiva lista + label_enumeration_new: Nova vrednost + label_information: Informacija + label_information_plural: Informacije + label_please_login: Molimo, prijavite se + label_register: Registracija + label_login_with_open_id_option: ili prijava sa OpenID + label_password_lost: Izgubljena lozinka + label_home: Početak + label_my_page: Moja stranica + label_my_account: Moj nalog + label_my_projects: Moji projekti + label_my_page_block: My page block + label_administration: Administracija + label_login: Prijava + label_logout: Odjava + label_help: Pomoć + label_reported_issues: Prijavljeni problemi + label_assigned_to_me_issues: Problemi dodeljeni meni + label_last_login: Poslednje povezivanje + label_registered_on: Registrovan + label_activity: Aktivnost + label_overall_activity: Celokupna aktivnost + label_user_activity: "Aktivnost korisnika %{value}" + label_new: Novo + label_logged_as: Prijavljeni ste kao + label_environment: Okruženje + label_authentication: Potvrda identiteta + label_auth_source: Režim potvrde identiteta + label_auth_source_new: Novi režim potvrde identiteta + label_auth_source_plural: Režimi potvrde identiteta + label_subproject_plural: Potprojekti + label_subproject_new: Novi potprojekat + label_and_its_subprojects: "%{value} i njegovi potprojekti" + label_min_max_length: Min. - Maks. dužina + label_list: Spisak + label_date: Datum + label_integer: Ceo broj + label_float: Sa pokretnim zarezom + label_boolean: Logički operator + label_string: Tekst + label_text: Dugi tekst + label_attribute: Osobina + label_attribute_plural: Osobine + label_no_data: Nema podataka za prikazivanje + label_change_status: Promena statusa + label_history: Istorija + label_attachment: Datoteka + label_attachment_new: Nova datoteka + label_attachment_delete: Brisanje datoteke + label_attachment_plural: Datoteke + label_file_added: Datoteka je dodata + label_report: Izveštaj + label_report_plural: Izveštaji + label_news: Vesti + label_news_new: Dodavanje vesti + label_news_plural: Vesti + label_news_latest: Poslednje vesti + label_news_view_all: Prikaz svih vesti + label_news_added: Vesti su dodate + label_settings: Podešavanja + label_overview: Pregled + label_version: Verzija + label_version_new: Nova verzija + label_version_plural: Verzije + label_close_versions: Zatvori završene verzije + label_confirmation: Potvrda + label_export_to: 'Takođe dostupno i u varijanti:' + label_read: Čitanje... + label_public_projects: Javni projekti + label_open_issues: otvoren + label_open_issues_plural: otvorenih + label_closed_issues: zatvoren + label_closed_issues_plural: zatvorenih + label_x_open_issues_abbr_on_total: + zero: 0 otvorenih / %{total} + one: 1 otvoren / %{total} + other: "%{count} otvorenih / %{total}" + label_x_open_issues_abbr: + zero: 0 otvorenih + one: 1 otvoren + other: "%{count} otvorenih" + label_x_closed_issues_abbr: + zero: 0 zatvorenih + one: 1 zatvoren + other: "%{count} zatvorenih" + label_total: Ukupno + label_permissions: Dozvole + label_current_status: Trenutni status + label_new_statuses_allowed: Novi statusi dozvoljeni + label_all: svi + label_none: nijedan + label_nobody: nikome + label_next: Sledeće + label_previous: Prethodno + label_used_by: Koristio + label_details: Detalji + label_add_note: Dodaj belešku + label_per_page: Po strani + label_calendar: Kalendar + label_months_from: meseci od + label_gantt: Gantov dijagram + label_internal: Unutrašnji + label_last_changes: "poslednjih %{count} promena" + label_change_view_all: Prikaži sve promene + label_personalize_page: Personalizuj ovu stranu + label_comment: Komentar + label_comment_plural: Komentari + label_x_comments: + zero: bez komentara + one: jedan komentar + other: "%{count} komentara" + label_comment_add: Dodaj komentar + label_comment_added: Komentar dodat + label_comment_delete: Obriši komentare + label_query: Prilagođen upit + label_query_plural: Prilagođeni upiti + label_query_new: Novi upit + label_filter_add: Dodavanje filtera + label_filter_plural: Filteri + label_equals: je + label_not_equals: nije + label_in_less_than: manje od + label_in_more_than: više od + label_greater_or_equal: '>=' + label_less_or_equal: '<=' + label_in: u + label_today: danas + label_all_time: sve vreme + label_yesterday: juče + label_this_week: ove sedmice + label_last_week: poslednje sedmice + label_last_n_days: "poslednjih %{count} dana" + label_this_month: ovog meseca + label_last_month: poslednjeg meseca + label_this_year: ove godine + label_date_range: Vremenski period + label_less_than_ago: pre manje od nekoliko dana + label_more_than_ago: pre više od nekoliko dana + label_ago: pre nekoliko dana + label_contains: sadrži + label_not_contains: ne sadrži + label_day_plural: dana + label_repository: Spremište + label_repository_plural: Spremišta + label_browse: Pregledanje + label_branch: Grana + label_tag: Oznaka + label_revision: Revizija + label_revision_plural: Revizije + label_revision_id: "Revizija %{value}" + label_associated_revisions: Pridružene revizije + label_added: dodato + label_modified: promenjeno + label_copied: kopirano + label_renamed: preimenovano + label_deleted: izbrisano + label_latest_revision: Poslednja revizija + label_latest_revision_plural: Poslednje revizije + label_view_revisions: Pregled revizija + label_view_all_revisions: Pregled svih revizija + label_max_size: Maksimalna veličina + label_sort_highest: Premeštanje na vrh + label_sort_higher: Premeštanje na gore + label_sort_lower: Premeštanje na dole + label_sort_lowest: Premeštanje na dno + label_roadmap: Plan rada + label_roadmap_due_in: "Dospeva %{value}" + label_roadmap_overdue: "%{value} najkasnije" + label_roadmap_no_issues: Nema problema za ovu verziju + label_search: Pretraga + label_result_plural: Rezultati + label_all_words: Sve reči + label_wiki: Wiki + label_wiki_edit: Wiki izmena + label_wiki_edit_plural: Wiki izmene + label_wiki_page: Wiki stranica + label_wiki_page_plural: Wiki stranice + label_index_by_title: Indeksiranje po naslovu + label_index_by_date: Indeksiranje po datumu + label_current_version: Trenutna verzija + label_preview: Pregled + label_feed_plural: Izvori vesti + label_changes_details: Detalji svih promena + label_issue_tracking: Praćenje problema + label_spent_time: Utrošeno vreme + label_overall_spent_time: Celokupno utrošeno vreme + label_f_hour: "%{value} sat" + label_f_hour_plural: "%{value} sati" + label_time_tracking: Praćenje vremena + label_change_plural: Promene + label_statistics: Statistika + label_commits_per_month: Izvršenja mesečno + label_commits_per_author: Izvršenja po autoru + label_view_diff: Pogledaj razlike + label_diff_inline: unutra + label_diff_side_by_side: uporedo + label_options: Opcije + label_copy_workflow_from: Kopiranje toka posla od + label_permissions_report: Izveštaj o dozvolama + label_watched_issues: Posmatrani problemi + label_related_issues: Srodni problemi + label_applied_status: Primenjeni statusi + label_loading: Učitavanje... + label_relation_new: Nova relacija + label_relation_delete: Brisanje relacije + label_relates_to: srodnih sa + label_duplicates: dupliranih + label_duplicated_by: dupliranih od + label_blocks: odbijenih + label_blocked_by: odbijenih od + label_precedes: prethodi + label_follows: praćenih + label_end_to_start: od kraja do početka + label_end_to_end: od kraja do kraja + label_start_to_start: od početka do početka + label_start_to_end: od početka do kraja + label_stay_logged_in: Ostanite prijavljeni + label_disabled: onemogućeno + label_show_completed_versions: Prikazivanje završene verzije + label_me: meni + label_board: Forum + label_board_new: Novi forum + label_board_plural: Forumi + label_board_locked: Zaključana + label_board_sticky: Lepljiva + label_topic_plural: Teme + label_message_plural: Poruke + label_message_last: Poslednja poruka + label_message_new: Nova poruka + label_message_posted: Poruka je dodata + label_reply_plural: Odgovori + label_send_information: Pošalji korisniku detalje naloga + label_year: Godina + label_month: Mesec + label_week: Sedmica + label_date_from: Šalje + label_date_to: Prima + label_language_based: Bazirano na jeziku korisnika + label_sort_by: "Sortirano po %{value}" + label_send_test_email: Slanje probne e-poruke + label_feeds_access_key: RSS pristupni ključ + label_missing_feeds_access_key: RSS pristupni ključ nedostaje + label_feeds_access_key_created_on: "RSS pristupni ključ je napravljen pre %{value}" + label_module_plural: Moduli + label_added_time_by: "Dodao %{author} pre %{age}" + label_updated_time_by: "Ažurirao %{author} pre %{age}" + label_updated_time: "Ažurirano pre %{value}" + label_jump_to_a_project: Skok na projekat... + label_file_plural: Datoteke + label_changeset_plural: Skupovi promena + label_default_columns: Podrazumevane kolone + label_no_change_option: (Bez promena) + label_bulk_edit_selected_issues: Grupna izmena odabranih problema + label_theme: Tema + label_default: Podrazumevano + label_search_titles_only: Pretražuj samo naslove + label_user_mail_option_all: "Za bilo koji događaj na svim mojim projektima" + label_user_mail_option_selected: "Za bilo koji događaj na samo odabranim projektima..." + label_user_mail_no_self_notified: "Ne želim biti obaveštavan za promene koje sam pravim" + label_registration_activation_by_email: aktivacija naloga putem e-poruke + label_registration_manual_activation: ručna aktivacija naloga + label_registration_automatic_activation: automatska aktivacija naloga + label_display_per_page: "Broj stavki po stranici: %{value}" + label_age: Starost + label_change_properties: Promeni svojstva + label_general: Opšti + label_more: Više + label_scm: SCM + label_plugins: Dodatne komponente + label_ldap_authentication: LDAP potvrda identiteta + label_downloads_abbr: D/L + label_optional_description: Opciono opis + label_add_another_file: Dodaj još jednu datoteku + label_preferences: Podešavanja + label_chronological_order: po hronološkom redosledu + label_reverse_chronological_order: po obrnutom hronološkom redosledu + label_planning: Planiranje + label_incoming_emails: Dolazne e-poruke + label_generate_key: Generisanje ključa + label_issue_watchers: Posmatrači + label_example: Primer + label_display: Prikaz + label_sort: Sortiranje + label_ascending: Rastući niz + label_descending: Opadajući niz + label_date_from_to: Od %{start} do %{end} + label_wiki_content_added: Wiki stranica je dodata + label_wiki_content_updated: Wiki stranica je ažurirana + label_group: Grupa + label_group_plural: Grupe + label_group_new: Nova grupa + label_time_entry_plural: Utrošeno vreme + label_version_sharing_none: Nije deljeno + label_version_sharing_descendants: Sa potprojektima + label_version_sharing_hierarchy: Sa hijerarhijom projekta + label_version_sharing_tree: Sa stablom projekta + label_version_sharing_system: Sa svim projektima + label_update_issue_done_ratios: Ažuriraj odnos rešenih problema + label_copy_source: Izvor + label_copy_target: Odredište + label_copy_same_as_target: Isto kao odredište + label_display_used_statuses_only: Prikazuj statuse korišćene samo od strane ovog praćenja + label_api_access_key: API pristupni ključ + label_missing_api_access_key: Nedostaje API pristupni ključ + label_api_access_key_created_on: "API pristupni ključ je kreiran pre %{value}" + label_profile: Profil + label_subtask_plural: Podzadatak + label_project_copy_notifications: Pošalji e-poruku sa obaveštenjem prilikom kopiranja projekta + + button_login: Prijava + button_submit: Pošalji + button_save: Snimi + button_check_all: Uključi sve + button_uncheck_all: Isključi sve + button_delete: Izbriši + button_create: Kreiraj + button_create_and_continue: Kreiraj i nastavi + button_test: Test + button_edit: Izmeni + button_add: Dodaj + button_change: Promeni + button_apply: Primeni + button_clear: Obriši + button_lock: Zaključaj + button_unlock: Otključaj + button_download: Preuzmi + button_list: Spisak + button_view: Prikaži + button_move: Pomeri + button_move_and_follow: Pomeri i prati + button_back: Nazad + button_cancel: Poništi + button_activate: Aktiviraj + button_sort: Sortiraj + button_log_time: Evidentiraj vreme + button_rollback: Povratak na ovu verziju + button_watch: Prati + button_unwatch: Ne prati više + button_reply: Odgovori + button_archive: Arhiviraj + button_unarchive: Vrati iz arhive + button_reset: Poništi + button_rename: Preimenuj + button_change_password: Promeni lozinku + button_copy: Kopiraj + button_copy_and_follow: Kopiraj i prati + button_annotate: Pribeleži + button_update: Ažuriraj + button_configure: Podesi + button_quote: Pod navodnicima + button_duplicate: Dupliraj + button_show: Prikaži + + status_active: aktivni + status_registered: registrovani + status_locked: zaključani + + version_status_open: otvoren + version_status_locked: zaključan + version_status_closed: zatvoren + + field_active: Aktivan + + text_select_mail_notifications: Odaberi akcije za koje će obaveštenje biti poslato putem e-pošte. + text_regexp_info: npr. ^[A-Z0-9]+$ + text_min_max_length_info: 0 znači bez ograničenja + text_project_destroy_confirmation: Jeste li sigurni da želite da izbrišete ovaj projekat i sve pripadajuće podatke? + text_subprojects_destroy_warning: "Potprojekti: %{value} će takođe biti izbrisan." + text_workflow_edit: Odaberite ulogu i praćenje za izmenu toka posla + text_are_you_sure: Jeste li sigurni? + text_journal_changed: "%{label} promenjen od %{old} u %{new}" + text_journal_set_to: "%{label} postavljen u %{value}" + text_journal_deleted: "%{label} izbrisano (%{old})" + text_journal_added: "%{label} %{value} dodato" + text_tip_issue_begin_day: zadatak počinje ovog dana + text_tip_issue_end_day: zadatak se završava ovog dana + text_tip_issue_begin_end_day: zadatak počinje i završava ovog dana + text_caracters_maximum: "Najviše %{count} znak(ova)." + text_caracters_minimum: "Broj znakova mora biti najmanje %{count}." + text_length_between: "Broj znakova mora biti između %{min} i %{max}." + text_tracker_no_workflow: Ovo praćenje nema definisan tok posla + text_unallowed_characters: Nedozvoljeni znakovi + text_comma_separated: Dozvoljene su višestruke vrednosti (odvojene zarezom). + text_line_separated: Dozvoljene su višestruke vrednosti (jedan red za svaku vrednost). + text_issues_ref_in_commit_messages: Referenciranje i popravljanje problema u izvršnim porukama + text_issue_added: "%{author} je prijavio problem %{id}." + text_issue_updated: "%{author} je ažurirao problem %{id}." + text_wiki_destroy_confirmation: Jeste li sigurni da želite da obrišete wiki i sav sadržaj? + text_issue_category_destroy_question: "Nekoliko problema (%{count}) je dodeljeno ovoj kategoriji. Šta želite da uradite?" + text_issue_category_destroy_assignments: Ukloni dodeljene kategorije + text_issue_category_reassign_to: Dodeli ponovo probleme ovoj kategoriji + text_user_mail_option: "Za neizabrane projekte, dobićete samo obaveštenje o stvarima koje pratite ili ste uključeni (npr. problemi čiji ste vi autor ili zastupnik)." + text_no_configuration_data: "Uloge, praćenja, statusi problema i toka posla još uvek nisu podešeni.\nPreporučljivo je da učitate podrazumevano konfigurisanje. Izmena je moguća nakon prvog učitavanja." + text_load_default_configuration: Učitaj podrazumevano konfigurisanje + text_status_changed_by_changeset: "Primenjeno u skupu sa promenama %{value}." + text_issues_destroy_confirmation: 'Jeste li sigurni da želite da izbrišete odabrane probleme?' + text_select_project_modules: 'Odaberite module koje želite omogućiti za ovaj projekat:' + text_default_administrator_account_changed: Podrazumevani administratorski nalog je promenjen + text_file_repository_writable: Fascikla priloženih datoteka je upisiva + text_plugin_assets_writable: Fascikla elemenata dodatnih komponenti je upisiva + text_rmagick_available: RMagick je dostupan (opciono) + text_destroy_time_entries_question: "%{hours} sati je prijavljeno za ovaj problem koji želite izbrisati. Šta želite da uradite?" + text_destroy_time_entries: Izbriši prijavljene sate + text_assign_time_entries_to_project: Dodeli prijavljene sate projektu + text_reassign_time_entries: 'Dodeli ponovo prijavljene sate ovom problemu:' + text_user_wrote: "%{value} je napisao:" + text_enumeration_destroy_question: "%{count} objekat(a) je dodeljeno ovoj vrednosti." + text_enumeration_category_reassign_to: 'Dodeli ih ponovo ovoj vrednosti:' + text_email_delivery_not_configured: "Isporuka e-poruka nije konfigurisana i obaveštenja su onemogućena.\nPodesite vaš SMTP server u config/configuration.yml i pokrenite ponovo aplikaciju za njihovo omogućavanje." + text_repository_usernames_mapping: "Odaberite ili ažurirajte Redmine korisnike mapiranjem svakog korisničkog imena pronađenog u evidenciji spremišta.\nKorisnici sa istim Redmine imenom i imenom spremišta ili e-adresom su automatski mapirani." + text_diff_truncated: '... Ova razlika je isečena jer je dostignuta maksimalna veličina prikaza.' + text_custom_field_possible_values_info: 'Jedan red za svaku vrednost' + text_wiki_page_destroy_question: "Ova stranica ima %{descendants} podređenih stranica i podstranica. Šta želite da uradite?" + text_wiki_page_nullify_children: "Zadrži podređene stranice kao korene stranice" + text_wiki_page_destroy_children: "Izbriši podređene stranice i sve njihove podstranice" + text_wiki_page_reassign_children: "Dodeli ponovo podređene stranice ovoj matičnoj stranici" + text_own_membership_delete_confirmation: "Nakon uklanjanja pojedinih ili svih vaših dozvola nećete više moći da uređujete ovaj projekat.\nŽelite li da nastavite?" + text_zoom_in: Uvećaj + text_zoom_out: Umanji + + default_role_manager: Menadžer + default_role_developer: Programer + default_role_reporter: Izveštač + default_tracker_bug: Greška + default_tracker_feature: Funkcionalnost + default_tracker_support: Podrška + default_issue_status_new: Novo + default_issue_status_in_progress: U toku + default_issue_status_resolved: Rešeno + default_issue_status_feedback: Povratna informacija + default_issue_status_closed: Zatvoreno + default_issue_status_rejected: Odbijeno + default_doc_category_user: Korisnička dokumentacija + default_doc_category_tech: Tehnička dokumentacija + default_priority_low: Nizak + default_priority_normal: Normalan + default_priority_high: Visok + default_priority_urgent: Hitno + default_priority_immediate: Neposredno + default_activity_design: Dizajn + default_activity_development: Razvoj + + enumeration_issue_priorities: Prioriteti problema + enumeration_doc_categories: Kategorije dokumenta + enumeration_activities: Aktivnosti (praćenje vremena) + enumeration_system_activity: Sistemska aktivnost + + field_time_entries: Vreme evidencije + project_module_gantt: Gantov dijagram + project_module_calendar: Kalendar + button_edit_associated_wikipage: "Edit associated Wiki page: %{page_title}" + field_text: Text field + label_user_mail_option_only_owner: Samo za stvari koje posedujem + setting_default_notification_option: Podrazumevana opcija za notifikaciju + label_user_mail_option_only_my_events: Za dogadjaje koje pratim ili sam u njih uključen + label_user_mail_option_only_assigned: Za dogadjaje koji su mi dodeljeni lično + label_user_mail_option_none: Bez obaveštenja + field_member_of_group: Assignee's group + field_assigned_to_role: Assignee's role + notice_not_authorized_archived_project: Projekat kome pokušavate da pristupite je arhiviran + label_principal_search: "Traži korisnike ili grupe:" + label_user_search: "Traži korisnike:" + field_visible: Vidljivo + setting_emails_header: Email zaglavlje + setting_commit_logtime_activity_id: Activity for logged time + text_time_logged_by_changeset: Applied in changeset %{value}. + setting_commit_logtime_enabled: Omogući praćenje vremena + notice_gantt_chart_truncated: The chart was truncated because it exceeds the maximum number of items that can be displayed (%{max}) + setting_gantt_items_limit: Maksimalan broj stavki na gant grafiku + field_warn_on_leaving_unsaved: Upozori me ako napuštam stranu sa tekstom koji nije snimljen + text_warn_on_leaving_unsaved: Strana sadrži tekst koji nije snimljen i biće izgubljen ako je napustite. + label_my_queries: My custom queries + text_journal_changed_no_detail: "%{label} ažuriran" + label_news_comment_added: Komentar dodat u novosti + button_expand_all: Proširi sve + button_collapse_all: Zatvori sve + label_additional_workflow_transitions_for_assignee: Additional transitions allowed when the user is the assignee + label_additional_workflow_transitions_for_author: Additional transitions allowed when the user is the author + label_bulk_edit_selected_time_entries: Bulk edit selected time entries + text_time_entries_destroy_confirmation: Da li ste sigurni da želite da obrišete selektovane stavke ? + label_role_anonymous: Anonimus + label_role_non_member: Nije član + label_issue_note_added: Nota dodana + label_issue_status_updated: Status ažuriran + label_issue_priority_updated: Prioritet ažuriran + label_issues_visibility_own: Problem kreiran od strane ili je dodeljen korisniku + field_issues_visibility: Vidljivost problema + label_issues_visibility_all: Svi problemi + permission_set_own_issues_private: Podesi sopstveni problem kao privatan ili javan + field_is_private: Privatno + permission_set_issues_private: Podesi problem kao privatan ili javan + label_issues_visibility_public: Svi javni problemi + text_issues_destroy_descendants_confirmation: Ova operacija će takođe obrisati %{count} podzadataka. + field_commit_logs_encoding: Kodiranje izvršnih poruka + field_scm_path_encoding: Path encoding + text_scm_path_encoding_note: "Default: UTF-8" + field_path_to_repository: Path to repository + field_root_directory: Root directory + field_cvs_module: Module + field_cvsroot: CVSROOT + text_mercurial_repository_note: Local repository (e.g. /hgrepo, c:\hgrepo) + text_scm_command: Command + text_scm_command_version: Version + label_git_report_last_commit: Report last commit for files and directories + notice_issue_successful_create: Issue %{id} created. + label_between: between + setting_issue_group_assignment: Allow issue assignment to groups + label_diff: diff + text_git_repository_note: Repository is bare and local (e.g. /gitrepo, c:\gitrepo) + description_query_sort_criteria_direction: Sort direction + description_project_scope: Search scope + description_filter: Filter + description_user_mail_notification: Mail notification settings + description_date_from: Enter start date + description_message_content: Message content + description_available_columns: Available Columns + description_date_range_interval: Choose range by selecting start and end date + description_issue_category_reassign: Choose issue category + description_search: Searchfield + description_notes: Notes + description_date_range_list: Choose range from list + description_choose_project: Projects + description_date_to: Enter end date + description_query_sort_criteria_attribute: Sort attribute + description_wiki_subpages_reassign: Choose new parent page + description_selected_columns: Selected Columns + label_parent_revision: Parent + label_child_revision: Child + error_scm_annotate_big_text_file: The entry cannot be annotated, as it exceeds the maximum text file size. + setting_default_issue_start_date_to_creation_date: Use current date as start date for new issues + button_edit_section: Edit this section + setting_repositories_encodings: Attachments and repositories encodings + description_all_columns: All Columns + button_export: Export + label_export_options: "%{export_format} export options" + error_attachment_too_big: This file cannot be uploaded because it exceeds the maximum allowed file size (%{max_size}) + notice_failed_to_save_time_entries: "Failed to save %{count} time entrie(s) on %{total} selected: %{ids}." + label_x_issues: + zero: 0 problem + one: 1 problem + other: "%{count} problemi" + label_repository_new: New repository + field_repository_is_default: Main repository + label_copy_attachments: Copy attachments + label_item_position: "%{position}/%{count}" + label_completed_versions: Completed versions + text_project_identifier_info: Only lower case letters (a-z), numbers, dashes and underscores are allowed.
    Once saved, the identifier cannot be changed. + field_multiple: Multiple values + setting_commit_cross_project_ref: Allow issues of all the other projects to be referenced and fixed + text_issue_conflict_resolution_add_notes: Add my notes and discard my other changes + text_issue_conflict_resolution_overwrite: Apply my changes anyway (previous notes will be kept but some changes may be overwritten) + notice_issue_update_conflict: The issue has been updated by an other user while you were editing it. + text_issue_conflict_resolution_cancel: Discard all my changes and redisplay %{link} + permission_manage_related_issues: Manage related issues + field_auth_source_ldap_filter: LDAP filter + label_search_for_watchers: Search for watchers to add + notice_account_deleted: Your account has been permanently deleted. + setting_unsubscribe: Allow users to delete their own account + button_delete_my_account: Delete my account + text_account_destroy_confirmation: |- + Are you sure you want to proceed? + Your account will be permanently deleted, with no way to reactivate it. + error_session_expired: Your session has expired. Please login again. + text_session_expiration_settings: "Warning: changing these settings may expire the current sessions including yours." + setting_session_lifetime: Session maximum lifetime + setting_session_timeout: Session inactivity timeout + label_session_expiration: Session expiration + permission_close_project: Close / reopen the project + label_show_closed_projects: View closed projects + button_close: Close + button_reopen: Reopen + project_status_active: active + project_status_closed: closed + project_status_archived: archived + text_project_closed: This project is closed and read-only. + notice_user_successful_create: User %{id} created. + field_core_fields: Standard fields + field_timeout: Timeout (in seconds) + setting_thumbnails_enabled: Display attachment thumbnails + setting_thumbnails_size: Thumbnails size (in pixels) + label_status_transitions: Status transitions + label_fields_permissions: Fields permissions + label_readonly: Read-only + label_required: Required + text_repository_identifier_info: Only lower case letters (a-z), numbers, dashes and underscores are allowed.
    Once saved, the identifier cannot be changed. + field_board_parent: Parent forum + label_attribute_of_project: Project's %{name} + label_attribute_of_author: Author's %{name} + label_attribute_of_assigned_to: Assignee's %{name} + label_attribute_of_fixed_version: Target version's %{name} + label_copy_subtasks: Copy subtasks + label_copied_to: copied to + label_copied_from: copied from + label_any_issues_in_project: any issues in project + label_any_issues_not_in_project: any issues not in project + field_private_notes: Private notes + permission_view_private_notes: View private notes + permission_set_notes_private: Set notes as private + label_no_issues_in_project: no issues in project + label_any: svi + label_last_n_weeks: last %{count} weeks + setting_cross_project_subtasks: Allow cross-project subtasks + label_cross_project_descendants: Sa potprojektima + label_cross_project_tree: Sa stablom projekta + label_cross_project_hierarchy: Sa hijerarhijom projekta + label_cross_project_system: Sa svim projektima + button_hide: Hide + setting_non_working_week_days: Non-working days + label_in_the_next_days: in the next + label_in_the_past_days: in the past + label_attribute_of_user: User's %{name} + text_turning_multiple_off: If you disable multiple values, multiple values will be + removed in order to preserve only one value per item. + label_attribute_of_issue: Issue's %{name} + permission_add_documents: Add documents + permission_edit_documents: Edit documents + permission_delete_documents: Delete documents + label_gantt_progress_line: Progress line + setting_jsonp_enabled: Enable JSONP support + field_inherit_members: Inherit members + field_closed_on: Closed + setting_default_projects_tracker_ids: Default trackers for new projects + label_total_time: Ukupno + text_scm_config: You can configure your SCM commands in config/configuration.yml. Please restart the application after editing it. + text_scm_command_not_available: SCM command is not available. Please check settings on the administration panel. diff --git a/config/locales/sr.yml b/config/locales/sr.yml new file mode 100644 index 00000000..f5573c96 --- /dev/null +++ b/config/locales/sr.yml @@ -0,0 +1,1090 @@ +# Serbian translations for Redmine +# by Vladimir Medarović (vlada@medarovic.com) +sr: + direction: ltr + date: + formats: + # Use the strftime parameters for formats. + # When no format has been given, it uses default. + # You can provide other formats here if you like! + default: "%d.%m.%Y." + short: "%e %b" + long: "%B %e, %Y" + + day_names: [недеља, понедељак, уторак, среда, четвртак, петак, субота] + abbr_day_names: [нед, пон, уто, сре, чет, пет, суб] + + # Don't forget the nil at the beginning; there's no such thing as a 0th month + month_names: [~, јануар, фебруар, март, април, мај, јун, јул, август, септембар, октобар, новембар, децембар] + abbr_month_names: [~, јан, феб, мар, апр, мај, јун, јул, авг, сеп, окт, нов, дец] + # Used in date_select and datime_select. + order: + - :day + - :month + - :year + + time: + formats: + default: "%d.%m.%Y. у %H:%M" + time: "%H:%M" + short: "%d. %b у %H:%M" + long: "%d. %B %Y у %H:%M" + am: "am" + pm: "pm" + + datetime: + distance_in_words: + half_a_minute: "пола минута" + less_than_x_seconds: + one: "мање од једне секунде" + other: "мање од %{count} сек." + x_seconds: + one: "једна секунда" + other: "%{count} сек." + less_than_x_minutes: + one: "мање од минута" + other: "мање од %{count} мин." + x_minutes: + one: "један минут" + other: "%{count} мин." + about_x_hours: + one: "приближно један сат" + other: "приближно %{count} сати" + x_hours: + one: "1 hour" + other: "%{count} hours" + x_days: + one: "један дан" + other: "%{count} дана" + about_x_months: + one: "приближно један месец" + other: "приближно %{count} месеци" + x_months: + one: "један месец" + other: "%{count} месеци" + about_x_years: + one: "приближно годину дана" + other: "приближно %{count} год." + over_x_years: + one: "преко годину дана" + other: "преко %{count} год." + almost_x_years: + one: "скоро годину дана" + other: "скоро %{count} год." + + number: + format: + separator: "," + delimiter: "" + precision: 3 + human: + format: + delimiter: "" + precision: 3 + storage_units: + format: "%n %u" + units: + byte: + one: "Byte" + other: "Bytes" + kb: "KB" + mb: "MB" + gb: "GB" + tb: "TB" + + +# Used in array.to_sentence. + support: + array: + sentence_connector: "и" + skip_last_comma: false + + activerecord: + errors: + template: + header: + one: "1 error prohibited this %{model} from being saved" + other: "%{count} errors prohibited this %{model} from being saved" + messages: + inclusion: "није укључен у списак" + exclusion: "је резервисан" + invalid: "је неисправан" + confirmation: "потврда не одговара" + accepted: "мора бити прихваћен" + empty: "не може бити празно" + blank: "не може бити празно" + too_long: "је предугачка (максимум знакова је %{count})" + too_short: "је прекратка (минимум знакова је %{count})" + wrong_length: "је погрешне дужине (број знакова мора бити %{count})" + taken: "је већ у употреби" + not_a_number: "није број" + not_a_date: "није исправан датум" + greater_than: "мора бити већи од %{count}" + greater_than_or_equal_to: "мора бити већи или једнак %{count}" + equal_to: "мора бити једнак %{count}" + less_than: "мора бити мањи од %{count}" + less_than_or_equal_to: "мора бити мањи или једнак %{count}" + odd: "мора бити паран" + even: "мора бити непаран" + greater_than_start_date: "мора бити већи од почетног датума" + not_same_project: "не припада истом пројекту" + circular_dependency: "Ова веза ће створити кружну референцу" + cant_link_an_issue_with_a_descendant: "Проблем не може бити повезан са једним од својих подзадатака" + + actionview_instancetag_blank_option: Молим одаберите + + general_text_No: 'Не' + general_text_Yes: 'Да' + general_text_no: 'не' + general_text_yes: 'да' + general_lang_name: 'Serbian Cyrillic (Српски)' + general_csv_separator: ',' + general_csv_decimal_separator: '.' + general_csv_encoding: UTF-8 + general_pdf_encoding: UTF-8 + general_first_day_of_week: '1' + + notice_account_updated: Налог је успешно ажуриран. + notice_account_invalid_creditentials: Неисправно корисничко име или лозинка. + notice_account_password_updated: Лозинка је успешно ажурирана. + notice_account_wrong_password: Погрешна лозинка + notice_account_register_done: Кориснички налог је успешно креиран. Кликните на линк који сте добили у е-поруци за активацију. + notice_account_unknown_email: Непознат корисник. + notice_can_t_change_password: Овај кориснички налог за потврду идентитета користи спољни извор. Немогуће је променити лозинку. + notice_account_lost_email_sent: Послата вам је е-порука са упутством за избор нове лозинке + notice_account_activated: Ваш кориснички налог је активиран. Сада се можете пријавити. + notice_successful_create: Успешно креирање. + notice_successful_update: Успешно ажурирање. + notice_successful_delete: Успешно брисање. + notice_successful_connection: Успешно повезивање. + notice_file_not_found: Страна којој желите приступити не постоји или је уклоњена. + notice_locking_conflict: Податак је ажуриран од стране другог корисника. + notice_not_authorized: Нисте овлашћени за приступ овој страни. + notice_email_sent: "E-порука је послата на %{value}" + notice_email_error: "Догодила се грешка приликом слања е-поруке (%{value})" + notice_feeds_access_key_reseted: Ваш RSS приступни кључ је поништен. + notice_api_access_key_reseted: Ваш API приступни кључ је поништен. + notice_failed_to_save_issues: "Неуспешно снимање %{count} проблема од %{total} одабраних: %{ids}." + notice_failed_to_save_members: "Неуспешно снимање члана(ова): %{errors}." + notice_no_issue_selected: "Ни један проблем није одабран! Молимо, одаберите проблем који желите да мењате." + notice_account_pending: "Ваш налог је креиран и чека на одобрење администратора." + notice_default_data_loaded: Подразумевано конфигурисање је успешно учитано. + notice_unable_delete_version: Верзију је немогуће избрисати. + notice_unable_delete_time_entry: Ставку евиденције времена је немогуће избрисати. + notice_issue_done_ratios_updated: Однос решених проблема је ажуриран. + + error_can_t_load_default_data: "Подразумевано конфигурисање је немогуће учитати: %{value}" + error_scm_not_found: "Ставка или исправка нису пронађене у спремишту." + error_scm_command_failed: "Грешка се јавила приликом покушаја приступа спремишту: %{value}" + error_scm_annotate: "Ставка не постоји или не може бити означена." + error_issue_not_found_in_project: 'Проблем није пронађен или не припада овом пројекту.' + error_no_tracker_in_project: 'Ни једно праћење није повезано са овим пројектом. Молимо проверите подешавања пројекта.' + error_no_default_issue_status: 'Подразумевани статус проблема није дефинисан. Молимо проверите ваше конфигурисање (идите на "Администрација -> Статуси проблема").' + error_can_not_delete_custom_field: Немогуће је избрисати прилагођено поље + error_can_not_delete_tracker: "Ово праћење садржи проблеме и не може бити обрисано." + error_can_not_remove_role: "Ова улога је у употреби и не може бити обрисана." + error_can_not_reopen_issue_on_closed_version: 'Проблем додељен затвореној верзији не може бити поново отворен' + error_can_not_archive_project: Овај пројекат се не може архивирати + error_issue_done_ratios_not_updated: "Однос решених проблема није ажуриран." + error_workflow_copy_source: 'Молимо одаберите изворно праћење или улогу' + error_workflow_copy_target: 'Молимо одаберите одредишно праћење и улогу' + error_unable_delete_issue_status: 'Статус проблема је немогуће обрисати' + error_unable_to_connect: "Повезивање са (%{value}) је немогуће" + warning_attachments_not_saved: "%{count} датотека не може бити снимљена." + + mail_subject_lost_password: "Ваша %{value} лозинка" + mail_body_lost_password: 'За промену ваше лозинке, кликните на следећи линк:' + mail_subject_register: "Активација вашег %{value} налога" + mail_body_register: 'За активацију вашег налога, кликните на следећи линк:' + mail_body_account_information_external: "Ваш налог %{value} можете користити за пријаву." + mail_body_account_information: Информације о вашем налогу + mail_subject_account_activation_request: "Захтев за активацију налога %{value}" + mail_body_account_activation_request: "Нови корисник (%{value}) је регистрован. Налог чека на ваше одобрење:" + mail_subject_reminder: "%{count} проблема доспева наредних %{days} дана" + mail_body_reminder: "%{count} проблема додељених вама доспева у наредних %{days} дана:" + mail_subject_wiki_content_added: "Wiki страница '%{id}' је додата" + mail_body_wiki_content_added: "%{author} је додао wiki страницу '%{id}'." + mail_subject_wiki_content_updated: "Wiki страница '%{id}' је ажурирана" + mail_body_wiki_content_updated: "%{author} је ажурирао wiki страницу '%{id}'." + + + field_name: Назив + field_description: Опис + field_summary: Резиме + field_is_required: Обавезно + field_firstname: Име + field_lastname: Презиме + field_mail: Е-адреса + field_filename: Датотека + field_filesize: Величина + field_downloads: Преузимања + field_author: Аутор + field_created_on: Креирано + field_updated_on: Ажурирано + field_field_format: Формат + field_is_for_all: За све пројекте + field_possible_values: Могуће вредности + field_regexp: Регуларан израз + field_min_length: Минимална дужина + field_max_length: Максимална дужина + field_value: Вредност + field_category: Категорија + field_title: Наслов + field_project: Пројекат + field_issue: Проблем + field_status: Статус + field_notes: Белешке + field_is_closed: Затворен проблем + field_is_default: Подразумевана вредност + field_tracker: Праћење + field_subject: Предмет + field_due_date: Крајњи рок + field_assigned_to: Додељено + field_priority: Приоритет + field_fixed_version: Одредишна верзија + field_user: Корисник + field_principal: Главни + field_role: Улога + field_homepage: Почетна страница + field_is_public: Јавно објављивање + field_parent: Потпројекат од + field_is_in_roadmap: Проблеми приказани у плану рада + field_login: Корисничко име + field_mail_notification: Обавештења путем е-поште + field_admin: Администратор + field_last_login_on: Последње повезивање + field_language: Језик + field_effective_date: Датум + field_password: Лозинка + field_new_password: Нова лозинка + field_password_confirmation: Потврда лозинке + field_version: Верзија + field_type: Тип + field_host: Главни рачунар + field_port: Порт + field_account: Кориснички налог + field_base_dn: Базни DN + field_attr_login: Атрибут пријављивања + field_attr_firstname: Атрибут имена + field_attr_lastname: Атрибут презимена + field_attr_mail: Атрибут е-адресе + field_onthefly: Креирање корисника у току рада + field_start_date: Почетак + field_done_ratio: "% урађено" + field_auth_source: Режим потврде идентитета + field_hide_mail: Сакриј моју е-адресу + field_comments: Коментар + field_url: URL + field_start_page: Почетна страница + field_subproject: Потпројекат + field_hours: сати + field_activity: Активност + field_spent_on: Датум + field_identifier: Идентификатор + field_is_filter: Употреби као филтер + field_issue_to: Сродни проблеми + field_delay: Кашњење + field_assignable: Проблем може бити додељен овој улози + field_redirect_existing_links: Преусмери постојеће везе + field_estimated_hours: Протекло време + field_column_names: Колоне + field_time_zone: Временска зона + field_searchable: Може да се претражује + field_default_value: Подразумевана вредност + field_comments_sorting: Прикажи коментаре + field_parent_title: Матична страница + field_editable: Изменљиво + field_watcher: Посматрач + field_identity_url: OpenID URL + field_content: Садржај + field_group_by: Груписање резултата по + field_sharing: Дељење + field_parent_issue: Матични задатак + + setting_app_title: Наслов апликације + setting_app_subtitle: Поднаслов апликације + setting_welcome_text: Текст добродошлице + setting_default_language: Подразумевани језик + setting_login_required: Обавезна потврда идентитета + setting_self_registration: Саморегистрација + setting_attachment_max_size: Макс. величина приложене датотеке + setting_issues_export_limit: Ограничење извоза „проблема“ + setting_mail_from: Е-адреса пошиљаоца + setting_bcc_recipients: Примаоци „Bcc“ копије + setting_plain_text_mail: Порука са чистим текстом (без HTML-а) + setting_host_name: Путања и назив главног рачунара + setting_text_formatting: Обликовање текста + setting_wiki_compression: Компресија Wiki историје + setting_feeds_limit: Ограничење садржаја извора вести + setting_default_projects_public: Подразумева се јавно приказивање нових пројеката + setting_autofetch_changesets: Извршавање аутоматског преузимања + setting_sys_api_enabled: Омогућавање WS за управљање спремиштем + setting_commit_ref_keywords: Референцирање кључних речи + setting_commit_fix_keywords: Поправљање кључних речи + setting_autologin: Аутоматска пријава + setting_date_format: Формат датума + setting_time_format: Формат времена + setting_cross_project_issue_relations: Дозволи повезивање проблема из унакрсних пројеката + setting_issue_list_default_columns: Подразумеване колоне приказане на списку проблема + setting_emails_footer: Подножје странице е-поруке + setting_protocol: Протокол + setting_per_page_options: Опције приказа објеката по страници + setting_user_format: Формат приказа корисника + setting_activity_days_default: Број дана приказаних на пројектној активности + setting_display_subprojects_issues: Приказуј проблеме из потпројеката на главном пројекту, уколико није другачије наведено + setting_enabled_scm: Омогућавање SCM + setting_mail_handler_body_delimiters: "Скраћивање е-поруке након једне од ових линија" + setting_mail_handler_api_enabled: Омогућавање WS долазне е-поруке + setting_mail_handler_api_key: API кључ + setting_sequential_project_identifiers: Генерисање секвенцијалног имена пројекта + setting_gravatar_enabled: Користи Gravatar корисничке иконе + setting_gravatar_default: Подразумевана Gravatar слика + setting_diff_max_lines_displayed: Макс. број приказаних различитих линија + setting_file_max_size_displayed: Макс. величина текст. датотека приказаних уметнуто + setting_repository_log_display_limit: Макс. број ревизија приказаних у датотеци за евиденцију + setting_openid: Дозволи OpenID пријаву и регистрацију + setting_password_min_length: Минимална дужина лозинке + setting_new_project_user_role_id: Креатору пројекта (који није администратор) додељује је улога + setting_default_projects_modules: Подразумевано омогућени модули за нове пројекте + setting_issue_done_ratio: Израчунај однос решених проблема + setting_issue_done_ratio_issue_field: користећи поље проблема + setting_issue_done_ratio_issue_status: користећи статус проблема + setting_start_of_week: Први дан у седмици + setting_rest_api_enabled: Омогући REST web услуге + setting_cache_formatted_text: Кеширање обрађеног текста + + permission_add_project: Креирање пројекта + permission_add_subprojects: Креирање потпојекта + permission_edit_project: Измена пројеката + permission_select_project_modules: Одабирање модула пројекта + permission_manage_members: Управљање члановима + permission_manage_project_activities: Управљање пројектним активностима + permission_manage_versions: Управљање верзијама + permission_manage_categories: Управљање категоријама проблема + permission_view_issues: Преглед проблема + permission_add_issues: Додавање проблема + permission_edit_issues: Измена проблема + permission_manage_issue_relations: Управљање везама између проблема + permission_add_issue_notes: Додавање белешки + permission_edit_issue_notes: Измена белешки + permission_edit_own_issue_notes: Измена сопствених белешки + permission_move_issues: Померање проблема + permission_delete_issues: Брисање проблема + permission_manage_public_queries: Управљање јавним упитима + permission_save_queries: Снимање упита + permission_view_gantt: Прегледање Гантовог дијаграма + permission_view_calendar: Прегледање календара + permission_view_issue_watchers: Прегледање списка посматрача + permission_add_issue_watchers: Додавање посматрача + permission_delete_issue_watchers: Брисање посматрача + permission_log_time: Бележење утрошеног времена + permission_view_time_entries: Прегледање утрошеног времена + permission_edit_time_entries: Измена утрошеног времена + permission_edit_own_time_entries: Измена сопственог утрошеног времена + permission_manage_news: Управљање вестима + permission_comment_news: Коментарисање вести + permission_view_documents: Прегледање докумената + permission_manage_files: Управљање датотекама + permission_view_files: Прегледање датотека + permission_manage_wiki: Управљање wiki страницама + permission_rename_wiki_pages: Промена имена wiki страницама + permission_delete_wiki_pages: Брисање wiki страница + permission_view_wiki_pages: Прегледање wiki страница + permission_view_wiki_edits: Прегледање wiki историје + permission_edit_wiki_pages: Измена wiki страница + permission_delete_wiki_pages_attachments: Брисање приложених датотека + permission_protect_wiki_pages: Заштита wiki страница + permission_manage_repository: Управљање спремиштем + permission_browse_repository: Прегледање спремишта + permission_view_changesets: Прегледање скупа промена + permission_commit_access: Потврда приступа + permission_manage_boards: Управљање форумима + permission_view_messages: Прегледање порука + permission_add_messages: Слање порука + permission_edit_messages: Измена порука + permission_edit_own_messages: Измена сопствених порука + permission_delete_messages: Брисање порука + permission_delete_own_messages: Брисање сопствених порука + permission_export_wiki_pages: Извоз wiki страница + permission_manage_subtasks: Управљање подзадацима + + project_module_issue_tracking: Праћење проблема + project_module_time_tracking: Праћење времена + project_module_news: Вести + project_module_documents: Документи + project_module_files: Датотеке + project_module_wiki: Wiki + project_module_repository: Спремиште + project_module_boards: Форуми + + label_user: Корисник + label_user_plural: Корисници + label_user_new: Нови корисник + label_user_anonymous: Анониман + label_project: Пројекат + label_project_new: Нови пројекат + label_project_plural: Пројекти + label_x_projects: + zero: нема пројеката + one: један пројекат + other: "%{count} пројеката" + label_project_all: Сви пројекти + label_project_latest: Последњи пројекти + label_issue: Проблем + label_issue_new: Нови проблем + label_issue_plural: Проблеми + label_issue_view_all: Приказ свих проблема + label_issues_by: "Проблеми (%{value})" + label_issue_added: Проблем је додат + label_issue_updated: Проблем је ажуриран + label_document: Документ + label_document_new: Нови документ + label_document_plural: Документи + label_document_added: Документ је додат + label_role: Улога + label_role_plural: Улоге + label_role_new: Нова улога + label_role_and_permissions: Улоге и дозволе + label_member: Члан + label_member_new: Нови члан + label_member_plural: Чланови + label_tracker: Праћење + label_tracker_plural: Праћења + label_tracker_new: Ново праћење + label_workflow: Ток посла + label_issue_status: Статус проблема + label_issue_status_plural: Статуси проблема + label_issue_status_new: Нови статус + label_issue_category: Категорија проблема + label_issue_category_plural: Категорије проблема + label_issue_category_new: Нова категорија + label_custom_field: Прилагођено поље + label_custom_field_plural: Прилагођена поља + label_custom_field_new: Ново прилагођено поље + label_enumerations: Набројива листа + label_enumeration_new: Нова вредност + label_information: Информација + label_information_plural: Информације + label_please_login: Молимо, пријавите се + label_register: Регистрација + label_login_with_open_id_option: или пријава са OpenID + label_password_lost: Изгубљена лозинка + label_home: Почетак + label_my_page: Моја страница + label_my_account: Мој налог + label_my_projects: Моји пројекти + label_my_page_block: My page block + label_administration: Администрација + label_login: Пријава + label_logout: Одјава + label_help: Помоћ + label_reported_issues: Пријављени проблеми + label_assigned_to_me_issues: Проблеми додељени мени + label_last_login: Последње повезивање + label_registered_on: Регистрован + label_activity: Активност + label_overall_activity: Целокупна активност + label_user_activity: "Активност корисника %{value}" + label_new: Ново + label_logged_as: Пријављени сте као + label_environment: Окружење + label_authentication: Потврда идентитета + label_auth_source: Режим потврде идентитета + label_auth_source_new: Нови режим потврде идентитета + label_auth_source_plural: Режими потврде идентитета + label_subproject_plural: Потпројекти + label_subproject_new: Нови потпројекат + label_and_its_subprojects: "%{value} и његови потпројекти" + label_min_max_length: Мин. - Макс. дужина + label_list: Списак + label_date: Датум + label_integer: Цео број + label_float: Са покретним зарезом + label_boolean: Логички оператор + label_string: Текст + label_text: Дуги текст + label_attribute: Особина + label_attribute_plural: Особине + label_no_data: Нема података за приказивање + label_change_status: Промена статуса + label_history: Историја + label_attachment: Датотека + label_attachment_new: Нова датотека + label_attachment_delete: Брисање датотеке + label_attachment_plural: Датотеке + label_file_added: Датотека је додата + label_report: Извештај + label_report_plural: Извештаји + label_news: Вести + label_news_new: Додавање вести + label_news_plural: Вести + label_news_latest: Последње вести + label_news_view_all: Приказ свих вести + label_news_added: Вести су додате + label_settings: Подешавања + label_overview: Преглед + label_version: Верзија + label_version_new: Нова верзија + label_version_plural: Верзије + label_close_versions: Затвори завршене верзије + label_confirmation: Потврда + label_export_to: 'Такође доступно и у варијанти:' + label_read: Читање... + label_public_projects: Јавни пројекти + label_open_issues: отворен + label_open_issues_plural: отворених + label_closed_issues: затворен + label_closed_issues_plural: затворених + label_x_open_issues_abbr_on_total: + zero: 0 отворених / %{total} + one: 1 отворен / %{total} + other: "%{count} отворених / %{total}" + label_x_open_issues_abbr: + zero: 0 отворених + one: 1 отворен + other: "%{count} отворених" + label_x_closed_issues_abbr: + zero: 0 затворених + one: 1 затворен + other: "%{count} затворених" + label_total: Укупно + label_permissions: Дозволе + label_current_status: Тренутни статус + label_new_statuses_allowed: Нови статуси дозвољени + label_all: сви + label_none: ниједан + label_nobody: никоме + label_next: Следеће + label_previous: Претходно + label_used_by: Користио + label_details: Детаљи + label_add_note: Додај белешку + label_per_page: По страни + label_calendar: Календар + label_months_from: месеци од + label_gantt: Гантов дијаграм + label_internal: Унутрашњи + label_last_changes: "последњих %{count} промена" + label_change_view_all: Прикажи све промене + label_personalize_page: Персонализуј ову страну + label_comment: Коментар + label_comment_plural: Коментари + label_x_comments: + zero: без коментара + one: један коментар + other: "%{count} коментара" + label_comment_add: Додај коментар + label_comment_added: Коментар додат + label_comment_delete: Обриши коментаре + label_query: Прилагођен упит + label_query_plural: Прилагођени упити + label_query_new: Нови упит + label_filter_add: Додавање филтера + label_filter_plural: Филтери + label_equals: је + label_not_equals: није + label_in_less_than: мање од + label_in_more_than: више од + label_greater_or_equal: '>=' + label_less_or_equal: '<=' + label_in: у + label_today: данас + label_all_time: све време + label_yesterday: јуче + label_this_week: ове седмице + label_last_week: последње седмице + label_last_n_days: "последњих %{count} дана" + label_this_month: овог месеца + label_last_month: последњег месеца + label_this_year: ове године + label_date_range: Временски период + label_less_than_ago: пре мање од неколико дана + label_more_than_ago: пре више од неколико дана + label_ago: пре неколико дана + label_contains: садржи + label_not_contains: не садржи + label_day_plural: дана + label_repository: Спремиште + label_repository_plural: Спремишта + label_browse: Прегледање + label_branch: Грана + label_tag: Ознака + label_revision: Ревизија + label_revision_plural: Ревизије + label_revision_id: "Ревизија %{value}" + label_associated_revisions: Придружене ревизије + label_added: додато + label_modified: промењено + label_copied: копирано + label_renamed: преименовано + label_deleted: избрисано + label_latest_revision: Последња ревизија + label_latest_revision_plural: Последње ревизије + label_view_revisions: Преглед ревизија + label_view_all_revisions: Преглед свих ревизија + label_max_size: Максимална величина + label_sort_highest: Премештање на врх + label_sort_higher: Премештање на горе + label_sort_lower: Премештање на доле + label_sort_lowest: Премештање на дно + label_roadmap: План рада + label_roadmap_due_in: "Доспева %{value}" + label_roadmap_overdue: "%{value} најкасније" + label_roadmap_no_issues: Нема проблема за ову верзију + label_search: Претрага + label_result_plural: Резултати + label_all_words: Све речи + label_wiki: Wiki + label_wiki_edit: Wiki измена + label_wiki_edit_plural: Wiki измене + label_wiki_page: Wiki страница + label_wiki_page_plural: Wiki странице + label_index_by_title: Индексирање по наслову + label_index_by_date: Индексирање по датуму + label_current_version: Тренутна верзија + label_preview: Преглед + label_feed_plural: Извори вести + label_changes_details: Детаљи свих промена + label_issue_tracking: Праћење проблема + label_spent_time: Утрошено време + label_overall_spent_time: Целокупно утрошено време + label_f_hour: "%{value} сат" + label_f_hour_plural: "%{value} сати" + label_time_tracking: Праћење времена + label_change_plural: Промене + label_statistics: Статистика + label_commits_per_month: Извршења месечно + label_commits_per_author: Извршења по аутору + label_view_diff: Погледај разлике + label_diff_inline: унутра + label_diff_side_by_side: упоредо + label_options: Опције + label_copy_workflow_from: Копирање тока посла од + label_permissions_report: Извештај о дозволама + label_watched_issues: Посматрани проблеми + label_related_issues: Сродни проблеми + label_applied_status: Примењени статуси + label_loading: Учитавање... + label_relation_new: Нова релација + label_relation_delete: Брисање релације + label_relates_to: сродних са + label_duplicates: дуплираних + label_duplicated_by: дуплираних од + label_blocks: одбијених + label_blocked_by: одбијених од + label_precedes: претходи + label_follows: праћених + label_end_to_start: од краја до почетка + label_end_to_end: од краја до краја + label_start_to_start: од почетка до почетка + label_start_to_end: од почетка до краја + label_stay_logged_in: Останите пријављени + label_disabled: онемогућено + label_show_completed_versions: Приказивање завршене верзије + label_me: мени + label_board: Форум + label_board_new: Нови форум + label_board_plural: Форуми + label_board_locked: Закључана + label_board_sticky: Лепљива + label_topic_plural: Теме + label_message_plural: Поруке + label_message_last: Последња порука + label_message_new: Нова порука + label_message_posted: Порука је додата + label_reply_plural: Одговори + label_send_information: Пошаљи кориснику детаље налога + label_year: Година + label_month: Месец + label_week: Седмица + label_date_from: Шаље + label_date_to: Прима + label_language_based: Базирано на језику корисника + label_sort_by: "Сортирано по %{value}" + label_send_test_email: Слање пробне е-поруке + label_feeds_access_key: RSS приступни кључ + label_missing_feeds_access_key: RSS приступни кључ недостаје + label_feeds_access_key_created_on: "RSS приступни кључ је направљен пре %{value}" + label_module_plural: Модули + label_added_time_by: "Додао %{author} пре %{age}" + label_updated_time_by: "Ажурирао %{author} пре %{age}" + label_updated_time: "Ажурирано пре %{value}" + label_jump_to_a_project: Скок на пројекат... + label_file_plural: Датотеке + label_changeset_plural: Скупови промена + label_default_columns: Подразумеване колоне + label_no_change_option: (Без промена) + label_bulk_edit_selected_issues: Групна измена одабраних проблема + label_theme: Тема + label_default: Подразумевано + label_search_titles_only: Претражуј само наслове + label_user_mail_option_all: "За било који догађај на свим мојим пројектима" + label_user_mail_option_selected: "За било који догађај на само одабраним пројектима..." + label_user_mail_no_self_notified: "Не желим бити обавештаван за промене које сам правим" + label_registration_activation_by_email: активација налога путем е-поруке + label_registration_manual_activation: ручна активација налога + label_registration_automatic_activation: аутоматска активација налога + label_display_per_page: "Број ставки по страници: %{value}" + label_age: Старост + label_change_properties: Промени својства + label_general: Општи + label_more: Више + label_scm: SCM + label_plugins: Додатне компоненте + label_ldap_authentication: LDAP потврда идентитета + label_downloads_abbr: D/L + label_optional_description: Опционо опис + label_add_another_file: Додај још једну датотеку + label_preferences: Подешавања + label_chronological_order: по хронолошком редоследу + label_reverse_chronological_order: по обрнутом хронолошком редоследу + label_planning: Планирање + label_incoming_emails: Долазне е-поруке + label_generate_key: Генерисање кључа + label_issue_watchers: Посматрачи + label_example: Пример + label_display: Приказ + label_sort: Сортирање + label_ascending: Растући низ + label_descending: Опадајући низ + label_date_from_to: Од %{start} до %{end} + label_wiki_content_added: Wiki страница је додата + label_wiki_content_updated: Wiki страница је ажурирана + label_group: Група + label_group_plural: Групе + label_group_new: Нова група + label_time_entry_plural: Утрошено време + label_version_sharing_none: Није дељено + label_version_sharing_descendants: Са потпројектима + label_version_sharing_hierarchy: Са хијерархијом пројекта + label_version_sharing_tree: Са стаблом пројекта + label_version_sharing_system: Са свим пројектима + label_update_issue_done_ratios: Ажурирај однос решених проблема + label_copy_source: Извор + label_copy_target: Одредиште + label_copy_same_as_target: Исто као одредиште + label_display_used_statuses_only: Приказуј статусе коришћене само од стране овог праћења + label_api_access_key: API приступни кључ + label_missing_api_access_key: Недостаје API приступни кључ + label_api_access_key_created_on: "API приступни кључ је креиран пре %{value}" + label_profile: Профил + label_subtask_plural: Подзадатак + label_project_copy_notifications: Пошаљи е-поруку са обавештењем приликом копирања пројекта + + button_login: Пријава + button_submit: Пошаљи + button_save: Сними + button_check_all: Укључи све + button_uncheck_all: Искључи све + button_delete: Избриши + button_create: Креирај + button_create_and_continue: Креирај и настави + button_test: Тест + button_edit: Измени + button_add: Додај + button_change: Промени + button_apply: Примени + button_clear: Обриши + button_lock: Закључај + button_unlock: Откључај + button_download: Преузми + button_list: Списак + button_view: Прикажи + button_move: Помери + button_move_and_follow: Помери и прати + button_back: Назад + button_cancel: Поништи + button_activate: Активирај + button_sort: Сортирај + button_log_time: Евидентирај време + button_rollback: Повратак на ову верзију + button_watch: Прати + button_unwatch: Не прати више + button_reply: Одговори + button_archive: Архивирај + button_unarchive: Врати из архиве + button_reset: Поништи + button_rename: Преименуј + button_change_password: Промени лозинку + button_copy: Копирај + button_copy_and_follow: Копирај и прати + button_annotate: Прибележи + button_update: Ажурирај + button_configure: Подеси + button_quote: Под наводницима + button_duplicate: Дуплирај + button_show: Прикажи + + status_active: активни + status_registered: регистровани + status_locked: закључани + + version_status_open: отворен + version_status_locked: закључан + version_status_closed: затворен + + field_active: Активан + + text_select_mail_notifications: Одабери акције за које ће обавештење бити послато путем е-поште. + text_regexp_info: нпр. ^[A-Z0-9]+$ + text_min_max_length_info: 0 значи без ограничења + text_project_destroy_confirmation: Јесте ли сигурни да желите да избришете овај пројекат и све припадајуће податке? + text_subprojects_destroy_warning: "Потпројекти: %{value} ће такође бити избрисан." + text_workflow_edit: Одаберите улогу и праћење за измену тока посла + text_are_you_sure: Јесте ли сигурни? + text_journal_changed: "%{label} промењен од %{old} у %{new}" + text_journal_set_to: "%{label} постављен у %{value}" + text_journal_deleted: "%{label} избрисано (%{old})" + text_journal_added: "%{label} %{value} додато" + text_tip_issue_begin_day: задатак почиње овог дана + text_tip_issue_end_day: задатак се завршава овог дана + text_tip_issue_begin_end_day: задатак почиње и завршава овог дана + text_caracters_maximum: "Највише %{count} знак(ова)." + text_caracters_minimum: "Број знакова мора бити најмање %{count}." + text_length_between: "Број знакова мора бити између %{min} и %{max}." + text_tracker_no_workflow: Ово праћење нема дефинисан ток посла + text_unallowed_characters: Недозвољени знакови + text_comma_separated: Дозвољене су вишеструке вредности (одвојене зарезом). + text_line_separated: Дозвољене су вишеструке вредности (један ред за сваку вредност). + text_issues_ref_in_commit_messages: Референцирање и поправљање проблема у извршним порукама + text_issue_added: "%{author} је пријавио проблем %{id}." + text_issue_updated: "%{author} је ажурирао проблем %{id}." + text_wiki_destroy_confirmation: Јесте ли сигурни да желите да обришете wiki и сав садржај? + text_issue_category_destroy_question: "Неколико проблема (%{count}) је додељено овој категорији. Шта желите да урадите?" + text_issue_category_destroy_assignments: Уклони додељене категорије + text_issue_category_reassign_to: Додели поново проблеме овој категорији + text_user_mail_option: "За неизабране пројекте, добићете само обавештење о стварима које пратите или сте укључени (нпр. проблеми чији сте ви аутор или заступник)." + text_no_configuration_data: "Улоге, праћења, статуси проблема и тока посла још увек нису подешени.\nПрепоручљиво је да учитате подразумевано конфигурисање. Измена је могућа након првог учитавања." + text_load_default_configuration: Учитај подразумевано конфигурисање + text_status_changed_by_changeset: "Примењено у скупу са променама %{value}." + text_issues_destroy_confirmation: 'Јесте ли сигурни да желите да избришете одабране проблеме?' + text_select_project_modules: 'Одаберите модуле које желите омогућити за овај пројекат:' + text_default_administrator_account_changed: Подразумевани администраторски налог је промењен + text_file_repository_writable: Фасцикла приложених датотека је уписива + text_plugin_assets_writable: Фасцикла елемената додатних компоненти је уписива + text_rmagick_available: RMagick је доступан (опционо) + text_destroy_time_entries_question: "%{hours} сати је пријављено за овај проблем који желите избрисати. Шта желите да урадите?" + text_destroy_time_entries: Избриши пријављене сате + text_assign_time_entries_to_project: Додели пријављене сате пројекту + text_reassign_time_entries: 'Додели поново пријављене сате овом проблему:' + text_user_wrote: "%{value} је написао:" + text_enumeration_destroy_question: "%{count} објекат(а) је додељено овој вредности." + text_enumeration_category_reassign_to: 'Додели их поново овој вредности:' + text_email_delivery_not_configured: "Испорука е-порука није конфигурисана и обавештења су онемогућена.\nПодесите ваш SMTP сервер у config/configuration.yml и покрените поново апликацију за њихово омогућавање." + text_repository_usernames_mapping: "Одаберите или ажурирајте Redmine кориснике мапирањем сваког корисничког имена пронађеног у евиденцији спремишта.\nКорисници са истим Redmine именом и именом спремишта или е-адресом су аутоматски мапирани." + text_diff_truncated: '... Ова разлика је исечена јер је достигнута максимална величина приказа.' + text_custom_field_possible_values_info: 'Један ред за сваку вредност' + text_wiki_page_destroy_question: "Ова страница има %{descendants} подређених страница и подстраница. Шта желите да урадите?" + text_wiki_page_nullify_children: "Задржи подређене странице као корене странице" + text_wiki_page_destroy_children: "Избриши подређене странице и све њихове подстранице" + text_wiki_page_reassign_children: "Додели поново подређене странице овој матичној страници" + text_own_membership_delete_confirmation: "Након уклањања појединих или свих ваших дозвола нећете више моћи да уређујете овај пројекат.\nЖелите ли да наставите?" + text_zoom_in: Увећај + text_zoom_out: Умањи + + default_role_manager: Менаџер + default_role_developer: Програмер + default_role_reporter: Извештач + default_tracker_bug: Грешка + default_tracker_feature: Функционалност + default_tracker_support: Подршка + default_issue_status_new: Ново + default_issue_status_in_progress: У току + default_issue_status_resolved: Решено + default_issue_status_feedback: Повратна информација + default_issue_status_closed: Затворено + default_issue_status_rejected: Одбијено + default_doc_category_user: Корисничка документација + default_doc_category_tech: Техничка документација + default_priority_low: Низак + default_priority_normal: Нормалан + default_priority_high: Висок + default_priority_urgent: Хитно + default_priority_immediate: Непосредно + default_activity_design: Дизајн + default_activity_development: Развој + + enumeration_issue_priorities: Приоритети проблема + enumeration_doc_categories: Категорије документа + enumeration_activities: Активности (праћење времена) + enumeration_system_activity: Системска активност + + field_time_entries: Време евиденције + project_module_gantt: Гантов дијаграм + project_module_calendar: Календар + + button_edit_associated_wikipage: "Edit associated Wiki page: %{page_title}" + field_text: Text field + label_user_mail_option_only_owner: Only for things I am the owner of + setting_default_notification_option: Default notification option + label_user_mail_option_only_my_events: Only for things I watch or I'm involved in + label_user_mail_option_only_assigned: Only for things I am assigned to + label_user_mail_option_none: No events + field_member_of_group: Assignee's group + field_assigned_to_role: Assignee's role + notice_not_authorized_archived_project: The project you're trying to access has been archived. + label_principal_search: "Search for user or group:" + label_user_search: "Search for user:" + field_visible: Visible + setting_commit_logtime_activity_id: Activity for logged time + text_time_logged_by_changeset: Applied in changeset %{value}. + setting_commit_logtime_enabled: Enable time logging + notice_gantt_chart_truncated: The chart was truncated because it exceeds the maximum number of items that can be displayed (%{max}) + setting_gantt_items_limit: Maximum number of items displayed on the gantt chart + field_warn_on_leaving_unsaved: Warn me when leaving a page with unsaved text + text_warn_on_leaving_unsaved: The current page contains unsaved text that will be lost if you leave this page. + label_my_queries: My custom queries + text_journal_changed_no_detail: "%{label} updated" + label_news_comment_added: Comment added to a news + button_expand_all: Expand all + button_collapse_all: Collapse all + label_additional_workflow_transitions_for_assignee: Additional transitions allowed when the user is the assignee + label_additional_workflow_transitions_for_author: Additional transitions allowed when the user is the author + label_bulk_edit_selected_time_entries: Bulk edit selected time entries + text_time_entries_destroy_confirmation: Are you sure you want to delete the selected time entr(y/ies)? + label_role_anonymous: Anonymous + label_role_non_member: Non member + label_issue_note_added: Note added + label_issue_status_updated: Status updated + label_issue_priority_updated: Priority updated + label_issues_visibility_own: Issues created by or assigned to the user + field_issues_visibility: Issues visibility + label_issues_visibility_all: All issues + permission_set_own_issues_private: Set own issues public or private + field_is_private: Private + permission_set_issues_private: Set issues public or private + label_issues_visibility_public: All non private issues + text_issues_destroy_descendants_confirmation: This will also delete %{count} subtask(s). + field_commit_logs_encoding: Кодирање извршних порука + field_scm_path_encoding: Path encoding + text_scm_path_encoding_note: "Default: UTF-8" + field_path_to_repository: Path to repository + field_root_directory: Root directory + field_cvs_module: Module + field_cvsroot: CVSROOT + text_mercurial_repository_note: Local repository (e.g. /hgrepo, c:\hgrepo) + text_scm_command: Command + text_scm_command_version: Version + label_git_report_last_commit: Report last commit for files and directories + notice_issue_successful_create: Issue %{id} created. + label_between: between + setting_issue_group_assignment: Allow issue assignment to groups + label_diff: diff + text_git_repository_note: Repository is bare and local (e.g. /gitrepo, c:\gitrepo) + description_query_sort_criteria_direction: Sort direction + description_project_scope: Search scope + description_filter: Filter + description_user_mail_notification: Mail notification settings + description_date_from: Enter start date + description_message_content: Message content + description_available_columns: Available Columns + description_date_range_interval: Choose range by selecting start and end date + description_issue_category_reassign: Choose issue category + description_search: Searchfield + description_notes: Notes + description_date_range_list: Choose range from list + description_choose_project: Projects + description_date_to: Enter end date + description_query_sort_criteria_attribute: Sort attribute + description_wiki_subpages_reassign: Choose new parent page + description_selected_columns: Selected Columns + label_parent_revision: Parent + label_child_revision: Child + error_scm_annotate_big_text_file: The entry cannot be annotated, as it exceeds the maximum text file size. + setting_default_issue_start_date_to_creation_date: Use current date as start date for new issues + button_edit_section: Edit this section + setting_repositories_encodings: Attachments and repositories encodings + description_all_columns: All Columns + button_export: Export + label_export_options: "%{export_format} export options" + error_attachment_too_big: This file cannot be uploaded because it exceeds the maximum allowed file size (%{max_size}) + notice_failed_to_save_time_entries: "Failed to save %{count} time entrie(s) on %{total} selected: %{ids}." + label_x_issues: + zero: 0 Проблем + one: 1 Проблем + other: "%{count} Проблеми" + label_repository_new: New repository + field_repository_is_default: Main repository + label_copy_attachments: Copy attachments + label_item_position: "%{position}/%{count}" + label_completed_versions: Completed versions + text_project_identifier_info: Only lower case letters (a-z), numbers, dashes and underscores are allowed.
    Once saved, the identifier cannot be changed. + field_multiple: Multiple values + setting_commit_cross_project_ref: Allow issues of all the other projects to be referenced and fixed + text_issue_conflict_resolution_add_notes: Add my notes and discard my other changes + text_issue_conflict_resolution_overwrite: Apply my changes anyway (previous notes will be kept but some changes may be overwritten) + notice_issue_update_conflict: The issue has been updated by an other user while you were editing it. + text_issue_conflict_resolution_cancel: Discard all my changes and redisplay %{link} + permission_manage_related_issues: Manage related issues + field_auth_source_ldap_filter: LDAP filter + label_search_for_watchers: Search for watchers to add + notice_account_deleted: Your account has been permanently deleted. + setting_unsubscribe: Allow users to delete their own account + button_delete_my_account: Delete my account + text_account_destroy_confirmation: |- + Are you sure you want to proceed? + Your account will be permanently deleted, with no way to reactivate it. + error_session_expired: Your session has expired. Please login again. + text_session_expiration_settings: "Warning: changing these settings may expire the current sessions including yours." + setting_session_lifetime: Session maximum lifetime + setting_session_timeout: Session inactivity timeout + label_session_expiration: Session expiration + permission_close_project: Close / reopen the project + label_show_closed_projects: View closed projects + button_close: Close + button_reopen: Reopen + project_status_active: active + project_status_closed: closed + project_status_archived: archived + text_project_closed: This project is closed and read-only. + notice_user_successful_create: User %{id} created. + field_core_fields: Standard fields + field_timeout: Timeout (in seconds) + setting_thumbnails_enabled: Display attachment thumbnails + setting_thumbnails_size: Thumbnails size (in pixels) + label_status_transitions: Status transitions + label_fields_permissions: Fields permissions + label_readonly: Read-only + label_required: Required + text_repository_identifier_info: Only lower case letters (a-z), numbers, dashes and underscores are allowed.
    Once saved, the identifier cannot be changed. + field_board_parent: Parent forum + label_attribute_of_project: Project's %{name} + label_attribute_of_author: Author's %{name} + label_attribute_of_assigned_to: Assignee's %{name} + label_attribute_of_fixed_version: Target version's %{name} + label_copy_subtasks: Copy subtasks + label_copied_to: copied to + label_copied_from: copied from + label_any_issues_in_project: any issues in project + label_any_issues_not_in_project: any issues not in project + field_private_notes: Private notes + permission_view_private_notes: View private notes + permission_set_notes_private: Set notes as private + label_no_issues_in_project: no issues in project + label_any: сви + label_last_n_weeks: last %{count} weeks + setting_cross_project_subtasks: Allow cross-project subtasks + label_cross_project_descendants: Са потпројектима + label_cross_project_tree: Са стаблом пројекта + label_cross_project_hierarchy: Са хијерархијом пројекта + label_cross_project_system: Са свим пројектима + button_hide: Hide + setting_non_working_week_days: Non-working days + label_in_the_next_days: in the next + label_in_the_past_days: in the past + label_attribute_of_user: User's %{name} + text_turning_multiple_off: If you disable multiple values, multiple values will be + removed in order to preserve only one value per item. + label_attribute_of_issue: Issue's %{name} + permission_add_documents: Add documents + permission_edit_documents: Edit documents + permission_delete_documents: Delete documents + label_gantt_progress_line: Progress line + setting_jsonp_enabled: Enable JSONP support + field_inherit_members: Inherit members + field_closed_on: Closed + setting_default_projects_tracker_ids: Default trackers for new projects + label_total_time: Укупно + text_scm_config: You can configure your SCM commands in config/configuration.yml. Please restart the application after editing it. + text_scm_command_not_available: SCM command is not available. Please check settings on the administration panel. + setting_emails_header: Email header diff --git a/config/locales/sv.yml b/config/locales/sv.yml new file mode 100644 index 00000000..b44b566b --- /dev/null +++ b/config/locales/sv.yml @@ -0,0 +1,1127 @@ +# Swedish translation for Ruby on Rails +# by Johan Lundström (johanlunds@gmail.com), +# with parts taken from http://github.com/daniel/swe_rails + +sv: + number: + # Used in number_with_delimiter() + # These are also the defaults for 'currency', 'percentage', 'precision', and 'human' + format: + # Sets the separator between the units, for more precision (e.g. 1.0 / 2.0 == 0.5) + separator: "," + # Delimets thousands (e.g. 1,000,000 is a million) (always in groups of three) + delimiter: "." + # Number of decimals, behind the separator (the number 1 with a precision of 2 gives: 1.00) + precision: 2 + + # Used in number_to_currency() + currency: + format: + # Where is the currency sign? %u is the currency unit, %n the number (default: $5.00) + format: "%n %u" + unit: "kr" + # These three are to override number.format and are optional + # separator: "." + # delimiter: "," + # precision: 2 + + # Used in number_to_percentage() + percentage: + format: + # These three are to override number.format and are optional + # separator: + delimiter: "" + # precision: + + # Used in number_to_precision() + precision: + format: + # These three are to override number.format and are optional + # separator: + delimiter: "" + # precision: + + # Used in number_to_human_size() + human: + format: + # These three are to override number.format and are optional + # separator: + delimiter: "" + precision: 3 + storage_units: + format: "%n %u" + units: + byte: + one: "Byte" + other: "Bytes" + kb: "KB" + mb: "MB" + gb: "GB" + tb: "TB" + + # Used in distance_of_time_in_words(), distance_of_time_in_words_to_now(), time_ago_in_words() + datetime: + distance_in_words: + half_a_minute: "en halv minut" + less_than_x_seconds: + one: "mindre än en sekund" + other: "mindre än %{count} sekunder" + x_seconds: + one: "en sekund" + other: "%{count} sekunder" + less_than_x_minutes: + one: "mindre än en minut" + other: "mindre än %{count} minuter" + x_minutes: + one: "en minut" + other: "%{count} minuter" + about_x_hours: + one: "ungefär en timme" + other: "ungefär %{count} timmar" + x_hours: + one: "1 timme" + other: "%{count} timmar" + x_days: + one: "en dag" + other: "%{count} dagar" + about_x_months: + one: "ungefär en månad" + other: "ungefär %{count} månader" + x_months: + one: "en månad" + other: "%{count} månader" + about_x_years: + one: "ungefär ett år" + other: "ungefär %{count} år" + over_x_years: + one: "mer än ett år" + other: "mer än %{count} år" + almost_x_years: + one: "nästan 1 år" + other: "nästan %{count} år" + + activerecord: + errors: + template: + header: + one: "Ett fel förhindrade denna %{model} från att sparas" + other: "%{count} fel förhindrade denna %{model} från att sparas" + # The variable :count is also available + body: "Det var problem med följande fält:" + # The values :model, :attribute and :value are always available for interpolation + # The value :count is available when applicable. Can be used for pluralization. + messages: + inclusion: "finns inte i listan" + exclusion: "är reserverat" + invalid: "är ogiltigt" + confirmation: "stämmer inte överens" + accepted : "måste vara accepterad" + empty: "får ej vara tom" + blank: "måste anges" + too_long: "är för lång (maximum är %{count} tecken)" + too_short: "är för kort (minimum är %{count} tecken)" + wrong_length: "har fel längd (ska vara %{count} tecken)" + taken: "har redan tagits" + not_a_number: "är inte ett nummer" + greater_than: "måste vara större än %{count}" + greater_than_or_equal_to: "måste vara större än eller lika med %{count}" + equal_to: "måste vara samma som" + less_than: "måste vara mindre än %{count}" + less_than_or_equal_to: "måste vara mindre än eller lika med %{count}" + odd: "måste vara udda" + even: "måste vara jämnt" + greater_than_start_date: "måste vara senare än startdatumet" + not_same_project: "tillhör inte samma projekt" + circular_dependency: "Denna relation skulle skapa ett cirkulärt beroende" + cant_link_an_issue_with_a_descendant: "Ett ärende kan inte länkas till ett av dess underärenden" + + direction: ltr + date: + formats: + # Use the strftime parameters for formats. + # When no format has been given, it uses default. + # You can provide other formats here if you like! + default: "%Y-%m-%d" + short: "%e %b" + long: "%e %B, %Y" + + day_names: [söndag, måndag, tisdag, onsdag, torsdag, fredag, lördag] + abbr_day_names: [sön, mån, tis, ons, tor, fre, lör] + + # Don't forget the nil at the beginning; there's no such thing as a 0th month + month_names: [~, januari, februari, mars, april, maj, juni, juli, augusti, september, oktober, november, december] + abbr_month_names: [~, jan, feb, mar, apr, maj, jun, jul, aug, sep, okt, nov, dec] + # Used in date_select and datime_select. + order: + - :day + - :month + - :year + + time: + formats: + default: "%Y-%m-%d %H:%M" + time: "%H:%M" + short: "%d %b %H:%M" + long: "%d %B, %Y %H:%M" + am: "" + pm: "" + +# Used in array.to_sentence. + support: + array: + sentence_connector: "och" + skip_last_comma: true + + actionview_instancetag_blank_option: Var god välj + + general_text_No: 'Nej' + general_text_Yes: 'Ja' + general_text_no: 'nej' + general_text_yes: 'ja' + general_lang_name: 'Svenska' + general_csv_separator: ',' + general_csv_decimal_separator: '.' + general_csv_encoding: ISO-8859-1 + general_pdf_encoding: UTF-8 + general_first_day_of_week: '1' + + notice_account_updated: Kontot har uppdaterats + notice_account_invalid_creditentials: Fel användarnamn eller lösenord + notice_account_password_updated: Lösenordet har uppdaterats + notice_account_wrong_password: Fel lösenord + notice_account_register_done: Kontot har skapats. För att aktivera kontot, klicka på länken i mailet som skickades till dig. + notice_account_unknown_email: Okänd användare. + notice_can_t_change_password: Detta konto använder en extern autentiseringskälla. Det går inte att byta lösenord. + notice_account_lost_email_sent: Ett mail med instruktioner om hur man väljer ett nytt lösenord har skickats till dig. + notice_account_activated: Ditt konto har blivit aktiverat. Du kan nu logga in. + notice_successful_create: Skapades korrekt. + notice_successful_update: Uppdatering lyckades. + notice_successful_delete: Borttagning lyckades. + notice_successful_connection: Uppkoppling lyckades. + notice_file_not_found: Sidan du försökte komma åt existerar inte eller är borttagen. + notice_locking_conflict: Data har uppdaterats av en annan användare. + notice_not_authorized: Du saknar behörighet att komma åt den här sidan. + notice_not_authorized_archived_project: Projektet du försöker komma åt har arkiverats. + notice_email_sent: "Ett mail skickades till %{value}" + notice_email_error: "Ett fel inträffade när mail skickades (%{value})" + notice_feeds_access_key_reseted: Din RSS-nyckel återställdes. + notice_api_access_key_reseted: Din API-nyckel återställdes. + notice_failed_to_save_issues: "Misslyckades med att spara %{count} ärende(n) på %{total} valda: %{ids}." + notice_failed_to_save_time_entries: "Misslyckades med att spara %{count} tidloggning(ar) på %{total} valda: %{ids}." + notice_failed_to_save_members: "Misslyckades med att spara medlem(mar): %{errors}." + notice_no_issue_selected: "Inget ärende är markerat! Var vänlig, markera de ärenden du vill ändra." + notice_account_pending: "Ditt konto skapades och avvaktar nu administratörens godkännande." + notice_default_data_loaded: Standardkonfiguration inläst. + notice_unable_delete_version: Denna version var inte möjlig att ta bort. + notice_unable_delete_time_entry: Tidloggning kunde inte tas bort. + notice_issue_done_ratios_updated: "% klart uppdaterade." + notice_gantt_chart_truncated: "Schemat förminskades eftersom det överskrider det maximala antalet aktiviteter som kan visas (%{max})" + notice_issue_successful_create: "Ärende %{id} skapades." + notice_issue_update_conflict: "Detta ärende har uppdaterats av en annan användare samtidigt som du redigerade det." + notice_account_deleted: "Ditt konto har avslutats permanent." + notice_user_successful_create: "Användare %{id} skapad." + + error_can_t_load_default_data: "Standardkonfiguration gick inte att läsa in: %{value}" + error_scm_not_found: "Inlägg och/eller revision finns inte i detta versionsarkiv." + error_scm_command_failed: "Ett fel inträffade vid försök att nå versionsarkivet: %{value}" + error_scm_annotate: "Inlägget existerar inte eller kan inte kommenteras." + error_scm_annotate_big_text_file: Inlägget kan inte annoteras eftersom det överskrider maximal storlek för textfiler. + error_issue_not_found_in_project: 'Ärendet hittades inte eller så tillhör det inte detta projekt' + error_no_tracker_in_project: 'Ingen ärendetyp är associerad med projektet. Vänligen kontrollera projektinställningarna.' + error_no_default_issue_status: 'Ingen status är definierad som standard för nya ärenden. Vänligen kontrollera din konfiguration (Gå till "Administration -> Ärendestatus").' + error_can_not_delete_custom_field: Kan inte ta bort användardefinerat fält + error_can_not_delete_tracker: "Det finns ärenden av denna typ och den är därför inte möjlig att ta bort." + error_can_not_remove_role: "Denna roll används och den är därför inte möjlig att ta bort." + error_can_not_reopen_issue_on_closed_version: 'Ett ärende tilldelat en stängd version kan inte öppnas på nytt' + error_can_not_archive_project: Detta projekt kan inte arkiveras + error_issue_done_ratios_not_updated: "% klart inte uppdaterade." + error_workflow_copy_source: 'Vänligen välj källans ärendetyp eller roll' + error_workflow_copy_target: 'Vänligen välj ärendetyp(er) och roll(er) för mål' + error_unable_delete_issue_status: 'Ärendestatus kunde inte tas bort' + error_unable_to_connect: "Kan inte ansluta (%{value})" + error_attachment_too_big: "Denna fil kan inte laddas upp eftersom den överstiger maximalt tillåten filstorlek (%{max_size})" + error_session_expired: "Din session har gått ut. Vänligen logga in på nytt." + warning_attachments_not_saved: "%{count} fil(er) kunde inte sparas." + + mail_subject_lost_password: "Ditt %{value} lösenord" + mail_body_lost_password: 'För att ändra ditt lösenord, klicka på följande länk:' + mail_subject_register: "Din %{value} kontoaktivering" + mail_body_register: 'För att aktivera ditt konto, klicka på följande länk:' + mail_body_account_information_external: "Du kan använda ditt %{value}-konto för att logga in." + mail_body_account_information: Din kontoinformation + mail_subject_account_activation_request: "%{value} begäran om kontoaktivering" + mail_body_account_activation_request: "En ny användare (%{value}) har registrerat sig och avvaktar ditt godkännande:" + mail_subject_reminder: "%{count} ärende(n) har deadline under de kommande %{days} dagarna" + mail_body_reminder: "%{count} ärende(n) som är tilldelat dig har deadline under de %{days} dagarna:" + mail_subject_wiki_content_added: "'%{id}' wikisida has lagts till" + mail_body_wiki_content_added: "The '%{id}' wikisida has lagts till av %{author}." + mail_subject_wiki_content_updated: "'%{id}' wikisida har uppdaterats" + mail_body_wiki_content_updated: "The '%{id}' wikisida har uppdaterats av %{author}." + + + field_name: Namn + field_description: Beskrivning + field_summary: Sammanfattning + field_is_required: Obligatorisk + field_firstname: Förnamn + field_lastname: Efternamn + field_mail: Mail + field_filename: Fil + field_filesize: Storlek + field_downloads: Nerladdningar + field_author: Författare + field_created_on: Skapad + field_updated_on: Uppdaterad + field_field_format: Format + field_is_for_all: För alla projekt + field_possible_values: Möjliga värden + field_regexp: Reguljärt uttryck + field_min_length: Minimilängd + field_max_length: Maxlängd + field_value: Värde + field_category: Kategori + field_title: Titel + field_project: Projekt + field_issue: Ärende + field_status: Status + field_notes: Anteckningar + field_is_closed: Ärendet är stängt + field_is_default: Standardvärde + field_tracker: Ärendetyp + field_subject: Ämne + field_due_date: Deadline + field_assigned_to: Tilldelad till + field_priority: Prioritet + field_fixed_version: Versionsmål + field_user: Användare + field_principal: Principal + field_role: Roll + field_homepage: Hemsida + field_is_public: Publik + field_parent: Underprojekt till + field_is_in_roadmap: Visa ärenden i roadmap + field_login: Användarnamn + field_mail_notification: Mailnotifieringar + field_admin: Administratör + field_last_login_on: Senaste inloggning + field_language: Språk + field_effective_date: Datum + field_password: Lösenord + field_new_password: Nytt lösenord + field_password_confirmation: Bekräfta lösenord + field_version: Version + field_type: Typ + field_host: Värddator + field_port: Port + field_account: Konto + field_base_dn: Bas-DN + field_attr_login: Inloggningsattribut + field_attr_firstname: Förnamnsattribut + field_attr_lastname: Efternamnsattribut + field_attr_mail: Mailattribut + field_onthefly: Skapa användare on-the-fly + field_start_date: Startdatum + field_done_ratio: "% Klart" + field_auth_source: Autentiseringsläge + field_hide_mail: Dölj min mailadress + field_comments: Kommentar + field_url: URL + field_start_page: Startsida + field_subproject: Underprojekt + field_hours: Timmar + field_activity: Aktivitet + field_spent_on: Datum + field_identifier: Identifierare + field_is_filter: Använd som filter + field_issue_to: Relaterade ärenden + field_delay: Fördröjning + field_assignable: Ärenden kan tilldelas denna roll + field_redirect_existing_links: Omdirigera existerande länkar + field_estimated_hours: Estimerad tid + field_column_names: Kolumner + field_time_entries: Spenderad tid + field_time_zone: Tidszon + field_searchable: Sökbar + field_default_value: Standardvärde + field_comments_sorting: Visa kommentarer + field_parent_title: Föräldersida + field_editable: Redigerbar + field_watcher: Bevakare + field_identity_url: OpenID URL + field_content: Innehåll + field_group_by: Gruppera resultat efter + field_sharing: Delning + field_parent_issue: Förälderaktivitet + field_member_of_group: "Tilldelad användares grupp" + field_assigned_to_role: "Tilldelad användares roll" + field_text: Textfält + field_visible: Synlig + field_warn_on_leaving_unsaved: Varna om jag lämnar en sida med osparad text + field_issues_visibility: Ärendesynlighet + field_is_private: Privat + field_commit_logs_encoding: Teckenuppsättning för commit-meddelanden + field_scm_path_encoding: Sökvägskodning + field_path_to_repository: Sökväg till versionsarkiv + field_root_directory: Rotmapp + field_cvsroot: CVSROOT + field_cvs_module: Modul + field_repository_is_default: Huvudarkiv + field_multiple: Flera värden + field_auth_source_ldap_filter: LDAP-filter + field_core_fields: Standardfält + field_timeout: "Timeout (i sekunder)" + field_board_parent: Förälderforum + field_private_notes: Privata anteckningar + + setting_app_title: Applikationsrubrik + setting_app_subtitle: Applikationsunderrubrik + setting_welcome_text: Välkomsttext + setting_default_language: Standardspråk + setting_login_required: Kräver inloggning + setting_self_registration: Självregistrering + setting_attachment_max_size: Maxstorlek på bilaga + setting_issues_export_limit: Exportgräns för ärenden + setting_mail_from: Avsändaradress + setting_bcc_recipients: Hemlig kopia (bcc) till mottagare + setting_plain_text_mail: Oformaterad text i mail (ingen HTML) + setting_host_name: Värddatornamn + setting_text_formatting: Textformatering + setting_wiki_compression: Komprimering av wikihistorik + setting_feeds_limit: Innehållsgräns för Feed + setting_default_projects_public: Nya projekt är publika + setting_autofetch_changesets: Automatisk hämtning av commits + setting_sys_api_enabled: Aktivera WS för versionsarkivhantering + setting_commit_ref_keywords: Referens-nyckelord + setting_commit_fix_keywords: Fix-nyckelord + setting_autologin: Automatisk inloggning + setting_date_format: Datumformat + setting_time_format: Tidsformat + setting_cross_project_subtasks: Tillåt underaktiviteter mellan projekt + setting_cross_project_issue_relations: Tillåt ärenderelationer mellan projekt + setting_issue_list_default_columns: Standardkolumner i ärendelistan + setting_repositories_encodings: Encoding för bilagor och versionsarkiv + setting_emails_header: Mail-header + setting_emails_footer: Signatur + setting_protocol: Protokoll + setting_per_page_options: Alternativ, objekt per sida + setting_user_format: Visningsformat för användare + setting_activity_days_default: Dagar som visas på projektaktivitet + setting_display_subprojects_issues: Visa ärenden från underprojekt i huvudprojekt + setting_enabled_scm: Aktivera SCM + setting_mail_handler_body_delimiters: "Trunkera mail efter en av följande rader" + setting_mail_handler_api_enabled: Aktivera WS för inkommande mail + setting_mail_handler_api_key: API-nyckel + setting_sequential_project_identifiers: Generera projektidentifierare sekventiellt + setting_gravatar_enabled: Använd Gravatar-avatarer + setting_gravatar_default: Förvald Gravatar-bild + setting_diff_max_lines_displayed: Maximalt antal synliga rader i diff + setting_file_max_size_displayed: Maxstorlek på textfiler som visas inline + setting_repository_log_display_limit: Maximalt antal revisioner i filloggen + setting_openid: Tillåt inloggning och registrering med OpenID + setting_password_min_length: Minsta tillåtna lösenordslängd + setting_new_project_user_role_id: Tilldelad roll för en icke-administratör som skapar ett projekt + setting_default_projects_modules: Aktiverade moduler för nya projekt + setting_issue_done_ratio: Beräkna % klart med + setting_issue_done_ratio_issue_field: Använd ärendefältet + setting_issue_done_ratio_issue_status: Använd ärendestatus + setting_start_of_week: Första dagen i veckan + setting_rest_api_enabled: Aktivera REST webbtjänst + setting_cache_formatted_text: Cacha formaterad text + setting_default_notification_option: Standard notifieringsalternativ + setting_commit_logtime_enabled: Aktivera tidloggning + setting_commit_logtime_activity_id: Aktivitet för loggad tid + setting_gantt_items_limit: Maximalt antal aktiviteter som visas i gantt-schemat + setting_issue_group_assignment: Tillåt att ärenden tilldelas till grupper + setting_default_issue_start_date_to_creation_date: Använd dagens datum som startdatum för nya ärenden + setting_commit_cross_project_ref: Tillåt ärende i alla de andra projekten att bli refererade och fixade + setting_unsubscribe: Tillåt användare att avsluta prenumereration + setting_session_lifetime: Maximal sessionslivslängd + setting_session_timeout: Tidsgräns för sessionsinaktivitet + setting_thumbnails_enabled: Visa miniatyrbilder av bilagor + setting_thumbnails_size: Storlek på miniatyrbilder (i pixlar) + setting_non_working_week_days: Lediga dagar + + permission_add_project: Skapa projekt + permission_add_subprojects: Skapa underprojekt + permission_edit_project: Ändra projekt + permission_close_project: Stänga / återöppna projektet + permission_select_project_modules: Välja projektmoduler + permission_manage_members: Hantera medlemmar + permission_manage_project_activities: Hantera projektaktiviteter + permission_manage_versions: Hantera versioner + permission_manage_categories: Hantera ärendekategorier + permission_add_issues: Lägga till ärenden + permission_edit_issues: Ändra ärenden + permission_view_issues: Visa ärenden + permission_manage_issue_relations: Hantera ärenderelationer + permission_set_issues_private: Sätta ärenden publika eller privata + permission_set_own_issues_private: Sätta egna ärenden publika eller privata + permission_add_issue_notes: Lägga till ärendeanteckning + permission_edit_issue_notes: Ändra ärendeanteckningar + permission_edit_own_issue_notes: Ändra egna ärendeanteckningar + permission_view_private_notes: Visa privata anteckningar + permission_set_notes_private: Ställa in anteckningar som privata + permission_move_issues: Flytta ärenden + permission_delete_issues: Ta bort ärenden + permission_manage_public_queries: Hantera publika frågor + permission_save_queries: Spara frågor + permission_view_gantt: Visa Gantt-schema + permission_view_calendar: Visa kalender + permission_view_issue_watchers: Visa bevakarlista + permission_add_issue_watchers: Lägga till bevakare + permission_delete_issue_watchers: Ta bort bevakare + permission_log_time: Logga spenderad tid + permission_view_time_entries: Visa spenderad tid + permission_edit_time_entries: Ändra tidloggningar + permission_edit_own_time_entries: Ändra egna tidloggningar + permission_manage_news: Hantera nyheter + permission_comment_news: Kommentera nyheter + permission_view_documents: Visa dokument + permission_add_documents: Lägga till dokument + permission_edit_documents: Ändra dokument + permission_delete_documents: Ta bort dokument + permission_manage_files: Hantera filer + permission_view_files: Visa filer + permission_manage_wiki: Hantera wiki + permission_rename_wiki_pages: Byta namn på wikisidor + permission_delete_wiki_pages: Ta bort wikisidor + permission_view_wiki_pages: Visa wiki + permission_view_wiki_edits: Visa wikihistorik + permission_edit_wiki_pages: Ändra wikisidor + permission_delete_wiki_pages_attachments: Ta bort bilagor + permission_protect_wiki_pages: Skydda wikisidor + permission_manage_repository: Hantera versionsarkiv + permission_browse_repository: Bläddra i versionsarkiv + permission_view_changesets: Visa changesets + permission_commit_access: Commit-åtkomst + permission_manage_boards: Hantera forum + permission_view_messages: Visa meddelanden + permission_add_messages: Lägg till meddelanden + permission_edit_messages: Ändra meddelanden + permission_edit_own_messages: Ändra egna meddelanden + permission_delete_messages: Ta bort meddelanden + permission_delete_own_messages: Ta bort egna meddelanden + permission_export_wiki_pages: Exportera wikisidor + permission_manage_subtasks: Hantera underaktiviteter + permission_manage_related_issues: Hantera relaterade ärenden + + project_module_issue_tracking: Ärendeuppföljning + project_module_time_tracking: Tidsuppföljning + project_module_news: Nyheter + project_module_documents: Dokument + project_module_files: Filer + project_module_wiki: Wiki + project_module_repository: Versionsarkiv + project_module_boards: Forum + project_module_calendar: Kalender + project_module_gantt: Gantt + + label_user: Användare + label_user_plural: Användare + label_user_new: Ny användare + label_user_anonymous: Anonym + label_project: Projekt + label_project_new: Nytt projekt + label_project_plural: Projekt + label_x_projects: + zero: inga projekt + one: 1 projekt + other: "%{count} projekt" + label_project_all: Alla projekt + label_project_latest: Senaste projekt + label_issue: Ärende + label_issue_new: Nytt ärende + label_issue_plural: Ärenden + label_issue_view_all: Visa alla ärenden + label_issues_by: "Ärenden %{value}" + label_issue_added: Ärende tillagt + label_issue_updated: Ärende uppdaterat + label_issue_note_added: Anteckning tillagd + label_issue_status_updated: Status uppdaterad + label_issue_priority_updated: Prioritet uppdaterad + label_document: Dokument + label_document_new: Nytt dokument + label_document_plural: Dokument + label_document_added: Dokument tillagt + label_role: Roll + label_role_plural: Roller + label_role_new: Ny roll + label_role_and_permissions: Roller och behörigheter + label_role_anonymous: Anonym + label_role_non_member: Icke-medlem + label_member: Medlem + label_member_new: Ny medlem + label_member_plural: Medlemmar + label_tracker: Ärendetyp + label_tracker_plural: Ärendetyper + label_tracker_new: Ny ärendetyp + label_workflow: Arbetsflöde + label_issue_status: Ärendestatus + label_issue_status_plural: Ärendestatus + label_issue_status_new: Ny status + label_issue_category: Ärendekategori + label_issue_category_plural: Ärendekategorier + label_issue_category_new: Ny kategori + label_custom_field: Användardefinerat fält + label_custom_field_plural: Användardefinerade fält + label_custom_field_new: Nytt användardefinerat fält + label_enumerations: Uppräkningar + label_enumeration_new: Nytt värde + label_information: Information + label_information_plural: Information + label_please_login: Var god logga in + label_register: Registrera + label_login_with_open_id_option: eller logga in med OpenID + label_password_lost: Glömt lösenord + label_home: Hem + label_my_page: Min sida + label_my_account: Mitt konto + label_my_projects: Mina projekt + label_my_page_block: '"Min sida"-block' + label_administration: Administration + label_login: Logga in + label_logout: Logga ut + label_help: Hjälp + label_reported_issues: Rapporterade ärenden + label_assigned_to_me_issues: Ärenden tilldelade till mig + label_last_login: Senaste inloggning + label_registered_on: Registrerad + label_activity: Aktivitet + label_overall_activity: All aktivitet + label_user_activity: "Aktiviteter för %{value}" + label_new: Ny + label_logged_as: Inloggad som + label_environment: Miljö + label_authentication: Autentisering + label_auth_source: Autentiseringsläge + label_auth_source_new: Nytt autentiseringsläge + label_auth_source_plural: Autentiseringslägen + label_subproject_plural: Underprojekt + label_subproject_new: Nytt underprojekt + label_and_its_subprojects: "%{value} och dess underprojekt" + label_min_max_length: Min./Max.-längd + label_list: Lista + label_date: Datum + label_integer: Heltal + label_float: Flyttal + label_boolean: Boolean + label_string: Text + label_text: Lång text + label_attribute: Attribut + label_attribute_plural: Attribut + label_no_data: Ingen data att visa + label_change_status: Ändra status + label_history: Historia + label_attachment: Fil + label_attachment_new: Ny fil + label_attachment_delete: Ta bort fil + label_attachment_plural: Filer + label_file_added: Fil tillagd + label_report: Rapport + label_report_plural: Rapporter + label_news: Nyhet + label_news_new: Lägg till nyhet + label_news_plural: Nyheter + label_news_latest: Senaste nyheterna + label_news_view_all: Visa alla nyheter + label_news_added: Nyhet tillagd + label_news_comment_added: Kommentar tillagd till en nyhet + label_settings: Inställningar + label_overview: Översikt + label_version: Version + label_version_new: Ny version + label_version_plural: Versioner + label_close_versions: Stäng klara versioner + label_confirmation: Bekräftelse + label_export_to: 'Finns även som:' + label_read: Läs... + label_public_projects: Publika projekt + label_open_issues: öppen + label_open_issues_plural: öppna + label_closed_issues: stängd + label_closed_issues_plural: stängda + label_x_open_issues_abbr_on_total: + zero: 0 öppna av %{total} + one: 1 öppen av %{total} + other: "%{count} öppna av %{total}" + label_x_open_issues_abbr: + zero: 0 öppna + one: 1 öppen + other: "%{count} öppna" + label_x_closed_issues_abbr: + zero: 0 stängda + one: 1 stängd + other: "%{count} stängda" + label_x_issues: + zero: 0 ärenden + one: 1 ärende + other: "%{count} ärenden" + label_total: Total + label_permissions: Behörigheter + label_current_status: Nuvarande status + label_new_statuses_allowed: Nya tillåtna statusvärden + label_all: alla + label_any: vad/vem som helst + label_none: inget/ingen + label_nobody: ingen + label_next: Nästa + label_previous: Föregående + label_used_by: Använd av + label_details: Detaljer + label_add_note: Lägg till anteckning + label_per_page: Per sida + label_calendar: Kalender + label_months_from: månader från + label_gantt: Gantt + label_internal: Intern + label_last_changes: "senaste %{count} ändringar" + label_change_view_all: Visa alla ändringar + label_personalize_page: Anpassa denna sida + label_comment: Kommentar + label_comment_plural: Kommentarer + label_x_comments: + zero: inga kommentarer + one: 1 kommentar + other: "%{count} kommentarer" + label_comment_add: Lägg till kommentar + label_comment_added: Kommentar tillagd + label_comment_delete: Ta bort kommentar + label_query: Användardefinerad fråga + label_query_plural: Användardefinerade frågor + label_query_new: Ny fråga + label_my_queries: Mina egna frågor + label_filter_add: Lägg till filter + label_filter_plural: Filter + label_equals: är + label_not_equals: är inte + label_in_less_than: om mindre än + label_in_more_than: om mer än + label_in_the_next_days: under kommande + label_in_the_past_days: under föregående + label_greater_or_equal: '>=' + label_less_or_equal: '<=' + label_between: mellan + label_in: om + label_today: idag + label_all_time: närsom + label_yesterday: igår + label_this_week: denna vecka + label_last_week: senaste veckan + label_last_n_weeks: "senaste %{count} veckorna" + label_last_n_days: "senaste %{count} dagarna" + label_this_month: denna månad + label_last_month: senaste månaden + label_this_year: detta året + label_date_range: Datumintervall + label_less_than_ago: mindre än dagar sedan + label_more_than_ago: mer än dagar sedan + label_ago: dagar sedan + label_contains: innehåller + label_not_contains: innehåller inte + label_any_issues_in_project: några ärenden i projektet + label_any_issues_not_in_project: några ärenden utanför projektet + label_no_issues_in_project: inga ärenden i projektet + label_day_plural: dagar + label_repository: Versionsarkiv + label_repository_new: Nytt versionsarkiv + label_repository_plural: Versionsarkiv + label_browse: Bläddra + label_branch: Branch + label_tag: Tag + label_revision: Revision + label_revision_plural: Revisioner + label_revision_id: "Revision %{value}" + label_associated_revisions: Associerade revisioner + label_added: tillagd + label_modified: modifierad + label_copied: kopierad + label_renamed: omdöpt + label_deleted: borttagen + label_latest_revision: Senaste revisionen + label_latest_revision_plural: Senaste revisionerna + label_view_revisions: Visa revisioner + label_view_all_revisions: Visa alla revisioner + label_max_size: Maxstorlek + label_sort_highest: Flytta till toppen + label_sort_higher: Flytta upp + label_sort_lower: Flytta ner + label_sort_lowest: Flytta till botten + label_roadmap: Roadmap + label_roadmap_due_in: "Färdig om %{value}" + label_roadmap_overdue: "%{value} sen" + label_roadmap_no_issues: Inga ärenden för denna version + label_search: Sök + label_result_plural: Resultat + label_all_words: Alla ord + label_wiki: Wiki + label_wiki_edit: Wikiändring + label_wiki_edit_plural: Wikiändringar + label_wiki_page: Wikisida + label_wiki_page_plural: Wikisidor + label_index_by_title: Innehåll efter titel + label_index_by_date: Innehåll efter datum + label_current_version: Nuvarande version + label_preview: Förhandsgranska + label_feed_plural: Feeds + label_changes_details: Detaljer om alla ändringar + label_issue_tracking: Ärendeuppföljning + label_spent_time: Spenderad tid + label_overall_spent_time: Total tid spenderad + label_f_hour: "%{value} timme" + label_f_hour_plural: "%{value} timmar" + label_time_tracking: Tidsuppföljning + label_change_plural: Ändringar + label_statistics: Statistik + label_commits_per_month: Commits per månad + label_commits_per_author: Commits per författare + label_diff: diff + label_view_diff: Visa skillnader + label_diff_inline: i texten + label_diff_side_by_side: sida vid sida + label_options: Inställningar + label_copy_workflow_from: Kopiera arbetsflöde från + label_permissions_report: Behörighetsrapport + label_watched_issues: Bevakade ärenden + label_related_issues: Relaterade ärenden + label_applied_status: Tilldelad status + label_loading: Laddar... + label_relation_new: Ny relation + label_relation_delete: Ta bort relation + label_relates_to: Relaterar till + label_duplicates: Kopierar + label_duplicated_by: Kopierad av + label_blocks: Blockerar + label_blocked_by: Blockerad av + label_precedes: Kommer före + label_follows: Följer + label_copied_to: Kopierad till + label_copied_from: Kopierad från + label_end_to_start: slut till start + label_end_to_end: slut till slut + label_start_to_start: start till start + label_start_to_end: start till slut + label_stay_logged_in: Förbli inloggad + label_disabled: inaktiverad + label_show_completed_versions: Visa färdiga versioner + label_me: mig + label_board: Forum + label_board_new: Nytt forum + label_board_plural: Forum + label_board_locked: Låst + label_board_sticky: Sticky + label_topic_plural: Ämnen + label_message_plural: Meddelanden + label_message_last: Senaste meddelande + label_message_new: Nytt meddelande + label_message_posted: Meddelande tillagt + label_reply_plural: Svar + label_send_information: Skicka kontoinformation till användaren + label_year: År + label_month: Månad + label_week: Vecka + label_date_from: Från + label_date_to: Till + label_language_based: Språkbaserad + label_sort_by: "Sortera på %{value}" + label_send_test_email: Skicka testmail + label_feeds_access_key: RSS-nyckel + label_missing_feeds_access_key: Saknar en RSS-nyckel + label_feeds_access_key_created_on: "RSS-nyckel skapad för %{value} sedan" + label_module_plural: Moduler + label_added_time_by: "Tillagd av %{author} för %{age} sedan" + label_updated_time_by: "Uppdaterad av %{author} för %{age} sedan" + label_updated_time: "Uppdaterad för %{value} sedan" + label_jump_to_a_project: Gå till projekt... + label_file_plural: Filer + label_changeset_plural: Changesets + label_default_columns: Standardkolumner + label_no_change_option: (Ingen ändring) + label_bulk_edit_selected_issues: Gemensam ändring av markerade ärenden + label_bulk_edit_selected_time_entries: Gruppredigera valda tidloggningar + label_theme: Tema + label_default: Standard + label_search_titles_only: Sök endast i titlar + label_user_mail_option_all: "För alla händelser i mina projekt" + label_user_mail_option_selected: "För alla händelser i markerade projekt..." + label_user_mail_option_none: "Inga händelser" + label_user_mail_option_only_my_events: "Endast för saker jag bevakar eller är inblandad i" + label_user_mail_option_only_assigned: "Endast för saker jag är tilldelad" + label_user_mail_option_only_owner: "Endast för saker jag äger" + label_user_mail_no_self_notified: "Jag vill inte bli underrättad om ändringar som jag har gjort" + label_registration_activation_by_email: kontoaktivering med mail + label_registration_manual_activation: manuell kontoaktivering + label_registration_automatic_activation: automatisk kontoaktivering + label_display_per_page: "Per sida: %{value}" + label_age: Ålder + label_change_properties: Ändra inställningar + label_general: Allmänt + label_more: Mer + label_scm: SCM + label_plugins: Tillägg + label_ldap_authentication: LDAP-autentisering + label_downloads_abbr: Nerl. + label_optional_description: Valfri beskrivning + label_add_another_file: Lägg till ytterligare en fil + label_preferences: Användarinställningar + label_chronological_order: I kronologisk ordning + label_reverse_chronological_order: I omvänd kronologisk ordning + label_planning: Planering + label_incoming_emails: Inkommande mail + label_generate_key: Generera en nyckel + label_issue_watchers: Bevakare + label_example: Exempel + label_display: Visa + label_sort: Sortera + label_descending: Fallande + label_ascending: Stigande + label_date_from_to: Från %{start} till %{end} + label_wiki_content_added: Wikisida tillagd + label_wiki_content_updated: Wikisida uppdaterad + label_group: Grupp + label_group_plural: Grupper + label_group_new: Ny grupp + label_time_entry_plural: Spenderad tid + label_version_sharing_none: Inte delad + label_version_sharing_descendants: Med underprojekt + label_version_sharing_hierarchy: Med projekthierarki + label_version_sharing_tree: Med projektträd + label_version_sharing_system: Med alla projekt + label_update_issue_done_ratios: Uppdatera % klart + label_copy_source: Källa + label_copy_target: Mål + label_copy_same_as_target: Samma som mål + label_display_used_statuses_only: Visa endast status som används av denna ärendetyp + label_api_access_key: API-nyckel + label_missing_api_access_key: Saknar en API-nyckel + label_api_access_key_created_on: "API-nyckel skapad för %{value} sedan" + label_profile: Profil + label_subtask_plural: Underaktiviteter + label_project_copy_notifications: Skicka mailnotifieringar när projektet kopieras + label_principal_search: "Sök efter användare eller grupp:" + label_user_search: "Sök efter användare:" + label_additional_workflow_transitions_for_author: Ytterligare övergångar tillåtna när användaren är den som skapat ärendet + label_additional_workflow_transitions_for_assignee: Ytterligare övergångar tillåtna när användaren är den som tilldelats ärendet + label_issues_visibility_all: Alla ärenden + label_issues_visibility_public: Alla icke-privata ärenden + label_issues_visibility_own: Ärenden skapade av eller tilldelade till användaren + label_git_report_last_commit: Rapportera senaste commit av filer och mappar + label_parent_revision: Förälder + label_child_revision: Barn + label_export_options: "%{export_format} exportalternativ" + label_copy_attachments: Kopiera bilagor + label_copy_subtasks: Kopiera underaktiviteter + label_item_position: "%{position}/%{count}" + label_completed_versions: Klara versioner + label_search_for_watchers: Sök efter bevakare att lägga till + label_session_expiration: Sessionsutgång + label_show_closed_projects: Visa stängda projekt + label_status_transitions: Statusövergångar + label_fields_permissions: Fältbehörigheter + label_readonly: Skrivskyddad + label_required: Nödvändig + label_attribute_of_project: Projektets %{name} + label_attribute_of_issue: Ärendets %{name} + label_attribute_of_author: Författarens %{name} + label_attribute_of_assigned_to: Tilldelad användares %{name} + label_attribute_of_user: Användarens %{name} + label_attribute_of_fixed_version: Målversionens %{name} + label_cross_project_descendants: Med underprojekt + label_cross_project_tree: Med projektträd + label_cross_project_hierarchy: Med projekthierarki + label_cross_project_system: Med alla projekt + label_gantt_progress_line: Framstegslinje + + button_login: Logga in + button_submit: Skicka + button_save: Spara + button_check_all: Markera alla + button_uncheck_all: Avmarkera alla + button_collapse_all: Kollapsa alla + button_expand_all: Expandera alla + button_delete: Ta bort + button_create: Skapa + button_create_and_continue: Skapa och fortsätt + button_test: Testa + button_edit: Ändra + button_edit_associated_wikipage: "Ändra associerad Wikisida: %{page_title}" + button_add: Lägg till + button_change: Ändra + button_apply: Verkställ + button_clear: Återställ + button_lock: Lås + button_unlock: Lås upp + button_download: Ladda ner + button_list: Lista + button_view: Visa + button_move: Flytta + button_move_and_follow: Flytta och följ efter + button_back: Tillbaka + button_cancel: Avbryt + button_activate: Aktivera + button_sort: Sortera + button_log_time: Logga tid + button_rollback: Återställ till denna version + button_watch: Bevaka + button_unwatch: Stoppa bevakning + button_reply: Svara + button_archive: Arkivera + button_unarchive: Ta bort från arkiv + button_reset: Återställ + button_rename: Byt namn + button_change_password: Ändra lösenord + button_copy: Kopiera + button_copy_and_follow: Kopiera och följ efter + button_annotate: Kommentera + button_update: Uppdatera + button_configure: Konfigurera + button_quote: Citera + button_duplicate: Duplicera + button_show: Visa + button_hide: Göm + button_edit_section: Redigera denna sektion + button_export: Exportera + button_delete_my_account: Ta bort mitt konto + button_close: Stäng + button_reopen: Återöppna + + status_active: aktiv + status_registered: registrerad + status_locked: låst + + project_status_active: aktiv + project_status_closed: stängd + project_status_archived: arkiverad + + version_status_open: öppen + version_status_locked: låst + version_status_closed: stängd + + field_active: Aktiv + + text_select_mail_notifications: Välj för vilka händelser mail ska skickas. + text_regexp_info: eg. ^[A-Z0-9]+$ + text_min_max_length_info: 0 betyder ingen gräns + text_project_destroy_confirmation: Är du säker på att du vill ta bort detta projekt och all relaterad data? + text_subprojects_destroy_warning: "Alla underprojekt: %{value} kommer också tas bort." + text_workflow_edit: Välj en roll och en ärendetyp för att ändra arbetsflöde + text_are_you_sure: Är du säker ? + text_journal_changed: "%{label} ändrad från %{old} till %{new}" + text_journal_changed_no_detail: "%{label} uppdaterad" + text_journal_set_to: "%{label} satt till %{value}" + text_journal_deleted: "%{label} borttagen (%{old})" + text_journal_added: "%{label} %{value} tillagd" + text_tip_issue_begin_day: ärende som börjar denna dag + text_tip_issue_end_day: ärende som slutar denna dag + text_tip_issue_begin_end_day: ärende som börjar och slutar denna dag + text_project_identifier_info: 'Endast gemener (a-z), siffror, streck och understreck är tillåtna, måste börja med en bokstav.
    När identifieraren sparats kan den inte ändras.' + text_caracters_maximum: "max %{count} tecken." + text_caracters_minimum: "Måste vara minst %{count} tecken lång." + text_length_between: "Längd mellan %{min} och %{max} tecken." + text_tracker_no_workflow: Inget arbetsflöde definerat för denna ärendetyp + text_unallowed_characters: Otillåtna tecken + text_comma_separated: Flera värden tillåtna (kommaseparerade). + text_line_separated: Flera värden tillåtna (ett värde per rad). + text_issues_ref_in_commit_messages: Referera och fixa ärenden i commit-meddelanden + text_issue_added: "Ärende %{id} har rapporterats (av %{author})." + text_issue_updated: "Ärende %{id} har uppdaterats (av %{author})." + text_wiki_destroy_confirmation: Är du säker på att du vill ta bort denna wiki och allt dess innehåll ? + text_issue_category_destroy_question: "Några ärenden (%{count}) är tilldelade till denna kategori. Vad vill du göra ?" + text_issue_category_destroy_assignments: Ta bort kategoritilldelningar + text_issue_category_reassign_to: Återtilldela ärenden till denna kategori + text_user_mail_option: "För omarkerade projekt kommer du bara bli underrättad om saker du bevakar eller är inblandad i (T.ex. ärenden du skapat eller tilldelats)." + text_no_configuration_data: "Roller, ärendetyper, ärendestatus och arbetsflöden har inte konfigurerats ännu.\nDet rekommenderas att läsa in standardkonfigurationen. Du kommer att kunna göra ändringar efter att den blivit inläst." + text_load_default_configuration: Läs in standardkonfiguration + text_status_changed_by_changeset: "Tilldelad i changeset %{value}." + text_time_logged_by_changeset: "Tilldelad i changeset %{value}." + text_issues_destroy_confirmation: 'Är du säker på att du vill radera markerade ärende(n) ?' + text_issues_destroy_descendants_confirmation: Detta kommer även ta bort %{count} underaktivitet(er). + text_time_entries_destroy_confirmation: Är du säker på att du vill ta bort valda tidloggningar? + text_select_project_modules: 'Välj vilka moduler som ska vara aktiva för projektet:' + text_default_administrator_account_changed: Standardadministratörens konto ändrat + text_file_repository_writable: Arkivet för bifogade filer är skrivbart + text_plugin_assets_writable: Arkivet för plug-ins är skrivbart + text_rmagick_available: RMagick tillgängligt (ej obligatoriskt) + text_destroy_time_entries_question: "%{hours} timmar har rapporterats på ärendena du är på väg att ta bort. Vad vill du göra ?" + text_destroy_time_entries: Ta bort rapporterade timmar + text_assign_time_entries_to_project: Tilldela rapporterade timmar till projektet + text_reassign_time_entries: 'Återtilldela rapporterade timmar till detta ärende:' + text_user_wrote: "%{value} skrev:" + text_enumeration_destroy_question: "%{count} objekt är tilldelade till detta värde." + text_enumeration_category_reassign_to: 'Återtilldela till detta värde:' + text_email_delivery_not_configured: "Mailfunktionen har inte konfigurerats, och notifieringar via mail kan därför inte skickas.\nKonfigurera din SMTP-server i config/configuration.yml och starta om applikationen för att aktivera dem." + text_repository_usernames_mapping: "Välj eller uppdatera den Redmine-användare som är mappad till varje användarnamn i versionarkivloggen.\nAnvändare med samma användarnamn eller mailadress i både Redmine och versionsarkivet mappas automatiskt." + text_diff_truncated: '... Denna diff har förminskats eftersom den överskrider den maximala storlek som kan visas.' + text_custom_field_possible_values_info: 'Ett värde per rad' + text_wiki_page_destroy_question: "Denna sida har %{descendants} underliggande sidor. Vad vill du göra?" + text_wiki_page_nullify_children: "Behåll undersidor som rotsidor" + text_wiki_page_destroy_children: "Ta bort alla underliggande sidor" + text_wiki_page_reassign_children: "Flytta undersidor till denna föräldersida" + text_own_membership_delete_confirmation: "Några av, eller alla, dina behörigheter kommer att tas bort och du kanske inte längre kommer kunna göra ändringar i det här projektet.\nVill du verkligen fortsätta?" + text_zoom_out: Zooma ut + text_zoom_in: Zooma in + text_warn_on_leaving_unsaved: "Nuvarande sida innehåller osparad text som kommer försvinna om du lämnar sidan." + text_scm_path_encoding_note: "Standard: UTF-8" + text_git_repository_note: Versionsarkiv är tomt och lokalt (t.ex. /gitrepo, c:\gitrepo) + text_mercurial_repository_note: Lokalt versionsarkiv (t.ex. /hgrepo, c:\hgrepo) + text_scm_command: Kommando + text_scm_command_version: Version + text_scm_config: Du kan konfigurera dina scm-kommando i config/configuration.yml. Vänligen starta om applikationen när ändringar gjorts. + text_scm_command_not_available: Scm-kommando är inte tillgängligt. Vänligen kontrollera inställningarna i administratörspanelen. + text_issue_conflict_resolution_overwrite: "Använd mina ändringar i alla fall (tidigare anteckningar kommer behållas men några ändringar kan bli överskrivna)" + text_issue_conflict_resolution_add_notes: "Lägg till mina anteckningar och kasta mina andra ändringar" + text_issue_conflict_resolution_cancel: "Kasta alla mina ändringar och visa igen %{link}" + text_account_destroy_confirmation: "Är du säker på att du vill fortsätta?\nDitt konto kommer tas bort permanent, utan möjlighet att återaktivera det." + text_session_expiration_settings: "Varning: ändring av dessa inställningar kan få alla nuvarande sessioner, inklusive din egen, att gå ut." + text_project_closed: Detta projekt är stängt och skrivskyddat. + text_turning_multiple_off: "Om du inaktiverar möjligheten till flera värden kommer endast ett värde per objekt behållas." + + default_role_manager: Projektledare + default_role_developer: Utvecklare + default_role_reporter: Rapportör + default_tracker_bug: Bugg + default_tracker_feature: Funktionalitet + default_tracker_support: Support + default_issue_status_new: Ny + default_issue_status_in_progress: Pågår + default_issue_status_resolved: Löst + default_issue_status_feedback: Återkoppling + default_issue_status_closed: Stängd + default_issue_status_rejected: Avslagen + default_doc_category_user: Användardokumentation + default_doc_category_tech: Teknisk dokumentation + default_priority_low: Låg + default_priority_normal: Normal + default_priority_high: Hög + default_priority_urgent: Brådskande + default_priority_immediate: Omedelbar + default_activity_design: Design + default_activity_development: Utveckling + + enumeration_issue_priorities: Ärendeprioriteter + enumeration_doc_categories: Dokumentkategorier + enumeration_activities: Aktiviteter (tidsuppföljning) + enumeration_system_activity: Systemaktivitet + description_filter: Filter + description_search: Sökfält + description_choose_project: Projekt + description_project_scope: Sökomfång + description_notes: Anteckningar + description_message_content: Meddelandeinnehåll + description_query_sort_criteria_attribute: Sorteringsattribut + description_query_sort_criteria_direction: Sorteringsriktning + description_user_mail_notification: Mailnotifieringsinställningar + description_available_columns: Tillgängliga Kolumner + description_selected_columns: Valda Kolumner + description_all_columns: Alla kolumner + description_issue_category_reassign: Välj ärendekategori + description_wiki_subpages_reassign: Välj ny föräldersida + description_date_range_list: Välj intervall från listan + description_date_range_interval: Ange intervall genom att välja start- och slutdatum + description_date_from: Ange startdatum + description_date_to: Ange slutdatum + text_repository_identifier_info: 'Endast gemener (a-z), siffror, streck och understreck är tillåtna.
    När identifieraren sparats kan den inte ändras.' + setting_jsonp_enabled: Enable JSONP support + field_inherit_members: Inherit members + field_closed_on: Closed + setting_default_projects_tracker_ids: Default trackers for new projects + label_total_time: Total diff --git a/config/locales/th.yml b/config/locales/th.yml new file mode 100644 index 00000000..a7e1255e --- /dev/null +++ b/config/locales/th.yml @@ -0,0 +1,1086 @@ +th: + direction: ltr + date: + formats: + # Use the strftime parameters for formats. + # When no format has been given, it uses default. + # You can provide other formats here if you like! + default: "%Y-%m-%d" + short: "%b %d" + long: "%B %d, %Y" + + day_names: [Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday] + abbr_day_names: [Sun, Mon, Tue, Wed, Thu, Fri, Sat] + + # Don't forget the nil at the beginning; there's no such thing as a 0th month + month_names: [~, January, February, March, April, May, June, July, August, September, October, November, December] + abbr_month_names: [~, Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec] + # Used in date_select and datime_select. + order: + - :year + - :month + - :day + + time: + formats: + default: "%a, %d %b %Y %H:%M:%S %z" + time: "%H:%M" + short: "%d %b %H:%M" + long: "%B %d, %Y %H:%M" + am: "am" + pm: "pm" + + datetime: + distance_in_words: + half_a_minute: "half a minute" + less_than_x_seconds: + one: "less than 1 second" + other: "less than %{count} seconds" + x_seconds: + one: "1 second" + other: "%{count} seconds" + less_than_x_minutes: + one: "less than a minute" + other: "less than %{count} minutes" + x_minutes: + one: "1 minute" + other: "%{count} minutes" + about_x_hours: + one: "about 1 hour" + other: "about %{count} hours" + x_hours: + one: "1 hour" + other: "%{count} hours" + x_days: + one: "1 day" + other: "%{count} days" + about_x_months: + one: "about 1 month" + other: "about %{count} months" + x_months: + one: "1 month" + other: "%{count} months" + about_x_years: + one: "about 1 year" + other: "about %{count} years" + over_x_years: + one: "over 1 year" + other: "over %{count} years" + almost_x_years: + one: "almost 1 year" + other: "almost %{count} years" + + number: + format: + separator: "." + delimiter: "" + precision: 3 + human: + format: + precision: 3 + delimiter: "" + storage_units: + format: "%n %u" + units: + kb: KB + tb: TB + gb: GB + byte: + one: Byte + other: Bytes + mb: MB + +# Used in array.to_sentence. + support: + array: + sentence_connector: "and" + skip_last_comma: false + + activerecord: + errors: + template: + header: + one: "1 error prohibited this %{model} from being saved" + other: "%{count} errors prohibited this %{model} from being saved" + messages: + inclusion: "ไม่อยู่ในรายการ" + exclusion: "ถูกสงวนไว้" + invalid: "ไม่ถูกต้อง" + confirmation: "พิมพ์ไม่เหมือนเดิม" + accepted: "ต้องยอมรับ" + empty: "ต้องเติม" + blank: "ต้องเติม" + too_long: "ยาวเกินไป" + too_short: "สั้นเกินไป" + wrong_length: "ความยาวไม่ถูกต้อง" + taken: "ถูกใช้ไปแล้ว" + not_a_number: "ไม่ใช่ตัวเลข" + not_a_date: "ไม่ใช่วันที่ ที่ถูกต้อง" + greater_than: "must be greater than %{count}" + greater_than_or_equal_to: "must be greater than or equal to %{count}" + equal_to: "must be equal to %{count}" + less_than: "must be less than %{count}" + less_than_or_equal_to: "must be less than or equal to %{count}" + odd: "must be odd" + even: "must be even" + greater_than_start_date: "ต้องมากกว่าวันเริ่ม" + not_same_project: "ไม่ได้อยู่ในโครงการเดียวกัน" + circular_dependency: "ความสัมพันธ์อ้างอิงเป็นวงกลม" + cant_link_an_issue_with_a_descendant: "An issue can not be linked to one of its subtasks" + + actionview_instancetag_blank_option: กรุณาเลือก + + general_text_No: 'ไม่' + general_text_Yes: 'ใช่' + general_text_no: 'ไม่' + general_text_yes: 'ใช่' + general_lang_name: 'Thai (ไทย)' + general_csv_separator: ',' + general_csv_decimal_separator: '.' + general_csv_encoding: Windows-874 + general_pdf_encoding: cp874 + general_first_day_of_week: '1' + + notice_account_updated: บัญชีได้ถูกปรับปรุงแล้ว. + notice_account_invalid_creditentials: ชื้ผู้ใช้หรือรหัสผ่านไม่ถูกต้อง + notice_account_password_updated: รหัสได้ถูกปรับปรุงแล้ว. + notice_account_wrong_password: รหัสผ่านไม่ถูกต้อง + notice_account_register_done: บัญชีถูกสร้างแล้ว. กรุณาเช็คเมล์ แล้วคลิ๊กที่ลิงค์ในอีเมล์เพื่อเปิดใช้บัญชี + notice_account_unknown_email: ไม่มีผู้ใช้ที่ใช้อีเมล์นี้. + notice_can_t_change_password: บัญชีนี้ใช้การยืนยันตัวตนจากแหล่งภายนอก. ไม่สามารถปลี่ยนรหัสผ่านได้. + notice_account_lost_email_sent: เราได้ส่งอีเมล์พร้อมวิธีการสร้างรหัีสผ่านใหม่ให้คุณแล้ว กรุณาเช็คเมล์. + notice_account_activated: บัญชีของคุณได้เปิดใช้แล้ว. ตอนนี้คุณสามารถเข้าสู่ระบบได้แล้ว. + notice_successful_create: สร้างเสร็จแล้ว. + notice_successful_update: ปรับปรุงเสร็จแล้ว. + notice_successful_delete: ลบเสร็จแล้ว. + notice_successful_connection: ติดต่อสำเร็จแล้ว. + notice_file_not_found: หน้าที่คุณต้องการดูไม่มีอยู่จริง หรือถูกลบไปแล้ว. + notice_locking_conflict: ข้อมูลถูกปรับปรุงโดยผู้ใช้คนอื่น. + notice_not_authorized: คุณไม่มีสิทธิเข้าถึงหน้านี้. + notice_email_sent: "อีเมล์ได้ถูกส่งถึง %{value}" + notice_email_error: "เกิดความผิดพลาดขณะกำส่งอีเมล์ (%{value})" + notice_feeds_access_key_reseted: RSS access key ของคุณถูก reset แล้ว. + notice_failed_to_save_issues: "%{count} ปัญหาจาก %{total} ปัญหาที่ถูกเลือกไม่สามารถจัดเก็บ: %{ids}." + notice_no_issue_selected: "ไม่มีปัญหาที่ถูกเลือก! กรุณาเลือกปัญหาที่คุณต้องการแก้ไข." + notice_account_pending: "บัญชีของคุณสร้างเสร็จแล้ว ขณะนี้รอการอนุมัติจากผู้บริหารจัดการ." + notice_default_data_loaded: ค่าเริ่มต้นโหลดเสร็จแล้ว. + + error_can_t_load_default_data: "ค่าเริ่มต้นโหลดไม่สำเร็จ: %{value}" + error_scm_not_found: "ไม่พบรุ่นที่ต้องการในแหล่งเก็บต้นฉบับ." + error_scm_command_failed: "เกิดความผิดพลาดในการเข้าถึงแหล่งเก็บต้นฉบับ: %{value}" + error_scm_annotate: "entry ไม่มีอยู่จริง หรือไม่สามารถเขียนหมายเหตุประกอบ." + error_issue_not_found_in_project: 'ไม่พบปัญหานี้ หรือปัญหาไม่ได้อยู่ในโครงการนี้' + + mail_subject_lost_password: "รหัสผ่าน %{value} ของคุณ" + mail_body_lost_password: 'คลิ๊กที่ลิงค์ต่อไปนี้เพื่อเปลี่ยนรหัสผ่าน:' + mail_subject_register: "เปิดบัญชี %{value} ของคุณ" + mail_body_register: 'คลิ๊กที่ลิงค์ต่อไปนี้เพื่อเปลี่ยนรหัสผ่าน:' + mail_body_account_information_external: "คุณสามารถใช้บัญชี %{value} เพื่อเข้าสู่ระบบ." + mail_body_account_information: ข้อมูลบัญชีของคุณ + mail_subject_account_activation_request: "กรุณาเปิดบัญชี %{value}" + mail_body_account_activation_request: "ผู้ใช้ใหม่ (%{value}) ได้ลงทะเบียน. บัญชีของเขากำลังรออนุมัติ:" + + + field_name: ชื่อ + field_description: รายละเอียด + field_summary: สรุปย่อ + field_is_required: ต้องใส่ + field_firstname: ชื่อ + field_lastname: นามสกุล + field_mail: อีเมล์ + field_filename: แฟ้ม + field_filesize: ขนาด + field_downloads: ดาวน์โหลด + field_author: ผู้แต่ง + field_created_on: สร้าง + field_updated_on: ปรับปรุง + field_field_format: รูปแบบ + field_is_for_all: สำหรับทุกโครงการ + field_possible_values: ค่าที่เป็นไปได้ + field_regexp: Regular expression + field_min_length: สั้นสุด + field_max_length: ยาวสุด + field_value: ค่า + field_category: ประเภท + field_title: ชื่อเรื่อง + field_project: โครงการ + field_issue: ปัญหา + field_status: สถานะ + field_notes: บันทึก + field_is_closed: ปัญหาจบ + field_is_default: ค่าเริ่มต้น + field_tracker: การติดตาม + field_subject: เรื่อง + field_due_date: วันครบกำหนด + field_assigned_to: มอบหมายให้ + field_priority: ความสำคัญ + field_fixed_version: รุ่น + field_user: ผู้ใช้ + field_role: บทบาท + field_homepage: หน้าแรก + field_is_public: สาธารณะ + field_parent: โครงการย่อยของ + field_is_in_roadmap: ปัญหาแสดงใน แผนงาน + field_login: ชื่อที่ใช้เข้าระบบ + field_mail_notification: การแจ้งเตือนทางอีเมล์ + field_admin: ผู้บริหารจัดการ + field_last_login_on: เข้าระบบครั้งสุดท้าย + field_language: ภาษา + field_effective_date: วันที่ + field_password: รหัสผ่าน + field_new_password: รหัสผ่านใหม่ + field_password_confirmation: ยืนยันรหัสผ่าน + field_version: รุ่น + field_type: ชนิด + field_host: โฮสต์ + field_port: พอร์ต + field_account: บัญชี + field_base_dn: Base DN + field_attr_login: เข้าระบบ attribute + field_attr_firstname: ชื่อ attribute + field_attr_lastname: นามสกุล attribute + field_attr_mail: อีเมล์ attribute + field_onthefly: สร้างผู้ใช้ทันที + field_start_date: เริ่ม + field_done_ratio: "% สำเร็จ" + field_auth_source: วิธีการยืนยันตัวตน + field_hide_mail: ซ่อนอีเมล์ของฉัน + field_comments: ความเห็น + field_url: URL + field_start_page: หน้าเริ่มต้น + field_subproject: โครงการย่อย + field_hours: ชั่วโมง + field_activity: กิจกรรม + field_spent_on: วันที่ + field_identifier: ชื่อเฉพาะ + field_is_filter: ใช้เป็นตัวกรอง + field_issue_to: ปัญหาที่เกี่ยวข้อง + field_delay: เลื่อน + field_assignable: ปัญหาสามารถมอบหมายให้คนที่ทำบทบาทนี้ + field_redirect_existing_links: ย้ายจุดเชื่อมโยงนี้ + field_estimated_hours: เวลาที่ใช้โดยประมาณ + field_column_names: สดมภ์ + field_time_zone: ย่านเวลา + field_searchable: ค้นหาได้ + field_default_value: ค่าเริ่มต้น + field_comments_sorting: แสดงความเห็น + + setting_app_title: ชื่อโปรแกรม + setting_app_subtitle: ชื่อโปรแกรมรอง + setting_welcome_text: ข้อความต้อนรับ + setting_default_language: ภาษาเริ่มต้น + setting_login_required: ต้องป้อนผู้ใช้-รหัสผ่าน + setting_self_registration: ลงทะเบียนด้วยตนเอง + setting_attachment_max_size: ขนาดแฟ้มแนบสูงสุด + setting_issues_export_limit: การส่งออกปัญหาสูงสุด + setting_mail_from: อีเมล์ที่ใช้ส่ง + setting_bcc_recipients: ไม่ระบุชื่อผู้รับ (bcc) + setting_host_name: ชื่อโฮสต์ + setting_text_formatting: การจัดรูปแบบข้อความ + setting_wiki_compression: บีบอัดประวัติ Wiki + setting_feeds_limit: จำนวน Feed + setting_default_projects_public: โครงการใหม่มีค่าเริ่มต้นเป็น สาธารณะ + setting_autofetch_changesets: ดึง commits อัตโนมัติ + setting_sys_api_enabled: เปิดใช้ WS สำหรับการจัดการที่เก็บต้นฉบับ + setting_commit_ref_keywords: คำสำคัญ Referencing + setting_commit_fix_keywords: คำสำคัญ Fixing + setting_autologin: เข้าระบบอัตโนมัติ + setting_date_format: รูปแบบวันที่ + setting_time_format: รูปแบบเวลา + setting_cross_project_issue_relations: อนุญาตให้ระบุปัญหาข้ามโครงการ + setting_issue_list_default_columns: สดมภ์เริ่มต้นแสดงในรายการปัญหา + setting_emails_footer: คำลงท้ายอีเมล์ + setting_protocol: Protocol + setting_per_page_options: ตัวเลือกจำนวนต่อหน้า + setting_user_format: รูปแบบการแสดงชื่อผู้ใช้ + setting_activity_days_default: จำนวนวันที่แสดงในกิจกรรมของโครงการ + setting_display_subprojects_issues: แสดงปัญหาของโครงการย่อยในโครงการหลัก + + project_module_issue_tracking: การติดตามปัญหา + project_module_time_tracking: การใช้เวลา + project_module_news: ข่าว + project_module_documents: เอกสาร + project_module_files: แฟ้ม + project_module_wiki: Wiki + project_module_repository: ที่เก็บต้นฉบับ + project_module_boards: กระดานข้อความ + + label_user: ผู้ใช้ + label_user_plural: ผู้ใช้ + label_user_new: ผู้ใช้ใหม่ + label_project: โครงการ + label_project_new: โครงการใหม่ + label_project_plural: โครงการ + label_x_projects: + zero: no projects + one: 1 project + other: "%{count} projects" + label_project_all: โครงการทั้งหมด + label_project_latest: โครงการล่าสุด + label_issue: ปัญหา + label_issue_new: ปัญหาใหม่ + label_issue_plural: ปัญหา + label_issue_view_all: ดูปัญหาทั้งหมด + label_issues_by: "ปัญหาโดย %{value}" + label_issue_added: ปัญหาถูกเพิ่ม + label_issue_updated: ปัญหาถูกปรับปรุง + label_document: เอกสาร + label_document_new: เอกสารใหม่ + label_document_plural: เอกสาร + label_document_added: เอกสารถูกเพิ่ม + label_role: บทบาท + label_role_plural: บทบาท + label_role_new: บทบาทใหม่ + label_role_and_permissions: บทบาทและสิทธิ + label_member: สมาชิก + label_member_new: สมาชิกใหม่ + label_member_plural: สมาชิก + label_tracker: การติดตาม + label_tracker_plural: การติดตาม + label_tracker_new: การติดตามใหม่ + label_workflow: ลำดับงาน + label_issue_status: สถานะของปัญหา + label_issue_status_plural: สถานะของปัญหา + label_issue_status_new: สถานะใหม + label_issue_category: ประเภทของปัญหา + label_issue_category_plural: ประเภทของปัญหา + label_issue_category_new: ประเภทใหม่ + label_custom_field: เขตข้อมูลแบบระบุเอง + label_custom_field_plural: เขตข้อมูลแบบระบุเอง + label_custom_field_new: สร้างเขตข้อมูลแบบระบุเอง + label_enumerations: รายการ + label_enumeration_new: สร้างใหม่ + label_information: ข้อมูล + label_information_plural: ข้อมูล + label_please_login: กรุณาเข้าระบบก่อน + label_register: ลงทะเบียน + label_password_lost: ลืมรหัสผ่าน + label_home: หน้าแรก + label_my_page: หน้าของฉัน + label_my_account: บัญชีของฉัน + label_my_projects: โครงการของฉัน + label_administration: บริหารจัดการ + label_login: เข้าระบบ + label_logout: ออกระบบ + label_help: ช่วยเหลือ + label_reported_issues: ปัญหาที่แจ้งไว้ + label_assigned_to_me_issues: ปัญหาที่มอบหมายให้ฉัน + label_last_login: ติดต่อครั้งสุดท้าย + label_registered_on: ลงทะเบียนเมื่อ + label_activity: กิจกรรม + label_activity_plural: กิจกรรม + label_activity_latest: กิจกรรมล่าสุด + label_overall_activity: กิจกรรมโดยรวม + label_new: ใหม่ + label_logged_as: เข้าระบบในชื่อ + label_environment: สภาพแวดล้อม + label_authentication: การยืนยันตัวตน + label_auth_source: วิธีการการยืนยันตัวตน + label_auth_source_new: สร้างวิธีการยืนยันตัวตนใหม่ + label_auth_source_plural: วิธีการ Authentication + label_subproject_plural: โครงการย่อย + label_min_max_length: สั้น-ยาว สุดที่ + label_list: รายการ + label_date: วันที่ + label_integer: จำนวนเต็ม + label_float: จำนวนจริง + label_boolean: ถูกผิด + label_string: ข้อความ + label_text: ข้อความขนาดยาว + label_attribute: คุณลักษณะ + label_attribute_plural: คุณลักษณะ + label_no_data: จำนวนข้อมูลที่แสดง + label_change_status: เปลี่ยนสถานะ + label_history: ประวัติ + label_attachment: แฟ้ม + label_attachment_new: แฟ้มใหม่ + label_attachment_delete: ลบแฟ้ม + label_attachment_plural: แฟ้ม + label_file_added: แฟ้มถูกเพิ่ม + label_report: รายงาน + label_report_plural: รายงาน + label_news: ข่าว + label_news_new: เพิ่มข่าว + label_news_plural: ข่าว + label_news_latest: ข่าวล่าสุด + label_news_view_all: ดูข่าวทั้งหมด + label_news_added: ข่าวถูกเพิ่ม + label_settings: ปรับแต่ง + label_overview: ภาพรวม + label_version: รุ่น + label_version_new: รุ่นใหม่ + label_version_plural: รุ่น + label_confirmation: ยืนยัน + label_export_to: 'รูปแบบอื่นๆ :' + label_read: อ่าน... + label_public_projects: โครงการสาธารณะ + label_open_issues: เปิด + label_open_issues_plural: เปิด + label_closed_issues: ปิด + label_closed_issues_plural: ปิด + label_x_open_issues_abbr_on_total: + zero: 0 open / %{total} + one: 1 open / %{total} + other: "%{count} open / %{total}" + label_x_open_issues_abbr: + zero: 0 open + one: 1 open + other: "%{count} open" + label_x_closed_issues_abbr: + zero: 0 closed + one: 1 closed + other: "%{count} closed" + label_total: จำนวนรวม + label_permissions: สิทธิ + label_current_status: สถานะปัจจุบัน + label_new_statuses_allowed: อนุญาตให้มีสถานะใหม่ + label_all: ทั้งหมด + label_none: ไม่มี + label_nobody: ไม่มีใคร + label_next: ต่อไป + label_previous: ก่อนหน้า + label_used_by: ถูกใช้โดย + label_details: รายละเอียด + label_add_note: เพิ่มบันทึก + label_per_page: ต่อหน้า + label_calendar: ปฏิทิน + label_months_from: เดือนจาก + label_gantt: Gantt + label_internal: ภายใน + label_last_changes: "last %{count} เปลี่ยนแปลง" + label_change_view_all: ดูการเปลี่ยนแปลงทั้งหมด + label_personalize_page: ปรับแต่งหน้านี้ + label_comment: ความเห็น + label_comment_plural: ความเห็น + label_x_comments: + zero: no comments + one: 1 comment + other: "%{count} comments" + label_comment_add: เพิ่มความเห็น + label_comment_added: ความเห็นถูกเพิ่ม + label_comment_delete: ลบความเห็น + label_query: แบบสอบถามแบบกำหนดเอง + label_query_plural: แบบสอบถามแบบกำหนดเอง + label_query_new: แบบสอบถามใหม่ + label_filter_add: เพิ่มตัวกรอง + label_filter_plural: ตัวกรอง + label_equals: คือ + label_not_equals: ไม่ใช่ + label_in_less_than: น้อยกว่า + label_in_more_than: มากกว่า + label_in: ในช่วง + label_today: วันนี้ + label_all_time: ตลอดเวลา + label_yesterday: เมื่อวาน + label_this_week: อาทิตย์นี้ + label_last_week: อาทิตย์ที่แล้ว + label_last_n_days: "%{count} วันย้อนหลัง" + label_this_month: เดือนนี้ + label_last_month: เดือนที่แล้ว + label_this_year: ปีนี้ + label_date_range: ช่วงวันที่ + label_less_than_ago: น้อยกว่าหนึ่งวัน + label_more_than_ago: มากกว่าหนึ่งวัน + label_ago: วันผ่านมาแล้ว + label_contains: มี... + label_not_contains: ไม่มี... + label_day_plural: วัน + label_repository: ที่เก็บต้นฉบับ + label_repository_plural: ที่เก็บต้นฉบับ + label_browse: เปิดหา + label_revision: การแก้ไข + label_revision_plural: การแก้ไข + label_associated_revisions: การแก้ไขที่เกี่ยวข้อง + label_added: ถูกเพิ่ม + label_modified: ถูกแก้ไข + label_deleted: ถูกลบ + label_latest_revision: รุ่นการแก้ไขล่าสุด + label_latest_revision_plural: รุ่นการแก้ไขล่าสุด + label_view_revisions: ดูการแก้ไข + label_max_size: ขนาดใหญ่สุด + label_sort_highest: ย้ายไปบนสุด + label_sort_higher: ย้ายขึ้น + label_sort_lower: ย้ายลง + label_sort_lowest: ย้ายไปล่างสุด + label_roadmap: แผนงาน + label_roadmap_due_in: "ถึงกำหนดใน %{value}" + label_roadmap_overdue: "%{value} ช้ากว่ากำหนด" + label_roadmap_no_issues: ไม่มีปัญหาสำหรับรุ่นนี้ + label_search: ค้นหา + label_result_plural: ผลการค้นหา + label_all_words: ทุกคำ + label_wiki: Wiki + label_wiki_edit: แก้ไข Wiki + label_wiki_edit_plural: แก้ไข Wiki + label_wiki_page: หน้า Wiki + label_wiki_page_plural: หน้า Wiki + label_index_by_title: เรียงตามชื่อเรื่อง + label_index_by_date: เรียงตามวัน + label_current_version: รุ่นปัจจุบัน + label_preview: ตัวอย่างก่อนจัดเก็บ + label_feed_plural: Feeds + label_changes_details: รายละเอียดการเปลี่ยนแปลงทั้งหมด + label_issue_tracking: ติดตามปัญหา + label_spent_time: เวลาที่ใช้ + label_f_hour: "%{value} ชั่วโมง" + label_f_hour_plural: "%{value} ชั่วโมง" + label_time_tracking: ติดตามการใช้เวลา + label_change_plural: เปลี่ยนแปลง + label_statistics: สถิติ + label_commits_per_month: Commits ต่อเดือน + label_commits_per_author: Commits ต่อผู้แต่ง + label_view_diff: ดูความแตกต่าง + label_diff_inline: inline + label_diff_side_by_side: side by side + label_options: ตัวเลือก + label_copy_workflow_from: คัดลอกลำดับงานจาก + label_permissions_report: รายงานสิทธิ + label_watched_issues: เฝ้าดูปัญหา + label_related_issues: ปัญหาที่เกี่ยวข้อง + label_applied_status: จัดเก็บสถานะ + label_loading: กำลังโหลด... + label_relation_new: ความสัมพันธ์ใหม่ + label_relation_delete: ลบความสัมพันธ์ + label_relates_to: สัมพันธ์กับ + label_duplicates: ซ้ำ + label_blocks: กีดกัน + label_blocked_by: กีดกันโดย + label_precedes: นำหน้า + label_follows: ตามหลัง + label_end_to_start: จบ-เริ่ม + label_end_to_end: จบ-จบ + label_start_to_start: เริ่ม-เริ่ม + label_start_to_end: เริ่ม-จบ + label_stay_logged_in: อยู่ในระบบต่อ + label_disabled: ไม่ใช้งาน + label_show_completed_versions: แสดงรุ่นที่สมบูรณ์ + label_me: ฉัน + label_board: สภากาแฟ + label_board_new: สร้างสภากาแฟ + label_board_plural: สภากาแฟ + label_topic_plural: หัวข้อ + label_message_plural: ข้อความ + label_message_last: ข้อความล่าสุด + label_message_new: เขียนข้อความใหม่ + label_message_posted: ข้อความถูกเพิ่มแล้ว + label_reply_plural: ตอบกลับ + label_send_information: ส่งรายละเอียดของบัญชีให้ผู้ใช้ + label_year: ปี + label_month: เดือน + label_week: สัปดาห์ + label_date_from: จาก + label_date_to: ถึง + label_language_based: ขึ้นอยู่กับภาษาของผู้ใช้ + label_sort_by: "เรียงโดย %{value}" + label_send_test_email: ส่งจดหมายทดสอบ + label_feeds_access_key_created_on: "RSS access key สร้างเมื่อ %{value} ที่ผ่านมา" + label_module_plural: ส่วนประกอบ + label_added_time_by: "เพิ่มโดย %{author} %{age} ที่ผ่านมา" + label_updated_time: "ปรับปรุง %{value} ที่ผ่านมา" + label_jump_to_a_project: ไปที่โครงการ... + label_file_plural: แฟ้ม + label_changeset_plural: กลุ่มการเปลี่ยนแปลง + label_default_columns: สดมภ์เริ่มต้น + label_no_change_option: (ไม่เปลี่ยนแปลง) + label_bulk_edit_selected_issues: แก้ไขปัญหาที่เลือกทั้งหมด + label_theme: ชุดรูปแบบ + label_default: ค่าเริ่มต้น + label_search_titles_only: ค้นหาจากชื่อเรื่องเท่านั้น + label_user_mail_option_all: "ทุกๆ เหตุการณ์ในโครงการของฉัน" + label_user_mail_option_selected: "ทุกๆ เหตุการณ์ในโครงการที่เลือก..." + label_user_mail_no_self_notified: "ฉันไม่ต้องการได้รับการแจ้งเตือนในสิ่งที่ฉันทำเอง" + label_registration_activation_by_email: เปิดบัญชีผ่านอีเมล์ + label_registration_manual_activation: อนุมัติโดยผู้บริหารจัดการ + label_registration_automatic_activation: เปิดบัญชีอัตโนมัติ + label_display_per_page: "ต่อหน้า: %{value}" + label_age: อายุ + label_change_properties: เปลี่ยนคุณสมบัติ + label_general: ทั่วๆ ไป + label_more: อื่น ๆ + label_scm: ตัวจัดการต้นฉบับ + label_plugins: ส่วนเสริม + label_ldap_authentication: การยืนยันตัวตนโดยใช้ LDAP + label_downloads_abbr: D/L + label_optional_description: รายละเอียดเพิ่มเติม + label_add_another_file: เพิ่มแฟ้มอื่นๆ + label_preferences: ค่าที่ชอบใจ + label_chronological_order: เรียงจากเก่าไปใหม่ + label_reverse_chronological_order: เรียงจากใหม่ไปเก่า + label_planning: การวางแผน + + button_login: เข้าระบบ + button_submit: จัดส่งข้อมูล + button_save: จัดเก็บ + button_check_all: เลือกทั้งหมด + button_uncheck_all: ไม่เลือกทั้งหมด + button_delete: ลบ + button_create: สร้าง + button_test: ทดสอบ + button_edit: แก้ไข + button_add: เพิ่ม + button_change: เปลี่ยนแปลง + button_apply: ประยุกต์ใช้ + button_clear: ล้างข้อความ + button_lock: ล็อค + button_unlock: ยกเลิกการล็อค + button_download: ดาวน์โหลด + button_list: รายการ + button_view: มุมมอง + button_move: ย้าย + button_back: กลับ + button_cancel: ยกเลิก + button_activate: เปิดใช้ + button_sort: จัดเรียง + button_log_time: บันทึกเวลา + button_rollback: ถอยกลับมาที่รุ่นนี้ + button_watch: เฝ้าดู + button_unwatch: เลิกเฝ้าดู + button_reply: ตอบกลับ + button_archive: เก็บเข้าโกดัง + button_unarchive: เอาออกจากโกดัง + button_reset: เริ่มใหมท + button_rename: เปลี่ยนชื่อ + button_change_password: เปลี่ยนรหัสผ่าน + button_copy: คัดลอก + button_annotate: หมายเหตุประกอบ + button_update: ปรับปรุง + button_configure: ปรับแต่ง + + status_active: เปิดใช้งานแล้ว + status_registered: รอการอนุมัติ + status_locked: ล็อค + + text_select_mail_notifications: เลือกการกระทำที่ต้องการให้ส่งอีเมล์แจ้ง. + text_regexp_info: ตัวอย่าง ^[A-Z0-9]+$ + text_min_max_length_info: 0 หมายถึงไม่จำกัด + text_project_destroy_confirmation: คุณแน่ใจไหมว่าต้องการลบโครงการและข้อมูลที่เกี่ยวข้่อง ? + text_subprojects_destroy_warning: "โครงการย่อย: %{value} จะถูกลบด้วย." + text_workflow_edit: เลือกบทบาทและการติดตาม เพื่อแก้ไขลำดับงาน + text_are_you_sure: คุณแน่ใจไหม ? + text_tip_issue_begin_day: งานที่เริ่มวันนี้ + text_tip_issue_end_day: งานที่จบวันนี้ + text_tip_issue_begin_end_day: งานที่เริ่มและจบวันนี้ + text_caracters_maximum: "สูงสุด %{count} ตัวอักษร." + text_caracters_minimum: "ต้องยาวอย่างน้อย %{count} ตัวอักษร." + text_length_between: "ความยาวระหว่าง %{min} ถึง %{max} ตัวอักษร." + text_tracker_no_workflow: ไม่ได้บัญญัติลำดับงานสำหรับการติดตามนี้ + text_unallowed_characters: ตัวอักษรต้องห้าม + text_comma_separated: ใส่ได้หลายค่า โดยคั่นด้วยลูกน้ำ( ,). + text_issues_ref_in_commit_messages: Referencing and fixing issues in commit messages + text_issue_added: "ปัญหา %{id} ถูกแจ้งโดย %{author}." + text_issue_updated: "ปัญหา %{id} ถูกปรับปรุงโดย %{author}." + text_wiki_destroy_confirmation: คุณแน่ใจหรือว่าต้องการลบ wiki นี้พร้อมทั้งเนี้อหา? + text_issue_category_destroy_question: "บางปัญหา (%{count}) อยู่ในประเภทนี้. คุณต้องการทำอย่างไร ?" + text_issue_category_destroy_assignments: ลบประเภทนี้ + text_issue_category_reassign_to: ระบุปัญหาในประเภทนี้ + text_user_mail_option: "ในโครงการที่ไม่ได้เลือก, คุณจะได้รับการแจ้งเกี่ยวกับสิ่งที่คุณเฝ้าดูหรือมีส่วนเกี่ยวข้อง (เช่นปัญหาที่คุณแจ้งไว้หรือได้รับมอบหมาย)." + text_no_configuration_data: "บทบาท, การติดตาม, สถานะปัญหา และลำดับงานยังไม่ได้ถูกตั้งค่า.\nขอแนะนำให้โหลดค่าเริ่มต้น. คุณสามารถแก้ไขค่าได้หลังจากโหลดแล้ว." + text_load_default_configuration: โหลดค่าเริ่มต้น + text_status_changed_by_changeset: "ประยุกต์ใช้ในกลุ่มการเปลี่ยนแปลง %{value}." + text_issues_destroy_confirmation: 'คุณแน่ใจไหมว่าต้องการลบปัญหา(ทั้งหลาย)ที่เลือกไว้?' + text_select_project_modules: 'เลือกส่วนประกอบที่ต้องการใช้งานสำหรับโครงการนี้:' + text_default_administrator_account_changed: ค่าเริ่มต้นของบัญชีผู้บริหารจัดการถูกเปลี่ยนแปลง + text_file_repository_writable: ที่เก็บต้นฉบับสามารถเขียนได้ + text_rmagick_available: RMagick มีให้ใช้ (เป็นตัวเลือก) + text_destroy_time_entries_question: "%{hours} ชั่วโมงที่ถูกแจ้งในปัญหานี้จะโดนลบ. คุณต้องการทำอย่างไร?" + text_destroy_time_entries: ลบเวลาที่รายงานไว้ + text_assign_time_entries_to_project: ระบุเวลาที่ใช้ในโครงการนี้ + text_reassign_time_entries: 'ระบุเวลาที่ใช้ในโครงการนี่อีกครั้ง:' + + default_role_manager: ผู้จัดการ + default_role_developer: ผู้พัฒนา + default_role_reporter: ผู้รายงาน + default_tracker_bug: บั๊ก + default_tracker_feature: ลักษณะเด่น + default_tracker_support: สนับสนุน + default_issue_status_new: เกิดขึ้น + default_issue_status_in_progress: In Progress + default_issue_status_resolved: ดำเนินการ + default_issue_status_feedback: รอคำตอบ + default_issue_status_closed: จบ + default_issue_status_rejected: ยกเลิก + default_doc_category_user: เอกสารของผู้ใช้ + default_doc_category_tech: เอกสารทางเทคนิค + default_priority_low: ต่ำ + default_priority_normal: ปกติ + default_priority_high: สูง + default_priority_urgent: เร่งด่วน + default_priority_immediate: ด่วนมาก + default_activity_design: ออกแบบ + default_activity_development: พัฒนา + + enumeration_issue_priorities: ความสำคัญของปัญหา + enumeration_doc_categories: ประเภทเอกสาร + enumeration_activities: กิจกรรม (ใช้ในการติดตามเวลา) + label_and_its_subprojects: "%{value} and its subprojects" + mail_body_reminder: "%{count} issue(s) that are assigned to you are due in the next %{days} days:" + mail_subject_reminder: "%{count} issue(s) due in the next %{days} days" + text_user_wrote: "%{value} wrote:" + label_duplicated_by: duplicated by + setting_enabled_scm: Enabled SCM + text_enumeration_category_reassign_to: 'Reassign them to this value:' + text_enumeration_destroy_question: "%{count} objects are assigned to this value." + label_incoming_emails: Incoming emails + label_generate_key: Generate a key + setting_mail_handler_api_enabled: Enable WS for incoming emails + setting_mail_handler_api_key: API key + text_email_delivery_not_configured: "Email delivery is not configured, and notifications are disabled.\nConfigure your SMTP server in config/configuration.yml and restart the application to enable them." + field_parent_title: Parent page + label_issue_watchers: Watchers + button_quote: Quote + setting_sequential_project_identifiers: Generate sequential project identifiers + notice_unable_delete_version: Unable to delete version + label_renamed: renamed + label_copied: copied + setting_plain_text_mail: plain text only (no HTML) + permission_view_files: View files + permission_edit_issues: Edit issues + permission_edit_own_time_entries: Edit own time logs + permission_manage_public_queries: Manage public queries + permission_add_issues: Add issues + permission_log_time: Log spent time + permission_view_changesets: View changesets + permission_view_time_entries: View spent time + permission_manage_versions: Manage versions + permission_manage_wiki: Manage wiki + permission_manage_categories: Manage issue categories + permission_protect_wiki_pages: Protect wiki pages + permission_comment_news: Comment news + permission_delete_messages: Delete messages + permission_select_project_modules: Select project modules + permission_edit_wiki_pages: Edit wiki pages + permission_add_issue_watchers: Add watchers + permission_view_gantt: View gantt chart + permission_move_issues: Move issues + permission_manage_issue_relations: Manage issue relations + permission_delete_wiki_pages: Delete wiki pages + permission_manage_boards: Manage boards + permission_delete_wiki_pages_attachments: Delete attachments + permission_view_wiki_edits: View wiki history + permission_add_messages: Post messages + permission_view_messages: View messages + permission_manage_files: Manage files + permission_edit_issue_notes: Edit notes + permission_manage_news: Manage news + permission_view_calendar: View calendrier + permission_manage_members: Manage members + permission_edit_messages: Edit messages + permission_delete_issues: Delete issues + permission_view_issue_watchers: View watchers list + permission_manage_repository: Manage repository + permission_commit_access: Commit access + permission_browse_repository: Browse repository + permission_view_documents: View documents + permission_edit_project: Edit project + permission_add_issue_notes: Add notes + permission_save_queries: Save queries + permission_view_wiki_pages: View wiki + permission_rename_wiki_pages: Rename wiki pages + permission_edit_time_entries: Edit time logs + permission_edit_own_issue_notes: Edit own notes + setting_gravatar_enabled: Use Gravatar user icons + label_example: Example + text_repository_usernames_mapping: "Select ou update the Redmine user mapped to each username found in the repository log.\nUsers with the same Redmine and repository username or email are automatically mapped." + permission_edit_own_messages: Edit own messages + permission_delete_own_messages: Delete own messages + label_user_activity: "%{value}'s activity" + label_updated_time_by: "Updated by %{author} %{age} ago" + text_diff_truncated: '... This diff was truncated because it exceeds the maximum size that can be displayed.' + setting_diff_max_lines_displayed: Max number of diff lines displayed + text_plugin_assets_writable: Plugin assets directory writable + warning_attachments_not_saved: "%{count} file(s) could not be saved." + button_create_and_continue: Create and continue + text_custom_field_possible_values_info: 'One line for each value' + label_display: Display + field_editable: Editable + setting_repository_log_display_limit: Maximum number of revisions displayed on file log + setting_file_max_size_displayed: Max size of text files displayed inline + field_watcher: Watcher + setting_openid: Allow OpenID login and registration + field_identity_url: OpenID URL + label_login_with_open_id_option: or login with OpenID + field_content: Content + label_descending: Descending + label_sort: Sort + label_ascending: Ascending + label_date_from_to: From %{start} to %{end} + label_greater_or_equal: ">=" + label_less_or_equal: <= + text_wiki_page_destroy_question: This page has %{descendants} child page(s) and descendant(s). What do you want to do? + text_wiki_page_reassign_children: Reassign child pages to this parent page + text_wiki_page_nullify_children: Keep child pages as root pages + text_wiki_page_destroy_children: Delete child pages and all their descendants + setting_password_min_length: Minimum password length + field_group_by: Group results by + mail_subject_wiki_content_updated: "'%{id}' wiki page has been updated" + label_wiki_content_added: Wiki page added + mail_subject_wiki_content_added: "'%{id}' wiki page has been added" + mail_body_wiki_content_added: The '%{id}' wiki page has been added by %{author}. + label_wiki_content_updated: Wiki page updated + mail_body_wiki_content_updated: The '%{id}' wiki page has been updated by %{author}. + permission_add_project: Create project + setting_new_project_user_role_id: Role given to a non-admin user who creates a project + label_view_all_revisions: View all revisions + label_tag: Tag + label_branch: Branch + error_no_tracker_in_project: No tracker is associated to this project. Please check the Project settings. + error_no_default_issue_status: No default issue status is defined. Please check your configuration (Go to "Administration -> Issue statuses"). + text_journal_changed: "%{label} changed from %{old} to %{new}" + text_journal_set_to: "%{label} set to %{value}" + text_journal_deleted: "%{label} deleted (%{old})" + label_group_plural: Groups + label_group: Group + label_group_new: New group + label_time_entry_plural: Spent time + text_journal_added: "%{label} %{value} added" + field_active: Active + enumeration_system_activity: System Activity + permission_delete_issue_watchers: Delete watchers + version_status_closed: closed + version_status_locked: locked + version_status_open: open + error_can_not_reopen_issue_on_closed_version: An issue assigned to a closed version can not be reopened + label_user_anonymous: Anonymous + button_move_and_follow: Move and follow + setting_default_projects_modules: Default enabled modules for new projects + setting_gravatar_default: Default Gravatar image + field_sharing: Sharing + label_version_sharing_hierarchy: With project hierarchy + label_version_sharing_system: With all projects + label_version_sharing_descendants: With subprojects + label_version_sharing_tree: With project tree + label_version_sharing_none: Not shared + error_can_not_archive_project: This project can not be archived + button_duplicate: Duplicate + button_copy_and_follow: Copy and follow + label_copy_source: Source + setting_issue_done_ratio: Calculate the issue done ratio with + setting_issue_done_ratio_issue_status: Use the issue status + error_issue_done_ratios_not_updated: Issue done ratios not updated. + error_workflow_copy_target: Please select target tracker(s) and role(s) + setting_issue_done_ratio_issue_field: Use the issue field + label_copy_same_as_target: Same as target + label_copy_target: Target + notice_issue_done_ratios_updated: Issue done ratios updated. + error_workflow_copy_source: Please select a source tracker or role + label_update_issue_done_ratios: Update issue done ratios + setting_start_of_week: Start calendars on + permission_view_issues: View Issues + label_display_used_statuses_only: Only display statuses that are used by this tracker + label_revision_id: Revision %{value} + label_api_access_key: API access key + label_api_access_key_created_on: API access key created %{value} ago + label_feeds_access_key: RSS access key + notice_api_access_key_reseted: Your API access key was reset. + setting_rest_api_enabled: Enable REST web service + label_missing_api_access_key: Missing an API access key + label_missing_feeds_access_key: Missing a RSS access key + button_show: Show + text_line_separated: Multiple values allowed (one line for each value). + setting_mail_handler_body_delimiters: Truncate emails after one of these lines + permission_add_subprojects: Create subprojects + label_subproject_new: New subproject + text_own_membership_delete_confirmation: |- + You are about to remove some or all of your permissions and may no longer be able to edit this project after that. + Are you sure you want to continue? + label_close_versions: Close completed versions + label_board_sticky: Sticky + label_board_locked: Locked + permission_export_wiki_pages: Export wiki pages + setting_cache_formatted_text: Cache formatted text + permission_manage_project_activities: Manage project activities + error_unable_delete_issue_status: Unable to delete issue status + label_profile: Profile + permission_manage_subtasks: Manage subtasks + field_parent_issue: Parent task + label_subtask_plural: Subtasks + label_project_copy_notifications: Send email notifications during the project copy + error_can_not_delete_custom_field: Unable to delete custom field + error_unable_to_connect: Unable to connect (%{value}) + error_can_not_remove_role: This role is in use and can not be deleted. + error_can_not_delete_tracker: This tracker contains issues and can't be deleted. + field_principal: Principal + label_my_page_block: My page block + notice_failed_to_save_members: "Failed to save member(s): %{errors}." + text_zoom_out: Zoom out + text_zoom_in: Zoom in + notice_unable_delete_time_entry: Unable to delete time log entry. + label_overall_spent_time: Overall spent time + field_time_entries: Log time + project_module_gantt: Gantt + project_module_calendar: Calendar + button_edit_associated_wikipage: "Edit associated Wiki page: %{page_title}" + field_text: Text field + label_user_mail_option_only_owner: Only for things I am the owner of + setting_default_notification_option: Default notification option + label_user_mail_option_only_my_events: Only for things I watch or I'm involved in + label_user_mail_option_only_assigned: Only for things I am assigned to + label_user_mail_option_none: No events + field_member_of_group: Assignee's group + field_assigned_to_role: Assignee's role + notice_not_authorized_archived_project: The project you're trying to access has been archived. + label_principal_search: "Search for user or group:" + label_user_search: "Search for user:" + field_visible: Visible + setting_commit_logtime_activity_id: Activity for logged time + text_time_logged_by_changeset: Applied in changeset %{value}. + setting_commit_logtime_enabled: Enable time logging + notice_gantt_chart_truncated: The chart was truncated because it exceeds the maximum number of items that can be displayed (%{max}) + setting_gantt_items_limit: Maximum number of items displayed on the gantt chart + field_warn_on_leaving_unsaved: Warn me when leaving a page with unsaved text + text_warn_on_leaving_unsaved: The current page contains unsaved text that will be lost if you leave this page. + label_my_queries: My custom queries + text_journal_changed_no_detail: "%{label} updated" + label_news_comment_added: Comment added to a news + button_expand_all: Expand all + button_collapse_all: Collapse all + label_additional_workflow_transitions_for_assignee: Additional transitions allowed when the user is the assignee + label_additional_workflow_transitions_for_author: Additional transitions allowed when the user is the author + label_bulk_edit_selected_time_entries: Bulk edit selected time entries + text_time_entries_destroy_confirmation: Are you sure you want to delete the selected time entr(y/ies)? + label_role_anonymous: Anonymous + label_role_non_member: Non member + label_issue_note_added: Note added + label_issue_status_updated: Status updated + label_issue_priority_updated: Priority updated + label_issues_visibility_own: Issues created by or assigned to the user + field_issues_visibility: Issues visibility + label_issues_visibility_all: All issues + permission_set_own_issues_private: Set own issues public or private + field_is_private: Private + permission_set_issues_private: Set issues public or private + label_issues_visibility_public: All non private issues + text_issues_destroy_descendants_confirmation: This will also delete %{count} subtask(s). + field_commit_logs_encoding: Commit messages encoding + field_scm_path_encoding: Path encoding + text_scm_path_encoding_note: "Default: UTF-8" + field_path_to_repository: Path to repository + field_root_directory: Root directory + field_cvs_module: Module + field_cvsroot: CVSROOT + text_mercurial_repository_note: Local repository (e.g. /hgrepo, c:\hgrepo) + text_scm_command: Command + text_scm_command_version: Version + label_git_report_last_commit: Report last commit for files and directories + notice_issue_successful_create: Issue %{id} created. + label_between: between + setting_issue_group_assignment: Allow issue assignment to groups + label_diff: diff + text_git_repository_note: Repository is bare and local (e.g. /gitrepo, c:\gitrepo) + description_query_sort_criteria_direction: Sort direction + description_project_scope: Search scope + description_filter: Filter + description_user_mail_notification: Mail notification settings + description_date_from: Enter start date + description_message_content: Message content + description_available_columns: Available Columns + description_date_range_interval: Choose range by selecting start and end date + description_issue_category_reassign: Choose issue category + description_search: Searchfield + description_notes: Notes + description_date_range_list: Choose range from list + description_choose_project: Projects + description_date_to: Enter end date + description_query_sort_criteria_attribute: Sort attribute + description_wiki_subpages_reassign: Choose new parent page + description_selected_columns: Selected Columns + label_parent_revision: Parent + label_child_revision: Child + error_scm_annotate_big_text_file: The entry cannot be annotated, as it exceeds the maximum text file size. + setting_default_issue_start_date_to_creation_date: Use current date as start date for new issues + button_edit_section: Edit this section + setting_repositories_encodings: Attachments and repositories encodings + description_all_columns: All Columns + button_export: Export + label_export_options: "%{export_format} export options" + error_attachment_too_big: This file cannot be uploaded because it exceeds the maximum allowed file size (%{max_size}) + notice_failed_to_save_time_entries: "Failed to save %{count} time entrie(s) on %{total} selected: %{ids}." + label_x_issues: + zero: 0 ปัญหา + one: 1 ปัญหา + other: "%{count} ปัญหา" + label_repository_new: New repository + field_repository_is_default: Main repository + label_copy_attachments: Copy attachments + label_item_position: "%{position}/%{count}" + label_completed_versions: Completed versions + text_project_identifier_info: Only lower case letters (a-z), numbers, dashes and underscores are allowed.
    Once saved, the identifier cannot be changed. + field_multiple: Multiple values + setting_commit_cross_project_ref: Allow issues of all the other projects to be referenced and fixed + text_issue_conflict_resolution_add_notes: Add my notes and discard my other changes + text_issue_conflict_resolution_overwrite: Apply my changes anyway (previous notes will be kept but some changes may be overwritten) + notice_issue_update_conflict: The issue has been updated by an other user while you were editing it. + text_issue_conflict_resolution_cancel: Discard all my changes and redisplay %{link} + permission_manage_related_issues: Manage related issues + field_auth_source_ldap_filter: LDAP filter + label_search_for_watchers: Search for watchers to add + notice_account_deleted: Your account has been permanently deleted. + setting_unsubscribe: Allow users to delete their own account + button_delete_my_account: Delete my account + text_account_destroy_confirmation: |- + Are you sure you want to proceed? + Your account will be permanently deleted, with no way to reactivate it. + error_session_expired: Your session has expired. Please login again. + text_session_expiration_settings: "Warning: changing these settings may expire the current sessions including yours." + setting_session_lifetime: Session maximum lifetime + setting_session_timeout: Session inactivity timeout + label_session_expiration: Session expiration + permission_close_project: Close / reopen the project + label_show_closed_projects: View closed projects + button_close: Close + button_reopen: Reopen + project_status_active: active + project_status_closed: closed + project_status_archived: archived + text_project_closed: This project is closed and read-only. + notice_user_successful_create: User %{id} created. + field_core_fields: Standard fields + field_timeout: Timeout (in seconds) + setting_thumbnails_enabled: Display attachment thumbnails + setting_thumbnails_size: Thumbnails size (in pixels) + label_status_transitions: Status transitions + label_fields_permissions: Fields permissions + label_readonly: Read-only + label_required: Required + text_repository_identifier_info: Only lower case letters (a-z), numbers, dashes and underscores are allowed.
    Once saved, the identifier cannot be changed. + field_board_parent: Parent forum + label_attribute_of_project: Project's %{name} + label_attribute_of_author: Author's %{name} + label_attribute_of_assigned_to: Assignee's %{name} + label_attribute_of_fixed_version: Target version's %{name} + label_copy_subtasks: Copy subtasks + label_copied_to: copied to + label_copied_from: copied from + label_any_issues_in_project: any issues in project + label_any_issues_not_in_project: any issues not in project + field_private_notes: Private notes + permission_view_private_notes: View private notes + permission_set_notes_private: Set notes as private + label_no_issues_in_project: no issues in project + label_any: ทั้งหมด + label_last_n_weeks: last %{count} weeks + setting_cross_project_subtasks: Allow cross-project subtasks + label_cross_project_descendants: With subprojects + label_cross_project_tree: With project tree + label_cross_project_hierarchy: With project hierarchy + label_cross_project_system: With all projects + button_hide: Hide + setting_non_working_week_days: Non-working days + label_in_the_next_days: in the next + label_in_the_past_days: in the past + label_attribute_of_user: User's %{name} + text_turning_multiple_off: If you disable multiple values, multiple values will be + removed in order to preserve only one value per item. + label_attribute_of_issue: Issue's %{name} + permission_add_documents: Add documents + permission_edit_documents: Edit documents + permission_delete_documents: Delete documents + label_gantt_progress_line: Progress line + setting_jsonp_enabled: Enable JSONP support + field_inherit_members: Inherit members + field_closed_on: Closed + setting_default_projects_tracker_ids: Default trackers for new projects + label_total_time: จำนวนรวม + text_scm_config: You can configure your SCM commands in config/configuration.yml. Please restart the application after editing it. + text_scm_command_not_available: SCM command is not available. Please check settings on the administration panel. + setting_emails_header: Email header diff --git a/config/locales/tr.yml b/config/locales/tr.yml new file mode 100644 index 00000000..757af1a9 --- /dev/null +++ b/config/locales/tr.yml @@ -0,0 +1,1108 @@ +# Turkish translations for Ruby on Rails +# by Ozgun Ataman (ozataman@gmail.com) +# by Burak Yigit Kaya (ben@byk.im) + +tr: + locale: + native_name: Türkçe + address_separator: " " + direction: ltr + date: + formats: + default: "%d.%m.%Y" + numeric: "%d.%m.%Y" + short: "%e %b" + long: "%e %B %Y, %A" + only_day: "%e" + + day_names: [Pazar, Pazartesi, Salı, Çarşamba, Perşembe, Cuma, Cumartesi] + abbr_day_names: [Pzr, Pzt, Sal, Çrş, Prş, Cum, Cts] + month_names: [~, Ocak, Şubat, Mart, Nisan, Mayıs, Haziran, Temmuz, Ağustos, Eylül, Ekim, Kasım, Aralık] + abbr_month_names: [~, Oca, Şub, Mar, Nis, May, Haz, Tem, Ağu, Eyl, Eki, Kas, Ara] + order: + - :day + - :month + - :year + + time: + formats: + default: "%a %d.%b.%y %H:%M" + numeric: "%d.%b.%y %H:%M" + short: "%e %B, %H:%M" + long: "%e %B %Y, %A, %H:%M" + time: "%H:%M" + + am: "öğleden önce" + pm: "öğleden sonra" + + datetime: + distance_in_words: + half_a_minute: 'yarım dakika' + less_than_x_seconds: + zero: '1 saniyeden az' + one: '1 saniyeden az' + other: '%{count} saniyeden az' + x_seconds: + one: '1 saniye' + other: '%{count} saniye' + less_than_x_minutes: + zero: '1 dakikadan az' + one: '1 dakikadan az' + other: '%{count} dakikadan az' + x_minutes: + one: '1 dakika' + other: '%{count} dakika' + about_x_hours: + one: 'yaklaşık 1 saat' + other: 'yaklaşık %{count} saat' + x_hours: + one: "1 hour" + other: "%{count} hours" + x_days: + one: '1 gün' + other: '%{count} gün' + about_x_months: + one: 'yaklaşık 1 ay' + other: 'yaklaşık %{count} ay' + x_months: + one: '1 ay' + other: '%{count} ay' + about_x_years: + one: 'yaklaşık 1 yıl' + other: 'yaklaşık %{count} yıl' + over_x_years: + one: '1 yıldan fazla' + other: '%{count} yıldan fazla' + almost_x_years: + one: "neredeyse 1 Yıl" + other: "neredeyse %{count} yıl" + + number: + format: + precision: 2 + separator: ',' + delimiter: '.' + currency: + format: + unit: 'TRY' + format: '%n%u' + separator: ',' + delimiter: '.' + precision: 2 + percentage: + format: + delimiter: '.' + separator: ',' + precision: 2 + precision: + format: + delimiter: '.' + separator: ',' + human: + format: + delimiter: '.' + separator: ',' + precision: 3 + storage_units: + format: "%n %u" + units: + byte: + one: "Byte" + other: "Byte" + kb: "KB" + mb: "MB" + gb: "GB" + tb: "TB" + + support: + array: + sentence_connector: "ve" + skip_last_comma: true + + activerecord: + errors: + template: + header: + one: "%{model} girişi kaydedilemedi: 1 hata." + other: "%{model} girişi kadedilemedi: %{count} hata." + body: "Lütfen aşağıdaki hataları düzeltiniz:" + + messages: + inclusion: "kabul edilen bir kelime değil" + exclusion: "kullanılamaz" + invalid: "geçersiz" + confirmation: "teyidi uyuşmamakta" + accepted: "kabul edilmeli" + empty: "doldurulmalı" + blank: "doldurulmalı" + too_long: "çok uzun (en fazla %{count} karakter)" + too_short: "çok kısa (en az %{count} karakter)" + wrong_length: "yanlış uzunlukta (tam olarak %{count} karakter olmalı)" + taken: "hali hazırda kullanılmakta" + not_a_number: "geçerli bir sayı değil" + greater_than: "%{count} sayısından büyük olmalı" + greater_than_or_equal_to: "%{count} sayısına eşit veya büyük olmalı" + equal_to: "tam olarak %{count} olmalı" + less_than: "%{count} sayısından küçük olmalı" + less_than_or_equal_to: "%{count} sayısına eşit veya küçük olmalı" + odd: "tek olmalı" + even: "çift olmalı" + greater_than_start_date: "başlangıç tarihinden büyük olmalı" + not_same_project: "aynı projeye ait değil" + circular_dependency: "Bu ilişki döngüsel bağımlılık meydana getirecektir" + cant_link_an_issue_with_a_descendant: "Bir iş, alt işlerinden birine bağlanamaz" + models: + + actionview_instancetag_blank_option: Lütfen Seçin + + general_text_No: 'Hayır' + general_text_Yes: 'Evet' + general_text_no: 'hayır' + general_text_yes: 'evet' + general_lang_name: 'Türkçe' + general_csv_separator: ',' + general_csv_encoding: ISO-8859-9 + general_pdf_encoding: UTF-8 + general_first_day_of_week: '7' + + notice_account_updated: Hesap başarıyla güncelleştirildi. + notice_account_invalid_creditentials: Geçersiz kullanıcı ya da parola + notice_account_password_updated: Parola başarıyla güncellendi. + notice_account_wrong_password: Yanlış parola + notice_account_register_done: Hesap başarıyla oluşturuldu. Hesabınızı etkinleştirmek için, size gönderilen e-postadaki bağlantıya tıklayın. + notice_account_unknown_email: Tanınmayan kullanıcı. + notice_can_t_change_password: Bu hesap harici bir denetim kaynağı kullanıyor. Parolayı değiştirmek mümkün değil. + notice_account_lost_email_sent: Yeni parola seçme talimatlarını içeren e-postanız gönderildi. + notice_account_activated: Hesabınız etkinleştirildi. Şimdi giriş yapabilirsiniz. + notice_successful_create: Başarıyla oluşturuldu. + notice_successful_update: Başarıyla güncellendi. + notice_successful_delete: Başarıyla silindi. + notice_successful_connection: Bağlantı başarılı. + notice_file_not_found: Erişmek istediğiniz sayfa mevcut değil ya da kaldırılmış. + notice_locking_conflict: Veri başka bir kullanıcı tarafından güncellendi. + notice_not_authorized: Bu sayfaya erişme yetkiniz yok. + notice_email_sent: "E-posta gönderildi %{value}" + notice_email_error: "E-posta gönderilirken bir hata oluştu (%{value})" + notice_feeds_access_key_reseted: RSS erişim anahtarınız sıfırlandı. + notice_failed_to_save_issues: "Failed to save %{count} issue(s) on %{total} selected: %{ids}." + notice_no_issue_selected: "Seçili iş yok! Lütfen, düzenlemek istediğiniz işleri işaretleyin." + notice_account_pending: "Hesabınız oluşturuldu ve yönetici onayı bekliyor." + notice_default_data_loaded: Varasayılan konfigürasyon başarılıyla yüklendi. + + error_can_t_load_default_data: "Varsayılan konfigürasyon yüklenemedi: %{value}" + error_scm_not_found: "Depoda, giriş ya da değişiklik yok." + error_scm_command_failed: "Depoya erişmeye çalışırken bir hata meydana geldi: %{value}" + error_scm_annotate: "Giriş mevcut değil veya izah edilemedi." + error_issue_not_found_in_project: 'İş bilgisi bulunamadı veya bu projeye ait değil' + + mail_subject_lost_password: "Parolanız %{value}" + mail_body_lost_password: 'Parolanızı değiştirmek için, aşağıdaki bağlantıya tıklayın:' + mail_subject_register: "%{value} hesap aktivasyonu" + mail_body_register: 'Hesabınızı etkinleştirmek için, aşağıdaki bağlantıya tıklayın:' + mail_body_account_information_external: "Hesabınızı %{value} giriş yapmak için kullanabilirsiniz." + mail_body_account_information: Hesap bilgileriniz + mail_subject_account_activation_request: "%{value} hesabı etkinleştirme isteği" + mail_body_account_activation_request: "Yeni bir kullanıcı (%{value}) kaydedildi. Hesap onaylanmayı bekliyor:" + + + field_name: İsim + field_description: Yorum + field_summary: Özet + field_is_required: Gerekli + field_firstname: Ad + field_lastname: Soyad + field_mail: E-Posta + field_filename: Dosya + field_filesize: Boyut + field_downloads: İndirilenler + field_author: Yazar + field_created_on: Oluşturulma + field_updated_on: Güncellenme + field_field_format: Biçim + field_is_for_all: Tüm projeler için + field_possible_values: Kullanılabilir değerler + field_regexp: Düzenli ifadeler + field_min_length: En az uzunluk + field_max_length: En çok uzunluk + field_value: Değer + field_category: Kategori + field_title: Başlık + field_project: Proje + field_issue: İş + field_status: Durum + field_notes: Notlar + field_is_closed: İş kapatıldı + field_is_default: Varsayılan Değer + field_tracker: İş tipi + field_subject: Konu + field_due_date: Bitiş Tarihi + field_assigned_to: Atanan + field_priority: Öncelik + field_fixed_version: Hedef Sürüm + field_user: Kullanıcı + field_role: Rol + field_homepage: Anasayfa + field_is_public: Genel + field_parent: 'Üst proje: ' + field_is_in_roadmap: Yol haritasında gösterilen işler + field_login: Giriş + field_mail_notification: E-posta uyarıları + field_admin: Yönetici + field_last_login_on: Son Bağlantı + field_language: Dil + field_effective_date: Tarih + field_password: Parola + field_new_password: Yeni Parola + field_password_confirmation: Onay + field_version: Sürüm + field_type: Tip + field_host: Host + field_port: Port + field_account: Hesap + field_base_dn: Base DN + field_attr_login: Giriş Niteliği + field_attr_firstname: Ad Niteliği + field_attr_lastname: Soyad Niteliği + field_attr_mail: E-Posta Niteliği + field_onthefly: Anında kullanıcı oluşturma + field_start_date: Başlangıç Tarihi + field_done_ratio: Tamamlanma yüzdesi + field_auth_source: Kimlik Denetim Modu + field_hide_mail: E-posta adresimi gizle + field_comments: Yorumlar + field_url: URL + field_start_page: Başlangıç Sayfası + field_subproject: Alt Proje + field_hours: Saat + field_activity: Etkinlik + field_spent_on: Tarih + field_identifier: Tanımlayıcı + field_is_filter: filtre olarak kullanılmış + field_issue_to: İlişkili iş + field_delay: Gecikme + field_assignable: Bu role atanabilecek işler + field_redirect_existing_links: Mevcut bağlantıları yönlendir + field_estimated_hours: Kalan zaman + field_column_names: Sütunlar + field_time_zone: Saat dilimi + field_searchable: Aranabilir + field_default_value: Varsayılan değer + field_comments_sorting: Yorumları göster + + setting_app_title: Uygulama Bağlığı + setting_app_subtitle: Uygulama alt başlığı + setting_welcome_text: Hoşgeldin Mesajı + setting_default_language: Varsayılan Dil + setting_login_required: Kimlik denetimi gerekli mi + setting_self_registration: Otomatik kayıt + setting_attachment_max_size: Maksimum ek boyutu + setting_issues_export_limit: İşlerin dışa aktarılma sınırı + setting_mail_from: Gönderici e-posta adresi + setting_bcc_recipients: Alıcıları birbirinden gizle (bcc) + setting_host_name: Host adı + setting_text_formatting: Metin biçimi + setting_wiki_compression: Wiki geçmişini sıkıştır + setting_feeds_limit: Haber yayını içerik limiti + setting_default_projects_public: Yeni projeler varsayılan olarak herkese açık + setting_autofetch_changesets: Otomatik gönderi al + setting_sys_api_enabled: Depo yönetimi için WS'yi etkinleştir + setting_commit_ref_keywords: Başvuru Kelimeleri + setting_commit_fix_keywords: Sabitleme kelimeleri + setting_autologin: Otomatik Giriş + setting_date_format: Tarih Formati + setting_time_format: Zaman Formatı + setting_cross_project_issue_relations: Çapraz-Proje iş ilişkilendirmesine izin ver + setting_issue_list_default_columns: İş listesinde gösterilen varsayılan sütunlar + setting_emails_footer: E-posta dip not + setting_protocol: Protokol + setting_per_page_options: Sayfada başına öğe sayısı + setting_user_format: Kullanıcı gösterim biçimi + setting_activity_days_default: Proje etkinliklerinde gösterilen gün sayısı + setting_display_subprojects_issues: Varsayılan olarak ana projenin iş listesinde alt proje işlerini göster + + project_module_issue_tracking: İş Takibi + project_module_time_tracking: Zaman Takibi + project_module_news: Haberler + project_module_documents: Belgeler + project_module_files: Dosyalar + project_module_wiki: Wiki + project_module_repository: Depo + project_module_boards: Tartışma Alanı + + label_user: Kullanıcı + label_user_plural: Kullanıcılar + label_user_new: Yeni Kullanıcı + label_project: Proje + label_project_new: Yeni proje + label_project_plural: Projeler + label_x_projects: + zero: hiç proje yok + one: 1 proje + other: "%{count} proje" + label_project_all: Tüm Projeler + label_project_latest: En son projeler + label_issue: İş + label_issue_new: Yeni İş + label_issue_plural: İşler + label_issue_view_all: Tüm işleri izle + label_issues_by: "%{value} tarafından gönderilmiş işler" + label_issue_added: İş eklendi + label_issue_updated: İş güncellendi + label_document: Belge + label_document_new: Yeni belge + label_document_plural: Belgeler + label_document_added: Belge eklendi + label_role: Rol + label_role_plural: Roller + label_role_new: Yeni rol + label_role_and_permissions: Roller ve izinler + label_member: Üye + label_member_new: Yeni üye + label_member_plural: Üyeler + label_tracker: İş tipi + label_tracker_plural: İş tipleri + label_tracker_new: Yeni iş tipi + label_workflow: İş akışı + label_issue_status: İş durumu + label_issue_status_plural: İş durumuları + label_issue_status_new: Yeni durum + label_issue_category: İş kategorisi + label_issue_category_plural: İş kategorileri + label_issue_category_new: Yeni kategori + label_custom_field: Özel alan + label_custom_field_plural: Özel alanlar + label_custom_field_new: Yeni özel alan + label_enumerations: Numaralandırmalar + label_enumeration_new: Yeni değer + label_information: Bilgi + label_information_plural: Bilgi + label_please_login: Lütfen giriş yapın + label_register: Kayıt + label_password_lost: Parolamı unuttum + label_home: Anasayfa + label_my_page: Kişisel Sayfam + label_my_account: Hesabım + label_my_projects: Projelerim + label_administration: Yönetim + label_login: Giriş + label_logout: Çıkış + label_help: Yardım + label_reported_issues: Rapor edilmiş işler + label_assigned_to_me_issues: Bana atanmış işler + label_last_login: Son bağlantı + label_registered_on: Kayıt tarihi + label_activity: Etkinlik + label_overall_activity: Tüm etkinlikler + label_new: Yeni + label_logged_as: "Kullanıcı :" + label_environment: Çevre + label_authentication: Kimlik Denetimi + label_auth_source: Kimlik Denetim Modu + label_auth_source_new: Yeni Denetim Modu + label_auth_source_plural: Denetim Modları + label_subproject_plural: Alt Projeler + label_min_max_length: Min - Maks uzunluk + label_list: Liste + label_date: Tarih + label_integer: Tam sayı + label_float: Ondalıklı sayı + label_boolean: "Evet/Hayır" + label_string: Metin + label_text: Uzun Metin + label_attribute: Nitelik + label_attribute_plural: Nitelikler + label_no_data: Gösterilecek veri yok + label_change_status: Değişim Durumu + label_history: Geçmiş + label_attachment: Dosya + label_attachment_new: Yeni Dosya + label_attachment_delete: Dosyayı Sil + label_attachment_plural: Dosyalar + label_file_added: Eklenen Dosyalar + label_report: Rapor + label_report_plural: Raporlar + label_news: Haber + label_news_new: Haber ekle + label_news_plural: Haber + label_news_latest: Son Haberler + label_news_view_all: Tüm haberleri oku + label_news_added: Haber eklendi + label_settings: Ayarlar + label_overview: Genel + label_version: Sürüm + label_version_new: Yeni sürüm + label_version_plural: Sürümler + label_confirmation: Doğrulamama + label_export_to: "Diğer uygun kaynaklar:" + label_read: "Oku..." + label_public_projects: Genel Projeler + label_open_issues: açık + label_open_issues_plural: açık + label_closed_issues: kapalı + label_closed_issues_plural: kapalı + label_x_open_issues_abbr_on_total: + zero: tamamı kapalı, toplam %{total} + one: 1'i' açık, toplam %{total} + other: "%{count} açık, toplam %{total}" + label_x_open_issues_abbr: + zero: hiç açık yok + one: 1 açık + other: "%{count} açık" + label_x_closed_issues_abbr: + zero: hiç kapalı yok + one: 1 kapalı + other: "%{count} kapalı" + label_total: Toplam + label_permissions: İzinler + label_current_status: Mevcut Durum + label_new_statuses_allowed: Yeni durumlara izin verildi + label_all: Hepsi + label_none: Hiçbiri + label_nobody: Hiçkimse + label_next: Sonraki + label_previous: Önceki + label_used_by: 'Kullanan: ' + label_details: Ayrıntılar + label_add_note: Not ekle + label_per_page: Sayfa başına + label_calendar: Takvim + label_months_from: ay öncesinden itibaren + label_gantt: İş-Zaman Çizelgesi + label_internal: Dahili + label_last_changes: "Son %{count} değişiklik" + label_change_view_all: Tüm Değişiklikleri gör + label_personalize_page: Bu sayfayı kişiselleştir + label_comment: Yorum + label_comment_plural: Yorumlar + label_x_comments: + zero: hiç yorum yok + one: 1 yorum + other: "%{count} yorum" + label_comment_add: Yorum Ekle + label_comment_added: Yorum Eklendi + label_comment_delete: Yorumları sil + label_query: Özel Sorgu + label_query_plural: Özel Sorgular + label_query_new: Yeni Sorgu + label_filter_add: Filtre ekle + label_filter_plural: Filtreler + label_equals: Eşit + label_not_equals: Eşit değil + label_in_less_than: küçüktür + label_in_more_than: büyüktür + label_in: içinde + label_today: bugün + label_all_time: Tüm Zamanlar + label_yesterday: Dün + label_this_week: Bu hafta + label_last_week: Geçen hafta + label_last_n_days: "Son %{count} gün" + label_this_month: Bu ay + label_last_month: Geçen ay + label_this_year: Bu yıl + label_date_range: Tarih aralığı + label_less_than_ago: günler öncesinden az + label_more_than_ago: günler öncesinden fazla + label_ago: gün önce + label_contains: içeriyor + label_not_contains: içermiyor + label_day_plural: Günler + label_repository: Depo + label_repository_plural: Depolar + label_browse: Gözat + label_revision: Değişiklik + label_revision_plural: Değişiklikler + label_associated_revisions: Birleştirilmiş değişiklikler + label_added: eklendi + label_modified: güncellendi + label_deleted: silindi + label_latest_revision: En son değişiklik + label_latest_revision_plural: En son değişiklikler + label_view_revisions: Değişiklikleri izle + label_max_size: En büyük boyut + label_sort_highest: Üste taşı + label_sort_higher: Yukarı taşı + label_sort_lower: Aşağı taşı + label_sort_lowest: Dibe taşı + label_roadmap: Yol Haritası + label_roadmap_due_in: "%{value} içinde bitmeli" + label_roadmap_overdue: "%{value} geç" + label_roadmap_no_issues: Bu sürüm için iş yok + label_search: Ara + label_result_plural: Sonuçlar + label_all_words: Tüm Kelimeler + label_wiki: Wiki + label_wiki_edit: Wiki düzenleme + label_wiki_edit_plural: Wiki düzenlemeleri + label_wiki_page: Wiki sayfası + label_wiki_page_plural: Wiki sayfaları + label_index_by_title: Başlığa göre diz + label_index_by_date: Tarihe göre diz + label_current_version: Güncel sürüm + label_preview: Önizleme + label_feed_plural: Beslemeler + label_changes_details: Bütün değişikliklerin detayları + label_issue_tracking: İş Takibi + label_spent_time: Harcanan zaman + label_f_hour: "%{value} saat" + label_f_hour_plural: "%{value} saat" + label_time_tracking: Zaman Takibi + label_change_plural: Değişiklikler + label_statistics: İstatistikler + label_commits_per_month: Aylık teslim + label_commits_per_author: Yazar başına teslim + label_view_diff: Farkları izle + label_diff_inline: satır içi + label_diff_side_by_side: Yan yana + label_options: Tercihler + label_copy_workflow_from: İşakışı kopyala + label_permissions_report: İzin raporu + label_watched_issues: İzlenmiş işler + label_related_issues: İlişkili işler + label_applied_status: uygulanmış işler + label_loading: Yükleniyor... + label_relation_new: Yeni ilişki + label_relation_delete: İlişkiyi sil + label_relates_to: ilişkili + label_duplicates: yinelenmiş + label_blocks: Engeller + label_blocked_by: Engelleyen + label_precedes: önce gelir + label_follows: sonra gelir + label_end_to_start: sondan başa + label_end_to_end: sondan sona + label_start_to_start: baştan başa + label_start_to_end: baştan sona + label_stay_logged_in: Sürekli bağlı kal + label_disabled: Devredışı + label_show_completed_versions: Tamamlanmış sürümleri göster + label_me: Ben + label_board: Tartışma Alanı + label_board_new: Yeni alan + label_board_plural: Tartışma alanları + label_topic_plural: Konular + label_message_plural: Mesajlar + label_message_last: Son mesaj + label_message_new: Yeni mesaj + label_message_posted: Mesaj eklendi + label_reply_plural: Cevaplar + label_send_information: Hesap bilgisini kullanıcıya gönder + label_year: Yıl + label_month: Ay + label_week: Hafta + label_date_from: Başlangıç + label_date_to: Bitiş + label_language_based: Kullanıcı dili bazlı + label_sort_by: "%{value} göre sırala" + label_send_test_email: Test e-postası gönder + label_feeds_access_key_created_on: "RSS erişim anahtarı %{value} önce oluşturuldu" + label_module_plural: Modüller + label_added_time_by: "%{author} tarafından %{age} önce eklendi" + label_updated_time: "%{value} önce güncellendi" + label_jump_to_a_project: Projeye git... + label_file_plural: Dosyalar + label_changeset_plural: Değişiklik Listeleri + label_default_columns: Varsayılan Sütunlar + label_no_change_option: (Değişiklik yok) + label_bulk_edit_selected_issues: Seçili işleri toplu olarak düzenle + label_theme: Tema + label_default: Varsayılan + label_search_titles_only: Sadece başlıkları ara + label_user_mail_option_all: "Tüm projelerimdeki herhangi bir olay için" + label_user_mail_option_selected: "Sadece seçili projelerdeki herhangi bir olay için" + label_user_mail_no_self_notified: "Kendi yaptığım değişikliklerden haberdar olmak istemiyorum" + label_registration_activation_by_email: e-posta ile hesap etkinleştirme + label_registration_manual_activation: Elle hesap etkinleştirme + label_registration_automatic_activation: Otomatik hesap etkinleştirme + label_display_per_page: "Sayfa başına: %{value}" + label_age: Yaş + label_change_properties: Özellikleri değiştir + label_general: Genel + label_more: Daha fazla + label_scm: KY + label_plugins: Eklentiler + label_ldap_authentication: LDAP Denetimi + label_downloads_abbr: D/L + label_optional_description: İsteğe bağlı açıklama + label_add_another_file: Bir dosya daha ekle + label_preferences: Tercihler + label_chronological_order: Tarih sırasına göre + label_reverse_chronological_order: Ters tarih sırasına göre + label_planning: Planlanıyor + + button_login: Giriş + button_submit: Gönder + button_save: Kaydet + button_check_all: Hepsini işaretle + button_uncheck_all: Tüm işaretleri kaldır + button_delete: Sil + button_create: Oluştur + button_test: Sına + button_edit: Düzenle + button_add: Ekle + button_change: Değiştir + button_apply: Uygula + button_clear: Temizle + button_lock: Kilitle + button_unlock: Kilidi aç + button_download: İndir + button_list: Listele + button_view: Bak + button_move: Taşı + button_back: Geri + button_cancel: İptal + button_activate: Etkinleştir + button_sort: Sırala + button_log_time: Zaman kaydı + button_rollback: Bu sürüme geri al + button_watch: İzle + button_unwatch: İzlemeyi iptal et + button_reply: Cevapla + button_archive: Arşivle + button_unarchive: Arşivlemeyi kaldır + button_reset: Sıfırla + button_rename: Yeniden adlandır + button_change_password: Parolayı değiştir + button_copy: Kopyala + button_annotate: Değişiklik geçmişine göre göster + button_update: Güncelle + button_configure: Yapılandır + + status_active: faal + status_registered: kayıtlı + status_locked: kilitli + + text_select_mail_notifications: Gönderilecek e-posta uyarısına göre hareketi seçin. + text_regexp_info: örn. ^[A-Z0-9]+$ + text_min_max_length_info: 0 sınırlama yok demektir + text_project_destroy_confirmation: Bu projeyi ve bağlantılı verileri silmek istediğinizden emin misiniz? + text_subprojects_destroy_warning: "Ayrıca %{value} alt proje silinecek." + text_workflow_edit: İşakışını düzenlemek için bir rol ve iş tipi seçin + text_are_you_sure: Emin misiniz ? + text_tip_issue_begin_day: Bugün başlayan görevler + text_tip_issue_end_day: Bugün sona eren görevler + text_tip_issue_begin_end_day: Bugün başlayan ve sona eren görevler + text_caracters_maximum: "En çok %{count} karakter." + text_caracters_minimum: "En az %{count} karakter uzunluğunda olmalı." + text_length_between: "%{min} ve %{max} karakterleri arasındaki uzunluk." + text_tracker_no_workflow: Bu iş tipi için işakışı tanımlanmamış + text_unallowed_characters: Yasaklı karakterler + text_comma_separated: Çoklu değer girilebilir(Virgül ile ayrılmış). + text_issues_ref_in_commit_messages: Teslim mesajlarındaki işleri çözme ve başvuruda bulunma + text_issue_added: "İş %{id}, %{author} tarafından rapor edildi." + text_issue_updated: "İş %{id}, %{author} tarafından güncellendi." + text_wiki_destroy_confirmation: bu wikiyi ve tüm içeriğini silmek istediğinizden emin misiniz? + text_issue_category_destroy_question: "Bazı işler (%{count}) bu kategoriye atandı. Ne yapmak istersiniz?" + text_issue_category_destroy_assignments: Kategori atamalarını kaldır + text_issue_category_reassign_to: İşleri bu kategoriye tekrar ata + text_user_mail_option: "Seçili olmayan projeler için, sadece dahil olduğunuz ya da izlediğiniz öğeler hakkında uyarılar alacaksınız (örneğin,yazarı veya atandığınız işler)." + text_no_configuration_data: "Roller, iş tipleri, iş durumları ve işakışı henüz yapılandırılmadı.\nVarsayılan yapılandırılmanın yüklenmesi şiddetle tavsiye edilir. Bir kez yüklendiğinde yapılandırmayı değiştirebileceksiniz." + text_load_default_configuration: Varsayılan yapılandırmayı yükle + text_status_changed_by_changeset: "Değişiklik listesi %{value} içinde uygulandı." + text_issues_destroy_confirmation: 'Seçili işleri silmek istediğinizden emin misiniz ?' + text_select_project_modules: 'Bu proje için etkinleştirmek istediğiniz modülleri seçin:' + text_default_administrator_account_changed: Varsayılan yönetici hesabı değişti + text_file_repository_writable: Dosya deposu yazılabilir + text_rmagick_available: RMagick Kullanılabilir (isteğe bağlı) + text_destroy_time_entries_question: Silmek üzere olduğunuz işler üzerine %{hours} saat raporlandı.Ne yapmak istersiniz ? + text_destroy_time_entries: Raporlanmış süreleri sil + text_assign_time_entries_to_project: Raporlanmış süreleri projeye ata + text_reassign_time_entries: 'Raporlanmış süreleri bu işe tekrar ata:' + + default_role_manager: Yönetici + default_role_developer: Geliştirici + default_role_reporter: Raporlayıcı + default_tracker_bug: Hata + default_tracker_feature: Özellik + default_tracker_support: Destek + default_issue_status_new: Yeni + default_issue_status_in_progress: Yapılıyor + default_issue_status_resolved: Çözüldü + default_issue_status_feedback: Geribildirim + default_issue_status_closed: "Kapatıldı" + default_issue_status_rejected: Reddedildi + default_doc_category_user: Kullanıcı Dökümantasyonu + default_doc_category_tech: Teknik Dökümantasyon + default_priority_low: Düşük + default_priority_normal: Normal + default_priority_high: Yüksek + default_priority_urgent: Acil + default_priority_immediate: Derhal + default_activity_design: Tasarım + default_activity_development: Geliştirme + + enumeration_issue_priorities: İş önceliği + enumeration_doc_categories: Belge Kategorileri + enumeration_activities: Faaliyetler (zaman takibi) + button_quote: Alıntı + setting_enabled_scm: KKY Açık + label_incoming_emails: "Gelen e-postalar" + label_generate_key: "Anahtar oluştur" + setting_sequential_project_identifiers: "Sıralı proje tanımlayıcıları oluştur" + field_parent_title: Üst sayfa + text_email_delivery_not_configured: "Email delivery is not configured, and notifications are disabled.\nConfigure your SMTP server in config/configuration.yml and restart the application to enable them." + text_enumeration_category_reassign_to: 'Hepsini şuna çevir:' + label_issue_watchers: Takipçiler + mail_body_reminder: "Size atanmış olan %{count} iş %{days} gün içerisinde bitirilmeli:" + label_duplicated_by: yineleyen + text_enumeration_destroy_question: "Bu nesneye %{count} değer bağlanmış." + text_user_wrote: "%{value} demiş ki:" + setting_mail_handler_api_enabled: Gelen e-postalar için WS'yi aç + label_and_its_subprojects: "%{value} ve alt projeleri" + mail_subject_reminder: "%{count} iş bir kaç güne bitecek" + setting_mail_handler_api_key: API anahtarı + setting_commit_logs_encoding: Gönderim mesajlarının kodlaması (UTF-8 vs.) + general_csv_decimal_separator: '.' + notice_unable_delete_version: Sürüm silinemiyor + label_renamed: yeniden adlandırılmış + label_copied: kopyalanmış + setting_plain_text_mail: sadece düz metin (HTML yok) + permission_view_files: Dosyaları görme + permission_edit_issues: İşleri düzenleme + permission_edit_own_time_entries: Kendi zaman girişlerini düzenleme + permission_manage_public_queries: Herkese açık sorguları yönetme + permission_add_issues: İş ekleme + permission_log_time: Harcanan zamanı kaydetme + permission_view_changesets: Değişimleri görme(SVN, vs.) + permission_view_time_entries: Harcanan zamanı görme + permission_manage_versions: Sürümleri yönetme + permission_manage_wiki: Wiki'yi yönetme + permission_manage_categories: İş kategorilerini yönetme + permission_protect_wiki_pages: Wiki sayfalarını korumaya alma + permission_comment_news: Haberlere yorum yapma + permission_delete_messages: Mesaj silme + permission_select_project_modules: Proje modüllerini seçme + permission_edit_wiki_pages: Wiki sayfalarını düzenleme + permission_add_issue_watchers: Takipçi ekleme + permission_view_gantt: İş-Zaman çizelgesi görme + permission_move_issues: İşlerin yerini değiştirme + permission_manage_issue_relations: İşlerin biribiriyle bağlantılarını yönetme + permission_delete_wiki_pages: Wiki sayfalarını silme + permission_manage_boards: Panoları yönetme + permission_delete_wiki_pages_attachments: Ekleri silme + permission_view_wiki_edits: Wiki geçmişini görme + permission_add_messages: Mesaj gönderme + permission_view_messages: Mesajları görme + permission_manage_files: Dosyaları yönetme + permission_edit_issue_notes: Notları düzenleme + permission_manage_news: Haberleri yönetme + permission_view_calendar: Takvimleri görme + permission_manage_members: Üyeleri yönetme + permission_edit_messages: Mesajları düzenleme + permission_delete_issues: İşleri silme + permission_view_issue_watchers: Takipçi listesini görme + permission_manage_repository: Depo yönetimi + permission_commit_access: Gönderme erişimi + permission_browse_repository: Depoya gözatma + permission_view_documents: Belgeleri görme + permission_edit_project: Projeyi düzenleme + permission_add_issue_notes: Not ekleme + permission_save_queries: Sorgu kaydetme + permission_view_wiki_pages: Wiki görme + permission_rename_wiki_pages: Wiki sayfasının adını değiştirme + permission_edit_time_entries: Zaman kayıtlarını düzenleme + permission_edit_own_issue_notes: Kendi notlarını düzenleme + setting_gravatar_enabled: Kullanıcı resimleri için Gravatar kullan + label_example: Örnek + text_repository_usernames_mapping: "Select ou update the Redmine user mapped to each username found in the repository log.\nUsers with the same Redmine and repository username or email are automatically mapped." + permission_edit_own_messages: Kendi mesajlarını düzenleme + permission_delete_own_messages: Kendi mesajlarını silme + label_user_activity: "%{value} kullanıcısının etkinlikleri" + label_updated_time_by: "%{author} tarafından %{age} önce güncellendi" + text_diff_truncated: '... Bu fark tam olarak gösterilemiyor çünkü gösterim için ayarlanmış üst sınırı aşıyor.' + setting_diff_max_lines_displayed: Gösterilebilecek maksimumu fark satırı + text_plugin_assets_writable: Eklenti yardımcı dosya dizini yazılabilir + warning_attachments_not_saved: "%{count} adet dosya kaydedilemedi." + button_create_and_continue: Oluştur ve devam et + text_custom_field_possible_values_info: 'Her değer için bir satır' + label_display: Göster + field_editable: Düzenlenebilir + setting_repository_log_display_limit: Dosya kaydında gösterilecek maksimum değişim sayısı + setting_file_max_size_displayed: Dahili olarak gösterilecek metin dosyaları için maksimum satır sayısı + field_watcher: Takipçi + setting_openid: Kayıt ve giriş için OpenID'ye izin ver + field_identity_url: OpenID URL + label_login_with_open_id_option: veya OpenID kullanın + field_content: İçerik + label_descending: Azalan + label_sort: Sırala + label_ascending: Artan + label_date_from_to: "%{start} - %{end} arası" + label_greater_or_equal: ">=" + label_less_or_equal: <= + text_wiki_page_destroy_question: Bu sayfanın %{descendants} adet alt sayfası var. Ne yapmak istersiniz? + text_wiki_page_reassign_children: Alt sayfaları bu sayfanın altına bağla + text_wiki_page_nullify_children: Alt sayfaları ana sayfa olarak sakla + text_wiki_page_destroy_children: Alt sayfaları ve onların alt sayfalarını tamamen sil + setting_password_min_length: Minimum parola uzunluğu + field_group_by: Sonuçları grupla + mail_subject_wiki_content_updated: "'%{id}' wiki sayfası güncellendi" + label_wiki_content_added: Wiki sayfası eklendi + mail_subject_wiki_content_added: "'%{id}' wiki sayfası eklendi" + mail_body_wiki_content_added: "'%{id}' wiki sayfası, %{author} tarafından eklendi." + label_wiki_content_updated: Wiki sayfası güncellendi + mail_body_wiki_content_updated: "'%{id}' wiki sayfası, %{author} tarafından güncellendi." + permission_add_project: Proje oluştur + setting_new_project_user_role_id: Yönetici olmayan ancak proje yaratabilen kullanıcıya verilen rol + label_view_all_revisions: Tüm değişiklikleri gör + label_tag: Etiket + label_branch: Kol + error_no_tracker_in_project: Bu projeye bağlanmış bir iş tipi yok. Lütfen proje ayarlarını kontrol edin. + error_no_default_issue_status: Varsayılan iş durumu tanımlanmamış. Lütfen ayarlarınızı kontrol edin ("Yönetim -> İş durumları" sayfasına gidin). + label_group_plural: Gruplar + label_group: Grup + label_group_new: Yeni grup + label_time_entry_plural: Harcanan zaman + text_journal_changed: "%{label}: %{old} -> %{new}" + text_journal_set_to: "%{label} %{value} yapıldı" + text_journal_deleted: "%{label} silindi (%{old})" + text_journal_added: "%{label} %{value} eklendi" + field_active: Etkin + enumeration_system_activity: Sistem Etkinlikleri + permission_delete_issue_watchers: İzleyicileri sil + version_status_closed: kapalı + version_status_locked: kilitli + version_status_open: açık + error_can_not_reopen_issue_on_closed_version: Kapatılmış bir sürüme ait işler tekrar açılamaz + label_user_anonymous: Anonim + button_move_and_follow: Yerini değiştir ve takip et + setting_default_projects_modules: Yeni projeler için varsayılan modüller + setting_gravatar_default: Varsayılan Gravatar resmi + field_sharing: Paylaşım + label_version_sharing_hierarchy: Proje hiyerarşisi ile + label_version_sharing_system: Tüm projeler ile + label_version_sharing_descendants: Alt projeler ile + label_version_sharing_tree: Proje ağacı ile + label_version_sharing_none: Paylaşılmamış + error_can_not_archive_project: Bu proje arşivlenemez + button_duplicate: Yinele + button_copy_and_follow: Kopyala ve takip et + label_copy_source: Kaynak + setting_issue_done_ratio: İş tamamlanma oranını şununla hesapla + setting_issue_done_ratio_issue_status: İş durumunu kullan + error_issue_done_ratios_not_updated: İş tamamlanma oranları güncellenmedi. + error_workflow_copy_target: Lütfen hedef iş tipi ve rolleri seçin + setting_issue_done_ratio_issue_field: İşteki alanı kullan + label_copy_same_as_target: Hedef ile aynı + label_copy_target: Hedef + notice_issue_done_ratios_updated: İş tamamlanma oranları güncellendi. + error_workflow_copy_source: Lütfen kaynak iş tipi ve rolleri seçin + label_update_issue_done_ratios: İş tamamlanma oranlarını güncelle + setting_start_of_week: Takvimleri şundan başlat + permission_view_issues: İşleri Gör + label_display_used_statuses_only: Sadece bu iş tipi tarafından kullanılan durumları göster + label_revision_id: Değişiklik %{value} + label_api_access_key: API erişim anahtarı + label_api_access_key_created_on: API erişim anahtarı %{value} önce oluşturuldu + label_feeds_access_key: RSS erişim anahtarı + notice_api_access_key_reseted: API erişim anahtarınız sıfırlandı. + setting_rest_api_enabled: REST web servisini etkinleştir + label_missing_api_access_key: Bir API erişim anahtarı eksik + label_missing_feeds_access_key: Bir RSS erişim anahtarı eksik + button_show: Göster + text_line_separated: Çoklu değer girilebilir (her satıra bir değer). + setting_mail_handler_body_delimiters: Şu satırların birinden sonra e-postayı sonlandır + permission_add_subprojects: Alt proje yaratma + label_subproject_new: Yeni alt proje + text_own_membership_delete_confirmation: "Projeyi daha sonra düzenleyememenize sebep olacak bazı yetkilerinizi kaldırmak üzeresiniz.\nDevam etmek istediğinize emin misiniz?" + label_close_versions: Tamamlanmış sürümleri kapat + label_board_sticky: Yapışkan + label_board_locked: Kilitli + permission_export_wiki_pages: Wiki sayfalarını dışarı aktar + setting_cache_formatted_text: Biçimlendirilmiş metni önbelleğe al + permission_manage_project_activities: Proje etkinliklerini yönetme + error_unable_delete_issue_status: İş durumu silinemiyor + label_profile: Profil + permission_manage_subtasks: Alt işleri yönetme + field_parent_issue: Üst iş + label_subtask_plural: Alt işler + label_project_copy_notifications: Proje kopyalaması esnasında bilgilendirme e-postaları gönder + error_can_not_delete_custom_field: Özel alan silinemiyor + error_unable_to_connect: Bağlanılamıyor (%{value}) + error_can_not_remove_role: Bu rol kullanımda olduğundan silinemez. + error_can_not_delete_tracker: Bu iş tipi içerisinde iş barındırdığından silinemiyor. + field_principal: Temel + label_my_page_block: Kişisel sayfa bloğum + notice_failed_to_save_members: "Üyeler kaydedilemiyor: %{errors}." + text_zoom_out: Uzaklaş + text_zoom_in: Yakınlaş + notice_unable_delete_time_entry: Zaman kayıt girdisi silinemiyor. + label_overall_spent_time: Toplam harcanan zaman + field_time_entries: Zaman Kayıtları + project_module_gantt: İş-Zaman Çizelgesi + project_module_calendar: Takvim + button_edit_associated_wikipage: "Edit associated Wiki page: %{page_title}" + field_text: Metin alanı + label_user_mail_option_only_owner: Sadece sahibi olduğum şeyler için + setting_default_notification_option: Varsayılan bildirim seçeneği + label_user_mail_option_only_my_events: Sadece takip ettiğim ya da içinde olduğum şeyler için + label_user_mail_option_only_assigned: Sadece bana atanan şeyler için + label_user_mail_option_none: Hiç bir şey için + field_member_of_group: Atananın grubu + field_assigned_to_role: Atananın rolü + notice_not_authorized_archived_project: Erişmeye çalıştığınız proje arşive kaldırılmış. + label_principal_search: "Kullanıcı ya da grup ara:" + label_user_search: "Kullanıcı ara:" + field_visible: Görünür + setting_emails_header: "E-Posta başlığı" + setting_commit_logtime_activity_id: Kaydedilen zaman için etkinlik + text_time_logged_by_changeset: Applied in changeset %{value}. + setting_commit_logtime_enabled: Zaman kaydını etkinleştir + notice_gantt_chart_truncated: The chart was truncated because it exceeds the maximum number of items that can be displayed (%{max}) + setting_gantt_items_limit: İş-Zaman çizelgesinde gösterilecek en fazla öğe sayısı + field_warn_on_leaving_unsaved: Kaydedilmemiş metin bulunan bir sayfadan çıkarken beni uyar + text_warn_on_leaving_unsaved: Bu sayfada terkettiğiniz takdirde kaybolacak kaydedilmemiş metinler var. + label_my_queries: Özel sorgularım + text_journal_changed_no_detail: "%{label} güncellendi" + label_news_comment_added: Bir habere yorum eklendi + button_expand_all: Tümünü genişlet + button_collapse_all: Tümünü daralt + label_additional_workflow_transitions_for_assignee: Additional transitions allowed when the user is the assignee + label_additional_workflow_transitions_for_author: Additional transitions allowed when the user is the author + label_bulk_edit_selected_time_entries: Seçilen zaman kayıtlarını toplu olarak düzenle + text_time_entries_destroy_confirmation: Seçilen zaman kaydını/kayıtlarını silmek istediğinize emin misiniz? + label_role_anonymous: Anonim + label_role_non_member: Üye Değil + label_issue_note_added: Not eklendi + label_issue_status_updated: Durum güncellendi + label_issue_priority_updated: Öncelik güncellendi + label_issues_visibility_own: Issues created by or assigned to the user + field_issues_visibility: İşlerin görünürlüğü + label_issues_visibility_all: Tüm işler + permission_set_own_issues_private: Set own issues public or private + field_is_private: Özel + permission_set_issues_private: İşleri özel ya da genel olarak işaretleme + label_issues_visibility_public: Özel olmayan tüm işler + text_issues_destroy_descendants_confirmation: This will also delete %{count} subtask(s). + field_commit_logs_encoding: Commit messages encoding + field_scm_path_encoding: Yol kodlaması(encoding) + text_scm_path_encoding_note: "Varsayılan: UTF-8" + field_path_to_repository: Path to repository + field_root_directory: Ana dizin + field_cvs_module: Modül + field_cvsroot: CVSROOT + text_mercurial_repository_note: Local repository (e.g. /hgrepo, c:\hgrepo) + text_scm_command: Komut + text_scm_command_version: Sürüm + label_git_report_last_commit: Report last commit for files and directories + notice_issue_successful_create: Issue %{id} created. + label_between: between + setting_issue_group_assignment: Allow issue assignment to groups + label_diff: diff + text_git_repository_note: Repository is bare and local (e.g. /gitrepo, c:\gitrepo) + description_query_sort_criteria_direction: Sort direction + description_project_scope: Search scope + description_filter: Filter + description_user_mail_notification: Mail notification settings + description_date_from: Enter start date + description_message_content: Message content + description_available_columns: Available Columns + description_date_range_interval: Choose range by selecting start and end date + description_issue_category_reassign: Choose issue category + description_search: Searchfield + description_notes: Notes + description_date_range_list: Choose range from list + description_choose_project: Projects + description_date_to: Enter end date + description_query_sort_criteria_attribute: Sort attribute + description_wiki_subpages_reassign: Choose new parent page + description_selected_columns: Selected Columns + label_parent_revision: Parent + label_child_revision: Child + error_scm_annotate_big_text_file: The entry cannot be annotated, as it exceeds the maximum text file size. + setting_default_issue_start_date_to_creation_date: Use current date as start date for new issues + button_edit_section: Edit this section + setting_repositories_encodings: Attachments and repositories encodings + description_all_columns: All Columns + button_export: Export + label_export_options: "%{export_format} export options" + error_attachment_too_big: This file cannot be uploaded because it exceeds the maximum allowed file size (%{max_size}) + notice_failed_to_save_time_entries: "Failed to save %{count} time entrie(s) on %{total} selected: %{ids}." + label_x_issues: + zero: 0 İş + one: 1 İş + other: "%{count} İşler" + label_repository_new: New repository + field_repository_is_default: Main repository + label_copy_attachments: Copy attachments + label_item_position: "%{position}/%{count}" + label_completed_versions: Completed versions + text_project_identifier_info: Only lower case letters (a-z), numbers, dashes and underscores are allowed.
    Once saved, the identifier cannot be changed. + field_multiple: Multiple values + setting_commit_cross_project_ref: Allow issues of all the other projects to be referenced and fixed + text_issue_conflict_resolution_add_notes: Add my notes and discard my other changes + text_issue_conflict_resolution_overwrite: Apply my changes anyway (previous notes will be kept but some changes may be overwritten) + notice_issue_update_conflict: The issue has been updated by an other user while you were editing it. + text_issue_conflict_resolution_cancel: Discard all my changes and redisplay %{link} + permission_manage_related_issues: Manage related issues + field_auth_source_ldap_filter: LDAP filter + label_search_for_watchers: Search for watchers to add + notice_account_deleted: Your account has been permanently deleted. + setting_unsubscribe: Allow users to delete their own account + button_delete_my_account: Delete my account + text_account_destroy_confirmation: |- + Are you sure you want to proceed? + Your account will be permanently deleted, with no way to reactivate it. + error_session_expired: Your session has expired. Please login again. + text_session_expiration_settings: "Warning: changing these settings may expire the current sessions including yours." + setting_session_lifetime: Session maximum lifetime + setting_session_timeout: Session inactivity timeout + label_session_expiration: Session expiration + permission_close_project: Close / reopen the project + label_show_closed_projects: View closed projects + button_close: Close + button_reopen: Reopen + project_status_active: active + project_status_closed: closed + project_status_archived: archived + text_project_closed: This project is closed and read-only. + notice_user_successful_create: User %{id} created. + field_core_fields: Standard fields + field_timeout: Timeout (in seconds) + setting_thumbnails_enabled: Display attachment thumbnails + setting_thumbnails_size: Thumbnails size (in pixels) + label_status_transitions: Status transitions + label_fields_permissions: Fields permissions + label_readonly: Read-only + label_required: Required + text_repository_identifier_info: Only lower case letters (a-z), numbers, dashes and underscores are allowed.
    Once saved, the identifier cannot be changed. + field_board_parent: Parent forum + label_attribute_of_project: Project's %{name} + label_attribute_of_author: Author's %{name} + label_attribute_of_assigned_to: Assignee's %{name} + label_attribute_of_fixed_version: Target version's %{name} + label_copy_subtasks: Copy subtasks + label_copied_to: copied to + label_copied_from: copied from + label_any_issues_in_project: any issues in project + label_any_issues_not_in_project: any issues not in project + field_private_notes: Private notes + permission_view_private_notes: View private notes + permission_set_notes_private: Set notes as private + label_no_issues_in_project: no issues in project + label_any: Hepsi + label_last_n_weeks: last %{count} weeks + setting_cross_project_subtasks: Allow cross-project subtasks + label_cross_project_descendants: Alt projeler ile + label_cross_project_tree: Proje ağacı ile + label_cross_project_hierarchy: Proje hiyerarşisi ile + label_cross_project_system: Tüm projeler ile + button_hide: Hide + setting_non_working_week_days: Non-working days + label_in_the_next_days: in the next + label_in_the_past_days: in the past + label_attribute_of_user: User's %{name} + text_turning_multiple_off: If you disable multiple values, multiple values will be + removed in order to preserve only one value per item. + label_attribute_of_issue: Issue's %{name} + permission_add_documents: Add documents + permission_edit_documents: Edit documents + permission_delete_documents: Delete documents + label_gantt_progress_line: Progress line + setting_jsonp_enabled: Enable JSONP support + field_inherit_members: Inherit members + field_closed_on: Closed + setting_default_projects_tracker_ids: Default trackers for new projects + label_total_time: Toplam + text_scm_config: You can configure your SCM commands in config/configuration.yml. Please restart the application after editing it. + text_scm_command_not_available: SCM command is not available. Please check settings on the administration panel. diff --git a/config/locales/uk.yml b/config/locales/uk.yml new file mode 100644 index 00000000..ddfd3ffa --- /dev/null +++ b/config/locales/uk.yml @@ -0,0 +1,1084 @@ +uk: + direction: ltr + date: + formats: + # Use the strftime parameters for formats. + # When no format has been given, it uses default. + # You can provide other formats here if you like! + default: "%Y-%m-%d" + short: "%b %d" + long: "%B %d, %Y" + + day_names: [Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday] + abbr_day_names: [Sun, Mon, Tue, Wed, Thu, Fri, Sat] + + # Don't forget the nil at the beginning; there's no such thing as a 0th month + month_names: [~, January, February, March, April, May, June, July, August, September, October, November, December] + abbr_month_names: [~, Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec] + # Used in date_select and datime_select. + order: + - :year + - :month + - :day + + time: + formats: + default: "%a, %d %b %Y %H:%M:%S %z" + time: "%H:%M" + short: "%d %b %H:%M" + long: "%B %d, %Y %H:%M" + am: "am" + pm: "pm" + + datetime: + distance_in_words: + half_a_minute: "half a minute" + less_than_x_seconds: + one: "less than 1 second" + other: "less than %{count} seconds" + x_seconds: + one: "1 second" + other: "%{count} seconds" + less_than_x_minutes: + one: "less than a minute" + other: "less than %{count} minutes" + x_minutes: + one: "1 minute" + other: "%{count} minutes" + about_x_hours: + one: "about 1 hour" + other: "about %{count} hours" + x_hours: + one: "1 hour" + other: "%{count} hours" + x_days: + one: "1 day" + other: "%{count} days" + about_x_months: + one: "about 1 month" + other: "about %{count} months" + x_months: + one: "1 month" + other: "%{count} months" + about_x_years: + one: "about 1 year" + other: "about %{count} years" + over_x_years: + one: "over 1 year" + other: "over %{count} years" + almost_x_years: + one: "almost 1 year" + other: "almost %{count} years" + + number: + format: + separator: "." + delimiter: "" + precision: 3 + human: + format: + precision: 3 + delimiter: "" + storage_units: + format: "%n %u" + units: + kb: KB + tb: TB + gb: GB + byte: + one: Byte + other: Bytes + mb: MB + +# Used in array.to_sentence. + support: + array: + sentence_connector: "and" + skip_last_comma: false + + activerecord: + errors: + template: + header: + one: "1 error prohibited this %{model} from being saved" + other: "%{count} errors prohibited this %{model} from being saved" + messages: + inclusion: "немає в списку" + exclusion: "зарезервовано" + invalid: "невірне" + confirmation: "не збігається з підтвердженням" + accepted: "необхідно прийняти" + empty: "не може бути порожнім" + blank: "не може бути незаповненим" + too_long: "дуже довге" + too_short: "дуже коротке" + wrong_length: "не відповідає довжині" + taken: "вже використовується" + not_a_number: "не є числом" + not_a_date: "є недійсною датою" + greater_than: "must be greater than %{count}" + greater_than_or_equal_to: "must be greater than or equal to %{count}" + equal_to: "must be equal to %{count}" + less_than: "must be less than %{count}" + less_than_or_equal_to: "must be less than or equal to %{count}" + odd: "must be odd" + even: "must be even" + greater_than_start_date: "повинна бути пізніша за дату початку" + not_same_project: "не відносяться до одного проекту" + circular_dependency: "Такий зв'язок приведе до циклічної залежності" + cant_link_an_issue_with_a_descendant: "An issue can not be linked to one of its subtasks" + + actionview_instancetag_blank_option: Оберіть + + general_text_No: 'Ні' + general_text_Yes: 'Так' + general_text_no: 'Ні' + general_text_yes: 'Так' + general_lang_name: 'Ukrainian (Українська)' + general_csv_separator: ',' + general_csv_decimal_separator: '.' + general_csv_encoding: UTF-8 + general_pdf_encoding: UTF-8 + general_first_day_of_week: '1' + + notice_account_updated: Обліковий запис успішно оновлений. + notice_account_invalid_creditentials: Неправильне ім'я користувача або пароль + notice_account_password_updated: Пароль успішно оновлений. + notice_account_wrong_password: Невірний пароль + notice_account_register_done: Обліковий запис успішно створений. Для активації Вашого облікового запису зайдіть по посиланню, яке відіслане вам електронною поштою. + notice_account_unknown_email: Невідомий користувач. + notice_can_t_change_password: Для даного облікового запису використовується джерело зовнішньої аутентифікації. Неможливо змінити пароль. + notice_account_lost_email_sent: Вам відправлений лист з інструкціями по вибору нового пароля. + notice_account_activated: Ваш обліковий запис активований. Ви можете увійти. + notice_successful_create: Створення успішно завершене. + notice_successful_update: Оновлення успішно завершене. + notice_successful_delete: Видалення успішно завершене. + notice_successful_connection: Підключення успішно встановлене. + notice_file_not_found: Сторінка, на яку ви намагаєтеся зайти, не існує або видалена. + notice_locking_conflict: Дані оновлено іншим користувачем. + notice_scm_error: Запису та/або виправлення немає в репозиторії. + notice_not_authorized: У вас немає прав для відвідини даної сторінки. + notice_email_sent: "Відправлено листа %{value}" + notice_email_error: "Під час відправки листа відбулася помилка (%{value})" + notice_feeds_access_key_reseted: Ваш ключ доступу RSS було скинуто. + notice_failed_to_save_issues: "Не вдалося зберегти %{count} пункт(ів) з %{total} вибраних: %{ids}." + notice_no_issue_selected: "Не вибрано жодної задачі! Будь ласка, відзначте задачу, яку ви хочете відредагувати." + notice_account_pending: "Ваш обліковий запис створено і він чекає на підтвердження адміністратором." + + mail_subject_lost_password: "Ваш %{value} пароль" + mail_body_lost_password: 'Для зміни пароля, зайдіть за наступним посиланням:' + mail_subject_register: "Активація облікового запису %{value}" + mail_body_register: 'Для активації облікового запису, зайдіть за наступним посиланням:' + mail_body_account_information_external: "Ви можете використовувати ваш %{value} обліковий запис для входу." + mail_body_account_information: Інформація по Вашому обліковому запису + mail_subject_account_activation_request: "Запит на активацію облікового запису %{value}" + mail_body_account_activation_request: "Новий користувач (%{value}) зареєструвався. Його обліковий запис чекає на ваше підтвердження:" + + + field_name: Ім'я + field_description: Опис + field_summary: Короткий опис + field_is_required: Необхідно + field_firstname: Ім'я + field_lastname: Прізвище + field_mail: Ел. пошта + field_filename: Файл + field_filesize: Розмір + field_downloads: Завантаження + field_author: Автор + field_created_on: Створено + field_updated_on: Оновлено + field_field_format: Формат + field_is_for_all: Для усіх проектів + field_possible_values: Можливі значення + field_regexp: Регулярний вираз + field_min_length: Мінімальна довжина + field_max_length: Максимальна довжина + field_value: Значення + field_category: Категорія + field_title: Назва + field_project: Проект + field_issue: Питання + field_status: Статус + field_notes: Примітки + field_is_closed: Питання закрито + field_is_default: Типове значення + field_tracker: Координатор + field_subject: Тема + field_due_date: Дата виконання + field_assigned_to: Призначена до + field_priority: Пріоритет + field_fixed_version: Target version + field_user: Користувач + field_role: Роль + field_homepage: Домашня сторінка + field_is_public: Публічний + field_parent: Підпроект + field_is_in_roadmap: Питання, що відображаються в оперативному плані + field_login: Вхід + field_mail_notification: Повідомлення за електронною поштою + field_admin: Адміністратор + field_last_login_on: Останнє підключення + field_language: Мова + field_effective_date: Дата + field_password: Пароль + field_new_password: Новий пароль + field_password_confirmation: Підтвердження + field_version: Версія + field_type: Тип + field_host: Машина + field_port: Порт + field_account: Обліковий запис + field_base_dn: Базове відмітне ім'я + field_attr_login: Атрибут Реєстрація + field_attr_firstname: Атрибут Ім'я + field_attr_lastname: Атрибут Прізвище + field_attr_mail: Атрибут Email + field_onthefly: Створення користувача на льоту + field_start_date: Початок + field_done_ratio: "% зроблено" + field_auth_source: Режим аутентифікації + field_hide_mail: Приховувати мій email + field_comments: Коментар + field_url: URL + field_start_page: Стартова сторінка + field_subproject: Підпроект + field_hours: Годин(и/а) + field_activity: Діяльність + field_spent_on: Дата + field_identifier: Ідентифікатор + field_is_filter: Використовується як фільтр + field_issue_to: Зв'язані задачі + field_delay: Відкласти + field_assignable: Задача може бути призначена цій ролі + field_redirect_existing_links: Перенаправити існуючі посилання + field_estimated_hours: Оцінний час + field_column_names: Колонки + field_time_zone: Часовий пояс + field_searchable: Вживається у пошуку + + setting_app_title: Назва додатку + setting_app_subtitle: Підзаголовок додатку + setting_welcome_text: Текст привітання + setting_default_language: Стандартна мова + setting_login_required: Необхідна аутентифікація + setting_self_registration: Можлива само-реєстрація + setting_attachment_max_size: Максимальний размір вкладення + setting_issues_export_limit: Обмеження по задачах, що експортуються + setting_mail_from: email адреса для передачі інформації + setting_bcc_recipients: Отримувачі сліпої копії (bcc) + setting_host_name: Им'я машини + setting_text_formatting: Форматування тексту + setting_wiki_compression: Стиснення історії Wiki + setting_feeds_limit: Обмеження змісту подачі + setting_autofetch_changesets: Автоматично доставати доповнення + setting_sys_api_enabled: Дозволити WS для управління репозиторієм + setting_commit_ref_keywords: Ключові слова для посилання + setting_commit_fix_keywords: Призначення ключових слів + setting_autologin: Автоматичний вхід + setting_date_format: Формат дати + setting_time_format: Формат часу + setting_cross_project_issue_relations: Дозволити міжпроектні відносини між питаннями + setting_issue_list_default_columns: Колонки, що відображаються за умовчанням в списку питань + setting_emails_footer: Підпис до електронної пошти + setting_protocol: Протокол + + label_user: Користувач + label_user_plural: Користувачі + label_user_new: Новий користувач + label_project: Проект + label_project_new: Новий проект + label_project_plural: Проекти + label_x_projects: + zero: no projects + one: 1 project + other: "%{count} projects" + label_project_all: Усі проекти + label_project_latest: Останні проекти + label_issue: Питання + label_issue_new: Нові питання + label_issue_plural: Питання + label_issue_view_all: Проглянути всі питання + label_issues_by: "Питання за %{value}" + label_document: Документ + label_document_new: Новий документ + label_document_plural: Документи + label_role: Роль + label_role_plural: Ролі + label_role_new: Нова роль + label_role_and_permissions: Ролі і права доступу + label_member: Учасник + label_member_new: Новий учасник + label_member_plural: Учасники + label_tracker: Координатор + label_tracker_plural: Координатори + label_tracker_new: Новий Координатор + label_workflow: Послідовність дій + label_issue_status: Статус питання + label_issue_status_plural: Статуси питань + label_issue_status_new: Новий статус + label_issue_category: Категорія питання + label_issue_category_plural: Категорії питань + label_issue_category_new: Нова категорія + label_custom_field: Поле клієнта + label_custom_field_plural: Поля клієнта + label_custom_field_new: Нове поле клієнта + label_enumerations: Довідники + label_enumeration_new: Нове значення + label_information: Інформація + label_information_plural: Інформація + label_please_login: Будь ласка, увійдіть + label_register: Зареєструватися + label_password_lost: Забули пароль + label_home: Домашня сторінка + label_my_page: Моя сторінка + label_my_account: Мій обліковий запис + label_my_projects: Мої проекти + label_administration: Адміністрування + label_login: Увійти + label_logout: Вийти + label_help: Допомога + label_reported_issues: Створені питання + label_assigned_to_me_issues: Мої питання + label_last_login: Останнє підключення + label_registered_on: Зареєстрований(а) + label_activity: Активність + label_new: Новий + label_logged_as: Увійшов як + label_environment: Оточення + label_authentication: Аутентифікація + label_auth_source: Режим аутентифікації + label_auth_source_new: Новий режим аутентифікації + label_auth_source_plural: Режими аутентифікації + label_subproject_plural: Підпроекти + label_min_max_length: Мінімальна - максимальна довжина + label_list: Список + label_date: Дата + label_integer: Цілий + label_float: З плаваючою крапкою + label_boolean: Логічний + label_string: Текст + label_text: Довгий текст + label_attribute: Атрибут + label_attribute_plural: атрибути + label_no_data: Немає даних для відображення + label_change_status: Змінити статус + label_history: Історія + label_attachment: Файл + label_attachment_new: Новий файл + label_attachment_delete: Видалити файл + label_attachment_plural: Файли + label_report: Звіт + label_report_plural: Звіти + label_news: Новини + label_news_new: Додати новину + label_news_plural: Новини + label_news_latest: Останні новини + label_news_view_all: Подивитися всі новини + label_settings: Налаштування + label_overview: Перегляд + label_version: Версія + label_version_new: Нова версія + label_version_plural: Версії + label_confirmation: Підтвердження + label_export_to: Експортувати в + label_read: Читання... + label_public_projects: Публічні проекти + label_open_issues: відкрите + label_open_issues_plural: відкриті + label_closed_issues: закрите + label_closed_issues_plural: закриті + label_x_open_issues_abbr_on_total: + zero: 0 open / %{total} + one: 1 open / %{total} + other: "%{count} open / %{total}" + label_x_open_issues_abbr: + zero: 0 open + one: 1 open + other: "%{count} open" + label_x_closed_issues_abbr: + zero: 0 closed + one: 1 closed + other: "%{count} closed" + label_total: Всього + label_permissions: Права доступу + label_current_status: Поточний статус + label_new_statuses_allowed: Дозволені нові статуси + label_all: Усі + label_none: Нікому + label_nobody: Ніхто + label_next: Наступний + label_previous: Попередній + label_used_by: Використовується + label_details: Подробиці + label_add_note: Додати зауваження + label_per_page: На сторінку + label_calendar: Календар + label_months_from: місяців(ця) з + label_gantt: Діаграма Ганта + label_internal: Внутрішній + label_last_changes: "останні %{count} змін" + label_change_view_all: Проглянути всі зміни + label_personalize_page: Персоналізувати цю сторінку + label_comment: Коментувати + label_comment_plural: Коментарі + label_x_comments: + zero: no comments + one: 1 comment + other: "%{count} comments" + label_comment_add: Залишити коментар + label_comment_added: Коментар додано + label_comment_delete: Видалити коментарі + label_query: Запит клієнта + label_query_plural: Запити клієнтів + label_query_new: Новий запит + label_filter_add: Додати фільтр + label_filter_plural: Фільтри + label_equals: є + label_not_equals: немає + label_in_less_than: менш ніж + label_in_more_than: більш ніж + label_in: у + label_today: сьогодні + label_this_week: цього тижня + label_less_than_ago: менш ніж днів(я) назад + label_more_than_ago: більш ніж днів(я) назад + label_ago: днів(я) назад + label_contains: містить + label_not_contains: не містить + label_day_plural: днів(я) + label_repository: Репозиторій + label_browse: Проглянути + label_revision: Версія + label_revision_plural: Версій + label_added: додано + label_modified: змінене + label_deleted: видалено + label_latest_revision: Остання версія + label_latest_revision_plural: Останні версії + label_view_revisions: Проглянути версії + label_max_size: Максимальний розмір + label_sort_highest: У початок + label_sort_higher: Вгору + label_sort_lower: Вниз + label_sort_lowest: У кінець + label_roadmap: Оперативний план + label_roadmap_due_in: "Строк %{value}" + label_roadmap_overdue: "%{value} запізнення" + label_roadmap_no_issues: Немає питань для даної версії + label_search: Пошук + label_result_plural: Результати + label_all_words: Всі слова + label_wiki: Wiki + label_wiki_edit: Редагування Wiki + label_wiki_edit_plural: Редагування Wiki + label_wiki_page: Сторінка Wiki + label_wiki_page_plural: Сторінки Wiki + label_index_by_title: Індекс за назвою + label_index_by_date: Індекс за датою + label_current_version: Поточна версія + label_preview: Попередній перегляд + label_feed_plural: Подання + label_changes_details: Подробиці по всіх змінах + label_issue_tracking: Координація питань + label_spent_time: Витрачений час + label_f_hour: "%{value} година" + label_f_hour_plural: "%{value} годин(и)" + label_time_tracking: Облік часу + label_change_plural: Зміни + label_statistics: Статистика + label_commits_per_month: Подань на місяць + label_commits_per_author: Подань на користувача + label_view_diff: Проглянути відмінності + label_diff_inline: підключений + label_diff_side_by_side: поряд + label_options: Опції + label_copy_workflow_from: Скопіювати послідовність дій з + label_permissions_report: Звіт про права доступу + label_watched_issues: Проглянуті питання + label_related_issues: Зв'язані питання + label_applied_status: Застосовний статус + label_loading: Завантаження... + label_relation_new: Новий зв'язок + label_relation_delete: Видалити зв'язок + label_relates_to: пов'язане з + label_duplicates: дублює + label_blocks: блокує + label_blocked_by: заблоковане + label_precedes: передує + label_follows: наступний за + label_end_to_start: з кінця до початку + label_end_to_end: з кінця до кінця + label_start_to_start: з початку до початку + label_start_to_end: з початку до кінця + label_stay_logged_in: Залишатися в системі + label_disabled: відключений + label_show_completed_versions: Показати завершені версії + label_me: мене + label_board: Форум + label_board_new: Новий форум + label_board_plural: Форуми + label_topic_plural: Теми + label_message_plural: Повідомлення + label_message_last: Останнє повідомлення + label_message_new: Нове повідомлення + label_reply_plural: Відповіді + label_send_information: Відправити користувачеві інформацію з облікового запису + label_year: Рік + label_month: Місяць + label_week: Неділя + label_date_from: З + label_date_to: Кому + label_language_based: На основі мови користувача + label_sort_by: "Сортувати за %{value}" + label_send_test_email: Послати email для перевірки + label_feeds_access_key_created_on: "Ключ доступу RSS створений %{value} назад " + label_module_plural: Модулі + label_added_time_by: "Доданий %{author} %{age} назад" + label_updated_time: "Оновлений %{value} назад" + label_jump_to_a_project: Перейти до проекту... + label_file_plural: Файли + label_changeset_plural: Набори змін + label_default_columns: Типові колонки + label_no_change_option: (Немає змін) + label_bulk_edit_selected_issues: Редагувати всі вибрані питання + label_theme: Тема + label_default: Типовий + label_search_titles_only: Шукати тільки в назвах + label_user_mail_option_all: "Для всіх подій у всіх моїх проектах" + label_user_mail_option_selected: "Для всіх подій тільки у вибраному проекті..." + label_user_mail_no_self_notified: "Не сповіщати про зміни, які я зробив сам" + label_registration_activation_by_email: активація облікового запису електронною поштою + label_registration_manual_activation: ручна активація облікового запису + label_registration_automatic_activation: автоматична активація облыкового + label_my_time_report: Мій звіт витраченого часу + + button_login: Вхід + button_submit: Відправити + button_save: Зберегти + button_check_all: Відзначити все + button_uncheck_all: Очистити + button_delete: Видалити + button_create: Створити + button_test: Перевірити + button_edit: Редагувати + button_add: Додати + button_change: Змінити + button_apply: Застосувати + button_clear: Очистити + button_lock: Заблокувати + button_unlock: Разблокувати + button_download: Завантажити + button_list: Список + button_view: Переглянути + button_move: Перемістити + button_back: Назад + button_cancel: Відмінити + button_activate: Активувати + button_sort: Сортувати + button_log_time: Записати час + button_rollback: Відкотити до даної версії + button_watch: Дивитися + button_unwatch: Не дивитися + button_reply: Відповісти + button_archive: Архівувати + button_unarchive: Розархівувати + button_reset: Перезапустити + button_rename: Перейменувати + button_change_password: Змінити пароль + button_copy: Копіювати + button_annotate: Анотувати + + status_active: Активний + status_registered: Зареєстрований + status_locked: Заблокований + + text_select_mail_notifications: Виберіть дії, на які відсилатиметься повідомлення на електронну пошту. + text_regexp_info: eg. ^[A-Z0-9]+$ + text_min_max_length_info: 0 означає відсутність заборон + text_project_destroy_confirmation: Ви наполягаєте на видаленні цього проекту і всієї інформації, що відноситься до нього? + text_workflow_edit: Виберіть роль і координатор для редагування послідовності дій + text_are_you_sure: Ви впевнені? + text_tip_issue_begin_day: день початку задачі + text_tip_issue_end_day: день завершення задачі + text_tip_issue_begin_end_day: початок задачі і закінчення цього дня + text_caracters_maximum: "%{count} символів(а) максимум." + text_caracters_minimum: "Повинно мати якнайменше %{count} символів(а) у довжину." + text_length_between: "Довжина між %{min} і %{max} символів." + text_tracker_no_workflow: Для цього координатора послідовність дій не визначена + text_unallowed_characters: Заборонені символи + text_comma_separated: Допустимі декілька значень (розділені комою). + text_issues_ref_in_commit_messages: Посилання та зміна питань у повідомленнях до подавань + text_issue_added: "Issue %{id} has been reported by %{author}." + text_issue_updated: "Issue %{id} has been updated by %{author}." + text_wiki_destroy_confirmation: Ви впевнені, що хочете видалити цю wiki і весь зміст? + text_issue_category_destroy_question: "Декілька питань (%{count}) призначено в цю категорію. Що ви хочете зробити?" + text_issue_category_destroy_assignments: Видалити призначення категорії + text_issue_category_reassign_to: Перепризначити задачі до даної категорії + text_user_mail_option: "Для невибраних проектів ви отримуватимете повідомлення тільки про те, що проглядаєте або в чому берете участь (наприклад, питання автором яких ви є або які вам призначені)." + + default_role_manager: Менеджер + default_role_developer: Розробник + default_role_reporter: Репортер + # default_tracker_bug: Bug + # звітів default_tracker_bug: Помилка + default_tracker_bug: Помилка + default_tracker_feature: Властивість + default_tracker_support: Підтримка + default_issue_status_new: Новий + default_issue_status_in_progress: In Progress + default_issue_status_resolved: Вирішено + default_issue_status_feedback: Зворотний зв'язок + default_issue_status_closed: Зачинено + default_issue_status_rejected: Відмовлено + default_doc_category_user: Документація користувача + default_doc_category_tech: Технічна документація + default_priority_low: Низький + default_priority_normal: Нормальний + default_priority_high: Високий + default_priority_urgent: Терміновий + default_priority_immediate: Негайний + default_activity_design: Проектування + default_activity_development: Розробка + + enumeration_issue_priorities: Пріоритети питань + enumeration_doc_categories: Категорії документів + enumeration_activities: Дії (облік часу) + text_status_changed_by_changeset: "Applied in changeset %{value}." + label_display_per_page: "Per page: %{value}" + label_issue_added: Issue added + label_issue_updated: Issue updated + setting_per_page_options: Objects per page options + notice_default_data_loaded: Default configuration successfully loaded. + error_scm_not_found: "Entry and/or revision doesn't exist in the repository." + label_associated_revisions: Associated revisions + label_document_added: Document added + label_message_posted: Message added + text_issues_destroy_confirmation: 'Are you sure you want to delete the selected issue(s) ?' + error_scm_command_failed: "An error occurred when trying to access the repository: %{value}" + setting_user_format: Users display format + label_age: Age + label_file_added: File added + label_more: More + field_default_value: Default value + label_scm: SCM + label_general: General + button_update: Update + text_select_project_modules: 'Select modules to enable for this project:' + label_change_properties: Change properties + text_load_default_configuration: Load the default configuration + text_no_configuration_data: "Roles, trackers, issue statuses and workflow have not been configured yet.\nIt is highly recommended to load the default configuration. You will be able to modify it once loaded." + label_news_added: News added + label_repository_plural: Repositories + error_can_t_load_default_data: "Default configuration could not be loaded: %{value}" + project_module_boards: Boards + project_module_issue_tracking: Issue tracking + project_module_wiki: Wiki + project_module_files: Files + project_module_documents: Documents + project_module_repository: Repository + project_module_news: News + project_module_time_tracking: Time tracking + text_file_repository_writable: File repository writable + text_default_administrator_account_changed: Default administrator account changed + text_rmagick_available: RMagick available (optional) + button_configure: Configure + label_plugins: Plugins + label_ldap_authentication: LDAP authentication + label_downloads_abbr: D/L + label_this_month: this month + label_last_n_days: "last %{count} days" + label_all_time: all time + label_this_year: this year + label_date_range: Date range + label_last_week: last week + label_yesterday: yesterday + label_last_month: last month + label_add_another_file: Add another file + label_optional_description: Optional description + text_destroy_time_entries_question: "%{hours} hours were reported on the issues you are about to delete. What do you want to do ?" + error_issue_not_found_in_project: 'The issue was not found or does not belong to this project' + text_assign_time_entries_to_project: Assign reported hours to the project + text_destroy_time_entries: Delete reported hours + text_reassign_time_entries: 'Reassign reported hours to this issue:' + setting_activity_days_default: Days displayed on project activity + label_chronological_order: In chronological order + field_comments_sorting: Display comments + label_reverse_chronological_order: In reverse chronological order + label_preferences: Preferences + setting_display_subprojects_issues: Display subprojects issues on main projects by default + label_overall_activity: Overall activity + setting_default_projects_public: New projects are public by default + error_scm_annotate: "The entry does not exist or can not be annotated." + label_planning: Planning + text_subprojects_destroy_warning: "Its subproject(s): %{value} will be also deleted." + label_and_its_subprojects: "%{value} and its subprojects" + mail_body_reminder: "%{count} issue(s) that are assigned to you are due in the next %{days} days:" + mail_subject_reminder: "%{count} issue(s) due in the next %{days} days" + text_user_wrote: "%{value} wrote:" + label_duplicated_by: duplicated by + setting_enabled_scm: Enabled SCM + text_enumeration_category_reassign_to: 'Reassign them to this value:' + text_enumeration_destroy_question: "%{count} objects are assigned to this value." + label_incoming_emails: Incoming emails + label_generate_key: Generate a key + setting_mail_handler_api_enabled: Enable WS for incoming emails + setting_mail_handler_api_key: API key + text_email_delivery_not_configured: "Email delivery is not configured, and notifications are disabled.\nConfigure your SMTP server in config/configuration.yml and restart the application to enable them." + field_parent_title: Parent page + label_issue_watchers: Watchers + button_quote: Quote + setting_sequential_project_identifiers: Generate sequential project identifiers + notice_unable_delete_version: Unable to delete version + label_renamed: renamed + label_copied: copied + setting_plain_text_mail: plain text only (no HTML) + permission_view_files: View files + permission_edit_issues: Edit issues + permission_edit_own_time_entries: Edit own time logs + permission_manage_public_queries: Manage public queries + permission_add_issues: Add issues + permission_log_time: Log spent time + permission_view_changesets: View changesets + permission_view_time_entries: View spent time + permission_manage_versions: Manage versions + permission_manage_wiki: Manage wiki + permission_manage_categories: Manage issue categories + permission_protect_wiki_pages: Protect wiki pages + permission_comment_news: Comment news + permission_delete_messages: Delete messages + permission_select_project_modules: Select project modules + permission_edit_wiki_pages: Edit wiki pages + permission_add_issue_watchers: Add watchers + permission_view_gantt: View gantt chart + permission_move_issues: Move issues + permission_manage_issue_relations: Manage issue relations + permission_delete_wiki_pages: Delete wiki pages + permission_manage_boards: Manage boards + permission_delete_wiki_pages_attachments: Delete attachments + permission_view_wiki_edits: View wiki history + permission_add_messages: Post messages + permission_view_messages: View messages + permission_manage_files: Manage files + permission_edit_issue_notes: Edit notes + permission_manage_news: Manage news + permission_view_calendar: View calendrier + permission_manage_members: Manage members + permission_edit_messages: Edit messages + permission_delete_issues: Delete issues + permission_view_issue_watchers: View watchers list + permission_manage_repository: Manage repository + permission_commit_access: Commit access + permission_browse_repository: Browse repository + permission_view_documents: View documents + permission_edit_project: Edit project + permission_add_issue_notes: Add notes + permission_save_queries: Save queries + permission_view_wiki_pages: View wiki + permission_rename_wiki_pages: Rename wiki pages + permission_edit_time_entries: Edit time logs + permission_edit_own_issue_notes: Edit own notes + setting_gravatar_enabled: Use Gravatar user icons + label_example: Example + text_repository_usernames_mapping: "Select ou update the Redmine user mapped to each username found in the repository log.\nUsers with the same Redmine and repository username or email are automatically mapped." + permission_edit_own_messages: Edit own messages + permission_delete_own_messages: Delete own messages + label_user_activity: "%{value}'s activity" + label_updated_time_by: "Updated by %{author} %{age} ago" + text_diff_truncated: '... This diff was truncated because it exceeds the maximum size that can be displayed.' + setting_diff_max_lines_displayed: Max number of diff lines displayed + text_plugin_assets_writable: Plugin assets directory writable + warning_attachments_not_saved: "%{count} file(s) could not be saved." + button_create_and_continue: Create and continue + text_custom_field_possible_values_info: 'One line for each value' + label_display: Display + field_editable: Editable + setting_repository_log_display_limit: Maximum number of revisions displayed on file log + setting_file_max_size_displayed: Max size of text files displayed inline + field_watcher: Watcher + setting_openid: Allow OpenID login and registration + field_identity_url: OpenID URL + label_login_with_open_id_option: or login with OpenID + field_content: Content + label_descending: Descending + label_sort: Sort + label_ascending: Ascending + label_date_from_to: From %{start} to %{end} + label_greater_or_equal: ">=" + label_less_or_equal: <= + text_wiki_page_destroy_question: This page has %{descendants} child page(s) and descendant(s). What do you want to do? + text_wiki_page_reassign_children: Reassign child pages to this parent page + text_wiki_page_nullify_children: Keep child pages as root pages + text_wiki_page_destroy_children: Delete child pages and all their descendants + setting_password_min_length: Minimum password length + field_group_by: Group results by + mail_subject_wiki_content_updated: "'%{id}' wiki page has been updated" + label_wiki_content_added: Wiki page added + mail_subject_wiki_content_added: "'%{id}' wiki page has been added" + mail_body_wiki_content_added: The '%{id}' wiki page has been added by %{author}. + label_wiki_content_updated: Wiki page updated + mail_body_wiki_content_updated: The '%{id}' wiki page has been updated by %{author}. + permission_add_project: Create project + setting_new_project_user_role_id: Role given to a non-admin user who creates a project + label_view_all_revisions: View all revisions + label_tag: Tag + label_branch: Branch + error_no_tracker_in_project: No tracker is associated to this project. Please check the Project settings. + error_no_default_issue_status: No default issue status is defined. Please check your configuration (Go to "Administration -> Issue statuses"). + text_journal_changed: "%{label} changed from %{old} to %{new}" + text_journal_set_to: "%{label} set to %{value}" + text_journal_deleted: "%{label} deleted (%{old})" + label_group_plural: Groups + label_group: Group + label_group_new: New group + label_time_entry_plural: Spent time + text_journal_added: "%{label} %{value} added" + field_active: Active + enumeration_system_activity: System Activity + permission_delete_issue_watchers: Delete watchers + version_status_closed: closed + version_status_locked: locked + version_status_open: open + error_can_not_reopen_issue_on_closed_version: An issue assigned to a closed version can not be reopened + label_user_anonymous: Anonymous + button_move_and_follow: Move and follow + setting_default_projects_modules: Default enabled modules for new projects + setting_gravatar_default: Default Gravatar image + field_sharing: Sharing + label_version_sharing_hierarchy: With project hierarchy + label_version_sharing_system: With all projects + label_version_sharing_descendants: With subprojects + label_version_sharing_tree: With project tree + label_version_sharing_none: Not shared + error_can_not_archive_project: This project can not be archived + button_duplicate: Duplicate + button_copy_and_follow: Copy and follow + label_copy_source: Source + setting_issue_done_ratio: Calculate the issue done ratio with + setting_issue_done_ratio_issue_status: Use the issue status + error_issue_done_ratios_not_updated: Issue done ratios not updated. + error_workflow_copy_target: Please select target tracker(s) and role(s) + setting_issue_done_ratio_issue_field: Use the issue field + label_copy_same_as_target: Same as target + label_copy_target: Target + notice_issue_done_ratios_updated: Issue done ratios updated. + error_workflow_copy_source: Please select a source tracker or role + label_update_issue_done_ratios: Update issue done ratios + setting_start_of_week: Start calendars on + permission_view_issues: View Issues + label_display_used_statuses_only: Only display statuses that are used by this tracker + label_revision_id: Revision %{value} + label_api_access_key: API access key + label_api_access_key_created_on: API access key created %{value} ago + label_feeds_access_key: RSS access key + notice_api_access_key_reseted: Your API access key was reset. + setting_rest_api_enabled: Enable REST web service + label_missing_api_access_key: Missing an API access key + label_missing_feeds_access_key: Missing a RSS access key + button_show: Show + text_line_separated: Multiple values allowed (one line for each value). + setting_mail_handler_body_delimiters: Truncate emails after one of these lines + permission_add_subprojects: Create subprojects + label_subproject_new: New subproject + text_own_membership_delete_confirmation: |- + You are about to remove some or all of your permissions and may no longer be able to edit this project after that. + Are you sure you want to continue? + label_close_versions: Close completed versions + label_board_sticky: Sticky + label_board_locked: Locked + permission_export_wiki_pages: Export wiki pages + setting_cache_formatted_text: Cache formatted text + permission_manage_project_activities: Manage project activities + error_unable_delete_issue_status: Unable to delete issue status + label_profile: Profile + permission_manage_subtasks: Manage subtasks + field_parent_issue: Parent task + label_subtask_plural: Subtasks + label_project_copy_notifications: Send email notifications during the project copy + error_can_not_delete_custom_field: Unable to delete custom field + error_unable_to_connect: Unable to connect (%{value}) + error_can_not_remove_role: This role is in use and can not be deleted. + error_can_not_delete_tracker: This tracker contains issues and can't be deleted. + field_principal: Principal + label_my_page_block: My page block + notice_failed_to_save_members: "Failed to save member(s): %{errors}." + text_zoom_out: Zoom out + text_zoom_in: Zoom in + notice_unable_delete_time_entry: Unable to delete time log entry. + label_overall_spent_time: Overall spent time + field_time_entries: Log time + project_module_gantt: Gantt + project_module_calendar: Calendar + button_edit_associated_wikipage: "Edit associated Wiki page: %{page_title}" + field_text: Text field + label_user_mail_option_only_owner: Only for things I am the owner of + setting_default_notification_option: Default notification option + label_user_mail_option_only_my_events: Only for things I watch or I'm involved in + label_user_mail_option_only_assigned: Only for things I am assigned to + label_user_mail_option_none: No events + field_member_of_group: Assignee's group + field_assigned_to_role: Assignee's role + notice_not_authorized_archived_project: The project you're trying to access has been archived. + label_principal_search: "Search for user or group:" + label_user_search: "Search for user:" + field_visible: Visible + setting_commit_logtime_activity_id: Activity for logged time + text_time_logged_by_changeset: Applied in changeset %{value}. + setting_commit_logtime_enabled: Enable time logging + notice_gantt_chart_truncated: The chart was truncated because it exceeds the maximum number of items that can be displayed (%{max}) + setting_gantt_items_limit: Maximum number of items displayed on the gantt chart + field_warn_on_leaving_unsaved: Warn me when leaving a page with unsaved text + text_warn_on_leaving_unsaved: The current page contains unsaved text that will be lost if you leave this page. + label_my_queries: My custom queries + text_journal_changed_no_detail: "%{label} updated" + label_news_comment_added: Comment added to a news + button_expand_all: Expand all + button_collapse_all: Collapse all + label_additional_workflow_transitions_for_assignee: Additional transitions allowed when the user is the assignee + label_additional_workflow_transitions_for_author: Additional transitions allowed when the user is the author + label_bulk_edit_selected_time_entries: Bulk edit selected time entries + text_time_entries_destroy_confirmation: Are you sure you want to delete the selected time entr(y/ies)? + label_role_anonymous: Anonymous + label_role_non_member: Non member + label_issue_note_added: Note added + label_issue_status_updated: Status updated + label_issue_priority_updated: Priority updated + label_issues_visibility_own: Issues created by or assigned to the user + field_issues_visibility: Issues visibility + label_issues_visibility_all: All issues + permission_set_own_issues_private: Set own issues public or private + field_is_private: Private + permission_set_issues_private: Set issues public or private + label_issues_visibility_public: All non private issues + text_issues_destroy_descendants_confirmation: This will also delete %{count} subtask(s). + field_commit_logs_encoding: Commit messages encoding + field_scm_path_encoding: Path encoding + text_scm_path_encoding_note: "Default: UTF-8" + field_path_to_repository: Path to repository + field_root_directory: Root directory + field_cvs_module: Module + field_cvsroot: CVSROOT + text_mercurial_repository_note: Local repository (e.g. /hgrepo, c:\hgrepo) + text_scm_command: Command + text_scm_command_version: Version + label_git_report_last_commit: Report last commit for files and directories + notice_issue_successful_create: Issue %{id} created. + label_between: between + setting_issue_group_assignment: Allow issue assignment to groups + label_diff: diff + text_git_repository_note: Repository is bare and local (e.g. /gitrepo, c:\gitrepo) + description_query_sort_criteria_direction: Sort direction + description_project_scope: Search scope + description_filter: Filter + description_user_mail_notification: Mail notification settings + description_date_from: Enter start date + description_message_content: Message content + description_available_columns: Available Columns + description_date_range_interval: Choose range by selecting start and end date + description_issue_category_reassign: Choose issue category + description_search: Searchfield + description_notes: Notes + description_date_range_list: Choose range from list + description_choose_project: Projects + description_date_to: Enter end date + description_query_sort_criteria_attribute: Sort attribute + description_wiki_subpages_reassign: Choose new parent page + description_selected_columns: Selected Columns + label_parent_revision: Parent + label_child_revision: Child + error_scm_annotate_big_text_file: The entry cannot be annotated, as it exceeds the maximum text file size. + setting_default_issue_start_date_to_creation_date: Use current date as start date for new issues + button_edit_section: Edit this section + setting_repositories_encodings: Attachments and repositories encodings + description_all_columns: All Columns + button_export: Export + label_export_options: "%{export_format} export options" + error_attachment_too_big: This file cannot be uploaded because it exceeds the maximum allowed file size (%{max_size}) + notice_failed_to_save_time_entries: "Failed to save %{count} time entrie(s) on %{total} selected: %{ids}." + label_x_issues: + zero: 0 Питання + one: 1 Питання + other: "%{count} Питання" + label_repository_new: New repository + field_repository_is_default: Main repository + label_copy_attachments: Copy attachments + label_item_position: "%{position}/%{count}" + label_completed_versions: Completed versions + text_project_identifier_info: Only lower case letters (a-z), numbers, dashes and underscores are allowed.
    Once saved, the identifier cannot be changed. + field_multiple: Multiple values + setting_commit_cross_project_ref: Allow issues of all the other projects to be referenced and fixed + text_issue_conflict_resolution_add_notes: Add my notes and discard my other changes + text_issue_conflict_resolution_overwrite: Apply my changes anyway (previous notes will be kept but some changes may be overwritten) + notice_issue_update_conflict: The issue has been updated by an other user while you were editing it. + text_issue_conflict_resolution_cancel: Discard all my changes and redisplay %{link} + permission_manage_related_issues: Manage related issues + field_auth_source_ldap_filter: LDAP filter + label_search_for_watchers: Search for watchers to add + notice_account_deleted: "Ваш обліковій запис повністю видалений" + setting_unsubscribe: "Дозволити користувачам видаляти свої облікові записи" + button_delete_my_account: "Видалити мій обліковий запис" + text_account_destroy_confirmation: "Ваш обліковий запис буде повністю видалений без можливості відновлення.\nВи певні, что бажаете продовжити?" + error_session_expired: Your session has expired. Please login again. + text_session_expiration_settings: "Warning: changing these settings may expire the current sessions including yours." + setting_session_lifetime: Session maximum lifetime + setting_session_timeout: Session inactivity timeout + label_session_expiration: Session expiration + permission_close_project: Close / reopen the project + label_show_closed_projects: View closed projects + button_close: Close + button_reopen: Reopen + project_status_active: active + project_status_closed: closed + project_status_archived: archived + text_project_closed: This project is closed and read-only. + notice_user_successful_create: User %{id} created. + field_core_fields: Standard fields + field_timeout: Timeout (in seconds) + setting_thumbnails_enabled: Display attachment thumbnails + setting_thumbnails_size: Thumbnails size (in pixels) + label_status_transitions: Status transitions + label_fields_permissions: Fields permissions + label_readonly: Read-only + label_required: Required + text_repository_identifier_info: Only lower case letters (a-z), numbers, dashes and underscores are allowed.
    Once saved, the identifier cannot be changed. + field_board_parent: Parent forum + label_attribute_of_project: Project's %{name} + label_attribute_of_author: Author's %{name} + label_attribute_of_assigned_to: Assignee's %{name} + label_attribute_of_fixed_version: Target version's %{name} + label_copy_subtasks: Copy subtasks + label_copied_to: copied to + label_copied_from: copied from + label_any_issues_in_project: any issues in project + label_any_issues_not_in_project: any issues not in project + field_private_notes: Private notes + permission_view_private_notes: View private notes + permission_set_notes_private: Set notes as private + label_no_issues_in_project: no issues in project + label_any: Усі + label_last_n_weeks: last %{count} weeks + setting_cross_project_subtasks: Allow cross-project subtasks + label_cross_project_descendants: With subprojects + label_cross_project_tree: With project tree + label_cross_project_hierarchy: With project hierarchy + label_cross_project_system: With all projects + button_hide: Hide + setting_non_working_week_days: Non-working days + label_in_the_next_days: in the next + label_in_the_past_days: in the past + label_attribute_of_user: User's %{name} + text_turning_multiple_off: If you disable multiple values, multiple values will be + removed in order to preserve only one value per item. + label_attribute_of_issue: Issue's %{name} + permission_add_documents: Add documents + permission_edit_documents: Edit documents + permission_delete_documents: Delete documents + label_gantt_progress_line: Progress line + setting_jsonp_enabled: Enable JSONP support + field_inherit_members: Inherit members + field_closed_on: Closed + setting_default_projects_tracker_ids: Default trackers for new projects + label_total_time: Всього + text_scm_config: You can configure your SCM commands in config/configuration.yml. Please restart the application after editing it. + text_scm_command_not_available: SCM command is not available. Please check settings on the administration panel. + setting_emails_header: Email header diff --git a/config/locales/vi.yml b/config/locales/vi.yml new file mode 100644 index 00000000..8703db8e --- /dev/null +++ b/config/locales/vi.yml @@ -0,0 +1,1142 @@ +# Vietnamese translation for Ruby on Rails +# by +# Do Hai Bac (dohaibac@gmail.com) +# Dao Thanh Ngoc (ngocdaothanh@gmail.com, http://github.com/ngocdaothanh/rails-i18n/tree/master) +# Nguyen Minh Thien (thiencdcn@gmail.com, http://www.eDesignLab.org) + +vi: + number: + # Used in number_with_delimiter() + # These are also the defaults for 'currency', 'percentage', 'precision', and 'human' + format: + # Sets the separator between the units, for more precision (e.g. 1.0 / 2.0 == 0.5) + separator: "," + # Delimets thousands (e.g. 1,000,000 is a million) (always in groups of three) + delimiter: "." + # Number of decimals, behind the separator (1 with a precision of 2 gives: 1.00) + precision: 3 + + # Used in number_to_currency() + currency: + format: + # Where is the currency sign? %u is the currency unit, %n the number (default: $5.00) + format: "%n %u" + unit: "đồng" + # These three are to override number.format and are optional + separator: "," + delimiter: "." + precision: 2 + + # Used in number_to_percentage() + percentage: + format: + # These three are to override number.format and are optional + # separator: + delimiter: "" + # precision: + + # Used in number_to_precision() + precision: + format: + # These three are to override number.format and are optional + # separator: + delimiter: "" + # precision: + + # Used in number_to_human_size() + human: + format: + # These three are to override number.format and are optional + # separator: + delimiter: "" + precision: 3 + storage_units: + format: "%n %u" + units: + byte: + one: "Byte" + other: "Bytes" + kb: "KB" + mb: "MB" + gb: "GB" + tb: "TB" + + # Used in distance_of_time_in_words(), distance_of_time_in_words_to_now(), time_ago_in_words() + datetime: + distance_in_words: + half_a_minute: "30 giây" + less_than_x_seconds: + one: "chưa tới 1 giây" + other: "chưa tới %{count} giây" + x_seconds: + one: "1 giây" + other: "%{count} giây" + less_than_x_minutes: + one: "chưa tới 1 phút" + other: "chưa tới %{count} phút" + x_minutes: + one: "1 phút" + other: "%{count} phút" + about_x_hours: + one: "khoảng 1 giờ" + other: "khoảng %{count} giờ" + x_hours: + one: "1 giờ" + other: "%{count} giờ" + x_days: + one: "1 ngày" + other: "%{count} ngày" + about_x_months: + one: "khoảng 1 tháng" + other: "khoảng %{count} tháng" + x_months: + one: "1 tháng" + other: "%{count} tháng" + about_x_years: + one: "khoảng 1 năm" + other: "khoảng %{count} năm" + over_x_years: + one: "hơn 1 năm" + other: "hơn %{count} năm" + almost_x_years: + one: "gần 1 năm" + other: "gần %{count} năm" + prompts: + year: "Năm" + month: "Tháng" + day: "Ngày" + hour: "Giờ" + minute: "Phút" + second: "Giây" + + activerecord: + errors: + template: + header: + one: "1 lỗi ngăn không cho lưu %{model} này" + other: "%{count} lỗi ngăn không cho lưu %{model} này" + # The variable :count is also available + body: "Có lỗi với các mục sau:" + + # The values :model, :attribute and :value are always available for interpolation + # The value :count is available when applicable. Can be used for pluralization. + messages: + inclusion: "không có trong danh sách" + exclusion: "đã được giành trước" + invalid: "không hợp lệ" + confirmation: "không khớp với xác nhận" + accepted: "phải được đồng ý" + empty: "không thể rỗng" + blank: "không thể để trắng" + too_long: "quá dài (tối đa %{count} ký tự)" + too_short: "quá ngắn (tối thiểu %{count} ký tự)" + wrong_length: "độ dài không đúng (phải là %{count} ký tự)" + taken: "đã có" + not_a_number: "không phải là số" + greater_than: "phải lớn hơn %{count}" + greater_than_or_equal_to: "phải lớn hơn hoặc bằng %{count}" + equal_to: "phải bằng %{count}" + less_than: "phải nhỏ hơn %{count}" + less_than_or_equal_to: "phải nhỏ hơn hoặc bằng %{count}" + odd: "phải là số chẵn" + even: "phải là số lẻ" + greater_than_start_date: "phải đi sau ngày bắt đầu" + not_same_project: "không thuộc cùng dự án" + circular_dependency: "quan hệ có thể gây ra lặp vô tận" + cant_link_an_issue_with_a_descendant: "Một vấn đề không thể liên kết tới một trong số những tác vụ con của nó" + + direction: ltr + date: + formats: + # Use the strftime parameters for formats. + # When no format has been given, it uses default. + # You can provide other formats here if you like! + default: "%d-%m-%Y" + short: "%d %b" + long: "%d %B, %Y" + + day_names: ["Chủ nhật", "Thứ hai", "Thứ ba", "Thứ tư", "Thứ năm", "Thứ sáu", "Thứ bảy"] + abbr_day_names: ["Chủ nhật", "Thứ hai", "Thứ ba", "Thứ tư", "Thứ năm", "Thứ sáu", "Thứ bảy"] + + # Don't forget the nil at the beginning; there's no such thing as a 0th month + month_names: [~, "Tháng một", "Tháng hai", "Tháng ba", "Tháng tư", "Tháng năm", "Tháng sáu", "Tháng bảy", "Tháng tám", "Tháng chín", "Tháng mười", "Tháng mười một", "Tháng mười hai"] + abbr_month_names: [~, "Tháng một", "Tháng hai", "Tháng ba", "Tháng tư", "Tháng năm", "Tháng sáu", "Tháng bảy", "Tháng tám", "Tháng chín", "Tháng mười", "Tháng mười một", "Tháng mười hai"] + # Used in date_select and datime_select. + order: + - :day + - :month + - :year + + time: + formats: + default: "%a, %d %b %Y %H:%M:%S %z" + time: "%H:%M" + short: "%d %b %H:%M" + long: "%d %B, %Y %H:%M" + am: "sáng" + pm: "chiều" + + # Used in array.to_sentence. + support: + array: + words_connector: ", " + two_words_connector: " và " + last_word_connector: ", và " + + actionview_instancetag_blank_option: Vui lòng chọn + + general_text_No: 'Không' + general_text_Yes: 'Có' + general_text_no: 'không' + general_text_yes: 'có' + general_lang_name: 'Tiếng Việt' + general_csv_separator: ',' + general_csv_decimal_separator: '.' + general_csv_encoding: UTF-8 + general_pdf_encoding: UTF-8 + general_first_day_of_week: '1' + + notice_account_updated: Cập nhật tài khoản thành công. + notice_account_invalid_creditentials: Tài khoản hoặc mật mã không hợp lệ + notice_account_password_updated: Cập nhật mật mã thành công. + notice_account_wrong_password: Sai mật mã + notice_account_register_done: Tài khoản được tạo thành công. Để kích hoạt vui lòng làm theo hướng dẫn trong email gửi đến bạn. + notice_account_unknown_email: Không rõ tài khoản. + notice_can_t_change_password: Tài khoản được chứng thực từ nguồn bên ngoài. Không thể đổi mật mã cho loại chứng thực này. + notice_account_lost_email_sent: Thông tin để đổi mật mã mới đã gửi đến bạn qua email. + notice_account_activated: Tài khoản vừa được kích hoạt. Bây giờ bạn có thể đăng nhập. + notice_successful_create: Tạo thành công. + notice_successful_update: Cập nhật thành công. + notice_successful_delete: Xóa thành công. + notice_successful_connection: Kết nối thành công. + notice_file_not_found: Trang bạn cố xem không tồn tại hoặc đã chuyển. + notice_locking_conflict: Thông tin đang được cập nhật bởi người khác. Hãy chép nội dung cập nhật của bạn vào clipboard. + notice_not_authorized: Bạn không có quyền xem trang này. + notice_email_sent: "Email đã được gửi tới %{value}" + notice_email_error: "Lỗi xảy ra khi gửi email (%{value})" + notice_feeds_access_key_reseted: Mã số chứng thực RSS đã được tạo lại. + notice_failed_to_save_issues: "Thất bại khi lưu %{count} vấn đề trong %{total} lựa chọn: %{ids}." + notice_no_issue_selected: "Không có vấn đề được chọn! Vui lòng kiểm tra các vấn đề bạn cần chỉnh sửa." + notice_account_pending: "Thông tin tài khoản đã được tạo ra và đang chờ chứng thực từ ban quản trị." + notice_default_data_loaded: Đã nạp cấu hình mặc định. + notice_unable_delete_version: Không thể xóa phiên bản. + + error_can_t_load_default_data: "Không thể nạp cấu hình mặc định: %{value}" + error_scm_not_found: "Không tìm thấy dữ liệu trong kho chứa." + error_scm_command_failed: "Lỗi xảy ra khi truy cập vào kho lưu trữ: %{value}" + error_scm_annotate: "Đầu vào không tồn tại hoặc không thể chú thích." + error_issue_not_found_in_project: 'Vấn đề không tồn tại hoặc không thuộc dự án' + + mail_subject_lost_password: "%{value}: mật mã của bạn" + mail_body_lost_password: "Để đổi mật mã, hãy click chuột vào liên kết sau:" + mail_subject_register: "%{value}: kích hoạt tài khoản" + mail_body_register: "Để kích hoạt tài khoản, hãy click chuột vào liên kết sau:" + mail_body_account_information_external: " Bạn có thể dùng tài khoản %{value} để đăng nhập." + mail_body_account_information: Thông tin về tài khoản + mail_subject_account_activation_request: "%{value}: Yêu cầu chứng thực tài khoản" + mail_body_account_activation_request: "Người dùng (%{value}) mới đăng ký và cần bạn xác nhận:" + mail_subject_reminder: "%{count} vấn đề hết hạn trong các %{days} ngày tới" + mail_body_reminder: "%{count} công việc bạn được phân công sẽ hết hạn trong %{days} ngày tới:" + + field_name: Tên dự án + field_description: Mô tả + field_summary: Tóm tắt + field_is_required: Bắt buộc + field_firstname: Tên đệm và Tên + field_lastname: Họ + field_mail: Email + field_filename: Tập tin + field_filesize: Cỡ + field_downloads: Tải về + field_author: Tác giả + field_created_on: Tạo + field_updated_on: Cập nhật + field_field_format: Định dạng + field_is_for_all: Cho mọi dự án + field_possible_values: Giá trị hợp lệ + field_regexp: Biểu thức chính quy + field_min_length: Chiều dài tối thiểu + field_max_length: Chiều dài tối đa + field_value: Giá trị + field_category: Chủ đề + field_title: Tiêu đề + field_project: Dự án + field_issue: Vấn đề + field_status: Trạng thái + field_notes: Ghi chú + field_is_closed: Vấn đề đóng + field_is_default: Giá trị mặc định + field_tracker: Kiểu vấn đề + field_subject: Chủ đề + field_due_date: Hết hạn + field_assigned_to: Phân công cho + field_priority: Mức ưu tiên + field_fixed_version: Phiên bản + field_user: Người dùng + field_role: Quyền + field_homepage: Trang chủ + field_is_public: Công cộng + field_parent: Dự án con của + field_is_in_roadmap: Có thể thấy trong Kế hoạch + field_login: Đăng nhập + field_mail_notification: Thông báo qua email + field_admin: Quản trị + field_last_login_on: Kết nối cuối + field_language: Ngôn ngữ + field_effective_date: Ngày + field_password: Mật khẩu + field_new_password: Mật khẩu mới + field_password_confirmation: Nhập lại mật khẩu + field_version: Phiên bản + field_type: Kiểu + field_host: Host + field_port: Cổng + field_account: Tài khoản + field_base_dn: Base DN + field_attr_login: Thuộc tính đăng nhập + field_attr_firstname: Thuộc tính tên đệm và Tên + field_attr_lastname: Thuộc tính Họ + field_attr_mail: Thuộc tính Email + field_onthefly: Tạo người dùng tức thì + field_start_date: Bắt đầu + field_done_ratio: Tiến độ + field_auth_source: Chế độ xác thực + field_hide_mail: Không hiện email của tôi + field_comments: Bình luận + field_url: URL + field_start_page: Trang bắt đầu + field_subproject: Dự án con + field_hours: Giờ + field_activity: Hoạt động + field_spent_on: Ngày + field_identifier: Mã nhận dạng + field_is_filter: Dùng như bộ lọc + field_issue_to: Vấn đề liên quan + field_delay: Độ trễ + field_assignable: Vấn đề có thể gán cho vai trò này + field_redirect_existing_links: Chuyển hướng trang đã có + field_estimated_hours: Thời gian ước lượng + field_column_names: Cột + field_time_zone: Múi giờ + field_searchable: Tìm kiếm được + field_default_value: Giá trị mặc định + field_comments_sorting: Liệt kê bình luận + field_parent_title: Trang mẹ + + setting_app_title: Tựa đề ứng dụng + setting_app_subtitle: Tựa đề nhỏ của ứng dụng + setting_welcome_text: Thông điệp chào mừng + setting_default_language: Ngôn ngữ mặc định + setting_login_required: Cần đăng nhập + setting_self_registration: Tự chứng thực + setting_attachment_max_size: Cỡ tối đa của tập tin đính kèm + setting_issues_export_limit: Giới hạn Export vấn đề + setting_mail_from: Địa chỉ email gửi thông báo + setting_bcc_recipients: Tạo bản CC bí mật (bcc) + setting_host_name: Tên miền và đường dẫn + setting_text_formatting: Định dạng bài viết + setting_wiki_compression: Nén lịch sử Wiki + setting_feeds_limit: Giới hạn nội dung của feed + setting_default_projects_public: Dự án mặc định là public + setting_autofetch_changesets: Tự động tìm nạp commits + setting_sys_api_enabled: Cho phép WS quản lý kho chứa + setting_commit_ref_keywords: Từ khóa tham khảo + setting_commit_fix_keywords: Từ khóa chỉ vấn đề đã giải quyết + setting_autologin: Tự động đăng nhập + setting_date_format: Định dạng ngày + setting_time_format: Định dạng giờ + setting_cross_project_issue_relations: Cho phép quan hệ chéo giữa các dự án + setting_issue_list_default_columns: Các cột mặc định hiển thị trong danh sách vấn đề + setting_emails_footer: Chữ ký cuối thư + setting_protocol: Giao thức + setting_per_page_options: Tùy chọn đối tượng mỗi trang + setting_user_format: Định dạng hiển thị người dùng + setting_activity_days_default: Ngày hiển thị hoạt động của dự án + setting_display_subprojects_issues: Hiển thị mặc định vấn đề của dự án con ở dự án chính + setting_enabled_scm: Cho phép SCM + setting_mail_handler_api_enabled: Cho phép WS cho các email tới + setting_mail_handler_api_key: Mã số API + setting_sequential_project_identifiers: Tự sinh chuỗi ID dự án + + project_module_issue_tracking: Theo dõi vấn đề + project_module_time_tracking: Theo dõi thời gian + project_module_news: Tin tức + project_module_documents: Tài liệu + project_module_files: Tập tin + project_module_wiki: Wiki + project_module_repository: Kho lưu trữ + project_module_boards: Diễn đàn + + label_user: Tài khoản + label_user_plural: Tài khoản + label_user_new: Tài khoản mới + label_project: Dự án + label_project_new: Dự án mới + label_project_plural: Dự án + label_x_projects: + zero: không có dự án + one: một dự án + other: "%{count} dự án" + label_project_all: Mọi dự án + label_project_latest: Dự án mới nhất + label_issue: Vấn đề + label_issue_new: Tạo vấn đề mới + label_issue_plural: Vấn đề + label_issue_view_all: Tất cả vấn đề + label_issues_by: "Vấn đề của %{value}" + label_issue_added: Đã thêm vấn đề + label_issue_updated: Vấn đề được cập nhật + label_document: Tài liệu + label_document_new: Tài liệu mới + label_document_plural: Tài liệu + label_document_added: Đã thêm tài liệu + label_role: Vai trò + label_role_plural: Vai trò + label_role_new: Vai trò mới + label_role_and_permissions: Vai trò và Quyền hạn + label_member: Thành viên + label_member_new: Thành viên mới + label_member_plural: Thành viên + label_tracker: Kiểu vấn đề + label_tracker_plural: Kiểu vấn đề + label_tracker_new: Tạo kiểu vấn đề mới + label_workflow: Quy trình làm việc + label_issue_status: Trạng thái vấn đề + label_issue_status_plural: Trạng thái vấn đề + label_issue_status_new: Thêm trạng thái + label_issue_category: Chủ đề + label_issue_category_plural: Chủ đề + label_issue_category_new: Chủ đề mới + label_custom_field: Trường tùy biến + label_custom_field_plural: Trường tùy biến + label_custom_field_new: Thêm Trường tùy biến + label_enumerations: Liệt kê + label_enumeration_new: Thêm giá trị + label_information: Thông tin + label_information_plural: Thông tin + label_please_login: Vui lòng đăng nhập + label_register: Đăng ký + label_password_lost: Phục hồi mật mã + label_home: Trang chính + label_my_page: Trang riêng + label_my_account: Cá nhân + label_my_projects: Dự án của bạn + label_administration: Quản trị + label_login: Đăng nhập + label_logout: Thoát + label_help: Giúp đỡ + label_reported_issues: Công việc bạn phân công + label_assigned_to_me_issues: Công việc được phân công + label_last_login: Kết nối cuối + label_registered_on: Ngày tham gia + label_activity: Hoạt động + label_overall_activity: Tất cả hoạt động + label_new: Mới + label_logged_as: Tài khoản » + label_environment: Môi trường + label_authentication: Xác thực + label_auth_source: Chế độ xác thực + label_auth_source_new: Chế độ xác thực mới + label_auth_source_plural: Chế độ xác thực + label_subproject_plural: Dự án con + label_and_its_subprojects: "%{value} và dự án con" + label_min_max_length: Độ dài nhỏ nhất - lớn nhất + label_list: Danh sách + label_date: Ngày + label_integer: Số nguyên + label_float: Số thực + label_boolean: Boolean + label_string: Văn bản + label_text: Văn bản dài + label_attribute: Thuộc tính + label_attribute_plural: Các thuộc tính + label_no_data: Chưa có thông tin gì + label_change_status: Đổi trạng thái + label_history: Lược sử + label_attachment: Tập tin + label_attachment_new: Thêm tập tin mới + label_attachment_delete: Xóa tập tin + label_attachment_plural: Tập tin + label_file_added: Đã thêm tập tin + label_report: Báo cáo + label_report_plural: Báo cáo + label_news: Tin tức + label_news_new: Thêm tin + label_news_plural: Tin tức + label_news_latest: Tin mới + label_news_view_all: Xem mọi tin + label_news_added: Đã thêm tin + label_settings: Thiết lập + label_overview: Tóm tắt + label_version: Phiên bản + label_version_new: Phiên bản mới + label_version_plural: Phiên bản + label_confirmation: Khẳng định + label_export_to: 'Định dạng khác của trang này:' + label_read: Đọc... + label_public_projects: Các dự án công cộng + label_open_issues: mở + label_open_issues_plural: mở + label_closed_issues: đóng + label_closed_issues_plural: đóng + label_x_open_issues_abbr_on_total: + zero: "0 mở / %{total}" + one: "1 mở / %{total}" + other: "%{count} mở / %{total}" + label_x_open_issues_abbr: + zero: 0 mở + one: 1 mở + other: "%{count} mở" + label_x_closed_issues_abbr: + zero: 0 đóng + one: 1 đóng + other: "%{count} đóng" + label_total: Tổng cộng + label_permissions: Quyền + label_current_status: Trạng thái hiện tại + label_new_statuses_allowed: Trạng thái mới được phép + label_all: Tất cả + label_none: không + label_nobody: Chẳng ai + label_next: Sau + label_previous: Trước + label_used_by: Được dùng bởi + label_details: Chi tiết + label_add_note: Thêm ghi chú + label_per_page: Mỗi trang + label_calendar: Lịch + label_months_from: tháng từ + label_gantt: Biểu đồ sự kiện + label_internal: Nội bộ + label_last_changes: "%{count} thay đổi cuối" + label_change_view_all: Xem mọi thay đổi + label_personalize_page: Điều chỉnh trang này + label_comment: Bình luận + label_comment_plural: Bình luận + label_x_comments: + zero: không có bình luận + one: 1 bình luận + other: "%{count} bình luận" + label_comment_add: Thêm bình luận + label_comment_added: Đã thêm bình luận + label_comment_delete: Xóa bình luận + label_query: Truy vấn riêng + label_query_plural: Truy vấn riêng + label_query_new: Truy vấn mới + label_filter_add: Thêm lọc + label_filter_plural: Bộ lọc + label_equals: là + label_not_equals: không là + label_in_less_than: ít hơn + label_in_more_than: nhiều hơn + label_in: trong + label_today: hôm nay + label_all_time: mọi thời gian + label_yesterday: hôm qua + label_this_week: tuần này + label_last_week: tuần trước + label_last_n_days: "%{count} ngày cuối" + label_this_month: tháng này + label_last_month: tháng cuối + label_this_year: năm này + label_date_range: Thời gian + label_less_than_ago: cách đây dưới + label_more_than_ago: cách đây hơn + label_ago: cách đây + label_contains: chứa + label_not_contains: không chứa + label_day_plural: ngày + label_repository: Kho lưu trữ + label_repository_plural: Kho lưu trữ + label_browse: Duyệt + label_revision: Bản điều chỉnh + label_revision_plural: Bản điều chỉnh + label_associated_revisions: Các bản điều chỉnh được ghép + label_added: thêm + label_modified: đổi + label_copied: chép + label_renamed: đổi tên + label_deleted: xóa + label_latest_revision: Bản điều chỉnh cuối cùng + label_latest_revision_plural: Bản điều chỉnh cuối cùng + label_view_revisions: Xem các bản điều chỉnh + label_max_size: Dung lượng tối đa + label_sort_highest: Lên trên cùng + label_sort_higher: Dịch lên + label_sort_lower: Dịch xuống + label_sort_lowest: Xuống dưới cùng + label_roadmap: Kế hoạch + label_roadmap_due_in: "Hết hạn trong %{value}" + label_roadmap_overdue: "Trễ %{value}" + label_roadmap_no_issues: Không có vấn đề cho phiên bản này + label_search: Tìm + label_result_plural: Kết quả + label_all_words: Mọi từ + label_wiki: Wiki + label_wiki_edit: Sửa Wiki + label_wiki_edit_plural: Thay đổi wiki + label_wiki_page: Trang wiki + label_wiki_page_plural: Trang wiki + label_index_by_title: Danh sách theo tên + label_index_by_date: Danh sách theo ngày + label_current_version: Bản hiện tại + label_preview: Xem trước + label_feed_plural: Nguồn cấp tin + label_changes_details: Chi tiết của mọi thay đổi + label_issue_tracking: Vấn đề + label_spent_time: Thời gian + label_f_hour: "%{value} giờ" + label_f_hour_plural: "%{value} giờ" + label_time_tracking: Theo dõi thời gian + label_change_plural: Thay đổi + label_statistics: Thống kê + label_commits_per_month: Commits mỗi tháng + label_commits_per_author: Commits mỗi tác giả + label_view_diff: So sánh + label_diff_inline: inline + label_diff_side_by_side: bên cạnh nhau + label_options: Tùy chọn + label_copy_workflow_from: Sao chép quy trình từ + label_permissions_report: Thống kê các quyền + label_watched_issues: Chủ đề đang theo dõi + label_related_issues: Liên quan + label_applied_status: Trạng thái áp dụng + label_loading: Đang xử lý... + label_relation_new: Quan hệ mới + label_relation_delete: Xóa quan hệ + label_relates_to: liên quan + label_duplicates: trùng với + label_duplicated_by: bị trùng bởi + label_blocks: chặn + label_blocked_by: chặn bởi + label_precedes: đi trước + label_follows: đi sau + label_end_to_start: cuối tới đầu + label_end_to_end: cuối tới cuối + label_start_to_start: đầu tớ đầu + label_start_to_end: đầu tới cuối + label_stay_logged_in: Lưu thông tin đăng nhập + label_disabled: Bị vô hiệu + label_show_completed_versions: Xem phiên bản đã hoàn thành + label_me: tôi + label_board: Diễn đàn + label_board_new: Tạo diễn đàn mới + label_board_plural: Diễn đàn + label_topic_plural: Chủ đề + label_message_plural: Diễn đàn + label_message_last: Bài cuối + label_message_new: Tạo bài mới + label_message_posted: Đã thêm bài viết + label_reply_plural: Hồi âm + label_send_information: Gửi thông tin đến người dùng qua email + label_year: Năm + label_month: Tháng + label_week: Tuần + label_date_from: Từ + label_date_to: Đến + label_language_based: Theo ngôn ngữ người dùng + label_sort_by: "Sắp xếp theo %{value}" + label_send_test_email: Gửi một email kiểm tra + label_feeds_access_key_created_on: "Mã chứng thực RSS được tạo ra cách đây %{value}" + label_module_plural: Module + label_added_time_by: "Thêm bởi %{author} cách đây %{age}" + label_updated_time: "Cập nhật cách đây %{value}" + label_jump_to_a_project: Nhảy đến dự án... + label_file_plural: Tập tin + label_changeset_plural: Thay đổi + label_default_columns: Cột mặc định + label_no_change_option: (không đổi) + label_bulk_edit_selected_issues: Sửa nhiều vấn đề + label_theme: Giao diện + label_default: Mặc định + label_search_titles_only: Chỉ tìm trong tựa đề + label_user_mail_option_all: "Mọi sự kiện trên mọi dự án của tôi" + label_user_mail_option_selected: "Mọi sự kiện trên các dự án được chọn..." + label_user_mail_no_self_notified: "Đừng gửi email về các thay đổi do chính tôi thực hiện" + label_registration_activation_by_email: kích hoạt tài khoản qua email + label_registration_manual_activation: kích hoạt tài khoản thủ công + label_registration_automatic_activation: kích hoạt tài khoản tự động + label_display_per_page: "mỗi trang: %{value}" + label_age: Thời gian + label_change_properties: Thay đổi thuộc tính + label_general: Tổng quan + label_more: Chi tiết + label_scm: SCM + label_plugins: Module + label_ldap_authentication: Chứng thực LDAP + label_downloads_abbr: Số lượng Download + label_optional_description: Mô tả bổ sung + label_add_another_file: Thêm tập tin khác + label_preferences: Cấu hình + label_chronological_order: Bài cũ xếp trước + label_reverse_chronological_order: Bài mới xếp trước + label_planning: Kế hoạch + label_incoming_emails: Nhận mail + label_generate_key: Tạo mã + label_issue_watchers: Theo dõi + + button_login: Đăng nhập + button_submit: Gửi + button_save: Lưu + button_check_all: Đánh dấu tất cả + button_uncheck_all: Bỏ dấu tất cả + button_delete: Xóa + button_create: Tạo + button_test: Kiểm tra + button_edit: Sửa + button_add: Thêm + button_change: Đổi + button_apply: Áp dụng + button_clear: Xóa + button_lock: Khóa + button_unlock: Mở khóa + button_download: Tải về + button_list: Liệt kê + button_view: Xem + button_move: Chuyển + button_back: Quay lại + button_cancel: Bỏ qua + button_activate: Kích hoạt + button_sort: Sắp xếp + button_log_time: Thêm thời gian + button_rollback: Quay trở lại phiên bản này + button_watch: Theo dõi + button_unwatch: Bỏ theo dõi + button_reply: Trả lời + button_archive: Đóng băng + button_unarchive: Xả băng + button_reset: Tạo lại + button_rename: Đổi tên + button_change_password: Đổi mật mã + button_copy: Sao chép + button_annotate: Chú giải + button_update: Cập nhật + button_configure: Cấu hình + button_quote: Trích dẫn + + status_active: Đang hoạt động + status_registered: Mới đăng ký + status_locked: Đã khóa + + text_select_mail_notifications: Chọn hành động đối với mỗi email sẽ gửi. + text_regexp_info: eg. ^[A-Z0-9]+$ + text_min_max_length_info: 0 để chỉ không hạn chế + text_project_destroy_confirmation: Bạn có chắc chắn muốn xóa dự án này và các dữ liệu liên quan ? + text_subprojects_destroy_warning: "Dự án con của : %{value} cũng sẽ bị xóa." + text_workflow_edit: Chọn một vai trò và một vấn đề để sửa quy trình + text_are_you_sure: Bạn chắc chứ? + text_tip_issue_begin_day: ngày bắt đầu + text_tip_issue_end_day: ngày kết thúc + text_tip_issue_begin_end_day: bắt đầu và kết thúc cùng ngày + text_caracters_maximum: "Tối đa %{count} ký tự." + text_caracters_minimum: "Phải gồm ít nhất %{count} ký tự." + text_length_between: "Chiều dài giữa %{min} và %{max} ký tự." + text_tracker_no_workflow: Không có quy trình được định nghĩa cho theo dõi này + text_unallowed_characters: Ký tự không hợp lệ + text_comma_separated: Nhiều giá trị được phép (cách nhau bởi dấu phẩy). + text_issues_ref_in_commit_messages: Vấn đề tham khảo và cố định trong ghi chú commit + text_issue_added: "Vấn đề %{id} đã được báo cáo bởi %{author}." + text_issue_updated: "Vấn đề %{id} đã được cập nhật bởi %{author}." + text_wiki_destroy_confirmation: Bạn có chắc chắn muốn xóa trang wiki này và tất cả nội dung của nó ? + text_issue_category_destroy_question: "Một số vấn đề (%{count}) được gán cho danh mục này. Bạn muốn làm gì ?" + text_issue_category_destroy_assignments: Gỡ bỏ danh mục được phân công + text_issue_category_reassign_to: Gán lại vấn đề cho danh mục này + text_user_mail_option: "Với các dự án không được chọn, bạn chỉ có thể nhận được thông báo về các vấn đề bạn đăng ký theo dõi hoặc có liên quan đến bạn (chẳng hạn, vấn đề được gán cho bạn)." + text_no_configuration_data: "Quyền, theo dõi, tình trạng vấn đề và quy trình chưa được cấu hình.\nBắt buộc phải nạp cấu hình mặc định. Bạn sẽ thay đổi nó được sau khi đã nạp." + text_load_default_configuration: Nạp lại cấu hình mặc định + text_status_changed_by_changeset: "Áp dụng trong changeset : %{value}." + text_issues_destroy_confirmation: 'Bạn có chắc chắn muốn xóa các vấn đề đã chọn ?' + text_select_project_modules: 'Chọn các module cho dự án:' + text_default_administrator_account_changed: Thay đổi tài khoản quản trị mặc định + text_file_repository_writable: Cho phép ghi thư mục đính kèm + text_rmagick_available: Trạng thái RMagick + text_destroy_time_entries_question: "Thời gian %{hours} giờ đã báo cáo trong vấn đề bạn định xóa. Bạn muốn làm gì tiếp ?" + text_destroy_time_entries: Xóa thời gian báo cáo + text_assign_time_entries_to_project: Gán thời gian báo cáo cho dự án + text_reassign_time_entries: 'Gán lại thời gian báo cáo cho Vấn đề này:' + text_user_wrote: "%{value} đã viết:" + text_enumeration_destroy_question: "%{count} đối tượng được gán giá trị này." + text_enumeration_category_reassign_to: 'Gán lại giá trị này:' + text_email_delivery_not_configured: "Cấu hình gửi Email chưa được đặt, và chức năng thông báo bị loại bỏ.\nCấu hình máy chủ SMTP của bạn ở file config/configuration.yml và khởi động lại để kích hoạt chúng." + + default_role_manager: 'Điều hành ' + default_role_developer: 'Phát triển ' + default_role_reporter: Báo cáo + default_tracker_bug: Lỗi + default_tracker_feature: Tính năng + default_tracker_support: Hỗ trợ + default_issue_status_new: Mới + default_issue_status_in_progress: Đang tiến hành + default_issue_status_resolved: Đã được giải quyết + default_issue_status_feedback: Phản hồi + default_issue_status_closed: Đã đóng + default_issue_status_rejected: Từ chối + default_doc_category_user: Tài liệu người dùng + default_doc_category_tech: Tài liệu kỹ thuật + default_priority_low: Thấp + default_priority_normal: Bình thường + default_priority_high: Cao + default_priority_urgent: Khẩn cấp + default_priority_immediate: Trung bình + default_activity_design: Thiết kế + default_activity_development: Phát triển + + enumeration_issue_priorities: Mức độ ưu tiên vấn đề + enumeration_doc_categories: Danh mục tài liệu + enumeration_activities: Hoạt động + + setting_plain_text_mail: Mail dạng text đơn giản (không dùng HTML) + setting_gravatar_enabled: Dùng biểu tượng Gravatar + permission_edit_project: Chỉnh dự án + permission_select_project_modules: Chọn Module + permission_manage_members: Quản lý thành viên + permission_manage_versions: Quản lý phiên bản + permission_manage_categories: Quản lý chủ đề + permission_add_issues: Thêm vấn đề + permission_edit_issues: Sửa vấn đề + permission_manage_issue_relations: Quản lý quan hệ vấn đề + permission_add_issue_notes: Thêm chú thích + permission_edit_issue_notes: Sửa chú thích + permission_edit_own_issue_notes: Sửa chú thích cá nhân + permission_move_issues: Chuyển vấn đề + permission_delete_issues: Xóa vấn đề + permission_manage_public_queries: Quản lý truy vấn công cộng + permission_save_queries: Lưu truy vấn + permission_view_gantt: Xem biểu đồ sự kiện + permission_view_calendar: Xem lịch + permission_view_issue_watchers: Xem những người theo dõi + permission_add_issue_watchers: Thêm người theo dõi + permission_log_time: Lưu thời gian đã qua + permission_view_time_entries: Xem thời gian đã qua + permission_edit_time_entries: Xem nhật ký thời gian + permission_edit_own_time_entries: Sửa thời gian đã lưu + permission_manage_news: Quản lý tin mới + permission_comment_news: Chú thích vào tin mới + permission_view_documents: Xem tài liệu + permission_manage_files: Quản lý tập tin + permission_view_files: Xem tập tin + permission_manage_wiki: Quản lý wiki + permission_rename_wiki_pages: Đổi tên trang wiki + permission_delete_wiki_pages: Xóa trang wiki + permission_view_wiki_pages: Xem wiki + permission_view_wiki_edits: Xem lược sử trang wiki + permission_edit_wiki_pages: Sửa trang wiki + permission_delete_wiki_pages_attachments: Xóa tệp đính kèm + permission_protect_wiki_pages: Bảo vệ trang wiki + permission_manage_repository: Quản lý kho lưu trữ + permission_browse_repository: Duyệt kho lưu trữ + permission_view_changesets: Xem các thay đổi + permission_commit_access: Truy cập commit + permission_manage_boards: Quản lý diễn đàn + permission_view_messages: Xem bài viết + permission_add_messages: Gửi bài viết + permission_edit_messages: Sửa bài viết + permission_edit_own_messages: Sửa bài viết cá nhân + permission_delete_messages: Xóa bài viết + permission_delete_own_messages: Xóa bài viết cá nhân + label_example: Ví dụ + text_repository_usernames_mapping: "Lựa chọn hoặc cập nhật ánh xạ người dùng hệ thống với người dùng trong kho lưu trữ.\nKhi người dùng trùng hợp về tên và email sẽ được tự động ánh xạ." + permission_delete_own_messages: Xóa thông điệp + label_user_activity: "%{value} hoạt động" + label_updated_time_by: "Cập nhật bởi %{author} cách đây %{age}" + text_diff_truncated: '... Thay đổi này đã được cắt bớt do nó vượt qua giới hạn kích thước có thể hiển thị.' + setting_diff_max_lines_displayed: Số dòng thay đổi tối đa được hiển thị + text_plugin_assets_writable: Cho phép ghi thư mục Plugin + warning_attachments_not_saved: "%{count} file không được lưu." + button_create_and_continue: Tạo và tiếp tục + text_custom_field_possible_values_info: 'Một dòng cho mỗi giá trị' + label_display: Hiển thị + field_editable: Có thể sửa được + setting_repository_log_display_limit: Số lượng tối đa các bản điều chỉnh hiển thị trong file log + setting_file_max_size_displayed: Kích thước tối đa của tệp tin văn bản + field_watcher: Người quan sát + setting_openid: Cho phép đăng nhập và đăng ký dùng OpenID + field_identity_url: OpenID URL + label_login_with_open_id_option: hoặc đăng nhập với OpenID + field_content: Nội dung + label_descending: Giảm dần + label_sort: Sắp xếp + label_ascending: Tăng dần + label_date_from_to: "Từ %{start} tới %{end}" + label_greater_or_equal: ">=" + label_less_or_equal: "<=" + text_wiki_page_destroy_question: "Trang này có %{descendants} trang con và trang cháu. Bạn muốn làm gì tiếp?" + text_wiki_page_reassign_children: Gán lại trang con vào trang mẹ này + text_wiki_page_nullify_children: Giữ trang con như trang gốc + text_wiki_page_destroy_children: Xóa trang con và tất cả trang con cháu của nó + setting_password_min_length: Chiều dài tối thiểu của mật khẩu + field_group_by: Nhóm kết quả bởi + mail_subject_wiki_content_updated: "%{id} trang wiki đã được cập nhật" + label_wiki_content_added: Đã thêm trang Wiki + mail_subject_wiki_content_added: "%{id} trang wiki đã được thêm vào" + mail_body_wiki_content_added: "Có %{id} trang wiki đã được thêm vào bởi %{author}." + label_wiki_content_updated: Trang Wiki đã được cập nhật + mail_body_wiki_content_updated: "Có %{id} trang wiki đã được cập nhật bởi %{author}." + permission_add_project: Tạo dự án + setting_new_project_user_role_id: Quyền được gán cho người dùng không phải quản trị viên khi tạo dự án mới + label_view_all_revisions: Xem tất cả bản điều chỉnh + label_tag: Thẻ + label_branch: Nhánh + error_no_tracker_in_project: Không có ai theo dõi dự án này. Hãy kiểm tra lại phần thiết lập cho dự án. + error_no_default_issue_status: Không có vấn đề mặc định được định nghĩa. Vui lòng kiểm tra cấu hình của bạn (Vào "Quản trị -> Trạng thái vấn đề"). + text_journal_changed: "%{label} thay đổi từ %{old} tới %{new}" + text_journal_set_to: "%{label} gán cho %{value}" + text_journal_deleted: "%{label} xóa (%{old})" + label_group_plural: Các nhóm + label_group: Nhóm + label_group_new: Thêm nhóm + label_time_entry_plural: Thời gian đã sử dụng + text_journal_added: "%{label} %{value} được thêm" + field_active: Tích cực + enumeration_system_activity: Hoạt động hệ thống + permission_delete_issue_watchers: Xóa người quan sát + version_status_closed: đóng + version_status_locked: khóa + version_status_open: mở + error_can_not_reopen_issue_on_closed_version: Một vấn đề được gán cho phiên bản đã đóng không thể mở lại được + label_user_anonymous: Ẩn danh + button_move_and_follow: Di chuyển và theo + setting_default_projects_modules: Các Module được kích hoạt mặc định cho dự án mới + setting_gravatar_default: Ảnh Gravatar mặc định + field_sharing: Chia sẻ + label_version_sharing_hierarchy: Với thứ bậc dự án + label_version_sharing_system: Với tất cả dự án + label_version_sharing_descendants: Với dự án con + label_version_sharing_tree: Với cây dự án + label_version_sharing_none: Không chia sẻ + error_can_not_archive_project: Dựa án này không thể lưu trữ được + button_duplicate: Nhân đôi + button_copy_and_follow: Sao chép và theo + label_copy_source: Nguồn + setting_issue_done_ratio: Tính toán tỷ lệ hoàn thành vấn đề với + setting_issue_done_ratio_issue_status: Sử dụng trạng thái của vấn đề + error_issue_done_ratios_not_updated: Tỷ lệ hoàn thành vấn đề không được cập nhật. + error_workflow_copy_target: Vui lòng lựa chọn đích của theo dấu và quyền + setting_issue_done_ratio_issue_field: Dùng trường vấn đề + label_copy_same_as_target: Tương tự như đích + label_copy_target: Đích + notice_issue_done_ratios_updated: Tỷ lệ hoàn thành vấn đề được cập nhật. + error_workflow_copy_source: Vui lòng lựa chọn nguồn của theo dấu hoặc quyền + label_update_issue_done_ratios: Cập nhật tỷ lệ hoàn thành vấn đề + setting_start_of_week: Định dạng lịch + permission_view_issues: Xem Vấn đề + label_display_used_statuses_only: Chỉ hiển thị trạng thái đã được dùng bởi theo dõi này + label_revision_id: "Bản điều chỉnh %{value}" + label_api_access_key: Khoá truy cập API + label_api_access_key_created_on: "Khoá truy cập API đựơc tạo cách đây %{value}. Khóa này được dùng cho eDesignLab Client." + label_feeds_access_key: Khoá truy cập RSS + notice_api_access_key_reseted: Khoá truy cập API của bạn đã được đặt lại. + setting_rest_api_enabled: Cho phép dịch vụ web REST + label_missing_api_access_key: Mất Khoá truy cập API + label_missing_feeds_access_key: Mất Khoá truy cập RSS + button_show: Hiện + text_line_separated: Nhiều giá trị được phép(mỗi dòng một giá trị). + setting_mail_handler_body_delimiters: "Cắt bớt email sau những dòng :" + permission_add_subprojects: Tạo Dự án con + label_subproject_new: Thêm dự án con + text_own_membership_delete_confirmation: |- + Bạn đang cố gỡ bỏ một số hoặc tất cả quyền của bạn với dự án này và có thể sẽ mất quyền thay đổi nó sau đó. + Bạn có muốn tiếp tục? + label_close_versions: Đóng phiên bản đã hoàn thành + label_board_sticky: Chú ý + label_board_locked: Đã khóa + permission_export_wiki_pages: Xuất trang wiki + setting_cache_formatted_text: Cache định dạng các ký tự + permission_manage_project_activities: Quản lý hoạt động của dự án + error_unable_delete_issue_status: Không thể xóa trạng thái vấn đề + label_profile: Hồ sơ + permission_manage_subtasks: Quản lý tác vụ con + field_parent_issue: Tác vụ cha + label_subtask_plural: Tác vụ con + label_project_copy_notifications: Gửi email thông báo trong khi dự án được sao chép + error_can_not_delete_custom_field: Không thể xóa trường tùy biến + error_unable_to_connect: "Không thể kết nối (%{value})" + error_can_not_remove_role: Quyền này đang được dùng và không thể xóa được. + error_can_not_delete_tracker: Theo dõi này chứa vấn đề và không thể xóa được. + field_principal: Chủ yếu + label_my_page_block: Block trang của tôi + notice_failed_to_save_members: "Thất bại khi lưu thành viên : %{errors}." + text_zoom_out: Thu nhỏ + text_zoom_in: Phóng to + notice_unable_delete_time_entry: Không thể xóa mục time log. + label_overall_spent_time: Tổng thời gian sử dụng + field_time_entries: Log time + project_module_gantt: Biểu đồ Gantt + project_module_calendar: Lịch + button_edit_associated_wikipage: "Chỉnh sửa trang Wiki liên quan: %{page_title}" + text_are_you_sure_with_children: Xóa vấn đề và tất cả vấn đề con? + field_text: Trường văn bản + label_user_mail_option_only_owner: Chỉ những thứ tôi sở hữu + setting_default_notification_option: Tuỳ chọn thông báo mặc định + label_user_mail_option_only_my_events: Chỉ những thứ tôi theo dõi hoặc liên quan + label_user_mail_option_only_assigned: Chỉ những thứ tôi được phân công + label_user_mail_option_none: Không có sự kiện + field_member_of_group: Nhóm thụ hưởng + field_assigned_to_role: Quyền thụ hưởng + notice_not_authorized_archived_project: Dự án bạn đang có truy cập đã được lưu trữ. + label_principal_search: "Tìm kiếm người dùng hoặc nhóm:" + label_user_search: "Tìm kiếm người dùng:" + field_visible: Nhìn thấy + setting_emails_header: Tiêu đề Email + setting_commit_logtime_activity_id: Cho phép ghi lại thời gian + text_time_logged_by_changeset: "Áp dụng trong changeset : %{value}." + setting_commit_logtime_enabled: Cho phép time logging + notice_gantt_chart_truncated: "Đồ thị đã được cắt bớt bởi vì nó đã vượt qua lượng thông tin tối đa có thể hiển thị :(%{max})" + setting_gantt_items_limit: Lượng thông tin tối đa trên đồ thị gantt + description_selected_columns: Các cột được lựa chọn + field_warn_on_leaving_unsaved: Cảnh báo tôi khi rời một trang có các nội dung chưa lưu + text_warn_on_leaving_unsaved: Trang hiện tại chứa nội dung chưa lưu và sẽ bị mất nếu bạn rời trang này. + label_my_queries: Các truy vấn tùy biến + text_journal_changed_no_detail: "%{label} cập nhật" + label_news_comment_added: Bình luận đã được thêm cho một tin tức + button_expand_all: Mở rộng tất cả + button_collapse_all: Thu gọn tất cả + label_additional_workflow_transitions_for_assignee: Chuyển đổi bổ sung cho phép khi người sử dụng là người nhận chuyển nhượng + label_additional_workflow_transitions_for_author: Các chuyển đổi bổ xung được phép khi người dùng là tác giả + label_bulk_edit_selected_time_entries: Sửa nhiều mục đã chọn + text_time_entries_destroy_confirmation: Bạn có chắc chắn muốn xóa bỏ các mục đã chọn? + label_role_anonymous: Ẩn danh + label_role_non_member: Không là thành viên + label_issue_note_added: Ghi chú được thêm + label_issue_status_updated: Trạng thái cập nhật + label_issue_priority_updated: Cập nhật ưu tiên + label_issues_visibility_own: Vấn đề tạo bởi hoặc gán cho người dùng + field_issues_visibility: Vấn đề được nhìn thấy + label_issues_visibility_all: Tất cả vấn đề + permission_set_own_issues_private: Đặt vấn đề sở hữu là riêng tư hoặc công cộng + field_is_private: Riêng tư + permission_set_issues_private: Gán vấn đề là riêng tư hoặc công cộng + label_issues_visibility_public: Tất cả vấn đề không riêng tư + text_issues_destroy_descendants_confirmation: "Hành động này sẽ xóa %{count} tác vụ con." + field_commit_logs_encoding: Mã hóa ghi chú Commit + field_scm_path_encoding: Mã hóa đường dẫn + text_scm_path_encoding_note: "Mặc định: UTF-8" + field_path_to_repository: Đường dẫn tới kho chứa + field_root_directory: Thư mục gốc + field_cvs_module: Module + field_cvsroot: CVSROOT + text_mercurial_repository_note: Kho chứa cục bộ (vd. /hgrepo, c:\hgrepo) + text_scm_command: Lệnh + text_scm_command_version: Phiên bản + label_git_report_last_commit: Báo cáo lần Commit cuối cùng cho file và thư mục + text_scm_config: Bạn có thể cấu hình lệnh Scm trong file config/configuration.yml. Vui lòng khởi động lại ứng dụng sau khi chỉnh sửa nó. + text_scm_command_not_available: Lệnh Scm không có sẵn. Vui lòng kiểm tra lại thiết đặt trong phần Quản trị. + notice_issue_successful_create: "Vấn đề %{id} đã được tạo." + label_between: Ở giữa + setting_issue_group_assignment: Cho phép gán vấn đề đến các nhóm + label_diff: Sự khác nhau + text_git_repository_note: Kho chứa cục bộ và công cộng (vd. /gitrepo, c:\gitrepo) + description_query_sort_criteria_direction: Chiều sắp xếp + description_project_scope: Phạm vi tìm kiếm + description_filter: Lọc + description_user_mail_notification: Thiết lập email thông báo + description_date_from: Nhập ngày bắt đầu + description_message_content: Nội dung thông điệp + description_available_columns: Các cột có sẵn + description_date_range_interval: Chọn khoảng thời gian giữa ngày bắt đầu và kết thúc + description_issue_category_reassign: Chọn danh mục vấn đề + description_search: Trường tìm kiếm + description_notes: Các chú ý + description_date_range_list: Chọn khoảng từ danh sách + description_choose_project: Các dự án + description_date_to: Nhập ngày kết thúc + description_query_sort_criteria_attribute: Sắp xếp thuộc tính + description_wiki_subpages_reassign: Chọn một trang cấp trên + label_parent_revision: Cha + label_child_revision: Con + error_scm_annotate_big_text_file: Các mục không được chú thích, vì nó vượt quá kích thước tập tin văn bản tối đa. + setting_default_issue_start_date_to_creation_date: Sử dụng thời gian hiện tại khi tạo vấn đề mới + button_edit_section: Soạn thảo sự lựa chọn này + setting_repositories_encodings: Mã hóa kho chứa + description_all_columns: Các cột + button_export: Export + label_export_options: "%{export_format} tùy chọn Export" + error_attachment_too_big: "File này không thể tải lên vì nó vượt quá kích thước cho phép : (%{max_size})" + notice_failed_to_save_time_entries: "Lỗi khi lưu %{count} lần trên %{total} sự lựa chọn : %{ids}." + label_x_issues: + zero: 0 vấn đề + one: 1 vấn đề + other: "%{count} vấn đề" + label_repository_new: Kho lưu trữ mới + field_repository_is_default: Kho lưu trữ chính + label_copy_attachments: Copy các file đính kèm + label_item_position: "%{position}/%{count}" + label_completed_versions: Các phiên bản hoàn thành + text_project_identifier_info: Chỉ cho phép chữ cái thường (a-z), con số và dấu gạch ngang.
    Sau khi lưu, chỉ số ID không thể thay đổi. + field_multiple: Nhiều giá trị + setting_commit_cross_project_ref: Sử dụng thời gian hiện tại khi tạo vấn đề mới + text_issue_conflict_resolution_add_notes: Thêm ghi chú của tôi và loại bỏ các thay đổi khác + text_issue_conflict_resolution_overwrite: Áp dụng thay đổi bằng bất cứ giá nào, ghi chú trước đó có thể bị ghi đè + notice_issue_update_conflict: Vấn đề này đã được cập nhật bởi một người dùng khác trong khi bạn đang chỉnh sửa nó. + text_issue_conflict_resolution_cancel: "Loại bỏ tất cả các thay đổi và hiển thị lại %{link}" + permission_manage_related_issues: Quản lý các vấn đề liên quan + field_auth_source_ldap_filter: Bộ lọc LDAP + label_search_for_watchers: Tìm kiếm người theo dõi để thêm + notice_account_deleted: Tài khoản của bạn đã được xóa vĩnh viễn. + button_delete_my_account: Xóa tài khoản của tôi + setting_unsubscribe: Cho phép người dùng xóa Account + text_account_destroy_confirmation: |- + Bạn đồng ý không ? + Tài khoản của bạn sẽ bị xóa vĩnh viễn, không thể khôi phục lại! + error_session_expired: Phiên làm việc của bạn bị quá hạn, hãy đăng nhập lại + text_session_expiration_settings: "Chú ý : Thay đổi các thiết lập này có thể gây vô hiệu hóa Session hiện tại" + setting_session_lifetime: Thời gian tồn tại lớn nhất của Session + setting_session_timeout: Thời gian vô hiệu hóa Session + label_session_expiration: Phiên làm việc bị quá hạn + permission_close_project: Đóng / Mở lại dự án + label_show_closed_projects: Xem các dự án đã đóng + button_close: Đóng + button_reopen: Mở lại + project_status_active: Kích hoạt + project_status_closed: Đã đóng + project_status_archived: Lưu trữ + text_project_closed: Dự án này đã đóng và chỉ đọc + notice_user_successful_create: "Người dùng %{id} đã được tạo." + field_core_fields: Các trường tiêu chuẩn + field_timeout: Quá hạn + setting_thumbnails_enabled: Hiển thị các thumbnail đính kèm + setting_thumbnails_size: Kích thước Thumbnails(pixel) + setting_session_lifetime: Thời gian tồn tại lớn nhất của Session + setting_session_timeout: Thời gian vô hiệu hóa Session + label_status_transitions: Trạng thái chuyển tiếp + label_fields_permissions: Cho phép các trường + label_readonly: Chỉ đọc + label_required: Yêu cầu + text_repository_identifier_info: Chỉ có các chữ thường (a-z), các số (0-9), dấu gạch ngang và gạch dưới là hợp lệ.
    Khi đã lưu, tên định danh sẽ không thể thay đổi. + field_board_parent: Diễn đàn cha + label_attribute_of_project: "Của dự án : %{name}" + label_attribute_of_author: "Của tác giả : %{name}" + label_attribute_of_assigned_to: "Được phân công bởi %{name}" + label_attribute_of_fixed_version: "Phiên bản mục tiêu của %{name}" + label_copy_subtasks: Sao chép các nhiệm vụ con + label_copied_to: Sao chép đến + label_copied_from: Sao chép từ + label_any_issues_in_project: Bất kỳ vấn đề nào trong dự án + label_any_issues_not_in_project: Bất kỳ vấn đề nào không thuộc dự án + field_private_notes: Ghi chú riêng tư + permission_view_private_notes: Xem ghi chú riêng tư + permission_set_notes_private: Đặt ghi chú thành riêng tư + label_no_issues_in_project: Không có vấn đề nào trong dự án + label_any: tất cả + label_last_n_weeks: "%{count} tuần qua" + setting_cross_project_subtasks: Cho phép các nhiệm vụ con liên dự án + label_cross_project_descendants: Trong các dự án con + label_cross_project_tree: Trong cùng cây dự án + label_cross_project_hierarchy: Trong dự án cùng cấp bậc + label_cross_project_system: Trong tất cả các dự án + button_hide: Ẩn + setting_non_working_week_days: Các ngày không làm việc + label_in_the_next_days: Trong tương lai + label_in_the_past_days: Trong quá khứ + label_attribute_of_user: "Của người dùng %{name}" + text_turning_multiple_off: Nếu bạn vô hiệu hóa nhiều giá trị, chúng sẽ bị loại bỏ để duy trì chỉ có một giá trị cho mỗi mục. + label_attribute_of_issue: "Vấn đề của %{name}" + permission_add_documents: Thêm tài liệu + permission_edit_documents: Soạn thảo tài liệu + permission_delete_documents: Xóa tài liệu + label_gantt_progress_line: Tiến độ + setting_jsonp_enabled: Cho phép trợ giúp JSONP + field_inherit_members: Các thành viên kế thừa + field_closed_on: Đã đóng + setting_default_projects_tracker_ids: Default trackers for new projects + label_total_time: Tổng cộng diff --git a/config/locales/zh-TW.yml b/config/locales/zh-TW.yml new file mode 100644 index 00000000..196b0ce9 --- /dev/null +++ b/config/locales/zh-TW.yml @@ -0,0 +1,1171 @@ +# Chinese (Taiwan) translations for Ruby on Rails +# by tsechingho (http://github.com/tsechingho) +# See http://github.com/svenfuchs/rails-i18n/ for details. + +"zh-TW": + direction: ltr + jquery: + locale: "zh-TW" + date: + formats: + # Use the strftime parameters for formats. + # When no format has been given, it uses default. + # You can provide other formats here if you like! + default: "%Y-%m-%d" + short: "%b%d日" + long: "%Y年%b%d日" + + day_names: [星期日, 星期一, 星期二, 星期三, 星期四, 星期五, 星期六] + abbr_day_names: [日, 一, 二, 三, 四, 五, 六] + + # Don't forget the nil at the beginning; there's no such thing as a 0th month + month_names: [~, 一月, 二月, 三月, 四月, 五月, 六月, 七月, 八月, 九月, 十月, 十一月, 十二月] + abbr_month_names: [~, 1月, 2月, 3月, 4月, 5月, 6月, 7月, 8月, 9月, 10月, 11月, 12月] + # 使用於 date_select 與 datime_select. + order: + - :year + - :month + - :day + + time: + formats: + default: "%Y年%b%d日 %A %H:%M:%S %Z" + time: "%H:%M" + short: "%b%d日 %H:%M" + long: "%Y年%b%d日 %H:%M" + am: "AM" + pm: "PM" + +# 使用於 array.to_sentence. + support: + array: + words_connector: ", " + two_words_connector: " 和 " + last_word_connector: ", 和 " + sentence_connector: "且" + skip_last_comma: false + + number: + # 使用於 number_with_delimiter() + # 同時也是 'currency', 'percentage', 'precision', 與 'human' 的預設值 + format: + # 設定小數點分隔字元,以使用更高的準確度 (例如: 1.0 / 2.0 == 0.5) + separator: "." + # 千分位符號 (例如:一百萬是 1,000,000) (均以三個位數來分組) + delimiter: "," + # 小數點分隔字元後之精確位數 (數字 1 搭配 2 位精確位數為: 1.00) + precision: 3 + + # 使用於 number_to_currency() + currency: + format: + # 貨幣符號的位置? %u 是貨幣符號, %n 是數值 (預設值: $5.00) + format: "%u%n" + unit: "NT$" + # 下列三個選項設定, 若有設定值將會取代 number.format 成為預設值 + separator: "." + delimiter: "," + precision: 2 + + # 使用於 number_to_percentage() + percentage: + format: + # 下列三個選項設定, 若有設定值將會取代 number.format 成為預設值 + # separator: + delimiter: "" + # precision: + + # 使用於 number_to_precision() + precision: + format: + # 下列三個選項設定, 若有設定值將會取代 number.format 成為預設值 + # separator: + delimiter: "" + # precision: + + # 使用於 number_to_human_size() + human: + format: + # 下列三個選項設定, 若有設定值將會取代 number.format 成為預設值 + # separator: + delimiter: "" + precision: 3 + # 儲存單位輸出格式. + # %u 是儲存單位, %n 是數值 (預設值: 2 MB) + storage_units: + format: "%n %u" + units: + byte: + one: "位元組 (B)" + other: "位元組 (B)" + kb: "KB" + mb: "MB" + gb: "GB" + tb: "TB" + + # 使用於 distance_of_time_in_words(), distance_of_time_in_words_to_now(), time_ago_in_words() + datetime: + distance_in_words: + half_a_minute: "半分鐘" + less_than_x_seconds: + one: "小於 1 秒" + other: "小於 %{count} 秒" + x_seconds: + one: "1 秒" + other: "%{count} 秒" + less_than_x_minutes: + one: "小於 1 分鐘" + other: "小於 %{count} 分鐘" + x_minutes: + one: "1 分鐘" + other: "%{count} 分鐘" + about_x_hours: + one: "約 1 小時" + other: "約 %{count} 小時" + x_hours: + one: "1 hour" + other: "%{count} hours" + x_days: + one: "1 天" + other: "%{count} 天" + about_x_months: + one: "約 1 個月" + other: "約 %{count} 個月" + x_months: + one: "1 個月" + other: "%{count} 個月" + about_x_years: + one: "約 1 年" + other: "約 %{count} 年" + over_x_years: + one: "超過 1 年" + other: "超過 %{count} 年" + almost_x_years: + one: "將近 1 年" + other: "將近 %{count} 年" + prompts: + year: "年" + month: "月" + day: "日" + hour: "時" + minute: "分" + second: "秒" + + activerecord: + errors: + template: + header: + one: "有 1 個錯誤發生使得「%{model}」無法被儲存。" + other: "有 %{count} 個錯誤發生使得「%{model}」無法被儲存。" + # The variable :count is also available + body: "下面所列欄位有問題:" + # The values :model, :attribute and :value are always available for interpolation + # The value :count is available when applicable. Can be used for pluralization. + messages: + inclusion: "沒有包含在列表中" + exclusion: "是被保留的" + invalid: "是無效的" + confirmation: "不符合確認值" + accepted: "必须是可被接受的" + empty: "不能留空" + blank: "不能是空白字元" + too_long: "過長(最長是 %{count} 個字)" + too_short: "過短(最短是 %{count} 個字)" + wrong_length: "字數錯誤(必須是 %{count} 個字)" + taken: "已經被使用" + not_a_number: "不是數字" + greater_than: "必須大於 %{count}" + greater_than_or_equal_to: "必須大於或等於 %{count}" + equal_to: "必須等於 %{count}" + less_than: "必須小於 %{count}" + less_than_or_equal_to: "必須小於或等於 %{count}" + odd: "必須是奇數" + even: "必須是偶數" + # Append your own errors here or at the model/attributes scope. + greater_than_start_date: "必須在開始日期之後" + not_same_project: "不屬於同一個專案" + circular_dependency: "這個關聯會導致環狀相依" + cant_link_an_issue_with_a_descendant: "問題無法被連結至自己的子任務" + + # You can define own errors for models or model attributes. + # The values :model, :attribute and :value are always available for interpolation. + # + # For example, + # models: + # user: + # blank: "This is a custom blank message for %{model}: %{attribute}" + # attributes: + # login: + # blank: "This is a custom blank message for User login" + # Will define custom blank validation message for User model and + # custom blank validation message for login attribute of User model. + #models: + + # Translate model names. Used in Model.human_name(). + #models: + # For example, + # user: "Dude" + # will translate User model name to "Dude" + + # Translate model attribute names. Used in Model.human_attribute_name(attribute). + #attributes: + # For example, + # user: + # login: "Handle" + # will translate User attribute "login" as "Handle" + + actionview_instancetag_blank_option: 請選擇 + + general_text_No: '否' + general_text_Yes: '是' + general_text_no: '否' + general_text_yes: '是' + general_lang_name: 'Traditional Chinese (繁體中文)' + general_csv_separator: ',' + general_csv_decimal_separator: '.' + general_csv_encoding: Big5 + general_pdf_encoding: Big5 + general_first_day_of_week: '7' + + notice_account_updated: 帳戶更新資訊已儲存 + notice_account_invalid_creditentials: 帳戶或密碼不正確 + notice_account_password_updated: 帳戶新密碼已儲存 + notice_account_wrong_password: 密碼不正確 + notice_account_register_done: 帳號已建立成功。欲啟用您的帳號,請點擊系統確認信函中的啟用連結。 + notice_account_unknown_email: 未知的使用者 + notice_can_t_change_password: 這個帳號使用外部認證方式,無法變更其密碼。 + notice_account_lost_email_sent: 包含選擇新密碼指示的電子郵件,已經寄出給您。 + notice_account_activated: 您的帳號已經啟用,可用它登入系統。 + notice_successful_create: 建立成功 + notice_successful_update: 更新成功 + notice_successful_delete: 刪除成功 + notice_successful_connection: 連線成功 + notice_file_not_found: 您想要存取的頁面已經不存在或被搬移至其他位置。 + notice_locking_conflict: 資料已被其他使用者更新。 + notice_not_authorized: 你未被授權存取此頁面。 + notice_not_authorized_archived_project: 您欲存取的專案已經被封存。 + notice_email_sent: "郵件已經成功寄送至以下收件者: %{value}" + notice_email_error: "寄送郵件的過程中發生錯誤 (%{value})" + notice_feeds_access_key_reseted: 您的 RSS 存取金鑰已被重新設定。 + notice_api_access_key_reseted: 您的 API 存取金鑰已被重新設定。 + notice_failed_to_save_issues: "無法儲存 %{count} 問題到下列所選取的 %{total} 個項目中: %{ids}。" + notice_failed_to_save_time_entries: "無法儲存 %{count} 個工時到下列所選取的 %{total} 個項目中: %{ids}。" + notice_failed_to_save_members: "成員儲存失敗: %{errors}." + notice_no_issue_selected: "未選擇任何問題!請勾選您想要編輯的問題。" + notice_account_pending: "您的帳號已經建立,正在等待管理員的審核。" + notice_default_data_loaded: 預設組態已載入成功。 + notice_unable_delete_version: 無法刪除版本。 + notice_unable_delete_time_entry: 無法刪除工時記錄項目。 + notice_issue_done_ratios_updated: 問題完成百分比已更新。 + notice_gantt_chart_truncated: "由於項目數量超過可顯示數量的最大值 (%{max}),故此甘特圖尾部已被截斷" + notice_issue_successful_create: "問題 %{id} 已建立。" + notice_issue_update_conflict: "當您正在編輯這個問題的時候,它已經被其他人搶先一步更新過。" + notice_account_deleted: "您的帳戶已被永久刪除。" + notice_user_successful_create: "已建立用戶 %{id}。" + + error_can_t_load_default_data: "無法載入預設組態: %{value}" + error_scm_not_found: "在儲存機制中找不到這個項目或修訂版。" + error_scm_command_failed: "嘗試存取儲存機制時發生錯誤: %{value}" + error_scm_annotate: "項目不存在或項目無法被加上附註。" + error_scm_annotate_big_text_file: 此項目無法被標註,因為它已經超過最大的文字檔大小。 + error_issue_not_found_in_project: '該問題不存在或不屬於此專案' + error_no_tracker_in_project: '此專案尚未指定追蹤標籤。請檢查專案的設定資訊。' + error_no_default_issue_status: '尚未定義問題狀態的預設值。請您前往「網站管理」->「問題狀態清單」頁面,檢查相關組態設定。' + error_can_not_delete_custom_field: 無法刪除自訂欄位 + error_can_not_delete_tracker: "此追蹤標籤已包含問題,無法被刪除。" + error_can_not_remove_role: "此角色已被使用,無法將其刪除。" + error_can_not_reopen_issue_on_closed_version: '指派給「已結束」版本的問題,無法再將其狀態變更為「進行中」' + error_can_not_archive_project: 此專案無法被封存 + error_issue_done_ratios_not_updated: "問題完成百分比未更新。" + error_workflow_copy_source: '請選擇一個來源問題追蹤標籤或角色' + error_workflow_copy_target: '請選擇一個(或多個)目的問題追蹤標籤或角色' + error_unable_delete_issue_status: '無法刪除問題狀態' + error_unable_to_connect: "無法連線至(%{value})" + error_attachment_too_big: "這個檔案無法被上傳,因為它已經超過最大的檔案大小 (%{max_size})" + error_session_expired: "您的工作階段已經過期。請重新登入。" + warning_attachments_not_saved: "%{count} 個附加檔案無法被儲存。" + + mail_subject_lost_password: 您的 Redmine 網站密碼 + mail_body_lost_password: '欲變更您的 Redmine 網站密碼, 請點選以下鏈結:' + mail_subject_register: 啟用您的 Redmine 帳號 + mail_body_register: '欲啟用您的 Redmine 帳號, 請點選以下鏈結:' + mail_body_account_information_external: "您可以使用 %{value} 帳號登入 Redmine 網站。" + mail_body_account_information: 您的 Redmine 帳號資訊 + mail_subject_account_activation_request: Redmine 帳號啟用需求通知 + mail_body_account_activation_request: "有位新用戶 (%{value}) 已經完成註冊,正等候您的審核:" + mail_subject_reminder: "您有 %{count} 個問題即將到期 (%{days})" + mail_body_reminder: "%{count} 個指派給您的問題,將於 %{days} 天之內到期:" + mail_subject_wiki_content_added: "'%{id}' wiki 頁面已被新增" + mail_body_wiki_content_added: "此 '%{id}' wiki 頁面已被 %{author} 新增。" + mail_subject_wiki_content_updated: "'%{id}' wiki 頁面已被更新" + mail_body_wiki_content_updated: "此 '%{id}' wiki 頁面已被 %{author} 更新。" + + + field_name: 名稱 + field_description: 概述 + field_summary: 摘要 + field_is_required: 必填 + field_firstname: 名字 + field_lastname: 姓氏 + field_mail: 電子郵件 + field_filename: 檔案名稱 + field_filesize: 大小 + field_downloads: 下載次數 + field_author: 作者 + field_created_on: 建立日期 + field_updated_on: 更新日期 + field_closed_on: 結束日期 + field_field_format: 格式 + field_is_for_all: 給全部的專案 + field_possible_values: 可能值 + field_regexp: 正規表示式 + field_min_length: 最小長度 + field_max_length: 最大長度 + field_value: 值 + field_category: 分類 + field_title: 標題 + field_project: 專案 + field_issue: 問題 + field_status: 狀態 + field_notes: 筆記 + field_is_closed: 問題已結束 + field_is_default: 預設值 + field_tracker: 追蹤標籤 + field_subject: 主旨 + field_due_date: 完成日期 + field_assigned_to: 分派給 + field_priority: 優先權 + field_fixed_version: 版本 + field_user: 用戶 + field_principal: 原則 + field_role: 角色 + field_homepage: 網站首頁 + field_is_public: 公開 + field_parent: 父專案 + field_is_in_roadmap: 問題顯示於版本藍圖中 + field_login: 帳戶名稱 + field_mail_notification: 電子郵件提醒選項 + field_admin: 管理者 + field_last_login_on: 最近連線日期 + field_language: 語系 + field_effective_date: 日期 + field_password: 目前密碼 + field_new_password: 新密碼 + field_password_confirmation: 確認新密碼 + field_version: 版本 + field_type: Type + field_host: Host + field_port: 連接埠 + field_account: 帳戶 + field_base_dn: Base DN + field_attr_login: 登入屬性 + field_attr_firstname: 名字屬性 + field_attr_lastname: 姓氏屬性 + field_attr_mail: 電子郵件信箱屬性 + field_onthefly: 即時建立使用者 + field_start_date: 開始日期 + field_done_ratio: 完成百分比 + field_auth_source: 認證模式 + field_hide_mail: 隱藏我的電子郵件 + field_comments: 回應 + field_url: 網址 + field_start_page: 首頁 + field_subproject: 子專案 + field_hours: 小時 + field_activity: 活動 + field_spent_on: 日期 + field_identifier: 代碼 + field_is_filter: 用來作為過濾器 + field_issue_to: 相關問題 + field_delay: 逾期 + field_assignable: 問題可被分派至此角色 + field_redirect_existing_links: 重新導向現有連結 + field_estimated_hours: 預估工時 + field_column_names: 欄位 + field_time_entries: 耗用工時 + field_time_zone: 時區 + field_searchable: 可用做搜尋條件 + field_default_value: 預設值 + field_comments_sorting: 回應排序 + field_parent_title: 父頁面 + field_editable: 可編輯 + field_watcher: 觀察者 + field_identity_url: OpenID 網址 + field_content: 內容 + field_group_by: 結果分組方式 + field_sharing: 共用 + field_parent_issue: 父問題 + field_member_of_group: "被指派者的群組" + field_assigned_to_role: "被指派者的角色" + field_text: 內容文字 + field_visible: 可被看見 + field_warn_on_leaving_unsaved: "提醒我將要離開的頁面中尚有未儲存的資料" + field_issues_visibility: 問題可見度 + field_is_private: 私人 + field_commit_logs_encoding: 認可訊息編碼 + field_scm_path_encoding: 路徑編碼 + field_path_to_repository: 儲存機制路徑 + field_root_directory: 根資料夾 + field_cvsroot: CVSROOT + field_cvs_module: 模組 + field_repository_is_default: 主要儲存機制 + field_multiple: 多重值 + field_auth_source_ldap_filter: LDAP 篩選器 + field_core_fields: 標準欄位 + field_timeout: "逾時 (單位: 秒)" + field_board_parent: 父論壇 + field_private_notes: 私人筆記 + field_inherit_members: 繼承父專案成員 + + setting_app_title: 標題 + setting_app_subtitle: 副標題 + setting_welcome_text: 歡迎詞 + setting_default_language: 預設語系 + setting_login_required: 需要驗證 + setting_self_registration: 註冊選項 + setting_attachment_max_size: 附件大小限制 + setting_issues_export_limit: 問題匯出限制 + setting_mail_from: 寄件者電子郵件 + setting_bcc_recipients: 使用密件副本 (BCC) + setting_plain_text_mail: 純文字郵件 (不含 HTML) + setting_host_name: 主機名稱 + setting_text_formatting: 文字格式 + setting_wiki_compression: 壓縮 Wiki 歷史文章 + setting_feeds_limit: RSS 新聞限制 + setting_autofetch_changesets: 自動擷取認可 + setting_default_projects_public: 新建立之專案預設為「公開」 + setting_sys_api_enabled: 啟用管理儲存機制的網頁服務 (Web Service) + setting_commit_ref_keywords: 認可用於參照之關鍵字 + setting_commit_fix_keywords: 認可用於修正之關鍵字 + setting_autologin: 自動登入 + setting_date_format: 日期格式 + setting_time_format: 時間格式 + setting_cross_project_issue_relations: 允許關聯至其它專案的問題 + setting_cross_project_subtasks: 允許跨專案的子任務 + setting_issue_list_default_columns: 預設顯示於問題清單的欄位 + setting_repositories_encodings: 附加檔案與儲存機制的編碼 + setting_emails_header: 電子郵件前頭說明 + setting_emails_footer: 電子郵件附帶說明 + setting_protocol: 協定 + setting_per_page_options: 每頁顯示個數選項 + setting_user_format: 使用者顯示格式 + setting_activity_days_default: 專案活動顯示天數 + setting_display_subprojects_issues: 預設於父專案中顯示子專案的問題 + setting_enabled_scm: 啟用的 SCM + setting_mail_handler_body_delimiters: "截去郵件中包含下列值之後的內容" + setting_mail_handler_api_enabled: 啟用處理傳入電子郵件的服務 + setting_mail_handler_api_key: API 金鑰 + setting_sequential_project_identifiers: 循序產生專案識別碼 + setting_gravatar_enabled: 啟用 Gravatar 全球認證大頭像 + setting_gravatar_default: 預設全球認證大頭像圖片 + setting_diff_max_lines_displayed: 差異顯示行數之最大值 + setting_file_max_size_displayed: 檔案內容顯示大小之最大值 + setting_repository_log_display_limit: 修訂版顯示數目之最大值 + setting_openid: 允許使用 OpenID 登入與註冊 + setting_password_min_length: 密碼最小長度 + setting_new_project_user_role_id: 管理者以外之用戶建立新專案時,將被指派的角色 + setting_default_projects_modules: 新專案預設啟用的模組 + setting_issue_done_ratio: 計算問題完成百分比之方式 + setting_issue_done_ratio_issue_field: 依據問題完成百分比欄位 + setting_issue_done_ratio_issue_status: 依據問題狀態 + setting_start_of_week: 週的第一天 + setting_rest_api_enabled: 啟用 REST 網路服務技術(Web Service) + setting_cache_formatted_text: 快取已格式化文字 + setting_default_notification_option: 預設通知選項 + setting_commit_logtime_enabled: 啟用認可中的時間記錄 + setting_commit_logtime_activity_id: 時間記錄對應的活動 + setting_gantt_items_limit: 甘特圖中項目顯示數量的最大值 + setting_issue_group_assignment: 允許問題被指派至群組 + setting_default_issue_start_date_to_creation_date: 設定新問題的起始日期為今天的日期 + setting_commit_cross_project_ref: 允許關聯並修正其他專案的問題 + setting_unsubscribe: 允許用戶取消註冊(刪除帳戶) + setting_session_lifetime: 工作階段存留時間最大值 + setting_session_timeout: 工作階段無活動逾時時間 + setting_thumbnails_enabled: 顯示附加檔案的縮圖 + setting_thumbnails_size: "縮圖大小 (單位: 像素 pixels)" + setting_non_working_week_days: 非工作日 + setting_jsonp_enabled: 啟用 JSONP 支援 + setting_default_projects_tracker_ids: 新專案預設使用的追蹤標籤 + + permission_add_project: 建立專案 + permission_add_subprojects: 建立子專案 + permission_edit_project: 編輯專案 + permission_close_project: 關閉 / 重新開啟專案 + permission_select_project_modules: 選擇專案模組 + permission_manage_members: 管理成員 + permission_manage_project_activities: 管理專案活動 + permission_manage_versions: 管理版本 + permission_manage_categories: 管理問題分類 + permission_view_issues: 檢視問題 + permission_add_issues: 新增問題 + permission_edit_issues: 編輯問題 + permission_manage_issue_relations: 管理問題關聯 + permission_set_issues_private: 設定問題為公開或私人 + permission_set_own_issues_private: 設定自己的問題為公開或私人 + permission_add_issue_notes: 新增筆記 + permission_edit_issue_notes: 編輯筆記 + permission_edit_own_issue_notes: 編輯自己的筆記 + permission_view_private_notes: 檢視私人筆記 + permission_set_notes_private: 設定筆記為私人筆記 + permission_move_issues: 搬移問題 + permission_delete_issues: 刪除問題 + permission_manage_public_queries: 管理公開查詢 + permission_save_queries: 儲存查詢 + permission_view_gantt: 檢視甘特圖 + permission_view_calendar: 檢視日曆 + permission_view_issue_watchers: 檢視監看者清單 + permission_add_issue_watchers: 新增監看者 + permission_delete_issue_watchers: 刪除監看者 + permission_log_time: 紀錄耗用工時 + permission_view_time_entries: 檢視耗用工時 + permission_edit_time_entries: 編輯工時紀錄 + permission_edit_own_time_entries: 編輯自己的工時記錄 + permission_manage_news: 管理新聞 + permission_comment_news: 回應新聞 + permission_view_documents: 檢視文件 + permission_add_documents: 新增文件 + permission_edit_documents: 編輯文件 + permission_delete_documents: 刪除文件 + permission_manage_files: 管理檔案 + permission_view_files: 檢視檔案 + permission_manage_wiki: 管理 wiki + permission_rename_wiki_pages: 重新命名 wiki 頁面 + permission_delete_wiki_pages: 刪除 wiki 頁面 + permission_view_wiki_pages: 檢視 wiki + permission_view_wiki_edits: 檢視 wiki 歷史 + permission_edit_wiki_pages: 編輯 wiki 頁面 + permission_delete_wiki_pages_attachments: 刪除附件 + permission_protect_wiki_pages: 專案 wiki 頁面 + permission_manage_repository: 管理儲存機制 + permission_browse_repository: 瀏覽儲存機制 + permission_view_changesets: 檢視變更集 + permission_commit_access: 存取認可 + permission_manage_boards: 管理討論版 + permission_view_messages: 檢視訊息 + permission_add_messages: 新增訊息 + permission_edit_messages: 編輯訊息 + permission_edit_own_messages: 編輯自己的訊息 + permission_delete_messages: 刪除訊息 + permission_delete_own_messages: 刪除自己的訊息 + permission_export_wiki_pages: 匯出 wiki 頁面 + permission_manage_subtasks: 管理子任務 + permission_manage_related_issues: 管理相關問題 + + project_module_issue_tracking: 問題追蹤 + project_module_time_tracking: 工時追蹤 + project_module_news: 新聞 + project_module_documents: 文件 + project_module_files: 檔案 + project_module_wiki: Wiki + project_module_repository: 版本控管 + project_module_boards: 討論區 + project_module_calendar: 日曆 + project_module_gantt: 甘特圖 + + label_user: 用戶 + label_user_plural: 用戶清單 + label_user_new: 建立新用戶 + label_user_anonymous: 匿名用戶 + label_project: 專案 + label_project_new: 建立新專案 + label_project_plural: 專案清單 + label_x_projects: + zero: 無專案 + one: 1 個專案 + other: "%{count} 個專案" + label_project_all: 全部的專案 + label_project_latest: 最近的專案 + label_issue: 問題 + label_issue_new: 建立新問題 + label_issue_plural: 問題清單 + label_issue_view_all: 檢視所有問題 + label_issues_by: "問題按 %{value} 分組顯示" + label_issue_added: 問題已新增 + label_issue_updated: 問題已更新 + label_issue_note_added: 筆記已新增 + label_issue_status_updated: 狀態已更新 + label_issue_priority_updated: 優先權已更新 + label_document: 文件 + label_document_new: 建立新文件 + label_document_plural: 文件 + label_document_added: 文件已新增 + label_role: 角色 + label_role_plural: 角色 + label_role_new: 建立新角色 + label_role_and_permissions: 角色與權限 + label_role_anonymous: 匿名者 + label_role_non_member: 非會員 + label_member: 成員 + label_member_new: 建立新成員 + label_member_plural: 成員 + label_tracker: 追蹤標籤 + label_tracker_plural: 追蹤標籤清單 + label_tracker_new: 建立新的追蹤標籤 + label_workflow: 流程 + label_issue_status: 問題狀態 + label_issue_status_plural: 問題狀態清單 + label_issue_status_new: 建立新狀態 + label_issue_category: 問題分類 + label_issue_category_plural: 問題分類清單 + label_issue_category_new: 建立新分類 + label_custom_field: 自訂欄位 + label_custom_field_plural: 自訂欄位清單 + label_custom_field_new: 建立新自訂欄位 + label_enumerations: 列舉值清單 + label_enumeration_new: 建立新列舉值 + label_information: 資訊 + label_information_plural: 資訊 + label_please_login: 請先登入 + label_register: 註冊 + label_login_with_open_id_option: 或使用 OpenID 登入 + label_password_lost: 遺失密碼 + label_home: 網站首頁 + label_my_page: 帳戶首頁 + label_my_account: 我的帳戶 + label_my_projects: 我的專案 + label_my_page_block: 帳戶首頁區塊 + label_administration: 網站管理 + label_login: 登入 + label_logout: 登出 + label_help: 說明 + label_reported_issues: 我通報的問題 + label_assigned_to_me_issues: 分派給我的問題 + label_last_login: 最近一次連線 + label_registered_on: 註冊於 + label_activity: 活動 + label_overall_activity: 整體活動 + label_user_activity: "%{value} 的活動" + label_new: 建立新的... + label_logged_as: 目前登入 + label_environment: 環境 + label_authentication: 認證 + label_auth_source: 認證模式 + label_auth_source_new: 建立新認證模式 + label_auth_source_plural: 認證模式清單 + label_subproject_plural: 子專案 + label_subproject_new: 建立子專案 + label_and_its_subprojects: "%{value} 與其子專案" + label_min_max_length: 最小 - 最大 長度 + label_list: 清單 + label_date: 日期 + label_integer: 整數 + label_float: 浮點數 + label_boolean: 布林 + label_string: 文字 + label_text: 長文字 + label_attribute: 屬性 + label_attribute_plural: 屬性 + label_no_data: 沒有任何資料可供顯示 + label_change_status: 變更狀態 + label_history: 歷史 + label_attachment: 檔案 + label_attachment_new: 建立新檔案 + label_attachment_delete: 刪除檔案 + label_attachment_plural: 檔案 + label_file_added: 檔案已新增 + label_report: 報告 + label_report_plural: 報告 + label_news: 新聞 + label_news_new: 建立新聞 + label_news_plural: 新聞 + label_news_latest: 最近新聞 + label_news_view_all: 檢視全部的新聞 + label_news_added: 新聞已新增 + label_news_comment_added: 回應已加入新聞 + label_settings: 設定 + label_overview: 概觀 + label_version: 版本 + label_version_new: 建立新版本 + label_version_plural: 版本 + label_close_versions: 結束已完成的版本 + label_confirmation: 確認 + label_export_to: 匯出至 + label_read: 讀取... + label_public_projects: 公開專案 + label_open_issues: 進行中 + label_open_issues_plural: 進行中 + label_closed_issues: 已結束 + label_closed_issues_plural: 已結束 + label_x_open_issues_abbr_on_total: + zero: 0 進行中 / 共 %{total} + one: 1 進行中 / 共 %{total} + other: "%{count} 進行中 / 共 %{total}" + label_x_open_issues_abbr: + zero: 0 進行中 + one: 1 進行中 + other: "%{count} 進行中" + label_x_closed_issues_abbr: + zero: 0 已結束 + one: 1 已結束 + other: "%{count} 已結束" + label_x_issues: + zero: 0 個問題 + one: 1 個問題 + other: "%{count} 個問題" + label_total: 總計 + label_permissions: 權限 + label_current_status: 目前狀態 + label_new_statuses_allowed: 可變更至以下狀態 + label_all: 全部 + label_any: 任意一個 + label_none: 空值 + label_nobody: 無名 + label_next: 下一頁 + label_previous: 上一頁 + label_used_by: Used by + label_details: 明細 + label_add_note: 加入一個新筆記 + label_per_page: 每頁 + label_calendar: 日曆 + label_months_from: 個月, 開始月份 + label_gantt: 甘特圖 + label_internal: 內部 + label_last_changes: "最近 %{count} 個變更" + label_change_view_all: 檢視全部的變更 + label_personalize_page: 自訂版面 + label_comment: 回應 + label_comment_plural: 回應 + label_x_comments: + zero: 無回應 + one: 1 個回應 + other: "%{count} 個回應" + label_comment_add: 加入新回應 + label_comment_added: 新回應已加入 + label_comment_delete: 刪除回應 + label_query: 自訂查詢 + label_query_plural: 自訂查詢 + label_query_new: 建立新查詢 + label_my_queries: 我的自訂查詢 + label_filter_add: 加入新篩選條件 + label_filter_plural: 篩選條件 + label_equals: 等於 + label_not_equals: 不等於 + label_in_less_than: 在小於 + label_in_more_than: 在大於 + label_in_the_next_days: 在未來幾天之內 + label_in_the_past_days: 在過去幾天之內 + label_greater_or_equal: "大於等於 (>=)" + label_less_or_equal: "小於等於 (<=)" + label_between: 區間 + label_in: 在 + label_today: 今天 + label_all_time: 全部 + label_yesterday: 昨天 + label_this_week: 本週 + label_last_week: 上週 + label_last_n_weeks: "過去 %{count} 週" + label_last_n_days: "過去 %{count} 天" + label_this_month: 這個月 + label_last_month: 上個月 + label_this_year: 今年 + label_date_range: 日期區間 + label_less_than_ago: 小於幾天之前 + label_more_than_ago: 大於幾天之前 + label_ago: 天以前 + label_contains: 包含 + label_not_contains: 不包含 + label_any_issues_in_project: 在專案中的任意問題 + label_any_issues_not_in_project: 不在專案中的任意問題 + label_no_issues_in_project: 沒有問題在專案中 + label_day_plural: 天 + label_repository: 儲存機制 + label_repository_new: 建立新儲存機制 + label_repository_plural: 儲存機制清單 + label_browse: 瀏覽 + label_branch: 分支 + label_tag: 標籤 + label_revision: 修訂版 + label_revision_plural: 修訂版清單 + label_revision_id: "修訂版 %{value}" + label_associated_revisions: 關聯的修訂版 + label_added: 已新增 + label_modified: 已修改 + label_copied: 已複製 + label_renamed: 已重新命名 + label_deleted: 已刪除 + label_latest_revision: 最新的修訂版 + label_latest_revision_plural: 最新的修訂版清單 + label_view_revisions: 檢視修訂版清單 + label_view_all_revisions: 檢視所有的的修訂版清單 + label_max_size: 最大長度 + label_sort_highest: 移動至開頭 + label_sort_higher: 往上移動 + label_sort_lower: 往下移動 + label_sort_lowest: 移動至結尾 + label_roadmap: 版本藍圖 + label_roadmap_due_in: "剩餘 %{value}" + label_roadmap_overdue: "逾期 %{value}" + label_roadmap_no_issues: 此版本尚未包含任何問題 + label_search: 搜尋 + label_result_plural: 結果 + label_all_words: 包含全部的字詞 + label_wiki: Wiki + label_wiki_edit: Wiki 編輯 + label_wiki_edit_plural: Wiki 編輯 + label_wiki_page: Wiki 網頁 + label_wiki_page_plural: Wiki 網頁 + label_index_by_title: 依標題索引 + label_index_by_date: 依日期索引 + label_current_version: 現行版本 + label_preview: 預覽 + label_feed_plural: Feeds + label_changes_details: 所有變更的明細 + label_issue_tracking: 問題追蹤 + label_spent_time: 耗用工時 + label_overall_spent_time: 整體耗用工時 + label_f_hour: "%{value} 小時" + label_f_hour_plural: "%{value} 小時" + label_time_tracking: 工時追蹤 + label_change_plural: 變更 + label_statistics: 統計資訊 + label_commits_per_month: 依月份統計認可 + label_commits_per_author: 依作者統計認可 + label_view_diff: 檢視差異 + label_diff: 差異 + label_diff_inline: 直列 + label_diff_side_by_side: 並排 + label_options: 選項清單 + label_copy_workflow_from: 從以下追蹤標籤複製工作流程 + label_permissions_report: 權限報表 + label_watched_issues: 監看中的問題清單 + label_related_issues: 相關的問題清單 + label_applied_status: 已套用狀態 + label_loading: 載入中... + label_relation_new: 建立新關聯 + label_relation_delete: 刪除關聯 + label_relates_to: 關聯至 + label_duplicates: 已重複 + label_duplicated_by: 與後面所列問題重複 + label_blocks: 阻擋 + label_blocked_by: 被阻擋 + label_precedes: 優先於 + label_follows: 跟隨於 + label_copied_to: 複製到 + label_copied_from: 複製於 + label_end_to_start: 結束─開始 + label_end_to_end: 結束─結束 + label_start_to_start: 開始─開始 + label_start_to_end: 開始─結束 + label_stay_logged_in: 維持已登入狀態 + label_disabled: 關閉 + label_show_completed_versions: 顯示已完成的版本 + label_me: 我自己 + label_board: 論壇 + label_board_new: 建立新論壇 + label_board_plural: 論壇 + label_board_locked: 鎖定 + label_board_sticky: 置頂 + label_topic_plural: 討論主題 + label_message_plural: 訊息 + label_message_last: 上一封訊息 + label_message_new: 建立新訊息 + label_message_posted: 訊息已新增 + label_reply_plural: 回應 + label_send_information: 寄送帳戶資訊電子郵件給用戶 + label_year: 年 + label_month: 月 + label_week: 週 + label_date_from: 開始 + label_date_to: 結束 + label_language_based: 依用戶之語系決定 + label_sort_by: "按 %{value} 排序" + label_send_test_email: 寄送測試郵件 + label_feeds_access_key: RSS 存取金鑰 + label_missing_feeds_access_key: 找不到 RSS 存取金鑰 + label_feeds_access_key_created_on: "RSS 存取鍵建立於 %{value} 之前" + label_module_plural: 模組 + label_added_time_by: "是由 %{author} 於 %{age} 前加入" + label_updated_time_by: "是由 %{author} 於 %{age} 前更新" + label_updated_time: "於 %{value} 前更新" + label_jump_to_a_project: 選擇欲前往的專案... + label_file_plural: 檔案清單 + label_changeset_plural: 變更集清單 + label_default_columns: 預設欄位清單 + label_no_change_option: (維持不變) + label_bulk_edit_selected_issues: 大量編輯選取的問題 + label_bulk_edit_selected_time_entries: 大量編輯選取的工時項目 + label_theme: 畫面主題 + label_default: 預設 + label_search_titles_only: 僅搜尋標題 + label_user_mail_option_all: "提醒與我的專案有關的全部事件" + label_user_mail_option_selected: "只提醒我所選擇專案中的事件..." + label_user_mail_option_none: "取消提醒" + label_user_mail_option_only_my_events: "只提醒我觀察中或參與中的事物" + label_user_mail_option_only_assigned: "只提醒我被指派的事物" + label_user_mail_option_only_owner: "只提醒我作為擁有者的事物" + label_user_mail_no_self_notified: "不提醒我自己所做的變更" + label_registration_activation_by_email: 透過電子郵件啟用帳戶 + label_registration_manual_activation: 手動啟用帳戶 + label_registration_automatic_activation: 自動啟用帳戶 + label_display_per_page: "每頁顯示: %{value} 個" + label_age: 年齡 + label_change_properties: 變更屬性 + label_general: 一般 + label_more: 更多 » + label_scm: 版本控管 + label_plugins: 附加元件 + label_ldap_authentication: LDAP 認證 + label_downloads_abbr: 下載 + label_optional_description: 額外的說明 + label_add_another_file: 增加其他檔案 + label_preferences: 偏好選項 + label_chronological_order: 以時間由遠至近排序 + label_reverse_chronological_order: 以時間由近至遠排序 + label_planning: 計劃表 + label_incoming_emails: 傳入的電子郵件 + label_generate_key: 產生金鑰 + label_issue_watchers: 監看者 + label_example: 範例 + label_display: 顯示 + label_sort: 排序 + label_ascending: 遞增排序 + label_descending: 遞減排序 + label_date_from_to: 起 %{start} 迄 %{end} + label_wiki_content_added: Wiki 頁面已新增 + label_wiki_content_updated: Wiki 頁面已更新 + label_group: 群組 + label_group_plural: 群組清單 + label_group_new: 建立新群組 + label_time_entry_plural: 耗用工時 + label_version_sharing_none: 不共用 + label_version_sharing_descendants: 與子專案共用 + label_version_sharing_hierarchy: 與專案階層架構共用 + label_version_sharing_tree: 與專案樹共用 + label_version_sharing_system: 與全部的專案共用 + label_update_issue_done_ratios: 更新問題完成百分比 + label_copy_source: 來源 + label_copy_target: 目的地 + label_copy_same_as_target: 與目的地相同 + label_display_used_statuses_only: 僅顯示此追蹤標籤所使用之狀態 + label_api_access_key: API 存取金鑰 + label_missing_api_access_key: 找不到 API 存取金鑰 + label_api_access_key_created_on: "API 存取金鑰建立於 %{value} 之前" + label_profile: 配置概況 + label_subtask_plural: 子任務 + label_project_copy_notifications: 在複製專案的過程中,傳送通知郵件 + label_principal_search: "搜尋用戶或群組:" + label_user_search: "搜尋用戶:" + label_additional_workflow_transitions_for_author: 用戶為作者時額外允許的流程轉換 + label_additional_workflow_transitions_for_assignee: 用戶為被指定者時額外允許的流程轉換 + label_issues_visibility_all: 所有問題 + label_issues_visibility_public: 所有非私人問題 + label_issues_visibility_own: 使用者所建立的或被指派的問題 + label_git_report_last_commit: 報告最後認可的文件和目錄 + label_parent_revision: 父項 + label_child_revision: 子項 + label_export_options: "%{export_format} 匯出選項" + label_copy_attachments: 複製附件 + label_copy_subtasks: 複製子任務 + label_item_position: "%{position} / %{count}" + label_completed_versions: 已完成版本 + label_search_for_watchers: 搜尋可供加入的監看者 + label_session_expiration: 工作階段逾期 + label_show_closed_projects: 檢視已關閉的專案 + label_status_transitions: 狀態轉換 + label_fields_permissions: 欄位權限 + label_readonly: 唯讀 + label_required: 必填 + label_attribute_of_project: "專案是 %{name}" + label_attribute_of_issue: "問題是 %{name}" + label_attribute_of_author: "作者是 %{name}" + label_attribute_of_assigned_to: "被指派者是 %{name}" + label_attribute_of_user: "用戶是 %{name}" + label_attribute_of_fixed_version: "版本是 %{name}" + label_cross_project_descendants: 與子專案共用 + label_cross_project_tree: 與專案樹共用 + label_cross_project_hierarchy: 與專案階層架構共用 + label_cross_project_system: 與全部的專案共用 + label_gantt_progress_line: 進度線 + + button_login: 登入 + button_submit: 送出 + button_save: 儲存 + button_check_all: 全選 + button_uncheck_all: 全不選 + button_collapse_all: 全部摺疊 + button_expand_all: 全部展開 + button_delete: 刪除 + button_create: 建立 + button_create_and_continue: 繼續建立 + button_test: 測試 + button_edit: 編輯 + button_edit_associated_wikipage: "編輯相關 Wiki 頁面: %{page_title}" + button_add: 新增 + button_change: 修改 + button_apply: 套用 + button_clear: 清除 + button_lock: 鎖定 + button_unlock: 解除鎖定 + button_download: 下載 + button_list: 清單 + button_view: 檢視 + button_move: 移動 + button_move_and_follow: 移動後跟隨 + button_back: 返回 + button_cancel: 取消 + button_activate: 啟用 + button_sort: 排序 + button_log_time: 記錄時間 + button_rollback: 還原至此版本 + button_watch: 觀察 + button_unwatch: 取消觀察 + button_reply: 回應 + button_archive: 封存 + button_unarchive: 取消封存 + button_reset: 回復 + button_rename: 重新命名 + button_change_password: 變更密碼 + button_copy: 複製 + button_copy_and_follow: 複製後跟隨 + button_annotate: 註解 + button_update: 更新 + button_configure: 設定 + button_quote: 引用 + button_duplicate: 重製 + button_show: 顯示 + button_hide: 隱藏 + button_edit_section: 編輯此區塊 + button_export: 匯出 + button_delete_my_account: 刪除我的帳戶 + button_close: 關閉 + button_reopen: 重新開啟 + + status_active: 活動中 + status_registered: 註冊完成 + status_locked: 鎖定中 + + project_status_active: 使用中 + project_status_closed: 已關閉 + project_status_archived: 已封存 + + version_status_open: 進行中 + version_status_locked: 已鎖定 + version_status_closed: 已結束 + + field_active: 活動中 + + text_select_mail_notifications: 選擇欲寄送提醒通知郵件之動作 + text_regexp_info: eg. ^[A-Z0-9]+$ + text_min_max_length_info: 0 代表「不限制」 + text_project_destroy_confirmation: 您確定要刪除這個專案和其他相關資料? + text_subprojects_destroy_warning: "下列子專案: %{value} 將一併被刪除。" + text_workflow_edit: 選擇角色與追蹤標籤以設定其工作流程 + text_are_you_sure: 確定執行? + text_journal_changed: "%{label} 從 %{old} 變更為 %{new}" + text_journal_changed_no_detail: "%{label} 已更新" + text_journal_set_to: "%{label} 設定為 %{value}" + text_journal_deleted: "%{label} 已刪除 (%{old})" + text_journal_added: "%{label} %{value} 已新增" + text_tip_issue_begin_day: 今天起始的問題 + text_tip_issue_end_day: 今天截止的的問題 + text_tip_issue_begin_end_day: 今天起始與截止的問題 + text_project_identifier_info: '僅允許使用小寫英文字母 (a-z), 阿拉伯數字, 虛線與底線。
    一旦儲存之後, 代碼便無法再次被更改。' + text_caracters_maximum: "最多 %{count} 個字元." + text_caracters_minimum: "長度必須大於 %{count} 個字元." + text_length_between: "長度必須介於 %{min} 至 %{max} 個字元之間." + text_tracker_no_workflow: 此追蹤標籤尚未定義工作流程 + text_unallowed_characters: 不允許的字元 + text_comma_separated: 可輸入多個值(須以逗號分隔)。 + text_line_separated: 可輸入多個值(須以換行符號分隔,即每列只能輸入一個值)。 + text_issues_ref_in_commit_messages: 認可訊息中參照(或修正)問題之關鍵字 + text_issue_added: "問題 %{id} 已被 %{author} 通報。" + text_issue_updated: "問題 %{id} 已被 %{author} 更新。" + text_wiki_destroy_confirmation: 您確定要刪除這個 wiki 和其中的所有內容? + text_issue_category_destroy_question: "有 (%{count}) 個問題被指派到此分類. 請選擇您想要的動作?" + text_issue_category_destroy_assignments: 移除這些問題的分類 + text_issue_category_reassign_to: 重新指派這些問題至其它分類 + text_user_mail_option: "對於那些未被選擇的專案,將只會接收到您正在觀察中,或是參與中的問題通知。(「參與中的問題」包含您建立的或是指派給您的問題)" + text_no_configuration_data: "角色、追蹤標籤、問題狀態與流程尚未被設定完成。\n強烈建議您先載入預設的組態。將預設組態載入之後,您可再變更其中之值。" + text_load_default_configuration: 載入預設組態 + text_status_changed_by_changeset: "已套用至變更集 %{value}." + text_time_logged_by_changeset: "紀錄於變更集 %{value}." + text_issues_destroy_confirmation: '確定刪除已選擇的問題?' + text_issues_destroy_descendants_confirmation: "這麼做將會一併刪除 %{count} 子任務。" + text_time_entries_destroy_confirmation: 您確定要刪除所選擇的工時紀錄? + text_select_project_modules: '選擇此專案可使用之模組:' + text_default_administrator_account_changed: 已變更預設管理員帳號內容 + text_file_repository_writable: 可寫入附加檔案目錄 + text_plugin_assets_writable: 可寫入附加元件目錄 + text_rmagick_available: 可使用 RMagick (選配) + text_destroy_time_entries_question: 您即將刪除的問題已報工 %{hours} 小時. 您的選擇是? + text_destroy_time_entries: 刪除已報工的時數 + text_assign_time_entries_to_project: 指定已報工的時數至專案中 + text_reassign_time_entries: '重新指定已報工的時數至此問題:' + text_user_wrote: "%{value} 先前提到:" + text_enumeration_destroy_question: "目前有 %{count} 個物件使用此列舉值。" + text_enumeration_category_reassign_to: '重新設定其列舉值為:' + text_email_delivery_not_configured: "您尚未設定電子郵件傳送方式,因此提醒選項已被停用。\n請在 config/configuration.yml 中設定 SMTP 之後,重新啟動 Redmine,以啟用電子郵件提醒選項。" + text_repository_usernames_mapping: "選擇或更新 Redmine 使用者與儲存機制紀錄使用者之對應關係。\n儲存機制中之使用者帳號或電子郵件信箱,與 Redmine 設定相同者,將自動產生對應關係。" + text_diff_truncated: '... 這份差異已被截短以符合顯示行數之最大值' + text_custom_field_possible_values_info: '一列輸入一個值' + text_wiki_page_destroy_question: "此頁面包含 %{descendants} 個子頁面及延伸頁面。 請選擇您想要的動作?" + text_wiki_page_nullify_children: "保留所有子頁面當作根頁面" + text_wiki_page_destroy_children: "刪除所有子頁面及其延伸頁面" + text_wiki_page_reassign_children: "重新指定所有的子頁面之父頁面至此頁面" + text_own_membership_delete_confirmation: "您在專案中,所擁有的部分或全部權限即將被移除,在這之後可能無法再次編輯此專案。\n您確定要繼續執行這個動作?" + text_zoom_in: 放大 + text_zoom_out: 縮小 + text_warn_on_leaving_unsaved: "若您離開這個頁面,此頁面所包含的未儲存資料將會遺失。" + text_scm_path_encoding_note: "預設: UTF-8" + text_git_repository_note: 儲存機制是本機的空(bare)目錄 (即: /gitrepo, c:\gitrepo) + text_mercurial_repository_note: 本機儲存機制 (即: /hgrepo, c:\hgrepo) + text_scm_command: 命令 + text_scm_command_version: 版本 + text_scm_config: 您可以在 config/configuration.yml 中設定 SCM 命令。請在編輯該檔案之後重新啟動 Redmine 應用程式。 + text_scm_command_not_available: SCM 命令無法使用。請檢查管理面板中的設定。 + text_issue_conflict_resolution_overwrite: "直接套用我的變更 (先前的筆記將會被保留,但是某些變更可能會被複寫)" + text_issue_conflict_resolution_add_notes: "新增我的筆記並捨棄我其他的變更" + text_issue_conflict_resolution_cancel: "捨棄我全部的變更並重新顯示 %{link}" + text_account_destroy_confirmation: |- + 您確定要繼續這個動作嗎? + 您的帳戶將會被永久刪除,且無法被重新啟用。 + text_session_expiration_settings: "警告:變更這些設定將會導致包含您在內的所有工作階段過期。" + text_project_closed: 此專案已被關閉,僅供唯讀使用。 + text_turning_multiple_off: "若您停用多重值設定,重複的值將會被移除,以使每個項目僅保留一個值。" + + default_role_manager: 管理人員 + default_role_developer: 開發人員 + default_role_reporter: 報告人員 + default_tracker_bug: 臭蟲 + default_tracker_feature: 功能 + default_tracker_support: 支援 + default_issue_status_new: 新建立 + default_issue_status_in_progress: 實作中 + default_issue_status_resolved: 已解決 + default_issue_status_feedback: 已回應 + default_issue_status_closed: 已結束 + default_issue_status_rejected: 已拒絕 + default_doc_category_user: 使用手冊 + default_doc_category_tech: 技術文件 + default_priority_low: 低 + default_priority_normal: 正常 + default_priority_high: 高 + default_priority_urgent: 速 + default_priority_immediate: 急 + default_activity_design: 設計 + default_activity_development: 開發 + + enumeration_issue_priorities: 問題優先權 + enumeration_doc_categories: 文件分類 + enumeration_activities: 活動 (時間追蹤) + enumeration_system_activity: 系統活動 + description_filter: 篩選條件 + description_search: 搜尋欄位 + description_choose_project: 專案清單 + description_project_scope: 搜尋範圍 + description_notes: 筆記 + description_message_content: 訊息內容 + description_query_sort_criteria_attribute: 排序屬性 + description_query_sort_criteria_direction: 排列順序 + description_user_mail_notification: 郵件通知設定 + description_available_columns: 可用欄位 + description_selected_columns: 已選取的欄位 + description_all_columns: 所有欄位 + description_issue_category_reassign: 選擇問題分類 + description_wiki_subpages_reassign: 選擇新的父頁面 + description_date_range_list: 從清單中選取範圍 + description_date_range_interval: 選擇起始與結束日期以設定範圍區間 + description_date_from: 輸入起始日期 + description_date_to: 輸入結束日期 + text_repository_identifier_info: '僅允許使用小寫英文字母 (a-z), 阿拉伯數字, 虛線與底線。
    一旦儲存之後, 代碼便無法再次被更改。' + label_total_time: 總計 diff --git a/config/locales/zh.yml b/config/locales/zh.yml new file mode 100644 index 00000000..846b9b65 --- /dev/null +++ b/config/locales/zh.yml @@ -0,0 +1,1149 @@ + +# Chinese (China) translations for Ruby on Rails +# by tsechingho (http://github.com/tsechingho) +zh: + # Text direction: Left-to-Right (ltr) or Right-to-Left (rtl) + direction: ltr + jquery: + locale: "zh-CN" + date: + formats: + # Use the strftime parameters for formats. + # When no format has been given, it uses default. + # You can provide other formats here if you like! + default: "%Y-%m-%d" + short: "%b%d日" + long: "%Y年%b%d日" + + day_names: [星期天, 星期一, 星期二, 星期三, 星期四, 星期五, 星期六] + abbr_day_names: [日, 一, 二, 三, 四, 五, 六] + + # Don't forget the nil at the beginning; there's no such thing as a 0th month + month_names: [~, 一月, 二月, 三月, 四月, 五月, 六月, 七月, 八月, 九月, 十月, 十一月, 十二月] + abbr_month_names: [~, 1月, 2月, 3月, 4月, 5月, 6月, 7月, 8月, 9月, 10月, 11月, 12月] + # Used in date_select and datime_select. + order: + - :year + - :month + - :day + + time: + formats: + default: "%Y年%b%d日 %A %H:%M:%S" + time: "%H:%M" + short: "%b%d日 %H:%M" + long: "%Y年%b%d日 %H:%M" + am: "上午" + pm: "下午" + + datetime: + distance_in_words: + half_a_minute: "半分钟" + less_than_x_seconds: + one: "一秒内" + other: "少于 %{count} 秒" + x_seconds: + one: "一秒" + other: "%{count} 秒" + less_than_x_minutes: + one: "一分钟内" + other: "少于 %{count} 分钟" + x_minutes: + one: "一分钟" + other: "%{count} 分钟" + about_x_hours: + one: "大约一小时" + other: "大约 %{count} 小时" + x_hours: + one: "1 小时" + other: "%{count} 小时" + x_days: + one: "一天" + other: "%{count} 天" + about_x_months: + one: "大约一个月" + other: "大约 %{count} 个月" + x_months: + one: "一个月" + other: "%{count} 个月" + about_x_years: + one: "大约一年" + other: "大约 %{count} 年" + over_x_years: + one: "超过一年" + other: "超过 %{count} 年" + almost_x_years: + one: "将近 1 年" + other: "将近 %{count} 年" + + number: + # Default format for numbers + format: + separator: "." + delimiter: "" + precision: 3 + human: + format: + delimiter: "" + precision: 3 + storage_units: + format: "%n %u" + units: + byte: + one: "Byte" + other: "Bytes" + kb: "KB" + mb: "MB" + gb: "GB" + tb: "TB" + +# Used in array.to_sentence. + support: + array: + sentence_connector: "和" + skip_last_comma: false + + activerecord: + errors: + template: + header: + one: "由于发生了一个错误 %{model} 无法保存" + other: "%{count} 个错误使得 %{model} 无法保存" + messages: + inclusion: "不包含于列表中" + exclusion: "是保留关键字" + invalid: "是无效的" + confirmation: "与确认值不匹配" + accepted: "必须是可被接受的" + empty: "不能留空" + blank: "不能为空字符" + too_long: "过长(最长为 %{count} 个字符)" + too_short: "过短(最短为 %{count} 个字符)" + wrong_length: "长度非法(必须为 %{count} 个字符)" + taken: "已经被使用" + not_a_number: "不是数字" + not_a_date: "不是合法日期" + greater_than: "必须大于 %{count}" + greater_than_or_equal_to: "必须大于或等于 %{count}" + equal_to: "必须等于 %{count}" + less_than: "必须小于 %{count}" + less_than_or_equal_to: "必须小于或等于 %{count}" + odd: "必须为单数" + even: "必须为双数" + greater_than_start_date: "必须在起始日期之后" + not_same_project: "不属于同一个项目" + circular_dependency: "此关联将导致循环依赖" + cant_link_an_issue_with_a_descendant: "问题不能关联到它的子任务" + + actionview_instancetag_blank_option: 请选择 + + general_text_No: '否' + general_text_Yes: '是' + general_text_no: '否' + general_text_yes: '是' + general_lang_name: 'Simplified Chinese (简体中文)' + general_csv_separator: ',' + general_csv_decimal_separator: '.' + general_csv_encoding: gb18030 + general_pdf_encoding: gb18030 + general_first_day_of_week: '7' + + notice_account_updated: 帐号更新成功 + notice_account_invalid_creditentials: 无效的用户名或密码 + notice_account_password_updated: 密码更新成功 + notice_account_wrong_password: 密码错误 + notice_account_register_done: 帐号创建成功,请使用注册确认邮件中的链接来激活您的帐号。 + notice_account_unknown_email: 未知用户 + notice_can_t_change_password: 该帐号使用了外部认证,因此无法更改密码。 + notice_account_lost_email_sent: 系统已将引导您设置新密码的邮件发送给您。 + notice_account_activated: 您的帐号已被激活。您现在可以登录了。 + notice_successful_create: 创建成功 + notice_successful_update: 更新成功 + notice_successful_delete: 删除成功 + notice_successful_connection: 连接成功 + notice_file_not_found: 您访问的页面不存在或已被删除。 + notice_locking_conflict: 数据已被另一位用户更新 + notice_not_authorized: 对不起,您无权访问此页面。 + notice_not_authorized_archived_project: 要访问的项目已经归档。 + notice_email_sent: "邮件已发送至 %{value}" + notice_email_error: "发送邮件时发生错误 (%{value})" + notice_feeds_access_key_reseted: 您的RSS存取键已被重置。 + notice_api_access_key_reseted: 您的API访问键已被重置。 + notice_failed_to_save_issues: "%{count} 个问题保存失败(共选择 %{total} 个问题):%{ids}." + notice_failed_to_save_members: "成员保存失败: %{errors}." + notice_no_issue_selected: "未选择任何问题!请选择您要编辑的问题。" + notice_account_pending: "您的帐号已被成功创建,正在等待管理员的审核。" + notice_default_data_loaded: 成功载入默认设置。 + notice_unable_delete_version: 无法删除版本 + notice_unable_delete_time_entry: 无法删除工时 + notice_issue_done_ratios_updated: 问题完成度已更新。 + notice_gantt_chart_truncated: "The chart was truncated because it exceeds the maximum number of items that can be displayed (%{max})" + + error_can_t_load_default_data: "无法载入默认设置:%{value}" + error_scm_not_found: "版本库中不存在该条目和(或)其修订版本。" + error_scm_command_failed: "访问版本库时发生错误:%{value}" + error_scm_annotate: "该条目不存在或无法追溯。" + error_issue_not_found_in_project: '问题不存在或不属于此项目' + error_no_tracker_in_project: 该项目未设定跟踪标签,请检查项目配置。 + error_no_default_issue_status: 未设置默认的问题状态。请检查系统设置("管理" -> "问题状态")。 + error_can_not_delete_custom_field: 无法删除自定义属性 + error_can_not_delete_tracker: "该跟踪标签已包含问题,无法删除" + error_can_not_remove_role: "该角色正在使用中,无法删除" + error_can_not_reopen_issue_on_closed_version: 该问题被关联到一个已经关闭的版本,因此无法重新打开。 + error_can_not_archive_project: 该项目无法被存档 + error_issue_done_ratios_not_updated: 问题完成度未能被更新。 + error_workflow_copy_source: 请选择一个源跟踪标签或者角色 + error_workflow_copy_target: 请选择目标跟踪标签和角色 + error_unable_delete_issue_status: '无法删除问题状态' + error_unable_to_connect: "无法连接 (%{value})" + warning_attachments_not_saved: "%{count} 个文件保存失败" + + mail_subject_lost_password: "您的 %{value} 密码" + mail_body_lost_password: '请点击以下链接来修改您的密码:' + mail_subject_register: "%{value}帐号激活" + mail_body_register: '请点击以下链接来激活您的帐号:' + mail_body_account_information_external: "您可以使用您的 %{value} 帐号来登录。" + mail_body_account_information: 您的帐号信息 + mail_subject_account_activation_request: "%{value}帐号激活请求" + mail_body_account_activation_request: "新用户(%{value})已完成注册,正在等候您的审核:" + mail_subject_reminder: "%{count} 个问题需要尽快解决 (%{days})" + mail_body_reminder: "指派给您的 %{count} 个问题需要在 %{days} 天内完成:" + mail_subject_wiki_content_added: "'%{id}' wiki页面已添加" + mail_body_wiki_content_added: "'%{id}' wiki页面已由 %{author} 添加。" + mail_subject_wiki_content_updated: "'%{id}' wiki页面已更新。" + mail_body_wiki_content_updated: "'%{id}' wiki页面已由 %{author} 更新。" + + + field_name: 名称 + field_description: 描述 + field_summary: 摘要 + field_is_required: 必填 + field_firstname: 名字 + field_lastname: 姓氏 + field_mail: 邮件地址 + field_filename: 文件 + field_filesize: 大小 + field_downloads: 下载次数 + field_author: 作者 + field_created_on: 创建于 + field_updated_on: 更新于 + field_field_format: 格式 + field_is_for_all: 用于所有项目 + field_possible_values: 可能的值 + field_regexp: 正则表达式 + field_min_length: 最小长度 + field_max_length: 最大长度 + field_value: 值 + field_category: 类别 + field_title: 标题 + field_project: 项目 + field_issue: 问题 + field_status: 状态 + field_notes: 说明 + field_is_closed: 已关闭的问题 + field_is_default: 默认值 + field_tracker: 跟踪 + field_subject: 主题 + field_due_date: 计划完成日期 + field_assigned_to: 指派给 + field_priority: 优先级 + field_fixed_version: 目标版本 + field_user: 用户 + field_principal: 用户/用户组 + field_role: 角色 + field_homepage: 主页 + field_is_public: 公开 + field_parent: 上级项目 + field_is_in_roadmap: 在路线图中显示 + field_login: 登录名 + field_mail_notification: 邮件通知 + field_admin: 管理员 + field_last_login_on: 最后登录 + field_language: 语言 + field_effective_date: 日期 + field_password: 密码 + field_new_password: 新密码 + field_password_confirmation: 确认 + field_version: 版本 + field_type: 类型 + field_host: 主机 + field_port: 端口 + field_account: 帐号 + field_base_dn: Base DN + field_attr_login: 登录名属性 + field_attr_firstname: 名字属性 + field_attr_lastname: 姓氏属性 + field_attr_mail: 邮件属性 + field_onthefly: 即时用户生成 + field_start_date: 开始日期 + field_done_ratio: "% 完成" + field_auth_source: 认证模式 + field_hide_mail: 隐藏我的邮件地址 + field_comments: 注释 + field_url: URL + field_start_page: 起始页 + field_subproject: 子项目 + field_hours: 小时 + field_activity: 活动 + field_spent_on: 日期 + field_identifier: 标识 + field_is_filter: 作为过滤条件 + field_issue_to: 相关问题 + field_delay: 延期 + field_assignable: 问题可指派给此角色 + field_redirect_existing_links: 重定向到现有链接 + field_estimated_hours: 预期时间 + field_column_names: 列 + field_time_entries: 工时 + field_time_zone: 时区 + field_searchable: 可用作搜索条件 + field_default_value: 默认值 + field_comments_sorting: 显示注释 + field_parent_title: 上级页面 + field_editable: 可编辑 + field_watcher: 跟踪者 + field_identity_url: OpenID URL + field_content: 内容 + field_group_by: 根据此条件分组 + field_sharing: 共享 + field_parent_issue: 父任务 + field_member_of_group: 用户组的成员 + field_assigned_to_role: 角色的成员 + field_text: 文本字段 + field_visible: 可见的 + + setting_app_title: 应用程序标题 + setting_app_subtitle: 应用程序子标题 + setting_welcome_text: 欢迎文字 + setting_default_language: 默认语言 + setting_login_required: 要求认证 + setting_self_registration: 允许自注册 + setting_attachment_max_size: 附件大小限制 + setting_issues_export_limit: 问题导出条目的限制 + setting_mail_from: 邮件发件人地址 + setting_bcc_recipients: 使用密件抄送 (bcc) + setting_plain_text_mail: 纯文本(无HTML) + setting_host_name: 主机名称 + setting_text_formatting: 文本格式 + setting_wiki_compression: 压缩Wiki历史文档 + setting_feeds_limit: RSS Feed内容条数限制 + setting_default_projects_public: 新建项目默认为公开项目 + setting_autofetch_changesets: 自动获取程序变更 + setting_sys_api_enabled: 启用用于版本库管理的Web Service + setting_commit_ref_keywords: 用于引用问题的关键字 + setting_commit_fix_keywords: 用于解决问题的关键字 + setting_autologin: 自动登录 + setting_date_format: 日期格式 + setting_time_format: 时间格式 + setting_cross_project_issue_relations: 允许不同项目之间的问题关联 + setting_issue_list_default_columns: 问题列表中显示的默认列 + setting_emails_header: 邮件头 + setting_emails_footer: 邮件签名 + setting_protocol: 协议 + setting_per_page_options: 每页显示条目个数的设置 + setting_user_format: 用户显示格式 + setting_activity_days_default: 在项目活动中显示的天数 + setting_display_subprojects_issues: 在项目页面上默认显示子项目的问题 + setting_enabled_scm: 启用 SCM + setting_mail_handler_body_delimiters: 在这些行之后截断邮件 + setting_mail_handler_api_enabled: 启用用于接收邮件的服务 + setting_mail_handler_api_key: API key + setting_sequential_project_identifiers: 顺序产生项目标识 + setting_gravatar_enabled: 使用Gravatar用户头像 + setting_gravatar_default: 默认的Gravatar头像 + setting_diff_max_lines_displayed: 查看差别页面上显示的最大行数 + setting_file_max_size_displayed: 允许直接显示的最大文本文件 + setting_repository_log_display_limit: 在文件变更记录页面上显示的最大修订版本数量 + setting_openid: 允许使用OpenID登录和注册 + setting_password_min_length: 最短密码长度 + setting_new_project_user_role_id: 非管理员用户新建项目时将被赋予的(在该项目中的)角色 + setting_default_projects_modules: 新建项目默认启用的模块 + setting_issue_done_ratio: 计算问题完成度: + setting_issue_done_ratio_issue_field: 使用问题(的完成度)属性 + setting_issue_done_ratio_issue_status: 使用问题状态 + setting_start_of_week: 日历开始于 + setting_rest_api_enabled: 启用REST web service + setting_cache_formatted_text: 缓存格式化文字 + setting_default_notification_option: 默认提醒选项 + setting_commit_logtime_enabled: 激活时间日志 + setting_commit_logtime_activity_id: 记录的活动 + setting_gantt_items_limit: 在甘特图上显示的最大记录数 + + permission_add_project: 新建项目 + permission_add_subprojects: 新建子项目 + permission_edit_project: 编辑项目 + permission_select_project_modules: 选择项目模块 + permission_manage_members: 管理成员 + permission_manage_project_activities: 管理项目活动 + permission_manage_versions: 管理版本 + permission_manage_categories: 管理问题类别 + permission_view_issues: 查看问题 + permission_add_issues: 新建问题 + permission_edit_issues: 更新问题 + permission_manage_issue_relations: 管理问题关联 + permission_add_issue_notes: 添加说明 + permission_edit_issue_notes: 编辑说明 + permission_edit_own_issue_notes: 编辑自己的说明 + permission_move_issues: 移动问题 + permission_delete_issues: 删除问题 + permission_manage_public_queries: 管理公开的查询 + permission_save_queries: 保存查询 + permission_view_gantt: 查看甘特图 + permission_view_calendar: 查看日历 + permission_view_issue_watchers: 查看跟踪者列表 + permission_add_issue_watchers: 添加跟踪者 + permission_delete_issue_watchers: 删除跟踪者 + permission_log_time: 登记工时 + permission_view_time_entries: 查看耗时 + permission_edit_time_entries: 编辑耗时 + permission_edit_own_time_entries: 编辑自己的耗时 + permission_manage_news: 管理新闻 + permission_comment_news: 为新闻添加评论 + permission_view_documents: 查看文档 + permission_manage_files: 管理文件 + permission_view_files: 查看文件 + permission_manage_wiki: 管理Wiki + permission_rename_wiki_pages: 重定向/重命名Wiki页面 + permission_delete_wiki_pages: 删除Wiki页面 + permission_view_wiki_pages: 查看Wiki + permission_view_wiki_edits: 查看Wiki历史记录 + permission_edit_wiki_pages: 编辑Wiki页面 + permission_delete_wiki_pages_attachments: 删除附件 + permission_protect_wiki_pages: 保护Wiki页面 + permission_manage_repository: 管理版本库 + permission_browse_repository: 浏览版本库 + permission_view_changesets: 查看变更 + permission_commit_access: 访问提交信息 + permission_manage_boards: 管理讨论区 + permission_view_messages: 查看帖子 + permission_add_messages: 发表帖子 + permission_edit_messages: 编辑帖子 + permission_edit_own_messages: 编辑自己的帖子 + permission_delete_messages: 删除帖子 + permission_delete_own_messages: 删除自己的帖子 + permission_export_wiki_pages: 导出 wiki 页面 + permission_manage_subtasks: 管理子任务 + + project_module_issue_tracking: 问题跟踪 + project_module_time_tracking: 时间跟踪 + project_module_news: 新闻 + project_module_documents: 文档 + project_module_files: 文件 + project_module_wiki: Wiki + project_module_repository: 版本库 + project_module_boards: 讨论区 + project_module_calendar: 日历 + project_module_gantt: 甘特图 + + label_user: 用户 + label_user_plural: 用户 + label_user_new: 新建用户 + label_user_anonymous: 匿名用户 + label_project: 项目 + label_project_new: 新建项目 + label_project_plural: 项目 + label_x_projects: + zero: 无项目 + one: 1 个项目 + other: "%{count} 个项目" + label_project_all: 所有的项目 + label_project_latest: 最近的项目 + label_issue: 问题 + label_issue_new: 新建问题 + label_issue_plural: 问题 + label_issue_view_all: 查看所有问题 + label_issues_by: "按 %{value} 分组显示问题" + label_issue_added: 问题已添加 + label_issue_updated: 问题已更新 + label_document: 文档 + label_document_new: 新建文档 + label_document_plural: 文档 + label_document_added: 文档已添加 + label_role: 角色 + label_role_plural: 角色 + label_role_new: 新建角色 + label_role_and_permissions: 角色和权限 + label_member: 成员 + label_member_new: 新建成员 + label_member_plural: 成员 + label_tracker: 跟踪标签 + label_tracker_plural: 跟踪标签 + label_tracker_new: 新建跟踪标签 + label_workflow: 工作流程 + label_issue_status: 问题状态 + label_issue_status_plural: 问题状态 + label_issue_status_new: 新建问题状态 + label_issue_category: 问题类别 + label_issue_category_plural: 问题类别 + label_issue_category_new: 新建问题类别 + label_custom_field: 自定义属性 + label_custom_field_plural: 自定义属性 + label_custom_field_new: 新建自定义属性 + label_enumerations: 枚举值 + label_enumeration_new: 新建枚举值 + label_information: 信息 + label_information_plural: 信息 + label_please_login: 请登录 + label_register: 注册 + label_login_with_open_id_option: 或使用OpenID登录 + label_password_lost: 忘记密码 + label_home: 主页 + #by young + label_requirement: 需求 + label_requirement_focus: 关注需求 + label_developer: 开发者 + label_investor: 投资人 + label_theme: 主题 + label_logged_as_new: 当前用户 + button_register: 注册 + issue_list: 缺陷列表 + lastest_respond: 最新反馈 + label_respond_view_all: 其他120个反馈 + label_news_lastest: 最新动态 + #end + label_my_page: 我的工作台 + label_my_account: 我的帐号 + label_my_projects: 我的项目 + label_my_page_block: 我的工作台模块 + label_administration: 管理 + label_login: 登录 + label_logout: 退出 + label_help: 帮助 + label_reported_issues: 已报告的问题 + label_assigned_to_me_issues: 指派给我的问题 + label_last_login: 最后登录 + label_registered_on: 注册于 + label_activity: 活动 + label_overall_activity: 活动概览 + label_user_activity: "%{value} 的活动" + label_new: 新建 + label_logged_as: 登录为 + label_environment: 环境 + label_authentication: 认证 + label_auth_source: 认证模式 + label_auth_source_new: 新建认证模式 + label_auth_source_plural: 认证模式 + label_subproject_plural: 子项目 + label_subproject_new: 新建子项目 + label_and_its_subprojects: "%{value} 及其子项目" + label_min_max_length: 最小 - 最大 长度 + label_list: 列表 + label_date: 日期 + label_integer: 整数 + label_float: 浮点数 + label_boolean: 布尔值 + label_string: 字符串 + label_text: 文本 + label_attribute: 属性 + label_attribute_plural: 属性 + label_no_data: 没有任何数据可供显示 + label_change_status: 变更状态 + label_history: 历史记录 + label_attachment: 文件 + label_attachment_new: 新建文件 + label_attachment_delete: 删除文件 + label_attachment_plural: 文件 + label_file_added: 文件已添加 + label_report: 报表 + label_report_plural: 报表 + label_news: 新闻 + label_news_new: 添加新闻 + label_news_plural: 新闻 + label_news_latest: 最近的新闻 + label_news_view_all: 查看所有新闻 + label_news_added: 新闻已添加 + label_settings: 配置 + label_overview: 活动 + label_version: 版本 + label_version_new: 新建版本 + label_version_plural: 版本 + label_close_versions: 关闭已完成的版本 + label_confirmation: 确认 + label_export_to: 导出 + label_read: 读取... + label_public_projects: 公开的项目 + label_open_issues: 打开 + label_open_issues_plural: 打开 + label_closed_issues: 已关闭 + label_closed_issues_plural: 已关闭 + label_x_open_issues_abbr_on_total: + zero: 0 打开 / %{total} + one: 1 打开 / %{total} + other: "%{count} 打开 / %{total}" + label_x_open_issues_abbr: + zero: 0 打开 + one: 1 打开 + other: "%{count} 打开" + label_x_closed_issues_abbr: + zero: 0 已关闭 + one: 1 已关闭 + other: "%{count} 已关闭" + label_total: 合计 + label_permissions: 权限 + label_current_status: 当前状态 + label_new_statuses_allowed: 允许的新状态 + label_all: 全部 + label_none: 无 + label_nobody: 无人 + label_next: 下一页 + label_previous: 上一页 + label_used_by: 使用中 + label_details: 详情 + label_add_note: 添加说明 + label_per_page: 每页 + label_calendar: 日历 + label_months_from: 个月以来 + label_gantt: 甘特图 + label_internal: 内部 + label_last_changes: "最近的 %{count} 次变更" + label_change_view_all: 查看所有变更 + label_personalize_page: 个性化定制本页 + label_comment: 评论 + label_comment_plural: 评论 + label_x_comments: + zero: 无评论 + one: 1 条评论 + other: "%{count} 条评论" + label_comment_add: 添加评论 + label_comment_added: 评论已添加 + label_comment_delete: 删除评论 + label_query: 自定义查询 + label_query_plural: 自定义查询 + label_query_new: 新建查询 + label_filter_add: 增加过滤器 + label_filter_plural: 过滤器 + label_equals: 等于 + label_not_equals: 不等于 + label_in_less_than: 剩余天数小于 + label_in_more_than: 剩余天数大于 + label_greater_or_equal: '>=' + label_less_or_equal: '<=' + label_in: 剩余天数 + label_today: 今天 + label_all_time: 全部时间 + label_yesterday: 昨天 + label_this_week: 本周 + label_last_week: 上周 + label_last_n_days: "最后 %{count} 天" + label_this_month: 本月 + label_last_month: 上月 + label_this_year: 今年 + label_date_range: 日期范围 + label_less_than_ago: 之前天数少于 + label_more_than_ago: 之前天数大于 + label_ago: 之前天数 + label_contains: 包含 + label_not_contains: 不包含 + label_day_plural: 天 + label_repository: 版本库 + label_repository_plural: 版本库 + label_browse: 浏览 + label_branch: 分支 + label_tag: 标签 + label_revision: 修订 + label_revision_plural: 修订 + label_revision_id: 修订 %{value} + label_associated_revisions: 相关修订版本 + label_added: 已添加 + label_modified: 已修改 + label_copied: 已复制 + label_renamed: 已重命名 + label_deleted: 已删除 + label_latest_revision: 最近的修订版本 + label_latest_revision_plural: 最近的修订版本 + label_view_revisions: 查看修订 + label_view_all_revisions: 查看所有修订 + label_max_size: 最大尺寸 + label_sort_highest: 置顶 + label_sort_higher: 上移 + label_sort_lower: 下移 + label_sort_lowest: 置底 + label_roadmap: 路线图 + label_roadmap_due_in: "截止日期到 %{value}" + label_roadmap_overdue: "%{value} 延期" + label_roadmap_no_issues: 该版本没有问题 + label_search: 搜索 + label_result_plural: 结果 + label_all_words: 所有单词 + label_wiki: Wiki + label_wiki_edit: Wiki 编辑 + label_wiki_edit_plural: Wiki 编辑记录 + label_wiki_page: Wiki 页面 + label_wiki_page_plural: Wiki 页面 + label_index_by_title: 按标题索引 + label_index_by_date: 按日期索引 + label_current_version: 当前版本 + label_preview: 预览 + label_feed_plural: Feeds + label_changes_details: 所有变更的详情 + label_issue_tracking: 问题跟踪 + label_spent_time: 耗时 + label_overall_spent_time: 总体耗时 + label_f_hour: "%{value} 小时" + label_f_hour_plural: "%{value} 小时" + label_time_tracking: 时间跟踪 + label_change_plural: 变更 + label_statistics: 统计 + label_commits_per_month: 每月提交次数 + label_commits_per_author: 每用户提交次数 + label_view_diff: 查看差别 + label_diff_inline: 直列 + label_diff_side_by_side: 并排 + label_options: 选项 + label_copy_workflow_from: 从以下选项复制工作流程 + label_permissions_report: 权限报表 + label_watched_issues: 跟踪的问题 + label_related_issues: 相关的问题 + label_applied_status: 应用后的状态 + label_loading: 载入中... + label_relation_new: 新建关联 + label_relation_delete: 删除关联 + label_relates_to: 关联到 + label_duplicates: 重复 + label_duplicated_by: 与其重复 + label_blocks: 阻挡 + label_blocked_by: 被阻挡 + label_precedes: 优先于 + label_follows: 跟随于 + label_end_to_start: 结束-开始 + label_end_to_end: 结束-结束 + label_start_to_start: 开始-开始 + label_start_to_end: 开始-结束 + label_stay_logged_in: 保持登录状态 + label_disabled: 禁用 + label_show_completed_versions: 显示已完成的版本 + label_me: 我 + label_board: 讨论区 + label_board_new: 新建讨论区 + label_board_plural: 讨论区 + label_board_locked: 锁定 + label_board_sticky: 置顶 + label_topic_plural: 主题 + label_message_plural: 帖子 + label_message_last: 最新的帖子 + label_message_new: 新贴 + label_message_posted: 发帖成功 + label_reply_plural: 回复 + label_send_information: 给用户发送帐号信息 + label_year: 年 + label_month: 月 + label_week: 周 + label_date_from: 从 + label_date_to: 到 + label_language_based: 根据用户的语言 + label_sort_by: "根据 %{value} 排序" + label_send_test_email: 发送测试邮件 + label_feeds_access_key: RSS存取键 + label_missing_feeds_access_key: 缺少RSS存取键 + label_feeds_access_key_created_on: "RSS存取键是在 %{value} 之前建立的" + label_module_plural: 模块 + label_added_time_by: "由 %{author} 在 %{age} 之前添加" + label_updated_time: " 更新于 %{value} 之前" + label_updated_time_by: "由 %{author} 更新于 %{age} 之前" + label_jump_to_a_project: 选择一个项目... + label_file_plural: 文件 + label_changeset_plural: 变更 + label_default_columns: 默认列 + label_no_change_option: (不变) + label_bulk_edit_selected_issues: 批量修改选中的问题 + label_theme: 主题 + label_default: 默认 + label_search_titles_only: 仅在标题中搜索 + label_user_mail_option_all: "收取我的项目的所有通知" + #huang + label_user_edit: "修改资料" + label_user_info: "个人简介" #huang 添加 + label_user_watcher: "关注" # huang添加的 + label_user_commits: "代码提交" + label_user_watchered: "被关注" # huang添加的 + label_user_newfeedback: "留言" ## huang添加的 + #。。 + label_user_mail_option_selected: "收取选中项目的所有通知..." + label_user_mail_option_none: "不收取任何通知" + label_user_mail_option_only_my_events: "只收取我跟踪或参与的项目的通知" + label_user_mail_option_only_assigned: "只收取分配给我的" + label_user_mail_option_only_owner: 只收取由我创建的 + label_user_mail_no_self_notified: "不要发送对我自己提交的修改的通知" + label_registration_activation_by_email: 通过邮件认证激活帐号 + label_registration_manual_activation: 手动激活帐号 + label_registration_automatic_activation: 自动激活帐号 + label_display_per_page: "每页显示:%{value}" + label_age: 提交时间 + label_change_properties: 修改属性 + label_general: 一般 + label_more: 更多 + label_scm: SCM + label_plugins: 插件 + label_ldap_authentication: LDAP 认证 + label_downloads_abbr: D/L + label_optional_description: 可选的描述 + label_add_another_file: 添加其它文件 + label_preferences: 首选项 + label_chronological_order: 按时间顺序 + label_reverse_chronological_order: 按时间顺序(倒序) + label_planning: 计划 + label_incoming_emails: 接收邮件 + label_generate_key: 生成一个key + label_issue_watchers: 跟踪者 + label_example: 示例 + label_display: 显示 + label_sort: 排序 + label_ascending: 升序 + label_descending: 降序 + label_date_from_to: 从 %{start} 到 %{end} + label_wiki_content_added: Wiki 页面已添加 + label_wiki_content_updated: Wiki 页面已更新 + label_group: 组 + label_group_plural: 组 + label_group_new: 新建组 + label_time_entry_plural: 耗时 + label_version_sharing_none: 不共享 + label_version_sharing_descendants: 与子项目共享 + label_version_sharing_hierarchy: 与项目继承层次共享 + label_version_sharing_tree: 与项目树共享 + label_version_sharing_system: 与所有项目共享 + label_update_issue_done_ratios: 更新问题的完成度 + label_copy_source: 源 + label_copy_target: 目标 + label_copy_same_as_target: 与目标一致 + label_display_used_statuses_only: 只显示被此跟踪标签使用的状态 + label_api_access_key: API访问键 + label_missing_api_access_key: 缺少API访问键 + label_api_access_key_created_on: API访问键是在 %{value} 之前建立的 + label_profile: 简介 + label_subtask_plural: 子任务 + label_project_copy_notifications: 复制项目时发送邮件通知 + label_principal_search: "搜索用户或组:" + label_user_search: "搜索用户:" + + button_login: 登录 + button_submit: 提交 + button_save: 保存 + button_check_all: 全选 + button_uncheck_all: 清除 + button_delete: 删除 + button_create: 创建 + button_create_and_continue: 创建并继续 + button_test: 测试 + button_edit: 编辑 + button_edit_associated_wikipage: "编辑相关wiki页面: %{page_title}" + button_add: 新增 + button_change: 修改 + button_apply: 应用 + button_clear: 清除 + button_lock: 锁定 + button_unlock: 解锁 + button_download: 下载 + button_list: 列表 + button_view: 查看 + button_move: 移动 + button_move_and_follow: 移动并转到新问题 + button_back: 返回 + button_cancel: 取消 + button_activate: 激活 + button_sort: 排序 + button_log_time: 登记工时 + button_rollback: 恢复到这个版本 + button_watch: 跟踪 + button_unwatch: 取消跟踪 + button_reply: 回复 + button_archive: 存档 + button_unarchive: 取消存档 + button_reset: 重置 + button_rename: 重命名/重定向 + button_change_password: 修改密码 + button_copy: 复制 + button_copy_and_follow: 复制并转到新问题 + button_annotate: 追溯 + button_update: 更新 + button_configure: 配置 + button_quote: 引用 + button_duplicate: 副本 + button_show: 显示 + + status_active: 活动的 + status_registered: 已注册 + status_locked: 已锁定 + + version_status_open: 打开 + version_status_locked: 锁定 + version_status_closed: 关闭 + + field_active: 活动 + + text_select_mail_notifications: 选择需要发送邮件通知的动作 + text_regexp_info: 例如:^[A-Z0-9]+$ + text_min_max_length_info: 0 表示没有限制 + text_project_destroy_confirmation: 您确信要删除这个项目以及所有相关的数据吗? + text_subprojects_destroy_warning: "以下子项目也将被同时删除:%{value}" + text_workflow_edit: 选择角色和跟踪标签来编辑工作流程 + text_are_you_sure: 您确定? + text_journal_changed: "%{label} 从 %{old} 变更为 %{new}" + text_journal_set_to: "%{label} 被设置为 %{value}" + text_journal_deleted: "%{label} 已删除 (%{old})" + text_journal_added: "%{label} %{value} 已添加" + text_tip_issue_begin_day: 今天开始的任务 + text_tip_issue_end_day: 今天结束的任务 + text_tip_issue_begin_end_day: 今天开始并结束的任务 + text_caracters_maximum: "最多 %{count} 个字符。" + text_caracters_minimum: "至少需要 %{count} 个字符。" + text_length_between: "长度必须在 %{min} 到 %{max} 个字符之间。" + text_tracker_no_workflow: 此跟踪标签未定义工作流程 + text_unallowed_characters: 非法字符 + text_comma_separated: 可以使用多个值(用逗号,分开)。 + text_line_separated: 可以使用多个值(每行一个值)。 + text_issues_ref_in_commit_messages: 在提交信息中引用和解决问题 + text_issue_added: "问题 %{id} 已由 %{author} 提交。" + text_issue_updated: "问题 %{id} 已由 %{author} 更新。" + text_wiki_destroy_confirmation: 您确定要删除这个 wiki 及其所有内容吗? + text_issue_category_destroy_question: "有一些问题(%{count} 个)属于此类别。您想进行哪种操作?" + text_issue_category_destroy_assignments: 删除问题的所属类别(问题变为无类别) + text_issue_category_reassign_to: 为问题选择其它类别 + text_user_mail_option: "对于没有选中的项目,您将只会收到您跟踪或参与的项目的通知(比如说,您是问题的报告者, 或被指派解决此问题)。" + text_no_configuration_data: "角色、跟踪标签、问题状态和工作流程还没有设置。\n强烈建议您先载入默认设置,然后在此基础上进行修改。" + text_load_default_configuration: 载入默认设置 + text_status_changed_by_changeset: "已应用到变更列表 %{value}." + text_time_logged_by_changeset: "已应用到修订版本 %{value}." + text_issues_destroy_confirmation: '您确定要删除选中的问题吗?' + text_select_project_modules: '请选择此项目可以使用的模块:' + text_default_administrator_account_changed: 默认的管理员帐号已改变 + text_file_repository_writable: 附件路径可写 + text_plugin_assets_writable: 插件的附件路径可写 + text_rmagick_available: RMagick 可用(可选的) + text_destroy_time_entries_question: 您要删除的问题已经上报了 %{hours} 小时的工作量。您想进行那种操作? + text_destroy_time_entries: 删除上报的工作量 + text_assign_time_entries_to_project: 将已上报的工作量提交到项目中 + text_reassign_time_entries: '将已上报的工作量指定到此问题:' + text_user_wrote: "%{value} 写到:" + text_enumeration_destroy_question: "%{count} 个对象被关联到了这个枚举值。" + text_enumeration_category_reassign_to: '将它们关联到新的枚举值:' + text_email_delivery_not_configured: "邮件参数尚未配置,因此邮件通知功能已被禁用。\n请在config/configuration.yml中配置您的SMTP服务器信息并重新启动以使其生效。" + text_repository_usernames_mapping: "选择或更新与版本库中的用户名对应的Redmine用户。\n版本库中与Redmine中的同名用户将被自动对应。" + text_diff_truncated: '... 差别内容超过了可显示的最大行数并已被截断' + text_custom_field_possible_values_info: '每项数值一行' + text_wiki_page_destroy_question: 此页面有 %{descendants} 个子页面和下级页面。您想进行那种操作? + text_wiki_page_nullify_children: 将子页面保留为根页面 + text_wiki_page_destroy_children: 删除子页面及其所有下级页面 + text_wiki_page_reassign_children: 将子页面的上级页面设置为 + text_own_membership_delete_confirmation: 你正在删除你现有的某些或全部权限,如果这样做了你可能将会再也无法编辑该项目了。你确定要继续吗? + text_zoom_in: 放大 + text_zoom_out: 缩小 + + default_role_manager: 管理人员 + default_role_developer: 开发人员 + default_role_reporter: 报告人员 + default_tracker_bug: 错误 + default_tracker_feature: 功能 + default_tracker_support: 支持 + default_issue_status_new: 新建 + default_issue_status_in_progress: 进行中 + default_issue_status_resolved: 已解决 + default_issue_status_feedback: 反馈 + default_issue_status_closed: 已关闭 + default_issue_status_rejected: 已拒绝 + default_doc_category_user: 用户文档 + default_doc_category_tech: 技术文档 + default_priority_low: 低 + default_priority_normal: 普通 + default_priority_high: 高 + default_priority_urgent: 紧急 + default_priority_immediate: 立刻 + default_activity_design: 设计 + default_activity_development: 开发 + + enumeration_issue_priorities: 问题优先级 + enumeration_doc_categories: 文档类别 + enumeration_activities: 活动(时间跟踪) + enumeration_system_activity: 系统活动 + + field_warn_on_leaving_unsaved: 当离开未保存内容的页面时,提示我 + text_warn_on_leaving_unsaved: 若离开当前页面,则该页面内未保存的内容将丢失。 + label_my_queries: 我的自定义查询 + text_journal_changed_no_detail: "%{label} 已更新。" + label_news_comment_added: 添加到新闻的评论 + button_expand_all: 展开所有 + button_collapse_all: 合拢所有 + label_additional_workflow_transitions_for_assignee: 当用户是问题的分配对象时所允许的问题状态转换 + label_additional_workflow_transitions_for_author: 当用户是问题作者时所允许的问题状态转换 + label_bulk_edit_selected_time_entries: 批量修改选定的时间条目 + text_time_entries_destroy_confirmation: 是否确定要删除选定的时间条目? + label_role_anonymous: Anonymous + label_role_non_member: Non member + label_issue_note_added: 问题备注已添加 + label_issue_status_updated: 问题状态更新 + label_issue_priority_updated: 问题优先级更新 + label_issues_visibility_own: 创建或分配给用户的问题 + field_issues_visibility: 问题可见 + label_issues_visibility_all: 全部问题 + permission_set_own_issues_private: 设置自己的问题为公开或私有 + field_is_private: 私有 + permission_set_issues_private: 设置问题为公开或私有 + label_issues_visibility_public: 全部非私有问题 + text_issues_destroy_descendants_confirmation: 此操作同时会删除 %{count} 个子任务。 + + field_commit_logs_encoding: 提交注释的编码 + field_scm_path_encoding: 路径编码 + text_scm_path_encoding_note: "默认: UTF-8" + field_path_to_repository: 库路径 + field_root_directory: 根目录 + field_cvs_module: CVS Module + field_cvsroot: CVSROOT + text_mercurial_repository_note: 本地库 (e.g. /hgrepo, c:\hgrepo) + text_scm_command: 命令 + text_scm_command_version: 版本 + label_git_report_last_commit: 报告最后一次文件/目录提交 + text_scm_config: 您可以在config/configuration.yml中配置您的SCM命令。 请在编辑后,重启Redmine应用。 + text_scm_command_not_available: Scm命令不可用。 请检查管理面板的配置。 + text_git_repository_note: 库中无内容。(e.g. /gitrepo, c:\gitrepo) + notice_issue_successful_create: 问题 %{id} 已创建。 + label_between: 介于 + setting_issue_group_assignment: 允许问题被分配给组 + label_diff: diff + description_query_sort_criteria_direction: 排序方式 + description_project_scope: 搜索范围 + description_filter: 过滤器 + description_user_mail_notification: 邮件通知设置 + description_date_from: 输入开始日期 + description_message_content: 信息内容 + description_available_columns: 备选列 + description_date_range_interval: 按开始日期和结束日期选择范围 + description_issue_category_reassign: 选择问题类别 + description_search: 搜索字段 + description_notes: 批注 + description_date_range_list: 从列表中选择范围 + description_choose_project: 项目 + description_date_to: 输入结束日期 + description_query_sort_criteria_attribute: 排序方式 + description_wiki_subpages_reassign: 选择父页面 + description_selected_columns: 已选列 + label_parent_revision: 父修订 + label_child_revision: 子修订 + error_scm_annotate_big_text_file: 输入文本内容超长,无法输入。 + setting_default_issue_start_date_to_creation_date: 使用当前日期作为新问题的开始日期 + button_edit_section: 编辑此区域 + setting_repositories_encodings: 附件和版本库编码 + description_all_columns: 所有列 + button_export: 导出 + label_export_options: "%{export_format} 导出选项" + error_attachment_too_big: 该文件无法上传。超过文件大小限制 (%{max_size}) + notice_failed_to_save_time_entries: "无法保存下列所选取的 %{total} 个项目中的 %{count} 工时: %{ids}。" + label_x_issues: + zero: 0 问题 + one: 1 问题 + other: "%{count} 问题" + label_repository_new: 新建版本库 + field_repository_is_default: 主版本库 + label_copy_attachments: 复制附件 + label_item_position: "%{position}/%{count}" + label_completed_versions: 已完成的版本 + text_project_identifier_info: 仅小写字母(a-z)、数字、破折号(-)和下划线(_)可以使用。
    一旦保存,标识无法修改。 + field_multiple: 多重取值 + setting_commit_cross_project_ref: 允许引用/修复所有其他项目的问题 + text_issue_conflict_resolution_add_notes: 添加说明并取消我的其他变更处理。 + text_issue_conflict_resolution_overwrite: 直接套用我的变更 (先前的说明将被保留,但是某些变更内容可能会被覆盖) + notice_issue_update_conflict: 当您正在编辑这个问题的时候,它已经被其他人抢先一步更新过了。 + text_issue_conflict_resolution_cancel: 取消我所有的变更并重新刷新显示 %{link} 。 + permission_manage_related_issues: 相关问题管理 + field_auth_source_ldap_filter: LDAP 过滤器 + label_search_for_watchers: 通过查找方式添加跟踪者 + notice_account_deleted: 您的账号已被永久删除(账号已无法恢复)。 + setting_unsubscribe: 允许用户退订 + button_delete_my_account: 删除我的账号 + text_account_destroy_confirmation: |- + 确定继续处理? + 您的账号一旦删除,将无法再次激活使用。 + error_session_expired: 您的会话已过期。请重新登陆。 + text_session_expiration_settings: "警告: 更改这些设置将会使包括你在内的当前会话失效。" + setting_session_lifetime: 会话最大有效时间 + setting_session_timeout: 会话闲置超时 + label_session_expiration: 会话过期 + permission_close_project: 关闭/重开项目 + label_show_closed_projects: 查看已关闭的项目 + button_close: 关闭 + button_reopen: 重开 + project_status_active: 已激活 + project_status_closed: 已关闭 + project_status_archived: 已存档 + text_project_closed: 当前项目已被关闭。当前项目只读。 + notice_user_successful_create: 用户 %{id} 已创建。 + field_core_fields: 标准字段 + field_timeout: 超时 (秒) + setting_thumbnails_enabled: 显示附件略缩图 + setting_thumbnails_size: 略缩图尺寸 (像素) + label_status_transitions: 状态转换 + label_fields_permissions: 字段权限 + label_readonly: 只读 + label_required: 必填 + text_repository_identifier_info: 仅小写字母(a-z)、数字、破折号(-)和下划线(_)可以使用。
    一旦保存,标识无法修改。 + field_board_parent: 父论坛 + label_attribute_of_project: 项目 %{name} + label_attribute_of_author: 作者 %{name} + label_attribute_of_assigned_to: 分配给 %{name} + label_attribute_of_fixed_version: 目标版本 %{name} + label_copy_subtasks: 复制子任务 + label_copied_to: 复制到 + label_copied_from: 复制于 + label_any_issues_in_project: 项目内任意问题 + label_any_issues_not_in_project: 项目外任意问题 + field_private_notes: 私有注解 + permission_view_private_notes: 查看私有注解 + permission_set_notes_private: 设置为私有注解 + label_no_issues_in_project: 项目内无相关问题 + label_any: 全部 + label_last_n_weeks: 上 %{count} 周前 + setting_cross_project_subtasks: 支持跨项目子任务 + label_cross_project_descendants: 与子项目共享 + label_cross_project_tree: 与项目树共享 + label_cross_project_hierarchy: 与项目继承层次共享 + label_cross_project_system: 与所有项目共享 + button_hide: 隐藏 + setting_non_working_week_days: Non-working days + label_in_the_next_days: in the next + label_in_the_past_days: in the past + label_attribute_of_user: User's %{name} + text_turning_multiple_off: If you disable multiple values, multiple values will be + removed in order to preserve only one value per item. + label_attribute_of_issue: Issue's %{name} + permission_add_documents: Add documents + permission_edit_documents: Edit documents + permission_delete_documents: Delete documents + label_gantt_progress_line: Progress line + setting_jsonp_enabled: Enable JSONP support + field_inherit_members: Inherit members + field_closed_on: Closed + setting_default_projects_tracker_ids: Default trackers for new projects + label_total_time: 合计 + + label_create_time: 创建时间 #Customer added! + label_current_contributors: 位当前贡献者 + label_lines_of_code: 行代码 + label_since_last_commits: 距离上次提交时间 + label_users_on_trustie: 用户 + label_front: 第一页 + label_commit_on: 次提交 + label_follow_people: 个关注者 + label_member_since: 加入trustie2 + label_contribute_to: 参与了%{project_count}个项目: + label_total_commit: 共%{total_commit}次提交 + label_upload_profile: 上传头像 + label_type_as: 类型为 + label_status_as: 状态为 + label_priority_as: 优先级为 + label_member_list: 成员列表 + + #added by liuping + button_unfollow: 取消关注 + button_follow: 关注 + label_delete_confirm: 确认删除? + label_more_tags: 更多 + #fq + button_leave_meassge: 留言 + label_leave_message_to: 给用户 %{name}留言 + label_leave_message: 留言内容 + label_message: 留言板 + field_add: 添加于 %{time} 之前 + button_more: 更多 + label_user_response: 用户反馈 + label_bidding_project: 应标项目 + button_bidding: 我要应标 + diff --git a/config/preinitializer.rb b/config/preinitializer.rb new file mode 100644 index 00000000..90f789c6 --- /dev/null +++ b/config/preinitializer.rb @@ -0,0 +1,20 @@ +begin + require "rubygems" + require "bundler" +rescue LoadError + $stderr.puts "Redmine requires Bundler. Please install it with `gem install bundler`." + exit 1 +end + +if Gem::Version.new(Bundler::VERSION) < Gem::Version.new("1.0.21") + $stderr.puts "Redmine requires Bundler 1.0.21 (you're using #{Bundler::VERSION}).\nPlease install a newer version with `gem install bundler`." + exit 1 +end + +begin + ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", __FILE__) + Bundler.setup +rescue Bundler::GemNotFound + $stderr.puts "Some gems may need to be installed or updated.\nPlease run `bundle install --without development test`." + exit 1 +end diff --git a/config/routes.rb b/config/routes.rb new file mode 100644 index 00000000..51daeb28 --- /dev/null +++ b/config/routes.rb @@ -0,0 +1,425 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +RedmineApp::Application.routes.draw do + get "tags/index" + + get "tags/show" + + root :to => 'welcome#index', :as => 'home' + + + match 'login', :to => 'account#login', :as => 'signin', :via => [:get, :post] + match 'logout', :to => 'account#logout', :as => 'signout', :via => [:get, :post] + match 'account/register', :to => 'account#register', :via => [:get, :post], :as => 'register' + match 'account/lost_password', :to => 'account#lost_password', :via => [:get, :post], :as => 'lost_password' + match 'account/activate', :to => 'account#activate', :via => :get + + match '/news/preview', :controller => 'previews', :action => 'news', :as => 'preview_news', :via => [:get, :post, :put] + match '/issues/preview/new/:project_id', :to => 'previews#issue', :as => 'preview_new_issue', :via => [:get, :post, :put] + match '/issues/preview/edit/:id', :to => 'previews#issue', :as => 'preview_edit_issue', :via => [:get, :post, :put] + match '/issues/preview', :to => 'previews#issue', :as => 'preview_issue', :via => [:get, :post, :put] + + match 'projects/:id/wiki', :to => 'wikis#edit', :via => :post + match 'projects/:id/wiki/destroy', :to => 'wikis#destroy', :via => [:get, :post] + + match 'boards/:board_id/topics/new', :to => 'messages#new', :via => [:get, :post], :as => 'new_board_message' + get 'boards/:board_id/topics/:id', :to => 'messages#show', :as => 'board_message' + match 'boards/:board_id/topics/quote/:id', :to => 'messages#quote', :via => [:get, :post] + get 'boards/:board_id/topics/:id/edit', :to => 'messages#edit' + + post 'boards/:board_id/topics/preview', :to => 'messages#preview', :as => 'preview_board_message' + post 'boards/:board_id/topics/:id/replies', :to => 'messages#reply' + post 'boards/:board_id/topics/:id/edit', :to => 'messages#edit' + post 'boards/:board_id/topics/:id/destroy', :to => 'messages#destroy' + + # Misc issue routes. TODO: move into resources + match '/issues/auto_complete', :to => 'auto_completes#issues', :via => :get, :as => 'auto_complete_issues' + match '/issues/context_menu', :to => 'context_menus#issues', :as => 'issues_context_menu', :via => [:get, :post] + match '/issues/changes', :to => 'journals#index', :as => 'issue_changes', :via => :get + match '/issues/:id/quoted', :to => 'journals#new', :id => /\d+/, :via => :post, :as => 'quoted_issue' + + match '/journals/diff/:id', :to => 'journals#diff', :id => /\d+/, :via => :get + match '/journals/edit/:id', :to => 'journals#edit', :id => /\d+/, :via => [:get, :post] + + get '/projects/:project_id/issues/gantt', :to => 'gantts#show', :as => 'project_gantt' + get '/issues/gantt', :to => 'gantts#show' + + get '/projects/:project_id/issues/calendar', :to => 'calendars#show', :as => 'project_calendar' + get '/issues/calendar', :to => 'calendars#show' + + get 'projects/:id/issues/report', :to => 'reports#issue_report', :as => 'project_issues_report' + get 'projects/:id/issues/report/:detail', :to => 'reports#issue_report_details', :as => 'project_issues_report_details' + + #added by young + resources :users do + member do + match 'user_projects', :to => 'users#user_projects', :via => :get, :as => "user_projects" + match 'user_activities', :to => 'users#show', :via => :get, :as => "user_activities" + match 'user_newfeedback', :to => 'users#user_newfeedback', :via => :get, :as => "user_newfeedback" + end + end +#end + match 'my/account', :controller => 'my', :action => 'account', :via => [:get, :post] + match 'my/account/destroy', :controller => 'my', :action => 'destroy', :via => [:get, :post] + match 'my/page', :controller => 'my', :action => 'page', :via => :get + match 'my', :controller => 'my', :action => 'index', :via => :get # Redirects to my/page + match 'my/reset_rss_key', :controller => 'my', :action => 'reset_rss_key', :via => :post + match 'my/reset_api_key', :controller => 'my', :action => 'reset_api_key', :via => :post + match 'my/password', :controller => 'my', :action => 'password', :via => [:get, :post] + match 'my/page_layout', :controller => 'my', :action => 'page_layout', :via => :get + match 'my/add_block', :controller => 'my', :action => 'add_block', :via => :post + match 'my/remove_block', :controller => 'my', :action => 'remove_block', :via => :post + match 'my/order_blocks', :controller => 'my', :action => 'order_blocks', :via => :post + + resources :users + match 'users/:id/memberships/:membership_id', :to => 'users#edit_membership', :via => :put, :as => 'user_membership' + match 'users/:id/memberships/:membership_id', :to => 'users#destroy_membership', :via => :delete + match 'users/:id/memberships', :to => 'users#edit_membership', :via => :post, :as => 'user_memberships' + ################# added by william + match 'users/tag_save', :to => 'users#tag_save', :via => :post, :as => 'tag' + + post 'watchers/watch', :to => 'watchers#watch', :as => 'watch' + delete 'watchers/watch', :to => 'watchers#unwatch' + get 'watchers/new', :to => 'watchers#new' + post 'watchers', :to => 'watchers#create' + post 'watchers/append', :to => 'watchers#append' + delete 'watchers', :to => 'watchers#destroy' + get 'watchers/autocomplete_for_user', :to => 'watchers#autocomplete_for_user' + # Specific routes for issue watchers API + post 'issues/:object_id/watchers', :to => 'watchers#create', :object_type => 'issue' + delete 'issues/:object_id/watchers/:user_id' => 'watchers#destroy', :object_type => 'issue' + + + resources :projects do + member do + get 'settings(/:tab)', :action => 'settings', :as => 'settings' + get 'show', :action => 'show', :as => 'project_show' + get 'activity', :controller => 'activities', :action => 'index', :as => 'activity' + get 'repository', :controller => 'repositories', :action => 'show', :repository_id => nil, :path => nil, :rev => nil, :as => 'repository' + #by young + get 'member', :controller => 'projects', :action => 'member', :as => 'member' + get 'focus', :action => 'focus', :as => 'focus' + get 'investor', :action => 'investor', :as => 'investor' +# get 'issue', :action =>'issue', :as => 'issue' + get 'mission', :action => 'mission', :as => 'mission' + get 'on', :action => 'on', :as => 'on' + get 'file', :action => 'file', :as => 'file' + #end + + post 'modules' + post 'archive' + post 'unarchive' + post 'close' + post 'reopen' + match 'copy', :via => [:get, :post] + end + +#by young + match '/member', :controller => 'projects', :action => 'member', :as => 'member', :via => :get + match '/focus', :controller => 'projects', :action => 'focus', :as => 'focus', :via => :get + match '/mission', :controller => 'projects', :action => 'mission', :as => 'mission', :via => :get + match '/on', :controller => 'projects', :action => 'on', :as => 'on', :via => :get + match '/settings(/:tab)', :controller => 'projects', :action => 'settings', :as => 'settings', :via => :get + match '/file', :controller => 'projects', :action => 'file', :as => 'file', :via => :get + match '/investor', :controller => 'projects', :action => 'investor', :as => 'investor', :via => :get + + match '/activity', :controller => 'activities', :action => 'index', :as => 'activity', :via => :get + match '/repository', :controller => 'repositories', :action => 'show', :repository_id => nil, :path => nil, :rev => nil, :as => 'repository', :via => :get + match '/', :controller => 'projects', :action => 'show', :as => 'project_show', :via => :get + get 'projects/:project_id/show', :to => 'projects#show', :as => 'project_show' + get 'projects/:project_id/repository', :to => 'repositories#show', :as => 'project_repository' + +# match '/show', :controller => 'projects', :action => 'show', :as => 'project_show', :via => :get + +#end + + resources :memberships, :shallow => true, :controller => 'members', :only => [:index, :show, :new, :create, :update, :destroy] do + collection do + get 'autocomplete' + end + end + + resource :enumerations, :controller => 'project_enumerations', :only => [:update, :destroy] + + get 'issues/:copy_from/copy', :to => 'issues#new', :as => 'copy_issue' + resources :issues, :only => [:index, :new, :create] do + resources :time_entries, :controller => 'timelog' do + collection do + get 'report' + end + end + end + # issue form update + match 'issues/update_form', :controller => 'issues', :action => 'update_form', :via => [:put, :post], :as => 'issue_form' + + resources :files, :only => [:index, :new, :create] + + resources :versions, :except => [:index, :show, :edit, :update, :destroy] do + collection do + put 'close_completed' + end + end + get 'versions.:format', :to => 'versions#index' + get 'roadmap', :to => 'versions#index', :format => false + get 'versions', :to => 'versions#index' + + resources :news, :except => [:show, :edit, :update, :destroy] + resources :time_entries, :controller => 'timelog' do + get 'report', :on => :collection + end + resources :queries, :only => [:new, :create] + resources :issue_categories, :shallow => true + resources :documents, :except => [:show, :edit, :update, :destroy] + resources :boards + resources :repositories, :shallow => true, :except => [:index, :show] do + member do + match 'committers', :via => [:get, :post] + end + end + + match 'wiki/index', :controller => 'wiki', :action => 'index', :via => :get + resources :wiki, :except => [:index, :new, :create], :as => 'wiki_page' do + member do + get 'rename' + post 'rename' + get 'history' + get 'diff' + match 'preview', :via => [:post, :put] + post 'protect' + post 'add_attachment' + end + collection do + get 'export' + get 'date_index' + end + end + match 'wiki', :controller => 'wiki', :action => 'show', :via => :get + get 'wiki/:id/:version', :to => 'wiki#show', :constraints => {:version => /\d+/} + delete 'wiki/:id/:version', :to => 'wiki#destroy_version' + get 'wiki/:id/:version/annotate', :to => 'wiki#annotate' + get 'wiki/:id/:version/diff', :to => 'wiki#diff' + end + + resources :issues do + collection do + match 'bulk_edit', :via => [:get, :post] + post 'bulk_update' + end + resources :time_entries, :controller => 'timelog' do + collection do + get 'report' + end + end + resources :relations, :shallow => true, :controller => 'issue_relations', :only => [:index, :show, :create, :destroy] + end + match '/issues', :controller => 'issues', :action => 'destroy', :via => :delete + + resources :queries, :except => [:show] + + resources :news, :only => [:index, :show, :edit, :update, :destroy] + match '/news/:id/comments', :to => 'comments#create', :via => :post + match '/news/:id/comments/:comment_id', :to => 'comments#destroy', :via => :delete + + resources :versions, :only => [:show, :edit, :update, :destroy] do + post 'status_by', :on => :member + end + + resources :documents, :only => [:show, :edit, :update, :destroy] do + post 'add_attachment', :on => :member + end + + match '/time_entries/context_menu', :to => 'context_menus#time_entries', :as => :time_entries_context_menu, :via => [:get, :post] + + resources :time_entries, :controller => 'timelog', :except => :destroy do + collection do + get 'report' + get 'bulk_edit' + post 'bulk_update' + end + end + match '/time_entries/:id', :to => 'timelog#destroy', :via => :delete, :id => /\d+/ + # TODO: delete /time_entries for bulk deletion + match '/time_entries/destroy', :to => 'timelog#destroy', :via => :delete + + get 'projects/:id/activity', :to => 'activities#index' + get 'projects/:id/activity.:format', :to => 'activities#index' + get 'activity', :to => 'activities#index' + + # repositories routes + get 'projects/:id/repository/:repository_id/statistics', :to => 'repositories#stats' + get 'projects/:id/repository/:repository_id/graph', :to => 'repositories#graph' + + get 'projects/:id/repository/:repository_id/changes(/*path(.:ext))', + :to => 'repositories#changes' + + get 'projects/:id/repository/:repository_id/revisions/:rev', :to => 'repositories#revision' + get 'projects/:id/repository/:repository_id/revision', :to => 'repositories#revision' + post 'projects/:id/repository/:repository_id/revisions/:rev/issues', :to => 'repositories#add_related_issue' + delete 'projects/:id/repository/:repository_id/revisions/:rev/issues/:issue_id', :to => 'repositories#remove_related_issue' + get 'projects/:id/repository/:repository_id/revisions', :to => 'repositories#revisions' + get 'projects/:id/repository/:repository_id/revisions/:rev/:action(/*path(.:ext))', + :controller => 'repositories', + :format => false, + :constraints => { + :action => /(browse|show|entry|raw|annotate|diff)/, + :rev => /[a-z0-9\.\-_]+/ + } + + get 'projects/:id/repository/statistics', :to => 'repositories#stats' + get 'projects/:id/repository/graph', :to => 'repositories#graph' + + get 'projects/:id/repository/changes(/*path(.:ext))', + :to => 'repositories#changes' + + get 'projects/:id/repository/revisions', :to => 'repositories#revisions' + get 'projects/:id/repository/revisions/:rev', :to => 'repositories#revision' + get 'projects/:id/repository/revision', :to => 'repositories#revision' + post 'projects/:id/repository/revisions/:rev/issues', :to => 'repositories#add_related_issue' + delete 'projects/:id/repository/revisions/:rev/issues/:issue_id', :to => 'repositories#remove_related_issue' + get 'projects/:id/repository/revisions/:rev/:action(/*path(.:ext))', + :controller => 'repositories', + :format => false, + :constraints => { + :action => /(browse|show|entry|raw|annotate|diff)/, + :rev => /[a-z0-9\.\-_]+/ + } + get 'projects/:id/repository/:repository_id/:action(/*path(.:ext))', + :controller => 'repositories', + :action => /(browse|show|entry|raw|changes|annotate|diff)/ + get 'projects/:id/repository/:action(/*path(.:ext))', + :controller => 'repositories', + :action => /(browse|show|entry|raw|changes|annotate|diff)/ + + get 'projects/:id/repository/:repository_id', :to => 'repositories#show', :path => nil + get 'projects/:id/repository', :to => 'repositories#show', :path => nil + + # additional routes for having the file name at the end of url + get 'attachments/:id/:filename', :to => 'attachments#show', :id => /\d+/, :filename => /.*/, :as => 'named_attachment' + get 'attachments/download/:id/:filename', :to => 'attachments#download', :id => /\d+/, :filename => /.*/, :as => 'download_named_attachment' + get 'attachments/download/:id', :to => 'attachments#download', :id => /\d+/ + get 'attachments/thumbnail/:id(/:size)', :to => 'attachments#thumbnail', :id => /\d+/, :size => /\d+/, :as => 'thumbnail' + resources :attachments, :only => [:show, :destroy] + + resources :groups do + member do + get 'autocomplete_for_user' + end + end + + match 'groups/:id/users', :controller => 'groups', :action => 'add_users', :id => /\d+/, :via => :post, :as => 'group_users' + match 'groups/:id/users/:user_id', :controller => 'groups', :action => 'remove_user', :id => /\d+/, :via => :delete, :as => 'group_user' + match 'groups/destroy_membership/:id', :controller => 'groups', :action => 'destroy_membership', :id => /\d+/, :via => :post + match 'groups/edit_membership/:id', :controller => 'groups', :action => 'edit_membership', :id => /\d+/, :via => :post + + resources :trackers, :except => :show do + collection do + match 'fields', :via => [:get, :post] + end + end + resources :issue_statuses, :except => :show do + collection do + post 'update_issue_done_ratio' + end + end + resources :custom_fields, :except => :show + resources :roles do + collection do + match 'permissions', :via => [:get, :post] + end + end + resources :enumerations, :except => :show + match 'enumerations/:type', :to => 'enumerations#index', :via => :get + + get 'projects/:id/search', :controller => 'search', :action => 'index' + get 'search', :controller => 'search', :action => 'index' + + match 'mail_handler', :controller => 'mail_handler', :action => 'index', :via => :post + + match 'admin', :controller => 'admin', :action => 'index', :via => :get + match 'admin/projects', :controller => 'admin', :action => 'projects', :via => :get + match 'admin/plugins', :controller => 'admin', :action => 'plugins', :via => :get + match 'admin/info', :controller => 'admin', :action => 'info', :via => :get + match 'admin/test_email', :controller => 'admin', :action => 'test_email', :via => :get + match 'admin/default_configuration', :controller => 'admin', :action => 'default_configuration', :via => :post + + resources :auth_sources do + member do + get 'test_connection', :as => 'try_connection' + end + collection do + get 'autocomplete_for_new_user' + end + end + + match 'workflows', :controller => 'workflows', :action => 'index', :via => :get + match 'workflows/edit', :controller => 'workflows', :action => 'edit', :via => [:get, :post] + match 'workflows/permissions', :controller => 'workflows', :action => 'permissions', :via => [:get, :post] + match 'workflows/copy', :controller => 'workflows', :action => 'copy', :via => [:get, :post] + match 'settings', :controller => 'settings', :action => 'index', :via => :get + match 'settings/edit', :controller => 'settings', :action => 'edit', :via => [:get, :post] + match 'settings/plugin/:id', :controller => 'settings', :action => 'plugin', :via => [:get, :post], :as => 'plugin_settings' + + match 'sys/projects', :to => 'sys#projects', :via => :get + match 'sys/projects/:id/repository', :to => 'sys#create_project_repository', :via => :post + match 'sys/fetch_changesets', :to => 'sys#fetch_changesets', :via => :get + + match 'uploads', :to => 'attachments#upload', :via => :post + # Added by Tao + match 'upload_avatar', :to => 'avatar#upload', :via => :post + # Endof Tao's code + get 'robots.txt', :to => 'welcome#robots' + + Dir.glob File.expand_path("plugins/*", Rails.root) do |plugin_dir| + file = File.join(plugin_dir, "config/routes.rb") + if File.exists?(file) + begin + instance_eval File.read(file) + rescue Exception => e + puts "An error occurred while loading the routes definition of #{File.basename(plugin_dir)} plugin (#{file}): #{e.message}." + exit 1 + end + end + end + + ##############测试留言功能 fq + post 'words/new', :to => 'words#new' + post 'words/create', :to => 'words#create' + post 'words/append', :to => 'words#append' + delete 'words/destroy', :to => 'words#destroy' + get 'words/more', :to => 'words#more' + get 'words/back', :to=> 'words#back' + ############## + post 'bids/create', :to => 'bids#create' + delete 'bids/destroy', :to => 'bids#destroy' + get 'bids/more', :to => 'bids#more' + get 'bids/back', :to=> 'bids#back' + match 'bids/:bid_id/show_project', :controller => 'bids', :action => 'show_project' + match 'bids/:bid_id/add', :controller => 'bids', :action => 'add' + match 'bids/new_bid', :controller => 'bids', :action => 'new_bid' + # added by young + match 'bids', :controller => 'bids', :action => 'index' + + match 'bids/:bid_id/show', :controller => 'bids', :action => 'show' + match 'bids/new', :controller => 'bids', :action => 'new', :via => [:get , :post] + + + ########### added by liuping + match 'tags/add_tag',:to => 'tags#add_tag',:as=>"add_tag" + match 'tags/delete_tag',:to => 'tags#delete_tag',:as=>"add_tag" + +end diff --git a/config/settings.yml b/config/settings.yml new file mode 100644 index 00000000..384e7d07 --- /dev/null +++ b/config/settings.yml @@ -0,0 +1,238 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + +# DO NOT MODIFY THIS FILE !!! +# Settings can be defined through the application in Admin -> Settings + +app_title: + default: Redmine +app_subtitle: + default: Project management +welcome_text: + default: +login_required: + default: 0 +self_registration: + default: '2' +lost_password: + default: 1 +unsubscribe: + default: 1 +password_min_length: + format: int + default: 8 +# Maximum lifetime of user sessions in minutes +session_lifetime: + format: int + default: 0 +# User session timeout in minutes +session_timeout: + format: int + default: 0 +attachment_max_size: + format: int + default: 5120 +issues_export_limit: + format: int + default: 500 +activity_days_default: + format: int + default: 30 +per_page_options: + default: '25,50,100' +mail_from: + default: redmine@example.net +bcc_recipients: + default: 1 +plain_text_mail: + default: 0 +text_formatting: + default: textile +cache_formatted_text: + default: 0 +wiki_compression: + default: "" +default_language: + default: en +host_name: + default: localhost:3000 +protocol: + default: http +feeds_limit: + format: int + default: 15 +gantt_items_limit: + format: int + default: 500 +# Maximum size of files that can be displayed +# inline through the file viewer (in KB) +file_max_size_displayed: + format: int + default: 512 +diff_max_lines_displayed: + format: int + default: 1500 +enabled_scm: + serialized: true + default: + - Subversion + - Darcs + - Mercurial + - Cvs + - Bazaar + - Git +autofetch_changesets: + default: 1 +sys_api_enabled: + default: 0 +sys_api_key: + default: '' +commit_cross_project_ref: + default: 0 +commit_ref_keywords: + default: 'refs,references,IssueID' +commit_fix_keywords: + default: 'fixes,closes' +commit_fix_status_id: + format: int + default: 0 +commit_fix_done_ratio: + default: 100 +commit_logtime_enabled: + default: 0 +commit_logtime_activity_id: + format: int + default: 0 +# autologin duration in days +# 0 means autologin is disabled +autologin: + format: int + default: 0 +# date format +date_format: + default: '' +time_format: + default: '' +user_format: + default: :firstname_lastname + format: symbol +cross_project_issue_relations: + default: 0 +# Enables subtasks to be in other projects +cross_project_subtasks: + default: 'tree' +issue_group_assignment: + default: 0 +default_issue_start_date_to_creation_date: + default: 1 +notified_events: + serialized: true + default: + - issue_added + - issue_updated +mail_handler_body_delimiters: + default: '' +mail_handler_api_enabled: + default: 0 +mail_handler_api_key: + default: +issue_list_default_columns: + serialized: true + default: + - tracker + - status + - priority + - subject + - assigned_to + - updated_on +display_subprojects_issues: + default: 1 +issue_done_ratio: + default: 'issue_field' +default_projects_public: + default: 1 +default_projects_modules: + serialized: true + default: + - issue_tracking + - time_tracking + - news + - documents + - files + - wiki + - repository + - boards + - calendar + - gantt +default_projects_tracker_ids: + serialized: true + default: +# Role given to a non-admin user who creates a project +new_project_user_role_id: + format: int + default: '' +sequential_project_identifiers: + default: 0 +# encodings used to convert repository files content to UTF-8 +# multiple values accepted, comma separated +repositories_encodings: + default: '' +# encoding used to convert commit logs to UTF-8 +commit_logs_encoding: + default: 'UTF-8' +repository_log_display_limit: + format: int + default: 100 +ui_theme: + default: '' +emails_footer: + default: |- + You have received this notification because you have either subscribed to it, or are involved in it. + To change your notification preferences, please click here: http://hostname/my/account +gravatar_enabled: + default: 0 +openid: + default: 0 +gravatar_default: + default: '' +start_of_week: + default: '' +rest_api_enabled: + default: 0 +jsonp_enabled: + default: 0 +default_notification_option: + default: 'only_my_events' +emails_header: + default: '' +thumbnails_enabled: + default: 0 +thumbnails_size: + format: int + default: 100 +non_working_week_days: + serialized: true + default: + - '6' + - '7' + + +#### added by liuping +show_tags_length: + format: int + default: 5 diff --git a/db/development.sqlite3 b/db/development.sqlite3 new file mode 100644 index 00000000..e69de29b diff --git a/db/migrate/001_setup.rb b/db/migrate/001_setup.rb new file mode 100644 index 00000000..f1b9c1ed --- /dev/null +++ b/db/migrate/001_setup.rb @@ -0,0 +1,323 @@ +# Redmine - project management software +# Copyright (C) 2006 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class Setup < ActiveRecord::Migration + + class User < ActiveRecord::Base; end + # model removed + class Permission < ActiveRecord::Base; end + + def self.up + create_table "attachments", :force => true do |t| + t.column "container_id", :integer, :default => 0, :null => false + t.column "container_type", :string, :limit => 30, :default => "", :null => false + t.column "filename", :string, :default => "", :null => false + t.column "disk_filename", :string, :default => "", :null => false + t.column "filesize", :integer, :default => 0, :null => false + t.column "content_type", :string, :limit => 60, :default => "" + t.column "digest", :string, :limit => 40, :default => "", :null => false + t.column "downloads", :integer, :default => 0, :null => false + t.column "author_id", :integer, :default => 0, :null => false + t.column "created_on", :timestamp + end + + create_table "auth_sources", :force => true do |t| + t.column "type", :string, :limit => 30, :default => "", :null => false + t.column "name", :string, :limit => 60, :default => "", :null => false + t.column "host", :string, :limit => 60 + t.column "port", :integer + t.column "account", :string, :limit => 60 + t.column "account_password", :string, :limit => 60 + t.column "base_dn", :string, :limit => 255 + t.column "attr_login", :string, :limit => 30 + t.column "attr_firstname", :string, :limit => 30 + t.column "attr_lastname", :string, :limit => 30 + t.column "attr_mail", :string, :limit => 30 + t.column "onthefly_register", :boolean, :default => false, :null => false + end + + create_table "custom_fields", :force => true do |t| + t.column "type", :string, :limit => 30, :default => "", :null => false + t.column "name", :string, :limit => 30, :default => "", :null => false + t.column "field_format", :string, :limit => 30, :default => "", :null => false + t.column "possible_values", :text + t.column "regexp", :string, :default => "" + t.column "min_length", :integer, :default => 0, :null => false + t.column "max_length", :integer, :default => 0, :null => false + t.column "is_required", :boolean, :default => false, :null => false + t.column "is_for_all", :boolean, :default => false, :null => false + end + + create_table "custom_fields_projects", :id => false, :force => true do |t| + t.column "custom_field_id", :integer, :default => 0, :null => false + t.column "project_id", :integer, :default => 0, :null => false + end + + create_table "custom_fields_trackers", :id => false, :force => true do |t| + t.column "custom_field_id", :integer, :default => 0, :null => false + t.column "tracker_id", :integer, :default => 0, :null => false + end + + create_table "custom_values", :force => true do |t| + t.column "customized_type", :string, :limit => 30, :default => "", :null => false + t.column "customized_id", :integer, :default => 0, :null => false + t.column "custom_field_id", :integer, :default => 0, :null => false + t.column "value", :text + end + + create_table "documents", :force => true do |t| + t.column "project_id", :integer, :default => 0, :null => false + t.column "category_id", :integer, :default => 0, :null => false + t.column "title", :string, :limit => 60, :default => "", :null => false + t.column "description", :text + t.column "created_on", :timestamp + end + + add_index "documents", ["project_id"], :name => "documents_project_id" + + create_table "enumerations", :force => true do |t| + t.column "opt", :string, :limit => 4, :default => "", :null => false + t.column "name", :string, :limit => 30, :default => "", :null => false + end + + create_table "issue_categories", :force => true do |t| + t.column "project_id", :integer, :default => 0, :null => false + t.column "name", :string, :limit => 30, :default => "", :null => false + end + + add_index "issue_categories", ["project_id"], :name => "issue_categories_project_id" + + create_table "issue_histories", :force => true do |t| + t.column "issue_id", :integer, :default => 0, :null => false + t.column "status_id", :integer, :default => 0, :null => false + t.column "author_id", :integer, :default => 0, :null => false + t.column "notes", :text + t.column "created_on", :timestamp + end + + add_index "issue_histories", ["issue_id"], :name => "issue_histories_issue_id" + + create_table "issue_statuses", :force => true do |t| + t.column "name", :string, :limit => 30, :default => "", :null => false + t.column "is_closed", :boolean, :default => false, :null => false + t.column "is_default", :boolean, :default => false, :null => false + t.column "html_color", :string, :limit => 6, :default => "FFFFFF", :null => false + end + + create_table "issues", :force => true do |t| + t.column "tracker_id", :integer, :default => 0, :null => false + t.column "project_id", :integer, :default => 0, :null => false + t.column "subject", :string, :default => "", :null => false + t.column "description", :text + t.column "due_date", :date + t.column "category_id", :integer + t.column "status_id", :integer, :default => 0, :null => false + t.column "assigned_to_id", :integer + t.column "priority_id", :integer, :default => 0, :null => false + t.column "fixed_version_id", :integer + t.column "author_id", :integer, :default => 0, :null => false + t.column "lock_version", :integer, :default => 0, :null => false + t.column "created_on", :timestamp + t.column "updated_on", :timestamp + end + + add_index "issues", ["project_id"], :name => "issues_project_id" + + create_table "members", :force => true do |t| + t.column "user_id", :integer, :default => 0, :null => false + t.column "project_id", :integer, :default => 0, :null => false + t.column "role_id", :integer, :default => 0, :null => false + t.column "created_on", :timestamp + end + + create_table "news", :force => true do |t| + t.column "project_id", :integer + t.column "title", :string, :limit => 60, :default => "", :null => false + t.column "summary", :string, :limit => 255, :default => "" + t.column "description", :text + t.column "author_id", :integer, :default => 0, :null => false + t.column "created_on", :timestamp + end + + add_index "news", ["project_id"], :name => "news_project_id" + + create_table "permissions", :force => true do |t| + t.column "controller", :string, :limit => 30, :default => "", :null => false + t.column "action", :string, :limit => 30, :default => "", :null => false + t.column "description", :string, :limit => 60, :default => "", :null => false + t.column "is_public", :boolean, :default => false, :null => false + t.column "sort", :integer, :default => 0, :null => false + t.column "mail_option", :boolean, :default => false, :null => false + t.column "mail_enabled", :boolean, :default => false, :null => false + end + + create_table "permissions_roles", :id => false, :force => true do |t| + t.column "permission_id", :integer, :default => 0, :null => false + t.column "role_id", :integer, :default => 0, :null => false + end + + add_index "permissions_roles", ["role_id"], :name => "permissions_roles_role_id" + + create_table "projects", :force => true do |t| + t.column "name", :string, :limit => 30, :default => "", :null => false + t.column "description", :string, :default => "", :null => false + t.column "homepage", :string, :limit => 60, :default => "" + t.column "is_public", :boolean, :default => true, :null => false + t.column "parent_id", :integer + t.column "projects_count", :integer, :default => 0 + t.column "created_on", :timestamp + t.column "updated_on", :timestamp + end + + create_table "roles", :force => true do |t| + t.column "name", :string, :limit => 30, :default => "", :null => false + end + + create_table "tokens", :force => true do |t| + t.column "user_id", :integer, :default => 0, :null => false + t.column "action", :string, :limit => 30, :default => "", :null => false + t.column "value", :string, :limit => 40, :default => "", :null => false + t.column "created_on", :datetime, :null => false + end + + create_table "trackers", :force => true do |t| + t.column "name", :string, :limit => 30, :default => "", :null => false + t.column "is_in_chlog", :boolean, :default => false, :null => false + end + + create_table "users", :force => true do |t| + t.column "login", :string, :limit => 30, :default => "", :null => false + t.column "hashed_password", :string, :limit => 40, :default => "", :null => false + t.column "firstname", :string, :limit => 30, :default => "", :null => false + t.column "lastname", :string, :limit => 30, :default => "", :null => false + t.column "mail", :string, :limit => 60, :default => "", :null => false + t.column "mail_notification", :boolean, :default => true, :null => false + t.column "admin", :boolean, :default => false, :null => false + t.column "status", :integer, :default => 1, :null => false + t.column "last_login_on", :datetime + t.column "language", :string, :limit => 2, :default => "" + t.column "auth_source_id", :integer + t.column "created_on", :timestamp + t.column "updated_on", :timestamp + end + + create_table "versions", :force => true do |t| + t.column "project_id", :integer, :default => 0, :null => false + t.column "name", :string, :limit => 30, :default => "", :null => false + t.column "description", :string, :default => "" + t.column "effective_date", :date + t.column "created_on", :timestamp + t.column "updated_on", :timestamp + end + + add_index "versions", ["project_id"], :name => "versions_project_id" + + create_table "workflows", :force => true do |t| + t.column "tracker_id", :integer, :default => 0, :null => false + t.column "old_status_id", :integer, :default => 0, :null => false + t.column "new_status_id", :integer, :default => 0, :null => false + t.column "role_id", :integer, :default => 0, :null => false + end + + # project + Permission.create :controller => "projects", :action => "show", :description => "label_overview", :sort => 100, :is_public => true + Permission.create :controller => "projects", :action => "changelog", :description => "label_change_log", :sort => 105, :is_public => true + Permission.create :controller => "reports", :action => "issue_report", :description => "label_report_plural", :sort => 110, :is_public => true + Permission.create :controller => "projects", :action => "settings", :description => "label_settings", :sort => 150 + Permission.create :controller => "projects", :action => "edit", :description => "button_edit", :sort => 151 + # members + Permission.create :controller => "projects", :action => "list_members", :description => "button_list", :sort => 200, :is_public => true + Permission.create :controller => "projects", :action => "add_member", :description => "button_add", :sort => 220 + Permission.create :controller => "members", :action => "edit", :description => "button_edit", :sort => 221 + Permission.create :controller => "members", :action => "destroy", :description => "button_delete", :sort => 222 + # versions + Permission.create :controller => "projects", :action => "add_version", :description => "button_add", :sort => 320 + Permission.create :controller => "versions", :action => "edit", :description => "button_edit", :sort => 321 + Permission.create :controller => "versions", :action => "destroy", :description => "button_delete", :sort => 322 + # issue categories + Permission.create :controller => "projects", :action => "add_issue_category", :description => "button_add", :sort => 420 + Permission.create :controller => "issue_categories", :action => "edit", :description => "button_edit", :sort => 421 + Permission.create :controller => "issue_categories", :action => "destroy", :description => "button_delete", :sort => 422 + # issues + Permission.create :controller => "projects", :action => "list_issues", :description => "button_list", :sort => 1000, :is_public => true + Permission.create :controller => "projects", :action => "export_issues_csv", :description => "label_export_csv", :sort => 1001, :is_public => true + Permission.create :controller => "issues", :action => "show", :description => "button_view", :sort => 1005, :is_public => true + Permission.create :controller => "issues", :action => "download", :description => "button_download", :sort => 1010, :is_public => true + Permission.create :controller => "projects", :action => "add_issue", :description => "button_add", :sort => 1050, :mail_option => 1, :mail_enabled => 1 + Permission.create :controller => "issues", :action => "edit", :description => "button_edit", :sort => 1055 + Permission.create :controller => "issues", :action => "change_status", :description => "label_change_status", :sort => 1060, :mail_option => 1, :mail_enabled => 1 + Permission.create :controller => "issues", :action => "destroy", :description => "button_delete", :sort => 1065 + Permission.create :controller => "issues", :action => "add_attachment", :description => "label_attachment_new", :sort => 1070 + Permission.create :controller => "issues", :action => "destroy_attachment", :description => "label_attachment_delete", :sort => 1075 + # news + Permission.create :controller => "projects", :action => "list_news", :description => "button_list", :sort => 1100, :is_public => true + Permission.create :controller => "news", :action => "show", :description => "button_view", :sort => 1101, :is_public => true + Permission.create :controller => "projects", :action => "add_news", :description => "button_add", :sort => 1120 + Permission.create :controller => "news", :action => "edit", :description => "button_edit", :sort => 1121 + Permission.create :controller => "news", :action => "destroy", :description => "button_delete", :sort => 1122 + # documents + Permission.create :controller => "projects", :action => "list_documents", :description => "button_list", :sort => 1200, :is_public => true + Permission.create :controller => "documents", :action => "show", :description => "button_view", :sort => 1201, :is_public => true + Permission.create :controller => "documents", :action => "download", :description => "button_download", :sort => 1202, :is_public => true + Permission.create :controller => "projects", :action => "add_document", :description => "button_add", :sort => 1220 + Permission.create :controller => "documents", :action => "edit", :description => "button_edit", :sort => 1221 + Permission.create :controller => "documents", :action => "destroy", :description => "button_delete", :sort => 1222 + Permission.create :controller => "documents", :action => "add_attachment", :description => "label_attachment_new", :sort => 1223 + Permission.create :controller => "documents", :action => "destroy_attachment", :description => "label_attachment_delete", :sort => 1224 + # files + Permission.create :controller => "projects", :action => "list_files", :description => "button_list", :sort => 1300, :is_public => true + Permission.create :controller => "versions", :action => "download", :description => "button_download", :sort => 1301, :is_public => true + Permission.create :controller => "projects", :action => "add_file", :description => "button_add", :sort => 1320 + Permission.create :controller => "versions", :action => "destroy_file", :description => "button_delete", :sort => 1322 + + # create default administrator account + user = User.create :login => "admin", + :hashed_password => "d033e22ae348aeb5660fc2140aec35850c4da997", + :admin => true, + :firstname => "Redmine", + :lastname => "Admin", + :mail => "admin@example.net", + :mail_notification => true, + :status => 1 + end + + def self.down + drop_table :attachments + drop_table :auth_sources + drop_table :custom_fields + drop_table :custom_fields_projects + drop_table :custom_fields_trackers + drop_table :custom_values + drop_table :documents + drop_table :enumerations + drop_table :issue_categories + drop_table :issue_histories + drop_table :issue_statuses + drop_table :issues + drop_table :members + drop_table :news + drop_table :permissions + drop_table :permissions_roles + drop_table :projects + drop_table :roles + drop_table :trackers + drop_table :tokens + drop_table :users + drop_table :versions + drop_table :workflows + end +end diff --git a/db/migrate/002_issue_move.rb b/db/migrate/002_issue_move.rb new file mode 100644 index 00000000..98e95d3b --- /dev/null +++ b/db/migrate/002_issue_move.rb @@ -0,0 +1,12 @@ +class IssueMove < ActiveRecord::Migration + # model removed + class Permission < ActiveRecord::Base; end + + def self.up + Permission.create :controller => "projects", :action => "move_issues", :description => "button_move", :sort => 1061, :mail_option => 0, :mail_enabled => 0 + end + + def self.down + Permission.where("controller=? and action=?", 'projects', 'move_issues').first.destroy + end +end diff --git a/db/migrate/003_issue_add_note.rb b/db/migrate/003_issue_add_note.rb new file mode 100644 index 00000000..dabdb858 --- /dev/null +++ b/db/migrate/003_issue_add_note.rb @@ -0,0 +1,12 @@ +class IssueAddNote < ActiveRecord::Migration + # model removed + class Permission < ActiveRecord::Base; end + + def self.up + Permission.create :controller => "issues", :action => "add_note", :description => "label_add_note", :sort => 1057, :mail_option => 1, :mail_enabled => 0 + end + + def self.down + Permission.where("controller=? and action=?", 'issues', 'add_note').first.destroy + end +end diff --git a/db/migrate/004_export_pdf.rb b/db/migrate/004_export_pdf.rb new file mode 100644 index 00000000..8d4ba0b3 --- /dev/null +++ b/db/migrate/004_export_pdf.rb @@ -0,0 +1,14 @@ +class ExportPdf < ActiveRecord::Migration + # model removed + class Permission < ActiveRecord::Base; end + + def self.up + Permission.create :controller => "projects", :action => "export_issues_pdf", :description => "label_export_pdf", :sort => 1002, :is_public => true, :mail_option => 0, :mail_enabled => 0 + Permission.create :controller => "issues", :action => "export_pdf", :description => "label_export_pdf", :sort => 1015, :is_public => true, :mail_option => 0, :mail_enabled => 0 + end + + def self.down + Permission.where("controller=? and action=?", 'projects', 'export_issues_pdf').first.destroy + Permission.where("controller=? and action=?", 'issues', 'export_pdf').first.destroy + end +end diff --git a/db/migrate/005_issue_start_date.rb b/db/migrate/005_issue_start_date.rb new file mode 100644 index 00000000..3d1693fc --- /dev/null +++ b/db/migrate/005_issue_start_date.rb @@ -0,0 +1,11 @@ +class IssueStartDate < ActiveRecord::Migration + def self.up + add_column :issues, :start_date, :date + add_column :issues, :done_ratio, :integer, :default => 0, :null => false + end + + def self.down + remove_column :issues, :start_date + remove_column :issues, :done_ratio + end +end diff --git a/db/migrate/006_calendar_and_activity.rb b/db/migrate/006_calendar_and_activity.rb new file mode 100644 index 00000000..a30979a2 --- /dev/null +++ b/db/migrate/006_calendar_and_activity.rb @@ -0,0 +1,16 @@ +class CalendarAndActivity < ActiveRecord::Migration + # model removed + class Permission < ActiveRecord::Base; end + + def self.up + Permission.create :controller => "projects", :action => "activity", :description => "label_activity", :sort => 160, :is_public => true, :mail_option => 0, :mail_enabled => 0 + Permission.create :controller => "projects", :action => "calendar", :description => "label_calendar", :sort => 165, :is_public => true, :mail_option => 0, :mail_enabled => 0 + Permission.create :controller => "projects", :action => "gantt", :description => "label_gantt", :sort => 166, :is_public => true, :mail_option => 0, :mail_enabled => 0 + end + + def self.down + Permission.where("controller=? and action=?", 'projects', 'activity').first.destroy + Permission.where("controller=? and action=?", 'projects', 'calendar').first.destroy + Permission.where("controller=? and action=?", 'projects', 'gantt').first.destroy + end +end diff --git a/db/migrate/007_create_journals.rb b/db/migrate/007_create_journals.rb new file mode 100644 index 00000000..63bdd237 --- /dev/null +++ b/db/migrate/007_create_journals.rb @@ -0,0 +1,56 @@ +class CreateJournals < ActiveRecord::Migration + + # model removed, but needed for data migration + class IssueHistory < ActiveRecord::Base; belongs_to :issue; end + # model removed + class Permission < ActiveRecord::Base; end + + def self.up + create_table :journals, :force => true do |t| + t.column "journalized_id", :integer, :default => 0, :null => false + t.column "journalized_type", :string, :limit => 30, :default => "", :null => false + t.column "user_id", :integer, :default => 0, :null => false + t.column "notes", :text + t.column "created_on", :datetime, :null => false + end + create_table :journal_details, :force => true do |t| + t.column "journal_id", :integer, :default => 0, :null => false + t.column "property", :string, :limit => 30, :default => "", :null => false + t.column "prop_key", :string, :limit => 30, :default => "", :null => false + t.column "old_value", :string + t.column "value", :string + end + + # indexes + add_index "journals", ["journalized_id", "journalized_type"], :name => "journals_journalized_id" + add_index "journal_details", ["journal_id"], :name => "journal_details_journal_id" + + Permission.create :controller => "issues", :action => "history", :description => "label_history", :sort => 1006, :is_public => true, :mail_option => 0, :mail_enabled => 0 + + # data migration + IssueHistory.all.each {|h| + j = Journal.new(:journalized => h.issue, :user_id => h.author_id, :notes => h.notes, :created_on => h.created_on) + j.details << JournalDetail.new(:property => 'attr', :prop_key => 'status_id', :value => h.status_id) + j.save + } + + drop_table :issue_histories + end + + def self.down + drop_table :journal_details + drop_table :journals + + create_table "issue_histories", :force => true do |t| + t.column "issue_id", :integer, :default => 0, :null => false + t.column "status_id", :integer, :default => 0, :null => false + t.column "author_id", :integer, :default => 0, :null => false + t.column "notes", :text, :default => "" + t.column "created_on", :timestamp + end + + add_index "issue_histories", ["issue_id"], :name => "issue_histories_issue_id" + + Permission.where("controller=? and action=?", 'issues', 'history').first.destroy + end +end diff --git a/db/migrate/008_create_user_preferences.rb b/db/migrate/008_create_user_preferences.rb new file mode 100644 index 00000000..80ae1cdf --- /dev/null +++ b/db/migrate/008_create_user_preferences.rb @@ -0,0 +1,12 @@ +class CreateUserPreferences < ActiveRecord::Migration + def self.up + create_table :user_preferences do |t| + t.column "user_id", :integer, :default => 0, :null => false + t.column "others", :text + end + end + + def self.down + drop_table :user_preferences + end +end diff --git a/db/migrate/009_add_hide_mail_pref.rb b/db/migrate/009_add_hide_mail_pref.rb new file mode 100644 index 00000000..a22eafd9 --- /dev/null +++ b/db/migrate/009_add_hide_mail_pref.rb @@ -0,0 +1,9 @@ +class AddHideMailPref < ActiveRecord::Migration + def self.up + add_column :user_preferences, :hide_mail, :boolean, :default => false + end + + def self.down + remove_column :user_preferences, :hide_mail + end +end diff --git a/db/migrate/010_create_comments.rb b/db/migrate/010_create_comments.rb new file mode 100644 index 00000000..29e1116a --- /dev/null +++ b/db/migrate/010_create_comments.rb @@ -0,0 +1,16 @@ +class CreateComments < ActiveRecord::Migration + def self.up + create_table :comments do |t| + t.column :commented_type, :string, :limit => 30, :default => "", :null => false + t.column :commented_id, :integer, :default => 0, :null => false + t.column :author_id, :integer, :default => 0, :null => false + t.column :comments, :text + t.column :created_on, :datetime, :null => false + t.column :updated_on, :datetime, :null => false + end + end + + def self.down + drop_table :comments + end +end diff --git a/db/migrate/011_add_news_comments_count.rb b/db/migrate/011_add_news_comments_count.rb new file mode 100644 index 00000000..a2474399 --- /dev/null +++ b/db/migrate/011_add_news_comments_count.rb @@ -0,0 +1,9 @@ +class AddNewsCommentsCount < ActiveRecord::Migration + def self.up + add_column :news, :comments_count, :integer, :default => 0, :null => false + end + + def self.down + remove_column :news, :comments_count + end +end diff --git a/db/migrate/012_add_comments_permissions.rb b/db/migrate/012_add_comments_permissions.rb new file mode 100644 index 00000000..91eed644 --- /dev/null +++ b/db/migrate/012_add_comments_permissions.rb @@ -0,0 +1,14 @@ +class AddCommentsPermissions < ActiveRecord::Migration + # model removed + class Permission < ActiveRecord::Base; end + + def self.up + Permission.create :controller => "news", :action => "add_comment", :description => "label_comment_add", :sort => 1130, :is_public => false, :mail_option => 0, :mail_enabled => 0 + Permission.create :controller => "news", :action => "destroy_comment", :description => "label_comment_delete", :sort => 1133, :is_public => false, :mail_option => 0, :mail_enabled => 0 + end + + def self.down + Permission.where("controller=? and action=?", 'news', 'add_comment').first.destroy + Permission.where("controller=? and action=?", 'news', 'destroy_comment').first.destroy + end +end diff --git a/db/migrate/013_create_queries.rb b/db/migrate/013_create_queries.rb new file mode 100644 index 00000000..e0e8c90c --- /dev/null +++ b/db/migrate/013_create_queries.rb @@ -0,0 +1,15 @@ +class CreateQueries < ActiveRecord::Migration + def self.up + create_table :queries, :force => true do |t| + t.column "project_id", :integer + t.column "name", :string, :default => "", :null => false + t.column "filters", :text + t.column "user_id", :integer, :default => 0, :null => false + t.column "is_public", :boolean, :default => false, :null => false + end + end + + def self.down + drop_table :queries + end +end diff --git a/db/migrate/014_add_queries_permissions.rb b/db/migrate/014_add_queries_permissions.rb new file mode 100644 index 00000000..ae1f2455 --- /dev/null +++ b/db/migrate/014_add_queries_permissions.rb @@ -0,0 +1,12 @@ +class AddQueriesPermissions < ActiveRecord::Migration + # model removed + class Permission < ActiveRecord::Base; end + + def self.up + Permission.create :controller => "projects", :action => "add_query", :description => "button_create", :sort => 600, :is_public => false, :mail_option => 0, :mail_enabled => 0 + end + + def self.down + Permission.where("controller=? and action=?", 'projects', 'add_query').first.destroy + end +end diff --git a/db/migrate/015_create_repositories.rb b/db/migrate/015_create_repositories.rb new file mode 100644 index 00000000..d8c0524b --- /dev/null +++ b/db/migrate/015_create_repositories.rb @@ -0,0 +1,12 @@ +class CreateRepositories < ActiveRecord::Migration + def self.up + create_table :repositories, :force => true do |t| + t.column "project_id", :integer, :default => 0, :null => false + t.column "url", :string, :default => "", :null => false + end + end + + def self.down + drop_table :repositories + end +end diff --git a/db/migrate/016_add_repositories_permissions.rb b/db/migrate/016_add_repositories_permissions.rb new file mode 100644 index 00000000..9fcddb09 --- /dev/null +++ b/db/migrate/016_add_repositories_permissions.rb @@ -0,0 +1,22 @@ +class AddRepositoriesPermissions < ActiveRecord::Migration + # model removed + class Permission < ActiveRecord::Base; end + + def self.up + Permission.create :controller => "repositories", :action => "show", :description => "button_view", :sort => 1450, :is_public => true + Permission.create :controller => "repositories", :action => "browse", :description => "label_browse", :sort => 1460, :is_public => true + Permission.create :controller => "repositories", :action => "entry", :description => "entry", :sort => 1462, :is_public => true + Permission.create :controller => "repositories", :action => "revisions", :description => "label_view_revisions", :sort => 1470, :is_public => true + Permission.create :controller => "repositories", :action => "revision", :description => "label_view_revisions", :sort => 1472, :is_public => true + Permission.create :controller => "repositories", :action => "diff", :description => "diff", :sort => 1480, :is_public => true + end + + def self.down + Permission.where("controller=? and action=?", 'repositories', 'show').first.destroy + Permission.where("controller=? and action=?", 'repositories', 'browse').first.destroy + Permission.where("controller=? and action=?", 'repositories', 'entry').first.destroy + Permission.where("controller=? and action=?", 'repositories', 'revisions').first.destroy + Permission.where("controller=? and action=?", 'repositories', 'revision').first.destroy + Permission.where("controller=? and action=?", 'repositories', 'diff').first.destroy + end +end diff --git a/db/migrate/017_create_settings.rb b/db/migrate/017_create_settings.rb new file mode 100644 index 00000000..99f96adf --- /dev/null +++ b/db/migrate/017_create_settings.rb @@ -0,0 +1,12 @@ +class CreateSettings < ActiveRecord::Migration + def self.up + create_table :settings, :force => true do |t| + t.column "name", :string, :limit => 30, :default => "", :null => false + t.column "value", :text + end + end + + def self.down + drop_table :settings + end +end diff --git a/db/migrate/018_set_doc_and_files_notifications.rb b/db/migrate/018_set_doc_and_files_notifications.rb new file mode 100644 index 00000000..8c1d054c --- /dev/null +++ b/db/migrate/018_set_doc_and_files_notifications.rb @@ -0,0 +1,18 @@ +class SetDocAndFilesNotifications < ActiveRecord::Migration + # model removed + class Permission < ActiveRecord::Base; end + + def self.up + Permission.find_by_controller_and_action("projects", "add_file").update_attribute(:mail_option, true) + Permission.find_by_controller_and_action("projects", "add_document").update_attribute(:mail_option, true) + Permission.find_by_controller_and_action("documents", "add_attachment").update_attribute(:mail_option, true) + Permission.find_by_controller_and_action("issues", "add_attachment").update_attribute(:mail_option, true) + end + + def self.down + Permission.find_by_controller_and_action("projects", "add_file").update_attribute(:mail_option, false) + Permission.find_by_controller_and_action("projects", "add_document").update_attribute(:mail_option, false) + Permission.find_by_controller_and_action("documents", "add_attachment").update_attribute(:mail_option, false) + Permission.find_by_controller_and_action("issues", "add_attachment").update_attribute(:mail_option, false) + end +end diff --git a/db/migrate/019_add_issue_status_position.rb b/db/migrate/019_add_issue_status_position.rb new file mode 100644 index 00000000..012f97c2 --- /dev/null +++ b/db/migrate/019_add_issue_status_position.rb @@ -0,0 +1,10 @@ +class AddIssueStatusPosition < ActiveRecord::Migration + def self.up + add_column :issue_statuses, :position, :integer, :default => 1 + IssueStatus.all.each_with_index {|status, i| status.update_attribute(:position, i+1)} + end + + def self.down + remove_column :issue_statuses, :position + end +end diff --git a/db/migrate/020_add_role_position.rb b/db/migrate/020_add_role_position.rb new file mode 100644 index 00000000..48ac89a3 --- /dev/null +++ b/db/migrate/020_add_role_position.rb @@ -0,0 +1,10 @@ +class AddRolePosition < ActiveRecord::Migration + def self.up + add_column :roles, :position, :integer, :default => 1 + Role.all.each_with_index {|role, i| role.update_attribute(:position, i+1)} + end + + def self.down + remove_column :roles, :position + end +end diff --git a/db/migrate/021_add_tracker_position.rb b/db/migrate/021_add_tracker_position.rb new file mode 100644 index 00000000..5fa8a318 --- /dev/null +++ b/db/migrate/021_add_tracker_position.rb @@ -0,0 +1,10 @@ +class AddTrackerPosition < ActiveRecord::Migration + def self.up + add_column :trackers, :position, :integer, :default => 1 + Tracker.all.each_with_index {|tracker, i| tracker.update_attribute(:position, i+1)} + end + + def self.down + remove_column :trackers, :position + end +end diff --git a/db/migrate/022_serialize_possibles_values.rb b/db/migrate/022_serialize_possibles_values.rb new file mode 100644 index 00000000..3e9fed0a --- /dev/null +++ b/db/migrate/022_serialize_possibles_values.rb @@ -0,0 +1,13 @@ +class SerializePossiblesValues < ActiveRecord::Migration + def self.up + CustomField.all.each do |field| + if field.possible_values and field.possible_values.is_a? String + field.possible_values = field.possible_values.split('|') + field.save + end + end + end + + def self.down + end +end diff --git a/db/migrate/023_add_tracker_is_in_roadmap.rb b/db/migrate/023_add_tracker_is_in_roadmap.rb new file mode 100644 index 00000000..82ef87bb --- /dev/null +++ b/db/migrate/023_add_tracker_is_in_roadmap.rb @@ -0,0 +1,9 @@ +class AddTrackerIsInRoadmap < ActiveRecord::Migration + def self.up + add_column :trackers, :is_in_roadmap, :boolean, :default => true, :null => false + end + + def self.down + remove_column :trackers, :is_in_roadmap + end +end diff --git a/db/migrate/024_add_roadmap_permission.rb b/db/migrate/024_add_roadmap_permission.rb new file mode 100644 index 00000000..f521e602 --- /dev/null +++ b/db/migrate/024_add_roadmap_permission.rb @@ -0,0 +1,12 @@ +class AddRoadmapPermission < ActiveRecord::Migration + # model removed + class Permission < ActiveRecord::Base; end + + def self.up + Permission.create :controller => "projects", :action => "roadmap", :description => "label_roadmap", :sort => 107, :is_public => true, :mail_option => 0, :mail_enabled => 0 + end + + def self.down + Permission.where("controller=? and action=?", 'projects', 'roadmap').first.destroy + end +end diff --git a/db/migrate/025_add_search_permission.rb b/db/migrate/025_add_search_permission.rb new file mode 100644 index 00000000..a942b01b --- /dev/null +++ b/db/migrate/025_add_search_permission.rb @@ -0,0 +1,12 @@ +class AddSearchPermission < ActiveRecord::Migration + # model removed + class Permission < ActiveRecord::Base; end + + def self.up + Permission.create :controller => "projects", :action => "search", :description => "label_search", :sort => 130, :is_public => true, :mail_option => 0, :mail_enabled => 0 + end + + def self.down + Permission.find_by_controller_and_action('projects', 'search').destroy + end +end diff --git a/db/migrate/026_add_repository_login_and_password.rb b/db/migrate/026_add_repository_login_and_password.rb new file mode 100644 index 00000000..5fc91972 --- /dev/null +++ b/db/migrate/026_add_repository_login_and_password.rb @@ -0,0 +1,11 @@ +class AddRepositoryLoginAndPassword < ActiveRecord::Migration + def self.up + add_column :repositories, :login, :string, :limit => 60, :default => "" + add_column :repositories, :password, :string, :limit => 60, :default => "" + end + + def self.down + remove_column :repositories, :login + remove_column :repositories, :password + end +end diff --git a/db/migrate/027_create_wikis.rb b/db/migrate/027_create_wikis.rb new file mode 100644 index 00000000..284eee2e --- /dev/null +++ b/db/migrate/027_create_wikis.rb @@ -0,0 +1,14 @@ +class CreateWikis < ActiveRecord::Migration + def self.up + create_table :wikis do |t| + t.column :project_id, :integer, :null => false + t.column :start_page, :string, :limit => 255, :null => false + t.column :status, :integer, :default => 1, :null => false + end + add_index :wikis, :project_id, :name => :wikis_project_id + end + + def self.down + drop_table :wikis + end +end diff --git a/db/migrate/028_create_wiki_pages.rb b/db/migrate/028_create_wiki_pages.rb new file mode 100644 index 00000000..e2282125 --- /dev/null +++ b/db/migrate/028_create_wiki_pages.rb @@ -0,0 +1,14 @@ +class CreateWikiPages < ActiveRecord::Migration + def self.up + create_table :wiki_pages do |t| + t.column :wiki_id, :integer, :null => false + t.column :title, :string, :limit => 255, :null => false + t.column :created_on, :datetime, :null => false + end + add_index :wiki_pages, [:wiki_id, :title], :name => :wiki_pages_wiki_id_title + end + + def self.down + drop_table :wiki_pages + end +end diff --git a/db/migrate/029_create_wiki_contents.rb b/db/migrate/029_create_wiki_contents.rb new file mode 100644 index 00000000..5b6a22f9 --- /dev/null +++ b/db/migrate/029_create_wiki_contents.rb @@ -0,0 +1,30 @@ +class CreateWikiContents < ActiveRecord::Migration + def self.up + create_table :wiki_contents do |t| + t.column :page_id, :integer, :null => false + t.column :author_id, :integer + t.column :text, :text + t.column :comments, :string, :limit => 255, :default => "" + t.column :updated_on, :datetime, :null => false + t.column :version, :integer, :null => false + end + add_index :wiki_contents, :page_id, :name => :wiki_contents_page_id + + create_table :wiki_content_versions do |t| + t.column :wiki_content_id, :integer, :null => false + t.column :page_id, :integer, :null => false + t.column :author_id, :integer + t.column :data, :binary + t.column :compression, :string, :limit => 6, :default => "" + t.column :comments, :string, :limit => 255, :default => "" + t.column :updated_on, :datetime, :null => false + t.column :version, :integer, :null => false + end + add_index :wiki_content_versions, :wiki_content_id, :name => :wiki_content_versions_wcid + end + + def self.down + drop_table :wiki_contents + drop_table :wiki_content_versions + end +end diff --git a/db/migrate/030_add_projects_feeds_permissions.rb b/db/migrate/030_add_projects_feeds_permissions.rb new file mode 100644 index 00000000..7f97035b --- /dev/null +++ b/db/migrate/030_add_projects_feeds_permissions.rb @@ -0,0 +1,12 @@ +class AddProjectsFeedsPermissions < ActiveRecord::Migration + # model removed + class Permission < ActiveRecord::Base; end + + def self.up + Permission.create :controller => "projects", :action => "feeds", :description => "label_feed_plural", :sort => 132, :is_public => true, :mail_option => 0, :mail_enabled => 0 + end + + def self.down + Permission.find_by_controller_and_action('projects', 'feeds').destroy + end +end diff --git a/db/migrate/031_add_repository_root_url.rb b/db/migrate/031_add_repository_root_url.rb new file mode 100644 index 00000000..df57809c --- /dev/null +++ b/db/migrate/031_add_repository_root_url.rb @@ -0,0 +1,9 @@ +class AddRepositoryRootUrl < ActiveRecord::Migration + def self.up + add_column :repositories, :root_url, :string, :limit => 255, :default => "" + end + + def self.down + remove_column :repositories, :root_url + end +end diff --git a/db/migrate/032_create_time_entries.rb b/db/migrate/032_create_time_entries.rb new file mode 100644 index 00000000..9b9a54eb --- /dev/null +++ b/db/migrate/032_create_time_entries.rb @@ -0,0 +1,24 @@ +class CreateTimeEntries < ActiveRecord::Migration + def self.up + create_table :time_entries do |t| + t.column :project_id, :integer, :null => false + t.column :user_id, :integer, :null => false + t.column :issue_id, :integer + t.column :hours, :float, :null => false + t.column :comments, :string, :limit => 255 + t.column :activity_id, :integer, :null => false + t.column :spent_on, :date, :null => false + t.column :tyear, :integer, :null => false + t.column :tmonth, :integer, :null => false + t.column :tweek, :integer, :null => false + t.column :created_on, :datetime, :null => false + t.column :updated_on, :datetime, :null => false + end + add_index :time_entries, [:project_id], :name => :time_entries_project_id + add_index :time_entries, [:issue_id], :name => :time_entries_issue_id + end + + def self.down + drop_table :time_entries + end +end diff --git a/db/migrate/033_add_timelog_permissions.rb b/db/migrate/033_add_timelog_permissions.rb new file mode 100644 index 00000000..ab9c809e --- /dev/null +++ b/db/migrate/033_add_timelog_permissions.rb @@ -0,0 +1,12 @@ +class AddTimelogPermissions < ActiveRecord::Migration + # model removed + class Permission < ActiveRecord::Base; end + + def self.up + Permission.create :controller => "timelog", :action => "edit", :description => "button_log_time", :sort => 1520, :is_public => false, :mail_option => 0, :mail_enabled => 0 + end + + def self.down + Permission.find_by_controller_and_action('timelog', 'edit').destroy + end +end diff --git a/db/migrate/034_create_changesets.rb b/db/migrate/034_create_changesets.rb new file mode 100644 index 00000000..612fd46b --- /dev/null +++ b/db/migrate/034_create_changesets.rb @@ -0,0 +1,16 @@ +class CreateChangesets < ActiveRecord::Migration + def self.up + create_table :changesets do |t| + t.column :repository_id, :integer, :null => false + t.column :revision, :integer, :null => false + t.column :committer, :string, :limit => 30 + t.column :committed_on, :datetime, :null => false + t.column :comments, :text + end + add_index :changesets, [:repository_id, :revision], :unique => true, :name => :changesets_repos_rev + end + + def self.down + drop_table :changesets + end +end diff --git a/db/migrate/035_create_changes.rb b/db/migrate/035_create_changes.rb new file mode 100644 index 00000000..fa0cfac3 --- /dev/null +++ b/db/migrate/035_create_changes.rb @@ -0,0 +1,16 @@ +class CreateChanges < ActiveRecord::Migration + def self.up + create_table :changes do |t| + t.column :changeset_id, :integer, :null => false + t.column :action, :string, :limit => 1, :default => "", :null => false + t.column :path, :string, :default => "", :null => false + t.column :from_path, :string + t.column :from_revision, :integer + end + add_index :changes, [:changeset_id], :name => :changesets_changeset_id + end + + def self.down + drop_table :changes + end +end diff --git a/db/migrate/036_add_changeset_commit_date.rb b/db/migrate/036_add_changeset_commit_date.rb new file mode 100644 index 00000000..b9cc49b8 --- /dev/null +++ b/db/migrate/036_add_changeset_commit_date.rb @@ -0,0 +1,10 @@ +class AddChangesetCommitDate < ActiveRecord::Migration + def self.up + add_column :changesets, :commit_date, :date + Changeset.update_all "commit_date = committed_on" + end + + def self.down + remove_column :changesets, :commit_date + end +end diff --git a/db/migrate/037_add_project_identifier.rb b/db/migrate/037_add_project_identifier.rb new file mode 100644 index 00000000..0fd8c751 --- /dev/null +++ b/db/migrate/037_add_project_identifier.rb @@ -0,0 +1,9 @@ +class AddProjectIdentifier < ActiveRecord::Migration + def self.up + add_column :projects, :identifier, :string, :limit => 20 + end + + def self.down + remove_column :projects, :identifier + end +end diff --git a/db/migrate/038_add_custom_field_is_filter.rb b/db/migrate/038_add_custom_field_is_filter.rb new file mode 100644 index 00000000..519ee0bd --- /dev/null +++ b/db/migrate/038_add_custom_field_is_filter.rb @@ -0,0 +1,9 @@ +class AddCustomFieldIsFilter < ActiveRecord::Migration + def self.up + add_column :custom_fields, :is_filter, :boolean, :null => false, :default => false + end + + def self.down + remove_column :custom_fields, :is_filter + end +end diff --git a/db/migrate/039_create_watchers.rb b/db/migrate/039_create_watchers.rb new file mode 100644 index 00000000..9579e19a --- /dev/null +++ b/db/migrate/039_create_watchers.rb @@ -0,0 +1,13 @@ +class CreateWatchers < ActiveRecord::Migration + def self.up + create_table :watchers do |t| + t.column :watchable_type, :string, :default => "", :null => false + t.column :watchable_id, :integer, :default => 0, :null => false + t.column :user_id, :integer + end + end + + def self.down + drop_table :watchers + end +end diff --git a/db/migrate/040_create_changesets_issues.rb b/db/migrate/040_create_changesets_issues.rb new file mode 100644 index 00000000..494d3cc4 --- /dev/null +++ b/db/migrate/040_create_changesets_issues.rb @@ -0,0 +1,13 @@ +class CreateChangesetsIssues < ActiveRecord::Migration + def self.up + create_table :changesets_issues, :id => false do |t| + t.column :changeset_id, :integer, :null => false + t.column :issue_id, :integer, :null => false + end + add_index :changesets_issues, [:changeset_id, :issue_id], :unique => true, :name => :changesets_issues_ids + end + + def self.down + drop_table :changesets_issues + end +end diff --git a/db/migrate/041_rename_comment_to_comments.rb b/db/migrate/041_rename_comment_to_comments.rb new file mode 100644 index 00000000..93677e57 --- /dev/null +++ b/db/migrate/041_rename_comment_to_comments.rb @@ -0,0 +1,13 @@ +class RenameCommentToComments < ActiveRecord::Migration + def self.up + rename_column(:comments, :comment, :comments) if ActiveRecord::Base.connection.columns(Comment.table_name).detect{|c| c.name == "comment"} + rename_column(:wiki_contents, :comment, :comments) if ActiveRecord::Base.connection.columns(WikiContent.table_name).detect{|c| c.name == "comment"} + rename_column(:wiki_content_versions, :comment, :comments) if ActiveRecord::Base.connection.columns(WikiContent.versioned_table_name).detect{|c| c.name == "comment"} + rename_column(:time_entries, :comment, :comments) if ActiveRecord::Base.connection.columns(TimeEntry.table_name).detect{|c| c.name == "comment"} + rename_column(:changesets, :comment, :comments) if ActiveRecord::Base.connection.columns(Changeset.table_name).detect{|c| c.name == "comment"} + end + + def self.down + raise IrreversibleMigration + end +end diff --git a/db/migrate/042_create_issue_relations.rb b/db/migrate/042_create_issue_relations.rb new file mode 100644 index 00000000..802c1243 --- /dev/null +++ b/db/migrate/042_create_issue_relations.rb @@ -0,0 +1,14 @@ +class CreateIssueRelations < ActiveRecord::Migration + def self.up + create_table :issue_relations do |t| + t.column :issue_from_id, :integer, :null => false + t.column :issue_to_id, :integer, :null => false + t.column :relation_type, :string, :default => "", :null => false + t.column :delay, :integer + end + end + + def self.down + drop_table :issue_relations + end +end diff --git a/db/migrate/043_add_relations_permissions.rb b/db/migrate/043_add_relations_permissions.rb new file mode 100644 index 00000000..32d464a5 --- /dev/null +++ b/db/migrate/043_add_relations_permissions.rb @@ -0,0 +1,14 @@ +class AddRelationsPermissions < ActiveRecord::Migration + # model removed + class Permission < ActiveRecord::Base; end + + def self.up + Permission.create :controller => "issue_relations", :action => "new", :description => "label_relation_new", :sort => 1080, :is_public => false, :mail_option => 0, :mail_enabled => 0 + Permission.create :controller => "issue_relations", :action => "destroy", :description => "label_relation_delete", :sort => 1085, :is_public => false, :mail_option => 0, :mail_enabled => 0 + end + + def self.down + Permission.find_by_controller_and_action("issue_relations", "new").destroy + Permission.find_by_controller_and_action("issue_relations", "destroy").destroy + end +end diff --git a/db/migrate/044_set_language_length_to_five.rb b/db/migrate/044_set_language_length_to_five.rb new file mode 100644 index 00000000..a417f7d7 --- /dev/null +++ b/db/migrate/044_set_language_length_to_five.rb @@ -0,0 +1,9 @@ +class SetLanguageLengthToFive < ActiveRecord::Migration + def self.up + change_column :users, :language, :string, :limit => 5, :default => "" + end + + def self.down + raise IrreversibleMigration + end +end diff --git a/db/migrate/045_create_boards.rb b/db/migrate/045_create_boards.rb new file mode 100644 index 00000000..17f2bbbe --- /dev/null +++ b/db/migrate/045_create_boards.rb @@ -0,0 +1,18 @@ +class CreateBoards < ActiveRecord::Migration + def self.up + create_table :boards do |t| + t.column :project_id, :integer, :null => false + t.column :name, :string, :default => "", :null => false + t.column :description, :string + t.column :position, :integer, :default => 1 + t.column :topics_count, :integer, :default => 0, :null => false + t.column :messages_count, :integer, :default => 0, :null => false + t.column :last_message_id, :integer + end + add_index :boards, [:project_id], :name => :boards_project_id + end + + def self.down + drop_table :boards + end +end diff --git a/db/migrate/046_create_messages.rb b/db/migrate/046_create_messages.rb new file mode 100644 index 00000000..d99aaf84 --- /dev/null +++ b/db/migrate/046_create_messages.rb @@ -0,0 +1,21 @@ +class CreateMessages < ActiveRecord::Migration + def self.up + create_table :messages do |t| + t.column :board_id, :integer, :null => false + t.column :parent_id, :integer + t.column :subject, :string, :default => "", :null => false + t.column :content, :text + t.column :author_id, :integer + t.column :replies_count, :integer, :default => 0, :null => false + t.column :last_reply_id, :integer + t.column :created_on, :datetime, :null => false + t.column :updated_on, :datetime, :null => false + end + add_index :messages, [:board_id], :name => :messages_board_id + add_index :messages, [:parent_id], :name => :messages_parent_id + end + + def self.down + drop_table :messages + end +end diff --git a/db/migrate/047_add_boards_permissions.rb b/db/migrate/047_add_boards_permissions.rb new file mode 100644 index 00000000..5b1f6f77 --- /dev/null +++ b/db/migrate/047_add_boards_permissions.rb @@ -0,0 +1,16 @@ +class AddBoardsPermissions < ActiveRecord::Migration + # model removed + class Permission < ActiveRecord::Base; end + + def self.up + Permission.create :controller => "boards", :action => "new", :description => "button_add", :sort => 2000, :is_public => false, :mail_option => 0, :mail_enabled => 0 + Permission.create :controller => "boards", :action => "edit", :description => "button_edit", :sort => 2005, :is_public => false, :mail_option => 0, :mail_enabled => 0 + Permission.create :controller => "boards", :action => "destroy", :description => "button_delete", :sort => 2010, :is_public => false, :mail_option => 0, :mail_enabled => 0 + end + + def self.down + Permission.find_by_controller_and_action("boards", "new").destroy + Permission.find_by_controller_and_action("boards", "edit").destroy + Permission.find_by_controller_and_action("boards", "destroy").destroy + end +end diff --git a/db/migrate/048_allow_null_version_effective_date.rb b/db/migrate/048_allow_null_version_effective_date.rb new file mode 100644 index 00000000..82d2a33e --- /dev/null +++ b/db/migrate/048_allow_null_version_effective_date.rb @@ -0,0 +1,9 @@ +class AllowNullVersionEffectiveDate < ActiveRecord::Migration + def self.up + change_column :versions, :effective_date, :date, :default => nil, :null => true + end + + def self.down + raise IrreversibleMigration + end +end diff --git a/db/migrate/049_add_wiki_destroy_page_permission.rb b/db/migrate/049_add_wiki_destroy_page_permission.rb new file mode 100644 index 00000000..c8215238 --- /dev/null +++ b/db/migrate/049_add_wiki_destroy_page_permission.rb @@ -0,0 +1,12 @@ +class AddWikiDestroyPagePermission < ActiveRecord::Migration + # model removed + class Permission < ActiveRecord::Base; end + + def self.up + Permission.create :controller => 'wiki', :action => 'destroy', :description => 'button_delete', :sort => 1740, :is_public => false, :mail_option => 0, :mail_enabled => 0 + end + + def self.down + Permission.find_by_controller_and_action('wiki', 'destroy').destroy + end +end diff --git a/db/migrate/050_add_wiki_attachments_permissions.rb b/db/migrate/050_add_wiki_attachments_permissions.rb new file mode 100644 index 00000000..c0697be9 --- /dev/null +++ b/db/migrate/050_add_wiki_attachments_permissions.rb @@ -0,0 +1,14 @@ +class AddWikiAttachmentsPermissions < ActiveRecord::Migration + # model removed + class Permission < ActiveRecord::Base; end + + def self.up + Permission.create :controller => 'wiki', :action => 'add_attachment', :description => 'label_attachment_new', :sort => 1750, :is_public => false, :mail_option => 0, :mail_enabled => 0 + Permission.create :controller => 'wiki', :action => 'destroy_attachment', :description => 'label_attachment_delete', :sort => 1755, :is_public => false, :mail_option => 0, :mail_enabled => 0 + end + + def self.down + Permission.find_by_controller_and_action('wiki', 'add_attachment').destroy + Permission.find_by_controller_and_action('wiki', 'destroy_attachment').destroy + end +end diff --git a/db/migrate/051_add_project_status.rb b/db/migrate/051_add_project_status.rb new file mode 100644 index 00000000..fba36d23 --- /dev/null +++ b/db/migrate/051_add_project_status.rb @@ -0,0 +1,9 @@ +class AddProjectStatus < ActiveRecord::Migration + def self.up + add_column :projects, :status, :integer, :default => 1, :null => false + end + + def self.down + remove_column :projects, :status + end +end diff --git a/db/migrate/052_add_changes_revision.rb b/db/migrate/052_add_changes_revision.rb new file mode 100644 index 00000000..6f58c1a7 --- /dev/null +++ b/db/migrate/052_add_changes_revision.rb @@ -0,0 +1,9 @@ +class AddChangesRevision < ActiveRecord::Migration + def self.up + add_column :changes, :revision, :string + end + + def self.down + remove_column :changes, :revision + end +end diff --git a/db/migrate/053_add_changes_branch.rb b/db/migrate/053_add_changes_branch.rb new file mode 100644 index 00000000..998ce2ba --- /dev/null +++ b/db/migrate/053_add_changes_branch.rb @@ -0,0 +1,9 @@ +class AddChangesBranch < ActiveRecord::Migration + def self.up + add_column :changes, :branch, :string + end + + def self.down + remove_column :changes, :branch + end +end diff --git a/db/migrate/054_add_changesets_scmid.rb b/db/migrate/054_add_changesets_scmid.rb new file mode 100644 index 00000000..188fa6ef --- /dev/null +++ b/db/migrate/054_add_changesets_scmid.rb @@ -0,0 +1,9 @@ +class AddChangesetsScmid < ActiveRecord::Migration + def self.up + add_column :changesets, :scmid, :string + end + + def self.down + remove_column :changesets, :scmid + end +end diff --git a/db/migrate/055_add_repositories_type.rb b/db/migrate/055_add_repositories_type.rb new file mode 100644 index 00000000..f5a71620 --- /dev/null +++ b/db/migrate/055_add_repositories_type.rb @@ -0,0 +1,11 @@ +class AddRepositoriesType < ActiveRecord::Migration + def self.up + add_column :repositories, :type, :string + # Set class name for existing SVN repositories + Repository.update_all "type = 'Subversion'" + end + + def self.down + remove_column :repositories, :type + end +end diff --git a/db/migrate/056_add_repositories_changes_permission.rb b/db/migrate/056_add_repositories_changes_permission.rb new file mode 100644 index 00000000..0d9b13b5 --- /dev/null +++ b/db/migrate/056_add_repositories_changes_permission.rb @@ -0,0 +1,12 @@ +class AddRepositoriesChangesPermission < ActiveRecord::Migration + # model removed + class Permission < ActiveRecord::Base; end + + def self.up + Permission.create :controller => 'repositories', :action => 'changes', :description => 'label_change_plural', :sort => 1475, :is_public => true, :mail_option => 0, :mail_enabled => 0 + end + + def self.down + Permission.find_by_controller_and_action('repositories', 'changes').destroy + end +end diff --git a/db/migrate/057_add_versions_wiki_page_title.rb b/db/migrate/057_add_versions_wiki_page_title.rb new file mode 100644 index 00000000..58b8fd9a --- /dev/null +++ b/db/migrate/057_add_versions_wiki_page_title.rb @@ -0,0 +1,9 @@ +class AddVersionsWikiPageTitle < ActiveRecord::Migration + def self.up + add_column :versions, :wiki_page_title, :string + end + + def self.down + remove_column :versions, :wiki_page_title + end +end diff --git a/db/migrate/058_add_issue_categories_assigned_to_id.rb b/db/migrate/058_add_issue_categories_assigned_to_id.rb new file mode 100644 index 00000000..8653532e --- /dev/null +++ b/db/migrate/058_add_issue_categories_assigned_to_id.rb @@ -0,0 +1,9 @@ +class AddIssueCategoriesAssignedToId < ActiveRecord::Migration + def self.up + add_column :issue_categories, :assigned_to_id, :integer + end + + def self.down + remove_column :issue_categories, :assigned_to_id + end +end diff --git a/db/migrate/059_add_roles_assignable.rb b/db/migrate/059_add_roles_assignable.rb new file mode 100644 index 00000000..a1ba7963 --- /dev/null +++ b/db/migrate/059_add_roles_assignable.rb @@ -0,0 +1,9 @@ +class AddRolesAssignable < ActiveRecord::Migration + def self.up + add_column :roles, :assignable, :boolean, :default => true + end + + def self.down + remove_column :roles, :assignable + end +end diff --git a/db/migrate/060_change_changesets_committer_limit.rb b/db/migrate/060_change_changesets_committer_limit.rb new file mode 100644 index 00000000..b0509637 --- /dev/null +++ b/db/migrate/060_change_changesets_committer_limit.rb @@ -0,0 +1,9 @@ +class ChangeChangesetsCommitterLimit < ActiveRecord::Migration + def self.up + change_column :changesets, :committer, :string, :limit => nil + end + + def self.down + change_column :changesets, :committer, :string, :limit => 30 + end +end diff --git a/db/migrate/061_add_roles_builtin.rb b/db/migrate/061_add_roles_builtin.rb new file mode 100644 index 00000000..a8d6fe9e --- /dev/null +++ b/db/migrate/061_add_roles_builtin.rb @@ -0,0 +1,9 @@ +class AddRolesBuiltin < ActiveRecord::Migration + def self.up + add_column :roles, :builtin, :integer, :default => 0, :null => false + end + + def self.down + remove_column :roles, :builtin + end +end diff --git a/db/migrate/062_insert_builtin_roles.rb b/db/migrate/062_insert_builtin_roles.rb new file mode 100644 index 00000000..070d9285 --- /dev/null +++ b/db/migrate/062_insert_builtin_roles.rb @@ -0,0 +1,16 @@ +class InsertBuiltinRoles < ActiveRecord::Migration + def self.up + Role.reset_column_information + nonmember = Role.new(:name => 'Non member', :position => 0) + nonmember.builtin = Role::BUILTIN_NON_MEMBER + nonmember.save + + anonymous = Role.new(:name => 'Anonymous', :position => 0) + anonymous.builtin = Role::BUILTIN_ANONYMOUS + anonymous.save + end + + def self.down + Role.destroy_all 'builtin <> 0' + end +end diff --git a/db/migrate/063_add_roles_permissions.rb b/db/migrate/063_add_roles_permissions.rb new file mode 100644 index 00000000..107a3af0 --- /dev/null +++ b/db/migrate/063_add_roles_permissions.rb @@ -0,0 +1,9 @@ +class AddRolesPermissions < ActiveRecord::Migration + def self.up + add_column :roles, :permissions, :text + end + + def self.down + remove_column :roles, :permissions + end +end diff --git a/db/migrate/064_drop_permissions.rb b/db/migrate/064_drop_permissions.rb new file mode 100644 index 00000000..f4ca470b --- /dev/null +++ b/db/migrate/064_drop_permissions.rb @@ -0,0 +1,10 @@ +class DropPermissions < ActiveRecord::Migration + def self.up + drop_table :permissions + drop_table :permissions_roles + end + + def self.down + raise IrreversibleMigration + end +end diff --git a/db/migrate/065_add_settings_updated_on.rb b/db/migrate/065_add_settings_updated_on.rb new file mode 100644 index 00000000..1fa00277 --- /dev/null +++ b/db/migrate/065_add_settings_updated_on.rb @@ -0,0 +1,11 @@ +class AddSettingsUpdatedOn < ActiveRecord::Migration + def self.up + add_column :settings, :updated_on, :timestamp + # set updated_on + Setting.all.each(&:save) + end + + def self.down + remove_column :settings, :updated_on + end +end diff --git a/db/migrate/066_add_custom_value_customized_index.rb b/db/migrate/066_add_custom_value_customized_index.rb new file mode 100644 index 00000000..1f4c40da --- /dev/null +++ b/db/migrate/066_add_custom_value_customized_index.rb @@ -0,0 +1,9 @@ +class AddCustomValueCustomizedIndex < ActiveRecord::Migration + def self.up + add_index :custom_values, [:customized_type, :customized_id], :name => :custom_values_customized + end + + def self.down + remove_index :custom_values, :name => :custom_values_customized + end +end diff --git a/db/migrate/067_create_wiki_redirects.rb b/db/migrate/067_create_wiki_redirects.rb new file mode 100644 index 00000000..dda6ba6d --- /dev/null +++ b/db/migrate/067_create_wiki_redirects.rb @@ -0,0 +1,15 @@ +class CreateWikiRedirects < ActiveRecord::Migration + def self.up + create_table :wiki_redirects do |t| + t.column :wiki_id, :integer, :null => false + t.column :title, :string + t.column :redirects_to, :string + t.column :created_on, :datetime, :null => false + end + add_index :wiki_redirects, [:wiki_id, :title], :name => :wiki_redirects_wiki_id_title + end + + def self.down + drop_table :wiki_redirects + end +end diff --git a/db/migrate/068_create_enabled_modules.rb b/db/migrate/068_create_enabled_modules.rb new file mode 100644 index 00000000..88005cdb --- /dev/null +++ b/db/migrate/068_create_enabled_modules.rb @@ -0,0 +1,18 @@ +class CreateEnabledModules < ActiveRecord::Migration + def self.up + create_table :enabled_modules do |t| + t.column :project_id, :integer + t.column :name, :string, :null => false + end + add_index :enabled_modules, [:project_id], :name => :enabled_modules_project_id + + # Enable all modules for existing projects + Project.all.each do |project| + project.enabled_module_names = Redmine::AccessControl.available_project_modules + end + end + + def self.down + drop_table :enabled_modules + end +end diff --git a/db/migrate/069_add_issues_estimated_hours.rb b/db/migrate/069_add_issues_estimated_hours.rb new file mode 100644 index 00000000..90b86e24 --- /dev/null +++ b/db/migrate/069_add_issues_estimated_hours.rb @@ -0,0 +1,9 @@ +class AddIssuesEstimatedHours < ActiveRecord::Migration + def self.up + add_column :issues, :estimated_hours, :float + end + + def self.down + remove_column :issues, :estimated_hours + end +end diff --git a/db/migrate/070_change_attachments_content_type_limit.rb b/db/migrate/070_change_attachments_content_type_limit.rb new file mode 100644 index 00000000..ebf6d08c --- /dev/null +++ b/db/migrate/070_change_attachments_content_type_limit.rb @@ -0,0 +1,9 @@ +class ChangeAttachmentsContentTypeLimit < ActiveRecord::Migration + def self.up + change_column :attachments, :content_type, :string, :limit => nil + end + + def self.down + change_column :attachments, :content_type, :string, :limit => 60 + end +end diff --git a/db/migrate/071_add_queries_column_names.rb b/db/migrate/071_add_queries_column_names.rb new file mode 100644 index 00000000..acaf4dab --- /dev/null +++ b/db/migrate/071_add_queries_column_names.rb @@ -0,0 +1,9 @@ +class AddQueriesColumnNames < ActiveRecord::Migration + def self.up + add_column :queries, :column_names, :text + end + + def self.down + remove_column :queries, :column_names + end +end diff --git a/db/migrate/072_add_enumerations_position.rb b/db/migrate/072_add_enumerations_position.rb new file mode 100644 index 00000000..98092e5c --- /dev/null +++ b/db/migrate/072_add_enumerations_position.rb @@ -0,0 +1,15 @@ +class AddEnumerationsPosition < ActiveRecord::Migration + def self.up + add_column(:enumerations, :position, :integer, :default => 1) unless Enumeration.column_names.include?('position') + Enumeration.all.group_by(&:opt).each do |opt, enums| + enums.each_with_index do |enum, i| + # do not call model callbacks + Enumeration.update_all "position = #{i+1}", {:id => enum.id} + end + end + end + + def self.down + remove_column :enumerations, :position + end +end diff --git a/db/migrate/073_add_enumerations_is_default.rb b/db/migrate/073_add_enumerations_is_default.rb new file mode 100644 index 00000000..7365a141 --- /dev/null +++ b/db/migrate/073_add_enumerations_is_default.rb @@ -0,0 +1,9 @@ +class AddEnumerationsIsDefault < ActiveRecord::Migration + def self.up + add_column :enumerations, :is_default, :boolean, :default => false, :null => false + end + + def self.down + remove_column :enumerations, :is_default + end +end diff --git a/db/migrate/074_add_auth_sources_tls.rb b/db/migrate/074_add_auth_sources_tls.rb new file mode 100644 index 00000000..3987f703 --- /dev/null +++ b/db/migrate/074_add_auth_sources_tls.rb @@ -0,0 +1,9 @@ +class AddAuthSourcesTls < ActiveRecord::Migration + def self.up + add_column :auth_sources, :tls, :boolean, :default => false, :null => false + end + + def self.down + remove_column :auth_sources, :tls + end +end diff --git a/db/migrate/075_add_members_mail_notification.rb b/db/migrate/075_add_members_mail_notification.rb new file mode 100644 index 00000000..d83ba8dd --- /dev/null +++ b/db/migrate/075_add_members_mail_notification.rb @@ -0,0 +1,9 @@ +class AddMembersMailNotification < ActiveRecord::Migration + def self.up + add_column :members, :mail_notification, :boolean, :default => false, :null => false + end + + def self.down + remove_column :members, :mail_notification + end +end diff --git a/db/migrate/076_allow_null_position.rb b/db/migrate/076_allow_null_position.rb new file mode 100644 index 00000000..ece0370d --- /dev/null +++ b/db/migrate/076_allow_null_position.rb @@ -0,0 +1,14 @@ +class AllowNullPosition < ActiveRecord::Migration + def self.up + # removes the 'not null' constraint on position fields + change_column :issue_statuses, :position, :integer, :default => 1, :null => true + change_column :roles, :position, :integer, :default => 1, :null => true + change_column :trackers, :position, :integer, :default => 1, :null => true + change_column :boards, :position, :integer, :default => 1, :null => true + change_column :enumerations, :position, :integer, :default => 1, :null => true + end + + def self.down + # nothing to do + end +end diff --git a/db/migrate/077_remove_issue_statuses_html_color.rb b/db/migrate/077_remove_issue_statuses_html_color.rb new file mode 100644 index 00000000..a3e2c3f8 --- /dev/null +++ b/db/migrate/077_remove_issue_statuses_html_color.rb @@ -0,0 +1,9 @@ +class RemoveIssueStatusesHtmlColor < ActiveRecord::Migration + def self.up + remove_column :issue_statuses, :html_color + end + + def self.down + raise IrreversibleMigration + end +end diff --git a/db/migrate/078_add_custom_fields_position.rb b/db/migrate/078_add_custom_fields_position.rb new file mode 100644 index 00000000..cb29098f --- /dev/null +++ b/db/migrate/078_add_custom_fields_position.rb @@ -0,0 +1,15 @@ +class AddCustomFieldsPosition < ActiveRecord::Migration + def self.up + add_column(:custom_fields, :position, :integer, :default => 1) + CustomField.all.group_by(&:type).each do |t, fields| + fields.each_with_index do |field, i| + # do not call model callbacks + CustomField.update_all "position = #{i+1}", {:id => field.id} + end + end + end + + def self.down + remove_column :custom_fields, :position + end +end diff --git a/db/migrate/079_add_user_preferences_time_zone.rb b/db/migrate/079_add_user_preferences_time_zone.rb new file mode 100644 index 00000000..9e36790a --- /dev/null +++ b/db/migrate/079_add_user_preferences_time_zone.rb @@ -0,0 +1,9 @@ +class AddUserPreferencesTimeZone < ActiveRecord::Migration + def self.up + add_column :user_preferences, :time_zone, :string + end + + def self.down + remove_column :user_preferences, :time_zone + end +end diff --git a/db/migrate/080_add_users_type.rb b/db/migrate/080_add_users_type.rb new file mode 100644 index 00000000..c907b472 --- /dev/null +++ b/db/migrate/080_add_users_type.rb @@ -0,0 +1,10 @@ +class AddUsersType < ActiveRecord::Migration + def self.up + add_column :users, :type, :string + User.update_all "type = 'User'" + end + + def self.down + remove_column :users, :type + end +end diff --git a/db/migrate/081_create_projects_trackers.rb b/db/migrate/081_create_projects_trackers.rb new file mode 100644 index 00000000..ddb801d3 --- /dev/null +++ b/db/migrate/081_create_projects_trackers.rb @@ -0,0 +1,19 @@ +class CreateProjectsTrackers < ActiveRecord::Migration + def self.up + create_table :projects_trackers, :id => false do |t| + t.column :project_id, :integer, :default => 0, :null => false + t.column :tracker_id, :integer, :default => 0, :null => false + end + add_index :projects_trackers, :project_id, :name => :projects_trackers_project_id + + # Associates all trackers to all projects (as it was before) + tracker_ids = Tracker.all.collect(&:id) + Project.all.each do |project| + project.tracker_ids = tracker_ids + end + end + + def self.down + drop_table :projects_trackers + end +end diff --git a/db/migrate/082_add_messages_locked.rb b/db/migrate/082_add_messages_locked.rb new file mode 100644 index 00000000..20a17256 --- /dev/null +++ b/db/migrate/082_add_messages_locked.rb @@ -0,0 +1,9 @@ +class AddMessagesLocked < ActiveRecord::Migration + def self.up + add_column :messages, :locked, :boolean, :default => false + end + + def self.down + remove_column :messages, :locked + end +end diff --git a/db/migrate/083_add_messages_sticky.rb b/db/migrate/083_add_messages_sticky.rb new file mode 100644 index 00000000..8fd5d2ce --- /dev/null +++ b/db/migrate/083_add_messages_sticky.rb @@ -0,0 +1,9 @@ +class AddMessagesSticky < ActiveRecord::Migration + def self.up + add_column :messages, :sticky, :integer, :default => 0 + end + + def self.down + remove_column :messages, :sticky + end +end diff --git a/db/migrate/084_change_auth_sources_account_limit.rb b/db/migrate/084_change_auth_sources_account_limit.rb new file mode 100644 index 00000000..cc127b43 --- /dev/null +++ b/db/migrate/084_change_auth_sources_account_limit.rb @@ -0,0 +1,9 @@ +class ChangeAuthSourcesAccountLimit < ActiveRecord::Migration + def self.up + change_column :auth_sources, :account, :string, :limit => nil + end + + def self.down + change_column :auth_sources, :account, :string, :limit => 60 + end +end diff --git a/db/migrate/085_add_role_tracker_old_status_index_to_workflows.rb b/db/migrate/085_add_role_tracker_old_status_index_to_workflows.rb new file mode 100644 index 00000000..a59135be --- /dev/null +++ b/db/migrate/085_add_role_tracker_old_status_index_to_workflows.rb @@ -0,0 +1,9 @@ +class AddRoleTrackerOldStatusIndexToWorkflows < ActiveRecord::Migration + def self.up + add_index :workflows, [:role_id, :tracker_id, :old_status_id], :name => :wkfs_role_tracker_old_status + end + + def self.down + remove_index(:workflows, :name => :wkfs_role_tracker_old_status); rescue + end +end diff --git a/db/migrate/086_add_custom_fields_searchable.rb b/db/migrate/086_add_custom_fields_searchable.rb new file mode 100644 index 00000000..53158d14 --- /dev/null +++ b/db/migrate/086_add_custom_fields_searchable.rb @@ -0,0 +1,9 @@ +class AddCustomFieldsSearchable < ActiveRecord::Migration + def self.up + add_column :custom_fields, :searchable, :boolean, :default => false + end + + def self.down + remove_column :custom_fields, :searchable + end +end diff --git a/db/migrate/087_change_projects_description_to_text.rb b/db/migrate/087_change_projects_description_to_text.rb new file mode 100644 index 00000000..132e921b --- /dev/null +++ b/db/migrate/087_change_projects_description_to_text.rb @@ -0,0 +1,8 @@ +class ChangeProjectsDescriptionToText < ActiveRecord::Migration + def self.up + change_column :projects, :description, :text, :null => true, :default => nil + end + + def self.down + end +end diff --git a/db/migrate/088_add_custom_fields_default_value.rb b/db/migrate/088_add_custom_fields_default_value.rb new file mode 100644 index 00000000..33a39ec6 --- /dev/null +++ b/db/migrate/088_add_custom_fields_default_value.rb @@ -0,0 +1,9 @@ +class AddCustomFieldsDefaultValue < ActiveRecord::Migration + def self.up + add_column :custom_fields, :default_value, :text + end + + def self.down + remove_column :custom_fields, :default_value + end +end diff --git a/db/migrate/089_add_attachments_description.rb b/db/migrate/089_add_attachments_description.rb new file mode 100644 index 00000000..411dfe4d --- /dev/null +++ b/db/migrate/089_add_attachments_description.rb @@ -0,0 +1,9 @@ +class AddAttachmentsDescription < ActiveRecord::Migration + def self.up + add_column :attachments, :description, :string + end + + def self.down + remove_column :attachments, :description + end +end diff --git a/db/migrate/090_change_versions_name_limit.rb b/db/migrate/090_change_versions_name_limit.rb new file mode 100644 index 00000000..27642972 --- /dev/null +++ b/db/migrate/090_change_versions_name_limit.rb @@ -0,0 +1,9 @@ +class ChangeVersionsNameLimit < ActiveRecord::Migration + def self.up + change_column :versions, :name, :string, :limit => nil + end + + def self.down + change_column :versions, :name, :string, :limit => 30 + end +end diff --git a/db/migrate/091_change_changesets_revision_to_string.rb b/db/migrate/091_change_changesets_revision_to_string.rb new file mode 100644 index 00000000..64988069 --- /dev/null +++ b/db/migrate/091_change_changesets_revision_to_string.rb @@ -0,0 +1,32 @@ +class ChangeChangesetsRevisionToString < ActiveRecord::Migration + def self.up + # Some backends (eg. SQLServer 2012) do not support changing the type + # of an indexed column so the index needs to be dropped first + # BUT this index is renamed with some backends (at least SQLite3) for + # some (unknown) reasons, thus we check for the other name as well + # so we don't end up with 2 identical indexes + if index_exists? :changesets, [:repository_id, :revision], :name => :changesets_repos_rev + remove_index :changesets, :name => :changesets_repos_rev + end + if index_exists? :changesets, [:repository_id, :revision], :name => :altered_changesets_repos_rev + remove_index :changesets, :name => :altered_changesets_repos_rev + end + + change_column :changesets, :revision, :string, :null => false + + add_index :changesets, [:repository_id, :revision], :unique => true, :name => :changesets_repos_rev + end + + def self.down + if index_exists? :changesets, :changesets_repos_rev + remove_index :changesets, :name => :changesets_repos_rev + end + if index_exists? :changesets, [:repository_id, :revision], :name => :altered_changesets_repos_rev + remove_index :changesets, :name => :altered_changesets_repos_rev + end + + change_column :changesets, :revision, :integer, :null => false + + add_index :changesets, [:repository_id, :revision], :unique => true, :name => :changesets_repos_rev + end +end diff --git a/db/migrate/092_change_changes_from_revision_to_string.rb b/db/migrate/092_change_changes_from_revision_to_string.rb new file mode 100644 index 00000000..b298a3f4 --- /dev/null +++ b/db/migrate/092_change_changes_from_revision_to_string.rb @@ -0,0 +1,9 @@ +class ChangeChangesFromRevisionToString < ActiveRecord::Migration + def self.up + change_column :changes, :from_revision, :string + end + + def self.down + change_column :changes, :from_revision, :integer + end +end diff --git a/db/migrate/093_add_wiki_pages_protected.rb b/db/migrate/093_add_wiki_pages_protected.rb new file mode 100644 index 00000000..49720fbb --- /dev/null +++ b/db/migrate/093_add_wiki_pages_protected.rb @@ -0,0 +1,9 @@ +class AddWikiPagesProtected < ActiveRecord::Migration + def self.up + add_column :wiki_pages, :protected, :boolean, :default => false, :null => false + end + + def self.down + remove_column :wiki_pages, :protected + end +end diff --git a/db/migrate/094_change_projects_homepage_limit.rb b/db/migrate/094_change_projects_homepage_limit.rb new file mode 100644 index 00000000..98374aa4 --- /dev/null +++ b/db/migrate/094_change_projects_homepage_limit.rb @@ -0,0 +1,9 @@ +class ChangeProjectsHomepageLimit < ActiveRecord::Migration + def self.up + change_column :projects, :homepage, :string, :limit => nil, :default => '' + end + + def self.down + change_column :projects, :homepage, :string, :limit => 60, :default => '' + end +end diff --git a/db/migrate/095_add_wiki_pages_parent_id.rb b/db/migrate/095_add_wiki_pages_parent_id.rb new file mode 100644 index 00000000..36b922ec --- /dev/null +++ b/db/migrate/095_add_wiki_pages_parent_id.rb @@ -0,0 +1,9 @@ +class AddWikiPagesParentId < ActiveRecord::Migration + def self.up + add_column :wiki_pages, :parent_id, :integer, :default => nil + end + + def self.down + remove_column :wiki_pages, :parent_id + end +end diff --git a/db/migrate/096_add_commit_access_permission.rb b/db/migrate/096_add_commit_access_permission.rb new file mode 100644 index 00000000..39642cdf --- /dev/null +++ b/db/migrate/096_add_commit_access_permission.rb @@ -0,0 +1,13 @@ +class AddCommitAccessPermission < ActiveRecord::Migration + def self.up + Role.all.select { |r| not r.builtin? }.each do |r| + r.add_permission!(:commit_access) + end + end + + def self.down + Role.all.select { |r| not r.builtin? }.each do |r| + r.remove_permission!(:commit_access) + end + end +end diff --git a/db/migrate/097_add_view_wiki_edits_permission.rb b/db/migrate/097_add_view_wiki_edits_permission.rb new file mode 100644 index 00000000..cd25f3cb --- /dev/null +++ b/db/migrate/097_add_view_wiki_edits_permission.rb @@ -0,0 +1,13 @@ +class AddViewWikiEditsPermission < ActiveRecord::Migration + def self.up + Role.all.each do |r| + r.add_permission!(:view_wiki_edits) if r.has_permission?(:view_wiki_pages) + end + end + + def self.down + Role.all.each do |r| + r.remove_permission!(:view_wiki_edits) + end + end +end diff --git a/db/migrate/098_set_topic_authors_as_watchers.rb b/db/migrate/098_set_topic_authors_as_watchers.rb new file mode 100644 index 00000000..92a53f4a --- /dev/null +++ b/db/migrate/098_set_topic_authors_as_watchers.rb @@ -0,0 +1,15 @@ +class SetTopicAuthorsAsWatchers < ActiveRecord::Migration + def self.up + # Sets active users who created/replied a topic as watchers of the topic + # so that the new watch functionality at topic level doesn't affect notifications behaviour + Message.connection.execute("INSERT INTO #{Watcher.table_name} (watchable_type, watchable_id, user_id)" + + " SELECT DISTINCT 'Message', COALESCE(m.parent_id, m.id), m.author_id" + + " FROM #{Message.table_name} m, #{User.table_name} u" + + " WHERE m.author_id = u.id AND u.status = 1") + end + + def self.down + # Removes all message watchers + Watcher.delete_all("watchable_type = 'Message'") + end +end diff --git a/db/migrate/099_add_delete_wiki_pages_attachments_permission.rb b/db/migrate/099_add_delete_wiki_pages_attachments_permission.rb new file mode 100644 index 00000000..475e4d0a --- /dev/null +++ b/db/migrate/099_add_delete_wiki_pages_attachments_permission.rb @@ -0,0 +1,13 @@ +class AddDeleteWikiPagesAttachmentsPermission < ActiveRecord::Migration + def self.up + Role.all.each do |r| + r.add_permission!(:delete_wiki_pages_attachments) if r.has_permission?(:edit_wiki_pages) + end + end + + def self.down + Role.all.each do |r| + r.remove_permission!(:delete_wiki_pages_attachments) + end + end +end diff --git a/db/migrate/100_add_changesets_user_id.rb b/db/migrate/100_add_changesets_user_id.rb new file mode 100644 index 00000000..9b25fd7b --- /dev/null +++ b/db/migrate/100_add_changesets_user_id.rb @@ -0,0 +1,9 @@ +class AddChangesetsUserId < ActiveRecord::Migration + def self.up + add_column :changesets, :user_id, :integer, :default => nil + end + + def self.down + remove_column :changesets, :user_id + end +end diff --git a/db/migrate/101_populate_changesets_user_id.rb b/db/migrate/101_populate_changesets_user_id.rb new file mode 100644 index 00000000..dd493d17 --- /dev/null +++ b/db/migrate/101_populate_changesets_user_id.rb @@ -0,0 +1,18 @@ +class PopulateChangesetsUserId < ActiveRecord::Migration + def self.up + committers = Changeset.connection.select_values("SELECT DISTINCT committer FROM #{Changeset.table_name}") + committers.each do |committer| + next if committer.blank? + if committer.strip =~ /^([^<]+)(<(.*)>)?$/ + username, email = $1.strip, $3 + u = User.find_by_login(username) + u ||= User.find_by_mail(email) unless email.blank? + Changeset.update_all("user_id = #{u.id}", ["committer = ?", committer]) unless u.nil? + end + end + end + + def self.down + Changeset.update_all('user_id = NULL') + end +end diff --git a/db/migrate/102_add_custom_fields_editable.rb b/db/migrate/102_add_custom_fields_editable.rb new file mode 100644 index 00000000..949f9db9 --- /dev/null +++ b/db/migrate/102_add_custom_fields_editable.rb @@ -0,0 +1,9 @@ +class AddCustomFieldsEditable < ActiveRecord::Migration + def self.up + add_column :custom_fields, :editable, :boolean, :default => true + end + + def self.down + remove_column :custom_fields, :editable + end +end diff --git a/db/migrate/103_set_custom_fields_editable.rb b/db/migrate/103_set_custom_fields_editable.rb new file mode 100644 index 00000000..937649e6 --- /dev/null +++ b/db/migrate/103_set_custom_fields_editable.rb @@ -0,0 +1,9 @@ +class SetCustomFieldsEditable < ActiveRecord::Migration + def self.up + UserCustomField.update_all("editable = #{CustomField.connection.quoted_false}") + end + + def self.down + UserCustomField.update_all("editable = #{CustomField.connection.quoted_true}") + end +end diff --git a/db/migrate/104_add_projects_lft_and_rgt.rb b/db/migrate/104_add_projects_lft_and_rgt.rb new file mode 100644 index 00000000..8952c16e --- /dev/null +++ b/db/migrate/104_add_projects_lft_and_rgt.rb @@ -0,0 +1,11 @@ +class AddProjectsLftAndRgt < ActiveRecord::Migration + def self.up + add_column :projects, :lft, :integer + add_column :projects, :rgt, :integer + end + + def self.down + remove_column :projects, :lft + remove_column :projects, :rgt + end +end diff --git a/db/migrate/105_build_projects_tree.rb b/db/migrate/105_build_projects_tree.rb new file mode 100644 index 00000000..cd35373c --- /dev/null +++ b/db/migrate/105_build_projects_tree.rb @@ -0,0 +1,8 @@ +class BuildProjectsTree < ActiveRecord::Migration + def self.up + Project.rebuild_tree! + end + + def self.down + end +end diff --git a/db/migrate/106_remove_projects_projects_count.rb b/db/migrate/106_remove_projects_projects_count.rb new file mode 100644 index 00000000..68bb3d11 --- /dev/null +++ b/db/migrate/106_remove_projects_projects_count.rb @@ -0,0 +1,9 @@ +class RemoveProjectsProjectsCount < ActiveRecord::Migration + def self.up + remove_column :projects, :projects_count + end + + def self.down + add_column :projects, :projects_count, :integer, :default => 0 + end +end diff --git a/db/migrate/107_add_open_id_authentication_tables.rb b/db/migrate/107_add_open_id_authentication_tables.rb new file mode 100644 index 00000000..caae0d8c --- /dev/null +++ b/db/migrate/107_add_open_id_authentication_tables.rb @@ -0,0 +1,20 @@ +class AddOpenIdAuthenticationTables < ActiveRecord::Migration + def self.up + create_table :open_id_authentication_associations, :force => true do |t| + t.integer :issued, :lifetime + t.string :handle, :assoc_type + t.binary :server_url, :secret + end + + create_table :open_id_authentication_nonces, :force => true do |t| + t.integer :timestamp, :null => false + t.string :server_url, :null => true + t.string :salt, :null => false + end + end + + def self.down + drop_table :open_id_authentication_associations + drop_table :open_id_authentication_nonces + end +end diff --git a/db/migrate/108_add_identity_url_to_users.rb b/db/migrate/108_add_identity_url_to_users.rb new file mode 100644 index 00000000..f5af77b2 --- /dev/null +++ b/db/migrate/108_add_identity_url_to_users.rb @@ -0,0 +1,9 @@ +class AddIdentityUrlToUsers < ActiveRecord::Migration + def self.up + add_column :users, :identity_url, :string + end + + def self.down + remove_column :users, :identity_url + end +end diff --git a/db/migrate/20090214190337_add_watchers_user_id_type_index.rb b/db/migrate/20090214190337_add_watchers_user_id_type_index.rb new file mode 100644 index 00000000..7ff4e542 --- /dev/null +++ b/db/migrate/20090214190337_add_watchers_user_id_type_index.rb @@ -0,0 +1,9 @@ +class AddWatchersUserIdTypeIndex < ActiveRecord::Migration + def self.up + add_index :watchers, [:user_id, :watchable_type], :name => :watchers_user_id_type + end + + def self.down + remove_index :watchers, :name => :watchers_user_id_type + end +end diff --git a/db/migrate/20090312172426_add_queries_sort_criteria.rb b/db/migrate/20090312172426_add_queries_sort_criteria.rb new file mode 100644 index 00000000..743ed42f --- /dev/null +++ b/db/migrate/20090312172426_add_queries_sort_criteria.rb @@ -0,0 +1,9 @@ +class AddQueriesSortCriteria < ActiveRecord::Migration + def self.up + add_column :queries, :sort_criteria, :text + end + + def self.down + remove_column :queries, :sort_criteria + end +end diff --git a/db/migrate/20090312194159_add_projects_trackers_unique_index.rb b/db/migrate/20090312194159_add_projects_trackers_unique_index.rb new file mode 100644 index 00000000..f4e3a26d --- /dev/null +++ b/db/migrate/20090312194159_add_projects_trackers_unique_index.rb @@ -0,0 +1,21 @@ +class AddProjectsTrackersUniqueIndex < ActiveRecord::Migration + def self.up + remove_duplicates + add_index :projects_trackers, [:project_id, :tracker_id], :name => :projects_trackers_unique, :unique => true + end + + def self.down + remove_index :projects_trackers, :name => :projects_trackers_unique + end + + # Removes duplicates in projects_trackers table + def self.remove_duplicates + Project.all.each do |project| + ids = project.trackers.collect(&:id) + unless ids == ids.uniq + project.trackers.clear + project.tracker_ids = ids.uniq + end + end + end +end diff --git a/db/migrate/20090318181151_extend_settings_name.rb b/db/migrate/20090318181151_extend_settings_name.rb new file mode 100644 index 00000000..eca03d55 --- /dev/null +++ b/db/migrate/20090318181151_extend_settings_name.rb @@ -0,0 +1,9 @@ +class ExtendSettingsName < ActiveRecord::Migration + def self.up + change_column :settings, :name, :string, :limit => 255, :default => '', :null => false + end + + def self.down + raise ActiveRecord::IrreversibleMigration + end +end diff --git a/db/migrate/20090323224724_add_type_to_enumerations.rb b/db/migrate/20090323224724_add_type_to_enumerations.rb new file mode 100644 index 00000000..c2aef5e4 --- /dev/null +++ b/db/migrate/20090323224724_add_type_to_enumerations.rb @@ -0,0 +1,9 @@ +class AddTypeToEnumerations < ActiveRecord::Migration + def self.up + add_column :enumerations, :type, :string + end + + def self.down + remove_column :enumerations, :type + end +end diff --git a/db/migrate/20090401221305_update_enumerations_to_sti.rb b/db/migrate/20090401221305_update_enumerations_to_sti.rb new file mode 100644 index 00000000..50bd5201 --- /dev/null +++ b/db/migrate/20090401221305_update_enumerations_to_sti.rb @@ -0,0 +1,11 @@ +class UpdateEnumerationsToSti < ActiveRecord::Migration + def self.up + Enumeration.update_all("type = 'IssuePriority'", "opt = 'IPRI'") + Enumeration.update_all("type = 'DocumentCategory'", "opt = 'DCAT'") + Enumeration.update_all("type = 'TimeEntryActivity'", "opt = 'ACTI'") + end + + def self.down + # no-op + end +end diff --git a/db/migrate/20090401231134_add_active_field_to_enumerations.rb b/db/migrate/20090401231134_add_active_field_to_enumerations.rb new file mode 100644 index 00000000..55824fa6 --- /dev/null +++ b/db/migrate/20090401231134_add_active_field_to_enumerations.rb @@ -0,0 +1,9 @@ +class AddActiveFieldToEnumerations < ActiveRecord::Migration + def self.up + add_column :enumerations, :active, :boolean, :default => true, :null => false + end + + def self.down + remove_column :enumerations, :active + end +end diff --git a/db/migrate/20090403001910_add_project_to_enumerations.rb b/db/migrate/20090403001910_add_project_to_enumerations.rb new file mode 100644 index 00000000..a3db6d51 --- /dev/null +++ b/db/migrate/20090403001910_add_project_to_enumerations.rb @@ -0,0 +1,11 @@ +class AddProjectToEnumerations < ActiveRecord::Migration + def self.up + add_column :enumerations, :project_id, :integer, :null => true, :default => nil + add_index :enumerations, :project_id + end + + def self.down + remove_index :enumerations, :project_id + remove_column :enumerations, :project_id + end +end diff --git a/db/migrate/20090406161854_add_parent_id_to_enumerations.rb b/db/migrate/20090406161854_add_parent_id_to_enumerations.rb new file mode 100644 index 00000000..2c1b1780 --- /dev/null +++ b/db/migrate/20090406161854_add_parent_id_to_enumerations.rb @@ -0,0 +1,9 @@ +class AddParentIdToEnumerations < ActiveRecord::Migration + def self.up + add_column :enumerations, :parent_id, :integer, :null => true, :default => nil + end + + def self.down + remove_column :enumerations, :parent_id + end +end diff --git a/db/migrate/20090425161243_add_queries_group_by.rb b/db/migrate/20090425161243_add_queries_group_by.rb new file mode 100644 index 00000000..1405f3d0 --- /dev/null +++ b/db/migrate/20090425161243_add_queries_group_by.rb @@ -0,0 +1,9 @@ +class AddQueriesGroupBy < ActiveRecord::Migration + def self.up + add_column :queries, :group_by, :string + end + + def self.down + remove_column :queries, :group_by + end +end diff --git a/db/migrate/20090503121501_create_member_roles.rb b/db/migrate/20090503121501_create_member_roles.rb new file mode 100644 index 00000000..38519ea7 --- /dev/null +++ b/db/migrate/20090503121501_create_member_roles.rb @@ -0,0 +1,12 @@ +class CreateMemberRoles < ActiveRecord::Migration + def self.up + create_table :member_roles do |t| + t.column :member_id, :integer, :null => false + t.column :role_id, :integer, :null => false + end + end + + def self.down + drop_table :member_roles + end +end diff --git a/db/migrate/20090503121505_populate_member_roles.rb b/db/migrate/20090503121505_populate_member_roles.rb new file mode 100644 index 00000000..285d7e51 --- /dev/null +++ b/db/migrate/20090503121505_populate_member_roles.rb @@ -0,0 +1,12 @@ +class PopulateMemberRoles < ActiveRecord::Migration + def self.up + MemberRole.delete_all + Member.all.each do |member| + MemberRole.create!(:member_id => member.id, :role_id => member.role_id) + end + end + + def self.down + MemberRole.delete_all + end +end diff --git a/db/migrate/20090503121510_drop_members_role_id.rb b/db/migrate/20090503121510_drop_members_role_id.rb new file mode 100644 index 00000000..c2811991 --- /dev/null +++ b/db/migrate/20090503121510_drop_members_role_id.rb @@ -0,0 +1,9 @@ +class DropMembersRoleId < ActiveRecord::Migration + def self.up + remove_column :members, :role_id + end + + def self.down + raise IrreversibleMigration + end +end diff --git a/db/migrate/20090614091200_fix_messages_sticky_null.rb b/db/migrate/20090614091200_fix_messages_sticky_null.rb new file mode 100644 index 00000000..cbe74173 --- /dev/null +++ b/db/migrate/20090614091200_fix_messages_sticky_null.rb @@ -0,0 +1,9 @@ +class FixMessagesStickyNull < ActiveRecord::Migration + def self.up + Message.update_all('sticky = 0', 'sticky IS NULL') + end + + def self.down + # nothing to do + end +end diff --git a/db/migrate/20090704172350_populate_users_type.rb b/db/migrate/20090704172350_populate_users_type.rb new file mode 100644 index 00000000..1c31fece --- /dev/null +++ b/db/migrate/20090704172350_populate_users_type.rb @@ -0,0 +1,8 @@ +class PopulateUsersType < ActiveRecord::Migration + def self.up + Principal.update_all("type = 'User'", "type IS NULL") + end + + def self.down + end +end diff --git a/db/migrate/20090704172355_create_groups_users.rb b/db/migrate/20090704172355_create_groups_users.rb new file mode 100644 index 00000000..9ce03b95 --- /dev/null +++ b/db/migrate/20090704172355_create_groups_users.rb @@ -0,0 +1,13 @@ +class CreateGroupsUsers < ActiveRecord::Migration + def self.up + create_table :groups_users, :id => false do |t| + t.column :group_id, :integer, :null => false + t.column :user_id, :integer, :null => false + end + add_index :groups_users, [:group_id, :user_id], :unique => true, :name => :groups_users_ids + end + + def self.down + drop_table :groups_users + end +end diff --git a/db/migrate/20090704172358_add_member_roles_inherited_from.rb b/db/migrate/20090704172358_add_member_roles_inherited_from.rb new file mode 100644 index 00000000..4ffa5238 --- /dev/null +++ b/db/migrate/20090704172358_add_member_roles_inherited_from.rb @@ -0,0 +1,9 @@ +class AddMemberRolesInheritedFrom < ActiveRecord::Migration + def self.up + add_column :member_roles, :inherited_from, :integer + end + + def self.down + remove_column :member_roles, :inherited_from + end +end diff --git a/db/migrate/20091010093521_fix_users_custom_values.rb b/db/migrate/20091010093521_fix_users_custom_values.rb new file mode 100644 index 00000000..923c78fc --- /dev/null +++ b/db/migrate/20091010093521_fix_users_custom_values.rb @@ -0,0 +1,9 @@ +class FixUsersCustomValues < ActiveRecord::Migration + def self.up + CustomValue.update_all("customized_type = 'Principal'", "customized_type = 'User'") + end + + def self.down + CustomValue.update_all("customized_type = 'User'", "customized_type = 'Principal'") + end +end diff --git a/db/migrate/20091017212227_add_missing_indexes_to_workflows.rb b/db/migrate/20091017212227_add_missing_indexes_to_workflows.rb new file mode 100644 index 00000000..13fa0137 --- /dev/null +++ b/db/migrate/20091017212227_add_missing_indexes_to_workflows.rb @@ -0,0 +1,13 @@ +class AddMissingIndexesToWorkflows < ActiveRecord::Migration + def self.up + add_index :workflows, :old_status_id + add_index :workflows, :role_id + add_index :workflows, :new_status_id + end + + def self.down + remove_index :workflows, :old_status_id + remove_index :workflows, :role_id + remove_index :workflows, :new_status_id + end +end diff --git a/db/migrate/20091017212457_add_missing_indexes_to_custom_fields_projects.rb b/db/migrate/20091017212457_add_missing_indexes_to_custom_fields_projects.rb new file mode 100644 index 00000000..b95f5432 --- /dev/null +++ b/db/migrate/20091017212457_add_missing_indexes_to_custom_fields_projects.rb @@ -0,0 +1,9 @@ +class AddMissingIndexesToCustomFieldsProjects < ActiveRecord::Migration + def self.up + add_index :custom_fields_projects, [:custom_field_id, :project_id] + end + + def self.down + remove_index :custom_fields_projects, :column => [:custom_field_id, :project_id] + end +end diff --git a/db/migrate/20091017212644_add_missing_indexes_to_messages.rb b/db/migrate/20091017212644_add_missing_indexes_to_messages.rb new file mode 100644 index 00000000..23c27299 --- /dev/null +++ b/db/migrate/20091017212644_add_missing_indexes_to_messages.rb @@ -0,0 +1,11 @@ +class AddMissingIndexesToMessages < ActiveRecord::Migration + def self.up + add_index :messages, :last_reply_id + add_index :messages, :author_id + end + + def self.down + remove_index :messages, :last_reply_id + remove_index :messages, :author_id + end +end diff --git a/db/migrate/20091017212938_add_missing_indexes_to_repositories.rb b/db/migrate/20091017212938_add_missing_indexes_to_repositories.rb new file mode 100644 index 00000000..b9f43b6d --- /dev/null +++ b/db/migrate/20091017212938_add_missing_indexes_to_repositories.rb @@ -0,0 +1,9 @@ +class AddMissingIndexesToRepositories < ActiveRecord::Migration + def self.up + add_index :repositories, :project_id + end + + def self.down + remove_index :repositories, :project_id + end +end diff --git a/db/migrate/20091017213027_add_missing_indexes_to_comments.rb b/db/migrate/20091017213027_add_missing_indexes_to_comments.rb new file mode 100644 index 00000000..2a1ed27c --- /dev/null +++ b/db/migrate/20091017213027_add_missing_indexes_to_comments.rb @@ -0,0 +1,11 @@ +class AddMissingIndexesToComments < ActiveRecord::Migration + def self.up + add_index :comments, [:commented_id, :commented_type] + add_index :comments, :author_id + end + + def self.down + remove_index :comments, :column => [:commented_id, :commented_type] + remove_index :comments, :author_id + end +end diff --git a/db/migrate/20091017213113_add_missing_indexes_to_enumerations.rb b/db/migrate/20091017213113_add_missing_indexes_to_enumerations.rb new file mode 100644 index 00000000..85dedf81 --- /dev/null +++ b/db/migrate/20091017213113_add_missing_indexes_to_enumerations.rb @@ -0,0 +1,9 @@ +class AddMissingIndexesToEnumerations < ActiveRecord::Migration + def self.up + add_index :enumerations, [:id, :type] + end + + def self.down + remove_index :enumerations, :column => [:id, :type] + end +end diff --git a/db/migrate/20091017213151_add_missing_indexes_to_wiki_pages.rb b/db/migrate/20091017213151_add_missing_indexes_to_wiki_pages.rb new file mode 100644 index 00000000..7fab09e3 --- /dev/null +++ b/db/migrate/20091017213151_add_missing_indexes_to_wiki_pages.rb @@ -0,0 +1,11 @@ +class AddMissingIndexesToWikiPages < ActiveRecord::Migration + def self.up + add_index :wiki_pages, :wiki_id + add_index :wiki_pages, :parent_id + end + + def self.down + remove_index :wiki_pages, :wiki_id + remove_index :wiki_pages, :parent_id + end +end diff --git a/db/migrate/20091017213228_add_missing_indexes_to_watchers.rb b/db/migrate/20091017213228_add_missing_indexes_to_watchers.rb new file mode 100644 index 00000000..618e1cd9 --- /dev/null +++ b/db/migrate/20091017213228_add_missing_indexes_to_watchers.rb @@ -0,0 +1,11 @@ +class AddMissingIndexesToWatchers < ActiveRecord::Migration + def self.up + add_index :watchers, :user_id + add_index :watchers, [:watchable_id, :watchable_type] + end + + def self.down + remove_index :watchers, :user_id + remove_index :watchers, :column => [:watchable_id, :watchable_type] + end +end diff --git a/db/migrate/20091017213257_add_missing_indexes_to_auth_sources.rb b/db/migrate/20091017213257_add_missing_indexes_to_auth_sources.rb new file mode 100644 index 00000000..ccd4f044 --- /dev/null +++ b/db/migrate/20091017213257_add_missing_indexes_to_auth_sources.rb @@ -0,0 +1,9 @@ +class AddMissingIndexesToAuthSources < ActiveRecord::Migration + def self.up + add_index :auth_sources, [:id, :type] + end + + def self.down + remove_index :auth_sources, :column => [:id, :type] + end +end diff --git a/db/migrate/20091017213332_add_missing_indexes_to_documents.rb b/db/migrate/20091017213332_add_missing_indexes_to_documents.rb new file mode 100644 index 00000000..f5190181 --- /dev/null +++ b/db/migrate/20091017213332_add_missing_indexes_to_documents.rb @@ -0,0 +1,9 @@ +class AddMissingIndexesToDocuments < ActiveRecord::Migration + def self.up + add_index :documents, :category_id + end + + def self.down + remove_index :documents, :category_id + end +end diff --git a/db/migrate/20091017213444_add_missing_indexes_to_tokens.rb b/db/migrate/20091017213444_add_missing_indexes_to_tokens.rb new file mode 100644 index 00000000..f0979f21 --- /dev/null +++ b/db/migrate/20091017213444_add_missing_indexes_to_tokens.rb @@ -0,0 +1,9 @@ +class AddMissingIndexesToTokens < ActiveRecord::Migration + def self.up + add_index :tokens, :user_id + end + + def self.down + remove_index :tokens, :user_id + end +end diff --git a/db/migrate/20091017213536_add_missing_indexes_to_changesets.rb b/db/migrate/20091017213536_add_missing_indexes_to_changesets.rb new file mode 100644 index 00000000..303be838 --- /dev/null +++ b/db/migrate/20091017213536_add_missing_indexes_to_changesets.rb @@ -0,0 +1,11 @@ +class AddMissingIndexesToChangesets < ActiveRecord::Migration + def self.up + add_index :changesets, :user_id + add_index :changesets, :repository_id + end + + def self.down + remove_index :changesets, :user_id + remove_index :changesets, :repository_id + end +end diff --git a/db/migrate/20091017213642_add_missing_indexes_to_issue_categories.rb b/db/migrate/20091017213642_add_missing_indexes_to_issue_categories.rb new file mode 100644 index 00000000..3f5b2b18 --- /dev/null +++ b/db/migrate/20091017213642_add_missing_indexes_to_issue_categories.rb @@ -0,0 +1,9 @@ +class AddMissingIndexesToIssueCategories < ActiveRecord::Migration + def self.up + add_index :issue_categories, :assigned_to_id + end + + def self.down + remove_index :issue_categories, :assigned_to_id + end +end diff --git a/db/migrate/20091017213716_add_missing_indexes_to_member_roles.rb b/db/migrate/20091017213716_add_missing_indexes_to_member_roles.rb new file mode 100644 index 00000000..e9ff62db --- /dev/null +++ b/db/migrate/20091017213716_add_missing_indexes_to_member_roles.rb @@ -0,0 +1,11 @@ +class AddMissingIndexesToMemberRoles < ActiveRecord::Migration + def self.up + add_index :member_roles, :member_id + add_index :member_roles, :role_id + end + + def self.down + remove_index :member_roles, :member_id + remove_index :member_roles, :role_id + end +end diff --git a/db/migrate/20091017213757_add_missing_indexes_to_boards.rb b/db/migrate/20091017213757_add_missing_indexes_to_boards.rb new file mode 100644 index 00000000..d3e94226 --- /dev/null +++ b/db/migrate/20091017213757_add_missing_indexes_to_boards.rb @@ -0,0 +1,9 @@ +class AddMissingIndexesToBoards < ActiveRecord::Migration + def self.up + add_index :boards, :last_message_id + end + + def self.down + remove_index :boards, :last_message_id + end +end diff --git a/db/migrate/20091017213835_add_missing_indexes_to_user_preferences.rb b/db/migrate/20091017213835_add_missing_indexes_to_user_preferences.rb new file mode 100644 index 00000000..f3a8ccbc --- /dev/null +++ b/db/migrate/20091017213835_add_missing_indexes_to_user_preferences.rb @@ -0,0 +1,9 @@ +class AddMissingIndexesToUserPreferences < ActiveRecord::Migration + def self.up + add_index :user_preferences, :user_id + end + + def self.down + remove_index :user_preferences, :user_id + end +end diff --git a/db/migrate/20091017213910_add_missing_indexes_to_issues.rb b/db/migrate/20091017213910_add_missing_indexes_to_issues.rb new file mode 100644 index 00000000..d651a546 --- /dev/null +++ b/db/migrate/20091017213910_add_missing_indexes_to_issues.rb @@ -0,0 +1,21 @@ +class AddMissingIndexesToIssues < ActiveRecord::Migration + def self.up + add_index :issues, :status_id + add_index :issues, :category_id + add_index :issues, :assigned_to_id + add_index :issues, :fixed_version_id + add_index :issues, :tracker_id + add_index :issues, :priority_id + add_index :issues, :author_id + end + + def self.down + remove_index :issues, :status_id + remove_index :issues, :category_id + remove_index :issues, :assigned_to_id + remove_index :issues, :fixed_version_id + remove_index :issues, :tracker_id + remove_index :issues, :priority_id + remove_index :issues, :author_id + end +end diff --git a/db/migrate/20091017214015_add_missing_indexes_to_members.rb b/db/migrate/20091017214015_add_missing_indexes_to_members.rb new file mode 100644 index 00000000..5fdf560f --- /dev/null +++ b/db/migrate/20091017214015_add_missing_indexes_to_members.rb @@ -0,0 +1,11 @@ +class AddMissingIndexesToMembers < ActiveRecord::Migration + def self.up + add_index :members, :user_id + add_index :members, :project_id + end + + def self.down + remove_index :members, :user_id + remove_index :members, :project_id + end +end diff --git a/db/migrate/20091017214107_add_missing_indexes_to_custom_fields.rb b/db/migrate/20091017214107_add_missing_indexes_to_custom_fields.rb new file mode 100644 index 00000000..18be0b44 --- /dev/null +++ b/db/migrate/20091017214107_add_missing_indexes_to_custom_fields.rb @@ -0,0 +1,9 @@ +class AddMissingIndexesToCustomFields < ActiveRecord::Migration + def self.up + add_index :custom_fields, [:id, :type] + end + + def self.down + remove_index :custom_fields, :column => [:id, :type] + end +end diff --git a/db/migrate/20091017214136_add_missing_indexes_to_queries.rb b/db/migrate/20091017214136_add_missing_indexes_to_queries.rb new file mode 100644 index 00000000..414b1ad6 --- /dev/null +++ b/db/migrate/20091017214136_add_missing_indexes_to_queries.rb @@ -0,0 +1,11 @@ +class AddMissingIndexesToQueries < ActiveRecord::Migration + def self.up + add_index :queries, :project_id + add_index :queries, :user_id + end + + def self.down + remove_index :queries, :project_id + remove_index :queries, :user_id + end +end diff --git a/db/migrate/20091017214236_add_missing_indexes_to_time_entries.rb b/db/migrate/20091017214236_add_missing_indexes_to_time_entries.rb new file mode 100644 index 00000000..cffc528e --- /dev/null +++ b/db/migrate/20091017214236_add_missing_indexes_to_time_entries.rb @@ -0,0 +1,11 @@ +class AddMissingIndexesToTimeEntries < ActiveRecord::Migration + def self.up + add_index :time_entries, :activity_id + add_index :time_entries, :user_id + end + + def self.down + remove_index :time_entries, :activity_id + remove_index :time_entries, :user_id + end +end diff --git a/db/migrate/20091017214308_add_missing_indexes_to_news.rb b/db/migrate/20091017214308_add_missing_indexes_to_news.rb new file mode 100644 index 00000000..808eb629 --- /dev/null +++ b/db/migrate/20091017214308_add_missing_indexes_to_news.rb @@ -0,0 +1,9 @@ +class AddMissingIndexesToNews < ActiveRecord::Migration + def self.up + add_index :news, :author_id + end + + def self.down + remove_index :news, :author_id + end +end diff --git a/db/migrate/20091017214336_add_missing_indexes_to_users.rb b/db/migrate/20091017214336_add_missing_indexes_to_users.rb new file mode 100644 index 00000000..c5a50958 --- /dev/null +++ b/db/migrate/20091017214336_add_missing_indexes_to_users.rb @@ -0,0 +1,11 @@ +class AddMissingIndexesToUsers < ActiveRecord::Migration + def self.up + add_index :users, [:id, :type] + add_index :users, :auth_source_id + end + + def self.down + remove_index :users, :column => [:id, :type] + remove_index :users, :auth_source_id + end +end diff --git a/db/migrate/20091017214406_add_missing_indexes_to_attachments.rb b/db/migrate/20091017214406_add_missing_indexes_to_attachments.rb new file mode 100644 index 00000000..d22fc98e --- /dev/null +++ b/db/migrate/20091017214406_add_missing_indexes_to_attachments.rb @@ -0,0 +1,11 @@ +class AddMissingIndexesToAttachments < ActiveRecord::Migration + def self.up + add_index :attachments, [:container_id, :container_type] + add_index :attachments, :author_id + end + + def self.down + remove_index :attachments, :column => [:container_id, :container_type] + remove_index :attachments, :author_id + end +end diff --git a/db/migrate/20091017214440_add_missing_indexes_to_wiki_contents.rb b/db/migrate/20091017214440_add_missing_indexes_to_wiki_contents.rb new file mode 100644 index 00000000..454e4c5d --- /dev/null +++ b/db/migrate/20091017214440_add_missing_indexes_to_wiki_contents.rb @@ -0,0 +1,9 @@ +class AddMissingIndexesToWikiContents < ActiveRecord::Migration + def self.up + add_index :wiki_contents, :author_id + end + + def self.down + remove_index :wiki_contents, :author_id + end +end diff --git a/db/migrate/20091017214519_add_missing_indexes_to_custom_values.rb b/db/migrate/20091017214519_add_missing_indexes_to_custom_values.rb new file mode 100644 index 00000000..b192a7e2 --- /dev/null +++ b/db/migrate/20091017214519_add_missing_indexes_to_custom_values.rb @@ -0,0 +1,9 @@ +class AddMissingIndexesToCustomValues < ActiveRecord::Migration + def self.up + add_index :custom_values, :custom_field_id + end + + def self.down + remove_index :custom_values, :custom_field_id + end +end diff --git a/db/migrate/20091017214611_add_missing_indexes_to_journals.rb b/db/migrate/20091017214611_add_missing_indexes_to_journals.rb new file mode 100644 index 00000000..2667f403 --- /dev/null +++ b/db/migrate/20091017214611_add_missing_indexes_to_journals.rb @@ -0,0 +1,11 @@ +class AddMissingIndexesToJournals < ActiveRecord::Migration + def self.up + add_index :journals, :user_id + add_index :journals, :journalized_id + end + + def self.down + remove_index :journals, :user_id + remove_index :journals, :journalized_id + end +end diff --git a/db/migrate/20091017214644_add_missing_indexes_to_issue_relations.rb b/db/migrate/20091017214644_add_missing_indexes_to_issue_relations.rb new file mode 100644 index 00000000..fc57f18b --- /dev/null +++ b/db/migrate/20091017214644_add_missing_indexes_to_issue_relations.rb @@ -0,0 +1,11 @@ +class AddMissingIndexesToIssueRelations < ActiveRecord::Migration + def self.up + add_index :issue_relations, :issue_from_id + add_index :issue_relations, :issue_to_id + end + + def self.down + remove_index :issue_relations, :issue_from_id + remove_index :issue_relations, :issue_to_id + end +end diff --git a/db/migrate/20091017214720_add_missing_indexes_to_wiki_redirects.rb b/db/migrate/20091017214720_add_missing_indexes_to_wiki_redirects.rb new file mode 100644 index 00000000..7442a544 --- /dev/null +++ b/db/migrate/20091017214720_add_missing_indexes_to_wiki_redirects.rb @@ -0,0 +1,9 @@ +class AddMissingIndexesToWikiRedirects < ActiveRecord::Migration + def self.up + add_index :wiki_redirects, :wiki_id + end + + def self.down + remove_index :wiki_redirects, :wiki_id + end +end diff --git a/db/migrate/20091017214750_add_missing_indexes_to_custom_fields_trackers.rb b/db/migrate/20091017214750_add_missing_indexes_to_custom_fields_trackers.rb new file mode 100644 index 00000000..c398b793 --- /dev/null +++ b/db/migrate/20091017214750_add_missing_indexes_to_custom_fields_trackers.rb @@ -0,0 +1,9 @@ +class AddMissingIndexesToCustomFieldsTrackers < ActiveRecord::Migration + def self.up + add_index :custom_fields_trackers, [:custom_field_id, :tracker_id] + end + + def self.down + remove_index :custom_fields_trackers, :column => [:custom_field_id, :tracker_id] + end +end diff --git a/db/migrate/20091025163651_add_activity_indexes.rb b/db/migrate/20091025163651_add_activity_indexes.rb new file mode 100644 index 00000000..f1805931 --- /dev/null +++ b/db/migrate/20091025163651_add_activity_indexes.rb @@ -0,0 +1,25 @@ +class AddActivityIndexes < ActiveRecord::Migration + def self.up + add_index :journals, :created_on + add_index :changesets, :committed_on + add_index :wiki_content_versions, :updated_on + add_index :messages, :created_on + add_index :issues, :created_on + add_index :news, :created_on + add_index :attachments, :created_on + add_index :documents, :created_on + add_index :time_entries, :created_on + end + + def self.down + remove_index :journals, :created_on + remove_index :changesets, :committed_on + remove_index :wiki_content_versions, :updated_on + remove_index :messages, :created_on + remove_index :issues, :created_on + remove_index :news, :created_on + remove_index :attachments, :created_on + remove_index :documents, :created_on + remove_index :time_entries, :created_on + end +end diff --git a/db/migrate/20091108092559_add_versions_status.rb b/db/migrate/20091108092559_add_versions_status.rb new file mode 100644 index 00000000..99f5f5a0 --- /dev/null +++ b/db/migrate/20091108092559_add_versions_status.rb @@ -0,0 +1,10 @@ +class AddVersionsStatus < ActiveRecord::Migration + def self.up + add_column :versions, :status, :string, :default => 'open' + Version.update_all("status = 'open'") + end + + def self.down + remove_column :versions, :status + end +end diff --git a/db/migrate/20091114105931_add_view_issues_permission.rb b/db/migrate/20091114105931_add_view_issues_permission.rb new file mode 100644 index 00000000..d12b2dee --- /dev/null +++ b/db/migrate/20091114105931_add_view_issues_permission.rb @@ -0,0 +1,13 @@ +class AddViewIssuesPermission < ActiveRecord::Migration + def self.up + Role.all.each do |r| + r.add_permission!(:view_issues) + end + end + + def self.down + Role.all.each do |r| + r.remove_permission!(:view_issues) + end + end +end diff --git a/db/migrate/20091123212029_add_default_done_ratio_to_issue_status.rb b/db/migrate/20091123212029_add_default_done_ratio_to_issue_status.rb new file mode 100644 index 00000000..0ce67210 --- /dev/null +++ b/db/migrate/20091123212029_add_default_done_ratio_to_issue_status.rb @@ -0,0 +1,9 @@ +class AddDefaultDoneRatioToIssueStatus < ActiveRecord::Migration + def self.up + add_column :issue_statuses, :default_done_ratio, :integer + end + + def self.down + remove_column :issue_statuses, :default_done_ratio + end +end diff --git a/db/migrate/20091205124427_add_versions_sharing.rb b/db/migrate/20091205124427_add_versions_sharing.rb new file mode 100644 index 00000000..3c28e115 --- /dev/null +++ b/db/migrate/20091205124427_add_versions_sharing.rb @@ -0,0 +1,10 @@ +class AddVersionsSharing < ActiveRecord::Migration + def self.up + add_column :versions, :sharing, :string, :default => 'none', :null => false + add_index :versions, :sharing + end + + def self.down + remove_column :versions, :sharing + end +end diff --git a/db/migrate/20091220183509_add_lft_and_rgt_indexes_to_projects.rb b/db/migrate/20091220183509_add_lft_and_rgt_indexes_to_projects.rb new file mode 100644 index 00000000..1c0b4b31 --- /dev/null +++ b/db/migrate/20091220183509_add_lft_and_rgt_indexes_to_projects.rb @@ -0,0 +1,11 @@ +class AddLftAndRgtIndexesToProjects < ActiveRecord::Migration + def self.up + add_index :projects, :lft + add_index :projects, :rgt + end + + def self.down + remove_index :projects, :lft + remove_index :projects, :rgt + end +end diff --git a/db/migrate/20091220183727_add_index_to_settings_name.rb b/db/migrate/20091220183727_add_index_to_settings_name.rb new file mode 100644 index 00000000..e6c96ec3 --- /dev/null +++ b/db/migrate/20091220183727_add_index_to_settings_name.rb @@ -0,0 +1,9 @@ +class AddIndexToSettingsName < ActiveRecord::Migration + def self.up + add_index :settings, :name + end + + def self.down + remove_index :settings, :name + end +end diff --git a/db/migrate/20091220184736_add_indexes_to_issue_status.rb b/db/migrate/20091220184736_add_indexes_to_issue_status.rb new file mode 100644 index 00000000..2497a1e6 --- /dev/null +++ b/db/migrate/20091220184736_add_indexes_to_issue_status.rb @@ -0,0 +1,13 @@ +class AddIndexesToIssueStatus < ActiveRecord::Migration + def self.up + add_index :issue_statuses, :position + add_index :issue_statuses, :is_closed + add_index :issue_statuses, :is_default + end + + def self.down + remove_index :issue_statuses, :position + remove_index :issue_statuses, :is_closed + remove_index :issue_statuses, :is_default + end +end diff --git a/db/migrate/20091225164732_remove_enumerations_opt.rb b/db/migrate/20091225164732_remove_enumerations_opt.rb new file mode 100644 index 00000000..72c39e05 --- /dev/null +++ b/db/migrate/20091225164732_remove_enumerations_opt.rb @@ -0,0 +1,12 @@ +class RemoveEnumerationsOpt < ActiveRecord::Migration + def self.up + remove_column :enumerations, :opt + end + + def self.down + add_column :enumerations, :opt, :string, :limit => 4, :default => '', :null => false + Enumeration.update_all("opt = 'IPRI'", "type = 'IssuePriority'") + Enumeration.update_all("opt = 'DCAT'", "type = 'DocumentCategory'") + Enumeration.update_all("opt = 'ACTI'", "type = 'TimeEntryActivity'") + end +end diff --git a/db/migrate/20091227112908_change_wiki_contents_text_limit.rb b/db/migrate/20091227112908_change_wiki_contents_text_limit.rb new file mode 100644 index 00000000..225f71e6 --- /dev/null +++ b/db/migrate/20091227112908_change_wiki_contents_text_limit.rb @@ -0,0 +1,16 @@ +class ChangeWikiContentsTextLimit < ActiveRecord::Migration + def self.up + # Migrates MySQL databases only + # Postgres would raise an error (see http://dev.rubyonrails.org/ticket/3818) + # Not fixed in Rails 2.3.5 + if ActiveRecord::Base.connection.adapter_name =~ /mysql/i + max_size = 16.megabytes + change_column :wiki_contents, :text, :text, :limit => max_size + change_column :wiki_content_versions, :data, :binary, :limit => max_size + end + end + + def self.down + # no-op + end +end diff --git a/db/migrate/20100129193402_change_users_mail_notification_to_string.rb b/db/migrate/20100129193402_change_users_mail_notification_to_string.rb new file mode 100644 index 00000000..401f6340 --- /dev/null +++ b/db/migrate/20100129193402_change_users_mail_notification_to_string.rb @@ -0,0 +1,17 @@ +class ChangeUsersMailNotificationToString < ActiveRecord::Migration + def self.up + rename_column :users, :mail_notification, :mail_notification_bool + add_column :users, :mail_notification, :string, :default => '', :null => false + User.update_all("mail_notification = 'all'", "mail_notification_bool = #{connection.quoted_true}") + User.update_all("mail_notification = 'selected'", "EXISTS (SELECT 1 FROM #{Member.table_name} WHERE #{Member.table_name}.mail_notification = #{connection.quoted_true} AND #{Member.table_name}.user_id = #{User.table_name}.id)") + User.update_all("mail_notification = 'only_my_events'", "mail_notification NOT IN ('all', 'selected')") + remove_column :users, :mail_notification_bool + end + + def self.down + rename_column :users, :mail_notification, :mail_notification_char + add_column :users, :mail_notification, :boolean, :default => true, :null => false + User.update_all("mail_notification = #{connection.quoted_false}", "mail_notification_char <> 'all'") + remove_column :users, :mail_notification_char + end +end diff --git a/db/migrate/20100129193813_update_mail_notification_values.rb b/db/migrate/20100129193813_update_mail_notification_values.rb new file mode 100644 index 00000000..a8a45ade --- /dev/null +++ b/db/migrate/20100129193813_update_mail_notification_values.rb @@ -0,0 +1,11 @@ +# Patch the data from a boolean change. +class UpdateMailNotificationValues < ActiveRecord::Migration + def self.up + # No-op + # See 20100129193402_change_users_mail_notification_to_string.rb + end + + def self.down + # No-op + end +end diff --git a/db/migrate/20100221100219_add_index_on_changesets_scmid.rb b/db/migrate/20100221100219_add_index_on_changesets_scmid.rb new file mode 100644 index 00000000..96d85a3a --- /dev/null +++ b/db/migrate/20100221100219_add_index_on_changesets_scmid.rb @@ -0,0 +1,9 @@ +class AddIndexOnChangesetsScmid < ActiveRecord::Migration + def self.up + add_index :changesets, [:repository_id, :scmid], :name => :changesets_repos_scmid + end + + def self.down + remove_index :changesets, :name => :changesets_repos_scmid + end +end diff --git a/db/migrate/20100313132032_add_issues_nested_sets_columns.rb b/db/migrate/20100313132032_add_issues_nested_sets_columns.rb new file mode 100644 index 00000000..2467f6f6 --- /dev/null +++ b/db/migrate/20100313132032_add_issues_nested_sets_columns.rb @@ -0,0 +1,17 @@ +class AddIssuesNestedSetsColumns < ActiveRecord::Migration + def self.up + add_column :issues, :parent_id, :integer, :default => nil + add_column :issues, :root_id, :integer, :default => nil + add_column :issues, :lft, :integer, :default => nil + add_column :issues, :rgt, :integer, :default => nil + + Issue.update_all("parent_id = NULL, root_id = id, lft = 1, rgt = 2") + end + + def self.down + remove_column :issues, :parent_id + remove_column :issues, :root_id + remove_column :issues, :lft + remove_column :issues, :rgt + end +end diff --git a/db/migrate/20100313171051_add_index_on_issues_nested_set.rb b/db/migrate/20100313171051_add_index_on_issues_nested_set.rb new file mode 100644 index 00000000..4dc94800 --- /dev/null +++ b/db/migrate/20100313171051_add_index_on_issues_nested_set.rb @@ -0,0 +1,9 @@ +class AddIndexOnIssuesNestedSet < ActiveRecord::Migration + def self.up + add_index :issues, [:root_id, :lft, :rgt] + end + + def self.down + remove_index :issues, [:root_id, :lft, :rgt] + end +end diff --git a/db/migrate/20100705164950_change_changes_path_length_limit.rb b/db/migrate/20100705164950_change_changes_path_length_limit.rb new file mode 100644 index 00000000..e00b69d0 --- /dev/null +++ b/db/migrate/20100705164950_change_changes_path_length_limit.rb @@ -0,0 +1,14 @@ +class ChangeChangesPathLengthLimit < ActiveRecord::Migration + def self.up + # these are two steps to please MySQL 5 on Win32 + change_column :changes, :path, :text, :default => nil, :null => true + change_column :changes, :path, :text, :null => false + + change_column :changes, :from_path, :text + end + + def self.down + change_column :changes, :path, :string, :default => "", :null => false + change_column :changes, :from_path, :string + end +end diff --git a/db/migrate/20100819172912_enable_calendar_and_gantt_modules_where_appropriate.rb b/db/migrate/20100819172912_enable_calendar_and_gantt_modules_where_appropriate.rb new file mode 100644 index 00000000..59cd4004 --- /dev/null +++ b/db/migrate/20100819172912_enable_calendar_and_gantt_modules_where_appropriate.rb @@ -0,0 +1,12 @@ +class EnableCalendarAndGanttModulesWhereAppropriate < ActiveRecord::Migration + def self.up + EnabledModule.where(:name => 'issue_tracking').all.each do |e| + EnabledModule.create(:name => 'calendar', :project_id => e.project_id) + EnabledModule.create(:name => 'gantt', :project_id => e.project_id) + end + end + + def self.down + EnabledModule.delete_all("name = 'calendar' OR name = 'gantt'") + end +end diff --git a/db/migrate/20101104182107_add_unique_index_on_members.rb b/db/migrate/20101104182107_add_unique_index_on_members.rb new file mode 100644 index 00000000..14d1585f --- /dev/null +++ b/db/migrate/20101104182107_add_unique_index_on_members.rb @@ -0,0 +1,22 @@ +class AddUniqueIndexOnMembers < ActiveRecord::Migration + def self.up + # Clean and reassign MemberRole rows if needed + MemberRole.delete_all("member_id NOT IN (SELECT id FROM #{Member.table_name})") + MemberRole.update_all("member_id =" + + " (SELECT min(m2.id) FROM #{Member.table_name} m1, #{Member.table_name} m2" + + " WHERE m1.user_id = m2.user_id AND m1.project_id = m2.project_id" + + " AND m1.id = #{MemberRole.table_name}.member_id)") + # Remove duplicates + Member.connection.select_values("SELECT m.id FROM #{Member.table_name} m" + + " WHERE m.id > (SELECT min(m1.id) FROM #{Member.table_name} m1 WHERE m1.user_id = m.user_id AND m1.project_id = m.project_id)").each do |i| + Member.delete_all(["id = ?", i]) + end + + # Then add a unique index + add_index :members, [:user_id, :project_id], :unique => true + end + + def self.down + remove_index :members, [:user_id, :project_id] + end +end diff --git a/db/migrate/20101107130441_add_custom_fields_visible.rb b/db/migrate/20101107130441_add_custom_fields_visible.rb new file mode 100644 index 00000000..9d59faee --- /dev/null +++ b/db/migrate/20101107130441_add_custom_fields_visible.rb @@ -0,0 +1,10 @@ +class AddCustomFieldsVisible < ActiveRecord::Migration + def self.up + add_column :custom_fields, :visible, :boolean, :null => false, :default => true + CustomField.update_all("visible = #{CustomField.connection.quoted_true}") + end + + def self.down + remove_column :custom_fields, :visible + end +end diff --git a/db/migrate/20101114115114_change_projects_name_limit.rb b/db/migrate/20101114115114_change_projects_name_limit.rb new file mode 100644 index 00000000..fabc3c9d --- /dev/null +++ b/db/migrate/20101114115114_change_projects_name_limit.rb @@ -0,0 +1,9 @@ +class ChangeProjectsNameLimit < ActiveRecord::Migration + def self.up + change_column :projects, :name, :string, :limit => nil, :default => '', :null => false + end + + def self.down + change_column :projects, :name, :string, :limit => 30, :default => '', :null => false + end +end diff --git a/db/migrate/20101114115359_change_projects_identifier_limit.rb b/db/migrate/20101114115359_change_projects_identifier_limit.rb new file mode 100644 index 00000000..79426fad --- /dev/null +++ b/db/migrate/20101114115359_change_projects_identifier_limit.rb @@ -0,0 +1,9 @@ +class ChangeProjectsIdentifierLimit < ActiveRecord::Migration + def self.up + change_column :projects, :identifier, :string, :limit => nil + end + + def self.down + change_column :projects, :identifier, :string, :limit => 20 + end +end diff --git a/db/migrate/20110220160626_add_workflows_assignee_and_author.rb b/db/migrate/20110220160626_add_workflows_assignee_and_author.rb new file mode 100644 index 00000000..448ac630 --- /dev/null +++ b/db/migrate/20110220160626_add_workflows_assignee_and_author.rb @@ -0,0 +1,14 @@ +class AddWorkflowsAssigneeAndAuthor < ActiveRecord::Migration + def self.up + add_column :workflows, :assignee, :boolean, :null => false, :default => false + add_column :workflows, :author, :boolean, :null => false, :default => false + + WorkflowRule.update_all(:assignee => false) + WorkflowRule.update_all(:author => false) + end + + def self.down + remove_column :workflows, :assignee + remove_column :workflows, :author + end +end diff --git a/db/migrate/20110223180944_add_users_salt.rb b/db/migrate/20110223180944_add_users_salt.rb new file mode 100644 index 00000000..f1cf6483 --- /dev/null +++ b/db/migrate/20110223180944_add_users_salt.rb @@ -0,0 +1,9 @@ +class AddUsersSalt < ActiveRecord::Migration + def self.up + add_column :users, :salt, :string, :limit => 64 + end + + def self.down + remove_column :users, :salt + end +end diff --git a/db/migrate/20110223180953_salt_user_passwords.rb b/db/migrate/20110223180953_salt_user_passwords.rb new file mode 100644 index 00000000..9f017db9 --- /dev/null +++ b/db/migrate/20110223180953_salt_user_passwords.rb @@ -0,0 +1,13 @@ +class SaltUserPasswords < ActiveRecord::Migration + + def self.up + say_with_time "Salting user passwords, this may take some time..." do + User.salt_unsalted_passwords! + end + end + + def self.down + # Unsalted passwords can not be restored + raise ActiveRecord::IrreversibleMigration, "Can't decypher salted passwords. This migration can not be rollback'ed." + end +end diff --git a/db/migrate/20110224000000_add_repositories_path_encoding.rb b/db/migrate/20110224000000_add_repositories_path_encoding.rb new file mode 100644 index 00000000..253d7a66 --- /dev/null +++ b/db/migrate/20110224000000_add_repositories_path_encoding.rb @@ -0,0 +1,9 @@ +class AddRepositoriesPathEncoding < ActiveRecord::Migration + def self.up + add_column :repositories, :path_encoding, :string, :limit => 64, :default => nil + end + + def self.down + remove_column :repositories, :path_encoding + end +end diff --git a/db/migrate/20110226120112_change_repositories_password_limit.rb b/db/migrate/20110226120112_change_repositories_password_limit.rb new file mode 100644 index 00000000..1ad937c7 --- /dev/null +++ b/db/migrate/20110226120112_change_repositories_password_limit.rb @@ -0,0 +1,9 @@ +class ChangeRepositoriesPasswordLimit < ActiveRecord::Migration + def self.up + change_column :repositories, :password, :string, :limit => nil, :default => '' + end + + def self.down + change_column :repositories, :password, :string, :limit => 60, :default => '' + end +end diff --git a/db/migrate/20110226120132_change_auth_sources_account_password_limit.rb b/db/migrate/20110226120132_change_auth_sources_account_password_limit.rb new file mode 100644 index 00000000..b1cd80aa --- /dev/null +++ b/db/migrate/20110226120132_change_auth_sources_account_password_limit.rb @@ -0,0 +1,9 @@ +class ChangeAuthSourcesAccountPasswordLimit < ActiveRecord::Migration + def self.up + change_column :auth_sources, :account_password, :string, :limit => nil, :default => '' + end + + def self.down + change_column :auth_sources, :account_password, :string, :limit => 60, :default => '' + end +end diff --git a/db/migrate/20110227125750_change_journal_details_values_to_text.rb b/db/migrate/20110227125750_change_journal_details_values_to_text.rb new file mode 100644 index 00000000..25886575 --- /dev/null +++ b/db/migrate/20110227125750_change_journal_details_values_to_text.rb @@ -0,0 +1,11 @@ +class ChangeJournalDetailsValuesToText < ActiveRecord::Migration + def self.up + change_column :journal_details, :old_value, :text + change_column :journal_details, :value, :text + end + + def self.down + change_column :journal_details, :old_value, :string + change_column :journal_details, :value, :string + end +end diff --git a/db/migrate/20110228000000_add_repositories_log_encoding.rb b/db/migrate/20110228000000_add_repositories_log_encoding.rb new file mode 100644 index 00000000..85cadafc --- /dev/null +++ b/db/migrate/20110228000000_add_repositories_log_encoding.rb @@ -0,0 +1,9 @@ +class AddRepositoriesLogEncoding < ActiveRecord::Migration + def self.up + add_column :repositories, :log_encoding, :string, :limit => 64, :default => nil + end + + def self.down + remove_column :repositories, :log_encoding + end +end diff --git a/db/migrate/20110228000100_copy_repositories_log_encoding.rb b/db/migrate/20110228000100_copy_repositories_log_encoding.rb new file mode 100644 index 00000000..31493288 --- /dev/null +++ b/db/migrate/20110228000100_copy_repositories_log_encoding.rb @@ -0,0 +1,11 @@ +class CopyRepositoriesLogEncoding < ActiveRecord::Migration + def self.up + encoding = Setting.commit_logs_encoding.to_s.strip + encoding = encoding.blank? ? 'UTF-8' : encoding + # encoding is NULL by default + Repository.update_all(["log_encoding = ?", encoding], "type IN ('Bazaar', 'Cvs', 'Darcs')") + end + + def self.down + end +end diff --git a/db/migrate/20110401192910_add_index_to_users_type.rb b/db/migrate/20110401192910_add_index_to_users_type.rb new file mode 100644 index 00000000..b9f50112 --- /dev/null +++ b/db/migrate/20110401192910_add_index_to_users_type.rb @@ -0,0 +1,9 @@ +class AddIndexToUsersType < ActiveRecord::Migration + def self.up + add_index :users, :type + end + + def self.down + remove_index :users, :type + end +end diff --git a/db/migrate/20110408103312_add_roles_issues_visibility.rb b/db/migrate/20110408103312_add_roles_issues_visibility.rb new file mode 100644 index 00000000..1e6b29a6 --- /dev/null +++ b/db/migrate/20110408103312_add_roles_issues_visibility.rb @@ -0,0 +1,9 @@ +class AddRolesIssuesVisibility < ActiveRecord::Migration + def self.up + add_column :roles, :issues_visibility, :string, :limit => 30, :default => 'default', :null => false + end + + def self.down + remove_column :roles, :issues_visibility + end +end diff --git a/db/migrate/20110412065600_add_issues_is_private.rb b/db/migrate/20110412065600_add_issues_is_private.rb new file mode 100644 index 00000000..2cc4e4b1 --- /dev/null +++ b/db/migrate/20110412065600_add_issues_is_private.rb @@ -0,0 +1,9 @@ +class AddIssuesIsPrivate < ActiveRecord::Migration + def self.up + add_column :issues, :is_private, :boolean, :default => false, :null => false + end + + def self.down + remove_column :issues, :is_private + end +end diff --git a/db/migrate/20110511000000_add_repositories_extra_info.rb b/db/migrate/20110511000000_add_repositories_extra_info.rb new file mode 100644 index 00000000..a5280dc5 --- /dev/null +++ b/db/migrate/20110511000000_add_repositories_extra_info.rb @@ -0,0 +1,9 @@ +class AddRepositoriesExtraInfo < ActiveRecord::Migration + def self.up + add_column :repositories, :extra_info, :text + end + + def self.down + remove_column :repositories, :extra_info + end +end diff --git a/db/migrate/20110902000000_create_changeset_parents.rb b/db/migrate/20110902000000_create_changeset_parents.rb new file mode 100644 index 00000000..e679d3f9 --- /dev/null +++ b/db/migrate/20110902000000_create_changeset_parents.rb @@ -0,0 +1,14 @@ +class CreateChangesetParents < ActiveRecord::Migration + def self.up + create_table :changeset_parents, :id => false do |t| + t.column :changeset_id, :integer, :null => false + t.column :parent_id, :integer, :null => false + end + add_index :changeset_parents, [:changeset_id], :unique => false, :name => :changeset_parents_changeset_ids + add_index :changeset_parents, [:parent_id], :unique => false, :name => :changeset_parents_parent_ids + end + + def self.down + drop_table :changeset_parents + end +end diff --git a/db/migrate/20111201201315_add_unique_index_to_issue_relations.rb b/db/migrate/20111201201315_add_unique_index_to_issue_relations.rb new file mode 100644 index 00000000..c27158c1 --- /dev/null +++ b/db/migrate/20111201201315_add_unique_index_to_issue_relations.rb @@ -0,0 +1,16 @@ +class AddUniqueIndexToIssueRelations < ActiveRecord::Migration + def self.up + + # Remove duplicates + IssueRelation.connection.select_values("SELECT r.id FROM #{IssueRelation.table_name} r" + + " WHERE r.id > (SELECT min(r1.id) FROM #{IssueRelation.table_name} r1 WHERE r1.issue_from_id = r.issue_from_id AND r1.issue_to_id = r.issue_to_id)").each do |i| + IssueRelation.delete_all(["id = ?", i]) + end + + add_index :issue_relations, [:issue_from_id, :issue_to_id], :unique => true + end + + def self.down + remove_index :issue_relations, :column => [:issue_from_id, :issue_to_id] + end +end diff --git a/db/migrate/20120115143024_add_repositories_identifier.rb b/db/migrate/20120115143024_add_repositories_identifier.rb new file mode 100644 index 00000000..b54ebd1d --- /dev/null +++ b/db/migrate/20120115143024_add_repositories_identifier.rb @@ -0,0 +1,9 @@ +class AddRepositoriesIdentifier < ActiveRecord::Migration + def self.up + add_column :repositories, :identifier, :string + end + + def self.down + remove_column :repositories, :identifier + end +end diff --git a/db/migrate/20120115143100_add_repositories_is_default.rb b/db/migrate/20120115143100_add_repositories_is_default.rb new file mode 100644 index 00000000..87f01812 --- /dev/null +++ b/db/migrate/20120115143100_add_repositories_is_default.rb @@ -0,0 +1,9 @@ +class AddRepositoriesIsDefault < ActiveRecord::Migration + def self.up + add_column :repositories, :is_default, :boolean, :default => false + end + + def self.down + remove_column :repositories, :is_default + end +end diff --git a/db/migrate/20120115143126_set_default_repositories.rb b/db/migrate/20120115143126_set_default_repositories.rb new file mode 100644 index 00000000..cd7674e7 --- /dev/null +++ b/db/migrate/20120115143126_set_default_repositories.rb @@ -0,0 +1,14 @@ +class SetDefaultRepositories < ActiveRecord::Migration + def self.up + Repository.update_all(["is_default = ?", false]) + # Sets the last repository as default in case multiple repositories exist for the same project + Repository.connection.select_values("SELECT r.id FROM #{Repository.table_name} r" + + " WHERE r.id = (SELECT max(r1.id) FROM #{Repository.table_name} r1 WHERE r1.project_id = r.project_id)").each do |i| + Repository.update_all(["is_default = ?", true], ["id = ?", i]) + end + end + + def self.down + Repository.update_all(["is_default = ?", false]) + end +end diff --git a/db/migrate/20120127174243_add_custom_fields_multiple.rb b/db/migrate/20120127174243_add_custom_fields_multiple.rb new file mode 100644 index 00000000..caee40bd --- /dev/null +++ b/db/migrate/20120127174243_add_custom_fields_multiple.rb @@ -0,0 +1,9 @@ +class AddCustomFieldsMultiple < ActiveRecord::Migration + def self.up + add_column :custom_fields, :multiple, :boolean, :default => false + end + + def self.down + remove_column :custom_fields, :multiple + end +end diff --git a/db/migrate/20120205111326_change_users_login_limit.rb b/db/migrate/20120205111326_change_users_login_limit.rb new file mode 100644 index 00000000..4508a5c4 --- /dev/null +++ b/db/migrate/20120205111326_change_users_login_limit.rb @@ -0,0 +1,9 @@ +class ChangeUsersLoginLimit < ActiveRecord::Migration + def self.up + change_column :users, :login, :string, :limit => nil, :default => '', :null => false + end + + def self.down + change_column :users, :login, :string, :limit => 30, :default => '', :null => false + end +end diff --git a/db/migrate/20120223110929_change_attachments_container_defaults.rb b/db/migrate/20120223110929_change_attachments_container_defaults.rb new file mode 100644 index 00000000..f959f4c3 --- /dev/null +++ b/db/migrate/20120223110929_change_attachments_container_defaults.rb @@ -0,0 +1,25 @@ +class ChangeAttachmentsContainerDefaults < ActiveRecord::Migration + def self.up + # Need to drop the index otherwise the following error occurs in Rails 3.1.3: + # + # Index name 'temp_index_altered_attachments_on_container_id_and_container_type' on + # table 'altered_attachments' is too long; the limit is 64 characters + remove_index :attachments, [:container_id, :container_type] + + change_column :attachments, :container_id, :integer, :default => nil, :null => true + change_column :attachments, :container_type, :string, :limit => 30, :default => nil, :null => true + Attachment.update_all "container_id = NULL", "container_id = 0" + Attachment.update_all "container_type = NULL", "container_type = ''" + + add_index :attachments, [:container_id, :container_type] + end + + def self.down + remove_index :attachments, [:container_id, :container_type] + + change_column :attachments, :container_id, :integer, :default => 0, :null => false + change_column :attachments, :container_type, :string, :limit => 30, :default => "", :null => false + + add_index :attachments, [:container_id, :container_type] + end +end diff --git a/db/migrate/20120301153455_add_auth_sources_filter.rb b/db/migrate/20120301153455_add_auth_sources_filter.rb new file mode 100644 index 00000000..617b3b77 --- /dev/null +++ b/db/migrate/20120301153455_add_auth_sources_filter.rb @@ -0,0 +1,9 @@ +class AddAuthSourcesFilter < ActiveRecord::Migration + def self.up + add_column :auth_sources, :filter, :string + end + + def self.down + remove_column :auth_sources, :filter + end +end diff --git a/db/migrate/20120422150750_change_repositories_to_full_sti.rb b/db/migrate/20120422150750_change_repositories_to_full_sti.rb new file mode 100644 index 00000000..067d6025 --- /dev/null +++ b/db/migrate/20120422150750_change_repositories_to_full_sti.rb @@ -0,0 +1,17 @@ +class ChangeRepositoriesToFullSti < ActiveRecord::Migration + def up + Repository.connection.select_rows("SELECT id, type FROM #{Repository.table_name}").each do |repository_id, repository_type| + unless repository_type =~ /^Repository::/ + Repository.update_all ["type = ?", "Repository::#{repository_type}"], ["id = ?", repository_id] + end + end + end + + def down + Repository.connection.select_rows("SELECT id, type FROM #{Repository.table_name}").each do |repository_id, repository_type| + if repository_type =~ /^Repository::(.+)$/ + Repository.update_all ["type = ?", $1], ["id = ?", repository_id] + end + end + end +end diff --git a/db/migrate/20120705074331_add_trackers_fields_bits.rb b/db/migrate/20120705074331_add_trackers_fields_bits.rb new file mode 100644 index 00000000..5d845838 --- /dev/null +++ b/db/migrate/20120705074331_add_trackers_fields_bits.rb @@ -0,0 +1,9 @@ +class AddTrackersFieldsBits < ActiveRecord::Migration + def self.up + add_column :trackers, :fields_bits, :integer, :default => 0 + end + + def self.down + remove_column :trackers, :fields_bits + end +end diff --git a/db/migrate/20120707064544_add_auth_sources_timeout.rb b/db/migrate/20120707064544_add_auth_sources_timeout.rb new file mode 100644 index 00000000..40f46781 --- /dev/null +++ b/db/migrate/20120707064544_add_auth_sources_timeout.rb @@ -0,0 +1,9 @@ +class AddAuthSourcesTimeout < ActiveRecord::Migration + def up + add_column :auth_sources, :timeout, :integer + end + + def self.down + remove_column :auth_sources, :timeout + end +end diff --git a/db/migrate/20120714122000_add_workflows_type.rb b/db/migrate/20120714122000_add_workflows_type.rb new file mode 100644 index 00000000..f263f25d --- /dev/null +++ b/db/migrate/20120714122000_add_workflows_type.rb @@ -0,0 +1,9 @@ +class AddWorkflowsType < ActiveRecord::Migration + def up + add_column :workflows, :type, :string, :limit => 30 + end + + def down + remove_column :workflows, :type + end +end diff --git a/db/migrate/20120714122100_update_workflows_to_sti.rb b/db/migrate/20120714122100_update_workflows_to_sti.rb new file mode 100644 index 00000000..8ee5c6dc --- /dev/null +++ b/db/migrate/20120714122100_update_workflows_to_sti.rb @@ -0,0 +1,9 @@ +class UpdateWorkflowsToSti < ActiveRecord::Migration + def up + WorkflowRule.update_all "type = 'WorkflowTransition'" + end + + def down + WorkflowRule.update_all "type = NULL" + end +end diff --git a/db/migrate/20120714122200_add_workflows_rule_fields.rb b/db/migrate/20120714122200_add_workflows_rule_fields.rb new file mode 100644 index 00000000..6e9c7df7 --- /dev/null +++ b/db/migrate/20120714122200_add_workflows_rule_fields.rb @@ -0,0 +1,11 @@ +class AddWorkflowsRuleFields < ActiveRecord::Migration + def up + add_column :workflows, :field_name, :string, :limit => 30 + add_column :workflows, :rule, :string, :limit => 30 + end + + def down + remove_column :workflows, :field_name + remove_column :workflows, :rule + end +end diff --git a/db/migrate/20120731164049_add_boards_parent_id.rb b/db/migrate/20120731164049_add_boards_parent_id.rb new file mode 100644 index 00000000..c9ce47f7 --- /dev/null +++ b/db/migrate/20120731164049_add_boards_parent_id.rb @@ -0,0 +1,9 @@ +class AddBoardsParentId < ActiveRecord::Migration + def up + add_column :boards, :parent_id, :integer + end + + def down + remove_column :boards, :parent_id + end +end diff --git a/db/migrate/20120930112914_add_journals_private_notes.rb b/db/migrate/20120930112914_add_journals_private_notes.rb new file mode 100644 index 00000000..41eb0e9e --- /dev/null +++ b/db/migrate/20120930112914_add_journals_private_notes.rb @@ -0,0 +1,9 @@ +class AddJournalsPrivateNotes < ActiveRecord::Migration + def up + add_column :journals, :private_notes, :boolean, :default => false, :null => false + end + + def down + remove_column :journals, :private_notes + end +end diff --git a/db/migrate/20121026002032_add_enumerations_position_name.rb b/db/migrate/20121026002032_add_enumerations_position_name.rb new file mode 100644 index 00000000..52cbe08e --- /dev/null +++ b/db/migrate/20121026002032_add_enumerations_position_name.rb @@ -0,0 +1,9 @@ +class AddEnumerationsPositionName < ActiveRecord::Migration + def up + add_column :enumerations, :position_name, :string, :limit => 30 + end + + def down + remove_column :enumerations, :position_name + end +end diff --git a/db/migrate/20121026003537_populate_enumerations_position_name.rb b/db/migrate/20121026003537_populate_enumerations_position_name.rb new file mode 100644 index 00000000..31777b75 --- /dev/null +++ b/db/migrate/20121026003537_populate_enumerations_position_name.rb @@ -0,0 +1,9 @@ +class PopulateEnumerationsPositionName < ActiveRecord::Migration + def up + IssuePriority.compute_position_names + end + + def down + IssuePriority.clear_position_names + end +end diff --git a/db/migrate/20121209123234_add_queries_type.rb b/db/migrate/20121209123234_add_queries_type.rb new file mode 100644 index 00000000..202d524e --- /dev/null +++ b/db/migrate/20121209123234_add_queries_type.rb @@ -0,0 +1,9 @@ +class AddQueriesType < ActiveRecord::Migration + def up + add_column :queries, :type, :string + end + + def down + remove_column :queries, :type + end +end diff --git a/db/migrate/20121209123358_update_queries_to_sti.rb b/db/migrate/20121209123358_update_queries_to_sti.rb new file mode 100644 index 00000000..d8dea407 --- /dev/null +++ b/db/migrate/20121209123358_update_queries_to_sti.rb @@ -0,0 +1,9 @@ +class UpdateQueriesToSti < ActiveRecord::Migration + def up + ::Query.update_all :type => 'IssueQuery' + end + + def down + ::Query.update_all :type => nil + end +end diff --git a/db/migrate/20121213084931_add_attachments_disk_directory.rb b/db/migrate/20121213084931_add_attachments_disk_directory.rb new file mode 100644 index 00000000..d11fcad9 --- /dev/null +++ b/db/migrate/20121213084931_add_attachments_disk_directory.rb @@ -0,0 +1,9 @@ +class AddAttachmentsDiskDirectory < ActiveRecord::Migration + def up + add_column :attachments, :disk_directory, :string + end + + def down + remove_column :attachments, :disk_directory + end +end diff --git a/db/migrate/20130110122628_split_documents_permissions.rb b/db/migrate/20130110122628_split_documents_permissions.rb new file mode 100644 index 00000000..0e010aa5 --- /dev/null +++ b/db/migrate/20130110122628_split_documents_permissions.rb @@ -0,0 +1,23 @@ +class SplitDocumentsPermissions < ActiveRecord::Migration + def up + # :manage_documents permission split into 3 permissions: + # :add_documents, :edit_documents and :delete_documents + Role.all.each do |role| + if role.has_permission?(:manage_documents) + role.add_permission! :add_documents, :edit_documents, :delete_documents + role.remove_permission! :manage_documents + end + end + end + + def down + Role.all.each do |role| + if role.has_permission?(:add_documents) || + role.has_permission?(:edit_documents) || + role.has_permission?(:delete_documents) + role.remove_permission! :add_documents, :edit_documents, :delete_documents + role.add_permission! :manage_documents + end + end + end +end diff --git a/db/migrate/20130201184705_add_unique_index_on_tokens_value.rb b/db/migrate/20130201184705_add_unique_index_on_tokens_value.rb new file mode 100644 index 00000000..fdec9f8e --- /dev/null +++ b/db/migrate/20130201184705_add_unique_index_on_tokens_value.rb @@ -0,0 +1,15 @@ +class AddUniqueIndexOnTokensValue < ActiveRecord::Migration + def up + say_with_time "Adding unique index on tokens, this may take some time..." do + # Just in case + duplicates = Token.connection.select_values("SELECT value FROM #{Token.table_name} GROUP BY value HAVING COUNT(id) > 1") + Token.where(:value => duplicates).delete_all + + add_index :tokens, :value, :unique => true, :name => 'tokens_value' + end + end + + def down + remove_index :tokens, :name => 'tokens_value' + end +end diff --git a/db/migrate/20130202090625_add_projects_inherit_members.rb b/db/migrate/20130202090625_add_projects_inherit_members.rb new file mode 100644 index 00000000..9cf5bade --- /dev/null +++ b/db/migrate/20130202090625_add_projects_inherit_members.rb @@ -0,0 +1,9 @@ +class AddProjectsInheritMembers < ActiveRecord::Migration + def up + add_column :projects, :inherit_members, :boolean, :default => false, :null => false + end + + def down + remove_column :projects, :inherit_members + end +end diff --git a/db/migrate/20130207175206_add_unique_index_on_custom_fields_trackers.rb b/db/migrate/20130207175206_add_unique_index_on_custom_fields_trackers.rb new file mode 100644 index 00000000..9977dcd5 --- /dev/null +++ b/db/migrate/20130207175206_add_unique_index_on_custom_fields_trackers.rb @@ -0,0 +1,24 @@ +class AddUniqueIndexOnCustomFieldsTrackers < ActiveRecord::Migration + def up + table_name = "#{CustomField.table_name_prefix}custom_fields_trackers#{CustomField.table_name_suffix}" + duplicates = CustomField.connection.select_rows("SELECT custom_field_id, tracker_id FROM #{table_name} GROUP BY custom_field_id, tracker_id HAVING COUNT(*) > 1") + duplicates.each do |custom_field_id, tracker_id| + # Removes duplicate rows + CustomField.connection.execute("DELETE FROM #{table_name} WHERE custom_field_id=#{custom_field_id} AND tracker_id=#{tracker_id}") + # And insert one + CustomField.connection.execute("INSERT INTO #{table_name} (custom_field_id, tracker_id) VALUES (#{custom_field_id}, #{tracker_id})") + end + + if index_exists? :custom_fields_trackers, [:custom_field_id, :tracker_id] + remove_index :custom_fields_trackers, [:custom_field_id, :tracker_id] + end + add_index :custom_fields_trackers, [:custom_field_id, :tracker_id], :unique => true + end + + def down + if index_exists? :custom_fields_trackers, [:custom_field_id, :tracker_id] + remove_index :custom_fields_trackers, [:custom_field_id, :tracker_id] + end + add_index :custom_fields_trackers, [:custom_field_id, :tracker_id] + end +end diff --git a/db/migrate/20130207181455_add_unique_index_on_custom_fields_projects.rb b/db/migrate/20130207181455_add_unique_index_on_custom_fields_projects.rb new file mode 100644 index 00000000..223818d4 --- /dev/null +++ b/db/migrate/20130207181455_add_unique_index_on_custom_fields_projects.rb @@ -0,0 +1,24 @@ +class AddUniqueIndexOnCustomFieldsProjects < ActiveRecord::Migration + def up + table_name = "#{CustomField.table_name_prefix}custom_fields_projects#{CustomField.table_name_suffix}" + duplicates = CustomField.connection.select_rows("SELECT custom_field_id, project_id FROM #{table_name} GROUP BY custom_field_id, project_id HAVING COUNT(*) > 1") + duplicates.each do |custom_field_id, project_id| + # Removes duplicate rows + CustomField.connection.execute("DELETE FROM #{table_name} WHERE custom_field_id=#{custom_field_id} AND project_id=#{project_id}") + # And insert one + CustomField.connection.execute("INSERT INTO #{table_name} (custom_field_id, project_id) VALUES (#{custom_field_id}, #{project_id})") + end + + if index_exists? :custom_fields_projects, [:custom_field_id, :project_id] + remove_index :custom_fields_projects, [:custom_field_id, :project_id] + end + add_index :custom_fields_projects, [:custom_field_id, :project_id], :unique => true + end + + def down + if index_exists? :custom_fields_projects, [:custom_field_id, :project_id] + remove_index :custom_fields_projects, [:custom_field_id, :project_id] + end + add_index :custom_fields_projects, [:custom_field_id, :project_id] + end +end diff --git a/db/migrate/20130215073721_change_users_lastname_length_to_255.rb b/db/migrate/20130215073721_change_users_lastname_length_to_255.rb new file mode 100644 index 00000000..7d68e37d --- /dev/null +++ b/db/migrate/20130215073721_change_users_lastname_length_to_255.rb @@ -0,0 +1,9 @@ +class ChangeUsersLastnameLengthTo255 < ActiveRecord::Migration + def self.up + change_column :users, :lastname, :string, :limit => 255, :default => '', :null => false + end + + def self.down + change_column :users, :lastname, :string, :limit => 30, :default => '', :null => false + end +end diff --git a/db/migrate/20130215111127_add_issues_closed_on.rb b/db/migrate/20130215111127_add_issues_closed_on.rb new file mode 100644 index 00000000..2670deba --- /dev/null +++ b/db/migrate/20130215111127_add_issues_closed_on.rb @@ -0,0 +1,9 @@ +class AddIssuesClosedOn < ActiveRecord::Migration + def up + add_column :issues, :closed_on, :datetime, :default => nil + end + + def down + remove_column :issues, :closed_on + end +end diff --git a/db/migrate/20130215111141_populate_issues_closed_on.rb b/db/migrate/20130215111141_populate_issues_closed_on.rb new file mode 100644 index 00000000..b2a828be --- /dev/null +++ b/db/migrate/20130215111141_populate_issues_closed_on.rb @@ -0,0 +1,25 @@ +class PopulateIssuesClosedOn < ActiveRecord::Migration + def up + closed_status_ids = IssueStatus.where(:is_closed => true).pluck(:id) + if closed_status_ids.any? + # First set closed_on for issues that have been closed once + closed_status_values = closed_status_ids.map {|status_id| "'#{status_id}'"}.join(',') + subselect = "SELECT MAX(#{Journal.table_name}.created_on)" + + " FROM #{Journal.table_name}, #{JournalDetail.table_name}" + + " WHERE #{Journal.table_name}.id = #{JournalDetail.table_name}.journal_id" + + " AND #{Journal.table_name}.journalized_type = 'Issue' AND #{Journal.table_name}.journalized_id = #{Issue.table_name}.id" + + " AND #{JournalDetail.table_name}.property = 'attr' AND #{JournalDetail.table_name}.prop_key = 'status_id'" + + " AND #{JournalDetail.table_name}.old_value NOT IN (#{closed_status_values})" + + " AND #{JournalDetail.table_name}.value IN (#{closed_status_values})" + Issue.update_all "closed_on = (#{subselect})" + + # Then set closed_on for closed issues that weren't up updated by the above UPDATE + # No journal was found so we assume that they were closed on creation + Issue.update_all "closed_on = created_on", {:status_id => closed_status_ids, :closed_on => nil} + end + end + + def down + Issue.update_all :closed_on => nil + end +end diff --git a/db/migrate/20130217094251_remove_issues_default_fk_values.rb b/db/migrate/20130217094251_remove_issues_default_fk_values.rb new file mode 100644 index 00000000..9345cf0b --- /dev/null +++ b/db/migrate/20130217094251_remove_issues_default_fk_values.rb @@ -0,0 +1,19 @@ +class RemoveIssuesDefaultFkValues < ActiveRecord::Migration + def up + change_column_default :issues, :tracker_id, nil + change_column_default :issues, :project_id, nil + change_column_default :issues, :status_id, nil + change_column_default :issues, :assigned_to_id, nil + change_column_default :issues, :priority_id, nil + change_column_default :issues, :author_id, nil + end + + def down + change_column_default :issues, :tracker_id, 0 + change_column_default :issues, :project_id, 0 + change_column_default :issues, :status_id, 0 + change_column_default :issues, :assigned_to_id, 0 + change_column_default :issues, :priority_id, 0 + change_column_default :issues, :author_id, 0 + end +end diff --git a/db/migrate/20130725021433_acts_as_taggable_on_migration.rb b/db/migrate/20130725021433_acts_as_taggable_on_migration.rb new file mode 100644 index 00000000..e8b978d9 --- /dev/null +++ b/db/migrate/20130725021433_acts_as_taggable_on_migration.rb @@ -0,0 +1,30 @@ +class ActsAsTaggableOnMigration < ActiveRecord::Migration + def self.up + create_table :tags do |t| + t.string :name + end + + create_table :taggings do |t| + t.references :tag + + # You should make sure that the column created is + # long enough to store the required class names. + t.references :taggable, :polymorphic => true + t.references :tagger, :polymorphic => true + + # Limit is created to prevent MySQL error on index + # length for MyISAM table type: http://bit.ly/vgW2Ql + t.string :context, :limit => 128 + + t.datetime :created_at + end + + add_index :taggings, :tag_id + add_index :taggings, [:taggable_id, :taggable_type, :context] + end + + def self.down + drop_table :taggings + drop_table :tags + end +end diff --git a/db/migrate/20130725122407_create_bids.rb b/db/migrate/20130725122407_create_bids.rb new file mode 100644 index 00000000..7297712d --- /dev/null +++ b/db/migrate/20130725122407_create_bids.rb @@ -0,0 +1,13 @@ +class CreateBids < ActiveRecord::Migration + def change + create_table :bids do |t| + t.string :name + t.integer :budget + t.integer :author_id + t.date :deadline + t.string :description + + t.timestamps + end + end +end diff --git a/db/migrate/20130725132508_create_biding_projects.rb b/db/migrate/20130725132508_create_biding_projects.rb new file mode 100644 index 00000000..9eaf7bde --- /dev/null +++ b/db/migrate/20130725132508_create_biding_projects.rb @@ -0,0 +1,12 @@ +class CreateBidingProjects < ActiveRecord::Migration + def change + create_table :biding_projects do |t| + t.integer :project_id + t.integer :bid_id + t.integer :user_id + t.string :description + + t.timestamps + end + end +end diff --git a/db/migrate/20130727021306_create_journals_for_messages.rb b/db/migrate/20130727021306_create_journals_for_messages.rb new file mode 100644 index 00000000..cd19ed9f --- /dev/null +++ b/db/migrate/20130727021306_create_journals_for_messages.rb @@ -0,0 +1,14 @@ +class CreateJournalsForMessages < ActiveRecord::Migration + def change + create_table :journals_for_messages do |t| + t.integer :jour_id + t.string :jour_type + t.integer :user_id + t.text :notes + t.integer :status + t.integer :reply_id + + t.timestamps + end + end +end diff --git a/db/migrate/20130728021709_add_commit_to_bids.rb b/db/migrate/20130728021709_add_commit_to_bids.rb new file mode 100644 index 00000000..dc0cd93f --- /dev/null +++ b/db/migrate/20130728021709_add_commit_to_bids.rb @@ -0,0 +1,5 @@ +class AddCommitToBids < ActiveRecord::Migration + def change + add_column :bids, :commit, :integer + end +end diff --git a/db/schema.rb b/db/schema.rb new file mode 100644 index 00000000..a6de651e --- /dev/null +++ b/db/schema.rb @@ -0,0 +1,741 @@ +# encoding: UTF-8 +# This file is auto-generated from the current state of the database. Instead +# of editing this file, please use the migrations feature of Active Record to +# incrementally modify your database, and then regenerate this schema definition. +# +# Note that this schema.rb definition is the authoritative source for your +# database schema. If you need to create the application database on another +# system, you should be using db:schema:load, not running all the migrations +# from scratch. The latter is a flawed and unsustainable approach (the more migrations +# you'll amass, the slower it'll run and the greater likelihood for issues). +# +# It's strongly recommended to check this file into your version control system. + +ActiveRecord::Schema.define(:version => 20130729033444) do + + create_table "a_user_watchers", :force => true do |t| + t.string "name" + t.text "description" + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + t.integer "member_id" + end + + create_table "attachments", :force => true do |t| + t.integer "container_id" + t.string "container_type", :limit => 30 + t.string "filename", :default => "", :null => false + t.string "disk_filename", :default => "", :null => false + t.integer "filesize", :default => 0, :null => false + t.string "content_type", :default => "" + t.string "digest", :limit => 40, :default => "", :null => false + t.integer "downloads", :default => 0, :null => false + t.integer "author_id", :default => 0, :null => false + t.datetime "created_on" + t.string "description" + t.string "disk_directory" + end + + add_index "attachments", ["author_id"], :name => "index_attachments_on_author_id" + add_index "attachments", ["container_id", "container_type"], :name => "index_attachments_on_container_id_and_container_type" + add_index "attachments", ["created_on"], :name => "index_attachments_on_created_on" + + create_table "auth_sources", :force => true do |t| + t.string "type", :limit => 30, :default => "", :null => false + t.string "name", :limit => 60, :default => "", :null => false + t.string "host", :limit => 60 + t.integer "port" + t.string "account" + t.string "account_password", :default => "" + t.string "base_dn" + t.string "attr_login", :limit => 30 + t.string "attr_firstname", :limit => 30 + t.string "attr_lastname", :limit => 30 + t.string "attr_mail", :limit => 30 + t.boolean "onthefly_register", :default => false, :null => false + t.boolean "tls", :default => false, :null => false + t.string "filter" + t.integer "timeout" + end + + add_index "auth_sources", ["id", "type"], :name => "index_auth_sources_on_id_and_type" + + create_table "b_watcher_lists", :force => true do |t| + t.string "name" + t.integer "user_id" + t.string "sexual" + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + end + + create_table "biding_projects", :force => true do |t| + t.integer "project_id" + t.integer "bid_id" + t.integer "user_id" + t.string "description" + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + end + + create_table "bids", :force => true do |t| + t.string "name" + t.integer "budget" + t.integer "author_id" + t.date "deadline" + t.string "description" + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + t.integer "commit" + end + + create_table "boards", :force => true do |t| + t.integer "project_id", :null => false + t.string "name", :default => "", :null => false + t.string "description" + t.integer "position", :default => 1 + t.integer "topics_count", :default => 0, :null => false + t.integer "messages_count", :default => 0, :null => false + t.integer "last_message_id" + t.integer "parent_id" + end + + add_index "boards", ["last_message_id"], :name => "index_boards_on_last_message_id" + add_index "boards", ["project_id"], :name => "boards_project_id" + + create_table "changes", :force => true do |t| + t.integer "changeset_id", :null => false + t.string "action", :limit => 1, :default => "", :null => false + t.text "path", :null => false + t.text "from_path" + t.string "from_revision" + t.string "revision" + t.string "branch" + end + + add_index "changes", ["changeset_id"], :name => "changesets_changeset_id" + + create_table "changeset_parents", :id => false, :force => true do |t| + t.integer "changeset_id", :null => false + t.integer "parent_id", :null => false + end + + add_index "changeset_parents", ["changeset_id"], :name => "changeset_parents_changeset_ids" + add_index "changeset_parents", ["parent_id"], :name => "changeset_parents_parent_ids" + + create_table "changesets", :force => true do |t| + t.integer "repository_id", :null => false + t.string "revision", :null => false + t.string "committer" + t.datetime "committed_on", :null => false + t.text "comments" + t.date "commit_date" + t.string "scmid" + t.integer "user_id" + end + + add_index "changesets", ["committed_on"], :name => "index_changesets_on_committed_on" + add_index "changesets", ["repository_id", "revision"], :name => "changesets_repos_rev", :unique => true + add_index "changesets", ["repository_id", "scmid"], :name => "changesets_repos_scmid" + add_index "changesets", ["repository_id"], :name => "index_changesets_on_repository_id" + add_index "changesets", ["user_id"], :name => "index_changesets_on_user_id" + + create_table "changesets_issues", :id => false, :force => true do |t| + t.integer "changeset_id", :null => false + t.integer "issue_id", :null => false + end + + add_index "changesets_issues", ["changeset_id", "issue_id"], :name => "changesets_issues_ids", :unique => true + + create_table "comments", :force => true do |t| + t.string "commented_type", :limit => 30, :default => "", :null => false + t.integer "commented_id", :default => 0, :null => false + t.integer "author_id", :default => 0, :null => false + t.text "comments" + t.datetime "created_on", :null => false + t.datetime "updated_on", :null => false + end + + add_index "comments", ["author_id"], :name => "index_comments_on_author_id" + add_index "comments", ["commented_id", "commented_type"], :name => "index_comments_on_commented_id_and_commented_type" + + create_table "custom_fields", :force => true do |t| + t.string "type", :limit => 30, :default => "", :null => false + t.string "name", :limit => 30, :default => "", :null => false + t.string "field_format", :limit => 30, :default => "", :null => false + t.text "possible_values" + t.string "regexp", :default => "" + t.integer "min_length", :default => 0, :null => false + t.integer "max_length", :default => 0, :null => false + t.boolean "is_required", :default => false, :null => false + t.boolean "is_for_all", :default => false, :null => false + t.boolean "is_filter", :default => false, :null => false + t.integer "position", :default => 1 + t.boolean "searchable", :default => false + t.text "default_value" + t.boolean "editable", :default => true + t.boolean "visible", :default => true, :null => false + t.boolean "multiple", :default => false + end + + add_index "custom_fields", ["id", "type"], :name => "index_custom_fields_on_id_and_type" + + create_table "custom_fields_projects", :id => false, :force => true do |t| + t.integer "custom_field_id", :default => 0, :null => false + t.integer "project_id", :default => 0, :null => false + end + + add_index "custom_fields_projects", ["custom_field_id", "project_id"], :name => "index_custom_fields_projects_on_custom_field_id_and_project_id", :unique => true + + create_table "custom_fields_trackers", :id => false, :force => true do |t| + t.integer "custom_field_id", :default => 0, :null => false + t.integer "tracker_id", :default => 0, :null => false + end + + add_index "custom_fields_trackers", ["custom_field_id", "tracker_id"], :name => "index_custom_fields_trackers_on_custom_field_id_and_tracker_id", :unique => true + + create_table "custom_values", :force => true do |t| + t.string "customized_type", :limit => 30, :default => "", :null => false + t.integer "customized_id", :default => 0, :null => false + t.integer "custom_field_id", :default => 0, :null => false + t.text "value" + end + + add_index "custom_values", ["custom_field_id"], :name => "index_custom_values_on_custom_field_id" + add_index "custom_values", ["customized_type", "customized_id"], :name => "custom_values_customized" + + create_table "documents", :force => true do |t| + t.integer "project_id", :default => 0, :null => false + t.integer "category_id", :default => 0, :null => false + t.string "title", :limit => 60, :default => "", :null => false + t.text "description" + t.datetime "created_on" + end + + add_index "documents", ["category_id"], :name => "index_documents_on_category_id" + add_index "documents", ["created_on"], :name => "index_documents_on_created_on" + add_index "documents", ["project_id"], :name => "documents_project_id" + + create_table "enabled_modules", :force => true do |t| + t.integer "project_id" + t.string "name", :null => false + end + + add_index "enabled_modules", ["project_id"], :name => "enabled_modules_project_id" + + create_table "enumerations", :force => true do |t| + t.string "name", :limit => 30, :default => "", :null => false + t.integer "position", :default => 1 + t.boolean "is_default", :default => false, :null => false + t.string "type" + t.boolean "active", :default => true, :null => false + t.integer "project_id" + t.integer "parent_id" + t.string "position_name", :limit => 30 + end + + add_index "enumerations", ["id", "type"], :name => "index_enumerations_on_id_and_type" + add_index "enumerations", ["project_id"], :name => "index_enumerations_on_project_id" + + create_table "groups_users", :id => false, :force => true do |t| + t.integer "group_id", :null => false + t.integer "user_id", :null => false + end + + add_index "groups_users", ["group_id", "user_id"], :name => "groups_users_ids", :unique => true + + create_table "issue_categories", :force => true do |t| + t.integer "project_id", :default => 0, :null => false + t.string "name", :limit => 30, :default => "", :null => false + t.integer "assigned_to_id" + end + + add_index "issue_categories", ["assigned_to_id"], :name => "index_issue_categories_on_assigned_to_id" + add_index "issue_categories", ["project_id"], :name => "issue_categories_project_id" + + create_table "issue_relations", :force => true do |t| + t.integer "issue_from_id", :null => false + t.integer "issue_to_id", :null => false + t.string "relation_type", :null => false + t.integer "delay" + end + + add_index "issue_relations", ["issue_from_id", "issue_to_id"], :name => "index_issue_relations_on_issue_from_id_and_issue_to_id", :unique => true + add_index "issue_relations", ["issue_from_id"], :name => "index_issue_relations_on_issue_from_id" + add_index "issue_relations", ["issue_to_id"], :name => "index_issue_relations_on_issue_to_id" + + create_table "issue_statuses", :force => true do |t| + t.string "name", :limit => 30, :default => "", :null => false + t.boolean "is_closed", :default => false, :null => false + t.boolean "is_default", :default => false, :null => false + t.integer "position", :default => 1 + t.integer "default_done_ratio" + end + + add_index "issue_statuses", ["is_closed"], :name => "index_issue_statuses_on_is_closed" + add_index "issue_statuses", ["is_default"], :name => "index_issue_statuses_on_is_default" + add_index "issue_statuses", ["position"], :name => "index_issue_statuses_on_position" + + create_table "issues", :force => true do |t| + t.integer "tracker_id", :null => false + t.integer "project_id", :null => false + t.string "subject", :default => "", :null => false + t.text "description" + t.date "due_date" + t.integer "category_id" + t.integer "status_id", :null => false + t.integer "assigned_to_id" + t.integer "priority_id", :null => false + t.integer "fixed_version_id" + t.integer "author_id", :null => false + t.integer "lock_version", :default => 0, :null => false + t.datetime "created_on" + t.datetime "updated_on" + t.date "start_date" + t.integer "done_ratio", :default => 0, :null => false + t.float "estimated_hours" + t.integer "parent_id" + t.integer "root_id" + t.integer "lft" + t.integer "rgt" + t.boolean "is_private", :default => false, :null => false + t.datetime "closed_on" + end + + add_index "issues", ["assigned_to_id"], :name => "index_issues_on_assigned_to_id" + add_index "issues", ["author_id"], :name => "index_issues_on_author_id" + add_index "issues", ["category_id"], :name => "index_issues_on_category_id" + add_index "issues", ["created_on"], :name => "index_issues_on_created_on" + add_index "issues", ["fixed_version_id"], :name => "index_issues_on_fixed_version_id" + add_index "issues", ["priority_id"], :name => "index_issues_on_priority_id" + add_index "issues", ["project_id"], :name => "issues_project_id" + add_index "issues", ["root_id", "lft", "rgt"], :name => "index_issues_on_root_id_and_lft_and_rgt" + add_index "issues", ["status_id"], :name => "index_issues_on_status_id" + add_index "issues", ["tracker_id"], :name => "index_issues_on_tracker_id" + + create_table "journal_details", :force => true do |t| + t.integer "journal_id", :default => 0, :null => false + t.string "property", :limit => 30, :default => "", :null => false + t.string "prop_key", :limit => 30, :default => "", :null => false + t.text "old_value" + t.text "value" + end + + add_index "journal_details", ["journal_id"], :name => "journal_details_journal_id" + + create_table "journals", :force => true do |t| + t.integer "journalized_id", :default => 0, :null => false + t.string "journalized_type", :limit => 30, :default => "", :null => false + t.integer "user_id", :default => 0, :null => false + t.text "notes" + t.datetime "created_on", :null => false + t.boolean "private_notes", :default => false, :null => false + end + + add_index "journals", ["created_on"], :name => "index_journals_on_created_on" + add_index "journals", ["journalized_id", "journalized_type"], :name => "journals_journalized_id" + add_index "journals", ["journalized_id"], :name => "index_journals_on_journalized_id" + add_index "journals", ["user_id"], :name => "index_journals_on_user_id" + + create_table "journals_for_messages", :force => true do |t| + t.integer "jour_id" + t.string "jour_type" + t.integer "user_id" + t.text "notes" + t.integer "status" + t.integer "reply_id" + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + end + + create_table "member_roles", :force => true do |t| + t.integer "member_id", :null => false + t.integer "role_id", :null => false + t.integer "inherited_from" + end + + add_index "member_roles", ["member_id"], :name => "index_member_roles_on_member_id" + add_index "member_roles", ["role_id"], :name => "index_member_roles_on_role_id" + + create_table "members", :force => true do |t| + t.integer "user_id", :default => 0, :null => false + t.integer "project_id", :default => 0, :null => false + t.datetime "created_on" + t.boolean "mail_notification", :default => false, :null => false + end + + add_index "members", ["project_id"], :name => "index_members_on_project_id" + add_index "members", ["user_id", "project_id"], :name => "index_members_on_user_id_and_project_id", :unique => true + add_index "members", ["user_id"], :name => "index_members_on_user_id" + + create_table "messages", :force => true do |t| + t.integer "board_id", :null => false + t.integer "parent_id" + t.string "subject", :default => "", :null => false + t.text "content" + t.integer "author_id" + t.integer "replies_count", :default => 0, :null => false + t.integer "last_reply_id" + t.datetime "created_on", :null => false + t.datetime "updated_on", :null => false + t.boolean "locked", :default => false + t.integer "sticky", :default => 0 + end + + add_index "messages", ["author_id"], :name => "index_messages_on_author_id" + add_index "messages", ["board_id"], :name => "messages_board_id" + add_index "messages", ["created_on"], :name => "index_messages_on_created_on" + add_index "messages", ["last_reply_id"], :name => "index_messages_on_last_reply_id" + add_index "messages", ["parent_id"], :name => "messages_parent_id" + + create_table "messages_for_bids", :force => true do |t| + t.string "message" + t.integer "user_id" + t.integer "bid_id" + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + end + + create_table "messages_for_users", :force => true do |t| + t.integer "messager_id" + t.integer "user_id" + t.string "message" + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + end + + create_table "news", :force => true do |t| + t.integer "project_id" + t.string "title", :limit => 60, :default => "", :null => false + t.string "summary", :default => "" + t.text "description" + t.integer "author_id", :default => 0, :null => false + t.datetime "created_on" + t.integer "comments_count", :default => 0, :null => false + end + + add_index "news", ["author_id"], :name => "index_news_on_author_id" + add_index "news", ["created_on"], :name => "index_news_on_created_on" + add_index "news", ["project_id"], :name => "news_project_id" + + create_table "open_id_authentication_associations", :force => true do |t| + t.integer "issued" + t.integer "lifetime" + t.string "handle" + t.string "assoc_type" + t.binary "server_url" + t.binary "secret" + end + + create_table "open_id_authentication_nonces", :force => true do |t| + t.integer "timestamp", :null => false + t.string "server_url" + t.string "salt", :null => false + end + + create_table "project_tags", :force => true do |t| + t.integer "project_id" + t.integer "tag_id" + t.string "description" + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + t.integer "user_id" + end + + create_table "projects", :force => true do |t| + t.string "name", :default => "", :null => false + t.text "description" + t.string "homepage", :default => "" + t.boolean "is_public", :default => true, :null => false + t.integer "parent_id" + t.datetime "created_on" + t.datetime "updated_on" + t.string "identifier" + t.integer "status", :default => 1, :null => false + t.integer "lft" + t.integer "rgt" + t.boolean "inherit_members", :default => false, :null => false + end + + add_index "projects", ["lft"], :name => "index_projects_on_lft" + add_index "projects", ["rgt"], :name => "index_projects_on_rgt" + + create_table "projects_trackers", :id => false, :force => true do |t| + t.integer "project_id", :default => 0, :null => false + t.integer "tracker_id", :default => 0, :null => false + end + + add_index "projects_trackers", ["project_id", "tracker_id"], :name => "projects_trackers_unique", :unique => true + add_index "projects_trackers", ["project_id"], :name => "projects_trackers_project_id" + + create_table "queries", :force => true do |t| + t.integer "project_id" + t.string "name", :default => "", :null => false + t.text "filters" + t.integer "user_id", :default => 0, :null => false + t.boolean "is_public", :default => false, :null => false + t.text "column_names" + t.text "sort_criteria" + t.string "group_by" + t.string "type" + end + + add_index "queries", ["project_id"], :name => "index_queries_on_project_id" + add_index "queries", ["user_id"], :name => "index_queries_on_user_id" + + create_table "repositories", :force => true do |t| + t.integer "project_id", :default => 0, :null => false + t.string "url", :default => "", :null => false + t.string "login", :limit => 60, :default => "" + t.string "password", :default => "" + t.string "root_url", :default => "" + t.string "type" + t.string "path_encoding", :limit => 64 + t.string "log_encoding", :limit => 64 + t.text "extra_info" + t.string "identifier" + t.boolean "is_default", :default => false + end + + add_index "repositories", ["project_id"], :name => "index_repositories_on_project_id" + + create_table "roles", :force => true do |t| + t.string "name", :limit => 30, :default => "", :null => false + t.integer "position", :default => 1 + t.boolean "assignable", :default => true + t.integer "builtin", :default => 0, :null => false + t.text "permissions" + t.string "issues_visibility", :limit => 30, :default => "default", :null => false + end + + create_table "settings", :force => true do |t| + t.string "name", :default => "", :null => false + t.text "value" + t.datetime "updated_on" + end + + add_index "settings", ["name"], :name => "index_settings_on_name" + + create_table "shares", :force => true do |t| + t.string "title" + t.string "type" + t.string "url" + t.date "created_on" + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + end + + create_table "students", :force => true do |t| + t.string "name" + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + end + + create_table "taggings", :force => true do |t| + t.integer "tag_id" + t.integer "taggable_id" + t.string "taggable_type" + t.integer "tagger_id" + t.string "tagger_type" + t.string "context", :limit => 128 + t.datetime "created_at" + end + + add_index "taggings", ["tag_id"], :name => "index_taggings_on_tag_id" + add_index "taggings", ["taggable_id", "taggable_type", "context"], :name => "index_taggings_on_taggable_id_and_taggable_type_and_context" + + create_table "tags", :force => true do |t| + t.string "name" + end + + create_table "time_entries", :force => true do |t| + t.integer "project_id", :null => false + t.integer "user_id", :null => false + t.integer "issue_id" + t.float "hours", :null => false + t.string "comments" + t.integer "activity_id", :null => false + t.date "spent_on", :null => false + t.integer "tyear", :null => false + t.integer "tmonth", :null => false + t.integer "tweek", :null => false + t.datetime "created_on", :null => false + t.datetime "updated_on", :null => false + end + + add_index "time_entries", ["activity_id"], :name => "index_time_entries_on_activity_id" + add_index "time_entries", ["created_on"], :name => "index_time_entries_on_created_on" + add_index "time_entries", ["issue_id"], :name => "time_entries_issue_id" + add_index "time_entries", ["project_id"], :name => "time_entries_project_id" + add_index "time_entries", ["user_id"], :name => "index_time_entries_on_user_id" + + create_table "tokens", :force => true do |t| + t.integer "user_id", :default => 0, :null => false + t.string "action", :limit => 30, :default => "", :null => false + t.string "value", :limit => 40 + t.datetime "created_on", :null => false + end + + add_index "tokens", ["user_id"], :name => "index_tokens_on_user_id" + add_index "tokens", ["value"], :name => "tokens_value", :unique => true + + create_table "trackers", :force => true do |t| + t.string "name", :limit => 30, :default => "", :null => false + t.boolean "is_in_chlog", :default => false, :null => false + t.integer "position", :default => 1 + t.boolean "is_in_roadmap", :default => true, :null => false + t.integer "fields_bits", :default => 0 + end + + create_table "user_preferences", :force => true do |t| + t.integer "user_id", :default => 0, :null => false + t.text "others" + t.boolean "hide_mail", :default => false + t.string "time_zone" + end + + add_index "user_preferences", ["user_id"], :name => "index_user_preferences_on_user_id" + + create_table "user_tags", :force => true do |t| + t.integer "user_id" + t.integer "tag_id" + t.string "description" + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + end + + create_table "users", :force => true do |t| + t.string "login", :default => "", :null => false + t.string "hashed_password", :limit => 40, :default => "", :null => false + t.string "firstname", :limit => 30, :default => "", :null => false + t.string "lastname", :default => "", :null => false + t.string "mail", :limit => 60, :default => "", :null => false + t.boolean "admin", :default => false, :null => false + t.integer "status", :default => 1, :null => false + t.datetime "last_login_on" + t.string "language", :limit => 5, :default => "" + t.integer "auth_source_id" + t.datetime "created_on" + t.datetime "updated_on" + t.string "type" + t.string "identity_url" + t.string "mail_notification", :default => "", :null => false + t.string "salt", :limit => 64 + end + + add_index "users", ["auth_source_id"], :name => "index_users_on_auth_source_id" + add_index "users", ["id", "type"], :name => "index_users_on_id_and_type" + add_index "users", ["type"], :name => "index_users_on_type" + + create_table "versions", :force => true do |t| + t.integer "project_id", :default => 0, :null => false + t.string "name", :default => "", :null => false + t.string "description", :default => "" + t.date "effective_date" + t.datetime "created_on" + t.datetime "updated_on" + t.string "wiki_page_title" + t.string "status", :default => "open" + t.string "sharing", :default => "none", :null => false + end + + add_index "versions", ["project_id"], :name => "versions_project_id" + add_index "versions", ["sharing"], :name => "index_versions_on_sharing" + + create_table "watchers", :force => true do |t| + t.string "watchable_type", :default => "", :null => false + t.integer "watchable_id", :default => 0, :null => false + t.integer "user_id" + end + + add_index "watchers", ["user_id", "watchable_type"], :name => "watchers_user_id_type" + add_index "watchers", ["user_id"], :name => "index_watchers_on_user_id" + add_index "watchers", ["watchable_id", "watchable_type"], :name => "index_watchers_on_watchable_id_and_watchable_type" + + create_table "watchers_of_projects", :force => true do |t| + t.integer "user_id" + t.integer "project_id" + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + end + + create_table "watchers_of_users", :force => true do |t| + t.integer "watcher_id" + t.integer "user_id" + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + end + + create_table "wiki_content_versions", :force => true do |t| + t.integer "wiki_content_id", :null => false + t.integer "page_id", :null => false + t.integer "author_id" + t.binary "data", :limit => 2147483647 + t.string "compression", :limit => 6, :default => "" + t.string "comments", :default => "" + t.datetime "updated_on", :null => false + t.integer "version", :null => false + end + + add_index "wiki_content_versions", ["updated_on"], :name => "index_wiki_content_versions_on_updated_on" + add_index "wiki_content_versions", ["wiki_content_id"], :name => "wiki_content_versions_wcid" + + create_table "wiki_contents", :force => true do |t| + t.integer "page_id", :null => false + t.integer "author_id" + t.text "text", :limit => 2147483647 + t.string "comments", :default => "" + t.datetime "updated_on", :null => false + t.integer "version", :null => false + end + + add_index "wiki_contents", ["author_id"], :name => "index_wiki_contents_on_author_id" + add_index "wiki_contents", ["page_id"], :name => "wiki_contents_page_id" + + create_table "wiki_pages", :force => true do |t| + t.integer "wiki_id", :null => false + t.string "title", :null => false + t.datetime "created_on", :null => false + t.boolean "protected", :default => false, :null => false + t.integer "parent_id" + end + + add_index "wiki_pages", ["parent_id"], :name => "index_wiki_pages_on_parent_id" + add_index "wiki_pages", ["wiki_id", "title"], :name => "wiki_pages_wiki_id_title" + add_index "wiki_pages", ["wiki_id"], :name => "index_wiki_pages_on_wiki_id" + + create_table "wiki_redirects", :force => true do |t| + t.integer "wiki_id", :null => false + t.string "title" + t.string "redirects_to" + t.datetime "created_on", :null => false + end + + add_index "wiki_redirects", ["wiki_id", "title"], :name => "wiki_redirects_wiki_id_title" + add_index "wiki_redirects", ["wiki_id"], :name => "index_wiki_redirects_on_wiki_id" + + create_table "wikis", :force => true do |t| + t.integer "project_id", :null => false + t.string "start_page", :null => false + t.integer "status", :default => 1, :null => false + end + + add_index "wikis", ["project_id"], :name => "wikis_project_id" + + create_table "workflows", :force => true do |t| + t.integer "tracker_id", :default => 0, :null => false + t.integer "old_status_id", :default => 0, :null => false + t.integer "new_status_id", :default => 0, :null => false + t.integer "role_id", :default => 0, :null => false + t.boolean "assignee", :default => false, :null => false + t.boolean "author", :default => false, :null => false + t.string "type", :limit => 30 + t.string "field_name", :limit => 30 + t.string "rule", :limit => 30 + end + + add_index "workflows", ["new_status_id"], :name => "index_workflows_on_new_status_id" + add_index "workflows", ["old_status_id"], :name => "index_workflows_on_old_status_id" + add_index "workflows", ["role_id", "tracker_id", "old_status_id"], :name => "wkfs_role_tracker_old_status" + add_index "workflows", ["role_id"], :name => "index_workflows_on_role_id" + +end diff --git a/doc/CHANGELOG b/doc/CHANGELOG new file mode 100644 index 00000000..ad808770 --- /dev/null +++ b/doc/CHANGELOG @@ -0,0 +1,2451 @@ +== Redmine changelog + +Redmine - project management software +Copyright (C) 2006-2013 Jean-Philippe Lang +http://www.redmine.org/ + +== 2013-05-01 v2.3.1 + +* Defect #12650: Lost text after selection in issue list with IE +* Defect #12684: Hotkey for Issue-Edit doesn't work as expected +* Defect #13405: Commit link title is escaped twice when using "commit:" prefix +* Defect #13541: Can't access SCM when log/production.scm.stderr.log is not writable +* Defect #13579: Datepicker uses Simplified Chinese in Traditional Chinese locale +* Defect #13584: Missing Portuguese jQuery UI date picker +* Defect #13586: Circular loop testing prevents precedes/follows relation between subtasks +* Defect #13618: CSV export of spent time ignores filters and columns selection +* Defect #13630: PDF export generates the issue id twice +* Defect #13644: Diff - Internal Error +* Defect #13712: Fix email rake tasks to also support no_account_notice and default_group options +* Defect #13811: Broken javascript in IE7 ; recurrence of #12195 +* Defect #13823: Trailing comma in javascript files +* Patch #13531: Traditional Chinese translation for 2.3-stable +* Patch #13552: Dutch translations for 2.3-stable +* Patch #13678: Lithuanian translation for 2.3-stable + +== 2013-03-19 v2.3.0 + +* Defect #3107: Issue with two digit year on Logtime +* Defect #3371: Autologin does not work when using openid +* Defect #3676: www. generates broken link in formatted text +* Defect #4700: Adding news does not send notification to all project members +* Defect #5329: Time entries report broken on first week of year +* Defect #8794: Circular loop when using relations and subtasks +* Defect #9475: German Translation "My custom queries" and "Custom queries" +* Defect #9549: Only 100 users are displayed when adding new project members +* Defect #10277: Redmine wikitext URL-into-link creation with hyphen is wrong +* Defect #10364: Custom field float separator in CSV export +* Defect #10930: rake redmine:load_default_data error in 2.0 with SQLServer +* Defect #10977: Redmine shouldn't require all database gems +* Defect #12528: Handle temporary failures gracefully in the external mail handler script +* Defect #12629: Wrong German "label_issues_by" translation +* Defect #12641: Diff outputs become ??? in some non ASCII words. +* Defect #12707: Typo in app/models/tracker.rb +* Defect #12716: Attachment description lost when issue validation fails +* Defect #12735: Negative duration allowed +* Defect #12736: Negative start/due dates allowed +* Defect #12968: Subtasks don't resepect following/precedes +* Defect #13006: Filter "Assignee's group" doesn't work with group assignments +* Defect #13022: Image pointing towards /logout signs out user +* Defect #13059: Custom fields are listed two times in workflow/Fields permission +* Defect #13076: Project overview page shows trackers from subprojects with disabled issue module +* Defect #13119: custom_field_values are not reloaded on #reload +* Defect #13154: After upgrade to 2.2.2 ticket list on some projects fails +* Defect #13188: Forms are not updated after changing the status field without "Add issues" permission +* Defect #13251: Adding a "follows" relation may not refresh relations list +* Defect #13272: translation missing: setting_default_projects_tracker_ids +* Defect #13328: Copying an issue as a child of itself creates an extra issue +* Defect #13335: Autologin does not work with custom autologin cookie name +* Defect #13350: Japanese mistranslation fix +* Feature #824: Add "closed_on" issue field (storing time of last closing) & add it as a column and filter on the issue list. +* Feature #1766: Custom fields should become addable to Spent Time list/report +* Feature #3436: Show relations in Gantt diagram +* Feature #3957: Ajax file upload with progress bar +* Feature #5298: Store attachments in sub directories +* Feature #5605: Subprojects should (optionally) inherit Members from their parent +* Feature #6727: Add/remove issue watchers via REST API +* Feature #7159: Bulk watch/unwatch issues from the context menu +* Feature #8529: Get the API key of the user through REST API +* Feature #8579: Multiple file upload with HTML5 / Drag-and-Drop +* Feature #10191: Add Filters For Spent time's Details and Report +* Feature #10286: Auto-populate fields while creating a new user with LDAP +* Feature #10352: Preview should already display the freshly attached images +* Feature #11498: Add --no-account-notice option for the mail handler script +* Feature #12122: Gantt progress lines (html only) +* Feature #12228: JRuby 1.7.2 support +* Feature #12251: Custom fields: 'Multiple values' should be able to be checked and then unchecked +* Feature #12401: Split "Manage documents" permission into create, edit and delete permissions +* Feature #12542: Group events in the activity view +* Feature #12665: Link to a file in a repository branch +* Feature #12713: Microsoft SQLServer support +* Feature #12787: Remove "Warning - iconv will be deprecated in the future, use String#encode instead." +* Feature #12843: Add links to projects in Group projects list +* Feature #12898: Handle GET /issues/context_menu parameters nicely to prevent returning error 500 to crawlers +* Feature #12992: Make JSONP support optional and disabled by default +* Feature #13174: Raise group name maximum length to 255 characters +* Feature #13175: Possibility to define the default enable trackers when creating a project +* Feature #13329: Ruby 2.0 support +* Feature #13337: Split translation "label_total" +* Feature #13340: Mail handler: option to add created user to default group +* Feature #13341: Mail handler: --no-notification option to disable notifications to the created user +* Patch #7202: Polish translation for v1.0.4 +* Patch #7851: Italian translation for 'issue' +* Patch #9225: Generate project identifier automatically with JavaScript +* Patch #10916: Optimisation in issues relations display +* Patch #12485: Don't force english language for default admin account +* Patch #12499: Use lambda in model scopes +* Patch #12611: Login link unexpected logs you out +* Patch #12626: Updated Japanese translations for button_view and permission_commit_access +* Patch #12640: Russian "about_x_hours" translation change +* Patch #12645: Russian numeric translation +* Patch #12660: Consistent German translation for my page +* Patch #12708: Restructured german translation (Cleanup) +* Patch #12721: Optimize MenuManager a bit +* Patch #12725: Change pourcent to percent (#12724) +* Patch #12754: Updated Japanese translation for notice_account_register_done +* Patch #12788: Copyright for 2013 +* Patch #12806: Serbian translation change +* Patch #12810: Swedish Translation change +* Patch #12910: Plugin settings div should perhaps have 'settings' CSS class +* Patch #12911: Fix 500 error for requests to the settings path for non-configurable plugins +* Patch #12926: Bulgarian translation (r11218) +* Patch #12927: Swedish Translation for r11244 +* Patch #12967: Change Spanish login/logout translations +* Patch #12988: Russian translation for trunk +* Patch #13080: German translation of label_in +* Patch #13098: Small datepicker improvements +* Patch #13152: Locale file for Azerbaijanian language +* Patch #13155: Add login to /users/:id API for current user +* Patch #13173: Put source :rubygems url HTTP secure +* Patch #13190: Bulgarian translation (r11404) +* Patch #13198: Traditional Chinese language file (to r11426) +* Patch #13203: German translation change for follow and precedes is inconsitent +* Patch #13206: Portuguese translation file +* Patch #13246: Some german translation patches +* Patch #13280: German translation (r11478) +* Patch #13301: Performance: avoid querying all memberships in User#roles_for_project +* Patch #13309: Add "tracker-[id]" CSS class to issues +* Patch #13324: fixing some pt-br locales +* Patch #13339: Complete language Vietnamese file +* Patch #13391: Czech translation update +* Patch #13399: Fixed some wrong or confusing translation in Korean locale +* Patch #13414: Bulgarian translation (r11567) +* Patch #13420: Korean translation for 2.3 (r11583) +* Patch #13437: German translation of setting_emails_header +* Patch #13438: English translation +* Patch #13447: German translation - some patches +* Patch #13450: Czech translation +* Patch #13475: fixing some pt-br locales +* Patch #13514: fixing some pt-br locales + +== 2013-03-19 v2.2.4 + +* Upgrade to Rails 3.2.13 +* Defect #12243: Ordering forum replies by last reply date is broken +* Defect #13127: h1 multiple lined titles breaks into main menu +* Defect #13138: Generating PDF of issue causes UndefinedConversionError with htmlentities gem +* Defect #13165: rdm-mailhandler.rb: initialize_http_header override basic auth +* Defect #13232: Link to topic in nonexistent forum causes error 500 +* Patch #13181: Bulgarian translation of jstoolbar-bg.js +* Patch #13207: Portuguese translation for 2.2-stable +* Patch #13310: pt-BR label_last_n_weeks translation +* Patch #13325: pt-BR translation for 2.2-stable +* Patch #13343: Vietnamese translation for 2.2-stable +* Patch #13398: Czech translation for 2.2-stable + +== 2013-02-12 v2.2.3 + +* Upgrade to Rails 3.2.12 +* Defect #11987: pdf: Broken new line in table +* Defect #12930: 404 Error when referencing different project source files in the wiki syntax +* Defect #12979: Wiki link syntax commit:repo_a:abcd doesn't work +* Defect #13075: Can't clear custom field value through context menu in the issue list +* Defect #13097: Project copy fails when wiki module is disabled +* Defect #13126: Issue view: estimated time vs. spent time +* Patch #12922: Update Spanish translation +* Patch #12928: Bulgarian translation for 2.2-stable +* Patch #12987: Russian translation for 2.2-stable + +== 2013-01-20 v2.2.2 + +* Defect #7510: Link to attachment should return latest attachment +* Defect #9842: {{toc}} is not replaced by table of content when exporting wiki page to pdf +* Defect #12749: Plugins cannot route wiki page sub-path +* Defect #12799: Cannot edit a wiki section which title starts with a tab +* Defect #12801: Viewing the history of a wiki page with attachments raises an error +* Defect #12833: Input fields restricted on length should have maxlength parameter set +* Defect #12838: Blank page when clicking Add with no block selected on my page layout +* Defect #12851: "Parent task is invalid" while editing child issues by Role with restricted Issues Visibility +* Patch #12800: Serbian Latin translation patch (sr-YU.yml) +* Patch #12809: Swedish Translation for r11162 +* Patch #12818: Minor swedish translation fix + +== 2013-01-09 v2.2.1 + +* Upgrade to Rails 3.2.11 +* Defect #12652: "Copy ticket" selects "new ticket" +* Defect #12691: Textile Homepage Dead? +* Defect #12711: incorrect fix of lib/SVG/Graph/TimeSeries.rb +* Defect #12744: Unable to call a macro with a name that contains uppercase letters +* Defect #12776: Security vulnerability in Rails 3.2.10 (CVE-2013-0156) +* Patch #12630: Russian "x_hours" translation + +== 2012-12-18 v2.2.0 + +* Defect #4787: Gannt to PNG - CJK (Chinese, Japanese and Korean) characters appear as ? +* Defect #8106: Issues by Category should show tasks without category +* Defect #8373: i18n string text_are_you_sure_with_children no longer used +* Defect #11426: Filtering with Due Date in less than N days should show overdue issues +* Defect #11834: Bazaar: "???" instead of non ASCII character in paths on non UTF-8 locale +* Defect #11868: Git and Mercurial diff displays deleted files as /dev/null +* Defect #11979: No validation errors when entering an invalid "Parent task" +* Defect #12012: Redmine::VERSION.revision method does not work on Subversion 1.7 working copy +* Defect #12018: Issue filter select box order changes randomly +* Defect #12090: email recipients not written to action_mailer log if BCC recipients setting is checked +* Defect #12092: Issue "start date" validation does not work correctly +* Defect #12285: Some unit and functional tests miss fixtures and break when run alone +* Defect #12286: Emails of private notes are sent to watcher users regardless of viewing permissions +* Defect #12310: Attachments may not be displayed in the order they were selected +* Defect #12356: Issue "Update" link broken focus +* Defect #12397: Error in Textile conversion of HTTP links, containing russian letters +* Defect #12434: Respond with 404 instead of 500 when requesting a wiki diff with invalid versions +* Feature #1554: Private comments in tickets +* Feature #2161: Time tracking code should respect weekends as "no work" days +* Feature #3239: Show related issues on the Issues Listing +* Feature #3265: Filter on issue relations +* Feature #3447: Option to display the issue descriptions on the issues list +* Feature #3511: Ability to sort issues by grouped column +* Feature #4590: Precede-Follow relation should move following issues when rescheduling issue earlier +* Feature #5487: Allow subtasks to cross projects +* Feature #6899: Add a relation between the original and copied issue +* Feature #7082: Rest API for wiki +* Feature #9835: REST API - List priorities +* Feature #10789: Macros {{child_pages}} with depth parameter +* Feature #10852: Ability to delete a version from a wiki page history +* Feature #10937: new user format #{lastname} +* Feature #11502: Expose roles details via REST API +* Feature #11755: Impersonate user through REST API auth +* Feature #12085: New user name format: firstname + first letter of lastname +* Feature #12125: Set filename used to store attachment updloaded via the REST API +* Feature #12167: Macro for inserting collapsible block of text +* Feature #12211: Wrap issue description and its contextual menu in a div +* Feature #12216: Textual CSS class for priorities +* Feature #12299: Redmine version requirement improvements (in plugins) +* Feature #12393: Upgrade to Rails 3.2.9 +* Feature #12475: Lazy loading of translation files for faster startup +* Patch #11846: Fill username when authentification failed +* Patch #11862: Add "last 2 weeks" preset to time entries reporting +* Patch #11992: Japanese translation about issue relations improved +* Patch #12027: Incorrect Spanish "September" month name +* Patch #12061: Japanese translation improvement (permission names) +* Patch #12078: User#allowed_to? should return true or false +* Patch #12117: Change Japanese translation of "admin" +* Patch #12142: Updated translation in Lithuanian +* Patch #12232: German translation enhancements +* Patch #12316: Fix Lithuanian numeral translation +* Patch #12494: Bulgarian "button_submit" translation change +* Patch #12514: Updated translation in Lithuanian +* Patch #12602: Korean translation update for 2.2-stable +* Patch #12608: Norwegian translation changed +* Patch #12619: Russian translation change + +== 2012-12-18 v2.1.5 + +* Defect #12400: Validation fails when receiving an email with list custom fields +* Defect #12451: Macros.rb extract_macro_options should use lazy search +* Defect #12513: Grouping of issues by custom fields not correct in PDF export +* Defect #12566: Issue history notes previews are broken +* Defect #12568: Clicking "edit" on a journal multiple times shows multiple forms +* Patch #12605: Norwegian translation for 1.4-stable update +* Patch #12614: Dutch translation +* Patch #12615: Russian translation + +== 2012-11-24 v2.1.4 + +* Defect #12274: Wiki export from Index by title is truncated +* Defect #12298: Right-click context menu unable to batch/bulk update (IE8) +* Defect #12332: Repository identifier does not display on Project/Settings/Repositories +* Defect #12396: Error when receiving an email without subject header +* Defect #12399: Non ASCII attachment filename encoding broken (MOJIBAKE) in receiving mail on Ruby 1.8 +* Defect #12409: Git: changesets aren't read after clear_changesets call +* Defect #12431: Project.rebuild! sorts root projects by id instead of name + +== 2012-11-17 v2.1.3 + +* Defect #12050: :export links to repository files lead to a 404 error +* Defect #12189: Missing tmp/pdf directory +* Defect #12195: Javascript error with IE7 / IE8 on new issue form +* Defect #12196: "Page not found" on OK button in SCM "View all revisions" page +* Defect #12199: Confirmation message displayed when clicking a disabled delete link in the context menu +* Defect #12231: Hardcoded "Back" in Repository +* Defect #12294: Incorrect german translation for "registered" users filter +* Defect #12349: Watchers auto-complete search on non-latin chars +* Defect #12358: 'None' grouped issue list section should be translated +* Defect #12359: Version date field regex validation accepts invalid date +* Defect #12375: Receiving mail subject encoding broken (MOJIBAKE) in some cases on Ruby 1.8 +* Patch #9732: German translations +* Patch #12021: Russian locale translations +* Patch #12188: Simplified Chinese translation with zh.yml file based on Rev:10681 +* Patch #12235: German translation for 2.1-stable +* Patch #12237: Added German Translation + +== 2012-09-30 v2.1.2 + +* Defect #11929: XSS vulnerability in Redmine 2.1.x + +== 2012-09-30 v2.1.1 + +* Defect #11290: ParseDate missing in Ruby 1.9x +* Defect #11844: "load_default_data" rake task fails to print the error message if one occurs +* Defect #11850: Can't create a user from ldap by on-the-fly on the redmine server using URI prefix +* Defect #11872: Private issue visible to anonymous users after its author is deleted +* Defect #11885: Filter misses Selectionfield on IE8 +* Defect #11893: New relation form Cancel link is broken with Chrome 21 +* Defect #11905: Potential "can't dup NilClass" error in UserPreference +* Defect #11909: Autocomplete results not reset after clearing search field +* Defect #11922: bs.yml and de.yml lead to error by number_to_currency() +* Defect #11945: rake task prints "can't convert Errno::EACCES into String" in case of no permission of public/plugin_assets +* Defect #11975: Undefined status transitions allowed in workflow (author of issue changes when selecting a new status) +* Defect #11982: SCM diff view generates extra parameter for switching mode +* Patch #11897: Traditional Chinese language file (to r10433) + +== 2012-09-16 v2.1.0 + +* Defect #2071: Reordering priority-enumerations breaks alternate-theme's issue-colouring +* Defect #2190: Month names not translated to german +* Defect #8978: LDAP timeout if an LDAP auth provider is unreachable +* Defect #9839: Gantt abbr of weekday should not be necessarily the first letter of the long day name +* Defect #10928: Documentation about generating a plugin is not up-to-date +* Defect #11034: TLS configuration documentation for Rails 3 +* Defect #11073: UserCustomField order_statement returns wrong output +* Defect #11153: Default sorting for target version is DESC instead of ASC +* Defect #11207: Issues associated with a locked version are not copied when copying a project +* Defect #11304: Issue-class: status-1, status-2 etc. refer to status position instead of status id +* Defect #11331: Openid registration form should not require user to enter password +* Defect #11345: Context menu should show shared versions when editing issues from different projects +* Defect #11355: Plain text notification emails content is HTML escaped +* Defect #11388: Updating a version through rest API returns invalid JSON +* Defect #11389: Warning in awesome_nested_set.rb +* Defect #11503: Accessing /projects/:project/wiki/something.png fails with error 500 +* Defect #11506: Versions that are not shared should not be assignable when selecting another project +* Defect #11508: Projects not ordered alphabetically after renaming project +* Defect #11540: Roadmap anchor links can be ambigous +* Defect #11545: Overwriting existing method Issue.open +* Defect #11552: MailHandler does not match assignee name with spaces +* Defect #11571: Custom fields of type version not proper handled in receiving e-mails +* Defect #11577: Can't use non-latin anchor in wiki +* Defect #11612: Revision graph sometimes broken due to raphael.js error +* Defect #11621: Redmine MIME Detection Of Javascript Files Non-Standard +* Defect #11633: Macro arguments should not be parsed by text formatters +* Defect #11662: Invalid query returned from Issues.visible scope after accessing User#projects_by_role with a role that is not present +* Defect #11691: 404 response when deleting a user from the edit page +* Defect #11723: redmine:send_reminders notification misses if assignee is a group +* Defect #11738: Batch update of issues clears project path +* Defect #11749: Redmine.pm: HEAD is not considered as a read-only method +* Defect #11814: Date picker does not respect week start setting +* Feature #703: Configurable required fields per tracker/status/role +* Feature #1006: Display thumbnails of attached images +* Feature #1091: Disabling default ticket fields per tracker +* Feature #1360: Permission for adding an issue to a version. +* Feature #3061: Let macros optionally match over multiple lines and ignore single curly braces +* Feature #3510: Inserting image thumbnails inside the wiki +* Feature #3521: Permissions for roles to change fields per tracker/status +* Feature #3640: Freeze / Close Projects +* Feature #3831: Support for subforums +* Feature #6597: Configurable session lifetime and timeout +* Feature #6965: Option to Copy Subtasks when copying an issue +* Feature #8161: Ability to filter issues on project custom fields +* Feature #8577: "Private" column and filter on the issue list +* Feature #8981: REST Api for Groups +* Feature #9258: Create role by copy +* Feature #9419: Group/sort the issue list by user/version-format custom fields +* Feature #10362: Show images in repositories inline when clicking the 'View' link +* Feature #10419: Upgrade raphael.js (2.1.0) +* Feature #11068: Ability to set default column order in issue list +* Feature #11102: Add autocomplete to "Related issue" field on revision +* Feature #11109: Repository Identifier should be frozen +* Feature #11181: Additional "Log time" link on project overview +* Feature #11205: Reversed order of priorities on the issue summary page +* Feature #11445: Switch from Prototype to JQuery +* Feature #11469: JSONP support +* Feature #11475: Redmine.pm: Allow fallback to other Apache auth providers +* Feature #11494: Don't turn #nnn with leading zeros into links +* Feature #11539: Display a projects tree instead of a flat list in notification preferences +* Feature #11578: Option to pass whole arguments to a macro without splitting them +* Feature #11595: Missing mime type for svg files +* Feature #11758: Upgrade to Rails 3.2.8 +* Patch #4905: Redmine.pm: add support for Git's smart HTTP protocol +* Patch #10988: New Korean translation patch +* Patch #11201: Korean translation special update +* Patch #11401: Fix Japanese mistranslation for "button_submit" +* Patch #11402: Japanese translation added for default role names +* Patch #11411: Fix disordered use of long sound in Japanese "user" translation +* Patch #11412: Unnatural Japanese message when users failed to login +* Patch #11419: Fix wrong Japanese "label_attachment" translation +* Patch #11496: Make labels clickable in Adminstration/Settings +* Patch #11704: Avoid the use of tag("...", "...", true) in layout +* Patch #11818: Redmine.pm fails when permissions are NULL + +== 2012-09-16 v2.0.4 + +* Defect #10818: Running rake in test environment causes exception +* Defect #11209: Wiki diff may generate broken HTML +* Defect #11217: Project names in drop-down are escaped twice +* Defect #11262: Link is escaped in wiki added/updated notification email +* Defect #11307: Can't filter for negative numeric custom fields +* Defect #11325: Unified diff link broken on specific file/revision diff view +* Defect #11341: Escaped link in conflict resolution form +* Defect #11365: Attachment description length is not validated +* Defect #11511: Confirmation page has broken HTML when a project folding sub project is deleted +* Defect #11533: rake redmine:plugins:test doesn't run tests in subdirectories +* Defect #11541: Version sharing is missing in the REST API +* Defect #11550: Issue reminder doesn't work when using asynchronous delivery +* Defect #11776: Can't override mailer views inside redmine plugin. +* Defect #11789: Edit section links broken with h5/h6 headings +* Feature #11338: Exclude emails with auto-submitted => auto-generated +* Patch #11299: redmine:plugins:migrate should update db/schema.rb +* Patch #11328: Fix Japanese mistranslation for 'label_language_based' +* Patch #11448: Russian translation for 1.4-stable and 2.0-stable +* Patch #11600: Fix plural form of the abbreviation for hours in Brazilian Portuguese + +== 2012-06-18 v2.0.3 + +* Defect #10688: PDF export from Wiki - Problems with tables +* Defect #11061: Cannot choose commit versions to view differences in Git/Mercurial repository view +* Defect #11065: E-Mail submitted tickets: German umlauts in 'Subject' get malformed (ruby 1.8) +* Defect #11098: Default priorities have the same position and can't be reordered +* Defect #11105: <% content_for :header_tags do %> doesn't work inside hook +* Defect #11112: REST API - custom fields in POST/PUT ignored for time_entries +* Defect #11118: "Maximum file size" displayed on upload forms is incorrect +* Defect #11124: Link to user is escaped in activity title +* Defect #11133: Wiki-page section edit link can point to incorrect section +* Defect #11160: SQL Error on time report if a custom field has multiple values for an entry +* Defect #11170: Topics sort order is broken in Redmine 2.x +* Defect #11178: Spent time sorted by date-descending order lists same-date entries in physical order (not-reverse) +* Defect #11185: Redmine fails to delete a project with parent/child task +* Feature #11162: Upgrade to Rails 3.2.6 +* Patch #11113: Small glitch in German localization + +== 2012-06-05 v2.0.2 + +* Defect #11032: Project list is not shown when "For any event on the selected projects only..." is selected on user edit panel +* Defect #11038: "Create and continue" should preserve project, issue and activity when logging time +* Defect #11046: Redmine.pm does not support "bind as user" ldap authentication +* Defect #11051: reposman.rb fails in 1.4.2 because of missing require for rubygems +* Defect #11085: Wiki start page can't be changed +* Feature #11084: Update Rails to 3.2.5 + +== 2012-05-28 v2.0.1 + +* Defect #10923: After creating a new Version Redmine jumps back to "Information" +* Defect #10932: Links to delete watchers are escaped when gravatars are enabled +* Defect #10964: Updated column doesn't get updated on issues +* Defect #10965: rake yard does not work for generating documentation. +* Defect #10972: Columns selection not displayed on the custom query form +* Defect #10991: My page > Spent time 'project' column is html-encoded +* Defect #10996: Time zones lost when upgrading from Redmine 1.4 to 2.0 +* Defect #11013: Fetching Email from IMAP/POP3 - uninitialized constant RAILS_DEFAULT_LOGGER error +* Defect #11024: redmine_plugin_model generator does not create the migration +* Defect #11027: Saving new query without name causes escaping of input field +* Defect #11028: Project identifier can be updated + +== 2012-05-15 v2.0.0 + +* Feature #4796: Rails 3 support +* Feature #7720: Limit the pagination-limit when max-results is fewer than max-pagination-limit +* Feature #9034: Add an id to the flash messages +* Patch #10782: Better translation for Estonian language + +== 2012-05-13 v1.4.2 + +* Defect #10744: rake task redmine:email:test broken +* Defect #10787: "Allow users to unsubscribe" option is confusing +* Defect #10827: Cannot access Repositories page and Settings in a Project - Error 500 +* Defect #10829: db:migrate fails 0.8.2 -> 1.4.1 +* Defect #10832: REST Uploads fail with fastcgi +* Defect #10837: reposman and rdm-mailhandler not working with ruby 1.9.x +* Defect #10856: can not load translations from hr.yml with ruby1.9.3-p194 +* Defect #10865: Filter reset when deleting locked user +* Feature #9790: Allow filtering text custom fields on "is null" and "is not null" +* Feature #10778: svn:ignore for config/additional_environment.rb +* Feature #10875: Partial Albanian Translations +* Feature #10888: Bring back List-Id to help aid Gmail filtering +* Patch #10733: Traditional Chinese language file (to r9502) +* Patch #10745: Japanese translation update (r9519) +* Patch #10750: Swedish Translation for r9522 +* Patch #10785: Bulgarian translation (jstoolbar) +* Patch #10800: Simplified Chinese translation + +== 2012-04-20 v1.4.1 + +* Defect #8574: Time report: date range fields not enabled when using the calendar popup +* Defect #10642: Nested textile ol/ul lists generate invalid HTML +* Defect #10668: RSS key is generated twice when user is not reloaded +* Defect #10669: Token.destroy_expired should not delete API tokens +* Defect #10675: "Submit and continue" is broken +* Defect #10711: User cannot change account details with "Login has already been taken" error +* Feature #10664: Unsubscribe Own User Account +* Patch #10693: German Translation Update + +== 2012-04-14 v1.4.0 + +* Defect #2719: Increase username length limit from 30 to 60 +* Defect #3087: Revision referring to issues across all projects +* Defect #4824: Unable to connect (can't convert Net::LDAP::LdapError into String) +* Defect #5058: reminder mails are not sent when delivery_method is :async_smtp +* Defect #6859: Moving issues to a tracker with different custom fields should let fill these fields +* Defect #7398: Error when trying to quick create a version with required custom field +* Defect #7495: Python multiline comments highlighting problem in Repository browser +* Defect #7826: bigdecimal-segfault-fix.rb must be removed for Oracle +* Defect #7920: Attempted to update a stale object when copying a project +* Defect #8857: Git: Too long in fetching repositories after upgrade from 1.1 or new branch at first time +* Defect #9472: The git scm module causes an excess amount of DB traffic. +* Defect #9685: Adding multiple times the same related issue relation is possible +* Defect #9798: Release 1.3.0 does not detect rubytree under ruby 1.9.3p0 / rails 2.3.14 +* Defect #9978: Japanese "permission_add_issue_watchers" is wrong +* Defect #10006: Email reminders are sent for closed issues +* Defect #10150: CSV export and spent time: rounding issue +* Defect #10168: CSV export breaks custom columns +* Defect #10181: Issue context menu and bulk edit form show irrelevant statuses +* Defect #10198: message_id regex in pop3.rb only recognizes Message-ID header (not Message-Id) +* Defect #10251: Description diff link in note details is relative when received by email +* Defect #10272: Ruby 1.9.3: "incompatible character encoding" with LDAP auth +* Defect #10275: Message object not passed to wiki macros for head topic and in preview edit mode +* Defect #10334: Full name is not unquoted when creating users from emails +* Defect #10410: [Localization] Grammar issue of Simplified Chinese in zh.yml +* Defect #10442: Ruby 1.9.3 Time Zone setting Internal error. +* Defect #10467: Confusing behavior while moving issue to a project with disabled Issues module +* Defect #10575: Uploading of attachments which filename contains non-ASCII chars fails with Ruby 1.9 +* Defect #10590: WikiContent::Version#text return string with # when uncompressed +* Defect #10593: Error: 'incompatible character encodings: UTF-8 and ASCII-8BIT' (old annoing issue) on ruby-1.9.3 +* Defect #10600: Watchers search generates an Internal error +* Defect #10605: Bulk edit selected issues does not allow selection of blank values for custom fields +* Defect #10619: When changing status before tracker, it shows improper status +* Feature #779: Multiple SCM per project +* Feature #971: Add "Spent time" column to query +* Feature #1060: Add a LDAP-filter using external auth sources +* Feature #1102: Shortcut for assigning an issue to me +* Feature #1189: Multiselect custom fields +* Feature #1363: Allow underscores in project identifiers +* Feature #1913: LDAP - authenticate as user +* Feature #1972: Attachments for News +* Feature #2009: Manually add related revisions +* Feature #2323: Workflow permissions for administrators +* Feature #2416: {background:color} doesn't work in text formatting +* Feature #2694: Notification on loosing assignment +* Feature #2715: "Magic links" to notes +* Feature #2850: Add next/previous navigation to issue +* Feature #3055: Option to copy attachments when copying an issue +* Feature #3108: set parent automatically for new pages +* Feature #3463: Export all wiki pages to PDF +* Feature #4050: Ruby 1.9 support +* Feature #4769: Ability to move an issue to a different project from the update form +* Feature #4774: Change the hyperlink for file attachment to view and download +* Feature #5159: Ability to add Non-Member watchers to the watch list +* Feature #5638: Use Bundler (Gemfile) for gem management +* Feature #5643: Add X-Redmine-Sender header to email notifications +* Feature #6296: Bulk-edit custom fields through context menu +* Feature #6386: Issue mail should render the HTML version of the issue details +* Feature #6449: Edit a wiki page's parent on the edit page +* Feature #6555: Double-click on "Submit" and "Save" buttons should not send two requests to server +* Feature #7361: Highlight active query in the side bar +* Feature #7420: Rest API for projects members +* Feature #7603: Please make editing issues more obvious than "Change properties (More)" +* Feature #8171: Adding attachments through the REST API +* Feature #8691: Better handling of issue update conflict +* Feature #9803: Change project through REST API issue update +* Feature #9923: User type custom fields should be filterable by "Me". +* Feature #9985: Group time report by the Status field +* Feature #9995: Time entries insertion, "Create and continue" button +* Feature #10020: Enable global time logging at /time_entries/new +* Feature #10042: Bulk change private flag +* Feature #10126: Add members of subprojects in the assignee and author filters +* Feature #10131: Include custom fiels in time entries API responses +* Feature #10207: Git: use default branch from HEAD +* Feature #10208: Estonian translation +* Feature #10253: Better handling of attachments when validation fails +* Feature #10350: Bulk copy should allow for changing the target version +* Feature #10607: Ignore out-of-office incoming emails +* Feature #10635: Adding time like "123 Min" is invalid +* Patch #9998: Make attachement "Optional Description" less wide +* Patch #10066: i18n not working with russian gem +* Patch #10128: Disable IE 8 compatibility mode to fix wrong div.autoscroll scroll bar behaviour +* Patch #10155: Russian translation changed +* Patch #10464: Enhanced PDF output for Issues list +* Patch #10470: Efficiently process new git revisions in a single batch +* Patch #10513: Dutch translation improvement + +== 2012-04-14 v1.3.3 + +* Defect #10505: Error when exporting to PDF with NoMethodError (undefined method `downcase' for nil:NilClass) +* Defect #10554: Defect symbols when exporting tasks in pdf +* Defect #10564: Unable to change locked, sticky flags and board when editing a message +* Defect #10591: Dutch "label_file_added" translation is wrong +* Defect #10622: "Default administrator account changed" is always true +* Patch #10555: rake redmine:send_reminders aborted if issue assigned to group +* Patch #10611: Simplified Chinese translations for 1.3-stable + +== 2012-03-11 v1.3.2 + +* Defect #8194: {{toc}} uses identical anchors for subsections with the same name +* Defect #9143: Partial diff comparison should be done on actual code, not on html +* Defect #9523: {{toc}} does not display headers with @ code markup +* Defect #9815: Release 1.3.0 does not detect rubytree with rubgems 1.8 +* Defect #10053: undefined method `<=>' for nil:NilClass when accessing the settings of a project +* Defect #10135: ActionView::TemplateError (can't convert Fixnum into String) +* Defect #10193: Unappropriate icons in highlighted code block +* Defect #10199: No wiki section edit when title contains code +* Defect #10218: Error when creating a project with a version custom field +* Defect #10241: "get version by ID" fails with "401 not authorized" error when using API access key +* Defect #10284: Note added by commit from a subproject does not contain project identifier +* Defect #10374: User list is empty when adding users to project / group if remaining users are added late +* Defect #10390: Mass assignment security vulnerability +* Patch #8413: Confirmation message before deleting a relationship +* Patch #10160: Bulgarian translation (r8777) +* Patch #10242: Migrate Redmine.pm from Digest::Sha1 to Digest::Sha +* Patch #10258: Italian translation for 1.3-stable + +== 2012-02-06 v1.3.1 + +* Defect #9775: app/views/repository/_revision_graph.html.erb sets window.onload directly.. +* Defect #9792: Ruby 1.9: [v1.3.0] Error: incompatible character encodings for it translation on Calendar page +* Defect #9793: Bad spacing between numbered list and heading (recently broken). +* Defect #9795: Unrelated error message when creating a group with an invalid name +* Defect #9832: Revision graph height should depend on height of rows in revisions table +* Defect #9937: Repository settings are not saved when all SCM are disabled +* Defect #9961: Ukrainian "default_tracker_bug" is wrong +* Defect #10013: Rest API - Create Version -> Internal server error 500 +* Defect #10115: Javascript error - Can't attach more than 1 file on IE 6 and 7 +* Defect #10130: Broken italic text style in edited comment preview +* Defect #10152: Attachment diff type is not saved in user preference +* Feature #9943: Arabic translation +* Patch #9874: pt-BR translation updates +* Patch #9922: Spanish translation updated +* Patch #10137: Korean language file ko.yml updated to Redmine 1.3.0 + +== 2011-12-10 v1.3.0 + +* Defect #2109: Context menu is being submitted twice per right click +* Defect #7717: MailHandler user creation for unknown_user impossible due to diverging length-limits of login and email fields +* Defect #7917: Creating users via email fails if user real name containes special chars +* Defect #7966: MailHandler does not include JournalDetail for attached files +* Defect #8368: Bad decimal separator in time entry CSV +* Defect #8371: MySQL error when filtering a custom field using the REST api +* Defect #8549: Export CSV has character encoding error +* Defect #8573: Do not show inactive Enumerations where not needed +* Defect #8611: rake/rdoctask is deprecated +* Defect #8751: Email notification: bug, when number of recipients more then 8 +* Defect #8894: Private issues - make it more obvious in the UI? +* Defect #8994: Hardcoded French string "anonyme" +* Defect #9043: Hardcoded string "diff" in Wiki#show and Repositories_Helper +* Defect #9051: wrong "text_issue_added" in russian translation. +* Defect #9108: Custom query not saving status filter +* Defect #9252: Regression: application title escaped 2 times +* Defect #9264: Bad Portuguese translation +* Defect #9470: News list is missing Avatars +* Defect #9471: Inline markup broken in Wiki link labels +* Defect #9489: Label all input field and control tags +* Defect #9534: Precedence: bulk email header is non standard and discouraged +* Defect #9540: Issue filter by assigned_to_role is not project specific +* Defect #9619: Time zone ignored when logging time while editing ticket +* Defect #9638: Inconsistent image filename extensions +* Defect #9669: Issue list doesn't sort assignees/authors regarding user display format +* Defect #9672: Message-quoting in forums module broken +* Defect #9719: Filtering by numeric custom field types broken after update to master +* Defect #9724: Can't remote add new categories +* Defect #9738: Setting of cross-project custom query is not remembered inside project +* Defect #9748: Error about configuration.yml validness should mention file path +* Feature #69: Textilized description in PDF +* Feature #401: Add pdf export for WIKI page +* Feature #1567: Make author column sortable and groupable +* Feature #2222: Single section edit. +* Feature #2269: Default issue start date should become configurable. +* Feature #2371: character encoding for attachment file +* Feature #2964: Ability to assign issues to groups +* Feature #3033: Bug Reporting: Using "Create and continue" should show bug id of saved bug +* Feature #3261: support attachment images in PDF export +* Feature #4264: Update CodeRay to 1.0 final +* Feature #4324: Redmine renames my files, it shouldn't. +* Feature #4729: Add Date-Based Filters for Issues List +* Feature #4742: CSV export: option to export selected or all columns +* Feature #4976: Allow rdm-mailhandler to read the API key from a file +* Feature #5501: Git: Mercurial: Adding visual merge/branch history to repository view +* Feature #5634: Export issue to PDF does not include Subtasks and Related Issues +* Feature #5670: Cancel option for file upload +* Feature #5737: Custom Queries available through the REST Api +* Feature #6180: Searchable custom fields do not provide adequate operators +* Feature #6954: Filter from date to date +* Feature #7180: List of statuses in REST API +* Feature #7181: List of trackers in REST API +* Feature #7366: REST API for Issue Relations +* Feature #7403: REST API for Versions +* Feature #7671: REST API for reading attachments +* Feature #7832: Ability to assign issue categories to groups +* Feature #8420: Consider removing #7013 workaround +* Feature #9196: Improve logging in MailHandler when user creation fails +* Feature #9496: Adds an option in mailhandler to disable server certificate verification +* Feature #9553: CRUD operations for "Issue categories" in REST API +* Feature #9593: HTML title should be reordered +* Feature #9600: Wiki links for news and forums +* Feature #9607: Filter for issues without start date (or any another field based on date type) +* Feature #9609: Upgrade to Rails 2.3.14 +* Feature #9612: "side by side" and "inline" patch view for attachments +* Feature #9667: Check attachment size before upload +* Feature #9690: Link in notification pointing to the actual update +* Feature #9720: Add note number for single issue's PDF +* Patch #8617: Indent subject of subtask ticket in exported issues PDF +* Patch #8778: Traditional Chinese 'issue' translation change +* Patch #9053: Fix up Russian translation +* Patch #9129: Improve wording of Git repository note at project setting +* Patch #9148: Better handling of field_due_date italian translation +* Patch #9273: Fix typos in russian localization +* Patch #9484: Limit SCM annotate to text files under the maximum file size for viewing +* Patch #9659: Indexing rows in auth_sources/index view +* Patch #9692: Fix Textilized description in PDF for CodeRay + +== 2011-12-10 v1.2.3 + +* Defect #8707: Reposman: wrong constant name +* Defect #8809: Table in timelog report overflows +* Defect #9055: Version files in Files module cannot be downloaded if issue tracking is disabled +* Defect #9137: db:encrypt fails to handle repositories with blank password +* Defect #9394: Custom date field only validating on regex and not a valid date +* Defect #9405: Any user with :log_time permission can edit time entries via context menu +* Defect #9448: The attached images are not shown in documents +* Defect #9520: Copied private query not visible after project copy +* Defect #9552: Error when reading ciphered text from the database without cipher key configured +* Defect #9566: Redmine.pm considers all projects private when login_required is enabled +* Defect #9567: Redmine.pm potential security issue with cache credential enabled and subversion +* Defect #9577: Deleting a subtasks doesn't update parent's rgt & lft values +* Defect #9597: Broken version links in wiki annotate history +* Defect #9682: Wiki HTML Export only useful when Access history is accessible +* Defect #9737: Custom values deleted before issue submit +* Defect #9741: calendar-hr.js (Croatian) is not UTF-8 +* Patch #9558: Simplified Chinese translation for 1.2.2 updated +* Patch #9695: Bulgarian translation (r7942) + +== 2011-11-11 v1.2.2 + +* Defect #3276: Incorrect handling of anchors in Wiki to HTML export +* Defect #7215: Wiki formatting mangles links to internal headers +* Defect #7613: Generated test instances may share the same attribute value object +* Defect #8411: Can't remove "Project" column on custom query +* Defect #8615: Custom 'version' fields don't show shared versions +* Defect #8633: Pagination counts non visible issues +* Defect #8651: Email attachments are not added to issues any more in v1.2 +* Defect #8825: JRuby + Windows: SCMs do not work on Redmine 1.2 +* Defect #8836: Additional workflow transitions not available when set to both author and assignee +* Defect #8865: Custom field regular expression is not validated +* Defect #8880: Error deleting issue with grandchild +* Defect #8884: Assignee is cleared when updating issue with locked assignee +* Defect #8892: Unused fonts in rfpdf plugin folder +* Defect #9161: pt-BR field_warn_on_leaving_unsaved has a small gramatical error +* Defect #9308: Search fails when a role haven't "view wiki" permission +* Defect #9465: Mercurial: can't browse named branch below Mercurial 1.5 + +== 2011-07-11 v1.2.1 + +* Defect #5089: i18N error on truncated revision diff view +* Defect #7501: Search options get lost after clicking on a specific result type +* Defect #8229: "project.xml" response does not include the parent ID +* Defect #8449: Wiki annotated page does not display author of version 1 +* Defect #8467: Missing german translation - Warn me when leaving a page with unsaved text +* Defect #8468: No warning when leaving page with unsaved text that has not lost focus +* Defect #8472: Private checkbox ignored on issue creation with "Set own issues public or private" permission +* Defect #8510: JRuby: Can't open administrator panel if scm command is not available +* Defect #8512: Syntax highlighter on Welcome page +* Defect #8554: Translation missing error on custom field validation +* Defect #8565: JRuby: Japanese PDF export error +* Defect #8566: Exported PDF UTF-8 Vietnamese not correct +* Defect #8569: JRuby: PDF export error with TypeError +* Defect #8576: Missing german translation - different things +* Defect #8616: Circular relations +* Defect #8646: Russian translation "label_follows" and "label_follows" are wrong +* Defect #8712: False 'Description updated' journal details messages +* Defect #8729: Not-public queries are not private +* Defect #8737: Broken line of long issue description on issue PDF. +* Defect #8738: Missing revision number/id of associated revisions on issue PDF +* Defect #8739: Workflow copy does not copy advanced workflow settings +* Defect #8759: Setting issue attributes from mail should be case-insensitive +* Defect #8777: Mercurial: Not able to Resetting Redmine project respository + +== 2011-05-30 v1.2.0 + +* Defect #61: Broken character encoding in pdf export +* Defect #1965: Redmine is not Tab Safe +* Defect #2274: Filesystem Repository path encoding of non UTF-8 characters +* Defect #2664: Mercurial: Repository path encoding of non UTF-8 characters +* Defect #3421: Mercurial reads files from working dir instead of changesets +* Defect #3462: CVS: Repository path encoding of non UTF-8 characters +* Defect #3715: Login page should not show projects link and search box if authentication is required +* Defect #3724: Mercurial repositories display revision ID instead of changeset ID +* Defect #3761: Most recent CVS revisions are missing in "revisions" view +* Defect #4270: CVS Repository view in Project doesn't show Author, Revision, Comment +* Defect #5138: Don't use Ajax for pagination +* Defect #5152: Cannot use certain characters for user and role names. +* Defect #5251: Git: Repository path encoding of non UTF-8 characters +* Defect #5373: Translation missing when adding invalid watchers +* Defect #5817: Shared versions not shown in subproject's gantt chart +* Defect #6013: git tab,browsing, very slow -- even after first time +* Defect #6148: Quoting, newlines, and nightmares... +* Defect #6256: Redmine considers non ASCII and UTF-16 text files as binary in SCM +* Defect #6476: Subproject's issues are not shown in the subproject's gantt +* Defect #6496: Remove i18n 0.3.x/0.4.x hack for Rails 2.3.5 +* Defect #6562: Context-menu deletion of issues deletes all subtasks too without explicit prompt +* Defect #6604: Issues targeted at parent project versions' are not shown on gantt chart +* Defect #6706: Resolving issues with the commit message produces the wrong comment with CVS +* Defect #6901: Copy/Move an issue does not give any history of who actually did the action. +* Defect #6905: Specific heading-content breaks CSS +* Defect #7000: Project filter not applied on versions in Gantt chart +* Defect #7097: Starting day of week cannot be set to Saturday +* Defect #7114: New gantt doesn't display some projects +* Defect #7146: Git adapter lost commits before 7 days from database latest changeset +* Defect #7218: Date range error on issue query +* Defect #7257: "Issues by" version links bad criterias +* Defect #7279: CSS class ".icon-home" is not used. +* Defect #7320: circular dependency >2 issues +* Defect #7352: Filters not working in Gantt charts +* Defect #7367: Receiving pop3 email should not output debug messages +* Defect #7373: Error with PDF output and ruby 1.9.2 +* Defect #7379: Remove extraneous hidden_field on wiki history +* Defect #7516: Redmine does not work with RubyGems 1.5.0 +* Defect #7518: Mercurial diff can be wrong if the previous changeset isn't the parent +* Defect #7581: Not including a spent time value on the main issue update screen causes silent data loss +* Defect #7582: hiding form pages from search engines +* Defect #7597: Subversion and Mercurial log have the possibility to miss encoding +* Defect #7604: ActionView::TemplateError (undefined method `name' for nil:NilClass) +* Defect #7605: Using custom queries always redirects to "Issues" tab +* Defect #7615: CVS diffs do not handle new files properly +* Defect #7618: SCM diffs do not handle one line new files properly +* Defect #7639: Some date fields do not have requested format. +* Defect #7657: Wrong commit range in git log command on Windows +* Defect #7818: Wiki pages don't use the local timezone to display the "Updated ? hours ago" mouseover +* Defect #7821: Git "previous" and "next" revisions are incorrect +* Defect #7827: CVS: Age column on repository view is off by timezone delta +* Defect #7843: Add a relation between issues = explicit login window ! (basic authentication popup is prompted on AJAX request) +* Defect #8011: {{toc}} does not display headlines with inline code markup +* Defect #8029: List of users for adding to a group may be empty if 100 first users have been added +* Defect #8064: Text custom fields do not wrap on the issue list +* Defect #8071: Watching a subtask from the context menu updates main issue watch link +* Defect #8072: Two untranslatable default role names +* Defect #8075: Some "notifiable" names are not i18n-enabled +* Defect #8081: GIT: Commits missing when user has the "decorate" git option enabled +* Defect #8088: Colorful indentation of subprojects must be on right in RTL locales +* Defect #8239: notes field is not propagated during issue copy +* Defect #8356: GET /time_entries.xml ignores limit/offset parameters +* Defect #8432: Private issues information shows up on Activity page for unauthorized users +* Feature #746: Versioned issue descriptions +* Feature #1067: Differentiate public/private saved queries in the sidebar +* Feature #1236: Make destination folder for attachment uploads configurable +* Feature #1735: Per project repository log encoding setting +* Feature #1763: Autologin-cookie should be configurable +* Feature #1981: display mercurial tags +* Feature #2074: Sending email notifications when comments are added in the news section +* Feature #2096: Custom fields referencing system tables (users and versions) +* Feature #2732: Allow additional workflow transitions for author and assignee +* Feature #2910: Warning on leaving edited issue/wiki page without saving +* Feature #3396: Git: use --encoding=UTF-8 in "git log" +* Feature #4273: SCM command availability automatic check in administration panel +* Feature #4477: Use mime types in downloading from repository +* Feature #5518: Graceful fallback for "missing translation" needed +* Feature #5520: Text format buttons and preview link missing when editing comment +* Feature #5831: Parent Task to Issue Bulk Edit +* Feature #6887: Upgrade to Rails 2.3.11 +* Feature #7139: Highlight changes inside diff lines +* Feature #7236: Collapse All for Groups +* Feature #7246: Handle "named branch" for mercurial +* Feature #7296: Ability for admin to delete users +* Feature #7318: Add user agent to Redmine Mailhandler +* Feature #7408: Add an application configuration file +* Feature #7409: Cross project Redmine links +* Feature #7410: Add salt to user passwords +* Feature #7411: Option to cipher LDAP ans SCM passwords stored in the database +* Feature #7412: Add an issue visibility level to each role +* Feature #7414: Private issues +* Feature #7517: Configurable path of executable for scm adapters +* Feature #7640: Add "mystery man" gravatar to options +* Feature #7858: RubyGems 1.6 support +* Feature #7893: Group filter on the users list +* Feature #7899: Box for editing comments should open with the formatting toolbar +* Feature #7921: issues by pulldown should have 'status' option +* Feature #7996: Bulk edit and context menu for time entries +* Feature #8006: Right click context menu for Related Issues +* Feature #8209: I18n YAML files not parsable with psych yaml library +* Feature #8345: Link to user profile from account page +* Feature #8365: Git: per project setting to report last commit or not in repository tree +* Patch #5148: metaKey not handled in issues selection +* Patch #5629: Wrap text fields properly in PDF +* Patch #7418: Redmine Persian Translation +* Patch #8295: Wrap title fields properly in PDF +* Patch #8310: fixes automatic line break problem with TCPDF +* Patch #8312: Switch to TCPDF from FPDF for PDF export + +== 2011-04-29 v1.1.3 + +* Defect #5773: Email reminders are sent to locked users +* Defect #6590: Wrong file list link in email notification on new file upload +* Defect #7589: Wiki page with backslash in title can not be found +* Defect #7785: Mailhandler keywords are not removed when updating issues +* Defect #7794: Internal server error on formatting an issue as a PDF in Japanese +* Defect #7838: Gantt- Issues does not show up in green when start and end date are the same +* Defect #7846: Headers (h1, etc.) containing backslash followed by a digit are not displayed correctly +* Defect #7875: CSV export separators in polish locale (pl.yml) +* Defect #7890: Internal server error when referencing an issue without project in commit message +* Defect #7904: Subprojects not properly deleted when deleting a parent project +* Defect #7939: Simultaneous Wiki Updates Cause Internal Error +* Defect #7951: Atom links broken on wiki index +* Defect #7954: IE 9 can not select issues, does not display context menu +* Defect #7985: Trying to do a bulk edit results in "Internal Error" +* Defect #8003: Error raised by reposman.rb under Windows server 2003 +* Defect #8012: Wrong selection of modules when adding new project after validation error +* Defect #8038: Associated Revisions OL/LI items are not styled properly in issue view +* Defect #8067: CSV exporting in Italian locale +* Defect #8235: bulk edit issues and copy issues error in es, gl and ca locales +* Defect #8244: selected modules are not activated when copying a project +* Patch #7278: Update Simplified Chinese translation to 1.1 +* Patch #7390: Fixes in Czech localization +* Patch #7963: Reminder email: Link for show all issues does not sort + +== 2011-03-07 v1.1.2 + +* Defect #3132: Bulk editing menu non-functional in Opera browser +* Defect #6090: Most binary files become corrupted when downloading from CVS repository browser when Redmine is running on a Windows server +* Defect #7280: Issues subjects wrap in Gantt +* Defect #7288: Non ASCII filename downloaded from repo is broken on Internet Explorer. +* Defect #7317: Gantt tab gives internal error due to nil avatar icon +* Defect #7497: Aptana Studio .project file added to version 1.1.1-stable +* Defect #7611: Workflow summary shows X icon for workflow with exactly 1 status transition +* Defect #7625: Syntax highlighting unavailable from board new topic or topic edit preview +* Defect #7630: Spent time in commits not recognized +* Defect #7656: MySQL SQL Syntax Error when filtering issues by Assignee's Group +* Defect #7718: Minutes logged in commit message are converted to hours +* Defect #7763: Email notification are sent to watchers even if 'No events' setting is chosen +* Feature #7608: Add "retro" gravatars +* Patch #7598: Extensible MailHandler +* Patch #7795: Internal server error at journals#index with custom fields + +== 2011-01-30 v1.1.1 + +* Defect #4899: Redmine fails to list files for darcs repository +* Defect #7245: Wiki fails to find pages with cyrillic characters using postgresql +* Defect #7256: redmine/public/.htaccess must be moved for non-fastcgi installs/upgrades +* Defect #7258: Automatic spent time logging does not work properly with SQLite3 +* Defect #7259: Released 1.1.0 uses "devel" label inside admin information +* Defect #7265: "Loading..." icon does not disappear after add project member +* Defect #7266: Test test_due_date_distance_in_words fail due to undefined locale +* Defect #7274: CSV value separator in dutch locale +* Defect #7277: Enabling gravatas causes usernames to overlap first name field in user list +* Defect #7294: "Notifiy for only project I select" is not available anymore in 1.1.0 +* Defect #7307: HTTP 500 error on query for empty revision +* Defect #7313: Label not translated in french in Settings/Email Notification tab +* Defect #7329: with long strings may hang server +* Defect #7337: My page french translation +* Defect #7348: French Translation of "Connection" +* Defect #7385: Error when viewing an issue which was related to a deleted subtask +* Defect #7386: NoMethodError on pdf export +* Defect #7415: Darcs adapter recognizes new files as modified files above Darcs 2.4 +* Defect #7421: no email sent with 'Notifiy for any event on the selected projects only' +* Feature #5344: Update to latest CodeRay 0.9.x + +== 2011-01-09 v1.1.0 + +* Defect #2038: Italics in wiki headers show-up wrong in the toc +* Defect #3449: Redmine Takes Too Long On Large Mercurial Repository +* Defect #3567: Sorting for changesets might go wrong on Mercurial repos +* Defect #3707: {{toc}} doesn't work with {{include}} +* Defect #5096: Redmine hangs up while browsing Git repository +* Defect #6000: Safe Attributes prevents plugin extension of Issue model... +* Defect #6064: Modules not assigned to projects created via API +* Defect #6110: MailHandler should allow updating Issue Priority and Custom fields +* Defect #6136: JSON API holds less information than XML API +* Defect #6345: xml used by rest API is invalid +* Defect #6348: Gantt chart PDF rendering errors +* Defect #6403: Updating an issue with custom fields fails +* Defect #6467: "Member of role", "Member of group" filter not work correctly +* Defect #6473: New gantt broken after clearing issue filters +* Defect #6541: Email notifications send to everybody +* Defect #6549: Notification settings not migrated properly +* Defect #6591: Acronyms must have a minimum of three characters +* Defect #6674: Delete time log broken after changes to REST +* Defect #6681: Mercurial, Bazaar and Darcs auto close issue text should be commit id instead of revision number +* Defect #6724: Wiki uploads does not work anymore (SVN 4266) +* Defect #6746: Wiki links are broken on Activity page +* Defect #6747: Wiki diff does not work since r4265 +* Defect #6763: New gantt charts: subject displayed twice on issues +* Defect #6826: Clicking "Add" twice creates duplicate member record +* Defect #6844: Unchecking status filter on the issue list has no effect +* Defect #6895: Wrong Polish translation of "blocks" +* Defect #6943: Migration from boolean to varchar fails on PostgreSQL 8.1 +* Defect #7064: Mercurial adapter does not recognize non alphabetic nor numeric in UTF-8 copied files +* Defect #7128: New gantt chart does not render subtasks under parent task +* Defect #7135: paging mechanism returns the same last page forever +* Defect #7188: Activity page not refreshed when changing language +* Defect #7195: Apply CLI-supplied defaults for incoming mail only to new issues not replies +* Defect #7197: Tracker reset to default when replying to an issue email +* Defect #7213: Copy project does not copy all roles and permissions +* Defect #7225: Project settings: Trackers & Custom fields only relevant if module Issue tracking is active +* Feature #630: Allow non-unique names for projects +* Feature #1738: Add a "Visible" flag to project/user custom fields +* Feature #2803: Support for Javascript in Themes +* Feature #2852: Clean Incoming Email of quoted text "----- Reply above this line ------" +* Feature #2995: Improve error message when trying to access an archived project +* Feature #3170: Autocomplete issue relations on subject +* Feature #3503: Administrator Be Able To Modify Email settings Of Users +* Feature #4155: Automatic spent time logging from commit messages +* Feature #5136: Parent select on Wiki rename page +* Feature #5338: Descendants (subtasks) should be available via REST API +* Feature #5494: Wiki TOC should display heading from level 4 +* Feature #5594: Improve MailHandler's keyword handling +* Feature #5622: Allow version to be set via incoming email +* Feature #5712: Reload themes +* Feature #5869: Issue filters by Group and Role +* Feature #6092: Truncate Git revision labels in Activity page/feed and allow configurable length +* Feature #6112: Accept localized keywords when receiving emails +* Feature #6140: REST issues response with issue count limit and offset +* Feature #6260: REST API for Users +* Feature #6276: Gantt Chart rewrite +* Feature #6446: Remove length limits on project identifier and name +* Feature #6628: Improvements in truncate email +* Feature #6779: Project JSON API +* Feature #6823: REST API for time tracker. +* Feature #7072: REST API for news +* Feature #7111: Expose more detail on journal entries +* Feature #7141: REST API: get information about current user +* Patch #4807: Allow to set the done_ratio field with the incoming mail system +* Patch #5441: Initialize TimeEntry attributes with params[:time_entry] +* Patch #6762: Use GET instead of POST to retrieve context_menu +* Patch #7160: French translation ofr "not_a_date" is missing +* Patch #7212: Missing remove_index in AddUniqueIndexOnMembers down migration + + +== 2010-12-23 v1.0.5 + +* #6656: Mercurial adapter loses seconds of commit times +* #6996: Migration trac(sqlite3) -> redmine(postgresql) doesnt escape ' char +* #7013: v-1.0.4 trunk - see {{count}} in page display rather than value +* #7016: redundant 'field_start_date' in ja.yml +* #7018: 'undefined method `reschedule_after' for nil:NilClass' on new issues +* #7024: E-mail notifications about Wiki changes. +* #7033: 'class' attribute of
     tag shouldn't be truncate
    +* #7035: CSV value separator in russian
    +* #7122: Issue-description Quote-button missing
    +* #7144: custom queries making use of deleted custom fields cause a 500 error
    +* #7162: Multiply defined label in french translation
    +
    +== 2010-11-28 v1.0.4
    +
    +* #5324: Git not working if color.ui is enabled
    +* #6447: Issues API doesn't allow full key auth for all actions
    +* #6457: Edit User group problem
    +* #6575: start date being filled with current date even when blank value is submitted
    +* #6740: Max attachment size, incorrect usage of 'KB'
    +* #6760: Select box sorted by ID instead of name in Issue Category
    +* #6766: Changing target version name can cause an internal error
    +* #6784: Redmine not working with i18n gem 0.4.2
    +* #6839: Hardcoded absolute links in my/page_layout
    +* #6841: Projects API doesn't allow full key auth for all actions
    +* #6860: svn: Write error: Broken pipe when browsing repository
    +* #6874: API should return XML description when creating a project
    +* #6932: submitting wrong parent task input creates a 500 error
    +* #6966: Records of Forums are remained, deleting project
    +* #6990: Layout problem in workflow overview
    +* #5117: mercurial_adapter should ensure the right LANG environment variable
    +* #6782: Traditional Chinese language file (to r4352)
    +* #6783: Swedish Translation for r4352
    +* #6804: Bugfix: spelling fixes
    +* #6814: Japanese Translation for r4362
    +* #6948: Bulgarian translation
    +* #6973: Update es.yml
    +
    +== 2010-10-31 v1.0.3
    +
    +* #4065: Redmine.pm doesn't work with LDAPS and a non-standard port
    +* #4416: Link from version details page to edit the wiki.
    +* #5484: Add new issue as subtask to an existing ticket
    +* #5948: Update help/wiki_syntax_detailed.html with more link options
    +* #6494: Typo in pt_BR translation for 1.0.2
    +* #6508: Japanese translation update
    +* #6509: Localization pt-PT (new strings)
    +* #6511: Rake task to test email
    +* #6525: Traditional Chinese language file (to r4225)
    +* #6536: Patch for swedish translation
    +* #6548: Rake tasks to add/remove i18n strings
    +* #6569: Updated Hebrew translation
    +* #6570: Japanese Translation for r4231
    +* #6596: pt-BR translation updates
    +* #6629: Change field-name of issues start date
    +* #6669: Bulgarian translation
    +* #6731: Macedonian translation fix
    +* #6732: Japanese Translation for r4287
    +* #6735: Add user-agent to reposman
    +* #6736: Traditional Chinese language file (to r4288)
    +* #6739: Swedish Translation for r4288
    +* #6765: Traditional Chinese language file (to r4302)
    +* Fixed #5324: Git not working if color.ui is enabled
    +* Fixed #5652: Bad URL parsing in the wiki when it ends with right-angle-bracket(greater-than mark).
    +* Fixed #5803: Precedes/Follows Relationships Broke
    +* Fixed #6435: Links to wikipages bound to versions do not respect version-sharing in Settings -> Versions
    +* Fixed #6438: Autologin cannot be disabled again once it's enabled
    +* Fixed #6513: "Move" and "Copy" are not displayed when deployed in subdirectory
    +* Fixed #6521: Tooltip/label for user "search-refinment" field on group/project member list
    +* Fixed #6563: i18n-issues on calendar view
    +* Fixed #6598: Wrong caption for button_create_and_continue in German language file
    +* Fixed #6607: Unclear caption for german button_update
    +* Fixed #6612: SortHelper missing from CalendarsController
    +* Fixed #6740: Max attachment size, incorrect usage of 'KB'
    +* Fixed #6750: ActionView::TemplateError (undefined method `empty?' for nil:NilClass) on line #12 of app/views/context_menus/issues.html.erb:
    +
    +== 2010-09-26 v1.0.2
    +
    +* #2285: issue-refinement: pressing enter should result to an "apply"
    +* #3411: Allow mass status update trough context menu
    +* #5929: https-enabled gravatars when called over https
    +* #6189: Japanese Translation for r4011
    +* #6197: Traditional Chinese language file (to r4036)
    +* #6198: Updated german translation
    +* #6208: Macedonian translation
    +* #6210: Swedish Translation for r4039
    +* #6248: nl translation update for r4050
    +* #6263: Catalan translation update
    +* #6275: After submitting a related issue, the Issue field should be re-focused
    +* #6289: Checkboxes in issues list shouldn't be displayed when printing
    +* #6290: Make journals theming easier
    +* #6291: User#allowed_to? is not tested
    +* #6306: Traditional Chinese language file (to r4061)
    +* #6307: Korean translation update for 4066(4061)
    +* #6316: pt_BR update
    +* #6339: SERBIAN Updated
    +* #6358: Updated Polish translation
    +* #6363: Japanese Translation for r4080
    +* #6365: Traditional Chinese language file (to r4081)
    +* #6382: Issue PDF export variable usage
    +* #6428: Interim solution for i18n >= 0.4
    +* #6441: Japanese Translation for r4162
    +* #6451: Traditional Chinese language file (to r4167)
    +* #6465: Japanese Translation for r4171
    +* #6466: Traditional Chinese language file (to r4171)
    +* #6490: pt-BR translation for 1.0.2
    +* Fixed #3935: stylesheet_link_tag with plugin doesn't take into account relative_url_root
    +* Fixed #4998: Global issue list's context menu has enabled options for parent menus but there are no valid selections
    +* Fixed #5170: Done ratio can not revert to 0% if status is used for done ratio
    +* Fixed #5608: broken with i18n 0.4.0
    +* Fixed #6054: Error 500 on filenames with whitespace in git reposities
    +* Fixed #6135: Default logger configuration grows without bound.
    +* Fixed #6191: Deletion of a main task deletes all subtasks
    +* Fixed #6195: Missing move issues between projects
    +* Fixed #6242: can't switch between inline and side-by-side diff
    +* Fixed #6249: Create and continue returns 404
    +* Fixed #6267: changing the authentication mode from ldap to internal with setting the password
    +* Fixed #6270: diff coderay malformed in the "news" page
    +* Fixed #6278: missing "cant_link_an_issue_with_a_descendant"from locale files
    +* Fixed #6333: Create and continue results in a 404 Error
    +* Fixed #6346: Age column on repository view is skewed for git, probably CVS too
    +* Fixed #6351: Context menu on roadmap broken
    +* Fixed #6388: New Subproject leads to a 404
    +* Fixed #6392: Updated/Created links to activity broken
    +* Fixed #6413: Error in SQL
    +* Fixed #6443: Redirect to project settings after Copying a Project
    +* Fixed #6448: Saving a wiki page with no content has a translation missing
    +* Fixed #6452: Unhandled exception on creating File
    +* Fixed #6471: Typo in label_report in Czech translation
    +* Fixed #6479: Changing tracker type will lose watchers
    +* Fixed #6499: Files with leading or trailing whitespace are not shown in git.
    +
    +== 2010-08-22 v1.0.1
    +
    +* #819: Add a body ID and class to all pages
    +* #871: Commit new CSS styles!
    +* #3301: Add favicon to base layout
    +* #4656: On Issue#show page, clicking on “Add related issue� should focus on the input
    +* #4896: Project identifier should be a limited field
    +* #5084: Filter all isssues by projects
    +* #5477: Replace Test::Unit::TestCase with ActiveSupport::TestCase
    +* #5591: 'calendar' action is used with 'issue' controller in issue/sidebar
    +* #5735: Traditional Chinese language file (to r3810)
    +* #5740: Swedish Translation for r3810
    +* #5785: pt-BR translation update
    +* #5898: Projects should be displayed as links in users/memberships
    +* #5910: Chinese translation to redmine-1.0.0
    +* #5912: Translation update for french locale
    +* #5962: Hungarian translation update to r3892
    +* #5971: Remove falsly applied chrome on revision links
    +* #5972: Updated Hebrew translation for 1.0.0
    +* #5982: Updated german translation
    +* #6008: Move admin_menu to Redmine::MenuManager
    +* #6012: RTL layout
    +* #6021: Spanish translation 1.0.0-RC
    +* #6025: nl translation updated for r3905
    +* #6030: Japanese Translation for r3907
    +* #6074: sr-CY.yml contains DOS-type newlines (\r\n)
    +* #6087: SERBIAN translation updated
    +* #6093: Updated italian translation
    +* #6142: Swedish Translation for r3940
    +* #6153: Move view_calendar and view_gantt to own modules
    +* #6169: Add issue status to issue tooltip
    +* Fixed #3834: Add a warning when not choosing a member role
    +* Fixed #3922: Bad english arround "Assigned to" text in journal entries
    +* Fixed #5158: Simplified Chinese language file zh.yml updated to r3608
    +* Fixed #5162: translation missing: zh-TW, field_time_entrie
    +* Fixed #5297: openid not validated correctly
    +* Fixed #5628: Wrong commit range in git log command
    +* Fixed #5760: Assigned_to and author filters in "Projects>View all issues" should be based on user's project visibility
    +* Fixed #5771: Problem when importing git repository
    +* Fixed #5775: ldap authentication in admin menu should have an icon
    +* Fixed #5811: deleting statuses doesnt delete workflow entries
    +* Fixed #5834: Emails with trailing spaces incorrectly detected as invalid
    +* Fixed #5846: ChangeChangesPathLengthLimit does not remove default for MySQL
    +* Fixed #5861: Vertical scrollbar always visible in Wiki "code" blocks in Chrome.
    +* Fixed #5883: correct label_project_latest Chinese translation
    +* Fixed #5892: Changing status from contextual menu opens the ticket instead
    +* Fixed #5904: Global gantt PDF and PNG should display project names
    +* Fixed #5925: parent task's priority edit should be disabled through shortcut menu in issues list page
    +* Fixed #5935: Add Another file to ticket doesn't work in IE Internet Explorer
    +* Fixed #5937: Harmonize french locale "zero" translation with other locales
    +* Fixed #5945: Forum message permalinks don't take pagination into account
    +* Fixed #5978: Debug code still remains
    +* Fixed #6009: When using "English (British)", the repository browser (svn) shows files over 1000 bytes as floating point (2.334355)
    +* Fixed #6045: Repository file Diff view sometimes shows more than selected file
    +* Fixed #6079: German Translation error in TimeEntryActivity
    +* Fixed #6100: User's profile should display all visible projects
    +* Fixed #6132: Allow Key based authentication in the Boards atom feed
    +* Fixed #6163: Bad CSS class for calendar project menu_item
    +* Fixed #6172: Browsing to a missing user's page shows the admin sidebar
    +
    +== 2010-07-18 v1.0.0 (Release candidate)
    +
    +* #443: Adds context menu to the roadmap issue lists
    +* #443: Subtasking
    +* #741: Description preview while editing an issue
    +* #1131: Add support for alternate (non-LDAP) authentication
    +* #1214: REST API for Issues
    +* #1223: File upload on wiki edit form
    +* #1755: add "blocked by" as a related issues option
    +* #2420: Fetching emails from an POP server
    +* #2482: Named scopes in Issue and ActsAsWatchable plus some view refactoring (logic extraction).
    +* #2924: Make the right click menu more discoverable using a cursor property
    +* #2985: Make syntax highlighting pluggable
    +* #3201: Workflow Check/Uncheck All Rows/Columns
    +* #3359: Update CodeRay 0.9
    +* #3706: Allow assigned_to field configuration on Issue creation by email
    +* #3936: configurable list of models to include in search
    +* #4480: Create a link to the user profile from the administration interface
    +* #4482: Cache textile rendering
    +* #4572: Make it harder to ruin your database
    +* #4573: Move github gems to Gemcutter
    +* #4664: Add pagination to forum threads
    +* #4732: Make login case-insensitive also for PostgreSQL
    +* #4812: Create links to other projects
    +* #4819: Replace images with smushed ones for speed
    +* #4945: Allow custom fields attached to project to be searchable
    +* #5121: Fix issues list layout overflow
    +* #5169: Issue list view hook request
    +* #5208: Aibility to edit wiki sidebar
    +* #5281: Remove empty ul tags in the issue history
    +* #5291: Updated basque translations
    +* #5328: Automatically add "Repository" menu_item after repository creation
    +* #5415: Fewer SQL statements generated for watcher_recipients
    +* #5416: Exclude "fields_for" from overridden methods in TabularFormBuilder
    +* #5573: Allow issue assignment in email
    +* #5595: Allow start date and due dates to be set via incoming email
    +* #5752: The projects view (/projects) renders ul's wrong
    +* #5781: Allow to use more macros on the welcome page and project list
    +* Fixed #1288: Unable to past escaped wiki syntax in an issue description
    +* Fixed #1334: Wiki formatting character *_ and _*
    +* Fixed #1416: Inline code with less-then/greater-than produces @lt; and @gt; respectively
    +* Fixed #2473: Login and mail should not be case sensitive
    +* Fixed #2990: Ruby 1.9 - wrong number of arguments (1 for 0) on rake db:migrate
    +* Fixed #3089: Text formatting sometimes breaks when combined
    +* Fixed #3690: Status change info duplicates on the issue screen
    +* Fixed #3691: Redmine allows two files with the same file name to be uploaded to the same issue
    +* Fixed #3764: ApplicationHelperTest fails with JRuby
    +* Fixed #4265: Unclosed code tags in issue descriptions affects main UI
    +* Fixed #4745: Bug in index.xml.builder (issues)
    +* Fixed #4852: changing user/roles of project member not possible without javascript
    +* Fixed #4857: Week number calculation in date picker is wrong if a week starts with Sunday
    +* Fixed #4883: Bottom "contextual" placement in issue with associated changeset
    +* Fixed #4918: Revisions r3453 and r3454 broke On-the-fly user creation with LDAP
    +* Fixed #4935: Navigation to the Master Timesheet page (time_entries)
    +* Fixed #5043: Flash messages are not displayed after the project settings[module/activity] saved
    +* Fixed #5081: Broken links on public/help/wiki_syntax_detailed.html
    +* Fixed #5104: Description of document not wikified on documents index
    +* Fixed #5108: Issue linking fails inside of []s
    +* Fixed #5199: diff code coloring using coderay
    +* Fixed #5233: Add a hook to the issue report (Summary) view
    +* Fixed #5265: timetracking: subtasks time is added to the main task
    +* Fixed #5343: acts_as_event Doesn't Accept Outside URLs
    +* Fixed #5440: UI Inconsistency : Administration > Enumerations table row headers should be enclosed in 
    +* Fixed #5463: 0.9.4 INSTALL and/or UPGRADE, missing session_store.rb
    +* Fixed #5524: Update_parent_attributes doesn't work for the old parent issue when reparenting
    +* Fixed #5548: SVN Repository: Can not list content of a folder which includes square brackets.
    +* Fixed #5589: "with subproject" malfunction
    +* Fixed #5676: Search for Numeric Value
    +* Fixed #5696: Redmine + PostgreSQL 8.4.4 fails on _dir_list_content.rhtml
    +* Fixed #5698: redmine:email:receive_imap fails silently for mails with subject longer than 255 characters
    +* Fixed #5700: TimelogController#destroy assumes success
    +* Fixed #5751: developer role is mispelled
    +* Fixed #5769: Popup Calendar doesn't Advance in Chrome
    +* Fixed #5771: Problem when importing git repository
    +* Fixed #5823: Error in comments in plugin.rb
    +
    +
    +== 2010-07-07 v0.9.6
    +
    +* Fixed: Redmine.pm access by unauthorized users
    +
    +== 2010-06-24 v0.9.5
    +
    +* Linkify folder names on revision view
    +* "fiters" and "options" should be hidden in print view via css
    +* Fixed: NoMethodError when no issue params are submitted
    +* Fixed: projects.atom with required authentication
    +* Fixed: External links not correctly displayed in Wiki TOC
    +* Fixed: Member role forms in project settings are not hidden after member added
    +* Fixed: pre can't be inside p
    +* Fixed: session cookie path does not respect RAILS_RELATIVE_URL_ROOT
    +* Fixed: mail handler fails when the from address is empty
    +
    +
    +== 2010-05-01 v0.9.4
    +
    +* Filters collapsed by default on issues index page for a saved query
    +* Fixed: When categories list is too big the popup menu doesn't adjust (ex. in the issue list)
    +* Fixed: remove "main-menu" div when the menu is empty
    +* Fixed: Code syntax highlighting not working in Document page
    +* Fixed: Git blame/annotate fails on moved files
    +* Fixed: Failing test in test_show_atom
    +* Fixed: Migrate from trac - not displayed Wikis
    +* Fixed: Email notifications on file upload sent to empty recipient list
    +* Fixed: Migrating from trac is not possible, fails to allocate memory
    +* Fixed: Lost password no longer flashes a confirmation message
    +* Fixed: Crash while deleting in-use enumeration
    +* Fixed: Hard coded English string at the selection of issue watchers
    +* Fixed: Bazaar v2.1.0 changed behaviour
    +* Fixed: Roadmap display can raise an exception if no trackers are selected
    +* Fixed: Gravatar breaks layout of "logged in" page
    +* Fixed: Reposman.rb on Windows
    +* Fixed: Possible error 500 while moving an issue to another project with SQLite
    +* Fixed: backslashes in issue description/note should be escaped when quoted
    +* Fixed: Long text in 
     disrupts Associated revisions
    +* Fixed: Links to missing wiki pages not red on project overview page
    +* Fixed: Cannot delete a project with subprojects that shares versions
    +* Fixed: Update of Subversion changesets broken under Solaris
    +* Fixed: "Move issues" permission not working for Non member
    +* Fixed: Sidebar overlap on Users tab of Group editor
    +* Fixed: Error on db:migrate with table prefix set (hardcoded name in principal.rb)
    +* Fixed: Report shows sub-projects for non-members
    +* Fixed: 500 internal error when browsing any Redmine page in epiphany
    +* Fixed: Watchers selection lost when issue creation fails
    +* Fixed: When copying projects, redmine should not generate an email to people who created issues
    +* Fixed: Issue "#" table cells should have a class attribute to enable fine-grained CSS theme
    +* Fixed: Plugin generators should display help if no parameter is given
    +
    +
    +== 2010-02-28 v0.9.3
    +
    +* Adds filter for system shared versions on the cross project issue list
    +* Makes project identifiers searchable
    +* Remove invalid utf8 sequences from commit comments and author name
    +* Fixed: Wrong link when "http" not included in project "Homepage" link
    +* Fixed: Escaping in html email templates
    +* Fixed: Pound (#) followed by number with leading zero (0) removes leading zero when rendered in wiki
    +* Fixed: Deselecting textile text formatting causes interning empty string errors
    +* Fixed: error with postgres when entering a non-numeric id for an issue relation
    +* Fixed: div.task incorrectly wrapping on Gantt Chart
    +* Fixed: Project copy loses wiki pages hierarchy
    +* Fixed: parent project field doesn't include blank value when a member with 'add subproject' permission edits a child project
    +* Fixed: Repository.fetch_changesets tries to fetch changesets for archived projects
    +* Fixed: Duplicated project name for subproject version on gantt chart
    +* Fixed: roadmap shows subprojects issues even if subprojects is unchecked
    +* Fixed: IndexError if all the :last menu items are deleted from a menu
    +* Fixed: Very high CPU usage for a long time when fetching commits from a large Git repository
    +
    +
    +== 2010-02-07 v0.9.2
    +
    +* Fixed: Sub-project repository commits not displayed on parent project issues
    +* Fixed: Potential security leak on my page calendar
    +* Fixed: Project tree structure is broken by deleting the project with the subproject
    +* Fixed: Error message shown duplicated when creating a new group
    +* Fixed: Firefox cuts off large pages
    +* Fixed: Invalid format parameter returns a DoubleRenderError on issues index
    +* Fixed: Unnecessary Quote button on locked forum message
    +* Fixed: Error raised when trying to view the gantt or calendar with a grouped query
    +* Fixed: PDF support for Korean locale
    +* Fixed: Deprecation warning in extra/svn/reposman.rb
    +
    +
    +== 2010-01-30 v0.9.1
    +
    +* Vertical alignment for inline images in formatted text set to 'middle'
    +* Fixed: Redmine.pm error "closing dbh with active statement handles at /usr/lib/perl5/Apache/Redmine.pm"
    +* Fixed: copyright year in footer set to 2010
    +* Fixed: Trac migration script may not output query lines
    +* Fixed: Email notifications may affect language of notice messages on the UI
    +* Fixed: Can not search for 2 letters word
    +* Fixed: Attachments get saved on issue update even if validation fails
    +* Fixed: Tab's 'border-bottom' not absent when selected
    +* Fixed: Issue summary tables that list by user are not sorted
    +* Fixed: Issue pdf export fails if target version is set
    +* Fixed: Issue list export to PDF breaks when issues are sorted by a custom field
    +* Fixed: SQL error when adding a group
    +* Fixes: Min password length during password reset always displays as 4 chars
    +
    +
    +== 2010-01-09 v0.9.0 (Release candidate)
    +
    +* Unlimited subproject nesting
    +* Multiple roles per user per project
    +* User groups
    +* Inheritence of versions
    +* OpenID login
    +* "Watched by me" issue filter
    +* Project copy
    +* Project creation by non admin users
    +* Accept emails from anyone on a private project
    +* Add email notification on Wiki changes
    +* Make issue description non-required field
    +* Custom fields for Versions
    +* Being able to sort the issue list by custom fields
    +* Ability to close versions
    +* User display/editing of custom fields attached to their user profile
    +* Add "follows" issue relation
    +* Copy workflows between trackers and roles
    +* Defaults enabled modules list for project creation
    +* Weighted version completion percentage on the roadmap
    +* Autocreate user account when user submits email that creates new issue
    +* CSS class on overdue issues on the issue list
    +* Enable tracker update on issue edit form
    +* Remove issue watchers
    +* Ability to move threads between project forums
    +* Changed custom field "Possible values" to a textarea
    +* Adds projects association on tracker form
    +* Set session store to cookie store by default
    +* Set a default wiki page on project creation
    +* Roadmap for main project should see Roadmaps for sub projects
    +* Ticket grouping on the issue list
    +* Hierarchical Project links in the page header
    +* Allow My Page blocks to be added to from a plugin
    +* Sort issues by multiple columns
    +* Filters of saved query are now visible and be adjusted without editing the query
    +* Saving "sort order" in custom queries
    +* Url to fetch changesets for a repository
    +* Managers able to create subprojects
    +* Issue Totals on My Page Modules
    +* Convert Enumerations to single table inheritance (STI)
    +* Allow custom my_page blocks to define drop-down names
    +* "View Issues" user permission added
    +* Ask user what to do with child pages when deleting a parent wiki page
    +* Contextual quick search
    +* Allow resending of password by email
    +* Change reply subject to be a link to the reply itself
    +* Include Logged Time as part of the project's Activity history
    +* REST API for authentication
    +* Browse through Git branches
    +* Setup Object Daddy to replace test fixtures
    +* Setup shoulda to make it easier to test
    +* Custom fields and overrides on Enumerations
    +* Add or remove columns from the issue list
    +* Ability to add new version from issues screen
    +* Setting to choose which day calendars start
    +* Asynchronous email delivery method
    +* RESTful URLs for (almost) everything
    +* Include issue status in search results and activity pages
    +* Add email to admin user search filter
    +* Proper content type for plain text mails
    +* Default value of project jump box
    +* Tree based menus
    +* Ability to use issue status to update percent done
    +* Second set of issue "Action Links" at the bottom of an issue page
    +* Proper exist status code for rdm-mailhandler.rb
    +* Remove incoming email body via a delimiter
    +* Fixed: Custom querry 'Export to PDF' ignores field selection
    +* Fixed: Related e-mail notifications aren't threaded
    +* Fixed: No warning when the creation of a categories from the issue form fails
    +* Fixed: Actually block issues from closing when relation 'blocked by' isn't closed
    +* Fixed: Include both first and last name when sorting by users
    +* Fixed: Table cell with multiple line text
    +* Fixed: Project overview page shows disabled trackers
    +* Fixed: Cross project issue relations and user permissions
    +* Fixed: My page shows tickets the user doesn't have access to
    +* Fixed: TOC does not parse wiki page reference links with description
    +* Fixed: Target version-list on bulk edit form is incorrectly sorted
    +* Fixed: Cannot modify/delete project named "Documents"
    +* Fixed: Email address in brackets breaks html
    +* Fixed: Timelog detail loose issue filter passing to report tab
    +* Fixed: Inform about custom field's name maximum length
    +* Fixed: Activity page and Atom feed links contain project id instead of identifier
    +* Fixed: no Atom key for forums with only 1 forum
    +* Fixed: When reading RSS feed in MS Outlook, the inline links are broken.
    +* Fixed: Sometimes new posts don't show up in the topic list of a forum.
    +* Fixed: The all/active filter selection in the project view does not stick.
    +* Fixed: Login box has Different width
    +* Fixed: User removed from project - still getting project update emails
    +* Fixed: Project with the identifier of 'new' cannot be viewed
    +* Fixed: Artefacts in search view (Cyrillic)
    +* Fixed: Allow [#id] as subject to reply by email
    +* Fixed: Wrong language used when closing an issue via a commit message
    +* Fixed: email handler drops emails for new issues with no subject
    +* Fixed: Calendar misspelled under Roles/Permissions
    +* Fixed: Emails from no-reply redmine's address hell cycle
    +* Fixed: child_pages macro fails on wiki page history
    +* Fixed: Pre-filled time tracking date ignores timezone
    +* Fixed: Links on locked users lead to 404 page
    +* Fixed: Page changes in issue-list when using context menu
    +* Fixed: diff parser removes lines starting with multiple dashes
    +* Fixed: Quoting in forums resets message subject
    +* Fixed: Editing issue comment removes quote link
    +* Fixed: Redmine.pm ignore browse_repository permission
    +* Fixed: text formatting breaks on [msg1][msg2]
    +* Fixed: Spent Time Default Value of 0.0
    +* Fixed: Wiki pages in search results are referenced by project number, not by project identifier.
    +* Fixed: When logging in via an autologin cookie the user's last_login_on should be updated
    +* Fixed: 50k users cause problems in project->settings->members screen
    +* Fixed: Document timestamp needs to show updated timestamps
    +* Fixed: Users getting notifications for issues they are no longer allowed to view
    +* Fixed: issue summary counts should link to the issue list without subprojects
    +* Fixed: 'Delete' link on LDAP list has no effect
    +
    +
    +== 2009-11-15 v0.8.7
    +
    +* Fixed: Hide paragraph terminator at the end of headings on html export
    +* Fixed: pre tags containing "
    1. bold text
    2. italic text
    3. underlined text
    4. link to http://www.tecnick.com
    5. test break
      second line
      third line
    6. font + 3
    7. small text
    8. normal subscript superscript

    9. table:
      #AB
      1A1B1
      2A2 € € € & è è B2
      3A3B3

      image:
      \"test"; + + + # ENGLISH + + @l = {} + + # PAGE META DESCRIPTORS -------------------------------------- + + @l['a_meta_charset'] = "UTF-8"; + @l['a_meta_dir'] = "ltr"; + @l['a_meta_language'] = "en"; + + # TRANSLATIONS -------------------------------------- + @l['w_page'] = "page"; + + + # create new PDF document (document units are set by default to millimeters) + pdf = TCPDF.new + + # set document information + pdf.SetCreator("TCPDF"); + pdf.SetAuthor("TCPDF"); + pdf.SetTitle(doc_title); + pdf.SetSubject(doc_subject); + pdf.SetKeywords(doc_keywords); + + pdf.SetHeaderData("#{File.join(RAILS_ROOT, 'public')}/logo_example.png", 20, "header title", "first row\nsecond row\nthird row"); + + #set margins + pdf.SetMargins(15, 27, 15); + #set auto page breaks + pdf.SetAutoPageBreak(true, 25); + pdf.SetPrintHeader + pdf.SetPrintFooter + pdf.SetHeaderMargin(5); + pdf.SetFooterMargin(10); + pdf.SetImageScale(4); #set image scale factor + + pdf.SetHeaderFont(["FreeSans", '', 10]); + pdf.SetFooterFont(["FreeSans", '', 8]); + + pdf.SetLanguageArray(@l); #set language items + + + #initialize document + pdf.alias_nb_pages(); + + pdf.AddPage(); + + # set barcode + # pdf.SetBarcode(Time.now.strftime("Y-m-d H:i:s")); + + # output some HTML code + pdf.SetFont("vera", "", 10); + + pdf.writeHTML(htmlcontent, true, 0); + + # output two html columns + first_column_width = 80; + current_y_position = pdf.GetY(); + pdf.writeHTMLCell(first_column_width, 0, 0, current_y_position, "hello", 0, 0, 0); + pdf.writeHTMLCell(0, 0, first_column_width, current_y_position, "world", 0, 1, 0); + + # output some content + pdf.SetFont("vera", "BI", 20); + pdf.Cell(0,10,"TEST Bold-Italic Cell",1,1,'C'); + + # output some UTF-8 test content + pdf.AddPage(); + pdf.SetFont("FreeSans", "", 12); + utf8text = open(File.join(RAILS_ROOT, 'vendor/plugins/rfpdf',"utf8test.txt"), "rb").read; # get utf-8 text form file + pdf.SetFillColor(230, 240, 255, true); + pdf.Write(5, utf8text, '', 1); + + # remove page header/footer + pdf.SetPrintHeader(false); + pdf.SetPrintFooter(false); + + # Two HTML columns test + pdf.AddPage(); + right_column = "right column right column right column right column right column + right column right column right column right column right column right column + right column right column right column right column right column right column"; + left_column = "left column left column left column left column left column left + column left column left column left column left column left column left column + left column left column left column left column left column left column left + column"; + first_column_width = 80; + second_column_width = 80; + column_space = 20; + current_y_position = pdf.GetY(); + pdf.writeHTMLCell(first_column_width, 0, 0, 0, left_column, 1, 0, 0); + pdf.Cell(0); + pdf.writeHTMLCell(second_column_width, 0, first_column_width+column_space, current_y_position, right_column, 0, 0, 0); + + # add page header/footer + pdf.SetPrintHeader(true); + pdf.SetPrintFooter(true); + + pdf.AddPage(); + + # Multicell test + pdf.MultiCell(40, 5, "A test multicell line 1\ntest multicell line 2\ntest multicell line 3", 1, 'J', 0, 0); + pdf.MultiCell(40, 5, "B test multicell line 1\ntest multicell line 2\ntest multicell line 3", 1, 'J', 0); + pdf.MultiCell(40, 5, "C test multicell line 1\ntest multicell line 2\ntest multicell line 3", 1, 'J', 0, 0); + pdf.MultiCell(40, 5, "D test multicell line 1\ntest multicell line 2\ntest multicell line 3", 1, 'J', 0, 2); + pdf.MultiCell(40, 5, "F test multicell line 1\ntest multicell line 2\ntest multicell line 3", 1, 'J', 0); + + #Close and output PDF document +%><%=pdf.Output()%> \ No newline at end of file diff --git a/lib/plugins/rfpdf/utf8test.txt b/lib/plugins/rfpdf/utf8test.txt new file mode 100644 index 00000000..fa0f4b75 --- /dev/null +++ b/lib/plugins/rfpdf/utf8test.txt @@ -0,0 +1,135 @@ +Sentences that contain all letters commonly used in a language +-------------------------------------------------------------- + +Markus Kuhn -- 2001-09-02 + +This file is UTF-8 encoded. + + +Danish (da) +--------- + + Quizdeltagerne spiste jordbær med fløde, mens cirkusklovnen + Wolther spillede på xylofon. + (= Quiz contestants were eating strawbery with cream while Wolther + the circus clown played on xylophone.) + +German (de) +----------- + + Falsches Üben von Xylophonmusik quält jeden größeren Zwerg + (= Wrongful practicing of xylophone music tortures every larger dwarf) + + Zwölf Boxkämpfer jagten Eva quer über den Sylter Deich + (= Twelve boxing fighters hunted Eva across the dike of Sylt) + + Heizölrückstoßabdämpfung + (= fuel oil recoil absorber) + (jqvwxy missing, but all non-ASCII letters in one word) + +English (en) +------------ + + The quick brown fox jumps over the lazy dog + +Spanish (es) +------------ + + El pingüino Wenceslao hizo kilómetros bajo exhaustiva lluvia y + frío, añoraba a su querido cachorro. + (Contains every letter and every accent, but not every combination + of vowel + acute.) + +French (fr) +----------- + + Portez ce vieux whisky au juge blond qui fume sur son île intérieure, à + côté de l'alcôve ovoïde, où les bûches se consument dans l'âtre, ce + qui lui permet de penser à la cænogenèse de l'être dont il est question + dans la cause ambiguë entendue à Moÿ, dans un capharnaüm qui, + pense-t-il, diminue çà et là la qualité de son œuvre. + + l'île exiguë + Où l'obèse jury mûr + Fête l'haï volapük, + Âne ex aéquo au whist, + Ôtez ce vœu déçu. + + Le cœur déçu mais l'âme plutôt naïve, Louÿs rêva de crapaüter en + canoë au delà des îles, près du mälström où brûlent les novæ. + +Irish Gaelic (ga) +----------------- + + D'fhuascail Íosa, Úrmhac na hÓighe Beannaithe, pór Éava agus Ádhaimh + +Hungarian (hu) +-------------- + + Árvíztűrő tükörfúrógép + (= flood-proof mirror-drilling machine, only all non-ASCII letters) + +Icelandic (is) +-------------- + + Kæmi ný öxi hér ykist þjófum nú bæði víl og ádrepa + + Sævör grét áðan því úlpan var ónýt + (some ASCII letters missing) + +Greek (el) +------------- + + Γαζέες καὶ μυρτιὲς δὲν θὰ βρῶ πιὰ στὸ χρυσαφὶ ξέφωτο + (= No more shall I see acacias or myrtles in the golden clearing) + + Ξεσκεπάζω τὴν ψυχοφθόρα βδελυγμία + (= I uncover the soul-destroying abhorrence) + +Japanese (jp) +------------- + + Hiragana: (Iroha) + + いろはにほへとちりぬるを + わかよたれそつねならむ + うゐのおくやまけふこえて + あさきゆめみしゑひもせす + + Katakana: + + イロハニホヘト チリヌルヲ ワカヨタレソ ツネナラム + ウヰノオクヤマ ケフコエテ アサキユメミシ ヱヒモセスン + +Hebrew (iw) +----------- + + ? דג סקרן שט בים מאוכזב ולפתע מצא לו חברה איך הקליטה + +Polish (pl) +----------- + + Pchnąć w tę łódź jeża lub ośm skrzyń fig + (= To push a hedgehog or eight bins of figs in this boat) + +Russian (ru) +------------ + + В чащах юга жил бы цитрус? Да, но фальшивый экземпляр! + (= Would a citrus live in the bushes of south? Yes, but only a fake one!) + +Thai (th) +--------- + + [--------------------------|------------------------] + ๏ เป็นมนุษย์สุดประเสริฐเลิศคุณค่า กว่าบรรดาฝูงสัตว์เดรัจฉาน + จงฝ่าฟันพัฒนาวิชาการ อย่าล้างผลาญฤๅเข่นฆ่าบีฑาใคร + ไม่ถือโทษโกรธแช่งซัดฮึดฮัดด่า หัดอภัยเหมือนกีฬาอัชฌาสัย + ปฏิบัติประพฤติกฎกำหนดใจ พูดจาให้จ๊ะๆ จ๋าๆ น่าฟังเอย ฯ + + [The copyright for the Thai example is owned by The Computer + Association of Thailand under the Royal Patronage of His Majesty the + King.] + +Please let me know if you find others! Special thanks to the people +from all over the world who contributed these sentences. diff --git a/lib/redcloth3.rb b/lib/redcloth3.rb new file mode 100644 index 00000000..b0bda81a --- /dev/null +++ b/lib/redcloth3.rb @@ -0,0 +1,1208 @@ +# vim:ts=4:sw=4: +# = RedCloth - Textile and Markdown Hybrid for Ruby +# +# Homepage:: http://whytheluckystiff.net/ruby/redcloth/ +# Author:: why the lucky stiff (http://whytheluckystiff.net/) +# Copyright:: (cc) 2004 why the lucky stiff (and his puppet organizations.) +# License:: BSD +# +# (see http://hobix.com/textile/ for a Textile Reference.) +# +# Based on (and also inspired by) both: +# +# PyTextile: http://diveintomark.org/projects/textile/textile.py.txt +# Textism for PHP: http://www.textism.com/tools/textile/ +# +# + +# = RedCloth +# +# RedCloth is a Ruby library for converting Textile and/or Markdown +# into HTML. You can use either format, intermingled or separately. +# You can also extend RedCloth to honor your own custom text stylings. +# +# RedCloth users are encouraged to use Textile if they are generating +# HTML and to use Markdown if others will be viewing the plain text. +# +# == What is Textile? +# +# Textile is a simple formatting style for text +# documents, loosely based on some HTML conventions. +# +# == Sample Textile Text +# +# h3. This is a title +# +# h3. This is a subhead +# +# This is a bit of paragraph. +# +# bq. This is a blockquote. +# +# = Writing Textile +# +# A Textile document consists of paragraphs. Paragraphs +# can be specially formatted by adding a small instruction +# to the beginning of the paragraph. +# +# h[n]. Header of size [n]. +# bq. Blockquote. +# # Numeric list. +# * Bulleted list. +# +# == Quick Phrase Modifiers +# +# Quick phrase modifiers are also included, to allow formatting +# of small portions of text within a paragraph. +# +# \_emphasis\_ +# \_\_italicized\_\_ +# \*strong\* +# \*\*bold\*\* +# ??citation?? +# -deleted text- +# +inserted text+ +# ^superscript^ +# ~subscript~ +# @code@ +# %(classname)span% +# +# ==notextile== (leave text alone) +# +# == Links +# +# To make a hypertext link, put the link text in "quotation +# marks" followed immediately by a colon and the URL of the link. +# +# Optional: text in (parentheses) following the link text, +# but before the closing quotation mark, will become a Title +# attribute for the link, visible as a tool tip when a cursor is above it. +# +# Example: +# +# "This is a link (This is a title) ":http://www.textism.com +# +# Will become: +# +# This is a link +# +# == Images +# +# To insert an image, put the URL for the image inside exclamation marks. +# +# Optional: text that immediately follows the URL in (parentheses) will +# be used as the Alt text for the image. Images on the web should always +# have descriptive Alt text for the benefit of readers using non-graphical +# browsers. +# +# Optional: place a colon followed by a URL immediately after the +# closing ! to make the image into a link. +# +# Example: +# +# !http://www.textism.com/common/textist.gif(Textist)! +# +# Will become: +# +# Textist +# +# With a link: +# +# !/common/textist.gif(Textist)!:http://textism.com +# +# Will become: +# +# Textist +# +# == Defining Acronyms +# +# HTML allows authors to define acronyms via the tag. The definition appears as a +# tool tip when a cursor hovers over the acronym. A crucial aid to clear writing, +# this should be used at least once for each acronym in documents where they appear. +# +# To quickly define an acronym in Textile, place the full text in (parentheses) +# immediately following the acronym. +# +# Example: +# +# ACLU(American Civil Liberties Union) +# +# Will become: +# +# ACLU +# +# == Adding Tables +# +# In Textile, simple tables can be added by seperating each column by +# a pipe. +# +# |a|simple|table|row| +# |And|Another|table|row| +# +# Attributes are defined by style definitions in parentheses. +# +# table(border:1px solid black). +# (background:#ddd;color:red). |{}| | | | +# +# == Using RedCloth +# +# RedCloth is simply an extension of the String class, which can handle +# Textile formatting. Use it like a String and output HTML with its +# RedCloth#to_html method. +# +# doc = RedCloth.new " +# +# h3. Test document +# +# Just a simple test." +# +# puts doc.to_html +# +# By default, RedCloth uses both Textile and Markdown formatting, with +# Textile formatting taking precedence. If you want to turn off Markdown +# formatting, to boost speed and limit the processor: +# +# class RedCloth::Textile.new( str ) + +class RedCloth3 < String + + VERSION = '3.0.4' + DEFAULT_RULES = [:textile, :markdown] + + # + # Two accessor for setting security restrictions. + # + # This is a nice thing if you're using RedCloth for + # formatting in public places (e.g. Wikis) where you + # don't want users to abuse HTML for bad things. + # + # If +:filter_html+ is set, HTML which wasn't + # created by the Textile processor will be escaped. + # + # If +:filter_styles+ is set, it will also disable + # the style markup specifier. ('{color: red}') + # + attr_accessor :filter_html, :filter_styles + + # + # Accessor for toggling hard breaks. + # + # If +:hard_breaks+ is set, single newlines will + # be converted to HTML break tags. This is the + # default behavior for traditional RedCloth. + # + attr_accessor :hard_breaks + + # Accessor for toggling lite mode. + # + # In lite mode, block-level rules are ignored. This means + # that tables, paragraphs, lists, and such aren't available. + # Only the inline markup for bold, italics, entities and so on. + # + # r = RedCloth.new( "And then? She *fell*!", [:lite_mode] ) + # r.to_html + # #=> "And then? She fell!" + # + attr_accessor :lite_mode + + # + # Accessor for toggling span caps. + # + # Textile places `span' tags around capitalized + # words by default, but this wreaks havoc on Wikis. + # If +:no_span_caps+ is set, this will be + # suppressed. + # + attr_accessor :no_span_caps + + # + # Establishes the markup predence. Available rules include: + # + # == Textile Rules + # + # The following textile rules can be set individually. Or add the complete + # set of rules with the single :textile rule, which supplies the rule set in + # the following precedence: + # + # refs_textile:: Textile references (i.e. [hobix]http://hobix.com/) + # block_textile_table:: Textile table block structures + # block_textile_lists:: Textile list structures + # block_textile_prefix:: Textile blocks with prefixes (i.e. bq., h3., etc.) + # inline_textile_image:: Textile inline images + # inline_textile_link:: Textile inline links + # inline_textile_span:: Textile inline spans + # glyphs_textile:: Textile entities (such as em-dashes and smart quotes) + # + # == Markdown + # + # refs_markdown:: Markdown references (for example: [hobix]: http://hobix.com/) + # block_markdown_setext:: Markdown setext headers + # block_markdown_atx:: Markdown atx headers + # block_markdown_rule:: Markdown horizontal rules + # block_markdown_bq:: Markdown blockquotes + # block_markdown_lists:: Markdown lists + # inline_markdown_link:: Markdown links + attr_accessor :rules + + # Returns a new RedCloth object, based on _string_ and + # enforcing all the included _restrictions_. + # + # r = RedCloth.new( "h1. A bold man", [:filter_html] ) + # r.to_html + # #=>"

      A <b>bold</b> man

      " + # + def initialize( string, restrictions = [] ) + restrictions.each { |r| method( "#{ r }=" ).call( true ) } + super( string ) + end + + # + # Generates HTML from the Textile contents. + # + # r = RedCloth.new( "And then? She *fell*!" ) + # r.to_html( true ) + # #=>"And then? She fell!" + # + def to_html( *rules ) + rules = DEFAULT_RULES if rules.empty? + # make our working copy + text = self.dup + + @urlrefs = {} + @shelf = [] + textile_rules = [:block_textile_table, :block_textile_lists, + :block_textile_prefix, :inline_textile_image, :inline_textile_link, + :inline_textile_code, :inline_textile_span, :glyphs_textile] + markdown_rules = [:refs_markdown, :block_markdown_setext, :block_markdown_atx, :block_markdown_rule, + :block_markdown_bq, :block_markdown_lists, + :inline_markdown_reflink, :inline_markdown_link] + @rules = rules.collect do |rule| + case rule + when :markdown + markdown_rules + when :textile + textile_rules + else + rule + end + end.flatten + + # standard clean up + incoming_entities text + clean_white_space text + + # start processor + @pre_list = [] + rip_offtags text + no_textile text + escape_html_tags text + # need to do this before #hard_break and #blocks + block_textile_quotes text unless @lite_mode + hard_break text + unless @lite_mode + refs text + blocks text + end + inline text + smooth_offtags text + + retrieve text + + text.gsub!( /<\/?notextile>/, '' ) + text.gsub!( /x%x%/, '&' ) + clean_html text if filter_html + text.strip! + text + + end + + ####### + private + ####### + # + # Mapping of 8-bit ASCII codes to HTML numerical entity equivalents. + # (from PyTextile) + # + TEXTILE_TAGS = + + [[128, 8364], [129, 0], [130, 8218], [131, 402], [132, 8222], [133, 8230], + [134, 8224], [135, 8225], [136, 710], [137, 8240], [138, 352], [139, 8249], + [140, 338], [141, 0], [142, 0], [143, 0], [144, 0], [145, 8216], [146, 8217], + [147, 8220], [148, 8221], [149, 8226], [150, 8211], [151, 8212], [152, 732], + [153, 8482], [154, 353], [155, 8250], [156, 339], [157, 0], [158, 0], [159, 376]]. + + collect! do |a, b| + [a.chr, ( b.zero? and "" or "&#{ b };" )] + end + + # + # Regular expressions to convert to HTML. + # + A_HLGN = /(?:(?:<>|<|>|\=|[()]+)+)/ + A_VLGN = /[\-^~]/ + C_CLAS = '(?:\([^")]+\))' + C_LNGE = '(?:\[[^"\[\]]+\])' + C_STYL = '(?:\{[^"}]+\})' + S_CSPN = '(?:\\\\\d+)' + S_RSPN = '(?:/\d+)' + A = "(?:#{A_HLGN}?#{A_VLGN}?|#{A_VLGN}?#{A_HLGN}?)" + S = "(?:#{S_CSPN}?#{S_RSPN}|#{S_RSPN}?#{S_CSPN}?)" + C = "(?:#{C_CLAS}?#{C_STYL}?#{C_LNGE}?|#{C_STYL}?#{C_LNGE}?#{C_CLAS}?|#{C_LNGE}?#{C_STYL}?#{C_CLAS}?)" + # PUNCT = Regexp::quote( '!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~' ) + PUNCT = Regexp::quote( '!"#$%&\'*+,-./:;=?@\\^_`|~' ) + PUNCT_NOQ = Regexp::quote( '!"#$&\',./:;=?@\\`|' ) + PUNCT_Q = Regexp::quote( '*-_+^~%' ) + HYPERLINK = '(\S+?)([^\w\s/;=\?]*?)(?=\s|<|$)' + + # Text markup tags, don't conflict with block tags + SIMPLE_HTML_TAGS = [ + 'tt', 'b', 'i', 'big', 'small', 'em', 'strong', 'dfn', 'code', + 'samp', 'kbd', 'var', 'cite', 'abbr', 'acronym', 'a', 'img', 'br', + 'br', 'map', 'q', 'sub', 'sup', 'span', 'bdo' + ] + + QTAGS = [ + ['**', 'b', :limit], + ['*', 'strong', :limit], + ['??', 'cite', :limit], + ['-', 'del', :limit], + ['__', 'i', :limit], + ['_', 'em', :limit], + ['%', 'span', :limit], + ['+', 'ins', :limit], + ['^', 'sup', :limit], + ['~', 'sub', :limit] + ] + QTAGS_JOIN = QTAGS.map {|rc, ht, rtype| Regexp::quote rc}.join('|') + + QTAGS.collect! do |rc, ht, rtype| + rcq = Regexp::quote rc + re = + case rtype + when :limit + /(^|[>\s\(]) # sta + (?!\-\-) + (#{QTAGS_JOIN}|) # oqs + (#{rcq}) # qtag + (\w|[^\s].*?[^\s]) # content + (?!\-\-) + #{rcq} + (#{QTAGS_JOIN}|) # oqa + (?=[[:punct:]]|<|\s|\)|$)/x + else + /(#{rcq}) + (#{C}) + (?::(\S+))? + (\w|[^\s\-].*?[^\s\-]) + #{rcq}/xm + end + [rc, ht, re, rtype] + end + + # Elements to handle + GLYPHS = [ + # [ /([^\s\[{(>])?\'([dmst]\b|ll\b|ve\b|\s|:|$)/, '\1’\2' ], # single closing + # [ /([^\s\[{(>#{PUNCT_Q}][#{PUNCT_Q}]*)\'/, '\1’' ], # single closing + # [ /\'(?=[#{PUNCT_Q}]*(s\b|[\s#{PUNCT_NOQ}]))/, '’' ], # single closing + # [ /\'/, '‘' ], # single opening + # [ //, '>' ], # greater-than + # [ /([^\s\[{(])?"(\s|:|$)/, '\1”\2' ], # double closing + # [ /([^\s\[{(>#{PUNCT_Q}][#{PUNCT_Q}]*)"/, '\1”' ], # double closing + # [ /"(?=[#{PUNCT_Q}]*[\s#{PUNCT_NOQ}])/, '”' ], # double closing + # [ /"/, '“' ], # double opening + # [ /\b( )?\.{3}/, '\1…' ], # ellipsis + # [ /\b([A-Z][A-Z0-9]{2,})\b(?:[(]([^)]*)[)])/, '\1' ], # 3+ uppercase acronym + # [ /(^|[^"][>\s])([A-Z][A-Z0-9 ]+[A-Z0-9])([^\2\3', :no_span_caps ], # 3+ uppercase caps + # [ /(\.\s)?\s?--\s?/, '\1—' ], # em dash + # [ /\s->\s/, ' → ' ], # right arrow + # [ /\s-\s/, ' – ' ], # en dash + # [ /(\d+) ?x ?(\d+)/, '\1×\2' ], # dimension sign + # [ /\b ?[(\[]TM[\])]/i, '™' ], # trademark + # [ /\b ?[(\[]R[\])]/i, '®' ], # registered + # [ /\b ?[(\[]C[\])]/i, '©' ] # copyright + ] + + H_ALGN_VALS = { + '<' => 'left', + '=' => 'center', + '>' => 'right', + '<>' => 'justify' + } + + V_ALGN_VALS = { + '^' => 'top', + '-' => 'middle', + '~' => 'bottom' + } + + # + # Flexible HTML escaping + # + def htmlesc( str, mode=:Quotes ) + if str + str.gsub!( '&', '&' ) + str.gsub!( '"', '"' ) if mode != :NoQuotes + str.gsub!( "'", ''' ) if mode == :Quotes + str.gsub!( '<', '<') + str.gsub!( '>', '>') + end + str + end + + # Search and replace for Textile glyphs (quotes, dashes, other symbols) + def pgl( text ) + #GLYPHS.each do |re, resub, tog| + # next if tog and method( tog ).call + # text.gsub! re, resub + #end + text.gsub!(/\b([A-Z][A-Z0-9]{1,})\b(?:[(]([^)]*)[)])/) do |m| + "#{$1}" + end + end + + # Parses Textile attribute lists and builds an HTML attribute string + def pba( text_in, element = "" ) + + return '' unless text_in + + style = [] + text = text_in.dup + if element == 'td' + colspan = $1 if text =~ /\\(\d+)/ + rowspan = $1 if text =~ /\/(\d+)/ + style << "vertical-align:#{ v_align( $& ) };" if text =~ A_VLGN + end + + if text.sub!( /\{([^"}]*)\}/, '' ) && !filter_styles + sanitized = sanitize_styles($1) + style << "#{ sanitized };" unless sanitized.blank? + end + + lang = $1 if + text.sub!( /\[([^)]+?)\]/, '' ) + + cls = $1 if + text.sub!( /\(([^()]+?)\)/, '' ) + + style << "padding-left:#{ $1.length }em;" if + text.sub!( /([(]+)/, '' ) + + style << "padding-right:#{ $1.length }em;" if text.sub!( /([)]+)/, '' ) + + style << "text-align:#{ h_align( $& ) };" if text =~ A_HLGN + + cls, id = $1, $2 if cls =~ /^(.*?)#(.*)$/ + + atts = '' + atts << " style=\"#{ style.join }\"" unless style.empty? + atts << " class=\"#{ cls }\"" unless cls.to_s.empty? + atts << " lang=\"#{ lang }\"" if lang + atts << " id=\"#{ id }\"" if id + atts << " colspan=\"#{ colspan }\"" if colspan + atts << " rowspan=\"#{ rowspan }\"" if rowspan + + atts + end + + STYLES_RE = /^(color|width|height|border|background|padding|margin|font|text|float)(-[a-z]+)*:\s*((\d+%?|\d+px|\d+(\.\d+)?em|#[0-9a-f]+|[a-z]+)\s*)+$/i + + def sanitize_styles(str) + styles = str.split(";").map(&:strip) + styles.reject! do |style| + !style.match(STYLES_RE) + end + styles.join(";") + end + + TABLE_RE = /^(?:table(_?#{S}#{A}#{C})\. ?\n)?^(#{A}#{C}\.? ?\|.*?\|)(\n\n|\Z)/m + + # Parses a Textile table block, building HTML from the result. + def block_textile_table( text ) + text.gsub!( TABLE_RE ) do |matches| + + tatts, fullrow = $~[1..2] + tatts = pba( tatts, 'table' ) + tatts = shelve( tatts ) if tatts + rows = [] + + fullrow.each_line do |row| + ratts, row = pba( $1, 'tr' ), $2 if row =~ /^(#{A}#{C}\. )(.*)/m + cells = [] + row.split( /(\|)(?![^\[\|]*\]\])/ )[1..-2].each do |cell| + next if cell == '|' + ctyp = 'd' + ctyp = 'h' if cell =~ /^_/ + + catts = '' + catts, cell = pba( $1, 'td' ), $2 if cell =~ /^(_?#{S}#{A}#{C}\. ?)(.*)/ + + catts = shelve( catts ) if catts + cells << "\t\t\t#{ cell }" + end + ratts = shelve( ratts ) if ratts + rows << "\t\t\n#{ cells.join( "\n" ) }\n\t\t" + end + "\t\n#{ rows.join( "\n" ) }\n\t\n\n" + end + end + + LISTS_RE = /^([#*]+?#{C} .*?)$(?![^#*])/m + LISTS_CONTENT_RE = /^([#*]+)(#{A}#{C}) (.*)$/m + + # Parses Textile lists and generates HTML + def block_textile_lists( text ) + text.gsub!( LISTS_RE ) do |match| + lines = match.split( /\n/ ) + last_line = -1 + depth = [] + lines.each_with_index do |line, line_id| + if line =~ LISTS_CONTENT_RE + tl,atts,content = $~[1..3] + if depth.last + if depth.last.length > tl.length + (depth.length - 1).downto(0) do |i| + break if depth[i].length == tl.length + lines[line_id - 1] << "\n\t\n\t" + depth.pop + end + end + if depth.last and depth.last.length == tl.length + lines[line_id - 1] << '' + end + end + unless depth.last == tl + depth << tl + atts = pba( atts ) + atts = shelve( atts ) if atts + lines[line_id] = "\t<#{ lT(tl) }l#{ atts }>\n\t
    10. #{ content }" + else + lines[line_id] = "\t\t
    11. #{ content }" + end + last_line = line_id + + else + last_line = line_id + end + if line_id - last_line > 1 or line_id == lines.length - 1 + while v = depth.pop + lines[last_line] << "
    12. \n\t" + end + end + end + lines.join( "\n" ) + end + end + + QUOTES_RE = /(^>+([^\n]*?)(\n|$))+/m + QUOTES_CONTENT_RE = /^([> ]+)(.*)$/m + + def block_textile_quotes( text ) + text.gsub!( QUOTES_RE ) do |match| + lines = match.split( /\n/ ) + quotes = '' + indent = 0 + lines.each do |line| + line =~ QUOTES_CONTENT_RE + bq,content = $1, $2 + l = bq.count('>') + if l != indent + quotes << ("\n\n" + (l>indent ? '
      ' * (l-indent) : '
      ' * (indent-l)) + "\n\n") + indent = l + end + quotes << (content + "\n") + end + quotes << ("\n" + '' * indent + "\n\n") + quotes + end + end + + CODE_RE = /(\W) + @ + (?:\|(\w+?)\|)? + (.+?) + @ + (?=\W)/x + + def inline_textile_code( text ) + text.gsub!( CODE_RE ) do |m| + before,lang,code,after = $~[1..4] + lang = " lang=\"#{ lang }\"" if lang + rip_offtags( "#{ before }#{ code }
      #{ after }", false ) + end + end + + def lT( text ) + text =~ /\#$/ ? 'o' : 'u' + end + + def hard_break( text ) + text.gsub!( /(.)\n(?!\Z| *([#*=]+(\s|$)|[{|]))/, "\\1
      " ) if hard_breaks + end + + BLOCKS_GROUP_RE = /\n{2,}(?! )/m + + def blocks( text, deep_code = false ) + text.replace( text.split( BLOCKS_GROUP_RE ).collect do |blk| + plain = blk !~ /\A[#*> ]/ + + # skip blocks that are complex HTML + if blk =~ /^<\/?(\w+).*>/ and not SIMPLE_HTML_TAGS.include? $1 + blk + else + # search for indentation levels + blk.strip! + if blk.empty? + blk + else + code_blk = nil + blk.gsub!( /((?:\n(?:\n^ +[^\n]*)+)+)/m ) do |iblk| + flush_left iblk + blocks iblk, plain + iblk.gsub( /^(\S)/, "\t\\1" ) + if plain + code_blk = iblk; "" + else + iblk + end + end + + block_applied = 0 + @rules.each do |rule_name| + block_applied += 1 if ( rule_name.to_s.match /^block_/ and method( rule_name ).call( blk ) ) + end + if block_applied.zero? + if deep_code + blk = "\t
      #{ blk }
      " + else + blk = "\t

      #{ blk }

      " + end + end + # hard_break blk + blk + "\n#{ code_blk }" + end + end + + end.join( "\n\n" ) ) + end + + def textile_bq( tag, atts, cite, content ) + cite, cite_title = check_refs( cite ) + cite = " cite=\"#{ cite }\"" if cite + atts = shelve( atts ) if atts + "\t\n\t\t#{ content }

      \n\t" + end + + def textile_p( tag, atts, cite, content ) + atts = shelve( atts ) if atts + "\t<#{ tag }#{ atts }>#{ content }" + end + + alias textile_h1 textile_p + alias textile_h3 textile_p + alias textile_h3 textile_p + alias textile_h4 textile_p + alias textile_h5 textile_p + alias textile_h6 textile_p + + def textile_fn_( tag, num, atts, cite, content ) + atts << " id=\"fn#{ num }\" class=\"footnote\"" + content = "#{ num } #{ content }" + atts = shelve( atts ) if atts + "\t#{ content }

      " + end + + BLOCK_RE = /^(([a-z]+)(\d*))(#{A}#{C})\.(?::(\S+))? (.*)$/m + + def block_textile_prefix( text ) + if text =~ BLOCK_RE + tag,tagpre,num,atts,cite,content = $~[1..6] + atts = pba( atts ) + + # pass to prefix handler + replacement = nil + if respond_to? "textile_#{ tag }", true + replacement = method( "textile_#{ tag }" ).call( tag, atts, cite, content ) + elsif respond_to? "textile_#{ tagpre }_", true + replacement = method( "textile_#{ tagpre }_" ).call( tagpre, num, atts, cite, content ) + end + text.gsub!( $& ) { replacement } if replacement + end + end + + SETEXT_RE = /\A(.+?)\n([=-])[=-]* *$/m + def block_markdown_setext( text ) + if text =~ SETEXT_RE + tag = if $2 == "="; "h1"; else; "h3"; end + blk, cont = "<#{ tag }>#{ $1 }", $' + blocks cont + text.replace( blk + cont ) + end + end + + ATX_RE = /\A(\#{1,6}) # $1 = string of #'s + [ ]* + (.+?) # $2 = Header text + [ ]* + \#* # optional closing #'s (not counted) + $/x + def block_markdown_atx( text ) + if text =~ ATX_RE + tag = "h#{ $1.length }" + blk, cont = "<#{ tag }>#{ $2 }\n\n", $' + blocks cont + text.replace( blk + cont ) + end + end + + MARKDOWN_BQ_RE = /\A(^ *> ?.+$(.+\n)*\n*)+/m + + def block_markdown_bq( text ) + text.gsub!( MARKDOWN_BQ_RE ) do |blk| + blk.gsub!( /^ *> ?/, '' ) + flush_left blk + blocks blk + blk.gsub!( /^(\S)/, "\t\\1" ) + "
      \n#{ blk }\n
      \n\n" + end + end + + MARKDOWN_RULE_RE = /^(#{ + ['*', '-', '_'].collect { |ch| ' ?(' + Regexp::quote( ch ) + ' ?){3,}' }.join( '|' ) + })$/ + + def block_markdown_rule( text ) + text.gsub!( MARKDOWN_RULE_RE ) do |blk| + "
      " + end + end + + # XXX TODO XXX + def block_markdown_lists( text ) + end + + def inline_textile_span( text ) + QTAGS.each do |qtag_rc, ht, qtag_re, rtype| + text.gsub!( qtag_re ) do |m| + + case rtype + when :limit + sta,oqs,qtag,content,oqa = $~[1..6] + atts = nil + if content =~ /^(#{C})(.+)$/ + atts, content = $~[1..2] + end + else + qtag,atts,cite,content = $~[1..4] + sta = '' + end + atts = pba( atts ) + atts = shelve( atts ) if atts + + "#{ sta }#{ oqs }<#{ ht }#{ atts }>#{ content }#{ oqa }" + + end + end + end + + LINK_RE = / + ( + ([\s\[{(]|[#{PUNCT}])? # $pre + " # start + (#{C}) # $atts + ([^"\n]+?) # $text + \s? + (?:\(([^)]+?)\)(?="))? # $title + ": + ( # $url + (\/|[a-zA-Z]+:\/\/|www\.|mailto:) # $proto + [[:alnum:]_\/]\S+? + ) + (\/)? # $slash + ([^[:alnum:]_\=\/;\(\)]*?) # $post + ) + (?=<|\s|$) + /x +#" + def inline_textile_link( text ) + text.gsub!( LINK_RE ) do |m| + all,pre,atts,text,title,url,proto,slash,post = $~[1..9] + if text.include?('
      ') + all + else + url, url_title = check_refs( url ) + title ||= url_title + + # Idea below : an URL with unbalanced parethesis and + # ending by ')' is put into external parenthesis + if ( url[-1]==?) and ((url.count("(") - url.count(")")) < 0 ) ) + url=url[0..-2] # discard closing parenth from url + post = ")"+post # add closing parenth to post + end + atts = pba( atts ) + atts = " href=\"#{ htmlesc url }#{ slash }\"#{ atts }" + atts << " title=\"#{ htmlesc title }\"" if title + atts = shelve( atts ) if atts + + external = (url =~ /^https?:\/\//) ? ' class="external"' : '' + + "#{ pre }#{ text }#{ post }" + end + end + end + + MARKDOWN_REFLINK_RE = / + \[([^\[\]]+)\] # $text + [ ]? # opt. space + (?:\n[ ]*)? # one optional newline followed by spaces + \[(.*?)\] # $id + /x + + def inline_markdown_reflink( text ) + text.gsub!( MARKDOWN_REFLINK_RE ) do |m| + text, id = $~[1..2] + + if id.empty? + url, title = check_refs( text ) + else + url, title = check_refs( id ) + end + + atts = " href=\"#{ url }\"" + atts << " title=\"#{ title }\"" if title + atts = shelve( atts ) + + "#{ text }" + end + end + + MARKDOWN_LINK_RE = / + \[([^\[\]]+)\] # $text + \( # open paren + [ \t]* # opt space + ? # $href + [ \t]* # opt space + (?: # whole title + (['"]) # $quote + (.*?) # $title + \3 # matching quote + )? # title is optional + \) + /x + + def inline_markdown_link( text ) + text.gsub!( MARKDOWN_LINK_RE ) do |m| + text, url, quote, title = $~[1..4] + + atts = " href=\"#{ url }\"" + atts << " title=\"#{ title }\"" if title + atts = shelve( atts ) + + "#{ text }" + end + end + + TEXTILE_REFS_RE = /(^ *)\[([^\[\n]+?)\](#{HYPERLINK})(?=\s|$)/ + MARKDOWN_REFS_RE = /(^ *)\[([^\n]+?)\]:\s+?(?:\s+"((?:[^"]|\\")+)")?(?=\s|$)/m + + def refs( text ) + @rules.each do |rule_name| + method( rule_name ).call( text ) if rule_name.to_s.match /^refs_/ + end + end + + def refs_textile( text ) + text.gsub!( TEXTILE_REFS_RE ) do |m| + flag, url = $~[2..3] + @urlrefs[flag.downcase] = [url, nil] + nil + end + end + + def refs_markdown( text ) + text.gsub!( MARKDOWN_REFS_RE ) do |m| + flag, url = $~[2..3] + title = $~[6] + @urlrefs[flag.downcase] = [url, title] + nil + end + end + + def check_refs( text ) + ret = @urlrefs[text.downcase] if text + ret || [text, nil] + end + + IMAGE_RE = / + (>|\s|^) # start of line? + \! # opening + (\<|\=|\>)? # optional alignment atts + (#{C}) # optional style,class atts + (?:\. )? # optional dot-space + ([^\s(!]+?) # presume this is the src + \s? # optional space + (?:\(((?:[^\(\)]|\([^\)]+\))+?)\))? # optional title + \! # closing + (?::#{ HYPERLINK })? # optional href + /x + + def inline_textile_image( text ) + text.gsub!( IMAGE_RE ) do |m| + stln,algn,atts,url,title,href,href_a1,href_a2 = $~[1..8] + htmlesc title + atts = pba( atts ) + atts = " src=\"#{ htmlesc url.dup }\"#{ atts }" + atts << " title=\"#{ title }\"" if title + atts << " alt=\"#{ title }\"" + # size = @getimagesize($url); + # if($size) $atts.= " $size[3]"; + + href, alt_title = check_refs( href ) if href + url, url_title = check_refs( url ) + + out = '' + out << "" if href + out << "" + out << "#{ href_a1 }#{ href_a2 }" if href + + if algn + algn = h_align( algn ) + if stln == "

      " + out = "

      #{ out }" + else + out = "#{ stln }

      #{ out }
      " + end + else + out = stln + out + end + + out + end + end + + def shelve( val ) + @shelf << val + " :redsh##{ @shelf.length }:" + end + + def retrieve( text ) + @shelf.each_with_index do |r, i| + text.gsub!( " :redsh##{ i + 1 }:", r ) + end + end + + def incoming_entities( text ) + ## turn any incoming ampersands into a dummy character for now. + ## This uses a negative lookahead for alphanumerics followed by a semicolon, + ## implying an incoming html entity, to be skipped + + text.gsub!( /&(?![#a-z0-9]+;)/i, "x%x%" ) + end + + def no_textile( text ) + text.gsub!( /(^|\s)==([^=]+.*?)==(\s|$)?/, + '\1\2\3' ) + text.gsub!( /^ *==([^=]+.*?)==/m, + '\1\2\3' ) + end + + def clean_white_space( text ) + # normalize line breaks + text.gsub!( /\r\n/, "\n" ) + text.gsub!( /\r/, "\n" ) + text.gsub!( /\t/, ' ' ) + text.gsub!( /^ +$/, '' ) + text.gsub!( /\n{3,}/, "\n\n" ) + text.gsub!( /"$/, "\" " ) + + # if entire document is indented, flush + # to the left side + flush_left text + end + + def flush_left( text ) + indt = 0 + if text =~ /^ / + while text !~ /^ {#{indt}}\S/ + indt += 1 + end unless text.empty? + if indt.nonzero? + text.gsub!( /^ {#{indt}}/, '' ) + end + end + end + + def footnote_ref( text ) + text.gsub!( /\b\[([0-9]+?)\](\s)?/, + '\1\2' ) + end + + OFFTAGS = /(code|pre|kbd|notextile)/ + OFFTAG_MATCH = /(?:(<\/#{ OFFTAGS }>)|(<#{ OFFTAGS }[^>]*>))(.*?)(?=<\/?#{ OFFTAGS }\W|\Z)/mi + OFFTAG_OPEN = /<#{ OFFTAGS }/ + OFFTAG_CLOSE = /<\/?#{ OFFTAGS }/ + HASTAG_MATCH = /(<\/?\w[^\n]*?>)/m + ALLTAG_MATCH = /(<\/?\w[^\n]*?>)|.*?(?=<\/?\w[^\n]*?>|$)/m + + def glyphs_textile( text, level = 0 ) + if text !~ HASTAG_MATCH + pgl text + footnote_ref text + else + codepre = 0 + text.gsub!( ALLTAG_MATCH ) do |line| + ## matches are off if we're between ,
       etc.
      +                if $1
      +                    if line =~ OFFTAG_OPEN
      +                        codepre += 1
      +                    elsif line =~ OFFTAG_CLOSE
      +                        codepre -= 1
      +                        codepre = 0 if codepre < 0
      +                    end 
      +                elsif codepre.zero?
      +                    glyphs_textile( line, level + 1 )
      +                else
      +                    htmlesc( line, :NoQuotes )
      +                end
      +                # p [level, codepre, line]
      +
      +                line
      +            end
      +        end
      +    end
      +
      +    def rip_offtags( text, escape_aftertag=true, escape_line=true )
      +        if text =~ /<.*>/
      +            ## strip and encode 
       content
      +            codepre, used_offtags = 0, {}
      +            text.gsub!( OFFTAG_MATCH ) do |line|
      +                if $3
      +                    first, offtag, aftertag = $3, $4, $5
      +                    codepre += 1
      +                    used_offtags[offtag] = true
      +                    if codepre - used_offtags.length > 0
      +                        htmlesc( line, :NoQuotes ) if escape_line
      +                        @pre_list.last << line
      +                        line = ""
      +                    else
      +                        ### htmlesc is disabled between CODE tags which will be parsed with highlighter
      +                        ### Regexp in formatter.rb is : /\s?(.+)/m
      +                        ### NB: some changes were made not to use $N variables, because we use "match"
      +                        ###   and it breaks following lines
      +                        htmlesc( aftertag, :NoQuotes ) if aftertag && escape_aftertag && !first.match(//)
      +                        line = ""
      +                        first.match(/<#{ OFFTAGS }([^>]*)>/)
      +                        tag = $1
      +                        $2.to_s.match(/(class\=("[^"]+"|'[^']+'))/i)
      +                        tag << " #{$1}" if $1
      +                        @pre_list << "<#{ tag }>#{ aftertag }"
      +                    end
      +                elsif $1 and codepre > 0
      +                    if codepre - used_offtags.length > 0
      +                        htmlesc( line, :NoQuotes ) if escape_line
      +                        @pre_list.last << line
      +                        line = ""
      +                    end
      +                    codepre -= 1 unless codepre.zero?
      +                    used_offtags = {} if codepre.zero?
      +                end 
      +                line
      +            end
      +        end
      +        text
      +    end
      +
      +    def smooth_offtags( text )
      +        unless @pre_list.empty?
      +            ## replace 
       content
      +            text.gsub!( // ) { @pre_list[$1.to_i] }
      +        end
      +    end
      +
      +    def inline( text ) 
      +        [/^inline_/, /^glyphs_/].each do |meth_re|
      +            @rules.each do |rule_name|
      +                method( rule_name ).call( text ) if rule_name.to_s.match( meth_re )
      +            end
      +        end
      +    end
      +
      +    def h_align( text ) 
      +        H_ALGN_VALS[text]
      +    end
      +
      +    def v_align( text ) 
      +        V_ALGN_VALS[text]
      +    end
      +
      +    def textile_popup_help( name, windowW, windowH )
      +        ' ' + name + '
      ' + end + + # HTML cleansing stuff + BASIC_TAGS = { + 'a' => ['href', 'title'], + 'img' => ['src', 'alt', 'title'], + 'br' => [], + 'i' => nil, + 'u' => nil, + 'b' => nil, + 'pre' => nil, + 'kbd' => nil, + 'code' => ['lang'], + 'cite' => nil, + 'strong' => nil, + 'em' => nil, + 'ins' => nil, + 'sup' => nil, + 'sub' => nil, + 'del' => nil, + 'table' => nil, + 'tr' => nil, + 'td' => ['colspan', 'rowspan'], + 'th' => nil, + 'ol' => nil, + 'ul' => nil, + 'li' => nil, + 'p' => nil, + 'h1' => nil, + 'h3' => nil, + 'h3' => nil, + 'h4' => nil, + 'h5' => nil, + 'h6' => nil, + 'blockquote' => ['cite'] + } + + def clean_html( text, tags = BASIC_TAGS ) + text.gsub!( /]*)>/ ) do + raw = $~ + tag = raw[2].downcase + if tags.has_key? tag + pcs = [tag] + tags[tag].each do |prop| + ['"', "'", ''].each do |q| + q2 = ( q != '' ? q : '\s' ) + if raw[3] =~ /#{prop}\s*=\s*#{q}([^#{q2}]+)#{q}/i + attrv = $1 + next if prop == 'src' and attrv =~ %r{^(?!http)\w+:} + pcs << "#{prop}=\"#{$1.gsub('"', '\\"')}\"" + break + end + end + end if tags[tag] + "<#{raw[1]}#{pcs.join " "}>" + else + " " + end + end + end + + ALLOWED_TAGS = %w(redpre pre code notextile) + + def escape_html_tags(text) + text.gsub!(%r{<(\/?([!\w]+)[^<>\n]*)(>?)}) {|m| ALLOWED_TAGS.include?($2) ? "<#{$1}#{$3}" : "<#{$1}#{'>' unless $3.blank?}" } + end +end + diff --git a/lib/redmine.rb b/lib/redmine.rb new file mode 100644 index 00000000..a2a9ba40 --- /dev/null +++ b/lib/redmine.rb @@ -0,0 +1,300 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +require 'redmine/core_ext' + +begin + require 'RMagick' unless Object.const_defined?(:Magick) +rescue LoadError + # RMagick is not available +end + +require 'redmine/scm/base' +require 'redmine/access_control' +require 'redmine/access_keys' +require 'redmine/activity' +require 'redmine/activity/fetcher' +require 'redmine/ciphering' +require 'redmine/codeset_util' +require 'redmine/custom_field_format' +require 'redmine/i18n' +require 'redmine/menu_manager' +require 'redmine/notifiable' +require 'redmine/platform' +require 'redmine/mime_type' +require 'redmine/notifiable' +require 'redmine/search' +require 'redmine/syntax_highlighting' +require 'redmine/thumbnail' +require 'redmine/unified_diff' +require 'redmine/utils' +require 'redmine/version' +require 'redmine/wiki_formatting' + +require 'redmine/default_data/loader' +require 'redmine/helpers/calendar' +require 'redmine/helpers/diff' +require 'redmine/helpers/gantt' +require 'redmine/helpers/time_report' +require 'redmine/views/other_formats_builder' +require 'redmine/views/labelled_form_builder' +require 'redmine/views/builders' + +require 'redmine/themes' +require 'redmine/hook' +require 'redmine/plugin' + +if RUBY_VERSION < '1.9' + require 'fastercsv' +else + require 'csv' + FCSV = CSV +end + +Redmine::Scm::Base.add "Subversion" +Redmine::Scm::Base.add "Darcs" +Redmine::Scm::Base.add "Mercurial" +Redmine::Scm::Base.add "Cvs" +Redmine::Scm::Base.add "Bazaar" +Redmine::Scm::Base.add "Git" +Redmine::Scm::Base.add "Filesystem" + +Redmine::CustomFieldFormat.map do |fields| + fields.register 'string' + fields.register 'text' + fields.register 'int', :label => :label_integer + fields.register 'float' + fields.register 'list' + fields.register 'date' + fields.register 'bool', :label => :label_boolean + fields.register 'user', :only => %w(Issue TimeEntry Version Project), :edit_as => 'list' + fields.register 'version', :only => %w(Issue TimeEntry Version Project), :edit_as => 'list' +end + +# Permissions +Redmine::AccessControl.map do |map| + map.permission :view_project, {:projects => [:show], :activities => [:index]}, :public => true, :read => true + map.permission :search_project, {:search => :index}, :public => true, :read => true + map.permission :add_project, {:projects => [:new, :create]}, :require => :loggedin + map.permission :edit_project, {:projects => [:settings, :edit, :update]}, :require => :member + map.permission :close_project, {:projects => [:close, :reopen]}, :require => :member, :read => true + map.permission :select_project_modules, {:projects => :modules}, :require => :member + map.permission :manage_members, {:projects => :settings, :members => [:index, :show, :create, :update, :destroy, :autocomplete]}, :require => :member + map.permission :manage_versions, {:projects => :settings, :versions => [:new, :create, :edit, :update, :close_completed, :destroy]}, :require => :member + map.permission :add_subprojects, {:projects => [:new, :create]}, :require => :member + + map.project_module :issue_tracking do |map| + # Issue categories + map.permission :manage_categories, {:projects => :settings, :issue_categories => [:index, :show, :new, :create, :edit, :update, :destroy]}, :require => :member + # Issues + map.permission :view_issues, {:issues => [:index, :show], + :auto_complete => [:issues], + :context_menus => [:issues], + :versions => [:index, :show, :status_by], + :journals => [:index, :diff], + :queries => :index, + :reports => [:issue_report, :issue_report_details]}, + :read => true + map.permission :add_issues, {:issues => [:new, :create, :update_form], :attachments => :upload} + map.permission :edit_issues, {:issues => [:edit, :update, :bulk_edit, :bulk_update, :update_form], :journals => [:new], :attachments => :upload} + map.permission :manage_issue_relations, {:issue_relations => [:index, :show, :create, :destroy]} + map.permission :manage_subtasks, {} + map.permission :set_issues_private, {} + map.permission :set_own_issues_private, {}, :require => :loggedin + map.permission :add_issue_notes, {:issues => [:edit, :update, :update_form], :journals => [:new], :attachments => :upload} + map.permission :edit_issue_notes, {:journals => :edit}, :require => :loggedin + map.permission :edit_own_issue_notes, {:journals => :edit}, :require => :loggedin + map.permission :view_private_notes, {}, :read => true, :require => :member + map.permission :set_notes_private, {}, :require => :member + map.permission :move_issues, {:issues => [:bulk_edit, :bulk_update]}, :require => :loggedin + map.permission :delete_issues, {:issues => :destroy}, :require => :member + # Queries + map.permission :manage_public_queries, {:queries => [:new, :create, :edit, :update, :destroy]}, :require => :member + map.permission :save_queries, {:queries => [:new, :create, :edit, :update, :destroy]}, :require => :loggedin + # Watchers + map.permission :view_issue_watchers, {}, :read => true + map.permission :add_issue_watchers, {:watchers => [:new, :create, :append, :autocomplete_for_user]} + map.permission :delete_issue_watchers, {:watchers => :destroy} + end + + map.project_module :time_tracking do |map| + map.permission :log_time, {:timelog => [:new, :create]}, :require => :loggedin + map.permission :view_time_entries, {:timelog => [:index, :report, :show]}, :read => true + map.permission :edit_time_entries, {:timelog => [:edit, :update, :destroy, :bulk_edit, :bulk_update]}, :require => :member + map.permission :edit_own_time_entries, {:timelog => [:edit, :update, :destroy,:bulk_edit, :bulk_update]}, :require => :loggedin + map.permission :manage_project_activities, {:project_enumerations => [:update, :destroy]}, :require => :member + end + + map.project_module :news do |map| + map.permission :manage_news, {:news => [:new, :create, :edit, :update, :destroy], :comments => [:destroy]}, :require => :member + map.permission :view_news, {:news => [:index, :show]}, :public => true, :read => true + map.permission :comment_news, {:comments => :create} + end + + map.project_module :documents do |map| + map.permission :add_documents, {:documents => [:new, :create, :add_attachment]}, :require => :loggedin + map.permission :edit_documents, {:documents => [:edit, :update, :add_attachment]}, :require => :loggedin + map.permission :delete_documents, {:documents => [:destroy]}, :require => :loggedin + map.permission :view_documents, {:documents => [:index, :show, :download]}, :read => true + end + + map.project_module :files do |map| + map.permission :manage_files, {:files => [:new, :create]}, :require => :loggedin + map.permission :view_files, {:files => :index, :versions => :download}, :read => true + end + + map.project_module :wiki do |map| + map.permission :manage_wiki, {:wikis => [:edit, :destroy]}, :require => :member + map.permission :rename_wiki_pages, {:wiki => :rename}, :require => :member + map.permission :delete_wiki_pages, {:wiki => [:destroy, :destroy_version]}, :require => :member + map.permission :view_wiki_pages, {:wiki => [:index, :show, :special, :date_index]}, :read => true + map.permission :export_wiki_pages, {:wiki => [:export]}, :read => true + map.permission :view_wiki_edits, {:wiki => [:history, :diff, :annotate]}, :read => true + map.permission :edit_wiki_pages, :wiki => [:edit, :update, :preview, :add_attachment] + map.permission :delete_wiki_pages_attachments, {} + map.permission :protect_wiki_pages, {:wiki => :protect}, :require => :member + end + + map.project_module :repository do |map| + map.permission :manage_repository, {:repositories => [:new, :create, :edit, :update, :committers, :destroy]}, :require => :member + map.permission :browse_repository, {:repositories => [:show, :browse, :entry, :raw, :annotate, :changes, :diff, :stats, :graph]}, :read => true + map.permission :view_changesets, {:repositories => [:show, :revisions, :revision]}, :read => true + map.permission :commit_access, {} + map.permission :manage_related_issues, {:repositories => [:add_related_issue, :remove_related_issue]} + end + + map.project_module :boards do |map| + map.permission :manage_boards, {:boards => [:new, :create, :edit, :update, :destroy]}, :require => :member + map.permission :view_messages, {:boards => [:index, :show], :messages => [:show]}, :public => true, :read => true + map.permission :add_messages, {:messages => [:new, :reply, :quote]} + map.permission :edit_messages, {:messages => :edit}, :require => :member + map.permission :edit_own_messages, {:messages => :edit}, :require => :loggedin + map.permission :delete_messages, {:messages => :destroy}, :require => :member + map.permission :delete_own_messages, {:messages => :destroy}, :require => :loggedin + end + + map.project_module :calendar do |map| + map.permission :view_calendar, {:calendars => [:show, :update]}, :read => true + end + + map.project_module :gantt do |map| + map.permission :view_gantt, {:gantts => [:show, :update]}, :read => true + end +end +#by young +Redmine::MenuManager.map :top_menu do |menu| + menu.push :home, :home_path + menu.push :projects, { :controller => 'projects', :action => 'index' }, :caption => :label_project_plural + menu.push :requirement, {:controller => 'bids', :action => 'index'} + menu.push :developer, {:controller => 'users', :action => 'index'} + menu.push :investor, :home_path + menu.push :theme, :home_path +# menu.push :my_page, { :controller => 'my', :action => 'page' }, :if => Proc.new { User.current.logged? } +# menu.push :administration, { :controller => 'admin', :action => 'index' }, :if => Proc.new { User.current.admin? }, :last => true +# menu.push :help, Redmine::Info.help_url, :last => true +end +#end +Redmine::MenuManager.map :account_menu do |menu| + menu.push :login, :signin_path, :if => Proc.new { !User.current.logged? } + menu.push :register, :register_path, :if => Proc.new { !User.current.logged? && Setting.self_registration? } + menu.push :my_account, { :controller => 'my', :action => 'account' }, :if => Proc.new { User.current.logged? } + menu.push :logout, :signout_path, :html => {:method => 'post'}, :if => Proc.new { User.current.logged? } +end +########fq +Redmine::MenuManager.map :bid_menu do |menu| + menu.push :respond, { :controller => 'bids', :action => 'show' }, :caption => :label_user_response + menu.push :project, { :controller => 'bids', :action => 'show_project' }, :caption => :label_bidding_project +end +Redmine::MenuManager.map :application_menu do |menu| + # Empty +end + +Redmine::MenuManager.map :admin_menu do |menu| + menu.push :projects, {:controller => 'admin', :action => 'projects'}, :caption => :label_project_plural + menu.push :users, {:controller => 'users'}, :caption => :label_user_plural + menu.push :groups, {:controller => 'groups'}, :caption => :label_group_plural + menu.push :roles, {:controller => 'roles'}, :caption => :label_role_and_permissions + menu.push :trackers, {:controller => 'trackers'}, :caption => :label_tracker_plural + menu.push :issue_statuses, {:controller => 'issue_statuses'}, :caption => :label_issue_status_plural, + :html => {:class => 'issue_statuses'} + menu.push :workflows, {:controller => 'workflows', :action => 'edit'}, :caption => :label_workflow + menu.push :custom_fields, {:controller => 'custom_fields'}, :caption => :label_custom_field_plural, + :html => {:class => 'custom_fields'} + menu.push :enumerations, {:controller => 'enumerations'} + menu.push :settings, {:controller => 'settings'} + menu.push :ldap_authentication, {:controller => 'auth_sources', :action => 'index'}, + :html => {:class => 'server_authentication'} + menu.push :plugins, {:controller => 'admin', :action => 'plugins'}, :last => true + menu.push :info, {:controller => 'admin', :action => 'info'}, :caption => :label_information_plural, :last => true +end + +Redmine::MenuManager.map :project_menu do |menu| + menu.push :overview, { :controller => 'projects', :action => 'show' } +# menu.push :activity, { :controller => 'activities', :action => 'index' } +# menu.push :roadmap, { :controller => 'versions', :action => 'index' }, :param => :project_id, +# :if => Proc.new { |p| p.shared_versions.any? } + menu.push :issues, { :controller => 'issues', :action => 'index' }, :param => :project_id, :caption => :label_issue_plural +# menu.push :new_issue, { :controller => 'issues', :action => 'new', :copy_from => nil }, :param => :project_id, :caption => :label_issue_new, +# :html => { :accesskey => Redmine::AccessKeys.key_for(:new_issue) } +# menu.push :gantt, { :controller => 'gantts', :action => 'show' }, :param => :project_id, :caption => :label_gantt +# menu.push :calendar, { :controller => 'calendars', :action => 'show' }, :param => :project_id, :caption => :label_calendar + menu.push :news, { :controller => 'news', :action => 'index' }, :param => :project_id, :caption => :label_news_plural +# menu.push :documents, { :controller => 'documents', :action => 'index' }, :param => :project_id, :caption => :label_document_plural +# menu.push :wiki, { :controller => 'wiki', :action => 'show', :id => nil }, :param => :project_id, +# :if => Proc.new { |p| p.wiki && !p.wiki.new_record? } +# menu.push :boards, { :controller => 'boards', :action => 'index', :id => nil }, :param => :project_id, +# :if => Proc.new { |p| p.boards.any? }, :caption => :label_board_plural +# menu.push :files, { :controller => 'files', :action => 'index' }, :caption => :label_file_plural, :param => :project_id + menu.push :repository, { :controller => 'repositories', :action => 'show', :repository_id => nil, :path => nil, :rev => nil }, + :if => Proc.new { |p| p.repository && !p.repository.new_record? } + menu.push :settings, { :controller => 'projects', :action => 'settings' }, :last => true +end +#added by young +Redmine::MenuManager.map :user_menu do |menu| + menu.push :activity, {:controller => 'users', :action => 'show' } + menu.push :project, {:controller => 'users', :action => 'user_projects'} + menu.push :requirement_focus, {} + menu.push :user_newfeedback, {:controller => 'users', :action => 'user_newfeedback'} +end +#end + +Redmine::Activity.map do |activity| + activity.register :issues, :class_name => %w(Issue Journal) + activity.register :changesets + activity.register :news + activity.register :documents, :class_name => %w(Document Attachment) + activity.register :files, :class_name => 'Attachment' + activity.register :wiki_edits, :class_name => 'WikiContent::Version', :default => false + activity.register :messages, :default => false + activity.register :time_entries, :default => false +end + +Redmine::Search.map do |search| + search.register :issues + search.register :news + search.register :documents + search.register :changesets + search.register :wiki_pages + search.register :messages + search.register :projects +end + +Redmine::WikiFormatting.map do |format| + format.register :textile, Redmine::WikiFormatting::Textile::Formatter, Redmine::WikiFormatting::Textile::Helper +end + +ActionView::Template.register_template_handler :rsb, Redmine::Views::ApiTemplateHandler diff --git a/lib/redmine/access_control.rb b/lib/redmine/access_control.rb new file mode 100644 index 00000000..7c4a5a5e --- /dev/null +++ b/lib/redmine/access_control.rb @@ -0,0 +1,135 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +module Redmine + module AccessControl + + class << self + def map + mapper = Mapper.new + yield mapper + @permissions ||= [] + @permissions += mapper.mapped_permissions + end + + def permissions + @permissions + end + + # Returns the permission of given name or nil if it wasn't found + # Argument should be a symbol + def permission(name) + permissions.detect {|p| p.name == name} + end + + # Returns the actions that are allowed by the permission of given name + def allowed_actions(permission_name) + perm = permission(permission_name) + perm ? perm.actions : [] + end + + def public_permissions + @public_permissions ||= @permissions.select {|p| p.public?} + end + + def members_only_permissions + @members_only_permissions ||= @permissions.select {|p| p.require_member?} + end + + def loggedin_only_permissions + @loggedin_only_permissions ||= @permissions.select {|p| p.require_loggedin?} + end + + def read_action?(action) + if action.is_a?(Symbol) + perm = permission(action) + !perm.nil? && perm.read? + else + s = "#{action[:controller]}/#{action[:action]}" + permissions.detect {|p| p.actions.include?(s) && !p.read?}.nil? + end + end + + def available_project_modules + @available_project_modules ||= @permissions.collect(&:project_module).uniq.compact + end + + def modules_permissions(modules) + @permissions.select {|p| p.project_module.nil? || modules.include?(p.project_module.to_s)} + end + end + + class Mapper + def initialize + @project_module = nil + end + + def permission(name, hash, options={}) + @permissions ||= [] + options.merge!(:project_module => @project_module) + @permissions << Permission.new(name, hash, options) + end + + def project_module(name, options={}) + @project_module = name + yield self + @project_module = nil + end + + def mapped_permissions + @permissions + end + end + + class Permission + attr_reader :name, :actions, :project_module + + def initialize(name, hash, options) + @name = name + @actions = [] + @public = options[:public] || false + @require = options[:require] + @read = options[:read] || false + @project_module = options[:project_module] + hash.each do |controller, actions| + if actions.is_a? Array + @actions << actions.collect {|action| "#{controller}/#{action}"} + else + @actions << "#{controller}/#{actions}" + end + end + @actions.flatten! + end + + def public? + @public + end + + def require_member? + @require && @require == :member + end + + def require_loggedin? + @require && (@require == :member || @require == :loggedin) + end + + def read? + @read + end + end + end +end diff --git a/lib/redmine/access_keys.rb b/lib/redmine/access_keys.rb new file mode 100644 index 00000000..c2f6157d --- /dev/null +++ b/lib/redmine/access_keys.rb @@ -0,0 +1,31 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +module Redmine + module AccessKeys + ACCESSKEYS = {:edit => 'e', + :preview => 'r', + :quick_search => 'f', + :search => '4', + :new_issue => '7' + }.freeze unless const_defined?(:ACCESSKEYS) + + def self.key_for(action) + ACCESSKEYS[action] + end + end +end diff --git a/lib/redmine/activity.rb b/lib/redmine/activity.rb new file mode 100644 index 00000000..27ff52eb --- /dev/null +++ b/lib/redmine/activity.rb @@ -0,0 +1,46 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +module Redmine + module Activity + + mattr_accessor :available_event_types, :default_event_types, :providers + + @@available_event_types = [] + @@default_event_types = [] + @@providers = Hash.new {|h,k| h[k]=[] } + + class << self + def map(&block) + yield self + end + + # Registers an activity provider + def register(event_type, options={}) + options.assert_valid_keys(:class_name, :default) + + event_type = event_type.to_s + providers = options[:class_name] || event_type.classify + providers = ([] << providers) unless providers.is_a?(Array) + + @@available_event_types << event_type unless @@available_event_types.include?(event_type) + @@default_event_types << event_type unless options[:default] == false + @@providers[event_type] += providers + end + end + end +end diff --git a/lib/redmine/activity/fetcher.rb b/lib/redmine/activity/fetcher.rb new file mode 100644 index 00000000..9ce12e0d --- /dev/null +++ b/lib/redmine/activity/fetcher.rb @@ -0,0 +1,95 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +module Redmine + module Activity + # Class used to retrieve activity events + class Fetcher + attr_reader :user, :project, :scope + + # Needs to be unloaded in development mode + @@constantized_providers = Hash.new {|h,k| h[k] = Redmine::Activity.providers[k].collect {|t| t.constantize } } + + def initialize(user, options={}) + options.assert_valid_keys(:project, :with_subprojects, :author) + @user = user + @project = options[:project] + @options = options + + @scope = event_types + end + + # Returns an array of available event types + def event_types + return @event_types unless @event_types.nil? + + @event_types = Redmine::Activity.available_event_types + @event_types = @event_types.select {|o| @project.self_and_descendants.detect {|p| @user.allowed_to?("view_#{o}".to_sym, p)}} if @project + @event_types + end + + # Yields to filter the activity scope + def scope_select(&block) + @scope = @scope.select {|t| yield t } + end + + # Sets the scope + # Argument can be :all, :default or an array of event types + def scope=(s) + case s + when :all + @scope = event_types + when :default + default_scope! + else + @scope = s & event_types + end + end + + # Resets the scope to the default scope + def default_scope! + @scope = Redmine::Activity.default_event_types + end + + # Returns an array of events for the given date range + # sorted in reverse chronological order + def events(from = nil, to = nil, options={}) + e = [] + @options[:limit] = options[:limit] + + @scope.each do |event_type| + constantized_providers(event_type).each do |provider| + e += provider.find_events(event_type, @user, from, to, @options) + end + end + + e.sort! {|a,b| b.event_datetime <=> a.event_datetime} + + if options[:limit] + e = e.slice(0, options[:limit]) + end + e + end + + private + + def constantized_providers(event_type) + @@constantized_providers[event_type] + end + end + end +end diff --git a/lib/redmine/ciphering.rb b/lib/redmine/ciphering.rb new file mode 100644 index 00000000..c691e23e --- /dev/null +++ b/lib/redmine/ciphering.rb @@ -0,0 +1,103 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +module Redmine + module Ciphering + def self.included(base) + base.extend ClassMethods + end + + class << self + def encrypt_text(text) + if cipher_key.blank? || text.blank? + text + else + c = OpenSSL::Cipher::Cipher.new("aes-256-cbc") + iv = c.random_iv + c.encrypt + c.key = cipher_key + c.iv = iv + e = c.update(text.to_s) + e << c.final + "aes-256-cbc:" + [e, iv].map {|v| Base64.encode64(v).strip}.join('--') + end + end + + def decrypt_text(text) + if text && match = text.match(/\Aaes-256-cbc:(.+)\Z/) + if cipher_key.blank? + logger.error "Attempt to decrypt a ciphered text with no cipher key configured in config/configuration.yml" if logger + return text + end + text = match[1] + c = OpenSSL::Cipher::Cipher.new("aes-256-cbc") + e, iv = text.split("--").map {|s| Base64.decode64(s)} + c.decrypt + c.key = cipher_key + c.iv = iv + d = c.update(e) + d << c.final + else + text + end + end + + def cipher_key + key = Redmine::Configuration['database_cipher_key'].to_s + key.blank? ? nil : Digest::SHA256.hexdigest(key) + end + + def logger + Rails.logger + end + end + + module ClassMethods + def encrypt_all(attribute) + transaction do + all.each do |object| + clear = object.send(attribute) + object.send "#{attribute}=", clear + raise(ActiveRecord::Rollback) unless object.save(:validation => false) + end + end ? true : false + end + + def decrypt_all(attribute) + transaction do + all.each do |object| + clear = object.send(attribute) + object.send :write_attribute, attribute, clear + raise(ActiveRecord::Rollback) unless object.save(:validation => false) + end + end + end ? true : false + end + + private + + # Returns the value of the given ciphered attribute + def read_ciphered_attribute(attribute) + Redmine::Ciphering.decrypt_text(read_attribute(attribute)) + end + + # Sets the value of the given ciphered attribute + def write_ciphered_attribute(attribute, value) + write_attribute(attribute, Redmine::Ciphering.encrypt_text(value)) + end + end +end diff --git a/lib/redmine/codeset_util.rb b/lib/redmine/codeset_util.rb new file mode 100644 index 00000000..45a5c352 --- /dev/null +++ b/lib/redmine/codeset_util.rb @@ -0,0 +1,161 @@ +if RUBY_VERSION < '1.9' + require 'iconv' +end + +module Redmine + module CodesetUtil + + def self.replace_invalid_utf8(str) + return str if str.nil? + if str.respond_to?(:force_encoding) + str.force_encoding('UTF-8') + if ! str.valid_encoding? + str = str.encode("US-ASCII", :invalid => :replace, + :undef => :replace, :replace => '?').encode("UTF-8") + end + elsif RUBY_PLATFORM == 'java' + begin + ic = Iconv.new('UTF-8', 'UTF-8') + str = ic.iconv(str) + rescue + str = str.gsub(%r{[^\r\n\t\x20-\x7e]}, '?') + end + else + ic = Iconv.new('UTF-8', 'UTF-8') + txtar = "" + begin + txtar += ic.iconv(str) + rescue Iconv::IllegalSequence + txtar += $!.success + str = '?' + $!.failed[1,$!.failed.length] + retry + rescue + txtar += $!.success + end + str = txtar + end + str + end + + def self.to_utf8(str, encoding) + return str if str.nil? + str.force_encoding("ASCII-8BIT") if str.respond_to?(:force_encoding) + if str.empty? + str.force_encoding("UTF-8") if str.respond_to?(:force_encoding) + return str + end + enc = encoding.blank? ? "UTF-8" : encoding + if str.respond_to?(:force_encoding) + if enc.upcase != "UTF-8" + str.force_encoding(enc) + str = str.encode("UTF-8", :invalid => :replace, + :undef => :replace, :replace => '?') + else + str.force_encoding("UTF-8") + if ! str.valid_encoding? + str = str.encode("US-ASCII", :invalid => :replace, + :undef => :replace, :replace => '?').encode("UTF-8") + end + end + elsif RUBY_PLATFORM == 'java' + begin + ic = Iconv.new('UTF-8', enc) + str = ic.iconv(str) + rescue + str = str.gsub(%r{[^\r\n\t\x20-\x7e]}, '?') + end + else + ic = Iconv.new('UTF-8', enc) + txtar = "" + begin + txtar += ic.iconv(str) + rescue Iconv::IllegalSequence + txtar += $!.success + str = '?' + $!.failed[1,$!.failed.length] + retry + rescue + txtar += $!.success + end + str = txtar + end + str + end + + def self.to_utf8_by_setting(str) + return str if str.nil? + str = self.to_utf8_by_setting_internal(str) + if str.respond_to?(:force_encoding) + str.force_encoding('UTF-8') + end + str + end + + def self.to_utf8_by_setting_internal(str) + return str if str.nil? + if str.respond_to?(:force_encoding) + str.force_encoding('ASCII-8BIT') + end + return str if str.empty? + return str if /\A[\r\n\t\x20-\x7e]*\Z/n.match(str) # for us-ascii + if str.respond_to?(:force_encoding) + str.force_encoding('UTF-8') + end + encodings = Setting.repositories_encodings.split(',').collect(&:strip) + encodings.each do |encoding| + if str.respond_to?(:force_encoding) + begin + str.force_encoding(encoding) + utf8 = str.encode('UTF-8') + return utf8 if utf8.valid_encoding? + rescue + # do nothing here and try the next encoding + end + else + begin + return Iconv.conv('UTF-8', encoding, str) + rescue Iconv::Failure + # do nothing here and try the next encoding + end + end + end + str = self.replace_invalid_utf8(str) + if str.respond_to?(:force_encoding) + str.force_encoding('UTF-8') + end + str + end + + def self.from_utf8(str, encoding) + str ||= '' + if str.respond_to?(:force_encoding) + str.force_encoding('UTF-8') + if encoding.upcase != 'UTF-8' + str = str.encode(encoding, :invalid => :replace, + :undef => :replace, :replace => '?') + else + str = self.replace_invalid_utf8(str) + end + elsif RUBY_PLATFORM == 'java' + begin + ic = Iconv.new(encoding, 'UTF-8') + str = ic.iconv(str) + rescue + str = str.gsub(%r{[^\r\n\t\x20-\x7e]}, '?') + end + else + ic = Iconv.new(encoding, 'UTF-8') + txtar = "" + begin + txtar += ic.iconv(str) + rescue Iconv::IllegalSequence + txtar += $!.success + str = '?' + $!.failed[1, $!.failed.length] + retry + rescue + txtar += $!.success + end + str = txtar + end + end + end +end diff --git a/lib/redmine/configuration.rb b/lib/redmine/configuration.rb new file mode 100644 index 00000000..6723b777 --- /dev/null +++ b/lib/redmine/configuration.rb @@ -0,0 +1,114 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +module Redmine + module Configuration + + # Configuration default values + @defaults = { + 'email_delivery' => nil, + 'max_concurrent_ajax_uploads' => 2 + } + + @config = nil + + class << self + # Loads the Redmine configuration file + # Valid options: + # * :file: the configuration file to load (default: config/configuration.yml) + # * :env: the environment to load the configuration for (default: Rails.env) + def load(options={}) + filename = options[:file] || File.join(Rails.root, 'config', 'configuration.yml') + env = options[:env] || Rails.env + + @config = @defaults.dup + + load_deprecated_email_configuration(env) + if File.file?(filename) + @config.merge!(load_from_yaml(filename, env)) + end + + # Compatibility mode for those who copy email.yml over configuration.yml + %w(delivery_method smtp_settings sendmail_settings).each do |key| + if value = @config.delete(key) + @config['email_delivery'] ||= {} + @config['email_delivery'][key] = value + end + end + + if @config['email_delivery'] + ActionMailer::Base.perform_deliveries = true + @config['email_delivery'].each do |k, v| + v.symbolize_keys! if v.respond_to?(:symbolize_keys!) + ActionMailer::Base.send("#{k}=", v) + end + end + + @config + end + + # Returns a configuration setting + def [](name) + load unless @config + @config[name] + end + + # Yields a block with the specified hash configuration settings + def with(settings) + settings.stringify_keys! + load unless @config + was = settings.keys.inject({}) {|h,v| h[v] = @config[v]; h} + @config.merge! settings + yield if block_given? + @config.merge! was + end + + private + + def load_from_yaml(filename, env) + yaml = nil + begin + yaml = YAML::load_file(filename) + rescue ArgumentError + $stderr.puts "Your Redmine configuration file located at #{filename} is not a valid YAML file and could not be loaded." + exit 1 + end + conf = {} + if yaml.is_a?(Hash) + if yaml['default'] + conf.merge!(yaml['default']) + end + if yaml[env] + conf.merge!(yaml[env]) + end + else + $stderr.puts "Your Redmine configuration file located at #{filename} is not a valid Redmine configuration file." + exit 1 + end + conf + end + + def load_deprecated_email_configuration(env) + deprecated_email_conf = File.join(Rails.root, 'config', 'email.yml') + if File.file?(deprecated_email_conf) + warn "Storing outgoing emails configuration in config/email.yml is deprecated. You should now store it in config/configuration.yml using the email_delivery setting." + @config.merge!({'email_delivery' => load_from_yaml(deprecated_email_conf, env)}) + end + end + end + end +end diff --git a/lib/redmine/core_ext.rb b/lib/redmine/core_ext.rb new file mode 100644 index 00000000..573313e7 --- /dev/null +++ b/lib/redmine/core_ext.rb @@ -0,0 +1 @@ +Dir[File.dirname(__FILE__) + "/core_ext/*.rb"].each { |file| require(file) } diff --git a/lib/redmine/core_ext/active_record.rb b/lib/redmine/core_ext/active_record.rb new file mode 100644 index 00000000..ad27a3f0 --- /dev/null +++ b/lib/redmine/core_ext/active_record.rb @@ -0,0 +1,52 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +module ActiveRecord + module FinderMethods + def find_ids(*args) + find_ids_with_associations + end + + private + + def find_ids_with_associations + join_dependency = construct_join_dependency_for_association_find + relation = construct_relation_for_association_find_ids(join_dependency) + rows = connection.select_all(relation, 'SQL', relation.bind_values) + rows.map {|row| row["id"].to_i} + rescue ThrowResult + [] + end + + def construct_relation_for_association_find_ids(join_dependency) + relation = except(:includes, :eager_load, :preload, :select).select("#{table_name}.id") + apply_join_dependency(relation, join_dependency) + end + end +end + +class DateValidator < ActiveModel::EachValidator + def validate_each(record, attribute, value) + before_type_cast = record.attributes_before_type_cast[attribute.to_s] + if before_type_cast.is_a?(String) && before_type_cast.present? + # TODO: #*_date_before_type_cast returns a Mysql::Time with ruby1.8+mysql gem + unless before_type_cast =~ /\A\d{4}-\d{2}-\d{2}( 00:00:00)?\z/ && value + record.errors.add attribute, :not_a_date + end + end + end +end diff --git a/lib/redmine/core_ext/date.rb b/lib/redmine/core_ext/date.rb new file mode 100644 index 00000000..9244b5d6 --- /dev/null +++ b/lib/redmine/core_ext/date.rb @@ -0,0 +1,5 @@ +require File.dirname(__FILE__) + '/date/calculations' + +class Date #:nodoc: + include Redmine::CoreExtensions::Date::Calculations +end diff --git a/lib/redmine/core_ext/date/calculations.rb b/lib/redmine/core_ext/date/calculations.rb new file mode 100644 index 00000000..0372e8ac --- /dev/null +++ b/lib/redmine/core_ext/date/calculations.rb @@ -0,0 +1,35 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +module Redmine #:nodoc: + module CoreExtensions #:nodoc: + module Date #:nodoc: + # Custom date calculations + module Calculations + # Returns difference with specified date in months + def months_ago(date = self.class.today) + (date.year - self.year)*12 + (date.month - self.month) + end + + # Returns difference with specified date in weeks + def weeks_ago(date = self.class.today) + (date.year - self.year)*52 + (date.cweek - self.cweek) + end + end + end + end +end diff --git a/lib/redmine/core_ext/string.rb b/lib/redmine/core_ext/string.rb new file mode 100644 index 00000000..c865284a --- /dev/null +++ b/lib/redmine/core_ext/string.rb @@ -0,0 +1,11 @@ +require File.dirname(__FILE__) + '/string/conversions' +require File.dirname(__FILE__) + '/string/inflections' + +class String #:nodoc: + include Redmine::CoreExtensions::String::Conversions + include Redmine::CoreExtensions::String::Inflections + + def is_binary_data? + ( self.count( "^ -~", "^\r\n" ).fdiv(self.size) > 0.3 || self.index( "\x00" ) ) unless empty? + end +end diff --git a/lib/redmine/core_ext/string/conversions.rb b/lib/redmine/core_ext/string/conversions.rb new file mode 100644 index 00000000..7fbc02ee --- /dev/null +++ b/lib/redmine/core_ext/string/conversions.rb @@ -0,0 +1,49 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +module Redmine #:nodoc: + module CoreExtensions #:nodoc: + module String #:nodoc: + # Custom string conversions + module Conversions + # Parses hours format and returns a float + def to_hours + s = self.dup + s.strip! + if s =~ %r{^(\d+([.,]\d+)?)h?$} + s = $1 + else + # 2:30 => 2.5 + s.gsub!(%r{^(\d+):(\d+)$}) { $1.to_i + $2.to_i / 60.0 } + # 2h30, 2h, 30m => 2.5, 2, 0.5 + s.gsub!(%r{^((\d+)\s*(h|hours?))?\s*((\d+)\s*(m|min)?)?$}i) { |m| ($1 || $4) ? ($2.to_i + $5.to_i / 60.0) : m[0] } + end + # 2,5 => 2.5 + s.gsub!(',', '.') + begin; Kernel.Float(s); rescue; nil; end + end + + # Object#to_a removed in ruby1.9 + if RUBY_VERSION > '1.9' + def to_a + [self.dup] + end + end + end + end + end +end diff --git a/lib/redmine/core_ext/string/inflections.rb b/lib/redmine/core_ext/string/inflections.rb new file mode 100644 index 00000000..ecbbe278 --- /dev/null +++ b/lib/redmine/core_ext/string/inflections.rb @@ -0,0 +1,29 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +module Redmine #:nodoc: + module CoreExtensions #:nodoc: + module String #:nodoc: + # Custom string inflections + module Inflections + def with_leading_slash + starts_with?('/') ? self : "/#{ self }" + end + end + end + end +end diff --git a/lib/redmine/custom_field_format.rb b/lib/redmine/custom_field_format.rb new file mode 100644 index 00000000..f7cd5d1c --- /dev/null +++ b/lib/redmine/custom_field_format.rb @@ -0,0 +1,108 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +module Redmine + class CustomFieldFormat + include Redmine::I18n + + cattr_accessor :available + @@available = {} + + attr_accessor :name, :order, :label, :edit_as, :class_names + + def initialize(name, options={}) + self.name = name + self.label = options[:label] || "label_#{name}".to_sym + self.order = options[:order] || self.class.available_formats.size + self.edit_as = options[:edit_as] || name + self.class_names = options[:only] + end + + def format(value) + send "format_as_#{name}", value + end + + def format_as_date(value) + begin; format_date(value.to_date); rescue; value end + end + + def format_as_bool(value) + l(value == "1" ? :general_text_Yes : :general_text_No) + end + + ['string','text','int','float','list'].each do |name| + define_method("format_as_#{name}") {|value| + return value + } + end + + ['user', 'version'].each do |name| + define_method("format_as_#{name}") {|value| + return value.blank? ? "" : name.classify.constantize.find_by_id(value.to_i).to_s + } + end + + class << self + def map(&block) + yield self + end + + # Registers a custom field format + def register(*args) + custom_field_format = args.first + unless custom_field_format.is_a?(Redmine::CustomFieldFormat) + custom_field_format = Redmine::CustomFieldFormat.new(*args) + end + @@available[custom_field_format.name] = custom_field_format unless @@available.keys.include?(custom_field_format.name) + end + + def available_formats + @@available.keys + end + + def find_by_name(name) + @@available[name.to_s] + end + + def label_for(name) + format = @@available[name.to_s] + format.label if format + end + + # Return an array of custom field formats which can be used in select_tag + def as_select(class_name=nil) + fields = @@available.values + fields = fields.select {|field| field.class_names.nil? || field.class_names.include?(class_name)} + fields.sort {|a,b| + a.order <=> b.order + }.collect {|custom_field_format| + [ l(custom_field_format.label), custom_field_format.name ] + } + end + + def format_value(value, field_format) + return "" unless value && !value.empty? + + if format_type = find_by_name(field_format) + format_type.format(value) + else + value + end + end + end + end +end diff --git a/lib/redmine/default_data/loader.rb b/lib/redmine/default_data/loader.rb new file mode 100644 index 00000000..393738f9 --- /dev/null +++ b/lib/redmine/default_data/loader.rb @@ -0,0 +1,185 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +module Redmine + module DefaultData + class DataAlreadyLoaded < Exception; end + + module Loader + include Redmine::I18n + + class << self + # Returns true if no data is already loaded in the database + # otherwise false + def no_data? + !Role.where(:builtin => 0).exists? && + !Tracker.exists? && + !IssueStatus.exists? && + !Enumeration.exists? + end + + # Loads the default data + # Raises a RecordNotSaved exception if something goes wrong + def load(lang=nil) + raise DataAlreadyLoaded.new("Some configuration data is already loaded.") unless no_data? + set_language_if_valid(lang) + + Role.transaction do + # Roles + manager = Role.create! :name => l(:default_role_manager), + :issues_visibility => 'all', + :position => 1 + manager.permissions = manager.setable_permissions.collect {|p| p.name} + manager.save! + + developer = Role.create! :name => l(:default_role_developer), + :position => 2, + :permissions => [:manage_versions, + :manage_categories, + :view_issues, + :add_issues, + :edit_issues, + :view_private_notes, + :set_notes_private, + :manage_issue_relations, + :manage_subtasks, + :add_issue_notes, + :save_queries, + :view_gantt, + :view_calendar, + :log_time, + :view_time_entries, + :comment_news, + :view_documents, + :view_wiki_pages, + :view_wiki_edits, + :edit_wiki_pages, + :delete_wiki_pages, + :add_messages, + :edit_own_messages, + :view_files, + :manage_files, + :browse_repository, + :view_changesets, + :commit_access, + :manage_related_issues] + + reporter = Role.create! :name => l(:default_role_reporter), + :position => 3, + :permissions => [:view_issues, + :add_issues, + :add_issue_notes, + :save_queries, + :view_gantt, + :view_calendar, + :log_time, + :view_time_entries, + :comment_news, + :view_documents, + :view_wiki_pages, + :view_wiki_edits, + :add_messages, + :edit_own_messages, + :view_files, + :browse_repository, + :view_changesets] + + Role.non_member.update_attribute :permissions, [:view_issues, + :add_issues, + :add_issue_notes, + :save_queries, + :view_gantt, + :view_calendar, + :view_time_entries, + :comment_news, + :view_documents, + :view_wiki_pages, + :view_wiki_edits, + :add_messages, + :view_files, + :browse_repository, + :view_changesets] + + Role.anonymous.update_attribute :permissions, [:view_issues, + :view_gantt, + :view_calendar, + :view_time_entries, + :view_documents, + :view_wiki_pages, + :view_wiki_edits, + :view_files, + :browse_repository, + :view_changesets] + + # Trackers + Tracker.create!(:name => l(:default_tracker_bug), :is_in_chlog => true, :is_in_roadmap => false, :position => 1) + Tracker.create!(:name => l(:default_tracker_feature), :is_in_chlog => true, :is_in_roadmap => true, :position => 2) + Tracker.create!(:name => l(:default_tracker_support), :is_in_chlog => false, :is_in_roadmap => false, :position => 3) + + # Issue statuses + new = IssueStatus.create!(:name => l(:default_issue_status_new), :is_closed => false, :is_default => true, :position => 1) + in_progress = IssueStatus.create!(:name => l(:default_issue_status_in_progress), :is_closed => false, :is_default => false, :position => 2) + resolved = IssueStatus.create!(:name => l(:default_issue_status_resolved), :is_closed => false, :is_default => false, :position => 3) + feedback = IssueStatus.create!(:name => l(:default_issue_status_feedback), :is_closed => false, :is_default => false, :position => 4) + closed = IssueStatus.create!(:name => l(:default_issue_status_closed), :is_closed => true, :is_default => false, :position => 5) + rejected = IssueStatus.create!(:name => l(:default_issue_status_rejected), :is_closed => true, :is_default => false, :position => 6) + + # Workflow + Tracker.all.each { |t| + IssueStatus.all.each { |os| + IssueStatus.all.each { |ns| + WorkflowTransition.create!(:tracker_id => t.id, :role_id => manager.id, :old_status_id => os.id, :new_status_id => ns.id) unless os == ns + } + } + } + + Tracker.all.each { |t| + [new, in_progress, resolved, feedback].each { |os| + [in_progress, resolved, feedback, closed].each { |ns| + WorkflowTransition.create!(:tracker_id => t.id, :role_id => developer.id, :old_status_id => os.id, :new_status_id => ns.id) unless os == ns + } + } + } + + Tracker.all.each { |t| + [new, in_progress, resolved, feedback].each { |os| + [closed].each { |ns| + WorkflowTransition.create!(:tracker_id => t.id, :role_id => reporter.id, :old_status_id => os.id, :new_status_id => ns.id) unless os == ns + } + } + WorkflowTransition.create!(:tracker_id => t.id, :role_id => reporter.id, :old_status_id => resolved.id, :new_status_id => feedback.id) + } + + # Enumerations + IssuePriority.create!(:name => l(:default_priority_low), :position => 1) + IssuePriority.create!(:name => l(:default_priority_normal), :position => 2, :is_default => true) + IssuePriority.create!(:name => l(:default_priority_high), :position => 3) + IssuePriority.create!(:name => l(:default_priority_urgent), :position => 4) + IssuePriority.create!(:name => l(:default_priority_immediate), :position => 5) + + DocumentCategory.create!(:name => l(:default_doc_category_user), :position => 1) + DocumentCategory.create!(:name => l(:default_doc_category_tech), :position => 2) + + TimeEntryActivity.create!(:name => l(:default_activity_design), :position => 1) + TimeEntryActivity.create!(:name => l(:default_activity_development), :position => 2) + end + true + end + end + end + end +end diff --git a/lib/redmine/export/pdf.rb b/lib/redmine/export/pdf.rb new file mode 100644 index 00000000..13941679 --- /dev/null +++ b/lib/redmine/export/pdf.rb @@ -0,0 +1,807 @@ +# encoding: utf-8 +# +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +require 'tcpdf' +require 'fpdf/chinese' +require 'fpdf/japanese' +require 'fpdf/korean' + +if RUBY_VERSION < '1.9' + require 'iconv' +end + +module Redmine + module Export + module PDF + include ActionView::Helpers::TextHelper + include ActionView::Helpers::NumberHelper + include IssuesHelper + + class ITCPDF < TCPDF + include Redmine::I18n + attr_accessor :footer_date + + def initialize(lang, orientation='P') + @@k_path_cache = Rails.root.join('tmp', 'pdf') + FileUtils.mkdir_p @@k_path_cache unless File::exist?(@@k_path_cache) + set_language_if_valid lang + pdf_encoding = l(:general_pdf_encoding).upcase + super(orientation, 'mm', 'A4', (pdf_encoding == 'UTF-8'), pdf_encoding) + case current_language.to_s.downcase + when 'vi' + @font_for_content = 'DejaVuSans' + @font_for_footer = 'DejaVuSans' + else + case pdf_encoding + when 'UTF-8' + @font_for_content = 'FreeSans' + @font_for_footer = 'FreeSans' + when 'CP949' + extend(PDF_Korean) + AddUHCFont() + @font_for_content = 'UHC' + @font_for_footer = 'UHC' + when 'CP932', 'SJIS', 'SHIFT_JIS' + extend(PDF_Japanese) + AddSJISFont() + @font_for_content = 'SJIS' + @font_for_footer = 'SJIS' + when 'GB18030' + extend(PDF_Chinese) + AddGBFont() + @font_for_content = 'GB' + @font_for_footer = 'GB' + when 'BIG5' + extend(PDF_Chinese) + AddBig5Font() + @font_for_content = 'Big5' + @font_for_footer = 'Big5' + else + @font_for_content = 'Arial' + @font_for_footer = 'Helvetica' + end + end + SetCreator(Redmine::Info.app_name) + SetFont(@font_for_content) + @outlines = [] + @outlineRoot = nil + end + + def SetFontStyle(style, size) + SetFont(@font_for_content, style, size) + end + + def SetTitle(txt) + txt = begin + utf16txt = to_utf16(txt) + hextxt = "" + rescue + txt + end || '' + super(txt) + end + + def textstring(s) + # Format a text string + if s =~ /^\{\{([<>]?)toc\}\}<\/p>/i, '') + html + end + + # Encodes an UTF-8 string to UTF-16BE + def to_utf16(str) + if str.respond_to?(:encode) + str.encode('UTF-16BE') + else + Iconv.conv('UTF-16BE', 'UTF-8', str) + end + end + + def RDMCell(w ,h=0, txt='', border=0, ln=0, align='', fill=0, link='') + Cell(w, h, fix_text_encoding(txt), border, ln, align, fill, link) + end + + def RDMMultiCell(w, h=0, txt='', border=0, align='', fill=0, ln=1) + MultiCell(w, h, fix_text_encoding(txt), border, align, fill, ln) + end + + def RDMwriteHTMLCell(w, h, x, y, txt='', attachments=[], border=0, ln=1, fill=0) + @attachments = attachments + writeHTMLCell(w, h, x, y, + fix_text_encoding(formatted_text(txt)), + border, ln, fill) + end + + def getImageFilename(attrname) + # attrname: general_pdf_encoding string file/uri name + atta = RDMPdfEncoding.attach(@attachments, attrname, l(:general_pdf_encoding)) + if atta + return atta.diskfile + else + return nil + end + end + + def Footer + SetFont(@font_for_footer, 'I', 8) + SetY(-15) + SetX(15) + RDMCell(0, 5, @footer_date, 0, 0, 'L') + SetY(-15) + SetX(-30) + RDMCell(0, 5, PageNo().to_s + '/{nb}', 0, 0, 'C') + end + + def Bookmark(txt, level=0, y=0) + if (y == -1) + y = GetY() + end + @outlines << {:t => txt, :l => level, :p => PageNo(), :y => (@h - y)*@k} + end + + def bookmark_title(txt) + txt = begin + utf16txt = to_utf16(txt) + hextxt = "" + rescue + txt + end || '' + end + + def putbookmarks + nb=@outlines.size + return if (nb==0) + lru=[] + level=0 + @outlines.each_with_index do |o, i| + if(o[:l]>0) + parent=lru[o[:l]-1] + #Set parent and last pointers + @outlines[i][:parent]=parent + @outlines[parent][:last]=i + if (o[:l]>level) + #Level increasing: set first pointer + @outlines[parent][:first]=i + end + else + @outlines[i][:parent]=nb + end + if (o[:l]<=level && i>0) + #Set prev and next pointers + prev=lru[o[:l]] + @outlines[prev][:next]=i + @outlines[i][:prev]=prev + end + lru[o[:l]]=i + level=o[:l] + end + #Outline items + n=self.n+1 + @outlines.each_with_index do |o, i| + newobj() + out('<>') + out('endobj') + end + #Outline root + newobj() + @outlineRoot=self.n + out("<>"); + out('endobj'); + end + + def putresources() + super + putbookmarks() + end + + def putcatalog() + super + if(@outlines.size > 0) + out("/Outlines #{@outlineRoot} 0 R"); + out('/PageMode /UseOutlines'); + end + end + end + + # fetch row values + def fetch_row_values(issue, query, level) + query.inline_columns.collect do |column| + s = if column.is_a?(QueryCustomFieldColumn) + cv = issue.custom_field_values.detect {|v| v.custom_field_id == column.custom_field.id} + show_value(cv) + else + value = issue.send(column.name) + if column.name == :subject + value = " " * level + value + end + if value.is_a?(Date) + format_date(value) + elsif value.is_a?(Time) + format_time(value) + else + value + end + end + s.to_s + end + end + + # calculate columns width + def calc_col_width(issues, query, table_width, pdf) + # calculate statistics + # by captions + pdf.SetFontStyle('B',8) + col_padding = pdf.GetStringWidth('OO') + col_width_min = query.inline_columns.map {|v| pdf.GetStringWidth(v.caption) + col_padding} + col_width_max = Array.new(col_width_min) + col_width_avg = Array.new(col_width_min) + word_width_max = query.inline_columns.map {|c| + n = 10 + c.caption.split.each {|w| + x = pdf.GetStringWidth(w) + col_padding + n = x if n < x + } + n + } + + # by properties of issues + pdf.SetFontStyle('',8) + col_padding = pdf.GetStringWidth('OO') + k = 1 + issue_list(issues) {|issue, level| + k += 1 + values = fetch_row_values(issue, query, level) + values.each_with_index {|v,i| + n = pdf.GetStringWidth(v) + col_padding + col_width_max[i] = n if col_width_max[i] < n + col_width_min[i] = n if col_width_min[i] > n + col_width_avg[i] += n + v.split.each {|w| + x = pdf.GetStringWidth(w) + col_padding + word_width_max[i] = x if word_width_max[i] < x + } + } + } + col_width_avg.map! {|x| x / k} + + # calculate columns width + ratio = table_width / col_width_avg.inject(0) {|s,w| s += w} + col_width = col_width_avg.map {|w| w * ratio} + + # correct max word width if too many columns + ratio = table_width / word_width_max.inject(0) {|s,w| s += w} + word_width_max.map! {|v| v * ratio} if ratio < 1 + + # correct and lock width of some columns + done = 1 + col_fix = [] + col_width.each_with_index do |w,i| + if w > col_width_max[i] + col_width[i] = col_width_max[i] + col_fix[i] = 1 + done = 0 + elsif w < word_width_max[i] + col_width[i] = word_width_max[i] + col_fix[i] = 1 + done = 0 + else + col_fix[i] = 0 + end + end + + # iterate while need to correct and lock coluns width + while done == 0 + # calculate free & locked columns width + done = 1 + fix_col_width = 0 + free_col_width = 0 + col_width.each_with_index do |w,i| + if col_fix[i] == 1 + fix_col_width += w + else + free_col_width += w + end + end + + # calculate column normalizing ratio + if free_col_width == 0 + ratio = table_width / col_width.inject(0) {|s,w| s += w} + else + ratio = (table_width - fix_col_width) / free_col_width + end + + # correct columns width + col_width.each_with_index do |w,i| + if col_fix[i] == 0 + col_width[i] = w * ratio + + # check if column width less then max word width + if col_width[i] < word_width_max[i] + col_width[i] = word_width_max[i] + col_fix[i] = 1 + done = 0 + elsif col_width[i] > col_width_max[i] + col_width[i] = col_width_max[i] + col_fix[i] = 1 + done = 0 + end + end + end + end + col_width + end + + def render_table_header(pdf, query, col_width, row_height, table_width) + # headers + pdf.SetFontStyle('B',8) + pdf.SetFillColor(230, 230, 230) + + # render it background to find the max height used + base_x = pdf.GetX + base_y = pdf.GetY + max_height = issues_to_pdf_write_cells(pdf, query.inline_columns, col_width, row_height, true) + pdf.Rect(base_x, base_y, table_width, max_height, 'FD'); + pdf.SetXY(base_x, base_y); + + # write the cells on page + issues_to_pdf_write_cells(pdf, query.inline_columns, col_width, row_height, true) + issues_to_pdf_draw_borders(pdf, base_x, base_y, base_y + max_height, col_width) + pdf.SetY(base_y + max_height); + + # rows + pdf.SetFontStyle('',8) + pdf.SetFillColor(255, 255, 255) + end + + # Returns a PDF string of a list of issues + def issues_to_pdf(issues, project, query) + pdf = ITCPDF.new(current_language, "L") + title = query.new_record? ? l(:label_issue_plural) : query.name + title = "#{project} - #{title}" if project + pdf.SetTitle(title) + pdf.alias_nb_pages + pdf.footer_date = format_date(Date.today) + pdf.SetAutoPageBreak(false) + pdf.AddPage("L") + + # Landscape A4 = 210 x 297 mm + page_height = 210 + page_width = 297 + left_margin = 10 + right_margin = 10 + bottom_margin = 20 + row_height = 4 + + # column widths + table_width = page_width - right_margin - left_margin + col_width = [] + unless query.inline_columns.empty? + col_width = calc_col_width(issues, query, table_width, pdf) + table_width = col_width.inject(0) {|s,v| s += v} + end + + # use full width if the description is displayed + if table_width > 0 && query.has_column?(:description) + col_width = col_width.map {|w| w * (page_width - right_margin - left_margin) / table_width} + table_width = col_width.inject(0) {|s,v| s += v} + end + + # title + pdf.SetFontStyle('B',11) + pdf.RDMCell(190,10, title) + pdf.Ln + render_table_header(pdf, query, col_width, row_height, table_width) + previous_group = false + issue_list(issues) do |issue, level| + if query.grouped? && + (group = query.group_by_column.value(issue)) != previous_group + pdf.SetFontStyle('B',10) + group_label = group.blank? ? 'None' : group.to_s.dup + group_label << " (#{query.issue_count_by_group[group]})" + pdf.Bookmark group_label, 0, -1 + pdf.RDMCell(table_width, row_height * 2, group_label, 1, 1, 'L') + pdf.SetFontStyle('',8) + previous_group = group + end + + # fetch row values + col_values = fetch_row_values(issue, query, level) + + # render it off-page to find the max height used + base_x = pdf.GetX + base_y = pdf.GetY + pdf.SetY(2 * page_height) + max_height = issues_to_pdf_write_cells(pdf, col_values, col_width, row_height) + pdf.SetXY(base_x, base_y) + + # make new page if it doesn't fit on the current one + space_left = page_height - base_y - bottom_margin + if max_height > space_left + pdf.AddPage("L") + render_table_header(pdf, query, col_width, row_height, table_width) + base_x = pdf.GetX + base_y = pdf.GetY + end + + # write the cells on page + issues_to_pdf_write_cells(pdf, col_values, col_width, row_height) + issues_to_pdf_draw_borders(pdf, base_x, base_y, base_y + max_height, col_width) + pdf.SetY(base_y + max_height); + + if query.has_column?(:description) && issue.description? + pdf.SetX(10) + pdf.SetAutoPageBreak(true, 20) + pdf.RDMwriteHTMLCell(0, 5, 10, 0, issue.description.to_s, issue.attachments, "LRBT") + pdf.SetAutoPageBreak(false) + end + end + + if issues.size == Setting.issues_export_limit.to_i + pdf.SetFontStyle('B',10) + pdf.RDMCell(0, row_height, '...') + end + pdf.Output + end + + # Renders MultiCells and returns the maximum height used + def issues_to_pdf_write_cells(pdf, col_values, col_widths, + row_height, head=false) + base_y = pdf.GetY + max_height = row_height + col_values.each_with_index do |column, i| + col_x = pdf.GetX + if head == true + pdf.RDMMultiCell(col_widths[i], row_height, column.caption, "T", 'L', 1) + else + pdf.RDMMultiCell(col_widths[i], row_height, column, "T", 'L', 1) + end + max_height = (pdf.GetY - base_y) if (pdf.GetY - base_y) > max_height + pdf.SetXY(col_x + col_widths[i], base_y); + end + return max_height + end + + # Draw lines to close the row (MultiCell border drawing in not uniform) + def issues_to_pdf_draw_borders(pdf, top_x, top_y, lower_y, col_widths) + col_x = top_x + pdf.Line(col_x, top_y, col_x, lower_y) # id right border + col_widths.each do |width| + col_x += width + pdf.Line(col_x, top_y, col_x, lower_y) # columns right border + end + pdf.Line(top_x, top_y, top_x, lower_y) # left border + pdf.Line(top_x, lower_y, col_x, lower_y) # bottom border + end + + # Returns a PDF string of a single issue + def issue_to_pdf(issue, assoc={}) + pdf = ITCPDF.new(current_language) + pdf.SetTitle("#{issue.project} - #{issue.tracker} ##{issue.id}") + pdf.alias_nb_pages + pdf.footer_date = format_date(Date.today) + pdf.AddPage + pdf.SetFontStyle('B',11) + buf = "#{issue.project} - #{issue.tracker} ##{issue.id}" + pdf.RDMMultiCell(190, 5, buf) + pdf.SetFontStyle('',8) + base_x = pdf.GetX + i = 1 + issue.ancestors.visible.each do |ancestor| + pdf.SetX(base_x + i) + buf = "#{ancestor.tracker} # #{ancestor.id} (#{ancestor.status.to_s}): #{ancestor.subject}" + pdf.RDMMultiCell(190 - i, 5, buf) + i += 1 if i < 35 + end + pdf.SetFontStyle('B',11) + pdf.RDMMultiCell(190 - i, 5, issue.subject.to_s) + pdf.SetFontStyle('',8) + pdf.RDMMultiCell(190, 5, "#{format_time(issue.created_on)} - #{issue.author}") + pdf.Ln + + left = [] + left << [l(:field_status), issue.status] + left << [l(:field_priority), issue.priority] + left << [l(:field_assigned_to), issue.assigned_to] unless issue.disabled_core_fields.include?('assigned_to_id') + left << [l(:field_category), issue.category] unless issue.disabled_core_fields.include?('category_id') + left << [l(:field_fixed_version), issue.fixed_version] unless issue.disabled_core_fields.include?('fixed_version_id') + + right = [] + right << [l(:field_start_date), format_date(issue.start_date)] unless issue.disabled_core_fields.include?('start_date') + right << [l(:field_due_date), format_date(issue.due_date)] unless issue.disabled_core_fields.include?('due_date') + right << [l(:field_done_ratio), "#{issue.done_ratio}%"] unless issue.disabled_core_fields.include?('done_ratio') + right << [l(:field_estimated_hours), l_hours(issue.estimated_hours)] unless issue.disabled_core_fields.include?('estimated_hours') + right << [l(:label_spent_time), l_hours(issue.total_spent_hours)] if User.current.allowed_to?(:view_time_entries, issue.project) + + rows = left.size > right.size ? left.size : right.size + while left.size < rows + left << nil + end + while right.size < rows + right << nil + end + + half = (issue.custom_field_values.size / 2.0).ceil + issue.custom_field_values.each_with_index do |custom_value, i| + (i < half ? left : right) << [custom_value.custom_field.name, show_value(custom_value)] + end + + rows = left.size > right.size ? left.size : right.size + rows.times do |i| + item = left[i] + pdf.SetFontStyle('B',9) + pdf.RDMCell(35,5, item ? "#{item.first}:" : "", i == 0 ? "LT" : "L") + pdf.SetFontStyle('',9) + pdf.RDMCell(60,5, item ? item.last.to_s : "", i == 0 ? "RT" : "R") + + item = right[i] + pdf.SetFontStyle('B',9) + pdf.RDMCell(35,5, item ? "#{item.first}:" : "", i == 0 ? "LT" : "L") + pdf.SetFontStyle('',9) + pdf.RDMCell(60,5, item ? item.last.to_s : "", i == 0 ? "RT" : "R") + pdf.Ln + end + + pdf.SetFontStyle('B',9) + pdf.RDMCell(35+155, 5, l(:field_description), "LRT", 1) + pdf.SetFontStyle('',9) + + # Set resize image scale + pdf.SetImageScale(1.6) + pdf.RDMwriteHTMLCell(35+155, 5, 0, 0, + issue.description.to_s, issue.attachments, "LRB") + + unless issue.leaf? + # for CJK + truncate_length = ( l(:general_pdf_encoding).upcase == "UTF-8" ? 90 : 65 ) + + pdf.SetFontStyle('B',9) + pdf.RDMCell(35+155,5, l(:label_subtask_plural) + ":", "LTR") + pdf.Ln + issue_list(issue.descendants.visible.sort_by(&:lft)) do |child, level| + buf = truncate("#{child.tracker} # #{child.id}: #{child.subject}", + :length => truncate_length) + level = 10 if level >= 10 + pdf.SetFontStyle('',8) + pdf.RDMCell(35+135,5, (level >=1 ? " " * level : "") + buf, "L") + pdf.SetFontStyle('B',8) + pdf.RDMCell(20,5, child.status.to_s, "R") + pdf.Ln + end + end + + relations = issue.relations.select { |r| r.other_issue(issue).visible? } + unless relations.empty? + # for CJK + truncate_length = ( l(:general_pdf_encoding).upcase == "UTF-8" ? 80 : 60 ) + + pdf.SetFontStyle('B',9) + pdf.RDMCell(35+155,5, l(:label_related_issues) + ":", "LTR") + pdf.Ln + relations.each do |relation| + buf = "" + buf += "#{l(relation.label_for(issue))} " + if relation.delay && relation.delay != 0 + buf += "(#{l('datetime.distance_in_words.x_days', :count => relation.delay)}) " + end + if Setting.cross_project_issue_relations? + buf += "#{relation.other_issue(issue).project} - " + end + buf += "#{relation.other_issue(issue).tracker}" + + " # #{relation.other_issue(issue).id}: #{relation.other_issue(issue).subject}" + buf = truncate(buf, :length => truncate_length) + pdf.SetFontStyle('', 8) + pdf.RDMCell(35+155-60, 5, buf, "L") + pdf.SetFontStyle('B',8) + pdf.RDMCell(20,5, relation.other_issue(issue).status.to_s, "") + pdf.RDMCell(20,5, format_date(relation.other_issue(issue).start_date), "") + pdf.RDMCell(20,5, format_date(relation.other_issue(issue).due_date), "R") + pdf.Ln + end + end + pdf.RDMCell(190,5, "", "T") + pdf.Ln + + if issue.changesets.any? && + User.current.allowed_to?(:view_changesets, issue.project) + pdf.SetFontStyle('B',9) + pdf.RDMCell(190,5, l(:label_associated_revisions), "B") + pdf.Ln + for changeset in issue.changesets + pdf.SetFontStyle('B',8) + csstr = "#{l(:label_revision)} #{changeset.format_identifier} - " + csstr += format_time(changeset.committed_on) + " - " + changeset.author.to_s + pdf.RDMCell(190, 5, csstr) + pdf.Ln + unless changeset.comments.blank? + pdf.SetFontStyle('',8) + pdf.RDMwriteHTMLCell(190,5,0,0, + changeset.comments.to_s, issue.attachments, "") + end + pdf.Ln + end + end + + if assoc[:journals].present? + pdf.SetFontStyle('B',9) + pdf.RDMCell(190,5, l(:label_history), "B") + pdf.Ln + assoc[:journals].each do |journal| + pdf.SetFontStyle('B',8) + title = "##{journal.indice} - #{format_time(journal.created_on)} - #{journal.user}" + title << " (#{l(:field_private_notes)})" if journal.private_notes? + pdf.RDMCell(190,5, title) + pdf.Ln + pdf.SetFontStyle('I',8) + details_to_strings(journal.details, true).each do |string| + pdf.RDMMultiCell(190,5, "- " + string) + end + if journal.notes? + pdf.Ln unless journal.details.empty? + pdf.SetFontStyle('',8) + pdf.RDMwriteHTMLCell(190,5,0,0, + journal.notes.to_s, issue.attachments, "") + end + pdf.Ln + end + end + + if issue.attachments.any? + pdf.SetFontStyle('B',9) + pdf.RDMCell(190,5, l(:label_attachment_plural), "B") + pdf.Ln + for attachment in issue.attachments + pdf.SetFontStyle('',8) + pdf.RDMCell(80,5, attachment.filename) + pdf.RDMCell(20,5, number_to_human_size(attachment.filesize),0,0,"R") + pdf.RDMCell(25,5, format_date(attachment.created_on),0,0,"R") + pdf.RDMCell(65,5, attachment.author.name,0,0,"R") + pdf.Ln + end + end + pdf.Output + end + + # Returns a PDF string of a set of wiki pages + def wiki_pages_to_pdf(pages, project) + pdf = ITCPDF.new(current_language) + pdf.SetTitle(project.name) + pdf.alias_nb_pages + pdf.footer_date = format_date(Date.today) + pdf.AddPage + pdf.SetFontStyle('B',11) + pdf.RDMMultiCell(190,5, project.name) + pdf.Ln + # Set resize image scale + pdf.SetImageScale(1.6) + pdf.SetFontStyle('',9) + write_page_hierarchy(pdf, pages.group_by(&:parent_id)) + pdf.Output + end + + # Returns a PDF string of a single wiki page + def wiki_page_to_pdf(page, project) + pdf = ITCPDF.new(current_language) + pdf.SetTitle("#{project} - #{page.title}") + pdf.alias_nb_pages + pdf.footer_date = format_date(Date.today) + pdf.AddPage + pdf.SetFontStyle('B',11) + pdf.RDMMultiCell(190,5, + "#{project} - #{page.title} - # #{page.content.version}") + pdf.Ln + # Set resize image scale + pdf.SetImageScale(1.6) + pdf.SetFontStyle('',9) + write_wiki_page(pdf, page) + pdf.Output + end + + def write_page_hierarchy(pdf, pages, node=nil, level=0) + if pages[node] + pages[node].each do |page| + if @new_page + pdf.AddPage + else + @new_page = true + end + pdf.Bookmark page.title, level + write_wiki_page(pdf, page) + write_page_hierarchy(pdf, pages, page.id, level + 1) if pages[page.id] + end + end + end + + def write_wiki_page(pdf, page) + pdf.RDMwriteHTMLCell(190,5,0,0, + page.content.text.to_s, page.attachments, 0) + if page.attachments.any? + pdf.Ln + pdf.SetFontStyle('B',9) + pdf.RDMCell(190,5, l(:label_attachment_plural), "B") + pdf.Ln + for attachment in page.attachments + pdf.SetFontStyle('',8) + pdf.RDMCell(80,5, attachment.filename) + pdf.RDMCell(20,5, number_to_human_size(attachment.filesize),0,0,"R") + pdf.RDMCell(25,5, format_date(attachment.created_on),0,0,"R") + pdf.RDMCell(65,5, attachment.author.name,0,0,"R") + pdf.Ln + end + end + end + + class RDMPdfEncoding + def self.rdm_from_utf8(txt, encoding) + txt ||= '' + txt = Redmine::CodesetUtil.from_utf8(txt, encoding) + if txt.respond_to?(:force_encoding) + txt.force_encoding('ASCII-8BIT') + end + txt + end + + def self.attach(attachments, filename, encoding) + filename_utf8 = Redmine::CodesetUtil.to_utf8(filename, encoding) + atta = nil + if filename_utf8 =~ /^[^\/"]+\.(gif|jpg|jpe|jpeg|png)$/i + atta = Attachment.latest_attach(attachments, filename_utf8) + end + if atta && atta.readable? && atta.visible? + return atta + else + return nil + end + end + end + end + end +end diff --git a/lib/redmine/helpers/calendar.rb b/lib/redmine/helpers/calendar.rb new file mode 100644 index 00000000..fa01b2f4 --- /dev/null +++ b/lib/redmine/helpers/calendar.rb @@ -0,0 +1,85 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +module Redmine + module Helpers + + # Simple class to compute the start and end dates of a calendar + class Calendar + include Redmine::I18n + attr_reader :startdt, :enddt + + def initialize(date, lang = current_language, period = :month) + @date = date + @events = [] + @ending_events_by_days = {} + @starting_events_by_days = {} + set_language_if_valid lang + case period + when :month + @startdt = Date.civil(date.year, date.month, 1) + @enddt = (@startdt >> 1)-1 + # starts from the first day of the week + @startdt = @startdt - (@startdt.cwday - first_wday)%7 + # ends on the last day of the week + @enddt = @enddt + (last_wday - @enddt.cwday)%7 + when :week + @startdt = date - (date.cwday - first_wday)%7 + @enddt = date + (last_wday - date.cwday)%7 + else + raise 'Invalid period' + end + end + + # Sets calendar events + def events=(events) + @events = events + @ending_events_by_days = @events.group_by {|event| event.due_date} + @starting_events_by_days = @events.group_by {|event| event.start_date} + end + + # Returns events for the given day + def events_on(day) + ((@ending_events_by_days[day] || []) + (@starting_events_by_days[day] || [])).uniq + end + + # Calendar current month + def month + @date.month + end + + # Return the first day of week + # 1 = Monday ... 7 = Sunday + def first_wday + case Setting.start_of_week.to_i + when 1 + @first_dow ||= (1 - 1)%7 + 1 + when 6 + @first_dow ||= (6 - 1)%7 + 1 + when 7 + @first_dow ||= (7 - 1)%7 + 1 + else + @first_dow ||= (l(:general_first_day_of_week).to_i - 1)%7 + 1 + end + end + + def last_wday + @last_dow ||= (first_wday + 5)%7 + 1 + end + end + end +end diff --git a/lib/redmine/helpers/diff.rb b/lib/redmine/helpers/diff.rb new file mode 100644 index 00000000..537bfa05 --- /dev/null +++ b/lib/redmine/helpers/diff.rb @@ -0,0 +1,73 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +module Redmine + module Helpers + class Diff + include ERB::Util + include ActionView::Helpers::TagHelper + include ActionView::Helpers::TextHelper + attr_reader :diff, :words + + def initialize(content_to, content_from) + @words = content_to.to_s.split(/(\s+)/) + @words = @words.select {|word| word != ' '} + words_from = content_from.to_s.split(/(\s+)/) + words_from = words_from.select {|word| word != ' '} + @diff = words_from.diff @words + end + + def to_html + words = self.words.collect{|word| h(word)} + words_add = 0 + words_del = 0 + dels = 0 + del_off = 0 + diff.diffs.each do |diff| + add_at = nil + add_to = nil + del_at = nil + deleted = "" + diff.each do |change| + pos = change[1] + if change[0] == "+" + add_at = pos + dels unless add_at + add_to = pos + dels + words_add += 1 + else + del_at = pos unless del_at + deleted << ' ' unless deleted.empty? + deleted << h(change[2]) + words_del += 1 + end + end + if add_at + words[add_at] = ''.html_safe + words[add_at] + words[add_to] = words[add_to] + ''.html_safe + end + if del_at + words.insert del_at - del_off + dels + words_add, ''.html_safe + deleted + ''.html_safe + dels += 1 + del_off += words_del + words_del = 0 + end + end + words.join(' ').html_safe + end + end + end +end diff --git a/lib/redmine/helpers/gantt.rb b/lib/redmine/helpers/gantt.rb new file mode 100644 index 00000000..32be436b --- /dev/null +++ b/lib/redmine/helpers/gantt.rb @@ -0,0 +1,943 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +module Redmine + module Helpers + # Simple class to handle gantt chart data + class Gantt + include ERB::Util + include Redmine::I18n + include Redmine::Utils::DateCalculation + + # Relation types that are rendered + DRAW_TYPES = { + IssueRelation::TYPE_BLOCKS => { :landscape_margin => 16, :color => '#F34F4F' }, + IssueRelation::TYPE_PRECEDES => { :landscape_margin => 20, :color => '#628FEA' } + }.freeze + + # :nodoc: + # Some utility methods for the PDF export + class PDF + MaxCharactorsForSubject = 45 + TotalWidth = 280 + LeftPaneWidth = 100 + + def self.right_pane_width + TotalWidth - LeftPaneWidth + end + end + + attr_reader :year_from, :month_from, :date_from, :date_to, :zoom, :months, :truncated, :max_rows + attr_accessor :query + attr_accessor :project + attr_accessor :view + + def initialize(options={}) + options = options.dup + if options[:year] && options[:year].to_i >0 + @year_from = options[:year].to_i + if options[:month] && options[:month].to_i >=1 && options[:month].to_i <= 12 + @month_from = options[:month].to_i + else + @month_from = 1 + end + else + @month_from ||= Date.today.month + @year_from ||= Date.today.year + end + zoom = (options[:zoom] || User.current.pref[:gantt_zoom]).to_i + @zoom = (zoom > 0 && zoom < 5) ? zoom : 2 + months = (options[:months] || User.current.pref[:gantt_months]).to_i + @months = (months > 0 && months < 25) ? months : 6 + # Save gantt parameters as user preference (zoom and months count) + if (User.current.logged? && (@zoom != User.current.pref[:gantt_zoom] || + @months != User.current.pref[:gantt_months])) + User.current.pref[:gantt_zoom], User.current.pref[:gantt_months] = @zoom, @months + User.current.preference.save + end + @date_from = Date.civil(@year_from, @month_from, 1) + @date_to = (@date_from >> @months) - 1 + @subjects = '' + @lines = '' + @number_of_rows = nil + @issue_ancestors = [] + @truncated = false + if options.has_key?(:max_rows) + @max_rows = options[:max_rows] + else + @max_rows = Setting.gantt_items_limit.blank? ? nil : Setting.gantt_items_limit.to_i + end + end + + def common_params + { :controller => 'gantts', :action => 'show', :project_id => @project } + end + + def params + common_params.merge({:zoom => zoom, :year => year_from, + :month => month_from, :months => months}) + end + + def params_previous + common_params.merge({:year => (date_from << months).year, + :month => (date_from << months).month, + :zoom => zoom, :months => months}) + end + + def params_next + common_params.merge({:year => (date_from >> months).year, + :month => (date_from >> months).month, + :zoom => zoom, :months => months}) + end + + # Returns the number of rows that will be rendered on the Gantt chart + def number_of_rows + return @number_of_rows if @number_of_rows + rows = projects.inject(0) {|total, p| total += number_of_rows_on_project(p)} + rows > @max_rows ? @max_rows : rows + end + + # Returns the number of rows that will be used to list a project on + # the Gantt chart. This will recurse for each subproject. + def number_of_rows_on_project(project) + return 0 unless projects.include?(project) + count = 1 + count += project_issues(project).size + count += project_versions(project).size + count + end + + # Renders the subjects of the Gantt chart, the left side. + def subjects(options={}) + render(options.merge(:only => :subjects)) unless @subjects_rendered + @subjects + end + + # Renders the lines of the Gantt chart, the right side + def lines(options={}) + render(options.merge(:only => :lines)) unless @lines_rendered + @lines + end + + # Returns issues that will be rendered + def issues + @issues ||= @query.issues( + :include => [:assigned_to, :tracker, :priority, :category, :fixed_version], + :order => "#{Project.table_name}.lft ASC, #{Issue.table_name}.id ASC", + :limit => @max_rows + ) + end + + # Returns a hash of the relations between the issues that are present on the gantt + # and that should be displayed, grouped by issue ids. + def relations + return @relations if @relations + if issues.any? + issue_ids = issues.map(&:id) + @relations = IssueRelation. + where(:issue_from_id => issue_ids, :issue_to_id => issue_ids, :relation_type => DRAW_TYPES.keys). + group_by(&:issue_from_id) + else + @relations = {} + end + end + + # Return all the project nodes that will be displayed + def projects + return @projects if @projects + ids = issues.collect(&:project).uniq.collect(&:id) + if ids.any? + # All issues projects and their visible ancestors + @projects = Project.visible.all( + :joins => "LEFT JOIN #{Project.table_name} child ON #{Project.table_name}.lft <= child.lft AND #{Project.table_name}.rgt >= child.rgt", + :conditions => ["child.id IN (?)", ids], + :order => "#{Project.table_name}.lft ASC" + ).uniq + else + @projects = [] + end + end + + # Returns the issues that belong to +project+ + def project_issues(project) + @issues_by_project ||= issues.group_by(&:project) + @issues_by_project[project] || [] + end + + # Returns the distinct versions of the issues that belong to +project+ + def project_versions(project) + project_issues(project).collect(&:fixed_version).compact.uniq + end + + # Returns the issues that belong to +project+ and are assigned to +version+ + def version_issues(project, version) + project_issues(project).select {|issue| issue.fixed_version == version} + end + + def render(options={}) + options = {:top => 0, :top_increment => 20, + :indent_increment => 20, :render => :subject, + :format => :html}.merge(options) + indent = options[:indent] || 4 + @subjects = '' unless options[:only] == :lines + @lines = '' unless options[:only] == :subjects + @number_of_rows = 0 + Project.project_tree(projects) do |project, level| + options[:indent] = indent + level * options[:indent_increment] + render_project(project, options) + break if abort? + end + @subjects_rendered = true unless options[:only] == :lines + @lines_rendered = true unless options[:only] == :subjects + render_end(options) + end + + def render_project(project, options={}) + subject_for_project(project, options) unless options[:only] == :lines + line_for_project(project, options) unless options[:only] == :subjects + options[:top] += options[:top_increment] + options[:indent] += options[:indent_increment] + @number_of_rows += 1 + return if abort? + issues = project_issues(project).select {|i| i.fixed_version.nil?} + sort_issues!(issues) + if issues + render_issues(issues, options) + return if abort? + end + versions = project_versions(project) + versions.each do |version| + render_version(project, version, options) + end + # Remove indent to hit the next sibling + options[:indent] -= options[:indent_increment] + end + + def render_issues(issues, options={}) + @issue_ancestors = [] + issues.each do |i| + subject_for_issue(i, options) unless options[:only] == :lines + line_for_issue(i, options) unless options[:only] == :subjects + options[:top] += options[:top_increment] + @number_of_rows += 1 + break if abort? + end + options[:indent] -= (options[:indent_increment] * @issue_ancestors.size) + end + + def render_version(project, version, options={}) + # Version header + subject_for_version(version, options) unless options[:only] == :lines + line_for_version(version, options) unless options[:only] == :subjects + options[:top] += options[:top_increment] + @number_of_rows += 1 + return if abort? + issues = version_issues(project, version) + if issues + sort_issues!(issues) + # Indent issues + options[:indent] += options[:indent_increment] + render_issues(issues, options) + options[:indent] -= options[:indent_increment] + end + end + + def render_end(options={}) + case options[:format] + when :pdf + options[:pdf].Line(15, options[:top], PDF::TotalWidth, options[:top]) + end + end + + def subject_for_project(project, options) + case options[:format] + when :html + html_class = "" + html_class << 'icon icon-projects ' + html_class << (project.overdue? ? 'project-overdue' : '') + s = view.link_to_project(project).html_safe + subject = view.content_tag(:span, s, + :class => html_class).html_safe + html_subject(options, subject, :css => "project-name") + when :image + image_subject(options, project.name) + when :pdf + pdf_new_page?(options) + pdf_subject(options, project.name) + end + end + + def line_for_project(project, options) + # Skip versions that don't have a start_date or due date + if project.is_a?(Project) && project.start_date && project.due_date + options[:zoom] ||= 1 + options[:g_width] ||= (self.date_to - self.date_from + 1) * options[:zoom] + coords = coordinates(project.start_date, project.due_date, nil, options[:zoom]) + label = h(project) + case options[:format] + when :html + html_task(options, coords, :css => "project task", :label => label, :markers => true) + when :image + image_task(options, coords, :label => label, :markers => true, :height => 3) + when :pdf + pdf_task(options, coords, :label => label, :markers => true, :height => 0.8) + end + else + '' + end + end + + def subject_for_version(version, options) + case options[:format] + when :html + html_class = "" + html_class << 'icon icon-package ' + html_class << (version.behind_schedule? ? 'version-behind-schedule' : '') << " " + html_class << (version.overdue? ? 'version-overdue' : '') + html_class << ' version-closed' unless version.open? + if version.start_date && version.due_date && version.completed_pourcent + progress_date = calc_progress_date(version.start_date, + version.due_date, version.completed_pourcent) + html_class << ' behind-start-date' if progress_date < self.date_from + html_class << ' over-end-date' if progress_date > self.date_to + end + s = view.link_to_version(version).html_safe + subject = view.content_tag(:span, s, + :class => html_class).html_safe + html_subject(options, subject, :css => "version-name", + :id => "version-#{version.id}") + when :image + image_subject(options, version.to_s_with_project) + when :pdf + pdf_new_page?(options) + pdf_subject(options, version.to_s_with_project) + end + end + + def line_for_version(version, options) + # Skip versions that don't have a start_date + if version.is_a?(Version) && version.due_date && version.start_date + options[:zoom] ||= 1 + options[:g_width] ||= (self.date_to - self.date_from + 1) * options[:zoom] + coords = coordinates(version.start_date, + version.due_date, version.completed_percent, + options[:zoom]) + label = "#{h version} #{h version.completed_percent.to_i.to_s}%" + label = h("#{version.project} -") + label unless @project && @project == version.project + case options[:format] + when :html + html_task(options, coords, :css => "version task", + :label => label, :markers => true, :version => version) + when :image + image_task(options, coords, :label => label, :markers => true, :height => 3) + when :pdf + pdf_task(options, coords, :label => label, :markers => true, :height => 0.8) + end + else + '' + end + end + + def subject_for_issue(issue, options) + while @issue_ancestors.any? && !issue.is_descendant_of?(@issue_ancestors.last) + @issue_ancestors.pop + options[:indent] -= options[:indent_increment] + end + output = case options[:format] + when :html + css_classes = '' + css_classes << ' issue-overdue' if issue.overdue? + css_classes << ' issue-behind-schedule' if issue.behind_schedule? + css_classes << ' icon icon-issue' unless Setting.gravatar_enabled? && issue.assigned_to + css_classes << ' issue-closed' if issue.closed? + if issue.start_date && issue.due_before && issue.done_ratio + progress_date = calc_progress_date(issue.start_date, + issue.due_before, issue.done_ratio) + css_classes << ' behind-start-date' if progress_date < self.date_from + css_classes << ' over-end-date' if progress_date > self.date_to + end + s = "".html_safe + if issue.assigned_to.present? + assigned_string = l(:field_assigned_to) + ": " + issue.assigned_to.name + s << view.avatar(issue.assigned_to, + :class => 'gravatar icon-gravatar', + :size => 10, + :title => assigned_string).to_s.html_safe + end + s << view.link_to_issue(issue).html_safe + subject = view.content_tag(:span, s, :class => css_classes).html_safe + html_subject(options, subject, :css => "issue-subject", + :title => issue.subject, :id => "issue-#{issue.id}") + "\n" + when :image + image_subject(options, issue.subject) + when :pdf + pdf_new_page?(options) + pdf_subject(options, issue.subject) + end + unless issue.leaf? + @issue_ancestors << issue + options[:indent] += options[:indent_increment] + end + output + end + + def line_for_issue(issue, options) + # Skip issues that don't have a due_before (due_date or version's due_date) + if issue.is_a?(Issue) && issue.due_before + coords = coordinates(issue.start_date, issue.due_before, issue.done_ratio, options[:zoom]) + label = "#{issue.status.name} #{issue.done_ratio}%" + case options[:format] + when :html + html_task(options, coords, + :css => "task " + (issue.leaf? ? 'leaf' : 'parent'), + :label => label, :issue => issue, + :markers => !issue.leaf?) + when :image + image_task(options, coords, :label => label) + when :pdf + pdf_task(options, coords, :label => label) + end + else + '' + end + end + + # Generates a gantt image + # Only defined if RMagick is avalaible + def to_image(format='PNG') + date_to = (@date_from >> @months) - 1 + show_weeks = @zoom > 1 + show_days = @zoom > 2 + subject_width = 400 + header_height = 18 + # width of one day in pixels + zoom = @zoom * 2 + g_width = (@date_to - @date_from + 1) * zoom + g_height = 20 * number_of_rows + 30 + headers_height = (show_weeks ? 2 * header_height : header_height) + height = g_height + headers_height + imgl = Magick::ImageList.new + imgl.new_image(subject_width + g_width + 1, height) + gc = Magick::Draw.new + gc.font = Redmine::Configuration['rmagick_font_path'] || "" + # Subjects + gc.stroke('transparent') + subjects(:image => gc, :top => (headers_height + 20), :indent => 4, :format => :image) + # Months headers + month_f = @date_from + left = subject_width + @months.times do + width = ((month_f >> 1) - month_f) * zoom + gc.fill('white') + gc.stroke('grey') + gc.stroke_width(1) + gc.rectangle(left, 0, left + width, height) + gc.fill('black') + gc.stroke('transparent') + gc.stroke_width(1) + gc.text(left.round + 8, 14, "#{month_f.year}-#{month_f.month}") + left = left + width + month_f = month_f >> 1 + end + # Weeks headers + if show_weeks + left = subject_width + height = header_height + if @date_from.cwday == 1 + # date_from is monday + week_f = date_from + else + # find next monday after date_from + week_f = @date_from + (7 - @date_from.cwday + 1) + width = (7 - @date_from.cwday + 1) * zoom + gc.fill('white') + gc.stroke('grey') + gc.stroke_width(1) + gc.rectangle(left, header_height, left + width, 2 * header_height + g_height - 1) + left = left + width + end + while week_f <= date_to + width = (week_f + 6 <= date_to) ? 7 * zoom : (date_to - week_f + 1) * zoom + gc.fill('white') + gc.stroke('grey') + gc.stroke_width(1) + gc.rectangle(left.round, header_height, left.round + width, 2 * header_height + g_height - 1) + gc.fill('black') + gc.stroke('transparent') + gc.stroke_width(1) + gc.text(left.round + 2, header_height + 14, week_f.cweek.to_s) + left = left + width + week_f = week_f + 7 + end + end + # Days details (week-end in grey) + if show_days + left = subject_width + height = g_height + header_height - 1 + wday = @date_from.cwday + (date_to - @date_from + 1).to_i.times do + width = zoom + gc.fill(non_working_week_days.include?(wday) ? '#eee' : 'white') + gc.stroke('#ddd') + gc.stroke_width(1) + gc.rectangle(left, 2 * header_height, left + width, 2 * header_height + g_height - 1) + left = left + width + wday = wday + 1 + wday = 1 if wday > 7 + end + end + # border + gc.fill('transparent') + gc.stroke('grey') + gc.stroke_width(1) + gc.rectangle(0, 0, subject_width + g_width, headers_height) + gc.stroke('black') + gc.rectangle(0, 0, subject_width + g_width, g_height + headers_height - 1) + # content + top = headers_height + 20 + gc.stroke('transparent') + lines(:image => gc, :top => top, :zoom => zoom, + :subject_width => subject_width, :format => :image) + # today red line + if Date.today >= @date_from and Date.today <= date_to + gc.stroke('red') + x = (Date.today - @date_from + 1) * zoom + subject_width + gc.line(x, headers_height, x, headers_height + g_height - 1) + end + gc.draw(imgl) + imgl.format = format + imgl.to_blob + end if Object.const_defined?(:Magick) + + def to_pdf + pdf = ::Redmine::Export::PDF::ITCPDF.new(current_language) + pdf.SetTitle("#{l(:label_gantt)} #{project}") + pdf.alias_nb_pages + pdf.footer_date = format_date(Date.today) + pdf.AddPage("L") + pdf.SetFontStyle('B', 12) + pdf.SetX(15) + pdf.RDMCell(PDF::LeftPaneWidth, 20, project.to_s) + pdf.Ln + pdf.SetFontStyle('B', 9) + subject_width = PDF::LeftPaneWidth + header_height = 5 + headers_height = header_height + show_weeks = false + show_days = false + if self.months < 7 + show_weeks = true + headers_height = 2 * header_height + if self.months < 3 + show_days = true + headers_height = 3 * header_height + end + end + g_width = PDF.right_pane_width + zoom = (g_width) / (self.date_to - self.date_from + 1) + g_height = 120 + t_height = g_height + headers_height + y_start = pdf.GetY + # Months headers + month_f = self.date_from + left = subject_width + height = header_height + self.months.times do + width = ((month_f >> 1) - month_f) * zoom + pdf.SetY(y_start) + pdf.SetX(left) + pdf.RDMCell(width, height, "#{month_f.year}-#{month_f.month}", "LTR", 0, "C") + left = left + width + month_f = month_f >> 1 + end + # Weeks headers + if show_weeks + left = subject_width + height = header_height + if self.date_from.cwday == 1 + # self.date_from is monday + week_f = self.date_from + else + # find next monday after self.date_from + week_f = self.date_from + (7 - self.date_from.cwday + 1) + width = (7 - self.date_from.cwday + 1) * zoom-1 + pdf.SetY(y_start + header_height) + pdf.SetX(left) + pdf.RDMCell(width + 1, height, "", "LTR") + left = left + width + 1 + end + while week_f <= self.date_to + width = (week_f + 6 <= self.date_to) ? 7 * zoom : (self.date_to - week_f + 1) * zoom + pdf.SetY(y_start + header_height) + pdf.SetX(left) + pdf.RDMCell(width, height, (width >= 5 ? week_f.cweek.to_s : ""), "LTR", 0, "C") + left = left + width + week_f = week_f + 7 + end + end + # Days headers + if show_days + left = subject_width + height = header_height + wday = self.date_from.cwday + pdf.SetFontStyle('B', 7) + (self.date_to - self.date_from + 1).to_i.times do + width = zoom + pdf.SetY(y_start + 2 * header_height) + pdf.SetX(left) + pdf.RDMCell(width, height, day_name(wday).first, "LTR", 0, "C") + left = left + width + wday = wday + 1 + wday = 1 if wday > 7 + end + end + pdf.SetY(y_start) + pdf.SetX(15) + pdf.RDMCell(subject_width + g_width - 15, headers_height, "", 1) + # Tasks + top = headers_height + y_start + options = { + :top => top, + :zoom => zoom, + :subject_width => subject_width, + :g_width => g_width, + :indent => 0, + :indent_increment => 5, + :top_increment => 5, + :format => :pdf, + :pdf => pdf + } + render(options) + pdf.Output + end + + private + + def coordinates(start_date, end_date, progress, zoom=nil) + zoom ||= @zoom + coords = {} + if start_date && end_date && start_date < self.date_to && end_date > self.date_from + if start_date > self.date_from + coords[:start] = start_date - self.date_from + coords[:bar_start] = start_date - self.date_from + else + coords[:bar_start] = 0 + end + if end_date < self.date_to + coords[:end] = end_date - self.date_from + coords[:bar_end] = end_date - self.date_from + 1 + else + coords[:bar_end] = self.date_to - self.date_from + 1 + end + if progress + progress_date = calc_progress_date(start_date, end_date, progress) + if progress_date > self.date_from && progress_date > start_date + if progress_date < self.date_to + coords[:bar_progress_end] = progress_date - self.date_from + else + coords[:bar_progress_end] = self.date_to - self.date_from + 1 + end + end + if progress_date < Date.today + late_date = [Date.today, end_date].min + if late_date > self.date_from && late_date > start_date + if late_date < self.date_to + coords[:bar_late_end] = late_date - self.date_from + 1 + else + coords[:bar_late_end] = self.date_to - self.date_from + 1 + end + end + end + end + end + # Transforms dates into pixels witdh + coords.keys.each do |key| + coords[key] = (coords[key] * zoom).floor + end + coords + end + + def calc_progress_date(start_date, end_date, progress) + start_date + (end_date - start_date + 1) * (progress / 100.0) + end + + # Sorts a collection of issues by start_date, due_date, id for gantt rendering + def sort_issues!(issues) + issues.sort! { |a, b| gantt_issue_compare(a, b) } + end + + # TODO: top level issues should be sorted by start date + def gantt_issue_compare(x, y) + if x.root_id == y.root_id + x.lft <=> y.lft + else + x.root_id <=> y.root_id + end + end + + def current_limit + if @max_rows + @max_rows - @number_of_rows + else + nil + end + end + + def abort? + if @max_rows && @number_of_rows >= @max_rows + @truncated = true + end + end + + def pdf_new_page?(options) + if options[:top] > 180 + options[:pdf].Line(15, options[:top], PDF::TotalWidth, options[:top]) + options[:pdf].AddPage("L") + options[:top] = 15 + options[:pdf].Line(15, options[:top] - 0.1, PDF::TotalWidth, options[:top] - 0.1) + end + end + + def html_subject(params, subject, options={}) + style = "position: absolute;top:#{params[:top]}px;left:#{params[:indent]}px;" + style << "width:#{params[:subject_width] - params[:indent]}px;" if params[:subject_width] + output = view.content_tag(:div, subject, + :class => options[:css], :style => style, + :title => options[:title], + :id => options[:id]) + @subjects << output + output + end + + def pdf_subject(params, subject, options={}) + params[:pdf].SetY(params[:top]) + params[:pdf].SetX(15) + char_limit = PDF::MaxCharactorsForSubject - params[:indent] + params[:pdf].RDMCell(params[:subject_width] - 15, 5, + (" " * params[:indent]) + + subject.to_s.sub(/^(.{#{char_limit}}[^\s]*\s).*$/, '\1 (...)'), + "LR") + params[:pdf].SetY(params[:top]) + params[:pdf].SetX(params[:subject_width]) + params[:pdf].RDMCell(params[:g_width], 5, "", "LR") + end + + def image_subject(params, subject, options={}) + params[:image].fill('black') + params[:image].stroke('transparent') + params[:image].stroke_width(1) + params[:image].text(params[:indent], params[:top] + 2, subject) + end + + def issue_relations(issue) + rels = {} + if relations[issue.id] + relations[issue.id].each do |relation| + (rels[relation.relation_type] ||= []) << relation.issue_to_id + end + end + rels + end + + def html_task(params, coords, options={}) + output = '' + # Renders the task bar, with progress and late + if coords[:bar_start] && coords[:bar_end] + width = coords[:bar_end] - coords[:bar_start] - 2 + style = "" + style << "top:#{params[:top]}px;" + style << "left:#{coords[:bar_start]}px;" + style << "width:#{width}px;" + html_id = "task-todo-issue-#{options[:issue].id}" if options[:issue] + html_id = "task-todo-version-#{options[:version].id}" if options[:version] + content_opt = {:style => style, + :class => "#{options[:css]} task_todo", + :id => html_id} + if options[:issue] + rels = issue_relations(options[:issue]) + if rels.present? + content_opt[:data] = {"rels" => rels.to_json} + end + end + output << view.content_tag(:div, ' '.html_safe, content_opt) + if coords[:bar_late_end] + width = coords[:bar_late_end] - coords[:bar_start] - 2 + style = "" + style << "top:#{params[:top]}px;" + style << "left:#{coords[:bar_start]}px;" + style << "width:#{width}px;" + output << view.content_tag(:div, ' '.html_safe, + :style => style, + :class => "#{options[:css]} task_late") + end + if coords[:bar_progress_end] + width = coords[:bar_progress_end] - coords[:bar_start] - 2 + style = "" + style << "top:#{params[:top]}px;" + style << "left:#{coords[:bar_start]}px;" + style << "width:#{width}px;" + html_id = "task-done-issue-#{options[:issue].id}" if options[:issue] + html_id = "task-done-version-#{options[:version].id}" if options[:version] + output << view.content_tag(:div, ' '.html_safe, + :style => style, + :class => "#{options[:css]} task_done", + :id => html_id) + end + end + # Renders the markers + if options[:markers] + if coords[:start] + style = "" + style << "top:#{params[:top]}px;" + style << "left:#{coords[:start]}px;" + style << "width:15px;" + output << view.content_tag(:div, ' '.html_safe, + :style => style, + :class => "#{options[:css]} marker starting") + end + if coords[:end] + style = "" + style << "top:#{params[:top]}px;" + style << "left:#{coords[:end] + params[:zoom]}px;" + style << "width:15px;" + output << view.content_tag(:div, ' '.html_safe, + :style => style, + :class => "#{options[:css]} marker ending") + end + end + # Renders the label on the right + if options[:label] + style = "" + style << "top:#{params[:top]}px;" + style << "left:#{(coords[:bar_end] || 0) + 8}px;" + style << "width:15px;" + output << view.content_tag(:div, options[:label], + :style => style, + :class => "#{options[:css]} label") + end + # Renders the tooltip + if options[:issue] && coords[:bar_start] && coords[:bar_end] + s = view.content_tag(:span, + view.render_issue_tooltip(options[:issue]).html_safe, + :class => "tip") + style = "" + style << "position: absolute;" + style << "top:#{params[:top]}px;" + style << "left:#{coords[:bar_start]}px;" + style << "width:#{coords[:bar_end] - coords[:bar_start]}px;" + style << "height:12px;" + output << view.content_tag(:div, s.html_safe, + :style => style, + :class => "tooltip") + end + @lines << output + output + end + + def pdf_task(params, coords, options={}) + height = options[:height] || 2 + # Renders the task bar, with progress and late + if coords[:bar_start] && coords[:bar_end] + params[:pdf].SetY(params[:top] + 1.5) + params[:pdf].SetX(params[:subject_width] + coords[:bar_start]) + params[:pdf].SetFillColor(200, 200, 200) + params[:pdf].RDMCell(coords[:bar_end] - coords[:bar_start], height, "", 0, 0, "", 1) + if coords[:bar_late_end] + params[:pdf].SetY(params[:top] + 1.5) + params[:pdf].SetX(params[:subject_width] + coords[:bar_start]) + params[:pdf].SetFillColor(255, 100, 100) + params[:pdf].RDMCell(coords[:bar_late_end] - coords[:bar_start], height, "", 0, 0, "", 1) + end + if coords[:bar_progress_end] + params[:pdf].SetY(params[:top] + 1.5) + params[:pdf].SetX(params[:subject_width] + coords[:bar_start]) + params[:pdf].SetFillColor(90, 200, 90) + params[:pdf].RDMCell(coords[:bar_progress_end] - coords[:bar_start], height, "", 0, 0, "", 1) + end + end + # Renders the markers + if options[:markers] + if coords[:start] + params[:pdf].SetY(params[:top] + 1) + params[:pdf].SetX(params[:subject_width] + coords[:start] - 1) + params[:pdf].SetFillColor(50, 50, 200) + params[:pdf].RDMCell(2, 2, "", 0, 0, "", 1) + end + if coords[:end] + params[:pdf].SetY(params[:top] + 1) + params[:pdf].SetX(params[:subject_width] + coords[:end] - 1) + params[:pdf].SetFillColor(50, 50, 200) + params[:pdf].RDMCell(2, 2, "", 0, 0, "", 1) + end + end + # Renders the label on the right + if options[:label] + params[:pdf].SetX(params[:subject_width] + (coords[:bar_end] || 0) + 5) + params[:pdf].RDMCell(30, 2, options[:label]) + end + end + + def image_task(params, coords, options={}) + height = options[:height] || 6 + # Renders the task bar, with progress and late + if coords[:bar_start] && coords[:bar_end] + params[:image].fill('#aaa') + params[:image].rectangle(params[:subject_width] + coords[:bar_start], + params[:top], + params[:subject_width] + coords[:bar_end], + params[:top] - height) + if coords[:bar_late_end] + params[:image].fill('#f66') + params[:image].rectangle(params[:subject_width] + coords[:bar_start], + params[:top], + params[:subject_width] + coords[:bar_late_end], + params[:top] - height) + end + if coords[:bar_progress_end] + params[:image].fill('#00c600') + params[:image].rectangle(params[:subject_width] + coords[:bar_start], + params[:top], + params[:subject_width] + coords[:bar_progress_end], + params[:top] - height) + end + end + # Renders the markers + if options[:markers] + if coords[:start] + x = params[:subject_width] + coords[:start] + y = params[:top] - height / 2 + params[:image].fill('blue') + params[:image].polygon(x - 4, y, x, y - 4, x + 4, y, x, y + 4) + end + if coords[:end] + x = params[:subject_width] + coords[:end] + params[:zoom] + y = params[:top] - height / 2 + params[:image].fill('blue') + params[:image].polygon(x - 4, y, x, y - 4, x + 4, y, x, y + 4) + end + end + # Renders the label on the right + if options[:label] + params[:image].fill('black') + params[:image].text(params[:subject_width] + (coords[:bar_end] || 0) + 5, + params[:top] + 1, + options[:label]) + end + end + end + end +end diff --git a/lib/redmine/helpers/time_report.rb b/lib/redmine/helpers/time_report.rb new file mode 100644 index 00000000..09093dc9 --- /dev/null +++ b/lib/redmine/helpers/time_report.rb @@ -0,0 +1,151 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +module Redmine + module Helpers + class TimeReport + attr_reader :criteria, :columns, :hours, :total_hours, :periods + + def initialize(project, issue, criteria, columns, time_entry_scope) + @project = project + @issue = issue + + @criteria = criteria || [] + @criteria = @criteria.select{|criteria| available_criteria.has_key? criteria} + @criteria.uniq! + @criteria = @criteria[0,3] + + @columns = (columns && %w(year month week day).include?(columns)) ? columns : 'month' + @scope = time_entry_scope + + run + end + + def available_criteria + @available_criteria || load_available_criteria + end + + private + + def run + unless @criteria.empty? + time_columns = %w(tyear tmonth tweek spent_on) + @hours = [] + @scope.sum(:hours, + :include => [:issue, :activity], + :group => @criteria.collect{|criteria| @available_criteria[criteria][:sql]} + time_columns, + :joins => @criteria.collect{|criteria| @available_criteria[criteria][:joins]}.compact).each do |hash, hours| + h = {'hours' => hours} + (@criteria + time_columns).each_with_index do |name, i| + h[name] = hash[i] + end + @hours << h + end + + @hours.each do |row| + case @columns + when 'year' + row['year'] = row['tyear'] + when 'month' + row['month'] = "#{row['tyear']}-#{row['tmonth']}" + when 'week' + row['week'] = "#{row['spent_on'].cwyear}-#{row['tweek']}" + when 'day' + row['day'] = "#{row['spent_on']}" + end + end + + min = @hours.collect {|row| row['spent_on']}.min + @from = min ? min.to_date : Date.today + + max = @hours.collect {|row| row['spent_on']}.max + @to = max ? max.to_date : Date.today + + @total_hours = @hours.inject(0) {|s,k| s = s + k['hours'].to_f} + + @periods = [] + # Date#at_beginning_of_ not supported in Rails 1.2.x + date_from = @from.to_time + # 100 columns max + while date_from <= @to.to_time && @periods.length < 100 + case @columns + when 'year' + @periods << "#{date_from.year}" + date_from = (date_from + 1.year).at_beginning_of_year + when 'month' + @periods << "#{date_from.year}-#{date_from.month}" + date_from = (date_from + 1.month).at_beginning_of_month + when 'week' + @periods << "#{date_from.to_date.cwyear}-#{date_from.to_date.cweek}" + date_from = (date_from + 7.day).at_beginning_of_week + when 'day' + @periods << "#{date_from.to_date}" + date_from = date_from + 1.day + end + end + end + end + + def load_available_criteria + @available_criteria = { 'project' => {:sql => "#{TimeEntry.table_name}.project_id", + :klass => Project, + :label => :label_project}, + 'status' => {:sql => "#{Issue.table_name}.status_id", + :klass => IssueStatus, + :label => :field_status}, + 'version' => {:sql => "#{Issue.table_name}.fixed_version_id", + :klass => Version, + :label => :label_version}, + 'category' => {:sql => "#{Issue.table_name}.category_id", + :klass => IssueCategory, + :label => :field_category}, + 'user' => {:sql => "#{TimeEntry.table_name}.user_id", + :klass => User, + :label => :label_user}, + 'tracker' => {:sql => "#{Issue.table_name}.tracker_id", + :klass => Tracker, + :label => :label_tracker}, + 'activity' => {:sql => "#{TimeEntry.table_name}.activity_id", + :klass => TimeEntryActivity, + :label => :label_activity}, + 'issue' => {:sql => "#{TimeEntry.table_name}.issue_id", + :klass => Issue, + :label => :label_issue} + } + + # Add time entry custom fields + custom_fields = TimeEntryCustomField.all + # Add project custom fields + custom_fields += ProjectCustomField.all + # Add issue custom fields + custom_fields += (@project.nil? ? IssueCustomField.for_all : @project.all_issue_custom_fields) + # Add time entry activity custom fields + custom_fields += TimeEntryActivityCustomField.all + + # Add list and boolean custom fields as available criteria + custom_fields.select {|cf| %w(list bool).include? cf.field_format }.each do |cf| + @available_criteria["cf_#{cf.id}"] = {:sql => "#{cf.join_alias}.value", + :joins => cf.join_for_order_statement, + :format => cf.field_format, + :label => cf.name} + end + + @available_criteria + end + end + end +end diff --git a/lib/redmine/hook.rb b/lib/redmine/hook.rb new file mode 100644 index 00000000..e5a2695d --- /dev/null +++ b/lib/redmine/hook.rb @@ -0,0 +1,166 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +module Redmine + module Hook + @@listener_classes = [] + @@listeners = nil + @@hook_listeners = {} + + class << self + # Adds a listener class. + # Automatically called when a class inherits from Redmine::Hook::Listener. + def add_listener(klass) + raise "Hooks must include Singleton module." unless klass.included_modules.include?(Singleton) + @@listener_classes << klass + clear_listeners_instances + end + + # Returns all the listerners instances. + def listeners + @@listeners ||= @@listener_classes.collect {|listener| listener.instance} + end + + # Returns the listeners instances for the given hook. + def hook_listeners(hook) + @@hook_listeners[hook] ||= listeners.select {|listener| listener.respond_to?(hook)} + end + + # Clears all the listeners. + def clear_listeners + @@listener_classes = [] + clear_listeners_instances + end + + # Clears all the listeners instances. + def clear_listeners_instances + @@listeners = nil + @@hook_listeners = {} + end + + # Calls a hook. + # Returns the listeners response. + def call_hook(hook, context={}) + [].tap do |response| + hls = hook_listeners(hook) + if hls.any? + hls.each {|listener| response << listener.send(hook, context)} + end + end + end + end + + # Base class for hook listeners. + class Listener + include Singleton + include Redmine::I18n + + # Registers the listener + def self.inherited(child) + Redmine::Hook.add_listener(child) + super + end + + end + + # Listener class used for views hooks. + # Listeners that inherit this class will include various helpers by default. + class ViewListener < Listener + include ERB::Util + include ActionView::Helpers::TagHelper + include ActionView::Helpers::FormHelper + include ActionView::Helpers::FormTagHelper + include ActionView::Helpers::FormOptionsHelper + include ActionView::Helpers::JavaScriptHelper + include ActionView::Helpers::NumberHelper + include ActionView::Helpers::UrlHelper + include ActionView::Helpers::AssetTagHelper + include ActionView::Helpers::TextHelper + include Rails.application.routes.url_helpers + include ApplicationHelper + + # Default to creating links using only the path. Subclasses can + # change this default as needed + def self.default_url_options + {:only_path => true } + end + + # Helper method to directly render a partial using the context: + # + # class MyHook < Redmine::Hook::ViewListener + # render_on :view_issues_show_details_bottom, :partial => "show_more_data" + # end + # + def self.render_on(hook, options={}) + define_method hook do |context| + if context[:hook_caller].respond_to?(:render) + context[:hook_caller].send(:render, {:locals => context}.merge(options)) + elsif context[:controller].is_a?(ActionController::Base) + context[:controller].send(:render_to_string, {:locals => context}.merge(options)) + else + raise "Cannot render #{self.name} hook from #{context[:hook_caller].class.name}" + end + end + end + + def controller + nil + end + + def config + ActionController::Base.config + end + end + + # Helper module included in ApplicationHelper and ActionController so that + # hooks can be called in views like this: + # + # <%= call_hook(:some_hook) %> + # <%= call_hook(:another_hook, :foo => 'bar') %> + # + # Or in controllers like: + # call_hook(:some_hook) + # call_hook(:another_hook, :foo => 'bar') + # + # Hooks added to views will be concatenated into a string. Hooks added to + # controllers will return an array of results. + # + # Several objects are automatically added to the call context: + # + # * project => current project + # * request => Request instance + # * controller => current Controller instance + # * hook_caller => object that called the hook + # + module Helper + def call_hook(hook, context={}) + if is_a?(ActionController::Base) + default_context = {:controller => self, :project => @project, :request => request, :hook_caller => self} + Redmine::Hook.call_hook(hook, default_context.merge(context)) + else + default_context = { :project => @project, :hook_caller => self } + default_context[:controller] = controller if respond_to?(:controller) + default_context[:request] = request if respond_to?(:request) + Redmine::Hook.call_hook(hook, default_context.merge(context)).join(' ').html_safe + end + end + end + end +end + +ApplicationHelper.send(:include, Redmine::Hook::Helper) +ActionController::Base.send(:include, Redmine::Hook::Helper) diff --git a/lib/redmine/i18n.rb b/lib/redmine/i18n.rb new file mode 100644 index 00000000..c5922d95 --- /dev/null +++ b/lib/redmine/i18n.rb @@ -0,0 +1,184 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +module Redmine + module I18n + def self.included(base) + base.extend Redmine::I18n + end + + def l(*args) + case args.size + when 1 + ::I18n.t(*args) + when 2 + if args.last.is_a?(Hash) + ::I18n.t(*args) + elsif args.last.is_a?(String) + ::I18n.t(args.first, :value => args.last) + else + ::I18n.t(args.first, :count => args.last) + end + else + raise "Translation string with multiple values: #{args.first}" + end + end + + def l_or_humanize(s, options={}) + k = "#{options[:prefix]}#{s}".to_sym + ::I18n.t(k, :default => s.to_s.humanize) + end + + def l_hours(hours) + hours = hours.to_f + l((hours < 2.0 ? :label_f_hour : :label_f_hour_plural), :value => ("%.2f" % hours.to_f)) + end + + def ll(lang, str, value=nil) + ::I18n.t(str.to_s, :value => value, :locale => lang.to_s.gsub(%r{(.+)\-(.+)$}) { "#{$1}-#{$2.upcase}" }) + end + + def format_date(date) + return nil unless date + options = {} + options[:format] = Setting.date_format unless Setting.date_format.blank? + options[:locale] = User.current.language unless User.current.language.blank? + ::I18n.l(date.to_date, options) + end + + def format_time(time, include_date = true) + return nil unless time + options = {} + options[:format] = (Setting.time_format.blank? ? :time : Setting.time_format) + options[:locale] = User.current.language unless User.current.language.blank? + time = time.to_time if time.is_a?(String) + zone = User.current.time_zone + local = zone ? time.in_time_zone(zone) : (time.utc? ? time.localtime : time) + (include_date ? "#{format_date(local)} " : "") + ::I18n.l(local, options) + end + + def day_name(day) + ::I18n.t('date.day_names')[day % 7] + end + + def day_letter(day) + ::I18n.t('date.abbr_day_names')[day % 7].first + end + + def month_name(month) + ::I18n.t('date.month_names')[month] + end + + def valid_languages + ::I18n.available_locales + end + + # Returns an array of languages names and code sorted by names, example: + # [["Deutsch", "de"], ["English", "en"] ...] + # + # The result is cached to prevent from loading all translations files. + def languages_options + ActionController::Base.cache_store.fetch "i18n/languages_options" do + valid_languages.map {|lang| [ll(lang.to_s, :general_lang_name), lang.to_s]}.sort {|x,y| x.first <=> y.first } + end + end + + def find_language(lang) + @@languages_lookup = valid_languages.inject({}) {|k, v| k[v.to_s.downcase] = v; k } + @@languages_lookup[lang.to_s.downcase] + end + + def set_language_if_valid(lang) + if l = find_language(lang) + ::I18n.locale = l + end + end + + def current_language + ::I18n.locale + end + + # Custom backend based on I18n::Backend::Simple with the following changes: + # * lazy loading of translation files + # * available_locales are determined by looking at translation file names + class Backend + (class << self; self; end).class_eval { public :include } + + module Implementation + include ::I18n::Backend::Base + + # Stores translations for the given locale in memory. + # This uses a deep merge for the translations hash, so existing + # translations will be overwritten by new ones only at the deepest + # level of the hash. + def store_translations(locale, data, options = {}) + locale = locale.to_sym + translations[locale] ||= {} + data = data.deep_symbolize_keys + translations[locale].deep_merge!(data) + end + + # Get available locales from the translations filenames + def available_locales + @available_locales ||= ::I18n.load_path.map {|path| File.basename(path, '.*')}.uniq.sort.map(&:to_sym) + end + + # Clean up translations + def reload! + @translations = nil + @available_locales = nil + super + end + + protected + + def init_translations(locale) + locale = locale.to_s + paths = ::I18n.load_path.select {|path| File.basename(path, '.*') == locale} + load_translations(paths) + translations[locale] ||= {} + end + + def translations + @translations ||= {} + end + + # Looks up a translation from the translations hash. Returns nil if + # eiher key is nil, or locale, scope or key do not exist as a key in the + # nested translations hash. Splits keys or scopes containing dots + # into multiple keys, i.e. currency.format is regarded the same as + # %w(currency format). + def lookup(locale, key, scope = [], options = {}) + init_translations(locale) unless translations.key?(locale) + keys = ::I18n.normalize_keys(locale, key, scope, options[:separator]) + + keys.inject(translations) do |result, _key| + _key = _key.to_sym + return nil unless result.is_a?(Hash) && result.has_key?(_key) + result = result[_key] + result = resolve(locale, _key, result, options.merge(:scope => nil)) if result.is_a?(Symbol) + result + end + end + end + + include Implementation + # Adds fallback to default locale for untranslated strings + include ::I18n::Backend::Fallbacks + end + end +end diff --git a/lib/redmine/imap.rb b/lib/redmine/imap.rb new file mode 100644 index 00000000..6e15c57e --- /dev/null +++ b/lib/redmine/imap.rb @@ -0,0 +1,60 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +require 'net/imap' + +module Redmine + module IMAP + class << self + def check(imap_options={}, options={}) + host = imap_options[:host] || '127.0.0.1' + port = imap_options[:port] || '143' + ssl = !imap_options[:ssl].nil? + folder = imap_options[:folder] || 'INBOX' + + imap = Net::IMAP.new(host, port, ssl) + imap.login(imap_options[:username], imap_options[:password]) unless imap_options[:username].nil? + imap.select(folder) + imap.search(['NOT', 'SEEN']).each do |message_id| + msg = imap.fetch(message_id,'RFC822')[0].attr['RFC822'] + logger.debug "Receiving message #{message_id}" if logger && logger.debug? + if MailHandler.receive(msg, options) + logger.debug "Message #{message_id} successfully received" if logger && logger.debug? + if imap_options[:move_on_success] + imap.copy(message_id, imap_options[:move_on_success]) + end + imap.store(message_id, "+FLAGS", [:Seen, :Deleted]) + else + logger.debug "Message #{message_id} can not be processed" if logger && logger.debug? + imap.store(message_id, "+FLAGS", [:Seen]) + if imap_options[:move_on_failure] + imap.copy(message_id, imap_options[:move_on_failure]) + imap.store(message_id, "+FLAGS", [:Deleted]) + end + end + end + imap.expunge + end + + private + + def logger + ::Rails.logger + end + end + end +end diff --git a/lib/redmine/info.rb b/lib/redmine/info.rb new file mode 100644 index 00000000..98df8d20 --- /dev/null +++ b/lib/redmine/info.rb @@ -0,0 +1,29 @@ +module Redmine + module Info + class << self + def app_name; 'Redmine' end + def url; 'http://www.redmine.org/' end + def help_url; 'http://www.redmine.org/guide' end + def versioned_name; "#{app_name} #{Redmine::VERSION}" end + + def environment + s = "Environment:\n" + s << [ + ["Redmine version", Redmine::VERSION], + ["Ruby version", "#{RUBY_VERSION} (#{RUBY_PLATFORM})"], + ["Rails version", Rails::VERSION::STRING], + ["Environment", Rails.env], + ["Database adapter", ActiveRecord::Base.connection.adapter_name] + ].map {|info| " %-40s %s" % info}.join("\n") + s << "\nRedmine plugins:\n" + + plugins = Redmine::Plugin.all + if plugins.any? + s << plugins.map {|plugin| " %-40s %s" % [plugin.id.to_s, plugin.version.to_s]}.join("\n") + else + s << " no plugin installed" + end + end + end + end +end diff --git a/lib/redmine/menu_manager.rb b/lib/redmine/menu_manager.rb new file mode 100644 index 00000000..25974ed8 --- /dev/null +++ b/lib/redmine/menu_manager.rb @@ -0,0 +1,435 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +module Redmine + module MenuManager + class MenuError < StandardError #:nodoc: + end + + module MenuController + def self.included(base) + base.extend(ClassMethods) + end + + module ClassMethods + @@menu_items = Hash.new {|hash, key| hash[key] = {:default => key, :actions => {}}} + mattr_accessor :menu_items + + # Set the menu item name for a controller or specific actions + # Examples: + # * menu_item :tickets # => sets the menu name to :tickets for the whole controller + # * menu_item :tickets, :only => :list # => sets the menu name to :tickets for the 'list' action only + # * menu_item :tickets, :only => [:list, :show] # => sets the menu name to :tickets for 2 actions only + # + # The default menu item name for a controller is controller_name by default + # Eg. the default menu item name for ProjectsController is :projects + def menu_item(id, options = {}) + if actions = options[:only] + actions = [] << actions unless actions.is_a?(Array) + actions.each {|a| menu_items[controller_name.to_sym][:actions][a.to_sym] = id} + else + menu_items[controller_name.to_sym][:default] = id + end + end + end + + def menu_items + self.class.menu_items + end + + # Returns the menu item name according to the current action + def current_menu_item + @current_menu_item ||= menu_items[controller_name.to_sym][:actions][action_name.to_sym] || + menu_items[controller_name.to_sym][:default] + end + + # Redirects user to the menu item of the given project + # Returns false if user is not authorized + def redirect_to_project_menu_item(project, name) + item = Redmine::MenuManager.items(:project_menu).detect {|i| i.name.to_s == name.to_s} + if item && User.current.allowed_to?(item.url, project) && (item.condition.nil? || item.condition.call(project)) + redirect_to({item.param => project}.merge(item.url)) + return true + end + false + end + end + + module MenuHelper + # Returns the current menu item name + def current_menu_item + controller.current_menu_item + end + + # Renders the application main menu + def render_main_menu(project) + render_menu((project && !project.new_record?) ? :project_menu : :application_menu, project) + end + + def display_main_menu?(project) + menu_name = project && !project.new_record? ? :project_menu : :application_menu + Redmine::MenuManager.items(menu_name).children.present? + end + + def render_menu(menu, project=nil) + links = [] + menu_items_for(menu, project) do |node| + links << render_menu_node(node, project) + end + links.empty? ? nil : content_tag('ul', links.join("\n").html_safe) + end + + def render_menu_node(node, project=nil) + if node.children.present? || !node.child_menus.nil? + return render_menu_node_with_children(node, project) + else + caption, url, selected = extract_node_details(node, project) + return content_tag('li', + render_single_menu_node(node, caption, url, selected)) + end + end + + def render_menu_node_with_children(node, project=nil) + caption, url, selected = extract_node_details(node, project) + + html = [].tap do |html| + html << '
    13. ' + # Parent + html << render_single_menu_node(node, caption, url, selected) + + # Standard children + standard_children_list = "".html_safe.tap do |child_html| + node.children.each do |child| + child_html << render_menu_node(child, project) + end + end + + html << content_tag(:ul, standard_children_list, :class => 'menu-children') unless standard_children_list.empty? + + # Unattached children + unattached_children_list = render_unattached_children_menu(node, project) + html << content_tag(:ul, unattached_children_list, :class => 'menu-children unattached') unless unattached_children_list.blank? + + html << '
    14. ' + end + return html.join("\n").html_safe + end + + # Returns a list of unattached children menu items + def render_unattached_children_menu(node, project) + return nil unless node.child_menus + + "".html_safe.tap do |child_html| + unattached_children = node.child_menus.call(project) + # Tree nodes support #each so we need to do object detection + if unattached_children.is_a? Array + unattached_children.each do |child| + child_html << content_tag(:li, render_unattached_menu_item(child, project)) + end + else + raise MenuError, ":child_menus must be an array of MenuItems" + end + end + end + + def render_single_menu_node(item, caption, url, selected) + link_to(h(caption), url, item.html_options(:selected => selected)) + end + + def render_unattached_menu_item(menu_item, project) + raise MenuError, ":child_menus must be an array of MenuItems" unless menu_item.is_a? MenuItem + + if User.current.allowed_to?(menu_item.url, project) + link_to(h(menu_item.caption), + menu_item.url, + menu_item.html_options) + end + end + + def menu_items_for(menu, project=nil) + items = [] + Redmine::MenuManager.items(menu).root.children.each do |node| + if allowed_node?(node, User.current, project) + if block_given? + yield node + else + items << node # TODO: not used? + end + end + end + return block_given? ? nil : items + end + + def extract_node_details(node, project=nil) + item = node + url = case item.url + when Hash + project.nil? ? item.url : {item.param => project}.merge(item.url) + when Symbol + send(item.url) + else + item.url + end + caption = item.caption(project) + return [caption, url, (current_menu_item == item.name)] + end + + # Checks if a user is allowed to access the menu item by: + # + # * Checking the url target (project only) + # * Checking the conditions of the item + def allowed_node?(node, user, project) + if project && user && !user.allowed_to?(node.url, project) + return false + end + if node.condition && !node.condition.call(project) + # Condition that doesn't pass + return false + end + return true + end + end + + class << self + def map(menu_name) + @items ||= {} + mapper = Mapper.new(menu_name.to_sym, @items) + if block_given? + yield mapper + else + mapper + end + end + + def items(menu_name) + @items[menu_name.to_sym] || MenuNode.new(:root, {}) + end + end + + class Mapper + def initialize(menu, items) + items[menu] ||= MenuNode.new(:root, {}) + @menu = menu + @menu_items = items[menu] + end + + # Adds an item at the end of the menu. Available options: + # * param: the parameter name that is used for the project id (default is :id) + # * if: a Proc that is called before rendering the item, the item is displayed only if it returns true + # * caption that can be: + # * a localized string Symbol + # * a String + # * a Proc that can take the project as argument + # * before, after: specify where the menu item should be inserted (eg. :after => :activity) + # * parent: menu item will be added as a child of another named menu (eg. :parent => :issues) + # * children: a Proc that is called before rendering the item. The Proc should return an array of MenuItems, which will be added as children to this item. + # eg. :children => Proc.new {|project| [Redmine::MenuManager::MenuItem.new(...)] } + # * last: menu item will stay at the end (eg. :last => true) + # * html_options: a hash of html options that are passed to link_to + def push(name, url, options={}) + options = options.dup + + if options[:parent] + subtree = self.find(options[:parent]) + if subtree + target_root = subtree + else + target_root = @menu_items.root + end + + else + target_root = @menu_items.root + end + + # menu item position + if first = options.delete(:first) + target_root.prepend(MenuItem.new(name, url, options)) + elsif before = options.delete(:before) + + if exists?(before) + target_root.add_at(MenuItem.new(name, url, options), position_of(before)) + else + target_root.add(MenuItem.new(name, url, options)) + end + + elsif after = options.delete(:after) + + if exists?(after) + target_root.add_at(MenuItem.new(name, url, options), position_of(after) + 1) + else + target_root.add(MenuItem.new(name, url, options)) + end + + elsif options[:last] # don't delete, needs to be stored + target_root.add_last(MenuItem.new(name, url, options)) + else + target_root.add(MenuItem.new(name, url, options)) + end + end + + # Removes a menu item + def delete(name) + if found = self.find(name) + @menu_items.remove!(found) + end + end + + # Checks if a menu item exists + def exists?(name) + @menu_items.any? {|node| node.name == name} + end + + def find(name) + @menu_items.find {|node| node.name == name} + end + + def position_of(name) + @menu_items.each do |node| + if node.name == name + return node.position + end + end + end + end + + class MenuNode + include Enumerable + attr_accessor :parent + attr_reader :last_items_count, :name + + def initialize(name, content = nil) + @name = name + @children = [] + @last_items_count = 0 + end + + def children + if block_given? + @children.each {|child| yield child} + else + @children + end + end + + # Returns the number of descendants + 1 + def size + @children.inject(1) {|sum, node| sum + node.size} + end + + def each &block + yield self + children { |child| child.each(&block) } + end + + # Adds a child at first position + def prepend(child) + add_at(child, 0) + end + + # Adds a child at given position + def add_at(child, position) + raise "Child already added" if find {|node| node.name == child.name} + + @children = @children.insert(position, child) + child.parent = self + child + end + + # Adds a child as last child + def add_last(child) + add_at(child, -1) + @last_items_count += 1 + child + end + + # Adds a child + def add(child) + position = @children.size - @last_items_count + add_at(child, position) + end + alias :<< :add + + # Removes a child + def remove!(child) + @children.delete(child) + @last_items_count -= +1 if child && child.last + child.parent = nil + child + end + + # Returns the position for this node in it's parent + def position + self.parent.children.index(self) + end + + # Returns the root for this node + def root + root = self + root = root.parent while root.parent + root + end + end + + class MenuItem < MenuNode + include Redmine::I18n + attr_reader :name, :url, :param, :condition, :parent, :child_menus, :last + + def initialize(name, url, options) + raise ArgumentError, "Invalid option :if for menu item '#{name}'" if options[:if] && !options[:if].respond_to?(:call) + raise ArgumentError, "Invalid option :html for menu item '#{name}'" if options[:html] && !options[:html].is_a?(Hash) + raise ArgumentError, "Cannot set the :parent to be the same as this item" if options[:parent] == name.to_sym + raise ArgumentError, "Invalid option :children for menu item '#{name}'" if options[:children] && !options[:children].respond_to?(:call) + @name = name + @url = url + @condition = options[:if] + @param = options[:param] || :id + @caption = options[:caption] + @html_options = options[:html] || {} + # Adds a unique class to each menu item based on its name + @html_options[:class] = [@html_options[:class], @name.to_s.dasherize].compact.join(' ') + @parent = options[:parent] + @child_menus = options[:children] + @last = options[:last] || false + super @name.to_sym + end + + def caption(project=nil) + if @caption.is_a?(Proc) + c = @caption.call(project).to_s + c = @name.to_s.humanize if c.blank? + c + else + if @caption.nil? + l_or_humanize(name, :prefix => 'label_') + else + @caption.is_a?(Symbol) ? l(@caption) : @caption + end + end + end + + def html_options(options={}) + if options[:selected] + o = @html_options.dup + o[:class] += ' selected' + o + else + @html_options + end + end + end + end +end diff --git a/lib/redmine/mime_type.rb b/lib/redmine/mime_type.rb new file mode 100644 index 00000000..d902c995 --- /dev/null +++ b/lib/redmine/mime_type.rb @@ -0,0 +1,98 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +module Redmine + module MimeType + + MIME_TYPES = { + 'text/plain' => 'txt,tpl,properties,patch,diff,ini,readme,install,upgrade', + 'text/css' => 'css', + 'text/html' => 'html,htm,xhtml', + 'text/jsp' => 'jsp', + 'text/x-c' => 'c,cpp,cc,h,hh', + 'text/x-csharp' => 'cs', + 'text/x-java' => 'java', + 'text/x-html-template' => 'rhtml', + 'text/x-perl' => 'pl,pm', + 'text/x-php' => 'php,php3,php4,php5', + 'text/x-python' => 'py', + 'text/x-ruby' => 'rb,rbw,ruby,rake,erb', + 'text/x-csh' => 'csh', + 'text/x-sh' => 'sh', + 'text/xml' => 'xml,xsd,mxml', + 'text/yaml' => 'yml,yaml', + 'text/csv' => 'csv', + 'text/x-po' => 'po', + 'image/gif' => 'gif', + 'image/jpeg' => 'jpg,jpeg,jpe', + 'image/png' => 'png', + 'image/tiff' => 'tiff,tif', + 'image/x-ms-bmp' => 'bmp', + 'image/x-xpixmap' => 'xpm', + 'image/svg+xml'=> 'svg', + 'application/javascript' => 'js', + 'application/pdf' => 'pdf', + 'application/rtf' => 'rtf', + 'application/msword' => 'doc', + 'application/vnd.ms-excel' => 'xls', + 'application/vnd.ms-powerpoint' => 'ppt,pps', + 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' => 'docx', + 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' => 'xlsx', + 'application/vnd.openxmlformats-officedocument.presentationml.presentation' => 'pptx', + 'application/vnd.openxmlformats-officedocument.presentationml.slideshow' => 'ppsx', + 'application/vnd.oasis.opendocument.spreadsheet' => 'ods', + 'application/vnd.oasis.opendocument.text' => 'odt', + 'application/vnd.oasis.opendocument.presentation' => 'odp', + 'application/x-7z-compressed' => '7z', + 'application/x-rar-compressed' => 'rar', + 'application/x-tar' => 'tar', + 'application/zip' => 'zip', + 'application/x-gzip' => 'gz', + }.freeze + + EXTENSIONS = MIME_TYPES.inject({}) do |map, (type, exts)| + exts.split(',').each {|ext| map[ext.strip] = type} + map + end + + # returns mime type for name or nil if unknown + def self.of(name) + return nil unless name + m = name.to_s.match(/(^|\.)([^\.]+)$/) + EXTENSIONS[m[2].downcase] if m + end + + # Returns the css class associated to + # the mime type of name + def self.css_class_of(name) + mime = of(name) + mime && mime.gsub('/', '-') + end + + def self.main_mimetype_of(name) + mimetype = of(name) + mimetype.split('/').first if mimetype + end + + # return true if mime-type for name is type/* + # otherwise false + def self.is_type?(type, name) + main_mimetype = main_mimetype_of(name) + type.to_s == main_mimetype + end + end +end diff --git a/lib/redmine/notifiable.rb b/lib/redmine/notifiable.rb new file mode 100644 index 00000000..88ca9d77 --- /dev/null +++ b/lib/redmine/notifiable.rb @@ -0,0 +1,26 @@ +module Redmine + class Notifiable < Struct.new(:name, :parent) + + def to_s + name + end + + # TODO: Plugin API for adding a new notification? + def self.all + notifications = [] + notifications << Notifiable.new('issue_added') + notifications << Notifiable.new('issue_updated') + notifications << Notifiable.new('issue_note_added', 'issue_updated') + notifications << Notifiable.new('issue_status_updated', 'issue_updated') + notifications << Notifiable.new('issue_priority_updated', 'issue_updated') + notifications << Notifiable.new('news_added') + notifications << Notifiable.new('news_comment_added') + notifications << Notifiable.new('document_added') + notifications << Notifiable.new('file_added') + notifications << Notifiable.new('message_posted') + notifications << Notifiable.new('wiki_content_added') + notifications << Notifiable.new('wiki_content_updated') + notifications + end + end +end diff --git a/lib/redmine/pagination.rb b/lib/redmine/pagination.rb new file mode 100644 index 00000000..9220b911 --- /dev/null +++ b/lib/redmine/pagination.rb @@ -0,0 +1,300 @@ +# encoding: utf-8 +# +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +module Redmine + module Pagination + class Paginator + attr_reader :item_count, :per_page, :page, :page_param + def initialize(*args) + if args.first.is_a?(ActionController::Base) + args.shift + ActiveSupport::Deprecation.warn "Paginator no longer takes a controller instance as the first argument. Remove it from #new arguments." + end + item_count, per_page, page, page_param = *args + + @item_count = item_count + @per_page = per_page + page = (page || 1).to_i + if page < 1 + page = 1 + end + @page = page + @page_param = page_param || :page + end + + def offset + (page - 1) * per_page + end + + def first_page + if item_count > 0 + 1 + end + end + + def previous_page + if page > 1 + page - 1 + end + end + + def next_page + if last_item < item_count + page + 1 + end + end + + def last_page + if item_count > 0 + (item_count - 1) / per_page + 1 + end + end + + def first_item + item_count == 0 ? 0 : (offset + 1) + end + + def last_item + l = first_item + per_page - 1 + l > item_count ? item_count : l + end + + def linked_pages + pages = [] + if item_count > 0 + pages += [first_page, page, last_page] + pages += ((page-2)..(page+2)).to_a.select {|p| p > first_page && p < last_page} + end + pages = pages.compact.uniq.sort + if pages.size > 1 + pages + else + [] + end + end + + def items_per_page + ActiveSupport::Deprecation.warn "Paginator#items_per_page will be removed. Use #per_page instead." + per_page + end + + def current + ActiveSupport::Deprecation.warn "Paginator#current will be removed. Use .offset instead of .current.offset." + self + end + end + + # Paginates the given scope or model. Returns a Paginator instance and + # the collection of objects for the current page. + # + # Options: + # :parameter name of the page parameter + # + # Examples: + # @user_pages, @users = paginate User.where(:status => 1) + # + def paginate(scope, options={}) + options = options.dup + finder_options = options.extract!( + :conditions, + :order, + :joins, + :include, + :select + ) + if scope.is_a?(Symbol) || finder_options.values.compact.any? + return deprecated_paginate(scope, finder_options, options) + end + + paginator = paginator(scope.count, options) + collection = scope.limit(paginator.per_page).offset(paginator.offset).to_a + + return paginator, collection + end + + def deprecated_paginate(arg, finder_options, options={}) + ActiveSupport::Deprecation.warn "#paginate with a Symbol and/or find options is depreceted and will be removed. Use a scope instead." + klass = arg.is_a?(Symbol) ? arg.to_s.classify.constantize : arg + scope = klass.scoped(finder_options) + paginate(scope, options) + end + + def paginator(item_count, options={}) + options.assert_valid_keys :parameter, :per_page + + page_param = options[:parameter] || :page + page = (params[page_param] || 1).to_i + per_page = options[:per_page] || per_page_option + Paginator.new(item_count, per_page, page, page_param) + end + + module Helper + include Redmine::I18n + # Renders the pagination links for the given paginator. + # + # Options: + # :per_page_links if set to false, the "Per page" links are not rendered + # + def pagination_links_full(*args) + pagination_links_each(*args) do |text, parameters, options| + if block_given? + yield text, parameters, options + else + link_to text, params.merge(parameters), options + end + end + end + + # Yields the given block with the text and parameters + # for each pagination link and returns a string that represents the links + # def pagination_links_each(paginator, count=nil, options={}, &block) + # options.assert_valid_keys :per_page_links + # + # per_page_links = options.delete(:per_page_links) + # per_page_links = false if count.nil? + # page_param = paginator.page_param + # + # html = '' + # if paginator.previous_page + # # \xc2\xab(utf-8) = « + # text = "\xc2\xab " + l(:label_previous) + # html << yield(text, {page_param => paginator.previous_page}, :class => 'previous') + ' ' + # end + # + # previous = nil + # paginator.linked_pages.each do |page| + # if previous && previous != page - 1 + # html << content_tag('span', '...', :class => 'spacer') + ' ' + # end + # if page == paginator.page + # html << content_tag('span', page.to_s, :class => 'current page') + # else + # html << yield(page.to_s, {page_param => page}, :class => 'page') + # end + # html << ' ' + # previous = page + # end + # + # if paginator.next_page + # # \xc2\xbb(utf-8) = » + # text = l(:label_next) + " \xc2\xbb" + # html << yield(text, {page_param => paginator.next_page}, :class => 'next') + ' ' + # end + # + # html << content_tag('span', "(#{paginator.first_item}-#{paginator.last_item}/#{paginator.item_count})", :class => 'items') + ' ' + # + # if per_page_links != false && links = per_page_links(paginator, &block) + # html << content_tag('span', links.to_s, :class => 'per-page') + # end + # + # html.html_safe + # end + #Added by Nie guanghui + #Designed for pagination. + def pagination_links_each(paginator, count=nil, options={}, &block) + options.assert_valid_keys :per_page_links + + per_page_links = options.delete(:per_page_links) + per_page_links = false if count.nil? + page_param = paginator.page_param + + html = '' + if paginator.previous_page + # \xc2\xab(utf-8) = « + text = "\xc2\xab " + l(:label_previous) + html << '
    15. ' << yield(text, {page_param => paginator.previous_page}, :class => 'previous') << '
    16. ' + ' ' + end + unless paginator.previous_page + if paginator.next_page + text = "\xc2\xab " + l(:label_previous) + html << '
    17. ' << yield(text, {page_param => paginator.previous_page}, :class => 'previous') << '
    18. ' + ' ' + end + end + + previous = nil + paginator.linked_pages.each do |page| + if previous && previous != page - 1 + html << '
    19. ' << content_tag('span', '...', :class => 'spacer') << '
    20. ' + ' ' + end + if page == paginator.page + html << '
    21. ' << content_tag('span', page.to_s, :class => 'current-page') << '
    22. ' + else + html << '
    23. ' << yield(page.to_s, {page_param => page}, :class => 'page') << '
    24. ' + end + html << ' ' + previous = page + end + + if paginator.next_page + # \xc2\xbb(utf-8) = » + text = l(:label_next) + " \xc2\xbb" + html << '
    25. ' << yield(text, {page_param => paginator.next_page}, :class => 'next') << '
    26. ' + ' ' + end + + unless paginator.next_page + if paginator.previous_page + # \xc2\xbb(utf-8) = » + text = l(:label_front) + " \xc2\xbb" + html << "
    27. " << yield(text, {page_param => paginator.next_page}, :class => 'next') << "
    28. " + ' ' + end + end + + # html << content_tag('span', "(#{paginator.first_item}-#{paginator.last_item}/#{paginator.item_count})", :class => 'items') + ' ' + # + # if per_page_links != false && links = per_page_links(paginator, &block) + # html << content_tag('span', links.to_s, :class => 'per-page') + # end + + html.html_safe + end + + # Renders the "Per page" links. + def per_page_links(paginator, &block) + values = per_page_options(paginator.per_page, paginator.item_count) + if values.any? + links = values.collect do |n| + if n == paginator.per_page + content_tag('span', n.to_s) + else + yield(n, :per_page => n, paginator.page_param => nil) + end + end + l(:label_display_per_page, links.join(', ')).html_safe + end + end + + def per_page_options(selected=nil, item_count=nil) + options = Setting.per_page_options_array + if item_count && options.any? + if item_count > options.first + max = options.detect {|value| value >= item_count} || item_count + else + max = item_count + end + options = options.select {|value| value <= max || value == selected} + end + if options.empty? || (options.size == 1 && options.first == selected) + [] + else + options + end + end + end + end +end diff --git a/lib/redmine/platform.rb b/lib/redmine/platform.rb new file mode 100644 index 00000000..e06ebeee --- /dev/null +++ b/lib/redmine/platform.rb @@ -0,0 +1,27 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +module Redmine + module Platform + class << self + def mswin? + (RUBY_PLATFORM =~ /(:?mswin|mingw)/) || + (RUBY_PLATFORM == 'java' && (ENV['OS'] || ENV['os']) =~ /windows/i) + end + end + end +end diff --git a/lib/redmine/plugin.rb b/lib/redmine/plugin.rb new file mode 100644 index 00000000..30c182d1 --- /dev/null +++ b/lib/redmine/plugin.rb @@ -0,0 +1,476 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +module Redmine #:nodoc: + + class PluginNotFound < StandardError; end + class PluginRequirementError < StandardError; end + + # Base class for Redmine plugins. + # Plugins are registered using the register class method that acts as the public constructor. + # + # Redmine::Plugin.register :example do + # name 'Example plugin' + # author 'John Smith' + # description 'This is an example plugin for Redmine' + # version '0.0.1' + # settings :default => {'foo'=>'bar'}, :partial => 'settings/settings' + # end + # + # === Plugin attributes + # + # +settings+ is an optional attribute that let the plugin be configurable. + # It must be a hash with the following keys: + # * :default: default value for the plugin settings + # * :partial: path of the configuration partial view, relative to the plugin app/views directory + # Example: + # settings :default => {'foo'=>'bar'}, :partial => 'settings/settings' + # In this example, the settings partial will be found here in the plugin directory: app/views/settings/_settings.rhtml. + # + # When rendered, the plugin settings value is available as the local variable +settings+ + class Plugin + cattr_accessor :directory + self.directory = File.join(Rails.root, 'plugins') + + cattr_accessor :public_directory + self.public_directory = File.join(Rails.root, 'public', 'plugin_assets') + + @registered_plugins = {} + class << self + attr_reader :registered_plugins + private :new + + def def_field(*names) + class_eval do + names.each do |name| + define_method(name) do |*args| + args.empty? ? instance_variable_get("@#{name}") : instance_variable_set("@#{name}", *args) + end + end + end + end + end + def_field :name, :description, :url, :author, :author_url, :version, :settings + attr_reader :id + + # Plugin constructor + def self.register(id, &block) + p = new(id) + p.instance_eval(&block) + # Set a default name if it was not provided during registration + p.name(id.to_s.humanize) if p.name.nil? + + # Adds plugin locales if any + # YAML translation files should be found under /config/locales/ + ::I18n.load_path += Dir.glob(File.join(p.directory, 'config', 'locales', '*.yml')) + + # Prepends the app/views directory of the plugin to the view path + view_path = File.join(p.directory, 'app', 'views') + if File.directory?(view_path) + ActionController::Base.prepend_view_path(view_path) + ActionMailer::Base.prepend_view_path(view_path) + end + + # Adds the app/{controllers,helpers,models} directories of the plugin to the autoload path + Dir.glob File.expand_path(File.join(p.directory, 'app', '{controllers,helpers,models}')) do |dir| + ActiveSupport::Dependencies.autoload_paths += [dir] + end + + registered_plugins[id] = p + end + + # Returns an array of all registered plugins + def self.all + registered_plugins.values.sort + end + + # Finds a plugin by its id + # Returns a PluginNotFound exception if the plugin doesn't exist + def self.find(id) + registered_plugins[id.to_sym] || raise(PluginNotFound) + end + + # Clears the registered plugins hash + # It doesn't unload installed plugins + def self.clear + @registered_plugins = {} + end + + # Checks if a plugin is installed + # + # @param [String] id name of the plugin + def self.installed?(id) + registered_plugins[id.to_sym].present? + end + + def self.load + Dir.glob(File.join(self.directory, '*')).sort.each do |directory| + if File.directory?(directory) + lib = File.join(directory, "lib") + if File.directory?(lib) + $:.unshift lib + ActiveSupport::Dependencies.autoload_paths += [lib] + end + initializer = File.join(directory, "init.rb") + if File.file?(initializer) + require initializer + end + end + end + end + + def initialize(id) + @id = id.to_sym + end + + def directory + File.join(self.class.directory, id.to_s) + end + + def public_directory + File.join(self.class.public_directory, id.to_s) + end + + def to_param + id + end + + def assets_directory + File.join(directory, 'assets') + end + + def <=>(plugin) + self.id.to_s <=> plugin.id.to_s + end + + # Sets a requirement on Redmine version + # Raises a PluginRequirementError exception if the requirement is not met + # + # Examples + # # Requires Redmine 0.7.3 or higher + # requires_redmine :version_or_higher => '0.7.3' + # requires_redmine '0.7.3' + # + # # Requires Redmine 0.7.x or higher + # requires_redmine '0.7' + # + # # Requires a specific Redmine version + # requires_redmine :version => '0.7.3' # 0.7.3 only + # requires_redmine :version => '0.7' # 0.7.x + # requires_redmine :version => ['0.7.3', '0.8.0'] # 0.7.3 or 0.8.0 + # + # # Requires a Redmine version within a range + # requires_redmine :version => '0.7.3'..'0.9.1' # >= 0.7.3 and <= 0.9.1 + # requires_redmine :version => '0.7'..'0.9' # >= 0.7.x and <= 0.9.x + def requires_redmine(arg) + arg = { :version_or_higher => arg } unless arg.is_a?(Hash) + arg.assert_valid_keys(:version, :version_or_higher) + + current = Redmine::VERSION.to_a + arg.each do |k, req| + case k + when :version_or_higher + raise ArgumentError.new(":version_or_higher accepts a version string only") unless req.is_a?(String) + unless compare_versions(req, current) <= 0 + raise PluginRequirementError.new("#{id} plugin requires Redmine #{req} or higher but current is #{current.join('.')}") + end + when :version + req = [req] if req.is_a?(String) + if req.is_a?(Array) + unless req.detect {|ver| compare_versions(ver, current) == 0} + raise PluginRequirementError.new("#{id} plugin requires one the following Redmine versions: #{req.join(', ')} but current is #{current.join('.')}") + end + elsif req.is_a?(Range) + unless compare_versions(req.first, current) <= 0 && compare_versions(req.last, current) >= 0 + raise PluginRequirementError.new("#{id} plugin requires a Redmine version between #{req.first} and #{req.last} but current is #{current.join('.')}") + end + else + raise ArgumentError.new(":version option accepts a version string, an array or a range of versions") + end + end + end + true + end + + def compare_versions(requirement, current) + requirement = requirement.split('.').collect(&:to_i) + requirement <=> current.slice(0, requirement.size) + end + private :compare_versions + + # Sets a requirement on a Redmine plugin version + # Raises a PluginRequirementError exception if the requirement is not met + # + # Examples + # # Requires a plugin named :foo version 0.7.3 or higher + # requires_redmine_plugin :foo, :version_or_higher => '0.7.3' + # requires_redmine_plugin :foo, '0.7.3' + # + # # Requires a specific version of a Redmine plugin + # requires_redmine_plugin :foo, :version => '0.7.3' # 0.7.3 only + # requires_redmine_plugin :foo, :version => ['0.7.3', '0.8.0'] # 0.7.3 or 0.8.0 + def requires_redmine_plugin(plugin_name, arg) + arg = { :version_or_higher => arg } unless arg.is_a?(Hash) + arg.assert_valid_keys(:version, :version_or_higher) + + plugin = Plugin.find(plugin_name) + current = plugin.version.split('.').collect(&:to_i) + + arg.each do |k, v| + v = [] << v unless v.is_a?(Array) + versions = v.collect {|s| s.split('.').collect(&:to_i)} + case k + when :version_or_higher + raise ArgumentError.new("wrong number of versions (#{versions.size} for 1)") unless versions.size == 1 + unless (current <=> versions.first) >= 0 + raise PluginRequirementError.new("#{id} plugin requires the #{plugin_name} plugin #{v} or higher but current is #{current.join('.')}") + end + when :version + unless versions.include?(current.slice(0,3)) + raise PluginRequirementError.new("#{id} plugin requires one the following versions of #{plugin_name}: #{v.join(', ')} but current is #{current.join('.')}") + end + end + end + true + end + + # Adds an item to the given +menu+. + # The +id+ parameter (equals to the project id) is automatically added to the url. + # menu :project_menu, :plugin_example, { :controller => 'example', :action => 'say_hello' }, :caption => 'Sample' + # + # +name+ parameter can be: :top_menu, :account_menu, :application_menu or :project_menu + # + def menu(menu, item, url, options={}) + Redmine::MenuManager.map(menu).push(item, url, options) + end + alias :add_menu_item :menu + + # Removes +item+ from the given +menu+. + def delete_menu_item(menu, item) + Redmine::MenuManager.map(menu).delete(item) + end + + # Defines a permission called +name+ for the given +actions+. + # + # The +actions+ argument is a hash with controllers as keys and actions as values (a single value or an array): + # permission :destroy_contacts, { :contacts => :destroy } + # permission :view_contacts, { :contacts => [:index, :show] } + # + # The +options+ argument is a hash that accept the following keys: + # * :public => the permission is public if set to true (implicitly given to any user) + # * :require => can be set to one of the following values to restrict users the permission can be given to: :loggedin, :member + # * :read => set it to true so that the permission is still granted on closed projects + # + # Examples + # # A permission that is implicitly given to any user + # # This permission won't appear on the Roles & Permissions setup screen + # permission :say_hello, { :example => :say_hello }, :public => true, :read => true + # + # # A permission that can be given to any user + # permission :say_hello, { :example => :say_hello } + # + # # A permission that can be given to registered users only + # permission :say_hello, { :example => :say_hello }, :require => :loggedin + # + # # A permission that can be given to project members only + # permission :say_hello, { :example => :say_hello }, :require => :member + def permission(name, actions, options = {}) + if @project_module + Redmine::AccessControl.map {|map| map.project_module(@project_module) {|map|map.permission(name, actions, options)}} + else + Redmine::AccessControl.map {|map| map.permission(name, actions, options)} + end + end + + # Defines a project module, that can be enabled/disabled for each project. + # Permissions defined inside +block+ will be bind to the module. + # + # project_module :things do + # permission :view_contacts, { :contacts => [:list, :show] }, :public => true + # permission :destroy_contacts, { :contacts => :destroy } + # end + def project_module(name, &block) + @project_module = name + self.instance_eval(&block) + @project_module = nil + end + + # Registers an activity provider. + # + # Options: + # * :class_name - one or more model(s) that provide these events (inferred from event_type by default) + # * :default - setting this option to false will make the events not displayed by default + # + # A model can provide several activity event types. + # + # Examples: + # register :news + # register :scrums, :class_name => 'Meeting' + # register :issues, :class_name => ['Issue', 'Journal'] + # + # Retrieving events: + # Associated model(s) must implement the find_events class method. + # ActiveRecord models can use acts_as_activity_provider as a way to implement this class method. + # + # The following call should return all the scrum events visible by current user that occured in the 5 last days: + # Meeting.find_events('scrums', User.current, 5.days.ago, Date.today) + # Meeting.find_events('scrums', User.current, 5.days.ago, Date.today, :project => foo) # events for project foo only + # + # Note that :view_scrums permission is required to view these events in the activity view. + def activity_provider(*args) + Redmine::Activity.register(*args) + end + + # Registers a wiki formatter. + # + # Parameters: + # * +name+ - human-readable name + # * +formatter+ - formatter class, which should have an instance method +to_html+ + # * +helper+ - helper module, which will be included by wiki pages + def wiki_format_provider(name, formatter, helper) + Redmine::WikiFormatting.register(name, formatter, helper) + end + + # Returns +true+ if the plugin can be configured. + def configurable? + settings && settings.is_a?(Hash) && !settings[:partial].blank? + end + + def mirror_assets + source = assets_directory + destination = public_directory + return unless File.directory?(source) + + source_files = Dir[source + "/**/*"] + source_dirs = source_files.select { |d| File.directory?(d) } + source_files -= source_dirs + + unless source_files.empty? + base_target_dir = File.join(destination, File.dirname(source_files.first).gsub(source, '')) + begin + FileUtils.mkdir_p(base_target_dir) + rescue Exception => e + raise "Could not create directory #{base_target_dir}: " + e.message + end + end + + source_dirs.each do |dir| + # strip down these paths so we have simple, relative paths we can + # add to the destination + target_dir = File.join(destination, dir.gsub(source, '')) + begin + FileUtils.mkdir_p(target_dir) + rescue Exception => e + raise "Could not create directory #{target_dir}: " + e.message + end + end + + source_files.each do |file| + begin + target = File.join(destination, file.gsub(source, '')) + unless File.exist?(target) && FileUtils.identical?(file, target) + FileUtils.cp(file, target) + end + rescue Exception => e + raise "Could not copy #{file} to #{target}: " + e.message + end + end + end + + # Mirrors assets from one or all plugins to public/plugin_assets + def self.mirror_assets(name=nil) + if name.present? + find(name).mirror_assets + else + all.each do |plugin| + plugin.mirror_assets + end + end + end + + # The directory containing this plugin's migrations (plugin/db/migrate) + def migration_directory + File.join(Rails.root, 'plugins', id.to_s, 'db', 'migrate') + end + + # Returns the version number of the latest migration for this plugin. Returns + # nil if this plugin has no migrations. + def latest_migration + migrations.last + end + + # Returns the version numbers of all migrations for this plugin. + def migrations + migrations = Dir[migration_directory+"/*.rb"] + migrations.map { |p| File.basename(p).match(/0*(\d+)\_/)[1].to_i }.sort + end + + # Migrate this plugin to the given version + def migrate(version = nil) + puts "Migrating #{id} (#{name})..." + Redmine::Plugin::Migrator.migrate_plugin(self, version) + end + + # Migrates all plugins or a single plugin to a given version + # Exemples: + # Plugin.migrate + # Plugin.migrate('sample_plugin') + # Plugin.migrate('sample_plugin', 1) + # + def self.migrate(name=nil, version=nil) + if name.present? + find(name).migrate(version) + else + all.each do |plugin| + plugin.migrate + end + end + end + + class Migrator < ActiveRecord::Migrator + # We need to be able to set the 'current' plugin being migrated. + cattr_accessor :current_plugin + + class << self + # Runs the migrations from a plugin, up (or down) to the version given + def migrate_plugin(plugin, version) + self.current_plugin = plugin + return if current_version(plugin) == version + migrate(plugin.migration_directory, version) + end + + def current_version(plugin=current_plugin) + # Delete migrations that don't match .. to_i will work because the number comes first + ::ActiveRecord::Base.connection.select_values( + "SELECT version FROM #{schema_migrations_table_name}" + ).delete_if{ |v| v.match(/-#{plugin.id}/) == nil }.map(&:to_i).max || 0 + end + end + + def migrated + sm_table = self.class.schema_migrations_table_name + ::ActiveRecord::Base.connection.select_values( + "SELECT version FROM #{sm_table}" + ).delete_if{ |v| v.match(/-#{current_plugin.id}/) == nil }.map(&:to_i).sort + end + + def record_version_state_after_migrating(version) + super(version.to_s + "-" + current_plugin.id.to_s) + end + end + end +end diff --git a/lib/redmine/pop3.rb b/lib/redmine/pop3.rb new file mode 100644 index 00000000..275e688d --- /dev/null +++ b/lib/redmine/pop3.rb @@ -0,0 +1,62 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +require 'net/pop' + +module Redmine + module POP3 + class << self + def check(pop_options={}, options={}) + host = pop_options[:host] || '127.0.0.1' + port = pop_options[:port] || '110' + apop = (pop_options[:apop].to_s == '1') + delete_unprocessed = (pop_options[:delete_unprocessed].to_s == '1') + + pop = Net::POP3.APOP(apop).new(host,port) + logger.debug "Connecting to #{host}..." if logger && logger.debug? + pop.start(pop_options[:username], pop_options[:password]) do |pop_session| + if pop_session.mails.empty? + logger.debug "No email to process" if logger && logger.debug? + else + logger.debug "#{pop_session.mails.size} email(s) to process..." if logger && logger.debug? + pop_session.each_mail do |msg| + message = msg.pop + message_id = (message =~ /^Message-I[dD]: (.*)/ ? $1 : '').strip + if MailHandler.receive(message, options) + msg.delete + logger.debug "--> Message #{message_id} processed and deleted from the server" if logger && logger.debug? + else + if delete_unprocessed + msg.delete + logger.debug "--> Message #{message_id} NOT processed and deleted from the server" if logger && logger.debug? + else + logger.debug "--> Message #{message_id} NOT processed and left on the server" if logger && logger.debug? + end + end + end + end + end + end + + private + + def logger + ::Rails.logger + end + end + end +end diff --git a/lib/redmine/safe_attributes.rb b/lib/redmine/safe_attributes.rb new file mode 100644 index 00000000..c8d5852b --- /dev/null +++ b/lib/redmine/safe_attributes.rb @@ -0,0 +1,87 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +module Redmine + module SafeAttributes + def self.included(base) + base.extend(ClassMethods) + end + + module ClassMethods + # Declares safe attributes + # An optional Proc can be given for conditional inclusion + # + # Example: + # safe_attributes 'title', 'pages' + # safe_attributes 'isbn', :if => {|book, user| book.author == user} + def safe_attributes(*args) + @safe_attributes ||= [] + if args.empty? + if superclass.include?(Redmine::SafeAttributes) + @safe_attributes + superclass.safe_attributes + else + @safe_attributes + end + else + options = args.last.is_a?(Hash) ? args.pop : {} + @safe_attributes << [args, options] + end + end + end + + # Returns an array that can be safely set by user or current user + # + # Example: + # book.safe_attributes # => ['title', 'pages'] + # book.safe_attributes(book.author) # => ['title', 'pages', 'isbn'] + def safe_attribute_names(user=nil) + return @safe_attribute_names if @safe_attribute_names && user.nil? + names = [] + self.class.safe_attributes.collect do |attrs, options| + if options[:if].nil? || options[:if].call(self, user || User.current) + names += attrs.collect(&:to_s) + end + end + names.uniq! + @safe_attribute_names = names if user.nil? + names + end + + # Returns true if attr can be set by user or the current user + def safe_attribute?(attr, user=nil) + safe_attribute_names(user).include?(attr.to_s) + end + + # Returns a hash with unsafe attributes removed + # from the given attrs hash + # + # Example: + # book.delete_unsafe_attributes({'title' => 'My book', 'foo' => 'bar'}) + # # => {'title' => 'My book'} + def delete_unsafe_attributes(attrs, user=User.current) + safe = safe_attribute_names(user) + attrs.dup.delete_if {|k,v| !safe.include?(k)} + end + + # Sets attributes from attrs that are safe + # attrs is a Hash with string keys + def safe_attributes=(attrs, user=User.current) + return unless attrs.is_a?(Hash) + self.attributes = delete_unsafe_attributes(attrs, user) + end + end +end diff --git a/lib/redmine/scm/adapters/abstract_adapter.rb b/lib/redmine/scm/adapters/abstract_adapter.rb new file mode 100644 index 00000000..3e51f2d4 --- /dev/null +++ b/lib/redmine/scm/adapters/abstract_adapter.rb @@ -0,0 +1,450 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +require 'cgi' + +if RUBY_VERSION < '1.9' + require 'iconv' +end + +module Redmine + module Scm + module Adapters + class CommandFailed < StandardError #:nodoc: + end + + class AbstractAdapter #:nodoc: + + # raised if scm command exited with error, e.g. unknown revision. + class ScmCommandAborted < CommandFailed; end + + class << self + def client_command + "" + end + + def shell_quote_command + if Redmine::Platform.mswin? && RUBY_PLATFORM == 'java' + client_command + else + shell_quote(client_command) + end + end + + # Returns the version of the scm client + # Eg: [1, 5, 0] or [] if unknown + def client_version + [] + end + + # Returns the version string of the scm client + # Eg: '1.5.0' or 'Unknown version' if unknown + def client_version_string + v = client_version || 'Unknown version' + v.is_a?(Array) ? v.join('.') : v.to_s + end + + # Returns true if the current client version is above + # or equals the given one + # If option is :unknown is set to true, it will return + # true if the client version is unknown + def client_version_above?(v, options={}) + ((client_version <=> v) >= 0) || (client_version.empty? && options[:unknown]) + end + + def client_available + true + end + + def shell_quote(str) + if Redmine::Platform.mswin? + '"' + str.gsub(/"/, '\\"') + '"' + else + "'" + str.gsub(/'/, "'\"'\"'") + "'" + end + end + end + + def initialize(url, root_url=nil, login=nil, password=nil, + path_encoding=nil) + @url = url + @login = login if login && !login.empty? + @password = (password || "") if @login + @root_url = root_url.blank? ? retrieve_root_url : root_url + end + + def adapter_name + 'Abstract' + end + + def supports_cat? + true + end + + def supports_annotate? + respond_to?('annotate') + end + + def root_url + @root_url + end + + def url + @url + end + + def path_encoding + nil + end + + # get info about the svn repository + def info + return nil + end + + # Returns the entry identified by path and revision identifier + # or nil if entry doesn't exist in the repository + def entry(path=nil, identifier=nil) + parts = path.to_s.split(%r{[\/\\]}).select {|n| !n.blank?} + search_path = parts[0..-2].join('/') + search_name = parts[-1] + if search_path.blank? && search_name.blank? + # Root entry + Entry.new(:path => '', :kind => 'dir') + else + # Search for the entry in the parent directory + es = entries(search_path, identifier) + es ? es.detect {|e| e.name == search_name} : nil + end + end + + # Returns an Entries collection + # or nil if the given path doesn't exist in the repository + def entries(path=nil, identifier=nil, options={}) + return nil + end + + def branches + return nil + end + + def tags + return nil + end + + def default_branch + return nil + end + + def properties(path, identifier=nil) + return nil + end + + def revisions(path=nil, identifier_from=nil, identifier_to=nil, options={}) + return nil + end + + def diff(path, identifier_from, identifier_to=nil) + return nil + end + + def cat(path, identifier=nil) + return nil + end + + def with_leading_slash(path) + path ||= '' + (path[0,1]!="/") ? "/#{path}" : path + end + + def with_trailling_slash(path) + path ||= '' + (path[-1,1] == "/") ? path : "#{path}/" + end + + def without_leading_slash(path) + path ||= '' + path.gsub(%r{^/+}, '') + end + + def without_trailling_slash(path) + path ||= '' + (path[-1,1] == "/") ? path[0..-2] : path + end + + def shell_quote(str) + self.class.shell_quote(str) + end + + private + def retrieve_root_url + info = self.info + info ? info.root_url : nil + end + + def target(path, sq=true) + path ||= '' + base = path.match(/^\//) ? root_url : url + str = "#{base}/#{path}".gsub(/[?<>\*]/, '') + if sq + str = shell_quote(str) + end + str + end + + def logger + self.class.logger + end + + def shellout(cmd, options = {}, &block) + self.class.shellout(cmd, options, &block) + end + + def self.logger + Rails.logger + end + + # Path to the file where scm stderr output is logged + # Returns nil if the log file is not writable + def self.stderr_log_file + if @stderr_log_file.nil? + writable = false + path = Redmine::Configuration['scm_stderr_log_file'].presence + path ||= Rails.root.join("log/#{Rails.env}.scm.stderr.log").to_s + if File.exists?(path) + if File.file?(path) && File.writable?(path) + writable = true + else + logger.warn("SCM log file (#{path}) is not writable") + end + else + begin + File.open(path, "w") {} + writable = true + rescue => e + logger.warn("SCM log file (#{path}) cannot be created: #{e.message}") + end + end + @stderr_log_file = writable ? path : false + end + @stderr_log_file || nil + end + + def self.shellout(cmd, options = {}, &block) + if logger && logger.debug? + logger.debug "Shelling out: #{strip_credential(cmd)}" + # Capture stderr in a log file + if stderr_log_file + cmd = "#{cmd} 2>>#{shell_quote(stderr_log_file)}" + end + end + begin + mode = "r+" + IO.popen(cmd, mode) do |io| + io.set_encoding("ASCII-8BIT") if io.respond_to?(:set_encoding) + io.close_write unless options[:write_stdin] + block.call(io) if block_given? + end + ## If scm command does not exist, + ## Linux JRuby 1.6.2 (ruby-1.8.7-p330) raises java.io.IOException + ## in production environment. + # rescue Errno::ENOENT => e + rescue Exception => e + msg = strip_credential(e.message) + # The command failed, log it and re-raise + logmsg = "SCM command failed, " + logmsg += "make sure that your SCM command (e.g. svn) is " + logmsg += "in PATH (#{ENV['PATH']})\n" + logmsg += "You can configure your scm commands in config/configuration.yml.\n" + logmsg += "#{strip_credential(cmd)}\n" + logmsg += "with: #{msg}" + logger.error(logmsg) + raise CommandFailed.new(msg) + end + end + + # Hides username/password in a given command + def self.strip_credential(cmd) + q = (Redmine::Platform.mswin? ? '"' : "'") + cmd.to_s.gsub(/(\-\-(password|username))\s+(#{q}[^#{q}]+#{q}|[^#{q}]\S+)/, '\\1 xxxx') + end + + def strip_credential(cmd) + self.class.strip_credential(cmd) + end + + def scm_iconv(to, from, str) + return nil if str.nil? + return str if to == from + if str.respond_to?(:force_encoding) + str.force_encoding(from) + begin + str.encode(to) + rescue Exception => err + logger.error("failed to convert from #{from} to #{to}. #{err}") + nil + end + else + begin + Iconv.conv(to, from, str) + rescue Iconv::Failure => err + logger.error("failed to convert from #{from} to #{to}. #{err}") + nil + end + end + end + + def parse_xml(xml) + if RUBY_PLATFORM == 'java' + xml = xml.sub(%r{<\?xml[^>]*\?>}, '') + end + ActiveSupport::XmlMini.parse(xml) + end + end + + class Entries < Array + def sort_by_name + dup.sort! {|x,y| + if x.kind == y.kind + x.name.to_s <=> y.name.to_s + else + x.kind <=> y.kind + end + } + end + + def revisions + revisions ||= Revisions.new(collect{|entry| entry.lastrev}.compact) + end + end + + class Info + attr_accessor :root_url, :lastrev + def initialize(attributes={}) + self.root_url = attributes[:root_url] if attributes[:root_url] + self.lastrev = attributes[:lastrev] + end + end + + class Entry + attr_accessor :name, :path, :kind, :size, :lastrev, :changeset + + def initialize(attributes={}) + self.name = attributes[:name] if attributes[:name] + self.path = attributes[:path] if attributes[:path] + self.kind = attributes[:kind] if attributes[:kind] + self.size = attributes[:size].to_i if attributes[:size] + self.lastrev = attributes[:lastrev] + end + + def is_file? + 'file' == self.kind + end + + def is_dir? + 'dir' == self.kind + end + + def is_text? + Redmine::MimeType.is_type?('text', name) + end + + def author + if changeset + changeset.author.to_s + elsif lastrev + Redmine::CodesetUtil.replace_invalid_utf8(lastrev.author.to_s.split('<').first) + end + end + end + + class Revisions < Array + def latest + sort {|x,y| + unless x.time.nil? or y.time.nil? + x.time <=> y.time + else + 0 + end + }.last + end + end + + class Revision + attr_accessor :scmid, :name, :author, :time, :message, + :paths, :revision, :branch, :identifier, + :parents + + def initialize(attributes={}) + self.identifier = attributes[:identifier] + self.scmid = attributes[:scmid] + self.name = attributes[:name] || self.identifier + self.author = attributes[:author] + self.time = attributes[:time] + self.message = attributes[:message] || "" + self.paths = attributes[:paths] + self.revision = attributes[:revision] + self.branch = attributes[:branch] + self.parents = attributes[:parents] + end + + # Returns the readable identifier. + def format_identifier + self.identifier.to_s + end + + def ==(other) + if other.nil? + false + elsif scmid.present? + scmid == other.scmid + elsif identifier.present? + identifier == other.identifier + elsif revision.present? + revision == other.revision + end + end + end + + class Annotate + attr_reader :lines, :revisions + + def initialize + @lines = [] + @revisions = [] + end + + def add_line(line, revision) + @lines << line + @revisions << revision + end + + def content + content = lines.join("\n") + end + + def empty? + lines.empty? + end + end + + class Branch < String + attr_accessor :revision, :scmid + end + end + end +end diff --git a/lib/redmine/scm/adapters/bazaar_adapter.rb b/lib/redmine/scm/adapters/bazaar_adapter.rb new file mode 100644 index 00000000..8de831d6 --- /dev/null +++ b/lib/redmine/scm/adapters/bazaar_adapter.rb @@ -0,0 +1,341 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +require 'redmine/scm/adapters/abstract_adapter' + +module Redmine + module Scm + module Adapters + class BazaarAdapter < AbstractAdapter + + # Bazaar executable name + BZR_BIN = Redmine::Configuration['scm_bazaar_command'] || "bzr" + + class << self + def client_command + @@bin ||= BZR_BIN + end + + def sq_bin + @@sq_bin ||= shell_quote_command + end + + def client_version + @@client_version ||= (scm_command_version || []) + end + + def client_available + !client_version.empty? + end + + def scm_command_version + scm_version = scm_version_from_command_line.dup + if scm_version.respond_to?(:force_encoding) + scm_version.force_encoding('ASCII-8BIT') + end + if m = scm_version.match(%r{\A(.*?)((\d+\.)+\d+)}) + m[2].scan(%r{\d+}).collect(&:to_i) + end + end + + def scm_version_from_command_line + shellout("#{sq_bin} --version") { |io| io.read }.to_s + end + end + + def initialize(url, root_url=nil, login=nil, password=nil, path_encoding=nil) + @url = url + @root_url = url + @path_encoding = 'UTF-8' + # do not call *super* for non ASCII repository path + end + + def bzr_path_encodig=(encoding) + @path_encoding = encoding + end + + # Get info about the repository + def info + cmd_args = %w|revno| + cmd_args << bzr_target('') + info = nil + scm_cmd(*cmd_args) do |io| + if io.read =~ %r{^(\d+)\r?$} + info = Info.new({:root_url => url, + :lastrev => Revision.new({ + :identifier => $1 + }) + }) + end + end + info + rescue ScmCommandAborted + return nil + end + + # Returns an Entries collection + # or nil if the given path doesn't exist in the repository + def entries(path=nil, identifier=nil, options={}) + path ||= '' + entries = Entries.new + identifier = -1 unless identifier && identifier.to_i > 0 + cmd_args = %w|ls -v --show-ids| + cmd_args << "-r#{identifier.to_i}" + cmd_args << bzr_target(path) + scm_cmd(*cmd_args) do |io| + prefix_utf8 = "#{url}/#{path}".gsub('\\', '/') + logger.debug "PREFIX: #{prefix_utf8}" + prefix = scm_iconv(@path_encoding, 'UTF-8', prefix_utf8) + prefix.force_encoding('ASCII-8BIT') if prefix.respond_to?(:force_encoding) + re = %r{^V\s+(#{Regexp.escape(prefix)})?(\/?)([^\/]+)(\/?)\s+(\S+)\r?$} + io.each_line do |line| + next unless line =~ re + name_locale, slash, revision = $3.strip, $4, $5.strip + name = scm_iconv('UTF-8', @path_encoding, name_locale) + entries << Entry.new({:name => name, + :path => ((path.empty? ? "" : "#{path}/") + name), + :kind => (slash.blank? ? 'file' : 'dir'), + :size => nil, + :lastrev => Revision.new(:revision => revision) + }) + end + end + if logger && logger.debug? + logger.debug("Found #{entries.size} entries in the repository for #{target(path)}") + end + entries.sort_by_name + rescue ScmCommandAborted + return nil + end + + def revisions(path=nil, identifier_from=nil, identifier_to=nil, options={}) + path ||= '' + identifier_from = (identifier_from and identifier_from.to_i > 0) ? identifier_from.to_i : 'last:1' + identifier_to = (identifier_to and identifier_to.to_i > 0) ? identifier_to.to_i : 1 + revisions = Revisions.new + cmd_args = %w|log -v --show-ids| + cmd_args << "-r#{identifier_to}..#{identifier_from}" + cmd_args << bzr_target(path) + scm_cmd(*cmd_args) do |io| + revision = nil + parsing = nil + io.each_line do |line| + if line =~ /^----/ + revisions << revision if revision + revision = Revision.new(:paths => [], :message => '') + parsing = nil + else + next unless revision + if line =~ /^revno: (\d+)($|\s\[merge\]$)/ + revision.identifier = $1.to_i + elsif line =~ /^committer: (.+)$/ + revision.author = $1.strip + elsif line =~ /^revision-id:(.+)$/ + revision.scmid = $1.strip + elsif line =~ /^timestamp: (.+)$/ + revision.time = Time.parse($1).localtime + elsif line =~ /^ -----/ + # partial revisions + parsing = nil unless parsing == 'message' + elsif line =~ /^(message|added|modified|removed|renamed):/ + parsing = $1 + elsif line =~ /^ (.*)$/ + if parsing == 'message' + revision.message << "#{$1}\n" + else + if $1 =~ /^(.*)\s+(\S+)$/ + path_locale = $1.strip + path = scm_iconv('UTF-8', @path_encoding, path_locale) + revid = $2 + case parsing + when 'added' + revision.paths << {:action => 'A', :path => "/#{path}", :revision => revid} + when 'modified' + revision.paths << {:action => 'M', :path => "/#{path}", :revision => revid} + when 'removed' + revision.paths << {:action => 'D', :path => "/#{path}", :revision => revid} + when 'renamed' + new_path = path.split('=>').last + if new_path + revision.paths << {:action => 'M', :path => "/#{new_path.strip}", + :revision => revid} + end + end + end + end + else + parsing = nil + end + end + end + revisions << revision if revision + end + revisions + rescue ScmCommandAborted + return nil + end + + def diff(path, identifier_from, identifier_to=nil) + path ||= '' + if identifier_to + identifier_to = identifier_to.to_i + else + identifier_to = identifier_from.to_i - 1 + end + if identifier_from + identifier_from = identifier_from.to_i + end + diff = [] + cmd_args = %w|diff| + cmd_args << "-r#{identifier_to}..#{identifier_from}" + cmd_args << bzr_target(path) + scm_cmd_no_raise(*cmd_args) do |io| + io.each_line do |line| + diff << line + end + end + diff + end + + def cat(path, identifier=nil) + cat = nil + cmd_args = %w|cat| + cmd_args << "-r#{identifier.to_i}" if identifier && identifier.to_i > 0 + cmd_args << bzr_target(path) + scm_cmd(*cmd_args) do |io| + io.binmode + cat = io.read + end + cat + rescue ScmCommandAborted + return nil + end + + def annotate(path, identifier=nil) + blame = Annotate.new + cmd_args = %w|annotate -q --all| + cmd_args << "-r#{identifier.to_i}" if identifier && identifier.to_i > 0 + cmd_args << bzr_target(path) + scm_cmd(*cmd_args) do |io| + author = nil + identifier = nil + io.each_line do |line| + next unless line =~ %r{^(\d+) ([^|]+)\| (.*)$} + rev = $1 + blame.add_line($3.rstrip, + Revision.new( + :identifier => rev, + :revision => rev, + :author => $2.strip + )) + end + end + blame + rescue ScmCommandAborted + return nil + end + + def self.branch_conf_path(path) + bcp = nil + m = path.match(%r{^(.*[/\\])\.bzr.*$}) + if m + bcp = m[1] + else + bcp = path + end + bcp.gsub!(%r{[\/\\]$}, "") + if bcp + bcp = File.join(bcp, ".bzr", "branch", "branch.conf") + end + bcp + end + + def append_revisions_only + return @aro if ! @aro.nil? + @aro = false + bcp = self.class.branch_conf_path(url) + if bcp && File.exist?(bcp) + begin + f = File::open(bcp, "r") + cnt = 0 + f.each_line do |line| + l = line.chomp.to_s + if l =~ /^\s*append_revisions_only\s*=\s*(\w+)\s*$/ + str_aro = $1 + if str_aro.upcase == "TRUE" + @aro = true + cnt += 1 + elsif str_aro.upcase == "FALSE" + @aro = false + cnt += 1 + end + if cnt > 1 + @aro = false + break + end + end + end + ensure + f.close + end + end + @aro + end + + def scm_cmd(*args, &block) + full_args = [] + full_args += args + full_args_locale = [] + full_args.map do |e| + full_args_locale << scm_iconv(@path_encoding, 'UTF-8', e) + end + ret = shellout( + self.class.sq_bin + ' ' + + full_args_locale.map { |e| shell_quote e.to_s }.join(' '), + &block + ) + if $? && $?.exitstatus != 0 + raise ScmCommandAborted, "bzr exited with non-zero status: #{$?.exitstatus}" + end + ret + end + private :scm_cmd + + def scm_cmd_no_raise(*args, &block) + full_args = [] + full_args += args + full_args_locale = [] + full_args.map do |e| + full_args_locale << scm_iconv(@path_encoding, 'UTF-8', e) + end + ret = shellout( + self.class.sq_bin + ' ' + + full_args_locale.map { |e| shell_quote e.to_s }.join(' '), + &block + ) + ret + end + private :scm_cmd_no_raise + + def bzr_target(path) + target(path, false) + end + private :bzr_target + end + end + end +end diff --git a/lib/redmine/scm/adapters/cvs_adapter.rb b/lib/redmine/scm/adapters/cvs_adapter.rb new file mode 100644 index 00000000..3a0d27c3 --- /dev/null +++ b/lib/redmine/scm/adapters/cvs_adapter.rb @@ -0,0 +1,462 @@ +# redMine - project management software +# Copyright (C) 2006-2007 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +require 'redmine/scm/adapters/abstract_adapter' + +module Redmine + module Scm + module Adapters + class CvsAdapter < AbstractAdapter + + # CVS executable name + CVS_BIN = Redmine::Configuration['scm_cvs_command'] || "cvs" + + class << self + def client_command + @@bin ||= CVS_BIN + end + + def sq_bin + @@sq_bin ||= shell_quote_command + end + + def client_version + @@client_version ||= (scm_command_version || []) + end + + def client_available + client_version_above?([1, 12]) + end + + def scm_command_version + scm_version = scm_version_from_command_line.dup + if scm_version.respond_to?(:force_encoding) + scm_version.force_encoding('ASCII-8BIT') + end + if m = scm_version.match(%r{\A(.*?)((\d+\.)+\d+)}m) + m[2].scan(%r{\d+}).collect(&:to_i) + end + end + + def scm_version_from_command_line + shellout("#{sq_bin} --version") { |io| io.read }.to_s + end + end + + # Guidelines for the input: + # url -> the project-path, relative to the cvsroot (eg. module name) + # root_url -> the good old, sometimes damned, CVSROOT + # login -> unnecessary + # password -> unnecessary too + def initialize(url, root_url=nil, login=nil, password=nil, + path_encoding=nil) + @path_encoding = path_encoding.blank? ? 'UTF-8' : path_encoding + @url = url + # TODO: better Exception here (IllegalArgumentException) + raise CommandFailed if root_url.blank? + @root_url = root_url + + # These are unused. + @login = login if login && !login.empty? + @password = (password || "") if @login + end + + def path_encoding + @path_encoding + end + + def info + logger.debug " info" + Info.new({:root_url => @root_url, :lastrev => nil}) + end + + def get_previous_revision(revision) + CvsRevisionHelper.new(revision).prevRev + end + + # Returns an Entries collection + # or nil if the given path doesn't exist in the repository + # this method is used by the repository-browser (aka LIST) + def entries(path=nil, identifier=nil, options={}) + logger.debug " entries '#{path}' with identifier '#{identifier}'" + path_locale = scm_iconv(@path_encoding, 'UTF-8', path) + path_locale.force_encoding("ASCII-8BIT") if path_locale.respond_to?(:force_encoding) + entries = Entries.new + cmd_args = %w|-q rls -e| + cmd_args << "-D" << time_to_cvstime_rlog(identifier) if identifier + cmd_args << path_with_proj(path) + scm_cmd(*cmd_args) do |io| + io.each_line() do |line| + fields = line.chop.split('/',-1) + logger.debug(">>InspectLine #{fields.inspect}") + if fields[0]!="D" + time = nil + # Thu Dec 13 16:27:22 2007 + time_l = fields[-3].split(' ') + if time_l.size == 5 && time_l[4].length == 4 + begin + time = Time.parse( + "#{time_l[1]} #{time_l[2]} #{time_l[3]} GMT #{time_l[4]}") + rescue + end + end + entries << Entry.new( + { + :name => scm_iconv('UTF-8', @path_encoding, fields[-5]), + #:path => fields[-4].include?(path)?fields[-4]:(path + "/"+ fields[-4]), + :path => scm_iconv('UTF-8', @path_encoding, "#{path_locale}/#{fields[-5]}"), + :kind => 'file', + :size => nil, + :lastrev => Revision.new( + { + :revision => fields[-4], + :name => scm_iconv('UTF-8', @path_encoding, fields[-4]), + :time => time, + :author => '' + }) + }) + else + entries << Entry.new( + { + :name => scm_iconv('UTF-8', @path_encoding, fields[1]), + :path => scm_iconv('UTF-8', @path_encoding, "#{path_locale}/#{fields[1]}"), + :kind => 'dir', + :size => nil, + :lastrev => nil + }) + end + end + end + entries.sort_by_name + rescue ScmCommandAborted + nil + end + + STARTLOG="----------------------------" + ENDLOG ="=============================================================================" + + # Returns all revisions found between identifier_from and identifier_to + # in the repository. both identifier have to be dates or nil. + # these method returns nothing but yield every result in block + def revisions(path=nil, identifier_from=nil, identifier_to=nil, options={}, &block) + path_with_project_utf8 = path_with_proj(path) + path_with_project_locale = scm_iconv(@path_encoding, 'UTF-8', path_with_project_utf8) + logger.debug " revisions path:" + + "'#{path}',identifier_from #{identifier_from}, identifier_to #{identifier_to}" + cmd_args = %w|-q rlog| + cmd_args << "-d" << ">#{time_to_cvstime_rlog(identifier_from)}" if identifier_from + cmd_args << path_with_project_utf8 + scm_cmd(*cmd_args) do |io| + state = "entry_start" + commit_log = String.new + revision = nil + date = nil + author = nil + entry_path = nil + entry_name = nil + file_state = nil + branch_map = nil + io.each_line() do |line| + if state != "revision" && /^#{ENDLOG}/ =~ line + commit_log = String.new + revision = nil + state = "entry_start" + end + if state == "entry_start" + branch_map = Hash.new + if /^RCS file: #{Regexp.escape(root_url_path)}\/#{Regexp.escape(path_with_project_locale)}(.+),v$/ =~ line + entry_path = normalize_cvs_path($1) + entry_name = normalize_path(File.basename($1)) + logger.debug("Path #{entry_path} <=> Name #{entry_name}") + elsif /^head: (.+)$/ =~ line + entry_headRev = $1 #unless entry.nil? + elsif /^symbolic names:/ =~ line + state = "symbolic" #unless entry.nil? + elsif /^#{STARTLOG}/ =~ line + commit_log = String.new + state = "revision" + end + next + elsif state == "symbolic" + if /^(.*):\s(.*)/ =~ (line.strip) + branch_map[$1] = $2 + else + state = "tags" + next + end + elsif state == "tags" + if /^#{STARTLOG}/ =~ line + commit_log = "" + state = "revision" + elsif /^#{ENDLOG}/ =~ line + state = "head" + end + next + elsif state == "revision" + if /^#{ENDLOG}/ =~ line || /^#{STARTLOG}/ =~ line + if revision + revHelper = CvsRevisionHelper.new(revision) + revBranch = "HEAD" + branch_map.each() do |branch_name, branch_point| + if revHelper.is_in_branch_with_symbol(branch_point) + revBranch = branch_name + end + end + logger.debug("********** YIELD Revision #{revision}::#{revBranch}") + yield Revision.new({ + :time => date, + :author => author, + :message => commit_log.chomp, + :paths => [{ + :revision => revision.dup, + :branch => revBranch.dup, + :path => scm_iconv('UTF-8', @path_encoding, entry_path), + :name => scm_iconv('UTF-8', @path_encoding, entry_name), + :kind => 'file', + :action => file_state + }] + }) + end + commit_log = String.new + revision = nil + if /^#{ENDLOG}/ =~ line + state = "entry_start" + end + next + end + + if /^branches: (.+)$/ =~ line + # TODO: version.branch = $1 + elsif /^revision (\d+(?:\.\d+)+).*$/ =~ line + revision = $1 + elsif /^date:\s+(\d+.\d+.\d+\s+\d+:\d+:\d+)/ =~ line + date = Time.parse($1) + line_utf8 = scm_iconv('UTF-8', options[:log_encoding], line) + author_utf8 = /author: ([^;]+)/.match(line_utf8)[1] + author = scm_iconv(options[:log_encoding], 'UTF-8', author_utf8) + file_state = /state: ([^;]+)/.match(line)[1] + # TODO: + # linechanges only available in CVS.... + # maybe a feature our SVN implementation. + # I'm sure, they are useful for stats or something else + # linechanges =/lines: \+(\d+) -(\d+)/.match(line) + # unless linechanges.nil? + # version.line_plus = linechanges[1] + # version.line_minus = linechanges[2] + # else + # version.line_plus = 0 + # version.line_minus = 0 + # end + else + commit_log << line unless line =~ /^\*\*\* empty log message \*\*\*/ + end + end + end + end + rescue ScmCommandAborted + Revisions.new + end + + def diff(path, identifier_from, identifier_to=nil) + logger.debug " diff path:'#{path}'" + + ",identifier_from #{identifier_from}, identifier_to #{identifier_to}" + cmd_args = %w|rdiff -u| + cmd_args << "-r#{identifier_to}" + cmd_args << "-r#{identifier_from}" + cmd_args << path_with_proj(path) + diff = [] + scm_cmd(*cmd_args) do |io| + io.each_line do |line| + diff << line + end + end + diff + rescue ScmCommandAborted + nil + end + + def cat(path, identifier=nil) + identifier = (identifier) ? identifier : "HEAD" + logger.debug " cat path:'#{path}',identifier #{identifier}" + cmd_args = %w|-q co| + cmd_args << "-D" << time_to_cvstime(identifier) if identifier + cmd_args << "-p" << path_with_proj(path) + cat = nil + scm_cmd(*cmd_args) do |io| + io.binmode + cat = io.read + end + cat + rescue ScmCommandAborted + nil + end + + def annotate(path, identifier=nil) + identifier = (identifier) ? identifier : "HEAD" + logger.debug " annotate path:'#{path}',identifier #{identifier}" + cmd_args = %w|rannotate| + cmd_args << "-D" << time_to_cvstime(identifier) if identifier + cmd_args << path_with_proj(path) + blame = Annotate.new + scm_cmd(*cmd_args) do |io| + io.each_line do |line| + next unless line =~ %r{^([\d\.]+)\s+\(([^\)]+)\s+[^\)]+\):\s(.*)$} + blame.add_line( + $3.rstrip, + Revision.new( + :revision => $1, + :identifier => nil, + :author => $2.strip + )) + end + end + blame + rescue ScmCommandAborted + Annotate.new + end + + private + + # Returns the root url without the connexion string + # :pserver:anonymous@foo.bar:/path => /path + # :ext:cvsservername:/path => /path + def root_url_path + root_url.to_s.gsub(/^:.+:\d*/, '') + end + + # convert a date/time into the CVS-format + def time_to_cvstime(time) + return nil if time.nil? + time = Time.now if time == 'HEAD' + + unless time.kind_of? Time + time = Time.parse(time) + end + return time_to_cvstime_rlog(time) + end + + def time_to_cvstime_rlog(time) + return nil if time.nil? + t1 = time.clone.localtime + return t1.strftime("%Y-%m-%d %H:%M:%S") + end + + def normalize_cvs_path(path) + normalize_path(path.gsub(/Attic\//,'')) + end + + def normalize_path(path) + path.sub(/^(\/)*(.*)/,'\2').sub(/(.*)(,v)+/,'\1') + end + + def path_with_proj(path) + "#{url}#{with_leading_slash(path)}" + end + private :path_with_proj + + class Revision < Redmine::Scm::Adapters::Revision + # Returns the readable identifier + def format_identifier + revision.to_s + end + end + + def scm_cmd(*args, &block) + full_args = ['-d', root_url] + full_args += args + full_args_locale = [] + full_args.map do |e| + full_args_locale << scm_iconv(@path_encoding, 'UTF-8', e) + end + ret = shellout( + self.class.sq_bin + ' ' + full_args_locale.map { |e| shell_quote e.to_s }.join(' '), + &block + ) + if $? && $?.exitstatus != 0 + raise ScmCommandAborted, "cvs exited with non-zero status: #{$?.exitstatus}" + end + ret + end + private :scm_cmd + end + + class CvsRevisionHelper + attr_accessor :complete_rev, :revision, :base, :branchid + + def initialize(complete_rev) + @complete_rev = complete_rev + parseRevision() + end + + def branchPoint + return @base + end + + def branchVersion + if isBranchRevision + return @base+"."+@branchid + end + return @base + end + + def isBranchRevision + !@branchid.nil? + end + + def prevRev + unless @revision == 0 + return buildRevision( @revision - 1 ) + end + return buildRevision( @revision ) + end + + def is_in_branch_with_symbol(branch_symbol) + bpieces = branch_symbol.split(".") + branch_start = "#{bpieces[0..-3].join(".")}.#{bpieces[-1]}" + return ( branchVersion == branch_start ) + end + + private + def buildRevision(rev) + if rev == 0 + if @branchid.nil? + @base + ".0" + else + @base + end + elsif @branchid.nil? + @base + "." + rev.to_s + else + @base + "." + @branchid + "." + rev.to_s + end + end + + # Interpretiert die cvs revisionsnummern wie z.b. 1.14 oder 1.3.0.15 + def parseRevision() + pieces = @complete_rev.split(".") + @revision = pieces.last.to_i + baseSize = 1 + baseSize += (pieces.size / 2) + @base = pieces[0..-baseSize].join(".") + if baseSize > 2 + @branchid = pieces[-2] + end + end + end + end + end +end diff --git a/lib/redmine/scm/adapters/darcs_adapter.rb b/lib/redmine/scm/adapters/darcs_adapter.rb new file mode 100644 index 00000000..348bd4d0 --- /dev/null +++ b/lib/redmine/scm/adapters/darcs_adapter.rb @@ -0,0 +1,242 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +require 'redmine/scm/adapters/abstract_adapter' +require 'rexml/document' + +module Redmine + module Scm + module Adapters + class DarcsAdapter < AbstractAdapter + # Darcs executable name + DARCS_BIN = Redmine::Configuration['scm_darcs_command'] || "darcs" + + class << self + def client_command + @@bin ||= DARCS_BIN + end + + def sq_bin + @@sq_bin ||= shell_quote_command + end + + def client_version + @@client_version ||= (darcs_binary_version || []) + end + + def client_available + !client_version.empty? + end + + def darcs_binary_version + darcsversion = darcs_binary_version_from_command_line.dup + if darcsversion.respond_to?(:force_encoding) + darcsversion.force_encoding('ASCII-8BIT') + end + if m = darcsversion.match(%r{\A(.*?)((\d+\.)+\d+)}) + m[2].scan(%r{\d+}).collect(&:to_i) + end + end + + def darcs_binary_version_from_command_line + shellout("#{sq_bin} --version") { |io| io.read }.to_s + end + end + + def initialize(url, root_url=nil, login=nil, password=nil, + path_encoding=nil) + @url = url + @root_url = url + end + + def supports_cat? + # cat supported in darcs 2.0.0 and higher + self.class.client_version_above?([2, 0, 0]) + end + + # Get info about the darcs repository + def info + rev = revisions(nil,nil,nil,{:limit => 1}) + rev ? Info.new({:root_url => @url, :lastrev => rev.last}) : nil + end + + # Returns an Entries collection + # or nil if the given path doesn't exist in the repository + def entries(path=nil, identifier=nil, options={}) + path_prefix = (path.blank? ? '' : "#{path}/") + if path.blank? + path = ( self.class.client_version_above?([2, 2, 0]) ? @url : '.' ) + end + entries = Entries.new + cmd = "#{self.class.sq_bin} annotate --repodir #{shell_quote @url} --xml-output" + cmd << " --match #{shell_quote("hash #{identifier}")}" if identifier + cmd << " #{shell_quote path}" + shellout(cmd) do |io| + begin + doc = REXML::Document.new(io) + if doc.root.name == 'directory' + doc.elements.each('directory/*') do |element| + next unless ['file', 'directory'].include? element.name + entries << entry_from_xml(element, path_prefix) + end + elsif doc.root.name == 'file' + entries << entry_from_xml(doc.root, path_prefix) + end + rescue + end + end + return nil if $? && $?.exitstatus != 0 + entries.compact! + entries.sort_by_name + end + + def revisions(path=nil, identifier_from=nil, identifier_to=nil, options={}) + path = '.' if path.blank? + revisions = Revisions.new + cmd = "#{self.class.sq_bin} changes --repodir #{shell_quote @url} --xml-output" + cmd << " --from-match #{shell_quote("hash #{identifier_from}")}" if identifier_from + cmd << " --last #{options[:limit].to_i}" if options[:limit] + shellout(cmd) do |io| + begin + doc = REXML::Document.new(io) + doc.elements.each("changelog/patch") do |patch| + message = patch.elements['name'].text + message << "\n" + patch.elements['comment'].text.gsub(/\*\*\*END OF DESCRIPTION\*\*\*.*\z/m, '') if patch.elements['comment'] + revisions << Revision.new({:identifier => nil, + :author => patch.attributes['author'], + :scmid => patch.attributes['hash'], + :time => Time.parse(patch.attributes['local_date']), + :message => message, + :paths => (options[:with_path] ? get_paths_for_patch(patch.attributes['hash']) : nil) + }) + end + rescue + end + end + return nil if $? && $?.exitstatus != 0 + revisions + end + + def diff(path, identifier_from, identifier_to=nil) + path = '*' if path.blank? + cmd = "#{self.class.sq_bin} diff --repodir #{shell_quote @url}" + if identifier_to.nil? + cmd << " --match #{shell_quote("hash #{identifier_from}")}" + else + cmd << " --to-match #{shell_quote("hash #{identifier_from}")}" + cmd << " --from-match #{shell_quote("hash #{identifier_to}")}" + end + cmd << " -u #{shell_quote path}" + diff = [] + shellout(cmd) do |io| + io.each_line do |line| + diff << line + end + end + return nil if $? && $?.exitstatus != 0 + diff + end + + def cat(path, identifier=nil) + cmd = "#{self.class.sq_bin} show content --repodir #{shell_quote @url}" + cmd << " --match #{shell_quote("hash #{identifier}")}" if identifier + cmd << " #{shell_quote path}" + cat = nil + shellout(cmd) do |io| + io.binmode + cat = io.read + end + return nil if $? && $?.exitstatus != 0 + cat + end + + private + + # Returns an Entry from the given XML element + # or nil if the entry was deleted + def entry_from_xml(element, path_prefix) + modified_element = element.elements['modified'] + if modified_element.elements['modified_how'].text.match(/removed/) + return nil + end + + Entry.new({:name => element.attributes['name'], + :path => path_prefix + element.attributes['name'], + :kind => element.name == 'file' ? 'file' : 'dir', + :size => nil, + :lastrev => Revision.new({ + :identifier => nil, + :scmid => modified_element.elements['patch'].attributes['hash'] + }) + }) + end + + def get_paths_for_patch(hash) + paths = get_paths_for_patch_raw(hash) + if self.class.client_version_above?([2, 4]) + orig_paths = paths + paths = [] + add_paths = [] + add_paths_name = [] + mod_paths = [] + other_paths = [] + orig_paths.each do |path| + if path[:action] == 'A' + add_paths << path + add_paths_name << path[:path] + elsif path[:action] == 'M' + mod_paths << path + else + other_paths << path + end + end + add_paths_name.each do |add_path| + mod_paths.delete_if { |m| m[:path] == add_path } + end + paths.concat add_paths + paths.concat mod_paths + paths.concat other_paths + end + paths + end + + # Retrieve changed paths for a single patch + def get_paths_for_patch_raw(hash) + cmd = "#{self.class.sq_bin} annotate --repodir #{shell_quote @url} --summary --xml-output" + cmd << " --match #{shell_quote("hash #{hash}")} " + paths = [] + shellout(cmd) do |io| + begin + # Darcs xml output has multiple root elements in this case (tested with darcs 1.0.7) + # A root element is added so that REXML doesn't raise an error + doc = REXML::Document.new("" + io.read + "") + doc.elements.each('fake_root/summary/*') do |modif| + paths << {:action => modif.name[0,1].upcase, + :path => "/" + modif.text.chomp.gsub(/^\s*/, '') + } + end + rescue + end + end + paths + rescue CommandFailed + paths + end + end + end + end +end diff --git a/lib/redmine/scm/adapters/filesystem_adapter.rb b/lib/redmine/scm/adapters/filesystem_adapter.rb new file mode 100644 index 00000000..2ce82b97 --- /dev/null +++ b/lib/redmine/scm/adapters/filesystem_adapter.rb @@ -0,0 +1,118 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# FileSystem adapter +# File written by Paul Rivier, at Demotera. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +require 'redmine/scm/adapters/abstract_adapter' +require 'find' + +module Redmine + module Scm + module Adapters + class FilesystemAdapter < AbstractAdapter + + class << self + def client_available + true + end + end + + def initialize(url, root_url=nil, login=nil, password=nil, + path_encoding=nil) + @url = with_trailling_slash(url) + @path_encoding = path_encoding.blank? ? 'UTF-8' : path_encoding + end + + def path_encoding + @path_encoding + end + + def format_path_ends(path, leading=true, trailling=true) + path = leading ? with_leading_slash(path) : + without_leading_slash(path) + trailling ? with_trailling_slash(path) : + without_trailling_slash(path) + end + + def info + info = Info.new({:root_url => target(), + :lastrev => nil + }) + info + rescue CommandFailed + return nil + end + + def entries(path="", identifier=nil, options={}) + entries = Entries.new + trgt_utf8 = target(path) + trgt = scm_iconv(@path_encoding, 'UTF-8', trgt_utf8) + Dir.new(trgt).each do |e1| + e_utf8 = scm_iconv('UTF-8', @path_encoding, e1) + next if e_utf8.blank? + relative_path_utf8 = format_path_ends( + (format_path_ends(path,false,true) + e_utf8),false,false) + t1_utf8 = target(relative_path_utf8) + t1 = scm_iconv(@path_encoding, 'UTF-8', t1_utf8) + relative_path = scm_iconv(@path_encoding, 'UTF-8', relative_path_utf8) + e1 = scm_iconv(@path_encoding, 'UTF-8', e_utf8) + if File.exist?(t1) and # paranoid test + %w{file directory}.include?(File.ftype(t1)) and # avoid special types + not File.basename(e1).match(/^\.+$/) # avoid . and .. + p1 = File.readable?(t1) ? relative_path : "" + utf_8_path = scm_iconv('UTF-8', @path_encoding, p1) + entries << + Entry.new({ :name => scm_iconv('UTF-8', @path_encoding, File.basename(e1)), + # below : list unreadable files, but dont link them. + :path => utf_8_path, + :kind => (File.directory?(t1) ? 'dir' : 'file'), + :size => (File.directory?(t1) ? nil : [File.size(t1)].pack('l').unpack('L').first), + :lastrev => + Revision.new({:time => (File.mtime(t1)) }) + }) + end + end + entries.sort_by_name + rescue => err + logger.error "scm: filesystem: error: #{err.message}" + raise CommandFailed.new(err.message) + end + + def cat(path, identifier=nil) + p = scm_iconv(@path_encoding, 'UTF-8', target(path)) + File.new(p, "rb").read + rescue => err + logger.error "scm: filesystem: error: #{err.message}" + raise CommandFailed.new(err.message) + end + + private + + # AbstractAdapter::target is implicitly made to quote paths. + # Here we do not shell-out, so we do not want quotes. + def target(path=nil) + # Prevent the use of .. + if path and !path.match(/(^|\/)\.\.(\/|$)/) + return "#{self.url}#{without_leading_slash(path)}" + end + return self.url + end + end + end + end +end diff --git a/lib/redmine/scm/adapters/git_adapter.rb b/lib/redmine/scm/adapters/git_adapter.rb new file mode 100644 index 00000000..1876190d --- /dev/null +++ b/lib/redmine/scm/adapters/git_adapter.rb @@ -0,0 +1,412 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +require 'redmine/scm/adapters/abstract_adapter' + +module Redmine + module Scm + module Adapters + class GitAdapter < AbstractAdapter + + # Git executable name + GIT_BIN = Redmine::Configuration['scm_git_command'] || "git" + + class GitBranch < Branch + attr_accessor :is_default + end + + class << self + def client_command + @@bin ||= GIT_BIN + end + + def sq_bin + @@sq_bin ||= shell_quote_command + end + + def client_version + @@client_version ||= (scm_command_version || []) + end + + def client_available + !client_version.empty? + end + + def scm_command_version + scm_version = scm_version_from_command_line.dup + if scm_version.respond_to?(:force_encoding) + scm_version.force_encoding('ASCII-8BIT') + end + if m = scm_version.match(%r{\A(.*?)((\d+\.)+\d+)}) + m[2].scan(%r{\d+}).collect(&:to_i) + end + end + + def scm_version_from_command_line + shellout("#{sq_bin} --version --no-color") { |io| io.read }.to_s + end + end + + def initialize(url, root_url=nil, login=nil, password=nil, path_encoding=nil) + super + @path_encoding = path_encoding.blank? ? 'UTF-8' : path_encoding + end + + def path_encoding + @path_encoding + end + + def info + begin + Info.new(:root_url => url, :lastrev => lastrev('',nil)) + rescue + nil + end + end + + def branches + return @branches if @branches + @branches = [] + cmd_args = %w|branch --no-color --verbose --no-abbrev| + git_cmd(cmd_args) do |io| + io.each_line do |line| + branch_rev = line.match('\s*(\*?)\s*(.*?)\s*([0-9a-f]{40}).*$') + bran = GitBranch.new(branch_rev[2]) + bran.revision = branch_rev[3] + bran.scmid = branch_rev[3] + bran.is_default = ( branch_rev[1] == '*' ) + @branches << bran + end + end + @branches.sort! + rescue ScmCommandAborted + nil + end + + def tags + return @tags if @tags + cmd_args = %w|tag| + git_cmd(cmd_args) do |io| + @tags = io.readlines.sort!.map{|t| t.strip} + end + rescue ScmCommandAborted + nil + end + + def default_branch + bras = self.branches + return nil if bras.nil? + default_bras = bras.select{|x| x.is_default == true} + return default_bras.first.to_s if ! default_bras.empty? + master_bras = bras.select{|x| x.to_s == 'master'} + master_bras.empty? ? bras.first.to_s : 'master' + end + + def entry(path=nil, identifier=nil) + parts = path.to_s.split(%r{[\/\\]}).select {|n| !n.blank?} + search_path = parts[0..-2].join('/') + search_name = parts[-1] + if search_path.blank? && search_name.blank? + # Root entry + Entry.new(:path => '', :kind => 'dir') + else + # Search for the entry in the parent directory + es = entries(search_path, identifier, + options = {:report_last_commit => false}) + es ? es.detect {|e| e.name == search_name} : nil + end + end + + def entries(path=nil, identifier=nil, options={}) + path ||= '' + p = scm_iconv(@path_encoding, 'UTF-8', path) + entries = Entries.new + cmd_args = %w|ls-tree -l| + cmd_args << "HEAD:#{p}" if identifier.nil? + cmd_args << "#{identifier}:#{p}" if identifier + git_cmd(cmd_args) do |io| + io.each_line do |line| + e = line.chomp.to_s + if e =~ /^\d+\s+(\w+)\s+([0-9a-f]{40})\s+([0-9-]+)\t(.+)$/ + type = $1 + sha = $2 + size = $3 + name = $4 + if name.respond_to?(:force_encoding) + name.force_encoding(@path_encoding) + end + full_path = p.empty? ? name : "#{p}/#{name}" + n = scm_iconv('UTF-8', @path_encoding, name) + full_p = scm_iconv('UTF-8', @path_encoding, full_path) + entries << Entry.new({:name => n, + :path => full_p, + :kind => (type == "tree") ? 'dir' : 'file', + :size => (type == "tree") ? nil : size, + :lastrev => options[:report_last_commit] ? + lastrev(full_path, identifier) : Revision.new + }) unless entries.detect{|entry| entry.name == name} + end + end + end + entries.sort_by_name + rescue ScmCommandAborted + nil + end + + def lastrev(path, rev) + return nil if path.nil? + cmd_args = %w|log --no-color --encoding=UTF-8 --date=iso --pretty=fuller --no-merges -n 1| + cmd_args << rev if rev + cmd_args << "--" << path unless path.empty? + lines = [] + git_cmd(cmd_args) { |io| lines = io.readlines } + begin + id = lines[0].split[1] + author = lines[1].match('Author:\s+(.*)$')[1] + time = Time.parse(lines[4].match('CommitDate:\s+(.*)$')[1]) + + Revision.new({ + :identifier => id, + :scmid => id, + :author => author, + :time => time, + :message => nil, + :paths => nil + }) + rescue NoMethodError => e + logger.error("The revision '#{path}' has a wrong format") + return nil + end + rescue ScmCommandAborted + nil + end + + def revisions(path, identifier_from, identifier_to, options={}) + revs = Revisions.new + cmd_args = %w|log --no-color --encoding=UTF-8 --raw --date=iso --pretty=fuller --parents --stdin| + cmd_args << "--reverse" if options[:reverse] + cmd_args << "-n" << "#{options[:limit].to_i}" if options[:limit] + cmd_args << "--" << scm_iconv(@path_encoding, 'UTF-8', path) if path && !path.empty? + revisions = [] + if identifier_from || identifier_to + revisions << "" + revisions[0] << "#{identifier_from}.." if identifier_from + revisions[0] << "#{identifier_to}" if identifier_to + else + unless options[:includes].blank? + revisions += options[:includes] + end + unless options[:excludes].blank? + revisions += options[:excludes].map{|r| "^#{r}"} + end + end + + git_cmd(cmd_args, {:write_stdin => true}) do |io| + io.binmode + io.puts(revisions.join("\n")) + io.close_write + files=[] + changeset = {} + parsing_descr = 0 #0: not parsing desc or files, 1: parsing desc, 2: parsing files + + io.each_line do |line| + if line =~ /^commit ([0-9a-f]{40})(( [0-9a-f]{40})*)$/ + key = "commit" + value = $1 + parents_str = $2 + if (parsing_descr == 1 || parsing_descr == 2) + parsing_descr = 0 + revision = Revision.new({ + :identifier => changeset[:commit], + :scmid => changeset[:commit], + :author => changeset[:author], + :time => Time.parse(changeset[:date]), + :message => changeset[:description], + :paths => files, + :parents => changeset[:parents] + }) + if block_given? + yield revision + else + revs << revision + end + changeset = {} + files = [] + end + changeset[:commit] = $1 + unless parents_str.nil? or parents_str == "" + changeset[:parents] = parents_str.strip.split(' ') + end + elsif (parsing_descr == 0) && line =~ /^(\w+):\s*(.*)$/ + key = $1 + value = $2 + if key == "Author" + changeset[:author] = value + elsif key == "CommitDate" + changeset[:date] = value + end + elsif (parsing_descr == 0) && line.chomp.to_s == "" + parsing_descr = 1 + changeset[:description] = "" + elsif (parsing_descr == 1 || parsing_descr == 2) \ + && line =~ /^:\d+\s+\d+\s+[0-9a-f.]+\s+[0-9a-f.]+\s+(\w)\t(.+)$/ + parsing_descr = 2 + fileaction = $1 + filepath = $2 + p = scm_iconv('UTF-8', @path_encoding, filepath) + files << {:action => fileaction, :path => p} + elsif (parsing_descr == 1 || parsing_descr == 2) \ + && line =~ /^:\d+\s+\d+\s+[0-9a-f.]+\s+[0-9a-f.]+\s+(\w)\d+\s+(\S+)\t(.+)$/ + parsing_descr = 2 + fileaction = $1 + filepath = $3 + p = scm_iconv('UTF-8', @path_encoding, filepath) + files << {:action => fileaction, :path => p} + elsif (parsing_descr == 1) && line.chomp.to_s == "" + parsing_descr = 2 + elsif (parsing_descr == 1) + changeset[:description] << line[4..-1] + end + end + + if changeset[:commit] + revision = Revision.new({ + :identifier => changeset[:commit], + :scmid => changeset[:commit], + :author => changeset[:author], + :time => Time.parse(changeset[:date]), + :message => changeset[:description], + :paths => files, + :parents => changeset[:parents] + }) + if block_given? + yield revision + else + revs << revision + end + end + end + revs + rescue ScmCommandAborted => e + err_msg = "git log error: #{e.message}" + logger.error(err_msg) + if block_given? + raise CommandFailed, err_msg + else + revs + end + end + + def diff(path, identifier_from, identifier_to=nil) + path ||= '' + cmd_args = [] + if identifier_to + cmd_args << "diff" << "--no-color" << identifier_to << identifier_from + else + cmd_args << "show" << "--no-color" << identifier_from + end + cmd_args << "--" << scm_iconv(@path_encoding, 'UTF-8', path) unless path.empty? + diff = [] + git_cmd(cmd_args) do |io| + io.each_line do |line| + diff << line + end + end + diff + rescue ScmCommandAborted + nil + end + + def annotate(path, identifier=nil) + identifier = 'HEAD' if identifier.blank? + cmd_args = %w|blame| + cmd_args << "-p" << identifier << "--" << scm_iconv(@path_encoding, 'UTF-8', path) + blame = Annotate.new + content = nil + git_cmd(cmd_args) { |io| io.binmode; content = io.read } + # git annotates binary files + return nil if content.is_binary_data? + identifier = '' + # git shows commit author on the first occurrence only + authors_by_commit = {} + content.split("\n").each do |line| + if line =~ /^([0-9a-f]{39,40})\s.*/ + identifier = $1 + elsif line =~ /^author (.+)/ + authors_by_commit[identifier] = $1.strip + elsif line =~ /^\t(.*)/ + blame.add_line($1, Revision.new( + :identifier => identifier, + :revision => identifier, + :scmid => identifier, + :author => authors_by_commit[identifier] + )) + identifier = '' + author = '' + end + end + blame + rescue ScmCommandAborted + nil + end + + def cat(path, identifier=nil) + if identifier.nil? + identifier = 'HEAD' + end + cmd_args = %w|show --no-color| + cmd_args << "#{identifier}:#{scm_iconv(@path_encoding, 'UTF-8', path)}" + cat = nil + git_cmd(cmd_args) do |io| + io.binmode + cat = io.read + end + cat + rescue ScmCommandAborted + nil + end + + class Revision < Redmine::Scm::Adapters::Revision + # Returns the readable identifier + def format_identifier + identifier[0,8] + end + end + + def git_cmd(args, options = {}, &block) + repo_path = root_url || url + full_args = ['--git-dir', repo_path] + if self.class.client_version_above?([1, 7, 2]) + full_args << '-c' << 'core.quotepath=false' + full_args << '-c' << 'log.decorate=no' + end + full_args += args + ret = shellout( + self.class.sq_bin + ' ' + full_args.map { |e| shell_quote e.to_s }.join(' '), + options, + &block + ) + if $? && $?.exitstatus != 0 + raise ScmCommandAborted, "git exited with non-zero status: #{$?.exitstatus}" + end + ret + end + private :git_cmd + end + end + end +end diff --git a/lib/redmine/scm/adapters/mercurial/hg-template-1.0.tmpl b/lib/redmine/scm/adapters/mercurial/hg-template-1.0.tmpl new file mode 100644 index 00000000..a2a324ba --- /dev/null +++ b/lib/redmine/scm/adapters/mercurial/hg-template-1.0.tmpl @@ -0,0 +1,12 @@ +changeset = 'This template must be used with --debug option\n' +changeset_quiet = 'This template must be used with --debug option\n' +changeset_verbose = 'This template must be used with --debug option\n' +changeset_debug = '\n{author|escape}\n{date|isodatesec}\n\n{file_mods}{file_adds}{file_dels}{file_copies}\n{desc|escape}\n\n{parents}\n\n\n' + +file_mod = '{file_mod|urlescape}\n' +file_add = '{file_add|urlescape}\n' +file_del = '{file_del|urlescape}\n' +file_copy = '{name|urlescape}\n' +parent = '{node|short}\n' +header='\n\n\n' +# footer="" diff --git a/lib/redmine/scm/adapters/mercurial/redminehelper.py b/lib/redmine/scm/adapters/mercurial/redminehelper.py new file mode 100644 index 00000000..bd82c002 --- /dev/null +++ b/lib/redmine/scm/adapters/mercurial/redminehelper.py @@ -0,0 +1,220 @@ +# redminehelper: Redmine helper extension for Mercurial +# +# Copyright 2010 Alessio Franceschelli (alefranz.net) +# Copyright 2010-2011 Yuya Nishihara +# +# This software may be used and distributed according to the terms of the +# GNU General Public License version 2 or any later version. +"""helper commands for Redmine to reduce the number of hg calls + +To test this extension, please try:: + + $ hg --config extensions.redminehelper=redminehelper.py rhsummary + +I/O encoding: + +:file path: urlencoded, raw string +:tag name: utf-8 +:branch name: utf-8 +:node: 12-digits (short) hex string + +Output example of rhsummary:: + + + + + + + + ... + + + +Output example of rhmanifest:: + + + + + + + ... + + ... + + + +""" +import re, time, cgi, urllib +from mercurial import cmdutil, commands, node, error, hg + +_x = cgi.escape +_u = lambda s: cgi.escape(urllib.quote(s)) + +def _tip(ui, repo): + # see mercurial/commands.py:tip + def tiprev(): + try: + return len(repo) - 1 + except TypeError: # Mercurial < 1.1 + return repo.changelog.count() - 1 + tipctx = repo.changectx(tiprev()) + ui.write('\n' + % (tipctx.rev(), _x(node.short(tipctx.node())))) + +_SPECIAL_TAGS = ('tip',) + +def _tags(ui, repo): + # see mercurial/commands.py:tags + for t, n in reversed(repo.tagslist()): + if t in _SPECIAL_TAGS: + continue + try: + r = repo.changelog.rev(n) + except error.LookupError: + continue + ui.write('\n' + % (r, _x(node.short(n)), _x(t))) + +def _branches(ui, repo): + # see mercurial/commands.py:branches + def iterbranches(): + for t, n in repo.branchtags().iteritems(): + yield t, n, repo.changelog.rev(n) + def branchheads(branch): + try: + return repo.branchheads(branch, closed=False) + except TypeError: # Mercurial < 1.2 + return repo.branchheads(branch) + for t, n, r in sorted(iterbranches(), key=lambda e: e[2], reverse=True): + if repo.lookup(r) in branchheads(t): + ui.write('\n' + % (r, _x(node.short(n)), _x(t))) + +def _manifest(ui, repo, path, rev): + ctx = repo.changectx(rev) + ui.write('\n' + % (ctx.rev(), _u(path))) + + known = set() + pathprefix = (path.rstrip('/') + '/').lstrip('/') + for f, n in sorted(ctx.manifest().iteritems(), key=lambda e: e[0]): + if not f.startswith(pathprefix): + continue + name = re.sub(r'/.*', '/', f[len(pathprefix):]) + if name in known: + continue + known.add(name) + + if name.endswith('/'): + ui.write('\n' + % _x(urllib.quote(name[:-1]))) + else: + fctx = repo.filectx(f, fileid=n) + tm, tzoffset = fctx.date() + ui.write('\n' + % (_u(name), fctx.rev(), _x(node.short(fctx.node())), + tm, fctx.size(), )) + + ui.write('\n') + +def rhannotate(ui, repo, *pats, **opts): + rev = urllib.unquote_plus(opts.pop('rev', None)) + opts['rev'] = rev + return commands.annotate(ui, repo, *map(urllib.unquote_plus, pats), **opts) + +def rhcat(ui, repo, file1, *pats, **opts): + rev = urllib.unquote_plus(opts.pop('rev', None)) + opts['rev'] = rev + return commands.cat(ui, repo, urllib.unquote_plus(file1), *map(urllib.unquote_plus, pats), **opts) + +def rhdiff(ui, repo, *pats, **opts): + """diff repository (or selected files)""" + change = opts.pop('change', None) + if change: # add -c option for Mercurial<1.1 + base = repo.changectx(change).parents()[0].rev() + opts['rev'] = [str(base), change] + opts['nodates'] = True + return commands.diff(ui, repo, *map(urllib.unquote_plus, pats), **opts) + +def rhlog(ui, repo, *pats, **opts): + rev = opts.pop('rev') + bra0 = opts.pop('branch') + from_rev = urllib.unquote_plus(opts.pop('from', None)) + to_rev = urllib.unquote_plus(opts.pop('to' , None)) + bra = urllib.unquote_plus(opts.pop('rhbranch', None)) + from_rev = from_rev.replace('"', '\\"') + to_rev = to_rev.replace('"', '\\"') + if hg.util.version() >= '1.6': + opts['rev'] = ['"%s":"%s"' % (from_rev, to_rev)] + else: + opts['rev'] = ['%s:%s' % (from_rev, to_rev)] + opts['branch'] = [bra] + return commands.log(ui, repo, *map(urllib.unquote_plus, pats), **opts) + +def rhmanifest(ui, repo, path='', **opts): + """output the sub-manifest of the specified directory""" + ui.write('\n') + ui.write('\n') + ui.write('\n' % _u(repo.root)) + try: + _manifest(ui, repo, urllib.unquote_plus(path), urllib.unquote_plus(opts.get('rev'))) + finally: + ui.write('\n') + ui.write('\n') + +def rhsummary(ui, repo, **opts): + """output the summary of the repository""" + ui.write('\n') + ui.write('\n') + ui.write('\n' % _u(repo.root)) + try: + _tip(ui, repo) + _tags(ui, repo) + _branches(ui, repo) + # TODO: bookmarks in core (Mercurial>=1.8) + finally: + ui.write('\n') + ui.write('\n') + +cmdtable = { + 'rhannotate': (rhannotate, + [('r', 'rev', '', 'revision'), + ('u', 'user', None, 'list the author (long with -v)'), + ('n', 'number', None, 'list the revision number (default)'), + ('c', 'changeset', None, 'list the changeset'), + ], + 'hg rhannotate [-r REV] [-u] [-n] [-c] FILE...'), + 'rhcat': (rhcat, + [('r', 'rev', '', 'revision')], + 'hg rhcat ([-r REV] ...) FILE...'), + 'rhdiff': (rhdiff, + [('r', 'rev', [], 'revision'), + ('c', 'change', '', 'change made by revision')], + 'hg rhdiff ([-c REV] | [-r REV] ...) [FILE]...'), + 'rhlog': (rhlog, + [ + ('r', 'rev', [], 'show the specified revision'), + ('b', 'branch', [], + 'show changesets within the given named branch'), + ('l', 'limit', '', + 'limit number of changes displayed'), + ('d', 'date', '', + 'show revisions matching date spec'), + ('u', 'user', [], + 'revisions committed by user'), + ('', 'from', '', + ''), + ('', 'to', '', + ''), + ('', 'rhbranch', '', + ''), + ('', 'template', '', + 'display with template')], + 'hg rhlog [OPTION]... [FILE]'), + 'rhmanifest': (rhmanifest, + [('r', 'rev', '', 'show the specified revision')], + 'hg rhmanifest [-r REV] [PATH]'), + 'rhsummary': (rhsummary, [], 'hg rhsummary'), +} diff --git a/lib/redmine/scm/adapters/mercurial_adapter.rb b/lib/redmine/scm/adapters/mercurial_adapter.rb new file mode 100644 index 00000000..a6bf959c --- /dev/null +++ b/lib/redmine/scm/adapters/mercurial_adapter.rb @@ -0,0 +1,341 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +require 'redmine/scm/adapters/abstract_adapter' +require 'cgi' + +module Redmine + module Scm + module Adapters + class MercurialAdapter < AbstractAdapter + + # Mercurial executable name + HG_BIN = Redmine::Configuration['scm_mercurial_command'] || "hg" + HELPERS_DIR = File.dirname(__FILE__) + "/mercurial" + HG_HELPER_EXT = "#{HELPERS_DIR}/redminehelper.py" + TEMPLATE_NAME = "hg-template" + TEMPLATE_EXTENSION = "tmpl" + + # raised if hg command exited with error, e.g. unknown revision. + class HgCommandAborted < CommandFailed; end + + class << self + def client_command + @@bin ||= HG_BIN + end + + def sq_bin + @@sq_bin ||= shell_quote_command + end + + def client_version + @@client_version ||= (hgversion || []) + end + + def client_available + client_version_above?([1, 2]) + end + + def hgversion + # The hg version is expressed either as a + # release number (eg 0.9.5 or 1.0) or as a revision + # id composed of 12 hexa characters. + theversion = hgversion_from_command_line.dup + if theversion.respond_to?(:force_encoding) + theversion.force_encoding('ASCII-8BIT') + end + if m = theversion.match(%r{\A(.*?)((\d+\.)+\d+)}) + m[2].scan(%r{\d+}).collect(&:to_i) + end + end + + def hgversion_from_command_line + shellout("#{sq_bin} --version") { |io| io.read }.to_s + end + + def template_path + @@template_path ||= template_path_for(client_version) + end + + def template_path_for(version) + "#{HELPERS_DIR}/#{TEMPLATE_NAME}-1.0.#{TEMPLATE_EXTENSION}" + end + end + + def initialize(url, root_url=nil, login=nil, password=nil, path_encoding=nil) + super + @path_encoding = path_encoding.blank? ? 'UTF-8' : path_encoding + end + + def path_encoding + @path_encoding + end + + def info + tip = summary['repository']['tip'] + Info.new(:root_url => CGI.unescape(summary['repository']['root']), + :lastrev => Revision.new(:revision => tip['revision'], + :scmid => tip['node'])) + # rescue HgCommandAborted + rescue Exception => e + logger.error "hg: error during getting info: #{e.message}" + nil + end + + def tags + as_ary(summary['repository']['tag']).map { |e| e['name'] } + end + + # Returns map of {'tag' => 'nodeid', ...} + def tagmap + alist = as_ary(summary['repository']['tag']).map do |e| + e.values_at('name', 'node') + end + Hash[*alist.flatten] + end + + def branches + brs = [] + as_ary(summary['repository']['branch']).each do |e| + br = Branch.new(e['name']) + br.revision = e['revision'] + br.scmid = e['node'] + brs << br + end + brs + end + + # Returns map of {'branch' => 'nodeid', ...} + def branchmap + alist = as_ary(summary['repository']['branch']).map do |e| + e.values_at('name', 'node') + end + Hash[*alist.flatten] + end + + def summary + return @summary if @summary + hg 'rhsummary' do |io| + output = io.read + if output.respond_to?(:force_encoding) + output.force_encoding('UTF-8') + end + begin + @summary = parse_xml(output)['rhsummary'] + rescue + end + end + end + private :summary + + def entries(path=nil, identifier=nil, options={}) + p1 = scm_iconv(@path_encoding, 'UTF-8', path) + manifest = hg('rhmanifest', '-r', CGI.escape(hgrev(identifier)), + CGI.escape(without_leading_slash(p1.to_s))) do |io| + output = io.read + if output.respond_to?(:force_encoding) + output.force_encoding('UTF-8') + end + begin + parse_xml(output)['rhmanifest']['repository']['manifest'] + rescue + end + end + path_prefix = path.blank? ? '' : with_trailling_slash(path) + + entries = Entries.new + as_ary(manifest['dir']).each do |e| + n = scm_iconv('UTF-8', @path_encoding, CGI.unescape(e['name'])) + p = "#{path_prefix}#{n}" + entries << Entry.new(:name => n, :path => p, :kind => 'dir') + end + + as_ary(manifest['file']).each do |e| + n = scm_iconv('UTF-8', @path_encoding, CGI.unescape(e['name'])) + p = "#{path_prefix}#{n}" + lr = Revision.new(:revision => e['revision'], :scmid => e['node'], + :identifier => e['node'], + :time => Time.at(e['time'].to_i)) + entries << Entry.new(:name => n, :path => p, :kind => 'file', + :size => e['size'].to_i, :lastrev => lr) + end + + entries + rescue HgCommandAborted + nil # means not found + end + + def revisions(path=nil, identifier_from=nil, identifier_to=nil, options={}) + revs = Revisions.new + each_revision(path, identifier_from, identifier_to, options) { |e| revs << e } + revs + end + + # Iterates the revisions by using a template file that + # makes Mercurial produce a xml output. + def each_revision(path=nil, identifier_from=nil, identifier_to=nil, options={}) + hg_args = ['log', '--debug', '-C', '--style', self.class.template_path] + hg_args << '-r' << "#{hgrev(identifier_from)}:#{hgrev(identifier_to)}" + hg_args << '--limit' << options[:limit] if options[:limit] + hg_args << hgtarget(path) unless path.blank? + log = hg(*hg_args) do |io| + output = io.read + if output.respond_to?(:force_encoding) + output.force_encoding('UTF-8') + end + begin + # Mercurial < 1.5 does not support footer template for '' + parse_xml("#{output}")['log'] + rescue + end + end + as_ary(log['logentry']).each do |le| + cpalist = as_ary(le['paths']['path-copied']).map do |e| + [e['__content__'], e['copyfrom-path']].map do |s| + scm_iconv('UTF-8', @path_encoding, CGI.unescape(s)) + end + end + cpmap = Hash[*cpalist.flatten] + paths = as_ary(le['paths']['path']).map do |e| + p = scm_iconv('UTF-8', @path_encoding, CGI.unescape(e['__content__']) ) + {:action => e['action'], + :path => with_leading_slash(p), + :from_path => (cpmap.member?(p) ? with_leading_slash(cpmap[p]) : nil), + :from_revision => (cpmap.member?(p) ? le['node'] : nil)} + end.sort { |a, b| a[:path] <=> b[:path] } + parents_ary = [] + as_ary(le['parents']['parent']).map do |par| + parents_ary << par['__content__'] if par['__content__'] != "000000000000" + end + yield Revision.new(:revision => le['revision'], + :scmid => le['node'], + :author => (le['author']['__content__'] rescue ''), + :time => Time.parse(le['date']['__content__']), + :message => le['msg']['__content__'], + :paths => paths, + :parents => parents_ary) + end + self + end + + # Returns list of nodes in the specified branch + def nodes_in_branch(branch, options={}) + hg_args = ['rhlog', '--template', '{node|short}\n', '--rhbranch', CGI.escape(branch)] + hg_args << '--from' << CGI.escape(branch) + hg_args << '--to' << '0' + hg_args << '--limit' << options[:limit] if options[:limit] + hg(*hg_args) { |io| io.readlines.map { |e| e.chomp } } + end + + def diff(path, identifier_from, identifier_to=nil) + hg_args = %w|rhdiff| + if identifier_to + hg_args << '-r' << hgrev(identifier_to) << '-r' << hgrev(identifier_from) + else + hg_args << '-c' << hgrev(identifier_from) + end + unless path.blank? + p = scm_iconv(@path_encoding, 'UTF-8', path) + hg_args << CGI.escape(hgtarget(p)) + end + diff = [] + hg *hg_args do |io| + io.each_line do |line| + diff << line + end + end + diff + rescue HgCommandAborted + nil # means not found + end + + def cat(path, identifier=nil) + p = CGI.escape(scm_iconv(@path_encoding, 'UTF-8', path)) + hg 'rhcat', '-r', CGI.escape(hgrev(identifier)), hgtarget(p) do |io| + io.binmode + io.read + end + rescue HgCommandAborted + nil # means not found + end + + def annotate(path, identifier=nil) + p = CGI.escape(scm_iconv(@path_encoding, 'UTF-8', path)) + blame = Annotate.new + hg 'rhannotate', '-ncu', '-r', CGI.escape(hgrev(identifier)), hgtarget(p) do |io| + io.each_line do |line| + line.force_encoding('ASCII-8BIT') if line.respond_to?(:force_encoding) + next unless line =~ %r{^([^:]+)\s(\d+)\s([0-9a-f]+):\s(.*)$} + r = Revision.new(:author => $1.strip, :revision => $2, :scmid => $3, + :identifier => $3) + blame.add_line($4.rstrip, r) + end + end + blame + rescue HgCommandAborted + # means not found or cannot be annotated + Annotate.new + end + + class Revision < Redmine::Scm::Adapters::Revision + # Returns the readable identifier + def format_identifier + "#{revision}:#{scmid}" + end + end + + # Runs 'hg' command with the given args + def hg(*args, &block) + repo_path = root_url || url + full_args = ['-R', repo_path, '--encoding', 'utf-8'] + full_args << '--config' << "extensions.redminehelper=#{HG_HELPER_EXT}" + full_args << '--config' << 'diff.git=false' + full_args += args + ret = shellout( + self.class.sq_bin + ' ' + full_args.map { |e| shell_quote e.to_s }.join(' '), + &block + ) + if $? && $?.exitstatus != 0 + raise HgCommandAborted, "hg exited with non-zero status: #{$?.exitstatus}" + end + ret + end + private :hg + + # Returns correct revision identifier + def hgrev(identifier, sq=false) + rev = identifier.blank? ? 'tip' : identifier.to_s + rev = shell_quote(rev) if sq + rev + end + private :hgrev + + def hgtarget(path) + path ||= '' + root_url + '/' + without_leading_slash(path) + end + private :hgtarget + + def as_ary(o) + return [] unless o + o.is_a?(Array) ? o : Array[o] + end + private :as_ary + end + end + end +end diff --git a/lib/redmine/scm/adapters/subversion_adapter.rb b/lib/redmine/scm/adapters/subversion_adapter.rb new file mode 100644 index 00000000..c496ba14 --- /dev/null +++ b/lib/redmine/scm/adapters/subversion_adapter.rb @@ -0,0 +1,291 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +require 'redmine/scm/adapters/abstract_adapter' +require 'uri' + +module Redmine + module Scm + module Adapters + class SubversionAdapter < AbstractAdapter + + # SVN executable name + SVN_BIN = Redmine::Configuration['scm_subversion_command'] || "svn" + + class << self + def client_command + @@bin ||= SVN_BIN + end + + def sq_bin + @@sq_bin ||= shell_quote_command + end + + def client_version + @@client_version ||= (svn_binary_version || []) + end + + def client_available + # --xml options are introduced in 1.3. + # http://subversion.apache.org/docs/release-notes/1.3.html + client_version_above?([1, 3]) + end + + def svn_binary_version + scm_version = scm_version_from_command_line.dup + if scm_version.respond_to?(:force_encoding) + scm_version.force_encoding('ASCII-8BIT') + end + if m = scm_version.match(%r{\A(.*?)((\d+\.)+\d+)}) + m[2].scan(%r{\d+}).collect(&:to_i) + end + end + + def scm_version_from_command_line + shellout("#{sq_bin} --version") { |io| io.read }.to_s + end + end + + # Get info about the svn repository + def info + cmd = "#{self.class.sq_bin} info --xml #{target}" + cmd << credentials_string + info = nil + shellout(cmd) do |io| + output = io.read + if output.respond_to?(:force_encoding) + output.force_encoding('UTF-8') + end + begin + doc = parse_xml(output) + # root_url = doc.elements["info/entry/repository/root"].text + info = Info.new({:root_url => doc['info']['entry']['repository']['root']['__content__'], + :lastrev => Revision.new({ + :identifier => doc['info']['entry']['commit']['revision'], + :time => Time.parse(doc['info']['entry']['commit']['date']['__content__']).localtime, + :author => (doc['info']['entry']['commit']['author'] ? doc['info']['entry']['commit']['author']['__content__'] : "") + }) + }) + rescue + end + end + return nil if $? && $?.exitstatus != 0 + info + rescue CommandFailed + return nil + end + + # Returns an Entries collection + # or nil if the given path doesn't exist in the repository + def entries(path=nil, identifier=nil, options={}) + path ||= '' + identifier = (identifier and identifier.to_i > 0) ? identifier.to_i : "HEAD" + entries = Entries.new + cmd = "#{self.class.sq_bin} list --xml #{target(path)}@#{identifier}" + cmd << credentials_string + shellout(cmd) do |io| + output = io.read + if output.respond_to?(:force_encoding) + output.force_encoding('UTF-8') + end + begin + doc = parse_xml(output) + each_xml_element(doc['lists']['list'], 'entry') do |entry| + commit = entry['commit'] + commit_date = commit['date'] + # Skip directory if there is no commit date (usually that + # means that we don't have read access to it) + next if entry['kind'] == 'dir' && commit_date.nil? + name = entry['name']['__content__'] + entries << Entry.new({:name => URI.unescape(name), + :path => ((path.empty? ? "" : "#{path}/") + name), + :kind => entry['kind'], + :size => ((s = entry['size']) ? s['__content__'].to_i : nil), + :lastrev => Revision.new({ + :identifier => commit['revision'], + :time => Time.parse(commit_date['__content__'].to_s).localtime, + :author => ((a = commit['author']) ? a['__content__'] : nil) + }) + }) + end + rescue Exception => e + logger.error("Error parsing svn output: #{e.message}") + logger.error("Output was:\n #{output}") + end + end + return nil if $? && $?.exitstatus != 0 + logger.debug("Found #{entries.size} entries in the repository for #{target(path)}") if logger && logger.debug? + entries.sort_by_name + end + + def properties(path, identifier=nil) + # proplist xml output supported in svn 1.5.0 and higher + return nil unless self.class.client_version_above?([1, 5, 0]) + + identifier = (identifier and identifier.to_i > 0) ? identifier.to_i : "HEAD" + cmd = "#{self.class.sq_bin} proplist --verbose --xml #{target(path)}@#{identifier}" + cmd << credentials_string + properties = {} + shellout(cmd) do |io| + output = io.read + if output.respond_to?(:force_encoding) + output.force_encoding('UTF-8') + end + begin + doc = parse_xml(output) + each_xml_element(doc['properties']['target'], 'property') do |property| + properties[ property['name'] ] = property['__content__'].to_s + end + rescue + end + end + return nil if $? && $?.exitstatus != 0 + properties + end + + def revisions(path=nil, identifier_from=nil, identifier_to=nil, options={}) + path ||= '' + identifier_from = (identifier_from && identifier_from.to_i > 0) ? identifier_from.to_i : "HEAD" + identifier_to = (identifier_to && identifier_to.to_i > 0) ? identifier_to.to_i : 1 + revisions = Revisions.new + cmd = "#{self.class.sq_bin} log --xml -r #{identifier_from}:#{identifier_to}" + cmd << credentials_string + cmd << " --verbose " if options[:with_paths] + cmd << " --limit #{options[:limit].to_i}" if options[:limit] + cmd << ' ' + target(path) + shellout(cmd) do |io| + output = io.read + if output.respond_to?(:force_encoding) + output.force_encoding('UTF-8') + end + begin + doc = parse_xml(output) + each_xml_element(doc['log'], 'logentry') do |logentry| + paths = [] + each_xml_element(logentry['paths'], 'path') do |path| + paths << {:action => path['action'], + :path => path['__content__'], + :from_path => path['copyfrom-path'], + :from_revision => path['copyfrom-rev'] + } + end if logentry['paths'] && logentry['paths']['path'] + paths.sort! { |x,y| x[:path] <=> y[:path] } + + revisions << Revision.new({:identifier => logentry['revision'], + :author => (logentry['author'] ? logentry['author']['__content__'] : ""), + :time => Time.parse(logentry['date']['__content__'].to_s).localtime, + :message => logentry['msg']['__content__'], + :paths => paths + }) + end + rescue + end + end + return nil if $? && $?.exitstatus != 0 + revisions + end + + def diff(path, identifier_from, identifier_to=nil) + path ||= '' + identifier_from = (identifier_from and identifier_from.to_i > 0) ? identifier_from.to_i : '' + + identifier_to = (identifier_to and identifier_to.to_i > 0) ? identifier_to.to_i : (identifier_from.to_i - 1) + + cmd = "#{self.class.sq_bin} diff -r " + cmd << "#{identifier_to}:" + cmd << "#{identifier_from}" + cmd << " #{target(path)}@#{identifier_from}" + cmd << credentials_string + diff = [] + shellout(cmd) do |io| + io.each_line do |line| + diff << line + end + end + return nil if $? && $?.exitstatus != 0 + diff + end + + def cat(path, identifier=nil) + identifier = (identifier and identifier.to_i > 0) ? identifier.to_i : "HEAD" + cmd = "#{self.class.sq_bin} cat #{target(path)}@#{identifier}" + cmd << credentials_string + cat = nil + shellout(cmd) do |io| + io.binmode + cat = io.read + end + return nil if $? && $?.exitstatus != 0 + cat + end + + def annotate(path, identifier=nil) + identifier = (identifier and identifier.to_i > 0) ? identifier.to_i : "HEAD" + cmd = "#{self.class.sq_bin} blame #{target(path)}@#{identifier}" + cmd << credentials_string + blame = Annotate.new + shellout(cmd) do |io| + io.each_line do |line| + next unless line =~ %r{^\s*(\d+)\s*(\S+)\s(.*)$} + rev = $1 + blame.add_line($3.rstrip, + Revision.new( + :identifier => rev, + :revision => rev, + :author => $2.strip + )) + end + end + return nil if $? && $?.exitstatus != 0 + blame + end + + private + + def credentials_string + str = '' + str << " --username #{shell_quote(@login)}" unless @login.blank? + str << " --password #{shell_quote(@password)}" unless @login.blank? || @password.blank? + str << " --no-auth-cache --non-interactive" + str + end + + # Helper that iterates over the child elements of a xml node + # MiniXml returns a hash when a single child is found + # or an array of hashes for multiple children + def each_xml_element(node, name) + if node && node[name] + if node[name].is_a?(Hash) + yield node[name] + else + node[name].each do |element| + yield element + end + end + end + end + + def target(path = '') + base = path.match(/^\//) ? root_url : url + uri = "#{base}/#{path}" + uri = URI.escape(URI.escape(uri), '[]') + shell_quote(uri.gsub(/[?<>\*]/, '')) + end + end + end + end +end diff --git a/lib/redmine/scm/base.rb b/lib/redmine/scm/base.rb new file mode 100644 index 00000000..b33a9cfd --- /dev/null +++ b/lib/redmine/scm/base.rb @@ -0,0 +1,23 @@ +module Redmine + module Scm + class Base + class << self + + def all + @scms || [] + end + + # Add a new SCM adapter and repository + def add(scm_name) + @scms ||= [] + @scms << scm_name + end + + # Remove a SCM adapter from Redmine's list of supported scms + def delete(scm_name) + @scms.delete(scm_name) + end + end + end + end +end diff --git a/lib/redmine/search.rb b/lib/redmine/search.rb new file mode 100644 index 00000000..dc2e526e --- /dev/null +++ b/lib/redmine/search.rb @@ -0,0 +1,72 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +module Redmine + module Search + + mattr_accessor :available_search_types + + @@available_search_types = [] + + class << self + def map(&block) + yield self + end + + # Registers a search provider + def register(search_type, options={}) + search_type = search_type.to_s + @@available_search_types << search_type unless @@available_search_types.include?(search_type) + end + end + + module Controller + def self.included(base) + base.extend(ClassMethods) + end + + module ClassMethods + @@default_search_scopes = Hash.new {|hash, key| hash[key] = {:default => nil, :actions => {}}} + mattr_accessor :default_search_scopes + + # Set the default search scope for a controller or specific actions + # Examples: + # * search_scope :issues # => sets the search scope to :issues for the whole controller + # * search_scope :issues, :only => :index + # * search_scope :issues, :only => [:index, :show] + def default_search_scope(id, options = {}) + if actions = options[:only] + actions = [] << actions unless actions.is_a?(Array) + actions.each {|a| default_search_scopes[controller_name.to_sym][:actions][a.to_sym] = id.to_s} + else + default_search_scopes[controller_name.to_sym][:default] = id.to_s + end + end + end + + def default_search_scopes + self.class.default_search_scopes + end + + # Returns the default search scope according to the current action + def default_search_scope + @default_search_scope ||= default_search_scopes[controller_name.to_sym][:actions][action_name.to_sym] || + default_search_scopes[controller_name.to_sym][:default] + end + end + end +end diff --git a/lib/redmine/subclass_factory.rb b/lib/redmine/subclass_factory.rb new file mode 100644 index 00000000..378bd39b --- /dev/null +++ b/lib/redmine/subclass_factory.rb @@ -0,0 +1,47 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +module Redmine + module SubclassFactory + def self.included(base) + base.extend ClassMethods + end + + module ClassMethods + def get_subclass(class_name) + klass = nil + begin + klass = class_name.to_s.classify.constantize + rescue + # invalid class name + end + unless subclasses.include? klass + klass = nil + end + klass + end + + # Returns an instance of the given subclass name + def new_subclass_instance(class_name, *args) + klass = get_subclass(class_name) + if klass + klass.new(*args) + end + end + end + end +end diff --git a/lib/redmine/syntax_highlighting.rb b/lib/redmine/syntax_highlighting.rb new file mode 100644 index 00000000..e8d9067d --- /dev/null +++ b/lib/redmine/syntax_highlighting.rb @@ -0,0 +1,56 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +module Redmine + module SyntaxHighlighting + + class << self + attr_reader :highlighter + delegate :highlight_by_filename, :highlight_by_language, :to => :highlighter + + def highlighter=(name) + if name.is_a?(Module) + @highlighter = name + else + @highlighter = const_get(name) + end + end + end + + module CodeRay + require 'coderay' + require 'coderay/helpers/file_type' + + class << self + # Highlights +text+ as the content of +filename+ + # Should not return line numbers nor outer pre tag + def highlight_by_filename(text, filename) + language = ::CodeRay::FileType[filename] + language ? ::CodeRay.scan(text, language).html(:break_lines => true) : ERB::Util.h(text) + end + + # Highlights +text+ using +language+ syntax + # Should not return outer pre tag + def highlight_by_language(text, language) + ::CodeRay.scan(text, language).html(:wrap => :span) + end + end + end + end + + SyntaxHighlighting.highlighter = 'CodeRay' +end diff --git a/lib/redmine/themes.rb b/lib/redmine/themes.rb new file mode 100644 index 00000000..eb2ba915 --- /dev/null +++ b/lib/redmine/themes.rb @@ -0,0 +1,127 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +module Redmine + module Themes + + # Return an array of installed themes + def self.themes + @@installed_themes ||= scan_themes + end + + # Rescan themes directory + def self.rescan + @@installed_themes = scan_themes + end + + # Return theme for given id, or nil if it's not found + def self.theme(id, options={}) + return nil if id.blank? + + found = themes.find {|t| t.id == id} + if found.nil? && options[:rescan] != false + rescan + found = theme(id, :rescan => false) + end + found + end + + # Class used to represent a theme + class Theme + attr_reader :path, :name, :dir + + def initialize(path) + @path = path + @dir = File.basename(path) + @name = @dir.humanize + @stylesheets = nil + @javascripts = nil + end + + # Directory name used as the theme id + def id; dir end + + def ==(theme) + theme.is_a?(Theme) && theme.dir == dir + end + + def <=>(theme) + name <=> theme.name + end + + def stylesheets + @stylesheets ||= assets("stylesheets", "css") + end + + def images + @images ||= assets("images") + end + + def javascripts + @javascripts ||= assets("javascripts", "js") + end + + def stylesheet_path(source) + "/themes/#{dir}/stylesheets/#{source}" + end + + def image_path(source) + "/themes/#{dir}/images/#{source}" + end + + def javascript_path(source) + "/themes/#{dir}/javascripts/#{source}" + end + + private + + def assets(dir, ext=nil) + if ext + Dir.glob("#{path}/#{dir}/*.#{ext}").collect {|f| File.basename(f).gsub(/\.#{ext}$/, '')} + else + Dir.glob("#{path}/#{dir}/*").collect {|f| File.basename(f)} + end + end + end + + private + + def self.scan_themes + dirs = Dir.glob("#{Rails.public_path}/themes/*").select do |f| + # A theme should at least override application.css + File.directory?(f) && File.exist?("#{f}/stylesheets/application.css") + end + dirs.collect {|dir| Theme.new(dir)}.sort + end + end +end + +module ApplicationHelper + def current_theme + unless instance_variable_defined?(:@current_theme) + @current_theme = Redmine::Themes.theme(Setting.ui_theme) + end + @current_theme + end + + # Returns the header tags for the current theme + def heads_for_theme + if current_theme && current_theme.javascripts.include?('theme') + javascript_include_tag current_theme.javascript_path('theme') + end + end +end diff --git a/lib/redmine/thumbnail.rb b/lib/redmine/thumbnail.rb new file mode 100644 index 00000000..96f9dfa3 --- /dev/null +++ b/lib/redmine/thumbnail.rb @@ -0,0 +1,55 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +require 'fileutils' + +module Redmine + module Thumbnail + extend Redmine::Utils::Shell + + CONVERT_BIN = (Redmine::Configuration['imagemagick_convert_command'] || 'convert').freeze + + # Generates a thumbnail for the source image to target + def self.generate(source, target, size) + return nil unless convert_available? + unless File.exists?(target) + directory = File.dirname(target) + unless File.exists?(directory) + FileUtils.mkdir_p directory + end + size_option = "#{size}x#{size}>" + cmd = "#{shell_quote CONVERT_BIN} #{shell_quote source} -thumbnail #{shell_quote size_option} #{shell_quote target}" + unless system(cmd) + logger.error("Creating thumbnail failed (#{$?}):\nCommand: #{cmd}") + return nil + end + end + target + end + + def self.convert_available? + return @convert_available if defined?(@convert_available) + @convert_available = system("#{shell_quote CONVERT_BIN} -version") rescue false + logger.warn("Imagemagick's convert binary (#{CONVERT_BIN}) not available") unless @convert_available + @convert_available + end + + def self.logger + Rails.logger + end + end +end diff --git a/lib/redmine/unified_diff.rb b/lib/redmine/unified_diff.rb new file mode 100644 index 00000000..54800322 --- /dev/null +++ b/lib/redmine/unified_diff.rb @@ -0,0 +1,294 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +module Redmine + # Class used to parse unified diffs + class UnifiedDiff < Array + attr_reader :diff_type, :diff_style + + def initialize(diff, options={}) + options.assert_valid_keys(:type, :style, :max_lines) + diff = diff.split("\n") if diff.is_a?(String) + @diff_type = options[:type] || 'inline' + @diff_style = options[:style] + lines = 0 + @truncated = false + diff_table = DiffTable.new(diff_type, diff_style) + diff.each do |line_raw| + line = Redmine::CodesetUtil.to_utf8_by_setting(line_raw) + unless diff_table.add_line(line) + self << diff_table if diff_table.length > 0 + diff_table = DiffTable.new(diff_type, diff_style) + end + lines += 1 + if options[:max_lines] && lines > options[:max_lines] + @truncated = true + break + end + end + self << diff_table unless diff_table.empty? + self + end + + def truncated?; @truncated; end + end + + # Class that represents a file diff + class DiffTable < Array + attr_reader :file_name + + # Initialize with a Diff file and the type of Diff View + # The type view must be inline or sbs (side_by_side) + def initialize(type="inline", style=nil) + @parsing = false + @added = 0 + @removed = 0 + @type = type + @style = style + @file_name = nil + @git_diff = false + end + + # Function for add a line of this Diff + # Returns false when the diff ends + def add_line(line) + unless @parsing + if line =~ /^(---|\+\+\+) (.*)$/ + self.file_name = $2 + elsif line =~ /^@@ (\+|\-)(\d+)(,\d+)? (\+|\-)(\d+)(,\d+)? @@/ + @line_num_l = $2.to_i + @line_num_r = $5.to_i + @parsing = true + end + else + if line =~ %r{^[^\+\-\s@\\]} + @parsing = false + return false + elsif line =~ /^@@ (\+|\-)(\d+)(,\d+)? (\+|\-)(\d+)(,\d+)? @@/ + @line_num_l = $2.to_i + @line_num_r = $5.to_i + else + parse_line(line, @type) + end + end + return true + end + + def each_line + prev_line_left, prev_line_right = nil, nil + each do |line| + spacing = prev_line_left && prev_line_right && (line.nb_line_left != prev_line_left+1) && (line.nb_line_right != prev_line_right+1) + yield spacing, line + prev_line_left = line.nb_line_left.to_i if line.nb_line_left.to_i > 0 + prev_line_right = line.nb_line_right.to_i if line.nb_line_right.to_i > 0 + end + end + + def inspect + puts '### DIFF TABLE ###' + puts "file : #{file_name}" + self.each do |d| + d.inspect + end + end + + private + + def file_name=(arg) + both_git_diff = false + if file_name.nil? + @git_diff = true if arg =~ %r{^(a/|/dev/null)} + else + both_git_diff = (@git_diff && arg =~ %r{^(b/|/dev/null)}) + end + if both_git_diff + if file_name && arg == "/dev/null" + # keep the original file name + @file_name = file_name.sub(%r{^a/}, '') + else + # remove leading b/ + @file_name = arg.sub(%r{^b/}, '') + end + elsif @style == "Subversion" + # removing trailing "(revision nn)" + @file_name = arg.sub(%r{\t+\(.*\)$}, '') + else + @file_name = arg + end + end + + def diff_for_added_line + if @type == 'sbs' && @removed > 0 && @added < @removed + self[-(@removed - @added)] + else + diff = Diff.new + self << diff + diff + end + end + + def parse_line(line, type="inline") + if line[0, 1] == "+" + diff = diff_for_added_line + diff.line_right = line[1..-1] + diff.nb_line_right = @line_num_r + diff.type_diff_right = 'diff_in' + @line_num_r += 1 + @added += 1 + true + elsif line[0, 1] == "-" + diff = Diff.new + diff.line_left = line[1..-1] + diff.nb_line_left = @line_num_l + diff.type_diff_left = 'diff_out' + self << diff + @line_num_l += 1 + @removed += 1 + true + else + write_offsets + if line[0, 1] =~ /\s/ + diff = Diff.new + diff.line_right = line[1..-1] + diff.nb_line_right = @line_num_r + diff.line_left = line[1..-1] + diff.nb_line_left = @line_num_l + self << diff + @line_num_l += 1 + @line_num_r += 1 + true + elsif line[0, 1] = "\\" + true + else + false + end + end + end + + def write_offsets + if @added > 0 && @added == @removed + @added.times do |i| + line = self[-(1 + i)] + removed = (@type == 'sbs') ? line : self[-(1 + @added + i)] + offsets = offsets(removed.line_left, line.line_right) + removed.offsets = line.offsets = offsets + end + end + @added = 0 + @removed = 0 + end + + def offsets(line_left, line_right) + if line_left.present? && line_right.present? && line_left != line_right + max = [line_left.size, line_right.size].min + starting = 0 + while starting < max && line_left[starting] == line_right[starting] + starting += 1 + end + if (! "".respond_to?(:force_encoding)) && starting < line_left.size + while line_left[starting].ord.between?(128, 191) && starting > 0 + starting -= 1 + end + end + ending = -1 + while ending >= -(max - starting) && line_left[ending] == line_right[ending] + ending -= 1 + end + if (! "".respond_to?(:force_encoding)) && ending > (-1 * line_left.size) + while line_left[ending].ord.between?(128, 191) && ending > -1 + ending -= 1 + end + end + unless starting == 0 && ending == -1 + [starting, ending] + end + end + end + end + + # A line of diff + class Diff + attr_accessor :nb_line_left + attr_accessor :line_left + attr_accessor :nb_line_right + attr_accessor :line_right + attr_accessor :type_diff_right + attr_accessor :type_diff_left + attr_accessor :offsets + + def initialize() + self.nb_line_left = '' + self.nb_line_right = '' + self.line_left = '' + self.line_right = '' + self.type_diff_right = '' + self.type_diff_left = '' + end + + def type_diff + type_diff_right == 'diff_in' ? type_diff_right : type_diff_left + end + + def line + type_diff_right == 'diff_in' ? line_right : line_left + end + + def html_line_left + line_to_html(line_left, offsets) + end + + def html_line_right + line_to_html(line_right, offsets) + end + + def html_line + line_to_html(line, offsets) + end + + def inspect + puts '### Start Line Diff ###' + puts self.nb_line_left + puts self.line_left + puts self.nb_line_right + puts self.line_right + end + + private + + def line_to_html(line, offsets) + html = line_to_html_raw(line, offsets) + html.force_encoding('UTF-8') if html.respond_to?(:force_encoding) + html + end + + def line_to_html_raw(line, offsets) + if offsets + s = '' + unless offsets.first == 0 + s << CGI.escapeHTML(line[0..offsets.first-1]) + end + s << '' + CGI.escapeHTML(line[offsets.first..offsets.last]) + '' + unless offsets.last == -1 + s << CGI.escapeHTML(line[offsets.last+1..-1]) + end + s + else + CGI.escapeHTML(line) + end + end + end +end diff --git a/lib/redmine/utils.rb b/lib/redmine/utils.rb new file mode 100644 index 00000000..c289404c --- /dev/null +++ b/lib/redmine/utils.rb @@ -0,0 +1,118 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +module Redmine + module Utils + class << self + # Returns the relative root url of the application + def relative_url_root + ActionController::Base.respond_to?('relative_url_root') ? + ActionController::Base.relative_url_root.to_s : + ActionController::Base.config.relative_url_root.to_s + end + + # Sets the relative root url of the application + def relative_url_root=(arg) + if ActionController::Base.respond_to?('relative_url_root=') + ActionController::Base.relative_url_root=arg + else + ActionController::Base.config.relative_url_root = arg + end + end + + # Generates a n bytes random hex string + # Example: + # random_hex(4) # => "89b8c729" + def random_hex(n) + SecureRandom.hex(n) + end + end + + module Shell + def shell_quote(str) + if Redmine::Platform.mswin? + '"' + str.gsub(/"/, '\\"') + '"' + else + "'" + str.gsub(/'/, "'\"'\"'") + "'" + end + end + end + + module DateCalculation + # Returns the number of working days between from and to + def working_days(from, to) + days = (to - from).to_i + if days > 0 + weeks = days / 7 + result = weeks * (7 - non_working_week_days.size) + days_left = days - weeks * 7 + start_cwday = from.cwday + days_left.times do |i| + unless non_working_week_days.include?(((start_cwday + i - 1) % 7) + 1) + result += 1 + end + end + result + else + 0 + end + end + + # Adds working days to the given date + def add_working_days(date, working_days) + if working_days > 0 + weeks = working_days / (7 - non_working_week_days.size) + result = weeks * 7 + days_left = working_days - weeks * (7 - non_working_week_days.size) + cwday = date.cwday + while days_left > 0 + cwday += 1 + unless non_working_week_days.include?(((cwday - 1) % 7) + 1) + days_left -= 1 + end + result += 1 + end + next_working_date(date + result) + else + date + end + end + + # Returns the date of the first day on or after the given date that is a working day + def next_working_date(date) + cwday = date.cwday + days = 0 + while non_working_week_days.include?(((cwday + days - 1) % 7) + 1) + days += 1 + end + date + days + end + + # Returns the index of non working week days (1=monday, 7=sunday) + def non_working_week_days + @non_working_week_days ||= begin + days = Setting.non_working_week_days + if days.is_a?(Array) && days.size < 7 + days.map(&:to_i) + else + [] + end + end + end + end + end +end diff --git a/lib/redmine/version.rb b/lib/redmine/version.rb new file mode 100644 index 00000000..a328db8a --- /dev/null +++ b/lib/redmine/version.rb @@ -0,0 +1,37 @@ +require 'rexml/document' + +module Redmine + module VERSION #:nodoc: + MAJOR = 2 + MINOR = 3 + TINY = 1 + + # Branch values: + # * official release: nil + # * stable branch: stable + # * trunk: devel + BRANCH = 'stable' + + # Retrieves the revision from the working copy + def self.revision + if File.directory?(File.join(Rails.root, '.svn')) + begin + path = Redmine::Scm::Adapters::AbstractAdapter.shell_quote(Rails.root.to_s) + if `svn info --xml #{path}` =~ /revision="(\d+)"/ + return $1.to_i + end + rescue + # Could not find the current revision + end + end + nil + end + + REVISION = self.revision + ARRAY = [MAJOR, MINOR, TINY, BRANCH, REVISION].compact + STRING = ARRAY.join('.') + + def self.to_a; ARRAY end + def self.to_s; STRING end + end +end diff --git a/lib/redmine/views/api_template_handler.rb b/lib/redmine/views/api_template_handler.rb new file mode 100644 index 00000000..04a7d564 --- /dev/null +++ b/lib/redmine/views/api_template_handler.rb @@ -0,0 +1,26 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +module Redmine + module Views + class ApiTemplateHandler + def self.call(template) + "Redmine::Views::Builders.for(params[:format], request, response) do |api|; #{template.source}; self.output_buffer = api.output; end" + end + end + end +end diff --git a/lib/redmine/views/builders.rb b/lib/redmine/views/builders.rb new file mode 100644 index 00000000..a1284fef --- /dev/null +++ b/lib/redmine/views/builders.rb @@ -0,0 +1,38 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +require 'redmine/views/builders/json' +require 'redmine/views/builders/xml' + +module Redmine + module Views + module Builders + def self.for(format, request, response, &block) + builder = case format + when 'xml', :xml; Builders::Xml.new(request, response) + when 'json', :json; Builders::Json.new(request, response) + else; raise "No builder for format #{format}" + end + if block + block.call(builder) + else + builder + end + end + end + end +end diff --git a/lib/redmine/views/builders/json.rb b/lib/redmine/views/builders/json.rb new file mode 100644 index 00000000..feae6de5 --- /dev/null +++ b/lib/redmine/views/builders/json.rb @@ -0,0 +1,45 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +require 'redmine/views/builders/structure' + +module Redmine + module Views + module Builders + class Json < Structure + attr_accessor :jsonp + + def initialize(request, response) + super + callback = request.params[:callback] || request.params[:jsonp] + if callback && Setting.jsonp_enabled? + self.jsonp = callback.to_s.gsub(/[^a-zA-Z0-9_]/, '') + end + end + + def output + json = @struct.first.to_json + if jsonp.present? + json = "#{jsonp}(#{json})" + response.content_type = 'application/javascript' + end + json + end + end + end + end +end diff --git a/lib/redmine/views/builders/structure.rb b/lib/redmine/views/builders/structure.rb new file mode 100644 index 00000000..a2615497 --- /dev/null +++ b/lib/redmine/views/builders/structure.rb @@ -0,0 +1,83 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +require 'blankslate' + +module Redmine + module Views + module Builders + class Structure < BlankSlate + attr_accessor :request, :response + + def initialize(request, response) + @struct = [{}] + self.request = request + self.response = response + end + + def array(tag, options={}, &block) + @struct << [] + block.call(self) + ret = @struct.pop + @struct.last[tag] = ret + @struct.last.merge!(options) if options + end + + def method_missing(sym, *args, &block) + if args.any? + if args.first.is_a?(Hash) + if @struct.last.is_a?(Array) + @struct.last << args.first unless block + else + @struct.last[sym] = args.first + end + else + if @struct.last.is_a?(Array) + if args.size == 1 && !block_given? + @struct.last << args.first + else + @struct.last << (args.last || {}).merge(:value => args.first) + end + else + @struct.last[sym] = args.first + end + end + end + + if block + @struct << (args.first.is_a?(Hash) ? args.first : {}) + block.call(self) + ret = @struct.pop + if @struct.last.is_a?(Array) + @struct.last << ret + else + if @struct.last.has_key?(sym) && @struct.last[sym].is_a?(Hash) + @struct.last[sym].merge! ret + else + @struct.last[sym] = ret + end + end + end + end + + def output + raise "Need to implement #{self.class.name}#output" + end + end + end + end +end diff --git a/lib/redmine/views/builders/xml.rb b/lib/redmine/views/builders/xml.rb new file mode 100644 index 00000000..8bee3fd1 --- /dev/null +++ b/lib/redmine/views/builders/xml.rb @@ -0,0 +1,47 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +require 'builder' + +module Redmine + module Views + module Builders + class Xml < ::Builder::XmlMarkup + def initialize(request, response) + super() + instruct! + end + + def output + target! + end + + def method_missing(sym, *args, &block) + if args.size == 1 && args.first.is_a?(::Time) + __send__ sym, args.first.xmlschema, &block + else + super + end + end + + def array(name, options={}, &block) + __send__ name, (options || {}).merge(:type => 'array'), &block + end + end + end + end +end diff --git a/lib/redmine/views/labelled_form_builder.rb b/lib/redmine/views/labelled_form_builder.rb new file mode 100644 index 00000000..2bba17fa --- /dev/null +++ b/lib/redmine/views/labelled_form_builder.rb @@ -0,0 +1,51 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +require 'action_view/helpers/form_helper' + +class Redmine::Views::LabelledFormBuilder < ActionView::Helpers::FormBuilder + include Redmine::I18n + + (field_helpers.map(&:to_s) - %w(radio_button hidden_field fields_for) + + %w(date_select)).each do |selector| + src = <<-END_SRC + def #{selector}(field, options = {}) + label_for_field(field, options) + super(field, options.except(:label)).html_safe + end + END_SRC + class_eval src, __FILE__, __LINE__ + end + + def select(field, choices, options = {}, html_options = {}) + label_for_field(field, options) + super(field, choices, options, html_options.except(:label)).html_safe + end + + def time_zone_select(field, priority_zones = nil, options = {}, html_options = {}) + label_for_field(field, options) + super(field, priority_zones, options, html_options.except(:label)).html_safe + end + + # Returns a label tag for the given field + def label_for_field(field, options = {}) + return ''.html_safe if options.delete(:no_label) + text = options[:label].is_a?(Symbol) ? l(options[:label]) : options[:label] + text ||= l(("field_" + field.to_s.gsub(/\_id$/, "")).to_sym) + text += @template.content_tag("span", " *", :class => "required") if options.delete(:required) + @template.content_tag("label", text.html_safe, + :class => (@object && @object.errors[field].present? ? "error" : nil), + :for => (@object_name.to_s + "_" + field.to_s)) + end +end diff --git a/lib/redmine/views/my_page/block.rb b/lib/redmine/views/my_page/block.rb new file mode 100644 index 00000000..dd664aca --- /dev/null +++ b/lib/redmine/views/my_page/block.rb @@ -0,0 +1,32 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +module Redmine + module Views + module MyPage + module Block + def self.additional_blocks + @@additional_blocks ||= Dir.glob("#{Redmine::Plugin.directory}/*/app/views/my/blocks/_*.{rhtml,erb}").inject({}) do |h,file| + name = File.basename(file).split('.').first.gsub(/^_/, '') + h[name] = name.to_sym + h + end + end + end + end + end +end diff --git a/lib/redmine/views/other_formats_builder.rb b/lib/redmine/views/other_formats_builder.rb new file mode 100644 index 00000000..0093ff63 --- /dev/null +++ b/lib/redmine/views/other_formats_builder.rb @@ -0,0 +1,33 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +module Redmine + module Views + class OtherFormatsBuilder + def initialize(view) + @view = view + end + + def link_to(name, options={}) + url = { :format => name.to_s.downcase }.merge(options.delete(:url) || {}).except('page') + caption = options.delete(:caption) || name + html_options = { :class => name.to_s.downcase, :rel => 'nofollow' }.merge(options) + @view.content_tag('span', @view.link_to(caption, url, html_options)) + end + end + end +end diff --git a/lib/redmine/wiki_formatting.rb b/lib/redmine/wiki_formatting.rb new file mode 100644 index 00000000..9a62bf6b --- /dev/null +++ b/lib/redmine/wiki_formatting.rb @@ -0,0 +1,173 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +require 'digest/md5' + +module Redmine + module WikiFormatting + class StaleSectionError < Exception; end + + @@formatters = {} + + class << self + def map + yield self + end + + def register(name, formatter, helper) + raise ArgumentError, "format name '#{name}' is already taken" if @@formatters[name.to_s] + @@formatters[name.to_s] = {:formatter => formatter, :helper => helper} + end + + def formatter + formatter_for(Setting.text_formatting) + end + + def formatter_for(name) + entry = @@formatters[name.to_s] + (entry && entry[:formatter]) || Redmine::WikiFormatting::NullFormatter::Formatter + end + + def helper_for(name) + entry = @@formatters[name.to_s] + (entry && entry[:helper]) || Redmine::WikiFormatting::NullFormatter::Helper + end + + def format_names + @@formatters.keys.map + end + + def to_html(format, text, options = {}) + text = if Setting.cache_formatted_text? && text.size > 2.kilobyte && cache_store && cache_key = cache_key_for(format, text, options[:object], options[:attribute]) + # Text retrieved from the cache store may be frozen + # We need to dup it so we can do in-place substitutions with gsub! + cache_store.fetch cache_key do + formatter_for(format).new(text).to_html + end.dup + else + formatter_for(format).new(text).to_html + end + text + end + + # Returns true if the text formatter supports single section edit + def supports_section_edit? + (formatter.instance_methods & ['update_section', :update_section]).any? + end + + # Returns a cache key for the given text +format+, +text+, +object+ and +attribute+ or nil if no caching should be done + def cache_key_for(format, text, object, attribute) + if object && attribute && !object.new_record? && format.present? + "formatted_text/#{format}/#{object.class.model_name.cache_key}/#{object.id}-#{attribute}-#{Digest::MD5.hexdigest text}" + end + end + + # Returns the cache store used to cache HTML output + def cache_store + ActionController::Base.cache_store + end + end + + module LinksHelper + AUTO_LINK_RE = %r{ + ( # leading text + <\w+.*?>| # leading HTML tag, or + [\s\(\[,;]| # leading punctuation, or + ^ # beginning of line + ) + ( + (?:https?://)| # protocol spec, or + (?:s?ftps?://)| + (?:www\.) # www.* + ) + ( + ([^<]\S*?) # url + (\/)? # slash + ) + ((?:>)?|[^[:alnum:]_\=\/;\(\)]*?) # post + (?=<|\s|$) + }x unless const_defined?(:AUTO_LINK_RE) + + # Destructively remplaces urls into clickable links + def auto_link!(text) + text.gsub!(AUTO_LINK_RE) do + all, leading, proto, url, post = $&, $1, $2, $3, $6 + if leading =~ /=]?/ + # don't replace URL's that are already linked + # and URL's prefixed with ! !> !< != (textile images) + all + else + # Idea below : an URL with unbalanced parethesis and + # ending by ')' is put into external parenthesis + if ( url[-1]==?) and ((url.count("(") - url.count(")")) < 0 ) ) + url=url[0..-2] # discard closing parenth from url + post = ")"+post # add closing parenth to post + end + content = proto + url + href = "#{proto=="www."?"http://www.":proto}#{url}" + %(#{leading}#{ERB::Util.html_escape content}#{post}).html_safe + end + end + end + + # Destructively remplaces email addresses into clickable links + def auto_mailto!(text) + text.gsub!(/([\w\.!#\$%\-+.]+@[A-Za-z0-9\-]+(\.[A-Za-z0-9\-]+)+)/) do + mail = $1 + if text.match(/]*>(.*)(#{Regexp.escape(mail)})(.*)<\/a>/) + mail + else + %().html_safe + end + end + end + end + + # Default formatter module + module NullFormatter + class Formatter + include ActionView::Helpers::TagHelper + include ActionView::Helpers::TextHelper + include ActionView::Helpers::UrlHelper + include Redmine::WikiFormatting::LinksHelper + + def initialize(text) + @text = text + end + + def to_html(*args) + t = CGI::escapeHTML(@text) + auto_link!(t) + auto_mailto!(t) + simple_format(t, {}, :sanitize => false) + end + end + + module Helper + def wikitoolbar_for(field_id) + end + + def heads_for_wiki_formatter + end + + def initial_page_content(page) + page.pretty_title.to_s + end + end + end + end +end diff --git a/lib/redmine/wiki_formatting/macros.rb b/lib/redmine/wiki_formatting/macros.rb new file mode 100644 index 00000000..3160cd4c --- /dev/null +++ b/lib/redmine/wiki_formatting/macros.rb @@ -0,0 +1,247 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +module Redmine + module WikiFormatting + module Macros + module Definitions + # Returns true if +name+ is the name of an existing macro + def macro_exists?(name) + Redmine::WikiFormatting::Macros.available_macros.key?(name.to_sym) + end + + def exec_macro(name, obj, args, text) + macro_options = Redmine::WikiFormatting::Macros.available_macros[name.to_sym] + return unless macro_options + + method_name = "macro_#{name}" + unless macro_options[:parse_args] == false + args = args.split(',').map(&:strip) + end + + begin + if self.class.instance_method(method_name).arity == 3 + send(method_name, obj, args, text) + elsif text + raise "This macro does not accept a block of text" + else + send(method_name, obj, args) + end + rescue => e + "
      Error executing the #{h name} macro (#{h e.to_s})
      ".html_safe + end + end + + def extract_macro_options(args, *keys) + options = {} + while args.last.to_s.strip =~ %r{^(.+?)\=(.+)$} && keys.include?($1.downcase.to_sym) + options[$1.downcase.to_sym] = $2 + args.pop + end + return [args, options] + end + end + + @@available_macros = {} + mattr_accessor :available_macros + + class << self + # Plugins can use this method to define new macros: + # + # Redmine::WikiFormatting::Macros.register do + # desc "This is my macro" + # macro :my_macro do |obj, args| + # "My macro output" + # end + # + # desc "This is my macro that accepts a block of text" + # macro :my_macro do |obj, args, text| + # "My macro output" + # end + # end + def register(&block) + class_eval(&block) if block_given? + end + + # Defines a new macro with the given name, options and block. + # + # Options: + # * :desc - A description of the macro + # * :parse_args => false - Disables arguments parsing (the whole arguments + # string is passed to the macro) + # + # Macro blocks accept 2 or 3 arguments: + # * obj: the object that is rendered (eg. an Issue, a WikiContent...) + # * args: macro arguments + # * text: the block of text given to the macro (should be present only if the + # macro accepts a block of text). text is a String or nil if the macro is + # invoked without a block of text. + # + # Examples: + # By default, when the macro is invoked, the coma separated list of arguments + # is split and passed to the macro block as an array. If no argument is given + # the macro will be invoked with an empty array: + # + # macro :my_macro do |obj, args| + # # args is an array + # # and this macro do not accept a block of text + # end + # + # You can disable arguments spliting with the :parse_args => false option. In + # this case, the full string of arguments is passed to the macro: + # + # macro :my_macro, :parse_args => false do |obj, args| + # # args is a string + # end + # + # Macro can optionally accept a block of text: + # + # macro :my_macro do |obj, args, text| + # # this macro accepts a block of text + # end + # + # Macros are invoked in formatted text using double curly brackets. Arguments + # must be enclosed in parenthesis if any. A new line after the macro name or the + # arguments starts the block of text that will be passe to the macro (invoking + # a macro that do not accept a block of text with some text will fail). + # Examples: + # + # No arguments: + # {{my_macro}} + # + # With arguments: + # {{my_macro(arg1, arg2)}} + # + # With a block of text: + # {{my_macro + # multiple lines + # of text + # }} + # + # With arguments and a block of text + # {{my_macro(arg1, arg2) + # multiple lines + # of text + # }} + # + # If a block of text is given, the closing tag }} must be at the start of a new line. + def macro(name, options={}, &block) + options.assert_valid_keys(:desc, :parse_args) + unless name.to_s.match(/\A\w+\z/) + raise "Invalid macro name: #{name} (only 0-9, A-Z, a-z and _ characters are accepted)" + end + unless block_given? + raise "Can not create a macro without a block!" + end + name = name.to_s.downcase.to_sym + available_macros[name] = {:desc => @@desc || ''}.merge(options) + @@desc = nil + Definitions.send :define_method, "macro_#{name}", &block + end + + # Sets description for the next macro to be defined + def desc(txt) + @@desc = txt + end + end + + # Builtin macros + desc "Sample macro." + macro :hello_world do |obj, args, text| + h("Hello world! Object: #{obj.class.name}, " + + (args.empty? ? "Called with no argument" : "Arguments: #{args.join(', ')}") + + " and " + (text.present? ? "a #{text.size} bytes long block of text." : "no block of text.") + ) + end + + desc "Displays a list of all available macros, including description if available." + macro :macro_list do |obj, args| + out = ''.html_safe + @@available_macros.each do |macro, options| + out << content_tag('dt', content_tag('code', macro.to_s)) + out << content_tag('dd', textilizable(options[:desc])) + end + content_tag('dl', out) + end + + desc "Displays a list of child pages. With no argument, it displays the child pages of the current wiki page. Examples:\n\n" + + " !{{child_pages}} -- can be used from a wiki page only\n" + + " !{{child_pages(depth=2)}} -- display 2 levels nesting only\n" + " !{{child_pages(Foo)}} -- lists all children of page Foo\n" + + " !{{child_pages(Foo, parent=1)}} -- same as above with a link to page Foo" + macro :child_pages do |obj, args| + args, options = extract_macro_options(args, :parent, :depth) + options[:depth] = options[:depth].to_i if options[:depth].present? + + page = nil + if args.size > 0 + page = Wiki.find_page(args.first.to_s, :project => @project) + elsif obj.is_a?(WikiContent) || obj.is_a?(WikiContent::Version) + page = obj.page + else + raise 'With no argument, this macro can be called from wiki pages only.' + end + raise 'Page not found' if page.nil? || !User.current.allowed_to?(:view_wiki_pages, page.wiki.project) + pages = page.self_and_descendants(options[:depth]).group_by(&:parent_id) + render_page_hierarchy(pages, options[:parent] ? page.parent_id : page.id) + end + + desc "Include a wiki page. Example:\n\n !{{include(Foo)}}\n\nor to include a page of a specific project wiki:\n\n !{{include(projectname:Foo)}}" + macro :include do |obj, args| + page = Wiki.find_page(args.first.to_s, :project => @project) + raise 'Page not found' if page.nil? || !User.current.allowed_to?(:view_wiki_pages, page.wiki.project) + @included_wiki_pages ||= [] + raise 'Circular inclusion detected' if @included_wiki_pages.include?(page.title) + @included_wiki_pages << page.title + out = textilizable(page.content, :text, :attachments => page.attachments, :headings => false) + @included_wiki_pages.pop + out + end + + desc "Inserts of collapsed block of text. Example:\n\n {{collapse(View details...)\nThis is a block of text that is collapsed by default.\nIt can be expanded by clicking a link.\n}}" + macro :collapse do |obj, args, text| + html_id = "collapse-#{Redmine::Utils.random_hex(4)}" + show_label = args[0] || l(:button_show) + hide_label = args[1] || args[0] || l(:button_hide) + js = "$('##{html_id}-show, ##{html_id}-hide').toggle(); $('##{html_id}').fadeToggle(150);" + out = ''.html_safe + out << link_to_function(show_label, js, :id => "#{html_id}-show", :class => 'collapsible collapsed') + out << link_to_function(hide_label, js, :id => "#{html_id}-hide", :class => 'collapsible', :style => 'display:none;') + out << content_tag('div', textilizable(text, :object => obj), :id => html_id, :class => 'collapsed-text', :style => 'display:none;') + out + end + + desc "Displays a clickable thumbnail of an attached image. Examples:\n\n
      {{thumbnail(image.png)}}\n{{thumbnail(image.png, size=300, title=Thumbnail)}}
      " + macro :thumbnail do |obj, args| + args, options = extract_macro_options(args, :size, :title) + filename = args.first + raise 'Filename required' unless filename.present? + size = options[:size] + raise 'Invalid size parameter' unless size.nil? || size.match(/^\d+$/) + size = size.to_i + size = nil unless size > 0 + if obj && obj.respond_to?(:attachments) && attachment = Attachment.latest_attach(obj.attachments, filename) + title = options[:title] || attachment.title + img = image_tag(url_for(:controller => 'attachments', :action => 'thumbnail', :id => attachment, :size => size), :alt => attachment.filename) + link_to(img, url_for(:controller => 'attachments', :action => 'show', :id => attachment), :class => 'thumbnail', :title => title) + else + raise "Attachment #{filename} not found" + end + end + end + end +end diff --git a/lib/redmine/wiki_formatting/textile/formatter.rb b/lib/redmine/wiki_formatting/textile/formatter.rb new file mode 100644 index 00000000..be4bcd67 --- /dev/null +++ b/lib/redmine/wiki_formatting/textile/formatter.rb @@ -0,0 +1,134 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +require 'redcloth3' +require 'digest/md5' + +module Redmine + module WikiFormatting + module Textile + class Formatter < RedCloth3 + include ActionView::Helpers::TagHelper + include Redmine::WikiFormatting::LinksHelper + + alias :inline_auto_link :auto_link! + alias :inline_auto_mailto :auto_mailto! + + # auto_link rule after textile rules so that it doesn't break !image_url! tags + RULES = [:textile, :block_markdown_rule, :inline_auto_link, :inline_auto_mailto] + + def initialize(*args) + super + self.hard_breaks=true + self.no_span_caps=true + self.filter_styles=false + end + + def to_html(*rules) + @toc = [] + super(*RULES).to_s + end + + def get_section(index) + section = extract_sections(index)[1] + hash = Digest::MD5.hexdigest(section) + return section, hash + end + + def update_section(index, update, hash=nil) + t = extract_sections(index) + if hash.present? && hash != Digest::MD5.hexdigest(t[1]) + raise Redmine::WikiFormatting::StaleSectionError + end + t[1] = update unless t[1].blank? + t.reject(&:blank?).join "\n\n" + end + + def extract_sections(index) + @pre_list = [] + text = self.dup + rip_offtags text, false, false + before = '' + s = '' + after = '' + i = 0 + l = 1 + started = false + ended = false + text.scan(/(((?:.*?)(\A|\r?\n\s*\r?\n))(h(\d+)(#{A}#{C})\.(?::(\S+))?[ \t](.*?)$)|.*)/m).each do |all, content, lf, heading, level| + if heading.nil? + if ended + after << all + elsif started + s << all + else + before << all + end + break + end + i += 1 + if ended + after << all + elsif i == index + l = level.to_i + before << content + s << heading + started = true + elsif i > index + s << content + if level.to_i > l + s << heading + else + after << heading + ended = true + end + else + before << all + end + end + sections = [before.strip, s.strip, after.strip] + sections.each {|section| smooth_offtags_without_code_highlighting section} + sections + end + + private + + # Patch for RedCloth. Fixed in RedCloth r128 but _why hasn't released it yet. + # http://code.whytheluckystiff.net/redcloth/changeset/128 + def hard_break( text ) + text.gsub!( /(.)\n(?!\n|\Z| *([#*=]+(\s|$)|[{|]))/, "\\1
      " ) if hard_breaks + end + + alias :smooth_offtags_without_code_highlighting :smooth_offtags + # Patch to add code highlighting support to RedCloth + def smooth_offtags( text ) + unless @pre_list.empty? + ## replace
       content
      +            text.gsub!(//) do
      +              content = @pre_list[$1.to_i]
      +              if content.match(/\s?(.+)/m)
      +                content = "" +
      +                  Redmine::SyntaxHighlighting.highlight_by_language($2, $1)
      +              end
      +              content
      +            end
      +          end
      +        end
      +      end
      +    end
      +  end
      +end
      diff --git a/lib/redmine/wiki_formatting/textile/helper.rb b/lib/redmine/wiki_formatting/textile/helper.rb
      new file mode 100644
      index 00000000..28accb59
      --- /dev/null
      +++ b/lib/redmine/wiki_formatting/textile/helper.rb
      @@ -0,0 +1,46 @@
      +# Redmine - project management software
      +# Copyright (C) 2006-2013  Jean-Philippe Lang
      +#
      +# This program is free software; you can redistribute it and/or
      +# modify it under the terms of the GNU General Public License
      +# as published by the Free Software Foundation; either version 2
      +# of the License, or (at your option) any later version.
      +#
      +# This program is distributed in the hope that it will be useful,
      +# but WITHOUT ANY WARRANTY; without even the implied warranty of
      +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      +# GNU General Public License for more details.
      +#
      +# You should have received a copy of the GNU General Public License
      +# along with this program; if not, write to the Free Software
      +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
      +
      +module Redmine
      +  module WikiFormatting
      +    module Textile
      +      module Helper
      +        def wikitoolbar_for(field_id)
      +          heads_for_wiki_formatter
      +          # Is there a simple way to link to a public resource?
      +          url = "#{Redmine::Utils.relative_url_root}/help/wiki_syntax.html"
      +          javascript_tag("var wikiToolbar = new jsToolBar(document.getElementById('#{field_id}')); wikiToolbar.setHelpLink('#{escape_javascript url}'); wikiToolbar.draw();")
      +        end
      +
      +        def initial_page_content(page)
      +          "h1. #{@page.pretty_title}"
      +        end
      +
      +        def heads_for_wiki_formatter
      +          unless @heads_for_wiki_formatter_included
      +            content_for :header_tags do
      +              javascript_include_tag('jstoolbar/jstoolbar-textile.min') +
      +              javascript_include_tag("jstoolbar/lang/jstoolbar-#{current_language.to_s.downcase}") +
      +              stylesheet_link_tag('jstoolbar')
      +            end
      +            @heads_for_wiki_formatter_included = true
      +          end
      +        end
      +      end
      +    end
      +  end
      +end
      diff --git a/lib/tasks/ci.rake b/lib/tasks/ci.rake
      new file mode 100644
      index 00000000..11ff67ee
      --- /dev/null
      +++ b/lib/tasks/ci.rake
      @@ -0,0 +1,63 @@
      +desc "Run the Continous Integration tests for Redmine"
      +task :ci do
      +  # RAILS_ENV and ENV[] can diverge so force them both to test
      +  ENV['RAILS_ENV'] = 'test'
      +  RAILS_ENV = 'test'
      +  Rake::Task["ci:setup"].invoke
      +  Rake::Task["ci:build"].invoke
      +  Rake::Task["ci:teardown"].invoke
      +end
      +
      +namespace :ci do
      +  desc "Setup Redmine for a new build"
      +  task :setup do
      +    Rake::Task["tmp:clear"].invoke
      +    Rake::Task["log:clear"].invoke
      +    Rake::Task["db:create:all"].invoke
      +    Rake::Task["db:migrate"].invoke
      +    Rake::Task["db:schema:dump"].invoke
      +    Rake::Task["test:scm:setup:all"].invoke
      +    Rake::Task["test:scm:update"].invoke
      +  end
      +
      +  desc "Build Redmine"
      +  task :build do
      +    Rake::Task["test"].invoke
      +    #Rake::Task["test:ui"].invoke unless RUBY_VERSION < '1.9'
      +  end
      +
      +  desc "Finish the build"
      +  task :teardown do
      +  end
      +end
      +
      +desc "Creates database.yml for the CI server"
      +file 'config/database.yml' do
      +  require 'yaml'
      +  database = ENV['DATABASE_ADAPTER']
      +  ruby = ENV['RUBY_VER'].gsub('.', '').gsub('-', '')
      +  branch = ENV['BRANCH'].gsub('.', '').gsub('-', '')
      +  dev_db_name = "ci_#{branch}_#{ruby}_dev"
      +  test_db_name = "ci_#{branch}_#{ruby}_test"
      +
      +  case database
      +  when 'mysql'
      +    dev_conf =  {'adapter' => (RUBY_VERSION >= '1.9' ? 'mysql2' : 'mysql'), 'database' => dev_db_name, 'host' => 'localhost', 'username' => 'jenkins', 'password' => 'jenkins', 'encoding' => 'utf8'}
      +    test_conf = dev_conf.merge('database' => test_db_name)
      +  when 'postgresql'
      +    dev_conf =  {'adapter' => 'postgresql', 'database' => dev_db_name, 'host' => 'localhost', 'username' => 'jenkins', 'password' => 'jenkins'}
      +    test_conf = dev_conf.merge('database' => test_db_name)
      +  when 'sqlite3'
      +    dev_conf =  {'adapter' => 'sqlite3', 'database' => "db/#{dev_db_name}.sqlite3"}
      +    test_conf = dev_conf.merge('database' => "db/#{test_db_name}.sqlite3")
      +  when 'sqlserver'
      +    dev_conf =  {'adapter' => 'sqlserver', 'database' => dev_db_name, 'host' => 'mssqlserver', 'port' => 1433, 'username' => 'jenkins', 'password' => 'jenkins'}
      +    test_conf = dev_conf.merge('database' => test_db_name)
      +  else
      +    abort "Unknown database"
      +  end
      +
      +  File.open('config/database.yml', 'w') do |f|
      +    f.write YAML.dump({'development' => dev_conf, 'test' => test_conf})
      +  end
      +end
      diff --git a/lib/tasks/ciphering.rake b/lib/tasks/ciphering.rake
      new file mode 100644
      index 00000000..520aae6f
      --- /dev/null
      +++ b/lib/tasks/ciphering.rake
      @@ -0,0 +1,35 @@
      +# Redmine - project management software
      +# Copyright (C) 2006-2013  Jean-Philippe Lang
      +#
      +# This program is free software; you can redistribute it and/or
      +# modify it under the terms of the GNU General Public License
      +# as published by the Free Software Foundation; either version 2
      +# of the License, or (at your option) any later version.
      +#
      +# This program is distributed in the hope that it will be useful,
      +# but WITHOUT ANY WARRANTY; without even the implied warranty of
      +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      +# GNU General Public License for more details.
      +#
      +# You should have received a copy of the GNU General Public License
      +# along with this program; if not, write to the Free Software
      +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
      +
      +
      +namespace :db do
      +  desc 'Encrypts SCM and LDAP passwords in the database.'
      +  task :encrypt => :environment do
      +    unless (Repository.encrypt_all(:password) &&
      +      AuthSource.encrypt_all(:account_password))
      +      raise "Some objects could not be saved after encryption, update was rollback'ed."
      +    end
      +  end
      +
      +  desc 'Decrypts SCM and LDAP passwords in the database.'
      +  task :decrypt => :environment do
      +    unless (Repository.decrypt_all(:password) &&
      +      AuthSource.decrypt_all(:account_password))
      +      raise "Some objects could not be saved after decryption, update was rollback'ed."
      +    end
      +  end
      +end
      diff --git a/lib/tasks/deprecated.rake b/lib/tasks/deprecated.rake
      new file mode 100644
      index 00000000..2e6cb3b7
      --- /dev/null
      +++ b/lib/tasks/deprecated.rake
      @@ -0,0 +1,12 @@
      +def deprecated_task(name, new_name)
      +  task name=>new_name do
      +    $stderr.puts "\nNote: The rake task #{name} has been deprecated, please use the replacement version #{new_name}"
      +  end
      +end
      +
      +deprecated_task :load_default_data, "redmine:load_default_data"
      +deprecated_task :migrate_from_mantis, "redmine:migrate_from_mantis"
      +deprecated_task :migrate_from_trac, "redmine:migrate_from_trac"
      +deprecated_task "db:migrate_plugins", "redmine:plugins:migrate"
      +deprecated_task "db:migrate:plugin", "redmine:plugins:migrate"
      +deprecated_task :generate_session_store, :generate_secret_token
      diff --git a/lib/tasks/email.rake b/lib/tasks/email.rake
      new file mode 100644
      index 00000000..934070e5
      --- /dev/null
      +++ b/lib/tasks/email.rake
      @@ -0,0 +1,198 @@
      +# Redmine - project management software
      +# Copyright (C) 2006-2013  Jean-Philippe Lang
      +#
      +# This program is free software; you can redistribute it and/or
      +# modify it under the terms of the GNU General Public License
      +# as published by the Free Software Foundation; either version 2
      +# of the License, or (at your option) any later version.
      +#
      +# This program is distributed in the hope that it will be useful,
      +# but WITHOUT ANY WARRANTY; without even the implied warranty of
      +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      +# GNU General Public License for more details.
      +#
      +# You should have received a copy of the GNU General Public License
      +# along with this program; if not, write to the Free Software
      +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
      +
      +namespace :redmine do
      +  namespace :email do
      +
      +    desc <<-END_DESC
      +Read an email from standard input.
      +
      +General options:
      +  unknown_user=ACTION      how to handle emails from an unknown user
      +                           ACTION can be one of the following values:
      +                           ignore: email is ignored (default)
      +                           accept: accept as anonymous user
      +                           create: create a user account
      +  no_permission_check=1    disable permission checking when receiving
      +                           the email
      +  no_account_notice=1      disable new user account notification
      +  default_group=foo,bar    adds created user to foo and bar groups
      +
      +Issue attributes control options:
      +  project=PROJECT          identifier of the target project
      +  status=STATUS            name of the target status
      +  tracker=TRACKER          name of the target tracker
      +  category=CATEGORY        name of the target category
      +  priority=PRIORITY        name of the target priority
      +  allow_override=ATTRS     allow email content to override attributes
      +                           specified by previous options
      +                           ATTRS is a comma separated list of attributes
      +
      +Examples:
      +  # No project specified. Emails MUST contain the 'Project' keyword:
      +  rake redmine:email:read RAILS_ENV="production" < raw_email
      +
      +  # Fixed project and default tracker specified, but emails can override
      +  # both tracker and priority attributes:
      +  rake redmine:email:read RAILS_ENV="production" \\
      +                  project=foo \\
      +                  tracker=bug \\
      +                  allow_override=tracker,priority < raw_email
      +END_DESC
      +
      +    task :read => :environment do
      +      options = { :issue => {} }
      +      %w(project status tracker category priority).each { |a| options[:issue][a.to_sym] = ENV[a] if ENV[a] }
      +      options[:allow_override] = ENV['allow_override'] if ENV['allow_override']
      +      options[:unknown_user] = ENV['unknown_user'] if ENV['unknown_user']
      +      options[:no_permission_check] = ENV['no_permission_check'] if ENV['no_permission_check']
      +      options[:no_account_notice] = ENV['no_account_notice'] if ENV['no_account_notice']
      +      options[:default_group] = ENV['default_group'] if ENV['default_group']
      +
      +      MailHandler.receive(STDIN.read, options)
      +    end
      +
      +    desc <<-END_DESC
      +Read emails from an IMAP server.
      +
      +General options:
      +  unknown_user=ACTION      how to handle emails from an unknown user
      +                           ACTION can be one of the following values:
      +                           ignore: email is ignored (default)
      +                           accept: accept as anonymous user
      +                           create: create a user account
      +  no_permission_check=1    disable permission checking when receiving
      +                           the email
      +  no_account_notice=1      disable new user account notification
      +  default_group=foo,bar    adds created user to foo and bar groups
      +
      +Available IMAP options:
      +  host=HOST                IMAP server host (default: 127.0.0.1)
      +  port=PORT                IMAP server port (default: 143)
      +  ssl=SSL                  Use SSL? (default: false)
      +  username=USERNAME        IMAP account
      +  password=PASSWORD        IMAP password
      +  folder=FOLDER            IMAP folder to read (default: INBOX)
      +
      +Issue attributes control options:
      +  project=PROJECT          identifier of the target project
      +  status=STATUS            name of the target status
      +  tracker=TRACKER          name of the target tracker
      +  category=CATEGORY        name of the target category
      +  priority=PRIORITY        name of the target priority
      +  allow_override=ATTRS     allow email content to override attributes
      +                           specified by previous options
      +                           ATTRS is a comma separated list of attributes
      +
      +Processed emails control options:
      +  move_on_success=MAILBOX  move emails that were successfully received
      +                           to MAILBOX instead of deleting them
      +  move_on_failure=MAILBOX  move emails that were ignored to MAILBOX
      +
      +Examples:
      +  # No project specified. Emails MUST contain the 'Project' keyword:
      +
      +  rake redmine:email:receive_imap RAILS_ENV="production" \\
      +    host=imap.foo.bar username=redmine@example.net password=xxx
      +
      +
      +  # Fixed project and default tracker specified, but emails can override
      +  # both tracker and priority attributes:
      +
      +  rake redmine:email:receive_imap RAILS_ENV="production" \\
      +    host=imap.foo.bar username=redmine@example.net password=xxx ssl=1 \\
      +    project=foo \\
      +    tracker=bug \\
      +    allow_override=tracker,priority
      +END_DESC
      +
      +    task :receive_imap => :environment do
      +      imap_options = {:host => ENV['host'],
      +                      :port => ENV['port'],
      +                      :ssl => ENV['ssl'],
      +                      :username => ENV['username'],
      +                      :password => ENV['password'],
      +                      :folder => ENV['folder'],
      +                      :move_on_success => ENV['move_on_success'],
      +                      :move_on_failure => ENV['move_on_failure']}
      +
      +      options = { :issue => {} }
      +      %w(project status tracker category priority).each { |a| options[:issue][a.to_sym] = ENV[a] if ENV[a] }
      +      options[:allow_override] = ENV['allow_override'] if ENV['allow_override']
      +      options[:unknown_user] = ENV['unknown_user'] if ENV['unknown_user']
      +      options[:no_permission_check] = ENV['no_permission_check'] if ENV['no_permission_check']
      +      options[:no_account_notice] = ENV['no_account_notice'] if ENV['no_account_notice']
      +      options[:default_group] = ENV['default_group'] if ENV['default_group']
      +
      +      Redmine::IMAP.check(imap_options, options)
      +    end
      +
      +    desc <<-END_DESC
      +Read emails from an POP3 server.
      +
      +Available POP3 options:
      +  host=HOST                POP3 server host (default: 127.0.0.1)
      +  port=PORT                POP3 server port (default: 110)
      +  username=USERNAME        POP3 account
      +  password=PASSWORD        POP3 password
      +  apop=1                   use APOP authentication (default: false)
      +  delete_unprocessed=1     delete messages that could not be processed
      +                           successfully from the server (default
      +                           behaviour is to leave them on the server)
      +
      +See redmine:email:receive_imap for more options and examples.
      +END_DESC
      +
      +    task :receive_pop3 => :environment do
      +      pop_options  = {:host => ENV['host'],
      +                      :port => ENV['port'],
      +                      :apop => ENV['apop'],
      +                      :username => ENV['username'],
      +                      :password => ENV['password'],
      +                      :delete_unprocessed => ENV['delete_unprocessed']}
      +
      +      options = { :issue => {} }
      +      %w(project status tracker category priority).each { |a| options[:issue][a.to_sym] = ENV[a] if ENV[a] }
      +      options[:allow_override] = ENV['allow_override'] if ENV['allow_override']
      +      options[:unknown_user] = ENV['unknown_user'] if ENV['unknown_user']
      +      options[:no_permission_check] = ENV['no_permission_check'] if ENV['no_permission_check']
      +      options[:no_account_notice] = ENV['no_account_notice'] if ENV['no_account_notice']
      +      options[:default_group] = ENV['default_group'] if ENV['default_group']
      +
      +      Redmine::POP3.check(pop_options, options)
      +    end
      +
      +    desc "Send a test email to the user with the provided login name"
      +    task :test, [:login] => :environment do |task, args|
      +      include Redmine::I18n
      +      abort l(:notice_email_error, "Please include the user login to test with. Example: rake redmine:email:test[login]") if args[:login].blank?
      +
      +      user = User.find_by_login(args[:login])
      +      abort l(:notice_email_error, "User #{args[:login]} not found") unless user && user.logged?
      +
      +      ActionMailer::Base.raise_delivery_errors = true
      +      begin
      +        Mailer.with_synched_deliveries do
      +          Mailer.test_email(user).deliver
      +        end
      +        puts l(:notice_email_sent, user.mail)
      +      rescue Exception => e
      +        abort l(:notice_email_error, e.message)
      +      end
      +    end
      +  end
      +end
      diff --git a/lib/tasks/extract_fixtures.rake b/lib/tasks/extract_fixtures.rake
      new file mode 100644
      index 00000000..65f52931
      --- /dev/null
      +++ b/lib/tasks/extract_fixtures.rake
      @@ -0,0 +1,22 @@
      +desc 'Create YAML test fixtures from data in an existing database.
      +Defaults to development database. Set RAILS_ENV to override.'
      +
      +task :extract_fixtures => :environment do
      +  sql = "SELECT * FROM %s"
      +  skip_tables = ["schema_info"]
      +  ActiveRecord::Base.establish_connection
      +  (ActiveRecord::Base.connection.tables - skip_tables).each do |table_name|
      +    i = "000"
      +    File.open("#{Rails.root}/#{table_name}.yml", 'w' ) do |file|
      +      data = ActiveRecord::Base.connection.select_all(sql % table_name)
      +      file.write data.inject({}) { |hash, record|
      +        # cast extracted values
      +        ActiveRecord::Base.connection.columns(table_name).each { |col|
      +          record[col.name] = col.type_cast(record[col.name]) if record[col.name]
      +        }
      +        hash["#{table_name}_#{i.succ!}"] = record
      +        hash
      +      }.to_yaml
      +    end
      +  end
      +end
      diff --git a/lib/tasks/initializers.rake b/lib/tasks/initializers.rake
      new file mode 100644
      index 00000000..c1fdc7bf
      --- /dev/null
      +++ b/lib/tasks/initializers.rake
      @@ -0,0 +1,24 @@
      +desc 'Generates a secret token for the application.'
      +
      +file 'config/initializers/secret_token.rb' do
      +  path = File.join(Rails.root, 'config', 'initializers', 'secret_token.rb')
      +  secret = SecureRandom.hex(40)
      +  File.open(path, 'w') do |f|
      +    f.write <<"EOF"
      +# This file was generated by 'rake generate_secret_token', and should
      +# not be made visible to public.
      +# If you have a load-balancing Redmine cluster, you will need to use the
      +# same version of this file on each machine. And be sure to restart your
      +# server when you modify this file.
      +#
      +# Your secret key for verifying cookie session data integrity. If you
      +# change this key, all old sessions will become invalid! Make sure the
      +# secret is at least 30 characters and all random, no regular words or
      +# you'll be exposed to dictionary attacks.
      +RedmineApp::Application.config.secret_token = '#{secret}'
      +EOF
      +  end
      +end
      +
      +desc 'Generates a secret token for the application.'
      +task :generate_secret_token => ['config/initializers/secret_token.rb']
      diff --git a/lib/tasks/jdbc.rake b/lib/tasks/jdbc.rake
      new file mode 100644
      index 00000000..289b3d94
      --- /dev/null
      +++ b/lib/tasks/jdbc.rake
      @@ -0,0 +1,8 @@
      +# This file was generated by the "jdbc" generator, which is provided
      +# by the activerecord-jdbc-adapter gem.
      +#
      +# This file allows you to use Rails' various db:* tasks with JDBC.
      +if defined?(JRUBY_VERSION)
      +  require 'jdbc_adapter'
      +  require 'jdbc_adapter/rake_tasks'
      +end
      diff --git a/lib/tasks/load_default_data.rake b/lib/tasks/load_default_data.rake
      new file mode 100644
      index 00000000..cc6774bc
      --- /dev/null
      +++ b/lib/tasks/load_default_data.rake
      @@ -0,0 +1,35 @@
      +desc 'Load Redmine default configuration data. Language is chosen interactively or by setting REDMINE_LANG environment variable.'
      +
      +namespace :redmine do
      +  task :load_default_data => :environment do
      +    include Redmine::I18n
      +    set_language_if_valid('en')
      +
      +    envlang = ENV['REDMINE_LANG']
      +    if !envlang || !set_language_if_valid(envlang)
      +      puts
      +      while true
      +        print "Select language: "
      +        print valid_languages.collect(&:to_s).sort.join(", ")
      +        print " [#{current_language}] "
      +        STDOUT.flush
      +        lang = STDIN.gets.chomp!
      +        break if lang.empty?
      +        break if set_language_if_valid(lang)
      +        puts "Unknown language!"
      +      end
      +      STDOUT.flush
      +      puts "===================================="
      +    end
      +
      +    begin
      +      Redmine::DefaultData::Loader.load(current_language)
      +      puts "Default configuration data loaded."
      +    rescue Redmine::DefaultData::DataAlreadyLoaded => error
      +      puts error.message
      +    rescue => error
      +      puts "Error: " + error.message
      +      puts "Default configuration data was not loaded."
      +    end
      +  end
      +end
      diff --git a/lib/tasks/locales.rake b/lib/tasks/locales.rake
      new file mode 100644
      index 00000000..6311d6ab
      --- /dev/null
      +++ b/lib/tasks/locales.rake
      @@ -0,0 +1,183 @@
      +desc 'Updates and checks locales against en.yml'
      +task :locales do
      +  %w(locales:update locales:check_interpolation).collect do |task|
      +    Rake::Task[task].invoke
      +  end
      +end
      +
      +namespace :locales do
      +  desc 'Updates language files based on en.yml content (only works for new top level keys).'
      +  task :update do
      +    dir = ENV['DIR'] || './config/locales'
      +
      +    en_strings = YAML.load(File.read(File.join(dir,'en.yml')))['en']
      +
      +    files = Dir.glob(File.join(dir,'*.{yaml,yml}'))
      +    files.sort.each do |file|
      +      puts "Updating file #{file}"
      +      file_strings = YAML.load(File.read(file))
      +      file_strings = file_strings[file_strings.keys.first]
      +
      +      missing_keys = en_strings.keys - file_strings.keys
      +      next if missing_keys.empty?
      +
      +      puts "==> Missing #{missing_keys.size} keys (#{missing_keys.join(', ')})"
      +      lang = File.open(file, 'a')
      +
      +      missing_keys.each do |key|
      +        {key => en_strings[key]}.to_yaml.each_line do |line|
      +          next if line =~ /^---/ || line.empty?
      +          puts "  #{line}"
      +          lang << "  #{line}"
      +        end
      +      end
      +
      +      lang.close
      +    end
      +  end
      +
      +  desc 'Checks interpolation arguments in locals against en.yml'
      +  task :check_interpolation do
      +    dir = ENV['DIR'] || './config/locales'
      +    en_strings = YAML.load(File.read(File.join(dir,'en.yml')))['en']
      +    files = Dir.glob(File.join(dir,'*.{yaml,yml}'))
      +    files.sort.each do |file|
      +      puts "parsing #{file}..."
      +      file_strings = YAML.load_file(file)
      +      unless file_strings.is_a?(Hash)
      +        puts "#{file}: content is not a Hash (#{file_strings.class.name})"
      +        next
      +      end
      +      unless file_strings.keys.size == 1
      +        puts "#{file}: content has multiple keys (#{file_strings.keys.size})"
      +        next
      +      end
      +      file_strings = file_strings[file_strings.keys.first]
      +
      +      file_strings.each do |key, string|
      +        next unless string.is_a?(String)
      +        string.scan /%\{\w+\}/ do |match|
      +          unless en_strings[key].nil? || en_strings[key].include?(match)
      +            puts "#{file}: #{key} uses #{match} not found in en.yml"
      +          end
      +        end
      +      end
      +    end
      +  end
      +
      +  desc <<-END_DESC
      +Removes a translation string from all locale file (only works for top-level childless non-multiline keys, probably doesn\'t work on windows).
      +
      +This task does not work on Ruby 1.8.6.
      +You need to use Ruby 1.8.7 or later.
      +
      +Options:
      +  key=key_1,key_2    Comma-separated list of keys to delete
      +  skip=en,de         Comma-separated list of locale files to ignore (filename without extension)
      +END_DESC
      +
      +  task :remove_key do
      +    dir = ENV['DIR'] || './config/locales'
      +    files = Dir.glob(File.join(dir,'*.yml'))
      +    skips = ENV['skip'] ? Regexp.union(ENV['skip'].split(',')) : nil
      +    deletes = ENV['key'] ? Regexp.union(ENV['key'].split(',')) : nil
      +    # Ignore multiline keys (begin with | or >) and keys with children (nothing meaningful after :)
      +    delete_regex = /\A  #{deletes}: +[^\|>\s#].*\z/
      +
      +    files.each do |path|
      +      # Skip certain locales
      +      (puts "Skipping #{path}"; next) if File.basename(path, ".yml") =~ skips
      +      puts "Deleting selected keys from #{path}"
      +      orig_content = File.open(path, 'r') {|file| file.read}
      +      File.open(path, 'w') {|file| orig_content.each_line {|line| file.puts line unless line.chomp =~ delete_regex}}
      +    end
      +  end
      +
      +  desc <<-END_DESC
      +Adds a new top-level translation string to all locale file (only works for childless keys, probably doesn\'t work on windows, doesn't check for duplicates).
      +
      +Options:
      +  key="some_key=foo"
      +  key1="another_key=bar"
      +  key_fb="foo=bar"         Keys to add in the form key=value, every option of the form key[,\\d,_*] will be recognised
      +  skip=en,de               Comma-separated list of locale files to ignore (filename without extension)
      +END_DESC
      +
      +  task :add_key do
      +    dir = ENV['DIR'] || './config/locales'
      +    files = Dir.glob(File.join(dir,'*.yml'))
      +    skips = ENV['skip'] ? Regexp.union(ENV['skip'].split(',')) : nil
      +    keys_regex = /\Akey(\d+|_.+)?\z/
      +    adds = ENV.reject {|k,v| !(k =~ keys_regex)}.values.collect {|v| Array.new v.split("=",2)}
      +    key_list = adds.collect {|v| v[0]}.join(", ")
      +
      +    files.each do |path|
      +      # Skip certain locales
      +      (puts "Skipping #{path}"; next) if File.basename(path, ".yml") =~ skips
      +      # TODO: Check for dupliate/existing keys
      +      puts "Adding #{key_list} to #{path}"
      +      File.open(path, 'a') do |file|
      +        adds.each do |kv|
      +          Hash[*kv].to_yaml.each_line do |line|
      +            file.puts "  #{line}" unless (line =~ /^---/ || line.empty?)
      +          end
      +        end
      +      end
      +    end
      +  end
      +
      +  desc 'Duplicates a key. Exemple rake locales:dup key=foo new_key=bar'
      +  task :dup do
      +    dir = ENV['DIR'] || './config/locales'
      +    files = Dir.glob(File.join(dir,'*.yml'))
      +    skips = ENV['skip'] ? Regexp.union(ENV['skip'].split(',')) : nil
      +    key = ENV['key']
      +    new_key = ENV['new_key']
      +    abort "Missing key argument" if key.blank?
      +    abort "Missing new_key argument" if new_key.blank?
      +
      +    files.each do |path|
      +      # Skip certain locales
      +      (puts "Skipping #{path}"; next) if File.basename(path, ".yml") =~ skips
      +      puts "Adding #{new_key} to #{path}"
      +
      +      strings = File.read(path)
      +      unless strings =~ /^(  #{key}: .+)$/
      +        puts "Key not found in #{path}"
      +        next
      +      end
      +      line = $1
      +
      +      File.open(path, 'a') do |file|
      +        file.puts(line.sub(key, new_key))
      +      end
      +    end
      +  end
      +
      +  desc 'Check parsing yaml by psych library on Ruby 1.9.'
      +
      +  # On Fedora 12 and 13, if libyaml-devel is available,
      +  # in case of installing by rvm,
      +  # Ruby 1.9 default yaml library is psych.
      +
      +  task :check_parsing_by_psych do
      +    begin
      +      require 'psych'
      +      parser = Psych::Parser.new
      +      dir = ENV['DIR'] || './config/locales'
      +      files = Dir.glob(File.join(dir,'*.yml'))
      +      files.sort.each do |filename|
      +        next if File.directory? filename
      +        puts "parsing #{filename}..."
      +        begin
      +          parser.parse File.open(filename)
      +        rescue Exception => e1
      +          puts(e1.message)
      +          puts("")
      +        end
      +      end
      +    rescue Exception => e
      +      puts(e.message)
      +    end
      +  end
      +end
      diff --git a/lib/tasks/metrics.rake b/lib/tasks/metrics.rake
      new file mode 100644
      index 00000000..214cc996
      --- /dev/null
      +++ b/lib/tasks/metrics.rake
      @@ -0,0 +1,6 @@
      +begin
      +  require 'metric_fu'
      +rescue LoadError
      +  # Metric-fu not installed
      +  # http://metric-fu.rubyforge.org/
      +end
      diff --git a/lib/tasks/migrate_from_mantis.rake b/lib/tasks/migrate_from_mantis.rake
      new file mode 100644
      index 00000000..465ca995
      --- /dev/null
      +++ b/lib/tasks/migrate_from_mantis.rake
      @@ -0,0 +1,512 @@
      +# Redmine - project management software
      +# Copyright (C) 2006-2013  Jean-Philippe Lang
      +#
      +# This program is free software; you can redistribute it and/or
      +# modify it under the terms of the GNU General Public License
      +# as published by the Free Software Foundation; either version 2
      +# of the License, or (at your option) any later version.
      +#
      +# This program is distributed in the hope that it will be useful,
      +# but WITHOUT ANY WARRANTY; without even the implied warranty of
      +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      +# GNU General Public License for more details.
      +#
      +# You should have received a copy of the GNU General Public License
      +# along with this program; if not, write to the Free Software
      +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
      +
      +desc 'Mantis migration script'
      +
      +require 'active_record'
      +require 'iconv' if RUBY_VERSION < '1.9'
      +require 'pp'
      +
      +namespace :redmine do
      +task :migrate_from_mantis => :environment do
      +
      +  module MantisMigrate
      +
      +      DEFAULT_STATUS = IssueStatus.default
      +      assigned_status = IssueStatus.find_by_position(2)
      +      resolved_status = IssueStatus.find_by_position(3)
      +      feedback_status = IssueStatus.find_by_position(4)
      +      closed_status = IssueStatus.where(:is_closed => true).first
      +      STATUS_MAPPING = {10 => DEFAULT_STATUS,  # new
      +                        20 => feedback_status, # feedback
      +                        30 => DEFAULT_STATUS,  # acknowledged
      +                        40 => DEFAULT_STATUS,  # confirmed
      +                        50 => assigned_status, # assigned
      +                        80 => resolved_status, # resolved
      +                        90 => closed_status    # closed
      +                        }
      +
      +      priorities = IssuePriority.all
      +      DEFAULT_PRIORITY = priorities[2]
      +      PRIORITY_MAPPING = {10 => priorities[1], # none
      +                          20 => priorities[1], # low
      +                          30 => priorities[2], # normal
      +                          40 => priorities[3], # high
      +                          50 => priorities[4], # urgent
      +                          60 => priorities[5]  # immediate
      +                          }
      +
      +      TRACKER_BUG = Tracker.find_by_position(1)
      +      TRACKER_FEATURE = Tracker.find_by_position(2)
      +
      +      roles = Role.where(:builtin => 0).order('position ASC').all
      +      manager_role = roles[0]
      +      developer_role = roles[1]
      +      DEFAULT_ROLE = roles.last
      +      ROLE_MAPPING = {10 => DEFAULT_ROLE,   # viewer
      +                      25 => DEFAULT_ROLE,   # reporter
      +                      40 => DEFAULT_ROLE,   # updater
      +                      55 => developer_role, # developer
      +                      70 => manager_role,   # manager
      +                      90 => manager_role    # administrator
      +                      }
      +
      +      CUSTOM_FIELD_TYPE_MAPPING = {0 => 'string', # String
      +                                   1 => 'int',    # Numeric
      +                                   2 => 'int',    # Float
      +                                   3 => 'list',   # Enumeration
      +                                   4 => 'string', # Email
      +                                   5 => 'bool',   # Checkbox
      +                                   6 => 'list',   # List
      +                                   7 => 'list',   # Multiselection list
      +                                   8 => 'date',   # Date
      +                                   }
      +
      +      RELATION_TYPE_MAPPING = {1 => IssueRelation::TYPE_RELATES,    # related to
      +                               2 => IssueRelation::TYPE_RELATES,    # parent of
      +                               3 => IssueRelation::TYPE_RELATES,    # child of
      +                               0 => IssueRelation::TYPE_DUPLICATES, # duplicate of
      +                               4 => IssueRelation::TYPE_DUPLICATES  # has duplicate
      +                               }
      +
      +    class MantisUser < ActiveRecord::Base
      +      self.table_name = :mantis_user_table
      +
      +      def firstname
      +        @firstname = realname.blank? ? username : realname.split.first[0..29]
      +        @firstname
      +      end
      +
      +      def lastname
      +        @lastname = realname.blank? ? '-' : realname.split[1..-1].join(' ')[0..29]
      +        @lastname = '-' if @lastname.blank?
      +        @lastname
      +      end
      +
      +      def email
      +        if read_attribute(:email).match(/^([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})$/i) &&
      +             !User.find_by_mail(read_attribute(:email))
      +          @email = read_attribute(:email)
      +        else
      +          @email = "#{username}@foo.bar"
      +        end
      +      end
      +
      +      def username
      +        read_attribute(:username)[0..29].gsub(/[^a-zA-Z0-9_\-@\.]/, '-')
      +      end
      +    end
      +
      +    class MantisProject < ActiveRecord::Base
      +      self.table_name = :mantis_project_table
      +      has_many :versions, :class_name => "MantisVersion", :foreign_key => :project_id
      +      has_many :categories, :class_name => "MantisCategory", :foreign_key => :project_id
      +      has_many :news, :class_name => "MantisNews", :foreign_key => :project_id
      +      has_many :members, :class_name => "MantisProjectUser", :foreign_key => :project_id
      +
      +      def identifier
      +        read_attribute(:name).gsub(/[^a-z0-9\-]+/, '-').slice(0, Project::IDENTIFIER_MAX_LENGTH)
      +      end
      +    end
      +
      +    class MantisVersion < ActiveRecord::Base
      +      self.table_name = :mantis_project_version_table
      +
      +      def version
      +        read_attribute(:version)[0..29]
      +      end
      +
      +      def description
      +        read_attribute(:description)[0..254]
      +      end
      +    end
      +
      +    class MantisCategory < ActiveRecord::Base
      +      self.table_name = :mantis_project_category_table
      +    end
      +
      +    class MantisProjectUser < ActiveRecord::Base
      +      self.table_name = :mantis_project_user_list_table
      +    end
      +
      +    class MantisBug < ActiveRecord::Base
      +      self.table_name = :mantis_bug_table
      +      belongs_to :bug_text, :class_name => "MantisBugText", :foreign_key => :bug_text_id
      +      has_many :bug_notes, :class_name => "MantisBugNote", :foreign_key => :bug_id
      +      has_many :bug_files, :class_name => "MantisBugFile", :foreign_key => :bug_id
      +      has_many :bug_monitors, :class_name => "MantisBugMonitor", :foreign_key => :bug_id
      +    end
      +
      +    class MantisBugText < ActiveRecord::Base
      +      self.table_name = :mantis_bug_text_table
      +
      +      # Adds Mantis steps_to_reproduce and additional_information fields
      +      # to description if any
      +      def full_description
      +        full_description = description
      +        full_description += "\n\n*Steps to reproduce:*\n\n#{steps_to_reproduce}" unless steps_to_reproduce.blank?
      +        full_description += "\n\n*Additional information:*\n\n#{additional_information}" unless additional_information.blank?
      +        full_description
      +      end
      +    end
      +
      +    class MantisBugNote < ActiveRecord::Base
      +      self.table_name = :mantis_bugnote_table
      +      belongs_to :bug, :class_name => "MantisBug", :foreign_key => :bug_id
      +      belongs_to :bug_note_text, :class_name => "MantisBugNoteText", :foreign_key => :bugnote_text_id
      +    end
      +
      +    class MantisBugNoteText < ActiveRecord::Base
      +      self.table_name = :mantis_bugnote_text_table
      +    end
      +
      +    class MantisBugFile < ActiveRecord::Base
      +      self.table_name = :mantis_bug_file_table
      +
      +      def size
      +        filesize
      +      end
      +
      +      def original_filename
      +        MantisMigrate.encode(filename)
      +      end
      +
      +      def content_type
      +        file_type
      +      end
      +
      +      def read(*args)
      +          if @read_finished
      +              nil
      +          else
      +              @read_finished = true
      +              content
      +          end
      +      end
      +    end
      +
      +    class MantisBugRelationship < ActiveRecord::Base
      +      self.table_name = :mantis_bug_relationship_table
      +    end
      +
      +    class MantisBugMonitor < ActiveRecord::Base
      +      self.table_name = :mantis_bug_monitor_table
      +    end
      +
      +    class MantisNews < ActiveRecord::Base
      +      self.table_name = :mantis_news_table
      +    end
      +
      +    class MantisCustomField < ActiveRecord::Base
      +      self.table_name = :mantis_custom_field_table
      +      set_inheritance_column :none
      +      has_many :values, :class_name => "MantisCustomFieldString", :foreign_key => :field_id
      +      has_many :projects, :class_name => "MantisCustomFieldProject", :foreign_key => :field_id
      +
      +      def format
      +        read_attribute :type
      +      end
      +
      +      def name
      +        read_attribute(:name)[0..29]
      +      end
      +    end
      +
      +    class MantisCustomFieldProject < ActiveRecord::Base
      +      self.table_name = :mantis_custom_field_project_table
      +    end
      +
      +    class MantisCustomFieldString < ActiveRecord::Base
      +      self.table_name = :mantis_custom_field_string_table
      +    end
      +
      +    def self.migrate
      +
      +      # Users
      +      print "Migrating users"
      +      User.delete_all "login <> 'admin'"
      +      users_map = {}
      +      users_migrated = 0
      +      MantisUser.all.each do |user|
      +        u = User.new :firstname => encode(user.firstname),
      +                     :lastname => encode(user.lastname),
      +                     :mail => user.email,
      +                     :last_login_on => user.last_visit
      +        u.login = user.username
      +        u.password = 'mantis'
      +        u.status = User::STATUS_LOCKED if user.enabled != 1
      +        u.admin = true if user.access_level == 90
      +        next unless u.save!
      +        users_migrated += 1
      +        users_map[user.id] = u.id
      +        print '.'
      +      end
      +      puts
      +
      +      # Projects
      +      print "Migrating projects"
      +      Project.destroy_all
      +      projects_map = {}
      +      versions_map = {}
      +      categories_map = {}
      +      MantisProject.all.each do |project|
      +        p = Project.new :name => encode(project.name),
      +                        :description => encode(project.description)
      +        p.identifier = project.identifier
      +        next unless p.save
      +        projects_map[project.id] = p.id
      +        p.enabled_module_names = ['issue_tracking', 'news', 'wiki']
      +        p.trackers << TRACKER_BUG unless p.trackers.include?(TRACKER_BUG)
      +        p.trackers << TRACKER_FEATURE unless p.trackers.include?(TRACKER_FEATURE)
      +        print '.'
      +
      +        # Project members
      +        project.members.each do |member|
      +          m = Member.new :user => User.find_by_id(users_map[member.user_id]),
      +                           :roles => [ROLE_MAPPING[member.access_level] || DEFAULT_ROLE]
      +          m.project = p
      +          m.save
      +        end
      +
      +        # Project versions
      +        project.versions.each do |version|
      +          v = Version.new :name => encode(version.version),
      +                          :description => encode(version.description),
      +                          :effective_date => (version.date_order ? version.date_order.to_date : nil)
      +          v.project = p
      +          v.save
      +          versions_map[version.id] = v.id
      +        end
      +
      +        # Project categories
      +        project.categories.each do |category|
      +          g = IssueCategory.new :name => category.category[0,30]
      +          g.project = p
      +          g.save
      +          categories_map[category.category] = g.id
      +        end
      +      end
      +      puts
      +
      +      # Bugs
      +      print "Migrating bugs"
      +      Issue.destroy_all
      +      issues_map = {}
      +      keep_bug_ids = (Issue.count == 0)
      +      MantisBug.find_each(:batch_size => 200) do |bug|
      +        next unless projects_map[bug.project_id] && users_map[bug.reporter_id]
      +        i = Issue.new :project_id => projects_map[bug.project_id],
      +                      :subject => encode(bug.summary),
      +                      :description => encode(bug.bug_text.full_description),
      +                      :priority => PRIORITY_MAPPING[bug.priority] || DEFAULT_PRIORITY,
      +                      :created_on => bug.date_submitted,
      +                      :updated_on => bug.last_updated
      +        i.author = User.find_by_id(users_map[bug.reporter_id])
      +        i.category = IssueCategory.find_by_project_id_and_name(i.project_id, bug.category[0,30]) unless bug.category.blank?
      +        i.fixed_version = Version.find_by_project_id_and_name(i.project_id, bug.fixed_in_version) unless bug.fixed_in_version.blank?
      +        i.status = STATUS_MAPPING[bug.status] || DEFAULT_STATUS
      +        i.tracker = (bug.severity == 10 ? TRACKER_FEATURE : TRACKER_BUG)
      +        i.id = bug.id if keep_bug_ids
      +        next unless i.save
      +        issues_map[bug.id] = i.id
      +        print '.'
      +        STDOUT.flush
      +
      +        # Assignee
      +        # Redmine checks that the assignee is a project member
      +        if (bug.handler_id && users_map[bug.handler_id])
      +          i.assigned_to = User.find_by_id(users_map[bug.handler_id])
      +          i.save(:validate => false)
      +        end
      +
      +        # Bug notes
      +        bug.bug_notes.each do |note|
      +          next unless users_map[note.reporter_id]
      +          n = Journal.new :notes => encode(note.bug_note_text.note),
      +                          :created_on => note.date_submitted
      +          n.user = User.find_by_id(users_map[note.reporter_id])
      +          n.journalized = i
      +          n.save
      +        end
      +
      +        # Bug files
      +        bug.bug_files.each do |file|
      +          a = Attachment.new :created_on => file.date_added
      +          a.file = file
      +          a.author = User.first
      +          a.container = i
      +          a.save
      +        end
      +
      +        # Bug monitors
      +        bug.bug_monitors.each do |monitor|
      +          next unless users_map[monitor.user_id]
      +          i.add_watcher(User.find_by_id(users_map[monitor.user_id]))
      +        end
      +      end
      +
      +      # update issue id sequence if needed (postgresql)
      +      Issue.connection.reset_pk_sequence!(Issue.table_name) if Issue.connection.respond_to?('reset_pk_sequence!')
      +      puts
      +
      +      # Bug relationships
      +      print "Migrating bug relations"
      +      MantisBugRelationship.all.each do |relation|
      +        next unless issues_map[relation.source_bug_id] && issues_map[relation.destination_bug_id]
      +        r = IssueRelation.new :relation_type => RELATION_TYPE_MAPPING[relation.relationship_type]
      +        r.issue_from = Issue.find_by_id(issues_map[relation.source_bug_id])
      +        r.issue_to = Issue.find_by_id(issues_map[relation.destination_bug_id])
      +        pp r unless r.save
      +        print '.'
      +        STDOUT.flush
      +      end
      +      puts
      +
      +      # News
      +      print "Migrating news"
      +      News.destroy_all
      +      MantisNews.where('project_id > 0').all.each do |news|
      +        next unless projects_map[news.project_id]
      +        n = News.new :project_id => projects_map[news.project_id],
      +                     :title => encode(news.headline[0..59]),
      +                     :description => encode(news.body),
      +                     :created_on => news.date_posted
      +        n.author = User.find_by_id(users_map[news.poster_id])
      +        n.save
      +        print '.'
      +        STDOUT.flush
      +      end
      +      puts
      +
      +      # Custom fields
      +      print "Migrating custom fields"
      +      IssueCustomField.destroy_all
      +      MantisCustomField.all.each do |field|
      +        f = IssueCustomField.new :name => field.name[0..29],
      +                                 :field_format => CUSTOM_FIELD_TYPE_MAPPING[field.format],
      +                                 :min_length => field.length_min,
      +                                 :max_length => field.length_max,
      +                                 :regexp => field.valid_regexp,
      +                                 :possible_values => field.possible_values.split('|'),
      +                                 :is_required => field.require_report?
      +        next unless f.save
      +        print '.'
      +        STDOUT.flush
      +        # Trackers association
      +        f.trackers = Tracker.all
      +
      +        # Projects association
      +        field.projects.each do |project|
      +          f.projects << Project.find_by_id(projects_map[project.project_id]) if projects_map[project.project_id]
      +        end
      +
      +        # Values
      +        field.values.each do |value|
      +          v = CustomValue.new :custom_field_id => f.id,
      +                              :value => value.value
      +          v.customized = Issue.find_by_id(issues_map[value.bug_id]) if issues_map[value.bug_id]
      +          v.save
      +        end unless f.new_record?
      +      end
      +      puts
      +
      +      puts
      +      puts "Users:           #{users_migrated}/#{MantisUser.count}"
      +      puts "Projects:        #{Project.count}/#{MantisProject.count}"
      +      puts "Memberships:     #{Member.count}/#{MantisProjectUser.count}"
      +      puts "Versions:        #{Version.count}/#{MantisVersion.count}"
      +      puts "Categories:      #{IssueCategory.count}/#{MantisCategory.count}"
      +      puts "Bugs:            #{Issue.count}/#{MantisBug.count}"
      +      puts "Bug notes:       #{Journal.count}/#{MantisBugNote.count}"
      +      puts "Bug files:       #{Attachment.count}/#{MantisBugFile.count}"
      +      puts "Bug relations:   #{IssueRelation.count}/#{MantisBugRelationship.count}"
      +      puts "Bug monitors:    #{Watcher.count}/#{MantisBugMonitor.count}"
      +      puts "News:            #{News.count}/#{MantisNews.count}"
      +      puts "Custom fields:   #{IssueCustomField.count}/#{MantisCustomField.count}"
      +    end
      +
      +    def self.encoding(charset)
      +      @charset = charset
      +    end
      +
      +    def self.establish_connection(params)
      +      constants.each do |const|
      +        klass = const_get(const)
      +        next unless klass.respond_to? 'establish_connection'
      +        klass.establish_connection params
      +      end
      +    end
      +
      +    def self.encode(text)
      +      if RUBY_VERSION < '1.9'
      +        @ic ||= Iconv.new('UTF-8', @charset)
      +        @ic.iconv text
      +      else
      +        text.to_s.force_encoding(@charset).encode('UTF-8')
      +      end
      +    end
      +  end
      +
      +  puts
      +  if Redmine::DefaultData::Loader.no_data?
      +    puts "Redmine configuration need to be loaded before importing data."
      +    puts "Please, run this first:"
      +    puts
      +    puts "  rake redmine:load_default_data RAILS_ENV=\"#{ENV['RAILS_ENV']}\""
      +    exit
      +  end
      +
      +  puts "WARNING: Your Redmine data will be deleted during this process."
      +  print "Are you sure you want to continue ? [y/N] "
      +  STDOUT.flush
      +  break unless STDIN.gets.match(/^y$/i)
      +
      +  # Default Mantis database settings
      +  db_params = {:adapter => 'mysql2',
      +               :database => 'bugtracker',
      +               :host => 'localhost',
      +               :username => 'root',
      +               :password => '' }
      +
      +  puts
      +  puts "Please enter settings for your Mantis database"
      +  [:adapter, :host, :database, :username, :password].each do |param|
      +    print "#{param} [#{db_params[param]}]: "
      +    value = STDIN.gets.chomp!
      +    db_params[param] = value unless value.blank?
      +  end
      +
      +  while true
      +    print "encoding [UTF-8]: "
      +    STDOUT.flush
      +    encoding = STDIN.gets.chomp!
      +    encoding = 'UTF-8' if encoding.blank?
      +    break if MantisMigrate.encoding encoding
      +    puts "Invalid encoding!"
      +  end
      +  puts
      +
      +  # Make sure bugs can refer bugs in other projects
      +  Setting.cross_project_issue_relations = 1 if Setting.respond_to? 'cross_project_issue_relations'
      +
      +  # Turn off email notifications
      +  Setting.notified_events = []
      +
      +  MantisMigrate.establish_connection db_params
      +  MantisMigrate.migrate
      +end
      +end
      diff --git a/lib/tasks/migrate_from_trac.rake b/lib/tasks/migrate_from_trac.rake
      new file mode 100644
      index 00000000..923b0c62
      --- /dev/null
      +++ b/lib/tasks/migrate_from_trac.rake
      @@ -0,0 +1,771 @@
      +# Redmine - project management software
      +# Copyright (C) 2006-2013  Jean-Philippe Lang
      +#
      +# This program is free software; you can redistribute it and/or
      +# modify it under the terms of the GNU General Public License
      +# as published by the Free Software Foundation; either version 2
      +# of the License, or (at your option) any later version.
      +#
      +# This program is distributed in the hope that it will be useful,
      +# but WITHOUT ANY WARRANTY; without even the implied warranty of
      +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      +# GNU General Public License for more details.
      +#
      +# You should have received a copy of the GNU General Public License
      +# along with this program; if not, write to the Free Software
      +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
      +
      +require 'active_record'
      +require 'iconv' if RUBY_VERSION < '1.9'
      +require 'pp'
      +
      +namespace :redmine do
      +  desc 'Trac migration script'
      +  task :migrate_from_trac => :environment do
      +
      +    module TracMigrate
      +        TICKET_MAP = []
      +
      +        DEFAULT_STATUS = IssueStatus.default
      +        assigned_status = IssueStatus.find_by_position(2)
      +        resolved_status = IssueStatus.find_by_position(3)
      +        feedback_status = IssueStatus.find_by_position(4)
      +        closed_status = IssueStatus.where(:is_closed => true).first
      +        STATUS_MAPPING = {'new' => DEFAULT_STATUS,
      +                          'reopened' => feedback_status,
      +                          'assigned' => assigned_status,
      +                          'closed' => closed_status
      +                          }
      +
      +        priorities = IssuePriority.all
      +        DEFAULT_PRIORITY = priorities[0]
      +        PRIORITY_MAPPING = {'lowest' => priorities[0],
      +                            'low' => priorities[0],
      +                            'normal' => priorities[1],
      +                            'high' => priorities[2],
      +                            'highest' => priorities[3],
      +                            # ---
      +                            'trivial' => priorities[0],
      +                            'minor' => priorities[1],
      +                            'major' => priorities[2],
      +                            'critical' => priorities[3],
      +                            'blocker' => priorities[4]
      +                            }
      +
      +        TRACKER_BUG = Tracker.find_by_position(1)
      +        TRACKER_FEATURE = Tracker.find_by_position(2)
      +        DEFAULT_TRACKER = TRACKER_BUG
      +        TRACKER_MAPPING = {'defect' => TRACKER_BUG,
      +                           'enhancement' => TRACKER_FEATURE,
      +                           'task' => TRACKER_FEATURE,
      +                           'patch' =>TRACKER_FEATURE
      +                           }
      +
      +        roles = Role.where(:builtin => 0).order('position ASC').all
      +        manager_role = roles[0]
      +        developer_role = roles[1]
      +        DEFAULT_ROLE = roles.last
      +        ROLE_MAPPING = {'admin' => manager_role,
      +                        'developer' => developer_role
      +                        }
      +
      +      class ::Time
      +        class << self
      +          alias :real_now :now
      +          def now
      +            real_now - @fake_diff.to_i
      +          end
      +          def fake(time)
      +            @fake_diff = real_now - time
      +            res = yield
      +            @fake_diff = 0
      +           res
      +          end
      +        end
      +      end
      +
      +      class TracComponent < ActiveRecord::Base
      +        self.table_name = :component
      +      end
      +
      +      class TracMilestone < ActiveRecord::Base
      +        self.table_name = :milestone
      +        # If this attribute is set a milestone has a defined target timepoint
      +        def due
      +          if read_attribute(:due) && read_attribute(:due) > 0
      +            Time.at(read_attribute(:due)).to_date
      +          else
      +            nil
      +          end
      +        end
      +        # This is the real timepoint at which the milestone has finished.
      +        def completed
      +          if read_attribute(:completed) && read_attribute(:completed) > 0
      +            Time.at(read_attribute(:completed)).to_date
      +          else
      +            nil
      +          end
      +        end
      +
      +        def description
      +          # Attribute is named descr in Trac v0.8.x
      +          has_attribute?(:descr) ? read_attribute(:descr) : read_attribute(:description)
      +        end
      +      end
      +
      +      class TracTicketCustom < ActiveRecord::Base
      +        self.table_name = :ticket_custom
      +      end
      +
      +      class TracAttachment < ActiveRecord::Base
      +        self.table_name = :attachment
      +        set_inheritance_column :none
      +
      +        def time; Time.at(read_attribute(:time)) end
      +
      +        def original_filename
      +          filename
      +        end
      +
      +        def content_type
      +          ''
      +        end
      +
      +        def exist?
      +          File.file? trac_fullpath
      +        end
      +
      +        def open
      +          File.open("#{trac_fullpath}", 'rb') {|f|
      +            @file = f
      +            yield self
      +          }
      +        end
      +
      +        def read(*args)
      +          @file.read(*args)
      +        end
      +
      +        def description
      +          read_attribute(:description).to_s.slice(0,255)
      +        end
      +
      +      private
      +        def trac_fullpath
      +          attachment_type = read_attribute(:type)
      +          trac_file = filename.gsub( /[^a-zA-Z0-9\-_\.!~*']/n ) {|x| sprintf('%%%02x', x[0]) }
      +          "#{TracMigrate.trac_attachments_directory}/#{attachment_type}/#{id}/#{trac_file}"
      +        end
      +      end
      +
      +      class TracTicket < ActiveRecord::Base
      +        self.table_name = :ticket
      +        set_inheritance_column :none
      +
      +        # ticket changes: only migrate status changes and comments
      +        has_many :ticket_changes, :class_name => "TracTicketChange", :foreign_key => :ticket
      +        has_many :customs, :class_name => "TracTicketCustom", :foreign_key => :ticket
      +
      +        def attachments
      +          TracMigrate::TracAttachment.all(:conditions => ["type = 'ticket' AND id = ?", self.id.to_s])
      +        end
      +
      +        def ticket_type
      +          read_attribute(:type)
      +        end
      +
      +        def summary
      +          read_attribute(:summary).blank? ? "(no subject)" : read_attribute(:summary)
      +        end
      +
      +        def description
      +          read_attribute(:description).blank? ? summary : read_attribute(:description)
      +        end
      +
      +        def time; Time.at(read_attribute(:time)) end
      +        def changetime; Time.at(read_attribute(:changetime)) end
      +      end
      +
      +      class TracTicketChange < ActiveRecord::Base
      +        self.table_name = :ticket_change
      +
      +        def self.columns
      +          # Hides Trac field 'field' to prevent clash with AR field_changed? method (Rails 3.0)
      +          super.select {|column| column.name.to_s != 'field'}
      +        end
      +
      +        def time; Time.at(read_attribute(:time)) end
      +      end
      +
      +      TRAC_WIKI_PAGES = %w(InterMapTxt InterTrac InterWiki RecentChanges SandBox TracAccessibility TracAdmin TracBackup TracBrowser TracCgi TracChangeset \
      +                           TracEnvironment TracFastCgi TracGuide TracImport TracIni TracInstall TracInterfaceCustomization \
      +                           TracLinks TracLogging TracModPython TracNotification TracPermissions TracPlugins TracQuery \
      +                           TracReports TracRevisionLog TracRoadmap TracRss TracSearch TracStandalone TracSupport TracSyntaxColoring TracTickets \
      +                           TracTicketsCustomFields TracTimeline TracUnicode TracUpgrade TracWiki WikiDeletePage WikiFormatting \
      +                           WikiHtml WikiMacros WikiNewPage WikiPageNames WikiProcessors WikiRestructuredText WikiRestructuredTextLinks \
      +                           CamelCase TitleIndex)
      +
      +      class TracWikiPage < ActiveRecord::Base
      +        self.table_name = :wiki
      +        set_primary_key :name
      +
      +        def self.columns
      +          # Hides readonly Trac field to prevent clash with AR readonly? method (Rails 2.0)
      +          super.select {|column| column.name.to_s != 'readonly'}
      +        end
      +
      +        def attachments
      +          TracMigrate::TracAttachment.all(:conditions => ["type = 'wiki' AND id = ?", self.id.to_s])
      +        end
      +
      +        def time; Time.at(read_attribute(:time)) end
      +      end
      +
      +      class TracPermission < ActiveRecord::Base
      +        self.table_name = :permission
      +      end
      +
      +      class TracSessionAttribute < ActiveRecord::Base
      +        self.table_name = :session_attribute
      +      end
      +
      +      def self.find_or_create_user(username, project_member = false)
      +        return User.anonymous if username.blank?
      +
      +        u = User.find_by_login(username)
      +        if !u
      +          # Create a new user if not found
      +          mail = username[0, User::MAIL_LENGTH_LIMIT]
      +          if mail_attr = TracSessionAttribute.find_by_sid_and_name(username, 'email')
      +            mail = mail_attr.value
      +          end
      +          mail = "#{mail}@foo.bar" unless mail.include?("@")
      +
      +          name = username
      +          if name_attr = TracSessionAttribute.find_by_sid_and_name(username, 'name')
      +            name = name_attr.value
      +          end
      +          name =~ (/(.*)(\s+\w+)?/)
      +          fn = $1.strip
      +          ln = ($2 || '-').strip
      +
      +          u = User.new :mail => mail.gsub(/[^-@a-z0-9\.]/i, '-'),
      +                       :firstname => fn[0, limit_for(User, 'firstname')],
      +                       :lastname => ln[0, limit_for(User, 'lastname')]
      +
      +          u.login = username[0, User::LOGIN_LENGTH_LIMIT].gsub(/[^a-z0-9_\-@\.]/i, '-')
      +          u.password = 'trac'
      +          u.admin = true if TracPermission.find_by_username_and_action(username, 'admin')
      +          # finally, a default user is used if the new user is not valid
      +          u = User.first unless u.save
      +        end
      +        # Make sure he is a member of the project
      +        if project_member && !u.member_of?(@target_project)
      +          role = DEFAULT_ROLE
      +          if u.admin
      +            role = ROLE_MAPPING['admin']
      +          elsif TracPermission.find_by_username_and_action(username, 'developer')
      +            role = ROLE_MAPPING['developer']
      +          end
      +          Member.create(:user => u, :project => @target_project, :roles => [role])
      +          u.reload
      +        end
      +        u
      +      end
      +
      +      # Basic wiki syntax conversion
      +      def self.convert_wiki_text(text)
      +        # Titles
      +        text = text.gsub(/^(\=+)\s(.+)\s(\=+)/) {|s| "\nh#{$1.length}. #{$2}\n"}
      +        # External Links
      +        text = text.gsub(/\[(http[^\s]+)\s+([^\]]+)\]/) {|s| "\"#{$2}\":#{$1}"}
      +        # Ticket links:
      +        #      [ticket:234 Text],[ticket:234 This is a test]
      +        text = text.gsub(/\[ticket\:([^\ ]+)\ (.+?)\]/, '"\2":/issues/show/\1')
      +        #      ticket:1234
      +        #      #1 is working cause Redmine uses the same syntax.
      +        text = text.gsub(/ticket\:([^\ ]+)/, '#\1')
      +        # Milestone links:
      +        #      [milestone:"0.1.0 Mercury" Milestone 0.1.0 (Mercury)]
      +        #      The text "Milestone 0.1.0 (Mercury)" is not converted,
      +        #      cause Redmine's wiki does not support this.
      +        text = text.gsub(/\[milestone\:\"([^\"]+)\"\ (.+?)\]/, 'version:"\1"')
      +        #      [milestone:"0.1.0 Mercury"]
      +        text = text.gsub(/\[milestone\:\"([^\"]+)\"\]/, 'version:"\1"')
      +        text = text.gsub(/milestone\:\"([^\"]+)\"/, 'version:"\1"')
      +        #      milestone:0.1.0
      +        text = text.gsub(/\[milestone\:([^\ ]+)\]/, 'version:\1')
      +        text = text.gsub(/milestone\:([^\ ]+)/, 'version:\1')
      +        # Internal Links
      +        text = text.gsub(/\[\[BR\]\]/, "\n") # This has to go before the rules below
      +        text = text.gsub(/\[\"(.+)\".*\]/) {|s| "[[#{$1.delete(',./?;|:')}]]"}
      +        text = text.gsub(/\[wiki:\"(.+)\".*\]/) {|s| "[[#{$1.delete(',./?;|:')}]]"}
      +        text = text.gsub(/\[wiki:\"(.+)\".*\]/) {|s| "[[#{$1.delete(',./?;|:')}]]"}
      +        text = text.gsub(/\[wiki:([^\s\]]+)\]/) {|s| "[[#{$1.delete(',./?;|:')}]]"}
      +        text = text.gsub(/\[wiki:([^\s\]]+)\s(.*)\]/) {|s| "[[#{$1.delete(',./?;|:')}|#{$2.delete(',./?;|:')}]]"}
      +
      +  # Links to pages UsingJustWikiCaps
      +  text = text.gsub(/([^!]|^)(^| )([A-Z][a-z]+[A-Z][a-zA-Z]+)/, '\\1\\2[[\3]]')
      +  # Normalize things that were supposed to not be links
      +  # like !NotALink
      +  text = text.gsub(/(^| )!([A-Z][A-Za-z]+)/, '\1\2')
      +        # Revisions links
      +        text = text.gsub(/\[(\d+)\]/, 'r\1')
      +        # Ticket number re-writing
      +        text = text.gsub(/#(\d+)/) do |s|
      +          if $1.length < 10
      +#            TICKET_MAP[$1.to_i] ||= $1
      +            "\##{TICKET_MAP[$1.to_i] || $1}"
      +          else
      +            s
      +          end
      +        end
      +        # We would like to convert the Code highlighting too
      +        # This will go into the next line.
      +        shebang_line = false
      +        # Reguar expression for start of code
      +        pre_re = /\{\{\{/
      +        # Code hightlighing...
      +        shebang_re = /^\#\!([a-z]+)/
      +        # Regular expression for end of code
      +        pre_end_re = /\}\}\}/
      +
      +        # Go through the whole text..extract it line by line
      +        text = text.gsub(/^(.*)$/) do |line|
      +          m_pre = pre_re.match(line)
      +          if m_pre
      +            line = '
      '
      +          else
      +            m_sl = shebang_re.match(line)
      +            if m_sl
      +              shebang_line = true
      +              line = ''
      +            end
      +            m_pre_end = pre_end_re.match(line)
      +            if m_pre_end
      +              line = '
      ' + if shebang_line + line = '' + line + end + end + end + line + end + + # Highlighting + text = text.gsub(/'''''([^\s])/, '_*\1') + text = text.gsub(/([^\s])'''''/, '\1*_') + text = text.gsub(/'''/, '*') + text = text.gsub(/''/, '_') + text = text.gsub(/__/, '+') + text = text.gsub(/~~/, '-') + text = text.gsub(/`/, '@') + text = text.gsub(/,,/, '~') + # Lists + text = text.gsub(/^([ ]+)\* /) {|s| '*' * $1.length + " "} + + text + end + + def self.migrate + establish_connection + + # Quick database test + TracComponent.count + + migrated_components = 0 + migrated_milestones = 0 + migrated_tickets = 0 + migrated_custom_values = 0 + migrated_ticket_attachments = 0 + migrated_wiki_edits = 0 + migrated_wiki_attachments = 0 + + #Wiki system initializing... + @target_project.wiki.destroy if @target_project.wiki + @target_project.reload + wiki = Wiki.new(:project => @target_project, :start_page => 'WikiStart') + wiki_edit_count = 0 + + # Components + print "Migrating components" + issues_category_map = {} + TracComponent.all.each do |component| + print '.' + STDOUT.flush + c = IssueCategory.new :project => @target_project, + :name => encode(component.name[0, limit_for(IssueCategory, 'name')]) + next unless c.save + issues_category_map[component.name] = c + migrated_components += 1 + end + puts + + # Milestones + print "Migrating milestones" + version_map = {} + TracMilestone.all.each do |milestone| + print '.' + STDOUT.flush + # First we try to find the wiki page... + p = wiki.find_or_new_page(milestone.name.to_s) + p.content = WikiContent.new(:page => p) if p.new_record? + p.content.text = milestone.description.to_s + p.content.author = find_or_create_user('trac') + p.content.comments = 'Milestone' + p.save + + v = Version.new :project => @target_project, + :name => encode(milestone.name[0, limit_for(Version, 'name')]), + :description => nil, + :wiki_page_title => milestone.name.to_s, + :effective_date => milestone.completed + + next unless v.save + version_map[milestone.name] = v + migrated_milestones += 1 + end + puts + + # Custom fields + # TODO: read trac.ini instead + print "Migrating custom fields" + custom_field_map = {} + TracTicketCustom.find_by_sql("SELECT DISTINCT name FROM #{TracTicketCustom.table_name}").each do |field| + print '.' + STDOUT.flush + # Redmine custom field name + field_name = encode(field.name[0, limit_for(IssueCustomField, 'name')]).humanize + # Find if the custom already exists in Redmine + f = IssueCustomField.find_by_name(field_name) + # Or create a new one + f ||= IssueCustomField.create(:name => encode(field.name[0, limit_for(IssueCustomField, 'name')]).humanize, + :field_format => 'string') + + next if f.new_record? + f.trackers = Tracker.all + f.projects << @target_project + custom_field_map[field.name] = f + end + puts + + # Trac 'resolution' field as a Redmine custom field + r = IssueCustomField.where(:name => "Resolution").first + r = IssueCustomField.new(:name => 'Resolution', + :field_format => 'list', + :is_filter => true) if r.nil? + r.trackers = Tracker.all + r.projects << @target_project + r.possible_values = (r.possible_values + %w(fixed invalid wontfix duplicate worksforme)).flatten.compact.uniq + r.save! + custom_field_map['resolution'] = r + + # Tickets + print "Migrating tickets" + TracTicket.find_each(:batch_size => 200) do |ticket| + print '.' + STDOUT.flush + i = Issue.new :project => @target_project, + :subject => encode(ticket.summary[0, limit_for(Issue, 'subject')]), + :description => convert_wiki_text(encode(ticket.description)), + :priority => PRIORITY_MAPPING[ticket.priority] || DEFAULT_PRIORITY, + :created_on => ticket.time + i.author = find_or_create_user(ticket.reporter) + i.category = issues_category_map[ticket.component] unless ticket.component.blank? + i.fixed_version = version_map[ticket.milestone] unless ticket.milestone.blank? + i.status = STATUS_MAPPING[ticket.status] || DEFAULT_STATUS + i.tracker = TRACKER_MAPPING[ticket.ticket_type] || DEFAULT_TRACKER + i.id = ticket.id unless Issue.exists?(ticket.id) + next unless Time.fake(ticket.changetime) { i.save } + TICKET_MAP[ticket.id] = i.id + migrated_tickets += 1 + + # Owner + unless ticket.owner.blank? + i.assigned_to = find_or_create_user(ticket.owner, true) + Time.fake(ticket.changetime) { i.save } + end + + # Comments and status/resolution changes + ticket.ticket_changes.group_by(&:time).each do |time, changeset| + status_change = changeset.select {|change| change.field == 'status'}.first + resolution_change = changeset.select {|change| change.field == 'resolution'}.first + comment_change = changeset.select {|change| change.field == 'comment'}.first + + n = Journal.new :notes => (comment_change ? convert_wiki_text(encode(comment_change.newvalue)) : ''), + :created_on => time + n.user = find_or_create_user(changeset.first.author) + n.journalized = i + if status_change && + STATUS_MAPPING[status_change.oldvalue] && + STATUS_MAPPING[status_change.newvalue] && + (STATUS_MAPPING[status_change.oldvalue] != STATUS_MAPPING[status_change.newvalue]) + n.details << JournalDetail.new(:property => 'attr', + :prop_key => 'status_id', + :old_value => STATUS_MAPPING[status_change.oldvalue].id, + :value => STATUS_MAPPING[status_change.newvalue].id) + end + if resolution_change + n.details << JournalDetail.new(:property => 'cf', + :prop_key => custom_field_map['resolution'].id, + :old_value => resolution_change.oldvalue, + :value => resolution_change.newvalue) + end + n.save unless n.details.empty? && n.notes.blank? + end + + # Attachments + ticket.attachments.each do |attachment| + next unless attachment.exist? + attachment.open { + a = Attachment.new :created_on => attachment.time + a.file = attachment + a.author = find_or_create_user(attachment.author) + a.container = i + a.description = attachment.description + migrated_ticket_attachments += 1 if a.save + } + end + + # Custom fields + custom_values = ticket.customs.inject({}) do |h, custom| + if custom_field = custom_field_map[custom.name] + h[custom_field.id] = custom.value + migrated_custom_values += 1 + end + h + end + if custom_field_map['resolution'] && !ticket.resolution.blank? + custom_values[custom_field_map['resolution'].id] = ticket.resolution + end + i.custom_field_values = custom_values + i.save_custom_field_values + end + + # update issue id sequence if needed (postgresql) + Issue.connection.reset_pk_sequence!(Issue.table_name) if Issue.connection.respond_to?('reset_pk_sequence!') + puts + + # Wiki + print "Migrating wiki" + if wiki.save + TracWikiPage.order('name, version').all.each do |page| + # Do not migrate Trac manual wiki pages + next if TRAC_WIKI_PAGES.include?(page.name) + wiki_edit_count += 1 + print '.' + STDOUT.flush + p = wiki.find_or_new_page(page.name) + p.content = WikiContent.new(:page => p) if p.new_record? + p.content.text = page.text + p.content.author = find_or_create_user(page.author) unless page.author.blank? || page.author == 'trac' + p.content.comments = page.comment + Time.fake(page.time) { p.new_record? ? p.save : p.content.save } + + next if p.content.new_record? + migrated_wiki_edits += 1 + + # Attachments + page.attachments.each do |attachment| + next unless attachment.exist? + next if p.attachments.find_by_filename(attachment.filename.gsub(/^.*(\\|\/)/, '').gsub(/[^\w\.\-]/,'_')) #add only once per page + attachment.open { + a = Attachment.new :created_on => attachment.time + a.file = attachment + a.author = find_or_create_user(attachment.author) + a.description = attachment.description + a.container = p + migrated_wiki_attachments += 1 if a.save + } + end + end + + wiki.reload + wiki.pages.each do |page| + page.content.text = convert_wiki_text(page.content.text) + Time.fake(page.content.updated_on) { page.content.save } + end + end + puts + + puts + puts "Components: #{migrated_components}/#{TracComponent.count}" + puts "Milestones: #{migrated_milestones}/#{TracMilestone.count}" + puts "Tickets: #{migrated_tickets}/#{TracTicket.count}" + puts "Ticket files: #{migrated_ticket_attachments}/" + TracAttachment.count(:conditions => {:type => 'ticket'}).to_s + puts "Custom values: #{migrated_custom_values}/#{TracTicketCustom.count}" + puts "Wiki edits: #{migrated_wiki_edits}/#{wiki_edit_count}" + puts "Wiki files: #{migrated_wiki_attachments}/" + TracAttachment.count(:conditions => {:type => 'wiki'}).to_s + end + + def self.limit_for(klass, attribute) + klass.columns_hash[attribute.to_s].limit + end + + def self.encoding(charset) + @charset = charset + end + + def self.set_trac_directory(path) + @@trac_directory = path + raise "This directory doesn't exist!" unless File.directory?(path) + raise "#{trac_attachments_directory} doesn't exist!" unless File.directory?(trac_attachments_directory) + @@trac_directory + rescue Exception => e + puts e + return false + end + + def self.trac_directory + @@trac_directory + end + + def self.set_trac_adapter(adapter) + return false if adapter.blank? + raise "Unknown adapter: #{adapter}!" unless %w(sqlite3 mysql postgresql).include?(adapter) + # If adapter is sqlite or sqlite3, make sure that trac.db exists + raise "#{trac_db_path} doesn't exist!" if %w(sqlite3).include?(adapter) && !File.exist?(trac_db_path) + @@trac_adapter = adapter + rescue Exception => e + puts e + return false + end + + def self.set_trac_db_host(host) + return nil if host.blank? + @@trac_db_host = host + end + + def self.set_trac_db_port(port) + return nil if port.to_i == 0 + @@trac_db_port = port.to_i + end + + def self.set_trac_db_name(name) + return nil if name.blank? + @@trac_db_name = name + end + + def self.set_trac_db_username(username) + @@trac_db_username = username + end + + def self.set_trac_db_password(password) + @@trac_db_password = password + end + + def self.set_trac_db_schema(schema) + @@trac_db_schema = schema + end + + mattr_reader :trac_directory, :trac_adapter, :trac_db_host, :trac_db_port, :trac_db_name, :trac_db_schema, :trac_db_username, :trac_db_password + + def self.trac_db_path; "#{trac_directory}/db/trac.db" end + def self.trac_attachments_directory; "#{trac_directory}/attachments" end + + def self.target_project_identifier(identifier) + project = Project.find_by_identifier(identifier) + if !project + # create the target project + project = Project.new :name => identifier.humanize, + :description => '' + project.identifier = identifier + puts "Unable to create a project with identifier '#{identifier}'!" unless project.save + # enable issues and wiki for the created project + project.enabled_module_names = ['issue_tracking', 'wiki'] + else + puts + puts "This project already exists in your Redmine database." + print "Are you sure you want to append data to this project ? [Y/n] " + STDOUT.flush + exit if STDIN.gets.match(/^n$/i) + end + project.trackers << TRACKER_BUG unless project.trackers.include?(TRACKER_BUG) + project.trackers << TRACKER_FEATURE unless project.trackers.include?(TRACKER_FEATURE) + @target_project = project.new_record? ? nil : project + @target_project.reload + end + + def self.connection_params + if trac_adapter == 'sqlite3' + {:adapter => 'sqlite3', + :database => trac_db_path} + else + {:adapter => trac_adapter, + :database => trac_db_name, + :host => trac_db_host, + :port => trac_db_port, + :username => trac_db_username, + :password => trac_db_password, + :schema_search_path => trac_db_schema + } + end + end + + def self.establish_connection + constants.each do |const| + klass = const_get(const) + next unless klass.respond_to? 'establish_connection' + klass.establish_connection connection_params + end + end + + def self.encode(text) + if RUBY_VERSION < '1.9' + @ic ||= Iconv.new('UTF-8', @charset) + @ic.iconv text + else + text.to_s.force_encoding(@charset).encode('UTF-8') + end + end + end + + puts + if Redmine::DefaultData::Loader.no_data? + puts "Redmine configuration need to be loaded before importing data." + puts "Please, run this first:" + puts + puts " rake redmine:load_default_data RAILS_ENV=\"#{ENV['RAILS_ENV']}\"" + exit + end + + puts "WARNING: a new project will be added to Redmine during this process." + print "Are you sure you want to continue ? [y/N] " + STDOUT.flush + break unless STDIN.gets.match(/^y$/i) + puts + + def prompt(text, options = {}, &block) + default = options[:default] || '' + while true + print "#{text} [#{default}]: " + STDOUT.flush + value = STDIN.gets.chomp! + value = default if value.blank? + break if yield value + end + end + + DEFAULT_PORTS = {'mysql' => 3306, 'postgresql' => 5432} + + prompt('Trac directory') {|directory| TracMigrate.set_trac_directory directory.strip} + prompt('Trac database adapter (sqlite3, mysql2, postgresql)', :default => 'sqlite3') {|adapter| TracMigrate.set_trac_adapter adapter} + unless %w(sqlite3).include?(TracMigrate.trac_adapter) + prompt('Trac database host', :default => 'localhost') {|host| TracMigrate.set_trac_db_host host} + prompt('Trac database port', :default => DEFAULT_PORTS[TracMigrate.trac_adapter]) {|port| TracMigrate.set_trac_db_port port} + prompt('Trac database name') {|name| TracMigrate.set_trac_db_name name} + prompt('Trac database schema', :default => 'public') {|schema| TracMigrate.set_trac_db_schema schema} + prompt('Trac database username') {|username| TracMigrate.set_trac_db_username username} + prompt('Trac database password') {|password| TracMigrate.set_trac_db_password password} + end + prompt('Trac database encoding', :default => 'UTF-8') {|encoding| TracMigrate.encoding encoding} + prompt('Target project identifier') {|identifier| TracMigrate.target_project_identifier identifier} + puts + + # Turn off email notifications + Setting.notified_events = [] + + TracMigrate.migrate + end +end + diff --git a/lib/tasks/permissions.rake b/lib/tasks/permissions.rake new file mode 100644 index 00000000..02ce1b2a --- /dev/null +++ b/lib/tasks/permissions.rake @@ -0,0 +1,9 @@ +namespace :redmine do + desc "List all permissions and the actions registered with them" + task :permissions => :environment do + puts "Permission Name - controller/action pairs" + Redmine::AccessControl.permissions.sort {|a,b| a.name.to_s <=> b.name.to_s }.each do |permission| + puts ":#{permission.name} - #{permission.actions.join(', ')}" + end + end +end diff --git a/lib/tasks/redmine.rake b/lib/tasks/redmine.rake new file mode 100644 index 00000000..0ad4f2f1 --- /dev/null +++ b/lib/tasks/redmine.rake @@ -0,0 +1,126 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +namespace :redmine do + namespace :attachments do + desc 'Removes uploaded files left unattached after one day.' + task :prune => :environment do + Attachment.prune + end + + desc 'Moves attachments stored at the root of the file directory (ie. created before Redmine 2.3) to their subdirectories' + task :move_to_subdirectories => :environment do + Attachment.move_from_root_to_target_directory + end + end + + namespace :tokens do + desc 'Removes expired tokens.' + task :prune => :environment do + Token.destroy_expired + end + end + + namespace :watchers do + desc 'Removes watchers from what they can no longer view.' + task :prune => :environment do + Watcher.prune + end + end + + desc 'Fetch changesets from the repositories' + task :fetch_changesets => :environment do + Repository.fetch_changesets + end + + desc 'Migrates and copies plugins assets.' + task :plugins do + Rake::Task["redmine:plugins:migrate"].invoke + Rake::Task["redmine:plugins:assets"].invoke + end + + namespace :plugins do + desc 'Migrates installed plugins.' + task :migrate => :environment do + name = ENV['NAME'] + version = nil + version_string = ENV['VERSION'] + if version_string + if version_string =~ /^\d+$/ + version = version_string.to_i + if name.nil? + abort "The VERSION argument requires a plugin NAME." + end + else + abort "Invalid VERSION #{version_string} given." + end + end + + begin + Redmine::Plugin.migrate(name, version) + rescue Redmine::PluginNotFound + abort "Plugin #{name} was not found." + end + + Rake::Task["db:schema:dump"].invoke + end + + desc 'Copies plugins assets into the public directory.' + task :assets => :environment do + name = ENV['NAME'] + + begin + Redmine::Plugin.mirror_assets(name) + rescue Redmine::PluginNotFound + abort "Plugin #{name} was not found." + end + end + + desc 'Runs the plugins tests.' + task :test do + Rake::Task["redmine:plugins:test:units"].invoke + Rake::Task["redmine:plugins:test:functionals"].invoke + Rake::Task["redmine:plugins:test:integration"].invoke + end + + namespace :test do + desc 'Runs the plugins unit tests.' + Rake::TestTask.new :units => "db:test:prepare" do |t| + t.libs << "test" + t.verbose = true + t.pattern = "plugins/#{ENV['NAME'] || '*'}/test/unit/**/*_test.rb" + end + + desc 'Runs the plugins functional tests.' + Rake::TestTask.new :functionals => "db:test:prepare" do |t| + t.libs << "test" + t.verbose = true + t.pattern = "plugins/#{ENV['NAME'] || '*'}/test/functional/**/*_test.rb" + end + + desc 'Runs the plugins integration tests.' + Rake::TestTask.new :integration => "db:test:prepare" do |t| + t.libs << "test" + t.verbose = true + t.pattern = "plugins/#{ENV['NAME'] || '*'}/test/integration/**/*_test.rb" + end + end + end +end + +# Load plugins' rake tasks +Dir[File.join(Rails.root, "plugins/*/lib/tasks/**/*.rake")].sort.each { |ext| load ext } diff --git a/lib/tasks/reminder.rake b/lib/tasks/reminder.rake new file mode 100644 index 00000000..67661a36 --- /dev/null +++ b/lib/tasks/reminder.rake @@ -0,0 +1,43 @@ +# Redmine - project management software +# Copyright (C) 2006-2013 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +desc <<-END_DESC +Send reminders about issues due in the next days. + +Available options: + * days => number of days to remind about (defaults to 7) + * tracker => id of tracker (defaults to all trackers) + * project => id or identifier of project (defaults to all projects) + * users => comma separated list of user/group ids who should be reminded + +Example: + rake redmine:send_reminders days=7 users="1,23, 56" RAILS_ENV="production" +END_DESC + +namespace :redmine do + task :send_reminders => :environment do + options = {} + options[:days] = ENV['days'].to_i if ENV['days'] + options[:project] = ENV['project'] if ENV['project'] + options[:tracker] = ENV['tracker'].to_i if ENV['tracker'] + options[:users] = (ENV['users'] || '').split(',').each(&:strip!) + + Mailer.with_synched_deliveries do + Mailer.reminders(options) + end + end +end diff --git a/lib/tasks/testing.rake b/lib/tasks/testing.rake new file mode 100644 index 00000000..cfb8e77f --- /dev/null +++ b/lib/tasks/testing.rake @@ -0,0 +1,110 @@ +### From http://svn.geekdaily.org/public/rails/plugins/generally_useful/tasks/coverage_via_rcov.rake + +namespace :test do + desc 'Measures test coverage' + task :coverage do + rm_f "coverage" + rm_f "coverage.data" + rcov = "rcov --rails --aggregate coverage.data --text-summary -Ilib --html --exclude gems/" + files = %w(unit functional integration).map {|dir| Dir.glob("test/#{dir}/**/*_test.rb")}.flatten.join(" ") + system("#{rcov} #{files}") + end + + desc 'Run unit and functional scm tests' + task :scm do + errors = %w(test:scm:units test:scm:functionals).collect do |task| + begin + Rake::Task[task].invoke + nil + rescue => e + task + end + end.compact + abort "Errors running #{errors.to_sentence(:locale => :en)}!" if errors.any? + end + + namespace :scm do + namespace :setup do + desc "Creates directory for test repositories" + task :create_dir do + FileUtils.mkdir_p Rails.root + '/tmp/test' + end + + supported_scms = [:subversion, :cvs, :bazaar, :mercurial, :git, :darcs, :filesystem] + + desc "Creates a test subversion repository" + task :subversion => :create_dir do + repo_path = "tmp/test/subversion_repository" + unless File.exists?(repo_path) + system "svnadmin create #{repo_path}" + system "gunzip < test/fixtures/repositories/subversion_repository.dump.gz | svnadmin load #{repo_path}" + end + end + + desc "Creates a test mercurial repository" + task :mercurial => :create_dir do + repo_path = "tmp/test/mercurial_repository" + unless File.exists?(repo_path) + bundle_path = "test/fixtures/repositories/mercurial_repository.hg" + system "hg init #{repo_path}" + system "hg -R #{repo_path} pull #{bundle_path}" + end + end + + (supported_scms - [:subversion, :mercurial]).each do |scm| + desc "Creates a test #{scm} repository" + task scm => :create_dir do + unless File.exists?("tmp/test/#{scm}_repository") + # system "gunzip < test/fixtures/repositories/#{scm}_repository.tar.gz | tar -xv -C tmp/test" + system "tar -xvz -C tmp/test -f test/fixtures/repositories/#{scm}_repository.tar.gz" + end + end + end + + desc "Creates all test repositories" + task :all => supported_scms + end + + desc "Updates installed test repositories" + task :update do + require 'fileutils' + Dir.glob("tmp/test/*_repository").each do |dir| + next unless File.basename(dir) =~ %r{^(.+)_repository$} && File.directory?(dir) + scm = $1 + next unless fixture = Dir.glob("test/fixtures/repositories/#{scm}_repository.*").first + next if File.stat(dir).ctime > File.stat(fixture).mtime + + FileUtils.rm_rf dir + Rake::Task["test:scm:setup:#{scm}"].execute + end + end + + Rake::TestTask.new(:units => "db:test:prepare") do |t| + t.libs << "test" + t.verbose = true + t.test_files = FileList['test/unit/repository*_test.rb'] + FileList['test/unit/lib/redmine/scm/**/*_test.rb'] + end + Rake::Task['test:scm:units'].comment = "Run the scm unit tests" + + Rake::TestTask.new(:functionals => "db:test:prepare") do |t| + t.libs << "test" + t.verbose = true + t.test_files = FileList['test/functional/repositories*_test.rb'] + end + Rake::Task['test:scm:functionals'].comment = "Run the scm functional tests" + end + + Rake::TestTask.new(:rdm_routing) do |t| + t.libs << "test" + t.verbose = true + t.test_files = FileList['test/integration/routing/*_test.rb'] + end + Rake::Task['test:rdm_routing'].comment = "Run the routing tests" + + Rake::TestTask.new(:ui => "db:test:prepare") do |t| + t.libs << "test" + t.verbose = true + t.test_files = FileList['test/ui/**/*_test.rb'] + end + Rake::Task['test:ui'].comment = "Run the UI tests with Capybara (PhantomJS listening on port 4444 is required)" +end diff --git a/lib/tasks/yardoc.rake b/lib/tasks/yardoc.rake new file mode 100644 index 00000000..aa6c5eeb --- /dev/null +++ b/lib/tasks/yardoc.rake @@ -0,0 +1,21 @@ +begin + require 'yard' + + YARD::Rake::YardocTask.new do |t| + files = ['lib/**/*.rb', 'app/**/*.rb'] + files << Dir['vendor/plugins/**/*.rb'].reject {|f| f.match(/test/) } # Exclude test files + t.files = files + + static_files = ['doc/CHANGELOG', + 'doc/COPYING', + 'doc/INSTALL', + 'doc/RUNNING_TESTS', + 'doc/UPGRADING'].join(',') + + t.options += ['--output-dir', './doc/app', '--files', static_files] + end + +rescue LoadError + # yard not installed (gem install yard) + # http://yardoc.org +end diff --git a/plugins/README b/plugins/README new file mode 100644 index 00000000..edef2567 --- /dev/null +++ b/plugins/README @@ -0,0 +1 @@ +Put your Redmine plugins here. diff --git a/public/404.html b/public/404.html new file mode 100644 index 00000000..23c08dd8 --- /dev/null +++ b/public/404.html @@ -0,0 +1,23 @@ + + +Redmine 404 error + + +

      Page not found

      +

      The page you were trying to access doesn't exist or has been removed.

      +

      Back

      + + diff --git a/public/500.html b/public/500.html new file mode 100644 index 00000000..588d83bb --- /dev/null +++ b/public/500.html @@ -0,0 +1,25 @@ + + +Redmine 500 error + + +

      Internal error

      +

      An error occurred on the page you were trying to access.
      + If you continue to experience problems please contact your Redmine administrator for assistance.

      +

      If you are the Redmine administrator, check your log files for details about the error.

      +

      Back

      + + diff --git a/public/application.css b/public/application.css new file mode 100644 index 00000000..deb7b321 --- /dev/null +++ b/public/application.css @@ -0,0 +1,1148 @@ +html {overflow-y:scroll;} +body { font-family: Verdana, sans-serif; font-size: 12px; color:#484848; margin: 0; padding: 0; min-width: 900px; } + +h1, h2, h3, h4 {font-family: "Trebuchet MS", Verdana, sans-serif;padding: 2px 10px 1px 0px;margin: 0 0 10px 0;} +#content h1, h2, h3, h4 {color: #555;} +h2, .wiki h1 {font-size: 20px;} +h3, .wiki h2 {font-size: 16px;} +h4, .wiki h3 {font-size: 13px;} +h4 {border-bottom: 1px dotted #bbb;} + +/***** Layout *****/ +#wrapper {background: white;} + +#top-menu {background: #3E5B76; color: #000; height:1.8em; font-size: 1.0em; padding: 2px 2px 0px 6px;} +#top-menu ul {margin: 0; padding: 0;} +#top-menu li { + float:left; + list-style-type:none; + margin: 0px 0px 0px 0px; + padding: 0px 0px 0px 0px; + white-space:nowrap; +} +#top-menu a {color: #000000; margin-right: 8px; font-weight: bold;} +#top-menu #loggedas { float: right; margin-right: 0.5em; color: #fff; } + +#account {float:right;} + +#header {min-height:5.3em;margin:0;background-color:#628DB6;color:#f8f8f8; padding: 4px 8px 20px 6px; position:relative;} +#header a {color:#f8f8f8;} +#header h1 a.ancestor { font-size: 80%; } +#quick-search {float:right;} + +#main-menu {position: absolute; bottom: 0px; left:6px; margin-right: -500px;} +#main-menu ul {margin: 0; padding: 0;} +#main-menu li { + float:left; + list-style-type:none; + margin: 0px 2px 0px 0px; + padding: 0px 0px 0px 0px; + white-space:nowrap; +} +#main-menu li a { + display: block; + color: #039ea0; + text-decoration: none; + font-weight: bold; + margin: 0; + padding: 4px 10px 4px 10px; +} +#main-menu li a:hover {background:#759FCF; color:#fff;} +#main-menu li a.selected, #main-menu li a.selected:hover {background:#fff; color:#555;} + +#admin-menu ul {margin: 0; padding: 0;} +#admin-menu li {margin: 0; padding: 0 0 6px 0; list-style-type:none;} + +#admin-menu a { background-position: 0% 40%; background-repeat: no-repeat; padding-left: 20px; padding-top: 2px; padding-bottom: 3px;} +#admin-menu a.projects { background-image: url(../images/projects.png); } +#admin-menu a.users { background-image: url(../images/user.png); } +#admin-menu a.groups { background-image: url(../images/group.png); } +#admin-menu a.roles { background-image: url(../images/database_key.png); } +#admin-menu a.trackers { background-image: url(../images/ticket.png); } +#admin-menu a.issue_statuses { background-image: url(../images/ticket_edit.png); } +#admin-menu a.workflows { background-image: url(../images/ticket_go.png); } +#admin-menu a.custom_fields { background-image: url(../images/textfield.png); } +#admin-menu a.enumerations { background-image: url(../images/text_list_bullets.png); } +#admin-menu a.settings { background-image: url(../images/changeset.png); } +#admin-menu a.plugins { background-image: url(../images/plugin.png); } +#admin-menu a.info { background-image: url(../images/help.png); } +#admin-menu a.server_authentication { background-image: url(../images/server_key.png); } + +#main {background-color:#EEEEEE;} + +#sidebar{ float: right; width: 22%; position: relative; z-index: 9; padding: 0; margin: 0;} +* html #sidebar{ width: 22%; } +#sidebar h3{ font-size: 14px; margin-top:14px; color: #666; } +#sidebar hr{ width: 100%; margin: 0 auto; height: 1px; background: #ccc; border: 0; } +* html #sidebar hr{ width: 95%; position: relative; left: -6px; color: #ccc; } +#sidebar .contextual { margin-right: 1em; } + +#content { width: 75%; background-color: #fff; margin: 0px; border-right: 1px solid #ddd; padding: 6px 10px 10px 10px; z-index: 10; } +* html #content{ width: 75%; padding-left: 0; margin-top: 0px; padding: 6px 10px 10px 10px;} +html>body #content { min-height: 600px; } +* html body #content { height: 600px; } /* IE */ + +#main.nosidebar #sidebar{ display: none; } +#main.nosidebar #content{ width: auto; border-right: 0; } + +#footer {clear: both; border-top: 1px solid #bbb; font-size: 0.9em; color: #aaa; padding: 5px; text-align:center; background:#fff;} + +#login-form table {margin-top:5em; padding:1em; margin-left: auto; margin-right: auto; border: 2px solid #FDBF3B; background-color:#FFEBC1; } +#login-form table td {padding: 6px;} +#login-form label {font-weight: bold;} +#login-form input#username, #login-form input#password { width: 300px; } + +div.modal { border-radius:5px; background:#fff; z-index:50; padding:4px;} +div.modal h3.title {display:none;} +div.modal p.buttons {text-align:right; margin-bottom:0;} + +input#openid_url { background: url(../images/openid-bg.gif) no-repeat; background-color: #fff; background-position: 0 50%; padding-left: 18px; } + +.clear:after{ content: "."; display: block; height: 0; clear: both; visibility: hidden; } + +/***** Links *****/ +a, a:link, a:visited{ color: #169; text-decoration: none; } +a:hover, a:active{ color: #c61a1a; text-decoration: underline;} +a img{ border: 0; } + +a.issue.closed, a.issue.closed:link, a.issue.closed:visited { color: #999; text-decoration: line-through; } +a.project.closed, a.project.closed:link, a.project.closed:visited { color: #999; } +a.user.locked, a.user.locked:link, a.user.locked:visited {color: #999;} + +#sidebar a.selected {line-height:1.7em; padding:1px 3px 2px 2px; margin-left:-2px; background-color:#9DB9D5; color:#fff; border-radius:2px;} +#sidebar a.selected:hover {text-decoration:none;} +#admin-menu a {line-height:1.7em;} +#admin-menu a.selected {padding-left: 20px !important; background-position: 2px 40%;} + +a.collapsible {padding-left: 12px; background: url(../images/arrow_expanded.png) no-repeat -3px 40%;} +a.collapsible.collapsed {background: url(../images/arrow_collapsed.png) no-repeat -5px 40%;} + +a#toggle-completed-versions {color:#999;} +/***** Tables *****/ +table.list { border: 1px solid #e4e4e4; border-collapse: collapse; width: 100%; margin-bottom: 4px; } +table.list th { background-color:#EEEEEE; padding: 4px; white-space:nowrap; } +table.list td { vertical-align: top; padding-right:10px; } +table.list td.id { width: 2%; text-align: center;} +table.list td.checkbox { width: 15px; padding: 2px 0 0 0; } +table.list td.checkbox input {padding:0px;} +table.list td.buttons { width: 15%; white-space:nowrap; text-align: right; } +table.list td.buttons a { padding-right: 0.6em; } +table.list caption { text-align: left; padding: 0.5em 0.5em 0.5em 0; } + +tr.project td.name a { white-space:nowrap; } +tr.project.closed, tr.project.archived { color: #aaa; } +tr.project.closed a, tr.project.archived a { color: #aaa; } + +tr.project.idnt td.name span {background: url(../images/bullet_arrow_right.png) no-repeat 0 50%; padding-left: 16px;} +tr.project.idnt-1 td.name {padding-left: 0.5em;} +tr.project.idnt-2 td.name {padding-left: 2em;} +tr.project.idnt-3 td.name {padding-left: 3.5em;} +tr.project.idnt-4 td.name {padding-left: 5em;} +tr.project.idnt-5 td.name {padding-left: 6.5em;} +tr.project.idnt-6 td.name {padding-left: 8em;} +tr.project.idnt-7 td.name {padding-left: 9.5em;} +tr.project.idnt-8 td.name {padding-left: 11em;} +tr.project.idnt-9 td.name {padding-left: 12.5em;} + +tr.issue { text-align: center; white-space: nowrap; } +tr.issue td.subject, tr.issue td.category, td.assigned_to, tr.issue td.string, tr.issue td.text, tr.issue td.relations { white-space: normal; } +tr.issue td.subject, tr.issue td.relations { text-align: left; } +tr.issue td.done_ratio table.progress { margin-left:auto; margin-right: auto;} +tr.issue td.relations span {white-space: nowrap;} +table.issues td.description {color:#777; font-size:90%; padding:4px 4px 4px 24px; text-align:left; white-space:normal;} +table.issues td.description pre {white-space:normal;} + +tr.issue.idnt td.subject a {background: url(../images/bullet_arrow_right.png) no-repeat 0 50%; padding-left: 16px;} +tr.issue.idnt-1 td.subject {padding-left: 0.5em;} +tr.issue.idnt-2 td.subject {padding-left: 2em;} +tr.issue.idnt-3 td.subject {padding-left: 3.5em;} +tr.issue.idnt-4 td.subject {padding-left: 5em;} +tr.issue.idnt-5 td.subject {padding-left: 6.5em;} +tr.issue.idnt-6 td.subject {padding-left: 8em;} +tr.issue.idnt-7 td.subject {padding-left: 9.5em;} +tr.issue.idnt-8 td.subject {padding-left: 11em;} +tr.issue.idnt-9 td.subject {padding-left: 12.5em;} + +tr.entry { border: 1px solid #f8f8f8; } +tr.entry td { white-space: nowrap; } +tr.entry td.filename { width: 30%; } +tr.entry td.filename_no_report { width: 70%; } +tr.entry td.size { text-align: right; font-size: 90%; } +tr.entry td.revision, tr.entry td.author { text-align: center; } +tr.entry td.age { text-align: right; } +tr.entry.file td.filename a { margin-left: 16px; } +tr.entry.file td.filename_no_report a { margin-left: 16px; } + +tr span.expander {background-image: url(../images/bullet_toggle_plus.png); padding-left: 8px; margin-left: 0; cursor: pointer;} +tr.open span.expander {background-image: url(../images/bullet_toggle_minus.png);} + +tr.changeset { height: 20px } +tr.changeset ul, ol { margin-top: 0px; margin-bottom: 0px; } +tr.changeset td.revision_graph { width: 15%; background-color: #fffffb; } +tr.changeset td.author { text-align: center; width: 15%; white-space:nowrap;} +tr.changeset td.committed_on { text-align: center; width: 15%; white-space:nowrap;} + +table.files tr.file td { text-align: center; } +table.files tr.file td.filename { text-align: left; padding-left: 24px; } +table.files tr.file td.digest { font-size: 80%; } + +table.members td.roles, table.memberships td.roles { width: 45%; } + +tr.message { height: 2.6em; } +tr.message td.subject { padding-left: 20px; } +tr.message td.created_on { white-space: nowrap; } +tr.message td.last_message { font-size: 80%; white-space: nowrap; } +tr.message.locked td.subject { background: url(../images/locked.png) no-repeat 0 1px; } +tr.message.sticky td.subject { background: url(../images/bullet_go.png) no-repeat 0 1px; font-weight: bold; } + +tr.version.closed, tr.version.closed a { color: #999; } +tr.version td.name { padding-left: 20px; } +tr.version.shared td.name { background: url(../images/link.png) no-repeat 0% 70%; } +tr.version td.date, tr.version td.status, tr.version td.sharing { text-align: center; white-space:nowrap; } + +tr.user td { width:13%; } +tr.user td.email { width:18%; } +tr.user td { white-space: nowrap; } +tr.user.locked, tr.user.registered { color: #aaa; } +tr.user.locked a, tr.user.registered a { color: #aaa; } + +table.permissions td.role {color:#999;font-size:90%;font-weight:normal !important;text-align:center;vertical-align:bottom;} + +tr.wiki-page-version td.updated_on, tr.wiki-page-version td.author {text-align:center;} + +tr.time-entry { text-align: center; white-space: nowrap; } +tr.time-entry td.issue, tr.time-entry td.comments { text-align: left; white-space: normal; } +td.hours { text-align: right; font-weight: bold; padding-right: 0.5em; } +td.hours .hours-dec { font-size: 0.9em; } + +table.plugins td { vertical-align: middle; } +table.plugins td.configure { text-align: right; padding-right: 1em; } +table.plugins span.name { font-weight: bold; display: block; margin-bottom: 6px; } +table.plugins span.description { display: block; font-size: 0.9em; } +table.plugins span.url { display: block; font-size: 0.9em; } + +table.list tbody tr.group td { padding: 0.8em 0 0.5em 0.3em; font-weight: bold; border-bottom: 1px solid #ccc; } +table.list tbody tr.group span.count {position:relative; top:-1px; color:#fff; font-size:10px; background:#9DB9D5; padding:0px 6px 1px 6px; border-radius:3px; margin-left:4px;} +tr.group a.toggle-all { color: #aaa; font-size: 80%; font-weight: normal; display:none;} +tr.group:hover a.toggle-all { display:inline;} +a.toggle-all:hover {text-decoration:none;} + +table.list tbody tr:hover { background-color:#ffffdd; } +table.list tbody tr.group:hover { background-color:inherit; } +table td {padding:2px;} +table p {margin:0;} +.odd {background-color:#f6f7f8;} +.even {background-color: #fff;} + +a.sort { padding-right: 16px; background-position: 100% 50%; background-repeat: no-repeat; } +a.sort.asc { background-image: url(../images/sort_asc.png); } +a.sort.desc { background-image: url(../images/sort_desc.png); } + +table.attributes { width: 100% } +table.attributes th { vertical-align: top; text-align: left; } +table.attributes td { vertical-align: top; } + +table.boards a.board, h3.comments { background: url(../images/comment.png) no-repeat 0% 50%; padding-left: 20px; } +table.boards td.topic-count, table.boards td.message-count {text-align:center;} +table.boards td.last-message {font-size:80%;} + +table.messages td.author, table.messages td.created_on, table.messages td.reply-count {text-align:center;} + +table.query-columns { + border-collapse: collapse; + border: 0; +} + +table.query-columns td.buttons { + vertical-align: middle; + text-align: center; +} + +td.center {text-align:center;} + +h3.version { background: url(../images/package.png) no-repeat 0% 50%; padding-left: 20px; } + +div.issues h3 { background: url(../images/ticket.png) no-repeat 0% 50%; padding-left: 20px; } +div.members h3 { background: url(../images/group.png) no-repeat 0% 50%; padding-left: 20px; } +div.news h3 { background: url(../images/news.png) no-repeat 0% 50%; padding-left: 20px; } +div.projects h3 { background: url(../images/projects.png) no-repeat 0% 50%; padding-left: 20px; } + +#watchers ul {margin: 0; padding: 0;} +#watchers li {list-style-type:none;margin: 0px 2px 0px 0px; padding: 0px 0px 0px 0px;} +#watchers select {width: 95%; display: block;} +#watchers a.delete {opacity: 0.4; vertical-align: middle;} +#watchers a.delete:hover {opacity: 1;} +#watchers img.gravatar {margin: 0 4px 2px 0;} + +span#watchers_inputs {overflow:auto; display:block;} +span.search_for_watchers {display:block;} +span.search_for_watchers, span.add_attachment {font-size:80%; line-height:2.5em;} +span.search_for_watchers a, span.add_attachment a {padding-left:16px; background: url(../images/bullet_add.png) no-repeat 0 50%; } + + +.highlight { background-color: #FCFD8D;} +.highlight.token-1 { background-color: #faa;} +.highlight.token-2 { background-color: #afa;} +.highlight.token-3 { background-color: #aaf;} + +.box{ + padding:6px; + margin-bottom: 10px; + background-color:#f6f6f6; + color:#505050; + line-height:1.5em; + border: 1px solid #e4e4e4; +} + +div.square { + border: 1px solid #999; + float: left; + margin: .3em .4em 0 .4em; + overflow: hidden; + width: .6em; height: .6em; +} +.contextual {float:right; white-space: nowrap; line-height:1.4em;margin-top:5px; padding-left: 10px; font-size:0.9em;} +.contextual input, .contextual select {font-size:0.9em;} +.message .contextual { margin-top: 0; } + +.splitcontent {overflow:auto;} +.splitcontentleft{float:left; width:49%;} +.splitcontentright{float:right; width:49%;} +form {display: inline;} +input, select {vertical-align: middle; margin-top: 1px; margin-bottom: 1px;} +fieldset {border: 1px solid #e4e4e4; margin:0;} +legend {color: #484848;} +hr { width: 100%; height: 1px; background: #ccc; border: 0;} +blockquote { font-style: italic; border-left: 3px solid #e0e0e0; padding-left: 0.6em; margin-left: 2.4em;} +blockquote blockquote { margin-left: 0;} +acronym { border-bottom: 1px dotted; cursor: help; } +textarea.wiki-edit {width:99%; resize:vertical;} +li p {margin-top: 0;} +div.issue {background:#ffffdd; padding:6px; margin-bottom:6px;border: 1px solid #d7d7d7;} +p.breadcrumb { font-size: 0.9em; margin: 4px 0 4px 0;} +p.subtitle { font-size: 0.9em; margin: -6px 0 12px 0; font-style: italic; } +p.footnote { font-size: 0.9em; margin-top: 0px; margin-bottom: 0px; } + +div.issue div.subject div div { padding-left: 16px; } +div.issue div.subject p {margin: 0; margin-bottom: 0.1em; font-size: 90%; color: #999;} +div.issue div.subject>div>p { margin-top: 0.5em; } +div.issue div.subject h3 {margin: 0; margin-bottom: 0.1em;} +div.issue span.private { position:relative; bottom: 2px; text-transform: uppercase; background: #d22; color: #fff; font-weight:bold; padding: 0px 2px 0px 2px; font-size: 60%; margin-right: 2px; border-radius: 2px;} +div.issue .next-prev-links {color:#999;} +div.issue table.attributes th {width:22%;} +div.issue table.attributes td {width:28%;} + +#issue_tree table.issues, #relations table.issues { border: 0; } +#issue_tree td.checkbox, #relations td.checkbox {display:none;} +#relations td.buttons {padding:0;} + +fieldset.collapsible { border-width: 1px 0 0 0; font-size: 0.9em; } +fieldset.collapsible>legend { padding-left: 16px; background: url(../images/arrow_expanded.png) no-repeat 0% 40%; cursor:pointer; } +fieldset.collapsible.collapsed>legend { background-image: url(../images/arrow_collapsed.png); } + +fieldset#date-range p { margin: 2px 0 2px 0; } +fieldset#filters table { border-collapse: collapse; } +fieldset#filters table td { padding: 0; vertical-align: middle; } +fieldset#filters tr.filter { height: 2.1em; } +fieldset#filters td.field { width:230px; } +fieldset#filters td.operator { width:180px; } +fieldset#filters td.operator select {max-width:170px;} +fieldset#filters td.values { white-space:nowrap; } +fieldset#filters td.values select {min-width:130px;} +fieldset#filters td.values input {height:1em;} +fieldset#filters td.add-filter { text-align: right; vertical-align: top; } + +.toggle-multiselect {background: url(../images/bullet_toggle_plus.png) no-repeat 0% 40%; padding-left:8px; margin-left:0; cursor:pointer;} +.buttons { font-size: 0.9em; margin-bottom: 1.4em; margin-top: 1em; } + +div#issue-changesets {float:right; width:45%; margin-left: 1em; margin-bottom: 1em; background: #fff; padding-left: 1em; font-size: 90%;} +div#issue-changesets div.changeset { padding: 4px;} +div#issue-changesets div.changeset { border-bottom: 1px solid #ddd; } +div#issue-changesets p { margin-top: 0; margin-bottom: 1em;} + +.journal ul.details img {margin:0 0 -3px 4px;} +div.journal {overflow:auto;} +div.journal.private-notes {border-left:2px solid #d22; padding-left:4px; margin-left:-6px;} + +div#activity dl, #search-results { margin-left: 2em; } +div#activity dd, #search-results dd { margin-bottom: 1em; padding-left: 18px; font-size: 0.9em; } +div#activity dt, #search-results dt { margin-bottom: 0px; padding-left: 20px; line-height: 18px; background-position: 0 50%; background-repeat: no-repeat; } +div#activity dt.me .time { border-bottom: 1px solid #999; } +div#activity dt .time { color: #777; font-size: 80%; } +div#activity dd .description, #search-results dd .description { font-style: italic; } +div#activity span.project:after, #search-results span.project:after { content: " -"; } +div#activity dd span.description, #search-results dd span.description { display:block; color: #808080; } +div#activity dt.grouped {margin-left:5em;} +div#activity dd.grouped {margin-left:9em;} + +#search-results dd { margin-bottom: 1em; padding-left: 20px; margin-left:0px; } + +div#search-results-counts {float:right;} +div#search-results-counts ul { margin-top: 0.5em; } +div#search-results-counts li { list-style-type:none; float: left; margin-left: 1em; } + +dt.issue { background-image: url(../images/ticket.png); } +dt.issue-edit { background-image: url(../images/ticket_edit.png); } +dt.issue-closed { background-image: url(../images/ticket_checked.png); } +dt.issue-note { background-image: url(../images/ticket_note.png); } +dt.changeset { background-image: url(../images/changeset.png); } +dt.news { background-image: url(../images/news.png); } +dt.message { background-image: url(../images/message.png); } +dt.reply { background-image: url(../images/comments.png); } +dt.wiki-page { background-image: url(../images/wiki_edit.png); } +dt.attachment { background-image: url(../images/attachment.png); } +dt.document { background-image: url(../images/document.png); } +dt.project { background-image: url(../images/projects.png); } +dt.time-entry { background-image: url(../images/time.png); } + +#search-results dt.issue.closed { background-image: url(../images/ticket_checked.png); } + +div#roadmap .related-issues { margin-bottom: 1em; } +div#roadmap .related-issues td.checkbox { display: none; } +div#roadmap .wiki h1:first-child { display: none; } +div#roadmap .wiki h1 { font-size: 120%; } +div#roadmap .wiki h2 { font-size: 110%; } +body.controller-versions.action-show div#roadmap .related-issues {width:70%;} + +div#version-summary { float:right; width:28%; margin-left: 16px; margin-bottom: 16px; background-color: #fff; } +div#version-summary fieldset { margin-bottom: 1em; } +div#version-summary fieldset.time-tracking table { width:100%; } +div#version-summary th, div#version-summary td.total-hours { text-align: right; } + +table#time-report td.hours, table#time-report th.period, table#time-report th.total { text-align: right; padding-right: 0.5em; } +table#time-report tbody tr.subtotal { font-style: italic; color:#777;} +table#time-report tbody tr.subtotal td.hours { color:#b0b0b0; } +table#time-report tbody tr.total { font-weight: bold; background-color:#EEEEEE; border-top:1px solid #e4e4e4;} +table#time-report .hours-dec { font-size: 0.9em; } + +div.wiki-page .contextual a {opacity: 0.4} +div.wiki-page .contextual a:hover {opacity: 1} + +form .attributes select { width: 60%; } +input#issue_subject { width: 99%; } +select#issue_done_ratio { width: 95px; } + +ul.projects {margin:0; padding-left:1em;} +ul.projects ul {padding-left:1.6em;} +ul.projects.root {margin:0; padding:0;} +ul.projects li {list-style-type:none;} + +#projects-index ul.projects ul.projects { border-left: 3px solid #e0e0e0; padding-left:1em;} +#projects-index ul.projects li.root {margin-bottom: 1em;} +#projects-index ul.projects li.child {margin-top: 1em;} +#projects-index ul.projects div.root a.project { font-family: "Trebuchet MS", Verdana, sans-serif; font-weight: bold; font-size: 16px; margin: 0 0 10px 0; } +.my-project { padding-left: 18px; background: url(../images/fav.png) no-repeat 0 50%; } + +#notified-projects ul, #tracker_project_ids ul {max-height:250px; overflow-y:auto;} + +#related-issues li img {vertical-align:middle;} + +ul.properties {padding:0; font-size: 0.9em; color: #777;} +ul.properties li {list-style-type:none;} +ul.properties li span {font-style:italic;} + +.total-hours { font-size: 110%; font-weight: bold; } +.total-hours span.hours-int { font-size: 120%; } + +.autoscroll {overflow-x: auto; padding:1px; margin-bottom: 1.2em;} +#user_login, #user_firstname, #user_lastname, #user_mail, #my_account_form select, #user_form select, #user_identity_url { width: 90%; } + +#workflow_copy_form select { width: 200px; } +table.transitions td.enabled {background: #bfb;} +table.fields_permissions select {font-size:90%} +table.fields_permissions td.readonly {background:#ddd;} +table.fields_permissions td.required {background:#d88;} + +textarea#custom_field_possible_values {width: 99%} +textarea#custom_field_default_value {width: 99%} + +input#content_comments {width: 99%} + +p.pagination {margin-top:8px; font-size: 90%} + +/***** Tabular forms ******/ +.tabular p{ + margin: 0; + padding: 3px 0 3px 0; + padding-left: 180px; /* width of left column containing the label elements */ + min-height: 1.8em; + clear:left; +} + +html>body .tabular p {overflow:hidden;} + +.tabular label{ + font-weight: bold; + float: left; + text-align: right; + /* width of left column */ + margin-left: -180px; + /* width of labels. Should be smaller than left column to create some right margin */ + width: 175px; +} + +.tabular label.floating{ + font-weight: normal; + margin-left: 0px; + text-align: left; + width: 270px; +} + +.tabular label.block{ + font-weight: normal; + margin-left: 0px !important; + text-align: left; + float: none; + display: block; + width: auto; +} + +.tabular label.inline{ + font-weight: normal; + float:none; + margin-left: 5px !important; + width: auto; +} + +label.no-css { + font-weight: inherit; + float:none; + text-align:left; + margin-left:0px; + width:auto; +} +input#time_entry_comments { width: 90%;} + +#preview fieldset {margin-top: 1em; background: url(../images/draft.png)} + +.tabular.settings p{ padding-left: 300px; } +.tabular.settings label{ margin-left: -300px; width: 295px; } +.tabular.settings textarea { width: 99%; } + +.settings.enabled_scm table {width:100%} +.settings.enabled_scm td.scm_name{ font-weight: bold; } + +fieldset.settings label { display: block; } +fieldset#notified_events .parent { padding-left: 20px; } + +span.required {color: #bb0000;} +.summary {font-style: italic;} + +#attachments_fields input.description {margin-left:4px; width:340px;} +#attachments_fields span {display:block; white-space:nowrap;} +#attachments_fields input.filename {border:0; height:1.8em; width:250px; color:#555; background-color:inherit; background:url(../images/attachment.png) no-repeat 1px 50%; padding-left:18px;} +#attachments_fields .ajax-waiting input.filename {background:url(../images/hourglass.png) no-repeat 0px 50%;} +#attachments_fields .ajax-loading input.filename {background:url(../images/loading.gif) no-repeat 0px 50%;} +#attachments_fields div.ui-progressbar { width: 100px; height:14px; margin: 2px 0 -5px 8px; display: inline-block; } +a.remove-upload {background: url(../images/delete.png) no-repeat 1px 50%; width:1px; display:inline-block; padding-left:16px;} +a.remove-upload:hover {text-decoration:none !important;} + +div.fileover { background-color: lavender; } + +div.attachments { margin-top: 12px; } +div.attachments p { margin:4px 0 2px 0; } +div.attachments img { vertical-align: middle; } +div.attachments span.author { font-size: 0.9em; color: #888; } + +div.thumbnails {margin-top:0.6em;} +div.thumbnails div {background:#fff;border:2px solid #ddd;display:inline-block;margin-right:2px;} +div.thumbnails img {margin: 3px;} + +p.other-formats { text-align: right; font-size:0.9em; color: #666; } +.other-formats span + span:before { content: "| "; } + +a.atom { background: url(../images/feed.png) no-repeat 1px 50%; padding: 2px 0px 3px 16px; } + +em.info {font-style:normal;font-size:90%;color:#888;display:block;} +em.info.error {padding-left:20px; background:url(../images/exclamation.png) no-repeat 0 50%;} + +textarea.text_cf {width:90%;} + +#tab-content-modules fieldset p {margin:3px 0 4px 0;} + +#tab-content-members .splitcontentleft, #tab-content-memberships .splitcontentleft, #tab-content-users .splitcontentleft {width: 64%;} +#tab-content-members .splitcontentright, #tab-content-memberships .splitcontentright, #tab-content-users .splitcontentright {width: 34%;} +#tab-content-members fieldset, #tab-content-memberships fieldset, #tab-content-users fieldset {padding:1em; margin-bottom: 1em;} +#tab-content-members fieldset legend, #tab-content-memberships fieldset legend, #tab-content-users fieldset legend {font-weight: bold;} +#tab-content-members fieldset label, #tab-content-memberships fieldset label, #tab-content-users fieldset label {display: block;} +#tab-content-members #principals, #tab-content-users #principals {max-height: 400px; overflow: auto;} + +#users_for_watcher {height: 200px; overflow:auto;} +#users_for_watcher label {display: block;} + +table.members td.group { padding-left: 20px; background: url(../images/group.png) no-repeat 0% 50%; } + +input#principal_search, input#user_search {width:90%} + +input.autocomplete { + background: #fff url(../images/magnifier.png) no-repeat 2px 50%; padding-left:20px; + border:1px solid #9EB1C2; border-radius:2px; height:1.5em; +} +input.autocomplete.ajax-loading { + background-image: url(../images/loading.gif); +} + +/***** Flash & error messages ****/ +#errorExplanation, div.flash, .nodata, .warning, .conflict { + padding: 4px 4px 4px 30px; + margin-bottom: 12px; + font-size: 1.1em; + border: 2px solid; +} + +div.flash {margin-top: 8px;} + +div.flash.error, #errorExplanation { + background: url(../images/exclamation.png) 8px 50% no-repeat; + background-color: #ffe3e3; + border-color: #dd0000; + color: #880000; +} + +div.flash.notice { + background: url(../images/true.png) 8px 5px no-repeat; + background-color: #dfffdf; + border-color: #9fcf9f; + color: #005f00; +} + +div.flash.warning, .conflict { + background: url(../images/warning.png) 8px 5px no-repeat; + background-color: #FFEBC1; + border-color: #FDBF3B; + color: #A6750C; + text-align: left; +} + +.nodata, .warning { + text-align: center; + background-color: #FFEBC1; + border-color: #FDBF3B; + color: #A6750C; +} + +#errorExplanation ul { font-size: 0.9em;} +#errorExplanation h2, #errorExplanation p { display: none; } + +.conflict-details {font-size:80%;} + +/***** Ajax indicator ******/ +#ajax-indicator { +position: absolute; /* fixed not supported by IE */ +background-color:#eee; +border: 1px solid #bbb; +top:35%; +left:40%; +width:20%; +font-weight:bold; +text-align:center; +padding:0.6em; +z-index:100; +opacity: 0.5; +} + +html>body #ajax-indicator { position: fixed; } + +#ajax-indicator span { +background-position: 0% 40%; +background-repeat: no-repeat; +background-image: url(../images/loading.gif); +padding-left: 26px; +vertical-align: bottom; +} + +/***** Calendar *****/ +table.cal {border-collapse: collapse; width: 100%; margin: 0px 0 6px 0;border: 1px solid #d7d7d7;} +table.cal thead th {width: 14%; background-color:#EEEEEE; padding: 4px; } +table.cal thead th.week-number {width: auto;} +table.cal tbody tr {height: 100px;} +table.cal td {border: 1px solid #d7d7d7; vertical-align: top; font-size: 0.9em;} +table.cal td.week-number { background-color:#EEEEEE; padding: 4px; border:none; font-size: 1em;} +table.cal td p.day-num {font-size: 1.1em; text-align:right;} +table.cal td.odd p.day-num {color: #bbb;} +table.cal td.today {background:#ffffdd;} +table.cal td.today p.day-num {font-weight: bold;} +table.cal .starting a, p.cal.legend .starting {background: url(../images/bullet_go.png) no-repeat -1px -2px; padding-left:16px;} +table.cal .ending a, p.cal.legend .ending {background: url(../images/bullet_end.png) no-repeat -1px -2px; padding-left:16px;} +table.cal .starting.ending a, p.cal.legend .starting.ending {background: url(../images/bullet_diamond.png) no-repeat -1px -2px; padding-left:16px;} +p.cal.legend span {display:block;} + +/***** Tooltips ******/ +.tooltip{position:relative;z-index:24;} +.tooltip:hover{z-index:25;color:#000;} +.tooltip span.tip{display: none; text-align:left;} + +div.tooltip:hover span.tip{ +display:block; +position:absolute; +top:12px; left:24px; width:270px; +border:1px solid #555; +background-color:#fff; +padding: 4px; +font-size: 0.8em; +color:#505050; +} + +img.ui-datepicker-trigger { + cursor: pointer; + vertical-align: middle; + margin-left: 4px; +} + +/***** Progress bar *****/ +table.progress { + border-collapse: collapse; + border-spacing: 0pt; + empty-cells: show; + text-align: center; + float:left; + margin: 1px 6px 1px 0px; +} + +table.progress td { height: 1em; } +table.progress td.closed { background: #BAE0BA none repeat scroll 0%; } +table.progress td.done { background: #D3EDD3 none repeat scroll 0%; } +table.progress td.todo { background: #eee none repeat scroll 0%; } +p.percent {font-size: 80%;} +p.progress-info {clear: left; font-size: 80%; margin-top:-4px; color:#777;} + +#roadmap table.progress td { height: 1.2em; } +/***** Tabs *****/ +#content .tabs {height: 2.6em; margin-bottom:1.2em; position:relative; overflow:hidden;} +#content .tabs ul {margin:0; position:absolute; bottom:0; padding-left:0.5em; width: 2000px; border-bottom: 1px solid #bbbbbb;} +#content .tabs ul li { + float:left; + list-style-type:none; + white-space:nowrap; + margin-right:4px; + background:#fff; + position:relative; + margin-bottom:-1px; +} +#content .tabs ul li a{ + display:block; + font-size: 0.9em; + text-decoration:none; + line-height:1.3em; + padding:4px 6px 4px 6px; + border: 1px solid #ccc; + border-bottom: 1px solid #bbbbbb; + background-color: #f6f6f6; + color:#999; + font-weight:bold; + border-top-left-radius:3px; + border-top-right-radius:3px; +} + +#content .tabs ul li a:hover { + background-color: #ffffdd; + text-decoration:none; +} + +#content .tabs ul li a.selected { + background-color: #fff; + border: 1px solid #bbbbbb; + border-bottom: 1px solid #fff; + color:#444; +} + +#content .tabs ul li a.selected:hover {background-color: #fff;} + +div.tabs-buttons { position:absolute; right: 0; width: 48px; height: 24px; background: white; bottom: 0; border-bottom: 1px solid #bbbbbb; } + +button.tab-left, button.tab-right { + font-size: 0.9em; + cursor: pointer; + height:24px; + border: 1px solid #ccc; + border-bottom: 1px solid #bbbbbb; + position:absolute; + padding:4px; + width: 20px; + bottom: -1px; +} + +button.tab-left { + right: 20px; + background: #eeeeee url(../images/bullet_arrow_left.png) no-repeat 50% 50%; + border-top-left-radius:3px; +} + +button.tab-right { + right: 0; + background: #eeeeee url(../images/bullet_arrow_right.png) no-repeat 50% 50%; + border-top-right-radius:3px; +} + +/***** Diff *****/ +.diff_out { background: #fcc; } +.diff_out span { background: #faa; } +.diff_in { background: #cfc; } +.diff_in span { background: #afa; } + +.text-diff { + padding: 1em; + background-color:#f6f6f6; + color:#505050; + border: 1px solid #e4e4e4; +} + +/***** Wiki *****/ +div.wiki table { + border-collapse: collapse; + margin-bottom: 1em; +} + +div.wiki table, div.wiki td, div.wiki th { + border: 1px solid #bbb; + padding: 4px; +} + +div.wiki .noborder, div.wiki .noborder td, div.wiki .noborder th {border:0;} + +div.wiki .external { + background-position: 0% 60%; + background-repeat: no-repeat; + padding-left: 12px; + background-image: url(../images/external.png); +} + +div.wiki a.new {color: #b73535;} + +div.wiki ul, div.wiki ol {margin-bottom:1em;} + +div.wiki pre { + margin: 1em 1em 1em 1.6em; + padding: 8px; + background-color: #fafafa; + border: 1px solid #e2e2e2; + width:auto; + overflow-x: auto; + overflow-y: hidden; +} + +div.wiki ul.toc { + background-color: #ffffdd; + border: 1px solid #e4e4e4; + padding: 4px; + line-height: 1.2em; + margin-bottom: 12px; + margin-right: 12px; + margin-left: 0; + display: table +} +* html div.wiki ul.toc { width: 50%; } /* IE6 doesn't autosize div */ + +div.wiki ul.toc.right { float: right; margin-left: 12px; margin-right: 0; width: auto; } +div.wiki ul.toc.left { float: left; margin-right: 12px; margin-left: 0; width: auto; } +div.wiki ul.toc ul { margin: 0; padding: 0; } +div.wiki ul.toc li {list-style-type:none; margin: 0; font-size:12px;} +div.wiki ul.toc li li {margin-left: 1.5em; font-size:10px;} +div.wiki ul.toc a { + font-size: 0.9em; + font-weight: normal; + text-decoration: none; + color: #606060; +} +div.wiki ul.toc a:hover { color: #c61a1a; text-decoration: underline;} + +a.wiki-anchor { display: none; margin-left: 6px; text-decoration: none; } +a.wiki-anchor:hover { color: #aaa !important; text-decoration: none; } +h1:hover a.wiki-anchor, h2:hover a.wiki-anchor, h3:hover a.wiki-anchor { display: inline; color: #ddd; } + +div.wiki img { vertical-align: middle; } + +/***** My page layout *****/ +.block-receiver { + border:1px dashed #c0c0c0; + margin-bottom: 20px; + padding: 15px 0 15px 0; +} + +.mypage-box { + margin:0 0 20px 0; + color:#505050; + line-height:1.5em; +} + +.handle {cursor: move;} + +a.close-icon { + display:block; + margin-top:3px; + overflow:hidden; + width:12px; + height:12px; + background-repeat: no-repeat; + cursor:pointer; + background-image:url('../images/close.png'); +} +a.close-icon:hover {background-image:url('../images/close_hl.png');} + +/***** Gantt chart *****/ +.gantt_hdr { + position:absolute; + top:0; + height:16px; + border-top: 1px solid #c0c0c0; + border-bottom: 1px solid #c0c0c0; + border-right: 1px solid #c0c0c0; + text-align: center; + overflow: hidden; +} + +.gantt_hdr.nwday {background-color:#f1f1f1;} + +.gantt_subjects { font-size: 0.8em; } +.gantt_subjects div { line-height:16px;height:16px;overflow:hidden;white-space:nowrap;text-overflow: ellipsis; } + +.task { + position: absolute; + height:8px; + font-size:0.8em; + color:#888; + padding:0; + margin:0; + line-height:16px; + white-space:nowrap; +} + +.task.label {width:100%;} +.task.label.project, .task.label.version { font-weight: bold; } + +.task_late { background:#f66 url(../images/task_late.png); border: 1px solid #f66; } +.task_done { background:#00c600 url(../images/task_done.png); border: 1px solid #00c600; } +.task_todo { background:#aaa url(../images/task_todo.png); border: 1px solid #aaa; } + +.task_todo.parent { background: #888; border: 1px solid #888; height: 3px;} +.task_late.parent, .task_done.parent { height: 3px;} +.task.parent.marker.starting { position: absolute; background: url(../images/task_parent_end.png) no-repeat 0 0; width: 8px; height: 16px; margin-left: -4px; left: 0px; top: -1px;} +.task.parent.marker.ending { position: absolute; background: url(../images/task_parent_end.png) no-repeat 0 0; width: 8px; height: 16px; margin-left: -4px; right: 0px; top: -1px;} + +.version.task_late { background:#f66 url(../images/milestone_late.png); border: 1px solid #f66; height: 2px; margin-top: 3px;} +.version.task_done { background:#00c600 url(../images/milestone_done.png); border: 1px solid #00c600; height: 2px; margin-top: 3px;} +.version.task_todo { background:#fff url(../images/milestone_todo.png); border: 1px solid #fff; height: 2px; margin-top: 3px;} +.version.marker { background-image:url(../images/version_marker.png); background-repeat: no-repeat; border: 0; margin-left: -4px; margin-top: 1px; } + +.project.task_late { background:#f66 url(../images/milestone_late.png); border: 1px solid #f66; height: 2px; margin-top: 3px;} +.project.task_done { background:#00c600 url(../images/milestone_done.png); border: 1px solid #00c600; height: 2px; margin-top: 3px;} +.project.task_todo { background:#fff url(../images/milestone_todo.png); border: 1px solid #fff; height: 2px; margin-top: 3px;} +.project.marker { background-image:url(../images/project_marker.png); background-repeat: no-repeat; border: 0; margin-left: -4px; margin-top: 1px; } + +.version-behind-schedule a, .issue-behind-schedule a {color: #f66914;} +.version-overdue a, .issue-overdue a, .project-overdue a {color: #f00;} + +/***** Icons *****/ +.icon { + background-position: 0% 50%; + background-repeat: no-repeat; + padding-left: 20px; + padding-top: 2px; + padding-bottom: 3px; +} + +.icon-add { background-image: url(../images/add.png); } +.icon-edit { background-image: url(../images/edit.png); } +.icon-copy { background-image: url(../images/copy.png); } +.icon-duplicate { background-image: url(../images/duplicate.png); } +.icon-del { background-image: url(../images/delete.png); } +.icon-move { background-image: url(../images/move.png); } +.icon-save { background-image: url(../images/save.png); } +.icon-cancel { background-image: url(../images/cancel.png); } +.icon-multiple { background-image: url(../images/table_multiple.png); } +.icon-folder { background-image: url(../images/folder.png); } +.open .icon-folder { background-image: url(../images/folder_open.png); } +.icon-package { background-image: url(../images/package.png); } +.icon-user { background-image: url(../images/user.png); } +.icon-projects { background-image: url(../images/projects.png); } +.icon-help { background-image: url(../images/help.png); } +.icon-attachment { background-image: url(../images/attachment.png); } +.icon-history { background-image: url(../images/history.png); } +.icon-time { background-image: url(../images/time.png); } +.icon-time-add { background-image: url(../images/time_add.png); } +.icon-stats { background-image: url(../images/stats.png); } +.icon-warning { background-image: url(../images/warning.png); } +.icon-fav { background-image: url(../images/fav.png); } +.icon-fav-off { background-image: url(../images/fav_off.png); } +.icon-reload { background-image: url(../images/reload.png); } +.icon-lock { background-image: url(../images/locked.png); } +.icon-unlock { background-image: url(../images/unlock.png); } +.icon-checked { background-image: url(../images/true.png); } +.icon-details { background-image: url(../images/zoom_in.png); } +.icon-report { background-image: url(../images/report.png); } +.icon-comment { background-image: url(../images/comment.png); } +.icon-summary { background-image: url(../images/lightning.png); } +.icon-server-authentication { background-image: url(../images/server_key.png); } +.icon-issue { background-image: url(../images/ticket.png); } +.icon-zoom-in { background-image: url(../images/zoom_in.png); } +.icon-zoom-out { background-image: url(../images/zoom_out.png); } +.icon-passwd { background-image: url(../images/textfield_key.png); } +.icon-test { background-image: url(../images/bullet_go.png); } + +.icon-file { background-image: url(../images/files/default.png); } +.icon-file.text-plain { background-image: url(../images/files/text.png); } +.icon-file.text-x-c { background-image: url(../images/files/c.png); } +.icon-file.text-x-csharp { background-image: url(../images/files/csharp.png); } +.icon-file.text-x-java { background-image: url(../images/files/java.png); } +.icon-file.text-x-javascript { background-image: url(../images/files/js.png); } +.icon-file.text-x-php { background-image: url(../images/files/php.png); } +.icon-file.text-x-ruby { background-image: url(../images/files/ruby.png); } +.icon-file.text-xml { background-image: url(../images/files/xml.png); } +.icon-file.text-css { background-image: url(../images/files/css.png); } +.icon-file.text-html { background-image: url(../images/files/html.png); } +.icon-file.image-gif { background-image: url(../images/files/image.png); } +.icon-file.image-jpeg { background-image: url(../images/files/image.png); } +.icon-file.image-png { background-image: url(../images/files/image.png); } +.icon-file.image-tiff { background-image: url(../images/files/image.png); } +.icon-file.application-pdf { background-image: url(../images/files/pdf.png); } +.icon-file.application-zip { background-image: url(../images/files/zip.png); } +.icon-file.application-x-gzip { background-image: url(../images/files/zip.png); } + +img.gravatar { + padding: 2px; + border: solid 1px #d5d5d5; + background: #fff; + vertical-align: middle; +} + +div.issue img.gravatar { + float: left; + margin: 0 6px 0 0; + padding: 5px; +} + +div.issue table img.gravatar { + height: 14px; + width: 14px; + padding: 2px; + float: left; + margin: 0 0.5em 0 0; +} + +h2 img.gravatar {margin: -2px 4px -4px 0;} +h3 img.gravatar {margin: -4px 4px -4px 0;} +h4 img.gravatar {margin: -6px 4px -4px 0;} +td.username img.gravatar {margin: 0 0.5em 0 0; vertical-align: top;} +#activity dt img.gravatar {float: left; margin: 0 1em 1em 0;} +/* Used on 12px Gravatar img tags without the icon background */ +.icon-gravatar {float: left; margin-right: 4px;} + +#activity dt, .journal {clear: left;} + +.journal-link {float: right;} + +h2 img { vertical-align:middle; } + +.hascontextmenu { cursor: context-menu; } + +/************* CodeRay styles *************/ +.syntaxhl div {display: inline;} +.syntaxhl .line-numbers {padding: 2px 4px 2px 4px; background-color: #eee; margin:0px 5px 0px 0px;} +.syntaxhl .code pre { overflow: auto } +.syntaxhl .debug { color: white !important; background: blue !important; } + +.syntaxhl .annotation { color:#007 } +.syntaxhl .attribute-name { color:#b48 } +.syntaxhl .attribute-value { color:#700 } +.syntaxhl .binary { color:#509 } +.syntaxhl .char .content { color:#D20 } +.syntaxhl .char .delimiter { color:#710 } +.syntaxhl .char { color:#D20 } +.syntaxhl .class { color:#258; font-weight:bold } +.syntaxhl .class-variable { color:#369 } +.syntaxhl .color { color:#0A0 } +.syntaxhl .comment { color:#385 } +.syntaxhl .comment .char { color:#385 } +.syntaxhl .comment .delimiter { color:#385 } +.syntaxhl .complex { color:#A08 } +.syntaxhl .constant { color:#258; font-weight:bold } +.syntaxhl .decorator { color:#B0B } +.syntaxhl .definition { color:#099; font-weight:bold } +.syntaxhl .delimiter { color:black } +.syntaxhl .directive { color:#088; font-weight:bold } +.syntaxhl .doc { color:#970 } +.syntaxhl .doc-string { color:#D42; font-weight:bold } +.syntaxhl .doctype { color:#34b } +.syntaxhl .entity { color:#800; font-weight:bold } +.syntaxhl .error { color:#F00; background-color:#FAA } +.syntaxhl .escape { color:#666 } +.syntaxhl .exception { color:#C00; font-weight:bold } +.syntaxhl .float { color:#06D } +.syntaxhl .function { color:#06B; font-weight:bold } +.syntaxhl .global-variable { color:#d70 } +.syntaxhl .hex { color:#02b } +.syntaxhl .imaginary { color:#f00 } +.syntaxhl .include { color:#B44; font-weight:bold } +.syntaxhl .inline { background-color: hsla(0,0%,0%,0.07); color: black } +.syntaxhl .inline-delimiter { font-weight: bold; color: #666 } +.syntaxhl .instance-variable { color:#33B } +.syntaxhl .integer { color:#06D } +.syntaxhl .key .char { color: #60f } +.syntaxhl .key .delimiter { color: #404 } +.syntaxhl .key { color: #606 } +.syntaxhl .keyword { color:#939; font-weight:bold } +.syntaxhl .label { color:#970; font-weight:bold } +.syntaxhl .local-variable { color:#963 } +.syntaxhl .namespace { color:#707; font-weight:bold } +.syntaxhl .octal { color:#40E } +.syntaxhl .operator { } +.syntaxhl .predefined { color:#369; font-weight:bold } +.syntaxhl .predefined-constant { color:#069 } +.syntaxhl .predefined-type { color:#0a5; font-weight:bold } +.syntaxhl .preprocessor { color:#579 } +.syntaxhl .pseudo-class { color:#00C; font-weight:bold } +.syntaxhl .regexp .content { color:#808 } +.syntaxhl .regexp .delimiter { color:#404 } +.syntaxhl .regexp .modifier { color:#C2C } +.syntaxhl .regexp { background-color:hsla(300,100%,50%,0.06); } +.syntaxhl .reserved { color:#080; font-weight:bold } +.syntaxhl .shell .content { color:#2B2 } +.syntaxhl .shell .delimiter { color:#161 } +.syntaxhl .shell { background-color:hsla(120,100%,50%,0.06); } +.syntaxhl .string .char { color: #46a } +.syntaxhl .string .content { color: #46a } +.syntaxhl .string .delimiter { color: #46a } +.syntaxhl .string .modifier { color: #46a } +.syntaxhl .symbol .content { color:#d33 } +.syntaxhl .symbol .delimiter { color:#d33 } +.syntaxhl .symbol { color:#d33 } +.syntaxhl .tag { color:#070 } +.syntaxhl .type { color:#339; font-weight:bold } +.syntaxhl .value { color: #088; } +.syntaxhl .variable { color:#037 } + +.syntaxhl .insert { background: hsla(120,100%,50%,0.12) } +.syntaxhl .delete { background: hsla(0,100%,50%,0.12) } +.syntaxhl .change { color: #bbf; background: #007; } +.syntaxhl .head { color: #f8f; background: #505 } +.syntaxhl .head .filename { color: white; } + +.syntaxhl .delete .eyecatcher { background-color: hsla(0,100%,50%,0.2); border: 1px solid hsla(0,100%,45%,0.5); margin: -1px; border-bottom: none; border-top-left-radius: 5px; border-top-right-radius: 5px; } +.syntaxhl .insert .eyecatcher { background-color: hsla(120,100%,50%,0.2); border: 1px solid hsla(120,100%,25%,0.5); margin: -1px; border-top: none; border-bottom-left-radius: 5px; border-bottom-right-radius: 5px; } + +.syntaxhl .insert .insert { color: #0c0; background:transparent; font-weight:bold } +.syntaxhl .delete .delete { color: #c00; background:transparent; font-weight:bold } +.syntaxhl .change .change { color: #88f } +.syntaxhl .head .head { color: #f4f } + +/***** Media print specific styles *****/ +@media print { + #top-menu, #header, #main-menu, #sidebar, #footer, .contextual, .other-formats { display:none; } + #main { background: #fff; } + #content { width: 99%; margin: 0; padding: 0; border: 0; background: #fff; overflow: visible !important;} + #wiki_add_attachment { display:none; } + .hide-when-print { display: none; } + .autoscroll {overflow-x: visible;} + table.list {margin-top:0.5em;} + table.list th, table.list td {border: 1px solid #aaa;} +} + +/* Accessibility specific styles */ +.hidden-for-sighted { + position:absolute; + left:-10000px; + top:auto; + width:1px; + height:1px; + overflow:hidden; +} diff --git a/public/dispatch.fcgi.example b/public/dispatch.fcgi.example new file mode 100644 index 00000000..85184c44 --- /dev/null +++ b/public/dispatch.fcgi.example @@ -0,0 +1,20 @@ +#!/usr/bin/env ruby + +require File.dirname(__FILE__) + '/../config/boot' +require File.dirname(__FILE__) + '/../config/environment' + +class Rack::PathInfoRewriter + def initialize(app) + @app = app + end + + def call(env) + env.delete('SCRIPT_NAME') + parts = env['REQUEST_URI'].split('?') + env['PATH_INFO'] = parts[0] + env['QUERY_STRING'] = parts[1].to_s + @app.call(env) + end +end + +Rack::Handler::FastCGI.run Rack::PathInfoRewriter.new(RedmineApp::Application) diff --git a/public/favicon.ico b/public/favicon.ico new file mode 100644 index 00000000..75a4c3df Binary files /dev/null and b/public/favicon.ico differ diff --git a/public/favicon.old.ico b/public/favicon.old.ico new file mode 100644 index 00000000..51c1aeb0 Binary files /dev/null and b/public/favicon.old.ico differ diff --git a/public/help/wiki_syntax.html b/public/help/wiki_syntax.html new file mode 100644 index 00000000..a92720b4 --- /dev/null +++ b/public/help/wiki_syntax.html @@ -0,0 +1,66 @@ + + + + + +Wiki formatting + + + + +

      Wiki Syntax Quick Reference

      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      Font Styles
      Strong*Strong*Strong
      Italic_Italic_Italic
      Underline+Underline+Underline
      Deleted-Deleted-Deleted
      ??Quote??Quote
      Inline Code@Inline Code@Inline Code
      Preformatted text<pre>
       lines
       of code
      </pre>
      +
      + lines
      + of code
      +
      +
      Lists
      Unordered list* Item 1
      * Item 2
      • Item 1
      • Item 2
      Ordered list# Item 1
      # Item 2
      1. Item 1
      2. Item 2
      Headings
      Heading 1h1. Title 1

      Title 1

      Heading 2h2. Title 2

      Title 2

      Heading 3h3. Title 3

      Title 3

      Links
      http://foo.barhttp://foo.bar
      "Foo":http://foo.barFoo
      Redmine links
      Link to a Wiki page[[Wiki page]]Wiki page
      Issue #12Issue #12
      Revision r43Revision r43
      commit:f30e13e43f30e13e4
      source:some/filesource:some/file
      Inline images
      Image!image_url!
      !attached_image!
      + +

      More Information

      + + + diff --git a/public/help/wiki_syntax_detailed.html b/public/help/wiki_syntax_detailed.html new file mode 100644 index 00000000..0398e4fa --- /dev/null +++ b/public/help/wiki_syntax_detailed.html @@ -0,0 +1,281 @@ + + + +RedmineWikiFormatting + + + + + +

      Wiki formatting

      + +

      Links

      + +

      Redmine links

      + +

      Redmine allows hyperlinking between resources (issues, changesets, wiki pages...) from anywhere wiki formatting is used.

      +
        +
      • Link to an issue: #124 (displays #124, link is striked-through if the issue is closed)
      • +
      • Link to an issue note: #124-6, or #124#note-6
      • +
      + +

      Wiki links:

      + +
        +
      • [[Guide]] displays a link to the page named 'Guide': Guide
      • +
      • [[Guide#further-reading]] takes you to the anchor "further-reading". Headings get automatically assigned anchors so that you can refer to them: Guide
      • +
      • [[Guide|User manual]] displays a link to the same page but with a different text: User manual
      • +
      + +

      You can also link to pages of an other project wiki:

      + +
        +
      • [[sandbox:some page]] displays a link to the page named 'Some page' of the Sandbox wiki
      • +
      • [[sandbox:]] displays a link to the Sandbox wiki main page
      • +
      + +

      Wiki links are displayed in red if the page doesn't exist yet, eg: Nonexistent page.

      + +

      Links to other resources:

      + +
        +
      • Documents: +
          +
        • document#17 (link to document with id 17)
        • +
        • document:Greetings (link to the document with title "Greetings")
        • +
        • document:"Some document" (double quotes can be used when document title contains spaces)
        • +
        • sandbox:document:"Some document" (link to a document with title "Some document" in other project "sandbox")
        • +
      • +
      + +
        +
      • Versions: +
          +
        • version#3 (link to version with id 3)
        • +
        • version:1.0.0 (link to version named "1.0.0")
        • +
        • version:"1.0 beta 2"
        • +
        • sandbox:version:1.0.0 (link to version "1.0.0" in the project "sandbox")
        • +
      • +
      + +
        +
      • Attachments: +
          +
        • attachment:file.zip (link to the attachment of the current object named file.zip)
        • +
        • For now, attachments of the current object can be referenced only (if you're on an issue, it's possible to reference attachments of this issue only)
        • +
      • +
      + +
        +
      • Changesets: +
          +
        • r758 (link to a changeset)
        • +
        • commit:c6f4d0fd (link to a changeset with a non-numeric hash)
        • +
        • svn1|r758 (link to a changeset of a specific repository, for projects with multiple repositories)
        • +
        • commit:hg|c6f4d0fd (link to a changeset with a non-numeric hash of a specific repository)
        • +
        • sandbox:r758 (link to a changeset of another project)
        • +
        • sandbox:commit:c6f4d0fd (link to a changeset with a non-numeric hash of another project)
        • +
      • +
      + +
        +
      • Repository files: +
          +
        • source:some/file (link to the file located at /some/file in the project's repository)
        • +
        • source:some/file@52 (link to the file's revision 52)
        • +
        • source:some/file#L120 (link to line 120 of the file)
        • +
        • source:some/file@52#L120 (link to line 120 of the file's revision 52)
        • +
        • source:"some file@52#L120" (use double quotes when the URL contains spaces
        • +
        • export:some/file (force the download of the file)
        • +
        • source:svn1|some/file (link to a file of a specific repository, for projects with multiple repositories)
        • +
        • sandbox:source:some/file (link to the file located at /some/file in the repository of the project "sandbox")
        • +
        • sandbox:export:some/file (force the download of the file)
        • +
      • +
      + +
        +
      • Forum messages: +
          +
        • message#1218 (link to message with id 1218)
        • +
      • +
      + +
        +
      • Projects: +
          +
        • project#3 (link to project with id 3)
        • +
        • project:someproject (link to project named "someproject")
        • +
      • +
      + + +

      Escaping:

      + +
        +
      • You can prevent Redmine links from being parsed by preceding them with an exclamation mark: !
      • +
      + + +

      External links

      + +

      HTTP URLs and email addresses are automatically turned into clickable links:

      + +
      +http://www.redmine.org, someone@foo.bar
      +
      + +

      displays: http://www.redmine.org,

      + +

      If you want to display a specific text instead of the URL, you can use the standard textile syntax:

      + +
      +"Redmine web site":http://www.redmine.org
      +
      + +

      displays: Redmine web site

      + + +

      Text formatting

      + + +

      For things such as headlines, bold, tables, lists, Redmine supports Textile syntax. See http://en.wikipedia.org/wiki/Textile_(markup_language) for information on using any of these features. A few samples are included below, but the engine is capable of much more of that.

      + +

      Font style

      + +
      +* *bold*
      +* _italic_
      +* _*bold italic*_
      +* +underline+
      +* -strike-through-
      +
      + +

      Display:

      + +
        +
      • bold
      • +
      • italic
      • +
      • *bold italic*
      • +
      • underline
      • +
      • strike-through
      • +
      + +

      Inline images

      + +
        +
      • !image_url! displays an image located at image_url (textile syntax)
      • +
      • !>image_url! right floating image
      • +
      • If you have an image attached to your wiki page, it can be displayed inline using its filename: !attached_image.png!
      • +
      + +

      Headings

      + +
      +h1. Heading
      +h2. Subheading
      +h3. Subsubheading
      +
      + +

      Redmine assigns an anchor to each of those headings thus you can link to them with "#Heading", "#Subheading" and so forth.

      + + +

      Paragraphs

      + +
      +p>. right aligned
      +p=. centered
      +
      + +

      This is a centered paragraph.

      + + +

      Blockquotes

      + +

      Start the paragraph with bq.

      + +
      +bq. Rails is a full-stack framework for developing database-backed web applications according to the Model-View-Control pattern.
      +To go live, all you need to add is a database and a web server.
      +
      + +

      Display:

      + +
      +

      Rails is a full-stack framework for developing database-backed web applications according to the Model-View-Control pattern.
      To go live, all you need to add is a database and a web server.

      +
      + + +

      Table of content

      + +
      +{{toc}} => left aligned toc
      +{{>toc}} => right aligned toc
      +
      + +

      Macros

      + +

      Redmine has the following builtin macros:

      + +

      hello_world

      Sample macro.

      include

      Include a wiki page. Example:

      + +
      {{include(Foo)}}
      macro_list

      Displays a list of all available macros, including description if available.

      + + +

      Code highlighting

      + +

      Default code highlightment relies on CodeRay, a fast syntax highlighting library written completely in Ruby. It currently supports c, cpp, css, delphi, groovy, html, java, javascript, json, php, python, rhtml, ruby, scheme, sql, xml and yaml languages.

      + +

      You can highlight code in your wiki page using this syntax:

      + +
      +<pre><code class="ruby">
      +  Place you code here.
      +</code></pre>
      +
      + +

      Example:

      + +
       1 # The Greeter class
      + 2 class Greeter
      + 3   def initialize(name)
      + 4     @name = name.capitalize
      + 5   end
      + 6 
      + 7   def salute
      + 8     puts "Hello #{@name}!" 
      + 9   end
      +10 end
      +
      + + diff --git a/public/htaccess.fcgi.example b/public/htaccess.fcgi.example new file mode 100644 index 00000000..f06975d4 --- /dev/null +++ b/public/htaccess.fcgi.example @@ -0,0 +1,49 @@ +# General Apache options + + AddHandler fastcgi-script .fcgi + + + AddHandler fcgid-script .fcgi + +Options +FollowSymLinks +ExecCGI + +# If you don't want Rails to look in certain directories, +# use the following rewrite rules so that Apache won't rewrite certain requests +# +# Example: +# RewriteCond %{REQUEST_URI} ^/notrails.* +# RewriteRule .* - [L] + +# Redirect all requests not available on the filesystem to Rails +# By default the cgi dispatcher is used which is very slow +# +# For better performance replace the dispatcher with the fastcgi one +# +# Example: +# RewriteRule ^(.*)$ dispatch.fcgi [QSA,L] +RewriteEngine On + +# If your Rails application is accessed via an Alias directive, +# then you MUST also set the RewriteBase in this htaccess file. +# +# Example: +# Alias /myrailsapp /path/to/myrailsapp/public +# RewriteBase /myrailsapp + +RewriteRule ^$ index.html [QSA] +RewriteRule ^([^.]+)$ $1.html [QSA] +RewriteCond %{REQUEST_FILENAME} !-f + + RewriteRule ^(.*)$ dispatch.fcgi [QSA,L] + + + RewriteRule ^(.*)$ dispatch.fcgi [QSA,L] + + +# In case Rails experiences terminal errors +# Instead of displaying this message you can supply a file here which will be rendered instead +# +# Example: +# ErrorDocument 500 /500.html + +ErrorDocument 500 "

      Application error

      Rails application failed to start properly" diff --git a/public/images/115960_50.jpg b/public/images/115960_50.jpg new file mode 100644 index 00000000..aa45853f Binary files /dev/null and b/public/images/115960_50.jpg differ diff --git a/public/images/121944_50.jpg b/public/images/121944_50.jpg new file mode 100644 index 00000000..26e7db3e Binary files /dev/null and b/public/images/121944_50.jpg differ diff --git a/public/images/12_50.png b/public/images/12_50.png new file mode 100644 index 00000000..af618c69 Binary files /dev/null and b/public/images/12_50.png differ diff --git a/public/images/1downarrow.png b/public/images/1downarrow.png new file mode 100644 index 00000000..a6d07e92 Binary files /dev/null and b/public/images/1downarrow.png differ diff --git a/public/images/1uparrow.png b/public/images/1uparrow.png new file mode 100644 index 00000000..6c0eae46 Binary files /dev/null and b/public/images/1uparrow.png differ diff --git a/public/images/233683_50.jpg b/public/images/233683_50.jpg new file mode 100644 index 00000000..65ef363c Binary files /dev/null and b/public/images/233683_50.jpg differ diff --git a/public/images/28_50.jpg b/public/images/28_50.jpg new file mode 100644 index 00000000..0d2f45b6 Binary files /dev/null and b/public/images/28_50.jpg differ diff --git a/public/images/2downarrow.png b/public/images/2downarrow.png new file mode 100644 index 00000000..17965168 Binary files /dev/null and b/public/images/2downarrow.png differ diff --git a/public/images/2uparrow.png b/public/images/2uparrow.png new file mode 100644 index 00000000..352cc2bb Binary files /dev/null and b/public/images/2uparrow.png differ diff --git a/public/images/47318_50.jpg b/public/images/47318_50.jpg new file mode 100644 index 00000000..e825b194 Binary files /dev/null and b/public/images/47318_50.jpg differ diff --git a/public/images/737521_50.jpg b/public/images/737521_50.jpg new file mode 100644 index 00000000..68a02e4a Binary files /dev/null and b/public/images/737521_50.jpg differ diff --git a/public/images/860270_50.jpg b/public/images/860270_50.jpg new file mode 100644 index 00000000..beea1490 Binary files /dev/null and b/public/images/860270_50.jpg differ diff --git a/public/images/926055_50.jpg b/public/images/926055_50.jpg new file mode 100644 index 00000000..90e0e847 Binary files /dev/null and b/public/images/926055_50.jpg differ diff --git a/public/images/add.png b/public/images/add.png new file mode 100644 index 00000000..d6d26db7 Binary files /dev/null and b/public/images/add.png differ diff --git a/public/images/arrow_collapsed.png b/public/images/arrow_collapsed.png new file mode 100644 index 00000000..cbcc70de Binary files /dev/null and b/public/images/arrow_collapsed.png differ diff --git a/public/images/arrow_down.png b/public/images/arrow_down.png new file mode 100644 index 00000000..7a2a1a35 Binary files /dev/null and b/public/images/arrow_down.png differ diff --git a/public/images/arrow_expanded.png b/public/images/arrow_expanded.png new file mode 100644 index 00000000..7b1c563b Binary files /dev/null and b/public/images/arrow_expanded.png differ diff --git a/public/images/attachment.png b/public/images/attachment.png new file mode 100644 index 00000000..3762eafe Binary files /dev/null and b/public/images/attachment.png differ diff --git a/public/images/avatars/AnonymousUser/0 b/public/images/avatars/AnonymousUser/0 new file mode 100644 index 00000000..26e7db3e Binary files /dev/null and b/public/images/avatars/AnonymousUser/0 differ diff --git a/public/images/avatars/Project/0 b/public/images/avatars/Project/0 new file mode 100644 index 00000000..beea1490 Binary files /dev/null and b/public/images/avatars/Project/0 differ diff --git a/public/images/avatars/Project/6314 b/public/images/avatars/Project/6314 new file mode 100644 index 00000000..6c099118 Binary files /dev/null and b/public/images/avatars/Project/6314 differ diff --git a/public/images/avatars/User/0 b/public/images/avatars/User/0 new file mode 100644 index 00000000..26e7db3e Binary files /dev/null and b/public/images/avatars/User/0 differ diff --git a/public/images/avatars/User/1 b/public/images/avatars/User/1 new file mode 100644 index 00000000..fa4fd411 Binary files /dev/null and b/public/images/avatars/User/1 differ diff --git a/public/images/avatars/User/4245 b/public/images/avatars/User/4245 new file mode 100644 index 00000000..8057fac1 Binary files /dev/null and b/public/images/avatars/User/4245 differ diff --git a/public/images/avatars/User/4246 b/public/images/avatars/User/4246 new file mode 100644 index 00000000..65ef363c Binary files /dev/null and b/public/images/avatars/User/4246 differ diff --git a/public/images/avatars/User/4247 b/public/images/avatars/User/4247 new file mode 100644 index 00000000..3df1c4e6 Binary files /dev/null and b/public/images/avatars/User/4247 differ diff --git a/public/images/avatars/User/4249 b/public/images/avatars/User/4249 new file mode 100644 index 00000000..93600eb8 Binary files /dev/null and b/public/images/avatars/User/4249 differ diff --git a/public/images/avatars/User/4275 b/public/images/avatars/User/4275 new file mode 100644 index 00000000..2659a14b Binary files /dev/null and b/public/images/avatars/User/4275 differ diff --git a/public/images/avatars/User/4288 b/public/images/avatars/User/4288 new file mode 100644 index 00000000..ca17e532 Binary files /dev/null and b/public/images/avatars/User/4288 differ diff --git a/public/images/avatars/User/4856 b/public/images/avatars/User/4856 new file mode 100644 index 00000000..96d1098f Binary files /dev/null and b/public/images/avatars/User/4856 differ diff --git a/public/images/avatars/User/4858 b/public/images/avatars/User/4858 new file mode 100644 index 00000000..8df8790b Binary files /dev/null and b/public/images/avatars/User/4858 differ diff --git a/public/images/avatars/User/4859 b/public/images/avatars/User/4859 new file mode 100644 index 00000000..2659a14b Binary files /dev/null and b/public/images/avatars/User/4859 differ diff --git a/public/images/avatars/User/4861 b/public/images/avatars/User/4861 new file mode 100644 index 00000000..0b88c913 Binary files /dev/null and b/public/images/avatars/User/4861 differ diff --git a/public/images/avatars/User/4863 b/public/images/avatars/User/4863 new file mode 100644 index 00000000..26e7db3e Binary files /dev/null and b/public/images/avatars/User/4863 differ diff --git a/public/images/bullet_add.png b/public/images/bullet_add.png new file mode 100644 index 00000000..a3f850dc Binary files /dev/null and b/public/images/bullet_add.png differ diff --git a/public/images/bullet_arrow_left.png b/public/images/bullet_arrow_left.png new file mode 100644 index 00000000..cabc1d79 Binary files /dev/null and b/public/images/bullet_arrow_left.png differ diff --git a/public/images/bullet_arrow_right.png b/public/images/bullet_arrow_right.png new file mode 100644 index 00000000..cbcc70de Binary files /dev/null and b/public/images/bullet_arrow_right.png differ diff --git a/public/images/bullet_black.png b/public/images/bullet_black.png new file mode 100644 index 00000000..6d87f99a Binary files /dev/null and b/public/images/bullet_black.png differ diff --git a/public/images/bullet_blue.png b/public/images/bullet_blue.png new file mode 100644 index 00000000..79d978c3 Binary files /dev/null and b/public/images/bullet_blue.png differ diff --git a/public/images/bullet_delete.png b/public/images/bullet_delete.png new file mode 100644 index 00000000..3459293c Binary files /dev/null and b/public/images/bullet_delete.png differ diff --git a/public/images/bullet_diamond.png b/public/images/bullet_diamond.png new file mode 100644 index 00000000..f68cb795 Binary files /dev/null and b/public/images/bullet_diamond.png differ diff --git a/public/images/bullet_end.png b/public/images/bullet_end.png new file mode 100644 index 00000000..0ff03323 Binary files /dev/null and b/public/images/bullet_end.png differ diff --git a/public/images/bullet_go.png b/public/images/bullet_go.png new file mode 100644 index 00000000..c724754b Binary files /dev/null and b/public/images/bullet_go.png differ diff --git a/public/images/bullet_orange.png b/public/images/bullet_orange.png new file mode 100644 index 00000000..d4b3cd05 Binary files /dev/null and b/public/images/bullet_orange.png differ diff --git a/public/images/bullet_purple.png b/public/images/bullet_purple.png new file mode 100644 index 00000000..58bc636b Binary files /dev/null and b/public/images/bullet_purple.png differ diff --git a/public/images/bullet_toggle_minus.png b/public/images/bullet_toggle_minus.png new file mode 100644 index 00000000..656fc9ce Binary files /dev/null and b/public/images/bullet_toggle_minus.png differ diff --git a/public/images/bullet_toggle_plus.png b/public/images/bullet_toggle_plus.png new file mode 100644 index 00000000..bbd81a90 Binary files /dev/null and b/public/images/bullet_toggle_plus.png differ diff --git a/public/images/calendar.png b/public/images/calendar.png new file mode 100644 index 00000000..62df31c9 Binary files /dev/null and b/public/images/calendar.png differ diff --git a/public/images/cancel.png b/public/images/cancel.png new file mode 100644 index 00000000..a98e5370 Binary files /dev/null and b/public/images/cancel.png differ diff --git a/public/images/changeset.png b/public/images/changeset.png new file mode 100644 index 00000000..8bf76fbb Binary files /dev/null and b/public/images/changeset.png differ diff --git a/public/images/close.png b/public/images/close.png new file mode 100644 index 00000000..3dd76e69 Binary files /dev/null and b/public/images/close.png differ diff --git a/public/images/close_hl.png b/public/images/close_hl.png new file mode 100644 index 00000000..b7667aa8 Binary files /dev/null and b/public/images/close_hl.png differ diff --git a/public/images/comment.png b/public/images/comment.png new file mode 100644 index 00000000..0e848cc0 Binary files /dev/null and b/public/images/comment.png differ diff --git a/public/images/comments.png b/public/images/comments.png new file mode 100644 index 00000000..ef57fdd1 Binary files /dev/null and b/public/images/comments.png differ diff --git a/public/images/copy.png b/public/images/copy.png new file mode 100644 index 00000000..689f251c Binary files /dev/null and b/public/images/copy.png differ diff --git a/public/images/database_key.png b/public/images/database_key.png new file mode 100644 index 00000000..107e34e5 Binary files /dev/null and b/public/images/database_key.png differ diff --git a/public/images/delete.png b/public/images/delete.png new file mode 100644 index 00000000..ba6256dd Binary files /dev/null and b/public/images/delete.png differ diff --git a/public/images/document.png b/public/images/document.png new file mode 100644 index 00000000..eb22f4c0 Binary files /dev/null and b/public/images/document.png differ diff --git a/public/images/draft.png b/public/images/draft.png new file mode 100644 index 00000000..b51b07b3 Binary files /dev/null and b/public/images/draft.png differ diff --git a/public/images/duplicate.png b/public/images/duplicate.png new file mode 100644 index 00000000..f7d159e5 Binary files /dev/null and b/public/images/duplicate.png differ diff --git a/public/images/edit.png b/public/images/edit.png new file mode 100644 index 00000000..8335716f Binary files /dev/null and b/public/images/edit.png differ diff --git a/public/images/exclamation.png b/public/images/exclamation.png new file mode 100644 index 00000000..7bd84f7a Binary files /dev/null and b/public/images/exclamation.png differ diff --git a/public/images/external.png b/public/images/external.png new file mode 100644 index 00000000..77c20289 Binary files /dev/null and b/public/images/external.png differ diff --git a/public/images/false.png b/public/images/false.png new file mode 100644 index 00000000..ec01ecd3 Binary files /dev/null and b/public/images/false.png differ diff --git a/public/images/fav.png b/public/images/fav.png new file mode 100644 index 00000000..eb43df93 Binary files /dev/null and b/public/images/fav.png differ diff --git a/public/images/fav_off.png b/public/images/fav_off.png new file mode 100644 index 00000000..51372e3f Binary files /dev/null and b/public/images/fav_off.png differ diff --git a/public/images/feed.png b/public/images/feed.png new file mode 100644 index 00000000..23160c34 Binary files /dev/null and b/public/images/feed.png differ diff --git a/public/images/files/c.png b/public/images/files/c.png new file mode 100644 index 00000000..0dff8cfd Binary files /dev/null and b/public/images/files/c.png differ diff --git a/public/images/files/csharp.png b/public/images/files/csharp.png new file mode 100644 index 00000000..093b1c5e Binary files /dev/null and b/public/images/files/csharp.png differ diff --git a/public/images/files/css.png b/public/images/files/css.png new file mode 100644 index 00000000..06a17cd8 Binary files /dev/null and b/public/images/files/css.png differ diff --git a/public/images/files/default.png b/public/images/files/default.png new file mode 100644 index 00000000..22996cd9 Binary files /dev/null and b/public/images/files/default.png differ diff --git a/public/images/files/html.png b/public/images/files/html.png new file mode 100644 index 00000000..6ed2490e Binary files /dev/null and b/public/images/files/html.png differ diff --git a/public/images/files/image.png b/public/images/files/image.png new file mode 100644 index 00000000..8954d2a5 Binary files /dev/null and b/public/images/files/image.png differ diff --git a/public/images/files/java.png b/public/images/files/java.png new file mode 100644 index 00000000..0a7d6f4a Binary files /dev/null and b/public/images/files/java.png differ diff --git a/public/images/files/js.png b/public/images/files/js.png new file mode 100644 index 00000000..0125edfa Binary files /dev/null and b/public/images/files/js.png differ diff --git a/public/images/files/pdf.png b/public/images/files/pdf.png new file mode 100644 index 00000000..544e0d87 Binary files /dev/null and b/public/images/files/pdf.png differ diff --git a/public/images/files/php.png b/public/images/files/php.png new file mode 100644 index 00000000..26f2e4d7 Binary files /dev/null and b/public/images/files/php.png differ diff --git a/public/images/files/ruby.png b/public/images/files/ruby.png new file mode 100644 index 00000000..95fb3afe Binary files /dev/null and b/public/images/files/ruby.png differ diff --git a/public/images/files/text.png b/public/images/files/text.png new file mode 100644 index 00000000..b880900b Binary files /dev/null and b/public/images/files/text.png differ diff --git a/public/images/files/xml.png b/public/images/files/xml.png new file mode 100644 index 00000000..b1b61b5f Binary files /dev/null and b/public/images/files/xml.png differ diff --git a/public/images/files/zip.png b/public/images/files/zip.png new file mode 100644 index 00000000..914fcc40 Binary files /dev/null and b/public/images/files/zip.png differ diff --git a/public/images/folder.png b/public/images/folder.png new file mode 100644 index 00000000..e20d6823 Binary files /dev/null and b/public/images/folder.png differ diff --git a/public/images/folder_open.png b/public/images/folder_open.png new file mode 100644 index 00000000..9d1e90d2 Binary files /dev/null and b/public/images/folder_open.png differ diff --git a/public/images/folder_open_add.png b/public/images/folder_open_add.png new file mode 100644 index 00000000..6fe9e032 Binary files /dev/null and b/public/images/folder_open_add.png differ diff --git a/public/images/folder_open_orange.png b/public/images/folder_open_orange.png new file mode 100644 index 00000000..ee6504a9 Binary files /dev/null and b/public/images/folder_open_orange.png differ diff --git a/public/images/group.png b/public/images/group.png new file mode 100644 index 00000000..d80eb260 Binary files /dev/null and b/public/images/group.png differ diff --git a/public/images/help.png b/public/images/help.png new file mode 100644 index 00000000..d533abd3 Binary files /dev/null and b/public/images/help.png differ diff --git a/public/images/history.png b/public/images/history.png new file mode 100644 index 00000000..4f2c1284 Binary files /dev/null and b/public/images/history.png differ diff --git a/public/images/home_images/2.png b/public/images/home_images/2.png new file mode 100644 index 00000000..49b71cff Binary files /dev/null and b/public/images/home_images/2.png differ diff --git a/public/images/home_images/3.png b/public/images/home_images/3.png new file mode 100644 index 00000000..21a2df64 Binary files /dev/null and b/public/images/home_images/3.png differ diff --git a/public/images/home_images/BackGround.gif b/public/images/home_images/BackGround.gif new file mode 100644 index 00000000..90d70b4b Binary files /dev/null and b/public/images/home_images/BackGround.gif differ diff --git a/public/images/home_images/logo1.png b/public/images/home_images/logo1.png new file mode 100644 index 00000000..57ff0ccf Binary files /dev/null and b/public/images/home_images/logo1.png differ diff --git a/public/images/home_new.png b/public/images/home_new.png new file mode 100644 index 00000000..57ff0ccf Binary files /dev/null and b/public/images/home_new.png differ diff --git a/public/images/home_project.png b/public/images/home_project.png new file mode 100644 index 00000000..21a2df64 Binary files /dev/null and b/public/images/home_project.png differ diff --git a/public/images/home_req.png b/public/images/home_req.png new file mode 100644 index 00000000..49b71cff Binary files /dev/null and b/public/images/home_req.png differ diff --git a/public/images/hourglass.png b/public/images/hourglass.png new file mode 100644 index 00000000..57b03ce7 Binary files /dev/null and b/public/images/hourglass.png differ diff --git a/public/images/jstoolbar/bt_bq.png b/public/images/jstoolbar/bt_bq.png new file mode 100644 index 00000000..d5617950 Binary files /dev/null and b/public/images/jstoolbar/bt_bq.png differ diff --git a/public/images/jstoolbar/bt_bq_remove.png b/public/images/jstoolbar/bt_bq_remove.png new file mode 100644 index 00000000..467957fd Binary files /dev/null and b/public/images/jstoolbar/bt_bq_remove.png differ diff --git a/public/images/jstoolbar/bt_code.png b/public/images/jstoolbar/bt_code.png new file mode 100644 index 00000000..0a6e1165 Binary files /dev/null and b/public/images/jstoolbar/bt_code.png differ diff --git a/public/images/jstoolbar/bt_del.png b/public/images/jstoolbar/bt_del.png new file mode 100644 index 00000000..16bf5fad Binary files /dev/null and b/public/images/jstoolbar/bt_del.png differ diff --git a/public/images/jstoolbar/bt_em.png b/public/images/jstoolbar/bt_em.png new file mode 100644 index 00000000..741c3bf5 Binary files /dev/null and b/public/images/jstoolbar/bt_em.png differ diff --git a/public/images/jstoolbar/bt_h1.png b/public/images/jstoolbar/bt_h1.png new file mode 100644 index 00000000..05a1dfd8 Binary files /dev/null and b/public/images/jstoolbar/bt_h1.png differ diff --git a/public/images/jstoolbar/bt_h2.png b/public/images/jstoolbar/bt_h2.png new file mode 100644 index 00000000..d747a5aa Binary files /dev/null and b/public/images/jstoolbar/bt_h2.png differ diff --git a/public/images/jstoolbar/bt_h3.png b/public/images/jstoolbar/bt_h3.png new file mode 100644 index 00000000..b37d4375 Binary files /dev/null and b/public/images/jstoolbar/bt_h3.png differ diff --git a/public/images/jstoolbar/bt_img.png b/public/images/jstoolbar/bt_img.png new file mode 100644 index 00000000..3691d1f1 Binary files /dev/null and b/public/images/jstoolbar/bt_img.png differ diff --git a/public/images/jstoolbar/bt_ins.png b/public/images/jstoolbar/bt_ins.png new file mode 100644 index 00000000..1a6683a3 Binary files /dev/null and b/public/images/jstoolbar/bt_ins.png differ diff --git a/public/images/jstoolbar/bt_link.png b/public/images/jstoolbar/bt_link.png new file mode 100644 index 00000000..74c9e0c5 Binary files /dev/null and b/public/images/jstoolbar/bt_link.png differ diff --git a/public/images/jstoolbar/bt_ol.png b/public/images/jstoolbar/bt_ol.png new file mode 100644 index 00000000..f895ec64 Binary files /dev/null and b/public/images/jstoolbar/bt_ol.png differ diff --git a/public/images/jstoolbar/bt_pre.png b/public/images/jstoolbar/bt_pre.png new file mode 100644 index 00000000..8056ddd4 Binary files /dev/null and b/public/images/jstoolbar/bt_pre.png differ diff --git a/public/images/jstoolbar/bt_strong.png b/public/images/jstoolbar/bt_strong.png new file mode 100644 index 00000000..ff338810 Binary files /dev/null and b/public/images/jstoolbar/bt_strong.png differ diff --git a/public/images/jstoolbar/bt_ul.png b/public/images/jstoolbar/bt_ul.png new file mode 100644 index 00000000..65c39f0f Binary files /dev/null and b/public/images/jstoolbar/bt_ul.png differ diff --git a/public/images/jstoolbar/logo1.png b/public/images/jstoolbar/logo1.png new file mode 100644 index 00000000..57ff0ccf Binary files /dev/null and b/public/images/jstoolbar/logo1.png differ diff --git a/public/images/lightning.png b/public/images/lightning.png new file mode 100644 index 00000000..81a544fa Binary files /dev/null and b/public/images/lightning.png differ diff --git a/public/images/link.png b/public/images/link.png new file mode 100644 index 00000000..53927566 Binary files /dev/null and b/public/images/link.png differ diff --git a/public/images/link_break.png b/public/images/link_break.png new file mode 100644 index 00000000..52357530 Binary files /dev/null and b/public/images/link_break.png differ diff --git a/public/images/loading.gif b/public/images/loading.gif new file mode 100644 index 00000000..085ccaec Binary files /dev/null and b/public/images/loading.gif differ diff --git a/public/images/locked.png b/public/images/locked.png new file mode 100644 index 00000000..5c46f15c Binary files /dev/null and b/public/images/locked.png differ diff --git a/public/images/logo-only_med.png b/public/images/logo-only_med.png new file mode 100644 index 00000000..fa5df376 Binary files /dev/null and b/public/images/logo-only_med.png differ diff --git a/public/images/magnifier.png b/public/images/magnifier.png new file mode 100644 index 00000000..cf3d97f7 Binary files /dev/null and b/public/images/magnifier.png differ diff --git a/public/images/message.png b/public/images/message.png new file mode 100644 index 00000000..0017800f Binary files /dev/null and b/public/images/message.png differ diff --git a/public/images/milestone_done.png b/public/images/milestone_done.png new file mode 100644 index 00000000..5fdcb415 Binary files /dev/null and b/public/images/milestone_done.png differ diff --git a/public/images/milestone_late.png b/public/images/milestone_late.png new file mode 100644 index 00000000..cf922e95 Binary files /dev/null and b/public/images/milestone_late.png differ diff --git a/public/images/milestone_todo.png b/public/images/milestone_todo.png new file mode 100644 index 00000000..4c051c85 Binary files /dev/null and b/public/images/milestone_todo.png differ diff --git a/public/images/move.png b/public/images/move.png new file mode 100644 index 00000000..7f269c36 Binary files /dev/null and b/public/images/move.png differ diff --git a/public/images/new/fenxiang.png b/public/images/new/fenxiang.png new file mode 100644 index 00000000..cce90bcb Binary files /dev/null and b/public/images/new/fenxiang.png differ diff --git a/public/images/new/liuyan.png b/public/images/new/liuyan.png new file mode 100644 index 00000000..391bbd95 Binary files /dev/null and b/public/images/new/liuyan.png differ diff --git a/public/images/new/liuyan2.png b/public/images/new/liuyan2.png new file mode 100644 index 00000000..ad04944d Binary files /dev/null and b/public/images/new/liuyan2.png differ diff --git a/public/images/new/logo.gif b/public/images/new/logo.gif new file mode 100644 index 00000000..6c099118 Binary files /dev/null and b/public/images/new/logo.gif differ diff --git a/public/images/new/logo.png b/public/images/new/logo.png new file mode 100644 index 00000000..b58caabf Binary files /dev/null and b/public/images/new/logo.png differ diff --git a/public/images/new/logo_top.png b/public/images/new/logo_top.png new file mode 100644 index 00000000..6d933b4b Binary files /dev/null and b/public/images/new/logo_top.png differ diff --git a/public/images/new/mlogo.png b/public/images/new/mlogo.png new file mode 100644 index 00000000..cce3b9cc Binary files /dev/null and b/public/images/new/mlogo.png differ diff --git a/public/images/new/news.png b/public/images/new/news.png new file mode 100644 index 00000000..1f033290 Binary files /dev/null and b/public/images/new/news.png differ diff --git a/public/images/new/small.png b/public/images/new/small.png new file mode 100644 index 00000000..cf2f738c Binary files /dev/null and b/public/images/new/small.png differ diff --git a/public/images/new/user.jpg b/public/images/new/user.jpg new file mode 100644 index 00000000..68a02e4a Binary files /dev/null and b/public/images/new/user.jpg differ diff --git a/public/images/new/zhishu.png b/public/images/new/zhishu.png new file mode 100644 index 00000000..e69f10b4 Binary files /dev/null and b/public/images/new/zhishu.png differ diff --git a/public/images/new/zhishu2.png b/public/images/new/zhishu2.png new file mode 100644 index 00000000..7784e847 Binary files /dev/null and b/public/images/new/zhishu2.png differ diff --git a/public/images/news.png b/public/images/news.png new file mode 100644 index 00000000..aa857e75 Binary files /dev/null and b/public/images/news.png differ diff --git a/public/images/openid-bg.gif b/public/images/openid-bg.gif new file mode 100644 index 00000000..e2d8377d Binary files /dev/null and b/public/images/openid-bg.gif differ diff --git a/public/images/package.png b/public/images/package.png new file mode 100644 index 00000000..c35e832d Binary files /dev/null and b/public/images/package.png differ diff --git a/public/images/pai.png b/public/images/pai.png new file mode 100644 index 00000000..98e8ca4c Binary files /dev/null and b/public/images/pai.png differ diff --git a/public/images/plugin.png b/public/images/plugin.png new file mode 100644 index 00000000..5a49f577 Binary files /dev/null and b/public/images/plugin.png differ diff --git a/public/images/project_marker.png b/public/images/project_marker.png new file mode 100644 index 00000000..4124787d Binary files /dev/null and b/public/images/project_marker.png differ diff --git a/public/images/projects.png b/public/images/projects.png new file mode 100644 index 00000000..018b8b95 Binary files /dev/null and b/public/images/projects.png differ diff --git a/public/images/reload.png b/public/images/reload.png new file mode 100644 index 00000000..384147dc Binary files /dev/null and b/public/images/reload.png differ diff --git a/public/images/report.png b/public/images/report.png new file mode 100644 index 00000000..4c0f857c Binary files /dev/null and b/public/images/report.png differ diff --git a/public/images/requirements/req.jpg b/public/images/requirements/req.jpg new file mode 100644 index 00000000..c299b3cb Binary files /dev/null and b/public/images/requirements/req.jpg differ diff --git a/public/images/save.png b/public/images/save.png new file mode 100644 index 00000000..7535814f Binary files /dev/null and b/public/images/save.png differ diff --git a/public/images/server_key.png b/public/images/server_key.png new file mode 100644 index 00000000..ecd51742 Binary files /dev/null and b/public/images/server_key.png differ diff --git a/public/images/sidebar/fork.png b/public/images/sidebar/fork.png new file mode 100644 index 00000000..48839110 Binary files /dev/null and b/public/images/sidebar/fork.png differ diff --git a/public/images/sidebar/tag_title.png b/public/images/sidebar/tag_title.png new file mode 100644 index 00000000..890d1af0 Binary files /dev/null and b/public/images/sidebar/tag_title.png differ diff --git a/public/images/sidebar/tool_tag.png b/public/images/sidebar/tool_tag.png new file mode 100644 index 00000000..a991880e Binary files /dev/null and b/public/images/sidebar/tool_tag.png differ diff --git a/public/images/sidebar/watch.png b/public/images/sidebar/watch.png new file mode 100644 index 00000000..b80d6334 Binary files /dev/null and b/public/images/sidebar/watch.png differ diff --git a/public/images/sort_asc.png b/public/images/sort_asc.png new file mode 100644 index 00000000..fbfbcdfa Binary files /dev/null and b/public/images/sort_asc.png differ diff --git a/public/images/sort_desc.png b/public/images/sort_desc.png new file mode 100644 index 00000000..28e977f0 Binary files /dev/null and b/public/images/sort_desc.png differ diff --git a/public/images/stars_ro.png b/public/images/stars_ro.png new file mode 100644 index 00000000..4c1da3c8 Binary files /dev/null and b/public/images/stars_ro.png differ diff --git a/public/images/stats.png b/public/images/stats.png new file mode 100644 index 00000000..0b120a49 Binary files /dev/null and b/public/images/stats.png differ diff --git a/public/images/table_multiple.png b/public/images/table_multiple.png new file mode 100644 index 00000000..057f4a5e Binary files /dev/null and b/public/images/table_multiple.png differ diff --git a/public/images/task_done.png b/public/images/task_done.png new file mode 100644 index 00000000..5fdcb415 Binary files /dev/null and b/public/images/task_done.png differ diff --git a/public/images/task_late.png b/public/images/task_late.png new file mode 100644 index 00000000..71fd2d70 Binary files /dev/null and b/public/images/task_late.png differ diff --git a/public/images/task_parent_end.png b/public/images/task_parent_end.png new file mode 100644 index 00000000..9442b86a Binary files /dev/null and b/public/images/task_parent_end.png differ diff --git a/public/images/task_todo.png b/public/images/task_todo.png new file mode 100644 index 00000000..632406ee Binary files /dev/null and b/public/images/task_todo.png differ diff --git a/public/images/text_list_bullets.png b/public/images/text_list_bullets.png new file mode 100644 index 00000000..00882072 Binary files /dev/null and b/public/images/text_list_bullets.png differ diff --git a/public/images/textfield.png b/public/images/textfield.png new file mode 100644 index 00000000..408c6b02 Binary files /dev/null and b/public/images/textfield.png differ diff --git a/public/images/textfield_key.png b/public/images/textfield_key.png new file mode 100644 index 00000000..a9d5e4f8 Binary files /dev/null and b/public/images/textfield_key.png differ diff --git a/public/images/ticket.png b/public/images/ticket.png new file mode 100644 index 00000000..73756ed4 Binary files /dev/null and b/public/images/ticket.png differ diff --git a/public/images/ticket_checked.png b/public/images/ticket_checked.png new file mode 100644 index 00000000..fc25958a Binary files /dev/null and b/public/images/ticket_checked.png differ diff --git a/public/images/ticket_edit.png b/public/images/ticket_edit.png new file mode 100644 index 00000000..89df6cba Binary files /dev/null and b/public/images/ticket_edit.png differ diff --git a/public/images/ticket_go.png b/public/images/ticket_go.png new file mode 100644 index 00000000..2aaec381 Binary files /dev/null and b/public/images/ticket_go.png differ diff --git a/public/images/ticket_note.png b/public/images/ticket_note.png new file mode 100644 index 00000000..c8de1657 Binary files /dev/null and b/public/images/ticket_note.png differ diff --git a/public/images/time.png b/public/images/time.png new file mode 100644 index 00000000..fa1bf5f9 Binary files /dev/null and b/public/images/time.png differ diff --git a/public/images/time_add.png b/public/images/time_add.png new file mode 100644 index 00000000..70119f77 Binary files /dev/null and b/public/images/time_add.png differ diff --git a/public/images/toggle_check.png b/public/images/toggle_check.png new file mode 100644 index 00000000..da85f26d Binary files /dev/null and b/public/images/toggle_check.png differ diff --git a/public/images/true.png b/public/images/true.png new file mode 100644 index 00000000..a2ed1a37 Binary files /dev/null and b/public/images/true.png differ diff --git a/public/images/unlock.png b/public/images/unlock.png new file mode 100644 index 00000000..0c284d99 Binary files /dev/null and b/public/images/unlock.png differ diff --git a/public/images/user.png b/public/images/user.png new file mode 100644 index 00000000..264381ed Binary files /dev/null and b/public/images/user.png differ diff --git a/public/images/user_images/L1.png b/public/images/user_images/L1.png new file mode 100644 index 00000000..178f783f Binary files /dev/null and b/public/images/user_images/L1.png differ diff --git a/public/images/user_images/L2.png b/public/images/user_images/L2.png new file mode 100644 index 00000000..6b816f8f Binary files /dev/null and b/public/images/user_images/L2.png differ diff --git a/public/images/user_images/L3.png b/public/images/user_images/L3.png new file mode 100644 index 00000000..6cf2afb1 Binary files /dev/null and b/public/images/user_images/L3.png differ diff --git a/public/images/user_images/fans.png b/public/images/user_images/fans.png new file mode 100644 index 00000000..3e48100d Binary files /dev/null and b/public/images/user_images/fans.png differ diff --git a/public/images/user_images/fork.png b/public/images/user_images/fork.png new file mode 100644 index 00000000..48839110 Binary files /dev/null and b/public/images/user_images/fork.png differ diff --git a/public/images/user_images/in_share.png b/public/images/user_images/in_share.png new file mode 100644 index 00000000..77aecfd8 Binary files /dev/null and b/public/images/user_images/in_share.png differ diff --git a/public/images/user_images/iuser.png b/public/images/user_images/iuser.png new file mode 100644 index 00000000..6cb78eba Binary files /dev/null and b/public/images/user_images/iuser.png differ diff --git a/public/images/user_images/m1.png b/public/images/user_images/m1.png new file mode 100644 index 00000000..40fc59c6 Binary files /dev/null and b/public/images/user_images/m1.png differ diff --git a/public/images/user_images/m2.png b/public/images/user_images/m2.png new file mode 100644 index 00000000..f00bf665 Binary files /dev/null and b/public/images/user_images/m2.png differ diff --git a/public/images/user_images/me.jpg b/public/images/user_images/me.jpg new file mode 100644 index 00000000..f4f76491 Binary files /dev/null and b/public/images/user_images/me.jpg differ diff --git a/public/images/user_images/mlogo.png b/public/images/user_images/mlogo.png new file mode 100644 index 00000000..cce3b9cc Binary files /dev/null and b/public/images/user_images/mlogo.png differ diff --git a/public/images/user_images/project.jpg b/public/images/user_images/project.jpg new file mode 100644 index 00000000..576239c0 Binary files /dev/null and b/public/images/user_images/project.jpg differ diff --git a/public/images/user_images/project.png b/public/images/user_images/project.png new file mode 100644 index 00000000..82ce8f6a Binary files /dev/null and b/public/images/user_images/project.png differ diff --git a/public/images/user_images/share.png b/public/images/user_images/share.png new file mode 100644 index 00000000..108425b2 Binary files /dev/null and b/public/images/user_images/share.png differ diff --git a/public/images/user_images/user2.png b/public/images/user_images/user2.png new file mode 100644 index 00000000..b0fe8ad8 Binary files /dev/null and b/public/images/user_images/user2.png differ diff --git a/public/images/user_images/watch.png b/public/images/user_images/watch.png new file mode 100644 index 00000000..b80d6334 Binary files /dev/null and b/public/images/user_images/watch.png differ diff --git a/public/images/user_images/watchers.png b/public/images/user_images/watchers.png new file mode 100644 index 00000000..7e057a20 Binary files /dev/null and b/public/images/user_images/watchers.png differ diff --git a/public/images/version_marker.png b/public/images/version_marker.png new file mode 100644 index 00000000..0368ca29 Binary files /dev/null and b/public/images/version_marker.png differ diff --git a/public/images/warning.png b/public/images/warning.png new file mode 100644 index 00000000..c5e482f8 Binary files /dev/null and b/public/images/warning.png differ diff --git a/public/images/watcher/watcher_button.png b/public/images/watcher/watcher_button.png new file mode 100644 index 00000000..2029d2f5 Binary files /dev/null and b/public/images/watcher/watcher_button.png differ diff --git a/public/images/welcome/1.png b/public/images/welcome/1.png new file mode 100644 index 00000000..75194ee4 Binary files /dev/null and b/public/images/welcome/1.png differ diff --git a/public/images/welcome/2.png b/public/images/welcome/2.png new file mode 100644 index 00000000..cb688d90 Binary files /dev/null and b/public/images/welcome/2.png differ diff --git a/public/images/welcome/3.png b/public/images/welcome/3.png new file mode 100644 index 00000000..dcd0f19e Binary files /dev/null and b/public/images/welcome/3.png differ diff --git a/public/images/welcome/4.png b/public/images/welcome/4.png new file mode 100644 index 00000000..da95636e Binary files /dev/null and b/public/images/welcome/4.png differ diff --git a/public/images/welcome/background.png b/public/images/welcome/background.png new file mode 100644 index 00000000..d7dc8d40 Binary files /dev/null and b/public/images/welcome/background.png differ diff --git a/public/images/welcome/background2.png b/public/images/welcome/background2.png new file mode 100644 index 00000000..6f86c76d Binary files /dev/null and b/public/images/welcome/background2.png differ diff --git a/public/images/welcome/background3.png b/public/images/welcome/background3.png new file mode 100644 index 00000000..7d55349a Binary files /dev/null and b/public/images/welcome/background3.png differ diff --git a/public/images/welcome/backgroundnew.png b/public/images/welcome/backgroundnew.png new file mode 100644 index 00000000..a61e59b6 Binary files /dev/null and b/public/images/welcome/backgroundnew.png differ diff --git a/public/images/wiki_edit.png b/public/images/wiki_edit.png new file mode 100644 index 00000000..e00618a5 Binary files /dev/null and b/public/images/wiki_edit.png differ diff --git a/public/images/zoom_in.png b/public/images/zoom_in.png new file mode 100644 index 00000000..af4fe074 Binary files /dev/null and b/public/images/zoom_in.png differ diff --git a/public/images/zoom_out.png b/public/images/zoom_out.png new file mode 100644 index 00000000..81f28199 Binary files /dev/null and b/public/images/zoom_out.png differ diff --git a/public/javascripts/application.js b/public/javascripts/application.js new file mode 100644 index 00000000..b726cce3 --- /dev/null +++ b/public/javascripts/application.js @@ -0,0 +1,595 @@ +/* Redmine - project management software + Copyright (C) 2006-2013 Jean-Philippe Lang */ + +function checkAll(id, checked) { + if (checked) { + $('#'+id).find('input[type=checkbox]').attr('checked', true); + } else { + $('#'+id).find('input[type=checkbox]').removeAttr('checked'); + } +} + +function toggleCheckboxesBySelector(selector) { + var all_checked = true; + $(selector).each(function(index) { + if (!$(this).is(':checked')) { all_checked = false; } + }); + $(selector).attr('checked', !all_checked); +} + +function showAndScrollTo(id, focus) { + $('#'+id).show(); + if (focus !== null) { + $('#'+focus).focus(); + } + $('html, body').animate({scrollTop: $('#'+id).offset().top}, 100); +} + +function toggleRowGroup(el) { + var tr = $(el).parents('tr').first(); + var n = tr.next(); + tr.toggleClass('open'); + while (n.length && !n.hasClass('group')) { + n.toggle(); + n = n.next('tr'); + } +} + +function collapseAllRowGroups(el) { + var tbody = $(el).parents('tbody').first(); + tbody.children('tr').each(function(index) { + if ($(this).hasClass('group')) { + $(this).removeClass('open'); + } else { + $(this).hide(); + } + }); +} + +function expandAllRowGroups(el) { + var tbody = $(el).parents('tbody').first(); + tbody.children('tr').each(function(index) { + if ($(this).hasClass('group')) { + $(this).addClass('open'); + } else { + $(this).show(); + } + }); +} + +function toggleAllRowGroups(el) { + var tr = $(el).parents('tr').first(); + if (tr.hasClass('open')) { + collapseAllRowGroups(el); + } else { + expandAllRowGroups(el); + } +} + +function toggleFieldset(el) { + var fieldset = $(el).parents('fieldset').first(); + fieldset.toggleClass('collapsed'); + fieldset.children('div').toggle(); +} + +function hideFieldset(el) { + var fieldset = $(el).parents('fieldset').first(); + fieldset.toggleClass('collapsed'); + fieldset.children('div').hide(); +} + +function initFilters(){ + $('#add_filter_select').change(function(){ + addFilter($(this).val(), '', []); + }); + $('#filters-table td.field input[type=checkbox]').each(function(){ + toggleFilter($(this).val()); + }); + $('#filters-table td.field input[type=checkbox]').live('click',function(){ + toggleFilter($(this).val()); + }); + $('#filters-table .toggle-multiselect').live('click',function(){ + toggleMultiSelect($(this).siblings('select')); + }); + $('#filters-table input[type=text]').live('keypress', function(e){ + if (e.keyCode == 13) submit_query_form("query_form"); + }); +} + +function addFilter(field, operator, values) { + var fieldId = field.replace('.', '_'); + var tr = $('#tr_'+fieldId); + if (tr.length > 0) { + tr.show(); + } else { + buildFilterRow(field, operator, values); + } + $('#cb_'+fieldId).attr('checked', true); + toggleFilter(field); + $('#add_filter_select').val('').children('option').each(function(){ + if ($(this).attr('value') == field) { + $(this).attr('disabled', true); + } + }); +} + +function buildFilterRow(field, operator, values) { + var fieldId = field.replace('.', '_'); + var filterTable = $("#filters-table"); + var filterOptions = availableFilters[field]; + var operators = operatorByType[filterOptions['type']]; + var filterValues = filterOptions['values']; + var i, select; + + var tr = $('').attr('id', 'tr_'+fieldId).html( + '' + + '' + + '  ' + ); + select = tr.find('td.values select'); + if (values.length > 1) { select.attr('multiple', true); } + for (i=0;i'); + if ($.isArray(filterValue)) { + option.val(filterValue[1]).text(filterValue[0]); + if ($.inArray(filterValue[1], values) > -1) {option.attr('selected', true);} + } else { + option.val(filterValue).text(filterValue); + if ($.inArray(filterValue, values) > -1) {option.attr('selected', true);} + } + select.append(option); + } + break; + case "date": + case "date_past": + tr.find('td.values').append( + '' + + ' ' + + ' '+labelDayPlural+'' + ); + $('#values_'+fieldId+'_1').val(values[0]).datepicker(datepickerOptions); + $('#values_'+fieldId+'_2').val(values[1]).datepicker(datepickerOptions); + $('#values_'+fieldId).val(values[0]); + break; + case "string": + case "text": + tr.find('td.values').append( + '' + ); + $('#values_'+fieldId).val(values[0]); + break; + case "relation": + tr.find('td.values').append( + '' + + '' + ); + $('#values_'+fieldId).val(values[0]); + select = tr.find('td.values select'); + for (i=0;i'); + option.val(filterValue[1]).text(filterValue[0]); + if (values[0] == filterValue[1]) { option.attr('selected', true); } + select.append(option); + } + case "integer": + case "float": + tr.find('td.values').append( + '' + + ' ' + ); + $('#values_'+fieldId+'_1').val(values[0]); + $('#values_'+fieldId+'_2').val(values[1]); + break; + } +} + +function toggleFilter(field) { + var fieldId = field.replace('.', '_'); + if ($('#cb_' + fieldId).is(':checked')) { + $("#operators_" + fieldId).show().removeAttr('disabled'); + toggleOperator(field); + } else { + $("#operators_" + fieldId).hide().attr('disabled', true); + enableValues(field, []); + } +} + +function enableValues(field, indexes) { + var fieldId = field.replace('.', '_'); + $('#tr_'+fieldId+' td.values .value').each(function(index) { + if ($.inArray(index, indexes) >= 0) { + $(this).removeAttr('disabled'); + $(this).parents('span').first().show(); + } else { + $(this).val(''); + $(this).attr('disabled', true); + $(this).parents('span').first().hide(); + } + + if ($(this).hasClass('group')) { + $(this).addClass('open'); + } else { + $(this).show(); + } + }); +} + +function toggleOperator(field) { + var fieldId = field.replace('.', '_'); + var operator = $("#operators_" + fieldId); + switch (operator.val()) { + case "!*": + case "*": + case "t": + case "ld": + case "w": + case "lw": + case "l2w": + case "m": + case "lm": + case "y": + case "o": + case "c": + enableValues(field, []); + break; + case "><": + enableValues(field, [0,1]); + break; + case "t+": + case ">t-": + case "0) { + lis.eq(i-1).show(); + } +} + +function displayTabsButtons() { + var lis; + var tabsWidth = 0; + var el; + $('div.tabs').each(function() { + el = $(this); + lis = el.find('ul').children(); + lis.each(function(){ + if ($(this).is(':visible')) { + tabsWidth += $(this).width() + 6; + } + }); + if ((tabsWidth < el.width() - 60) && (lis.first().is(':visible'))) { + el.find('div.tabs-buttons').hide(); + } else { + el.find('div.tabs-buttons').show(); + } + }); +} + +function setPredecessorFieldsVisibility() { + var relationType = $('#relation_relation_type'); + if (relationType.val() == "precedes" || relationType.val() == "follows") { + $('#predecessor_fields').show(); + } else { + $('#predecessor_fields').hide(); + } +} + +function showModal(id, width) { + var el = $('#'+id).first(); + if (el.length === 0 || el.is(':visible')) {return;} + var title = el.find('h3.title').text(); + el.dialog({ + width: width, + modal: true, + resizable: false, + dialogClass: 'modal', + title: title + }); + el.find("input[type=text], input[type=submit]").first().focus(); +} + +function hideModal(el) { + var modal; + if (el) { + modal = $(el).parents('.ui-dialog-content'); + } else { + modal = $('#ajax-modal'); + } + modal.dialog("close"); +} + +function submitPreview(url, form, target) { + $.ajax({ + url: url, + type: 'post', + data: $('#'+form).serialize(), + success: function(data){ + $('#'+target).html(data); + } + }); +} + +function collapseScmEntry(id) { + $('.'+id).each(function() { + if ($(this).hasClass('open')) { + collapseScmEntry($(this).attr('id')); + } + $(this).hide(); + }); + $('#'+id).removeClass('open'); +} + +function expandScmEntry(id) { + $('.'+id).each(function() { + $(this).show(); + if ($(this).hasClass('loaded') && !$(this).hasClass('collapsed')) { + expandScmEntry($(this).attr('id')); + } + }); + $('#'+id).addClass('open'); +} + +function scmEntryClick(id, url) { + el = $('#'+id); + if (el.hasClass('open')) { + collapseScmEntry(id); + el.addClass('collapsed'); + return false; + } else if (el.hasClass('loaded')) { + expandScmEntry(id); + el.removeClass('collapsed'); + return false; + } + if (el.hasClass('loading')) { + return false; + } + el.addClass('loading'); + $.ajax({ + url: url, + success: function(data){ + el.after(data); + el.addClass('open').addClass('loaded').removeClass('loading'); + } + }); + return true; +} + +function randomKey(size) { + var chars = new Array('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'); + var key = ''; + for (i = 0; i < size; i++) { + key += chars[Math.floor(Math.random() * chars.length)]; + } + return key; +} + +// Can't use Rails' remote select because we need the form data +function updateIssueFrom(url) { + $.ajax({ + url: url, + type: 'post', + data: $('#issue-form').serialize() + }); +} + +function updateBulkEditFrom(url) { + $.ajax({ + url: url, + type: 'post', + data: $('#bulk_edit_form').serialize() + }); +} + +function clearMessage(id) { + $('#'+id).val(""); +} + + +function observeAutocompleteField(fieldId, url, options) { + $(document).ready(function() { + $('#'+fieldId).autocomplete($.extend({ + source: url, + minLength: 2, + search: function(){$('#'+fieldId).addClass('ajax-loading');}, + response: function(){$('#'+fieldId).removeClass('ajax-loading');} + }, options)); + $('#'+fieldId).addClass('autocomplete'); + }); +} + +function observeSearchfield(fieldId, targetId, url) { + $('#'+fieldId).each(function() { + var $this = $(this); + $this.addClass('autocomplete'); + $this.attr('data-value-was', $this.val()); + var check = function() { + var val = $this.val(); + if ($this.attr('data-value-was') != val){ + $this.attr('data-value-was', val); + $.ajax({ + url: url, + type: 'get', + data: {q: $this.val()}, + success: function(data){ if(targetId) $('#'+targetId).html(data); }, + beforeSend: function(){ $this.addClass('ajax-loading'); }, + complete: function(){ $this.removeClass('ajax-loading'); } + }); + } + }; + var reset = function() { + if (timer) { + clearInterval(timer); + timer = setInterval(check, 300); + } + }; + var timer = setInterval(check, 300); + $this.bind('keyup click mousemove', reset); + }); +} + +function observeProjectModules() { + var f = function() { + /* Hides trackers and issues custom fields on the new project form when issue_tracking module is disabled */ + if ($('#project_enabled_module_names_issue_tracking').attr('checked')) { + $('#project_trackers').show(); + }else{ + $('#project_trackers').hide(); + } + }; + + $(window).load(f); + $('#project_enabled_module_names_issue_tracking').change(f); +} + +function initMyPageSortable(list, url) { + $('#list-'+list).sortable({ + connectWith: '.block-receiver', + tolerance: 'pointer', + update: function(){ + $.ajax({ + url: url, + type: 'post', + data: {'blocks': $.map($('#list-'+list).children(), function(el){return $(el).attr('id');})} + }); + } + }); + $("#list-top, #list-left, #list-right").disableSelection(); +} + +var warnLeavingUnsavedMessage; +function warnLeavingUnsaved(message) { + warnLeavingUnsavedMessage = message; + + $('form').submit(function(){ + $('textarea').removeData('changed'); + }); + $('textarea').change(function(){ + $(this).data('changed', 'changed'); + }); + window.onbeforeunload = function(){ + var warn = false; + $('textarea').blur().each(function(){ + if ($(this).data('changed')) { + warn = true; + } + }); + if (warn) {return warnLeavingUnsavedMessage;} + }; +} + +function setupAjaxIndicator() { + + $('#ajax-indicator').bind('ajaxSend', function(event, xhr, settings) { + + if ($('.ajax-loading').length === 0 && settings.contentType != 'application/octet-stream') { + $('#ajax-indicator').show(); + } + }); + + $('#ajax-indicator').bind('ajaxStop', function() { + $('#ajax-indicator').hide(); + }); +} + +function hideOnLoad() { + $('.hol').hide(); +} + +function addFormObserversForDoubleSubmit() { + $('form[method=post]').each(function() { + if (!$(this).hasClass('multiple-submit')) { + $(this).submit(function(form_submission) { + if ($(form_submission.target).attr('data-submitted')) { + form_submission.preventDefault(); + } else { + $(form_submission.target).attr('data-submitted', true); + } + }); + } + }); +} + +function blockEventPropagation(event) { + event.stopPropagation(); + event.preventDefault(); +} + +$(document).ready(setupAjaxIndicator); +$(document).ready(hideOnLoad); +$(document).ready(addFormObserversForDoubleSubmit); diff --git a/public/javascripts/attachments.js b/public/javascripts/attachments.js new file mode 100644 index 00000000..260c060e --- /dev/null +++ b/public/javascripts/attachments.js @@ -0,0 +1,188 @@ +/* Redmine - project management software + Copyright (C) 2006-2013 Jean-Philippe Lang */ + +function addFile(inputEl, file, eagerUpload) { + + if ($('#attachments_fields').children().length < 10) { + + var attachmentId = addFile.nextAttachmentId++; + + var fileSpan = $('', { id: 'attachments_' + attachmentId }); + + fileSpan.append( + $('', { type: 'text', 'class': 'filename readonly', name: 'attachments[' + attachmentId + '][filename]', readonly: 'readonly'} ).val(file.name), + $('', { type: 'text', 'class': 'description', name: 'attachments[' + attachmentId + '][description]', maxlength: 255, placeholder: $(inputEl).data('description-placeholder') } ).toggle(!eagerUpload), + $(' ').attr({ href: "#", 'class': 'remove-upload' }).click(removeFile).toggle(!eagerUpload) + ).appendTo('#attachments_fields'); + + if(eagerUpload) { + ajaxUpload(file, attachmentId, fileSpan, inputEl); + } + + return attachmentId; + } + return null; +} + +addFile.nextAttachmentId = 1; + +function ajaxUpload(file, attachmentId, fileSpan, inputEl) { + + function onLoadstart(e) { + fileSpan.removeClass('ajax-waiting'); + fileSpan.addClass('ajax-loading'); + $('input:submit', $(this).parents('form')).attr('disabled', 'disabled'); + } + + function onProgress(e) { + if(e.lengthComputable) { + this.progressbar( 'value', e.loaded * 100 / e.total ); + } + } + + function actualUpload(file, attachmentId, fileSpan, inputEl) { + + ajaxUpload.uploading++; + + uploadBlob(file, $(inputEl).data('upload-path'), attachmentId, { + loadstartEventHandler: onLoadstart.bind(progressSpan), + progressEventHandler: onProgress.bind(progressSpan) + }) + .done(function(result) { + progressSpan.progressbar( 'value', 100 ).remove(); + fileSpan.find('input.description, a').css('display', 'inline-block'); + }) + .fail(function(result) { + progressSpan.text(result.statusText); + }).always(function() { + ajaxUpload.uploading--; + fileSpan.removeClass('ajax-loading'); + var form = fileSpan.parents('form'); + if (form.queue('upload').length == 0 && ajaxUpload.uploading == 0) { + $('input:submit', form).removeAttr('disabled'); + } + form.dequeue('upload'); + }); + } + + var progressSpan = $('
      ').insertAfter(fileSpan.find('input.filename')); + progressSpan.progressbar(); + fileSpan.addClass('ajax-waiting'); + + var maxSyncUpload = $(inputEl).data('max-concurrent-uploads'); + + if(maxSyncUpload == null || maxSyncUpload <= 0 || ajaxUpload.uploading < maxSyncUpload) + actualUpload(file, attachmentId, fileSpan, inputEl); + else + $(inputEl).parents('form').queue('upload', actualUpload.bind(this, file, attachmentId, fileSpan, inputEl)); +} + +ajaxUpload.uploading = 0; + +function removeFile() { + $(this).parent('span').remove(); + return false; +} + +function uploadBlob(blob, uploadUrl, attachmentId, options) { + + var actualOptions = $.extend({ + loadstartEventHandler: $.noop, + progressEventHandler: $.noop + }, options); + + uploadUrl = uploadUrl + '?attachment_id=' + attachmentId; + if (blob instanceof window.File) { + uploadUrl += '&filename=' + encodeURIComponent(blob.name); + } + + return $.ajax(uploadUrl, { + type: 'POST', + contentType: 'application/octet-stream', + beforeSend: function(jqXhr) { + jqXhr.setRequestHeader('Accept', 'application/js'); + }, + xhr: function() { + var xhr = $.ajaxSettings.xhr(); + xhr.upload.onloadstart = actualOptions.loadstartEventHandler; + xhr.upload.onprogress = actualOptions.progressEventHandler; + return xhr; + }, + data: blob, + cache: false, + processData: false + }); +} + +function addInputFiles(inputEl) { + var clearedFileInput = $(inputEl).clone().val(''); + + if (inputEl.files) { + // upload files using ajax + uploadAndAttachFiles(inputEl.files, inputEl); + $(inputEl).remove(); + } else { + // browser not supporting the file API, upload on form submission + var attachmentId; + var aFilename = inputEl.value.split(/\/|\\/); + attachmentId = addFile(inputEl, { name: aFilename[ aFilename.length - 1 ] }, false); + if (attachmentId) { + $(inputEl).attr({ name: 'attachments[' + attachmentId + '][file]', style: 'display:none;' }).appendTo('#attachments_' + attachmentId); + } + } + + clearedFileInput.insertAfter('#attachments_fields'); +} + +function uploadAndAttachFiles(files, inputEl) { + + var maxFileSize = $(inputEl).data('max-file-size'); + var maxFileSizeExceeded = $(inputEl).data('max-file-size-message'); + + var sizeExceeded = false; + $.each(files, function() { + if (this.size && maxFileSize && this.size > parseInt(maxFileSize)) {sizeExceeded=true;} + }); + if (sizeExceeded) { + window.alert(maxFileSizeExceeded); + } else { + $.each(files, function() {addFile(inputEl, this, true);}); + } +} + +function handleFileDropEvent(e) { + + $(this).removeClass('fileover'); + blockEventPropagation(e); + + if ($.inArray('Files', e.dataTransfer.types) > -1) { + uploadAndAttachFiles(e.dataTransfer.files, $('input:file.file_selector')); + } +} + +function dragOverHandler(e) { + $(this).addClass('fileover'); + blockEventPropagation(e); +} + +function dragOutHandler(e) { + $(this).removeClass('fileover'); + blockEventPropagation(e); +} + +function setupFileDrop() { + if (window.File && window.FileList && window.ProgressEvent && window.FormData) { + + $.event.fixHooks.drop = { props: [ 'dataTransfer' ] }; + + $('form div.box').has('input:file').each(function() { + $(this).on({ + dragover: dragOverHandler, + dragleave: dragOutHandler, + drop: handleFileDropEvent + }); + }); + } +} + +$(document).ready(setupFileDrop); diff --git a/public/javascripts/avatars.js b/public/javascripts/avatars.js new file mode 100644 index 00000000..ea8a843b --- /dev/null +++ b/public/javascripts/avatars.js @@ -0,0 +1,181 @@ +/* Redmine - project management software + Copyright (C) 2006-2013 Jean-Philippe Lang + Modified by Jianfeng Tao, to upload one avatar for user*/ + +function addFile(inputEl, file, eagerUpload) { + + var fileSpan = $('#avatar_file'); + + //fileSpan.append( + // $('', { type: 'text', 'class': 'filename readonly', name: 'avatar[filename]', readonly: 'readonly'} ).val(file.name), + // $(' ').attr({ href: "#", 'class': 'remove-upload' }).click(removeFile).toggle(!eagerUpload) + //).appendTo('#avatar_fields'); + + if(eagerUpload) { + ajaxUpload(file, fileSpan, inputEl); + } + + return 1; +} + +function ajaxUpload(file, fileSpan, inputEl) { + + function onLoadstart(e) { + fileSpan.removeClass('ajax-waiting'); + fileSpan.addClass('ajax-loading'); + $('input:submit', $(this).parents('form')).attr('disabled', 'disabled'); + } + + function onProgress(e) { + if(e.lengthComputable) { + this.progressbar( 'value', e.loaded * 100 / e.total ); + } + } + + function actualUpload(file, fileSpan, inputEl) { + + ajaxUpload.uploading++; + + uploadBlob(file, $(inputEl).data('upload-path'),$(inputEl).data('source-type'), $(inputEl).data('source-id'),{ + loadstartEventHandler: onLoadstart.bind(progressSpan), + progressEventHandler: onProgress.bind(progressSpan) + }) + .done(function(result) { + progressSpan.progressbar( 'value', 100 ).remove(); + fileSpan.find('input.description, a').css('display', 'inline-block'); + }) + .fail(function(result) { + progressSpan.text(result.statusText); + }).always(function() { + ajaxUpload.uploading--; + fileSpan.removeClass('ajax-loading'); + var form = fileSpan.parents('form'); + if (form.queue('upload').length == 0 && ajaxUpload.uploading == 0) { + $('input:submit', form).removeAttr('disabled'); + } + form.dequeue('upload'); + }); + } + + var progressSpan = fileSpan.append('
      '); + progressSpan.progressbar(); + fileSpan.addClass('ajax-waiting'); + + var maxSyncUpload = $(inputEl).data('max-concurrent-uploads'); + + if(maxSyncUpload == null || maxSyncUpload <= 0 || ajaxUpload.uploading < maxSyncUpload) + actualUpload(file, fileSpan, inputEl); + else + $(inputEl).parents('form').queue('upload', actualUpload.bind(this, file, fileSpan, inputEl)); +} + +ajaxUpload.uploading = 0; + +function removeFile() { + $(this).parent('span').remove(); + return false; +} + +function uploadBlob(blob, uploadUrl, source_type,source_id, options) { + + var actualOptions = $.extend({ + loadstartEventHandler: $.noop, + progressEventHandler: $.noop + }, options); + + uploadUrl = uploadUrl + '?source_type=' + source_type + '&source_id=' + source_id; + if (blob instanceof window.File) { + uploadUrl += '&filename=' + encodeURIComponent(blob.name); + } + + return $.ajax(uploadUrl, { + type: 'POST', + contentType: 'application/octet-stream', + beforeSend: function(jqXhr) { + jqXhr.setRequestHeader('Accept', 'application/js'); + }, + xhr: function() { + var xhr = $.ajaxSettings.xhr(); + xhr.upload.onloadstart = actualOptions.loadstartEventHandler; + xhr.upload.onprogress = actualOptions.progressEventHandler; + return xhr; + }, + data: blob, + cache: false, + processData: false + }); +} + +function addInputAvatar(inputEl) { +// var clearedFileInput = $(inputEl).clone().val(''); + + if (inputEl.files) { + // upload files using ajax + uploadAndAttachFiles(inputEl.files, inputEl); + // $(inputEl).remove(); + } else { + // browser not supporting the file API, upload on form submission + var avatarId; + var aFilename = inputEl.value.split(/\/|\\/); + avatarId = addFile(inputEl, { name: aFilename[ aFilename.length - 1 ] }, false); + if (avatarId) { + $(inputEl).attr({ name: 'avatar[file]', style: 'display:none;' }).appendTo('#avatar_image'); + } + } + + //clearedFileInput.insertAfter('#avatars_fields'); +} + + +function uploadAndAttachFiles(files, inputEl) { + + var maxFileSize = $(inputEl).data('max-file-size'); + var maxFileSizeExceeded = $(inputEl).data('max-file-size-message'); + + var sizeExceeded = false; + $.each(files, function() { + if (this.size && maxFileSize && this.size > parseInt(maxFileSize)) {sizeExceeded=true;} + }); + if (sizeExceeded) { + window.alert(maxFileSizeExceeded); + } else { + $.each(files, function() {addFile(inputEl, this, true);}); + } +} + +function handleFileDropEvent(e) { + + $(this).removeClass('fileover'); + blockEventPropagation(e); + + if ($.inArray('Files', e.dataTransfer.types) > -1) { + uploadAndAttachFiles(e.dataTransfer.files, $('input:file.file_selector')); + } +} + +function dragOverHandler(e) { + $(this).addClass('fileover'); + blockEventPropagation(e); +} + +function dragOutHandler(e) { + $(this).removeClass('fileover'); + blockEventPropagation(e); +} + +function setupFileDrop() { + if (window.File && window.FileList && window.ProgressEvent && window.FormData) { + + $.event.fixHooks.drop = { props: [ 'dataTransfer' ] }; + + $('form div.box').has('input:file').each(function() { + $(this).on({ + dragover: dragOverHandler, + dragleave: dragOutHandler, + drop: handleFileDropEvent + }); + }); + } +} + +$(document).ready(setupFileDrop); diff --git a/public/javascripts/context_menu.js b/public/javascripts/context_menu.js new file mode 100644 index 00000000..a3e1545b --- /dev/null +++ b/public/javascripts/context_menu.js @@ -0,0 +1,236 @@ +var contextMenuObserving; +var contextMenuUrl; + +function contextMenuRightClick(event) { + var target = $(event.target); + if (target.is('a')) {return;} + var tr = target.parents('tr').first(); + if (!tr.hasClass('hascontextmenu')) {return;} + event.preventDefault(); + if (!contextMenuIsSelected(tr)) { + contextMenuUnselectAll(); + contextMenuAddSelection(tr); + contextMenuSetLastSelected(tr); + } + contextMenuShow(event); +} + +function contextMenuClick(event) { + var target = $(event.target); + var lastSelected; + + if (target.is('a') && target.hasClass('submenu')) { + event.preventDefault(); + return; + } + contextMenuHide(); + if (target.is('a') || target.is('img')) { return; } + if (event.which == 1 || (navigator.appVersion.match(/\bMSIE\b/))) { + var tr = target.parents('tr').first(); + if (tr.length && tr.hasClass('hascontextmenu')) { + // a row was clicked, check if the click was on checkbox + if (target.is('input')) { + // a checkbox may be clicked + if (target.attr('checked')) { + tr.addClass('context-menu-selection'); + } else { + tr.removeClass('context-menu-selection'); + } + } else { + if (event.ctrlKey || event.metaKey) { + contextMenuToggleSelection(tr); + } else if (event.shiftKey) { + lastSelected = contextMenuLastSelected(); + if (lastSelected.length) { + var toggling = false; + $('.hascontextmenu').each(function(){ + if (toggling || $(this).is(tr)) { + contextMenuAddSelection($(this)); + } + if ($(this).is(tr) || $(this).is(lastSelected)) { + toggling = !toggling; + } + }); + } else { + contextMenuAddSelection(tr); + } + } else { + contextMenuUnselectAll(); + contextMenuAddSelection(tr); + } + contextMenuSetLastSelected(tr); + } + } else { + // click is outside the rows + if (target.is('a') && (target.hasClass('disabled') || target.hasClass('submenu'))) { + event.preventDefault(); + } else { + contextMenuUnselectAll(); + } + } + } +} + +function contextMenuCreate() { + if ($('#context-menu').length < 1) { + var menu = document.createElement("div"); + menu.setAttribute("id", "context-menu"); + menu.setAttribute("style", "display:none;"); + document.getElementById("content").appendChild(menu); + } +} + +function contextMenuShow(event) { + var mouse_x = event.pageX; + var mouse_y = event.pageY; + var render_x = mouse_x; + var render_y = mouse_y; + var dims; + var menu_width; + var menu_height; + var window_width; + var window_height; + var max_width; + var max_height; + + $('#context-menu').css('left', (render_x + 'px')); + $('#context-menu').css('top', (render_y + 'px')); + $('#context-menu').html(''); + + $.ajax({ + url: contextMenuUrl, + data: $(event.target).parents('form').first().serialize(), + success: function(data, textStatus, jqXHR) { + $('#context-menu').html(data); + menu_width = $('#context-menu').width(); + menu_height = $('#context-menu').height(); + max_width = mouse_x + 2*menu_width; + max_height = mouse_y + menu_height; + + var ws = window_size(); + window_width = ws.width; + window_height = ws.height; + + /* display the menu above and/or to the left of the click if needed */ + if (max_width > window_width) { + render_x -= menu_width; + $('#context-menu').addClass('reverse-x'); + } else { + $('#context-menu').removeClass('reverse-x'); + } + if (max_height > window_height) { + render_y -= menu_height; + $('#context-menu').addClass('reverse-y'); + } else { + $('#context-menu').removeClass('reverse-y'); + } + if (render_x <= 0) render_x = 1; + if (render_y <= 0) render_y = 1; + $('#context-menu').css('left', (render_x + 'px')); + $('#context-menu').css('top', (render_y + 'px')); + $('#context-menu').show(); + + //if (window.parseStylesheets) { window.parseStylesheets(); } // IE + + } + }); +} + +function contextMenuSetLastSelected(tr) { + $('.cm-last').removeClass('cm-last'); + tr.addClass('cm-last'); +} + +function contextMenuLastSelected() { + return $('.cm-last').first(); +} + +function contextMenuUnselectAll() { + $('.hascontextmenu').each(function(){ + contextMenuRemoveSelection($(this)); + }); + $('.cm-last').removeClass('cm-last'); +} + +function contextMenuHide() { + $('#context-menu').hide(); +} + +function contextMenuToggleSelection(tr) { + if (contextMenuIsSelected(tr)) { + contextMenuRemoveSelection(tr); + } else { + contextMenuAddSelection(tr); + } +} + +function contextMenuAddSelection(tr) { + tr.addClass('context-menu-selection'); + contextMenuCheckSelectionBox(tr, true); + contextMenuClearDocumentSelection(); +} + +function contextMenuRemoveSelection(tr) { + tr.removeClass('context-menu-selection'); + contextMenuCheckSelectionBox(tr, false); +} + +function contextMenuIsSelected(tr) { + return tr.hasClass('context-menu-selection'); +} + +function contextMenuCheckSelectionBox(tr, checked) { + tr.find('input[type=checkbox]').attr('checked', checked); +} + +function contextMenuClearDocumentSelection() { + // TODO + if (document.selection) { + document.selection.empty(); // IE + } else { + window.getSelection().removeAllRanges(); + } +} + +function contextMenuInit(url) { + contextMenuUrl = url; + contextMenuCreate(); + contextMenuUnselectAll(); + + if (!contextMenuObserving) { + $(document).click(contextMenuClick); + $(document).contextmenu(contextMenuRightClick); + contextMenuObserving = true; + } +} + +function toggleIssuesSelection(el) { + var boxes = $(el).parents('form').find('input[type=checkbox]'); + var all_checked = true; + boxes.each(function(){ if (!$(this).attr('checked')) { all_checked = false; } }); + boxes.each(function(){ + if (all_checked) { + $(this).removeAttr('checked'); + $(this).parents('tr').removeClass('context-menu-selection'); + } else if (!$(this).attr('checked')) { + $(this).attr('checked', true); + $(this).parents('tr').addClass('context-menu-selection'); + } + }); +} + +function window_size() { + var w; + var h; + if (window.innerWidth) { + w = window.innerWidth; + h = window.innerHeight; + } else if (document.documentElement) { + w = document.documentElement.clientWidth; + h = document.documentElement.clientHeight; + } else { + w = document.body.clientWidth; + h = document.body.clientHeight; + } + return {width: w, height: h}; +} diff --git a/public/javascripts/gantt.js b/public/javascripts/gantt.js new file mode 100644 index 00000000..ba0af9eb --- /dev/null +++ b/public/javascripts/gantt.js @@ -0,0 +1,172 @@ +var draw_gantt = null; +var draw_top; +var draw_right; +var draw_left; + +var rels_stroke_width = 2; + +function setDrawArea() { + draw_top = $("#gantt_draw_area").position().top; + draw_right = $("#gantt_draw_area").width(); + draw_left = $("#gantt_area").scrollLeft(); +} + +function getRelationsArray() { + var arr = new Array(); + $.each($('div.task_todo[data-rels]'), function(index_div, element) { + var element_id = $(element).attr("id"); + if (element_id != null) { + var issue_id = element_id.replace("task-todo-issue-", ""); + var data_rels = $(element).data("rels"); + for (rel_type_key in data_rels) { + $.each(data_rels[rel_type_key], function(index_issue, element_issue) { + arr.push({issue_from: issue_id, issue_to: element_issue, + rel_type: rel_type_key}); + }); + } + } + }); + return arr; +} + +function drawRelations() { + var arr = getRelationsArray(); + $.each(arr, function(index_issue, element_issue) { + var issue_from = $("#task-todo-issue-" + element_issue["issue_from"]); + var issue_to = $("#task-todo-issue-" + element_issue["issue_to"]); + if (issue_from.size() == 0 || issue_to.size() == 0) { + return; + } + var issue_height = issue_from.height(); + var issue_from_top = issue_from.position().top + (issue_height / 2) - draw_top; + var issue_from_right = issue_from.position().left + issue_from.width(); + var issue_to_top = issue_to.position().top + (issue_height / 2) - draw_top; + var issue_to_left = issue_to.position().left; + var color = issue_relation_type[element_issue["rel_type"]]["color"]; + var landscape_margin = issue_relation_type[element_issue["rel_type"]]["landscape_margin"]; + var issue_from_right_rel = issue_from_right + landscape_margin; + var issue_to_left_rel = issue_to_left - landscape_margin; + draw_gantt.path(["M", issue_from_right + draw_left, issue_from_top, + "L", issue_from_right_rel + draw_left, issue_from_top]) + .attr({stroke: color, + "stroke-width": rels_stroke_width + }); + if (issue_from_right_rel < issue_to_left_rel) { + draw_gantt.path(["M", issue_from_right_rel + draw_left, issue_from_top, + "L", issue_from_right_rel + draw_left, issue_to_top]) + .attr({stroke: color, + "stroke-width": rels_stroke_width + }); + draw_gantt.path(["M", issue_from_right_rel + draw_left, issue_to_top, + "L", issue_to_left + draw_left, issue_to_top]) + .attr({stroke: color, + "stroke-width": rels_stroke_width + }); + } else { + var issue_middle_top = issue_to_top + + (issue_height * + ((issue_from_top > issue_to_top) ? 1 : -1)); + draw_gantt.path(["M", issue_from_right_rel + draw_left, issue_from_top, + "L", issue_from_right_rel + draw_left, issue_middle_top]) + .attr({stroke: color, + "stroke-width": rels_stroke_width + }); + draw_gantt.path(["M", issue_from_right_rel + draw_left, issue_middle_top, + "L", issue_to_left_rel + draw_left, issue_middle_top]) + .attr({stroke: color, + "stroke-width": rels_stroke_width + }); + draw_gantt.path(["M", issue_to_left_rel + draw_left, issue_middle_top, + "L", issue_to_left_rel + draw_left, issue_to_top]) + .attr({stroke: color, + "stroke-width": rels_stroke_width + }); + draw_gantt.path(["M", issue_to_left_rel + draw_left, issue_to_top, + "L", issue_to_left + draw_left, issue_to_top]) + .attr({stroke: color, + "stroke-width": rels_stroke_width + }); + } + draw_gantt.path(["M", issue_to_left + draw_left, issue_to_top, + "l", -4 * rels_stroke_width, -2 * rels_stroke_width, + "l", 0, 4 * rels_stroke_width, "z"]) + .attr({stroke: "none", + fill: color, + "stroke-linecap": "butt", + "stroke-linejoin": "miter" + }); + }); +} + +function getProgressLinesArray() { + var arr = new Array(); + var today_left = $('#today_line').position().left; + arr.push({left: today_left, top: 0}); + $.each($('div.issue-subject, div.version-name'), function(index, element) { + var t = $(element).position().top - draw_top ; + var h = ($(element).height() / 9); + var element_top_upper = t - h; + var element_top_center = t + (h * 3); + var element_top_lower = t + (h * 8); + var issue_closed = $(element).children('span').hasClass('issue-closed'); + var version_closed = $(element).children('span').hasClass('version-closed'); + if (issue_closed || version_closed) { + arr.push({left: today_left, top: element_top_center}); + } else { + var issue_done = $("#task-done-" + $(element).attr("id")); + var is_behind_start = $(element).children('span').hasClass('behind-start-date'); + var is_over_end = $(element).children('span').hasClass('over-end-date'); + if (is_over_end) { + arr.push({left: draw_right, top: element_top_upper, is_right_edge: true}); + arr.push({left: draw_right, top: element_top_lower, is_right_edge: true, none_stroke: true}); + } else if (issue_done.size() > 0) { + var done_left = issue_done.first().position().left + + issue_done.first().width(); + arr.push({left: done_left, top: element_top_center}); + } else if (is_behind_start) { + arr.push({left: 0 , top: element_top_upper, is_left_edge: true}); + arr.push({left: 0 , top: element_top_lower, is_left_edge: true, none_stroke: true}); + } else { + var todo_left = today_left; + var issue_todo = $("#task-todo-" + $(element).attr("id")); + if (issue_todo.size() > 0){ + todo_left = issue_todo.first().position().left; + } + arr.push({left: Math.min(today_left, todo_left), top: element_top_center}); + } + } + }); + return arr; +} + +function drawGanttProgressLines() { + var arr = getProgressLinesArray(); + var color = $("#today_line") + .css("border-left-color"); + var i; + for(i = 1 ; i < arr.length ; i++) { + if (!("none_stroke" in arr[i]) && + (!("is_right_edge" in arr[i - 1] && "is_right_edge" in arr[i]) && + !("is_left_edge" in arr[i - 1] && "is_left_edge" in arr[i])) + ) { + var x1 = (arr[i - 1].left == 0) ? 0 : arr[i - 1].left + draw_left; + var x2 = (arr[i].left == 0) ? 0 : arr[i].left + draw_left; + draw_gantt.path(["M", x1, arr[i - 1].top, + "L", x2, arr[i].top]) + .attr({stroke: color, "stroke-width": 2}); + } + } +} + +function drawGanttHandler() { + var folder = document.getElementById('gantt_draw_area'); + if(draw_gantt != null) + draw_gantt.clear(); + else + draw_gantt = Raphael(folder); + setDrawArea(); + if ($("#draw_progress_line").attr('checked')) + drawGanttProgressLines(); + if ($("#draw_rels").attr('checked')) + drawRelations(); +} diff --git a/public/javascripts/i18n/jquery.ui.datepicker-ar.js b/public/javascripts/i18n/jquery.ui.datepicker-ar.js new file mode 100644 index 00000000..8a9218d8 --- /dev/null +++ b/public/javascripts/i18n/jquery.ui.datepicker-ar.js @@ -0,0 +1,23 @@ +/* Arabic Translation for jQuery UI date picker plugin. */ +/* Khaled Alhourani -- me@khaledalhourani.com */ +/* NOTE: monthNames are the original months names and they are the Arabic names, not the new months name فبراير - يناير and there isn't any Arabic roots for these months */ +jQuery(function($){ + $.datepicker.regional['ar'] = { + closeText: 'إغلاق', + prevText: '<السابق', + nextText: 'التالي>', + currentText: 'اليوم', + monthNames: ['كانون الثاني', 'شباط', 'آذار', 'نيسان', 'مايو', 'حزيران', + 'تموز', 'آب', 'أيلول', 'تشرين الأول', 'تشرين الثاني', 'كانون الأول'], + monthNamesShort: ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12'], + dayNames: ['الأحد', 'الاثنين', 'الثلاثاء', 'الأربعاء', 'الخميس', 'الجمعة', 'السبت'], + dayNamesShort: ['الأحد', 'الاثنين', 'الثلاثاء', 'الأربعاء', 'الخميس', 'الجمعة', 'السبت'], + dayNamesMin: ['ح', 'ن', 'ث', 'ر', 'خ', 'ج', 'س'], + weekHeader: 'أسبوع', + dateFormat: 'dd/mm/yy', + firstDay: 6, + isRTL: true, + showMonthAfterYear: false, + yearSuffix: ''}; + $.datepicker.setDefaults($.datepicker.regional['ar']); +}); \ No newline at end of file diff --git a/public/javascripts/i18n/jquery.ui.datepicker-az.js b/public/javascripts/i18n/jquery.ui.datepicker-az.js new file mode 100644 index 00000000..a133a9eb --- /dev/null +++ b/public/javascripts/i18n/jquery.ui.datepicker-az.js @@ -0,0 +1,23 @@ +/* Azerbaijani (UTF-8) initialisation for the jQuery UI date picker plugin. */ +/* Written by Jamil Najafov (necefov33@gmail.com). */ +jQuery(function($) { + $.datepicker.regional['az'] = { + closeText: 'Bağla', + prevText: '<Geri', + nextText: 'İrəli>', + currentText: 'Bugün', + monthNames: ['Yanvar','Fevral','Mart','Aprel','May','İyun', + 'İyul','Avqust','Sentyabr','Oktyabr','Noyabr','Dekabr'], + monthNamesShort: ['Yan','Fev','Mar','Apr','May','İyun', + 'İyul','Avq','Sen','Okt','Noy','Dek'], + dayNames: ['Bazar','Bazar ertəsi','Çərşənbə axşamı','Çərşənbə','Cümə axşamı','Cümə','Şənbə'], + dayNamesShort: ['B','Be','Ça','Ç','Ca','C','Ş'], + dayNamesMin: ['B','B','Ç','С','Ç','C','Ş'], + weekHeader: 'Hf', + dateFormat: 'dd.mm.yy', + firstDay: 1, + isRTL: false, + showMonthAfterYear: false, + yearSuffix: ''}; + $.datepicker.setDefaults($.datepicker.regional['az']); +}); diff --git a/public/javascripts/i18n/jquery.ui.datepicker-bg.js b/public/javascripts/i18n/jquery.ui.datepicker-bg.js new file mode 100644 index 00000000..c19d20fb --- /dev/null +++ b/public/javascripts/i18n/jquery.ui.datepicker-bg.js @@ -0,0 +1,24 @@ +/* Bulgarian initialisation for the jQuery UI date picker plugin. */ +/* Written by Stoyan Kyosev (http://svest.org). */ +jQuery(function($){ + $.datepicker.regional['bg'] = { + closeText: 'затвори', + prevText: '<назад', + nextText: 'напред>', + nextBigText: '>>', + currentText: 'днес', + monthNames: ['Януари','Февруари','Март','Април','Май','Юни', + 'Юли','Август','Септември','Октомври','Ноември','Декември'], + monthNamesShort: ['Яну','Фев','Мар','Апр','Май','Юни', + 'Юли','Авг','Сеп','Окт','Нов','Дек'], + dayNames: ['Неделя','Понеделник','Вторник','Сряда','Четвъртък','Петък','Събота'], + dayNamesShort: ['Нед','Пон','Вто','Сря','Чет','Пет','Съб'], + dayNamesMin: ['Не','По','Вт','Ср','Че','Пе','Съ'], + weekHeader: 'Wk', + dateFormat: 'dd.mm.yy', + firstDay: 1, + isRTL: false, + showMonthAfterYear: false, + yearSuffix: ''}; + $.datepicker.setDefaults($.datepicker.regional['bg']); +}); diff --git a/public/javascripts/i18n/jquery.ui.datepicker-bs.js b/public/javascripts/i18n/jquery.ui.datepicker-bs.js new file mode 100644 index 00000000..d4dc8b0e --- /dev/null +++ b/public/javascripts/i18n/jquery.ui.datepicker-bs.js @@ -0,0 +1,23 @@ +/* Bosnian i18n for the jQuery UI date picker plugin. */ +/* Written by Kenan Konjo. */ +jQuery(function($){ + $.datepicker.regional['bs'] = { + closeText: 'Zatvori', + prevText: '<', + nextText: '>', + currentText: 'Danas', + monthNames: ['Januar','Februar','Mart','April','Maj','Juni', + 'Juli','August','Septembar','Oktobar','Novembar','Decembar'], + monthNamesShort: ['Jan','Feb','Mar','Apr','Maj','Jun', + 'Jul','Aug','Sep','Okt','Nov','Dec'], + dayNames: ['Nedelja','Ponedeljak','Utorak','Srijeda','Četvrtak','Petak','Subota'], + dayNamesShort: ['Ned','Pon','Uto','Sri','Čet','Pet','Sub'], + dayNamesMin: ['Ne','Po','Ut','Sr','Če','Pe','Su'], + weekHeader: 'Wk', + dateFormat: 'dd.mm.yy', + firstDay: 1, + isRTL: false, + showMonthAfterYear: false, + yearSuffix: ''}; + $.datepicker.setDefaults($.datepicker.regional['bs']); +}); \ No newline at end of file diff --git a/public/javascripts/i18n/jquery.ui.datepicker-ca.js b/public/javascripts/i18n/jquery.ui.datepicker-ca.js new file mode 100644 index 00000000..b128e699 --- /dev/null +++ b/public/javascripts/i18n/jquery.ui.datepicker-ca.js @@ -0,0 +1,23 @@ +/* Inicialització en català per a l'extenció 'calendar' per jQuery. */ +/* Writers: (joan.leon@gmail.com). */ +jQuery(function($){ + $.datepicker.regional['ca'] = { + closeText: 'Tancar', + prevText: '<Ant', + nextText: 'Seg>', + currentText: 'Avui', + monthNames: ['Gener','Febrer','Març','Abril','Maig','Juny', + 'Juliol','Agost','Setembre','Octubre','Novembre','Desembre'], + monthNamesShort: ['Gen','Feb','Mar','Abr','Mai','Jun', + 'Jul','Ago','Set','Oct','Nov','Des'], + dayNames: ['Diumenge','Dilluns','Dimarts','Dimecres','Dijous','Divendres','Dissabte'], + dayNamesShort: ['Dug','Dln','Dmt','Dmc','Djs','Dvn','Dsb'], + dayNamesMin: ['Dg','Dl','Dt','Dc','Dj','Dv','Ds'], + weekHeader: 'Sm', + dateFormat: 'dd/mm/yy', + firstDay: 1, + isRTL: false, + showMonthAfterYear: false, + yearSuffix: ''}; + $.datepicker.setDefaults($.datepicker.regional['ca']); +}); \ No newline at end of file diff --git a/public/javascripts/i18n/jquery.ui.datepicker-cs.js b/public/javascripts/i18n/jquery.ui.datepicker-cs.js new file mode 100644 index 00000000..9805bcdb --- /dev/null +++ b/public/javascripts/i18n/jquery.ui.datepicker-cs.js @@ -0,0 +1,23 @@ +/* Czech initialisation for the jQuery UI date picker plugin. */ +/* Written by Tomas Muller (tomas@tomas-muller.net). */ +jQuery(function($){ + $.datepicker.regional['cs'] = { + closeText: 'Zavřít', + prevText: '<Dříve', + nextText: 'Později>', + currentText: 'Nyní', + monthNames: ['leden','únor','březen','duben','květen','červen', + 'červenec','srpen','září','říjen','listopad','prosinec'], + monthNamesShort: ['led','úno','bře','dub','kvě','čer', + 'čvc','srp','zář','říj','lis','pro'], + dayNames: ['neděle', 'pondělí', 'úterý', 'středa', 'čtvrtek', 'pátek', 'sobota'], + dayNamesShort: ['ne', 'po', 'út', 'st', 'čt', 'pá', 'so'], + dayNamesMin: ['ne','po','út','st','čt','pá','so'], + weekHeader: 'Týd', + dateFormat: 'dd.mm.yy', + firstDay: 1, + isRTL: false, + showMonthAfterYear: false, + yearSuffix: ''}; + $.datepicker.setDefaults($.datepicker.regional['cs']); +}); diff --git a/public/javascripts/i18n/jquery.ui.datepicker-da.js b/public/javascripts/i18n/jquery.ui.datepicker-da.js new file mode 100644 index 00000000..176044e1 --- /dev/null +++ b/public/javascripts/i18n/jquery.ui.datepicker-da.js @@ -0,0 +1,23 @@ +/* Danish initialisation for the jQuery UI date picker plugin. */ +/* Written by Jan Christensen ( deletestuff@gmail.com). */ +jQuery(function($){ + $.datepicker.regional['da'] = { + closeText: 'Luk', + prevText: '<Forrige', + nextText: 'Næste>', + currentText: 'Idag', + monthNames: ['Januar','Februar','Marts','April','Maj','Juni', + 'Juli','August','September','Oktober','November','December'], + monthNamesShort: ['Jan','Feb','Mar','Apr','Maj','Jun', + 'Jul','Aug','Sep','Okt','Nov','Dec'], + dayNames: ['Søndag','Mandag','Tirsdag','Onsdag','Torsdag','Fredag','Lørdag'], + dayNamesShort: ['Søn','Man','Tir','Ons','Tor','Fre','Lør'], + dayNamesMin: ['Sø','Ma','Ti','On','To','Fr','Lø'], + weekHeader: 'Uge', + dateFormat: 'dd-mm-yy', + firstDay: 1, + isRTL: false, + showMonthAfterYear: false, + yearSuffix: ''}; + $.datepicker.setDefaults($.datepicker.regional['da']); +}); diff --git a/public/javascripts/i18n/jquery.ui.datepicker-de.js b/public/javascripts/i18n/jquery.ui.datepicker-de.js new file mode 100644 index 00000000..f3ef9e82 --- /dev/null +++ b/public/javascripts/i18n/jquery.ui.datepicker-de.js @@ -0,0 +1,23 @@ +/* German initialisation for the jQuery UI date picker plugin. */ +/* Written by Milian Wolff (mail@milianw.de). */ +jQuery(function($){ + $.datepicker.regional['de'] = { + closeText: 'schließen', + prevText: '<zurück', + nextText: 'Vor>', + currentText: 'heute', + monthNames: ['Januar','Februar','März','April','Mai','Juni', + 'Juli','August','September','Oktober','November','Dezember'], + monthNamesShort: ['Jan','Feb','Mär','Apr','Mai','Jun', + 'Jul','Aug','Sep','Okt','Nov','Dez'], + dayNames: ['Sonntag','Montag','Dienstag','Mittwoch','Donnerstag','Freitag','Samstag'], + dayNamesShort: ['So','Mo','Di','Mi','Do','Fr','Sa'], + dayNamesMin: ['So','Mo','Di','Mi','Do','Fr','Sa'], + weekHeader: 'KW', + dateFormat: 'dd.mm.yy', + firstDay: 1, + isRTL: false, + showMonthAfterYear: false, + yearSuffix: ''}; + $.datepicker.setDefaults($.datepicker.regional['de']); +}); diff --git a/public/javascripts/i18n/jquery.ui.datepicker-el.js b/public/javascripts/i18n/jquery.ui.datepicker-el.js new file mode 100644 index 00000000..6d775f99 --- /dev/null +++ b/public/javascripts/i18n/jquery.ui.datepicker-el.js @@ -0,0 +1,23 @@ +/* Greek (el) initialisation for the jQuery UI date picker plugin. */ +/* Written by Alex Cicovic (http://www.alexcicovic.com) */ +jQuery(function($){ + $.datepicker.regional['el'] = { + closeText: 'Κλείσιμο', + prevText: 'Προηγούμενος', + nextText: 'Επόμενος', + currentText: 'Τρέχων Μήνας', + monthNames: ['Ιανουάριος','Φεβρουάριος','Μάρτιος','Απρίλιος','Μάιος','Ιούνιος', + 'Ιούλιος','Αύγουστος','Σεπτέμβριος','Οκτώβριος','Νοέμβριος','Δεκέμβριος'], + monthNamesShort: ['Ιαν','Φεβ','Μαρ','Απρ','Μαι','Ιουν', + 'Ιουλ','Αυγ','Σεπ','Οκτ','Νοε','Δεκ'], + dayNames: ['Κυριακή','Δευτέρα','Τρίτη','Τετάρτη','Πέμπτη','Παρασκευή','Σάββατο'], + dayNamesShort: ['Κυρ','Δευ','Τρι','Τετ','Πεμ','Παρ','Σαβ'], + dayNamesMin: ['Κυ','Δε','Τρ','Τε','Πε','Πα','Σα'], + weekHeader: 'Εβδ', + dateFormat: 'dd/mm/yy', + firstDay: 1, + isRTL: false, + showMonthAfterYear: false, + yearSuffix: ''}; + $.datepicker.setDefaults($.datepicker.regional['el']); +}); \ No newline at end of file diff --git a/public/javascripts/i18n/jquery.ui.datepicker-en-GB.js b/public/javascripts/i18n/jquery.ui.datepicker-en-GB.js new file mode 100644 index 00000000..16a096e7 --- /dev/null +++ b/public/javascripts/i18n/jquery.ui.datepicker-en-GB.js @@ -0,0 +1,23 @@ +/* English/UK initialisation for the jQuery UI date picker plugin. */ +/* Written by Stuart. */ +jQuery(function($){ + $.datepicker.regional['en-GB'] = { + closeText: 'Done', + prevText: 'Prev', + nextText: 'Next', + currentText: 'Today', + monthNames: ['January','February','March','April','May','June', + 'July','August','September','October','November','December'], + monthNamesShort: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', + 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], + dayNames: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'], + dayNamesShort: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'], + dayNamesMin: ['Su','Mo','Tu','We','Th','Fr','Sa'], + weekHeader: 'Wk', + dateFormat: 'dd/mm/yy', + firstDay: 1, + isRTL: false, + showMonthAfterYear: false, + yearSuffix: ''}; + $.datepicker.setDefaults($.datepicker.regional['en-GB']); +}); diff --git a/public/javascripts/i18n/jquery.ui.datepicker-es.js b/public/javascripts/i18n/jquery.ui.datepicker-es.js new file mode 100644 index 00000000..a02133de --- /dev/null +++ b/public/javascripts/i18n/jquery.ui.datepicker-es.js @@ -0,0 +1,23 @@ +/* Inicialización en español para la extensión 'UI date picker' para jQuery. */ +/* Traducido por Vester (xvester@gmail.com). */ +jQuery(function($){ + $.datepicker.regional['es'] = { + closeText: 'Cerrar', + prevText: '<Ant', + nextText: 'Sig>', + currentText: 'Hoy', + monthNames: ['Enero','Febrero','Marzo','Abril','Mayo','Junio', + 'Julio','Agosto','Septiembre','Octubre','Noviembre','Diciembre'], + monthNamesShort: ['Ene','Feb','Mar','Abr','May','Jun', + 'Jul','Ago','Sep','Oct','Nov','Dic'], + dayNames: ['Domingo','Lunes','Martes','Miércoles','Jueves','Viernes','Sábado'], + dayNamesShort: ['Dom','Lun','Mar','Mié','Juv','Vie','Sáb'], + dayNamesMin: ['Do','Lu','Ma','Mi','Ju','Vi','Sá'], + weekHeader: 'Sm', + dateFormat: 'dd/mm/yy', + firstDay: 1, + isRTL: false, + showMonthAfterYear: false, + yearSuffix: ''}; + $.datepicker.setDefaults($.datepicker.regional['es']); +}); \ No newline at end of file diff --git a/public/javascripts/i18n/jquery.ui.datepicker-et.js b/public/javascripts/i18n/jquery.ui.datepicker-et.js new file mode 100644 index 00000000..32702b24 --- /dev/null +++ b/public/javascripts/i18n/jquery.ui.datepicker-et.js @@ -0,0 +1,23 @@ +/* Estonian initialisation for the jQuery UI date picker plugin. */ +/* Written by Mart Sõmermaa (mrts.pydev at gmail com). */ +jQuery(function($){ + $.datepicker.regional['et'] = { + closeText: 'Sulge', + prevText: 'Eelnev', + nextText: 'Järgnev', + currentText: 'Täna', + monthNames: ['Jaanuar','Veebruar','Märts','Aprill','Mai','Juuni', + 'Juuli','August','September','Oktoober','November','Detsember'], + monthNamesShort: ['Jaan', 'Veebr', 'Märts', 'Apr', 'Mai', 'Juuni', + 'Juuli', 'Aug', 'Sept', 'Okt', 'Nov', 'Dets'], + dayNames: ['Pühapäev', 'Esmaspäev', 'Teisipäev', 'Kolmapäev', 'Neljapäev', 'Reede', 'Laupäev'], + dayNamesShort: ['Pühap', 'Esmasp', 'Teisip', 'Kolmap', 'Neljap', 'Reede', 'Laup'], + dayNamesMin: ['P','E','T','K','N','R','L'], + weekHeader: 'näd', + dateFormat: 'dd.mm.yy', + firstDay: 1, + isRTL: false, + showMonthAfterYear: false, + yearSuffix: ''}; + $.datepicker.setDefaults($.datepicker.regional['et']); +}); \ No newline at end of file diff --git a/public/javascripts/i18n/jquery.ui.datepicker-eu.js b/public/javascripts/i18n/jquery.ui.datepicker-eu.js new file mode 100644 index 00000000..ff66e494 --- /dev/null +++ b/public/javascripts/i18n/jquery.ui.datepicker-eu.js @@ -0,0 +1,23 @@ +/* Euskarako oinarria 'UI date picker' jquery-ko extentsioarentzat */ +/* Karrikas-ek itzulia (karrikas@karrikas.com) */ +jQuery(function($){ + $.datepicker.regional['eu'] = { + closeText: 'Egina', + prevText: '<Aur', + nextText: 'Hur>', + currentText: 'Gaur', + monthNames: ['urtarrila','otsaila','martxoa','apirila','maiatza','ekaina', + 'uztaila','abuztua','iraila','urria','azaroa','abendua'], + monthNamesShort: ['urt.','ots.','mar.','api.','mai.','eka.', + 'uzt.','abu.','ira.','urr.','aza.','abe.'], + dayNames: ['igandea','astelehena','asteartea','asteazkena','osteguna','ostirala','larunbata'], + dayNamesShort: ['ig.','al.','ar.','az.','og.','ol.','lr.'], + dayNamesMin: ['ig','al','ar','az','og','ol','lr'], + weekHeader: 'As', + dateFormat: 'yy-mm-dd', + firstDay: 1, + isRTL: false, + showMonthAfterYear: false, + yearSuffix: ''}; + $.datepicker.setDefaults($.datepicker.regional['eu']); +}); \ No newline at end of file diff --git a/public/javascripts/i18n/jquery.ui.datepicker-fa.js b/public/javascripts/i18n/jquery.ui.datepicker-fa.js new file mode 100644 index 00000000..be8acd2a --- /dev/null +++ b/public/javascripts/i18n/jquery.ui.datepicker-fa.js @@ -0,0 +1,59 @@ +/* Persian (Farsi) Translation for the jQuery UI date picker plugin. */ +/* Javad Mowlanezhad -- jmowla@gmail.com */ +/* Jalali calendar should supported soon! (Its implemented but I have to test it) */ +jQuery(function($) { + $.datepicker.regional['fa'] = { + closeText: 'بستن', + prevText: '<قبلی', + nextText: 'بعدی>', + currentText: 'امروز', + monthNames: [ + 'فروردين', + 'ارديبهشت', + 'خرداد', + 'تير', + 'مرداد', + 'شهريور', + 'مهر', + 'آبان', + 'آذر', + 'دی', + 'بهمن', + 'اسفند' + ], + monthNamesShort: ['1','2','3','4','5','6','7','8','9','10','11','12'], + dayNames: [ + 'يکشنبه', + 'دوشنبه', + 'سه‌شنبه', + 'چهارشنبه', + 'پنجشنبه', + 'جمعه', + 'شنبه' + ], + dayNamesShort: [ + 'ی', + 'د', + 'س', + 'چ', + 'پ', + 'ج', + 'ش' + ], + dayNamesMin: [ + 'ی', + 'د', + 'س', + 'چ', + 'پ', + 'ج', + 'ش' + ], + weekHeader: 'هف', + dateFormat: 'yy/mm/dd', + firstDay: 6, + isRTL: true, + showMonthAfterYear: false, + yearSuffix: ''}; + $.datepicker.setDefaults($.datepicker.regional['fa']); +}); \ No newline at end of file diff --git a/public/javascripts/i18n/jquery.ui.datepicker-fi.js b/public/javascripts/i18n/jquery.ui.datepicker-fi.js new file mode 100644 index 00000000..4c5adda3 --- /dev/null +++ b/public/javascripts/i18n/jquery.ui.datepicker-fi.js @@ -0,0 +1,23 @@ +/* Finnish initialisation for the jQuery UI date picker plugin. */ +/* Written by Harri Kilpiö (harrikilpio@gmail.com). */ +jQuery(function($){ + $.datepicker.regional['fi'] = { + closeText: 'Sulje', + prevText: '«Edellinen', + nextText: 'Seuraava»', + currentText: 'Tänään', + monthNames: ['Tammikuu','Helmikuu','Maaliskuu','Huhtikuu','Toukokuu','Kesäkuu', + 'Heinäkuu','Elokuu','Syyskuu','Lokakuu','Marraskuu','Joulukuu'], + monthNamesShort: ['Tammi','Helmi','Maalis','Huhti','Touko','Kesä', + 'Heinä','Elo','Syys','Loka','Marras','Joulu'], + dayNamesShort: ['Su','Ma','Ti','Ke','To','Pe','La'], + dayNames: ['Sunnuntai','Maanantai','Tiistai','Keskiviikko','Torstai','Perjantai','Lauantai'], + dayNamesMin: ['Su','Ma','Ti','Ke','To','Pe','La'], + weekHeader: 'Vk', + dateFormat: 'dd.mm.yy', + firstDay: 1, + isRTL: false, + showMonthAfterYear: false, + yearSuffix: ''}; + $.datepicker.setDefaults($.datepicker.regional['fi']); +}); diff --git a/public/javascripts/i18n/jquery.ui.datepicker-fr.js b/public/javascripts/i18n/jquery.ui.datepicker-fr.js new file mode 100644 index 00000000..7e793639 --- /dev/null +++ b/public/javascripts/i18n/jquery.ui.datepicker-fr.js @@ -0,0 +1,25 @@ +/* French initialisation for the jQuery UI date picker plugin. */ +/* Written by Keith Wood (kbwood{at}iinet.com.au), + Stéphane Nahmani (sholby@sholby.net), + Stéphane Raimbault */ +jQuery(function($){ + $.datepicker.regional['fr'] = { + closeText: 'Fermer', + prevText: 'Précédent', + nextText: 'Suivant', + currentText: 'Aujourd\'hui', + monthNames: ['Janvier','Février','Mars','Avril','Mai','Juin', + 'Juillet','Août','Septembre','Octobre','Novembre','Décembre'], + monthNamesShort: ['Janv.','Févr.','Mars','Avril','Mai','Juin', + 'Juil.','Août','Sept.','Oct.','Nov.','Déc.'], + dayNames: ['Dimanche','Lundi','Mardi','Mercredi','Jeudi','Vendredi','Samedi'], + dayNamesShort: ['Dim.','Lun.','Mar.','Mer.','Jeu.','Ven.','Sam.'], + dayNamesMin: ['D','L','M','M','J','V','S'], + weekHeader: 'Sem.', + dateFormat: 'dd/mm/yy', + firstDay: 1, + isRTL: false, + showMonthAfterYear: false, + yearSuffix: ''}; + $.datepicker.setDefaults($.datepicker.regional['fr']); +}); diff --git a/public/javascripts/i18n/jquery.ui.datepicker-gl.js b/public/javascripts/i18n/jquery.ui.datepicker-gl.js new file mode 100644 index 00000000..278403e8 --- /dev/null +++ b/public/javascripts/i18n/jquery.ui.datepicker-gl.js @@ -0,0 +1,23 @@ +/* Galician localization for 'UI date picker' jQuery extension. */ +/* Translated by Jorge Barreiro . */ +jQuery(function($){ + $.datepicker.regional['gl'] = { + closeText: 'Pechar', + prevText: '<Ant', + nextText: 'Seg>', + currentText: 'Hoxe', + monthNames: ['Xaneiro','Febreiro','Marzo','Abril','Maio','Xuño', + 'Xullo','Agosto','Setembro','Outubro','Novembro','Decembro'], + monthNamesShort: ['Xan','Feb','Mar','Abr','Mai','Xuñ', + 'Xul','Ago','Set','Out','Nov','Dec'], + dayNames: ['Domingo','Luns','Martes','Mércores','Xoves','Venres','Sábado'], + dayNamesShort: ['Dom','Lun','Mar','Mér','Xov','Ven','Sáb'], + dayNamesMin: ['Do','Lu','Ma','Mé','Xo','Ve','Sá'], + weekHeader: 'Sm', + dateFormat: 'dd/mm/yy', + firstDay: 1, + isRTL: false, + showMonthAfterYear: false, + yearSuffix: ''}; + $.datepicker.setDefaults($.datepicker.regional['gl']); +}); \ No newline at end of file diff --git a/public/javascripts/i18n/jquery.ui.datepicker-he.js b/public/javascripts/i18n/jquery.ui.datepicker-he.js new file mode 100644 index 00000000..135cdec1 --- /dev/null +++ b/public/javascripts/i18n/jquery.ui.datepicker-he.js @@ -0,0 +1,23 @@ +/* Hebrew initialisation for the UI Datepicker extension. */ +/* Written by Amir Hardon (ahardon at gmail dot com). */ +jQuery(function($){ + $.datepicker.regional['he'] = { + closeText: 'סגור', + prevText: '<הקודם', + nextText: 'הבא>', + currentText: 'היום', + monthNames: ['ינואר','פברואר','מרץ','אפריל','מאי','יוני', + 'יולי','אוגוסט','ספטמבר','אוקטובר','נובמבר','דצמבר'], + monthNamesShort: ['ינו','פבר','מרץ','אפר','מאי','יוני', + 'יולי','אוג','ספט','אוק','נוב','דצמ'], + dayNames: ['ראשון','שני','שלישי','רביעי','חמישי','שישי','שבת'], + dayNamesShort: ['א\'','ב\'','ג\'','ד\'','ה\'','ו\'','שבת'], + dayNamesMin: ['א\'','ב\'','ג\'','ד\'','ה\'','ו\'','שבת'], + weekHeader: 'Wk', + dateFormat: 'dd/mm/yy', + firstDay: 0, + isRTL: true, + showMonthAfterYear: false, + yearSuffix: ''}; + $.datepicker.setDefaults($.datepicker.regional['he']); +}); diff --git a/public/javascripts/i18n/jquery.ui.datepicker-hr.js b/public/javascripts/i18n/jquery.ui.datepicker-hr.js new file mode 100644 index 00000000..1eb3dd92 --- /dev/null +++ b/public/javascripts/i18n/jquery.ui.datepicker-hr.js @@ -0,0 +1,23 @@ +/* Croatian i18n for the jQuery UI date picker plugin. */ +/* Written by Vjekoslav Nesek. */ +jQuery(function($){ + $.datepicker.regional['hr'] = { + closeText: 'Zatvori', + prevText: '<', + nextText: '>', + currentText: 'Danas', + monthNames: ['Siječanj','Veljača','Ožujak','Travanj','Svibanj','Lipanj', + 'Srpanj','Kolovoz','Rujan','Listopad','Studeni','Prosinac'], + monthNamesShort: ['Sij','Velj','Ožu','Tra','Svi','Lip', + 'Srp','Kol','Ruj','Lis','Stu','Pro'], + dayNames: ['Nedjelja','Ponedjeljak','Utorak','Srijeda','Četvrtak','Petak','Subota'], + dayNamesShort: ['Ned','Pon','Uto','Sri','Čet','Pet','Sub'], + dayNamesMin: ['Ne','Po','Ut','Sr','Če','Pe','Su'], + weekHeader: 'Tje', + dateFormat: 'dd.mm.yy.', + firstDay: 1, + isRTL: false, + showMonthAfterYear: false, + yearSuffix: ''}; + $.datepicker.setDefaults($.datepicker.regional['hr']); +}); \ No newline at end of file diff --git a/public/javascripts/i18n/jquery.ui.datepicker-hu.js b/public/javascripts/i18n/jquery.ui.datepicker-hu.js new file mode 100644 index 00000000..b28c268c --- /dev/null +++ b/public/javascripts/i18n/jquery.ui.datepicker-hu.js @@ -0,0 +1,23 @@ +/* Hungarian initialisation for the jQuery UI date picker plugin. */ +/* Written by Istvan Karaszi (jquery@spam.raszi.hu). */ +jQuery(function($){ + $.datepicker.regional['hu'] = { + closeText: 'bezár', + prevText: 'vissza', + nextText: 'előre', + currentText: 'ma', + monthNames: ['Január', 'Február', 'Március', 'Április', 'Május', 'Június', + 'Július', 'Augusztus', 'Szeptember', 'Október', 'November', 'December'], + monthNamesShort: ['Jan', 'Feb', 'Már', 'Ápr', 'Máj', 'Jún', + 'Júl', 'Aug', 'Szep', 'Okt', 'Nov', 'Dec'], + dayNames: ['Vasárnap', 'Hétfő', 'Kedd', 'Szerda', 'Csütörtök', 'Péntek', 'Szombat'], + dayNamesShort: ['Vas', 'Hét', 'Ked', 'Sze', 'Csü', 'Pén', 'Szo'], + dayNamesMin: ['V', 'H', 'K', 'Sze', 'Cs', 'P', 'Szo'], + weekHeader: 'Hét', + dateFormat: 'yy.mm.dd.', + firstDay: 1, + isRTL: false, + showMonthAfterYear: true, + yearSuffix: ''}; + $.datepicker.setDefaults($.datepicker.regional['hu']); +}); diff --git a/public/javascripts/i18n/jquery.ui.datepicker-id.js b/public/javascripts/i18n/jquery.ui.datepicker-id.js new file mode 100644 index 00000000..c626fbb7 --- /dev/null +++ b/public/javascripts/i18n/jquery.ui.datepicker-id.js @@ -0,0 +1,23 @@ +/* Indonesian initialisation for the jQuery UI date picker plugin. */ +/* Written by Deden Fathurahman (dedenf@gmail.com). */ +jQuery(function($){ + $.datepicker.regional['id'] = { + closeText: 'Tutup', + prevText: '<mundur', + nextText: 'maju>', + currentText: 'hari ini', + monthNames: ['Januari','Februari','Maret','April','Mei','Juni', + 'Juli','Agustus','September','Oktober','Nopember','Desember'], + monthNamesShort: ['Jan','Feb','Mar','Apr','Mei','Jun', + 'Jul','Agus','Sep','Okt','Nop','Des'], + dayNames: ['Minggu','Senin','Selasa','Rabu','Kamis','Jumat','Sabtu'], + dayNamesShort: ['Min','Sen','Sel','Rab','kam','Jum','Sab'], + dayNamesMin: ['Mg','Sn','Sl','Rb','Km','jm','Sb'], + weekHeader: 'Mg', + dateFormat: 'dd/mm/yy', + firstDay: 0, + isRTL: false, + showMonthAfterYear: false, + yearSuffix: ''}; + $.datepicker.setDefaults($.datepicker.regional['id']); +}); \ No newline at end of file diff --git a/public/javascripts/i18n/jquery.ui.datepicker-it.js b/public/javascripts/i18n/jquery.ui.datepicker-it.js new file mode 100644 index 00000000..59da2df6 --- /dev/null +++ b/public/javascripts/i18n/jquery.ui.datepicker-it.js @@ -0,0 +1,23 @@ +/* Italian initialisation for the jQuery UI date picker plugin. */ +/* Written by Antonello Pasella (antonello.pasella@gmail.com). */ +jQuery(function($){ + $.datepicker.regional['it'] = { + closeText: 'Chiudi', + prevText: '<Prec', + nextText: 'Succ>', + currentText: 'Oggi', + monthNames: ['Gennaio','Febbraio','Marzo','Aprile','Maggio','Giugno', + 'Luglio','Agosto','Settembre','Ottobre','Novembre','Dicembre'], + monthNamesShort: ['Gen','Feb','Mar','Apr','Mag','Giu', + 'Lug','Ago','Set','Ott','Nov','Dic'], + dayNames: ['Domenica','Lunedì','Martedì','Mercoledì','Giovedì','Venerdì','Sabato'], + dayNamesShort: ['Dom','Lun','Mar','Mer','Gio','Ven','Sab'], + dayNamesMin: ['Do','Lu','Ma','Me','Gi','Ve','Sa'], + weekHeader: 'Sm', + dateFormat: 'dd/mm/yy', + firstDay: 1, + isRTL: false, + showMonthAfterYear: false, + yearSuffix: ''}; + $.datepicker.setDefaults($.datepicker.regional['it']); +}); diff --git a/public/javascripts/i18n/jquery.ui.datepicker-ja.js b/public/javascripts/i18n/jquery.ui.datepicker-ja.js new file mode 100644 index 00000000..7eb4268d --- /dev/null +++ b/public/javascripts/i18n/jquery.ui.datepicker-ja.js @@ -0,0 +1,23 @@ +/* Japanese initialisation for the jQuery UI date picker plugin. */ +/* Written by Kentaro SATO (kentaro@ranvis.com). */ +jQuery(function($){ + $.datepicker.regional['ja'] = { + closeText: '閉じる', + prevText: '<前', + nextText: '次>', + currentText: '今日', + monthNames: ['1月','2月','3月','4月','5月','6月', + '7月','8月','9月','10月','11月','12月'], + monthNamesShort: ['1月','2月','3月','4月','5月','6月', + '7月','8月','9月','10月','11月','12月'], + dayNames: ['日曜日','月曜日','火曜日','水曜日','木曜日','金曜日','土曜日'], + dayNamesShort: ['日','月','火','水','木','金','土'], + dayNamesMin: ['日','月','火','水','木','金','土'], + weekHeader: '週', + dateFormat: 'yy/mm/dd', + firstDay: 0, + isRTL: false, + showMonthAfterYear: true, + yearSuffix: '年'}; + $.datepicker.setDefaults($.datepicker.regional['ja']); +}); \ No newline at end of file diff --git a/public/javascripts/i18n/jquery.ui.datepicker-ko.js b/public/javascripts/i18n/jquery.ui.datepicker-ko.js new file mode 100644 index 00000000..04112424 --- /dev/null +++ b/public/javascripts/i18n/jquery.ui.datepicker-ko.js @@ -0,0 +1,23 @@ +/* Korean initialisation for the jQuery calendar extension. */ +/* Written by DaeKwon Kang (ncrash.dk@gmail.com), Edited by Genie. */ +jQuery(function($){ + $.datepicker.regional['ko'] = { + closeText: '닫기', + prevText: '이전달', + nextText: '다음달', + currentText: '오늘', + monthNames: ['1월','2월','3월','4월','5월','6월', + '7월','8월','9월','10월','11월','12월'], + monthNamesShort: ['1월','2월','3월','4월','5월','6월', + '7월','8월','9월','10월','11월','12월'], + dayNames: ['일요일','월요일','화요일','수요일','목요일','금요일','토요일'], + dayNamesShort: ['일','월','화','수','목','금','토'], + dayNamesMin: ['일','월','화','수','목','금','토'], + weekHeader: 'Wk', + dateFormat: 'yy-mm-dd', + firstDay: 0, + isRTL: false, + showMonthAfterYear: true, + yearSuffix: '년'}; + $.datepicker.setDefaults($.datepicker.regional['ko']); +}); \ No newline at end of file diff --git a/public/javascripts/i18n/jquery.ui.datepicker-lt.js b/public/javascripts/i18n/jquery.ui.datepicker-lt.js new file mode 100644 index 00000000..67d5119c --- /dev/null +++ b/public/javascripts/i18n/jquery.ui.datepicker-lt.js @@ -0,0 +1,23 @@ +/* Lithuanian (UTF-8) initialisation for the jQuery UI date picker plugin. */ +/* @author Arturas Paleicikas */ +jQuery(function($){ + $.datepicker.regional['lt'] = { + closeText: 'Uždaryti', + prevText: '<Atgal', + nextText: 'Pirmyn>', + currentText: 'Šiandien', + monthNames: ['Sausis','Vasaris','Kovas','Balandis','Gegužė','Birželis', + 'Liepa','Rugpjūtis','Rugsėjis','Spalis','Lapkritis','Gruodis'], + monthNamesShort: ['Sau','Vas','Kov','Bal','Geg','Bir', + 'Lie','Rugp','Rugs','Spa','Lap','Gru'], + dayNames: ['sekmadienis','pirmadienis','antradienis','trečiadienis','ketvirtadienis','penktadienis','šeštadienis'], + dayNamesShort: ['sek','pir','ant','tre','ket','pen','šeš'], + dayNamesMin: ['Se','Pr','An','Tr','Ke','Pe','Še'], + weekHeader: 'Wk', + dateFormat: 'yy-mm-dd', + firstDay: 1, + isRTL: false, + showMonthAfterYear: false, + yearSuffix: ''}; + $.datepicker.setDefaults($.datepicker.regional['lt']); +}); \ No newline at end of file diff --git a/public/javascripts/i18n/jquery.ui.datepicker-lv.js b/public/javascripts/i18n/jquery.ui.datepicker-lv.js new file mode 100644 index 00000000..003934e7 --- /dev/null +++ b/public/javascripts/i18n/jquery.ui.datepicker-lv.js @@ -0,0 +1,23 @@ +/* Latvian (UTF-8) initialisation for the jQuery UI date picker plugin. */ +/* @author Arturas Paleicikas */ +jQuery(function($){ + $.datepicker.regional['lv'] = { + closeText: 'Aizvērt', + prevText: 'Iepr', + nextText: 'Nāka', + currentText: 'Šodien', + monthNames: ['Janvāris','Februāris','Marts','Aprīlis','Maijs','Jūnijs', + 'Jūlijs','Augusts','Septembris','Oktobris','Novembris','Decembris'], + monthNamesShort: ['Jan','Feb','Mar','Apr','Mai','Jūn', + 'Jūl','Aug','Sep','Okt','Nov','Dec'], + dayNames: ['svētdiena','pirmdiena','otrdiena','trešdiena','ceturtdiena','piektdiena','sestdiena'], + dayNamesShort: ['svt','prm','otr','tre','ctr','pkt','sst'], + dayNamesMin: ['Sv','Pr','Ot','Tr','Ct','Pk','Ss'], + weekHeader: 'Nav', + dateFormat: 'dd-mm-yy', + firstDay: 1, + isRTL: false, + showMonthAfterYear: false, + yearSuffix: ''}; + $.datepicker.setDefaults($.datepicker.regional['lv']); +}); \ No newline at end of file diff --git a/public/javascripts/i18n/jquery.ui.datepicker-mk.js b/public/javascripts/i18n/jquery.ui.datepicker-mk.js new file mode 100644 index 00000000..02853255 --- /dev/null +++ b/public/javascripts/i18n/jquery.ui.datepicker-mk.js @@ -0,0 +1,23 @@ +/* Macedonian i18n for the jQuery UI date picker plugin. */ +/* Written by Stojce Slavkovski. */ +jQuery(function($){ + $.datepicker.regional['mk'] = { + closeText: 'Затвори', + prevText: '<', + nextText: '>', + currentText: 'Денес', + monthNames: ['Јануари','Февруари','Март','Април','Мај','Јуни', + 'Јули','Август','Септември','Октомври','Ноември','Декември'], + monthNamesShort: ['Јан','Фев','Мар','Апр','Мај','Јун', + 'Јул','Авг','Сеп','Окт','Ное','Дек'], + dayNames: ['Недела','Понеделник','Вторник','Среда','Четврток','Петок','Сабота'], + dayNamesShort: ['Нед','Пон','Вто','Сре','Чет','Пет','Саб'], + dayNamesMin: ['Не','По','Вт','Ср','Че','Пе','Са'], + weekHeader: 'Сед', + dateFormat: 'dd.mm.yy', + firstDay: 1, + isRTL: false, + showMonthAfterYear: false, + yearSuffix: ''}; + $.datepicker.setDefaults($.datepicker.regional['mk']); +}); diff --git a/public/javascripts/i18n/jquery.ui.datepicker-nl.js b/public/javascripts/i18n/jquery.ui.datepicker-nl.js new file mode 100644 index 00000000..781fe619 --- /dev/null +++ b/public/javascripts/i18n/jquery.ui.datepicker-nl.js @@ -0,0 +1,23 @@ +/* Dutch (UTF-8) initialisation for the jQuery UI date picker plugin. */ +/* Written by Mathias Bynens */ +jQuery(function($){ + $.datepicker.regional.nl = { + closeText: 'Sluiten', + prevText: '←', + nextText: '→', + currentText: 'Vandaag', + monthNames: ['januari', 'februari', 'maart', 'april', 'mei', 'juni', + 'juli', 'augustus', 'september', 'oktober', 'november', 'december'], + monthNamesShort: ['jan', 'feb', 'mrt', 'apr', 'mei', 'jun', + 'jul', 'aug', 'sep', 'okt', 'nov', 'dec'], + dayNames: ['zondag', 'maandag', 'dinsdag', 'woensdag', 'donderdag', 'vrijdag', 'zaterdag'], + dayNamesShort: ['zon', 'maa', 'din', 'woe', 'don', 'vri', 'zat'], + dayNamesMin: ['zo', 'ma', 'di', 'wo', 'do', 'vr', 'za'], + weekHeader: 'Wk', + dateFormat: 'dd-mm-yy', + firstDay: 1, + isRTL: false, + showMonthAfterYear: false, + yearSuffix: ''}; + $.datepicker.setDefaults($.datepicker.regional.nl); +}); \ No newline at end of file diff --git a/public/javascripts/i18n/jquery.ui.datepicker-no.js b/public/javascripts/i18n/jquery.ui.datepicker-no.js new file mode 100644 index 00000000..2507043a --- /dev/null +++ b/public/javascripts/i18n/jquery.ui.datepicker-no.js @@ -0,0 +1,23 @@ +/* Norwegian initialisation for the jQuery UI date picker plugin. */ +/* Written by Naimdjon Takhirov (naimdjon@gmail.com). */ + +jQuery(function($){ + $.datepicker.regional['no'] = { + closeText: 'Lukk', + prevText: '«Forrige', + nextText: 'Neste»', + currentText: 'I dag', + monthNames: ['januar','februar','mars','april','mai','juni','juli','august','september','oktober','november','desember'], + monthNamesShort: ['jan','feb','mar','apr','mai','jun','jul','aug','sep','okt','nov','des'], + dayNamesShort: ['søn','man','tir','ons','tor','fre','lør'], + dayNames: ['søndag','mandag','tirsdag','onsdag','torsdag','fredag','lørdag'], + dayNamesMin: ['sø','ma','ti','on','to','fr','lø'], + weekHeader: 'Uke', + dateFormat: 'dd.mm.yy', + firstDay: 1, + isRTL: false, + showMonthAfterYear: false, + yearSuffix: '' + }; + $.datepicker.setDefaults($.datepicker.regional['no']); +}); diff --git a/public/javascripts/i18n/jquery.ui.datepicker-pl.js b/public/javascripts/i18n/jquery.ui.datepicker-pl.js new file mode 100644 index 00000000..61fa29cc --- /dev/null +++ b/public/javascripts/i18n/jquery.ui.datepicker-pl.js @@ -0,0 +1,23 @@ +/* Polish initialisation for the jQuery UI date picker plugin. */ +/* Written by Jacek Wysocki (jacek.wysocki@gmail.com). */ +jQuery(function($){ + $.datepicker.regional['pl'] = { + closeText: 'Zamknij', + prevText: '<Poprzedni', + nextText: 'Następny>', + currentText: 'Dziś', + monthNames: ['Styczeń','Luty','Marzec','Kwiecień','Maj','Czerwiec', + 'Lipiec','Sierpień','Wrzesień','Październik','Listopad','Grudzień'], + monthNamesShort: ['Sty','Lu','Mar','Kw','Maj','Cze', + 'Lip','Sie','Wrz','Pa','Lis','Gru'], + dayNames: ['Niedziela','Poniedziałek','Wtorek','Środa','Czwartek','Piątek','Sobota'], + dayNamesShort: ['Nie','Pn','Wt','Śr','Czw','Pt','So'], + dayNamesMin: ['N','Pn','Wt','Śr','Cz','Pt','So'], + weekHeader: 'Tydz', + dateFormat: 'dd.mm.yy', + firstDay: 1, + isRTL: false, + showMonthAfterYear: false, + yearSuffix: ''}; + $.datepicker.setDefaults($.datepicker.regional['pl']); +}); diff --git a/public/javascripts/i18n/jquery.ui.datepicker-pt-BR.js b/public/javascripts/i18n/jquery.ui.datepicker-pt-BR.js new file mode 100644 index 00000000..3cc8c796 --- /dev/null +++ b/public/javascripts/i18n/jquery.ui.datepicker-pt-BR.js @@ -0,0 +1,23 @@ +/* Brazilian initialisation for the jQuery UI date picker plugin. */ +/* Written by Leonildo Costa Silva (leocsilva@gmail.com). */ +jQuery(function($){ + $.datepicker.regional['pt-BR'] = { + closeText: 'Fechar', + prevText: '<Anterior', + nextText: 'Próximo>', + currentText: 'Hoje', + monthNames: ['Janeiro','Fevereiro','Março','Abril','Maio','Junho', + 'Julho','Agosto','Setembro','Outubro','Novembro','Dezembro'], + monthNamesShort: ['Jan','Fev','Mar','Abr','Mai','Jun', + 'Jul','Ago','Set','Out','Nov','Dez'], + dayNames: ['Domingo','Segunda-feira','Terça-feira','Quarta-feira','Quinta-feira','Sexta-feira','Sábado'], + dayNamesShort: ['Dom','Seg','Ter','Qua','Qui','Sex','Sáb'], + dayNamesMin: ['Dom','Seg','Ter','Qua','Qui','Sex','Sáb'], + weekHeader: 'Sm', + dateFormat: 'dd/mm/yy', + firstDay: 0, + isRTL: false, + showMonthAfterYear: false, + yearSuffix: ''}; + $.datepicker.setDefaults($.datepicker.regional['pt-BR']); +}); \ No newline at end of file diff --git a/public/javascripts/i18n/jquery.ui.datepicker-pt.js b/public/javascripts/i18n/jquery.ui.datepicker-pt.js new file mode 100644 index 00000000..999f20e3 --- /dev/null +++ b/public/javascripts/i18n/jquery.ui.datepicker-pt.js @@ -0,0 +1,22 @@ +/* Portuguese initialisation for the jQuery UI date picker plugin. */ +jQuery(function($){ + $.datepicker.regional['pt'] = { + closeText: 'Fechar', + prevText: '<Anterior', + nextText: 'Seguinte', + currentText: 'Hoje', + monthNames: ['Janeiro','Fevereiro','Março','Abril','Maio','Junho', + 'Julho','Agosto','Setembro','Outubro','Novembro','Dezembro'], + monthNamesShort: ['Jan','Fev','Mar','Abr','Mai','Jun', + 'Jul','Ago','Set','Out','Nov','Dez'], + dayNames: ['Domingo','Segunda-feira','Terça-feira','Quarta-feira','Quinta-feira','Sexta-feira','Sábado'], + dayNamesShort: ['Dom','Seg','Ter','Qua','Qui','Sex','Sáb'], + dayNamesMin: ['Dom','Seg','Ter','Qua','Qui','Sex','Sáb'], + weekHeader: 'Sem', + dateFormat: 'dd/mm/yy', + firstDay: 0, + isRTL: false, + showMonthAfterYear: false, + yearSuffix: ''}; + $.datepicker.setDefaults($.datepicker.regional['pt']); +}); diff --git a/public/javascripts/i18n/jquery.ui.datepicker-ro.js b/public/javascripts/i18n/jquery.ui.datepicker-ro.js new file mode 100644 index 00000000..6b140aff --- /dev/null +++ b/public/javascripts/i18n/jquery.ui.datepicker-ro.js @@ -0,0 +1,26 @@ +/* Romanian initialisation for the jQuery UI date picker plugin. + * + * Written by Edmond L. (ll_edmond@walla.com) + * and Ionut G. Stan (ionut.g.stan@gmail.com) + */ +jQuery(function($){ + $.datepicker.regional['ro'] = { + closeText: 'Închide', + prevText: '« Luna precedentă', + nextText: 'Luna următoare »', + currentText: 'Azi', + monthNames: ['Ianuarie','Februarie','Martie','Aprilie','Mai','Iunie', + 'Iulie','August','Septembrie','Octombrie','Noiembrie','Decembrie'], + monthNamesShort: ['Ian', 'Feb', 'Mar', 'Apr', 'Mai', 'Iun', + 'Iul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], + dayNames: ['Duminică', 'Luni', 'Marţi', 'Miercuri', 'Joi', 'Vineri', 'Sâmbătă'], + dayNamesShort: ['Dum', 'Lun', 'Mar', 'Mie', 'Joi', 'Vin', 'Sâm'], + dayNamesMin: ['Du','Lu','Ma','Mi','Jo','Vi','Sâ'], + weekHeader: 'Săpt', + dateFormat: 'dd.mm.yy', + firstDay: 1, + isRTL: false, + showMonthAfterYear: false, + yearSuffix: ''}; + $.datepicker.setDefaults($.datepicker.regional['ro']); +}); diff --git a/public/javascripts/i18n/jquery.ui.datepicker-ru.js b/public/javascripts/i18n/jquery.ui.datepicker-ru.js new file mode 100644 index 00000000..50a46135 --- /dev/null +++ b/public/javascripts/i18n/jquery.ui.datepicker-ru.js @@ -0,0 +1,23 @@ +/* Russian (UTF-8) initialisation for the jQuery UI date picker plugin. */ +/* Written by Andrew Stromnov (stromnov@gmail.com). */ +jQuery(function($){ + $.datepicker.regional['ru'] = { + closeText: 'Закрыть', + prevText: '<Пред', + nextText: 'След>', + currentText: 'Сегодня', + monthNames: ['Январь','Февраль','Март','Апрель','Май','Июнь', + 'Июль','Август','Сентябрь','Октябрь','Ноябрь','Декабрь'], + monthNamesShort: ['Янв','Фев','Мар','Апр','Май','Июн', + 'Июл','Авг','Сен','Окт','Ноя','Дек'], + dayNames: ['воскресенье','понедельник','вторник','среда','четверг','пятница','суббота'], + dayNamesShort: ['вск','пнд','втр','срд','чтв','птн','сбт'], + dayNamesMin: ['Вс','Пн','Вт','Ср','Чт','Пт','Сб'], + weekHeader: 'Нед', + dateFormat: 'dd.mm.yy', + firstDay: 1, + isRTL: false, + showMonthAfterYear: false, + yearSuffix: ''}; + $.datepicker.setDefaults($.datepicker.regional['ru']); +}); \ No newline at end of file diff --git a/public/javascripts/i18n/jquery.ui.datepicker-sk.js b/public/javascripts/i18n/jquery.ui.datepicker-sk.js new file mode 100644 index 00000000..078d1b0f --- /dev/null +++ b/public/javascripts/i18n/jquery.ui.datepicker-sk.js @@ -0,0 +1,23 @@ +/* Slovak initialisation for the jQuery UI date picker plugin. */ +/* Written by Vojtech Rinik (vojto@hmm.sk). */ +jQuery(function($){ + $.datepicker.regional['sk'] = { + closeText: 'Zavrieť', + prevText: '<Predchádzajúci', + nextText: 'Nasledujúci>', + currentText: 'Dnes', + monthNames: ['Január','Február','Marec','Apríl','Máj','Jún', + 'Júl','August','September','Október','November','December'], + monthNamesShort: ['Jan','Feb','Mar','Apr','Máj','Jún', + 'Júl','Aug','Sep','Okt','Nov','Dec'], + dayNames: ['Nedeľa','Pondelok','Utorok','Streda','Štvrtok','Piatok','Sobota'], + dayNamesShort: ['Ned','Pon','Uto','Str','Štv','Pia','Sob'], + dayNamesMin: ['Ne','Po','Ut','St','Št','Pia','So'], + weekHeader: 'Ty', + dateFormat: 'dd.mm.yy', + firstDay: 1, + isRTL: false, + showMonthAfterYear: false, + yearSuffix: ''}; + $.datepicker.setDefaults($.datepicker.regional['sk']); +}); diff --git a/public/javascripts/i18n/jquery.ui.datepicker-sl.js b/public/javascripts/i18n/jquery.ui.datepicker-sl.js new file mode 100644 index 00000000..51655019 --- /dev/null +++ b/public/javascripts/i18n/jquery.ui.datepicker-sl.js @@ -0,0 +1,24 @@ +/* Slovenian initialisation for the jQuery UI date picker plugin. */ +/* Written by Jaka Jancar (jaka@kubje.org). */ +/* c = č, s = š z = ž C = Č S = Š Z = Ž */ +jQuery(function($){ + $.datepicker.regional['sl'] = { + closeText: 'Zapri', + prevText: '<Prejšnji', + nextText: 'Naslednji>', + currentText: 'Trenutni', + monthNames: ['Januar','Februar','Marec','April','Maj','Junij', + 'Julij','Avgust','September','Oktober','November','December'], + monthNamesShort: ['Jan','Feb','Mar','Apr','Maj','Jun', + 'Jul','Avg','Sep','Okt','Nov','Dec'], + dayNames: ['Nedelja','Ponedeljek','Torek','Sreda','Četrtek','Petek','Sobota'], + dayNamesShort: ['Ned','Pon','Tor','Sre','Čet','Pet','Sob'], + dayNamesMin: ['Ne','Po','To','Sr','Če','Pe','So'], + weekHeader: 'Teden', + dateFormat: 'dd.mm.yy', + firstDay: 1, + isRTL: false, + showMonthAfterYear: false, + yearSuffix: ''}; + $.datepicker.setDefaults($.datepicker.regional['sl']); +}); diff --git a/public/javascripts/i18n/jquery.ui.datepicker-sq.js b/public/javascripts/i18n/jquery.ui.datepicker-sq.js new file mode 100644 index 00000000..21974c56 --- /dev/null +++ b/public/javascripts/i18n/jquery.ui.datepicker-sq.js @@ -0,0 +1,23 @@ +/* Albanian initialisation for the jQuery UI date picker plugin. */ +/* Written by Flakron Bytyqi (flakron@gmail.com). */ +jQuery(function($){ + $.datepicker.regional['sq'] = { + closeText: 'mbylle', + prevText: '<mbrapa', + nextText: 'Përpara>', + currentText: 'sot', + monthNames: ['Janar','Shkurt','Mars','Prill','Maj','Qershor', + 'Korrik','Gusht','Shtator','Tetor','Nëntor','Dhjetor'], + monthNamesShort: ['Jan','Shk','Mar','Pri','Maj','Qer', + 'Kor','Gus','Sht','Tet','Nën','Dhj'], + dayNames: ['E Diel','E Hënë','E Martë','E Mërkurë','E Enjte','E Premte','E Shtune'], + dayNamesShort: ['Di','Hë','Ma','Më','En','Pr','Sh'], + dayNamesMin: ['Di','Hë','Ma','Më','En','Pr','Sh'], + weekHeader: 'Ja', + dateFormat: 'dd.mm.yy', + firstDay: 1, + isRTL: false, + showMonthAfterYear: false, + yearSuffix: ''}; + $.datepicker.setDefaults($.datepicker.regional['sq']); +}); diff --git a/public/javascripts/i18n/jquery.ui.datepicker-sr.js b/public/javascripts/i18n/jquery.ui.datepicker-sr.js new file mode 100644 index 00000000..0bd240e6 --- /dev/null +++ b/public/javascripts/i18n/jquery.ui.datepicker-sr.js @@ -0,0 +1,23 @@ +/* Serbian i18n for the jQuery UI date picker plugin. */ +/* Written by Dejan Dimić. */ +jQuery(function($){ + $.datepicker.regional['sr'] = { + closeText: 'Затвори', + prevText: '<', + nextText: '>', + currentText: 'Данас', + monthNames: ['Јануар','Фебруар','Март','Април','Мај','Јун', + 'Јул','Август','Септембар','Октобар','Новембар','Децембар'], + monthNamesShort: ['Јан','Феб','Мар','Апр','Мај','Јун', + 'Јул','Авг','Сеп','Окт','Нов','Дец'], + dayNames: ['Недеља','Понедељак','Уторак','Среда','Четвртак','Петак','Субота'], + dayNamesShort: ['Нед','Пон','Уто','Сре','Чет','Пет','Суб'], + dayNamesMin: ['Не','По','Ут','Ср','Че','Пе','Су'], + weekHeader: 'Сед', + dateFormat: 'dd/mm/yy', + firstDay: 1, + isRTL: false, + showMonthAfterYear: false, + yearSuffix: ''}; + $.datepicker.setDefaults($.datepicker.regional['sr']); +}); diff --git a/public/javascripts/i18n/jquery.ui.datepicker-sv.js b/public/javascripts/i18n/jquery.ui.datepicker-sv.js new file mode 100644 index 00000000..e5f549fb --- /dev/null +++ b/public/javascripts/i18n/jquery.ui.datepicker-sv.js @@ -0,0 +1,23 @@ +/* Swedish initialisation for the jQuery UI date picker plugin. */ +/* Written by Anders Ekdahl ( anders@nomadiz.se). */ +jQuery(function($){ + $.datepicker.regional['sv'] = { + closeText: 'Stäng', + prevText: '«Förra', + nextText: 'Nästa»', + currentText: 'Idag', + monthNames: ['Januari','Februari','Mars','April','Maj','Juni', + 'Juli','Augusti','September','Oktober','November','December'], + monthNamesShort: ['Jan','Feb','Mar','Apr','Maj','Jun', + 'Jul','Aug','Sep','Okt','Nov','Dec'], + dayNamesShort: ['Sön','Mån','Tis','Ons','Tor','Fre','Lör'], + dayNames: ['Söndag','Måndag','Tisdag','Onsdag','Torsdag','Fredag','Lördag'], + dayNamesMin: ['Sö','Må','Ti','On','To','Fr','Lö'], + weekHeader: 'Ve', + dateFormat: 'yy-mm-dd', + firstDay: 1, + isRTL: false, + showMonthAfterYear: false, + yearSuffix: ''}; + $.datepicker.setDefaults($.datepicker.regional['sv']); +}); diff --git a/public/javascripts/i18n/jquery.ui.datepicker-th.js b/public/javascripts/i18n/jquery.ui.datepicker-th.js new file mode 100644 index 00000000..2e5300cf --- /dev/null +++ b/public/javascripts/i18n/jquery.ui.datepicker-th.js @@ -0,0 +1,23 @@ +/* Thai initialisation for the jQuery UI date picker plugin. */ +/* Written by pipo (pipo@sixhead.com). */ +jQuery(function($){ + $.datepicker.regional['th'] = { + closeText: 'ปิด', + prevText: '« ย้อน', + nextText: 'ถัดไป »', + currentText: 'วันนี้', + monthNames: ['มกราคม','กุมภาพันธ์','มีนาคม','เมษายน','พฤษภาคม','มิถุนายน', + 'กรกฎาคม','สิงหาคม','กันยายน','ตุลาคม','พฤศจิกายน','ธันวาคม'], + monthNamesShort: ['ม.ค.','ก.พ.','มี.ค.','เม.ย.','พ.ค.','มิ.ย.', + 'ก.ค.','ส.ค.','ก.ย.','ต.ค.','พ.ย.','ธ.ค.'], + dayNames: ['อาทิตย์','จันทร์','อังคาร','พุธ','พฤหัสบดี','ศุกร์','เสาร์'], + dayNamesShort: ['อา.','จ.','อ.','พ.','พฤ.','ศ.','ส.'], + dayNamesMin: ['อา.','จ.','อ.','พ.','พฤ.','ศ.','ส.'], + weekHeader: 'Wk', + dateFormat: 'dd/mm/yy', + firstDay: 0, + isRTL: false, + showMonthAfterYear: false, + yearSuffix: ''}; + $.datepicker.setDefaults($.datepicker.regional['th']); +}); \ No newline at end of file diff --git a/public/javascripts/i18n/jquery.ui.datepicker-tr.js b/public/javascripts/i18n/jquery.ui.datepicker-tr.js new file mode 100644 index 00000000..dedfc7ff --- /dev/null +++ b/public/javascripts/i18n/jquery.ui.datepicker-tr.js @@ -0,0 +1,23 @@ +/* Turkish initialisation for the jQuery UI date picker plugin. */ +/* Written by Izzet Emre Erkan (kara@karalamalar.net). */ +jQuery(function($){ + $.datepicker.regional['tr'] = { + closeText: 'kapat', + prevText: '<geri', + nextText: 'ileri>', + currentText: 'bugün', + monthNames: ['Ocak','Şubat','Mart','Nisan','Mayıs','Haziran', + 'Temmuz','Ağustos','Eylül','Ekim','Kasım','Aralık'], + monthNamesShort: ['Oca','Şub','Mar','Nis','May','Haz', + 'Tem','Ağu','Eyl','Eki','Kas','Ara'], + dayNames: ['Pazar','Pazartesi','Salı','Çarşamba','Perşembe','Cuma','Cumartesi'], + dayNamesShort: ['Pz','Pt','Sa','Ça','Pe','Cu','Ct'], + dayNamesMin: ['Pz','Pt','Sa','Ça','Pe','Cu','Ct'], + weekHeader: 'Hf', + dateFormat: 'dd.mm.yy', + firstDay: 1, + isRTL: false, + showMonthAfterYear: false, + yearSuffix: ''}; + $.datepicker.setDefaults($.datepicker.regional['tr']); +}); \ No newline at end of file diff --git a/public/javascripts/i18n/jquery.ui.datepicker-uk.js b/public/javascripts/i18n/jquery.ui.datepicker-uk.js new file mode 100644 index 00000000..2718f5d1 --- /dev/null +++ b/public/javascripts/i18n/jquery.ui.datepicker-uk.js @@ -0,0 +1,24 @@ +/* Ukrainian (UTF-8) initialisation for the jQuery UI date picker plugin. */ +/* Written by Maxim Drogobitskiy (maxdao@gmail.com). */ +/* Corrected by Igor Milla (igor.fsp.milla@gmail.com). */ +jQuery(function($){ + $.datepicker.regional['uk'] = { + closeText: 'Закрити', + prevText: '<', + nextText: '>', + currentText: 'Сьогодні', + monthNames: ['Січень','Лютий','Березень','Квітень','Травень','Червень', + 'Липень','Серпень','Вересень','Жовтень','Листопад','Грудень'], + monthNamesShort: ['Січ','Лют','Бер','Кві','Тра','Чер', + 'Лип','Сер','Вер','Жов','Лис','Гру'], + dayNames: ['неділя','понеділок','вівторок','середа','четвер','п’ятниця','субота'], + dayNamesShort: ['нед','пнд','вів','срд','чтв','птн','сбт'], + dayNamesMin: ['Нд','Пн','Вт','Ср','Чт','Пт','Сб'], + weekHeader: 'Тиж', + dateFormat: 'dd/mm/yy', + firstDay: 1, + isRTL: false, + showMonthAfterYear: false, + yearSuffix: ''}; + $.datepicker.setDefaults($.datepicker.regional['uk']); +}); \ No newline at end of file diff --git a/public/javascripts/i18n/jquery.ui.datepicker-vi.js b/public/javascripts/i18n/jquery.ui.datepicker-vi.js new file mode 100644 index 00000000..1d8f7bbd --- /dev/null +++ b/public/javascripts/i18n/jquery.ui.datepicker-vi.js @@ -0,0 +1,23 @@ +/* Vietnamese initialisation for the jQuery UI date picker plugin. */ +/* Translated by Le Thanh Huy (lthanhhuy@cit.ctu.edu.vn). */ +jQuery(function($){ + $.datepicker.regional['vi'] = { + closeText: 'Đóng', + prevText: '<Trước', + nextText: 'Tiếp>', + currentText: 'Hôm nay', + monthNames: ['Tháng Một', 'Tháng Hai', 'Tháng Ba', 'Tháng Tư', 'Tháng Năm', 'Tháng Sáu', + 'Tháng Bảy', 'Tháng Tám', 'Tháng Chín', 'Tháng Mười', 'Tháng Mười Một', 'Tháng Mười Hai'], + monthNamesShort: ['Tháng 1', 'Tháng 2', 'Tháng 3', 'Tháng 4', 'Tháng 5', 'Tháng 6', + 'Tháng 7', 'Tháng 8', 'Tháng 9', 'Tháng 10', 'Tháng 11', 'Tháng 12'], + dayNames: ['Chủ Nhật', 'Thứ Hai', 'Thứ Ba', 'Thứ Tư', 'Thứ Năm', 'Thứ Sáu', 'Thứ Bảy'], + dayNamesShort: ['CN', 'T2', 'T3', 'T4', 'T5', 'T6', 'T7'], + dayNamesMin: ['CN', 'T2', 'T3', 'T4', 'T5', 'T6', 'T7'], + weekHeader: 'Tu', + dateFormat: 'dd/mm/yy', + firstDay: 0, + isRTL: false, + showMonthAfterYear: false, + yearSuffix: ''}; + $.datepicker.setDefaults($.datepicker.regional['vi']); +}); diff --git a/public/javascripts/i18n/jquery.ui.datepicker-zh-CN.js b/public/javascripts/i18n/jquery.ui.datepicker-zh-CN.js new file mode 100644 index 00000000..6c4883f5 --- /dev/null +++ b/public/javascripts/i18n/jquery.ui.datepicker-zh-CN.js @@ -0,0 +1,23 @@ +/* Chinese initialisation for the jQuery UI date picker plugin. */ +/* Written by Cloudream (cloudream@gmail.com). */ +jQuery(function($){ + $.datepicker.regional['zh-CN'] = { + closeText: '关闭', + prevText: '<上月', + nextText: '下月>', + currentText: '今天', + monthNames: ['一月','二月','三月','四月','五月','六月', + '七月','八月','九月','十月','十一月','十二月'], + monthNamesShort: ['一','二','三','四','五','六', + '七','八','九','十','十一','十二'], + dayNames: ['星期日','星期一','星期二','星期三','星期四','星期五','星期六'], + dayNamesShort: ['周日','周一','周二','周三','周四','周五','周六'], + dayNamesMin: ['日','一','二','三','四','五','六'], + weekHeader: '周', + dateFormat: 'yy-mm-dd', + firstDay: 1, + isRTL: false, + showMonthAfterYear: true, + yearSuffix: '年'}; + $.datepicker.setDefaults($.datepicker.regional['zh-CN']); +}); diff --git a/public/javascripts/i18n/jquery.ui.datepicker-zh-TW.js b/public/javascripts/i18n/jquery.ui.datepicker-zh-TW.js new file mode 100644 index 00000000..dd51e359 --- /dev/null +++ b/public/javascripts/i18n/jquery.ui.datepicker-zh-TW.js @@ -0,0 +1,23 @@ +/* Chinese initialisation for the jQuery UI date picker plugin. */ +/* Written by Ressol (ressol@gmail.com). */ +jQuery(function($){ + $.datepicker.regional['zh-TW'] = { + closeText: '關閉', + prevText: '<上月', + nextText: '下月>', + currentText: '今天', + monthNames: ['一月','二月','三月','四月','五月','六月', + '七月','八月','九月','十月','十一月','十二月'], + monthNamesShort: ['一','二','三','四','五','六', + '七','八','九','十','十一','十二'], + dayNames: ['星期日','星期一','星期二','星期三','星期四','星期五','星期六'], + dayNamesShort: ['周日','周一','周二','周三','周四','周五','周六'], + dayNamesMin: ['日','一','二','三','四','五','六'], + weekHeader: '周', + dateFormat: 'yy/mm/dd', + firstDay: 1, + isRTL: false, + showMonthAfterYear: true, + yearSuffix: '年'}; + $.datepicker.setDefaults($.datepicker.regional['zh-TW']); +}); diff --git a/public/javascripts/jquery-1.8.3-ui-1.9.2-ujs-2.0.3.js b/public/javascripts/jquery-1.8.3-ui-1.9.2-ujs-2.0.3.js new file mode 100644 index 00000000..5fe1a15e --- /dev/null +++ b/public/javascripts/jquery-1.8.3-ui-1.9.2-ujs-2.0.3.js @@ -0,0 +1,11 @@ +/*! jQuery v1.8.3 jquery.com | jquery.org/license */ +(function(e,t){function _(e){var t=M[e]={};return v.each(e.split(y),function(e,n){t[n]=!0}),t}function H(e,n,r){if(r===t&&e.nodeType===1){var i="data-"+n.replace(P,"-$1").toLowerCase();r=e.getAttribute(i);if(typeof r=="string"){try{r=r==="true"?!0:r==="false"?!1:r==="null"?null:+r+""===r?+r:D.test(r)?v.parseJSON(r):r}catch(s){}v.data(e,n,r)}else r=t}return r}function B(e){var t;for(t in e){if(t==="data"&&v.isEmptyObject(e[t]))continue;if(t!=="toJSON")return!1}return!0}function et(){return!1}function tt(){return!0}function ut(e){return!e||!e.parentNode||e.parentNode.nodeType===11}function at(e,t){do e=e[t];while(e&&e.nodeType!==1);return e}function ft(e,t,n){t=t||0;if(v.isFunction(t))return v.grep(e,function(e,r){var i=!!t.call(e,r,e);return i===n});if(t.nodeType)return v.grep(e,function(e,r){return e===t===n});if(typeof t=="string"){var r=v.grep(e,function(e){return e.nodeType===1});if(it.test(t))return v.filter(t,r,!n);t=v.filter(t,r)}return v.grep(e,function(e,r){return v.inArray(e,t)>=0===n})}function lt(e){var t=ct.split("|"),n=e.createDocumentFragment();if(n.createElement)while(t.length)n.createElement(t.pop());return n}function Lt(e,t){return e.getElementsByTagName(t)[0]||e.appendChild(e.ownerDocument.createElement(t))}function At(e,t){if(t.nodeType!==1||!v.hasData(e))return;var n,r,i,s=v._data(e),o=v._data(t,s),u=s.events;if(u){delete o.handle,o.events={};for(n in u)for(r=0,i=u[n].length;r").appendTo(i.body),n=t.css("display");t.remove();if(n==="none"||n===""){Pt=i.body.appendChild(Pt||v.extend(i.createElement("iframe"),{frameBorder:0,width:0,height:0}));if(!Ht||!Pt.createElement)Ht=(Pt.contentWindow||Pt.contentDocument).document,Ht.write(""),Ht.close();t=Ht.body.appendChild(Ht.createElement(e)),n=Dt(t,"display"),i.body.removeChild(Pt)}return Wt[e]=n,n}function fn(e,t,n,r){var i;if(v.isArray(t))v.each(t,function(t,i){n||sn.test(e)?r(e,i):fn(e+"["+(typeof i=="object"?t:"")+"]",i,n,r)});else if(!n&&v.type(t)==="object")for(i in t)fn(e+"["+i+"]",t[i],n,r);else r(e,t)}function Cn(e){return function(t,n){typeof t!="string"&&(n=t,t="*");var r,i,s,o=t.toLowerCase().split(y),u=0,a=o.length;if(v.isFunction(n))for(;u)[^>]*$|#([\w\-]*)$)/,E=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,S=/^[\],:{}\s]*$/,x=/(?:^|:|,)(?:\s*\[)+/g,T=/\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g,N=/"[^"\\\r\n]*"|true|false|null|-?(?:\d\d*\.|)\d+(?:[eE][\-+]?\d+|)/g,C=/^-ms-/,k=/-([\da-z])/gi,L=function(e,t){return(t+"").toUpperCase()},A=function(){i.addEventListener?(i.removeEventListener("DOMContentLoaded",A,!1),v.ready()):i.readyState==="complete"&&(i.detachEvent("onreadystatechange",A),v.ready())},O={};v.fn=v.prototype={constructor:v,init:function(e,n,r){var s,o,u,a;if(!e)return this;if(e.nodeType)return this.context=this[0]=e,this.length=1,this;if(typeof e=="string"){e.charAt(0)==="<"&&e.charAt(e.length-1)===">"&&e.length>=3?s=[null,e,null]:s=w.exec(e);if(s&&(s[1]||!n)){if(s[1])return n=n instanceof v?n[0]:n,a=n&&n.nodeType?n.ownerDocument||n:i,e=v.parseHTML(s[1],a,!0),E.test(s[1])&&v.isPlainObject(n)&&this.attr.call(e,n,!0),v.merge(this,e);o=i.getElementById(s[2]);if(o&&o.parentNode){if(o.id!==s[2])return r.find(e);this.length=1,this[0]=o}return this.context=i,this.selector=e,this}return!n||n.jquery?(n||r).find(e):this.constructor(n).find(e)}return v.isFunction(e)?r.ready(e):(e.selector!==t&&(this.selector=e.selector,this.context=e.context),v.makeArray(e,this))},selector:"",jquery:"1.8.3",length:0,size:function(){return this.length},toArray:function(){return l.call(this)},get:function(e){return e==null?this.toArray():e<0?this[this.length+e]:this[e]},pushStack:function(e,t,n){var r=v.merge(this.constructor(),e);return r.prevObject=this,r.context=this.context,t==="find"?r.selector=this.selector+(this.selector?" ":"")+n:t&&(r.selector=this.selector+"."+t+"("+n+")"),r},each:function(e,t){return v.each(this,e,t)},ready:function(e){return v.ready.promise().done(e),this},eq:function(e){return e=+e,e===-1?this.slice(e):this.slice(e,e+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(l.apply(this,arguments),"slice",l.call(arguments).join(","))},map:function(e){return this.pushStack(v.map(this,function(t,n){return e.call(t,n,t)}))},end:function(){return this.prevObject||this.constructor(null)},push:f,sort:[].sort,splice:[].splice},v.fn.init.prototype=v.fn,v.extend=v.fn.extend=function(){var e,n,r,i,s,o,u=arguments[0]||{},a=1,f=arguments.length,l=!1;typeof u=="boolean"&&(l=u,u=arguments[1]||{},a=2),typeof u!="object"&&!v.isFunction(u)&&(u={}),f===a&&(u=this,--a);for(;a0)return;r.resolveWith(i,[v]),v.fn.trigger&&v(i).trigger("ready").off("ready")},isFunction:function(e){return v.type(e)==="function"},isArray:Array.isArray||function(e){return v.type(e)==="array"},isWindow:function(e){return e!=null&&e==e.window},isNumeric:function(e){return!isNaN(parseFloat(e))&&isFinite(e)},type:function(e){return e==null?String(e):O[h.call(e)]||"object"},isPlainObject:function(e){if(!e||v.type(e)!=="object"||e.nodeType||v.isWindow(e))return!1;try{if(e.constructor&&!p.call(e,"constructor")&&!p.call(e.constructor.prototype,"isPrototypeOf"))return!1}catch(n){return!1}var r;for(r in e);return r===t||p.call(e,r)},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},error:function(e){throw new Error(e)},parseHTML:function(e,t,n){var r;return!e||typeof e!="string"?null:(typeof t=="boolean"&&(n=t,t=0),t=t||i,(r=E.exec(e))?[t.createElement(r[1])]:(r=v.buildFragment([e],t,n?null:[]),v.merge([],(r.cacheable?v.clone(r.fragment):r.fragment).childNodes)))},parseJSON:function(t){if(!t||typeof t!="string")return null;t=v.trim(t);if(e.JSON&&e.JSON.parse)return e.JSON.parse(t);if(S.test(t.replace(T,"@").replace(N,"]").replace(x,"")))return(new Function("return "+t))();v.error("Invalid JSON: "+t)},parseXML:function(n){var r,i;if(!n||typeof n!="string")return null;try{e.DOMParser?(i=new DOMParser,r=i.parseFromString(n,"text/xml")):(r=new ActiveXObject("Microsoft.XMLDOM"),r.async="false",r.loadXML(n))}catch(s){r=t}return(!r||!r.documentElement||r.getElementsByTagName("parsererror").length)&&v.error("Invalid XML: "+n),r},noop:function(){},globalEval:function(t){t&&g.test(t)&&(e.execScript||function(t){e.eval.call(e,t)})(t)},camelCase:function(e){return e.replace(C,"ms-").replace(k,L)},nodeName:function(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()},each:function(e,n,r){var i,s=0,o=e.length,u=o===t||v.isFunction(e);if(r){if(u){for(i in e)if(n.apply(e[i],r)===!1)break}else for(;s0&&e[0]&&e[a-1]||a===0||v.isArray(e));if(f)for(;u-1)a.splice(n,1),i&&(n<=o&&o--,n<=u&&u--)}),this},has:function(e){return v.inArray(e,a)>-1},empty:function(){return a=[],this},disable:function(){return a=f=n=t,this},disabled:function(){return!a},lock:function(){return f=t,n||c.disable(),this},locked:function(){return!f},fireWith:function(e,t){return t=t||[],t=[e,t.slice?t.slice():t],a&&(!r||f)&&(i?f.push(t):l(t)),this},fire:function(){return c.fireWith(this,arguments),this},fired:function(){return!!r}};return c},v.extend({Deferred:function(e){var t=[["resolve","done",v.Callbacks("once memory"),"resolved"],["reject","fail",v.Callbacks("once memory"),"rejected"],["notify","progress",v.Callbacks("memory")]],n="pending",r={state:function(){return n},always:function(){return i.done(arguments).fail(arguments),this},then:function(){var e=arguments;return v.Deferred(function(n){v.each(t,function(t,r){var s=r[0],o=e[t];i[r[1]](v.isFunction(o)?function(){var e=o.apply(this,arguments);e&&v.isFunction(e.promise)?e.promise().done(n.resolve).fail(n.reject).progress(n.notify):n[s+"With"](this===i?n:this,[e])}:n[s])}),e=null}).promise()},promise:function(e){return e!=null?v.extend(e,r):r}},i={};return r.pipe=r.then,v.each(t,function(e,s){var o=s[2],u=s[3];r[s[1]]=o.add,u&&o.add(function(){n=u},t[e^1][2].disable,t[2][2].lock),i[s[0]]=o.fire,i[s[0]+"With"]=o.fireWith}),r.promise(i),e&&e.call(i,i),i},when:function(e){var t=0,n=l.call(arguments),r=n.length,i=r!==1||e&&v.isFunction(e.promise)?r:0,s=i===1?e:v.Deferred(),o=function(e,t,n){return function(r){t[e]=this,n[e]=arguments.length>1?l.call(arguments):r,n===u?s.notifyWith(t,n):--i||s.resolveWith(t,n)}},u,a,f;if(r>1){u=new Array(r),a=new Array(r),f=new Array(r);for(;t
      a",n=p.getElementsByTagName("*"),r=p.getElementsByTagName("a")[0];if(!n||!r||!n.length)return{};s=i.createElement("select"),o=s.appendChild(i.createElement("option")),u=p.getElementsByTagName("input")[0],r.style.cssText="top:1px;float:left;opacity:.5",t={leadingWhitespace:p.firstChild.nodeType===3,tbody:!p.getElementsByTagName("tbody").length,htmlSerialize:!!p.getElementsByTagName("link").length,style:/top/.test(r.getAttribute("style")),hrefNormalized:r.getAttribute("href")==="/a",opacity:/^0.5/.test(r.style.opacity),cssFloat:!!r.style.cssFloat,checkOn:u.value==="on",optSelected:o.selected,getSetAttribute:p.className!=="t",enctype:!!i.createElement("form").enctype,html5Clone:i.createElement("nav").cloneNode(!0).outerHTML!=="<:nav>",boxModel:i.compatMode==="CSS1Compat",submitBubbles:!0,changeBubbles:!0,focusinBubbles:!1,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0,boxSizingReliable:!0,pixelPosition:!1},u.checked=!0,t.noCloneChecked=u.cloneNode(!0).checked,s.disabled=!0,t.optDisabled=!o.disabled;try{delete p.test}catch(d){t.deleteExpando=!1}!p.addEventListener&&p.attachEvent&&p.fireEvent&&(p.attachEvent("onclick",h=function(){t.noCloneEvent=!1}),p.cloneNode(!0).fireEvent("onclick"),p.detachEvent("onclick",h)),u=i.createElement("input"),u.value="t",u.setAttribute("type","radio"),t.radioValue=u.value==="t",u.setAttribute("checked","checked"),u.setAttribute("name","t"),p.appendChild(u),a=i.createDocumentFragment(),a.appendChild(p.lastChild),t.checkClone=a.cloneNode(!0).cloneNode(!0).lastChild.checked,t.appendChecked=u.checked,a.removeChild(u),a.appendChild(p);if(p.attachEvent)for(l in{submit:!0,change:!0,focusin:!0})f="on"+l,c=f in p,c||(p.setAttribute(f,"return;"),c=typeof p[f]=="function"),t[l+"Bubbles"]=c;return v(function(){var n,r,s,o,u="padding:0;margin:0;border:0;display:block;overflow:hidden;",a=i.getElementsByTagName("body")[0];if(!a)return;n=i.createElement("div"),n.style.cssText="visibility:hidden;border:0;width:0;height:0;position:static;top:0;margin-top:1px",a.insertBefore(n,a.firstChild),r=i.createElement("div"),n.appendChild(r),r.innerHTML="
      t
      ",s=r.getElementsByTagName("td"),s[0].style.cssText="padding:0;margin:0;border:0;display:none",c=s[0].offsetHeight===0,s[0].style.display="",s[1].style.display="none",t.reliableHiddenOffsets=c&&s[0].offsetHeight===0,r.innerHTML="",r.style.cssText="box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%;",t.boxSizing=r.offsetWidth===4,t.doesNotIncludeMarginInBodyOffset=a.offsetTop!==1,e.getComputedStyle&&(t.pixelPosition=(e.getComputedStyle(r,null)||{}).top!=="1%",t.boxSizingReliable=(e.getComputedStyle(r,null)||{width:"4px"}).width==="4px",o=i.createElement("div"),o.style.cssText=r.style.cssText=u,o.style.marginRight=o.style.width="0",r.style.width="1px",r.appendChild(o),t.reliableMarginRight=!parseFloat((e.getComputedStyle(o,null)||{}).marginRight)),typeof r.style.zoom!="undefined"&&(r.innerHTML="",r.style.cssText=u+"width:1px;padding:1px;display:inline;zoom:1",t.inlineBlockNeedsLayout=r.offsetWidth===3,r.style.display="block",r.style.overflow="visible",r.innerHTML="
      ",r.firstChild.style.width="5px",t.shrinkWrapBlocks=r.offsetWidth!==3,n.style.zoom=1),a.removeChild(n),n=r=s=o=null}),a.removeChild(p),n=r=s=o=u=a=p=null,t}();var D=/(?:\{[\s\S]*\}|\[[\s\S]*\])$/,P=/([A-Z])/g;v.extend({cache:{},deletedIds:[],uuid:0,expando:"jQuery"+(v.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(e){return e=e.nodeType?v.cache[e[v.expando]]:e[v.expando],!!e&&!B(e)},data:function(e,n,r,i){if(!v.acceptData(e))return;var s,o,u=v.expando,a=typeof n=="string",f=e.nodeType,l=f?v.cache:e,c=f?e[u]:e[u]&&u;if((!c||!l[c]||!i&&!l[c].data)&&a&&r===t)return;c||(f?e[u]=c=v.deletedIds.pop()||v.guid++:c=u),l[c]||(l[c]={},f||(l[c].toJSON=v.noop));if(typeof n=="object"||typeof n=="function")i?l[c]=v.extend(l[c],n):l[c].data=v.extend(l[c].data,n);return s=l[c],i||(s.data||(s.data={}),s=s.data),r!==t&&(s[v.camelCase(n)]=r),a?(o=s[n],o==null&&(o=s[v.camelCase(n)])):o=s,o},removeData:function(e,t,n){if(!v.acceptData(e))return;var r,i,s,o=e.nodeType,u=o?v.cache:e,a=o?e[v.expando]:v.expando;if(!u[a])return;if(t){r=n?u[a]:u[a].data;if(r){v.isArray(t)||(t in r?t=[t]:(t=v.camelCase(t),t in r?t=[t]:t=t.split(" ")));for(i=0,s=t.length;i1,null,!1))},removeData:function(e){return this.each(function(){v.removeData(this,e)})}}),v.extend({queue:function(e,t,n){var r;if(e)return t=(t||"fx")+"queue",r=v._data(e,t),n&&(!r||v.isArray(n)?r=v._data(e,t,v.makeArray(n)):r.push(n)),r||[]},dequeue:function(e,t){t=t||"fx";var n=v.queue(e,t),r=n.length,i=n.shift(),s=v._queueHooks(e,t),o=function(){v.dequeue(e,t)};i==="inprogress"&&(i=n.shift(),r--),i&&(t==="fx"&&n.unshift("inprogress"),delete s.stop,i.call(e,o,s)),!r&&s&&s.empty.fire()},_queueHooks:function(e,t){var n=t+"queueHooks";return v._data(e,n)||v._data(e,n,{empty:v.Callbacks("once memory").add(function(){v.removeData(e,t+"queue",!0),v.removeData(e,n,!0)})})}}),v.fn.extend({queue:function(e,n){var r=2;return typeof e!="string"&&(n=e,e="fx",r--),arguments.length1)},removeAttr:function(e){return this.each(function(){v.removeAttr(this,e)})},prop:function(e,t){return v.access(this,v.prop,e,t,arguments.length>1)},removeProp:function(e){return e=v.propFix[e]||e,this.each(function(){try{this[e]=t,delete this[e]}catch(n){}})},addClass:function(e){var t,n,r,i,s,o,u;if(v.isFunction(e))return this.each(function(t){v(this).addClass(e.call(this,t,this.className))});if(e&&typeof e=="string"){t=e.split(y);for(n=0,r=this.length;n=0)r=r.replace(" "+n[s]+" "," ");i.className=e?v.trim(r):""}}}return this},toggleClass:function(e,t){var n=typeof e,r=typeof t=="boolean";return v.isFunction(e)?this.each(function(n){v(this).toggleClass(e.call(this,n,this.className,t),t)}):this.each(function(){if(n==="string"){var i,s=0,o=v(this),u=t,a=e.split(y);while(i=a[s++])u=r?u:!o.hasClass(i),o[u?"addClass":"removeClass"](i)}else if(n==="undefined"||n==="boolean")this.className&&v._data(this,"__className__",this.className),this.className=this.className||e===!1?"":v._data(this,"__className__")||""})},hasClass:function(e){var t=" "+e+" ",n=0,r=this.length;for(;n=0)return!0;return!1},val:function(e){var n,r,i,s=this[0];if(!arguments.length){if(s)return n=v.valHooks[s.type]||v.valHooks[s.nodeName.toLowerCase()],n&&"get"in n&&(r=n.get(s,"value"))!==t?r:(r=s.value,typeof r=="string"?r.replace(R,""):r==null?"":r);return}return i=v.isFunction(e),this.each(function(r){var s,o=v(this);if(this.nodeType!==1)return;i?s=e.call(this,r,o.val()):s=e,s==null?s="":typeof s=="number"?s+="":v.isArray(s)&&(s=v.map(s,function(e){return e==null?"":e+""})),n=v.valHooks[this.type]||v.valHooks[this.nodeName.toLowerCase()];if(!n||!("set"in n)||n.set(this,s,"value")===t)this.value=s})}}),v.extend({valHooks:{option:{get:function(e){var t=e.attributes.value;return!t||t.specified?e.value:e.text}},select:{get:function(e){var t,n,r=e.options,i=e.selectedIndex,s=e.type==="select-one"||i<0,o=s?null:[],u=s?i+1:r.length,a=i<0?u:s?i:0;for(;a=0}),n.length||(e.selectedIndex=-1),n}}},attrFn:{},attr:function(e,n,r,i){var s,o,u,a=e.nodeType;if(!e||a===3||a===8||a===2)return;if(i&&v.isFunction(v.fn[n]))return v(e)[n](r);if(typeof e.getAttribute=="undefined")return v.prop(e,n,r);u=a!==1||!v.isXMLDoc(e),u&&(n=n.toLowerCase(),o=v.attrHooks[n]||(X.test(n)?F:j));if(r!==t){if(r===null){v.removeAttr(e,n);return}return o&&"set"in o&&u&&(s=o.set(e,r,n))!==t?s:(e.setAttribute(n,r+""),r)}return o&&"get"in o&&u&&(s=o.get(e,n))!==null?s:(s=e.getAttribute(n),s===null?t:s)},removeAttr:function(e,t){var n,r,i,s,o=0;if(t&&e.nodeType===1){r=t.split(y);for(;o=0}})});var $=/^(?:textarea|input|select)$/i,J=/^([^\.]*|)(?:\.(.+)|)$/,K=/(?:^|\s)hover(\.\S+|)\b/,Q=/^key/,G=/^(?:mouse|contextmenu)|click/,Y=/^(?:focusinfocus|focusoutblur)$/,Z=function(e){return v.event.special.hover?e:e.replace(K,"mouseenter$1 mouseleave$1")};v.event={add:function(e,n,r,i,s){var o,u,a,f,l,c,h,p,d,m,g;if(e.nodeType===3||e.nodeType===8||!n||!r||!(o=v._data(e)))return;r.handler&&(d=r,r=d.handler,s=d.selector),r.guid||(r.guid=v.guid++),a=o.events,a||(o.events=a={}),u=o.handle,u||(o.handle=u=function(e){return typeof v=="undefined"||!!e&&v.event.triggered===e.type?t:v.event.dispatch.apply(u.elem,arguments)},u.elem=e),n=v.trim(Z(n)).split(" ");for(f=0;f=0&&(y=y.slice(0,-1),a=!0),y.indexOf(".")>=0&&(b=y.split("."),y=b.shift(),b.sort());if((!s||v.event.customEvent[y])&&!v.event.global[y])return;n=typeof n=="object"?n[v.expando]?n:new v.Event(y,n):new v.Event(y),n.type=y,n.isTrigger=!0,n.exclusive=a,n.namespace=b.join("."),n.namespace_re=n.namespace?new RegExp("(^|\\.)"+b.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,h=y.indexOf(":")<0?"on"+y:"";if(!s){u=v.cache;for(f in u)u[f].events&&u[f].events[y]&&v.event.trigger(n,r,u[f].handle.elem,!0);return}n.result=t,n.target||(n.target=s),r=r!=null?v.makeArray(r):[],r.unshift(n),p=v.event.special[y]||{};if(p.trigger&&p.trigger.apply(s,r)===!1)return;m=[[s,p.bindType||y]];if(!o&&!p.noBubble&&!v.isWindow(s)){g=p.delegateType||y,l=Y.test(g+y)?s:s.parentNode;for(c=s;l;l=l.parentNode)m.push([l,g]),c=l;c===(s.ownerDocument||i)&&m.push([c.defaultView||c.parentWindow||e,g])}for(f=0;f=0:v.find(h,this,null,[s]).length),u[h]&&f.push(c);f.length&&w.push({elem:s,matches:f})}d.length>m&&w.push({elem:this,matches:d.slice(m)});for(r=0;r0?this.on(t,null,e,n):this.trigger(t)},Q.test(t)&&(v.event.fixHooks[t]=v.event.keyHooks),G.test(t)&&(v.event.fixHooks[t]=v.event.mouseHooks)}),function(e,t){function nt(e,t,n,r){n=n||[],t=t||g;var i,s,a,f,l=t.nodeType;if(!e||typeof e!="string")return n;if(l!==1&&l!==9)return[];a=o(t);if(!a&&!r)if(i=R.exec(e))if(f=i[1]){if(l===9){s=t.getElementById(f);if(!s||!s.parentNode)return n;if(s.id===f)return n.push(s),n}else if(t.ownerDocument&&(s=t.ownerDocument.getElementById(f))&&u(t,s)&&s.id===f)return n.push(s),n}else{if(i[2])return S.apply(n,x.call(t.getElementsByTagName(e),0)),n;if((f=i[3])&&Z&&t.getElementsByClassName)return S.apply(n,x.call(t.getElementsByClassName(f),0)),n}return vt(e.replace(j,"$1"),t,n,r,a)}function rt(e){return function(t){var n=t.nodeName.toLowerCase();return n==="input"&&t.type===e}}function it(e){return function(t){var n=t.nodeName.toLowerCase();return(n==="input"||n==="button")&&t.type===e}}function st(e){return N(function(t){return t=+t,N(function(n,r){var i,s=e([],n.length,t),o=s.length;while(o--)n[i=s[o]]&&(n[i]=!(r[i]=n[i]))})})}function ot(e,t,n){if(e===t)return n;var r=e.nextSibling;while(r){if(r===t)return-1;r=r.nextSibling}return 1}function ut(e,t){var n,r,s,o,u,a,f,l=L[d][e+" "];if(l)return t?0:l.slice(0);u=e,a=[],f=i.preFilter;while(u){if(!n||(r=F.exec(u)))r&&(u=u.slice(r[0].length)||u),a.push(s=[]);n=!1;if(r=I.exec(u))s.push(n=new m(r.shift())),u=u.slice(n.length),n.type=r[0].replace(j," ");for(o in i.filter)(r=J[o].exec(u))&&(!f[o]||(r=f[o](r)))&&(s.push(n=new m(r.shift())),u=u.slice(n.length),n.type=o,n.matches=r);if(!n)break}return t?u.length:u?nt.error(e):L(e,a).slice(0)}function at(e,t,r){var i=t.dir,s=r&&t.dir==="parentNode",o=w++;return t.first?function(t,n,r){while(t=t[i])if(s||t.nodeType===1)return e(t,n,r)}:function(t,r,u){if(!u){var a,f=b+" "+o+" ",l=f+n;while(t=t[i])if(s||t.nodeType===1){if((a=t[d])===l)return t.sizset;if(typeof a=="string"&&a.indexOf(f)===0){if(t.sizset)return t}else{t[d]=l;if(e(t,r,u))return t.sizset=!0,t;t.sizset=!1}}}else while(t=t[i])if(s||t.nodeType===1)if(e(t,r,u))return t}}function ft(e){return e.length>1?function(t,n,r){var i=e.length;while(i--)if(!e[i](t,n,r))return!1;return!0}:e[0]}function lt(e,t,n,r,i){var s,o=[],u=0,a=e.length,f=t!=null;for(;u-1&&(s[f]=!(o[f]=c))}}else g=lt(g===o?g.splice(d,g.length):g),i?i(null,o,g,a):S.apply(o,g)})}function ht(e){var t,n,r,s=e.length,o=i.relative[e[0].type],u=o||i.relative[" "],a=o?1:0,f=at(function(e){return e===t},u,!0),l=at(function(e){return T.call(t,e)>-1},u,!0),h=[function(e,n,r){return!o&&(r||n!==c)||((t=n).nodeType?f(e,n,r):l(e,n,r))}];for(;a1&&ft(h),a>1&&e.slice(0,a-1).join("").replace(j,"$1"),n,a0,s=e.length>0,o=function(u,a,f,l,h){var p,d,v,m=[],y=0,w="0",x=u&&[],T=h!=null,N=c,C=u||s&&i.find.TAG("*",h&&a.parentNode||a),k=b+=N==null?1:Math.E;T&&(c=a!==g&&a,n=o.el);for(;(p=C[w])!=null;w++){if(s&&p){for(d=0;v=e[d];d++)if(v(p,a,f)){l.push(p);break}T&&(b=k,n=++o.el)}r&&((p=!v&&p)&&y--,u&&x.push(p))}y+=w;if(r&&w!==y){for(d=0;v=t[d];d++)v(x,m,a,f);if(u){if(y>0)while(w--)!x[w]&&!m[w]&&(m[w]=E.call(l));m=lt(m)}S.apply(l,m),T&&!u&&m.length>0&&y+t.length>1&&nt.uniqueSort(l)}return T&&(b=k,c=N),x};return o.el=0,r?N(o):o}function dt(e,t,n){var r=0,i=t.length;for(;r2&&(f=u[0]).type==="ID"&&t.nodeType===9&&!s&&i.relative[u[1].type]){t=i.find.ID(f.matches[0].replace($,""),t,s)[0];if(!t)return n;e=e.slice(u.shift().length)}for(o=J.POS.test(e)?-1:u.length-1;o>=0;o--){f=u[o];if(i.relative[l=f.type])break;if(c=i.find[l])if(r=c(f.matches[0].replace($,""),z.test(u[0].type)&&t.parentNode||t,s)){u.splice(o,1),e=r.length&&u.join("");if(!e)return S.apply(n,x.call(r,0)),n;break}}}return a(e,h)(r,t,s,n,z.test(e)),n}function mt(){}var n,r,i,s,o,u,a,f,l,c,h=!0,p="undefined",d=("sizcache"+Math.random()).replace(".",""),m=String,g=e.document,y=g.documentElement,b=0,w=0,E=[].pop,S=[].push,x=[].slice,T=[].indexOf||function(e){var t=0,n=this.length;for(;ti.cacheLength&&delete e[t.shift()],e[n+" "]=r},e)},k=C(),L=C(),A=C(),O="[\\x20\\t\\r\\n\\f]",M="(?:\\\\.|[-\\w]|[^\\x00-\\xa0])+",_=M.replace("w","w#"),D="([*^$|!~]?=)",P="\\["+O+"*("+M+")"+O+"*(?:"+D+O+"*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|("+_+")|)|)"+O+"*\\]",H=":("+M+")(?:\\((?:(['\"])((?:\\\\.|[^\\\\])*?)\\2|([^()[\\]]*|(?:(?:"+P+")|[^:]|\\\\.)*|.*))\\)|)",B=":(even|odd|eq|gt|lt|nth|first|last)(?:\\("+O+"*((?:-\\d)?\\d*)"+O+"*\\)|)(?=[^-]|$)",j=new RegExp("^"+O+"+|((?:^|[^\\\\])(?:\\\\.)*)"+O+"+$","g"),F=new RegExp("^"+O+"*,"+O+"*"),I=new RegExp("^"+O+"*([\\x20\\t\\r\\n\\f>+~])"+O+"*"),q=new RegExp(H),R=/^(?:#([\w\-]+)|(\w+)|\.([\w\-]+))$/,U=/^:not/,z=/[\x20\t\r\n\f]*[+~]/,W=/:not\($/,X=/h\d/i,V=/input|select|textarea|button/i,$=/\\(?!\\)/g,J={ID:new RegExp("^#("+M+")"),CLASS:new RegExp("^\\.("+M+")"),NAME:new RegExp("^\\[name=['\"]?("+M+")['\"]?\\]"),TAG:new RegExp("^("+M.replace("w","w*")+")"),ATTR:new RegExp("^"+P),PSEUDO:new RegExp("^"+H),POS:new RegExp(B,"i"),CHILD:new RegExp("^:(only|nth|first|last)-child(?:\\("+O+"*(even|odd|(([+-]|)(\\d*)n|)"+O+"*(?:([+-]|)"+O+"*(\\d+)|))"+O+"*\\)|)","i"),needsContext:new RegExp("^"+O+"*[>+~]|"+B,"i")},K=function(e){var t=g.createElement("div");try{return e(t)}catch(n){return!1}finally{t=null}},Q=K(function(e){return e.appendChild(g.createComment("")),!e.getElementsByTagName("*").length}),G=K(function(e){return e.innerHTML="",e.firstChild&&typeof e.firstChild.getAttribute!==p&&e.firstChild.getAttribute("href")==="#"}),Y=K(function(e){e.innerHTML="";var t=typeof e.lastChild.getAttribute("multiple");return t!=="boolean"&&t!=="string"}),Z=K(function(e){return e.innerHTML="",!e.getElementsByClassName||!e.getElementsByClassName("e").length?!1:(e.lastChild.className="e",e.getElementsByClassName("e").length===2)}),et=K(function(e){e.id=d+0,e.innerHTML="
      ",y.insertBefore(e,y.firstChild);var t=g.getElementsByName&&g.getElementsByName(d).length===2+g.getElementsByName(d+0).length;return r=!g.getElementById(d),y.removeChild(e),t});try{x.call(y.childNodes,0)[0].nodeType}catch(tt){x=function(e){var t,n=[];for(;t=this[e];e++)n.push(t);return n}}nt.matches=function(e,t){return nt(e,null,null,t)},nt.matchesSelector=function(e,t){return nt(t,null,null,[e]).length>0},s=nt.getText=function(e){var t,n="",r=0,i=e.nodeType;if(i){if(i===1||i===9||i===11){if(typeof e.textContent=="string")return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=s(e)}else if(i===3||i===4)return e.nodeValue}else for(;t=e[r];r++)n+=s(t);return n},o=nt.isXML=function(e){var t=e&&(e.ownerDocument||e).documentElement;return t?t.nodeName!=="HTML":!1},u=nt.contains=y.contains?function(e,t){var n=e.nodeType===9?e.documentElement:e,r=t&&t.parentNode;return e===r||!!(r&&r.nodeType===1&&n.contains&&n.contains(r))}:y.compareDocumentPosition?function(e,t){return t&&!!(e.compareDocumentPosition(t)&16)}:function(e,t){while(t=t.parentNode)if(t===e)return!0;return!1},nt.attr=function(e,t){var n,r=o(e);return r||(t=t.toLowerCase()),(n=i.attrHandle[t])?n(e):r||Y?e.getAttribute(t):(n=e.getAttributeNode(t),n?typeof e[t]=="boolean"?e[t]?t:null:n.specified?n.value:null:null)},i=nt.selectors={cacheLength:50,createPseudo:N,match:J,attrHandle:G?{}:{href:function(e){return e.getAttribute("href",2)},type:function(e){return e.getAttribute("type")}},find:{ID:r?function(e,t,n){if(typeof t.getElementById!==p&&!n){var r=t.getElementById(e);return r&&r.parentNode?[r]:[]}}:function(e,n,r){if(typeof n.getElementById!==p&&!r){var i=n.getElementById(e);return i?i.id===e||typeof i.getAttributeNode!==p&&i.getAttributeNode("id").value===e?[i]:t:[]}},TAG:Q?function(e,t){if(typeof t.getElementsByTagName!==p)return t.getElementsByTagName(e)}:function(e,t){var n=t.getElementsByTagName(e);if(e==="*"){var r,i=[],s=0;for(;r=n[s];s++)r.nodeType===1&&i.push(r);return i}return n},NAME:et&&function(e,t){if(typeof t.getElementsByName!==p)return t.getElementsByName(name)},CLASS:Z&&function(e,t,n){if(typeof t.getElementsByClassName!==p&&!n)return t.getElementsByClassName(e)}},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace($,""),e[3]=(e[4]||e[5]||"").replace($,""),e[2]==="~="&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),e[1]==="nth"?(e[2]||nt.error(e[0]),e[3]=+(e[3]?e[4]+(e[5]||1):2*(e[2]==="even"||e[2]==="odd")),e[4]=+(e[6]+e[7]||e[2]==="odd")):e[2]&&nt.error(e[0]),e},PSEUDO:function(e){var t,n;if(J.CHILD.test(e[0]))return null;if(e[3])e[2]=e[3];else if(t=e[4])q.test(t)&&(n=ut(t,!0))&&(n=t.indexOf(")",t.length-n)-t.length)&&(t=t.slice(0,n),e[0]=e[0].slice(0,n)),e[2]=t;return e.slice(0,3)}},filter:{ID:r?function(e){return e=e.replace($,""),function(t){return t.getAttribute("id")===e}}:function(e){return e=e.replace($,""),function(t){var n=typeof t.getAttributeNode!==p&&t.getAttributeNode("id");return n&&n.value===e}},TAG:function(e){return e==="*"?function(){return!0}:(e=e.replace($,"").toLowerCase(),function(t){return t.nodeName&&t.nodeName.toLowerCase()===e})},CLASS:function(e){var t=k[d][e+" "];return t||(t=new RegExp("(^|"+O+")"+e+"("+O+"|$)"))&&k(e,function(e){return t.test(e.className||typeof e.getAttribute!==p&&e.getAttribute("class")||"")})},ATTR:function(e,t,n){return function(r,i){var s=nt.attr(r,e);return s==null?t==="!=":t?(s+="",t==="="?s===n:t==="!="?s!==n:t==="^="?n&&s.indexOf(n)===0:t==="*="?n&&s.indexOf(n)>-1:t==="$="?n&&s.substr(s.length-n.length)===n:t==="~="?(" "+s+" ").indexOf(n)>-1:t==="|="?s===n||s.substr(0,n.length+1)===n+"-":!1):!0}},CHILD:function(e,t,n,r){return e==="nth"?function(e){var t,i,s=e.parentNode;if(n===1&&r===0)return!0;if(s){i=0;for(t=s.firstChild;t;t=t.nextSibling)if(t.nodeType===1){i++;if(e===t)break}}return i-=r,i===n||i%n===0&&i/n>=0}:function(t){var n=t;switch(e){case"only":case"first":while(n=n.previousSibling)if(n.nodeType===1)return!1;if(e==="first")return!0;n=t;case"last":while(n=n.nextSibling)if(n.nodeType===1)return!1;return!0}}},PSEUDO:function(e,t){var n,r=i.pseudos[e]||i.setFilters[e.toLowerCase()]||nt.error("unsupported pseudo: "+e);return r[d]?r(t):r.length>1?(n=[e,e,"",t],i.setFilters.hasOwnProperty(e.toLowerCase())?N(function(e,n){var i,s=r(e,t),o=s.length;while(o--)i=T.call(e,s[o]),e[i]=!(n[i]=s[o])}):function(e){return r(e,0,n)}):r}},pseudos:{not:N(function(e){var t=[],n=[],r=a(e.replace(j,"$1"));return r[d]?N(function(e,t,n,i){var s,o=r(e,null,i,[]),u=e.length;while(u--)if(s=o[u])e[u]=!(t[u]=s)}):function(e,i,s){return t[0]=e,r(t,null,s,n),!n.pop()}}),has:N(function(e){return function(t){return nt(e,t).length>0}}),contains:N(function(e){return function(t){return(t.textContent||t.innerText||s(t)).indexOf(e)>-1}}),enabled:function(e){return e.disabled===!1},disabled:function(e){return e.disabled===!0},checked:function(e){var t=e.nodeName.toLowerCase();return t==="input"&&!!e.checked||t==="option"&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,e.selected===!0},parent:function(e){return!i.pseudos.empty(e)},empty:function(e){var t;e=e.firstChild;while(e){if(e.nodeName>"@"||(t=e.nodeType)===3||t===4)return!1;e=e.nextSibling}return!0},header:function(e){return X.test(e.nodeName)},text:function(e){var t,n;return e.nodeName.toLowerCase()==="input"&&(t=e.type)==="text"&&((n=e.getAttribute("type"))==null||n.toLowerCase()===t)},radio:rt("radio"),checkbox:rt("checkbox"),file:rt("file"),password:rt("password"),image:rt("image"),submit:it("submit"),reset:it("reset"),button:function(e){var t=e.nodeName.toLowerCase();return t==="input"&&e.type==="button"||t==="button"},input:function(e){return V.test(e.nodeName)},focus:function(e){var t=e.ownerDocument;return e===t.activeElement&&(!t.hasFocus||t.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},active:function(e){return e===e.ownerDocument.activeElement},first:st(function(){return[0]}),last:st(function(e,t){return[t-1]}),eq:st(function(e,t,n){return[n<0?n+t:n]}),even:st(function(e,t){for(var n=0;n=0;)e.push(r);return e}),gt:st(function(e,t,n){for(var r=n<0?n+t:n;++r",e.querySelectorAll("[selected]").length||i.push("\\["+O+"*(?:checked|disabled|ismap|multiple|readonly|selected|value)"),e.querySelectorAll(":checked").length||i.push(":checked")}),K(function(e){e.innerHTML="

      ",e.querySelectorAll("[test^='']").length&&i.push("[*^$]="+O+"*(?:\"\"|'')"),e.innerHTML="",e.querySelectorAll(":enabled").length||i.push(":enabled",":disabled")}),i=new RegExp(i.join("|")),vt=function(e,r,s,o,u){if(!o&&!u&&!i.test(e)){var a,f,l=!0,c=d,h=r,p=r.nodeType===9&&e;if(r.nodeType===1&&r.nodeName.toLowerCase()!=="object"){a=ut(e),(l=r.getAttribute("id"))?c=l.replace(n,"\\$&"):r.setAttribute("id",c),c="[id='"+c+"'] ",f=a.length;while(f--)a[f]=c+a[f].join("");h=z.test(e)&&r.parentNode||r,p=a.join(",")}if(p)try{return S.apply(s,x.call(h.querySelectorAll(p),0)),s}catch(v){}finally{l||r.removeAttribute("id")}}return t(e,r,s,o,u)},u&&(K(function(t){e=u.call(t,"div");try{u.call(t,"[test!='']:sizzle"),s.push("!=",H)}catch(n){}}),s=new RegExp(s.join("|")),nt.matchesSelector=function(t,n){n=n.replace(r,"='$1']");if(!o(t)&&!s.test(n)&&!i.test(n))try{var a=u.call(t,n);if(a||e||t.document&&t.document.nodeType!==11)return a}catch(f){}return nt(n,null,null,[t]).length>0})}(),i.pseudos.nth=i.pseudos.eq,i.filters=mt.prototype=i.pseudos,i.setFilters=new mt,nt.attr=v.attr,v.find=nt,v.expr=nt.selectors,v.expr[":"]=v.expr.pseudos,v.unique=nt.uniqueSort,v.text=nt.getText,v.isXMLDoc=nt.isXML,v.contains=nt.contains}(e);var nt=/Until$/,rt=/^(?:parents|prev(?:Until|All))/,it=/^.[^:#\[\.,]*$/,st=v.expr.match.needsContext,ot={children:!0,contents:!0,next:!0,prev:!0};v.fn.extend({find:function(e){var t,n,r,i,s,o,u=this;if(typeof e!="string")return v(e).filter(function(){for(t=0,n=u.length;t0)for(i=r;i=0:v.filter(e,this).length>0:this.filter(e).length>0)},closest:function(e,t){var n,r=0,i=this.length,s=[],o=st.test(e)||typeof e!="string"?v(e,t||this.context):0;for(;r-1:v.find.matchesSelector(n,e)){s.push(n);break}n=n.parentNode}}return s=s.length>1?v.unique(s):s,this.pushStack(s,"closest",e)},index:function(e){return e?typeof e=="string"?v.inArray(this[0],v(e)):v.inArray(e.jquery?e[0]:e,this):this[0]&&this[0].parentNode?this.prevAll().length:-1},add:function(e,t){var n=typeof e=="string"?v(e,t):v.makeArray(e&&e.nodeType?[e]:e),r=v.merge(this.get(),n);return this.pushStack(ut(n[0])||ut(r[0])?r:v.unique(r))},addBack:function(e){return this.add(e==null?this.prevObject:this.prevObject.filter(e))}}),v.fn.andSelf=v.fn.addBack,v.each({parent:function(e){var t=e.parentNode;return t&&t.nodeType!==11?t:null},parents:function(e){return v.dir(e,"parentNode")},parentsUntil:function(e,t,n){return v.dir(e,"parentNode",n)},next:function(e){return at(e,"nextSibling")},prev:function(e){return at(e,"previousSibling")},nextAll:function(e){return v.dir(e,"nextSibling")},prevAll:function(e){return v.dir(e,"previousSibling")},nextUntil:function(e,t,n){return v.dir(e,"nextSibling",n)},prevUntil:function(e,t,n){return v.dir(e,"previousSibling",n)},siblings:function(e){return v.sibling((e.parentNode||{}).firstChild,e)},children:function(e){return v.sibling(e.firstChild)},contents:function(e){return v.nodeName(e,"iframe")?e.contentDocument||e.contentWindow.document:v.merge([],e.childNodes)}},function(e,t){v.fn[e]=function(n,r){var i=v.map(this,t,n);return nt.test(e)||(r=n),r&&typeof r=="string"&&(i=v.filter(r,i)),i=this.length>1&&!ot[e]?v.unique(i):i,this.length>1&&rt.test(e)&&(i=i.reverse()),this.pushStack(i,e,l.call(arguments).join(","))}}),v.extend({filter:function(e,t,n){return n&&(e=":not("+e+")"),t.length===1?v.find.matchesSelector(t[0],e)?[t[0]]:[]:v.find.matches(e,t)},dir:function(e,n,r){var i=[],s=e[n];while(s&&s.nodeType!==9&&(r===t||s.nodeType!==1||!v(s).is(r)))s.nodeType===1&&i.push(s),s=s[n];return i},sibling:function(e,t){var n=[];for(;e;e=e.nextSibling)e.nodeType===1&&e!==t&&n.push(e);return n}});var ct="abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",ht=/ jQuery\d+="(?:null|\d+)"/g,pt=/^\s+/,dt=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,vt=/<([\w:]+)/,mt=/]","i"),Et=/^(?:checkbox|radio)$/,St=/checked\s*(?:[^=]|=\s*.checked.)/i,xt=/\/(java|ecma)script/i,Tt=/^\s*\s*$/g,Nt={option:[1,""],legend:[1,"
      ","
      "],thead:[1,"","
      "],tr:[2,"","
      "],td:[3,"","
      "],col:[2,"","
      "],area:[1,"",""],_default:[0,"",""]},Ct=lt(i),kt=Ct.appendChild(i.createElement("div"));Nt.optgroup=Nt.option,Nt.tbody=Nt.tfoot=Nt.colgroup=Nt.caption=Nt.thead,Nt.th=Nt.td,v.support.htmlSerialize||(Nt._default=[1,"X
      ","
      "]),v.fn.extend({text:function(e){return v.access(this,function(e){return e===t?v.text(this):this.empty().append((this[0]&&this[0].ownerDocument||i).createTextNode(e))},null,e,arguments.length)},wrapAll:function(e){if(v.isFunction(e))return this.each(function(t){v(this).wrapAll(e.call(this,t))});if(this[0]){var t=v(e,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){var e=this;while(e.firstChild&&e.firstChild.nodeType===1)e=e.firstChild;return e}).append(this)}return this},wrapInner:function(e){return v.isFunction(e)?this.each(function(t){v(this).wrapInner(e.call(this,t))}):this.each(function(){var t=v(this),n=t.contents();n.length?n.wrapAll(e):t.append(e)})},wrap:function(e){var t=v.isFunction(e);return this.each(function(n){v(this).wrapAll(t?e.call(this,n):e)})},unwrap:function(){return this.parent().each(function(){v.nodeName(this,"body")||v(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(e){(this.nodeType===1||this.nodeType===11)&&this.appendChild(e)})},prepend:function(){return this.domManip(arguments,!0,function(e){(this.nodeType===1||this.nodeType===11)&&this.insertBefore(e,this.firstChild)})},before:function(){if(!ut(this[0]))return this.domManip(arguments,!1,function(e){this.parentNode.insertBefore(e,this)});if(arguments.length){var e=v.clean(arguments);return this.pushStack(v.merge(e,this),"before",this.selector)}},after:function(){if(!ut(this[0]))return this.domManip(arguments,!1,function(e){this.parentNode.insertBefore(e,this.nextSibling)});if(arguments.length){var e=v.clean(arguments);return this.pushStack(v.merge(this,e),"after",this.selector)}},remove:function(e,t){var n,r=0;for(;(n=this[r])!=null;r++)if(!e||v.filter(e,[n]).length)!t&&n.nodeType===1&&(v.cleanData(n.getElementsByTagName("*")),v.cleanData([n])),n.parentNode&&n.parentNode.removeChild(n);return this},empty:function(){var e,t=0;for(;(e=this[t])!=null;t++){e.nodeType===1&&v.cleanData(e.getElementsByTagName("*"));while(e.firstChild)e.removeChild(e.firstChild)}return this},clone:function(e,t){return e=e==null?!1:e,t=t==null?e:t,this.map(function(){return v.clone(this,e,t)})},html:function(e){return v.access(this,function(e){var n=this[0]||{},r=0,i=this.length;if(e===t)return n.nodeType===1?n.innerHTML.replace(ht,""):t;if(typeof e=="string"&&!yt.test(e)&&(v.support.htmlSerialize||!wt.test(e))&&(v.support.leadingWhitespace||!pt.test(e))&&!Nt[(vt.exec(e)||["",""])[1].toLowerCase()]){e=e.replace(dt,"<$1>");try{for(;r1&&typeof f=="string"&&St.test(f))return this.each(function(){v(this).domManip(e,n,r)});if(v.isFunction(f))return this.each(function(i){var s=v(this);e[0]=f.call(this,i,n?s.html():t),s.domManip(e,n,r)});if(this[0]){i=v.buildFragment(e,this,l),o=i.fragment,s=o.firstChild,o.childNodes.length===1&&(o=s);if(s){n=n&&v.nodeName(s,"tr");for(u=i.cacheable||c-1;a0?this.clone(!0):this).get(),v(o[i])[t](r),s=s.concat(r);return this.pushStack(s,e,o.selector)}}),v.extend({clone:function(e,t,n){var r,i,s,o;v.support.html5Clone||v.isXMLDoc(e)||!wt.test("<"+e.nodeName+">")?o=e.cloneNode(!0):(kt.innerHTML=e.outerHTML,kt.removeChild(o=kt.firstChild));if((!v.support.noCloneEvent||!v.support.noCloneChecked)&&(e.nodeType===1||e.nodeType===11)&&!v.isXMLDoc(e)){Ot(e,o),r=Mt(e),i=Mt(o);for(s=0;r[s];++s)i[s]&&Ot(r[s],i[s])}if(t){At(e,o);if(n){r=Mt(e),i=Mt(o);for(s=0;r[s];++s)At(r[s],i[s])}}return r=i=null,o},clean:function(e,t,n,r){var s,o,u,a,f,l,c,h,p,d,m,g,y=t===i&&Ct,b=[];if(!t||typeof t.createDocumentFragment=="undefined")t=i;for(s=0;(u=e[s])!=null;s++){typeof u=="number"&&(u+="");if(!u)continue;if(typeof u=="string")if(!gt.test(u))u=t.createTextNode(u);else{y=y||lt(t),c=t.createElement("div"),y.appendChild(c),u=u.replace(dt,"<$1>"),a=(vt.exec(u)||["",""])[1].toLowerCase(),f=Nt[a]||Nt._default,l=f[0],c.innerHTML=f[1]+u+f[2];while(l--)c=c.lastChild;if(!v.support.tbody){h=mt.test(u),p=a==="table"&&!h?c.firstChild&&c.firstChild.childNodes:f[1]===""&&!h?c.childNodes:[];for(o=p.length-1;o>=0;--o)v.nodeName(p[o],"tbody")&&!p[o].childNodes.length&&p[o].parentNode.removeChild(p[o])}!v.support.leadingWhitespace&&pt.test(u)&&c.insertBefore(t.createTextNode(pt.exec(u)[0]),c.firstChild),u=c.childNodes,c.parentNode.removeChild(c)}u.nodeType?b.push(u):v.merge(b,u)}c&&(u=c=y=null);if(!v.support.appendChecked)for(s=0;(u=b[s])!=null;s++)v.nodeName(u,"input")?_t(u):typeof u.getElementsByTagName!="undefined"&&v.grep(u.getElementsByTagName("input"),_t);if(n){m=function(e){if(!e.type||xt.test(e.type))return r?r.push(e.parentNode?e.parentNode.removeChild(e):e):n.appendChild(e)};for(s=0;(u=b[s])!=null;s++)if(!v.nodeName(u,"script")||!m(u))n.appendChild(u),typeof u.getElementsByTagName!="undefined"&&(g=v.grep(v.merge([],u.getElementsByTagName("script")),m),b.splice.apply(b,[s+1,0].concat(g)),s+=g.length)}return b},cleanData:function(e,t){var n,r,i,s,o=0,u=v.expando,a=v.cache,f=v.support.deleteExpando,l=v.event.special;for(;(i=e[o])!=null;o++)if(t||v.acceptData(i)){r=i[u],n=r&&a[r];if(n){if(n.events)for(s in n.events)l[s]?v.event.remove(i,s):v.removeEvent(i,s,n.handle);a[r]&&(delete a[r],f?delete i[u]:i.removeAttribute?i.removeAttribute(u):i[u]=null,v.deletedIds.push(r))}}}}),function(){var e,t;v.uaMatch=function(e){e=e.toLowerCase();var t=/(chrome)[ \/]([\w.]+)/.exec(e)||/(webkit)[ \/]([\w.]+)/.exec(e)||/(opera)(?:.*version|)[ \/]([\w.]+)/.exec(e)||/(msie) ([\w.]+)/.exec(e)||e.indexOf("compatible")<0&&/(mozilla)(?:.*? rv:([\w.]+)|)/.exec(e)||[];return{browser:t[1]||"",version:t[2]||"0"}},e=v.uaMatch(o.userAgent),t={},e.browser&&(t[e.browser]=!0,t.version=e.version),t.chrome?t.webkit=!0:t.webkit&&(t.safari=!0),v.browser=t,v.sub=function(){function e(t,n){return new e.fn.init(t,n)}v.extend(!0,e,this),e.superclass=this,e.fn=e.prototype=this(),e.fn.constructor=e,e.sub=this.sub,e.fn.init=function(r,i){return i&&i instanceof v&&!(i instanceof e)&&(i=e(i)),v.fn.init.call(this,r,i,t)},e.fn.init.prototype=e.fn;var t=e(i);return e}}();var Dt,Pt,Ht,Bt=/alpha\([^)]*\)/i,jt=/opacity=([^)]*)/,Ft=/^(top|right|bottom|left)$/,It=/^(none|table(?!-c[ea]).+)/,qt=/^margin/,Rt=new RegExp("^("+m+")(.*)$","i"),Ut=new RegExp("^("+m+")(?!px)[a-z%]+$","i"),zt=new RegExp("^([-+])=("+m+")","i"),Wt={BODY:"block"},Xt={position:"absolute",visibility:"hidden",display:"block"},Vt={letterSpacing:0,fontWeight:400},$t=["Top","Right","Bottom","Left"],Jt=["Webkit","O","Moz","ms"],Kt=v.fn.toggle;v.fn.extend({css:function(e,n){return v.access(this,function(e,n,r){return r!==t?v.style(e,n,r):v.css(e,n)},e,n,arguments.length>1)},show:function(){return Yt(this,!0)},hide:function(){return Yt(this)},toggle:function(e,t){var n=typeof e=="boolean";return v.isFunction(e)&&v.isFunction(t)?Kt.apply(this,arguments):this.each(function(){(n?e:Gt(this))?v(this).show():v(this).hide()})}}),v.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=Dt(e,"opacity");return n===""?"1":n}}}},cssNumber:{fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":v.support.cssFloat?"cssFloat":"styleFloat"},style:function(e,n,r,i){if(!e||e.nodeType===3||e.nodeType===8||!e.style)return;var s,o,u,a=v.camelCase(n),f=e.style;n=v.cssProps[a]||(v.cssProps[a]=Qt(f,a)),u=v.cssHooks[n]||v.cssHooks[a];if(r===t)return u&&"get"in u&&(s=u.get(e,!1,i))!==t?s:f[n];o=typeof r,o==="string"&&(s=zt.exec(r))&&(r=(s[1]+1)*s[2]+parseFloat(v.css(e,n)),o="number");if(r==null||o==="number"&&isNaN(r))return;o==="number"&&!v.cssNumber[a]&&(r+="px");if(!u||!("set"in u)||(r=u.set(e,r,i))!==t)try{f[n]=r}catch(l){}},css:function(e,n,r,i){var s,o,u,a=v.camelCase(n);return n=v.cssProps[a]||(v.cssProps[a]=Qt(e.style,a)),u=v.cssHooks[n]||v.cssHooks[a],u&&"get"in u&&(s=u.get(e,!0,i)),s===t&&(s=Dt(e,n)),s==="normal"&&n in Vt&&(s=Vt[n]),r||i!==t?(o=parseFloat(s),r||v.isNumeric(o)?o||0:s):s},swap:function(e,t,n){var r,i,s={};for(i in t)s[i]=e.style[i],e.style[i]=t[i];r=n.call(e);for(i in t)e.style[i]=s[i];return r}}),e.getComputedStyle?Dt=function(t,n){var r,i,s,o,u=e.getComputedStyle(t,null),a=t.style;return u&&(r=u.getPropertyValue(n)||u[n],r===""&&!v.contains(t.ownerDocument,t)&&(r=v.style(t,n)),Ut.test(r)&&qt.test(n)&&(i=a.width,s=a.minWidth,o=a.maxWidth,a.minWidth=a.maxWidth=a.width=r,r=u.width,a.width=i,a.minWidth=s,a.maxWidth=o)),r}:i.documentElement.currentStyle&&(Dt=function(e,t){var n,r,i=e.currentStyle&&e.currentStyle[t],s=e.style;return i==null&&s&&s[t]&&(i=s[t]),Ut.test(i)&&!Ft.test(t)&&(n=s.left,r=e.runtimeStyle&&e.runtimeStyle.left,r&&(e.runtimeStyle.left=e.currentStyle.left),s.left=t==="fontSize"?"1em":i,i=s.pixelLeft+"px",s.left=n,r&&(e.runtimeStyle.left=r)),i===""?"auto":i}),v.each(["height","width"],function(e,t){v.cssHooks[t]={get:function(e,n,r){if(n)return e.offsetWidth===0&&It.test(Dt(e,"display"))?v.swap(e,Xt,function(){return tn(e,t,r)}):tn(e,t,r)},set:function(e,n,r){return Zt(e,n,r?en(e,t,r,v.support.boxSizing&&v.css(e,"boxSizing")==="border-box"):0)}}}),v.support.opacity||(v.cssHooks.opacity={get:function(e,t){return jt.test((t&&e.currentStyle?e.currentStyle.filter:e.style.filter)||"")?.01*parseFloat(RegExp.$1)+"":t?"1":""},set:function(e,t){var n=e.style,r=e.currentStyle,i=v.isNumeric(t)?"alpha(opacity="+t*100+")":"",s=r&&r.filter||n.filter||"";n.zoom=1;if(t>=1&&v.trim(s.replace(Bt,""))===""&&n.removeAttribute){n.removeAttribute("filter");if(r&&!r.filter)return}n.filter=Bt.test(s)?s.replace(Bt,i):s+" "+i}}),v(function(){v.support.reliableMarginRight||(v.cssHooks.marginRight={get:function(e,t){return v.swap(e,{display:"inline-block"},function(){if(t)return Dt(e,"marginRight")})}}),!v.support.pixelPosition&&v.fn.position&&v.each(["top","left"],function(e,t){v.cssHooks[t]={get:function(e,n){if(n){var r=Dt(e,t);return Ut.test(r)?v(e).position()[t]+"px":r}}}})}),v.expr&&v.expr.filters&&(v.expr.filters.hidden=function(e){return e.offsetWidth===0&&e.offsetHeight===0||!v.support.reliableHiddenOffsets&&(e.style&&e.style.display||Dt(e,"display"))==="none"},v.expr.filters.visible=function(e){return!v.expr.filters.hidden(e)}),v.each({margin:"",padding:"",border:"Width"},function(e,t){v.cssHooks[e+t]={expand:function(n){var r,i=typeof n=="string"?n.split(" "):[n],s={};for(r=0;r<4;r++)s[e+$t[r]+t]=i[r]||i[r-2]||i[0];return s}},qt.test(e)||(v.cssHooks[e+t].set=Zt)});var rn=/%20/g,sn=/\[\]$/,on=/\r?\n/g,un=/^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,an=/^(?:select|textarea)/i;v.fn.extend({serialize:function(){return v.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?v.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||an.test(this.nodeName)||un.test(this.type))}).map(function(e,t){var n=v(this).val();return n==null?null:v.isArray(n)?v.map(n,function(e,n){return{name:t.name,value:e.replace(on,"\r\n")}}):{name:t.name,value:n.replace(on,"\r\n")}}).get()}}),v.param=function(e,n){var r,i=[],s=function(e,t){t=v.isFunction(t)?t():t==null?"":t,i[i.length]=encodeURIComponent(e)+"="+encodeURIComponent(t)};n===t&&(n=v.ajaxSettings&&v.ajaxSettings.traditional);if(v.isArray(e)||e.jquery&&!v.isPlainObject(e))v.each(e,function(){s(this.name,this.value)});else for(r in e)fn(r,e[r],n,s);return i.join("&").replace(rn,"+")};var ln,cn,hn=/#.*$/,pn=/^(.*?):[ \t]*([^\r\n]*)\r?$/mg,dn=/^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/,vn=/^(?:GET|HEAD)$/,mn=/^\/\//,gn=/\?/,yn=/)<[^<]*)*<\/script>/gi,bn=/([?&])_=[^&]*/,wn=/^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+)|)|)/,En=v.fn.load,Sn={},xn={},Tn=["*/"]+["*"];try{cn=s.href}catch(Nn){cn=i.createElement("a"),cn.href="",cn=cn.href}ln=wn.exec(cn.toLowerCase())||[],v.fn.load=function(e,n,r){if(typeof e!="string"&&En)return En.apply(this,arguments);if(!this.length)return this;var i,s,o,u=this,a=e.indexOf(" ");return a>=0&&(i=e.slice(a,e.length),e=e.slice(0,a)),v.isFunction(n)?(r=n,n=t):n&&typeof n=="object"&&(s="POST"),v.ajax({url:e,type:s,dataType:"html",data:n,complete:function(e,t){r&&u.each(r,o||[e.responseText,t,e])}}).done(function(e){o=arguments,u.html(i?v("
      ").append(e.replace(yn,"")).find(i):e)}),this},v.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(e,t){v.fn[t]=function(e){return this.on(t,e)}}),v.each(["get","post"],function(e,n){v[n]=function(e,r,i,s){return v.isFunction(r)&&(s=s||i,i=r,r=t),v.ajax({type:n,url:e,data:r,success:i,dataType:s})}}),v.extend({getScript:function(e,n){return v.get(e,t,n,"script")},getJSON:function(e,t,n){return v.get(e,t,n,"json")},ajaxSetup:function(e,t){return t?Ln(e,v.ajaxSettings):(t=e,e=v.ajaxSettings),Ln(e,t),e},ajaxSettings:{url:cn,isLocal:dn.test(ln[1]),global:!0,type:"GET",contentType:"application/x-www-form-urlencoded; charset=UTF-8",processData:!0,async:!0,accepts:{xml:"application/xml, text/xml",html:"text/html",text:"text/plain",json:"application/json, text/javascript","*":Tn},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":e.String,"text html":!0,"text json":v.parseJSON,"text xml":v.parseXML},flatOptions:{context:!0,url:!0}},ajaxPrefilter:Cn(Sn),ajaxTransport:Cn(xn),ajax:function(e,n){function T(e,n,s,a){var l,y,b,w,S,T=n;if(E===2)return;E=2,u&&clearTimeout(u),o=t,i=a||"",x.readyState=e>0?4:0,s&&(w=An(c,x,s));if(e>=200&&e<300||e===304)c.ifModified&&(S=x.getResponseHeader("Last-Modified"),S&&(v.lastModified[r]=S),S=x.getResponseHeader("Etag"),S&&(v.etag[r]=S)),e===304?(T="notmodified",l=!0):(l=On(c,w),T=l.state,y=l.data,b=l.error,l=!b);else{b=T;if(!T||e)T="error",e<0&&(e=0)}x.status=e,x.statusText=(n||T)+"",l?d.resolveWith(h,[y,T,x]):d.rejectWith(h,[x,T,b]),x.statusCode(g),g=t,f&&p.trigger("ajax"+(l?"Success":"Error"),[x,c,l?y:b]),m.fireWith(h,[x,T]),f&&(p.trigger("ajaxComplete",[x,c]),--v.active||v.event.trigger("ajaxStop"))}typeof e=="object"&&(n=e,e=t),n=n||{};var r,i,s,o,u,a,f,l,c=v.ajaxSetup({},n),h=c.context||c,p=h!==c&&(h.nodeType||h instanceof v)?v(h):v.event,d=v.Deferred(),m=v.Callbacks("once memory"),g=c.statusCode||{},b={},w={},E=0,S="canceled",x={readyState:0,setRequestHeader:function(e,t){if(!E){var n=e.toLowerCase();e=w[n]=w[n]||e,b[e]=t}return this},getAllResponseHeaders:function(){return E===2?i:null},getResponseHeader:function(e){var n;if(E===2){if(!s){s={};while(n=pn.exec(i))s[n[1].toLowerCase()]=n[2]}n=s[e.toLowerCase()]}return n===t?null:n},overrideMimeType:function(e){return E||(c.mimeType=e),this},abort:function(e){return e=e||S,o&&o.abort(e),T(0,e),this}};d.promise(x),x.success=x.done,x.error=x.fail,x.complete=m.add,x.statusCode=function(e){if(e){var t;if(E<2)for(t in e)g[t]=[g[t],e[t]];else t=e[x.status],x.always(t)}return this},c.url=((e||c.url)+"").replace(hn,"").replace(mn,ln[1]+"//"),c.dataTypes=v.trim(c.dataType||"*").toLowerCase().split(y),c.crossDomain==null&&(a=wn.exec(c.url.toLowerCase()),c.crossDomain=!(!a||a[1]===ln[1]&&a[2]===ln[2]&&(a[3]||(a[1]==="http:"?80:443))==(ln[3]||(ln[1]==="http:"?80:443)))),c.data&&c.processData&&typeof c.data!="string"&&(c.data=v.param(c.data,c.traditional)),kn(Sn,c,n,x);if(E===2)return x;f=c.global,c.type=c.type.toUpperCase(),c.hasContent=!vn.test(c.type),f&&v.active++===0&&v.event.trigger("ajaxStart");if(!c.hasContent){c.data&&(c.url+=(gn.test(c.url)?"&":"?")+c.data,delete c.data),r=c.url;if(c.cache===!1){var N=v.now(),C=c.url.replace(bn,"$1_="+N);c.url=C+(C===c.url?(gn.test(c.url)?"&":"?")+"_="+N:"")}}(c.data&&c.hasContent&&c.contentType!==!1||n.contentType)&&x.setRequestHeader("Content-Type",c.contentType),c.ifModified&&(r=r||c.url,v.lastModified[r]&&x.setRequestHeader("If-Modified-Since",v.lastModified[r]),v.etag[r]&&x.setRequestHeader("If-None-Match",v.etag[r])),x.setRequestHeader("Accept",c.dataTypes[0]&&c.accepts[c.dataTypes[0]]?c.accepts[c.dataTypes[0]]+(c.dataTypes[0]!=="*"?", "+Tn+"; q=0.01":""):c.accepts["*"]);for(l in c.headers)x.setRequestHeader(l,c.headers[l]);if(!c.beforeSend||c.beforeSend.call(h,x,c)!==!1&&E!==2){S="abort";for(l in{success:1,error:1,complete:1})x[l](c[l]);o=kn(xn,c,n,x);if(!o)T(-1,"No Transport");else{x.readyState=1,f&&p.trigger("ajaxSend",[x,c]),c.async&&c.timeout>0&&(u=setTimeout(function(){x.abort("timeout")},c.timeout));try{E=1,o.send(b,T)}catch(k){if(!(E<2))throw k;T(-1,k)}}return x}return x.abort()},active:0,lastModified:{},etag:{}});var Mn=[],_n=/\?/,Dn=/(=)\?(?=&|$)|\?\?/,Pn=v.now();v.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=Mn.pop()||v.expando+"_"+Pn++;return this[e]=!0,e}}),v.ajaxPrefilter("json jsonp",function(n,r,i){var s,o,u,a=n.data,f=n.url,l=n.jsonp!==!1,c=l&&Dn.test(f),h=l&&!c&&typeof a=="string"&&!(n.contentType||"").indexOf("application/x-www-form-urlencoded")&&Dn.test(a);if(n.dataTypes[0]==="jsonp"||c||h)return s=n.jsonpCallback=v.isFunction(n.jsonpCallback)?n.jsonpCallback():n.jsonpCallback,o=e[s],c?n.url=f.replace(Dn,"$1"+s):h?n.data=a.replace(Dn,"$1"+s):l&&(n.url+=(_n.test(f)?"&":"?")+n.jsonp+"="+s),n.converters["script json"]=function(){return u||v.error(s+" was not called"),u[0]},n.dataTypes[0]="json",e[s]=function(){u=arguments},i.always(function(){e[s]=o,n[s]&&(n.jsonpCallback=r.jsonpCallback,Mn.push(s)),u&&v.isFunction(o)&&o(u[0]),u=o=t}),"script"}),v.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/javascript|ecmascript/},converters:{"text script":function(e){return v.globalEval(e),e}}}),v.ajaxPrefilter("script",function(e){e.cache===t&&(e.cache=!1),e.crossDomain&&(e.type="GET",e.global=!1)}),v.ajaxTransport("script",function(e){if(e.crossDomain){var n,r=i.head||i.getElementsByTagName("head")[0]||i.documentElement;return{send:function(s,o){n=i.createElement("script"),n.async="async",e.scriptCharset&&(n.charset=e.scriptCharset),n.src=e.url,n.onload=n.onreadystatechange=function(e,i){if(i||!n.readyState||/loaded|complete/.test(n.readyState))n.onload=n.onreadystatechange=null,r&&n.parentNode&&r.removeChild(n),n=t,i||o(200,"success")},r.insertBefore(n,r.firstChild)},abort:function(){n&&n.onload(0,1)}}}});var Hn,Bn=e.ActiveXObject?function(){for(var e in Hn)Hn[e](0,1)}:!1,jn=0;v.ajaxSettings.xhr=e.ActiveXObject?function(){return!this.isLocal&&Fn()||In()}:Fn,function(e){v.extend(v.support,{ajax:!!e,cors:!!e&&"withCredentials"in e})}(v.ajaxSettings.xhr()),v.support.ajax&&v.ajaxTransport(function(n){if(!n.crossDomain||v.support.cors){var r;return{send:function(i,s){var o,u,a=n.xhr();n.username?a.open(n.type,n.url,n.async,n.username,n.password):a.open(n.type,n.url,n.async);if(n.xhrFields)for(u in n.xhrFields)a[u]=n.xhrFields[u];n.mimeType&&a.overrideMimeType&&a.overrideMimeType(n.mimeType),!n.crossDomain&&!i["X-Requested-With"]&&(i["X-Requested-With"]="XMLHttpRequest");try{for(u in i)a.setRequestHeader(u,i[u])}catch(f){}a.send(n.hasContent&&n.data||null),r=function(e,i){var u,f,l,c,h;try{if(r&&(i||a.readyState===4)){r=t,o&&(a.onreadystatechange=v.noop,Bn&&delete Hn[o]);if(i)a.readyState!==4&&a.abort();else{u=a.status,l=a.getAllResponseHeaders(),c={},h=a.responseXML,h&&h.documentElement&&(c.xml=h);try{c.text=a.responseText}catch(p){}try{f=a.statusText}catch(p){f=""}!u&&n.isLocal&&!n.crossDomain?u=c.text?200:404:u===1223&&(u=204)}}}catch(d){i||s(-1,d)}c&&s(u,f,c,l)},n.async?a.readyState===4?setTimeout(r,0):(o=++jn,Bn&&(Hn||(Hn={},v(e).unload(Bn)),Hn[o]=r),a.onreadystatechange=r):r()},abort:function(){r&&r(0,1)}}}});var qn,Rn,Un=/^(?:toggle|show|hide)$/,zn=new RegExp("^(?:([-+])=|)("+m+")([a-z%]*)$","i"),Wn=/queueHooks$/,Xn=[Gn],Vn={"*":[function(e,t){var n,r,i=this.createTween(e,t),s=zn.exec(t),o=i.cur(),u=+o||0,a=1,f=20;if(s){n=+s[2],r=s[3]||(v.cssNumber[e]?"":"px");if(r!=="px"&&u){u=v.css(i.elem,e,!0)||n||1;do a=a||".5",u/=a,v.style(i.elem,e,u+r);while(a!==(a=i.cur()/o)&&a!==1&&--f)}i.unit=r,i.start=u,i.end=s[1]?u+(s[1]+1)*n:n}return i}]};v.Animation=v.extend(Kn,{tweener:function(e,t){v.isFunction(e)?(t=e,e=["*"]):e=e.split(" ");var n,r=0,i=e.length;for(;r-1,f={},l={},c,h;a?(l=i.position(),c=l.top,h=l.left):(c=parseFloat(o)||0,h=parseFloat(u)||0),v.isFunction(t)&&(t=t.call(e,n,s)),t.top!=null&&(f.top=t.top-s.top+c),t.left!=null&&(f.left=t.left-s.left+h),"using"in t?t.using.call(e,f):i.css(f)}},v.fn.extend({position:function(){if(!this[0])return;var e=this[0],t=this.offsetParent(),n=this.offset(),r=er.test(t[0].nodeName)?{top:0,left:0}:t.offset();return n.top-=parseFloat(v.css(e,"marginTop"))||0,n.left-=parseFloat(v.css(e,"marginLeft"))||0,r.top+=parseFloat(v.css(t[0],"borderTopWidth"))||0,r.left+=parseFloat(v.css(t[0],"borderLeftWidth"))||0,{top:n.top-r.top,left:n.left-r.left}},offsetParent:function(){return this.map(function(){var e=this.offsetParent||i.body;while(e&&!er.test(e.nodeName)&&v.css(e,"position")==="static")e=e.offsetParent;return e||i.body})}}),v.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(e,n){var r=/Y/.test(n);v.fn[e]=function(i){return v.access(this,function(e,i,s){var o=tr(e);if(s===t)return o?n in o?o[n]:o.document.documentElement[i]:e[i];o?o.scrollTo(r?v(o).scrollLeft():s,r?s:v(o).scrollTop()):e[i]=s},e,i,arguments.length,null)}}),v.each({Height:"height",Width:"width"},function(e,n){v.each({padding:"inner"+e,content:n,"":"outer"+e},function(r,i){v.fn[i]=function(i,s){var o=arguments.length&&(r||typeof i!="boolean"),u=r||(i===!0||s===!0?"margin":"border");return v.access(this,function(n,r,i){var s;return v.isWindow(n)?n.document.documentElement["client"+e]:n.nodeType===9?(s=n.documentElement,Math.max(n.body["scroll"+e],s["scroll"+e],n.body["offset"+e],s["offset"+e],s["client"+e])):i===t?v.css(n,r,i,u):v.style(n,r,i,u)},n,o?i:t,o,null)}})}),e.jQuery=e.$=v,typeof define=="function"&&define.amd&&define.amd.jQuery&&define("jquery",[],function(){return v})})(window); + +/*! jQuery UI - v1.9.2 - 2012-12-26 +* http://jqueryui.com +* Includes: jquery.ui.core.js, jquery.ui.widget.js, jquery.ui.mouse.js, jquery.ui.position.js, jquery.ui.draggable.js, jquery.ui.droppable.js, jquery.ui.resizable.js, jquery.ui.selectable.js, jquery.ui.sortable.js, jquery.ui.accordion.js, jquery.ui.autocomplete.js, jquery.ui.button.js, jquery.ui.datepicker.js, jquery.ui.dialog.js, jquery.ui.menu.js, jquery.ui.progressbar.js, jquery.ui.slider.js, jquery.ui.spinner.js, jquery.ui.tabs.js, jquery.ui.tooltip.js, jquery.ui.effect.js, jquery.ui.effect-blind.js, jquery.ui.effect-bounce.js, jquery.ui.effect-clip.js, jquery.ui.effect-drop.js, jquery.ui.effect-explode.js, jquery.ui.effect-fade.js, jquery.ui.effect-fold.js, jquery.ui.effect-highlight.js, jquery.ui.effect-pulsate.js, jquery.ui.effect-scale.js, jquery.ui.effect-shake.js, jquery.ui.effect-slide.js, jquery.ui.effect-transfer.js +* Copyright (c) 2012 jQuery Foundation and other contributors Licensed MIT */ +(function(e,t){function i(t,n){var r,i,o,u=t.nodeName.toLowerCase();return"area"===u?(r=t.parentNode,i=r.name,!t.href||!i||r.nodeName.toLowerCase()!=="map"?!1:(o=e("img[usemap=#"+i+"]")[0],!!o&&s(o))):(/input|select|textarea|button|object/.test(u)?!t.disabled:"a"===u?t.href||n:n)&&s(t)}function s(t){return e.expr.filters.visible(t)&&!e(t).parents().andSelf().filter(function(){return e.css(this,"visibility")==="hidden"}).length}var n=0,r=/^ui-id-\d+$/;e.ui=e.ui||{};if(e.ui.version)return;e.extend(e.ui,{version:"1.9.2",keyCode:{BACKSPACE:8,COMMA:188,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,LEFT:37,NUMPAD_ADD:107,NUMPAD_DECIMAL:110,NUMPAD_DIVIDE:111,NUMPAD_ENTER:108,NUMPAD_MULTIPLY:106,NUMPAD_SUBTRACT:109,PAGE_DOWN:34,PAGE_UP:33,PERIOD:190,RIGHT:39,SPACE:32,TAB:9,UP:38}}),e.fn.extend({_focus:e.fn.focus,focus:function(t,n){return typeof t=="number"?this.each(function(){var r=this;setTimeout(function(){e(r).focus(),n&&n.call(r)},t)}):this._focus.apply(this,arguments)},scrollParent:function(){var t;return e.ui.ie&&/(static|relative)/.test(this.css("position"))||/absolute/.test(this.css("position"))?t=this.parents().filter(function(){return/(relative|absolute|fixed)/.test(e.css(this,"position"))&&/(auto|scroll)/.test(e.css(this,"overflow")+e.css(this,"overflow-y")+e.css(this,"overflow-x"))}).eq(0):t=this.parents().filter(function(){return/(auto|scroll)/.test(e.css(this,"overflow")+e.css(this,"overflow-y")+e.css(this,"overflow-x"))}).eq(0),/fixed/.test(this.css("position"))||!t.length?e(document):t},zIndex:function(n){if(n!==t)return this.css("zIndex",n);if(this.length){var r=e(this[0]),i,s;while(r.length&&r[0]!==document){i=r.css("position");if(i==="absolute"||i==="relative"||i==="fixed"){s=parseInt(r.css("zIndex"),10);if(!isNaN(s)&&s!==0)return s}r=r.parent()}}return 0},uniqueId:function(){return this.each(function(){this.id||(this.id="ui-id-"+ ++n)})},removeUniqueId:function(){return this.each(function(){r.test(this.id)&&e(this).removeAttr("id")})}}),e.extend(e.expr[":"],{data:e.expr.createPseudo?e.expr.createPseudo(function(t){return function(n){return!!e.data(n,t)}}):function(t,n,r){return!!e.data(t,r[3])},focusable:function(t){return i(t,!isNaN(e.attr(t,"tabindex")))},tabbable:function(t){var n=e.attr(t,"tabindex"),r=isNaN(n);return(r||n>=0)&&i(t,!r)}}),e(function(){var t=document.body,n=t.appendChild(n=document.createElement("div"));n.offsetHeight,e.extend(n.style,{minHeight:"100px",height:"auto",padding:0,borderWidth:0}),e.support.minHeight=n.offsetHeight===100,e.support.selectstart="onselectstart"in n,t.removeChild(n).style.display="none"}),e("").outerWidth(1).jquery||e.each(["Width","Height"],function(n,r){function u(t,n,r,s){return e.each(i,function(){n-=parseFloat(e.css(t,"padding"+this))||0,r&&(n-=parseFloat(e.css(t,"border"+this+"Width"))||0),s&&(n-=parseFloat(e.css(t,"margin"+this))||0)}),n}var i=r==="Width"?["Left","Right"]:["Top","Bottom"],s=r.toLowerCase(),o={innerWidth:e.fn.innerWidth,innerHeight:e.fn.innerHeight,outerWidth:e.fn.outerWidth,outerHeight:e.fn.outerHeight};e.fn["inner"+r]=function(n){return n===t?o["inner"+r].call(this):this.each(function(){e(this).css(s,u(this,n)+"px")})},e.fn["outer"+r]=function(t,n){return typeof t!="number"?o["outer"+r].call(this,t):this.each(function(){e(this).css(s,u(this,t,!0,n)+"px")})}}),e("").data("a-b","a").removeData("a-b").data("a-b")&&(e.fn.removeData=function(t){return function(n){return arguments.length?t.call(this,e.camelCase(n)):t.call(this)}}(e.fn.removeData)),function(){var t=/msie ([\w.]+)/.exec(navigator.userAgent.toLowerCase())||[];e.ui.ie=t.length?!0:!1,e.ui.ie6=parseFloat(t[1],10)===6}(),e.fn.extend({disableSelection:function(){return this.bind((e.support.selectstart?"selectstart":"mousedown")+".ui-disableSelection",function(e){e.preventDefault()})},enableSelection:function(){return this.unbind(".ui-disableSelection")}}),e.extend(e.ui,{plugin:{add:function(t,n,r){var i,s=e.ui[t].prototype;for(i in r)s.plugins[i]=s.plugins[i]||[],s.plugins[i].push([n,r[i]])},call:function(e,t,n){var r,i=e.plugins[t];if(!i||!e.element[0].parentNode||e.element[0].parentNode.nodeType===11)return;for(r=0;r0?!0:(t[r]=1,i=t[r]>0,t[r]=0,i)},isOverAxis:function(e,t,n){return e>t&&e",options:{disabled:!1,create:null},_createWidget:function(t,r){r=e(r||this.defaultElement||this)[0],this.element=e(r),this.uuid=n++,this.eventNamespace="."+this.widgetName+this.uuid,this.options=e.widget.extend({},this.options,this._getCreateOptions(),t),this.bindings=e(),this.hoverable=e(),this.focusable=e(),r!==this&&(e.data(r,this.widgetName,this),e.data(r,this.widgetFullName,this),this._on(!0,this.element,{remove:function(e){e.target===r&&this.destroy()}}),this.document=e(r.style?r.ownerDocument:r.document||r),this.window=e(this.document[0].defaultView||this.document[0].parentWindow)),this._create(),this._trigger("create",null,this._getCreateEventData()),this._init()},_getCreateOptions:e.noop,_getCreateEventData:e.noop,_create:e.noop,_init:e.noop,destroy:function(){this._destroy(),this.element.unbind(this.eventNamespace).removeData(this.widgetName).removeData(this.widgetFullName).removeData(e.camelCase(this.widgetFullName)),this.widget().unbind(this.eventNamespace).removeAttr("aria-disabled").removeClass(this.widgetFullName+"-disabled "+"ui-state-disabled"),this.bindings.unbind(this.eventNamespace),this.hoverable.removeClass("ui-state-hover"),this.focusable.removeClass("ui-state-focus")},_destroy:e.noop,widget:function(){return this.element},option:function(n,r){var i=n,s,o,u;if(arguments.length===0)return e.widget.extend({},this.options);if(typeof n=="string"){i={},s=n.split("."),n=s.shift();if(s.length){o=i[n]=e.widget.extend({},this.options[n]);for(u=0;u=9||!!t.button?this._mouseStarted?(this._mouseDrag(t),t.preventDefault()):(this._mouseDistanceMet(t)&&this._mouseDelayMet(t)&&(this._mouseStarted=this._mouseStart(this._mouseDownEvent,t)!==!1,this._mouseStarted?this._mouseDrag(t):this._mouseUp(t)),!this._mouseStarted):this._mouseUp(t)},_mouseUp:function(t){return e(document).unbind("mousemove."+this.widgetName,this._mouseMoveDelegate).unbind("mouseup."+this.widgetName,this._mouseUpDelegate),this._mouseStarted&&(this._mouseStarted=!1,t.target===this._mouseDownEvent.target&&e.data(t.target,this.widgetName+".preventClickEvent",!0),this._mouseStop(t)),!1},_mouseDistanceMet:function(e){return Math.max(Math.abs(this._mouseDownEvent.pageX-e.pageX),Math.abs(this._mouseDownEvent.pageY-e.pageY))>=this.options.distance},_mouseDelayMet:function(e){return this.mouseDelayMet},_mouseStart:function(e){},_mouseDrag:function(e){},_mouseStop:function(e){},_mouseCapture:function(e){return!0}})})(jQuery);(function(e,t){function h(e,t,n){return[parseInt(e[0],10)*(l.test(e[0])?t/100:1),parseInt(e[1],10)*(l.test(e[1])?n/100:1)]}function p(t,n){return parseInt(e.css(t,n),10)||0}e.ui=e.ui||{};var n,r=Math.max,i=Math.abs,s=Math.round,o=/left|center|right/,u=/top|center|bottom/,a=/[\+\-]\d+%?/,f=/^\w+/,l=/%$/,c=e.fn.position;e.position={scrollbarWidth:function(){if(n!==t)return n;var r,i,s=e("
      "),o=s.children()[0];return e("body").append(s),r=o.offsetWidth,s.css("overflow","scroll"),i=o.offsetWidth,r===i&&(i=s[0].clientWidth),s.remove(),n=r-i},getScrollInfo:function(t){var n=t.isWindow?"":t.element.css("overflow-x"),r=t.isWindow?"":t.element.css("overflow-y"),i=n==="scroll"||n==="auto"&&t.width0?"right":"center",vertical:u<0?"top":o>0?"bottom":"middle"};lr(i(o),i(u))?h.important="horizontal":h.important="vertical",t.using.call(this,e,h)}),a.offset(e.extend(C,{using:u}))})},e.ui.position={fit:{left:function(e,t){var n=t.within,i=n.isWindow?n.scrollLeft:n.offset.left,s=n.width,o=e.left-t.collisionPosition.marginLeft,u=i-o,a=o+t.collisionWidth-s-i,f;t.collisionWidth>s?u>0&&a<=0?(f=e.left+u+t.collisionWidth-s-i,e.left+=u-f):a>0&&u<=0?e.left=i:u>a?e.left=i+s-t.collisionWidth:e.left=i:u>0?e.left+=u:a>0?e.left-=a:e.left=r(e.left-o,e.left)},top:function(e,t){var n=t.within,i=n.isWindow?n.scrollTop:n.offset.top,s=t.within.height,o=e.top-t.collisionPosition.marginTop,u=i-o,a=o+t.collisionHeight-s-i,f;t.collisionHeight>s?u>0&&a<=0?(f=e.top+u+t.collisionHeight-s-i,e.top+=u-f):a>0&&u<=0?e.top=i:u>a?e.top=i+s-t.collisionHeight:e.top=i:u>0?e.top+=u:a>0?e.top-=a:e.top=r(e.top-o,e.top)}},flip:{left:function(e,t){var n=t.within,r=n.offset.left+n.scrollLeft,s=n.width,o=n.isWindow?n.scrollLeft:n.offset.left,u=e.left-t.collisionPosition.marginLeft,a=u-o,f=u+t.collisionWidth-s-o,l=t.my[0]==="left"?-t.elemWidth:t.my[0]==="right"?t.elemWidth:0,c=t.at[0]==="left"?t.targetWidth:t.at[0]==="right"?-t.targetWidth:0,h=-2*t.offset[0],p,d;if(a<0){p=e.left+l+c+h+t.collisionWidth-s-r;if(p<0||p0){d=e.left-t.collisionPosition.marginLeft+l+c+h-o;if(d>0||i(d)a&&(v<0||v0&&(d=e.top-t.collisionPosition.marginTop+c+h+p-o,e.top+c+h+p>f&&(d>0||i(d)10&&i<11,t.innerHTML="",n.removeChild(t)}(),e.uiBackCompat!==!1&&function(e){var n=e.fn.position;e.fn.position=function(r){if(!r||!r.offset)return n.call(this,r);var i=r.offset.split(" "),s=r.at.split(" ");return i.length===1&&(i[1]=i[0]),/^\d/.test(i[0])&&(i[0]="+"+i[0]),/^\d/.test(i[1])&&(i[1]="+"+i[1]),s.length===1&&(/left|center|right/.test(s[0])?s[1]="center":(s[1]=s[0],s[0]="center")),n.call(this,e.extend(r,{at:s[0]+i[0]+" "+s[1]+i[1],offset:t}))}}(jQuery)})(jQuery);(function(e,t){e.widget("ui.draggable",e.ui.mouse,{version:"1.9.2",widgetEventPrefix:"drag",options:{addClasses:!0,appendTo:"parent",axis:!1,connectToSortable:!1,containment:!1,cursor:"auto",cursorAt:!1,grid:!1,handle:!1,helper:"original",iframeFix:!1,opacity:!1,refreshPositions:!1,revert:!1,revertDuration:500,scope:"default",scroll:!0,scrollSensitivity:20,scrollSpeed:20,snap:!1,snapMode:"both",snapTolerance:20,stack:!1,zIndex:!1},_create:function(){this.options.helper=="original"&&!/^(?:r|a|f)/.test(this.element.css("position"))&&(this.element[0].style.position="relative"),this.options.addClasses&&this.element.addClass("ui-draggable"),this.options.disabled&&this.element.addClass("ui-draggable-disabled"),this._mouseInit()},_destroy:function(){this.element.removeClass("ui-draggable ui-draggable-dragging ui-draggable-disabled"),this._mouseDestroy()},_mouseCapture:function(t){var n=this.options;return this.helper||n.disabled||e(t.target).is(".ui-resizable-handle")?!1:(this.handle=this._getHandle(t),this.handle?(e(n.iframeFix===!0?"iframe":n.iframeFix).each(function(){e('
      ').css({width:this.offsetWidth+"px",height:this.offsetHeight+"px",position:"absolute",opacity:"0.001",zIndex:1e3}).css(e(this).offset()).appendTo("body")}),!0):!1)},_mouseStart:function(t){var n=this.options;return this.helper=this._createHelper(t),this.helper.addClass("ui-draggable-dragging"),this._cacheHelperProportions(),e.ui.ddmanager&&(e.ui.ddmanager.current=this),this._cacheMargins(),this.cssPosition=this.helper.css("position"),this.scrollParent=this.helper.scrollParent(),this.offset=this.positionAbs=this.element.offset(),this.offset={top:this.offset.top-this.margins.top,left:this.offset.left-this.margins.left},e.extend(this.offset,{click:{left:t.pageX-this.offset.left,top:t.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()}),this.originalPosition=this.position=this._generatePosition(t),this.originalPageX=t.pageX,this.originalPageY=t.pageY,n.cursorAt&&this._adjustOffsetFromHelper(n.cursorAt),n.containment&&this._setContainment(),this._trigger("start",t)===!1?(this._clear(),!1):(this._cacheHelperProportions(),e.ui.ddmanager&&!n.dropBehaviour&&e.ui.ddmanager.prepareOffsets(this,t),this._mouseDrag(t,!0),e.ui.ddmanager&&e.ui.ddmanager.dragStart(this,t),!0)},_mouseDrag:function(t,n){this.position=this._generatePosition(t),this.positionAbs=this._convertPositionTo("absolute");if(!n){var r=this._uiHash();if(this._trigger("drag",t,r)===!1)return this._mouseUp({}),!1;this.position=r.position}if(!this.options.axis||this.options.axis!="y")this.helper[0].style.left=this.position.left+"px";if(!this.options.axis||this.options.axis!="x")this.helper[0].style.top=this.position.top+"px";return e.ui.ddmanager&&e.ui.ddmanager.drag(this,t),!1},_mouseStop:function(t){var n=!1;e.ui.ddmanager&&!this.options.dropBehaviour&&(n=e.ui.ddmanager.drop(this,t)),this.dropped&&(n=this.dropped,this.dropped=!1);var r=this.element[0],i=!1;while(r&&(r=r.parentNode))r==document&&(i=!0);if(!i&&this.options.helper==="original")return!1;if(this.options.revert=="invalid"&&!n||this.options.revert=="valid"&&n||this.options.revert===!0||e.isFunction(this.options.revert)&&this.options.revert.call(this.element,n)){var s=this;e(this.helper).animate(this.originalPosition,parseInt(this.options.revertDuration,10),function(){s._trigger("stop",t)!==!1&&s._clear()})}else this._trigger("stop",t)!==!1&&this._clear();return!1},_mouseUp:function(t){return e("div.ui-draggable-iframeFix").each(function(){this.parentNode.removeChild(this)}),e.ui.ddmanager&&e.ui.ddmanager.dragStop(this,t),e.ui.mouse.prototype._mouseUp.call(this,t)},cancel:function(){return this.helper.is(".ui-draggable-dragging")?this._mouseUp({}):this._clear(),this},_getHandle:function(t){var n=!this.options.handle||!e(this.options.handle,this.element).length?!0:!1;return e(this.options.handle,this.element).find("*").andSelf().each(function(){this==t.target&&(n=!0)}),n},_createHelper:function(t){var n=this.options,r=e.isFunction(n.helper)?e(n.helper.apply(this.element[0],[t])):n.helper=="clone"?this.element.clone().removeAttr("id"):this.element;return r.parents("body").length||r.appendTo(n.appendTo=="parent"?this.element[0].parentNode:n.appendTo),r[0]!=this.element[0]&&!/(fixed|absolute)/.test(r.css("position"))&&r.css("position","absolute"),r},_adjustOffsetFromHelper:function(t){typeof t=="string"&&(t=t.split(" ")),e.isArray(t)&&(t={left:+t[0],top:+t[1]||0}),"left"in t&&(this.offset.click.left=t.left+this.margins.left),"right"in t&&(this.offset.click.left=this.helperProportions.width-t.right+this.margins.left),"top"in t&&(this.offset.click.top=t.top+this.margins.top),"bottom"in t&&(this.offset.click.top=this.helperProportions.height-t.bottom+this.margins.top)},_getParentOffset:function(){this.offsetParent=this.helper.offsetParent();var t=this.offsetParent.offset();this.cssPosition=="absolute"&&this.scrollParent[0]!=document&&e.contains(this.scrollParent[0],this.offsetParent[0])&&(t.left+=this.scrollParent.scrollLeft(),t.top+=this.scrollParent.scrollTop());if(this.offsetParent[0]==document.body||this.offsetParent[0].tagName&&this.offsetParent[0].tagName.toLowerCase()=="html"&&e.ui.ie)t={top:0,left:0};return{top:t.top+(parseInt(this.offsetParent.css("borderTopWidth"),10)||0),left:t.left+(parseInt(this.offsetParent.css("borderLeftWidth"),10)||0)}},_getRelativeOffset:function(){if(this.cssPosition=="relative"){var e=this.element.position();return{top:e.top-(parseInt(this.helper.css("top"),10)||0)+this.scrollParent.scrollTop(),left:e.left-(parseInt(this.helper.css("left"),10)||0)+this.scrollParent.scrollLeft()}}return{top:0,left:0}},_cacheMargins:function(){this.margins={left:parseInt(this.element.css("marginLeft"),10)||0,top:parseInt(this.element.css("marginTop"),10)||0,right:parseInt(this.element.css("marginRight"),10)||0,bottom:parseInt(this.element.css("marginBottom"),10)||0}},_cacheHelperProportions:function(){this.helperProportions={width:this.helper.outerWidth(),height:this.helper.outerHeight()}},_setContainment:function(){var t=this.options;t.containment=="parent"&&(t.containment=this.helper[0].parentNode);if(t.containment=="document"||t.containment=="window")this.containment=[t.containment=="document"?0:e(window).scrollLeft()-this.offset.relative.left-this.offset.parent.left,t.containment=="document"?0:e(window).scrollTop()-this.offset.relative.top-this.offset.parent.top,(t.containment=="document"?0:e(window).scrollLeft())+e(t.containment=="document"?document:window).width()-this.helperProportions.width-this.margins.left,(t.containment=="document"?0:e(window).scrollTop())+(e(t.containment=="document"?document:window).height()||document.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top];if(!/^(document|window|parent)$/.test(t.containment)&&t.containment.constructor!=Array){var n=e(t.containment),r=n[0];if(!r)return;var i=n.offset(),s=e(r).css("overflow")!="hidden";this.containment=[(parseInt(e(r).css("borderLeftWidth"),10)||0)+(parseInt(e(r).css("paddingLeft"),10)||0),(parseInt(e(r).css("borderTopWidth"),10)||0)+(parseInt(e(r).css("paddingTop"),10)||0),(s?Math.max(r.scrollWidth,r.offsetWidth):r.offsetWidth)-(parseInt(e(r).css("borderLeftWidth"),10)||0)-(parseInt(e(r).css("paddingRight"),10)||0)-this.helperProportions.width-this.margins.left-this.margins.right,(s?Math.max(r.scrollHeight,r.offsetHeight):r.offsetHeight)-(parseInt(e(r).css("borderTopWidth"),10)||0)-(parseInt(e(r).css("paddingBottom"),10)||0)-this.helperProportions.height-this.margins.top-this.margins.bottom],this.relative_container=n}else t.containment.constructor==Array&&(this.containment=t.containment)},_convertPositionTo:function(t,n){n||(n=this.position);var r=t=="absolute"?1:-1,i=this.options,s=this.cssPosition!="absolute"||this.scrollParent[0]!=document&&!!e.contains(this.scrollParent[0],this.offsetParent[0])?this.scrollParent:this.offsetParent,o=/(html|body)/i.test(s[0].tagName);return{top:n.top+this.offset.relative.top*r+this.offset.parent.top*r-(this.cssPosition=="fixed"?-this.scrollParent.scrollTop():o?0:s.scrollTop())*r,left:n.left+this.offset.relative.left*r+this.offset.parent.left*r-(this.cssPosition=="fixed"?-this.scrollParent.scrollLeft():o?0:s.scrollLeft())*r}},_generatePosition:function(t){var n=this.options,r=this.cssPosition!="absolute"||this.scrollParent[0]!=document&&!!e.contains(this.scrollParent[0],this.offsetParent[0])?this.scrollParent:this.offsetParent,i=/(html|body)/i.test(r[0].tagName),s=t.pageX,o=t.pageY;if(this.originalPosition){var u;if(this.containment){if(this.relative_container){var a=this.relative_container.offset();u=[this.containment[0]+a.left,this.containment[1]+a.top,this.containment[2]+a.left,this.containment[3]+a.top]}else u=this.containment;t.pageX-this.offset.click.leftu[2]&&(s=u[2]+this.offset.click.left),t.pageY-this.offset.click.top>u[3]&&(o=u[3]+this.offset.click.top)}if(n.grid){var f=n.grid[1]?this.originalPageY+Math.round((o-this.originalPageY)/n.grid[1])*n.grid[1]:this.originalPageY;o=u?f-this.offset.click.topu[3]?f-this.offset.click.topu[2]?l-this.offset.click.left=0;l--){var c=r.snapElements[l].left,h=c+r.snapElements[l].width,p=r.snapElements[l].top,d=p+r.snapElements[l].height;if(!(c-s=l&&o<=c||u>=l&&u<=c||oc)&&(i>=a&&i<=f||s>=a&&s<=f||if);default:return!1}},e.ui.ddmanager={current:null,droppables:{"default":[]},prepareOffsets:function(t,n){var r=e.ui.ddmanager.droppables[t.options.scope]||[],i=n?n.type:null,s=(t.currentItem||t.element).find(":data(droppable)").andSelf();e:for(var o=0;o
      ').css({position:this.element.css("position"),width:this.element.outerWidth(),height:this.element.outerHeight(),top:this.element.css("top"),left:this.element.css("left")})),this.element=this.element.parent().data("resizable",this.element.data("resizable")),this.elementIsWrapper=!0,this.element.css({marginLeft:this.originalElement.css("marginLeft"),marginTop:this.originalElement.css("marginTop"),marginRight:this.originalElement.css("marginRight"),marginBottom:this.originalElement.css("marginBottom")}),this.originalElement.css({marginLeft:0,marginTop:0,marginRight:0,marginBottom:0}),this.originalResizeStyle=this.originalElement.css("resize"),this.originalElement.css("resize","none"),this._proportionallyResizeElements.push(this.originalElement.css({position:"static",zoom:1,display:"block"})),this.originalElement.css({margin:this.originalElement.css("margin")}),this._proportionallyResize()),this.handles=n.handles||(e(".ui-resizable-handle",this.element).length?{n:".ui-resizable-n",e:".ui-resizable-e",s:".ui-resizable-s",w:".ui-resizable-w",se:".ui-resizable-se",sw:".ui-resizable-sw",ne:".ui-resizable-ne",nw:".ui-resizable-nw"}:"e,s,se");if(this.handles.constructor==String){this.handles=="all"&&(this.handles="n,e,s,w,se,sw,ne,nw");var r=this.handles.split(",");this.handles={};for(var i=0;i');u.css({zIndex:n.zIndex}),"se"==s&&u.addClass("ui-icon ui-icon-gripsmall-diagonal-se"),this.handles[s]=".ui-resizable-"+s,this.element.append(u)}}this._renderAxis=function(t){t=t||this.element;for(var n in this.handles){this.handles[n].constructor==String&&(this.handles[n]=e(this.handles[n],this.element).show());if(this.elementIsWrapper&&this.originalElement[0].nodeName.match(/textarea|input|select|button/i)){var r=e(this.handles[n],this.element),i=0;i=/sw|ne|nw|se|n|s/.test(n)?r.outerHeight():r.outerWidth();var s=["padding",/ne|nw|n/.test(n)?"Top":/se|sw|s/.test(n)?"Bottom":/^e$/.test(n)?"Right":"Left"].join("");t.css(s,i),this._proportionallyResize()}if(!e(this.handles[n]).length)continue}},this._renderAxis(this.element),this._handles=e(".ui-resizable-handle",this.element).disableSelection(),this._handles.mouseover(function(){if(!t.resizing){if(this.className)var e=this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i);t.axis=e&&e[1]?e[1]:"se"}}),n.autoHide&&(this._handles.hide(),e(this.element).addClass("ui-resizable-autohide").mouseenter(function(){if(n.disabled)return;e(this).removeClass("ui-resizable-autohide"),t._handles.show()}).mouseleave(function(){if(n.disabled)return;t.resizing||(e(this).addClass("ui-resizable-autohide"),t._handles.hide())})),this._mouseInit()},_destroy:function(){this._mouseDestroy();var t=function(t){e(t).removeClass("ui-resizable ui-resizable-disabled ui-resizable-resizing").removeData("resizable").removeData("ui-resizable").unbind(".resizable").find(".ui-resizable-handle").remove()};if(this.elementIsWrapper){t(this.element);var n=this.element;this.originalElement.css({position:n.css("position"),width:n.outerWidth(),height:n.outerHeight(),top:n.css("top"),left:n.css("left")}).insertAfter(n),n.remove()}return this.originalElement.css("resize",this.originalResizeStyle),t(this.originalElement),this},_mouseCapture:function(t){var n=!1;for(var r in this.handles)e(this.handles[r])[0]==t.target&&(n=!0);return!this.options.disabled&&n},_mouseStart:function(t){var r=this.options,i=this.element.position(),s=this.element;this.resizing=!0,this.documentScroll={top:e(document).scrollTop(),left:e(document).scrollLeft()},(s.is(".ui-draggable")||/absolute/.test(s.css("position")))&&s.css({position:"absolute",top:i.top,left:i.left}),this._renderProxy();var o=n(this.helper.css("left")),u=n(this.helper.css("top"));r.containment&&(o+=e(r.containment).scrollLeft()||0,u+=e(r.containment).scrollTop()||0),this.offset=this.helper.offset(),this.position={left:o,top:u},this.size=this._helper?{width:s.outerWidth(),height:s.outerHeight()}:{width:s.width(),height:s.height()},this.originalSize=this._helper?{width:s.outerWidth(),height:s.outerHeight()}:{width:s.width(),height:s.height()},this.originalPosition={left:o,top:u},this.sizeDiff={width:s.outerWidth()-s.width(),height:s.outerHeight()-s.height()},this.originalMousePosition={left:t.pageX,top:t.pageY},this.aspectRatio=typeof r.aspectRatio=="number"?r.aspectRatio:this.originalSize.width/this.originalSize.height||1;var a=e(".ui-resizable-"+this.axis).css("cursor");return e("body").css("cursor",a=="auto"?this.axis+"-resize":a),s.addClass("ui-resizable-resizing"),this._propagate("start",t),!0},_mouseDrag:function(e){var t=this.helper,n=this.options,r={},i=this,s=this.originalMousePosition,o=this.axis,u=e.pageX-s.left||0,a=e.pageY-s.top||0,f=this._change[o];if(!f)return!1;var l=f.apply(this,[e,u,a]);this._updateVirtualBoundaries(e.shiftKey);if(this._aspectRatio||e.shiftKey)l=this._updateRatio(l,e);return l=this._respectSize(l,e),this._propagate("resize",e),t.css({top:this.position.top+"px",left:this.position.left+"px",width:this.size.width+"px",height:this.size.height+"px"}),!this._helper&&this._proportionallyResizeElements.length&&this._proportionallyResize(),this._updateCache(l),this._trigger("resize",e,this.ui()),!1},_mouseStop:function(t){this.resizing=!1;var n=this.options,r=this;if(this._helper){var i=this._proportionallyResizeElements,s=i.length&&/textarea/i.test(i[0].nodeName),o=s&&e.ui.hasScroll(i[0],"left")?0:r.sizeDiff.height,u=s?0:r.sizeDiff.width,a={width:r.helper.width()-u,height:r.helper.height()-o},f=parseInt(r.element.css("left"),10)+(r.position.left-r.originalPosition.left)||null,l=parseInt(r.element.css("top"),10)+(r.position.top-r.originalPosition.top)||null;n.animate||this.element.css(e.extend(a,{top:l,left:f})),r.helper.height(r.size.height),r.helper.width(r.size.width),this._helper&&!n.animate&&this._proportionallyResize()}return e("body").css("cursor","auto"),this.element.removeClass("ui-resizable-resizing"),this._propagate("stop",t),this._helper&&this.helper.remove(),!1},_updateVirtualBoundaries:function(e){var t=this.options,n,i,s,o,u;u={minWidth:r(t.minWidth)?t.minWidth:0,maxWidth:r(t.maxWidth)?t.maxWidth:Infinity,minHeight:r(t.minHeight)?t.minHeight:0,maxHeight:r(t.maxHeight)?t.maxHeight:Infinity};if(this._aspectRatio||e)n=u.minHeight*this.aspectRatio,s=u.minWidth/this.aspectRatio,i=u.maxHeight*this.aspectRatio,o=u.maxWidth/this.aspectRatio,n>u.minWidth&&(u.minWidth=n),s>u.minHeight&&(u.minHeight=s),ie.width,l=r(e.height)&&i.minHeight&&i.minHeight>e.height;f&&(e.width=i.minWidth),l&&(e.height=i.minHeight),u&&(e.width=i.maxWidth),a&&(e.height=i.maxHeight);var c=this.originalPosition.left+this.originalSize.width,h=this.position.top+this.size.height,p=/sw|nw|w/.test(o),d=/nw|ne|n/.test(o);f&&p&&(e.left=c-i.minWidth),u&&p&&(e.left=c-i.maxWidth),l&&d&&(e.top=h-i.minHeight),a&&d&&(e.top=h-i.maxHeight);var v=!e.width&&!e.height;return v&&!e.left&&e.top?e.top=null:v&&!e.top&&e.left&&(e.left=null),e},_proportionallyResize:function(){var t=this.options;if(!this._proportionallyResizeElements.length)return;var n=this.helper||this.element;for(var r=0;r');var r=e.ui.ie6?1:0,i=e.ui.ie6?2:-1;this.helper.addClass(this._helper).css({width:this.element.outerWidth()+i,height:this.element.outerHeight()+i,position:"absolute",left:this.elementOffset.left-r+"px",top:this.elementOffset.top-r+"px",zIndex:++n.zIndex}),this.helper.appendTo("body").disableSelection()}else this.helper=this.element},_change:{e:function(e,t,n){return{width:this.originalSize.width+t}},w:function(e,t,n){var r=this.options,i=this.originalSize,s=this.originalPosition;return{left:s.left+t,width:i.width-t}},n:function(e,t,n){var r=this.options,i=this.originalSize,s=this.originalPosition;return{top:s.top+n,height:i.height-n}},s:function(e,t,n){return{height:this.originalSize.height+n}},se:function(t,n,r){return e.extend(this._change.s.apply(this,arguments),this._change.e.apply(this,[t,n,r]))},sw:function(t,n,r){return e.extend(this._change.s.apply(this,arguments),this._change.w.apply(this,[t,n,r]))},ne:function(t,n,r){return e.extend(this._change.n.apply(this,arguments),this._change.e.apply(this,[t,n,r]))},nw:function(t,n,r){return e.extend(this._change.n.apply(this,arguments),this._change.w.apply(this,[t,n,r]))}},_propagate:function(t,n){e.ui.plugin.call(this,t,[n,this.ui()]),t!="resize"&&this._trigger(t,n,this.ui())},plugins:{},ui:function(){return{originalElement:this.originalElement,element:this.element,helper:this.helper,position:this.position,size:this.size,originalSize:this.originalSize,originalPosition:this.originalPosition}}}),e.ui.plugin.add("resizable","alsoResize",{start:function(t,n){var r=e(this).data("resizable"),i=r.options,s=function(t){e(t).each(function(){var t=e(this);t.data("resizable-alsoresize",{width:parseInt(t.width(),10),height:parseInt(t.height(),10),left:parseInt(t.css("left"),10),top:parseInt(t.css("top"),10)})})};typeof i.alsoResize=="object"&&!i.alsoResize.parentNode?i.alsoResize.length?(i.alsoResize=i.alsoResize[0],s(i.alsoResize)):e.each(i.alsoResize,function(e){s(e)}):s(i.alsoResize)},resize:function(t,n){var r=e(this).data("resizable"),i=r.options,s=r.originalSize,o=r.originalPosition,u={height:r.size.height-s.height||0,width:r.size.width-s.width||0,top:r.position.top-o.top||0,left:r.position.left-o.left||0},a=function(t,r){e(t).each(function(){var t=e(this),i=e(this).data("resizable-alsoresize"),s={},o=r&&r.length?r:t.parents(n.originalElement[0]).length?["width","height"]:["width","height","top","left"];e.each(o,function(e,t){var n=(i[t]||0)+(u[t]||0);n&&n>=0&&(s[t]=n||null)}),t.css(s)})};typeof i.alsoResize=="object"&&!i.alsoResize.nodeType?e.each(i.alsoResize,function(e,t){a(e,t)}):a(i.alsoResize)},stop:function(t,n){e(this).removeData("resizable-alsoresize")}}),e.ui.plugin.add("resizable","animate",{stop:function(t,n){var r=e(this).data("resizable"),i=r.options,s=r._proportionallyResizeElements,o=s.length&&/textarea/i.test(s[0].nodeName),u=o&&e.ui.hasScroll(s[0],"left")?0:r.sizeDiff.height,a=o?0:r.sizeDiff.width,f={width:r.size.width-a,height:r.size.height-u},l=parseInt(r.element.css("left"),10)+(r.position.left-r.originalPosition.left)||null,c=parseInt(r.element.css("top"),10)+(r.position.top-r.originalPosition.top)||null;r.element.animate(e.extend(f,c&&l?{top:c,left:l}:{}),{duration:i.animateDuration,easing:i.animateEasing,step:function(){var n={width:parseInt(r.element.css("width"),10),height:parseInt(r.element.css("height"),10),top:parseInt(r.element.css("top"),10),left:parseInt(r.element.css("left"),10)};s&&s.length&&e(s[0]).css({width:n.width,height:n.height}),r._updateCache(n),r._propagate("resize",t)}})}}),e.ui.plugin.add("resizable","containment",{start:function(t,r){var i=e(this).data("resizable"),s=i.options,o=i.element,u=s.containment,a=u instanceof e?u.get(0):/parent/.test(u)?o.parent().get(0):u;if(!a)return;i.containerElement=e(a);if(/document/.test(u)||u==document)i.containerOffset={left:0,top:0},i.containerPosition={left:0,top:0},i.parentData={element:e(document),left:0,top:0,width:e(document).width(),height:e(document).height()||document.body.parentNode.scrollHeight};else{var f=e(a),l=[];e(["Top","Right","Left","Bottom"]).each(function(e,t){l[e]=n(f.css("padding"+t))}),i.containerOffset=f.offset(),i.containerPosition=f.position(),i.containerSize={height:f.innerHeight()-l[3],width:f.innerWidth()-l[1]};var c=i.containerOffset,h=i.containerSize.height,p=i.containerSize.width,d=e.ui.hasScroll(a,"left")?a.scrollWidth:p,v=e.ui.hasScroll(a)?a.scrollHeight:h;i.parentData={element:a,left:c.left,top:c.top,width:d,height:v}}},resize:function(t,n){var r=e(this).data("resizable"),i=r.options,s=r.containerSize,o=r.containerOffset,u=r.size,a=r.position,f=r._aspectRatio||t.shiftKey,l={top:0,left:0},c=r.containerElement;c[0]!=document&&/static/.test(c.css("position"))&&(l=o),a.left<(r._helper?o.left:0)&&(r.size.width=r.size.width+(r._helper?r.position.left-o.left:r.position.left-l.left),f&&(r.size.height=r.size.width/r.aspectRatio),r.position.left=i.helper?o.left:0),a.top<(r._helper?o.top:0)&&(r.size.height=r.size.height+(r._helper?r.position.top-o.top:r.position.top),f&&(r.size.width=r.size.height*r.aspectRatio),r.position.top=r._helper?o.top:0),r.offset.left=r.parentData.left+r.position.left,r.offset.top=r.parentData.top+r.position.top;var h=Math.abs((r._helper?r.offset.left-l.left:r.offset.left-l.left)+r.sizeDiff.width),p=Math.abs((r._helper?r.offset.top-l.top:r.offset.top-o.top)+r.sizeDiff.height),d=r.containerElement.get(0)==r.element.parent().get(0),v=/relative|absolute/.test(r.containerElement.css("position"));d&&v&&(h-=r.parentData.left),h+r.size.width>=r.parentData.width&&(r.size.width=r.parentData.width-h,f&&(r.size.height=r.size.width/r.aspectRatio)),p+r.size.height>=r.parentData.height&&(r.size.height=r.parentData.height-p,f&&(r.size.width=r.size.height*r.aspectRatio))},stop:function(t,n){var r=e(this).data("resizable"),i=r.options,s=r.position,o=r.containerOffset,u=r.containerPosition,a=r.containerElement,f=e(r.helper),l=f.offset(),c=f.outerWidth()-r.sizeDiff.width,h=f.outerHeight()-r.sizeDiff.height;r._helper&&!i.animate&&/relative/.test(a.css("position"))&&e(this).css({left:l.left-u.left-o.left,width:c,height:h}),r._helper&&!i.animate&&/static/.test(a.css("position"))&&e(this).css({left:l.left-u.left-o.left,width:c,height:h})}}),e.ui.plugin.add("resizable","ghost",{start:function(t,n){var r=e(this).data("resizable"),i=r.options,s=r.size;r.ghost=r.originalElement.clone(),r.ghost.css({opacity:.25,display:"block",position:"relative",height:s.height,width:s.width,margin:0,left:0,top:0}).addClass("ui-resizable-ghost").addClass(typeof i.ghost=="string"?i.ghost:""),r.ghost.appendTo(r.helper)},resize:function(t,n){var r=e(this).data("resizable"),i=r.options;r.ghost&&r.ghost.css({position:"relative",height:r.size.height,width:r.size.width})},stop:function(t,n){var r=e(this).data("resizable"),i=r.options;r.ghost&&r.helper&&r.helper.get(0).removeChild(r.ghost.get(0))}}),e.ui.plugin.add("resizable","grid",{resize:function(t,n){var r=e(this).data("resizable"),i=r.options,s=r.size,o=r.originalSize,u=r.originalPosition,a=r.axis,f=i._aspectRatio||t.shiftKey;i.grid=typeof i.grid=="number"?[i.grid,i.grid]:i.grid;var l=Math.round((s.width-o.width)/(i.grid[0]||1))*(i.grid[0]||1),c=Math.round((s.height-o.height)/(i.grid[1]||1))*(i.grid[1]||1);/^(se|s|e)$/.test(a)?(r.size.width=o.width+l,r.size.height=o.height+c):/^(ne)$/.test(a)?(r.size.width=o.width+l,r.size.height=o.height+c,r.position.top=u.top-c):/^(sw)$/.test(a)?(r.size.width=o.width+l,r.size.height=o.height+c,r.position.left=u.left-l):(r.size.width=o.width+l,r.size.height=o.height+c,r.position.top=u.top-c,r.position.left=u.left-l)}});var n=function(e){return parseInt(e,10)||0},r=function(e){return!isNaN(parseInt(e,10))}})(jQuery);(function(e,t){e.widget("ui.selectable",e.ui.mouse,{version:"1.9.2",options:{appendTo:"body",autoRefresh:!0,distance:0,filter:"*",tolerance:"touch"},_create:function(){var t=this;this.element.addClass("ui-selectable"),this.dragged=!1;var n;this.refresh=function(){n=e(t.options.filter,t.element[0]),n.addClass("ui-selectee"),n.each(function(){var t=e(this),n=t.offset();e.data(this,"selectable-item",{element:this,$element:t,left:n.left,top:n.top,right:n.left+t.outerWidth(),bottom:n.top+t.outerHeight(),startselected:!1,selected:t.hasClass("ui-selected"),selecting:t.hasClass("ui-selecting"),unselecting:t.hasClass("ui-unselecting")})})},this.refresh(),this.selectees=n.addClass("ui-selectee"),this._mouseInit(),this.helper=e("
      ")},_destroy:function(){this.selectees.removeClass("ui-selectee").removeData("selectable-item"),this.element.removeClass("ui-selectable ui-selectable-disabled"),this._mouseDestroy()},_mouseStart:function(t){var n=this;this.opos=[t.pageX,t.pageY];if(this.options.disabled)return;var r=this.options;this.selectees=e(r.filter,this.element[0]),this._trigger("start",t),e(r.appendTo).append(this.helper),this.helper.css({left:t.clientX,top:t.clientY,width:0,height:0}),r.autoRefresh&&this.refresh(),this.selectees.filter(".ui-selected").each(function(){var r=e.data(this,"selectable-item");r.startselected=!0,!t.metaKey&&!t.ctrlKey&&(r.$element.removeClass("ui-selected"),r.selected=!1,r.$element.addClass("ui-unselecting"),r.unselecting=!0,n._trigger("unselecting",t,{unselecting:r.element}))}),e(t.target).parents().andSelf().each(function(){var r=e.data(this,"selectable-item");if(r){var i=!t.metaKey&&!t.ctrlKey||!r.$element.hasClass("ui-selected");return r.$element.removeClass(i?"ui-unselecting":"ui-selected").addClass(i?"ui-selecting":"ui-unselecting"),r.unselecting=!i,r.selecting=i,r.selected=i,i?n._trigger("selecting",t,{selecting:r.element}):n._trigger("unselecting",t,{unselecting:r.element}),!1}})},_mouseDrag:function(t){var n=this;this.dragged=!0;if(this.options.disabled)return;var r=this.options,i=this.opos[0],s=this.opos[1],o=t.pageX,u=t.pageY;if(i>o){var a=o;o=i,i=a}if(s>u){var a=u;u=s,s=a}return this.helper.css({left:i,top:s,width:o-i,height:u-s}),this.selectees.each(function(){var a=e.data(this,"selectable-item");if(!a||a.element==n.element[0])return;var f=!1;r.tolerance=="touch"?f=!(a.left>o||a.rightu||a.bottomi&&a.rights&&a.bottom *",opacity:!1,placeholder:!1,revert:!1,scroll:!0,scrollSensitivity:20,scrollSpeed:20,scope:"default",tolerance:"intersect",zIndex:1e3},_create:function(){var e=this.options;this.containerCache={},this.element.addClass("ui-sortable"),this.refresh(),this.floating=this.items.length?e.axis==="x"||/left|right/.test(this.items[0].item.css("float"))||/inline|table-cell/.test(this.items[0].item.css("display")):!1,this.offset=this.element.offset(),this._mouseInit(),this.ready=!0},_destroy:function(){this.element.removeClass("ui-sortable ui-sortable-disabled"),this._mouseDestroy();for(var e=this.items.length-1;e>=0;e--)this.items[e].item.removeData(this.widgetName+"-item");return this},_setOption:function(t,n){t==="disabled"?(this.options[t]=n,this.widget().toggleClass("ui-sortable-disabled",!!n)):e.Widget.prototype._setOption.apply(this,arguments)},_mouseCapture:function(t,n){var r=this;if(this.reverting)return!1;if(this.options.disabled||this.options.type=="static")return!1;this._refreshItems(t);var i=null,s=e(t.target).parents().each(function(){if(e.data(this,r.widgetName+"-item")==r)return i=e(this),!1});e.data(t.target,r.widgetName+"-item")==r&&(i=e(t.target));if(!i)return!1;if(this.options.handle&&!n){var o=!1;e(this.options.handle,i).find("*").andSelf().each(function(){this==t.target&&(o=!0)});if(!o)return!1}return this.currentItem=i,this._removeCurrentsFromItems(),!0},_mouseStart:function(t,n,r){var i=this.options;this.currentContainer=this,this.refreshPositions(),this.helper=this._createHelper(t),this._cacheHelperProportions(),this._cacheMargins(),this.scrollParent=this.helper.scrollParent(),this.offset=this.currentItem.offset(),this.offset={top:this.offset.top-this.margins.top,left:this.offset.left-this.margins.left},e.extend(this.offset,{click:{left:t.pageX-this.offset.left,top:t.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()}),this.helper.css("position","absolute"),this.cssPosition=this.helper.css("position"),this.originalPosition=this._generatePosition(t),this.originalPageX=t.pageX,this.originalPageY=t.pageY,i.cursorAt&&this._adjustOffsetFromHelper(i.cursorAt),this.domPosition={prev:this.currentItem.prev()[0],parent:this.currentItem.parent()[0]},this.helper[0]!=this.currentItem[0]&&this.currentItem.hide(),this._createPlaceholder(),i.containment&&this._setContainment(),i.cursor&&(e("body").css("cursor")&&(this._storedCursor=e("body").css("cursor")),e("body").css("cursor",i.cursor)),i.opacity&&(this.helper.css("opacity")&&(this._storedOpacity=this.helper.css("opacity")),this.helper.css("opacity",i.opacity)),i.zIndex&&(this.helper.css("zIndex")&&(this._storedZIndex=this.helper.css("zIndex")),this.helper.css("zIndex",i.zIndex)),this.scrollParent[0]!=document&&this.scrollParent[0].tagName!="HTML"&&(this.overflowOffset=this.scrollParent.offset()),this._trigger("start",t,this._uiHash()),this._preserveHelperProportions||this._cacheHelperProportions();if(!r)for(var s=this.containers.length-1;s>=0;s--)this.containers[s]._trigger("activate",t,this._uiHash(this));return e.ui.ddmanager&&(e.ui.ddmanager.current=this),e.ui.ddmanager&&!i.dropBehaviour&&e.ui.ddmanager.prepareOffsets(this,t),this.dragging=!0,this.helper.addClass("ui-sortable-helper"),this._mouseDrag(t),!0},_mouseDrag:function(t){this.position=this._generatePosition(t),this.positionAbs=this._convertPositionTo("absolute"),this.lastPositionAbs||(this.lastPositionAbs=this.positionAbs);if(this.options.scroll){var n=this.options,r=!1;this.scrollParent[0]!=document&&this.scrollParent[0].tagName!="HTML"?(this.overflowOffset.top+this.scrollParent[0].offsetHeight-t.pageY=0;i--){var s=this.items[i],o=s.item[0],u=this._intersectsWithPointer(s);if(!u)continue;if(s.instance!==this.currentContainer)continue;if(o!=this.currentItem[0]&&this.placeholder[u==1?"next":"prev"]()[0]!=o&&!e.contains(this.placeholder[0],o)&&(this.options.type=="semi-dynamic"?!e.contains(this.element[0],o):!0)){this.direction=u==1?"down":"up";if(this.options.tolerance!="pointer"&&!this._intersectsWithSides(s))break;this._rearrange(t,s),this._trigger("change",t,this._uiHash());break}}return this._contactContainers(t),e.ui.ddmanager&&e.ui.ddmanager.drag(this,t),this._trigger("sort",t,this._uiHash()),this.lastPositionAbs=this.positionAbs,!1},_mouseStop:function(t,n){if(!t)return;e.ui.ddmanager&&!this.options.dropBehaviour&&e.ui.ddmanager.drop(this,t);if(this.options.revert){var r=this,i=this.placeholder.offset();this.reverting=!0,e(this.helper).animate({left:i.left-this.offset.parent.left-this.margins.left+(this.offsetParent[0]==document.body?0:this.offsetParent[0].scrollLeft),top:i.top-this.offset.parent.top-this.margins.top+(this.offsetParent[0]==document.body?0:this.offsetParent[0].scrollTop)},parseInt(this.options.revert,10)||500,function(){r._clear(t)})}else this._clear(t,n);return!1},cancel:function(){if(this.dragging){this._mouseUp({target:null}),this.options.helper=="original"?this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper"):this.currentItem.show();for(var t=this.containers.length-1;t>=0;t--)this.containers[t]._trigger("deactivate",null,this._uiHash(this)),this.containers[t].containerCache.over&&(this.containers[t]._trigger("out",null,this._uiHash(this)),this.containers[t].containerCache.over=0)}return this.placeholder&&(this.placeholder[0].parentNode&&this.placeholder[0].parentNode.removeChild(this.placeholder[0]),this.options.helper!="original"&&this.helper&&this.helper[0].parentNode&&this.helper.remove(),e.extend(this,{helper:null,dragging:!1,reverting:!1,_noFinalSort:null}),this.domPosition.prev?e(this.domPosition.prev).after(this.currentItem):e(this.domPosition.parent).prepend(this.currentItem)),this},serialize:function(t){var n=this._getItemsAsjQuery(t&&t.connected),r=[];return t=t||{},e(n).each(function(){var n=(e(t.item||this).attr(t.attribute||"id")||"").match(t.expression||/(.+)[-=_](.+)/);n&&r.push((t.key||n[1]+"[]")+"="+(t.key&&t.expression?n[1]:n[2]))}),!r.length&&t.key&&r.push(t.key+"="),r.join("&")},toArray:function(t){var n=this._getItemsAsjQuery(t&&t.connected),r=[];return t=t||{},n.each(function(){r.push(e(t.item||this).attr(t.attribute||"id")||"")}),r},_intersectsWith:function(e){var t=this.positionAbs.left,n=t+this.helperProportions.width,r=this.positionAbs.top,i=r+this.helperProportions.height,s=e.left,o=s+e.width,u=e.top,a=u+e.height,f=this.offset.click.top,l=this.offset.click.left,c=r+f>u&&r+fs&&t+le[this.floating?"width":"height"]?c:s0?"down":"up")},_getDragHorizontalDirection:function(){var e=this.positionAbs.left-this.lastPositionAbs.left;return e!=0&&(e>0?"right":"left")},refresh:function(e){return this._refreshItems(e),this.refreshPositions(),this},_connectWith:function(){var e=this.options;return e.connectWith.constructor==String?[e.connectWith]:e.connectWith},_getItemsAsjQuery:function(t){var n=[],r=[],i=this._connectWith();if(i&&t)for(var s=i.length-1;s>=0;s--){var o=e(i[s]);for(var u=o.length-1;u>=0;u--){var a=e.data(o[u],this.widgetName);a&&a!=this&&!a.options.disabled&&r.push([e.isFunction(a.options.items)?a.options.items.call(a.element):e(a.options.items,a.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"),a])}}r.push([e.isFunction(this.options.items)?this.options.items.call(this.element,null,{options:this.options,item:this.currentItem}):e(this.options.items,this.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"),this]);for(var s=r.length-1;s>=0;s--)r[s][0].each(function(){n.push(this)});return e(n)},_removeCurrentsFromItems:function(){var t=this.currentItem.find(":data("+this.widgetName+"-item)");this.items=e.grep(this.items,function(e){for(var n=0;n=0;s--){var o=e(i[s]);for(var u=o.length-1;u>=0;u--){var a=e.data(o[u],this.widgetName);a&&a!=this&&!a.options.disabled&&(r.push([e.isFunction(a.options.items)?a.options.items.call(a.element[0],t,{item:this.currentItem}):e(a.options.items,a.element),a]),this.containers.push(a))}}for(var s=r.length-1;s>=0;s--){var f=r[s][1],l=r[s][0];for(var u=0,c=l.length;u=0;n--){var r=this.items[n];if(r.instance!=this.currentContainer&&this.currentContainer&&r.item[0]!=this.currentItem[0])continue;var i=this.options.toleranceElement?e(this.options.toleranceElement,r.item):r.item;t||(r.width=i.outerWidth(),r.height=i.outerHeight());var s=i.offset();r.left=s.left,r.top=s.top}if(this.options.custom&&this.options.custom.refreshContainers)this.options.custom.refreshContainers.call(this);else for(var n=this.containers.length-1;n>=0;n--){var s=this.containers[n].element.offset();this.containers[n].containerCache.left=s.left,this.containers[n].containerCache.top=s.top,this.containers[n].containerCache.width=this.containers[n].element.outerWidth(),this.containers[n].containerCache.height=this.containers[n].element.outerHeight()}return this},_createPlaceholder:function(t){t=t||this;var n=t.options;if(!n.placeholder||n.placeholder.constructor==String){var r=n.placeholder;n.placeholder={element:function(){var n=e(document.createElement(t.currentItem[0].nodeName)).addClass(r||t.currentItem[0].className+" ui-sortable-placeholder").removeClass("ui-sortable-helper")[0];return r||(n.style.visibility="hidden"),n},update:function(e,i){if(r&&!n.forcePlaceholderSize)return;i.height()||i.height(t.currentItem.innerHeight()-parseInt(t.currentItem.css("paddingTop")||0,10)-parseInt(t.currentItem.css("paddingBottom")||0,10)),i.width()||i.width(t.currentItem.innerWidth()-parseInt(t.currentItem.css("paddingLeft")||0,10)-parseInt(t.currentItem.css("paddingRight")||0,10))}}}t.placeholder=e(n.placeholder.element.call(t.element,t.currentItem)),t.currentItem.after(t.placeholder),n.placeholder.update(t,t.placeholder)},_contactContainers:function(t){var n=null,r=null;for(var i=this.containers.length-1;i>=0;i--){if(e.contains(this.currentItem[0],this.containers[i].element[0]))continue;if(this._intersectsWith(this.containers[i].containerCache)){if(n&&e.contains(this.containers[i].element[0],n.element[0]))continue;n=this.containers[i],r=i}else this.containers[i].containerCache.over&&(this.containers[i]._trigger("out",t,this._uiHash(this)),this.containers[i].containerCache.over=0)}if(!n)return;if(this.containers.length===1)this.containers[r]._trigger("over",t,this._uiHash(this)),this.containers[r].containerCache.over=1;else{var s=1e4,o=null,u=this.containers[r].floating?"left":"top",a=this.containers[r].floating?"width":"height",f=this.positionAbs[u]+this.offset.click[u];for(var l=this.items.length-1;l>=0;l--){if(!e.contains(this.containers[r].element[0],this.items[l].item[0]))continue;if(this.items[l].item[0]==this.currentItem[0])continue;var c=this.items[l].item.offset()[u],h=!1;Math.abs(c-f)>Math.abs(c+this.items[l][a]-f)&&(h=!0,c+=this.items[l][a]),Math.abs(c-f)this.containment[2]&&(s=this.containment[2]+this.offset.click.left),t.pageY-this.offset.click.top>this.containment[3]&&(o=this.containment[3]+this.offset.click.top));if(n.grid){var u=this.originalPageY+Math.round((o-this.originalPageY)/n.grid[1])*n.grid[1];o=this.containment?u-this.offset.click.topthis.containment[3]?u-this.offset.click.topthis.containment[2]?a-this.offset.click.left=0;i--)n||r.push(function(e){return function(t){e._trigger("deactivate",t,this._uiHash(this))}}.call(this,this.containers[i])),this.containers[i].containerCache.over&&(r.push(function(e){return function(t){e._trigger("out",t,this._uiHash(this))}}.call(this,this.containers[i])),this.containers[i].containerCache.over=0);this._storedCursor&&e("body").css("cursor",this._storedCursor),this._storedOpacity&&this.helper.css("opacity",this._storedOpacity),this._storedZIndex&&this.helper.css("zIndex",this._storedZIndex=="auto"?"":this._storedZIndex),this.dragging=!1;if(this.cancelHelperRemoval){if(!n){this._trigger("beforeStop",t,this._uiHash());for(var i=0;i li > :first-child,> :not(li):even",heightStyle:"auto",icons:{activeHeader:"ui-icon-triangle-1-s",header:"ui-icon-triangle-1-e"},activate:null,beforeActivate:null},_create:function(){var t=this.accordionId="ui-accordion-"+(this.element.attr("id")||++n),r=this.options;this.prevShow=this.prevHide=e(),this.element.addClass("ui-accordion ui-widget ui-helper-reset"),this.headers=this.element.find(r.header).addClass("ui-accordion-header ui-helper-reset ui-state-default ui-corner-all"),this._hoverable(this.headers),this._focusable(this.headers),this.headers.next().addClass("ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom").hide(),!r.collapsible&&(r.active===!1||r.active==null)&&(r.active=0),r.active<0&&(r.active+=this.headers.length),this.active=this._findActive(r.active).addClass("ui-accordion-header-active ui-state-active").toggleClass("ui-corner-all ui-corner-top"),this.active.next().addClass("ui-accordion-content-active").show(),this._createIcons(),this.refresh(),this.element.attr("role","tablist"),this.headers.attr("role","tab").each(function(n){var r=e(this),i=r.attr("id"),s=r.next(),o=s.attr("id");i||(i=t+"-header-"+n,r.attr("id",i)),o||(o=t+"-panel-"+n,s.attr("id",o)),r.attr("aria-controls",o),s.attr("aria-labelledby",i)}).next().attr("role","tabpanel"),this.headers.not(this.active).attr({"aria-selected":"false",tabIndex:-1}).next().attr({"aria-expanded":"false","aria-hidden":"true"}).hide(),this.active.length?this.active.attr({"aria-selected":"true",tabIndex:0}).next().attr({"aria-expanded":"true","aria-hidden":"false"}):this.headers.eq(0).attr("tabIndex",0),this._on(this.headers,{keydown:"_keydown"}),this._on(this.headers.next(),{keydown:"_panelKeyDown"}),this._setupEvents(r.event)},_getCreateEventData:function(){return{header:this.active,content:this.active.length?this.active.next():e()}},_createIcons:function(){var t=this.options.icons;t&&(e("").addClass("ui-accordion-header-icon ui-icon "+t.header).prependTo(this.headers),this.active.children(".ui-accordion-header-icon").removeClass(t.header).addClass(t.activeHeader),this.headers.addClass("ui-accordion-icons"))},_destroyIcons:function(){this.headers.removeClass("ui-accordion-icons").children(".ui-accordion-header-icon").remove()},_destroy:function(){var e;this.element.removeClass("ui-accordion ui-widget ui-helper-reset").removeAttr("role"),this.headers.removeClass("ui-accordion-header ui-accordion-header-active ui-helper-reset ui-state-default ui-corner-all ui-state-active ui-state-disabled ui-corner-top").removeAttr("role").removeAttr("aria-selected").removeAttr("aria-controls").removeAttr("tabIndex").each(function(){/^ui-accordion/.test(this.id)&&this.removeAttribute("id")}),this._destroyIcons(),e=this.headers.next().css("display","").removeAttr("role").removeAttr("aria-expanded").removeAttr("aria-hidden").removeAttr("aria-labelledby").removeClass("ui-helper-reset ui-widget-content ui-corner-bottom ui-accordion-content ui-accordion-content-active ui-state-disabled").each(function(){/^ui-accordion/.test(this.id)&&this.removeAttribute("id")}),this.options.heightStyle!=="content"&&e.css("height","")},_setOption:function(e,t){if(e==="active"){this._activate(t);return}e==="event"&&(this.options.event&&this._off(this.headers,this.options.event),this._setupEvents(t)),this._super(e,t),e==="collapsible"&&!t&&this.options.active===!1&&this._activate(0),e==="icons"&&(this._destroyIcons(),t&&this._createIcons()),e==="disabled"&&this.headers.add(this.headers.next()).toggleClass("ui-state-disabled",!!t)},_keydown:function(t){if(t.altKey||t.ctrlKey)return;var n=e.ui.keyCode,r=this.headers.length,i=this.headers.index(t.target),s=!1;switch(t.keyCode){case n.RIGHT:case n.DOWN:s=this.headers[(i+1)%r];break;case n.LEFT:case n.UP:s=this.headers[(i-1+r)%r];break;case n.SPACE:case n.ENTER:this._eventHandler(t);break;case n.HOME:s=this.headers[0];break;case n.END:s=this.headers[r-1]}s&&(e(t.target).attr("tabIndex",-1),e(s).attr("tabIndex",0),s.focus(),t.preventDefault())},_panelKeyDown:function(t){t.keyCode===e.ui.keyCode.UP&&t.ctrlKey&&e(t.currentTarget).prev().focus()},refresh:function(){var t,n,r=this.options.heightStyle,i=this.element.parent();r==="fill"?(e.support.minHeight||(n=i.css("overflow"),i.css("overflow","hidden")),t=i.height(),this.element.siblings(":visible").each(function(){var n=e(this),r=n.css("position");if(r==="absolute"||r==="fixed")return;t-=n.outerHeight(!0)}),n&&i.css("overflow",n),this.headers.each(function(){t-=e(this).outerHeight(!0)}),this.headers.next().each(function(){e(this).height(Math.max(0,t-e(this).innerHeight()+e(this).height()))}).css("overflow","auto")):r==="auto"&&(t=0,this.headers.next().each(function(){t=Math.max(t,e(this).css("height","").height())}).height(t))},_activate:function(t){var n=this._findActive(t)[0];if(n===this.active[0])return;n=n||this.active[0],this._eventHandler({target:n,currentTarget:n,preventDefault:e.noop})},_findActive:function(t){return typeof t=="number"?this.headers.eq(t):e()},_setupEvents:function(t){var n={};if(!t)return;e.each(t.split(" "),function(e,t){n[t]="_eventHandler"}),this._on(this.headers,n)},_eventHandler:function(t){var n=this.options,r=this.active,i=e(t.currentTarget),s=i[0]===r[0],o=s&&n.collapsible,u=o?e():i.next(),a=r.next(),f={oldHeader:r,oldPanel:a,newHeader:o?e():i,newPanel:u};t.preventDefault();if(s&&!n.collapsible||this._trigger("beforeActivate",t,f)===!1)return;n.active=o?!1:this.headers.index(i),this.active=s?e():i,this._toggle(f),r.removeClass("ui-accordion-header-active ui-state-active"),n.icons&&r.children(".ui-accordion-header-icon").removeClass(n.icons.activeHeader).addClass(n.icons.header),s||(i.removeClass("ui-corner-all").addClass("ui-accordion-header-active ui-state-active ui-corner-top"),n.icons&&i.children(".ui-accordion-header-icon").removeClass(n.icons.header).addClass(n.icons.activeHeader),i.next().addClass("ui-accordion-content-active"))},_toggle:function(t){var n=t.newPanel,r=this.prevShow.length?this.prevShow:t.oldPanel;this.prevShow.add(this.prevHide).stop(!0,!0),this.prevShow=n,this.prevHide=r,this.options.animate?this._animate(n,r,t):(r.hide(),n.show(),this._toggleComplete(t)),r.attr({"aria-expanded":"false","aria-hidden":"true"}),r.prev().attr("aria-selected","false"),n.length&&r.length?r.prev().attr("tabIndex",-1):n.length&&this.headers.filter(function(){return e(this).attr("tabIndex")===0}).attr("tabIndex",-1),n.attr({"aria-expanded":"true","aria-hidden":"false"}).prev().attr({"aria-selected":"true",tabIndex:0})},_animate:function(e,t,n){var s,o,u,a=this,f=0,l=e.length&&(!t.length||e.index()",options:{appendTo:"body",autoFocus:!1,delay:300,minLength:1,position:{my:"left top",at:"left bottom",collision:"none"},source:null,change:null,close:null,focus:null,open:null,response:null,search:null,select:null},pending:0,_create:function(){var t,n,r;this.isMultiLine=this._isMultiLine(),this.valueMethod=this.element[this.element.is("input,textarea")?"val":"text"],this.isNewMenu=!0,this.element.addClass("ui-autocomplete-input").attr("autocomplete","off"),this._on(this.element,{keydown:function(i){if(this.element.prop("readOnly")){t=!0,r=!0,n=!0;return}t=!1,r=!1,n=!1;var s=e.ui.keyCode;switch(i.keyCode){case s.PAGE_UP:t=!0,this._move("previousPage",i);break;case s.PAGE_DOWN:t=!0,this._move("nextPage",i);break;case s.UP:t=!0,this._keyEvent("previous",i);break;case s.DOWN:t=!0,this._keyEvent("next",i);break;case s.ENTER:case s.NUMPAD_ENTER:this.menu.active&&(t=!0,i.preventDefault(),this.menu.select(i));break;case s.TAB:this.menu.active&&this.menu.select(i);break;case s.ESCAPE:this.menu.element.is(":visible")&&(this._value(this.term),this.close(i),i.preventDefault());break;default:n=!0,this._searchTimeout(i)}},keypress:function(r){if(t){t=!1,r.preventDefault();return}if(n)return;var i=e.ui.keyCode;switch(r.keyCode){case i.PAGE_UP:this._move("previousPage",r);break;case i.PAGE_DOWN:this._move("nextPage",r);break;case i.UP:this._keyEvent("previous",r);break;case i.DOWN:this._keyEvent("next",r)}},input:function(e){if(r){r=!1,e.preventDefault();return}this._searchTimeout(e)},focus:function(){this.selectedItem=null,this.previous=this._value()},blur:function(e){if(this.cancelBlur){delete this.cancelBlur;return}clearTimeout(this.searching),this.close(e),this._change(e)}}),this._initSource(),this.menu=e("
      '+"";var z=N?'":"";for(var W=0;W<7;W++){var X=(W+T)%7;z+="=5?' class="ui-datepicker-week-end"':"")+">"+''+L[X]+""}U+=z+"";var V=this._getDaysInMonth(d,p);d==e.selectedYear&&p==e.selectedMonth&&(e.selectedDay=Math.min(e.selectedDay,V));var J=(this._getFirstDayOfMonth(d,p)-T+7)%7,K=Math.ceil((J+V)/7),Q=f?this.maxRows>K?this.maxRows:K:K;this.maxRows=Q;var G=this._daylightSavingAdjust(new Date(d,p,1-J));for(var Y=0;Y";var Z=N?'":"";for(var W=0;W<7;W++){var et=M?M.apply(e.input?e.input[0]:null,[G]):[!0,""],tt=G.getMonth()!=p,nt=tt&&!D||!et[0]||c&&Gh;Z+='",G.setDate(G.getDate()+1),G=this._daylightSavingAdjust(G)}U+=Z+""}p++,p>11&&(p=0,d++),U+="
      '+this._get(e,"weekHeader")+"
      '+this._get(e,"calculateWeek")(G)+""+(tt&&!_?" ":nt?''+G.getDate()+"":''+G.getDate()+"")+"
      "+(f?"
      "+(o[0]>0&&I==o[1]-1?'
      ':""):""),F+=U}B+=F}return B+=x+($.ui.ie6&&!e.inline?'':""),e._keyEvent=!1,B},_generateMonthYearHeader:function(e,t,n,r,i,s,o,u){var a=this._get(e,"changeMonth"),f=this._get(e,"changeYear"),l=this._get(e,"showMonthAfterYear"),c='
      ',h="";if(s||!a)h+=''+o[t]+"";else{var p=r&&r.getFullYear()==n,d=i&&i.getFullYear()==n;h+='"}l||(c+=h+(s||!a||!f?" ":""));if(!e.yearshtml){e.yearshtml="";if(s||!f)c+=''+n+"";else{var m=this._get(e,"yearRange").split(":"),g=(new Date).getFullYear(),y=function(e){var t=e.match(/c[+-].*/)?n+parseInt(e.substring(1),10):e.match(/[+-].*/)?g+parseInt(e,10):parseInt(e,10);return isNaN(t)?g:t},b=y(m[0]),w=Math.max(b,y(m[1]||""));b=r?Math.max(b,r.getFullYear()):b,w=i?Math.min(w,i.getFullYear()):w,e.yearshtml+='",c+=e.yearshtml,e.yearshtml=null}}return c+=this._get(e,"yearSuffix"),l&&(c+=(s||!a||!f?" ":"")+h),c+="
      ",c},_adjustInstDate:function(e,t,n){var r=e.drawYear+(n=="Y"?t:0),i=e.drawMonth+(n=="M"?t:0),s=Math.min(e.selectedDay,this._getDaysInMonth(r,i))+(n=="D"?t:0),o=this._restrictMinMax(e,this._daylightSavingAdjust(new Date(r,i,s)));e.selectedDay=o.getDate(),e.drawMonth=e.selectedMonth=o.getMonth(),e.drawYear=e.selectedYear=o.getFullYear(),(n=="M"||n=="Y")&&this._notifyChange(e)},_restrictMinMax:function(e,t){var n=this._getMinMaxDate(e,"min"),r=this._getMinMaxDate(e,"max"),i=n&&tr?r:i,i},_notifyChange:function(e){var t=this._get(e,"onChangeMonthYear");t&&t.apply(e.input?e.input[0]:null,[e.selectedYear,e.selectedMonth+1,e])},_getNumberOfMonths:function(e){var t=this._get(e,"numberOfMonths");return t==null?[1,1]:typeof t=="number"?[1,t]:t},_getMinMaxDate:function(e,t){return this._determineDate(e,this._get(e,t+"Date"),null)},_getDaysInMonth:function(e,t){return 32-this._daylightSavingAdjust(new Date(e,t,32)).getDate()},_getFirstDayOfMonth:function(e,t){return(new Date(e,t,1)).getDay()},_canAdjustMonth:function(e,t,n,r){var i=this._getNumberOfMonths(e),s=this._daylightSavingAdjust(new Date(n,r+(t<0?t:i[0]*i[1]),1));return t<0&&s.setDate(this._getDaysInMonth(s.getFullYear(),s.getMonth())),this._isInRange(e,s)},_isInRange:function(e,t){var n=this._getMinMaxDate(e,"min"),r=this._getMinMaxDate(e,"max");return(!n||t.getTime()>=n.getTime())&&(!r||t.getTime()<=r.getTime())},_getFormatConfig:function(e){var t=this._get(e,"shortYearCutoff");return t=typeof t!="string"?t:(new Date).getFullYear()%100+parseInt(t,10),{shortYearCutoff:t,dayNamesShort:this._get(e,"dayNamesShort"),dayNames:this._get(e,"dayNames"),monthNamesShort:this._get(e,"monthNamesShort"),monthNames:this._get(e,"monthNames")}},_formatDate:function(e,t,n,r){t||(e.currentDay=e.selectedDay,e.currentMonth=e.selectedMonth,e.currentYear=e.selectedYear);var i=t?typeof t=="object"?t:this._daylightSavingAdjust(new Date(r,n,t)):this._daylightSavingAdjust(new Date(e.currentYear,e.currentMonth,e.currentDay));return this.formatDate(this._get(e,"dateFormat"),i,this._getFormatConfig(e))}}),$.fn.datepicker=function(e){if(!this.length)return this;$.datepicker.initialized||($(document).mousedown($.datepicker._checkExternalClick).find(document.body).append($.datepicker.dpDiv),$.datepicker.initialized=!0);var t=Array.prototype.slice.call(arguments,1);return typeof e!="string"||e!="isDisabled"&&e!="getDate"&&e!="widget"?e=="option"&&arguments.length==2&&typeof arguments[1]=="string"?$.datepicker["_"+e+"Datepicker"].apply($.datepicker,[this[0]].concat(t)):this.each(function(){typeof e=="string"?$.datepicker["_"+e+"Datepicker"].apply($.datepicker,[this].concat(t)):$.datepicker._attachDatepicker(this,e)}):$.datepicker["_"+e+"Datepicker"].apply($.datepicker,[this[0]].concat(t))},$.datepicker=new Datepicker,$.datepicker.initialized=!1,$.datepicker.uuid=(new Date).getTime(),$.datepicker.version="1.9.2",window["DP_jQuery_"+dpuuid]=$})(jQuery);(function(e,t){var n="ui-dialog ui-widget ui-widget-content ui-corner-all ",r={buttons:!0,height:!0,maxHeight:!0,maxWidth:!0,minHeight:!0,minWidth:!0,width:!0},i={maxHeight:!0,maxWidth:!0,minHeight:!0,minWidth:!0};e.widget("ui.dialog",{version:"1.9.2",options:{autoOpen:!0,buttons:{},closeOnEscape:!0,closeText:"close",dialogClass:"",draggable:!0,hide:null,height:"auto",maxHeight:!1,maxWidth:!1,minHeight:150,minWidth:150,modal:!1,position:{my:"center",at:"center",of:window,collision:"fit",using:function(t){var n=e(this).css(t).offset().top;n<0&&e(this).css("top",t.top-n)}},resizable:!0,show:null,stack:!0,title:"",width:300,zIndex:1e3},_create:function(){this.originalTitle=this.element.attr("title"),typeof this.originalTitle!="string"&&(this.originalTitle=""),this.oldPosition={parent:this.element.parent(),index:this.element.parent().children().index(this.element)},this.options.title=this.options.title||this.originalTitle;var t=this,r=this.options,i=r.title||" ",s,o,u,a,f;s=(this.uiDialog=e("
      ")).addClass(n+r.dialogClass).css({display:"none",outline:0,zIndex:r.zIndex}).attr("tabIndex",-1).keydown(function(n){r.closeOnEscape&&!n.isDefaultPrevented()&&n.keyCode&&n.keyCode===e.ui.keyCode.ESCAPE&&(t.close(n),n.preventDefault())}).mousedown(function(e){t.moveToTop(!1,e)}).appendTo("body"),this.element.show().removeAttr("title").addClass("ui-dialog-content ui-widget-content").appendTo(s),o=(this.uiDialogTitlebar=e("
      ")).addClass("ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix").bind("mousedown",function(){s.focus()}).prependTo(s),u=e("").addClass("ui-dialog-titlebar-close ui-corner-all").attr("role","button").click(function(e){e.preventDefault(),t.close(e)}).appendTo(o),(this.uiDialogTitlebarCloseText=e("")).addClass("ui-icon ui-icon-closethick").text(r.closeText).appendTo(u),a=e("").uniqueId().addClass("ui-dialog-title").html(i).prependTo(o),f=(this.uiDialogButtonPane=e("
      ")).addClass("ui-dialog-buttonpane ui-widget-content ui-helper-clearfix"),(this.uiButtonSet=e("
      ")).addClass("ui-dialog-buttonset").appendTo(f),s.attr({role:"dialog","aria-labelledby":a.attr("id")}),o.find("*").add(o).disableSelection(),this._hoverable(u),this._focusable(u),r.draggable&&e.fn.draggable&&this._makeDraggable(),r.resizable&&e.fn.resizable&&this._makeResizable(),this._createButtons(r.buttons),this._isOpen=!1,e.fn.bgiframe&&s.bgiframe(),this._on(s,{keydown:function(t){if(!r.modal||t.keyCode!==e.ui.keyCode.TAB)return;var n=e(":tabbable",s),i=n.filter(":first"),o=n.filter(":last");if(t.target===o[0]&&!t.shiftKey)return i.focus(1),!1;if(t.target===i[0]&&t.shiftKey)return o.focus(1),!1}})},_init:function(){this.options.autoOpen&&this.open()},_destroy:function(){var e,t=this.oldPosition;this.overlay&&this.overlay.destroy(),this.uiDialog.hide(),this.element.removeClass("ui-dialog-content ui-widget-content").hide().appendTo("body"),this.uiDialog.remove(),this.originalTitle&&this.element.attr("title",this.originalTitle),e=t.parent.children().eq(t.index),e.length&&e[0]!==this.element[0]?e.before(this.element):t.parent.append(this.element)},widget:function(){return this.uiDialog},close:function(t){var n=this,r,i;if(!this._isOpen)return;if(!1===this._trigger("beforeClose",t))return;return this._isOpen=!1,this.overlay&&this.overlay.destroy(),this.options.hide?this._hide(this.uiDialog,this.options.hide,function(){n._trigger("close",t)}):(this.uiDialog.hide(),this._trigger("close",t)),e.ui.dialog.overlay.resize(),this.options.modal&&(r=0,e(".ui-dialog").each(function(){this!==n.uiDialog[0]&&(i=e(this).css("z-index"),isNaN(i)||(r=Math.max(r,i)))}),e.ui.dialog.maxZ=r),this},isOpen:function(){return this._isOpen},moveToTop:function(t,n){var r=this.options,i;return r.modal&&!t||!r.stack&&!r.modal?this._trigger("focus",n):(r.zIndex>e.ui.dialog.maxZ&&(e.ui.dialog.maxZ=r.zIndex),this.overlay&&(e.ui.dialog.maxZ+=1,e.ui.dialog.overlay.maxZ=e.ui.dialog.maxZ,this.overlay.$el.css("z-index",e.ui.dialog.overlay.maxZ)),i={scrollTop:this.element.scrollTop(),scrollLeft:this.element.scrollLeft()},e.ui.dialog.maxZ+=1,this.uiDialog.css("z-index",e.ui.dialog.maxZ),this.element.attr(i),this._trigger("focus",n),this)},open:function(){if(this._isOpen)return;var t,n=this.options,r=this.uiDialog;return this._size(),this._position(n.position),r.show(n.show),this.overlay=n.modal?new e.ui.dialog.overlay(this):null,this.moveToTop(!0),t=this.element.find(":tabbable"),t.length||(t=this.uiDialogButtonPane.find(":tabbable"),t.length||(t=r)),t.eq(0).focus(),this._isOpen=!0,this._trigger("open"),this},_createButtons:function(t){var n=this,r=!1;this.uiDialogButtonPane.remove(),this.uiButtonSet.empty(),typeof t=="object"&&t!==null&&e.each(t,function(){return!(r=!0)}),r?(e.each(t,function(t,r){var i,s;r=e.isFunction(r)?{click:r,text:t}:r,r=e.extend({type:"button"},r),s=r.click,r.click=function(){s.apply(n.element[0],arguments)},i=e("",r).appendTo(n.uiButtonSet),e.fn.button&&i.button()}),this.uiDialog.addClass("ui-dialog-buttons"),this.uiDialogButtonPane.appendTo(this.uiDialog)):this.uiDialog.removeClass("ui-dialog-buttons")},_makeDraggable:function(){function r(e){return{position:e.position,offset:e.offset}}var t=this,n=this.options;this.uiDialog.draggable({cancel:".ui-dialog-content, .ui-dialog-titlebar-close",handle:".ui-dialog-titlebar",containment:"document",start:function(n,i){e(this).addClass("ui-dialog-dragging"),t._trigger("dragStart",n,r(i))},drag:function(e,n){t._trigger("drag",e,r(n))},stop:function(i,s){n.position=[s.position.left-t.document.scrollLeft(),s.position.top-t.document.scrollTop()],e(this).removeClass("ui-dialog-dragging"),t._trigger("dragStop",i,r(s)),e.ui.dialog.overlay.resize()}})},_makeResizable:function(n){function u(e){return{originalPosition:e.originalPosition,originalSize:e.originalSize,position:e.position,size:e.size}}n=n===t?this.options.resizable:n;var r=this,i=this.options,s=this.uiDialog.css("position"),o=typeof n=="string"?n:"n,e,s,w,se,sw,ne,nw";this.uiDialog.resizable({cancel:".ui-dialog-content",containment:"document",alsoResize:this.element,maxWidth:i.maxWidth,maxHeight:i.maxHeight,minWidth:i.minWidth,minHeight:this._minHeight(),handles:o,start:function(t,n){e(this).addClass("ui-dialog-resizing"),r._trigger("resizeStart",t,u(n))},resize:function(e,t){r._trigger("resize",e,u(t))},stop:function(t,n){e(this).removeClass("ui-dialog-resizing"),i.height=e(this).height(),i.width=e(this).width(),r._trigger("resizeStop",t,u(n)),e.ui.dialog.overlay.resize()}}).css("position",s).find(".ui-resizable-se").addClass("ui-icon ui-icon-grip-diagonal-se")},_minHeight:function(){var e=this.options;return e.height==="auto"?e.minHeight:Math.min(e.minHeight,e.height)},_position:function(t){var n=[],r=[0,0],i;if(t){if(typeof t=="string"||typeof t=="object"&&"0"in t)n=t.split?t.split(" "):[t[0],t[1]],n.length===1&&(n[1]=n[0]),e.each(["left","top"],function(e,t){+n[e]===n[e]&&(r[e]=n[e],n[e]=t)}),t={my:n[0]+(r[0]<0?r[0]:"+"+r[0])+" "+n[1]+(r[1]<0?r[1]:"+"+r[1]),at:n.join(" ")};t=e.extend({},e.ui.dialog.prototype.options.position,t)}else t=e.ui.dialog.prototype.options.position;i=this.uiDialog.is(":visible"),i||this.uiDialog.show(),this.uiDialog.position(t),i||this.uiDialog.hide()},_setOptions:function(t){var n=this,s={},o=!1;e.each(t,function(e,t){n._setOption(e,t),e in r&&(o=!0),e in i&&(s[e]=t)}),o&&this._size(),this.uiDialog.is(":data(resizable)")&&this.uiDialog.resizable("option",s)},_setOption:function(t,r){var i,s,o=this.uiDialog;switch(t){case"buttons":this._createButtons(r);break;case"closeText":this.uiDialogTitlebarCloseText.text(""+r);break;case"dialogClass":o.removeClass(this.options.dialogClass).addClass(n+r);break;case"disabled":r?o.addClass("ui-dialog-disabled"):o.removeClass("ui-dialog-disabled");break;case"draggable":i=o.is(":data(draggable)"),i&&!r&&o.draggable("destroy"),!i&&r&&this._makeDraggable();break;case"position":this._position(r);break;case"resizable":s=o.is(":data(resizable)"),s&&!r&&o.resizable("destroy"),s&&typeof r=="string"&&o.resizable("option","handles",r),!s&&r!==!1&&this._makeResizable(r);break;case"title":e(".ui-dialog-title",this.uiDialogTitlebar).html(""+(r||" "))}this._super(t,r)},_size:function(){var t,n,r,i=this.options,s=this.uiDialog.is(":visible");this.element.show().css({width:"auto",minHeight:0,height:0}),i.minWidth>i.width&&(i.width=i.minWidth),t=this.uiDialog.css({height:"auto",width:i.width}).outerHeight(),n=Math.max(0,i.minHeight-t),i.height==="auto"?e.support.minHeight?this.element.css({minHeight:n,height:"auto"}):(this.uiDialog.show(),r=this.element.css("height","auto").height(),s||this.uiDialog.hide(),this.element.height(Math.max(r,n))):this.element.height(Math.max(i.height-t,0)),this.uiDialog.is(":data(resizable)")&&this.uiDialog.resizable("option","minHeight",this._minHeight())}}),e.extend(e.ui.dialog,{uuid:0,maxZ:0,getTitleId:function(e){var t=e.attr("id");return t||(this.uuid+=1,t=this.uuid),"ui-dialog-title-"+t},overlay:function(t){this.$el=e.ui.dialog.overlay.create(t)}}),e.extend(e.ui.dialog.overlay,{instances:[],oldInstances:[],maxZ:0,events:e.map("focus,mousedown,mouseup,keydown,keypress,click".split(","),function(e){return e+".dialog-overlay"}).join(" "),create:function(t){this.instances.length===0&&(setTimeout(function(){e.ui.dialog.overlay.instances.length&&e(document).bind(e.ui.dialog.overlay.events,function(t){if(e(t.target).zIndex()").addClass("ui-widget-overlay");return e(document).bind("keydown.dialog-overlay",function(r){var i=e.ui.dialog.overlay.instances;i.length!==0&&i[i.length-1]===n&&t.options.closeOnEscape&&!r.isDefaultPrevented()&&r.keyCode&&r.keyCode===e.ui.keyCode.ESCAPE&&(t.close(r),r.preventDefault())}),n.appendTo(document.body).css({width:this.width(),height:this.height()}),e.fn.bgiframe&&n.bgiframe(),this.instances.push(n),n},destroy:function(t){var n=e.inArray(t,this.instances),r=0;n!==-1&&this.oldInstances.push(this.instances.splice(n,1)[0]),this.instances.length===0&&e([document,window]).unbind(".dialog-overlay"),t.height(0).width(0).remove(),e.each(this.instances,function(){r=Math.max(r,this.css("z-index"))}),this.maxZ=r},height:function(){var t,n;return e.ui.ie?(t=Math.max(document.documentElement.scrollHeight,document.body.scrollHeight),n=Math.max(document.documentElement.offsetHeight,document.body.offsetHeight),t",delay:300,options:{icons:{submenu:"ui-icon-carat-1-e"},menus:"ul",position:{my:"left top",at:"right top"},role:"menu",blur:null,focus:null,select:null},_create:function(){this.activeMenu=this.element,this.element.uniqueId().addClass("ui-menu ui-widget ui-widget-content ui-corner-all").toggleClass("ui-menu-icons",!!this.element.find(".ui-icon").length).attr({role:this.options.role,tabIndex:0}).bind("click"+this.eventNamespace,e.proxy(function(e){this.options.disabled&&e.preventDefault()},this)),this.options.disabled&&this.element.addClass("ui-state-disabled").attr("aria-disabled","true"),this._on({"mousedown .ui-menu-item > a":function(e){e.preventDefault()},"click .ui-state-disabled > a":function(e){e.preventDefault()},"click .ui-menu-item:has(a)":function(t){var r=e(t.target).closest(".ui-menu-item");!n&&r.not(".ui-state-disabled").length&&(n=!0,this.select(t),r.has(".ui-menu").length?this.expand(t):this.element.is(":focus")||(this.element.trigger("focus",[!0]),this.active&&this.active.parents(".ui-menu").length===1&&clearTimeout(this.timer)))},"mouseenter .ui-menu-item":function(t){var n=e(t.currentTarget);n.siblings().children(".ui-state-active").removeClass("ui-state-active"),this.focus(t,n)},mouseleave:"collapseAll","mouseleave .ui-menu":"collapseAll",focus:function(e,t){var n=this.active||this.element.children(".ui-menu-item").eq(0);t||this.focus(e,n)},blur:function(t){this._delay(function(){e.contains(this.element[0],this.document[0].activeElement)||this.collapseAll(t)})},keydown:"_keydown"}),this.refresh(),this._on(this.document,{click:function(t){e(t.target).closest(".ui-menu").length||this.collapseAll(t),n=!1}})},_destroy:function(){this.element.removeAttr("aria-activedescendant").find(".ui-menu").andSelf().removeClass("ui-menu ui-widget ui-widget-content ui-corner-all ui-menu-icons").removeAttr("role").removeAttr("tabIndex").removeAttr("aria-labelledby").removeAttr("aria-expanded").removeAttr("aria-hidden").removeAttr("aria-disabled").removeUniqueId().show(),this.element.find(".ui-menu-item").removeClass("ui-menu-item").removeAttr("role").removeAttr("aria-disabled").children("a").removeUniqueId().removeClass("ui-corner-all ui-state-hover").removeAttr("tabIndex").removeAttr("role").removeAttr("aria-haspopup").children().each(function(){var t=e(this);t.data("ui-menu-submenu-carat")&&t.remove()}),this.element.find(".ui-menu-divider").removeClass("ui-menu-divider ui-widget-content")},_keydown:function(t){function a(e){return e.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g,"\\$&")}var n,r,i,s,o,u=!0;switch(t.keyCode){case e.ui.keyCode.PAGE_UP:this.previousPage(t);break;case e.ui.keyCode.PAGE_DOWN:this.nextPage(t);break;case e.ui.keyCode.HOME:this._move("first","first",t);break;case e.ui.keyCode.END:this._move("last","last",t);break;case e.ui.keyCode.UP:this.previous(t);break;case e.ui.keyCode.DOWN:this.next(t);break;case e.ui.keyCode.LEFT:this.collapse(t);break;case e.ui.keyCode.RIGHT:this.active&&!this.active.is(".ui-state-disabled")&&this.expand(t);break;case e.ui.keyCode.ENTER:case e.ui.keyCode.SPACE:this._activate(t);break;case e.ui.keyCode.ESCAPE:this.collapse(t);break;default:u=!1,r=this.previousFilter||"",i=String.fromCharCode(t.keyCode),s=!1,clearTimeout(this.filterTimer),i===r?s=!0:i=r+i,o=new RegExp("^"+a(i),"i"),n=this.activeMenu.children(".ui-menu-item").filter(function(){return o.test(e(this).children("a").text())}),n=s&&n.index(this.active.next())!==-1?this.active.nextAll(".ui-menu-item"):n,n.length||(i=String.fromCharCode(t.keyCode),o=new RegExp("^"+a(i),"i"),n=this.activeMenu.children(".ui-menu-item").filter(function(){return o.test(e(this).children("a").text())})),n.length?(this.focus(t,n),n.length>1?(this.previousFilter=i,this.filterTimer=this._delay(function(){delete this.previousFilter},1e3)):delete this.previousFilter):delete this.previousFilter}u&&t.preventDefault()},_activate:function(e){this.active.is(".ui-state-disabled")||(this.active.children("a[aria-haspopup='true']").length?this.expand(e):this.select(e))},refresh:function(){var t,n=this.options.icons.submenu,r=this.element.find(this.options.menus);r.filter(":not(.ui-menu)").addClass("ui-menu ui-widget ui-widget-content ui-corner-all").hide().attr({role:this.options.role,"aria-hidden":"true","aria-expanded":"false"}).each(function(){var t=e(this),r=t.prev("a"),i=e("").addClass("ui-menu-icon ui-icon "+n).data("ui-menu-submenu-carat",!0);r.attr("aria-haspopup","true").prepend(i),t.attr("aria-labelledby",r.attr("id"))}),t=r.add(this.element),t.children(":not(.ui-menu-item):has(a)").addClass("ui-menu-item").attr("role","presentation").children("a").uniqueId().addClass("ui-corner-all").attr({tabIndex:-1,role:this._itemRole()}),t.children(":not(.ui-menu-item)").each(function(){var t=e(this);/[^\-—–\s]/.test(t.text())||t.addClass("ui-widget-content ui-menu-divider")}),t.children(".ui-state-disabled").attr("aria-disabled","true"),this.active&&!e.contains(this.element[0],this.active[0])&&this.blur()},_itemRole:function(){return{menu:"menuitem",listbox:"option"}[this.options.role]},focus:function(e,t){var n,r;this.blur(e,e&&e.type==="focus"),this._scrollIntoView(t),this.active=t.first(),r=this.active.children("a").addClass("ui-state-focus"),this.options.role&&this.element.attr("aria-activedescendant",r.attr("id")),this.active.parent().closest(".ui-menu-item").children("a:first").addClass("ui-state-active"),e&&e.type==="keydown"?this._close():this.timer=this._delay(function(){this._close()},this.delay),n=t.children(".ui-menu"),n.length&&/^mouse/.test(e.type)&&this._startOpening(n),this.activeMenu=t.parent(),this._trigger("focus",e,{item:t})},_scrollIntoView:function(t){var n,r,i,s,o,u;this._hasScroll()&&(n=parseFloat(e.css(this.activeMenu[0],"borderTopWidth"))||0,r=parseFloat(e.css(this.activeMenu[0],"paddingTop"))||0,i=t.offset().top-this.activeMenu.offset().top-n-r,s=this.activeMenu.scrollTop(),o=this.activeMenu.height(),u=t.height(),i<0?this.activeMenu.scrollTop(s+i):i+u>o&&this.activeMenu.scrollTop(s+i-o+u))},blur:function(e,t){t||clearTimeout(this.timer);if(!this.active)return;this.active.children("a").removeClass("ui-state-focus"),this.active=null,this._trigger("blur",e,{item:this.active})},_startOpening:function(e){clearTimeout(this.timer);if(e.attr("aria-hidden")!=="true")return;this.timer=this._delay(function(){this._close(),this._open(e)},this.delay)},_open:function(t){var n=e.extend({of:this.active},this.options.position);clearTimeout(this.timer),this.element.find(".ui-menu").not(t.parents(".ui-menu")).hide().attr("aria-hidden","true"),t.show().removeAttr("aria-hidden").attr("aria-expanded","true").position(n)},collapseAll:function(t,n){clearTimeout(this.timer),this.timer=this._delay(function(){var r=n?this.element:e(t&&t.target).closest(this.element.find(".ui-menu"));r.length||(r=this.element),this._close(r),this.blur(t),this.activeMenu=r},this.delay)},_close:function(e){e||(e=this.active?this.active.parent():this.element),e.find(".ui-menu").hide().attr("aria-hidden","true").attr("aria-expanded","false").end().find("a.ui-state-active").removeClass("ui-state-active")},collapse:function(e){var t=this.active&&this.active.parent().closest(".ui-menu-item",this.element);t&&t.length&&(this._close(),this.focus(e,t))},expand:function(e){var t=this.active&&this.active.children(".ui-menu ").children(".ui-menu-item").first();t&&t.length&&(this._open(t.parent()),this._delay(function(){this.focus(e,t)}))},next:function(e){this._move("next","first",e)},previous:function(e){this._move("prev","last",e)},isFirstItem:function(){return this.active&&!this.active.prevAll(".ui-menu-item").length},isLastItem:function(){return this.active&&!this.active.nextAll(".ui-menu-item").length},_move:function(e,t,n){var r;this.active&&(e==="first"||e==="last"?r=this.active[e==="first"?"prevAll":"nextAll"](".ui-menu-item").eq(-1):r=this.active[e+"All"](".ui-menu-item").eq(0));if(!r||!r.length||!this.active)r=this.activeMenu.children(".ui-menu-item")[t]();this.focus(n,r)},nextPage:function(t){var n,r,i;if(!this.active){this.next(t);return}if(this.isLastItem())return;this._hasScroll()?(r=this.active.offset().top,i=this.element.height(),this.active.nextAll(".ui-menu-item").each(function(){return n=e(this),n.offset().top-r-i<0}),this.focus(t,n)):this.focus(t,this.activeMenu.children(".ui-menu-item")[this.active?"last":"first"]())},previousPage:function(t){var n,r,i;if(!this.active){this.next(t);return}if(this.isFirstItem())return;this._hasScroll()?(r=this.active.offset().top,i=this.element.height(),this.active.prevAll(".ui-menu-item").each(function(){return n=e(this),n.offset().top-r+i>0}),this.focus(t,n)):this.focus(t,this.activeMenu.children(".ui-menu-item").first())},_hasScroll:function(){return this.element.outerHeight()
      ").appendTo(this.element),this.oldValue=this._value(),this._refreshValue()},_destroy:function(){this.element.removeClass("ui-progressbar ui-widget ui-widget-content ui-corner-all").removeAttr("role").removeAttr("aria-valuemin").removeAttr("aria-valuemax").removeAttr("aria-valuenow"),this.valueDiv.remove()},value:function(e){return e===t?this._value():(this._setOption("value",e),this)},_setOption:function(e,t){e==="value"&&(this.options.value=t,this._refreshValue(),this._value()===this.options.max&&this._trigger("complete")),this._super(e,t)},_value:function(){var e=this.options.value;return typeof e!="number"&&(e=0),Math.min(this.options.max,Math.max(this.min,e))},_percentage:function(){return 100*this._value()/this.options.max},_refreshValue:function(){var e=this.value(),t=this._percentage();this.oldValue!==e&&(this.oldValue=e,this._trigger("change")),this.valueDiv.toggle(e>this.min).toggleClass("ui-corner-right",e===this.options.max).width(t.toFixed(0)+"%"),this.element.attr("aria-valuenow",e)}})})(jQuery);(function(e,t){var n=5;e.widget("ui.slider",e.ui.mouse,{version:"1.9.2",widgetEventPrefix:"slide",options:{animate:!1,distance:0,max:100,min:0,orientation:"horizontal",range:!1,step:1,value:0,values:null},_create:function(){var t,r,i=this.options,s=this.element.find(".ui-slider-handle").addClass("ui-state-default ui-corner-all"),o="",u=[];this._keySliding=!1,this._mouseSliding=!1,this._animateOff=!0,this._handleIndex=null,this._detectOrientation(),this._mouseInit(),this.element.addClass("ui-slider ui-slider-"+this.orientation+" ui-widget"+" ui-widget-content"+" ui-corner-all"+(i.disabled?" ui-slider-disabled ui-disabled":"")),this.range=e([]),i.range&&(i.range===!0&&(i.values||(i.values=[this._valueMin(),this._valueMin()]),i.values.length&&i.values.length!==2&&(i.values=[i.values[0],i.values[0]])),this.range=e("
      ").appendTo(this.element).addClass("ui-slider-range ui-widget-header"+(i.range==="min"||i.range==="max"?" ui-slider-range-"+i.range:""))),r=i.values&&i.values.length||1;for(t=s.length;tn&&(i=n,s=e(this),o=t)}),c.range===!0&&this.values(1)===c.min&&(o+=1,s=e(this.handles[o])),u=this._start(t,o),u===!1?!1:(this._mouseSliding=!0,this._handleIndex=o,s.addClass("ui-state-active").focus(),a=s.offset(),f=!e(t.target).parents().andSelf().is(".ui-slider-handle"),this._clickOffset=f?{left:0,top:0}:{left:t.pageX-a.left-s.width()/2,top:t.pageY-a.top-s.height()/2-(parseInt(s.css("borderTopWidth"),10)||0)-(parseInt(s.css("borderBottomWidth"),10)||0)+(parseInt(s.css("marginTop"),10)||0)},this.handles.hasClass("ui-state-hover")||this._slide(t,o,r),this._animateOff=!0,!0))},_mouseStart:function(){return!0},_mouseDrag:function(e){var t={x:e.pageX,y:e.pageY},n=this._normValueFromMouse(t);return this._slide(e,this._handleIndex,n),!1},_mouseStop:function(e){return this.handles.removeClass("ui-state-active"),this._mouseSliding=!1,this._stop(e,this._handleIndex),this._change(e,this._handleIndex),this._handleIndex=null,this._clickOffset=null,this._animateOff=!1,!1},_detectOrientation:function(){this.orientation=this.options.orientation==="vertical"?"vertical":"horizontal"},_normValueFromMouse:function(e){var t,n,r,i,s;return this.orientation==="horizontal"?(t=this.elementSize.width,n=e.x-this.elementOffset.left-(this._clickOffset?this._clickOffset.left:0)):(t=this.elementSize.height,n=e.y-this.elementOffset.top-(this._clickOffset?this._clickOffset.top:0)),r=n/t,r>1&&(r=1),r<0&&(r=0),this.orientation==="vertical"&&(r=1-r),i=this._valueMax()-this._valueMin(),s=this._valueMin()+r*i,this._trimAlignValue(s)},_start:function(e,t){var n={handle:this.handles[t],value:this.value()};return this.options.values&&this.options.values.length&&(n.value=this.values(t),n.values=this.values()),this._trigger("start",e,n)},_slide:function(e,t,n){var r,i,s;this.options.values&&this.options.values.length?(r=this.values(t?0:1),this.options.values.length===2&&this.options.range===!0&&(t===0&&n>r||t===1&&n1){this.options.values[t]=this._trimAlignValue(n),this._refreshValue(),this._change(null,t);return}if(!arguments.length)return this._values();if(!e.isArray(arguments[0]))return this.options.values&&this.options.values.length?this._values(t):this.value();r=this.options.values,i=arguments[0];for(s=0;s=this._valueMax())return this._valueMax();var t=this.options.step>0?this.options.step:1,n=(e-this._valueMin())%t,r=e-n;return Math.abs(n)*2>=t&&(r+=n>0?t:-t),parseFloat(r.toFixed(5))},_valueMin:function(){return this.options.min},_valueMax:function(){return this.options.max},_refreshValue:function(){var t,n,r,i,s,o=this.options.range,u=this.options,a=this,f=this._animateOff?!1:u.animate,l={};this.options.values&&this.options.values.length?this.handles.each(function(r){n=(a.values(r)-a._valueMin())/(a._valueMax()-a._valueMin())*100,l[a.orientation==="horizontal"?"left":"bottom"]=n+"%",e(this).stop(1,1)[f?"animate":"css"](l,u.animate),a.options.range===!0&&(a.orientation==="horizontal"?(r===0&&a.range.stop(1,1)[f?"animate":"css"]({left:n+"%"},u.animate),r===1&&a.range[f?"animate":"css"]({width:n-t+"%"},{queue:!1,duration:u.animate})):(r===0&&a.range.stop(1,1)[f?"animate":"css"]({bottom:n+"%"},u.animate),r===1&&a.range[f?"animate":"css"]({height:n-t+"%"},{queue:!1,duration:u.animate}))),t=n}):(r=this.value(),i=this._valueMin(),s=this._valueMax(),n=s!==i?(r-i)/(s-i)*100:0,l[this.orientation==="horizontal"?"left":"bottom"]=n+"%",this.handle.stop(1,1)[f?"animate":"css"](l,u.animate),o==="min"&&this.orientation==="horizontal"&&this.range.stop(1,1)[f?"animate":"css"]({width:n+"%"},u.animate),o==="max"&&this.orientation==="horizontal"&&this.range[f?"animate":"css"]({width:100-n+"%"},{queue:!1,duration:u.animate}),o==="min"&&this.orientation==="vertical"&&this.range.stop(1,1)[f?"animate":"css"]({height:n+"%"},u.animate),o==="max"&&this.orientation==="vertical"&&this.range[f?"animate":"css"]({height:100-n+"%"},{queue:!1,duration:u.animate}))}})})(jQuery);(function(e){function t(e){return function(){var t=this.element.val();e.apply(this,arguments),this._refresh(),t!==this.element.val()&&this._trigger("change")}}e.widget("ui.spinner",{version:"1.9.2",defaultElement:"",widgetEventPrefix:"spin",options:{culture:null,icons:{down:"ui-icon-triangle-1-s",up:"ui-icon-triangle-1-n"},incremental:!0,max:null,min:null,numberFormat:null,page:10,step:1,change:null,spin:null,start:null,stop:null},_create:function(){this._setOption("max",this.options.max),this._setOption("min",this.options.min),this._setOption("step",this.options.step),this._value(this.element.val(),!0),this._draw(),this._on(this._events),this._refresh(),this._on(this.window,{beforeunload:function(){this.element.removeAttr("autocomplete")}})},_getCreateOptions:function(){var t={},n=this.element;return e.each(["min","max","step"],function(e,r){var i=n.attr(r);i!==undefined&&i.length&&(t[r]=i)}),t},_events:{keydown:function(e){this._start(e)&&this._keydown(e)&&e.preventDefault()},keyup:"_stop",focus:function(){this.previous=this.element.val()},blur:function(e){if(this.cancelBlur){delete this.cancelBlur;return}this._refresh(),this.previous!==this.element.val()&&this._trigger("change",e)},mousewheel:function(e,t){if(!t)return;if(!this.spinning&&!this._start(e))return!1;this._spin((t>0?1:-1)*this.options.step,e),clearTimeout(this.mousewheelTimer),this.mousewheelTimer=this._delay(function(){this.spinning&&this._stop(e)},100),e.preventDefault()},"mousedown .ui-spinner-button":function(t){function r(){var e=this.element[0]===this.document[0].activeElement;e||(this.element.focus(),this.previous=n,this._delay(function(){this.previous=n}))}var n;n=this.element[0]===this.document[0].activeElement?this.previous:this.element.val(),t.preventDefault(),r.call(this),this.cancelBlur=!0,this._delay(function(){delete this.cancelBlur,r.call(this)});if(this._start(t)===!1)return;this._repeat(null,e(t.currentTarget).hasClass("ui-spinner-up")?1:-1,t)},"mouseup .ui-spinner-button":"_stop","mouseenter .ui-spinner-button":function(t){if(!e(t.currentTarget).hasClass("ui-state-active"))return;if(this._start(t)===!1)return!1;this._repeat(null,e(t.currentTarget).hasClass("ui-spinner-up")?1:-1,t)},"mouseleave .ui-spinner-button":"_stop"},_draw:function(){var e=this.uiSpinner=this.element.addClass("ui-spinner-input").attr("autocomplete","off").wrap(this._uiSpinnerHtml()).parent().append(this._buttonHtml());this.element.attr("role","spinbutton"),this.buttons=e.find(".ui-spinner-button").attr("tabIndex",-1).button().removeClass("ui-corner-all"),this.buttons.height()>Math.ceil(e.height()*.5)&&e.height()>0&&e.height(e.height()),this.options.disabled&&this.disable()},_keydown:function(t){var n=this.options,r=e.ui.keyCode;switch(t.keyCode){case r.UP:return this._repeat(null,1,t),!0;case r.DOWN:return this._repeat(null,-1,t),!0;case r.PAGE_UP:return this._repeat(null,n.page,t),!0;case r.PAGE_DOWN:return this._repeat(null,-n.page,t),!0}return!1},_uiSpinnerHtml:function(){return""},_buttonHtml:function(){return""+""+""+""+""},_start:function(e){return!this.spinning&&this._trigger("start",e)===!1?!1:(this.counter||(this.counter=1),this.spinning=!0,!0)},_repeat:function(e,t,n){e=e||500,clearTimeout(this.timer),this.timer=this._delay(function(){this._repeat(40,t,n)},e),this._spin(t*this.options.step,n)},_spin:function(e,t){var n=this.value()||0;this.counter||(this.counter=1),n=this._adjustValue(n+e*this._increment(this.counter));if(!this.spinning||this._trigger("spin",t,{value:n})!==!1)this._value(n),this.counter++},_increment:function(t){var n=this.options.incremental;return n?e.isFunction(n)?n(t):Math.floor(t*t*t/5e4-t*t/500+17*t/200+1):1},_precision:function(){var e=this._precisionOf(this.options.step);return this.options.min!==null&&(e=Math.max(e,this._precisionOf(this.options.min))),e},_precisionOf:function(e){var t=e.toString(),n=t.indexOf(".");return n===-1?0:t.length-n-1},_adjustValue:function(e){var t,n,r=this.options;return t=r.min!==null?r.min:0,n=e-t,n=Math.round(n/r.step)*r.step,e=t+n,e=parseFloat(e.toFixed(this._precision())),r.max!==null&&e>r.max?r.max:r.min!==null&&e1&&e.href.replace(r,"")===location.href.replace(r,"").replace(/\s/g,"%20")}var n=0,r=/#.*$/;e.widget("ui.tabs",{version:"1.9.2",delay:300,options:{active:null,collapsible:!1,event:"click",heightStyle:"content",hide:null,show:null,activate:null,beforeActivate:null,beforeLoad:null,load:null},_create:function(){var t=this,n=this.options,r=n.active,i=location.hash.substring(1);this.running=!1,this.element.addClass("ui-tabs ui-widget ui-widget-content ui-corner-all").toggleClass("ui-tabs-collapsible",n.collapsible).delegate(".ui-tabs-nav > li","mousedown"+this.eventNamespace,function(t){e(this).is(".ui-state-disabled")&&t.preventDefault()}).delegate(".ui-tabs-anchor","focus"+this.eventNamespace,function(){e(this).closest("li").is(".ui-state-disabled")&&this.blur()}),this._processTabs();if(r===null){i&&this.tabs.each(function(t,n){if(e(n).attr("aria-controls")===i)return r=t,!1}),r===null&&(r=this.tabs.index(this.tabs.filter(".ui-tabs-active")));if(r===null||r===-1)r=this.tabs.length?0:!1}r!==!1&&(r=this.tabs.index(this.tabs.eq(r)),r===-1&&(r=n.collapsible?!1:0)),n.active=r,!n.collapsible&&n.active===!1&&this.anchors.length&&(n.active=0),e.isArray(n.disabled)&&(n.disabled=e.unique(n.disabled.concat(e.map(this.tabs.filter(".ui-state-disabled"),function(e){return t.tabs.index(e)}))).sort()),this.options.active!==!1&&this.anchors.length?this.active=this._findActive(this.options.active):this.active=e(),this._refresh(),this.active.length&&this.load(n.active)},_getCreateEventData:function(){return{tab:this.active,panel:this.active.length?this._getPanelForTab(this.active):e()}},_tabKeydown:function(t){var n=e(this.document[0].activeElement).closest("li"),r=this.tabs.index(n),i=!0;if(this._handlePageNav(t))return;switch(t.keyCode){case e.ui.keyCode.RIGHT:case e.ui.keyCode.DOWN:r++;break;case e.ui.keyCode.UP:case e.ui.keyCode.LEFT:i=!1,r--;break;case e.ui.keyCode.END:r=this.anchors.length-1;break;case e.ui.keyCode.HOME:r=0;break;case e.ui.keyCode.SPACE:t.preventDefault(),clearTimeout(this.activating),this._activate(r);return;case e.ui.keyCode.ENTER:t.preventDefault(),clearTimeout(this.activating),this._activate(r===this.options.active?!1:r);return;default:return}t.preventDefault(),clearTimeout(this.activating),r=this._focusNextTab(r,i),t.ctrlKey||(n.attr("aria-selected","false"),this.tabs.eq(r).attr("aria-selected","true"),this.activating=this._delay(function(){this.option("active",r)},this.delay))},_panelKeydown:function(t){if(this._handlePageNav(t))return;t.ctrlKey&&t.keyCode===e.ui.keyCode.UP&&(t.preventDefault(),this.active.focus())},_handlePageNav:function(t){if(t.altKey&&t.keyCode===e.ui.keyCode.PAGE_UP)return this._activate(this._focusNextTab(this.options.active-1,!1)),!0;if(t.altKey&&t.keyCode===e.ui.keyCode.PAGE_DOWN)return this._activate(this._focusNextTab(this.options.active+1,!0)),!0},_findNextTab:function(t,n){function i(){return t>r&&(t=0),t<0&&(t=r),t}var r=this.tabs.length-1;while(e.inArray(i(),this.options.disabled)!==-1)t=n?t+1:t-1;return t},_focusNextTab:function(e,t){return e=this._findNextTab(e,t),this.tabs.eq(e).focus(),e},_setOption:function(e,t){if(e==="active"){this._activate(t);return}if(e==="disabled"){this._setupDisabled(t);return}this._super(e,t),e==="collapsible"&&(this.element.toggleClass("ui-tabs-collapsible",t),!t&&this.options.active===!1&&this._activate(0)),e==="event"&&this._setupEvents(t),e==="heightStyle"&&this._setupHeightStyle(t)},_tabId:function(e){return e.attr("aria-controls")||"ui-tabs-"+i()},_sanitizeSelector:function(e){return e?e.replace(/[!"$%&'()*+,.\/:;<=>?@\[\]\^`{|}~]/g,"\\$&"):""},refresh:function(){var t=this.options,n=this.tablist.children(":has(a[href])");t.disabled=e.map(n.filter(".ui-state-disabled"),function(e){return n.index(e)}),this._processTabs(),t.active===!1||!this.anchors.length?(t.active=!1,this.active=e()):this.active.length&&!e.contains(this.tablist[0],this.active[0])?this.tabs.length===t.disabled.length?(t.active=!1,this.active=e()):this._activate(this._findNextTab(Math.max(0,t.active-1),!1)):t.active=this.tabs.index(this.active),this._refresh()},_refresh:function(){this._setupDisabled(this.options.disabled),this._setupEvents(this.options.event),this._setupHeightStyle(this.options.heightStyle),this.tabs.not(this.active).attr({"aria-selected":"false",tabIndex:-1}),this.panels.not(this._getPanelForTab(this.active)).hide().attr({"aria-expanded":"false","aria-hidden":"true"}),this.active.length?(this.active.addClass("ui-tabs-active ui-state-active").attr({"aria-selected":"true",tabIndex:0}),this._getPanelForTab(this.active).show().attr({"aria-expanded":"true","aria-hidden":"false"})):this.tabs.eq(0).attr("tabIndex",0)},_processTabs:function(){var t=this;this.tablist=this._getList().addClass("ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all").attr("role","tablist"),this.tabs=this.tablist.find("> li:has(a[href])").addClass("ui-state-default ui-corner-top").attr({role:"tab",tabIndex:-1}),this.anchors=this.tabs.map(function(){return e("a",this)[0]}).addClass("ui-tabs-anchor").attr({role:"presentation",tabIndex:-1}),this.panels=e(),this.anchors.each(function(n,r){var i,o,u,a=e(r).uniqueId().attr("id"),f=e(r).closest("li"),l=f.attr("aria-controls");s(r)?(i=r.hash,o=t.element.find(t._sanitizeSelector(i))):(u=t._tabId(f),i="#"+u,o=t.element.find(i),o.length||(o=t._createPanel(u),o.insertAfter(t.panels[n-1]||t.tablist)),o.attr("aria-live","polite")),o.length&&(t.panels=t.panels.add(o)),l&&f.data("ui-tabs-aria-controls",l),f.attr({"aria-controls":i.substring(1),"aria-labelledby":a}),o.attr("aria-labelledby",a)}),this.panels.addClass("ui-tabs-panel ui-widget-content ui-corner-bottom").attr("role","tabpanel")},_getList:function(){return this.element.find("ol,ul").eq(0)},_createPanel:function(t){return e("
      ").attr("id",t).addClass("ui-tabs-panel ui-widget-content ui-corner-bottom").data("ui-tabs-destroy",!0)},_setupDisabled:function(t){e.isArray(t)&&(t.length?t.length===this.anchors.length&&(t=!0):t=!1);for(var n=0,r;r=this.tabs[n];n++)t===!0||e.inArray(n,t)!==-1?e(r).addClass("ui-state-disabled").attr("aria-disabled","true"):e(r).removeClass("ui-state-disabled").removeAttr("aria-disabled");this.options.disabled=t},_setupEvents:function(t){var n={click:function(e){e.preventDefault()}};t&&e.each(t.split(" "),function(e,t){n[t]="_eventHandler"}),this._off(this.anchors.add(this.tabs).add(this.panels)),this._on(this.anchors,n),this._on(this.tabs,{keydown:"_tabKeydown"}),this._on(this.panels,{keydown:"_panelKeydown"}),this._focusable(this.tabs),this._hoverable(this.tabs)},_setupHeightStyle:function(t){var n,r,i=this.element.parent();t==="fill"?(e.support.minHeight||(r=i.css("overflow"),i.css("overflow","hidden")),n=i.height(),this.element.siblings(":visible").each(function(){var t=e(this),r=t.css("position");if(r==="absolute"||r==="fixed")return;n-=t.outerHeight(!0)}),r&&i.css("overflow",r),this.element.children().not(this.panels).each(function(){n-=e(this).outerHeight(!0)}),this.panels.each(function(){e(this).height(Math.max(0,n-e(this).innerHeight()+e(this).height()))}).css("overflow","auto")):t==="auto"&&(n=0,this.panels.each(function(){n=Math.max(n,e(this).height("").height())}).height(n))},_eventHandler:function(t){var n=this.options,r=this.active,i=e(t.currentTarget),s=i.closest("li"),o=s[0]===r[0],u=o&&n.collapsible,a=u?e():this._getPanelForTab(s),f=r.length?this._getPanelForTab(r):e(),l={oldTab:r,oldPanel:f,newTab:u?e():s,newPanel:a};t.preventDefault();if(s.hasClass("ui-state-disabled")||s.hasClass("ui-tabs-loading")||this.running||o&&!n.collapsible||this._trigger("beforeActivate",t,l)===!1)return;n.active=u?!1:this.tabs.index(s),this.active=o?e():s,this.xhr&&this.xhr.abort(),!f.length&&!a.length&&e.error("jQuery UI Tabs: Mismatching fragment identifier."),a.length&&this.load(this.tabs.index(s),t),this._toggle(t,l)},_toggle:function(t,n){function o(){r.running=!1,r._trigger("activate",t,n)}function u(){n.newTab.closest("li").addClass("ui-tabs-active ui-state-active"),i.length&&r.options.show?r._show(i,r.options.show,o):(i.show(),o())}var r=this,i=n.newPanel,s=n.oldPanel;this.running=!0,s.length&&this.options.hide?this._hide(s,this.options.hide,function(){n.oldTab.closest("li").removeClass("ui-tabs-active ui-state-active"),u()}):(n.oldTab.closest("li").removeClass("ui-tabs-active ui-state-active"),s.hide(),u()),s.attr({"aria-expanded":"false","aria-hidden":"true"}),n.oldTab.attr("aria-selected","false"),i.length&&s.length?n.oldTab.attr("tabIndex",-1):i.length&&this.tabs.filter(function(){return e(this).attr("tabIndex")===0}).attr("tabIndex",-1),i.attr({"aria-expanded":"true","aria-hidden":"false"}),n.newTab.attr({"aria-selected":"true",tabIndex:0})},_activate:function(t){var n,r=this._findActive(t);if(r[0]===this.active[0])return;r.length||(r=this.active),n=r.find(".ui-tabs-anchor")[0],this._eventHandler({target:n,currentTarget:n,preventDefault:e.noop})},_findActive:function(t){return t===!1?e():this.tabs.eq(t)},_getIndex:function(e){return typeof e=="string"&&(e=this.anchors.index(this.anchors.filter("[href$='"+e+"']"))),e},_destroy:function(){this.xhr&&this.xhr.abort(),this.element.removeClass("ui-tabs ui-widget ui-widget-content ui-corner-all ui-tabs-collapsible"),this.tablist.removeClass("ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all").removeAttr("role"),this.anchors.removeClass("ui-tabs-anchor").removeAttr("role").removeAttr("tabIndex").removeData("href.tabs").removeData("load.tabs").removeUniqueId(),this.tabs.add(this.panels).each(function(){e.data(this,"ui-tabs-destroy")?e(this).remove():e(this).removeClass("ui-state-default ui-state-active ui-state-disabled ui-corner-top ui-corner-bottom ui-widget-content ui-tabs-active ui-tabs-panel").removeAttr("tabIndex").removeAttr("aria-live").removeAttr("aria-busy").removeAttr("aria-selected").removeAttr("aria-labelledby").removeAttr("aria-hidden").removeAttr("aria-expanded").removeAttr("role")}),this.tabs.each(function(){var t=e(this),n=t.data("ui-tabs-aria-controls");n?t.attr("aria-controls",n):t.removeAttr("aria-controls")}),this.panels.show(),this.options.heightStyle!=="content"&&this.panels.css("height","")},enable:function(n){var r=this.options.disabled;if(r===!1)return;n===t?r=!1:(n=this._getIndex(n),e.isArray(r)?r=e.map(r,function(e){return e!==n?e:null}):r=e.map(this.tabs,function(e,t){return t!==n?t:null})),this._setupDisabled(r)},disable:function(n){var r=this.options.disabled;if(r===!0)return;if(n===t)r=!0;else{n=this._getIndex(n);if(e.inArray(n,r)!==-1)return;e.isArray(r)?r=e.merge([n],r).sort():r=[n]}this._setupDisabled(r)},load:function(t,n){t=this._getIndex(t);var r=this,i=this.tabs.eq(t),o=i.find(".ui-tabs-anchor"),u=this._getPanelForTab(i),a={tab:i,panel:u};if(s(o[0]))return;this.xhr=e.ajax(this._ajaxSettings(o,n,a)),this.xhr&&this.xhr.statusText!=="canceled"&&(i.addClass("ui-tabs-loading"),u.attr("aria-busy","true"),this.xhr.success(function(e){setTimeout(function(){u.html(e),r._trigger("load",n,a)},1)}).complete(function(e,t){setTimeout(function(){t==="abort"&&r.panels.stop(!1,!0),i.removeClass("ui-tabs-loading"),u.removeAttr("aria-busy"),e===r.xhr&&delete r.xhr},1)}))},_ajaxSettings:function(t,n,r){var i=this;return{url:t.attr("href"),beforeSend:function(t,s){return i._trigger("beforeLoad",n,e.extend({jqXHR:t,ajaxSettings:s},r))}}},_getPanelForTab:function(t){var n=e(t).attr("aria-controls");return this.element.find(this._sanitizeSelector("#"+n))}}),e.uiBackCompat!==!1&&(e.ui.tabs.prototype._ui=function(e,t){return{tab:e,panel:t,index:this.anchors.index(e)}},e.widget("ui.tabs",e.ui.tabs,{url:function(e,t){this.anchors.eq(e).attr("href",t)}}),e.widget("ui.tabs",e.ui.tabs,{options:{ajaxOptions:null,cache:!1},_create:function(){this._super();var t=this;this._on({tabsbeforeload:function(n,r){if(e.data(r.tab[0],"cache.tabs")){n.preventDefault();return}r.jqXHR.success(function(){t.options.cache&&e.data(r.tab[0],"cache.tabs",!0)})}})},_ajaxSettings:function(t,n,r){var i=this.options.ajaxOptions;return e.extend({},i,{error:function(e,t){try{i.error(e,t,r.tab.closest("li").index(),r.tab[0])}catch(n){}}},this._superApply(arguments))},_setOption:function(e,t){e==="cache"&&t===!1&&this.anchors.removeData("cache.tabs"),this._super(e,t)},_destroy:function(){this.anchors.removeData("cache.tabs"),this._super()},url:function(e){this.anchors.eq(e).removeData("cache.tabs"),this._superApply(arguments)}}),e.widget("ui.tabs",e.ui.tabs,{abort:function(){this.xhr&&this.xhr.abort()}}),e.widget("ui.tabs",e.ui.tabs,{options:{spinner:"Loading…"},_create:function(){this._super(),this._on({tabsbeforeload:function(e,t){if(e.target!==this.element[0]||!this.options.spinner)return;var n=t.tab.find("span"),r=n.html();n.html(this.options.spinner),t.jqXHR.complete(function(){n.html(r)})}})}}),e.widget("ui.tabs",e.ui.tabs,{options:{enable:null,disable:null},enable:function(t){var n=this.options,r;if(t&&n.disabled===!0||e.isArray(n.disabled)&&e.inArray(t,n.disabled)!==-1)r=!0;this._superApply(arguments),r&&this._trigger("enable",null,this._ui(this.anchors[t],this.panels[t]))},disable:function(t){var n=this.options,r;if(t&&n.disabled===!1||e.isArray(n.disabled)&&e.inArray(t,n.disabled)===-1)r=!0;this._superApply(arguments),r&&this._trigger("disable",null,this._ui(this.anchors[t],this.panels[t]))}}),e.widget("ui.tabs",e.ui.tabs,{options:{add:null,remove:null,tabTemplate:"
    29. #{label}
    30. "},add:function(n,r,i){i===t&&(i=this.anchors.length);var s,o,u=this.options,a=e(u.tabTemplate.replace(/#\{href\}/g,n).replace(/#\{label\}/g,r)),f=n.indexOf("#")?this._tabId(a):n.replace("#","");return a.addClass("ui-state-default ui-corner-top").data("ui-tabs-destroy",!0),a.attr("aria-controls",f),s=i>=this.tabs.length,o=this.element.find("#"+f),o.length||(o=this._createPanel(f),s?i>0?o.insertAfter(this.panels.eq(-1)):o.appendTo(this.element):o.insertBefore(this.panels[i])),o.addClass("ui-tabs-panel ui-widget-content ui-corner-bottom").hide(),s?a.appendTo(this.tablist):a.insertBefore(this.tabs[i]),u.disabled=e.map(u.disabled,function(e){return e>=i?++e:e}),this.refresh(),this.tabs.length===1&&u.active===!1&&this.option("active",0),this._trigger("add",null,this._ui(this.anchors[i],this.panels[i])),this},remove:function(t){t=this._getIndex(t);var n=this.options,r=this.tabs.eq(t).remove(),i=this._getPanelForTab(r).remove();return r.hasClass("ui-tabs-active")&&this.anchors.length>2&&this._activate(t+(t+1=t?--e:e}),this.refresh(),this._trigger("remove",null,this._ui(r.find("a")[0],i[0])),this}}),e.widget("ui.tabs",e.ui.tabs,{length:function(){return this.anchors.length}}),e.widget("ui.tabs",e.ui.tabs,{options:{idPrefix:"ui-tabs-"},_tabId:function(t){var n=t.is("li")?t.find("a[href]"):t;return n=n[0],e(n).closest("li").attr("aria-controls")||n.title&&n.title.replace(/\s/g,"_").replace(/[^\w\u00c0-\uFFFF\-]/g,"")||this.options.idPrefix+i()}}),e.widget("ui.tabs",e.ui.tabs,{options:{panelTemplate:"
      "},_createPanel:function(t){return e(this.options.panelTemplate).attr("id",t).addClass("ui-tabs-panel ui-widget-content ui-corner-bottom").data("ui-tabs-destroy",!0)}}),e.widget("ui.tabs",e.ui.tabs,{_create:function(){var e=this.options;e.active===null&&e.selected!==t&&(e.active=e.selected===-1?!1:e.selected),this._super(),e.selected=e.active,e.selected===!1&&(e.selected=-1)},_setOption:function(e,t){if(e!=="selected")return this._super(e,t);var n=this.options;this._super("active",t===-1?!1:t),n.selected=n.active,n.selected===!1&&(n.selected=-1)},_eventHandler:function(){this._superApply(arguments),this.options.selected=this.options.active,this.options.selected===!1&&(this.options.selected=-1)}}),e.widget("ui.tabs",e.ui.tabs,{options:{show:null,select:null},_create:function(){this._super(),this.options.active!==!1&&this._trigger("show",null,this._ui(this.active.find(".ui-tabs-anchor")[0],this._getPanelForTab(this.active)[0]))},_trigger:function(e,t,n){var r,i,s=this._superApply(arguments);return s?(e==="beforeActivate"?(r=n.newTab.length?n.newTab:n.oldTab,i=n.newPanel.length?n.newPanel:n.oldPanel,s=this._super("select",t,{tab:r.find(".ui-tabs-anchor")[0],panel:i[0],index:r.closest("li").index()})):e==="activate"&&n.newTab.length&&(s=this._super("show",t,{tab:n.newTab.find(".ui-tabs-anchor")[0],panel:n.newPanel[0],index:n.newTab.closest("li").index()})),s):!1}}),e.widget("ui.tabs",e.ui.tabs,{select:function(e){e=this._getIndex(e);if(e===-1){if(!this.options.collapsible||this.options.selected===-1)return;e=this.options.selected}this.anchors.eq(e).trigger(this.options.event+this.eventNamespace)}}),function(){var t=0;e.widget("ui.tabs",e.ui.tabs,{options:{cookie:null},_create:function(){var e=this.options,t;e.active==null&&e.cookie&&(t=parseInt(this._cookie(),10),t===-1&&(t=!1),e.active=t),this._super()},_cookie:function(n){var r=[this.cookie||(this.cookie=this.options.cookie.name||"ui-tabs-"+ ++t)];return arguments.length&&(r.push(n===!1?-1:n),r.push(this.options.cookie)),e.cookie.apply(null,r)},_refresh:function(){this._super(),this.options.cookie&&this._cookie(this.options.active,this.options.cookie)},_eventHandler:function(){this._superApply(arguments),this.options.cookie&&this._cookie(this.options.active,this.options.cookie)},_destroy:function(){this._super(),this.options.cookie&&this._cookie(null,this.options.cookie)}})}(),e.widget("ui.tabs",e.ui.tabs,{_trigger:function(t,n,r){var i=e.extend({},r);return t==="load"&&(i.panel=i.panel[0],i.tab=i.tab.find(".ui-tabs-anchor")[0]),this._super(t,n,i)}}),e.widget("ui.tabs",e.ui.tabs,{options:{fx:null},_getFx:function(){var t,n,r=this.options.fx;return r&&(e.isArray(r)?(t=r[0],n=r[1]):t=n=r),r?{show:n,hide:t}:null},_toggle:function(e,t){function o(){n.running=!1,n._trigger("activate",e,t)}function u(){t.newTab.closest("li").addClass("ui-tabs-active ui-state-active"),r.length&&s.show?r.animate(s.show,s.show.duration,function(){o()}):(r.show(),o())}var n=this,r=t.newPanel,i=t.oldPanel,s=this._getFx();if(!s)return this._super(e,t);n.running=!0,i.length&&s.hide?i.animate(s.hide,s.hide.duration,function(){t.oldTab.closest("li").removeClass("ui-tabs-active ui-state-active"),u()}):(t.oldTab.closest("li").removeClass("ui-tabs-active ui-state-active"),i.hide(),u())}}))})(jQuery);(function(e){function n(t,n){var r=(t.attr("aria-describedby")||"").split(/\s+/);r.push(n),t.data("ui-tooltip-id",n).attr("aria-describedby",e.trim(r.join(" ")))}function r(t){var n=t.data("ui-tooltip-id"),r=(t.attr("aria-describedby")||"").split(/\s+/),i=e.inArray(n,r);i!==-1&&r.splice(i,1),t.removeData("ui-tooltip-id"),r=e.trim(r.join(" ")),r?t.attr("aria-describedby",r):t.removeAttr("aria-describedby")}var t=0;e.widget("ui.tooltip",{version:"1.9.2",options:{content:function(){return e(this).attr("title")},hide:!0,items:"[title]:not([disabled])",position:{my:"left top+15",at:"left bottom",collision:"flipfit flip"},show:!0,tooltipClass:null,track:!1,close:null,open:null},_create:function(){this._on({mouseover:"open",focusin:"open"}),this.tooltips={},this.parents={},this.options.disabled&&this._disable()},_setOption:function(t,n){var r=this;if(t==="disabled"){this[n?"_disable":"_enable"](),this.options[t]=n;return}this._super(t,n),t==="content"&&e.each(this.tooltips,function(e,t){r._updateContent(t)})},_disable:function(){var t=this;e.each(this.tooltips,function(n,r){var i=e.Event("blur");i.target=i.currentTarget=r[0],t.close(i,!0)}),this.element.find(this.options.items).andSelf().each(function(){var t=e(this);t.is("[title]")&&t.data("ui-tooltip-title",t.attr("title")).attr("title","")})},_enable:function(){this.element.find(this.options.items).andSelf().each(function(){var t=e(this);t.data("ui-tooltip-title")&&t.attr("title",t.data("ui-tooltip-title"))})},open:function(t){var n=this,r=e(t?t.target:this.element).closest(this.options.items);if(!r.length||r.data("ui-tooltip-id"))return;r.attr("title")&&r.data("ui-tooltip-title",r.attr("title")),r.data("ui-tooltip-open",!0),t&&t.type==="mouseover"&&r.parents().each(function(){var t=e(this),r;t.data("ui-tooltip-open")&&(r=e.Event("blur"),r.target=r.currentTarget=this,n.close(r,!0)),t.attr("title")&&(t.uniqueId(),n.parents[this.id]={element:this,title:t.attr("title")},t.attr("title",""))}),this._updateContent(r,t)},_updateContent:function(e,t){var n,r=this.options.content,i=this,s=t?t.type:null;if(typeof r=="string")return this._open(t,e,r);n=r.call(e[0],function(n){if(!e.data("ui-tooltip-open"))return;i._delay(function(){t&&(t.type=s),this._open(t,e,n)})}),n&&this._open(t,e,n)},_open:function(t,r,i){function f(e){a.of=e;if(s.is(":hidden"))return;s.position(a)}var s,o,u,a=e.extend({},this.options.position);if(!i)return;s=this._find(r);if(s.length){s.find(".ui-tooltip-content").html(i);return}r.is("[title]")&&(t&&t.type==="mouseover"?r.attr("title",""):r.removeAttr("title")),s=this._tooltip(r),n(r,s.attr("id")),s.find(".ui-tooltip-content").html(i),this.options.track&&t&&/^mouse/.test(t.type)?(this._on(this.document,{mousemove:f}),f(t)):s.position(e.extend({of:r},this.options.position)),s.hide(),this._show(s,this.options.show),this.options.show&&this.options.show.delay&&(u=setInterval(function(){s.is(":visible")&&(f(a.of),clearInterval(u))},e.fx.interval)),this._trigger("open",t,{tooltip:s}),o={keyup:function(t){if(t.keyCode===e.ui.keyCode.ESCAPE){var n=e.Event(t);n.currentTarget=r[0],this.close(n,!0)}},remove:function(){this._removeTooltip(s)}};if(!t||t.type==="mouseover")o.mouseleave="close";if(!t||t.type==="focusin")o.focusout="close";this._on(!0,r,o)},close:function(t){var n=this,i=e(t?t.currentTarget:this.element),s=this._find(i);if(this.closing)return;i.data("ui-tooltip-title")&&i.attr("title",i.data("ui-tooltip-title")),r(i),s.stop(!0),this._hide(s,this.options.hide,function(){n._removeTooltip(e(this))}),i.removeData("ui-tooltip-open"),this._off(i,"mouseleave focusout keyup"),i[0]!==this.element[0]&&this._off(i,"remove"),this._off(this.document,"mousemove"),t&&t.type==="mouseleave"&&e.each(this.parents,function(t,r){e(r.element).attr("title",r.title),delete n.parents[t]}),this.closing=!0,this._trigger("close",t,{tooltip:s}),this.closing=!1},_tooltip:function(n){var r="ui-tooltip-"+t++,i=e("
      ").attr({id:r,role:"tooltip"}).addClass("ui-tooltip ui-widget ui-corner-all ui-widget-content "+(this.options.tooltipClass||""));return e("
      ").addClass("ui-tooltip-content").appendTo(i),i.appendTo(this.document[0].body),e.fn.bgiframe&&i.bgiframe(),this.tooltips[r]=n,i},_find:function(t){var n=t.data("ui-tooltip-id");return n?e("#"+n):e()},_removeTooltip:function(e){e.remove(),delete this.tooltips[e.attr("id")]},_destroy:function(){var t=this;e.each(this.tooltips,function(n,r){var i=e.Event("blur");i.target=i.currentTarget=r[0],t.close(i,!0),e("#"+n).remove(),r.data("ui-tooltip-title")&&(r.attr("title",r.data("ui-tooltip-title")),r.removeData("ui-tooltip-title"))})}})})(jQuery);jQuery.effects||function(e,t){var n=e.uiBackCompat!==!1,r="ui-effects-";e.effects={effect:{}},function(t,n){function p(e,t,n){var r=a[t.type]||{};return e==null?n||!t.def?null:t.def:(e=r.floor?~~e:parseFloat(e),isNaN(e)?t.def:r.mod?(e+r.mod)%r.mod:0>e?0:r.max")[0],c,h=t.each;l.style.cssText="background-color:rgba(1,1,1,.5)",f.rgba=l.style.backgroundColor.indexOf("rgba")>-1,h(u,function(e,t){t.cache="_"+e,t.props.alpha={idx:3,type:"percent",def:1}}),o.fn=t.extend(o.prototype,{parse:function(r,i,s,a){if(r===n)return this._rgba=[null,null,null,null],this;if(r.jquery||r.nodeType)r=t(r).css(i),i=n;var f=this,l=t.type(r),v=this._rgba=[];i!==n&&(r=[r,i,s,a],l="array");if(l==="string")return this.parse(d(r)||c._default);if(l==="array")return h(u.rgba.props,function(e,t){v[t.idx]=p(r[t.idx],t)}),this;if(l==="object")return r instanceof o?h(u,function(e,t){r[t.cache]&&(f[t.cache]=r[t.cache].slice())}):h(u,function(t,n){var i=n.cache;h(n.props,function(e,t){if(!f[i]&&n.to){if(e==="alpha"||r[e]==null)return;f[i]=n.to(f._rgba)}f[i][t.idx]=p(r[e],t,!0)}),f[i]&&e.inArray(null,f[i].slice(0,3))<0&&(f[i][3]=1,n.from&&(f._rgba=n.from(f[i])))}),this},is:function(e){var t=o(e),n=!0,r=this;return h(u,function(e,i){var s,o=t[i.cache];return o&&(s=r[i.cache]||i.to&&i.to(r._rgba)||[],h(i.props,function(e,t){if(o[t.idx]!=null)return n=o[t.idx]===s[t.idx],n})),n}),n},_space:function(){var e=[],t=this;return h(u,function(n,r){t[r.cache]&&e.push(n)}),e.pop()},transition:function(e,t){var n=o(e),r=n._space(),i=u[r],s=this.alpha()===0?o("transparent"):this,f=s[i.cache]||i.to(s._rgba),l=f.slice();return n=n[i.cache],h(i.props,function(e,r){var i=r.idx,s=f[i],o=n[i],u=a[r.type]||{};if(o===null)return;s===null?l[i]=o:(u.mod&&(o-s>u.mod/2?s+=u.mod:s-o>u.mod/2&&(s-=u.mod)),l[i]=p((o-s)*t+s,r))}),this[r](l)},blend:function(e){if(this._rgba[3]===1)return this;var n=this._rgba.slice(),r=n.pop(),i=o(e)._rgba;return o(t.map(n,function(e,t){return(1-r)*i[t]+r*e}))},toRgbaString:function(){var e="rgba(",n=t.map(this._rgba,function(e,t){return e==null?t>2?1:0:e});return n[3]===1&&(n.pop(),e="rgb("),e+n.join()+")"},toHslaString:function(){var e="hsla(",n=t.map(this.hsla(),function(e,t){return e==null&&(e=t>2?1:0),t&&t<3&&(e=Math.round(e*100)+"%"),e});return n[3]===1&&(n.pop(),e="hsl("),e+n.join()+")"},toHexString:function(e){var n=this._rgba.slice(),r=n.pop();return e&&n.push(~~(r*255)),"#"+t.map(n,function(e){return e=(e||0).toString(16),e.length===1?"0"+e:e}).join("")},toString:function(){return this._rgba[3]===0?"transparent":this.toRgbaString()}}),o.fn.parse.prototype=o.fn,u.hsla.to=function(e){if(e[0]==null||e[1]==null||e[2]==null)return[null,null,null,e[3]];var t=e[0]/255,n=e[1]/255,r=e[2]/255,i=e[3],s=Math.max(t,n,r),o=Math.min(t,n,r),u=s-o,a=s+o,f=a*.5,l,c;return o===s?l=0:t===s?l=60*(n-r)/u+360:n===s?l=60*(r-t)/u+120:l=60*(t-n)/u+240,f===0||f===1?c=f:f<=.5?c=u/a:c=u/(2-a),[Math.round(l)%360,c,f,i==null?1:i]},u.hsla.from=function(e){if(e[0]==null||e[1]==null||e[2]==null)return[null,null,null,e[3]];var t=e[0]/360,n=e[1],r=e[2],i=e[3],s=r<=.5?r*(1+n):r+n-r*n,o=2*r-s;return[Math.round(v(o,s,t+1/3)*255),Math.round(v(o,s,t)*255),Math.round(v(o,s,t-1/3)*255),i]},h(u,function(e,r){var s=r.props,u=r.cache,a=r.to,f=r.from;o.fn[e]=function(e){a&&!this[u]&&(this[u]=a(this._rgba));if(e===n)return this[u].slice();var r,i=t.type(e),l=i==="array"||i==="object"?e:arguments,c=this[u].slice();return h(s,function(e,t){var n=l[i==="object"?e:t.idx];n==null&&(n=c[t.idx]),c[t.idx]=p(n,t)}),f?(r=o(f(c)),r[u]=c,r):o(c)},h(s,function(n,r){if(o.fn[n])return;o.fn[n]=function(s){var o=t.type(s),u=n==="alpha"?this._hsla?"hsla":"rgba":e,a=this[u](),f=a[r.idx],l;return o==="undefined"?f:(o==="function"&&(s=s.call(this,f),o=t.type(s)),s==null&&r.empty?this:(o==="string"&&(l=i.exec(s),l&&(s=f+parseFloat(l[2])*(l[1]==="+"?1:-1))),a[r.idx]=s,this[u](a)))}})}),h(r,function(e,n){t.cssHooks[n]={set:function(e,r){var i,s,u="";if(t.type(r)!=="string"||(i=d(r))){r=o(i||r);if(!f.rgba&&r._rgba[3]!==1){s=n==="backgroundColor"?e.parentNode:e;while((u===""||u==="transparent")&&s&&s.style)try{u=t.css(s,"backgroundColor"),s=s.parentNode}catch(a){}r=r.blend(u&&u!=="transparent"?u:"_default")}r=r.toRgbaString()}try{e.style[n]=r}catch(l){}}},t.fx.step[n]=function(e){e.colorInit||(e.start=o(e.elem,n),e.end=o(e.end),e.colorInit=!0),t.cssHooks[n].set(e.elem,e.start.transition(e.end,e.pos))}}),t.cssHooks.borderColor={expand:function(e){var t={};return h(["Top","Right","Bottom","Left"],function(n,r){t["border"+r+"Color"]=e}),t}},c=t.Color.names={aqua:"#00ffff",black:"#000000",blue:"#0000ff",fuchsia:"#ff00ff",gray:"#808080",green:"#008000",lime:"#00ff00",maroon:"#800000",navy:"#000080",olive:"#808000",purple:"#800080",red:"#ff0000",silver:"#c0c0c0",teal:"#008080",white:"#ffffff",yellow:"#ffff00",transparent:[null,null,null,0],_default:"#ffffff"}}(jQuery),function(){function i(){var t=this.ownerDocument.defaultView?this.ownerDocument.defaultView.getComputedStyle(this,null):this.currentStyle,n={},r,i;if(t&&t.length&&t[0]&&t[t[0]]){i=t.length;while(i--)r=t[i],typeof t[r]=="string"&&(n[e.camelCase(r)]=t[r])}else for(r in t)typeof t[r]=="string"&&(n[r]=t[r]);return n}function s(t,n){var i={},s,o;for(s in n)o=n[s],t[s]!==o&&!r[s]&&(e.fx.step[s]||!isNaN(parseFloat(o)))&&(i[s]=o);return i}var n=["add","remove","toggle"],r={border:1,borderBottom:1,borderColor:1,borderLeft:1,borderRight:1,borderTop:1,borderWidth:1,margin:1,padding:1};e.each(["borderLeftStyle","borderRightStyle","borderBottomStyle","borderTopStyle"],function(t,n){e.fx.step[n]=function(e){if(e.end!=="none"&&!e.setAttr||e.pos===1&&!e.setAttr)jQuery.style(e.elem,n,e.end),e.setAttr=!0}}),e.effects.animateClass=function(t,r,o,u){var a=e.speed(r,o,u);return this.queue(function(){var r=e(this),o=r.attr("class")||"",u,f=a.children?r.find("*").andSelf():r;f=f.map(function(){var t=e(this);return{el:t,start:i.call(this)}}),u=function(){e.each(n,function(e,n){t[n]&&r[n+"Class"](t[n])})},u(),f=f.map(function(){return this.end=i.call(this.el[0]),this.diff=s(this.start,this.end),this}),r.attr("class",o),f=f.map(function(){var t=this,n=e.Deferred(),r=jQuery.extend({},a,{queue:!1,complete:function(){n.resolve(t)}});return this.el.animate(this.diff,r),n.promise()}),e.when.apply(e,f.get()).done(function(){u(),e.each(arguments,function(){var t=this.el;e.each(this.diff,function(e){t.css(e,"")})}),a.complete.call(r[0])})})},e.fn.extend({_addClass:e.fn.addClass,addClass:function(t,n,r,i){return n?e.effects.animateClass.call(this,{add:t},n,r,i):this._addClass(t)},_removeClass:e.fn.removeClass,removeClass:function(t,n,r,i){return n?e.effects.animateClass.call(this,{remove:t},n,r,i):this._removeClass(t)},_toggleClass:e.fn.toggleClass,toggleClass:function(n,r,i,s,o){return typeof r=="boolean"||r===t?i?e.effects.animateClass.call(this,r?{add:n}:{remove:n},i,s,o):this._toggleClass(n,r):e.effects.animateClass.call(this,{toggle:n},r,i,s)},switchClass:function(t,n,r,i,s){return e.effects.animateClass.call(this,{add:n,remove:t},r,i,s)}})}(),function(){function i(t,n,r,i){e.isPlainObject(t)&&(n=t,t=t.effect),t={effect:t},n==null&&(n={}),e.isFunction(n)&&(i=n,r=null,n={});if(typeof n=="number"||e.fx.speeds[n])i=r,r=n,n={};return e.isFunction(r)&&(i=r,r=null),n&&e.extend(t,n),r=r||n.duration,t.duration=e.fx.off?0:typeof r=="number"?r:r in e.fx.speeds?e.fx.speeds[r]:e.fx.speeds._default,t.complete=i||n.complete,t}function s(t){return!t||typeof t=="number"||e.fx.speeds[t]?!0:typeof t=="string"&&!e.effects.effect[t]?n&&e.effects[t]?!1:!0:!1}e.extend(e.effects,{version:"1.9.2",save:function(e,t){for(var n=0;n
      ").addClass("ui-effects-wrapper").css({fontSize:"100%",background:"transparent",border:"none",margin:0,padding:0}),i={width:t.width(),height:t.height()},s=document.activeElement;try{s.id}catch(o){s=document.body}return t.wrap(r),(t[0]===s||e.contains(t[0],s))&&e(s).focus(),r=t.parent(),t.css("position")==="static"?(r.css({position:"relative"}),t.css({position:"relative"})):(e.extend(n,{position:t.css("position"),zIndex:t.css("z-index")}),e.each(["top","left","bottom","right"],function(e,r){n[r]=t.css(r),isNaN(parseInt(n[r],10))&&(n[r]="auto")}),t.css({position:"relative",top:0,left:0,right:"auto",bottom:"auto"})),t.css(i),r.css(n).show()},removeWrapper:function(t){var n=document.activeElement;return t.parent().is(".ui-effects-wrapper")&&(t.parent().replaceWith(t),(t[0]===n||e.contains(t[0],n))&&e(n).focus()),t},setTransition:function(t,n,r,i){return i=i||{},e.each(n,function(e,n){var s=t.cssUnit(n);s[0]>0&&(i[n]=s[0]*r+s[1])}),i}}),e.fn.extend({effect:function(){function a(n){function u(){e.isFunction(i)&&i.call(r[0]),e.isFunction(n)&&n()}var r=e(this),i=t.complete,s=t.mode;(r.is(":hidden")?s==="hide":s==="show")?u():o.call(r[0],t,u)}var t=i.apply(this,arguments),r=t.mode,s=t.queue,o=e.effects.effect[t.effect],u=!o&&n&&e.effects[t.effect];return e.fx.off||!o&&!u?r?this[r](t.duration,t.complete):this.each(function(){t.complete&&t.complete.call(this)}):o?s===!1?this.each(a):this.queue(s||"fx",a):u.call(this,{options:t,duration:t.duration,callback:t.complete,mode:t.mode})},_show:e.fn.show,show:function(e){if(s(e))return this._show.apply(this,arguments);var t=i.apply(this,arguments);return t.mode="show",this.effect.call(this,t)},_hide:e.fn.hide,hide:function(e){if(s(e))return this._hide.apply(this,arguments);var t=i.apply(this,arguments);return t.mode="hide",this.effect.call(this,t)},__toggle:e.fn.toggle,toggle:function(t){if(s(t)||typeof t=="boolean"||e.isFunction(t))return this.__toggle.apply(this,arguments);var n=i.apply(this,arguments);return n.mode="toggle",this.effect.call(this,n)},cssUnit:function(t){var n=this.css(t),r=[];return e.each(["em","px","%","pt"],function(e,t){n.indexOf(t)>0&&(r=[parseFloat(n),t])}),r}})}(),function(){var t={};e.each(["Quad","Cubic","Quart","Quint","Expo"],function(e,n){t[n]=function(t){return Math.pow(t,e+2)}}),e.extend(t,{Sine:function(e){return 1-Math.cos(e*Math.PI/2)},Circ:function(e){return 1-Math.sqrt(1-e*e)},Elastic:function(e){return e===0||e===1?e:-Math.pow(2,8*(e-1))*Math.sin(((e-1)*80-7.5)*Math.PI/15)},Back:function(e){return e*e*(3*e-2)},Bounce:function(e){var t,n=4;while(e<((t=Math.pow(2,--n))-1)/11);return 1/Math.pow(4,3-n)-7.5625*Math.pow((t*3-2)/22-e,2)}}),e.each(t,function(t,n){e.easing["easeIn"+t]=n,e.easing["easeOut"+t]=function(e){return 1-n(1-e)},e.easing["easeInOut"+t]=function(e){return e<.5?n(e*2)/2:1-n(e*-2+2)/2}})}()}(jQuery);(function(e,t){var n=/up|down|vertical/,r=/up|left|vertical|horizontal/;e.effects.effect.blind=function(t,i){var s=e(this),o=["position","top","bottom","left","right","height","width"],u=e.effects.setMode(s,t.mode||"hide"),a=t.direction||"up",f=n.test(a),l=f?"height":"width",c=f?"top":"left",h=r.test(a),p={},d=u==="show",v,m,g;s.parent().is(".ui-effects-wrapper")?e.effects.save(s.parent(),o):e.effects.save(s,o),s.show(),v=e.effects.createWrapper(s).css({overflow:"hidden"}),m=v[l](),g=parseFloat(v.css(c))||0,p[l]=d?m:0,h||(s.css(f?"bottom":"right",0).css(f?"top":"left","auto").css({position:"absolute"}),p[c]=d?g:m+g),d&&(v.css(l,0),h||v.css(c,g+m)),v.animate(p,{duration:t.duration,easing:t.easing,queue:!1,complete:function(){u==="hide"&&s.hide(),e.effects.restore(s,o),e.effects.removeWrapper(s),i()}})}})(jQuery);(function(e,t){e.effects.effect.bounce=function(t,n){var r=e(this),i=["position","top","bottom","left","right","height","width"],s=e.effects.setMode(r,t.mode||"effect"),o=s==="hide",u=s==="show",a=t.direction||"up",f=t.distance,l=t.times||5,c=l*2+(u||o?1:0),h=t.duration/c,p=t.easing,d=a==="up"||a==="down"?"top":"left",v=a==="up"||a==="left",m,g,y,b=r.queue(),w=b.length;(u||o)&&i.push("opacity"),e.effects.save(r,i),r.show(),e.effects.createWrapper(r),f||(f=r[d==="top"?"outerHeight":"outerWidth"]()/3),u&&(y={opacity:1},y[d]=0,r.css("opacity",0).css(d,v?-f*2:f*2).animate(y,h,p)),o&&(f/=Math.pow(2,l-1)),y={},y[d]=0;for(m=0;m1&&b.splice.apply(b,[1,0].concat(b.splice(w,c+1))),r.dequeue()}})(jQuery);(function(e,t){e.effects.effect.clip=function(t,n){var r=e(this),i=["position","top","bottom","left","right","height","width"],s=e.effects.setMode(r,t.mode||"hide"),o=s==="show",u=t.direction||"vertical",a=u==="vertical",f=a?"height":"width",l=a?"top":"left",c={},h,p,d;e.effects.save(r,i),r.show(),h=e.effects.createWrapper(r).css({overflow:"hidden"}),p=r[0].tagName==="IMG"?h:r,d=p[f](),o&&(p.css(f,0),p.css(l,d/2)),c[f]=o?d:0,c[l]=o?0:d/2,p.animate(c,{queue:!1,duration:t.duration,easing:t.easing,complete:function(){o||r.hide(),e.effects.restore(r,i),e.effects.removeWrapper(r),n()}})}})(jQuery);(function(e,t){e.effects.effect.drop=function(t,n){var r=e(this),i=["position","top","bottom","left","right","opacity","height","width"],s=e.effects.setMode(r,t.mode||"hide"),o=s==="show",u=t.direction||"left",a=u==="up"||u==="down"?"top":"left",f=u==="up"||u==="left"?"pos":"neg",l={opacity:o?1:0},c;e.effects.save(r,i),r.show(),e.effects.createWrapper(r),c=t.distance||r[a==="top"?"outerHeight":"outerWidth"](!0)/2,o&&r.css("opacity",0).css(a,f==="pos"?-c:c),l[a]=(o?f==="pos"?"+=":"-=":f==="pos"?"-=":"+=")+c,r.animate(l,{queue:!1,duration:t.duration,easing:t.easing,complete:function(){s==="hide"&&r.hide(),e.effects.restore(r,i),e.effects.removeWrapper(r),n()}})}})(jQuery);(function(e,t){e.effects.effect.explode=function(t,n){function y(){c.push(this),c.length===r*i&&b()}function b(){s.css({visibility:"visible"}),e(c).remove(),u||s.hide(),n()}var r=t.pieces?Math.round(Math.sqrt(t.pieces)):3,i=r,s=e(this),o=e.effects.setMode(s,t.mode||"hide"),u=o==="show",a=s.show().css("visibility","hidden").offset(),f=Math.ceil(s.outerWidth()/i),l=Math.ceil(s.outerHeight()/r),c=[],h,p,d,v,m,g;for(h=0;h
      ").css({position:"absolute",visibility:"visible",left:-p*f,top:-h*l}).parent().addClass("ui-effects-explode").css({position:"absolute",overflow:"hidden",width:f,height:l,left:d+(u?m*f:0),top:v+(u?g*l:0),opacity:u?0:1}).animate({left:d+(u?0:m*f),top:v+(u?0:g*l),opacity:u?1:0},t.duration||500,t.easing,y)}}})(jQuery);(function(e,t){e.effects.effect.fade=function(t,n){var r=e(this),i=e.effects.setMode(r,t.mode||"toggle");r.animate({opacity:i},{queue:!1,duration:t.duration,easing:t.easing,complete:n})}})(jQuery);(function(e,t){e.effects.effect.fold=function(t,n){var r=e(this),i=["position","top","bottom","left","right","height","width"],s=e.effects.setMode(r,t.mode||"hide"),o=s==="show",u=s==="hide",a=t.size||15,f=/([0-9]+)%/.exec(a),l=!!t.horizFirst,c=o!==l,h=c?["width","height"]:["height","width"],p=t.duration/2,d,v,m={},g={};e.effects.save(r,i),r.show(),d=e.effects.createWrapper(r).css({overflow:"hidden"}),v=c?[d.width(),d.height()]:[d.height(),d.width()],f&&(a=parseInt(f[1],10)/100*v[u?0:1]),o&&d.css(l?{height:0,width:a}:{height:a,width:0}),m[h[0]]=o?v[0]:a,g[h[1]]=o?v[1]:0,d.animate(m,p,t.easing).animate(g,p,t.easing,function(){u&&r.hide(),e.effects.restore(r,i),e.effects.removeWrapper(r),n()})}})(jQuery);(function(e,t){e.effects.effect.highlight=function(t,n){var r=e(this),i=["backgroundImage","backgroundColor","opacity"],s=e.effects.setMode(r,t.mode||"show"),o={backgroundColor:r.css("backgroundColor")};s==="hide"&&(o.opacity=0),e.effects.save(r,i),r.show().css({backgroundImage:"none",backgroundColor:t.color||"#ffff99"}).animate(o,{queue:!1,duration:t.duration,easing:t.easing,complete:function(){s==="hide"&&r.hide(),e.effects.restore(r,i),n()}})}})(jQuery);(function(e,t){e.effects.effect.pulsate=function(t,n){var r=e(this),i=e.effects.setMode(r,t.mode||"show"),s=i==="show",o=i==="hide",u=s||i==="hide",a=(t.times||5)*2+(u?1:0),f=t.duration/a,l=0,c=r.queue(),h=c.length,p;if(s||!r.is(":visible"))r.css("opacity",0).show(),l=1;for(p=1;p1&&c.splice.apply(c,[1,0].concat(c.splice(h,a+1))),r.dequeue()}})(jQuery);(function(e,t){e.effects.effect.puff=function(t,n){var r=e(this),i=e.effects.setMode(r,t.mode||"hide"),s=i==="hide",o=parseInt(t.percent,10)||150,u=o/100,a={height:r.height(),width:r.width(),outerHeight:r.outerHeight(),outerWidth:r.outerWidth()};e.extend(t,{effect:"scale",queue:!1,fade:!0,mode:i,complete:n,percent:s?o:100,from:s?a:{height:a.height*u,width:a.width*u,outerHeight:a.outerHeight*u,outerWidth:a.outerWidth*u}}),r.effect(t)},e.effects.effect.scale=function(t,n){var r=e(this),i=e.extend(!0,{},t),s=e.effects.setMode(r,t.mode||"effect"),o=parseInt(t.percent,10)||(parseInt(t.percent,10)===0?0:s==="hide"?0:100),u=t.direction||"both",a=t.origin,f={height:r.height(),width:r.width(),outerHeight:r.outerHeight(),outerWidth:r.outerWidth()},l={y:u!=="horizontal"?o/100:1,x:u!=="vertical"?o/100:1};i.effect="size",i.queue=!1,i.complete=n,s!=="effect"&&(i.origin=a||["middle","center"],i.restore=!0),i.from=t.from||(s==="show"?{height:0,width:0,outerHeight:0,outerWidth:0}:f),i.to={height:f.height*l.y,width:f.width*l.x,outerHeight:f.outerHeight*l.y,outerWidth:f.outerWidth*l.x},i.fade&&(s==="show"&&(i.from.opacity=0,i.to.opacity=1),s==="hide"&&(i.from.opacity=1,i.to.opacity=0)),r.effect(i)},e.effects.effect.size=function(t,n){var r,i,s,o=e(this),u=["position","top","bottom","left","right","width","height","overflow","opacity"],a=["position","top","bottom","left","right","overflow","opacity"],f=["width","height","overflow"],l=["fontSize"],c=["borderTopWidth","borderBottomWidth","paddingTop","paddingBottom"],h=["borderLeftWidth","borderRightWidth","paddingLeft","paddingRight"],p=e.effects.setMode(o,t.mode||"effect"),d=t.restore||p!=="effect",v=t.scale||"both",m=t.origin||["middle","center"],g=o.css("position"),y=d?u:a,b={height:0,width:0,outerHeight:0,outerWidth:0};p==="show"&&o.show(),r={height:o.height(),width:o.width(),outerHeight:o.outerHeight(),outerWidth:o.outerWidth()},t.mode==="toggle"&&p==="show"?(o.from=t.to||b,o.to=t.from||r):(o.from=t.from||(p==="show"?b:r),o.to=t.to||(p==="hide"?b:r)),s={from:{y:o.from.height/r.height,x:o.from.width/r.width},to:{y:o.to.height/r.height,x:o.to.width/r.width}};if(v==="box"||v==="both")s.from.y!==s.to.y&&(y=y.concat(c),o.from=e.effects.setTransition(o,c,s.from.y,o.from),o.to=e.effects.setTransition(o,c,s.to.y,o.to)),s.from.x!==s.to.x&&(y=y.concat(h),o.from=e.effects.setTransition(o,h,s.from.x,o.from),o.to=e.effects.setTransition(o,h,s.to.x,o.to));(v==="content"||v==="both")&&s.from.y!==s.to.y&&(y=y.concat(l).concat(f),o.from=e.effects.setTransition(o,l,s.from.y,o.from),o.to=e.effects.setTransition(o,l,s.to.y,o.to)),e.effects.save(o,y),o.show(),e.effects.createWrapper(o),o.css("overflow","hidden").css(o.from),m&&(i=e.effects.getBaseline(m,r),o.from.top=(r.outerHeight-o.outerHeight())*i.y,o.from.left=(r.outerWidth-o.outerWidth())*i.x,o.to.top=(r.outerHeight-o.to.outerHeight)*i.y,o.to.left=(r.outerWidth-o.to.outerWidth)*i.x),o.css(o.from);if(v==="content"||v==="both")c=c.concat(["marginTop","marginBottom"]).concat(l),h=h.concat(["marginLeft","marginRight"]),f=u.concat(c).concat(h),o.find("*[width]").each(function(){var n=e(this),r={height:n.height(),width:n.width(),outerHeight:n.outerHeight(),outerWidth:n.outerWidth()};d&&e.effects.save(n,f),n.from={height:r.height*s.from.y,width:r.width*s.from.x,outerHeight:r.outerHeight*s.from.y,outerWidth:r.outerWidth*s.from.x},n.to={height:r.height*s.to.y,width:r.width*s.to.x,outerHeight:r.height*s.to.y,outerWidth:r.width*s.to.x},s.from.y!==s.to.y&&(n.from=e.effects.setTransition(n,c,s.from.y,n.from),n.to=e.effects.setTransition(n,c,s.to.y,n.to)),s.from.x!==s.to.x&&(n.from=e.effects.setTransition(n,h,s.from.x,n.from),n.to=e.effects.setTransition(n,h,s.to.x,n.to)),n.css(n.from),n.animate(n.to,t.duration,t.easing,function(){d&&e.effects.restore(n,f)})});o.animate(o.to,{queue:!1,duration:t.duration,easing:t.easing,complete:function(){o.to.opacity===0&&o.css("opacity",o.from.opacity),p==="hide"&&o.hide(),e.effects.restore(o,y),d||(g==="static"?o.css({position:"relative",top:o.to.top,left:o.to.left}):e.each(["top","left"],function(e,t){o.css(t,function(t,n){var r=parseInt(n,10),i=e?o.to.left:o.to.top;return n==="auto"?i+"px":r+i+"px"})})),e.effects.removeWrapper(o),n()}})}})(jQuery);(function(e,t){e.effects.effect.shake=function(t,n){var r=e(this),i=["position","top","bottom","left","right","height","width"],s=e.effects.setMode(r,t.mode||"effect"),o=t.direction||"left",u=t.distance||20,a=t.times||3,f=a*2+1,l=Math.round(t.duration/f),c=o==="up"||o==="down"?"top":"left",h=o==="up"||o==="left",p={},d={},v={},m,g=r.queue(),y=g.length;e.effects.save(r,i),r.show(),e.effects.createWrapper(r),p[c]=(h?"-=":"+=")+u,d[c]=(h?"+=":"-=")+u*2,v[c]=(h?"-=":"+=")+u*2,r.animate(p,l,t.easing);for(m=1;m1&&g.splice.apply(g,[1,0].concat(g.splice(y,f+1))),r.dequeue()}})(jQuery);(function(e,t){e.effects.effect.slide=function(t,n){var r=e(this),i=["position","top","bottom","left","right","width","height"],s=e.effects.setMode(r,t.mode||"show"),o=s==="show",u=t.direction||"left",a=u==="up"||u==="down"?"top":"left",f=u==="up"||u==="left",l,c={};e.effects.save(r,i),r.show(),l=t.distance||r[a==="top"?"outerHeight":"outerWidth"](!0),e.effects.createWrapper(r).css({overflow:"hidden"}),o&&r.css(a,f?isNaN(l)?"-"+l:-l:l),c[a]=(o?f?"+=":"-=":f?"-=":"+=")+l,r.animate(c,{queue:!1,duration:t.duration,easing:t.easing,complete:function(){s==="hide"&&r.hide(),e.effects.restore(r,i),e.effects.removeWrapper(r),n()}})}})(jQuery);(function(e,t){e.effects.effect.transfer=function(t,n){var r=e(this),i=e(t.to),s=i.css("position")==="fixed",o=e("body"),u=s?o.scrollTop():0,a=s?o.scrollLeft():0,f=i.offset(),l={top:f.top-u,left:f.left-a,height:i.innerHeight(),width:i.innerWidth()},c=r.offset(),h=e('
      ').appendTo(document.body).addClass(t.className).css({top:c.top-u,left:c.left-a,height:r.innerHeight(),width:r.innerWidth(),position:s?"fixed":"absolute"}).animate(l,t.duration,t.easing,function(){h.remove(),n()})}})(jQuery); + +/* JQuery UJS 2.0.3 */ +(function(a,b){var c=function(){var b=a(document).data("events");return b&&b.click&&a.grep(b.click,function(a){return a.namespace==="rails"}).length};if(c()){a.error("jquery-ujs has already been loaded!")}var d;a.rails=d={linkClickSelector:"a[data-confirm], a[data-method], a[data-remote], a[data-disable-with]",inputChangeSelector:"select[data-remote], input[data-remote], textarea[data-remote]",formSubmitSelector:"form",formInputClickSelector:"form input[type=submit], form input[type=image], form button[type=submit], form button:not([type])",disableSelector:"input[data-disable-with], button[data-disable-with], textarea[data-disable-with]",enableSelector:"input[data-disable-with]:disabled, button[data-disable-with]:disabled, textarea[data-disable-with]:disabled",requiredInputSelector:"input[name][required]:not([disabled]),textarea[name][required]:not([disabled])",fileInputSelector:"input:file",linkDisableSelector:"a[data-disable-with]",CSRFProtection:function(b){var c=a('meta[name="csrf-token"]').attr("content");if(c)b.setRequestHeader("X-CSRF-Token",c)},fire:function(b,c,d){var e=a.Event(c);b.trigger(e,d);return e.result!==false},confirm:function(a){return confirm(a)},ajax:function(b){return a.ajax(b)},href:function(a){return a.attr("href")},handleRemote:function(c){var e,f,g,h,i,j,k,l;if(d.fire(c,"ajax:before")){h=c.data("cross-domain");i=h===b?null:h;j=c.data("with-credentials")||null;k=c.data("type")||a.ajaxSettings&&a.ajaxSettings.dataType;if(c.is("form")){e=c.attr("method");f=c.attr("action");g=c.serializeArray();var m=c.data("ujs:submit-button");if(m){g.push(m);c.data("ujs:submit-button",null)}}else if(c.is(d.inputChangeSelector)){e=c.data("method");f=c.data("url");g=c.serialize();if(c.data("params"))g=g+"&"+c.data("params")}else{e=c.data("method");f=d.href(c);g=c.data("params")||null}l={type:e||"GET",data:g,dataType:k,beforeSend:function(a,e){if(e.dataType===b){a.setRequestHeader("accept","*/*;q=0.5, "+e.accepts.script)}return d.fire(c,"ajax:beforeSend",[a,e])},success:function(a,b,d){c.trigger("ajax:success",[a,b,d])},complete:function(a,b){c.trigger("ajax:complete",[a,b])},error:function(a,b,d){c.trigger("ajax:error",[a,b,d])},xhrFields:{withCredentials:j},crossDomain:i};if(f){l.url=f}var n=d.ajax(l);c.trigger("ajax:send",n);return n}else{return false}},handleMethod:function(c){var e=d.href(c),f=c.data("method"),g=c.attr("target"),h=a("meta[name=csrf-token]").attr("content"),i=a("meta[name=csrf-param]").attr("content"),j=a('
      '),k='';if(i!==b&&h!==b){k+=''}if(g){j.attr("target",g)}j.hide().append(k).appendTo("body");j.submit()},disableFormElements:function(b){b.find(d.disableSelector).each(function(){var b=a(this),c=b.is("button")?"html":"val";b.data("ujs:enable-with",b[c]());b[c](b.data("disable-with"));b.prop("disabled",true)})},enableFormElements:function(b){b.find(d.enableSelector).each(function(){var b=a(this),c=b.is("button")?"html":"val";if(b.data("ujs:enable-with"))b[c](b.data("ujs:enable-with"));b.prop("disabled",false)})},allowAction:function(a){var b=a.data("confirm"),c=false,e;if(!b){return true}if(d.fire(a,"confirm")){c=d.confirm(b);e=d.fire(a,"confirm:complete",[c])}return c&&e},blankInputs:function(b,c,d){var e=a(),f,g,h=c||"input,textarea";b.find(h).each(function(){f=a(this);g=f.is(":checkbox,:radio")?f.is(":checked"):f.val();if(g==!!d){e=e.add(f)}});return e.length?e:false},nonBlankInputs:function(a,b){return d.blankInputs(a,b,true)},stopEverything:function(b){a(b.target).trigger("ujs:everythingStopped");b.stopImmediatePropagation();return false},callFormSubmitBindings:function(c,d){var e=c.data("events"),f=true;if(e!==b&&e["submit"]!==b){a.each(e["submit"],function(a,b){if(typeof b.handler==="function")return f=b.handler(d)})}return f},disableElement:function(a){a.data("ujs:enable-with",a.html());a.html(a.data("disable-with"));a.bind("click.railsDisable",function(a){return d.stopEverything(a)})},enableElement:function(a){if(a.data("ujs:enable-with")!==b){a.html(a.data("ujs:enable-with"));a.data("ujs:enable-with",false)}a.unbind("click.railsDisable")}};if(d.fire(a(document),"rails:attachBindings")){a.ajaxPrefilter(function(a,b,c){if(!a.crossDomain){d.CSRFProtection(c)}});a(document).delegate(d.linkDisableSelector,"ajax:complete",function(){d.enableElement(a(this))});a(document).delegate(d.linkClickSelector,"click.rails",function(c){var e=a(this),f=e.data("method"),g=e.data("params");if(!d.allowAction(e))return d.stopEverything(c);if(e.is(d.linkDisableSelector))d.disableElement(e);if(e.data("remote")!==b){if((c.metaKey||c.ctrlKey)&&(!f||f==="GET")&&!g){return true}if(d.handleRemote(e)===false){d.enableElement(e)}return false}else if(e.data("method")){d.handleMethod(e);return false}});a(document).delegate(d.inputChangeSelector,"change.rails",function(b){var c=a(this);if(!d.allowAction(c))return d.stopEverything(b);d.handleRemote(c);return false});a(document).delegate(d.formSubmitSelector,"submit.rails",function(c){var e=a(this),f=e.data("remote")!==b,g=d.blankInputs(e,d.requiredInputSelector),h=d.nonBlankInputs(e,d.fileInputSelector);if(!d.allowAction(e))return d.stopEverything(c);if(g&&e.attr("novalidate")==b&&d.fire(e,"ajax:aborted:required",[g])){return d.stopEverything(c)}if(f){if(h){setTimeout(function(){d.disableFormElements(e)},13);return d.fire(e,"ajax:aborted:file",[h])}if(!a.support.submitBubbles&&a().jquery<"1.7"&&d.callFormSubmitBindings(e,c)===false)return d.stopEverything(c);d.handleRemote(e);return false}else{setTimeout(function(){d.disableFormElements(e)},13)}});a(document).delegate(d.formInputClickSelector,"click.rails",function(b){var c=a(this);if(!d.allowAction(c))return d.stopEverything(b);var e=c.attr("name"),f=e?{name:e,value:c.val()}:null;c.closest("form").data("ujs:submit-button",f)});a(document).delegate(d.formSubmitSelector,"ajax:beforeSend.rails",function(b){if(this==b.target)d.disableFormElements(a(this))});a(document).delegate(d.formSubmitSelector,"ajax:complete.rails",function(b){if(this==b.target)d.enableFormElements(a(this))});a(function(){csrf_token=a("meta[name=csrf-token]").attr("content");csrf_param=a("meta[name=csrf-param]").attr("content");a('form input[name="'+csrf_param+'"]').val(csrf_token)})}})(jQuery) diff --git a/public/javascripts/jstoolbar/jstoolbar-textile.min.js b/public/javascripts/jstoolbar/jstoolbar-textile.min.js new file mode 100644 index 00000000..e74cb387 --- /dev/null +++ b/public/javascripts/jstoolbar/jstoolbar-textile.min.js @@ -0,0 +1,2 @@ +function jsToolBar(e){if(!document.createElement){return}if(!e){return}if(typeof document["selection"]=="undefined"&&typeof e["setSelectionRange"]=="undefined"){return}this.textarea=e;this.editor=document.createElement("div");this.editor.className="jstEditor";this.textarea.parentNode.insertBefore(this.editor,this.textarea);this.editor.appendChild(this.textarea);this.toolbar=document.createElement("div");this.toolbar.className="jstElements";this.editor.parentNode.insertBefore(this.toolbar,this.editor);if(this.editor.addEventListener&&navigator.appVersion.match(/\bMSIE\b/)){this.handle=document.createElement("div");this.handle.className="jstHandle";var t=this.resizeDragStart;var n=this;this.handle.addEventListener("mousedown",function(e){t.call(n,e)},false);window.addEventListener("unload",function(){var e=n.handle.parentNode.removeChild(n.handle);delete n.handle},false);this.editor.parentNode.insertBefore(this.handle,this.editor.nextSibling)}this.context=null;this.toolNodes={}}function jsButton(e,t,n,r){if(typeof jsToolBar.strings=="undefined"){this.title=e||null}else{this.title=jsToolBar.strings[e]||e||null}this.fn=t||function(){};this.scope=n||null;this.className=r||null}function jsSpace(e){this.id=e||null;this.width=null}function jsCombo(e,t,n,r,i){this.title=e||null;this.options=t||null;this.scope=n||null;this.fn=r||function(){};this.className=i||null}jsButton.prototype.draw=function(){if(!this.scope)return null;var e=document.createElement("button");e.setAttribute("type","button");e.tabIndex=200;if(this.className)e.className=this.className;e.title=this.title;var t=document.createElement("span");t.appendChild(document.createTextNode(this.title));e.appendChild(t);if(this.icon!=undefined){e.style.backgroundImage="url("+this.icon+")"}if(typeof this.fn=="function"){var n=this;e.onclick=function(){try{n.fn.apply(n.scope,arguments)}catch(e){}return false}}return e};jsSpace.prototype.draw=function(){var e=document.createElement("span");if(this.id)e.id=this.id;e.appendChild(document.createTextNode(String.fromCharCode(160)));e.className="jstSpacer";if(this.width)e.style.marginRight=this.width+"px";return e};jsCombo.prototype.draw=function(){if(!this.scope||!this.options)return null;var e=document.createElement("select");if(this.className)e.className=className;e.title=this.title;for(var t in this.options){var n=document.createElement("option");n.value=t;n.appendChild(document.createTextNode(this.options[t]));e.appendChild(n)}var r=this;e.onchange=function(){try{r.fn.call(r.scope,this.value)}catch(e){alert(e)}return false};return e};jsToolBar.prototype={base_url:"",mode:"wiki",elements:{},help_link:"",getMode:function(){return this.mode},setMode:function(e){this.mode=e||"wiki"},switchMode:function(e){e=e||"wiki";this.draw(e)},setHelpLink:function(e){this.help_link=e},button:function(e){var t=this.elements[e];if(typeof t.fn[this.mode]!="function")return null;var n=new jsButton(t.title,t.fn[this.mode],this,"jstb_"+e);if(t.icon!=undefined)n.icon=t.icon;return n},space:function(e){var t=new jsSpace(e);if(this.elements[e].width!==undefined)t.width=this.elements[e].width;return t},combo:function(e){var t=this.elements[e];var n=t[this.mode].list.length;if(typeof t[this.mode].fn!="function"||n==0){return null}else{var r={};for(var i=0;i $2")})}}};jsToolBar.prototype.elements.unbq={type:"button",title:"Unquote",fn:{wiki:function(){this.encloseLineSelection("","",function(e){e=e.replace(/\r/g,"");return e.replace(/(\n|^) *[>]? *([^\n]*)/g,"$1$2")})}}};jsToolBar.prototype.elements.pre={type:"button",title:"Preformatted text",fn:{wiki:function(){this.encloseLineSelection("
      \n","\n
      ")}}};jsToolBar.prototype.elements.space4={type:"space"};jsToolBar.prototype.elements.link={type:"button",title:"Wiki link",fn:{wiki:function(){this.encloseSelection("[[","]]")}}};jsToolBar.prototype.elements.img={type:"button",title:"Image",fn:{wiki:function(){this.encloseSelection("!","!")}}};jsToolBar.prototype.elements.space5={type:"space"};jsToolBar.prototype.elements.help={type:"button",title:"Help",fn:{wiki:function(){window.open(this.help_link,"","resizable=yes, location=no, width=300, height=640, menubar=no, status=no, scrollbars=yes")}}} diff --git a/public/javascripts/jstoolbar/jstoolbar.js b/public/javascripts/jstoolbar/jstoolbar.js new file mode 100644 index 00000000..19f4bdf9 --- /dev/null +++ b/public/javascripts/jstoolbar/jstoolbar.js @@ -0,0 +1,374 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * This file is part of DotClear. + * Copyright (c) 2005 Nicolas Martin & Olivier Meunier and contributors. All + * rights reserved. + * + * DotClear is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * DotClear is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with DotClear; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * ***** END LICENSE BLOCK ***** +*/ + +/* Modified by JP LANG for textile formatting */ + +function jsToolBar(textarea) { + if (!document.createElement) { return; } + + if (!textarea) { return; } + + if ((typeof(document["selection"]) == "undefined") + && (typeof(textarea["setSelectionRange"]) == "undefined")) { + return; + } + + this.textarea = textarea; + + this.editor = document.createElement('div'); + this.editor.className = 'jstEditor'; + + this.textarea.parentNode.insertBefore(this.editor,this.textarea); + this.editor.appendChild(this.textarea); + + this.toolbar = document.createElement("div"); + this.toolbar.className = 'jstElements'; + this.editor.parentNode.insertBefore(this.toolbar,this.editor); + + // Dragable resizing + if (this.editor.addEventListener && navigator.appVersion.match(/\bMSIE\b/)) + { + this.handle = document.createElement('div'); + this.handle.className = 'jstHandle'; + var dragStart = this.resizeDragStart; + var This = this; + this.handle.addEventListener('mousedown',function(event) { dragStart.call(This,event); },false); + // fix memory leak in Firefox (bug #241518) + window.addEventListener('unload',function() { + var del = This.handle.parentNode.removeChild(This.handle); + delete(This.handle); + },false); + + this.editor.parentNode.insertBefore(this.handle,this.editor.nextSibling); + } + + this.context = null; + this.toolNodes = {}; // lorsque la toolbar est dessinée , cet objet est garni + // de raccourcis vers les éléments DOM correspondants aux outils. +} + +function jsButton(title, fn, scope, className) { + if(typeof jsToolBar.strings == 'undefined') { + this.title = title || null; + } else { + this.title = jsToolBar.strings[title] || title || null; + } + this.fn = fn || function(){}; + this.scope = scope || null; + this.className = className || null; +} +jsButton.prototype.draw = function() { + if (!this.scope) return null; + + var button = document.createElement('button'); + button.setAttribute('type','button'); + button.tabIndex = 200; + if (this.className) button.className = this.className; + button.title = this.title; + var span = document.createElement('span'); + span.appendChild(document.createTextNode(this.title)); + button.appendChild(span); + + if (this.icon != undefined) { + button.style.backgroundImage = 'url('+this.icon+')'; + } + if (typeof(this.fn) == 'function') { + var This = this; + button.onclick = function() { try { This.fn.apply(This.scope, arguments) } catch (e) {} return false; }; + } + return button; +} + +function jsSpace(id) { + this.id = id || null; + this.width = null; +} +jsSpace.prototype.draw = function() { + var span = document.createElement('span'); + if (this.id) span.id = this.id; + span.appendChild(document.createTextNode(String.fromCharCode(160))); + span.className = 'jstSpacer'; + if (this.width) span.style.marginRight = this.width+'px'; + + return span; +} + +function jsCombo(title, options, scope, fn, className) { + this.title = title || null; + this.options = options || null; + this.scope = scope || null; + this.fn = fn || function(){}; + this.className = className || null; +} +jsCombo.prototype.draw = function() { + if (!this.scope || !this.options) return null; + + var select = document.createElement('select'); + if (this.className) select.className = className; + select.title = this.title; + + for (var o in this.options) { + //var opt = this.options[o]; + var option = document.createElement('option'); + option.value = o; + option.appendChild(document.createTextNode(this.options[o])); + select.appendChild(option); + } + + var This = this; + select.onchange = function() { + try { + This.fn.call(This.scope, this.value); + } catch (e) { alert(e); } + + return false; + } + + return select; +} + + +jsToolBar.prototype = { + base_url: '', + mode: 'wiki', + elements: {}, + help_link: '', + + getMode: function() { + return this.mode; + }, + + setMode: function(mode) { + this.mode = mode || 'wiki'; + }, + + switchMode: function(mode) { + mode = mode || 'wiki'; + this.draw(mode); + }, + + setHelpLink: function(link) { + this.help_link = link; + }, + + button: function(toolName) { + var tool = this.elements[toolName]; + if (typeof tool.fn[this.mode] != 'function') return null; + var b = new jsButton(tool.title, tool.fn[this.mode], this, 'jstb_'+toolName); + if (tool.icon != undefined) b.icon = tool.icon; + return b; + }, + space: function(toolName) { + var tool = new jsSpace(toolName) + if (this.elements[toolName].width !== undefined) + tool.width = this.elements[toolName].width; + return tool; + }, + combo: function(toolName) { + var tool = this.elements[toolName]; + var length = tool[this.mode].list.length; + + if (typeof tool[this.mode].fn != 'function' || length == 0) { + return null; + } else { + var options = {}; + for (var i=0; i < length; i++) { + var opt = tool[this.mode].list[i]; + options[opt] = tool.options[opt]; + } + return new jsCombo(tool.title, options, this, tool[this.mode].fn); + } + }, + draw: function(mode) { + this.setMode(mode); + + // Empty toolbar + while (this.toolbar.hasChildNodes()) { + this.toolbar.removeChild(this.toolbar.firstChild) + } + this.toolNodes = {}; // vide les raccourcis DOM/**/ + + // Draw toolbar elements + var b, tool, newTool; + + for (var i in this.elements) { + b = this.elements[i]; + + var disabled = + b.type == undefined || b.type == '' + || (b.disabled != undefined && b.disabled) + || (b.context != undefined && b.context != null && b.context != this.context); + + if (!disabled && typeof this[b.type] == 'function') { + tool = this[b.type](i); + if (tool) newTool = tool.draw(); + if (newTool) { + this.toolNodes[i] = newTool; //mémorise l'accès DOM pour usage éventuel ultérieur + this.toolbar.appendChild(newTool); + } + } + } + }, + + singleTag: function(stag,etag) { + stag = stag || null; + etag = etag || stag; + + if (!stag || !etag) { return; } + + this.encloseSelection(stag,etag); + }, + + encloseLineSelection: function(prefix, suffix, fn) { + this.textarea.focus(); + + prefix = prefix || ''; + suffix = suffix || ''; + + var start, end, sel, scrollPos, subst, res; + + if (typeof(document["selection"]) != "undefined") { + sel = document.selection.createRange().text; + } else if (typeof(this.textarea["setSelectionRange"]) != "undefined") { + start = this.textarea.selectionStart; + end = this.textarea.selectionEnd; + scrollPos = this.textarea.scrollTop; + // go to the start of the line + start = this.textarea.value.substring(0, start).replace(/[^\r\n]*$/g,'').length; + // go to the end of the line + end = this.textarea.value.length - this.textarea.value.substring(end, this.textarea.value.length).replace(/^[^\r\n]*/, '').length; + sel = this.textarea.value.substring(start, end); + } + + if (sel.match(/ $/)) { // exclude ending space char, if any + sel = sel.substring(0, sel.length - 1); + suffix = suffix + " "; + } + + if (typeof(fn) == 'function') { + res = (sel) ? fn.call(this,sel) : fn(''); + } else { + res = (sel) ? sel : ''; + } + + subst = prefix + res + suffix; + + if (typeof(document["selection"]) != "undefined") { + document.selection.createRange().text = subst; + var range = this.textarea.createTextRange(); + range.collapse(false); + range.move('character', -suffix.length); + range.select(); + } else if (typeof(this.textarea["setSelectionRange"]) != "undefined") { + this.textarea.value = this.textarea.value.substring(0, start) + subst + + this.textarea.value.substring(end); + if (sel) { + this.textarea.setSelectionRange(start + subst.length, start + subst.length); + } else { + this.textarea.setSelectionRange(start + prefix.length, start + prefix.length); + } + this.textarea.scrollTop = scrollPos; + } + }, + + encloseSelection: function(prefix, suffix, fn) { + this.textarea.focus(); + + prefix = prefix || ''; + suffix = suffix || ''; + + var start, end, sel, scrollPos, subst, res; + + if (typeof(document["selection"]) != "undefined") { + sel = document.selection.createRange().text; + } else if (typeof(this.textarea["setSelectionRange"]) != "undefined") { + start = this.textarea.selectionStart; + end = this.textarea.selectionEnd; + scrollPos = this.textarea.scrollTop; + sel = this.textarea.value.substring(start, end); + } + + if (sel.match(/ $/)) { // exclude ending space char, if any + sel = sel.substring(0, sel.length - 1); + suffix = suffix + " "; + } + + if (typeof(fn) == 'function') { + res = (sel) ? fn.call(this,sel) : fn(''); + } else { + res = (sel) ? sel : ''; + } + + subst = prefix + res + suffix; + + if (typeof(document["selection"]) != "undefined") { + document.selection.createRange().text = subst; + var range = this.textarea.createTextRange(); + range.collapse(false); + range.move('character', -suffix.length); + range.select(); +// this.textarea.caretPos -= suffix.length; + } else if (typeof(this.textarea["setSelectionRange"]) != "undefined") { + this.textarea.value = this.textarea.value.substring(0, start) + subst + + this.textarea.value.substring(end); + if (sel) { + this.textarea.setSelectionRange(start + subst.length, start + subst.length); + } else { + this.textarea.setSelectionRange(start + prefix.length, start + prefix.length); + } + this.textarea.scrollTop = scrollPos; + } + }, + + stripBaseURL: function(url) { + if (this.base_url != '') { + var pos = url.indexOf(this.base_url); + if (pos == 0) { + url = url.substr(this.base_url.length); + } + } + + return url; + } +}; + +/** Resizer +-------------------------------------------------------- */ +jsToolBar.prototype.resizeSetStartH = function() { + this.dragStartH = this.textarea.offsetHeight + 0; +}; +jsToolBar.prototype.resizeDragStart = function(event) { + var This = this; + this.dragStartY = event.clientY; + this.resizeSetStartH(); + document.addEventListener('mousemove', this.dragMoveHdlr=function(event){This.resizeDragMove(event);}, false); + document.addEventListener('mouseup', this.dragStopHdlr=function(event){This.resizeDragStop(event);}, false); +}; + +jsToolBar.prototype.resizeDragMove = function(event) { + this.textarea.style.height = (this.dragStartH+event.clientY-this.dragStartY)+'px'; +}; + +jsToolBar.prototype.resizeDragStop = function(event) { + document.removeEventListener('mousemove', this.dragMoveHdlr, false); + document.removeEventListener('mouseup', this.dragStopHdlr, false); +}; diff --git a/public/javascripts/jstoolbar/lang/jstoolbar-ar.js b/public/javascripts/jstoolbar/lang/jstoolbar-ar.js new file mode 100644 index 00000000..740312b0 --- /dev/null +++ b/public/javascripts/jstoolbar/lang/jstoolbar-ar.js @@ -0,0 +1,16 @@ +jsToolBar.strings = {}; +jsToolBar.strings ['Strong'] = 'قوي'; +jsToolBar.strings ['Italic'] = 'مائل'; +jsToolBar.strings ['Underline'] = 'تسطير'; +jsToolBar.strings ['Deleted'] = 'محذوف'; +jsToolBar.strings ['Code'] = 'رمز ضمني'; +jsToolBar.strings ['Heading 1'] = 'عنوان 1'; +jsToolBar.strings ['Heading 2'] = 'عنوان 2'; +jsToolBar.strings ['Heading 3'] = 'عنوان 3'; +jsToolBar.strings ['Unordered list'] = 'قائمة غير مرتبة'; +jsToolBar.strings ['Ordered list'] = 'قائمة مرتبة'; +jsToolBar.strings ['Quote'] = 'اقتباس'; +jsToolBar.strings ['Unquote'] = 'إزالة الاقتباس'; +jsToolBar.strings ['Preformatted text'] = 'نص مسبق التنسيق'; +jsToolBar.strings ['Wiki link'] = 'رابط الى صفحة ويكي'; +jsToolBar.strings ['Image'] = 'صورة'; diff --git a/public/javascripts/jstoolbar/lang/jstoolbar-az.js b/public/javascripts/jstoolbar/lang/jstoolbar-az.js new file mode 100644 index 00000000..2d68498f --- /dev/null +++ b/public/javascripts/jstoolbar/lang/jstoolbar-az.js @@ -0,0 +1,16 @@ +jsToolBar.strings = {}; +jsToolBar.strings['Strong'] = 'Strong'; +jsToolBar.strings['Italic'] = 'Italic'; +jsToolBar.strings['Underline'] = 'Underline'; +jsToolBar.strings['Deleted'] = 'Deleted'; +jsToolBar.strings['Code'] = 'Inline Code'; +jsToolBar.strings['Heading 1'] = 'Heading 1'; +jsToolBar.strings['Heading 2'] = 'Heading 2'; +jsToolBar.strings['Heading 3'] = 'Heading 3'; +jsToolBar.strings['Unordered list'] = 'Unordered list'; +jsToolBar.strings['Ordered list'] = 'Ordered list'; +jsToolBar.strings['Quote'] = 'Quote'; +jsToolBar.strings['Unquote'] = 'Remove Quote'; +jsToolBar.strings['Preformatted text'] = 'Preformatted text'; +jsToolBar.strings['Wiki link'] = 'Link to a Wiki page'; +jsToolBar.strings['Image'] = 'Image'; diff --git a/public/javascripts/jstoolbar/lang/jstoolbar-bg.js b/public/javascripts/jstoolbar/lang/jstoolbar-bg.js new file mode 100644 index 00000000..6c7b06d4 --- /dev/null +++ b/public/javascripts/jstoolbar/lang/jstoolbar-bg.js @@ -0,0 +1,16 @@ +jsToolBar.strings = {}; +jsToolBar.strings['Strong'] = 'Получер'; +jsToolBar.strings['Italic'] = 'Курсив'; +jsToolBar.strings['Underline'] = 'Подчертан'; +jsToolBar.strings['Deleted'] = 'Изтрит'; +jsToolBar.strings['Code'] = 'Вграден код'; +jsToolBar.strings['Heading 1'] = 'Заглавие 1'; +jsToolBar.strings['Heading 2'] = 'Заглавие 2'; +jsToolBar.strings['Heading 3'] = 'Заглавие 3'; +jsToolBar.strings['Unordered list'] = 'Неподреден списък'; +jsToolBar.strings['Ordered list'] = 'Подреден списък'; +jsToolBar.strings['Quote'] = 'Цитат'; +jsToolBar.strings['Unquote'] = 'Премахване на цитат'; +jsToolBar.strings['Preformatted text'] = 'Форматиран текст'; +jsToolBar.strings['Wiki link'] = 'Връзка до Wiki страница'; +jsToolBar.strings['Image'] = 'Изображение'; diff --git a/public/javascripts/jstoolbar/lang/jstoolbar-bs.js b/public/javascripts/jstoolbar/lang/jstoolbar-bs.js new file mode 100644 index 00000000..c9b67734 --- /dev/null +++ b/public/javascripts/jstoolbar/lang/jstoolbar-bs.js @@ -0,0 +1,14 @@ +jsToolBar.strings = {}; +jsToolBar.strings['Strong'] = 'Strong'; +jsToolBar.strings['Italic'] = 'Italic'; +jsToolBar.strings['Underline'] = 'Underline'; +jsToolBar.strings['Deleted'] = 'Deleted'; +jsToolBar.strings['Code'] = 'Inline Code'; +jsToolBar.strings['Heading 1'] = 'Heading 1'; +jsToolBar.strings['Heading 2'] = 'Heading 2'; +jsToolBar.strings['Heading 3'] = 'Heading 3'; +jsToolBar.strings['Unordered list'] = 'Unordered list'; +jsToolBar.strings['Ordered list'] = 'Ordered list'; +jsToolBar.strings['Preformatted text'] = 'Preformatted text'; +jsToolBar.strings['Wiki link'] = 'Link na Wiki stranicu'; +jsToolBar.strings['Image'] = 'Slika'; diff --git a/public/javascripts/jstoolbar/lang/jstoolbar-ca.js b/public/javascripts/jstoolbar/lang/jstoolbar-ca.js new file mode 100644 index 00000000..3d652a4a --- /dev/null +++ b/public/javascripts/jstoolbar/lang/jstoolbar-ca.js @@ -0,0 +1,16 @@ +jsToolBar.strings = {}; +jsToolBar.strings['Strong'] = 'Negreta'; +jsToolBar.strings['Italic'] = 'Cursiva'; +jsToolBar.strings['Underline'] = 'Subratllat'; +jsToolBar.strings['Deleted'] = 'Barrat'; +jsToolBar.strings['Code'] = 'Codi en línia'; +jsToolBar.strings['Heading 1'] = 'Encapçalament 1'; +jsToolBar.strings['Heading 2'] = 'Encapçalament 2'; +jsToolBar.strings['Heading 3'] = 'Encapçalament 3'; +jsToolBar.strings['Unordered list'] = 'Llista sense ordre'; +jsToolBar.strings['Ordered list'] = 'Llista ordenada'; +jsToolBar.strings['Quote'] = 'Cometes'; +jsToolBar.strings['Unquote'] = 'Sense cometes'; +jsToolBar.strings['Preformatted text'] = 'Text formatat'; +jsToolBar.strings['Wiki link'] = 'Enllaça a una pàgina Wiki'; +jsToolBar.strings['Image'] = 'Imatge'; diff --git a/public/javascripts/jstoolbar/lang/jstoolbar-cs.js b/public/javascripts/jstoolbar/lang/jstoolbar-cs.js new file mode 100644 index 00000000..f2c0dbff --- /dev/null +++ b/public/javascripts/jstoolbar/lang/jstoolbar-cs.js @@ -0,0 +1,16 @@ +jsToolBar.strings = {}; +jsToolBar.strings['Strong'] = 'Tučné'; +jsToolBar.strings['Italic'] = 'Kurzíva'; +jsToolBar.strings['Underline'] = 'Podtržené'; +jsToolBar.strings['Deleted'] = 'Přeškrtnuté '; +jsToolBar.strings['Code'] = 'Zobrazení kódu'; +jsToolBar.strings['Heading 1'] = 'Záhlaví 1'; +jsToolBar.strings['Heading 2'] = 'Záhlaví 2'; +jsToolBar.strings['Heading 3'] = 'Záhlaví 3'; +jsToolBar.strings['Unordered list'] = 'Seznam'; +jsToolBar.strings['Ordered list'] = 'Uspořádaný seznam'; +jsToolBar.strings['Quote'] = 'Quote'; +jsToolBar.strings['Unquote'] = 'Remove Quote'; +jsToolBar.strings['Preformatted text'] = 'Předformátovaný text'; +jsToolBar.strings['Wiki link'] = 'Vložit odkaz na Wiki stránku'; +jsToolBar.strings['Image'] = 'Vložit obrázek'; diff --git a/public/javascripts/jstoolbar/lang/jstoolbar-da.js b/public/javascripts/jstoolbar/lang/jstoolbar-da.js new file mode 100644 index 00000000..53b2c36f --- /dev/null +++ b/public/javascripts/jstoolbar/lang/jstoolbar-da.js @@ -0,0 +1,16 @@ +jsToolBar.strings = {}; +jsToolBar.strings['Strong'] = 'Fed'; +jsToolBar.strings['Italic'] = 'Kursiv'; +jsToolBar.strings['Underline'] = 'Understreget'; +jsToolBar.strings['Deleted'] = 'Slettet'; +jsToolBar.strings['Code'] = 'Inline-kode'; +jsToolBar.strings['Heading 1'] = 'Overskrift 1'; +jsToolBar.strings['Heading 2'] = 'Overskrift 2'; +jsToolBar.strings['Heading 3'] = 'Overskrift 3'; +jsToolBar.strings['Unordered list'] = 'Unummereret liste'; +jsToolBar.strings['Ordered list'] = 'Nummereret liste'; +jsToolBar.strings['Quote'] = 'Citér'; +jsToolBar.strings['Unquote'] = 'Fjern citér'; +jsToolBar.strings['Preformatted text'] = 'Præformateret tekst'; +jsToolBar.strings['Wiki link'] = 'Link til en wiki-side'; +jsToolBar.strings['Image'] = 'Billede'; diff --git a/public/javascripts/jstoolbar/lang/jstoolbar-de.js b/public/javascripts/jstoolbar/lang/jstoolbar-de.js new file mode 100644 index 00000000..ce686860 --- /dev/null +++ b/public/javascripts/jstoolbar/lang/jstoolbar-de.js @@ -0,0 +1,16 @@ +jsToolBar.strings = {}; +jsToolBar.strings['Strong'] = 'Fett'; +jsToolBar.strings['Italic'] = 'Kursiv'; +jsToolBar.strings['Underline'] = 'Unterstrichen'; +jsToolBar.strings['Deleted'] = 'Durchgestrichen'; +jsToolBar.strings['Code'] = 'Quelltext'; +jsToolBar.strings['Heading 1'] = 'Überschrift 1. Ordnung'; +jsToolBar.strings['Heading 2'] = 'Überschrift 2. Ordnung'; +jsToolBar.strings['Heading 3'] = 'Überschrift 3. Ordnung'; +jsToolBar.strings['Unordered list'] = 'Aufzählungsliste'; +jsToolBar.strings['Ordered list'] = 'Nummerierte Liste'; +jsToolBar.strings['Quote'] = 'Quote'; +jsToolBar.strings['Unquote'] = 'Remove Quote'; +jsToolBar.strings['Preformatted text'] = 'Präformatierter Text'; +jsToolBar.strings['Wiki link'] = 'Verweis (Link) zu einer Wiki-Seite'; +jsToolBar.strings['Image'] = 'Grafik'; diff --git a/public/javascripts/jstoolbar/lang/jstoolbar-en-gb.js b/public/javascripts/jstoolbar/lang/jstoolbar-en-gb.js new file mode 100644 index 00000000..2d68498f --- /dev/null +++ b/public/javascripts/jstoolbar/lang/jstoolbar-en-gb.js @@ -0,0 +1,16 @@ +jsToolBar.strings = {}; +jsToolBar.strings['Strong'] = 'Strong'; +jsToolBar.strings['Italic'] = 'Italic'; +jsToolBar.strings['Underline'] = 'Underline'; +jsToolBar.strings['Deleted'] = 'Deleted'; +jsToolBar.strings['Code'] = 'Inline Code'; +jsToolBar.strings['Heading 1'] = 'Heading 1'; +jsToolBar.strings['Heading 2'] = 'Heading 2'; +jsToolBar.strings['Heading 3'] = 'Heading 3'; +jsToolBar.strings['Unordered list'] = 'Unordered list'; +jsToolBar.strings['Ordered list'] = 'Ordered list'; +jsToolBar.strings['Quote'] = 'Quote'; +jsToolBar.strings['Unquote'] = 'Remove Quote'; +jsToolBar.strings['Preformatted text'] = 'Preformatted text'; +jsToolBar.strings['Wiki link'] = 'Link to a Wiki page'; +jsToolBar.strings['Image'] = 'Image'; diff --git a/public/javascripts/jstoolbar/lang/jstoolbar-en.js b/public/javascripts/jstoolbar/lang/jstoolbar-en.js new file mode 100644 index 00000000..2d68498f --- /dev/null +++ b/public/javascripts/jstoolbar/lang/jstoolbar-en.js @@ -0,0 +1,16 @@ +jsToolBar.strings = {}; +jsToolBar.strings['Strong'] = 'Strong'; +jsToolBar.strings['Italic'] = 'Italic'; +jsToolBar.strings['Underline'] = 'Underline'; +jsToolBar.strings['Deleted'] = 'Deleted'; +jsToolBar.strings['Code'] = 'Inline Code'; +jsToolBar.strings['Heading 1'] = 'Heading 1'; +jsToolBar.strings['Heading 2'] = 'Heading 2'; +jsToolBar.strings['Heading 3'] = 'Heading 3'; +jsToolBar.strings['Unordered list'] = 'Unordered list'; +jsToolBar.strings['Ordered list'] = 'Ordered list'; +jsToolBar.strings['Quote'] = 'Quote'; +jsToolBar.strings['Unquote'] = 'Remove Quote'; +jsToolBar.strings['Preformatted text'] = 'Preformatted text'; +jsToolBar.strings['Wiki link'] = 'Link to a Wiki page'; +jsToolBar.strings['Image'] = 'Image'; diff --git a/public/javascripts/jstoolbar/lang/jstoolbar-es.js b/public/javascripts/jstoolbar/lang/jstoolbar-es.js new file mode 100644 index 00000000..878489fb --- /dev/null +++ b/public/javascripts/jstoolbar/lang/jstoolbar-es.js @@ -0,0 +1,16 @@ +jsToolBar.strings = {}; +jsToolBar.strings['Strong'] = 'Negrita'; +jsToolBar.strings['Italic'] = 'Itálica'; +jsToolBar.strings['Underline'] = 'Subrayado'; +jsToolBar.strings['Deleted'] = 'Tachado'; +jsToolBar.strings['Code'] = 'Código fuente'; +jsToolBar.strings['Heading 1'] = 'Encabezado 1'; +jsToolBar.strings['Heading 2'] = 'Encabezado 2'; +jsToolBar.strings['Heading 3'] = 'Encabezado 3'; +jsToolBar.strings['Unordered list'] = 'Lista sin ordenar'; +jsToolBar.strings['Ordered list'] = 'Lista ordenada'; +jsToolBar.strings['Quote'] = 'Citar'; +jsToolBar.strings['Unquote'] = 'Quitar cita'; +jsToolBar.strings['Preformatted text'] = 'Texto con formato'; +jsToolBar.strings['Wiki link'] = 'Enlace a página Wiki'; +jsToolBar.strings['Image'] = 'Imagen'; diff --git a/public/javascripts/jstoolbar/lang/jstoolbar-et.js b/public/javascripts/jstoolbar/lang/jstoolbar-et.js new file mode 100644 index 00000000..aa0f16ab --- /dev/null +++ b/public/javascripts/jstoolbar/lang/jstoolbar-et.js @@ -0,0 +1,33 @@ +/* + Copyright (C) 2012 Kaitseministeerium + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +jsToolBar.strings = {}; +jsToolBar.strings['Strong'] = 'Rõhutatult'; +jsToolBar.strings['Italic'] = 'Kaldkirjas'; +jsToolBar.strings['Underline'] = 'Allakriipsutatult'; +jsToolBar.strings['Deleted'] = 'Läbikriipsutatult'; +jsToolBar.strings['Code'] = 'Koodiblokk'; +jsToolBar.strings['Heading 1'] = '1. taseme pealkiri'; +jsToolBar.strings['Heading 2'] = '2. taseme pealkiri'; +jsToolBar.strings['Heading 3'] = '3. taseme pealkiri'; +jsToolBar.strings['Unordered list'] = 'Täpitud nimekiri'; +jsToolBar.strings['Ordered list'] = 'Nummerdatud nimekiri'; +jsToolBar.strings['Quote'] = 'Tsitaat: aste juurde'; +jsToolBar.strings['Unquote'] = 'Tsitaat: aste madalamaks'; +jsToolBar.strings['Preformatted text'] = 'Eelvormindatud tekst'; +jsToolBar.strings['Wiki link'] = 'Vikilehe link'; +jsToolBar.strings['Image'] = 'Pilt'; diff --git a/public/javascripts/jstoolbar/lang/jstoolbar-eu.js b/public/javascripts/jstoolbar/lang/jstoolbar-eu.js new file mode 100644 index 00000000..3067fc8a --- /dev/null +++ b/public/javascripts/jstoolbar/lang/jstoolbar-eu.js @@ -0,0 +1,20 @@ +// jsToolBar EU language +// Author: Ales Zabala Alava (Shagi), +// 2010-01-25 +// Distributed under the same terms as the jsToolBar itself. +jsToolBar.strings = {}; +jsToolBar.strings['Strong'] = 'Lodia'; +jsToolBar.strings['Italic'] = 'Etzana'; +jsToolBar.strings['Underline'] = 'Azpimarra'; +jsToolBar.strings['Deleted'] = 'Ezabatuta'; +jsToolBar.strings['Code'] = 'Inline Code'; +jsToolBar.strings['Heading 1'] = '1 Goiburua'; +jsToolBar.strings['Heading 2'] = '2 Goiburua'; +jsToolBar.strings['Heading 3'] = '3 Goiburua'; +jsToolBar.strings['Unordered list'] = 'Ordenatu gabeko zerrenda'; +jsToolBar.strings['Ordered list'] = 'Ordenatutako zerrenda'; +jsToolBar.strings['Quote'] = 'Aipamena'; +jsToolBar.strings['Unquote'] = 'Aipamena kendu'; +jsToolBar.strings['Preformatted text'] = 'Aurrez formateatutako testua'; +jsToolBar.strings['Wiki link'] = 'Wiki orri baterako esteka'; +jsToolBar.strings['Image'] = 'Irudia'; diff --git a/public/javascripts/jstoolbar/lang/jstoolbar-fa.js b/public/javascripts/jstoolbar/lang/jstoolbar-fa.js new file mode 100644 index 00000000..61236bf6 --- /dev/null +++ b/public/javascripts/jstoolbar/lang/jstoolbar-fa.js @@ -0,0 +1,16 @@ +jsToolBar.strings = {}; +jsToolBar.strings['Strong'] = 'پررنگ'; +jsToolBar.strings['Italic'] = 'کج'; +jsToolBar.strings['Underline'] = 'زیرخط'; +jsToolBar.strings['Deleted'] = 'برداشته شده'; +jsToolBar.strings['Code'] = 'کد درون خطی'; +jsToolBar.strings['Heading 1'] = 'سربرگ ۱'; +jsToolBar.strings['Heading 2'] = 'سربرگ ۲'; +jsToolBar.strings['Heading 3'] = 'سربرگ ۳'; +jsToolBar.strings['Unordered list'] = 'فهرست بدون شماره'; +jsToolBar.strings['Ordered list'] = 'فهرست با شماره'; +jsToolBar.strings['Quote'] = 'تو بردن'; +jsToolBar.strings['Unquote'] = 'بیرون آوردن'; +jsToolBar.strings['Preformatted text'] = 'نوشته قالب بندی شده'; +jsToolBar.strings['Wiki link'] = 'پیوند به برگ ویکی'; +jsToolBar.strings['Image'] = 'عکس'; diff --git a/public/javascripts/jstoolbar/lang/jstoolbar-fi.js b/public/javascripts/jstoolbar/lang/jstoolbar-fi.js new file mode 100644 index 00000000..c2229b28 --- /dev/null +++ b/public/javascripts/jstoolbar/lang/jstoolbar-fi.js @@ -0,0 +1,16 @@ +jsToolBar.strings = {}; +jsToolBar.strings['Strong'] = 'Lihavoitu'; +jsToolBar.strings['Italic'] = 'Kursivoitu'; +jsToolBar.strings['Underline'] = 'Alleviivattu'; +jsToolBar.strings['Deleted'] = 'Yliviivattu'; +jsToolBar.strings['Code'] = 'Koodi näkymä'; +jsToolBar.strings['Heading 1'] = 'Otsikko 1'; +jsToolBar.strings['Heading 2'] = 'Otsikko 2'; +jsToolBar.strings['Heading 3'] = 'Otsikko 3'; +jsToolBar.strings['Unordered list'] = 'Järjestämätön lista'; +jsToolBar.strings['Ordered list'] = 'Järjestetty lista'; +jsToolBar.strings['Quote'] = 'Quote'; +jsToolBar.strings['Unquote'] = 'Remove Quote'; +jsToolBar.strings['Preformatted text'] = 'Ennaltamuotoiltu teksti'; +jsToolBar.strings['Wiki link'] = 'Linkki Wiki sivulle'; +jsToolBar.strings['Image'] = 'Kuva'; diff --git a/public/javascripts/jstoolbar/lang/jstoolbar-fr.js b/public/javascripts/jstoolbar/lang/jstoolbar-fr.js new file mode 100644 index 00000000..c52a783b --- /dev/null +++ b/public/javascripts/jstoolbar/lang/jstoolbar-fr.js @@ -0,0 +1,16 @@ +jsToolBar.strings = {}; +jsToolBar.strings['Strong'] = 'Gras'; +jsToolBar.strings['Italic'] = 'Italique'; +jsToolBar.strings['Underline'] = 'Souligné'; +jsToolBar.strings['Deleted'] = 'Rayé'; +jsToolBar.strings['Code'] = 'Code en ligne'; +jsToolBar.strings['Heading 1'] = 'Titre niveau 1'; +jsToolBar.strings['Heading 2'] = 'Titre niveau 2'; +jsToolBar.strings['Heading 3'] = 'Titre niveau 3'; +jsToolBar.strings['Unordered list'] = 'Liste à puces'; +jsToolBar.strings['Ordered list'] = 'Liste numérotée'; +jsToolBar.strings['Quote'] = 'Citer'; +jsToolBar.strings['Unquote'] = 'Supprimer citation'; +jsToolBar.strings['Preformatted text'] = 'Texte préformaté'; +jsToolBar.strings['Wiki link'] = 'Lien vers une page Wiki'; +jsToolBar.strings['Image'] = 'Image'; diff --git a/public/javascripts/jstoolbar/lang/jstoolbar-gl.js b/public/javascripts/jstoolbar/lang/jstoolbar-gl.js new file mode 100644 index 00000000..bd1462ae --- /dev/null +++ b/public/javascripts/jstoolbar/lang/jstoolbar-gl.js @@ -0,0 +1,16 @@ +jsToolBar.strings = {}; +jsToolBar.strings['Strong'] = 'Negriña'; +jsToolBar.strings['Italic'] = 'Itálica'; +jsToolBar.strings['Underline'] = 'Suliñado'; +jsToolBar.strings['Deleted'] = 'Tachado'; +jsToolBar.strings['Code'] = 'Código fonte'; +jsToolBar.strings['Heading 1'] = 'Encabezado 1'; +jsToolBar.strings['Heading 2'] = 'Encabezado 2'; +jsToolBar.strings['Heading 3'] = 'Encabezado 3'; +jsToolBar.strings['Unordered list'] = 'Lista sen ordenar'; +jsToolBar.strings['Ordered list'] = 'Lista ordenada'; +jsToolBar.strings['Quote'] = 'Citar'; +jsToolBar.strings['Unquote'] = 'Quitar cita'; +jsToolBar.strings['Preformatted text'] = 'Texto con formato'; +jsToolBar.strings['Wiki link'] = 'Enlace a páxina Wiki'; +jsToolBar.strings['Image'] = 'Imaxe'; diff --git a/public/javascripts/jstoolbar/lang/jstoolbar-he.js b/public/javascripts/jstoolbar/lang/jstoolbar-he.js new file mode 100644 index 00000000..2d68498f --- /dev/null +++ b/public/javascripts/jstoolbar/lang/jstoolbar-he.js @@ -0,0 +1,16 @@ +jsToolBar.strings = {}; +jsToolBar.strings['Strong'] = 'Strong'; +jsToolBar.strings['Italic'] = 'Italic'; +jsToolBar.strings['Underline'] = 'Underline'; +jsToolBar.strings['Deleted'] = 'Deleted'; +jsToolBar.strings['Code'] = 'Inline Code'; +jsToolBar.strings['Heading 1'] = 'Heading 1'; +jsToolBar.strings['Heading 2'] = 'Heading 2'; +jsToolBar.strings['Heading 3'] = 'Heading 3'; +jsToolBar.strings['Unordered list'] = 'Unordered list'; +jsToolBar.strings['Ordered list'] = 'Ordered list'; +jsToolBar.strings['Quote'] = 'Quote'; +jsToolBar.strings['Unquote'] = 'Remove Quote'; +jsToolBar.strings['Preformatted text'] = 'Preformatted text'; +jsToolBar.strings['Wiki link'] = 'Link to a Wiki page'; +jsToolBar.strings['Image'] = 'Image'; diff --git a/public/javascripts/jstoolbar/lang/jstoolbar-hr.js b/public/javascripts/jstoolbar/lang/jstoolbar-hr.js new file mode 100644 index 00000000..578ae7c0 --- /dev/null +++ b/public/javascripts/jstoolbar/lang/jstoolbar-hr.js @@ -0,0 +1,16 @@ +jsToolBar.strings = {}; +jsToolBar.strings['Strong'] = 'Podebljano'; +jsToolBar.strings['Italic'] = 'Kurziv'; +jsToolBar.strings['Underline'] = 'Podcrtano'; +jsToolBar.strings['Deleted'] = 'Obrisano'; +jsToolBar.strings['Code'] = 'Inline Code'; +jsToolBar.strings['Heading 1'] = 'Naslov 1'; +jsToolBar.strings['Heading 2'] = 'Naslov 2'; +jsToolBar.strings['Heading 3'] = 'Naslov 3'; +jsToolBar.strings['Unordered list'] = 'Graficke oznake'; +jsToolBar.strings['Ordered list'] = 'Numeriranje'; +jsToolBar.strings['Quote'] = 'Citat'; +jsToolBar.strings['Unquote'] = 'Ukloni citat'; +jsToolBar.strings['Preformatted text'] = 'Izveden tekst'; +jsToolBar.strings['Wiki link'] = 'Link na Wiki stranicu'; +jsToolBar.strings['Image'] = 'Slika'; \ No newline at end of file diff --git a/public/javascripts/jstoolbar/lang/jstoolbar-hu.js b/public/javascripts/jstoolbar/lang/jstoolbar-hu.js new file mode 100644 index 00000000..c31ba00c --- /dev/null +++ b/public/javascripts/jstoolbar/lang/jstoolbar-hu.js @@ -0,0 +1,16 @@ +jsToolBar.strings = {}; +jsToolBar.strings['Strong'] = 'Félkövér'; +jsToolBar.strings['Italic'] = 'Dőlt'; +jsToolBar.strings['Underline'] = 'Aláhúzott'; +jsToolBar.strings['Deleted'] = 'Törölt'; +jsToolBar.strings['Code'] = 'Kód sorok'; +jsToolBar.strings['Heading 1'] = 'Fejléc 1'; +jsToolBar.strings['Heading 2'] = 'Fejléc 2'; +jsToolBar.strings['Heading 3'] = 'Fejléc 3'; +jsToolBar.strings['Unordered list'] = 'Felsorolás'; +jsToolBar.strings['Ordered list'] = 'Számozott lista'; +jsToolBar.strings['Quote'] = 'Quote'; +jsToolBar.strings['Unquote'] = 'Remove Quote'; +jsToolBar.strings['Preformatted text'] = 'Előreformázott szöveg'; +jsToolBar.strings['Wiki link'] = 'Link egy Wiki oldalra'; +jsToolBar.strings['Image'] = 'Kép'; diff --git a/public/javascripts/jstoolbar/lang/jstoolbar-id.js b/public/javascripts/jstoolbar/lang/jstoolbar-id.js new file mode 100644 index 00000000..cca978ad --- /dev/null +++ b/public/javascripts/jstoolbar/lang/jstoolbar-id.js @@ -0,0 +1,16 @@ +jsToolBar.strings = {}; +jsToolBar.strings['Strong'] = 'Tebal'; +jsToolBar.strings['Italic'] = 'Miring'; +jsToolBar.strings['Underline'] = 'Garis bawah'; +jsToolBar.strings['Deleted'] = 'Dihapus'; +jsToolBar.strings['Code'] = 'Inline Code'; +jsToolBar.strings['Heading 1'] = 'Judul 1'; +jsToolBar.strings['Heading 2'] = 'Judul 2'; +jsToolBar.strings['Heading 3'] = 'Judul 3'; +jsToolBar.strings['Unordered list'] = 'Daftar tak terurut'; +jsToolBar.strings['Ordered list'] = 'Daftar terurut'; +jsToolBar.strings['Quote'] = 'Kutipan'; +jsToolBar.strings['Unquote'] = 'Hapus kutipan'; +jsToolBar.strings['Preformatted text'] = 'Teks terformat'; +jsToolBar.strings['Wiki link'] = 'Tautkan ke halaman wiki'; +jsToolBar.strings['Image'] = 'Gambar'; diff --git a/public/javascripts/jstoolbar/lang/jstoolbar-it.js b/public/javascripts/jstoolbar/lang/jstoolbar-it.js new file mode 100644 index 00000000..99749b40 --- /dev/null +++ b/public/javascripts/jstoolbar/lang/jstoolbar-it.js @@ -0,0 +1,19 @@ +// Italian translation +// by Diego Pierotto (ita.translations@tiscali.it) + +jsToolBar.strings = {}; +jsToolBar.strings['Strong'] = 'Grassetto'; +jsToolBar.strings['Italic'] = 'Corsivo'; +jsToolBar.strings['Underline'] = 'Sottolineato'; +jsToolBar.strings['Deleted'] = 'Barrato'; +jsToolBar.strings['Code'] = 'Codice sorgente'; +jsToolBar.strings['Heading 1'] = 'Titolo 1'; +jsToolBar.strings['Heading 2'] = 'Titolo 2'; +jsToolBar.strings['Heading 3'] = 'Titolo 3'; +jsToolBar.strings['Unordered list'] = 'Elenco puntato'; +jsToolBar.strings['Ordered list'] = 'Elenco numerato'; +jsToolBar.strings['Quote'] = 'Aumenta rientro'; +jsToolBar.strings['Unquote'] = 'Riduci rientro'; +jsToolBar.strings['Preformatted text'] = 'Testo preformattato'; +jsToolBar.strings['Wiki link'] = 'Collegamento a pagina Wiki'; +jsToolBar.strings['Image'] = 'Immagine'; diff --git a/public/javascripts/jstoolbar/lang/jstoolbar-ja.js b/public/javascripts/jstoolbar/lang/jstoolbar-ja.js new file mode 100644 index 00000000..0073271e --- /dev/null +++ b/public/javascripts/jstoolbar/lang/jstoolbar-ja.js @@ -0,0 +1,16 @@ +jsToolBar.strings = {}; +jsToolBar.strings['Strong'] = '強調'; +jsToolBar.strings['Italic'] = '斜体'; +jsToolBar.strings['Underline'] = '下線'; +jsToolBar.strings['Deleted'] = '取り消し線'; +jsToolBar.strings['Code'] = 'コード'; +jsToolBar.strings['Heading 1'] = '見出し 1'; +jsToolBar.strings['Heading 2'] = '見出し 2'; +jsToolBar.strings['Heading 3'] = '見出し 3'; +jsToolBar.strings['Unordered list'] = '順不同リスト'; +jsToolBar.strings['Ordered list'] = '番号つきリスト'; +jsToolBar.strings['Quote'] = '引用'; +jsToolBar.strings['Unquote'] = '引用解除'; +jsToolBar.strings['Preformatted text'] = '整形済みテキスト'; +jsToolBar.strings['Wiki link'] = 'Wikiページへのリンク'; +jsToolBar.strings['Image'] = '画像'; diff --git a/public/javascripts/jstoolbar/lang/jstoolbar-ko.js b/public/javascripts/jstoolbar/lang/jstoolbar-ko.js new file mode 100644 index 00000000..1c437ef7 --- /dev/null +++ b/public/javascripts/jstoolbar/lang/jstoolbar-ko.js @@ -0,0 +1,16 @@ +jsToolBar.strings = {}; +jsToolBar.strings['Strong'] = '굵게'; +jsToolBar.strings['Italic'] = '기울임'; +jsToolBar.strings['Underline'] = '밑줄'; +jsToolBar.strings['Deleted'] = '취소선'; +jsToolBar.strings['Code'] = '코드'; +jsToolBar.strings['Heading 1'] = '제목 1'; +jsToolBar.strings['Heading 2'] = '제목 2'; +jsToolBar.strings['Heading 3'] = '제목 3'; +jsToolBar.strings['Unordered list'] = '글머리 기호'; +jsToolBar.strings['Ordered list'] = '번호 매기기'; +jsToolBar.strings['Quote'] = '인용'; +jsToolBar.strings['Unquote'] = '인용 취소'; +jsToolBar.strings['Preformatted text'] = '있는 그대로 표현 (Preformatted text)'; +jsToolBar.strings['Wiki link'] = 'Wiki 페이지에 연결'; +jsToolBar.strings['Image'] = '그림'; diff --git a/public/javascripts/jstoolbar/lang/jstoolbar-lt.js b/public/javascripts/jstoolbar/lang/jstoolbar-lt.js new file mode 100644 index 00000000..29d8ec4a --- /dev/null +++ b/public/javascripts/jstoolbar/lang/jstoolbar-lt.js @@ -0,0 +1,16 @@ +jsToolBar.strings = {}; +jsToolBar.strings['Strong'] = 'Pastorinti'; +jsToolBar.strings['Italic'] = 'Italic'; +jsToolBar.strings['Underline'] = 'Pabraukti'; +jsToolBar.strings['Deleted'] = 'Užbraukti'; +jsToolBar.strings['Code'] = 'Kodas'; +jsToolBar.strings['Heading 1'] = 'Heading 1'; +jsToolBar.strings['Heading 2'] = 'Heading 2'; +jsToolBar.strings['Heading 3'] = 'Heading 3'; +jsToolBar.strings['Unordered list'] = 'Nenumeruotas sąrašas'; +jsToolBar.strings['Ordered list'] = 'Numeruotas sąrašas'; +jsToolBar.strings['Quote'] = 'Cituoti'; +jsToolBar.strings['Unquote'] = 'Pašalinti citavimą'; +jsToolBar.strings['Preformatted text'] = 'Preformatuotas tekstas'; +jsToolBar.strings['Wiki link'] = 'Nuoroda į Wiki puslapį'; +jsToolBar.strings['Image'] = 'Paveikslas'; diff --git a/public/javascripts/jstoolbar/lang/jstoolbar-lv.js b/public/javascripts/jstoolbar/lang/jstoolbar-lv.js new file mode 100644 index 00000000..b8215004 --- /dev/null +++ b/public/javascripts/jstoolbar/lang/jstoolbar-lv.js @@ -0,0 +1,17 @@ +// translated by Dzintars Bergs (dzintars.bergs@gmail.com) +jsToolBar.strings = {}; +jsToolBar.strings['Strong'] = 'Treknraksts'; +jsToolBar.strings['Italic'] = 'Slīpraksts'; +jsToolBar.strings['Underline'] = 'Pasvītrojums'; +jsToolBar.strings['Deleted'] = 'Dzēsts'; +jsToolBar.strings['Code'] = 'Iekļauts kods'; +jsToolBar.strings['Heading 1'] = 'Virsraksts 1'; +jsToolBar.strings['Heading 2'] = 'Virsraksts 2'; +jsToolBar.strings['Heading 3'] = 'Virsraksts 3'; +jsToolBar.strings['Unordered list'] = 'Nesakārtots saraksts'; +jsToolBar.strings['Ordered list'] = 'Sakārtots saraksts'; +jsToolBar.strings['Quote'] = 'Citēt'; +jsToolBar.strings['Unquote'] = 'Noņemt citātu'; +jsToolBar.strings['Preformatted text'] = 'Iepriekš formatēts teksts'; +jsToolBar.strings['Wiki link'] = 'Saite uz Wiki lapu'; +jsToolBar.strings['Image'] = 'Attēls'; diff --git a/public/javascripts/jstoolbar/lang/jstoolbar-mk.js b/public/javascripts/jstoolbar/lang/jstoolbar-mk.js new file mode 100644 index 00000000..30c68ec6 --- /dev/null +++ b/public/javascripts/jstoolbar/lang/jstoolbar-mk.js @@ -0,0 +1,17 @@ +jsToolBar.strings = {}; +jsToolBar.strings['Strong'] = 'Задебелен'; +jsToolBar.strings['Italic'] = 'Закосен'; +jsToolBar.strings['Underline'] = 'Подвлечен'; +jsToolBar.strings['Deleted'] = 'Прецртан'; +jsToolBar.strings['Code'] = 'Код'; +jsToolBar.strings['Heading 1'] = 'Заглавје 1'; +jsToolBar.strings['Heading 2'] = 'Заглавје 2'; +jsToolBar.strings['Heading 3'] = 'Заглавје 3'; +jsToolBar.strings['Unordered list'] = 'Неподредена листа'; +jsToolBar.strings['Ordered list'] = 'Подредена листа'; +jsToolBar.strings['Quote'] = 'Цитат'; +jsToolBar.strings['Unquote'] = 'Отстрани цитат'; +jsToolBar.strings['Preformatted text'] = 'Форматиран текст'; +jsToolBar.strings['Wiki link'] = 'Врска до вики страна'; +jsToolBar.strings['Image'] = 'Слика'; + diff --git a/public/javascripts/jstoolbar/lang/jstoolbar-mn.js b/public/javascripts/jstoolbar/lang/jstoolbar-mn.js new file mode 100644 index 00000000..ef1da465 --- /dev/null +++ b/public/javascripts/jstoolbar/lang/jstoolbar-mn.js @@ -0,0 +1,16 @@ +jsToolBar.strings = {}; +jsToolBar.strings['Strong'] = 'Бүдүүн'; +jsToolBar.strings['Italic'] = 'Налуу'; +jsToolBar.strings['Underline'] = 'Доогуур зураас'; +jsToolBar.strings['Deleted'] = 'Устгагдсан'; +jsToolBar.strings['Code'] = 'Програмын код'; +jsToolBar.strings['Heading 1'] = 'Гарчиг 1'; +jsToolBar.strings['Heading 2'] = 'Гарчиг 2'; +jsToolBar.strings['Heading 3'] = 'Гарчиг 3'; +jsToolBar.strings['Unordered list'] = 'Эрэмбэгүй жагсаалт'; +jsToolBar.strings['Ordered list'] = 'Эрэмбэтэй жагсаалт'; +jsToolBar.strings['Quote'] = 'Ишлэл'; +jsToolBar.strings['Unquote'] = 'Ишлэлийг устгах'; +jsToolBar.strings['Preformatted text'] = 'Өмнө нь хэлбэржсэн текст'; +jsToolBar.strings['Wiki link'] = 'Вики хуудас руу холбох'; +jsToolBar.strings['Image'] = 'Зураг'; diff --git a/public/javascripts/jstoolbar/lang/jstoolbar-nl.js b/public/javascripts/jstoolbar/lang/jstoolbar-nl.js new file mode 100644 index 00000000..0c54163f --- /dev/null +++ b/public/javascripts/jstoolbar/lang/jstoolbar-nl.js @@ -0,0 +1,16 @@ +jsToolBar.strings = {}; +jsToolBar.strings['Strong'] = 'Extra nadruk'; +jsToolBar.strings['Italic'] = 'Cursief'; +jsToolBar.strings['Underline'] = 'Onderstreept'; +jsToolBar.strings['Deleted'] = 'Verwijderd'; +jsToolBar.strings['Code'] = 'Computercode'; +jsToolBar.strings['Heading 1'] = 'Kop 1'; +jsToolBar.strings['Heading 2'] = 'Kop 2'; +jsToolBar.strings['Heading 3'] = 'Kop 3'; +jsToolBar.strings['Unordered list'] = 'Ongeordende lijst'; +jsToolBar.strings['Ordered list'] = 'Geordende lijst'; +jsToolBar.strings['Quote'] = 'Citaat'; +jsToolBar.strings['Unquote'] = 'Verwijder citaat'; +jsToolBar.strings['Preformatted text'] = 'Voor-geformateerde tekst'; +jsToolBar.strings['Wiki link'] = 'Link naar een Wiki pagina'; +jsToolBar.strings['Image'] = 'Afbeelding'; diff --git a/public/javascripts/jstoolbar/lang/jstoolbar-no.js b/public/javascripts/jstoolbar/lang/jstoolbar-no.js new file mode 100644 index 00000000..79959734 --- /dev/null +++ b/public/javascripts/jstoolbar/lang/jstoolbar-no.js @@ -0,0 +1,16 @@ +jsToolBar.strings = {}; +jsToolBar.strings['Strong'] = 'Fet'; +jsToolBar.strings['Italic'] = 'Kursiv'; +jsToolBar.strings['Underline'] = 'Understreking'; +jsToolBar.strings['Deleted'] = 'Slettet'; +jsToolBar.strings['Code'] = 'Kode'; +jsToolBar.strings['Heading 1'] = 'Overskrift 1'; +jsToolBar.strings['Heading 2'] = 'Overskrift 2'; +jsToolBar.strings['Heading 3'] = 'Overskrift 3'; +jsToolBar.strings['Unordered list'] = 'Punktliste'; +jsToolBar.strings['Ordered list'] = 'Nummerert liste'; +jsToolBar.strings['Quote'] = 'Sitat'; +jsToolBar.strings['Unquote'] = 'Avslutt sitat'; +jsToolBar.strings['Preformatted text'] = 'Preformatert tekst'; +jsToolBar.strings['Wiki link'] = 'Lenke til Wiki-side'; +jsToolBar.strings['Image'] = 'Bilde'; diff --git a/public/javascripts/jstoolbar/lang/jstoolbar-pl.js b/public/javascripts/jstoolbar/lang/jstoolbar-pl.js new file mode 100644 index 00000000..0e7a38c9 --- /dev/null +++ b/public/javascripts/jstoolbar/lang/jstoolbar-pl.js @@ -0,0 +1,17 @@ +// Keep this line in order to avoid problems with Windows Notepad UTF-8 EF-BB-BF idea... +jsToolBar.strings = {}; +jsToolBar.strings['Strong'] = 'Pogrubienie'; +jsToolBar.strings['Italic'] = 'Kursywa'; +jsToolBar.strings['Underline'] = 'Podkreślenie'; +jsToolBar.strings['Deleted'] = 'Usunięte'; +jsToolBar.strings['Code'] = 'Wstawka kodu'; +jsToolBar.strings['Heading 1'] = 'Nagłowek 1'; +jsToolBar.strings['Heading 2'] = 'Nagłówek 2'; +jsToolBar.strings['Heading 3'] = 'Nagłówek 3'; +jsToolBar.strings['Unordered list'] = 'Nieposortowana lista'; +jsToolBar.strings['Ordered list'] = 'Posortowana lista'; +jsToolBar.strings['Quote'] = 'Cytat'; +jsToolBar.strings['Unquote'] = 'Usuń cytat'; +jsToolBar.strings['Preformatted text'] = 'Sformatowany tekst'; +jsToolBar.strings['Wiki link'] = 'Odnośnik do strony Wiki'; +jsToolBar.strings['Image'] = 'Obraz'; diff --git a/public/javascripts/jstoolbar/lang/jstoolbar-pt-br.js b/public/javascripts/jstoolbar/lang/jstoolbar-pt-br.js new file mode 100644 index 00000000..5035524a --- /dev/null +++ b/public/javascripts/jstoolbar/lang/jstoolbar-pt-br.js @@ -0,0 +1,18 @@ +// Translated by: Alexandre da Silva + +jsToolBar.strings = {}; +jsToolBar.strings['Strong'] = 'Negrito'; +jsToolBar.strings['Italic'] = 'Itálico'; +jsToolBar.strings['Underline'] = 'Sublinhado'; +jsToolBar.strings['Deleted'] = 'Excluído'; +jsToolBar.strings['Code'] = 'Código Inline'; +jsToolBar.strings['Heading 1'] = 'Cabeçalho 1'; +jsToolBar.strings['Heading 2'] = 'Cabeçalho 2'; +jsToolBar.strings['Heading 3'] = 'Cabeçalho 3'; +jsToolBar.strings['Unordered list'] = 'Lista não ordenada'; +jsToolBar.strings['Ordered list'] = 'Lista ordenada'; +jsToolBar.strings['Quote'] = 'Quote'; +jsToolBar.strings['Unquote'] = 'Remove Quote'; +jsToolBar.strings['Preformatted text'] = 'Texto pré-formatado'; +jsToolBar.strings['Wiki link'] = 'Link para uma página Wiki'; +jsToolBar.strings['Image'] = 'Imagem'; diff --git a/public/javascripts/jstoolbar/lang/jstoolbar-pt.js b/public/javascripts/jstoolbar/lang/jstoolbar-pt.js new file mode 100644 index 00000000..137d7952 --- /dev/null +++ b/public/javascripts/jstoolbar/lang/jstoolbar-pt.js @@ -0,0 +1,17 @@ +// Translated by: Pedro Araújo +jsToolBar.strings = {}; +jsToolBar.strings['Strong'] = 'Negrito'; +jsToolBar.strings['Italic'] = 'Itálico'; +jsToolBar.strings['Underline'] = 'Sublinhado'; +jsToolBar.strings['Deleted'] = 'Apagado'; +jsToolBar.strings['Code'] = 'Código Inline'; +jsToolBar.strings['Heading 1'] = 'Cabeçalho 1'; +jsToolBar.strings['Heading 2'] = 'Cabeçalho 2'; +jsToolBar.strings['Heading 3'] = 'Cabeçalho 3'; +jsToolBar.strings['Unordered list'] = 'Lista não ordenada'; +jsToolBar.strings['Ordered list'] = 'Lista ordenada'; +jsToolBar.strings['Quote'] = 'Citação'; +jsToolBar.strings['Unquote'] = 'Remover citação'; +jsToolBar.strings['Preformatted text'] = 'Texto pré-formatado'; +jsToolBar.strings['Wiki link'] = 'Link para uma página da Wiki'; +jsToolBar.strings['Image'] = 'Imagem'; diff --git a/public/javascripts/jstoolbar/lang/jstoolbar-ro.js b/public/javascripts/jstoolbar/lang/jstoolbar-ro.js new file mode 100644 index 00000000..fdaec4a2 --- /dev/null +++ b/public/javascripts/jstoolbar/lang/jstoolbar-ro.js @@ -0,0 +1,16 @@ +jsToolBar.strings = {}; +jsToolBar.strings['Strong'] = 'Bold'; +jsToolBar.strings['Italic'] = 'Italic'; +jsToolBar.strings['Underline'] = 'Subliniat'; +jsToolBar.strings['Deleted'] = 'Șters'; +jsToolBar.strings['Code'] = 'Fragment de cod'; +jsToolBar.strings['Heading 1'] = 'Heading 1'; +jsToolBar.strings['Heading 2'] = 'Heading 2'; +jsToolBar.strings['Heading 3'] = 'Heading 3'; +jsToolBar.strings['Unordered list'] = 'Listă pe puncte'; +jsToolBar.strings['Ordered list'] = 'Listă ordonată'; +jsToolBar.strings['Quote'] = 'Citează'; +jsToolBar.strings['Unquote'] = 'Fără citat'; +jsToolBar.strings['Preformatted text'] = 'Text preformatat'; +jsToolBar.strings['Wiki link'] = 'Trimitere către o pagină wiki'; +jsToolBar.strings['Image'] = 'Imagine'; diff --git a/public/javascripts/jstoolbar/lang/jstoolbar-ru.js b/public/javascripts/jstoolbar/lang/jstoolbar-ru.js new file mode 100644 index 00000000..f4c81013 --- /dev/null +++ b/public/javascripts/jstoolbar/lang/jstoolbar-ru.js @@ -0,0 +1,16 @@ +jsToolBar.strings = {}; +jsToolBar.strings['Strong'] = 'Жирный'; +jsToolBar.strings['Italic'] = 'Курсив'; +jsToolBar.strings['Underline'] = 'Подчеркнутый'; +jsToolBar.strings['Deleted'] = 'Зачеркнутый'; +jsToolBar.strings['Code'] = 'Вставка кода'; +jsToolBar.strings['Heading 1'] = 'Заголовок 1'; +jsToolBar.strings['Heading 2'] = 'Заголовок 2'; +jsToolBar.strings['Heading 3'] = 'Заголовок 3'; +jsToolBar.strings['Unordered list'] = 'Маркированный список'; +jsToolBar.strings['Ordered list'] = 'Нумерованный список'; +jsToolBar.strings['Quote'] = 'Цитата'; +jsToolBar.strings['Unquote'] = 'Удалить цитату'; +jsToolBar.strings['Preformatted text'] = 'Заранее форматированный текст'; +jsToolBar.strings['Wiki link'] = 'Ссылка на страницу в Wiki'; +jsToolBar.strings['Image'] = 'Вставка изображения'; diff --git a/public/javascripts/jstoolbar/lang/jstoolbar-sk.js b/public/javascripts/jstoolbar/lang/jstoolbar-sk.js new file mode 100644 index 00000000..0d47cd51 --- /dev/null +++ b/public/javascripts/jstoolbar/lang/jstoolbar-sk.js @@ -0,0 +1,16 @@ +jsToolBar.strings = {}; +jsToolBar.strings['Strong'] = 'Tučné'; +jsToolBar.strings['Italic'] = 'Kurzíva'; +jsToolBar.strings['Underline'] = 'Podčiarknuté'; +jsToolBar.strings['Deleted'] = 'Preškrtnuté'; +jsToolBar.strings['Code'] = 'Zobrazenie kódu'; +jsToolBar.strings['Heading 1'] = 'Záhlavie 1'; +jsToolBar.strings['Heading 2'] = 'Záhlavie 2'; +jsToolBar.strings['Heading 3'] = 'Záhlavie 3'; +jsToolBar.strings['Unordered list'] = 'Zoznam'; +jsToolBar.strings['Ordered list'] = 'Zoradený zoznam'; +jsToolBar.strings['Quote'] = 'Citácia'; +jsToolBar.strings['Unquote'] = 'Odstránenie citácie'; +jsToolBar.strings['Preformatted text'] = 'Predformátovaný text'; +jsToolBar.strings['Wiki link'] = 'Link na Wiki stránku'; +jsToolBar.strings['Image'] = 'Obrázok'; diff --git a/public/javascripts/jstoolbar/lang/jstoolbar-sl.js b/public/javascripts/jstoolbar/lang/jstoolbar-sl.js new file mode 100644 index 00000000..70949957 --- /dev/null +++ b/public/javascripts/jstoolbar/lang/jstoolbar-sl.js @@ -0,0 +1,16 @@ +jsToolBar.strings = {}; +jsToolBar.strings['Strong'] = 'Krepko'; +jsToolBar.strings['Italic'] = 'Poševno'; +jsToolBar.strings['Underline'] = 'Podčrtano'; +jsToolBar.strings['Deleted'] = 'Izbrisano'; +jsToolBar.strings['Code'] = 'Koda med vrsticami'; +jsToolBar.strings['Heading 1'] = 'Naslov 1'; +jsToolBar.strings['Heading 2'] = 'Naslov 2'; +jsToolBar.strings['Heading 3'] = 'Naslov 3'; +jsToolBar.strings['Unordered list'] = 'Neurejen seznam'; +jsToolBar.strings['Ordered list'] = 'Urejen seznam'; +jsToolBar.strings['Quote'] = 'Citat'; +jsToolBar.strings['Unquote'] = 'Odstrani citat'; +jsToolBar.strings['Preformatted text'] = 'Predoblikovano besedilo'; +jsToolBar.strings['Wiki link'] = 'Povezava na Wiki stran'; +jsToolBar.strings['Image'] = 'Slika'; diff --git a/public/javascripts/jstoolbar/lang/jstoolbar-sq.js b/public/javascripts/jstoolbar/lang/jstoolbar-sq.js new file mode 100644 index 00000000..2d68498f --- /dev/null +++ b/public/javascripts/jstoolbar/lang/jstoolbar-sq.js @@ -0,0 +1,16 @@ +jsToolBar.strings = {}; +jsToolBar.strings['Strong'] = 'Strong'; +jsToolBar.strings['Italic'] = 'Italic'; +jsToolBar.strings['Underline'] = 'Underline'; +jsToolBar.strings['Deleted'] = 'Deleted'; +jsToolBar.strings['Code'] = 'Inline Code'; +jsToolBar.strings['Heading 1'] = 'Heading 1'; +jsToolBar.strings['Heading 2'] = 'Heading 2'; +jsToolBar.strings['Heading 3'] = 'Heading 3'; +jsToolBar.strings['Unordered list'] = 'Unordered list'; +jsToolBar.strings['Ordered list'] = 'Ordered list'; +jsToolBar.strings['Quote'] = 'Quote'; +jsToolBar.strings['Unquote'] = 'Remove Quote'; +jsToolBar.strings['Preformatted text'] = 'Preformatted text'; +jsToolBar.strings['Wiki link'] = 'Link to a Wiki page'; +jsToolBar.strings['Image'] = 'Image'; diff --git a/public/javascripts/jstoolbar/lang/jstoolbar-sr-yu.js b/public/javascripts/jstoolbar/lang/jstoolbar-sr-yu.js new file mode 100644 index 00000000..0e231e02 --- /dev/null +++ b/public/javascripts/jstoolbar/lang/jstoolbar-sr-yu.js @@ -0,0 +1,16 @@ +jsToolBar.strings = {}; +jsToolBar.strings['Strong'] = 'Podebljano'; +jsToolBar.strings['Italic'] = 'Kurziv'; +jsToolBar.strings['Underline'] = 'Podvučeno'; +jsToolBar.strings['Deleted'] = 'Obrisano'; +jsToolBar.strings['Code'] = 'Ugrađeni kôd'; +jsToolBar.strings['Heading 1'] = 'Naslov 1'; +jsToolBar.strings['Heading 2'] = 'Naslov 2'; +jsToolBar.strings['Heading 3'] = 'Naslov 3'; +jsToolBar.strings['Unordered list'] = 'Lista nabrajanja'; +jsToolBar.strings['Ordered list'] = 'Uređena lista'; +jsToolBar.strings['Quote'] = 'Pod navodnicima'; +jsToolBar.strings['Unquote'] = 'Ukloni navodnike'; +jsToolBar.strings['Preformatted text'] = 'Prethodno formatiran tekst'; +jsToolBar.strings['Wiki link'] = 'Veza prema Wiki strani'; +jsToolBar.strings['Image'] = 'Slika'; diff --git a/public/javascripts/jstoolbar/lang/jstoolbar-sr.js b/public/javascripts/jstoolbar/lang/jstoolbar-sr.js new file mode 100644 index 00000000..75a768ad --- /dev/null +++ b/public/javascripts/jstoolbar/lang/jstoolbar-sr.js @@ -0,0 +1,16 @@ +jsToolBar.strings = {}; +jsToolBar.strings['Strong'] = 'Подебљано'; +jsToolBar.strings['Italic'] = 'Курзив'; +jsToolBar.strings['Underline'] = 'Подвучено'; +jsToolBar.strings['Deleted'] = 'Обрисано'; +jsToolBar.strings['Code'] = 'Уграђени кôд'; +jsToolBar.strings['Heading 1'] = 'Наслов 1'; +jsToolBar.strings['Heading 2'] = 'Наслов 2'; +jsToolBar.strings['Heading 3'] = 'Наслов 3'; +jsToolBar.strings['Unordered list'] = 'Листа набрајања'; +jsToolBar.strings['Ordered list'] = 'Уређена листа'; +jsToolBar.strings['Quote'] = 'Под наводницима'; +jsToolBar.strings['Unquote'] = 'Уклони наводнике'; +jsToolBar.strings['Preformatted text'] = 'Претходно форматиран текст'; +jsToolBar.strings['Wiki link'] = 'Веза према Wiki страни'; +jsToolBar.strings['Image'] = 'Слика'; diff --git a/public/javascripts/jstoolbar/lang/jstoolbar-sv.js b/public/javascripts/jstoolbar/lang/jstoolbar-sv.js new file mode 100644 index 00000000..08c0b69a --- /dev/null +++ b/public/javascripts/jstoolbar/lang/jstoolbar-sv.js @@ -0,0 +1,16 @@ +jsToolBar.strings = {}; +jsToolBar.strings['Strong'] = 'Fet'; +jsToolBar.strings['Italic'] = 'Kursiv'; +jsToolBar.strings['Underline'] = 'Understruken'; +jsToolBar.strings['Deleted'] = 'Genomstruken'; +jsToolBar.strings['Code'] = 'Kod'; +jsToolBar.strings['Heading 1'] = 'Rubrik 1'; +jsToolBar.strings['Heading 2'] = 'Rubrik 2'; +jsToolBar.strings['Heading 3'] = 'Rubrik 3'; +jsToolBar.strings['Unordered list'] = 'Osorterad lista'; +jsToolBar.strings['Ordered list'] = 'Sorterad lista'; +jsToolBar.strings['Quote'] = 'Citat'; +jsToolBar.strings['Unquote'] = 'Ta bort citat'; +jsToolBar.strings['Preformatted text'] = 'Förformaterad text'; +jsToolBar.strings['Wiki link'] = 'Länk till en wikisida'; +jsToolBar.strings['Image'] = 'Bild'; diff --git a/public/javascripts/jstoolbar/lang/jstoolbar-th.js b/public/javascripts/jstoolbar/lang/jstoolbar-th.js new file mode 100644 index 00000000..d8716422 --- /dev/null +++ b/public/javascripts/jstoolbar/lang/jstoolbar-th.js @@ -0,0 +1,16 @@ +jsToolBar.strings = {}; +jsToolBar.strings['Strong'] = 'หนา'; +jsToolBar.strings['Italic'] = 'เอียง'; +jsToolBar.strings['Underline'] = 'ขีดเส้นใต้'; +jsToolBar.strings['Deleted'] = 'ขีดฆ่า'; +jsToolBar.strings['Code'] = 'โค๊ดโปรแกรม'; +jsToolBar.strings['Heading 1'] = 'หัวข้อ 1'; +jsToolBar.strings['Heading 2'] = 'หัวข้อ 2'; +jsToolBar.strings['Heading 3'] = 'หัวข้อ 3'; +jsToolBar.strings['Unordered list'] = 'รายการ'; +jsToolBar.strings['Ordered list'] = 'ลำดับเลข'; +jsToolBar.strings['Quote'] = 'Quote'; +jsToolBar.strings['Unquote'] = 'Remove Quote'; +jsToolBar.strings['Preformatted text'] = 'รูปแบบข้อความคงที่'; +jsToolBar.strings['Wiki link'] = 'เชื่อมโยงไปหน้า Wiki อื่น'; +jsToolBar.strings['Image'] = 'รูปภาพ'; diff --git a/public/javascripts/jstoolbar/lang/jstoolbar-tr.js b/public/javascripts/jstoolbar/lang/jstoolbar-tr.js new file mode 100644 index 00000000..31705d7c --- /dev/null +++ b/public/javascripts/jstoolbar/lang/jstoolbar-tr.js @@ -0,0 +1,14 @@ +jsToolBar.strings = {}; +jsToolBar.strings['Strong'] = 'Kalın'; +jsToolBar.strings['Italic'] = 'İtalik'; +jsToolBar.strings['Underline'] = 'Altı çizgili'; +jsToolBar.strings['Deleted'] = 'Silinmiş'; +jsToolBar.strings['Code'] = 'Satır içi kod'; +jsToolBar.strings['Heading 1'] = 'Başlık 1'; +jsToolBar.strings['Heading 2'] = 'Başlık 2'; +jsToolBar.strings['Heading 3'] = 'Başlık 3'; +jsToolBar.strings['Unordered list'] = 'Sırasız liste'; +jsToolBar.strings['Ordered list'] = 'Sıralı liste'; +jsToolBar.strings['Preformatted text'] = 'Preformatted text'; +jsToolBar.strings['Wiki link'] = 'Wiki sayfasına bağlantı'; +jsToolBar.strings['Image'] = 'Resim'; diff --git a/public/javascripts/jstoolbar/lang/jstoolbar-uk.js b/public/javascripts/jstoolbar/lang/jstoolbar-uk.js new file mode 100644 index 00000000..2d68498f --- /dev/null +++ b/public/javascripts/jstoolbar/lang/jstoolbar-uk.js @@ -0,0 +1,16 @@ +jsToolBar.strings = {}; +jsToolBar.strings['Strong'] = 'Strong'; +jsToolBar.strings['Italic'] = 'Italic'; +jsToolBar.strings['Underline'] = 'Underline'; +jsToolBar.strings['Deleted'] = 'Deleted'; +jsToolBar.strings['Code'] = 'Inline Code'; +jsToolBar.strings['Heading 1'] = 'Heading 1'; +jsToolBar.strings['Heading 2'] = 'Heading 2'; +jsToolBar.strings['Heading 3'] = 'Heading 3'; +jsToolBar.strings['Unordered list'] = 'Unordered list'; +jsToolBar.strings['Ordered list'] = 'Ordered list'; +jsToolBar.strings['Quote'] = 'Quote'; +jsToolBar.strings['Unquote'] = 'Remove Quote'; +jsToolBar.strings['Preformatted text'] = 'Preformatted text'; +jsToolBar.strings['Wiki link'] = 'Link to a Wiki page'; +jsToolBar.strings['Image'] = 'Image'; diff --git a/public/javascripts/jstoolbar/lang/jstoolbar-vi.js b/public/javascripts/jstoolbar/lang/jstoolbar-vi.js new file mode 100644 index 00000000..f598bfe0 --- /dev/null +++ b/public/javascripts/jstoolbar/lang/jstoolbar-vi.js @@ -0,0 +1,16 @@ +jsToolBar.strings = {}; +jsToolBar.strings['Strong'] = 'Đậm'; +jsToolBar.strings['Italic'] = 'Nghiêng'; +jsToolBar.strings['Underline'] = 'Gạch chân'; +jsToolBar.strings['Deleted'] = 'Xóa'; +jsToolBar.strings['Code'] = 'Mã chung dòng'; +jsToolBar.strings['Heading 1'] = 'Tiêu đề 1'; +jsToolBar.strings['Heading 2'] = 'Tiêu đề 2'; +jsToolBar.strings['Heading 3'] = 'Tiêu đề 3'; +jsToolBar.strings['Unordered list'] = 'Danh sách không thứ tự'; +jsToolBar.strings['Ordered list'] = 'Danh sách có thứ tự'; +jsToolBar.strings['Quote'] = 'Trích dẫn'; +jsToolBar.strings['Unquote'] = 'Bỏ trích dẫn'; +jsToolBar.strings['Preformatted text'] = 'Mã nguồn'; +jsToolBar.strings['Wiki link'] = 'Liên kết đến trang wiki'; +jsToolBar.strings['Image'] = 'Ảnh'; diff --git a/public/javascripts/jstoolbar/lang/jstoolbar-zh-tw.js b/public/javascripts/jstoolbar/lang/jstoolbar-zh-tw.js new file mode 100644 index 00000000..86599c5a --- /dev/null +++ b/public/javascripts/jstoolbar/lang/jstoolbar-zh-tw.js @@ -0,0 +1,16 @@ +jsToolBar.strings = {}; +jsToolBar.strings['Strong'] = '粗體'; +jsToolBar.strings['Italic'] = '斜體'; +jsToolBar.strings['Underline'] = '底線'; +jsToolBar.strings['Deleted'] = '刪除線'; +jsToolBar.strings['Code'] = '程式碼'; +jsToolBar.strings['Heading 1'] = '標題 1'; +jsToolBar.strings['Heading 2'] = '標題 2'; +jsToolBar.strings['Heading 3'] = '標題 3'; +jsToolBar.strings['Unordered list'] = '項目清單'; +jsToolBar.strings['Ordered list'] = '編號清單'; +jsToolBar.strings['Quote'] = '引文'; +jsToolBar.strings['Unquote'] = '取消引文'; +jsToolBar.strings['Preformatted text'] = '已格式文字'; +jsToolBar.strings['Wiki link'] = '連結至 Wiki 頁面'; +jsToolBar.strings['Image'] = '圖片'; diff --git a/public/javascripts/jstoolbar/lang/jstoolbar-zh.js b/public/javascripts/jstoolbar/lang/jstoolbar-zh.js new file mode 100644 index 00000000..a9b6ba23 --- /dev/null +++ b/public/javascripts/jstoolbar/lang/jstoolbar-zh.js @@ -0,0 +1,16 @@ +jsToolBar.strings = {}; +jsToolBar.strings['Strong'] = '粗体'; +jsToolBar.strings['Italic'] = '斜体'; +jsToolBar.strings['Underline'] = '下划线'; +jsToolBar.strings['Deleted'] = '删除线'; +jsToolBar.strings['Code'] = '程序代码'; +jsToolBar.strings['Heading 1'] = '标题 1'; +jsToolBar.strings['Heading 2'] = '标题 2'; +jsToolBar.strings['Heading 3'] = '标题 3'; +jsToolBar.strings['Unordered list'] = '无序列表'; +jsToolBar.strings['Ordered list'] = '排序列表'; +jsToolBar.strings['Quote'] = '引用'; +jsToolBar.strings['Unquote'] = '删除引用'; +jsToolBar.strings['Preformatted text'] = '格式化文本'; +jsToolBar.strings['Wiki link'] = '连接到 Wiki 页面'; +jsToolBar.strings['Image'] = '图片'; diff --git a/public/javascripts/jstoolbar/textile.js b/public/javascripts/jstoolbar/textile.js new file mode 100644 index 00000000..cf925d54 --- /dev/null +++ b/public/javascripts/jstoolbar/textile.js @@ -0,0 +1,211 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * This file is part of DotClear. + * Copyright (c) 2005 Nicolas Martin & Olivier Meunier and contributors. All + * rights reserved. + * + * DotClear is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * DotClear is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with DotClear; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * ***** END LICENSE BLOCK ***** +*/ + +/* Modified by JP LANG for textile formatting */ + +// strong +jsToolBar.prototype.elements.strong = { + type: 'button', + title: 'Strong', + fn: { + wiki: function() { this.singleTag('*') } + } +} + +// em +jsToolBar.prototype.elements.em = { + type: 'button', + title: 'Italic', + fn: { + wiki: function() { this.singleTag("_") } + } +} + +// ins +jsToolBar.prototype.elements.ins = { + type: 'button', + title: 'Underline', + fn: { + wiki: function() { this.singleTag('+') } + } +} + +// del +jsToolBar.prototype.elements.del = { + type: 'button', + title: 'Deleted', + fn: { + wiki: function() { this.singleTag('-') } + } +} + +// code +jsToolBar.prototype.elements.code = { + type: 'button', + title: 'Code', + fn: { + wiki: function() { this.singleTag('@') } + } +} + +// spacer +jsToolBar.prototype.elements.space1 = {type: 'space'} + +// headings +jsToolBar.prototype.elements.h1 = { + type: 'button', + title: 'Heading 1', + fn: { + wiki: function() { + this.encloseLineSelection('h1. ', '',function(str) { + str = str.replace(/^h\d+\.\s+/, '') + return str; + }); + } + } +} +jsToolBar.prototype.elements.h2 = { + type: 'button', + title: 'Heading 2', + fn: { + wiki: function() { + this.encloseLineSelection('h2. ', '',function(str) { + str = str.replace(/^h\d+\.\s+/, '') + return str; + }); + } + } +} +jsToolBar.prototype.elements.h3 = { + type: 'button', + title: 'Heading 3', + fn: { + wiki: function() { + this.encloseLineSelection('h3. ', '',function(str) { + str = str.replace(/^h\d+\.\s+/, '') + return str; + }); + } + } +} + +// spacer +jsToolBar.prototype.elements.space2 = {type: 'space'} + +// ul +jsToolBar.prototype.elements.ul = { + type: 'button', + title: 'Unordered list', + fn: { + wiki: function() { + this.encloseLineSelection('','',function(str) { + str = str.replace(/\r/g,''); + return str.replace(/(\n|^)[#-]?\s*/g,"$1* "); + }); + } + } +} + +// ol +jsToolBar.prototype.elements.ol = { + type: 'button', + title: 'Ordered list', + fn: { + wiki: function() { + this.encloseLineSelection('','',function(str) { + str = str.replace(/\r/g,''); + return str.replace(/(\n|^)[*-]?\s*/g,"$1# "); + }); + } + } +} + +// spacer +jsToolBar.prototype.elements.space3 = {type: 'space'} + +// bq +jsToolBar.prototype.elements.bq = { + type: 'button', + title: 'Quote', + fn: { + wiki: function() { + this.encloseLineSelection('','',function(str) { + str = str.replace(/\r/g,''); + return str.replace(/(\n|^) *([^\n]*)/g,"$1> $2"); + }); + } + } +} + +// unbq +jsToolBar.prototype.elements.unbq = { + type: 'button', + title: 'Unquote', + fn: { + wiki: function() { + this.encloseLineSelection('','',function(str) { + str = str.replace(/\r/g,''); + return str.replace(/(\n|^) *[>]? *([^\n]*)/g,"$1$2"); + }); + } + } +} + +// pre +jsToolBar.prototype.elements.pre = { + type: 'button', + title: 'Preformatted text', + fn: { + wiki: function() { this.encloseLineSelection('
      \n', '\n
      ') } + } +} + +// spacer +jsToolBar.prototype.elements.space4 = {type: 'space'} + +// wiki page +jsToolBar.prototype.elements.link = { + type: 'button', + title: 'Wiki link', + fn: { + wiki: function() { this.encloseSelection("[[", "]]") } + } +} +// image +jsToolBar.prototype.elements.img = { + type: 'button', + title: 'Image', + fn: { + wiki: function() { this.encloseSelection("!", "!") } + } +} + +// spacer +jsToolBar.prototype.elements.space5 = {type: 'space'} +// help +jsToolBar.prototype.elements.help = { + type: 'button', + title: 'Help', + fn: { + wiki: function() { window.open(this.help_link, '', 'resizable=yes, location=no, width=300, height=640, menubar=no, status=no, scrollbars=yes') } + } +} diff --git a/public/javascripts/project_identifier.js b/public/javascripts/project_identifier.js new file mode 100644 index 00000000..298ca38f --- /dev/null +++ b/public/javascripts/project_identifier.js @@ -0,0 +1,78 @@ +// Automatic project identifier generation + +function generateProjectIdentifier(identifier, maxlength) { + var diacriticsMap = [ + {'base':'a', 'letters':/[\u0061\u24D0\uFF41\u1E9A\u00E0\u00E1\u00E2\u1EA7\u1EA5\u1EAB\u1EA9\u00E3\u0101\u0103\u1EB1\u1EAF\u1EB5\u1EB3\u0227\u01E1\u01DF\u1EA3\u00E5\u01FB\u01CE\u0201\u0203\u1EA1\u1EAD\u1EB7\u1E01\u0105\u2C65\u0250\u0041\u24B6\uFF21\u00C0\u00C1\u00C2\u1EA6\u1EA4\u1EAA\u1EA8\u00C3\u0100\u0102\u1EB0\u1EAE\u1EB4\u1EB2\u0226\u01E0\u01DE\u1EA2\u00C5\u01FA\u01CD\u0200\u0202\u1EA0\u1EAC\u1EB6\u1E00\u0104\u023A\u2C6F]/g}, + {'base':'aa','letters':/[\uA733\uA732]/g}, + {'base':'ae','letters':/[\u00E4\u00E6\u01FD\u01E3\u00C4\u00C6\u01FC\u01E2]/g}, + {'base':'ao','letters':/[\uA735\uA734]/g}, + {'base':'au','letters':/[\uA737\uA736]/g}, + {'base':'av','letters':/[\uA739\uA73B\uA738\uA73A]/g}, + {'base':'ay','letters':/[\uA73D\uA73C]/g}, + {'base':'b', 'letters':/[\u0062\u24D1\uFF42\u1E03\u1E05\u1E07\u0180\u0183\u0253\u0042\u24B7\uFF22\u1E02\u1E04\u1E06\u0243\u0182\u0181]/g}, + {'base':'c', 'letters':/[\u0063\u24D2\uFF43\u0107\u0109\u010B\u010D\u00E7\u1E09\u0188\u023C\uA73F\u2184\u0043\u24B8\uFF23\u0106\u0108\u010A\u010C\u00C7\u1E08\u0187\u023B\uA73E]/g}, + {'base':'d', 'letters':/[\u0064\u24D3\uFF44\u1E0B\u010F\u1E0D\u1E11\u1E13\u1E0F\u0111\u018C\u0256\u0257\uA77A\u0044\u24B9\uFF24\u1E0A\u010E\u1E0C\u1E10\u1E12\u1E0E\u0110\u018B\u018A\u0189\uA779]/g}, + {'base':'dz','letters':/[\u01F3\u01C6\u01F1\u01C4\u01F2\u01C5]/g}, + {'base':'e', 'letters':/[\u0065\u24D4\uFF45\u00E8\u00E9\u00EA\u1EC1\u1EBF\u1EC5\u1EC3\u1EBD\u0113\u1E15\u1E17\u0115\u0117\u00EB\u1EBB\u011B\u0205\u0207\u1EB9\u1EC7\u0229\u1E1D\u0119\u1E19\u1E1B\u0247\u025B\u01DD\u0045\u24BA\uFF25\u00C8\u00C9\u00CA\u1EC0\u1EBE\u1EC4\u1EC2\u1EBC\u0112\u1E14\u1E16\u0114\u0116\u00CB\u1EBA\u011A\u0204\u0206\u1EB8\u1EC6\u0228\u1E1C\u0118\u1E18\u1E1A\u0190\u018E]/g}, + {'base':'f', 'letters':/[\u0066\u24D5\uFF46\u1E1F\u0192\uA77C\u0046\u24BB\uFF26\u1E1E\u0191\uA77B]/g}, + {'base':'g', 'letters':/[\u0067\u24D6\uFF47\u01F5\u011D\u1E21\u011F\u0121\u01E7\u0123\u01E5\u0260\uA7A1\u1D79\uA77F\u0047\u24BC\uFF27\u01F4\u011C\u1E20\u011E\u0120\u01E6\u0122\u01E4\u0193\uA7A0\uA77D\uA77E]/g}, + {'base':'h', 'letters':/[\u0068\u24D7\uFF48\u0125\u1E23\u1E27\u021F\u1E25\u1E29\u1E2B\u1E96\u0127\u2C68\u2C76\u0265\u0048\u24BD\uFF28\u0124\u1E22\u1E26\u021E\u1E24\u1E28\u1E2A\u0126\u2C67\u2C75\uA78D]/g}, + {'base':'hv','letters':/[\u0195]/g}, + {'base':'i', 'letters':/[\u0069\u24D8\uFF49\u00EC\u00ED\u00EE\u0129\u012B\u012D\u00EF\u1E2F\u1EC9\u01D0\u0209\u020B\u1ECB\u012F\u1E2D\u0268\u0131\u0049\u24BE\uFF29\u00CC\u00CD\u00CE\u0128\u012A\u012C\u0130\u00CF\u1E2E\u1EC8\u01CF\u0208\u020A\u1ECA\u012E\u1E2C\u0197]/g}, + {'base':'j', 'letters':/[\u006A\u24D9\uFF4A\u0135\u01F0\u0249\u004A\u24BF\uFF2A\u0134\u0248]/g}, + {'base':'k', 'letters':/[\u006B\u24DA\uFF4B\u1E31\u01E9\u1E33\u0137\u1E35\u0199\u2C6A\uA741\uA743\uA745\uA7A3\u004B\u24C0\uFF2B\u1E30\u01E8\u1E32\u0136\u1E34\u0198\u2C69\uA740\uA742\uA744\uA7A2]/g}, + {'base':'l', 'letters':/[\u006C\u24DB\uFF4C\u0140\u013A\u013E\u1E37\u1E39\u013C\u1E3D\u1E3B\u017F\u0142\u019A\u026B\u2C61\uA749\uA781\uA747\u004C\u24C1\uFF2C\u013F\u0139\u013D\u1E36\u1E38\u013B\u1E3C\u1E3A\u0141\u023D\u2C62\u2C60\uA748\uA746\uA780]/g}, + {'base':'lj','letters':/[\u01C9\u01C7\u01C8]/g}, + {'base':'m', 'letters':/[\u006D\u24DC\uFF4D\u1E3F\u1E41\u1E43\u0271\u026F\u004D\u24C2\uFF2D\u1E3E\u1E40\u1E42\u2C6E\u019C]/g}, + {'base':'n', 'letters':/[\u006E\u24DD\uFF4E\u01F9\u0144\u00F1\u1E45\u0148\u1E47\u0146\u1E4B\u1E49\u019E\u0272\u0149\uA791\uA7A5\u004E\u24C3\uFF2E\u01F8\u0143\u00D1\u1E44\u0147\u1E46\u0145\u1E4A\u1E48\u0220\u019D\uA790\uA7A4]/g}, + {'base':'nj','letters':/[\u01CC\u01CA\u01CB]/g}, + {'base':'o', 'letters':/[\u006F\u24DE\uFF4F\u00F2\u00F3\u00F4\u1ED3\u1ED1\u1ED7\u1ED5\u00F5\u1E4D\u022D\u1E4F\u014D\u1E51\u1E53\u014F\u022F\u0231\u022B\u1ECF\u0151\u01D2\u020D\u020F\u01A1\u1EDD\u1EDB\u1EE1\u1EDF\u1EE3\u1ECD\u1ED9\u01EB\u01ED\u00F8\u01FF\u0254\uA74B\uA74D\u0275\u004F\u24C4\uFF2F\u00D2\u00D3\u00D4\u1ED2\u1ED0\u1ED6\u1ED4\u00D5\u1E4C\u022C\u1E4E\u014C\u1E50\u1E52\u014E\u022E\u0230\u022A\u1ECE\u0150\u01D1\u020C\u020E\u01A0\u1EDC\u1EDA\u1EE0\u1EDE\u1EE2\u1ECC\u1ED8\u01EA\u01EC\u00D8\u01FE\u0186\u019F\uA74A\uA74C]/g}, + {'base':'oe','letters': /[\u00F6\u0153\u00D6\u0152]/g}, + {'base':'oi','letters':/[\u01A3\u01A2]/g}, + {'base':'ou','letters':/[\u0223\u0222]/g}, + {'base':'oo','letters':/[\uA74F\uA74E]/g}, + {'base':'p','letters':/[\u0070\u24DF\uFF50\u1E55\u1E57\u01A5\u1D7D\uA751\uA753\uA755\u0050\u24C5\uFF30\u1E54\u1E56\u01A4\u2C63\uA750\uA752\uA754]/g}, + {'base':'q','letters':/[\u0071\u24E0\uFF51\u024B\uA757\uA759\u0051\u24C6\uFF31\uA756\uA758\u024A]/g}, + {'base':'r','letters':/[\u0072\u24E1\uFF52\u0155\u1E59\u0159\u0211\u0213\u1E5B\u1E5D\u0157\u1E5F\u024D\u027D\uA75B\uA7A7\uA783\u0052\u24C7\uFF32\u0154\u1E58\u0158\u0210\u0212\u1E5A\u1E5C\u0156\u1E5E\u024C\u2C64\uA75A\uA7A6\uA782]/g}, + {'base':'s','letters':/[\u0073\u24E2\uFF53\u015B\u1E65\u015D\u1E61\u0161\u1E67\u1E63\u1E69\u0219\u015F\u023F\uA7A9\uA785\u1E9B\u0053\u24C8\uFF33\u1E9E\u015A\u1E64\u015C\u1E60\u0160\u1E66\u1E62\u1E68\u0218\u015E\u2C7E\uA7A8\uA784]/g}, + {'base':'ss','letters':/[\u00DF]/g}, + {'base':'t','letters':/[\u0074\u24E3\uFF54\u1E6B\u1E97\u0165\u1E6D\u021B\u0163\u1E71\u1E6F\u0167\u01AD\u0288\u2C66\uA787\u0054\u24C9\uFF34\u1E6A\u0164\u1E6C\u021A\u0162\u1E70\u1E6E\u0166\u01AC\u01AE\u023E\uA786]/g}, + {'base':'tz','letters':/[\uA729\uA728]/g}, + {'base':'u','letters':/[\u0075\u24E4\uFF55\u00F9\u00FA\u00FB\u0169\u1E79\u016B\u1E7B\u016D\u01DC\u01D8\u01D6\u01DA\u1EE7\u016F\u0171\u01D4\u0215\u0217\u01B0\u1EEB\u1EE9\u1EEF\u1EED\u1EF1\u1EE5\u1E73\u0173\u1E77\u1E75\u0289\u0055\u24CA\uFF35\u00D9\u00DA\u00DB\u0168\u1E78\u016A\u1E7A\u016C\u01DB\u01D7\u01D5\u01D9\u1EE6\u016E\u0170\u01D3\u0214\u0216\u01AF\u1EEA\u1EE8\u1EEE\u1EEC\u1EF0\u1EE4\u1E72\u0172\u1E76\u1E74\u0244]/g}, + {'base':'ue','letters':/[\u00FC\u00DC]/g}, + {'base':'v','letters':/[\u0076\u24E5\uFF56\u1E7D\u1E7F\u028B\uA75F\u028C\u0056\u24CB\uFF36\u1E7C\u1E7E\u01B2\uA75E\u0245]/g}, + {'base':'vy','letters':/[\uA761\uA760]/g}, + {'base':'w','letters':/[\u0077\u24E6\uFF57\u1E81\u1E83\u0175\u1E87\u1E85\u1E98\u1E89\u2C73\u0057\u24CC\uFF37\u1E80\u1E82\u0174\u1E86\u1E84\u1E88\u2C72]/g}, + {'base':'x','letters':/[\u0078\u24E7\uFF58\u1E8B\u1E8D\u0058\u24CD\uFF38\u1E8A\u1E8C]/g}, + {'base':'y','letters':/[\u0079\u24E8\uFF59\u1EF3\u00FD\u0177\u1EF9\u0233\u1E8F\u00FF\u1EF7\u1E99\u1EF5\u01B4\u024F\u1EFF\u0059\u24CE\uFF39\u1EF2\u00DD\u0176\u1EF8\u0232\u1E8E\u0178\u1EF6\u1EF4\u01B3\u024E\u1EFE]/g}, + {'base':'z','letters':/[\u007A\u24E9\uFF5A\u017A\u1E91\u017C\u017E\u1E93\u1E95\u01B6\u0225\u0240\u2C6C\uA763\u005A\u24CF\uFF3A\u0179\u1E90\u017B\u017D\u1E92\u1E94\u01B5\u0224\u2C7F\u2C6B\uA762]/g} + ]; + + for(var i=0; i hyphen + identifier = identifier.replace(/^[-_\d]*|[-_]*$/g, ''); // remove hyphens/underscores and numbers at beginning and hyphens/underscores at end + identifier = identifier.toLowerCase(); // to lower + identifier = identifier.substr(0, maxlength); // max characters + return identifier; +} + +function autoFillProjectIdentifier() { + var locked = ($('#project_identifier').val() != ''); + var maxlength = parseInt($('#project_identifier').attr('maxlength')); + + $('#project_name').keyup(function(){ + if(!locked) { + $('#project_identifier').val(generateProjectIdentifier($('#project_name').val(), maxlength)); + } + }); + + $('#project_identifier').keyup(function(){ + locked = ($('#project_identifier').val() != '' && $('#project_identifier').val() != generateProjectIdentifier($('#project_name').val(), maxlength)); + }); +} + +$(document).ready(function(){ + autoFillProjectIdentifier(); +}); diff --git a/public/javascripts/raphael.js b/public/javascripts/raphael.js new file mode 100644 index 00000000..6a0c7852 --- /dev/null +++ b/public/javascripts/raphael.js @@ -0,0 +1,10 @@ +// ┌────────────────────────────────────────────────────────────────────┐ \\ +// │ Raphaël 2.1.0 - JavaScript Vector Library │ \\ +// ├────────────────────────────────────────────────────────────────────┤ \\ +// │ Copyright © 2008-2012 Dmitry Baranovskiy (http://raphaeljs.com) │ \\ +// │ Copyright © 2008-2012 Sencha Labs (http://sencha.com) │ \\ +// ├────────────────────────────────────────────────────────────────────┤ \\ +// │ Licensed under the MIT (http://raphaeljs.com/license.html) license.│ \\ +// └────────────────────────────────────────────────────────────────────┘ \\ + +(function(a){var b="0.3.4",c="hasOwnProperty",d=/[\.\/]/,e="*",f=function(){},g=function(a,b){return a-b},h,i,j={n:{}},k=function(a,b){var c=j,d=i,e=Array.prototype.slice.call(arguments,2),f=k.listeners(a),l=0,m=!1,n,o=[],p={},q=[],r=h,s=[];h=a,i=0;for(var t=0,u=f.length;tf*b.top){e=b.percents[y],p=b.percents[y-1]||0,t=t/b.top*(e-p),o=b.percents[y+1],j=b.anim[e];break}f&&d.attr(b.anim[b.percents[y]])}if(!!j){if(!k){for(var A in j)if(j[g](A))if(U[g](A)||d.paper.customAttributes[g](A)){u[A]=d.attr(A),u[A]==null&&(u[A]=T[A]),v[A]=j[A];switch(U[A]){case C:w[A]=(v[A]-u[A])/t;break;case"colour":u[A]=a.getRGB(u[A]);var B=a.getRGB(v[A]);w[A]={r:(B.r-u[A].r)/t,g:(B.g-u[A].g)/t,b:(B.b-u[A].b)/t};break;case"path":var D=bR(u[A],v[A]),E=D[1];u[A]=D[0],w[A]=[];for(y=0,z=u[A].length;yd)return d;while(cf?c=e:d=e,e=(d-c)/2+c}return e}function n(a,b){var c=o(a,b);return((l*c+k)*c+j)*c}function m(a){return((i*a+h)*a+g)*a}var g=3*b,h=3*(d-b)-g,i=1-g-h,j=3*c,k=3*(e-c)-j,l=1-j-k;return n(a,1/(200*f))}function cq(){return this.x+q+this.y+q+this.width+" × "+this.height}function cp(){return this.x+q+this.y}function cb(a,b,c,d,e,f){a!=null?(this.a=+a,this.b=+b,this.c=+c,this.d=+d,this.e=+e,this.f=+f):(this.a=1,this.b=0,this.c=0,this.d=1,this.e=0,this.f=0)}function bH(b,c,d){b=a._path2curve(b),c=a._path2curve(c);var e,f,g,h,i,j,k,l,m,n,o=d?0:[];for(var p=0,q=b.length;p=0&&y<=1&&A>=0&&A<=1&&(d?n++:n.push({x:x.x,y:x.y,t1:y,t2:A}))}}return n}function bF(a,b){return bG(a,b,1)}function bE(a,b){return bG(a,b)}function bD(a,b,c,d,e,f,g,h){if(!(x(a,c)x(e,g)||x(b,d)x(f,h))){var i=(a*d-b*c)*(e-g)-(a-c)*(e*h-f*g),j=(a*d-b*c)*(f-h)-(b-d)*(e*h-f*g),k=(a-c)*(f-h)-(b-d)*(e-g);if(!k)return;var l=i/k,m=j/k,n=+l.toFixed(2),o=+m.toFixed(2);if(n<+y(a,c).toFixed(2)||n>+x(a,c).toFixed(2)||n<+y(e,g).toFixed(2)||n>+x(e,g).toFixed(2)||o<+y(b,d).toFixed(2)||o>+x(b,d).toFixed(2)||o<+y(f,h).toFixed(2)||o>+x(f,h).toFixed(2))return;return{x:l,y:m}}}function bC(a,b,c,d,e,f,g,h,i){if(!(i<0||bB(a,b,c,d,e,f,g,h)n)k/=2,l+=(m1?1:i<0?0:i;var j=i/2,k=12,l=[-0.1252,.1252,-0.3678,.3678,-0.5873,.5873,-0.7699,.7699,-0.9041,.9041,-0.9816,.9816],m=[.2491,.2491,.2335,.2335,.2032,.2032,.1601,.1601,.1069,.1069,.0472,.0472],n=0;for(var o=0;od;d+=2){var f=[{x:+a[d-2],y:+a[d-1]},{x:+a[d],y:+a[d+1]},{x:+a[d+2],y:+a[d+3]},{x:+a[d+4],y:+a[d+5]}];b?d?e-4==d?f[3]={x:+a[0],y:+a[1]}:e-2==d&&(f[2]={x:+a[0],y:+a[1]},f[3]={x:+a[2],y:+a[3]}):f[0]={x:+a[e-2],y:+a[e-1]}:e-4==d?f[3]=f[2]:d||(f[0]={x:+a[d],y:+a[d+1]}),c.push(["C",(-f[0].x+6*f[1].x+f[2].x)/6,(-f[0].y+6*f[1].y+f[2].y)/6,(f[1].x+6*f[2].x-f[3].x)/6,(f[1].y+6*f[2].y-f[3].y)/6,f[2].x,f[2].y])}return c}function bx(){return this.hex}function bv(a,b,c){function d(){var e=Array.prototype.slice.call(arguments,0),f=e.join("␀"),h=d.cache=d.cache||{},i=d.count=d.count||[];if(h[g](f)){bu(i,f);return c?c(h[f]):h[f]}i.length>=1e3&&delete h[i.shift()],i.push(f),h[f]=a[m](b,e);return c?c(h[f]):h[f]}return d}function bu(a,b){for(var c=0,d=a.length;c',bl=bk.firstChild,bl.style.behavior="url(#default#VML)";if(!bl||typeof bl.adj!="object")return a.type=p;bk=null}a.svg=!(a.vml=a.type=="VML"),a._Paper=j,a.fn=k=j.prototype=a.prototype,a._id=0,a._oid=0,a.is=function(a,b){b=v.call(b);if(b=="finite")return!M[g](+a);if(b=="array")return a instanceof Array;return b=="null"&&a===null||b==typeof a&&a!==null||b=="object"&&a===Object(a)||b=="array"&&Array.isArray&&Array.isArray(a)||H.call(a).slice(8,-1).toLowerCase()==b},a.angle=function(b,c,d,e,f,g){if(f==null){var h=b-d,i=c-e;if(!h&&!i)return 0;return(180+w.atan2(-i,-h)*180/B+360)%360}return a.angle(b,c,f,g)-a.angle(d,e,f,g)},a.rad=function(a){return a%360*B/180},a.deg=function(a){return a*180/B%360},a.snapTo=function(b,c,d){d=a.is(d,"finite")?d:10;if(a.is(b,E)){var e=b.length;while(e--)if(z(b[e]-c)<=d)return b[e]}else{b=+b;var f=c%b;if(fb-d)return c-f+b}return c};var bn=a.createUUID=function(a,b){return function(){return"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(a,b).toUpperCase()}}(/[xy]/g,function(a){var b=w.random()*16|0,c=a=="x"?b:b&3|8;return c.toString(16)});a.setWindow=function(b){eve("raphael.setWindow",a,h.win,b),h.win=b,h.doc=h.win.document,a._engine.initWin&&a._engine.initWin(h.win)};var bo=function(b){if(a.vml){var c=/^\s+|\s+$/g,d;try{var e=new ActiveXObject("htmlfile");e.write(""),e.close(),d=e.body}catch(f){d=createPopup().document.body}var g=d.createTextRange();bo=bv(function(a){try{d.style.color=r(a).replace(c,p);var b=g.queryCommandValue("ForeColor");b=(b&255)<<16|b&65280|(b&16711680)>>>16;return"#"+("000000"+b.toString(16)).slice(-6)}catch(e){return"none"}})}else{var i=h.doc.createElement("i");i.title="Raphaël Colour Picker",i.style.display="none",h.doc.body.appendChild(i),bo=bv(function(a){i.style.color=a;return h.doc.defaultView.getComputedStyle(i,p).getPropertyValue("color")})}return bo(b)},bp=function(){return"hsb("+[this.h,this.s,this.b]+")"},bq=function(){return"hsl("+[this.h,this.s,this.l]+")"},br=function(){return this.hex},bs=function(b,c,d){c==null&&a.is(b,"object")&&"r"in b&&"g"in b&&"b"in b&&(d=b.b,c=b.g,b=b.r);if(c==null&&a.is(b,D)){var e=a.getRGB(b);b=e.r,c=e.g,d=e.b}if(b>1||c>1||d>1)b/=255,c/=255,d/=255;return[b,c,d]},bt=function(b,c,d,e){b*=255,c*=255,d*=255;var f={r:b,g:c,b:d,hex:a.rgb(b,c,d),toString:br};a.is(e,"finite")&&(f.opacity=e);return f};a.color=function(b){var c;a.is(b,"object")&&"h"in b&&"s"in b&&"b"in b?(c=a.hsb2rgb(b),b.r=c.r,b.g=c.g,b.b=c.b,b.hex=c.hex):a.is(b,"object")&&"h"in b&&"s"in b&&"l"in b?(c=a.hsl2rgb(b),b.r=c.r,b.g=c.g,b.b=c.b,b.hex=c.hex):(a.is(b,"string")&&(b=a.getRGB(b)),a.is(b,"object")&&"r"in b&&"g"in b&&"b"in b?(c=a.rgb2hsl(b),b.h=c.h,b.s=c.s,b.l=c.l,c=a.rgb2hsb(b),b.v=c.b):(b={hex:"none"},b.r=b.g=b.b=b.h=b.s=b.v=b.l=-1)),b.toString=br;return b},a.hsb2rgb=function(a,b,c,d){this.is(a,"object")&&"h"in a&&"s"in a&&"b"in a&&(c=a.b,b=a.s,a=a.h,d=a.o),a*=360;var e,f,g,h,i;a=a%360/60,i=c*b,h=i*(1-z(a%2-1)),e=f=g=c-i,a=~~a,e+=[i,h,0,0,h,i][a],f+=[h,i,i,h,0,0][a],g+=[0,0,h,i,i,h][a];return bt(e,f,g,d)},a.hsl2rgb=function(a,b,c,d){this.is(a,"object")&&"h"in a&&"s"in a&&"l"in a&&(c=a.l,b=a.s,a=a.h);if(a>1||b>1||c>1)a/=360,b/=100,c/=100;a*=360;var e,f,g,h,i;a=a%360/60,i=2*b*(c<.5?c:1-c),h=i*(1-z(a%2-1)),e=f=g=c-i/2,a=~~a,e+=[i,h,0,0,h,i][a],f+=[h,i,i,h,0,0][a],g+=[0,0,h,i,i,h][a];return bt(e,f,g,d)},a.rgb2hsb=function(a,b,c){c=bs(a,b,c),a=c[0],b=c[1],c=c[2];var d,e,f,g;f=x(a,b,c),g=f-y(a,b,c),d=g==0?null:f==a?(b-c)/g:f==b?(c-a)/g+2:(a-b)/g+4,d=(d+360)%6*60/360,e=g==0?0:g/f;return{h:d,s:e,b:f,toString:bp}},a.rgb2hsl=function(a,b,c){c=bs(a,b,c),a=c[0],b=c[1],c=c[2];var d,e,f,g,h,i;g=x(a,b,c),h=y(a,b,c),i=g-h,d=i==0?null:g==a?(b-c)/i:g==b?(c-a)/i+2:(a-b)/i+4,d=(d+360)%6*60/360,f=(g+h)/2,e=i==0?0:f<.5?i/(2*f):i/(2-2*f);return{h:d,s:e,l:f,toString:bq}},a._path2string=function(){return this.join(",").replace(Y,"$1")};var bw=a._preload=function(a,b){var c=h.doc.createElement("img");c.style.cssText="position:absolute;left:-9999em;top:-9999em",c.onload=function(){b.call(this),this.onload=null,h.doc.body.removeChild(this)},c.onerror=function(){h.doc.body.removeChild(this)},h.doc.body.appendChild(c),c.src=a};a.getRGB=bv(function(b){if(!b||!!((b=r(b)).indexOf("-")+1))return{r:-1,g:-1,b:-1,hex:"none",error:1,toString:bx};if(b=="none")return{r:-1,g:-1,b:-1,hex:"none",toString:bx};!X[g](b.toLowerCase().substring(0,2))&&b.charAt()!="#"&&(b=bo(b));var c,d,e,f,h,i,j,k=b.match(L);if(k){k[2]&&(f=R(k[2].substring(5),16),e=R(k[2].substring(3,5),16),d=R(k[2].substring(1,3),16)),k[3]&&(f=R((i=k[3].charAt(3))+i,16),e=R((i=k[3].charAt(2))+i,16),d=R((i=k[3].charAt(1))+i,16)),k[4]&&(j=k[4][s](W),d=Q(j[0]),j[0].slice(-1)=="%"&&(d*=2.55),e=Q(j[1]),j[1].slice(-1)=="%"&&(e*=2.55),f=Q(j[2]),j[2].slice(-1)=="%"&&(f*=2.55),k[1].toLowerCase().slice(0,4)=="rgba"&&(h=Q(j[3])),j[3]&&j[3].slice(-1)=="%"&&(h/=100));if(k[5]){j=k[5][s](W),d=Q(j[0]),j[0].slice(-1)=="%"&&(d*=2.55),e=Q(j[1]),j[1].slice(-1)=="%"&&(e*=2.55),f=Q(j[2]),j[2].slice(-1)=="%"&&(f*=2.55),(j[0].slice(-3)=="deg"||j[0].slice(-1)=="°")&&(d/=360),k[1].toLowerCase().slice(0,4)=="hsba"&&(h=Q(j[3])),j[3]&&j[3].slice(-1)=="%"&&(h/=100);return a.hsb2rgb(d,e,f,h)}if(k[6]){j=k[6][s](W),d=Q(j[0]),j[0].slice(-1)=="%"&&(d*=2.55),e=Q(j[1]),j[1].slice(-1)=="%"&&(e*=2.55),f=Q(j[2]),j[2].slice(-1)=="%"&&(f*=2.55),(j[0].slice(-3)=="deg"||j[0].slice(-1)=="°")&&(d/=360),k[1].toLowerCase().slice(0,4)=="hsla"&&(h=Q(j[3])),j[3]&&j[3].slice(-1)=="%"&&(h/=100);return a.hsl2rgb(d,e,f,h)}k={r:d,g:e,b:f,toString:bx},k.hex="#"+(16777216|f|e<<8|d<<16).toString(16).slice(1),a.is(h,"finite")&&(k.opacity=h);return k}return{r:-1,g:-1,b:-1,hex:"none",error:1,toString:bx}},a),a.hsb=bv(function(b,c,d){return a.hsb2rgb(b,c,d).hex}),a.hsl=bv(function(b,c,d){return a.hsl2rgb(b,c,d).hex}),a.rgb=bv(function(a,b,c){return"#"+(16777216|c|b<<8|a<<16).toString(16).slice(1)}),a.getColor=function(a){var b=this.getColor.start=this.getColor.start||{h:0,s:1,b:a||.75},c=this.hsb2rgb(b.h,b.s,b.b);b.h+=.075,b.h>1&&(b.h=0,b.s-=.2,b.s<=0&&(this.getColor.start={h:0,s:1,b:b.b}));return c.hex},a.getColor.reset=function(){delete this.start},a.parsePathString=function(b){if(!b)return null;var c=bz(b);if(c.arr)return bJ(c.arr);var d={a:7,c:6,h:1,l:2,m:2,r:4,q:4,s:4,t:2,v:1,z:0},e=[];a.is(b,E)&&a.is(b[0],E)&&(e=bJ(b)),e.length||r(b).replace(Z,function(a,b,c){var f=[],g=b.toLowerCase();c.replace(_,function(a,b){b&&f.push(+b)}),g=="m"&&f.length>2&&(e.push([b][n](f.splice(0,2))),g="l",b=b=="m"?"l":"L");if(g=="r")e.push([b][n](f));else while(f.length>=d[g]){e.push([b][n](f.splice(0,d[g])));if(!d[g])break}}),e.toString=a._path2string,c.arr=bJ(e);return e},a.parseTransformString=bv(function(b){if(!b)return null;var c={r:3,s:4,t:2,m:6},d=[];a.is(b,E)&&a.is(b[0],E)&&(d=bJ(b)),d.length||r(b).replace($,function(a,b,c){var e=[],f=v.call(b);c.replace(_,function(a,b){b&&e.push(+b)}),d.push([b][n](e))}),d.toString=a._path2string;return d});var bz=function(a){var b=bz.ps=bz.ps||{};b[a]?b[a].sleep=100:b[a]={sleep:100},setTimeout(function(){for(var c in b)b[g](c)&&c!=a&&(b[c].sleep--,!b[c].sleep&&delete b[c])});return b[a]};a.findDotsAtSegment=function(a,b,c,d,e,f,g,h,i){var j=1-i,k=A(j,3),l=A(j,2),m=i*i,n=m*i,o=k*a+l*3*i*c+j*3*i*i*e+n*g,p=k*b+l*3*i*d+j*3*i*i*f+n*h,q=a+2*i*(c-a)+m*(e-2*c+a),r=b+2*i*(d-b)+m*(f-2*d+b),s=c+2*i*(e-c)+m*(g-2*e+c),t=d+2*i*(f-d)+m*(h-2*f+d),u=j*a+i*c,v=j*b+i*d,x=j*e+i*g,y=j*f+i*h,z=90-w.atan2(q-s,r-t)*180/B;(q>s||r=a.x&&b<=a.x2&&c>=a.y&&c<=a.y2},a.isBBoxIntersect=function(b,c){var d=a.isPointInsideBBox;return d(c,b.x,b.y)||d(c,b.x2,b.y)||d(c,b.x,b.y2)||d(c,b.x2,b.y2)||d(b,c.x,c.y)||d(b,c.x2,c.y)||d(b,c.x,c.y2)||d(b,c.x2,c.y2)||(b.xc.x||c.xb.x)&&(b.yc.y||c.yb.y)},a.pathIntersection=function(a,b){return bH(a,b)},a.pathIntersectionNumber=function(a,b){return bH(a,b,1)},a.isPointInsidePath=function(b,c,d){var e=a.pathBBox(b);return a.isPointInsideBBox(e,c,d)&&bH(b,[["M",c,d],["H",e.x2+10]],1)%2==1},a._removedFactory=function(a){return function(){eve("raphael.log",null,"Raphaël: you are calling to method “"+a+"” of removed object",a)}};var bI=a.pathBBox=function(a){var b=bz(a);if(b.bbox)return b.bbox;if(!a)return{x:0,y:0,width:0,height:0,x2:0,y2:0};a=bR(a);var c=0,d=0,e=[],f=[],g;for(var h=0,i=a.length;h1&&(v=w.sqrt(v),c=v*c,d=v*d);var x=c*c,y=d*d,A=(f==g?-1:1)*w.sqrt(z((x*y-x*u*u-y*t*t)/(x*u*u+y*t*t))),C=A*c*u/d+(a+h)/2,D=A*-d*t/c+(b+i)/2,E=w.asin(((b-D)/d).toFixed(9)),F=w.asin(((i-D)/d).toFixed(9));E=aF&&(E=E-B*2),!g&&F>E&&(F=F-B*2)}else E=j[0],F=j[1],C=j[2],D=j[3];var G=F-E;if(z(G)>k){var H=F,I=h,J=i;F=E+k*(g&&F>E?1:-1),h=C+c*w.cos(F),i=D+d*w.sin(F),m=bO(h,i,c,d,e,0,g,I,J,[F,H,C,D])}G=F-E;var K=w.cos(E),L=w.sin(E),M=w.cos(F),N=w.sin(F),O=w.tan(G/4),P=4/3*c*O,Q=4/3*d*O,R=[a,b],S=[a+P*L,b-Q*K],T=[h+P*N,i-Q*M],U=[h,i];S[0]=2*R[0]-S[0],S[1]=2*R[1]-S[1];if(j)return[S,T,U][n](m);m=[S,T,U][n](m).join()[s](",");var V=[];for(var W=0,X=m.length;W"1e12"&&(l=.5),z(n)>"1e12"&&(n=.5),l>0&&l<1&&(q=bP(a,b,c,d,e,f,g,h,l),p.push(q.x),o.push(q.y)),n>0&&n<1&&(q=bP(a,b,c,d,e,f,g,h,n),p.push(q.x),o.push(q.y)),i=f-2*d+b-(h-2*f+d),j=2*(d-b)-2*(f-d),k=b-d,l=(-j+w.sqrt(j*j-4*i*k))/2/i,n=(-j-w.sqrt(j*j-4*i*k))/2/i,z(l)>"1e12"&&(l=.5),z(n)>"1e12"&&(n=.5),l>0&&l<1&&(q=bP(a,b,c,d,e,f,g,h,l),p.push(q.x),o.push(q.y)),n>0&&n<1&&(q=bP(a,b,c,d,e,f,g,h,n),p.push(q.x),o.push(q.y));return{min:{x:y[m](0,p),y:y[m](0,o)},max:{x:x[m](0,p),y:x[m](0,o)}}}),bR=a._path2curve=bv(function(a,b){var c=!b&&bz(a);if(!b&&c.curve)return bJ(c.curve);var d=bL(a),e=b&&bL(b),f={x:0,y:0,bx:0,by:0,X:0,Y:0,qx:null,qy:null},g={x:0,y:0,bx:0,by:0,X:0,Y:0,qx:null,qy:null},h=function(a,b){var c,d;if(!a)return["C",b.x,b.y,b.x,b.y,b.x,b.y];!(a[0]in{T:1,Q:1})&&(b.qx=b.qy=null);switch(a[0]){case"M":b.X=a[1],b.Y=a[2];break;case"A":a=["C"][n](bO[m](0,[b.x,b.y][n](a.slice(1))));break;case"S":c=b.x+(b.x-(b.bx||b.x)),d=b.y+(b.y-(b.by||b.y)),a=["C",c,d][n](a.slice(1));break;case"T":b.qx=b.x+(b.x-(b.qx||b.x)),b.qy=b.y+(b.y-(b.qy||b.y)),a=["C"][n](bN(b.x,b.y,b.qx,b.qy,a[1],a[2]));break;case"Q":b.qx=a[1],b.qy=a[2],a=["C"][n](bN(b.x,b.y,a[1],a[2],a[3],a[4]));break;case"L":a=["C"][n](bM(b.x,b.y,a[1],a[2]));break;case"H":a=["C"][n](bM(b.x,b.y,a[1],b.y));break;case"V":a=["C"][n](bM(b.x,b.y,b.x,a[1]));break;case"Z":a=["C"][n](bM(b.x,b.y,b.X,b.Y))}return a},i=function(a,b){if(a[b].length>7){a[b].shift();var c=a[b];while(c.length)a.splice(b++,0,["C"][n](c.splice(0,6)));a.splice(b,1),l=x(d.length,e&&e.length||0)}},j=function(a,b,c,f,g){a&&b&&a[g][0]=="M"&&b[g][0]!="M"&&(b.splice(g,0,["M",f.x,f.y]),c.bx=0,c.by=0,c.x=a[g][1],c.y=a[g][2],l=x(d.length,e&&e.length||0))};for(var k=0,l=x(d.length,e&&e.length||0);ke){if(c&&!l.start){m=cs(g,h,i[1],i[2],i[3],i[4],i[5],i[6],e-n),k+=["C"+m.start.x,m.start.y,m.m.x,m.m.y,m.x,m.y];if(f)return k;l.start=k,k=["M"+m.x,m.y+"C"+m.n.x,m.n.y,m.end.x,m.end.y,i[5],i[6]].join(),n+=j,g=+i[5],h=+i[6];continue}if(!b&&!c){m=cs(g,h,i[1],i[2],i[3],i[4],i[5],i[6],e-n);return{x:m.x,y:m.y,alpha:m.alpha}}}n+=j,g=+i[5],h=+i[6]}k+=i.shift()+i}l.end=k,m=b?n:c?l:a.findDotsAtSegment(g,h,i[0],i[1],i[2],i[3],i[4],i[5],1),m.alpha&&(m={x:m.x,y:m.y,alpha:m.alpha});return m}},cu=ct(1),cv=ct(),cw=ct(0,1);a.getTotalLength=cu,a.getPointAtLength=cv,a.getSubpath=function(a,b,c){if(this.getTotalLength(a)-c<1e-6)return cw(a,b).end;var d=cw(a,c,1);return b?cw(d,b).end:d},cl.getTotalLength=function(){if(this.type=="path"){if(this.node.getTotalLength)return this.node.getTotalLength();return cu(this.attrs.path)}},cl.getPointAtLength=function(a){if(this.type=="path")return cv(this.attrs.path,a)},cl.getSubpath=function(b,c){if(this.type=="path")return a.getSubpath(this.attrs.path,b,c)};var cx=a.easing_formulas={linear:function(a){return a},"<":function(a){return A(a,1.7)},">":function(a){return A(a,.48)},"<>":function(a){var b=.48-a/1.04,c=w.sqrt(.1734+b*b),d=c-b,e=A(z(d),1/3)*(d<0?-1:1),f=-c-b,g=A(z(f),1/3)*(f<0?-1:1),h=e+g+.5;return(1-h)*3*h*h+h*h*h},backIn:function(a){var b=1.70158;return a*a*((b+1)*a-b)},backOut:function(a){a=a-1;var b=1.70158;return a*a*((b+1)*a+b)+1},elastic:function(a){if(a==!!a)return a;return A(2,-10*a)*w.sin((a-.075)*2*B/.3)+1},bounce:function(a){var b=7.5625,c=2.75,d;a<1/c?d=b*a*a:a<2/c?(a-=1.5/c,d=b*a*a+.75):a<2.5/c?(a-=2.25/c,d=b*a*a+.9375):(a-=2.625/c,d=b*a*a+.984375);return d}};cx.easeIn=cx["ease-in"]=cx["<"],cx.easeOut=cx["ease-out"]=cx[">"],cx.easeInOut=cx["ease-in-out"]=cx["<>"],cx["back-in"]=cx.backIn,cx["back-out"]=cx.backOut;var cy=[],cz=window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||window.oRequestAnimationFrame||window.msRequestAnimationFrame||function(a){setTimeout(a,16)},cA=function(){var b=+(new Date),c=0;for(;c1&&!d.next){for(s in k)k[g](s)&&(r[s]=d.totalOrigin[s]);d.el.attr(r),cE(d.anim,d.el,d.anim.percents[0],null,d.totalOrigin,d.repeat-1)}d.next&&!d.stop&&cE(d.anim,d.el,d.next,null,d.totalOrigin,d.repeat)}}a.svg&&m&&m.paper&&m.paper.safari(),cy.length&&cz(cA)},cB=function(a){return a>255?255:a<0?0:a};cl.animateWith=function(b,c,d,e,f,g){var h=this;if(h.removed){g&&g.call(h);return h}var i=d instanceof cD?d:a.animation(d,e,f,g),j,k;cE(i,h,i.percents[0],null,h.attr());for(var l=0,m=cy.length;l.5)*2-1;i(m-.5,2)+i(n-.5,2)>.25&&(n=f.sqrt(.25-i(m-.5,2))*e+.5)&&n!=.5&&(n=n.toFixed(5)-1e-5*e)}return l}),e=e.split(/\s*\-\s*/);if(j=="linear"){var t=e.shift();t=-d(t);if(isNaN(t))return null;var u=[0,0,f.cos(a.rad(t)),f.sin(a.rad(t))],v=1/(g(h(u[2]),h(u[3]))||1);u[2]*=v,u[3]*=v,u[2]<0&&(u[0]=-u[2],u[2]=0),u[3]<0&&(u[1]=-u[3],u[3]=0)}var w=a._parseDots(e);if(!w)return null;k=k.replace(/[\(\)\s,\xb0#]/g,"_"),b.gradient&&k!=b.gradient.id&&(p.defs.removeChild(b.gradient),delete b.gradient);if(!b.gradient){s=q(j+"Gradient",{id:k}),b.gradient=s,q(s,j=="radial"?{fx:m,fy:n}:{x1:u[0],y1:u[1],x2:u[2],y2:u[3],gradientTransform:b.matrix.invert()}),p.defs.appendChild(s);for(var x=0,y=w.length;x1?G.opacity/100:G.opacity});case"stroke":G=a.getRGB(p),i.setAttribute(o,G.hex),o=="stroke"&&G[b]("opacity")&&q(i,{"stroke-opacity":G.opacity>1?G.opacity/100:G.opacity}),o=="stroke"&&d._.arrows&&("startString"in d._.arrows&&t(d,d._.arrows.startString),"endString"in d._.arrows&&t(d,d._.arrows.endString,1));break;case"gradient":(d.type=="circle"||d.type=="ellipse"||c(p).charAt()!="r")&&r(d,p);break;case"opacity":k.gradient&&!k[b]("stroke-opacity")&&q(i,{"stroke-opacity":p>1?p/100:p});case"fill-opacity":if(k.gradient){H=a._g.doc.getElementById(i.getAttribute("fill").replace(/^url\(#|\)$/g,l)),H&&(I=H.getElementsByTagName("stop"),q(I[I.length-1],{"stop-opacity":p}));break};default:o=="font-size"&&(p=e(p,10)+"px");var J=o.replace(/(\-.)/g,function(a){return a.substring(1).toUpperCase()});i.style[J]=p,d._.dirty=1,i.setAttribute(o,p)}}y(d,f),i.style.visibility=m},x=1.2,y=function(d,f){if(d.type=="text"&&!!(f[b]("text")||f[b]("font")||f[b]("font-size")||f[b]("x")||f[b]("y"))){var g=d.attrs,h=d.node,i=h.firstChild?e(a._g.doc.defaultView.getComputedStyle(h.firstChild,l).getPropertyValue("font-size"),10):10;if(f[b]("text")){g.text=f.text;while(h.firstChild)h.removeChild(h.firstChild);var j=c(f.text).split("\n"),k=[],m;for(var n=0,o=j.length;n"));var $=X.getBoundingClientRect();t.W=m.w=($.right-$.left)/Y,t.H=m.h=($.bottom-$.top)/Y,t.X=m.x,t.Y=m.y+t.H/2,("x"in i||"y"in i)&&(t.path.v=a.format("m{0},{1}l{2},{1}",f(m.x*u),f(m.y*u),f(m.x*u)+1));var _=["x","y","text","font","font-family","font-weight","font-style","font-size"];for(var ba=0,bb=_.length;ba.25&&(c=e.sqrt(.25-i(b-.5,2))*((c>.5)*2-1)+.5),m=b+n+c);return o}),f=f.split(/\s*\-\s*/);if(l=="linear"){var p=f.shift();p=-d(p);if(isNaN(p))return null}var q=a._parseDots(f);if(!q)return null;b=b.shape||b.node;if(q.length){b.removeChild(g),g.on=!0,g.method="none",g.color=q[0].color,g.color2=q[q.length-1].color;var r=[];for(var s=0,t=q.length;s')}}catch(c){F=function(a){return b.createElement("<"+a+' xmlns="urn:schemas-microsoft.com:vml" class="rvml">')}}},a._engine.initWin(a._g.win),a._engine.create=function(){var b=a._getContainer.apply(0,arguments),c=b.container,d=b.height,e,f=b.width,g=b.x,h=b.y;if(!c)throw new Error("VML container not found.");var i=new a._Paper,j=i.canvas=a._g.doc.createElement("div"),k=j.style;g=g||0,h=h||0,f=f||512,d=d||342,i.width=f,i.height=d,f==+f&&(f+="px"),d==+d&&(d+="px"),i.coordsize=u*1e3+n+u*1e3,i.coordorigin="0 0",i.span=a._g.doc.createElement("span"),i.span.style.cssText="position:absolute;left:-9999em;top:-9999em;padding:0;margin:0;line-height:1;",j.appendChild(i.span),k.cssText=a.format("top:0;left:0;width:{0};height:{1};display:inline-block;position:relative;clip:rect(0 {0} {1} 0);overflow:hidden",f,d),c==1?(a._g.doc.body.appendChild(j),k.left=g+"px",k.top=h+"px",k.position="absolute"):c.firstChild?c.insertBefore(j,c.firstChild):c.appendChild(j),i.renderfix=function(){};return i},a.prototype.clear=function(){a.eve("raphael.clear",this),this.canvas.innerHTML=o,this.span=a._g.doc.createElement("span"),this.span.style.cssText="position:absolute;left:-9999em;top:-9999em;padding:0;margin:0;line-height:1;display:inline;",this.canvas.appendChild(this.span),this.bottom=this.top=null},a.prototype.remove=function(){a.eve("raphael.remove",this),this.canvas.parentNode.removeChild(this.canvas);for(var b in this)this[b]=typeof this[b]=="function"?a._removedFactory(b):null;return!0};var G=a.st;for(var H in E)E[b](H)&&!G[b](H)&&(G[H]=function(a){return function(){var b=arguments;return this.forEach(function(c){c[a].apply(c,b)})}}(H))}(window.Raphael) diff --git a/public/javascripts/repository_navigation.js b/public/javascripts/repository_navigation.js new file mode 100644 index 00000000..511f2e6d --- /dev/null +++ b/public/javascripts/repository_navigation.js @@ -0,0 +1,33 @@ +$(document).ready(function() { + /* + If we're viewing a tag or branch, don't display it in the + revision box + */ + var branch_selected = $('#branch').length > 0 && $('#rev').val() == $('#branch').val(); + var tag_selected = $('#tag').length > 0 && $('#rev').val() == $('#tag').val(); + if (branch_selected || tag_selected) { + $('#rev').val(''); + } + + /* + Copy the branch/tag value into the revision box, then disable + the dropdowns before submitting the form + */ + $('#branch,#tag').change(function() { + $('#rev').val($(this).val()); + $('#branch,#tag').attr('disabled', true); + $(this).parent().submit(); + $('#branch,#tag').removeAttr('disabled'); + }); + + /* + Disable the branch/tag dropdowns before submitting the revision form + */ + $('#rev').keydown(function(e) { + if (e.keyCode == 13) { + $('#branch,#tag').attr('disabled', true); + $(this).parent().submit(); + $('#branch,#tag').removeAttr('disabled'); + } + }); +}) diff --git a/public/javascripts/revision_graph.js b/public/javascripts/revision_graph.js new file mode 100644 index 00000000..33843cc5 --- /dev/null +++ b/public/javascripts/revision_graph.js @@ -0,0 +1,94 @@ +var revisionGraph = null; + +function drawRevisionGraph(holder, commits_hash, graph_space) { + var XSTEP = 20, + CIRCLE_INROW_OFFSET = 10; + var commits_by_scmid = commits_hash, + commits = $.map(commits_by_scmid, function(val,i){return val;}); + var max_rdmid = commits.length - 1; + var commit_table_rows = $('table.changesets tr.changeset'); + + // create graph + if(revisionGraph != null) + revisionGraph.clear(); + else + revisionGraph = Raphael(holder); + + var top = revisionGraph.set(); + // init dimensions + var graph_x_offset = commit_table_rows.first().find('td').first().position().left - $(holder).position().left, + graph_y_offset = $(holder).position().top, + graph_right_side = graph_x_offset + (graph_space + 1) * XSTEP, + graph_bottom = commit_table_rows.last().position().top + commit_table_rows.last().height() - graph_y_offset; + + revisionGraph.setSize(graph_right_side, graph_bottom); + + // init colors + var colors = []; + Raphael.getColor.reset(); + for (var k = 0; k <= graph_space; k++) { + colors.push(Raphael.getColor()); + } + + var parent_commit; + var x, y, parent_x, parent_y; + var path, title; + var revision_dot_overlay; + $.each(commits, function(index, commit) { + if (!commit.hasOwnProperty("space")) + commit.space = 0; + + y = commit_table_rows.eq(max_rdmid - commit.rdmid).position().top - graph_y_offset + CIRCLE_INROW_OFFSET; + x = graph_x_offset + XSTEP / 2 + XSTEP * commit.space; + revisionGraph.circle(x, y, 3) + .attr({ + fill: colors[commit.space], + stroke: 'none' + }).toFront(); + // paths to parents + $.each(commit.parent_scmids, function(index, parent_scmid) { + parent_commit = commits_by_scmid[parent_scmid]; + if (parent_commit) { + if (!parent_commit.hasOwnProperty("space")) + parent_commit.space = 0; + + parent_y = commit_table_rows.eq(max_rdmid - parent_commit.rdmid).position().top - graph_y_offset + CIRCLE_INROW_OFFSET; + parent_x = graph_x_offset + XSTEP / 2 + XSTEP * parent_commit.space; + if (parent_commit.space == commit.space) { + // vertical path + path = revisionGraph.path([ + 'M', x, y, + 'V', parent_y]); + } else { + // path to a commit in a different branch (Bezier curve) + path = revisionGraph.path([ + 'M', x, y, + 'C', x, y, x, y + (parent_y - y) / 2, x + (parent_x - x) / 2, y + (parent_y - y) / 2, + 'C', x + (parent_x - x) / 2, y + (parent_y - y) / 2, parent_x, parent_y-(parent_y-y)/2, parent_x, parent_y]); + } + } else { + // vertical path ending at the bottom of the revisionGraph + path = revisionGraph.path([ + 'M', x, y, + 'V', graph_bottom]); + } + path.attr({stroke: colors[commit.space], "stroke-width": 1.5}).toBack(); + }); + revision_dot_overlay = revisionGraph.circle(x, y, 10); + revision_dot_overlay + .attr({ + fill: '#000', + opacity: 0, + cursor: 'pointer', + href: commit.href + }); + + if(commit.refs != null && commit.refs.length > 0) { + title = document.createElementNS(revisionGraph.canvas.namespaceURI, 'title'); + title.appendChild(document.createTextNode(commit.refs)); + revision_dot_overlay.node.appendChild(title); + } + top.push(revision_dot_overlay); + }); + top.toFront(); +}; diff --git a/public/javascripts/select_list_move.js b/public/javascripts/select_list_move.js new file mode 100644 index 00000000..7c87f8a0 --- /dev/null +++ b/public/javascripts/select_list_move.js @@ -0,0 +1,83 @@ +var NS4 = (navigator.appName == "Netscape" && parseInt(navigator.appVersion) < 5); + +function addOption(theSel, theText, theValue) +{ + var newOpt = new Option(theText, theValue); + var selLength = theSel.length; + theSel.options[selLength] = newOpt; +} + +function swapOptions(theSel, index1, index2) +{ + var text, value; + text = theSel.options[index1].text; + value = theSel.options[index1].value; + theSel.options[index1].text = theSel.options[index2].text; + theSel.options[index1].value = theSel.options[index2].value; + theSel.options[index2].text = text; + theSel.options[index2].value = value; +} + +function deleteOption(theSel, theIndex) +{ + var selLength = theSel.length; + if(selLength>0) + { + theSel.options[theIndex] = null; + } +} + +function moveOptions(theSelFrom, theSelTo) +{ + + var selLength = theSelFrom.length; + var selectedText = new Array(); + var selectedValues = new Array(); + var selectedCount = 0; + + var i; + + for(i=selLength-1; i>=0; i--) + { + if(theSelFrom.options[i].selected) + { + selectedText[selectedCount] = theSelFrom.options[i].text; + selectedValues[selectedCount] = theSelFrom.options[i].value; + deleteOption(theSelFrom, i); + selectedCount++; + } + } + + for(i=selectedCount-1; i>=0; i--) + { + addOption(theSelTo, selectedText[i], selectedValues[i]); + } + + if(NS4) history.go(0); +} + +function moveOptionUp(theSel) { + var index = theSel.selectedIndex; + if (index > 0) { + swapOptions(theSel, index-1, index); + theSel.selectedIndex = index-1; + } +} + +function moveOptionDown(theSel) { + var index = theSel.selectedIndex; + if (index < theSel.length - 1) { + swapOptions(theSel, index, index+1); + theSel.selectedIndex = index+1; + } +} + +// OK +function selectAllOptions(id) +{ + var select = $('#'+id);/* + for (var i=0; ibody #content { min-height: 600px; } +* html body #content { height: 600px; } /* IE */ + +#main.nosidebar #sidebar{ display: none; } +#main.nosidebar #content{ width: auto; border-right: 0; } + +#footer {clear: both; border-top: 1px solid #bbb; font-size: 0.9em; color: #aaa; padding: 5px; text-align:center; background:#fff;} + +#login-form table {margin-top:5em; padding:1em; margin-left: auto; margin-right: auto; border: 2px solid #FDBF3B; background-color:#FFEBC1; } +#login-form table td {padding: 6px;} +#login-form label {font-weight: bold;} +#login-form input#username, #login-form input#password { width: 300px; } + +div.modal { border-radius:5px; background:#fff; z-index:50; padding:4px;} +div.modal h3.title {display:none;} +div.modal p.buttons {text-align:right; margin-bottom:0;} + +input#openid_url { background: url(../images/openid-bg.gif) no-repeat; background-color: #fff; background-position: 0 50%; padding-left: 18px; } + +.clear:after{ content: "."; display: block; height: 0; clear: both; visibility: hidden; } + +/***** Links *****/ +a, a:link, a:visited{ color: #169; text-decoration: none; } +a:hover, a:active{ color: #c61a1a; text-decoration: underline;} +a img{ border: 0; } + +a.issue.closed, a.issue.closed:link, a.issue.closed:visited { color: #999; text-decoration: line-through; } +a.project.closed, a.project.closed:link, a.project.closed:visited { color: #999; } +a.user.locked, a.user.locked:link, a.user.locked:visited {color: #999;} + +#sidebar a.selected {line-height:1.7em; padding:1px 3px 2px 2px; margin-left:-2px; background-color:#9DB9D5; color:#fff; border-radius:2px;} +#sidebar a.selected:hover {text-decoration:none;} +#admin-menu a {line-height:1.7em;} +#admin-menu a.selected {padding-left: 20px !important; background-position: 2px 40%;} + +a.collapsible {padding-left: 12px; background: url(../images/arrow_expanded.png) no-repeat -3px 40%;} +a.collapsible.collapsed {background: url(../images/arrow_collapsed.png) no-repeat -5px 40%;} + +a#toggle-completed-versions {color:#999;} +/***** Tables *****/ +table.list { border: 1px solid #e4e4e4; border-collapse: collapse; width: 100%; margin-bottom: 4px; } +table.list th { background-color:#EEEEEE; padding: 4px; white-space:nowrap; } +table.list td { vertical-align: top; padding-right:10px; } +table.list td.id { width: 2%; text-align: center;} +table.list td.checkbox { width: 15px; padding: 2px 0 0 0; } +table.list td.checkbox input {padding:0px;} +table.list td.buttons { width: 15%; white-space:nowrap; text-align: right; } +table.list td.buttons a { padding-right: 0.6em; } +table.list caption { text-align: left; padding: 0.5em 0.5em 0.5em 0; } + +tr.project td.name a { white-space:nowrap; } +tr.project.closed, tr.project.archived { color: #aaa; } +tr.project.closed a, tr.project.archived a { color: #aaa; } + +tr.project.idnt td.name span {background: url(../images/bullet_arrow_right.png) no-repeat 0 50%; padding-left: 16px;} +tr.project.idnt-1 td.name {padding-left: 0.5em;} +tr.project.idnt-2 td.name {padding-left: 2em;} +tr.project.idnt-3 td.name {padding-left: 3.5em;} +tr.project.idnt-4 td.name {padding-left: 5em;} +tr.project.idnt-5 td.name {padding-left: 6.5em;} +tr.project.idnt-6 td.name {padding-left: 8em;} +tr.project.idnt-7 td.name {padding-left: 9.5em;} +tr.project.idnt-8 td.name {padding-left: 11em;} +tr.project.idnt-9 td.name {padding-left: 12.5em;} + +tr.issue { text-align: center; white-space: nowrap; } +tr.issue td.subject, tr.issue td.category, td.assigned_to, tr.issue td.string, tr.issue td.text, tr.issue td.relations { white-space: normal; } +tr.issue td.subject, tr.issue td.relations { text-align: left; } +tr.issue td.done_ratio table.progress { margin-left:auto; margin-right: auto;} +tr.issue td.relations span {white-space: nowrap;} +table.issues td.description {color:#777; font-size:90%; padding:4px 4px 4px 24px; text-align:left; white-space:normal;} +table.issues td.description pre {white-space:normal;} + +tr.issue.idnt td.subject a {background: url(../images/bullet_arrow_right.png) no-repeat 0 50%; padding-left: 16px;} +tr.issue.idnt-1 td.subject {padding-left: 0.5em;} +tr.issue.idnt-2 td.subject {padding-left: 2em;} +tr.issue.idnt-3 td.subject {padding-left: 3.5em;} +tr.issue.idnt-4 td.subject {padding-left: 5em;} +tr.issue.idnt-5 td.subject {padding-left: 6.5em;} +tr.issue.idnt-6 td.subject {padding-left: 8em;} +tr.issue.idnt-7 td.subject {padding-left: 9.5em;} +tr.issue.idnt-8 td.subject {padding-left: 11em;} +tr.issue.idnt-9 td.subject {padding-left: 12.5em;} + +tr.entry { border: 1px solid #f8f8f8; } +tr.entry td { white-space: nowrap; } +tr.entry td.filename { width: 30%; } +tr.entry td.filename_no_report { width: 70%; } +tr.entry td.size { text-align: right; font-size: 90%; } +tr.entry td.revision, tr.entry td.author { text-align: center; } +tr.entry td.age { text-align: right; } +tr.entry.file td.filename a { margin-left: 16px; } +tr.entry.file td.filename_no_report a { margin-left: 16px; } + +tr span.expander {background-image: url(../images/bullet_toggle_plus.png); padding-left: 8px; margin-left: 0; cursor: pointer;} +tr.open span.expander {background-image: url(../images/bullet_toggle_minus.png);} + +tr.changeset { height: 20px } +tr.changeset ul, ol { margin-top: 0px; margin-bottom: 0px; } +tr.changeset td.revision_graph { width: 15%; background-color: #fffffb; } +tr.changeset td.author { text-align: center; width: 15%; white-space:nowrap;} +tr.changeset td.committed_on { text-align: center; width: 15%; white-space:nowrap;} + +table.files tr.file td { text-align: center; } +table.files tr.file td.filename { text-align: left; padding-left: 24px; } +table.files tr.file td.digest { font-size: 80%; } + +table.members td.roles, table.memberships td.roles { width: 45%; } + +tr.message { height: 2.6em; } +tr.message td.subject { padding-left: 20px; } +tr.message td.created_on { white-space: nowrap; } +tr.message td.last_message { font-size: 80%; white-space: nowrap; } +tr.message.locked td.subject { background: url(../images/locked.png) no-repeat 0 1px; } +tr.message.sticky td.subject { background: url(../images/bullet_go.png) no-repeat 0 1px; font-weight: bold; } + +tr.version.closed, tr.version.closed a { color: #999; } +tr.version td.name { padding-left: 20px; } +tr.version.shared td.name { background: url(../images/link.png) no-repeat 0% 70%; } +tr.version td.date, tr.version td.status, tr.version td.sharing { text-align: center; white-space:nowrap; } + +tr.user td { width:13%; } +tr.user td.email { width:18%; } +tr.user td { white-space: nowrap; } +tr.user.locked, tr.user.registered { color: #aaa; } +tr.user.locked a, tr.user.registered a { color: #aaa; } + +table.permissions td.role {color:#999;font-size:90%;font-weight:normal !important;text-align:center;vertical-align:bottom;} + +tr.wiki-page-version td.updated_on, tr.wiki-page-version td.author {text-align:center;} + +tr.time-entry { text-align: center; white-space: nowrap; } +tr.time-entry td.issue, tr.time-entry td.comments { text-align: left; white-space: normal; } +td.hours { text-align: right; font-weight: bold; padding-right: 0.5em; } +td.hours .hours-dec { font-size: 0.9em; } + +table.plugins td { vertical-align: middle; } +table.plugins td.configure { text-align: right; padding-right: 1em; } +table.plugins span.name { font-weight: bold; display: block; margin-bottom: 6px; } +table.plugins span.description { display: block; font-size: 0.9em; } +table.plugins span.url { display: block; font-size: 0.9em; } + +table.list tbody tr.group td { padding: 0.8em 0 0.5em 0.3em; font-weight: bold; border-bottom: 1px solid #ccc; } +table.list tbody tr.group span.count {position:relative; top:-1px; color:#fff; font-size:10px; background:#9DB9D5; padding:0px 6px 1px 6px; border-radius:3px; margin-left:4px;} +tr.group a.toggle-all { color: #aaa; font-size: 80%; font-weight: normal; display:none;} +tr.group:hover a.toggle-all { display:inline;} +a.toggle-all:hover {text-decoration:none;} + +table.list tbody tr:hover { background-color:#ffffdd; } +table.list tbody tr.group:hover { background-color:inherit; } +table td {padding:2px;} +table p {margin:0;} +.odd {background-color:#f6f7f8;} +.even {background-color: #fff;} + +a.sort { padding-right: 16px; background-position: 100% 50%; background-repeat: no-repeat; } +a.sort.asc { background-image: url(../images/sort_asc.png); } +a.sort.desc { background-image: url(../images/sort_desc.png); } + +table.attributes { width: 100% } +table.attributes th { vertical-align: top; text-align: left; } +table.attributes td { vertical-align: top; } + +table.boards a.board, h3.comments { background: url(../images/comment.png) no-repeat 0% 50%; padding-left: 20px; } +table.boards td.topic-count, table.boards td.message-count {text-align:center;} +table.boards td.last-message {font-size:80%;} + +table.messages td.author, table.messages td.created_on, table.messages td.reply-count {text-align:center;} + +table.query-columns { + border-collapse: collapse; + border: 0; +} + +table.query-columns td.buttons { + vertical-align: middle; + text-align: center; +} + +td.center {text-align:center;} + +h3.version { background: url(../images/package.png) no-repeat 0% 50%; padding-left: 20px; } + +div.issues h3 { background: url(../images/ticket.png) no-repeat 0% 50%; padding-left: 20px; } +div.members h3 { background: url(../images/group.png) no-repeat 0% 50%; padding-left: 20px; } +div.news h3 { background: url(../images/news.png) no-repeat 0% 50%; padding-left: 20px; } +div.projects h3 { background: url(../images/projects.png) no-repeat 0% 50%; padding-left: 20px; } + +#watchers ul {margin: 0; padding: 0;} +#watchers li {list-style-type:none;margin: 0px 2px 0px 0px; padding: 0px 0px 0px 0px;} +#watchers select {width: 95%; display: block;} +#watchers a.delete {opacity: 0.4; vertical-align: middle;} +#watchers a.delete:hover {opacity: 1;} +#watchers img.gravatar {margin: 0 4px 2px 0;} + +span#watchers_inputs {overflow:auto; display:block;} +span.search_for_watchers {display:block;} +span.search_for_watchers, span.add_attachment {font-size:80%; line-height:2.5em;} +span.search_for_watchers a, span.add_attachment a {padding-left:16px; background: url(../images/bullet_add.png) no-repeat 0 50%; } + + +.highlight { background-color: #FCFD8D;} +.highlight.token-1 { background-color: #faa;} +.highlight.token-2 { background-color: #afa;} +.highlight.token-3 { background-color: #aaf;} + +.box{ + padding:6px; + margin-bottom: 10px; + background-color:#f6f6f6; + color:#505050; + line-height:1.5em; + border: 1px solid #e4e4e4; +} + +div.square { + border: 1px solid #999; + float: left; + margin: .3em .4em 0 .4em; + overflow: hidden; + width: .6em; height: .6em; +} +.contextual {float:right; white-space: nowrap; line-height:1.4em;margin-top:5px; padding-left: 10px; font-size:0.9em;} +.contextual input, .contextual select {font-size:0.9em;} +.message .contextual { margin-top: 0; } + +.splitcontent {overflow:auto;} +.splitcontentleft{float:left; width:49%;} +/*by young*/ + +.hotlist { +padding:0 15px 25px; +} +.splitcontentleft_{float:left; width:33%;} +.splitcontentright_{float:right; width:33%;} +.table{margin-top:10px;margin-left: 100px;} +.table_{margin-top:-10px; +margin-left:-10px; +} + +.splitcontentleft_{float:left; width:33%;} +.splitcontentright_{float:right; width:33%;} +.table{margin-top:10px;margin-left: 100px;} +.table_{margin-top:10px;} + +.table_font{font-size:20px;color:#DD0000} +.registerd_box{padding-left: 600px;} +.project_table{margin:0,0,0,0;margin-bottom:10px;background-color:#0ee;height:50px;} +.project_header_tag{float:right; color:#000000;} + +.project_right_tag{margin-top:44%;} +.project_homepage_tag{float:left; margin-top:9%;color:#000000;} +.project_infor_tag{float:auto;color:#000000;padding-left: 15px;} +.project_page_tag{float:right;color:#C0C0C0; font-family: Verdana;font-size: 13px;} +.wiki_text{font-size:small;color:#000000;} +.user_setting{float:right; color:#000000;padding-right: 10px;} +.line_color{color:#000000;} + +.project_right_tag{margin-top:40%;} +.project_homepage_tag{padding-left:570px;color:#000000;} +.project_infor_tag{float:auto;color:#000000;padding-left: 15px; } +.project_page_tag{float:right;color:#C0C0C0; font-family: Verdana;font-size: 13px;} +.wiki_text{font-size:small;color:#000000;} +.user_setting +{ + float:right; + color:#000000; + padding-right:10px; + background-color: #CCCCBB; + border-radius: 5px 5px 5px 5px; + color: rgb(58, 88, 125) !important; + padding: 0px 4px; + margin: 3px; + display: inline-block; + font-size: 11px; + text-decoration: none; + cursor: pointer; +} +.line_color{color:#000000;} +.project_description +{ + overflow: hidden; + text-overflow:ellipsis; + width:500px; + height:50px; +} + +#header a {font-family: Verdana, sans-serif; font-size: 12px; color:#808080;} +#login-form_new table +{ + padding:25px 28px; + background:#fff; + text-align:left; + + width:380px; + margin:10px auto; + margin-top:100px; + + width:410px; + margin:10px auto; + + font-family:lucida grande,verdana; + font-size:12px; + -webkit-border-radius:10px; + -moz-border-radius:10px; + border-radius:10px; + -moz-box-shadow:0 0 6px #039ea0; + -webkit-box-shadow:0 0 6px #039ea0; + box-shadow:0 0 6px #039ea0; + border:1px solid #AAA; + margin-left: 500px; +} +/*end*/ +.splitcontentright{float:right; width:49%;} +form {display: inline;} +input, select {vertical-align: middle; margin-top: 1px; margin-bottom: 1px;} +fieldset {border: 1px solid #e4e4e4; margin:0;} +legend {color: #484848;} +hr { width: 100%; height: 1px; background: #ccc; border: 0; color:#000000;} +blockquote { font-style: italic; border-left: 3px solid #e0e0e0; padding-left: 0.6em; margin-left: 2.4em;} +blockquote blockquote { margin-left: 0;} +acronym { border-bottom: 1px dotted; cursor: help; } +textarea.wiki-edit {width:99%; resize:vertical;} +li p {margin-top: 0;} +div.issue {background:#ffffdd; padding:6px; margin-bottom:6px;border: 1px solid #d7d7d7;} +p.breadcrumb { font-size: 0.9em; margin: 4px 0 4px 0;} +p.subtitle { font-size: 0.9em; margin: -6px 0 12px 0; font-style: italic; } +p.footnote { font-size: 0.9em; margin-top: 0px; margin-bottom: 0px; } + +div.issue div.subject div div { padding-left: 16px; } +div.issue div.subject p {margin: 0; margin-bottom: 0.1em; font-size: 90%; color: #999;} +div.issue div.subject>div>p { margin-top: 0.5em; } +div.issue div.subject h3 {margin: 0; margin-bottom: 0.1em;} +div.issue span.private { position:relative; bottom: 2px; text-transform: uppercase; background: #d22; color: #fff; font-weight:bold; padding: 0px 2px 0px 2px; font-size: 60%; margin-right: 2px; border-radius: 2px;} +div.issue .next-prev-links {color:#999;} +div.issue table.attributes th {width:22%;} +div.issue table.attributes td {width:28%;} + +#issue_tree table.issues, #relations table.issues { border: 0; } +#issue_tree td.checkbox, #relations td.checkbox {display:none;} +#relations td.buttons {padding:0;} + +fieldset.collapsible { border-width: 1px 0 0 0; font-size: 0.9em; } +fieldset.collapsible>legend { padding-left: 16px; background: url(../images/arrow_expanded.png) no-repeat 0% 40%; cursor:pointer; } +fieldset.collapsible.collapsed>legend { background-image: url(../images/arrow_collapsed.png); } + +fieldset#date-range p { margin: 2px 0 2px 0; } +fieldset#filters table { border-collapse: collapse; } +fieldset#filters table td { padding: 0; vertical-align: middle; } +fieldset#filters tr.filter { height: 2.1em; } +fieldset#filters td.field { width:230px; } +fieldset#filters td.operator { width:180px; } +fieldset#filters td.operator select {max-width:170px;} +fieldset#filters td.values { white-space:nowrap; } +fieldset#filters td.values select {min-width:130px;} +fieldset#filters td.values input {height:1em;} +fieldset#filters td.add-filter { text-align: right; vertical-align: top; } + +.toggle-multiselect {background: url(../images/bullet_toggle_plus.png) no-repeat 0% 40%; padding-left:8px; margin-left:0; cursor:pointer;} +.buttons { font-size: 0.9em; margin-bottom: 1.4em; margin-top: 1em; } + +div#issue-changesets {float:right; width:45%; margin-left: 1em; margin-bottom: 1em; background: #fff; padding-left: 1em; font-size: 90%;} +div#issue-changesets div.changeset { padding: 4px;} +div#issue-changesets div.changeset { border-bottom: 1px solid #ddd; } +div#issue-changesets p { margin-top: 0; margin-bottom: 1em;} + +.journal ul.details img {margin:0 0 -3px 4px;} +div.journal {overflow:auto;} +div.journal.private-notes {border-left:2px solid #d22; padding-left:4px; margin-left:-6px;} + +div#activity dl, #search-results { margin-left: 2em; } +div#activity dd, #search-results dd { margin-bottom: 1em; padding-left: 18px; font-size: 0.9em; } +div#activity dt, #search-results dt { margin-bottom: 0px; padding-left: 20px; line-height: 18px; background-position: 0 50%; background-repeat: no-repeat; } +div#activity dt.me .time { border-bottom: 1px solid #999; } +div#activity dt .time { color: #777; font-size: 80%; } +div#activity dd .description, #search-results dd .description { font-style: italic; } +div#activity span.project:after, #search-results span.project:after { content: " -"; } +div#activity dd span.description, #search-results dd span.description { display:block; color: #808080; } +div#activity dt.grouped {margin-left:5em;} +div#activity dd.grouped {margin-left:9em;} + +#search-results dd { margin-bottom: 1em; padding-left: 20px; margin-left:0px; } + +div#search-results-counts {float:right;} +div#search-results-counts ul { margin-top: 0.5em; } +div#search-results-counts li { list-style-type:none; float: left; margin-left: 1em; } + +dt.issue { background-image: url(../images/ticket.png); } +dt.issue-edit { background-image: url(../images/ticket_edit.png); } +dt.issue-closed { background-image: url(../images/ticket_checked.png); } +dt.issue-note { background-image: url(../images/ticket_note.png); } +dt.changeset { background-image: url(../images/changeset.png); } +dt.news { background-image: url(../images/news.png); } +dt.message { background-image: url(../images/message.png); } +dt.reply { background-image: url(../images/comments.png); } +dt.wiki-page { background-image: url(../images/wiki_edit.png); } +dt.attachment { background-image: url(../images/attachment.png); } +dt.document { background-image: url(../images/document.png); } +dt.project { background-image: url(../images/projects.png); } +dt.time-entry { background-image: url(../images/time.png); } + +#search-results dt.issue.closed { background-image: url(../images/ticket_checked.png); } + +div#roadmap .related-issues { margin-bottom: 1em; } +div#roadmap .related-issues td.checkbox { display: none; } +div#roadmap .wiki h1:first-child { display: none; } +div#roadmap .wiki h1 { font-size: 120%; } +div#roadmap .wiki h2 { font-size: 110%; } +body.controller-versions.action-show div#roadmap .related-issues {width:70%;} + +div#version-summary { float:right; width:28%; margin-left: 16px; margin-bottom: 16px; background-color: #fff; } +div#version-summary fieldset { margin-bottom: 1em; } +div#version-summary fieldset.time-tracking table { width:100%; } +div#version-summary th, div#version-summary td.total-hours { text-align: right; } + +table#time-report td.hours, table#time-report th.period, table#time-report th.total { text-align: right; padding-right: 0.5em; } +table#time-report tbody tr.subtotal { font-style: italic; color:#777;} +table#time-report tbody tr.subtotal td.hours { color:#b0b0b0; } +table#time-report tbody tr.total { font-weight: bold; background-color:#EEEEEE; border-top:1px solid #e4e4e4;} +table#time-report .hours-dec { font-size: 0.9em; } + +div.wiki-page .contextual a {opacity: 0.4} +div.wiki-page .contextual a:hover {opacity: 1} + +form .attributes select { width: 60%; } +input#issue_subject { width: 99%; } +select#issue_done_ratio { width: 95px; } + +ul.projects {margin:0px; padding-left:0em;}/*1em*/ +ul.projects ul {padding-left:1.6em;} +ul.projects.root {margin:0; padding:0;} + +ul.projects li {list-style-type:none;} + +ul.projects li {list-style-type:none; + + } + + +#projects-index ul.projects ul.projects { border-left: 3px solid #e0e0e0; padding-left:1em;} +#projects-index ul.projects li.root {margin-bottom: 1em;} +#projects-index ul.projects li.child {margin-top: 1em;} +#projects-index ul.projects div.root a.project {font-family: "Trebuchet MS", Verdana, sans-serif; font-weight: bold; font-size: 16px; margin: 0 0 10px 0; } +.my-project { padding-left: 18px; background: url(../images/fav.png) no-repeat 0 50%; } + +#notified-projects ul, #tracker_project_ids ul {max-height:250px; overflow-y:auto;} + +#related-issues li img {vertical-align:middle;} + +ul.properties {padding:0; font-size: 0.9em; color: #777;} +ul.properties li {list-style-type:none;} +ul.properties li span {font-style:italic;} + +.total-hours { font-size: 110%; font-weight: bold; } +.total-hours span.hours-int { font-size: 120%; } + +.autoscroll {overflow-x: auto; padding:1px; margin-bottom: 1.2em;} +#user_login, #user_firstname, #user_lastname, #user_mail, #my_account_form select, #user_form select, #user_identity_url { width: 60%; } + +#workflow_copy_form select { width: 200px; } +table.transitions td.enabled {background: #bfb;} +table.fields_permissions select {font-size:90%} +table.fields_permissions td.readonly {background:#ddd;} +table.fields_permissions td.required {background:#d88;} + +textarea#custom_field_possible_values {width: 99%} +textarea#custom_field_default_value {width: 99%} + +input#content_comments {width: 99%} + +p.pagination {margin-top:8px; font-size: 90%} + +/***** Tabular forms ******/ +.tabular p{ + margin: 0; + padding: 3px 0 3px 0; + padding-left: 100px; /* width of left column containing the label elements *//*by young*/ + min-height: 1.8em; + clear:left; +} + +html>body .tabular p {overflow:hidden;} + +.tabular label{ + font-weight: bold; + float: left; + text-align: right; + /* width of left column */ + margin-left: -180px; + /* width of labels. Should be smaller than left column to create some right margin */ + width: 175px; +} + +.tabular label.floating{ + font-weight: normal; + margin-left: 0px; + text-align: left; + width: 270px; +} + +.tabular label.block{ + font-weight: normal; + margin-left: 0px !important; + text-align: left; + float: none; + display: block; + width: auto; +} + +.tabular label.inline{ + font-weight: normal; + float:none; + margin-left: 5px !important; + width: auto; +} + +label.no-css { + font-weight: inherit; + float:none; + text-align:left; + margin-left:0px; + width:auto; +} +input#time_entry_comments { width: 90%;} + +#preview fieldset {margin-top: 1em; background: url(../images/draft.png)} + +.tabular.settings p{ padding-left: 300px; } +.tabular.settings label{ margin-left: -300px; width: 295px; } +.tabular.settings textarea { width: 99%; } + +.settings.enabled_scm table {width:100%} +.settings.enabled_scm td.scm_name{ font-weight: bold; } + +fieldset.settings label { display: block; } +fieldset#notified_events .parent { padding-left: 20px; } + +span.required {color: #bb0000;} +.summary {font-style: italic;} + +#attachments_fields input.description {margin-left:4px; width:340px;} +#attachments_fields span {display:block; white-space:nowrap;} +#attachments_fields input.filename {border:0; height:1.8em; width:250px; color:#555; background-color:inherit; background:url(../images/attachment.png) no-repeat 1px 50%; padding-left:18px;} +#attachments_fields .ajax-waiting input.filename {background:url(../images/hourglass.png) no-repeat 0px 50%;} +#attachments_fields .ajax-loading input.filename {background:url(../images/loading.gif) no-repeat 0px 50%;} +#attachments_fields div.ui-progressbar { width: 100px; height:14px; margin: 2px 0 -5px 8px; display: inline-block; } +a.remove-upload {background: url(../images/delete.png) no-repeat 1px 50%; width:1px; display:inline-block; padding-left:16px;} +a.remove-upload:hover {text-decoration:none !important;} + +div.fileover { background-color: lavender; } + +div.attachments { margin-top: 12px; } +div.attachments p { margin:4px 0 2px 0; } +div.attachments img { vertical-align: middle; } +div.attachments span.author { font-size: 0.9em; color: #888; } + +div.thumbnails {margin-top:0.6em;} +div.thumbnails div {background:#fff;border:2px solid #ddd;display:inline-block;margin-right:2px;} +div.thumbnails img {margin: 3px;} + +p.other-formats { text-align: right; font-size:0.9em; color: #666; } +.other-formats span + span:before { content: "| "; } + +a.atom { background: url(../images/feed.png) no-repeat 1px 50%; padding: 2px 0px 3px 16px; } + +em.info {font-style:normal;font-size:90%;color:#888;display:block;} +em.info.error {padding-left:20px; background:url(../images/exclamation.png) no-repeat 0 50%;} + +textarea.text_cf {width:90%;} + +#tab-content-modules fieldset p {margin:3px 0 4px 0;} + +#tab-content-members .splitcontentleft, #tab-content-memberships .splitcontentleft, #tab-content-users .splitcontentleft {width: 64%;} +#tab-content-members .splitcontentright, #tab-content-memberships .splitcontentright, #tab-content-users .splitcontentright {width: 34%;} +#tab-content-members fieldset, #tab-content-memberships fieldset, #tab-content-users fieldset {padding:1em; margin-bottom: 1em;} +#tab-content-members fieldset legend, #tab-content-memberships fieldset legend, #tab-content-users fieldset legend {font-weight: bold;} +#tab-content-members fieldset label, #tab-content-memberships fieldset label, #tab-content-users fieldset label {display: block;} +#tab-content-members #principals, #tab-content-users #principals {max-height: 400px; overflow: auto;} + +#users_for_watcher {height: 200px; overflow:auto;} +#users_for_watcher label {display: block;} + +table.members td.group { padding-left: 20px; background: url(../images/group.png) no-repeat 0% 50%; } + +input#principal_search, input#user_search {width:90%} + +input.autocomplete { + background: #fff url(../images/magnifier.png) no-repeat 2px 50%; padding-left:20px; + border:1px solid #9EB1C2; border-radius:2px; height:1.5em; +} +input.autocomplete.ajax-loading { + background-image: url(../images/loading.gif); +} + +/***** Flash & error messages ****/ +#errorExplanation, div.flash, .nodata, .warning, .conflict { + padding: 4px 4px 4px 30px; + margin-bottom: 12px; + font-size: 1.1em; + border: 2px solid; +} + +div.flash {margin-top: 8px;} + +div.flash.error, #errorExplanation { + background: url(../images/exclamation.png) 8px 50% no-repeat; + background-color: #ffe3e3; + border-color: #dd0000; + color: #880000; +} + +div.flash.notice { + background: url(../images/true.png) 8px 5px no-repeat; + background-color: #dfffdf; + border-color: #9fcf9f; + color: #005f00; +} + +div.flash.warning, .conflict { + background: url(../images/warning.png) 8px 5px no-repeat; + background-color: #FFEBC1; + border-color: #FDBF3B; + color: #A6750C; + text-align: left; +} + +.nodata, .warning { + text-align: center; + background-color: #FFEBC1; + border-color: #FDBF3B; + color: #A6750C; +} + +#errorExplanation ul { font-size: 0.9em;} +#errorExplanation h2, #errorExplanation p { display: none; } + +.conflict-details {font-size:80%;} + +/***** Ajax indicator ******/ +#ajax-indicator { +position: absolute; /* fixed not supported by IE */ +background-color:#eee; +border: 1px solid #bbb; +top:35%; +left:40%; +width:20%; +font-weight:bold; +text-align:center; +padding:0.6em; +z-index:100; +opacity: 0.5; +} + +html>body #ajax-indicator { position: fixed; } + +#ajax-indicator span { +background-position: 0% 40%; +background-repeat: no-repeat; +background-image: url(../images/loading.gif); +padding-left: 26px; +vertical-align: bottom; +} + +/***** Calendar *****/ +table.cal {border-collapse: collapse; width: 100%; margin: 0px 0 6px 0;border: 1px solid #d7d7d7;} +table.cal thead th {width: 14%; background-color:#EEEEEE; padding: 4px; } +table.cal thead th.week-number {width: auto;} +table.cal tbody tr {height: 100px;} +table.cal td {border: 1px solid #d7d7d7; vertical-align: top; font-size: 0.9em;} +table.cal td.week-number { background-color:#EEEEEE; padding: 4px; border:none; font-size: 1em;} +table.cal td p.day-num {font-size: 1.1em; text-align:right;} +table.cal td.odd p.day-num {color: #bbb;} +table.cal td.today {background:#ffffdd;} +table.cal td.today p.day-num {font-weight: bold;} +table.cal .starting a, p.cal.legend .starting {background: url(../images/bullet_go.png) no-repeat -1px -2px; padding-left:16px;} +table.cal .ending a, p.cal.legend .ending {background: url(../images/bullet_end.png) no-repeat -1px -2px; padding-left:16px;} +table.cal .starting.ending a, p.cal.legend .starting.ending {background: url(../images/bullet_diamond.png) no-repeat -1px -2px; padding-left:16px;} +p.cal.legend span {display:block;} + +/***** Tooltips ******/ +.tooltip{position:relative;z-index:24;} +.tooltip:hover{z-index:25;color:#000;} +.tooltip span.tip{display: none; text-align:left;} + +div.tooltip:hover span.tip{ +display:block; +position:absolute; +top:12px; left:24px; width:270px; +border:1px solid #555; +background-color:#fff; +padding: 4px; +font-size: 0.8em; +color:#505050; +} + +img.ui-datepicker-trigger { + cursor: pointer; + vertical-align: middle; + margin-left: 4px; +} + +/***** Progress bar *****/ +table.progress { + border-collapse: collapse; + border-spacing: 0pt; + empty-cells: show; + text-align: center; + float:left; + margin: 1px 6px 1px 0px; +} + +table.progress td { height: 1em; } +table.progress td.closed { background: #BAE0BA none repeat scroll 0%; } +table.progress td.done { background: #D3EDD3 none repeat scroll 0%; } +table.progress td.todo { background: #eee none repeat scroll 0%; } +p.percent {font-size: 80%;} +p.progress-info {clear: left; font-size: 80%; margin-top:-4px; color:#777;} + +#roadmap table.progress td { height: 1.2em; } +/***** Tabs *****/ +#content .tabs {height: 2.6em; margin-bottom:1.2em; position:relative; overflow:hidden;} +#content .tabs ul {margin:0; position:absolute; bottom:0; padding-left:0.5em; width: 2000px; border-bottom: 1px solid #bbbbbb;} +#content .tabs ul li { + float:left; + list-style-type:none; + white-space:nowrap; + margin-right:4px; + background:#fff; + position:relative; + margin-bottom:-1px; +} +#content .tabs ul li a{ + display:block; + font-size: 0.9em; + text-decoration:none; + line-height:1.3em; + padding:4px 6px 4px 6px; + border: 1px solid #ccc; + border-bottom: 1px solid #bbbbbb; + background-color: #f6f6f6; + color:#999; + font-weight:bold; + border-top-left-radius:3px; + border-top-right-radius:3px; +} + +#content .tabs ul li a:hover { + background-color: #cacbcb; + text-decoration:none; +} + +#content .tabs ul li a.selected { + background-color: #fff; + border: 1px solid #bbbbbb; + border-bottom: 1px solid #fff; + color:#111; +} + +#content .tabs ul li a.selected:hover {background-color: #fff;} + +div.tabs-buttons { position:absolute; right: 0; width: 48px; height: 24px; background: white; bottom: 0; border-bottom: 1px solid #bbbbbb; } + +button.tab-left, button.tab-right { + font-size: 0.9em; + cursor: pointer; + height:24px; + border: 1px solid #ccc; + border-bottom: 1px solid #bbbbbb; + position:absolute; + padding:4px; + width: 20px; + bottom: -1px; +} + +button.tab-left { + right: 20px; + background: #eeeeee url(../images/bullet_arrow_left.png) no-repeat 50% 50%; + border-top-left-radius:3px; +} + +button.tab-right { + right: 0; + background: #eeeeee url(../images/bullet_arrow_right.png) no-repeat 50% 50%; + border-top-right-radius:3px; +} + +/***** Diff *****/ +.diff_out { background: #fcc; } +.diff_out span { background: #faa; } +.diff_in { background: #cfc; } +.diff_in span { background: #afa; } + +.text-diff { + padding: 1em; + background-color:#f6f6f6; + color:#505050; + border: 1px solid #e4e4e4; +} + +/***** Wiki *****/ +div.wiki table { + border-collapse: collapse; + margin-bottom: 1em; +} + +div.wiki table, div.wiki td, div.wiki th { + border: 1px solid #bbb; + padding: 4px; +} + +div.wiki .noborder, div.wiki .noborder td, div.wiki .noborder th {border:0;} + +div.wiki .external { + background-position: 0% 60%; + background-repeat: no-repeat; + padding-left: 12px; + background-image: url(../images/external.png); +} + +div.wiki a.new {color: #b73535;} + +div.wiki ul, div.wiki ol {margin-bottom:1em;} + +div.wiki pre { + margin: 1em 1em 1em 1.6em; + padding: 8px; + background-color: #fafafa; + border: 1px solid #e2e2e2; + width:auto; + overflow-x: auto; + overflow-y: hidden; +} + +div.wiki ul.toc { + background-color: #ffffdd; + border: 1px solid #e4e4e4; + padding: 4px; + line-height: 1.2em; + margin-bottom: 12px; + margin-right: 12px; + margin-left: 0; + display: table +} +* html div.wiki ul.toc { width: 50%; } /* IE6 doesn't autosize div */ + +div.wiki ul.toc.right { float: right; margin-left: 12px; margin-right: 0; width: auto; } +div.wiki ul.toc.left { float: left; margin-right: 12px; margin-left: 0; width: auto; } +div.wiki ul.toc ul { margin: 0; padding: 0; } +div.wiki ul.toc li {list-style-type:none; margin: 0; font-size:12px;} +div.wiki ul.toc li li {margin-left: 1.5em; font-size:10px;} +div.wiki ul.toc a { + font-size: 0.9em; + font-weight: normal; + text-decoration: none; + color: #606060; +} +div.wiki ul.toc a:hover { color: #c61a1a; text-decoration: underline;} + +a.wiki-anchor { display: none; margin-left: 6px; text-decoration: none; } +a.wiki-anchor:hover { color: #aaa !important; text-decoration: none; } +h1:hover a.wiki-anchor, h2:hover a.wiki-anchor, h3:hover a.wiki-anchor { display: inline; color: #ddd; } + +div.wiki img { vertical-align: middle; } + +/***** My page layout *****/ +.block-receiver { + border:1px dashed #c0c0c0; + margin-bottom: 20px; + padding: 15px 0 15px 0; +} + +.mypage-box { + margin:0 0 20px 0; + color:#505050; + line-height:1.5em; +} + +.handle {cursor: move;} + +a.close-icon { + display:block; + margin-top:3px; + overflow:hidden; + width:12px; + height:12px; + background-repeat: no-repeat; + cursor:pointer; + background-image:url('../images/close.png'); +} +a.close-icon:hover {background-image:url('../images/close_hl.png');} + +/***** Gantt chart *****/ +.gantt_hdr { + position:absolute; + top:0; + height:16px; + border-top: 1px solid #c0c0c0; + border-bottom: 1px solid #c0c0c0; + border-right: 1px solid #c0c0c0; + text-align: center; + overflow: hidden; +} + +.gantt_hdr.nwday {background-color:#f1f1f1;} + +.gantt_subjects { font-size: 0.8em; } +.gantt_subjects div { line-height:16px;height:16px;overflow:hidden;white-space:nowrap;text-overflow: ellipsis; } + +.task { + position: absolute; + height:8px; + font-size:0.8em; + color:#888; + padding:0; + margin:0; + line-height:16px; + white-space:nowrap; +} + +.task.label {width:100%;} +.task.label.project, .task.label.version { font-weight: bold; } + +.task_late { background:#f66 url(../images/task_late.png); border: 1px solid #f66; } +.task_done { background:#00c600 url(../images/task_done.png); border: 1px solid #00c600; } +.task_todo { background:#aaa url(../images/task_todo.png); border: 1px solid #aaa; } + +.task_todo.parent { background: #888; border: 1px solid #888; height: 3px;} +.task_late.parent, .task_done.parent { height: 3px;} +.task.parent.marker.starting { position: absolute; background: url(../images/task_parent_end.png) no-repeat 0 0; width: 8px; height: 16px; margin-left: -4px; left: 0px; top: -1px;} +.task.parent.marker.ending { position: absolute; background: url(../images/task_parent_end.png) no-repeat 0 0; width: 8px; height: 16px; margin-left: -4px; right: 0px; top: -1px;} + +.version.task_late { background:#f66 url(../images/milestone_late.png); border: 1px solid #f66; height: 2px; margin-top: 3px;} +.version.task_done { background:#00c600 url(../images/milestone_done.png); border: 1px solid #00c600; height: 2px; margin-top: 3px;} +.version.task_todo { background:#fff url(../images/milestone_todo.png); border: 1px solid #fff; height: 2px; margin-top: 3px;} +.version.marker { background-image:url(../images/version_marker.png); background-repeat: no-repeat; border: 0; margin-left: -4px; margin-top: 1px; } + +.project.task_late { background:#f66 url(../images/milestone_late.png); border: 1px solid #f66; height: 2px; margin-top: 3px;} +.project.task_done { background:#00c600 url(../images/milestone_done.png); border: 1px solid #00c600; height: 2px; margin-top: 3px;} +.project.task_todo { background:#fff url(../images/milestone_todo.png); border: 1px solid #fff; height: 2px; margin-top: 3px;} +.project.marker { background-image:url(../images/project_marker.png); background-repeat: no-repeat; border: 0; margin-left: -4px; margin-top: 1px; } + +.version-behind-schedule a, .issue-behind-schedule a {color: #f66914;} +.version-overdue a, .issue-overdue a, .project-overdue a {color: #f00;} + +/***** Icons *****/ +.icon { + background-position: 0% 50%; + background-repeat: no-repeat; + padding-left: 20px; + padding-top: 2px; + padding-bottom: 3px; +} + +.icon-add { background-image: url(../images/add.png); } +.icon-edit { background-image: url(../images/edit.png); } +.icon-copy { background-image: url(../images/copy.png); } +.icon-duplicate { background-image: url(../images/duplicate.png); } +.icon-del { background-image: url(../images/delete.png); } +.icon-move { background-image: url(../images/move.png); } +.icon-save { background-image: url(../images/save.png); } +.icon-cancel { background-image: url(../images/cancel.png); } +.icon-multiple { background-image: url(../images/table_multiple.png); } +.icon-folder { background-image: url(../images/folder.png); } +.open .icon-folder { background-image: url(../images/folder_open.png); } +.icon-package { background-image: url(../images/package.png); } +.icon-user { background-image: url(../images/user.png); } +.icon-projects { background-image: url(../images/projects.png); } +.icon-help { background-image: url(../images/help.png); } +.icon-attachment { background-image: url(../images/attachment.png); } +.icon-history { background-image: url(../images/history.png); } +.icon-time { background-image: url(../images/time.png); } +.icon-time-add { background-image: url(../images/time_add.png); } +.icon-stats { background-image: url(../images/stats.png); } +.icon-warning { background-image: url(../images/warning.png); } +.icon-fav { background-image: url(../images/fav.png); } +.icon-fav-off { background-image: url(../images/fav_off.png); } +.icon-reload { background-image: url(../images/reload.png); } +.icon-lock { background-image: url(../images/locked.png); } +.icon-unlock { background-image: url(../images/unlock.png); } +.icon-checked { background-image: url(../images/true.png); } +.icon-details { background-image: url(../images/zoom_in.png); } +.icon-report { background-image: url(../images/report.png); } +.icon-comment { background-image: url(../images/comment.png); } +.icon-summary { background-image: url(../images/lightning.png); } +.icon-server-authentication { background-image: url(../images/server_key.png); } +.icon-issue { background-image: url(../images/ticket.png); } +.icon-zoom-in { background-image: url(../images/zoom_in.png); } +.icon-zoom-out { background-image: url(../images/zoom_out.png); } +.icon-passwd { background-image: url(../images/textfield_key.png); } +.icon-test { background-image: url(../images/bullet_go.png); } + +.icon-file { background-image: url(../images/files/default.png); } +.icon-file.text-plain { background-image: url(../images/files/text.png); } +.icon-file.text-x-c { background-image: url(../images/files/c.png); } +.icon-file.text-x-csharp { background-image: url(../images/files/csharp.png); } +.icon-file.text-x-java { background-image: url(../images/files/java.png); } +.icon-file.text-x-javascript { background-image: url(../images/files/js.png); } +.icon-file.text-x-php { background-image: url(../images/files/php.png); } +.icon-file.text-x-ruby { background-image: url(../images/files/ruby.png); } +.icon-file.text-xml { background-image: url(../images/files/xml.png); } +.icon-file.text-css { background-image: url(../images/files/css.png); } +.icon-file.text-html { background-image: url(../images/files/html.png); } +.icon-file.image-gif { background-image: url(../images/files/image.png); } +.icon-file.image-jpeg { background-image: url(../images/files/image.png); } +.icon-file.image-png { background-image: url(../images/files/image.png); } +.icon-file.image-tiff { background-image: url(../images/files/image.png); } +.icon-file.application-pdf { background-image: url(../images/files/pdf.png); } +.icon-file.application-zip { background-image: url(../images/files/zip.png); } +.icon-file.application-x-gzip { background-image: url(../images/files/zip.png); } + +img.gravatar { + padding: 2px; + border: solid 1px #d5d5d5; + background: #fff; + vertical-align: middle; +} + +div.issue img.gravatar { + float: left; + margin: 0 6px 0 0; + padding: 5px; +} + +div.issue table img.gravatar { + height: 14px; + width: 14px; + padding: 2px; + float: left; + margin: 0 0.5em 0 0; +} + +h2 img.gravatar {margin: -2px 4px -4px 0;} +h3 img.gravatar {margin: -4px 4px -4px 0;} +h4 img.gravatar {margin: -6px 4px -4px 0;} +td.username img.gravatar {margin: 0 0.5em 0 0; vertical-align: top;} +#activity dt img.gravatar {float: left; margin: 0 1em 1em 0;} +/* Used on 12px Gravatar img tags without the icon background */ +.icon-gravatar {float: left; margin-right: 4px;} + +#activity dt, .journal {clear: left;} + +.journal-link {float: right;} + +h2 img { vertical-align:middle; } + +.hascontextmenu { cursor: context-menu; } + +/************* CodeRay styles *************/ +.syntaxhl div {display: inline;} +.syntaxhl .line-numbers {padding: 2px 4px 2px 4px; background-color: #eee; margin:0px 5px 0px 0px;} +.syntaxhl .code pre { overflow: auto } +.syntaxhl .debug { color: white !important; background: blue !important; } + +.syntaxhl .annotation { color:#007 } +.syntaxhl .attribute-name { color:#b48 } +.syntaxhl .attribute-value { color:#700 } +.syntaxhl .binary { color:#509 } +.syntaxhl .char .content { color:#D20 } +.syntaxhl .char .delimiter { color:#710 } +.syntaxhl .char { color:#D20 } +.syntaxhl .class { color:#258; font-weight:bold } +.syntaxhl .class-variable { color:#369 } +.syntaxhl .color { color:#0A0 } +.syntaxhl .comment { color:#385 } +.syntaxhl .comment .char { color:#385 } +.syntaxhl .comment .delimiter { color:#385 } +.syntaxhl .complex { color:#A08 } +.syntaxhl .constant { color:#258; font-weight:bold } +.syntaxhl .decorator { color:#B0B } +.syntaxhl .definition { color:#099; font-weight:bold } +.syntaxhl .delimiter { color:black } +.syntaxhl .directive { color:#088; font-weight:bold } +.syntaxhl .doc { color:#970 } +.syntaxhl .doc-string { color:#D42; font-weight:bold } +.syntaxhl .doctype { color:#34b } +.syntaxhl .entity { color:#800; font-weight:bold } +.syntaxhl .error { color:#F00; background-color:#FAA } +.syntaxhl .escape { color:#666 } +.syntaxhl .exception { color:#C00; font-weight:bold } +.syntaxhl .float { color:#06D } +.syntaxhl .function { color:#06B; font-weight:bold } +.syntaxhl .global-variable { color:#d70 } +.syntaxhl .hex { color:#02b } +.syntaxhl .imaginary { color:#f00 } +.syntaxhl .include { color:#B44; font-weight:bold } +.syntaxhl .inline { background-color: hsla(0,0%,0%,0.07); color: black } +.syntaxhl .inline-delimiter { font-weight: bold; color: #666 } +.syntaxhl .instance-variable { color:#33B } +.syntaxhl .integer { color:#06D } +.syntaxhl .key .char { color: #60f } +.syntaxhl .key .delimiter { color: #404 } +.syntaxhl .key { color: #606 } +.syntaxhl .keyword { color:#939; font-weight:bold } +.syntaxhl .label { color:#970; font-weight:bold } +.syntaxhl .local-variable { color:#963 } +.syntaxhl .namespace { color:#707; font-weight:bold } +.syntaxhl .octal { color:#40E } +.syntaxhl .operator { } +.syntaxhl .predefined { color:#369; font-weight:bold } +.syntaxhl .predefined-constant { color:#069 } +.syntaxhl .predefined-type { color:#0a5; font-weight:bold } +.syntaxhl .preprocessor { color:#579 } +.syntaxhl .pseudo-class { color:#00C; font-weight:bold } +.syntaxhl .regexp .content { color:#808 } +.syntaxhl .regexp .delimiter { color:#404 } +.syntaxhl .regexp .modifier { color:#C2C } +.syntaxhl .regexp { background-color:hsla(300,100%,50%,0.06); } +.syntaxhl .reserved { color:#080; font-weight:bold } +.syntaxhl .shell .content { color:#2B2 } +.syntaxhl .shell .delimiter { color:#161 } +.syntaxhl .shell { background-color:hsla(120,100%,50%,0.06); } +.syntaxhl .string .char { color: #46a } +.syntaxhl .string .content { color: #46a } +.syntaxhl .string .delimiter { color: #46a } +.syntaxhl .string .modifier { color: #46a } +.syntaxhl .symbol .content { color:#d33 } +.syntaxhl .symbol .delimiter { color:#d33 } +.syntaxhl .symbol { color:#d33 } +.syntaxhl .tag { color:#070 } +.syntaxhl .type { color:#339; font-weight:bold } +.syntaxhl .value { color: #088; } +.syntaxhl .variable { color:#037 } + +.syntaxhl .insert { background: hsla(120,100%,50%,0.12) } +.syntaxhl .delete { background: hsla(0,100%,50%,0.12) } +.syntaxhl .change { color: #bbf; background: #007; } +.syntaxhl .head { color: #f8f; background: #505 } +.syntaxhl .head .filename { color: white; } + +.syntaxhl .delete .eyecatcher { background-color: hsla(0,100%,50%,0.2); border: 1px solid hsla(0,100%,45%,0.5); margin: -1px; border-bottom: none; border-top-left-radius: 5px; border-top-right-radius: 5px; } +.syntaxhl .insert .eyecatcher { background-color: hsla(120,100%,50%,0.2); border: 1px solid hsla(120,100%,25%,0.5); margin: -1px; border-top: none; border-bottom-left-radius: 5px; border-bottom-right-radius: 5px; } + +.syntaxhl .insert .insert { color: #0c0; background:transparent; font-weight:bold } +.syntaxhl .delete .delete { color: #c00; background:transparent; font-weight:bold } +.syntaxhl .change .change { color: #88f } +.syntaxhl .head .head { color: #f4f } + +/***** Media print specific styles *****/ +@media print { + #top-menu, #header, #main-menu, #sidebar, #footer, .contextual, .other-formats { display:none; } + #main { background: #fff; } + #content { width: 99%; margin: 0; padding: 0; border: 0; background: #fff; overflow: visible !important;} + #wiki_add_attachment { display:none; } + .hide-when-print { display: none; } + .autoscroll {overflow-x: visible;} + table.list {margin-top:0.5em;} + table.list th, table.list td {border: 1px solid #aaa;} +} + +/* Accessibility specific styles */ +.hidden-for-sighted { + position:absolute; + left:-10000px; + top:auto; + width:1px; + height:1px; + overflow:hidden; +} + diff --git a/public/stylesheets/context_menu.css b/public/stylesheets/context_menu.css new file mode 100644 index 00000000..1d02ebfb --- /dev/null +++ b/public/stylesheets/context_menu.css @@ -0,0 +1,52 @@ +#context-menu { position: absolute; z-index: 40; font-size: 0.9em;} + +#context-menu ul, #context-menu li, #context-menu a { + display:block; + margin:0; + padding:0; + border:0; +} + +#context-menu ul { + width:150px; + border: 1px solid #ccc; + background:white; + list-style:none; + padding:2px; + border-radius:2px; +} + +#context-menu li { + position:relative; + padding:1px; + z-index:39; + border:1px solid white; +} +#context-menu li.folder ul { position:absolute; left:168px; /* IE6 */ top:-2px; max-height:300px; overflow:hidden; overflow-y: auto; } +#context-menu li.folder>ul { left:148px; } + +#context-menu.reverse-y li.folder>ul { top:auto; bottom:0; } +#context-menu.reverse-x li.folder ul { left:auto; right:168px; /* IE6 */ } +#context-menu.reverse-x li.folder>ul { right:148px; } + +#context-menu a { + text-decoration:none !important; + background-repeat: no-repeat; + background-position: 1px 50%; + padding: 2px 0px 2px 20px; + width:100%; /* IE */ +} +#context-menu li>a { width:auto; } /* others */ +#context-menu a.disabled, #context-menu a.disabled:hover {color: #aaa;} +#context-menu li a.submenu { padding-right:16px; background:url("../images/bullet_arrow_right.png") right no-repeat; } +#context-menu li:hover { border:1px solid #628db6; background-color:#eef5fd; border-radius:3px; } +#context-menu a:hover {color:#2A5685;} +#context-menu li.folder:hover { z-index:40; } +#context-menu ul ul, #context-menu li:hover ul ul { display:none; } +#context-menu li:hover ul, #context-menu li:hover li:hover ul { display:block; } +#context-menu a.icon-checked {background: url(../images/toggle_check.png) no-repeat 3px 40%;} + +/* selected element */ +.context-menu-selection { background-color:#507AAA !important; color:#f8f8f8 !important; } +.context-menu-selection a, .context-menu-selection a:hover { color:#f8f8f8 !important; } +.context-menu-selection:hover { background-color:#507AAA !important; color:#f8f8f8 !important; } diff --git a/public/stylesheets/context_menu_rtl.css b/public/stylesheets/context_menu_rtl.css new file mode 100644 index 00000000..205bb918 --- /dev/null +++ b/public/stylesheets/context_menu_rtl.css @@ -0,0 +1,9 @@ +#context-menu li.folder ul { left:auto; right:168px; } +#context-menu li.folder>ul { left:auto; right:148px; } +#context-menu li a.submenu { background:url("../images/bullet_arrow_left.png") left no-repeat; } + +#context-menu a { + background-position: 100% 40%; + padding-right: 20px; + padding-left: 0px; +} diff --git a/public/stylesheets/jquery/images/ui-bg_diagonals-thick_18_b81900_40x40.png b/public/stylesheets/jquery/images/ui-bg_diagonals-thick_18_b81900_40x40.png new file mode 100644 index 00000000..954e22db Binary files /dev/null and b/public/stylesheets/jquery/images/ui-bg_diagonals-thick_18_b81900_40x40.png differ diff --git a/public/stylesheets/jquery/images/ui-bg_diagonals-thick_20_666666_40x40.png b/public/stylesheets/jquery/images/ui-bg_diagonals-thick_20_666666_40x40.png new file mode 100644 index 00000000..64ece570 Binary files /dev/null and b/public/stylesheets/jquery/images/ui-bg_diagonals-thick_20_666666_40x40.png differ diff --git a/public/stylesheets/jquery/images/ui-bg_flat_10_000000_40x100.png b/public/stylesheets/jquery/images/ui-bg_flat_10_000000_40x100.png new file mode 100644 index 00000000..abdc0108 Binary files /dev/null and b/public/stylesheets/jquery/images/ui-bg_flat_10_000000_40x100.png differ diff --git a/public/stylesheets/jquery/images/ui-bg_glass_100_eef5fd_1x400.png b/public/stylesheets/jquery/images/ui-bg_glass_100_eef5fd_1x400.png new file mode 100644 index 00000000..c3492e33 Binary files /dev/null and b/public/stylesheets/jquery/images/ui-bg_glass_100_eef5fd_1x400.png differ diff --git a/public/stylesheets/jquery/images/ui-bg_glass_100_f6f6f6_1x400.png b/public/stylesheets/jquery/images/ui-bg_glass_100_f6f6f6_1x400.png new file mode 100644 index 00000000..9b383f4d Binary files /dev/null and b/public/stylesheets/jquery/images/ui-bg_glass_100_f6f6f6_1x400.png differ diff --git a/public/stylesheets/jquery/images/ui-bg_glass_65_ffffff_1x400.png b/public/stylesheets/jquery/images/ui-bg_glass_65_ffffff_1x400.png new file mode 100644 index 00000000..42ccba26 Binary files /dev/null and b/public/stylesheets/jquery/images/ui-bg_glass_65_ffffff_1x400.png differ diff --git a/public/stylesheets/jquery/images/ui-bg_gloss-wave_35_759fcf_500x100.png b/public/stylesheets/jquery/images/ui-bg_gloss-wave_35_759fcf_500x100.png new file mode 100644 index 00000000..70b39a86 Binary files /dev/null and b/public/stylesheets/jquery/images/ui-bg_gloss-wave_35_759fcf_500x100.png differ diff --git a/public/stylesheets/jquery/images/ui-bg_highlight-soft_100_eeeeee_1x100.png b/public/stylesheets/jquery/images/ui-bg_highlight-soft_100_eeeeee_1x100.png new file mode 100644 index 00000000..f1273672 Binary files /dev/null and b/public/stylesheets/jquery/images/ui-bg_highlight-soft_100_eeeeee_1x100.png differ diff --git a/public/stylesheets/jquery/images/ui-bg_highlight-soft_75_759fcf_1x100.png b/public/stylesheets/jquery/images/ui-bg_highlight-soft_75_759fcf_1x100.png new file mode 100644 index 00000000..3fc3f9ba Binary files /dev/null and b/public/stylesheets/jquery/images/ui-bg_highlight-soft_75_759fcf_1x100.png differ diff --git a/public/stylesheets/jquery/images/ui-icons_222222_256x240.png b/public/stylesheets/jquery/images/ui-icons_222222_256x240.png new file mode 100644 index 00000000..b273ff11 Binary files /dev/null and b/public/stylesheets/jquery/images/ui-icons_222222_256x240.png differ diff --git a/public/stylesheets/jquery/images/ui-icons_759fcf_256x240.png b/public/stylesheets/jquery/images/ui-icons_759fcf_256x240.png new file mode 100644 index 00000000..e0c6374c Binary files /dev/null and b/public/stylesheets/jquery/images/ui-icons_759fcf_256x240.png differ diff --git a/public/stylesheets/jquery/images/ui-icons_ffd27a_256x240.png b/public/stylesheets/jquery/images/ui-icons_ffd27a_256x240.png new file mode 100644 index 00000000..e117effa Binary files /dev/null and b/public/stylesheets/jquery/images/ui-icons_ffd27a_256x240.png differ diff --git a/public/stylesheets/jquery/images/ui-icons_ffffff_256x240.png b/public/stylesheets/jquery/images/ui-icons_ffffff_256x240.png new file mode 100644 index 00000000..42f8f992 Binary files /dev/null and b/public/stylesheets/jquery/images/ui-icons_ffffff_256x240.png differ diff --git a/public/stylesheets/jquery/jquery-ui-1.9.2.css b/public/stylesheets/jquery/jquery-ui-1.9.2.css new file mode 100644 index 00000000..090d220d --- /dev/null +++ b/public/stylesheets/jquery/jquery-ui-1.9.2.css @@ -0,0 +1,5 @@ +/*! jQuery UI - v1.9.2 - 2012-12-26 +* http://jqueryui.com +* Includes: jquery.ui.core.css, jquery.ui.resizable.css, jquery.ui.selectable.css, jquery.ui.accordion.css, jquery.ui.autocomplete.css, jquery.ui.button.css, jquery.ui.datepicker.css, jquery.ui.dialog.css, jquery.ui.menu.css, jquery.ui.progressbar.css, jquery.ui.slider.css, jquery.ui.spinner.css, jquery.ui.tabs.css, jquery.ui.tooltip.css +* To view and modify this theme, visit http://jqueryui.com/themeroller/?ffDefault=Verdana%2C%20sans-serif&fwDefault=bold&fsDefault=1.1em&cornerRadius=4px&bgColorHeader=759fcf&bgTextureHeader=12_gloss_wave.png&bgImgOpacityHeader=35&borderColorHeader=628db6&fcHeader=ffffff&iconColorHeader=ffffff&bgColorContent=eeeeee&bgTextureContent=03_highlight_soft.png&bgImgOpacityContent=100&borderColorContent=dddddd&fcContent=333333&iconColorContent=222222&bgColorDefault=f6f6f6&bgTextureDefault=02_glass.png&bgImgOpacityDefault=100&borderColorDefault=cccccc&fcDefault=628db6&iconColorDefault=759fcf&bgColorHover=eef5fd&bgTextureHover=02_glass.png&bgImgOpacityHover=100&borderColorHover=628db6&fcHover=628db6&iconColorHover=759fcf&bgColorActive=ffffff&bgTextureActive=02_glass.png&bgImgOpacityActive=65&borderColorActive=628db6&fcActive=628db6&iconColorActive=759fcf&bgColorHighlight=759fcf&bgTextureHighlight=03_highlight_soft.png&bgImgOpacityHighlight=75&borderColorHighlight=628db6&fcHighlight=363636&iconColorHighlight=759fcf&bgColorError=b81900&bgTextureError=08_diagonals_thick.png&bgImgOpacityError=18&borderColorError=cd0a0a&fcError=ffffff&iconColorError=ffd27a&bgColorOverlay=666666&bgTextureOverlay=08_diagonals_thick.png&bgImgOpacityOverlay=20&opacityOverlay=50&bgColorShadow=000000&bgTextureShadow=01_flat.png&bgImgOpacityShadow=10&opacityShadow=20&thicknessShadow=5px&offsetTopShadow=-5px&offsetLeftShadow=-5px&cornerRadiusShadow=5px +* Copyright (c) 2012 jQuery Foundation and other contributors Licensed MIT */.ui-helper-hidden{display:none}.ui-helper-hidden-accessible{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.ui-helper-reset{margin:0;padding:0;border:0;outline:0;line-height:1.3;text-decoration:none;font-size:100%;list-style:none}.ui-helper-clearfix:before,.ui-helper-clearfix:after{content:"";display:table}.ui-helper-clearfix:after{clear:both}.ui-helper-clearfix{zoom:1}.ui-helper-zfix{width:100%;height:100%;top:0;left:0;position:absolute;opacity:0;filter:Alpha(Opacity=0)}.ui-state-disabled{cursor:default!important}.ui-icon{display:block;text-indent:-99999px;overflow:hidden;background-repeat:no-repeat}.ui-widget-overlay{position:absolute;top:0;left:0;width:100%;height:100%}.ui-resizable{position:relative}.ui-resizable-handle{position:absolute;font-size:0.1px;display:block}.ui-resizable-disabled .ui-resizable-handle,.ui-resizable-autohide .ui-resizable-handle{display:none}.ui-resizable-n{cursor:n-resize;height:7px;width:100%;top:-5px;left:0}.ui-resizable-s{cursor:s-resize;height:7px;width:100%;bottom:-5px;left:0}.ui-resizable-e{cursor:e-resize;width:7px;right:-5px;top:0;height:100%}.ui-resizable-w{cursor:w-resize;width:7px;left:-5px;top:0;height:100%}.ui-resizable-se{cursor:se-resize;width:12px;height:12px;right:1px;bottom:1px}.ui-resizable-sw{cursor:sw-resize;width:9px;height:9px;left:-5px;bottom:-5px}.ui-resizable-nw{cursor:nw-resize;width:9px;height:9px;left:-5px;top:-5px}.ui-resizable-ne{cursor:ne-resize;width:9px;height:9px;right:-5px;top:-5px}.ui-selectable-helper{position:absolute;z-index:100;border:1px dotted black}.ui-accordion .ui-accordion-header{display:block;cursor:pointer;position:relative;margin-top:2px;padding:.5em .5em .5em .7em;zoom:1}.ui-accordion .ui-accordion-icons{padding-left:2.2em}.ui-accordion .ui-accordion-noicons{padding-left:.7em}.ui-accordion .ui-accordion-icons .ui-accordion-icons{padding-left:2.2em}.ui-accordion .ui-accordion-header .ui-accordion-header-icon{position:absolute;left:.5em;top:50%;margin-top:-8px}.ui-accordion .ui-accordion-content{padding:1em 2.2em;border-top:0;overflow:auto;zoom:1}.ui-autocomplete{position:absolute;top:0;left:0;cursor:default}* html .ui-autocomplete{width:1px}.ui-button{display:inline-block;position:relative;padding:0;margin-right:.1em;cursor:pointer;text-align:center;zoom:1;overflow:visible}.ui-button,.ui-button:link,.ui-button:visited,.ui-button:hover,.ui-button:active{text-decoration:none}.ui-button-icon-only{width:2.2em}button.ui-button-icon-only{width:2.4em}.ui-button-icons-only{width:3.4em}button.ui-button-icons-only{width:3.7em}.ui-button .ui-button-text{display:block;line-height:1.4}.ui-button-text-only .ui-button-text{padding:.4em 1em}.ui-button-icon-only .ui-button-text,.ui-button-icons-only .ui-button-text{padding:.4em;text-indent:-9999999px}.ui-button-text-icon-primary .ui-button-text,.ui-button-text-icons .ui-button-text{padding:.4em 1em .4em 2.1em}.ui-button-text-icon-secondary .ui-button-text,.ui-button-text-icons .ui-button-text{padding:.4em 2.1em .4em 1em}.ui-button-text-icons .ui-button-text{padding-left:2.1em;padding-right:2.1em}input.ui-button{padding:.4em 1em}.ui-button-icon-only .ui-icon,.ui-button-text-icon-primary .ui-icon,.ui-button-text-icon-secondary .ui-icon,.ui-button-text-icons .ui-icon,.ui-button-icons-only .ui-icon{position:absolute;top:50%;margin-top:-8px}.ui-button-icon-only .ui-icon{left:50%;margin-left:-8px}.ui-button-text-icon-primary .ui-button-icon-primary,.ui-button-text-icons .ui-button-icon-primary,.ui-button-icons-only .ui-button-icon-primary{left:.5em}.ui-button-text-icon-secondary .ui-button-icon-secondary,.ui-button-text-icons .ui-button-icon-secondary,.ui-button-icons-only .ui-button-icon-secondary{right:.5em}.ui-button-text-icons .ui-button-icon-secondary,.ui-button-icons-only .ui-button-icon-secondary{right:.5em}.ui-buttonset{margin-right:7px}.ui-buttonset .ui-button{margin-left:0;margin-right:-.3em}button.ui-button::-moz-focus-inner{border:0;padding:0}.ui-datepicker{width:17em;padding:.2em .2em 0;display:none}.ui-datepicker .ui-datepicker-header{position:relative;padding:.2em 0}.ui-datepicker .ui-datepicker-prev,.ui-datepicker .ui-datepicker-next{position:absolute;top:2px;width:1.8em;height:1.8em}.ui-datepicker .ui-datepicker-prev-hover,.ui-datepicker .ui-datepicker-next-hover{top:1px}.ui-datepicker .ui-datepicker-prev{left:2px}.ui-datepicker .ui-datepicker-next{right:2px}.ui-datepicker .ui-datepicker-prev-hover{left:1px}.ui-datepicker .ui-datepicker-next-hover{right:1px}.ui-datepicker .ui-datepicker-prev span,.ui-datepicker .ui-datepicker-next span{display:block;position:absolute;left:50%;margin-left:-8px;top:50%;margin-top:-8px}.ui-datepicker .ui-datepicker-title{margin:0 2.3em;line-height:1.8em;text-align:center}.ui-datepicker .ui-datepicker-title select{font-size:1em;margin:1px 0}.ui-datepicker select.ui-datepicker-month-year{width:100%}.ui-datepicker select.ui-datepicker-month,.ui-datepicker select.ui-datepicker-year{width:49%}.ui-datepicker table{width:100%;font-size:.9em;border-collapse:collapse;margin:0 0 .4em}.ui-datepicker th{padding:.7em .3em;text-align:center;font-weight:bold;border:0}.ui-datepicker td{border:0;padding:1px}.ui-datepicker td span,.ui-datepicker td a{display:block;padding:.2em;text-align:right;text-decoration:none}.ui-datepicker .ui-datepicker-buttonpane{background-image:none;margin:.7em 0 0 0;padding:0 .2em;border-left:0;border-right:0;border-bottom:0}.ui-datepicker .ui-datepicker-buttonpane button{float:right;margin:.5em .2em .4em;cursor:pointer;padding:.2em .6em .3em .6em;width:auto;overflow:visible}.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current{float:left}.ui-datepicker.ui-datepicker-multi{width:auto}.ui-datepicker-multi .ui-datepicker-group{float:left}.ui-datepicker-multi .ui-datepicker-group table{width:95%;margin:0 auto .4em}.ui-datepicker-multi-2 .ui-datepicker-group{width:50%}.ui-datepicker-multi-3 .ui-datepicker-group{width:33.3%}.ui-datepicker-multi-4 .ui-datepicker-group{width:25%}.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header{border-left-width:0}.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header{border-left-width:0}.ui-datepicker-multi .ui-datepicker-buttonpane{clear:left}.ui-datepicker-row-break{clear:both;width:100%;font-size:0em}.ui-datepicker-rtl{direction:rtl}.ui-datepicker-rtl .ui-datepicker-prev{right:2px;left:auto}.ui-datepicker-rtl .ui-datepicker-next{left:2px;right:auto}.ui-datepicker-rtl .ui-datepicker-prev:hover{right:1px;left:auto}.ui-datepicker-rtl .ui-datepicker-next:hover{left:1px;right:auto}.ui-datepicker-rtl .ui-datepicker-buttonpane{clear:right}.ui-datepicker-rtl .ui-datepicker-buttonpane button{float:left}.ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current{float:right}.ui-datepicker-rtl .ui-datepicker-group{float:right}.ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header{border-right-width:0;border-left-width:1px}.ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header{border-right-width:0;border-left-width:1px}.ui-datepicker-cover{position:absolute;z-index:-1;filter:mask();top:-4px;left:-4px;width:200px;height:200px}.ui-dialog{position:absolute;top:0;left:0;padding:.2em;width:300px;overflow:hidden}.ui-dialog .ui-dialog-titlebar{padding:.4em 1em;position:relative}.ui-dialog .ui-dialog-title{float:left;margin:.1em 16px .1em 0}.ui-dialog .ui-dialog-titlebar-close{position:absolute;right:.3em;top:50%;width:19px;margin:-10px 0 0 0;padding:1px;height:18px}.ui-dialog .ui-dialog-titlebar-close span{display:block;margin:1px}.ui-dialog .ui-dialog-titlebar-close:hover,.ui-dialog .ui-dialog-titlebar-close:focus{padding:0}.ui-dialog .ui-dialog-content{position:relative;border:0;padding:.5em 1em;background:none;overflow:auto;zoom:1}.ui-dialog .ui-dialog-buttonpane{text-align:left;border-width:1px 0 0 0;background-image:none;margin:.5em 0 0 0;padding:.3em 1em .5em .4em}.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset{float:right}.ui-dialog .ui-dialog-buttonpane button{margin:.5em .4em .5em 0;cursor:pointer}.ui-dialog .ui-resizable-se{width:14px;height:14px;right:3px;bottom:3px}.ui-draggable .ui-dialog-titlebar{cursor:move}.ui-menu{list-style:none;padding:2px;margin:0;display:block;outline:none}.ui-menu .ui-menu{margin-top:-3px;position:absolute}.ui-menu .ui-menu-item{margin:0;padding:0;zoom:1;width:100%}.ui-menu .ui-menu-divider{margin:5px -2px 5px -2px;height:0;font-size:0;line-height:0;border-width:1px 0 0 0}.ui-menu .ui-menu-item a{text-decoration:none;display:block;padding:2px .4em;line-height:1.5;zoom:1;font-weight:normal}.ui-menu .ui-menu-item a.ui-state-focus,.ui-menu .ui-menu-item a.ui-state-active{font-weight:normal;margin:-1px}.ui-menu .ui-state-disabled{font-weight:normal;margin:.4em 0 .2em;line-height:1.5}.ui-menu .ui-state-disabled a{cursor:default}.ui-menu-icons{position:relative}.ui-menu-icons .ui-menu-item a{position:relative;padding-left:2em}.ui-menu .ui-icon{position:absolute;top:.2em;left:.2em}.ui-menu .ui-menu-icon{position:static;float:right}.ui-progressbar{height:2em;text-align:left;overflow:hidden}.ui-progressbar .ui-progressbar-value{margin:-1px;height:100%}.ui-slider{position:relative;text-align:left}.ui-slider .ui-slider-handle{position:absolute;z-index:2;width:1.2em;height:1.2em;cursor:default}.ui-slider .ui-slider-range{position:absolute;z-index:1;font-size:.7em;display:block;border:0;background-position:0 0}.ui-slider-horizontal{height:.8em}.ui-slider-horizontal .ui-slider-handle{top:-.3em;margin-left:-.6em}.ui-slider-horizontal .ui-slider-range{top:0;height:100%}.ui-slider-horizontal .ui-slider-range-min{left:0}.ui-slider-horizontal .ui-slider-range-max{right:0}.ui-slider-vertical{width:.8em;height:100px}.ui-slider-vertical .ui-slider-handle{left:-.3em;margin-left:0;margin-bottom:-.6em}.ui-slider-vertical .ui-slider-range{left:0;width:100%}.ui-slider-vertical .ui-slider-range-min{bottom:0}.ui-slider-vertical .ui-slider-range-max{top:0}.ui-spinner{position:relative;display:inline-block;overflow:hidden;padding:0;vertical-align:middle}.ui-spinner-input{border:none;background:none;padding:0;margin:.2em 0;vertical-align:middle;margin-left:.4em;margin-right:22px}.ui-spinner-button{width:16px;height:50%;font-size:.5em;padding:0;margin:0;text-align:center;position:absolute;cursor:default;display:block;overflow:hidden;right:0}.ui-spinner a.ui-spinner-button{border-top:none;border-bottom:none;border-right:none}.ui-spinner .ui-icon{position:absolute;margin-top:-8px;top:50%;left:0}.ui-spinner-up{top:0}.ui-spinner-down{bottom:0}.ui-spinner .ui-icon-triangle-1-s{background-position:-65px -16px}.ui-tabs{position:relative;padding:.2em;zoom:1}.ui-tabs .ui-tabs-nav{margin:0;padding:.2em .2em 0}.ui-tabs .ui-tabs-nav li{list-style:none;float:left;position:relative;top:0;margin:1px .2em 0 0;border-bottom:0;padding:0;white-space:nowrap}.ui-tabs .ui-tabs-nav li a{float:left;padding:.5em 1em;text-decoration:none}.ui-tabs .ui-tabs-nav li.ui-tabs-active{margin-bottom:-1px;padding-bottom:1px}.ui-tabs .ui-tabs-nav li.ui-tabs-active a,.ui-tabs .ui-tabs-nav li.ui-state-disabled a,.ui-tabs .ui-tabs-nav li.ui-tabs-loading a{cursor:text}.ui-tabs .ui-tabs-nav li a,.ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-active a{cursor:pointer}.ui-tabs .ui-tabs-panel{display:block;border-width:0;padding:1em 1.4em;background:none}.ui-tooltip{padding:8px;position:absolute;z-index:9999;max-width:300px;-webkit-box-shadow:0 0 5px #aaa;box-shadow:0 0 5px #aaa}* html .ui-tooltip{background-image:none}body .ui-tooltip{border-width:2px}.ui-widget{font-family:Verdana,sans-serif;font-size:1.1em}.ui-widget .ui-widget{font-size:1em}.ui-widget input,.ui-widget select,.ui-widget textarea,.ui-widget button{font-family:Verdana,sans-serif;font-size:1em}.ui-widget-content{border:1px solid #ddd;background:#eee url(images/ui-bg_highlight-soft_100_eeeeee_1x100.png) 50% top repeat-x;color:#333}.ui-widget-content a{color:#333}.ui-widget-header{border:1px solid #628db6;background:#759fcf url(images/ui-bg_gloss-wave_35_759fcf_500x100.png) 50% 50% repeat-x;color:#fff;font-weight:bold}.ui-widget-header a{color:#fff}.ui-state-default,.ui-widget-content .ui-state-default,.ui-widget-header .ui-state-default{border:1px solid #ccc;background:#f6f6f6 url(images/ui-bg_glass_100_f6f6f6_1x400.png) 50% 50% repeat-x;font-weight:bold;color:#628db6}.ui-state-default a,.ui-state-default a:link,.ui-state-default a:visited{color:#628db6;text-decoration:none}.ui-state-hover,.ui-widget-content .ui-state-hover,.ui-widget-header .ui-state-hover,.ui-state-focus,.ui-widget-content .ui-state-focus,.ui-widget-header .ui-state-focus{border:1px solid #628db6;background:#eef5fd url(images/ui-bg_glass_100_eef5fd_1x400.png) 50% 50% repeat-x;font-weight:bold;color:#628db6}.ui-state-hover a,.ui-state-hover a:hover,.ui-state-hover a:link,.ui-state-hover a:visited{color:#628db6;text-decoration:none}.ui-state-active,.ui-widget-content .ui-state-active,.ui-widget-header .ui-state-active{border:1px solid #628db6;background:#fff url(images/ui-bg_glass_65_ffffff_1x400.png) 50% 50% repeat-x;font-weight:bold;color:#628db6}.ui-state-active a,.ui-state-active a:link,.ui-state-active a:visited{color:#628db6;text-decoration:none}.ui-state-highlight,.ui-widget-content .ui-state-highlight,.ui-widget-header .ui-state-highlight{border:1px solid #628db6;background:#759fcf url(images/ui-bg_highlight-soft_75_759fcf_1x100.png) 50% top repeat-x;color:#363636}.ui-state-highlight a,.ui-widget-content .ui-state-highlight a,.ui-widget-header .ui-state-highlight a{color:#363636}.ui-state-error,.ui-widget-content .ui-state-error,.ui-widget-header .ui-state-error{border:1px solid #cd0a0a;background:#b81900 url(images/ui-bg_diagonals-thick_18_b81900_40x40.png) 50% 50% repeat;color:#fff}.ui-state-error a,.ui-widget-content .ui-state-error a,.ui-widget-header .ui-state-error a{color:#fff}.ui-state-error-text,.ui-widget-content .ui-state-error-text,.ui-widget-header .ui-state-error-text{color:#fff}.ui-priority-primary,.ui-widget-content .ui-priority-primary,.ui-widget-header .ui-priority-primary{font-weight:bold}.ui-priority-secondary,.ui-widget-content .ui-priority-secondary,.ui-widget-header .ui-priority-secondary{opacity:.7;filter:Alpha(Opacity=70);font-weight:normal}.ui-state-disabled,.ui-widget-content .ui-state-disabled,.ui-widget-header .ui-state-disabled{opacity:.35;filter:Alpha(Opacity=35);background-image:none}.ui-state-disabled .ui-icon{filter:Alpha(Opacity=35)}.ui-icon{width:16px;height:16px;background-image:url(images/ui-icons_222222_256x240.png)}.ui-widget-content .ui-icon{background-image:url(images/ui-icons_222222_256x240.png)}.ui-widget-header .ui-icon{background-image:url(images/ui-icons_ffffff_256x240.png)}.ui-state-default .ui-icon{background-image:url(images/ui-icons_759fcf_256x240.png)}.ui-state-hover .ui-icon,.ui-state-focus .ui-icon{background-image:url(images/ui-icons_759fcf_256x240.png)}.ui-state-active .ui-icon{background-image:url(images/ui-icons_759fcf_256x240.png)}.ui-state-highlight .ui-icon{background-image:url(images/ui-icons_759fcf_256x240.png)}.ui-state-error .ui-icon,.ui-state-error-text .ui-icon{background-image:url(images/ui-icons_ffd27a_256x240.png)}.ui-icon-carat-1-n{background-position:0 0}.ui-icon-carat-1-ne{background-position:-16px 0}.ui-icon-carat-1-e{background-position:-32px 0}.ui-icon-carat-1-se{background-position:-48px 0}.ui-icon-carat-1-s{background-position:-64px 0}.ui-icon-carat-1-sw{background-position:-80px 0}.ui-icon-carat-1-w{background-position:-96px 0}.ui-icon-carat-1-nw{background-position:-112px 0}.ui-icon-carat-2-n-s{background-position:-128px 0}.ui-icon-carat-2-e-w{background-position:-144px 0}.ui-icon-triangle-1-n{background-position:0 -16px}.ui-icon-triangle-1-ne{background-position:-16px -16px}.ui-icon-triangle-1-e{background-position:-32px -16px}.ui-icon-triangle-1-se{background-position:-48px -16px}.ui-icon-triangle-1-s{background-position:-64px -16px}.ui-icon-triangle-1-sw{background-position:-80px -16px}.ui-icon-triangle-1-w{background-position:-96px -16px}.ui-icon-triangle-1-nw{background-position:-112px -16px}.ui-icon-triangle-2-n-s{background-position:-128px -16px}.ui-icon-triangle-2-e-w{background-position:-144px -16px}.ui-icon-arrow-1-n{background-position:0 -32px}.ui-icon-arrow-1-ne{background-position:-16px -32px}.ui-icon-arrow-1-e{background-position:-32px -32px}.ui-icon-arrow-1-se{background-position:-48px -32px}.ui-icon-arrow-1-s{background-position:-64px -32px}.ui-icon-arrow-1-sw{background-position:-80px -32px}.ui-icon-arrow-1-w{background-position:-96px -32px}.ui-icon-arrow-1-nw{background-position:-112px -32px}.ui-icon-arrow-2-n-s{background-position:-128px -32px}.ui-icon-arrow-2-ne-sw{background-position:-144px -32px}.ui-icon-arrow-2-e-w{background-position:-160px -32px}.ui-icon-arrow-2-se-nw{background-position:-176px -32px}.ui-icon-arrowstop-1-n{background-position:-192px -32px}.ui-icon-arrowstop-1-e{background-position:-208px -32px}.ui-icon-arrowstop-1-s{background-position:-224px -32px}.ui-icon-arrowstop-1-w{background-position:-240px -32px}.ui-icon-arrowthick-1-n{background-position:0 -48px}.ui-icon-arrowthick-1-ne{background-position:-16px -48px}.ui-icon-arrowthick-1-e{background-position:-32px -48px}.ui-icon-arrowthick-1-se{background-position:-48px -48px}.ui-icon-arrowthick-1-s{background-position:-64px -48px}.ui-icon-arrowthick-1-sw{background-position:-80px -48px}.ui-icon-arrowthick-1-w{background-position:-96px -48px}.ui-icon-arrowthick-1-nw{background-position:-112px -48px}.ui-icon-arrowthick-2-n-s{background-position:-128px -48px}.ui-icon-arrowthick-2-ne-sw{background-position:-144px -48px}.ui-icon-arrowthick-2-e-w{background-position:-160px -48px}.ui-icon-arrowthick-2-se-nw{background-position:-176px -48px}.ui-icon-arrowthickstop-1-n{background-position:-192px -48px}.ui-icon-arrowthickstop-1-e{background-position:-208px -48px}.ui-icon-arrowthickstop-1-s{background-position:-224px -48px}.ui-icon-arrowthickstop-1-w{background-position:-240px -48px}.ui-icon-arrowreturnthick-1-w{background-position:0 -64px}.ui-icon-arrowreturnthick-1-n{background-position:-16px -64px}.ui-icon-arrowreturnthick-1-e{background-position:-32px -64px}.ui-icon-arrowreturnthick-1-s{background-position:-48px -64px}.ui-icon-arrowreturn-1-w{background-position:-64px -64px}.ui-icon-arrowreturn-1-n{background-position:-80px -64px}.ui-icon-arrowreturn-1-e{background-position:-96px -64px}.ui-icon-arrowreturn-1-s{background-position:-112px -64px}.ui-icon-arrowrefresh-1-w{background-position:-128px -64px}.ui-icon-arrowrefresh-1-n{background-position:-144px -64px}.ui-icon-arrowrefresh-1-e{background-position:-160px -64px}.ui-icon-arrowrefresh-1-s{background-position:-176px -64px}.ui-icon-arrow-4{background-position:0 -80px}.ui-icon-arrow-4-diag{background-position:-16px -80px}.ui-icon-extlink{background-position:-32px -80px}.ui-icon-newwin{background-position:-48px -80px}.ui-icon-refresh{background-position:-64px -80px}.ui-icon-shuffle{background-position:-80px -80px}.ui-icon-transfer-e-w{background-position:-96px -80px}.ui-icon-transferthick-e-w{background-position:-112px -80px}.ui-icon-folder-collapsed{background-position:0 -96px}.ui-icon-folder-open{background-position:-16px -96px}.ui-icon-document{background-position:-32px -96px}.ui-icon-document-b{background-position:-48px -96px}.ui-icon-note{background-position:-64px -96px}.ui-icon-mail-closed{background-position:-80px -96px}.ui-icon-mail-open{background-position:-96px -96px}.ui-icon-suitcase{background-position:-112px -96px}.ui-icon-comment{background-position:-128px -96px}.ui-icon-person{background-position:-144px -96px}.ui-icon-print{background-position:-160px -96px}.ui-icon-trash{background-position:-176px -96px}.ui-icon-locked{background-position:-192px -96px}.ui-icon-unlocked{background-position:-208px -96px}.ui-icon-bookmark{background-position:-224px -96px}.ui-icon-tag{background-position:-240px -96px}.ui-icon-home{background-position:0 -112px}.ui-icon-flag{background-position:-16px -112px}.ui-icon-calendar{background-position:-32px -112px}.ui-icon-cart{background-position:-48px -112px}.ui-icon-pencil{background-position:-64px -112px}.ui-icon-clock{background-position:-80px -112px}.ui-icon-disk{background-position:-96px -112px}.ui-icon-calculator{background-position:-112px -112px}.ui-icon-zoomin{background-position:-128px -112px}.ui-icon-zoomout{background-position:-144px -112px}.ui-icon-search{background-position:-160px -112px}.ui-icon-wrench{background-position:-176px -112px}.ui-icon-gear{background-position:-192px -112px}.ui-icon-heart{background-position:-208px -112px}.ui-icon-star{background-position:-224px -112px}.ui-icon-link{background-position:-240px -112px}.ui-icon-cancel{background-position:0 -128px}.ui-icon-plus{background-position:-16px -128px}.ui-icon-plusthick{background-position:-32px -128px}.ui-icon-minus{background-position:-48px -128px}.ui-icon-minusthick{background-position:-64px -128px}.ui-icon-close{background-position:-80px -128px}.ui-icon-closethick{background-position:-96px -128px}.ui-icon-key{background-position:-112px -128px}.ui-icon-lightbulb{background-position:-128px -128px}.ui-icon-scissors{background-position:-144px -128px}.ui-icon-clipboard{background-position:-160px -128px}.ui-icon-copy{background-position:-176px -128px}.ui-icon-contact{background-position:-192px -128px}.ui-icon-image{background-position:-208px -128px}.ui-icon-video{background-position:-224px -128px}.ui-icon-script{background-position:-240px -128px}.ui-icon-alert{background-position:0 -144px}.ui-icon-info{background-position:-16px -144px}.ui-icon-notice{background-position:-32px -144px}.ui-icon-help{background-position:-48px -144px}.ui-icon-check{background-position:-64px -144px}.ui-icon-bullet{background-position:-80px -144px}.ui-icon-radio-on{background-position:-96px -144px}.ui-icon-radio-off{background-position:-112px -144px}.ui-icon-pin-w{background-position:-128px -144px}.ui-icon-pin-s{background-position:-144px -144px}.ui-icon-play{background-position:0 -160px}.ui-icon-pause{background-position:-16px -160px}.ui-icon-seek-next{background-position:-32px -160px}.ui-icon-seek-prev{background-position:-48px -160px}.ui-icon-seek-end{background-position:-64px -160px}.ui-icon-seek-start{background-position:-80px -160px}.ui-icon-seek-first{background-position:-80px -160px}.ui-icon-stop{background-position:-96px -160px}.ui-icon-eject{background-position:-112px -160px}.ui-icon-volume-off{background-position:-128px -160px}.ui-icon-volume-on{background-position:-144px -160px}.ui-icon-power{background-position:0 -176px}.ui-icon-signal-diag{background-position:-16px -176px}.ui-icon-signal{background-position:-32px -176px}.ui-icon-battery-0{background-position:-48px -176px}.ui-icon-battery-1{background-position:-64px -176px}.ui-icon-battery-2{background-position:-80px -176px}.ui-icon-battery-3{background-position:-96px -176px}.ui-icon-circle-plus{background-position:0 -192px}.ui-icon-circle-minus{background-position:-16px -192px}.ui-icon-circle-close{background-position:-32px -192px}.ui-icon-circle-triangle-e{background-position:-48px -192px}.ui-icon-circle-triangle-s{background-position:-64px -192px}.ui-icon-circle-triangle-w{background-position:-80px -192px}.ui-icon-circle-triangle-n{background-position:-96px -192px}.ui-icon-circle-arrow-e{background-position:-112px -192px}.ui-icon-circle-arrow-s{background-position:-128px -192px}.ui-icon-circle-arrow-w{background-position:-144px -192px}.ui-icon-circle-arrow-n{background-position:-160px -192px}.ui-icon-circle-zoomin{background-position:-176px -192px}.ui-icon-circle-zoomout{background-position:-192px -192px}.ui-icon-circle-check{background-position:-208px -192px}.ui-icon-circlesmall-plus{background-position:0 -208px}.ui-icon-circlesmall-minus{background-position:-16px -208px}.ui-icon-circlesmall-close{background-position:-32px -208px}.ui-icon-squaresmall-plus{background-position:-48px -208px}.ui-icon-squaresmall-minus{background-position:-64px -208px}.ui-icon-squaresmall-close{background-position:-80px -208px}.ui-icon-grip-dotted-vertical{background-position:0 -224px}.ui-icon-grip-dotted-horizontal{background-position:-16px -224px}.ui-icon-grip-solid-vertical{background-position:-32px -224px}.ui-icon-grip-solid-horizontal{background-position:-48px -224px}.ui-icon-gripsmall-diagonal-se{background-position:-64px -224px}.ui-icon-grip-diagonal-se{background-position:-80px -224px}.ui-corner-all,.ui-corner-top,.ui-corner-left,.ui-corner-tl{-moz-border-radius-topleft:4px;-webkit-border-top-left-radius:4px;-khtml-border-top-left-radius:4px;border-top-left-radius:4px}.ui-corner-all,.ui-corner-top,.ui-corner-right,.ui-corner-tr{-moz-border-radius-topright:4px;-webkit-border-top-right-radius:4px;-khtml-border-top-right-radius:4px;border-top-right-radius:4px}.ui-corner-all,.ui-corner-bottom,.ui-corner-left,.ui-corner-bl{-moz-border-radius-bottomleft:4px;-webkit-border-bottom-left-radius:4px;-khtml-border-bottom-left-radius:4px;border-bottom-left-radius:4px}.ui-corner-all,.ui-corner-bottom,.ui-corner-right,.ui-corner-br{-moz-border-radius-bottomright:4px;-webkit-border-bottom-right-radius:4px;-khtml-border-bottom-right-radius:4px;border-bottom-right-radius:4px}.ui-widget-overlay{background:#666 url(images/ui-bg_diagonals-thick_20_666666_40x40.png) 50% 50% repeat;opacity:.5;filter:Alpha(Opacity=50)}.ui-widget-shadow{margin:-5px 0 0 -5px;padding:5px;background:#000 url(images/ui-bg_flat_10_000000_40x100.png) 50% 50% repeat-x;opacity:.2;filter:Alpha(Opacity=20);-moz-border-radius:5px;-khtml-border-radius:5px;-webkit-border-radius:5px;border-radius:5px} diff --git a/public/stylesheets/jstoolbar.css b/public/stylesheets/jstoolbar.css new file mode 100644 index 00000000..315d814b --- /dev/null +++ b/public/stylesheets/jstoolbar.css @@ -0,0 +1,100 @@ +.jstEditor { + padding-left: 0px; +} +.jstEditor textarea, .jstEditor iframe { + margin: 0; +} + +.jstHandle { + height: 10px; + font-size: 0.1em; + cursor: s-resize; + /*background: transparent url(img/resizer.png) no-repeat 45% 50%;*/ +} + +.jstElements { + padding: 3px 3px 3px 0; +} + +.jstElements button { + margin-right: 4px; + width : 24px; + height: 24px; + padding: 4px; + border-style: solid; + border-width: 1px; + border-color: #ddd; + background-color : #f7f7f7; + background-position : 50% 50%; + background-repeat: no-repeat; +} +.jstElements button:hover { + border-color: #bbb; + background-color: #e5e5e5; +} +.jstElements button span { + display : none; +} +.jstElements span { + display : inline; +} + +.jstSpacer { + width : 0px; + font-size: 1px; + margin-right: 6px; +} + +.jstElements .help { float: right; margin-right: 0.5em; padding-top: 8px; font-size: 0.9em; } +.jstElements .help a {padding: 2px 0 2px 20px; background: url(../images/help.png) no-repeat 0 50%;} + +/* Buttons +-------------------------------------------------------- */ +.jstb_strong { + background-image: url(../images/jstoolbar/bt_strong.png); +} +.jstb_em { + background-image: url(../images/jstoolbar/bt_em.png); +} +.jstb_ins { + background-image: url(../images/jstoolbar/bt_ins.png); +} +.jstb_del { + background-image: url(../images/jstoolbar/bt_del.png); +} +.jstb_code { + background-image: url(../images/jstoolbar/bt_code.png); +} +.jstb_h1 { + background-image: url(../images/jstoolbar/bt_h1.png); +} +.jstb_h2 { + background-image: url(../images/jstoolbar/bt_h2.png); +} +.jstb_h3 { + background-image: url(../images/jstoolbar/bt_h3.png); +} +.jstb_ul { + background-image: url(../images/jstoolbar/bt_ul.png); +} +.jstb_ol { + background-image: url(../images/jstoolbar/bt_ol.png); +} +.jstb_bq { + background-image: url(../images/jstoolbar/bt_bq.png); +} +.jstb_unbq { + background-image: url(../images/jstoolbar/bt_bq_remove.png); +} +.jstb_pre { + background-image: url(../images/jstoolbar/bt_pre.png); +} +.jstb_link { + background-image: url(../images/jstoolbar/bt_link.png); +} +.jstb_img { + background-image: url(../images/jstoolbar/bt_img.png); +} +.jstb_help { + background-image: url(../images/help.png); +} diff --git a/public/stylesheets/rtl.css b/public/stylesheets/rtl.css new file mode 100644 index 00000000..eb047794 --- /dev/null +++ b/public/stylesheets/rtl.css @@ -0,0 +1,94 @@ +body, #wrapper { direction: rtl;} + +#quick-search { float: left; } +#main-menu { margin-left: -500px; left: auto; right: 6px; margin-right: 0px;} +#main-menu li { float: right; } +#top-menu ul { float: right; } +#account { float: left; } +#top-menu #loggedas { float: left; } +#top-menu li { float: right; } +.tabular label.floating +{ + margin-right: 0; + margin-left: auto; + text-align: right; +} +.tabular label +{ + float: right; + margin-left: auto; +} +.tabular p +{ + clear: right; +} +.tabular label.block { text-align: right; } +.icon +{ + background-position: 100% 40%; + padding-right: 20px; + padding-left: 0px; +} +div#activity dt, #search-results dt +{ + background-position: 100% 50%; + padding-right: 20px; + padding-left: 0px; +} +#content .tabs ul li { float: right; } +#content .tabs ul { padding-left: auto; padding-right: 1em; } +table.progress { float: right; } +.contextual { float: left; } +.icon22 { background-position: 100% 40%; padding-right: 26px; padding-left: auto; } +h3, .wiki h2 { padding: 10px 2px 1px 0; } +.tooltip span.tip { text-align: right; } +tr.issue td.subject { text-align: right; } +tr.time-entry td.subject, tr.time-entry td.comments { text-align: right; } +#sidebar { float: left; } +#main.nosidebar #content { border-width: 1px; border-style: solid; border-color: #D7D7D7 #BBBBBB #BBBBBB #D7D7D7;} +.tabular.settings label { margin-left: auto; } +.splitcontentleft { float: right; } +.splitcontentright { float: left; } +p.progress-info { clear: right; } +table.list td.buttons a { padding-right: 20px; } +.filecontent { direction: ltr; } +.entries { direction: ltr; } +.changeset-changes { direction: ltr; padding-left: 2em } +.changesets { direction: ltr; } +div#issue-changesets { float: left; margin-right: 1em; margin-left: 0 } +div#issue-changesets div.wiki { direction: ltr; padding-left: 2em } +#activity dt, .journal { clear: right; } +.journal-link { float: left; } +div.wiki pre { direction: ltr; } + +ul.projects { padding-right: 1em; padding-left: 0; } +ul.projects ul.projects { border-right: 3px solid #e0e0e0; border-left: 0; } +.my-project { padding-right: 18px; padding-left: 0; background-position: 100% 50%; } + +#admin-menu a { background-position: 100% 40%; padding-right: 20px; padding-left: 0;} +input#openid_url { background-position: 100% 50%; padding-right: 18px; padding-left: 0; } + +tr.project.idnt td.name span { background: url(../images/bullet_arrow_left.png) no-repeat 100% 50%; padding-right: 16px; padding-left: 0; } +tr.project.idnt-1 td.name { padding-right: 0.5em; } +tr.project.idnt-2 td.name { padding-right: 2em; } +tr.project.idnt-3 td.name { padding-right: 3.5em; } +tr.project.idnt-4 td.name { padding-right: 5em; } +tr.project.idnt-5 td.name { padding-right: 6.5em; } +tr.project.idnt-6 td.name { padding-right: 8em; } +tr.project.idnt-7 td.name { padding-right: 9.5em; } +tr.project.idnt-8 td.name { padding-right: 11em; } +tr.project.idnt-9 td.name { padding-right: 12.5em; } + +tr.issue.idnt td.subject a { background: url(../images/bullet_arrow_left.png) no-repeat 100% 50%; padding-right: 16px; padding-left: 0; } +tr.issue.idnt-1 td.subject { padding-right: 0.5em; } +tr.issue.idnt-2 td.subject { padding-right: 2em; } +tr.issue.idnt-3 td.subject { padding-right: 3.5em; } +tr.issue.idnt-4 td.subject { padding-right: 5em; } +tr.issue.idnt-5 td.subject { padding-right: 6.5em; } +tr.issue.idnt-6 td.subject { padding-right: 8em; } +tr.issue.idnt-7 td.subject { padding-right: 9.5em; } +tr.issue.idnt-8 td.subject { padding-right: 11em; } +tr.issue.idnt-9 td.subject { padding-right: 12.5em; } + +div.wiki ul.toc { margin-right: 0; margin-left: 12px; } +div.wiki ul.toc li li { margin-right: 1.5em; margin-left: 0; } diff --git a/public/stylesheets/scm.css b/public/stylesheets/scm.css new file mode 100644 index 00000000..29c90a67 --- /dev/null +++ b/public/stylesheets/scm.css @@ -0,0 +1,104 @@ + +table.revision-info td { + margin: 0px; + padding: 0px; +} + +div.revision-graph { position: absolute; min-width: 1px; } + +div.changeset-changes ul { margin: 0; padding: 0; } +div.changeset-changes ul > ul { margin-left: 18px; padding: 0; } + +li.change { + list-style-type:none; + background-image: url(../images/bullet_black.png); + background-position: 1px 1px; + background-repeat: no-repeat; + padding-top: 1px; + padding-bottom: 1px; + padding-left: 20px; + margin: 0; +} +li.change.folder { background-image: url(../images/folder_open.png); } +li.change.folder.change-A { background-image: url(../images/folder_open_add.png); } +li.change.folder.change-M { background-image: url(../images/folder_open_orange.png); } +li.change.change-A { background-image: url(../images/bullet_add.png); } +li.change.change-M { background-image: url(../images/bullet_orange.png); } +li.change.change-C { background-image: url(../images/bullet_blue.png); } +li.change.change-R { background-image: url(../images/bullet_purple.png); } +li.change.change-D { background-image: url(../images/bullet_delete.png); } + +li.change .copied-from { font-style: italic; color: #999; font-size: 0.9em; } +li.change .copied-from:before { content: " - "} + +#changes-legend { float: right; font-size: 0.8em; margin:0; margin-right: 10px; }/*by young*/ +#changes-legend li { float: left; background-position: 5px 0; } + +table.filecontent { border: 1px solid #e2e2e2; border-collapse: collapse; width:98%; background-color: #fafafa; } +table.filecontent tbody {font-family:"Liberation Mono", Courier, monospace; font-size:12px;} +table.filecontent th { border: 1px solid #e2e2e2; background-color: #eee; } +table.filecontent th.filename { background-color: #e4e4d4; text-align: left; padding:5px;} +table.filecontent tr.spacing th { text-align:center; } +table.filecontent tr.spacing td { height: 0.4em; background: #EAF2F5;} +table.filecontent th.line-num { + border: 1px solid #e2e2e2; + text-align: right; + width: 2%; + padding: 0 3px 0 0; + color: #999; + user-select: none; + -moz-user-select: none; + -o-user-select: none; + -ms-user-select: none; + -webkit-user-select: none; + font-weight:normal; +} +table.filecontent th.line-num a { + text-decoration: none; + color: inherit; +} +table.filecontent td.line-code {padding: 0 0 0 4px;} +table.filecontent td.line-code pre { + margin: 0px; + white-space: pre-wrap; + font-family:"Liberation Mono", Courier, monospace; font-size:12px; +} + +/* 12 different colors for the annonate view */ +table.annotate tr.bloc-0 {background: #FFFFBF;} +table.annotate tr.bloc-1 {background: #EABFFF;} +table.annotate tr.bloc-2 {background: #BFFFFF;} +table.annotate tr.bloc-3 {background: #FFD9BF;} +table.annotate tr.bloc-4 {background: #E6FFBF;} +table.annotate tr.bloc-5 {background: #BFCFFF;} +table.annotate tr.bloc-6 {background: #FFBFEF;} +table.annotate tr.bloc-7 {background: #FFE6BF;} +table.annotate tr.bloc-8 {background: #FFE680;} +table.annotate tr.bloc-9 {background: #AA80FF;} +table.annotate tr.bloc-10 {background: #FFBFDC;} +table.annotate tr.bloc-11 {background: #BFE4FF;} + +table.annotate td.revision { + padding:0; + text-align: center; + width: 2%; + padding-left: 1em; + background: inherit; +} + +table.annotate td.author { + padding:0; + text-align: center; + border-right: 1px solid #d7d7d7; + white-space: nowrap; + padding-left: 1em; + padding-right: 1em; + width: 3%; + background: inherit; +} + +table.annotate td.line-code { background-color: #fafafa; } + +div.action_M { background: #fd8 } +div.action_D { background: #f88 } +div.action_A { background: #bfb } diff --git a/public/stylesheetsold/application.css b/public/stylesheetsold/application.css new file mode 100644 index 00000000..ca9877fd --- /dev/null +++ b/public/stylesheetsold/application.css @@ -0,0 +1,1148 @@ +html {overflow-y:scroll;} +body { font-family: Verdana, sans-serif; font-size: 12px; color:#484848; margin: 0; padding: 0; min-width: 900px; } + +h1, h2, h3, h4 {font-family: "Trebuchet MS", Verdana, sans-serif;padding: 2px 10px 1px 0px;margin: 0 0 10px 0;} +#content h1, h2, h3, h4 {color: #555;} +h2, .wiki h1 {font-size: 20px;} +h3, .wiki h2 {font-size: 16px;} +h4, .wiki h3 {font-size: 13px;} +h4 {border-bottom: 1px dotted #bbb;} + +/***** Layout *****/ +#wrapper {background: white;} + +#top-menu {background: #3E5B76; color: #fff; height:1.8em; font-size: 0.8em; padding: 2px 2px 0px 6px;} +#top-menu ul {margin: 0; padding: 0;} +#top-menu li { + float:left; + list-style-type:none; + margin: 0px 0px 0px 0px; + padding: 0px 0px 0px 0px; + white-space:nowrap; +} +#top-menu a {color: #fff; margin-right: 8px; font-weight: bold;} +#top-menu #loggedas { float: right; margin-right: 0.5em; color: #fff; } + +#account {float:right;} + +#header {min-height:5.3em;margin:0;background-color:#628DB6;color:#f8f8f8; padding: 4px 8px 20px 6px; position:relative;} +#header a {color:#f8f8f8;} +#header h1 a.ancestor { font-size: 80%; } +#quick-search {float:right;} + +#main-menu {position: absolute; bottom: 0px; left:6px; margin-right: -500px;} +#main-menu ul {margin: 0; padding: 0;} +#main-menu li { + float:left; + list-style-type:none; + margin: 0px 2px 0px 0px; + padding: 0px 0px 0px 0px; + white-space:nowrap; +} +#main-menu li a { + display: block; + color: #fff; + text-decoration: none; + font-weight: bold; + margin: 0; + padding: 4px 10px 4px 10px; +} +#main-menu li a:hover {background:#759FCF; color:#fff;} +#main-menu li a.selected, #main-menu li a.selected:hover {background:#fff; color:#555;} + +#admin-menu ul {margin: 0; padding: 0;} +#admin-menu li {margin: 0; padding: 0 0 6px 0; list-style-type:none;} + +#admin-menu a { background-position: 0% 40%; background-repeat: no-repeat; padding-left: 20px; padding-top: 2px; padding-bottom: 3px;} +#admin-menu a.projects { background-image: url(../images/projects.png); } +#admin-menu a.users { background-image: url(../images/user.png); } +#admin-menu a.groups { background-image: url(../images/group.png); } +#admin-menu a.roles { background-image: url(../images/database_key.png); } +#admin-menu a.trackers { background-image: url(../images/ticket.png); } +#admin-menu a.issue_statuses { background-image: url(../images/ticket_edit.png); } +#admin-menu a.workflows { background-image: url(../images/ticket_go.png); } +#admin-menu a.custom_fields { background-image: url(../images/textfield.png); } +#admin-menu a.enumerations { background-image: url(../images/text_list_bullets.png); } +#admin-menu a.settings { background-image: url(../images/changeset.png); } +#admin-menu a.plugins { background-image: url(../images/plugin.png); } +#admin-menu a.info { background-image: url(../images/help.png); } +#admin-menu a.server_authentication { background-image: url(../images/server_key.png); } + +#main {background-color:#EEEEEE;} + +#sidebar{ float: right; width: 22%; position: relative; z-index: 9; padding: 0; margin: 0;} +* html #sidebar{ width: 22%; } +#sidebar h3{ font-size: 14px; margin-top:14px; color: #666; } +#sidebar hr{ width: 100%; margin: 0 auto; height: 1px; background: #ccc; border: 0; } +* html #sidebar hr{ width: 95%; position: relative; left: -6px; color: #ccc; } +#sidebar .contextual { margin-right: 1em; } + +#content { width: 75%; background-color: #fff; margin: 0px; border-right: 1px solid #ddd; padding: 6px 10px 10px 10px; z-index: 10; } +* html #content{ width: 75%; padding-left: 0; margin-top: 0px; padding: 6px 10px 10px 10px;} +html>body #content { min-height: 600px; } +* html body #content { height: 600px; } /* IE */ + +#main.nosidebar #sidebar{ display: none; } +#main.nosidebar #content{ width: auto; border-right: 0; } + +#footer {clear: both; border-top: 1px solid #bbb; font-size: 0.9em; color: #aaa; padding: 5px; text-align:center; background:#fff;} + +#login-form table {margin-top:5em; padding:1em; margin-left: auto; margin-right: auto; border: 2px solid #FDBF3B; background-color:#FFEBC1; } +#login-form table td {padding: 6px;} +#login-form label {font-weight: bold;} +#login-form input#username, #login-form input#password { width: 300px; } + +div.modal { border-radius:5px; background:#fff; z-index:50; padding:4px;} +div.modal h3.title {display:none;} +div.modal p.buttons {text-align:right; margin-bottom:0;} + +input#openid_url { background: url(../images/openid-bg.gif) no-repeat; background-color: #fff; background-position: 0 50%; padding-left: 18px; } + +.clear:after{ content: "."; display: block; height: 0; clear: both; visibility: hidden; } + +/***** Links *****/ +a, a:link, a:visited{ color: #169; text-decoration: none; } +a:hover, a:active{ color: #c61a1a; text-decoration: underline;} +a img{ border: 0; } + +a.issue.closed, a.issue.closed:link, a.issue.closed:visited { color: #999; text-decoration: line-through; } +a.project.closed, a.project.closed:link, a.project.closed:visited { color: #999; } +a.user.locked, a.user.locked:link, a.user.locked:visited {color: #999;} + +#sidebar a.selected {line-height:1.7em; padding:1px 3px 2px 2px; margin-left:-2px; background-color:#9DB9D5; color:#fff; border-radius:2px;} +#sidebar a.selected:hover {text-decoration:none;} +#admin-menu a {line-height:1.7em;} +#admin-menu a.selected {padding-left: 20px !important; background-position: 2px 40%;} + +a.collapsible {padding-left: 12px; background: url(../images/arrow_expanded.png) no-repeat -3px 40%;} +a.collapsible.collapsed {background: url(../images/arrow_collapsed.png) no-repeat -5px 40%;} + +a#toggle-completed-versions {color:#999;} +/***** Tables *****/ +table.list { border: 1px solid #e4e4e4; border-collapse: collapse; width: 100%; margin-bottom: 4px; } +table.list th { background-color:#EEEEEE; padding: 4px; white-space:nowrap; } +table.list td { vertical-align: top; padding-right:10px; } +table.list td.id { width: 2%; text-align: center;} +table.list td.checkbox { width: 15px; padding: 2px 0 0 0; } +table.list td.checkbox input {padding:0px;} +table.list td.buttons { width: 15%; white-space:nowrap; text-align: right; } +table.list td.buttons a { padding-right: 0.6em; } +table.list caption { text-align: left; padding: 0.5em 0.5em 0.5em 0; } + +tr.project td.name a { white-space:nowrap; } +tr.project.closed, tr.project.archived { color: #aaa; } +tr.project.closed a, tr.project.archived a { color: #aaa; } + +tr.project.idnt td.name span {background: url(../images/bullet_arrow_right.png) no-repeat 0 50%; padding-left: 16px;} +tr.project.idnt-1 td.name {padding-left: 0.5em;} +tr.project.idnt-2 td.name {padding-left: 2em;} +tr.project.idnt-3 td.name {padding-left: 3.5em;} +tr.project.idnt-4 td.name {padding-left: 5em;} +tr.project.idnt-5 td.name {padding-left: 6.5em;} +tr.project.idnt-6 td.name {padding-left: 8em;} +tr.project.idnt-7 td.name {padding-left: 9.5em;} +tr.project.idnt-8 td.name {padding-left: 11em;} +tr.project.idnt-9 td.name {padding-left: 12.5em;} + +tr.issue { text-align: center; white-space: nowrap; } +tr.issue td.subject, tr.issue td.category, td.assigned_to, tr.issue td.string, tr.issue td.text, tr.issue td.relations { white-space: normal; } +tr.issue td.subject, tr.issue td.relations { text-align: left; } +tr.issue td.done_ratio table.progress { margin-left:auto; margin-right: auto;} +tr.issue td.relations span {white-space: nowrap;} +table.issues td.description {color:#777; font-size:90%; padding:4px 4px 4px 24px; text-align:left; white-space:normal;} +table.issues td.description pre {white-space:normal;} + +tr.issue.idnt td.subject a {background: url(../images/bullet_arrow_right.png) no-repeat 0 50%; padding-left: 16px;} +tr.issue.idnt-1 td.subject {padding-left: 0.5em;} +tr.issue.idnt-2 td.subject {padding-left: 2em;} +tr.issue.idnt-3 td.subject {padding-left: 3.5em;} +tr.issue.idnt-4 td.subject {padding-left: 5em;} +tr.issue.idnt-5 td.subject {padding-left: 6.5em;} +tr.issue.idnt-6 td.subject {padding-left: 8em;} +tr.issue.idnt-7 td.subject {padding-left: 9.5em;} +tr.issue.idnt-8 td.subject {padding-left: 11em;} +tr.issue.idnt-9 td.subject {padding-left: 12.5em;} + +tr.entry { border: 1px solid #f8f8f8; } +tr.entry td { white-space: nowrap; } +tr.entry td.filename { width: 30%; } +tr.entry td.filename_no_report { width: 70%; } +tr.entry td.size { text-align: right; font-size: 90%; } +tr.entry td.revision, tr.entry td.author { text-align: center; } +tr.entry td.age { text-align: right; } +tr.entry.file td.filename a { margin-left: 16px; } +tr.entry.file td.filename_no_report a { margin-left: 16px; } + +tr span.expander {background-image: url(../images/bullet_toggle_plus.png); padding-left: 8px; margin-left: 0; cursor: pointer;} +tr.open span.expander {background-image: url(../images/bullet_toggle_minus.png);} + +tr.changeset { height: 20px } +tr.changeset ul, ol { margin-top: 0px; margin-bottom: 0px; } +tr.changeset td.revision_graph { width: 15%; background-color: #fffffb; } +tr.changeset td.author { text-align: center; width: 15%; white-space:nowrap;} +tr.changeset td.committed_on { text-align: center; width: 15%; white-space:nowrap;} + +table.files tr.file td { text-align: center; } +table.files tr.file td.filename { text-align: left; padding-left: 24px; } +table.files tr.file td.digest { font-size: 80%; } + +table.members td.roles, table.memberships td.roles { width: 45%; } + +tr.message { height: 2.6em; } +tr.message td.subject { padding-left: 20px; } +tr.message td.created_on { white-space: nowrap; } +tr.message td.last_message { font-size: 80%; white-space: nowrap; } +tr.message.locked td.subject { background: url(../images/locked.png) no-repeat 0 1px; } +tr.message.sticky td.subject { background: url(../images/bullet_go.png) no-repeat 0 1px; font-weight: bold; } + +tr.version.closed, tr.version.closed a { color: #999; } +tr.version td.name { padding-left: 20px; } +tr.version.shared td.name { background: url(../images/link.png) no-repeat 0% 70%; } +tr.version td.date, tr.version td.status, tr.version td.sharing { text-align: center; white-space:nowrap; } + +tr.user td { width:13%; } +tr.user td.email { width:18%; } +tr.user td { white-space: nowrap; } +tr.user.locked, tr.user.registered { color: #aaa; } +tr.user.locked a, tr.user.registered a { color: #aaa; } + +table.permissions td.role {color:#999;font-size:90%;font-weight:normal !important;text-align:center;vertical-align:bottom;} + +tr.wiki-page-version td.updated_on, tr.wiki-page-version td.author {text-align:center;} + +tr.time-entry { text-align: center; white-space: nowrap; } +tr.time-entry td.issue, tr.time-entry td.comments { text-align: left; white-space: normal; } +td.hours { text-align: right; font-weight: bold; padding-right: 0.5em; } +td.hours .hours-dec { font-size: 0.9em; } + +table.plugins td { vertical-align: middle; } +table.plugins td.configure { text-align: right; padding-right: 1em; } +table.plugins span.name { font-weight: bold; display: block; margin-bottom: 6px; } +table.plugins span.description { display: block; font-size: 0.9em; } +table.plugins span.url { display: block; font-size: 0.9em; } + +table.list tbody tr.group td { padding: 0.8em 0 0.5em 0.3em; font-weight: bold; border-bottom: 1px solid #ccc; } +table.list tbody tr.group span.count {position:relative; top:-1px; color:#fff; font-size:10px; background:#9DB9D5; padding:0px 6px 1px 6px; border-radius:3px; margin-left:4px;} +tr.group a.toggle-all { color: #aaa; font-size: 80%; font-weight: normal; display:none;} +tr.group:hover a.toggle-all { display:inline;} +a.toggle-all:hover {text-decoration:none;} + +table.list tbody tr:hover { background-color:#ffffdd; } +table.list tbody tr.group:hover { background-color:inherit; } +table td {padding:2px;} +table p {margin:0;} +.odd {background-color:#f6f7f8;} +.even {background-color: #fff;} + +a.sort { padding-right: 16px; background-position: 100% 50%; background-repeat: no-repeat; } +a.sort.asc { background-image: url(../images/sort_asc.png); } +a.sort.desc { background-image: url(../images/sort_desc.png); } + +table.attributes { width: 100% } +table.attributes th { vertical-align: top; text-align: left; } +table.attributes td { vertical-align: top; } + +table.boards a.board, h3.comments { background: url(../images/comment.png) no-repeat 0% 50%; padding-left: 20px; } +table.boards td.topic-count, table.boards td.message-count {text-align:center;} +table.boards td.last-message {font-size:80%;} + +table.messages td.author, table.messages td.created_on, table.messages td.reply-count {text-align:center;} + +table.query-columns { + border-collapse: collapse; + border: 0; +} + +table.query-columns td.buttons { + vertical-align: middle; + text-align: center; +} + +td.center {text-align:center;} + +h3.version { background: url(../images/package.png) no-repeat 0% 50%; padding-left: 20px; } + +div.issues h3 { background: url(../images/ticket.png) no-repeat 0% 50%; padding-left: 20px; } +div.members h3 { background: url(../images/group.png) no-repeat 0% 50%; padding-left: 20px; } +div.news h3 { background: url(../images/news.png) no-repeat 0% 50%; padding-left: 20px; } +div.projects h3 { background: url(../images/projects.png) no-repeat 0% 50%; padding-left: 20px; } + +#watchers ul {margin: 0; padding: 0;} +#watchers li {list-style-type:none;margin: 0px 2px 0px 0px; padding: 0px 0px 0px 0px;} +#watchers select {width: 95%; display: block;} +#watchers a.delete {opacity: 0.4; vertical-align: middle;} +#watchers a.delete:hover {opacity: 1;} +#watchers img.gravatar {margin: 0 4px 2px 0;} + +span#watchers_inputs {overflow:auto; display:block;} +span.search_for_watchers {display:block;} +span.search_for_watchers, span.add_attachment {font-size:80%; line-height:2.5em;} +span.search_for_watchers a, span.add_attachment a {padding-left:16px; background: url(../images/bullet_add.png) no-repeat 0 50%; } + + +.highlight { background-color: #FCFD8D;} +.highlight.token-1 { background-color: #faa;} +.highlight.token-2 { background-color: #afa;} +.highlight.token-3 { background-color: #aaf;} + +.box{ + padding:6px; + margin-bottom: 10px; + background-color:#f6f6f6; + color:#505050; + line-height:1.5em; + border: 1px solid #e4e4e4; +} + +div.square { + border: 1px solid #999; + float: left; + margin: .3em .4em 0 .4em; + overflow: hidden; + width: .6em; height: .6em; +} +.contextual {float:right; white-space: nowrap; line-height:1.4em;margin-top:5px; padding-left: 10px; font-size:0.9em;} +.contextual input, .contextual select {font-size:0.9em;} +.message .contextual { margin-top: 0; } + +.splitcontent {overflow:auto;} +.splitcontentleft{float:left; width:49%;} +.splitcontentright{float:right; width:49%;} +form {display: inline;} +input, select {vertical-align: middle; margin-top: 1px; margin-bottom: 1px;} +fieldset {border: 1px solid #e4e4e4; margin:0;} +legend {color: #484848;} +hr { width: 100%; height: 1px; background: #ccc; border: 0;} +blockquote { font-style: italic; border-left: 3px solid #e0e0e0; padding-left: 0.6em; margin-left: 2.4em;} +blockquote blockquote { margin-left: 0;} +acronym { border-bottom: 1px dotted; cursor: help; } +textarea.wiki-edit {width:99%; resize:vertical;} +li p {margin-top: 0;} +div.issue {background:#ffffdd; padding:6px; margin-bottom:6px;border: 1px solid #d7d7d7;} +p.breadcrumb { font-size: 0.9em; margin: 4px 0 4px 0;} +p.subtitle { font-size: 0.9em; margin: -6px 0 12px 0; font-style: italic; } +p.footnote { font-size: 0.9em; margin-top: 0px; margin-bottom: 0px; } + +div.issue div.subject div div { padding-left: 16px; } +div.issue div.subject p {margin: 0; margin-bottom: 0.1em; font-size: 90%; color: #999;} +div.issue div.subject>div>p { margin-top: 0.5em; } +div.issue div.subject h3 {margin: 0; margin-bottom: 0.1em;} +div.issue span.private { position:relative; bottom: 2px; text-transform: uppercase; background: #d22; color: #fff; font-weight:bold; padding: 0px 2px 0px 2px; font-size: 60%; margin-right: 2px; border-radius: 2px;} +div.issue .next-prev-links {color:#999;} +div.issue table.attributes th {width:22%;} +div.issue table.attributes td {width:28%;} + +#issue_tree table.issues, #relations table.issues { border: 0; } +#issue_tree td.checkbox, #relations td.checkbox {display:none;} +#relations td.buttons {padding:0;} + +fieldset.collapsible { border-width: 1px 0 0 0; font-size: 0.9em; } +fieldset.collapsible>legend { padding-left: 16px; background: url(../images/arrow_expanded.png) no-repeat 0% 40%; cursor:pointer; } +fieldset.collapsible.collapsed>legend { background-image: url(../images/arrow_collapsed.png); } + +fieldset#date-range p { margin: 2px 0 2px 0; } +fieldset#filters table { border-collapse: collapse; } +fieldset#filters table td { padding: 0; vertical-align: middle; } +fieldset#filters tr.filter { height: 2.1em; } +fieldset#filters td.field { width:230px; } +fieldset#filters td.operator { width:180px; } +fieldset#filters td.operator select {max-width:170px;} +fieldset#filters td.values { white-space:nowrap; } +fieldset#filters td.values select {min-width:130px;} +fieldset#filters td.values input {height:1em;} +fieldset#filters td.add-filter { text-align: right; vertical-align: top; } + +.toggle-multiselect {background: url(../images/bullet_toggle_plus.png) no-repeat 0% 40%; padding-left:8px; margin-left:0; cursor:pointer;} +.buttons { font-size: 0.9em; margin-bottom: 1.4em; margin-top: 1em; } + +div#issue-changesets {float:right; width:45%; margin-left: 1em; margin-bottom: 1em; background: #fff; padding-left: 1em; font-size: 90%;} +div#issue-changesets div.changeset { padding: 4px;} +div#issue-changesets div.changeset { border-bottom: 1px solid #ddd; } +div#issue-changesets p { margin-top: 0; margin-bottom: 1em;} + +.journal ul.details img {margin:0 0 -3px 4px;} +div.journal {overflow:auto;} +div.journal.private-notes {border-left:2px solid #d22; padding-left:4px; margin-left:-6px;} + +div#activity dl, #search-results { margin-left: 2em; } +div#activity dd, #search-results dd { margin-bottom: 1em; padding-left: 18px; font-size: 0.9em; } +div#activity dt, #search-results dt { margin-bottom: 0px; padding-left: 20px; line-height: 18px; background-position: 0 50%; background-repeat: no-repeat; } +div#activity dt.me .time { border-bottom: 1px solid #999; } +div#activity dt .time { color: #777; font-size: 80%; } +div#activity dd .description, #search-results dd .description { font-style: italic; } +div#activity span.project:after, #search-results span.project:after { content: " -"; } +div#activity dd span.description, #search-results dd span.description { display:block; color: #808080; } +div#activity dt.grouped {margin-left:5em;} +div#activity dd.grouped {margin-left:9em;} + +#search-results dd { margin-bottom: 1em; padding-left: 20px; margin-left:0px; } + +div#search-results-counts {float:right;} +div#search-results-counts ul { margin-top: 0.5em; } +div#search-results-counts li { list-style-type:none; float: left; margin-left: 1em; } + +dt.issue { background-image: url(../images/ticket.png); } +dt.issue-edit { background-image: url(../images/ticket_edit.png); } +dt.issue-closed { background-image: url(../images/ticket_checked.png); } +dt.issue-note { background-image: url(../images/ticket_note.png); } +dt.changeset { background-image: url(../images/changeset.png); } +dt.news { background-image: url(../images/news.png); } +dt.message { background-image: url(../images/message.png); } +dt.reply { background-image: url(../images/comments.png); } +dt.wiki-page { background-image: url(../images/wiki_edit.png); } +dt.attachment { background-image: url(../images/attachment.png); } +dt.document { background-image: url(../images/document.png); } +dt.project { background-image: url(../images/projects.png); } +dt.time-entry { background-image: url(../images/time.png); } + +#search-results dt.issue.closed { background-image: url(../images/ticket_checked.png); } + +div#roadmap .related-issues { margin-bottom: 1em; } +div#roadmap .related-issues td.checkbox { display: none; } +div#roadmap .wiki h1:first-child { display: none; } +div#roadmap .wiki h1 { font-size: 120%; } +div#roadmap .wiki h2 { font-size: 110%; } +body.controller-versions.action-show div#roadmap .related-issues {width:70%;} + +div#version-summary { float:right; width:28%; margin-left: 16px; margin-bottom: 16px; background-color: #fff; } +div#version-summary fieldset { margin-bottom: 1em; } +div#version-summary fieldset.time-tracking table { width:100%; } +div#version-summary th, div#version-summary td.total-hours { text-align: right; } + +table#time-report td.hours, table#time-report th.period, table#time-report th.total { text-align: right; padding-right: 0.5em; } +table#time-report tbody tr.subtotal { font-style: italic; color:#777;} +table#time-report tbody tr.subtotal td.hours { color:#b0b0b0; } +table#time-report tbody tr.total { font-weight: bold; background-color:#EEEEEE; border-top:1px solid #e4e4e4;} +table#time-report .hours-dec { font-size: 0.9em; } + +div.wiki-page .contextual a {opacity: 0.4} +div.wiki-page .contextual a:hover {opacity: 1} + +form .attributes select { width: 60%; } +input#issue_subject { width: 99%; } +select#issue_done_ratio { width: 95px; } + +ul.projects {margin:0; padding-left:1em;} +ul.projects ul {padding-left:1.6em;} +ul.projects.root {margin:0; padding:0;} +ul.projects li {list-style-type:none;} + +#projects-index ul.projects ul.projects { border-left: 3px solid #e0e0e0; padding-left:1em;} +#projects-index ul.projects li.root {margin-bottom: 1em;} +#projects-index ul.projects li.child {margin-top: 1em;} +#projects-index ul.projects div.root a.project { font-family: "Trebuchet MS", Verdana, sans-serif; font-weight: bold; font-size: 16px; margin: 0 0 10px 0; } +.my-project { padding-left: 18px; background: url(../images/fav.png) no-repeat 0 50%; } + +#notified-projects ul, #tracker_project_ids ul {max-height:250px; overflow-y:auto;} + +#related-issues li img {vertical-align:middle;} + +ul.properties {padding:0; font-size: 0.9em; color: #777;} +ul.properties li {list-style-type:none;} +ul.properties li span {font-style:italic;} + +.total-hours { font-size: 110%; font-weight: bold; } +.total-hours span.hours-int { font-size: 120%; } + +.autoscroll {overflow-x: auto; padding:1px; margin-bottom: 1.2em;} +#user_login, #user_firstname, #user_lastname, #user_mail, #my_account_form select, #user_form select, #user_identity_url { width: 90%; } + +#workflow_copy_form select { width: 200px; } +table.transitions td.enabled {background: #bfb;} +table.fields_permissions select {font-size:90%} +table.fields_permissions td.readonly {background:#ddd;} +table.fields_permissions td.required {background:#d88;} + +textarea#custom_field_possible_values {width: 99%} +textarea#custom_field_default_value {width: 99%} + +input#content_comments {width: 99%} + +p.pagination {margin-top:8px; font-size: 90%} + +/***** Tabular forms ******/ +.tabular p{ + margin: 0; + padding: 3px 0 3px 0; + padding-left: 180px; /* width of left column containing the label elements */ + min-height: 1.8em; + clear:left; +} + +html>body .tabular p {overflow:hidden;} + +.tabular label{ + font-weight: bold; + float: left; + text-align: right; + /* width of left column */ + margin-left: -180px; + /* width of labels. Should be smaller than left column to create some right margin */ + width: 175px; +} + +.tabular label.floating{ + font-weight: normal; + margin-left: 0px; + text-align: left; + width: 270px; +} + +.tabular label.block{ + font-weight: normal; + margin-left: 0px !important; + text-align: left; + float: none; + display: block; + width: auto; +} + +.tabular label.inline{ + font-weight: normal; + float:none; + margin-left: 5px !important; + width: auto; +} + +label.no-css { + font-weight: inherit; + float:none; + text-align:left; + margin-left:0px; + width:auto; +} +input#time_entry_comments { width: 90%;} + +#preview fieldset {margin-top: 1em; background: url(../images/draft.png)} + +.tabular.settings p{ padding-left: 300px; } +.tabular.settings label{ margin-left: -300px; width: 295px; } +.tabular.settings textarea { width: 99%; } + +.settings.enabled_scm table {width:100%} +.settings.enabled_scm td.scm_name{ font-weight: bold; } + +fieldset.settings label { display: block; } +fieldset#notified_events .parent { padding-left: 20px; } + +span.required {color: #bb0000;} +.summary {font-style: italic;} + +#attachments_fields input.description {margin-left:4px; width:340px;} +#attachments_fields span {display:block; white-space:nowrap;} +#attachments_fields input.filename {border:0; height:1.8em; width:250px; color:#555; background-color:inherit; background:url(../images/attachment.png) no-repeat 1px 50%; padding-left:18px;} +#attachments_fields .ajax-waiting input.filename {background:url(../images/hourglass.png) no-repeat 0px 50%;} +#attachments_fields .ajax-loading input.filename {background:url(../images/loading.gif) no-repeat 0px 50%;} +#attachments_fields div.ui-progressbar { width: 100px; height:14px; margin: 2px 0 -5px 8px; display: inline-block; } +a.remove-upload {background: url(../images/delete.png) no-repeat 1px 50%; width:1px; display:inline-block; padding-left:16px;} +a.remove-upload:hover {text-decoration:none !important;} + +div.fileover { background-color: lavender; } + +div.attachments { margin-top: 12px; } +div.attachments p { margin:4px 0 2px 0; } +div.attachments img { vertical-align: middle; } +div.attachments span.author { font-size: 0.9em; color: #888; } + +div.thumbnails {margin-top:0.6em;} +div.thumbnails div {background:#fff;border:2px solid #ddd;display:inline-block;margin-right:2px;} +div.thumbnails img {margin: 3px;} + +p.other-formats { text-align: right; font-size:0.9em; color: #666; } +.other-formats span + span:before { content: "| "; } + +a.atom { background: url(../images/feed.png) no-repeat 1px 50%; padding: 2px 0px 3px 16px; } + +em.info {font-style:normal;font-size:90%;color:#888;display:block;} +em.info.error {padding-left:20px; background:url(../images/exclamation.png) no-repeat 0 50%;} + +textarea.text_cf {width:90%;} + +#tab-content-modules fieldset p {margin:3px 0 4px 0;} + +#tab-content-members .splitcontentleft, #tab-content-memberships .splitcontentleft, #tab-content-users .splitcontentleft {width: 64%;} +#tab-content-members .splitcontentright, #tab-content-memberships .splitcontentright, #tab-content-users .splitcontentright {width: 34%;} +#tab-content-members fieldset, #tab-content-memberships fieldset, #tab-content-users fieldset {padding:1em; margin-bottom: 1em;} +#tab-content-members fieldset legend, #tab-content-memberships fieldset legend, #tab-content-users fieldset legend {font-weight: bold;} +#tab-content-members fieldset label, #tab-content-memberships fieldset label, #tab-content-users fieldset label {display: block;} +#tab-content-members #principals, #tab-content-users #principals {max-height: 400px; overflow: auto;} + +#users_for_watcher {height: 200px; overflow:auto;} +#users_for_watcher label {display: block;} + +table.members td.group { padding-left: 20px; background: url(../images/group.png) no-repeat 0% 50%; } + +input#principal_search, input#user_search {width:90%} + +input.autocomplete { + background: #fff url(../images/magnifier.png) no-repeat 2px 50%; padding-left:20px; + border:1px solid #9EB1C2; border-radius:2px; height:1.5em; +} +input.autocomplete.ajax-loading { + background-image: url(../images/loading.gif); +} + +/***** Flash & error messages ****/ +#errorExplanation, div.flash, .nodata, .warning, .conflict { + padding: 4px 4px 4px 30px; + margin-bottom: 12px; + font-size: 1.1em; + border: 2px solid; +} + +div.flash {margin-top: 8px;} + +div.flash.error, #errorExplanation { + background: url(../images/exclamation.png) 8px 50% no-repeat; + background-color: #ffe3e3; + border-color: #dd0000; + color: #880000; +} + +div.flash.notice { + background: url(../images/true.png) 8px 5px no-repeat; + background-color: #dfffdf; + border-color: #9fcf9f; + color: #005f00; +} + +div.flash.warning, .conflict { + background: url(../images/warning.png) 8px 5px no-repeat; + background-color: #FFEBC1; + border-color: #FDBF3B; + color: #A6750C; + text-align: left; +} + +.nodata, .warning { + text-align: center; + background-color: #FFEBC1; + border-color: #FDBF3B; + color: #A6750C; +} + +#errorExplanation ul { font-size: 0.9em;} +#errorExplanation h2, #errorExplanation p { display: none; } + +.conflict-details {font-size:80%;} + +/***** Ajax indicator ******/ +#ajax-indicator { +position: absolute; /* fixed not supported by IE */ +background-color:#eee; +border: 1px solid #bbb; +top:35%; +left:40%; +width:20%; +font-weight:bold; +text-align:center; +padding:0.6em; +z-index:100; +opacity: 0.5; +} + +html>body #ajax-indicator { position: fixed; } + +#ajax-indicator span { +background-position: 0% 40%; +background-repeat: no-repeat; +background-image: url(../images/loading.gif); +padding-left: 26px; +vertical-align: bottom; +} + +/***** Calendar *****/ +table.cal {border-collapse: collapse; width: 100%; margin: 0px 0 6px 0;border: 1px solid #d7d7d7;} +table.cal thead th {width: 14%; background-color:#EEEEEE; padding: 4px; } +table.cal thead th.week-number {width: auto;} +table.cal tbody tr {height: 100px;} +table.cal td {border: 1px solid #d7d7d7; vertical-align: top; font-size: 0.9em;} +table.cal td.week-number { background-color:#EEEEEE; padding: 4px; border:none; font-size: 1em;} +table.cal td p.day-num {font-size: 1.1em; text-align:right;} +table.cal td.odd p.day-num {color: #bbb;} +table.cal td.today {background:#ffffdd;} +table.cal td.today p.day-num {font-weight: bold;} +table.cal .starting a, p.cal.legend .starting {background: url(../images/bullet_go.png) no-repeat -1px -2px; padding-left:16px;} +table.cal .ending a, p.cal.legend .ending {background: url(../images/bullet_end.png) no-repeat -1px -2px; padding-left:16px;} +table.cal .starting.ending a, p.cal.legend .starting.ending {background: url(../images/bullet_diamond.png) no-repeat -1px -2px; padding-left:16px;} +p.cal.legend span {display:block;} + +/***** Tooltips ******/ +.tooltip{position:relative;z-index:24;} +.tooltip:hover{z-index:25;color:#000;} +.tooltip span.tip{display: none; text-align:left;} + +div.tooltip:hover span.tip{ +display:block; +position:absolute; +top:12px; left:24px; width:270px; +border:1px solid #555; +background-color:#fff; +padding: 4px; +font-size: 0.8em; +color:#505050; +} + +img.ui-datepicker-trigger { + cursor: pointer; + vertical-align: middle; + margin-left: 4px; +} + +/***** Progress bar *****/ +table.progress { + border-collapse: collapse; + border-spacing: 0pt; + empty-cells: show; + text-align: center; + float:left; + margin: 1px 6px 1px 0px; +} + +table.progress td { height: 1em; } +table.progress td.closed { background: #BAE0BA none repeat scroll 0%; } +table.progress td.done { background: #D3EDD3 none repeat scroll 0%; } +table.progress td.todo { background: #eee none repeat scroll 0%; } +p.percent {font-size: 80%;} +p.progress-info {clear: left; font-size: 80%; margin-top:-4px; color:#777;} + +#roadmap table.progress td { height: 1.2em; } +/***** Tabs *****/ +#content .tabs {height: 2.6em; margin-bottom:1.2em; position:relative; overflow:hidden;} +#content .tabs ul {margin:0; position:absolute; bottom:0; padding-left:0.5em; width: 2000px; border-bottom: 1px solid #bbbbbb;} +#content .tabs ul li { + float:left; + list-style-type:none; + white-space:nowrap; + margin-right:4px; + background:#fff; + position:relative; + margin-bottom:-1px; +} +#content .tabs ul li a{ + display:block; + font-size: 0.9em; + text-decoration:none; + line-height:1.3em; + padding:4px 6px 4px 6px; + border: 1px solid #ccc; + border-bottom: 1px solid #bbbbbb; + background-color: #f6f6f6; + color:#999; + font-weight:bold; + border-top-left-radius:3px; + border-top-right-radius:3px; +} + +#content .tabs ul li a:hover { + background-color: #ffffdd; + text-decoration:none; +} + +#content .tabs ul li a.selected { + background-color: #fff; + border: 1px solid #bbbbbb; + border-bottom: 1px solid #fff; + color:#444; +} + +#content .tabs ul li a.selected:hover {background-color: #fff;} + +div.tabs-buttons { position:absolute; right: 0; width: 48px; height: 24px; background: white; bottom: 0; border-bottom: 1px solid #bbbbbb; } + +button.tab-left, button.tab-right { + font-size: 0.9em; + cursor: pointer; + height:24px; + border: 1px solid #ccc; + border-bottom: 1px solid #bbbbbb; + position:absolute; + padding:4px; + width: 20px; + bottom: -1px; +} + +button.tab-left { + right: 20px; + background: #eeeeee url(../images/bullet_arrow_left.png) no-repeat 50% 50%; + border-top-left-radius:3px; +} + +button.tab-right { + right: 0; + background: #eeeeee url(../images/bullet_arrow_right.png) no-repeat 50% 50%; + border-top-right-radius:3px; +} + +/***** Diff *****/ +.diff_out { background: #fcc; } +.diff_out span { background: #faa; } +.diff_in { background: #cfc; } +.diff_in span { background: #afa; } + +.text-diff { + padding: 1em; + background-color:#f6f6f6; + color:#505050; + border: 1px solid #e4e4e4; +} + +/***** Wiki *****/ +div.wiki table { + border-collapse: collapse; + margin-bottom: 1em; +} + +div.wiki table, div.wiki td, div.wiki th { + border: 1px solid #bbb; + padding: 4px; +} + +div.wiki .noborder, div.wiki .noborder td, div.wiki .noborder th {border:0;} + +div.wiki .external { + background-position: 0% 60%; + background-repeat: no-repeat; + padding-left: 12px; + background-image: url(../images/external.png); +} + +div.wiki a.new {color: #b73535;} + +div.wiki ul, div.wiki ol {margin-bottom:1em;} + +div.wiki pre { + margin: 1em 1em 1em 1.6em; + padding: 8px; + background-color: #fafafa; + border: 1px solid #e2e2e2; + width:auto; + overflow-x: auto; + overflow-y: hidden; +} + +div.wiki ul.toc { + background-color: #ffffdd; + border: 1px solid #e4e4e4; + padding: 4px; + line-height: 1.2em; + margin-bottom: 12px; + margin-right: 12px; + margin-left: 0; + display: table +} +* html div.wiki ul.toc { width: 50%; } /* IE6 doesn't autosize div */ + +div.wiki ul.toc.right { float: right; margin-left: 12px; margin-right: 0; width: auto; } +div.wiki ul.toc.left { float: left; margin-right: 12px; margin-left: 0; width: auto; } +div.wiki ul.toc ul { margin: 0; padding: 0; } +div.wiki ul.toc li {list-style-type:none; margin: 0; font-size:12px;} +div.wiki ul.toc li li {margin-left: 1.5em; font-size:10px;} +div.wiki ul.toc a { + font-size: 0.9em; + font-weight: normal; + text-decoration: none; + color: #606060; +} +div.wiki ul.toc a:hover { color: #c61a1a; text-decoration: underline;} + +a.wiki-anchor { display: none; margin-left: 6px; text-decoration: none; } +a.wiki-anchor:hover { color: #aaa !important; text-decoration: none; } +h1:hover a.wiki-anchor, h2:hover a.wiki-anchor, h3:hover a.wiki-anchor { display: inline; color: #ddd; } + +div.wiki img { vertical-align: middle; } + +/***** My page layout *****/ +.block-receiver { + border:1px dashed #c0c0c0; + margin-bottom: 20px; + padding: 15px 0 15px 0; +} + +.mypage-box { + margin:0 0 20px 0; + color:#505050; + line-height:1.5em; +} + +.handle {cursor: move;} + +a.close-icon { + display:block; + margin-top:3px; + overflow:hidden; + width:12px; + height:12px; + background-repeat: no-repeat; + cursor:pointer; + background-image:url('../images/close.png'); +} +a.close-icon:hover {background-image:url('../images/close_hl.png');} + +/***** Gantt chart *****/ +.gantt_hdr { + position:absolute; + top:0; + height:16px; + border-top: 1px solid #c0c0c0; + border-bottom: 1px solid #c0c0c0; + border-right: 1px solid #c0c0c0; + text-align: center; + overflow: hidden; +} + +.gantt_hdr.nwday {background-color:#f1f1f1;} + +.gantt_subjects { font-size: 0.8em; } +.gantt_subjects div { line-height:16px;height:16px;overflow:hidden;white-space:nowrap;text-overflow: ellipsis; } + +.task { + position: absolute; + height:8px; + font-size:0.8em; + color:#888; + padding:0; + margin:0; + line-height:16px; + white-space:nowrap; +} + +.task.label {width:100%;} +.task.label.project, .task.label.version { font-weight: bold; } + +.task_late { background:#f66 url(../images/task_late.png); border: 1px solid #f66; } +.task_done { background:#00c600 url(../images/task_done.png); border: 1px solid #00c600; } +.task_todo { background:#aaa url(../images/task_todo.png); border: 1px solid #aaa; } + +.task_todo.parent { background: #888; border: 1px solid #888; height: 3px;} +.task_late.parent, .task_done.parent { height: 3px;} +.task.parent.marker.starting { position: absolute; background: url(../images/task_parent_end.png) no-repeat 0 0; width: 8px; height: 16px; margin-left: -4px; left: 0px; top: -1px;} +.task.parent.marker.ending { position: absolute; background: url(../images/task_parent_end.png) no-repeat 0 0; width: 8px; height: 16px; margin-left: -4px; right: 0px; top: -1px;} + +.version.task_late { background:#f66 url(../images/milestone_late.png); border: 1px solid #f66; height: 2px; margin-top: 3px;} +.version.task_done { background:#00c600 url(../images/milestone_done.png); border: 1px solid #00c600; height: 2px; margin-top: 3px;} +.version.task_todo { background:#fff url(../images/milestone_todo.png); border: 1px solid #fff; height: 2px; margin-top: 3px;} +.version.marker { background-image:url(../images/version_marker.png); background-repeat: no-repeat; border: 0; margin-left: -4px; margin-top: 1px; } + +.project.task_late { background:#f66 url(../images/milestone_late.png); border: 1px solid #f66; height: 2px; margin-top: 3px;} +.project.task_done { background:#00c600 url(../images/milestone_done.png); border: 1px solid #00c600; height: 2px; margin-top: 3px;} +.project.task_todo { background:#fff url(../images/milestone_todo.png); border: 1px solid #fff; height: 2px; margin-top: 3px;} +.project.marker { background-image:url(../images/project_marker.png); background-repeat: no-repeat; border: 0; margin-left: -4px; margin-top: 1px; } + +.version-behind-schedule a, .issue-behind-schedule a {color: #f66914;} +.version-overdue a, .issue-overdue a, .project-overdue a {color: #f00;} + +/***** Icons *****/ +.icon { + background-position: 0% 50%; + background-repeat: no-repeat; + padding-left: 20px; + padding-top: 2px; + padding-bottom: 3px; +} + +.icon-add { background-image: url(../images/add.png); } +.icon-edit { background-image: url(../images/edit.png); } +.icon-copy { background-image: url(../images/copy.png); } +.icon-duplicate { background-image: url(../images/duplicate.png); } +.icon-del { background-image: url(../images/delete.png); } +.icon-move { background-image: url(../images/move.png); } +.icon-save { background-image: url(../images/save.png); } +.icon-cancel { background-image: url(../images/cancel.png); } +.icon-multiple { background-image: url(../images/table_multiple.png); } +.icon-folder { background-image: url(../images/folder.png); } +.open .icon-folder { background-image: url(../images/folder_open.png); } +.icon-package { background-image: url(../images/package.png); } +.icon-user { background-image: url(../images/user.png); } +.icon-projects { background-image: url(../images/projects.png); } +.icon-help { background-image: url(../images/help.png); } +.icon-attachment { background-image: url(../images/attachment.png); } +.icon-history { background-image: url(../images/history.png); } +.icon-time { background-image: url(../images/time.png); } +.icon-time-add { background-image: url(../images/time_add.png); } +.icon-stats { background-image: url(../images/stats.png); } +.icon-warning { background-image: url(../images/warning.png); } +.icon-fav { background-image: url(../images/fav.png); } +.icon-fav-off { background-image: url(../images/fav_off.png); } +.icon-reload { background-image: url(../images/reload.png); } +.icon-lock { background-image: url(../images/locked.png); } +.icon-unlock { background-image: url(../images/unlock.png); } +.icon-checked { background-image: url(../images/true.png); } +.icon-details { background-image: url(../images/zoom_in.png); } +.icon-report { background-image: url(../images/report.png); } +.icon-comment { background-image: url(../images/comment.png); } +.icon-summary { background-image: url(../images/lightning.png); } +.icon-server-authentication { background-image: url(../images/server_key.png); } +.icon-issue { background-image: url(../images/ticket.png); } +.icon-zoom-in { background-image: url(../images/zoom_in.png); } +.icon-zoom-out { background-image: url(../images/zoom_out.png); } +.icon-passwd { background-image: url(../images/textfield_key.png); } +.icon-test { background-image: url(../images/bullet_go.png); } + +.icon-file { background-image: url(../images/files/default.png); } +.icon-file.text-plain { background-image: url(../images/files/text.png); } +.icon-file.text-x-c { background-image: url(../images/files/c.png); } +.icon-file.text-x-csharp { background-image: url(../images/files/csharp.png); } +.icon-file.text-x-java { background-image: url(../images/files/java.png); } +.icon-file.text-x-javascript { background-image: url(../images/files/js.png); } +.icon-file.text-x-php { background-image: url(../images/files/php.png); } +.icon-file.text-x-ruby { background-image: url(../images/files/ruby.png); } +.icon-file.text-xml { background-image: url(../images/files/xml.png); } +.icon-file.text-css { background-image: url(../images/files/css.png); } +.icon-file.text-html { background-image: url(../images/files/html.png); } +.icon-file.image-gif { background-image: url(../images/files/image.png); } +.icon-file.image-jpeg { background-image: url(../images/files/image.png); } +.icon-file.image-png { background-image: url(../images/files/image.png); } +.icon-file.image-tiff { background-image: url(../images/files/image.png); } +.icon-file.application-pdf { background-image: url(../images/files/pdf.png); } +.icon-file.application-zip { background-image: url(../images/files/zip.png); } +.icon-file.application-x-gzip { background-image: url(../images/files/zip.png); } + +img.gravatar { + padding: 2px; + border: solid 1px #d5d5d5; + background: #fff; + vertical-align: middle; +} + +div.issue img.gravatar { + float: left; + margin: 0 6px 0 0; + padding: 5px; +} + +div.issue table img.gravatar { + height: 14px; + width: 14px; + padding: 2px; + float: left; + margin: 0 0.5em 0 0; +} + +h2 img.gravatar {margin: -2px 4px -4px 0;} +h3 img.gravatar {margin: -4px 4px -4px 0;} +h4 img.gravatar {margin: -6px 4px -4px 0;} +td.username img.gravatar {margin: 0 0.5em 0 0; vertical-align: top;} +#activity dt img.gravatar {float: left; margin: 0 1em 1em 0;} +/* Used on 12px Gravatar img tags without the icon background */ +.icon-gravatar {float: left; margin-right: 4px;} + +#activity dt, .journal {clear: left;} + +.journal-link {float: right;} + +h2 img { vertical-align:middle; } + +.hascontextmenu { cursor: context-menu; } + +/************* CodeRay styles *************/ +.syntaxhl div {display: inline;} +.syntaxhl .line-numbers {padding: 2px 4px 2px 4px; background-color: #eee; margin:0px 5px 0px 0px;} +.syntaxhl .code pre { overflow: auto } +.syntaxhl .debug { color: white !important; background: blue !important; } + +.syntaxhl .annotation { color:#007 } +.syntaxhl .attribute-name { color:#b48 } +.syntaxhl .attribute-value { color:#700 } +.syntaxhl .binary { color:#509 } +.syntaxhl .char .content { color:#D20 } +.syntaxhl .char .delimiter { color:#710 } +.syntaxhl .char { color:#D20 } +.syntaxhl .class { color:#258; font-weight:bold } +.syntaxhl .class-variable { color:#369 } +.syntaxhl .color { color:#0A0 } +.syntaxhl .comment { color:#385 } +.syntaxhl .comment .char { color:#385 } +.syntaxhl .comment .delimiter { color:#385 } +.syntaxhl .complex { color:#A08 } +.syntaxhl .constant { color:#258; font-weight:bold } +.syntaxhl .decorator { color:#B0B } +.syntaxhl .definition { color:#099; font-weight:bold } +.syntaxhl .delimiter { color:black } +.syntaxhl .directive { color:#088; font-weight:bold } +.syntaxhl .doc { color:#970 } +.syntaxhl .doc-string { color:#D42; font-weight:bold } +.syntaxhl .doctype { color:#34b } +.syntaxhl .entity { color:#800; font-weight:bold } +.syntaxhl .error { color:#F00; background-color:#FAA } +.syntaxhl .escape { color:#666 } +.syntaxhl .exception { color:#C00; font-weight:bold } +.syntaxhl .float { color:#06D } +.syntaxhl .function { color:#06B; font-weight:bold } +.syntaxhl .global-variable { color:#d70 } +.syntaxhl .hex { color:#02b } +.syntaxhl .imaginary { color:#f00 } +.syntaxhl .include { color:#B44; font-weight:bold } +.syntaxhl .inline { background-color: hsla(0,0%,0%,0.07); color: black } +.syntaxhl .inline-delimiter { font-weight: bold; color: #666 } +.syntaxhl .instance-variable { color:#33B } +.syntaxhl .integer { color:#06D } +.syntaxhl .key .char { color: #60f } +.syntaxhl .key .delimiter { color: #404 } +.syntaxhl .key { color: #606 } +.syntaxhl .keyword { color:#939; font-weight:bold } +.syntaxhl .label { color:#970; font-weight:bold } +.syntaxhl .local-variable { color:#963 } +.syntaxhl .namespace { color:#707; font-weight:bold } +.syntaxhl .octal { color:#40E } +.syntaxhl .operator { } +.syntaxhl .predefined { color:#369; font-weight:bold } +.syntaxhl .predefined-constant { color:#069 } +.syntaxhl .predefined-type { color:#0a5; font-weight:bold } +.syntaxhl .preprocessor { color:#579 } +.syntaxhl .pseudo-class { color:#00C; font-weight:bold } +.syntaxhl .regexp .content { color:#808 } +.syntaxhl .regexp .delimiter { color:#404 } +.syntaxhl .regexp .modifier { color:#C2C } +.syntaxhl .regexp { background-color:hsla(300,100%,50%,0.06); } +.syntaxhl .reserved { color:#080; font-weight:bold } +.syntaxhl .shell .content { color:#2B2 } +.syntaxhl .shell .delimiter { color:#161 } +.syntaxhl .shell { background-color:hsla(120,100%,50%,0.06); } +.syntaxhl .string .char { color: #46a } +.syntaxhl .string .content { color: #46a } +.syntaxhl .string .delimiter { color: #46a } +.syntaxhl .string .modifier { color: #46a } +.syntaxhl .symbol .content { color:#d33 } +.syntaxhl .symbol .delimiter { color:#d33 } +.syntaxhl .symbol { color:#d33 } +.syntaxhl .tag { color:#070 } +.syntaxhl .type { color:#339; font-weight:bold } +.syntaxhl .value { color: #088; } +.syntaxhl .variable { color:#037 } + +.syntaxhl .insert { background: hsla(120,100%,50%,0.12) } +.syntaxhl .delete { background: hsla(0,100%,50%,0.12) } +.syntaxhl .change { color: #bbf; background: #007; } +.syntaxhl .head { color: #f8f; background: #505 } +.syntaxhl .head .filename { color: white; } + +.syntaxhl .delete .eyecatcher { background-color: hsla(0,100%,50%,0.2); border: 1px solid hsla(0,100%,45%,0.5); margin: -1px; border-bottom: none; border-top-left-radius: 5px; border-top-right-radius: 5px; } +.syntaxhl .insert .eyecatcher { background-color: hsla(120,100%,50%,0.2); border: 1px solid hsla(120,100%,25%,0.5); margin: -1px; border-top: none; border-bottom-left-radius: 5px; border-bottom-right-radius: 5px; } + +.syntaxhl .insert .insert { color: #0c0; background:transparent; font-weight:bold } +.syntaxhl .delete .delete { color: #c00; background:transparent; font-weight:bold } +.syntaxhl .change .change { color: #88f } +.syntaxhl .head .head { color: #f4f } + +/***** Media print specific styles *****/ +@media print { + #top-menu, #header, #main-menu, #sidebar, #footer, .contextual, .other-formats { display:none; } + #main { background: #fff; } + #content { width: 99%; margin: 0; padding: 0; border: 0; background: #fff; overflow: visible !important;} + #wiki_add_attachment { display:none; } + .hide-when-print { display: none; } + .autoscroll {overflow-x: visible;} + table.list {margin-top:0.5em;} + table.list th, table.list td {border: 1px solid #aaa;} +} + +/* Accessibility specific styles */ +.hidden-for-sighted { + position:absolute; + left:-10000px; + top:auto; + width:1px; + height:1px; + overflow:hidden; +} diff --git a/public/stylesheetsold/context_menu.css b/public/stylesheetsold/context_menu.css new file mode 100644 index 00000000..1d02ebfb --- /dev/null +++ b/public/stylesheetsold/context_menu.css @@ -0,0 +1,52 @@ +#context-menu { position: absolute; z-index: 40; font-size: 0.9em;} + +#context-menu ul, #context-menu li, #context-menu a { + display:block; + margin:0; + padding:0; + border:0; +} + +#context-menu ul { + width:150px; + border: 1px solid #ccc; + background:white; + list-style:none; + padding:2px; + border-radius:2px; +} + +#context-menu li { + position:relative; + padding:1px; + z-index:39; + border:1px solid white; +} +#context-menu li.folder ul { position:absolute; left:168px; /* IE6 */ top:-2px; max-height:300px; overflow:hidden; overflow-y: auto; } +#context-menu li.folder>ul { left:148px; } + +#context-menu.reverse-y li.folder>ul { top:auto; bottom:0; } +#context-menu.reverse-x li.folder ul { left:auto; right:168px; /* IE6 */ } +#context-menu.reverse-x li.folder>ul { right:148px; } + +#context-menu a { + text-decoration:none !important; + background-repeat: no-repeat; + background-position: 1px 50%; + padding: 2px 0px 2px 20px; + width:100%; /* IE */ +} +#context-menu li>a { width:auto; } /* others */ +#context-menu a.disabled, #context-menu a.disabled:hover {color: #aaa;} +#context-menu li a.submenu { padding-right:16px; background:url("../images/bullet_arrow_right.png") right no-repeat; } +#context-menu li:hover { border:1px solid #628db6; background-color:#eef5fd; border-radius:3px; } +#context-menu a:hover {color:#2A5685;} +#context-menu li.folder:hover { z-index:40; } +#context-menu ul ul, #context-menu li:hover ul ul { display:none; } +#context-menu li:hover ul, #context-menu li:hover li:hover ul { display:block; } +#context-menu a.icon-checked {background: url(../images/toggle_check.png) no-repeat 3px 40%;} + +/* selected element */ +.context-menu-selection { background-color:#507AAA !important; color:#f8f8f8 !important; } +.context-menu-selection a, .context-menu-selection a:hover { color:#f8f8f8 !important; } +.context-menu-selection:hover { background-color:#507AAA !important; color:#f8f8f8 !important; } diff --git a/public/stylesheetsold/context_menu_rtl.css b/public/stylesheetsold/context_menu_rtl.css new file mode 100644 index 00000000..205bb918 --- /dev/null +++ b/public/stylesheetsold/context_menu_rtl.css @@ -0,0 +1,9 @@ +#context-menu li.folder ul { left:auto; right:168px; } +#context-menu li.folder>ul { left:auto; right:148px; } +#context-menu li a.submenu { background:url("../images/bullet_arrow_left.png") left no-repeat; } + +#context-menu a { + background-position: 100% 40%; + padding-right: 20px; + padding-left: 0px; +} diff --git a/public/stylesheetsold/jquery/images/ui-bg_diagonals-thick_18_b81900_40x40.png b/public/stylesheetsold/jquery/images/ui-bg_diagonals-thick_18_b81900_40x40.png new file mode 100644 index 00000000..954e22db Binary files /dev/null and b/public/stylesheetsold/jquery/images/ui-bg_diagonals-thick_18_b81900_40x40.png differ diff --git a/public/stylesheetsold/jquery/images/ui-bg_diagonals-thick_20_666666_40x40.png b/public/stylesheetsold/jquery/images/ui-bg_diagonals-thick_20_666666_40x40.png new file mode 100644 index 00000000..64ece570 Binary files /dev/null and b/public/stylesheetsold/jquery/images/ui-bg_diagonals-thick_20_666666_40x40.png differ diff --git a/public/stylesheetsold/jquery/images/ui-bg_flat_10_000000_40x100.png b/public/stylesheetsold/jquery/images/ui-bg_flat_10_000000_40x100.png new file mode 100644 index 00000000..abdc0108 Binary files /dev/null and b/public/stylesheetsold/jquery/images/ui-bg_flat_10_000000_40x100.png differ diff --git a/public/stylesheetsold/jquery/images/ui-bg_glass_100_eef5fd_1x400.png b/public/stylesheetsold/jquery/images/ui-bg_glass_100_eef5fd_1x400.png new file mode 100644 index 00000000..c3492e33 Binary files /dev/null and b/public/stylesheetsold/jquery/images/ui-bg_glass_100_eef5fd_1x400.png differ diff --git a/public/stylesheetsold/jquery/images/ui-bg_glass_100_f6f6f6_1x400.png b/public/stylesheetsold/jquery/images/ui-bg_glass_100_f6f6f6_1x400.png new file mode 100644 index 00000000..9b383f4d Binary files /dev/null and b/public/stylesheetsold/jquery/images/ui-bg_glass_100_f6f6f6_1x400.png differ diff --git a/public/stylesheetsold/jquery/images/ui-bg_glass_65_ffffff_1x400.png b/public/stylesheetsold/jquery/images/ui-bg_glass_65_ffffff_1x400.png new file mode 100644 index 00000000..42ccba26 Binary files /dev/null and b/public/stylesheetsold/jquery/images/ui-bg_glass_65_ffffff_1x400.png differ diff --git a/public/stylesheetsold/jquery/images/ui-bg_gloss-wave_35_759fcf_500x100.png b/public/stylesheetsold/jquery/images/ui-bg_gloss-wave_35_759fcf_500x100.png new file mode 100644 index 00000000..70b39a86 Binary files /dev/null and b/public/stylesheetsold/jquery/images/ui-bg_gloss-wave_35_759fcf_500x100.png differ diff --git a/public/stylesheetsold/jquery/images/ui-bg_highlight-soft_100_eeeeee_1x100.png b/public/stylesheetsold/jquery/images/ui-bg_highlight-soft_100_eeeeee_1x100.png new file mode 100644 index 00000000..f1273672 Binary files /dev/null and b/public/stylesheetsold/jquery/images/ui-bg_highlight-soft_100_eeeeee_1x100.png differ diff --git a/public/stylesheetsold/jquery/images/ui-bg_highlight-soft_75_759fcf_1x100.png b/public/stylesheetsold/jquery/images/ui-bg_highlight-soft_75_759fcf_1x100.png new file mode 100644 index 00000000..3fc3f9ba Binary files /dev/null and b/public/stylesheetsold/jquery/images/ui-bg_highlight-soft_75_759fcf_1x100.png differ diff --git a/public/stylesheetsold/jquery/images/ui-icons_222222_256x240.png b/public/stylesheetsold/jquery/images/ui-icons_222222_256x240.png new file mode 100644 index 00000000..b273ff11 Binary files /dev/null and b/public/stylesheetsold/jquery/images/ui-icons_222222_256x240.png differ diff --git a/public/stylesheetsold/jquery/images/ui-icons_759fcf_256x240.png b/public/stylesheetsold/jquery/images/ui-icons_759fcf_256x240.png new file mode 100644 index 00000000..e0c6374c Binary files /dev/null and b/public/stylesheetsold/jquery/images/ui-icons_759fcf_256x240.png differ diff --git a/public/stylesheetsold/jquery/images/ui-icons_ffd27a_256x240.png b/public/stylesheetsold/jquery/images/ui-icons_ffd27a_256x240.png new file mode 100644 index 00000000..e117effa Binary files /dev/null and b/public/stylesheetsold/jquery/images/ui-icons_ffd27a_256x240.png differ diff --git a/public/stylesheetsold/jquery/images/ui-icons_ffffff_256x240.png b/public/stylesheetsold/jquery/images/ui-icons_ffffff_256x240.png new file mode 100644 index 00000000..42f8f992 Binary files /dev/null and b/public/stylesheetsold/jquery/images/ui-icons_ffffff_256x240.png differ diff --git a/public/stylesheetsold/jquery/jquery-ui-1.9.2.css b/public/stylesheetsold/jquery/jquery-ui-1.9.2.css new file mode 100644 index 00000000..090d220d --- /dev/null +++ b/public/stylesheetsold/jquery/jquery-ui-1.9.2.css @@ -0,0 +1,5 @@ +/*! jQuery UI - v1.9.2 - 2012-12-26 +* http://jqueryui.com +* Includes: jquery.ui.core.css, jquery.ui.resizable.css, jquery.ui.selectable.css, jquery.ui.accordion.css, jquery.ui.autocomplete.css, jquery.ui.button.css, jquery.ui.datepicker.css, jquery.ui.dialog.css, jquery.ui.menu.css, jquery.ui.progressbar.css, jquery.ui.slider.css, jquery.ui.spinner.css, jquery.ui.tabs.css, jquery.ui.tooltip.css +* To view and modify this theme, visit http://jqueryui.com/themeroller/?ffDefault=Verdana%2C%20sans-serif&fwDefault=bold&fsDefault=1.1em&cornerRadius=4px&bgColorHeader=759fcf&bgTextureHeader=12_gloss_wave.png&bgImgOpacityHeader=35&borderColorHeader=628db6&fcHeader=ffffff&iconColorHeader=ffffff&bgColorContent=eeeeee&bgTextureContent=03_highlight_soft.png&bgImgOpacityContent=100&borderColorContent=dddddd&fcContent=333333&iconColorContent=222222&bgColorDefault=f6f6f6&bgTextureDefault=02_glass.png&bgImgOpacityDefault=100&borderColorDefault=cccccc&fcDefault=628db6&iconColorDefault=759fcf&bgColorHover=eef5fd&bgTextureHover=02_glass.png&bgImgOpacityHover=100&borderColorHover=628db6&fcHover=628db6&iconColorHover=759fcf&bgColorActive=ffffff&bgTextureActive=02_glass.png&bgImgOpacityActive=65&borderColorActive=628db6&fcActive=628db6&iconColorActive=759fcf&bgColorHighlight=759fcf&bgTextureHighlight=03_highlight_soft.png&bgImgOpacityHighlight=75&borderColorHighlight=628db6&fcHighlight=363636&iconColorHighlight=759fcf&bgColorError=b81900&bgTextureError=08_diagonals_thick.png&bgImgOpacityError=18&borderColorError=cd0a0a&fcError=ffffff&iconColorError=ffd27a&bgColorOverlay=666666&bgTextureOverlay=08_diagonals_thick.png&bgImgOpacityOverlay=20&opacityOverlay=50&bgColorShadow=000000&bgTextureShadow=01_flat.png&bgImgOpacityShadow=10&opacityShadow=20&thicknessShadow=5px&offsetTopShadow=-5px&offsetLeftShadow=-5px&cornerRadiusShadow=5px +* Copyright (c) 2012 jQuery Foundation and other contributors Licensed MIT */.ui-helper-hidden{display:none}.ui-helper-hidden-accessible{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.ui-helper-reset{margin:0;padding:0;border:0;outline:0;line-height:1.3;text-decoration:none;font-size:100%;list-style:none}.ui-helper-clearfix:before,.ui-helper-clearfix:after{content:"";display:table}.ui-helper-clearfix:after{clear:both}.ui-helper-clearfix{zoom:1}.ui-helper-zfix{width:100%;height:100%;top:0;left:0;position:absolute;opacity:0;filter:Alpha(Opacity=0)}.ui-state-disabled{cursor:default!important}.ui-icon{display:block;text-indent:-99999px;overflow:hidden;background-repeat:no-repeat}.ui-widget-overlay{position:absolute;top:0;left:0;width:100%;height:100%}.ui-resizable{position:relative}.ui-resizable-handle{position:absolute;font-size:0.1px;display:block}.ui-resizable-disabled .ui-resizable-handle,.ui-resizable-autohide .ui-resizable-handle{display:none}.ui-resizable-n{cursor:n-resize;height:7px;width:100%;top:-5px;left:0}.ui-resizable-s{cursor:s-resize;height:7px;width:100%;bottom:-5px;left:0}.ui-resizable-e{cursor:e-resize;width:7px;right:-5px;top:0;height:100%}.ui-resizable-w{cursor:w-resize;width:7px;left:-5px;top:0;height:100%}.ui-resizable-se{cursor:se-resize;width:12px;height:12px;right:1px;bottom:1px}.ui-resizable-sw{cursor:sw-resize;width:9px;height:9px;left:-5px;bottom:-5px}.ui-resizable-nw{cursor:nw-resize;width:9px;height:9px;left:-5px;top:-5px}.ui-resizable-ne{cursor:ne-resize;width:9px;height:9px;right:-5px;top:-5px}.ui-selectable-helper{position:absolute;z-index:100;border:1px dotted black}.ui-accordion .ui-accordion-header{display:block;cursor:pointer;position:relative;margin-top:2px;padding:.5em .5em .5em .7em;zoom:1}.ui-accordion .ui-accordion-icons{padding-left:2.2em}.ui-accordion .ui-accordion-noicons{padding-left:.7em}.ui-accordion .ui-accordion-icons .ui-accordion-icons{padding-left:2.2em}.ui-accordion .ui-accordion-header .ui-accordion-header-icon{position:absolute;left:.5em;top:50%;margin-top:-8px}.ui-accordion .ui-accordion-content{padding:1em 2.2em;border-top:0;overflow:auto;zoom:1}.ui-autocomplete{position:absolute;top:0;left:0;cursor:default}* html .ui-autocomplete{width:1px}.ui-button{display:inline-block;position:relative;padding:0;margin-right:.1em;cursor:pointer;text-align:center;zoom:1;overflow:visible}.ui-button,.ui-button:link,.ui-button:visited,.ui-button:hover,.ui-button:active{text-decoration:none}.ui-button-icon-only{width:2.2em}button.ui-button-icon-only{width:2.4em}.ui-button-icons-only{width:3.4em}button.ui-button-icons-only{width:3.7em}.ui-button .ui-button-text{display:block;line-height:1.4}.ui-button-text-only .ui-button-text{padding:.4em 1em}.ui-button-icon-only .ui-button-text,.ui-button-icons-only .ui-button-text{padding:.4em;text-indent:-9999999px}.ui-button-text-icon-primary .ui-button-text,.ui-button-text-icons .ui-button-text{padding:.4em 1em .4em 2.1em}.ui-button-text-icon-secondary .ui-button-text,.ui-button-text-icons .ui-button-text{padding:.4em 2.1em .4em 1em}.ui-button-text-icons .ui-button-text{padding-left:2.1em;padding-right:2.1em}input.ui-button{padding:.4em 1em}.ui-button-icon-only .ui-icon,.ui-button-text-icon-primary .ui-icon,.ui-button-text-icon-secondary .ui-icon,.ui-button-text-icons .ui-icon,.ui-button-icons-only .ui-icon{position:absolute;top:50%;margin-top:-8px}.ui-button-icon-only .ui-icon{left:50%;margin-left:-8px}.ui-button-text-icon-primary .ui-button-icon-primary,.ui-button-text-icons .ui-button-icon-primary,.ui-button-icons-only .ui-button-icon-primary{left:.5em}.ui-button-text-icon-secondary .ui-button-icon-secondary,.ui-button-text-icons .ui-button-icon-secondary,.ui-button-icons-only .ui-button-icon-secondary{right:.5em}.ui-button-text-icons .ui-button-icon-secondary,.ui-button-icons-only .ui-button-icon-secondary{right:.5em}.ui-buttonset{margin-right:7px}.ui-buttonset .ui-button{margin-left:0;margin-right:-.3em}button.ui-button::-moz-focus-inner{border:0;padding:0}.ui-datepicker{width:17em;padding:.2em .2em 0;display:none}.ui-datepicker .ui-datepicker-header{position:relative;padding:.2em 0}.ui-datepicker .ui-datepicker-prev,.ui-datepicker .ui-datepicker-next{position:absolute;top:2px;width:1.8em;height:1.8em}.ui-datepicker .ui-datepicker-prev-hover,.ui-datepicker .ui-datepicker-next-hover{top:1px}.ui-datepicker .ui-datepicker-prev{left:2px}.ui-datepicker .ui-datepicker-next{right:2px}.ui-datepicker .ui-datepicker-prev-hover{left:1px}.ui-datepicker .ui-datepicker-next-hover{right:1px}.ui-datepicker .ui-datepicker-prev span,.ui-datepicker .ui-datepicker-next span{display:block;position:absolute;left:50%;margin-left:-8px;top:50%;margin-top:-8px}.ui-datepicker .ui-datepicker-title{margin:0 2.3em;line-height:1.8em;text-align:center}.ui-datepicker .ui-datepicker-title select{font-size:1em;margin:1px 0}.ui-datepicker select.ui-datepicker-month-year{width:100%}.ui-datepicker select.ui-datepicker-month,.ui-datepicker select.ui-datepicker-year{width:49%}.ui-datepicker table{width:100%;font-size:.9em;border-collapse:collapse;margin:0 0 .4em}.ui-datepicker th{padding:.7em .3em;text-align:center;font-weight:bold;border:0}.ui-datepicker td{border:0;padding:1px}.ui-datepicker td span,.ui-datepicker td a{display:block;padding:.2em;text-align:right;text-decoration:none}.ui-datepicker .ui-datepicker-buttonpane{background-image:none;margin:.7em 0 0 0;padding:0 .2em;border-left:0;border-right:0;border-bottom:0}.ui-datepicker .ui-datepicker-buttonpane button{float:right;margin:.5em .2em .4em;cursor:pointer;padding:.2em .6em .3em .6em;width:auto;overflow:visible}.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current{float:left}.ui-datepicker.ui-datepicker-multi{width:auto}.ui-datepicker-multi .ui-datepicker-group{float:left}.ui-datepicker-multi .ui-datepicker-group table{width:95%;margin:0 auto .4em}.ui-datepicker-multi-2 .ui-datepicker-group{width:50%}.ui-datepicker-multi-3 .ui-datepicker-group{width:33.3%}.ui-datepicker-multi-4 .ui-datepicker-group{width:25%}.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header{border-left-width:0}.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header{border-left-width:0}.ui-datepicker-multi .ui-datepicker-buttonpane{clear:left}.ui-datepicker-row-break{clear:both;width:100%;font-size:0em}.ui-datepicker-rtl{direction:rtl}.ui-datepicker-rtl .ui-datepicker-prev{right:2px;left:auto}.ui-datepicker-rtl .ui-datepicker-next{left:2px;right:auto}.ui-datepicker-rtl .ui-datepicker-prev:hover{right:1px;left:auto}.ui-datepicker-rtl .ui-datepicker-next:hover{left:1px;right:auto}.ui-datepicker-rtl .ui-datepicker-buttonpane{clear:right}.ui-datepicker-rtl .ui-datepicker-buttonpane button{float:left}.ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current{float:right}.ui-datepicker-rtl .ui-datepicker-group{float:right}.ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header{border-right-width:0;border-left-width:1px}.ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header{border-right-width:0;border-left-width:1px}.ui-datepicker-cover{position:absolute;z-index:-1;filter:mask();top:-4px;left:-4px;width:200px;height:200px}.ui-dialog{position:absolute;top:0;left:0;padding:.2em;width:300px;overflow:hidden}.ui-dialog .ui-dialog-titlebar{padding:.4em 1em;position:relative}.ui-dialog .ui-dialog-title{float:left;margin:.1em 16px .1em 0}.ui-dialog .ui-dialog-titlebar-close{position:absolute;right:.3em;top:50%;width:19px;margin:-10px 0 0 0;padding:1px;height:18px}.ui-dialog .ui-dialog-titlebar-close span{display:block;margin:1px}.ui-dialog .ui-dialog-titlebar-close:hover,.ui-dialog .ui-dialog-titlebar-close:focus{padding:0}.ui-dialog .ui-dialog-content{position:relative;border:0;padding:.5em 1em;background:none;overflow:auto;zoom:1}.ui-dialog .ui-dialog-buttonpane{text-align:left;border-width:1px 0 0 0;background-image:none;margin:.5em 0 0 0;padding:.3em 1em .5em .4em}.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset{float:right}.ui-dialog .ui-dialog-buttonpane button{margin:.5em .4em .5em 0;cursor:pointer}.ui-dialog .ui-resizable-se{width:14px;height:14px;right:3px;bottom:3px}.ui-draggable .ui-dialog-titlebar{cursor:move}.ui-menu{list-style:none;padding:2px;margin:0;display:block;outline:none}.ui-menu .ui-menu{margin-top:-3px;position:absolute}.ui-menu .ui-menu-item{margin:0;padding:0;zoom:1;width:100%}.ui-menu .ui-menu-divider{margin:5px -2px 5px -2px;height:0;font-size:0;line-height:0;border-width:1px 0 0 0}.ui-menu .ui-menu-item a{text-decoration:none;display:block;padding:2px .4em;line-height:1.5;zoom:1;font-weight:normal}.ui-menu .ui-menu-item a.ui-state-focus,.ui-menu .ui-menu-item a.ui-state-active{font-weight:normal;margin:-1px}.ui-menu .ui-state-disabled{font-weight:normal;margin:.4em 0 .2em;line-height:1.5}.ui-menu .ui-state-disabled a{cursor:default}.ui-menu-icons{position:relative}.ui-menu-icons .ui-menu-item a{position:relative;padding-left:2em}.ui-menu .ui-icon{position:absolute;top:.2em;left:.2em}.ui-menu .ui-menu-icon{position:static;float:right}.ui-progressbar{height:2em;text-align:left;overflow:hidden}.ui-progressbar .ui-progressbar-value{margin:-1px;height:100%}.ui-slider{position:relative;text-align:left}.ui-slider .ui-slider-handle{position:absolute;z-index:2;width:1.2em;height:1.2em;cursor:default}.ui-slider .ui-slider-range{position:absolute;z-index:1;font-size:.7em;display:block;border:0;background-position:0 0}.ui-slider-horizontal{height:.8em}.ui-slider-horizontal .ui-slider-handle{top:-.3em;margin-left:-.6em}.ui-slider-horizontal .ui-slider-range{top:0;height:100%}.ui-slider-horizontal .ui-slider-range-min{left:0}.ui-slider-horizontal .ui-slider-range-max{right:0}.ui-slider-vertical{width:.8em;height:100px}.ui-slider-vertical .ui-slider-handle{left:-.3em;margin-left:0;margin-bottom:-.6em}.ui-slider-vertical .ui-slider-range{left:0;width:100%}.ui-slider-vertical .ui-slider-range-min{bottom:0}.ui-slider-vertical .ui-slider-range-max{top:0}.ui-spinner{position:relative;display:inline-block;overflow:hidden;padding:0;vertical-align:middle}.ui-spinner-input{border:none;background:none;padding:0;margin:.2em 0;vertical-align:middle;margin-left:.4em;margin-right:22px}.ui-spinner-button{width:16px;height:50%;font-size:.5em;padding:0;margin:0;text-align:center;position:absolute;cursor:default;display:block;overflow:hidden;right:0}.ui-spinner a.ui-spinner-button{border-top:none;border-bottom:none;border-right:none}.ui-spinner .ui-icon{position:absolute;margin-top:-8px;top:50%;left:0}.ui-spinner-up{top:0}.ui-spinner-down{bottom:0}.ui-spinner .ui-icon-triangle-1-s{background-position:-65px -16px}.ui-tabs{position:relative;padding:.2em;zoom:1}.ui-tabs .ui-tabs-nav{margin:0;padding:.2em .2em 0}.ui-tabs .ui-tabs-nav li{list-style:none;float:left;position:relative;top:0;margin:1px .2em 0 0;border-bottom:0;padding:0;white-space:nowrap}.ui-tabs .ui-tabs-nav li a{float:left;padding:.5em 1em;text-decoration:none}.ui-tabs .ui-tabs-nav li.ui-tabs-active{margin-bottom:-1px;padding-bottom:1px}.ui-tabs .ui-tabs-nav li.ui-tabs-active a,.ui-tabs .ui-tabs-nav li.ui-state-disabled a,.ui-tabs .ui-tabs-nav li.ui-tabs-loading a{cursor:text}.ui-tabs .ui-tabs-nav li a,.ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-active a{cursor:pointer}.ui-tabs .ui-tabs-panel{display:block;border-width:0;padding:1em 1.4em;background:none}.ui-tooltip{padding:8px;position:absolute;z-index:9999;max-width:300px;-webkit-box-shadow:0 0 5px #aaa;box-shadow:0 0 5px #aaa}* html .ui-tooltip{background-image:none}body .ui-tooltip{border-width:2px}.ui-widget{font-family:Verdana,sans-serif;font-size:1.1em}.ui-widget .ui-widget{font-size:1em}.ui-widget input,.ui-widget select,.ui-widget textarea,.ui-widget button{font-family:Verdana,sans-serif;font-size:1em}.ui-widget-content{border:1px solid #ddd;background:#eee url(images/ui-bg_highlight-soft_100_eeeeee_1x100.png) 50% top repeat-x;color:#333}.ui-widget-content a{color:#333}.ui-widget-header{border:1px solid #628db6;background:#759fcf url(images/ui-bg_gloss-wave_35_759fcf_500x100.png) 50% 50% repeat-x;color:#fff;font-weight:bold}.ui-widget-header a{color:#fff}.ui-state-default,.ui-widget-content .ui-state-default,.ui-widget-header .ui-state-default{border:1px solid #ccc;background:#f6f6f6 url(images/ui-bg_glass_100_f6f6f6_1x400.png) 50% 50% repeat-x;font-weight:bold;color:#628db6}.ui-state-default a,.ui-state-default a:link,.ui-state-default a:visited{color:#628db6;text-decoration:none}.ui-state-hover,.ui-widget-content .ui-state-hover,.ui-widget-header .ui-state-hover,.ui-state-focus,.ui-widget-content .ui-state-focus,.ui-widget-header .ui-state-focus{border:1px solid #628db6;background:#eef5fd url(images/ui-bg_glass_100_eef5fd_1x400.png) 50% 50% repeat-x;font-weight:bold;color:#628db6}.ui-state-hover a,.ui-state-hover a:hover,.ui-state-hover a:link,.ui-state-hover a:visited{color:#628db6;text-decoration:none}.ui-state-active,.ui-widget-content .ui-state-active,.ui-widget-header .ui-state-active{border:1px solid #628db6;background:#fff url(images/ui-bg_glass_65_ffffff_1x400.png) 50% 50% repeat-x;font-weight:bold;color:#628db6}.ui-state-active a,.ui-state-active a:link,.ui-state-active a:visited{color:#628db6;text-decoration:none}.ui-state-highlight,.ui-widget-content .ui-state-highlight,.ui-widget-header .ui-state-highlight{border:1px solid #628db6;background:#759fcf url(images/ui-bg_highlight-soft_75_759fcf_1x100.png) 50% top repeat-x;color:#363636}.ui-state-highlight a,.ui-widget-content .ui-state-highlight a,.ui-widget-header .ui-state-highlight a{color:#363636}.ui-state-error,.ui-widget-content .ui-state-error,.ui-widget-header .ui-state-error{border:1px solid #cd0a0a;background:#b81900 url(images/ui-bg_diagonals-thick_18_b81900_40x40.png) 50% 50% repeat;color:#fff}.ui-state-error a,.ui-widget-content .ui-state-error a,.ui-widget-header .ui-state-error a{color:#fff}.ui-state-error-text,.ui-widget-content .ui-state-error-text,.ui-widget-header .ui-state-error-text{color:#fff}.ui-priority-primary,.ui-widget-content .ui-priority-primary,.ui-widget-header .ui-priority-primary{font-weight:bold}.ui-priority-secondary,.ui-widget-content .ui-priority-secondary,.ui-widget-header .ui-priority-secondary{opacity:.7;filter:Alpha(Opacity=70);font-weight:normal}.ui-state-disabled,.ui-widget-content .ui-state-disabled,.ui-widget-header .ui-state-disabled{opacity:.35;filter:Alpha(Opacity=35);background-image:none}.ui-state-disabled .ui-icon{filter:Alpha(Opacity=35)}.ui-icon{width:16px;height:16px;background-image:url(images/ui-icons_222222_256x240.png)}.ui-widget-content .ui-icon{background-image:url(images/ui-icons_222222_256x240.png)}.ui-widget-header .ui-icon{background-image:url(images/ui-icons_ffffff_256x240.png)}.ui-state-default .ui-icon{background-image:url(images/ui-icons_759fcf_256x240.png)}.ui-state-hover .ui-icon,.ui-state-focus .ui-icon{background-image:url(images/ui-icons_759fcf_256x240.png)}.ui-state-active .ui-icon{background-image:url(images/ui-icons_759fcf_256x240.png)}.ui-state-highlight .ui-icon{background-image:url(images/ui-icons_759fcf_256x240.png)}.ui-state-error .ui-icon,.ui-state-error-text .ui-icon{background-image:url(images/ui-icons_ffd27a_256x240.png)}.ui-icon-carat-1-n{background-position:0 0}.ui-icon-carat-1-ne{background-position:-16px 0}.ui-icon-carat-1-e{background-position:-32px 0}.ui-icon-carat-1-se{background-position:-48px 0}.ui-icon-carat-1-s{background-position:-64px 0}.ui-icon-carat-1-sw{background-position:-80px 0}.ui-icon-carat-1-w{background-position:-96px 0}.ui-icon-carat-1-nw{background-position:-112px 0}.ui-icon-carat-2-n-s{background-position:-128px 0}.ui-icon-carat-2-e-w{background-position:-144px 0}.ui-icon-triangle-1-n{background-position:0 -16px}.ui-icon-triangle-1-ne{background-position:-16px -16px}.ui-icon-triangle-1-e{background-position:-32px -16px}.ui-icon-triangle-1-se{background-position:-48px -16px}.ui-icon-triangle-1-s{background-position:-64px -16px}.ui-icon-triangle-1-sw{background-position:-80px -16px}.ui-icon-triangle-1-w{background-position:-96px -16px}.ui-icon-triangle-1-nw{background-position:-112px -16px}.ui-icon-triangle-2-n-s{background-position:-128px -16px}.ui-icon-triangle-2-e-w{background-position:-144px -16px}.ui-icon-arrow-1-n{background-position:0 -32px}.ui-icon-arrow-1-ne{background-position:-16px -32px}.ui-icon-arrow-1-e{background-position:-32px -32px}.ui-icon-arrow-1-se{background-position:-48px -32px}.ui-icon-arrow-1-s{background-position:-64px -32px}.ui-icon-arrow-1-sw{background-position:-80px -32px}.ui-icon-arrow-1-w{background-position:-96px -32px}.ui-icon-arrow-1-nw{background-position:-112px -32px}.ui-icon-arrow-2-n-s{background-position:-128px -32px}.ui-icon-arrow-2-ne-sw{background-position:-144px -32px}.ui-icon-arrow-2-e-w{background-position:-160px -32px}.ui-icon-arrow-2-se-nw{background-position:-176px -32px}.ui-icon-arrowstop-1-n{background-position:-192px -32px}.ui-icon-arrowstop-1-e{background-position:-208px -32px}.ui-icon-arrowstop-1-s{background-position:-224px -32px}.ui-icon-arrowstop-1-w{background-position:-240px -32px}.ui-icon-arrowthick-1-n{background-position:0 -48px}.ui-icon-arrowthick-1-ne{background-position:-16px -48px}.ui-icon-arrowthick-1-e{background-position:-32px -48px}.ui-icon-arrowthick-1-se{background-position:-48px -48px}.ui-icon-arrowthick-1-s{background-position:-64px -48px}.ui-icon-arrowthick-1-sw{background-position:-80px -48px}.ui-icon-arrowthick-1-w{background-position:-96px -48px}.ui-icon-arrowthick-1-nw{background-position:-112px -48px}.ui-icon-arrowthick-2-n-s{background-position:-128px -48px}.ui-icon-arrowthick-2-ne-sw{background-position:-144px -48px}.ui-icon-arrowthick-2-e-w{background-position:-160px -48px}.ui-icon-arrowthick-2-se-nw{background-position:-176px -48px}.ui-icon-arrowthickstop-1-n{background-position:-192px -48px}.ui-icon-arrowthickstop-1-e{background-position:-208px -48px}.ui-icon-arrowthickstop-1-s{background-position:-224px -48px}.ui-icon-arrowthickstop-1-w{background-position:-240px -48px}.ui-icon-arrowreturnthick-1-w{background-position:0 -64px}.ui-icon-arrowreturnthick-1-n{background-position:-16px -64px}.ui-icon-arrowreturnthick-1-e{background-position:-32px -64px}.ui-icon-arrowreturnthick-1-s{background-position:-48px -64px}.ui-icon-arrowreturn-1-w{background-position:-64px -64px}.ui-icon-arrowreturn-1-n{background-position:-80px -64px}.ui-icon-arrowreturn-1-e{background-position:-96px -64px}.ui-icon-arrowreturn-1-s{background-position:-112px -64px}.ui-icon-arrowrefresh-1-w{background-position:-128px -64px}.ui-icon-arrowrefresh-1-n{background-position:-144px -64px}.ui-icon-arrowrefresh-1-e{background-position:-160px -64px}.ui-icon-arrowrefresh-1-s{background-position:-176px -64px}.ui-icon-arrow-4{background-position:0 -80px}.ui-icon-arrow-4-diag{background-position:-16px -80px}.ui-icon-extlink{background-position:-32px -80px}.ui-icon-newwin{background-position:-48px -80px}.ui-icon-refresh{background-position:-64px -80px}.ui-icon-shuffle{background-position:-80px -80px}.ui-icon-transfer-e-w{background-position:-96px -80px}.ui-icon-transferthick-e-w{background-position:-112px -80px}.ui-icon-folder-collapsed{background-position:0 -96px}.ui-icon-folder-open{background-position:-16px -96px}.ui-icon-document{background-position:-32px -96px}.ui-icon-document-b{background-position:-48px -96px}.ui-icon-note{background-position:-64px -96px}.ui-icon-mail-closed{background-position:-80px -96px}.ui-icon-mail-open{background-position:-96px -96px}.ui-icon-suitcase{background-position:-112px -96px}.ui-icon-comment{background-position:-128px -96px}.ui-icon-person{background-position:-144px -96px}.ui-icon-print{background-position:-160px -96px}.ui-icon-trash{background-position:-176px -96px}.ui-icon-locked{background-position:-192px -96px}.ui-icon-unlocked{background-position:-208px -96px}.ui-icon-bookmark{background-position:-224px -96px}.ui-icon-tag{background-position:-240px -96px}.ui-icon-home{background-position:0 -112px}.ui-icon-flag{background-position:-16px -112px}.ui-icon-calendar{background-position:-32px -112px}.ui-icon-cart{background-position:-48px -112px}.ui-icon-pencil{background-position:-64px -112px}.ui-icon-clock{background-position:-80px -112px}.ui-icon-disk{background-position:-96px -112px}.ui-icon-calculator{background-position:-112px -112px}.ui-icon-zoomin{background-position:-128px -112px}.ui-icon-zoomout{background-position:-144px -112px}.ui-icon-search{background-position:-160px -112px}.ui-icon-wrench{background-position:-176px -112px}.ui-icon-gear{background-position:-192px -112px}.ui-icon-heart{background-position:-208px -112px}.ui-icon-star{background-position:-224px -112px}.ui-icon-link{background-position:-240px -112px}.ui-icon-cancel{background-position:0 -128px}.ui-icon-plus{background-position:-16px -128px}.ui-icon-plusthick{background-position:-32px -128px}.ui-icon-minus{background-position:-48px -128px}.ui-icon-minusthick{background-position:-64px -128px}.ui-icon-close{background-position:-80px -128px}.ui-icon-closethick{background-position:-96px -128px}.ui-icon-key{background-position:-112px -128px}.ui-icon-lightbulb{background-position:-128px -128px}.ui-icon-scissors{background-position:-144px -128px}.ui-icon-clipboard{background-position:-160px -128px}.ui-icon-copy{background-position:-176px -128px}.ui-icon-contact{background-position:-192px -128px}.ui-icon-image{background-position:-208px -128px}.ui-icon-video{background-position:-224px -128px}.ui-icon-script{background-position:-240px -128px}.ui-icon-alert{background-position:0 -144px}.ui-icon-info{background-position:-16px -144px}.ui-icon-notice{background-position:-32px -144px}.ui-icon-help{background-position:-48px -144px}.ui-icon-check{background-position:-64px -144px}.ui-icon-bullet{background-position:-80px -144px}.ui-icon-radio-on{background-position:-96px -144px}.ui-icon-radio-off{background-position:-112px -144px}.ui-icon-pin-w{background-position:-128px -144px}.ui-icon-pin-s{background-position:-144px -144px}.ui-icon-play{background-position:0 -160px}.ui-icon-pause{background-position:-16px -160px}.ui-icon-seek-next{background-position:-32px -160px}.ui-icon-seek-prev{background-position:-48px -160px}.ui-icon-seek-end{background-position:-64px -160px}.ui-icon-seek-start{background-position:-80px -160px}.ui-icon-seek-first{background-position:-80px -160px}.ui-icon-stop{background-position:-96px -160px}.ui-icon-eject{background-position:-112px -160px}.ui-icon-volume-off{background-position:-128px -160px}.ui-icon-volume-on{background-position:-144px -160px}.ui-icon-power{background-position:0 -176px}.ui-icon-signal-diag{background-position:-16px -176px}.ui-icon-signal{background-position:-32px -176px}.ui-icon-battery-0{background-position:-48px -176px}.ui-icon-battery-1{background-position:-64px -176px}.ui-icon-battery-2{background-position:-80px -176px}.ui-icon-battery-3{background-position:-96px -176px}.ui-icon-circle-plus{background-position:0 -192px}.ui-icon-circle-minus{background-position:-16px -192px}.ui-icon-circle-close{background-position:-32px -192px}.ui-icon-circle-triangle-e{background-position:-48px -192px}.ui-icon-circle-triangle-s{background-position:-64px -192px}.ui-icon-circle-triangle-w{background-position:-80px -192px}.ui-icon-circle-triangle-n{background-position:-96px -192px}.ui-icon-circle-arrow-e{background-position:-112px -192px}.ui-icon-circle-arrow-s{background-position:-128px -192px}.ui-icon-circle-arrow-w{background-position:-144px -192px}.ui-icon-circle-arrow-n{background-position:-160px -192px}.ui-icon-circle-zoomin{background-position:-176px -192px}.ui-icon-circle-zoomout{background-position:-192px -192px}.ui-icon-circle-check{background-position:-208px -192px}.ui-icon-circlesmall-plus{background-position:0 -208px}.ui-icon-circlesmall-minus{background-position:-16px -208px}.ui-icon-circlesmall-close{background-position:-32px -208px}.ui-icon-squaresmall-plus{background-position:-48px -208px}.ui-icon-squaresmall-minus{background-position:-64px -208px}.ui-icon-squaresmall-close{background-position:-80px -208px}.ui-icon-grip-dotted-vertical{background-position:0 -224px}.ui-icon-grip-dotted-horizontal{background-position:-16px -224px}.ui-icon-grip-solid-vertical{background-position:-32px -224px}.ui-icon-grip-solid-horizontal{background-position:-48px -224px}.ui-icon-gripsmall-diagonal-se{background-position:-64px -224px}.ui-icon-grip-diagonal-se{background-position:-80px -224px}.ui-corner-all,.ui-corner-top,.ui-corner-left,.ui-corner-tl{-moz-border-radius-topleft:4px;-webkit-border-top-left-radius:4px;-khtml-border-top-left-radius:4px;border-top-left-radius:4px}.ui-corner-all,.ui-corner-top,.ui-corner-right,.ui-corner-tr{-moz-border-radius-topright:4px;-webkit-border-top-right-radius:4px;-khtml-border-top-right-radius:4px;border-top-right-radius:4px}.ui-corner-all,.ui-corner-bottom,.ui-corner-left,.ui-corner-bl{-moz-border-radius-bottomleft:4px;-webkit-border-bottom-left-radius:4px;-khtml-border-bottom-left-radius:4px;border-bottom-left-radius:4px}.ui-corner-all,.ui-corner-bottom,.ui-corner-right,.ui-corner-br{-moz-border-radius-bottomright:4px;-webkit-border-bottom-right-radius:4px;-khtml-border-bottom-right-radius:4px;border-bottom-right-radius:4px}.ui-widget-overlay{background:#666 url(images/ui-bg_diagonals-thick_20_666666_40x40.png) 50% 50% repeat;opacity:.5;filter:Alpha(Opacity=50)}.ui-widget-shadow{margin:-5px 0 0 -5px;padding:5px;background:#000 url(images/ui-bg_flat_10_000000_40x100.png) 50% 50% repeat-x;opacity:.2;filter:Alpha(Opacity=20);-moz-border-radius:5px;-khtml-border-radius:5px;-webkit-border-radius:5px;border-radius:5px} diff --git a/public/stylesheetsold/jstoolbar.css b/public/stylesheetsold/jstoolbar.css new file mode 100644 index 00000000..315d814b --- /dev/null +++ b/public/stylesheetsold/jstoolbar.css @@ -0,0 +1,100 @@ +.jstEditor { + padding-left: 0px; +} +.jstEditor textarea, .jstEditor iframe { + margin: 0; +} + +.jstHandle { + height: 10px; + font-size: 0.1em; + cursor: s-resize; + /*background: transparent url(img/resizer.png) no-repeat 45% 50%;*/ +} + +.jstElements { + padding: 3px 3px 3px 0; +} + +.jstElements button { + margin-right: 4px; + width : 24px; + height: 24px; + padding: 4px; + border-style: solid; + border-width: 1px; + border-color: #ddd; + background-color : #f7f7f7; + background-position : 50% 50%; + background-repeat: no-repeat; +} +.jstElements button:hover { + border-color: #bbb; + background-color: #e5e5e5; +} +.jstElements button span { + display : none; +} +.jstElements span { + display : inline; +} + +.jstSpacer { + width : 0px; + font-size: 1px; + margin-right: 6px; +} + +.jstElements .help { float: right; margin-right: 0.5em; padding-top: 8px; font-size: 0.9em; } +.jstElements .help a {padding: 2px 0 2px 20px; background: url(../images/help.png) no-repeat 0 50%;} + +/* Buttons +-------------------------------------------------------- */ +.jstb_strong { + background-image: url(../images/jstoolbar/bt_strong.png); +} +.jstb_em { + background-image: url(../images/jstoolbar/bt_em.png); +} +.jstb_ins { + background-image: url(../images/jstoolbar/bt_ins.png); +} +.jstb_del { + background-image: url(../images/jstoolbar/bt_del.png); +} +.jstb_code { + background-image: url(../images/jstoolbar/bt_code.png); +} +.jstb_h1 { + background-image: url(../images/jstoolbar/bt_h1.png); +} +.jstb_h2 { + background-image: url(../images/jstoolbar/bt_h2.png); +} +.jstb_h3 { + background-image: url(../images/jstoolbar/bt_h3.png); +} +.jstb_ul { + background-image: url(../images/jstoolbar/bt_ul.png); +} +.jstb_ol { + background-image: url(../images/jstoolbar/bt_ol.png); +} +.jstb_bq { + background-image: url(../images/jstoolbar/bt_bq.png); +} +.jstb_unbq { + background-image: url(../images/jstoolbar/bt_bq_remove.png); +} +.jstb_pre { + background-image: url(../images/jstoolbar/bt_pre.png); +} +.jstb_link { + background-image: url(../images/jstoolbar/bt_link.png); +} +.jstb_img { + background-image: url(../images/jstoolbar/bt_img.png); +} +.jstb_help { + background-image: url(../images/help.png); +} diff --git a/public/stylesheetsold/rtl.css b/public/stylesheetsold/rtl.css new file mode 100644 index 00000000..eb047794 --- /dev/null +++ b/public/stylesheetsold/rtl.css @@ -0,0 +1,94 @@ +body, #wrapper { direction: rtl;} + +#quick-search { float: left; } +#main-menu { margin-left: -500px; left: auto; right: 6px; margin-right: 0px;} +#main-menu li { float: right; } +#top-menu ul { float: right; } +#account { float: left; } +#top-menu #loggedas { float: left; } +#top-menu li { float: right; } +.tabular label.floating +{ + margin-right: 0; + margin-left: auto; + text-align: right; +} +.tabular label +{ + float: right; + margin-left: auto; +} +.tabular p +{ + clear: right; +} +.tabular label.block { text-align: right; } +.icon +{ + background-position: 100% 40%; + padding-right: 20px; + padding-left: 0px; +} +div#activity dt, #search-results dt +{ + background-position: 100% 50%; + padding-right: 20px; + padding-left: 0px; +} +#content .tabs ul li { float: right; } +#content .tabs ul { padding-left: auto; padding-right: 1em; } +table.progress { float: right; } +.contextual { float: left; } +.icon22 { background-position: 100% 40%; padding-right: 26px; padding-left: auto; } +h3, .wiki h2 { padding: 10px 2px 1px 0; } +.tooltip span.tip { text-align: right; } +tr.issue td.subject { text-align: right; } +tr.time-entry td.subject, tr.time-entry td.comments { text-align: right; } +#sidebar { float: left; } +#main.nosidebar #content { border-width: 1px; border-style: solid; border-color: #D7D7D7 #BBBBBB #BBBBBB #D7D7D7;} +.tabular.settings label { margin-left: auto; } +.splitcontentleft { float: right; } +.splitcontentright { float: left; } +p.progress-info { clear: right; } +table.list td.buttons a { padding-right: 20px; } +.filecontent { direction: ltr; } +.entries { direction: ltr; } +.changeset-changes { direction: ltr; padding-left: 2em } +.changesets { direction: ltr; } +div#issue-changesets { float: left; margin-right: 1em; margin-left: 0 } +div#issue-changesets div.wiki { direction: ltr; padding-left: 2em } +#activity dt, .journal { clear: right; } +.journal-link { float: left; } +div.wiki pre { direction: ltr; } + +ul.projects { padding-right: 1em; padding-left: 0; } +ul.projects ul.projects { border-right: 3px solid #e0e0e0; border-left: 0; } +.my-project { padding-right: 18px; padding-left: 0; background-position: 100% 50%; } + +#admin-menu a { background-position: 100% 40%; padding-right: 20px; padding-left: 0;} +input#openid_url { background-position: 100% 50%; padding-right: 18px; padding-left: 0; } + +tr.project.idnt td.name span { background: url(../images/bullet_arrow_left.png) no-repeat 100% 50%; padding-right: 16px; padding-left: 0; } +tr.project.idnt-1 td.name { padding-right: 0.5em; } +tr.project.idnt-2 td.name { padding-right: 2em; } +tr.project.idnt-3 td.name { padding-right: 3.5em; } +tr.project.idnt-4 td.name { padding-right: 5em; } +tr.project.idnt-5 td.name { padding-right: 6.5em; } +tr.project.idnt-6 td.name { padding-right: 8em; } +tr.project.idnt-7 td.name { padding-right: 9.5em; } +tr.project.idnt-8 td.name { padding-right: 11em; } +tr.project.idnt-9 td.name { padding-right: 12.5em; } + +tr.issue.idnt td.subject a { background: url(../images/bullet_arrow_left.png) no-repeat 100% 50%; padding-right: 16px; padding-left: 0; } +tr.issue.idnt-1 td.subject { padding-right: 0.5em; } +tr.issue.idnt-2 td.subject { padding-right: 2em; } +tr.issue.idnt-3 td.subject { padding-right: 3.5em; } +tr.issue.idnt-4 td.subject { padding-right: 5em; } +tr.issue.idnt-5 td.subject { padding-right: 6.5em; } +tr.issue.idnt-6 td.subject { padding-right: 8em; } +tr.issue.idnt-7 td.subject { padding-right: 9.5em; } +tr.issue.idnt-8 td.subject { padding-right: 11em; } +tr.issue.idnt-9 td.subject { padding-right: 12.5em; } + +div.wiki ul.toc { margin-right: 0; margin-left: 12px; } +div.wiki ul.toc li li { margin-right: 1.5em; margin-left: 0; } diff --git a/public/stylesheetsold/scm.css b/public/stylesheetsold/scm.css new file mode 100644 index 00000000..7ae59abd --- /dev/null +++ b/public/stylesheetsold/scm.css @@ -0,0 +1,104 @@ + +table.revision-info td { + margin: 0px; + padding: 0px; +} + +div.revision-graph { position: absolute; min-width: 1px; } + +div.changeset-changes ul { margin: 0; padding: 0; } +div.changeset-changes ul > ul { margin-left: 18px; padding: 0; } + +li.change { + list-style-type:none; + background-image: url(../images/bullet_black.png); + background-position: 1px 1px; + background-repeat: no-repeat; + padding-top: 1px; + padding-bottom: 1px; + padding-left: 20px; + margin: 0; +} +li.change.folder { background-image: url(../images/folder_open.png); } +li.change.folder.change-A { background-image: url(../images/folder_open_add.png); } +li.change.folder.change-M { background-image: url(../images/folder_open_orange.png); } +li.change.change-A { background-image: url(../images/bullet_add.png); } +li.change.change-M { background-image: url(../images/bullet_orange.png); } +li.change.change-C { background-image: url(../images/bullet_blue.png); } +li.change.change-R { background-image: url(../images/bullet_purple.png); } +li.change.change-D { background-image: url(../images/bullet_delete.png); } + +li.change .copied-from { font-style: italic; color: #999; font-size: 0.9em; } +li.change .copied-from:before { content: " - "} + +#changes-legend { float: right; font-size: 0.8em; margin: 0; } +#changes-legend li { float: left; background-position: 5px 0; } + +table.filecontent { border: 1px solid #e2e2e2; border-collapse: collapse; width:98%; background-color: #fafafa; } +table.filecontent tbody {font-family:"Liberation Mono", Courier, monospace; font-size:12px;} +table.filecontent th { border: 1px solid #e2e2e2; background-color: #eee; } +table.filecontent th.filename { background-color: #e4e4d4; text-align: left; padding:5px;} +table.filecontent tr.spacing th { text-align:center; } +table.filecontent tr.spacing td { height: 0.4em; background: #EAF2F5;} +table.filecontent th.line-num { + border: 1px solid #e2e2e2; + text-align: right; + width: 2%; + padding: 0 3px 0 0; + color: #999; + user-select: none; + -moz-user-select: none; + -o-user-select: none; + -ms-user-select: none; + -webkit-user-select: none; + font-weight:normal; +} +table.filecontent th.line-num a { + text-decoration: none; + color: inherit; +} +table.filecontent td.line-code {padding: 0 0 0 4px;} +table.filecontent td.line-code pre { + margin: 0px; + white-space: pre-wrap; + font-family:"Liberation Mono", Courier, monospace; font-size:12px; +} + +/* 12 different colors for the annonate view */ +table.annotate tr.bloc-0 {background: #FFFFBF;} +table.annotate tr.bloc-1 {background: #EABFFF;} +table.annotate tr.bloc-2 {background: #BFFFFF;} +table.annotate tr.bloc-3 {background: #FFD9BF;} +table.annotate tr.bloc-4 {background: #E6FFBF;} +table.annotate tr.bloc-5 {background: #BFCFFF;} +table.annotate tr.bloc-6 {background: #FFBFEF;} +table.annotate tr.bloc-7 {background: #FFE6BF;} +table.annotate tr.bloc-8 {background: #FFE680;} +table.annotate tr.bloc-9 {background: #AA80FF;} +table.annotate tr.bloc-10 {background: #FFBFDC;} +table.annotate tr.bloc-11 {background: #BFE4FF;} + +table.annotate td.revision { + padding:0; + text-align: center; + width: 2%; + padding-left: 1em; + background: inherit; +} + +table.annotate td.author { + padding:0; + text-align: center; + border-right: 1px solid #d7d7d7; + white-space: nowrap; + padding-left: 1em; + padding-right: 1em; + width: 3%; + background: inherit; +} + +table.annotate td.line-code { background-color: #fafafa; } + +div.action_M { background: #fd8 } +div.action_D { background: #f88 } +div.action_A { background: #bfb } diff --git a/public/themes/README b/public/themes/README new file mode 100644 index 00000000..1af3d199 --- /dev/null +++ b/public/themes/README @@ -0,0 +1 @@ +Put your Redmine themes here. diff --git a/public/themes/alternate/stylesheets/application.css b/public/themes/alternate/stylesheets/application.css new file mode 100644 index 00000000..efa1129e --- /dev/null +++ b/public/themes/alternate/stylesheets/application.css @@ -0,0 +1,70 @@ +@import url(../../../stylesheets/application.css); + +body, #wrapper { background-color:#EEEEEE; } +#header, #top-menu { margin: 0px 10px 0px 11px; } +#main { background: #EEEEEE; margin: 8px 10px 0px 10px; } +#content, #main.nosidebar #content { background: #fff; border-right: 1px solid #bbb; border-bottom: 1px solid #bbb; border-left: 1px solid #d7d7d7; border-top: 1px solid #d7d7d7; } +#footer { background-color:#EEEEEE; border: 0px; } + +/* Headers */ +h2, h3, h4, .wiki h1, .wiki h2, .wiki h3 {border-bottom: 0px;} + +/* Menu */ +#main-menu li a { background-color: #507AAA; font-weight: bold;} +#main-menu li a:hover { background: #507AAA; text-decoration: underline; } +#main-menu li a.selected, #main-menu li a.selected:hover { background-color:#EEEEEE; } + +/* Tables */ +table.list tbody td, table.list tbody tr:hover td { border: solid 1px #d7d7d7; } +table.list thead th { + border-width: 1px; + border-style: solid; + border-top-color: #d7d7d7; + border-right-color: #d7d7d7; + border-left-color: #d7d7d7; + border-bottom-color: #999999; +} + +/* Issues grid styles by priorities (provided by Wynn Netherland) */ +table.list tr.issue a { color: #666; } + +tr.odd.priority-highest, table.list tbody tr.odd.priority-highest:hover { color: #900; font-weight: bold; } +tr.odd.priority-highest { background: #ffc4c4; } +tr.even.priority-highest, table.list tbody tr.even.priority-highest:hover { color: #900; font-weight: bold; } +tr.even.priority-highest { background: #ffd4d4; } +tr.priority-highest a, tr.priority-5:hover a { color: #900; } +tr.odd.priority-highest td, tr.even.priority-highest td { border-color: #ffb4b4; } + +tr.odd.priority-high2, table.list tbody tr.odd.priority-high4:hover { color: #900; } +tr.odd.priority-high2 { background: #ffc4c4; } +tr.even.priority-high2, table.list tbody tr.even.priority-high4:hover { color: #900; } +tr.even.priority-high2 { background: #ffd4d4; } +tr.priority-high2 a { color: #900; } +tr.odd.priority-high2 td, tr.even.priority-high4 td { border-color: #ffb4b4; } + +tr.odd.priority-high3, table.list tbody tr.odd.priority-high3:hover { color: #900; } +tr.odd.priority-high3 { background: #fee; } +tr.even.priority-high3, table.list tbody tr.even.priority-high3:hover { color: #900; } +tr.even.priority-high3 { background: #fff2f2; } +tr.priority-high3 a { color: #900; } +tr.odd.priority-high3 td, tr.even.priority-high3 td { border-color: #fcc; } + +tr.odd.priority-lowest, table.list tbody tr.odd.priority-lowest:hover { color: #559; } +tr.odd.priority-lowest { background: #eaf7ff; } +tr.even.priority-lowest, table.list tbody tr.even.priority-lowest:hover { color: #559; } +tr.even.priority-lowest { background: #f2faff; } +tr.priority-lowest a { color: #559; } +tr.odd.priority-lowest td, tr.even.priority-lowest td { border-color: #add7f3; } + +/* Buttons */ +input[type="button"], input[type="submit"], input[type="reset"] { background-color: #f2f2f2; color: #222222; border: 1px outset #cccccc; } +input[type="button"]:hover, input[type="submit"]:hover, input[type="reset"]:hover { background-color: #ccccbb; } + +/* Fields */ +input[type="text"], input[type="password"], textarea, select { padding: 2px; border: 1px solid #d7d7d7; } +input[type="text"], input[type="password"] { padding: 3px; } +input[type="text"]:focus, input[type="password"]:focus, textarea:focus, select:focus { border: 1px solid #888866; } +option { border-bottom: 1px dotted #d7d7d7; } + +/* Misc */ +.box { background-color: #fcfcfc; } diff --git a/public/themes/classic/images/home.png b/public/themes/classic/images/home.png new file mode 100644 index 00000000..fed62219 Binary files /dev/null and b/public/themes/classic/images/home.png differ diff --git a/public/themes/classic/images/wrench.png b/public/themes/classic/images/wrench.png new file mode 100644 index 00000000..5c8213fe Binary files /dev/null and b/public/themes/classic/images/wrench.png differ diff --git a/public/themes/classic/stylesheets/application.css b/public/themes/classic/stylesheets/application.css new file mode 100644 index 00000000..3f855fe9 --- /dev/null +++ b/public/themes/classic/stylesheets/application.css @@ -0,0 +1,41 @@ +@import url(../../../stylesheets/application.css); + +body{ color:#303030; background:#e8eaec; } + +#top-menu { font-size: 80%; height: 2em; padding-top: 0.5em; background-color: #578bb8; } +#top-menu a { font-weight: bold; } +#header { background: #467aa7; height:5.8em; padding: 10px 0 0 0; } +#header h1 { margin-left: 6px; } +#quick-search { margin-right: 6px; } +#main-menu { background-color: #578bb8; left: 0; border-top: 1px solid #fff; width: 100%; } +#main-menu li { margin: 0; padding: 0; } +#main-menu li a { background-color: #578bb8; border-right: 1px solid #fff; font-size: 90%; padding: 4px 8px 4px 8px; font-weight: bold; } +#main-menu li a:hover { background-color: #80b0da; color: #ffffff; } +#main-menu li a.selected, #main-menu li a.selected:hover { background-color: #80b0da; color: #ffffff; } + +#footer { background-color: #578bb8; border: 0; color: #fff;} +#footer a { color: #fff; font-weight: bold; } + +#main { font:90% Verdana,Tahoma,Arial,sans-serif; background: #e8eaec; } +#main a { font-weight: bold; color: #467aa7;} +#main a:hover { color: #2a5a8a; text-decoration: underline; } +#content { background: #fff; } +#content .tabs ul { bottom:-1px; } + +h2, h3, h4, .wiki h1, .wiki h2, .wiki h3 { border-bottom: 0px; color:#606060; font-family: Trebuchet MS,Georgia,"Times New Roman",serif; } +h2, .wiki h1 { letter-spacing:-1px; } +h4 { border-bottom: dotted 1px #c0c0c0; } + +#top-menu a.home, #top-menu a.my-page, #top-menu a.projects, #top-menu a.administration, #top-menu a.help { + background-position: 0% 40%; + background-repeat: no-repeat; + padding-left: 20px; + padding-top: 2px; + padding-bottom: 3px; +} + +#top-menu a.home { background-image: url(../images/home.png); } +#top-menu a.my-page { background-image: url(../../../images/user.png); } +#top-menu a.projects { background-image: url(../../../images/projects.png); } +#top-menu a.administration { background-image: url(../images/wrench.png); } +#top-menu a.help { background-image: url(../../../images/help.png); } diff --git a/public/themes/redpenny-master/README.md b/public/themes/redpenny-master/README.md new file mode 100644 index 00000000..de6729e4 --- /dev/null +++ b/public/themes/redpenny-master/README.md @@ -0,0 +1,12 @@ +## Red Penny - Redmine Theme. + +### Installation +To install, just clone Red Penny files to your Redmine theme directory "public/themes" + +zsh$ cd /path/to/redmine/public/themes + +zsh$ git clone http://github.com/themondays/redpenny.git redpenny + +### Additional thank for amazing fonts: +Dave Gandy (@byscuits) +Paul D. Hunt \ No newline at end of file diff --git a/public/themes/redpenny-master/images/bg/bg.gif b/public/themes/redpenny-master/images/bg/bg.gif new file mode 100644 index 00000000..ee801204 Binary files /dev/null and b/public/themes/redpenny-master/images/bg/bg.gif differ diff --git a/public/themes/redpenny-master/images/bg/bg.jpg b/public/themes/redpenny-master/images/bg/bg.jpg new file mode 100644 index 00000000..fe5bdf09 Binary files /dev/null and b/public/themes/redpenny-master/images/bg/bg.jpg differ diff --git a/public/themes/redpenny-master/images/bg/f.jpg b/public/themes/redpenny-master/images/bg/f.jpg new file mode 100644 index 00000000..eb5528db Binary files /dev/null and b/public/themes/redpenny-master/images/bg/f.jpg differ diff --git a/public/themes/redpenny-master/images/bullet.png b/public/themes/redpenny-master/images/bullet.png new file mode 100644 index 00000000..c9106449 Binary files /dev/null and b/public/themes/redpenny-master/images/bullet.png differ diff --git a/public/themes/redpenny-master/images/logo.png b/public/themes/redpenny-master/images/logo.png new file mode 100644 index 00000000..88e31f56 Binary files /dev/null and b/public/themes/redpenny-master/images/logo.png differ diff --git a/public/themes/redpenny-master/stylesheets/application.css b/public/themes/redpenny-master/stylesheets/application.css new file mode 100644 index 00000000..7b40d828 --- /dev/null +++ b/public/themes/redpenny-master/stylesheets/application.css @@ -0,0 +1,1505 @@ +/** + * Redpenny stylesheet + * + * Author: Jarod Denison (@jaroslavius) + * @2013-05-25 + * + */ + + +@import "http://fonts.googleapis.com/css?family=PT+Sans:400,700|Source+Code+Pro"; +@import "../../../stylesheets/application.css"; + +@font-face { + font-family: 'FontAwesome'; + src: url('font/fontawesome-webfont.eot?v=3.1.0'); + src: url('font/fontawesome-webfont.eot?#iefix&v=3.1.0') format('embedded-opentype'), url('font/fontawesome-webfont.woff?v=3.1.0') format('woff'), url('font/fontawesome-webfont.ttf?v=3.1.0') format('truetype'), url('font/fontawesome-webfont.svg#fontawesomeregular?v=3.1.0') format('svg'); + font-weight: normal; + font-style: normal; +} + +#header > h1 { + /*background: url(../images/logo.png) no-repeat 30px 30%;*/ + /*by young*/ + padding: 29px 130px; +} + + +/*by young*/ + +#header > h1 { + /*background: url(../images/logo.gif) no-repeat 40px 45%;*/ + padding: 28px 130px; +} +/*end*/ + +@media only screen and (-webkit-min-device-pixel-ratio: 2), +only screen and (min-device-pixel-ratio: 2) { + #header > h1 { + background-image:ol url(../images/logo-2x.png); + background-size: 43px 30px; + } +} +#body +{ + padding-top:90px; + background-image:url(images/bg/bg.gif); + background-repeat:repeat-x; + background-position:center top +} + +body,#wrapper +{ + background-color:#fff; /*整体背景色ecfffb*/ + font-family:Helvetica,Arial,"Lucida Grande",verdana,sans-serif +} + +a +{ + transition:all .2s linear; + -moz-transition:all .2s linear; + -o-transition:all .2s linear; + -webkit-transition:all .2s linear +} + + +.action-settings #header h1:before +{ + font-family: Fontawesome; + + +/*by young*/ +.action-settings #header h1:before +{ + font-family: Fontawesome; +/* content: "\f013";*/ + + padding-right: 5px; +} + +.controller-projects.action-show #header h1:before +{ + font-family: Fontawesome; + + + +/* content: "\f132";*/ + + padding-right: 5px; +} + +.controller-activities #header h1:before +{ + font-family: Fontawesome; + + + +/* content: "\f135";*/ + + padding-right: 5px; +} + +.controller-versions #header h1:before +{ + font-family: Fontawesome; + + + +/* content: "\f018";*/ + + padding-right: 5px; +} + +.controller-issues #header h1:before +{ + font-family: Fontawesome; + + + +/* content: "\f145";*/ + + padding-right: 5px; +} + +.controller-calendars #header h1:before +{ + font-family: Fontawesome; + + + +/* content: "\f073";*/ + + padding-right: 5px; +} + +.controller-news #header h1:before +{ + font-family: Fontawesome; + + + +/* content: "\f06c";*/ + + padding-right: 5px; +} + +.controller-documents #header h1:before +{ + font-family: Fontawesome; + + + +/* content: "\f02d";*/ + + padding-right: 5px; +} + +.controller-wiki #header h1:before +{ + font-family: Fontawesome; + + + +/* content: "\f14b";*/ + + padding-right: 5px; +} + +.controller-files #header h1:before +{ + font-family: Fontawesome; + + + +/* content: "\f0b1";*/ + + padding-right: 5px; +} + +.controller-repositories #header h1:before +{ + font-family: Fontawesome; + + + +/* content: "\f074";*/ + + padding-right: 5px; +} + +.controller-gantts #header h1:before +{ + font-family: Fontawesome; + + + +/* content: "\f080";*/ + + padding-right: 5px; +} + +.controller-admin #header,.controller-users #header,.controller-groups #header,.controller-roles #header,.controller-trackers #header,.controller-issue_statuses #header,.controller-workflows #header,.controller-custom_fields #header,.controller-users #header,.controller-enumerations #header,.controller-settings #header,.controller-auth_sources #header,.controller-plugins #header,.controller-info #header,.controller-projects.action-index #header,.controller-welcome #header,.controller-my #header,.controller-account.action-login #header +{ + height:3.1em +} + +.controller-account.action-login #content +{ + background-color:#fafafa!important +} +.controller-welcome #header h1:before +{ + font-family: Fontawesome; + + + +/* content: "\f015 ";*/ + + padding-right: 5px; + font-weight: 100; +} +.controller-users #header h1:before +{ + font-family: Fontawesome; + + + padding-right: 5px; +} + +/* content: "\f0f0 ";*/ + padding-right: 5px; +} +/*end*/ + + +.splitcontentright .projects.box ul +{ + padding-left:20px +} + +.splitcontentright .projects.box li +{ + margin-bottom: 10px; + list-style:none +} +.splitcontentleft .news.box p a:first-child, +.splitcontentright .news.box p a:first-child, + +.splitcontentleft .projects.box li a:link, +.splitcontentright .projects.box li a:link +{ + font-size: 11px; + border-radius:3px; + -moz-border-radius:3px; + -webkit-border-radius:3px; + -o-border-radius:3px; + -ms-border-radius:3px; + background-color:#eee; /* 项目名底色 */ + padding:4px 10px +} + +a:hover +{ + text-decoration:underline +} + +a:hover,a:active +{ + color:#FF0000 /* 项目字体底色 */ +} + +.action-index .wiki +{ + width:100%; /* 描述字体内容的宽度 */ + color:#909090; /* 项目描述字体颜色 */ + display:block +} + +.action-index h4 a +{ + font-size:110%; + border-bottom:#ededed 1px dashed; + display:block; + padding-bottom:5px +} + +.action-index h3 +{ + background-color:#fff; /* 右top边项目底色 */ + padding:10px +} +/*by young +.action-index p +{ + margin-top:0; + padding-top:0; +} +*/ +ul.projects.root +{ + -webkit-column-count:4; + -moz-column-count:4; + -ms-column-count:4; + -o-column-count:4; + column-count:4 +} + +ul.projects li.root +{ + padding:5%; /*项目界面的宽度 */ + height:25px; + background-color:#0ee; /* 项目界面 #eee*/ + margin:0 0 10px; + display:inline-block; + width:90%; + vertical-align:top; + border-bottom:2px #dbedf4 solid; + border-left:1px dotted #dbedf4 +} + +#header,#top-menu +{ + margin:60; +} +/*by young*/ +#header +{ + background-color: #FFFFFF; +/* background-image: -moz-linear-gradient(top,#BBBBBB,#FFFFEC); + background-image: -webkit-gradient(linear,0 0,0 100%,from(#039ea0),to(#f5f1e8)); + background-image: -webkit-linear-gradient(top,#039ea0,#f5f1e8); + background-image: -o-linear-gradient(top,#039ea0,#f5f1e8); + background-image: linear-gradient(to bottom,#039ea0,#f5f1e8); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff222222',endColorstr='#ff111111',GradientType=0);*/ + border-color: #252525; + + height: 130px; + + height: 125px; + + color: #000000; +} +/*控制logo位置,如redmine位置*/ +#header h1 +{ + margin:0 0px; + + margin-top: 5px; + margin-left: 5px; + + height: 61px;/*by young*/ + margin-top: -90px;/*by young*/ + margin-left: -30px; + + color: #000000; +} +/*添加logo*/ + +#header #quick-search +{ + margin:3px 24px 0; + color: #000000; +} + +#top-menu +{ + background-color:#000; /*顶层导航颜色*/ + font-size:12px; + position:relative; + padding:0; + height:1px; + padding-top:0 +} + +#top-menu ul +{ + padding:0 1px /*控制顶层导航宽度*/ +} + +#top-menu li,#top-menu #loggedas +{ + /*by young*/ + color:#AAAAAA; + line-height:21px; + margin-right:4px +} + +#top-menu li a +{ + /*by young*/ + color:#AAAAAA; + font-weight:6px; + padding:4px 5px +} + +#top-menu li a:hover +{ + color:#a1ebff; /*顶层导航鼠标效果*/ + text-decoration:none +} + +#main +{ + background:#fff; /*右边图标背景颜色dbedf4*/ + margin:20px 24px 0 +} + +#content,#main.nosidebar #content +{ + /*by young*/ +/* background:#fff; /*主题框架背景yanse*/ +/* border-right:1px solid #bbb; + border-bottom:1px solid #bbb; + overflow:auto; + + -moz-box-shadow:#bbb 1px 1px 2px; + -webkit-box-shadow:2px 2px 0px -2px #bbb; + border-left:1px #ddd solid*/ +} + +#content +{ + width:680px; + float:right; + background-color: #FFFFFF +} + +#content .wiki img +{ + max-width:98% +} + +#main.nosidebar #content_ +{ + width:auto; + float:center; + min-height:800px; +} + + +#sidebar +{ + width:240px;/*by young*/ + height: auto; + background:#edecec; /*主题框架背景yanse*/ + border-right:1px solid #bbb; + overflow:auto; + /*by young*/ + -moz-box-shadow:#bbb 1px 1px 2px; + -webkit-box-shadow:2px 2px 0px -2px #bbb; +} + +#sidebar a,#sidebar a.selected +{ + display:inline-block; + padding:4px 4px 4px 21px !important; + transition:all .2s linear; + -moz-transition:all .2s linear; + -o-transition:all .2s linear; + -webkit-transition:all .2s linear; +} + +#sidebar a.selected +{ + padding-top:2px; + padding-bottom:2px; + background-position:2px 5px; + margin:auto; + color:#a0a0a0; + font-weight:600 +} + +#footer +{ + background-color:#EEE; /*低端背景*/ + border:0; + clear:left; + color:#666; + font-size:9px; + margin:4px 20px 20px; + padding-bottom:15px; + text-align:left +} + +#footer a:hover +{ + background:#666 none repeat scroll 0 0; + color:#FFF!important +} + +#footer a:link,#footer a:visited +{ + color:#666 +} + +#footer .bgr:after +{ + content:' Theme by Jared Denison (themondays)'; + float:right +} + +h1,h2,h3,h4 +{ + font-family:"PT Sans","Lucida Grande",arial,sans-serif +} + +h1 +{ + font-size:24px; /*工作台界面框框大小*/ + font-weight:400; + margin:0 0 0 .25em; + padding:0 0 10px; + text-align:left +} + +h2,h3,h4,.wiki h1,.wiki h2,.wiki h3 +{ + border-bottom:0 +} + +h2,.wiki h1 +{ + background-color:#e0e0e0; /*第三层背景非导航条*/ + margin:-6px -10px 10px; + padding:10px 20px; + font-size:14px; + color:#fff; + border-top:1px #ddd solid +} + +.wiki h1 +{ + font-family:"PT Sans","Trebuchet MS",Helvetica,sans-serif; + font-weight:700 +} + +.wiki h2 +{ + background-color:transparent +} + +div.issue div.wiki h3 +{ + text-decoration:underline +} + +h3,h4 +{ + font-weight:400 +} + +div.wiki h3,div.wiki h4 +{ + font-weight:700 +} + +#sidebar h3 +{ + border-bottom:1px solid #DCDCDC; /*右边项目应用*/ + padding:3px 4px +} + +div.journal h4 +{ + background-color:#EDF3FE; + border-left:3px solid #9FBFFA; + padding:10px +} + +div.splitcontentleft h2 +{ + background-color:transparent; + padding:0; + margin:20px 0 5px +} + +#sidebar a:hover +{ + background-color:#039; + color:#FFF; + text-decoration:none +} + +#main-menu +{ + + margin-top:5px; + margin-bottom:20px; + background-color:#000; + /*border-bottom:1px solid #ccc; + padding-left:5px; + line-height:30px;*/ + + +} + +#main-menu li a +{ + /*float:left; + margin-top:5px; + margin-right:5px; + border: 1px solid #ccc; + padding: 0px 10px; + height:30px; + top:0px; + position:relative; + z-index: 2; + background: #fff;*/ + font-family:微软雅黑, "PT Sans", Helvetica, Arial; + font: color: #FFF; + transition:all .4s linear; + -moz-transition:all .4s linear; + -o-transition:all .4s linear; + -webkit-transition:all .4s linear; + background-color:#cdd0cf; /*导航条颜色*/ + /*font-weight:400; + padding:4px 8px 4px;8*/ + +} + +#main-menu li a:hover +{ + background:#aaabab; /*鼠标经过时背景颜色*/ + text-decoration:none +} + +#main-menu li a.selected,#main-menu li a.selected:hover +{ + background-color:#969a99; /*当前打开导航条背景颜色*/ + color:#000; + font-weight:700 +} + +#top-menu li a.home:before { + font-family: Fontawesome; + content: "\f015 "; +} +#top-menu li a.my-page:before { + font-family: Fontawesome; + content: "\f0c9 "; + +/*by young*/ +#top-menu li a.home:before { + font-family: Fontawesome; +/* content: "\f015 ";*/ +} +#top-menu li a.my-page:before { + font-family: Fontawesome; +/* content: "\f0c9 ";*/ + +} + +#top-menu li a.projects:before { + font-family: Fontawesome; + + content: "\f0c2 "; + +/* content: "\f0c2 ";*/ + +} + +#top-menu li a.administration:before { + font-family: Fontawesome; + + content: "\f11b "; + +/* content: "\f11b ";*/ + +} + +#top-menu li a.help:before { + font-family: Fontawesome; + + content: "\f0e9 "; + +/* content: "\f0e9 ";*/ + +} + +#top-menu #account a.my-account:before { + font-family: Fontawesome; + + content: "\f0f0 "; +} +#top-menu #account a.logout:before { + font-family: Fontawesome; + content: "\f08b "; +} + + +/* content: "\f0f0 ";*/ +} +#top-menu #account a.logout:before { + font-family: Fontawesome; +/* content: "\f08b ";*/ +} +/*end*/ + +table.list +{ + border:none +} + +table.list th +{ + background-color:#fff +} + +table.list tbody td,table.list tbody tr td,table.list tbody tr td.checkbox +{ + border-bottom:solid 1px #ddd; + font-size:11px; + padding:4px 10px 4px 3px +} + +table.list thead th +{ + border:none; + border-bottom:1px solid #999; + font-size:9px; + font-weight:400; + padding:0 3px 3px; + text-transform:uppercase +} + +table.list thead th a +{ + color:#000 +} + +table.list thead th a:hover +{ + color:#000 +} + +table.list tr.issue a +{ + color:#333 +} + +tr.odd.priority-5,table.list tbody tr.odd.priority-5:hover +{ + color:#900; + font-weight:700 +} + +tr.odd.priority-5 +{ + background:#ffc4c4 +} + +tr.even.priority-5,table.list tbody tr.even.priority-5:hover +{ + color:#900; + font-weight:700 +} + +tr.even.priority-5 +{ + background:#ffd4d4 +} + +tr.priority-5 a,tr.priority-5:hover a +{ + color:#900 +} + +tr.odd.priority-5 td,tr.even.priority-5 td +{ + border-color:#ffb4b4 +} + +tr.odd.priority-4,table.list tbody tr.odd.priority-4:hover +{ + color:#900 +} + +tr.odd.priority-4 +{ + background:#ffc4c4 +} + +tr.even.priority-4,table.list tbody tr.even.priority-4:hover +{ + color:#900 +} + +tr.even.priority-4 +{ + background:#ffd4d4 +} + +tr.priority-4 a +{ + color:#900 +} + +tr.odd.priority-4 td,tr.even.priority-4 td +{ + border-color:#ffb4b4 +} + +tr.odd.priority-3,table.list tbody tr.odd.priority-3:hover +{ + color:#900 +} + +tr.odd.priority-3 +{ + background:#fee +} + +tr.even.priority-3,table.list tbody tr.even.priority-3:hover +{ + color:#900 +} + +tr.even.priority-3 +{ + background:#fff2f2 +} + +tr.priority-3 a +{ + color:#900 +} + +tr.odd.priority-3 td,tr.even.priority-3 td +{ + border-color:#fcc +} + +tr.odd.priority-1,table.list tbody tr.odd.priority-1:hover +{ + color:#559 +} + +tr.odd.priority-1 +{ + background:#eaf7ff +} + +tr.even.priority-1,table.list tbody tr.even.priority-1:hover +{ + color:#dbedf4 +} + +tr.even.priority-1 +{ + background:#f2faff +} + +tr.priority-1 a +{ + color:#039ea0 +} + +tr.odd.priority-1 td,tr.even.priority-1 td +{ + border-color:#add7f3 +} + +p.breadcrumb +{ + background-color:#EEE; + border-bottom:1px solid #fff; + font-size:.9em; + margin:-6px -10px 6px; + padding:6px; + text-indent:15px +} + +input[type="text"],input[type="password"],textarea,select +{ + padding:2px; + border:1px solid #039ea0 +} + +input[type="text"],input[type="password"] +{ + padding:3px +} + +input[type="text"]:focus,input[type="password"]:focus,textarea:focus,select:focus +{ + border:1px solid #886 +} + +option +{ + border-bottom:1px dotted #d7d7d7 +} + +input#issue_subject +{ + font-size:200%; + width:90% +} + +textarea.wiki-edit +{ + font-family:Cambria,Verdana,Serif; + font-size:larger +} + +.box +{ + background-color:#fcfcfc +} + +.contextual +{ + font-size:.9em; + font-family:verdana +} +/*by young*/ +hr +{ + background:#A0A0A0 none repeat scroll 0 0; + + + margin: 0 0 0 0; + +} +p +{ + font-size: small +} +/*end*/ +div.issue +{ + background:#FFFFEC +} + +div.splitcontentleft ol li,div.splitcontentleft ul li,div.wiki ol li,div.wiki ul li +{ + padding:4px 0 +} + +div.wiki ul.toc li +{ + padding:0 +} + +ol li ol li +{ + list-style-type:lower-alpha +} + +ol li ol li ol li +{ + list-style-type:lower-roman +} + +#login-form table +{ + padding:25px 28px; + background:#fff; + text-align:left; + width:410px; + margin:10px auto; + font-family:lucida grande,verdana; + font-size:12px; + -webkit-border-radius:10px; + -moz-border-radius:10px; + border-radius:10px; + -moz-box-shadow:0 0 6px #039ea0; + -webkit-box-shadow:0 0 6px #039ea0; + box-shadow:0 0 6px #039ea0; + border:1px solid #AAA +} + +#login-form input +{ + font-size:14px; + padding:3px; + margin-bottom:10px +} + +#login-form #username,#login-form #password +{ + width:275px!important; + font-size:14px; + padding:3px; + margin-bottom:10px +} + +input[type="submit"] +{ + font-family:Arial,Helvetica,sans-serif; + font-size:13px; + color:#050505; + padding:5px 10px; + background:-moz-linear-gradient(top,#fff 0%,#ebebeb 50%,#dbdbdb 50%,#b5b5b5); + background:-webkit-gradient(linear,left top,left bottom,from(#fff),color-stop(0.50,#ebebeb),color-stop(0.50,#dbdbdb),to(#b5b5b5)); + -moz-border-radius:4px; + -webkit-border-radius:4px; + border-radius:4px; + border:1px solid #949494; + -moz-box-shadow:0 1px 3px rgba(000,000,000,0.5),inset 0 0 2px rgba(255,255,255,1); + -webkit-box-shadow:0 1px 3px rgba(000,000,000,0.3),inset 0 0 2px rgba(255,255,255,1); + box-shadow:0 1px 3px rgba(000,000,000,0.2),inset 0 0 2px rgba(255,255,255,1); + text-shadow:0 -1px 0 rgba(000,000,000,0.2),0 1px 0 rgba(255,255,255,1); + cursor:pointer +} + +html > body #content +{ + min-height:auto!important +} + +pre,code,.line-code +{ + font-family:'Source Code Pro' +} +/*by young*/ +#main,#footer,#top-menu,#header +{ + + width:940px; + margin:25px auto +} +#main +{ + width:940px; + height:auto; + margin:0px auto; +} +#header +{ + width:925px; + border-top:1px solid #bbb; + border-left:1px solid #bbb; + border-right:1px solid #bbb; + /*by young*/ +/* -moz-box-shadow:#bbb 1px 1px 2px;*/ + -webkit-box-shadow:2px 2px 0px -2px #bbb; + margin: 0px auto; +} +/*end*/ +.autoscroll table.filecontent th.line-num { + + padding-right: 7px; + font-family:'Source Code Pro', helvetica, Arial; + +} + + + + +/* + * Added by Nie guanghui. + * + * Designed for project#index. + */ + +.img-tag { + float: left; + margin-top: 30px; + width: 64px; + height: 64px; +} + + + + +div.wiki-description { + /*word-break; break-all; + word-wrap: break-word;*/ + display: block; + /*white-space: nowrap;*/ + float: left; + margin-left: 20px; + margin-top: 10px; + width: 427px; + max-height: 121px; + font-family: helvetica,arial,sans-serif; + color: rgb(0, 0, 0); + font-size: 13px; + line-height: 18px; + overflow: hidden; + /*text-overflow: ellipsis; + -o-text-overflow: ellipsis;*/ +} +.information { + margin-top: 0px; + margin-left: 607px; + float: left; + height: 108px; + width: 246px; + font-family: helvetica,arial,sans-serif; + color: rgb(0, 0, 0); + font-size: 13px; + line-height: 18px; + position: absolute; + } +/* +a.project { + float: left; +}*/ + +.project-block { + float: left; + margin-top: 0px; + width: 908px; + height: 148px; +} + +a.root { + margin :2px; + font-size: 3em; + font-weight: bold; + line-height: 1; +} + +.project-table { + margin-left: auto; + margin-right: auto; + margin-bottom: 10px; + width: 908px; + height: 250px; + padding-top: 10px; + padding-left: 10px; + padding-bottom: 10px; + margin-bottom: 20px; + background-color: #f5f5f5; + border: 1px solid #eee; + border: 1px solid rgba(0, 0, 0, 0.05); + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); +} + +.reviews { + display: block; + float: left; + width: 90; + height: 90; + margin-top: -114px; + margin-left: 870px; + text-align: center; + font-family: helvetica,arial,sans-serif; + color: rgb(0, 0, 0); + line-height: 18px; +} + +.img-tag4 { + float: right; + width: 65px; + min-height: 36px; + margin: -5px 0px 10px 25px; + text-align: center; + font-family: helvetica,arial,sans-serif; + color: rgb(0, 0, 0); + line-height: 18px; +} + +.img-tag2 { + margin-top: 0px; +} + +.img-tag1 { + margin-top: -5px; + color: blue; + font-size: 13px; + font-family: helvetica,arial,sans-serif; + line-height: 18px; +} + +a.img-tag3{ + float: left; + background-image: url("../images/pai.png"); + background-position: 0px 0px; + background-repeat: no-repeat; + position: absolute; +} + +.stats a { + width: 100px; + text-align: right; + display: inline-block; + font-weight: bold; + font-size: 1.2em; +} + +.stats span { + margin-left: 10px; +} + +.add-info { + margin-top: 160px; + height: 20px; + width: 908px; +} +.main-language { + float: left; + height: 18px; + width: 375px; + font-size: 13px; + font-family: helvetica,arial,sans-serif; + line-height: 18px; +} +.licences { + float: left; + height: 18px; + width: 260px; + font-size: 13px; + font-family: helvetica,arial,sans-serif; + line-height: 18px; +} + +a { + color: rgb(51, 102, 153); +} + +.tags { + clear: left; + margin-top: 10px; +} + +a.tag { + background-color: rgb(219, 228, 238); + border-radius: 5px 5px 5px 5px; + color: rgb(58, 88, 125) !important; + padding: 0px 4px; + margin: 3px; + display: inline-block; + font-size: 11px; + text-decoration: none; + cursor: pointer; +} + + + + + +/* + * Added by Nie. + * + * + * Designed for user#index. + */ + + div.well { + color: black; + min-height: 20px; + height: 110px; + padding: 19px; + margin-bottom: 20px; + background-color: #f5f5f5; + border: 1px solid #eee; + border: 1px solid rgba(0, 0, 0, 0.05); + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); +} + +.float_right { + display: block; + float: right; +} + +.member_since { + padding-right: 20px; +} + +img.avatar { + background: rgb(245, 245, 245); + padding: 4px; + border: 1px solid #e5dfc7; + float: left; + display: block; +} + +.avatar_name { + position: relative; + font-size: 13px; + top: 4px; + left: 4px; + display:block; +} + +div.nomargin { + margin-bottom: 0px; +} + + +div.pagination { + margin: 18px 0px; + height: 36px; + text-align: center; + font-size: 13px; + } + +div.pagination ul { + display: inline-block; + border-radius: 3px 3px 3px 3px; + box-shadow: 0px 1px 2px rgba(0, 0, 0, 0.05); + list-style: disc outside none; + padding: 0px; + margin-left: 0px; + margin-top: 0px; +} + +div.pagination li { + display: inline; + line-height: 18px; + padding: 0px; + margin: 0px; +} + +div.pagination li:first-child a { + border-left-width: 1px; + border-radius: 3px 0px 0px 3px; +} + +div.pagination a { + float: left; + padding: 0px 14px; + line-height: 34px; + text-decoration: none; + border-width: 1px 1px 1px 0px; + border-style: solid; + border-color: rgb(221, 221, 221); + -moz-border-top-colors: none; + -moz-border-right-colors: none; + -moz-border-left-colors: none; + -moz-border-bottom-colors: none; + border-image: none; +} +div.pagination span { + float: left; + padding: 0px 14px; + line-height: 34px; + text-decoration: none; + border-width: 1px 1px 1px 0px; + border-style: solid; + border-color: rgb(221, 221, 221); + -moz-border-top-colors: none; + -moz-border-right-colors: none; + -moz-border-left-colors: none; + -moz-border-bottom-colors: none; + border-image: none; +} +} + +div.pagination span.current-page { + color: rgb(153, 153, 153); + cursor: default; +} + +div.pagination a:hover, div.pagination span.current-page { + background-color: rgb(245, 245, 245); +} + +/* + * Designed for activity. + * Added by Nie. + */ +div.issue-note { + width: 580px; + margin-left: 30px; + margin-bottom: 10px; + padding-bottom: 10px; + border-bottom: 1px dashed rgb(204, 204, 204); +} +div.activity-info { + margin-top: 10px; + width: 700px; + font-size: 10pt; + color: rgb(153, 153, 153); +} +div.time { + float: left; + margin-left: 60px; + width: 100px; +} +div.content { + float: left; + width: 300px; +} +div.author { + float: left; + width: 200px; +} +div.issue-note .description { + font-size: 10.5pt; + line-height: 22px; + margin: 5px 0px 0px 80px; + overflow: hidden; +} + + /*issue style Added by nie + */ + +div.autoscroll ul.issue_list { + +} +div.autoscroll ul { + padding: 0px; + margin-top: 0px; + margin-bottom: 0px; +} +div.autoscroll li{ + list-style-type: none; +} + +div.autoscroll li.hascontextmenu{ + position: relative; + display: block; + margin-bottom: -1px; + padding: 8px 10px 10px 10px;/*by young*/ + border: 1px solid rgb(229,229,229); + width: 650px;/*by young*/ +} + +div.autoscroll li.id { + position: relative; + top: 2px; + float: right; + margin-left: 12px; + font-size: 13px; + +} +div.autoscroll li.id a { + color: rgb(153, 153, 153); +} + +div.autoscroll li.subject { + margin:0px 60px 0px 0px; + font-size: 15px; + line-height: 1.3; + word-wrap: break-word; +} +div.autoscroll li.subject a{ + color: rgb(0, 0, 0); +} +div.autoscroll ul.list-group-item-meta{ + font-size: 11px; + line-height: 17px; + overflow: hidden; + color: rgb(153, 153, 153); +} + +div.autoscroll ul.list-group-item-meta li { + display: inline-block; + margin-right: 4px; +} + +div.autoscroll li.tracker, div.autoscroll li.status, div.autoscroll li.priority{ + color: rgb(17, 102, 153); +} + + +/* +*/ + + + img.avatar { + background: rgb(245, 245, 245); + padding: 4px; + border: 1px solid #e5dfc7; + float: left; + display: block; + width: 38px; + height: 38px; +} + + +div.left_wf a { + display: inline-block; + padding: 0px !important; + transition: all 0.2s linear 0s; +} + + +#sidebar a, #sidebar a.selected{ + display: inline-block; +padding: 0px !important; +transition: all 0.2s linear 0s; +} + + +/* +member style +*/ + +div.member_content div.well { + height: auto; + margin-bottom: 10px; +} + + +div.member_content { + float: left; + margin-top: 20px; + width: 600px; + margin-left: 40px; +} \ No newline at end of file diff --git a/public/themes/redpenny-master/stylesheets/font/FontAwesome.otf b/public/themes/redpenny-master/stylesheets/font/FontAwesome.otf new file mode 100644 index 00000000..32dd8b1c Binary files /dev/null and b/public/themes/redpenny-master/stylesheets/font/FontAwesome.otf differ diff --git a/public/themes/redpenny-master/stylesheets/font/fontawesome-webfont.eot b/public/themes/redpenny-master/stylesheets/font/fontawesome-webfont.eot new file mode 100644 index 00000000..c080283b Binary files /dev/null and b/public/themes/redpenny-master/stylesheets/font/fontawesome-webfont.eot differ diff --git a/public/themes/redpenny-master/stylesheets/font/fontawesome-webfont.svg b/public/themes/redpenny-master/stylesheets/font/fontawesome-webfont.svg new file mode 100644 index 00000000..10a1e1bb --- /dev/null +++ b/public/themes/redpenny-master/stylesheets/font/fontawesome-webfont.svg @@ -0,0 +1,339 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/public/themes/redpenny-master/stylesheets/font/fontawesome-webfont.ttf b/public/themes/redpenny-master/stylesheets/font/fontawesome-webfont.ttf new file mode 100644 index 00000000..908f69ec Binary files /dev/null and b/public/themes/redpenny-master/stylesheets/font/fontawesome-webfont.ttf differ diff --git a/public/themes/redpenny-master/stylesheets/font/fontawesome-webfont.woff b/public/themes/redpenny-master/stylesheets/font/fontawesome-webfont.woff new file mode 100644 index 00000000..a33af950 Binary files /dev/null and b/public/themes/redpenny-master/stylesheets/font/fontawesome-webfont.woff differ diff --git a/public/themes/redpenny-master/stylesheets/images/bg.png b/public/themes/redpenny-master/stylesheets/images/bg.png new file mode 100644 index 00000000..dc9509ed Binary files /dev/null and b/public/themes/redpenny-master/stylesheets/images/bg.png differ diff --git a/public/themes/redpenny-master/stylesheets/images/bg/bg.gif b/public/themes/redpenny-master/stylesheets/images/bg/bg.gif new file mode 100644 index 00000000..ee801204 Binary files /dev/null and b/public/themes/redpenny-master/stylesheets/images/bg/bg.gif differ diff --git a/public/themes/redpenny-master/stylesheets/images/bg/bg.jpg b/public/themes/redpenny-master/stylesheets/images/bg/bg.jpg new file mode 100644 index 00000000..fe5bdf09 Binary files /dev/null and b/public/themes/redpenny-master/stylesheets/images/bg/bg.jpg differ diff --git a/public/themes/redpenny-master/stylesheets/images/bg/f.jpg b/public/themes/redpenny-master/stylesheets/images/bg/f.jpg new file mode 100644 index 00000000..eb5528db Binary files /dev/null and b/public/themes/redpenny-master/stylesheets/images/bg/f.jpg differ diff --git a/public/themes/redpenny-master/stylesheets/images/bullet.png b/public/themes/redpenny-master/stylesheets/images/bullet.png new file mode 100644 index 00000000..c9106449 Binary files /dev/null and b/public/themes/redpenny-master/stylesheets/images/bullet.png differ diff --git a/public/themes/redpenny-master/stylesheets/images/log.png b/public/themes/redpenny-master/stylesheets/images/log.png new file mode 100644 index 00000000..7dd5a12d Binary files /dev/null and b/public/themes/redpenny-master/stylesheets/images/log.png differ diff --git a/public/themes/redpenny-master/stylesheets/images/logo.png b/public/themes/redpenny-master/stylesheets/images/logo.png new file mode 100644 index 00000000..7dd5a12d Binary files /dev/null and b/public/themes/redpenny-master/stylesheets/images/logo.png differ diff --git a/public/themes/redpenny-master/stylesheets/images/logo/bg.png b/public/themes/redpenny-master/stylesheets/images/logo/bg.png new file mode 100644 index 00000000..dc9509ed Binary files /dev/null and b/public/themes/redpenny-master/stylesheets/images/logo/bg.png differ diff --git a/script/about b/script/about new file mode 100644 index 00000000..cfec3b40 --- /dev/null +++ b/script/about @@ -0,0 +1,6 @@ +#!/usr/bin/env ruby + +ENV["RAILS_ENV"] ||= "production" +require File.expand_path(File.dirname(__FILE__) + "/../config/environment") +puts +puts Redmine::Info.environment diff --git a/script/rails b/script/rails new file mode 100644 index 00000000..f8da2cff --- /dev/null +++ b/script/rails @@ -0,0 +1,6 @@ +#!/usr/bin/env ruby +# This command will automatically be run when you run "rails" with Rails 3 gems installed from the root of your application. + +APP_PATH = File.expand_path('../../config/application', __FILE__) +require File.expand_path('../../config/boot', __FILE__) +require 'rails/commands'