Compare commits

...

9 Commits
0.8.5 ... 0.7.1

Author SHA1 Message Date
Jean-Philippe Lang
2f4ef0530e tagged version 0.7.1
git-svn-id: http://redmine.rubyforge.org/svn/tags/0.7.1@1414 e93f8b46-1217-0410-a6f0-8f06a7374b81
2008-05-04 13:40:51 +00:00
Jean-Philippe Lang
c0db7007fa Doc and version update for 0.7.1 release.
git-svn-id: http://redmine.rubyforge.org/svn/branches/0.7-stable@1413 e93f8b46-1217-0410-a6f0-8f06a7374b81
2008-05-04 10:26:25 +00:00
Jean-Philippe Lang
d7e3c4df26 Merged r1409 and r1410 from trunk.
git-svn-id: http://redmine.rubyforge.org/svn/branches/0.7-stable@1411 e93f8b46-1217-0410-a6f0-8f06a7374b81
2008-05-04 10:04:19 +00:00
Jean-Philippe Lang
76ec11422d Merged r1400 from trunk.
git-svn-id: http://redmine.rubyforge.org/svn/branches/0.7-stable@1408 e93f8b46-1217-0410-a6f0-8f06a7374b81
2008-05-03 10:34:41 +00:00
Jean-Philippe Lang
8bc721c264 Merged r1399, r1403, r1405 and r1406 from trunk.
git-svn-id: http://redmine.rubyforge.org/svn/branches/0.7-stable@1407 e93f8b46-1217-0410-a6f0-8f06a7374b81
2008-05-02 18:39:32 +00:00
Jean-Philippe Lang
914d1e6645 Merged r1379 to r1385 from trunk.
git-svn-id: http://redmine.rubyforge.org/svn/branches/0.7-stable@1387 e93f8b46-1217-0410-a6f0-8f06a7374b81
2008-04-30 11:41:16 +00:00
Jean-Philippe Lang
5f346bbf2b Version set to 0.7.0.
git-svn-id: http://redmine.rubyforge.org/svn/branches/0.7-stable@1371 e93f8b46-1217-0410-a6f0-8f06a7374b81
2008-04-28 10:37:47 +00:00
Jean-Philippe Lang
10191813ec Merged r1307 to r1369 from trunk.
git-svn-id: http://redmine.rubyforge.org/svn/branches/0.7-stable@1370 e93f8b46-1217-0410-a6f0-8f06a7374b81
2008-04-28 10:36:12 +00:00
Jean-Philippe Lang
be071deae2 Added 0.7 stable branch.
git-svn-id: http://redmine.rubyforge.org/svn/branches/0.7-stable@1305 e93f8b46-1217-0410-a6f0-8f06a7374b81
2008-03-29 11:45:53 +00:00
150 changed files with 2867 additions and 903 deletions

View File

@@ -56,6 +56,8 @@ class AccountController < ApplicationController
flash.now[:error] = l(:notice_account_invalid_creditentials)
end
end
rescue User::OnTheFlyCreationFailure
flash.now[:error] = 'Redmine could not retrieve the required information from the LDAP to create your account. Please, contact your Redmine administrator.'
end
# Log out current user and redirect to welcome page

View File

@@ -150,6 +150,7 @@ class ApplicationController < ActionController::Base
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.atom.rxml", :layout => false, :content_type => 'application/atom+xml'
end

View File

@@ -73,6 +73,8 @@ class IssuesController < ApplicationController
# Send html if the query is not valid
render(:template => 'issues/index.rhtml', :layout => !request.xhr?)
end
rescue ActiveRecord::RecordNotFound
render_404
end
def changes
@@ -87,6 +89,8 @@ class IssuesController < ApplicationController
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 show
@@ -136,7 +140,9 @@ class IssuesController < ApplicationController
requested_status = IssueStatus.find_by_id(params[:issue][:status_id])
# Check that the user is allowed to apply the requested status
@issue.status = (@allowed_statuses.include? requested_status) ? requested_status : default_status
@custom_values = @project.custom_fields_for_issues(@issue.tracker).collect { |x| CustomValue.new(:custom_field => x, :customized => @issue, :value => params["custom_fields"][x.id.to_s]) }
@custom_values = @project.custom_fields_for_issues(@issue.tracker).collect { |x| CustomValue.new(:custom_field => x,
:customized => @issue,
:value => (params[:custom_fields] ? params[:custom_fields][x.id.to_s] : nil)) }
@issue.custom_values = @custom_values
if @issue.save
attach_files(@issue, params[:attachments])
@@ -338,8 +344,8 @@ class IssuesController < ApplicationController
end
def preview
issue = @project.issues.find_by_id(params[:id])
@attachements = issue.attachments if issue
@issue = @project.issues.find_by_id(params[:id]) unless params[:id].blank?
@attachements = @issue.attachments if @issue
@text = params[:notes] || (params[:issue] ? params[:issue][:description] : nil)
render :partial => 'common/preview'
end
@@ -384,7 +390,10 @@ private
# Retrieve query from session or build a new query
def retrieve_query
if !params[:query_id].blank?
@query = Query.find(params[:query_id], :conditions => {:project_id => (@project ? @project.id : nil)})
cond = "project_id IS NULL"
cond << " OR project_id = #{@project.id}" if @project
@query = Query.find(params[:query_id], :conditions => cond)
@query.project = @project
session[:query] = {:id => @query.id, :project_id => @query.project_id}
else
if params[:set_filter] || session[:query].nil? || session[:query][:project_id] != (@project ? @project.id : nil)
@@ -404,6 +413,7 @@ private
else
@query = Query.find_by_id(session[:query][:id]) if session[:query][:id]
@query ||= Query.new(:name => "_", :project => @project, :filters => session[:query][:filters])
@query.project = @project
end
end
end

View File

@@ -66,20 +66,20 @@ class ProjectsController < ApplicationController
:conditions => "parent_id IS NULL AND status = #{Project::STATUS_ACTIVE}",
:order => 'name')
@project = Project.new(params[:project])
@project.enabled_module_names = Redmine::AccessControl.available_project_modules
if request.get?
@custom_values = ProjectCustomField.find(:all, :order => "#{CustomField.table_name}.position").collect { |x| CustomValue.new(:custom_field => x, :customized => @project) }
@project.trackers = Tracker.all
@project.is_public = Setting.default_projects_public?
@project.enabled_module_names = Redmine::AccessControl.available_project_modules
else
@project.custom_fields = CustomField.find(params[:custom_field_ids]) if params[:custom_field_ids]
@custom_values = ProjectCustomField.find(:all, :order => "#{CustomField.table_name}.position").collect { |x| CustomValue.new(:custom_field => x, :customized => @project, :value => (params[:custom_fields] ? params["custom_fields"][x.id.to_s] : nil)) }
@project.custom_values = @custom_values
@project.enabled_module_names = params[:enabled_modules]
if @project.save
@project.enabled_module_names = params[:enabled_modules]
flash[:notice] = l(:notice_successful_create)
redirect_to :controller => 'admin', :action => 'projects'
end
end
end
end
@@ -87,7 +87,7 @@ class ProjectsController < ApplicationController
def show
@custom_values = @project.custom_values.find(:all, :include => :custom_field, :order => "#{CustomField.table_name}.position")
@members_by_role = @project.members.find(:all, :include => [:user, :role], :order => 'position').group_by {|m| m.role}
@subprojects = @project.active_children
@subprojects = @project.children.find(:all, :conditions => Project.visible_by(User.current))
@news = @project.news.find(:all, :limit => 5, :include => [ :author, :project ], :order => "#{News.table_name}.created_on DESC")
@trackers = @project.rolled_up_trackers
@@ -204,7 +204,10 @@ class ProjectsController < ApplicationController
end
def list_files
@versions = @project.versions.sort.reverse
sort_init "#{Attachment.table_name}.filename", "asc"
sort_update
@versions = @project.versions.find(:all, :include => :attachments, :order => sort_clause).sort.reverse
render :layout => !request.xhr?
end
# Show changelog for @project
@@ -338,8 +341,9 @@ class ProjectsController < ApplicationController
:include => [:tracker, :status, :assigned_to, :priority, :project],
:conditions => ["((start_date BETWEEN ? AND ?) OR (due_date BETWEEN ? AND ?)) AND #{Issue.table_name}.tracker_id IN (#{@selected_tracker_ids.join(',')})", @calendar.startdt, @calendar.enddt, @calendar.startdt, @calendar.enddt]
) unless @selected_tracker_ids.empty?
events += Version.find(:all, :include => :project,
:conditions => ["effective_date BETWEEN ? AND ?", @calendar.startdt, @calendar.enddt])
end
events += @project.versions.find(:all, :conditions => ["effective_date BETWEEN ? AND ?", @calendar.startdt, @calendar.enddt])
@calendar.events = events
render :layout => false if request.xhr?
@@ -383,8 +387,9 @@ class ProjectsController < ApplicationController
:include => [:tracker, :status, :assigned_to, :priority, :project],
:conditions => ["(((start_date>=? and start_date<=?) or (due_date>=? and due_date<=?) or (start_date<? and due_date>?)) and start_date is not null and due_date is not null and #{Issue.table_name}.tracker_id in (#{@selected_tracker_ids.join(',')}))", @date_from, @date_to, @date_from, @date_to, @date_from, @date_to]
) unless @selected_tracker_ids.empty?
@events += Version.find(:all, :include => :project,
:conditions => ["effective_date BETWEEN ? AND ?", @date_from, @date_to])
end
@events += @project.versions.find(:all, :conditions => ["effective_date BETWEEN ? AND ?", @date_from, @date_to])
@events.sort! {|x,y| x.start_date <=> y.start_date }
if params[:format]=='pdf'

View File

@@ -18,19 +18,14 @@
class QueriesController < ApplicationController
layout 'base'
menu_item :issues
before_filter :find_project, :authorize
def index
@queries = @project.queries.find(:all,
:order => "name ASC",
:conditions => ["is_public = ? or user_id = ?", true, (User.current.logged? ? User.current.id : 0)])
end
before_filter :find_query, :except => :new
before_filter :find_optional_project, :only => :new
def new
@query = Query.new(params[:query])
@query.project = @project
@query.project = params[:query_is_for_all] ? nil : @project
@query.user = User.current
@query.is_public = false unless current_role.allowed_to?(:manage_public_queries)
@query.is_public = false unless (@query.project && current_role.allowed_to?(:manage_public_queries)) || User.current.admin?
@query.column_names = nil if params[:default_columns]
params[:fields].each do |field|
@@ -52,7 +47,8 @@ class QueriesController < ApplicationController
@query.add_filter(field, params[:operators][field], params[:values][field])
end if params[:fields]
@query.attributes = params[:query]
@query.is_public = false unless current_role.allowed_to?(:manage_public_queries)
@query.project = nil if params[:query_is_for_all]
@query.is_public = false unless (@query.project && current_role.allowed_to?(:manage_public_queries)) || User.current.admin?
@query.column_names = nil if params[:default_columns]
if @query.save
@@ -64,18 +60,21 @@ class QueriesController < ApplicationController
def destroy
@query.destroy if request.post?
redirect_to :controller => 'queries', :project_id => @project
redirect_to :controller => 'issues', :action => 'index', :project_id => @project, :set_filter => 1
end
private
def find_project
if params[:id]
@query = Query.find(params[:id])
@project = @query.project
render_403 unless @query.editable_by?(User.current)
else
@project = Project.find(params[:project_id])
end
def find_query
@query = Query.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]
User.current.allowed_to?(:save_queries, @project, :global => true)
rescue ActiveRecord::RecordNotFound
render_404
end

View File

@@ -19,8 +19,8 @@ require 'SVG/Graph/Bar'
require 'SVG/Graph/BarHorizontal'
require 'digest/sha1'
class ChangesetNotFound < Exception
end
class ChangesetNotFound < Exception; end
class InvalidRevisionParam < Exception; end
class RepositoriesController < ApplicationController
layout 'base'
@@ -51,8 +51,8 @@ class RepositoriesController < ApplicationController
def show
# check if new revisions have been committed in the repository
@repository.fetch_changesets if Setting.autofetch_changesets?
# get entries for the browse frame
@entries = @repository.entries('')
# root entries
@entries = @repository.entries('', @rev)
# latest changesets
@changesets = @repository.changesets.find(:all, :limit => 10, :order => "committed_on DESC")
show_error_not_found unless @entries || @changesets.any?
@@ -65,7 +65,8 @@ class RepositoriesController < ApplicationController
if request.xhr?
@entries ? render(:partial => 'dir_list_content') : render(:nothing => true)
else
show_error_not_found unless @entries
show_error_not_found and return unless @entries
render :action => 'browse'
end
rescue Redmine::Scm::Adapters::CommandFailed => e
show_error_command_failed(e.message)
@@ -95,6 +96,12 @@ class RepositoriesController < ApplicationController
end
def entry
@entry = @repository.scm.entry(@path, @rev)
show_error_not_found and return unless @entry
# If the entry is a dir, show the browser
browse and return if @entry.is_dir?
@content = @repository.scm.cat(@path, @rev)
show_error_not_found and return unless @content
if 'raw' == params[:format] || @content.is_binary_data?
@@ -135,7 +142,6 @@ class RepositoriesController < ApplicationController
end
def diff
@rev_to = params[:rev_to]
@diff_type = params[:type] || User.current.pref[:diff_type] || 'inline'
@diff_type = 'inline' unless %w(inline sbs).include?(@diff_type)
@@ -180,6 +186,8 @@ private
render_404
end
REV_PARAM_RE = %r{^[a-f0-9]*$}
def find_repository
@project = Project.find(params[:id])
@repository = @project.repository
@@ -187,8 +195,12 @@ private
@path = params[:path].join('/') unless params[:path].nil?
@path ||= ''
@rev = params[:rev]
@rev_to = params[:rev_to]
raise InvalidRevisionParam unless @rev.to_s.match(REV_PARAM_RE) && @rev.to_s.match(REV_PARAM_RE)
rescue ActiveRecord::RecordNotFound
render_404
rescue InvalidRevisionParam
show_error_not_found
end
def show_error_not_found
@@ -255,6 +267,9 @@ private
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 => 300,
:width => 500,

View File

@@ -26,6 +26,8 @@ class TimelogController < ApplicationController
include SortHelper
helper :issues
include TimelogHelper
helper :custom_fields
include CustomFieldsHelper
def report
@available_criterias = { 'project' => {:sql => "#{TimeEntry.table_name}.project_id",
@@ -45,37 +47,40 @@ class TimelogController < ApplicationController
:label => :label_tracker},
'activity' => {:sql => "#{TimeEntry.table_name}.activity_id",
:klass => Enumeration,
:label => :label_activity}
:label => :label_activity},
'issue' => {:sql => "#{TimeEntry.table_name}.issue_id",
:klass => Issue,
:label => :label_issue}
}
# Add list and boolean custom fields as available criterias
@project.all_custom_fields.select {|cf| %w(list bool).include? cf.field_format }.each do |cf|
@available_criterias["cf_#{cf.id}"] = {:sql => "(SELECT c.value FROM custom_values c WHERE c.custom_field_id = #{cf.id} AND c.customized_type = 'Issue' AND c.customized_id = issues.id)",
:format => cf.field_format,
:label => cf.name}
end
@criterias = params[:criterias] || []
@criterias = @criterias.select{|criteria| @available_criterias.has_key? criteria}
@criterias.uniq!
@criterias = @criterias[0,3]
@columns = (params[:period] && %w(year month week).include?(params[:period])) ? params[:period] : 'month'
@columns = (params[:columns] && %w(year month week day).include?(params[:columns])) ? params[:columns] : 'month'
if params[:date_from]
begin; @date_from = params[:date_from].to_date; rescue; end
end
if params[:date_to]
begin; @date_to = params[:date_to].to_date; rescue; end
end
@date_from ||= Date.civil(Date.today.year, 1, 1)
@date_to ||= (Date.civil(Date.today.year, Date.today.month, 1) >> 1) - 1
retrieve_date_range
unless @criterias.empty?
sql_select = @criterias.collect{|criteria| @available_criterias[criteria][:sql] + " AS " + criteria}.join(', ')
sql_group_by = @criterias.collect{|criteria| @available_criterias[criteria][:sql]}.join(', ')
sql = "SELECT #{sql_select}, tyear, tmonth, tweek, SUM(hours) AS hours"
sql = "SELECT #{sql_select}, tyear, tmonth, tweek, spent_on, SUM(hours) AS hours"
sql << " FROM #{TimeEntry.table_name}"
sql << " LEFT JOIN #{Issue.table_name} ON #{TimeEntry.table_name}.issue_id = #{Issue.table_name}.id"
sql << " LEFT JOIN #{Project.table_name} ON #{TimeEntry.table_name}.project_id = #{Project.table_name}.id"
sql << " WHERE (%s)" % @project.project_condition(Setting.display_subprojects_issues?)
sql << " AND (%s)" % Project.allowed_to_condition(User.current, :view_time_entries)
sql << " AND spent_on BETWEEN '%s' AND '%s'" % [ActiveRecord::Base.connection.quoted_date(@date_from.to_time), ActiveRecord::Base.connection.quoted_date(@date_to.to_time)]
sql << " GROUP BY #{sql_group_by}, tyear, tmonth, tweek"
sql << " AND spent_on BETWEEN '%s' AND '%s'" % [ActiveRecord::Base.connection.quoted_date(@from.to_time), ActiveRecord::Base.connection.quoted_date(@to.to_time)]
sql << " GROUP BY #{sql_group_by}, tyear, tmonth, tweek, spent_on"
@hours = ActiveRecord::Base.connection.select_all(sql)
@@ -87,36 +92,122 @@ class TimelogController < ApplicationController
row['month'] = "#{row['tyear']}-#{row['tmonth']}"
when 'week'
row['week'] = "#{row['tyear']}-#{row['tweek']}"
when 'day'
row['day'] = "#{row['spent_on']}"
end
end
@total_hours = @hours.inject(0) {|s,k| s = s + k['hours'].to_f}
end
@periods = []
date_from = @date_from
# 100 columns max
while date_from < @date_to && @periods.length < 100
case @columns
when 'year'
@periods << "#{date_from.year}"
date_from = date_from >> 12
when 'month'
@periods << "#{date_from.year}-#{date_from.month}"
date_from = date_from >> 1
when 'week'
@periods << "#{date_from.year}-#{date_from.cweek}"
date_from = date_from + 7
@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.year}-#{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
render :layout => false if request.xhr?
respond_to do |format|
format.html { render :layout => !request.xhr? }
format.csv { send_data(report_to_csv(@criterias, @periods, @hours).read, :type => 'text/csv; header=present', :filename => 'timelog.csv') }
end
end
def details
sort_init 'spent_on', 'desc'
sort_update
cond = ARCondition.new
cond << (@issue.nil? ? @project.project_condition(Setting.display_subprojects_issues?) :
["#{TimeEntry.table_name}.issue_id = ?", @issue.id])
retrieve_date_range
cond << ['spent_on BETWEEN ? AND ?', @from, @to]
TimeEntry.visible_by(User.current) do
respond_to do |format|
format.html {
# Paginate results
@entry_count = TimeEntry.count(:include => :project, :conditions => cond.conditions)
@entry_pages = Paginator.new self, @entry_count, per_page_option, params['page']
@entries = TimeEntry.find(:all,
:include => [:project, :activity, :user, {:issue => :tracker}],
:conditions => cond.conditions,
:order => sort_clause,
:limit => @entry_pages.items_per_page,
:offset => @entry_pages.current.offset)
@total_hours = TimeEntry.sum(:hours, :include => :project, :conditions => cond.conditions).to_f
render :layout => !request.xhr?
}
format.csv {
# Export all entries
@entries = TimeEntry.find(:all,
:include => [:project, :activity, :user, {:issue => [:tracker, :assigned_to, :priority]}],
:conditions => cond.conditions,
:order => sort_clause)
send_data(entries_to_csv(@entries).read, :type => 'text/csv; header=present', :filename => 'timelog.csv')
}
end
end
end
def edit
render_403 and return if @time_entry && !@time_entry.editable_by?(User.current)
@time_entry ||= TimeEntry.new(:project => @project, :issue => @issue, :user => User.current, :spent_on => Date.today)
@time_entry.attributes = params[:time_entry]
if request.post? and @time_entry.save
flash[:notice] = l(:notice_successful_update)
redirect_to(params[:back_url] || {:action => 'details', :project_id => @time_entry.project})
return
end
@activities = Enumeration::get_values('ACTI')
end
def destroy
render_404 and return unless @time_entry
render_403 and return unless @time_entry.editable_by?(User.current)
@time_entry.destroy
flash[:notice] = l(:notice_successful_delete)
redirect_to :back
rescue RedirectBackError
redirect_to :action => 'details', :project_id => @time_entry.project
end
private
def find_project
if params[:id]
@time_entry = TimeEntry.find(params[:id])
@project = @time_entry.project
elsif params[:issue_id]
@issue = Issue.find(params[:issue_id])
@project = @issue.project
elsif params[:project_id]
@project = Project.find(params[:project_id])
else
render_404
return false
end
rescue ActiveRecord::RecordNotFound
render_404
end
# Retrieves the date range based on predefined ranges or specific from/to param dates
def retrieve_date_range
@free_period = false
@from, @to = nil, nil
@@ -157,85 +248,7 @@ class TimelogController < ApplicationController
end
@from, @to = @to, @from if @from && @to && @from > @to
cond = ARCondition.new
cond << (@issue.nil? ? @project.project_condition(Setting.display_subprojects_issues?) :
["#{TimeEntry.table_name}.issue_id = ?", @issue.id])
if @from
if @to
cond << ['spent_on BETWEEN ? AND ?', @from, @to]
else
cond << ['spent_on >= ?', @from]
end
elsif @to
cond << ['spent_on <= ?', @to]
end
TimeEntry.visible_by(User.current) do
respond_to do |format|
format.html {
# Paginate results
@entry_count = TimeEntry.count(:include => :project, :conditions => cond.conditions)
@entry_pages = Paginator.new self, @entry_count, per_page_option, params['page']
@entries = TimeEntry.find(:all,
:include => [:project, :activity, :user, {:issue => :tracker}],
:conditions => cond.conditions,
:order => sort_clause,
:limit => @entry_pages.items_per_page,
:offset => @entry_pages.current.offset)
@total_hours = TimeEntry.sum(:hours, :include => :project, :conditions => cond.conditions).to_f
render :layout => !request.xhr?
}
format.csv {
# Export all entries
@entries = TimeEntry.find(:all,
:include => [:project, :activity, :user, {:issue => [:tracker, :assigned_to, :priority]}],
:conditions => cond.conditions,
:order => sort_clause)
send_data(entries_to_csv(@entries).read, :type => 'text/csv; header=present', :filename => 'timelog.csv')
}
end
end
end
def edit
render_403 and return if @time_entry && !@time_entry.editable_by?(User.current)
@time_entry ||= TimeEntry.new(:project => @project, :issue => @issue, :user => User.current, :spent_on => Date.today)
@time_entry.attributes = params[:time_entry]
if request.post? and @time_entry.save
flash[:notice] = l(:notice_successful_update)
redirect_to :action => 'details', :project_id => @time_entry.project
return
end
@activities = Enumeration::get_values('ACTI')
end
def destroy
render_404 and return unless @time_entry
render_403 and return unless @time_entry.editable_by?(User.current)
@time_entry.destroy
flash[:notice] = l(:notice_successful_delete)
redirect_to :back
rescue RedirectBackError
redirect_to :action => 'details', :project_id => @time_entry.project
end
private
def find_project
if params[:id]
@time_entry = TimeEntry.find(params[:id])
@project = @time_entry.project
elsif params[:issue_id]
@issue = Issue.find(params[:issue_id])
@project = @issue.project
elsif params[:project_id]
@project = Project.find(params[:project_id])
else
render_404
return false
end
rescue ActiveRecord::RecordNotFound
render_404
@from ||= (TimeEntry.minimum(:spent_on, :include => :project, :conditions => @project.project_condition(Setting.display_subprojects_issues?)) || Date.today) - 1
@to ||= (TimeEntry.maximum(:spent_on, :include => :project, :conditions => @project.project_condition(Setting.display_subprojects_issues?)) || Date.today)
end
end

View File

@@ -83,7 +83,8 @@ class UsersController < ApplicationController
end
if @user.update_attributes(params[:user])
flash[:notice] = l(:notice_successful_update)
redirect_to :action => 'list'
# Give a string to redirect_to otherwise it would use status param as the response code
redirect_to(url_for(:action => 'list', :status => params[:status], :page => params[:page]))
end
end
@auth_sources = AuthSource.find(:all)

View File

@@ -207,8 +207,10 @@ module ApplicationHelper
rf = Regexp.new(filename, Regexp::IGNORECASE)
# search for the picture in attachments
if found = attachments.detect { |att| att.filename =~ rf }
image_url = url_for :only_path => only_path, :controller => 'attachments', :action => 'download', :id => found.id
"!#{style}#{image_url}!"
image_url = url_for :only_path => only_path, :controller => 'attachments', :action => 'download', :id => found
desc = found.description.to_s.gsub(/^([^\(\)]*).*$/, "\\1")
alt = desc.blank? ? nil : "(#{desc})"
"!#{style}#{image_url}#{alt}!"
else
"!#{style}#{filename}!"
end
@@ -425,6 +427,10 @@ module ApplicationHelper
form_for(name, object, options.merge({ :builder => TabularFormBuilder, :lang => current_language}), &proc)
end
def back_url_hidden_field_tag
hidden_field_tag 'back_url', (params[:back_url] || request.env['HTTP_REFERER'])
end
def check_all_links(form_name)
link_to_function(l(:button_check_all), "checkAll('#{form_name}', true)") +
" | " +
@@ -463,9 +469,22 @@ module ApplicationHelper
end
def calendar_for(field_id)
include_calendar_headers_tags
image_tag("calendar.png", {:id => "#{field_id}_trigger",:class => "calendar-trigger"}) +
javascript_tag("Calendar.setup({inputField : '#{field_id}', ifFormat : '%Y-%m-%d', button : '#{field_id}_trigger' });")
end
def include_calendar_headers_tags
unless @calendar_headers_tags_included
@calendar_headers_tags_included = true
content_for :header_tags do
javascript_include_tag('calendar/calendar') +
javascript_include_tag("calendar/lang/calendar-#{current_language}.js") +
javascript_include_tag('calendar/calendar-setup') +
stylesheet_link_tag('calendar')
end
end
end
def wikitoolbar_for(field_id)
return '' unless Setting.text_formatting == 'textile'

View File

@@ -32,6 +32,19 @@ module IssuesHelper
"<strong>#{@cached_label_assigned_to}</strong>: #{issue.assigned_to}<br />" +
"<strong>#{@cached_label_priority}</strong>: #{issue.priority.name}"
end
def sidebar_queries
unless @sidebar_queries
# User can see public queries and his own queries
visible = ARCondition.new(["is_public = ? OR user_id = ?", true, (User.current.logged? ? User.current.id : 0)])
# Project specific queries and global queries
visible << (@project.nil? ? ["project_id IS NULL"] : ["project_id IS NULL OR project_id = ?", @project.id])
@sidebar_queries = Query.find(:all,
:order => "name ASC",
:conditions => visible.conditions)
end
@sidebar_queries
end
def show_detail(detail, no_html=false)
case detail.property

View File

@@ -58,8 +58,11 @@ module RepositoriesHelper
end
def with_leading_slash(path)
path ||= ''
path.starts_with?('/') ? path : "/#{path}"
path.to_s.starts_with?('/') ? path : "/#{path}"
end
def without_leading_slash(path)
path.gsub(%r{^/+}, '')
end
def subversion_field_tags(form, repository)

View File

@@ -83,7 +83,7 @@ module SortHelper
# Use this to sort the controller's table items collection.
#
def sort_clause()
session[@sort_name][:key] + ' ' + session[@sort_name][:order]
session[@sort_name][:key] + ' ' + (session[@sort_name][:order] || 'ASC')
end
# Returns a link which sorts by the named column.

View File

@@ -76,4 +76,60 @@ module TimelogHelper
export.rewind
export
end
def format_criteria_value(criteria, value)
value.blank? ? l(:label_none) : ((k = @available_criterias[criteria][:klass]) ? k.find_by_id(value.to_i) : format_value(value, @available_criterias[criteria][:format]))
end
def report_to_csv(criterias, periods, hours)
export = StringIO.new
CSV::Writer.generate(export, l(:general_csv_separator)) do |csv|
# Column headers
headers = criterias.collect {|criteria| l(@available_criterias[criteria][:label]) }
headers += periods
headers << l(:label_total)
csv << headers.collect {|c| to_utf8(c) }
# Content
report_criteria_to_csv(csv, criterias, periods, hours)
# Total row
row = [ l(:label_total) ] + [''] * (criterias.size - 1)
total = 0
periods.each do |period|
sum = sum_hours(select_hours(hours, @columns, period.to_s))
total += sum
row << (sum > 0 ? "%.2f" % sum : '')
end
row << "%.2f" %total
csv << row
end
export.rewind
export
end
def report_criteria_to_csv(csv, criterias, periods, hours, level=0)
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?
row = [''] * level
row << to_utf8(format_criteria_value(criterias[level], value))
row += [''] * (criterias.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 : '')
end
row << "%.2f" %total
csv << row
if criterias.length > level + 1
report_criteria_to_csv(csv, criterias, periods, hours_for_value, level + 1)
end
end
end
def to_utf8(s)
@ic ||= Iconv.new(l(:general_csv_encoding), 'UTF-8')
begin; @ic.iconv(s.to_s); rescue; s.to_s; end
end
end

View File

@@ -22,4 +22,16 @@ module UsersHelper
[l(:status_registered), 2],
[l(:status_locked), 3]], selected)
end
def change_status_link(user)
url = {:action => 'edit', :id => user, :page => params[:page], :status => params[:status]}
if user.locked?
link_to l(:button_unlock), url.merge(:user => {:status => User::STATUS_ACTIVE}), :method => :post, :class => 'icon icon-unlock'
elsif user.registered?
link_to l(:button_activate), url.merge(:user => {:status => User::STATUS_ACTIVE}), :method => :post, :class => 'icon icon-unlock'
else
link_to l(:button_lock), url.merge(:user => {:status => User::STATUS_LOCKED}), :method => :post, :class => 'icon icon-lock'
end
end
end

View File

@@ -35,48 +35,48 @@ class Attachment < ActiveRecord::Base
errors.add_to_base :too_long if self.filesize > Setting.attachment_max_size.to_i.kilobytes
end
def file=(incomming_file)
unless incomming_file.nil?
@temp_file = incomming_file
if @temp_file.size > 0
self.filename = sanitize_filename(@temp_file.original_filename)
self.disk_filename = DateTime.now.strftime("%y%m%d%H%M%S") + "_" + self.filename
self.content_type = @temp_file.content_type.to_s.chomp
self.filesize = @temp_file.size
end
end
end
def file=(incoming_file)
unless incoming_file.nil?
@temp_file = incoming_file
if @temp_file.size > 0
self.filename = sanitize_filename(@temp_file.original_filename)
self.disk_filename = DateTime.now.strftime("%y%m%d%H%M%S") + "_" + self.filename
self.content_type = @temp_file.content_type.to_s.chomp
self.filesize = @temp_file.size
end
end
end
def file
nil
end
# Copy temp file to its final location
def before_save
if @temp_file && (@temp_file.size > 0)
logger.debug("saving '#{self.diskfile}'")
File.open(diskfile, "wb") do |f|
f.write(@temp_file.read)
end
self.digest = Digest::MD5.hexdigest(File.read(diskfile))
end
# 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 file on the disk
def after_destroy
if self.filename?
File.delete(diskfile) if File.exist?(diskfile)
end
end
# Returns file's location on disk
def diskfile
"#{@@storage_path}/#{self.disk_filename}"
end
def file
nil
end
# Copy temp file to its final location
def before_save
if @temp_file && (@temp_file.size > 0)
logger.debug("saving '#{self.diskfile}'")
File.open(diskfile, "wb") do |f|
f.write(@temp_file.read)
end
self.digest = Digest::MD5.hexdigest(File.read(diskfile))
end
# 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 file on the disk
def after_destroy
if self.filename?
File.delete(diskfile) if File.exist?(diskfile)
end
end
# Returns file's location on disk
def diskfile
"#{@@storage_path}/#{self.disk_filename}"
end
def increment_download
increment!(:downloads)
@@ -87,18 +87,17 @@ class Attachment < ActiveRecord::Base
end
def image?
self.filename =~ /\.(jpeg|jpg|gif|png)$/i
self.filename =~ /\.(jpe?g|gif|png)$/i
end
private
def sanitize_filename(value)
# get only the filename, not the whole path
just_filename = value.gsub(/^.*(\\|\/)/, '')
# NOTE: File.basename doesn't work right with Windows paths on Unix
# INCORRECT: just_filename = File.basename(value.gsub('\\\\', '/'))
# get only the filename, not the whole path
just_filename = value.gsub(/^.*(\\|\/)/, '')
# NOTE: File.basename doesn't work right with Windows paths on Unix
# INCORRECT: just_filename = File.basename(value.gsub('\\\\', '/'))
# Finally, replace all non alphanumeric, underscore or periods with underscore
@filename = just_filename.gsub(/[^\w\.\-]/,'_')
# Finally, replace all non alphanumeric, hyphens or periods with underscore
@filename = just_filename.gsub(/[^\w\.\-]/,'_')
end
end

View File

@@ -35,6 +35,10 @@ class Changeset < ActiveRecord::Base
validates_uniqueness_of :revision, :scope => :repository_id
validates_uniqueness_of :scmid, :scope => :repository_id, :allow_nil => true
def revision=(r)
write_attribute :revision, (r.nil? ? nil : r.to_s)
end
def comments=(comment)
write_attribute(:comments, comment.strip)
end

View File

@@ -93,7 +93,11 @@ class Issue < ActiveRecord::Base
self.priority = nil
write_attribute(:priority_id, pid)
end
def estimated_hours=(h)
write_attribute :estimated_hours, (h.is_a?(String) ? h.to_hours : h)
end
def validate
if self.due_date.nil? && @attributes['due_date'] && !@attributes['due_date'].empty?
errors.add :due_date, :activerecord_error_not_a_date
@@ -153,6 +157,8 @@ class Issue < ActiveRecord::Base
# Close duplicates if the issue was closed
if @issue_before_change && !@issue_before_change.closed? && self.closed?
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
@@ -237,4 +243,8 @@ class Issue < ActiveRecord::Base
yield
end
end
def to_s
"#{tracker} ##{id}: #{subject}"
end
end

View File

@@ -33,6 +33,7 @@ class Journal < ActiveRecord::Base
acts_as_event :title => Proc.new {|o| "#{o.issue.tracker.name} ##{o.issue.id}: #{o.issue.subject}" + ((s = o.new_status) ? " (#{s})" : '') },
:description => :notes,
:author => :user,
:type => Proc.new {|o| (s = o.new_status) && s.is_closed? ? 'issue-closed' : 'issue-edit' },
:url => Proc.new {|o| {:controller => 'issues', :action => 'show', :id => o.issue.id, :anchor => "change-#{o.id}"}}
def save

View File

@@ -28,6 +28,7 @@ class Message < ActiveRecord::Base
:date_column => 'created_on'
acts_as_event :title => Proc.new {|o| "#{o.board.name}: #{o.subject}"},
:description => :content,
:type => Proc.new {|o| o.parent_id.nil? ? 'message' : 'reply'},
:url => Proc.new {|o| {:controller => 'messages', :action => 'show', :board_id => o.board_id, :id => o.id}}
attr_protected :locked, :sticky

View File

@@ -21,6 +21,8 @@ class MessageObserver < ActiveRecord::Observer
recipients = ([message.root] + message.root.children).collect {|m| m.author.mail if m.author && m.author.active?}
# send notification to the board watchers
recipients += message.board.watcher_recipients
# send notification to project members who want to be notified
recipients += message.board.project.recipients
recipients = recipients.compact.uniq
Mailer.deliver_message_posted(message, recipients) if !recipients.empty? && Setting.notified_events.include?('message_posted')
end

View File

@@ -33,7 +33,7 @@ class Project < ActiveRecord::Base
has_many :documents, :dependent => :destroy
has_many :news, :dependent => :delete_all, :include => :author
has_many :issue_categories, :dependent => :delete_all, :order => "#{IssueCategory.table_name}.name"
has_many :boards, :order => "position ASC"
has_many :boards, :dependent => :destroy, :order => "position ASC"
has_one :repository, :dependent => :destroy
has_many :changesets, :through => :repository
has_one :wiki, :dependent => :destroy
@@ -75,12 +75,14 @@ class Project < ActiveRecord::Base
conditions = nil
if include_subprojects && !active_children.empty?
ids = [id] + active_children.collect {|c| c.id}
conditions = ["#{Issue.table_name}.project_id IN (#{ids.join(',')})"]
conditions = ["#{Project.table_name}.id IN (#{ids.join(',')})"]
end
conditions ||= ["#{Issue.table_name}.project_id = ?", id]
conditions ||= ["#{Project.table_name}.id = ?", id]
# Quick and dirty fix for Rails 2 compatibility
Issue.send(:with_scope, :find => { :conditions => conditions }) do
yield
Version.send(:with_scope, :find => { :conditions => conditions }) do
yield
end
end
end

View File

@@ -116,11 +116,16 @@ class Query < ActiveRecord::Base
set_language_if_valid(User.current.language)
end
def after_initialize
# Store the fact that project is nil (used in #editable_by?)
@is_for_all = project.nil?
end
def validate
filters.each_key do |field|
errors.add label_for(field), :activerecord_error_blank unless
# filter requires one or more values
(values_for(field) and !values_for(field).first.empty?) or
(values_for(field) and !values_for(field).first.blank?) or
# filter doesn't require any value
["o", "c", "!*", "*", "t", "w"].include? operator_for(field)
end if filters
@@ -128,8 +133,10 @@ class Query < ActiveRecord::Base
def editable_by?(user)
return false unless user
return true if !is_public && self.user_id == user.id
is_public && user.allowed_to?(:manage_public_queries, project)
# 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 available_filters
@@ -139,7 +146,7 @@ class Query < ActiveRecord::Base
@available_filters = { "status_id" => { :type => :list_status, :order => 1, :values => IssueStatus.find(:all, :order => 'position').collect{|s| [s.name, s.id.to_s] } },
"tracker_id" => { :type => :list, :order => 2, :values => trackers.collect{|s| [s.name, s.id.to_s] } },
"priority_id" => { :type => :list, :order => 3, :values => Enumeration.find(:all, :conditions => ['opt=?','IPRI']).collect{|s| [s.name, s.id.to_s] } },
"priority_id" => { :type => :list, :order => 3, :values => Enumeration.find(:all, :conditions => ['opt=?','IPRI'], :order => 'position').collect{|s| [s.name, s.id.to_s] } },
"subject" => { :type => :text, :order => 8 },
"created_on" => { :type => :date_past, :order => 9 },
"updated_on" => { :type => :date_past, :order => 10 },
@@ -289,12 +296,14 @@ class Query < ActiveRecord::Base
v = values_for(field).clone
next unless v and !v.empty?
sql = ''
sql = ''
is_custom_filter = false
if field =~ /^cf_(\d+)$/
# custom field
db_table = CustomValue.table_name
db_field = 'value'
sql << "#{Issue.table_name}.id IN (SELECT #{db_table}.customized_id FROM #{db_table} where #{db_table}.customized_type='Issue' AND #{db_table}.customized_id=#{Issue.table_name}.id AND #{db_table}.custom_field_id=#{$1} AND "
is_custom_filter = true
sql << "#{Issue.table_name}.id IN (SELECT #{Issue.table_name}.id FROM #{Issue.table_name} LEFT OUTER JOIN #{db_table} ON #{db_table}.customized_type='Issue' AND #{db_table}.customized_id=#{Issue.table_name}.id AND #{db_table}.custom_field_id=#{$1} WHERE "
else
# regular field
db_table = Issue.table_name
@@ -314,8 +323,10 @@ class Query < ActiveRecord::Base
sql = sql + "(#{db_table}.#{db_field} IS NULL OR #{db_table}.#{db_field} NOT IN (" + v.collect{|val| "'#{connection.quote_string(val)}'"}.join(",") + "))"
when "!*"
sql = sql + "#{db_table}.#{db_field} IS NULL"
sql << " OR #{db_table}.#{db_field} = ''" if is_custom_filter
when "*"
sql = sql + "#{db_table}.#{db_field} IS NOT NULL"
sql << " AND #{db_table}.#{db_field} <> ''" if is_custom_filter
when ">="
sql = sql + "#{db_table}.#{db_field} >= #{v.first.to_i}"
when "<="

View File

@@ -35,7 +35,8 @@ class Repository::Cvs < Repository
end
def entries(path=nil, identifier=nil)
entries=scm.entries(path, identifier)
rev = identifier.nil? ? nil : changesets.find_by_revision(identifier)
entries = scm.entries(path, rev.nil? ? nil : rev.committed_on)
if entries
entries.each() do |entry|
unless entry.lastrev.nil? || entry.lastrev.identifier
@@ -137,12 +138,18 @@ class Repository::Cvs < Repository
end
# Renumber new changesets in chronological order
c = changesets.find(:first, :order => 'committed_on DESC, id DESC', :conditions => "revision NOT LIKE '_%'")
next_rev = c.nil? ? 1 : (c.revision.to_i + 1)
changesets.find(:all, :order => 'committed_on ASC, id ASC', :conditions => "revision LIKE '_%'").each do |changeset|
changeset.update_attribute :revision, next_rev
next_rev += 1
changeset.update_attribute :revision, next_revision_number
end
end # transaction
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
@current_revision_number ||= (connection.select_values("SELECT revision FROM #{Changeset.table_name} WHERE repository_id = #{id} AND revision NOT LIKE '_%'").collect(&:to_i).max || 0)
@current_revision_number += 1
end
end

View File

@@ -29,7 +29,8 @@ class Repository::Darcs < Repository
end
def entries(path=nil, identifier=nil)
entries=scm.entries(path, identifier)
patch = identifier.nil? ? nil : changesets.find_by_revision(identifier)
entries = scm.entries(path, patch.nil? ? nil : patch.scmid)
if entries
entries.each do |entry|
# Search the DB for the entry's last change

View File

@@ -34,6 +34,11 @@ class Repository::Mercurial < Repository
if entries
entries.each do |entry|
next unless entry.is_file?
# Set the filesize unless browsing a specific revision
if identifier.nil?
full_path = File.join(root_url, entry.path)
entry.size = File.stat(full_path).size if File.file?(full_path)
end
# Search the DB for the entry's last change
change = changes.find(:first, :conditions => ["path = ?", scm.with_leading_slash(entry.path)], :order => "#{Changeset.table_name}.committed_on DESC")
if change
@@ -53,7 +58,9 @@ class Repository::Mercurial < Repository
# latest revision found in database
db_revision = latest_changeset ? latest_changeset.revision.to_i : -1
# latest revision in the repository
scm_revision = scm_info.lastrev.identifier.to_i
latest_revision = scm_info.lastrev
return if latest_revision.nil?
scm_revision = latest_revision.identifier.to_i
if db_revision < scm_revision
logger.debug "Fetching changesets for repository #{url}" if logger && logger.debug?
identifier_from = db_revision + 1

View File

@@ -1,5 +1,5 @@
# redMine - project management software
# Copyright (C) 2006-2007 Jean-Philippe Lang
# Copyright (C) 2006-2008 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
@@ -39,6 +39,10 @@ class TimeEntry < ActiveRecord::Base
errors.add :issue_id, :activerecord_error_invalid if (issue_id && !issue) || (issue && project!=issue.project)
end
def hours=(h)
write_attribute :hours, (h.is_a?(String) ? h.to_hours : h)
end
# tyear, tmonth, tweek assigned where setting spent_on attributes
# these attributes make time aggregations easier
def spent_on=(date)

View File

@@ -18,6 +18,9 @@
require "digest/sha1"
class User < ActiveRecord::Base
class OnTheFlyCreationFailure < Exception; end
# Account statuses
STATUS_ANONYMOUS = 0
STATUS_ACTIVE = 1
@@ -105,15 +108,17 @@ class User < ActiveRecord::Base
onthefly.language = Setting.default_language
if onthefly.save
user = find(:first, :conditions => ["login=?", login])
logger.info("User '#{user.login}' created on the fly.") if logger
logger.info("User '#{user.login}' created from the LDAP") if logger
else
logger.error("User '#{onthefly.login}' found in LDAP but could not be created (#{onthefly.errors.full_messages.join(', ')})") if logger
raise OnTheFlyCreationFailure.new
end
end
end
user.update_attribute(:last_login_on, Time.now) if user
user
rescue => text
raise text
rescue => text
raise text
end
# Return user's full name for display
@@ -222,17 +227,26 @@ class User < ActiveRecord::Base
# action can be:
# * a parameter-like Hash (eg. :controller => 'projects', :action => 'edit')
# * a permission Symbol (eg. :edit_project)
def allowed_to?(action, project)
# No action allowed on archived projects
return false unless project.active?
# No action allowed on disabled modules
return false unless project.allows_to?(action)
# Admin users are authorized for anything else
return true if admin?
role = role_for_project(project)
return false unless role
role.allowed_to?(action) && (project.is_public? || role.member?)
def allowed_to?(action, project, options={})
if project
# No action allowed on archived projects
return false unless project.active?
# No action allowed on disabled modules
return false unless project.allows_to?(action)
# Admin users are authorized for anything else
return true if admin?
role = role_for_project(project)
return false unless role
role.allowed_to?(action) && (project.is_public? || role.member?)
elsif options[:global]
# authorize if user has at least one role that has this permission
roles = memberships.collect {|m| m.role}.uniq
roles.detect {|r| r.allowed_to?(action)}
else
false
end
end
def self.current=(user)

View File

@@ -32,6 +32,7 @@ class WikiContent < ActiveRecord::Base
acts_as_event :title => Proc.new {|o| "#{l(:label_wiki_edit)}: #{o.page.title} (##{o.version})"},
:description => :comments,
:datetime => :updated_on,
:type => 'wiki-page',
:url => Proc.new {|o| {:controller => 'wiki', :id => o.page.wiki.project_id, :page => o.page.title, :version => o.version}}
def text=(plain)

View File

@@ -35,10 +35,3 @@
<%= submit_tag l(:button_submit) %>
<% end %>
<% content_for :header_tags do %>
<%= javascript_include_tag 'calendar/calendar' %>
<%= javascript_include_tag "calendar/lang/calendar-#{current_language}.js" %>
<%= javascript_include_tag 'calendar/calendar-setup' %>
<%= stylesheet_link_tag 'calendar' %>
<% end %>

View File

@@ -19,12 +19,15 @@ while day <= calendar.enddt %>
elsif day == i.due_date
image_tag('arrow_to.png')
end %>
<%= h("#{i.project.name} -") unless @project && @project == i.project %>
<%= h("#{i.project} -") unless @project && @project == i.project %>
<%= link_to_issue i %>: <%= h(truncate(i.subject, 30)) %>
<span class="tip"><%= render_issue_tooltip i %></span>
</div>
<% else %>
<%= link_to_version i, :class => "icon icon-package" %>
<span class="icon icon-package">
<%= h("#{i.project} -") unless @project && @project == i.project %>
<%= link_to_version i%>
</span>
<% end %>
<% end %>
</td>

View File

@@ -49,10 +49,3 @@
<% end %>
<%= wikitoolbar_for 'issue_description' %>
<% content_for :header_tags do %>
<%= javascript_include_tag 'calendar/calendar' %>
<%= javascript_include_tag "calendar/lang/calendar-#{current_language}.js" %>
<%= javascript_include_tag 'calendar/calendar-setup' %>
<%= stylesheet_link_tag 'calendar' %>
<% end %>

View File

@@ -1,5 +1,5 @@
<% for journal in journals %>
<div id="change-<%= journal.id %>">
<div id="change-<%= journal.id %>" class="journal">
<h4><div style="float:right;"><%= link_to "##{journal.indice}", :anchor => "note-#{journal.indice}" %></div>
<%= content_tag('a', '', :name => "note-#{journal.indice}")%>
<%= format_time(journal.created_on) %> - <%= journal.user.name %></h4>

View File

@@ -1,13 +1,14 @@
<h3><%= l(:label_issue_plural) %></h3>
<%= link_to l(:label_issue_view_all), { :controller => 'issues', :action => 'index', :project_id => @project, :set_filter => 1 } %><br />
<% if @project %>
<%= link_to l(:field_summary), :controller => 'reports', :action => 'issue_report', :id => @project %><br />
<%= link_to l(:label_change_log), :controller => 'projects', :action => 'changelog', :id => @project %>
<% end %>
<% unless sidebar_queries.empty? -%>
<h3><%= l(:label_query_plural) %></h3>
<% queries = @project.queries.find(:all,
:order => "name ASC",
:conditions => ["is_public = ? or user_id = ?", true, (User.current.logged? ? User.current.id : 0)])
queries.each do |query| %>
<% sidebar_queries.each do |query| -%>
<%= link_to query.name, :controller => 'issues', :action => 'index', :project_id => @project, :query_id => query %><br />
<% end %>
<% end -%>
<% end -%>

View File

@@ -47,10 +47,3 @@
<p><%= submit_tag l(:button_submit) %>
<% end %>
<% content_for :header_tags do %>
<%= javascript_include_tag 'calendar/calendar' %>
<%= javascript_include_tag "calendar/lang/calendar-#{current_language}.js" %>
<%= javascript_include_tag 'calendar/calendar-setup' %>
<%= stylesheet_link_tag 'calendar' %>
<% end %>

View File

@@ -18,7 +18,7 @@
:update => "content",
}, :class => 'icon icon-reload' %>
<% if current_role && current_role.allowed_to?(:save_queries) %>
<% if User.current.allowed_to?(:save_queries, @project, :global => true) %>
<%= link_to l(:button_save), {}, :onclick => "$('query_form').submit(); return false;", :class => 'icon icon-save' %>
<% end %>
</p>
@@ -54,7 +54,7 @@
<% content_for :sidebar do %>
<%= render :partial => 'issues/sidebar' %>
<% end if @project%>
<% 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)) %>

View File

@@ -8,7 +8,7 @@
</div>
<%= submit_tag l(:button_create) %>
<%= link_to_remote l(:label_preview),
{ :url => { :controller => 'issues', :action => 'preview', :project_id => @project, :id => @issue },
{ :url => { :controller => 'issues', :action => 'preview', :project_id => @project },
:method => 'post',
:update => 'preview',
:with => "Form.serialize('issue-form')",

View File

@@ -13,7 +13,7 @@
<h3><%=h @issue.subject %></h3>
<p class="author">
<%= authoring @issue.created_on, @issue.author %>.
<%= l(:label_updated_time, distance_of_time_in_words(Time.now, @issue.updated_on)) if @issue.created_on != @issue.updated_on %>.
<%= l(:label_updated_time, distance_of_time_in_words(Time.now, @issue.updated_on)) + '.' if @issue.created_on != @issue.updated_on %>
</p>
<table width="100%">

View File

@@ -26,7 +26,7 @@
</div>
<div class="message reply">
<h4><%=h message.subject %> - <%= authoring message.created_on, message.author %></h4>
<div class="wiki"><%= textilizable message.content %></div>
<div class="wiki"><%= textilizable message, :content, :attachments => message.attachments %></div>
<%= link_to_attachments message.attachments, :no_author => true %>
</div>
<% end %>

View File

@@ -25,7 +25,7 @@
<div id="preview" class="wiki"></div>
</div>
<p><em><% unless @news.summary.empty? %><%=h @news.summary %><br /><% end %>
<p><em><% unless @news.summary.blank? %><%=h @news.summary %><br /><% end %>
<span class="author"><%= authoring @news.created_on, @news.author %></span></em></p>
<div class="wiki">
<%= textilizable(@news.description) %>

View File

@@ -46,11 +46,3 @@
</fieldset>
<% end %>
<!--[eoform:project]-->
<% content_for :header_tags do %>
<%= javascript_include_tag 'calendar/calendar' %>
<%= javascript_include_tag "calendar/lang/calendar-#{current_language}.js" %>
<%= javascript_include_tag 'calendar/calendar-setup' %>
<%= stylesheet_link_tag 'calendar' %>
<% end %>

View File

@@ -6,7 +6,7 @@
<h3><%= format_activity_day(day) %></h3>
<dl>
<% @events_by_day[day].sort {|x,y| y.event_datetime <=> x.event_datetime }.each do |e| -%>
<dt class="<%= e.class.name.downcase %>"><span class="time"><%= format_time(e.event_datetime, false) %></span>
<dt class="<%= e.event_type %>"><span class="time"><%= format_time(e.event_datetime, false) %></span>
<%= content_tag('span', h(e.project), :class => 'project') if @project.nil? || @project != e.project %> <%= link_to h(truncate(e.event_title, 100)), e.event_url %></dt>
<dd><% unless e.event_description.blank? -%>
<span class="description"><%= format_activity_description(e.event_description) %></span><br />

View File

@@ -1,14 +1,16 @@
<h2><%=l(:label_confirmation)%></h2>
<div class="box">
<center>
<p><strong><%=h @project_to_destroy.name %></strong><br />
<%=l(:text_project_destroy_confirmation)%></p>
<div class="warning">
<p><strong><%=h @project_to_destroy %></strong><br />
<%=l(:text_project_destroy_confirmation)%>
<% if @project_to_destroy.children.any? %>
<br /><%= l(:text_subprojects_destroy_warning, content_tag('strong', h(@project_to_destroy.children.sort.collect{|p| p.to_s}.join(', ')))) %>
<% end %>
</p>
<p>
<% form_tag({:controller => 'projects', :action => 'destroy', :id => @project_to_destroy}) do %>
<%= hidden_field_tag "confirm", 1 %>
<label><%= check_box_tag 'confirm', 1 %> <%= l(:general_text_Yes) %></label>
<%= submit_tag l(:button_delete) %>
<% end %>
</p>
</center>
</div>
</div>

View File

@@ -70,10 +70,13 @@ top = headers_height + 8
@events.each do |i| %>
<div style="position: absolute;line-height:1.2em;height:16px;top:<%= top %>px;left:4px;overflow:hidden;"><small>
<% if i.is_a? Issue %>
<%= h("#{i.project.name} -") unless @project && @project == i.project %>
<%= h("#{i.project} -") unless @project && @project == i.project %>
<%= link_to_issue i %>: <%=h i.subject %>
<% else %>
<%= link_to_version i, :class => "icon icon-package" %>
<span class="icon icon-package">
<%= h("#{i.project} -") unless @project && @project == i.project %>
<%= link_to_version i %>
</span>
<% end %>
</small></div>
<% top = top + 20
@@ -197,7 +200,8 @@ top = headers_height + 10
%>
<div style="top:<%= top %>px;left:<%= i_left %>px;width:15px;" class="task milestone">&nbsp;</div>
<div style="top:<%= top %>px;left:<%= i_left + 12 %>px;background:#fff;" class="task">
<strong><%= i.name %></strong>
<%= h("#{i.project} -") unless @project && @project == i.project %>
<strong><%=h i %></strong>
</div>
<% end %>
<% top = top + 20

View File

@@ -9,10 +9,10 @@
<table class="list">
<thead><tr>
<th><%=l(:field_version)%></th>
<th><%=l(:field_filename)%></th>
<th><%=l(:label_date)%></th>
<th><%=l(:field_filesize)%></th>
<th><%=l(:label_downloads_abbr)%></th>
<%= sort_header_tag("#{Attachment.table_name}.filename", :caption => l(:field_filename)) %>
<%= sort_header_tag("#{Attachment.table_name}.created_on", :caption => l(:label_date), :default_order => 'desc') %>
<%= sort_header_tag("#{Attachment.table_name}.filesize", :caption => l(:field_filesize), :default_order => 'desc') %>
<%= sort_header_tag("#{Attachment.table_name}.downloads", :caption => l(:label_downloads_abbr), :default_order => 'desc') %>
<th>MD5</th>
<% if delete_allowed %><th></th><% end %>
</tr></thead>

View File

@@ -59,19 +59,19 @@ function toggle_multi_select(field) {
<table width="100%">
<tr>
<td>
<table style="padding:0;">
<table>
<% query.available_filters.sort{|a,b| a[1][:order]<=>b[1][:order]}.each do |filter| %>
<% field = filter[0]
options = filter[1] %>
<tr <%= 'style="display:none;"' unless query.has_filter?(field) %> id="tr_<%= field %>">
<td valign="top" style="width:200px;">
<tr <%= 'style="display:none;"' unless query.has_filter?(field) %> id="tr_<%= field %>" class="filter">
<td style="width:200px;">
<%= check_box_tag 'fields[]', field, query.has_filter?(field), :onclick => "toggle_filter('#{field}');", :id => "cb_#{field}" %>
<label for="cb_<%= field %>"><%= filter[1][:name] || l(("field_"+field.to_s.gsub(/\_id$/, "")).to_sym) %></label>
</td>
<td valign="top" style="width:150px;">
<td style="width:150px;">
<%= select_tag "operators[#{field}]", options_for_select(operators_for_select(options[:type]), query.operator_for(field)), :id => "operators_#{field}", :onchange => "toggle_operator('#{field}');", :class => "select-small", :style => "vertical-align: top;" %>
</td>
<td valign="top">
<td>
<div id="div_values_<%= field %>" style="display:none;">
<% case options[:type]
when :list, :list_optional, :list_status, :list_subprojects %>
@@ -93,7 +93,7 @@ function toggle_multi_select(field) {
<% end %>
</table>
</td>
<td align="right" valign="top">
<td class="add-filter">
<%= l(:label_filter_add) %>:
<%= select_tag 'add_filter_select', options_for_select([["",""]] + query.available_filters.sort{|a,b| a[1][:order]<=>b[1][:order]}.collect{|field| [ field[1][:name] || l(("field_"+field[0].to_s.gsub(/\_id$/, "")).to_sym), field[0]] unless query.has_filter?(field[0])}.compact), :onchange => "add_filter();", :class => "select-small" %>
</td>

View File

@@ -6,11 +6,16 @@
<p><label for="query_name"><%=l(:field_name)%></label>
<%= text_field 'query', 'name', :size => 80 %></p>
<% if current_role.allowed_to?(:manage_public_queries) %>
<p><label for="query_is_public"><%=l(:field_is_public)%></label>
<%= check_box 'query', 'is_public' %></p>
<% if User.current.admin? || (@project && current_role.allowed_to?(:manage_public_queries)) %>
<p><label for="query_is_public"><%=l(:field_is_public)%></label>
<%= check_box 'query', 'is_public',
:onchange => (User.current.admin? ? nil : 'if (this.checked) {$("query_is_for_all").checked = false; $("query_is_for_all").disabled = true;} else {$("query_is_for_all").disabled = false;}') %></p>
<% end %>
<p><label for="query_is_for_all"><%=l(:field_is_for_all)%></label>
<%= check_box_tag 'query_is_for_all', 1, @query.project.nil?,
:disabled => (!@query.new_record? && (@query.project.nil? || (@query.is_public? && !User.current.admin?))) %></p>
<p><label for="query_default_columns"><%=l(:label_default_columns)%></label>
<%= check_box_tag 'default_columns', 1, @query.has_default_columns?, :id => 'query_default_columns',
:onclick => 'if (this.checked) {Element.hide("columns")} else {Element.show("columns")}' %></p>

View File

@@ -49,7 +49,7 @@
<td><div class="square action_<%= change.action %>"></div> <%= change.path %> <%= "(#{change.revision})" unless change.revision.blank? %></td>
<td align="right">
<% if change.action == "M" %>
<%= link_to l(:label_view_diff), :action => 'diff', :id => @project, :path => change.path, :rev => @changeset.revision %>
<%= link_to l(:label_view_diff), :action => 'diff', :id => @project, :path => without_leading_slash(change.path), :rev => @changeset.revision %>
<% end %>
</td>
</tr>

View File

@@ -0,0 +1,28 @@
<fieldset id="filters"><legend><%= l(:label_date_range) %></legend>
<p>
<%= radio_button_tag 'period_type', '1', !@free_period %>
<%= select_tag 'period', options_for_period_select(params[:period]),
:onchange => 'this.form.onsubmit();',
:onfocus => '$("period_type_1").checked = true;' %>
</p>
<p>
<%= radio_button_tag 'period_type', '2', @free_period %>
<span onclick="$('period_type_2').checked = true;">
<%= l(:label_date_from) %>
<%= text_field_tag 'from', @from, :size => 10 %> <%= calendar_for('from') %>
<%= l(:label_date_to) %>
<%= text_field_tag 'to', @to, :size => 10 %> <%= calendar_for('to') %>
</span>
<%= submit_tag l(:button_apply), :name => nil %>
</p>
</fieldset>
<div class="tabs">
<% url_params = @free_period ? { :from => @from, :to => @to } : { :period => params[:period] } %>
<ul>
<li><%= link_to(l(:label_details), url_params.merge({:controller => 'timelog', :action => 'details', :project_id => @project }),
:class => (@controller.action_name == 'details' ? 'selected' : nil)) %></li>
<li><%= link_to(l(:label_report), url_params.merge({:controller => 'timelog', :action => 'report', :project_id => @project}),
:class => (@controller.action_name == 'report' ? 'selected' : nil)) %></li>
</ul>
</div>

View File

@@ -1,5 +1,6 @@
<table class="list time-entries">
<thead>
<tr>
<%= sort_header_tag('spent_on', :caption => l(:label_date), :default_order => 'desc') %>
<%= sort_header_tag('user_id', :caption => l(:label_member)) %>
<%= sort_header_tag('activity_id', :caption => l(:label_activity)) %>
@@ -8,6 +9,7 @@
<th><%= l(:field_comments) %></th>
<%= sort_header_tag('hours', :caption => l(:field_hours)) %>
<th></th>
</tr>
</thead>
<tbody>
<% entries.each do |entry| -%>
@@ -35,5 +37,5 @@
</td>
</tr>
<% end -%>
</tbdoy>
</tbody>
</table>

View File

@@ -1,14 +1,16 @@
<% @hours.collect {|h| h[criterias[level]]}.uniq.each do |value| %>
<% @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? -%>
<tr class="<%= cycle('odd', 'even') %> <%= 'last-level' unless criterias.length > level+1 %>">
<%= '<td></td>' * level %>
<td><%= value.nil? ? l(:label_none) : @available_criterias[criterias[level]][:klass].find_by_id(value) %></td>
<td><%= format_criteria_value(criterias[level], value) %></td>
<%= '<td></td>' * (criterias.length - level - 1) -%>
<% total = 0 -%>
<% @periods.each do |period| -%>
<% sum = sum_hours(select_hours(hours_for_value, @columns, period.to_s)) %>
<% sum = sum_hours(select_hours(hours_for_value, @columns, period.to_s)); total += sum -%>
<td class="hours"><%= html_hours("%.2f" % sum) if sum > 0 %></td>
<% end -%>
<td class="hours"><%= html_hours("%.2f" % total) if total > 0 %></td>
</tr>
<% if criterias.length > level+1 -%>
<%= render(:partial => 'report_criteria', :locals => {:criterias => criterias, :hours => hours_for_value, :level => (level + 1)}) %>

View File

@@ -1,5 +1,4 @@
<div class="contextual">
<%= link_to(l(:label_report), {:controller => 'timelog', :action => 'report', :project_id => @project}, :class => 'icon icon-report') %>
<%= link_to_if_authorized l(:button_log_time), {:controller => 'timelog', :action => 'edit', :project_id => @project, :issue_id => @issue}, :class => 'icon icon-time' %>
</div>
@@ -12,23 +11,7 @@
<% form_remote_tag( :url => {}, :method => :get, :update => 'content' ) do %>
<%= hidden_field_tag 'project_id', params[:project_id] %>
<%= hidden_field_tag 'issue_id', params[:issue_id] if @issue %>
<fieldset><legend><%= l(:label_date_range) %></legend>
<p>
<%= radio_button_tag 'period_type', '1', !@free_period %>
<%= select_tag 'period', options_for_period_select(params[:period]),
:onchange => 'this.form.onsubmit();',
:onfocus => '$("period_type_1").checked = true;' %>
</p>
<p>
<%= radio_button_tag 'period_type', '2', @free_period %>
<%= l(:label_date_from) %>
<%= text_field_tag 'from', @from, :size => 10, :onfocus => '$("period_type_2").checked = true;' %> <%= calendar_for('from') %>
<%= l(:label_date_to) %>
<%= text_field_tag 'to', @to, :size => 10, :onfocus => '$("period_type_2").checked = true;' %> <%= calendar_for('to') %>
<%= submit_tag l(:button_apply), :name => nil, :onclick => '$("period_type_2").checked = true;' %>
</p>
</fieldset>
<%= render :partial => 'date_range' %>
<% end %>
<div class="total-hours">
@@ -45,9 +28,4 @@
</p>
<% end %>
<% content_for :header_tags do %>
<%= javascript_include_tag 'calendar/calendar' %>
<%= javascript_include_tag "calendar/lang/calendar-#{current_language}.js" %>
<%= javascript_include_tag 'calendar/calendar-setup' %>
<%= stylesheet_link_tag 'calendar' %>
<% end %>
<% html_title l(:label_spent_time), l(:label_details) %>

View File

@@ -2,6 +2,7 @@
<% labelled_tabular_form_for :time_entry, @time_entry, :url => {:action => 'edit', :project_id => @time_entry.project} do |f| %>
<%= error_messages_for 'time_entry' %>
<%= back_url_hidden_field_tag %>
<div class="box">
<p><%= f.text_field :issue_id, :size => 6 %> <em><%= h("#{@time_entry.issue.tracker.name} ##{@time_entry.issue.id}: #{@time_entry.issue.subject}") if @time_entry.issue %></em></p>
@@ -14,10 +15,3 @@
<%= submit_tag l(:button_save) %>
<% end %>
<% content_for :header_tags do %>
<%= javascript_include_tag 'calendar/calendar' %>
<%= javascript_include_tag "calendar/lang/calendar-#{current_language}.js" %>
<%= javascript_include_tag 'calendar/calendar-setup' %>
<%= stylesheet_link_tag 'calendar' %>
<% end %>

View File

@@ -1,36 +1,32 @@
<div class="contextual">
<%= link_to(l(:label_details), {:controller => 'timelog', :action => 'details', :project_id => @project}, :class => 'icon icon-details') %>
<%= link_to_if_authorized l(:button_log_time), {:controller => 'timelog', :action => 'edit', :project_id => @project, :issue_id => @issue}, :class => 'icon icon-time' %>
</div>
<h2><%= l(:label_spent_time) %></h2>
<% form_remote_tag(:url => {:project_id => @project}, :update => 'content') do %>
<% form_remote_tag(:url => {}, :update => 'content') do %>
<% @criterias.each do |criteria| %>
<%= hidden_field_tag 'criterias[]', criteria %>
<%= hidden_field_tag 'criterias[]', criteria, :id => nil %>
<% end %>
<fieldset><legend><%= l(:label_date_range) %></legend>
<p>
<%= l(:label_date_from) %>
<%= text_field_tag 'date_from', @date_from, :size => 10 %><%= calendar_for('date_from') %>
<%= l(:label_date_to) %>
<%= text_field_tag 'date_to', @date_to, :size => 10 %><%= calendar_for('date_to') %>
<%= l(:label_details) %>
<%= select_tag 'period', options_for_select([[l(:label_year), 'year'],
[l(:label_month), 'month'],
[l(:label_week), 'week']], @columns) %>
&nbsp;
<%= submit_tag l(:button_apply) %>
</p>
</fieldset>
<%= hidden_field_tag 'project_id', params[:project_id] %>
<%= render :partial => 'date_range' %>
<p><%= l(:button_add) %>: <%= select_tag('criterias[]', options_for_select([[]] + (@available_criterias.keys - @criterias).collect{|k| [l(@available_criterias[k][:label]), k]}),
<p><%= l(:label_details) %>: <%= select_tag 'columns', options_for_select([[l(:label_year), 'year'],
[l(:label_month), 'month'],
[l(:label_week), 'week'],
[l(:label_day_plural).titleize, 'day']], @columns),
:onchange => "this.form.onsubmit();" %>
<%= l(:button_add) %>: <%= select_tag('criterias[]', options_for_select([[]] + (@available_criterias.keys - @criterias).collect{|k| [l(@available_criterias[k][:label]), k]}),
:onchange => "this.form.onsubmit();",
:style => 'width: 200px',
:id => nil,
:disabled => (@criterias.length >= 3)) %>
<%= link_to_remote l(:button_clear), {:url => {:project_id => @project, :date_from => @date_from, :date_to => @date_to, :period => @columns}, :update => 'content'},
:class => 'icon icon-reload' %></p>
<%= link_to_remote l(:button_clear), {:url => {:project_id => @project, :period_type => params[:period_type], :period => params[:period], :from => @from, :to => @to, :columns => @columns},
:update => 'content'
}, :class => 'icon icon-reload' %></p>
<% end %>
<% unless @criterias.empty? %>
<div class="total-hours">
<p><%= l(:label_total) %>: <%= html_hours(lwr(:label_f_hour, @total_hours)) %></p>
@@ -41,11 +37,13 @@
<thead>
<tr>
<% @criterias.each do |criteria| %>
<th width="15%"><%= l(@available_criterias[criteria][:label]) %></th>
<th><%= l(@available_criterias[criteria][:label]) %></th>
<% end %>
<% columns_width = (40 / (@periods.length+1)).to_i %>
<% @periods.each do |period| %>
<th width="<%= ((100 - @criterias.length * 15 - 15 ) / @periods.length).to_i %>%"><%= period %></th>
<th class="period" width="<%= columns_width %>%"><%= period %></th>
<% end %>
<th class="total" width="<%= columns_width %>%"><%= l(:label_total) %></th>
</tr>
</thead>
<tbody>
@@ -53,20 +51,22 @@
<tr class="total">
<td><%= l(:label_total) %></td>
<%= '<td></td>' * (@criterias.size - 1) %>
<% total = 0 -%>
<% @periods.each do |period| -%>
<% sum = sum_hours(select_hours(@hours, @columns, period.to_s)) %>
<% sum = sum_hours(select_hours(@hours, @columns, period.to_s)); total += sum -%>
<td class="hours"><%= html_hours("%.2f" % sum) if sum > 0 %></td>
<% end -%>
<td class="hours"><%= html_hours("%.2f" % total) if total > 0 %></td>
</tr>
</tbody>
</table>
<% end %>
<p class="other-formats">
<%= l(:label_export_to) %>
<span><%= link_to 'CSV', params.merge({:format => 'csv'}), :class => 'csv' %></span>
</p>
<% end %>
<% end %>
<% content_for :header_tags do %>
<%= javascript_include_tag 'calendar/calendar' %>
<%= javascript_include_tag "calendar/lang/calendar-#{current_language}.js" %>
<%= javascript_include_tag 'calendar/calendar-setup' %>
<%= stylesheet_link_tag 'calendar' %>
<% end %>
<% html_title l(:label_spent_time), l(:label_report) %>

View File

@@ -30,10 +30,3 @@
</div>
</div>
<!--[eoform:user]-->
<% content_for :header_tags do %>
<%= javascript_include_tag 'calendar/calendar' %>
<%= javascript_include_tag "calendar/lang/calendar-#{current_language}.js" %>
<%= javascript_include_tag 'calendar/calendar-setup' %>
<%= stylesheet_link_tag 'calendar' %>
<% end %>

View File

@@ -33,17 +33,7 @@
<td align="center"><%= image_tag('true.png') if user.admin? %></td>
<td class="created_on" align="center"><%= format_time(user.created_on) %></td>
<td class="last_login_on" align="center"><%= format_time(user.last_login_on) unless user.last_login_on.nil? %></td>
<td>
<small>
<% if user.locked? -%>
<%= link_to l(:button_unlock), {:action => 'edit', :id => user, :user => {:status => User::STATUS_ACTIVE}}, :method => :post, :class => 'icon icon-unlock' %>
<% elsif user.registered? -%>
<%= link_to l(:button_activate), {:action => 'edit', :id => user, :user => {:status => User::STATUS_ACTIVE}}, :method => :post, :class => 'icon icon-unlock' %>
<% else -%>
<%= link_to l(:button_lock), {:action => 'edit', :id => user, :user => {:status => User::STATUS_LOCKED}}, :method => :post, :class => 'icon icon-lock' %>
<% end -%>
</small>
</td>
<td><small><%= change_status_link(user) %></small></td>
</tr>
<% end -%>
</tbody>

View File

@@ -6,10 +6,3 @@
<p><%= f.text_field :wiki_page_title, :label => :label_wiki_page, :size => 60, :disabled => @project.wiki.nil? %></p>
<p><%= f.text_field :effective_date, :size => 10 %><%= calendar_for('version_effective_date') %></p>
</div>
<% content_for :header_tags do %>
<%= javascript_include_tag 'calendar/calendar' %>
<%= javascript_include_tag "calendar/lang/calendar-#{current_language}.js" %>
<%= javascript_include_tag 'calendar/calendar-setup' %>
<%= stylesheet_link_tag 'calendar' %>
<% end %>

View File

@@ -12,6 +12,7 @@
</div>
<div class="splitcontentright">
<% if @projects.any? %>
<div class="box">
<h3 class="icon22 icon22-projects"><%=l(:label_project_latest)%></h3>
<ul>
@@ -22,7 +23,8 @@
</li>
<% end %>
</ul>
</div>
</div>
<% end %>
</div>
<% content_for :header_tags do %>

View File

@@ -4,6 +4,9 @@
# you don't control web/app server and can't set it the proper way
# ENV['RAILS_ENV'] ||= 'production'
# Specifies gem version of Rails to use when vendor/rails is not present
RAILS_GEM_VERSION = '2.0.2' unless defined? RAILS_GEM_VERSION
# Bootstrap the Rails environment, frameworks, and default configuration
require File.join(File.dirname(__FILE__), 'boot')

View File

@@ -5,6 +5,53 @@ Copyright (C) 2006-2008 Jean-Philippe Lang
http://www.redmine.org/
== 2008-05-04 v0.7.1
* Thai translation added (Gampol Thitinilnithi)
* Translations updates
* Escape HTML comment tags
* Prevent "can't convert nil into String" error when :sort_order param is not present
* Fixed: Updating tickets add a time log with zero hours
* Fixed: private subprojects names are revealed on the project overview
* Fixed: Search for target version of "none" fails with postgres 8.3
* Fixed: Home, Logout, Login links shouldn't be absolute links
* Fixed: 'Latest projects' box on the welcome screen should be hidden if there are no projects
* Fixed: error when using upcase language name in coderay
* Fixed: error on Trac import when :due attribute is nil
== 2008-04-28 v0.7.0
* Forces Redmine to use rails 2.0.2 gem when vendor/rails is not present
* Queries can be marked as 'For all projects'. Such queries will be available on all projects and on the global issue list.
* Add predefined date ranges to the time report
* Time report can be done at issue level
* Various timelog report enhancements
* Accept the following formats for "hours" field: 1h, 1 h, 1 hour, 2 hours, 30m, 30min, 1h30, 1h30m, 1:30
* Display the context menu above and/or to the left of the click if needed
* Make the admin project files list sortable
* Mercurial: display working directory files sizes unless browsing a specific revision
* Preserve status filter and page number when using lock/unlock/activate links on the users list
* Redmine.pm support for LDAP authentication
* Better error message and AR errors in log for failed LDAP on-the-fly user creation
* Redirected user to where he is coming from after logging hours
* Warn user that subprojects are also deleted when deleting a project
* Include subprojects versions on calendar and gantt
* Notify project members when a message is posted if they want to receive notifications
* Fixed: Feed content limit setting has no effect
* Fixed: Priorities not ordered when displayed as a filter in issue list
* Fixed: can not display attached images inline in message replies
* Fixed: Boards are not deleted when project is deleted
* Fixed: trying to preview a new issue raises an exception with postgresql
* Fixed: single file 'View difference' links do not work because of duplicate slashes in url
* Fixed: inline image not displayed when including a wiki page
* Fixed: CVS duplicate key violation
* Fixed: ActiveRecord::StaleObjectError exception on closing a set of circular duplicate issues
* Fixed: custom field filters behaviour
* Fixed: Postgresql 8.3 compatibility
* Fixed: Links to repository directories don't work
== 2008-03-29 v0.7.0-rc1
* Overall activity view and feed added, link is available on the project list

View File

@@ -1,7 +1,7 @@
== Redmine installation
Redmine - project management software
Copyright (C) 2006-2007 Jean-Philippe Lang
Copyright (C) 2006-2008 Jean-Philippe Lang
http://www.redmine.org/

View File

@@ -8,8 +8,8 @@ against redmine database
=head1 SYNOPSIS
This module allow anonymous users to browse public project and
registred users to browse and commit their project. authentication is
done on the redmine database.
registred users to browse and commit their project. Authentication is
done against the redmine database or the LDAP configured in redmine.
This method is far simpler than the one with pam_* and works with all
database without an hassle but you need to have apache/mod_perl on the
@@ -29,6 +29,11 @@ On debian/ubuntu you must do :
aptitude install libapache-dbi-perl libapache2-mod-perl2 libdbd-mysql-perl
If your Redmine users use LDAP authentication, you will also need
Authen::Simple::LDAP (and IO::Socket::SSL if LDAPS is used):
aptitude install libauthen-simple-ldap-perl libio-socket-ssl-perl
=head1 CONFIGURATION
## if the module isn't in your perl path
@@ -90,6 +95,8 @@ use strict;
use DBI;
use Digest::SHA1;
# optional module for LDAP authentication
my $CanUseLDAPAuth = eval("use Authen::Simple::LDAP; 1");
use Apache2::Module;
use Apache2::Access;
@@ -140,7 +147,7 @@ sub is_public_project {
my $dbh = connect_database($r);
my $sth = $dbh->prepare(
"SELECT * FROM projects WHERE projects.identifier=? and projects.is_public=true;"
"SELECT * FROM projects WHERE projects.identifier=? and projects.is_public=true;"
);
$sth->execute($project_id);
@@ -176,17 +183,37 @@ sub is_member {
my $pass_digest = Digest::SHA1::sha1_hex($redmine_pass);
my $sth = $dbh->prepare(
"SELECT hashed_password FROM members, projects, users WHERE projects.id=members.project_id AND users.id=members.user_id AND users.status=1 AND login=? AND identifier=?;"
"SELECT hashed_password, auth_source_id FROM members, projects, users WHERE projects.id=members.project_id AND users.id=members.user_id AND users.status=1 AND login=? AND identifier=?;"
);
$sth->execute($redmine_user, $project_id);
my $ret;
while (my @row = $sth->fetchrow_array) {
if ($row[0] eq $pass_digest) {
$ret = 1;
last;
unless ($row[1]) {
if ($row[0] eq $pass_digest) {
$ret = 1;
last;
}
} elsif ($CanUseLDAPAuth) {
my $sthldap = $dbh->prepare(
"SELECT host,port,tls,account,account_password,base_dn,attr_login from auth_sources WHERE id = ?;"
);
$sthldap->execute($row[1]);
while (my @rowldap = $sthldap->fetchrow_array) {
my $ldap = Authen::Simple::LDAP->new(
host => ($rowldap[2] == 1 || $rowldap[2] eq "t") ? "ldaps://$rowldap[0]" : $rowldap[0],
port => $rowldap[1],
basedn => $rowldap[5],
binddn => $rowldap[3] ? $rowldap[3] : "",
bindpw => $rowldap[4] ? $rowldap[4] : "",
filter => "(".$rowldap[6]."=%s)"
);
$ret = 1 if ($ldap->authenticate($redmine_user, $redmine_pass));
}
$sthldap->finish();
}
}
$sth->finish();
$dbh->disconnect();
$ret;

View File

@@ -48,8 +48,8 @@ general_text_no: 'не'
general_text_yes: 'да'
general_lang_name: 'Bulgarian'
general_csv_separator: ','
general_csv_encoding: cp1251
general_pdf_encoding: cp1251
general_csv_encoding: UTF-8
general_pdf_encoding: UTF-8
general_day_names: Понеделник,Вторник,Сряда,Четвъртък,Петък,Събота,Неделя
general_first_day_of_week: '1'
@@ -57,11 +57,11 @@ 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_register_done: Профилът е създаден успешно.
notice_account_unknown_email: Непознат e-mail.
notice_can_t_change_password: Този профил е с външен метод за оторизация. Невъзможна смяна на паролата.
notice_account_lost_email_sent: Изпратен ви е e-mail с инструкции за избор на нова парола.
notice_account_activated: Акаунтът ви е активиран. Вече може да влезете.
notice_account_activated: Профилът ви е активиран. Вече може да влезете в системата.
notice_successful_create: Успешно създаване.
notice_successful_update: Успешно обновяване.
notice_successful_delete: Успешно изтриване.
@@ -78,8 +78,8 @@ error_scm_command_failed: "Грешка при опит за комуникац
mail_subject_lost_password: Вашата парола (%s)
mail_body_lost_password: 'За да смените паролата си, използвайте следния линк:'
mail_subject_register: Активация на акаунт (%s)
mail_body_register: 'За да активирате акаунта си използвайте следния линк:'
mail_subject_register: Активация на профил (%s)
mail_body_register: 'За да активирате профила си използвайте следния линк:'
gui_validation_error: 1 грешка
gui_validation_error_plural: %d грешки
@@ -113,11 +113,11 @@ field_notes: Бележка
field_is_closed: Затворена задача
field_is_default: Статус по подразбиране
field_tracker: Тракер
field_subject: Тема
field_subject: Относно
field_due_date: Крайна дата
field_assigned_to: Възложена на
field_priority: Приоритет
field_fixed_version: Target version
field_fixed_version: Планувана версия
field_user: Потребител
field_role: Роля
field_homepage: Начална страница
@@ -138,7 +138,7 @@ field_version: Версия
field_type: Тип
field_host: Хост
field_port: Порт
field_account: Акаунт
field_account: Профил
field_base_dn: Base DN
field_attr_login: Login attribute
field_attr_firstname: Firstname attribute
@@ -163,7 +163,7 @@ field_delay: Отместване
field_assignable: Възможно е възлагане на задачи за тази роля
field_redirect_existing_links: Пренасочване на съществуващи линкове
field_estimated_hours: Изчислено време
field_default_value: Статус по подразбиране
field_default_value: Стойност по подразбиране
setting_app_title: Заглавие
setting_app_subtitle: Описание
@@ -171,15 +171,15 @@ setting_welcome_text: Допълнителен текст
setting_default_language: Език по подразбиране
setting_login_required: Изискване за вход в системата
setting_self_registration: Регистрация от потребители
setting_attachment_max_size: Максимално голям приложен файл
setting_attachment_max_size: Максимална големина на прикачен файл
setting_issues_export_limit: Лимит за експорт на задачи
setting_mail_from: E-mail адрес за емисии
setting_host_name: Хост
setting_text_formatting: Форматиране на текста
setting_wiki_compression: Wiki компресиране на историята
setting_feeds_limit: Лимит на Feeds
setting_autofetch_changesets: Автоматично обработване на commits в хранилището
setting_sys_api_enabled: Разрешаване на WS за управление на хранилището
setting_autofetch_changesets: Автоматично обработване на ревизиите
setting_sys_api_enabled: Разрешаване на WS за управление
setting_commit_ref_keywords: Отбелязващи ключови думи
setting_commit_fix_keywords: Приключващи ключови думи
setting_autologin: Автоматичен вход
@@ -231,7 +231,7 @@ label_password_lost: Забравена парола
label_home: Начало
label_my_page: Лична страница
label_my_account: Профил
label_my_projects: Моите проекти
label_my_projects: Проекти, в които участвам
label_administration: Администрация
label_login: Вход
label_logout: Изход
@@ -375,8 +375,8 @@ label_f_hour_plural: %.2f часа
label_time_tracking: Отделяне на време
label_change_plural: Промени
label_statistics: Статистики
label_commits_per_month: Commits за месец
label_commits_per_author: Commits за автор
label_commits_per_month: Ревизии по месеци
label_commits_per_author: Ревизии по автор
label_view_diff: Виж разликите
label_diff_inline: хоризонтално
label_diff_side_by_side: вертикално
@@ -389,7 +389,7 @@ label_applied_status: Промени статуса на
label_loading: Зареждане...
label_relation_new: Нова релация
label_relation_delete: Изтриване на релация
label_relates_to: Свързана със
label_relates_to: свързана със
label_duplicates: дублира
label_blocks: блокира
label_blocked_by: блокирана от
@@ -427,10 +427,10 @@ label_updated_time: Обновена преди %s
label_jump_to_a_project: Проект...
button_login: Вход
button_submit: Приложи
button_submit: Прикачване
button_save: Запис
button_check_all: Маркирай всички
button_uncheck_all: Изчисти всички
button_check_all: Избор на всички
button_uncheck_all: Изчистване на всички
button_delete: Изтриване
button_create: Създаване
button_test: Тест
@@ -481,9 +481,9 @@ text_length_between: От %d до %d символа.
text_tracker_no_workflow: Няма дефиниран работен процес за този тракер
text_unallowed_characters: Непозволени символи
text_comma_separated: Позволено е изброяване (с разделител запетая).
text_issues_ref_in_commit_messages: Отбелязване и приключване на задачи от commit съобщения
text_issue_added: Публикувана е нова задача с номер %s (by %s).
text_issue_updated: Задача %s е обновена (by %s).
text_issues_ref_in_commit_messages: Отбелязване и приключване на задачи от ревизии
text_issue_added: Публикувана е нова задача с номер %s (от %s).
text_issue_updated: Задача %s е обновена (от %s).
text_wiki_destroy_confirmation: Сигурни ли сте, че искате да изтриете това Wiki и цялото му съдържание?
text_issue_category_destroy_question: Има задачи (%d) обвързани с тази категория. Какво ще изберете?
text_issue_category_destroy_assignments: Премахване на връзките с категорията
@@ -515,11 +515,11 @@ enumeration_issue_priorities: Приоритети на задачи
enumeration_doc_categories: Категории документи
enumeration_activities: Дейности (time tracking)
label_file_plural: Файлове
label_changeset_plural: Changesets
label_changeset_plural: Ревизии
field_column_names: Колони
label_default_columns: По подразбиране
setting_issue_list_default_columns: Показвани колони по подразбиране
setting_repositories_encodings: Кодови таблици на хранилищата
setting_repositories_encodings: Кодови таблици
notice_no_issue_selected: "Няма избрани задачи."
label_bulk_edit_selected_issues: Редактиране на задачи
label_no_change_option: (Без промяна)
@@ -536,20 +536,20 @@ label_user_mail_option_none: "Само за наблюдавани или в к
setting_emails_footer: Подтекст за e-mail
label_float: Дробно
button_copy: Копиране
mail_body_account_information_external: Можете да използвате вашия "%s" акаунт за вход.
mail_body_account_information: Информацията за акаунта
mail_body_account_information_external: Можете да използвате вашия "%s" профил за вход.
mail_body_account_information: Информацията за профила ви
setting_protocol: Протокол
label_user_mail_no_self_notified: "Не искам известия за извършени от мен промени"
setting_time_format: Формат на часа
label_registration_activation_by_email: активиране на акаунта по email
mail_subject_account_activation_request: Заявка за активиране на акаунт в %s
label_registration_activation_by_email: активиране на профила по email
mail_subject_account_activation_request: Заявка за активиране на профил в %s
mail_body_account_activation_request: 'Има новорегистриран потребител (%s), очакващ вашето одобрение:'
label_registration_automatic_activation: автоматично активиране
label_registration_manual_activation: ръчно активиране
notice_account_pending: "Акаунтът Ви е създаден и очаква одобрение от администратор."
notice_account_pending: "Профилът Ви е създаден и очаква одобрение от администратор."
field_time_zone: Часова зона
text_caracters_minimum: Минимум %d символа.
setting_bcc_recipients: Blind carbon copy (bcc) получатели
setting_bcc_recipients: Получатели на скрито копие (bcc)
button_annotate: Анотация
label_issues_by: Задачи по %s
field_searchable: С възможност за търсене
@@ -566,54 +566,55 @@ label_general: Основни
label_repository_plural: Хранилища
label_associated_revisions: Асоциирани ревизии
setting_user_format: Потребителски формат
text_status_changed_by_changeset: Applied in changeset %s.
label_more: More
text_issues_destroy_confirmation: 'Are you sure you want to delete the selected issue(s) ?'
label_scm: SCM
text_select_project_modules: 'Select modules to enable for this project:'
label_issue_added: Issue added
label_issue_updated: Issue updated
label_document_added: Document added
label_message_posted: Message added
label_file_added: File added
label_news_added: News added
project_module_boards: Boards
project_module_issue_tracking: Issue tracking
text_status_changed_by_changeset: Приложено с ревизия %s.
label_more: Още
text_issues_destroy_confirmation: 'Сигурни ли сте, че искате да изтриете избраните задачи?'
label_scm: SCM (Система за контрол на кода)
text_select_project_modules: 'Изберете активните модули за този проект:'
label_issue_added: Добавена задача
label_issue_updated: Обновена задача
label_document_added: Добавен документ
label_message_posted: Добавено съобщение
label_file_added: Добавен файл
label_news_added: Добавена новина
project_module_boards: Форуми
project_module_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
project_module_files: Файлове
project_module_documents: Документи
project_module_repository: Хранилище
project_module_news: Новини
project_module_time_tracking: Отделяне на време
text_file_repository_writable: Възможност за писане в хранилището с файлове
text_default_administrator_account_changed: Сменен фабричния администраторски профил
text_rmagick_available: Наличен RMagick (по избор)
button_configure: Конфигуриране
label_plugins: Плъгини
label_ldap_authentication: LDAP оторизация
label_downloads_abbr: D/L
label_this_month: this month
label_last_n_days: last %d 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: %.02f 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
label_this_month: текущия месец
label_last_n_days: последните %d дни
label_all_time: всички
label_this_year: текущата година
label_date_range: Период
label_last_week: последната седмица
label_yesterday: вчера
label_last_month: последния месец
label_add_another_file: Добавяне на друг файл
label_optional_description: Незадължително описание
text_destroy_time_entries_question: %.02f часа са отделени на задачите, които искате да изтриете. Какво избирате?
error_issue_not_found_in_project: 'Задачата не е намерена или не принадлежи на този проект'
text_assign_time_entries_to_project: Прехвърляне на отделеното време към проект
text_destroy_time_entries: Изтриване на отделеното време
text_reassign_time_entries: 'Прехвърляне на отделеното време към задача:'
setting_activity_days_default: Брой дни показвани на таб Дейност
label_chronological_order: Хронологичен ред
field_comments_sorting: Сортиране на коментарите
label_reverse_chronological_order: Обратен хронологичен ред
label_preferences: Предпочитания
setting_display_subprojects_issues: Показване на подпроектите в проектите по подразбиране
label_overall_activity: Цялостна дейност
setting_default_projects_public: Новите проекти са публични по подразбиране
error_scm_annotate: "Обектът не съществува или не може да бъде анотиран."
label_planning: Планиране
text_subprojects_destroy_warning: 'Its subproject(s): %s will be also deleted.'

View File

@@ -10,16 +10,16 @@ actionview_datehelper_select_month_prefix:
actionview_datehelper_select_year_prefix:
actionview_datehelper_time_in_words_day: 1 den
actionview_datehelper_time_in_words_day_plural: %d dny
actionview_datehelper_time_in_words_hour_about: asi hodinu
actionview_datehelper_time_in_words_hour_about_plural: asi %d hodin
actionview_datehelper_time_in_words_hour_about_single: asi hodinu
actionview_datehelper_time_in_words_minute: 1 minuta
actionview_datehelper_time_in_words_minute_half: půl minuty
actionview_datehelper_time_in_words_minute_less_than: méně než minutu
actionview_datehelper_time_in_words_minute_plural: %d minut
actionview_datehelper_time_in_words_minute_single: 1 minuta
actionview_datehelper_time_in_words_second_less_than: méně než sekunda
actionview_datehelper_time_in_words_second_less_than_plural: méně než %d sekund
actionview_datehelper_time_in_words_hour_about: asi hodinou
actionview_datehelper_time_in_words_hour_about_plural: asi %d hodinami
actionview_datehelper_time_in_words_hour_about_single: asi hodinou
actionview_datehelper_time_in_words_minute: 1 minutou
actionview_datehelper_time_in_words_minute_half: půl minutou
actionview_datehelper_time_in_words_minute_less_than: méně než minutou
actionview_datehelper_time_in_words_minute_plural: %d minutami
actionview_datehelper_time_in_words_minute_single: 1 minutou
actionview_datehelper_time_in_words_second_less_than: méně než sekundou
actionview_datehelper_time_in_words_second_less_than_plural: méně než %d sekundami
actionview_instancetag_blank_option: Prosím vyberte
activerecord_error_inclusion: není zahrnuto v seznamu
@@ -98,7 +98,7 @@ mail_body_account_activation_request: Byl zaregistrován nový uživatel "%s". A
gui_validation_error: 1 chyba
gui_validation_error_plural: %d chyb(y)
field_name: Jméno
field_name: Název
field_description: Popis
field_summary: Přehled
field_is_required: Povinné pole
@@ -306,7 +306,7 @@ label_attribute: Atribut
label_attribute_plural: Atributy
label_download: %d Download
label_download_plural: %d Downloads
label_no_data: Žádná data k zobrazení
label_no_data: Žádné položky
label_change_status: Změnit stav
label_history: Historie
label_attachment: Soubor
@@ -480,8 +480,8 @@ label_sort_by: Seřadit podle %s
label_send_test_email: Poslat testovací email
label_feeds_access_key_created_on: Přístupový klíč pro RSS byl vytvořen před %s
label_module_plural: Moduly
label_added_time_by: 'Přidáno před: %s %s'
label_updated_time: 'Aktualizováno před: %s'
label_added_time_by: 'Přidáno uživatelem %s před %s'
label_updated_time: 'Aktualizováno před %s'
label_jump_to_a_project: Zvolit projekt...
label_file_plural: Soubory
label_changeset_plural: Changesety
@@ -586,7 +586,7 @@ text_no_configuration_data: "Role, fronty, stavy úkolů ani workflow nebyly zat
text_load_default_configuration: Nahrát výchozí konfiguraci
text_status_changed_by_changeset: Použito v changesetu %s.
text_issues_destroy_confirmation: 'Opravdu si přejete odstranit všechny zvolené úkoly?'
text_select_project_modules: 'Zvolte moduly aktivní v tomto projektu:'
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 repository
text_rmagick_available: RMagick k dispozici (volitelné)
@@ -620,5 +620,6 @@ default_activity_development: Vývoj
enumeration_issue_priorities: Priority úkolů
enumeration_doc_categories: Kategorie dokumentů
enumeration_activities: Aktivity (sledování času)
error_scm_annotate: "The entry does not exist or can not be annotated."
label_planning: Planning
error_scm_annotate: "Položka neexistuje nebo nemůže být komentována."
label_planning: Plánování
text_subprojects_destroy_warning: 'Its subproject(s): %s will be also deleted.'

View File

@@ -619,3 +619,4 @@ label_overall_activity: Overordnet aktivitet
setting_default_projects_public: Nye projekter er offentlige som default
error_scm_annotate: "The entry does not exist or can not be annotated."
label_planning: Planlægning
text_subprojects_destroy_warning: 'Its subproject(s): %s will be also deleted.'

View File

@@ -71,7 +71,7 @@ notice_locking_conflict: Datum wurde von einem anderen Benutzer geändert.
notice_not_authorized: Sie sind nicht berechtigt, auf diese Seite zuzugreifen.
notice_email_sent: Eine E-Mail wurde an %s gesendet.
notice_email_error: Beim Senden einer E-Mail ist ein Fehler aufgetreten (%s).
notice_feeds_access_key_reseted: Ihr RSS-Zugriffsschlüssel wurde zurückgesetzt.
notice_feeds_access_key_reseted: Ihr Atom-Zugriffsschlüssel wurde zurückgesetzt.
notice_failed_to_save_issues: "%d von %d ausgewählten Tickets konnte(n) nicht gespeichert werden: %s."
notice_no_issue_selected: "Kein Ticket ausgewählt! Bitte wählen Sie die Tickets, die Sie bearbeiten möchten."
notice_account_pending: "Ihr Konto wurde erstellt und wartet jetzt auf die Genehmigung des Administrators."
@@ -80,6 +80,7 @@ notice_default_data_loaded: Die Standard-Konfiguration wurde erfolgreich geladen
error_can_t_load_default_data: "Die Standard-Konfiguration konnte nicht geladen werden: %s"
error_scm_not_found: Eintrag und/oder Revision besteht nicht im Projektarchiv.
error_scm_command_failed: "Beim Zugriff auf das Projektarchiv ist ein Fehler aufgetreten: %s"
error_scm_annotate: "Der Eintrag existiert nicht oder kann nicht annotiert werden."
error_issue_not_found_in_project: 'Das Ticket wurde nicht gefunden oder gehört nicht zu diesem Projekt.'
mail_subject_lost_password: Ihr %s Kennwort
@@ -120,8 +121,8 @@ field_project: Projekt
field_issue: Ticket
field_status: Status
field_notes: Kommentare
field_is_closed: Problem erledigt
field_is_default: Default
field_is_closed: Ticket geschlossen
field_is_default: Standardeinstellung
field_tracker: Tracker
field_subject: Thema
field_due_date: Abgabedatum
@@ -133,8 +134,8 @@ field_role: Rolle
field_homepage: Projekt-Homepage
field_is_public: Öffentlich
field_parent: Unterprojekt von
field_is_in_chlog: Ansicht im Change-Log
field_is_in_roadmap: Ansicht in der Roadmap
field_is_in_chlog: Im Change-Log anzeigen
field_is_in_roadmap: In der Roadmap anzeigen
field_login: Mitgliedsname
field_mail_notification: Mailbenachrichtigung
field_admin: Administrator
@@ -177,6 +178,7 @@ field_column_names: Spalten
field_time_zone: Zeitzone
field_searchable: Durchsuchbar
field_default_value: Standardwert
field_comments_sorting: Kommentare anzeigen
setting_app_title: Applikations-Titel
setting_app_subtitle: Applikations-Untertitel
@@ -191,7 +193,8 @@ setting_bcc_recipients: E-Mails als Blindkopie (BCC) senden
setting_host_name: Hostname
setting_text_formatting: Textformatierung
setting_wiki_compression: Wiki-Historie komprimieren
setting_feeds_limit: Feed-Inhalt begrenzen
setting_feeds_limit: Max. Anzahl Einträge pro Atom-Feed
setting_default_projects_public: Neue Projekte sind standardmäßig öffentlich
setting_autofetch_changesets: Changesets automatisch abrufen
setting_sys_api_enabled: Webservice zur Verwaltung der Projektarchive benutzen
setting_commit_ref_keywords: Schlüsselwörter (Beziehungen)
@@ -206,6 +209,8 @@ setting_emails_footer: E-Mail-Fußzeile
setting_protocol: Protokoll
setting_per_page_options: Objekte pro Seite
setting_user_format: Benutzer-Anzeigeformat
setting_activity_days_default: Anzahl Tage pro Seite der Projekt-Aktivität
setting_display_subprojects_issues: Tickets von Unterprojekten im Hauptprojekt anzeigen
project_module_issue_tracking: Ticket-Verfolgung
project_module_time_tracking: Zeiterfassung
@@ -227,7 +232,7 @@ label_project_latest: Neueste Projekte
label_issue: Ticket
label_issue_new: Neues Ticket
label_issue_plural: Tickets
label_issue_view_all: Alle Tickets ansehen
label_issue_view_all: Alle Tickets anzeigen
label_issues_by: Tickets von %s
label_issue_added: Ticket hinzugefügt
label_issue_updated: Ticket aktualisiert
@@ -277,6 +282,7 @@ label_last_updates: zuletzt aktualisiert
label_last_updates_plural: %d zuletzt aktualisierten
label_registered_on: Angemeldet am
label_activity: Aktivität
label_overall_activity: Aktivität aller Projekte anzeigen
label_new: Neu
label_logged_as: Angemeldet als
label_environment: Environment
@@ -320,7 +326,7 @@ label_version: Version
label_version_new: Neue Version
label_version_plural: Versionen
label_confirmation: Bestätigung
label_export_to: Export zu
label_export_to: "Auch abrufbar als:"
label_read: Lesen...
label_public_projects: Öffentliche Projekte
label_open_issues: offen
@@ -345,7 +351,7 @@ label_months_from: Monate ab
label_gantt: Gantt
label_internal: Intern
label_last_changes: %d letzte Änderungen
label_change_view_all: Alle Änderungen ansehen
label_change_view_all: Alle Änderungen anzeigen
label_personalize_page: Diese Seite anpassen
label_comment: Kommentar
label_comment_plural: Kommentare
@@ -469,7 +475,7 @@ label_date_to: Bis
label_language_based: Sprachabhängig
label_sort_by: Sortiert nach %s
label_send_test_email: Test-E-Mail senden
label_feeds_access_key_created_on: RSS-Zugriffsschlüssel vor %s erstellt
label_feeds_access_key_created_on: Atom-Zugriffsschlüssel vor %s erstellt
label_module_plural: Module
label_added_time_by: Von %s vor %s hinzugefügt
label_updated_time: Vor %s aktualisiert
@@ -500,6 +506,10 @@ label_ldap_authentication: LDAP-Authentifizierung
label_downloads_abbr: D/L
label_optional_description: Beschreibung (optional)
label_add_another_file: Eine weitere Datei hinzufügen
label_preferences: Präferenzen
label_chronological_order: in zeitlicher Reihenfolge
label_reverse_chronological_order: in umgekehrter zeitlicher Reihenfolge
label_planning: Terminplanung
button_login: Anmelden
button_submit: OK
@@ -518,7 +528,7 @@ button_lock: Sperren
button_unlock: Entsperren
button_download: Download
button_list: Liste
button_view: Ansehen
button_view: Anzeigen
button_move: Verschieben
button_back: Zurück
button_cancel: Abbrechen
@@ -535,7 +545,7 @@ button_reset: Zurücksetzen
button_rename: Umbenennen
button_change_password: Kennwort ändern
button_copy: Kopieren
button_annotate: Mit Anmerkungen versehen
button_annotate: Annotieren
button_update: Aktualisieren
button_configure: Konfigurieren
@@ -608,13 +618,4 @@ default_activity_development: Entwicklung
enumeration_issue_priorities: Ticket-Prioritäten
enumeration_doc_categories: Dokumentenkategorien
enumeration_activities: Aktivitäten (Zeiterfassung)
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): %s will be also deleted.'

View File

@@ -557,6 +557,7 @@ text_select_mail_notifications: Select actions for which email notifications sho
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): %s 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: changed from %s to %s

View File

@@ -333,8 +333,8 @@ label_revision_plural: Revisiones
label_added: añadido
label_modified: modificado
label_deleted: suprimido
label_latest_revision: La revisión más actual
label_latest_revision_plural: Las revisiones más actuales
label_latest_revision: Última revisión
label_latest_revision_plural: Últimas revisiones
label_view_revisions: Ver las revisiones
label_max_size: Tamaño máximo
label_on: de
@@ -372,7 +372,7 @@ label_view_diff: Ver diferencias
label_diff_inline: en línea
label_diff_side_by_side: cara a cara
label_options: Opciones
label_copy_workflow_from: Copiar workflow desde
label_copy_workflow_from: Copiar flujo de trabajo desde
label_permissions_report: Informe de permisos
label_watched_issues: Peticiones monitorizadas
label_related_issues: Peticiones relacionadas
@@ -432,7 +432,7 @@ button_move: Mover
button_back: Atrás
button_cancel: Cancelar
button_activate: Activar
button_sort: Clasificar
button_sort: Ordenar
button_log_time: Tiempo dedicado
button_rollback: Volver a esta versión
button_watch: Monitorizar
@@ -448,7 +448,7 @@ status_locked: bloqueado
text_select_mail_notifications: Seleccionar los eventos a notificar
text_regexp_info: eg. ^[A-Z0-9]+$
text_min_max_length_info: 0 para ninguna restricción
text_project_destroy_confirmation: ¿ Estás seguro de querer eliminar el proyecto ?
text_project_destroy_confirmation: ¿Estás seguro de querer eliminar el proyecto?
text_workflow_edit: Seleccionar un flujo de trabajo para actualizar
text_are_you_sure: ¿ Estás seguro ?
text_journal_changed: cambiado de %s a %s
@@ -460,7 +460,7 @@ text_tip_task_begin_end_day: tarea que comienza y termina este día
text_project_identifier_info: 'Letras minúsculas (a-z), números y signos de puntuación permitidos.<br />Una vez guardado, el identificador no puede modificarse.'
text_caracters_maximum: %d carácteres como máximo.
text_length_between: Longitud entre %d y %d carácteres.
text_tracker_no_workflow: No hay ningún workflow definido para este tracker
text_tracker_no_workflow: No hay ningún flujo de trabajo definido para este tracker
text_unallowed_characters: Carácteres no permitidos
text_comma_separated: Múltiples valores permitidos (separados por coma).
text_issues_ref_in_commit_messages: Referencia y petición de corrección en los mensajes
@@ -559,64 +559,65 @@ field_searchable: Incluir en las búsquedas
label_display_per_page: 'Por página: %s'
setting_per_page_options: Objetos por página
label_age: Edad
notice_default_data_loaded: Default configuration successfully loaded.
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."
error_can_t_load_default_data: "Default configuration could not be loaded: %s"
button_update: Update
label_change_properties: Change properties
notice_default_data_loaded: Configuración por defecto cargada correctamente.
text_load_default_configuration: Cargar la configuración por defecto
text_no_configuration_data: "Todavía no se han configurado roles, ni trackers, ni estados y flujo de trabajo asociado a peticiones. Se recomiendo encarecidamente cargar la configuración por defecto. Una vez cargada, podrá modificarla."
error_can_t_load_default_data: "No se ha podido cargar la configuración por defecto: %s"
button_update: Actualizar
label_change_properties: Cambiar propiedades
label_general: General
label_repository_plural: Repositories
label_associated_revisions: Associated revisions
setting_user_format: Users display format
text_status_changed_by_changeset: Applied in changeset %s.
label_more: More
text_issues_destroy_confirmation: 'Are you sure you want to delete the selected issue(s) ?'
label_repository_plural: Repositorios
label_associated_revisions: Revisiones asociadas
setting_user_format: Formato de nombre de usuario
text_status_changed_by_changeset: Aplicado en los cambios %s
label_more: Más
text_issues_destroy_confirmation: '¿Seguro que quiere borrar las peticiones seleccionadas?'
label_scm: SCM
text_select_project_modules: 'Select modules to enable for this project:'
label_issue_added: Issue added
label_issue_updated: Issue updated
label_document_added: Document added
label_message_posted: Message added
label_file_added: File added
label_news_added: News added
project_module_boards: Boards
project_module_issue_tracking: Issue tracking
text_select_project_modules: 'Seleccione los módulos a activar para este proyecto:'
label_issue_added: Petición añadida
label_issue_updated: Petición actualizada
label_document_added: Documento añadido
label_message_posted: Mensaje añadido
label_file_added: Fichero añadido
label_news_added: Noticia añadida
project_module_boards: Foros
project_module_issue_tracking: Peticiones
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
project_module_files: Ficheros
project_module_documents: Documentos
project_module_repository: Repositorio
project_module_news: Noticias
project_module_time_tracking: Control de tiempo
text_file_repository_writable: Se puede escribir en el repositorio
text_default_administrator_account_changed: Cuenta de administrador por defecto modificada
text_rmagick_available: RMagick disponible (opcional)
button_configure: Configurar
label_plugins: Plugins
label_ldap_authentication: LDAP authentication
label_ldap_authentication: Autenticación LDAP
label_downloads_abbr: D/L
label_this_month: this month
label_last_n_days: last %d 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: %.02f 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
label_this_month: este mes
label_last_n_days: últimos %d días
label_all_time: todo el tiempo
label_this_year: este año
label_date_range: Rango de fechas
label_last_week: última semana
label_yesterday: ayer
label_last_month: último mes
label_add_another_file: Añadir otro fichero
label_optional_description: Descripción opcional
text_destroy_time_entries_question: Existen %.02f horas asignadas a la petición que quiere borrar. ¿Qué quiere hacer ?
error_issue_not_found_in_project: 'La petición no se encuentra o no está asociada a este proyecto'
text_assign_time_entries_to_project: Asignar las horas al proyecto
text_destroy_time_entries: Borrar las horas
text_reassign_time_entries: 'Reasignar las horas a esta petición:'
setting_activity_days_default: Días a mostrar en la actividad de proyecto
label_chronological_order: En orden cronológico
field_comments_sorting: Mostrar comentarios
label_reverse_chronological_order: En orden cronológico inverso
label_preferences: Preferencias
setting_display_subprojects_issues: Mostrar peticiones de un subproyecto en el proyecto padre por defecto
label_overall_activity: Actividad global
setting_default_projects_public: Los proyectos nuevos son públicos por defecto
error_scm_annotate: "No existe la entrada o no ha podido ser anotada"
label_planning: Planificación
text_subprojects_destroy_warning: 'Sus subprojectos: %s también se eliminarán'

View File

@@ -307,8 +307,8 @@ label_confirmation: Vahvistus
label_export_to: Vie
label_read: Lukee...
label_public_projects: Julkiset projektit
label_open_issues: avoin
label_open_issues_plural: avointa
label_open_issues: avoin, yhteensä
label_open_issues_plural: avointa, yhteensä
label_closed_issues: suljettu
label_closed_issues_plural: suljettua
label_total: Yhteensä
@@ -614,6 +614,7 @@ 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: Kokonaisaktiviteetti
error_scm_annotate: "The entry does not exist or can not be annotated."
label_planning: Planning
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 alaprojekti(t): %s tullaan myös poistamaan.'

View File

@@ -556,7 +556,8 @@ status_locked: vérouillé
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: Etes-vous sûr de vouloir supprimer ce projet et tout ce qui lui est rattaché ?
text_project_destroy_confirmation: Etes-vous sûr de vouloir supprimer ce projet et toutes ses données ?
text_subprojects_destroy_warning: 'Ses sous-projets: %s seront également supprimés.'
text_workflow_edit: Sélectionner un tracker et un rôle pour éditer le workflow
text_are_you_sure: Etes-vous sûr ?
text_journal_changed: changé de %s à %s

View File

@@ -76,7 +76,7 @@ notice_failed_to_save_issues: "נכשרת בשמירת %d נושא\ים ב %d נ
notice_no_issue_selected: "לא נבחר אף נושא! בחר בבקשה את הנושאים שברצונך לערוך."
error_scm_not_found: כניסה ו\או גירסא אינם קיימים במאגר.
error_scm_command_failed: "An error occurred when trying to access the repository: %s"
error_scm_command_failed: "ארעה שגיאה בעת ניסון גישה למאגר: %s"
mail_subject_lost_password: סיסמת ה-%s שלך
mail_body_lost_password: 'לשינו סיסמת ה-Redmine שלך,לחץ על הקישור הבא:'
@@ -98,7 +98,7 @@ field_filesize: גודל
field_downloads: הורדות
field_author: כותב
field_created_on: נוצר
field_updated_on: עודגן
field_updated_on: עודכן
field_field_format: פורמט
field_is_for_all: לכל הפרויקטים
field_possible_values: ערכים אפשריים
@@ -119,7 +119,7 @@ field_subject: שם נושא
field_due_date: תאריך סיום
field_assigned_to: מוצב ל
field_priority: עדיפות
field_fixed_version: Target version
field_fixed_version: גירסאת יעד
field_user: מתשמש
field_role: תפקיד
field_homepage: דף הבית
@@ -140,7 +140,7 @@ field_version: גירסא
field_type: סוג
field_host: שרת
field_port: פורט
field_account: חשבום
field_account: חשבון
field_base_dn: בסיס DN
field_attr_login: תכונת התחברות
field_attr_firstname: תכונת שם פרטים
@@ -182,7 +182,7 @@ setting_text_formatting: עיצוב טקסט
setting_wiki_compression: כיווץ היסטורית WIKI
setting_feeds_limit: גבול תוכן הזנות
setting_autofetch_changesets: משיכה אוטומתי של עידכונים
setting_sys_api_enabled: Enable WS for repository management
setting_sys_api_enabled: אפשר WS לניהול המאגר
setting_commit_ref_keywords: מילות מפתח מקשרות
setting_commit_fix_keywords: מילות מפתח מתקנות
setting_autologin: חיבור אוטומטי
@@ -233,7 +233,7 @@ label_information_plural: מידע
label_please_login: התחבר בבקשה
label_register: הרשמה
label_password_lost: אבדה הסיסמה?
label_home: דך הבית
label_home: דף הבית
label_my_page: הדף שלי
label_my_account: השבון שלי
label_my_projects: הפרויקטים שלי
@@ -259,7 +259,7 @@ label_subproject_plural: תת-פרויקטים
label_min_max_length: אורך מינימאלי - מקסימאלי
label_list: רשימה
label_date: תאריך
label_integer: מספר שלים
label_integer: מספר שלם
label_boolean: ערך בוליאני
label_string: טקסט
label_text: טקסט ארוך
@@ -269,7 +269,7 @@ label_download: הורדה %d
label_download_plural: %d הורדות
label_no_data: אין מידע להציג
label_change_status: שנה מצב
label_history: הידטוריה
label_history: היסטוריה
label_attachment: קובץ
label_attachment_new: קובץ חדש
label_attachment_delete: מחק קובץ
@@ -279,7 +279,7 @@ label_report_plural: דו"חות
label_news: חדשות
label_news_new: הוסף חדשות
label_news_plural: חדשות
label_news_latest: חדשות חדשות
label_news_latest: חדשות אחרונות
label_news_view_all: צפה בכל החדשות
label_change_log: דו"ח שינויים
label_settings: הגדרות
@@ -419,7 +419,7 @@ label_reply_plural: השבות
label_send_information: שלח מידע על חשבון למשתמש
label_year: שנה
label_month: חודש
label_week: שבו
label_week: שבוע
label_date_from: מאת
label_date_to: אל
label_language_based: מבוסס שפה
@@ -444,7 +444,7 @@ button_save: שמור
button_check_all: בחר הכל
button_uncheck_all: בחר כלום
button_delete: מחק
button_create: צוק
button_create: צור
button_test: בדוק
button_edit: ערוך
button_add: הוסף
@@ -454,13 +454,13 @@ button_clear: נקה
button_lock: נעל
button_unlock: בטל נעילה
button_download: הורד
button_list: קשימה
button_list: רשימה
button_view: צפה
button_move: הזז
button_back: הקודם
button_cancel: בטח
button_activate: הפעל
button_sort: מין
button_sort: מיין
button_log_time: זמן לוג
button_rollback: חזור לגירסא זו
button_watch: צפה
@@ -526,94 +526,95 @@ default_activity_development: פיתוח
enumeration_issue_priorities: עדיפות נושאים
enumeration_doc_categories: קטגוריות מסמכים
enumeration_activities: פעילויות (מעקב אחר זמנים)
label_search_titles_only: Search titles only
label_nobody: nobody
button_change_password: Change password
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)."
label_user_mail_option_selected: "For any event on the selected projects only..."
label_user_mail_option_all: "For any event on all my projects"
label_user_mail_option_none: "Only for things I watch or I'm involved in"
setting_emails_footer: Emails footer
label_float: Float
button_copy: Copy
mail_body_account_information_external: You can use your "%s" account to log in.
mail_body_account_information: Your account information
setting_protocol: Protocol
label_user_mail_no_self_notified: "I don't want to be notified of changes that I make myself"
setting_time_format: Time format
label_registration_activation_by_email: account activation by email
mail_subject_account_activation_request: %s account activation request
mail_body_account_activation_request: 'A new user (%s) has registered. His account his pending your approval:'
label_registration_automatic_activation: automatic account activation
label_registration_manual_activation: manual account activation
notice_account_pending: "Your account was created and is now pending administrator approval."
field_time_zone: Time zone
text_caracters_minimum: Must be at least %d characters long.
setting_bcc_recipients: Blind carbon copy recipients (bcc)
button_annotate: Annotate
label_issues_by: Issues by %s
field_searchable: Searchable
label_display_per_page: 'Per page: %s'
setting_per_page_options: Objects per page options
label_age: Age
notice_default_data_loaded: Default configuration successfully loaded.
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."
error_can_t_load_default_data: "Default configuration could not be loaded: %s"
button_update: Update
label_change_properties: Change properties
label_general: General
label_repository_plural: Repositories
label_associated_revisions: Associated revisions
setting_user_format: Users display format
text_status_changed_by_changeset: Applied in changeset %s.
label_more: More
text_issues_destroy_confirmation: 'Are you sure you want to delete the selected issue(s) ?'
label_search_titles_only: חפש בכותרות בלבד
label_nobody: אף אחד
button_change_password: שנה סיסמא
text_user_mail_option: "בפרויקטים שלא בחרת, אתה רק תקבל התרעות על שאתה צופה או קשור אליהם (לדוגמא:נושאים שאתה היוצר שלהם או מוצבים אליך)."
label_user_mail_option_selected: "לכל אירוע בפרויקטים שבחרתי בלבד..."
label_user_mail_option_all: "לכל אירוע בכל הפרויקטים שלי"
label_user_mail_option_none: "רק לנושאים שאני צופה או קשור אליהם"
setting_emails_footer: תחתית דוא"ל
label_float: צף
button_copy: העתק
mail_body_account_information_external: אתה יכול להשתמש בחשבון "%s" כדי להתחבר
mail_body_account_information: פרטי החשבון שלך
setting_protocol: פרוטוקול
label_user_mail_no_self_notified: "אני לא רוצה שיודיעו לי על שינויים שאני מבצע"
setting_time_format: פורמט זמן
label_registration_activation_by_email: הפעל חשבון באמצעות דוא"ל
mail_subject_account_activation_request: בקשת הפעלה לחשבון %s
mail_body_account_activation_request: 'משתמש חדש (%s) נרשם. החשבון שלו מחכה לאישור שלך:'
label_registration_automatic_activation: הפעלת חשבון אוטומטית
label_registration_manual_activation: הפעלת חשבון ידנית
notice_account_pending: "החשבון שלך נוצר ועתה מחכה לאישור מנהל המערכת."
field_time_zone: איזור זמן
text_caracters_minimum: חייב להיות לפחות באורך של %d תווים.
setting_bcc_recipients: מוסתר (bcc)
button_annotate: הוסף תיאור מסגרת
label_issues_by: נושאים של %s
field_searchable: ניתן לחיפוש
label_display_per_page: 'לכל דף: %s'
setting_per_page_options: אפשרויות אוביקטים לפי דף
label_age: גיל
notice_default_data_loaded: אפשרויות ברירת מחדל מופעלות.
text_load_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. יהיה באפשרותך לשנותו לאחר שיטען."
error_can_t_load_default_data: "אפשרויות ברירת המחדל לא הצליחו להיטען: %s"
button_update: עדכן
label_change_properties: שנה מאפיינים
label_general: כללי
label_repository_plural: מאגרים
label_associated_revisions: שינויים קשורים
setting_user_format: פורמט הצגת משתמשים
text_status_changed_by_changeset: הוחל בסדרת השינויים %s.
label_more: עוד
text_issues_destroy_confirmation: 'האם את\ה בטוח שברצונך למחוק את הנושא\ים ?'
label_scm: SCM
text_select_project_modules: 'Select modules to enable for this project:'
label_issue_added: Issue added
label_issue_updated: Issue updated
label_document_added: Document added
label_message_posted: Message added
label_file_added: File added
label_news_added: News added
project_module_boards: Boards
project_module_issue_tracking: Issue tracking
text_select_project_modules: 'בחר מודולים להחיל על פקרויקט זה:'
label_issue_added: נושא הוסף
label_issue_updated: נושא עודכן
label_document_added: מוסמך הוסף
label_message_posted: הודעה הוספה
label_file_added: קובץ הוסף
label_news_added: חדשות הוספו
project_module_boards: לוחות
project_module_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
project_module_files: קבצים
project_module_documents: מסמכים
project_module_repository: מאגר
project_module_news: חדשות
project_module_time_tracking: מעקב אחר זמנים
text_file_repository_writable: מאגר הקבצים ניתן לכתיבה
text_default_administrator_account_changed: מנהל המערכת ברירת המחדל שונה
text_rmagick_available: RMagick available (optional)
button_configure: Configure
label_plugins: Plugins
label_ldap_authentication: LDAP authentication
button_configure: אפשרויות
label_plugins: פלאגינים
label_ldap_authentication: אימות LDAP
label_downloads_abbr: D/L
label_this_month: this month
label_last_n_days: last %d 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: %.02f 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
label_this_month: החודש
label_last_n_days: ב-%d ימים אחרונים
label_all_time: תמיד
label_this_year: השנה
label_date_range: טווח תאריכים
label_last_week: שבוע שעבר
label_yesterday: אתמול
label_last_month: חודש שעבר
label_add_another_file: הוסף עוד קובץ
label_optional_description: תיאור רשות
text_destroy_time_entries_question: %.02f שעות דווחו על הנושים שאת\ה עומד\ת למחוק. מה ברצונך לעשות ?
error_issue_not_found_in_project: 'הנושאים לא נמצאו או אינם שיכים לפרויקט'
text_assign_time_entries_to_project: הצב שעות שדווחו לפרויקט הזה
text_destroy_time_entries: מחק שעות שדווחו
text_reassign_time_entries: 'הצב מחדש שעות שדווחו לפרויקט הזה:'
setting_activity_days_default: ימים המוצגים על פעילות הפרויקט
label_chronological_order: בסדר כרונולוגי
field_comments_sorting: הצג הערות
label_reverse_chronological_order: בסדר כרונולוגי הפוך
label_preferences: העדפות
setting_display_subprojects_issues: הצג נושאים של תת פרויקטים כברירת מחדל
label_overall_activity: פעילות כוללת
setting_default_projects_public: פרויקטים חדשים הינם פומביים כברירת מחדל
error_scm_annotate: "הכניסה לא קיימת או שלא ניתן לתאר אותה."
label_planning: תכנון
text_subprojects_destroy_warning: 'Its subproject(s): %s will be also deleted.'

View File

@@ -617,3 +617,4 @@ 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): %s will be also deleted.'

View File

@@ -618,3 +618,4 @@ label_overall_activity: 全ての活動
setting_default_projects_public: デフォルトで新しいプロジェクトは公開にする
error_scm_annotate: "エントリが存在しない、もしくはアノテートできません。"
label_planning: 計画
text_subprojects_destroy_warning: 'Its subproject(s): %s will be also deleted.'

View File

@@ -617,3 +617,4 @@ 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): %s will be also deleted.'

View File

@@ -618,3 +618,4 @@ 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): %s will be also deleted.'

View File

@@ -618,3 +618,4 @@ 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): %s will be also deleted.'

View File

@@ -80,7 +80,7 @@ notice_default_data_loaded: Standardkonfigurasjonen lastet inn.
error_can_t_load_default_data: "Standardkonfigurasjonen kunne ikke lastes inn: %s"
error_scm_not_found: "Elementet og/eller revisjonen eksisterer ikke i depoet."
error_scm_command_failed: "En feil oppstod under tilkobling til depoet: %s"
error_scm_annotate: "Elementet eksisterer ikke, eller kan ikke annoteres."
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 %s passord
@@ -137,7 +137,7 @@ field_parent: Underprosjekt til
field_is_in_chlog: Vises i endringslogg
field_is_in_roadmap: Vises i veikart
field_login: Brukernavn
field_mail_notification: E-post varsling
field_mail_notification: E-post-varsling
field_admin: Administrator
field_last_login_on: Sist innlogget
field_language: Språk
@@ -165,7 +165,7 @@ field_url: URL
field_start_page: Startside
field_subproject: Underprosjekt
field_hours: Timer
field_activity: Activitet
field_activity: Aktivitet
field_spent_on: Dato
field_identifier: Identifikasjon
field_is_filter: Brukes som filter
@@ -282,7 +282,7 @@ label_last_updates: Sist oppdatert
label_last_updates_plural: %d siste oppdaterte
label_registered_on: Registrert
label_activity: Aktivitet
label_overall_activity: Total aktivitet
label_overall_activity: All aktivitet
label_new: Ny
label_logged_as: Innlogget som
label_environment: Miljø
@@ -352,7 +352,7 @@ label_gantt: Gantt
label_internal: Intern
label_last_changes: siste %d endringer
label_change_view_all: Vis alle endringer
label_personalize_page: Tilrettelegg denne siden
label_personalize_page: Tilpass denne siden
label_comment: Kommentar
label_comment_plural: Kommentarer
label_comment_add: Legg til kommentar
@@ -545,7 +545,7 @@ button_reset: Nullstill
button_rename: Endre navn
button_change_password: Endre passord
button_copy: Kopier
button_annotate: Annotér
button_annotate: Notér
button_update: Oppdater
button_configure: Konfigurer
@@ -557,6 +557,7 @@ text_select_mail_notifications: Velg hendelser som skal varsles med e-post.
text_regexp_info: eg. ^[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): %s vil også bli slettet.'
text_workflow_edit: Velg en rolle og en sakstype for å endre arbeidsflyten
text_are_you_sure: Er du sikker ?
text_journal_changed: endret fra %s til %s
@@ -565,7 +566,7 @@ text_journal_deleted: slettet
text_tip_task_begin_day: oppgaven starter denne dagen
text_tip_task_end_day: oppgaven avsluttes denne dagen
text_tip_task_begin_end_day: oppgaven starter og avsluttes denne dagen
text_project_identifier_info: 'Små bokstaver (a-z), nummer og binde-/understrek tillat.<br />Identifikatoren kan ikke endres etter den er lagret.'
text_project_identifier_info: 'Små bokstaver (a-z), nummer og bindestrek tillatt.<br />Identifikatoren kan ikke endres etter den er lagret.'
text_caracters_maximum: %d tegn maksimum.
text_caracters_minimum: Må være minst %d tegn langt.
text_length_between: Lengde mellom %d og %d tegn.
@@ -586,8 +587,8 @@ text_status_changed_by_changeset: Brukt i endringssett %s.
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-depotet er skrivbart
text_rmagick_available: RMagick tilgjengelig (valgfritt)
text_file_repository_writable: Fil-arkivet er skrivbart
text_rmagick_available: RMagick er tilgjengelig (valgfritt)
text_destroy_time_entries_question: %.02f 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

View File

@@ -114,7 +114,7 @@ field_subject: Temat
field_due_date: Data oddania
field_assigned_to: Przydzielony do
field_priority: Priorytet
field_fixed_version: Target version
field_fixed_version: Wersja docelowa
field_user: Użytkownik
field_role: Rola
field_homepage: Strona www
@@ -331,7 +331,7 @@ label_modification_plural: %d modyfikacja
label_revision: Zmiana
label_revision_plural: Zmiany
label_added: dodane
label_modified: zmodufikowane
label_modified: zmodyfikowane
label_deleted: usunięte
label_latest_revision: Ostatnia zmiana
label_latest_revision_plural: Ostatnie zmiany
@@ -469,7 +469,7 @@ default_role_manager: Kierownik
default_role_developper: Programista
default_role_reporter: Wprowadzajacy
default_tracker_bug: Błąd
default_tracker_feature: Cecha
default_tracker_feature: Zadanie
default_tracker_support: Wsparcie
default_issue_status_new: Nowy
default_issue_status_assigned: Przypisany
@@ -483,7 +483,7 @@ default_priority_low: Niski
default_priority_normal: Normalny
default_priority_high: Wysoki
default_priority_urgent: Pilny
default_priority_immediate: Natyczmiastowy
default_priority_immediate: Natychmiastowy
default_activity_design: Projektowanie
default_activity_development: Rozwój
@@ -617,3 +617,4 @@ label_overall_activity: Ogólna aktywność
setting_default_projects_public: Nowe projekty są domyślnie publiczne
error_scm_annotate: "Wpis nie istnieje lub nie można do niego dodawać adnotacji."
label_planning: Planning
text_subprojects_destroy_warning: 'Its subproject(s): %s will be also deleted.'

View File

@@ -617,3 +617,4 @@ 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): %s will be also deleted.'

View File

@@ -617,3 +617,4 @@ 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): %s will be also deleted.'

View File

@@ -617,3 +617,4 @@ 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): %s will be also deleted.'

View File

@@ -619,5 +619,6 @@ label_preferences: Предпочтения
setting_display_subprojects_issues: Отображение подпроектов по умолчанию
label_overall_activity: Сводная активность
setting_default_projects_public: Новые проекты являются публичными
error_scm_annotate: "The entry does not exist or can not be annotated."
label_planning: Planning
error_scm_annotate: "Данные отсутствуют или не могут быть подписаны."
label_planning: Планирование
text_subprojects_destroy_warning: 'Its subproject(s): %s will be also deleted.'

View File

@@ -618,3 +618,4 @@ 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): %s will be also deleted.'

View File

@@ -618,3 +618,4 @@ 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): %s will be also deleted.'

623
lang/th.yml Normal file
View File

@@ -0,0 +1,623 @@
_gloc_rule_default: '|n| n==1 ? "" : "_plural" '
actionview_datehelper_select_day_prefix:
actionview_datehelper_select_month_names: มกราคม,กุมภาพันธ์,มีนาคม,เมษายน,พฤษภาคม,มิถุนายน,กรกฎาคม,สิงหาคม,กันยายน,ตุลาคม,พฤศจิกายน,ธันวาคม
actionview_datehelper_select_month_names_abbr: ม.ค.,ก.พ.,มี.ค.,เม.ย.,พ.ค.,มิ.ย.,ก.ค.,ส.ค.,ก.ย.,ต.ค.,พ.ย.,ธ.ค.
actionview_datehelper_select_month_prefix:
actionview_datehelper_select_year_prefix:
actionview_datehelper_time_in_words_day: 1 วัน
actionview_datehelper_time_in_words_day_plural: %d วัน
actionview_datehelper_time_in_words_hour_about: ประมาณ 1 ชั่วโมง
actionview_datehelper_time_in_words_hour_about_plural: ประมาณ %d ชั่วโมง
actionview_datehelper_time_in_words_hour_about_single: ประมาณ 1 ชั่วโมง
actionview_datehelper_time_in_words_minute: 1 นาที
actionview_datehelper_time_in_words_minute_half: ครึ่งนาที
actionview_datehelper_time_in_words_minute_less_than: ไม่ถึงนาที
actionview_datehelper_time_in_words_minute_plural: %d นาที
actionview_datehelper_time_in_words_minute_single: 1 นาที
actionview_datehelper_time_in_words_second_less_than: ไม่ถึงวินาที
actionview_datehelper_time_in_words_second_less_than_plural: ไม่ถึง %d วินาที
actionview_instancetag_blank_option: กรุณาเลือก
activerecord_error_inclusion: ไม่อยู่ในรายการ
activerecord_error_exclusion: ถูกสงวนไว้
activerecord_error_invalid: ไม่ถูกต้อง
activerecord_error_confirmation: พิมพ์ไม่เหมือนเดิม
activerecord_error_accepted: ต้องยอมรับ
activerecord_error_empty: ต้องเติม
activerecord_error_blank: ต้องเติม
activerecord_error_too_long: ยาวเกินไป
activerecord_error_too_short: สั้นเกินไป
activerecord_error_wrong_length: ความยาวไม่ถูกต้อง
activerecord_error_taken: ถูกใช้ไปแล้ว
activerecord_error_not_a_number: ไม่ใช่ตัวเลข
activerecord_error_not_a_date: ไม่ใช่วันที่ ที่ถูกต้อง
activerecord_error_greater_than_start_date: ต้องมากกว่าวันเริ่ม
activerecord_error_not_same_project: ไม่ได้อยู่ในโครงการเดียวกัน
activerecord_error_circular_dependency: ความสัมพันธ์อ้างอิงเป็นวงกลม
general_fmt_age: %d ปี
general_fmt_age_plural: %d ปี
general_fmt_date: %%d/%%B/%%Y
general_fmt_datetime: %%d/%%B/%%Y %%H:%%M
general_fmt_datetime_short: %%d %%b, %%H:%%M
general_fmt_time: %%H:%%M
general_text_No: 'ไม่'
general_text_Yes: 'ใช่'
general_text_no: 'ไม่'
general_text_yes: 'ใช่'
general_lang_name: 'Thai (ไทย)'
general_csv_separator: ','
general_csv_encoding: Windows-874
general_pdf_encoding: cp874
general_day_names: จันทร์,อังคาร,พุธ,พฤหัสบดี,ศุกร์,เสาร์,อาทิตย์
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: อีเมล์ได้ถูกส่งถึง %s
notice_email_error: เกิดความผิดพลาดขณะกำส่งอีเมล์ (%s)
notice_feeds_access_key_reseted: RSS access key ของคุณถูก reset แล้ว.
notice_failed_to_save_issues: "%d ปัญหาจาก %d ปัญหาที่ถูกเลือกไม่สามารถจัดเก็บ: %s."
notice_no_issue_selected: "ไม่มีปัญหาที่ถูกเลือก! กรุณาเลือกปัญหาที่คุณต้องการแก้ไข."
notice_account_pending: "บัญชีของคุณสร้างเสร็จแล้ว ขณะนี้รอการอนุมัติจากผู้บริหารจัดการ."
notice_default_data_loaded: ค่าเริ่มต้นโหลดเสร็จแล้ว.
error_can_t_load_default_data: "ค่าเริ่มต้นโหลดไม่สำเร็จ: %s"
error_scm_not_found: "ไม่พบรุ่นที่ต้องการในแหล่งเก็บต้นฉบับ."
error_scm_command_failed: "เกิดความผิดพลาดในการเข้าถึงแหล่งเก็บต้นฉบับ: %s"
error_scm_annotate: "entry ไม่มีอยู่จริง หรือไม่สามารถเขียนหมายเหตุประกอบ."
error_issue_not_found_in_project: 'ไม่พบปัญหานี้ หรือปัญหาไม่ได้อยู่ในโครงการนี้'
mail_subject_lost_password: รหัสผ่าน %s ของคุณ
mail_body_lost_password: 'คลิ๊กที่ลิงค์ต่อไปนี้เพื่อเปลี่ยนรหัสผ่าน:'
mail_subject_register: เปิดบัญชี %s ของคุณ
mail_body_register: 'คลิ๊กที่ลิงค์ต่อไปนี้เพื่อเปลี่ยนรหัสผ่าน:'
mail_body_account_information_external: คุณสามารถใช้บัญชี "%s" เพื่อเข้าสู่ระบบ.
mail_body_account_information: ข้อมูลบัญชีของคุณ
mail_subject_account_activation_request: กรุณาเปิดบัญชี %s
mail_body_account_activation_request: 'ผู้ใช้ใหม่ (%s) ได้ลงทะเบียน. บัญชีของเขากำลังรออนุมัติ:'
gui_validation_error: 1 ข้อผิดพลาด
gui_validation_error_plural: %d ข้อผิดพลาด
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_chlog: ปัญหาแสดงใน รายกาเปลี่ยนแปลง
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_id: ปัญหาที่เกี่ยวข้อง
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_repositories_encodings: การเข้ารหัสที่เก็บต้นฉบับ
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_project_all: โครงการทั้งหมด
label_project_latest: โครงการล่าสุด
label_issue: ปัญหา
label_issue_new: ปัญหาใหม่
label_issue_plural: ปัญหา
label_issue_view_all: ดูปัญหาทั้งหมด
label_issues_by: ปัญหาโดย %s
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_last_updates: ปรับปรุงครั้งสุดท้าย
label_last_updates_plural: %d ปรับปรุงครั้งสุดท้าย
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_download: %d ดาวน์โหลด
label_download_plural: %d ดาวน์โหลด
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_change_log: บันทึกการเปลี่ยนแปลง
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_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 %d เปลี่ยนแปลง
label_change_view_all: ดูการเปลี่ยนแปลงทั้งหมด
label_personalize_page: ปรับแต่งหน้านี้
label_comment: ความเห็น
label_comment_plural: ความเห็น
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: %d วันย้อนหลัง
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_modification: %d เปลี่ยนแปลง
label_modification_plural: %d เปลี่ยนแปลง
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_on: 'ใน'
label_sort_highest: ย้ายไปบนสุด
label_sort_higher: ย้ายขึ้น
label_sort_lower: ย้ายลง
label_sort_lowest: ย้ายไปล่างสุด
label_roadmap: แผนงาน
label_roadmap_due_in: ถึงกำหนดใน
label_roadmap_overdue: %s ช้ากว่ากำหนด
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: %.2f ชั่วโมง
label_f_hour_plural: %.2f ชั่วโมง
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: เรียงโดย %s
label_send_test_email: ส่งจดหมายทดสอบ
label_feeds_access_key_created_on: RSS access key สร้างเมื่อ %s ที่ผ่านมา
label_module_plural: ส่วนประกอบ
label_added_time_by: เพิ่มโดย %s %s ที่ผ่านมา
label_updated_time: ปรับปรุง %s ที่ผ่านมา
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_no_self_notified: "ฉันไม่ต้องการได้รับการแจ้งเตือนในสิ่งที่ฉันทำเอง"
label_registration_activation_by_email: เปิดบัญชีผ่านอีเมล์
label_registration_manual_activation: อนุมัติโดยผู้บริหารจัดการ
label_registration_automatic_activation: เปิดบัญชีอัตโนมัติ
label_display_per_page: 'ต่อหน้า: %s'
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: 'โครงการย่อย: %s จะถูกลบด้วย.'
text_workflow_edit: เลือกบทบาทและการติดตาม เพื่อแก้ไขลำดับงาน
text_are_you_sure: คุณแน่ใจไหม ?
text_journal_changed: เปลี่ยนแปลงจาก %s เป็น %s
text_journal_set_to: ตั้งค่าเป็น %s
text_journal_deleted: ถูกลบ
text_tip_task_begin_day: งานที่เริ่มวันนี้
text_tip_task_end_day: งานที่จบวันนี้
text_tip_task_begin_end_day: งานที่เริ่มและจบวันนี้
text_project_identifier_info: 'ภาษาอังกฤษตัวเล็ก(a-z), ตัวเลข(0-9) และขีด (-) เท่านั้น.<br />เมื่อจัดเก็บแล้ว, ชื่อเฉพาะไม่สามารถเปลี่ยนแปลงได้'
text_caracters_maximum: สูงสุด %d ตัวอักษร.
text_caracters_minimum: ต้องยาวอย่างน้อย %d ตัวอักษร.
text_length_between: ความยาวระหว่าง %d ถึง %d ตัวอักษร.
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: ปัญหา %s ถูกแจ้งโดย %s.
text_issue_updated: ปัญหา %s ถูกปรับปรุงโดย %s.
text_wiki_destroy_confirmation: คุณแน่ใจหรือว่าต้องการลบ wiki นี้พร้อมทั้งเนี้อหา?
text_issue_category_destroy_question: บางปัญหา (%d) อยู่ในประเภทนี้. คุณต้องการทำอย่างไร ?
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: ประยุกต์ใช้ในกลุ่มการเปลี่ยนแปลง %s.
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: %.02f ชั่วโมงที่ถูกแจ้งในปัญหานี้จะโดนลบ. คุณต้องการทำอย่างไร?
text_destroy_time_entries: ลบเวลาที่รายงานไว้
text_assign_time_entries_to_project: ระบุเวลาที่ใช้ในโครงการนี้
text_reassign_time_entries: 'ระบุเวลาที่ใช้ในโครงการนี่อีกครั้ง:'
default_role_manager: ผู้จัดการ
default_role_developper: ผู้พัฒนา
default_role_reporter: ผู้รายงาน
default_tracker_bug: บั๊ก
default_tracker_feature: ลักษณะเด่น
default_tracker_support: สนับสนุน
default_issue_status_new: เกิดขึ้น
default_issue_status_assigned: รับมอบหมาย
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: กิจกรรม (ใช้ในการติดตามเวลา)

View File

@@ -619,3 +619,4 @@ 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): %s will be also deleted.'

View File

@@ -210,7 +210,7 @@ setting_protocol: 協定
setting_per_page_options: 每頁顯示個數選項
setting_user_format: 使用者顯示格式
setting_activity_days_default: 專案活動顯示天數
setting_display_subprojects_issues: 預設於主控專案中顯示從屬專案的項目
setting_display_subprojects_issues: 預設於專案中顯示專案的項目
project_module_issue_tracking: 項目追蹤
project_module_time_tracking: 工時追蹤
@@ -557,6 +557,7 @@ 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: '下列子專案: %s 將一併被刪除。'
text_workflow_edit: 選擇角色與追蹤標籤以設定其工作流程
text_are_you_sure: 確定執行?
text_journal_changed: 從 %s 變更為 %s

View File

@@ -554,9 +554,10 @@ status_registered: 已注册
status_locked: 已锁定
text_select_mail_notifications: 选择需要发送邮件通知的动作
text_regexp_info: eg. ^[A-Z0-9]+$
text_regexp_info: 例如:^[A-Z0-9]+$
text_min_max_length_info: 0 表示没有限制
text_project_destroy_confirmation: 您确信要删除这个项目以及所有相关的数据吗?
text_subprojects_destroy_warning: '以下子项目也将被同时删除:%s'
text_workflow_edit: 选择角色和跟踪标签来编辑工作流程
text_are_you_sure: 您确定?
text_journal_changed: 从 %s 变更为 %s

View File

@@ -1134,7 +1134,7 @@ class RedCloth < String
ALLOWED_TAGS = %w(redpre pre code)
def escape_html_tags(text)
text.gsub!(%r{<((\/?)(\w+))}) {|m| ALLOWED_TAGS.include?($3) ? "<#{$1}" : "&lt;#{$1}" }
text.gsub!(%r{<(\/?([!\w]+)[^<>\n]*)(>?)}) {|m| ALLOWED_TAGS.include?($2) ? "<#{$1}#{$3}" : "&lt;#{$1}#{'&gt;' unless $3.blank?}" }
end
end

View File

@@ -1,6 +1,7 @@
require 'redmine/access_control'
require 'redmine/menu_manager'
require 'redmine/mime_type'
require 'redmine/core_ext'
require 'redmine/themes'
require 'redmine/plugin'
@@ -93,7 +94,7 @@ Redmine::AccessControl.map do |map|
end
Redmine::MenuManager.map :top_menu do |menu|
menu.push :home, :home_url, :html => { :class => 'home' }
menu.push :home, :home_path, :html => { :class => 'home' }
menu.push :my_page, { :controller => 'my', :action => 'page' }, :html => { :class => 'mypage' }, :if => Proc.new { User.current.logged? }
menu.push :projects, { :controller => 'projects', :action => 'index' }, :caption => :label_project_plural, :html => { :class => 'projects' }
menu.push :administration, { :controller => 'admin', :action => 'index' }, :html => { :class => 'admin' }, :if => Proc.new { User.current.admin? }
@@ -101,10 +102,10 @@ Redmine::MenuManager.map :top_menu do |menu|
end
Redmine::MenuManager.map :account_menu do |menu|
menu.push :login, :signin_url, :html => { :class => 'login' }, :if => Proc.new { !User.current.logged? }
menu.push :login, :signin_path, :html => { :class => 'login' }, :if => Proc.new { !User.current.logged? }
menu.push :register, { :controller => 'account', :action => 'register' }, :html => { :class => 'register' }, :if => Proc.new { !User.current.logged? && Setting.self_registration? }
menu.push :my_account, { :controller => 'my', :action => 'account' }, :html => { :class => 'myaccount' }, :if => Proc.new { User.current.logged? }
menu.push :logout, :signout_url, :html => { :class => 'logout' }, :if => Proc.new { User.current.logged? }
menu.push :logout, :signout_path, :html => { :class => 'logout' }, :if => Proc.new { User.current.logged? }
end
Redmine::MenuManager.map :application_menu do |menu|

1
lib/redmine/core_ext.rb Normal file
View File

@@ -0,0 +1 @@
Dir[File.dirname(__FILE__) + "/core_ext/*.rb"].each { |file| require(file) }

View File

@@ -0,0 +1,5 @@
require File.dirname(__FILE__) + '/string/conversions'
class String #:nodoc:
include Redmine::CoreExtensions::String::Conversions
end

View File

@@ -0,0 +1,40 @@
# redMine - project management software
# Copyright (C) 2008 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!
unless s =~ %r{^[\d\.,]+$}
# 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)?)?$}) { |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
end
end
end
end

View File

@@ -59,8 +59,17 @@ module Redmine
# 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)
e = entries(path, identifier)
e ? e.first : 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

View File

@@ -44,18 +44,6 @@ module Redmine
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)
path ||= ''
parts = path.split(%r{[\/\\]}).select {|p| !p.blank?}
if parts.size > 0
parent = parts[0..-2].join('/')
entries = entries(parent, identifier)
entries ? entries.detect {|e| e.name == parts.last} : 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)

View File

@@ -55,15 +55,6 @@ module Redmine
def get_previous_revision(revision)
CvsRevisionHelper.new(revision).prevRev
end
# Returns the entry identified by path and revision identifier
# or nil if entry doesn't exist in the repository
# this method returns all revisions from one single SCM-Entry
def entry(path=nil, identifier="HEAD")
e = entries(path, identifier)
logger.debug("<cvs-result> #{e.first.inspect}") if e
e ? e.first : nil
end
# Returns an Entries collection
# or nil if the given path doesn't exist in the repository
@@ -72,7 +63,9 @@ module Redmine
logger.debug "<cvs> entries '#{path}' with identifier '#{identifier}'"
path_with_project="#{url}#{with_leading_slash(path)}"
entries = Entries.new
cmd = "#{CVS_BIN} -d #{root_url} rls -ed #{path_with_project}"
cmd = "#{CVS_BIN} -d #{root_url} rls -ed"
cmd << " -D \"#{time_to_cvstime(identifier)}\"" if identifier
cmd << " #{path_with_project}"
shellout(cmd) do |io|
io.each_line(){|line|
fields=line.chop.split('/',-1)

View File

@@ -40,20 +40,15 @@ module Redmine
rev ? Info.new({:root_url => @url, :lastrev => rev.last}) : 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)
e = entries(path, identifier)
e ? e.first : nil
end
# Returns an Entries collection
# or nil if the given path doesn't exist in the repository
def entries(path=nil, identifier=nil)
path_prefix = (path.blank? ? '' : "#{path}/")
path = '.' if path.blank?
entries = Entries.new
cmd = "#{DARCS_BIN} annotate --repodir #{@url} --xml-output #{path}"
cmd = "#{DARCS_BIN} annotate --repodir #{@url} --xml-output"
cmd << " --match \"hash #{identifier}\"" if identifier
cmd << " #{path}"
shellout(cmd) do |io|
begin
doc = REXML::Document.new(io)

View File

@@ -79,7 +79,7 @@ module Redmine
rev = Revision.new({:identifier => changeset[:commit],
:scmid => changeset[:commit],
:author => changeset[:author],
:time => Time.parse(changeset[:date]),
:time => (changeset[:date] ? Time.parse(changeset[:date]) : nil),
:message => changeset[:description],
:paths => files
})
@@ -132,14 +132,6 @@ module Redmine
entries.sort_by_name
end
def entry(path=nil, identifier=nil)
path ||= ''
search_path = path.split('/')[0..-2].join('/')
entry_name = path.split('/').last
e = entries(search_path, identifier)
e ? e.detect{|entry| entry.name == entry_name} : nil
end
def revisions(path, identifier_from, identifier_to, options={})
revisions = Revisions.new
cmd = "#{GIT_BIN} --git-dir #{target('')} log --raw "

View File

@@ -59,14 +59,6 @@ module Redmine
return nil if $? && $?.exitstatus != 0
entries.sort_by_name
end
def entry(path=nil, identifier=nil)
path ||= ''
search_path = path.split('/')[0..-2].join('/')
entry_name = path.split('/').last
e = entries(search_path, identifier)
e ? e.detect{|entry| entry.name == entry_name} : nil
end
def revisions(path=nil, identifier_from=nil, identifier_to=nil, options={})
revisions = Revisions.new
@@ -88,13 +80,7 @@ module Redmine
value = $2
if parsing_descr && line_feeds > 1
parsing_descr = false
revisions << Revision.new({:identifier => changeset[:changeset].split(':').first.to_i,
:scmid => changeset[:changeset].split(':').last,
:author => changeset[:user],
:time => Time.parse(changeset[:date]),
:message => changeset[:description],
:paths => changeset[:files].to_s.split.collect{|path| {:action => 'X', :path => "/#{path}"}}
})
revisions << build_revision_from_changeset(changeset)
changeset = {}
end
if !parsing_descr
@@ -111,13 +97,8 @@ module Redmine
line_feeds += 1 if line.chomp.empty?
end
end
revisions << Revision.new({:identifier => changeset[:changeset].split(':').first.to_i,
:scmid => changeset[:changeset].split(':').last,
:author => changeset[:user],
:time => Time.parse(changeset[:date]),
:message => changeset[:description],
:paths => changeset[:files].to_s.split.collect{|path| {:action => 'X', :path => "/#{path}"}}
})
# Add the last changeset if there is one left
revisions << build_revision_from_changeset(changeset) if changeset[:date]
end
return nil if $? && $?.exitstatus != 0
revisions
@@ -171,6 +152,47 @@ module Redmine
return nil if $? && $?.exitstatus != 0
blame
end
private
# Builds a revision objet from the changeset returned by hg command
def build_revision_from_changeset(changeset)
rev_id = changeset[:changeset].to_s.split(':').first.to_i
# Changes
paths = (rev_id == 0) ?
# Can't get changes for revision 0 with hg status
changeset[:files].to_s.split.collect{|path| {:action => 'A', :path => "/#{path}"}} :
status(rev_id)
Revision.new({:identifier => rev_id,
:scmid => changeset[:changeset].to_s.split(':').last,
:author => changeset[:user],
:time => Time.parse(changeset[:date]),
:message => changeset[:description],
:paths => paths
})
end
# Returns the file changes for a given revision
def status(rev_id)
cmd = "#{HG_BIN} -R #{target('')} status --rev #{rev_id.to_i - 1}:#{rev_id.to_i}"
result = []
shellout(cmd) do |io|
io.each_line do |line|
action, file = line.chomp.split
next unless action && file
file.gsub!("\\", "/")
case action
when 'R'
result << { :action => 'D' , :path => "/#{file}" }
else
result << { :action => action, :path => "/#{file}" }
end
end
end
result
end
end
end
end

View File

@@ -51,18 +51,11 @@ module Redmine
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)
e = entries(path, identifier)
e ? e.first : nil
end
# Returns an Entries collection
# or nil if the given path doesn't exist in the repository
def entries(path=nil, identifier=nil)
path ||= ''
identifier = 'HEAD' unless identifier and identifier > 0
identifier = (identifier and identifier.to_i > 0) ? identifier.to_i : "HEAD"
entries = Entries.new
cmd = "#{SVN_BIN} list --xml #{target(path)}@#{identifier}"
cmd << credentials_string
@@ -94,8 +87,8 @@ module Redmine
def revisions(path=nil, identifier_from=nil, identifier_to=nil, options={})
path ||= ''
identifier_from = 'HEAD' unless identifier_from and identifier_from.to_i > 0
identifier_to = 1 unless identifier_to and identifier_to.to_i > 0
identifier_from = (identifier_from and identifier_from.to_i > 0) ? identifier_from.to_i : "HEAD"
identifier_to = (identifier_to and identifier_to.to_i > 0) ? identifier_to.to_i : 1
revisions = Revisions.new
cmd = "#{SVN_BIN} log --xml -r #{identifier_from}:#{identifier_to}"
cmd << credentials_string
@@ -131,11 +124,9 @@ module Redmine
def diff(path, identifier_from, identifier_to=nil, type="inline")
path ||= ''
if identifier_to and identifier_to.to_i > 0
identifier_to = identifier_to.to_i
else
identifier_to = identifier_from.to_i - 1
end
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 = "#{SVN_BIN} diff -r "
cmd << "#{identifier_to}:"
cmd << "#{identifier_from}"

View File

@@ -4,7 +4,7 @@ module Redmine
module VERSION #:nodoc:
MAJOR = 0
MINOR = 7
TINY = 'devel'
TINY = 1
def self.revision
revision = nil

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