From 8c669eeb80c2371d76224b4678f5f8e494946cdc Mon Sep 17 00:00:00 2001 From: Nicolas Chuche Date: Sat, 14 Feb 2009 12:06:45 +0000 Subject: [PATCH] r18658@gaspard (orig r1900): jplang | 2008-09-22 21:50:10 +0200 Truncate comments on changeset list. r18659@gaspard (orig r1901): jplang | 2008-09-23 19:03:51 +0200 Fixes html escaping. r18660@gaspard (orig r1902): winterheart | 2008-09-24 16:45:20 +0200 Patch #1938, update for nl.yml r18661@gaspard (orig r1903): jplang | 2008-09-24 19:30:36 +0200 Fixes back_url in login filter (#1900). r18662@gaspard (orig r1904): jplang | 2008-09-24 19:32:49 +0200 Reverts r1903. r18663@gaspard (orig r1905): jplang | 2008-09-24 19:33:02 +0200 Fixes back_url in login filter (#1900). r18667@gaspard (orig r1907): jplang | 2008-09-25 20:51:03 +0200 Fixed: cross-project issue list should not show issues of projects for which the issue tracking module was disabled. r18669@gaspard (orig r1909): winterheart | 2008-09-27 21:06:48 +0200 Fixed #1961, pt-br update r18670@gaspard (orig r1910): jplang | 2008-09-28 09:54:41 +0200 Fixed: Latest news appear on the homepage for projects with the News module disabled (#1941). r18671@gaspard (orig r1911): jplang | 2008-09-28 10:05:55 +0200 Fixed: the default status is lost when reordering issue statuses (#1955). r18672@gaspard (orig r1912): jplang | 2008-09-28 10:19:25 +0200 Wrap 'Assigned to' column on the issue list (#1960). r18673@gaspard (orig r1913): jplang | 2008-09-28 10:41:17 +0200 Fixed: Status list on bulk edit form does not follow normal sequence (#1956). r18674@gaspard (orig r1914): jplang | 2008-09-28 14:03:17 +0200 Adds a workflow overview screen. Workflow setup moved to a dedicated controller. r18675@gaspard (orig r1915): jplang | 2008-09-28 14:20:47 +0200 Fixes workflow setup link on trackers list (follows r1914). r18676@gaspard (orig r1916): jplang | 2008-09-28 14:36:30 +0200 Slight changes to the workflow setup screen. r18677@gaspard (orig r1917): jplang | 2008-09-28 15:10:00 +0200 Fixes Workflow.count_by_tracker_and_role. r18678@gaspard (orig r1918): edavis10 | 2008-09-30 01:55:11 +0200 Slight non-code change MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit r18679@gaspard (orig r1919): edavis10 | 2008-09-30 01:56:35 +0200 Reverting slight non-code change r18680@gaspard (orig r1920): edavis10 | 2008-09-30 02:02:46 +0200 Slight non-code change to test git sync r18681@gaspard (orig r1921): edavis10 | 2008-09-30 07:18:50 +0200 Adds :view_layouts_base_body_bottom hook r18682@gaspard (orig r1922): edavis10 | 2008-10-02 04:40:29 +0200 Fixed a failing assertion in test_post_edit_with_attachment_only that would occur when running the full test suite but not the functional test suite. r18683@gaspard (orig r1923): edavis10 | 2008-10-02 05:23:35 +0200 Added tests to cover IssueStatus.destroy and IssueStatus.check_integrity r18684@gaspard (orig r1924): jplang | 2008-10-04 19:38:31 +0200 Escape image filename regexp (#1971). r18685@gaspard (orig r1925): winterheart | 2008-10-05 21:30:58 +0200 #1988, update for ko.yml r18686@gaspard (orig r1926): winterheart | 2008-10-05 22:40:25 +0200 Patch #1987, ca.yml update, thanks to Joan Duran for file r18687@gaspard (orig r1927): winterheart | 2008-10-06 17:00:56 +0200 #1992 update pt.yml, thanks to Pedro Araújo r18688@gaspard (orig r1928): winterheart | 2008-10-07 19:41:16 +0200 Patch #2001, update for Polish language r18689@gaspard (orig r1929): winterheart | 2008-10-11 13:32:30 +0200 Patch #2005, nl.yml update r18690@gaspard (orig r1930): jplang | 2008-10-12 21:13:36 +0200 Remove pre tag attributes. r18691@gaspard (orig r1931): nbc | 2008-10-16 00:30:57 +0200 bugfix to two failed tests r18692@gaspard (orig r1932): nbc | 2008-10-16 01:50:33 +0200 add plain text option for mail #2029 r18693@gaspard (orig r1933): jplang | 2008-10-16 21:13:43 +0200 Makes email address case-insensitive in MailHandler (#2032). r18694@gaspard (orig r1934): winterheart | 2008-10-16 22:50:50 +0200 #2036 update for hu.yml r18695@gaspard (orig r1935): winterheart | 2008-10-16 22:51:27 +0200 Update for ru.yml r18696@gaspard (orig r1936): edavis10 | 2008-10-18 01:30:37 +0200 Added a plugin hook :routes that plugins can use to add and even override routes r18697@gaspard (orig r1937): winterheart | 2008-10-18 12:03:50 +0200 #2043, #2044, #2046, translation updates r18698@gaspard (orig r1938): jplang | 2008-10-18 12:07:49 +0200 Adds 'Delete wiki pages attachments' permission. r18699@gaspard (orig r1939): jplang | 2008-10-18 12:18:21 +0200 Show the most recent file when displaying an inline image. r18700@gaspard (orig r1940): jplang | 2008-10-18 12:42:29 +0200 link_to project homepage instead of auto_link (#1937). r18701@gaspard (orig r1941): jplang | 2008-10-18 13:25:27 +0200 Fixed: textile footnotes no longer work after r1113 (#974). r18702@gaspard (orig r1942): winterheart | 2008-10-23 17:24:16 +0200 #1928 it.yml update r18703@gaspard (orig r1943): jplang | 2008-10-24 17:24:35 +0200 Makes permission screens localized (#2070). r18704@gaspard (orig r1944): jplang | 2008-10-24 17:39:40 +0200 AuthSource list: display associated users count and disable 'Delete' buton if any (#2041). r18705@gaspard (orig r1945): jplang | 2008-10-24 18:59:15 +0200 Adds the ability to search for a user on the administration users list. r18706@gaspard (orig r1946): jplang | 2008-10-24 19:01:42 +0200 Adds functional test for user search. r18707@gaspard (orig r1947): jplang | 2008-10-24 19:12:39 +0200 Adds the ability to search for a project name or identifier on the administration projects list. r18708@gaspard (orig r1948): edavis10 | 2008-10-25 06:21:57 +0200 Added hook :view_repositories_show_contextual to allow adding items to the repository's contextual menu. #2073 r18709@gaspard (orig r1949): edavis10 | 2008-10-25 06:37:31 +0200 Renamed the .rb files in the plugin_generator to end in .erb. The .rb was causing rdoc to try to document them and fail. * Updated the generator's manifest to use the new files * Renamed template README to README.rdoc #2011 r18710@gaspard (orig r1950): edavis10 | 2008-10-25 06:46:21 +0200 Added the board's description below the board's name. Thanks to Go MAEDA for the patch. #2079 r18711@gaspard (orig r1951): jplang | 2008-10-25 11:35:51 +0200 Renames template ruby files to erb. r18712@gaspard (orig r1952): jplang | 2008-10-25 11:55:31 +0200 Adds #delete_menu_item to the plugin API (#2087). r18713@gaspard (orig r1953): jplang | 2008-10-25 12:23:29 +0200 Check that git changeset is not in the database before creating it (#1419). r18714@gaspard (orig r1954): jplang | 2008-10-26 16:17:26 +0100 Slight change to english string (#2088). r18715@gaspard (orig r1955): jplang | 2008-10-27 12:08:29 +0100 Makes wiki text formatter pluggable. Original patch #2025 by Yuki Sonoda slightly edited. r18716@gaspard (orig r1956): jplang | 2008-10-27 12:50:23 +0100 Adds back textile acronyms support (#2077). r18717@gaspard (orig r1957): jplang | 2008-10-27 13:34:01 +0100 Makes GLoc language global. r18718@gaspard (orig r1958): jplang | 2008-10-28 11:43:34 +0100 Fixed: Inline images don't work if file name has upper case letters or if image is in BMP format (#2102). r18719@gaspard (orig r1959): winterheart | 2008-10-28 17:08:19 +0100 #2080, #2097, #2100 - ja, zh-tw, zh updates r18720@gaspard (orig r1960): edavis10 | 2008-10-28 21:29:38 +0100 Added :view_timelog_edit_form_bottom hook to the timelog/edit form. r18721@gaspard (orig r1961): winterheart | 2008-10-29 00:31:14 +0100 Update for ru.yml r18722@gaspard (orig r1962): edavis10 | 2008-10-30 03:58:04 +0100 Gravatar support for issue detai, user grid, and activity stream r18723@gaspard (orig r1963): edavis10 | 2008-10-30 03:58:10 +0100 styling tweaks for gravatars r18724@gaspard (orig r1964): edavis10 | 2008-10-30 03:58:16 +0100 styling tweaks for gravatars r18725@gaspard (orig r1965): edavis10 | 2008-10-30 03:58:23 +0100 Reduced the size of the gravatar on the issue history r18726@gaspard (orig r1966): edavis10 | 2008-10-30 03:58:28 +0100 Fixed a bug with using gravatar on a nil value. r18727@gaspard (orig r1967): edavis10 | 2008-10-30 03:58:34 +0100 Added gravatar image to the user's public account page r18728@gaspard (orig r1968): edavis10 | 2008-10-30 04:29:30 +0100 Fixed typo in an English string, 'View calender' r18729@gaspard (orig r1969): edavis10 | 2008-10-30 04:49:04 +0100 Link the version name to VersionsController#show in the issue list. r18730@gaspard (orig r1970): edavis10 | 2008-10-31 01:09:36 +0100 Tweaking of the CSS for the gravatars. #1776 r18731@gaspard (orig r1971): edavis10 | 2008-10-31 01:19:48 +0100 Tighened up the gravator CSS in the issue div r18732@gaspard (orig r1972): edavis10 | 2008-10-31 01:41:28 +0100 Added an option to turn user Gravatars on or off * Option can be found in Administration > General, called "Use Gravatar user icons" * Defaulting Gravatars to off * Added a helper gravatar_for_mail to check the setting before rendering the Gravatar. #1776 r18733@gaspard (orig r1973): winterheart | 2008-10-31 15:38:09 +0100 Populating new string with rake gloc:update r18734@gaspard (orig r1974): winterheart | 2008-10-31 15:48:07 +0100 Update pt-rb, #2105 r18735@gaspard (orig r1975): winterheart | 2008-10-31 15:49:33 +0100 Update zh-tw, #2116 r18736@gaspard (orig r1976): winterheart | 2008-10-31 15:58:05 +0100 update ru.yml r18737@gaspard (orig r1977): winterheart | 2008-11-01 17:42:49 +0100 #2121, pt-br update r18738@gaspard (orig r1978): edavis10 | 2008-11-04 19:27:13 +0100 Added :view_projects_form plugin hook r18739@gaspard (orig r1979): edavis10 | 2008-11-06 06:37:29 +0100 Included Redmine::Hook::Helper to ActionController::Base so call_hook is available in all controllers. #2111 r18740@gaspard (orig r1980): winterheart | 2008-11-07 11:41:10 +0100 #2127, #2129, #2130, #2135, translation updates. Thanks to all participants :) r18741@gaspard (orig r1981): winterheart | 2008-11-07 11:53:09 +0100 Intial support Vietnamese language (#2125), thanks to Kỳ Anh Huỳnh for work r18742@gaspard (orig r1982): winterheart | 2008-11-07 12:07:25 +0100 Ooops, wrong. r18743@gaspard (orig r1983): winterheart | 2008-11-07 12:12:12 +0100 Intial support Vietnamese language (#2125), thanks to Kỳ Anh Huỳnh for work (now - really) r18744@gaspard (orig r1984): winterheart | 2008-11-07 12:20:25 +0100 refreshing vn.yml (#2125) r18745@gaspard (orig r1985): winterheart | 2008-11-07 12:22:26 +0100 D'oh... r18746@gaspard (orig r1986): winterheart | 2008-11-07 12:28:29 +0100 Update for pl.yml, #1299 r18747@gaspard (orig r1987): jplang | 2008-11-07 14:08:01 +0100 French translation update. r18748@gaspard (orig r1988): jplang | 2008-11-07 15:35:18 +0100 Email address should be lowercased for gravatar (#2145). r18749@gaspard (orig r1989): jplang | 2008-11-07 16:37:17 +0100 Host setting should contain the path prefix (Redmine base URL) to properly generate links in emails that are sent offline (#2122). r18750@gaspard (orig r1990): jplang | 2008-11-07 18:27:56 +0100 Fixed: broken subject when submitting issue via email written in japanese (Patch #2059 by Go MAEDA). r18751@gaspard (orig r1991): edavis10 | 2008-11-08 01:12:43 +0100 Removing the custom Redmine hook in routes in favor of Engine's hook. * Plugins' routes.rb are now added automatically to Redmine's routing, including the ability to override Redmine's default routing. Thank you to Jean-Baptiste Barth for the suggestion. #2142 r18752@gaspard (orig r1992): jplang | 2008-11-08 14:25:45 +0100 Do not use @:skip_relative_url_root@ to generate urls in Mailer (#2122). r18753@gaspard (orig r1993): jplang | 2008-11-08 16:18:02 +0100 Fixes syntax highlighting broken by r1930 (#2143). r18754@gaspard (orig r1994): jplang | 2008-11-08 16:28:00 +0100 Fixed Bazaar shared repository browsing (#2101, patch #1685 by Dmitry Shaposhnik). r18755@gaspard (orig r1995): jplang | 2008-11-08 16:50:51 +0100 Tells git to output dates in ISO format. Fixes: Git Adapter date parsing ignores timezone (#2149). r18756@gaspard (orig r1996): jplang | 2008-11-08 18:15:18 +0100 git path reverted. r18757@gaspard (orig r1997): winterheart | 2008-11-08 23:34:41 +0100 #2126, initial support of Slovak, thank to Stanislav Pach for translation r18758@gaspard (orig r1998): winterheart | 2008-11-09 01:29:20 +0100 populating new string, updates for ru.yml and sv.yml (#2126) r18759@gaspard (orig r1999): jplang | 2008-11-09 13:07:35 +0100 Git adapter: use commit time instead of author time (#2108). r18760@gaspard (orig r2000): jplang | 2008-11-09 15:52:16 +0100 Changes ApplicationHelper#gravatar_for_mail to #avatar that takes a User or a String (less code in views). r18761@gaspard (orig r2001): jplang | 2008-11-09 18:53:30 +0100 Fixes activity date param. r18762@gaspard (orig r2002): jplang | 2008-11-09 18:56:20 +0100 Link to activity view when displaying dates. r18763@gaspard (orig r2003): jplang | 2008-11-09 21:39:49 +0100 Hide Redmine version in atom feeds and pdf properties (#794). r18764@gaspard (orig r2004): jplang | 2008-11-10 12:33:04 +0100 Fixed: non-ASCII subversion path can't be displayed (patch #1993 by Chaoqun Zou). r18765@gaspard (orig r2005): jplang | 2008-11-10 13:23:54 +0100 Include GLoc in hook listener base class (#2112). r18766@gaspard (orig r2006): jplang | 2008-11-10 19:59:06 +0100 Maps repository users to Redmine users (#1383). Users with same username or email are automatically mapped. Mapping can be manually adjusted in repository settings. Multiple usernames can be mapped to the same Redmine user. r18767@gaspard (orig r2007): jplang | 2008-11-10 20:09:00 +0100 Eager-load users. r18768@gaspard (orig r2008): jplang | 2008-11-11 13:07:03 +0100 Fixes a typo in en.yml. r18769@gaspard (orig r2009): jplang | 2008-11-11 13:50:11 +0100 Eager-load users. r18770@gaspard (orig r2010): jplang | 2008-11-11 13:59:28 +0100 Sort users by their display names so that user dropdown lists are sorted alphabetically (#2015). r18771@gaspard (orig r2011): jplang | 2008-11-11 14:22:05 +0100 Trac importer improvements (patch #2050 by Karl Heinz Marbaise). r18772@gaspard (orig r2012): jplang | 2008-11-11 14:28:13 +0100 Fixed: Trac migration of ticket:123 or [ticket:34] do not work (#2053). r18773@gaspard (orig r2013): jplang | 2008-11-11 14:28:48 +0100 Fixed: Trac migration of ticket:123 or [ticket:34] do not work (#2053). r18774@gaspard (orig r2014): jplang | 2008-11-11 14:32:22 +0100 Fixed: Trac milestone links not correctly converted (#2052). r18775@gaspard (orig r2015): jplang | 2008-11-11 14:37:10 +0100 Documents Wiki page anchors (#1647). r18776@gaspard (orig r2016): jplang | 2008-11-11 14:49:07 +0100 Updated pt-br and zh-tw lang files. r18777@gaspard (orig r2017): jplang | 2008-11-11 14:54:10 +0100 Changes ruby bang path to #!/usr/bin/env ruby (#1876). r18778@gaspard (orig r2018): jplang | 2008-11-11 15:24:06 +0100 Turn ftps and sftp proto into links (#1514). r18779@gaspard (orig r2019): jplang | 2008-11-11 16:07:55 +0100 Adds permissions to let users edit and/or delete their messages (#854, patch by Markus Knittig with slight changes). r18780@gaspard (orig r2020): jplang | 2008-11-11 17:26:05 +0100 Less agressive Redcloth lang attribute parsing (#2091). r18781@gaspard (orig r2021): jplang | 2008-11-11 17:49:20 +0100 Hungarian language file updated. r18782@gaspard (orig r2022): jplang | 2008-11-11 19:10:21 +0100 Pluggable admin menu (patch #2031 by Yuki Sonoda with slight changes). r18783@gaspard (orig r2023): winterheart | 2008-11-12 16:13:49 +0100 update for pt-br (#2164) r18784@gaspard (orig r2024): winterheart | 2008-11-12 16:17:47 +0100 update for zh (#2151) r18785@gaspard (orig r2025): winterheart | 2008-11-12 16:18:55 +0100 Populating new strings for zh.yml r18786@gaspard (orig r2026): winterheart | 2008-11-12 16:22:57 +0100 New file for sk (#2126) r18787@gaspard (orig r2027): winterheart | 2008-11-12 16:23:52 +0100 Populating new strings for sk.yml r18788@gaspard (orig r2028): winterheart | 2008-11-12 16:34:11 +0100 update for ru r18789@gaspard (orig r2029): edavis10 | 2008-11-13 02:07:58 +0100 Changed the CSS clear on journals so they will wrap around the revisions. #2165 r18790@gaspard (orig r2030): jplang | 2008-11-13 17:39:50 +0100 Fixes #2171: issue pdf export broken by r2006. r18791@gaspard (orig r2031): jplang | 2008-11-13 17:43:39 +0100 Fixes #2170: user display format in application settings broken by r2010. r18792@gaspard (orig r2032): winterheart | 2008-11-14 16:00:23 +0100 Missed %s in label, thank Martin Bächtold for reporting (#2186) r18793@gaspard (orig r2033): winterheart | 2008-11-14 16:18:13 +0100 Translation updates (#2168, #2172, #2176, #2178) r18794@gaspard (orig r2034): winterheart | 2008-11-14 16:33:27 +0100 Polish update, #2188 r18795@gaspard (orig r2035): winterheart | 2008-11-15 09:35:17 +0100 Translation updates (#2189, #2193) r18796@gaspard (orig r2036): jplang | 2008-11-16 12:49:37 +0100 Changes version naming rule (#2162). r18797@gaspard (orig r2037): jplang | 2008-11-16 12:58:41 +0100 Moves plugin list to its own administration menu item. r18798@gaspard (orig r2038): jplang | 2008-11-16 16:22:48 +0100 Adds plugin id attribute. r18799@gaspard (orig r2039): jplang | 2008-11-16 16:38:37 +0100 Adds .find and .all Plugin class methods. r18800@gaspard (orig r2040): jplang | 2008-11-16 17:08:25 +0100 Adds a few Plugin tests. r18801@gaspard (orig r2041): jplang | 2008-11-16 18:12:02 +0100 Adds url and author_url plugin attributes (#2162). r18802@gaspard (orig r2042): jplang | 2008-11-16 21:00:20 +0100 Adds Plugin#requires_redmine method so that plugin compatibility can be checked against current Redmine version (#2162). r18803@gaspard (orig r2043): jplang | 2008-11-17 18:27:08 +0100 Do not query multiple times git for branch (#1435). r18804@gaspard (orig r2044): jplang | 2008-11-18 18:22:28 +0100 Vietnamese language updated (#2125). r18805@gaspard (orig r2045): jplang | 2008-11-18 19:36:47 +0100 SubversionAdapter#entries performance improvement. r18806@gaspard (orig r2046): jplang | 2008-11-18 22:11:25 +0100 Fixed: Printing long roadmap doesn't split across pages (#2203). r18807@gaspard (orig r2047): winterheart | 2008-11-19 16:52:09 +0100 Typo in sv, #2213 r18808@gaspard (orig r2048): jplang | 2008-11-19 20:38:19 +0100 Remove eclipse files r18811@gaspard (orig r2051): winterheart | 2008-11-21 17:35:00 +0100 fix for Polish, #2215 r18812@gaspard (orig r2052): winterheart | 2008-11-21 17:40:11 +0100 removing BOM, sorting, #2169 r18813@gaspard (orig r2053): jplang | 2008-11-22 12:44:07 +0100 Extends child_pages macro to display child pages based on page parameter (#1975). It can also be called from anywhere now (not only from wiki pages). r18814@gaspard (orig r2054): jplang | 2008-11-23 17:40:35 +0100 Fixed date filters accuracy with SQLite (#2221). r18815@gaspard (orig r2055): jplang | 2008-11-25 18:37:41 +0100 Slight tests fixes. r18816@gaspard (orig r2056): jplang | 2008-11-25 20:33:41 +0100 Do not request blank LDAP attributes. r18817@gaspard (orig r2057): winterheart | 2008-11-26 18:32:56 +0100 rake gloc:update, update for Serbian (#2232) r18819@gaspard (orig r2059): jplang | 2008-11-27 19:04:48 +0100 Adds a css class on menu items in order to apply item specific styles (eg. icons). r18820@gaspard (orig r2060): jplang | 2008-11-27 19:41:40 +0100 Typo in lang files (#2241). r18821@gaspard (orig r2061): jplang | 2008-11-27 19:43:18 +0100 Typo in gloc:update task description (#2243). r18822@gaspard (orig r2062): jplang | 2008-11-27 21:15:45 +0100 Fixed: inappropriate redirection to login or register page may occur (#2206). Eg. user clicks login link twice before logging in. r18823@gaspard (orig r2063): winterheart | 2008-11-28 16:44:59 +0100 Italian update (#2239) r18826@gaspard (orig r2066): jplang | 2008-11-30 12:18:22 +0100 Display latest user's activity on account/show view. r18827@gaspard (orig r2067): jplang | 2008-11-30 13:12:06 +0100 Makes activity view accept a user_id param to show user's activity (#1002). r18828@gaspard (orig r2068): jplang | 2008-11-30 13:14:12 +0100 Fixes activity atom link params (when not on first page). r18829@gaspard (orig r2069): jplang | 2008-11-30 13:18:59 +0100 Adds atom feed on user's account page. r18830@gaspard (orig r2070): jplang | 2008-11-30 14:38:07 +0100 Adds links between account and user's activity pages. r18831@gaspard (orig r2071): jplang | 2008-11-30 14:42:15 +0100 Slight changes to profile on account page and last connexion date added. r18832@gaspard (orig r2072): jplang | 2008-11-30 15:23:57 +0100 Obfuscates email address on user's account page using javascript. r18833@gaspard (orig r2073): jplang | 2008-11-30 15:31:01 +0100 Adds link to user's account on issue history. r18834@gaspard (orig r2074): jplang | 2008-11-30 15:55:45 +0100 Mail handler: check workflow for status set/change. r18835@gaspard (orig r2075): jplang | 2008-11-30 15:57:46 +0100 Adds status option to email integration rake tasks. r18836@gaspard (orig r2076): jplang | 2008-11-30 16:51:44 +0100 Adds --status option to rdm-mailhandler. r18837@gaspard (orig r2077): jplang | 2008-11-30 17:00:45 +0100 Adds To and Cc as watchers when submitting an issue by email (#2245). Only works if the sender has the 'Add issue watchers' permission. r18838@gaspard (orig r2078): jplang | 2008-11-30 17:34:39 +0100 Changes Portuguese decimal separator (#1372). r18839@gaspard (orig r2079): jplang | 2008-11-30 17:57:56 +0100 Replaces User.find_active with a named scope. r18840@gaspard (orig r2080): winterheart | 2008-12-01 17:00:54 +0100 Translation updates (#2249, #2250, #2252, #2254) r18841@gaspard (orig r2081): winterheart | 2008-12-01 17:11:05 +0100 ru.yml update r18842@gaspard (orig r2082): jplang | 2008-12-01 18:27:44 +0100 Fixed: 404 when "Apply" clicked on activity page (#2251). r18843@gaspard (orig r2083): jplang | 2008-12-02 18:16:06 +0100 Fixed: activity broken by r2066 with postgresql (#2266). r18844@gaspard (orig r2084): jplang | 2008-12-02 18:29:52 +0100 Use style attribute for setting width of table cells in progress bars (#2267). r18845@gaspard (orig r2085): jplang | 2008-12-02 18:57:13 +0100 Fixed: wrong digest for text files under Windows (#2264). r18846@gaspard (orig r2086): edavis10 | 2008-12-04 00:18:07 +0100 Added :controller_issues_edit_before_save hook r18847@gaspard (orig r2087): edavis10 | 2008-12-04 00:18:12 +0100 Added :view_issues_edit_notes_bottom hook r18848@gaspard (orig r2088): jplang | 2008-12-05 16:41:32 +0100 Cross-project gantt and calendar (#1157). r18849@gaspard (orig r2089): edavis10 | 2008-12-05 22:03:55 +0100 Added :view_issues_history_journal_bottom hook r18850@gaspard (orig r2090): edavis10 | 2008-12-05 23:56:03 +0100 Refactor: Extracted new method Query#sql_for_field from Query#statement in order to clean up Query#statement. r18851@gaspard (orig r2091): edavis10 | 2008-12-05 23:56:08 +0100 Bit more refactoring on Query#sql_for_field to remove multiple returns r18852@gaspard (orig r2092): edavis10 | 2008-12-05 23:56:13 +0100 Final refactoring on Query#sql_for_field to rename v to value r18853@gaspard (orig r2093): edavis10 | 2008-12-06 01:51:03 +0100 Added several useful hooks to the Issue sidebar * :view_issues_sidebar_issues_bottom * :view_issues_sidebar_planning_bottom * :view_issues_sidebar_queries_bottom r18854@gaspard (orig r2094): jplang | 2008-12-06 12:21:10 +0100 Changes issue history headings. r18855@gaspard (orig r2095): jplang | 2008-12-06 18:20:37 +0100 Fixes Darcs#cat with Postgresql. r18856@gaspard (orig r2096): jplang | 2008-12-06 18:40:54 +0100 Fixed: CVS connexion string may not contain @. r18857@gaspard (orig r2097): jplang | 2008-12-06 19:01:20 +0100 Slight change to css so that gravatar is vertically centered on user's page. r18858@gaspard (orig r2098): jplang | 2008-12-06 23:40:50 +0100 Translations updates. r18860@gaspard (orig r2100): jplang | 2008-12-07 09:41:54 +0100 Changelog updated. r18861@gaspard (orig r2101): jplang | 2008-12-07 09:48:29 +0100 Show project name in front of related issues if cross-project issue relations are enabled (#2282). r18862@gaspard (orig r2102): jplang | 2008-12-07 10:53:27 +0100 Upgrade to Rails 2.1.2 r18863@gaspard (orig r2103): jplang | 2008-12-07 10:54:37 +0100 Set version to 0.8 r18864@gaspard (orig r2104): jplang | 2008-12-07 10:56:28 +0100 Update changelog for 0.8 rc1 r18865@gaspard (orig r2105): jplang | 2008-12-07 10:59:19 +0100 UPGRADING updated r18869@gaspard (orig r2109): jplang | 2008-12-07 14:12:19 +0100 Makes logged-in username in topbar linking to (#2291). r18870@gaspard (orig r2110): jplang | 2008-12-07 15:40:33 +0100 Use options hash in UnifiedDiff.new r18871@gaspard (orig r2111): jplang | 2008-12-07 15:44:08 +0100 Follows r2110. r18872@gaspard (orig r2112): jplang | 2008-12-07 16:21:40 +0100 Adds a setting to limit the number of diff lines that should be displayed (default to 1500). r18874@gaspard (orig r2114): jplang | 2008-12-08 19:20:26 +0100 Fixed: project activity truncated after viewing user's activity. r18876@gaspard (orig r2116): jplang | 2008-12-09 17:54:46 +0100 AttachmentsController now handles attachments deletion. r18877@gaspard (orig r2117): jplang | 2008-12-09 19:00:27 +0100 Files module: makes version field non required (#1053). r18878@gaspard (orig r2118): jplang | 2008-12-09 19:30:22 +0100 Fixed: Firefox cuts off large diffs (#2234). r18879@gaspard (orig r2119): winterheart | 2008-12-10 18:01:39 +0100 Translation updates (#2310, #2309, #2306, #2304, #2302, #2300, #2299) r18880@gaspard (orig r2120): winterheart | 2008-12-10 18:13:04 +0100 russian update r18881@gaspard (orig r2121): edavis10 | 2008-12-11 00:44:22 +0100 Added plugin hooks around Journal editing * :controller_journals_edit_post * :view_journals_notes_form_after_notes * :view_journals_update_rjs_bottom r18882@gaspard (orig r2122): jplang | 2008-12-12 13:07:09 +0100 Makes User.find_by_mail case-insensitive (password reminder #2322, repo users mapping). r18883@gaspard (orig r2123): jplang | 2008-12-12 14:32:39 +0100 Fixed: default flag removed when editing a default enumeration (#2327). r18884@gaspard (orig r2124): jplang | 2008-12-12 14:49:14 +0100 Fixed: default category ignored when adding a document (#2328). r18885@gaspard (orig r2125): jplang | 2008-12-12 17:01:35 +0100 Escape back_url field value (#2320). r18886@gaspard (orig r2126): jplang | 2008-12-12 17:03:57 +0100 Rescue back_url param parsing on redirect. r18887@gaspard (orig r2127): jplang | 2008-12-12 17:04:54 +0100 Undo unwanted change. r18888@gaspard (orig r2128): jplang | 2008-12-12 17:07:14 +0100 Capture scm CLI stderr to log/scm.stderr.log when running in dev environment r18889@gaspard (orig r2129): jplang | 2008-12-12 20:11:16 +0100 Make use of User.find_by_mail r18890@gaspard (orig r2130): winterheart | 2008-12-12 20:34:31 +0100 translation updates r18891@gaspard (orig r2131): winterheart | 2008-12-12 20:41:12 +0100 Fixing quotes r18894@gaspard (orig r2134): jplang | 2008-12-14 16:36:59 +0100 Rails 2.1.2 deprecations (#2332). r18895@gaspard (orig r2135): jplang | 2008-12-14 16:57:13 +0100 Fixed: CVS browser should not show dead revisions (deleted files) (#2319). r18896@gaspard (orig r2136): jplang | 2008-12-14 18:10:16 +0100 Mail handler: strip tags when receiving a html-only email (#2312). r18897@gaspard (orig r2137): jplang | 2008-12-15 19:02:25 +0100 Fixes repository user mapping submission when a repository username is blank (#2339, Conflicting types for parameter containers). r18899@gaspard (orig r2139): jplang | 2008-12-16 22:11:37 +0100 Adds a helper that returns issues css classes. r18900@gaspard (orig r2140): jplang | 2008-12-16 22:13:35 +0100 Adds a css class (overdue) to overdue issues on issue lists and detail views (#2337). r18901@gaspard (orig r2141): edavis10 | 2008-12-18 08:10:23 +0100 Fixed a failing test caused by comparing a Time object (n.day.ago) with a Date object r18902@gaspard (orig r2142): winterheart | 2008-12-18 23:27:32 +0100 Typo on translation, #2352 r18903@gaspard (orig r2143): jplang | 2008-12-19 09:10:35 +0100 Escape textarea content when editing a issue note. r18904@gaspard (orig r2144): jplang | 2008-12-19 11:16:15 +0100 Escape double-quotes in image titles. r18905@gaspard (orig r2145): jplang | 2008-12-19 11:43:06 +0100 Check that wiki page exists before processing (#2360). r18907@gaspard (orig r2147): jplang | 2008-12-19 15:13:24 +0100 CHANGELOG updated. r18924@gaspard (orig r2164): jplang | 2008-12-22 20:21:02 +0100 Adds watchers selection on new issue form (#398). Permission 'add issue watchers' required. r18925@gaspard (orig r2165): jplang | 2008-12-22 20:24:17 +0100 Do not hardcode Watcher string in r2164. r18926@gaspard (orig r2166): jplang | 2008-12-22 20:25:07 +0100 Sligth change to fr.yml. r18927@gaspard (orig r2167): jplang | 2008-12-22 21:33:01 +0100 Show view/annotate/download links on repositories/entries and repositories/annotate views (#2367). r18928@gaspard (orig r2168): jplang | 2008-12-23 01:16:26 +0100 Escape wiki annotate lines content (#2380). r18929@gaspard (orig r2169): jplang | 2008-12-23 01:19:15 +0100 Escape query names (#2379). r18930@gaspard (orig r2170): jplang | 2008-12-23 18:05:38 +0100 Escape textile titles and styles (#2377). r18931@gaspard (orig r2171): jplang | 2008-12-24 11:03:13 +0100 Validates sort_key and sort_order params (#2378). r18938@gaspard (orig r2178): jplang | 2008-12-24 14:29:43 +0100 Fixes a JS error on context_menu with IE (#2390). r18940@gaspard (orig r2180): winterheart | 2008-12-24 16:44:43 +0100 #2329, swedish lang update r18941@gaspard (orig r2181): winterheart | 2008-12-24 16:47:24 +0100 #2368, pt.yml update r18942@gaspard (orig r2182): winterheart | 2008-12-24 16:48:59 +0100 #2386, korean translation update r18943@gaspard (orig r2183): jplang | 2008-12-27 15:05:03 +0100 Prevent SQL error with old sessions after r2171. r18946@gaspard (orig r2186): jplang | 2008-12-27 18:49:01 +0100 Fixtures update. r18947@gaspard (orig r2187): jplang | 2008-12-27 19:07:46 +0100 Fixes functional test failures. r18948@gaspard (orig r2188): jplang | 2008-12-27 19:10:36 +0100 Do not show a link to the current annotate or view page (#2367). r18949@gaspard (orig r2189): jplang | 2008-12-27 19:33:35 +0100 Fixed: deleted files should not be shown when browsing a Darcs repository (#2385). r18950@gaspard (orig r2190): jplang | 2008-12-28 10:46:16 +0100 Fixes functional tests fixtures (#2398). r18951@gaspard (orig r2191): jplang | 2008-12-28 11:12:09 +0100 Fixed bold syntax around single character in series (#2351). r18952@gaspard (orig r2192): jplang | 2008-12-28 14:38:34 +0100 Disable textile inline styles to prevent XSS attacks (#2377). r18955@gaspard (orig r2195): jplang | 2008-12-28 15:48:23 +0100 Mail handler: add watchers before sending notification (#2245). r18956@gaspard (orig r2196): jplang | 2008-12-29 13:40:56 +0100 Renumbers projects_trackers fixtures (#2411). r18959@gaspard (orig r2199): jplang | 2008-12-29 16:43:42 +0100 Translations updates. r18961@gaspard (orig r2201): jplang | 2008-12-29 17:08:31 +0100 CHANGELOG updated. r18962@gaspard (orig r2202): winterheart | 2008-12-29 19:27:27 +0100 #2373, fixing encoding r18968@gaspard (orig r2208): jplang | 2008-12-30 14:32:14 +0100 CHANGELOG updated. r18969@gaspard (orig r2209): jplang | 2008-12-30 14:32:51 +0100 Increment project files downloads. r18970@gaspard (orig r2210): jplang | 2008-12-30 15:24:51 +0100 Jump to the current tab when using the project quick-jump combo (#2364). r18971@gaspard (orig r2211): jplang | 2008-12-30 15:57:33 +0100 Import custom fields values from emails (#2413). r18972@gaspard (orig r2212): jplang | 2008-12-30 17:23:05 +0100 Stricter textile links parsing (#2417). r18973@gaspard (orig r2213): jplang | 2008-12-30 17:43:26 +0100 Changes pt-br decimal separator (#1372). r18974@gaspard (orig r2214): jplang | 2008-12-31 11:39:33 +0100 Do not escape back_url twice when login fails. r18978@gaspard (orig r2218): jplang | 2008-12-31 12:48:56 +0100 Admin Info Screen: Display if plugin assets directory is writable (#2425). r18979@gaspard (orig r2219): jplang | 2008-12-31 14:59:30 +0100 Fix sv lang file r18980@gaspard (orig r2220): jplang | 2008-12-31 15:56:30 +0100 IMAP: add options to move received emails. r18981@gaspard (orig r2221): jplang | 2009-01-03 14:09:36 +0100 Lower the project identifier limit to a minimum of two characters (#2003). r18982@gaspard (orig r2222): jplang | 2009-01-03 14:14:28 +0100 Fixed: syntax highlight doesn't appear in new ticket preview (#1976). r18983@gaspard (orig r2223): jplang | 2009-01-03 15:11:44 +0100 Moves flash messages rendering to a helper method. r18984@gaspard (orig r2224): jplang | 2009-01-03 15:44:12 +0100 Display a warning if some attachments were not saved (#2008). r18985@gaspard (orig r2225): jplang | 2009-01-03 17:03:12 +0100 Fixed: email notification for changes I make still occurs when running Repository.fetch_changesets (#1957). r18986@gaspard (orig r2226): jplang | 2009-01-04 13:03:39 +0100 Move PDF stuff to a single helper. r18987@gaspard (orig r2227): jplang | 2009-01-04 13:14:05 +0100 Makes the app boot with Rails 2.2.2 r18988@gaspard (orig r2228): jplang | 2009-01-04 13:50:45 +0100 Do not use compute_public_path. r18992@gaspard (orig r2232): jplang | 2009-01-04 14:27:48 +0100 Merged r2231 from 0.8-stable (#2402). r18993@gaspard (orig r2233): jplang | 2009-01-04 15:54:19 +0100 Scramble PDF title (#1204). r18994@gaspard (orig r2234): jplang | 2009-01-04 18:09:25 +0100 Slight changes to ease Rails 2.2 support. r18995@gaspard (orig r2235): jplang | 2009-01-04 19:14:51 +0100 Slight changes in functional tests. r19006@gaspard (orig r2246): jplang | 2009-01-07 20:47:24 +0100 Makes issue description a non-required field (#2456). r19007@gaspard (orig r2247): jplang | 2009-01-07 21:03:33 +0100 Refactor TabularFormBuilder field helpers (#2461). r19008@gaspard (orig r2248): jplang | 2009-01-07 21:21:27 +0100 Fixes functional test broken by r2246. r19009@gaspard (orig r2249): jplang | 2009-01-07 21:22:06 +0100 Fixes a test failure with svn < 1.5 (#2455). r19010@gaspard (orig r2250): jplang | 2009-01-07 21:30:02 +0100 Adds 'closed' css class to closed issues in the issue list (#2458). r19011@gaspard (orig r2251): jplang | 2009-01-09 18:32:46 +0100 Fixed: no error is raised when entering invalid hours on the issue update form (#2465). r19013@gaspard (orig r2253): jplang | 2009-01-10 12:29:35 +0100 Makes email adress uniqueness case-insensitive (#2473). r19016@gaspard (orig r2256): jplang | 2009-01-11 12:01:35 +0100 Different icon for closed issues in search result (#992). r19017@gaspard (orig r2257): jplang | 2009-01-11 17:33:51 +0100 Ability to sort the issue list by text, list, date and boolean custom fields (#1139). r19018@gaspard (orig r2258): jplang | 2009-01-11 19:38:07 +0100 Ability to sort the issue list by text, int and float custom fields (#1139). r19019@gaspard (orig r2259): jplang | 2009-01-11 20:48:16 +0100 Use margin-right instead of padding-right on top menu links. r19020@gaspard (orig r2260): edavis10 | 2009-01-12 05:44:01 +0100 Codified instructions from RUNNING_TESTS as rake tasks for convenience Rake tasks are in testing.rake and can be run by `rake test:scm:setup:` Updated RUNNING_TESTS Contributed by Gerrit Kaiser r19021@gaspard (orig r2261): edavis10 | 2009-01-12 05:52:56 +0100 Added two new plugin hooks to IssuesController: * :controller_issues_new_after_save * :controller_issues_edit_after_save #2475 r19022@gaspard (orig r2262): jplang | 2009-01-12 18:45:23 +0100 Fixes r2226: exporting an issue with attachments to PDF raises an error (#2492). r19023@gaspard (orig r2263): jplang | 2009-01-12 18:46:53 +0100 Typo (#2489). r19025@gaspard (orig r2265): jplang | 2009-01-16 18:20:41 +0100 Adds a 'Create and continue' button on the new issue form, that will create the issue and display the form again (#2523). r19026@gaspard (orig r2266): jplang | 2009-01-16 21:57:18 +0100 Makes subject field get focus on 'New issue' form (#2522). r19027@gaspard (orig r2267): jplang | 2009-01-16 22:02:03 +0100 Use a textarea for custom fields possible values (#2472). r19028@gaspard (orig r2268): jplang | 2009-01-16 22:02:56 +0100 Adds custom fields functional tests. r19029@gaspard (orig r2269): jplang | 2009-01-17 08:53:32 +0100 Slight visual changes on the issue form. r19030@gaspard (orig r2270): jplang | 2009-01-17 09:03:53 +0100 Do not show Category field when categories are not defined. r19031@gaspard (orig r2271): jplang | 2009-01-17 09:08:33 +0100 Project jump box fix. r19032@gaspard (orig r2272): jplang | 2009-01-17 09:25:55 +0100 Make use of tracker_ids association in issue custom field form. r19033@gaspard (orig r2273): jplang | 2009-01-17 09:41:30 +0100 CustomFieldsController refactoring. r19034@gaspard (orig r2274): jplang | 2009-01-17 09:46:23 +0100 CustomFieldsController#list moved to #index. r19035@gaspard (orig r2275): jplang | 2009-01-17 10:04:10 +0100 Moves a few settings to a "Display" panel. r19036@gaspard (orig r2276): jplang | 2009-01-17 12:18:04 +0100 User custom fields can now be set as editable so that users can edit them on 'My account'. For existing user custom fields, this new attribute is set to false by default to preserve the prior behaviour (it can turned on by editing the custom field in admin area). Note: on the registration form, *required* custom fields will be displayed even if they are not defined as editable so that the account can be created. r19039@gaspard (orig r2279): jplang | 2009-01-18 11:54:08 +0100 Fixes 103_set_custom_fields_editable migration from r2276 (#2526). r19040@gaspard (orig r2280): jplang | 2009-01-18 12:54:56 +0100 Fixed that Trac importer was creating duplicate custom values (#2506). r19041@gaspard (orig r2281): jplang | 2009-01-18 16:16:31 +0100 Adds Message-Id and References headers to email notifications so that issues and messages threads can be displayed by email clients (#1401). r19042@gaspard (orig r2282): jplang | 2009-01-18 21:00:03 +0100 Fix in AttachmentsController#show. r19043@gaspard (orig r2283): winterheart | 2009-01-19 16:55:54 +0100 #2439, translation update r19044@gaspard (orig r2284): winterheart | 2009-01-19 16:57:19 +0100 #2442, translation update r19045@gaspard (orig r2285): winterheart | 2009-01-19 17:02:57 +0100 #2429, translation update r19046@gaspard (orig r2286): winterheart | 2009-01-19 17:06:39 +0100 #2442, small fix r19047@gaspard (orig r2287): winterheart | 2009-01-19 17:43:28 +0100 translation updates (#2535, #2505, #2524, #2434) r19048@gaspard (orig r2288): jplang | 2009-01-19 19:29:07 +0100 Use In-Reply-To and References headers to handle replies by email. r19049@gaspard (orig r2289): jplang | 2009-01-19 20:03:53 +0100 Allow email to reply to a forum message (#1616). r19050@gaspard (orig r2290): winterheart | 2009-01-20 16:45:34 +0100 #2453, sv.yml patch, some errors still exist (see ticket) r19051@gaspard (orig r2291): winterheart | 2009-01-20 16:53:09 +0100 #2445, nl.yml update r19052@gaspard (orig r2292): winterheart | 2009-01-20 17:09:07 +0100 #2463, partially solved r19053@gaspard (orig r2293): winterheart | 2009-01-20 17:13:14 +0100 #2540, pt-br update r19054@gaspard (orig r2294): jplang | 2009-01-21 19:22:30 +0100 Accept replies to forum messages by subject recognition (#1616). r19055@gaspard (orig r2295): jplang | 2009-01-22 17:34:54 +0100 Automatically focus several form fields. r19056@gaspard (orig r2296): winterheart | 2009-01-23 16:37:59 +0100 New Galician Translation (#2547), thanks to Martín Vázquez for intial translation r19057@gaspard (orig r2297): winterheart | 2009-01-23 16:40:38 +0100 #2562, update for zh.yml r19058@gaspard (orig r2298): winterheart | 2009-01-23 16:46:22 +0100 Translation updates (#2453, #2463, #2551) r19059@gaspard (orig r2299): winterheart | 2009-01-23 16:58:58 +0100 removing \r\n r19060@gaspard (orig r2300): winterheart | 2009-01-23 17:30:04 +0100 ru.yml update r19062@gaspard (orig r2302): jplang | 2009-01-24 09:58:03 +0100 Fixed: Details time log report CSV export doesn't honour date format from settings (patch #2466 by Russell Hind). r19063@gaspard (orig r2303): jplang | 2009-01-24 10:02:55 +0100 Fixes a test that was broken by r2294. r19064@gaspard (orig r2304): jplang | 2009-01-24 12:31:15 +0100 Merged nested projects branch. Removes limit on subproject nesting (#594). r19065@gaspard (orig r2305): jplang | 2009-01-24 12:48:38 +0100 Removes unused projects_count column from projects table. r19071@gaspard (orig r2311): jplang | 2009-01-25 12:15:28 +0100 Ignore archived subprojects in Project#rolled_up_trackers (#2550). r19072@gaspard (orig r2312): jplang | 2009-01-25 13:13:27 +0100 Fixed that the project jump box does not preserve current tab after r2304. r19073@gaspard (orig r2313): jplang | 2009-01-25 14:12:56 +0100 Adds ability to bulk copy issues (#1847). This can be done by checking the 'Copy' checkbox on the 'Move' form. r19074@gaspard (orig r2314): jplang | 2009-01-25 14:18:44 +0100 Removes spaces before colons. r19075@gaspard (orig r2315): jplang | 2009-01-25 14:52:40 +0100 Render the project list as a tree on Move form. r19076@gaspard (orig r2316): jplang | 2009-01-25 17:04:28 +0100 Ability to bulk edit custom fields of type 'list' (#461). r19077@gaspard (orig r2317): edavis10 | 2009-01-26 02:47:51 +0100 Converted routing and urls to follow the Rails REST convention. Patch supplied by commits from Gerrit Kaiser on Github. Existing routes will still work (backwards compatible) but any new urls will be generated using the new routing rules. Changes listed below: * made the URLs for some project tabs and project settings follow the new rails RESTful conventions of /collection/:id/subcollection/:sub_id * prettier URL for project roadmap * more nice project URLs * use GET for filtering form * prettified URLs used on issues tab * custom route for activity atom feeds * prettier repository urls * fixed broken route definition * fixed failing tests for issuecontroller that were hardcoding the url string * more RESTful routes for boards and messages * RESTful routes for wiki pages * RESTful routes for documents * moved old routes that are retained for compatibility to the bottom and grouped them together * added RESTful URIs for issues * RESTfulness for the news section * fixed route order * changed hardcoded URLs in tests * fixed badly written tests * fixed forgotten parameter in routes * changed hardcoded URLS to new scheme * changed project add url to the standard POST to collection * create new issue by POSTing to collection * changed hardcoded URLs in integrations tests * made project add form work again * restful routes for project deletion * prettier routes for project (un)archival * made routes table more readable * fixed note quoting * user routing * fixed bug * always sort by GET * Fixed: cross-project issue list should not show issues of projects for which the issue tracking module was disabled. * prettified URLs used on issues tab * urls for time log * fixed reply routing * eliminate revision query paremeter for diff and entry actions * fixed test failures with hard-coded urls * ensure ajax links always use get * refactored ajax link generation into separate method #1901 r19078@gaspard (orig r2318): jplang | 2009-01-26 18:43:58 +0100 Fixes activity pagination broken by r2317. r19079@gaspard (orig r2319): jplang | 2009-01-27 18:27:50 +0100 Replaces the obsolete robots.txt with a cached action (#2491). r19080@gaspard (orig r2320): jplang | 2009-01-27 18:40:55 +0100 Fixed actions on issues (gantt, calendar, move, bulk_edit...) at global level broken by r2317. r19081@gaspard (orig r2321): jplang | 2009-01-27 18:58:56 +0100 Explicitly require 'rfpdf/fpdf' (#2584). r19082@gaspard (orig r2322): jplang | 2009-01-27 19:19:27 +0100 Fixed that 'My page' blocks may display issues that the user is no longer allowed to view (#2590). r19083@gaspard (orig r2323): jplang | 2009-01-27 20:33:03 +0100 Fixed: users should not be able to add relations with issues they're not allowed to view (#2589). r19084@gaspard (orig r2324): edavis10 | 2009-01-27 21:42:19 +0100 Fixes Issue sorting in a project, broken by #2317 Issues were sorting but the project id wasn't being added so the IssuesController would return all issues (cross-project). r19085@gaspard (orig r2325): edavis10 | 2009-01-27 21:59:02 +0100 Fixed clearing the Issue filters in the issue list, broken by #2317 r19086@gaspard (orig r2326): jplang | 2009-01-28 21:52:39 +0100 Fixed user's activity atom feed broken by r2317. r19087@gaspard (orig r2327): jplang | 2009-01-28 22:11:13 +0100 Fixed calendar navigation links broken by r2317. r19088@gaspard (orig r2328): jplang | 2009-01-28 22:20:39 +0100 Fixing calendar and gantt links broken by r2317. r19089@gaspard (orig r2329): jplang | 2009-01-28 22:25:35 +0100 Fixed project news atom link broken by r2317. r19090@gaspard (orig r2330): jplang | 2009-01-29 10:05:36 +0100 Sort target versions list on bulk edit form (#2616). r19091@gaspard (orig r2331): jplang | 2009-01-29 12:09:46 +0100 Fixes other formats download links on the project issue list (project_id lost) broken r2317. r19092@gaspard (orig r2332): jplang | 2009-01-29 13:26:32 +0100 Fixed an error when downloading gantt png at global level. r19093@gaspard (orig r2333): jplang | 2009-01-29 14:53:17 +0100 Adds an helper to render other formats download links. r19094@gaspard (orig r2334): jplang | 2009-01-29 14:54:44 +0100 Adds rel='nofollow' attribute to other formats download links (#2491). r19095@gaspard (orig r2335): jplang | 2009-01-29 15:22:56 +0100 Adds projects association on tracker form (#2578). r19096@gaspard (orig r2336): jplang | 2009-01-29 17:33:45 +0100 Fixed: TOC does not parse wiki page reference links with description (#2601). r19097@gaspard (orig r2337): jplang | 2009-01-29 17:34:00 +0100 Cleaning test. r19098@gaspard (orig r2338): jplang | 2009-01-30 18:50:28 +0100 Changes time related icons. r19099@gaspard (orig r2339): jplang | 2009-01-31 12:43:54 +0100 Adds :async_smtp and :async_sendmail delivery methods to perform email deliveries asynchronously. Code from http://www.datanoise.com/articles/2006/7/14/asynchronous-email-delivery. r19100@gaspard (orig r2340): winterheart | 2009-01-31 13:02:37 +0100 New translation - Slovenian, thank to Nejc Vidmar for work (#2577), translation updates (#2129, #2586) r19101@gaspard (orig r2341): jplang | 2009-01-31 13:42:02 +0100 Updates footer year. r19102@gaspard (orig r2342): jplang | 2009-01-31 13:48:09 +0100 Removes Issue.visible_by r19103@gaspard (orig r2343): jplang | 2009-01-31 14:22:29 +0100 Fixed: issue details view discloses relations to issues that the user is not allowed to view (#2589). r19104@gaspard (orig r2344): jplang | 2009-01-31 15:50:56 +0100 Less strict textile links parsing (#2582). r19105@gaspard (orig r2345): jplang | 2009-02-01 15:36:38 +0100 Fixed: Contextual divs after attachments are placed incorrectly in FireFox (#2633). r19106@gaspard (orig r2346): jplang | 2009-02-01 16:48:56 +0100 Do not repeat one-line commit logs on the activity view. r19107@gaspard (orig r2347): jplang | 2009-02-01 16:57:01 +0100 Show line breaks in activity events summary. r19108@gaspard (orig r2348): jplang | 2009-02-01 17:00:20 +0100 Changes color of activity events/search results summary. r19109@gaspard (orig r2349): jplang | 2009-02-01 19:54:05 +0100 Use estimated hours to weight issues in version completion calculation (#2182). r19110@gaspard (orig r2350): jplang | 2009-02-01 20:54:50 +0100 Adds a setting to limit the number of revisions displayed on a repository file log (default=100). r19111@gaspard (orig r2351): jplang | 2009-02-01 21:56:10 +0100 Include both last and first name when sorting issues by assignee (#1841). r19112@gaspard (orig r2352): jplang | 2009-02-01 21:57:44 +0100 Include both version date and name when sorting issues by target version (#1502). r19113@gaspard (orig r2353): jplang | 2009-02-02 18:34:12 +0100 Adds a 'box' div around news comment form (#2632). r19119@gaspard (orig r2359): jplang | 2009-02-03 18:13:37 +0100 Fixes message search eager loading (#2654). r19120@gaspard (orig r2360): jplang | 2009-02-03 18:15:59 +0100 Typos/fixes in views (#2654). r19121@gaspard (orig r2361): jplang | 2009-02-03 18:32:07 +0100 Closed issue are not overdue, fixes r2140 (#2337). r19122@gaspard (orig r2362): jplang | 2009-02-05 18:43:49 +0100 Typo in wiki link example (#2673). r19123@gaspard (orig r2363): jplang | 2009-02-05 21:25:01 +0100 Fixed: inline attached image should not match partial filename (#2683). r19159@gaspard (orig r2399): jplang | 2009-02-07 21:11:03 +0100 Fixed: path parameter is not an array when changing diff style (#2695), broken by r2317. r19175@gaspard (orig r2415): jplang | 2009-02-08 18:24:39 +0100 Fixed: migration 98 breaks when using table name prefix. r19183@gaspard (orig r2423): jplang | 2009-02-09 18:18:41 +0100 Fixed: TypeError (can't modify frozen string) on settings view (#2700). r19184@gaspard (orig r2424): jplang | 2009-02-09 18:24:06 +0100 Removes hardcoded table names (#2701). r19186@gaspard (orig r2426): jplang | 2009-02-09 21:17:58 +0100 Strip keywords from received email body (#2436). r19187@gaspard (orig r2427): edavis10 | 2009-02-10 02:18:49 +0100 Added plugin hook :view_projects_roadmap_version_bottom. #2543 r19188@gaspard (orig r2428): edavis10 | 2009-02-10 02:24:32 +0100 Added two new plugin hooks: * :view_layouts_base_sidebar * :view_layouts_base_content r19189@gaspard (orig r2429): edavis10 | 2009-02-10 04:12:40 +0100 Added request and controller objects to the hooks by default. The request and controller objects are now added to all hook contexts by default. This will also make url_for work better in hooks by setting up the default_url_options :host, :port, and :protocol. Finally a new helper method @render_or@ has been added to ViewListener. This will let a hook easily render a partial without a full method definition. Thanks to Thomas Löber for the original patch. #2542 r19190@gaspard (orig r2430): edavis10 | 2009-02-10 04:12:45 +0100 Renamed variables to be more descriptive. #2542 r19191@gaspard (orig r2431): winterheart | 2009-02-10 16:41:05 +0100 Updated translations (#2577, #2640, #2644, #2652) r19192@gaspard (orig r2432): winterheart | 2009-02-10 16:57:52 +0100 Translation updates (#2643, #2645, #2668) r19193@gaspard (orig r2433): winterheart | 2009-02-10 17:05:31 +0100 New language - Macedonian (mk). Thank to Ilin Tatabitovski for work. r19194@gaspard (orig r2434): jplang | 2009-02-10 18:18:19 +0100 Fixes broken action url on time edit form (#2707). r19195@gaspard (orig r2435): jplang | 2009-02-10 23:03:25 +0100 Replaces the repositories management SOAP API with a simple REST API. reposman usage is unchanged but the script now requires activeresource. actionwebservice is now longer used and thus removed from plugins. r19196@gaspard (orig r2436): jplang | 2009-02-10 23:54:22 +0100 Leave wiki links untouched if target project doesn't exist or have no wiki. r19197@gaspard (orig r2437): edavis10 | 2009-02-11 20:06:37 +0100 Unpacked OpenID gem. #699 r19198@gaspard (orig r2438): edavis10 | 2009-02-11 20:06:45 +0100 Added open_id_authentication plugin r19199@gaspard (orig r2439): edavis10 | 2009-02-11 20:06:50 +0100 Added OpenID tables. #699 r19200@gaspard (orig r2440): edavis10 | 2009-02-11 20:06:55 +0100 Added identity_url to User. #699 r19201@gaspard (orig r2441): edavis10 | 2009-02-11 20:07:00 +0100 Fixed a bug in open_id_authentication, where relative_url_root is defined on ActionController:AbstractRequest not Base #699 r19202@gaspard (orig r2442): edavis10 | 2009-02-11 20:07:07 +0100 Added the ability to login via OpenID. * Refactored AccountController#login to use either password or openid based authentication * Extracted AccountController#successful_authentication to setup a user's session cookies and redirect * Implemented the start of AccountController#open_id_authentication which will check with the OpenID server and perform authentication. * Added text field for the OpenID url to /login * Added identity_url for OpenID to the user forms. * Added option to login with OpenID to the register form. * Added a root url route, which is used by the OpenID plugin #699 r19203@gaspard (orig r2443): edavis10 | 2009-02-11 20:07:12 +0100 Hooked up on the fly OpenID user creation. * Use OpenID registration fields for the user. * Generate a random password when a user is created. r19204@gaspard (orig r2444): edavis10 | 2009-02-11 20:07:18 +0100 Adding OpenID mock and test. #699 r19205@gaspard (orig r2445): edavis10 | 2009-02-11 20:07:23 +0100 Added tests for the other OpenID authentication cases. #699 r19206@gaspard (orig r2446): edavis10 | 2009-02-11 20:07:28 +0100 Added user setup needed based on the system's registration settings * Copied the register action's chunk of code used to setup the account based on Setting.self_registration * Extracted method for when onthefly_creation_failed * Added tests to confirm the behavior #699 r19207@gaspard (orig r2447): edavis10 | 2009-02-11 20:07:34 +0100 Refactored common methods out of register and open_id_authenticate * Extracted register_by_email_activation * Extracted register_automatically * Extracted register_manually_by_administrator #699 r19208@gaspard (orig r2448): edavis10 | 2009-02-11 20:07:41 +0100 Prevent registration via OpenID if self registration is off. #699 r19209@gaspard (orig r2449): edavis10 | 2009-02-11 20:24:28 +0100 Added a system setting for allowing OpenID logins and registrations * Defaults to off * Is set in the Administration panel under Authentication #699 r19210@gaspard (orig r2450): edavis10 | 2009-02-11 20:45:53 +0100 Added a space so words don't runtogeatherlikethis. #699 r19211@gaspard (orig r2451): jplang | 2009-02-11 21:25:05 +0100 Slight changes to the issue lists displayed on My page. r19212@gaspard (orig r2452): edavis10 | 2009-02-12 02:32:50 +0100 Fixed the bundled ruby-openid gem * The open_id_authentication plugin will require the gem automatically so it doesn't need to be added to environment.rb * Changed the version requirement on the open_id_authentication to match the latest stable version. Rails config.gem looks for a directory named after that specific version and will not load newer versions. #699 r19213@gaspard (orig r2453): edavis10 | 2009-02-12 05:31:28 +0100 Normalize the identity_url when it's set. OpenId uses a specific format for the url it uses which requires the protocol and trailing slash. This change will normalize the value to when a user sets it. #699 r19214@gaspard (orig r2454): jplang | 2009-02-12 18:19:32 +0100 Hide openid stuff on my account if disabled (#699). r19215@gaspard (orig r2455): jplang | 2009-02-12 18:30:56 +0100 Adds missing strings (#699). r19216@gaspard (orig r2456): jplang | 2009-02-12 18:35:57 +0100 Adds ability to filter watched issues (#846). r19217@gaspard (orig r2457): jplang | 2009-02-12 18:38:36 +0100 Link to watched issues list on my page. r19218@gaspard (orig r2458): jplang | 2009-02-12 22:25:50 +0100 Removes the fat ruby-openid gem. Simply use 'gem install ruby-openid' to enable openid support. r19219@gaspard (orig r2459): jplang | 2009-02-12 23:01:20 +0100 Issues pagination loses project param after applying or clearing filter (#2726). r19220@gaspard (orig r2460): jplang | 2009-02-12 23:14:22 +0100 Adds watch/unwatch link on the issue context menu (#2730). r19221@gaspard (orig r2461): jplang | 2009-02-13 18:29:49 +0100 Removes invalid css class on issue details (#2733). r19223@gaspard (orig r2463): jplang | 2009-02-13 18:59:45 +0100 Timelog is ignored when updating an issue if user is admin but not a project member (#2717). git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/nbc@2464 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- app/controllers/account_controller.rb | 170 +- app/controllers/admin_controller.rb | 27 +- app/controllers/application.rb | 22 +- app/controllers/attachments_controller.rb | 39 +- app/controllers/boards_controller.rb | 8 +- app/controllers/custom_fields_controller.rb | 45 +- app/controllers/documents_controller.rb | 6 +- app/controllers/issue_relations_controller.rb | 3 + app/controllers/issues_controller.rb | 70 +- app/controllers/journals_controller.rb | 1 + app/controllers/messages_controller.rb | 8 +- app/controllers/my_controller.rb | 1 + app/controllers/projects_controller.rb | 82 +- app/controllers/reports_controller.rb | 8 +- app/controllers/repositories_controller.rb | 23 +- app/controllers/roles_controller.rb | 21 - app/controllers/search_controller.rb | 2 +- app/controllers/settings_controller.rb | 22 +- app/controllers/sys_controller.rb | 50 +- app/controllers/timelog_controller.rb | 7 +- app/controllers/trackers_controller.rb | 4 + app/controllers/users_controller.rb | 16 +- app/controllers/versions_controller.rb | 6 - app/controllers/welcome_controller.rb | 6 + app/controllers/wiki_controller.rb | 48 +- app/controllers/workflows_controller.rb | 45 + app/helpers/admin_helper.rb | 10 +- app/helpers/application_helper.rb | 344 ++-- app/helpers/attachments_helper.rb | 13 +- app/helpers/ifpdf_helper.rb | 85 - app/helpers/issues_helper.rb | 8 + app/helpers/projects_helper.rb | 47 +- app/helpers/queries_helper.rb | 6 +- app/helpers/repositories_helper.rb | 6 + app/helpers/search_helper.rb | 2 +- app/helpers/settings_helper.rb | 1 + app/helpers/sort_helper.rb | 23 +- app/helpers/timelog_helper.rb | 4 +- app/helpers/users_helper.rb | 11 +- app/helpers/wiki_helper.rb | 16 - .../workflows_helper.rb} | 20 +- app/models/attachment.rb | 19 +- app/models/auth_source.rb | 3 +- app/models/auth_source_ldap.rb | 4 +- app/models/changeset.rb | 47 +- app/models/custom_field.rb | 40 +- app/models/custom_value.rb | 12 + app/models/document.rb | 8 +- app/models/enumeration.rb | 4 +- app/models/issue.rb | 79 +- app/models/issue_relation.rb | 2 + app/models/issue_status.rb | 4 +- app/models/journal.rb | 1 + app/models/mail_handler.rb | 134 +- app/models/mailer.rb | 132 +- app/models/message.rb | 15 +- app/models/news.rb | 11 +- app/models/project.rb | 77 +- app/models/query.rb | 156 +- app/models/repository.rb | 48 +- app/models/repository/darcs.rb | 2 +- app/models/repository/git.rb | 37 +- app/models/repository/subversion.rb | 6 +- app/models/role.rb | 4 +- app/models/setting.rb | 8 +- app/models/time_entry.rb | 4 +- app/models/tracker.rb | 4 +- app/models/user.rb | 59 +- app/models/version.rb | 47 +- app/models/wiki.rb | 19 + app/models/wiki_content.rb | 1 + app/models/wiki_page.rb | 6 +- app/models/workflow.rb | 19 + app/views/account/login.rhtml | 6 + app/views/account/register.rhtml | 9 +- app/views/account/show.rhtml | 58 +- app/views/admin/index.rhtml | 12 +- app/views/admin/info.rhtml | 19 +- app/views/admin/plugins.rhtml | 19 + app/views/admin/projects.rhtml | 26 +- app/views/attachments/_links.rhtml | 6 +- app/views/auth_sources/list.rhtml | 7 +- app/views/boards/index.rhtml | 8 +- app/views/boards/show.rhtml | 9 +- app/views/common/_diff.rhtml | 5 +- app/views/common/feed.atom.rxml | 2 +- app/views/custom_fields/_form.rhtml | 32 +- .../custom_fields/{list.rhtml => index.rhtml} | 0 app/views/documents/index.rhtml | 2 +- app/views/documents/show.rhtml | 2 +- app/views/issues/_changesets.rhtml | 2 +- app/views/issues/_edit.rhtml | 1 + app/views/issues/_form.rhtml | 14 +- app/views/issues/_form_update.rhtml | 2 + app/views/issues/_history.rhtml | 24 +- app/views/issues/_list.rhtml | 4 +- app/views/issues/_list_simple.rhtml | 13 +- app/views/issues/_relations.rhtml | 5 +- app/views/issues/_sidebar.rhtml | 18 +- app/views/issues/bulk_edit.rhtml | 10 +- app/views/issues/context_menu.rhtml | 5 +- app/views/issues/gantt.rfpdf | 188 --- app/views/issues/gantt.rhtml | 9 +- app/views/issues/index.rfpdf | 50 - app/views/issues/index.rhtml | 17 +- app/views/issues/move.rhtml | 9 +- app/views/issues/new.rhtml | 7 + app/views/issues/show.rfpdf | 126 -- app/views/issues/show.rhtml | 42 +- app/views/journals/_notes_form.rhtml | 5 +- app/views/journals/update.rjs | 2 + app/views/layouts/_project_selector.rhtml | 12 - app/views/layouts/base.rhtml | 14 +- app/views/mailer/layout.text.html.rhtml | 2 +- app/views/messages/show.rhtml | 18 +- app/views/my/account.rhtml | 9 +- app/views/my/blocks/_issuesassignedtome.rhtml | 4 +- app/views/my/blocks/_issuesreportedbyme.rhtml | 4 +- app/views/my/blocks/_issueswatched.rhtml | 6 +- app/views/my/blocks/_timelog.rhtml | 2 +- app/views/news/index.rhtml | 9 +- app/views/news/show.rhtml | 6 +- app/views/projects/_form.rhtml | 7 +- app/views/projects/activity.rhtml | 27 +- app/views/projects/add.rhtml | 1 + app/views/projects/add_file.rhtml | 9 +- app/views/projects/changelog.rhtml | 2 +- app/views/projects/destroy.rhtml | 4 +- app/views/projects/index.rhtml | 20 +- app/views/projects/list_files.rhtml | 30 +- app/views/projects/roadmap.rhtml | 1 + app/views/projects/settings/_members.rhtml | 2 +- app/views/projects/settings/_repository.rhtml | 5 +- app/views/projects/settings/_versions.rhtml | 1 - app/views/projects/show.rhtml | 14 +- app/views/queries/_filters.rhtml | 5 +- .../repositories/_dir_list_content.rhtml | 4 +- .../repositories/_link_to_functions.rhtml | 10 + app/views/repositories/_revisions.rhtml | 4 +- app/views/repositories/annotate.rhtml | 2 + app/views/repositories/changes.rhtml | 11 +- app/views/repositories/committers.rhtml | 34 + app/views/repositories/diff.rhtml | 16 +- app/views/repositories/entry.rhtml | 2 + app/views/repositories/revision.rhtml | 2 +- app/views/repositories/revisions.rhtml | 7 +- app/views/repositories/show.rhtml | 9 +- app/views/roles/_form.rhtml | 4 +- app/views/roles/report.rhtml | 4 +- app/views/settings/_authentication.rhtml | 3 + app/views/settings/_display.rhtml | 24 + app/views/settings/_general.rhtml | 23 +- app/views/settings/_notifications.rhtml | 6 +- app/views/settings/_repositories.rhtml | 3 + app/views/timelog/_list.rhtml | 8 +- app/views/timelog/details.rhtml | 15 +- app/views/timelog/edit.rhtml | 3 +- app/views/timelog/report.rhtml | 13 +- app/views/trackers/_form.rhtml | 17 +- app/views/trackers/edit.rhtml | 4 +- app/views/trackers/list.rhtml | 2 +- app/views/trackers/new.rhtml | 4 +- app/views/users/_form.rhtml | 3 + app/views/users/_general.rhtml | 2 +- app/views/users/_memberships.rhtml | 2 +- app/views/users/list.rhtml | 7 +- app/views/welcome/robots.rhtml | 9 + app/views/wiki/annotate.rhtml | 2 +- app/views/wiki/export.rhtml | 2 +- app/views/wiki/export_multiple.rhtml | 2 +- app/views/wiki/show.rhtml | 11 +- app/views/wiki/special_date_index.rhtml | 9 +- app/views/wiki/special_page_index.rhtml | 9 +- .../workflow.rhtml => workflows/edit.rhtml} | 42 +- app/views/workflows/index.rhtml | 31 + config/environment.rb | 2 +- config/initializers/10-patches.rb | 16 +- config/routes.rb | 244 ++- config/settings.yml | 13 +- .../098_set_topic_authors_as_watchers.rb | 7 +- ...elete_wiki_pages_attachments_permission.rb | 13 + db/migrate/100_add_changesets_user_id.rb | 9 + db/migrate/101_populate_changesets_user_id.rb | 18 + db/migrate/102_add_custom_fields_editable.rb | 9 + db/migrate/103_set_custom_fields_editable.rb | 9 + db/migrate/104_add_projects_lft_and_rgt.rb | 11 + db/migrate/105_build_projects_tree.rb | 8 + .../106_remove_projects_projects_count.rb | 9 + .../107_add_open_id_authentication_tables.rb | 20 + db/migrate/108_add_identity_url_to_users.rb | 9 + doc/CHANGELOG | 198 +++ doc/RUNNING_TESTS | 49 +- doc/UPGRADING | 2 +- extra/mail_handler/rdm-mailhandler.rb | 6 +- extra/svn/reposman.rb | 32 +- lang/bg.yml | 69 +- lang/ca.yml | 86 +- lang/cs.yml | 69 +- lang/da.yml | 478 +++--- lang/de.yml | 89 +- lang/en.yml | 77 +- lang/es.yml | 1193 +++++++------- lang/fi.yml | 81 +- lang/fr.yml | 79 +- lang/gl.yml | 694 +++++++++ lang/he.yml | 119 +- lang/hu.yml | 69 +- lang/it.yml | 103 +- lang/ja.yml | 109 +- lang/ko.yml | 437 +++--- lang/lt.yml | 1081 +++++++------ lang/mk.yml | 711 +++++++++ lang/nl.yml | 1197 +++++++------- lang/no.yml | 69 +- lang/pl.yml | 1216 ++++++++------- lang/pt-br.yml | 81 +- lang/pt.yml | 661 ++++---- lang/ro.yml | 69 +- lang/ru.yml | 77 +- lang/sk.yml | 714 +++++++++ lang/sl.yml | 711 +++++++++ lang/sr.yml | 361 +++-- lang/sv.yml | 738 +++++---- lang/th.yml | 69 +- lang/tr.yml | 69 +- lang/uk.yml | 247 +-- lang/vn.yml | 712 +++++++++ lang/zh-tw.yml | 77 +- lang/zh.yml | 77 +- .../redmine_plugin_generator.rb | 6 +- .../templates/{README => README.rdoc} | 0 .../templates/{init.rb => init.rb.erb} | 0 .../{test_helper.rb => test_helper.rb.erb} | 0 .../redmine_plugin_controller_generator.rb | 36 + .../{controller.rb => controller.rb.erb} | 0 ...ctional_test.rb => functional_test.rb.erb} | 0 .../templates/{helper.rb => helper.rb.erb} | 0 .../redmine_plugin_model_generator.rb | 26 + .../{migration.rb => migration.rb.erb} | 0 .../templates/{model.rb => model.rb.erb} | 0 .../{unit_test.rb => unit_test.rb.erb} | 0 lib/redcloth3.rb | 73 +- lib/redmine.rb | 40 +- lib/redmine/access_control.rb | 10 +- lib/redmine/activity/fetcher.rb | 20 +- lib/redmine/core_ext/string/conversions.rb | 4 +- lib/redmine/default_data/loader.rb | 2 + lib/redmine/export/pdf.rb | 462 ++++++ lib/redmine/hook.rb | 62 +- lib/redmine/imap.rb | 11 +- lib/redmine/menu_manager.rb | 53 +- lib/redmine/plugin.rb | 95 +- lib/redmine/scm/adapters/abstract_adapter.rb | 4 + lib/redmine/scm/adapters/bazaar_adapter.rb | 3 +- lib/redmine/scm/adapters/cvs_adapter.rb | 12 +- lib/redmine/scm/adapters/darcs_adapter.rb | 31 +- lib/redmine/scm/adapters/git_adapter.rb | 13 +- .../scm/adapters/subversion_adapter.rb | 31 +- lib/redmine/unified_diff.rb | 20 +- lib/redmine/utils.rb | 38 + lib/redmine/version.rb | 14 +- lib/redmine/views/other_formats_builder.rb | 33 + lib/redmine/wiki_formatting.rb | 193 +-- lib/redmine/wiki_formatting/macros.rb | 40 +- .../wiki_formatting/textile/formatter.rb | 184 +++ lib/redmine/wiki_formatting/textile/helper.rb | 46 + lib/tabular_form_builder.rb | 26 +- lib/tasks/email.rake | 17 +- lib/tasks/migrate_from_trac.rake | 336 ++-- lib/tasks/testing.rake | 30 + public/dispatch.cgi.example | 2 +- public/dispatch.fcgi.example | 2 +- public/dispatch.rb.example | 2 +- public/help/wiki_syntax_detailed.html | 599 +++---- public/images/openid-bg.gif | Bin 0 -> 328 bytes public/images/time.png | Bin 404 -> 793 bytes public/images/time_add.png | Bin 0 -> 827 bytes public/images/warning.png | Bin 535 -> 666 bytes .../javascripts/calendar/lang/calendar-da.js | 10 +- .../javascripts/calendar/lang/calendar-gl.js | 128 ++ .../javascripts/calendar/lang/calendar-ko.js | 28 +- .../javascripts/calendar/lang/calendar-mk.js | 127 ++ .../javascripts/calendar/lang/calendar-pt.js | 37 +- .../javascripts/calendar/lang/calendar-sk.js | 68 + .../javascripts/calendar/lang/calendar-sl.js | 127 ++ .../javascripts/calendar/lang/calendar-sv.js | 56 +- .../javascripts/calendar/lang/calendar-vn.js | 126 ++ public/javascripts/context_menu.js | 2 +- public/javascripts/jstoolbar/jstoolbar.js | 179 --- .../jstoolbar/lang/jstoolbar-da.js | 12 +- .../jstoolbar/lang/jstoolbar-es.js | 30 +- .../jstoolbar/lang/jstoolbar-gl.js | 16 + .../jstoolbar/lang/jstoolbar-it.js | 30 +- .../jstoolbar/lang/jstoolbar-ko.js | 30 +- .../jstoolbar/lang/jstoolbar-mk.js | 16 + .../jstoolbar/lang/jstoolbar-nl.js | 30 +- .../jstoolbar/lang/jstoolbar-pl.js | 31 +- .../jstoolbar/lang/jstoolbar-pt.js | 31 +- .../jstoolbar/lang/jstoolbar-sk.js | 16 + .../jstoolbar/lang/jstoolbar-sl.js | 16 + .../jstoolbar/lang/jstoolbar-sv.js | 30 +- .../jstoolbar/lang/jstoolbar-vn.js | 16 + public/javascripts/jstoolbar/textile.js | 200 +++ public/robots.txt | 4 - public/stylesheets/application.css | 103 +- .../classic/stylesheets/application.css | 6 +- test/fixtures/attachments.yml | 24 + test/fixtures/changesets.yml | 4 + test/fixtures/custom_fields.yml | 18 + test/fixtures/custom_fields_trackers.yml | 9 + test/fixtures/custom_values.yml | 48 +- test/fixtures/diffs/subversion.diff | 79 + test/fixtures/enabled_modules.yml | 12 + test/fixtures/files/testfile.txt | 3 +- test/fixtures/issues.yml | 34 + test/fixtures/mail_handler/message_reply.eml | 15 + .../mail_handler/message_reply_by_subject.eml | 13 + .../mail_handler/ticket_html_only.eml | 22 + .../mail_handler/ticket_on_given_project.eml | 4 +- test/fixtures/mail_handler/ticket_reply.eml | 3 +- test/fixtures/mail_handler/ticket_with_cc.eml | 40 + .../ticket_with_custom_fields.eml | 41 + test/fixtures/members.yml | 5 + test/fixtures/messages.yml | 17 +- test/fixtures/projects.yml | 29 +- test/fixtures/projects_trackers.yml | 28 +- test/fixtures/roles.yml | 4 + test/fixtures/watchers.yml | 4 + test/fixtures/wiki_contents.yml | 22 + test/fixtures/wiki_pages.yml | 14 + test/functional/account_controller_test.rb | 79 +- test/functional/admin_controller_test.rb | 58 +- .../functional/application_controller_test.rb | 4 + .../functional/attachments_controller_test.rb | 51 +- test/functional/boards_controller_test.rb | 43 + .../custom_fields_controller_test.rb | 61 + test/functional/documents_controller_test.rb | 54 +- .../issue_relations_controller_test.rb | 58 + test/functional/issues_controller_test.rb | 357 ++++- test/functional/members_controller_test.rb | 15 + test/functional/messages_controller_test.rb | 47 +- test/functional/my_controller_test.rb | 23 +- test/functional/news_controller_test.rb | 64 + test/functional/projects_controller_test.rb | 308 +++- test/functional/reports_controller_test.rb | 20 + .../repositories_controller_test.rb | 147 +- ...repositories_subversion_controller_test.rb | 24 +- test/functional/roles_controller_test.rb | 40 - test/functional/search_controller_test.rb | 11 + test/functional/sys_api_test.rb | 50 - test/functional/sys_controller_test.rb | 55 + test/functional/timelog_controller_test.rb | 128 +- test/functional/trackers_controller_test.rb | 68 + test/functional/users_controller_test.rb | 84 +- test/functional/versions_controller_test.rb | 4 +- test/functional/welcome_controller_test.rb | 7 + test/functional/wiki_controller_test.rb | 129 +- test/functional/wikis_controller_test.rb | 23 +- test/functional/workflows_controller_test.rb | 84 + test/integration/account_test.rb | 2 +- test/integration/admin_test.rb | 4 +- test/integration/issues_test.rb | 8 +- test/integration/projects_test.rb | 10 +- test/mocks/open_id_authentication_mock.rb | 45 + test/test_helper.rb | 1 + test/unit/activity_test.rb | 9 + test/unit/attachment_test.rb | 7 +- test/unit/custom_field_test.rb | 18 + test/unit/document_test.rb | 37 + test/unit/enumeration_test.rb | 37 + test/unit/helpers/application_helper_test.rb | 163 +- test/unit/issue_status_test.rb | 22 +- test/unit/issue_test.rb | 38 + test/unit/lib/redmine/access_control_test.rb | 49 + test/unit/lib/redmine/hook_test.rb | 83 +- test/unit/lib/redmine/plugin_test.rb | 78 + test/unit/lib/redmine/unified_diff_test.rb | 42 + .../redmine/wiki_formatting/macros_test.rb | 98 ++ test/unit/mail_handler_test.rb | 59 +- test/unit/mailer_test.rb | 104 +- test/unit/message_test.rb | 20 +- test/unit/news_test.rb | 63 + test/unit/project_test.rb | 109 +- test/unit/query_test.rb | 119 +- test/unit/repository_cvs_test.rb | 6 + test/unit/repository_darcs_test.rb | 6 + test/unit/repository_git_test.rb | 17 +- test/unit/repository_subversion_test.rb | 7 + test/unit/repository_test.rb | 44 +- test/unit/time_entry_test.rb | 3 +- test/unit/user_test.rb | 335 ++-- test/unit/version_test.rb | 86 +- vendor/plugins/actionwebservice/CHANGELOG | 265 ---- vendor/plugins/actionwebservice/README | 364 ----- vendor/plugins/actionwebservice/Rakefile | 172 -- vendor/plugins/actionwebservice/TODO | 32 - vendor/plugins/actionwebservice/init.rb | 7 - vendor/plugins/actionwebservice/install.rb | 30 - .../lib/action_web_service.rb | 66 - .../lib/action_web_service/api.rb | 297 ---- .../lib/action_web_service/base.rb | 38 - .../lib/action_web_service/casting.rb | 138 -- .../lib/action_web_service/client.rb | 3 - .../lib/action_web_service/client/base.rb | 28 - .../action_web_service/client/soap_client.rb | 113 -- .../client/xmlrpc_client.rb | 58 - .../lib/action_web_service/container.rb | 3 - .../container/action_controller_container.rb | 93 -- .../container/delegated_container.rb | 86 - .../container/direct_container.rb | 69 - .../lib/action_web_service/dispatcher.rb | 2 - .../action_web_service/dispatcher/abstract.rb | 207 --- .../action_controller_dispatcher.rb | 379 ----- .../lib/action_web_service/invocation.rb | 202 --- .../lib/action_web_service/protocol.rb | 4 - .../action_web_service/protocol/abstract.rb | 112 -- .../action_web_service/protocol/discovery.rb | 37 - .../protocol/soap_protocol.rb | 176 --- .../protocol/soap_protocol/marshaler.rb | 235 --- .../protocol/xmlrpc_protocol.rb | 122 -- .../lib/action_web_service/scaffolding.rb | 283 ---- .../lib/action_web_service/struct.rb | 64 - .../support/class_inheritable_options.rb | 26 - .../support/signature_types.rb | 226 --- .../templates/scaffolds/layout.erb | 65 - .../templates/scaffolds/layout.rhtml | 0 .../templates/scaffolds/methods.erb | 6 - .../templates/scaffolds/methods.rhtml | 0 .../templates/scaffolds/parameters.erb | 29 - .../templates/scaffolds/parameters.rhtml | 0 .../templates/scaffolds/result.erb | 30 - .../templates/scaffolds/result.rhtml | 0 .../lib/action_web_service/test_invoke.rb | 110 -- .../lib/action_web_service/version.rb | 9 - .../actionwebservice/lib/actionwebservice.rb | 1 - vendor/plugins/actionwebservice/setup.rb | 1379 ----------------- .../lib/acts_as_activity_provider.rb | 23 +- vendor/plugins/acts_as_attachable/init.rb | 2 + .../lib/acts_as_attachable.rb | 57 + .../lib/acts_as_watchable.rb | 2 + .../MIT-LICENSE | 3 +- vendor/plugins/awesome_nested_set/README.rdoc | 64 + vendor/plugins/awesome_nested_set/Rakefile | 46 + .../awesome_nested_set.gemspec | 20 + vendor/plugins/awesome_nested_set/init.rb | 1 + .../lib/awesome_nested_set.rb | 547 +++++++ .../lib/awesome_nested_set/compatability.rb | 29 + .../lib/awesome_nested_set/helper.rb | 40 + .../lib/awesome_nested_set/named_scope.rb | 140 ++ .../plugins/awesome_nested_set/rails/init.rb | 13 + .../test/awesome_nested_set/helper_test.rb | 41 + .../test/awesome_nested_set_test.rb | 603 +++++++ .../awesome_nested_set/test/db/database.yml | 18 + .../awesome_nested_set/test/db/schema.rb | 23 + .../test/fixtures/categories.yml | 34 + .../test/fixtures/category.rb | 15 + .../test/fixtures/departments.yml | 3 + .../test/fixtures/notes.yml | 38 + .../awesome_nested_set/test/test_helper.rb | 31 + .../classic_pagination/lib/pagination.rb | 4 +- .../engines/rails_extensions/dependencies.rb | 2 +- vendor/plugins/gloc-1.1.0/lib/gloc.rb | 16 +- vendor/plugins/gloc-1.1.0/tasks/gloc.rake | 2 +- vendor/plugins/gravatar/MIT-LICENSE | 20 + vendor/plugins/gravatar/README | 52 + vendor/plugins/gravatar/Rakefile | 33 + vendor/plugins/gravatar/about.yml | 7 + vendor/plugins/gravatar/init.rb | 2 + vendor/plugins/gravatar/lib/gravatar.rb | 67 + vendor/plugins/gravatar/spec/gravatar_spec.rb | 37 + .../plugins/open_id_authentication/CHANGELOG | 35 + vendor/plugins/open_id_authentication/README | 231 +++ .../plugins/open_id_authentication/Rakefile | 22 + ...open_id_authentication_tables_generator.rb | 11 + .../templates/migration.rb | 20 + .../templates/migration.rb | 26 + ...open_id_authentication_tables_generator.rb | 11 + vendor/plugins/open_id_authentication/init.rb | 16 + .../lib/open_id_authentication.rb | 241 +++ .../lib/open_id_authentication/association.rb | 9 + .../lib/open_id_authentication/db_store.rb | 55 + .../open_id_authentication/mem_cache_store.rb | 73 + .../lib/open_id_authentication/nonce.rb | 5 + .../lib/open_id_authentication/request.rb | 23 + .../open_id_authentication/timeout_fixes.rb | 20 + .../tasks/open_id_authentication_tasks.rake | 30 + .../test/mem_cache_store_test.rb | 151 ++ .../test/normalize_test.rb | 32 + .../test/open_id_authentication_test.rb | 46 + .../test/status_test.rb | 14 + .../test/test_helper.rb | 17 + 491 files changed, 21672 insertions(+), 12490 deletions(-) create mode 100644 app/controllers/workflows_controller.rb delete mode 100644 app/helpers/ifpdf_helper.rb rename app/{apis/sys_api.rb => helpers/workflows_helper.rb} (53%) create mode 100644 app/views/admin/plugins.rhtml rename app/views/custom_fields/{list.rhtml => index.rhtml} (100%) delete mode 100644 app/views/issues/gantt.rfpdf delete mode 100644 app/views/issues/index.rfpdf delete mode 100644 app/views/issues/show.rfpdf delete mode 100644 app/views/layouts/_project_selector.rhtml create mode 100644 app/views/repositories/_link_to_functions.rhtml create mode 100644 app/views/repositories/committers.rhtml create mode 100644 app/views/settings/_display.rhtml create mode 100644 app/views/welcome/robots.rhtml rename app/views/{roles/workflow.rhtml => workflows/edit.rhtml} (56%) create mode 100644 app/views/workflows/index.rhtml create mode 100644 db/migrate/099_add_delete_wiki_pages_attachments_permission.rb create mode 100644 db/migrate/100_add_changesets_user_id.rb create mode 100644 db/migrate/101_populate_changesets_user_id.rb create mode 100644 db/migrate/102_add_custom_fields_editable.rb create mode 100644 db/migrate/103_set_custom_fields_editable.rb create mode 100644 db/migrate/104_add_projects_lft_and_rgt.rb create mode 100644 db/migrate/105_build_projects_tree.rb create mode 100644 db/migrate/106_remove_projects_projects_count.rb create mode 100644 db/migrate/107_add_open_id_authentication_tables.rb create mode 100644 db/migrate/108_add_identity_url_to_users.rb create mode 100644 lang/gl.yml create mode 100644 lang/mk.yml create mode 100644 lang/sk.yml create mode 100644 lang/sl.yml create mode 100644 lang/vn.yml rename lib/generators/redmine_plugin/templates/{README => README.rdoc} (100%) rename lib/generators/redmine_plugin/templates/{init.rb => init.rb.erb} (100%) rename lib/generators/redmine_plugin/templates/{test_helper.rb => test_helper.rb.erb} (100%) rename lib/generators/redmine_plugin_controller/templates/{controller.rb => controller.rb.erb} (100%) rename lib/generators/redmine_plugin_controller/templates/{functional_test.rb => functional_test.rb.erb} (100%) rename lib/generators/redmine_plugin_controller/templates/{helper.rb => helper.rb.erb} (100%) rename lib/generators/redmine_plugin_model/templates/{migration.rb => migration.rb.erb} (100%) rename lib/generators/redmine_plugin_model/templates/{model.rb => model.rb.erb} (100%) rename lib/generators/redmine_plugin_model/templates/{unit_test.rb => unit_test.rb.erb} (100%) create mode 100644 lib/redmine/export/pdf.rb create mode 100644 lib/redmine/utils.rb create mode 100644 lib/redmine/views/other_formats_builder.rb create mode 100644 lib/redmine/wiki_formatting/textile/formatter.rb create mode 100644 lib/redmine/wiki_formatting/textile/helper.rb create mode 100644 public/images/openid-bg.gif create mode 100644 public/images/time_add.png create mode 100644 public/javascripts/calendar/lang/calendar-gl.js create mode 100644 public/javascripts/calendar/lang/calendar-mk.js create mode 100644 public/javascripts/calendar/lang/calendar-sk.js create mode 100644 public/javascripts/calendar/lang/calendar-sl.js create mode 100644 public/javascripts/calendar/lang/calendar-vn.js create mode 100644 public/javascripts/jstoolbar/lang/jstoolbar-gl.js create mode 100644 public/javascripts/jstoolbar/lang/jstoolbar-mk.js create mode 100644 public/javascripts/jstoolbar/lang/jstoolbar-sk.js create mode 100644 public/javascripts/jstoolbar/lang/jstoolbar-sl.js create mode 100644 public/javascripts/jstoolbar/lang/jstoolbar-vn.js create mode 100644 public/javascripts/jstoolbar/textile.js delete mode 100644 public/robots.txt create mode 100644 test/fixtures/diffs/subversion.diff create mode 100644 test/fixtures/mail_handler/message_reply.eml create mode 100644 test/fixtures/mail_handler/message_reply_by_subject.eml create mode 100644 test/fixtures/mail_handler/ticket_html_only.eml create mode 100644 test/fixtures/mail_handler/ticket_with_cc.eml create mode 100644 test/fixtures/mail_handler/ticket_with_custom_fields.eml create mode 100644 test/functional/custom_fields_controller_test.rb create mode 100644 test/functional/issue_relations_controller_test.rb create mode 100644 test/functional/members_controller_test.rb create mode 100644 test/functional/reports_controller_test.rb delete mode 100644 test/functional/sys_api_test.rb create mode 100644 test/functional/sys_controller_test.rb create mode 100644 test/functional/trackers_controller_test.rb create mode 100644 test/functional/workflows_controller_test.rb create mode 100644 test/mocks/open_id_authentication_mock.rb create mode 100644 test/unit/document_test.rb create mode 100644 test/unit/lib/redmine/access_control_test.rb create mode 100644 test/unit/lib/redmine/plugin_test.rb create mode 100644 test/unit/lib/redmine/unified_diff_test.rb create mode 100644 test/unit/lib/redmine/wiki_formatting/macros_test.rb create mode 100644 test/unit/news_test.rb delete mode 100644 vendor/plugins/actionwebservice/CHANGELOG delete mode 100644 vendor/plugins/actionwebservice/README delete mode 100644 vendor/plugins/actionwebservice/Rakefile delete mode 100644 vendor/plugins/actionwebservice/TODO delete mode 100644 vendor/plugins/actionwebservice/init.rb delete mode 100644 vendor/plugins/actionwebservice/install.rb delete mode 100644 vendor/plugins/actionwebservice/lib/action_web_service.rb delete mode 100644 vendor/plugins/actionwebservice/lib/action_web_service/api.rb delete mode 100644 vendor/plugins/actionwebservice/lib/action_web_service/base.rb delete mode 100644 vendor/plugins/actionwebservice/lib/action_web_service/casting.rb delete mode 100644 vendor/plugins/actionwebservice/lib/action_web_service/client.rb delete mode 100644 vendor/plugins/actionwebservice/lib/action_web_service/client/base.rb delete mode 100644 vendor/plugins/actionwebservice/lib/action_web_service/client/soap_client.rb delete mode 100644 vendor/plugins/actionwebservice/lib/action_web_service/client/xmlrpc_client.rb delete mode 100644 vendor/plugins/actionwebservice/lib/action_web_service/container.rb delete mode 100644 vendor/plugins/actionwebservice/lib/action_web_service/container/action_controller_container.rb delete mode 100644 vendor/plugins/actionwebservice/lib/action_web_service/container/delegated_container.rb delete mode 100644 vendor/plugins/actionwebservice/lib/action_web_service/container/direct_container.rb delete mode 100644 vendor/plugins/actionwebservice/lib/action_web_service/dispatcher.rb delete mode 100644 vendor/plugins/actionwebservice/lib/action_web_service/dispatcher/abstract.rb delete mode 100644 vendor/plugins/actionwebservice/lib/action_web_service/dispatcher/action_controller_dispatcher.rb delete mode 100644 vendor/plugins/actionwebservice/lib/action_web_service/invocation.rb delete mode 100644 vendor/plugins/actionwebservice/lib/action_web_service/protocol.rb delete mode 100644 vendor/plugins/actionwebservice/lib/action_web_service/protocol/abstract.rb delete mode 100644 vendor/plugins/actionwebservice/lib/action_web_service/protocol/discovery.rb delete mode 100644 vendor/plugins/actionwebservice/lib/action_web_service/protocol/soap_protocol.rb delete mode 100644 vendor/plugins/actionwebservice/lib/action_web_service/protocol/soap_protocol/marshaler.rb delete mode 100644 vendor/plugins/actionwebservice/lib/action_web_service/protocol/xmlrpc_protocol.rb delete mode 100644 vendor/plugins/actionwebservice/lib/action_web_service/scaffolding.rb delete mode 100644 vendor/plugins/actionwebservice/lib/action_web_service/struct.rb delete mode 100644 vendor/plugins/actionwebservice/lib/action_web_service/support/class_inheritable_options.rb delete mode 100644 vendor/plugins/actionwebservice/lib/action_web_service/support/signature_types.rb delete mode 100644 vendor/plugins/actionwebservice/lib/action_web_service/templates/scaffolds/layout.erb delete mode 100644 vendor/plugins/actionwebservice/lib/action_web_service/templates/scaffolds/layout.rhtml delete mode 100644 vendor/plugins/actionwebservice/lib/action_web_service/templates/scaffolds/methods.erb delete mode 100644 vendor/plugins/actionwebservice/lib/action_web_service/templates/scaffolds/methods.rhtml delete mode 100644 vendor/plugins/actionwebservice/lib/action_web_service/templates/scaffolds/parameters.erb delete mode 100644 vendor/plugins/actionwebservice/lib/action_web_service/templates/scaffolds/parameters.rhtml delete mode 100644 vendor/plugins/actionwebservice/lib/action_web_service/templates/scaffolds/result.erb delete mode 100644 vendor/plugins/actionwebservice/lib/action_web_service/templates/scaffolds/result.rhtml delete mode 100644 vendor/plugins/actionwebservice/lib/action_web_service/test_invoke.rb delete mode 100644 vendor/plugins/actionwebservice/lib/action_web_service/version.rb delete mode 100644 vendor/plugins/actionwebservice/lib/actionwebservice.rb delete mode 100644 vendor/plugins/actionwebservice/setup.rb create mode 100644 vendor/plugins/acts_as_attachable/init.rb create mode 100644 vendor/plugins/acts_as_attachable/lib/acts_as_attachable.rb rename vendor/plugins/{actionwebservice => awesome_nested_set}/MIT-LICENSE (95%) create mode 100644 vendor/plugins/awesome_nested_set/README.rdoc create mode 100644 vendor/plugins/awesome_nested_set/Rakefile create mode 100644 vendor/plugins/awesome_nested_set/awesome_nested_set.gemspec create mode 100644 vendor/plugins/awesome_nested_set/init.rb create mode 100644 vendor/plugins/awesome_nested_set/lib/awesome_nested_set.rb create mode 100644 vendor/plugins/awesome_nested_set/lib/awesome_nested_set/compatability.rb create mode 100644 vendor/plugins/awesome_nested_set/lib/awesome_nested_set/helper.rb create mode 100644 vendor/plugins/awesome_nested_set/lib/awesome_nested_set/named_scope.rb create mode 100644 vendor/plugins/awesome_nested_set/rails/init.rb create mode 100644 vendor/plugins/awesome_nested_set/test/awesome_nested_set/helper_test.rb create mode 100644 vendor/plugins/awesome_nested_set/test/awesome_nested_set_test.rb create mode 100644 vendor/plugins/awesome_nested_set/test/db/database.yml create mode 100644 vendor/plugins/awesome_nested_set/test/db/schema.rb create mode 100644 vendor/plugins/awesome_nested_set/test/fixtures/categories.yml create mode 100644 vendor/plugins/awesome_nested_set/test/fixtures/category.rb create mode 100644 vendor/plugins/awesome_nested_set/test/fixtures/departments.yml create mode 100644 vendor/plugins/awesome_nested_set/test/fixtures/notes.yml create mode 100644 vendor/plugins/awesome_nested_set/test/test_helper.rb create mode 100644 vendor/plugins/gravatar/MIT-LICENSE create mode 100644 vendor/plugins/gravatar/README create mode 100644 vendor/plugins/gravatar/Rakefile create mode 100644 vendor/plugins/gravatar/about.yml create mode 100644 vendor/plugins/gravatar/init.rb create mode 100644 vendor/plugins/gravatar/lib/gravatar.rb create mode 100644 vendor/plugins/gravatar/spec/gravatar_spec.rb create mode 100644 vendor/plugins/open_id_authentication/CHANGELOG create mode 100644 vendor/plugins/open_id_authentication/README create mode 100644 vendor/plugins/open_id_authentication/Rakefile create mode 100644 vendor/plugins/open_id_authentication/generators/open_id_authentication_tables/open_id_authentication_tables_generator.rb create mode 100644 vendor/plugins/open_id_authentication/generators/open_id_authentication_tables/templates/migration.rb create mode 100644 vendor/plugins/open_id_authentication/generators/upgrade_open_id_authentication_tables/templates/migration.rb create mode 100644 vendor/plugins/open_id_authentication/generators/upgrade_open_id_authentication_tables/upgrade_open_id_authentication_tables_generator.rb create mode 100644 vendor/plugins/open_id_authentication/init.rb create mode 100644 vendor/plugins/open_id_authentication/lib/open_id_authentication.rb create mode 100644 vendor/plugins/open_id_authentication/lib/open_id_authentication/association.rb create mode 100644 vendor/plugins/open_id_authentication/lib/open_id_authentication/db_store.rb create mode 100644 vendor/plugins/open_id_authentication/lib/open_id_authentication/mem_cache_store.rb create mode 100644 vendor/plugins/open_id_authentication/lib/open_id_authentication/nonce.rb create mode 100644 vendor/plugins/open_id_authentication/lib/open_id_authentication/request.rb create mode 100644 vendor/plugins/open_id_authentication/lib/open_id_authentication/timeout_fixes.rb create mode 100644 vendor/plugins/open_id_authentication/tasks/open_id_authentication_tasks.rake create mode 100644 vendor/plugins/open_id_authentication/test/mem_cache_store_test.rb create mode 100644 vendor/plugins/open_id_authentication/test/normalize_test.rb create mode 100644 vendor/plugins/open_id_authentication/test/open_id_authentication_test.rb create mode 100644 vendor/plugins/open_id_authentication/test/status_test.rb create mode 100644 vendor/plugins/open_id_authentication/test/test_helper.rb diff --git a/app/controllers/account_controller.rb b/app/controllers/account_controller.rb index 4b2ec8317..dae268f20 100644 --- a/app/controllers/account_controller.rb +++ b/app/controllers/account_controller.rb @@ -1,5 +1,5 @@ -# redMine - project management software -# Copyright (C) 2006-2007 Jean-Philippe Lang +# Redmine - project management software +# 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 @@ -24,13 +24,17 @@ class AccountController < ApplicationController # Show user's account def show - @user = User.find_active(params[:id]) + @user = User.active.find(params[:id]) @custom_values = @user.custom_values # show only public projects and private projects that the logged in user is also a member of @memberships = @user.memberships.select do |membership| membership.project.is_public? || (User.current.member_of?(membership.project)) end + + events = Redmine::Activity::Fetcher.new(User.current, :author => @user).events(nil, nil, :limit => 10) + @events_by_day = events.group_by(&:event_date) + rescue ActiveRecord::RecordNotFound render_404 end @@ -42,24 +46,10 @@ class AccountController < ApplicationController self.logged_user = nil else # Authenticate user - user = User.try_to_login(params[:username], params[:password]) - if user.nil? - # Invalid credentials - flash.now[:error] = l(:notice_account_invalid_creditentials) - elsif user.new_record? - # Onthefly creation failed, display the registration form to fill/fix attributes - @user = user - session[:auth_source_registration] = {:login => user.login, :auth_source_id => user.auth_source_id } - render :action => 'register' + if Setting.openid? && using_open_id? + open_id_authenticate(params[:openid_url]) else - # Valid user - self.logged_user = user - # generate a key and set cookie if autologin - if params[:autologin] && Setting.autologin? - token = Token.create(:user => user, :action => 'autologin') - cookies[:autologin] = { :value => token.value, :expires => 1.year.from_now } - end - redirect_back_or_default :controller => 'my', :action => 'page' + password_authentication end end end @@ -132,31 +122,14 @@ class AccountController < ApplicationController else @user.login = params[:user][:login] @user.password, @user.password_confirmation = params[:password], params[:password_confirmation] + case Setting.self_registration when '1' - # Email activation - token = Token.new(:user => @user, :action => "register") - if @user.save and token.save - Mailer.deliver_register(token) - flash[:notice] = l(:notice_account_register_done) - redirect_to :action => 'login' - end + register_by_email_activation(@user) when '3' - # Automatic activation - @user.status = User::STATUS_ACTIVE - if @user.save - self.logged_user = @user - flash[:notice] = l(:notice_account_activated) - redirect_to :controller => 'my', :action => 'account' - end + register_automatically(@user) else - # Manual activation by the administrator - if @user.save - # Sends an email to the administrators - Mailer.deliver_account_activation_request(@user) - flash[:notice] = l(:notice_account_pending) - redirect_to :action => 'login' - end + register_manually_by_administrator(@user) end end end @@ -187,4 +160,119 @@ private session[:user_id] = nil end end + + def password_authentication + user = User.try_to_login(params[:username], params[:password]) + if user.nil? + # Invalid credentials + flash.now[:error] = l(:notice_account_invalid_creditentials) + elsif user.new_record? + # Onthefly creation failed, display the registration form to fill/fix attributes + @user = user + session[:auth_source_registration] = {:login => user.login, :auth_source_id => user.auth_source_id } + render :action => 'register' + else + # Valid user + successful_authentication(user) + end + end + + + def open_id_authenticate(openid_url) + authenticate_with_open_id(openid_url, :required => [:nickname, :fullname, :email], :return_to => signin_url) do |result, identity_url, registration| + if result.successful? + user = User.find_or_initialize_by_identity_url(identity_url) + if user.new_record? + # Self-registration off + redirect_to(home_url) && return unless Setting.self_registration? + + # Create on the fly + user.login = registration['nickname'] unless registration['nickname'].nil? + user.mail = registration['email'] unless registration['email'].nil? + user.firstname, user.lastname = registration['fullname'].split(' ') unless registration['fullname'].nil? + user.random_password + user.status = User::STATUS_REGISTERED + + case Setting.self_registration + when '1' + register_by_email_activation(user) do + onthefly_creation_failed(user, {:login => user.login, :identity_url => identity_url }) + end + when '3' + register_automatically(user) do + onthefly_creation_failed(user, {:login => user.login, :identity_url => identity_url }) + end + else + register_manually_by_administrator(user) do + onthefly_creation_failed(user, {:login => user.login, :identity_url => identity_url }) + end + end + else + # Existing record + successful_authentication(user) + end + end + end + end + + def successful_authentication(user) + # Valid user + self.logged_user = user + # generate a key and set cookie if autologin + if params[:autologin] && Setting.autologin? + token = Token.create(:user => user, :action => 'autologin') + cookies[:autologin] = { :value => token.value, :expires => 1.year.from_now } + end + redirect_back_or_default :controller => 'my', :action => 'page' + end + + # Onthefly creation failed, display the registration form to fill/fix attributes + def onthefly_creation_failed(user, auth_source_options = { }) + @user = user + session[:auth_source_registration] = auth_source_options unless auth_source_options.empty? + render :action => 'register' + end + + # Register a user for email activation. + # + # Pass a block for behavior when a user fails to save + def register_by_email_activation(user, &block) + token = Token.new(:user => user, :action => "register") + if user.save and token.save + Mailer.deliver_register(token) + flash[:notice] = l(:notice_account_register_done) + redirect_to :action => 'login' + else + yield if block_given? + end + end + + # Automatically register a user + # + # Pass a block for behavior when a user fails to save + def register_automatically(user, &block) + # Automatic activation + user.status = User::STATUS_ACTIVE + if user.save + self.logged_user = user + flash[:notice] = l(:notice_account_activated) + redirect_to :controller => 'my', :action => 'account' + else + yield if block_given? + end + end + + # Manual activation by the administrator + # + # Pass a block for behavior when a user fails to save + def register_manually_by_administrator(user, &block) + if user.save + # Sends an email to the administrators + Mailer.deliver_account_activation_request(user) + flash[:notice] = l(:notice_account_pending) + redirect_to :action => 'login' + else + yield if block_given? + end + end end diff --git a/app/controllers/admin_controller.rb b/app/controllers/admin_controller.rb index a6df49dcd..61d1eada7 100644 --- a/app/controllers/admin_controller.rb +++ b/app/controllers/admin_controller.rb @@ -26,25 +26,24 @@ class AdminController < ApplicationController end def projects - sort_init 'name', 'asc' - sort_update + @status = params[:status] ? params[:status].to_i : 1 + c = ARCondition.new(@status == 0 ? "status <> 0" : ["status = ?", @status]) - @status = params[:status] ? params[:status].to_i : 0 - conditions = nil - conditions = ["status=?", @status] unless @status == 0 + unless params[:name].blank? + name = "%#{params[:name].strip.downcase}%" + c << ["LOWER(identifier) LIKE ? OR LOWER(name) LIKE ?", name, name] + end - @project_count = Project.count(:conditions => conditions) - @project_pages = Paginator.new self, @project_count, - per_page_option, - params['page'] - @projects = Project.find :all, :order => sort_clause, - :conditions => conditions, - :limit => @project_pages.items_per_page, - :offset => @project_pages.current.offset + @projects = Project.find :all, :order => 'lft', + :conditions => c.conditions render :action => "projects", :layout => false if request.xhr? end + def plugins + @plugins = Redmine::Plugin.all + end + # Loads the default configuration # (roles, trackers, statuses, workflow, enumerations) def default_configuration @@ -78,8 +77,8 @@ class AdminController < ApplicationController @flags = { :default_admin_changed => User.find(:first, :conditions => ["login=? and hashed_password=?", 'admin', User.hash_password('admin')]).nil?, :file_repository_writable => File.writable?(Attachment.storage_path), + :plugin_assets_writable => File.writable?(Engines.public_directory), :rmagick_available => Object.const_defined?(:Magick) } - @plugins = Redmine::Plugin.registered_plugins end end diff --git a/app/controllers/application.rb b/app/controllers/application.rb index 238239c44..e8d0a85b7 100644 --- a/app/controllers/application.rb +++ b/app/controllers/application.rb @@ -46,7 +46,7 @@ class ApplicationController < ActionController::Base def find_current_user if session[:user_id] # existing session - (User.find_active(session[:user_id]) rescue nil) + (User.active.find(session[:user_id]) rescue nil) elsif cookies[:autologin] && Setting.autologin? # auto-login feature User.find_by_autologin_key(cookies[:autologin]) @@ -82,7 +82,7 @@ class ApplicationController < ActionController::Base def require_login if !User.current.logged? - redirect_to :controller => "account", :action => "login", :back_url => (request.relative_url_root + request.request_uri) + redirect_to :controller => "account", :action => "login", :back_url => url_for(params) return false end true @@ -126,10 +126,14 @@ class ApplicationController < ActionController::Base def redirect_back_or_default(default) back_url = CGI.unescape(params[:back_url].to_s) if !back_url.blank? - uri = URI.parse(back_url) - # do not redirect user to another host - if uri.relative? || (uri.host == request.host) - redirect_to(back_url) and return + begin + uri = URI.parse(back_url) + # do not redirect user to another host or to the login or register page + if (uri.relative? || (uri.host == request.host)) && !uri.path.match(%r{/(login|account/register)}) + redirect_to(back_url) and return + end + rescue URI::InvalidURIError + # redirect to default end end redirect_to default @@ -171,6 +175,7 @@ class ApplicationController < ActionController::Base # TODO: move to model def attach_files(obj, attachments) attached = [] + unsaved = [] if attachments && attachments.is_a?(Hash) attachments.each_value do |attachment| file = attachment['file'] @@ -179,7 +184,10 @@ class ApplicationController < ActionController::Base :file => file, :description => attachment['description'].to_s.strip, :author => User.current) - attached << a unless a.new_record? + a.new_record? ? (unsaved << a) : (attached << a) + end + if unsaved.any? + flash[:warning] = l(:warning_attachments_not_saved, unsaved.size) end end attached diff --git a/app/controllers/attachments_controller.rb b/app/controllers/attachments_controller.rb index 788bab94d..c55e8de25 100644 --- a/app/controllers/attachments_controller.rb +++ b/app/controllers/attachments_controller.rb @@ -1,5 +1,5 @@ -# redMine - project management software -# Copyright (C) 2006-2007 Jean-Philippe Lang +# Redmine - project management software +# 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 @@ -17,7 +17,11 @@ class AttachmentsController < ApplicationController before_filter :find_project - + before_filter :read_authorize, :except => :destroy + before_filter :delete_authorize, :only => :destroy + + verify :method => :post, :only => :destroy + def show if @attachment.is_diff? @diff = File.new(@attachment.diskfile, "rb").read @@ -25,31 +29,46 @@ class AttachmentsController < ApplicationController elsif @attachment.is_text? @content = File.new(@attachment.diskfile, "rb").read render :action => 'file' - elsif + else download end end def download - @attachment.increment_download if @attachment.container.is_a?(Version) + if @attachment.container.is_a?(Version) || @attachment.container.is_a?(Project) + @attachment.increment_download + end # images are sent inline send_file @attachment.diskfile, :filename => filename_for_content_disposition(@attachment.filename), :type => @attachment.content_type, :disposition => (@attachment.image? ? 'inline' : 'attachment') + + end + + def destroy + # Make sure association callbacks are called + @attachment.container.attachments.delete(@attachment) + redirect_to :back + rescue ::ActionController::RedirectBackError + redirect_to :controller => 'projects', :action => 'show', :id => @project end - + private def find_project @attachment = Attachment.find(params[:id]) # Show 404 if the filename in the url is wrong raise ActiveRecord::RecordNotFound if params[:filename] && params[:filename] != @attachment.filename - @project = @attachment.project - permission = @attachment.container.is_a?(Version) ? :view_files : "view_#{@attachment.container.class.name.underscore.pluralize}".to_sym - allowed = User.current.allowed_to?(permission, @project) - allowed ? true : (User.current.logged? ? render_403 : require_login) rescue ActiveRecord::RecordNotFound render_404 end + + def read_authorize + @attachment.visible? ? true : deny_access + end + + def delete_authorize + @attachment.deletable? ? true : deny_access + end end diff --git a/app/controllers/boards_controller.rb b/app/controllers/boards_controller.rb index 4532a88fe..55a9737f5 100644 --- a/app/controllers/boards_controller.rb +++ b/app/controllers/boards_controller.rb @@ -35,12 +35,14 @@ class BoardsController < ApplicationController end def show - sort_init "#{Message.table_name}.updated_on", "desc" - sort_update + sort_init 'updated_on', 'desc' + sort_update 'created_on' => "#{Message.table_name}.created_on", + 'replies' => "#{Message.table_name}.replies_count", + 'updated_on' => "#{Message.table_name}.updated_on" @topic_count = @board.topics.count @topic_pages = Paginator.new self, @topic_count, per_page_option, params['page'] - @topics = @board.topics.find :all, :order => "#{Message.table_name}.sticky DESC, #{sort_clause}", + @topics = @board.topics.find :all, :order => ["#{Message.table_name}.sticky DESC", sort_clause].compact.join(', '), :include => [:author, {:last_reply => :author}], :limit => @topic_pages.items_per_page, :offset => @topic_pages.current.offset diff --git a/app/controllers/custom_fields_controller.rb b/app/controllers/custom_fields_controller.rb index 4589996f1..5a79e4b7b 100644 --- a/app/controllers/custom_fields_controller.rb +++ b/app/controllers/custom_fields_controller.rb @@ -1,5 +1,5 @@ -# redMine - project management software -# Copyright (C) 2006 Jean-Philippe Lang +# Redmine - project management software +# Copyright (C) 2006-2009 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 @@ -19,34 +19,22 @@ class CustomFieldsController < ApplicationController before_filter :require_admin def index - list - render :action => 'list' unless request.xhr? - end - - def list @custom_fields_by_type = CustomField.find(:all).group_by {|f| f.class.name } @tab = params[:tab] || 'IssueCustomField' - render :action => "list", :layout => false if request.xhr? end def new - case params[:type] - when "IssueCustomField" - @custom_field = IssueCustomField.new(params[:custom_field]) - @custom_field.trackers = Tracker.find(params[:tracker_ids]) if params[:tracker_ids] - when "UserCustomField" - @custom_field = UserCustomField.new(params[:custom_field]) - when "ProjectCustomField" - @custom_field = ProjectCustomField.new(params[:custom_field]) - when "TimeEntryCustomField" - @custom_field = TimeEntryCustomField.new(params[:custom_field]) - else - redirect_to :action => 'list' - return - end + @custom_field = begin + if params[:type].to_s.match(/.+CustomField$/) + params[:type].to_s.constantize.new(params[:custom_field]) + end + rescue + end + redirect_to(:action => 'index') and return unless @custom_field.is_a?(CustomField) + if request.post? and @custom_field.save flash[:notice] = l(:notice_successful_create) - redirect_to :action => 'list', :tab => @custom_field.class.name + redirect_to :action => 'index', :tab => @custom_field.class.name end @trackers = Tracker.find(:all, :order => 'position') end @@ -54,11 +42,8 @@ class CustomFieldsController < ApplicationController def edit @custom_field = CustomField.find(params[:id]) if request.post? and @custom_field.update_attributes(params[:custom_field]) - if @custom_field.is_a? IssueCustomField - @custom_field.trackers = params[:tracker_ids] ? Tracker.find(params[:tracker_ids]) : [] - end flash[:notice] = l(:notice_successful_update) - redirect_to :action => 'list', :tab => @custom_field.class.name + redirect_to :action => 'index', :tab => @custom_field.class.name end @trackers = Tracker.find(:all, :order => 'position') end @@ -75,14 +60,14 @@ class CustomFieldsController < ApplicationController when 'lowest' @custom_field.move_to_bottom end if params[:position] - redirect_to :action => 'list', :tab => @custom_field.class.name + redirect_to :action => 'index', :tab => @custom_field.class.name end def destroy @custom_field = CustomField.find(params[:id]).destroy - redirect_to :action => 'list', :tab => @custom_field.class.name + redirect_to :action => 'index', :tab => @custom_field.class.name rescue flash[:error] = "Unable to delete custom field" - redirect_to :action => 'list' + redirect_to :action => 'index' end end diff --git a/app/controllers/documents_controller.rb b/app/controllers/documents_controller.rb index dbf9cd8e5..2d1c414c9 100644 --- a/app/controllers/documents_controller.rb +++ b/app/controllers/documents_controller.rb @@ -35,6 +35,7 @@ class DocumentsController < ApplicationController else @grouped = documents.group_by(&:category) end + @document = @project.documents.build render :layout => false if request.xhr? end @@ -70,11 +71,6 @@ class DocumentsController < ApplicationController Mailer.deliver_attachments_added(attachments) if !attachments.empty? && Setting.notified_events.include?('document_added') redirect_to :action => 'show', :id => @document end - - def destroy_attachment - @document.attachments.find(params[:attachment_id]).destroy - redirect_to :action => 'show', :id => @document - end private def find_project diff --git a/app/controllers/issue_relations_controller.rb b/app/controllers/issue_relations_controller.rb index 2ca3f0d68..8a41c3830 100644 --- a/app/controllers/issue_relations_controller.rb +++ b/app/controllers/issue_relations_controller.rb @@ -21,6 +21,9 @@ class IssueRelationsController < ApplicationController def new @relation = IssueRelation.new(params[:relation]) @relation.issue_from = @issue + if params[:relation] && !params[:relation][:issue_to_id].blank? + @relation.issue_to = Issue.visible.find_by_id(params[:relation][:issue_to_id]) + end @relation.save if request.post? respond_to do |format| format.html { redirect_to :controller => 'issues', :action => 'show', :id => @issue } diff --git a/app/controllers/issues_controller.rb b/app/controllers/issues_controller.rb index 04f78092b..557347bba 100644 --- a/app/controllers/issues_controller.rb +++ b/app/controllers/issues_controller.rb @@ -18,11 +18,11 @@ class IssuesController < ApplicationController menu_item :new_issue, :only => :new - before_filter :find_issue, :only => [:show, :edit, :reply, :destroy_attachment] + before_filter :find_issue, :only => [:show, :edit, :reply] before_filter :find_issues, :only => [:bulk_edit, :move, :destroy] - before_filter :find_project, :only => [:new, :update_form, :preview, :gantt, :calendar] - before_filter :authorize, :except => [:index, :changes, :preview, :update_form, :context_menu] - before_filter :find_optional_project, :only => [:index, :changes] + before_filter :find_project, :only => [:new, :update_form, :preview] + before_filter :authorize, :except => [:index, :changes, :gantt, :calendar, :preview, :update_form, :context_menu] + before_filter :find_optional_project, :only => [:index, :changes, :gantt, :calendar] accept_key_auth :index, :changes helper :journals @@ -30,8 +30,6 @@ class IssuesController < ApplicationController include ProjectsHelper helper :custom_fields include CustomFieldsHelper - helper :ifpdf - include IfpdfHelper helper :issue_relations include IssueRelationsHelper helper :watchers @@ -43,11 +41,13 @@ class IssuesController < ApplicationController include SortHelper include IssuesHelper helper :timelog + include Redmine::Export::PDF def index - sort_init "#{Issue.table_name}.id", "desc" - sort_update retrieve_query + sort_init 'id', 'desc' + sort_update({'id' => "#{Issue.table_name}.id"}.merge(@query.columns.inject({}) {|h, c| h[c.name.to_s] = c.sortable; h})) + if @query.valid? limit = per_page_option respond_to do |format| @@ -67,7 +67,7 @@ class IssuesController < ApplicationController format.html { render :template => 'issues/index.rhtml', :layout => !request.xhr? } format.atom { render_feed(@issues, :title => "#{@project || Setting.app_title}: #{l(:label_issue_plural)}") } format.csv { send_data(issues_to_csv(@issues, @project).read, :type => 'text/csv; header=present', :filename => 'export.csv') } - format.pdf { send_data(render(:template => 'issues/index.rfpdf', :layout => false), :type => 'application/pdf', :filename => 'export.pdf') } + format.pdf { send_data(issues_to_pdf(@issues, @project), :type => 'application/pdf', :filename => 'export.pdf') } end else # Send html if the query is not valid @@ -78,9 +78,10 @@ class IssuesController < ApplicationController end def changes - sort_init "#{Issue.table_name}.id", "desc" - sort_update retrieve_query + sort_init 'id', 'desc' + sort_update({'id' => "#{Issue.table_name}.id"}.merge(@query.columns.inject({}) {|h, c| h[c.name.to_s] = c.sortable; h})) + if @query.valid? @journals = Journal.find :all, :include => [ :details, :user, {:issue => [:project, :author, :tracker, :status]} ], :conditions => @query.statement, @@ -104,7 +105,7 @@ class IssuesController < ApplicationController respond_to do |format| format.html { render :template => 'issues/show.rhtml' } format.atom { render :action => 'changes', :layout => false, :content_type => 'application/atom+xml' } - format.pdf { send_data(render(:template => 'issues/show.rfpdf', :layout => false), :type => 'application/pdf', :filename => "#{@project.identifier}-#{@issue.id}.pdf") } + format.pdf { send_data(issue_to_pdf(@issue), :type => 'application/pdf', :filename => "#{@project.identifier}-#{@issue.id}.pdf") } end end @@ -121,7 +122,10 @@ class IssuesController < ApplicationController render :nothing => true, :layout => true return end - @issue.attributes = params[:issue] + if params[:issue].is_a?(Hash) + @issue.attributes = params[:issue] + @issue.watcher_user_ids = params[:issue]['watcher_user_ids'] if User.current.allowed_to?(:add_issue_watchers, @project) + end @issue.author = User.current default_status = IssueStatus.default @@ -143,7 +147,9 @@ class IssuesController < ApplicationController attach_files(@issue, params[:attachments]) flash[:notice] = l(:notice_successful_create) Mailer.deliver_issue_add(@issue) if Setting.notified_events.include?('issue_added') - redirect_to :controller => 'issues', :action => 'show', :id => @issue + call_hook(:controller_issues_new_after_save, { :params => params, :issue => @issue}) + redirect_to(params[:continue] ? { :action => 'new', :tracker_id => @issue.tracker } : + { :action => 'show', :id => @issue }) return end end @@ -176,9 +182,12 @@ class IssuesController < ApplicationController @time_entry.attributes = params[:time_entry] attachments = attach_files(@issue, params[:attachments]) attachments.each {|a| journal.details << JournalDetail.new(:property => 'attachment', :prop_key => a.id, :value => a.filename)} + + call_hook(:controller_issues_edit_before_save, { :params => params, :issue => @issue, :time_entry => @time_entry, :journal => journal}) + if (@time_entry.hours.nil? || @time_entry.valid?) && @issue.save # Log spend time - if current_role.allowed_to?(:log_time) + if User.current.allowed_to?(:log_time, @project) @time_entry.save end if !journal.new_record? @@ -186,6 +195,7 @@ class IssuesController < ApplicationController flash[:notice] = l(:notice_successful_update) Mailer.deliver_issue_edit(journal) if Setting.notified_events.include?('issue_updated') end + call_hook(:controller_issues_edit_after_save, { :params => params, :issue => @issue, :time_entry => @time_entry, :journal => journal}) redirect_to(params[:back_to] || {:action => 'show', :id => @issue}) end end @@ -222,6 +232,7 @@ class IssuesController < ApplicationController assigned_to = (params[:assigned_to_id].blank? || params[:assigned_to_id] == 'none') ? nil : User.find_by_id(params[:assigned_to_id]) category = (params[:category_id].blank? || params[:category_id] == 'none') ? nil : @project.issue_categories.find_by_id(params[:category_id]) fixed_version = (params[:fixed_version_id].blank? || params[:fixed_version_id] == 'none') ? nil : @project.versions.find_by_id(params[:fixed_version_id]) + custom_field_values = params[:custom_field_values] ? params[:custom_field_values].reject {|k,v| v.blank?} : nil unsaved_issue_ids = [] @issues.each do |issue| @@ -233,6 +244,7 @@ class IssuesController < ApplicationController issue.start_date = params[:start_date] unless params[:start_date].blank? issue.due_date = params[:due_date] unless params[:due_date].blank? issue.done_ratio = params[:done_ratio] unless params[:done_ratio].blank? + issue.custom_field_values = custom_field_values if custom_field_values && !custom_field_values.empty? call_hook(:controller_issues_bulk_edit_before_save, { :params => params, :issue => issue }) # Don't save any change to the issue if the user is not authorized to apply the requested status if (status.nil? || (issue.status.new_status_allowed_to?(status, current_role, issue.tracker) && issue.status = status)) && issue.save @@ -253,7 +265,8 @@ class IssuesController < ApplicationController end # Find potential statuses the user could be allowed to switch issues to @available_statuses = Workflow.find(:all, :include => :new_status, - :conditions => {:role_id => current_role.id}).collect(&:new_status).compact.uniq + :conditions => {:role_id => current_role.id}).collect(&:new_status).compact.uniq.sort + @custom_fields = @project.issue_custom_fields.select {|f| f.field_format == 'list'} end def move @@ -261,7 +274,7 @@ class IssuesController < ApplicationController # find projects to which the user is allowed to move the issue if User.current.admin? # admin is allowed to move issues to any active (visible) project - @allowed_projects = Project.find(:all, :conditions => Project.visible_by(User.current), :order => 'name') + @allowed_projects = Project.find(:all, :conditions => Project.visible_by(User.current)) else User.current.memberships.each {|m| @allowed_projects << m.project if m.role.allowed_to?(:move_issues)} end @@ -273,7 +286,7 @@ class IssuesController < ApplicationController unsaved_issue_ids = [] @issues.each do |issue| issue.init_journal(User.current) - unsaved_issue_ids << issue.id unless issue.move_to(@target_project, new_tracker) + unsaved_issue_ids << issue.id unless issue.move_to(@target_project, new_tracker, params[:copy_options]) end if unsaved_issue_ids.empty? flash[:notice] = l(:notice_successful_update) unless @issues.empty? @@ -310,17 +323,6 @@ class IssuesController < ApplicationController @issues.each(&:destroy) redirect_to :action => 'index', :project_id => @project end - - def destroy_attachment - a = @issue.attachments.find(params[:attachment_id]) - a.destroy - journal = @issue.init_journal(User.current) - journal.details << JournalDetail.new(:property => 'attachment', - :prop_key => a.id, - :old_value => a.filename) - journal.save - redirect_to :action => 'show', :id => @issue - end def gantt @gantt = Redmine::Helpers::Gantt.new(params) @@ -348,8 +350,8 @@ class IssuesController < ApplicationController respond_to do |format| format.html { render :template => "issues/gantt.rhtml", :layout => !request.xhr? } - format.png { send_data(@gantt.to_image, :disposition => 'inline', :type => 'image/png', :filename => "#{@project.identifier}-gantt.png") } if @gantt.respond_to?('to_image') - format.pdf { send_data(render(:template => "issues/gantt.rfpdf", :layout => false), :type => 'application/pdf', :filename => "#{@project.identifier}-gantt.pdf") } + format.png { send_data(@gantt.to_image, :disposition => 'inline', :type => 'image/png', :filename => "#{@project.nil? ? '' : "#{@project.identifier}-" }gantt.png") } if @gantt.respond_to?('to_image') + format.pdf { send_data(gantt_to_pdf(@gantt, @project), :type => 'application/pdf', :filename => "#{@project.nil? ? '' : "#{@project.identifier}-" }gantt.pdf") } end end @@ -450,9 +452,9 @@ private end def find_optional_project - return true unless params[:project_id] - @project = Project.find(params[:project_id]) - authorize + @project = Project.find(params[:project_id]) unless params[:project_id].blank? + allowed = User.current.allowed_to?({:controller => params[:controller], :action => params[:action]}, @project, :global => true) + allowed ? true : deny_access rescue ActiveRecord::RecordNotFound render_404 end diff --git a/app/controllers/journals_controller.rb b/app/controllers/journals_controller.rb index 6df54f098..d479855f2 100644 --- a/app/controllers/journals_controller.rb +++ b/app/controllers/journals_controller.rb @@ -22,6 +22,7 @@ class JournalsController < ApplicationController if request.post? @journal.update_attributes(:notes => params[:notes]) if params[:notes] @journal.destroy if @journal.details.empty? && @journal.notes.blank? + call_hook(:controller_journals_edit_post, { :journal => @journal, :params => params}) respond_to do |format| format.html { redirect_to :controller => 'issues', :action => 'show', :id => @journal.journalized_id } format.js { render :action => 'update' } diff --git a/app/controllers/messages_controller.rb b/app/controllers/messages_controller.rb index 79b4b616a..af39efb21 100644 --- a/app/controllers/messages_controller.rb +++ b/app/controllers/messages_controller.rb @@ -19,7 +19,7 @@ class MessagesController < ApplicationController menu_item :boards before_filter :find_board, :only => [:new, :preview] before_filter :find_message, :except => [:new, :preview] - before_filter :authorize, :except => :preview + before_filter :authorize, :except => [:preview, :edit, :destroy] verify :method => :post, :only => [ :reply, :destroy ], :redirect_to => { :action => :show } verify :xhr => true, :only => :quote @@ -30,7 +30,7 @@ class MessagesController < ApplicationController # Show a topic and its replies def show - @replies = @topic.children + @replies = @topic.children.find(:all, :include => [:author, :attachments, {:board => :project}]) @replies.reverse! if User.current.wants_comments_in_reverse_order? @reply = Message.new(:subject => "RE: #{@message.subject}") render :action => "show", :layout => false if request.xhr? @@ -65,7 +65,8 @@ class MessagesController < ApplicationController # Edit a message def edit - if params[:message] && User.current.allowed_to?(:edit_messages, @project) + render_403 and return false unless @message.editable_by?(User.current) + if params[:message] @message.locked = params[:message]['locked'] @message.sticky = params[:message]['sticky'] end @@ -78,6 +79,7 @@ class MessagesController < ApplicationController # Delete a messages def destroy + render_403 and return false unless @message.destroyable_by?(User.current) @message.destroy redirect_to @message.parent.nil? ? { :controller => 'boards', :action => 'show', :project_id => @project, :id => @board } : diff --git a/app/controllers/my_controller.rb b/app/controllers/my_controller.rb index 1cfa3e531..5e1b9d2c8 100644 --- a/app/controllers/my_controller.rb +++ b/app/controllers/my_controller.rb @@ -19,6 +19,7 @@ class MyController < ApplicationController before_filter :require_login helper :issues + helper :custom_fields BLOCKS = { 'issuesassignedtome' => :label_assigned_to_me_issues, 'issuesreportedbyme' => :label_reported_issues, diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb index fc33336a0..a75e4120a 100644 --- a/app/controllers/projects_controller.rb +++ b/app/controllers/projects_controller.rb @@ -29,12 +29,16 @@ class ProjectsController < ApplicationController before_filter :require_admin, :only => [ :add, :archive, :unarchive, :destroy ] accept_key_auth :activity + after_filter :only => [:add, :edit, :archive, :unarchive, :destroy] do |controller| + if controller.request.post? + controller.send :expire_action, :controller => 'welcome', :action => 'robots.txt' + end + end + helper :sort include SortHelper helper :custom_fields include CustomFieldsHelper - helper :ifpdf - include IfpdfHelper helper :issues helper IssuesHelper helper :queries @@ -45,17 +49,14 @@ class ProjectsController < ApplicationController # Lists visible projects def index - projects = Project.find :all, - :conditions => Project.visible_by(User.current), - :include => :parent respond_to do |format| format.html { - @project_tree = projects.group_by {|p| p.parent || p} - @project_tree.keys.each {|p| @project_tree[p] -= [p]} + @projects = Project.visible.find(:all, :order => 'lft') } format.atom { - render_feed(projects.sort_by(&:created_on).reverse.slice(0, Setting.feeds_limit.to_i), - :title => "#{Setting.app_title}: #{l(:label_project_latest)}") + projects = Project.visible.find(:all, :order => 'created_on DESC', + :limit => Setting.feeds_limit.to_i) + render_feed(projects, :title => "#{Setting.app_title}: #{l(:label_project_latest)}") } end end @@ -64,9 +65,6 @@ class ProjectsController < ApplicationController def add @issue_custom_fields = IssueCustomField.find(:all, :order => "#{CustomField.table_name}.position") @trackers = Tracker.all - @root_projects = Project.find(:all, - :conditions => "parent_id IS NULL AND status = #{Project::STATUS_ACTIVE}", - :order => 'name') @project = Project.new(params[:project]) if request.get? @project.identifier = Project.next_identifier if Setting.sequential_project_identifiers? @@ -76,6 +74,7 @@ class ProjectsController < ApplicationController else @project.enabled_module_names = params[:enabled_modules] if @project.save + @project.set_parent!(params[:project]['parent_id']) if User.current.admin? && params[:project].has_key?('parent_id') flash[:notice] = l(:notice_successful_create) redirect_to :controller => 'admin', :action => 'projects' end @@ -84,20 +83,26 @@ class ProjectsController < ApplicationController # Show @project def show + if params[:jump] + # try to redirect to the requested menu item + redirect_to_project_menu_item(@project, params[:jump]) && return + end + @members_by_role = @project.members.find(:all, :include => [:user, :role], :order => 'position').group_by {|m| m.role} - @subprojects = @project.children.find(:all, :conditions => Project.visible_by(User.current)) + @subprojects = @project.children.visible + @ancestors = @project.ancestors.visible @news = @project.news.find(:all, :limit => 5, :include => [ :author, :project ], :order => "#{News.table_name}.created_on DESC") @trackers = @project.rolled_up_trackers cond = @project.project_condition(Setting.display_subprojects_issues?) - Issue.visible_by(User.current) do - @open_issues_by_tracker = Issue.count(:group => :tracker, + + @open_issues_by_tracker = Issue.visible.count(:group => :tracker, :include => [:project, :status, :tracker], :conditions => ["(#{cond}) AND #{IssueStatus.table_name}.is_closed=?", false]) - @total_issues_by_tracker = Issue.count(:group => :tracker, + @total_issues_by_tracker = Issue.visible.count(:group => :tracker, :include => [:project, :status, :tracker], :conditions => cond) - end + TimeEntry.visible_by(User.current) do @total_hours = TimeEntry.sum(:hours, :include => :project, @@ -107,9 +112,6 @@ class ProjectsController < ApplicationController end def settings - @root_projects = Project.find(:all, - :conditions => ["parent_id IS NULL AND status = #{Project::STATUS_ACTIVE} AND id <> ?", @project.id], - :order => 'name') @issue_custom_fields = IssueCustomField.find(:all, :order => "#{CustomField.table_name}.position") @issue_category ||= IssueCategory.new @member ||= @project.members.new @@ -123,6 +125,7 @@ class ProjectsController < ApplicationController if request.post? @project.attributes = params[:project] if @project.save + @project.set_parent!(params[:project]['parent_id']) if User.current.admin? && params[:project].has_key?('parent_id') flash[:notice] = l(:notice_successful_update) redirect_to :action => 'settings', :id => @project else @@ -188,18 +191,26 @@ class ProjectsController < ApplicationController def add_file if request.post? - @version = @project.versions.find_by_id(params[:version_id]) - attachments = attach_files(@version, params[:attachments]) - Mailer.deliver_attachments_added(attachments) if !attachments.empty? && Setting.notified_events.include?('file_added') + container = (params[:version_id].blank? ? @project : @project.versions.find_by_id(params[:version_id])) + attachments = attach_files(container, params[:attachments]) + if !attachments.empty? && Setting.notified_events.include?('file_added') + Mailer.deliver_attachments_added(attachments) + end redirect_to :controller => 'projects', :action => 'list_files', :id => @project + return end @versions = @project.versions.sort end def list_files - sort_init "#{Attachment.table_name}.filename", "asc" - sort_update - @versions = @project.versions.find(:all, :include => :attachments, :order => sort_clause).sort.reverse + sort_init 'filename', 'asc' + sort_update 'filename' => "#{Attachment.table_name}.filename", + 'created_on' => "#{Attachment.table_name}.created_on", + 'size' => "#{Attachment.table_name}.filesize", + 'downloads' => "#{Attachment.table_name}.downloads" + + @containers = [ Project.find(@project.id, :include => :attachments, :order => sort_clause)] + @containers += @project.versions.find(:all, :include => :attachments, :order => sort_clause).sort.reverse render :layout => !request.xhr? end @@ -221,16 +232,19 @@ class ProjectsController < ApplicationController @days = Setting.activity_days_default.to_i if params[:from] - begin; @date_to = params[:from].to_date; rescue; end + begin; @date_to = params[:from].to_date + 1; rescue; end end @date_to ||= Date.today + 1 @date_from = @date_to - @days @with_subprojects = params[:with_subprojects].nil? ? Setting.display_subprojects_issues? : (params[:with_subprojects] == '1') + @author = (params[:user_id].blank? ? nil : User.active.find(params[:user_id])) - @activity = Redmine::Activity::Fetcher.new(User.current, :project => @project, :with_subprojects => @with_subprojects) + @activity = Redmine::Activity::Fetcher.new(User.current, :project => @project, + :with_subprojects => @with_subprojects, + :author => @author) @activity.scope_select {|t| !params["show_#{t}"].nil?} - @activity.default_scope! if @activity.scope.empty? + @activity.scope = (@author.nil? ? :default : :all) if @activity.scope.empty? events = @activity.events(@date_from, @date_to) @@ -240,10 +254,18 @@ class ProjectsController < ApplicationController render :layout => false if request.xhr? } format.atom { - title = (@activity.scope.size == 1) ? l("label_#{@activity.scope.first.singularize}_plural") : l(:label_activity) + title = l(:label_activity) + if @author + title = @author.name + elsif @activity.scope.size == 1 + title = l("label_#{@activity.scope.first.singularize}_plural") + end render_feed(events, :title => "#{@project || Setting.app_title}: #{title}") } end + + rescue ActiveRecord::RecordNotFound + render_404 end private diff --git a/app/controllers/reports_controller.rb b/app/controllers/reports_controller.rb index dd3ece930..bfe515778 100644 --- a/app/controllers/reports_controller.rb +++ b/app/controllers/reports_controller.rb @@ -61,7 +61,7 @@ class ReportsController < ApplicationController render :template => "reports/issue_report_details" when "subproject" @field = "project_id" - @rows = @project.active_children + @rows = @project.descendants.active @data = issues_by_subproject @report_title = l(:field_subproject) render :template => "reports/issue_report_details" @@ -72,7 +72,7 @@ class ReportsController < ApplicationController @categories = @project.issue_categories @assignees = @project.members.collect { |m| m.user } @authors = @project.members.collect { |m| m.user } - @subprojects = @project.active_children + @subprojects = @project.descendants.active issues_by_tracker issues_by_version issues_by_priority @@ -229,8 +229,8 @@ private #{Issue.table_name} i, #{IssueStatus.table_name} s where i.status_id=s.id - and i.project_id IN (#{@project.active_children.collect{|p| p.id}.join(',')}) - group by s.id, s.is_closed, i.project_id") if @project.active_children.any? + and i.project_id IN (#{@project.descendants.active.collect{|p| p.id}.join(',')}) + group by s.id, s.is_closed, i.project_id") if @project.descendants.active.any? @issues_by_subproject ||= [] end end diff --git a/app/controllers/repositories_controller.rb b/app/controllers/repositories_controller.rb index 78576856d..a90b57c3d 100644 --- a/app/controllers/repositories_controller.rb +++ b/app/controllers/repositories_controller.rb @@ -44,6 +44,21 @@ class RepositoriesController < ApplicationController render(:update) {|page| page.replace_html "tab-content-repository", :partial => 'projects/settings/repository'} end + def committers + @committers = @repository.committers + @users = @project.users + additional_user_ids = @committers.collect(&:last).collect(&:to_i) - @users.collect(&:id) + @users += User.find_all_by_id(additional_user_ids) unless additional_user_ids.empty? + @users.compact! + @users.sort! + if request.post? && params[:committers].is_a?(Hash) + # Build a hash with repository usernames as keys and corresponding user ids as values + @repository.committer_ids = params[:committers].values.inject({}) {|h, c| h[c.first] = c.last; h} + flash[:notice] = l(:notice_successful_update) + redirect_to :action => 'committers', :id => @project + end + end + def destroy @repository.destroy redirect_to :controller => 'projects', :action => 'settings', :id => @project, :tab => 'repository' @@ -73,7 +88,7 @@ class RepositoriesController < ApplicationController def changes @entry = @repository.entry(@path, @rev) show_error_not_found and return unless @entry - @changesets = @repository.changesets_for_path(@path) + @changesets = @repository.changesets_for_path(@path, :limit => Setting.repository_log_display_limit.to_i) @properties = @repository.properties(@path, @rev) end @@ -84,7 +99,8 @@ class RepositoriesController < ApplicationController params['page'] @changesets = @repository.changesets.find(:all, :limit => @changeset_pages.items_per_page, - :offset => @changeset_pages.current.offset) + :offset => @changeset_pages.current.offset, + :include => :user) respond_to do |format| format.html { render :layout => false if request.xhr? } @@ -111,6 +127,9 @@ class RepositoriesController < ApplicationController end def annotate + @entry = @repository.entry(@path, @rev) + show_error_not_found and return unless @entry + @annotate = @repository.scm.annotate(@path, @rev) render_error l(:error_scm_annotate) and return if @annotate.nil? || @annotate.empty? end diff --git a/app/controllers/roles_controller.rb b/app/controllers/roles_controller.rb index 72555e5b0..ab70ebf41 100644 --- a/app/controllers/roles_controller.rb +++ b/app/controllers/roles_controller.rb @@ -79,27 +79,6 @@ class RolesController < ApplicationController redirect_to :action => 'list' end - def workflow - @role = Role.find_by_id(params[:role_id]) - @tracker = Tracker.find_by_id(params[:tracker_id]) - - if request.post? - Workflow.destroy_all( ["role_id=? and tracker_id=?", @role.id, @tracker.id]) - (params[:issue_status] || []).each { |old, news| - news.each { |new| - @role.workflows.build(:tracker_id => @tracker.id, :old_status_id => old, :new_status_id => new) - } - } - if @role.save - flash[:notice] = l(:notice_successful_update) - redirect_to :action => 'workflow', :role_id => @role, :tracker_id => @tracker - end - end - @roles = Role.find(:all, :order => 'builtin, position') - @trackers = Tracker.find(:all, :order => 'position') - @statuses = IssueStatus.find(:all, :order => 'position') - end - def report @roles = Role.find(:all, :order => 'builtin, position') @permissions = Redmine::AccessControl.permissions.select { |p| !p.public? } diff --git a/app/controllers/search_controller.rb b/app/controllers/search_controller.rb index e6e66f05c..485d2349d 100644 --- a/app/controllers/search_controller.rb +++ b/app/controllers/search_controller.rb @@ -34,7 +34,7 @@ class SearchController < ApplicationController when 'my_projects' User.current.memberships.collect(&:project) when 'subprojects' - @project ? ([ @project ] + @project.active_children) : nil + @project ? (@project.self_and_descendants.active) : nil else @project end diff --git a/app/controllers/settings_controller.rb b/app/controllers/settings_controller.rb index 6482a3576..7d99a7266 100644 --- a/app/controllers/settings_controller.rb +++ b/app/controllers/settings_controller.rb @@ -5,19 +5,19 @@ # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. -# +# # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. -# +# # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. class SettingsController < ApplicationController before_filter :require_admin - + def index edit render :action => 'edit' @@ -39,17 +39,21 @@ class SettingsController < ApplicationController @options = {} @options[:user_format] = User::USER_FORMATS.keys.collect {|f| [User.current.name(f), f.to_s] } @deliveries = ActionMailer::Base.perform_deliveries + + @guessed_host_and_path = request.host_with_port.dup + @guessed_host_and_path << ('/'+ Redmine::Utils.relative_url_root.gsub(%r{^\/}, '')) unless Redmine::Utils.relative_url_root.blank? end - + def plugin - plugin_id = params[:id].to_sym - @plugin = Redmine::Plugin.registered_plugins[plugin_id] + @plugin = Redmine::Plugin.find(params[:id]) if request.post? - Setting["plugin_#{plugin_id}"] = params[:settings] + Setting["plugin_#{@plugin.id}"] = params[:settings] flash[:notice] = l(:notice_successful_update) - redirect_to :action => 'plugin', :id => params[:id] + redirect_to :action => 'plugin', :id => @plugin.id end @partial = @plugin.settings[:partial] - @settings = Setting["plugin_#{plugin_id}"] + @settings = Setting["plugin_#{@plugin.id}"] + rescue Redmine::PluginNotFound + render_404 end end diff --git a/app/controllers/sys_controller.rb b/app/controllers/sys_controller.rb index 8aff3bd15..da4b119a7 100644 --- a/app/controllers/sys_controller.rb +++ b/app/controllers/sys_controller.rb @@ -1,5 +1,5 @@ -# redMine - project management software -# Copyright (C) 2006-2007 Jean-Philippe Lang +# Redmine - project management software +# Copyright (C) 2006-2009 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 @@ -16,31 +16,35 @@ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. class SysController < ActionController::Base - wsdl_service_name 'Sys' - web_service_api SysApi - web_service_scaffold :invoke + before_filter :check_enabled - before_invocation :check_enabled - - # Returns the projects list, with their repositories - def projects_with_repository_enabled - Project.has_module(:repository).find(:all, :include => :repository, :order => 'identifier') + def projects + p = Project.active.has_module(:repository).find(:all, :include => :repository, :order => 'identifier') + render :xml => p.to_xml(:include => :repository) end - - # Registers a repository for the given project identifier - def repository_created(identifier, vendor, url) - project = Project.find_by_identifier(identifier) - # Do not create the repository if the project has already one - return 0 unless project && project.repository.nil? - logger.debug "Repository for #{project.name} was created" - repository = Repository.factory(vendor, :project => project, :url => url) - repository.save - repository.id || 0 + + def create_project_repository + project = Project.find(params[:id]) + if project.repository + render :nothing => true, :status => 409 + else + logger.info "Repository for #{project.name} was reported to be created by #{request.remote_ip}." + project.repository = Repository.factory(params[:vendor], params[:repository]) + if project.repository && project.repository.save + render :xml => project.repository, :status => 201 + else + render :nothing => true, :status => 422 + end + end end -protected + protected - def check_enabled(name, args) - Setting.sys_api_enabled? + def check_enabled + User.current = nil + unless Setting.sys_api_enabled? + render :nothing => 'Access denied. Repository management WS is disabled.', :status => 403 + return false + end end end diff --git a/app/controllers/timelog_controller.rb b/app/controllers/timelog_controller.rb index c333c02bb..58df1f5bc 100644 --- a/app/controllers/timelog_controller.rb +++ b/app/controllers/timelog_controller.rb @@ -138,7 +138,12 @@ class TimelogController < ApplicationController def details sort_init 'spent_on', 'desc' - sort_update + sort_update 'spent_on' => 'spent_on', + 'user' => 'user_id', + 'activity' => 'activity_id', + 'project' => "#{Project.table_name}.name", + 'issue' => 'issue_id', + 'hours' => 'hours' cond = ARCondition.new if @project.nil? diff --git a/app/controllers/trackers_controller.rb b/app/controllers/trackers_controller.rb index 8c02f9474..51e70ddf4 100644 --- a/app/controllers/trackers_controller.rb +++ b/app/controllers/trackers_controller.rb @@ -40,8 +40,10 @@ class TrackersController < ApplicationController end flash[:notice] = l(:notice_successful_create) redirect_to :action => 'list' + return end @trackers = Tracker.find :all, :order => 'position' + @projects = Project.find(:all) end def edit @@ -49,7 +51,9 @@ class TrackersController < ApplicationController if request.post? and @tracker.update_attributes(params[:tracker]) flash[:notice] = l(:notice_successful_update) redirect_to :action => 'list' + return end + @projects = Project.find(:all) end def move diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index d2564c2cb..ced17d667 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -30,18 +30,22 @@ class UsersController < ApplicationController def list sort_init 'login', 'asc' - sort_update + sort_update %w(login firstname lastname mail admin created_on last_login_on) @status = params[:status] ? params[:status].to_i : 1 - conditions = "status <> 0" - conditions = ["status=?", @status] unless @status == 0 + c = ARCondition.new(@status == 0 ? "status <> 0" : ["status = ?", @status]) + + unless params[:name].blank? + name = "%#{params[:name].strip.downcase}%" + c << ["LOWER(login) LIKE ? OR LOWER(firstname) LIKE ? OR LOWER(lastname) LIKE ?", name, name, name] + end - @user_count = User.count(:conditions => conditions) + @user_count = User.count(:conditions => c.conditions) @user_pages = Paginator.new self, @user_count, per_page_option, params['page'] @users = User.find :all,:order => sort_clause, - :conditions => conditions, + :conditions => c.conditions, :limit => @user_pages.items_per_page, :offset => @user_pages.current.offset @@ -79,7 +83,7 @@ class UsersController < ApplicationController end @auth_sources = AuthSource.find(:all) @roles = Role.find_all_givable - @projects = Project.find(:all, :order => 'name', :conditions => "status=#{Project::STATUS_ACTIVE}") - @user.projects + @projects = Project.active.find(:all, :order => 'lft') @membership ||= Member.new @memberships = @user.memberships end diff --git a/app/controllers/versions_controller.rb b/app/controllers/versions_controller.rb index 3a2221761..c269432f3 100644 --- a/app/controllers/versions_controller.rb +++ b/app/controllers/versions_controller.rb @@ -37,12 +37,6 @@ class VersionsController < ApplicationController redirect_to :controller => 'projects', :action => 'settings', :tab => 'versions', :id => @project end - def destroy_file - @version.attachments.find(params[:attachment_id]).destroy - flash[:notice] = l(:notice_successful_delete) - redirect_to :controller => 'projects', :action => 'list_files', :id => @project - end - def status_by respond_to do |format| format.html { render :action => 'show' } diff --git a/app/controllers/welcome_controller.rb b/app/controllers/welcome_controller.rb index b8108e8ac..c14ec4dbe 100644 --- a/app/controllers/welcome_controller.rb +++ b/app/controllers/welcome_controller.rb @@ -16,9 +16,15 @@ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. class WelcomeController < ApplicationController + caches_action :robots def index @news = News.latest User.current @projects = Project.latest User.current end + + def robots + @projects = Project.public.active + render :layout => false, :content_type => 'text/plain' + end end diff --git a/app/controllers/wiki_controller.rb b/app/controllers/wiki_controller.rb index 114010dff..1a480e4bd 100644 --- a/app/controllers/wiki_controller.rb +++ b/app/controllers/wiki_controller.rb @@ -19,8 +19,9 @@ require 'diff' class WikiController < ApplicationController before_filter :find_wiki, :authorize + before_filter :find_existing_page, :only => [:rename, :protect, :history, :diff, :annotate, :add_attachment, :destroy] - verify :method => :post, :only => [:destroy, :destroy_attachment, :protect], :redirect_to => { :action => :index } + verify :method => :post, :only => [:destroy, :protect], :redirect_to => { :action => :index } helper :attachments include AttachmentsHelper @@ -44,11 +45,11 @@ class WikiController < ApplicationController return end @content = @page.content_for_version(params[:version]) - if params[:export] == 'html' + if params[:format] == 'html' export = render_to_string :action => 'export', :layout => false send_data(export, :type => 'text/html', :filename => "#{@page.title}.html") return - elsif params[:export] == 'txt' + elsif params[:format] == 'txt' send_data(@content.text, :type => 'text/plain', :filename => "#{@page.title}.txt") return end @@ -63,7 +64,7 @@ class WikiController < ApplicationController @page.content = WikiContent.new(:page => @page) if @page.new_record? @content = @page.content_for_version(params[:version]) - @content.text = "h1. #{@page.pretty_title}" if @content.text.blank? + @content.text = initial_page_content(@page) if @content.text.blank? # don't keep previous comment @content.comments = nil if request.get? @@ -91,8 +92,7 @@ class WikiController < ApplicationController # rename a page def rename - @page = @wiki.find_page(params[:page]) - return render_403 unless editable? + return render_403 unless editable? @page.redirect_existing_links = true # used to display the *original* title if some AR validation errors occur @original_title = @page.pretty_title @@ -103,15 +103,12 @@ class WikiController < ApplicationController end def protect - page = @wiki.find_page(params[:page]) - page.update_attribute :protected, params[:protected] - redirect_to :action => 'index', :id => @project, :page => page.title + @page.update_attribute :protected, params[:protected] + redirect_to :action => 'index', :id => @project, :page => @page.title end # show page history def history - @page = @wiki.find_page(params[:page]) - @version_count = @page.content.versions.count @version_pages = Paginator.new self, @version_count, per_page_option, params['p'] # don't load text @@ -125,21 +122,19 @@ class WikiController < ApplicationController end def diff - @page = @wiki.find_page(params[:page]) @diff = @page.diff(params[:version], params[:version_from]) render_404 unless @diff end def annotate - @page = @wiki.find_page(params[:page]) @annotate = @page.annotate(params[:version]) + render_404 unless @annotate end # remove a wiki page and its history def destroy - @page = @wiki.find_page(params[:page]) - return render_403 unless editable? - @page.destroy if @page + return render_403 unless editable? + @page.destroy redirect_to :action => 'special', :id => @project, :page => 'Page_index' end @@ -181,19 +176,11 @@ class WikiController < ApplicationController end def add_attachment - @page = @wiki.find_page(params[:page]) return render_403 unless editable? attach_files(@page, params[:attachments]) redirect_to :action => 'index', :page => @page.title end - def destroy_attachment - @page = @wiki.find_page(params[:page]) - return render_403 unless editable? - @page.attachments.find(params[:attachment_id]).destroy - redirect_to :action => 'index', :page => @page.title - end - private def find_wiki @@ -204,8 +191,21 @@ private render_404 end + # Finds the requested page and returns a 404 error if it doesn't exist + def find_existing_page + @page = @wiki.find_page(params[:page]) + render_404 if @page.nil? + end + # Returns true if the current user is allowed to edit the page, otherwise false def editable?(page = @page) page.editable_by?(User.current) end + + # Returns the default content of a new wiki page + def initial_page_content(page) + helper = Redmine::WikiFormatting.helper_for(Setting.text_formatting) + extend helper unless self.instance_of?(helper) + helper.instance_method(:initial_page_content).bind(self).call(page) + end end diff --git a/app/controllers/workflows_controller.rb b/app/controllers/workflows_controller.rb new file mode 100644 index 000000000..380d4e752 --- /dev/null +++ b/app/controllers/workflows_controller.rb @@ -0,0 +1,45 @@ +# Redmine - project management software +# 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 +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class WorkflowsController < ApplicationController + before_filter :require_admin + + def index + @workflow_counts = Workflow.count_by_tracker_and_role + end + + def edit + @role = Role.find_by_id(params[:role_id]) + @tracker = Tracker.find_by_id(params[:tracker_id]) + + if request.post? + Workflow.destroy_all( ["role_id=? and tracker_id=?", @role.id, @tracker.id]) + (params[:issue_status] || []).each { |old, news| + news.each { |new| + @role.workflows.build(:tracker_id => @tracker.id, :old_status_id => old, :new_status_id => new) + } + } + if @role.save + flash[:notice] = l(:notice_successful_update) + redirect_to :action => 'edit', :role_id => @role, :tracker_id => @tracker + end + end + @roles = Role.find(:all, :order => 'builtin, position') + @trackers = Tracker.find(:all, :order => 'position') + @statuses = IssueStatus.find(:all, :order => 'position') + end +end diff --git a/app/helpers/admin_helper.rb b/app/helpers/admin_helper.rb index 1b41d8374..b49a5674c 100644 --- a/app/helpers/admin_helper.rb +++ b/app/helpers/admin_helper.rb @@ -17,7 +17,15 @@ module AdminHelper def project_status_options_for_select(selected) - options_for_select([[l(:label_all), "*"], + options_for_select([[l(:label_all), ''], [l(:status_active), 1]], selected) end + + def css_project_classes(project) + s = 'project' + s << ' root' if project.root? + s << ' child' if project.child? + s << (project.leaf? ? ' leaf' : ' parent') + s + end end diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index c3701b377..e7aa27033 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -5,26 +5,32 @@ # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. -# +# # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. -# +# # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. require 'coderay' require 'coderay/helpers/file_type' +require 'forwardable' +require 'cgi' module ApplicationHelper include Redmine::WikiFormatting::Macros::Definitions + include GravatarHelper::PublicMethods + + extend Forwardable + def_delegators :wiki_helper, :wikitoolbar_for, :heads_for_wiki_formatter def current_role @current_role ||= User.current.role_for_project(@project) end - + # Return true if user is authorized for controller/action, otherwise false def authorize_for(controller, action) User.current.allowed_to?({:controller => controller, :action => action}, @project) @@ -34,7 +40,7 @@ module ApplicationHelper def link_to_if_authorized(name, options = {}, html_options = nil, *parameters_for_method_reference) link_to(name, options, html_options, *parameters_for_method_reference) if authorize_for(options[:controller] || params[:controller], options[:action]) end - + # Display a link to remote if user is authorized def link_to_remote_if_authorized(name, options = {}, html_options = nil) url = options[:url] || {} @@ -42,17 +48,17 @@ module ApplicationHelper end # Display a link to user's account page - def link_to_user(user) - user ? link_to(user, :controller => 'account', :action => 'show', :id => user) : 'Anonymous' + def link_to_user(user, options={}) + (user && !user.anonymous?) ? link_to(user.name(options[:format]), :controller => 'account', :action => 'show', :id => user) : 'Anonymous' end - + def link_to_issue(issue, options={}) options[:class] ||= '' options[:class] << ' issue' options[:class] << ' closed' if issue.closed? link_to "#{issue.tracker.name} ##{issue.id}", {:controller => "issues", :action => "show", :id => issue}, options end - + # Generates a link to an attachment. # Options: # * :text - Link text (default to attachment filename) @@ -60,37 +66,37 @@ module ApplicationHelper def link_to_attachment(attachment, options={}) text = options.delete(:text) || attachment.filename action = options.delete(:download) ? 'download' : 'show' - + link_to(h(text), {:controller => 'attachments', :action => action, :id => attachment, :filename => attachment.filename }, options) end - + def toggle_link(name, id, options={}) onclick = "Element.toggle('#{id}'); " onclick << (options[:focus] ? "Form.Element.focus('#{options[:focus]}'); " : "this.blur(); ") onclick << "return false;" link_to(name, "#", :onclick => onclick) end - + def image_to_function(name, function, html_options = {}) html_options.symbolize_keys! - tag(:input, html_options.merge({ - :type => "image", :src => image_path(name), - :onclick => (html_options[:onclick] ? "#{html_options[:onclick]}; " : "") + "#{function};" + tag(:input, html_options.merge({ + :type => "image", :src => image_path(name), + :onclick => (html_options[:onclick] ? "#{html_options[:onclick]}; " : "") + "#{function};" })) end - + def prompt_to_remote(name, text, param, url, html_options = {}) html_options[:onclick] = "promptToRemote('#{text}', '#{param}', '#{url_for(url)}'); return false;" link_to name, {}, html_options end - + def format_date(date) return nil unless date # "Setting.date_format.size < 2" is a temporary fix (content of date_format setting changed) @date_format ||= (Setting.date_format.blank? || Setting.date_format.size < 2 ? l(:general_fmt_date) : Setting.date_format) date.strftime(@date_format) end - + def format_time(time, include_date = true) return nil unless time time = time.to_time if time.is_a?(String) @@ -100,43 +106,147 @@ module ApplicationHelper @time_format ||= (Setting.time_format.blank? ? l(:general_fmt_time) : Setting.time_format) include_date ? local.strftime("#{@date_format} #{@time_format}") : local.strftime(@time_format) end - + + def format_activity_title(text) + h(truncate_single_line(text, 100)) + end + + def format_activity_day(date) + date == Date.today ? l(:label_today).titleize : format_date(date) + end + + def format_activity_description(text) + h(truncate(text.to_s, 120).gsub(%r{[\r\n]*<(pre|code)>.*$}m, '...')).gsub(/[\r\n]+/, "
") + end + def distance_of_date_in_words(from_date, to_date = 0) from_date = from_date.to_date if from_date.respond_to?(:to_date) to_date = to_date.to_date if to_date.respond_to?(:to_date) distance_in_days = (to_date - from_date).abs lwr(:actionview_datehelper_time_in_words_day, distance_in_days) end - + def due_date_distance_in_words(date) if date l((date < Date.today ? :label_roadmap_overdue : :label_roadmap_due_in), distance_of_date_in_words(Date.today, date)) end end + + def render_page_hierarchy(pages, node=nil) + content = '' + if pages[node] + content << "\n" + end + content + end + # Renders flash messages + def render_flash_messages + s = '' + flash.each do |k,v| + s << content_tag('div', v, :class => "flash #{k}") + end + s + end + + # Renders the project quick-jump box + def render_project_jump_box + # Retrieve them now to avoid a COUNT query + projects = User.current.projects.all + if projects.any? + s = '' + s + end + end + + def project_tree_options_for_select(projects, options = {}) + s = '' + project_tree(projects) do |project, level| + name_prefix = (level > 0 ? (' ' * 2 * level + '» ') : '') + tag_options = {:value => project.id, :selected => ((project == options[:selected]) ? 'selected' : nil)} + tag_options.merge!(yield(project)) if block_given? + s << content_tag('option', name_prefix + h(project), tag_options) + end + s + end + + # Yields the given block for each project with its level in the tree + def project_tree(projects, &block) + ancestors = [] + projects.sort_by(&:lft).each do |project| + while (ancestors.any? && !project.is_descendant_of?(ancestors.last)) + ancestors.pop + end + yield project, ancestors.size + ancestors << project + end + end + + def project_nested_ul(projects, &block) + s = '' + if projects.any? + ancestors = [] + projects.sort_by(&:lft).each do |project| + if (ancestors.empty? || project.is_descendant_of?(ancestors.last)) + s << "\n" + end + end + s << "
  • " + s << yield(project).to_s + ancestors << project + end + s << ("
  • \n" * ancestors.size) + end + s + end + # Truncates and returns the string as a single line def truncate_single_line(string, *args) truncate(string, *args).gsub(%r{[\r\n]+}m, ' ') end - + def html_hours(text) text.gsub(%r{(\d+)\.(\d+)}, '\1.\2') end - - def authoring(created, author) - time_tag = content_tag('acronym', distance_of_time_in_words(Time.now, created), :title => format_time(created)) + + def authoring(created, author, options={}) + time_tag = @project.nil? ? content_tag('acronym', distance_of_time_in_words(Time.now, created), :title => format_time(created)) : + link_to(distance_of_time_in_words(Time.now, created), + {:controller => 'projects', :action => 'activity', :id => @project, :from => created.to_date}, + :title => format_time(created)) author_tag = (author.is_a?(User) && !author.anonymous?) ? link_to(h(author), :controller => 'account', :action => 'show', :id => author) : h(author || 'Anonymous') - l(:label_added_time_by, author_tag, time_tag) + l(options[:label] || :label_added_time_by, author_tag, time_tag) end - - def l_or_humanize(s) - l_has_string?("label_#{s}".to_sym) ? l("label_#{s}".to_sym) : s.to_s.humanize + + def l_or_humanize(s, options={}) + k = "#{options[:prefix]}#{s}".to_sym + l_has_string?(k) ? l(k) : s.to_s.humanize end - + def day_name(day) l(:general_day_names).split(',')[day-1] end - + def month_name(month) l(:actionview_datehelper_select_month_names).split(',')[month-1] end @@ -145,7 +255,7 @@ module ApplicationHelper type = CodeRay::FileType[name] type ? CodeRay.scan(content, type).html : h(content) end - + def to_path_param(path) path.to_s.split(%r{[/\\]}).select {|p| !p.blank?} end @@ -153,53 +263,56 @@ module ApplicationHelper def pagination_links_full(paginator, count=nil, options={}) page_param = options.delete(:page_param) || :page url_param = params.dup - # don't reuse params if filters are present - url_param.clear if url_param.has_key?(:set_filter) - - html = '' - html << link_to_remote(('« ' + l(:label_previous)), - {:update => 'content', - :url => url_param.merge(page_param => paginator.current.previous), - :complete => 'window.scrollTo(0,0)'}, - {:href => url_for(:params => url_param.merge(page_param => paginator.current.previous))}) + ' ' if paginator.current.previous - + # don't reuse query params if filters are present + url_param.merge!(:fields => nil, :values => nil, :operators => nil) if url_param.delete(:set_filter) + + html = '' + if paginator.current.previous + html << link_to_remote_content_update('« ' + l(:label_previous), url_param.merge(page_param => paginator.current.previous)) + ' ' + end + html << (pagination_links_each(paginator, options) do |n| - link_to_remote(n.to_s, - {:url => {:params => url_param.merge(page_param => n)}, - :update => 'content', - :complete => 'window.scrollTo(0,0)'}, - {:href => url_for(:params => url_param.merge(page_param => n))}) + link_to_remote_content_update(n.to_s, url_param.merge(page_param => n)) end || '') - html << ' ' + link_to_remote((l(:label_next) + ' »'), - {:update => 'content', - :url => url_param.merge(page_param => paginator.current.next), - :complete => 'window.scrollTo(0,0)'}, - {:href => url_for(:params => url_param.merge(page_param => paginator.current.next))}) if paginator.current.next - + if paginator.current.next + html << ' ' + link_to_remote_content_update((l(:label_next) + ' »'), url_param.merge(page_param => paginator.current.next)) + end + unless count.nil? - html << [" (#{paginator.current.first_item}-#{paginator.current.last_item}/#{count})", per_page_links(paginator.items_per_page)].compact.join(' | ') + html << [ + " (#{paginator.current.first_item}-#{paginator.current.last_item}/#{count})", + per_page_links(paginator.items_per_page) + ].compact.join(' | ') end - - html + + html end def per_page_links(selected=nil) url_param = params.dup url_param.clear if url_param.has_key?(:set_filter) - + links = Setting.per_page_options_array.collect do |n| - n == selected ? n : link_to_remote(n, {:update => "content", :url => params.dup.merge(:per_page => n)}, + n == selected ? n : link_to_remote(n, {:update => "content", + :url => params.dup.merge(:per_page => n), + :method => :get}, {:href => url_for(url_param.merge(:per_page => n))}) end links.size > 1 ? l(:label_display_per_page, links.join(', ')) : nil end - + def breadcrumb(*args) elements = args.flatten elements.any? ? content_tag('p', args.join(' » ') + ' » ', :class => 'breadcrumb') : nil end + def other_formats_links(&block) + concat('

    ' + l(:label_export_to), block.binding) + yield Redmine::Views::OtherFormatsBuilder.new(self) + concat('

    ', block.binding) + end + def html_title(*args) if args.empty? title = [] @@ -234,32 +347,30 @@ module ApplicationHelper raise ArgumentError, 'invalid arguments to textilizable' end return '' if text.blank? - + only_path = options.delete(:only_path) == false ? false : true # when using an image link, try to use an attachment, if possible attachments = options[:attachments] || (obj && obj.respond_to?(:attachments) ? obj.attachments : nil) - + if attachments - text = text.gsub(/!((\<|\=|\>)?(\([^\)]+\))?(\[[^\]]+\])?(\{[^\}]+\})?)(\S+\.(gif|jpg|jpeg|png))!/) do |m| + attachments = attachments.sort_by(&:created_on).reverse + text = text.gsub(/!((\<|\=|\>)?(\([^\)]+\))?(\[[^\]]+\])?(\{[^\}]+\})?)(\S+\.(bmp|gif|jpg|jpeg|png))!/i) do |m| style = $1 - filename = $6 - rf = Regexp.new(filename, Regexp::IGNORECASE) + filename = $6.downcase # search for the picture in attachments - if found = attachments.detect { |att| att.filename =~ rf } + if found = attachments.detect { |att| att.filename.downcase == filename } 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}!" + m end end end - - text = (Setting.text_formatting == 'textile') ? - Redmine::WikiFormatting.to_html(text) { |macro, args| exec_macro(macro, obj, args) } : - simple_format(auto_link(h(text))) + + text = Redmine::WikiFormatting.to_html(Setting.text_formatting, text) { |macro, args| exec_macro(macro, obj, args) } # different methods for formatting wiki links case options[:wiki_links] @@ -272,11 +383,11 @@ module ApplicationHelper else format_wiki_link = Proc.new {|project, title, anchor| url_for(:only_path => only_path, :controller => 'wiki', :action => 'index', :id => project, :page => title, :anchor => anchor) } end - + project = options[:project] || @project || (obj && obj.respond_to?(:project) ? obj.project : nil) - + # Wiki links - # + # # Examples: # [[mypage]] # [[mypage|mytext]] @@ -294,7 +405,7 @@ module ApplicationHelper page = $2 title ||= $1 if page.blank? end - + if link_project && link_project.wiki # extract anchor anchor = nil @@ -307,7 +418,7 @@ module ApplicationHelper :class => ('wiki-page' + (wiki_page ? '' : ' new'))) else # project or wiki doesn't exist - title || page + all end else all @@ -315,7 +426,7 @@ module ApplicationHelper end # Redmine links - # + # # Examples: # Issues: # #52 -> Link to issue #52 @@ -354,7 +465,7 @@ module ApplicationHelper oid = oid.to_i case prefix when nil - if issue = Issue.find_by_id(oid, :include => [:project, :status], :conditions => Project.visible_by(User.current)) + if issue = Issue.find_by_id(oid, :include => [:project, :status], :conditions => Project.visible_by(User.current)) link = link_to("##{oid}", {:only_path => only_path, :controller => 'issues', :action => 'show', :id => oid}, :class => (issue.closed? ? 'issue closed' : 'issue'), :title => "#{truncate(issue.subject, 100)} (#{issue.status.name})") @@ -422,10 +533,10 @@ module ApplicationHelper end leading + (link || "#{prefix}#{sep}#{oid}") end - + text end - + # Same as Rails' simple_format helper without using paragraphs def simple_format_without_paragraph(text) text.to_s. @@ -433,7 +544,7 @@ module ApplicationHelper gsub(/\n\n+/, "

    "). # 2+ newline -> 2 br gsub(/([^\n]\n)(?=[^\n])/, '\1
    ') # 1 newline -> br end - + def error_messages_for(object_name, options = {}) options = options.symbolize_keys object = instance_variable_get("@#{object_name}") @@ -451,14 +562,14 @@ module ApplicationHelper end # retrieve custom values error messages if object.errors[:custom_values] - object.custom_values.each do |v| + object.custom_values.each do |v| v.errors.each do |attr, msg| next if msg.nil? msg = msg.first if msg.is_a? Array full_messages << "« " + v.custom_field.name + " » " + l(msg) end end - end + end content_tag("div", content_tag( options[:header_tag] || "span", lwr(:gui_validation_error, full_messages.length) + ":" @@ -470,34 +581,35 @@ module ApplicationHelper "" end end - + def lang_options_for_select(blank=true) - (blank ? [["(auto)", ""]] : []) + + (blank ? [["(auto)", ""]] : []) + GLoc.valid_languages.collect{|lang| [ ll(lang.to_s, :general_lang_name), lang.to_s]}.sort{|x,y| x.last <=> y.last } end - + def label_tag_for(name, option_tags = nil, options = {}) label_text = l(("field_"+field.to_s.gsub(/\_id$/, "")).to_sym) + (options.delete(:required) ? @template.content_tag("span", " *", :class => "required"): "") content_tag("label", label_text) end - + def labelled_tabular_form_for(name, object, options, &proc) options[:html] ||= {} options[:html][:class] = 'tabular' unless options[:html].has_key?(:class) form_for(name, object, options.merge({ :builder => TabularFormBuilder, :lang => current_language}), &proc) end - + def back_url_hidden_field_tag back_url = params[:back_url] || request.env['HTTP_REFERER'] - hidden_field_tag('back_url', back_url) unless back_url.blank? + back_url = CGI.unescape(back_url.to_s) + hidden_field_tag('back_url', CGI.escape(back_url)) unless back_url.blank? end - + def check_all_links(form_name) link_to_function(l(:button_check_all), "checkAll('#{form_name}', true)") + " | " + - link_to_function(l(:button_uncheck_all), "checkAll('#{form_name}', false)") + link_to_function(l(:button_uncheck_all), "checkAll('#{form_name}', false)") end - + def progress_bar(pcts, options={}) pcts = [pcts, pcts] unless pcts.is_a?(Array) pcts[1] = pcts[1] - pcts[0] @@ -506,13 +618,13 @@ module ApplicationHelper legend = options[:legend] || '' content_tag('table', content_tag('tr', - (pcts[0] > 0 ? content_tag('td', '', :width => "#{pcts[0].floor}%;", :class => 'closed') : '') + - (pcts[1] > 0 ? content_tag('td', '', :width => "#{pcts[1].floor}%;", :class => 'done') : '') + - (pcts[2] > 0 ? content_tag('td', '', :width => "#{pcts[2].floor}%;", :class => 'todo') : '') + (pcts[0] > 0 ? content_tag('td', '', :style => "width: #{pcts[0].floor}%;", :class => 'closed') : '') + + (pcts[1] > 0 ? content_tag('td', '', :style => "width: #{pcts[1].floor}%;", :class => 'done') : '') + + (pcts[2] > 0 ? content_tag('td', '', :style => "width: #{pcts[2].floor}%;", :class => 'todo') : '') ), :class => 'progress', :style => "width: #{width};") + content_tag('p', legend, :class => 'pourcent') end - + def context_menu_link(name, url, options={}) options[:class] ||= '' if options.delete(:selected) @@ -528,7 +640,7 @@ module ApplicationHelper end link_to name, url, options end - + def calendar_for(field_id) include_calendar_headers_tags image_tag("calendar.png", {:id => "#{field_id}_trigger",:class => "calendar-trigger"}) + @@ -546,26 +658,44 @@ module ApplicationHelper end end end - - def wikitoolbar_for(field_id) - return '' unless Setting.text_formatting == 'textile' - - help_link = l(:setting_text_formatting) + ': ' + - link_to(l(:label_help), compute_public_path('wiki_syntax', 'help', 'html'), - :onclick => "window.open(\"#{ compute_public_path('wiki_syntax', 'help', 'html') }\", \"\", \"resizable=yes, location=no, width=300, height=640, menubar=no, status=no, scrollbars=yes\"); return false;") - javascript_include_tag('jstoolbar/jstoolbar') + - javascript_include_tag("jstoolbar/lang/jstoolbar-#{current_language}") + - javascript_tag("var toolbar = new jsToolBar($('#{field_id}')); toolbar.setHelpLink('#{help_link}'); toolbar.draw();") - end - def content_for(name, content = nil, &block) @has_content ||= {} @has_content[name] = true super(name, content, &block) end - + def has_content?(name) (@has_content && @has_content[name]) || false end + + # Returns the avatar image tag for the given +user+ if avatars are enabled + # +user+ can be a User or a string that will be scanned for an email address (eg. 'joe ') + def avatar(user, options = { }) + if Setting.gravatar_enabled? + email = nil + if user.respond_to?(:mail) + email = user.mail + elsif user.to_s =~ %r{<(.+?)>} + email = $1 + end + return gravatar(email.to_s.downcase, options) unless email.blank? rescue nil + end + end + + private + + def wiki_helper + helper = Redmine::WikiFormatting.helper_for(Setting.text_formatting) + extend helper + return self + end + + def link_to_remote_content_update(text, url_params) + link_to_remote(text, + {:url => url_params, :method => :get, :update => 'content', :complete => 'window.scrollTo(0,0)'}, + {:href => url_for(:params => url_params)} + ) + end + end diff --git a/app/helpers/attachments_helper.rb b/app/helpers/attachments_helper.rb index ebf417bab..29cdb9790 100644 --- a/app/helpers/attachments_helper.rb +++ b/app/helpers/attachments_helper.rb @@ -16,10 +16,15 @@ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. module AttachmentsHelper - # displays the links to a collection of attachments - def link_to_attachments(attachments, options = {}) - if attachments.any? - render :partial => 'attachments/links', :locals => {:attachments => attachments, :options => options} + # Displays view/delete links to the attachments of the given object + # Options: + # :author -- author names are not displayed if set to false + def link_to_attachments(container, options = {}) + options.assert_valid_keys(:author) + + if container.attachments.any? + options = {:deletable => container.attachments_deletable?, :author => true}.merge(options) + render :partial => 'attachments/links', :locals => {:attachments => container.attachments, :options => options} end end diff --git a/app/helpers/ifpdf_helper.rb b/app/helpers/ifpdf_helper.rb deleted file mode 100644 index 2cfca1929..000000000 --- a/app/helpers/ifpdf_helper.rb +++ /dev/null @@ -1,85 +0,0 @@ -# redMine - project management software -# Copyright (C) 2006 Jean-Philippe Lang -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -require 'iconv' -require 'rfpdf/chinese' - -module IfpdfHelper - - class IFPDF < FPDF - include GLoc - attr_accessor :footer_date - - def initialize(lang) - super() - set_language_if_valid lang - case current_language.to_s - when 'ja' - extend(PDF_Japanese) - AddSJISFont() - @font_for_content = 'SJIS' - @font_for_footer = 'SJIS' - when 'zh' - extend(PDF_Chinese) - AddGBFont() - @font_for_content = 'GB' - @font_for_footer = 'GB' - when 'zh-tw' - extend(PDF_Chinese) - AddBig5Font() - @font_for_content = 'Big5' - @font_for_footer = 'Big5' - else - @font_for_content = 'Arial' - @font_for_footer = 'Helvetica' - end - SetCreator("redMine #{Redmine::VERSION}") - SetFont(@font_for_content) - end - - def SetFontStyle(style, size) - SetFont(@font_for_content, style, size) - end - - def Cell(w,h=0,txt='',border=0,ln=0,align='',fill=0,link='') - @ic ||= Iconv.new(l(:general_pdf_encoding), 'UTF-8') - # these quotation marks are not correctly rendered in the pdf - txt = txt.gsub(/[“”]/, '"') if txt - txt = begin - # 0x5c char handling - txtar = txt.split('\\') - txtar << '' if txt[-1] == ?\\ - txtar.collect {|x| @ic.iconv(x)}.join('\\').gsub(/\\/, "\\\\\\\\") - rescue - txt - end || '' - super w,h,txt,border,ln,align,fill,link - end - - def Footer - SetFont(@font_for_footer, 'I', 8) - SetY(-15) - SetX(15) - Cell(0, 5, @footer_date, 0, 0, 'L') - SetY(-15) - SetX(-30) - Cell(0, 5, PageNo().to_s + '/{nb}', 0, 0, 'C') - end - - end - -end diff --git a/app/helpers/issues_helper.rb b/app/helpers/issues_helper.rb index 43acabd19..b2b85ee4c 100644 --- a/app/helpers/issues_helper.rb +++ b/app/helpers/issues_helper.rb @@ -33,6 +33,14 @@ module IssuesHelper "#{@cached_label_priority}: #{issue.priority.name}" end + # Returns a string of css classes that apply to the given issue + def css_issue_classes(issue) + s = "issue status-#{issue.status.position} priority-#{issue.priority.position}" + s << ' closed' if issue.closed? + s << ' overdue' if issue.overdue? + s + end + def sidebar_queries unless @sidebar_queries # User can see public queries and his own queries diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb index cd2e743fe..912450c1c 100644 --- a/app/helpers/projects_helper.rb +++ b/app/helpers/projects_helper.rb @@ -21,18 +21,6 @@ module ProjectsHelper link_to h(version.name), { :controller => 'versions', :action => 'show', :id => version }, options end - def format_activity_title(text) - h(truncate_single_line(text, 100)) - end - - def format_activity_day(date) - date == Date.today ? l(:label_today).titleize : format_date(date) - end - - def format_activity_description(text) - h(truncate(text.to_s, 250).gsub(%r{<(pre|code)>.*$}m, '...')) - end - def project_settings_tabs tabs = [{:name => 'info', :action => :edit_project, :partial => 'projects/edit', :label => :label_information_plural}, {:name => 'modules', :action => :select_project_modules, :partial => 'projects/settings/modules', :label => :label_module_plural}, @@ -45,4 +33,39 @@ module ProjectsHelper ] tabs.select {|tab| User.current.allowed_to?(tab[:action], @project)} end + + def parent_project_select_tag(project) + options = '' + project_tree_options_for_select(project.possible_parents, :selected => project.parent) + content_tag('select', options, :name => 'project[parent_id]') + end + + # Renders a tree of projects as a nested set of unordered lists + # The given collection may be a subset of the whole project tree + # (eg. some intermediate nodes are private and can not be seen) + def render_project_hierarchy(projects) + s = '' + if projects.any? + ancestors = [] + projects.each do |project| + if (ancestors.empty? || project.is_descendant_of?(ancestors.last)) + s << "
      \n" + else + ancestors.pop + s << "" + while (ancestors.any? && !project.is_descendant_of?(ancestors.last)) + ancestors.pop + s << "
    \n" + end + end + classes = (ancestors.empty? ? 'root' : 'child') + s << "
  • " + + link_to(h(project), {:controller => 'projects', :action => 'show', :id => project}, :class => "project #{User.current.member_of?(project) ? 'my-project' : nil}") + s << "
    #{textilizable(project.short_description, :project => project)}
    " unless project.description.blank? + s << "
    \n" + ancestors << project + end + s << ("
  • \n" * ancestors.size) + end + s + end end diff --git a/app/helpers/queries_helper.rb b/app/helpers/queries_helper.rb index a58c5d0ea..63d6a5356 100644 --- a/app/helpers/queries_helper.rb +++ b/app/helpers/queries_helper.rb @@ -22,8 +22,8 @@ module QueriesHelper end def column_header(column) - column.sortable ? sort_header_tag(column.sortable, :caption => column.caption, - :default_order => column.default_order) : + column.sortable ? sort_header_tag(column.name.to_s, :caption => column.caption, + :default_order => column.default_order) : content_tag('th', column.caption) end @@ -44,6 +44,8 @@ module QueriesHelper link_to(h(value), :controller => 'issues', :action => 'show', :id => issue) when :done_ratio progress_bar(value, :width => '80px') + when :fixed_version + link_to(h(value), { :controller => 'versions', :action => 'show', :id => issue.fixed_version_id }) else h(value) end diff --git a/app/helpers/repositories_helper.rb b/app/helpers/repositories_helper.rb index d798a2a5f..8310b83bb 100644 --- a/app/helpers/repositories_helper.rb +++ b/app/helpers/repositories_helper.rb @@ -22,6 +22,12 @@ module RepositoriesHelper txt.to_s[0,8] end + def truncate_at_line_break(text, length = 255) + if text + text.gsub(%r{^(.{#{length}}[^\n]*)\n.+$}m, '\\1...') + end + end + def render_properties(properties) unless properties.nil? || properties.empty? content = '' diff --git a/app/helpers/search_helper.rb b/app/helpers/search_helper.rb index cd96dbd3f..32ff16f67 100644 --- a/app/helpers/search_helper.rb +++ b/app/helpers/search_helper.rb @@ -44,7 +44,7 @@ module SearchHelper def project_select_tag options = [[l(:label_project_all), 'all']] options << [l(:label_my_projects), 'my_projects'] unless User.current.memberships.empty? - options << [l(:label_and_its_subprojects, @project.name), 'subprojects'] unless @project.nil? || @project.active_children.empty? + options << [l(:label_and_its_subprojects, @project.name), 'subprojects'] unless @project.nil? || @project.descendants.active.empty? options << [@project.name, ''] unless @project.nil? select_tag('scope', options_for_select(options, params[:scope].to_s)) if options.size > 1 end diff --git a/app/helpers/settings_helper.rb b/app/helpers/settings_helper.rb index 47e691334..35442f615 100644 --- a/app/helpers/settings_helper.rb +++ b/app/helpers/settings_helper.rb @@ -18,6 +18,7 @@ module SettingsHelper def administration_settings_tabs tabs = [{:name => 'general', :partial => 'settings/general', :label => :label_general}, + {:name => 'display', :partial => 'settings/display', :label => :label_display}, {:name => 'authentication', :partial => 'settings/authentication', :label => :label_authentication}, {:name => 'projects', :partial => 'settings/projects', :label => :label_project_plural}, {:name => 'issues', :partial => 'settings/issues', :label => :label_issue_tracking}, diff --git a/app/helpers/sort_helper.rb b/app/helpers/sort_helper.rb index 9ca5c11bd..f5e9bb494 100644 --- a/app/helpers/sort_helper.rb +++ b/app/helpers/sort_helper.rb @@ -67,23 +67,31 @@ module SortHelper # Updates the sort state. Call this in the controller prior to calling # sort_clause. - # - def sort_update() - if params[:sort_key] - sort = {:key => params[:sort_key], :order => params[:sort_order]} + # sort_keys can be either an array or a hash of allowed keys + def sort_update(sort_keys) + sort_key = params[:sort_key] + sort_key = nil unless (sort_keys.is_a?(Array) ? sort_keys.include?(sort_key) : sort_keys[sort_key]) + + sort_order = (params[:sort_order] == 'desc' ? 'DESC' : 'ASC') + + if sort_key + sort = {:key => sort_key, :order => sort_order} elsif session[@sort_name] sort = session[@sort_name] # Previous sort. else sort = @sort_default end session[@sort_name] = sort + + sort_column = (sort_keys.is_a?(Hash) ? sort_keys[sort[:key]] : sort[:key]) + @sort_clause = (sort_column.blank? ? nil : [sort_column].flatten.collect {|s| "#{s} #{sort[:order]}"}.join(',')) end # Returns an SQL sort clause corresponding to the current sort state. # Use this to sort the controller's table items collection. # def sort_clause() - session[@sort_name][:key] + ' ' + (session[@sort_name][:order] || 'ASC') + @sort_clause end # Returns a link which sorts by the named column. @@ -112,8 +120,11 @@ module SortHelper # don't reuse params if filters are present url_options = params.has_key?(:set_filter) ? sort_options : params.merge(sort_options) + # Add project_id to url_options + url_options = url_options.merge(:project_id => params[:project_id]) if params.has_key?(:project_id) + link_to_remote(caption, - {:update => "content", :url => url_options}, + {:update => "content", :url => url_options, :method => :get}, {:href => url_for(url_options)}) + (icon ? nbsp(2) + image_tag(icon) : '') end diff --git a/app/helpers/timelog_helper.rb b/app/helpers/timelog_helper.rb index f55a8ffe7..f068b4db8 100644 --- a/app/helpers/timelog_helper.rb +++ b/app/helpers/timelog_helper.rb @@ -16,6 +16,8 @@ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. module TimelogHelper + include ApplicationHelper + def render_timelog_breadcrumb links = [] links << link_to(l(:label_project_all), {:project_id => nil, :issue_id => nil}) @@ -81,7 +83,7 @@ module TimelogHelper csv << headers.collect {|c| begin; ic.iconv(c.to_s); rescue; c.to_s; end } # csv lines entries.each do |entry| - fields = [l_date(entry.spent_on), + fields = [format_date(entry.spent_on), entry.user, entry.activity, entry.project, diff --git a/app/helpers/users_helper.rb b/app/helpers/users_helper.rb index 5b113e880..b9e990d6e 100644 --- a/app/helpers/users_helper.rb +++ b/app/helpers/users_helper.rb @@ -25,15 +25,10 @@ module UsersHelper end # Options for the new membership projects combo-box - def projects_options_for_select(projects) + def options_for_membership_project_select(user, projects) options = content_tag('option', "--- #{l(:actionview_instancetag_blank_option)} ---") - projects_by_root = projects.group_by(&:root) - projects_by_root.keys.sort.each do |root| - options << content_tag('option', h(root.name), :value => root.id, :disabled => (!projects.include?(root))) - projects_by_root[root].sort.each do |project| - next if project == root - options << content_tag('option', '» ' + h(project.name), :value => project.id) - end + options << project_tree_options_for_select(projects) do |p| + {:disabled => (user.projects.include?(p))} end options end diff --git a/app/helpers/wiki_helper.rb b/app/helpers/wiki_helper.rb index 0a6b810de..c692c748b 100644 --- a/app/helpers/wiki_helper.rb +++ b/app/helpers/wiki_helper.rb @@ -16,22 +16,6 @@ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. module WikiHelper - - def render_page_hierarchy(pages, node=nil) - content = '' - if pages[node] - content << "
      \n" - pages[node].each do |page| - content << "
    • " - content << link_to(h(page.pretty_title), {:action => 'index', :page => page.title}, - :title => (page.respond_to?(:updated_on) ? l(:label_updated_time, distance_of_time_in_words(Time.now, page.updated_on)) : nil)) - content << "\n" + render_page_hierarchy(pages, page.id) if pages[page.id] - content << "
    • \n" - end - content << "
    \n" - end - content - end def html_diff(wdiff) words = wdiff.words.collect{|word| h(word)} diff --git a/app/apis/sys_api.rb b/app/helpers/workflows_helper.rb similarity index 53% rename from app/apis/sys_api.rb rename to app/helpers/workflows_helper.rb index fcee616b5..48ded305f 100644 --- a/app/apis/sys_api.rb +++ b/app/helpers/workflows_helper.rb @@ -1,5 +1,5 @@ -# redMine - project management software -# Copyright (C) 2006-2007 Jean-Philippe Lang +# Redmine - project management software +# 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 @@ -15,19 +15,5 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -class AWSProjectWithRepository < ActionWebService::Struct - member :id, :int - member :identifier, :string - member :name, :string - member :is_public, :bool - member :repository, Repository -end - -class SysApi < ActionWebService::API::Base - api_method :projects_with_repository_enabled, - :expects => [], - :returns => [[AWSProjectWithRepository]] - api_method :repository_created, - :expects => [:string, :string, :string], - :returns => [:int] +module WorkflowsHelper end diff --git a/app/models/attachment.rb b/app/models/attachment.rb index 95ba8491f..2ba75a3fd 100644 --- a/app/models/attachment.rb +++ b/app/models/attachment.rb @@ -30,12 +30,14 @@ class Attachment < ActiveRecord::Base acts_as_activity_provider :type => 'files', :permission => :view_files, + :author_key => :author_id, :find_options => {:select => "#{Attachment.table_name}.*", :joins => "LEFT JOIN #{Version.table_name} ON #{Attachment.table_name}.container_type='Version' AND #{Version.table_name}.id = #{Attachment.table_name}.container_id " + "LEFT JOIN #{Project.table_name} ON #{Version.table_name}.project_id = #{Project.table_name}.id"} acts_as_activity_provider :type => 'documents', :permission => :view_documents, + :author_key => :author_id, :find_options => {:select => "#{Attachment.table_name}.*", :joins => "LEFT JOIN #{Document.table_name} ON #{Attachment.table_name}.container_type='Document' AND #{Document.table_name}.id = #{Attachment.table_name}.container_id " + "LEFT JOIN #{Project.table_name} ON #{Document.table_name}.project_id = #{Project.table_name}.id"} @@ -70,7 +72,7 @@ class Attachment < ActiveRecord::Base File.open(diskfile, "wb") do |f| f.write(@temp_file.read) end - self.digest = Digest::MD5.hexdigest(File.read(diskfile)) + self.digest = self.class.digest(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 @@ -96,6 +98,14 @@ class Attachment < ActiveRecord::Base container.project end + def visible?(user=User.current) + container.attachments_visible?(user) + end + + def deletable?(user=User.current) + container.attachments_deletable?(user) + end + def image? self.filename =~ /\.(jpe?g|gif|png)$/i end @@ -131,4 +141,11 @@ private end df end + + # Returns the MD5 digest of the file at given path + def self.digest(filename) + File.open(filename, 'rb') do |f| + Digest::MD5.hexdigest(f.read) + end + end end diff --git a/app/models/auth_source.rb b/app/models/auth_source.rb index a0a2cdc5f..537ed2d43 100644 --- a/app/models/auth_source.rb +++ b/app/models/auth_source.rb @@ -38,7 +38,8 @@ class AuthSource < ActiveRecord::Base begin logger.debug "Authenticating '#{login}' against '#{source.name}'" if logger && logger.debug? attrs = source.authenticate(login, password) - rescue + rescue => e + logger.error "Error during authentication: #{e.message}" attrs = nil end return attrs if attrs diff --git a/app/models/auth_source_ldap.rb b/app/models/auth_source_ldap.rb index 6203a7c85..a619b2f85 100644 --- a/app/models/auth_source_ldap.rb +++ b/app/models/auth_source_ldap.rb @@ -91,6 +91,8 @@ class AuthSourceLdap < AuthSource end def self.get_attr(entry, attr_name) - entry[attr_name].is_a?(Array) ? entry[attr_name].first : entry[attr_name] + if !attr_name.blank? + entry[attr_name].is_a?(Array) ? entry[attr_name].first : entry[attr_name] + end end end diff --git a/app/models/changeset.rb b/app/models/changeset.rb index c4258c88b..0824a980e 100644 --- a/app/models/changeset.rb +++ b/app/models/changeset.rb @@ -1,5 +1,5 @@ -# redMine - project management software -# Copyright (C) 2006-2007 Jean-Philippe Lang +# Redmine - project management software +# 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 @@ -19,13 +19,13 @@ require 'iconv' class Changeset < ActiveRecord::Base belongs_to :repository + belongs_to :user has_many :changes, :dependent => :delete_all has_and_belongs_to_many :issues - acts_as_event :title => Proc.new {|o| "#{l(:label_revision)} #{o.revision}" + (o.comments.blank? ? '' : (': ' + o.comments))}, - :description => :comments, + acts_as_event :title => Proc.new {|o| "#{l(:label_revision)} #{o.revision}" + (o.short_comments.blank? ? '' : (': ' + o.short_comments))}, + :description => :long_comments, :datetime => :committed_on, - :author => :committer, :url => Proc.new {|o| {:controller => 'repositories', :action => 'revision', :id => o.repository.project_id, :rev => o.revision}} acts_as_searchable :columns => 'comments', @@ -34,6 +34,7 @@ class Changeset < ActiveRecord::Base :date_column => 'committed_on' acts_as_activity_provider :timestamp => "#{table_name}.committed_on", + :author_key => :user_id, :find_options => {:include => {:repository => :project}} validates_presence_of :repository_id, :revision, :committed_on, :commit_date @@ -57,6 +58,14 @@ class Changeset < ActiveRecord::Base repository.project end + def author + user || committer.to_s.split('<').first + end + + def before_create + self.user = repository.find_committer_user(committer) + end + def after_create scan_comment_for_issue_ids end @@ -96,12 +105,11 @@ class Changeset < ActiveRecord::Base issue.reload # don't change the status is the issue is closed next if issue.status.is_closed? - user = committer_user || User.anonymous csettext = "r#{self.revision}" if self.scmid && (! (csettext =~ /^r[0-9]+$/)) csettext = "commit:\"#{self.scmid}\"" end - journal = issue.init_journal(user, l(:text_status_changed_by_changeset, csettext)) + journal = issue.init_journal(user || User.anonymous, l(:text_status_changed_by_changeset, csettext)) issue.status = fix_status issue.done_ratio = done_ratio if done_ratio issue.save @@ -113,15 +121,13 @@ class Changeset < ActiveRecord::Base self.issues = referenced_issues.uniq end - - # Returns the Redmine User corresponding to the committer - def committer_user - if committer && committer.strip =~ /^([^<]+)(<(.*)>)?$/ - username, email = $1.strip, $3 - u = User.find_by_login(username) - u ||= User.find_by_mail(email) unless email.blank? - u - end + + def short_comments + @short_comments || split_comments.first + end + + def long_comments + @long_comments || split_comments.last end # Returns the previous changeset @@ -140,7 +146,14 @@ class Changeset < ActiveRecord::Base end private - + + def split_comments + comments =~ /\A(.+?)\r?\n(.*)$/m + @short_comments = $1 || comments + @long_comments = $2.to_s.strip + return @short_comments, @long_comments + end + def self.to_utf8(str) return str if /\A[\r\n\t\x20-\x7e]*\Z/n.match(str) # for us-ascii encoding = Setting.commit_logs_encoding.to_s.strip diff --git a/app/models/custom_field.rb b/app/models/custom_field.rb index 4759b714b..f277dc349 100644 --- a/app/models/custom_field.rb +++ b/app/models/custom_field.rb @@ -41,8 +41,6 @@ class CustomField < ActiveRecord::Base end def before_validation - # remove empty values - self.possible_values = self.possible_values.collect{|v| v unless v.empty?}.compact # make sure these fields are not searchable self.searchable = false if %w(int float date bool).include?(field_format) true @@ -59,11 +57,49 @@ class CustomField < ActiveRecord::Base v.custom_field.is_required = false errors.add(:default_value, :activerecord_error_invalid) unless v.valid? end + + # Makes possible_values accept a multiline string + def possible_values=(arg) + if arg.is_a?(Array) + write_attribute(:possible_values, arg.compact.collect(&:strip).select {|v| !v.blank?}) + else + self.possible_values = arg.to_s.split(/[\n\r]+/) + end + end + + # Returns a ORDER BY clause that can used to sort customized + # objects by their value of the custom field. + # Returns false, if the custom field can not be used for sorting. + def order_statement + case field_format + when 'string', 'text', 'list', 'date', 'bool' + # COALESCE is here to make sure that blank and NULL values are sorted equally + "COALESCE((SELECT cv_sort.value FROM #{CustomValue.table_name} cv_sort" + + " WHERE cv_sort.customized_type='#{self.class.customized_class.name}'" + + " AND cv_sort.customized_id=#{self.class.customized_class.table_name}.id" + + " AND cv_sort.custom_field_id=#{id} LIMIT 1), '')" + when 'int', 'float' + # Make the database cast values into numeric + # Postgresql will raise an error if a value can not be casted! + # CustomValue validations should ensure that it doesn't occur + "(SELECT CAST(cv_sort.value AS decimal(60,3)) FROM #{CustomValue.table_name} cv_sort" + + " WHERE cv_sort.customized_type='#{self.class.customized_class.name}'" + + " AND cv_sort.customized_id=#{self.class.customized_class.table_name}.id" + + " AND cv_sort.custom_field_id=#{id} AND cv_sort.value <> '' AND cv_sort.value IS NOT NULL LIMIT 1)" + else + nil + end + end def <=>(field) position <=> field.position end + def self.customized_class + self.name =~ /^(.+)CustomField$/ + begin; $1.constantize; rescue nil; end + end + # to move in project_custom_field def self.for_all find(:all, :conditions => ["is_for_all=?", true], :order => 'position') diff --git a/app/models/custom_value.rb b/app/models/custom_value.rb index 1d453baf0..1f662baa7 100644 --- a/app/models/custom_value.rb +++ b/app/models/custom_value.rb @@ -30,6 +30,18 @@ class CustomValue < ActiveRecord::Base self.value == '1' end + def editable? + custom_field.editable? + end + + def required? + custom_field.is_required? + end + + def to_s + value.to_s + end + protected def validate if value.blank? diff --git a/app/models/document.rb b/app/models/document.rb index 627a2418f..2ec99fe07 100644 --- a/app/models/document.rb +++ b/app/models/document.rb @@ -18,7 +18,7 @@ class Document < ActiveRecord::Base belongs_to :project belongs_to :category, :class_name => "Enumeration", :foreign_key => "category_id" - has_many :attachments, :as => :container, :dependent => :destroy + acts_as_attachable :delete_permission => :manage_documents acts_as_searchable :columns => ['title', "#{table_name}.description"], :include => :project acts_as_event :title => Proc.new {|o| "#{l(:label_document)}: #{o.title}"}, @@ -28,4 +28,10 @@ class Document < ActiveRecord::Base validates_presence_of :project, :title, :category validates_length_of :title, :maximum => 60 + + def after_initialize + if new_record? + self.category ||= Enumeration.default('DCAT') + end + end end diff --git a/app/models/enumeration.rb b/app/models/enumeration.rb index d32a0c049..e4b080be1 100644 --- a/app/models/enumeration.rb +++ b/app/models/enumeration.rb @@ -44,7 +44,9 @@ class Enumeration < ActiveRecord::Base end def before_save - Enumeration.update_all("is_default = #{connection.quoted_false}", {:opt => opt}) if is_default? + if is_default? && is_default_changed? + Enumeration.update_all("is_default = #{connection.quoted_false}", {:opt => opt}) + end end def objects_count diff --git a/app/models/issue.rb b/app/models/issue.rb index 4701e41f1..618c5597d 100644 --- a/app/models/issue.rb +++ b/app/models/issue.rb @@ -26,13 +26,13 @@ class Issue < ActiveRecord::Base belongs_to :category, :class_name => 'IssueCategory', :foreign_key => 'category_id' has_many :journals, :as => :journalized, :dependent => :destroy - has_many :attachments, :as => :container, :dependent => :destroy has_many :time_entries, :dependent => :delete_all has_and_belongs_to_many :changesets, :order => "#{Changeset.table_name}.committed_on ASC, #{Changeset.table_name}.id ASC" has_many :relations_from, :class_name => 'IssueRelation', :foreign_key => 'issue_from_id', :dependent => :delete_all has_many :relations_to, :class_name => 'IssueRelation', :foreign_key => 'issue_to_id', :dependent => :delete_all + acts_as_attachable :after_remove => :attachment_removed acts_as_customizable acts_as_watchable acts_as_searchable :columns => ['subject', "#{table_name}.description", "#{Journal.table_name}.notes"], @@ -40,15 +40,25 @@ class Issue < ActiveRecord::Base # sort by id so that limited eager loading doesn't break with postgresql :order_column => "#{table_name}.id" acts_as_event :title => Proc.new {|o| "#{o.tracker.name} ##{o.id}: #{o.subject}"}, - :url => Proc.new {|o| {:controller => 'issues', :action => 'show', :id => o.id}} + :url => Proc.new {|o| {:controller => 'issues', :action => 'show', :id => o.id}}, + :type => Proc.new {|o| 'issue' + (o.closed? ? ' closed' : '') } - acts_as_activity_provider :find_options => {:include => [:project, :author, :tracker]} + acts_as_activity_provider :find_options => {:include => [:project, :author, :tracker]}, + :author_key => :author_id - validates_presence_of :subject, :description, :priority, :project, :tracker, :author, :status + validates_presence_of :subject, :priority, :project, :tracker, :author, :status validates_length_of :subject, :maximum => 255 validates_inclusion_of :done_ratio, :in => 0..100 validates_numericality_of :estimated_hours, :allow_nil => true + named_scope :visible, lambda {|*args| { :include => :project, + :conditions => Project.allowed_to_condition(args.first || User.current, :view_issues) } } + + # Returns true if usr or current user is allowed to view the issue + def visible?(usr=nil) + (usr || User.current).allowed_to?(:view_issues, self.project) + end + def after_initialize if new_record? # set default values for new records only @@ -69,34 +79,43 @@ class Issue < ActiveRecord::Base self end - # Move an issue to a new project and tracker - def move_to(new_project, new_tracker = nil) + # Moves/copies an issue to a new project and tracker + # Returns the moved/copied issue on success, false on failure + def move_to(new_project, new_tracker = nil, options = {}) + options ||= {} + issue = options[:copy] ? self.clone : self transaction do - if new_project && project_id != new_project.id + if new_project && issue.project_id != new_project.id # delete issue relations unless Setting.cross_project_issue_relations? - self.relations_from.clear - self.relations_to.clear + issue.relations_from.clear + issue.relations_to.clear end # issue is moved to another project # reassign to the category with same name if any - new_category = category.nil? ? nil : new_project.issue_categories.find_by_name(category.name) - self.category = new_category - self.fixed_version = nil - self.project = new_project + new_category = issue.category.nil? ? nil : new_project.issue_categories.find_by_name(issue.category.name) + issue.category = new_category + issue.fixed_version = nil + issue.project = new_project end if new_tracker - self.tracker = new_tracker + issue.tracker = new_tracker + end + if options[:copy] + issue.custom_field_values = self.custom_field_values.inject({}) {|h,v| h[v.custom_field_id] = v.value; h} + issue.status = self.status end - if save - # Manually update project_id on related time entries - TimeEntry.update_all("project_id = #{new_project.id}", {:issue_id => id}) + if issue.save + unless options[:copy] + # Manually update project_id on related time entries + TimeEntry.update_all("project_id = #{new_project.id}", {:issue_id => id}) + end else - rollback_db_transaction + Issue.connection.rollback_db_transaction return false end end - return true + return issue end def priority_id=(pid) @@ -194,6 +213,11 @@ class Issue < ActiveRecord::Base self.status.is_closed? end + # Returns true if the issue is overdue + def overdue? + !due_date.nil? && (due_date < Date.today) && !status.is_closed? + end + # Users the issue can be assigned to def assignable_users project.assignable_users @@ -251,13 +275,18 @@ class Issue < ActiveRecord::Base @soonest_start ||= relations_to.collect{|relation| relation.successor_soonest_start}.compact.min end - def self.visible_by(usr) - with_scope(:find => { :conditions => Project.visible_by(usr) }) do - yield - end - end - def to_s "#{tracker} ##{id}: #{subject}" end + + private + + # Callback on attachment deletion + def attachment_removed(obj) + journal = init_journal(User.current) + journal.details << JournalDetail.new(:property => 'attachment', + :prop_key => obj.id, + :old_value => obj.filename) + journal.save + end end diff --git a/app/models/issue_relation.rb b/app/models/issue_relation.rb index 49329e0bb..13e14cccc 100644 --- a/app/models/issue_relation.rb +++ b/app/models/issue_relation.rb @@ -35,6 +35,8 @@ class IssueRelation < ActiveRecord::Base validates_numericality_of :delay, :allow_nil => true validates_uniqueness_of :issue_to_id, :scope => :issue_from_id + attr_protected :issue_from_id, :issue_to_id + def validate if issue_from && issue_to errors.add :issue_to_id, :activerecord_error_invalid if issue_from_id == issue_to_id diff --git a/app/models/issue_status.rb b/app/models/issue_status.rb index ddff9c005..16c7bce91 100644 --- a/app/models/issue_status.rb +++ b/app/models/issue_status.rb @@ -25,8 +25,8 @@ class IssueStatus < ActiveRecord::Base validates_length_of :name, :maximum => 30 validates_format_of :name, :with => /^[\w\s\'\-]*$/i - def before_save - IssueStatus.update_all "is_default=#{connection.quoted_false}" if self.is_default? + def after_save + IssueStatus.update_all("is_default=#{connection.quoted_false}", ['id <> ?', id]) if self.is_default? end # Returns the default status for new issues diff --git a/app/models/journal.rb b/app/models/journal.rb index 71a51290b..72e7eb91c 100644 --- a/app/models/journal.rb +++ b/app/models/journal.rb @@ -33,6 +33,7 @@ class Journal < ActiveRecord::Base acts_as_activity_provider :type => 'issues', :permission => :view_issues, + :author_key => :user_id, :find_options => {:include => [{:issue => :project}, :details, :user], :conditions => "#{Journal.table_name}.journalized_type = 'Issue' AND" + " (#{JournalDetail.table_name}.prop_key = 'status_id' OR #{Journal.table_name}.notes <> '')"} diff --git a/app/models/mail_handler.rb b/app/models/mail_handler.rb index 2f1eba3e9..8e19bcdf4 100644 --- a/app/models/mail_handler.rb +++ b/app/models/mail_handler.rb @@ -16,6 +16,7 @@ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. class MailHandler < ActionMailer::Base + include ActionView::Helpers::SanitizeHelper class UnauthorizedAction < StandardError; end class MissingInformation < StandardError; end @@ -31,7 +32,7 @@ class MailHandler < ActionMailer::Base @@handler_options[:allow_override] ||= [] # Project needs to be overridable if not specified @@handler_options[:allow_override] << 'project' unless @@handler_options[:issue].has_key?(:project) - # Status needs to be overridable if not specified + # Status overridable by default @@handler_options[:allow_override] << 'status' unless @@handler_options[:issue].has_key?(:status) super email end @@ -39,7 +40,7 @@ class MailHandler < ActionMailer::Base # Processes incoming emails def receive(email) @email = email - @user = User.find_active(:first, :conditions => {:mail => email.from.first}) + @user = User.active.find_by_mail(email.from.first.to_s.strip) unless @user # Unknown user => the email is ignored # TODO: ability to create the user's account @@ -52,11 +53,24 @@ class MailHandler < ActionMailer::Base private + MESSAGE_ID_RE = %r{^ user, :project => project, :tracker => tracker, :category => category, :priority => priority, :status => status) - issue.subject = email.subject.chomp - issue.description = email.plain_text_body.chomp + issue = Issue.new(:author => user, :project => project, :tracker => tracker, :category => category, :priority => priority) + # check workflow + if status && issue.new_statuses_allowed_to(user).include?(status) + issue.status = status + end + issue.subject = email.subject.chomp.toutf8 + issue.description = plain_text_body + # custom fields + issue.custom_field_values = issue.available_custom_fields.inject({}) do |h, c| + if value = get_keyword(c.name, :override => true) + h[c.id] = value + end + h + end issue.save! add_attachments(issue) logger.info "MailHandler: issue ##{issue.id} created by #{user}" if logger && logger.info + # add To and Cc as watchers + add_watchers(issue) + # send notification after adding watchers so that they can reply to Redmine Mailer.deliver_issue_add(issue) if Setting.notified_events.include?('issue_added') issue end @@ -102,7 +130,7 @@ class MailHandler < ActionMailer::Base end # Adds a note to an existing issue - def receive_issue_update(issue_id) + def receive_issue_reply(issue_id) status = (get_keyword(:status) && IssueStatus.find_by_name(get_keyword(:status))) issue = Issue.find_by_id(issue_id) @@ -112,15 +140,45 @@ class MailHandler < ActionMailer::Base raise UnauthorizedAction unless status.nil? || user.allowed_to?(:edit_issues, issue.project) # add the note - journal = issue.init_journal(user, email.plain_text_body.chomp) + journal = issue.init_journal(user, plain_text_body) add_attachments(issue) - issue.status = status unless status.nil? + # check workflow + if status && issue.new_statuses_allowed_to(user).include?(status) + issue.status = status + end issue.save! logger.info "MailHandler: issue ##{issue.id} updated by #{user}" if logger && logger.info Mailer.deliver_issue_edit(journal) if Setting.notified_events.include?('issue_updated') journal end + # Reply will be added to the issue + def receive_journal_reply(journal_id) + journal = Journal.find_by_id(journal_id) + if journal && journal.journalized_type == 'Issue' + receive_issue_reply(journal.journalized_id) + end + end + + # Receives a reply to a forum message + def receive_message_reply(message_id) + message = Message.find_by_id(message_id) + if message + message = message.root + if user.allowed_to?(:add_messages, message.project) && !message.locked? + reply = Message.new(:subject => email.subject.gsub(%r{^.*msg\d+\]}, '').strip, + :content => plain_text_body) + reply.author = user + reply.board = message.board + message.children << reply + add_attachments(reply) + reply + else + raise UnauthorizedAction + end + end + end + def add_attachments(obj) if email.has_attachments? email.attachments.each do |attachment| @@ -132,22 +190,50 @@ class MailHandler < ActionMailer::Base end end - def get_keyword(attr) - if @@handler_options[:allow_override].include?(attr.to_s) && email.plain_text_body =~ /^#{attr}:[ \t]*(.+)$/i - $1.strip - elsif !@@handler_options[:issue][attr].blank? - @@handler_options[:issue][attr] + # Adds To and Cc as watchers of the given object if the sender has the + # appropriate permission + def add_watchers(obj) + if user.allowed_to?("add_#{obj.class.name.underscore}_watchers".to_sym, obj.project) + addresses = [email.to, email.cc].flatten.compact.uniq.collect {|a| a.strip.downcase} + unless addresses.empty? + watchers = User.active.find(:all, :conditions => ['LOWER(mail) IN (?)', addresses]) + watchers.each {|w| obj.add_watcher(w)} + end end end -end - -class TMail::Mail - # Returns body of the first plain text part found if any + + def get_keyword(attr, options={}) + @keywords ||= {} + if @keywords.has_key?(attr) + @keywords[attr] + else + @keywords[attr] = begin + if (options[:override] || @@handler_options[:allow_override].include?(attr.to_s)) && plain_text_body.gsub!(/^#{attr}:[ \t]*(.+)\s*$/i, '') + $1.strip + elsif !@@handler_options[:issue][attr].blank? + @@handler_options[:issue][attr] + end + end + end + end + + # Returns the text/plain part of the email + # If not found (eg. HTML-only email), returns the body with tags removed def plain_text_body return @plain_text_body unless @plain_text_body.nil? - p = self.parts.collect {|c| (c.respond_to?(:parts) && !c.parts.empty?) ? c.parts : c}.flatten - plain = p.detect {|c| c.content_type == 'text/plain'} - @plain_text_body = plain.nil? ? self.body : plain.body + parts = @email.parts.collect {|c| (c.respond_to?(:parts) && !c.parts.empty?) ? c.parts : c}.flatten + if parts.empty? + parts << @email + end + plain_text_part = parts.detect {|p| p.content_type == 'text/plain'} + if plain_text_part.nil? + # no text/plain part found, assuming html-only email + # strip html tags and remove doctype directive + @plain_text_body = strip_tags(@email.body.to_s) + @plain_text_body.gsub! %r{^ issue.project.identifier, 'Issue-Id' => issue.id, 'Issue-Author' => issue.author.login redmine_headers 'Issue-Assignee' => issue.assigned_to.login if issue.assigned_to - recipients issue.recipients + message_id issue + recipients issue.recipients + cc(issue.watcher_recipients - @recipients) subject "[#{issue.project.name} - #{issue.tracker.name} ##{issue.id}] (#{issue.status.name}) #{issue.subject}" body :issue => issue, :issue_url => url_for(:controller => 'issues', :action => 'show', :id => issue) @@ -39,6 +41,9 @@ class Mailer < ActionMailer::Base 'Issue-Id' => issue.id, 'Issue-Author' => issue.author.login redmine_headers 'Issue-Assignee' => issue.assigned_to.login if issue.assigned_to + message_id journal + references issue + @author = journal.user recipients issue.recipients # Watchers in cc cc(issue.watcher_recipients - @recipients) @@ -50,16 +55,16 @@ class Mailer < ActionMailer::Base :journal => journal, :issue_url => url_for(:controller => 'issues', :action => 'show', :id => issue) end - + def reminder(user, issues, days) set_language_if_valid user.language recipients user.mail subject l(:mail_subject_reminder, issues.size) body :issues => issues, :days => days, - :issues_url => url_for(:controller => 'issues', :action => 'index', :set_filter => 1, :assigned_to_id => user.id, :sort_key => 'issues.due_date', :sort_order => 'asc') + :issues_url => url_for(:controller => 'issues', :action => 'index', :set_filter => 1, :assigned_to_id => user.id, :sort_key => 'due_date', :sort_order => 'asc') end - + def document_added(document) redmine_headers 'Project' => document.project.identifier recipients document.project.recipients @@ -67,12 +72,15 @@ class Mailer < ActionMailer::Base body :document => document, :document_url => url_for(:controller => 'documents', :action => 'show', :id => document) end - + def attachments_added(attachments) container = attachments.first.container added_to = '' added_to_url = '' case container.class.name + when 'Project' + added_to_url = url_for(:controller => 'projects', :action => 'list_files', :id => container) + added_to = "#{l(:label_project)}: #{container}" when 'Version' added_to_url = url_for(:controller => 'projects', :action => 'list_files', :id => container.project_id) added_to = "#{l(:label_version)}: #{container.name}" @@ -90,6 +98,7 @@ class Mailer < ActionMailer::Base def news_added(news) redmine_headers 'Project' => news.project.identifier + message_id news recipients news.project.recipients subject "[#{news.project.name}] #{l(:label_news)}: #{news.title}" body :news => news, @@ -99,12 +108,14 @@ class Mailer < ActionMailer::Base def message_posted(message, recipients) redmine_headers 'Project' => message.project.identifier, 'Topic-Id' => (message.parent_id || message.id) + message_id message + references message.parent unless message.parent.nil? recipients(recipients) - subject "[#{message.board.project.name} - #{message.board.name}] #{message.subject}" + subject "[#{message.board.project.name} - #{message.board.name} - msg#{message.root.id}] #{message.subject}" body :message => message, :message_url => url_for(:controller => 'messages', :action => 'show', :board_id => message.board_id, :id => message.root) end - + def account_information(user, password) set_language_if_valid user.language recipients user.mail @@ -113,10 +124,10 @@ class Mailer < ActionMailer::Base :password => password, :login_url => url_for(:controller => 'account', :action => 'login') end - + def account_activation_request(user) # Send the email to all active administrators - recipients User.find_active(:all, :conditions => {:admin => true}).collect { |u| u.mail }.compact + recipients User.active.find(:all, :conditions => {:admin => true}).collect { |u| u.mail }.compact subject l(:mail_subject_account_activation_request, Setting.app_title) body :user => user, :url => url_for(:controller => 'users', :action => 'index', :status => User::STATUS_REGISTERED, :sort_key => 'created_on', :sort_order => 'desc') @@ -128,7 +139,7 @@ class Mailer < ActionMailer::Base subject l(:mail_subject_lost_password, Setting.app_title) body :token => token, :url => url_for(:controller => 'account', :action => 'lost_password', :token => token.value) - end + end def register(token) set_language_if_valid(token.user.language) @@ -137,7 +148,7 @@ class Mailer < ActionMailer::Base body :token => token, :url => url_for(:controller => 'account', :action => 'activate', :token => token.value) end - + def test(user) set_language_if_valid(user.language) recipients user.mail @@ -148,12 +159,20 @@ class Mailer < ActionMailer::Base # Overrides default deliver! method to prevent from sending an email # with no recipient, cc or bcc def deliver!(mail = @mail) - return false if (recipients.nil? || recipients.empty?) && + return false if (recipients.nil? || recipients.empty?) && (cc.nil? || cc.empty?) && (bcc.nil? || bcc.empty?) - super + + # Set Message-Id and References + if @message_id_object + mail.message_id = self.class.message_id_for(@message_id_object) + end + if @references_objects + mail.references = @references_objects.collect {|o| self.class.message_id_for(o)} + end + super(mail) end - + # Sends reminders to issue assignees # Available options: # * :days => how many days in the future to remind about (defaults to 7) @@ -163,13 +182,13 @@ class Mailer < ActionMailer::Base days = options[:days] || 7 project = options[:project] ? Project.find(options[:project]) : nil tracker = options[:tracker] ? Tracker.find(options[:tracker]) : nil - + s = ARCondition.new ["#{IssueStatus.table_name}.is_closed = ? AND #{Issue.table_name}.due_date <= ?", false, days.day.from_now.to_date] s << "#{Issue.table_name}.assigned_to_id IS NOT NULL" s << "#{Project.table_name}.status = #{Project::STATUS_ACTIVE}" s << "#{Issue.table_name}.project_id = #{project.id}" if project s << "#{Issue.table_name}.tracker_id = #{tracker.id}" if tracker - + issues_by_assignee = Issue.find(:all, :include => [:status, :assigned_to, :project, :tracker], :conditions => s.conditions ).group_by(&:assigned_to) @@ -183,45 +202,96 @@ class Mailer < ActionMailer::Base super set_language_if_valid Setting.default_language from Setting.mail_from - default_url_options[:host] = Setting.host_name + + # URL options + h = Setting.host_name + h = h.to_s.gsub(%r{\/.*$}, '') unless Redmine::Utils.relative_url_root.blank? + default_url_options[:host] = h default_url_options[:protocol] = Setting.protocol + # Common headers headers 'X-Mailer' => 'Redmine', 'X-Redmine-Host' => Setting.host_name, 'X-Redmine-Site' => Setting.app_title end - + # Appends a Redmine header field (name is prepended with 'X-Redmine-') def redmine_headers(h) h.each { |k,v| headers["X-Redmine-#{k}"] = v } end - + # Overrides the create_mail method def create_mail # Removes the current user from the recipients and cc # if he doesn't want to receive notifications about what he does - if User.current.pref[:no_self_notified] - recipients.delete(User.current.mail) if recipients - cc.delete(User.current.mail) if cc + @author ||= User.current + if @author.pref[:no_self_notified] + recipients.delete(@author.mail) if recipients + cc.delete(@author.mail) if cc end # Blind carbon copy recipients if Setting.bcc_recipients? bcc([recipients, cc].flatten.compact.uniq) recipients [] cc [] - end + end super end - + # Renders a message with the corresponding layout def render_message(method_name, body) - layout = method_name.match(%r{text\.html\.(rhtml|rxml)}) ? 'layout.text.html.rhtml' : 'layout.text.plain.rhtml' + layout = method_name.to_s.match(%r{text\.html\.(rhtml|rxml)}) ? 'layout.text.html.rhtml' : 'layout.text.plain.rhtml' body[:content_for_layout] = render(:file => method_name, :body => body) ActionView::Base.new(template_root, body, self).render(:file => "mailer/#{layout}", :use_full_path => true) end - + + # for the case of plain text only + def body(*params) + value = super(*params) + if Setting.plain_text_mail? + templates = Dir.glob("#{template_path}/#{@template}.text.plain.{rhtml,erb}") + unless String === @body or templates.empty? + template = File.basename(templates.first) + @body[:content_for_layout] = render(:file => template, :body => @body) + @body = ActionView::Base.new(template_root, @body, self).render(:file => "mailer/layout.text.plain.rhtml", :use_full_path => true) + return @body + end + end + return value + end + # Makes partial rendering work with Rails 1.2 (retro-compatibility) def self.controller_path '' end unless respond_to?('controller_path') + + # Returns a predictable Message-Id for the given object + def self.message_id_for(object) + # id + timestamp should reduce the odds of a collision + # as far as we don't send multiple emails for the same object + hash = "redmine.#{object.class.name.demodulize.underscore}-#{object.id}.#{object.created_on.strftime("%Y%m%d%H%M%S")}" + host = Setting.mail_from.to_s.gsub(%r{^.*@}, '') + host = "#{::Socket.gethostname}.redmine" if host.empty? + "<#{hash}@#{host}>" + end + + private + + def message_id(object) + @message_id_object = object + end + + def references(object) + @references_objects ||= [] + @references_objects << object + end +end + +# Patch TMail so that message_id is not overwritten +module TMail + class Mail + def add_message_id( fqdn = nil ) + self.message_id ||= ::TMail::new_message_id(fqdn) + end + end end diff --git a/app/models/message.rb b/app/models/message.rb index f1cb2d0ba..716c53b0b 100644 --- a/app/models/message.rb +++ b/app/models/message.rb @@ -19,11 +19,11 @@ class Message < ActiveRecord::Base belongs_to :board belongs_to :author, :class_name => 'User', :foreign_key => 'author_id' acts_as_tree :counter_cache => :replies_count, :order => "#{Message.table_name}.created_on ASC" - has_many :attachments, :as => :container, :dependent => :destroy + acts_as_attachable belongs_to :last_reply, :class_name => 'Message', :foreign_key => 'last_reply_id' acts_as_searchable :columns => ['subject', 'content'], - :include => {:board, :project}, + :include => {:board => :project}, :project_key => 'project_id', :date_column => "#{table_name}.created_on" acts_as_event :title => Proc.new {|o| "#{o.board.name}: #{o.subject}"}, @@ -32,7 +32,8 @@ class Message < ActiveRecord::Base :url => Proc.new {|o| {:controller => 'messages', :action => 'show', :board_id => o.board_id}.merge(o.parent_id.nil? ? {:id => o.id} : {:id => o.parent_id, :anchor => "message-#{o.id}"})} - acts_as_activity_provider :find_options => {:include => [{:board => :project}, :author]} + acts_as_activity_provider :find_options => {:include => [{:board => :project}, :author]}, + :author_key => :author_id acts_as_watchable attr_protected :locked, :sticky @@ -71,6 +72,14 @@ class Message < ActiveRecord::Base def project board.project end + + def editable_by?(usr) + usr && usr.logged? && (usr.allowed_to?(:edit_messages, project) || (self.author == usr && usr.allowed_to?(:edit_own_messages, project))) + end + + def destroyable_by?(usr) + usr && usr.logged? && (usr.allowed_to?(:delete_messages, project) || (self.author == usr && usr.allowed_to?(:delete_own_messages, project))) + end private diff --git a/app/models/news.rb b/app/models/news.rb index 4c4943b78..5949a731b 100644 --- a/app/models/news.rb +++ b/app/models/news.rb @@ -1,5 +1,5 @@ -# redMine - project management software -# Copyright (C) 2006 Jean-Philippe Lang +# Redmine - project management software +# 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 @@ -26,10 +26,11 @@ class News < ActiveRecord::Base acts_as_searchable :columns => ['title', "#{table_name}.description"], :include => :project acts_as_event :url => Proc.new {|o| {:controller => 'news', :action => 'show', :id => o.id}} - acts_as_activity_provider :find_options => {:include => [:project, :author]} + acts_as_activity_provider :find_options => {:include => [:project, :author]}, + :author_key => :author_id # returns latest news for projects visible by user - def self.latest(user=nil, count=5) - find(:all, :limit => count, :conditions => Project.visible_by(user), :include => [ :author, :project ], :order => "#{News.table_name}.created_on DESC") + def self.latest(user = User.current, count = 5) + find(:all, :limit => count, :conditions => Project.allowed_to_condition(user, :view_news), :include => [ :author, :project ], :order => "#{News.table_name}.created_on DESC") end end diff --git a/app/models/project.rb b/app/models/project.rb index e40af9967..7ce0051ed 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -43,7 +43,9 @@ class Project < ActiveRecord::Base :join_table => "#{table_name_prefix}custom_fields_projects#{table_name_suffix}", :association_foreign_key => 'custom_field_id' - acts_as_tree :order => "name", :counter_cache => true + acts_as_nested_set :order => 'name', :dependent => :destroy + acts_as_attachable :view_permission => :view_files, + :delete_permission => :manage_files acts_as_customizable acts_as_searchable :columns => ['name', 'description'], :project_key => 'id', :permission => nil @@ -58,12 +60,15 @@ class Project < ActiveRecord::Base validates_associated :repository, :wiki validates_length_of :name, :maximum => 30 validates_length_of :homepage, :maximum => 255 - validates_length_of :identifier, :in => 3..20 + validates_length_of :identifier, :in => 2..20 validates_format_of :identifier, :with => /^[a-z0-9\-]*$/ before_destroy :delete_all_members named_scope :has_module, lambda { |mod| { :conditions => ["#{Project.table_name}.id IN (SELECT em.project_id FROM #{EnabledModule.table_name} em WHERE em.name=?)", mod.to_s] } } + named_scope :active, { :conditions => "#{Project.table_name}.status = #{STATUS_ACTIVE}"} + named_scope :public, { :conditions => { :is_public => true } } + named_scope :visible, lambda { { :conditions => Project.visible_by(User.current) } } def identifier=(identifier) super unless identifier_frozen? @@ -76,7 +81,7 @@ class Project < ActiveRecord::Base def issues_with_subprojects(include_subprojects=false) conditions = nil if include_subprojects - ids = [id] + child_ids + ids = [id] + descendants.collect(&:id) conditions = ["#{Project.table_name}.id IN (#{ids.join(',')}) AND #{Project.visible_by}"] end conditions ||= ["#{Project.table_name}.id = ?", id] @@ -108,9 +113,15 @@ class Project < ActiveRecord::Base def self.allowed_to_condition(user, permission, options={}) statements = [] base_statement = "#{Project.table_name}.status=#{Project::STATUS_ACTIVE}" + if perm = Redmine::AccessControl.permission(permission) + unless perm.project_module.nil? + # If the permission belongs to a project module, make sure the module is enabled + base_statement << " AND EXISTS (SELECT em.id FROM #{EnabledModule.table_name} em WHERE em.name='#{perm.project_module}' AND em.project_id=#{Project.table_name}.id)" + end + end if options[:project] project_statement = "#{Project.table_name}.id = #{options[:project].id}" - project_statement << " OR #{Project.table_name}.parent_id = #{options[:project].id}" if options[:with_subprojects] + project_statement << " OR (#{Project.table_name}.lft > #{options[:project].lft} AND #{Project.table_name}.rgt < #{options[:project].rgt})" if options[:with_subprojects] base_statement = "(#{project_statement}) AND (#{base_statement})" end if user.admin? @@ -133,7 +144,7 @@ class Project < ActiveRecord::Base def project_condition(with_subprojects) cond = "#{Project.table_name}.id = #{id}" - cond = "(#{cond} OR #{Project.table_name}.parent_id = #{id})" if with_subprojects + cond = "(#{cond} OR (#{Project.table_name}.lft > #{lft} AND #{Project.table_name}.rgt < #{rgt}))" if with_subprojects cond end @@ -156,6 +167,7 @@ class Project < ActiveRecord::Base self.status == STATUS_ACTIVE end + # Archives the project and its descendants recursively def archive # Archive subprojects if any children.each do |subproject| @@ -164,21 +176,62 @@ class Project < ActiveRecord::Base update_attribute :status, STATUS_ARCHIVED end + # Unarchives the project + # All its ancestors must be active def unarchive - return false if parent && !parent.active? + return false if ancestors.detect {|a| !a.active?} update_attribute :status, STATUS_ACTIVE end - def active_children - children.select {|child| child.active?} + # Returns an array of projects the project can be moved to + def possible_parents + @possible_parents ||= (Project.active.find(:all) - self_and_descendants) + end + + # Sets the parent of the project + # Argument can be either a Project, a String, a Fixnum or nil + def set_parent!(p) + unless p.nil? || p.is_a?(Project) + if p.to_s.blank? + p = nil + else + p = Project.find_by_id(p) + return false unless p + end + end + if p == parent && !p.nil? + # Nothing to do + true + elsif p.nil? || (p.active? && move_possible?(p)) + # Insert the project so that target's children or root projects stay alphabetically sorted + sibs = (p.nil? ? self.class.roots : p.children) + to_be_inserted_before = sibs.detect {|c| c.name.to_s.downcase > name.to_s.downcase } + if to_be_inserted_before + move_to_left_of(to_be_inserted_before) + elsif p.nil? + if sibs.empty? + # move_to_root adds the project in first (ie. left) position + move_to_root + else + move_to_right_of(sibs.last) unless self == sibs.last + end + else + # move_to_child_of adds the project in last (ie.right) position + move_to_child_of(p) + end + true + else + # Can not move to the given target + false + end end - # Returns an array of the trackers used by the project and its sub projects + # Returns an array of the trackers used by the project and its active sub projects def rolled_up_trackers @rolled_up_trackers ||= Tracker.find(:all, :include => :projects, :select => "DISTINCT #{Tracker.table_name}.*", - :conditions => ["#{Project.table_name}.id = ? OR #{Project.table_name}.parent_id = ?", id, id], + :conditions => ["#{Project.table_name}.lft >= ? AND #{Project.table_name}.rgt <= ? AND #{Project.table_name}.status = #{STATUS_ACTIVE}", lft, rgt], :order => "#{Tracker.table_name}.position") end @@ -217,7 +270,7 @@ class Project < ActiveRecord::Base # Returns a short description of the projects (first lines) def short_description(length = 255) - description.gsub(/^(.{#{length}}[^\n]*).*$/m, '\1').strip if description + description.gsub(/^(.{#{length}}[^\n\r]*).*$/m, '\1...').strip if description end def allows_to?(action) @@ -249,8 +302,6 @@ class Project < ActiveRecord::Base protected def validate - errors.add(parent_id, " must be a root project") if parent and parent.parent - errors.add_to_base("A project with subprojects can't be a subproject") if parent and children.size > 0 errors.add(:identifier, :activerecord_error_invalid) if !identifier.blank? && identifier.match(/^\d*$/) end diff --git a/app/models/query.rb b/app/models/query.rb index f8c236145..23742cfa5 100644 --- a/app/models/query.rb +++ b/app/models/query.rb @@ -35,7 +35,7 @@ class QueryCustomFieldColumn < QueryColumn def initialize(custom_field) self.name = "cf_#{custom_field.id}".to_sym - self.sortable = false + self.sortable = custom_field.order_statement || false @cf = custom_field end @@ -98,10 +98,10 @@ class Query < ActiveRecord::Base QueryColumn.new(:priority, :sortable => "#{Enumeration.table_name}.position", :default_order => 'desc'), QueryColumn.new(:subject, :sortable => "#{Issue.table_name}.subject"), QueryColumn.new(:author), - QueryColumn.new(:assigned_to, :sortable => "#{User.table_name}.lastname"), + QueryColumn.new(:assigned_to, :sortable => ["#{User.table_name}.lastname", "#{User.table_name}.firstname"]), QueryColumn.new(:updated_on, :sortable => "#{Issue.table_name}.updated_on", :default_order => 'desc'), QueryColumn.new(:category, :sortable => "#{IssueCategory.table_name}.name"), - QueryColumn.new(:fixed_version, :sortable => "#{Version.table_name}.effective_date", :default_order => 'desc'), + QueryColumn.new(:fixed_version, :sortable => ["#{Version.table_name}.effective_date", "#{Version.table_name}.name"], :default_order => 'desc'), QueryColumn.new(:start_date, :sortable => "#{Issue.table_name}.start_date"), QueryColumn.new(:due_date, :sortable => "#{Issue.table_name}.due_date"), QueryColumn.new(:estimated_hours, :sortable => "#{Issue.table_name}.estimated_hours"), @@ -165,6 +165,10 @@ class Query < ActiveRecord::Base end @available_filters["assigned_to_id"] = { :type => :list_optional, :order => 4, :values => user_values } unless user_values.empty? @available_filters["author_id"] = { :type => :list, :order => 5, :values => user_values } unless user_values.empty? + + if User.current.logged? + @available_filters["watcher_id"] = { :type => :list, :order => 15, :values => [["<< #{l(:label_me)} >>", "me"]] } + end if project # project specific filters @@ -174,8 +178,8 @@ class Query < ActiveRecord::Base unless @project.versions.empty? @available_filters["fixed_version_id"] = { :type => :list_optional, :order => 7, :values => @project.versions.sort.collect{|s| [s.name, s.id.to_s] } } end - unless @project.active_children.empty? - @available_filters["subproject_id"] = { :type => :list_subprojects, :order => 13, :values => @project.active_children.collect{|s| [s.name, s.id.to_s] } } + unless @project.descendants.active.empty? + @available_filters["subproject_id"] = { :type => :list_subprojects, :order => 13, :values => @project.descendants.visible.collect{|s| [s.name, s.id.to_s] } } end add_custom_fields_filters(@project.all_issue_custom_fields) else @@ -257,7 +261,7 @@ class Query < ActiveRecord::Base def project_statement project_clauses = [] - if project && !@project.active_children.empty? + if project && !@project.descendants.active.empty? ids = [project.id] if has_filter?("subproject_id") case operator_for("subproject_id") @@ -268,16 +272,16 @@ class Query < ActiveRecord::Base # main project only else # all subprojects - ids += project.child_ids + ids += project.descendants.collect(&:id) end elsif Setting.display_subprojects_issues? - ids += project.child_ids + ids += project.descendants.collect(&:id) end project_clauses << "#{Project.table_name}.id IN (%s)" % ids.join(',') elsif project project_clauses << "#{Project.table_name}.id = %d" % project.id end - project_clauses << Project.visible_by(User.current) + project_clauses << Project.allowed_to_condition(User.current, :view_issues) project_clauses.join(' AND ') end @@ -288,74 +292,34 @@ class Query < ActiveRecord::Base next if field == "subproject_id" v = values_for(field).clone next unless v and !v.empty? - + operator = operator_for(field) + + # "me" value subsitution + if %w(assigned_to_id author_id watcher_id).include?(field) + v.push(User.current.logged? ? User.current.id.to_s : "0") if v.delete("me") + end + sql = '' - is_custom_filter = false if field =~ /^cf_(\d+)$/ # custom field db_table = CustomValue.table_name db_field = 'value' 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 " + sql << sql_for_field(field, operator, v, db_table, db_field, true) + ')' + elsif field == 'watcher_id' + db_table = Watcher.table_name + db_field = 'user_id' + sql << "#{Issue.table_name}.id #{ operator == '=' ? 'IN' : 'NOT IN' } (SELECT #{db_table}.watchable_id FROM #{db_table} WHERE #{db_table}.watchable_type='Issue' AND " + sql << sql_for_field(field, '=', v, db_table, db_field) + ')' else # regular field db_table = Issue.table_name db_field = field - sql << '(' - end - - # "me" value subsitution - if %w(assigned_to_id author_id).include?(field) - v.push(User.current.logged? ? User.current.id.to_s : "0") if v.delete("me") + sql << '(' + sql_for_field(field, operator, v, db_table, db_field) + ')' end - - case operator_for field - when "=" - sql = sql + "#{db_table}.#{db_field} IN (" + v.collect{|val| "'#{connection.quote_string(val)}'"}.join(",") + ")" - when "!" - 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 "<=" - sql = sql + "#{db_table}.#{db_field} <= #{v.first.to_i}" - when "o" - sql = sql + "#{IssueStatus.table_name}.is_closed=#{connection.quoted_false}" if field == "status_id" - when "c" - sql = sql + "#{IssueStatus.table_name}.is_closed=#{connection.quoted_true}" if field == "status_id" - when ">t-" - sql = sql + "#{db_table}.#{db_field} BETWEEN '%s' AND '%s'" % [connection.quoted_date((Date.today - v.first.to_i).to_time), connection.quoted_date((Date.today + 1).to_time)] - when "t+" - sql = sql + "#{db_table}.#{db_field} >= '%s'" % connection.quoted_date((Date.today + v.first.to_i).to_time) - when " ''" if is_custom_filter + when ">=" + sql = "#{db_table}.#{db_field} >= #{value.first.to_i}" + when "<=" + sql = "#{db_table}.#{db_field} <= #{value.first.to_i}" + when "o" + sql = "#{IssueStatus.table_name}.is_closed=#{connection.quoted_false}" if field == "status_id" + when "c" + sql = "#{IssueStatus.table_name}.is_closed=#{connection.quoted_true}" if field == "status_id" + when ">t-" + sql = date_range_clause(db_table, db_field, - value.first.to_i, 0) + when "t+" + sql = date_range_clause(db_table, db_field, value.first.to_i, nil) + when " field.name }) end end + + # Returns a SQL clause for a date or datetime field. + def date_range_clause(table, field, from, to) + s = [] + if from + s << ("#{table}.#{field} > '%s'" % [connection.quoted_date((Date.yesterday + from).to_time.end_of_day)]) + end + if to + s << ("#{table}.#{field} <= '%s'" % [connection.quoted_date((Date.today + to).to_time.end_of_day)]) + end + s.join(' AND ') + end end diff --git a/app/models/repository.rb b/app/models/repository.rb index b0a7a0a16..a62388bb6 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -78,11 +78,12 @@ class Repository < ActiveRecord::Base end # Default behaviour: we search in cached changesets - def changesets_for_path(path) + def changesets_for_path(path, options={}) path = "/#{path}" unless path.starts_with?('/') - Change.find(:all, :include => :changeset, - :conditions => ["repository_id = ? AND path = ?", id, path], - :order => "committed_on DESC, #{Changeset.table_name}.id DESC").collect(&:changeset) + Change.find(:all, :include => {:changeset => :user}, + :conditions => ["repository_id = ? AND path = ?", id, path], + :order => "committed_on DESC, #{Changeset.table_name}.id DESC", + :limit => options[:limit]).collect(&:changeset) end # Returns a path relative to the url of the repository @@ -98,6 +99,45 @@ class Repository < ActiveRecord::Base self.changesets.each(&:scan_comment_for_issue_ids) end + # Returns an array of committers usernames and associated user_id + def committers + @committers ||= Changeset.connection.select_rows("SELECT DISTINCT committer, user_id FROM #{Changeset.table_name} WHERE repository_id = #{id}") + end + + # Maps committers username to a user ids + def committer_ids=(h) + if h.is_a?(Hash) + committers.each do |committer, user_id| + new_user_id = h[committer] + if new_user_id && (new_user_id.to_i != user_id.to_i) + new_user_id = (new_user_id.to_i > 0 ? new_user_id.to_i : nil) + Changeset.update_all("user_id = #{ new_user_id.nil? ? 'NULL' : new_user_id }", ["repository_id = ? AND committer = ?", id, committer]) + end + end + @committers = nil + true + else + false + end + end + + # Returns the Redmine User corresponding to the given +committer+ + # It will return nil if the committer is not yet mapped and if no User + # with the same username or email was found + def find_committer_user(committer) + if committer + c = changesets.find(:first, :conditions => {:committer => committer}, :include => :user) + if c && c.user + c.user + elsif committer.strip =~ /^([^<]+)(<(.*)>)?$/ + username, email = $1.strip, $3 + u = User.find_by_login(username) + u ||= User.find_by_mail(email) unless email.blank? + u + end + end + end + # fetch new changesets for all repositories # can be called periodically by an external script # eg. ruby script/runner "Repository.fetch_changesets" diff --git a/app/models/repository/darcs.rb b/app/models/repository/darcs.rb index 855a403fc..5c8d3871a 100644 --- a/app/models/repository/darcs.rb +++ b/app/models/repository/darcs.rb @@ -52,7 +52,7 @@ class Repository::Darcs < Repository end def cat(path, identifier=nil) - patch = identifier.nil? ? nil : changesets.find_by_revision(identifier) + patch = identifier.nil? ? nil : changesets.find_by_revision(identifier.to_s) scm.cat(path, patch.nil? ? nil : patch.scmid) end diff --git a/app/models/repository/git.rb b/app/models/repository/git.rb index f6b9c2fef..0538e11cc 100644 --- a/app/models/repository/git.rb +++ b/app/models/repository/git.rb @@ -40,10 +40,11 @@ class Repository::Git < Repository 'Git' end - def changesets_for_path(path) - Change.find(:all, :include => :changeset, + def changesets_for_path(path, options={}) + Change.find(:all, :include => {:changeset => :user}, :conditions => ["repository_id = ? AND path = ?", id, path], - :order => "committed_on DESC, #{Changeset.table_name}.revision DESC").collect(&:changeset) + :order => "committed_on DESC, #{Changeset.table_name}.revision DESC", + :limit => options[:limit]).collect(&:changeset) end def fetch_changesets @@ -58,20 +59,22 @@ class Repository::Git < Repository unless changesets.find_by_scmid(scm_revision) scm.revisions('', db_revision, nil, :reverse => true) do |revision| - transaction do - changeset = Changeset.create(:repository => self, - :revision => revision.identifier, - :scmid => revision.scmid, - :committer => revision.author, - :committed_on => revision.time, - :comments => revision.message) - - revision.paths.each do |change| - Change.create(:changeset => changeset, - :action => change[:action], - :path => change[:path], - :from_path => change[:from_path], - :from_revision => change[:from_revision]) + if changesets.find_by_scmid(revision.scmid.to_s).nil? + transaction do + changeset = Changeset.create!(:repository => self, + :revision => revision.identifier, + :scmid => revision.scmid, + :committer => revision.author, + :committed_on => revision.time, + :comments => revision.message) + + revision.paths.each do |change| + Change.create!(:changeset => changeset, + :action => change[:action], + :path => change[:path], + :from_path => change[:from_path], + :from_revision => change[:from_revision]) + end end end end diff --git a/app/models/repository/subversion.rb b/app/models/repository/subversion.rb index e29c42bb9..055b00876 100644 --- a/app/models/repository/subversion.rb +++ b/app/models/repository/subversion.rb @@ -40,9 +40,9 @@ class Repository::Subversion < Repository 'Subversion' end - def changesets_for_path(path) - revisions = scm.revisions(path) - revisions ? changesets.find_all_by_revision(revisions.collect(&:identifier), :order => "committed_on DESC") : [] + def changesets_for_path(path, options={}) + revisions = scm.revisions(path, nil, nil, :limit => options[:limit]) + revisions ? changesets.find_all_by_revision(revisions.collect(&:identifier), :order => "committed_on DESC", :include => :user) : [] end # Returns a path relative to the url of the repository diff --git a/app/models/role.rb b/app/models/role.rb index beb13c03b..b07e7a039 100644 --- a/app/models/role.rb +++ b/app/models/role.rb @@ -31,9 +31,9 @@ class Role < ActiveRecord::Base raise "Can not copy workflow from a #{role.class}" unless role.is_a?(Role) raise "Can not copy workflow from/to an unsaved role" if proxy_owner.new_record? || role.new_record? clear - connection.insert "INSERT INTO workflows (tracker_id, old_status_id, new_status_id, role_id)" + + connection.insert "INSERT INTO #{Workflow.table_name} (tracker_id, old_status_id, new_status_id, role_id)" + " SELECT tracker_id, old_status_id, new_status_id, #{proxy_owner.id}" + - " FROM workflows" + + " FROM #{Workflow.table_name}" + " WHERE role_id = #{role.id}" end end diff --git a/app/models/setting.rb b/app/models/setting.rb index c59925a9f..64d6c1401 100644 --- a/app/models/setting.rb +++ b/app/models/setting.rb @@ -75,9 +75,9 @@ class Setting < ActiveRecord::Base cattr_accessor :available_settings @@available_settings = YAML::load(File.open("#{RAILS_ROOT}/config/settings.yml")) - Redmine::Plugin.registered_plugins.each do |id, plugin| + Redmine::Plugin.all.each do |plugin| next unless plugin.settings - @@available_settings["plugin_#{id}"] = {'default' => plugin.settings[:default], 'serialized' => true} + @@available_settings["plugin_#{plugin.id}"] = {'default' => plugin.settings[:default], 'serialized' => true} end validates_uniqueness_of :name @@ -140,6 +140,10 @@ class Setting < ActiveRecord::Base per_page_options.split(%r{[\s,]}).collect(&:to_i).select {|n| n > 0}.sort end + def self.openid? + Object.const_defined?(:OpenID) && self['openid'].to_s == '1' + end + # Checks if settings have changed since the values were read # and clears the cache hash if it's the case # Called once per request diff --git a/app/models/time_entry.rb b/app/models/time_entry.rb index 57a75604d..f10b179d1 100644 --- a/app/models/time_entry.rb +++ b/app/models/time_entry.rb @@ -32,7 +32,7 @@ class TimeEntry < ActiveRecord::Base :description => :comments validates_presence_of :user_id, :activity_id, :project_id, :hours, :spent_on - validates_numericality_of :hours, :allow_nil => true + validates_numericality_of :hours, :allow_nil => true, :message => :activerecord_error_invalid validates_length_of :comments, :maximum => 255, :allow_nil => true def after_initialize @@ -54,7 +54,7 @@ class TimeEntry < ActiveRecord::Base end def hours=(h) - write_attribute :hours, (h.is_a?(String) ? h.to_hours : h) + write_attribute :hours, (h.is_a?(String) ? (h.to_hours || h) : h) end # tyear, tmonth, tweek assigned where setting spent_on attributes diff --git a/app/models/tracker.rb b/app/models/tracker.rb index ecee908eb..7c5bae250 100644 --- a/app/models/tracker.rb +++ b/app/models/tracker.rb @@ -23,9 +23,9 @@ class Tracker < ActiveRecord::Base raise "Can not copy workflow from a #{tracker.class}" unless tracker.is_a?(Tracker) raise "Can not copy workflow from/to an unsaved tracker" if proxy_owner.new_record? || tracker.new_record? clear - connection.insert "INSERT INTO workflows (tracker_id, old_status_id, new_status_id, role_id)" + + connection.insert "INSERT INTO #{Workflow.table_name} (tracker_id, old_status_id, new_status_id, role_id)" + " SELECT #{proxy_owner.id}, old_status_id, new_status_id, role_id" + - " FROM workflows" + + " FROM #{Workflow.table_name}" + " WHERE tracker_id = #{tracker.id}" end end diff --git a/app/models/user.rb b/app/models/user.rb index 132896ad9..4f8223dc0 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -37,10 +37,14 @@ class User < ActiveRecord::Base has_many :members, :dependent => :delete_all has_many :projects, :through => :memberships has_many :issue_categories, :foreign_key => 'assigned_to_id', :dependent => :nullify + has_many :changesets, :dependent => :nullify has_one :preference, :dependent => :destroy, :class_name => 'UserPreference' has_one :rss_token, :dependent => :destroy, :class_name => 'Token', :conditions => "action='feeds'" belongs_to :auth_source + # Active non-anonymous users scope + named_scope :active, :conditions => "#{User.table_name}.status = #{STATUS_ACTIVE}" + acts_as_customizable attr_accessor :password, :password_confirmation @@ -50,7 +54,7 @@ class User < ActiveRecord::Base validates_presence_of :login, :firstname, :lastname, :mail, :if => Proc.new { |user| !user.is_a?(AnonymousUser) } validates_uniqueness_of :login, :if => Proc.new { |user| !user.login.blank? } - validates_uniqueness_of :mail, :if => Proc.new { |user| !user.mail.blank? } + validates_uniqueness_of :mail, :if => Proc.new { |user| !user.mail.blank? }, :case_sensitive => false # Login must contain lettres, numbers, underscores only validates_format_of :login, :with => /^[a-z0-9_\-@\.]*$/i validates_length_of :login, :maximum => 30 @@ -70,17 +74,19 @@ class User < ActiveRecord::Base # update hashed_password if password was set self.hashed_password = User.hash_password(self.password) if self.password end - - def self.active - with_scope :find => { :conditions => [ "status = ?", STATUS_ACTIVE ] } do - yield - end + + def reload(*args) + @name = nil + super end - def self.find_active(*args) - active do - find(*args) + def identity_url=(url) + begin + self.write_attribute(:identity_url, OpenIdAuthentication.normalize_identifier(url)) + rescue InvalidOpenId + # Invlaid url, don't save end + self.read_attribute(:identity_url) end # Returns the user that matches provided login and password, or nil @@ -119,8 +125,11 @@ class User < ActiveRecord::Base # Return user's full name for display def name(formatter = nil) - f = USER_FORMATS[formatter || Setting.user_format] || USER_FORMATS[:firstname_lastname] - eval '"' + f + '"' + if formatter + eval('"' + (USER_FORMATS[formatter] || USER_FORMATS[:firstname_lastname]) + '"') + else + @name ||= eval('"' + (USER_FORMATS[Setting.user_format] || USER_FORMATS[:firstname_lastname]) + '"') + end end def active? @@ -138,13 +147,25 @@ class User < ActiveRecord::Base def check_password?(clear_password) User.hash_password(clear_password) == self.hashed_password end + + # Generate and set a random password. Useful for automated user creation + # Based on Token#generate_token_value + # + def random_password + chars = ("a".."z").to_a + ("A".."Z").to_a + ("0".."9").to_a + password = '' + 40.times { |i| password << chars[rand(chars.size-1)] } + self.password = password + self.password_confirmation = password + self + end def pref self.preference ||= UserPreference.new(:user => self) end def time_zone - @time_zone ||= (self.pref.time_zone.blank? ? nil : TimeZone[self.pref.time_zone]) + @time_zone ||= (self.pref.time_zone.blank? ? nil : ActiveSupport::TimeZone[self.pref.time_zone]) end def wants_comments_in_reverse_order? @@ -178,15 +199,15 @@ class User < ActiveRecord::Base token = Token.find_by_action_and_value('autologin', key) token && (token.created_on > Setting.autologin.to_i.day.ago) && token.user.active? ? token.user : nil end + + # Makes find_by_mail case-insensitive + def self.find_by_mail(mail) + find(:first, :conditions => ["LOWER(mail) = ?", mail.to_s.downcase]) + end + # Sort users by their display names def <=>(user) - if user.nil? - -1 - elsif lastname.to_s.downcase == user.lastname.to_s.downcase - firstname.to_s.downcase <=> user.firstname.to_s.downcase - else - lastname.to_s.downcase <=> user.lastname.to_s.downcase - end + self.to_s.downcase <=> user.to_s.downcase end def to_s diff --git a/app/models/version.rb b/app/models/version.rb index e379f4b05..7f96cea6b 100644 --- a/app/models/version.rb +++ b/app/models/version.rb @@ -19,7 +19,8 @@ class Version < ActiveRecord::Base before_destroy :check_integrity belongs_to :project has_many :fixed_issues, :class_name => 'Issue', :foreign_key => 'fixed_version_id' - has_many :attachments, :as => :container, :dependent => :destroy + acts_as_attachable :view_permission => :view_files, + :delete_permission => :manage_files validates_presence_of :name validates_uniqueness_of :name, :scope => [:project_id] @@ -50,20 +51,20 @@ class Version < ActiveRecord::Base end def completed_pourcent - if fixed_issues.count == 0 + if issues_count == 0 0 elsif open_issues_count == 0 100 else - (closed_issues_count * 100 + Issue.sum('done_ratio', :include => 'status', :conditions => ["fixed_version_id = ? AND is_closed = ?", id, false]).to_f) / fixed_issues.count + issues_progress(false) + issues_progress(true) end end def closed_pourcent - if fixed_issues.count == 0 + if issues_count == 0 0 else - closed_issues_count * 100.0 / fixed_issues.count + issues_progress(false) end end @@ -72,6 +73,11 @@ class Version < ActiveRecord::Base effective_date && (effective_date < Date.today) && (open_issues_count > 0) end + # Returns assigned issues count + def issues_count + @issue_count ||= fixed_issues.count + end + def open_issues_count @open_issues_count ||= Issue.count(:all, :conditions => ["fixed_version_id = ? AND is_closed = ?", self.id, false], :include => :status) end @@ -103,4 +109,35 @@ private def check_integrity raise "Can't delete version" if self.fixed_issues.find(:first) end + + # Returns the average estimated time of assigned issues + # or 1 if no issue has an estimated time + # Used to weigth unestimated issues in progress calculation + def estimated_average + if @estimated_average.nil? + average = fixed_issues.average(:estimated_hours).to_f + if average == 0 + average = 1 + end + @estimated_average = average + end + @estimated_average + end + + # Returns the total progress of open or closed issues + def issues_progress(open) + @issues_progress ||= {} + @issues_progress[open] ||= begin + progress = 0 + if issues_count > 0 + ratio = open ? 'done_ratio' : 100 + done = fixed_issues.sum("COALESCE(estimated_hours, #{estimated_average}) * #{ratio}", + :include => :status, + :conditions => ["is_closed = ?", !open]).to_f + + progress = done / (estimated_average * issues_count) + end + progress + end + end end diff --git a/app/models/wiki.rb b/app/models/wiki.rb index 3432a2bc7..be048775a 100644 --- a/app/models/wiki.rb +++ b/app/models/wiki.rb @@ -43,6 +43,25 @@ class Wiki < ActiveRecord::Base page end + # Finds a page by title + # The given string can be of one of the forms: "title" or "project:title" + # Examples: + # Wiki.find_page("bar", project => foo) + # Wiki.find_page("foo:bar") + def self.find_page(title, options = {}) + project = options[:project] + if title.to_s =~ %r{^([^\:]+)\:(.*)$} + project_identifier, title = $1, $2 + project = Project.find_by_identifier(project_identifier) || Project.find_by_name(project_identifier) + end + if project && project.wiki + page = project.wiki.find_page(title) + if page && page.content + page + end + end + end + # turn a string into a valid page title def self.titleize(title) # replace spaces with _ and remove unwanted caracters diff --git a/app/models/wiki_content.rb b/app/models/wiki_content.rb index 4a4c5c270..e958e7b24 100644 --- a/app/models/wiki_content.rb +++ b/app/models/wiki_content.rb @@ -37,6 +37,7 @@ class WikiContent < ActiveRecord::Base acts_as_activity_provider :type => 'wiki_edits', :timestamp => "#{WikiContent.versioned_table_name}.updated_on", + :author_key => "#{WikiContent.versioned_table_name}.author_id", :permission => :view_wiki_edits, :find_options => {:select => "#{WikiContent.versioned_table_name}.updated_on, #{WikiContent.versioned_table_name}.comments, " + "#{WikiContent.versioned_table_name}.#{WikiContent.version_column}, #{WikiPage.table_name}.title, " + diff --git a/app/models/wiki_page.rb b/app/models/wiki_page.rb index 2416fab74..0d96cc047 100644 --- a/app/models/wiki_page.rb +++ b/app/models/wiki_page.rb @@ -21,7 +21,7 @@ require 'enumerator' class WikiPage < ActiveRecord::Base belongs_to :wiki has_one :content, :class_name => 'WikiContent', :foreign_key => 'page_id', :dependent => :destroy - has_many :attachments, :as => :container, :dependent => :destroy + acts_as_attachable :delete_permission => :delete_wiki_pages_attachments acts_as_tree :order => 'title' acts_as_event :title => Proc.new {|o| "#{l(:label_wiki)}: #{o.title}"}, @@ -111,6 +111,10 @@ class WikiPage < ActiveRecord::Base def editable_by?(usr) !protected? || usr.allowed_to?(:protect_wiki_pages, wiki.project) end + + def attachments_deletable?(usr=User.current) + editable_by?(usr) && super(usr) + end def parent_title @parent_title || (self.parent && self.parent.pretty_title) diff --git a/app/models/workflow.rb b/app/models/workflow.rb index 89322aa58..4168fdea0 100644 --- a/app/models/workflow.rb +++ b/app/models/workflow.rb @@ -21,4 +21,23 @@ class Workflow < ActiveRecord::Base belongs_to :new_status, :class_name => 'IssueStatus', :foreign_key => 'new_status_id' validates_presence_of :role, :old_status, :new_status + + # Returns workflow transitions count by tracker and role + def self.count_by_tracker_and_role + counts = connection.select_all("SELECT role_id, tracker_id, count(id) AS c FROM #{Workflow.table_name} GROUP BY role_id, tracker_id") + roles = Role.find(:all, :order => 'builtin, position') + trackers = Tracker.find(:all, :order => 'position') + + result = [] + trackers.each do |tracker| + t = [] + roles.each do |role| + row = counts.detect {|c| c['role_id'] == role.id.to_s && c['tracker_id'] == tracker.id.to_s} + t << [role, (row.nil? ? 0 : row['c'].to_i)] + end + result << [tracker, t] + end + + result + end end diff --git a/app/views/account/login.rhtml b/app/views/account/login.rhtml index d8c1f313f..c55419d8e 100644 --- a/app/views/account/login.rhtml +++ b/app/views/account/login.rhtml @@ -10,6 +10,12 @@ <%= password_field_tag 'password', nil, :size => 40 %> +<% if Setting.openid? %> + + + <%= text_field_tag "openid_url" %> + +<% end %> diff --git a/app/views/account/register.rhtml b/app/views/account/register.rhtml index 755a7ad4b..f9f388ae4 100644 --- a/app/views/account/register.rhtml +++ b/app/views/account/register.rhtml @@ -1,4 +1,4 @@ -

    <%=l(:label_register)%>

    +

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

    <% form_tag({:action => 'register'}, :class => "tabular") do %> <%= error_messages_for 'user' %> @@ -29,7 +29,12 @@

    <%= select("user", "language", lang_options_for_select) %>

    -<% @user.custom_field_values.each do |value| %> +<% if Setting.openid? %> +

    +<%= text_field 'user', 'identity_url' %>

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

    <%= custom_field_tag_with_label :user, value %>

    <% end %> diff --git a/app/views/account/show.rhtml b/app/views/account/show.rhtml index 1160a5d8c..649b4b45c 100644 --- a/app/views/account/show.rhtml +++ b/app/views/account/show.rhtml @@ -2,19 +2,23 @@ <%= link_to(l(:button_edit), {:controller => 'users', :action => 'edit', :id => @user}, :class => 'icon icon-edit') if User.current.admin? %> -

    <%=h @user.name %>

    +

    <%= avatar @user %> <%=h @user.name %>

    -

    -<%= mail_to(h(@user.mail)) unless @user.pref.hide_mail %> +

      -
    • <%=l(:label_registered_on)%>: <%= format_date(@user.created_on) %>
    • -<% for custom_value in @custom_values %> -<% if !custom_value.value.empty? %> + <% unless @user.pref.hide_mail %> +
    • <%=l(:field_mail)%>: <%= mail_to(h(@user.mail), nil, :encode => 'javascript') %>
    • + <% end %> + <% for custom_value in @custom_values %> + <% if !custom_value.value.empty? %>
    • <%= custom_value.custom_field.name%>: <%=h show_value(custom_value) %>
    • -<% end %> -<% end %> + <% end %> + <% end %> +
    • <%=l(:label_registered_on)%>: <%= format_date(@user.created_on) %>
    • + <% unless @user.last_login_on.nil? %> +
    • <%=l(:field_last_login_on)%>: <%= format_date(@user.last_login_on) %>
    • + <% end %>
    -

    <% unless @memberships.empty? %>

    <%=l(:label_project_plural)%>

    @@ -25,8 +29,40 @@ <% end %> <% end %> +
    + +
    + +<% unless @events_by_day.empty? %> +

    <%= link_to l(:label_activity), :controller => 'projects', :action => 'activity', :user_id => @user, :from => @events_by_day.keys.first %>

    -

    <%=l(:label_activity)%>

    <%=l(:label_reported_issues)%>: <%= Issue.count(:conditions => ["author_id=?", @user.id]) %> -

    \ No newline at end of file +

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

    <%= format_activity_day(day) %>

    +
    +<% @events_by_day[day].sort {|x,y| y.event_datetime <=> x.event_datetime }.each do |e| -%> +
    + <%= format_time(e.event_datetime, false) %> + <%= content_tag('span', h(e.project), :class => 'project') %> + <%= link_to format_activity_title(e.event_title), e.event_url %>
    +
    <%= format_activity_description(e.event_description) %>
    +<% end -%> +
    +<% end -%> +
    + +<% other_formats_links do |f| %> + <%= f.link_to 'Atom', :url => {:controller => 'projects', :action => 'activity', :id => nil, :user_id => @user, :key => User.current.rss_key} %> +<% end %> + +<% content_for :header_tags do %> + <%= auto_discovery_link_tag(:atom, :controller => 'projects', :action => 'activity', :user_id => @user, :format => :atom, :key => User.current.rss_key) %> +<% end %> +<% end %> +
    + +<% html_title @user.name %> diff --git a/app/views/admin/index.rhtml b/app/views/admin/index.rhtml index 18bee34cb..323641744 100644 --- a/app/views/admin/index.rhtml +++ b/app/views/admin/index.rhtml @@ -19,7 +19,7 @@

    <%= link_to l(:label_tracker_plural), :controller => 'trackers' %> | <%= link_to l(:label_issue_status_plural), :controller => 'issue_statuses' %> | -<%= link_to l(:label_workflow), :controller => 'roles', :action => 'workflow' %> +<%= link_to l(:label_workflow), :controller => 'workflows', :action => 'edit' %>

    @@ -34,6 +34,16 @@ <%= link_to l(:label_settings), :controller => 'settings' %>

    +<% menu_items_for(:admin_menu) do |item, caption, url, selected| -%> + <%= content_tag 'p', + link_to(h(caption), item.url, item.html_options), + :class => ["icon22", "icon22-#{item.name}"].join(' ') %> +<% end -%> + +

    +<%= link_to l(:label_plugins), :controller => 'admin', :action => 'plugins' %> +

    +

    <%= link_to l(:label_information_plural), :controller => 'admin', :action => 'info' %>

    diff --git a/app/views/admin/info.rhtml b/app/views/admin/info.rhtml index 05c27f5ac..8c126b50a 100644 --- a/app/views/admin/info.rhtml +++ b/app/views/admin/info.rhtml @@ -4,24 +4,9 @@ - + +
    <%= l(:text_default_administrator_account_changed) %><%= image_tag (@flags[:default_admin_changed] ? 'true.png' : 'false.png'), :style => "vertical-align:bottom;" %>
    <%= l(:text_file_repository_writable) %><%= image_tag (@flags[:file_repository_writable] ? 'true.png' : 'false.png'), :style => "vertical-align:bottom;" %>
    <%= l(:text_file_repository_writable) %> (<%= Attachment.storage_path %>)<%= image_tag (@flags[:file_repository_writable] ? 'true.png' : 'false.png'), :style => "vertical-align:bottom;" %>
    <%= l(:text_plugin_assets_writable) %> (<%= Engines.public_directory %>)<%= image_tag (@flags[:plugin_assets_writable] ? 'true.png' : 'false.png'), :style => "vertical-align:bottom;" %>
    <%= l(:text_rmagick_available) %><%= image_tag (@flags[:rmagick_available] ? 'true.png' : 'false.png'), :style => "vertical-align:bottom;" %>
    -<% if @plugins.any? %> -  -

    <%= l(:label_plugins) %>

    - - <% @plugins.keys.sort {|x,y| x.to_s <=> y.to_s}.each do |plugin| %> - - - - - - - - <% end %> -
    <%=h @plugins[plugin].name %><%=h @plugins[plugin].description %><%=h @plugins[plugin].author %><%=h @plugins[plugin].version %><%= link_to(l(:button_configure), :controller => 'settings', :action => 'plugin', :id => plugin.to_s) if @plugins[plugin].configurable? %>
    -<% end %> - <% html_title(l(:label_information_plural)) -%> diff --git a/app/views/admin/plugins.rhtml b/app/views/admin/plugins.rhtml new file mode 100644 index 000000000..4ee6c142c --- /dev/null +++ b/app/views/admin/plugins.rhtml @@ -0,0 +1,19 @@ +

    <%= l(:label_plugins) %>

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

    <%= l(:label_no_data) %>

    +<% end %> diff --git a/app/views/admin/projects.rhtml b/app/views/admin/projects.rhtml index c42845622..40177a63b 100644 --- a/app/views/admin/projects.rhtml +++ b/app/views/admin/projects.rhtml @@ -4,33 +4,33 @@

    <%=l(:label_project_plural)%>

    -<% form_tag() do %> +<% form_tag({}, :method => :get) do %>
    <%= l(:label_filter_plural) %> <%= select_tag 'status', project_status_options_for_select(@status), :class => "small", :onchange => "this.form.submit(); return false;" %> -<%= submit_tag l(:button_apply), :class => "small" %> + +<%= text_field_tag 'name', params[:name], :size => 30 %> +<%= submit_tag l(:button_apply), :class => "small", :name => nil %>
    <% end %>   - <%= sort_header_tag('name', :caption => l(:label_project)) %> + - - <%= sort_header_tag('is_public', :caption => l(:field_is_public), :default_order => 'desc') %> - <%= sort_header_tag('created_on', :caption => l(:field_created_on), :default_order => 'desc') %> + + <% for project in @projects %> - "> - <%= css_project_classes(project) %>"> + + + +
    <%=l(:label_project)%> <%=l(:field_description)%><%=l(:label_subproject_plural)%><%=l(:field_is_public)%><%=l(:field_created_on)%>
    <%= project.active? ? link_to(h(project.name), :controller => 'projects', :action => 'settings', :id => project) : h(project.name) %> - <%= textilizable project.short_description, :project => project %> - <%= project.children.size %> - <%= image_tag 'true.png' if project.is_public? %> - <%= format_date(project.created_on) %> +
    <%= project.active? ? link_to(h(project.name), :controller => 'projects', :action => 'settings', :id => project) : h(project.name) %><%= textilizable project.short_description, :project => project %><%= image_tag 'true.png' if project.is_public? %><%= format_date(project.created_on) %> <%= link_to(l(:button_archive), { :controller => 'projects', :action => 'archive', :id => project }, :confirm => l(:text_are_you_sure), :method => :post, :class => 'icon icon-lock') if project.active? %> @@ -45,6 +45,4 @@
    -

    <%= pagination_links_full @project_pages, @project_count %>

    - <% html_title(l(:label_project_plural)) -%> diff --git a/app/views/attachments/_links.rhtml b/app/views/attachments/_links.rhtml index 9aae909fe..19ab6734a 100644 --- a/app/views/attachments/_links.rhtml +++ b/app/views/attachments/_links.rhtml @@ -3,14 +3,14 @@

    <%= link_to_attachment attachment, :class => 'icon icon-attachment' -%> <%= h(" - #{attachment.description}") unless attachment.description.blank? %> (<%= number_to_human_size attachment.filesize %>) - <% if options[:delete_url] %> - <%= link_to image_tag('delete.png'), options[:delete_url].update({:attachment_id => attachment}), + <% if options[:deletable] %> + <%= link_to image_tag('delete.png'), {:controller => 'attachments', :action => 'destroy', :id => attachment}, :confirm => l(:text_are_you_sure), :method => :post, :class => 'delete', :title => l(:button_delete) %> <% end %> - <% unless options[:no_author] %> + <% if options[:author] %> <%= attachment.author %>, <%= format_time(attachment.created_on) %> <% end %>

    diff --git a/app/views/auth_sources/list.rhtml b/app/views/auth_sources/list.rhtml index 6836e6c67..5729ec77c 100644 --- a/app/views/auth_sources/list.rhtml +++ b/app/views/auth_sources/list.rhtml @@ -9,6 +9,7 @@ <%=l(:field_name)%> <%=l(:field_type)%> <%=l(:field_host)%> + <%=l(:label_user_plural)%> @@ -18,8 +19,12 @@ <%= link_to source.name, :action => 'edit', :id => source%> <%= source.auth_method_name %> <%= source.host %> + <%= source.users.count %> <%= link_to l(:button_test), :action => 'test_connection', :id => source %> - <%= button_to l(:button_delete), { :action => 'destroy', :id => source }, :confirm => l(:text_are_you_sure), :class => "button-small" %> + <%= button_to l(:button_delete), { :action => 'destroy', :id => source }, + :confirm => l(:text_are_you_sure), + :class => "button-small", + :disabled => source.users.any? %> <% end %> diff --git a/app/views/boards/index.rhtml b/app/views/boards/index.rhtml index 655352a96..440a77412 100644 --- a/app/views/boards/index.rhtml +++ b/app/views/boards/index.rhtml @@ -29,11 +29,9 @@ -

    -<%= l(:label_export_to) %> -<%= link_to 'Atom', {:controller => 'projects', :action => 'activity', :id => @project, :format => 'atom', :show_messages => 1, :key => User.current.rss_key}, - :class => 'feed' %> -

    +<% other_formats_links do |f| %> + <%= f.link_to 'Atom', :url => {:controller => 'projects', :action => 'activity', :id => @project, :show_messages => 1, :key => User.current.rss_key} %> +<% end %> <% content_for :header_tags do %> <%= auto_discovery_link_tag(:atom, {:controller => 'projects', :action => 'activity', :id => @project, :format => 'atom', :show_messages => 1, :key => User.current.rss_key}) %> diff --git a/app/views/boards/show.rhtml b/app/views/boards/show.rhtml index 96818df34..011a25e06 100644 --- a/app/views/boards/show.rhtml +++ b/app/views/boards/show.rhtml @@ -4,7 +4,7 @@ <%= link_to_if_authorized l(:label_message_new), {:controller => 'messages', :action => 'new', :board_id => @board}, :class => 'icon icon-add', - :onclick => 'Element.show("add-message"); return false;' %> + :onclick => 'Element.show("add-message"); Form.Element.focus("message_subject"); return false;' %> <%= watcher_tag(@board, User.current) %> @@ -26,15 +26,16 @@

    <%=h @board.name %>

    +

    <%=h @board.description %>

    <% if @topics.any? %> - <%= sort_header_tag("#{Message.table_name}.created_on", :caption => l(:field_created_on)) %> - <%= sort_header_tag("#{Message.table_name}.replies_count", :caption => l(:label_reply_plural)) %> - <%= sort_header_tag("#{Message.table_name}.updated_on", :caption => l(:label_message_last)) %> + <%= sort_header_tag('created_on', :caption => l(:field_created_on)) %> + <%= sort_header_tag('replies', :caption => l(:label_reply_plural)) %> + <%= sort_header_tag('updated_on', :caption => l(:label_message_last)) %> <% @topics.each do |topic| %> diff --git a/app/views/common/_diff.rhtml b/app/views/common/_diff.rhtml index 0b28101b7..104845b4d 100644 --- a/app/views/common/_diff.rhtml +++ b/app/views/common/_diff.rhtml @@ -1,4 +1,5 @@ -<% Redmine::UnifiedDiff.new(diff, diff_type).each do |table_file| -%> +<% diff = Redmine::UnifiedDiff.new(diff, :type => diff_type, :max_lines => Setting.diff_max_lines_displayed.to_i) -%> +<% diff.each do |table_file| -%>
    <% if diff_type == 'sbs' -%>
    <%= l(:field_subject) %> <%= l(:field_author) %>
    @@ -62,3 +63,5 @@ <% end -%> + +<%= l(:text_diff_truncated) if diff.truncated? %> diff --git a/app/views/common/feed.atom.rxml b/app/views/common/feed.atom.rxml index c1b88a28e..8d07cf208 100644 --- a/app/views/common/feed.atom.rxml +++ b/app/views/common/feed.atom.rxml @@ -6,7 +6,7 @@ xml.feed "xmlns" => "http://www.w3.org/2005/Atom" do xml.id url_for(:controller => 'welcome', :only_path => false) xml.updated((@items.first ? @items.first.event_datetime : Time.now).xmlschema) xml.author { xml.name "#{Setting.app_title}" } - xml.generator(:uri => Redmine::Info.url, :version => Redmine::VERSION) { xml.text! Redmine::Info.versioned_name; } + xml.generator(:uri => Redmine::Info.url) { xml.text! Redmine::Info.app_name; } @items.each do |item| xml.entry do url = url_for(item.event_url(:only_path => false)) diff --git a/app/views/custom_fields/_form.rhtml b/app/views/custom_fields/_form.rhtml index f4aee6870..874c571bf 100644 --- a/app/views/custom_fields/_form.rhtml +++ b/app/views/custom_fields/_form.rhtml @@ -49,23 +49,6 @@ function toggle_custom_field_format() { } } -function addValueField() { - var f = $$('p#custom_field_possible_values span'); - p = document.getElementById("custom_field_possible_values"); - var v = f[0].cloneNode(true); - v.childNodes[0].value = ""; - p.appendChild(v); -} - -function deleteValueField(e) { - var f = $$('p#custom_field_possible_values span'); - if (f.length == 1) { - e.parentNode.childNodes[0].value = ""; - } else { - Element.remove(e.parentNode); - } -} - //]]> @@ -76,22 +59,22 @@ function deleteValueField(e) { <%= f.text_field :min_length, :size => 5, :no_label => true %> - <%= f.text_field :max_length, :size => 5, :no_label => true %>
    (<%=l(:text_min_max_length_info)%>)

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

    -

    -<% (@custom_field.possible_values.to_a + [""]).each do |value| %> -<%= text_field_tag 'custom_field[possible_values][]', value, :size => 30 %> <%= image_to_function "delete.png", "deleteValueField(this);return false" %>
    -<% end %> -

    +

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

    <%= @custom_field.field_format == 'bool' ? f.check_box(:default_value) : f.text_field(:default_value) %>

    -<% case @custom_field.type.to_s +<% case @custom_field.class.name when "IssueCustomField" %>
    <%=l(:label_tracker_plural)%> <% for tracker in @trackers %> - <%= check_box_tag "tracker_ids[]", tracker.id, (@custom_field.trackers.include? tracker) %> <%= tracker.name %> + <%= check_box_tag "custom_field[tracker_ids][]", tracker.id, (@custom_field.trackers.include? tracker) %> <%= tracker.name %> <% end %> + <%= hidden_field_tag "custom_field[tracker_ids][]", '' %>
     

    <%= f.check_box :is_required %>

    @@ -101,6 +84,7 @@ when "IssueCustomField" %> <% when "UserCustomField" %>

    <%= f.check_box :is_required %>

    +

    <%= f.check_box :editable %>

    <% when "ProjectCustomField" %>

    <%= f.check_box :is_required %>

    diff --git a/app/views/custom_fields/list.rhtml b/app/views/custom_fields/index.rhtml similarity index 100% rename from app/views/custom_fields/list.rhtml rename to app/views/custom_fields/index.rhtml diff --git a/app/views/documents/index.rhtml b/app/views/documents/index.rhtml index 14d997360..7449b67c6 100644 --- a/app/views/documents/index.rhtml +++ b/app/views/documents/index.rhtml @@ -2,7 +2,7 @@ <%= link_to_if_authorized l(:label_document_new), {:controller => 'documents', :action => 'new', :project_id => @project}, :class => 'icon icon-add', - :onclick => 'Element.show("add-document"); return false;' %> + :onclick => 'Element.show("add-document"); Form.Element.focus("document_title"); return false;' %>

    <%= l(:label_attachment_plural) %>

    -<%= link_to_attachments @attachments, :delete_url => (authorize_for('documents', 'destroy_attachment') ? {:controller => 'documents', :action => 'destroy_attachment', :id => @document} : nil) %> +<%= link_to_attachments @document %> <% if authorize_for('documents', 'add_attachment') %>

    <%= link_to l(:label_attachment_new), {}, :onclick => "Element.show('add_attachment_form'); Element.hide(this); Element.scrollTo('add_attachment_form'); return false;", diff --git a/app/views/issues/_changesets.rhtml b/app/views/issues/_changesets.rhtml index caa983cbf..15b75c61d 100644 --- a/app/views/issues/_changesets.rhtml +++ b/app/views/issues/_changesets.rhtml @@ -2,7 +2,7 @@

    <%= link_to("#{l(:label_revision)} #{changeset.revision}", :controller => 'repositories', :action => 'revision', :id => @project, :rev => changeset.revision) %>
    - <%= authoring(changeset.committed_on, changeset.committer) %>

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

    <%= textilizable(changeset, :comments) %>
    <% end %> diff --git a/app/views/issues/_edit.rhtml b/app/views/issues/_edit.rhtml index 2c7a4286e..413f21729 100644 --- a/app/views/issues/_edit.rhtml +++ b/app/views/issues/_edit.rhtml @@ -35,6 +35,7 @@
    <%= l(:field_notes) %> <%= text_area_tag 'notes', @notes, :cols => 60, :rows => 10, :class => 'wiki-edit' %> <%= wikitoolbar_for 'notes' %> + <%= call_hook(:view_issues_edit_notes_bottom, { :issue => @issue, :notes => @notes, :form => f }) %>

    <%=l(:label_attachment_plural)%>
    <%= render :partial => 'attachments/form' %>

    diff --git a/app/views/issues/_form.rhtml b/app/views/issues/_form.rhtml index 419536fee..fac2d6a36 100644 --- a/app/views/issues/_form.rhtml +++ b/app/views/issues/_form.rhtml @@ -8,13 +8,14 @@
    >

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

    -

    <%= f.text_area :description, :required => true, +

    <%= f.text_area :description, :cols => 60, :rows => (@issue.description.blank? ? 10 : [[10, @issue.description.length / 50].max, 100].min), :accesskey => accesskey(:edit), :class => 'wiki-edit' %>

    +
    <% if @issue.new_record? || @allowed_statuses.any? %>

    <%= f.select :status_id, (@allowed_statuses.collect {|p| [p.name, p.id]}), :required => true %>

    @@ -24,11 +25,13 @@

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

    <%= f.select :assigned_to_id, (@issue.assignable_users.collect {|m| [m.name, m.id]}), :include_blank => true %>

    +<% unless @project.issue_categories.empty? %>

    <%= f.select :category_id, (@project.issue_categories.collect {|c| [c.name, c.id]}), :include_blank => true %> <%= prompt_to_remote(l(:label_issue_category_new), l(:label_issue_category_new), 'category[name]', {:controller => 'projects', :action => 'add_issue_category', :id => @project}, :class => 'small', :tabindex => 199) if authorize_for('projects', 'add_issue_category') %>

    +<% end %> <%= content_tag('p', f.select(:fixed_version_id, (@project.versions.sort.collect {|v| [v.name, v.id]}), { :include_blank => true })) unless @project.versions.empty? %> @@ -43,11 +46,20 @@
    <%= render :partial => 'form_custom_fields' %> +
    <% if @issue.new_record? %>

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

    <% end %> +<% if @issue.new_record? && User.current.allowed_to?(:add_issue_watchers, @project) -%> +

    +<% @issue.project.users.sort.each do |user| -%> + +<% end -%> +

    +<% end %> + <%= call_hook(:view_issues_form_details_bottom, { :issue => @issue, :form => f }) %> <%= wikitoolbar_for 'issue_description' %> diff --git a/app/views/issues/_form_update.rhtml b/app/views/issues/_form_update.rhtml index 25e81a7fd..3f17a0300 100644 --- a/app/views/issues/_form_update.rhtml +++ b/app/views/issues/_form_update.rhtml @@ -1,3 +1,4 @@ +

    <%= f.select :status_id, (@allowed_statuses.collect {|p| [p.name, p.id]}), :required => true %>

    <%= f.select :assigned_to_id, (@issue.assignable_users.collect {|m| [m.name, m.id]}), :include_blank => true %>

    @@ -8,3 +9,4 @@ (@project.versions.sort.collect {|v| [v.name, v.id]}), { :include_blank => true })) unless @project.versions.empty? %>
    +
    diff --git a/app/views/issues/_history.rhtml b/app/views/issues/_history.rhtml index b8efdb400..267263b72 100644 --- a/app/views/issues/_history.rhtml +++ b/app/views/issues/_history.rhtml @@ -1,14 +1,16 @@ <% reply_links = authorize_for('issues', 'edit') -%> <% for journal in journals %> -
    -

    <%= link_to "##{journal.indice}", :anchor => "note-#{journal.indice}" %>
    - <%= content_tag('a', '', :name => "note-#{journal.indice}")%> - <%= format_time(journal.created_on) %> - <%= journal.user.name %>

    -
      - <% for detail in journal.details %> -
    • <%= show_detail(detail) %>
    • - <% end %> -
    - <%= render_notes(journal, :reply_links => reply_links) unless journal.notes.blank? %> -
    +
    +

    <%= link_to "##{journal.indice}", :anchor => "note-#{journal.indice}" %>
    + <%= content_tag('a', '', :name => "note-#{journal.indice}")%> + <%= authoring journal.created_on, journal.user, :label => :label_updated_time_by %>

    + <%= avatar(journal.user, :size => "32") %> +
      + <% for detail in journal.details %> +
    • <%= show_detail(detail) %>
    • + <% end %> +
    + <%= render_notes(journal, :reply_links => reply_links) unless journal.notes.blank? %> +
    + <%= call_hook(:view_issues_history_journal_bottom, { :journal => journal }) %> <% end %> diff --git a/app/views/issues/_list.rhtml b/app/views/issues/_list.rhtml index b42357894..932676015 100644 --- a/app/views/issues/_list.rhtml +++ b/app/views/issues/_list.rhtml @@ -4,14 +4,14 @@
    - <%= sort_header_tag("#{Issue.table_name}.id", :caption => '#', :default_order => 'desc') %> + <%= sort_header_tag('id', :caption => '#', :default_order => 'desc') %> <% query.columns.each do |column| %> <%= column_header(column) %> <% end %> <% issues.each do |issue| -%> - "> + <% query.columns.each do |column| %><%= content_tag 'td', column_content(column, issue), :class => column.name %><% end %> diff --git a/app/views/issues/_list_simple.rhtml b/app/views/issues/_list_simple.rhtml index 8900b7359..64c00e5a7 100644 --- a/app/views/issues/_list_simple.rhtml +++ b/app/views/issues/_list_simple.rhtml @@ -3,21 +3,22 @@
    <%= link_to image_tag('toggle_check.png'), {}, :onclick => 'toggleIssuesSelection(Element.up(this, "form")); return false;', :title => "#{l(:button_check_all)}/#{l(:button_uncheck_all)}" %>
    <%= check_box_tag("ids[]", issue.id, false, :id => nil) %> <%= link_to issue.id, :controller => 'issues', :action => 'show', :id => issue %>
    + <% for issue in issues %> - "> + - + + + <%= link_to h(truncate(issue.subject, 60)), :controller => 'issues', :action => 'show', :id => issue %> (<%=h issue.status %>) + <% end %> diff --git a/app/views/issues/_relations.rhtml b/app/views/issues/_relations.rhtml index d4b3e5aa6..f99976f5c 100644 --- a/app/views/issues/_relations.rhtml +++ b/app/views/issues/_relations.rhtml @@ -8,9 +8,10 @@ <% if @issue.relations.any? %>
    #<%=l(:field_project)%> <%=l(:field_tracker)%> <%=l(:field_subject)%>
    - <%= check_box_tag("ids[]", issue.id, false, :style => 'display:none;') %> + <%= check_box_tag("ids[]", issue.id, false, :style => 'display:none;') %> <%= link_to issue.id, :controller => 'issues', :action => 'show', :id => issue %> <%=h issue.project.name %> - <%= issue.tracker.name %>
    - <%= issue.status.name %> - <%= format_time(issue.updated_on) %>
    <%=h issue.project %><%=h issue.tracker %> - <%= link_to h(issue.subject), :controller => 'issues', :action => 'show', :id => issue %> -
    -<% @issue.relations.each do |relation| %> +<% @issue.relations.select {|r| r.other_issue(@issue).visible? }.each do |relation| %> - + diff --git a/app/views/issues/_sidebar.rhtml b/app/views/issues/_sidebar.rhtml index 1b486966e..bbc00f091 100644 --- a/app/views/issues/_sidebar.rhtml +++ b/app/views/issues/_sidebar.rhtml @@ -2,23 +2,25 @@ <%= link_to l(:label_issue_view_all), { :controller => 'issues', :action => 'index', :project_id => @project, :set_filter => 1 } %>
    <% if @project %> <%= link_to l(:field_summary), :controller => 'reports', :action => 'issue_report', :id => @project %>
    -<%= link_to l(:label_change_log), :controller => 'projects', :action => 'changelog', :id => @project %> +<%= link_to l(:label_change_log), :controller => 'projects', :action => 'changelog', :id => @project %>
    +<% end %> +<%= call_hook(:view_issues_sidebar_issues_bottom) %> <% planning_links = [] - planning_links << link_to_if_authorized(l(:label_calendar), :action => 'calendar', :project_id => @project) - planning_links << link_to_if_authorized(l(:label_gantt), :action => 'gantt', :project_id => @project) - planning_links.compact! - unless planning_links.empty? %> + planning_links << link_to(l(:label_calendar), :action => 'calendar', :project_id => @project) if User.current.allowed_to?(:view_calendar, @project, :global => true) + planning_links << link_to(l(:label_gantt), :action => 'gantt', :project_id => @project) if User.current.allowed_to?(:view_gantt, @project, :global => true) +%> +<% unless planning_links.empty? %>

    <%= l(:label_planning) %>

    <%= planning_links.join(' | ') %>

    -<% end %> - +<%= call_hook(:view_issues_sidebar_planning_bottom) %> <% end %> <% unless sidebar_queries.empty? -%>

    <%= l(:label_query_plural) %>

    <% sidebar_queries.each do |query| -%> -<%= link_to query.name, :controller => 'issues', :action => 'index', :project_id => @project, :query_id => query %>
    +<%= link_to(h(query.name), :controller => 'issues', :action => 'index', :project_id => @project, :query_id => query) %>
    <% end -%> +<%= call_hook(:view_issues_sidebar_queries_bottom) %> <% end -%> diff --git a/app/views/issues/bulk_edit.rhtml b/app/views/issues/bulk_edit.rhtml index b916cf092..acda6a65f 100644 --- a/app/views/issues/bulk_edit.rhtml +++ b/app/views/issues/bulk_edit.rhtml @@ -27,7 +27,7 @@ + options_from_collection_for_select(@project.versions.sort, :id, :name)) %>

    @@ -38,12 +38,20 @@

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

    +<%= select_tag "custom_field_values[#{custom_field.id}]", options_for_select([[l(:label_no_change_option), '']] + custom_field.possible_values) %> +

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

    <%= submit_tag l(:button_submit) %> diff --git a/app/views/issues/context_menu.rhtml b/app/views/issues/context_menu.rhtml index 671655db7..0d50e5f76 100644 --- a/app/views/issues/context_menu.rhtml +++ b/app/views/issues/context_menu.rhtml @@ -79,7 +79,10 @@ :class => 'icon-copy', :disabled => !@can[:copy] %> <% if @can[:log_time] -%>

  • <%= context_menu_link l(:button_log_time), {:controller => 'timelog', :action => 'edit', :issue_id => @issue}, - :class => 'icon-time' %>
  • + :class => 'icon-time-add' %> + <% end %> + <% if User.current.logged? %> +
  • <%= watcher_link(@issue, User.current) %>
  • <% end %> <% end %> diff --git a/app/views/issues/gantt.rfpdf b/app/views/issues/gantt.rfpdf deleted file mode 100644 index 692e0d261..000000000 --- a/app/views/issues/gantt.rfpdf +++ /dev/null @@ -1,188 +0,0 @@ -<% -pdf=IfpdfHelper::IFPDF.new(current_language) -pdf.SetTitle("#{@project.name} - #{l(:label_gantt)}") -pdf.AliasNbPages -pdf.footer_date = format_date(Date.today) -pdf.AddPage("L") -pdf.SetFontStyle('B',12) -pdf.SetX(15) -pdf.Cell(70, 20, @project.name) -pdf.Ln -pdf.SetFontStyle('B',9) - -subject_width = 70 -header_heigth = 5 - -headers_heigth = header_heigth -show_weeks = false -show_days = false - -if @gantt.months < 7 - show_weeks = true - headers_heigth = 2*header_heigth - if @gantt.months < 3 - show_days = true - headers_heigth = 3*header_heigth - end -end - -g_width = 210 -zoom = (g_width) / (@gantt.date_to - @gantt.date_from + 1) -g_height = 120 -t_height = g_height + headers_heigth - -y_start = pdf.GetY - - -# -# Months headers -# -month_f = @gantt.date_from -left = subject_width -height = header_heigth -@gantt.months.times do - width = ((month_f >> 1) - month_f) * zoom - pdf.SetY(y_start) - pdf.SetX(left) - pdf.Cell(width, height, "#{month_f.year}-#{month_f.month}", "LTR", 0, "C") - left = left + width - month_f = month_f >> 1 -end - -# -# Weeks headers -# -if show_weeks - left = subject_width - height = header_heigth - if @gantt.date_from.cwday == 1 - # @gantt.date_from is monday - week_f = @gantt.date_from - else - # find next monday after @gantt.date_from - week_f = @gantt.date_from + (7 - @gantt.date_from.cwday + 1) - width = (7 - @gantt.date_from.cwday + 1) * zoom-1 - pdf.SetY(y_start + header_heigth) - pdf.SetX(left) - pdf.Cell(width + 1, height, "", "LTR") - left = left + width+1 - end - while week_f <= @gantt.date_to - width = (week_f + 6 <= @gantt.date_to) ? 7 * zoom : (@gantt.date_to - week_f + 1) * zoom - pdf.SetY(y_start + header_heigth) - pdf.SetX(left) - pdf.Cell(width, height, (width >= 5 ? week_f.cweek.to_s : ""), "LTR", 0, "C") - left = left + width - week_f = week_f+7 - end -end - -# -# Days headers -# -if show_days - left = subject_width - height = header_heigth - wday = @gantt.date_from.cwday - pdf.SetFontStyle('B',7) - (@gantt.date_to - @gantt.date_from + 1).to_i.times do - width = zoom - pdf.SetY(y_start + 2 * header_heigth) - pdf.SetX(left) - pdf.Cell(width, height, day_name(wday).first, "LTR", 0, "C") - left = left + width - wday = wday + 1 - wday = 1 if wday > 7 - end -end - -pdf.SetY(y_start) -pdf.SetX(15) -pdf.Cell(subject_width+g_width-15, headers_heigth, "", 1) - - -# -# Tasks -# -top = headers_heigth + y_start -pdf.SetFontStyle('B',7) -@gantt.events.each do |i| - pdf.SetY(top) - pdf.SetX(15) - - if i.is_a? Issue - pdf.Cell(subject_width-15, 5, "#{i.tracker.name} #{i.id}: #{i.subject}".sub(/^(.{30}[^\s]*\s).*$/, '\1 (...)'), "LR") - else - pdf.Cell(subject_width-15, 5, "#{l(:label_version)}: #{i.name}", "LR") - end - - pdf.SetY(top) - pdf.SetX(subject_width) - pdf.Cell(g_width, 5, "", "LR") - - pdf.SetY(top+1.5) - - if i.is_a? Issue - i_start_date = (i.start_date >= @gantt.date_from ? i.start_date : @gantt.date_from ) - i_end_date = (i.due_before <= @gantt.date_to ? i.due_before : @gantt.date_to ) - - i_done_date = i.start_date + ((i.due_before - i.start_date+1)*i.done_ratio/100).floor - i_done_date = (i_done_date <= @gantt.date_from ? @gantt.date_from : i_done_date ) - i_done_date = (i_done_date >= @gantt.date_to ? @gantt.date_to : i_done_date ) - - i_late_date = [i_end_date, Date.today].min if i_start_date < Date.today - - i_left = ((i_start_date - @gantt.date_from)*zoom) - i_width = ((i_end_date - i_start_date + 1)*zoom) - d_width = ((i_done_date - i_start_date)*zoom) - l_width = ((i_late_date - i_start_date+1)*zoom) if i_late_date - l_width ||= 0 - - pdf.SetX(subject_width + i_left) - pdf.SetFillColor(200,200,200) - pdf.Cell(i_width, 2, "", 0, 0, "", 1) - - if l_width > 0 - pdf.SetY(top+1.5) - pdf.SetX(subject_width + i_left) - pdf.SetFillColor(255,100,100) - pdf.Cell(l_width, 2, "", 0, 0, "", 1) - end - if d_width > 0 - pdf.SetY(top+1.5) - pdf.SetX(subject_width + i_left) - pdf.SetFillColor(100,100,255) - pdf.Cell(d_width, 2, "", 0, 0, "", 1) - end - - pdf.SetY(top+1.5) - pdf.SetX(subject_width + i_left + i_width) - pdf.Cell(30, 2, "#{i.status.name} #{i.done_ratio}%") - else - i_left = ((i.start_date - @gantt.date_from)*zoom) - - pdf.SetX(subject_width + i_left) - pdf.SetFillColor(50,200,50) - pdf.Cell(2, 2, "", 0, 0, "", 1) - - pdf.SetY(top+1.5) - pdf.SetX(subject_width + i_left + 3) - pdf.Cell(30, 2, "#{i.name}") - end - - - top = top + 5 - pdf.SetDrawColor(200, 200, 200) - pdf.Line(15, top, subject_width+g_width, top) - if pdf.GetY() > 180 - pdf.AddPage("L") - top = 20 - pdf.Line(15, top, subject_width+g_width, top) - end - pdf.SetDrawColor(0, 0, 0) -end - -pdf.Line(15, top, subject_width+g_width, top) - -%> -<%= pdf.Output %> \ No newline at end of file diff --git a/app/views/issues/gantt.rhtml b/app/views/issues/gantt.rhtml index b9af1f961..0b38982ce 100644 --- a/app/views/issues/gantt.rhtml +++ b/app/views/issues/gantt.rhtml @@ -241,13 +241,10 @@ if Date.today >= @gantt.date_from and Date.today <= @gantt.date_to %>
    <%= l(relation.label_for(@issue)) %> <%= "(#{lwr(:actionview_datehelper_time_in_words_day, relation.delay)})" if relation.delay && relation.delay != 0 %> <%= link_to_issue relation.other_issue(@issue) %><%= l(relation.label_for(@issue)) %> <%= "(#{lwr(:actionview_datehelper_time_in_words_day, relation.delay)})" if relation.delay && relation.delay != 0 %> + <%= h(relation.other_issue(@issue).project) + ' - ' if Setting.cross_project_issue_relations? %> <%= link_to_issue relation.other_issue(@issue) %> <%=h relation.other_issue(@issue).subject %> <%= relation.other_issue(@issue).status.name %> <%= format_date(relation.other_issue(@issue).start_date) %>
    -

    -<%= l(:label_export_to) %> -<%= link_to 'PDF', @gantt.params.merge(:format => 'pdf'), :class => 'pdf' %> -<% if @gantt.respond_to?('to_image') %> -<%= link_to 'PNG', @gantt.params.merge(:format => 'png'), :class => 'image' %> +<% other_formats_links do |f| %> + <%= f.link_to 'PDF', :url => @gantt.params %> + <%= f.link_to('PNG', :url => @gantt.params) if @gantt.respond_to?('to_image') %> <% end %> -

    <% end # query.valid? %> <% content_for :sidebar do %> diff --git a/app/views/issues/index.rfpdf b/app/views/issues/index.rfpdf deleted file mode 100644 index d5a8d3c31..000000000 --- a/app/views/issues/index.rfpdf +++ /dev/null @@ -1,50 +0,0 @@ -<% pdf=IfpdfHelper::IFPDF.new(current_language) - title = @project ? "#{@project.name} - #{l(:label_issue_plural)}" : "#{l(:label_issue_plural)}" - pdf.SetTitle(title) - pdf.AliasNbPages - pdf.footer_date = format_date(Date.today) - pdf.AddPage("L") - row_height = 7 - - # - # title - # - pdf.SetFontStyle('B',11) - pdf.Cell(190,10, title) - pdf.Ln - - # - # headers - # - pdf.SetFontStyle('B',10) - pdf.SetFillColor(230, 230, 230) - pdf.Cell(15, row_height, "#", 0, 0, 'L', 1) - pdf.Cell(30, row_height, l(:field_tracker), 0, 0, 'L', 1) - pdf.Cell(30, row_height, l(:field_status), 0, 0, 'L', 1) - pdf.Cell(30, row_height, l(:field_priority), 0, 0, 'L', 1) - pdf.Cell(40, row_height, l(:field_assigned_to), 0, 0, 'L', 1) - pdf.Cell(25, row_height, l(:field_updated_on), 0, 0, 'L', 1) - pdf.Cell(0, row_height, l(:field_subject), 0, 0, 'L', 1) - pdf.Line(10, pdf.GetY, 287, pdf.GetY) - pdf.Ln - pdf.Line(10, pdf.GetY, 287, pdf.GetY) - pdf.SetY(pdf.GetY() + 1) - - # - # rows - # - pdf.SetFontStyle('',9) - pdf.SetFillColor(255, 255, 255) - @issues.each do |issue| - pdf.Cell(15, row_height, issue.id.to_s, 0, 0, 'L', 1) - pdf.Cell(30, row_height, issue.tracker.name, 0, 0, 'L', 1) - pdf.Cell(30, row_height, issue.status.name, 0, 0, 'L', 1) - pdf.Cell(30, row_height, issue.priority.name, 0, 0, 'L', 1) - pdf.Cell(40, row_height, issue.assigned_to ? issue.assigned_to.name : '', 0, 0, 'L', 1) - pdf.Cell(25, row_height, format_date(issue.updated_on), 0, 0, 'L', 1) - pdf.MultiCell(0, row_height, (@project == issue.project ? issue.subject : "#{issue.project.name} - #{issue.subject}")) - pdf.Line(10, pdf.GetY, 287, pdf.GetY) - pdf.SetY(pdf.GetY() + 1) - end -%> -<%= pdf.Output %> \ No newline at end of file diff --git a/app/views/issues/index.rhtml b/app/views/issues/index.rhtml index 973f3eb25..dc93e41f2 100644 --- a/app/views/issues/index.rhtml +++ b/app/views/issues/index.rhtml @@ -3,7 +3,7 @@ <% html_title(l(:label_issue_plural)) %> <% form_tag({ :controller => 'queries', :action => 'new' }, :id => 'query_form') do %> - <%= hidden_field_tag('project_id', @project.id) if @project %> + <%= hidden_field_tag('project_id', @project.to_param) if @project %>
    <%= l(:label_filter_plural) %> <%= render :partial => 'queries/filters', :locals => {:query => @query} %>

    @@ -14,7 +14,8 @@ }, :class => 'icon icon-checked' %> <%= link_to_remote l(:button_clear), - { :url => { :set_filter => 1 }, + { :url => { :set_filter => 1, :project_id => @project }, + :method => :get, :update => "content", }, :class => 'icon icon-reload' %> @@ -43,12 +44,12 @@ <%= render :partial => 'issues/list', :locals => {:issues => @issues, :query => @query} %>

    <%= pagination_links_full @issue_pages, @issue_count %>

    -

    -<%= l(:label_export_to) %> -<%= link_to 'Atom', {:query_id => @query, :format => 'atom', :key => User.current.rss_key}, :class => 'feed' %> -<%= link_to 'CSV', {:format => 'csv'}, :class => 'csv' %> -<%= link_to 'PDF', {:format => 'pdf'}, :class => 'pdf' %> -

    +<% other_formats_links do |f| %> + <%= f.link_to 'Atom', :url => {:query_id => (@query.new_record? ? nil : @query), :key => User.current.rss_key} %> + <%= f.link_to 'CSV' %> + <%= f.link_to 'PDF' %> +<% end %> + <% end %> <% end %> diff --git a/app/views/issues/move.rhtml b/app/views/issues/move.rhtml index 35761e160..e1189db45 100644 --- a/app/views/issues/move.rhtml +++ b/app/views/issues/move.rhtml @@ -6,16 +6,19 @@ <%= @issues.collect {|i| hidden_field_tag('ids[]', i.id)}.join %>
    -

    +

    <%= select_tag "new_project_id", - options_from_collection_for_select(@allowed_projects, 'id', 'name', @target_project.id), + project_tree_options_for_select(@allowed_projects, :selected => @target_project), :onchange => remote_function(:url => { :action => 'move' }, :method => :get, :update => 'content', :with => "Form.serialize('move_form')") %>

    -

    +

    <%= select_tag "new_tracker_id", "" + options_from_collection_for_select(@trackers, "id", "name") %>

    + +

    +<%= check_box_tag "copy_options[copy]", "1" %>

    <%= submit_tag l(:button_move) %> diff --git a/app/views/issues/new.rhtml b/app/views/issues/new.rhtml index 280e2009b..94f86dde9 100644 --- a/app/views/issues/new.rhtml +++ b/app/views/issues/new.rhtml @@ -7,6 +7,7 @@ <%= render :partial => 'issues/form', :locals => {:f => f} %> <%= submit_tag l(:button_create) %> + <%= submit_tag l(:button_create_and_continue), :name => 'continue' %> <%= link_to_remote l(:label_preview), { :url => { :controller => 'issues', :action => 'preview', :project_id => @project }, :method => 'post', @@ -14,6 +15,12 @@ :with => "Form.serialize('issue-form')", :complete => "Element.scrollTo('preview')" }, :accesskey => accesskey(:preview) %> + + <%= javascript_tag "Form.Element.focus('issue_subject');" %> <% end %>
    + +<% content_for :header_tags do %> + <%= stylesheet_link_tag 'scm' %> +<% end %> diff --git a/app/views/issues/show.rfpdf b/app/views/issues/show.rfpdf deleted file mode 100644 index 73d9d66b5..000000000 --- a/app/views/issues/show.rfpdf +++ /dev/null @@ -1,126 +0,0 @@ -<% pdf=IfpdfHelper::IFPDF.new(current_language) - pdf.SetTitle("#{@project.name} - ##{@issue.tracker.name} #{@issue.id}") - pdf.AliasNbPages - pdf.footer_date = format_date(Date.today) - pdf.AddPage - - pdf.SetFontStyle('B',11) - pdf.Cell(190,10, "#{@issue.project} - #{@issue.tracker} # #{@issue.id}: #{@issue.subject}") - pdf.Ln - - y0 = pdf.GetY - - pdf.SetFontStyle('B',9) - pdf.Cell(35,5, l(:field_status) + ":","LT") - pdf.SetFontStyle('',9) - pdf.Cell(60,5, @issue.status.name,"RT") - pdf.SetFontStyle('B',9) - pdf.Cell(35,5, l(:field_priority) + ":","LT") - pdf.SetFontStyle('',9) - pdf.Cell(60,5, @issue.priority.name,"RT") - pdf.Ln - - pdf.SetFontStyle('B',9) - pdf.Cell(35,5, l(:field_author) + ":","L") - pdf.SetFontStyle('',9) - pdf.Cell(60,5, @issue.author.name,"R") - pdf.SetFontStyle('B',9) - pdf.Cell(35,5, l(:field_category) + ":","L") - pdf.SetFontStyle('',9) - pdf.Cell(60,5, (@issue.category ? @issue.category.name : "-"),"R") - pdf.Ln - - pdf.SetFontStyle('B',9) - pdf.Cell(35,5, l(:field_created_on) + ":","L") - pdf.SetFontStyle('',9) - pdf.Cell(60,5, format_date(@issue.created_on),"R") - pdf.SetFontStyle('B',9) - pdf.Cell(35,5, l(:field_assigned_to) + ":","L") - pdf.SetFontStyle('',9) - pdf.Cell(60,5, (@issue.assigned_to ? @issue.assigned_to.name : "-"),"R") - pdf.Ln - - pdf.SetFontStyle('B',9) - pdf.Cell(35,5, l(:field_updated_on) + ":","LB") - pdf.SetFontStyle('',9) - pdf.Cell(60,5, format_date(@issue.updated_on),"RB") - pdf.SetFontStyle('B',9) - pdf.Cell(35,5, l(:field_due_date) + ":","LB") - pdf.SetFontStyle('',9) - pdf.Cell(60,5, format_date(@issue.due_date),"RB") - pdf.Ln - - for custom_value in @issue.custom_values - pdf.SetFontStyle('B',9) - pdf.Cell(35,5, custom_value.custom_field.name + ":","L") - pdf.SetFontStyle('',9) - pdf.MultiCell(155,5, (show_value custom_value),"R") - end - - pdf.SetFontStyle('B',9) - pdf.Cell(35,5, l(:field_subject) + ":","LTB") - pdf.SetFontStyle('',9) - pdf.Cell(155,5, @issue.subject,"RTB") - pdf.Ln - - pdf.SetFontStyle('B',9) - pdf.Cell(35,5, l(:field_description) + ":") - pdf.SetFontStyle('',9) - pdf.MultiCell(155,5, @issue.description,"BR") - - pdf.Line(pdf.GetX, y0, pdf.GetX, pdf.GetY) - pdf.Line(pdf.GetX, pdf.GetY, 170, pdf.GetY) - - pdf.Ln - - if @issue.changesets.any? && User.current.allowed_to?(:view_changesets, @issue.project) - pdf.SetFontStyle('B',9) - pdf.Cell(190,5, l(:label_associated_revisions), "B") - pdf.Ln - for changeset in @issue.changesets - pdf.SetFontStyle('B',8) - pdf.Cell(190,5, format_time(changeset.committed_on) + " - " + changeset.committer) - pdf.Ln - unless changeset.comments.blank? - pdf.SetFontStyle('',8) - pdf.MultiCell(190,5, changeset.comments) - end - pdf.Ln - end - end - - pdf.SetFontStyle('B',9) - pdf.Cell(190,5, l(:label_history), "B") - pdf.Ln - for journal in @issue.journals.find(:all, :include => [:user, :details], :order => "#{Journal.table_name}.created_on ASC") - pdf.SetFontStyle('B',8) - pdf.Cell(190,5, format_time(journal.created_on) + " - " + journal.user.name) - pdf.Ln - pdf.SetFontStyle('I',8) - for detail in journal.details - pdf.Cell(190,5, "- " + show_detail(detail, true)) - pdf.Ln - end - if journal.notes? - pdf.SetFontStyle('',8) - pdf.MultiCell(190,5, journal.notes) - end - pdf.Ln - end - - if @issue.attachments.any? - pdf.SetFontStyle('B',9) - pdf.Cell(190,5, l(:label_attachment_plural), "B") - pdf.Ln - for attachment in @issue.attachments - pdf.SetFontStyle('',8) - pdf.Cell(80,5, attachment.filename) - pdf.Cell(20,5, number_to_human_size(attachment.filesize),0,0,"R") - pdf.Cell(25,5, format_date(attachment.created_on),0,0,"R") - pdf.Cell(65,5, attachment.author.name,0,0,"R") - pdf.Ln - end - end -%> - -<%= pdf.Output %> diff --git a/app/views/issues/show.rhtml b/app/views/issues/show.rhtml index 463fa6960..2d947d047 100644 --- a/app/views/issues/show.rhtml +++ b/app/views/issues/show.rhtml @@ -1,6 +1,6 @@
    <%= link_to_if_authorized(l(:button_update), {:controller => 'issues', :action => 'edit', :id => @issue }, :onclick => 'showAndScrollTo("update", "notes"); return false;', :class => 'icon icon-edit', :accesskey => accesskey(:edit)) %> -<%= link_to_if_authorized l(:button_log_time), {:controller => 'timelog', :action => 'edit', :issue_id => @issue}, :class => 'icon icon-time' %> +<%= link_to_if_authorized l(:button_log_time), {:controller => 'timelog', :action => 'edit', :issue_id => @issue}, :class => 'icon icon-time-add' %> <%= watcher_tag(@issue, User.current) %> <%= link_to_if_authorized l(:button_copy), {:controller => 'issues', :action => 'new', :project_id => @project, :copy_from => @issue }, :class => 'icon icon-copy' %> <%= link_to_if_authorized l(:button_move), {:controller => 'issues', :action => 'move', :id => @issue }, :class => 'icon icon-move' %> @@ -9,7 +9,8 @@

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

    -
    "> +
    + <%= avatar(@issue.author, :size => "64") %>

    <%=h @issue.subject %>

    <%= authoring @issue.created_on, @issue.author %>. @@ -18,28 +19,28 @@ - - + + - - + + - - + + - + <% if User.current.allowed_to?(:view_time_entries, @project) %> - - + + <% end %> - + <% if @issue.estimated_hours %> - + <% end %> @@ -58,7 +59,7 @@ end %>
    -<%= link_to_remote_if_authorized l(:button_quote), { :url => {:action => 'reply', :id => @issue} }, :class => 'icon icon-comment' %> +<%= link_to_remote_if_authorized(l(:button_quote), { :url => {:action => 'reply', :id => @issue} }, :class => 'icon icon-comment') unless @issue.description.blank? %>

    <%=l(:field_description)%>

    @@ -66,9 +67,7 @@ end %> <%= textilizable @issue, :description, :attachments => @issue.attachments %> -<% if @issue.attachments.any? %> -<%= link_to_attachments @issue.attachments, :delete_url => (authorize_for('issues', 'destroy_attachment') ? {:controller => 'issues', :action => 'destroy_attachment', :id => @issue} : nil) %> -<% end %> +<%= link_to_attachments @issue %> <% if authorize_for('issue_relations', 'new') || @issue.relations.any? %>
    @@ -109,11 +108,10 @@ end %> <% end %> -

    -<%= l(:label_export_to) %> -<%= link_to 'Atom', {:format => 'atom', :key => User.current.rss_key}, :class => 'feed' %> -<%= link_to 'PDF', {:format => 'pdf'}, :class => 'pdf' %> -

    +<% other_formats_links do |f| %> + <%= f.link_to 'Atom', :url => {:key => User.current.rss_key} %> + <%= f.link_to 'PDF' %> +<% end %> <% html_title "#{@issue.tracker.name} ##{@issue.id}: #{@issue.subject}" %> diff --git a/app/views/journals/_notes_form.rhtml b/app/views/journals/_notes_form.rhtml index 9baec03fa..6e6ad0f88 100644 --- a/app/views/journals/_notes_form.rhtml +++ b/app/views/journals/_notes_form.rhtml @@ -1,6 +1,7 @@ <% form_remote_tag(:url => {}, :html => { :id => "journal-#{@journal.id}-form" }) do %> - <%= text_area_tag :notes, @journal.notes, :class => 'wiki-edit', - :rows => (@journal.notes.blank? ? 10 : [[10, @journal.notes.length / 50].max, 100].min) %> + <%= text_area_tag :notes, h(@journal.notes), :class => 'wiki-edit', + :rows => (@journal.notes.blank? ? 10 : [[10, @journal.notes.length / 50].max, 100].min) %> + <%= call_hook(:view_journals_notes_form_after_notes, { :journal => @journal}) %>

    <%= submit_tag l(:button_save) %> <%= link_to l(:button_cancel), '#', :onclick => "Element.remove('journal-#{@journal.id}-form'); " + "Element.show('journal-#{@journal.id}-notes'); return false;" %>

    diff --git a/app/views/journals/update.rjs b/app/views/journals/update.rjs index 2b5a54c0a..55efb9bf3 100644 --- a/app/views/journals/update.rjs +++ b/app/views/journals/update.rjs @@ -6,3 +6,5 @@ else page.show "journal-#{@journal.id}-notes" page.remove "journal-#{@journal.id}-form" end + +call_hook(:view_journals_update_rjs_bottom, { :page => page, :journal => @journal }) diff --git a/app/views/layouts/_project_selector.rhtml b/app/views/layouts/_project_selector.rhtml deleted file mode 100644 index 7a2803534..000000000 --- a/app/views/layouts/_project_selector.rhtml +++ /dev/null @@ -1,12 +0,0 @@ -<% user_projects_by_root = User.current.projects.find(:all, :include => :parent).group_by(&:root) %> - diff --git a/app/views/layouts/base.rhtml b/app/views/layouts/base.rhtml index e866287a2..8cb8f5f69 100644 --- a/app/views/layouts/base.rhtml +++ b/app/views/layouts/base.rhtml @@ -7,7 +7,7 @@ <%= stylesheet_link_tag 'application', :media => 'all' %> <%= javascript_include_tag :defaults %> -<%= stylesheet_link_tag 'jstoolbar' %> +<%= heads_for_wiki_formatter %>

    <%= f.text_field :name, :required => true %>
    <%= l(:text_caracters_maximum, 30) %>

    -<% if User.current.admin? and !@root_projects.empty? %> -

    <%= f.select :parent_id, (@root_projects.collect {|p| [p.name, p.id]}), { :include_blank => true } %>

    +<% if User.current.admin? && !@project.possible_parents.empty? %> +

    <%= parent_project_select_tag(@project) %>

    <% end %>

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

    <%= f.text_field :identifier, :required => true, :disabled => @project.identifier_frozen? %> <% unless @project.identifier_frozen? %> -
    <%= l(:text_length_between, 3, 20) %> <%= l(:text_project_identifier_info) %> +
    <%= l(:text_length_between, 2, 20) %> <%= l(:text_project_identifier_info) %> <% end %>

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

    <%= f.check_box :is_public %>

    @@ -20,6 +20,7 @@ <% @project.custom_field_values.each do |value| %>

    <%= custom_field_tag_with_label :project, value %>

    <% end %> +<%= call_hook(:view_projects_form, :project => @project, :form => f) %> <% unless @trackers.empty? %> diff --git a/app/views/projects/activity.rhtml b/app/views/projects/activity.rhtml index fa25812ac..5174cb33d 100644 --- a/app/views/projects/activity.rhtml +++ b/app/views/projects/activity.rhtml @@ -1,4 +1,4 @@ -

    <%= l(:label_activity) %>

    +

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

    <%= "#{l(:label_date_from)} #{format_date(@date_to - @days)} #{l(:label_date_to).downcase} #{format_date(@date_to-1)}" %>

    @@ -6,7 +6,8 @@

    <%= format_activity_day(day) %>

    <% @events_by_day[day].sort {|x,y| y.event_datetime <=> x.event_datetime }.each do |e| -%> -
    +
    + <%= avatar(e.event_author, :size => "24") if e.respond_to?(:event_author) %> <%= format_time(e.event_datetime, false) %> <%= content_tag('span', h(e.project), :class => 'project') if @project.nil? || @project != e.project %> <%= link_to format_activity_title(e.event_title), e.event_url %>
    @@ -21,24 +22,23 @@
    <%= link_to_remote(('« ' + l(:label_previous)), - {:update => "content", :url => params.merge(:from => @date_to - @days), :complete => 'window.scrollTo(0,0)'}, - {:href => url_for(params.merge(:from => @date_to - @days)), + {:update => "content", :url => params.merge(:from => @date_to - @days - 1), :method => :get, :complete => 'window.scrollTo(0,0)'}, + {:href => url_for(params.merge(:from => @date_to - @days - 1)), :title => "#{l(:label_date_from)} #{format_date(@date_to - 2*@days)} #{l(:label_date_to).downcase} #{format_date(@date_to - @days - 1)}"}) %>
    <%= link_to_remote((l(:label_next) + ' »'), - {:update => "content", :url => params.merge(:from => @date_to + @days), :complete => 'window.scrollTo(0,0)'}, - {:href => url_for(params.merge(:from => @date_to + @days)), + {:update => "content", :url => params.merge(:from => @date_to + @days - 1), :method => :get, :complete => 'window.scrollTo(0,0)'}, + {:href => url_for(params.merge(:from => @date_to + @days - 1)), :title => "#{l(:label_date_from)} #{format_date(@date_to)} #{l(:label_date_to).downcase} #{format_date(@date_to + @days - 1)}"}) unless @date_to >= Date.today %>
      -

    - <%= l(:label_export_to) %> - <%= link_to 'Atom', params.merge(:format => :atom, :key => User.current.rss_key).delete_if{|k,v|k=="commit"}, :class => 'feed' %> -

    +<% other_formats_links do |f| %> + <%= f.link_to 'Atom', :url => params.merge(:from => nil, :key => User.current.rss_key) %> +<% end %> <% content_for :header_tags do %> -<%= auto_discovery_link_tag(:atom, params.merge(:format => 'atom', :year => nil, :month => nil, :key => User.current.rss_key)) %> +<%= auto_discovery_link_tag(:atom, params.merge(:format => 'atom', :from => nil, :key => User.current.rss_key)) %> <% end %> <% content_for :sidebar do %> @@ -47,12 +47,13 @@

    <% @activity.event_types.each do |t| %>
    <% end %>

    -<% if @project && @project.active_children.any? %> +<% if @project && @project.descendants.active.any? %>

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

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

    <% end %> <% end %> -<% html_title(l(:label_activity)) -%> +<% html_title(l(:label_activity), @author) -%> diff --git a/app/views/projects/add.rhtml b/app/views/projects/add.rhtml index bc3d7b09a..46ab1a9be 100644 --- a/app/views/projects/add.rhtml +++ b/app/views/projects/add.rhtml @@ -13,4 +13,5 @@ <%= submit_tag l(:button_save) %> +<%= javascript_tag "Form.Element.focus('project_name');" %> <% end %> diff --git a/app/views/projects/add_file.rhtml b/app/views/projects/add_file.rhtml index 0ee55083d..ab9c7352d 100644 --- a/app/views/projects/add_file.rhtml +++ b/app/views/projects/add_file.rhtml @@ -4,10 +4,13 @@
    <% form_tag({ :action => 'add_file', :id => @project }, :multipart => true, :class => "tabular") do %> -

    -<%= select_tag "version_id", options_from_collection_for_select(@versions, "id", "name") %>

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

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

    +<% end %>

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

    <%= submit_tag l(:button_add) %> -<% end %> \ No newline at end of file +<% end %> diff --git a/app/views/projects/changelog.rhtml b/app/views/projects/changelog.rhtml index e4d32a393..e44d1d1ee 100644 --- a/app/views/projects/changelog.rhtml +++ b/app/views/projects/changelog.rhtml @@ -26,7 +26,7 @@ <% end %> <% content_for :sidebar do %> -<% form_tag do %> +<% form_tag({},:method => :get) do %>

    <%= l(:label_change_log) %>

    <% @trackers.each do |tracker| %>
    <%=l(:field_status)%>:<%= @issue.status.name %><%=l(:field_start_date)%>:<%= format_date(@issue.start_date) %><%=l(:field_status)%>:<%= @issue.status.name %><%=l(:field_start_date)%>:<%= format_date(@issue.start_date) %>
    <%=l(:field_priority)%>:<%= @issue.priority.name %><%=l(:field_due_date)%>:<%= format_date(@issue.due_date) %><%=l(:field_priority)%>:<%= @issue.priority.name %><%=l(:field_due_date)%>:<%= format_date(@issue.due_date) %>
    <%=l(:field_assigned_to)%>:<%= @issue.assigned_to ? link_to_user(@issue.assigned_to) : "-" %><%=l(:field_done_ratio)%>:<%= progress_bar @issue.done_ratio, :width => '80px', :legend => "#{@issue.done_ratio}%" %><%=l(:field_assigned_to)%>:<%= avatar(@issue.assigned_to, :size => "14") %><%= @issue.assigned_to ? link_to_user(@issue.assigned_to) : "-" %><%=l(:field_done_ratio)%>:<%= progress_bar @issue.done_ratio, :width => '80px', :legend => "#{@issue.done_ratio}%" %>
    <%=l(:field_category)%>:<%=h @issue.category ? @issue.category.name : "-" %><%=l(:field_category)%>:<%=h @issue.category ? @issue.category.name : "-" %><%=l(:label_spent_time)%>:<%= @issue.spent_hours > 0 ? (link_to lwr(:label_f_hour, @issue.spent_hours), {:controller => 'timelog', :action => 'details', :project_id => @project, :issue_id => @issue}, :class => 'icon icon-time') : "-" %><%=l(:label_spent_time)%>:<%= @issue.spent_hours > 0 ? (link_to lwr(:label_f_hour, @issue.spent_hours), {:controller => 'timelog', :action => 'details', :project_id => @project, :issue_id => @issue}) : "-" %>
    <%=l(:field_fixed_version)%>:<%= @issue.fixed_version ? link_to_version(@issue.fixed_version) : "-" %><%=l(:field_fixed_version)%>:<%= @issue.fixed_version ? link_to_version(@issue.fixed_version) : "-" %><%=l(:field_estimated_hours)%>:<%= lwr(:label_f_hour, @issue.estimated_hours) %><%=l(:field_estimated_hours)%>:<%= lwr(:label_f_hour, @issue.estimated_hours) %>
    - - <%= 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') %> + <%= sort_header_tag('filename', :caption => l(:field_filename)) %> + <%= sort_header_tag('created_on', :caption => l(:label_date), :default_order => 'desc') %> + <%= sort_header_tag('size', :caption => l(:field_filesize), :default_order => 'desc') %> + <%= sort_header_tag('downloads', :caption => l(:label_downloads_abbr), :default_order => 'desc') %> - <% if delete_allowed %><% end %> + -<% for version in @versions %> - <% unless version.attachments.empty? %> - - <% for file in version.attachments %> +<% @containers.each do |container| %> + <% next if container.attachments.empty? -%> + <% if container.is_a?(Version) -%> + + <% end -%> + <% container.attachments.each do |file| %> "> - - <% if delete_allowed %> - <% end %> <% end reset_cycle %> - <% end %> <% end %>
    <%=l(:field_version)%>MD5
    <%= version.name %>
    <%=h container %>
    <%= link_to_attachment file, :download => true, :title => file.description %> <%= format_time(file.created_on) %> <%= number_to_human_size(file.filesize) %> <%= file.downloads %> <%= file.digest %> - <%= link_to_if_authorized image_tag('delete.png'), {:controller => 'versions', :action => 'destroy_file', :id => version, :attachment_id => file}, :confirm => l(:text_are_you_sure), :method => :post %> + <%= link_to(image_tag('delete.png'), {:controller => 'attachments', :action => 'destroy', :id => file}, + :confirm => l(:text_are_you_sure), :method => :post) if delete_allowed %>
    diff --git a/app/views/projects/roadmap.rhtml b/app/views/projects/roadmap.rhtml index 0778d8138..bcba13abd 100644 --- a/app/views/projects/roadmap.rhtml +++ b/app/views/projects/roadmap.rhtml @@ -25,6 +25,7 @@

    <% end %> + <%= call_hook :view_projects_roadmap_version_bottom, :version => version %> <% end %> <% end %> diff --git a/app/views/projects/settings/_members.rhtml b/app/views/projects/settings/_members.rhtml index 67c3fb505..20806fe2d 100644 --- a/app/views/projects/settings/_members.rhtml +++ b/app/views/projects/settings/_members.rhtml @@ -1,6 +1,6 @@ <%= error_messages_for 'member' %> <% roles = Role.find_all_givable %> -<% users = User.find_active(:all).sort - @project.users %> +<% users = User.active.find(:all).sort - @project.users %> <% # members sorted by role position members = @project.members.find(:all, :include => [:role, :user]).sort %> diff --git a/app/views/projects/settings/_repository.rhtml b/app/views/projects/settings/_repository.rhtml index dcfabbbf0..cdfb7feb4 100644 --- a/app/views/projects/settings/_repository.rhtml +++ b/app/views/projects/settings/_repository.rhtml @@ -11,10 +11,13 @@
    +<% if @repository && !@repository.new_record? %> +<%= link_to(l(:label_user_plural), {:controller => 'repositories', :action => 'committers', :id => @project}, :class => 'icon icon-user') %> <%= link_to(l(:button_delete), {:controller => 'repositories', :action => 'destroy', :id => @project}, :confirm => l(:text_are_you_sure), :method => :post, - :class => 'icon icon-del') if @repository && !@repository.new_record? %> + :class => 'icon icon-del') %> +<% end %>
    <%= submit_tag((@repository.nil? || @repository.new_record?) ? l(:button_create) : l(:button_save), :disabled => @repository.nil?) %> diff --git a/app/views/projects/settings/_versions.rhtml b/app/views/projects/settings/_versions.rhtml index 7329c7f3b..79d92d81e 100644 --- a/app/views/projects/settings/_versions.rhtml +++ b/app/views/projects/settings/_versions.rhtml @@ -17,7 +17,6 @@ <%= link_to(version.wiki_page_title, :controller => 'wiki', :page => Wiki.titleize(version.wiki_page_title)) unless version.wiki_page_title.blank? || @project.wiki.nil? %> <%= link_to_if_authorized l(:button_edit), { :controller => 'versions', :action => 'edit', :id => version }, :class => 'icon icon-edit' %> <%= link_to_if_authorized l(:button_delete), {:controller => 'versions', :action => 'destroy', :id => version}, :confirm => l(:text_are_you_sure), :method => :post, :class => 'icon icon-del' %> - <% end; reset_cycle %> diff --git a/app/views/projects/show.rhtml b/app/views/projects/show.rhtml index c1d8bb2c6..6d5a1536b 100644 --- a/app/views/projects/show.rhtml +++ b/app/views/projects/show.rhtml @@ -3,12 +3,14 @@
    <%= textilizable @project.description %>
      - <% unless @project.homepage.blank? %>
    • <%=l(:field_homepage)%>: <%= auto_link(h(@project.homepage)) %>
    • <% end %> - <% if @subprojects.any? %> -
    • <%=l(:label_subproject_plural)%>: <%= @subprojects.collect{|p| link_to(h(p.name), :action => 'show', :id => p)}.join(", ") %>
    • - <% end %> - <% if @project.parent %> -
    • <%=l(:field_parent)%>: <%= link_to h(@project.parent.name), :controller => 'projects', :action => 'show', :id => @project.parent %>
    • + <% unless @project.homepage.blank? %>
    • <%=l(:field_homepage)%>: <%= link_to(h(@project.homepage), @project.homepage) %>
    • <% end %> + <% if @subprojects.any? %> +
    • <%=l(:label_subproject_plural)%>: + <%= @subprojects.collect{|p| link_to(h(p), :action => 'show', :id => p)}.join(", ") %>
    • + <% end %> + <% if @ancestors.any? %> +
    • <%=l(:field_parent)%>: + <%= @ancestors.collect {|p| link_to(h(p), :action => 'show', :id => p)}.join(" » ") %>
    • <% end %> <% @project.custom_values.each do |custom_value| %> <% if !custom_value.value.empty? %> diff --git a/app/views/queries/_filters.rhtml b/app/views/queries/_filters.rhtml index c9d612364..b25cd01aa 100644 --- a/app/views/queries/_filters.rhtml +++ b/app/views/queries/_filters.rhtml @@ -95,7 +95,10 @@ function toggle_multi_select(field) { <%= 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" %> +<%= 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", + :name => nil %> diff --git a/app/views/repositories/_dir_list_content.rhtml b/app/views/repositories/_dir_list_content.rhtml index 20473a264..12ee44dbf 100644 --- a/app/views/repositories/_dir_list_content.rhtml +++ b/app/views/repositories/_dir_list_content.rhtml @@ -15,10 +15,10 @@ :class => (entry.is_dir? ? 'icon icon-folder' : 'icon icon-file')%> <%= (entry.size ? number_to_human_size(entry.size) : "?") unless entry.is_dir? %> +<% changeset = @project.repository.changesets.find_by_revision(entry.lastrev.identifier) if entry.lastrev && entry.lastrev.identifier %> <%= link_to(format_revision(entry.lastrev.name), :action => 'revision', :id => @project, :rev => entry.lastrev.identifier) if entry.lastrev && entry.lastrev.identifier %> <%= distance_of_time_in_words(entry.lastrev.time, Time.now) if entry.lastrev && entry.lastrev.time %> -<%=h(entry.lastrev.author.to_s.split('<').first) if entry.lastrev %> -<% changeset = @project.repository.changesets.find_by_revision(entry.lastrev.identifier) if entry.lastrev && entry.lastrev.identifier %> +<%= changeset.nil? ? h(entry.lastrev.author.to_s.split('<').first) : changeset.author if entry.lastrev %> <%=h truncate(changeset.comments, 50) unless changeset.nil? %> <% end %> diff --git a/app/views/repositories/_link_to_functions.rhtml b/app/views/repositories/_link_to_functions.rhtml new file mode 100644 index 000000000..7737bf484 --- /dev/null +++ b/app/views/repositories/_link_to_functions.rhtml @@ -0,0 +1,10 @@ +

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

      diff --git a/app/views/repositories/_revisions.rhtml b/app/views/repositories/_revisions.rhtml index a938fecb8..fb0131c82 100644 --- a/app/views/repositories/_revisions.rhtml +++ b/app/views/repositories/_revisions.rhtml @@ -17,8 +17,8 @@ <%= radio_button_tag('rev', changeset.revision, (line_num==1), :id => "cb-#{line_num}", :onclick => "$('cbto-#{line_num+1}').checked=true;") if show_diff && (line_num < revisions.size) %> <%= radio_button_tag('rev_to', changeset.revision, (line_num==2), :id => "cbto-#{line_num}", :onclick => "if ($('cb-#{line_num}').checked==true) {$('cb-#{line_num-1}').checked=true;}") if show_diff && (line_num > 1) %> <%= format_time(changeset.committed_on) %> -<%=h changeset.committer.to_s.split('<').first %> -<%= textilizable(changeset.comments) %> +<%=h changeset.author %> +<%= textilizable(truncate_at_line_break(changeset.comments)) %> <% line_num += 1 %> <% end %> diff --git a/app/views/repositories/annotate.rhtml b/app/views/repositories/annotate.rhtml index b5669ef76..44b5a81a6 100644 --- a/app/views/repositories/annotate.rhtml +++ b/app/views/repositories/annotate.rhtml @@ -1,5 +1,7 @@

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

      +

      <%= render :partial => 'link_to_functions' %>

      + <% colors = Hash.new {|k,v| k[v] = (k.size % 12) } %>
      diff --git a/app/views/repositories/changes.rhtml b/app/views/repositories/changes.rhtml index ca5c58328..aa359ef4d 100644 --- a/app/views/repositories/changes.rhtml +++ b/app/views/repositories/changes.rhtml @@ -1,15 +1,6 @@

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

      -

      -<% if @repository.supports_cat? %> - <%= link_to l(:button_view), {:action => 'entry', :id => @project, :path => to_path_param(@path), :rev => @rev } %> | -<% end %> -<% if @repository.supports_annotate? %> - <%= link_to l(:button_annotate), {:action => 'annotate', :id => @project, :path => to_path_param(@path), :rev => @rev } %> | -<% end %> -<%= link_to(l(:button_download), {:action => 'entry', :id => @project, :path => to_path_param(@path), :rev => @rev, :format => 'raw' }) if @repository.supports_cat? %> -<%= "(#{number_to_human_size(@entry.size)})" if @entry.size %> -

      +

      <%= render :partial => 'link_to_functions' %>

      <%= render_properties(@properties) %> diff --git a/app/views/repositories/committers.rhtml b/app/views/repositories/committers.rhtml new file mode 100644 index 000000000..597a414aa --- /dev/null +++ b/app/views/repositories/committers.rhtml @@ -0,0 +1,34 @@ +

      <%= l(:label_repository) %>

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

      <%= l(:label_no_data) %>

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

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

      +<% end %> + +<% end %> \ No newline at end of file diff --git a/app/views/repositories/diff.rhtml b/app/views/repositories/diff.rhtml index 52a5d6057..8538f30de 100644 --- a/app/views/repositories/diff.rhtml +++ b/app/views/repositories/diff.rhtml @@ -1,12 +1,9 @@

      <%= l(:label_revision) %> <%= format_revision(@rev) %> <%= @path.gsub(/^.*\//, '') %>

      -<% form_tag({ :controller => 'repositories', :action => 'diff'}, :method => 'get') do %> - <% params.each do |k, p| %> - <% if k != "type" %> - <%= hidden_field_tag(k,p) %> - <% end %> - <% end %> +<% form_tag({}, :method => 'get') do %> + <%= hidden_field_tag('rev', params[:rev]) if params[:rev] %> + <%= hidden_field_tag('rev_to', params[:rev_to]) if params[:rev_to] %>

      <%= select_tag 'type', options_for_select([[l(:label_diff_inline), "inline"], [l(:label_diff_side_by_side), "sbs"]], @diff_type), :onchange => "if (this.value != '') {this.form.submit()}" %>

      <% end %> @@ -15,10 +12,9 @@ <%= render :partial => 'common/diff', :locals => {:diff => @diff, :diff_type => @diff_type} %> <% end -%> -

      -<%= l(:label_export_to) %> -<%= link_to 'Unified diff', params.merge(:format => 'diff') %> -

      +<% other_formats_links do |f| %> + <%= f.link_to 'Diff', :url => params, :caption => 'Unified diff' %> +<% end %> <% html_title(with_leading_slash(@path), 'Diff') -%> diff --git a/app/views/repositories/entry.rhtml b/app/views/repositories/entry.rhtml index 8e1e1992c..12ba9f428 100644 --- a/app/views/repositories/entry.rhtml +++ b/app/views/repositories/entry.rhtml @@ -1,5 +1,7 @@

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

      +

      <%= render :partial => 'link_to_functions' %>

      + <%= render :partial => 'common/file', :locals => {:filename => @path, :content => @content} %> <% content_for :header_tags do %> diff --git a/app/views/repositories/revision.rhtml b/app/views/repositories/revision.rhtml index 123fccf26..c5bac720b 100644 --- a/app/views/repositories/revision.rhtml +++ b/app/views/repositories/revision.rhtml @@ -22,7 +22,7 @@

      <%= l(:label_revision) %> <%= format_revision(@changeset.revision) %>

      <% if @changeset.scmid %>ID: <%= @changeset.scmid %>
      <% end %> -<%= @changeset.committer.to_s.split('<').first %>, <%= format_time(@changeset.committed_on) %>

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

      <%= textilizable @changeset.comments %> diff --git a/app/views/repositories/revisions.rhtml b/app/views/repositories/revisions.rhtml index 8da7d582d..c06c204cd 100644 --- a/app/views/repositories/revisions.rhtml +++ b/app/views/repositories/revisions.rhtml @@ -16,9 +16,8 @@ <%= auto_discovery_link_tag(:atom, params.merge({:format => 'atom', :page => nil, :key => User.current.rss_key})) %> <% end %> -

      -<%= l(:label_export_to) %> -<%= link_to 'Atom', {:format => 'atom', :key => User.current.rss_key}, :class => 'feed' %> -

      +<% other_formats_links do |f| %> + <%= f.link_to 'Atom', :url => {:key => User.current.rss_key} %> +<% end %> <% html_title(l(:label_revision_plural)) -%> diff --git a/app/views/repositories/show.rhtml b/app/views/repositories/show.rhtml index 9dc38a832..943fe9485 100644 --- a/app/views/repositories/show.rhtml +++ b/app/views/repositories/show.rhtml @@ -1,4 +1,5 @@
      +<%= call_hook(:view_repositories_show_contextual, { :repository => @repository, :project => @project }) %> <%= link_to l(:label_statistics), {:action => 'stats', :id => @project}, :class => 'icon icon-stats' %> <% if !@entries.nil? && authorize_for('repositories', 'browse') -%> @@ -21,10 +22,10 @@ <% content_for :header_tags do %> <%= auto_discovery_link_tag(:atom, params.merge({:format => 'atom', :action => 'revisions', :id => @project, :page => nil, :key => User.current.rss_key})) %> <% end %> -

      -<%= l(:label_export_to) %> -<%= link_to 'Atom', {:action => 'revisions', :id => @project, :format => 'atom', :key => User.current.rss_key}, :class => 'feed' %> -

      + +<% other_formats_links do |f| %> + <%= f.link_to 'Atom', :url => {:action => 'revisions', :id => @project, :key => User.current.rss_key} %> +<% end %> <% end %> <% content_for :header_tags do %> diff --git a/app/views/roles/_form.rhtml b/app/views/roles/_form.rhtml index 4aad45471..a167907e8 100644 --- a/app/views/roles/_form.rhtml +++ b/app/views/roles/_form.rhtml @@ -15,11 +15,11 @@
      <% perms_by_module = @permissions.group_by {|p| p.project_module.to_s} %> <% perms_by_module.keys.sort.each do |mod| %> -
      <%= mod.blank? ? l(:label_project) : mod.humanize %> +
      <%= mod.blank? ? l(:label_project) : l_or_humanize(mod, :prefix => 'project_module_') %> <% perms_by_module[mod].each do |permission| %> <% end %>
      diff --git a/app/views/roles/report.rhtml b/app/views/roles/report.rhtml index 8e254379e..f5ebc8845 100644 --- a/app/views/roles/report.rhtml +++ b/app/views/roles/report.rhtml @@ -19,14 +19,14 @@ <% perms_by_module = @permissions.group_by {|p| p.project_module.to_s} %> <% perms_by_module.keys.sort.each do |mod| %> <% unless mod.blank? %> - <%= content_tag('th', mod.humanize, :colspan => (@roles.size + 1), :align => 'left') %> + <%= content_tag('th', l_or_humanize(mod, :prefix => 'project_module_'), :colspan => (@roles.size + 1), :align => 'left') %> <% end %> <% perms_by_module[mod].each do |permission| %> <%= link_to_function(image_tag('toggle_check.png'), "toggleCheckboxesBySelector('.permission-#{permission.name} input')", :title => "#{l(:button_check_all)}/#{l(:button_uncheck_all)}") %> - <%= permission.name.to_s.humanize %> + <%= l_or_humanize(permission.name, :prefix => 'permission_') %> <% @roles.each do |role| %> diff --git a/app/views/settings/_authentication.rhtml b/app/views/settings/_authentication.rhtml index 6bf20cbce..a3ac555ed 100644 --- a/app/views/settings/_authentication.rhtml +++ b/app/views/settings/_authentication.rhtml @@ -17,6 +17,9 @@

      <%= check_box_tag 'settings[lost_password]', 1, Setting.lost_password? %><%= hidden_field_tag 'settings[lost_password]', 0 %>

      + +

      +<%= check_box_tag 'settings[openid]', 1, Setting.openid?, :disabled => !Object.const_defined?(:OpenID) %><%= hidden_field_tag 'settings[openid]', 0 %>

      diff --git a/app/views/settings/_display.rhtml b/app/views/settings/_display.rhtml new file mode 100644 index 000000000..a14ff47ce --- /dev/null +++ b/app/views/settings/_display.rhtml @@ -0,0 +1,24 @@ +<% form_tag({:action => 'edit', :tab => 'display'}) do %> + +
      +

      +<%= select_tag 'settings[ui_theme]', options_for_select( ([[l(:label_default), '']] + Redmine::Themes.themes.collect {|t| [t.name, t.id]}), Setting.ui_theme) %>

      + +

      +<%= select_tag 'settings[default_language]', options_for_select( lang_options_for_select(false), Setting.default_language) %>

      + +

      +<%= select_tag 'settings[date_format]', options_for_select( [[l(:label_language_based), '']] + Setting::DATE_FORMATS.collect {|f| [Date.today.strftime(f), f]}, Setting.date_format) %>

      + +

      +<%= select_tag 'settings[time_format]', options_for_select( [[l(:label_language_based), '']] + Setting::TIME_FORMATS.collect {|f| [Time.now.strftime(f), f]}, Setting.time_format) %>

      + +

      +<%= select_tag 'settings[user_format]', options_for_select( @options[:user_format], Setting.user_format.to_s ) %>

      + +

      +<%= check_box_tag 'settings[gravatar_enabled]', 1, Setting.gravatar_enabled? %><%= hidden_field_tag 'settings[gravatar_enabled]', 0 %>

      +
      + +<%= submit_tag l(:button_save) %> +<% end %> diff --git a/app/views/settings/_general.rhtml b/app/views/settings/_general.rhtml index bb56c43db..e78667154 100644 --- a/app/views/settings/_general.rhtml +++ b/app/views/settings/_general.rhtml @@ -8,21 +8,6 @@ <%= text_area_tag 'settings[welcome_text]', Setting.welcome_text, :cols => 60, :rows => 5, :class => 'wiki-edit' %>

      <%= wikitoolbar_for 'settings[welcome_text]' %> -

      -<%= select_tag 'settings[ui_theme]', options_for_select( ([[l(:label_default), '']] + Redmine::Themes.themes.collect {|t| [t.name, t.id]}), Setting.ui_theme) %>

      - -

      -<%= select_tag 'settings[default_language]', options_for_select( lang_options_for_select(false), Setting.default_language) %>

      - -

      -<%= select_tag 'settings[date_format]', options_for_select( [[l(:label_language_based), '']] + Setting::DATE_FORMATS.collect {|f| [Date.today.strftime(f), f]}, Setting.date_format) %>

      - -

      -<%= select_tag 'settings[time_format]', options_for_select( [[l(:label_language_based), '']] + Setting::TIME_FORMATS.collect {|f| [Time.now.strftime(f), f]}, Setting.time_format) %>

      - -

      -<%= select_tag 'settings[user_format]', options_for_select( @options[:user_format], Setting.user_format.to_s ) %>

      -

      <%= text_field_tag 'settings[attachment_max_size]', Setting.attachment_max_size, :size => 6 %> KB

      @@ -33,19 +18,23 @@ <%= text_field_tag 'settings[activity_days_default]', Setting.activity_days_default, :size => 6 %> <%= l(:label_day_plural) %>

      -<%= text_field_tag 'settings[host_name]', Setting.host_name, :size => 60 %>

      +<%= text_field_tag 'settings[host_name]', Setting.host_name, :size => 60 %>
      +<%= l(:label_example) %>: <%= @guessed_host_and_path %>

      <%= select_tag 'settings[protocol]', options_for_select(['http', 'https'], Setting.protocol) %>

      -<%= select_tag 'settings[text_formatting]', options_for_select([[l(:label_none), "0"], ["textile", "textile"]], Setting.text_formatting) %>

      +<%= select_tag 'settings[text_formatting]', options_for_select([[l(:label_none), "0"], *Redmine::WikiFormatting.format_names.collect{|name| [name, name]} ], Setting.text_formatting.to_sym) %>

      <%= select_tag 'settings[wiki_compression]', options_for_select( [[l(:label_none), 0], ["gzip", "gzip"]], Setting.wiki_compression) %>

      <%= text_field_tag 'settings[feeds_limit]', Setting.feeds_limit, :size => 6 %>

      + +

      +<%= text_field_tag 'settings[diff_max_lines_displayed]', Setting.diff_max_lines_displayed, :size => 6 %>

      <%= submit_tag l(:button_save) %> diff --git a/app/views/settings/_notifications.rhtml b/app/views/settings/_notifications.rhtml index 36701463a..bc0141187 100644 --- a/app/views/settings/_notifications.rhtml +++ b/app/views/settings/_notifications.rhtml @@ -8,12 +8,16 @@

      <%= check_box_tag 'settings[bcc_recipients]', 1, Setting.bcc_recipients? %> <%= hidden_field_tag 'settings[bcc_recipients]', 0 %>

      + +

      +<%= check_box_tag 'settings[plain_text_mail]', 1, Setting.plain_text_mail? %> +<%= hidden_field_tag 'settings[plain_text_mail]', 0 %>

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

      <%= check_all_links('notified_events') %>

      diff --git a/app/views/settings/_repositories.rhtml b/app/views/settings/_repositories.rhtml index fb4e88f4c..dfb9d6454 100644 --- a/app/views/settings/_repositories.rhtml +++ b/app/views/settings/_repositories.rhtml @@ -22,6 +22,9 @@

      <%= select_tag 'settings[commit_logs_encoding]', options_for_select(Setting::ENCODINGS, Setting.commit_logs_encoding) %>

      + +

      +<%= text_field_tag 'settings[repository_log_display_limit]', Setting.repository_log_display_limit, :size => 6 %>

      <%= l(:text_issues_ref_in_commit_messages) %> diff --git a/app/views/timelog/_list.rhtml b/app/views/timelog/_list.rhtml index 8aebd75de..1144d42cc 100644 --- a/app/views/timelog/_list.rhtml +++ b/app/views/timelog/_list.rhtml @@ -2,10 +2,10 @@ <%= 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)) %> -<%= sort_header_tag("#{Project.table_name}.name", :caption => l(:label_project)) %> -<%= sort_header_tag('issue_id', :caption => l(:label_issue), :default_order => 'desc') %> +<%= sort_header_tag('user', :caption => l(:label_member)) %> +<%= sort_header_tag('activity', :caption => l(:label_activity)) %> +<%= sort_header_tag('project', :caption => l(:label_project)) %> +<%= sort_header_tag('issue', :caption => l(:label_issue), :default_order => 'desc') %> <%= l(:field_comments) %> <%= sort_header_tag('hours', :caption => l(:field_hours)) %> diff --git a/app/views/timelog/details.rhtml b/app/views/timelog/details.rhtml index db62fae66..f4ae68aa9 100644 --- a/app/views/timelog/details.rhtml +++ b/app/views/timelog/details.rhtml @@ -1,12 +1,14 @@
      -<%= link_to_if_authorized l(:button_log_time), {:controller => 'timelog', :action => 'edit', :project_id => @project, :issue_id => @issue}, :class => 'icon icon-time' %> +<%= link_to_if_authorized l(:button_log_time), {:controller => 'timelog', :action => 'edit', :project_id => @project, :issue_id => @issue}, :class => 'icon icon-time-add' %>
      <%= render_timelog_breadcrumb %>

      <%= l(:label_spent_time) %>

      -<% form_remote_tag( :url => {}, :method => :get, :update => 'content' ) do %> +<% form_remote_tag( :url => {}, :html => {:method => :get}, :method => :get, :update => 'content' ) do %> +<%# TOOD: remove the project_id and issue_id hidden fields, that information is +already in the URI %> <%= hidden_field_tag 'project_id', params[:project_id] %> <%= hidden_field_tag 'issue_id', params[:issue_id] if @issue %> <%= render :partial => 'date_range' %> @@ -20,11 +22,10 @@ <%= render :partial => 'list', :locals => { :entries => @entries }%>

      <%= pagination_links_full @entry_pages, @entry_count %>

      -

      -<%= l(:label_export_to) %> -<%= link_to 'Atom', {:issue_id => @issue, :format => 'atom', :key => User.current.rss_key}, :class => 'feed' %> -<%= link_to 'CSV', params.merge(:format => 'csv'), :class => 'csv' %> -

      +<% other_formats_links do |f| %> + <%= f.link_to 'Atom', :url => params.merge({:issue_id => @issue, :key => User.current.rss_key}) %> + <%= f.link_to 'CSV', :url => params %> +<% end %> <% end %> <% html_title l(:label_spent_time), l(:label_details) %> diff --git a/app/views/timelog/edit.rhtml b/app/views/timelog/edit.rhtml index 0dd3503ec..085f3d805 100644 --- a/app/views/timelog/edit.rhtml +++ b/app/views/timelog/edit.rhtml @@ -1,6 +1,6 @@

      <%= l(:label_spent_time) %>

      -<% labelled_tabular_form_for :time_entry, @time_entry, :url => {:action => 'edit', :project_id => @time_entry.project} do |f| %> +<% labelled_tabular_form_for :time_entry, @time_entry, :url => {:action => 'edit', :id => @time_entry, :project_id => @time_entry.project} do |f| %> <%= error_messages_for 'time_entry' %> <%= back_url_hidden_field_tag %> @@ -13,6 +13,7 @@ <% @time_entry.custom_field_values.each do |value| %>

      <%= custom_field_tag_with_label :time_entry, value %>

      <% end %> +<%= call_hook(:view_timelog_edit_form_bottom, { :time_entry => @time_entry, :form => f }) %>
    <%= submit_tag l(:button_save) %> diff --git a/app/views/timelog/report.rhtml b/app/views/timelog/report.rhtml index eea0d0fc7..5f3ed09bd 100644 --- a/app/views/timelog/report.rhtml +++ b/app/views/timelog/report.rhtml @@ -1,15 +1,16 @@
    -<%= link_to_if_authorized l(:button_log_time), {:controller => 'timelog', :action => 'edit', :project_id => @project, :issue_id => @issue}, :class => 'icon icon-time' %> +<%= link_to_if_authorized l(:button_log_time), {:controller => 'timelog', :action => 'edit', :project_id => @project, :issue_id => @issue}, :class => 'icon icon-time-add' %>
    <%= render_timelog_breadcrumb %>

    <%= l(:label_spent_time) %>

    -<% form_remote_tag(:url => {}, :update => 'content') do %> +<% form_remote_tag(:url => {}, :html => {:method => :get}, :method => :get, :update => 'content') do %> <% @criterias.each do |criteria| %> <%= hidden_field_tag 'criterias[]', criteria, :id => nil %> <% end %> + <%# TODO: get rid of the project_id field, that should already be in the URL %> <%= hidden_field_tag 'project_id', params[:project_id] %> <%= render :partial => 'date_range' %> @@ -25,6 +26,7 @@ :id => nil, :disabled => (@criterias.length >= 3)) %> <%= link_to_remote l(:button_clear), {:url => {:project_id => @project, :period_type => params[:period_type], :period => params[:period], :from => @from, :to => @to, :columns => @columns}, + :method => :get, :update => 'content' }, :class => 'icon icon-reload' %>

    <% end %> @@ -63,10 +65,9 @@ -

    -<%= l(:label_export_to) %> -<%= link_to 'CSV', params.merge({:format => 'csv'}), :class => 'csv' %> -

    +<% other_formats_links do |f| %> + <%= f.link_to 'CSV', :url => params %> +<% end %> <% end %> <% end %> diff --git a/app/views/trackers/_form.rhtml b/app/views/trackers/_form.rhtml index 856b70bbc..d8d35ba36 100644 --- a/app/views/trackers/_form.rhtml +++ b/app/views/trackers/_form.rhtml @@ -1,5 +1,7 @@ <%= error_messages_for 'tracker' %> -
    + +
    +

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

    <%= f.check_box :is_in_chlog %>

    @@ -10,3 +12,16 @@ <% end %>
    +
    + +
    +<% if @projects.any? %> +
    <%= l(:label_project_plural) %> +<%= project_nested_ul(@projects) do |p| + content_tag('label', check_box_tag('tracker[project_ids][]', p.id, @tracker.projects.include?(p), :id => nil) + ' ' + h(p)) +end %> +<%= hidden_field_tag('tracker[project_ids][]', '', :id => nil) %> +

    <%= check_all_links 'tracker_project_ids' %>

    +
    +<% end %> +
    diff --git a/app/views/trackers/edit.rhtml b/app/views/trackers/edit.rhtml index d8411099c..038acc86e 100644 --- a/app/views/trackers/edit.rhtml +++ b/app/views/trackers/edit.rhtml @@ -1,6 +1,6 @@

    <%=l(:label_tracker)%>

    -<% labelled_tabular_form_for :tracker, @tracker, :url => { :action => 'edit' } do |f| %> +<% form_for :tracker, @tracker, :url => { :action => 'edit' }, :builder => TabularFormBuilder do |f| %> <%= render :partial => 'form', :locals => { :f => f } %> <%= submit_tag l(:button_save) %> -<% end %> \ No newline at end of file +<% end %> diff --git a/app/views/trackers/list.rhtml b/app/views/trackers/list.rhtml index 9ccfda386..2531f334b 100644 --- a/app/views/trackers/list.rhtml +++ b/app/views/trackers/list.rhtml @@ -15,7 +15,7 @@ <% for tracker in @trackers %> "> <%= link_to tracker.name, :action => 'edit', :id => tracker %> - <% unless tracker.workflows.count > 0 %><%= l(:text_tracker_no_workflow) %> (<%= link_to l(:button_edit), {:controller => "roles", :action => "workflow", :tracker_id => tracker} %>)<% end %> + <% unless tracker.workflows.count > 0 %><%= l(:text_tracker_no_workflow) %> (<%= link_to l(:button_edit), {:controller => 'workflows', :action => 'edit', :tracker_id => tracker} %>)<% end %> <%= link_to image_tag('2uparrow.png', :alt => l(:label_sort_highest)), {:action => 'move', :id => tracker, :position => 'highest'}, :method => :post, :title => l(:label_sort_highest) %> <%= link_to image_tag('1uparrow.png', :alt => l(:label_sort_higher)), {:action => 'move', :id => tracker, :position => 'higher'}, :method => :post, :title => l(:label_sort_higher) %> - diff --git a/app/views/trackers/new.rhtml b/app/views/trackers/new.rhtml index b318a5dc4..3f8384cdd 100644 --- a/app/views/trackers/new.rhtml +++ b/app/views/trackers/new.rhtml @@ -1,6 +1,6 @@

    <%=l(:label_tracker_new)%>

    -<% labelled_tabular_form_for :tracker, @tracker, :url => { :action => 'new' } do |f| %> +<% form_for :tracker, @tracker, :url => { :action => 'new' }, :builder => TabularFormBuilder do |f| %> <%= render :partial => 'form', :locals => { :f => f } %> <%= submit_tag l(:button_create) %> -<% end %> \ No newline at end of file +<% end %> diff --git a/app/views/users/_form.rhtml b/app/views/users/_form.rhtml index 799ebde47..00b6aeac5 100644 --- a/app/views/users/_form.rhtml +++ b/app/views/users/_form.rhtml @@ -7,6 +7,9 @@

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

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

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

    +<% if Setting.openid? %> +

    <%= f.text_field :identity_url %>

    +<% end %> <% @user.custom_field_values.each do |value| %>

    <%= custom_field_tag_with_label :user, value %>

    diff --git a/app/views/users/_general.rhtml b/app/views/users/_general.rhtml index 80615ff6c..352c002d0 100644 --- a/app/views/users/_general.rhtml +++ b/app/views/users/_general.rhtml @@ -1,4 +1,4 @@ -<% labelled_tabular_form_for :user, @user, :url => { :action => "edit" } do |f| %> +<% labelled_tabular_form_for :user, @user, :url => { :action => "edit", :tab => nil } do |f| %> <%= render :partial => 'form', :locals => { :f => f } %> <%= submit_tag l(:button_save) %> <% end %> diff --git a/app/views/users/_memberships.rhtml b/app/views/users/_memberships.rhtml index 94b49159e..d1657fb98 100644 --- a/app/views/users/_memberships.rhtml +++ b/app/views/users/_memberships.rhtml @@ -31,7 +31,7 @@


    <% form_tag({ :action => 'edit_membership', :id => @user }) do %> -<%= select_tag 'membership[project_id]', projects_options_for_select(@projects) %> +<%= select_tag 'membership[project_id]', options_for_membership_project_select(@user, @projects) %> <%= l(:label_role) %>: <%= select_tag 'membership[role_id]', options_from_collection_for_select(@roles, "id", "name") %> <%= submit_tag l(:button_add) %> diff --git a/app/views/users/list.rhtml b/app/views/users/list.rhtml index 77d45a6bb..758f1767a 100644 --- a/app/views/users/list.rhtml +++ b/app/views/users/list.rhtml @@ -6,8 +6,11 @@ <% form_tag({}, :method => :get) do %>

    <%= l(:label_filter_plural) %> - + <%= select_tag 'status', users_status_options_for_select(@status), :class => "small", :onchange => "this.form.submit(); return false;" %> + +<%= text_field_tag 'name', params[:name], :size => 30 %> +<%= submit_tag l(:button_apply), :class => "small", :name => nil %>
    <% end %>   @@ -26,7 +29,7 @@ <% for user in @users -%> <%= %w(anon active registered locked)[user.status] %>"> - <%= link_to h(user.login), :action => 'edit', :id => user %> + <%= avatar(user, :size => "14") %><%= link_to h(user.login), :action => 'edit', :id => user %> <%= h(user.firstname) %> <%= h(user.lastname) %> <%= mail_to(h(user.mail)) %> diff --git a/app/views/welcome/robots.rhtml b/app/views/welcome/robots.rhtml new file mode 100644 index 000000000..c6e206bd6 --- /dev/null +++ b/app/views/welcome/robots.rhtml @@ -0,0 +1,9 @@ +User-agent: * +<% @projects.each do |p| -%> +Disallow: /projects/<%= p.to_param %>/repository +Disallow: /projects/<%= p.to_param %>/issues +Disallow: /projects/<%= p.to_param %>/activity +<% end -%> +Disallow: /issues/gantt +Disallow: /issues/calendar +Disallow: /activity diff --git a/app/views/wiki/annotate.rhtml b/app/views/wiki/annotate.rhtml index 1c683404b..c27451606 100644 --- a/app/views/wiki/annotate.rhtml +++ b/app/views/wiki/annotate.rhtml @@ -20,7 +20,7 @@ <%= line_num %> <%= link_to line[0], :controller => 'wiki', :action => 'index', :id => @project, :page => @page.title, :version => line[0] %> <%= h(line[1]) %> -
    <%= line[2] %>
    +
    <%=h line[2] %>
    <% line_num += 1 %> <% end -%> diff --git a/app/views/wiki/export.rhtml b/app/views/wiki/export.rhtml index 94b4e6f0d..7f861facf 100644 --- a/app/views/wiki/export.rhtml +++ b/app/views/wiki/export.rhtml @@ -5,7 +5,7 @@ diff --git a/app/views/wiki/show.rhtml b/app/views/wiki/show.rhtml index 844c6c0f8..7abfd8a28 100644 --- a/app/views/wiki/show.rhtml +++ b/app/views/wiki/show.rhtml @@ -28,7 +28,7 @@ <%= render(:partial => "wiki/content", :locals => {:content => @content}) %> -<%= link_to_attachments @page.attachments, :delete_url => ((@editable && authorize_for('wiki', 'destroy_attachment')) ? {:controller => 'wiki', :action => 'destroy_attachment', :page => @page.title} : nil) %> +<%= link_to_attachments @page %> <% if @editable && authorize_for('wiki', 'add_attachment') %>

    <%= link_to l(:label_attachment_new), {}, :onclick => "Element.show('add_attachment_form'); Element.hide(this); Element.scrollTo('add_attachment_form'); return false;", @@ -42,11 +42,10 @@ <% end %> <% end %> -

    -<%= l(:label_export_to) %> -<%= link_to 'HTML', {:page => @page.title, :export => 'html', :version => @content.version}, :class => 'html' %> -<%= link_to 'TXT', {:page => @page.title, :export => 'txt', :version => @content.version}, :class => 'text' %> -

    +<% other_formats_links do |f| %> + <%= f.link_to 'HTML', :url => {:page => @page.title, :version => @content.version} %> + <%= f.link_to 'TXT', :url => {:page => @page.title, :version => @content.version} %> +<% end %> <% content_for :header_tags do %> <%= stylesheet_link_tag 'scm' %> diff --git a/app/views/wiki/special_date_index.rhtml b/app/views/wiki/special_date_index.rhtml index 6717ebc85..008f89293 100644 --- a/app/views/wiki/special_date_index.rhtml +++ b/app/views/wiki/special_date_index.rhtml @@ -18,11 +18,10 @@ <% end %> <% unless @pages.empty? %> -

    -<%= l(:label_export_to) %> -<%= link_to 'Atom', {:controller => 'projects', :action => 'activity', :id => @project, :show_wiki_pages => 1, :format => 'atom', :key => User.current.rss_key}, :class => 'feed' %> -<%= link_to 'HTML', {:action => 'special', :page => 'export'}, :class => 'html' %> -

    +<% other_formats_links do |f| %> + <%= f.link_to 'Atom', :url => {:controller => 'projects', :action => 'activity', :id => @project, :show_wiki_pages => 1, :key => User.current.rss_key} %> + <%= f.link_to 'HTML', :url => {:action => 'special', :page => 'export'} %> +<% end %> <% end %> <% content_for :header_tags do %> diff --git a/app/views/wiki/special_page_index.rhtml b/app/views/wiki/special_page_index.rhtml index 72b395ef7..5547f5b1c 100644 --- a/app/views/wiki/special_page_index.rhtml +++ b/app/views/wiki/special_page_index.rhtml @@ -11,11 +11,10 @@ <% end %> <% unless @pages.empty? %> -

    -<%= l(:label_export_to) %> -<%= link_to 'Atom', {:controller => 'projects', :action => 'activity', :id => @project, :show_wiki_pages => 1, :format => 'atom', :key => User.current.rss_key}, :class => 'feed' %> -<%= link_to 'HTML', {:action => 'special', :page => 'export'} %> -

    +<% other_formats_links do |f| %> + <%= f.link_to 'Atom', :url => {:controller => 'projects', :action => 'activity', :id => @project, :show_wiki_pages => 1, :key => User.current.rss_key} %> + <%= f.link_to 'HTML', :url => {:action => 'special', :page => 'export'} %> +<% end %> <% end %> <% content_for :header_tags do %> diff --git a/app/views/roles/workflow.rhtml b/app/views/workflows/edit.rhtml similarity index 56% rename from app/views/roles/workflow.rhtml rename to app/views/workflows/edit.rhtml index 0f08b0d22..1aef8eb7e 100644 --- a/app/views/roles/workflow.rhtml +++ b/app/views/workflows/edit.rhtml @@ -1,40 +1,47 @@ +
    +<%= link_to l(:field_summary), :action => 'index' %> +
    +

    <%=l(:label_workflow)%>

    <%=l(:text_workflow_edit)%>:

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

    - <%= options_from_collection_for_select @roles, "id", "name", (@role.id unless @role.nil?) %> - <%= options_from_collection_for_select @trackers, "id", "name", (@tracker.id unless @tracker.nil?) %> -<%= submit_tag l(:button_edit) %> +<%= submit_tag l(:button_edit), :name => nil %>

    <% end %> -<% unless @tracker.nil? or @role.nil? %> -<% form_tag({:action => 'workflow', :role_id => @role, :tracker_id => @tracker }, :id => 'workflow_form' ) do %> -
    - +<% unless @tracker.nil? or @role.nil? or @statuses.empty? %> +<% form_tag({}, :id => 'workflow_form' ) do %> +<%= hidden_field_tag 'tracker_id', @tracker.id %> +<%= hidden_field_tag 'role_id', @role.id %> +
    + - - + + <% for new_status in @statuses %> - + <% end %> - + + <% for old_status in @statuses %> - + "> <% new_status_ids_allowed = old_status.find_new_statuses_allowed_to(@role, @tracker).collect(&:id) -%> <% for new_status in @statuses -%> @@ -42,14 +49,15 @@ > + <%= 'checked="checked"' if new_status_ids_allowed.include? new_status.id %> /> <% end -%> <% end %> -
    <%=l(:label_current_status)%><%=l(:label_new_statuses_allowed)%><%=l(:label_current_status)%><%=l(:label_new_statuses_allowed)%>
    <%= new_status.name %><%= new_status.name %>
    <%= old_status.name %>
    -

    <%= check_all_links 'workflow_form' %>

    -
    + + +

    <%= check_all_links 'workflow_form' %>

    + <%= submit_tag l(:button_save) %> <% end %> diff --git a/app/views/workflows/index.rhtml b/app/views/workflows/index.rhtml new file mode 100644 index 000000000..2fd080d8f --- /dev/null +++ b/app/views/workflows/index.rhtml @@ -0,0 +1,31 @@ +

    <%=l(:label_workflow)%>

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

    <%= l(:label_no_data) %>

    +<% else %> + + + + + <% @workflow_counts.first.last.each do |role, count| %> + + + <% end %> + + + +<% @workflow_counts.each do |tracker, roles| -%> + + + <% roles.each do |role, count| -%> + + <% end -%> + +<% end -%> + +
    + <%= content_tag(role.builtin? ? 'em' : 'span', h(role.name)) %> +
    <%= h tracker %> + <%= link_to((count > 1 ? count : image_tag('false.png')), {:action => 'edit', :role_id => role, :tracker_id => tracker}, :title => l(:button_edit)) %> +
    +<% end %> diff --git a/config/environment.rb b/config/environment.rb index 9a3bf4b1d..fdac6b4f0 100644 --- a/config/environment.rb +++ b/config/environment.rb @@ -5,7 +5,7 @@ # ENV['RAILS_ENV'] ||= 'production' # Specifies gem version of Rails to use when vendor/rails is not present -RAILS_GEM_VERSION = '2.1.0' unless defined? RAILS_GEM_VERSION +RAILS_GEM_VERSION = '2.1.2' unless defined? RAILS_GEM_VERSION # Bootstrap the Rails environment, frameworks, and default configuration require File.join(File.dirname(__FILE__), 'boot') diff --git a/config/initializers/10-patches.rb b/config/initializers/10-patches.rb index fcc091997..d1235d93f 100644 --- a/config/initializers/10-patches.rb +++ b/config/initializers/10-patches.rb @@ -12,6 +12,20 @@ ActiveRecord::Errors.default_error_messages = { :wrong_length => "activerecord_error_wrong_length", :taken => "activerecord_error_taken", :not_a_number => "activerecord_error_not_a_number" -} +} if ActiveRecord::Errors.respond_to?('default_error_messages=') ActionView::Base.field_error_proc = Proc.new{ |html_tag, instance| "#{html_tag}" } + +# Adds :async_smtp and :async_sendmail delivery methods +# to perform email deliveries asynchronously +module AsynchronousMailer + %w(smtp sendmail).each do |type| + define_method("perform_delivery_async_#{type}") do |mail| + Thread.start do + send "perform_delivery_#{type}", mail + end + end + end +end + +ActionMailer::Base.send :include, AsynchronousMailer diff --git a/config/routes.rb b/config/routes.rb index 913a8020f..d20bc3c9f 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -6,41 +6,255 @@ ActionController::Routing::Routes.draw do |map| # map.connect 'products/:id', :controller => 'catalog', :action => 'view' # Keep in mind you can assign values other than :controller and :action + # Allow Redmine plugins to map routes and potentially override them + Rails.plugins.each do |plugin| + map.from_plugin plugin.name.to_sym + end + map.home '', :controller => 'welcome' + map.signin 'login', :controller => 'account', :action => 'login' map.signout 'logout', :controller => 'account', :action => 'logout' - map.connect 'wiki/:id/:page/:action', :controller => 'wiki', :page => nil map.connect 'roles/workflow/:id/:role_id/:tracker_id', :controller => 'roles', :action => 'workflow' map.connect 'help/:ctrl/:page', :controller => 'help' - #map.connect ':controller/:action/:id/:sort_key/:sort_order' - map.connect 'issues/:issue_id/relations/:action/:id', :controller => 'issue_relations' + map.connect 'time_entries/:id/edit', :action => 'edit', :controller => 'timelog' + map.connect 'projects/:project_id/time_entries/new', :action => 'edit', :controller => 'timelog' + map.connect 'projects/:project_id/issues/:issue_id/time_entries/new', :action => 'edit', :controller => 'timelog' + + map.with_options :controller => 'timelog' do |timelog| + timelog.connect 'projects/:project_id/time_entries', :action => 'details' + + timelog.with_options :action => 'details', :conditions => {:method => :get} do |time_details| + time_details.connect 'time_entries' + time_details.connect 'time_entries.:format' + time_details.connect 'issues/:issue_id/time_entries' + time_details.connect 'issues/:issue_id/time_entries.:format' + time_details.connect 'projects/:project_id/time_entries.:format' + time_details.connect 'projects/:project_id/issues/:issue_id/time_entries' + time_details.connect 'projects/:project_id/issues/:issue_id/time_entries.:format' + end + timelog.connect 'projects/:project_id/time_entries/report', :action => 'report' + timelog.with_options :action => 'report',:conditions => {:method => :get} do |time_report| + time_report.connect 'time_entries/report' + time_report.connect 'time_entries/report.:format' + time_report.connect 'projects/:project_id/time_entries/report.:format' + end + + timelog.with_options :action => 'edit', :conditions => {:method => :get} do |time_edit| + time_edit.connect 'issues/:issue_id/time_entries/new' + end + + timelog.connect 'time_entries/:id/destroy', :action => 'destroy', :conditions => {:method => :post} + end + + map.connect 'projects/:id/wiki', :controller => 'wikis', :action => 'edit', :conditions => {:method => :post} + map.connect 'projects/:id/wiki/destroy', :controller => 'wikis', :action => 'destroy', :conditions => {:method => :get} + map.connect 'projects/:id/wiki/destroy', :controller => 'wikis', :action => 'destroy', :conditions => {:method => :post} + map.with_options :controller => 'wiki' do |wiki_routes| + wiki_routes.with_options :conditions => {:method => :get} do |wiki_views| + wiki_views.connect 'projects/:id/wiki/:page', :action => 'special', :page => /page_index|date_index|export/i + wiki_views.connect 'projects/:id/wiki/:page', :action => 'index', :page => nil + wiki_views.connect 'projects/:id/wiki/:page/edit', :action => 'edit' + wiki_views.connect 'projects/:id/wiki/:page/rename', :action => 'rename' + wiki_views.connect 'projects/:id/wiki/:page/history', :action => 'history' + wiki_views.connect 'projects/:id/wiki/:page/diff/:version/vs/:version_from', :action => 'diff' + wiki_views.connect 'projects/:id/wiki/:page/annotate/:version', :action => 'annotate' + end + + wiki_routes.connect 'projects/:id/wiki/:page/:action', + :action => /edit|rename|destroy|preview|protect/, + :conditions => {:method => :post} + end + + map.with_options :controller => 'messages' do |messages_routes| + messages_routes.with_options :conditions => {:method => :get} do |messages_views| + messages_views.connect 'boards/:board_id/topics/new', :action => 'new' + messages_views.connect 'boards/:board_id/topics/:id', :action => 'show' + messages_views.connect 'boards/:board_id/topics/:id/edit', :action => 'edit' + end + messages_routes.with_options :conditions => {:method => :post} do |messages_actions| + messages_actions.connect 'boards/:board_id/topics/new', :action => 'new' + messages_actions.connect 'boards/:board_id/topics/:id/replies', :action => 'reply' + messages_actions.connect 'boards/:board_id/topics/:id/:action', :action => /edit|destroy/ + end + end + + map.with_options :controller => 'boards' do |board_routes| + board_routes.with_options :conditions => {:method => :get} do |board_views| + board_views.connect 'projects/:project_id/boards', :action => 'index' + board_views.connect 'projects/:project_id/boards/new', :action => 'new' + board_views.connect 'projects/:project_id/boards/:id', :action => 'show' + board_views.connect 'projects/:project_id/boards/:id/edit', :action => 'edit' + end + board_routes.with_options :conditions => {:method => :post} do |board_actions| + board_actions.connect 'projects/:project_id/boards', :action => 'new' + board_actions.connect 'projects/:project_id/boards/:id/:action', :action => /edit|destroy/ + end + end + + map.with_options :controller => 'documents' do |document_routes| + document_routes.with_options :conditions => {:method => :get} do |document_views| + document_views.connect 'projects/:project_id/documents', :action => 'index' + document_views.connect 'projects/:project_id/documents/new', :action => 'new' + document_views.connect 'documents/:id', :action => 'show' + document_views.connect 'documents/:id/edit', :action => 'edit' + end + document_routes.with_options :conditions => {:method => :post} do |document_actions| + document_actions.connect 'projects/:project_id/documents', :action => 'new' + document_actions.connect 'documents/:id/:action', :action => /destroy|edit/ + end + end + + map.with_options :controller => 'issues' do |issues_routes| + issues_routes.with_options :conditions => {:method => :get} do |issues_views| + issues_views.connect 'issues', :action => 'index' + issues_views.connect 'issues.:format', :action => 'index' + issues_views.connect 'projects/:project_id/issues', :action => 'index' + issues_views.connect 'projects/:project_id/issues.:format', :action => 'index' + issues_views.connect 'projects/:project_id/issues/new', :action => 'new' + issues_views.connect 'projects/:project_id/issues/gantt', :action => 'gantt' + issues_views.connect 'projects/:project_id/issues/calendar', :action => 'calendar' + issues_views.connect 'projects/:project_id/issues/:copy_from/copy', :action => 'new' + issues_views.connect 'issues/:id', :action => 'show', :id => /\d+/ + issues_views.connect 'issues/:id.:format', :action => 'show', :id => /\d+/ + issues_views.connect 'issues/:id/edit', :action => 'edit', :id => /\d+/ + issues_views.connect 'issues/:id/move', :action => 'move', :id => /\d+/ + end + issues_routes.with_options :conditions => {:method => :post} do |issues_actions| + issues_actions.connect 'projects/:project_id/issues', :action => 'new' + issues_actions.connect 'issues/:id/quoted', :action => 'reply', :id => /\d+/ + issues_actions.connect 'issues/:id/:action', :action => /edit|move|destroy/, :id => /\d+/ + end + issues_routes.connect 'issues/:action' + end + + map.with_options :controller => 'issue_relations', :conditions => {:method => :post} do |relations| + relations.connect 'issues/:issue_id/relations/:id', :action => 'new' + relations.connect 'issues/:issue_id/relations/:id/destroy', :action => 'destroy' + end + + map.with_options :controller => 'reports', :action => 'issue_report', :conditions => {:method => :get} do |reports| + reports.connect 'projects/:id/issues/report' + reports.connect 'projects/:id/issues/report/:detail' + end + + map.with_options :controller => 'news' do |news_routes| + news_routes.with_options :conditions => {:method => :get} do |news_views| + news_views.connect 'news', :action => 'index' + news_views.connect 'projects/:project_id/news', :action => 'index' + news_views.connect 'projects/:project_id/news.:format', :action => 'index' + news_views.connect 'news.:format', :action => 'index' + news_views.connect 'projects/:project_id/news/new', :action => 'new' + news_views.connect 'news/:id', :action => 'show' + news_views.connect 'news/:id/edit', :action => 'edit' + end + news_routes.with_options do |news_actions| + news_actions.connect 'projects/:project_id/news', :action => 'new' + news_actions.connect 'news/:id/edit', :action => 'edit' + news_actions.connect 'news/:id/destroy', :action => 'destroy' + end + end + + map.connect 'projects/:id/members/new', :controller => 'members', :action => 'new' + + map.with_options :controller => 'users' do |users| + users.with_options :conditions => {:method => :get} do |user_views| + user_views.connect 'users', :action => 'list' + user_views.connect 'users', :action => 'index' + user_views.connect 'users/new', :action => 'add' + user_views.connect 'users/:id/edit/:tab', :action => 'edit', :tab => nil + end + users.with_options :conditions => {:method => :post} do |user_actions| + user_actions.connect 'users', :action => 'add' + user_actions.connect 'users/new', :action => 'add' + user_actions.connect 'users/:id/edit', :action => 'edit' + user_actions.connect 'users/:id/memberships', :action => 'edit_membership' + user_actions.connect 'users/:id/memberships/:membership_id', :action => 'edit_membership' + user_actions.connect 'users/:id/memberships/:membership_id/destroy', :action => 'destroy_membership' + end + end + + map.with_options :controller => 'projects' do |projects| + projects.with_options :conditions => {:method => :get} do |project_views| + project_views.connect 'projects', :action => 'index' + project_views.connect 'projects.:format', :action => 'index' + project_views.connect 'projects/new', :action => 'add' + project_views.connect 'projects/:id', :action => 'show' + project_views.connect 'projects/:id/:action', :action => /roadmap|changelog|destroy|settings/ + project_views.connect 'projects/:id/files', :action => 'list_files' + project_views.connect 'projects/:id/files/new', :action => 'add_file' + project_views.connect 'projects/:id/versions/new', :action => 'add_version' + project_views.connect 'projects/:id/categories/new', :action => 'add_issue_category' + project_views.connect 'projects/:id/settings/:tab', :action => 'settings' + end + + projects.with_options :action => 'activity', :conditions => {:method => :get} do |activity| + activity.connect 'projects/:id/activity' + activity.connect 'projects/:id/activity.:format' + activity.connect 'activity' + activity.connect 'activity.:format' + end + + projects.with_options :conditions => {:method => :post} do |project_actions| + project_actions.connect 'projects/new', :action => 'add' + project_actions.connect 'projects', :action => 'add' + project_actions.connect 'projects/:id/:action', :action => /destroy|archive|unarchive/ + project_actions.connect 'projects/:id/files/new', :action => 'add_file' + project_actions.connect 'projects/:id/versions/new', :action => 'add_version' + project_actions.connect 'projects/:id/categories/new', :action => 'add_issue_category' + end + end + + map.with_options :controller => 'repositories' do |repositories| + repositories.with_options :conditions => {:method => :get} do |repository_views| + repositories.connect 'projects/:id/repository', :action => 'show' + repositories.connect 'projects/:id/repository/edit', :action => 'edit' + repositories.connect 'projects/:id/repository/statistics', :action => 'stats' + repositories.connect 'projects/:id/repository/revisions', :action => 'revisions' + repositories.connect 'projects/:id/repository/revisions.:format', :action => 'revisions' + repositories.connect 'projects/:id/repository/revisions/:rev', :action => 'revision' + repositories.connect 'projects/:id/repository/revisions/:rev/diff', :action => 'diff' + repositories.connect 'projects/:id/repository/revisions/:rev/diff.:format', :action => 'diff' + repositories.connect 'projects/:id/repository/revisions/:rev/:action/*path' + repositories.connect 'projects/:id/repository/:action/*path' + end + + repositories.connect 'projects/:id/repository/edit', :action => 'edit', :conditions => {:method => :post} + end + + map.connect 'attachments/:id', :controller => 'attachments', :action => 'show', :id => /\d+/ + map.connect 'attachments/:id/:filename', :controller => 'attachments', :action => 'show', :id => /\d+/, :filename => /.*/ + map.connect 'attachments/download/:id/:filename', :controller => 'attachments', :action => 'download', :id => /\d+/, :filename => /.*/ + + + #left old routes at the bottom for backwards compat map.connect 'projects/:project_id/issues/:action', :controller => 'issues' - map.connect 'projects/:project_id/news/:action', :controller => 'news' map.connect 'projects/:project_id/documents/:action', :controller => 'documents' map.connect 'projects/:project_id/boards/:action/:id', :controller => 'boards' - map.connect 'projects/:project_id/timelog/:action/:id', :controller => 'timelog', :project_id => /.+/ map.connect 'boards/:board_id/topics/:action/:id', :controller => 'messages' - + map.connect 'wiki/:id/:page/:action', :page => nil, :controller => 'wiki' + map.connect 'issues/:issue_id/relations/:action/:id', :controller => 'issue_relations' + map.connect 'projects/:project_id/news/:action', :controller => 'news' + map.connect 'projects/:project_id/timelog/:action/:id', :controller => 'timelog', :project_id => /.+/ map.with_options :controller => 'repositories' do |omap| omap.repositories_show 'repositories/browse/:id/*path', :action => 'browse' omap.repositories_changes 'repositories/changes/:id/*path', :action => 'changes' omap.repositories_diff 'repositories/diff/:id/*path', :action => 'diff' omap.repositories_entry 'repositories/entry/:id/*path', :action => 'entry' omap.repositories_entry 'repositories/annotate/:id/*path', :action => 'annotate' - omap.repositories_revision 'repositories/revision/:id/:rev', :action => 'revision' + omap.connect 'repositories/revision/:id/:rev', :action => 'revision' end - map.connect 'attachments/:id', :controller => 'attachments', :action => 'show', :id => /\d+/ - map.connect 'attachments/:id/:filename', :controller => 'attachments', :action => 'show', :id => /\d+/, :filename => /.*/ - map.connect 'attachments/download/:id/:filename', :controller => 'attachments', :action => 'download', :id => /\d+/, :filename => /.*/ - - # Allow downloading Web Service WSDL as a file with an extension - # instead of a file named 'wsdl' - map.connect ':controller/service.wsdl', :action => 'wsdl' - + map.with_options :controller => 'sys' do |sys| + sys.connect 'sys/projects.:format', :action => 'projects', :conditions => {:method => :get} + sys.connect 'sys/projects/:id/repository.:format', :action => 'create_project_repository', :conditions => {:method => :post} + end # Install the default route as the lowest priority. map.connect ':controller/:action/:id' + map.connect 'robots.txt', :controller => 'welcome', :action => 'robots' + # Used for OpenID + map.root :controller => 'account', :action => 'login' end diff --git a/config/settings.yml b/config/settings.yml index 52f7bed87..56cdf8659 100644 --- a/config/settings.yml +++ b/config/settings.yml @@ -46,6 +46,8 @@ mail_from: default: redmine@example.net bcc_recipients: default: 1 +plain_text_mail: + default: 0 text_formatting: default: textile wiki_compression: @@ -59,6 +61,9 @@ protocol: feeds_limit: format: int default: 15 +diff_max_lines_displayed: + format: int + default: 1500 enabled_scm: serialized: true default: @@ -129,10 +134,16 @@ repositories_cache_directory: # encoding used to convert commit logs to UTF-8 commit_logs_encoding: default: 'UTF-8' +repository_log_display_limit: + format: int + default: 100 ui_theme: default: '' emails_footer: default: |- You have received this notification because you have either subscribed to it, or are involved in it. To change your notification preferences, please click here: http://hostname/my/account - +gravatar_enabled: + default: 0 +openid: + default: 0 diff --git a/db/migrate/098_set_topic_authors_as_watchers.rb b/db/migrate/098_set_topic_authors_as_watchers.rb index 5bc41fb38..92a53f4a1 100644 --- a/db/migrate/098_set_topic_authors_as_watchers.rb +++ b/db/migrate/098_set_topic_authors_as_watchers.rb @@ -2,9 +2,10 @@ class SetTopicAuthorsAsWatchers < ActiveRecord::Migration def self.up # Sets active users who created/replied a topic as watchers of the topic # so that the new watch functionality at topic level doesn't affect notifications behaviour - Message.connection.execute("INSERT INTO watchers (watchable_type, watchable_id, user_id)" + - " SELECT DISTINCT 'Message', COALESCE(messages.parent_id, messages.id), messages.author_id FROM messages, users" + - " WHERE messages.author_id = users.id AND users.status = 1") + Message.connection.execute("INSERT INTO #{Watcher.table_name} (watchable_type, watchable_id, user_id)" + + " SELECT DISTINCT 'Message', COALESCE(m.parent_id, m.id), m.author_id" + + " FROM #{Message.table_name} m, #{User.table_name} u" + + " WHERE m.author_id = u.id AND u.status = 1") end def self.down diff --git a/db/migrate/099_add_delete_wiki_pages_attachments_permission.rb b/db/migrate/099_add_delete_wiki_pages_attachments_permission.rb new file mode 100644 index 000000000..1ff888f3c --- /dev/null +++ b/db/migrate/099_add_delete_wiki_pages_attachments_permission.rb @@ -0,0 +1,13 @@ +class AddDeleteWikiPagesAttachmentsPermission < ActiveRecord::Migration + def self.up + Role.find(:all).each do |r| + r.add_permission!(:delete_wiki_pages_attachments) if r.has_permission?(:edit_wiki_pages) + end + end + + def self.down + Role.find(:all).each do |r| + r.remove_permission!(:delete_wiki_pages_attachments) + end + end +end diff --git a/db/migrate/100_add_changesets_user_id.rb b/db/migrate/100_add_changesets_user_id.rb new file mode 100644 index 000000000..9b25fd7bc --- /dev/null +++ b/db/migrate/100_add_changesets_user_id.rb @@ -0,0 +1,9 @@ +class AddChangesetsUserId < ActiveRecord::Migration + def self.up + add_column :changesets, :user_id, :integer, :default => nil + end + + def self.down + remove_column :changesets, :user_id + end +end diff --git a/db/migrate/101_populate_changesets_user_id.rb b/db/migrate/101_populate_changesets_user_id.rb new file mode 100644 index 000000000..dd493d17d --- /dev/null +++ b/db/migrate/101_populate_changesets_user_id.rb @@ -0,0 +1,18 @@ +class PopulateChangesetsUserId < ActiveRecord::Migration + def self.up + committers = Changeset.connection.select_values("SELECT DISTINCT committer FROM #{Changeset.table_name}") + committers.each do |committer| + next if committer.blank? + if committer.strip =~ /^([^<]+)(<(.*)>)?$/ + username, email = $1.strip, $3 + u = User.find_by_login(username) + u ||= User.find_by_mail(email) unless email.blank? + Changeset.update_all("user_id = #{u.id}", ["committer = ?", committer]) unless u.nil? + end + end + end + + def self.down + Changeset.update_all('user_id = NULL') + end +end diff --git a/db/migrate/102_add_custom_fields_editable.rb b/db/migrate/102_add_custom_fields_editable.rb new file mode 100644 index 000000000..949f9db9d --- /dev/null +++ b/db/migrate/102_add_custom_fields_editable.rb @@ -0,0 +1,9 @@ +class AddCustomFieldsEditable < ActiveRecord::Migration + def self.up + add_column :custom_fields, :editable, :boolean, :default => true + end + + def self.down + remove_column :custom_fields, :editable + end +end diff --git a/db/migrate/103_set_custom_fields_editable.rb b/db/migrate/103_set_custom_fields_editable.rb new file mode 100644 index 000000000..937649e61 --- /dev/null +++ b/db/migrate/103_set_custom_fields_editable.rb @@ -0,0 +1,9 @@ +class SetCustomFieldsEditable < ActiveRecord::Migration + def self.up + UserCustomField.update_all("editable = #{CustomField.connection.quoted_false}") + end + + def self.down + UserCustomField.update_all("editable = #{CustomField.connection.quoted_true}") + end +end diff --git a/db/migrate/104_add_projects_lft_and_rgt.rb b/db/migrate/104_add_projects_lft_and_rgt.rb new file mode 100644 index 000000000..8952c16e1 --- /dev/null +++ b/db/migrate/104_add_projects_lft_and_rgt.rb @@ -0,0 +1,11 @@ +class AddProjectsLftAndRgt < ActiveRecord::Migration + def self.up + add_column :projects, :lft, :integer + add_column :projects, :rgt, :integer + end + + def self.down + remove_column :projects, :lft + remove_column :projects, :rgt + end +end diff --git a/db/migrate/105_build_projects_tree.rb b/db/migrate/105_build_projects_tree.rb new file mode 100644 index 000000000..92799f97d --- /dev/null +++ b/db/migrate/105_build_projects_tree.rb @@ -0,0 +1,8 @@ +class BuildProjectsTree < ActiveRecord::Migration + def self.up + Project.rebuild! + end + + def self.down + end +end diff --git a/db/migrate/106_remove_projects_projects_count.rb b/db/migrate/106_remove_projects_projects_count.rb new file mode 100644 index 000000000..68bb3d115 --- /dev/null +++ b/db/migrate/106_remove_projects_projects_count.rb @@ -0,0 +1,9 @@ +class RemoveProjectsProjectsCount < ActiveRecord::Migration + def self.up + remove_column :projects, :projects_count + end + + def self.down + add_column :projects, :projects_count, :integer, :default => 0 + end +end diff --git a/db/migrate/107_add_open_id_authentication_tables.rb b/db/migrate/107_add_open_id_authentication_tables.rb new file mode 100644 index 000000000..caae0d8c7 --- /dev/null +++ b/db/migrate/107_add_open_id_authentication_tables.rb @@ -0,0 +1,20 @@ +class AddOpenIdAuthenticationTables < ActiveRecord::Migration + def self.up + create_table :open_id_authentication_associations, :force => true do |t| + t.integer :issued, :lifetime + t.string :handle, :assoc_type + t.binary :server_url, :secret + end + + create_table :open_id_authentication_nonces, :force => true do |t| + t.integer :timestamp, :null => false + t.string :server_url, :null => true + t.string :salt, :null => false + end + end + + def self.down + drop_table :open_id_authentication_associations + drop_table :open_id_authentication_nonces + end +end diff --git a/db/migrate/108_add_identity_url_to_users.rb b/db/migrate/108_add_identity_url_to_users.rb new file mode 100644 index 000000000..f5af77b24 --- /dev/null +++ b/db/migrate/108_add_identity_url_to_users.rb @@ -0,0 +1,9 @@ +class AddIdentityUrlToUsers < ActiveRecord::Migration + def self.up + add_column :users, :identity_url, :string + end + + def self.down + remove_column :users, :identity_url + end +end diff --git a/doc/CHANGELOG b/doc/CHANGELOG index ac8cb6673..31f316557 100644 --- a/doc/CHANGELOG +++ b/doc/CHANGELOG @@ -5,6 +5,204 @@ Copyright (C) 2006-2008 Jean-Philippe Lang http://www.redmine.org/ +== v0.8.1 + +* Select watchers on new issue form +* Files module: ability to add files without version +* Show view/annotate/download links on entry and annotate views +* Fixed: Deleted files are shown when using Darcs + + +== 2008-12-30 v0.8.0 + +* Setting added in order to limit the number of diff lines that should be displayed +* Makes logged-in username in topbar linking to +* Mail handler: strip tags when receiving a html-only email +* Mail handler: add watchers before sending notification +* Adds a css class (overdue) to overdue issues on issue lists and detail views +* Fixed: project activity truncated after viewing user's activity +* Fixed: email address entered for password recovery shouldn't be case-sensitive +* Fixed: default flag removed when editing a default enumeration +* Fixed: default category ignored when adding a document +* Fixed: error on repository user mapping when a repository username is blank +* Fixed: Firefox cuts off large diffs +* Fixed: CVS browser should not show dead revisions (deleted files) +* Fixed: escape double-quotes in image titles +* Fixed: escape textarea content when editing a issue note +* Fixed: JS error on context menu with IE +* Fixed: bold syntax around single character in series doesn't work +* Fixed several XSS vulnerabilities +* Fixed a SQL injection vulnerability + + +== 2008-12-07 v0.8.0-rc1 + +* Wiki page protection +* Wiki page hierarchy. Parent page can be assigned on the Rename screen +* Adds support for issue creation via email +* Adds support for free ticket filtering and custom queries on Gantt chart and calendar +* Cross-project search +* Ability to search a project and its subprojects +* Ability to search the projects the user belongs to +* Adds custom fields on time entries +* Adds boolean and list custom fields for time entries as criteria on time report +* Cross-project time reports +* Display latest user's activity on account/show view +* Show last connexion time on user's page +* Obfuscates email address on user's account page using javascript +* wiki TOC rendered as an unordered list +* Adds the ability to search for a user on the administration users list +* Adds the ability to search for a project name or identifier on the administration projects list +* Redirect user to the previous page after logging in +* Adds a permission 'view wiki edits' so that wiki history can be hidden to certain users +* Adds permissions for viewing the watcher list and adding new watchers on the issue detail view +* Adds permissions to let users edit and/or delete their messages +* Link to activity view when displaying dates +* Hide Redmine version in atom feeds and pdf properties +* Maps repository users to Redmine users. Users with same username or email are automatically mapped. Mapping can be manually adjusted in repository settings. Multiple usernames can be mapped to the same Redmine user. +* Sort users by their display names so that user dropdown lists are sorted alphabetically +* Adds estimated hours to issue filters +* Switch order of current and previous revisions in side-by-side diff +* Render the commit changes list as a tree +* Adds watch/unwatch functionality at forum topic level +* When moving an issue to another project, reassign it to the category with same name if any +* Adds child_pages macro for wiki pages +* Use GET instead of POST on roadmap (#718), gantt and calendar forms +* Search engine: display total results count and count by result type +* Email delivery configuration moved to an unversioned YAML file (config/email.yml, see the sample file) +* Adds icons on search results +* Adds 'Edit' link on account/show for admin users +* Adds Lock/Unlock/Activate link on user edit screen +* Adds user count in status drop down on admin user list +* Adds multi-levels blockquotes support by using > at the beginning of lines +* Adds a Reply link to each issue note +* Adds plain text only option for mail notifications +* Gravatar support for issue detail, user grid, and activity stream (disabled by default) +* Adds 'Delete wiki pages attachments' permission +* Show the most recent file when displaying an inline image +* Makes permission screens localized +* AuthSource list: display associated users count and disable 'Delete' buton if any +* Make the 'duplicates of' relation asymmetric +* Adds username to the password reminder email +* Adds links to forum messages using message#id syntax +* Allow same name for custom fields on different object types +* One-click bulk edition using the issue list context menu within the same project +* Adds support for commit logs reencoding to UTF-8 before insertion in the database. Source encoding of commit logs can be selected in Application settings -> Repositories. +* Adds checkboxes toggle links on permissions report +* Adds Trac-Like anchors on wiki headings +* Adds support for wiki links with anchor +* Adds category to the issue context menu +* Adds a workflow overview screen +* Appends the filename to the attachment url so that clients that ignore content-disposition http header get the real filename +* Dots allowed in custom field name +* Adds posts quoting functionality +* Adds an option to generate sequential project identifiers +* Adds mailto link on the user administration list +* Ability to remove enumerations (activities, priorities, document categories) that are in use. Associated objects can be reassigned to another value +* Gantt chart: display issues that don't have a due date if they are assigned to a version with a date +* Change projects homepage limit to 255 chars +* Improved on-the-fly account creation. If some attributes are missing (eg. not present in the LDAP) or are invalid, the registration form is displayed so that the user is able to fill or fix these attributes +* Adds "please select" to activity select box if no activity is set as default +* Do not silently ignore timelog validation failure on issue edit +* Adds a rake task to send reminder emails +* Allow empty cells in wiki tables +* Makes wiki text formatter pluggable +* Adds back textile acronyms support +* Remove pre tag attributes +* Plugin hooks +* Pluggable admin menu +* Plugins can provide activity content +* Moves plugin list to its own administration menu item +* Adds url and author_url plugin attributes +* Adds Plugin#requires_redmine method so that plugin compatibility can be checked against current Redmine version +* Adds atom feed on time entries details +* Adds project name to issues feed title +* Adds a css class on menu items in order to apply item specific styles (eg. icons) +* Adds a Redmine plugin generators +* Adds timelog link to the issue context menu +* Adds links to the user page on various views +* Turkish translation by Ismail Sezen +* Catalan translation +* Vietnamese translation +* Slovak translation +* Better naming of activity feed if only one kind of event is displayed +* Enable syntax highlight on issues, messages and news +* Add target version to the issue list context menu +* Hide 'Target version' filter if no version is defined +* Add filters on cross-project issue list for custom fields marked as 'For all projects' +* Turn ftp urls into links +* Hiding the View Differences button when a wiki page's history only has one version +* Messages on a Board can now be sorted by the number of replies +* Adds a class ('me') to events of the activity view created by current user +* Strip pre/code tags content from activity view events +* Display issue notes in the activity view +* Adds links to changesets atom feed on repository browser +* Track project and tracker changes in issue history +* Adds anchor to atom feed messages links +* Adds a key in lang files to set the decimal separator (point or comma) in csv exports +* Makes importer work with Trac 0.8.x +* Upgraded to Prototype 1.6.0.1 +* File viewer for attached text files +* Menu mapper: add support for :before, :after and :last options to #push method and add #delete method +* Removed inconsistent revision numbers on diff view +* CVS: add support for modules names with spaces +* Log the user in after registration if account activation is not needed +* Mercurial adapter improvements +* Trac importer: read session_attribute table to find user's email and real name +* Ability to disable unused SCM adapters in application settings +* Adds Filesystem adapter +* Clear changesets and changes with raw sql when deleting a repository for performance +* Redmine.pm now uses the 'commit access' permission defined in Redmine +* Reposman can create any type of scm (--scm option) +* Reposman creates a repository if the 'repository' module is enabled at project level only +* Display svn properties in the browser, svn >= 1.5.0 only +* Reduces memory usage when importing large git repositories +* Wider SVG graphs in repository stats +* SubversionAdapter#entries performance improvement +* SCM browser: ability to download raw unified diffs +* More detailed error message in log when scm command fails +* Adds support for file viewing with Darcs 2.0+ +* Check that git changeset is not in the database before creating it +* Unified diff viewer for attached files with .patch or .diff extension +* File size display with Bazaar repositories +* Git adapter: use commit time instead of author time +* Prettier url for changesets +* Makes changes link to entries on the revision view +* Adds a field on the repository view to browse at specific revision +* Adds new projects atom feed +* Added rake tasks to generate rcov code coverage reports +* Add Redcloth's :block_markdown_rule to allow horizontal rules in wiki +* Show the project hierarchy in the drop down list for new membership on user administration screen +* Split user edit screen into tabs +* Renames bundled RedCloth to RedCloth3 to avoid RedCloth 4 to be loaded instead +* Fixed: Roadmap crashes when a version has a due date > 2037 +* Fixed: invalid effective date (eg. 99999-01-01) causes an error on version edition screen +* Fixed: login filter providing incorrect back_url for Redmine installed in sub-directory +* Fixed: logtime entry duplicated when edited from parent project +* Fixed: wrong digest for text files under Windows +* Fixed: associated revisions are displayed in wrong order on issue view +* Fixed: Git Adapter date parsing ignores timezone +* Fixed: Printing long roadmap doesn't split across pages +* Fixes custom fields display order at several places +* Fixed: urls containing @ are parsed as email adress by the wiki formatter +* Fixed date filters accuracy with SQLite +* Fixed: tokens not escaped in highlight_tokens regexp +* Fixed Bazaar shared repository browsing +* Fixes platform determination under JRuby +* Fixed: Estimated time in issue's journal should be rounded to two decimals +* Fixed: 'search titles only' box ignored after one search is done on titles only +* Fixed: non-ASCII subversion path can't be displayed +* Fixed: Inline images don't work if file name has upper case letters or if image is in BMP format +* Fixed: document listing shows on "my page" when viewing documents is disabled for the role +* Fixed: Latest news appear on the homepage for projects with the News module disabled +* Fixed: cross-project issue list should not show issues of projects for which the issue tracking module was disabled +* Fixed: the default status is lost when reordering issue statuses +* Fixes error with Postgresql and non-UTF8 commit logs +* Fixed: textile footnotes no longer work +* Fixed: http links containing parentheses fail to reder correctly +* Fixed: GitAdapter#get_rev should use current branch instead of hardwiring master + + == 2008-07-06 v0.7.3 * Allow dot in firstnames and lastnames diff --git a/doc/RUNNING_TESTS b/doc/RUNNING_TESTS index 6ee977811..b5bfa3862 100644 --- a/doc/RUNNING_TESTS +++ b/doc/RUNNING_TESTS @@ -1,45 +1,16 @@ -Creating test repositories -=================== - -mkdir tmp/test - -Subversion ----------- -svnadmin create tmp/test/subversion_repository -gunzip < test/fixtures/repositories/subversion_repository.dump.gz | svnadmin load tmp/test/subversion_repository - -CVS ---- -gunzip < test/fixtures/repositories/cvs_repository.tar.gz | tar -xv -C tmp/test - -Bazaar ------- -gunzip < test/fixtures/repositories/bazaar_repository.tar.gz | tar -xv -C tmp/test - -Mercurial ---------- -gunzip < test/fixtures/repositories/mercurial_repository.tar.gz | tar -xv -C tmp/test - -Git ---- -gunzip < test/fixtures/repositories/git_repository.tar.gz | tar -xv -C tmp/test - -Darcs (2.0+ required) ---------------------- -gunzip < test/fixtures/repositories/darcs_repository.tar.gz | tar -xv -C tmp/test - -FileSystem ----------- -gunzip < test/fixtures/repositories/filesystem_repository.tar.gz | tar -xv -C tmp/test - - Running Tests ============= -Run +Run `rake --tasks test` to see available tests. +`rake test` will run the entire testsuite. + + +Creating test repositories +=================== - rake --tasks | grep test +Redmine supports a wide array of different version control systems. +To test the support, a test repository needs to be created for each of those. -to see available tests. +Run `rake --tasks test:scm:setup` for a list of available test-repositories or +run `rake test:scm:setup:all` to set up all of them -RAILS_ENV=test rake test will run tests. diff --git a/doc/UPGRADING b/doc/UPGRADING index 1dd901171..40c691fea 100644 --- a/doc/UPGRADING +++ b/doc/UPGRADING @@ -22,7 +22,7 @@ http://www.redmine.org/ == Notes -1. Rails 2.0.2 is required for version 0.7 and later. +1. Rails 2.1.2 is required for version 0.8. 2. When upgrading your code with svn update, don't forget to clear the application cache (RAILS_ROOT/tmp/cache) before restarting. diff --git a/extra/mail_handler/rdm-mailhandler.rb b/extra/mail_handler/rdm-mailhandler.rb index 0f8020c76..93484ca34 100644 --- a/extra/mail_handler/rdm-mailhandler.rb +++ b/extra/mail_handler/rdm-mailhandler.rb @@ -1,4 +1,4 @@ -#!/usr/bin/ruby +#!/usr/bin/env ruby # == Synopsis # @@ -21,6 +21,7 @@ # # Issue attributes control options: # -p, --project=PROJECT identifier of the target project +# -s, --status=STATUS name of the target status # -t, --tracker=TRACKER name of the target tracker # --category=CATEGORY name of the target category # --priority=PRIORITY name of the target priority @@ -75,6 +76,7 @@ class RedmineMailHandler [ '--url', '-u', GetoptLong::REQUIRED_ARGUMENT ], [ '--key', '-k', GetoptLong::REQUIRED_ARGUMENT], [ '--project', '-p', GetoptLong::REQUIRED_ARGUMENT ], + [ '--status', '-s', GetoptLong::REQUIRED_ARGUMENT ], [ '--tracker', '-t', GetoptLong::REQUIRED_ARGUMENT], [ '--category', GetoptLong::REQUIRED_ARGUMENT], [ '--priority', GetoptLong::REQUIRED_ARGUMENT], @@ -93,7 +95,7 @@ class RedmineMailHandler self.verbose = true when '--version' puts VERSION; exit - when '--project', '--tracker', '--category', '--priority' + when '--project', '--status', '--tracker', '--category', '--priority' self.issue_attributes[opt.gsub(%r{^\-\-}, '')] = arg.dup when '--allow-override' self.allow_override = arg.dup diff --git a/extra/svn/reposman.rb b/extra/svn/reposman.rb index b7aa2a462..84e9bc2da 100755 --- a/extra/svn/reposman.rb +++ b/extra/svn/reposman.rb @@ -1,4 +1,4 @@ -#!/usr/bin/ruby +#!/usr/bin/env ruby # == Synopsis # @@ -57,11 +57,10 @@ require 'getoptlong' require 'rdoc/usage' -require 'soap/wsdlDriver' require 'find' require 'etc' -Version = "1.1" +Version = "1.2" SUPPORTED_SCM = %w( Subversion Darcs Mercurial Bazaar Git Filesystem ) opts = GetoptLong.new( @@ -164,21 +163,28 @@ unless File.directory?($repos_base) log("directory '#{$repos_base}' doesn't exists", :exit => true) end +begin + require 'activeresource' +rescue LoadError + log("This script requires activeresource.\nRun 'gem install activeresource' to install it.", :exit => true) +end + +class Project < ActiveResource::Base; end + log("querying Redmine for projects...", :level => 1); $redmine_host.gsub!(/^/, "http://") unless $redmine_host.match("^https?://") $redmine_host.gsub!(/\/$/, '') -wsdl_url = "#{$redmine_host}/sys/service.wsdl"; +Project.site = "#{$redmine_host}/sys"; begin - soap = SOAP::WSDLDriverFactory.new(wsdl_url).create_rpc_driver + # Get all active projects that have the Repository module enabled + projects = Project.find(:all) rescue => e - log("Unable to connect to #{wsdl_url} : #{e}", :exit => true) + log("Unable to connect to #{Project.site}: #{e}", :exit => true) end -projects = soap.ProjectsWithRepositoryEnabled - if projects.nil? log('no project found, perhaps you forgot to "Enable WS for repository management"', :exit => true) end @@ -247,7 +253,7 @@ projects.each do |project| else # if repository is already declared in redmine, we don't create # unless user use -f with reposman - if $force == false and not project.repository.nil? + if $force == false and project.respond_to?(:repository) log("\trepository for project #{project.identifier} already exists in Redmine", :level => 1) next end @@ -274,11 +280,11 @@ projects.each do |project| end if $svn_url - ret = soap.RepositoryCreated project.identifier, $scm, "#{$svn_url}#{project.identifier}" - if ret > 0 + begin + project.post(:repository, :vendor => $scm, :repository => {:url => "#{$svn_url}#{project.identifier}"}) log("\trepository #{repos_path} registered in Redmine with url #{$svn_url}#{project.identifier}"); - else - log("\trepository #{repos_path} not registered in Redmine. Look in your log to find why."); + rescue => e + log("\trepository #{repos_path} not registered in Redmine: #{e.message}"); end end diff --git a/lang/bg.yml b/lang/bg.yml index 7c171a461..0079c4ab2 100644 --- a/lang/bg.yml +++ b/lang/bg.yml @@ -640,5 +640,70 @@ setting_sequential_project_identifiers: Generate sequential project identifiers notice_unable_delete_version: Unable to delete version label_renamed: renamed label_copied: copied -setting_repositories_cache_directory: Cache directory for repositories -field_cache: Local cache +setting_plain_text_mail: plain text only (no HTML) +permission_view_files: View files +permission_edit_issues: Edit issues +permission_edit_own_time_entries: Edit own time logs +permission_manage_public_queries: Manage public queries +permission_add_issues: Add issues +permission_log_time: Log spent time +permission_view_changesets: View changesets +permission_view_time_entries: View spent time +permission_manage_versions: Manage versions +permission_manage_wiki: Manage wiki +permission_manage_categories: Manage issue categories +permission_protect_wiki_pages: Protect wiki pages +permission_comment_news: Comment news +permission_delete_messages: Delete messages +permission_select_project_modules: Select project modules +permission_manage_documents: Manage documents +permission_edit_wiki_pages: Edit wiki pages +permission_add_issue_watchers: Add watchers +permission_view_gantt: View gantt chart +permission_move_issues: Move issues +permission_manage_issue_relations: Manage issue relations +permission_delete_wiki_pages: Delete wiki pages +permission_manage_boards: Manage boards +permission_delete_wiki_pages_attachments: Delete attachments +permission_view_wiki_edits: View wiki history +permission_add_messages: Post messages +permission_view_messages: View messages +permission_manage_files: Manage files +permission_edit_issue_notes: Edit notes +permission_manage_news: Manage news +permission_view_calendar: View calendrier +permission_manage_members: Manage members +permission_edit_messages: Edit messages +permission_delete_issues: Delete issues +permission_view_issue_watchers: View watchers list +permission_manage_repository: Manage repository +permission_commit_access: Commit access +permission_browse_repository: Browse repository +permission_view_documents: View documents +permission_edit_project: Edit project +permission_add_issue_notes: Add notes +permission_save_queries: Save queries +permission_view_wiki_pages: View wiki +permission_rename_wiki_pages: Rename wiki pages +permission_edit_time_entries: Edit time logs +permission_edit_own_issue_notes: Edit own notes +setting_gravatar_enabled: Use Gravatar user icons +label_example: Example +text_repository_usernames_mapping: "Select ou update the Redmine user mapped to each username found in the repository log.\nUsers with the same Redmine and repository username or email are automatically mapped." +permission_edit_own_messages: Edit own messages +permission_delete_own_messages: Delete own messages +label_user_activity: "%s's activity" +label_updated_time_by: Updated by %s %s ago +text_diff_truncated: '... This diff was truncated because it exceeds the maximum size that can be displayed.' +setting_diff_max_lines_displayed: Max number of diff lines displayed +text_plugin_assets_writable: Plugin assets directory writable +warning_attachments_not_saved: "%d file(s) could not be saved." +button_create_and_continue: Create and continue +text_custom_field_possible_values_info: 'One line for each value' +label_display: Display +field_editable: Editable +setting_repository_log_display_limit: Maximum number of revisions displayed on file log +field_identity_url: OpenID URL +setting_openid: Allow OpenID login and registration +label_login_with_open_id_option: or login with OpenID +field_watcher: Watcher diff --git a/lang/ca.yml b/lang/ca.yml index 0641d781b..770cc305c 100644 --- a/lang/ca.yml +++ b/lang/ca.yml @@ -77,6 +77,7 @@ notice_failed_to_save_issues: "No s'han pogut desar %s assumptes de %d seleccion notice_no_issue_selected: "No s'ha seleccionat cap assumpte. Activeu els assumptes que voleu editar." notice_account_pending: "S'ha creat el compte i ara està pendent de l'aprovació de l'administrador." notice_default_data_loaded: "S'ha carregat correctament la configuració predeterminada." +notice_unable_delete_version: "No s'ha pogut suprimir la versió." error_can_t_load_default_data: "No s'ha pogut carregar la configuració predeterminada: %s" error_scm_not_found: "No s'ha trobat l'entrada o la revisió en el dipòsit." @@ -163,7 +164,7 @@ field_start_date: Inici field_done_ratio: %% realitzat field_auth_source: "Mode d'autenticació" field_hide_mail: "Oculta l'adreça de correu electrònic" -field_comment: Comentari +field_comments: Comentari field_url: URL field_start_page: Pàgina inicial field_subproject: Subprojecte @@ -209,6 +210,7 @@ setting_time_format: Format de hora setting_cross_project_issue_relations: "Permet les relacions d'assumptes entre projectes" setting_issue_list_default_columns: "Columnes mostrades per defecte en la llista d'assumptes" setting_repositories_encodings: Codificacions del dipòsit +setting_commit_logs_encoding: Codificació dels missatges publicats setting_emails_footer: Peu dels correus electrònics setting_protocol: Protocol setting_per_page_options: Opcions dels objectes per pàgina @@ -218,6 +220,7 @@ setting_display_subprojects_issues: "Mostra els assumptes d'un subprojecte en el setting_enabled_scm: "Habilita l'SCM" setting_mail_handler_api_enabled: "Habilita el WS per correus electrònics d'entrada" setting_mail_handler_api_key: Clau API +setting_sequential_project_identifiers: Genera identificadors de projecte seqüencials project_module_issue_tracking: "Seguidor d'assumptes" project_module_time_tracking: Seguidor de temps @@ -402,6 +405,8 @@ label_revision_plural: Revisions label_associated_revisions: Revisions associades label_added: afegit label_modified: modificat +label_renamed: reanomenat +label_copied: copiat label_deleted: suprimit label_latest_revision: Última revisió label_latest_revision_plural: Últimes revisions @@ -462,7 +467,7 @@ label_end_to_start: final al començament label_end_to_end: final al final label_start_to_start: començament al començament label_start_to_end: començament al final -label_stay_logged_in: "Manté l'entrada en" +label_stay_logged_in: "Manté l'entrada" label_disabled: inhabilitat label_show_completed_versions: Mostra les versions completes label_me: jo mateix @@ -560,6 +565,7 @@ button_copy: Copia button_annotate: Anota button_update: Actualitza button_configure: Configura +button_quote: Cita status_active: actiu status_registered: informat @@ -635,12 +641,70 @@ default_activity_development: Desenvolupament enumeration_issue_priorities: Prioritat dels assumptes enumeration_doc_categories: Categories del document enumeration_activities: Activitats (seguidor de temps) -button_quote: Quote -setting_sequential_project_identifiers: Generate sequential project identifiers -notice_unable_delete_version: Unable to delete version. -field_comments: Comment -setting_commit_logs_encoding: Commit messages encoding -label_renamed: renamed -label_copied: copied -setting_repositories_cache_directory: Cache directory for repositories -field_cache: Local cache +setting_plain_text_mail: plain text only (no HTML) +permission_view_files: View files +permission_edit_issues: Edit issues +permission_edit_own_time_entries: Edit own time logs +permission_manage_public_queries: Manage public queries +permission_add_issues: Add issues +permission_log_time: Log spent time +permission_view_changesets: View changesets +permission_view_time_entries: View spent time +permission_manage_versions: Manage versions +permission_manage_wiki: Manage wiki +permission_manage_categories: Manage issue categories +permission_protect_wiki_pages: Protect wiki pages +permission_comment_news: Comment news +permission_delete_messages: Delete messages +permission_select_project_modules: Select project modules +permission_manage_documents: Manage documents +permission_edit_wiki_pages: Edit wiki pages +permission_add_issue_watchers: Add watchers +permission_view_gantt: View gantt chart +permission_move_issues: Move issues +permission_manage_issue_relations: Manage issue relations +permission_delete_wiki_pages: Delete wiki pages +permission_manage_boards: Manage boards +permission_delete_wiki_pages_attachments: Delete attachments +permission_view_wiki_edits: View wiki history +permission_add_messages: Post messages +permission_view_messages: View messages +permission_manage_files: Manage files +permission_edit_issue_notes: Edit notes +permission_manage_news: Manage news +permission_view_calendar: View calendrier +permission_manage_members: Manage members +permission_edit_messages: Edit messages +permission_delete_issues: Delete issues +permission_view_issue_watchers: View watchers list +permission_manage_repository: Manage repository +permission_commit_access: Commit access +permission_browse_repository: Browse repository +permission_view_documents: View documents +permission_edit_project: Edit project +permission_add_issue_notes: Add notes +permission_save_queries: Save queries +permission_view_wiki_pages: View wiki +permission_rename_wiki_pages: Rename wiki pages +permission_edit_time_entries: Edit time logs +permission_edit_own_issue_notes: Edit own notes +setting_gravatar_enabled: Use Gravatar user icons +label_example: Example +text_repository_usernames_mapping: "Select ou update the Redmine user mapped to each username found in the repository log.\nUsers with the same Redmine and repository username or email are automatically mapped." +permission_edit_own_messages: Edit own messages +permission_delete_own_messages: Delete own messages +label_user_activity: "%s's activity" +label_updated_time_by: Updated by %s %s ago +text_diff_truncated: '... This diff was truncated because it exceeds the maximum size that can be displayed.' +setting_diff_max_lines_displayed: Max number of diff lines displayed +text_plugin_assets_writable: Plugin assets directory writable +warning_attachments_not_saved: "%d file(s) could not be saved." +button_create_and_continue: Create and continue +text_custom_field_possible_values_info: 'One line for each value' +label_display: Display +field_editable: Editable +setting_repository_log_display_limit: Maximum number of revisions displayed on file log +field_identity_url: OpenID URL +setting_openid: Allow OpenID login and registration +label_login_with_open_id_option: or login with OpenID +field_watcher: Watcher diff --git a/lang/cs.yml b/lang/cs.yml index 29babd3a9..bbfdfae4d 100644 --- a/lang/cs.yml +++ b/lang/cs.yml @@ -645,5 +645,70 @@ setting_sequential_project_identifiers: Generate sequential project identifiers notice_unable_delete_version: Unable to delete version label_renamed: renamed label_copied: copied -setting_repositories_cache_directory: Cache directory for repositories -field_cache: Local cache +setting_plain_text_mail: plain text only (no HTML) +permission_view_files: View files +permission_edit_issues: Edit issues +permission_edit_own_time_entries: Edit own time logs +permission_manage_public_queries: Manage public queries +permission_add_issues: Add issues +permission_log_time: Log spent time +permission_view_changesets: View changesets +permission_view_time_entries: View spent time +permission_manage_versions: Manage versions +permission_manage_wiki: Manage wiki +permission_manage_categories: Manage issue categories +permission_protect_wiki_pages: Protect wiki pages +permission_comment_news: Comment news +permission_delete_messages: Delete messages +permission_select_project_modules: Select project modules +permission_manage_documents: Manage documents +permission_edit_wiki_pages: Edit wiki pages +permission_add_issue_watchers: Add watchers +permission_view_gantt: View gantt chart +permission_move_issues: Move issues +permission_manage_issue_relations: Manage issue relations +permission_delete_wiki_pages: Delete wiki pages +permission_manage_boards: Manage boards +permission_delete_wiki_pages_attachments: Delete attachments +permission_view_wiki_edits: View wiki history +permission_add_messages: Post messages +permission_view_messages: View messages +permission_manage_files: Manage files +permission_edit_issue_notes: Edit notes +permission_manage_news: Manage news +permission_view_calendar: View calendrier +permission_manage_members: Manage members +permission_edit_messages: Edit messages +permission_delete_issues: Delete issues +permission_view_issue_watchers: View watchers list +permission_manage_repository: Manage repository +permission_commit_access: Commit access +permission_browse_repository: Browse repository +permission_view_documents: View documents +permission_edit_project: Edit project +permission_add_issue_notes: Add notes +permission_save_queries: Save queries +permission_view_wiki_pages: View wiki +permission_rename_wiki_pages: Rename wiki pages +permission_edit_time_entries: Edit time logs +permission_edit_own_issue_notes: Edit own notes +setting_gravatar_enabled: Use Gravatar user icons +label_example: Example +text_repository_usernames_mapping: "Select ou update the Redmine user mapped to each username found in the repository log.\nUsers with the same Redmine and repository username or email are automatically mapped." +permission_edit_own_messages: Edit own messages +permission_delete_own_messages: Delete own messages +label_user_activity: "%s's activity" +label_updated_time_by: Updated by %s %s ago +text_diff_truncated: '... This diff was truncated because it exceeds the maximum size that can be displayed.' +setting_diff_max_lines_displayed: Max number of diff lines displayed +text_plugin_assets_writable: Plugin assets directory writable +warning_attachments_not_saved: "%d file(s) could not be saved." +button_create_and_continue: Create and continue +text_custom_field_possible_values_info: 'One line for each value' +label_display: Display +field_editable: Editable +setting_repository_log_display_limit: Maximum number of revisions displayed on file log +field_identity_url: OpenID URL +setting_openid: Allow OpenID login and registration +label_login_with_open_id_option: or login with OpenID +field_watcher: Watcher diff --git a/lang/da.yml b/lang/da.yml index 92f5501a2..c07d6be88 100644 --- a/lang/da.yml +++ b/lang/da.yml @@ -30,62 +30,58 @@ activerecord_error_too_long: er for lang activerecord_error_too_short: er for kort activerecord_error_wrong_length: har den forkerte længde activerecord_error_taken: er allerede valgt -activerecord_error_not_a_number: er ikke et tal +activerecord_error_not_a_number: er ikke et nummer activerecord_error_not_a_date: er en ugyldig dato activerecord_error_greater_than_start_date: skal være senere end startdatoen -activerecord_error_not_same_project: hører ikke til samme projekt -activerecord_error_circular_dependency: Denne relation vil skabe en cirkulær afhængighed +activerecord_error_not_same_project: høre ikke til samme projekt +activerecord_error_circular_dependency: Denne relation vil skabe et afhængighedsforhold general_fmt_age: %d år general_fmt_age_plural: %d år -general_fmt_date: %%m/%%d/%%Y -general_fmt_datetime: %%m/%%d/%%Y %%I:%%M %%p -general_fmt_datetime_short: %%b %%d, %%I:%%M %%p -general_fmt_time: %%I:%%M %%p +general_fmt_date: %%d/%%m/%%Y +general_fmt_datetime: %%d/%%m/%%Y %%H:%%M +general_fmt_datetime_short: %%b %%d, %%H:%%M +general_fmt_time: %%H:%%M general_text_No: 'Nej' general_text_Yes: 'Ja' general_text_no: 'nej' general_text_yes: 'ja' -general_lang_name: 'Dansk' +general_lang_name: 'Danish (Dansk)' general_csv_separator: ',' -general_csv_decimal_separator: '.' general_csv_encoding: ISO-8859-1 general_pdf_encoding: ISO-8859-1 general_day_names: Mandag,Tirsdag,Onsdag,Torsdag,Fredag,Lørdag,Søndag general_first_day_of_week: '1' notice_account_updated: Kontoen er opdateret. -notice_account_invalid_creditentials: Forkert brugernavn eller kodeord +notice_account_invalid_creditentials: Ugyldig bruger og kodeord notice_account_password_updated: Kodeordet er opdateret. notice_account_wrong_password: Forkert kodeord -notice_account_register_done: Kontoen er oprettet. For at aktivere kontoen, skal du klikke på linket i den tilsendte e-mail. -notice_account_unknown_email: Ukendt brugernavn. +notice_account_register_done: Kontoen er oprettet. For at aktivere kontoen skal du klikke på linket i den tilsendte email. +notice_account_unknown_email: Ukendt bruger. notice_can_t_change_password: Denne konto benytter en ekstern sikkerhedsgodkendelse. Det er ikke muligt at skifte kodeord. -notice_account_lost_email_sent: En e-mail med instruktioner til at vælge et nyt kodeord er afsendt til dig. +notice_account_lost_email_sent: En email med instruktioner til at vælge et nyt kodeord er afsendt til dig. notice_account_activated: Din konto er aktiveret. Du kan nu logge ind. -notice_successful_create: Oprettelse lykkedes. -notice_successful_update: Opdatering lykkedes. -notice_successful_delete: Sletning lykkedes. +notice_successful_create: Succesfuld oprettelse. +notice_successful_update: Succesfuld opdatering. +notice_successful_delete: Succesfuld sletning. notice_successful_connection: Succesfuld forbindelse. -notice_file_not_found: Siden, du forsøger at tilgå, eksisterer ikke eller er blevet fjernet. +notice_file_not_found: Siden du forsøger at tilgå, eksisterer ikke eller er blevet fjernet. notice_locking_conflict: Data er opdateret af en anden bruger. notice_not_authorized: Du har ikke adgang til denne side. -notice_email_sent: En e-mail er sendt til %s -notice_email_error: En fejl opstod under afsendelse af e-mail (%s) -notice_feeds_access_key_reseted: Din RSS-adgangsnøgle er nulstillet. +notice_email_sent: En email er sendt til %s +notice_email_error: En fejl opstod under afsendelse af email (%s) +notice_feeds_access_key_reseted: Din adgangsnøgle til RSS er nulstillet. notice_failed_to_save_issues: "Det mislykkedes at gemme %d sage(r) på %d valgt: %s." -notice_no_issue_selected: "Ingen sag er valgt! Vælg venligst, hvilke emner du vil rette." -notice_account_pending: "Din konto er oprettet og afventer administratorens godkendelse." -notice_default_data_loaded: Standardkonfiguration er indlæst. -notice_unable_delete_version: Kan ikke slette version +notice_no_issue_selected: "Ingen sag er valgt! Vælg venligst hvilke emner du vil rette." +notice_account_pending: "Din konto er oprettet, og afventer administrators godkendelse." +notice_default_data_loaded: Standardopsætningen er indlæst. -error_can_t_load_default_data: "Standardkonfiguration kunne ikke indlæses: %s" -error_scm_not_found: "Fil og/eller revision blev ikke fundet i det valgte filarkiv." -error_scm_command_failed: "En fejl opstod under forbindelsen til det valgte filarkiv: %s" -error_scm_annotate: "Filen findes ikke eller kan ikke annoteres." -error_issue_not_found_in_project: 'Sagen blev ikke fundet eller tilhører ikke dette projekt' +error_can_t_load_default_data: "Standardopsætning kunne ikke indlæses: %s" +error_scm_not_found: "Adgang og/eller revision blev ikke fundet i det valgte repository." +error_scm_command_failed: "En fejl opstod under fobindelsen til det valgte repository: %s" -mail_subject_lost_password: Dit kodeord til %s +mail_subject_lost_password: Dit %s kodeord mail_body_lost_password: 'For at ændre dit kodeord, klik på dette link:' mail_subject_register: %s kontoaktivering mail_body_register: 'For at aktivere din konto, klik på dette link:' @@ -93,31 +89,29 @@ mail_body_account_information_external: Du kan bruge din "%s" konto til at logge mail_body_account_information: Din kontoinformation mail_subject_account_activation_request: %s kontoaktivering mail_body_account_activation_request: 'En ny bruger (%s) er registreret. Godkend venligst kontoen:' -mail_subject_reminder: "%d sag(er) har snart deadline" -mail_body_reminder: "%d sag(er) der er tildelt dig har deadline i løbet af de kommende %d dage:" gui_validation_error: 1 fejl gui_validation_error_plural: %d fejl field_name: Navn field_description: Beskrivelse -field_summary: Oversigt +field_summary: Sammenfatning field_is_required: Skal udfyldes field_firstname: Fornavn field_lastname: Efternavn -field_mail: E-mail +field_mail: Email field_filename: Fil field_filesize: Størrelse field_downloads: Downloads -field_author: Opretter +field_author: Forfatter field_created_on: Oprettet field_updated_on: Opdateret field_field_format: Format field_is_for_all: For alle projekter field_possible_values: Mulige værdier field_regexp: Regulære udtryk -field_min_length: Minimum længde -field_max_length: Maksimal længde +field_min_length: Mindste længde +field_max_length: Største længde field_value: Værdi field_category: Kategori field_title: Titel @@ -132,18 +126,18 @@ field_subject: Emne field_due_date: Deadline field_assigned_to: Tildelt til field_priority: Prioritet -field_fixed_version: Planlagt version +field_fixed_version: Target version field_user: Bruger field_role: Rolle field_homepage: Hjemmeside field_is_public: Offentlig field_parent: Underprojekt af -field_is_in_chlog: Sager vist i ændringslog -field_is_in_roadmap: Sager vist i plan -field_login: Brugernavn -field_mail_notification: E-mail-notifikationer +field_is_in_chlog: Sager vist i ændringer +field_is_in_roadmap: Sager vist i roadmap +field_login: Login +field_mail_notification: Email-påmindelser field_admin: Administrator -field_last_login_on: Sidst logget ind +field_last_login_on: Sidste forbindelse field_language: Sprog field_effective_date: Dato field_password: Kodeord @@ -154,16 +148,16 @@ field_type: Type field_host: Vært field_port: Port field_account: Kode -field_base_dn: Base-DN -field_attr_login: Attribut for brugernavn -field_attr_firstname: Attribut for fornavn -field_attr_lastname: Attribut for efternavn -field_attr_mail: Attribut for e-mail -field_onthefly: Løbende brugeroprettelse +field_base_dn: Base DN +field_attr_login: Login attribut +field_attr_firstname: Fornavn attribut +field_attr_lastname: Efternavn attribut +field_attr_mail: Email attribut +field_onthefly: løbende brugeroprettelse field_start_date: Start -field_done_ratio: %% færdig -field_auth_source: Godkendelsesmetode -field_hide_mail: Skjul min e-mail +field_done_ratio: %% Færdig +field_auth_source: Sikkerhedsmetode +field_hide_mail: Skjul min email field_comments: Kommentar field_url: URL field_start_page: Startside @@ -171,64 +165,54 @@ field_subproject: Underprojekt field_hours: Timer field_activity: Aktivitet field_spent_on: Dato -field_identifier: Identifikator +field_identifier: Identificering field_is_filter: Brugt som et filter -field_issue_to_id: Relateret sag +field_issue_to_id: Beslægtede sag field_delay: Udsættelse field_assignable: Sager kan tildeles denne rolle field_redirect_existing_links: Videresend eksisterende links -field_estimated_hours: Tidsestimat +field_estimated_hours: Anslået tid field_column_names: Kolonner field_time_zone: Tidszone field_searchable: Søgbar field_default_value: Standardværdi -field_comments_sorting: Vis kommentarer -field_parent_title: Forælderside -setting_app_title: Applikationens titel -setting_app_subtitle: Applikationes undertitel +setting_app_title: Applikationstitel +setting_app_subtitle: Applikationsundertekst setting_welcome_text: Velkomsttekst -setting_default_language: Standardsprog -setting_login_required: Indlogning påkrævet +setting_default_language: Standardsporg +setting_login_required: Sikkerhed påkrævet setting_self_registration: Brugeroprettelse -setting_attachment_max_size: Maks. størrelse for vedhæftede filer -setting_issues_export_limit: Maks. antal sager i eksport -setting_mail_from: Afsender-e-mail -setting_bcc_recipients: Blindkopimodtager (bcc) -setting_host_name: Værtsnavn +setting_attachment_max_size: Vedhæftede filers max størrelse +setting_issues_export_limit: Sagseksporteringsbegrænsning +setting_mail_from: Afsender-email +setting_bcc_recipients: Skjult modtager (bcc) +setting_host_name: Værts navn setting_text_formatting: Tekstformatering -setting_wiki_compression: Komprimer wiki-historik -setting_feeds_limit: Antal objekter i feeds -setting_default_projects_public: Nye projekter er som standard offentlige -setting_autofetch_changesets: Hent automatisk commits -setting_sys_api_enabled: Aktiver webservice til versionsstyring -setting_commit_ref_keywords: Nøgleord for sagsreferencer -setting_commit_fix_keywords: Nøgleord for lukning af sager +setting_wiki_compression: Wiki historikkomprimering +setting_feeds_limit: Feed indholdsbegrænsning +setting_autofetch_changesets: Automatisk hent commits +setting_sys_api_enabled: Aktiver webservice for automatisk administration af repository +setting_commit_ref_keywords: Referencenøgleord +setting_commit_fix_keywords: Afslutningsnøgleord setting_autologin: Autologin setting_date_format: Datoformat setting_time_format: Tidsformat setting_cross_project_issue_relations: Tillad sagsrelationer på tværs af projekter setting_issue_list_default_columns: Standardkolonner på sagslisten -setting_repositories_encodings: Filarkivtegnsæt -setting_commit_logs_encoding: Tegnsæt for commitbeskeder -setting_emails_footer: Sidefod i e-mail +setting_repositories_encodings: Repository-tegnsæt +setting_emails_footer: Email-fodnote setting_protocol: Protokol -setting_per_page_options: Valgmuligheder for antal objekter pr. side +setting_per_page_options: Objekter pr. side-indstillinger setting_user_format: Brugervisningsformat -setting_activity_days_default: Antal dage der vises under projektaktivitet -setting_display_subprojects_issues: Vis som standard sager for underprojekter på hovedprojektet -setting_enabled_scm: Aktiveret versionsstyring -setting_mail_handler_api_enabled: Aktiver redigering af sager via mail -setting_mail_handler_api_key: API-nøgle -setting_sequential_project_identifiers: Generer fortløbende identifikatorer project_module_issue_tracking: Sagssøgning -project_module_time_tracking: Tidsregistrering +project_module_time_tracking: Tidsstyring project_module_news: Nyheder project_module_documents: Dokumenter project_module_files: Filer project_module_wiki: Wiki -project_module_repository: Versionsstyring +project_module_repository: Repository project_module_boards: Opslagstavle label_user: Bruger @@ -240,16 +224,16 @@ label_project_plural: Projekter label_project_all: Alle projekter label_project_latest: Seneste projekter label_issue: Sag -label_issue_new: Ny sag +label_issue_new: Opret sag label_issue_plural: Sager label_issue_view_all: Vis alle sager label_issues_by: Sager fra %s -label_issue_added: Sag oprettet -label_issue_updated: Sag opdateret +label_issue_added: Sagen er oprettet +label_issue_updated: Sagen er opdateret label_document: Dokument label_document_new: Nyt dokument label_document_plural: Dokumenter -label_document_added: Dokument oprettet +label_document_added: Dokument tilføjet label_role: Rolle label_role_plural: Roller label_role_new: Ny rolle @@ -261,20 +245,20 @@ label_tracker: Type label_tracker_plural: Typer label_tracker_new: Ny type label_workflow: Arbejdsgang -label_issue_status: Statuskode -label_issue_status_plural: Statuskoder -label_issue_status_new: Ny statuskode +label_issue_status: Sagsstatus +label_issue_status_plural: Sagsstatuser +label_issue_status_new: Ny status label_issue_category: Sagskategori label_issue_category_plural: Sagskategorier label_issue_category_new: Ny kategori label_custom_field: Brugerdefineret felt -label_custom_field_plural: Brugerdefinerede felter +label_custom_field_plural: Brugerdefineret felt label_custom_field_new: Nyt brugerdefineret felt label_enumerations: Værdier label_enumeration_new: Ny værdi label_information: Information label_information_plural: Information -label_please_login: Log venligst ind +label_please_login: Login label_register: Registrer label_password_lost: Glemt kodeord label_home: Forside @@ -286,23 +270,21 @@ label_login: Log ind label_logout: Log ud label_help: Hjælp label_reported_issues: Rapporterede sager -label_assigned_to_me_issues: Sager tildelt mig -label_last_login: Sidste indlogning +label_assigned_to_me_issues: Sager tildelt til mig +label_last_login: Sidste forbindelse label_last_updates: Sidst opdateret label_last_updates_plural: %d sidst opdateret -label_registered_on: Oprettet den +label_registered_on: Registeret den label_activity: Aktivitet -label_overall_activity: Al aktivitet label_new: Ny -label_logged_as: Logget ind som +label_logged_as: Registreret som label_environment: Miljø -label_authentication: Godkendelse -label_auth_source: Godkendelsesmetode -label_auth_source_new: Ny godkendelsemetode -label_auth_source_plural: Godkendelsesmetoder +label_authentication: Sikkerhed +label_auth_source: Sikkerhedsmetode +label_auth_source_new: Ny sikkerhedsmetode +label_auth_source_plural: Sikkerhedsmetoder label_subproject_plural: Underprojekter -label_and_its_subprojects: Projektet %s og dets underprojekter -label_min_max_length: Min.-maks.-længde +label_min_max_length: Min - Max længde label_list: Liste label_date: Dato label_integer: Heltal @@ -312,8 +294,8 @@ label_string: Tekst label_text: Lang tekst label_attribute: Attribut label_attribute_plural: Attributter -label_download: %d download -label_download_plural: %d downloads +label_download: %d Download +label_download_plural: %d Downloads label_no_data: Ingen data at vise label_change_status: Ændringsstatus label_history: Historik @@ -321,22 +303,22 @@ label_attachment: Fil label_attachment_new: Ny fil label_attachment_delete: Slet fil label_attachment_plural: Filer -label_file_added: Fil oprettet +label_file_added: Fil tilføjet label_report: Rapport label_report_plural: Rapporter label_news: Nyheder -label_news_new: Ny nyhed +label_news_new: Tilføj nyheder label_news_plural: Nyheder label_news_latest: Seneste nyheder label_news_view_all: Vis alle nyheder -label_news_added: Nyhed oprettet +label_news_added: Nyhed tilføjet label_change_log: Ændringer label_settings: Indstillinger label_overview: Oversigt label_version: Version label_version_new: Ny version label_version_plural: Versioner -label_confirmation: Bekræftelser +label_confirmation: Bekræftigelser label_export_to: Eksporter til label_read: Læs... label_public_projects: Offentlige projekter @@ -347,15 +329,15 @@ label_closed_issues_plural: lukkede label_total: Total label_permissions: Rettigheder label_current_status: Nuværende status -label_new_statuses_allowed: Tilladte nye statuskoder +label_new_statuses_allowed: Ny status tilladt label_all: alle label_none: intet label_nobody: ingen label_next: Næste -label_previous: Forrige +label_previous: Forrig label_used_by: Brugt af label_details: Detaljer -label_add_note: Ny note +label_add_note: Tilføj en note label_per_page: Pr. side label_calendar: Kalender label_months_from: måneder frem @@ -367,11 +349,11 @@ label_personalize_page: Tilret denne side label_comment: Kommentar label_comment_plural: Kommentarer label_comment_add: Tilføj en kommentar -label_comment_added: Kommentar tilføjet +label_comment_added: Kommentaren er tilføjet label_comment_delete: Slet kommentar -label_query: Brugerdefineret søgning -label_query_plural: Brugerdefinerede søgning -label_query_new: Ny søgning +label_query: Brugerdefineret forespørgsel +label_query_plural: Brugerdefinerede forespørgsler +label_query_new: Ny forespørgsel label_filter_add: Tilføj filter label_filter_plural: Filtre label_equals: er @@ -388,25 +370,23 @@ label_last_n_days: sidste %d dage label_this_month: denne måned label_last_month: sidste måned label_this_year: dette år -label_date_range: Datointerval +label_date_range: Dato interval label_less_than_ago: mindre end dage siden label_more_than_ago: mere end dage siden label_ago: days siden label_contains: indeholder -label_not_contains: indeholder ikke +label_not_contains: ikke indeholder label_day_plural: dage -label_repository: Versionsstyring -label_repository_plural: Versionsstyring +label_repository: Repository +label_repository_plural: Repositories label_browse: Gennemse label_modification: %d ændring label_modification_plural: %d ændringer label_revision: Revision label_revision_plural: Revisioner label_associated_revisions: Tilnyttede revisioner -label_added: oprettet +label_added: tilføjet label_modified: ændret -label_copied: kopieret -label_renamed: omdøbt label_deleted: slettet label_latest_revision: Seneste revision label_latest_revision_plural: Seneste revisioner @@ -417,48 +397,47 @@ label_sort_highest: Flyt til toppen label_sort_higher: Flyt op label_sort_lower: Flyt ned label_sort_lowest: Flyt til bunden -label_roadmap: Plan -label_roadmap_due_in: Deadline %s +label_roadmap: Roadmap +label_roadmap_due_in: Deadline label_roadmap_overdue: %s forsinket -label_roadmap_no_issues: Ingen sager i denne version +label_roadmap_no_issues: Ingen sager til denne version label_search: Søg label_result_plural: Resultater label_all_words: Alle ord label_wiki: Wiki -label_wiki_edit: Wikiændring -label_wiki_edit_plural: Wikiændringer -label_wiki_page: Wikiside -label_wiki_page_plural: Wikisider +label_wiki_edit: Wiki ændring +label_wiki_edit_plural: Wiki ændringer +label_wiki_page: Wiki side +label_wiki_page_plural: Wiki sider label_index_by_title: Indhold efter titel label_index_by_date: Indhold efter dato label_current_version: Nuværende version label_preview: Forhåndsvisning label_feed_plural: Feeds -label_changes_details: Detaljer for alle ændringer -label_issue_tracking: Sagsstyring -label_spent_time: Tidsforbrug +label_changes_details: Detaljer for alle ænringer +label_issue_tracking: Sags søgning +label_spent_time: Brugt tid label_f_hour: %.2f time label_f_hour_plural: %.2f timer -label_time_tracking: Tidsregistrering +label_time_tracking: Tidsstyring label_change_plural: Ændringer label_statistics: Statistik label_commits_per_month: Commits pr. måned label_commits_per_author: Commits pr. bruger -label_view_diff: Vis ændringer +label_view_diff: Vis forskellighed label_diff_inline: inline label_diff_side_by_side: side om side label_options: Optioner label_copy_workflow_from: Kopier arbejdsgang fra -label_permissions_report: Rettighedsoversigt +label_permissions_report: Godkendelsesrapport label_watched_issues: Overvågede sager label_related_issues: Relaterede sager -label_applied_status: Tildelt status +label_applied_status: Anvendte statuser label_loading: Indlæser... label_relation_new: Ny relation label_relation_delete: Slet relation -label_relates_to: er relateret til -label_duplicates: dublerer -label_duplicated_by: dubleret af +label_relates_to: relaterer til +label_duplicates: kopierer label_blocks: blokerer label_blocked_by: blokeret af label_precedes: kommer før @@ -476,11 +455,11 @@ label_board_new: Nyt forum label_board_plural: Fora label_topic_plural: Emner label_message_plural: Beskeder -label_message_last: Seneste besked +label_message_last: Sidste besked label_message_new: Ny besked -label_message_posted: Besked oprettet +label_message_posted: Besked tilføjet label_reply_plural: Besvarer -label_send_information: Send kontoinformation til bruger +label_send_information: Send konto information til bruger label_year: År label_month: Måned label_week: Uge @@ -488,57 +467,48 @@ label_date_from: Fra label_date_to: Til label_language_based: Baseret på brugerens sprog label_sort_by: Sorter efter %s -label_send_test_email: Send en testmail -label_feeds_access_key_created_on: RSS-adgangsnøgle genereret for %s siden +label_send_test_email: Send en test email +label_feeds_access_key_created_on: RSS adgangsnøgle danet for %s siden label_module_plural: Moduler -label_added_time_by: Oprettet af %s for %s siden +label_added_time_by: Tilføjet af %s for %s siden label_updated_time: Opdateret for %s siden label_jump_to_a_project: Skift til projekt... label_file_plural: Filer label_changeset_plural: Ændringer -label_default_columns: Standardkolonner +label_default_columns: Standard kolonner label_no_change_option: (Ingen ændringer) label_bulk_edit_selected_issues: Masseret de valgte sager label_theme: Tema label_default: standard label_search_titles_only: Søg kun i titler label_user_mail_option_all: "For alle hændelser på mine projekter" -label_user_mail_option_selected: "For alle hændelser på udvalgte projekter..." -label_user_mail_option_none: "Kun for ting jeg overvåger eller er involveret i" -label_user_mail_no_self_notified: "Jeg ønsker ikke at blive notificeret om ændringer foretaget af mig selv" -label_registration_activation_by_email: kontoaktivering på e-mail +label_user_mail_option_selected: "For alle hændelser, kun på de valgte projekter..." +label_user_mail_option_none: "Kun for ting jeg overvåger, eller jeg er involveret i" +label_user_mail_no_self_notified: "Jeg ønsker ikke besked, om ændring foretaget af mig selv" +label_registration_activation_by_email: kontoaktivering på email label_registration_manual_activation: manuel kontoaktivering label_registration_automatic_activation: automatisk kontoaktivering -label_display_per_page: 'Pr. side: %s' +label_display_per_page: 'Per side: %s' label_age: Alder label_change_properties: Ændre indstillinger -label_general: Generelt +label_general: Generalt label_more: Mere -label_scm: Versionsstyring +label_scm: SCM label_plugins: Plugins label_ldap_authentication: LDAP-godkendelse label_downloads_abbr: D/L -label_add_another_file: Opret endnu en fil -label_optional_description: Valgfri beskrivelse -label_preferences: Indstillinger -label_chronological_order: I kronologisk rækkefølge -label_reverse_chronological_order: I omvendt kronologisk rækkefølge -label_planning: Planlægning -label_incoming_emails: Indkommende e-mails -label_generate_key: Generer en nøgle -label_issue_watchers: Overvågere -button_login: Log ind +button_login: Login button_submit: Send button_save: Gem -button_check_all: Vælg alle -button_uncheck_all: Fravælg alle +button_check_all: Vælg alt +button_uncheck_all: Fravælg alt button_delete: Slet button_create: Opret button_test: Test button_edit: Ret -button_add: Opret -button_change: Skift +button_add: Tilføj +button_change: Ændre button_apply: Anvend button_clear: Nulstil button_lock: Lås @@ -551,8 +521,8 @@ button_back: Tilbage button_cancel: Annuller button_activate: Aktiver button_sort: Sorter -button_log_time: Registrer tid -button_rollback: Rul tilbage til denne version +button_log_time: Log tid +button_rollback: Tilbagefør til denne version button_watch: Overvåg button_unwatch: Stop overvågning button_reply: Besvar @@ -565,56 +535,46 @@ button_copy: Kopier button_annotate: Annotere button_update: Opdater button_configure: Konfigurer -button_quote: Citer status_active: aktiv status_registered: registreret status_locked: låst -text_select_mail_notifications: Vælg handlinger for hvilke, der skal sendes en e-mail-notifikation. +text_select_mail_notifications: Vælg handlinger der skal sendes email besked for. text_regexp_info: f.eks. ^[A-ZÆØÅ0-9]+$ text_min_max_length_info: 0 betyder ingen begrænsninger -text_project_destroy_confirmation: Er du sikker på, at du vil slette dette projekt og alle relaterede data ? -text_subprojects_destroy_warning: 'Dets underprojekt(er): %s vil også blive slettet.' +text_project_destroy_confirmation: Er du sikker på at du vil slette dette projekt og alle relaterede data? text_workflow_edit: Vælg en rolle samt en type for at redigere arbejdsgangen text_are_you_sure: Er du sikker? text_journal_changed: ændret fra %s til %s text_journal_set_to: sat til %s text_journal_deleted: slettet text_tip_task_begin_day: opgaven begynder denne dag -text_tip_task_end_day: opgaven slutter denne dag +text_tip_task_end_day: opaven slutter denne dag text_tip_task_begin_end_day: opgaven begynder og slutter denne dag -text_project_identifier_info: 'Små bogstaver (a-z), numre og bindestreg er tilladt.
    Når den er gemt, kan identifikatoren ikke rettes.' -text_caracters_maximum: maks. %d tegn. -text_caracters_minimum: Skal være mindst %d tegn lang. -text_length_between: Længde skal være mellem %d og %d tegn. +text_project_identifier_info: 'Små bogstaver (a-z), numre og bindestreg er tilladt.
    Når den er gemt, kan indifikatoren ikke rettes.' +text_caracters_maximum: max %d karakterer. +text_caracters_minimum: Skal være mindst %d karakterer lang. +text_length_between: Længde skal være mellem %d og %d karakterer. text_tracker_no_workflow: Ingen arbejdsgang defineret for denne type -text_unallowed_characters: Ugyldige tegn -text_comma_separated: Flere værdier tilladt (adskilt af komma). -text_issues_ref_in_commit_messages: Referer og luk sager i commitbeskeder +text_unallowed_characters: Ikke tilladte karakterer +text_comma_separated: Adskillige værdier tilladt (adskilt med komma). +text_issues_ref_in_commit_messages: Referer og løser sager i commit-beskeder text_issue_added: Sag %s er rapporteret af %s. text_issue_updated: Sag %s er blevet opdateret af %s. -text_wiki_destroy_confirmation: Er du sikker på, at du vil slette denne wiki og alt dens indhold? +text_wiki_destroy_confirmation: Er du sikker på at du vil slette denne wiki og dens indhold? text_issue_category_destroy_question: Nogle sager (%d) er tildelt denne kategori. Hvad ønsker du at gøre? -text_issue_category_destroy_assignments: Slet kategoritildelinger +text_issue_category_destroy_assignments: Slet tildelinger af kategori text_issue_category_reassign_to: Tildel sager til denne kategori -text_user_mail_option: "For ikke-valgte projekter vil du kun modtage notifikationer omhandlende ting, du er involveret i eller overvåger (f.eks. sager du har oprettet eller er tildelt)." -text_no_configuration_data: "Roller, typer, statuskoder og arbejdsgange er endnu ikke konfigureret.\nDet er anbefalet at indlæse standardkonfigurationen. Du vil kunne ændre denne, når den er indlæst." -text_load_default_configuration: Indlæs standardkonfiguration +text_user_mail_option: "For ikke-valgte projekter vil du kun modtage beskeder omhandlende ting du er involveret i eller overvåger (f.eks. sager du ha indberettet eller ejer)." +text_no_configuration_data: "Roller, typer, sagsstatuser og arbejdsgange er endnu ikke konfigureret.\nDet er anbefalet at indlæse standardopsætningen. Du vil kunne ændre denne når den er indlæst." +text_load_default_configuration: Indlæs standardopsætningen text_status_changed_by_changeset: Anvendt i ændring %s. -text_issues_destroy_confirmation: 'Er du sikker på, du ønsker at slette den/de valgte sag(er) ?' -text_select_project_modules: 'Vælg moduler, der skal være aktiveret for dette projekt:' -text_default_administrator_account_changed: Standardadministratorkonto ændret -text_file_repository_writable: Filarkiv er skrivbart +text_issues_destroy_confirmation: 'Er du sikker på du ønsker at slette den/de valgte sag(er)?' +text_select_project_modules: 'Vælg moduler er skal være aktiveret for dette projekt:' +text_default_administrator_account_changed: Standard administratorkonto ændret +text_file_repository_writable: Filarkiv er skrivbar text_rmagick_available: RMagick tilgængelig (valgfri) -text_destroy_time_entries_question: %.02f timer er registreret på denne sag, som du er ved at slette. Hvad vil du gøre? -text_destroy_time_entries: Slet registrerede timer -text_assign_time_entries_to_project: Overfør registrerede timer til projektet -text_reassign_time_entries: 'Tilbagefør registrerede timer til denne sag igen:' -text_user_wrote: '%s skrev:' -text_enumeration_destroy_question: '%d objekter er tildelt denne værdi.' -text_enumeration_category_reassign_to: 'Tildel dem denne værdi:' -text_email_delivery_not_configured: "E-mail-afsendelse er ikke konfigureret, så notifikationer er deaktiverede.\nKonfigurer din SMTP-server i config/email.yml og genstart applikationen for at aktivere disse." default_role_manager: Leder default_role_developper: Udvikler @@ -633,13 +593,119 @@ default_doc_category_tech: Teknisk dokumentation default_priority_low: Lav default_priority_normal: Normal default_priority_high: Høj -default_priority_urgent: Haster -default_priority_immediate: Akut +default_priority_urgent: Akut +default_priority_immediate: Omgående default_activity_design: Design default_activity_development: Udvikling enumeration_issue_priorities: Sagsprioriteter enumeration_doc_categories: Dokumentkategorier -enumeration_activities: Aktiviteter (tidsregistrering) -setting_repositories_cache_directory: Cache directory for repositories -field_cache: Local cache +enumeration_activities: Aktiviteter (tidsstyring) + +label_add_another_file: Tilføj endnu en fil +label_chronological_order: I kronologisk rækkefølge +setting_activity_days_default: Antal dage der vises under projektaktivitet +text_destroy_time_entries_question: %.02f timer er reporteret på denne sag, som du er ved at slette. Hvad vil du gøre? +error_issue_not_found_in_project: 'Sagen blev ikke fundet eller tilhører ikke dette projekt' +text_assign_time_entries_to_project: Tildel raporterede timer til projektet +setting_display_subprojects_issues: Vis sager for underprojekter på hovedprojektet som standard +label_optional_description: Optionel beskrivelse +text_destroy_time_entries: Slet raportede timer +field_comments_sorting: Vis kommentar +text_reassign_time_entries: 'Tildel raportede timer til denne sag igen' +label_reverse_chronological_order: I omvendt kronologisk rækkefølge +label_preferences: Preferences +label_overall_activity: Overordnet aktivitet +setting_default_projects_public: Nye projekter er offentlige som standard +error_scm_annotate: "The entry does not exist or can not be annotated." +label_planning: Planlægning +text_subprojects_destroy_warning: 'Dets underprojekter(er): %s vil også blive slettet.' +permission_edit_issues: Edit issues +setting_diff_max_lines_displayed: Max number of diff lines displayed +permission_edit_own_issue_notes: Edit own notes +setting_enabled_scm: Enabled SCM +button_quote: Quote +permission_view_files: View files +permission_add_issues: Add issues +permission_edit_own_messages: Edit own messages +permission_delete_own_messages: Delete own messages +permission_manage_public_queries: Manage public queries +permission_log_time: Log spent time +label_renamed: renamed +label_incoming_emails: Incoming emails +permission_view_changesets: View changesets +permission_manage_versions: Manage versions +permission_view_time_entries: View spent time +label_generate_key: Generate a key +permission_manage_categories: Manage issue categories +permission_manage_wiki: Manage wiki +setting_sequential_project_identifiers: Generate sequential project identifiers +setting_plain_text_mail: Plain text mail (no HTML) +field_parent_title: Parent page +text_email_delivery_not_configured: "Email delivery is not configured, and notifications are disabled.\nConfigure your SMTP server in config/email.yml and restart the application to enable them." +permission_protect_wiki_pages: Protect wiki pages +permission_manage_documents: Manage documents +permission_add_issue_watchers: Add watchers +warning_attachments_not_saved: "%d file(s) could not be saved." +permission_comment_news: Comment news +text_enumeration_category_reassign_to: 'Reassign them to this value:' +permission_select_project_modules: Select project modules +permission_view_gantt: View gantt chart +permission_delete_messages: Delete messages +permission_move_issues: Move issues +permission_edit_wiki_pages: Edit wiki pages +label_user_activity: "%s's activity" +permission_manage_issue_relations: Manage issue relations +label_issue_watchers: Watchers +permission_delete_wiki_pages: Delete wiki pages +notice_unable_delete_version: Unable to delete version. +permission_view_wiki_edits: View wiki history +field_editable: Editable +mail_body_reminder: "%d issue(s) that are assigned to you are due in the next %d days:" +label_duplicated_by: duplicated by +permission_manage_boards: Manage boards +permission_delete_wiki_pages_attachments: Delete attachments +permission_view_messages: View messages +text_enumeration_destroy_question: '%d objects are assigned to this value.' +permission_manage_files: Manage files +permission_add_messages: Post messages +permission_edit_issue_notes: Edit notes +permission_manage_news: Manage news +text_plugin_assets_writable: Plugin assets directory writable +label_display: Display +label_and_its_subprojects: %s and its subprojects +permission_view_calendar: View calender +button_create_and_continue: Create and continue +setting_gravatar_enabled: Use Gravatar user icons +label_updated_time_by: Updated by %s %s ago +text_diff_truncated: '... This diff was truncated because it exceeds the maximum size that can be displayed.' +text_user_wrote: '%s wrote:' +setting_mail_handler_api_enabled: Enable WS for incoming emails +permission_delete_issues: Delete issues +permission_view_documents: View documents +permission_browse_repository: Browse repository +permission_manage_repository: Manage repository +permission_manage_members: Manage members +mail_subject_reminder: "%d issue(s) due in the next days" +permission_add_issue_notes: Add notes +permission_edit_messages: Edit messages +permission_view_issue_watchers: View watchers list +permission_commit_access: Commit access +setting_mail_handler_api_key: API key +label_example: Example +permission_rename_wiki_pages: Rename wiki pages +text_custom_field_possible_values_info: 'One line for each value' +permission_view_wiki_pages: View wiki +permission_edit_project: Edit project +permission_save_queries: Save queries +label_copied: copied +setting_commit_logs_encoding: Commit messages encoding +text_repository_usernames_mapping: "Select or update the Redmine user mapped to each username found in the repository log.\nUsers with the same Redmine and repository username or email are automatically mapped." +permission_edit_time_entries: Edit time logs +general_csv_decimal_separator: '.' +permission_edit_own_time_entries: Edit own time logs +setting_repository_log_display_limit: Maximum number of revisions displayed on file log +field_identity_url: OpenID URL +setting_openid: Allow OpenID login and registration +label_login_with_open_id_option: or login with OpenID +field_watcher: Watcher diff --git a/lang/de.yml b/lang/de.yml index dbbb1183d..366b7dd06 100644 --- a/lang/de.yml +++ b/lang/de.yml @@ -67,7 +67,7 @@ notice_successful_create: Erfolgreich angelegt notice_successful_update: Erfolgreich aktualisiert. notice_successful_delete: Erfolgreich gelöscht. notice_successful_connection: Verbindung erfolgreich. -notice_file_not_found: Anhang besteht nicht oder ist gelöscht worden. +notice_file_not_found: Anhang existiert nicht oder ist gelöscht worden. 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. @@ -80,11 +80,13 @@ notice_default_data_loaded: Die Standard-Konfiguration wurde erfolgreich geladen notice_unable_delete_version: Die Version konnte nicht gelöscht werden 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_not_found: Eintrag und/oder Revision existiert 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.' +warning_attachments_not_saved: "%d Datei(en) konnten nicht gespeichert werden." + mail_subject_lost_password: Ihr %s Kennwort mail_body_lost_password: 'Benutzen Sie den folgenden Link, um Ihr Kennwort zu ändern:' mail_subject_register: %s Kontoaktivierung @@ -195,6 +197,7 @@ setting_attachment_max_size: Max. Dateigröße setting_issues_export_limit: Max. Anzahl Tickets bei CSV/PDF-Export setting_mail_from: E-Mail-Absender setting_bcc_recipients: E-Mails als Blindkopie (BCC) senden +setting_plain_text_mail: Nur reinen Text (kein HTML) senden setting_host_name: Hostname setting_text_formatting: Textformatierung setting_wiki_compression: Wiki-Historie komprimieren @@ -210,7 +213,7 @@ setting_time_format: Zeitformat setting_cross_project_issue_relations: Ticket-Beziehungen zwischen Projekten erlauben setting_issue_list_default_columns: Default-Spalten in der Ticket-Auflistung setting_repositories_encodings: Kodierungen der Projektarchive -setting_commit_logs_encoding: Kodierung der Log-Meldungen +setting_commit_logs_encoding: Kodierung der Commit-Log-Meldungen setting_emails_footer: E-Mail-Fußzeile setting_protocol: Protokoll setting_per_page_options: Objekte pro Seite @@ -221,6 +224,57 @@ setting_enabled_scm: Aktivierte Versionskontrollsysteme setting_mail_handler_api_enabled: Abruf eingehender E-Mails aktivieren setting_mail_handler_api_key: API-Schlüssel setting_sequential_project_identifiers: Fortlaufende Projektkennungen generieren +setting_gravatar_enabled: Gravatar Benutzerbilder benutzen +setting_diff_max_lines_displayed: Maximale Anzahl anzuzeigender Diff-Zeilen + +permission_edit_project: Projekt bearbeiten +permission_select_project_modules: Projektmodule auswählen +permission_manage_members: Mitglieder verwalten +permission_manage_versions: Versionen verwalten +permission_manage_categories: Ticket-Kategorien verwalten +permission_add_issues: Tickets hinzufügen +permission_edit_issues: Tickets bearbeiten +permission_manage_issue_relations: Ticket-Beziehungen verwalten +permission_add_issue_notes: Kommentare hinzufügen +permission_edit_issue_notes: Kommentare bearbeiten +permission_edit_own_issue_notes: Eigene Kommentare bearbeiten +permission_move_issues: Tickets verschieben +permission_delete_issues: Tickets löschen +permission_manage_public_queries: Öffentliche Filter verwalten +permission_save_queries: Filter speichern +permission_view_gantt: Gantt-Diagramm ansehen +permission_view_calendar: Kalender ansehen +permission_view_issue_watchers: Liste der Beobachter ansehen +permission_add_issue_watchers: Beobachter hinzufügen +permission_log_time: Aufwände buchen +permission_view_time_entries: Gebuchte Aufwände ansehen +permission_edit_time_entries: Gebuchte Aufwände bearbeiten +permission_edit_own_time_entries: Selbst gebuchte Aufwände bearbeiten +permission_manage_news: News verwalten +permission_comment_news: News kommentieren +permission_manage_documents: Dokumente verwalten +permission_view_documents: Dokumente ansehen +permission_manage_files: Dateien verwalten +permission_view_files: Dateien ansehen +permission_manage_wiki: Wiki verwalten +permission_rename_wiki_pages: Wiki-Seiten umbenennen +permission_delete_wiki_pages: Wiki-Seiten löschen +permission_view_wiki_pages: Wiki ansehen +permission_view_wiki_edits: Wiki-Versionsgeschichte ansehen +permission_edit_wiki_pages: Wiki-Seiten bearbeiten +permission_delete_wiki_pages_attachments: Anhänge löschen +permission_protect_wiki_pages: Wiki-Seiten schützen +permission_manage_repository: Projektarchiv verwalten +permission_browse_repository: Projektarchiv ansehen +permission_view_changesets: Changesets ansehen +permission_commit_access: Commit-Zugriff (über WebDAV) +permission_manage_boards: Foren verwalten +permission_view_messages: Forenbeiträge ansehen +permission_add_messages: Forenbeiträge hinzufügen +permission_edit_messages: Forenbeiträge bearbeiten +permission_edit_own_messages: Eigene Forenbeiträge bearbeiten +permission_delete_messages: Forenbeiträge löschen +permission_delete_own_messages: Eigene Forenbeiträge löschen project_module_issue_tracking: Ticket-Verfolgung project_module_time_tracking: Zeiterfassung @@ -293,6 +347,7 @@ 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_user_activity: "Aktivität von %s" label_new: Neu label_logged_as: Angemeldet als label_environment: Environment @@ -359,7 +414,7 @@ label_add_note: Kommentar hinzufügen label_per_page: Pro Seite label_calendar: Kalender label_months_from: Monate ab -label_gantt: Gantt +label_gantt: Gantt-Diagramm label_internal: Intern label_last_changes: %d letzte Änderungen label_change_view_all: Alle Änderungen anzeigen @@ -418,7 +473,7 @@ label_sort_higher: Eins höher label_sort_lower: Eins tiefer label_sort_lowest: Ans Ende label_roadmap: Roadmap -label_roadmap_due_in: Fällig in +label_roadmap_due_in: Fällig in %s label_roadmap_overdue: %s verspätet label_roadmap_no_issues: Keine Tickets für diese Version label_search: Suche @@ -475,10 +530,10 @@ label_board: Forum label_board_new: Neues Forum label_board_plural: Foren label_topic_plural: Themen -label_message_plural: Nachrichten -label_message_last: Letzte Nachricht -label_message_new: Neue Nachricht -label_message_posted: Forums-Beitrag hinzugefügt +label_message_plural: Forenbeiträge +label_message_last: Letzter Forenbeitrag +label_message_new: Neues Thema +label_message_posted: Forenbeitrag hinzugefügt label_reply_plural: Antworten label_send_information: Sende Kontoinformationen zum Benutzer label_year: Jahr @@ -492,6 +547,7 @@ label_send_test_email: Test-E-Mail senden 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_by: Von %s vor %s aktualisiert label_updated_time: Vor %s aktualisiert label_jump_to_a_project: Zu einem Projekt springen... label_file_plural: Dateien @@ -527,6 +583,7 @@ label_planning: Terminplanung label_incoming_emails: Eingehende E-Mails label_generate_key: Generieren label_issue_watchers: Beobachter +label_example: Beispiel button_login: Anmelden button_submit: OK @@ -606,6 +663,7 @@ text_issues_destroy_confirmation: 'Sind Sie sicher, dass Sie die ausgewählten T text_select_project_modules: 'Bitte wählen Sie die Module aus, die in diesem Projekt aktiviert sein sollen:' text_default_administrator_account_changed: Administrator-Kennwort geändert text_file_repository_writable: Verzeichnis für Dateien beschreibbar +text_plugin_assets_writable: Verzeichnis für Plugin-Assets beschreibbar text_rmagick_available: RMagick verfügbar (optional) text_destroy_time_entries_question: Es wurden bereits %.02f Stunden auf dieses Ticket gebucht. Was soll mit den Aufwänden geschehen? text_destroy_time_entries: Gebuchte Aufwände löschen @@ -615,6 +673,8 @@ text_user_wrote: '%s schrieb:' text_enumeration_destroy_question: '%d Objekte sind diesem Wert zugeordnet.' text_enumeration_category_reassign_to: 'Die Objekte stattdessen diesem Wert zuordnen:' text_email_delivery_not_configured: "Der SMTP-Server ist nicht konfiguriert und Mailbenachrichtigungen sind ausgeschaltet.\nNehmen Sie die Einstellungen für Ihren SMTP-Server in config/email.yml vor und starten Sie die Applikation neu." +text_repository_usernames_mapping: "Bitte legen Sie die Zuordnung der Redmine-Benutzer zu den Benutzernamen der Commit-Log-Meldungen des Projektarchivs fest.\nBenutzer mit identischen Redmine- und Projektarchiv-Benutzernamen oder -E-Mail-Adressen werden automatisch zugeordnet." +text_diff_truncated: '... Dieser Diff wurde abgeschnitten, weil er die maximale Anzahl anzuzeigender Zeilen überschreitet.' default_role_manager: Manager default_role_developper: Entwickler @@ -641,5 +701,12 @@ default_activity_development: Entwicklung enumeration_issue_priorities: Ticket-Prioritäten enumeration_doc_categories: Dokumentenkategorien enumeration_activities: Aktivitäten (Zeiterfassung) -field_cache: Local cache -setting_repositories_cache_directory: Cache directory for repositories +field_editable: Editable +label_display: Display +button_create_and_continue: Create and continue +text_custom_field_possible_values_info: 'One line for each value' +setting_repository_log_display_limit: Maximum number of revisions displayed on file log +field_identity_url: OpenID URL +setting_openid: Allow OpenID login and registration +label_login_with_open_id_option: or login with OpenID +field_watcher: Watcher diff --git a/lang/en.yml b/lang/en.yml index 22543af26..f4f59df22 100644 --- a/lang/en.yml +++ b/lang/en.yml @@ -85,6 +85,8 @@ error_scm_command_failed: "An error occurred when trying to access the repositor error_scm_annotate: "The entry does not exist or can not be annotated." error_issue_not_found_in_project: 'The issue was not found or does not belong to this project' +warning_attachments_not_saved: "%d file(s) could not be saved." + mail_subject_lost_password: Your %s password mail_body_lost_password: 'To change your password, click on the following link:' mail_subject_register: Your %s account activation @@ -92,7 +94,7 @@ mail_body_register: 'To activate your account, click on the following link:' mail_body_account_information_external: You can use your "%s" account to log in. mail_body_account_information: Your account information mail_subject_account_activation_request: %s account activation request -mail_body_account_activation_request: 'A new user (%s) has registered. His account is pending your approval:' +mail_body_account_activation_request: 'A new user (%s) has registered. The account is pending your approval:' mail_subject_reminder: "%d issue(s) due in the next days" mail_body_reminder: "%d issue(s) that are assigned to you are due in the next %d days:" @@ -145,6 +147,7 @@ field_mail_notification: Email notifications field_admin: Administrator field_last_login_on: Last connection field_language: Language +field_identity_url: OpenID URL field_effective_date: Date field_password: Password field_new_password: New password @@ -184,7 +187,8 @@ field_searchable: Searchable field_default_value: Default value field_comments_sorting: Display comments field_parent_title: Parent page -field_cache: Local cache +field_editable: Editable +field_watcher: Watcher setting_app_title: Application title setting_app_subtitle: Application subtitle @@ -196,7 +200,8 @@ setting_attachment_max_size: Attachment max. size setting_issues_export_limit: Issues export limit setting_mail_from: Emission email address setting_bcc_recipients: Blind carbon copy recipients (bcc) -setting_host_name: Host name +setting_plain_text_mail: Plain text mail (no HTML) +setting_host_name: Host name and path setting_text_formatting: Text formatting setting_wiki_compression: Wiki history compression setting_feeds_limit: Feed content limit @@ -222,7 +227,59 @@ setting_enabled_scm: Enabled SCM setting_mail_handler_api_enabled: Enable WS for incoming emails setting_mail_handler_api_key: API key setting_sequential_project_identifiers: Generate sequential project identifiers -setting_repositories_cache_directory: Cache directory for repositories +setting_gravatar_enabled: Use Gravatar user icons +setting_diff_max_lines_displayed: Max number of diff lines displayed +setting_repository_log_display_limit: Maximum number of revisions displayed on file log +setting_openid: Allow OpenID login and registration + +permission_edit_project: Edit project +permission_select_project_modules: Select project modules +permission_manage_members: Manage members +permission_manage_versions: Manage versions +permission_manage_categories: Manage issue categories +permission_add_issues: Add issues +permission_edit_issues: Edit issues +permission_manage_issue_relations: Manage issue relations +permission_add_issue_notes: Add notes +permission_edit_issue_notes: Edit notes +permission_edit_own_issue_notes: Edit own notes +permission_move_issues: Move issues +permission_delete_issues: Delete issues +permission_manage_public_queries: Manage public queries +permission_save_queries: Save queries +permission_view_gantt: View gantt chart +permission_view_calendar: View calender +permission_view_issue_watchers: View watchers list +permission_add_issue_watchers: Add watchers +permission_log_time: Log spent time +permission_view_time_entries: View spent time +permission_edit_time_entries: Edit time logs +permission_edit_own_time_entries: Edit own time logs +permission_manage_news: Manage news +permission_comment_news: Comment news +permission_manage_documents: Manage documents +permission_view_documents: View documents +permission_manage_files: Manage files +permission_view_files: View files +permission_manage_wiki: Manage wiki +permission_rename_wiki_pages: Rename wiki pages +permission_delete_wiki_pages: Delete wiki pages +permission_view_wiki_pages: View wiki +permission_view_wiki_edits: View wiki history +permission_edit_wiki_pages: Edit wiki pages +permission_delete_wiki_pages_attachments: Delete attachments +permission_protect_wiki_pages: Protect wiki pages +permission_manage_repository: Manage repository +permission_browse_repository: Browse repository +permission_view_changesets: View changesets +permission_commit_access: Commit access +permission_manage_boards: Manage boards +permission_view_messages: View messages +permission_add_messages: Post messages +permission_edit_messages: Edit messages +permission_edit_own_messages: Edit own messages +permission_delete_messages: Delete messages +permission_delete_own_messages: Delete own messages project_module_issue_tracking: Issue tracking project_module_time_tracking: Time tracking @@ -278,6 +335,7 @@ label_information: Information label_information_plural: Information label_please_login: Please log in label_register: Register +label_login_with_open_id_option: or login with OpenID label_password_lost: Lost password label_home: Home label_my_page: My page @@ -295,6 +353,7 @@ label_last_updates_plural: %d last updated label_registered_on: Registered on label_activity: Activity label_overall_activity: Overall activity +label_user_activity: "%s's activity" label_new: New label_logged_as: Logged in as label_environment: Environment @@ -494,6 +553,7 @@ label_send_test_email: Send a test email label_feeds_access_key_created_on: RSS access key created %s ago label_module_plural: Modules label_added_time_by: Added by %s %s ago +label_updated_time_by: Updated by %s %s ago label_updated_time: Updated %s ago label_jump_to_a_project: Jump to a project... label_file_plural: Files @@ -529,6 +589,8 @@ label_planning: Planning label_incoming_emails: Incoming emails label_generate_key: Generate a key label_issue_watchers: Watchers +label_example: Example +label_display: Display button_login: Login button_submit: Submit @@ -537,6 +599,7 @@ button_check_all: Check all button_uncheck_all: Uncheck all button_delete: Delete button_create: Create +button_create_and_continue: Create and continue button_test: Test button_edit: Edit button_add: Add @@ -607,7 +670,8 @@ text_status_changed_by_changeset: Applied in changeset %s. text_issues_destroy_confirmation: 'Are you sure you want to delete the selected issue(s) ?' text_select_project_modules: 'Select modules to enable for this project:' text_default_administrator_account_changed: Default administrator account changed -text_file_repository_writable: File repository writable +text_file_repository_writable: Attachments directory writable +text_plugin_assets_writable: Plugin assets directory writable text_rmagick_available: RMagick available (optional) text_destroy_time_entries_question: %.02f hours were reported on the issues you are about to delete. What do you want to do ? text_destroy_time_entries: Delete reported hours @@ -617,6 +681,9 @@ text_user_wrote: '%s wrote:' text_enumeration_destroy_question: '%d objects are assigned to this value.' text_enumeration_category_reassign_to: 'Reassign them to this value:' text_email_delivery_not_configured: "Email delivery is not configured, and notifications are disabled.\nConfigure your SMTP server in config/email.yml and restart the application to enable them." +text_repository_usernames_mapping: "Select or update the Redmine user mapped to each username found in the repository log.\nUsers with the same Redmine and repository username or email are automatically mapped." +text_diff_truncated: '... This diff was truncated because it exceeds the maximum size that can be displayed.' +text_custom_field_possible_values_info: 'One line for each value' default_role_manager: Manager default_role_developper: Developer diff --git a/lang/es.yml b/lang/es.yml index 05d42549c..67f103416 100644 --- a/lang/es.yml +++ b/lang/es.yml @@ -1,5 +1,4 @@ _gloc_rule_default: '|n| n==1 ? "" : "_plural" ' - actionview_datehelper_select_day_prefix: actionview_datehelper_select_month_names: Enero,Febrero,Marzo,Abril,Mayo,Junio,Julio,Agosto,Septiembre,Octubre,Noviembre,Diciembre actionview_datehelper_select_month_names_abbr: Ene,Feb,Mar,Abr,Mayo,Jun,Jul,Ago,Sep,Oct,Nov,Dic @@ -18,630 +17,678 @@ actionview_datehelper_time_in_words_minute_single: 1 minuto actionview_datehelper_time_in_words_second_less_than: menos de un segundo actionview_datehelper_time_in_words_second_less_than_plural: menos de %d segundos actionview_instancetag_blank_option: Por favor seleccione - -activerecord_error_inclusion: no está incluído en la lista -activerecord_error_exclusion: está reservado -activerecord_error_invalid: no es válido -activerecord_error_confirmation: la confirmación no coincide activerecord_error_accepted: debe ser aceptado -activerecord_error_empty: no puede estar vacío activerecord_error_blank: no puede estar en blanco +activerecord_error_circular_dependency: Esta relación podría crear una dependencia circular +activerecord_error_confirmation: la confirmación no coincide +activerecord_error_empty: no puede estar vacío +activerecord_error_exclusion: está reservado +activerecord_error_greater_than_start_date: debe ser posterior a la fecha de comienzo +activerecord_error_inclusion: no está incluído en la lista +activerecord_error_invalid: no es válido +activerecord_error_not_a_date: no es una fecha válida +activerecord_error_not_a_number: no es un número +activerecord_error_not_same_project: no pertenece al mismo proyecto +activerecord_error_taken: ya está siendo usado activerecord_error_too_long: es demasiado largo activerecord_error_too_short: es demasiado corto activerecord_error_wrong_length: la longitud es incorrecta -activerecord_error_taken: ya está siendo usado -activerecord_error_not_a_number: no es un número -activerecord_error_not_a_date: no es una fecha válida -activerecord_error_greater_than_start_date: debe ser la fecha mayor que del comienzo -activerecord_error_not_same_project: no pertenece al mismo proyecto -activerecord_error_circular_dependency: Esta relación podría crear una dependencia anidada - -general_fmt_age: %d año -general_fmt_age_plural: %d años -general_fmt_date: %%d/%%m/%%Y -general_fmt_datetime: %%d/%%m/%%Y %%H:%%M -general_fmt_datetime_short: %%d/%%m %%H:%%M -general_fmt_time: %%H:%%M -general_text_No: 'No' -general_text_Yes: 'Sí' -general_text_no: 'no' -general_text_yes: 'sí' -general_lang_name: 'Español' -general_csv_separator: ';' -general_csv_decimal_separator: ',' -general_csv_encoding: ISO-8859-15 -general_pdf_encoding: ISO-8859-15 -general_day_names: Lunes,Martes,Miércoles,Jueves,Viernes,Sábado,Domingo -general_first_day_of_week: '1' - -notice_account_updated: Cuenta actualizada correctamente. -notice_account_invalid_creditentials: Usuario o contraseña inválido. -notice_account_password_updated: Contraseña modificada correctamente. -notice_account_wrong_password: Contraseña incorrecta. -notice_account_register_done: Cuenta creada correctamente. -notice_account_unknown_email: Usuario desconocido. -notice_can_t_change_password: Esta cuenta utiliza una fuente de autenticación externa. No es posible cambiar la contraseña. -notice_account_lost_email_sent: Se le ha enviado un correo con instrucciones para elegir una nueva contraseña. -notice_account_activated: Su cuenta ha sido activada. Ahora se encuentra conectado. -notice_successful_create: Creación correcta. -notice_successful_update: Modificación correcta. -notice_successful_delete: Borrado correcto. -notice_successful_connection: Conexión correcta. -notice_file_not_found: La página a la que intentas acceder no existe. -notice_locking_conflict: Los datos han sido modificados por otro usuario. -notice_not_authorized: No tiene autorización para acceder a esta página. - +button_activate: Activar +button_add: Añadir +button_annotate: Anotar +button_apply: Aceptar +button_archive: Archivar +button_back: Atrás +button_cancel: Cancelar +button_change: Cambiar +button_change_password: Cambiar contraseña +button_check_all: Seleccionar todo +button_clear: Anular +button_configure: Configurar +button_copy: Copiar +button_create: Crear +button_delete: Borrar +button_download: Descargar +button_edit: Modificar +button_list: Listar +button_lock: Bloquear +button_log_time: Tiempo dedicado +button_login: Conexión +button_move: Mover +button_quote: Citar +button_rename: Renombrar +button_reply: Responder +button_reset: Reestablecer +button_rollback: Volver a esta versión +button_save: Guardar +button_sort: Ordenar +button_submit: Aceptar +button_test: Probar +button_unarchive: Desarchivar +button_uncheck_all: No seleccionar nada +button_unlock: Desbloquear +button_unwatch: No monitorizar +button_update: Actualizar +button_view: Ver +button_watch: Monitorizar +default_activity_design: Diseño +default_activity_development: Desarrollo +default_doc_category_tech: Documentación técnica +default_doc_category_user: Documentación de usuario +default_issue_status_assigned: Asignada +default_issue_status_closed: Cerrada +default_issue_status_feedback: Comentarios +default_issue_status_new: Nueva +default_issue_status_rejected: Rechazada +default_issue_status_resolved: Resuelta +default_priority_high: Alta +default_priority_immediate: Inmediata +default_priority_low: Baja +default_priority_normal: Normal +default_priority_urgent: Urgente +default_role_developper: Desarrollador +default_role_manager: Jefe de proyecto +default_role_reporter: Informador +default_tracker_bug: Errores +default_tracker_feature: Tareas +default_tracker_support: Soporte +enumeration_activities: Actividades (tiempo dedicado) +enumeration_doc_categories: Categorías del documento +enumeration_issue_priorities: Prioridad de las peticiones +error_can_t_load_default_data: "No se ha podido cargar la configuración por defecto: %s" +error_issue_not_found_in_project: 'La petición no se encuentra o no está asociada a este proyecto' +error_scm_annotate: "No existe la entrada o no ha podido ser anotada" +error_scm_command_failed: "Se produjo un error al acceder al repositorio: %s" error_scm_not_found: "La entrada y/o la revisión no existe en el repositorio." -error_scm_command_failed: "An error occurred when trying to access the repository: %s" - -mail_subject_lost_password: Tu contraseña del %s -mail_body_lost_password: 'Para cambiar su contraseña, haga click en el siguiente enlace:' -mail_subject_register: Activación de la cuenta del %s -mail_body_register: 'Para activar su cuenta, haga click en el siguiente enlace:' - -gui_validation_error: 1 error -gui_validation_error_plural: %d errores - -field_name: Nombre -field_description: Descripción -field_summary: Resumen -field_is_required: Obligatorio -field_firstname: Nombre -field_lastname: Apellido -field_mail: Correo electrónico -field_filename: Fichero -field_filesize: Tamaño -field_downloads: Descargas +field_account: Cuenta +field_activity: Actividad +field_admin: Administrador +field_assignable: Se pueden asignar peticiones a este perfil +field_assigned_to: Asignado a +field_attr_firstname: Cualidad del nombre +field_attr_lastname: Cualidad del apellido +field_attr_login: Cualidad del identificador +field_attr_mail: Cualidad del Email +field_auth_source: Modo de identificación field_author: Autor +field_base_dn: DN base +field_category: Categoría +field_column_names: Columnas +field_comments: Comentario +field_comments_sorting: Mostrar comentarios field_created_on: Creado -field_updated_on: Actualizado +field_default_value: Estado por defecto +field_delay: Retraso +field_description: Descripción +field_done_ratio: %% Realizado +field_downloads: Descargas +field_due_date: Fecha fin +field_effective_date: Fecha +field_estimated_hours: Tiempo estimado field_field_format: Formato -field_is_for_all: Para todos los proyectos -field_possible_values: Valores posibles -field_regexp: Expresión regular -field_min_length: Longitud mínima -field_max_length: Longitud máxima -field_value: Valor -field_category: Categoría -field_title: Título -field_project: Proyecto -field_issue: Petición -field_status: Estado -field_notes: Notas +field_filename: Fichero +field_filesize: Tamaño +field_firstname: Nombre +field_fixed_version: Versión prevista +field_hide_mail: Ocultar mi dirección de correo +field_homepage: Sitio web +field_host: Anfitrión +field_hours: Horas +field_identifier: Identificador field_is_closed: Petición resuelta field_is_default: Estado por defecto -field_tracker: Tracker -field_subject: Tema -field_due_date: Fecha fin -field_assigned_to: Asignado a -field_priority: Prioridad -field_fixed_version: Target version -field_user: Usuario -field_role: Perfil -field_homepage: Sitio web -field_is_public: Público -field_parent: Proyecto padre +field_is_filter: Usado como filtro +field_is_for_all: Para todos los proyectos field_is_in_chlog: Consultar las peticiones en el histórico -field_is_in_roadmap: Consultar las peticiones en el roadmap +field_is_in_roadmap: Consultar las peticiones en la planificación +field_is_public: Público +field_is_required: Obligatorio +field_issue: Petición +field_issue_to_id: Petición relacionada +field_language: Idioma +field_last_login_on: Última conexión +field_lastname: Apellido field_login: Identificador +field_mail: Correo electrónico field_mail_notification: Notificaciones por correo -field_admin: Administrador -field_last_login_on: Última conexión -field_language: Idioma -field_effective_date: Fecha -field_password: Contraseña +field_max_length: Longitud máxima +field_min_length: Longitud mínima +field_name: Nombre field_new_password: Nueva contraseña +field_notes: Notas +field_onthefly: Creación del usuario "al vuelo" +field_parent: Proyecto padre +field_parent_title: Página padre +field_password: Contraseña field_password_confirmation: Confirmación -field_version: Versión -field_type: Tipo -field_host: Anfitrión field_port: Puerto -field_account: Cuenta -field_base_dn: DN base -field_attr_login: Cualidad del identificador -field_attr_firstname: Cualidad del nombre -field_attr_lastname: Cualidad del apellido -field_attr_mail: Cualidad del Email -field_onthefly: Creación del usuario "al vuelo" -field_start_date: Fecha de inicio -field_done_ratio: %% Realizado -field_auth_source: Modo de identificación -field_hide_mail: Ocultar mi dirección de correo -field_comment: Comentario -field_url: URL +field_possible_values: Valores posibles +field_priority: Prioridad +field_project: Proyecto +field_redirect_existing_links: Redireccionar enlaces existentes +field_regexp: Expresión regular +field_role: Perfil +field_searchable: Incluir en las búsquedas +field_spent_on: Fecha +field_start_date: Fecha de inicio field_start_page: Página principal +field_status: Estado +field_subject: Tema field_subproject: Proyecto secundario -field_hours: Horas -field_activity: Actividad -field_spent_on: Fecha -field_identifier: Identificador -field_is_filter: Usado como filtro -field_issue_to_id: Petición Relacionada -field_delay: Retraso -field_default_value: Estado por defecto - -setting_app_title: Título de la aplicación -setting_app_subtitle: Subtítulo de la aplicación -setting_welcome_text: Texto de bienvenida -setting_default_language: Idioma por defecto -setting_login_required: Se requiere identificación -setting_self_registration: Registro permitido -setting_attachment_max_size: Tamaño máximo del fichero -setting_issues_export_limit: Límite de exportación de peticiones -setting_mail_from: Correo desde el que enviar mensajes -setting_host_name: Nombre de host -setting_text_formatting: Formato de texto -setting_wiki_compression: Compresión del historial de Wiki -setting_feeds_limit: Límite de contenido para sindicación -setting_autofetch_changesets: Autorellenar los commits del repositorio -setting_sys_api_enabled: Habilitar WS para la gestión del repositorio -setting_commit_ref_keywords: Palabras clave para la referencia -setting_commit_fix_keywords: Palabras clave para la corrección -setting_autologin: Conexión automática -setting_date_format: Formato de la fecha - -label_user: Usuario -label_user_plural: Usuarios -label_user_new: Nuevo usuario -label_project: Proyecto -label_project_new: Nuevo proyecto -label_project_plural: Proyectos -label_project_all: Todos los proyectos -label_project_latest: Últimos proyectos -label_issue: Petición -label_issue_new: Nueva petición -label_issue_plural: Peticiones -label_issue_view_all: Ver todas las peticiones -label_document: Documento -label_document_new: Nuevo documento -label_document_plural: Documentos -label_role: Perfil -label_role_plural: Perfiles -label_role_new: Nuevo perfil -label_role_and_permissions: Perfiles y permisos -label_member: Miembro -label_member_new: Nuevo miembro -label_member_plural: Miembros -label_tracker: Tracker -label_tracker_plural: Trackers -label_tracker_new: Nuevo tracker -label_workflow: Flujo de trabajo -label_issue_status: Estado de petición -label_issue_status_plural: Estados de las peticiones -label_issue_status_new: Nuevo estado -label_issue_category: Categoría de las peticiones -label_issue_category_plural: Categorías de las peticiones -label_issue_category_new: Nueva categoría -label_custom_field: Campo personalizado -label_custom_field_plural: Campos personalizados -label_custom_field_new: Nuevo campo personalizado -label_enumerations: Listas de valores -label_enumeration_new: Nuevo valor -label_information: Información -label_information_plural: Información -label_please_login: Conexión -label_register: Registrar -label_password_lost: ¿Olvidaste la contraseña? -label_home: Inicio -label_my_page: Mi página -label_my_account: Mi cuenta -label_my_projects: Mis proyectos +field_summary: Resumen +field_time_zone: Zona horaria +field_title: Título +field_tracker: Tipo +field_type: Tipo +field_updated_on: Actualizado +field_url: URL +field_user: Usuario +field_value: Valor +field_version: Versión +general_csv_decimal_separator: ',' +general_csv_encoding: ISO-8859-15 +general_csv_separator: ';' +general_day_names: Lunes,Martes,Miércoles,Jueves,Viernes,Sábado,Domingo +general_first_day_of_week: '1' +general_fmt_age: %d año +general_fmt_age_plural: %d años +general_fmt_date: %%d/%%m/%%Y +general_fmt_datetime: %%d/%%m/%%Y %%H:%%M +general_fmt_datetime_short: %%d/%%m %%H:%%M +general_fmt_time: %%H:%%M +general_lang_name: 'Español' +general_pdf_encoding: ISO-8859-15 +general_text_No: 'No' +general_text_Yes: 'Sí' +general_text_no: 'no' +general_text_yes: 'sí' +gui_validation_error: 1 error +gui_validation_error_plural: %d errores +label_activity: Actividad +label_add_another_file: Añadir otro fichero +label_add_note: Añadir una nota +label_added: añadido +label_added_time_by: Añadido por %s hace %s label_administration: Administración -label_login: Conexión -label_logout: Desconexión -label_help: Ayuda -label_reported_issues: Peticiones registradas por mí +label_age: Edad +label_ago: hace +label_all: todos +label_all_time: todo el tiempo +label_all_words: Todas las palabras +label_and_its_subprojects: %s y proyectos secundarios +label_applied_status: Aplicar estado label_assigned_to_me_issues: Peticiones que me están asignadas -label_last_login: Última conexión -label_last_updates: Actualizado -label_last_updates_plural: %d Actualizados -label_registered_on: Inscrito el -label_activity: Actividad -label_new: Nuevo -label_logged_as: Conectado como -label_environment: Entorno -label_authentication: Autenticación -label_auth_source: Modo de autenticación -label_auth_source_new: Nuevo modo de autenticación -label_auth_source_plural: Modos de autenticación -label_subproject_plural: Proyectos secundarios -label_min_max_length: Longitud mín - máx -label_list: Lista -label_date: Fecha -label_integer: Número -label_boolean: Boleano -label_string: Texto -label_text: Texto largo -label_attribute: Cualidad -label_attribute_plural: Cualidades -label_download: %d Descarga -label_download_plural: %d Descargas -label_no_data: Ningun dato a mostrar -label_change_status: Cambiar el estado -label_history: Histórico +label_associated_revisions: Revisiones asociadas label_attachment: Fichero -label_attachment_new: Nuevo fichero label_attachment_delete: Borrar el fichero +label_attachment_new: Nuevo fichero label_attachment_plural: Ficheros -label_report: Informe -label_report_plural: Informes -label_news: Noticia -label_news_new: Nueva noticia -label_news_plural: Noticias -label_news_latest: Últimas noticias -label_news_view_all: Ver todas las noticias +label_attribute: Cualidad +label_attribute_plural: Cualidades +label_auth_source: Modo de autenticación +label_auth_source_new: Nuevo modo de autenticación +label_auth_source_plural: Modos de autenticación +label_authentication: Autenticación +label_blocked_by: bloqueado por +label_blocks: bloquea a +label_board: Foro +label_board_new: Nuevo foro +label_board_plural: Foros +label_boolean: Booleano +label_browse: Hojear +label_bulk_edit_selected_issues: Editar las peticiones seleccionadas +label_calendar: Calendario label_change_log: Cambios -label_settings: Configuración -label_overview: Vistazo -label_version: Versión -label_version_new: Nueva versión -label_version_plural: Versiones -label_confirmation: Confirmación -label_export_to: Exportar a -label_read: Leer... -label_public_projects: Proyectos públicos -label_open_issues: abierta -label_open_issues_plural: abiertas +label_change_plural: Cambios +label_change_properties: Cambiar propiedades +label_change_status: Cambiar el estado +label_change_view_all: Ver todos los cambios +label_changes_details: Detalles de todos los cambios +label_changeset_plural: Cambios +label_chronological_order: En orden cronológico label_closed_issues: cerrada label_closed_issues_plural: cerradas -label_total: Total -label_permissions: Permisos -label_current_status: Estado actual -label_new_statuses_allowed: Nuevos estados autorizados -label_all: todos -label_none: ninguno -label_next: Próximo -label_previous: Anterior -label_used_by: Utilizado por -label_details: Detalles -label_add_note: Añadir una nota -label_per_page: Por la página -label_calendar: Calendario -label_months_from: meses de -label_gantt: Gantt -label_internal: Interno -label_last_changes: %d cambios del último -label_change_view_all: Ver todos los cambios -label_personalize_page: Personalizar esta página label_comment: Comentario -label_comment_plural: Comentarios label_comment_add: Añadir un comentario label_comment_added: Comentario añadido label_comment_delete: Borrar comentarios -label_query: Consulta personalizada -label_query_plural: Consultas personalizadas -label_query_new: Nueva consulta -label_filter_add: Añadir el filtro -label_filter_plural: Filtros -label_equals: igual -label_not_equals: no igual -label_in_less_than: en menos que -label_in_more_than: en más que -label_in: en -label_today: hoy -label_less_than_ago: hace menos de -label_more_than_ago: hace más de -label_ago: hace -label_contains: contiene -label_not_contains: no contiene +label_comment_plural: Comentarios +label_commits_per_author: Commits por autor +label_commits_per_month: Commits por mes +label_confirmation: Confirmación +label_contains: contiene +label_copied: copiado +label_copy_workflow_from: Copiar flujo de trabajo desde +label_current_status: Estado actual +label_current_version: Versión actual +label_custom_field: Campo personalizado +label_custom_field_new: Nuevo campo personalizado +label_custom_field_plural: Campos personalizados +label_date: Fecha +label_date_from: Desde +label_date_range: Rango de fechas +label_date_to: Hasta label_day_plural: días -label_repository: Repositorio -label_browse: Hojear -label_modification: %d modificación -label_modification_plural: %d modificaciones -label_revision: Revisión -label_revision_plural: Revisiones -label_added: añadido -label_modified: modificado +label_default: Por defecto +label_default_columns: Columnas por defecto label_deleted: suprimido -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 -label_sort_highest: Primero -label_sort_higher: Subir -label_sort_lower: Bajar -label_sort_lowest: Último -label_roadmap: Roadmap -label_roadmap_due_in: Finaliza en %s -label_roadmap_no_issues: No hay peticiones para esta versión -label_search: Búsqueda -label_result: %d resultado -label_result_plural: Resultados -label_all_words: Todas las palabras -label_wiki: Wiki -label_wiki_edit: Wiki edicción -label_wiki_edit_plural: Wiki edicciones -label_wiki_page: Wiki página -label_wiki_page_plural: Wiki páginas -label_page_index: Índice -label_current_version: Versión actual -label_preview: Previsualizar -label_feed_plural: Feeds -label_changes_details: Detalles de todos los cambios -label_issue_tracking: Peticiones -label_spent_time: Tiempo dedicado -label_f_hour: %.2f hora -label_f_hour_plural: %.2f horas -label_time_tracking: Tiempo tracking -label_change_plural: Cambios -label_statistics: Estadísticas -label_commits_per_month: Commits por mes -label_commits_per_author: Commits por autor -label_view_diff: Ver diferencias +label_details: Detalles label_diff_inline: en línea label_diff_side_by_side: cara a cara -label_options: Opciones -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 -label_applied_status: Aplicar estado -label_loading: Cargando... -label_relation_new: Nueva relación -label_relation_delete: Eliminar relación -label_relates_to: relacionada con +label_disabled: deshabilitado +label_display_per_page: 'Por página: %s' +label_document: Documento +label_document_added: Documento añadido +label_document_new: Nuevo documento +label_document_plural: Documentos +label_download: %d Descarga +label_download_plural: %d Descargas +label_downloads_abbr: D/L +label_duplicated_by: duplicada por label_duplicates: duplicada de -label_blocks: bloquea a -label_blocked_by: bloqueado por -label_precedes: anterior a -label_follows: posterior a -label_end_to_start: fin a principio label_end_to_end: fin a fin -label_start_to_start: principio a principio -label_start_to_end: principio a fin -label_stay_logged_in: Recordar conexión -label_disabled: deshabilitado -label_show_completed_versions: Muestra las versiones completas -label_me: yo mismo -label_board: Foro -label_board_new: Nuevo foro -label_board_plural: Foros -label_topic_plural: Temas -label_message_plural: Mensajes -label_message_last: Último mensaje -label_message_new: Nuevo mensaje -label_reply_plural: Respuestas -label_send_information: Enviar información de la cuenta al usuario -label_year: Año -label_month: Mes -label_week: Semana -label_date_from: Desde -label_date_to: Hasta -label_language_based: Badado en el idioma - -button_login: Conexión -button_submit: Aceptar -button_save: Guardar -button_check_all: Seleccionar todo -button_uncheck_all: No seleccionar nada -button_delete: Borrar -button_create: Crear -button_test: Probar -button_edit: Modificar -button_add: Añadir -button_change: Cambiar -button_apply: Aceptar -button_clear: Anular -button_lock: Bloquear -button_unlock: Desbloquear -button_download: Descargar -button_list: Listar -button_view: Ver -button_move: Mover -button_back: Atrás -button_cancel: Cancelar -button_activate: Activar -button_sort: Ordenar -button_log_time: Tiempo dedicado -button_rollback: Volver a esta versión -button_watch: Monitorizar -button_unwatch: No monitorizar -button_reply: Responder -button_archive: Archivar -button_unarchive: Desarchivar - -status_active: activo -status_registered: registrado -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_workflow_edit: Seleccionar un flujo de trabajo para actualizar -text_are_you_sure: ¿ Estás seguro ? -text_journal_changed: cambiado de %s a %s -text_journal_set_to: fijado a %s -text_journal_deleted: suprimido -text_tip_task_begin_day: tarea que comienza este día -text_tip_task_end_day: tarea que termina este día -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.
    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 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 - -default_role_manager: Jefe de proyecto -default_role_developper: Desarrollador -default_role_reporter: Informador -default_tracker_bug: Errores -default_tracker_feature: Tareas -default_tracker_support: Soporte -default_issue_status_new: Nueva -default_issue_status_assigned: Asignada -default_issue_status_resolved: Resuelta -default_issue_status_feedback: Comentarios -default_issue_status_closed: Cerrada -default_issue_status_rejected: Rechazada -default_doc_category_user: Documentación de usuario -default_doc_category_tech: Documentación técnica -default_priority_low: Baja -default_priority_normal: Normal -default_priority_high: Alta -default_priority_urgent: Urgente -default_priority_immediate: Inmediata -default_activity_design: Diseño -default_activity_development: Desarrollo - -enumeration_issue_priorities: Prioridad de las peticiones -enumeration_doc_categories: Categorías del documento -enumeration_activities: Actividades (tiempo dedicado) -label_index_by_date: Índice por fecha -field_column_names: Columnas -button_rename: Renombrar -text_issue_category_destroy_question: Algunas peticiones (%d) están asignadas a esta categoría. ¿Qué desea hacer? +label_end_to_start: fin a principio +label_enumeration_new: Nuevo valor +label_enumerations: Listas de valores +label_environment: Entorno +label_equals: igual +label_example: Ejemplo +label_export_to: 'Exportar a:' +label_f_hour: %.2f hora +label_f_hour_plural: %.2f horas +label_feed_plural: Feeds label_feeds_access_key_created_on: Clave de acceso por RSS creada hace %s -label_default_columns: Columnas por defecto -setting_cross_project_issue_relations: Permitir relacionar peticiones de distintos proyectos -label_roadmap_overdue: %s tarde -label_module_plural: Módulos -label_this_week: esta semana +label_file_added: Fichero añadido +label_file_plural: Archivos +label_filter_add: Añadir el filtro +label_filter_plural: Filtros +label_float: Flotante +label_follows: posterior a +label_gantt: Gantt +label_general: General +label_generate_key: Generar clave +label_help: Ayuda +label_history: Histórico +label_home: Inicio +label_in: en +label_in_less_than: en menos que +label_in_more_than: en más que +label_incoming_emails: Correos entrantes +label_index_by_date: Índice por fecha label_index_by_title: Índice por título +label_information: Información +label_information_plural: Información +label_integer: Número +label_internal: Interno +label_issue: Petición +label_issue_added: Petición añadida +label_issue_category: Categoría de las peticiones +label_issue_category_new: Nueva categoría +label_issue_category_plural: Categorías de las peticiones +label_issue_new: Nueva petición +label_issue_plural: Peticiones +label_issue_status: Estado de la petición +label_issue_status_new: Nuevo estado +label_issue_status_plural: Estados de las peticiones +label_issue_tracking: Peticiones +label_issue_updated: Petición actualizada +label_issue_view_all: Ver todas las peticiones +label_issue_watchers: Seguidores +label_issues_by: Peticiones por %s label_jump_to_a_project: Ir al proyecto... -field_assignable: Se pueden asignar peticiones a este perfil -label_sort_by: Ordenar por %s -setting_issue_list_default_columns: Columnas por defecto para la lista de peticiones -text_issue_updated: La petición %s ha sido actualizada por %s. -notice_feeds_access_key_reseted: Su clave de acceso para RSS ha sido reiniciada -field_redirect_existing_links: Redireccionar enlaces existentes -text_issue_category_reassign_to: Reasignar las peticiones a la categoría -notice_email_sent: Se ha enviado un correo a %s -text_issue_added: Petición añadida por %s. -field_comments: Comentario -label_file_plural: Archivos -text_wiki_destroy_confirmation: ¿Seguro que quiere borrar el wiki y todo su contenido? -notice_email_error: Ha ocurrido un error mientras enviando el correo (%s) -label_updated_time: Actualizado hace %s -text_issue_category_destroy_assignments: Dejar las peticiones sin categoría -label_send_test_email: Enviar un correo de prueba -button_reset: Reestablecer -label_added_time_by: Añadido por %s hace %s -field_estimated_hours: Tiempo estimado -label_changeset_plural: Cambios -setting_repositories_encodings: Codificaciones del repositorio -notice_no_issue_selected: "Ninguna petición seleccionada. Por favor, compruebe la petición que quiere modificar" -label_bulk_edit_selected_issues: Editar las peticiones seleccionadas +label_language_based: Basado en el idioma +label_last_changes: últimos %d cambios +label_last_login: Última conexión +label_last_month: último mes +label_last_n_days: últimos %d días +label_last_updates: Actualizado +label_last_updates_plural: %d Actualizados +label_last_week: última semana +label_latest_revision: Última revisión +label_latest_revision_plural: Últimas revisiones +label_ldap_authentication: Autenticación LDAP +label_less_than_ago: hace menos de +label_list: Lista +label_loading: Cargando... +label_logged_as: Conectado como +label_login: Conexión +label_logout: Desconexión +label_max_size: Tamaño máximo +label_me: yo mismo +label_member: Miembro +label_member_new: Nuevo miembro +label_member_plural: Miembros +label_message_last: Último mensaje +label_message_new: Nuevo mensaje +label_message_plural: Mensajes +label_message_posted: Mensaje añadido +label_min_max_length: Longitud mín - máx +label_modification: %d modificación +label_modification_plural: %d modificaciones +label_modified: modificado +label_module_plural: Módulos +label_month: Mes +label_months_from: meses de +label_more: Más +label_more_than_ago: hace más de +label_my_account: Mi cuenta +label_my_page: Mi página +label_my_projects: Mis proyectos +label_new: Nuevo +label_new_statuses_allowed: Nuevos estados autorizados +label_news: Noticia +label_news_added: Noticia añadida +label_news_latest: Últimas noticias +label_news_new: Nueva noticia +label_news_plural: Noticias +label_news_view_all: Ver todas las noticias +label_next: Siguiente label_no_change_option: (Sin cambios) -notice_failed_to_save_issues: "Imposible salvar %s peticion(es) en %d seleccionado: %s." -label_theme: Tema -label_default: Por defecto -label_search_titles_only: Buscar sólo en títulos +label_no_data: Ningún dato a mostrar label_nobody: nadie -button_change_password: Cambiar contraseña -text_user_mail_option: "En los proyectos no seleccionados, sólo recibirá notificaciones sobre elementos monitorizados o elementos en los que esté involucrado (por ejemplo, peticiones de las que usted sea autor o asignadas a usted)." -label_user_mail_option_selected: "Para cualquier evento del proyecto seleccionado..." -label_user_mail_option_all: "Para cualquier evento en todos mis proyectos" -label_user_mail_option_none: "Sólo para elementos monitorizados o relacionados conmigo" -setting_emails_footer: Pie de mensajes -label_float: Flotante -button_copy: Copiar -mail_body_account_information_external: Puede usar su cuenta "%s" para conectarse. -mail_body_account_information: Información sobre su cuenta -setting_protocol: Protocolo -text_caracters_minimum: %d carácteres como mínimo -field_time_zone: Zona horaria +label_none: ninguno +label_not_contains: no contiene +label_not_equals: no igual +label_on: de +label_open_issues: abierta +label_open_issues_plural: abiertas +label_optional_description: Descripción opcional +label_options: Opciones +label_overall_activity: Actividad global +label_overview: Vistazo +label_password_lost: ¿Olvidaste la contraseña? +label_per_page: Por página +label_permissions: Permisos +label_permissions_report: Informe de permisos +label_personalize_page: Personalizar esta página +label_planning: Planificación +label_please_login: Conexión +label_plugins: Extensiones +label_precedes: anterior a +label_preferences: Preferencias +label_preview: Previsualizar +label_previous: Anterior +label_project: Proyecto +label_project_all: Todos los proyectos +label_project_latest: Últimos proyectos +label_project_new: Nuevo proyecto +label_project_plural: Proyectos +label_public_projects: Proyectos públicos +label_query: Consulta personalizada +label_query_new: Nueva consulta +label_query_plural: Consultas personalizadas +label_read: Leer... +label_register: Registrar +label_registered_on: Inscrito el label_registration_activation_by_email: activación de cuenta por correo -label_user_mail_no_self_notified: "No quiero ser avisado de cambios hechos por mí" -mail_subject_account_activation_request: Petición de activación de cuenta %s -mail_body_account_activation_request: "Un nuevo usuario (%s) ha sido registrado. Esta cuenta está pendiende de aprobación" label_registration_automatic_activation: activación automática de cuenta label_registration_manual_activation: activación manual de cuenta -notice_account_pending: "Su cuenta ha sido creada y está pendiende de la aprobación por parte de administrador" -setting_time_format: Formato de hora -setting_bcc_recipients: Ocultar las copias de carbon (bcc) -button_annotate: Anotar -label_issues_by: Peticiones por %s -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: 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_related_issues: Peticiones relacionadas +label_relates_to: relacionada con +label_relation_delete: Eliminar relación +label_relation_new: Nueva relación +label_renamed: renombrado +label_reply_plural: Respuestas +label_report: Informe +label_report_plural: Informes +label_reported_issues: Peticiones registradas por mí +label_repository: Repositorio label_repository_plural: Repositorios -label_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_result_plural: Resultados +label_reverse_chronological_order: En orden cronológico inverso +label_revision: Revisión +label_revision_plural: Revisiones +label_roadmap: Planificación +label_roadmap_due_in: Finaliza en %s +label_roadmap_no_issues: No hay peticiones para esta versión +label_roadmap_overdue: %s tarde +label_role: Perfil +label_role_and_permissions: Perfiles y permisos +label_role_new: Nuevo perfil +label_role_plural: Perfiles label_scm: SCM -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 +label_search: Búsqueda +label_search_titles_only: Buscar sólo en títulos +label_send_information: Enviar información de la cuenta al usuario +label_send_test_email: Enviar un correo de prueba +label_settings: Configuración +label_show_completed_versions: Muestra las versiones terminadas +label_sort_by: Ordenar por %s +label_sort_higher: Subir +label_sort_highest: Primero +label_sort_lower: Bajar +label_sort_lowest: Último +label_spent_time: Tiempo dedicado +label_start_to_end: principio a fin +label_start_to_start: principio a principio +label_statistics: Estadísticas +label_stay_logged_in: Recordar conexión +label_string: Texto +label_subproject_plural: Proyectos secundarios +label_text: Texto largo +label_theme: Tema +label_this_month: este mes +label_this_week: esta semana +label_this_year: este año +label_time_tracking: Control de tiempo +label_today: hoy +label_topic_plural: Temas +label_total: Total +label_tracker: Tipo +label_tracker_new: Nuevo tipo +label_tracker_plural: Tipos de peticiones +label_updated_time: Actualizado hace %s +label_updated_time_by: Actualizado por %s hace %s +label_used_by: Utilizado por +label_user: Usuario +label_user_activity: "Actividad de %s" +label_user_mail_no_self_notified: "No quiero ser avisado de cambios hechos por mí" +label_user_mail_option_all: "Para cualquier evento en todos mis proyectos" +label_user_mail_option_none: "Sólo para elementos monitorizados o relacionados conmigo" +label_user_mail_option_selected: "Para cualquier evento de los proyectos seleccionados..." +label_user_new: Nuevo usuario +label_user_plural: Usuarios +label_version: Versión +label_version_new: Nueva versión +label_version_plural: Versiones +label_view_diff: Ver diferencias +label_view_revisions: Ver las revisiones +label_watched_issues: Peticiones monitorizadas +label_week: Semana +label_wiki: Wiki +label_wiki_edit: Wiki edicción +label_wiki_edit_plural: Wiki edicciones +label_wiki_page: Wiki página +label_wiki_page_plural: Wiki páginas +label_workflow: Flujo de trabajo +label_year: Año +label_yesterday: ayer +mail_body_account_activation_request: 'Se ha inscrito un nuevo usuario (%s). La cuenta está pendiende de aprobación:' +mail_body_account_information: Información sobre su cuenta +mail_body_account_information_external: Puede usar su cuenta "%s" para conectarse. +mail_body_lost_password: 'Para cambiar su contraseña, haga clic en el siguiente enlace:' +mail_body_register: 'Para activar su cuenta, haga clic en el siguiente enlace:' +mail_body_reminder: "%d peticion(es) asignadas a tí finalizan en los próximos %d días:" +mail_subject_account_activation_request: Petición de activación de cuenta %s +mail_subject_lost_password: Tu contraseña del %s +mail_subject_register: Activación de la cuenta del %s +mail_subject_reminder: "%d peticion(es) finalizan en los próximos días" +notice_account_activated: Su cuenta ha sido activada. Ya puede conectarse. +notice_account_invalid_creditentials: Usuario o contraseña inválido. +notice_account_lost_email_sent: Se le ha enviado un correo con instrucciones para elegir una nueva contraseña. +notice_account_password_updated: Contraseña modificada correctamente. +notice_account_pending: "Su cuenta ha sido creada y está pendiende de la aprobación por parte del administrador." +notice_account_register_done: Cuenta creada correctamente. Para activarla, haga clic sobre el enlace que le ha sido enviado por correo. +notice_account_unknown_email: Usuario desconocido. +notice_account_updated: Cuenta actualizada correctamente. +notice_account_wrong_password: Contraseña incorrecta. +notice_can_t_change_password: Esta cuenta utiliza una fuente de autenticación externa. No es posible cambiar la contraseña. +notice_default_data_loaded: Configuración por defecto cargada correctamente. +notice_email_error: Ha ocurrido un error mientras enviando el correo (%s) +notice_email_sent: Se ha enviado un correo a %s +notice_failed_to_save_issues: "Imposible grabar %s peticion(es) en %d seleccionado: %s." +notice_feeds_access_key_reseted: Su clave de acceso para RSS ha sido reiniciada. +notice_file_not_found: La página a la que intenta acceder no existe. +notice_locking_conflict: Los datos han sido modificados por otro usuario. +notice_no_issue_selected: "Ninguna petición seleccionada. Por favor, compruebe la petición que quiere modificar" +notice_not_authorized: No tiene autorización para acceder a esta página. +notice_successful_connection: Conexión correcta. +notice_successful_create: Creación correcta. +notice_successful_delete: Borrado correcto. +notice_successful_update: Modificación correcta. +notice_unable_delete_version: No se puede borrar la versión +permission_add_issue_notes: Añadir notas +permission_add_issue_watchers: Añadir seguidores +permission_add_issues: Añadir peticiones +permission_add_messages: Enviar mensajes +permission_browse_repository: Hojear repositiorio +permission_comment_news: Comentar noticias +permission_commit_access: Acceso de escritura +permission_delete_issues: Borrar peticiones +permission_delete_messages: Borrar mensajes +permission_delete_own_messages: Borrar mensajes propios +permission_delete_wiki_pages: Borrar páginas wiki +permission_delete_wiki_pages_attachments: Borrar ficheros +permission_edit_issue_notes: Modificar notas +permission_edit_issues: Modificar peticiones +permission_edit_messages: Modificar mensajes +permission_edit_own_issue_notes: Modificar notas propias +permission_edit_own_messages: Editar mensajes propios +permission_edit_own_time_entries: Modificar tiempos dedicados propios +permission_edit_project: Modificar proyecto +permission_edit_time_entries: Modificar tiempos dedicados +permission_edit_wiki_pages: Modificar páginas wiki +permission_log_time: Anotar tiempo dedicado +permission_manage_boards: Administrar foros +permission_manage_categories: Administrar categorías de peticiones +permission_manage_documents: Administrar documentos +permission_manage_files: Administrar ficheros +permission_manage_issue_relations: Administrar relación con otras peticiones +permission_manage_members: Administrar miembros +permission_manage_news: Administrar noticias +permission_manage_public_queries: Administrar consultas públicas +permission_manage_repository: Administrar repositorio +permission_manage_versions: Administrar versiones +permission_manage_wiki: Administrar wiki +permission_move_issues: Mover peticiones +permission_protect_wiki_pages: Proteger páginas wiki +permission_rename_wiki_pages: Renombrar páginas wiki +permission_save_queries: Grabar consultas +permission_select_project_modules: Seleccionar módulos del proyecto +permission_view_calendar: Ver calendario +permission_view_changesets: Ver cambios +permission_view_documents: Ver documentos +permission_view_files: Ver ficheros +permission_view_gantt: Ver diagrama de Gantt +permission_view_issue_watchers: Ver lista de seguidores +permission_view_messages: Ver mensajes +permission_view_time_entries: Ver tiempo dedicado +permission_view_wiki_edits: Ver histórico del wiki +permission_view_wiki_pages: Ver wiki project_module_boards: Foros -project_module_issue_tracking: Peticiones -project_module_wiki: Wiki -project_module_files: Ficheros project_module_documents: Documentos -project_module_repository: Repositorio +project_module_files: Ficheros +project_module_issue_tracking: Peticiones project_module_news: Noticias +project_module_repository: Repositorio 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: Autenticación LDAP -label_downloads_abbr: D/L -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:' +project_module_wiki: Wiki 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' -label_and_its_subprojects: %s y sus subproyectos -mail_body_reminder: "la petición %d asignada a tí finaliza en los próximos %d días:" -mail_subject_reminder: "%d peticion(es) finaliza en los próximos días" -text_user_wrote: '%s escribió:' -label_duplicated_by: duplicada por +setting_app_subtitle: Subtítulo de la aplicación +setting_app_title: Título de la aplicación +setting_attachment_max_size: Tamaño máximo del fichero +setting_autofetch_changesets: Autorellenar los commits del repositorio +setting_autologin: Conexión automática +setting_bcc_recipients: Ocultar las copias de carbón (bcc) +setting_commit_fix_keywords: Palabras clave para la corrección +setting_commit_logs_encoding: Codificación de los mensajes de commit +setting_commit_ref_keywords: Palabras clave para la referencia +setting_cross_project_issue_relations: Permitir relacionar peticiones de distintos proyectos +setting_date_format: Formato de fecha +setting_default_language: Idioma por defecto +setting_default_projects_public: Los proyectos nuevos son públicos por defecto +setting_diff_max_lines_displayed: Número máximo de diferencias mostradas +setting_display_subprojects_issues: Mostrar por defecto peticiones de proy. secundarios en el principal +setting_emails_footer: Pie de mensajes setting_enabled_scm: Activar SCM -text_enumeration_category_reassign_to: 'Reasignar el siguiente valor:' -text_enumeration_destroy_question: '%d objetos con este valor asignado.' -label_incoming_emails: Correos entrantes -label_generate_key: Generar clave +setting_feeds_limit: Límite de contenido para sindicación +setting_gravatar_enabled: Usar iconos de usuario (Gravatar) +setting_host_name: Nombre y ruta del servidor +setting_issue_list_default_columns: Columnas por defecto para la lista de peticiones +setting_issues_export_limit: Límite de exportación de peticiones +setting_login_required: Se requiere identificación +setting_mail_from: Correo desde el que enviar mensajes setting_mail_handler_api_enabled: Activar SW para mensajes entrantes -setting_mail_handler_api_key: clave de la API +setting_mail_handler_api_key: Clave de la API +setting_per_page_options: Objetos por página +setting_plain_text_mail: sólo texto plano (no HTML) +setting_protocol: Protocolo +setting_repositories_encodings: Codificaciones del repositorio +setting_self_registration: Registro permitido +setting_sequential_project_identifiers: Generar identificadores de proyecto +setting_sys_api_enabled: Habilitar SW para la gestión del repositorio +setting_text_formatting: Formato de texto +setting_time_format: Formato de hora +setting_user_format: Formato de nombre de usuario +setting_welcome_text: Texto de bienvenida +setting_wiki_compression: Compresión del historial del Wiki +status_active: activo +status_locked: bloqueado +status_registered: registrado +text_are_you_sure: ¿Está seguro? +text_assign_time_entries_to_project: Asignar las horas al proyecto +text_caracters_maximum: %d caracteres como máximo. +text_caracters_minimum: %d caracteres como mínimo +text_comma_separated: Múltiples valores permitidos (separados por coma). +text_default_administrator_account_changed: Cuenta de administrador por defecto modificada +text_destroy_time_entries: Borrar las horas +text_destroy_time_entries_question: Existen %.02f horas asignadas a la petición que quiere borrar. ¿Qué quiere hacer ? +text_diff_truncated: '... Diferencia truncada por exceder el máximo tamaño visualizable.' text_email_delivery_not_configured: "El envío de correos no está configurado, y las notificaciones se han desactivado. \n Configure el servidor de SMTP en config/email.yml y reinicie la aplicación para activar los cambios." -field_parent_title: Página padre -label_issue_watchers: Seguidores -setting_commit_logs_encoding: Codificación de los mensajes de commit -button_quote: Quote -setting_sequential_project_identifiers: Generate sequential project identifiers -notice_unable_delete_version: Unable to delete version -label_renamed: renamed -label_copied: copied -setting_repositories_cache_directory: Cache directory for repositories -field_cache: Local cache +text_enumeration_category_reassign_to: 'Reasignar al siguiente valor:' +text_enumeration_destroy_question: '%d objetos con este valor asignado.' +text_file_repository_writable: Se puede escribir en el repositorio +text_issue_added: Petición %s añadida por %s. +text_issue_category_destroy_assignments: Dejar las peticiones sin categoría +text_issue_category_destroy_question: Algunas peticiones (%d) están asignadas a esta categoría. ¿Qué desea hacer? +text_issue_category_reassign_to: Reasignar las peticiones a la categoría +text_issue_updated: La petición %s ha sido actualizada por %s. +text_issues_destroy_confirmation: '¿Seguro que quiere borrar las peticiones seleccionadas?' +text_issues_ref_in_commit_messages: Referencia y petición de corrección en los mensajes +text_journal_changed: cambiado de %s a %s +text_journal_deleted: suprimido +text_journal_set_to: fijado a %s +text_length_between: Longitud entre %d y %d caracteres. +text_load_default_configuration: Cargar la configuración por defecto +text_min_max_length_info: 0 para ninguna restricción +text_no_configuration_data: "Todavía no se han configurado perfiles, ni tipos, estados y flujo de trabajo asociado a peticiones. Se recomiendo encarecidamente cargar la configuración por defecto. Una vez cargada, podrá modificarla." +text_project_destroy_confirmation: ¿Estás seguro de querer eliminar el proyecto? +text_project_identifier_info: 'Letras minúsculas (a-z), números y signos de puntuación permitidos.
    Una vez guardado, el identificador no puede modificarse.' +text_reassign_time_entries: 'Reasignar las horas a esta petición:' +text_regexp_info: ej. ^[A-Z0-9]+$ +text_repository_usernames_mapping: "Establezca la correspondencia entre los usuarios de Redmine y los presentes en el log del repositorio.\nLos usuarios con el mismo nombre o correo en Redmine y en el repositorio serán asociados automáticamente." +text_rmagick_available: RMagick disponible (opcional) +text_select_mail_notifications: Seleccionar los eventos a notificar +text_select_project_modules: 'Seleccione los módulos a activar para este proyecto:' +text_status_changed_by_changeset: Aplicado en los cambios %s +text_subprojects_destroy_warning: 'Los proyectos secundarios: %s también se eliminarán' +text_tip_task_begin_day: tarea que comienza este día +text_tip_task_begin_end_day: tarea que comienza y termina este día +text_tip_task_end_day: tarea que termina este día +text_tracker_no_workflow: No hay ningún flujo de trabajo definido para este tipo de petición +text_unallowed_characters: Caracteres no permitidos +text_user_mail_option: "De los proyectos no seleccionados, sólo recibirá notificaciones sobre elementos monitorizados o elementos en los que esté involucrado (por ejemplo, peticiones de las que usted sea autor o asignadas a usted)." +text_user_wrote: '%s escribió:' +text_wiki_destroy_confirmation: ¿Seguro que quiere borrar el wiki y todo su contenido? +text_workflow_edit: Seleccionar un flujo de trabajo para actualizar +text_plugin_assets_writable: Plugin assets directory writable +warning_attachments_not_saved: "%d file(s) could not be saved." +button_create_and_continue: Create and continue +text_custom_field_possible_values_info: 'One line for each value' +label_display: Display +field_editable: Editable +setting_repository_log_display_limit: Maximum number of revisions displayed on file log +field_identity_url: OpenID URL +setting_openid: Allow OpenID login and registration +label_login_with_open_id_option: or login with OpenID +field_watcher: Watcher diff --git a/lang/fi.yml b/lang/fi.yml index d674568ef..65478776d 100644 --- a/lang/fi.yml +++ b/lang/fi.yml @@ -634,11 +634,76 @@ setting_mail_handler_api_key: API avain text_email_delivery_not_configured: "Sähköpostin jakelu ei ole määritelty ja sähköpostimuistutukset eivät ole käytössä.\nKonfiguroi sähköpostipalvelinasetukset (SMTP) config/email.yml tiedostosta ja uudelleenkäynnistä sovellus jotta asetukset astuvat voimaan." field_parent_title: Aloitussivu label_issue_watchers: Tapahtuman seuraajat -button_quote: Quote -setting_sequential_project_identifiers: Generate sequential project identifiers -setting_commit_logs_encoding: Commit messages encoding -notice_unable_delete_version: Unable to delete version -label_renamed: renamed -label_copied: copied -setting_repositories_cache_directory: Cache directory for repositories -field_cache: Local cache +button_quote: Vastaa +setting_sequential_project_identifiers: Luo peräkkäiset projektien tunnisteet +setting_commit_logs_encoding: Tee viestien koodaus +notice_unable_delete_version: Version poisto epäonnistui +label_renamed: uudelleennimetty +label_copied: kopioitu +setting_plain_text_mail: vain muotoilematonta tekstiä (ei HTML) +permission_view_files: Näytä tiedostot +permission_edit_issues: Muokkaa tapahtumia +permission_edit_own_time_entries: Muokka omia aikamerkintöjä +permission_manage_public_queries: Hallinnoi julkisia hakuja +permission_add_issues: Lisää tapahtumia +permission_log_time: Lokita käytettyä aikaa +permission_view_changesets: Näytä muutosryhmät +permission_view_time_entries: Näytä käytetty aika +permission_manage_versions: Hallinnoi versioita +permission_manage_wiki: Hallinnoi wikiä +permission_manage_categories: Hallinnoi tapahtumien luokkia +permission_protect_wiki_pages: Suojaa wiki sivut +permission_comment_news: Kommentoi uutisia +permission_delete_messages: Poista viestit +permission_select_project_modules: Valitse projektin modulit +permission_manage_documents: Hallinnoi dokumentteja +permission_edit_wiki_pages: Muokkaa wiki sivuja +permission_add_issue_watchers: Lisää seuraajia +permission_view_gantt: Näytä gantt kaavio +permission_move_issues: Siirrä tapahtuma +permission_manage_issue_relations: Hallinoi tapahtuman suhteita +permission_delete_wiki_pages: Poista wiki sivuja +permission_manage_boards: Hallinnoi keskustelupalstaa +permission_delete_wiki_pages_attachments: Poista liitteitä +permission_view_wiki_edits: Näytä wiki historia +permission_add_messages: Jätä viesti +permission_view_messages: Näytä viestejä +permission_manage_files: Hallinnoi tiedostoja +permission_edit_issue_notes: Muokkaa muistiinpanoja +permission_manage_news: Hallinnoi uutisia +permission_view_calendar: Näytä kalenteri +permission_manage_members: Hallinnoi jäseniä +permission_edit_messages: Muokkaa viestejä +permission_delete_issues: Poista tapahtumia +permission_view_issue_watchers: Näytä seuraaja lista +permission_manage_repository: Hallinnoi tietovarastoa +permission_commit_access: Tee pääsyoikeus +permission_browse_repository: Selaa tietovarastoa +permission_view_documents: Näytä dokumentit +permission_edit_project: Muokkaa projektia +permission_add_issue_notes: Lisää muistiinpanoja +permission_save_queries: Tallenna hakuja +permission_view_wiki_pages: Näytä wiki +permission_rename_wiki_pages: Uudelleennimeä wiki sivuja +permission_edit_time_entries: Muokkaa aika lokeja +permission_edit_own_issue_notes: Muokkaa omia muistiinpanoja +setting_gravatar_enabled: Käytä Gravatar käyttäjä ikoneita +label_example: Esimerkki +text_repository_usernames_mapping: "Valitse päivittääksesi Redmine käyttäjä jokaiseen käyttäjään joka löytyy tietovaraston lokista.\nKäyttäjät joilla on sama Redmine ja tietovaraston käyttäjänimi tai sähköpostiosoite, yhdistetään automaattisesti." +permission_edit_own_messages: Muokkaa omia viestejä +permission_delete_own_messages: Poista omia viestejä +label_user_activity: "Käyttäjän %s historia" +label_updated_time_by: Updated by %s %s ago +text_diff_truncated: '... This diff was truncated because it exceeds the maximum size that can be displayed.' +setting_diff_max_lines_displayed: Max number of diff lines displayed +text_plugin_assets_writable: Plugin assets directory writable +warning_attachments_not_saved: "%d file(s) could not be saved." +button_create_and_continue: Create and continue +text_custom_field_possible_values_info: 'One line for each value' +label_display: Display +field_editable: Editable +setting_repository_log_display_limit: Maximum number of revisions displayed on file log +field_identity_url: OpenID URL +setting_openid: Allow OpenID login and registration +label_login_with_open_id_option: or login with OpenID +field_watcher: Watcher diff --git a/lang/fr.yml b/lang/fr.yml index 77c358a9b..4a7c51708 100644 --- a/lang/fr.yml +++ b/lang/fr.yml @@ -77,6 +77,7 @@ notice_failed_to_save_issues: "%d demande(s) sur les %d sélectionnées n'ont pa notice_no_issue_selected: "Aucune demande sélectionnée ! Cochez les demandes que vous voulez mettre à jour." notice_account_pending: "Votre compte a été créé et attend l'approbation de l'administrateur." notice_default_data_loaded: Paramétrage par défaut chargé avec succès. +notice_unable_delete_version: Impossible de supprimer cette version. error_can_t_load_default_data: "Une erreur s'est produite lors du chargement du paramétrage: %s" error_scm_not_found: "L'entrée et/ou la révision demandée n'existe pas dans le dépôt." @@ -84,6 +85,8 @@ error_scm_command_failed: "Une erreur s'est produite lors de l'accès au dépôt error_scm_annotate: "L'entrée n'existe pas ou ne peut pas être annotée." error_issue_not_found_in_project: "La demande n'existe pas ou n'appartient pas à ce projet" +warning_attachments_not_saved: "%d fichier(s) n'ont pas pu être sauvegardés." + mail_subject_lost_password: Votre mot de passe %s mail_body_lost_password: 'Pour changer votre mot de passe, cliquez sur le lien suivant:' mail_subject_register: Activation de votre compte %s @@ -169,7 +172,6 @@ field_start_page: Page de démarrage field_subproject: Sous-projet field_hours: Heures field_activity: Activité -label_overall_activity: Activité globale field_spent_on: Date field_identifier: Identifiant field_is_filter: Utilisé comme filtre @@ -184,6 +186,9 @@ field_searchable: Utilisé pour les recherches field_default_value: Valeur par défaut field_comments_sorting: Afficher les commentaires field_parent_title: Page parent +field_editable: Modifiable +field_identity_url: URL OpenID +field_watcher: Observateur setting_app_title: Titre de l'application setting_app_subtitle: Sous-titre de l'application @@ -195,7 +200,8 @@ setting_attachment_max_size: Taille max des fichiers setting_issues_export_limit: Limite export demandes setting_mail_from: Adresse d'émission setting_bcc_recipients: Destinataires en copie cachée (cci) -setting_host_name: Nom d'hôte +setting_plain_text_mail: Mail texte brut (non HTML) +setting_host_name: Nom d'hôte et chemin setting_text_formatting: Formatage du texte setting_wiki_compression: Compression historique wiki setting_feeds_limit: Limite du contenu des flux RSS @@ -221,7 +227,59 @@ setting_enabled_scm: SCM activés setting_mail_handler_api_enabled: "Activer le WS pour la réception d'emails" setting_mail_handler_api_key: Clé de protection de l'API setting_sequential_project_identifiers: Générer des identifiants de projet séquentiels -setting_repositories_cache_directory: Répertoire du cache pour les dépôts +setting_gravatar_enabled: Afficher les Gravatar des utilisateurs +setting_diff_max_lines_displayed: Nombre maximum de lignes de diff affichées +setting_repository_log_display_limit: "Nombre maximum de revisions affichées sur l'historique d'un fichier" +setting_openid: "Autoriser l'authentification et l'enregistrement OpenID" + +permission_edit_project: Modifier le projet +permission_select_project_modules: Choisir les modules +permission_manage_members: Gérer les members +permission_manage_versions: Gérer les versions +permission_manage_categories: Gérer les catégories de demandes +permission_add_issues: Créer des demandes +permission_edit_issues: Modifier les demandes +permission_manage_issue_relations: Gérer les relations +permission_add_issue_notes: Ajouter des notes +permission_edit_issue_notes: Modifier les notes +permission_edit_own_issue_notes: Modifier ses propres notes +permission_move_issues: Déplacer les demandes +permission_delete_issues: Supprimer les demandes +permission_manage_public_queries: Gérer les requêtes publiques +permission_save_queries: Sauvegarder les requêtes +permission_view_gantt: Voir le gantt +permission_view_calendar: Voir le calendrier +permission_view_issue_watchers: Voir la liste des observateurs +permission_add_issue_watchers: Ajouter des observateurs +permission_log_time: Saisir le temps passé +permission_view_time_entries: Voir le temps passé +permission_edit_time_entries: Modifier les temps passés +permission_edit_own_time_entries: Modifier son propre temps passé +permission_manage_news: Gérer les annonces +permission_comment_news: Commenter les annonces +permission_manage_documents: Gérer les documents +permission_view_documents: Voir les documents +permission_manage_files: Gérer les fichiers +permission_view_files: Voir les fichiers +permission_manage_wiki: Gérer le wiki +permission_rename_wiki_pages: Renommer les pages +permission_delete_wiki_pages: Supprimer les pages +permission_view_wiki_pages: Voir le wiki +permission_view_wiki_edits: "Voir l'historique des modifications" +permission_edit_wiki_pages: Modifier les pages +permission_delete_wiki_pages_attachments: Supprimer les fichiers joints +permission_protect_wiki_pages: Protéger les pages +permission_manage_repository: Gérer le dépôt de sources +permission_browse_repository: Parcourir les sources +permission_view_changesets: Voir les révisions +permission_commit_access: Droit de commit +permission_manage_boards: Gérer les forums +permission_view_messages: Voir les messages +permission_add_messages: Poster un message +permission_edit_messages: Modifier les messages +permission_edit_own_messages: Modifier ses propres messages +permission_delete_messages: Supprimer les messages +permission_delete_own_messages: Supprimer ses propres messages project_module_issue_tracking: Suivi des demandes project_module_time_tracking: Suivi du temps passé @@ -293,6 +351,8 @@ label_last_updates: Dernière mise à jour label_last_updates_plural: %d dernières mises à jour label_registered_on: Inscrit le label_activity: Activité +label_overall_activity: Activité globale +label_user_activity: "Activité de %s" label_new: Nouveau label_logged_as: Connecté en tant que label_environment: Environnement @@ -492,6 +552,7 @@ label_send_test_email: Envoyer un email de test label_feeds_access_key_created_on: Clé d'accès RSS créée il y a %s label_module_plural: Modules label_added_time_by: Ajouté par %s il y a %s +label_updated_time_by: Mis à jour par %s il y a %s label_updated_time: Mis à jour il y a %s label_jump_to_a_project: Aller à un projet... label_file_plural: Fichiers @@ -526,7 +587,10 @@ label_reverse_chronological_order: Dans l'ordre chronologique inverse label_planning: Planning label_incoming_emails: Emails entrants label_generate_key: Générer une clé -label_issue_watchers: Utilisateurs surveillant cette demande +label_issue_watchers: Observateurs +label_example: Exemple +label_display: Affichage +label_login_with_open_id_option: Authentification OpenID button_login: Connexion button_submit: Soumettre @@ -535,6 +599,7 @@ button_check_all: Tout cocher button_uncheck_all: Tout décocher button_delete: Supprimer button_create: Créer +button_create_and_continue: Créer et continuer button_test: Tester button_edit: Modifier button_add: Ajouter @@ -606,6 +671,7 @@ text_issues_destroy_confirmation: 'Etes-vous sûr de vouloir supprimer le(s) dem text_select_project_modules: 'Selectionner les modules à activer pour ce project:' text_default_administrator_account_changed: Compte administrateur par défaut changé text_file_repository_writable: Répertoire de stockage des fichiers accessible en écriture +text_plugin_assets_writable: Répertoire public des plugins accessible en écriture text_rmagick_available: Bibliothèque RMagick présente (optionnelle) text_destroy_time_entries_question: %.02f heures ont été enregistrées sur les demandes à supprimer. Que voulez-vous faire ? text_destroy_time_entries: Supprimer les heures @@ -615,6 +681,9 @@ text_user_wrote: '%s a écrit:' text_enumeration_destroy_question: 'Cette valeur est affectée à %d objets.' text_enumeration_category_reassign_to: 'Réaffecter les objets à cette valeur:' text_email_delivery_not_configured: "L'envoi de mail n'est pas configuré, les notifications sont désactivées.\nConfigurez votre serveur SMTP dans config/email.yml et redémarrez l'application pour les activer." +text_repository_usernames_mapping: "Vous pouvez sélectionner ou modifier l'utilisateur Redmine associé à chaque nom d'utilisateur figurant dans l'historique du dépôt.\nLes utilisateurs avec le même identifiant ou la même adresse mail seront automatiquement associés." +text_diff_truncated: '... Ce différentiel a été tronqué car il excède la taille maximale pouvant être affichée.' +text_custom_field_possible_values_info: 'Une ligne par valeur' default_role_manager: Manager default_role_developper: Développeur @@ -641,5 +710,3 @@ default_activity_development: Développement enumeration_issue_priorities: Priorités des demandes enumeration_doc_categories: Catégories des documents enumeration_activities: Activités (suivi du temps) -notice_unable_delete_version: Unable to delete version -field_cache: Cache local diff --git a/lang/gl.yml b/lang/gl.yml new file mode 100644 index 000000000..701fe22c7 --- /dev/null +++ b/lang/gl.yml @@ -0,0 +1,694 @@ +_gloc_rule_default: '|n| n==1 ? "" : "_plural" ' +actionview_datehelper_select_day_prefix: +actionview_datehelper_select_month_names: Xaneiro,Febreiro,Marzo,Abril,Maio,Xuño,Xullo,Agosto,Setembro,Outubro,Novembro,Decembro +actionview_datehelper_select_month_names_abbr: Xan,Feb,Mar,Abr,Mai,Xun,Xul,Ago,Set,Out,Nov,Dec +actionview_datehelper_select_month_prefix: +actionview_datehelper_select_year_prefix: +actionview_datehelper_time_in_words_day: 1 día +actionview_datehelper_time_in_words_day_plural: %d días +actionview_datehelper_time_in_words_hour_about: unha hora aproximadamente +actionview_datehelper_time_in_words_hour_about_plural: aproximadamente %d horas +actionview_datehelper_time_in_words_hour_about_single: unha hora aproximadamente +actionview_datehelper_time_in_words_minute: 1 minuto +actionview_datehelper_time_in_words_minute_half: medio minuto +actionview_datehelper_time_in_words_minute_less_than: menos dun minuto +actionview_datehelper_time_in_words_minute_plural: %d minutos +actionview_datehelper_time_in_words_minute_single: 1 minuto +actionview_datehelper_time_in_words_second_less_than: menos dun segundo +actionview_datehelper_time_in_words_second_less_than_plural: menos de %d segundos +actionview_instancetag_blank_option: Por favor seleccione +activerecord_error_accepted: debe ser aceptado +activerecord_error_blank: non pode estar en branco +activerecord_error_circular_dependency: Esta relación podería crear unha dependencia circular +activerecord_error_confirmation: a confirmación non coincide +activerecord_error_empty: non pode estar baleiro +activerecord_error_exclusion: está reservado +activerecord_error_greater_than_start_date: debe ser posterior á data de comezo +activerecord_error_inclusion: non está incluído nas lista +activerecord_error_invalid: non é válido +activerecord_error_not_a_date: non é una data válida +activerecord_error_not_a_number: non é un número +activerecord_error_not_same_project: non pertence ao mesmo proxecto +activerecord_error_taken: xa está sendo usado +activerecord_error_too_long: é demasiado longo +activerecord_error_too_short: é demasiado curto +activerecord_error_wrong_length: a lonxitude é incorrecta +button_activate: Activar +button_add: Engadir +button_annotate: Anotar +button_apply: Aceptar +button_archive: Arquivar +button_back: Atrás +button_cancel: Cancelar +button_change: Cambiar +button_change_password: Cambiar contrasinal +button_check_all: Seleccionar todo +button_clear: Anular +button_configure: Configurar +button_copy: Copiar +button_create: Crear +button_delete: Borrar +button_download: Descargar +button_edit: Modificar +button_list: Listar +button_lock: Bloquear +button_log_time: Tempo dedicado +button_login: Conexión +button_move: Mover +button_quote: Citar +button_rename: Renomear +button_reply: Respostar +button_reset: Restablecer +button_rollback: Volver a esta versión +button_save: Gardar +button_sort: Ordenar +button_submit: Aceptar +button_test: Probar +button_unarchive: Desarquivar +button_uncheck_all: Non seleccionar nada +button_unlock: Desbloquear +button_unwatch: Non monitorizar +button_update: Actualizar +button_view: Ver +button_watch: Monitorizar +default_activity_design: Deseño +default_activity_development: Desenvolvemento +default_doc_category_tech: Documentación técnica +default_doc_category_user: Documentación de usuario +default_issue_status_assigned: Asignada +default_issue_status_closed: Pechada +default_issue_status_feedback: Comentarios +default_issue_status_new: Nova +default_issue_status_rejected: Rexeitada +default_issue_status_resolved: Resolta +default_priority_high: Alta +default_priority_immediate: Inmediata +default_priority_low: Baixa +default_priority_normal: Normal +default_priority_urgent: Urxente +default_role_developper: Desenvolvedor +default_role_manager: Xefe de proxecto +default_role_reporter: Informador +default_tracker_bug: Erros +default_tracker_feature: Tarefas +default_tracker_support: Soporte +enumeration_activities: Actividades (tempo dedicado) +enumeration_doc_categories: Categorías do documento +enumeration_issue_priorities: Prioridade das peticións +error_can_t_load_default_data: "Non se puido cargar a configuración por defecto: %s" +error_issue_not_found_in_project: 'A petición non se atopa ou non está asociada a este proxecto' +error_scm_annotate: "Non existe a entrada ou non se puido anotar" +error_scm_command_failed: "Aconteceu un erro ao acceder ó repositorio: %s" +error_scm_not_found: "A entrada e/ou revisión non existe no repositorio." +field_account: Conta +field_activity: Actividade +field_admin: Administrador +field_assignable: Pódense asignar peticións a este perfil +field_assigned_to: Asignado a +field_attr_firstname: Atributo do nome +field_attr_lastname: Atributo do apelido +field_attr_login: Atributo do identificador +field_attr_mail: Atributo do Email +field_auth_source: Modo de identificación +field_author: Autor +field_base_dn: DN base +field_category: Categoría +field_column_names: Columnas +field_comments: Comentario +field_comments_sorting: Mostrar comentarios +field_created_on: Creado +field_default_value: Estado por defecto +field_delay: Retraso +field_description: Descrición +field_done_ratio: %% Realizado +field_downloads: Descargas +field_due_date: Data fin +field_effective_date: Data +field_estimated_hours: Tempo estimado +field_field_format: Formato +field_filename: Arquivo +field_filesize: Tamaño +field_firstname: Nome +field_fixed_version: Versión prevista +field_hide_mail: Ocultar a miña dirección de correo +field_homepage: Sitio web +field_host: Anfitrión +field_hours: Horas +field_identifier: Identificador +field_is_closed: Petición resolta +field_is_default: Estado por defecto +field_is_filter: Usado como filtro +field_is_for_all: Para todos os proxectos +field_is_in_chlog: Consultar as peticións no histórico +field_is_in_roadmap: Consultar as peticións na planificación +field_is_public: Público +field_is_required: Obrigatorio +field_issue: Petición +field_issue_to_id: Petición relacionada +field_language: Idioma +field_last_login_on: Última conexión +field_lastname: Apelido +field_login: Identificador +field_mail: Correo electrónico +field_mail_notification: Notificacións por correo +field_max_length: Lonxitude máxima +field_min_length: Lonxitude mínima +field_name: Nome +field_new_password: Novo contrasinal +field_notes: Notas +field_onthefly: Creación do usuario "ao voo" +field_parent: Proxecto pai +field_parent_title: Páxina pai +field_password: Contrasinal +field_password_confirmation: Confirmación +field_port: Porto +field_possible_values: Valores posibles +field_priority: Prioridade +field_project: Proxecto +field_redirect_existing_links: Redireccionar enlaces existentes +field_regexp: Expresión regular +field_role: Perfil +field_searchable: Incluír nas búsquedas +field_spent_on: Data +field_start_date: Data de inicio +field_start_page: Páxina principal +field_status: Estado +field_subject: Tema +field_subproject: Proxecto secundario +field_summary: Resumo +field_time_zone: Zona horaria +field_title: Título +field_tracker: Tipo +field_type: Tipo +field_updated_on: Actualizado +field_url: URL +field_user: Usuario +field_value: Valor +field_version: Versión +general_csv_decimal_separator: ',' +general_csv_encoding: ISO-8859-15 +general_csv_separator: ';' +general_day_names: Luns,Martes,Mércores,Xoves,Venres,Sábado,Domingo +general_first_day_of_week: '1' +general_fmt_age: %d ano +general_fmt_age_plural: %d anos +general_fmt_date: %%d/%%m/%%Y +general_fmt_datetime: %%d/%%m/%%Y %%H:%%M +general_fmt_datetime_short: %%d/%%m %%H:%%M +general_fmt_time: %%H:%%M +general_lang_name: 'Galego' +general_pdf_encoding: ISO-8859-15 +general_text_No: 'Non' +general_text_Yes: 'Si' +general_text_no: 'non' +general_text_yes: 'si' +gui_validation_error: 1 erro +gui_validation_error_plural: %d erros +label_activity: Actividade +label_add_another_file: Engadir outro arquivo +label_add_note: Engadir unha nota +label_added: engadido +label_added_time_by: Engadido por %s fai %s +label_administration: Administración +label_age: Idade +label_ago: fai +label_all: todos +label_all_time: todo o tempo +label_all_words: Tódalas palabras +label_and_its_subprojects: %s e proxectos secundarios +label_applied_status: Aplicar estado +label_assigned_to_me_issues: Peticións asignadas a min +label_associated_revisions: Revisións asociadas +label_attachment: Arquivo +label_attachment_delete: Borrar o arquivo +label_attachment_new: Novo arquivo +label_attachment_plural: Arquivos +label_attribute: Atributo +label_attribute_plural: Atributos +label_auth_source: Modo de autenticación +label_auth_source_new: Novo modo de autenticación +label_auth_source_plural: Modos de autenticación +label_authentication: Autenticación +label_blocked_by: bloqueado por +label_blocks: bloquea a +label_board: Foro +label_board_new: Novo foro +label_board_plural: Foros +label_boolean: Booleano +label_browse: Ollar +label_bulk_edit_selected_issues: Editar as peticións seleccionadas +label_calendar: Calendario +label_change_log: Cambios +label_change_plural: Cambios +label_change_properties: Cambiar propiedades +label_change_status: Cambiar o estado +label_change_view_all: Ver tódolos cambios +label_changes_details: Detalles de tódolos cambios +label_changeset_plural: Cambios +label_chronological_order: En orde cronolóxica +label_closed_issues: pechada +label_closed_issues_plural: pechadas +label_comment: Comentario +label_comment_add: Engadir un comentario +label_comment_added: Comentario engadido +label_comment_delete: Borrar comentarios +label_comment_plural: Comentarios +label_commits_per_author: Commits por autor +label_commits_per_month: Commits por mes +label_confirmation: Confirmación +label_contains: conten +label_copied: copiado +label_copy_workflow_from: Copiar fluxo de traballo dende +label_current_status: Estado actual +label_current_version: Versión actual +label_custom_field: Campo personalizado +label_custom_field_new: Novo campo personalizado +label_custom_field_plural: Campos personalizados +label_date: Data +label_date_from: Dende +label_date_range: Rango de datas +label_date_to: Ata +label_day_plural: días +label_default: Por defecto +label_default_columns: Columnas por defecto +label_deleted: suprimido +label_details: Detalles +label_diff_inline: en liña +label_diff_side_by_side: cara a cara +label_disabled: deshabilitado +label_display_per_page: 'Por páxina: %s' +label_document: Documento +label_document_added: Documento engadido +label_document_new: Novo documento +label_document_plural: Documentos +label_download: %d Descarga +label_download_plural: %d Descargas +label_downloads_abbr: D/L +label_duplicated_by: duplicada por +label_duplicates: duplicada de +label_end_to_end: fin a fin +label_end_to_start: fin a principio +label_enumeration_new: Novo valor +label_enumerations: Listas de valores +label_environment: Entorno +label_equals: igual +label_example: Exemplo +label_export_to: 'Exportar a:' +label_f_hour: %.2f hora +label_f_hour_plural: %.2f horas +label_feed_plural: Feeds +label_feeds_access_key_created_on: Clave de acceso por RSS creada fai %s +label_file_added: Arquivo engadido +label_file_plural: Arquivos +label_filter_add: Engadir o filtro +label_filter_plural: Filtros +label_float: Flotante +label_follows: posterior a +label_gantt: Gantt +label_general: Xeral +label_generate_key: Xerar clave +label_help: Axuda +label_history: Histórico +label_home: Inicio +label_in: en +label_in_less_than: en menos que +label_in_more_than: en mais que +label_incoming_emails: Correos entrantes +label_index_by_date: Índice por data +label_index_by_title: Índice por título +label_information: Información +label_information_plural: Información +label_integer: Número +label_internal: Interno +label_issue: Petición +label_issue_added: Petición engadida +label_issue_category: Categoría das peticións +label_issue_category_new: Nova categoría +label_issue_category_plural: Categorías das peticións +label_issue_new: Nova petición +label_issue_plural: Peticións +label_issue_status: Estado da petición +label_issue_status_new: Novo estado +label_issue_status_plural: Estados das peticións +label_issue_tracking: Peticións +label_issue_updated: Petición actualizada +label_issue_view_all: Ver tódalas peticións +label_issue_watchers: Seguidores +label_issues_by: Peticións por %s +label_jump_to_a_project: Ir ao proxecto... +label_language_based: Baseado no idioma +label_last_changes: últimos %d cambios +label_last_login: Última conexión +label_last_month: último mes +label_last_n_days: últimos %d días +label_last_updates: Actualizado +label_last_updates_plural: %d Actualizados +label_last_week: última semana +label_latest_revision: Última revisión +label_latest_revision_plural: Últimas revisións +label_ldap_authentication: Autenticación LDAP +label_less_than_ago: fai menos de +label_list: Lista +label_loading: Cargando... +label_logged_as: Conectado como +label_login: Conexión +label_logout: Desconexión +label_max_size: Tamaño máximo +label_me: eu mesmo +label_member: Membro +label_member_new: Novo membro +label_member_plural: Membros +label_message_last: Última mensaxe +label_message_new: Nova mensaxe +label_message_plural: Mensaxes +label_message_posted: Mensaxe engadida +label_min_max_length: Lonxitude mín - máx +label_modification: %d modificación +label_modification_plural: %d modificacións +label_modified: modificado +label_module_plural: Módulos +label_month: Mes +label_months_from: meses de +label_more: Mais +label_more_than_ago: fai mais de +label_my_account: A miña conta +label_my_page: A miña páxina +label_my_projects: Os meus proxectos +label_new: Novo +label_new_statuses_allowed: Novos estados autorizados +label_news: Noticia +label_news_added: Noticia engadida +label_news_latest: Últimas noticias +label_news_new: Nova noticia +label_news_plural: Noticias +label_news_view_all: Ver tódalas noticias +label_next: Seguinte +label_no_change_option: (Sen cambios) +label_no_data: Ningún dato a mostrar +label_nobody: ninguén +label_none: ningún +label_not_contains: non conten +label_not_equals: non igual +label_on: de +label_open_issues: aberta +label_open_issues_plural: abertas +label_optional_description: Descrición opcional +label_options: Opcións +label_overall_activity: Actividade global +label_overview: Vistazo +label_password_lost: ¿Esqueciches o contrasinal? +label_per_page: Por páxina +label_permissions: Permisos +label_permissions_report: Informe de permisos +label_personalize_page: Personalizar esta páxina +label_planning: Planificación +label_please_login: Conexión +label_plugins: Extensións +label_precedes: anterior a +label_preferences: Preferencias +label_preview: Previsualizar +label_previous: Anterior +label_project: Proxecto +label_project_all: Tódolos proxectos +label_project_latest: Últimos proxectos +label_project_new: Novo proxecto +label_project_plural: Proxectos +label_public_projects: Proxectos públicos +label_query: Consulta personalizada +label_query_new: Nova consulta +label_query_plural: Consultas personalizadas +label_read: Ler... +label_register: Rexistrar +label_registered_on: Inscrito o +label_registration_activation_by_email: activación de conta por correo +label_registration_automatic_activation: activación automática de conta +label_registration_manual_activation: activación manual de conta +label_related_issues: Peticións relacionadas +label_relates_to: relacionada con +label_relation_delete: Eliminar relación +label_relation_new: Nova relación +label_renamed: renomeado +label_reply_plural: Respostas +label_report: Informe +label_report_plural: Informes +label_reported_issues: Peticións rexistradas por min +label_repository: Repositorio +label_repository_plural: Repositorios +label_result_plural: Resultados +label_reverse_chronological_order: En orde cronolóxica inversa +label_revision: Revisión +label_revision_plural: Revisións +label_roadmap: Planificación +label_roadmap_due_in: Remata en %s +label_roadmap_no_issues: Non hai peticións para esta versión +label_roadmap_overdue: %s tarde +label_role: Perfil +label_role_and_permissions: Perfiles e permisos +label_role_new: Novo perfil +label_role_plural: Perfiles +label_scm: SCM +label_search: Búsqueda +label_search_titles_only: Buscar só en títulos +label_send_information: Enviar información da conta ó usuario +label_send_test_email: Enviar un correo de proba +label_settings: Configuración +label_show_completed_versions: Mostra as versións rematadas +label_sort_by: Ordenar por %s +label_sort_higher: Subir +label_sort_highest: Primeiro +label_sort_lower: Baixar +label_sort_lowest: Último +label_spent_time: Tempo dedicado +label_start_to_end: comezo a fin +label_start_to_start: comezo a comezo +label_statistics: Estatísticas +label_stay_logged_in: Lembrar contrasinal +label_string: Texto +label_subproject_plural: Proxectos secundarios +label_text: Texto largo +label_theme: Tema +label_this_month: este mes +label_this_week: esta semana +label_this_year: este ano +label_time_tracking: Control de tempo +label_today: hoxe +label_topic_plural: Temas +label_total: Total +label_tracker: Tipo +label_tracker_new: Novo tipo +label_tracker_plural: Tipos de peticións +label_updated_time: Actualizado fai %s +label_updated_time_by: Actualizado por %s fai %s +label_used_by: Utilizado por +label_user: Usuario +label_user_activity: "Actividade de %s" +label_user_mail_no_self_notified: "Non quero ser avisado de cambios feitos por min" +label_user_mail_option_all: "Para calquera evento en tódolos proxectos" +label_user_mail_option_none: "Só para elementos monitorizados ou relacionados comigo" +label_user_mail_option_selected: "Para calquera evento dos proxectos seleccionados..." +label_user_new: Novo usuario +label_user_plural: Usuarios +label_version: Versión +label_version_new: Nova versión +label_version_plural: Versións +label_view_diff: Ver diferencias +label_view_revisions: Ver as revisións +label_watched_issues: Peticións monitorizadas +label_week: Semana +label_wiki: Wiki +label_wiki_edit: Wiki edición +label_wiki_edit_plural: Wiki edicións +label_wiki_page: Wiki páxina +label_wiki_page_plural: Wiki páxinas +label_workflow: Fluxo de traballo +label_year: Ano +label_yesterday: onte +mail_body_account_activation_request: 'Inscribiuse un novo usuario (%s). A conta está pendente de aprobación:' +mail_body_account_information: Información sobre a súa conta +mail_body_account_information_external: Pode usar a súa conta "%s" para conectarse. +mail_body_lost_password: 'Para cambiar o seu contrasinal, faga clic no seguinte enlace:' +mail_body_register: 'Para activar a súa conta, faga clic no seguinte enlace:' +mail_body_reminder: "%d petición(s) asignadas a ti rematan nos próximos %d días:" +mail_subject_account_activation_request: Petición de activación de conta %s +mail_subject_lost_password: O teu contrasinal de %s +mail_subject_register: Activación da conta de %s +mail_subject_reminder: "%d petición(s) rematarán nos próximos días" +notice_account_activated: A súa conta foi activada. Xa pode conectarse. +notice_account_invalid_creditentials: Usuario ou contrasinal inválido. +notice_account_lost_email_sent: Enviouse un correo con instrucións para elixir un novo contrasinal. +notice_account_password_updated: Contrasinal modificado correctamente. +notice_account_pending: "A súa conta creouse e está pendente da aprobación por parte do administrador." +notice_account_register_done: Conta creada correctamente. Para activala, faga clic sobre o enlace que se lle enviou por correo. +notice_account_unknown_email: Usuario descoñecido. +notice_account_updated: Conta actualizada correctamente. +notice_account_wrong_password: Contrasinal incorrecto. +notice_can_t_change_password: Esta conta utiliza unha fonte de autenticación externa. Non é posible cambiar o contrasinal. +notice_default_data_loaded: Configuración por defecto cargada correctamente. +notice_email_error: Ocorreu un error enviando o correo (%s) +notice_email_sent: Enviouse un correo a %s +notice_failed_to_save_issues: "Imposible gravar %s petición(s) en %d seleccionado: %s." +notice_feeds_access_key_reseted: A súa clave de acceso para RSS reiniciouse. +notice_file_not_found: A páxina á que tenta acceder non existe. +notice_locking_conflict: Os datos modificáronse por outro usuario. +notice_no_issue_selected: "Ningunha petición seleccionada. Por favor, comprobe a petición que quere modificar" +notice_not_authorized: Non ten autorización para acceder a esta páxina. +notice_successful_connection: Conexión correcta. +notice_successful_create: Creación correcta. +notice_successful_delete: Borrado correcto. +notice_successful_update: Modificación correcta. +notice_unable_delete_version: Non se pode borrar a versión +permission_add_issue_notes: Engadir notas +permission_add_issue_watchers: Engadir seguidores +permission_add_issues: Engadir peticións +permission_add_messages: Enviar mensaxes +permission_browse_repository: Ollar repositorio +permission_comment_news: Comentar noticias +permission_commit_access: Acceso de escritura +permission_delete_issues: Borrar peticións +permission_delete_messages: Borrar mensaxes +permission_delete_own_messages: Borrar mensaxes propios +permission_delete_wiki_pages: Borrar páxinas wiki +permission_delete_wiki_pages_attachments: Borrar arquivos +permission_edit_issue_notes: Modificar notas +permission_edit_issues: Modificar peticións +permission_edit_messages: Modificar mensaxes +permission_edit_own_issue_notes: Modificar notas propias +permission_edit_own_messages: Editar mensaxes propios +permission_edit_own_time_entries: Modificar tempos dedicados propios +permission_edit_project: Modificar proxecto +permission_edit_time_entries: Modificar tempos dedicados +permission_edit_wiki_pages: Modificar páxinas wiki +permission_log_time: Anotar tempo dedicado +permission_manage_boards: Administrar foros +permission_manage_categories: Administrar categorías de peticións +permission_manage_documents: Administrar documentos +permission_manage_files: Administrar arquivos +permission_manage_issue_relations: Administrar relación con outras peticións +permission_manage_members: Administrar membros +permission_manage_news: Administrar noticias +permission_manage_public_queries: Administrar consultas públicas +permission_manage_repository: Administrar repositorio +permission_manage_versions: Administrar versións +permission_manage_wiki: Administrar wiki +permission_move_issues: Mover peticións +permission_protect_wiki_pages: Protexer páxinas wiki +permission_rename_wiki_pages: Renomear páxinas wiki +permission_save_queries: Gravar consultas +permission_select_project_modules: Seleccionar módulos do proxecto +permission_view_calendar: Ver calendario +permission_view_changesets: Ver cambios +permission_view_documents: Ver documentos +permission_view_files: Ver arquivos +permission_view_gantt: Ver diagrama de Gantt +permission_view_issue_watchers: Ver lista de seguidores +permission_view_messages: Ver mensaxes +permission_view_time_entries: Ver tempo dedicado +permission_view_wiki_edits: Ver histórico do wiki +permission_view_wiki_pages: Ver wiki +project_module_boards: Foros +project_module_documents: Documentos +project_module_files: Arquivos +project_module_issue_tracking: Peticións +project_module_news: Noticias +project_module_repository: Repositorio +project_module_time_tracking: Control de tempo +project_module_wiki: Wiki +setting_activity_days_default: Días a mostrar na actividade do proxecto +setting_app_subtitle: Subtítulo da aplicación +setting_app_title: Título da aplicación +setting_attachment_max_size: Tamaño máximo do arquivo +setting_autofetch_changesets: Autorechear os commits do repositorio +setting_autologin: Conexión automática +setting_bcc_recipients: Ocultar as copias de carbón (bcc) +setting_commit_fix_keywords: Palabras clave para a corrección +setting_commit_logs_encoding: Codificación das mensaxes de commit +setting_commit_ref_keywords: Palabras clave para a referencia +setting_cross_project_issue_relations: Permitir relacionar peticións de distintos proxectos +setting_date_format: Formato da data +setting_default_language: Idioma por defecto +setting_default_projects_public: Os proxectos novos son públicos por defecto +setting_diff_max_lines_displayed: Número máximo de diferencias mostradas +setting_display_subprojects_issues: Mostrar por defecto peticións de prox. secundarios no principal +setting_emails_footer: Pe de mensaxes +setting_enabled_scm: Activar SCM +setting_feeds_limit: Límite de contido para sindicación +setting_gravatar_enabled: Usar iconas de usuario (Gravatar) +setting_host_name: Nome e ruta do servidor +setting_issue_list_default_columns: Columnas por defecto para a lista de peticións +setting_issues_export_limit: Límite de exportación de peticións +setting_login_required: Requírese identificación +setting_mail_from: Correo dende o que enviar mensaxes +setting_mail_handler_api_enabled: Activar SW para mensaxes entrantes +setting_mail_handler_api_key: Clave da API +setting_per_page_options: Obxectos por páxina +setting_plain_text_mail: só texto plano (non HTML) +setting_protocol: Protocolo +setting_repositories_encodings: Codificacións do repositorio +setting_self_registration: Rexistro permitido +setting_sequential_project_identifiers: Xerar identificadores de proxecto +setting_sys_api_enabled: Habilitar SW para a xestión do repositorio +setting_text_formatting: Formato de texto +setting_time_format: Formato de hora +setting_user_format: Formato de nome de usuario +setting_welcome_text: Texto de benvida +setting_wiki_compression: Compresión do historial do Wiki +status_active: activo +status_locked: bloqueado +status_registered: rexistrado +text_are_you_sure: ¿Está seguro? +text_assign_time_entries_to_project: Asignar as horas ó proxecto +text_caracters_maximum: %d caracteres como máximo. +text_caracters_minimum: %d caracteres como mínimo +text_comma_separated: Múltiples valores permitidos (separados por coma). +text_default_administrator_account_changed: Conta de administrador por defecto modificada +text_destroy_time_entries: Borrar as horas +text_destroy_time_entries_question: Existen %.02f horas asignadas á petición que quere borrar. ¿Que quere facer ? +text_diff_truncated: '... Diferencia truncada por exceder o máximo tamaño visualizable.' +text_email_delivery_not_configured: "O envío de correos non está configurado, e as notificacións desactiváronse. \n Configure o servidor de SMTP en config/email.yml e reinicie a aplicación para activar os cambios." +text_enumeration_category_reassign_to: 'Reasignar ó seguinte valor:' +text_enumeration_destroy_question: '%d obxectos con este valor asignado.' +text_file_repository_writable: Pódese escribir no repositorio +text_issue_added: Petición %s engadida por %s. +text_issue_category_destroy_assignments: Deixar as peticións sen categoría +text_issue_category_destroy_question: Algunhas peticións (%d) están asignadas a esta categoría. ¿Que desexa facer? +text_issue_category_reassign_to: Reasignar as peticións á categoría +text_issue_updated: A petición %s actualizouse por %s. +text_issues_destroy_confirmation: '¿Seguro que quere borrar as peticións seleccionadas?' +text_issues_ref_in_commit_messages: Referencia e petición de corrección nas mensaxes +text_journal_changed: cambiado de %s a %s +text_journal_deleted: suprimido +text_journal_set_to: fixado a %s +text_length_between: Lonxitude entre %d e %d caracteres. +text_load_default_configuration: Cargar a configuración por defecto +text_min_max_length_info: 0 para ningunha restrición +text_no_configuration_data: "Inda non se configuraron perfiles, nin tipos, estados e fluxo de traballo asociado a peticións. Recoméndase encarecidamente cargar a configuración por defecto. Unha vez cargada, poderá modificala." +text_project_destroy_confirmation: ¿Estás seguro de querer eliminar o proxecto? +text_project_identifier_info: 'Letras minúsculas (a-z), números e signos de puntuación permitidos.
    Unha vez gardado, o identificador non pode modificarse.' +text_reassign_time_entries: 'Reasignar as horas a esta petición:' +text_regexp_info: ex. ^[A-Z0-9]+$ +text_repository_usernames_mapping: "Estableza a correspondencia entre os usuarios de Redmine e os presentes no log do repositorio.\nOs usuarios co mesmo nome ou correo en Redmine e no repositorio serán asociados automaticamente." +text_rmagick_available: RMagick dispoñible (opcional) +text_select_mail_notifications: Seleccionar os eventos a notificar +text_select_project_modules: 'Seleccione os módulos a activar para este proxecto:' +text_status_changed_by_changeset: Aplicado nos cambios %s +text_subprojects_destroy_warning: 'Os proxectos secundarios: %s tamén se eliminarán' +text_tip_task_begin_day: tarefa que comeza este día +text_tip_task_begin_end_day: tarefa que comeza e remata este día +text_tip_task_end_day: tarefa que remata este día +text_tracker_no_workflow: Non hai ningún fluxo de traballo definido para este tipo de petición +text_unallowed_characters: Caracteres non permitidos +text_user_mail_option: "Dos proxectos non seleccionados, só recibirá notificacións sobre elementos monitorizados ou elementos nos que estea involucrado (por exemplo, peticións das que vostede sexa autor ou asignadas a vostede)." +text_user_wrote: '%s escribiu:' +text_wiki_destroy_confirmation: ¿Seguro que quere borrar o wiki e todo o seu contido? +text_workflow_edit: Seleccionar un fluxo de traballo para actualizar +warning_attachments_not_saved: "%d file(s) could not be saved." +field_editable: Editable +text_plugin_assets_writable: Plugin assets directory writable +label_display: Display +button_create_and_continue: Create and continue +text_custom_field_possible_values_info: 'One line for each value' +setting_repository_log_display_limit: Maximum number of revisions displayed on file log +field_identity_url: OpenID URL +setting_openid: Allow OpenID login and registration +label_login_with_open_id_option: or login with OpenID +field_watcher: Watcher diff --git a/lang/he.yml b/lang/he.yml index f95843b85..7a1519ae0 100644 --- a/lang/he.yml +++ b/lang/he.yml @@ -236,7 +236,7 @@ label_register: הרשמה label_password_lost: אבדה הסיסמה? label_home: דף הבית label_my_page: הדף שלי -label_my_account: השבון שלי +label_my_account: החשבון שלי label_my_projects: הפרויקטים שלי label_administration: אדמיניסטרציה label_login: התחבר @@ -292,7 +292,7 @@ label_confirmation: אישור label_export_to: יצא ל label_read: קרא... label_public_projects: פרויקטים פומביים -label_open_issues: פותח +label_open_issues: פתוח label_open_issues_plural: פתוחים label_closed_issues: סגור label_closed_issues_plural: סגורים @@ -308,7 +308,7 @@ label_used_by: בשימוש ע"י label_details: פרטים label_add_note: הוסף הערה label_per_page: לכל דף -label_calendar: לו"ח שנה +label_calendar: לוח שנה label_months_from: חודשים מ label_gantt: גאנט label_internal: פנימי @@ -357,7 +357,7 @@ label_sort_higher: הזז למעלה label_sort_lower: הזז למטה label_sort_lowest: הזז לתחתית label_roadmap: מפת הדרכים -label_roadmap_due_in: %s נגמר בעוד +label_roadmap_due_in: נגמר בעוד %s label_roadmap_overdue: %s מאחר label_roadmap_no_issues: אין נושאים לגירסא זו label_search: חפש @@ -421,8 +421,8 @@ label_send_information: שלח מידע על חשבון למשתמש label_year: שנה label_month: חודש label_week: שבוע -label_date_from: מאת -label_date_to: אל +label_date_from: מתאריך +label_date_to: עד label_language_based: מבוסס שפה label_sort_by: מין לפי %s label_send_test_email: שלח דו"ל בדיקה @@ -487,7 +487,7 @@ 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_tip_task_begin_end_day: מטלה המתחילה ומסתיימת היום text_project_identifier_info: 'אותיות לטיניות (a-z), מספרים ומקפים.
    ברגע שנשמר, לא ניתן לשנות את המזהה.' text_caracters_maximum: מקסימום %d תווים. text_length_between: אורך בין %d ל %d תווים. @@ -618,27 +618,92 @@ label_overall_activity: פעילות כוללת setting_default_projects_public: פרויקטים חדשים הינם פומביים כברירת מחדל error_scm_annotate: "הכניסה לא קיימת או שלא ניתן לתאר אותה." label_planning: תכנון -text_subprojects_destroy_warning: 'Its subproject(s): %s will be also deleted.' -label_and_its_subprojects: %s and its subprojects -mail_body_reminder: "%d issue(s) that are assigned to you are due in the next %d days:" -mail_subject_reminder: "%d issue(s) due in the next days" -text_user_wrote: '%s wrote:' -label_duplicated_by: duplicated by -setting_enabled_scm: Enabled SCM -text_enumeration_category_reassign_to: 'Reassign them to this value:' -text_enumeration_destroy_question: '%d objects are assigned to this value.' -label_incoming_emails: Incoming emails -label_generate_key: Generate a key +text_subprojects_destroy_warning: 'תת הפרויקט\ים: %s ימחקו גם כן.' +label_and_its_subprojects: %s וכל תת הפרויקטים שלו +mail_body_reminder: "%d נושאים שמיועדים אליך מיועדים להגשה בתוך %d ימים:" +mail_subject_reminder: "%d נושאים מיעדים להגשה בימים הקרובים" +text_user_wrote: '%s כתב:' +label_duplicated_by: שוכפל ע"י +setting_enabled_scm: אפשר SCM +text_enumeration_category_reassign_to: 'הצב מחדש לערך הזה:' +text_enumeration_destroy_question: '%d אוביקטים מוצבים לערך זה.' +label_incoming_emails: דוא"ל נכנס +label_generate_key: יצר מפתח setting_mail_handler_api_enabled: Enable WS for incoming emails -setting_mail_handler_api_key: API key +setting_mail_handler_api_key: מפתח API text_email_delivery_not_configured: "Email delivery is not configured, and notifications are disabled.\nConfigure your SMTP server in config/email.yml and restart the application to enable them." -field_parent_title: Parent page -label_issue_watchers: Watchers +field_parent_title: דף אב +label_issue_watchers: צופים setting_commit_logs_encoding: Commit messages encoding -button_quote: Quote +button_quote: צטט setting_sequential_project_identifiers: Generate sequential project identifiers -notice_unable_delete_version: Unable to delete version -label_renamed: renamed -label_copied: copied -setting_repositories_cache_directory: Cache directory for repositories -field_cache: Local cache +notice_unable_delete_version: לא ניתן למחוק גירסא +label_renamed: השם שונה +label_copied: הועתק +setting_plain_text_mail: טקסט פשוט בלבד (ללא HTML) +permission_view_files: צפה בקבצים +permission_edit_issues: ערוך נושאים +permission_edit_own_time_entries: ערוך את לוג הזמן של עצמך +permission_manage_public_queries: נהל שאילתות פומביות +permission_add_issues: הוסף נושא +permission_log_time: תעד זמן שבוזבז +permission_view_changesets: צפה בקבוצות שינויים +permission_view_time_entries: צפה בזמן שבוזבז +permission_manage_versions: נהל גירסאות +permission_manage_wiki: נהל wiki +permission_manage_categories: נהל קטגוריות נושאים +permission_protect_wiki_pages: הגן כל דפי wiki +permission_comment_news: הגב על החדשות +permission_delete_messages: מחק הודעות +permission_select_project_modules: בחר מודולי פרויקט +permission_manage_documents: נהל מסמכים +permission_edit_wiki_pages: ערוך דפי wiki +permission_add_issue_watchers: הוסף צופים +permission_view_gantt: צפה בגאנט +permission_move_issues: הזז נושאים +permission_manage_issue_relations: נהל יחס בין נושאים +permission_delete_wiki_pages: מחק דפי wiki +permission_manage_boards: נהל לוחות +permission_delete_wiki_pages_attachments: מחק דבוקות +permission_view_wiki_edits: צפה בהיסטורית wiki +permission_add_messages: הצב הודעות +permission_view_messages: צפה בהודעות +permission_manage_files: נהל קבצים +permission_edit_issue_notes: ערוך רשימות +permission_manage_news: נהל חדשות +permission_view_calendar: צפה בלוח השנה +permission_manage_members: נהל חברים +permission_edit_messages: ערוך הודעות +permission_delete_issues: מחק נושאים +permission_view_issue_watchers: צפה ברשימה צופים +permission_manage_repository: נהל מאגר +permission_commit_access: Commit access +permission_browse_repository: סייר במאגר +permission_view_documents: צפה במסמכים +permission_edit_project: ערוך פרויקט +permission_add_issue_notes: Add notes +permission_save_queries: שמור שאילתות +permission_view_wiki_pages: צפה ב-wiki +permission_rename_wiki_pages: שנה שם של דפי wiki +permission_edit_time_entries: ערוך רישום זמנים +permission_edit_own_issue_notes: Edit own notes +setting_gravatar_enabled: Use Gravatar user icons +label_example: דוגמא +text_repository_usernames_mapping: "Select ou update the Redmine user mapped to each username found in the repository log.\nUsers with the same Redmine and repository username or email are automatically mapped." +permission_edit_own_messages: ערוך הודעות של עצמך +permission_delete_own_messages: מחק הודעות של עצמך +label_user_activity: "הפעילות של %s" +label_updated_time_by: עודכן ע"י %s לפני %s +setting_diff_max_lines_displayed: Max number of diff lines displayed +text_plugin_assets_writable: Plugin assets directory writable +text_diff_truncated: '... This diff was truncated because it exceeds the maximum size that can be displayed.' +warning_attachments_not_saved: "%d file(s) could not be saved." +button_create_and_continue: Create and continue +text_custom_field_possible_values_info: 'One line for each value' +label_display: Display +field_editable: Editable +setting_repository_log_display_limit: Maximum number of revisions displayed on file log +field_identity_url: OpenID URL +setting_openid: Allow OpenID login and registration +label_login_with_open_id_option: or login with OpenID +field_watcher: Watcher diff --git a/lang/hu.yml b/lang/hu.yml index 28008aabb..697b26a1c 100644 --- a/lang/hu.yml +++ b/lang/hu.yml @@ -641,5 +641,70 @@ setting_sequential_project_identifiers: Szekvenciális projekt azonosítók gene notice_unable_delete_version: A verziót nem lehet törölni label_renamed: átnevezve label_copied: lemásolva -setting_repositories_cache_directory: Cache directory for repositories -field_cache: Local cache +setting_plain_text_mail: csak szöveg (nem HTML) +permission_view_files: Fájlok megtekintése +permission_edit_issues: Feladatok szerkesztése +permission_edit_own_time_entries: Saját időnapló szerkesztése +permission_manage_public_queries: Nyilvános kérések kezelése +permission_add_issues: Feladat felvétele +permission_log_time: Idő rögzítése +permission_view_changesets: Változáskötegek megtekintése +permission_view_time_entries: Időrögzítések megtekintése +permission_manage_versions: Verziók kezelése +permission_manage_wiki: Wiki kezelése +permission_manage_categories: Feladat kategóriák kezelése +permission_protect_wiki_pages: Wiki oldalak védelme +permission_comment_news: Hírek kommentelése +permission_delete_messages: Üzenetek törlése +permission_select_project_modules: Projekt modulok kezelése +permission_manage_documents: Dokumentumok kezelése +permission_edit_wiki_pages: Wiki oldalak szerkesztése +permission_add_issue_watchers: Megfigyelők felvétele +permission_view_gantt: Gannt diagramm megtekintése +permission_move_issues: Feladatok mozgatása +permission_manage_issue_relations: Feladat kapcsolatok kezelése +permission_delete_wiki_pages: Wiki oldalak törlése +permission_manage_boards: Fórumok kezelése +permission_delete_wiki_pages_attachments: Csatolmányok törlése +permission_view_wiki_edits: Wiki történet megtekintése +permission_add_messages: Üzenet beküldése +permission_view_messages: Üzenetek megtekintése +permission_manage_files: Fájlok kezelése +permission_edit_issue_notes: Jegyzetek szerkesztése +permission_manage_news: Hírek kezelése +permission_view_calendar: Naptár megtekintése +permission_manage_members: Tagok kezelése +permission_edit_messages: Üzenetek szerkesztése +permission_delete_issues: Feladatok törlése +permission_view_issue_watchers: Megfigyelők listázása +permission_manage_repository: Tárolók kezelése +permission_commit_access: Commit hozzáférés +permission_browse_repository: Tároló böngészése +permission_view_documents: Dokumetumok megtekintése +permission_edit_project: Projekt szerkesztése +permission_add_issue_notes: Jegyzet rögzítése +permission_save_queries: Kérések mentése +permission_view_wiki_pages: Wiki megtekintése +permission_rename_wiki_pages: Wiki oldalak átnevezése +permission_edit_time_entries: Időnaplók szerkesztése +permission_edit_own_issue_notes: Saját jegyzetek szerkesztése +setting_gravatar_enabled: Felhasználói fényképek engedélyezése +label_example: Példa +text_repository_usernames_mapping: "Állítsd be a felhasználó összerendeléseket a Redmine, és a tároló logban található felhasználók között.\nAz azonos felhasználó nevek összerendelése automatikusan megtörténik." +permission_edit_own_messages: Saját üzenetek szerkesztése +permission_delete_own_messages: Saját üzenetek törlése +label_user_activity: "%s tevékenységei" +label_updated_time_by: "Módosította %s ennyivel ezelőtt: %s" +text_diff_truncated: '... A diff fájl vége nem jelenik meg, mert hosszab, mint a megjeleníthető sorok száma.' +setting_diff_max_lines_displayed: A megjelenítendő sorok száma (maximum) a diff fájloknál +text_plugin_assets_writable: Plugin eszközök könyvtár írható +warning_attachments_not_saved: "%d fájl mentése nem sikerült." +button_create_and_continue: Létrehozás és folytatás +text_custom_field_possible_values_info: 'Értékenként egy sor' +label_display: Megmutat +field_editable: Szerkeszthető +setting_repository_log_display_limit: Maximum hány revízió jelenjen meg a fájl logban +field_identity_url: OpenID URL +setting_openid: Allow OpenID login and registration +label_login_with_open_id_option: or login with OpenID +field_watcher: Watcher diff --git a/lang/it.yml b/lang/it.yml index 20e53472c..418f3529d 100644 --- a/lang/it.yml +++ b/lang/it.yml @@ -24,8 +24,8 @@ activerecord_error_exclusion: è riservato activerecord_error_invalid: non è valido activerecord_error_confirmation: non coincide con la conferma activerecord_error_accepted: deve essere accettato -activerecord_error_empty: non puo' essere vuoto -activerecord_error_blank: non puo' essere blank +activerecord_error_empty: non può essere vuoto +activerecord_error_blank: non può essere lasciato in bianco activerecord_error_too_long: è troppo lungo/a activerecord_error_too_short: è troppo corto/a activerecord_error_wrong_length: è della lunghezza sbagliata @@ -108,7 +108,7 @@ field_value: Valore field_category: Categoria field_title: Titolo field_project: Progetto -field_issue: Issue +field_issue: Segnalazione field_status: Stato field_notes: Note field_is_closed: Chiude la segnalazione @@ -169,7 +169,7 @@ field_default_value: Stato predefinito setting_app_title: Titolo applicazione setting_app_subtitle: Sottotitolo applicazione setting_welcome_text: Testo di benvenuto -setting_default_language: Lingua di default +setting_default_language: Lingua predefinita setting_login_required: Autenticazione richiesta setting_self_registration: Auto-registrazione abilitata setting_attachment_max_size: Massima dimensione allegati @@ -177,12 +177,12 @@ setting_issues_export_limit: Limite esportazione segnalazioni setting_mail_from: Indirizzo sorgente e-mail setting_host_name: Nome host setting_text_formatting: Formattazione testo -setting_wiki_compression: Compressione di storia di Wiki +setting_wiki_compression: Comprimi cronologia wiki setting_feeds_limit: Limite contenuti del feed setting_autofetch_changesets: Acquisisci automaticamente le commit setting_sys_api_enabled: Abilita WS per la gestione del repository -setting_commit_ref_keywords: Referencing keywords -setting_commit_fix_keywords: Fixing keywords +setting_commit_ref_keywords: Parole chiave riferimento +setting_commit_fix_keywords: Parole chiave chiusura setting_autologin: Login automatico setting_date_format: Formato data setting_cross_project_issue_relations: Consenti la creazione di relazioni tra segnalazioni in progetti differenti @@ -353,7 +353,7 @@ label_sort_lower: Giù label_sort_lowest: Sposta in fondo label_roadmap: Roadmap label_roadmap_due_in: Da ultimare in %s -label_roadmap_overdue: %s late +label_roadmap_overdue: %s di ritardo label_roadmap_no_issues: Nessuna segnalazione per questa versione label_search: Ricerca label_result_plural: Risultati @@ -482,7 +482,7 @@ text_length_between: Lunghezza compresa tra %d e %d caratteri. text_tracker_no_workflow: Nessun workflow definito per questo tracker text_unallowed_characters: Caratteri non permessi text_comma_separated: Valori multipli permessi (separati da virgola). -text_issues_ref_in_commit_messages: Referencing and fixing issues in commit messages +text_issues_ref_in_commit_messages: Segnalazioni di riferimento e chiusura nei messaggi di commit text_issue_added: "E' stata segnalata l'anomalia %s da %s." text_issue_updated: "L'anomalia %s e' stata aggiornata da %s." text_wiki_destroy_confirmation: Sicuro di voler cancellare questo wiki e tutti i suoi contenuti? @@ -530,7 +530,7 @@ label_default: Predefinito label_search_titles_only: Cerca solo nei titoli label_nobody: nessuno button_change_password: Modifica 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)." +text_user_mail_option: "Per i progetti non selezionati, riceverai solo le notifiche riguardanti le cose che osservi o nelle quali sei coinvolto (per esempio segnalazioni che hai creato o che ti sono state assegnate)." label_user_mail_option_selected: "Solo per gli eventi relativi ai progetti selezionati..." label_user_mail_option_all: "Per ogni evento relativo ad uno dei miei progetti" label_user_mail_option_none: "Solo per argomenti che osservo o che mi riguardano" @@ -548,7 +548,7 @@ mail_body_account_activation_request: 'Un nuovo utente (%s) ha effettuato la reg label_registration_automatic_activation: attivazione account automatica label_registration_manual_activation: attivazione account manuale notice_account_pending: "Il tuo account è stato creato ed è in attesa di attivazione da parte dell'amministratore." -field_time_zone: Time zone +field_time_zone: Fuso orario text_caracters_minimum: Deve essere lungo almeno %d caratteri. setting_bcc_recipients: Destinatari in copia nascosta (bcc) button_annotate: Annota @@ -557,10 +557,10 @@ field_searchable: Ricercabile label_display_per_page: 'Per pagina: %s' setting_per_page_options: Opzioni oggetti per pagina label_age: Età -notice_default_data_loaded: Configurazione di default caricata con successo. -text_load_default_configuration: Carica la configurazione di default +notice_default_data_loaded: Configurazione predefinita caricata con successo. +text_load_default_configuration: Carica la configurazione predefinita text_no_configuration_data: "Ruoli, tracker, stati delle segnalazioni e workflow non sono stati ancora configurati.\nIt is highly recommended to load the default configuration. You will be able to modify it once loaded." -error_can_t_load_default_data: "Non è stato possibile caricare la configurazione di default : %s" +error_can_t_load_default_data: "Non è stato possibile caricare la configurazione predefinita : %s" button_update: Aggiorna label_change_properties: Modifica le proprietà label_general: Generale @@ -578,7 +578,7 @@ label_document_added: Documenti aggiunti label_message_posted: Messaggi aggiunti label_file_added: File aggiunti label_news_added: Notizie aggiunte -project_module_boards: Boards +project_module_boards: Forum project_module_issue_tracking: Tracking delle segnalazioni project_module_wiki: Wiki project_module_files: File @@ -587,7 +587,7 @@ project_module_repository: Repository project_module_news: Notizie project_module_time_tracking: Time tracking text_file_repository_writable: Repository dei file scrivibile -text_default_administrator_account_changed: L'account amministrativo di default è stato modificato +text_default_administrator_account_changed: L'account amministrativo predefinito è stato modificato text_rmagick_available: RMagick disponibile (opzionale) button_configure: Configura label_plugins: Plugin @@ -630,7 +630,7 @@ text_enumeration_destroy_question: '%d oggetti hanno un assegnamento su questo v label_incoming_emails: E-mail in arrivo label_generate_key: Genera una chiave setting_mail_handler_api_enabled: Abilita WS per le e-mail in arrivo -setting_mail_handler_api_key: chiave API +setting_mail_handler_api_key: Chiave API text_email_delivery_not_configured: "La consegna via e-mail non è configurata e le notifiche sono disabilitate.\nConfigura il tuo server SMTP in config/email.yml e riavvia l'applicazione per abilitarle." field_parent_title: Parent page label_issue_watchers: Osservatori @@ -640,5 +640,70 @@ setting_sequential_project_identifiers: Genera progetti con identificativi in se notice_unable_delete_version: Impossibile cancellare la versione label_renamed: rinominato label_copied: copiato -field_cache: Local cache -setting_repositories_cache_directory: Cache directory for repositories +setting_plain_text_mail: Solo testo (non HTML) +permission_view_files: Vedi files +permission_edit_issues: Modifica segnalazioni +permission_edit_own_time_entries: Modifica propri time logs +permission_manage_public_queries: Gestisci query pubbliche +permission_add_issues: Aggiungi segnalazioni +permission_log_time: Segna tempo impiegato +permission_view_changesets: Vedi changesets +permission_view_time_entries: Vedi tempi impiegati +permission_manage_versions: Gestisci versioni +permission_manage_wiki: Gestisci wiki +permission_manage_categories: Gestisci categorie segnalazione +permission_protect_wiki_pages: Proteggi pagine wiki +permission_comment_news: Commenta notizie +permission_delete_messages: Elimina messaggi +permission_select_project_modules: Seleziona moduli progetto +permission_manage_documents: Gestisci documenti +permission_edit_wiki_pages: Modifica pagine wiki +permission_add_issue_watchers: Aggiungi osservatori +permission_view_gantt: Vedi diagrammi gantt +permission_move_issues: Muovi segnalazioni +permission_manage_issue_relations: Gestisci relazioni tra segnalazioni +permission_delete_wiki_pages: Elimina pagine wiki +permission_manage_boards: Gestisci forum +permission_delete_wiki_pages_attachments: Elimina allegati +permission_view_wiki_edits: Vedi cronologia wiki +permission_add_messages: Aggiungi messaggi +permission_view_messages: Vedi messaggi +permission_manage_files: Gestisci files +permission_edit_issue_notes: Modifica note +permission_manage_news: Gestisci notizie +permission_view_calendar: Vedi calendario +permission_manage_members: Gestisci membri +permission_edit_messages: Modifica messaggi +permission_delete_issues: Elimina segnalazioni +permission_view_issue_watchers: Vedi lista osservatori +permission_manage_repository: Gestisci repository +permission_commit_access: Permesso di commit +permission_browse_repository: Sfoglia repository +permission_view_documents: Vedi documenti +permission_edit_project: Modifica progetti +permission_add_issue_notes: Aggiungi note +permission_save_queries: Salva query +permission_view_wiki_pages: Vedi pagine wiki +permission_rename_wiki_pages: Rinomina pagine wiki +permission_edit_time_entries: Modifica time logs +permission_edit_own_issue_notes: Modifica proprie note +setting_gravatar_enabled: Usa icone utente Gravatar +label_example: Esempio +text_repository_usernames_mapping: "Seleziona per aggiornare la corrispondenza tra gli utenti Redmine e quelli presenti nel log del repository.\nGli utenti Redmine e repository con lo stesso username o email sono mappati automaticamente." +permission_edit_own_messages: Modifica propri messaggi +permission_delete_own_messages: Elimina propri messaggi +label_user_activity: "attività di %s" +label_updated_time_by: Aggiornato da %s %s fa +text_diff_truncated: '... Le differenze sono state troncate perchè superano il limite massimo visualizzabile.' +setting_diff_max_lines_displayed: Limite massimo di differenze (linee) mostrate +text_plugin_assets_writable: Plugin assets directory writable +warning_attachments_not_saved: "%d file(s) could not be saved." +button_create_and_continue: Create and continue +text_custom_field_possible_values_info: 'One line for each value' +label_display: Display +field_editable: Editable +setting_repository_log_display_limit: Maximum number of revisions displayed on file log +field_identity_url: OpenID URL +setting_openid: Allow OpenID login and registration +label_login_with_open_id_option: or login with OpenID +field_watcher: Watcher diff --git a/lang/ja.yml b/lang/ja.yml index 95c632b8d..b92287678 100644 --- a/lang/ja.yml +++ b/lang/ja.yml @@ -181,7 +181,7 @@ setting_text_formatting: テキストの書式 setting_wiki_compression: Wiki履歴を圧縮する setting_feeds_limit: フィード内容の上限 setting_autofetch_changesets: コミットを自動取得する -setting_sys_api_enabled: リポジトリ管理用のWeb Serviceを有効化する +setting_sys_api_enabled: リポジトリ管理用のWeb Serviceを有効にする setting_commit_ref_keywords: 参照用キーワード setting_commit_fix_keywords: 修正用キーワード setting_autologin: 自動ログイン @@ -354,7 +354,7 @@ label_sort_lower: 下へ label_sort_lowest: 一番下へ label_roadmap: ロードマップ label_roadmap_due_in: 期日まで %s -label_roadmap_overdue: %s late +label_roadmap_overdue: %s遅れ label_roadmap_no_issues: このバージョンに向けてのチケットはありません label_search: 検索 label_result_plural: 結果 @@ -510,7 +510,7 @@ default_priority_normal: 通常 default_priority_high: 高め default_priority_urgent: 急いで default_priority_immediate: 今すぐ -default_activity_design: デザイン作業 +default_activity_design: 設計作業 default_activity_development: 開発作業 enumeration_issue_priorities: チケットの優先度 @@ -552,6 +552,7 @@ notice_account_pending: アカウントは作成済みで、管理者の承認 field_time_zone: タイムゾーン text_caracters_minimum: 最低%d文字の長さが必要です setting_bcc_recipients: ブラインドカーボンコピーで受信(bcc) +setting_plain_text_mail: プレインテキストのみ(HTMLなし) button_annotate: 注釈 label_issues_by: %s別のチケット field_searchable: Searchable @@ -619,27 +620,91 @@ label_overall_activity: 全ての活動 setting_default_projects_public: デフォルトで新しいプロジェクトは公開にする error_scm_annotate: "エントリが存在しない、もしくはアノテートできません。" label_planning: 計画 -text_subprojects_destroy_warning: 'Its subproject(s): %s will be also deleted.' -label_and_its_subprojects: %s and its subprojects -mail_body_reminder: "%d issue(s) that are assigned to you are due in the next %d days:" -mail_subject_reminder: "%d issue(s) due in the next days" +text_subprojects_destroy_warning: 'サブプロジェクト %s も削除されます。' +label_and_its_subprojects: %s とサブプロジェクト +mail_body_reminder: "%d件の担当チケットの期限が%d日以内に到来します:" +mail_subject_reminder: "%d件のチケットが期限間近です" text_user_wrote: '%s wrote:' label_duplicated_by: duplicated by -setting_enabled_scm: Enabled SCM -text_enumeration_category_reassign_to: 'Reassign them to this value:' -text_enumeration_destroy_question: '%d objects are assigned to this value.' -label_incoming_emails: Incoming emails -label_generate_key: Generate a key -setting_mail_handler_api_enabled: Enable WS for incoming emails -setting_mail_handler_api_key: API key -text_email_delivery_not_configured: "Email delivery is not configured, and notifications are disabled.\nConfigure your SMTP server in config/email.yml and restart the application to enable them." -field_parent_title: Parent page +setting_enabled_scm: 使用するSCM +text_enumeration_category_reassign_to: '次の値に割り当て直す:' +text_enumeration_destroy_question: '%d個のオブジェクトがこの値に割り当てられています。' +label_incoming_emails: 受信メール +label_generate_key: キーの生成 +setting_mail_handler_api_enabled: 受信メール用のWeb Serviceを有効にする +setting_mail_handler_api_key: APIキー +text_email_delivery_not_configured: "メールを送信するために必要な設定が行われていないため、メール通知は利用できません。\nconfig/email.ymlでSMTPサーバの設定を行い、アプリケーションを再起動してください。" +field_parent_title: 親ページ label_issue_watchers: Watchers -setting_commit_logs_encoding: Commit messages encoding -button_quote: Quote -setting_sequential_project_identifiers: Generate sequential project identifiers -notice_unable_delete_version: Unable to delete version +setting_commit_logs_encoding: コミットメッセージのエンコーディング +button_quote: 引用 +setting_sequential_project_identifiers: プロジェクト識別子を連番で生成する +notice_unable_delete_version: バージョンを削除できません label_renamed: renamed label_copied: copied -setting_repositories_cache_directory: Cache directory for repositories -field_cache: Local cache +permission_view_files: View files +permission_edit_issues: Edit issues +permission_edit_own_time_entries: Edit own time logs +permission_manage_public_queries: Manage public queries +permission_add_issues: Add issues +permission_log_time: Log spent time +permission_view_changesets: View changesets +permission_view_time_entries: View spent time +permission_manage_versions: Manage versions +permission_manage_wiki: Manage wiki +permission_manage_categories: Manage issue categories +permission_protect_wiki_pages: Protect wiki pages +permission_comment_news: Comment news +permission_delete_messages: Delete messages +permission_select_project_modules: Select project modules +permission_manage_documents: Manage documents +permission_edit_wiki_pages: Edit wiki pages +permission_add_issue_watchers: Add watchers +permission_view_gantt: View gantt chart +permission_move_issues: Move issues +permission_manage_issue_relations: Manage issue relations +permission_delete_wiki_pages: Delete wiki pages +permission_manage_boards: Manage boards +permission_delete_wiki_pages_attachments: Delete attachments +permission_view_wiki_edits: View wiki history +permission_add_messages: Post messages +permission_view_messages: View messages +permission_manage_files: Manage files +permission_edit_issue_notes: Edit notes +permission_manage_news: Manage news +permission_view_calendar: View calendrier +permission_manage_members: Manage members +permission_edit_messages: Edit messages +permission_delete_issues: Delete issues +permission_view_issue_watchers: View watchers list +permission_manage_repository: Manage repository +permission_commit_access: Commit access +permission_browse_repository: Browse repository +permission_view_documents: View documents +permission_edit_project: Edit project +permission_add_issue_notes: Add notes +permission_save_queries: Save queries +permission_view_wiki_pages: View wiki +permission_rename_wiki_pages: Rename wiki pages +permission_edit_time_entries: Edit time logs +permission_edit_own_issue_notes: Edit own notes +setting_gravatar_enabled: Gravatarユーザーアイコンを使用する +label_example: 例 +text_repository_usernames_mapping: "リポジトリのログから検出されたユーザー名をどのRedmineユーザーに関連づけるのか選択してください。\nログ上のユーザー名またはメールアドレスがRedmineのユーザーと一致する場合は自動的に関連づけられます。" +permission_edit_own_messages: Edit own messages +permission_delete_own_messages: Delete own messages +label_user_activity: "%sの活動" +label_updated_time_by: %sが%s前に更新 +text_diff_truncated: '... 差分の行数が表示可能な上限を超えました。超過分は表示しません。' +setting_diff_max_lines_displayed: 差分の表示行数の上限 +text_plugin_assets_writable: Plugin assets directory writable +warning_attachments_not_saved: "%d個のファイルが保存できませんでした。" +button_create_and_continue: 連続作成 +text_custom_field_possible_values_info: '選択肢の値は1行に1個ずつ記述してください。' +label_display: 表示 +field_editable: Editable +setting_repository_log_display_limit: Maximum number of revisions displayed on file log +field_identity_url: OpenID URL +setting_openid: Allow OpenID login and registration +label_login_with_open_id_option: or login with OpenID +field_watcher: Watcher diff --git a/lang/ko.yml b/lang/ko.yml index 0d96274f2..008fe866c 100644 --- a/lang/ko.yml +++ b/lang/ko.yml @@ -55,13 +55,13 @@ general_day_names: 월요일,화요일,수요일,목요일,금요일,토요일, general_first_day_of_week: '7' notice_account_updated: 계정이 성공적으로 변경 되었습니다. -notice_account_invalid_creditentials: 잘못된 계정 또는 패스워드 +notice_account_invalid_creditentials: 잘못된 계정 또는 비밀번호 notice_account_password_updated: 비밀번호가 잘 변경되었습니다. -notice_account_wrong_password: 잘못된 패스워드 -notice_account_register_done: 계정이 성공적으로 생성되었습니다. 계정을 활성화 하기 위해서 수신한 Email의 링크를 클릭해주세요. +notice_account_wrong_password: 잘못된 비밀번호 +notice_account_register_done: 계정이 잘 만들어졌습니다. 계정을 활성화하시려면 받은 메일의 링크를 클릭해주세요. notice_account_unknown_email: 알려지지 않은 사용자. -notice_can_t_change_password: 이 계정은 외부 인증을 이용합니다. 비밀번호 변경이 불가능 합니다. -notice_account_lost_email_sent: 새로운 패스워드를 위한 Email이 발송되었습니다. +notice_can_t_change_password: 이 계정은 외부 인증을 이용합니다. 비밀번호를 변경할 수 없습니다. +notice_account_lost_email_sent: 새로운 비밀번호를 위한 메일이 발송되었습니다. notice_account_activated: 계정이 활성화 되었습니다. 이제 로그인 하실수 있습니다. notice_successful_create: 생성 성공. notice_successful_update: 변경 성공. @@ -70,14 +70,14 @@ notice_successful_connection: 연결 성공. notice_file_not_found: 요청하신 페이지는 삭제되었거나 옮겨졌습니다. notice_locking_conflict: 다른 사용자에 의해서 데이터가 변경되었습니다. notice_not_authorized: 이 페이지에 접근할 권한이 없습니다. -notice_email_sent: %s 님에게 Email이 발송되었습니다. +notice_email_sent: %s님에게 메일이 발송되었습니다. notice_email_error: 메일을 전송하는 과정에 오류가 발생했습니다. (%s) notice_feeds_access_key_reseted: RSS에 접근가능한 열쇠(key)가 생성되었습니다. -notice_failed_to_save_issues: "Failed to save %d issue(s) on %d selected: %s." -notice_no_issue_selected: "이슈가 선택되지 않았습니다. 수정하기 원하는 이슈를 선택하세요" +notice_failed_to_save_issues: "저장에 실패하였습니다: 실패 %d(선택 %d): %s." +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: '비밀번호를 변경하기 위해서 링크를 이용하세요' @@ -97,7 +97,7 @@ field_mail: 메일 field_filename: 파일 field_filesize: 크기 field_downloads: 다운로드 -field_author: 보고자 +field_author: 저자 field_created_on: 보고시간 field_updated_on: 변경시간 field_field_format: 포맷 @@ -110,44 +110,44 @@ field_value: 값 field_category: 카테고리 field_title: 제목 field_project: 프로젝트 -field_issue: 이슈 +field_issue: 일감 field_status: 상태 -field_notes: 노트 -field_is_closed: 완료된 이슈 +field_notes: 덧글 +field_is_closed: 완료된 일감 field_is_default: 기본값 field_tracker: 구분 field_subject: 제목 field_due_date: 완료 기한 field_assigned_to: 담당자 field_priority: 우선순위 -field_fixed_version: Target version -field_user: 유저 +field_fixed_version: 목표버전 +field_user: 사용자 field_role: 역할 field_homepage: 홈페이지 field_is_public: 공개 field_parent: 상위 프로젝트 -field_is_in_chlog: 변경이력(changelog)에서 보여지는 이슈들 -field_is_in_roadmap: 로드맵에서 보여지는 이슈들 +field_is_in_chlog: 변경이력(changelog)에서 표시할 일감들 +field_is_in_roadmap: 로드맵에서표시할 일감들 field_login: 로그인 field_mail_notification: 메일 알림 field_admin: 관리자 -field_last_login_on: 최종 접속 +field_last_login_on: 마지막 로그인 field_language: 언어 field_effective_date: 일자 field_password: 비밀번호 -field_new_password: 신규 비밀번호 +field_new_password: 새 비밀번호 field_password_confirmation: 비밀번호 확인 field_version: 버전 field_type: 타입 field_host: 호스트 field_port: 포트 field_account: 계정 -field_base_dn: Base DN +field_base_dn: 기본 DN field_attr_login: 로그인 속성 field_attr_firstname: 이름 속성 field_attr_lastname: 성 속성 field_attr_mail: 메일 속성 -field_onthefly: On-the-fly user creation +field_onthefly: 빠른 사용자 생성 field_start_date: 시작시간 field_done_ratio: 완료 %% field_auth_source: 인증 방법 @@ -161,10 +161,10 @@ field_activity: 작업종류 field_spent_on: 작업시간 field_identifier: 식별자 field_is_filter: 필터로 사용됨 -field_issue_to_id: 연관된 이슈 +field_issue_to_id: 연관된 일감 field_delay: 지연 -field_assignable: 이 역할에 할당될수 있는 이슈 -field_redirect_existing_links: Redirect existing links +field_assignable: 이 역할에 할당될수 있는 일감 +field_redirect_existing_links: 기존의 링크로 돌려보냄(redirect) field_estimated_hours: 추정시간 field_column_names: 컬럼 field_default_value: 기본값 @@ -174,62 +174,62 @@ setting_app_subtitle: 레드마인 부제목 setting_welcome_text: 환영 메시지 setting_default_language: 기본 언어 setting_login_required: 인증이 필요함. -setting_self_registration: Self-registration +setting_self_registration: 사용자 직접등록 setting_attachment_max_size: 최대 첨부파일 크기 -setting_issues_export_limit: Issues export limit -setting_mail_from: Emission mail address +setting_issues_export_limit: 일감 내보내기 제한 개수 +setting_mail_from: 발신 메일 주소 setting_host_name: 호스트 이름 -setting_text_formatting: 텍스트 형식 -setting_wiki_compression: 위키 기록(history) 압축 -setting_feeds_limit: Feed content limit -setting_autofetch_changesets: Autofetch commits -setting_sys_api_enabled: Enable WS for repository management -setting_commit_ref_keywords: 이슈 참조에 사용할 키워드들 -setting_commit_fix_keywords: 이슈 해결에 사용할 키워드들 +setting_text_formatting: 본문 형식 +setting_wiki_compression: 위키 이력 압축 +setting_feeds_limit: 내용 피드(RSS Feed) 제한 개수 +setting_autofetch_changesets: 커밋된 변경묶음을 자동으로 가져오기 +setting_sys_api_enabled: 저장소 관리자에 WS 를 허용 +setting_commit_ref_keywords: 일감 참조에 사용할 키워드들 +setting_commit_fix_keywords: 일감 해결에 사용할 키워드들 setting_autologin: 자동 로그인 setting_date_format: 날짜 형식 -setting_cross_project_issue_relations: 프로젝트간 이슈에 관련을 맺는 것을 허용 -setting_issue_list_default_columns: 이슈 목록에 보여줄 기본 컬럼들 +setting_cross_project_issue_relations: 프로젝트간 일감에 관계을 맺는 것을 허용 +setting_issue_list_default_columns: 일감 목록에 보여줄 기본 컬럼들 setting_repositories_encodings: 저장소 인코딩 setting_emails_footer: 메일 꼬리 label_user: 사용자 label_user_plural: 사용자관리 -label_user_new: 신규 유저 +label_user_new: 새 사용자 label_project: 프로젝트 -label_project_new: 신규 프로젝트 +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_issue: 일감 +label_issue_new: 새 일감만들기 +label_issue_plural: 일감 +label_issue_view_all: 모든 일감 보기 label_document: 문서 -label_document_new: 새로운 문서 +label_document_new: 새 문서 label_document_plural: 문서 label_role: 역할 label_role_plural: 역할 -label_role_new: 새로운 역할 +label_role_new: 새 역할 label_role_and_permissions: 권한관리 label_member: 담당자 -label_member_new: 새로운 담당자 +label_member_new: 새 담당자 label_member_plural: 담당자 -label_tracker: 이슈 유형 -label_tracker_plural: 이슈 유형 -label_tracker_new: 새로운 이슈 유형 -label_workflow: 워크플로(Workflow) -label_issue_status: 이슈 상태 -label_issue_status_plural: 이슈 상태 -label_issue_status_new: 새로운 이슈 상태 +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_custom_field_new: 새 사용자 정의 항목 label_enumerations: 코드값 설정 -label_enumeration_new: 새로운 코드값 +label_enumeration_new: 새 코드값 label_information: 정보 label_information_plural: 정보 label_please_login: 로그인하세요. @@ -243,15 +243,15 @@ label_administration: 관리자 label_login: 로그인 label_logout: 로그아웃 label_help: 도움말 -label_reported_issues: 보고된 이슈 -label_assigned_to_me_issues: 나에게 할당된 이슈 +label_reported_issues: 보고한 일감 +label_assigned_to_me_issues: 나에게 할당된 일감 label_last_login: 최종 접속 label_last_updates: 최종 변경 내역 label_last_updates_plural: 최종변경 %d -label_registered_on: Registered on -label_activity: 진행중인 작업 -label_new: 신규 -label_logged_as: ▶ +label_registered_on: 등록시각 +label_activity: 작업내역 +label_new: 새로 만들기 +label_logged_as: '로그인계정:' label_environment: 환경 label_authentication: 인증설정 label_auth_source: 인증 모드 @@ -272,7 +272,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: 파일삭제 @@ -280,7 +280,7 @@ label_attachment_plural: 관련파일 label_report: 보고서 label_report_plural: 보고서 label_news: 뉴스 -label_news_new: 뉴스추가 +label_news_new: 새 뉴스 label_news_plural: 뉴스 label_news_latest: 최근 뉴스 label_news_view_all: 모든 뉴스 @@ -288,7 +288,7 @@ label_change_log: 변경 로그 label_settings: 설정 label_overview: 개요 label_version: 버전 -label_version_new: 새로운 버전 +label_version_new: 새 버전 label_version_plural: 버전 label_confirmation: 확인 label_export_to: 내보내기 @@ -298,25 +298,25 @@ label_open_issues: 진행중 label_open_issues_plural: 진행중 label_closed_issues: 완료됨 label_closed_issues_plural: 완료됨 -label_total: Total +label_total: 합계 label_permissions: 허가권한 -label_current_status: 이슈 상태 -label_new_statuses_allowed: 허용되는 이슈 상태 +label_current_status: 일감 상태 +label_new_statuses_allowed: 허용되는 일감 상태 label_all: 모두 label_none: 없음 label_next: 다음 label_previous: 이전 label_used_by: 사용됨 -label_details: 상세 -label_add_note: 이슈노트 추가 +label_details: 자세히 +label_add_note: 일감덧글 추가 label_per_page: 페이지별 label_calendar: 달력 label_months_from: 개월 동안 | 다음부터 label_gantt: Gantt 챠트 -label_internal: Internal +label_internal: 내부 label_last_changes: 지난 변경사항 %d 건 label_change_view_all: 모든 변경 내역 보기 -label_personalize_page: 입맛대로 구성하기(Drag & Drop) +label_personalize_page: 입맛대로 구성하기 label_comment: 댓글 label_comment_plural: 댓글 label_comment_add: 댓글 추가 @@ -324,7 +324,7 @@ label_comment_added: 댓글이 추가되었습니다. label_comment_delete: 댓글 삭제 label_query: 사용자 검색조건 label_query_plural: 사용자 검색조건 -label_query_new: 새로운 사용자 검색조건 +label_query_new: 새 사용자 검색조건 label_filter_add: 필터 추가 label_filter_plural: 필터 label_equals: 이다 @@ -344,16 +344,16 @@ label_repository: 저장소 label_browse: 저장소 살피기 label_modification: %d 변경 label_modification_plural: %d 변경 -label_revision: 개정판(Revision) -label_revision_plural: 개정판(Revisions) -label_added: added -label_modified: modified -label_deleted: deleted +label_revision: 개정판 +label_revision_plural: 개정판 +label_added: 추가됨 +label_modified: 변경됨 +label_deleted: 삭제됨 label_latest_revision: 최근 개정판 label_latest_revision_plural: 최근 개정판 label_view_revisions: 개정판 보기 label_max_size: 최대 크기 -label_on: 'on' +label_on: '전체: ' label_sort_highest: 최상단으로 label_sort_higher: 위로 label_sort_lower: 아래로 @@ -361,7 +361,7 @@ label_sort_lowest: 최하단으로 label_roadmap: 로드맵 label_roadmap_due_in: 기한 %s label_roadmap_overdue: %s 지연 -label_roadmap_no_issues: 이버전에 해당하는 이슈 없음 +label_roadmap_no_issues: 이 버전에 해당하는 일감 없음 label_search: 검색 label_result_plural: 결과 label_all_words: 모든 단어 @@ -376,7 +376,7 @@ label_current_version: 현재 버전 label_preview: 미리보기 label_feed_plural: 피드(Feeds) label_changes_details: 모든 상세 변경 내역 -label_issue_tracking: 이슈 추적 +label_issue_tracking: 일감 추적 label_spent_time: 작업 시간 label_f_hour: %.2f 시간 label_f_hour_plural: %.2f 시간 @@ -385,24 +385,24 @@ label_change_plural: 변경사항들 label_statistics: 통계 label_commits_per_month: 월별 커밋 내역 label_commits_per_author: 아이디별 커밋 내역 -label_view_diff: diff 보기 +label_view_diff: 차이점 보기 label_diff_inline: 한줄로 label_diff_side_by_side: 두줄로 -label_options: Options -label_copy_workflow_from: Copy workflow from +label_options: 옵션 +label_copy_workflow_from: 워크플로우를 복사해올 일감유형 label_permissions_report: 권한 보고서 -label_watched_issues: 감시중인 이슈 -label_related_issues: 연결된 이슈 -label_applied_status: Applied status +label_watched_issues: 지켜보고 있는 일감 +label_related_issues: 연결된 일감 +label_applied_status: 적용된 상태 label_loading: 읽는 중... -label_relation_new: New relation -label_relation_delete: Delete relation -label_relates_to: 다음 이슈와 관련되어 있음 -label_duplicates: 다음 이슈와 중복됨. -label_blocks: 다음 이슈가 해결을 막고 있음. -label_blocked_by: 막고 있는 이슈 -label_precedes: 다음 이슈보다 앞서서 처리해야 함. -label_follows: 선처리 이슈 +label_relation_new: 새 관계 +label_relation_delete: 관계 지우기 +label_relates_to: 다음 일감과 관련되어 있음 +label_duplicates: 다음 일감과 중복됨. +label_blocks: 다음 일감이 해결을 막고 있음. +label_blocked_by: 막고 있는 일감 +label_precedes: 다음 일감보다 앞서서 처리해야 함. +label_follows: 먼저 처리해야할 일감 label_end_to_start: end to start label_end_to_end: end to end label_start_to_start: start to start @@ -412,32 +412,32 @@ label_disabled: 비활성화 label_show_completed_versions: 완료된 버전 보기 label_me: 나 label_board: 게시판 -label_board_new: 신규 게시판 +label_board_new: 새 게시판 label_board_plural: 게시판 label_topic_plural: 주제 label_message_plural: 관련글 -label_message_last: 최종 글 +label_message_last: 마지막 글 label_message_new: 새글쓰기 label_reply_plural: 답글 label_send_information: 사용자에게 계정정보를 보냄 label_year: 년 label_month: 월 label_week: 주 -label_date_from: 에서 -label_date_to: (으)로 -label_language_based: Language based +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 created %s ago +label_feeds_access_key_created_on: RSS에 접근가능한 열쇠(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_changeset_plural: 변경묶음 label_default_columns: 기본 컬럼 label_no_change_option: (수정 안함) -label_bulk_edit_selected_issues: 선택된 이슈들을 한꺼번에 수정하기 +label_bulk_edit_selected_issues: 선택된 일감들을 한꺼번에 수정하기 label_theme: 테마 label_default: 기본 label_search_titles_only: 제목에서만 찾기 @@ -470,13 +470,13 @@ button_activate: 활성화 button_sort: 정렬 button_log_time: 작업시간 기록 button_rollback: 이 버전으로 롤백 -button_watch: 감시하기 -button_unwatch: 감시해제 +button_watch: 지켜보기 +button_unwatch: 관심끄기 button_reply: 답글 button_archive: 잠금보관 button_unarchive: 잠금보관해제 button_reset: 리셋 -button_rename: 이름 변경 +button_rename: 이름변경 status_active: 사용중 status_registered: 등록대기 @@ -486,7 +486,7 @@ text_select_mail_notifications: 알림메일이 필요한 작업을 선택하세 text_regexp_info: 예) ^[A-Z0-9]+$ text_min_max_length_info: 0 는 제한이 없음을 의미함 text_project_destroy_confirmation: 이 프로젝트를 삭제하고 모든 데이터를 지우시겠습니까? -text_workflow_edit: 워크플로를 수정하기 위해서 역할과 이슈유형을 선택하세요. +text_workflow_edit: 워크플로를 수정하기 위해서 역할과 일감유형을 선택하세요. text_are_you_sure: 계속 진행 하시겠습니까? text_journal_changed: %s에서 %s(으)로 변경 text_journal_set_to: %s로 설정 @@ -500,14 +500,14 @@ text_length_between: %d 에서 %d 글자 text_tracker_no_workflow: 이 추적타입(tracker)에 워크플로우가 정의되지 않았습니다. text_unallowed_characters: 허용되지 않는 문자열 text_comma_separated: 복수의 값들이 허용됩니다.(구분자 ,) -text_issues_ref_in_commit_messages: 커밋메시지에서 이슈를 참조하거나 해결하기 -text_issue_added: 이슈[%s]가 보고되었습니다. -text_issue_updated: 이슈[%s]가 수정되었습니다. +text_issues_ref_in_commit_messages: 커밋메시지에서 일감을 참조하거나 해결하기 +text_issue_added: 일감[%s]가 보고되었습니다. +text_issue_updated: 일감[%s]가 수정되었습니다. text_wiki_destroy_confirmation: 이 위키와 모든 내용을 지우시겠습니까? -text_issue_category_destroy_question: 일부 이슈들(%d개)이 이 카테고리에 할당되어 있습니다. 어떻게 하시겠습니까? +text_issue_category_destroy_question: 일부 일감들(%d개)이 이 카테고리에 할당되어 있습니다. 어떻게 하시겠습니까? text_issue_category_destroy_assignments: 카테고리 할당 지우기 -text_issue_category_reassign_to: 이슈를 이 카테고리에 다시 할당하기 -text_user_mail_option: "선택하지 않은 프로젝트에서도, 모니터링 중이거나 속해있는 사항(이슈를 발행했거나 할당된 경우)이 있으면 알림메일을 받게 됩니다." +text_issue_category_reassign_to: 일감을 이 카테고리에 다시 할당하기 +text_user_mail_option: "선택하지 않은 프로젝트에서도, 모니터링 중이거나 속해있는 사항(일감을 발행했거나 할당된 경우)이 있으면 알림메일을 받게 됩니다." default_role_manager: 관리자 default_role_developper: 개발자 @@ -515,7 +515,7 @@ default_role_reporter: 보고자 default_tracker_bug: 버그 default_tracker_feature: 새기능 default_tracker_support: 지원 -default_issue_status_new: 신규 +default_issue_status_new: 새로 만들기 default_issue_status_assigned: 확인 default_issue_status_resolved: 해결 default_issue_status_feedback: 피드백 @@ -531,9 +531,9 @@ default_priority_immediate: 즉시 default_activity_design: 설계 default_activity_development: 개발 -enumeration_issue_priorities: 이슈 우선순위 +enumeration_issue_priorities: 일감 우선순위 enumeration_doc_categories: 문서 카테고리 -enumeration_activities: 진행활동(시간 추적) +enumeration_activities: 작업분류(시간추적) button_copy: 복사 mail_body_account_information_external: 레드마인에 로그인할 때 "%s" 계정을 사용하실 수 있습니다. button_change_password: 비밀번호 변경 @@ -551,94 +551,159 @@ notice_account_pending: "계정이 만들어 졌습니다. 관리자의 승인 field_time_zone: 타임존 text_caracters_minimum: 최소한 %d 글자 이상이어야 합니다. setting_bcc_recipients: 참조자들을 bcc로 숨기기 -button_annotate: Annotate -label_issues_by: Issues by %s +button_annotate: 주석달기(annotate) +label_issues_by: 일감분류 방식 %s field_searchable: 검색가능 -label_display_per_page: 'Per page: %s' -setting_per_page_options: Objects per page options -label_age: Age +label_display_per_page: '페이지당: %s' +setting_per_page_options: 페이지당 표시할 객체 수 +label_age: 마지막 수정일 notice_default_data_loaded: 기본 설정을 성공적으로 로드하였습니다. text_load_default_configuration: 기본 설정을 로딩하기 -text_no_configuration_data: "역할, 이슈 타입, 이슈 상태들과 워크플로가 아직 설정되지 않았습니다.\n기본 설정을 로딩하는 것을 권장합니다. 로드된 후에 수정할 수 있습니다." +text_no_configuration_data: "역할, 일감 타입, 일감 상태들과 워크플로가 아직 설정되지 않았습니다.\n기본 설정을 로딩하는 것을 권장합니다. 로드된 후에 수정할 수 있습니다." error_can_t_load_default_data: "기본 설정을 로드할 수 없습니다.: %s" -button_update: 변경사항기록 +button_update: 수정 label_change_properties: 속성 변경 label_general: 일반 label_repository_plural: 저장소들 -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: '선택한 이슈를 정말로 삭제하시겠습니까?' -label_scm: SCM +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: '이 프로젝트에서 활성화시킬 모듈을 선택하세요:' -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 +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_issue_tracking: 일감관리 project_module_wiki: 위키 project_module_files: 관련파일 project_module_documents: 문서 project_module_repository: 저장소 project_module_news: 뉴스 -project_module_time_tracking: Time tracking -text_file_repository_writable: File repository writable +project_module_time_tracking: 시간추적 +text_file_repository_writable: 파일 저장소 쓰기 가능 text_default_administrator_account_changed: 기본 관리자 계정이 변경되었습니다. -text_rmagick_available: RMagick available (optional) +text_rmagick_available: RMagick 사용가능(옵션) button_configure: 설정 label_plugins: 플러그인 label_ldap_authentication: LDAP 인증 label_downloads_abbr: D/L -label_add_another_file: Add another file -label_this_month: this month -text_destroy_time_entries_question: %.02f hours were reported on the issues you are about to delete. What do you want to do ? -label_last_n_days: last %d days -label_all_time: all time -error_issue_not_found_in_project: 'The issue was not found or does not belong to this project' -label_this_year: this year -text_assign_time_entries_to_project: Assign reported hours to the project -label_date_range: Date range -label_last_week: last week -label_yesterday: yesterday -label_optional_description: Optional description -label_last_month: last month -text_destroy_time_entries: Delete reported hours -text_reassign_time_entries: 'Reassign reported hours to this issue:' -setting_activity_days_default: Days displayed on project activity -label_chronological_order: In chronological order -field_comments_sorting: Display comments -label_reverse_chronological_order: In reverse chronological order -label_preferences: Preferences -setting_display_subprojects_issues: Display subprojects issues on main projects by default -label_overall_activity: Overall activity -setting_default_projects_public: New projects are public by default -error_scm_annotate: "The entry does not exist or can not be annotated." -label_planning: Planning -text_subprojects_destroy_warning: 'Its subproject(s): %s will be also deleted.' -label_and_its_subprojects: %s and its subprojects -mail_body_reminder: "%d issue(s) that are assigned to you are due in the next %d days:" -mail_subject_reminder: "%d issue(s) due in the next days" -text_user_wrote: '%s wrote:' -label_duplicated_by: duplicated by -setting_enabled_scm: Enabled SCM -text_enumeration_category_reassign_to: 'Reassign them to this value:' -text_enumeration_destroy_question: '%d objects are assigned to this value.' -label_incoming_emails: Incoming emails -label_generate_key: Generate a key -setting_mail_handler_api_enabled: Enable WS for incoming emails -setting_mail_handler_api_key: API key -text_email_delivery_not_configured: "Email delivery is not configured, and notifications are disabled.\nConfigure your SMTP server in config/email.yml and restart the application to enable them." -field_parent_title: Parent page -label_issue_watchers: Watchers -setting_commit_logs_encoding: Commit messages encoding -button_quote: Quote -setting_sequential_project_identifiers: Generate sequential project identifiers -notice_unable_delete_version: Unable to delete version -label_renamed: renamed -label_copied: copied -setting_repositories_cache_directory: Cache directory for repositories -field_cache: Local cache +label_add_another_file: 다른 파일 추가 +label_this_month: 이번 달 +text_destroy_time_entries_question: 삭제하려는 일감에 %.02f 시간이 보고되어 있습니다. 어떻게 하시겠습니까? +label_last_n_days: 지난 %d 일 +label_all_time: 모든 시간 +error_issue_not_found_in_project: '일감이 없거나 이 프로젝트의 것이 아닙니다.' +label_this_year: 올해 +text_assign_time_entries_to_project: 보고된 시간을 프로젝트에 할당하기 +label_date_range: 날짜 범위 +label_last_week: 지난 주 +label_yesterday: 어제 +label_optional_description: 부가적인 설명 +label_last_month: 지난 달 +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: 프로젝트계획(Planning) +text_subprojects_destroy_warning: '서브프로젝트(%s)가 자동으로 지워질 것입니다.' +label_and_its_subprojects: %s와 서브프로젝트들 +mail_body_reminder: "님에게 할당된 %d개의 일감들을 다음 %d일 안으로 마쳐야 합니다.:" +mail_subject_reminder: "내일까지 마쳐야할 일감 %d개" +text_user_wrote: '%s의 덧글:' +label_duplicated_by: 중복된 일감 +setting_enabled_scm: 허용할 SCM +text_enumeration_category_reassign_to: '새로운 값을 설정:' +text_enumeration_destroy_question: '%d 개의 일감이 이 값을 사용하고 있습니다.' +label_incoming_emails: 수신 메일 설정 +label_generate_key: 키 생성 +setting_mail_handler_api_enabled: 수신 메일에 WS 를 허용 +setting_mail_handler_api_key: API 키 +text_email_delivery_not_configured: "이메일 전달이 설정되지 않았습니다. 그래서 알림이 비활성화되었습니다.\n SMTP서버를 config/email.yml에서 설정하고 어플리케이션을 다시 시작하십시오. 그러면 동작합니다." +field_parent_title: 상위 제목 +label_issue_watchers: 일감지킴이 설정 +setting_commit_logs_encoding: 저장소 커밋 메시지 인코딩 +button_quote: 댓글달기 +setting_sequential_project_identifiers: 프로젝트 식별자를 순차적으로 생성 +notice_unable_delete_version: 삭제 할 수 없는 버전 입니다. +label_renamed: 이름바뀜 +label_copied: 복사됨 +setting_plain_text_mail: 테스트만(HTML없음) +permission_view_files: 파일보기 +permission_edit_issues: 일감 편집 +permission_edit_own_time_entries: 내 시간로그 편집 +permission_manage_public_queries: 공용 질의 관리 +permission_add_issues: 일감 추가 +permission_log_time: 소요시간 기록 +permission_view_changesets: 변경묶음보기 +permission_view_time_entries: 소요시간 보기 +permission_manage_versions: 버전 관리 +permission_manage_wiki: 위키 관리 +permission_manage_categories: 일감 카테고리 관리 +permission_protect_wiki_pages: 프로젝트 위키 페이지 +permission_comment_news: 뉴스에 코멘트달기 +permission_delete_messages: 메시지 삭제 +permission_select_project_modules: 프로젝트 모듈 선택 +permission_manage_documents: 문서 관리 +permission_edit_wiki_pages: 위키 페이지 편집 +permission_add_issue_watchers: 일감지킴이 추가 +permission_view_gantt: Gantt차트 보기 +permission_move_issues: 일감 이동 +permission_manage_issue_relations: 일감 관계 관리 +permission_delete_wiki_pages: 위치 페이지 삭제 +permission_manage_boards: 게시판 관리 +permission_delete_wiki_pages_attachments: 첨부파일 삭제 +permission_view_wiki_edits: 위키 기록 보기 +permission_add_messages: 메시지 추가 +permission_view_messages: 메시지 보기 +permission_manage_files: 파일관리 +permission_edit_issue_notes: 덧글 편집 +permission_manage_news: 뉴스 관리 +permission_view_calendar: 달력 보기 +permission_manage_members: 멤버 관리 +permission_edit_messages: 메시지 편집 +permission_delete_issues: 일감 삭제 +permission_view_issue_watchers: 일감지킴이 보기 +permission_manage_repository: 저장소 관리 +permission_commit_access: 변경로그 보기 +permission_browse_repository: 저장소 둘러보기 +permission_view_documents: 문서 보기 +permission_edit_project: 프로젝트 편집 +permission_add_issue_notes: 덧글 추가 +permission_save_queries: 쿼리 저장 +permission_view_wiki_pages: 위키 보기 +permission_rename_wiki_pages: 위키 페이지 이름변경 +permission_edit_time_entries: 시간기록 편집 +permission_edit_own_issue_notes: 내 덧글 편집 +setting_gravatar_enabled: 그라바타 사용자 아이콘 쓰기 +label_example: 예 +text_repository_usernames_mapping: "저장소 로그에서 발견된 각 사용자에 레드마인 사용자를 업데이트할때 선택합니다.\n레드마인과 저장소의 이름이나 이메일이 같은 사용자가 자동으로 연결됩니다." +permission_edit_own_messages: 자기 메시지 편집 +permission_delete_own_messages: 자기 메시지 삭제 +label_user_activity: "%s의 작업내역" +label_updated_time_by: %s가 %s 전에 변경 +text_diff_truncated: '... 이 차이점은 표시할 수 있는 최대 줄수를 초과해서 이 차이점은 잘렸습니다.' +setting_diff_max_lines_displayed: 차이점보기에 표시할 최대 줄수 +text_plugin_assets_writable: Plugin assets directory writable +warning_attachments_not_saved: "%d file(s) could not be saved." +button_create_and_continue: Create and continue +text_custom_field_possible_values_info: 'One line for each value' +label_display: Display +field_editable: Editable +setting_repository_log_display_limit: Maximum number of revisions displayed on file log +field_identity_url: OpenID URL +setting_openid: Allow OpenID login and registration +label_login_with_open_id_option: or login with OpenID +field_watcher: Watcher diff --git a/lang/lt.yml b/lang/lt.yml index ffb831575..0a732a59a 100644 --- a/lang/lt.yml +++ b/lang/lt.yml @@ -1,85 +1,89 @@ _gloc_rule_default: '|n| n==1 ? "" : "_plural" ' - -actionview_datehelper_select_day_prefix: + +actionview_datehelper_select_day_prefix: actionview_datehelper_select_month_names: sausis,vasaris,kovas,balandis,gegužė,birželis,liepa,rugpjūtis,rugsėjis,spalis,lapkritis,gruodis actionview_datehelper_select_month_names_abbr: Sau,Vas,Kov,Bal,Geg,Brž,Lie,Rgp,Rgs,Spl,Lap,Grd actionview_datehelper_select_month_prefix: -actionview_datehelper_select_year_prefix: +actionview_datehelper_select_year_prefix: actionview_datehelper_time_in_words_day: 1 diena actionview_datehelper_time_in_words_day_plural: %d dienų -actionview_datehelper_time_in_words_hour_about: apytiksliai valanda -actionview_datehelper_time_in_words_hour_about_plural: apie %d valandas -actionview_datehelper_time_in_words_hour_about_single: apytiksliai valanda -actionview_datehelper_time_in_words_minute: 1 minutė -actionview_datehelper_time_in_words_minute_half: pusė minutės -actionview_datehelper_time_in_words_minute_less_than: mažiau kaip minutė -actionview_datehelper_time_in_words_minute_plural: %d minutės -actionview_datehelper_time_in_words_minute_single: 1 minutė -actionview_datehelper_time_in_words_second_less_than: mažiau kaip sekundė -actionview_datehelper_time_in_words_second_less_than_plural: mažiau, negu %d sekundės -actionview_instancetag_blank_option: prašom išrinkti - -activerecord_error_inclusion: nėra įtrauktas į sąrašą -activerecord_error_exclusion: yra rezervuota(as) +actionview_datehelper_time_in_words_hour_about: apytiksliai valanda +actionview_datehelper_time_in_words_hour_about_plural: apie %d valandas +actionview_datehelper_time_in_words_hour_about_single: apytiksliai valanda +actionview_datehelper_time_in_words_minute: 1 minutė +actionview_datehelper_time_in_words_minute_half: pusė minutės +actionview_datehelper_time_in_words_minute_less_than: mažiau kaip minutė +actionview_datehelper_time_in_words_minute_plural: %d minutės +actionview_datehelper_time_in_words_minute_single: 1 minutė +actionview_datehelper_time_in_words_second_less_than: mažiau kaip sekundė +actionview_datehelper_time_in_words_second_less_than_plural: mažiau, negu %d sekundės +actionview_instancetag_blank_option: prašom išrinkti + +activerecord_error_inclusion: nėra įtrauktas į sąrašą +activerecord_error_exclusion: yra rezervuota(as) activerecord_error_invalid: yra negaliojanti(is) -activerecord_error_confirmation: neatitinka patvirtinimo -activerecord_error_accepted: turi būti priimtas -activerecord_error_empty: negali būti tuščiu -activerecord_error_blank: negali būti tuščiu -activerecord_error_too_long: yra per ilgas -activerecord_error_too_short: yra per trumpas -activerecord_error_wrong_length: neteisingas ilgis -activerecord_error_taken: buvo jau paimtas -activerecord_error_not_a_number: nėra skaičius -activerecord_error_not_a_date: data nėra galiojanti -activerecord_error_greater_than_start_date: turi būti didesnė negu pradžios data -activerecord_error_not_same_project: nepriklauso tam pačiam projektui -activerecord_error_circular_dependency: Šis ryšys sukurtų ciklinę priklausomybę - +activerecord_error_confirmation: neatitinka patvirtinimo +activerecord_error_accepted: turi būti priimtas +activerecord_error_empty: negali būti tuščiu +activerecord_error_blank: negali būti tuščiu +activerecord_error_too_long: yra per ilgas +activerecord_error_too_short: yra per trumpas +activerecord_error_wrong_length: neteisingas ilgis +activerecord_error_taken: buvo jau paimtas +activerecord_error_not_a_number: nėra skaičius +activerecord_error_not_a_date: data nėra galiojanti +activerecord_error_greater_than_start_date: turi būti didesnė negu pradžios data +activerecord_error_not_same_project: nepriklauso tam pačiam projektui +activerecord_error_circular_dependency: Šis ryšys sukurtų ciklinę priklausomybę + general_fmt_age: %d m. general_fmt_age_plural: %d metų(ai) general_fmt_date: %%Y-%%m-%%d -general_fmt_datetime: %%Y-%%m-%%d %%I:%%M %%p -general_fmt_datetime_short: %%b %%d, %%I:%%M %%p -general_fmt_time: %%I:%%M %%p +general_fmt_datetime: %%Y-%%m-%%d %%H:%%M +general_fmt_datetime_short: %%b %%d, %%H:%%M +general_fmt_time: %%H:%%M general_text_No: 'Ne' general_text_Yes: 'Taip' general_text_no: 'ne' general_text_yes: 'taip' general_lang_name: 'Lithuanian (lietuvių)' -general_csv_separator: ',' +general_csv_separator: ';' general_csv_decimal_separator: '.' general_csv_encoding: UTF-8 general_pdf_encoding: UTF-8 general_day_names: pirmadienis,antradienis,trečiadienis,ketvirtadienis,penktadienis,šeštadienis,sekmadienis general_first_day_of_week: '1' - -notice_account_updated: Paskyra buvo sėkmingai atnaujinta. + +notice_account_updated: Paskyra buvo sėkmingai atnaujinta. notice_account_invalid_creditentials: Negaliojantis vartotojo vardas ar slaptažodis -notice_account_password_updated: Slaptažodis buvo sėkmingai atnaujintas. -notice_account_wrong_password: Neteisingas slaptažodis -notice_account_register_done: Paskyra buvo sėkmingai sukurta. Kad aktyvintumėte savo paskyrą, paspauskite sąsają, kuri jums buvo siųsta elektroniniu paštu. -notice_account_unknown_email: Nežinomas vartotojas. -notice_can_t_change_password: Šis pranešimas naudoja išorinį autentiškumo nustatymo šaltinį. Neįmanoma pakeisti slaptažodį. -notice_account_lost_email_sent: Į Jūsų pašą išsiūstas laiškas su naujo slaptažodžio pasirinkimo instrukcija. +notice_account_password_updated: Slaptažodis buvo sėkmingai atnaujintas. +notice_account_wrong_password: Neteisingas slaptažodis +notice_account_register_done: Paskyra buvo sėkmingai sukurta. Kad aktyvintumėte savo paskyrą, paspauskite sąsają, kuri jums buvo siųsta elektroniniu paštu. +notice_account_unknown_email: Nežinomas vartotojas. +notice_can_t_change_password: Šis pranešimas naudoja išorinį autentiškumo nustatymo šaltinį. Neįmanoma pakeisti slaptažodį. +notice_account_lost_email_sent: Į Jūsų pašą išsiūstas laiškas su naujo slaptažodžio pasirinkimo instrukcija. notice_account_activated: Jūsų paskyra aktyvuota. Galite prisijungti. -notice_successful_create: Sėkmingas sukūrimas. -notice_successful_update: Sėkmingas atnaujinimas. -notice_successful_delete: Sėkmingas panaikinimas. -notice_successful_connection: Sėkmingas susijungimas. -notice_file_not_found: Puslapis, į kurį ketinate įeiti, neegzistuoja arba pašalintas. -notice_locking_conflict: Duomenys atnaujinti kito vartotojo. -notice_scm_error: Duomenys ir/ar pakeitimai saugykloje(repozitorojoje) neegzistuoja. -notice_not_authorized: Jūs neturite teisių gauti prieigą prie šio puslapio. +notice_successful_create: Sėkmingas sukūrimas. +notice_successful_update: Sėkmingas atnaujinimas. +notice_successful_delete: Sėkmingas panaikinimas. +notice_successful_connection: Sėkmingas susijungimas. +notice_file_not_found: Puslapis, į kurį ketinate įeiti, neegzistuoja arba pašalintas. +notice_locking_conflict: Duomenys atnaujinti kito vartotojo. +notice_not_authorized: Jūs neturite teisių gauti prieigą prie šio puslapio. notice_email_sent: Laiškas išsiųstas %s notice_email_error: Laiško siųntimo metu įvyko klaida (%s) notice_feeds_access_key_reseted: Jūsų RSS raktas buvo atnaujintas. notice_failed_to_save_issues: "Nepavyko išsaugoti %d problemos(ų) iš %d pasirinkto: %s." notice_no_issue_selected: "Nepasirinkta nė viena problema! Prašom pažymėti problemą, kurią norite redaguoti." notice_account_pending: "Jūsų paskyra buvo sukūrta ir dabar laukiama administratoriaus patvirtinimo." +notice_default_data_loaded: Numatytoji konfiguracija sėkmingai užkrauta. +notice_unable_delete_version: Neimanoma panaikinti versiją +error_can_t_load_default_data: "Numatytoji konfiguracija negali būti užkrauta: %s" error_scm_not_found: "Duomenys ir/ar pakeitimai saugykloje(repozitorojoje) neegzistuoja." error_scm_command_failed: "Įvyko klaida jungiantis prie saugyklos: %s" +error_scm_annotate: "Įrašas neegzituoja arba negalima jo atvaizduoti." +error_issue_not_found_in_project: 'Darbas nerastas arba nesurištas su šiuo projektu' mail_subject_lost_password: Jūsų %s slaptažodis mail_body_lost_password: 'Norėdami pakeisti slaptažodį, spauskite nuorodą:' @@ -89,10 +93,12 @@ mail_body_account_information_external: Jūs galite naudoti Jūsų "%s" paskyrą mail_body_account_information: Informacija apie Jūsų paskyrą mail_subject_account_activation_request: %s paskyros aktyvavimo prašymas mail_body_account_activation_request: 'Užsiregistravo naujas vartotojas (%s). Jo paskyra laukia jūsų patvirtinimo:' - +mail_subject_reminder: "%d darbas(ai) po kelių dienų" +mail_body_reminder: "%d darbas(ai), kurie yra jums priskirti, baigiasi po %d dienų(os):" + gui_validation_error: 1 klaida gui_validation_error_plural: %d klaidų(os) - + field_name: Pavadinimas field_description: Aprašas field_summary: Santrauka @@ -111,536 +117,595 @@ field_is_for_all: Visiems projektams field_possible_values: Galimos reikšmės field_regexp: Pastovi išraiška field_min_length: Minimalus ilgis -field_max_length: Maksimalus ilgis -field_value: Vertė -field_category: Kategorija -field_title: Pavadinimas -field_project: Projektas -field_issue: Darbas -field_status: Būsena -field_notes: Pastabos -field_is_closed: Darbas uždarytas -field_is_default: Numatytoji vertė -field_tracker: Pėdsekys -field_subject: Tema -field_due_date: Užbaigimo data -field_assigned_to: Paskirtas -field_priority: Prioritetas -field_fixed_version: Target version -field_user: Vartotojas -field_role: Vaidmuo -field_homepage: Pagrindinis puslapis -field_is_public: Viešas +field_max_length: Maksimalus ilgis +field_value: Vertė +field_category: Kategorija +field_title: Pavadinimas +field_project: Projektas +field_issue: Darbas +field_status: Būsena +field_notes: Pastabos +field_is_closed: Darbas uždarytas +field_is_default: Numatytoji vertė +field_tracker: Pėdsekys +field_subject: Tema +field_due_date: Užbaigimo data +field_assigned_to: Paskirtas +field_priority: Prioritetas +field_fixed_version: Tikslinė versija +field_user: Vartotojas +field_role: Vaidmuo +field_homepage: Pagrindinis puslapis +field_is_public: Viešas field_parent: Priklauso projektui -field_is_in_chlog: Darbai rodomi pokyčių žurnale -field_is_in_roadmap: Darbai rodomi veiklos grafike -field_login: Registracijos vardas -field_mail_notification: Elektroninio pašto pranešimai -field_admin: Administratorius -field_last_login_on: Paskutinis ryšys -field_language: Kalba -field_effective_date: Data +field_is_in_chlog: Darbai rodomi pokyčių žurnale +field_is_in_roadmap: Darbai rodomi veiklos grafike +field_login: Registracijos vardas +field_mail_notification: Elektroninio pašto pranešimai +field_admin: Administratorius +field_last_login_on: Paskutinis ryšys +field_language: Kalba +field_effective_date: Data field_password: Slaptažodis field_new_password: Naujas slaptažodis -field_password_confirmation: Patvirtinimas +field_password_confirmation: Patvirtinimas field_version: Versija -field_type: Tipas -field_host: Pagrindinis kompiuteris -field_port: Jungtis -field_account: Paskyra -field_base_dn: Bazinis skiriamasis vardas -field_attr_login: Registracijos vardo požymis -field_attr_firstname: Vardo priskiria -field_attr_lastname: Pavardės priskiria -field_attr_mail: Elektroninio pašto požymis -field_onthefly: Vartotojų sukūrimas paskubomis -field_start_date: Pradėti -field_done_ratio: %% Atlikta -field_auth_source: Autentiškumo nustatymo būdas -field_hide_mail: Paslėpkite mano elektroninio pašto adresą +field_type: Tipas +field_host: Pagrindinis kompiuteris +field_port: Portas +field_account: Paskyra +field_base_dn: Bazinis skiriamasis vardas +field_attr_login: Registracijos vardo požymis +field_attr_firstname: Vardo priskiria +field_attr_lastname: Pavardės priskiria +field_attr_mail: Elektroninio pašto požymis +field_onthefly: Automatinis vartotojų registravimas +field_start_date: Pradėti +field_done_ratio: %% Atlikta +field_auth_source: Autentiškumo nustatymo būdas +field_hide_mail: Paslėpkite mano elektroninio pašto adresą field_comments: Komentaras -field_url: URL +field_url: URL field_start_page: Pradžios puslapis -field_subproject: Subprojektas -field_hours: Valandos -field_activity: Veikla -field_spent_on: Data -field_identifier: Identifikuotojas -field_is_filter: Panaudotas kaip filtras +field_subproject: Subprojektas +field_hours: Valandos +field_activity: Veikla +field_spent_on: Data +field_identifier: Identifikuotojas +field_is_filter: Panaudotas kaip filtras field_issue_to_id: Susijęs darbas -field_delay: Užlaikymas -field_assignable: Darbai gali būti paskirti šiam vaidmeniui -field_redirect_existing_links: Peradresuokite egzistuojančias sąsajas -field_estimated_hours: Numatyta trukmė -field_column_names: Skiltys -field_time_zone: Laiko juosta -field_searchable: Randamas -field_default_value: Numatytoji vertė -setting_app_title: Programos pavadinimas -setting_app_subtitle: Programos paantraštė -setting_welcome_text: Pasveikinimas -setting_default_language: Numatytoji kalba -setting_login_required: Reikalingas autentiškumo nustatymas -setting_self_registration: Saviregistracija -setting_attachment_max_size: Priedo maks. dydis -setting_issues_export_limit pagal dydį: Darbų eksportavimo riba -setting_mail_from: Emisijos elektroninio pašto adresas +field_delay: Užlaikymas +field_assignable: Darbai gali būti paskirti šiam vaidmeniui +field_redirect_existing_links: Peradresuokite egzistuojančias sąsajas +field_estimated_hours: Numatyta trukmė +field_column_names: Skiltys +field_time_zone: Laiko juosta +field_searchable: Randamas +field_default_value: Numatytoji vertė +field_comments_sorting: rodyti komentarus +field_parent_title: Aukštesnio lygio puslapis + +setting_app_title: Programos pavadinimas +setting_app_subtitle: Programos paantraštė +setting_welcome_text: Pasveikinimas +setting_default_language: Numatytoji kalba +setting_login_required: Reikalingas autentiškumo nustatymas +setting_self_registration: Saviregistracija +setting_attachment_max_size: Priedo maks. dydis +setting_issues_export_limit: Darbų eksportavimo riba +setting_mail_from: Emisijos elektroninio pašto adresas setting_bcc_recipients: Akli tikslios kopijos gavėjai (bcc) +setting_plain_text_mail: tik grinas tekstas (be HTML) setting_host_name: Pagrindinio kompiuterio vardas -setting_text_formatting: Teksto apipavidalinimas -setting_wiki_compression: Wiki istorijos suspaudimas -setting_feeds_limit: Perdavimo turinio riba +setting_text_formatting: Teksto apipavidalinimas +setting_wiki_compression: Wiki istorijos suspaudimas +setting_feeds_limit: Perdavimo turinio riba +setting_default_projects_public: Naujas projektas viešas pagal nutylėjimą setting_autofetch_changesets: Automatinis pakeitimų siuntimas -setting_sys_api_enabled: Įgalinkite WS sandėlio vadybai +setting_sys_api_enabled: Įgalinkite WS sandėlio vadybai setting_commit_ref_keywords: Nurodymo reikšminiai žodžiai setting_commit_fix_keywords: Fiksavimo reikšminiai žodžiai setting_autologin: Autoregistracija -setting_date_format: Datos formatas -setting_time_format: Laiko formatas +setting_date_format: Datos formatas +setting_time_format: Laiko formatas setting_cross_project_issue_relations: Leisti tarprojektinius darbų ryšius setting_issue_list_default_columns: Numatytosios skiltys darbų sąraše setting_repositories_encodings: Saugyklos koduotė +setting_commit_logs_encoding: Commit pranėšimų koduotė setting_emails_footer: elektroninio pašto puslapinė poraštė setting_protocol: Protokolas - +setting_per_page_options: Įrašų puslapyje nustatimas +setting_user_format: Vartotojo atvaizdavimo formatas +setting_activity_days_default: Atvaizduojamos dienos projekto veikloje +setting_display_subprojects_issues: Pagal nutylėjimą rodyti subprojektų darbus pagrindiniame projekte +setting_enabled_scm: Įgalintas SCM +setting_mail_handler_api_enabled: Įgalinti WS įeinantiems laiškams +setting_mail_handler_api_key: API raktas +setting_sequential_project_identifiers: Generuoti nuoseklus projekto identifikatorius +setting_gravatar_enabled: Naudoti Gravatar vartotojo ikonkės +setting_diff_max_lines_displayed: Maksimalus rodomas eilučiu skaičius diff\'e + +permission_edit_project: Edit project +permission_select_project_modules: Select project modules +permission_manage_members: Manage members +permission_manage_versions: Manage versions +permission_manage_categories: Manage issue categories +permission_add_issues: Add issues +permission_edit_issues: Edit issues +permission_manage_issue_relations: Manage issue relations +permission_add_issue_notes: Add notes +permission_edit_issue_notes: Edit notes +permission_edit_own_issue_notes: Edit own notes +permission_move_issues: Move issues +permission_delete_issues: Delete issues +permission_manage_public_queries: Manage public queries +permission_save_queries: Save queries +permission_view_gantt: View gantt chart +permission_view_calendar: View calender +permission_view_issue_watchers: View watchers list +permission_add_issue_watchers: Add watchers +permission_log_time: Log spent time +permission_view_time_entries: View spent time +permission_edit_time_entries: Edit time logs +permission_edit_own_time_entries: Edit own time logs +permission_manage_news: Manage news +permission_comment_news: Comment news +permission_manage_documents: Manage documents +permission_view_documents: View documents +permission_manage_files: Manage files +permission_view_files: View files +permission_manage_wiki: Manage wiki +permission_rename_wiki_pages: Rename wiki pages +permission_delete_wiki_pages: Delete wiki pages +permission_view_wiki_pages: View wiki +permission_view_wiki_edits: View wiki history +permission_edit_wiki_pages: Edit wiki pages +permission_delete_wiki_pages_attachments: Delete attachments +permission_protect_wiki_pages: Protect wiki pages +permission_manage_repository: Manage repository +permission_browse_repository: Browse repository +permission_view_changesets: View changesets +permission_commit_access: Commit access +permission_manage_boards: Manage boards +permission_view_messages: View messages +permission_add_messages: Post messages +permission_edit_messages: Edit messages +permission_edit_own_messages: Edit own messages +permission_delete_messages: Delete messages +permission_delete_own_messages: Delete own messages + +project_module_issue_tracking: Darbu pėdsekys +project_module_time_tracking: Laiko pėdsekys +project_module_news: Žinios +project_module_documents: Dokumentai +project_module_files: Rinkmenos +project_module_wiki: Wiki +project_module_repository: Saugykla +project_module_boards: Forumai + label_user: Vartotojas -label_user_plural: Vartotojai -label_user_new: Naujas vartotojas -label_project: Projektas -label_project_new: Naujas projektas -label_project_plural: Projektai -label_project_all: Visi Projektai -label_project_latest: Paskutiniai projektai -label_issue: Darbas -label_issue_new: Naujas darbas -label_issue_plural: Darbai +label_user_plural: Vartotojai +label_user_new: Naujas vartotojas +label_project: Projektas +label_project_new: Naujas projektas +label_project_plural: Projektai +label_project_all: Visi Projektai +label_project_latest: Paskutiniai projektai +label_issue: Darbas +label_issue_new: Naujas darbas +label_issue_plural: Darbai label_issue_view_all: Peržiūrėti visus darbus -label_issues_by: Darbai pagal %s +label_issues_by: Darbai pagal %s +label_issue_added: Darbas pridėtas +label_issue_updated: Darbas atnaujintas label_document: Dokumentas label_document_new: Naujas dokumentas -label_document_plural: Dokumentai -label_role: Vaidmuo -label_role_plural: Vaidmenys -label_role_new: Naujas vaidmuo -label_role_and_permissions: Vaidmenys ir leidimai -label_member: Narys -label_member_new: Naujas narys -label_member_plural: Nariai -label_tracker: Pėdsekys -label_tracker_plural: Pėdsekiai -label_tracker_new: Naujas pėdsekys -label_workflow: Darbų eiga -label_issue_status: Darbo padėtis -label_issue_status_plural: Darbų padėtys -label_issue_status_new: Nauja padėtis -label_issue_category: Darbo kategorija -label_issue_category_plural: Darbo kategorijos -label_issue_category_new: Nauja kategorija -label_custom_field: Kliento laukas -label_custom_field_plural: Kliento laukai -label_custom_field_new: Naujas kliento laukas -label_enumerations: Išvardinimai -label_enumeration_new: Nauja vertė -label_information: Informacija -label_information_plural: Informacija -label_please_login: Prašom prisijungti -label_register: Užsiregistruoti +label_document_plural: Dokumentai +label_document_added: Dokumentas pridėtas +label_role: Vaidmuo +label_role_plural: Vaidmenys +label_role_new: Naujas vaidmuo +label_role_and_permissions: Vaidmenys ir leidimai +label_member: Narys +label_member_new: Naujas narys +label_member_plural: Nariai +label_tracker: Pėdsekys +label_tracker_plural: Pėdsekiai +label_tracker_new: Naujas pėdsekys +label_workflow: Darbų eiga +label_issue_status: Darbo padėtis +label_issue_status_plural: Darbų padėtys +label_issue_status_new: Nauja padėtis +label_issue_category: Darbo kategorija +label_issue_category_plural: Darbo kategorijos +label_issue_category_new: Nauja kategorija +label_custom_field: Kliento laukas +label_custom_field_plural: Kliento laukai +label_custom_field_new: Naujas kliento laukas +label_enumerations: Išvardinimai +label_enumeration_new: Nauja vertė +label_information: Informacija +label_information_plural: Informacija +label_please_login: Prašom prisijungti +label_register: Užsiregistruoti label_password_lost: Prarastas slaptažodis -label_home: Pagrindinis +label_home: Pagrindinis label_my_page: Mano puslapis -label_my_account: Mano paskyra -label_my_projects: Mano projektai -label_administration: Administravimas -label_login: Prisijungti -label_logout: Atsijungti -label_help: Pagalba -label_reported_issues: Pranešti darbai -label_assigned_to_me_issues: Darbai, priskirti man -label_last_login: Paskutinis ryšys +label_my_account: Mano paskyra +label_my_projects: Mano projektai +label_administration: Administravimas +label_login: Prisijungti +label_logout: Atsijungti +label_help: Pagalba +label_reported_issues: Pranešti darbai +label_assigned_to_me_issues: Darbai, priskirti man +label_last_login: Paskutinis ryšys label_last_updates: Paskutinis atnaujinimas -label_last_updates_plural: %d paskutinis atnaujinimas -label_registered_on: Užregistruota -label_activity: Veikla -label_new: Naujas -label_logged_as: Prisijungęs kaip -label_environment: Aplinka -label_authentication: Autentiškumo nustatymas -label_auth_source: Autentiškumo nustatymo būdas -label_auth_source_new: Naujas autentiškumo nustatymo būdas -label_auth_source_plural: Autentiškumo nustatymo būdai -label_subproject_plural: Subprojektai -label_min_max_length: Min - Maks ilgis -label_list: Sąrašas -label_date: Data -label_integer: Sveikasis skaičius -label_float: Float -label_boolean: Boolean -label_string: Tekstas -label_text: Ilgas tekstas -label_attribute: Požymis -label_attribute_plural: Požymiai -label_download: %d Persiuntimas -label_download_plural: %d Persiuntimai -label_no_data: Nėra ką atvaizduoti -label_change_status: Pakeitimo padėtis -label_history: Istorija +label_last_updates_plural: %d paskutinis atnaujinimas +label_registered_on: Užregistruota +label_activity: Veikla +label_overall_activity: Visa veikla +label_user_activity: "%so veiksmai" +label_new: Naujas +label_logged_as: Prisijungęs kaip +label_environment: Aplinka +label_authentication: Autentiškumo nustatymas +label_auth_source: Autentiškumo nustatymo būdas +label_auth_source_new: Naujas autentiškumo nustatymo būdas +label_auth_source_plural: Autentiškumo nustatymo būdai +label_subproject_plural: Subprojektai +label_and_its_subprojects: %s projektas ir jo subprojektai +label_min_max_length: Min - Maks ilgis +label_list: Sąrašas +label_date: Data +label_integer: Sveikasis skaičius +label_float: Float +label_boolean: Boolean +label_string: Tekstas +label_text: Ilgas tekstas +label_attribute: Požymis +label_attribute_plural: Požymiai +label_download: %d Persiuntimas +label_download_plural: %d Persiuntimai +label_no_data: Nėra ką atvaizduoti +label_change_status: Pakeitimo padėtis +label_history: Istorija label_attachment: Rinkmena label_attachment_new: Nauja rinkmena label_attachment_delete: Pašalinkite rinkmeną -label_attachment_plural: Rinkmenos +label_attachment_plural: Rinkmenos +label_file_added: Byla pridėta label_report: Ataskaita -label_report_plural: Ataskaitos -label_news: Žinia -label_news_new: Pridėkite žinią -label_news_plural: Žinios -label_news_latest: Paskutinės naujienos -label_news_view_all: Peržiūrėti visas žinias -label_change_log: Pakeitimų žurnalas -label_settings: Nustatymai -label_overview: Apžvalga +label_report_plural: Ataskaitos +label_news: Žinia +label_news_new: Pridėkite žinią +label_news_plural: Žinios +label_news_latest: Paskutinės naujienos +label_news_view_all: Peržiūrėti visas žinias +label_news_added: Naujiena pridėta +label_change_log: Pakeitimų žurnalas +label_settings: Nustatymai +label_overview: Apžvalga label_version: Versija label_version_new: Nauja versija -label_version_plural: Versijos -label_confirmation: Patvirtinimas -label_export_to: Eksportuoti į -label_read: Skaitykite... -label_public_projects: Vieši projektai +label_version_plural: Versijos +label_confirmation: Patvirtinimas +label_export_to: Eksportuoti į +label_read: Skaitykite... +label_public_projects: Vieši projektai label_open_issues: atidaryta label_open_issues_plural: atidarytos -label_closed_issues: uždaryta +label_closed_issues: uždaryta label_closed_issues_plural: uždarytos -label_total: Bendra suma -label_permissions: Leidimai -label_current_status: Einamoji padėtis -label_new_statuses_allowed: Naujos padėtys galimos -label_all: visi -label_none: niekas -label_nobody: niekas -label_next: Kitas -label_previous: Ankstesnis -label_used_by: Naudotas -label_details: Detalės -label_add_note: Pridėkite pastabą +label_total: Bendra suma +label_permissions: Leidimai +label_current_status: Einamoji padėtis +label_new_statuses_allowed: Naujos padėtys galimos +label_all: visi +label_none: niekas +label_nobody: niekas +label_next: Kitas +label_previous: Ankstesnis +label_used_by: Naudotas +label_details: Detalės +label_add_note: Pridėkite pastabą label_per_page: Per puslapį -label_calendar: Kalendorius -label_months_from: mėnesiai nuo -label_gantt: Gantt -label_internal: Vidinis -label_last_changes: paskutiniai %d, pokyčiai -label_change_view_all: Peržiūrėti visus pakeitimus +label_calendar: Kalendorius +label_months_from: mėnesiai nuo +label_gantt: Gantt +label_internal: Vidinis +label_last_changes: paskutiniai %d, pokyčiai +label_change_view_all: Peržiūrėti visus pakeitimus label_personalize_page: Suasmeninti šį puslapį label_comment: Komentaras -label_comment_plural: Komentarai +label_comment_plural: Komentarai label_comment_add: Pridėkite komentarą -label_comment_added: Komentaras pridėtas -label_comment_delete: Pašalinkite komentarus +label_comment_added: Komentaras pridėtas +label_comment_delete: Pašalinkite komentarus label_query: Užklausa -label_query_plural: Užklausos -label_query_new: Nauja užklausa -label_filter_add: Pridėti filtrą -label_filter_plural: Filtrai -label_equals: yra -label_not_equals: nėra -label_in_less_than: mažiau negu -label_in_more_than: daugiau negu +label_query_plural: Užklausos +label_query_new: Nauja užklausa +label_filter_add: Pridėti filtrą +label_filter_plural: Filtrai +label_equals: yra +label_not_equals: nėra +label_in_less_than: mažiau negu +label_in_more_than: daugiau negu label_in: in -label_today: šiandien -label_this_week: šią savaitę -label_less_than_ago: mažiau negu dienomis prieš -label_more_than_ago: daugiau negu dienomis prieš -label_ago: dienomis prieš -label_contains: turi savyje -label_not_contains: neturi savyje -label_day_plural: dienos -label_repository: Saugykla +label_today: šiandien +label_all_time: visas laikas +label_yesterday: vakar +label_this_week: šią savaitę +label_last_week: paskutinė savaitė +label_last_n_days: paskutinių %d dienų +label_this_month: šis menuo +label_last_month: paskutinis menuo +label_this_year: šiemet +label_date_range: Dienų diapazonas +label_less_than_ago: mažiau negu dienomis prieš +label_more_than_ago: daugiau negu dienomis prieš +label_ago: dienomis prieš +label_contains: turi savyje +label_not_contains: neturi savyje +label_day_plural: dienos +label_repository: Saugykla +label_repository_plural: Saugiklos label_browse: Naršyti -label_modification: %d pakeitimas -label_modification_plural: %d pakeitimai -label_revision: Revizija -label_revision_plural: Revizijos -label_added: pridėtas -label_modified: pakeistas -label_deleted: pašalintas +label_modification: %d pakeitimas +label_modification_plural: %d pakeitimai +label_revision: Revizija +label_revision_plural: Revizijos +label_associated_revisions: susijusios revizijos +label_added: pridėtas +label_modified: pakeistas +label_copied: nukopijuotas +label_renamed: pervardintas +label_deleted: pašalintas label_latest_revision: Paskutinė revizija -label_latest_revision_plural: Paskutinės revizijos -label_view_revisions: Pežiūrėti revizijas -label_max_size: Maksimalus dydis -label_on: 'iš' -label_sort_highest: Perkelti į viršūnę -label_sort_higher: Perkelti į viršų -label_sort_lower: Perkelti žemyn -label_sort_lowest: Perkelti į apačią -label_roadmap: Veiklos grafikas +label_latest_revision_plural: Paskutinės revizijos +label_view_revisions: Pežiūrėti revizijas +label_max_size: Maksimalus dydis +label_on: 'iš' +label_sort_highest: Perkelti į viršūnę +label_sort_higher: Perkelti į viršų +label_sort_lower: Perkelti žemyn +label_sort_lowest: Perkelti į apačią +label_roadmap: Veiklos grafikas label_roadmap_due_in: Baigiasi po %s -label_roadmap_overdue: %s vėluojama +label_roadmap_overdue: %s vėluojama label_roadmap_no_issues: Jokio darbo šiai versijai nėra -label_search: Ieškoti -label_result_plural: Rezultatai -label_all_words: Visi žodžiai -label_wiki: Wiki -label_wiki_edit: Wiki redakcija -label_wiki_edit_plural: Wiki redakcijos +label_search: Ieškoti +label_result_plural: Rezultatai +label_all_words: Visi žodžiai +label_wiki: Wiki +label_wiki_edit: Wiki redakcija +label_wiki_edit_plural: Wiki redakcijos label_wiki_page: Wiki puslapis -label_wiki_page_plural: Wiki puslapiai -label_index_by_title: Indeksas prie pavadinimo -label_index_by_date: Indeksas prie datos +label_wiki_page_plural: Wiki puslapiai +label_index_by_title: Indeksas prie pavadinimo +label_index_by_date: Indeksas prie datos label_current_version: Einamoji versija -label_preview: Peržiūra +label_preview: Peržiūra label_feed_plural: Įeitys(Feeds) -label_changes_details: Visų pakeitimų detalės -label_issue_tracking: Darbų sekimas -label_spent_time: Sugaištas laikas -label_f_hour: %.2f valanda -label_f_hour_plural: %.2f valandų -label_time_tracking: Laiko sekimas -label_change_plural: Pakeitimai -label_statistics: Statistika -label_commits_per_month: Paveda(commit) per mėnesį -label_commits_per_author: Autoriaus pavedos(commit) -label_view_diff: Skirtumų peržiūra -label_diff_inline: įterptas -label_diff_side_by_side: šalia +label_changes_details: Visų pakeitimų detalės +label_issue_tracking: Darbų sekimas +label_spent_time: Sugaištas laikas +label_f_hour: %.2f valanda +label_f_hour_plural: %.2f valandų +label_time_tracking: Laiko sekimas +label_change_plural: Pakeitimai +label_statistics: Statistika +label_commits_per_month: Paveda(commit) per mėnesį +label_commits_per_author: Autoriaus pavedos(commit) +label_view_diff: Skirtumų peržiūra +label_diff_inline: įterptas +label_diff_side_by_side: šalia label_options: Pasirinkimai -label_copy_workflow_from: Kopijuoti darbų eiga iš -label_permissions_report: Leidimų pranešimas -label_watched_issues: Stebimi darbai -label_related_issues: Susiję darbai -label_applied_status: Taikomoji padėtis -label_loading: Kraunama... -label_relation_new: Naujas ryšys -label_relation_delete: Pašalinkite ryšį -label_relates_to: susietas su -label_duplicates: dublikatai -label_blocks: blokai -label_blocked_by: blokuotas -label_precedes: įvyksta pirma -label_follows: seka +label_copy_workflow_from: Kopijuoti darbų eiga iš +label_permissions_report: Leidimų pranešimas +label_watched_issues: Stebimi darbai +label_related_issues: Susiję darbai +label_applied_status: Taikomoji padėtis +label_loading: Kraunama... +label_relation_new: Naujas ryšys +label_relation_delete: Pašalinkite ryšį +label_relates_to: susietas su +label_duplicates: dubliuoja +label_duplicated_by: dubliuojasi +label_blocks: blokuoja +label_blocked_by: blokuojasi +label_precedes: ankstesnė +label_follows: seka label_end_to_start: užbaigti, kad pradėti -label_end_to_end: užbaigti, kad pabaigti -label_start_to_start: pradėkite pradėti -label_start_to_end: pradėkite užbaigti -label_stay_logged_in: Likti prisijungus -label_disabled: išjungta(as) -label_show_completed_versions: Parodyti užbaigtas versijas -label_me: aš -label_board: Forumas -label_board_new: Naujas forumas -label_board_plural: Forumai -label_topic_plural: Temos -label_message_plural: Pranešimai +label_end_to_end: užbaigti, kad pabaigti +label_start_to_start: pradėkite pradėti +label_start_to_end: pradėkite užbaigti +label_stay_logged_in: Likti prisijungus +label_disabled: išjungta(as) +label_show_completed_versions: Parodyti užbaigtas versijas +label_me: aš +label_board: Forumas +label_board_new: Naujas forumas +label_board_plural: Forumai +label_topic_plural: Temos +label_message_plural: Pranešimai label_message_last: Paskutinis pranešimas label_message_new: Naujas pranešimas -label_reply_plural: Atsakymai -label_send_information: Nusiųsti paskyros informaciją vartotojui -label_year: Metai -label_month: Mėnuo -label_week: Savaitė -label_date_from: Nuo -label_date_to: Iki -label_language_based: Pagrįsta vartotojo kalba -label_sort_by: Rūšiuoti pagal %s -label_send_test_email: Nusiųsti bandomąjį elektroninį laišką -label_feeds_access_key_created_on: RSS prieigos raktas sukūrtas prieš %s -label_module_plural: Moduliai +label_message_posted: Pranešimas pridėtas +label_reply_plural: Atsakymai +label_send_information: Nusiųsti paskyros informaciją vartotojui +label_year: Metai +label_month: Mėnuo +label_week: Savaitė +label_date_from: Nuo +label_date_to: Iki +label_language_based: Pagrįsta vartotojo kalba +label_sort_by: Rūšiuoti pagal %s +label_send_test_email: Nusiųsti bandomąjį elektroninį laišką +label_feeds_access_key_created_on: RSS prieigos raktas sukūrtas prieš %s +label_module_plural: Moduliai label_added_time_by: Pridėjo %s prieš %s -label_updated_time: Atnaujinta prieš %s -label_jump_to_a_project: Šuolis į projektą... -label_file_plural: Bylos -label_changeset_plural: Changesets -label_default_columns: Numatytosios skiltys -label_no_change_option: (Jokio pakeitimo) -label_bulk_edit_selected_issues: Masinis pasirinktų darbų(issues) redagavimas -label_theme: Tema -label_default: Numatyta(as) -label_search_titles_only: Ieškoti pavadinimų tiktai -label_user_mail_option_all: "Bet kokiam įvykiui visuose mano projektuose" -label_user_mail_option_selected: "Bet kokiam įvykiui tiktai pasirinktuose projektuose ..." -label_user_mail_option_none: "Tiktai dalykai kuriuos aš stebiu ar aš esu įtrauktas į" +label_updated_time_by: Atnaujino %s %s atgal +label_updated_time: Atnaujinta prieš %s +label_jump_to_a_project: Šuolis į projektą... +label_file_plural: Bylos +label_changeset_plural: Changesets +label_default_columns: Numatyti stulpeliai +label_no_change_option: (Jokio pakeitimo) +label_bulk_edit_selected_issues: Masinis pasirinktų darbų(issues) redagavimas +label_theme: Tema +label_default: Numatyta(as) +label_search_titles_only: Ieškoti pavadinimų tiktai +label_user_mail_option_all: "Bet kokiam įvykiui visuose mano projektuose" +label_user_mail_option_selected: "Bet kokiam įvykiui tiktai pasirinktuose projektuose ..." +label_user_mail_option_none: "Tiktai dalykai kuriuos aš stebiu ar aš esu įtrauktas į" label_user_mail_no_self_notified: "Nenoriu būti informuotas apie pakeitimus, kuriuos pats atlieku" label_registration_activation_by_email: "paskyros aktyvacija per e-paštą" label_registration_manual_activation: "rankinė paskyros aktyvacija" label_registration_automatic_activation: "automatinė paskyros aktyvacija" - -button_login: Registruotis -button_submit: Pateikti -button_save: Išsaugoti +label_display_per_page: '%s įrašų puslapyje' +label_age: Amžius +label_change_properties: Pakeisti nustatymus +label_general: Bendri +label_more: Daugiau +label_scm: SCM +label_plugins: Plugins +label_ldap_authentication: LDAP autentifikacija +label_downloads_abbr: siunt. +label_optional_description: Apibūdinimas (laisvai pasirenkamas) +label_add_another_file: Pridėti kitą bylą +label_preferences: Savybės +label_chronological_order: Chronologine tvarka +label_reverse_chronological_order: Atbuline chronologine tvarka +label_planning: Planavimas +label_incoming_emails: Įeinantys laiškai +label_generate_key: Generuoti raktą +label_issue_watchers: Stebėtojai +label_example: Pavizdys + +button_login: Registruotis +button_submit: Pateikti +button_save: Išsaugoti button_check_all: Žymėti visus button_uncheck_all: Atžymėti visus -button_delete: Trinti -button_create: Sukurti -button_test: Testas -button_edit: Redaguoti -button_add: Pridėti -button_change: Keisti +button_delete: Trinti +button_create: Sukurti +button_test: Testas +button_edit: Redaguoti +button_add: Pridėti +button_change: Keisti button_apply: Pritaikyti -button_clear: Išvalyti -button_lock: Rakinti -button_unlock: Atrakinti -button_download: Atsisiųsti -button_list: Sąrašas -button_view: Žiūrėti -button_move: Perkelti -button_back: Atgal -button_cancel: Atšaukti -button_activate: Aktyvinti +button_clear: Išvalyti +button_lock: Rakinti +button_unlock: Atrakinti +button_download: Atsisiųsti +button_list: Sąrašas +button_view: Žiūrėti +button_move: Perkelti +button_back: Atgal +button_cancel: Atšaukti +button_activate: Aktyvinti button_sort: Rūšiuoti -button_log_time: Praleistas laikas +button_log_time: Praleistas laikas button_rollback: Grįžti į šią versiją -button_watch: Stebėti +button_watch: Stebėti button_unwatch: Nestebėti -button_reply: Atsakyti +button_reply: Atsakyti button_archive: Archyvuoti -button_unarchive: Išpakuoti -button_reset: Reset -button_rename: Pervadinti +button_unarchive: Išpakuoti +button_reset: Reset +button_rename: Pervadinti button_change_password: Pakeisti slaptažodį -button_copy: Kopijuoti -button_annotate: Rašyti pastabą - -status_active: aktyvus -status_registered: užregistruotas -status_locked: užrakintas - +button_copy: Kopijuoti +button_annotate: Rašyti pastabą +button_update: Atnaujinti +button_configure: Konfigūruoti +button_quote: Cituoti + +status_active: aktyvus +status_registered: užregistruotas +status_locked: užrakintas + text_select_mail_notifications: Išrinkite veiksmus, apie kuriuos būtų pranešta elektroniniu paštu. -text_regexp_info: pvz. ^[A-Z0-9]+$ +text_regexp_info: pvz. ^[A-Z0-9]+$ text_min_max_length_info: 0 reiškia jokių apribojimų -text_project_destroy_confirmation: Ar esate įsitikinęs, kad jūs norite pašalinti šį projektą ir visus susijusius duomenis? -text_workflow_edit: Išrinkite vaidmenį ir pėdsekį, kad redaguotumėte darbų eigą -text_are_you_sure: Ar esate įsitikinęs? -text_journal_changed: pakeistas iš %s į %s -text_journal_set_to: nustatyta į %s -text_journal_deleted: ištrintas -text_tip_task_begin_day: užduotis, prasidedanti šią dieną -text_tip_task_end_day: užduotis, pasibaigianti šią dieną -text_tip_task_begin_end_day: užduotis, prasidedanti ir pasibaigianti šią dieną -text_project_identifier_info: 'Mažosios raidės (a-z), skaičiai ir brūkšniai galimi.
    Išsaugojus, identifikuotojas negali būti keičiamas.' -text_caracters_maximum: %d simbolių maksimumas. -text_caracters_minimum: Turi būti mažiausiai %d simbolių ilgio. -text_length_between: Ilgis tarp %d ir %d simbolių. -text_tracker_no_workflow: Jokia darbų eiga neapibrėžta šiam pėdsekiui -text_unallowed_characters: Neleistini simboliai -text_comma_separated: Leistinos kelios reikšmės (atskirtos kableliu). -text_issues_ref_in_commit_messages: Darbų pavedimų(commit) nurodymas ir fiksavimas pranešimuose -text_issue_added: Darbas %s buvo praneštas (by %s). -text_issue_updated: Darbas %s buvo atnaujintas (by %s). -text_wiki_destroy_confirmation: Ar esate įsitikinęs, kad jūs norite pašalinti wiki ir visą jos turinį? -text_issue_category_destroy_question: Kai kurie darbai (%d) yra paskirti šiai kategorijai. Ką jūs norite daryti? -text_issue_category_destroy_assignments: Pašalinti kategorijos užduotis -text_issue_category_reassign_to: Iš naujo priskirti darbus šiai kategorijai -text_user_mail_option: "neišrinktiems projektams, jūs tiktai gausite pranešimus apie įvykius, kuriuos jūs stebite, arba į kuriuos esate įtrauktas (pvz. darbai, jūs esate autorius ar įgaliotinis)." - -default_role_manager: Vadovas -default_role_developper: Projektuotojas -default_role_reporter: Pranešėjas -default_tracker_bug: Klaida -default_tracker_feature: Ypatybė -default_tracker_support: Palaikymas -default_issue_status_new: Nauja -default_issue_status_assigned: Priskirta -default_issue_status_resolved: Išspręsta -default_issue_status_feedback: Grįžtamasis ryšys -default_issue_status_closed: Uždaryta -default_issue_status_rejected: Atmesta -default_doc_category_user: Vartotojo dokumentacija -default_doc_category_tech: Techniniai dokumentacija -default_priority_low: Žemas -default_priority_normal: Normalus -default_priority_high: Aukštas -default_priority_urgent: Skubus -default_priority_immediate: Neatidėliotinas -default_activity_design: Projektavimas -default_activity_development: Vystymas - -enumeration_issue_priorities: Darbo prioritetai -enumeration_doc_categories: Dokumento kategorijos -enumeration_activities: Veiklos (laiko sekimas) -label_display_per_page: '%s įrašų puslapyje' -setting_per_page_options: Įrašų puslapyje nustatimas -notice_default_data_loaded: Numatytoji konfiguracija sėkmingai užkrauta. -label_age: Amžius -label_general: Bendri -button_update: Atnaujinti -setting_issues_export_limit: Darbų eksportavimo limitas -label_change_properties: Pakeisti nustatymus -text_load_default_configuration: Užkrauti numatytąj konfiguraciją +text_project_destroy_confirmation: Ar esate įsitikinęs, kad jūs norite pašalinti šį projektą ir visus susijusius duomenis? +text_subprojects_destroy_warning: 'Šis(ie) subprojektas(ai): %s taip pat bus ištrintas(i).' +text_workflow_edit: Išrinkite vaidmenį ir pėdsekį, kad redaguotumėte darbų eigą +text_are_you_sure: Ar esate įsitikinęs? +text_journal_changed: pakeistas iš %s į %s +text_journal_set_to: nustatyta į %s +text_journal_deleted: ištrintas +text_tip_task_begin_day: užduotis, prasidedanti šią dieną +text_tip_task_end_day: užduotis, pasibaigianti šią dieną +text_tip_task_begin_end_day: užduotis, prasidedanti ir pasibaigianti šią dieną +text_project_identifier_info: 'Mažosios raidės (a-z), skaičiai ir brūkšniai galimi.
    Išsaugojus, identifikuotojas negali būti keičiamas.' +text_caracters_maximum: %d simbolių maksimumas. +text_caracters_minimum: Turi būti mažiausiai %d simbolių ilgio. +text_length_between: Ilgis tarp %d ir %d simbolių. +text_tracker_no_workflow: Jokia darbų eiga neapibrėžta šiam pėdsekiui +text_unallowed_characters: Neleistini simboliai +text_comma_separated: Leistinos kelios reikšmės (atskirtos kableliu). +text_issues_ref_in_commit_messages: Darbų pavedimų(commit) nurodymas ir fiksavimas pranešimuose +text_issue_added: Darbas %s buvo praneštas (by %s). +text_issue_updated: Darbas %s buvo atnaujintas (by %s). +text_wiki_destroy_confirmation: Ar esate įsitikinęs, kad jūs norite pašalinti wiki ir visą jos turinį? +text_issue_category_destroy_question: Kai kurie darbai (%d) yra paskirti šiai kategorijai. Ką jūs norite daryti? +text_issue_category_destroy_assignments: Pašalinti kategorijos užduotis +text_issue_category_reassign_to: Iš naujo priskirti darbus šiai kategorijai +text_user_mail_option: "neišrinktiems projektams, jūs tiktai gausite pranešimus apie įvykius, kuriuos jūs stebite, arba į kuriuos esate įtrauktas (pvz. darbai, jūs esate autorius ar įgaliotinis)." text_no_configuration_data: "Vaidmenys, pėdsekiai, darbų būsenos ir darbų eiga dar nebuvo konfigūruoti.\nGriežtai rekomenduojam užkrauti numatytąją(default)konfiguraciją. Užkrovus, galėsite ją modifikuoti." -label_repository_plural: Saugiklos -error_can_t_load_default_data: "Numatytoji konfiguracija negali būti užkrauta: %s" -label_associated_revisions: susijusios revizijos -setting_user_format: Vartotojo atvaizdavimo formatas +text_load_default_configuration: Užkrauti numatytąj konfiguraciją text_status_changed_by_changeset: Pakeista %s revizijoi. -label_more: Daugiau text_issues_destroy_confirmation: 'Ar jūs tikrai norite panaikinti pažimėtą(us) darbą(us)?' -label_scm: SCM text_select_project_modules: 'Parinkite modulius, kuriuos norite naudoti šiame projekte:' -label_issue_added: Darbas pridėtas -label_issue_updated: Darbas atnaujintas -label_document_added: Dokumentas pridėtas -label_message_posted: Pranešimas pridėtas -label_file_added: Byla pridėta -label_news_added: Naujiena pridėta -project_module_boards: Forumai -project_module_issue_tracking: Darbu pėdsekys -project_module_wiki: Wiki -project_module_files: Rinkmenos -project_module_documents: Dokumentai -project_module_repository: Saugykla -project_module_news: Žinios -project_module_time_tracking: Laiko pėdsekys -text_file_repository_writable: Į rinkmenu saugyklą galima saugoti (RW) text_default_administrator_account_changed: Administratoriaus numatyta paskyra pakeista +text_file_repository_writable: Į rinkmenu saugyklą galima saugoti (RW) text_rmagick_available: RMagick pasiekiamas (pasirinktinai) -button_configure: Konfiguruoti -label_plugins: Plugins -label_ldap_authentication: LDAP autentifikacija -label_downloads_abbr: siunt. -label_this_month: šis menuo -label_last_n_days: paskutinių %d dienų -label_all_time: visas laikas -label_this_year: šiemet -label_date_range: Dienų diapazonas -label_last_week: paskutinė savaitė -label_yesterday: vakar -label_last_month: paskutinis menuo -label_add_another_file: Pridėti kitą bylą -label_optional_description: Apibūdinimas (laisvai pasirenkamas) text_destroy_time_entries_question: Naikinamam darbui paskelbta %.02f valandų. Ką jūs noryte su jomis daryti? -error_issue_not_found_in_project: 'Darbas nerastas arba nesurištas su šiuo projektu' -text_assign_time_entries_to_project: Priskirti valandas prie projekto text_destroy_time_entries: Ištrinti paskelbtas valandas +text_assign_time_entries_to_project: Priskirti valandas prie projekto text_reassign_time_entries: 'Priskirti paskelbtas valandas šiam darbui:' -setting_activity_days_default: Atvaizduojamos dienos projekto veikloje -label_chronological_order: Chronologine tvarka -field_comments_sorting: rodyti komentarus -label_reverse_chronological_order: Atbuline chronologine tvarka -label_preferences: Savybės -setting_display_subprojects_issues: Pagal nutylėjimą rodyti subprojektų darbus pagrindiniame projekte -label_overall_activity: Visa veikla -setting_default_projects_public: Naujas projektas viešas pagal nutylėjimą -error_scm_annotate: "Įrašas neegzituoja arba negalima jo atvaizduoti." -label_planning: Planavimas -text_subprojects_destroy_warning: 'Šis(ie) subprojektas(ai): %s taip pat bus ištrintas(i).' -label_and_its_subprojects: %s projektas ir jo subprojektai - -mail_body_reminder: "%d darbas(ai), kurie yra jums priskirti, baigiasi po %d dienų(os):" -mail_subject_reminder: "%d darbas(ai) po kelių dienų" text_user_wrote: '%s parašė:' -label_duplicated_by: susiejo -setting_enabled_scm: Įgalintas SCM -text_enumeration_category_reassign_to: 'Priskirti juos šiai reikšmei:' text_enumeration_destroy_question: '%d objektai priskirti šiai reikšmei.' -label_incoming_emails: Įeinantys laiškai -label_generate_key: Generuoti raktą -setting_mail_handler_api_enabled: Įgalinti WS įeinantiems laiškams -setting_mail_handler_api_key: API raktas +text_enumeration_category_reassign_to: 'Priskirti juos šiai reikšmei:' text_email_delivery_not_configured: "Email pristatymas nesukonfigūruotas , ir perspėjimai neaktyvus.\nSukonfigūruokyte savo SMTP serverį byloje config/email.yml ir perleiskyte programą kad pritaikyti pakeitymus." -field_parent_title: Aukštesnio lygio puslapis -label_issue_watchers: Stebetojai -setting_commit_logs_encoding: Commit pranėšimų koduotė -setting_sequential_project_identifiers: Generate sequential project identifiers -button_quote: Cituoti -notice_unable_delete_version: Neimanoma panaikinti versiją -label_renamed: pervardintas -label_copied: nukopijuotas -setting_repositories_cache_directory: Cache directory for repositories -field_cache: Local cache +text_repository_usernames_mapping: "Select ou update the Redmine user mapped to each username found in the repository log.\nUsers with the same Redmine and repository username or email are automatically mapped." +text_diff_truncated: "... Šis diff'as nukarpitas, todėl kad jis viršijo maksimalu rodoma eilučiu skaičiu." + +default_role_manager: Vadovas +default_role_developper: Projektuotojas +default_role_reporter: Pranešėjas +default_tracker_bug: Klaida +default_tracker_feature: Ypatybė +default_tracker_support: Palaikymas +default_issue_status_new: Nauja +default_issue_status_assigned: Priskirta +default_issue_status_resolved: Išspręsta +default_issue_status_feedback: Grįžtamasis ryšys +default_issue_status_closed: Uždaryta +default_issue_status_rejected: Atmesta +default_doc_category_user: Vartotojo dokumentacija +default_doc_category_tech: Techniniai dokumentacija +default_priority_low: Žemas +default_priority_normal: Normalus +default_priority_high: Aukštas +default_priority_urgent: Skubus +default_priority_immediate: Neatidėliotinas +default_activity_design: Projektavimas +default_activity_development: Vystymas + +enumeration_issue_priorities: Darbo prioritetai +enumeration_doc_categories: Dokumento kategorijos +enumeration_activities: Veiklos (laiko sekimas) +text_plugin_assets_writable: Plugin assets directory writable +warning_attachments_not_saved: "%d file(s) could not be saved." +button_create_and_continue: Create and continue +text_custom_field_possible_values_info: 'One line for each value' +label_display: Display +field_editable: Editable +setting_repository_log_display_limit: Maximum number of revisions displayed on file log +field_identity_url: OpenID URL +setting_openid: Allow OpenID login and registration +label_login_with_open_id_option: or login with OpenID +field_watcher: Watcher diff --git a/lang/mk.yml b/lang/mk.yml new file mode 100644 index 000000000..269d4dddb --- /dev/null +++ b/lang/mk.yml @@ -0,0 +1,711 @@ +_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: doesn't match 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: This relation would create a circular dependency + +general_fmt_age: %d год. +general_fmt_age_plural: %d год. +general_fmt_date: %%d/%%m/%%Y +general_fmt_datetime: %%d/%%m/%%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: 'Македонски' +general_csv_separator: ',' +general_csv_decimal_separator: '.' +general_csv_encoding: UTF-8 +general_pdf_encoding: UTF-8 +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: Data has been updated by another user. +notice_not_authorized: Немате овластување да пристапите до оваа страница. +notice_email_sent: Испратена е е-порака до %s +notice_email_error: Грешка при праќањето на е-пошта (%s) +notice_feeds_access_key_reseted: Вашиот RSS клуч е ресетиран. +notice_failed_to_save_issues: "Failed to save %d issue(s) on %d selected: %s." +notice_no_issue_selected: "Не е избрана задача! Изберете ги задачите што сакате да ги уредувате." +notice_account_pending: "Вашиот профил е креиран и чека одобрување од администраторот." +notice_default_data_loaded: Основната конфигурација е успешно вчитана. +notice_unable_delete_version: Верзијата неможе да се избрише. + +error_can_t_load_default_data: "Основната конфигурација неможе да биде вчитана: %s" +error_scm_not_found: "The entry or revision was not found in the repository." +error_scm_command_failed: "An error occurred when trying to access the repository: %s" +error_scm_annotate: "The entry does not exist or can not be annotated." +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) е регистриран. Профилот чека на Ваше одобрување:' +mail_subject_reminder: "%d issue(s) due in the next days" +mail_body_reminder: "%d issue(s) that are assigned to you are due in the next %d days:" + +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: Tracker +field_subject: Наслов +field_due_date: Краен датум +field_assigned_to: Доделена на +field_priority: Приоритет +field_fixed_version: За верзија +field_user: Корисник +field_role: Функција +field_homepage: Homepagе +field_is_public: Јавен +field_parent: Подпроект на +field_is_in_chlog: Issues displayed in changelog +field_is_in_roadmap: Issues displayed 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: Account +field_base_dn: Base DN +field_attr_login: Login attribute +field_attr_firstname: Firstname attribute +field_attr_lastname: Lastname attribute +field_attr_mail: Email attribute +field_onthefly: On-the-fly user creation +field_start_date: Старт +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: Used as a filter +field_issue_to_id: Related issue +field_delay: Каснење +field_assignable: На оваа функција може да и се доделуваат задачи +field_redirect_existing_links: Redirect existing links +field_estimated_hours: Предвидено време +field_column_names: Колони +field_time_zone: Временска зона +field_searchable: Searchable +field_default_value: Основна вредност +field_comments_sorting: Прикажи коментари +field_parent_title: Parent page + +setting_app_title: Име на апликацијата +setting_app_subtitle: Application 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: Blind carbon copy recipients (bcc) +setting_plain_text_mail: обичен текст (без HTML) +setting_host_name: Име на хостот и патека +setting_text_formatting: Форматирање на текст +setting_wiki_compression: Компресија на историјата на Вики +setting_feeds_limit: Feed content limit +setting_default_projects_public: Новите проекти се иницијално јавни +setting_autofetch_changesets: Autofetch commits +setting_sys_api_enabled: Enable WS for repository management +setting_commit_ref_keywords: Referencing keywords +setting_commit_fix_keywords: Fixing keywords +setting_autologin: Автоматска најава +setting_date_format: Формат на дата +setting_time_format: Формат на време +setting_cross_project_issue_relations: Allow cross-project issue relations +setting_issue_list_default_columns: Default columns displayed on the issue list +setting_repositories_encodings: Repositories encodings +setting_commit_logs_encoding: Commit messages encoding +setting_emails_footer: Подножје на е-пораките +setting_protocol: Протокол +setting_per_page_options: Objects per page options +setting_user_format: Приказ на корисник +setting_activity_days_default: Денови прикажани од активноста на проект +setting_display_subprojects_issues: Display subprojects issues on main projects by default +setting_enabled_scm: Активирај SCM +setting_mail_handler_api_enabled: Enable WS for incoming emails +setting_mail_handler_api_key: API клуч +setting_sequential_project_identifiers: Генерирај последователни идентификатори на проекти +setting_gravatar_enabled: Кориси Gravatar кориснички икони +setting_diff_max_lines_displayed: Макс. број на прикажани diff линии + +permission_edit_project: Уреди проект +permission_select_project_modules: Избери модули за проектот +permission_manage_members: Manage members +permission_manage_versions: Manage versions +permission_manage_categories: Manage issue categories +permission_add_issues: Додади задачи +permission_edit_issues: Уреди задачи +permission_manage_issue_relations: Manage issue relations +permission_add_issue_notes: Додади белешки +permission_edit_issue_notes: Уреди белешки +permission_edit_own_issue_notes: Уреди лични белешки +permission_move_issues: Премести задачи +permission_delete_issues: Избриши задачи +permission_manage_public_queries: Manage public queries +permission_save_queries: Save queries +permission_view_gantt: View gantt chart +permission_view_calendar: Прикажи календар +permission_view_issue_watchers: Прикажи листа на монитори +permission_add_issue_watchers: Додади монитори +permission_log_time: Бележи потрошено време +permission_view_time_entries: Прикажи потрошено време +permission_edit_time_entries: Edit time logs +permission_edit_own_time_entries: Edit own time logs +permission_manage_news: Уредувај новости +permission_comment_news: Коментирај новости +permission_manage_documents: Уредувај документи +permission_view_documents: Прегледувај документи +permission_manage_files: Уредувај датотеки +permission_view_files: Прегледувај датотеки +permission_manage_wiki: Уредувај вики +permission_rename_wiki_pages: Преименувај вики страни +permission_delete_wiki_pages: Бриши вики страни +permission_view_wiki_pages: Прегледувај вики +permission_view_wiki_edits: Прегледувај вики историја +permission_edit_wiki_pages: Уредувај вики страни +permission_delete_wiki_pages_attachments: Бриши прилози +permission_protect_wiki_pages: Protect wiki pages +permission_manage_repository: Manage repository +permission_browse_repository: Browse repository +permission_view_changesets: View changesets +permission_commit_access: Commit access +permission_manage_boards: Уредувај форуми +permission_view_messages: Прегледувај пораки +permission_add_messages: Праќај пораки +permission_edit_messages: Уредувај пораки +permission_edit_own_messages: Уредувај сопствени пораки +permission_delete_messages: Бриши пораки +permission_delete_own_messages: Бриши сопствени пораки + +project_module_issue_tracking: Следење на задачи +project_module_time_tracking: Следење на време +project_module_news: Новости +project_module_documents: Документи +project_module_files: Датотеки +project_module_wiki: Вики +project_module_repository: 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: Tracker +label_tracker_plural: Trackers +label_tracker_new: New tracker +label_workflow: Workflow +label_issue_status: Статус на задачата +label_issue_status_plural: Статуси на задача +label_issue_status_new: Нов статус +label_issue_category: Категорија на задача +label_issue_category_plural: Категории на задача +label_issue_category_new: Нова категорија +label_custom_field: Custom field +label_custom_field_plural: Custom fields +label_custom_field_new: New custom field +label_enumerations: 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_overall_activity: Севкупна активност +label_user_activity: "Активност на %s" +label_new: Нов +label_logged_as: Најавен како +label_environment: Environment +label_authentication: Автентикација +label_auth_source: Режим на автентикација +label_auth_source_new: Нов ежим на автентикација +label_auth_source_plural: Режими на автентикација +label_subproject_plural: Подпроекти +label_and_its_subprojects: %s и неговите подпроекти +label_min_max_length: Мин. - Макс. должина +label_list: Листа +label_date: Датум +label_integer: Цел број +label_float: Децимален +label_boolean: 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: последни %d промени +label_change_view_all: Прегледај ги сите промени +label_personalize_page: Прилагоди ја оваа страна +label_comment: Коментар +label_comment_plural: Коментари +label_comment_add: Додади коментар +label_comment_added: Коментарот е додаден +label_comment_delete: Избриши ги коментарите +label_query: Custom query +label_query_plural: Custom queries +label_query_new: New query +label_filter_add: Додади филтер +label_filter_plural: Филтри +label_equals: е +label_not_equals: не е +label_in_less_than: е помалку од +label_in_more_than: е повеќе од +label_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: Date range +label_less_than_ago: пред помалку од дена +label_more_than_ago: пред повеќе од дена +label_ago: пред дена +label_contains: содржи +label_not_contains: не содржи +label_day_plural: дена +label_repository: Repository +label_repository_plural: Repositories +label_browse: Browse +label_modification: %d промена +label_modification_plural: %d промени +label_revision: Ревизија +label_revision_plural: Ревизии +label_associated_revisions: Associated revisions +label_added: додадено +label_modified: променето +label_copied: копирано +label_renamed: преименувано +label_deleted: избришано +label_latest_revision: Последна ревизија +label_latest_revision_plural: Последни ревизии +label_view_revisions: Прегледај ги ревизиите +label_max_size: Максимална големина +label_on: 'од' +label_sort_highest: Премести најгоре +label_sort_higher: Премести погоре +label_sort_lower: Премести подоле +label_sort_lowest: Премести најдоле +label_roadmap: Планирани верзии +label_roadmap_due_in: За %s +label_roadmap_overdue: %s покасно +label_roadmap_no_issues: Нема задачи за оваа верзија +label_search: Пребарувај +label_result_plural: Резултати +label_all_words: Сите зборови +label_wiki: Вики +label_wiki_edit: Уредување на вики +label_wiki_edit_plural: Уредувања на вики +label_wiki_page: Вики страница +label_wiki_page_plural: Вики страници +label_index_by_title: Index by title +label_index_by_date: 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 per month +label_commits_per_author: Commits per author +label_view_diff: Прегледај ги разликите +label_diff_inline: inline +label_diff_side_by_side: side by side +label_options: Опции +label_copy_workflow_from: Copy workflow from +label_permissions_report: Извештај со овластувања +label_watched_issues: Следени задачи +label_related_issues: Поврзани задачи +label_applied_status: Applied status +label_loading: Вчитување... +label_relation_new: New relation +label_relation_delete: Delete relation +label_relates_to: related to +label_duplicates: дупликати +label_duplicated_by: duplicated by +label_blocks: blocks +label_blocked_by: blocked by +label_precedes: предходи +label_follows: следи +label_end_to_start: end to start +label_end_to_end: end to end +label_start_to_start: start to start +label_start_to_end: start to end +label_stay_logged_in: Остани најавен +label_disabled: disabled +label_show_completed_versions: Покажи ги завршените верзии +label_me: јас +label_board: Форум +label_board_new: Нов форум +label_board_plural: Форуми +label_topic_plural: Topics +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 клучот е креиран пред %s +label_module_plural: Модули +label_added_time_by: Додадено од %s пред %s +label_updated_time_by: Ажурирано од %s пред %s +label_updated_time: Ажурирано пред %s +label_jump_to_a_project: Промени проект... +label_file_plural: Датотеки +label_changeset_plural: Changesets +label_default_columns: Основни колони +label_no_change_option: (Без промена) +label_bulk_edit_selected_issues: Групно уредување на избраните задачи +label_theme: Тема +label_default: Основна +label_search_titles_only: Пребарувај ги само насловите +label_user_mail_option_all: "За секој настан во сите мои проекти" +label_user_mail_option_selected: "За секој настан само во избраните проекти..." +label_user_mail_option_none: "Само за работите кои ги следам или сум дел од" +label_user_mail_no_self_notified: "Несакам да сум известуван за промените што јас ги правам" +label_registration_activation_by_email: account activation by email +label_registration_manual_activation: manual account activation +label_registration_automatic_activation: automatic account activation +label_display_per_page: 'По страна: %s' +label_age: Age +label_change_properties: Промени својства +label_general: Општо +label_more: Повеќе +label_scm: SCM +label_plugins: Додатоци +label_ldap_authentication: LDAP автентикација +label_downloads_abbr: Преземања +label_optional_description: Дополнителен опис +label_add_another_file: Додадете друга датотека +label_preferences: Параметри +label_chronological_order: In chronological order +label_reverse_chronological_order: In reverse chronological order +label_planning: Планирање +label_incoming_emails: Incoming emails +label_generate_key: Генерирај клуч +label_issue_watchers: Монитори +label_example: Пример + +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: Back +button_cancel: Откажи +button_activate: Активирај +button_sort: Сортирај +button_log_time: Бележи време +button_rollback: Врати се на оваа верзија +button_watch: Следи +button_unwatch: Не следи +button_reply: Одговори +button_archive: Архивирај +button_unarchive: Unarchive +button_reset: Reset +button_rename: Преименувај +button_change_password: Промени лозинка +button_copy: Копирај +button_annotate: Annotate +button_update: Ажурирај +button_configure: Конфигурирај +button_quote: Цитирај + +status_active: активен +status_registered: регистриран +status_locked: заклучен + +text_select_mail_notifications: Select actions for which email notifications should be sent. +text_regexp_info: eg. ^[A-Z0-9]+$ +text_min_max_length_info: 0 значи без ограничување +text_project_destroy_confirmation: Дали сте сигурни дека сакате да го избришете овој проект и целата негова содржина ? +text_subprojects_destroy_warning: 'Подпроектите: %s ќе бидат исто така избришани.' +text_workflow_edit: Select a role and a tracker to edit the workflow +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), бројките и dashes се дозволени.
    По зачувувањето, идентификаторот неможе да се менува.' +text_caracters_maximum: Максимум %d знаци. +text_caracters_minimum: Мора да е најмалку %d знаци долгa. +text_length_between: Должина меѓу %d и %d знаци. +text_tracker_no_workflow: No workflow defined for this tracker +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: Дали сте сигурни дека сакате да ја избришете оваа вики и целата нејзина содржина ? +text_issue_category_destroy_question: Некои задачи (%d) се доделени во оваа категорија. Што сакате да направите ? +text_issue_category_destroy_assignments: Remove category assignments +text_issue_category_reassign_to: Reassign issues to this category +text_user_mail_option: "For unselected projects, you will only receive notifications about things you watch or you're involved in (eg. issues you're the author or assignee)." +text_no_configuration_data: "Финкции, trackers, статус на задачи and workflow сеуште не се конфигурирани.\nПрепорачано е вчитување на основната конфигурација. По вчитувањето може да се промени." +text_load_default_configuration: Вчитај ја основната конфигурација +text_status_changed_by_changeset: Applied in changeset %s. +text_issues_destroy_confirmation: 'Дали сте сигурни дека сакате да ги избришете избраните задачи ?' +text_select_project_modules: 'Избери кои модули да бидат активни за овој проект:' +text_default_administrator_account_changed: Основниот администраторски профил е сменет +text_file_repository_writable: File repository writable +text_rmagick_available: RMagick инсталиран (optional) +text_destroy_time_entries_question: %.02f часа се пријавени за задачите што сакате да ги избришете. Што сакате да направите ? +text_destroy_time_entries: Избриши ги пријавените часови +text_assign_time_entries_to_project: Assign reported hours to the project +text_reassign_time_entries: 'Reassign reported hours to this issue:' +text_user_wrote: '%s напиша:' +text_enumeration_destroy_question: '%d objects are assigned to this value.' +text_enumeration_category_reassign_to: 'Reassign them to this value:' +text_email_delivery_not_configured: "Email delivery is not configured, and notifications are disabled.\nКонфигурирајте го Вашиот SMTP сервер во config/email.yml и рестартирај те ја апликацијата to enable them." +text_repository_usernames_mapping: "Select or update the Redmine user mapped to each username found in the repository log.\nUsers with the same Redmine and repository username or email are automatically mapped." +text_diff_truncated: '... This diff was truncated because it exceeds the maximum size that can be displayed.' + +default_role_manager: Менаџер +default_role_developper: Програмер +default_role_reporter: Reporter +default_tracker_bug: Грешка +default_tracker_feature: Функционалност +default_tracker_support: Поддршка +default_issue_status_new: New +default_issue_status_assigned: Доделена +default_issue_status_resolved: Решена +default_issue_status_feedback: Feedback +default_issue_status_closed: Затворена +default_issue_status_rejected: Одбиена +default_doc_category_user: Корисничка документација +default_doc_category_tech: Техничка документација +default_priority_low: Низок +default_priority_normal: Нормален +default_priority_high: Висок +default_priority_urgent: Итен +default_priority_immediate: Многу итен +default_activity_design: Дизајн +default_activity_development: Развој + +enumeration_issue_priorities: Приоритети на задача +enumeration_doc_categories: Категории на документ +enumeration_activities: Типови на активност (следење на време) +setting_repository_log_display_limit: Maximum number of revisions displayed on file log +warning_attachments_not_saved: "%d file(s) could not be saved." +field_editable: Editable +text_plugin_assets_writable: Plugin assets directory writable +label_display: Display +button_create_and_continue: Create and continue +text_custom_field_possible_values_info: 'One line for each value' +field_identity_url: OpenID URL +setting_openid: Allow OpenID login and registration +label_login_with_open_id_option: or login with OpenID +field_watcher: Watcher diff --git a/lang/nl.yml b/lang/nl.yml index 18954534a..859972ee0 100644 --- a/lang/nl.yml +++ b/lang/nl.yml @@ -1,5 +1,4 @@ _gloc_rule_default: '|n| n==1 ? "" : "_plural" ' - actionview_datehelper_select_day_prefix: actionview_datehelper_select_month_names: Januari,Februari,Maart,April,Mei,Juni,Juli,Augustus,September,Oktober,November,December actionview_datehelper_select_month_names_abbr: Jan,Feb,Maa,Apr,Mei,Jun,Jul,Aug,Sep,Okt,Nov,Dec @@ -18,630 +17,678 @@ actionview_datehelper_time_in_words_minute_single: 1 minuut actionview_datehelper_time_in_words_second_less_than: minder dan een seconde actionview_datehelper_time_in_words_second_less_than_plural: minder dan %d seconden actionview_instancetag_blank_option: Selecteer - -activerecord_error_inclusion: staat niet in de lijst -activerecord_error_exclusion: is gereserveerd -activerecord_error_invalid: is ongeldig -activerecord_error_confirmation: komt niet overeen met confirmatie activerecord_error_accepted: moet geaccepteerd worden -activerecord_error_empty: mag niet leeg zijn activerecord_error_blank: mag niet blanco zijn -activerecord_error_too_long: is te lang -activerecord_error_too_short: is te kort -activerecord_error_wrong_length: heeft de verkeerde lengte -activerecord_error_taken: is al in gebruik -activerecord_error_not_a_number: is geen getal +activerecord_error_circular_dependency: Deze relatie zou een circulaire afhankelijkheid tot gevolg hebben +activerecord_error_confirmation: komt niet overeen met bevestiging +activerecord_error_empty: mag niet leeg zijn +activerecord_error_exclusion: is gereserveerd +activerecord_error_greater_than_start_date: moet na de startdatum liggen +activerecord_error_inclusion: staat niet in de lijst +activerecord_error_invalid: is ongeldig activerecord_error_not_a_date: is geen valide datum -activerecord_error_greater_than_start_date: moet hoger zijn dan startdatum +activerecord_error_not_a_number: is geen getal activerecord_error_not_same_project: hoort niet bij hetzelfde project -activerecord_error_circular_dependency: Deze relatie zou een circulaire afhankelijkheid tot gevolg hebben - -general_fmt_age: %d jr -general_fmt_age_plural: %d jr -general_fmt_date: %%m/%%d/%%Y -general_fmt_datetime: %%m/%%d/%%Y %%I:%%M %%p -general_fmt_datetime_short: %%b %%d, %%I:%%M %%p -general_fmt_time: %%I:%%M %%p -general_text_No: 'Nee' -general_text_Yes: 'Ja' -general_text_no: 'nee' -general_text_yes: 'ja' -general_lang_name: 'Nederlands' -general_csv_separator: ',' -general_csv_decimal_separator: '.' -general_csv_encoding: ISO-8859-1 -general_pdf_encoding: ISO-8859-1 -general_day_names: Maandag, Dinsdag, Woensdag, Donderdag, Vrijdag, Zaterdag, Zondag -general_first_day_of_week: '7' - -notice_account_updated: Account is met succes gewijzigd -notice_account_invalid_creditentials: Incorrecte gebruikersnaam of wachtwoord -notice_account_password_updated: Wachtwoord is met succes gewijzigd -notice_account_wrong_password: Incorrect wachtwoord -notice_account_register_done: Account is met succes aangemaakt. -notice_account_unknown_email: Onbekende gebruiker. -notice_can_t_change_password: Dit account gebruikt een externe bron voor authenticatie. Het is niet mogelijk om het wachtwoord te veranderen. -notice_account_lost_email_sent: Er is een email naar U verstuurd met instructies over het kiezen van een nieuw wachtwoord. -notice_account_activated: Uw account is geactiveerd. U kunt nu inloggen. -notice_successful_create: Maken succesvol. -notice_successful_update: Wijzigen succesvol. -notice_successful_delete: Verwijderen succesvol. -notice_successful_connection: Verbinding succesvol. -notice_file_not_found: De pagina die U probeerde te benaderen bestaat niet of is verwijderd. -notice_locking_conflict: De gegevens zijn gewijzigd door een andere gebruiker. -notice_not_authorized: Het is U niet toegestaan om deze pagina te raadplegen. -notice_email_sent: Een e-mail werd verstuurd naar %s -notice_email_error: Er is een fout opgetreden tijdens het versturen van (%s) -notice_feeds_access_key_reseted: Je RSS toegangssleutel werd gereset. - +activerecord_error_taken: is al in gebruik +activerecord_error_too_long: is te lang +activerecord_error_too_short: is te kort +activerecord_error_wrong_length: heeft een onjuiste lengte +button_activate: Activeer +button_add: Voeg toe +button_annotate: Annoteer +button_apply: Pas toe +button_archive: Archiveer +button_back: Terug +button_cancel: Annuleer +button_change: Wijzig +button_change_password: Wijzig wachtwoord +button_check_all: Selecteer alle +button_clear: Leeg maken +button_configure: Configureer +button_copy: Kopiëer +button_create: Maak +button_delete: Verwijder +button_download: Download +button_edit: Bewerk +button_list: Lijst +button_lock: Sluit +button_log_time: Log tijd +button_login: Inloggen +button_move: Verplaatsen +button_quote: Citaat +button_rename: Hernoemen +button_reply: Antwoord +button_reset: Reset +button_rollback: Rollback naar deze versie +button_save: Bewaren +button_sort: Sorteer +button_submit: Toevoegen +button_test: Test +button_unarchive: Dearchiveer +button_uncheck_all: Deselecteer alle +button_unlock: Open +button_unwatch: Niet meer monitoren +button_update: Update +button_view: Bekijken +button_watch: Monitor +default_activity_design: Ontwerp +default_activity_development: Ontwikkeling +default_doc_category_tech: Technische documentatie +default_doc_category_user: Gebruikersdocumentatie +default_issue_status_assigned: Toegewezen +default_issue_status_closed: Gesloten +default_issue_status_feedback: Terugkoppeling +default_issue_status_new: Nieuw +default_issue_status_rejected: Afgewezen +default_issue_status_resolved: Opgelost +default_priority_high: Hoog +default_priority_immediate: Onmiddellijk +default_priority_low: Laag +default_priority_normal: Normaal +default_priority_urgent: Spoed +default_role_developper: Ontwikkelaar +default_role_manager: Manager +default_role_reporter: Rapporteur +default_tracker_bug: Bug +default_tracker_feature: Feature +default_tracker_support: Support +enumeration_activities: Activiteiten (tijdtracking) +enumeration_doc_categories: Documentcategorieën +enumeration_issue_priorities: Issueprioriteiten +error_can_t_load_default_data: "De standaard configuratie kon niet worden geladen: %s" +error_issue_not_found_in_project: 'Deze issue is niet gevonden of behoort niet toe tot dit project.' +error_scm_annotate: "Er kan geen commentaar toegevoegd worden." +error_scm_command_failed: "Er trad een fout op tijdens de poging om verbinding te maken met de repository: %s" error_scm_not_found: "Deze ingang of revisie bestaat niet in de repository." -error_scm_command_failed: "Een fout trad op tijdens de poging om verbinding te maken met de repository: %s" - -mail_subject_lost_password: Uw %s wachtwoord -mail_body_lost_password: 'Gebruik de volgende link om Uw wachtwoord te wijzigen:' -mail_subject_register: Uw %s account activatie -mail_body_register: 'Gebruik de volgende link om Uw account te activeren:' - -gui_validation_error: 1 fout -gui_validation_error_plural: %d fouten - -field_name: Naam -field_description: Beschrijving -field_summary: Samenvatting -field_is_required: Verplicht -field_firstname: Voornaam -field_lastname: Achternaam -field_mail: Email -field_filename: Bestand -field_filesize: Grootte -field_downloads: Downloads +field_account: Account +field_activity: Activiteit +field_admin: Beheerder +field_assignable: Issues kunnen toegewezen worden aan deze rol +field_assigned_to: Toegewezen aan +field_attr_firstname: Voornaam attribuut +field_attr_lastname: Achternaam attribuut +field_attr_login: Login attribuut +field_attr_mail: E-mail attribuut +field_auth_source: Authenticatiemethode field_author: Auteur +field_base_dn: Base DN +field_category: Categorie +field_column_names: Kolommen +field_comments: Commentaar +field_comments_sorting: Commentaar weergeven field_created_on: Aangemaakt -field_updated_on: Gewijzigd +field_default_value: Standaardwaarde +field_delay: Vertraging +field_description: Beschrijving +field_done_ratio: %% Gereed +field_downloads: Downloads +field_due_date: Verwachte datum gereed +field_effective_date: Datum +field_estimated_hours: Geschatte tijd field_field_format: Formaat -field_is_for_all: Voor alle projecten -field_possible_values: Mogelijke waarden -field_regexp: Reguliere expressie -field_min_length: Minimale lengte -field_max_length: Maximale lengte -field_value: Waarde -field_category: Categorie -field_title: Titel -field_project: Project -field_issue: Issue -field_status: Status -field_notes: Notities +field_filename: Bestand +field_filesize: Grootte +field_firstname: Voornaam +field_fixed_version: Versie +field_hide_mail: Verberg mijn e-mailadres +field_homepage: Homepage +field_host: Host +field_hours: Uren +field_identifier: Identificatiecode field_is_closed: Issue gesloten field_is_default: Standaard -field_tracker: Tracker -field_subject: Onderwerp -field_due_date: Verwachte datum gereed -field_assigned_to: Toegewezen aan -field_priority: Prioriteit -field_fixed_version: Doel versie -field_user: Gebruiker -field_role: Rol -field_homepage: Homepage -field_is_public: Publiek -field_parent: Subproject van +field_is_filter: Gebruikt als een filter +field_is_for_all: Voor alle projecten field_is_in_chlog: Issues weergegeven in wijzigingslog field_is_in_roadmap: Issues weergegeven in roadmap +field_is_public: Publiek +field_is_required: Verplicht +field_issue: Issue +field_issue_to_id: Gerelateerd issue +field_language: Taal +field_last_login_on: Laatste bezoek +field_lastname: Achternaam field_login: Inloggen +field_mail: E-mail field_mail_notification: Mail mededelingen -field_admin: Beheerder -field_last_login_on: Laatste bezoek -field_language: Taal -field_effective_date: Datum -field_password: Wachtwoord +field_max_length: Maximale lengte +field_min_length: Minimale lengte +field_name: Naam field_new_password: Nieuw wachtwoord +field_notes: Notities +field_onthefly: On-the-fly aanmaken van een gebruiker +field_parent: Subproject van +field_parent_title: Bovenliggende pagina +field_password: Wachtwoord field_password_confirmation: Bevestigen -field_version: Versie -field_type: Type -field_host: Host field_port: Port -field_account: Account -field_base_dn: Base DN -field_attr_login: Login attribuut -field_attr_firstname: Voornaam attribuut -field_attr_lastname: Achternaam attribuut -field_attr_mail: Email attribuut -field_onthefly: On-the-fly aanmaken van een gebruiker -field_start_date: Start -field_done_ratio: %% Gereed -field_auth_source: Authenticatiemethode -field_hide_mail: Verberg mijn emailadres -field_comments: Commentaar -field_url: URL +field_possible_values: Mogelijke waarden +field_priority: Prioriteit +field_project: Project +field_redirect_existing_links: Verwijs bestaande links door +field_regexp: Reguliere expressie +field_role: Rol +field_searchable: Doorzoekbaar +field_spent_on: Datum +field_start_date: Startdatum field_start_page: Startpagina +field_status: Status +field_subject: Onderwerp field_subproject: Subproject -field_hours: Uren -field_activity: Activiteit -field_spent_on: Datum -field_identifier: Identificatiecode -field_is_filter: Gebruikt als een filter -field_issue_to_id: Gerelateerd issue -field_delay: Vertraging -field_assignable: Issues kunnen toegewezen worden aan deze rol -field_redirect_existing_links: Verwijs bestaande links door -field_estimated_hours: Geschatte tijd -field_default_value: Standaard waarde - -setting_app_title: Applicatie titel -setting_app_subtitle: Applicatie ondertitel -setting_welcome_text: Welkomsttekst -setting_default_language: Standaard taal -setting_login_required: Authent. nodig -setting_self_registration: Zelf-registratie toegestaan -setting_attachment_max_size: Attachment max. grootte -setting_issues_export_limit: Limiet export issues -setting_mail_from: Afzender mail adres -setting_host_name: Host naam -setting_text_formatting: Tekst formaat -setting_wiki_compression: Wiki geschiedenis comprimeren -setting_feeds_limit: Feed inhoud limiet -setting_autofetch_changesets: Haal commits automatisch op -setting_sys_api_enabled: Gebruik WS voor repository beheer -setting_commit_ref_keywords: Referencing trefwoorden -setting_commit_fix_keywords: Fixing trefwoorden -setting_autologin: Autologin -setting_date_format: Datum formaat -setting_cross_project_issue_relations: Sta cross-project issue relaties toe - -label_user: Gebruiker -label_user_plural: Gebruikers -label_user_new: Nieuwe gebruiker -label_project: Project -label_project_new: Nieuw project -label_project_plural: Projecten -label_project_all: Alle Projecten -label_project_latest: Nieuwste projecten -label_issue: Issue -label_issue_new: Nieuw issue -label_issue_plural: Issues -label_issue_view_all: Bekijk alle issues -label_document: Document -label_document_new: Nieuw document -label_document_plural: Documenten -label_role: Rol -label_role_plural: Rollen -label_role_new: Nieuwe rol -label_role_and_permissions: Rollen en permissies -label_member: Lid -label_member_new: Nieuw lid -label_member_plural: Leden -label_tracker: Tracker -label_tracker_plural: Trackers -label_tracker_new: Nieuwe tracker -label_workflow: Workflow -label_issue_status: Issue status -label_issue_status_plural: Issue statussen -label_issue_status_new: Nieuwe status -label_issue_category: Issue categorie -label_issue_category_plural: Issue categorieën -label_issue_category_new: Nieuwe categorie -label_custom_field: Specifiek veld -label_custom_field_plural: Specifieke velden -label_custom_field_new: Nieuw specifiek veld -label_enumerations: Enumeraties -label_enumeration_new: Nieuwe waarde -label_information: Informatie -label_information_plural: Informatie -label_please_login: Inloggen a.u.b. -label_register: Registreer -label_password_lost: Wachtwoord verloren -label_home: Home -label_my_page: Mijn pagina -label_my_account: Mijn account -label_my_projects: Mijn projecten +field_summary: Samenvatting +field_time_zone: Tijdzone +field_title: Titel +field_tracker: Tracker +field_type: Type +field_updated_on: Gewijzigd +field_url: URL +field_user: Gebruiker +field_value: Waarde +field_version: Versie +general_csv_decimal_separator: '.' +general_csv_encoding: ISO-8859-1 +general_csv_separator: ',' +general_day_names: Maandag, Dinsdag, Woensdag, Donderdag, Vrijdag, Zaterdag, Zondag +general_first_day_of_week: '7' +general_fmt_age: %d jr +general_fmt_age_plural: %d jr +general_fmt_date: %%d/%%m/%%Y +general_fmt_datetime: %%d/%%m/%%Y %%H:%%M +general_fmt_datetime_short: %%d %%b, %%H:%%M +general_fmt_time: %%H:%%M +general_lang_name: 'Nederlands' +general_pdf_encoding: ISO-8859-1 +general_text_No: 'Nee' +general_text_Yes: 'Ja' +general_text_no: 'nee' +general_text_yes: 'ja' +gui_validation_error: 1 fout +gui_validation_error_plural: %d fouten +label_activity: Activiteit +label_add_another_file: Ander bestand toevoegen +label_add_note: Voeg een notitie toe +label_added: toegevoegd +label_added_time_by: Toegevoegd door %s %s geleden label_administration: Administratie -label_login: Inloggen -label_logout: Uitloggen -label_help: Help -label_reported_issues: Gemelde issues +label_age: Leeftijd +label_ago: dagen geleden +label_all: alle +label_all_time: alles +label_all_words: Alle woorden +label_and_its_subprojects: %s en zijn subprojecten. +label_applied_status: Toegekende status label_assigned_to_me_issues: Aan mij toegewezen issues -label_last_login: Laatste bezoek -label_last_updates: Laatste wijziging -label_last_updates_plural: %d laatste wijziging -label_registered_on: Geregistreerd op -label_activity: Activiteit -label_new: Nieuw -label_logged_as: Ingelogd als -label_environment: Omgeving -label_authentication: Authenticatie -label_auth_source: Authenticatie modus -label_auth_source_new: Nieuwe authenticatie modus -label_auth_source_plural: Authenticatie modi -label_subproject_plural: Subprojecten -label_min_max_length: Min - Max lengte -label_list: Lijst -label_date: Datum -label_integer: Integer -label_boolean: Boolean -label_string: Tekst -label_text: Lange tekst -label_attribute: Attribuut -label_attribute_plural: Attributen -label_download: %d Download -label_download_plural: %d Downloads -label_no_data: Geen gegevens om te tonen -label_change_status: Wijzig status -label_history: Geschiedenis +label_associated_revisions: Geassociëerde revisies label_attachment: Bestand -label_attachment_new: Nieuw bestand label_attachment_delete: Verwijder bestand +label_attachment_new: Nieuw bestand label_attachment_plural: Bestanden -label_report: Rapport -label_report_plural: Rapporten -label_news: Nieuws -label_news_new: Voeg nieuws toe -label_news_plural: Nieuws -label_news_latest: Laatste nieuws -label_news_view_all: Bekijk al het nieuws +label_attribute: Attribuut +label_attribute_plural: Attributen +label_auth_source: Authenticatiemodus +label_auth_source_new: Nieuwe authenticatiemodus +label_auth_source_plural: Authenticatiemodi +label_authentication: Authenticatie +label_blocked_by: geblokkeerd door +label_blocks: blokkeert +label_board: Forum +label_board_new: Nieuw forum +label_board_plural: Forums +label_boolean: Boolean +label_browse: Blader +label_bulk_edit_selected_issues: Bewerk geselecteerde issues in bulk +label_calendar: Kalender label_change_log: Wijzigingslog -label_settings: Instellingen -label_overview: Overzicht -label_version: Versie -label_version_new: Nieuwe versie -label_version_plural: Versies -label_confirmation: Bevestiging -label_export_to: Exporteer naar -label_read: Lees... -label_public_projects: Publieke projecten -label_open_issues: open -label_open_issues_plural: open +label_change_plural: Wijzigingen +label_change_properties: Eigenschappen wijzigen +label_change_status: Wijzig status +label_change_view_all: Bekijk alle wijzigingen +label_changes_details: Details van alle wijzigingen +label_changeset_plural: Changesets +label_chronological_order: In chronologische volgorde label_closed_issues: gesloten label_closed_issues_plural: gesloten -label_total: Totaal -label_permissions: Permissies -label_current_status: Huidige status -label_new_statuses_allowed: Nieuwe statuses toegestaan -label_all: alle -label_none: geen -label_next: Volgende -label_previous: Vorige -label_used_by: Gebruikt door -label_details: Details -label_add_note: Voeg een notitie toe -label_per_page: Per pagina -label_calendar: Kalender -label_months_from: maanden vanaf -label_gantt: Gantt -label_internal: Intern -label_last_changes: laatste %d wijzigingen -label_change_view_all: Bekijk alle wijzigingen -label_personalize_page: Personaliseer deze pagina label_comment: Commentaar -label_comment_plural: Commentaar label_comment_add: Voeg commentaar toe label_comment_added: Commentaar toegevoegd label_comment_delete: Verwijder commentaar -label_query: Eigen zoekvraag -label_query_plural: Eigen zoekvragen -label_query_new: Nieuwe zoekvraag -label_filter_add: Voeg filter toe -label_filter_plural: Filters -label_equals: is gelijk -label_not_equals: is niet gelijk -label_in_less_than: in minder dan -label_in_more_than: in meer dan -label_in: in -label_today: vandaag -label_this_week: deze week -label_less_than_ago: minder dan dagen geleden -label_more_than_ago: meer dan dagen geleden -label_ago: dagen geleden +label_comment_plural: Commentaar +label_commits_per_author: Commits per auteur +label_commits_per_month: Commits per maand +label_confirmation: Bevestiging label_contains: bevat -label_not_contains: bevat niet +label_copied: gekopieerd +label_copy_workflow_from: Kopieer workflow van +label_current_status: Huidige status +label_current_version: Huidige versie +label_custom_field: Specifiek veld +label_custom_field_new: Nieuw specifiek veld +label_custom_field_plural: Specifieke velden +label_date: Datum +label_date_from: Van +label_date_range: Datumbereik +label_date_to: Tot label_day_plural: dagen -label_repository: Repository -label_browse: Blader -label_modification: %d wijziging -label_modification_plural: %d wijzigingen -label_revision: Revisie -label_revision_plural: Revisies -label_added: toegevoegd -label_modified: gewijzigd +label_default: Standaard +label_default_columns: Standaard kolommen. label_deleted: verwijderd -label_latest_revision: Meest recente revisie -label_latest_revision_plural: Meest recente revisies -label_view_revisions: Bekijk revisies -label_max_size: Maximum grootte -label_on: 'van' -label_sort_highest: Verplaats naar begin -label_sort_higher: Verplaats naar boven -label_sort_lower: Verplaats naar beneden -label_sort_lowest: Verplaats naar eind -label_roadmap: Roadmap -label_roadmap_due_in: Voldaan in %s -label_roadmap_overdue: %s overtijd -label_roadmap_no_issues: Geen issues voor deze versie -label_search: Zoeken -label_result_plural: Resultaten -label_all_words: Alle woorden -label_wiki: Wiki -label_wiki_edit: Wiki edit -label_wiki_edit_plural: Wiki edits -label_wiki_page: Wiki page -label_wiki_page_plural: Wiki pages -label_index_by_title: Index by title -label_index_by_date: Index by date -label_current_version: Huidige versie -label_preview: Testweergave -label_feed_plural: Feeds -label_changes_details: Details van alle wijzigingen -label_issue_tracking: Issue tracking -label_spent_time: Gespendeerde tijd -label_f_hour: %.2f uur -label_f_hour_plural: %.2f uren -label_time_tracking: Tijd tracking -label_change_plural: Wijzigingen -label_statistics: Statistieken -label_commits_per_month: Commits per maand -label_commits_per_author: Commits per auteur -label_view_diff: Bekijk verschillen +label_details: Details label_diff_inline: inline label_diff_side_by_side: naast elkaar -label_options: Opties -label_copy_workflow_from: Kopieer workflow van -label_permissions_report: Permissies rapport -label_watched_issues: Gemonitorde issues -label_related_issues: Gerelateerde issues -label_applied_status: Toegekende status -label_loading: Laden... -label_relation_new: Nieuwe relatie -label_relation_delete: Verwijder relatie -label_relates_to: gerelateerd aan +label_disabled: uitgeschakeld +label_display_per_page: 'Per pagina: %s' +label_document: Document +label_document_added: Document toegevoegd +label_document_new: Nieuw document +label_document_plural: Documenten +label_download: %d Download +label_download_plural: %d Downloads +label_downloads_abbr: D/L +label_duplicated_by: gedupliceerd door label_duplicates: dupliceert -label_blocks: blokkeert -label_blocked_by: geblokkeerd door -label_precedes: gaat vooraf aan -label_follows: volgt op -label_end_to_start: eind tot start label_end_to_end: eind tot eind -label_start_to_start: start tot start -label_start_to_end: start tot eind -label_stay_logged_in: Blijf ingelogd -label_disabled: uitgeschakeld -label_show_completed_versions: Toon afgeronde versies -label_me: ik -label_board: Forum -label_board_new: Nieuw forum -label_board_plural: Forums -label_topic_plural: Onderwerpen -label_message_plural: Berichten -label_message_last: Laatste bericht -label_message_new: Nieuw bericht -label_reply_plural: Antwoorden -label_send_information: Stuur account informatie naar de gebruiker -label_year: Jaar -label_month: Maand -label_week: Week -label_date_from: Van -label_date_to: Tot -label_language_based: Taal gebaseerd -label_sort_by: Sorteer op %s -label_send_test_email: Stuur een test e-mail +label_end_to_start: eind tot start +label_enumeration_new: Nieuwe waarde +label_enumerations: Enumeraties +label_environment: Omgeving +label_equals: is gelijk +label_example: Voorbeeld +label_export_to: Exporteer naar +label_f_hour: %.2f uur +label_f_hour_plural: %.2f uren +label_feed_plural: Feeds label_feeds_access_key_created_on: RSS toegangssleutel %s geleden gemaakt. -label_module_plural: Modules -label_added_time_by: Toegevoegd door %s %s geleden -label_updated_time: Upgedated %s geleden -label_jump_to_a_project: Spring naar een project... - -button_login: Inloggen -button_submit: Toevoegen -button_save: Bewaren -button_check_all: Selecteer alle -button_uncheck_all: Deselecteer alle -button_delete: Verwijder -button_create: Maak -button_test: Test -button_edit: Bewerk -button_add: Voeg toe -button_change: Wijzig -button_apply: Pas toe -button_clear: Leeg maken -button_lock: Sluit -button_unlock: Open -button_download: Download -button_list: Lijst -button_view: Bekijken -button_move: Verplaatsen -button_back: Terug -button_cancel: Annuleer -button_activate: Activeer -button_sort: Sorteer -button_log_time: Log tijd -button_rollback: Rollback naar deze versie -button_watch: Monitor -button_unwatch: Niet meer monitoren -button_reply: Antwoord -button_archive: Archiveer -button_unarchive: Desarchiveer -button_reset: Reset -button_rename: Hernoemen - -status_active: Actief -status_registered: geregistreerd -status_locked: gelockt - -text_select_mail_notifications: Selecteer acties waarvoor mededelingen via mail moeten worden verstuurd. -text_regexp_info: bv. ^[A-Z0-9]+$ -text_min_max_length_info: 0 betekent geen restrictie -text_project_destroy_confirmation: Weet U zeker dat U dit project en alle gerelateerde gegevens wilt verwijderen ? -text_workflow_edit: Selecteer een rol en een tracker om de workflow te wijzigen -text_are_you_sure: Weet U het zeker ? -text_journal_changed: gewijzigd van %s naar %s -text_journal_set_to: ingesteld op %s -text_journal_deleted: verwijderd -text_tip_task_begin_day: taak die op deze dag begint -text_tip_task_end_day: taak die op deze dag eindigt -text_tip_task_begin_end_day: taak die op deze dag begint en eindigt -text_project_identifier_info: 'kleine letters (a-z), cijfers en liggende streepjes toegestaan.
    Eenmaal bewaard kan de identificatiecode niet meer worden gewijzigd.' -text_caracters_maximum: %d van maximum aantal tekens. -text_length_between: Lengte tussen %d en %d tekens. -text_tracker_no_workflow: Geen workflow gedefinieerd voor deze tracker -text_unallowed_characters: Niet toegestane tekens -text_coma_separated: Meerdere waarden toegestaan (door komma's gescheiden). -text_issues_ref_in_commit_messages: Opzoeken en aanpassen van issues in commit berichten -text_issue_added: Issue %s is gerapporteerd (by %s). -text_issue_updated: Issue %s is gewijzigd (by %s). -text_wiki_destroy_confirmation: Bent u zeker dat u deze wiki en zijn inhoud wenst te verwijderen? -text_issue_category_destroy_question: Sommige issues (%d) zijn aan deze categorie toegewezen. Wat wilt u hiermee doen ? -text_issue_category_destroy_assignments: Verwijder categorie toewijzigingen -text_issue_category_reassign_to: Issues opnieuw toewijzen aan deze categorie - -default_role_manager: Manager -default_role_developper: Ontwikkelaar -default_role_reporter: Rapporteur -default_tracker_bug: Bug -default_tracker_feature: Feature -default_tracker_support: Support -default_issue_status_new: Nieuw -default_issue_status_assigned: Toegewezen -default_issue_status_resolved: Opgelost -default_issue_status_feedback: Terugkoppeling -default_issue_status_closed: Gesloten -default_issue_status_rejected: Afgewezen -default_doc_category_user: Gebruikersdocumentatie -default_doc_category_tech: Technische documentatie -default_priority_low: Laag -default_priority_normal: Normaal -default_priority_high: Hoog -default_priority_urgent: Spoed -default_priority_immediate: Onmiddellijk -default_activity_design: Design -default_activity_development: Development - -enumeration_issue_priorities: Issue prioriteiten -enumeration_doc_categories: Document categorieën -enumeration_activities: Activiteiten (tijd tracking) -text_comma_separated: Meerdere waarden toegestaan (kommagescheiden). +label_file_added: Bericht toegevoegd label_file_plural: Bestanden -label_changeset_plural: Changesets -field_column_names: Kolommen -label_default_columns: Standaard kolommen. -setting_issue_list_default_columns: Standaard kolommen getoond om de lijst met issues -setting_repositories_encodings: Repositories encodings -notice_no_issue_selected: "Er is geen issue geselecteerd. Selecteer de issue die u wilt bewerken." -label_bulk_edit_selected_issues: Bewerk geselecteerde issues in bulk -label_no_change_option: (Geen wijziging) -notice_failed_to_save_issues: "Gefaald om %d issue(s) (%d geselecteerd) te bewaren: %s." - -label_theme: Thema -label_default: Standaard -label_search_titles_only: Enkel titels doorzoeken -label_nobody: nobody -button_change_password: Wijzig wachtwoord -text_user_mail_option: "For unselected projects, you will only receive notifications about things you watch or you're involved in (eg. issues you're the author or assignee)." -text_user_mail_option: "Bij niet-geselecteerde projecten zult u enkel notificaties ontvangen voor issues die u monitort of waar je bij betrokken bent (auteur of toegewezen persoon)." -label_user_mail_option_selected: "Enkel bij elke event op het geselecteerde project..." -label_user_mail_option_all: "Bij elk event in al mijn projecten..." -label_user_mail_option_none: "Alleen in de dingen die ik monitor of in betrokken ben" -setting_emails_footer: Emails footer +label_filter_add: Voeg filter toe +label_filter_plural: Filters label_float: Float -button_copy: Kopieer -mail_body_account_information_external: Je kan je account (%s) gebruiken om in te loggen. -mail_body_account_information: Je account gegevens -setting_protocol: Protocol -label_user_mail_no_self_notified: "Ik wil niet verwittigd worden van wijzigingen die ik zelf maak." -setting_time_format: Tijd formaat -label_registration_activation_by_email: account activatie per email -mail_subject_account_activation_request: %s account activatie verzoek -mail_body_account_activation_request: 'Een nieuwe gebruiker (%s) is geregistreerd. Zijn account wacht op uw akkoord:' -label_registration_automatic_activation: automatische account activatie -label_registration_manual_activation: manuele account activatie -notice_account_pending: "Je account is aangemaakt maar wacht nog op goedkeuring van de beheerder." -field_time_zone: Tijd zone -text_caracters_minimum: Moet minstens %d karakters lang zijn. -setting_bcc_recipients: Blind carbon copy ontvangers (bcc) -button_annotate: Annotate -label_issues_by: Issues door %s -field_searchable: Doorzoekbaar -label_display_per_page: 'Per pagina: %s' -setting_per_page_options: Objects per pagina opties -label_age: Leeftijd -notice_default_data_loaded: Standaard configuratie succesvol geladen. -text_load_default_configuration: Laad de standaardconfiguratie -text_no_configuration_data: "Rollen, trackers, issue statuses en workflow zijn nog niet geconfigureerd.\nHet is ten zeerste aangeraden om de standaardconfiguratie in te laden. Je kan deze aanpassen nadat deze is ingeladen." -error_can_t_load_default_data: "Standaard configuratie kon niet worden geladen: %s" -button_update: Update -label_change_properties: Eigenschappen wijzigen +label_follows: volgt op +label_gantt: Gantt label_general: Algemeen -label_repository_plural: Repositories -label_associated_revisions: Geassocieerde revisies -setting_user_format: Gebruikers weergave formaat -text_status_changed_by_changeset: Toegepast in changeset %s. -label_more: Meer -text_issues_destroy_confirmation: 'Ben je zeker dat je deze issue(s) wenst te verwijderen?' -label_scm: SCM -text_select_project_modules: 'Selecteer de modules die je wenst te gebruiken voor dit project:' +label_generate_key: Genereer een sleutel +label_help: Help +label_history: Geschiedenis +label_home: Home +label_in: in +label_in_less_than: in minder dan +label_in_more_than: in meer dan +label_incoming_emails: Inkomende e-mail +label_index_by_date: Indexeer op datum +label_index_by_title: Indexeer op titel +label_information: Informatie +label_information_plural: Informatie +label_integer: Integer +label_internal: Intern +label_issue: Issue label_issue_added: Issue toegevoegd -label_issue_updated: Issue geupdated -label_document_added: Document toegevoegd +label_issue_category: Issuecategorie +label_issue_category_new: Nieuwe categorie +label_issue_category_plural: Issuecategorieën +label_issue_new: Nieuw issue +label_issue_plural: Issues +label_issue_status: Issuestatus +label_issue_status_new: Nieuwe status +label_issue_status_plural: Issue statussen +label_issue_tracking: Issue-tracking +label_issue_updated: Issue bijgewerkt +label_issue_view_all: Bekijk alle issues +label_issue_watchers: Monitoren +label_issues_by: Issues door %s +label_jump_to_a_project: Ga naar een project... +label_language_based: Taal gebaseerd +label_last_changes: laatste %d wijzigingen +label_last_login: Laatste bezoek +label_last_month: laatste maand +label_last_n_days: %d dagen geleden +label_last_updates: Laatste wijziging +label_last_updates_plural: %d laatste wijziging +label_last_week: vorige week +label_latest_revision: Meest recente revisie +label_latest_revision_plural: Meest recente revisies +label_ldap_authentication: LDAP authenticatie +label_less_than_ago: minder dan x dagen geleden +label_list: Lijst +label_loading: Laden... +label_logged_as: Ingelogd als +label_login: Inloggen +label_logout: Uitloggen +label_max_size: Maximumgrootte +label_me: mij +label_member: Lid +label_member_new: Nieuw lid +label_member_plural: Leden +label_message_last: Laatste bericht +label_message_new: Nieuw bericht +label_message_plural: Berichten label_message_posted: Bericht toegevoegd -label_file_added: Bericht toegevoegd +label_min_max_length: Min-max lengte +label_modification: %d wijziging +label_modification_plural: %d wijzigingen +label_modified: gewijzigd +label_module_plural: Modules +label_month: Maand +label_months_from: maanden vanaf +label_more: Meer +label_more_than_ago: meer dan x dagen geleden +label_my_account: Mijn account +label_my_page: Mijn pagina +label_my_projects: Mijn projecten +label_new: Nieuw +label_new_statuses_allowed: Nieuwe toegestane statussen +label_news: Nieuws label_news_added: Nieuws toegevoegd -project_module_boards: Boards -project_module_issue_tracking: Issue tracking -project_module_wiki: Wiki -project_module_files: Bestanden -project_module_documents: Documenten -project_module_repository: Repository -project_module_news: Nieuws -project_module_time_tracking: Tijd tracking -text_file_repository_writable: Bestandsrepository beschrijfbaar -text_default_administrator_account_changed: Standaard beheerderaccount gewijzigd -text_rmagick_available: RMagick beschikbaar (optioneel) -button_configure: Configureer +label_news_latest: Laatste nieuws +label_news_new: Voeg nieuws toe +label_news_plural: Nieuws +label_news_view_all: Bekijk al het nieuws +label_next: Volgende +label_no_change_option: (Geen wijziging) +label_no_data: Geen gegevens om te tonen +label_nobody: niemand +label_none: geen +label_not_contains: bevat niet +label_not_equals: is niet gelijk +label_on: 'van' +label_open_issues: open +label_open_issues_plural: open +label_optional_description: Optionele beschrijving +label_options: Opties +label_overall_activity: Activiteit +label_overview: Overzicht +label_password_lost: Wachtwoord verloren +label_per_page: Per pagina +label_permissions: Permissies +label_permissions_report: Permissierapport +label_personalize_page: Personaliseer deze pagina +label_planning: Planning +label_please_login: Log a.u.b. in label_plugins: Plugins -label_ldap_authentication: LDAP authenticatie -label_downloads_abbr: D/L +label_precedes: gaat vooraf aan +label_preferences: Voorkeuren +label_preview: Voorbeeldweergave +label_previous: Vorige +label_project: Project +label_project_all: Alle projecten +label_project_latest: Nieuwste projecten +label_project_new: Nieuw project +label_project_plural: Projecten +label_public_projects: Publieke projecten +label_query: Eigen zoekvraag +label_query_new: Nieuwe zoekvraag +label_query_plural: Eigen zoekvragen +label_read: Lees... +label_register: Registreer +label_registered_on: Geregistreerd op +label_registration_activation_by_email: accountactivatie per e-mail +label_registration_automatic_activation: automatische accountactivatie +label_registration_manual_activation: handmatige accountactivatie +label_related_issues: Gerelateerde issues +label_relates_to: gerelateerd aan +label_relation_delete: Verwijder relatie +label_relation_new: Nieuwe relatie +label_renamed: hernoemd +label_reply_plural: Antwoorden +label_report: Rapport +label_report_plural: Rapporten +label_reported_issues: Gemelde issues +label_repository: Repository +label_repository_plural: Repositories +label_result_plural: Resultaten +label_reverse_chronological_order: In omgekeerde chronologische volgorde +label_revision: Revisie +label_revision_plural: Revisies +label_roadmap: Roadmap +label_roadmap_due_in: Voldaan in %s +label_roadmap_no_issues: Geen issues voor deze versie +label_roadmap_overdue: %s over tijd +label_role: Rol +label_role_and_permissions: Rollen en permissies +label_role_new: Nieuwe rol +label_role_plural: Rollen +label_scm: SCM +label_search: Zoeken +label_search_titles_only: Enkel titels doorzoeken +label_send_information: Stuur accountinformatie naar de gebruiker +label_send_test_email: Stuur een test e-mail +label_settings: Instellingen +label_show_completed_versions: Toon afgeronde versies +label_sort_by: Sorteer op %s +label_sort_higher: Verplaats naar boven +label_sort_highest: Verplaats naar begin +label_sort_lower: Verplaats naar beneden +label_sort_lowest: Verplaats naar eind +label_spent_time: Gespendeerde tijd +label_start_to_end: start tot eind +label_start_to_start: start tot start +label_statistics: Statistieken +label_stay_logged_in: Blijf ingelogd +label_string: Tekst +label_subproject_plural: Subprojecten +label_text: Lange tekst +label_theme: Thema label_this_month: deze maand -label_last_n_days: %d dagen geleden -label_all_time: all time +label_this_week: deze week label_this_year: dit jaar -label_date_range: Datum bereik -label_last_week: vorige week +label_time_tracking: Tijdregistratie bijhouden +label_today: vandaag +label_topic_plural: Onderwerpen +label_total: Totaal +label_tracker: Tracker +label_tracker_new: Nieuwe tracker +label_tracker_plural: Trackers +label_updated_time: %s geleden bijgewerkt +label_updated_time_by: %2$s geleden bijgewerkt door %1$s +label_used_by: Gebruikt door +label_user: Gebruiker +label_user_activity: "%s's activiteit" +label_user_mail_no_self_notified: "Ik wil niet verwittigd worden van wijzigingen die ik zelf maak." +label_user_mail_option_all: "Bij elk gebeurtenis in al mijn projecten..." +label_user_mail_option_none: "Alleen in de dingen die ik monitor of in betrokken ben" +label_user_mail_option_selected: "Enkel bij elke gebeurtenis op het geselecteerde project..." +label_user_new: Nieuwe gebruiker +label_user_plural: Gebruikers +label_version: Versie +label_version_new: Nieuwe versie +label_version_plural: Versies +label_view_diff: Bekijk verschillen +label_view_revisions: Bekijk revisies +label_watched_issues: Gemonitorde issues +label_week: Week +label_wiki: Wiki +label_wiki_edit: Wiki edit +label_wiki_edit_plural: Wiki edits +label_wiki_page: Wikipagina +label_wiki_page_plural: Wikipagina's +label_workflow: Workflow +label_year: Jaar label_yesterday: gisteren -label_last_month: laatste maand -label_add_another_file: Ander bestand toevoegen -label_optional_description: Optionele beschrijving -text_destroy_time_entries_question: %.02f uren werden gerapporteerd op de issue(s) die je wou verwijderen. Wat wil je doen? -error_issue_not_found_in_project: 'Deze issue is niet gevonden of behoort niet toe tot dit project.' -text_assign_time_entries_to_project: Geraporteerde uren toevoegen aan dit project -text_destroy_time_entries: Verwijder geraporteerde uren -text_reassign_time_entries: 'Gerapporteerde uren opnieuw toewijzen:' +mail_body_account_activation_request: 'Een nieuwe gebruiker (%s) is geregistreerd. Zijn account wacht op uw akkoord:' +mail_body_account_information: Uw account gegevens +mail_body_account_information_external: U kunt uw account (%s) gebruiken om in te loggen. +mail_body_lost_password: 'Gebruik de volgende link om uw wachtwoord te wijzigen:' +mail_body_register: 'Gebruik de volgende link om uw account te activeren:' +mail_body_reminder: "%d issue(s) die aan u toegewezen zijn en voldaan moeten zijn in de komende %d dagen:" +mail_subject_account_activation_request: %s accountactivatieverzoek +mail_subject_lost_password: uw %s wachtwoord +mail_subject_register: uw %s accountactivatie +mail_subject_reminder: "%d issue(s) die voldaan moeten zijn in de komende dagen." +notice_account_activated: uw account is geactiveerd. u kunt nu inloggen. +notice_account_invalid_creditentials: Incorrecte gebruikersnaam of wachtwoord +notice_account_lost_email_sent: Er is een e-mail naar u verstuurd met instructies over het kiezen van een nieuw wachtwoord. +notice_account_password_updated: Wachtwoord is met succes gewijzigd +notice_account_pending: "Uw account is aangemaakt, maar wacht nog op goedkeuring van de beheerder." +notice_account_register_done: Account is met succes aangemaakt. +notice_account_unknown_email: Onbekende gebruiker. +notice_account_updated: Account is met succes gewijzigd +notice_account_wrong_password: Incorrect wachtwoord +notice_can_t_change_password: Dit account gebruikt een externe bron voor authenticatie. Het is niet mogelijk om het wachtwoord te veranderen. +notice_default_data_loaded: Standaard configuratie succesvol geladen. +notice_email_error: Er is een fout opgetreden tijdens het versturen van (%s) +notice_email_sent: Een e-mail werd verstuurd naar %s +notice_failed_to_save_issues: "Fout bij bewaren van %d issue(s) (%d geselecteerd): %s." +notice_feeds_access_key_reseted: Je RSS toegangssleutel werd gereset. +notice_file_not_found: De pagina die u probeerde te benaderen bestaat niet of is verwijderd. +notice_locking_conflict: De gegevens zijn gewijzigd door een andere gebruiker. +notice_no_issue_selected: "Er is geen issue geselecteerd. Selecteer de issue die u wilt bewerken." +notice_not_authorized: Het is u niet toegestaan deze pagina te raadplegen. +notice_successful_connection: Verbinding succesvol. +notice_successful_create: Succesvol aangemaakt. +notice_successful_delete: Succesvol verwijderd. +notice_successful_update: Wijzigen succesvol. +notice_unable_delete_version: Niet mogelijk om deze versie te verwijderen. +permission_add_issue_notes: Voeg notities toe +permission_add_issue_watchers: Voeg monitors toe +permission_add_issues: Voeg issues toe +permission_add_messages: Voeg berichten toe +permission_browse_repository: Repository doorbladeren +permission_comment_news: Nieuws commentaar geven +permission_commit_access: Commit toegang +permission_delete_issues: Issues verwijderen +permission_delete_messages: Berichten verwijderen +permission_delete_own_messages: Eigen berichten verwijderen +permission_delete_wiki_pages: Wiki pagina's verwijderen +permission_delete_wiki_pages_attachments: Bijlagen verwijderen +permission_edit_issue_notes: Notities bewerken +permission_edit_issues: Issues bewerken +permission_edit_messages: Berichten bewerken +permission_edit_own_issue_notes: Eigen notities bewerken +permission_edit_own_messages: Eigen berichten bewerken +permission_edit_own_time_entries: Eigen tijdlogboek bewerken +permission_edit_project: Project bewerken +permission_edit_time_entries: Tijdlogboek bewerken +permission_edit_wiki_pages: Wiki pagina's bewerken +permission_log_time: Gespendeerde tijd loggen +permission_manage_boards: Forums beheren +permission_manage_categories: Issue-categorieën beheren +permission_manage_documents: Documenten beheren +permission_manage_files: Bestanden beheren +permission_manage_issue_relations: Issuerelaties beheren +permission_manage_members: Leden beheren +permission_manage_news: Nieuws beheren +permission_manage_public_queries: Publieke queries beheren +permission_manage_repository: Repository beheren +permission_manage_versions: Versiebeheer +permission_manage_wiki: Wikibeheer +permission_move_issues: Issues verplaatsen +permission_protect_wiki_pages: Wikipagina's beschermen +permission_rename_wiki_pages: Wikipagina's hernoemen +permission_save_queries: Queries opslaan +permission_select_project_modules: Project modules selecteren +permission_view_calendar: Kalender bekijken +permission_view_changesets: Changesets bekijken +permission_view_documents: Documenten bekijken +permission_view_files: Bestanden bekijken +permission_view_gantt: Gantt grafiek bekijken +permission_view_issue_watchers: Monitorlijst bekijken +permission_view_messages: Berichten bekijken +permission_view_time_entries: Gespendeerde tijd bekijken +permission_view_wiki_edits: Wikihistorie bekijken +permission_view_wiki_pages: Wikipagina's bekijken +project_module_boards: Forums +project_module_documents: Documenten +project_module_files: Bestanden +project_module_issue_tracking: Issue tracking +project_module_news: Nieuws +project_module_repository: Repository +project_module_time_tracking: Tijd tracking +project_module_wiki: Wiki setting_activity_days_default: Aantal dagen getoond bij het tabblad "Activiteit" -label_chronological_order: In chronologische volgorde -field_comments_sorting: Commentaar weergeven -label_reverse_chronological_order: In omgekeerde chronologische volgorde -label_preferences: Voorkeuren -setting_display_subprojects_issues: Standaard issues van subproject tonen -label_overall_activity: Activiteit +setting_app_subtitle: Applicatieondertitel +setting_app_title: Applicatietitel +setting_attachment_max_size: Attachment max. grootte +setting_autofetch_changesets: Haal commits automatisch op +setting_autologin: Automatisch inloggen +setting_bcc_recipients: Blind carbon copy ontvangers (bcc) +setting_commit_fix_keywords: Gefixeerde trefwoorden +setting_commit_logs_encoding: Encodering van commit berichten +setting_commit_ref_keywords: Refererende trefwoorden +setting_cross_project_issue_relations: Sta crossproject issuerelaties toe +setting_date_format: Datumformaat +setting_default_language: Standaard taal setting_default_projects_public: Nieuwe projecten zijn standaard publiek -error_scm_annotate: "Er kan geen commentaar toegevoegd worden." -label_planning: Planning -text_subprojects_destroy_warning: 'Its subproject(s): %s will be also deleted.' -label_and_its_subprojects: %s and its subprojects -mail_body_reminder: "%d issue(s) that are assigned to you are due in the next %d days:" -mail_subject_reminder: "%d issue(s) due in the next days" -text_user_wrote: '%s wrote:' -label_duplicated_by: duplicated by -setting_enabled_scm: Enabled SCM -text_enumeration_category_reassign_to: 'Reassign them to this value:' -text_enumeration_destroy_question: '%d objects are assigned to this value.' -label_incoming_emails: Incoming emails -label_generate_key: Generate a key +setting_diff_max_lines_displayed: Max number of diff lines displayed +setting_display_subprojects_issues: Standaard issues van subproject tonen +setting_emails_footer: E-mails footer +setting_enabled_scm: SCM ingeschakeld +setting_feeds_limit: Feedinhoudlimiet +setting_gravatar_enabled: Gebruik Gravatar gebruikersiconen +setting_host_name: Hostnaam +setting_issue_list_default_columns: Standaardkolommen getoond op de lijst met issues +setting_issues_export_limit: Limiet export issues +setting_login_required: Authenticatie vereist +setting_mail_from: Afzender e-mail adres setting_mail_handler_api_enabled: Schakel WS in voor inkomende mail. setting_mail_handler_api_key: API sleutel -text_email_delivery_not_configured: "Email bezorging is niet geconfigureerd. Notificaties zijn uitgeschakeld.\nConfigureer je SMTP server in config/email.yml en herstant de applicatie om dit in te schakelen." -field_parent_title: Bovenliggende pagina -label_issue_watchers: Monitoren -setting_commit_logs_encoding: Commit messages encodering -button_quote: Citaat -setting_sequential_project_identifiers: Genereer sequentiele project identiteiten -notice_unable_delete_version: Onmogelijk om deze versie te verwijderen. -label_renamed: hernoemt -label_copied: gekopieerd -setting_repositories_cache_directory: Cache directory for repositories -field_cache: Local cache +setting_per_page_options: Objects per pagina-opties +setting_plain_text_mail: platte tekst (geen HTML) +setting_protocol: Protocol +setting_repositories_encodings: Repositories coderingen +setting_self_registration: Zelfregistratie toegestaan +setting_sequential_project_identifiers: Genereer sequentiële projectidentiteiten +setting_sys_api_enabled: Gebruik WS voor repository beheer +setting_text_formatting: Tekstformaat +setting_time_format: Tijd formaat +setting_user_format: Gebruikers weergaveformaat +setting_welcome_text: Welkomsttekst +setting_wiki_compression: Wikigeschiedenis comprimeren +status_active: actief +status_locked: gelockt +status_registered: geregistreerd +text_are_you_sure: Weet u het zeker? +text_assign_time_entries_to_project: Gerapporteerde uren toevoegen aan dit project +text_caracters_maximum: %d van maximum aantal tekens. +text_caracters_minimum: Moet minstens %d karakters lang zijn. +text_comma_separated: Meerdere waarden toegestaan (kommagescheiden). +text_default_administrator_account_changed: Standaard beheerderaccount gewijzigd +text_destroy_time_entries: Verwijder gerapporteerde uren +text_destroy_time_entries_question: %.02f uren werden gerapporteerd op de issue(s) die u wilde verwijderen. Wat wil u doen? +text_diff_truncated: '... Deze diff werd afgekort omdat het de maximale weer te geven karakters overschreed.' +text_email_delivery_not_configured: "E-mailbezorging is niet geconfigureerd. Notificaties zijn uitgeschakeld.\nConfigureer uw SMTP server in config/email.yml en herstart de applicatie om dit te activeren." +text_enumeration_category_reassign_to: 'Wijs de volgende waarde toe:' +text_enumeration_destroy_question: '%d objecten zijn toegewezen aan deze waarde.' +text_file_repository_writable: Bestandsrepository beschrijfbaar +text_issue_added: Issue %s is gerapporteerd (door %s). +text_issue_category_destroy_assignments: Verwijder toewijzingen aan deze categorie +text_issue_category_destroy_question: Er zijn issues (%d) aan deze categorie toegewezen. Wat wilt u hiermee doen ? +text_issue_category_reassign_to: Issues opnieuw toewijzen aan deze categorie +text_issue_updated: Issue %s is gewijzigd (door %s). +text_issues_destroy_confirmation: 'Weet u zeker dat u deze issue(s) wil verwijderen?' +text_issues_ref_in_commit_messages: Opzoeken en aanpassen van issues in commitberichten +text_journal_changed: gewijzigd van %s naar %s +text_journal_deleted: verwijderd +text_journal_set_to: ingesteld op %s +text_length_between: Lengte tussen %d en %d tekens. +text_load_default_configuration: Laad de standaardconfiguratie +text_min_max_length_info: 0 betekent geen restrictie +text_no_configuration_data: "Rollen, trackers, issue statussen en workflows zijn nog niet geconfigureerd.\nHet is ten zeerste aangeraden om de standaard configuratie in te laden. U kunt deze aanpassen nadat deze is ingeladen." +text_plugin_assets_writable: Plugin assets directory writable +text_project_destroy_confirmation: Weet u zeker dat u dit project en alle gerelateerde gegevens wilt verwijderen? +text_project_identifier_info: 'kleine letters (a-z), cijfers en liggende streepjes toegestaan.
    Eenmaal bewaard kan de identificatiecode niet meer worden gewijzigd.' +text_reassign_time_entries: 'Gerapporteerde uren opnieuw toewijzen:' +text_regexp_info: bv. ^[A-Z0-9]+$ +text_repository_usernames_mapping: "Koppel de Redminegebruikers aan gebruikers in de repository log.\nGebruikers met dezelfde Redmine en repository gebruikersnaam of email worden automatisch gekoppeld." +text_rmagick_available: RMagick beschikbaar (optioneel) +text_select_mail_notifications: Selecteer acties waarvoor mededelingen via mail moeten worden verstuurd. +text_select_project_modules: 'Selecteer de modules die u wilt gebruiken voor dit project:' +text_status_changed_by_changeset: Toegepast in changeset %s. +text_subprojects_destroy_warning: 'De subprojecten: %s zullen ook verwijderd worden.' +text_tip_task_begin_day: taak die op deze dag begint +text_tip_task_begin_end_day: taak die op deze dag begint en eindigt +text_tip_task_end_day: taak die op deze dag eindigt +text_tracker_no_workflow: Geen workflow gedefinieerd voor deze tracker +text_unallowed_characters: Niet toegestane tekens +text_user_mail_option: "Bij niet-geselecteerde projecten zult u enkel notificaties ontvangen voor issues die u monitort of waar u bij betrokken bent (als auteur of toegewezen persoon)." +text_user_wrote: '%s schreef:' +text_wiki_destroy_confirmation: Weet u zeker dat u deze wiki en zijn inhoud wenst te verwijderen? +text_workflow_edit: Selecteer een rol en een tracker om de workflow te wijzigen +warning_attachments_not_saved: "%d bestand(en) konden niet opgeslagen worden." +button_create_and_continue: Create and continue +text_custom_field_possible_values_info: 'One line for each value' +label_display: Display +field_editable: Editable +setting_repository_log_display_limit: Maximum number of revisions displayed on file log +field_identity_url: OpenID URL +setting_openid: Allow OpenID login and registration +label_login_with_open_id_option: or login with OpenID +field_watcher: Watcher diff --git a/lang/no.yml b/lang/no.yml index 9b3be9ae1..10bf48427 100644 --- a/lang/no.yml +++ b/lang/no.yml @@ -641,5 +641,70 @@ setting_sequential_project_identifiers: Generate sequential project identifiers notice_unable_delete_version: Unable to delete version label_renamed: renamed label_copied: copied -setting_repositories_cache_directory: Cache directory for repositories -field_cache: Local cache +setting_plain_text_mail: plain text only (no HTML) +permission_view_files: View files +permission_edit_issues: Edit issues +permission_edit_own_time_entries: Edit own time logs +permission_manage_public_queries: Manage public queries +permission_add_issues: Add issues +permission_log_time: Log spent time +permission_view_changesets: View changesets +permission_view_time_entries: View spent time +permission_manage_versions: Manage versions +permission_manage_wiki: Manage wiki +permission_manage_categories: Manage issue categories +permission_protect_wiki_pages: Protect wiki pages +permission_comment_news: Comment news +permission_delete_messages: Delete messages +permission_select_project_modules: Select project modules +permission_manage_documents: Manage documents +permission_edit_wiki_pages: Edit wiki pages +permission_add_issue_watchers: Add watchers +permission_view_gantt: View gantt chart +permission_move_issues: Move issues +permission_manage_issue_relations: Manage issue relations +permission_delete_wiki_pages: Delete wiki pages +permission_manage_boards: Manage boards +permission_delete_wiki_pages_attachments: Delete attachments +permission_view_wiki_edits: View wiki history +permission_add_messages: Post messages +permission_view_messages: View messages +permission_manage_files: Manage files +permission_edit_issue_notes: Edit notes +permission_manage_news: Manage news +permission_view_calendar: View calendrier +permission_manage_members: Manage members +permission_edit_messages: Edit messages +permission_delete_issues: Delete issues +permission_view_issue_watchers: View watchers list +permission_manage_repository: Manage repository +permission_commit_access: Commit access +permission_browse_repository: Browse repository +permission_view_documents: View documents +permission_edit_project: Edit project +permission_add_issue_notes: Add notes +permission_save_queries: Save queries +permission_view_wiki_pages: View wiki +permission_rename_wiki_pages: Rename wiki pages +permission_edit_time_entries: Edit time logs +permission_edit_own_issue_notes: Edit own notes +setting_gravatar_enabled: Use Gravatar user icons +label_example: Example +text_repository_usernames_mapping: "Select ou update the Redmine user mapped to each username found in the repository log.\nUsers with the same Redmine and repository username or email are automatically mapped." +permission_edit_own_messages: Edit own messages +permission_delete_own_messages: Delete own messages +label_user_activity: "%s's activity" +label_updated_time_by: Updated by %s %s ago +text_diff_truncated: '... This diff was truncated because it exceeds the maximum size that can be displayed.' +setting_diff_max_lines_displayed: Max number of diff lines displayed +text_plugin_assets_writable: Plugin assets directory writable +warning_attachments_not_saved: "%d file(s) could not be saved." +button_create_and_continue: Create and continue +text_custom_field_possible_values_info: 'One line for each value' +label_display: Display +field_editable: Editable +setting_repository_log_display_limit: Maximum number of revisions displayed on file log +field_identity_url: OpenID URL +setting_openid: Allow OpenID login and registration +label_login_with_open_id_option: or login with OpenID +field_watcher: Watcher diff --git a/lang/pl.yml b/lang/pl.yml index dc49dce4b..1ca3da32c 100644 --- a/lang/pl.yml +++ b/lang/pl.yml @@ -1,644 +1,728 @@ -_gloc_rule_default: '|n| n==1 ? "" : "_plural" ' - +# Keep this line in order to avoid problems with Windows Notepad UTF-8 EF-BB-BFidea... +# Best regards from Lublin@Poland :-) +# PL translation by Mariusz@Olejnik.net, +_gloc_rule_default: '|n| n10=n%10; n100=n%100; n==1 ? "" : n10>=2 && n10<=4 && (n100<10 || n100>=20) ? "_plural234" : "_plural5"' actionview_datehelper_select_day_prefix: actionview_datehelper_select_month_names: Styczeń,Luty,Marzec,Kwiecień,Maj,Czerwiec,Lipiec,Sierpień,Wrzesień,Październik,Listopad,Grudzień actionview_datehelper_select_month_names_abbr: Sty,Lut,Mar,Kwi,Maj,Cze,Lip,Sie,Wrz,Paź,Lis,Gru actionview_datehelper_select_month_prefix: actionview_datehelper_select_year_prefix: actionview_datehelper_time_in_words_day: 1 dzień +actionview_datehelper_time_in_words_day_plural234: %d dni +actionview_datehelper_time_in_words_day_plural5: %d dni actionview_datehelper_time_in_words_day_plural: %d dni actionview_datehelper_time_in_words_hour_about: około godziny +actionview_datehelper_time_in_words_hour_about_plural234: około %d godzin +actionview_datehelper_time_in_words_hour_about_plural5: około %d godzin actionview_datehelper_time_in_words_hour_about_plural: około %d godzin actionview_datehelper_time_in_words_hour_about_single: około godziny actionview_datehelper_time_in_words_minute: 1 minuta actionview_datehelper_time_in_words_minute_half: pół minuty actionview_datehelper_time_in_words_minute_less_than: mniej niż minuta +actionview_datehelper_time_in_words_minute_plural234: %d minuty +actionview_datehelper_time_in_words_minute_plural5: %d minut 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: mniej niż sekunda +actionview_datehelper_time_in_words_second_less_than_plural234: mniej niż %d sekundy +actionview_datehelper_time_in_words_second_less_than_plural5: mniej niż %d sekund actionview_datehelper_time_in_words_second_less_than_plural: mniej niż %d sekund actionview_instancetag_blank_option: Proszę wybierz - -activerecord_error_inclusion: nie jest zawarte na liście -activerecord_error_exclusion: jest zarezerwowane -activerecord_error_invalid: jest nieprawidłowe -activerecord_error_confirmation: nie pasuje do potwierdzenia activerecord_error_accepted: musi być zaakceptowane -activerecord_error_empty: nie może być puste activerecord_error_blank: nie może być czyste +activerecord_error_circular_dependency: Ta relacja może wytworzyć kołową zależność +activerecord_error_confirmation: nie pasuje do potwierdzenia +activerecord_error_empty: nie może być puste +activerecord_error_exclusion: jest zarezerwowane +activerecord_error_greater_than_start_date: musi być większe niż początkowa data +activerecord_error_inclusion: nie jest zawarte na liście +activerecord_error_invalid: jest nieprawidłowe +activerecord_error_not_a_date: nie jest prawidłową datą +activerecord_error_not_a_number: nie jest numerem +activerecord_error_not_same_project: nie należy do tego samego projektu +activerecord_error_taken: jest już wybrane activerecord_error_too_long: jest za długie activerecord_error_too_short: jest za krótkie activerecord_error_wrong_length: ma złą długość -activerecord_error_taken: jest już wybrane -activerecord_error_not_a_number: nie jest numerem -activerecord_error_not_a_date: nie jest prawidłową datą -activerecord_error_greater_than_start_date: musi być większe niż początkowa data -activerecord_error_not_same_project: nie należy do tego samego projektu -activerecord_error_circular_dependency: Ta relacja może wytworzyć kołową zależność - -general_fmt_age: %d lat -general_fmt_age_plural: %d lat -general_fmt_date: %%m/%%d/%%Y -general_fmt_datetime: %%m/%%d/%%Y %%I:%%M %%p -general_fmt_datetime_short: %%b %%d, %%I:%%M %%p -general_fmt_time: %%I:%%M %%p -general_text_No: 'Nie' -general_text_Yes: 'Tak' -general_text_no: 'nie' -general_text_yes: 'tak' -general_lang_name: 'Polski' -general_csv_separator: ',' -general_csv_decimal_separator: '.' -general_csv_encoding: ISO-8859-2 -general_pdf_encoding: ISO-8859-2 -general_day_names: Poniedziałek,Wtorek,Środa,Czwartek,Piątek,Sobota,Niedziela -general_first_day_of_week: '1' - -notice_account_updated: Konto prawidłowo zaktualizowane. -notice_account_invalid_creditentials: Zły użytkownik lub hasło -notice_account_password_updated: Hasło prawidłowo zmienione. -notice_account_wrong_password: Złe hasło -notice_account_register_done: Konto prawidłowo stworzone. -notice_account_unknown_email: Nieznany użytkownik. -notice_can_t_change_password: To konto ma zewnętrzne źródło identyfikacji. Nie możesz zmienić hasła. -notice_account_lost_email_sent: Email z instrukcjami zmiany hasła został wysłany do Ciebie. -notice_account_activated: Twoje konto zostało aktywowane. Możesz się zalogować. -notice_successful_create: Udane stworzenie. -notice_successful_update: Udane poprawienie. -notice_successful_delete: Udane usunięcie. -notice_successful_connection: Udane nawiązanie połączenia. -notice_file_not_found: Strona do której próbujesz się dostać nie istnieje lub została usunięta. -notice_locking_conflict: Dane poprawione przez innego użytkownika. -notice_not_authorized: Nie jesteś autoryzowany by zobaczyć stronę. - +button_activate: Aktywuj +button_add: Dodaj +button_annotate: Adnotuj +button_apply: Ustaw +button_archive: Archiwizuj +button_back: Wstecz +button_cancel: Anuluj +button_change: Zmień +button_change_password: Zmień hasło +button_check_all: Zaznacz wszystko +button_clear: Wyczyść +button_configure: Konfiguruj +button_copy: Kopia +button_create: Stwórz +button_delete: Usuń +button_download: Pobierz +button_edit: Edytuj +button_list: Lista +button_lock: Zablokuj +button_log_time: Log czasu +button_login: Login +button_move: Przenieś +button_quote: Cytuj +button_rename: Zmień nazwę +button_reply: Odpowiedz +button_reset: Resetuj +button_rollback: Przywróc do tej wersji +button_save: Zapisz +button_sort: Sortuj +button_submit: Wyślij +button_test: Testuj +button_unarchive: Przywróc z archiwum +button_uncheck_all: Odznacz wszystko +button_unlock: Odblokuj +button_unwatch: Nie obserwuj +button_update: Uaktualnij +button_view: Pokaż +button_watch: Obserwuj +default_activity_design: Projektowanie +default_activity_development: Rozwój +default_doc_category_tech: Dokumentacja techniczna +default_doc_category_user: Dokumentacja użytkownika +default_issue_status_assigned: Przypisany +default_issue_status_closed: Zamknięty +default_issue_status_feedback: Odpowiedź +default_issue_status_new: Nowy +default_issue_status_rejected: Odrzucony +default_issue_status_resolved: Rozwiązany +default_priority_high: Wysoki +default_priority_immediate: Natychmiastowy +default_priority_low: Niski +default_priority_normal: Normalny +default_priority_urgent: Pilny +default_role_developper: Programista +default_role_manager: Kierownik +default_role_reporter: Wprowadzajacy +default_tracker_bug: Błąd +default_tracker_feature: Zadanie +default_tracker_support: Wsparcie +enumeration_activities: Działania (śledzenie czasu) +enumeration_doc_categories: Kategorie dokumentów +enumeration_issue_priorities: Priorytety zagadnień +error_can_t_load_default_data: "Domyślna konfiguracja nie może być załadowana: %s" +error_issue_not_found_in_project: 'Zaganienie nie zostało znalezione lub nie należy do tego projektu' +error_scm_annotate: "Wpis nie istnieje lub nie można do niego dodawać adnotacji." +error_scm_command_failed: "Wystąpił błąd przy próbie dostępu do repozytorium: %s" error_scm_not_found: "Obiekt lub wersja nie zostały znalezione w repozytorium." -error_scm_command_failed: "An error occurred when trying to access the repository: %s" - -mail_subject_lost_password: Twoje hasło do %s -mail_body_lost_password: 'W celu zmiany swojego hasła użyj poniższego odnośnika:' -mail_subject_register: Aktywacja konta w %s -mail_body_register: 'W celu aktywacji Twojego konta, użyj poniższego odnośnika:' - -gui_validation_error: 1 błąd -gui_validation_error_plural: %d błędów - -field_name: Nazwa -field_description: Opis -field_summary: Podsumowanie -field_is_required: Wymagane -field_firstname: Imię -field_lastname: Nazwisko -field_mail: Email -field_filename: Plik -field_filesize: Rozmiar -field_downloads: Pobrań +field_account: Konto +field_activity: Aktywność +field_admin: Administrator +field_assignable: Zagadnienia mogą być przypisane do tej roli +field_assigned_to: Przydzielony do +field_attr_firstname: Imię atrybut +field_attr_lastname: Nazwisko atrybut +field_attr_login: Login atrybut +field_attr_mail: Email atrybut +field_auth_source: Tryb identyfikacji field_author: Autor -field_created_on: Stworzone -field_updated_on: Zmienione -field_field_format: Format -field_is_for_all: Dla wszystkich projektów -field_possible_values: Możliwe wartości -field_regexp: Wyrażenie regularne -field_min_length: Minimalna długość -field_max_length: Maksymalna długość -field_value: Wartość +field_base_dn: Base DN field_category: Kategoria -field_title: Tytuł -field_project: Projekt -field_issue: Zagadnienie -field_status: Status -field_notes: Notatki -field_is_closed: Zagadnienie zamknięte -field_is_default: Domyślny status -field_tracker: Typ zagadnienia -field_subject: Temat +field_column_names: Nazwy kolumn +field_comments: Komentarz +field_comments_sorting: Pokazuj komentarze +field_created_on: Stworzone +field_default_value: Domyślny +field_delay: Opóźnienie +field_description: Opis +field_done_ratio: %% Wykonane +field_downloads: Pobrań field_due_date: Data oddania -field_assigned_to: Przydzielony do -field_priority: Priorytet +field_effective_date: Data +field_estimated_hours: Szacowany czas +field_field_format: Format +field_filename: Plik +field_filesize: Rozmiar +field_firstname: Imię field_fixed_version: Wersja docelowa -field_user: Użytkownik -field_role: Rola +field_hide_mail: Ukryj mój adres email field_homepage: Strona www -field_is_public: Publiczny -field_parent: Nadprojekt +field_host: Host +field_hours: Godzin +field_identifier: Identifikator +field_is_closed: Zagadnienie zamknięte +field_is_default: Domyślny status +field_is_filter: Atrybut filtrowania +field_is_for_all: Dla wszystkich projektów field_is_in_chlog: Zagadnienie pokazywane w zapisie zmian field_is_in_roadmap: Zagadnienie pokazywane na mapie +field_is_public: Publiczny +field_is_required: Wymagane +field_issue: Zagadnienie +field_issue_to_id: Powiązania zagadnienia +field_language: Język +field_last_login_on: Ostatnie połączenie +field_lastname: Nazwisko field_login: Login +field_mail: Email field_mail_notification: Powiadomienia Email -field_admin: Administrator -field_last_login_on: Ostatnie połączenie -field_language: Język -field_effective_date: Data -field_password: Hasło +field_max_length: Maksymalna długość +field_min_length: Minimalna długość +field_name: Nazwa field_new_password: Nowe hasło +field_notes: Notatki +field_onthefly: Tworzenie użytkownika w locie +field_parent: Nadprojekt +field_parent_title: Strona rodzica +field_password: Hasło field_password_confirmation: Potwierdzenie -field_version: Wersja -field_type: Typ -field_host: Host field_port: Port -field_account: Konto -field_base_dn: Base DN -field_attr_login: Login atrybut -field_attr_firstname: Imię atrybut -field_attr_lastname: Nazwisko atrybut -field_attr_mail: Email atrybut -field_onthefly: Tworzenie użytkownika w locie +field_possible_values: Możliwe wartości +field_priority: Priorytet +field_project: Projekt +field_redirect_existing_links: Przekierowanie istniejących odnośników +field_regexp: Wyrażenie regularne +field_role: Rola +field_searchable: Przeszukiwalne +field_spent_on: Data field_start_date: Start -field_done_ratio: %% Wykonane -field_auth_source: Tryb identyfikacji -field_hide_mail: Ukryj mój adres email -field_comments: Komentarz -field_url: URL field_start_page: Strona startowa +field_status: Status +field_subject: Temat field_subproject: Podprojekt -field_hours: Godzin -field_activity: Aktywność -field_spent_on: Data -field_identifier: Identifikator -field_is_filter: Atrybut filtrowania -field_issue_to_id: Powiązania zagadnienia -field_delay: Opóźnienie -field_default_value: Domyślny - -setting_app_title: Tytuł aplikacji -setting_app_subtitle: Podtytuł aplikacji -setting_welcome_text: Tekst powitalny -setting_default_language: Domyślny język -setting_login_required: Identyfikacja wymagana -setting_self_registration: Własna rejestracja umożliwiona -setting_attachment_max_size: Maks. rozm. załącznika -setting_issues_export_limit: Limit eksportu zagadnień -setting_mail_from: Adres email wysyłki -setting_host_name: Nazwa hosta -setting_text_formatting: Formatowanie tekstu -setting_wiki_compression: Kompresja historii Wiki -setting_feeds_limit: Limit danych RSS -setting_autofetch_changesets: Automatyczne pobieranie zmian -setting_sys_api_enabled: Włączenie WS do zarządzania repozytorium -setting_commit_ref_keywords: Słowa tworzące powiązania -setting_commit_fix_keywords: Słowa zmieniające status -setting_autologin: Auto logowanie -setting_date_format: Format daty - -label_user: Użytkownik -label_user_plural: Użytkownicy -label_user_new: Nowy użytkownik -label_project: Projekt -label_project_new: Nowy projekt -label_project_plural: Projekty -label_project_all: Wszystkie projekty -label_project_latest: Ostatnie projekty -label_issue: Zagadnienie -label_issue_new: Nowe zagadnienie -label_issue_plural: Zagadnienia -label_issue_view_all: Zobacz wszystkie zagadnienia -label_document: Dokument -label_document_new: Nowy dokument -label_document_plural: Dokumenty -label_role: Rola -label_role_plural: Role -label_role_new: Nowa rola -label_role_and_permissions: Role i Uprawnienia -label_member: Uczestnik -label_member_new: Nowy uczestnik -label_member_plural: Uczestnicy -label_tracker: Typ zagadnienia -label_tracker_plural: Typy zagadnień -label_tracker_new: Nowy typ zagadnienia -label_workflow: Przepływ -label_issue_status: Status zagadnienia -label_issue_status_plural: Statusy zagadnień -label_issue_status_new: Nowy status -label_issue_category: Kategoria zagadnienia -label_issue_category_plural: Kategorie zagadnień -label_issue_category_new: Nowa kategoria -label_custom_field: Dowolne pole -label_custom_field_plural: Dowolne pola -label_custom_field_new: Nowe dowolne pole -label_enumerations: Wyliczenia -label_enumeration_new: Nowa wartość -label_information: Informacja -label_information_plural: Informacje -label_please_login: Zaloguj się -label_register: Rejestracja -label_password_lost: Zapomniane hasło -label_home: Główna -label_my_page: Moja strona -label_my_account: Moje konto -label_my_projects: Moje projekty +field_summary: Podsumowanie +field_time_zone: Strefa czasowa +field_title: Tytuł +field_tracker: Typ zagadnienia +field_type: Typ +field_updated_on: Zmienione +field_url: URL +field_user: Użytkownik +field_value: Wartość +field_version: Wersja +field_vf_personnel: Personel +field_vf_watcher: Obserwator +general_csv_decimal_separator: '.' +general_csv_encoding: UTF-8 +general_csv_separator: ',' +general_day_names: Poniedziałek,Wtorek,Środa,Czwartek,Piątek,Sobota,Niedziela +general_first_day_of_week: '1' +general_fmt_age: %d rok +general_fmt_age_plural234: %d lata +general_fmt_age_plural5: %d lat +general_fmt_age_plural: %d lat +general_fmt_date: %%m/%%d/%%Y +general_fmt_datetime: %%m/%%d/%%Y %%I:%%M %%p +general_fmt_datetime_short: %%b %%d, %%I:%%M %%p +general_fmt_time: %%I:%%M %%p +general_lang_name: 'Polski' +general_pdf_encoding: UTF-8 +general_text_No: 'Nie' +general_text_Yes: 'Tak' +general_text_no: 'nie' +general_text_yes: 'tak' +gui_validation_error: 1 błąd +gui_validation_error_plural234: %d błędy +gui_validation_error_plural5: %d błędów +gui_validation_error_plural: %d błędów +label_activity: Aktywność +label_add_another_file: Dodaj kolejny plik +label_add_note: Dodaj notatkę +label_added: dodane +label_added_time_by: Dodane przez %s %s temu label_administration: Administracja -label_login: Login -label_logout: Wylogowanie -label_help: Pomoc -label_reported_issues: Wprowadzone zagadnienia +label_age: Wiek +label_ago: dni temu +label_all: wszystko +label_all_time: cały czas +label_all_words: Wszystkie słowa +label_and_its_subprojects: %s i podprojekty +label_applied_status: Stosowany status label_assigned_to_me_issues: Zagadnienia przypisane do mnie -label_last_login: Ostatnie połączenie -label_last_updates: Ostatnia zmieniana -label_last_updates_plural: %d ostatnie zmiany -label_registered_on: Zarejestrowany -label_activity: Aktywność -label_new: Nowy -label_logged_as: Zalogowany jako -label_environment: Środowisko -label_authentication: Identyfikacja +label_associated_revisions: Skojarzone rewizje +label_attachment: Plik +label_attachment_delete: Usuń plik +label_attachment_new: Nowy plik +label_attachment_plural: Pliki +label_attribute: Atrybut +label_attribute_plural: Atrybuty label_auth_source: Tryb identyfikacji label_auth_source_new: Nowy tryb identyfikacji label_auth_source_plural: Tryby identyfikacji -label_subproject_plural: Podprojekty -label_min_max_length: Min - Maks długość -label_list: Lista -label_date: Data -label_integer: Liczba całkowita +label_authentication: Identyfikacja +label_blocked_by: zablokowane przez +label_blocks: blokady +label_board: Forum +label_board_new: Nowe forum +label_board_plural: Fora label_boolean: Wartość logiczna -label_string: Tekst -label_text: Długi tekst -label_attribute: Atrybut -label_attribute_plural: Atrybuty -label_download: %d Pobranie -label_download_plural: %d Pobrania -label_no_data: Brak danych do pokazania -label_change_status: Status zmian -label_history: Historia -label_attachment: Plik -label_attachment_new: Nowy plik -label_attachment_delete: Skasuj plik -label_attachment_plural: Pliki -label_report: Raport -label_report_plural: Raporty -label_news: Wiadomość -label_news_new: Dodaj wiadomość -label_news_plural: Wiadomości -label_news_latest: Ostatnie wiadomości -label_news_view_all: Pokaż wszystkie wiadomości +label_browse: Przegląd +label_bulk_edit_selected_issues: Zbiorowa edycja zagadnień +label_calendar: Kalendarz label_change_log: Lista zmian -label_settings: Ustawienia -label_overview: Przegląd -label_version: Wersja -label_version_new: Nowa wersja -label_version_plural: Wersje -label_confirmation: Potwierdzenie -label_export_to: Eksportuj do -label_read: Czytanie... -label_public_projects: Projekty publiczne -label_open_issues: otwarte -label_open_issues_plural: otwarte +label_change_plural: Zmiany +label_change_properties: Zmień właściwości +label_change_status: Status zmian +label_change_view_all: Pokaż wszystkie zmiany +label_changes_details: Szczegóły wszystkich zmian +label_changeset_plural: Zestawienia zmian +label_chronological_order: W kolejności chronologicznej label_closed_issues: zamknięte +label_closed_issues_plural234: zamknięte +label_closed_issues_plural5: zamknięte label_closed_issues_plural: zamknięte -label_total: Ogółem -label_permissions: Uprawnienia -label_current_status: Obecny status -label_new_statuses_allowed: Uprawnione nowe statusy -label_all: wszystko -label_none: brak -label_next: Następne -label_previous: Poprzednie -label_used_by: Używane przez -label_details: Szczegóły -label_add_note: Dodaj notatkę -label_per_page: Na stronę -label_calendar: Kalendarz -label_months_from: miesiące od -label_gantt: Gantt -label_internal: Wewnętrzny -label_last_changes: ostatnie %d zmian -label_change_view_all: Pokaż wszystkie zmiany -label_personalize_page: Personalizuj tą stronę label_comment: Komentarz -label_comment_plural: Komentarze label_comment_add: Dodaj komentarz label_comment_added: Komentarz dodany label_comment_delete: Usuń komentarze -label_query: Dowolne zapytanie -label_query_plural: Dowolne zapytania -label_query_new: Nowe zapytanie -label_filter_add: Dodaj filtr -label_filter_plural: Filtry -label_equals: jest -label_not_equals: nie jest -label_in_less_than: w mniejszych od -label_in_more_than: w większych niż -label_in: w -label_today: dzisiaj -label_less_than_ago: dni mniej -label_more_than_ago: dni więcej -label_ago: dni temu +label_comment_plural234: Komentarze +label_comment_plural5: Komentarze +label_comment_plural: Komentarze +label_commits_per_author: Zatwierdzenia według autorów +label_commits_per_month: Zatwierdzenia według miesięcy +label_confirmation: Potwierdzenie label_contains: zawiera -label_not_contains: nie zawiera +label_copied: skopiowano +label_copy_workflow_from: Kopiuj przepływ z +label_current_status: Obecny status +label_current_version: Obecna wersja +label_custom_field: Dowolne pole +label_custom_field_new: Nowe dowolne pole +label_custom_field_plural: Dowolne pola +label_date: Data +label_date_from: Z +label_date_range: Zakres datowy +label_date_to: Do label_day_plural: dni -label_repository: Repozytorium -label_browse: Przegląd -label_modification: %d modyfikacja -label_modification_plural: %d modyfikacja -label_revision: Rewizja -label_revision_plural: Rewizje -label_added: dodane -label_modified: zmodyfikowane +label_default: Domyślne +label_default_columns: Domyślne kolumny label_deleted: usunięte -label_latest_revision: Najnowsza rewizja -label_latest_revision_plural: Najnowsze rewizje -label_view_revisions: Pokaż rewizje -label_max_size: Maksymalny rozmiar -label_on: 'z' -label_sort_highest: Przesuń na górę -label_sort_higher: Do góry -label_sort_lower: Do dołu -label_sort_lowest: Przesuń na dół -label_roadmap: Mapa -label_roadmap_due_in: W czasie %s -label_roadmap_no_issues: Brak zagadnień do tej wersji -label_search: Szukaj -label_result_plural: Rezultatów -label_all_words: Wszystkie słowa -label_wiki: Wiki -label_wiki_edit: Edycja wiki -label_wiki_edit_plural: Edycje wiki -label_wiki_page: Strona wiki -label_wiki_page_plural: Strony wiki -label_index_by_title: Indeks -label_index_by_date: Index by date -label_current_version: Obecna wersja -label_preview: Podgląd -label_feed_plural: Ilość RSS -label_changes_details: Szczegóły wszystkich zmian -label_issue_tracking: Śledzenie zagadnień -label_spent_time: Spędzony czas -label_f_hour: %.2f godzina -label_f_hour_plural: %.2f godzin -label_time_tracking: Śledzenie czasu -label_change_plural: Zmiany -label_statistics: Statystyki -label_commits_per_month: Zatwierdzenia według miesięcy -label_commits_per_author: Zatwierdzenia według autorów -label_view_diff: Pokaż różnice +label_details: Szczegóły label_diff_inline: w linii label_diff_side_by_side: obok siebie -label_options: Opcje -label_copy_workflow_from: Kopiuj przepływ z -label_permissions_report: Raport uprawnień -label_watched_issues: Obserwowane zagadnienia -label_related_issues: Powiązane zagadnienia -label_applied_status: Stosowany status -label_loading: Ładowanie... -label_relation_new: Nowe powiązanie -label_relation_delete: Usuń powiązanie -label_relates_to: powiązane z -label_duplicates: duplikaty -label_blocks: blokady -label_blocked_by: zablokowane przez -label_precedes: poprzedza -label_follows: podąża -label_end_to_start: koniec do początku -label_end_to_end: koniec do końca -label_start_to_start: początek do początku -label_start_to_end: początek do końca -label_stay_logged_in: Pozostań zalogowany label_disabled: zablokowany -label_show_completed_versions: Pokaż kompletne wersje +label_display_per_page: 'Na stronę: %s' +label_document: Dokument +label_document_added: Dodano dokument +label_document_new: Nowy dokument +label_document_plural: Dokumenty +label_download: %d Pobranie +label_download_plural234: %d Pobrania +label_download_plural5: %d Pobrań +label_download_plural: %d Pobrania +label_downloads_abbr: Pobieranie +label_duplicated_by: zdublikowane przez +label_duplicates: duplikaty +label_end_to_end: koniec do końca +label_end_to_start: koniec do początku +label_enumeration_new: Nowa wartość +label_enumerations: Wyliczenia +label_environment: Środowisko +label_equals: równa się +label_example: Przykład +label_export_to: Eksportuj do +label_f_hour: %.2f godzina +label_f_hour_plural234: %.2f godziny +label_f_hour_plural5: %.2f godzin +label_f_hour_plural: %.2f godzin +label_feed_plural: Ilość RSS +label_feeds_access_key_created_on: Klucz dostępu RSS stworzony %s dni temu +label_file_added: Dodano plik +label_file_plural: Pliki +label_filter_add: Dodaj filtr +label_filter_plural: Filtry +label_float: Liczba rzeczywista +label_follows: następuje po +label_gantt: Gantt +label_general: Ogólne +label_generate_key: Wygeneruj klucz +label_help: Pomoc +label_history: Historia +label_home: Główna +label_in: w +label_in_less_than: mniejsze niż +label_in_more_than: większe niż +label_incoming_emails: Przychodząca poczta elektroniczna +label_index_by_date: Index by date +label_index_by_title: Indeks +label_information: Informacja +label_information_plural: Informacje +label_integer: Liczba całkowita +label_internal: Wewnętrzny +label_issue: Zagadnienie +label_issue_added: Dodano zagadnienie +label_issue_category: Kategoria zagadnienia +label_issue_category_new: Nowa kategoria +label_issue_category_plural: Kategorie zagadnień +label_issue_new: Nowe zagadnienie +label_issue_plural: Zagadnienia +label_issue_status: Status zagadnienia +label_issue_status_new: Nowy status +label_issue_status_plural: Statusy zagadnień +label_issue_tracking: Śledzenie zagadnień +label_issue_updated: Uaktualniono zagadnienie +label_issue_view_all: Zobacz wszystkie zagadnienia +label_issue_watchers: Obserwatorzy +label_issues_by: Zagadnienia wprowadzone przez %s +label_jump_to_a_project: Skocz do projektu... +label_language_based: Na podstawie języka +label_last_changes: ostatnie %d zmian +label_last_login: Ostatnie połączenie +label_last_month: ostatni miesiąc +label_last_n_days: ostatnie %d dni +label_last_updates: Ostatnia zmiana +label_last_updates_plural234: %d ostatnie zmiany +label_last_updates_plural5: %d ostatnich zmian +label_last_updates_plural: %d ostatnie zmiany +label_last_week: ostatni tydzień +label_latest_revision: Najnowsza rewizja +label_latest_revision_plural: Najnowsze rewizje +label_ldap_authentication: Autoryzacja LDAP +label_less_than_ago: dni mniej +label_list: Lista +label_loading: Ładowanie... +label_logged_as: Zalogowany jako +label_login: Login +label_logout: Wylogowanie +label_max_size: Maksymalny rozmiar label_me: ja -label_board: Forum -label_board_new: Nowe forum -label_board_plural: Fora -label_topic_plural: Tematy -label_message_plural: Wiadomości +label_member: Uczestnik +label_member_new: Nowy uczestnik +label_member_plural: Uczestnicy label_message_last: Ostatnia wiadomość label_message_new: Nowa wiadomość -label_reply_plural: Odpowiedzi -label_send_information: Wyślij informację użytkownikowi -label_year: Rok +label_message_plural: Wiadomości +label_message_posted: Dodano wiadomość +label_min_max_length: Min - Maks długość +label_modification: %d modyfikacja +label_modification_plural234: %d modyfikacje +label_modification_plural5: %d modyfikacji +label_modification_plural: %d modyfikacje +label_modified: zmodyfikowane +label_module_plural: Moduły label_month: Miesiąc -label_week: Tydzień -label_date_from: Z -label_date_to: Do -label_language_based: Na podstawie języka - -button_login: Login -button_submit: Wyślij -button_save: Zapisz -button_check_all: Zaznacz wszystko -button_uncheck_all: Odznacz wszystko -button_delete: Usuń -button_create: Stwórz -button_test: Testuj -button_edit: Edytuj -button_add: Dodaj -button_change: Zmień -button_apply: Ustaw -button_clear: Wyczyść -button_lock: Zablokuj -button_unlock: Odblokuj -button_download: Pobierz -button_list: Lista -button_view: Pokaż -button_move: Przenieś -button_back: Wstecz -button_cancel: Anuluj -button_activate: Aktywuj -button_sort: Sortuj -button_log_time: Log czasu -button_rollback: Przywróc do tej wersji -button_watch: Obserwuj -button_unwatch: Nie obserwuj -button_reply: Odpowiedz -button_archive: Archiwizuj -button_unarchive: Przywróc z archiwum - -status_active: aktywny -status_registered: zarejestrowany -status_locked: zablokowany - -text_select_mail_notifications: Zaznacz czynności przy których użytkownik powinien być powiadomiony mailem. -text_regexp_info: np. ^[A-Z0-9]+$ -text_min_max_length_info: 0 oznacza brak restrykcji -text_project_destroy_confirmation: Jesteś pewien, że chcesz usunąć ten projekt i wszyskie powiązane dane? -text_workflow_edit: Zaznacz rolę i typ zagadnienia do edycji przepływu -text_are_you_sure: Jesteś pewien ? -text_journal_changed: zmienione %s do %s -text_journal_set_to: ustawione na %s -text_journal_deleted: usunięte -text_tip_task_begin_day: zadanie zaczynające się dzisiaj -text_tip_task_end_day: zadanie kończące się dzisiaj -text_tip_task_begin_end_day: zadanie zaczynające i kończące się dzisiaj -text_project_identifier_info: 'Małe litery (a-z), liczby i myślniki dozwolone.
    Raz zapisany, identyfikator nie może być zmieniony.' -text_caracters_maximum: %d znaków maksymalnie. -text_length_between: Długość pomiędzy %d i %d znaków. -text_tracker_no_workflow: Brak przepływu zefiniowanego dla tego typu zagadnienia -text_unallowed_characters: Niedozwolone znaki -text_comma_separated: Wielokrotne wartości dozwolone (rozdzielone przecinkami). -text_issues_ref_in_commit_messages: Odwołania do zagadnień w komentarzach zatwierdzeń - -default_role_manager: Kierownik -default_role_developper: Programista -default_role_reporter: Wprowadzajacy -default_tracker_bug: Błąd -default_tracker_feature: Zadanie -default_tracker_support: Wsparcie -default_issue_status_new: Nowy -default_issue_status_assigned: Przypisany -default_issue_status_resolved: Rozwiązany -default_issue_status_feedback: Odpowiedź -default_issue_status_closed: Zamknięty -default_issue_status_rejected: Odrzucony -default_doc_category_user: Dokumentacja użytkownika -default_doc_category_tech: Dokumentacja techniczna -default_priority_low: Niski -default_priority_normal: Normalny -default_priority_high: Wysoki -default_priority_urgent: Pilny -default_priority_immediate: Natychmiastowy -default_activity_design: Projektowanie -default_activity_development: Rozwój - -enumeration_issue_priorities: Priorytety zagadnień -enumeration_doc_categories: Kategorie dokumentów -enumeration_activities: Działania (śledzenie czasu) -button_rename: Zmień nazwę -text_issue_category_destroy_question: Zagadnienia (%d) są przypisane do tej kategorii. Co chcesz uczynić? -label_feeds_access_key_created_on: Klucz dostępu RSS stworzony %s dni temu -setting_cross_project_issue_relations: Zezwól na powiązania zagadnień między projektami +label_months_from: miesiące od +label_more: Więcej +label_more_than_ago: dni więcej +label_my_account: Moje konto +label_my_page: Moja strona +label_my_projects: Moje projekty +label_new: Nowy +label_new_statuses_allowed: Uprawnione nowe statusy +label_news: Komunikat +label_news_added: Dodano komunikat +label_news_latest: Ostatnie komunikaty +label_news_new: Dodaj komunikat +label_news_plural: Komunikaty +label_news_view_all: Pokaż wszystkie komunikaty +label_next: Następne +label_no_change_option: (Bez zmian) +label_no_data: Brak danych do pokazania +label_nobody: nikt +label_none: brak +label_not_contains: nie zawiera +label_not_equals: różni się +label_on: 'z' +label_open_issues: otwarte +label_open_issues_plural234: otwarte +label_open_issues_plural5: otwarte +label_open_issues_plural: otwarte +label_optional_description: Opcjonalny opis +label_options: Opcje +label_overall_activity: Ogólna aktywność +label_overview: Przegląd +label_password_lost: Zapomniane hasło +label_per_page: Na stronę +label_permissions: Uprawnienia +label_permissions_report: Raport uprawnień +label_personalize_page: Personalizuj tą stronę +label_planning: Planowanie +label_please_login: Zaloguj się +label_plugins: Wtyczki +label_precedes: poprzedza +label_preferences: Preferencje +label_preview: Podgląd +label_previous: Poprzednie +label_project: Projekt +label_project_all: Wszystkie projekty +label_project_latest: Ostatnie projekty +label_project_new: Nowy projekt +label_project_plural234: Projekty +label_project_plural5: Projekty +label_project_plural: Projekty +label_public_projects: Projekty publiczne +label_query: Kwerenda +label_query_new: Nowa kwerenda +label_query_plural: Kwerendy +label_read: Czytanie... +label_register: Rejestracja +label_registered_on: Zarejestrowany +label_registration_activation_by_email: aktywacja konta przez e-mail +label_registration_automatic_activation: automatyczna aktywacja kont +label_registration_manual_activation: manualna aktywacja kont +label_related_issues: Powiązane zagadnienia +label_relates_to: powiązane z +label_relation_delete: Usuń powiązanie +label_relation_new: Nowe powiązanie +label_renamed: przemianowano +label_reply_plural: Odpowiedzi +label_report: Raport +label_report_plural: Raporty +label_reported_issues: Wprowadzone zagadnienia +label_repository: Repozytorium +label_repository_plural: Repozytoria +label_result_plural: Rezultatów +label_reverse_chronological_order: W kolejności odwrotnej do chronologicznej +label_revision: Rewizja +label_revision_plural: Rewizje +label_roadmap: Mapa +label_roadmap_due_in: W czasie +label_roadmap_no_issues: Brak zagadnień do tej wersji label_roadmap_overdue: %s spóźnienia -label_module_plural: Moduły -label_this_week: ten tydzień -label_jump_to_a_project: Skocz do projektu... -field_assignable: Zagadnienia mogą być przypisane do tej roli -label_sort_by: Sortuj po %s -text_issue_updated: Zagadnienie %s zostało zaktualizowane (by %s). -notice_feeds_access_key_reseted: Twój klucz dostępu RSS został zrestetowany. -field_redirect_existing_links: Przekierowanie istniejących odnośników -text_issue_category_reassign_to: Przydziel zagadnienie do tej kategorii -notice_email_sent: Email został wysłany do %s -text_issue_added: Zagadnienie %s zostało wprowadzone (by %s). -text_wiki_destroy_confirmation: Jesteś pewien, że chcesz usunąć to wiki i całą jego zawartość ? -notice_email_error: Wystąpił błąd w trakcie wysyłania maila (%s) -label_updated_time: Zaktualizowane %s temu -text_issue_category_destroy_assignments: Usuń przydziały kategorii +label_role: Rola +label_role_and_permissions: Role i Uprawnienia +label_role_new: Nowa rola +label_role_plural: Role +label_scm: SCM +label_search: Szukaj +label_search_titles_only: Przeszukuj tylko tytuły +label_send_information: Wyślij informację użytkownikowi label_send_test_email: Wyślij próbny email -button_reset: Resetuj -label_added_time_by: Dodane przez %s %s temu -field_estimated_hours: Szacowany czas -label_file_plural: Pliki -label_changeset_plural: Zestawienia zmian -field_column_names: Nazwy kolumn -label_default_columns: Domyślne kolumny -setting_issue_list_default_columns: Domyślne kolumny wiświetlane na liście zagadnień -setting_repositories_encodings: Kodowanie repozytoriów -notice_no_issue_selected: "Nie wybrano zagadnienia! Zaznacz zagadnienie, które chcesz edytować." -label_bulk_edit_selected_issues: Zbiorowa edycja zagadnień -label_no_change_option: (Bez zmian) -notice_failed_to_save_issues: "Błąd podczas zapisu zagadnień %d z %d zaznaczonych: %s." +label_settings: Ustawienia +label_show_completed_versions: Pokaż kompletne wersje +label_sort_by: Sortuj po %s +label_sort_higher: Do góry +label_sort_highest: Przesuń na górę +label_sort_lower: Do dołu +label_sort_lowest: Przesuń na dół +label_spent_time: Spędzony czas +label_start_to_end: początek do końca +label_start_to_start: początek do początku +label_statistics: Statystyki +label_stay_logged_in: Pozostań zalogowany +label_string: Tekst +label_subproject_plural: Podprojekty +label_text: Długi tekst label_theme: Temat -label_default: Domyślne -label_search_titles_only: Przeszukuj tylko tytuły -label_nobody: nikt -button_change_password: Zmień hasło -text_user_mail_option: "W przypadku niezaznaczonych projektów, będziesz otrzymywał powiadomienia tylko na temat zagadnien, które obserwujesz, lub w których bierzesz udział (np. jesteś autorem lub adresatem)." -label_user_mail_option_selected: "Tylko dla każdego zdarzenia w wybranych projektach..." +label_this_month: ten miesiąc +label_this_week: ten tydzień +label_this_year: ten rok +label_time_tracking: Śledzenie czasu +label_today: dzisiaj +label_topic_plural: Tematy +label_total: Ogółem +label_tracker: Typ zagadnienia +label_tracker_new: Nowy typ zagadnienia +label_tracker_plural: Typy zagadnień +label_updated_time: Zaktualizowane %s temu +label_used_by: Używane przez +label_user: Użytkownik +label_user_mail_no_self_notified: "Nie chcę powiadomień o zmianach, które sam wprowadzam." label_user_mail_option_all: "Dla każdego zdarzenia w każdym moim projekcie" label_user_mail_option_none: "Tylko to co obserwuje lub w czym biorę udział" -setting_emails_footer: Stopka e-mail -label_float: Liczba rzeczywista -button_copy: Kopia -mail_body_account_information_external: Możesz użyć twojego "%s" konta do zalogowania. +label_user_mail_option_selected: "Tylko dla każdego zdarzenia w wybranych projektach..." +label_user_new: Nowy użytkownik +label_user_plural: Użytkownicy +label_version: Wersja +label_version_new: Nowa wersja +label_version_plural: Wersje +label_view_diff: Pokaż różnice +label_view_revisions: Pokaż rewizje +label_watched_issues: Obserwowane zagadnienia +label_week: Tydzień +label_wiki: Wiki +label_wiki_edit: Edycja wiki +label_wiki_edit_plural: Edycje wiki +label_wiki_page: Strona wiki +label_wiki_page_plural: Strony wiki +label_workflow: Przepływ +label_year: Rok +label_yesterday: wczoraj +mail_body_account_activation_request: 'Zarejestrowano nowego użytkownika: (%s). Konto oczekuje na twoje zatwierdzenie:' mail_body_account_information: Twoje konto -setting_protocol: Protokoł -label_user_mail_no_self_notified: "Nie chcę powiadomień o zmianach, które sam wprowadzam." -setting_time_format: Format czasu -label_registration_activation_by_email: aktywacja konta przez e-mail +mail_body_account_information_external: Możesz użyć twojego "%s" konta do zalogowania. +mail_body_lost_password: 'W celu zmiany swojego hasła użyj poniższego odnośnika:' +mail_body_register: 'W celu aktywacji Twojego konta, użyj poniższego odnośnika:' +mail_body_reminder: "Wykaz przypisanych do Ciebie zagadnień, których termin wypada w ciągu następnych %d dni" mail_subject_account_activation_request: Zapytanie aktywacyjne konta %s -mail_body_account_activation_request: 'Zarejestrowano nowego użytkownika: (%s). Konto oczekuje na twoje zatwierdzenie:' -label_registration_automatic_activation: automatyczna aktywacja kont -label_registration_manual_activation: manualna aktywacja kont +mail_subject_lost_password: Twoje hasło do %s +mail_subject_register: Aktywacja konta w %s +mail_subject_reminder: "Uwaga na terminy, masz zagadnienia do obsłużenia w ciągu następnych %d dni!" +notice_account_activated: Twoje konto zostało aktywowane. Możesz się zalogować. +notice_account_invalid_creditentials: Zły użytkownik lub hasło +notice_account_lost_email_sent: Email z instrukcjami zmiany hasła został wysłany do Ciebie. +notice_account_password_updated: Hasło prawidłowo zmienione. notice_account_pending: "Twoje konto zostało utworzone i oczekuje na zatwierdzenie administratora." -field_time_zone: Strefa czasowa -text_caracters_minimum: Musi być nie krótsze niż %d znaków. -setting_bcc_recipients: Odbiorcy kopii tajnej (kt/bcc) -button_annotate: Adnotuj -label_issues_by: Zagadnienia wprowadzone przez %s -field_searchable: Przeszukiwalne -label_display_per_page: 'Na stronę: %s' -setting_per_page_options: Opcje ilości obiektów na stronie -label_age: Wiek +notice_account_register_done: Konto prawidłowo stworzone. +notice_account_unknown_email: Nieznany użytkownik. +notice_account_updated: Konto prawidłowo zaktualizowane. +notice_account_wrong_password: Złe hasło +notice_can_t_change_password: To konto ma zewnętrzne źródło identyfikacji. Nie możesz zmienić hasła. notice_default_data_loaded: Domyślna konfiguracja została pomyślnie załadowana. -text_load_default_configuration: Załaduj domyślną konfigurację -text_no_configuration_data: "Role użytkowników, typy zagadnień, statusy zagadnień oraz przepływ pracy nie zostały jeszcze skonfigurowane.\nJest wysoce rekomendowane by załadować domyślną konfigurację. Po załadowaniu będzie możliwość edycji tych danych." -error_can_t_load_default_data: "Domyślna konfiguracja nie może być załadowana: %s" -button_update: Uaktualnij -label_change_properties: Zmień właściwości -label_general: Ogólne -label_repository_plural: Repozytoria -label_associated_revisions: Skojarzone rewizje -setting_user_format: Personalny format wyświetlania -text_status_changed_by_changeset: Zastosowane w zmianach %s. -label_more: Więcej -text_issues_destroy_confirmation: 'Czy jestes pewien, że chcesz usunąć wskazane zagadnienia?' -label_scm: SCM -text_select_project_modules: 'Wybierz moduły do aktywacji w tym projekcie:' -label_issue_added: Dodano zagadnienie -label_issue_updated: Uaktualniono zagadnienie -label_document_added: Dodano dokument -label_message_posted: Dodano wiadomość -label_file_added: Dodano plik -label_news_added: Dodano wiadomość +notice_email_error: Wystąpił błąd w trakcie wysyłania maila (%s) +notice_email_sent: Email został wysłany do %s +notice_failed_to_save_issues: "Błąd podczas zapisu zagadnień %d z %d zaznaczonych: %s." +notice_feeds_access_key_reseted: Twój klucz dostępu RSS został zrestetowany. +notice_file_not_found: Strona do której próbujesz się dostać nie istnieje lub została usunięta. +notice_locking_conflict: Dane poprawione przez innego użytkownika. +notice_no_issue_selected: "Nie wybrano zagadnienia! Zaznacz zagadnienie, które chcesz edytować." +notice_not_authorized: Nie jesteś autoryzowany by zobaczyć stronę. +notice_successful_connection: Udane nawiązanie połączenia. +notice_successful_create: Utworzenie zakończone sukcesem. +notice_successful_delete: Usunięcie zakończone sukcesem. +notice_successful_update: Uaktualnienie zakończone sukcesem. +notice_unable_delete_version: Nie można usunąć wersji +permission_add_issue_notes: Dodawanie notatek +permission_add_issue_watchers: Dodawanie obserwatorów +permission_add_issues: Dodawanie zagadnień +permission_add_messages: Dodawanie wiadomości +permission_browse_repository: Przeglądanie repozytorium +permission_comment_news: Komentowanie komunikatów +permission_commit_access: Wykonywanie zatwierdzeń +permission_delete_issues: Usuwanie zagadnień +permission_delete_messages: Usuwanie wiadomości +permission_delete_wiki_pages: Usuwanie stron wiki +permission_delete_wiki_pages_attachments: Usuwanie załączników +permission_delete_own_messages: Usuwanie własnych wiadomości +permission_edit_issue_notes: Edycja notatek +permission_edit_issues: Edycja zagadnień +permission_edit_messages: Edycja wiadomości +permission_edit_own_issue_notes: Edycja własnych notatek +permission_edit_own_messages: Edycja własnych wiadomości +permission_edit_own_time_entries: Edycja własnego logu czasu +permission_edit_project: Edycja projektów +permission_edit_time_entries: Edycja logów czasu +permission_edit_wiki_pages: Edycja stron wiki +permission_log_time: Zapisywanie spędzonego czasu +permission_manage_boards: Zarządzanie forami +permission_manage_categories: Zarządzanie kategoriami zaganień +permission_manage_documents: Zarządzanie dokumentami +permission_manage_files: Zarządzanie plikami +permission_manage_issue_relations: Zarządzanie powiązaniami zagadnień +permission_manage_members: Zarządzanie uczestnikami +permission_manage_news: Zarządzanie komunikatami +permission_manage_public_queries: Zarządzanie publicznymi kwerendami +permission_manage_repository: Zarządzanie repozytorium +permission_manage_versions: Zarządzanie wersjami +permission_manage_wiki: Zarządzanie wiki +permission_move_issues: Przenoszenie zagadnień +permission_protect_wiki_pages: Blokowanie stron wiki +permission_rename_wiki_pages: Zmiana nazw stron wiki +permission_save_queries: Zapisywanie kwerend +permission_select_project_modules: Wybieranie modułów projektu +permission_view_calendar: Podgląd kalendarza +permission_view_changesets: Podgląd zmian +permission_view_documents: Podgląd dokumentów +permission_view_files: Podgląd plików +permission_view_gantt: Podgląd diagramu Gantta +permission_view_issue_watchers: Podgląd listy obserwatorów +permission_view_messages: Podgląd wiadomości +permission_view_time_entries: Podgląd spędzonego czasu +permission_view_wiki_edits: Podgląd historii wiki +permission_view_wiki_pages: Podgląd wiki project_module_boards: Fora -project_module_issue_tracking: Śledzenie zagadnień -project_module_wiki: Wiki -project_module_files: Pliki project_module_documents: Dokumenty +project_module_files: Pliki +project_module_issue_tracking: Śledzenie zagadnień +project_module_news: Komunikaty project_module_repository: Repozytorium -project_module_news: Wiadomości project_module_time_tracking: Śledzenie czasu -text_file_repository_writable: Zapisywalne repozytorium plików -text_default_administrator_account_changed: Zmieniono domyślne hasło administratora -text_rmagick_available: RMagick dostępne (opcjonalnie) -button_configure: Konfiguruj -label_plugins: Wtyczki -label_ldap_authentication: Autoryzacja LDAP -label_downloads_abbr: Pobieranie -label_this_month: ten miesiąc -label_last_n_days: ostatnie %d dni -label_all_time: cały czas -label_this_year: ten rok -label_date_range: Zakres datowy -label_last_week: ostatni tydzień -label_yesterday: wczoraj -label_last_month: ostatni miesiąc -label_add_another_file: Dodaj kolejny plik -label_optional_description: Opcjonalny opis -text_destroy_time_entries_question: Zalogowano %.02f godzin przy zagadnieniu, które chcesz usunąć. Co chcesz zrobić? -error_issue_not_found_in_project: 'Zaganienie nie zostało znalezione lub nie należy do tego projektu' +project_module_wiki: Wiki +setting_activity_days_default: Dni wyświetlane w aktywności projektu +setting_app_subtitle: Podtytuł aplikacji +setting_app_title: Tytuł aplikacji +setting_attachment_max_size: Maks. rozm. załącznika +setting_autofetch_changesets: Automatyczne pobieranie zmian +setting_autologin: Auto logowanie +setting_bcc_recipients: Odbiorcy kopii tajnej (kt/bcc) +setting_commit_fix_keywords: Słowa zmieniające status +setting_commit_logs_encoding: Kodowanie komentarzy zatwierdzeń +setting_commit_ref_keywords: Słowa tworzące powiązania +setting_cross_project_issue_relations: Zezwól na powiązania zagadnień między projektami +setting_date_format: Format daty +setting_default_language: Domyślny język +setting_default_projects_public: Nowe projekty są domyślnie publiczne +setting_display_subprojects_issues: Domyślnie pokazuj zagadnienia podprojektów w głównym projekcie +setting_emails_footer: Stopka e-mail +setting_enabled_scm: Dostępny SCM +setting_feeds_limit: Limit danych RSS +setting_gravatar_enabled: Używaj ikon użytkowników Gravatar +setting_host_name: Nazwa hosta i ścieżka +setting_issue_list_default_columns: Domyślne kolumny wiświetlane na liście zagadnień +setting_issues_export_limit: Limit eksportu zagadnień +setting_login_required: Identyfikacja wymagana +setting_mail_from: Adres email wysyłki +setting_mail_handler_api_enabled: Uaktywnij usługi sieciowe (WebServices) dla poczty przychodzącej +setting_mail_handler_api_key: Klucz API +setting_per_page_options: Opcje ilości obiektów na stronie +setting_plain_text_mail: tylko tekst (bez HTML) +setting_protocol: Protokoł +setting_repositories_encodings: Kodowanie repozytoriów +setting_self_registration: Własna rejestracja umożliwiona +setting_sequential_project_identifiers: Generuj sekwencyjne identyfikatory projektów +setting_sys_api_enabled: Włączenie WS do zarządzania repozytorium +setting_text_formatting: Formatowanie tekstu +setting_time_format: Format czasu +setting_user_format: Personalny format wyświetlania +setting_welcome_text: Tekst powitalny +setting_wiki_compression: Kompresja historii Wiki +status_active: aktywny +status_locked: zablokowany +status_registered: zarejestrowany +text_are_you_sure: Jesteś pewien ? text_assign_time_entries_to_project: Przypisz logowany czas do projektu +text_caracters_maximum: %d znaków maksymalnie. +text_caracters_minimum: Musi być nie krótsze niż %d znaków. +text_comma_separated: Wielokrotne wartości dozwolone (rozdzielone przecinkami). +text_default_administrator_account_changed: Zmieniono domyślne hasło administratora text_destroy_time_entries: Usuń zalogowany czas +text_destroy_time_entries_question: Zalogowano %.02f godzin przy zagadnieniu, które chcesz usunąć. Co chcesz zrobić? +text_email_delivery_not_configured: "Dostarczanie poczty elektronicznej nie zostało skonfigurowane, więc powiadamianie jest nieaktywne.\nSkonfiguruj serwer SMTP w config/email.yml a następnie zrestartuj aplikację i uaktywnij to." +text_enumeration_category_reassign_to: 'Zmień przypisanie na tą wartość:' +text_enumeration_destroy_question: '%d obiektów jest przypisana do tej wartości.' +text_file_repository_writable: Zapisywalne repozytorium plików +text_issue_added: Zagadnienie %s zostało wprowadzone (by %s). +text_issue_category_destroy_assignments: Usuń przydziały kategorii +text_issue_category_destroy_question: Zagadnienia (%d) są przypisane do tej kategorii. Co chcesz uczynić? +text_issue_category_reassign_to: Przydziel zagadnienie do tej kategorii +text_issue_updated: Zagadnienie %s zostało zaktualizowane (by %s). +text_issues_destroy_confirmation: 'Czy jestes pewien, że chcesz usunąć wskazane zagadnienia?' +text_issues_ref_in_commit_messages: Odwołania do zagadnień w komentarzach zatwierdzeń +text_journal_changed: zmienione %s do %s +text_journal_deleted: usunięte +text_journal_set_to: ustawione na %s +text_length_between: Długość pomiędzy %d i %d znaków. +text_load_default_configuration: Załaduj domyślną konfigurację +text_min_max_length_info: 0 oznacza brak restrykcji +text_no_configuration_data: "Role użytkowników, typy zagadnień, statusy zagadnień oraz przepływ pracy nie zostały jeszcze skonfigurowane.\nJest wysoce rekomendowane by załadować domyślną konfigurację. Po załadowaniu będzie możliwość edycji tych danych." +text_project_destroy_confirmation: Jesteś pewien, że chcesz usunąć ten projekt i wszyskie powiązane dane? +text_project_identifier_info: 'Małe litery (a-z), liczby i myślniki dozwolone.
    Raz zapisany, identyfikator nie może być zmieniony.' text_reassign_time_entries: 'Przepnij zalogowany czas do tego zagadnienia:' -label_chronological_order: W kolejności chronologicznej -setting_activity_days_default: Dni wyświetlane w aktywności projektu -setting_display_subprojects_issues: Domyślnie pokazuj zagadnienia podprojektów w głównym projekcie -field_comments_sorting: Pokazuj komentarze -label_reverse_chronological_order: W kolejności odwrotnej do chronologicznej -label_preferences: Preferencje -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.' -label_and_its_subprojects: %s and its subprojects -mail_body_reminder: "%d issue(s) that are assigned to you are due in the next %d days:" -mail_subject_reminder: "%d issue(s) due in the next days" -text_user_wrote: '%s wrote:' -label_duplicated_by: duplicated by -setting_enabled_scm: Enabled SCM -text_enumeration_category_reassign_to: 'Reassign them to this value:' -text_enumeration_destroy_question: '%d objects are assigned to this value.' -label_incoming_emails: Incoming emails -label_generate_key: Generate a key -setting_mail_handler_api_enabled: Enable WS for incoming emails -setting_mail_handler_api_key: API key -text_email_delivery_not_configured: "Email delivery is not configured, and notifications are disabled.\nConfigure your SMTP server in config/email.yml and restart the application to enable them." -field_parent_title: Parent page -label_issue_watchers: Watchers -setting_commit_logs_encoding: Commit messages encoding -button_quote: Quote -setting_sequential_project_identifiers: Generate sequential project identifiers -notice_unable_delete_version: Unable to delete version -label_renamed: renamed -label_copied: copied -setting_repositories_cache_directory: Cache directory for repositories -field_cache: Local cache +text_regexp_info: np. ^[A-Z0-9]+$ +text_repository_usernames_mapping: "Wybierz lub uaktualnij przyporządkowanie użytkowników Redmine do użytkowników repozytorium.\nUżytkownicy z taką samą nazwą lub adresem email są przyporządkowani automatycznie." +text_rmagick_available: RMagick dostępne (opcjonalnie) +text_select_mail_notifications: Zaznacz czynności przy których użytkownik powinien być powiadomiony mailem. +text_select_project_modules: 'Wybierz moduły do aktywacji w tym projekcie:' +text_status_changed_by_changeset: Zastosowane w zmianach %s. +text_subprojects_destroy_warning: 'Podprojekt(y): %s zostaną także usunięte.' +text_tip_task_begin_day: zadanie zaczynające się dzisiaj +text_tip_task_begin_end_day: zadanie zaczynające i kończące się dzisiaj +text_tip_task_end_day: zadanie kończące się dzisiaj +text_tracker_no_workflow: Brak przepływu zefiniowanego dla tego typu zagadnienia +text_unallowed_characters: Niedozwolone znaki +text_user_mail_option: "W przypadku niezaznaczonych projektów, będziesz otrzymywał powiadomienia tylko na temat zagadnien, które obserwujesz, lub w których bierzesz udział (np. jesteś autorem lub adresatem)." +text_user_wrote: '%s napisał:' +text_wiki_destroy_confirmation: Jesteś pewien, że chcesz usunąć to wiki i całą jego zawartość ? +text_workflow_edit: Zaznacz rolę i typ zagadnienia do edycji przepływu + +label_user_activity: "Aktywność: %s" +label_updated_time_by: Uaktualnione przez %s %s temu +text_diff_truncated: '... Ten plik różnic został przycięty ponieważ jest zbyt długi.' +setting_diff_max_lines_displayed: Maksymalna liczba linii różnicy do pokazania +text_plugin_assets_writable: Zapisywalny katalog zasobów wtyczek +warning_attachments_not_saved: "%d file(s) could not be saved." +field_editable: Editable +label_display: Display +button_create_and_continue: Create and continue +text_custom_field_possible_values_info: 'One line for each value' +setting_repository_log_display_limit: Maximum number of revisions displayed on file log +field_identity_url: OpenID URL +setting_openid: Allow OpenID login and registration +label_login_with_open_id_option: or login with OpenID +field_watcher: Watcher diff --git a/lang/pt-br.yml b/lang/pt-br.yml index 74ee2486c..073c8e377 100644 --- a/lang/pt-br.yml +++ b/lang/pt-br.yml @@ -1,7 +1,7 @@ _gloc_rule_default: '|n| n==1 ? "" : "_plural" ' actionview_datehelper_select_day_prefix: -actionview_datehelper_select_month_names: Janeiro,Fevereiro,Março,Abrill,Maio,Junho,Julho,Agosto,Setembro,Outubro,Novembro,Dezembro +actionview_datehelper_select_month_names: Janeiro,Fevereiro,Março,Abril,Maio,Junho,Julho,Agosto,Setembro,Outubro,Novembro,Dezembro actionview_datehelper_select_month_names_abbr: Jan,Fev,Mar,Abr,Mai,Jun,Jul,Ago,Set,Out,Nov,Dez actionview_datehelper_select_month_prefix: actionview_datehelper_select_year_prefix: @@ -47,8 +47,8 @@ general_text_Yes: 'Sim' general_text_no: 'não' general_text_yes: 'sim' general_lang_name: 'Português(Brasil)' -general_csv_separator: ',' -general_csv_decimal_separator: '.' +general_csv_separator: ';' +general_csv_decimal_separator: ',' general_csv_encoding: ISO-8859-1 general_pdf_encoding: ISO-8859-1 general_day_names: Segunda,Terça,Quarta,Quinta,Sexta,Sábado,Domingo @@ -638,8 +638,73 @@ default_activity_development: Desenvolvimento enumeration_issue_priorities: Prioridade das tarefas enumeration_doc_categories: Categorias de documento enumeration_activities: Atividades (time tracking) -notice_unable_delete_version: Unable to delete version -label_renamed: renamed -label_copied: copied -setting_repositories_cache_directory: Cache directory for repositories -field_cache: Local cache +notice_unable_delete_version: Não foi possível excluir a versão +label_renamed: renomeado +label_copied: copiado +setting_plain_text_mail: texto plano apenas (sem HTML) +permission_view_files: Ver Arquivos +permission_edit_issues: Editar tickets +permission_edit_own_time_entries: Editar o próprio tempo de trabalho +permission_manage_public_queries: Gerenciar consultas publicas +permission_add_issues: Adicionar Tickets +permission_log_time: Adicionar tempo gasto +permission_view_changesets: Ver changesets +permission_view_time_entries: Ver tempo gasto +permission_manage_versions: Gerenciar versões +permission_manage_wiki: Gerenciar wiki +permission_manage_categories: Gerenciar categorias de tickets +permission_protect_wiki_pages: Proteger páginas wiki +permission_comment_news: Comentar notícias +permission_delete_messages: Excluir mensagens +permission_select_project_modules: Selecionar módulos de projeto +permission_manage_documents: Gerenciar documentos +permission_edit_wiki_pages: Editar páginas wiki +permission_add_issue_watchers: Adicionar monitores +permission_view_gantt: Ver gráfico gantt +permission_move_issues: Mover tickets +permission_manage_issue_relations: Gerenciar relacionamentos de tickets +permission_delete_wiki_pages: Excluir páginas wiki +permission_manage_boards: Gerenciar fóruns +permission_delete_wiki_pages_attachments: Excluir anexos +permission_view_wiki_edits: Ver histórico do wiki +permission_add_messages: Postar mensagens +permission_view_messages: Ver mensagens +permission_manage_files: Gerenciar arquivos +permission_edit_issue_notes: Editar notas +permission_manage_news: Gerenciar notícias +permission_view_calendar: Ver caneldário +permission_manage_members: Gerenciar membros +permission_edit_messages: Editar mensagens +permission_delete_issues: Excluir tickets +permission_view_issue_watchers: Ver lista de monitores +permission_manage_repository: Gerenciar repositório +permission_commit_access: Acesso de commit +permission_browse_repository: Pesquisar repositorio +permission_view_documents: Ver documentos +permission_edit_project: Editar projeto +permission_add_issue_notes: Adicionar notas +permission_save_queries: Salvar consultas +permission_view_wiki_pages: Ver wiki +permission_rename_wiki_pages: Renomear páginas wiki +permission_edit_time_entries: Editar tempo gasto +permission_edit_own_issue_notes: Editar próprias notas +setting_gravatar_enabled: Usar ícones do Gravatar +label_example: Exemplo +text_repository_usernames_mapping: "Seleciona ou atualiza os usuários do Redmine mapeando para cada usuário encontrado no log do repositório.\nUsuários com o mesmo login ou email no Redmine e no repositório serão mapeados automaticamente." +permission_edit_own_messages: Editar próprias mensagens +permission_delete_own_messages: Excluir próprias mensagens +label_user_activity: "Atividade de %s" +label_updated_time_by: Atualizado por %s à %s +text_diff_truncated: '... Este diff foi truncado porque excede o tamanho máximo que pode ser exibido.' +setting_diff_max_lines_displayed: Número máximo de linhas exibidas no diff +text_plugin_assets_writable: Diretório de plugins gravável +warning_attachments_not_saved: "%d arquivo(s) não puderam ser salvo(s)." +button_create_and_continue: Criar e continuar +text_custom_field_possible_values_info: 'Uma linha para cada valor' +label_display: Exibição +field_editable: Editável +setting_repository_log_display_limit: Número máximo de revisões exibidas no arquivo de log +field_identity_url: OpenID URL +setting_openid: Allow OpenID login and registration +label_login_with_open_id_option: or login with OpenID +field_watcher: Watcher diff --git a/lang/pt.yml b/lang/pt.yml index 98f13108b..7836f0fc6 100644 --- a/lang/pt.yml +++ b/lang/pt.yml @@ -1,3 +1,4 @@ +## Translated by: Pedro Araújo _gloc_rule_default: '|n| n==1 ? "" : "_plural" ' actionview_datehelper_select_day_prefix: @@ -7,9 +8,9 @@ actionview_datehelper_select_month_prefix: actionview_datehelper_select_year_prefix: actionview_datehelper_time_in_words_day: 1 dia actionview_datehelper_time_in_words_day_plural: %d dias -actionview_datehelper_time_in_words_hour_about: em torno de uma hora -actionview_datehelper_time_in_words_hour_about_plural: em torno de %d horas -actionview_datehelper_time_in_words_hour_about_single: em torno de uma hora +actionview_datehelper_time_in_words_hour_about: cerca de uma hora +actionview_datehelper_time_in_words_hour_about_plural: cerca de %d horas +actionview_datehelper_time_in_words_hour_about_single: cerca de uma hora actionview_datehelper_time_in_words_minute: 1 minuto actionview_datehelper_time_in_words_minute_half: meio minuto actionview_datehelper_time_in_words_minute_less_than: menos de um minuto @@ -22,19 +23,19 @@ actionview_instancetag_blank_option: Seleccione activerecord_error_inclusion: não existe na lista activerecord_error_exclusion: já existe na lista activerecord_error_invalid: é inválido -activerecord_error_confirmation: não está de acordo com sua confirmação -activerecord_error_accepted: deve ser aceite -activerecord_error_empty: não pode ser vazio +activerecord_error_confirmation: não está de acordo com a confirmação +activerecord_error_accepted: tem de ser aceite +activerecord_error_empty: não pode estar vazio activerecord_error_blank: não pode estar em branco -activerecord_error_too_long: é muito longo -activerecord_error_too_short: é muito curto -activerecord_error_wrong_length: possui o comprimento errado +activerecord_error_too_long: é demasiado longo +activerecord_error_too_short: é demasiado curto +activerecord_error_wrong_length: tem o comprimento errado activerecord_error_taken: já foi usado em outro registo activerecord_error_not_a_number: não é um número activerecord_error_not_a_date: não é uma data válida activerecord_error_greater_than_start_date: deve ser maior que a data inicial activerecord_error_not_same_project: não pertence ao mesmo projecto -activerecord_error_circular_dependency: Esta relação pode criar uma dependência circular +activerecord_error_circular_dependency: Esta relação iria criar uma dependência circular general_fmt_age: %d ano general_fmt_age_plural: %d anos @@ -47,40 +48,54 @@ general_text_Yes: 'Sim' general_text_no: 'não' general_text_yes: 'sim' general_lang_name: 'Português' -general_csv_separator: ',' -general_csv_decimal_separator: '.' -general_csv_encoding: ISO-8859-1 -general_pdf_encoding: ISO-8859-1 +general_csv_separator: ';' +general_csv_decimal_separator: ',' +general_csv_encoding: ISO-8859-15 +general_pdf_encoding: ISO-8859-15 general_day_names: Segunda,Terça,Quarta,Quinta,Sexta,Sábado,Domingo general_first_day_of_week: '1' -notice_account_updated: Conta actualizada com sucesso. +notice_account_updated: A conta foi actualizada com sucesso. notice_account_invalid_creditentials: Utilizador ou palavra-chave inválidos. -notice_account_password_updated: Palavra-chave foi alterada com sucesso. +notice_account_password_updated: A palavra-chave foi alterada com sucesso. notice_account_wrong_password: Palavra-chave errada. -notice_account_register_done: Conta criada com sucesso. +notice_account_register_done: A conta foi criada com sucesso. notice_account_unknown_email: Utilizador desconhecido. -notice_can_t_change_password: Esta conta utiliza autenticação externa. Não é possível alterar a palavra-chave. -notice_account_lost_email_sent: Foi enviado e-mail com as instruções para criar uma nova palavra-chave. -notice_account_activated: Conta foi activada. Pode ligar-se agora +notice_can_t_change_password: Esta conta utiliza uma fonte de autenticação externa. Não é possível alterar a palavra-chave. +notice_account_lost_email_sent: Foi-lhe enviado um e-mail com as instruções para escolher uma nova palavra-chave. +notice_account_activated: A sua conta foi activada. Já pode autenticar-se. notice_successful_create: Criado com sucesso. notice_successful_update: Alterado com sucesso. notice_successful_delete: Apagado com sucesso. notice_successful_connection: Ligado com sucesso. -notice_file_not_found: A página que está a tentar aceder não existe ou foi eliminada. +notice_file_not_found: A página que está a tentar aceder não existe ou foi removida. notice_locking_conflict: Os dados foram actualizados por outro utilizador. notice_not_authorized: Não está autorizado a visualizar esta página. notice_email_sent: Foi enviado um e-mail para %s notice_email_error: Ocorreu um erro ao enviar o e-mail (%s) -notice_feeds_access_key_reseted: A sua chave RSS foi inicializada. +notice_feeds_access_key_reseted: A sua chave de RSS foi inicializada. +notice_failed_to_save_issues: "Não foi possível guardar %d tarefa(s) das %d seleccionadas: %s." +notice_no_issue_selected: "Nenhuma tarefa seleccionada! Por favor, seleccione as tarefas que quer editar." +notice_account_pending: "A sua conta foi criada e está agora à espera de aprovação do administrador." +notice_default_data_loaded: Configuração padrão carregada com sucesso. +notice_unable_delete_version: Não foi possível apagar a versão. -error_scm_not_found: "A entrada e/ou a revisão não existem no repositório." -error_scm_command_failed: "Ocorreu um erro ao tentar aceder ao repositorio: %s" +error_can_t_load_default_data: "Não foi possível carregar a configuração padrão: %s" +error_scm_not_found: "A entrada ou revisão não foi encontrada no repositório." +error_scm_command_failed: "Ocorreu um erro ao tentar aceder ao repositório: %s" +error_scm_annotate: "A entrada não existe ou não pode ser anotada." +error_issue_not_found_in_project: 'A tarefa não foi encontrada ou não pertence a este projecto.' -mail_subject_lost_password: Palavra-chave do %s. -mail_body_lost_password: 'Para mudar a palavra-chave, clique no link abaixo:' -mail_subject_register: Activação de conta do %s. -mail_body_register: 'Para activar a conta, clique no link abaixo:' +mail_subject_lost_password: Palavra-chave de %s +mail_body_lost_password: 'Para mudar a sua palavra-chave, clique no link abaixo:' +mail_subject_register: Activação de conta de %s +mail_body_register: 'Para activar a sua conta, clique no link abaixo:' +mail_body_account_information_external: Pode utilizar a conta "%s" para autenticar-se. +mail_body_account_information: Informação da sua conta +mail_subject_account_activation_request: Pedido de activação da conta %s +mail_body_account_activation_request: 'Um novo utilizador (%s) registou-se. A sua conta está à espera de aprovação:' +mail_subject_reminder: "%d tarefa(s) para entregar nos próximos dias" +mail_body_reminder: "%d tarefa(s) que estão atribuídas a si estão agendadas para estarem completas nos próximos %d dias:" gui_validation_error: 1 erro gui_validation_error_plural: %d erros @@ -89,10 +104,10 @@ field_name: Nome field_description: Descrição field_summary: Sumário field_is_required: Obrigatório -field_firstname: Primeiro nome -field_lastname: Último nome +field_firstname: Nome +field_lastname: Apelido field_mail: E-mail -field_filename: Arquivo +field_filename: Ficheiro field_filesize: Tamanho field_downloads: Downloads field_author: Autor @@ -100,7 +115,7 @@ field_created_on: Criado field_updated_on: Alterado field_field_format: Formato field_is_for_all: Para todos os projectos -field_possible_values: Possíveis valores +field_possible_values: Valores possíveis field_regexp: Expressão regular field_min_length: Tamanho mínimo field_max_length: Tamanho máximo @@ -108,11 +123,11 @@ field_value: Valor field_category: Categoria field_title: Título field_project: Projecto -field_issue: Tarefa +field_issue: Tarefa field_status: Estado field_notes: Notas field_is_closed: Tarefa fechada -field_is_default: Estado padrão +field_is_default: Valor por omissão field_tracker: Tipo field_subject: Assunto field_due_date: Data final @@ -120,16 +135,16 @@ field_assigned_to: Atribuído a field_priority: Prioridade field_fixed_version: Versão field_user: Utilizador -field_role: Regra -field_homepage: Página inicial +field_role: Papel +field_homepage: Página field_is_public: Público -field_parent: Subprojecto de +field_parent: Sub-projecto de field_is_in_chlog: Tarefas mostradas no changelog field_is_in_roadmap: Tarefas mostradas no roadmap -field_login: Utilizador +field_login: Nome de utilizador field_mail_notification: Notificações por e-mail field_admin: Administrador -field_last_login_on: Último acesso +field_last_login_on: Última visita field_language: Língua field_effective_date: Data field_password: Palavra-chave @@ -142,12 +157,12 @@ field_port: Porta field_account: Conta field_base_dn: Base DN field_attr_login: Atributo utilizador -field_attr_firstname: Atributo primeiro nome +field_attr_firstname: Atributo nome próprio field_attr_lastname: Atributo último nome field_attr_mail: Atributo e-mail -field_onthefly: Criação de utilizadores sob demanda +field_onthefly: Criação de utilizadores na hora field_start_date: Início -field_done_ratio: %% Terminado +field_done_ratio: %% Completo field_auth_source: Modo de autenticação field_hide_mail: Esconder endereço de e-mail field_comments: Comentário @@ -161,31 +176,61 @@ field_identifier: Identificador field_is_filter: Usado como filtro field_issue_to_id: Tarefa relacionada field_delay: Atraso -field_assignable: As tarefas não podem ser associados a esta regra -field_redirect_existing_links: Redireccionar as hiperligações -field_estimated_hours: Estimativa de horas -field_default_value: Padrão +field_assignable: As tarefas podem ser associados a este papel +field_redirect_existing_links: Redireccionar links existentes +field_estimated_hours: Tempo estimado +field_column_names: Colunas +field_time_zone: Fuso horário +field_searchable: Procurável +field_default_value: Valor por omissão +field_comments_sorting: Mostrar comentários +field_parent_title: Página pai setting_app_title: Título da aplicação -setting_app_subtitle: Subtítulo da aplicação -setting_welcome_text: Texto de boas-vindas -setting_default_language: Linguagem padrão +setting_app_subtitle: Sub-título da aplicação +setting_welcome_text: Texto de boas vindas +setting_default_language: Língua por omissão setting_login_required: Autenticação obrigatória -setting_self_registration: Registro permitido +setting_self_registration: Auto-registo setting_attachment_max_size: Tamanho máximo do anexo setting_issues_export_limit: Limite de exportação das tarefas setting_mail_from: E-mail enviado de -setting_host_name: Servidor -setting_text_formatting: Formato do texto -setting_wiki_compression: Compactação do histórico do Wiki -setting_feeds_limit: Limite do Feed +setting_bcc_recipients: Recipientes de BCC +setting_host_name: Hostname +setting_text_formatting: Formatação do texto +setting_wiki_compression: Compressão do histórico do Wiki +setting_feeds_limit: Limite de conteúdo do feed +setting_default_projects_public: Projectos novos são públicos por omissão setting_autofetch_changesets: Buscar automaticamente commits setting_sys_api_enabled: Activar Web Service para gestão do repositório setting_commit_ref_keywords: Palavras-chave de referência -setting_commit_fix_keywords: Palavras-chave fixas -setting_autologin: Acesso automático +setting_commit_fix_keywords: Palavras-chave de fecho +setting_autologin: Login automático setting_date_format: Formato da data -setting_cross_project_issue_relations: Permitir relações de tarefas de projectos diferentes +setting_time_format: Formato do tempo +setting_cross_project_issue_relations: Permitir relações entre tarefas de projectos diferentes +setting_issue_list_default_columns: Colunas na lista de tarefas por omissão +setting_repositories_encodings: Encodings dos repositórios +setting_commit_logs_encoding: Encoding das mensagens de commit +setting_emails_footer: Rodapé do e-mails +setting_protocol: Protocolo +setting_per_page_options: Opções de objectos por página +setting_user_format: Formato de apresentaão de utilizadores +setting_activity_days_default: Dias mostrados na actividade do projecto +setting_display_subprojects_issues: Mostrar as tarefas dos sub-projectos nos projectos principais +setting_enabled_scm: Activar SCM +setting_mail_handler_api_enabled: Activar Web Service para e-mails recebidos +setting_mail_handler_api_key: Chave da API +setting_sequential_project_identifiers: Gerar identificadores de projecto sequênciais + +project_module_issue_tracking: Tarefas +project_module_time_tracking: Registo de tempo +project_module_news: Notícias +project_module_documents: Documentos +project_module_files: Ficheiros +project_module_wiki: Wiki +project_module_repository: Repositório +project_module_boards: Forum label_user: Utilizador label_user_plural: Utilizadores @@ -199,13 +244,17 @@ label_issue: Tarefa label_issue_new: Nova tarefa label_issue_plural: Tarefas label_issue_view_all: Ver todas as tarefas +label_issues_by: Tarefas por %s +label_issue_added: Tarefa adicionada +label_issue_updated: Tarefa actualizada label_document: Documento label_document_new: Novo documento label_document_plural: Documentos -label_role: Regra -label_role_plural: Regras -label_role_new: Nova regra -label_role_and_permissions: Regras e permissões +label_document_added: Documento adicionado +label_role: Papel +label_role_plural: Papéis +label_role_new: Novo papel +label_role_and_permissions: Papéis e permissões label_member: Membro label_member_new: Novo membro label_member_plural: Membros @@ -214,36 +263,37 @@ label_tracker_plural: Tipos label_tracker_new: Novo tipo label_workflow: Workflow label_issue_status: Estado da tarefa -label_issue_status_plural: Estado das tarefas +label_issue_status_plural: Estados da tarefa label_issue_status_new: Novo estado -label_issue_category: Categoria da tarefa -label_issue_category_plural: Categorias das tarefas +label_issue_category: Categoria de tarefa +label_issue_category_plural: Categorias de tarefa label_issue_category_new: Nova categoria label_custom_field: Campo personalizado label_custom_field_plural: Campos personalizados label_custom_field_new: Novo campo personalizado -label_enumerations: Enumeração +label_enumerations: Enumerações label_enumeration_new: Novo valor label_information: Informação label_information_plural: Informações -label_please_login: Efectuar acesso -label_register: Registe-se +label_please_login: Por favor autentique-se +label_register: Registar label_password_lost: Perdi a palavra-chave -label_home: Página inicial -label_my_page: Página pessoal +label_home: Página Inicial +label_my_page: Página Pessoal label_my_account: Minha conta label_my_projects: Meus projectos label_administration: Administração label_login: Entrar label_logout: Sair label_help: Ajuda -label_reported_issues: Tarefas reportadas -label_assigned_to_me_issues: Tarefas atribuídas +label_reported_issues: Tarefas criadas +label_assigned_to_me_issues: Tarefas atribuídas a mim label_last_login: Último acesso label_last_updates: Última alteração label_last_updates_plural: %d Últimas alterações label_registered_on: Registado em label_activity: Actividade +label_overall_activity: Actividade geral label_new: Novo label_logged_as: Ligado como label_environment: Ambiente @@ -251,11 +301,13 @@ label_authentication: Autenticação label_auth_source: Modo de autenticação label_auth_source_new: Novo modo de autenticação label_auth_source_plural: Modos de autenticação -label_subproject_plural: Subprojectos -label_min_max_length: Tamanho min-max +label_subproject_plural: Sub-projectos +label_and_its_subprojects: %s e sub-projectos +label_min_max_length: Tamanho mínimo-máximo label_list: Lista label_date: Data label_integer: Inteiro +label_float: Decimal label_boolean: Booleano label_string: Texto label_text: Texto longo @@ -266,37 +318,40 @@ label_download_plural: %d Downloads label_no_data: Sem dados para mostrar label_change_status: Mudar estado label_history: Histórico -label_attachment: Arquivo -label_attachment_new: Novo arquivo -label_attachment_delete: Apagar arquivo -label_attachment_plural: Arquivos +label_attachment: Ficheiro +label_attachment_new: Novo ficheiro +label_attachment_delete: Apagar ficheiro +label_attachment_plural: Ficheiros +label_file_added: Ficheiro adicionado label_report: Relatório -label_report_plural: Relatório -label_news: Notícias -label_news_new: Adicionar notícias +label_report_plural: Relatórios +label_news: Notícia +label_news_new: Nova notícia label_news_plural: Notícias label_news_latest: Últimas notícias label_news_view_all: Ver todas as notícias -label_change_log: Log de mudanças +label_news_added: Notícia adicionada +label_change_log: Change log label_settings: Configurações label_overview: Visão geral label_version: Versão label_version_new: Nova versão label_version_plural: Versões label_confirmation: Confirmação -label_export_to: Exportar para +label_export_to: 'Também disponível em:' label_read: Ler... label_public_projects: Projectos públicos -label_open_issues: Aberto -label_open_issues_plural: Abertos -label_closed_issues: Fechado -label_closed_issues_plural: Fechados +label_open_issues: aberto +label_open_issues_plural: abertos +label_closed_issues: fechado +label_closed_issues_plural: fechados label_total: Total label_permissions: Permissões label_current_status: Estado actual -label_new_statuses_allowed: Novo estado permitido +label_new_statuses_allowed: Novos estados permitidos label_all: todos label_none: nenhum +label_nobody: ninguém label_next: Próximo label_previous: Anterior label_used_by: Usado por @@ -304,65 +359,77 @@ label_details: Detalhes label_add_note: Adicionar nota label_per_page: Por página label_calendar: Calendário -label_months_from: Meses de +label_months_from: meses de label_gantt: Gantt label_internal: Interno -label_last_changes: últimas %d mudanças -label_change_view_all: Mostrar todas as mudanças -label_personalize_page: Personalizar página +label_last_changes: últimas %d alterações +label_change_view_all: Ver todas as alterações +label_personalize_page: Personalizar esta página label_comment: Comentário label_comment_plural: Comentários label_comment_add: Adicionar comentário label_comment_added: Comentário adicionado -label_comment_delete: Apagar comentário +label_comment_delete: Apagar comentários label_query: Consulta personalizada label_query_plural: Consultas personalizadas label_query_new: Nova consulta label_filter_add: Adicionar filtro label_filter_plural: Filtros label_equals: é -label_not_equals: não e -label_in_less_than: é maior que -label_in_more_than: é menor que +label_not_equals: não é +label_in_less_than: em menos de +label_in_more_than: em mais de label_in: em label_today: hoje +label_all_time: sempre +label_yesterday: ontem label_this_week: esta semana -label_less_than_ago: faz menos de -label_more_than_ago: faz mais de +label_last_week: semana passada +label_last_n_days: últimos %d dias +label_this_month: este mês +label_last_month: mês passado +label_this_year: este ano +label_date_range: Date range +label_less_than_ago: menos de dias atrás +label_more_than_ago: mais de dias atrás label_ago: dias atrás label_contains: contém label_not_contains: não contém label_day_plural: dias label_repository: Repositório -label_browse: Procurar -label_modification: %d mudança -label_modification_plural: %d mudanças +label_repository_plural: Repositórios +label_browse: Navegar +label_modification: %d alteração +label_modification_plural: %d alterações label_revision: Revisão label_revision_plural: Revisões +label_associated_revisions: Revisões associadas label_added: adicionado label_modified: modificado +label_copied: copiado +label_renamed: renomeado label_deleted: apagado label_latest_revision: Última revisão label_latest_revision_plural: Últimas revisões label_view_revisions: Ver revisões label_max_size: Tamanho máximo -label_on: em +label_on: 'em' label_sort_highest: Mover para o início label_sort_higher: Mover para cima label_sort_lower: Mover para baixo label_sort_lowest: Mover para o fim label_roadmap: Roadmap -label_roadmap_due_in: Termina em -label_roadmap_overdue: %s atrasado -label_roadmap_no_issues: Sem tarefas para essa versão +label_roadmap_due_in: Termina em %s +label_roadmap_overdue: Atrasado %s +label_roadmap_no_issues: Sem tarefas para esta versão label_search: Procurar label_result_plural: Resultados label_all_words: Todas as palavras label_wiki: Wiki -label_wiki_edit: Editar Wiki -label_wiki_edit_plural: Editar Wiki's -label_wiki_page: Página de Wiki -label_wiki_page_plural: Páginas de Wiki +label_wiki_edit: Edição da Wiki +label_wiki_edit_plural: Edições da Wiki +label_wiki_page: Página da Wiki +label_wiki_page_plural: Páginas da Wiki label_index_by_title: Índice por título label_index_by_date: Índice por data label_current_version: Versão actual @@ -373,7 +440,7 @@ label_issue_tracking: Tarefas label_spent_time: Tempo gasto label_f_hour: %.2f hora label_f_hour_plural: %.2f horas -label_time_tracking: Tempo trabalhado +label_time_tracking: Registo de tempo label_change_plural: Mudanças label_statistics: Estatísticas label_commits_per_month: Commits por mês @@ -385,59 +452,94 @@ label_options: Opções label_copy_workflow_from: Copiar workflow de label_permissions_report: Relatório de permissões label_watched_issues: Tarefas observadas -label_related_issues: tarefas relacionadas +label_related_issues: Tarefas relacionadas label_applied_status: Estado aplicado -label_loading: Carregando... +label_loading: A carregar... label_relation_new: Nova relação label_relation_delete: Apagar relação -label_relates_to: relacionado à -label_duplicates: duplicadas -label_blocks: bloqueios +label_relates_to: relacionado a +label_duplicates: duplica +label_duplicated_by: duplicado por +label_blocks: bloqueia label_blocked_by: bloqueado por -label_precedes: procede +label_precedes: precede label_follows: segue -label_end_to_start: fim ao início -label_end_to_end: fim ao fim -label_start_to_start: início ao início -label_start_to_end: início ao fim +label_end_to_start: fim a início +label_end_to_end: fim a fim +label_start_to_start: início a início +label_start_to_end: início a fim label_stay_logged_in: Guardar sessão -label_disabled: desactivar -label_show_completed_versions: Ver as versões completas -label_me: Eu +label_disabled: desactivado +label_show_completed_versions: Mostrar versões acabadas +label_me: eu label_board: Forum label_board_new: Novo forum -label_board_plural: Foruns -label_topic_plural: Topicos +label_board_plural: Forums +label_topic_plural: Tópicos label_message_plural: Mensagens -label_message_last: Ultima mensagem +label_message_last: Última mensagem label_message_new: Nova mensagem +label_message_posted: Mensagem adicionada label_reply_plural: Respostas label_send_information: Enviar dados da conta para o utilizador label_year: Ano -label_month: Mês +label_month: mês label_week: Semana label_date_from: De label_date_to: Para -label_language_based: Baseado na língua +label_language_based: Baseado na língua do utilizador label_sort_by: Ordenar por %s -label_send_test_email: Enviar e-mail de teste -label_feeds_access_key_created_on: Chave RSS criada à %s atrás +label_send_test_email: enviar um e-mail de teste +label_feeds_access_key_created_on: Chave RSS criada há %s atrás label_module_plural: Módulos -label_added_time_by: Adicionado por %s %s atrás -label_updated_time: Actualizado %s atrás +label_added_time_by: Adicionado por %s há %s atrás +label_updated_time: Alterado há %s atrás label_jump_to_a_project: Ir para o projecto... +label_file_plural: Ficheiros +label_changeset_plural: Changesets +label_default_columns: Colunas por omissão +label_no_change_option: (sem alteração) +label_bulk_edit_selected_issues: Editar tarefas seleccionadas em conjunto +label_theme: Tema +label_default: Padrão +label_search_titles_only: Procurar apenas em títulos +label_user_mail_option_all: "Para qualquer evento em todos os meus projectos" +label_user_mail_option_selected: "Para qualquer evento apenas nos projectos seleccionados..." +label_user_mail_option_none: "Apenas para coisas que esteja a observar ou esteja envolvido" +label_user_mail_no_self_notified: "Não quero ser notificado de alterações feitas por mim" +label_registration_activation_by_email: Activação da conta por e-mail +label_registration_manual_activation: Activação manual da conta +label_registration_automatic_activation: Activação automática da conta +label_display_per_page: 'Por página: %s' +label_age: Idade +label_change_properties: Mudar propriedades +label_general: Geral +label_more: Mais +label_scm: SCM +label_plugins: Extensões +label_ldap_authentication: Autenticação LDAP +label_downloads_abbr: D/L +label_optional_description: Descrição opcional +label_add_another_file: Adicionar outro ficheiro +label_preferences: Preferências +label_chronological_order: Em ordem cronológica +label_reverse_chronological_order: Em ordem cronológica inversa +label_planning: Planeamento +label_incoming_emails: E-mails a chegar +label_generate_key: Gerar uma chave +label_issue_watchers: Observadores button_login: Entrar -button_submit: Enviar +button_submit: Submeter button_save: Guardar -button_check_all: Marcar todos -button_uncheck_all: Desmarcar todos +button_check_all: Marcar tudo +button_uncheck_all: Desmarcar tudo button_delete: Apagar button_create: Criar button_test: Testar button_edit: Editar button_add: Adicionar -button_change: Mudar +button_change: Alterar button_apply: Aplicar button_clear: Limpar button_lock: Bloquear @@ -453,192 +555,157 @@ button_sort: Ordenar button_log_time: Tempo de trabalho button_rollback: Voltar para esta versão button_watch: Observar -button_unwatch: Não observar +button_unwatch: Deixar de observar button_reply: Responder button_archive: Arquivar button_unarchive: Desarquivar button_reset: Reinicializar button_rename: Renomear +button_change_password: Mudar palavra-chave +button_copy: Copiar +button_annotate: Anotar +button_update: Actualizar +button_configure: Configurar +button_quote: Citar status_active: activo -status_registered: registrado +status_registered: registado status_locked: bloqueado -text_select_mail_notifications: Seleccionar as acções que originam uma notificação por e-mail +text_select_mail_notifications: Seleccionar as acções que originam uma notificação por e-mail. text_regexp_info: ex. ^[A-Z0-9]+$ text_min_max_length_info: 0 siginifica sem restrição -text_project_destroy_confirmation: Você tem certeza que deseja apagar este projecto e todos os dados relacionados? -text_workflow_edit: Seleccione uma regra e um tipo de tarefa para editar o workflow -text_are_you_sure: Você tem certeza? -text_journal_changed: alterado de %s para %s -text_journal_set_to: alterar para %s +text_project_destroy_confirmation: Tem a certeza que deseja apagar o projecto e todos os dados relacionados? +text_subprojects_destroy_warning: 'O(s) seu(s) sub-projecto(s): %s também será/serão apagado(s).' +text_workflow_edit: Seleccione um papel e um tipo de tarefa para editar o workflow +text_are_you_sure: Tem a certeza? +text_journal_changed: mudado de %s para %s +text_journal_set_to: alterado para %s text_journal_deleted: apagado -text_tip_task_begin_day: tarefa começa neste dia -text_tip_task_end_day: tarefa termina neste dia -text_tip_task_begin_end_day: tarefa começa e termina neste dia -text_project_identifier_info: 'Letras minúsculas (a-z), números e traços permitido.
    Uma vez gravado, o identificador nao pode ser mudado.' -text_caracters_maximum: %d máximo de caracteres -text_length_between: Tamanho entre %d e %d caracteres. -text_tracker_no_workflow: Sem workflow definido para este tipo. +text_tip_task_begin_day: tarefa a começar neste dia +text_tip_task_end_day: tarefa a acabar neste dia +text_tip_task_begin_end_day: tarefa a começar e acabar neste dia +text_project_identifier_info: 'Apenas são permitidos letras minúsculas (a-z), números e hífens.
    Uma vez guardado, o identificador não poderá ser alterado.' +text_caracters_maximum: máximo %d caracteres. +text_caracters_minimum: Deve ter pelo menos %d caracteres. +text_length_between: Deve ter entre %d e %d caracteres. +text_tracker_no_workflow: Sem workflow definido para este tipo de tarefa. text_unallowed_characters: Caracteres não permitidos text_comma_separated: Permitidos múltiplos valores (separados por vírgula). -text_issues_ref_in_commit_messages: Referenciando e arrumando tarefas nas mensagens de commit -text_issue_added: Tarefa %s foi incluída (by %s). -text_issue_updated: Tarefa %s foi alterada (by %s). -text_wiki_destroy_confirmation: Tem certeza que quer apagar esta página de wiki e todo o conteudo relacionado? -text_issue_category_destroy_question: Existem tarefas (%d) associadas a esta categoria. Seleccione uma opção? -text_issue_category_destroy_assignments: Remover as relações com a categoria -text_issue_category_reassign_to: Re-associar as tarefas á categoria +text_issues_ref_in_commit_messages: Referenciando e fechando tarefas em mensagens de commit +text_issue_added: Tarefa %s foi criada por %s. +text_issue_updated: Tarefa %s foi actualizada por %s. +text_wiki_destroy_confirmation: Tem a certeza que deseja apagar este wiki e todo o seu conteúdo? +text_issue_category_destroy_question: Algumas tarefas (%d) estão atribuídas a esta categoria. O que quer fazer? +text_issue_category_destroy_assignments: Remover as atribuições à categoria +text_issue_category_reassign_to: Re-atribuir as tarefas para esta categoria +text_user_mail_option: "Para projectos não seleccionados, apenas receberá notificações acerca de coisas que está a observar ou está envolvido (ex. tarefas das quais foi o criador ou lhes foram atribuídas)." +text_no_configuration_data: "Papeis, tipos de tarefas, estados das tarefas e workflows ainda não foram configurados.\nÉ extremamente recomendado carregar as configurações padrão. Será capaz de as modificar depois de estarem carregadas." +text_load_default_configuration: Carregar as configurações padrão +text_status_changed_by_changeset: Aplicado no changeset %s. +text_issues_destroy_confirmation: 'Tem a certeza que deseja apagar a(s) tarefa(s) seleccionada(s)?' +text_select_project_modules: 'Seleccione os módulos a activar para este projecto:' +text_default_administrator_account_changed: Conta default de administrador alterada. +text_file_repository_writable: Repositório de ficheiros com permissões de escrita +text_rmagick_available: RMagick disponível (opcional) +text_destroy_time_entries_question: %.02f horas de trabalho foram atribuídas a estas tarefas que vai apagar. O que deseja fazer? +text_destroy_time_entries: Apagar as horas +text_assign_time_entries_to_project: Atribuir as horas ao projecto +text_reassign_time_entries: 'Re-atribuir as horas para esta tarefa:' +text_user_wrote: '%s escreveu:' +text_enumeration_destroy_question: '%d objectos estão atribuídos a este valor.' +text_enumeration_category_reassign_to: 'Re-atribuí-los para este valor:' +text_email_delivery_not_configured: "Entrega por e-mail não está configurada, e as notificação estão desactivadas.\nConfigure o seu servidor de SMTP em config/email.yml e reinicie a aplicação para activar estas funcionalidades." -default_role_manager: Gestor de Projecto -default_role_developper: Desenvolvedor -default_role_reporter: Analista de Suporte +default_role_manager: Gestor +default_role_developper: Programador +default_role_reporter: Repórter default_tracker_bug: Bug -default_tracker_feature: Implementação +default_tracker_feature: Funcionalidade default_tracker_support: Suporte default_issue_status_new: Novo default_issue_status_assigned: Atribuído default_issue_status_resolved: Resolvido -default_issue_status_feedback: Comentário +default_issue_status_feedback: Feedback default_issue_status_closed: Fechado default_issue_status_rejected: Rejeitado -default_doc_category_user: Documentação do utilizador +default_doc_category_user: Documentação de utilizador default_doc_category_tech: Documentação técnica -default_priority_low: Baixo +default_priority_low: Baixa default_priority_normal: Normal -default_priority_high: Alto +default_priority_high: Alta default_priority_urgent: Urgente -default_priority_immediate: Imediato -default_activity_design: Desenho +default_priority_immediate: Imediata +default_activity_design: Planeamento default_activity_development: Desenvolvimento -enumeration_issue_priorities: Prioridade das tarefas -enumeration_doc_categories: Categorias de documento -enumeration_activities: Actividades (time tracking) -label_file_plural: Arquivos -label_changeset_plural: Alterações -field_column_names: Colunas -label_default_columns: Valores por defeito das colunas -setting_issue_list_default_columns: Colunas listadas nas tarefas por defeito -setting_repositories_encodings: Codificação dos repositórios -notice_no_issue_selected: "Nenhuma tarefa seleccionada! Por favor, selecione uma tarefa para editar." -label_bulk_edit_selected_issues: Edição em massa das tarefas seleccionadas -label_no_change_option: (Sem alterações) -notice_failed_to_save_issues: "Erro ao gravar %d tarefa(s) no %d seleccionado: %s." -label_theme: Tema -label_default: Padrão -label_search_titles_only: Procurar apenas nos títulos -label_nobody: desconhecido -button_change_password: Alterar palavra-chave -text_user_mail_option: "Para os projectos não seleccionados, irá receber e-mails de notificação apenas de eventos que esteja a observar ou envolvido (isto é, tarefas que é autor ou que estão atribuidas a si)." -label_user_mail_option_selected: "Qualquer evento que ocorra nos projectos selecionados apenas..." -label_user_mail_option_all: "Todos eventos em todos os projectos" -label_user_mail_option_none: "Apenas eventos que sou observador ou que estou envolvido" -setting_emails_footer: Rodapé do e-mail -label_float: Float -button_copy: Copiar -mail_body_account_information_external: Pode utilizar a sua conta "%s" para entrar. -mail_body_account_information: Informação da sua conta de acesso -setting_protocol: Protocolo -label_user_mail_no_self_notified: "Não quero ser notificado de alterações efectuadas por mim" -setting_time_format: Formato da hora -label_registration_activation_by_email: Activação de conta de acesso por e-mail -mail_subject_account_activation_request: %s pedido de activação de conta de acesso -mail_body_account_activation_request: 'Novo utilizador (%s) registado. Conta de acesso pendente a aguardar validação:' -label_registration_automatic_activation: Activação de conta de acesso automático -label_registration_manual_activation: activação de conta de acesso manual -notice_account_pending: "Conta de acesso criada, mas pendente para validação do administrador" -field_time_zone: Fuso horário -text_caracters_minimum: Tem que ter no minimo %d caracteres. -setting_bcc_recipients: Esconder endereços destinos de e-mail (bcc) -button_annotate: Anotar -label_issues_by: tarefas por %s -field_searchable: Pesquisável -label_display_per_page: 'Por página: %s' -setting_per_page_options: Objects per page options -label_age: Idade -notice_default_data_loaded: Configuração inicial por defeito carregada. -text_load_default_configuration: Inserir configuração por defeito inicial -text_no_configuration_data: "Regras, trackers, estado das tarefas e workflow ainda não foram configurados.\nÉ recomendado que carregue a configuração por defeito. Posteriormente poderá alterar a configuração carregada." -error_can_t_load_default_data: "Configuração inical por defeito não pode ser carregada: %s" -button_update: Actualizar -label_change_properties: Alterar propriedades -label_general: Geral -label_repository_plural: Repositórios -label_associated_revisions: Versões associadas -setting_user_format: Formato para visualizar o utilizador -text_status_changed_by_changeset: Applied in changeset %s. -label_more: mais -text_issues_destroy_confirmation: 'Tem certeza que deseja apagar as tarefa(s) seleccionada(s)?' -label_scm: SCM -text_select_project_modules: 'Seleccione o(s) modulo(s) que deseja activar para o projecto:' -label_issue_added: Tarefa adicionada -label_issue_updated: Tarefa alterada -label_document_added: Documento adicionado -label_message_posted: Mensagem adicionada -label_file_added: Arquivo adicionado -label_news_added: Noticia adicionada -project_module_boards: Boards -project_module_issue_tracking: Tracking de tarefas -project_module_wiki: Wiki -project_module_files: Ficheiros -project_module_documents: Documentos -project_module_repository: Repositório -project_module_news: Noticias -project_module_time_tracking: Time tracking -text_file_repository_writable: Repositório de ficheiros com permissões de escrita -text_default_administrator_account_changed: Dados da conta de administrador padrão alterados -text_rmagick_available: RMagick disponível (opcional) -button_configure: Configurar -label_plugins: Plugins -label_ldap_authentication: autenticação por LDAP -label_downloads_abbr: D/L -label_this_month: este mês -label_last_n_days: últimos %d dias -label_all_time: todo o tempo -label_this_year: este ano -label_date_range: intervalo de datas -label_last_week: ultima semana -label_yesterday: ontem -label_last_month: último mês -label_add_another_file: Adicionar outro ficheiro -label_optional_description: Descrição opcional -text_destroy_time_entries_question: %.02f horas reportadas nesta tarefa. Estas horas serão eliminada. Continuar? -error_issue_not_found_in_project: 'Esta tarefa não foi encontrada ou não pertence a este projecto' -text_assign_time_entries_to_project: Associar as horas reportadas ao projecto -text_destroy_time_entries: Apagar as horas reportadas -text_reassign_time_entries: 'Re-associar as horas reportadas a esta tarefa:' -setting_activity_days_default: dias visualizados da actividade do projecto -label_chronological_order: Ordem cronológica -field_comments_sorting: Apresentar comentários -label_reverse_chronological_order: Ordem cronológica inversa -label_preferences: Preferências -setting_display_subprojects_issues: Ver tarefas dos subprojectos no projecto principal por defeito -label_overall_activity: Ver todas as actividades -setting_default_projects_public: Novos projectos são classificados como publicos por defeito -error_scm_annotate: "Esta entrada não existe ou não pode ser alterada." -label_planning: Plano -text_subprojects_destroy_warning: 'O(s) subprojecto(s): %s serão tambem apagados.' -label_and_its_subprojects: %s e os subprojectos -mail_body_reminder: "%d tarefa(s) que estão associadas a si e que tem de ser feitas nos próximos %d dias:" -mail_subject_reminder: "%d tarefa(s) para fazer nos próximos dias" -text_user_wrote: '%s escreveu:' -label_duplicated_by: duplicado por -setting_enabled_scm: Activar SCM -text_enumeration_category_reassign_to: 're-associar a este valor:' -text_enumeration_destroy_question: '%d objectos estão associados com este valor.' -label_incoming_emails: Receber e-mails -label_generate_key: Gerar uma chave -setting_mail_handler_api_enabled: Activar Serviço Web para as receber mensagens de e-mail -setting_mail_handler_api_key: Chave da API -text_email_delivery_not_configured: "Servidor de e-mail por configurar e notificações inactivas.\nConfigure o servidor de e-mail (SMTP) no ficheiro config/email.yml e re-inicie a aplicação." -field_parent_title: Página origem -label_issue_watchers: Observadores -setting_commit_logs_encoding: Guardar codificação das mensagens de log -button_quote: Comentário -setting_sequential_project_identifiers: Gerar identificador sequencial -notice_unable_delete_version: Impossível apagar esta versão -label_renamed: renomeado -label_copied: copiado -field_cache: Local cache -setting_repositories_cache_directory: Cache directory for repositories +enumeration_issue_priorities: Prioridade de tarefas +enumeration_doc_categories: Categorias de documentos +enumeration_activities: Actividades (Registo de tempo) +setting_plain_text_mail: Apenas texto simples (sem HTML) +permission_view_files: Ver ficheiros +permission_edit_issues: Editar tarefas +permission_edit_own_time_entries: Editar horas pessoais +permission_manage_public_queries: Gerir queries públicas +permission_add_issues: Adicionar tarefas +permission_log_time: Registar tempo gasto +permission_view_changesets: Ver changesets +permission_view_time_entries: Ver tempo gasto +permission_manage_versions: Gerir versões +permission_manage_wiki: Gerir wiki +permission_manage_categories: Gerir categorias de tarefas +permission_protect_wiki_pages: Proteger páginas de wiki +permission_comment_news: Comentar notícias +permission_delete_messages: Apagar mensagens +permission_select_project_modules: Seleccionar módulos do projecto +permission_manage_documents: Gerir documentos +permission_edit_wiki_pages: Editar páginas de wiki +permission_add_issue_watchers: Adicionar observadores +permission_view_gantt: ver diagrama de Gantt +permission_move_issues: Mover tarefas +permission_manage_issue_relations: Gerir relações de tarefas +permission_delete_wiki_pages: Apagar páginas de wiki +permission_manage_boards: Gerir forums +permission_delete_wiki_pages_attachments: Apagar anexos +permission_view_wiki_edits: Ver histórico da wiki +permission_add_messages: Submeter mensagens +permission_view_messages: Ver mensagens +permission_manage_files: Gerir ficheiros +permission_edit_issue_notes: Editar notas de tarefas +permission_manage_news: Gerir notícias +permission_view_calendar: Ver calendário +permission_manage_members: Gerir membros +permission_edit_messages: Editar mensagens +permission_delete_issues: Apagar tarefas +permission_view_issue_watchers: Ver lista de observadores +permission_manage_repository: Gerir repositório +permission_commit_access: Acesso a submissão +permission_browse_repository: Navegar em repositório +permission_view_documents: Ver documentos +permission_edit_project: Editar projecto +permission_add_issue_notes: Adicionar notas a tarefas +permission_save_queries: Guardar queries +permission_view_wiki_pages: Ver wiki +permission_rename_wiki_pages: Renomear páginas de wiki +permission_edit_time_entries: Editar entradas de tempo +permission_edit_own_issue_notes: Editar as prórpias notas +setting_gravatar_enabled: Utilizar icons Gravatar +label_example: Exemplo +text_repository_usernames_mapping: "Seleccionar ou actualizar o utilizador de Redmine mapeado a cada nome de utilizador encontrado no repositório.\nUtilizadores com o mesmo nome de utilizador ou email no Redmine e no repositório são mapeados automaticamente." +permission_edit_own_messages: Editar as próprias mensagens +permission_delete_own_messages: Apagar as próprias mensagens +label_user_activity: "Actividade de %s" +label_updated_time_by: Actualizado por %s há %s +text_diff_truncated: '... Este diff foi truncado porque excede o tamanho máximo que pode ser mostrado.' +setting_diff_max_lines_displayed: Número máximo de linhas de diff mostradas +text_plugin_assets_writable: Plugin assets directory writable +warning_attachments_not_saved: "%d file(s) could not be saved." +button_create_and_continue: Create and continue +text_custom_field_possible_values_info: 'One line for each value' +label_display: Display +field_editable: Editable +setting_repository_log_display_limit: Maximum number of revisions displayed on file log +field_identity_url: OpenID URL +setting_openid: Allow OpenID login and registration +label_login_with_open_id_option: or login with OpenID +field_watcher: Watcher diff --git a/lang/ro.yml b/lang/ro.yml index 1f399989c..ac06ccda5 100644 --- a/lang/ro.yml +++ b/lang/ro.yml @@ -640,5 +640,70 @@ setting_sequential_project_identifiers: Generate sequential project identifiers notice_unable_delete_version: Unable to delete version label_renamed: renamed label_copied: copied -setting_repositories_cache_directory: Cache directory for repositories -field_cache: Local cache +setting_plain_text_mail: plain text only (no HTML) +permission_view_files: View files +permission_edit_issues: Edit issues +permission_edit_own_time_entries: Edit own time logs +permission_manage_public_queries: Manage public queries +permission_add_issues: Add issues +permission_log_time: Log spent time +permission_view_changesets: View changesets +permission_view_time_entries: View spent time +permission_manage_versions: Manage versions +permission_manage_wiki: Manage wiki +permission_manage_categories: Manage issue categories +permission_protect_wiki_pages: Protect wiki pages +permission_comment_news: Comment news +permission_delete_messages: Delete messages +permission_select_project_modules: Select project modules +permission_manage_documents: Manage documents +permission_edit_wiki_pages: Edit wiki pages +permission_add_issue_watchers: Add watchers +permission_view_gantt: View gantt chart +permission_move_issues: Move issues +permission_manage_issue_relations: Manage issue relations +permission_delete_wiki_pages: Delete wiki pages +permission_manage_boards: Manage boards +permission_delete_wiki_pages_attachments: Delete attachments +permission_view_wiki_edits: View wiki history +permission_add_messages: Post messages +permission_view_messages: View messages +permission_manage_files: Manage files +permission_edit_issue_notes: Edit notes +permission_manage_news: Manage news +permission_view_calendar: View calendrier +permission_manage_members: Manage members +permission_edit_messages: Edit messages +permission_delete_issues: Delete issues +permission_view_issue_watchers: View watchers list +permission_manage_repository: Manage repository +permission_commit_access: Commit access +permission_browse_repository: Browse repository +permission_view_documents: View documents +permission_edit_project: Edit project +permission_add_issue_notes: Add notes +permission_save_queries: Save queries +permission_view_wiki_pages: View wiki +permission_rename_wiki_pages: Rename wiki pages +permission_edit_time_entries: Edit time logs +permission_edit_own_issue_notes: Edit own notes +setting_gravatar_enabled: Use Gravatar user icons +label_example: Example +text_repository_usernames_mapping: "Select ou update the Redmine user mapped to each username found in the repository log.\nUsers with the same Redmine and repository username or email are automatically mapped." +permission_edit_own_messages: Edit own messages +permission_delete_own_messages: Delete own messages +label_user_activity: "%s's activity" +label_updated_time_by: Updated by %s %s ago +text_diff_truncated: '... This diff was truncated because it exceeds the maximum size that can be displayed.' +setting_diff_max_lines_displayed: Max number of diff lines displayed +text_plugin_assets_writable: Plugin assets directory writable +warning_attachments_not_saved: "%d file(s) could not be saved." +button_create_and_continue: Create and continue +text_custom_field_possible_values_info: 'One line for each value' +label_display: Display +field_editable: Editable +setting_repository_log_display_limit: Maximum number of revisions displayed on file log +field_identity_url: OpenID URL +setting_openid: Allow OpenID login and registration +label_login_with_open_id_option: or login with OpenID +field_watcher: Watcher diff --git a/lang/ru.yml b/lang/ru.yml index bcc7121b2..87be71e2c 100644 --- a/lang/ru.yml +++ b/lang/ru.yml @@ -13,7 +13,7 @@ actionview_datehelper_time_in_words_hour_about_plural2: около %d часов actionview_datehelper_time_in_words_hour_about_plural5: около %d часов actionview_datehelper_time_in_words_hour_about_plural: около %d часов actionview_datehelper_time_in_words_hour_about_single: около часа -actionview_datehelper_time_in_words_hour_about: около часа +actionview_datehelper_time_in_words_hour_about: около %d часа actionview_datehelper_time_in_words_minute: 1 минута actionview_datehelper_time_in_words_minute_half: полминуты actionview_datehelper_time_in_words_minute_less_than: менее минуты @@ -322,6 +322,7 @@ label_enumeration_new: Новое значение label_enumerations: Справочники label_environment: Окружение label_equals: соответствует +label_example: Пример label_export_to: Экспортировать в label_feed_plural: Вводы label_feeds_access_key_created_on: Ключ доступа RSS создан %s назад @@ -517,8 +518,10 @@ label_total: Всего label_tracker_new: Новый трекер label_tracker_plural: Трекеры label_tracker: Трекер -label_updated_time: Обновлен %s назад +label_updated_time: Обновлено %s назад +label_updated_time_by: Обновлено %s %s назад label_used_by: Используется +label_user_activity: "Активность пользователя %s" label_user_mail_no_self_notified: "Не извещать об изменениях, которые я сделал сам" label_user_mail_option_all: "О всех событиях во всех моих проектах" label_user_mail_option_none: "Только о тех событиях, которые я отслеживаю или в которых я участвую" @@ -578,6 +581,55 @@ notice_successful_delete: Удаление успешно завершено. notice_successful_update: Обновление успешно завершено. notice_unable_delete_version: Невозможно удалить версию. +permission_view_files: Просмотр файлов +permission_edit_issues: Редактирование задач +permission_edit_own_time_entries: Редактирование собственного учета времени +permission_manage_public_queries: Управление общими запросами +permission_add_issues: Добавление задач +permission_log_time: Учет затраченного времени +permission_view_changesets: Просмотр изменений хранилища +permission_view_time_entries: Просмотр затраченного времени +permission_manage_versions: Управление версиями +permission_manage_wiki: Управление wiki +permission_manage_categories: Управление категориями задач +permission_protect_wiki_pages: Блокирование страниц wiki +permission_comment_news: Комментирование новостей +permission_delete_messages: Удаление сообщений +permission_select_project_modules: Выбор модулей проекта +permission_manage_documents: Управление документами +permission_edit_wiki_pages: Редактирование страниц wiki +permission_add_issue_watchers: Добавление наблюдателей +permission_view_gantt: Просмотр диаграммы Ганта +permission_move_issues: Перенос задач +permission_manage_issue_relations: Управление связыванием задач +permission_delete_wiki_pages: Удаление страниц wiki +permission_manage_boards: Управление форумами +permission_delete_wiki_pages_attachments: Удаление прикрепленных файлов +permission_view_wiki_edits: Просмотр истории wiki +permission_add_messages: Отправка сообщений +permission_view_messages: Просмотр сообщение +permission_manage_files: Управление файлами +permission_edit_issue_notes: Редактирование примечаний +permission_manage_news: Управление новостями +permission_view_calendar: Просмотр календаря +permission_manage_members: Управление участниками +permission_edit_messages: Редактирование сообщений +permission_delete_issues: Удаление задач +permission_view_issue_watchers: Просмотр списка наблюдателей +permission_manage_repository: Управление хранилищем +permission_commit_access: Разрешение фиксации +permission_browse_repository: Просмотр хранилища +permission_view_documents: Просмотр документов +permission_edit_project: Редактирование проектов +permission_add_issue_notes: Добавление примечаний +permission_save_queries: Сохранение запросов +permission_view_wiki_pages: Просмотр wiki +permission_rename_wiki_pages: Переименование страниц wiki +permission_edit_time_entries: Редактирование учета времени +permission_edit_own_issue_notes: Редактирование собственных примечаний +permission_edit_own_messages: Редактирование собственных сообщений +permission_delete_own_messages: Удаление собственных сообщений + project_module_boards: Форумы project_module_documents: Документы project_module_files: Файлы @@ -601,10 +653,12 @@ setting_cross_project_issue_relations: Разрешить пересечение setting_date_format: Формат даты setting_default_language: Язык по умолчанию setting_default_projects_public: Новые проекты являются общедоступными +setting_diff_max_lines_displayed: Максимальное число строк для diff setting_display_subprojects_issues: Отображение подпроектов по умолчанию setting_emails_footer: Подстрочные примечания Email setting_enabled_scm: Разрешенные SCM setting_feeds_limit: Ограничение количества заголовков для RSS потока +setting_gravatar_enabled: Использовать аватар пользователя из Gravatar setting_host_name: Имя компьютера setting_issue_list_default_columns: Колонки, отображаемые в списке задач по умолчанию setting_issues_export_limit: Ограничение по экспортируемым задачам @@ -613,6 +667,7 @@ setting_mail_from: email адрес для передачи информации setting_mail_handler_api_enabled: Включить веб-сервис для входящих сообщений setting_mail_handler_api_key: API ключ setting_per_page_options: Количество строк на страницу +setting_plain_text_mail: Только простой текст (без HTML) setting_protocol: Протокол setting_repositories_encodings: Кодировки хранилища setting_self_registration: Возможна саморегистрация @@ -636,6 +691,7 @@ text_comma_separated: Допустимы несколько значений (ч text_default_administrator_account_changed: Учетная запись администратора по умолчанию изменена text_destroy_time_entries_question: Вы собираетесь удалить %.02f часа(ов) прикрепленных за этой задачей. text_destroy_time_entries: Удалить зарегистрированное время +text_diff_truncated: '... Этот diff ограничен, так как превышает максимальный отображаемый размер.' text_email_delivery_not_configured: "Параметры работы с почтовым сервером не настроены и функция уведомления по email не активна.\nНастроить параметры для Вашего SMTP-сервера Вы можете в файле config/email.yml. Для применения изменений перезапустите приложение." text_enumeration_category_reassign_to: 'Назначить им следующее значение:' text_enumeration_destroy_question: '%d объект(а,ов) связаны с этим значением.' @@ -658,6 +714,7 @@ text_project_destroy_confirmation: Вы настаиваете на удален text_project_identifier_info: 'Допустимы строчные буквы (a-z), цифры и дефис.
    Сохраненный идентификатор не может быть изменен.' text_reassign_time_entries: 'Перенести зарегистрированное время на следующую задачу:' text_regexp_info: напр. ^[A-Z0-9]+$ +text_repository_usernames_mapping: "Выберите или обновите пользователя Redmine, связанного с найденными именами в журнале хранилица.\nПользователи с одинаковыми именами или email в Redmine и хранилище связываются автоматически." text_rmagick_available: Доступно использование RMagick (опционально) text_select_mail_notifications: Выберите действия, на которые будет отсылаться уведомление на электронную почту. text_select_project_modules: 'Выберите модули, которые будут использованы в проекте:' @@ -670,8 +727,18 @@ text_tracker_no_workflow: Для этого трекера последоват text_unallowed_characters: Запрещенные символы text_user_mail_option: "Для невыбранных проектов, Вы будете получать уведомления только о том что просматриваете или в чем участвуете (например, вопросы, автором которых Вы являетесь или которые Вам назначены)." text_user_wrote: '%s написал(а):' -text_wiki_destroy_confirmation: Вы уверены, что хотите удалить данную Wiki и все содержимое? +text_wiki_destroy_confirmation: Вы уверены, что хотите удалить данную Wiki и все ее содержимое? text_workflow_edit: Выберите роль и трекер для редактирования последовательности состояний -setting_repositories_cache_directory: Cache directory for repositories -field_cache: Local cache +text_plugin_assets_writable: Каталог для плагинов доступен по записи +warning_attachments_not_saved: "%d файл(ов) невозможно сохранить." +button_create_and_continue: Создать и продолжить +text_custom_field_possible_values_info: 'По одному значению в каждой строке' +label_display: Отображение +field_editable: Редактируемый + +setting_repository_log_display_limit: Maximum number of revisions displayed on file log +field_identity_url: OpenID URL +setting_openid: Allow OpenID login and registration +label_login_with_open_id_option: or login with OpenID +field_watcher: Watcher diff --git a/lang/sk.yml b/lang/sk.yml new file mode 100644 index 000000000..351173a32 --- /dev/null +++ b/lang/sk.yml @@ -0,0 +1,714 @@ +# SK translation by Stanislav Pach | stano.pach@seznam.cz + + +_gloc_rule_default: '|n| n==1 ? "" : "_plural" ' + +actionview_datehelper_select_day_prefix: +actionview_datehelper_select_month_names: Január,Február,Marec,Apríl,Máj,Jún,Júl,August,September,Október,November,December +actionview_datehelper_select_month_names_abbr: Jan,Feb,Mar,Apr,Máj,Jún,Júl,Aug,Sep,Okt,Nov,Dec +actionview_datehelper_select_month_prefix: +actionview_datehelper_select_year_prefix: +actionview_datehelper_time_in_words_day: 1 deň +actionview_datehelper_time_in_words_day_plural: %d dní/dňami +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 minútou +actionview_datehelper_time_in_words_minute_half: pol minútou +actionview_datehelper_time_in_words_minute_less_than: menej ako minútou +actionview_datehelper_time_in_words_minute_plural: %d minútami +actionview_datehelper_time_in_words_minute_single: 1 minútou +actionview_datehelper_time_in_words_second_less_than: menej ako sekundou +actionview_datehelper_time_in_words_second_less_than_plural: menej ako %d sekundami +actionview_instancetag_blank_option: Prosím vyberte + +activerecord_error_inclusion: nieje zahrnuté v zozname +activerecord_error_exclusion: je rezervované +activerecord_error_invalid: je neplatné +activerecord_error_confirmation: sa nezhoduje s potvrdením +activerecord_error_accepted: musí byť akceptované +activerecord_error_empty: nemôže byť prázdne +activerecord_error_blank: nemôže byť prázdne +activerecord_error_too_long: je príliš dlhé +activerecord_error_too_short: je príliš krátke +activerecord_error_wrong_length: má chybnú dĺžku +activerecord_error_taken: je už použité +activerecord_error_not_a_number: nieje číslo +activerecord_error_not_a_date: nieje platný dátum +activerecord_error_greater_than_start_date: musí byť väčší ako počiatočný dátum +activerecord_error_not_same_project: nepatrí rovnakému projektu +activerecord_error_circular_dependency: Tento vzťah by vytvoril cyklickú závislosť + +general_fmt_age: %d rok +general_fmt_age_plural: %d rokov +general_fmt_date: %%m/%%d/%%Y +general_fmt_datetime: %%m/%%d/%%Y %%I:%%M %%p +general_fmt_datetime_short: %%b %%d, %%I:%%M %%p +general_fmt_time: %%I:%%M %%p +general_text_No: 'Nie' +general_text_Yes: 'Áno' +general_text_no: 'nie' +general_text_yes: 'áno' +general_lang_name: 'Slovensky' +general_csv_separator: ',' +general_csv_decimal_separator: '.' +general_csv_encoding: UTF-8 +general_pdf_encoding: UTF-8 +general_day_names: Pondelok,Utorok,Streda,Štvrtok,Piatok,Sobota,Nedeľa +general_first_day_of_week: '1' + +notice_account_updated: Účet bol úspešne zmenený. +notice_account_invalid_creditentials: Chybné meno alebo heslo +notice_account_password_updated: Heslo bolo úspešne zmenené. +notice_account_wrong_password: Chybné heslo +notice_account_register_done: Účet bol úspešne vytvorený. Pre aktiváciu účtu kliknite na odkaz v emailu, ktorý vam bol zaslaný. +notice_account_unknown_email: Neznámy uživateľ. +notice_can_t_change_password: Tento účet používa externú autentifikáciu. Tu heslo zmeniť nemôžete. +notice_account_lost_email_sent: Bol vám zaslaný email s inštrukciami ako si nastavite nové heslo. +notice_account_activated: Váš účet bol aktivovaný. Teraz se môžete prihlásiť. +notice_successful_create: Úspešne vytvorené. +notice_successful_update: Úspešne aktualizované. +notice_successful_delete: Úspešne odstránené. +notice_successful_connection: Úspešne pripojené. +notice_file_not_found: Stránka, ktorú se snažíte zobraziť, neexistuje alebo bola smazaná. +notice_locking_conflict: Údaje boli zmenené iným užívateľom. +notice_scm_error: Položka a/alebo revízia neexistuje v repository. +notice_not_authorized: Nemáte dostatočné práva pre zobrazenie tejto stránky. +notice_email_sent: Na adresu %s bol odeslaný email +notice_email_error: Pri odosielaní emailu nastala chyba (%s) +notice_feeds_access_key_reseted: Váš klúč pre prístup k Atomu bol resetovaný. +notice_failed_to_save_issues: "Nastala chyba pri ukládaní %d úloh na %d zvolený: %s." +notice_no_issue_selected: "Nebola zvolená žiadná úloha. Prosím, zvoľte úlohy, ktoré chcete editovať" +notice_account_pending: "Váš účet bol vytvorený, teraz čaká na schválenie administrátorom." +notice_default_data_loaded: Výchozia konfigurácia úspešne nahraná. + +error_can_t_load_default_data: "Výchozia konfigurácia nebola nahraná: %s" +error_scm_not_found: "Položka a/alebo revízia neexistuje v repository." +error_scm_command_failed: "Pri pokuse o prístup k repository došlo k chybe: %s" +error_issue_not_found_in_project: 'Úloha nebola nájdená alebo nepatrí k tomuto projektu' + +mail_subject_lost_password: Vaše heslo (%s) +mail_body_lost_password: 'Pre zmenu vašeho hesla kliknite na následujúci odkaz:' +mail_subject_register: Aktivácia účtu (%s) +mail_body_register: 'Pre aktiváciu vašeho účtu kliknite na následujúci odkaz:' +mail_body_account_information_external: Pomocou vašeho účtu "%s" se môžete prihlásiť. +mail_body_account_information: Informácie o vašom účte +mail_subject_account_activation_request: Aktivácia %s účtu +mail_body_account_activation_request: Bol zaregistrovaný nový uživateľ "%s". Aktivácia jeho účtu závisí na vašom potvrdení. + +gui_validation_error: 1 chyba +gui_validation_error_plural: %d chyb(y) + +field_name: Názov +field_description: Popis +field_summary: Prehľad +field_is_required: Povinné pole +field_firstname: Meno +field_lastname: Priezvisko +field_mail: Email +field_filename: Súbor +field_filesize: Veľkosť +field_downloads: Stiahnuté +field_author: Autor +field_created_on: Vytvorené +field_updated_on: Aktualizované +field_field_format: Formát +field_is_for_all: Pre všetky projekty +field_possible_values: Možné hodnoty +field_regexp: Regulérny výraz +field_min_length: Minimálna dĺžka +field_max_length: Maximálna dĺžka +field_value: Hodnota +field_category: Kategória +field_title: Názov +field_project: Projekt +field_issue: Úloha +field_status: Stav +field_notes: Poznámka +field_is_closed: Úloha uzavretá +field_is_default: Východzí stav +field_tracker: Fronta +field_subject: Predmet +field_due_date: Uzavrieť do +field_assigned_to: Priradené +field_priority: Priorita +field_fixed_version: Priradené k verzii +field_user: Užívateľ +field_role: Rola +field_homepage: Domovská stránka +field_is_public: Verejný +field_parent: Nadradený projekt +field_is_in_chlog: Úlohy zobrazené v rozdielovom logu +field_is_in_roadmap: Úlohy zobrazené v pláne +field_login: Login +field_mail_notification: Emailové oznámenie +field_admin: Administrátor +field_last_login_on: Posledné prihlásenie +field_language: Jazyk +field_effective_date: Dátum +field_password: Heslo +field_new_password: Nové heslo +field_password_confirmation: Potvrdenie +field_version: Verzia +field_type: Typ +field_host: Host +field_port: Port +field_account: Účet +field_base_dn: Base DN +field_attr_login: Prihlásenie (atribut) +field_attr_firstname: Meno (atribut) +field_attr_lastname: Priezvisko (atribut) +field_attr_mail: Email (atribut) +field_onthefly: Automatické vytváranie užívateľov +field_start_date: Začiatok +field_done_ratio: %% Hotovo +field_auth_source: Autentifikačný mód +field_hide_mail: Nezobrazovať môj email +field_comments: Komentár +field_url: URL +field_start_page: Výchozia stránka +field_subproject: Podprojekt +field_hours: hodiny +field_activity: Aktivita +field_spent_on: Dátum +field_identifier: Identifikátor +field_is_filter: Použíť ako filter +field_issue_to_id: Súvisiaca úloha +field_delay: Oneskorenie +field_assignable: Úlohy môžu byť priradené tejto roli +field_redirect_existing_links: Presmerovať existujúce odkazy +field_estimated_hours: Odhadovaná doba +field_column_names: Stĺpce +field_time_zone: Časové pásmo +field_searchable: Umožniť vyhľadávanie +field_default_value: Východzia hodnota +field_comments_sorting: Zobraziť komentáre + +setting_app_title: Názov aplikácie +setting_app_subtitle: Podtitulok aplikácie +setting_welcome_text: Uvítací text +setting_default_language: Východzí jazyk +setting_login_required: Auten. vyžadovaná +setting_self_registration: Povolenie vlastnej registrácie +setting_attachment_max_size: Maximálna veľkosť prílohy +setting_issues_export_limit: Limit pre export úloh +setting_mail_from: Odosielať emaily z adresy +setting_bcc_recipients: Príjemci skrytej kópie (bcc) +setting_host_name: Hostname +setting_text_formatting: Formátovanie textu +setting_wiki_compression: Kompresia histórie Wiki +setting_feeds_limit: Limit zobrazených položiek (Atom feed) +setting_default_projects_public: Nové projekty nastavovať ako verejné +setting_autofetch_changesets: Automatický prenos zmien +setting_sys_api_enabled: Povolit WS pre správu repozitory +setting_commit_ref_keywords: Klúčové slová pre odkazy +setting_commit_fix_keywords: Klúčové slová pre uzavretie +setting_autologin: Automatické prihlasovanie +setting_date_format: Formát dátumu +setting_time_format: Formát času +setting_cross_project_issue_relations: Povoliť väzby úloh skrz projekty +setting_issue_list_default_columns: Východzie stĺpce zobrazené v zozname úloh +setting_repositories_encodings: Kódovanie +setting_emails_footer: Zapätie emailov +setting_protocol: Protokol +setting_per_page_options: Povolené množstvo riadkov na stránke +setting_user_format: Formát zobrazenia užívateľa +setting_activity_days_default: "Zobrazené dni aktivity projektu:" +setting_display_subprojects_issues: Prednastavenie zobrazenia úloh podporojektov v hlavnom projekte + +project_module_issue_tracking: Sledovanie úloh +project_module_time_tracking: Sledovanie času +project_module_news: Novinky +project_module_documents: Dokumenty +project_module_files: Súbory +project_module_wiki: Wiki +project_module_repository: Repository +project_module_boards: Diskusie + +label_user: Užívateľ +label_user_plural: Užívatelia +label_user_new: Nový užívateľ +label_project: Projekt +label_project_new: Nový projekt +label_project_plural: Projekty +label_project_all: Všetky projekty +label_project_latest: Posledné projekty +label_issue: Úloha +label_issue_new: Nová úloha +label_issue_plural: Úlohy +label_issue_view_all: Všetky úlohy +label_issues_by: Úlohy od užívateľa %s +label_issue_added: Úloha pridaná +label_issue_updated: Úloha aktualizovaná +label_document: Dokument +label_document_new: Nový dokument +label_document_plural: Dokumenty +label_document_added: Dokument pridaný +label_role: Rola +label_role_plural: Role +label_role_new: Nová rola +label_role_and_permissions: Role a práva +label_member: Člen +label_member_new: Nový člen +label_member_plural: Členovia +label_tracker: Fronta +label_tracker_plural: Fronty +label_tracker_new: Nová fronta +label_workflow: Workflow +label_issue_status: Stav úloh +label_issue_status_plural: Stavy úloh +label_issue_status_new: Nový stav +label_issue_category: Kategória úloh +label_issue_category_plural: Kategórie úloh +label_issue_category_new: Nová kategória +label_custom_field: Užívateľské pole +label_custom_field_plural: Užívateľské polia +label_custom_field_new: Nové užívateľské pole +label_enumerations: Zoznamy +label_enumeration_new: Nová hodnota +label_information: Informácia +label_information_plural: Informácie +label_please_login: Prosím prihláste sa +label_register: Registrovať +label_password_lost: Zabudnuté heslo +label_home: Domovská stránka +label_my_page: Moja stránka +label_my_account: Môj účet +label_my_projects: Moje projekty +label_administration: Administrácia +label_login: Prihlásenie +label_logout: Odhlásenie +label_help: Nápoveda +label_reported_issues: Nahlásené úlohy +label_assigned_to_me_issues: Moje úlohy +label_last_login: Posledné prihlásenie +label_last_updates: Posledná zmena +label_last_updates_plural: %d posledné zmeny +label_registered_on: Registrovaný +label_activity: Aktivita +label_overall_activity: Celková aktivita +label_new: Nový +label_logged_as: Prihlásený ako +label_environment: Prostredie +label_authentication: Autentifikácia +label_auth_source: Mód autentifikácie +label_auth_source_new: Nový mód autentifikácie +label_auth_source_plural: Módy autentifikácie +label_subproject_plural: Podprojekty +label_min_max_length: Min - Max dĺžka +label_list: Zoznam +label_date: Dátum +label_integer: Celé číslo +label_float: Desatinné číslo +label_boolean: Áno/Nie +label_string: Text +label_text: Dlhý text +label_attribute: Atribut +label_attribute_plural: Atributy +label_download: %d Download +label_download_plural: %d Downloady +label_no_data: Žiadné položky +label_change_status: Zmeniť stav +label_history: História +label_attachment: Súbor +label_attachment_new: Nový súbor +label_attachment_delete: Odstrániť súbor +label_attachment_plural: Súbory +label_file_added: Súbor pridaný +label_report: Prehľad +label_report_plural: Prehľady +label_news: Novinky +label_news_new: Pridať novinku +label_news_plural: Novinky +label_news_latest: Posledné novinky +label_news_view_all: Zobrazit všetky novinky +label_news_added: Novinka pridaná +label_change_log: Protokol zmien +label_settings: Nastavenie +label_overview: Prehľad +label_version: Verzia +label_version_new: Nová verzia +label_version_plural: Verzie +label_confirmation: Potvrdenie +label_export_to: 'Tiež k dispozícií:' +label_read: Načíta sa... +label_public_projects: Verejné projekty +label_open_issues: Otvorený +label_open_issues_plural: Otvorené +label_closed_issues: Uzavrený +label_closed_issues_plural: Uzavrené +label_total: Celkovo +label_permissions: Práva +label_current_status: Aktuálny stav +label_new_statuses_allowed: Nové povolené stavy +label_all: všetko +label_none: nič +label_nobody: nikto +label_next: Ďalší +label_previous: Predchádzajúci +label_used_by: Použité +label_details: Detaily +label_add_note: Pridať poznámku +label_per_page: Na stránku +label_calendar: Kalendár +label_months_from: mesiacov od +label_gantt: Ganttov graf +label_internal: Interný +label_last_changes: posledných %d zmien +label_change_view_all: Zobraziť všetky zmeny +label_personalize_page: Prispôsobiť túto stránku +label_comment: Komentár +label_comment_plural: Komentáre +label_comment_add: Pridať komentár +label_comment_added: Komentár pridaný +label_comment_delete: Odstrániť komentár +label_query: Užívateľský dotaz +label_query_plural: Užívateľské dotazy +label_query_new: Nový dotaz +label_filter_add: Pridať filter +label_filter_plural: Filtre +label_equals: je +label_not_equals: nieje +label_in_less_than: je menší ako +label_in_more_than: je väčší ako +label_in: v +label_today: dnes +label_all_time: vždy +label_yesterday: včera +label_this_week: tento týždeň +label_last_week: minulý týždeň +label_last_n_days: posledných %d dní +label_this_month: tento mesiac +label_last_month: minulý mesiac +label_this_year: tento rok +label_date_range: Časový rozsah +label_less_than_ago: pred menej ako (dňami) +label_more_than_ago: pred viac ako (dňami) +label_ago: pred (dňami) +label_contains: obsahuje +label_not_contains: neobsahuje +label_day_plural: dní +label_repository: Repository +label_repository_plural: Repository +label_browse: Prechádzať +label_modification: %d zmena +label_modification_plural: %d zmien +label_revision: Revízia +label_revision_plural: Revízií +label_associated_revisions: Súvisiace verzie +label_added: pridané +label_modified: zmenené +label_deleted: odstránené +label_latest_revision: Posledná revízia +label_latest_revision_plural: Posledné revízie +label_view_revisions: Zobraziť revízie +label_max_size: Maximálna veľkosť +label_on: 'z celkovo' +label_sort_highest: Presunúť na začiatok +label_sort_higher: Presunúť navrch +label_sort_lower: Presunúť dole +label_sort_lowest: Presunúť na koniec +label_roadmap: Plán +label_roadmap_due_in: Zostáva %s +label_roadmap_overdue: %s neskoro +label_roadmap_no_issues: Pre túto verziu niesu žiadne úlohy +label_search: Hľadať +label_result_plural: Výsledky +label_all_words: Všetky slova +label_wiki: Wiki +label_wiki_edit: Wiki úprava +label_wiki_edit_plural: Wiki úpravy +label_wiki_page: Wiki stránka +label_wiki_page_plural: Wiki stránky +label_index_by_title: Index podľa názvu +label_index_by_date: Index podľa dátumu +label_current_version: Aktuálna verzia +label_preview: Náhľad +label_feed_plural: Príspevky +label_changes_details: Detail všetkých zmien +label_issue_tracking: Sledovanie úloh +label_spent_time: Strávený čas +label_f_hour: %.2f hodina +label_f_hour_plural: %.2f hodín +label_time_tracking: Sledovánie času +label_change_plural: Zmeny +label_statistics: Štatistiky +label_commits_per_month: Úkony za mesiac +label_commits_per_author: Úkony podľa autora +label_view_diff: Zobrazit rozdiely +label_diff_inline: vo vnútri +label_diff_side_by_side: vedľa seba +label_options: Nastavenie +label_copy_workflow_from: Kopírovať workflow z +label_permissions_report: Prehľad práv +label_watched_issues: Sledované úlohy +label_related_issues: Súvisiace úlohy +label_applied_status: Použitý stav +label_loading: Nahrávam ... +label_relation_new: Nová súvislosť +label_relation_delete: Odstrániť súvislosť +label_relates_to: súvisiací s +label_duplicates: duplicity +label_blocks: blokovaný +label_blocked_by: zablokovaný +label_precedes: predcháza +label_follows: následuje +label_end_to_start: od konca na začiatok +label_end_to_end: od konca do konca +label_start_to_start: od začiatku do začiatku +label_start_to_end: od začiatku do konca +label_stay_logged_in: Zostať prihlásený +label_disabled: zakazané +label_show_completed_versions: Ukázať dokončené verzie +label_me: ja +label_board: Fórum +label_board_new: Nové fórum +label_board_plural: Fóra +label_topic_plural: Témy +label_message_plural: Správy +label_message_last: Posledná správa +label_message_new: Nová správa +label_message_posted: Správa pridaná +label_reply_plural: Odpovede +label_send_information: Zaslať informácie o účte užívateľa +label_year: Rok +label_month: Mesiac +label_week: Týžden +label_date_from: Od +label_date_to: Do +label_language_based: Podľa výchozieho jazyka +label_sort_by: Zoradenie podľa %s +label_send_test_email: Poslať testovací email +label_feeds_access_key_created_on: Prístupový klúč pre RSS bol vytvorený pred %s +label_module_plural: Moduly +label_added_time_by: 'Pridané užívateľom %s pred %s' +label_updated_time: 'Aktualizované pred %s' +label_jump_to_a_project: Zvoliť projekt... +label_file_plural: Súbory +label_changeset_plural: Sady zmien +label_default_columns: Východzie stĺpce +label_no_change_option: (bez zmeny) +label_bulk_edit_selected_issues: Skupinová úprava vybraných úloh +label_theme: Téma +label_default: Východzí +label_search_titles_only: Vyhľadávať iba v názvoch +label_user_mail_option_all: "Pre všetky události všetkých mojích projektov" +label_user_mail_option_selected: "Pre všetky události vybraných projektov.." +label_user_mail_option_none: "Len pre události, ktoré sledujem alebo sa ma týkajú" +label_user_mail_no_self_notified: "Nezasielať informácie o mnou vytvorených zmenách" +label_registration_activation_by_email: aktivácia účtu emailom +label_registration_manual_activation: manuálna aktivácia účtu +label_registration_automatic_activation: automatická aktivácia účtu +label_display_per_page: '%s na stránku' +label_age: Vek +label_change_properties: Zmeniť vlastnosti +label_general: Všeobecné +label_more: Viac +label_scm: SCM +label_plugins: Pluginy +label_ldap_authentication: Autentifikácia LDAP +label_downloads_abbr: D/L +label_optional_description: Voliteľný popis +label_add_another_file: Pridať další súbor +label_preferences: Nastavenia +label_chronological_order: V chronologickom poradí +label_reverse_chronological_order: V obrátenom chronologickom poradí + +button_login: Prihlásiť +button_submit: Potvrdiť +button_save: Uložiť +button_check_all: Označiť všetko +button_uncheck_all: Odznačiť všetko +button_delete: Odstrániť +button_create: Vytvoriť +button_test: Test +button_edit: Upraviť +button_add: Pridať +button_change: Zmeniť +button_apply: Použiť +button_clear: Zmazať +button_lock: Zamknúť +button_unlock: Odomknúť +button_download: Stiahnúť +button_list: Vypísať +button_view: Zobraziť +button_move: Presunúť +button_back: Naspäť +button_cancel: Storno +button_activate: Aktivovať +button_sort: Zoradenie +button_log_time: Pridať čas +button_rollback: Naspäť k tejto verzii +button_watch: Sledovať +button_unwatch: Nesledovať +button_reply: Odpovedať +button_archive: Archivovať +button_unarchive: Odarchivovať +button_reset: Reset +button_rename: Premenovať +button_change_password: Zmeniť heslo +button_copy: Kopírovať +button_annotate: Komentovať +button_update: Aktualizovať +button_configure: Konfigurovať + +status_active: aktívny +status_registered: registrovaný +status_locked: uzamknutý + +text_select_mail_notifications: Vyberte akciu, pri ktorej bude zaslané upozornenie emailom +text_regexp_info: napr. ^[A-Z0-9]+$ +text_min_max_length_info: 0 znamená bez limitu +text_project_destroy_confirmation: Ste si istý, že chcete odstránit tento projekt a všetky súvisiace dáta ? +text_workflow_edit: Vyberte rolu a frontu k editácii workflow +text_are_you_sure: Ste si istý? +text_journal_changed: zmenené z %s na %s +text_journal_set_to: nastavené na %s +text_journal_deleted: odstránené +text_tip_task_begin_day: úloha začína v tento deň +text_tip_task_end_day: úloha končí v tento deň +text_tip_task_begin_end_day: úloha začína a končí v tento deň +text_project_identifier_info: 'Povolené znaky sú malé písmena (a-z), čísla a pomlčka.
    Po uložení už nieje možné identifikátor zmeniť.' +text_caracters_maximum: %d znakov maximálne. +text_caracters_minimum: Musí byť aspoň %d znaky/ov dlhé. +text_length_between: Dĺžka medzi %d až %d znakmi. +text_tracker_no_workflow: Pre tuto frontu nieje definovaný žiadný workflow +text_unallowed_characters: Nepovolené znaky +text_comma_separated: Je povolené viacero hodnôt (oddelené navzájom čiarkou). +text_issues_ref_in_commit_messages: Odkazovať a upravovať úlohy v správach s následovnym obsahom +text_issue_added: úloha %s bola vytvorená užívateľom %s. +text_issue_updated: Úloha %s byla aktualizovaná užívateľom %s. +text_wiki_destroy_confirmation: Naozaj si prajete odstráni%t túto Wiki a celý jej obsah? +text_issue_category_destroy_question: Niektoré úlohy (%d) sú priradené k tejto kategórii. Čo chtete s nimi spraviť? +text_issue_category_destroy_assignments: Zrušiť priradenie ku kategórii +text_issue_category_reassign_to: Priradiť úlohy do tejto kategórie +text_user_mail_option: "U projektov, které neboli vybrané, budete dostávať oznamenie iba o vašich či o sledovaných položkách (napr. o položkách, ktorých ste autor, alebo ku ktorým ste priradený/á)." +text_no_configuration_data: "Role, fronty, stavy úloh ani workflow neboli zatiaľ nakonfigurované.\nVelmi doporučujeme nahrať východziu konfiguráciu. Potom si môžete všetko upraviť" +text_load_default_configuration: Nahrať východziu konfiguráciu +text_status_changed_by_changeset: Aktualizované v sade zmien %s. +text_issues_destroy_confirmation: 'Naozaj si prajete odstrániť všetky zvolené úlohy?' +text_select_project_modules: 'Aktivne moduly v tomto projekte:' +text_default_administrator_account_changed: Zmenené výchozie nastavenie administrátorského účtu +text_file_repository_writable: Povolený zápis do repository +text_rmagick_available: RMagick k dispozícií (voliteľné) +text_destroy_time_entries_question: U úloh, které chcete odstraniť, je evidované %.02f práce. Čo chcete vykonať? +text_destroy_time_entries: Odstrániť evidované hodiny. +text_assign_time_entries_to_project: Priradiť evidované hodiny projektu +text_reassign_time_entries: 'Preradiť evidované hodiny k tejto úlohe:' + +default_role_manager: Manažér +default_role_developper: Vývojár +default_role_reporter: Reportér +default_tracker_bug: Chyba +default_tracker_feature: Rozšírenie +default_tracker_support: Podpora +default_issue_status_new: Nový +default_issue_status_assigned: Priradený +default_issue_status_resolved: Vyriešený +default_issue_status_feedback: Čaká sa +default_issue_status_closed: Uzavrený +default_issue_status_rejected: Odmietnutý +default_doc_category_user: Užívateľská dokumentácia +default_doc_category_tech: Technická dokumentácia +default_priority_low: Nízká +default_priority_normal: Normálna +default_priority_high: Vysoká +default_priority_urgent: Urgentná +default_priority_immediate: Okamžitá +default_activity_design: Design +default_activity_development: Vývoj + +enumeration_issue_priorities: Priority úloh +enumeration_doc_categories: Kategorie dokumentov +enumeration_activities: Aktivity (sledovanie času) +error_scm_annotate: "Položka neexistuje alebo nemôže byť komentovaná." +label_planning: Plánovanie +text_subprojects_destroy_warning: 'Jeho podprojekt(y): %s budú takisto vymazané.' +label_and_its_subprojects: %s a jeho podprojekty +mail_body_reminder: "%d úloha(y), ktorá(é) je(sú) vám priradený(é), ma(jú) byť hotova(é) za %d dní:" +mail_subject_reminder: "%d úloha(y) ma(jú) byť hotova(é) za pár dní" +text_user_wrote: '%s napísal:' +label_duplicated_by: duplikovaný +setting_enabled_scm: Zapnúť SCM +text_enumeration_category_reassign_to: 'Prenastaviť na túto hodnotu:' +text_enumeration_destroy_question: '%d objekty sú nastavené na túto hodnotu.' +label_incoming_emails: Príchádzajúce emaily +label_generate_key: Vygenerovať kľúč +setting_mail_handler_api_enabled: Zapnúť WS pre príchodzie emaily +setting_mail_handler_api_key: API kľúč +text_email_delivery_not_configured: "Doručenie emailov nieje nastavené, notifikácie sú vypnuté.\nNastavte váš SMTP server v config/email.yml a reštartnite aplikáciu pre aktiváciu funkcie." +field_parent_title: Nadradená stránka +label_issue_watchers: Pozorovatelia +setting_commit_logs_encoding: Kódovanie prenášaných správ +button_quote: Citácia +setting_sequential_project_identifiers: Generovať sekvenčné identifikátory projektov +notice_unable_delete_version: Verzia nemôže byť zmazaná +label_renamed: premenované +label_copied: kopírované +setting_plain_text_mail: Len jednoduchý text (bez HTML) +permission_view_files: Zobrazenie súborov +permission_edit_issues: Editácia úloh +permission_edit_own_time_entries: Editácia vlastných časových logov +permission_manage_public_queries: Správa verejných dotazov +permission_add_issues: Pridanie úlohy +permission_log_time: Log stráveného času +permission_view_changesets: Zobrazenie sád zmien +permission_view_time_entries: Zobrazenie stráveného času +permission_manage_versions: Správa verzií +permission_manage_wiki: Správa Wiki +permission_manage_categories: Správa kategórií úloh +permission_protect_wiki_pages: Ochrana Wiki strániek +permission_comment_news: Komentovanie noviniek +permission_delete_messages: Mazanie správ +permission_select_project_modules: Voľba projektových modulov +permission_manage_documents: Správa dokumentov +permission_edit_wiki_pages: Editácia Wiki strániek +permission_add_issue_watchers: Pridanie pozorovateľov +permission_view_gantt: Zobrazenie Ganttovho diagramu +permission_move_issues: Presun úloh +permission_manage_issue_relations: Správa vzťahov úloh +permission_delete_wiki_pages: Mazanie Wiki strániek +permission_manage_boards: Správa diskusií +permission_delete_wiki_pages_attachments: Mazanie Wiki príloh +permission_view_wiki_edits: Zobrazenie Wiki zmien +permission_add_messages: Pridanie správ +permission_view_messages: Zobrazenie správ +permission_manage_files: Správa súborov +permission_edit_issue_notes: Editácia poznámok úlohy +permission_manage_news: Správa noviniek +permission_view_calendar: Zobrazenie kalendára +permission_manage_members: Správa členov +permission_edit_messages: Editácia správ +permission_delete_issues: Mazanie správ +permission_view_issue_watchers: Zobrazenie zoznamu pozorovateľov +permission_manage_repository: Správa repository +permission_commit_access: Povoliť prístup +permission_browse_repository: Prechádzanie (browse) repository +permission_view_documents: Zobrazenie dokumentov +permission_edit_project: Editovanie projektu +permission_add_issue_notes: Pridanie poznámky úlohy +permission_save_queries: Uloženie dotazov +permission_view_wiki_pages: Zobrazenie Wiki strániek +permission_rename_wiki_pages: Premenovanie Wiki strániek +permission_edit_time_entries: Editácia časových záznamov +permission_edit_own_issue_notes: Editácia vlastných poznámok úlohy +setting_gravatar_enabled: Použitie užívateľských Gravatar ikon +permission_edit_own_messages: Úprava vlastných správ +permission_delete_own_messages: Mazanie vlastných správ +text_repository_usernames_mapping: "Vyberte alebo doplňte užívateľov systému Redmine, ktorí majú byť namapovaní k užívateľským menám, nájdeným v logu repository.\nUžívatelia s rovnakým prihlasovacím menom alebo emailom v systéme Redmine a repository sú mapovaní automaticky." +label_example: Príklad +label_user_activity: "Aktivita užívateľa %s" +label_updated_time_by: Aktualizované užívateľom %s pred %s +text_diff_truncated: '... Tento rozdielový výpis bol skratený, pretože prekračuje maximálnu veľkosť, ktorá môže byť zobrazená.' +setting_diff_max_lines_displayed: Maximálne množstvo zobrazených riadkov rozdielového výpisu +text_plugin_assets_writable: Adresár pre pluginy s možnosťou zápisu +warning_attachments_not_saved: "%d súbor(y) nemohli byť uložené." +field_editable: Editable +label_display: Display +button_create_and_continue: Create and continue +text_custom_field_possible_values_info: 'One line for each value' +setting_repository_log_display_limit: Maximum number of revisions displayed on file log +field_identity_url: OpenID URL +setting_openid: Allow OpenID login and registration +label_login_with_open_id_option: or login with OpenID +field_watcher: Watcher diff --git a/lang/sl.yml b/lang/sl.yml new file mode 100644 index 000000000..bd51bda35 --- /dev/null +++ b/lang/sl.yml @@ -0,0 +1,711 @@ +_gloc_rule_default: '|n| n==1 ? "" : "_plural" ' + +actionview_datehelper_select_day_prefix: +actionview_datehelper_select_month_names: Januar,Februar,Marec,April,Maj,Junij,Julij,Avgust,September,Oktober,November,December +actionview_datehelper_select_month_names_abbr: Jan,Feb,Mar,Apr,Maj,Jun,Jul,Aug,Sep,Okt,Nov,Dec +actionview_datehelper_select_month_prefix: +actionview_datehelper_select_year_prefix: +actionview_datehelper_time_in_words_day: 1 dan +actionview_datehelper_time_in_words_day_plural: %d dni +actionview_datehelper_time_in_words_hour_about: kakšno uro +actionview_datehelper_time_in_words_hour_about_plural: kakšnih %d ur +actionview_datehelper_time_in_words_hour_about_single: kakšno uro +actionview_datehelper_time_in_words_minute: 1 minuta +actionview_datehelper_time_in_words_minute_half: pol minute +actionview_datehelper_time_in_words_minute_less_than: manj kot minuto +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: manj kot sekunda +actionview_datehelper_time_in_words_second_less_than_plural: manj kot %d sekund +actionview_instancetag_blank_option: Prosimo izberite + +activerecord_error_inclusion: ni vključen na seznamu +activerecord_error_exclusion: je rezerviran +activerecord_error_invalid: je napačen +activerecord_error_confirmation: ne ustreza potrdilu +activerecord_error_accepted: mora biti sprejet +activerecord_error_empty: ne sme biti prazen +activerecord_error_blank: ne sme biti neizpolnjen +activerecord_error_too_long: je predolg +activerecord_error_too_short: je prekratek +activerecord_error_wrong_length: je napačne dolžine +activerecord_error_taken: je že zaseden +activerecord_error_not_a_number: ni število +activerecord_error_not_a_date: ni veljaven datum +activerecord_error_greater_than_start_date: mora biti kasnejši kot začeten datum +activerecord_error_not_same_project: ne pripada istemu projektu +activerecord_error_circular_dependency: Ta odnos bi povzročil krožno odvisnost + +general_fmt_age: %d l +general_fmt_age_plural: %d let +general_fmt_date: %%m/%%d/%%Y +general_fmt_datetime: %%m/%%d/%%Y %%I:%%M %%p +general_fmt_datetime_short: %%b %%d, %%I:%%M %%p +general_fmt_time: %%I:%%M %%p +general_text_No: 'Ne' +general_text_Yes: 'Da' +general_text_no: 'ne' +general_text_yes: 'da' +general_lang_name: 'Slovenščina' +general_csv_separator: ',' +general_csv_decimal_separator: '.' +general_csv_encoding: ISO-8859-1 +general_pdf_encoding: ISO-8859-1 +general_day_names: Ponedeljek,Torek,Sreda,Četrtek,Petek,Sobota,Nedelja +general_first_day_of_week: '1' + +notice_account_updated: Račun je bil uspešno posodobljen. +notice_account_invalid_creditentials: Napačno uporabniško ime ali geslo +notice_account_password_updated: Geslo je bilo uspešno posodobljeno. +notice_account_wrong_password: Napačno geslo +notice_account_register_done: Račun je bil uspešno ustvarjen. Za aktivacijo potrdite povezavo, ki vam je bila poslana v e-nabiralnik. +notice_account_unknown_email: Neznan uporabnik. +notice_can_t_change_password: Ta račun za overovljanje uporablja zunanji. Gesla ni mogoče spremeniti. +notice_account_lost_email_sent: Poslano vam je bilo e-pismo z navodili za izbiro novega gesla. +notice_account_activated: Vaš račun je bil aktiviran. Sedaj se lahko prijavite. +notice_successful_create: Zapisovanje uspelo. +notice_successful_update: Posodobitev uspela. +notice_successful_delete: Izbris uspel. +notice_successful_connection: Povezava uspela. +notice_file_not_found: Stran na katero se želite povezati ne obstaja ali pa je bila umaknjena. +notice_locking_conflict: Drug uporabnik je posodobil podatke. +notice_not_authorized: Nimate privilegijev za dostop do te strani. +notice_email_sent: E-poštno sporočilo je bilo poslano %s +notice_email_error: Ob pošiljanju e-sporočila je prišlo do napake (%s) +notice_feeds_access_key_reseted: Vaš RSS dostopni ključ je bil ponastavljen. +notice_failed_to_save_issues: "Neuspelo shranjevanje %d zahtevka na %d izbranem: %s." +notice_no_issue_selected: "Izbran ni noben zahtevek! Prosimo preverite zahtevke, ki jih želite urediti." +notice_account_pending: "Vaš račun je bil ustvarjen in čaka na potrditev s strani administratorja." +notice_default_data_loaded: Privzete nastavitve so bile uspešno naložene. +notice_unable_delete_version: Verzije ni bilo mogoče izbrisati. + +error_can_t_load_default_data: "Privzetih nastavitev ni bilo mogoče naložiti: %s" +error_scm_not_found: "Vnos ali revizija v shrambi ni bila najdena ." +error_scm_command_failed: "Med vzpostavljem povezave s shrambo je prišlo do napake: %s" +error_scm_annotate: "Vnos ne obstaja ali pa ga ni mogoče komentirati." +error_issue_not_found_in_project: 'Zahtevek ni bil najden ali pa ne pripada temu projektu' + +mail_subject_lost_password: Vaše %s geslo +mail_body_lost_password: 'Za spremembo glesla kliknite na naslednjo povezavo:' +mail_subject_register: Aktivacija %s vašega računa +mail_body_register: 'Za aktivacijo vašega računa kliknite na naslednjo povezavo:' +mail_body_account_information_external: Za prijavo lahko uporabite vaš "%s" račun. +mail_body_account_information: Informacije o vašem računu +mail_subject_account_activation_request: %s zahtevek za aktivacijo računa +mail_body_account_activation_request: 'Registriral se je nov uporabnik (%s). Račun čaka na vašo odobritev:' +mail_subject_reminder: "%d zahtevek(zahtevki) zapadejo v naslednjih dneh" +mail_body_reminder: "%d zahtevek(zahtevki), ki so vam dodeljeni bodo zapadli v naslednjih %d dneh:" + +gui_validation_error: 1 napaka +gui_validation_error_plural: %d napak + +field_name: Ime +field_description: Opis +field_summary: Povzetek +field_is_required: Zahtevano +field_firstname: Ime +field_lastname: Priimek +field_mail: E-naslov +field_filename: Datoteka +field_filesize: Velikost +field_downloads: Prenosi +field_author: Avtor +field_created_on: Ustvarjen +field_updated_on: Posodobljeno +field_field_format: Format +field_is_for_all: Za vse projekte +field_possible_values: Možne vrednosti +field_regexp: Regularni izraz +field_min_length: Minimalna dolžina +field_max_length: Maksimalna dolžina +field_value: Vrednost +field_category: Kategorija +field_title: Naslov +field_project: Projekt +field_issue: Zahtevek +field_status: Status +field_notes: Zabeležka +field_is_closed: Zahtevek zaprt +field_is_default: Privzeta vrednost +field_tracker: Vrsta zahtevka +field_subject: Tema +field_due_date: Do datuma +field_assigned_to: Dodeljen +field_priority: Prioriteta +field_fixed_version: Ciljna verzija +field_user: Uporabnik +field_role: Vloga +field_homepage: Domača stran +field_is_public: Javno +field_parent: Podprojekt projekta +field_is_in_chlog: Zahtevki prikazani v zapisu sprememb +field_is_in_roadmap: Zahtevki prikazani na zemljevidu +field_login: Prijava +field_mail_notification: E-poštna oznanila +field_admin: Administrator +field_last_login_on: Zadnjič povezan(a) +field_language: Jezik +field_effective_date: Datum +field_password: Geslo +field_new_password: Novo geslo +field_password_confirmation: Potrditev +field_version: Verzija +field_type: Tip +field_host: Gostitelj +field_port: Vrata +field_account: Račun +field_base_dn: Bazni DN +field_attr_login: Oznaka za prijavo +field_attr_firstname: Oznaka za ime +field_attr_lastname: Oznaka za priimek +field_attr_mail: Oznaka za e-naslov +field_onthefly: Sprotna izdelava uporabnikov +field_start_date: Začetek +field_done_ratio: %% Narejeno +field_auth_source: Način overovljanja +field_hide_mail: Skrij moj e-naslov +field_comments: Komentar +field_url: URL +field_start_page: Začetna stran +field_subproject: Podprojekt +field_hours: Ur +field_activity: Aktivnost +field_spent_on: Datum +field_identifier: Identifikator +field_is_filter: Uporabljen kot filter +field_issue_to_id: Povezan zahtevek +field_delay: Zamik +field_assignable: Zahtevki so lahko dodeljeni tej vlogi +field_redirect_existing_links: Preusmeri obstoječe povezave +field_estimated_hours: Ocenjen čas +field_column_names: Stolpci +field_time_zone: Časovni pas +field_searchable: Zmožen iskanja +field_default_value: Privzeta vrednost +field_comments_sorting: Prikaži komentarje +field_parent_title: Matična stran + +setting_app_title: Naslov aplikacije +setting_app_subtitle: Podnaslov aplikacije +setting_welcome_text: Pozdravno besedilo +setting_default_language: Privzeti jezik +setting_login_required: Zahtevano overovljanje +setting_self_registration: Samostojna registracija +setting_attachment_max_size: Maksimalna velikost priponk +setting_issues_export_limit: Skrajna meja za izvoz zahtevkov +setting_mail_from: E-naslov za emisijo +setting_bcc_recipients: Prejemniki slepih kopij (bcc) +setting_plain_text_mail: navadno e-sporočilo (ne HTML) +setting_host_name: Ime gostitelja in pot +setting_text_formatting: Oblikovanje besedila +setting_wiki_compression: Stiskanje Wiki zgodovine +setting_feeds_limit: Meja obsega RSS virov +setting_default_projects_public: Novi projekti so privzeto javni +setting_autofetch_changesets: Samodejni izvleček zapisa sprememb +setting_sys_api_enabled: Omogoči WS za upravljanje shrambe +setting_commit_ref_keywords: Sklicne ključne besede +setting_commit_fix_keywords: Urejanje ključne besede +setting_autologin: Avtomatska prijava +setting_date_format: Oblika datuma +setting_time_format: Oblika časa +setting_cross_project_issue_relations: Dovoli povezave zahtevkov med različnimi projekti +setting_issue_list_default_columns: Privzeti stolpci prikazani na seznamu zahtevkov +setting_repositories_encodings: Kodiranje shrambe +setting_commit_logs_encoding: Kodiranje sporočil ob predaji +setting_emails_footer: Noga e-sporočil +setting_protocol: Protokol +setting_per_page_options: Število elementov na stran +setting_user_format: Oblika prikaza uporabnikov +setting_activity_days_default: Prikaz dni na aktivnost projekta +setting_display_subprojects_issues: Privzeti prikaz zahtevkov podprojektov v glavnem projektu +setting_enabled_scm: Omogočen SCM +setting_mail_handler_api_enabled: Omogoči WS za prihajajočo e-pošto +setting_mail_handler_api_key: API ključ +setting_sequential_project_identifiers: Generiraj projektne identifikatorje sekvenčno +setting_gravatar_enabled: Uporabljaj Gravatar ikone +setting_diff_max_lines_displayed: Maksimalno število prikazanih vrstic različnosti + +permission_edit_project: Uredi projekt +permission_select_project_modules: Izberi module projekta +permission_manage_members: Uredi člane +permission_manage_versions: Uredi verzije +permission_manage_categories: Urejanje kategorij zahtevkov +permission_add_issues: Dodaj zahtevke +permission_edit_issues: Uredi zahtevke +permission_manage_issue_relations: Uredi odnose med zahtevki +permission_add_issue_notes: Dodaj zabeležke +permission_edit_issue_notes: Uredi zabeležke +permission_edit_own_issue_notes: Uredi lastne zabeležke +permission_move_issues: Premakni zahtevke +permission_delete_issues: Izbriši zahtevke +permission_manage_public_queries: Uredi javna povpraševanja +permission_save_queries: Shrani povpraševanje +permission_view_gantt: Poglej gantogram +permission_view_calendar: Poglej koledar +permission_view_issue_watchers: Oglej si listo spremeljevalcev +permission_add_issue_watchers: Dodaj spremljevalce +permission_log_time: Beleži porabljen čas +permission_view_time_entries: Poglej porabljen čas +permission_edit_time_entries: Uredi beležko časa +permission_edit_own_time_entries: Uredi beležko lastnega časa +permission_manage_news: Uredi novice +permission_comment_news: Komentiraj novice +permission_manage_documents: Uredi dokumente +permission_view_documents: Poglej dokumente +permission_manage_files: Uredi datoteke +permission_view_files: Poglej datoteke +permission_manage_wiki: Uredi wiki +permission_rename_wiki_pages: Preimenuj wiki strani +permission_delete_wiki_pages: Izbriši wiki strani +permission_view_wiki_pages: Poglej wiki +permission_view_wiki_edits: Poglej wiki zgodovino +permission_edit_wiki_pages: Uredi wiki strani +permission_delete_wiki_pages_attachments: Izbriši priponke +permission_protect_wiki_pages: Zaščiti wiki strani +permission_manage_repository: Uredi shrambo +permission_browse_repository: Prebrskaj shrambo +permission_view_changesets: Poglej zapis sprememb +permission_commit_access: Dostop za predajo +permission_manage_boards: Uredi table +permission_view_messages: Poglej sporočila +permission_add_messages: Objavi sporočila +permission_edit_messages: Uredi sporočila +permission_edit_own_messages: Uredi lastna sporočila +permission_delete_messages: Izbriši sporočila +permission_delete_own_messages: Izbriši lastna sporočila + +project_module_issue_tracking: Sledenje zahtevkom +project_module_time_tracking: Sledenje časa +project_module_news: Novice +project_module_documents: Dokumenti +project_module_files: Datoteke +project_module_wiki: Wiki +project_module_repository: Shramba +project_module_boards: Table + +label_user: Uporabnik +label_user_plural: Uporabniki +label_user_new: Nov uporabnik +label_project: Projekt +label_project_new: Nov projekt +label_project_plural: Projekti +label_project_all: Vsi projekti +label_project_latest: Zadnji projekti +label_issue: Zahtevek +label_issue_new: Nov zahtevek +label_issue_plural: Zahtevki +label_issue_view_all: Poglej vse zahtevke +label_issues_by: Zahtevki od %s +label_issue_added: Zahtevek dodan +label_issue_updated: Zahtevek posodobljen +label_document: Dokument +label_document_new: Nov dokument +label_document_plural: Dokumenti +label_document_added: Dokument dodan +label_role: Vloga +label_role_plural: Vloge +label_role_new: Nova vloga +label_role_and_permissions: Vloge in dovoljenja +label_member: Član +label_member_new: Nov član +label_member_plural: Člani +label_tracker: Vrsta zahtevka +label_tracker_plural: Vrste zahtevkov +label_tracker_new: Nova vrsta zahtevka +label_workflow: Potek dela +label_issue_status: Stanje zahtevka +label_issue_status_plural: Stanje zahtevkov +label_issue_status_new: Novo stanje +label_issue_category: Kategorija zahtevka +label_issue_category_plural: Kategorije zahtevkov +label_issue_category_new: Nova kategorija +label_custom_field: Polje po meri +label_custom_field_plural: Polja po meri +label_custom_field_new: Novo polje po meri +label_enumerations: Seznami +label_enumeration_new: Nova vrednost +label_information: Informacija +label_information_plural: Informacije +label_please_login: Prosimo prijavite se +label_register: Registracija +label_password_lost: Izgubljeno geslo +label_home: Domov +label_my_page: Moja stran +label_my_account: Moj račun +label_my_projects: Moji projekti +label_administration: Upravljanje +label_login: Prijavi se +label_logout: Odjavi se +label_help: Pomoč +label_reported_issues: Prijavljeni zahtevki +label_assigned_to_me_issues: Zahtevki dodeljeni meni +label_last_login: Zadnja povezava +label_last_updates: Zadnja posodobitev +label_last_updates_plural: %d zadnje posodobitve +label_registered_on: Registriran +label_activity: Aktivnost +label_overall_activity: Celotna aktivnost +label_user_activity: "Aktivnost %s" +label_new: Nov +label_logged_as: Prijavljen(a) kot +label_environment: Okolje +label_authentication: Overovitev +label_auth_source: Način overovitve +label_auth_source_new: Nov način overovitve +label_auth_source_plural: Načini overovitve +label_subproject_plural: Podprojekti +label_and_its_subprojects: %s in njegovi podprojekti +label_min_max_length: Min - Max dolžina +label_list: Seznam +label_date: Datum +label_integer: Celo število +label_float: Decimalno število +label_boolean: Boolean +label_string: Besedilo +label_text: Dolgo besedilo +label_attribute: Lastnost +label_attribute_plural: Lastnosti +label_download: %d Prenos +label_download_plural: %d Prenosi +label_no_data: Ni podatkov za prikaz +label_change_status: Spremeni stanje +label_history: Zgodovina +label_attachment: Datoteka +label_attachment_new: Nova datoteka +label_attachment_delete: Izbriši datoteko +label_attachment_plural: Datoteke +label_file_added: Datoteka dodana +label_report: Poročilo +label_report_plural: Poročila +label_news: Novica +label_news_new: Dodaj novico +label_news_plural: Novice +label_news_latest: Zadnje novice +label_news_view_all: Poglej vse novice +label_news_added: Dodane novice +label_change_log: Zapisnik spremeb +label_settings: Nastavitve +label_overview: Pregled +label_version: Verzija +label_version_new: Nova verzija +label_version_plural: Verzije +label_confirmation: Potrditev +label_export_to: 'Na razpolago tudi v:' +label_read: Preberi... +label_public_projects: Javni projekti +label_open_issues: odpri zahtevek +label_open_issues_plural: odpri zahtevke +label_closed_issues: zapri zahtevek +label_closed_issues_plural: zapri zahtevke +label_total: Skupaj +label_permissions: Dovoljenja +label_current_status: Trenutno stanje +label_new_statuses_allowed: Novi zahtevki dovoljeni +label_all: vsi +label_none: noben +label_nobody: nihče +label_next: Naslednji +label_previous: Prejšnji +label_used_by: V uporabi od +label_details: Podrobnosti +label_add_note: Dodaj zabeležko +label_per_page: Na stran +label_calendar: Koledar +label_months_from: mesecev od +label_gantt: Gantt +label_internal: Notranji +label_last_changes: zadnjih %d sprememb +label_change_view_all: Poglej vse spremembe +label_personalize_page: Individualiziraj to stran +label_comment: Komentar +label_comment_plural: Komentarji +label_comment_add: Dodaj komentar +label_comment_added: Komentar dodan +label_comment_delete: Izbriši komentarje +label_query: Iskanje po meri +label_query_plural: Iskanja po meri +label_query_new: Novo iskanje +label_filter_add: Dodaj filter +label_filter_plural: Filtri +label_equals: je enako +label_not_equals: ni enako +label_in_less_than: v manj kot +label_in_more_than: v več kot +label_in: v +label_today: danes +label_all_time: v vsem času +label_yesterday: včeraj +label_this_week: ta teden +label_last_week: pretekli teden +label_last_n_days: zadnjih %d dni +label_this_month: ta mesec +label_last_month: zadnji mesec +label_this_year: to leto +label_date_range: Razpon datumov +label_less_than_ago: manj kot dni nazaj +label_more_than_ago: več kot dni nazaj +label_ago: dni nazaj +label_contains: vsebuje +label_not_contains: ne vsebuje +label_day_plural: dni +label_repository: Shramba +label_repository_plural: Shrambe +label_browse: Prebrskaj +label_modification: %d sprememba +label_modification_plural: %d spremembe +label_revision: Revizija +label_revision_plural: Revizije +label_associated_revisions: Povezane revizije +label_added: dodano +label_modified: spremenjeno +label_copied: kopirano +label_renamed: preimenovano +label_deleted: izbrisano +label_latest_revision: Zadnja revizija +label_latest_revision_plural: Zadnje revizije +label_view_revisions: Poglej revizije +label_max_size: Največja velikost +label_on: 'na' +label_sort_highest: Premakni na vrh +label_sort_higher: Premakni gor +label_sort_lower: Premakni dol +label_sort_lowest: Premakni na dno +label_roadmap: Načrt +label_roadmap_due_in: Do %s +label_roadmap_overdue: %s zakasnel +label_roadmap_no_issues: Ni zahtevkov za to verzijo +label_search: Išči +label_result_plural: Rezultati +label_all_words: Vse besede +label_wiki: Wiki +label_wiki_edit: Wiki urejanje +label_wiki_edit_plural: Wiki urejanja +label_wiki_page: Wiki stran +label_wiki_page_plural: Wiki strani +label_index_by_title: Razvrsti po naslovu +label_index_by_date: Razvrsti po datumu +label_current_version: Trenutna verzija +label_preview: Predogled +label_feed_plural: RSS viri +label_changes_details: Podrobnosti o vseh spremembah +label_issue_tracking: Sledenje zahtevkom +label_spent_time: Porabljen čas +label_f_hour: %.2f ura +label_f_hour_plural: %.2f ur +label_time_tracking: Sledenje času +label_change_plural: Spremembe +label_statistics: Statistika +label_commits_per_month: Predaj na mesec +label_commits_per_author: Predaj na avtorja +label_view_diff: Preglej razlike +label_diff_inline: znotraj +label_diff_side_by_side: vzporedno +label_options: Možnosti +label_copy_workflow_from: Kopiraj potek dela od +label_permissions_report: Poročilo o dovoljenjih +label_watched_issues: Spremljani zahtevki +label_related_issues: Povezani zahtevki +label_applied_status: Uveljavljeno stanje +label_loading: Nalaganje... +label_relation_new: Nova povezava +label_relation_delete: Izbriši povezavo +label_relates_to: povezan z +label_duplicates: duplikati +label_duplicated_by: dupliciral +label_blocks: blok +label_blocked_by: blokiral +label_precedes: ima prednost pred +label_follows: sledi +label_end_to_start: konec na začetek +label_end_to_end: konec na konec +label_start_to_start: začetek na začetek +label_start_to_end: začetek na konec +label_stay_logged_in: Ostani prijavljen(a) +label_disabled: onemogoči +label_show_completed_versions: Prikaži zaključene verzije +label_me: jaz +label_board: Forum +label_board_new: Nov forum +label_board_plural: Forumi +label_topic_plural: Teme +label_message_plural: Sporočila +label_message_last: Zadnje sporočilo +label_message_new: Novo sporočilo +label_message_posted: Sporočilo dodano +label_reply_plural: Odgovori +label_send_information: Pošlji informacijo o računu uporabniku +label_year: Leto +label_month: Mesec +label_week: Teden +label_date_from: Od +label_date_to: Do +label_language_based: Glede na uporabnikov jezik +label_sort_by: Razporedi po %s +label_send_test_email: Pošlji testno e-pismo +label_feeds_access_key_created_on: RSS dostopni ključ narejen %s nazaj +label_module_plural: Moduli +label_added_time_by: Dodal(a) %s %s nazaj +label_updated_time_by: Posodobljen od %s %s nazaj +label_updated_time: Posodobljen %s nazaj +label_jump_to_a_project: Skoči na projekt... +label_file_plural: Datoteke +label_changeset_plural: Zapisi sprememb +label_default_columns: Privzeti stolpci +label_no_change_option: (Ni spremembe) +label_bulk_edit_selected_issues: Uredi izbrane zahtevke skupaj +label_theme: Tema +label_default: Privzeto +label_search_titles_only: Preišči samo naslove +label_user_mail_option_all: "Za vsak dogodek v vseh mojih projektih" +label_user_mail_option_selected: "Za vsak dogodek samo na izbranih projektih..." +label_user_mail_option_none: "Samo za zadeve ki jih spremljam ali sem v njih udeležen(a)" +label_user_mail_no_self_notified: "Ne želim biti opozorjen(a) na spremembe, ki jih naredim sam(a)" +label_registration_activation_by_email: aktivacija računa po e-pošti +label_registration_manual_activation: ročna aktivacija računa +label_registration_automatic_activation: samodejna aktivacija računa +label_display_per_page: 'Na stran: %s' +label_age: Starost +label_change_properties: Sprememba lastnosti +label_general: Splošno +label_more: Več +label_scm: SCM +label_plugins: Vtičniki +label_ldap_authentication: LDAP overovljanje +label_downloads_abbr: D/L +label_optional_description: Neobvezen opis +label_add_another_file: Dodaj še eno datoteko +label_preferences: Preference +label_chronological_order: Kronološko +label_reverse_chronological_order: Obrnjeno kronološko +label_planning: Načrtovanje +label_incoming_emails: Prihajajoča e-pošta +label_generate_key: Ustvari ključ +label_issue_watchers: Spremljevalci +label_example: Vzorec + +button_login: Prijavi se +button_submit: Pošlji +button_save: Shrani +button_check_all: Označi vse +button_uncheck_all: Odznači vse +button_delete: Izbriši +button_create: Ustvari +button_test: Testiraj +button_edit: Uredi +button_add: Dodaj +button_change: Spremeni +button_apply: Uporabi +button_clear: Počisti +button_lock: Zakleni +button_unlock: Odkleni +button_download: Prenesi +button_list: Seznam +button_view: Pogled +button_move: Premakni +button_back: Nazaj +button_cancel: Prekliči +button_activate: Aktiviraj +button_sort: Razvrsti +button_log_time: Beleži čas +button_rollback: Povrni na to verzijo +button_watch: Spremljaj +button_unwatch: Ne spremljaj +button_reply: Odgovori +button_archive: Arhiviraj +button_unarchive: Odarhiviraj +button_reset: Ponastavi +button_rename: Preimenuj +button_change_password: Spremeni geslo +button_copy: Kopiraj +button_annotate: Zapiši pripombo +button_update: Posodobi +button_configure: Konfiguriraj +button_quote: Citiraj + +status_active: aktivni +status_registered: registriran +status_locked: zaklenjen + +text_select_mail_notifications: Izberite dejanja za katera naj bodo poslana oznanila preko e-pošto. +text_regexp_info: npr. ^[A-Z0-9]+$ +text_min_max_length_info: 0 pomeni brez omejitev +text_project_destroy_confirmation: Ali ste prepričani da želite izbrisati izbrani projekt in vse z njim povezane podatke? +text_subprojects_destroy_warning: 'Njegov(i) podprojekt(i): %s bodo prav tako izbrisani.' +text_workflow_edit: Izberite vlogo in zahtevek za urejanje poteka dela +text_are_you_sure: Ali ste prepričani? +text_journal_changed: Spremenjen iz %s na %s +text_journal_set_to: Nastavi na %s +text_journal_deleted: izbrisan +text_tip_task_begin_day: naloga z začetkom na ta dan +text_tip_task_end_day: naloga z zaključkom na ta dan +text_tip_task_begin_end_day: naloga ki se začne in konča ta dan +text_project_identifier_info: 'Dovoljene so samo male črke (a-z), številke in vezaji.
    Enkrat shranjen identifikator ne more biti spremenjen.' +text_caracters_maximum: največ %d znakov. +text_caracters_minimum: Mora biti dolgo vsaj %d znake. +text_length_between: Dolžina med %d in %d znaki. +text_tracker_no_workflow: Potek dela za to vrsto zahtevka ni določen +text_unallowed_characters: Nedovoljeni znaki +text_comma_separated: Dovoljenih je več vrednosti (ločenih z vejico). +text_issues_ref_in_commit_messages: Zahtevki sklicev in popravkov v sporočilu predaje +text_issue_added: Zahtevek %s je sporočil(a) %s. +text_issue_updated: Zahtevek %s je posodobil(a) %s. +text_wiki_destroy_confirmation: Ali ste prepričani da želite izbrisati ta wiki in vso njegovo vsebino? +text_issue_category_destroy_question: Nekateri zahtevki (%d) so dodeljeni tej kategoriji. Kaj želite storiti? +text_issue_category_destroy_assignments: Odstrani naloge v kategoriji +text_issue_category_reassign_to: Ponovno dodeli zahtevke tej kategoriji +text_user_mail_option: "Na neizbrane projekte boste prejemali le obvestila o zadevah ki jih spremljate ali v katere ste vključeni (npr. zahtevki katerih avtor(ica) ste)" +text_no_configuration_data: "Vloge, vrste zahtevkov, statusi zahtevkov in potek dela še niso bili določeni. \nZelo priporočljivo je, da naložite privzeto konfiguracijo, ki jo lahko kasneje tudi prilagodite." +text_load_default_configuration: Naloži privzeto konfiguracijo +text_status_changed_by_changeset: Dodano v zapis sprememb %s. +text_issues_destroy_confirmation: 'Ali ste prepričani, da želite izbrisati izbrani(e) zahtevek(ke)?' +text_select_project_modules: 'Izberite module, ki jih želite omogočiti za ta projekt:' +text_default_administrator_account_changed: Spremenjen privzeti administratorski račun +text_file_repository_writable: Omogočeno pisanje v shrambo datotek +text_rmagick_available: RMagick je na voljo(neobvezno) +text_destroy_time_entries_question: %.02f ur je bilo opravljenih na zahtevku, ki ga želite izbrisati. Kaj želite storiti? +text_destroy_time_entries: Izbriši opravljene ure +text_assign_time_entries_to_project: Predaj opravljene ure projektu +text_reassign_time_entries: 'Prenesi opravljene ure na ta zahtevek:' +text_user_wrote: '%s je napisal(a):' +text_enumeration_destroy_question: '%d objektov je določenih tej vrednosti.' +text_enumeration_category_reassign_to: 'Ponastavi jih na to vrednost:' +text_email_delivery_not_configured: "E-poštna dostava ni nastavljena in oznanila so onemogočena.\nNastavite vaš SMTP strežnik v config/email.yml in ponovno zaženite aplikacijo da ga omogočite.\n" +text_repository_usernames_mapping: "Izberite ali posodobite Redmine uporabnika dodeljenega vsakemu uporabniškemu imenu najdenemu v zapisniku shrambe.\n Uporabniki z enakim Redmine ali shrambinem uporabniškem imenu ali e-poštnem naslovu so samodejno dodeljeni." +text_diff_truncated: '... Ta sprememba je bila odsekana ker presega največjo velikost ki je lahko prikazana.' + +default_role_manager: Upravnik +default_role_developper: Razvijalec +default_role_reporter: Poročevalec +default_tracker_bug: Hrošč +default_tracker_feature: Funkcija +default_tracker_support: Podpora +default_issue_status_new: Nov +default_issue_status_assigned: Dodeljen +default_issue_status_resolved: Rešen +default_issue_status_feedback: Povratna informacija +default_issue_status_closed: Zaključen +default_issue_status_rejected: Zavrnjen +default_doc_category_user: Uporabniška dokumentacija +default_doc_category_tech: Tehnična dokumentacija +default_priority_low: Nizka +default_priority_normal: Običajna +default_priority_high: Visoka +default_priority_urgent: Urgentna +default_priority_immediate: Takojšnje ukrepanje +default_activity_design: Oblikovanje +default_activity_development: Razvoj + +enumeration_issue_priorities: Prioritete zahtevkov +enumeration_doc_categories: Kategorije dokumentov +enumeration_activities: Aktivnosti (sledenje časa) +setting_repository_log_display_limit: Maximum number of revisions displayed on file log +warning_attachments_not_saved: "%d file(s) could not be saved." +field_editable: Editable +text_plugin_assets_writable: Plugin assets directory writable +label_display: Display +button_create_and_continue: Create and continue +text_custom_field_possible_values_info: 'One line for each value' +field_identity_url: OpenID URL +setting_openid: Allow OpenID login and registration +label_login_with_open_id_option: or login with OpenID +field_watcher: Watcher diff --git a/lang/sr.yml b/lang/sr.yml index 3ac7b7cd9..7455d20e0 100644 --- a/lang/sr.yml +++ b/lang/sr.yml @@ -34,7 +34,7 @@ activerecord_error_not_a_number: nije broj activerecord_error_not_a_date: nije datum activerecord_error_greater_than_start_date: mora biti veći od početnog datuma activerecord_error_not_same_project: ne pripada istom projektu -activerecord_error_circular_dependency: Ova relacija bi kreirala kružnu zavisnost +activerecord_error_circular_dependency: Ova relacija bi napravila kružnu zavisnost general_fmt_age: %d g general_fmt_age_plural: %d god. @@ -51,24 +51,24 @@ general_csv_separator: ',' general_csv_decimal_separator: '.' general_csv_encoding: ISO-8859-1 general_pdf_encoding: ISO-8859-1 -general_day_names: Ponedeljak, Utorak, Sreda, četvrtak, Petak, Subota, Nedelja +general_day_names: Ponedeljak, Utorak, Sreda, Četvrtak, Petak, Subota, Nedelja general_first_day_of_week: '1' -notice_account_updated: Nalog je uspešno izmenjen. +notice_account_updated: Nalog je uspešno promenjen. notice_account_invalid_creditentials: Pogrešan korisnik ili lozinka -notice_account_password_updated: Lozinka je uspešno izmenjena. +notice_account_password_updated: Lozinka je uspešno promenjena. notice_account_wrong_password: Pogrešna lozinka -notice_account_register_done: Nalog je uspešno kreiran. Da bi ste aktivirali vaš nalog kliknite na link koji vam je poslat. +notice_account_register_done: Nalog je uspešno napravljen. Da bi ste aktivirali vaš nalog kliknite na link koji vam je poslat. notice_account_unknown_email: Nepoznati korisnik. notice_can_t_change_password: Ovaj nalog koristi eksterni izvor prijavljivanja. Ne mogu da promenim šifru. notice_account_lost_email_sent: Email sa uputstvima o izboru nove šifre je poslat na vašu adresu. notice_account_activated: Vaš nalog je aktiviran. Možete se ulogovati. notice_successful_create: Uspešna kreacija. -notice_successful_update: Uspešna izmena. +notice_successful_update: Uspešna promena. notice_successful_delete: Uspešno brisanje. notice_successful_connection: Uspešna konekcija. notice_file_not_found: Stranica kojoj pokušavate da pristupite ne postoji ili je uklonjena. -notice_locking_conflict: Podaci su izmenjeni od strane drugog korisnika. +notice_locking_conflict: Podaci su promenjeni od strane drugog korisnika. notice_not_authorized: Niste ovlašćeni da pristupite ovoj stranici. notice_email_sent: Email je poslat %s notice_email_error: Došlo je do greške pri slanju maila (%s) @@ -77,13 +77,13 @@ notice_failed_to_save_issues: "Neuspešno snimanje %d kartica na %d izabrano: %s notice_no_issue_selected: "Nijedna kartica nije izabrana! Molim, izaberite kartice koje želite za editujete." error_scm_not_found: "Unos i/ili revizija ne postoji u spremištu." -error_scm_command_failed: "An error occurred when trying to access the repository: %s" +error_scm_command_failed: "Došlo je do greške pri pristupanju spremištu: %s" mail_subject_lost_password: Vaša %s lozinka -mail_body_lost_password: 'Da biste izmenili vašu lozinku, kliknite na sledeći link:' -mail_subject_register: Aktivacija %s naloga +mail_body_lost_password: 'Da biste promenili vašu lozinku, kliknite na sledeći link:' +mail_subject_register: Aktivacija naloga %s mail_body_register: 'Da biste aktivirali vaš nalog, kliknite na sledeći link:' -mail_body_account_information_external: Mozete koristiti vas "%s" nalog da bi ste se prikljucili. +mail_body_account_information_external: Mozete koristiti vas nalog "%s" da bi ste se prikljucili. mail_body_account_information: Informacije o vasem nalogu gui_validation_error: 1 greška @@ -96,12 +96,12 @@ field_is_required: Zahtevano field_firstname: Ime field_lastname: Prezime field_mail: Email -field_filename: File +field_filename: Fajl field_filesize: Veličina -field_downloads: Downloads +field_downloads: Preuzimanja field_author: Autor -field_created_on: Kreirano -field_updated_on: Izmenjeno +field_created_on: Postavljeno +field_updated_on: Promenjeno field_field_format: Format field_is_for_all: Za sve projekte field_possible_values: Moguće vrednosti @@ -115,25 +115,25 @@ field_project: Projekat field_issue: Kartica field_status: Status field_notes: Beleške -field_is_closed: Greška zatvorena +field_is_closed: Kartica zatvorena field_is_default: Podrazumevana vrednost -field_tracker: Tracker -field_subject: Subjekat +field_tracker: Vrsta +field_subject: Tema field_due_date: Do datuma field_assigned_to: Dodeljeno field_priority: Prioritet -field_fixed_version: Target version +field_fixed_version: Verzija field_user: Korisnik field_role: Uloga field_homepage: Homepage field_is_public: Javni -field_parent: Podprojekat od -field_is_in_chlog: Kartice se prikazuju u changelog-u -field_is_in_roadmap: Kartice se prikazuju u roadmap-u -field_login: Login +field_parent: Potprojekat od +field_is_in_chlog: Kartice se prikazuju u dnevniku promena +field_is_in_roadmap: Kartice se prikazuju u Redosledu +field_login: Korisnik field_mail_notification: Obaveštavanje putem mail-a field_admin: Administrator -field_last_login_on: Poslednja konekcija +field_last_login_on: Poslednje prijavljivanje field_language: Jezik field_effective_date: Datum field_password: Lozinka @@ -150,14 +150,14 @@ field_attr_firstname: Atribut imena field_attr_lastname: Atribut prezimena field_attr_mail: Atribut email-a field_onthefly: Kreacija naloga "On-the-fly" -field_start_date: Start +field_start_date: Početak field_done_ratio: %% Završeno field_auth_source: Vrsta prijavljivanja field_hide_mail: Sakrij moju email adresu field_comments: Komentar field_url: URL field_start_page: Početna strana -field_subproject: Podprojekat +field_subproject: Potprojekat field_hours: Sati field_activity: Aktivnost field_spent_on: Datum @@ -175,7 +175,7 @@ setting_app_title: Naziv aplikacije setting_app_subtitle: Podnaslov aplikacije setting_welcome_text: Tekst dobrodošlice setting_default_language: Podrazumevani jezik -setting_login_required: Prijavljivanje obaveyno +setting_login_required: Prijavljivanje je obavezno setting_self_registration: Samoregistracija je dozvoljena setting_attachment_max_size: Maksimalna velicina Attachment-a setting_issues_export_limit: Max broj kartica u exportu @@ -188,27 +188,28 @@ setting_autofetch_changesets: Autofetch commits setting_sys_api_enabled: Ukljuci WS za menadžment spremišta setting_commit_ref_keywords: Referentne ključne reči setting_commit_fix_keywords: Fiksne ključne reči -setting_autologin: Autologin +setting_autologin: Automatsko prijavljivanje setting_date_format: Format datuma setting_cross_project_issue_relations: Dozvoli relacije kartica između različitih projekata setting_issue_list_default_columns: Podrazumevana kolona se prikazuje na listi kartica setting_repositories_encodings: Kodna stranica spremišta setting_emails_footer: Zaglavlje emaila +label_example: Primer label_user: Korisnik label_user_plural: Korisnici label_user_new: Novi korisnik label_project: Projekat label_project_new: Novi projekat label_project_plural: Projekti -label_project_all: Svi Projekti +label_project_all: Svi projekti label_project_latest: Poslednji projekat label_issue: Kartica label_issue_new: Nova kartica label_issue_plural: Kartice label_issue_view_all: Pregled svih kartica -label_document: Dokumenat -label_document_new: Novi dokumenat +label_document: Dokument +label_document_new: Novi dokument label_document_plural: Dokumenti label_role: Uloga label_role_plural: Uloge @@ -217,39 +218,39 @@ label_role_and_permissions: Uloge i prava label_member: Član label_member_new: Novi član label_member_plural: Članovi -label_tracker: Tracker -label_tracker_plural: Trackers -label_tracker_new: Novi tracker +label_tracker: Vrsta +label_tracker_plural: Vrste +label_tracker_new: Nova vrsta label_workflow: Tok rada label_issue_status: Status kartice label_issue_status_plural: Statusi kartica label_issue_status_new: Novi status -label_issue_category: Kategorij kartice +label_issue_category: Kategorija kartice label_issue_category_plural: Kategorije kartica label_issue_category_new: Nova kategorija label_custom_field: Korisnički definisano polje label_custom_field_plural: Korisnički definisana polja label_custom_field_new: Novo korisnički definisano polje -label_enumerations: Enumeracije +label_enumerations: Konstante label_enumeration_new: Nova vrednost label_information: Informacija label_information_plural: Informacije -label_please_login: Molim ulogujte se +label_please_login: Molim prijavite se label_register: Registracija label_password_lost: Izgubljena lozinka -label_home: Home -label_my_page: Moja Stranica +label_home: Naslovna stranica +label_my_page: Moja stranica label_my_account: Moj nalog label_my_projects: Moji projekti label_administration: Administracija -label_login: Login -label_logout: Logout +label_login: Korisnik +label_logout: Odjavi me label_help: Pomoć label_reported_issues: Prijavljene kartice -label_assigned_to_me_issues: Kartice meni dodeljene -label_last_login: Poslednja konekcija -label_last_updates: Poslednje izmene -label_last_updates_plural: %d poslednje izmenjene +label_assigned_to_me_issues: Moje kartice +label_last_login: Poslednje prijavljivanje +label_last_updates: Poslednje promene +label_last_updates_plural: %d poslednje promenjene label_registered_on: Registrovano label_activity: Aktivnost label_new: Novo @@ -259,8 +260,8 @@ label_authentication: Prijavljivanje label_auth_source: Način prijavljivanja label_auth_source_new: Novi način prijavljivanja label_auth_source_plural: Načini prijavljivanja -label_subproject_plural: Podprojekti -label_min_max_length: Min - Max velicina +label_subproject_plural: Potprojekti +label_min_max_length: Min - Max veličina label_list: Liste label_date: Datum label_integer: Integer @@ -272,7 +273,7 @@ label_attribute_plural: Atributi label_download: %d Download label_download_plural: %d Downloads label_no_data: Nema podataka za prikaz -label_change_status: Izmena statusa +label_change_status: Promena statusa label_history: Istorija label_attachment: Fajl label_attachment_new: Novi fajl @@ -281,13 +282,13 @@ label_attachment_plural: Fajlovi label_report: Izveštaj label_report_plural: Izveštaji label_news: Novosti -label_news_new: Dodaj novosti +label_news_new: Dodaj novost label_news_plural: Novosti label_news_latest: Poslednje novosti label_news_view_all: Pregled svih novosti -label_change_log: Change log +label_change_log: Dnevnik promena label_settings: Podešavanja -label_overview: Overview +label_overview: Pregled label_version: Verzija label_version_new: Nova verzija label_version_plural: Verzije @@ -296,9 +297,9 @@ label_export_to: Izvoz u label_read: Čitaj... label_public_projects: Javni projekti label_open_issues: Otvoren -label_open_issues_plural: Otvoreni -label_closed_issues: Zatvoreni -label_closed_issues_plural: Zatvoreni +label_open_issues_plural: Otvoreno +label_closed_issues: Zatvoren +label_closed_issues_plural: Zatvoreno label_total: Ukupno label_permissions: Dozvole label_current_status: Trenutni status @@ -317,8 +318,8 @@ label_calendar: Kalendar label_months_from: Meseci od label_gantt: Gantt label_internal: Interno -label_last_changes: Poslednjih %d izmena -label_change_view_all: Prikaz svih izmena +label_last_changes: Poslednjih %d promena +label_change_view_all: Prikaz svih promena label_personalize_page: Personalizuj ovu stranicu label_comment: Komentar label_comment_plural: Komentari @@ -332,26 +333,26 @@ label_filter_add: Dodaj filter label_filter_plural: Filter label_equals: je label_not_equals: nije -label_in_less_than: je manji od -label_in_more_than: je veci od -label_in: u +label_in_less_than: za manje od +label_in_more_than: za više od +label_in: za tačno label_today: danas label_this_week: ove nedelje -label_less_than_ago: manje nego dana -label_more_than_ago: više nego dana -label_ago: pre dana +label_less_than_ago: pre manje od +label_more_than_ago: pre više od +label_ago: pre tačno label_contains: Sadrži label_not_contains: ne sadrži label_day_plural: dana label_repository: Spremište label_browse: Pregled -label_modification: %d izmena -label_modification_plural: %d izmena +label_modification: %d promena +label_modification_plural: %d promena label_revision: Revizija label_revision_plural: Revizije label_added: dodato label_modified: modifikovano -label_deleted: izmenjeno +label_deleted: promenjeno label_latest_revision: Poslednja revizija label_latest_revision_plural: Poslednje revizije label_view_revisions: Pregled revizija @@ -361,7 +362,7 @@ label_sort_highest: Premesti na vrh label_sort_higher: premesti na gore label_sort_lower: Premesti na dole label_sort_lowest: Premesti na dno -label_roadmap: Roadmap +label_roadmap: Redosled label_roadmap_due_in: Završava se za %s label_roadmap_overdue: %s kasni label_roadmap_no_issues: Nema kartica za ovu verziju @@ -369,8 +370,8 @@ label_search: Traži label_result_plural: Rezultati label_all_words: Sve reči label_wiki: Wiki -label_wiki_edit: Wiki izmena -label_wiki_edit_plural: Wiki izmene +label_wiki_edit: Wiki promena +label_wiki_edit_plural: Wiki promene label_wiki_page: Wiki stranica label_wiki_page_plural: Wiki stranice label_index_by_title: Indeks po naslovima @@ -378,13 +379,13 @@ label_index_by_date: Indeks po datumu label_current_version: Trenutna verzija label_preview: Brzi pregled label_feed_plural: Feeds -label_changes_details: Detalji svih izmena +label_changes_details: Detalji svih promena label_issue_tracking: Praćenje kartica -label_spent_time: Potrošeno vremena +label_spent_time: Utrošeno vremena label_f_hour: %.2f časa label_f_hour_plural: %.2f časova label_time_tracking: Praćenje vremena -label_change_plural: Izmene +label_change_plural: Promene label_statistics: Statistika label_commits_per_month: Commit-a po mesecu label_commits_per_author: Commit-a po autoru @@ -395,7 +396,7 @@ label_options: Opcije label_copy_workflow_from: Kopiraj tok rada od label_permissions_report: Izveštaj o dozvolama label_watched_issues: Praćene kartice -label_related_issues: Kartice u vezi +label_related_issues: Povezane kartice label_applied_status: Primenjen status label_loading: Učitavam... label_relation_new: Nova relacija @@ -429,18 +430,18 @@ label_week: Nedelja label_date_from: Od label_date_to: Do label_language_based: Bazirano na jeziku -label_sort_by: Sortiraj po %s +label_sort_by: Uredi po %s label_send_test_email: Pošalji probni email -label_feeds_access_key_created_on: RSS ključ za pristup je kreiran pre %s -label_module_plural: Modulovi +label_feeds_access_key_created_on: RSS ključ za pristup je napravljen pre %s +label_module_plural: Moduli label_added_time_by: Dodato pre %s %s -label_updated_time: Izmenjeno pre %s +label_updated_time: Promenjeno pre %s label_jump_to_a_project: Prebaci se na projekat... label_file_plural: Fajlovi -label_changeset_plural: Skupovi izmena +label_changeset_plural: Skupovi promena label_default_columns: Podrazumevane kolone -label_no_change_option: (Bez izmena) -label_bulk_edit_selected_issues: Zajednička izmena izabranih kartica +label_no_change_option: (Bez promena) +label_bulk_edit_selected_issues: Zajednička promena izabranih kartica label_theme: Tema label_default: Podrazumevana label_search_titles_only: Pretraga samo naslova @@ -448,39 +449,39 @@ label_user_mail_option_all: "Za bilo koji događaj na svim mojim projektima" label_user_mail_option_selected: "Za bilo koji događaj za samo izabrane projekte..." label_user_mail_option_none: "Samo za stvari koje pratim ili u kojima učestvujem" -button_login: Login +button_login: Prijavi button_submit: Pošalji -button_save: Snimi +button_save: Sačuvaj button_check_all: Označi sve button_uncheck_all: Isključi sve -button_delete: Briši -button_create: Kreiraj -button_test: Testiraj -button_edit: Izmene -button_add: Dodavanje -button_change: Izmena -button_apply: Primena -button_clear: Brisanje -button_lock: Zaključavanje -button_unlock: Odključavanje -button_download: Download -button_list: Lista +button_delete: Obriši +button_create: Napravi +button_test: Proveri +button_edit: Menjanje +button_add: Dodaj +button_change: Promeni +button_apply: Primeni +button_clear: Poništi +button_lock: Zaključaj +button_unlock: Otključaj +button_download: Preuzmi +button_list: Spisak button_view: Pregled -button_move: Premeštanje +button_move: Premesti button_back: Nazad -button_cancel: Odustajanje +button_cancel: Odustani button_activate: Aktiviraj -button_sort: Sortiranje -button_log_time: Log time +button_sort: Uredi +button_log_time: Zapiši vreme button_rollback: Izvrši rollback na ovu verziju -button_watch: Praćenje -button_unwatch: Prekid praćenja -button_reply: Odgovor -button_archive: Arhiviranje -button_unarchive: Dearhiviranje -button_reset: Reset -button_rename: Promena imena -button_change_password: Izmena lozinke +button_watch: Prati +button_unwatch: Prekini praćenje +button_reply: Odgovori +button_archive: Arhiviraj +button_unarchive: Dearhiviraj +button_reset: Poništi +button_rename: Promeni ime +button_change_password: Promeni lozinku status_active: aktivan status_registered: registrovan @@ -492,7 +493,7 @@ text_min_max_length_info: 0 znači bez restrikcija text_project_destroy_confirmation: Da li ste sigurni da želite da izbrišete ovaj projekat i sve njegove podatke? text_workflow_edit: Select a role and a tracker to edit the workflow text_are_you_sure: Da li ste sigurni ? -text_journal_changed: izmenjen iz %s u %s +text_journal_changed: promenjen iz %s u %s text_journal_set_to: postavi na %s text_journal_deleted: izbrisano text_tip_task_begin_day: Zadaci koji počinju ovog dana @@ -506,12 +507,12 @@ text_unallowed_characters: Nedozvoljeni karakteri text_comma_separated: Višestruke vrednosti su dozvoljene (razdvojene zarezom). text_issues_ref_in_commit_messages: Referencing and fixing issues in commit messages text_issue_added: Kartica %s je prijavljena (by %s). -text_issue_updated: Kartica %s je izmenjena (by %s). +text_issue_updated: Kartica %s je promenjena (by %s). text_wiki_destroy_confirmation: Da li ste sigurni da želite da izbrišete ovaj wiki i svu njegovu sadržinu ? text_issue_category_destroy_question: Neke kartice (%d) su dodeljene ovoj kategoriji. Šta želite da uradite ? text_issue_category_destroy_assignments: Ukloni dodeljivanje kategorija text_issue_category_reassign_to: Ponovo dodeli kartice ovoj kategoriji -text_user_mail_option: "Za neizabrane projekte, primaćete obaveštenja samo o stvarima koje pratite ili u kojima učestvujete (npr. kartice koje ste vi kreirali ili koje su vama dodeljene)." +text_user_mail_option: "Za neizabrane projekte, primaćete obaveštenja samo o stvarima koje pratite ili u kojima učestvujete (npr. kartice koje ste vi napravili ili koje su vama dodeljene)." default_role_manager: Menadžer default_role_developper: Developer @@ -528,7 +529,7 @@ default_issue_status_rejected: Odbačeno default_doc_category_user: Korisnička dokumentacija default_doc_category_tech: Tehnička dokumentacija default_priority_low: Nizak -default_priority_normal: Normalan +default_priority_normal: Redovan default_priority_high: Visok default_priority_urgent: Hitan default_priority_immediate: Odmah @@ -539,16 +540,16 @@ enumeration_issue_priorities: Prioriteti kartica enumeration_doc_categories: Kategorija dokumenata enumeration_activities: Aktivnosti (praćenje vremena)) label_float: Float -button_copy: Copy +button_copy: Iskopiraj setting_protocol: Protocol -label_user_mail_no_self_notified: "Ne želim da budem obaveštavan o izmenama koje sam pravim" +label_user_mail_no_self_notified: "Ne želim da budem obaveštavan o promenama koje sam pravim" setting_time_format: Format vremena label_registration_activation_by_email: aktivacija naloga putem email-a mail_subject_account_activation_request: %s zahtev za aktivacijom naloga mail_body_account_activation_request: 'Novi korisnik (%s) se registrovao. Njegov nalog čeka vaše odobrenje:' label_registration_automatic_activation: automatska aktivacija naloga label_registration_manual_activation: ručna aktivacija naloga -notice_account_pending: "Vaš nalog je kreiran i čeka odobrenje administratora." +notice_account_pending: "Vaš nalog je napravljen i čeka odobrenje administratora." field_time_zone: Vremenska zona text_caracters_minimum: Mora biti minimum %d karaktera dugačka. setting_bcc_recipients: '"Blind carbon copy" primaoci (bcc)' @@ -562,23 +563,23 @@ 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 +button_update: Promeni +label_change_properties: Promeni svojstva +label_general: Opšte +label_repository_plural: Spremišta +label_associated_revisions: Dodeljene revizije setting_user_format: Users display format text_status_changed_by_changeset: Applied in changeset %s. -label_more: More +label_more: Još 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 +label_issue_added: Kartica dodata +label_issue_updated: Kartica promenjena +label_document_added: Dokument dodat +label_message_posted: Poruka dodata +label_file_added: Fajl dodat +label_news_added: Novost dodata project_module_boards: Boards project_module_issue_tracking: Issue tracking project_module_wiki: Wiki @@ -594,52 +595,116 @@ button_configure: Configure label_plugins: Plugins label_ldap_authentication: LDAP authentication label_downloads_abbr: D/L -label_this_month: this month -label_last_n_days: last %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 +label_this_month: ovog meseca +label_last_n_days: poslednjih %d dana +label_all_time: sva vremena +label_this_year: ove godine +label_date_range: Raspon datuma +label_last_week: prošle nedelje +label_yesterday: juče +label_last_month: prošlog meseca +label_add_another_file: Dodaj još jedan fajl +label_optional_description: Opcioni opis 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 +label_chronological_order: U hronološkom redosledu field_comments_sorting: Display comments -label_reverse_chronological_order: In reverse chronological order +label_reverse_chronological_order: U obrnutom hronološkom redosledu label_preferences: Preferences setting_display_subprojects_issues: Display subprojects issues on main projects by default -label_overall_activity: Overall activity +label_overall_activity: Ukupna aktivnost 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.' -label_and_its_subprojects: %s and its subprojects +label_planning: Planiranje +text_subprojects_destroy_warning: 'I potprojekti projekta: %s će takođe biti obrisani.' +label_and_its_subprojects: %s i potprojekti mail_body_reminder: "%d issue(s) that are assigned to you are due in the next %d days:" mail_subject_reminder: "%d issue(s) due in the next days" text_user_wrote: '%s wrote:' -label_duplicated_by: duplicated by +label_duplicated_by: ponovljen kao setting_enabled_scm: Enabled SCM text_enumeration_category_reassign_to: 'Reassign them to this value:' text_enumeration_destroy_question: '%d objects are assigned to this value.' -label_incoming_emails: Incoming emails -label_generate_key: Generate a key +label_incoming_emails: Dolazeće e-poruke +label_generate_key: Generiši ključ setting_mail_handler_api_enabled: Enable WS for incoming emails setting_mail_handler_api_key: API key text_email_delivery_not_configured: "Email delivery is not configured, and notifications are disabled.\nConfigure your SMTP server in config/email.yml and restart the application to enable them." field_parent_title: Parent page -label_issue_watchers: Watchers +label_issue_watchers: Posmatrači setting_commit_logs_encoding: Commit messages encoding button_quote: Quote setting_sequential_project_identifiers: Generate sequential project identifiers notice_unable_delete_version: Unable to delete version -label_renamed: renamed -label_copied: copied -setting_repositories_cache_directory: Cache directory for repositories -field_cache: Local cache +label_renamed: preimenovano +label_copied: iskopirano +setting_plain_text_mail: plain text only (no HTML) +permission_view_files: View files +permission_edit_issues: Edit issues +permission_edit_own_time_entries: Edit own time logs +permission_manage_public_queries: Manage public queries +permission_add_issues: Add issues +permission_log_time: Log spent time +permission_view_changesets: View changesets +permission_view_time_entries: View spent time +permission_manage_versions: Manage versions +permission_manage_wiki: Manage wiki +permission_manage_categories: Manage issue categories +permission_protect_wiki_pages: Protect wiki pages +permission_comment_news: Comment news +permission_delete_messages: Delete messages +permission_select_project_modules: Select project modules +permission_manage_documents: Manage documents +permission_edit_wiki_pages: Edit wiki pages +permission_add_issue_watchers: Add watchers +permission_view_gantt: View gantt chart +permission_move_issues: Move issues +permission_manage_issue_relations: Manage issue relations +permission_delete_wiki_pages: Delete wiki pages +permission_manage_boards: Manage boards +permission_delete_wiki_pages_attachments: Delete attachments +permission_view_wiki_edits: View wiki history +permission_add_messages: Post messages +permission_view_messages: View messages +permission_manage_files: Manage files +permission_edit_issue_notes: Edit notes +permission_manage_news: Manage news +permission_view_calendar: View calendrier +permission_manage_members: Manage members +permission_edit_messages: Edit messages +permission_delete_issues: Delete issues +permission_view_issue_watchers: View watchers list +permission_manage_repository: Manage repository +permission_commit_access: Commit access +permission_browse_repository: Browse repository +permission_view_documents: View documents +permission_edit_project: Edit project +permission_add_issue_notes: Add notes +permission_save_queries: Save queries +permission_view_wiki_pages: View wiki +permission_rename_wiki_pages: Rename wiki pages +permission_edit_time_entries: Edit time logs +permission_edit_own_issue_notes: Edit own notes +setting_gravatar_enabled: Use Gravatar user icons +permission_edit_own_messages: Edit own messages +permission_delete_own_messages: Delete own messages +text_repository_usernames_mapping: "Select or update the Redmine user mapped to each username found in the repository log.\nUsers with the same Redmine and repository username or email are automatically mapped." +label_user_activity: "%s's activity" +label_updated_time_by: Updated by %s %s ago +text_diff_truncated: '... This diff was truncated because it exceeds the maximum size that can be displayed.' +setting_diff_max_lines_displayed: Max number of diff lines displayed +text_plugin_assets_writable: Plugin assets directory writable +warning_attachments_not_saved: "%d file(s) could not be saved." +button_create_and_continue: Create and continue +text_custom_field_possible_values_info: 'One line for each value' +label_display: Display +field_editable: Editable +setting_repository_log_display_limit: Maximum number of revisions displayed on file log +field_identity_url: OpenID URL +setting_openid: Allow OpenID login and registration +label_login_with_open_id_option: or login with OpenID +field_watcher: Watcher diff --git a/lang/sv.yml b/lang/sv.yml index 5df46232d..884dd16a4 100644 --- a/lang/sv.yml +++ b/lang/sv.yml @@ -11,7 +11,7 @@ actionview_datehelper_time_in_words_hour_about: cirka en timme actionview_datehelper_time_in_words_hour_about_plural: cirka %d timmar actionview_datehelper_time_in_words_hour_about_single: cirka en timme actionview_datehelper_time_in_words_minute: 1 minut -actionview_datehelper_time_in_words_minute_half: en halv minute +actionview_datehelper_time_in_words_minute_half: en halv minut actionview_datehelper_time_in_words_minute_less_than: mindre än en minut actionview_datehelper_time_in_words_minute_plural: %d minuter actionview_datehelper_time_in_words_minute_single: 1 minut @@ -22,19 +22,19 @@ actionview_instancetag_blank_option: Var god välj activerecord_error_inclusion: finns inte i listan activerecord_error_exclusion: är reserverad activerecord_error_invalid: är ogiltig -activerecord_error_confirmation: överränsstämmer inte med bekräftelsen +activerecord_error_confirmation: överensstämmer inte med bekräftelsen activerecord_error_accepted: måste accepteras activerecord_error_empty: får inte vara tom activerecord_error_blank: får inte vara tom activerecord_error_too_long: är för lång activerecord_error_too_short: är för kort activerecord_error_wrong_length: har fel längd -activerecord_error_taken: har redan blivit tagen +activerecord_error_taken: har redan tagits activerecord_error_not_a_number: är inte ett nummer activerecord_error_not_a_date: är inte ett korrekt datum activerecord_error_greater_than_start_date: måste vara senare än startdatumet -activerecord_error_not_same_project: doesn't belong to the same project -activerecord_error_circular_dependency: This relation would create a circular dependency +activerecord_error_not_same_project: tillhör inte samma projekt +activerecord_error_circular_dependency: Denna relation skulle skapa ett cirkulärt beroende general_fmt_age: %d år general_fmt_age_plural: %d år @@ -52,35 +52,51 @@ general_csv_decimal_separator: '.' general_csv_encoding: ISO-8859-1 general_pdf_encoding: ISO-8859-1 general_day_names: Måndag,Tisdag,Onsdag,Torsdag,Fredag,Lördag,Söndag -general_first_day_of_week: '7' +general_first_day_of_week: '1' notice_account_updated: Kontot har uppdaterats notice_account_invalid_creditentials: Fel användarnamn eller lösenord notice_account_password_updated: Lösenordet har uppdaterats notice_account_wrong_password: Fel lösenord -notice_account_register_done: Kontot har skapats. -notice_account_unknown_email: Okäns användare. -notice_can_t_change_password: Detta konto använder en extern authentikeringskälla. Det går inte att byta lösenord. -notice_account_lost_email_sent: Ett email med instruktioner om hur man väljer ett nytt lösenord har skickats till dig. +notice_account_register_done: Kontot har skapats. För att aktivera kontot, klicka på länken i mailet som skickades till dig. +notice_account_unknown_email: Okänd användare. +notice_can_t_change_password: Detta konto använder en extern autentiseringskälla. Det går inte att byta lösenord. +notice_account_lost_email_sent: Ett mail med instruktioner om hur man väljer ett nytt lösenord har skickats till dig. notice_account_activated: Ditt konto har blivit aktiverat. Du kan nu logga in. -notice_successful_create: Lyckat skapande. -notice_successful_update: Lyckad uppdatering. -notice_successful_delete: Lyckad borttagning. -notice_successful_connection: Lyckad uppkoppling. -notice_file_not_found: Sidan du försökte komma åt existerar inte eller har blivit borttagen. +notice_successful_create: Skapandet lyckades. +notice_successful_update: Uppdatering lyckades. +notice_successful_delete: Borttagning lyckades. +notice_successful_connection: Uppkoppling lyckades. +notice_file_not_found: Sidan du försökte komma åt existerar inte eller är borttagen. notice_locking_conflict: Data har uppdaterats av en annan användare. -notice_not_authorized: You are not authorized to access this page. -notice_email_sent: An email was sent to %s -notice_email_error: An error occurred while sending mail (%s) -notice_feeds_access_key_reseted: Your RSS access key was reseted. +notice_not_authorized: Du saknar behörighet att komma åt den här sidan. +notice_email_sent: Ett mail skickades till %s +notice_email_error: Ett fel inträffade när mail skickades (%s) +notice_feeds_access_key_reseted: Din RSS-nyckel återställdes. +notice_failed_to_save_issues: "Misslyckades att spara %d ärende(n) på %d valt: %s." +notice_no_issue_selected: "Inget ärende är markerat! Var vänlig, markera de ärenden du vill ändra." +notice_account_pending: "Ditt konto skapades och avvaktar nu administratörens godkännande." +notice_default_data_loaded: Standardkonfiguration inläst. +notice_unable_delete_version: Denna version var inte möjlig att ta bort. -error_scm_not_found: "Inlägg och/eller revision finns inte i repositoriet." -error_scm_command_failed: "An error occurred when trying to access the repository: %s" +error_can_t_load_default_data: "Standardkonfiguration gick inte att läsa in: %s" +error_scm_not_found: "Inlägg och/eller revision finns inte i detta repository." +error_scm_command_failed: "Ett fel inträffade vid försök att nå repositoryt: %s" +error_scm_annotate: "Inlägget existerar inte eller kan inte kommenteras." +error_issue_not_found_in_project: 'Ärendet hittades inte eller så tillhör det inte detta projekt' + +warning_attachments_not_saved: "%d fil(er) kunde inte sparas." mail_subject_lost_password: Ditt %s lösenord -mail_body_lost_password: 'För att ändra lösenord, följ denna länk:' -mail_subject_register: Ditt %s kontoaktivering -mail_body_register: 'För att aktivera ditt konto, använd följande länk.' +mail_body_lost_password: 'För att ändra ditt lösenord, klicka på följande länk:' +mail_subject_register: Din %s kontoaktivering +mail_body_register: 'För att aktivera ditt konto, klicka på följande länk:' +mail_body_account_information_external: Du kan använda ditt "%s"-konto för att logga in. +mail_body_account_information: Din kontoinformation +mail_subject_account_activation_request: %s begäran om kontoaktivering +mail_body_account_activation_request: 'En ny användare (%s) har registrerat sig och avvaktar ditt godkännande:' +mail_subject_reminder: "%d ärende(n) har deadline under de kommande dagarna" +mail_body_reminder: "%d ärende(n) som är tilldelat dig har deadline under de %d dagarna:" gui_validation_error: 1 fel gui_validation_error_plural: %d fel @@ -91,7 +107,7 @@ field_summary: Sammanfattning field_is_required: Obligatorisk field_firstname: Förnamn field_lastname: Efternamn -field_mail: Email +field_mail: Mail field_filename: Fil field_filesize: Storlek field_downloads: Nerladdningar @@ -101,91 +117,174 @@ field_updated_on: Uppdaterad field_field_format: Format field_is_for_all: För alla projekt field_possible_values: Möjliga värden -field_regexp: Regular expression +field_regexp: Reguljärt uttryck field_min_length: Minimilängd -field_max_length: Maximumlängd +field_max_length: Maxlängd field_value: Värde field_category: Kategori field_title: Titel field_project: Projekt -field_issue: Brist +field_issue: Ärende field_status: Status field_notes: Anteckningar -field_is_closed: Brist stängd -field_is_default: Defaultstatus -field_tracker: Tracker -field_subject: Rubrik -field_due_date: Färdigdatum -field_assigned_to: Tilldelad +field_is_closed: Ärendet är stängt +field_is_default: Standardvärde +field_tracker: Ärendetyp +field_subject: Ämne +field_due_date: Deadline +field_assigned_to: Tilldelad till field_priority: Prioritet -field_fixed_version: Target version +field_fixed_version: Versionsmål field_user: Användare field_role: Roll field_homepage: Hemsida -field_is_public: Offentlig -field_parent: Delprojekt av -field_is_in_chlog: Brister visade i ändringslogg -field_is_in_roadmap: Bsiter visade i roadmap -field_login: Inloggning -field_mail_notification: Emailnotifieringar +field_is_public: Publik +field_parent: Underprojekt till +field_is_in_chlog: Visa ärenden i ändringslogg +field_is_in_roadmap: Visa ärenden i roadmap +field_login: Användarnamn +field_mail_notification: Mailnotifieringar field_admin: Administratör field_last_login_on: Senaste inloggning field_language: Språk field_effective_date: Datum field_password: Lösenord field_new_password: Nytt lösenord -field_password_confirmation: Bekräfta +field_password_confirmation: Bekräfta lösenord field_version: Version field_type: Typ field_host: Värddator field_port: Port field_account: Konto -field_base_dn: Bas DN +field_base_dn: Bas-DN field_attr_login: Inloggningsattribut -field_attr_firstname: Förnamnattribut -field_attr_lastname: Efternamnattribut -field_attr_mail: Emailattribut +field_attr_firstname: Förnamnsattribut +field_attr_lastname: Efternamnsattribut +field_attr_mail: Mailattribut field_onthefly: On-the-fly användarskapning field_start_date: Start -field_done_ratio: %% Done -field_auth_source: Authentikeringsläge -field_hide_mail: Dölj min emailadress -field_comment: Kommentar +field_done_ratio: %% Klart +field_auth_source: Autentiseringsläge +field_hide_mail: Dölj min mailadress +field_comments: Kommentar field_url: URL field_start_page: Startsida -field_subproject: Delprojekt +field_subproject: Underprojekt field_hours: Timmar field_activity: Aktivitet field_spent_on: Datum field_identifier: Identifierare -field_is_filter: Used as a filter -field_issue_to_id: Related issue -field_delay: Delay -field_assignable: Issues can be assigned to this role -field_redirect_existing_links: Redirect existing links -field_estimated_hours: Estimated time -field_default_value: Default value +field_is_filter: Använd som filter +field_issue_to_id: Relaterade ärenden +field_delay: Fördröjning +field_assignable: Ärenden kan tilldelas denna roll +field_redirect_existing_links: Omdirigera existerande länkar +field_estimated_hours: Estimerad tid +field_column_names: Kolumner +field_time_zone: Tidszon +field_searchable: Sökbar +field_default_value: Standardvärde +field_comments_sorting: Visa kommentarer +field_parent_title: Föräldersida +field_editable: Redigerbar -setting_app_title: Applikationstitel -setting_app_subtitle: Applicationsunderrubrik -setting_welcome_text: Välkommentext -setting_default_language: Default språk -setting_login_required: Authent. obligatoriskt -setting_self_registration: Självregistrering påslaget -setting_attachment_max_size: Bifogad maxstorlek -setting_issues_export_limit: Brist exportgräns -setting_mail_from: Emailavsändare +setting_app_title: Applikationsrubrik +setting_app_subtitle: Applikationsunderrubrik +setting_welcome_text: Välkomsttext +setting_default_language: Standardspråk +setting_login_required: Kräver inloggning +setting_self_registration: Självregistrering +setting_attachment_max_size: Maxstorlek på bilaga +setting_issues_export_limit: Exportgräns för ärenden +setting_mail_from: Mailavsändare +setting_bcc_recipients: Hemlig kopia (bcc) till mottagare +setting_plain_text_mail: Oformaterad text i mail (ingen HTML) setting_host_name: Värddatornamn -setting_text_formatting: Textformattering -setting_wiki_compression: Wiki historiekomprimering -setting_feeds_limit: Feed innehållsgräns +setting_text_formatting: Textformatering +setting_wiki_compression: Komprimering av wikihistorik +setting_feeds_limit: Innehållsgräns för Feed +setting_default_projects_public: Nya projekt är publika som standard setting_autofetch_changesets: Automatisk hämtning av commits -setting_sys_api_enabled: Aktivera WS för repository management -setting_commit_ref_keywords: Referencing keywords -setting_commit_fix_keywords: Fixing keywords -setting_autologin: Autologin -setting_date_format: Date format -setting_cross_project_issue_relations: Allow cross-project issue relations +setting_sys_api_enabled: Aktivera WS för repository-hantering +setting_commit_ref_keywords: Referens-nyckelord +setting_commit_fix_keywords: Fix-nyckelord +setting_autologin: Automatisk inloggning +setting_date_format: Datumformat +setting_time_format: Tidsformat +setting_cross_project_issue_relations: Tillåt ärenderelationer mellan projekt +setting_issue_list_default_columns: Standardkolumner i ärendelistan +setting_repositories_encodings: Teckenuppsättningar för repositoriy +setting_commit_logs_encoding: Teckenuppsättning för commit-meddelanden +setting_emails_footer: Mailsignatur +setting_protocol: Protokoll +setting_per_page_options: Alternativ, objekt per sida +setting_user_format: Visningsformat för användare +setting_activity_days_default: Dagar som visas på projektaktivitet +setting_display_subprojects_issues: Visa ärenden från underprojekt i huvudprojekt som standard +setting_enabled_scm: Aktivera SCM +setting_mail_handler_api_enabled: Aktivera WS for inkommande mail +setting_mail_handler_api_key: API-nyckel +setting_sequential_project_identifiers: Generera projektidentifierare sekventiellt +setting_gravatar_enabled: Använd Gravatar-avatarer +setting_diff_max_lines_displayed: Maximalt antal synliga rader i diff +setting_repository_log_display_limit: Maximalt antal revisioner i filloggen + +permission_edit_project: Ändra projekt +permission_select_project_modules: Välja projektmoduler +permission_manage_members: Hantera medlemmar +permission_manage_versions: Hantera versioner +permission_manage_categories: Hantera ärendekategorier +permission_add_issues: Lägga till ärende +permission_edit_issues: Ändra ärende +permission_manage_issue_relations: Hantera ärenderelationer +permission_add_issue_notes: Lägga till notering +permission_edit_issue_notes: Ändra noteringar +permission_edit_own_issue_notes: Ändra egna noteringar +permission_move_issues: Flytta ärenden +permission_delete_issues: Ta bort ärenden +permission_manage_public_queries: Hantera publika frågor +permission_save_queries: Spara frågor +permission_view_gantt: Visa Gantt-schema +permission_view_calendar: Visa kalender +permission_view_issue_watchers: Visa bevakarlista +permission_add_issue_watchers: Lägga till bevakare +permission_log_time: Logga spenderad tid +permission_view_time_entries: Visa spenderad tid +permission_edit_time_entries: Ändra tidloggar +permission_edit_own_time_entries: Ändra egna tidloggar +permission_manage_news: Hantera nyheter +permission_comment_news: Kommentera nyheter +permission_manage_documents: Hantera dokument +permission_view_documents: Visa dokument +permission_manage_files: Hantera filer +permission_view_files: Visa filer +permission_manage_wiki: Hantera wiki +permission_rename_wiki_pages: Byta namn på wikisidor +permission_delete_wiki_pages: Ta bort wikisidor +permission_view_wiki_pages: Visa wiki +permission_view_wiki_edits: Visa wikihistorik +permission_edit_wiki_pages: Ändra wikisidor +permission_delete_wiki_pages_attachments: Ta bort bilagor +permission_protect_wiki_pages: Skydda wikisidor +permission_manage_repository: Hantera repository +permission_browse_repository: Bläddra i repository +permission_view_changesets: Visa changesets +permission_commit_access: Commit-tillgång +permission_manage_boards: Hantera forum +permission_view_messages: Visa meddelanden +permission_add_messages: Lägg till meddelanden +permission_edit_messages: Ändra meddelanden +permission_edit_own_messages: Ändra egna meddelanden +permission_delete_messages: Ta bort meddelanden +permission_delete_own_messages: Ta bort egna meddelanden +project_module_issue_tracking: Ärendeuppföljning +project_module_time_tracking: Tidsuppföljning +project_module_news: Nyheter +project_module_documents: Dokument +project_module_files: Filer +project_module_wiki: Wiki +project_module_repository: Repository +project_module_boards: Forum label_user: Användare label_user_plural: Användare @@ -193,36 +292,40 @@ label_user_new: Ny användare label_project: Projekt label_project_new: Nytt projekt label_project_plural: Projekt -label_project_all: All Projects +label_project_all: Alla projekt label_project_latest: Senaste projekt -label_issue: Brist -label_issue_new: Ny brist -label_issue_plural: Brister -label_issue_view_all: Visa alla brister +label_issue: Ärende +label_issue_new: Nytt ärende +label_issue_plural: Ärenden +label_issue_view_all: Visa alla ärenden +label_issues_by: Ärenden %s +label_issue_added: Ärende tillagt +label_issue_updated: Ärende uppdaterat label_document: Dokument label_document_new: Nytt dokument label_document_plural: Dokument +label_document_added: Dokument tillagt label_role: Roll label_role_plural: Roller label_role_new: Ny roll -label_role_and_permissions: Roller och rättigheter +label_role_and_permissions: Roller och behörigheter label_member: Medlem label_member_new: Ny medlem label_member_plural: Medlemmar -label_tracker: Tracker -label_tracker_plural: Trackers -label_tracker_new: Ny tracker -label_workflow: Workflow -label_issue_status: Briststatus -label_issue_status_plural: Briststatusar +label_tracker: Ärendetyp +label_tracker_plural: Ärendetyper +label_tracker_new: Ny ärendetyp +label_workflow: Arbetsflöde +label_issue_status: Ärendestatus +label_issue_status_plural: Ärendestatusar label_issue_status_new: Ny status -label_issue_category: Bristkategori -label_issue_category_plural: Bristkategorier +label_issue_category: Ärendekategori +label_issue_category_plural: Ärendekategorier label_issue_category_new: Ny kategori label_custom_field: Användardefinerat fält label_custom_field_plural: Användardefinerade fält -label_custom_field_new: Nytt Användardefinerat fält -label_enumerations: Uppräkningar +label_custom_field_new: Nytt användardefinerat fält +label_enumerations: Enumerationer label_enumeration_new: Nytt värde label_information: Information label_information_plural: Information @@ -237,28 +340,32 @@ label_administration: Administration label_login: Logga in label_logout: Logga ut label_help: Hjälp -label_reported_issues: Rapporterade brister -label_assigned_to_me_issues: Brister tilldelade mig +label_reported_issues: Rapporterade ärenden +label_assigned_to_me_issues: Ärenden tilldelade till mig label_last_login: Senaste inloggning label_last_updates: Senast uppdaterad label_last_updates_plural: %d senaste uppdateringarna label_registered_on: Registrerad label_activity: Aktivitet +label_overall_activity: All aktivitet +label_user_activity: "Aktiviteter för %s" label_new: Ny -label_logged_as: Loggad som +label_logged_as: Inloggad som label_environment: Miljö -label_authentication: Authentikering -label_auth_source: Authentikeringsläge -label_auth_source_new: Nytt authentikeringsläge -label_auth_source_plural: Authentikeringslägen -label_subproject_plural: Delprojekt -label_min_max_length: Min - Max längd +label_authentication: Autentisering +label_auth_source: Autentiseringsläge +label_auth_source_new: Nytt autentiseringsläge +label_auth_source_plural: Autentiseringslägen +label_subproject_plural: Underprojekt +label_and_its_subprojects: %s och dess underprojekt +label_min_max_length: Min./Max.-längd label_list: Lista label_date: Datum label_integer: Heltal +label_float: Flyttal label_boolean: Boolean label_string: Text -label_text: Long text +label_text: Lång text label_attribute: Attribut label_attribute_plural: Attribut label_download: %d Nerladdning @@ -270,13 +377,15 @@ label_attachment: Fil label_attachment_new: Ny fil label_attachment_delete: Ta bort fil label_attachment_plural: Filer +label_file_added: Fil tillagd label_report: Rapport label_report_plural: Rapporter label_news: Nyhet label_news_new: Lägg till nyhet label_news_plural: Nyheter -label_news_latest: Senaste neheten +label_news_latest: Senaste nyheterna label_news_view_all: Visa alla nyheter +label_news_added: Nyhet tillagd label_change_log: Ändringslogg label_settings: Inställningar label_overview: Överblick @@ -286,17 +395,18 @@ label_version_plural: Versioner label_confirmation: Bekräftelse label_export_to: Exportera till label_read: Läs... -label_public_projects: Offentligt projekt +label_public_projects: Publika projekt label_open_issues: öppen label_open_issues_plural: öppna label_closed_issues: stängd label_closed_issues_plural: stängda label_total: Total -label_permissions: Rättigheter +label_permissions: Behörigheter label_current_status: Nuvarande status label_new_statuses_allowed: Nya statusar tillåtna label_all: alla -label_none: inga +label_none: ingen +label_nobody: ingen label_next: Nästa label_previous: Föregående label_used_by: Använd av @@ -322,124 +432,175 @@ label_filter_add: Lägg till filter label_filter_plural: Filter label_equals: är label_not_equals: är inte -label_in_less_than: i mindre än -label_in_more_than: i mer än -label_in: i +label_in_less_than: om mindre än +label_in_more_than: om mer än +label_in: om label_today: idag -label_this_week: this week +label_all_time: närsom +label_yesterday: igår +label_this_week: denna vecka +label_last_week: senaste veckan +label_last_n_days: senaste %d dagarna +label_this_month: denna månad +label_last_month: senaste månaden +label_this_year: detta året +label_date_range: Datumintervall label_less_than_ago: mindre än dagar sedan label_more_than_ago: mer än dagar sedan label_ago: dagar sedan label_contains: innehåller label_not_contains: innehåller inte label_day_plural: dagar -label_repository: Repositorie +label_repository: Repository +label_repository_plural: Repositorys label_browse: Bläddra label_modification: %d ändring label_modification_plural: %d ändringar label_revision: Revision label_revision_plural: Revisioner +label_associated_revisions: Associerade revisioner label_added: tillagd label_modified: modifierad +label_copied: kopierad +label_renamed: omdöpt label_deleted: borttagen label_latest_revision: Senaste revisionen label_latest_revision_plural: Senaste revisionerna label_view_revisions: Visa revisioner -label_max_size: Maximumstorlek +label_max_size: Maxstorlek label_on: 'på' -label_sort_highest: Flytta till top -label_sort_higher: Flytta up +label_sort_highest: Flytta till toppen +label_sort_higher: Flytta upp label_sort_lower: Flytta ner label_sort_lowest: Flytta till botten label_roadmap: Roadmap label_roadmap_due_in: Färdig om %s -label_roadmap_overdue: %s late -label_roadmap_no_issues: Inga brister för denna version +label_roadmap_overdue: %s sen +label_roadmap_no_issues: Inga ärenden för denna version label_search: Sök label_result_plural: Resultat label_all_words: Alla ord label_wiki: Wiki -label_wiki_edit: Wiki editera -label_wiki_edit_plural: Wiki editeringar -label_wiki_page: Wiki page -label_wiki_page_plural: Wiki pages -label_index_by_title: Index by title -label_index_by_date: Index by date +label_wiki_edit: Wikiändring +label_wiki_edit_plural: Wikiändringar +label_wiki_page: Wikisida +label_wiki_page_plural: Wikisidor +label_index_by_title: Innehåll efter titel +label_index_by_date: Innehåll efter datum label_current_version: Nuvarande version -label_preview: Preview -label_feed_plural: Feeder +label_preview: Förhandsgranska +label_feed_plural: Feeds label_changes_details: Detaljer om alla ändringar -label_issue_tracking: Bristspårning +label_issue_tracking: Ärendeuppföljning label_spent_time: Spenderad tid -label_f_hour: %.2f timmar +label_f_hour: %.2f timme label_f_hour_plural: %.2f timmar -label_time_tracking: Tidsspårning +label_time_tracking: Tidsuppföljning label_change_plural: Ändringar label_statistics: Statistik -label_commits_per_month: Commit per månad -label_commits_per_author: Commit per författare +label_commits_per_month: Commits per månad +label_commits_per_author: Commits per författare label_view_diff: Visa skillnader -label_diff_inline: inline +label_diff_inline: i texten label_diff_side_by_side: sida vid sida label_options: Inställningar -label_copy_workflow_from: Kopiera workflow från -label_permissions_report: Rättighetsrapport -label_watched_issues: Watched issues -label_related_issues: Related issues -label_applied_status: Applied status -label_loading: Loading... -label_relation_new: New relation -label_relation_delete: Delete relation -label_relates_to: related to -label_duplicates: duplicates -label_blocks: blocks -label_blocked_by: blocked by -label_precedes: precedes -label_follows: follows -label_end_to_start: end to start -label_end_to_end: end to end -label_start_to_start: start to start -label_start_to_end: start to end -label_stay_logged_in: Stay logged in -label_disabled: disabled -label_show_completed_versions: Show completed versions -label_me: me +label_copy_workflow_from: Kopiera arbetsflöde från +label_permissions_report: Behörighetsrapport +label_watched_issues: Bevakade ärenden +label_related_issues: Relaterade ärenden +label_applied_status: Tilldelad status +label_loading: Laddar... +label_relation_new: Ny relation +label_relation_delete: Ta bort relation +label_relates_to: relaterar till +label_duplicates: kopierar +label_duplicated_by: kopierad av +label_blocks: blockerar +label_blocked_by: blockerad av +label_precedes: kommer före +label_follows: följer +label_end_to_start: slut till start +label_end_to_end: slut till slut +label_start_to_start: start till start +label_start_to_end: start till slut +label_stay_logged_in: Förbli inloggad +label_disabled: inaktiverad +label_show_completed_versions: Visa färdiga versioner +label_me: mig label_board: Forum -label_board_new: New forum -label_board_plural: Forums -label_topic_plural: Topics -label_message_plural: Messages -label_message_last: Last message -label_message_new: New message -label_reply_plural: Replies -label_send_information: Send account information to the user -label_year: Year -label_month: Month -label_week: Week -label_date_from: From -label_date_to: To -label_language_based: Language based -label_sort_by: Sort by %s -label_send_test_email: Send a test email -label_feeds_access_key_created_on: RSS access key created %s ago -label_module_plural: Modules -label_added_time_by: Added by %s %s ago -label_updated_time: Updated %s ago -label_jump_to_a_project: Jump to a project... +label_board_new: Nytt forum +label_board_plural: Forum +label_topic_plural: Ämnen +label_message_plural: Meddelanden +label_message_last: Senaste meddelande +label_message_new: Nytt meddelande +label_message_posted: Meddelande tillagt +label_reply_plural: Svar +label_send_information: Skicka kontoinformation till användaren +label_year: År +label_month: Månad +label_week: Vecka +label_date_from: Från +label_date_to: Till +label_language_based: Språkbaserad +label_sort_by: Sortera på %s +label_send_test_email: Skicka testmail +label_feeds_access_key_created_on: RSS-nyckel skapad för %s sedan +label_module_plural: Moduler +label_added_time_by: Tillagd av %s för %s sedan +label_updated_time_by: Uppdaterad av %s för %s sedan +label_updated_time: Uppdaterad för %s sedan +label_jump_to_a_project: Gå till projekt... +label_file_plural: Filer +label_changeset_plural: Changesets +label_default_columns: Standardkolumner +label_no_change_option: (Ingen ändring) +label_bulk_edit_selected_issues: Gemensam ändring av markerade ärenden +label_theme: Tema +label_default: Standard +label_search_titles_only: Sök endast i titlar +label_user_mail_option_all: "För alla händelser i mina projekt" +label_user_mail_option_selected: "För alla händelser i markerade projekt..." +label_user_mail_option_none: "Endast för saker jag bevakar eller är involverad i" +label_user_mail_no_self_notified: "Jag vill inte bli notifierad om ändringar som jag har gjort" +label_registration_activation_by_email: kontoaktivering med mail +label_registration_manual_activation: manuell kontoaktivering +label_registration_automatic_activation: automatisk kontoaktivering +label_display_per_page: 'Per sida: %s' +label_age: Ålder +label_change_properties: Ändra inställningar +label_general: Allmänt +label_more: Mer +label_scm: SCM +label_plugins: Tillägg +label_ldap_authentication: LDAP-autentisering +label_downloads_abbr: Nerl. +label_optional_description: Valfri beskrivning +label_add_another_file: Lägg till ytterligare en fil +label_preferences: Användarinställningar +label_chronological_order: I kronologisk ordning +label_reverse_chronological_order: I omvänd kronologisk ordning +label_planning: Planering +label_incoming_emails: Inkommande mail +label_generate_key: Generera en nyckel +label_issue_watchers: Bevakare +label_example: Exempel +label_display: Visa button_login: Logga in -button_submit: Skicka +button_submit: Spara button_save: Spara button_check_all: Markera alla button_uncheck_all: Avmarkera alla button_delete: Ta bort button_create: Skapa +button_create_and_continue: Skapa och fortsätt button_test: Testa -button_edit: Editera +button_edit: Ändra button_add: Lägg till button_change: Ändra -button_apply: Värkställ -button_clear: Rensa +button_apply: Verkställ +button_clear: Återställ button_lock: Lås button_unlock: Lås upp button_download: Ladda ner @@ -451,50 +612,79 @@ button_cancel: Avbryt button_activate: Aktivera button_sort: Sortera button_log_time: Logga tid -button_rollback: Rulla tillbaka till denna version -button_watch: Watch -button_unwatch: Unwatch -button_reply: Reply -button_archive: Archive -button_unarchive: Unarchive -button_reset: Reset -button_rename: Rename +button_rollback: Återställ till denna version +button_watch: Bevaka +button_unwatch: Stoppa bevakning +button_reply: Svara +button_archive: Arkivera +button_unarchive: Ta bort från arkiv +button_reset: Återställ +button_rename: Byt namn +button_change_password: Ändra lösenord +button_copy: Kopiera +button_annotate: Kommentera +button_update: Uppdatera +button_configure: Konfigurera +button_quote: Citera -status_active: activ +status_active: aktiv status_registered: registrerad status_locked: låst -text_select_mail_notifications: Väl action för vilka email ska skickas. +text_select_mail_notifications: Välj för vilka händelser mail ska skickas. text_regexp_info: eg. ^[A-Z0-9]+$ text_min_max_length_info: 0 betyder ingen gräns text_project_destroy_confirmation: Är du säker på att du vill ta bort detta projekt och all relaterad data? -text_workflow_edit: Väl en roll och en tracker för att editera workflow. -text_are_you_sure: Är du säker? +text_subprojects_destroy_warning: 'Alla underprojekt: %s kommer också tas bort.' +text_workflow_edit: Välj en roll och en ärendetyp för att ändra arbetsflöde +text_are_you_sure: Är du säker ? text_journal_changed: ändrad från %s till %s text_journal_set_to: satt till %s text_journal_deleted: borttagen -text_tip_task_begin_day: arbetsuppgift börjar denna dag -text_tip_task_end_day: arbetsuppgift slutar denna dag +text_tip_task_begin_day: arbetsuppgift som börjar denna dag +text_tip_task_end_day: arbetsuppgift som slutar denna dag text_tip_task_begin_end_day: arbetsuppgift börjar och slutar denna dag text_project_identifier_info: 'Små bokstäver (a-z), siffror och streck tillåtna.
    När den är sparad kan identifieraren inte ändras.' -text_caracters_maximum: %d tecken maximum. +text_caracters_maximum: max %d tecken. +text_caracters_minimum: Måste vara minst %d tecken lång. text_length_between: Längd mellan %d och %d tecken. -text_tracker_no_workflow: Inget workflow definerat för denna tracker -text_unallowed_characters: Unallowed characters -text_comma_separated: Multiple values allowed (comma separated). -text_issues_ref_in_commit_messages: Referencing and fixing issues in commit messages -text_issue_added: Brist %s har rapporterats (by %s). -text_issue_updated: Brist %s har uppdaterats (by %s). -text_wiki_destroy_confirmation: Are you sure you want to delete this wiki and all its content ? -text_issue_category_destroy_question: Some issues (%d) are assigned to this category. What do you want to do ? -text_issue_category_destroy_assignments: Remove category assignments -text_issue_category_reassign_to: Reassing issues to this category +text_tracker_no_workflow: Inget arbetsflöde definerat för denna ärendetyp +text_unallowed_characters: Otillåtna tecken +text_comma_separated: Flera värden tillåtna (kommaseparerade). +text_issues_ref_in_commit_messages: Referera och fixa ärenden i commit-meddelanden +text_issue_added: Ärende %s har rapporterats (av %s). +text_issue_updated: Ärende %s har uppdaterats (av %s). +text_wiki_destroy_confirmation: Är du säker på att du vill ta bort denna wiki och allt dess innehåll ? +text_issue_category_destroy_question: Några ärenden (%d) är tilldelade till denna kategori. Vad vill du göra ? +text_issue_category_destroy_assignments: Ta bort kategoritilldelningar +text_issue_category_reassign_to: Återtilldela ärenden till denna kategori +text_user_mail_option: "För omarkerade projekt kommer du bara få notifieringar om saker du bevakar eller är inblandad i (T.ex. ärenden du skapat eller tilldelats)." +text_no_configuration_data: "Roller, ärendetyper, ärendestatusar och arbetsflöden har inte konfigurerats ännu.\nDet rekommenderas att läsa in standardkonfigurationen. Du kommer att kunna göra ändringar efter att den blivit inläst." +text_load_default_configuration: Läs in standardkonfiguration +text_status_changed_by_changeset: Tilldelad i changeset %s. +text_issues_destroy_confirmation: 'Är du säker på att du vill radera markerade ärende(n) ?' +text_select_project_modules: 'Välj vilka moduler som ska vara aktiva för projektet:' +text_default_administrator_account_changed: Standardadministratörens konto ändrat +text_file_repository_writable: Foldern för bifogade filer är skrivbar +text_plugin_assets_writable: Foldern för plug-ins är skrivbar +text_rmagick_available: RMagick tillgängligt (valfritt) +text_destroy_time_entries_question: %.02f timmar har rapporterats på ärendena du är på väg att ta bort. Vad vill du göra ? +text_destroy_time_entries: Ta bort rapporterade timmar +text_assign_time_entries_to_project: Tilldela rapporterade timmar till projektet +text_reassign_time_entries: 'Återtilldela rapporterade timmar till detta ärende:' +text_user_wrote: '%s skrev:' +text_enumeration_destroy_question: '%d objekt är tilldelade till detta värde.' +text_enumeration_category_reassign_to: 'Återtilldela till detta värde:' +text_email_delivery_not_configured: "Mailfunktionen har inte konfigurerats, och notifieringar är inaktiverade.\nKonfigurera din SMTP-server i config/email.yml och starta om applikationen för att aktivera dem." +text_repository_usernames_mapping: "Välj eller uppdatera den Redmine-användare som är mappad till varje användarnamn i repository-loggen.\nAnvändare med samma användarnamn eller emailadress i både Redmine och repositoryt mappas automatiskt." +text_diff_truncated: '... Denna diff har förminskats eftersom den överskrider den maximala storlek som kan visas.' +text_custom_field_possible_values_info: 'En rad för varje värde' -default_role_manager: Förvaltare +default_role_manager: Projektledare default_role_developper: Utvecklare -default_role_reporter: Rapporterare +default_role_reporter: Rapportör default_tracker_bug: Bugg -default_tracker_feature: Finess +default_tracker_feature: Funktionalitet default_tracker_support: Support default_issue_status_new: Ny default_issue_status_assigned: Tilldelad @@ -507,139 +697,15 @@ default_doc_category_tech: Teknisk dokumentation default_priority_low: Låg default_priority_normal: Normal default_priority_high: Hög -default_priority_urgent: Bråttom +default_priority_urgent: Brådskande default_priority_immediate: Omedelbar default_activity_design: Design default_activity_development: Utveckling -enumeration_issue_priorities: Bristprioriteringar +enumeration_issue_priorities: Ärendeprioriteter enumeration_doc_categories: Dokumentkategorier -enumeration_activities: Aktiviteter (tidsspårning) -field_comments: Comment -label_file_plural: Files -label_changeset_plural: Changesets -field_column_names: Columns -label_default_columns: Default columns -setting_issue_list_default_columns: Default columns displayed on the issue list -setting_repositories_encodings: Repositories encodings -notice_no_issue_selected: "No issue is selected! Please, check the issues you want to edit." -label_bulk_edit_selected_issues: Bulk edit selected issues -label_no_change_option: (No change) -notice_failed_to_save_issues: "Failed to save %d issue(s) on %d selected: %s." -label_theme: Theme -label_default: Default -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_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 -project_module_wiki: Wiki -project_module_files: Files -project_module_documents: Documents -project_module_repository: Repository -project_module_news: News -project_module_time_tracking: Time tracking -text_file_repository_writable: File repository writable -text_default_administrator_account_changed: Default administrator account changed -text_rmagick_available: RMagick available (optional) -button_configure: Configure -label_plugins: Plugins -label_ldap_authentication: LDAP authentication -label_downloads_abbr: D/L -label_this_month: this month -label_last_n_days: last %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 -text_subprojects_destroy_warning: 'Its subproject(s): %s will be also deleted.' -label_and_its_subprojects: %s and its subprojects -mail_body_reminder: "%d issue(s) that are assigned to you are due in the next %d days:" -mail_subject_reminder: "%d issue(s) due in the next days" -text_user_wrote: '%s wrote:' -label_duplicated_by: duplicated by -setting_enabled_scm: Enabled SCM -text_enumeration_category_reassign_to: 'Reassign them to this value:' -text_enumeration_destroy_question: '%d objects are assigned to this value.' -label_incoming_emails: Incoming emails -label_generate_key: Generate a key -setting_mail_handler_api_enabled: Enable WS for incoming emails -setting_mail_handler_api_key: API key -text_email_delivery_not_configured: "Email delivery is not configured, and notifications are disabled.\nConfigure your SMTP server in config/email.yml and restart the application to enable them." -field_parent_title: Parent page -label_issue_watchers: Watchers -setting_commit_logs_encoding: Commit messages encoding -button_quote: Quote -setting_sequential_project_identifiers: Generate sequential project identifiers -notice_unable_delete_version: Unable to delete version -label_renamed: renamed -label_copied: copied -setting_repositories_cache_directory: Cache directory for repositories -field_cache: Local cache +enumeration_activities: Aktiviteter (tidsuppföljning) +field_identity_url: OpenID URL +setting_openid: Allow OpenID login and registration +label_login_with_open_id_option: or login with OpenID +field_watcher: Watcher diff --git a/lang/th.yml b/lang/th.yml index ca2db8bcc..7cb03a1b8 100644 --- a/lang/th.yml +++ b/lang/th.yml @@ -643,5 +643,70 @@ setting_sequential_project_identifiers: Generate sequential project identifiers notice_unable_delete_version: Unable to delete version label_renamed: renamed label_copied: copied -setting_repositories_cache_directory: Cache directory for repositories -field_cache: Local cache +setting_plain_text_mail: plain text only (no HTML) +permission_view_files: View files +permission_edit_issues: Edit issues +permission_edit_own_time_entries: Edit own time logs +permission_manage_public_queries: Manage public queries +permission_add_issues: Add issues +permission_log_time: Log spent time +permission_view_changesets: View changesets +permission_view_time_entries: View spent time +permission_manage_versions: Manage versions +permission_manage_wiki: Manage wiki +permission_manage_categories: Manage issue categories +permission_protect_wiki_pages: Protect wiki pages +permission_comment_news: Comment news +permission_delete_messages: Delete messages +permission_select_project_modules: Select project modules +permission_manage_documents: Manage documents +permission_edit_wiki_pages: Edit wiki pages +permission_add_issue_watchers: Add watchers +permission_view_gantt: View gantt chart +permission_move_issues: Move issues +permission_manage_issue_relations: Manage issue relations +permission_delete_wiki_pages: Delete wiki pages +permission_manage_boards: Manage boards +permission_delete_wiki_pages_attachments: Delete attachments +permission_view_wiki_edits: View wiki history +permission_add_messages: Post messages +permission_view_messages: View messages +permission_manage_files: Manage files +permission_edit_issue_notes: Edit notes +permission_manage_news: Manage news +permission_view_calendar: View calendrier +permission_manage_members: Manage members +permission_edit_messages: Edit messages +permission_delete_issues: Delete issues +permission_view_issue_watchers: View watchers list +permission_manage_repository: Manage repository +permission_commit_access: Commit access +permission_browse_repository: Browse repository +permission_view_documents: View documents +permission_edit_project: Edit project +permission_add_issue_notes: Add notes +permission_save_queries: Save queries +permission_view_wiki_pages: View wiki +permission_rename_wiki_pages: Rename wiki pages +permission_edit_time_entries: Edit time logs +permission_edit_own_issue_notes: Edit own notes +setting_gravatar_enabled: Use Gravatar user icons +label_example: Example +text_repository_usernames_mapping: "Select ou update the Redmine user mapped to each username found in the repository log.\nUsers with the same Redmine and repository username or email are automatically mapped." +permission_edit_own_messages: Edit own messages +permission_delete_own_messages: Delete own messages +label_user_activity: "%s's activity" +label_updated_time_by: Updated by %s %s ago +text_diff_truncated: '... This diff was truncated because it exceeds the maximum size that can be displayed.' +setting_diff_max_lines_displayed: Max number of diff lines displayed +text_plugin_assets_writable: Plugin assets directory writable +warning_attachments_not_saved: "%d file(s) could not be saved." +button_create_and_continue: Create and continue +text_custom_field_possible_values_info: 'One line for each value' +label_display: Display +field_editable: Editable +setting_repository_log_display_limit: Maximum number of revisions displayed on file log +field_identity_url: OpenID URL +setting_openid: Allow OpenID login and registration +label_login_with_open_id_option: or login with OpenID +field_watcher: Watcher diff --git a/lang/tr.yml b/lang/tr.yml index 56bf3311a..8766b1127 100644 --- a/lang/tr.yml +++ b/lang/tr.yml @@ -641,5 +641,70 @@ general_csv_decimal_separator: '.' notice_unable_delete_version: Unable to delete version label_renamed: renamed label_copied: copied -setting_repositories_cache_directory: Cache directory for repositories -field_cache: Local cache +setting_plain_text_mail: plain text only (no HTML) +permission_view_files: View files +permission_edit_issues: Edit issues +permission_edit_own_time_entries: Edit own time logs +permission_manage_public_queries: Manage public queries +permission_add_issues: Add issues +permission_log_time: Log spent time +permission_view_changesets: View changesets +permission_view_time_entries: View spent time +permission_manage_versions: Manage versions +permission_manage_wiki: Manage wiki +permission_manage_categories: Manage issue categories +permission_protect_wiki_pages: Protect wiki pages +permission_comment_news: Comment news +permission_delete_messages: Delete messages +permission_select_project_modules: Select project modules +permission_manage_documents: Manage documents +permission_edit_wiki_pages: Edit wiki pages +permission_add_issue_watchers: Add watchers +permission_view_gantt: View gantt chart +permission_move_issues: Move issues +permission_manage_issue_relations: Manage issue relations +permission_delete_wiki_pages: Delete wiki pages +permission_manage_boards: Manage boards +permission_delete_wiki_pages_attachments: Delete attachments +permission_view_wiki_edits: View wiki history +permission_add_messages: Post messages +permission_view_messages: View messages +permission_manage_files: Manage files +permission_edit_issue_notes: Edit notes +permission_manage_news: Manage news +permission_view_calendar: View calendrier +permission_manage_members: Manage members +permission_edit_messages: Edit messages +permission_delete_issues: Delete issues +permission_view_issue_watchers: View watchers list +permission_manage_repository: Manage repository +permission_commit_access: Commit access +permission_browse_repository: Browse repository +permission_view_documents: View documents +permission_edit_project: Edit project +permission_add_issue_notes: Add notes +permission_save_queries: Save queries +permission_view_wiki_pages: View wiki +permission_rename_wiki_pages: Rename wiki pages +permission_edit_time_entries: Edit time logs +permission_edit_own_issue_notes: Edit own notes +setting_gravatar_enabled: Use Gravatar user icons +label_example: Example +text_repository_usernames_mapping: "Select ou update the Redmine user mapped to each username found in the repository log.\nUsers with the same Redmine and repository username or email are automatically mapped." +permission_edit_own_messages: Edit own messages +permission_delete_own_messages: Delete own messages +label_user_activity: "%s's activity" +label_updated_time_by: Updated by %s %s ago +text_diff_truncated: '... This diff was truncated because it exceeds the maximum size that can be displayed.' +setting_diff_max_lines_displayed: Max number of diff lines displayed +text_plugin_assets_writable: Plugin assets directory writable +warning_attachments_not_saved: "%d file(s) could not be saved." +button_create_and_continue: Create and continue +text_custom_field_possible_values_info: 'One line for each value' +label_display: Display +field_editable: Editable +setting_repository_log_display_limit: Maximum number of revisions displayed on file log +field_identity_url: OpenID URL +setting_openid: Allow OpenID login and registration +label_login_with_open_id_option: or login with OpenID +field_watcher: Watcher diff --git a/lang/uk.yml b/lang/uk.yml index dd3954a90..235bbadb8 100644 --- a/lang/uk.yml +++ b/lang/uk.yml @@ -123,7 +123,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: Домашня сторінка @@ -156,7 +156,7 @@ field_done_ratio: %% зроблено field_auth_source: Режим аутентифікації field_hide_mail: Приховувати мій email field_comments: Коментар -field_url: URL +field_url: Посилання field_start_page: Стартова сторінка field_subproject: Підпроект field_hours: Годин(и/а) @@ -183,7 +183,7 @@ setting_attachment_max_size: Максимальний размір вкладе setting_issues_export_limit: Обмеження по задачах, що експортуються setting_mail_from: email адреса для передачі інформації setting_bcc_recipients: Отримувачі сліпої копії (bcc) -setting_host_name: Им'я машини +setting_host_name: Ім'я машини setting_text_formatting: Форматування тексту setting_wiki_compression: Стиснення історії Wiki setting_feeds_limit: Обмеження змісту подачі @@ -209,7 +209,7 @@ label_project_plural: Проекти label_project_all: Усі проекти label_project_latest: Останні проекти label_issue: Питання -label_issue_new: Нові питання +label_issue_new: Задати питання label_issue_plural: Питання label_issue_view_all: Проглянути всі питання label_issues_by: Питання за %s @@ -511,7 +511,7 @@ 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), допустимі цифри і дефіс.
    Збережений ідентифікатор не може бути змінений.' +text_project_identifier_info: 'Рядкові букви (a-z), допустимі цифри і дефіс.
    Збережений ідентифікатор не може бути змінений.' text_caracters_maximum: %d символів(а) максимум. text_caracters_minimum: Повинно мати якнайменше %d символів(а) у довжину. text_length_between: Довжина між %d і %d символів. @@ -552,95 +552,160 @@ default_activity_development: Розробка enumeration_issue_priorities: Пріоритети питань enumeration_doc_categories: Категорії документів enumeration_activities: Дії (облік часу) -text_status_changed_by_changeset: Applied in changeset %s. -label_display_per_page: 'Per page: %s' -label_issue_added: Issue added -label_issue_updated: Issue updated -setting_per_page_options: Objects per page options -notice_default_data_loaded: Default configuration successfully loaded. -error_scm_not_found: "Entry and/or revision doesn't exist in the repository." -label_associated_revisions: Associated revisions -label_document_added: Document added -label_message_posted: Message added -text_issues_destroy_confirmation: 'Are you sure you want to delete the selected issue(s) ?' -error_scm_command_failed: "An error occurred when trying to access the repository: %s" -setting_user_format: Users display format -label_age: Age -label_file_added: File added -label_more: More -field_default_value: Default value -default_tracker_bug: Bug -label_scm: SCM -label_general: General -button_update: Update -text_select_project_modules: 'Select modules to enable for this project:' -label_change_properties: Change properties -text_load_default_configuration: Load the default configuration +text_status_changed_by_changeset: Реалізовано в редакції %s. +label_display_per_page: 'На сторінку : %s' +label_issue_added: Питання додано +label_issue_updated: Питання поновлено +setting_per_page_options: Кількість обєктів на сторінці +notice_default_data_loaded: Конфігурація по замовчуванню успішно завантажена. +error_scm_not_found: Репозиторій не містить даних чи змін +label_associated_revisions: Звязані редакції +label_document_added: Документ додано +label_message_posted: Повідомлення додано +text_issues_destroy_confirmation: Ви впевнені що хочете видалити обрані задачі ?' +error_scm_command_failed: "Помилка доступу до репозиторію : %s" +setting_user_format: Формат відображення імені +label_age: Вік +label_file_added: Файл додано +label_more: Більше/Далі +field_default_value: Значення по замовчуванню +default_tracker_bug: Помилка +label_scm: Тип репозиторію +label_general: Загальне +button_update: Додати коментар +text_select_project_modules: Виберіть модулі,які будуть використовуватись у цьому проекті +label_change_properties: Змінити властивості +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. You will be able to modify it once loaded." -label_news_added: News added -label_repository_plural: Repositories -error_can_t_load_default_data: "Default configuration could not be loaded: %s" -project_module_boards: Boards -project_module_issue_tracking: Issue tracking +label_news_added: Додано новину +label_repository_plural: Репозиторії +error_can_t_load_default_data: "Конфігурація по замовчуванню %s" +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 +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: Default administrator account changed text_rmagick_available: RMagick available (optional) -button_configure: Configure -label_plugins: Plugins +button_configure: Конфігурація +label_plugins: Додатки label_ldap_authentication: LDAP authentication 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 -text_subprojects_destroy_warning: 'Its subproject(s): %s will be also deleted.' -label_and_its_subprojects: %s and its subprojects -mail_body_reminder: "%d issue(s) that are assigned to you are due in the next %d days:" -mail_subject_reminder: "%d issue(s) due in the next days" -text_user_wrote: '%s wrote:' -label_duplicated_by: duplicated by -setting_enabled_scm: Enabled SCM -text_enumeration_category_reassign_to: 'Reassign them to this value:' -text_enumeration_destroy_question: '%d objects are assigned to this value.' -label_incoming_emails: Incoming emails -label_generate_key: Generate a key -setting_mail_handler_api_enabled: Enable WS for incoming emails -setting_mail_handler_api_key: API key -text_email_delivery_not_configured: "Email delivery is not configured, and notifications are disabled.\nConfigure your SMTP server in config/email.yml and restart the application to enable them." -field_parent_title: Parent page -label_issue_watchers: Watchers -setting_commit_logs_encoding: Commit messages encoding -button_quote: Quote -setting_sequential_project_identifiers: Generate sequential project identifiers -notice_unable_delete_version: Unable to delete version -label_renamed: renamed -label_copied: copied -setting_repositories_cache_directory: Cache directory for repositories -field_cache: Local cache +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: 'Підпроекти: %s також будуть видалені.' +label_and_its_subprojects: %s і всі підпроекти +mail_body_reminder: "%d призначених для Вас завдання,на слідуючих %d днів:" +mail_subject_reminder: "%d призначених для Вас завдань на найближчі дні" +text_user_wrote: '%s написав:' +label_duplicated_by: дублюється +setting_enabled_scm: Дозволити SCM +text_enumeration_category_reassign_to: 'Призначити слідуючі значення:' +text_enumeration_destroy_question: '%d обєктів звязаних з цим значенням.' +label_incoming_emails: Вхідна електронна пошта +label_generate_key: Генерувати ключі +setting_mail_handler_api_enabled: Дозволити веб-сервіс для вхідної пошти +setting_mail_handler_api_key: API ключ +text_email_delivery_not_configured: "Доставка пошти не налаштована, функції повідомлень на пошту не активні.\nНалаштуйте ваш SMTP сервер в файлі config/email.yml та перезапустіть систему щоб дозволити ці функції." +field_parent_title: Вищестояча сторінка +label_issue_watchers: Наглядачі +setting_commit_logs_encoding: Кодування коментарів в репозиторії +button_quote: Цитувати +setting_sequential_project_identifiers: Генерувати послідовні ідентифікатори проектів +notice_unable_delete_version: Неможливо видалити версію +label_renamed: перейменовано +label_copied: копійовано +setting_plain_text_mail: лише простий текст (без HTML) +permission_view_files: Дивитись файли +permission_edit_issues: Редагувати завдання +permission_edit_own_time_entries: Редагувати власний облік часу +permission_manage_public_queries: Управління загальними запитами +permission_add_issues: Додати завдання +permission_log_time: Облік затраченого часу +permission_view_changesets: Дивитись зміни репозиторію +permission_view_time_entries: Дивитись затраченого часу +permission_manage_versions: Управління версіями +permission_manage_wiki: Управління wiki +permission_manage_categories: Управління категоріями завдань +permission_protect_wiki_pages: Блокування сторінок wiki +permission_comment_news: Коментувати новини +permission_delete_messages: Видаляти повідомлення +permission_select_project_modules: Вибір модулів для проекту +permission_manage_documents: Управління документами +permission_edit_wiki_pages: Редагувати сторінки wiki +permission_add_issue_watchers: Додавати наглядачів +permission_view_gantt: Дивитись діаграму Ганта +permission_move_issues: Переміщати завдання +permission_manage_issue_relations: Управління звязуванням завдань +permission_delete_wiki_pages: Видалення сторінок wiki +permission_manage_boards: Управління форумом +permission_delete_wiki_pages_attachments: Видалення приєднань +permission_view_wiki_edits: Дивитись історію wiki +permission_add_messages: Відправка повідомлень +permission_view_messages: Дивитись повідомлення +permission_manage_files: Управління файлами +permission_edit_issue_notes: Редагувати замітки +permission_manage_news: Управління новинами +permission_view_calendar: Дивитись календар +permission_manage_members: Управління користувачами +permission_edit_messages: Редагування повідомлень +permission_delete_issues: Видалення завдань +permission_view_issue_watchers: Дивитись список наглядачів +permission_manage_repository: Управління репозиторієм +permission_commit_access: Дозволити фіксацію змін +permission_browse_repository: Дивитись репозиторій +permission_view_documents: Дивитись документи +permission_edit_project: Редагувати проекти +permission_add_issue_notes: Додати замітку +permission_save_queries: Зберігати запити +permission_view_wiki_pages: Дивитись wiki +permission_rename_wiki_pages: Перейменування сторінок wiki +permission_edit_time_entries: Редагування обліку часу +permission_edit_own_issue_notes: Редагування обліку часу +setting_gravatar_enabled: Використовувати Gravatar аватари +label_example: Приклад +text_repository_usernames_mapping: "Виберіть чи поновіть користувача Redmine, звязаного з знайденими іменами в журналі репозиторію.\nКористувачі з однаковими іменами чи email в Redmine і репозиторії звязуються автоматично." +permission_edit_own_messages: Редагування власних повідомлень +permission_delete_own_messages: Видалення власних повідомлень +label_user_activity: "Активність користувача %s" +label_updated_time_by: Поновлено %s %s тому +text_diff_truncated: '... порівняння обмежено,так як перевищує ліміт стрічок для порівняння .' +setting_diff_max_lines_displayed: Максимальна кількість стрічок для порівняння +setting_repository_log_display_limit: Maximum number of revisions displayed on file log +warning_attachments_not_saved: "%d file(s) could not be saved." +field_editable: Editable +text_plugin_assets_writable: Plugin assets directory writable +label_display: Display +button_create_and_continue: Create and continue +text_custom_field_possible_values_info: 'One line for each value' +field_identity_url: OpenID URL +setting_openid: Allow OpenID login and registration +label_login_with_open_id_option: or login with OpenID +field_watcher: Watcher diff --git a/lang/vn.yml b/lang/vn.yml new file mode 100644 index 000000000..e4f4fd47c --- /dev/null +++ b/lang/vn.yml @@ -0,0 +1,712 @@ +_gloc_rule_default: '|n| n==1 ? "" : "_plural" ' + +actionview_datehelper_select_day_prefix: +actionview_datehelper_select_month_names: Tháng Giêng,Tháng Hai,Tháng Ba,Tháng TÆ°,Tháng Năm,Tháng Sáu,Tháng Bảy,Tháng Tám,Tháng Chín,Tháng Mười,Tháng M.Một,Tháng Chạp +actionview_datehelper_select_month_names_abbr: Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec +actionview_datehelper_select_month_prefix: +actionview_datehelper_select_year_prefix: +actionview_datehelper_time_in_words_day: 1 ngày +actionview_datehelper_time_in_words_day_plural: %d ngày +actionview_datehelper_time_in_words_hour_about: khoảng 1 giờ +actionview_datehelper_time_in_words_hour_about_plural: khoảng %d giờ +actionview_datehelper_time_in_words_hour_about_single: khoảng 1 giờ +actionview_datehelper_time_in_words_minute: 1 phút +actionview_datehelper_time_in_words_minute_half: ná»­a phút +actionview_datehelper_time_in_words_minute_less_than: dưới một phút +actionview_datehelper_time_in_words_minute_plural: %d phút +actionview_datehelper_time_in_words_minute_single: 1 phút +actionview_datehelper_time_in_words_second_less_than: cách vài giây +actionview_datehelper_time_in_words_second_less_than_plural: cách %d giấy +actionview_instancetag_blank_option: Vui lòng chọn + +activerecord_error_inclusion: không chứa trong danh sách +activerecord_error_exclusion: đã được dùng +activerecord_error_invalid: không hợp lệ +activerecord_error_confirmation: không khớp +activerecord_error_accepted: phải được chấp nhận +activerecord_error_empty: không thể để trống +activerecord_error_blank: không thể để trống +activerecord_error_too_long: quá dài +activerecord_error_too_short: quá ngắn +activerecord_error_wrong_length: độ dài không đúng +activerecord_error_taken: đã được chọn +activerecord_error_not_a_number: không phải con số +activerecord_error_not_a_date: không phải ngày hợp lệ +activerecord_error_greater_than_start_date: phải đi sau ngày bắt đầu +activerecord_error_not_same_project: không thuộc cùng dá»± án +activerecord_error_circular_dependency: quan hệ có thể gây ra lặp vô tận + +general_fmt_age: %d năm +general_fmt_age_plural: %d năm +general_fmt_date: %%m/%%d/%%Y +general_fmt_datetime: %%m/%%d/%%Y %%I:%%M %%p +general_fmt_datetime_short: %%b %%d, %%I:%%M %%p +general_fmt_time: %%I:%%M %%p +general_text_No: 'Không' +general_text_Yes: 'Có' +general_text_no: 'không' +general_text_yes: 'có' +general_lang_name: 'Tiếng Việt' +general_csv_separator: ',' +general_csv_decimal_separator: '.' +general_csv_encoding: UTF-8 +general_pdf_encoding: UTF-8 +general_day_names: Hai,Ba,TÆ°,Năm,Sáu,Bảy,C.Nhật +general_first_day_of_week: '1' + +notice_account_updated: Cập nhật tài khoản thành công. +notice_account_invalid_creditentials: Tài khoản hoặc mật mã không hợp lệ +notice_account_password_updated: Cập nhật mật mã thành công. +notice_account_wrong_password: Sai mật mã +notice_account_register_done: Tài khoản được tạo thành công. Để kích hoạt vui lòng làm theo hướng dẫn trong email gá»­i đến bạn. +notice_account_unknown_email: Không rõ tài khoản. +notice_can_t_change_password: Tài khoản được chứng thá»±c từ nguồn bên ngoài. Không thể đổi mật mã cho loại chứng thá»±c này. +notice_account_lost_email_sent: Thông tin để đổi mật mã mới đã gá»­i đến bạn qua email. +notice_account_activated: Tài khoản vừa được kích hoạt. Bây giờ bạn có thể đăng nhập. +notice_successful_create: Tạo thành công. +notice_successful_update: Cập nhật thành công. +notice_successful_delete: Xóa thành công. +notice_successful_connection: Kết nối thành công. +notice_file_not_found: Trang bạn cố xem không tồn tại hoặc đã chuyển. +notice_locking_conflict: Thông tin đang được cập nhật bởi người khác. Hãy chép nội dung cập nhật của bạn vào clipboard. +notice_not_authorized: Bạn không có quyền xem trang này. +notice_email_sent: Email đã được gá»­i tới %s +notice_email_error: Lỗi xảy ra khi gá»­i email (%s) +notice_feeds_access_key_reseted: Mã số chứng thá»±c RSS đã được tạo lại. +notice_failed_to_save_issues: "Failed to save %d issue(s) on %d selected: %s." +notice_no_issue_selected: "No issue is selected! Please, check the issues you want to edit." +notice_account_pending: "Thông tin tài khoản đã được tạo ra và đang chờ chứng thá»±c từ ban quản trị." +notice_default_data_loaded: Đã nạp cấu hình mặc định. +notice_unable_delete_version: Không thể xóa phiên bản. + +error_can_t_load_default_data: "Không thể nạp cấu hình mặc định: %s" +error_scm_not_found: "The entry or revision was not found in the repository." +error_scm_command_failed: "Lỗi xảy ra khi truy cập vào kho lÆ°u trữ: %s" +error_scm_annotate: "The entry does not exist or can not be annotated." +error_issue_not_found_in_project: 'Vấn đề không tồn tại hoặc không thuộc dá»± án' + +mail_subject_lost_password: "%s: mật mã của bạn" +mail_body_lost_password: "Để đổi mật mã, hãy click chuột vào liên kết sau:" +mail_subject_register: "%s: kích hoạt tài khoản" +mail_body_register: "Để kích hoạt tài khoản, hãy click chuột vào liên kết sau:" +mail_body_account_information_external: Bạn có thể dùng tài khoản "%s" để đăng nhập. +mail_body_account_information: Thông tin về tài khoản +mail_subject_account_activation_request: "%s: Yêu cầu chứng thá»±c tài khoản" +mail_body_account_activation_request: 'Người dùng (%s) mới đăng ký và cần bạn xác nhận:' +mail_subject_reminder: "%d vấn đề hết hạn trong các ngày tới" +mail_body_reminder: "%d vấn đề gán cho bạn sẽ hết hạn trong %d ngày tới:" + +gui_validation_error: 1 lỗi +gui_validation_error_plural: %d lỗi + +field_name: Tên +field_description: Mô tả +field_summary: Tóm tắt +field_is_required: Bắt buộc +field_firstname: Tên lót + Tên +field_lastname: Họ +field_mail: Email +field_filename: Tập tin +field_filesize: Cỡ +field_downloads: Tải về +field_author: Tác giả +field_created_on: Tạo +field_updated_on: Cập nhật +field_field_format: Định dạng +field_is_for_all: Cho mọi dá»± án +field_possible_values: Giá trị hợp lệ +field_regexp: Biểu thức chính quy +field_min_length: Chiều dài tối thiểu +field_max_length: Chiều dài tối đa +field_value: Giá trị +field_category: Chủ đề +field_title: Tiêu đề +field_project: Dá»± án +field_issue: Vấn đề +field_status: Trạng thái +field_notes: Ghi chú +field_is_closed: Vấn đề đóng +field_is_default: Giá trị mặc định +field_tracker: Dòng vấn đề +field_subject: Chủ đề +field_due_date: Hết hạn +field_assigned_to: Gán cho +field_priority: Ưu tiên +field_fixed_version: Phiên bản +field_user: Người dùng +field_role: Quyền +field_homepage: Trang chủ +field_is_public: Công cộng +field_parent: Dá»± án con của +field_is_in_chlog: Có thể thấy trong Thay đổi +field_is_in_roadmap: Có thể thấy trong Kế hoạch +field_login: Đăng nhập +field_mail_notification: Thông báo qua email +field_admin: Quản trị +field_last_login_on: Kết nối cuối +field_language: Ngôn ngữ +field_effective_date: Ngày +field_password: Mật mã +field_new_password: Mật mã mới +field_password_confirmation: Khẳng định lại +field_version: Phiên bản +field_type: Kiểu +field_host: Host +field_port: Port +field_account: Tài khoản +field_base_dn: Base DN +field_attr_login: Login attribute +field_attr_firstname: Firstname attribute +field_attr_lastname: Lastname attribute +field_attr_mail: Email attribute +field_onthefly: On-the-fly user creation +field_start_date: Bắt đầu +field_done_ratio: Tiến độ +field_auth_source: Authentication mode +field_hide_mail: Không làm lộ email của bạn +field_comments: Bình luận +field_url: URL +field_start_page: Trang bắt đầu +field_subproject: Dá»± án con +field_hours: Giờ +field_activity: Hoạt động +field_spent_on: Ngày +field_identifier: Mã nhận dạng +field_is_filter: Dùng nhÆ° một lọc +field_issue_to_id: Vấn đền liên quan +field_delay: Độ trễ +field_assignable: Vấn đề có thể gán cho vai trò này +field_redirect_existing_links: Chuyển hướng trang đã có +field_estimated_hours: Thời gian ước đoán +field_column_names: Cột +field_time_zone: Múi giờ +field_searchable: Tìm kiếm được +field_default_value: Giá trị mặc định +field_comments_sorting: Liệt kê bình luận +field_parent_title: Trang mẹ + +setting_app_title: Tá»±a đề ứng dụng +setting_app_subtitle: Tá»±a đề nhỏ của ứng dụng +setting_welcome_text: Thông điệp chào mừng +setting_default_language: Ngôn ngữ mặc định +setting_login_required: Cần đăng nhập +setting_self_registration: Tá»± chứng thá»±c +setting_attachment_max_size: Cỡ tối đa của tập tin đính kèm +setting_issues_export_limit: Issues export limit +setting_mail_from: Emission email address +setting_bcc_recipients: Tạo bản CC bí mật (bcc) +setting_host_name: Tên miền và đường dẫn +setting_text_formatting: Định dạng bài viết +setting_wiki_compression: Wiki history compression +setting_feeds_limit: Giới hạn nội dung của feed +setting_default_projects_public: Dá»± án mặc định là công cộng +setting_autofetch_changesets: Autofetch commits +setting_sys_api_enabled: Enable WS for repository management +setting_commit_ref_keywords: Từ khóa tham khảo +setting_commit_fix_keywords: Từ khóa chỉ vấn đề đã giải quyết +setting_autologin: Tá»± động đăng nhập +setting_date_format: Định dạng ngày +setting_time_format: Định dạng giờ +setting_cross_project_issue_relations: Cho phép quan hệ chéo giữa các dá»± án +setting_issue_list_default_columns: Default columns displayed on the issue list +setting_repositories_encodings: Repositories encodings +setting_commit_logs_encoding: Commit messages encoding +setting_emails_footer: Chữ ký cuối thÆ° +setting_protocol: Giao thức +setting_per_page_options: Objects per page options +setting_user_format: Định dạng hiển thị người dùng +setting_activity_days_default: Days displayed on project activity +setting_display_subprojects_issues: Display subprojects issues on main projects by default +setting_enabled_scm: Enabled SCM +setting_mail_handler_api_enabled: Enable WS for incoming emails +setting_mail_handler_api_key: Mã số API +setting_sequential_project_identifiers: Tá»± sinh chuỗi ID dá»± án + +project_module_issue_tracking: Theo dõi vấn đề +project_module_time_tracking: Theo dõi thời gian +project_module_news: Tin tức +project_module_documents: Tài liệu +project_module_files: Tập tin +project_module_wiki: Wiki +project_module_repository: Kho lÆ°u trữ +project_module_boards: Diễn đàn + +label_user: Tài khoản +label_user_plural: Tài khoản +label_user_new: Tài khoản mới +label_project: Dá»± án +label_project_new: Dá»± án mới +label_project_plural: Dá»± án +label_project_all: Mọi dá»± án +label_project_latest: Dá»± án mới nhất +label_issue: Vấn đề +label_issue_new: Tạo vấn đề mới +label_issue_plural: Vấn đề +label_issue_view_all: Tất cả vấn đề +label_issues_by: Vấn đề của %s +label_issue_added: Đã thêm vấn đề +label_issue_updated: Vấn đề được cập nhật +label_document: Tài liệu +label_document_new: Tài liệu mới +label_document_plural: Tài liệu +label_document_added: Đã thêm tài liệu +label_role: Vai trò +label_role_plural: Vai trò +label_role_new: Vai trò mới +label_role_and_permissions: Vai trò và Quyền hạn +label_member: Thành viên +label_member_new: Thành viên mới +label_member_plural: Thành viên +label_tracker: Dòng vấn đề +label_tracker_plural: Dòng vấn đề +label_tracker_new: Tạo dòng vấn đề mới +label_workflow: Workflow +label_issue_status: Issue status +label_issue_status_plural: Issue statuses +label_issue_status_new: New status +label_issue_category: Chủ đề +label_issue_category_plural: Chủ đề +label_issue_category_new: Chủ đề mới +label_custom_field: Custom field +label_custom_field_plural: Custom fields +label_custom_field_new: New custom field +label_enumerations: Enumerations +label_enumeration_new: New value +label_information: Thông tin +label_information_plural: Thông tin +label_please_login: Vui lòng đăng nhập +label_register: Đăng ký +label_password_lost: Phục hồi mật mã +label_home: Trang chính +label_my_page: Trang riêng +label_my_account: Cá nhân +label_my_projects: Dá»± án của bạn +label_administration: Quản trị +label_login: Đăng nhập +label_logout: Thoát +label_help: Giúp đỡ +label_reported_issues: Vấn đề đã báo cáo +label_assigned_to_me_issues: Vấn đề gán cho bạn +label_last_login: Kết nối cuối +label_last_updates: Cập nhật cuối +label_last_updates_plural: %d cập nhật cuối +label_registered_on: Ngày tham gia +label_activity: Hoạt động +label_overall_activity: Tất cả hoạt động +label_new: Mới +label_logged_as: Tài khoản » +label_environment: Environment +label_authentication: Authentication +label_auth_source: Authentication mode +label_auth_source_new: New authentication mode +label_auth_source_plural: Authentication modes +label_subproject_plural: Dá»± án con +label_and_its_subprojects: %s và dá»± án con +label_min_max_length: Min - Max length +label_list: List +label_date: Ngày +label_integer: Integer +label_float: Float +label_boolean: Boolean +label_string: Text +label_text: Long text +label_attribute: Attribute +label_attribute_plural: Attributes +label_download: %d lần tải +label_download_plural: %d lần tải +label_no_data: ChÆ°a có thông tin gì +label_change_status: Đổi trạng thái +label_history: Lược sá»­ +label_attachment: Tập tin +label_attachment_new: Thêm tập tin mới +label_attachment_delete: Xóa tập tin +label_attachment_plural: Tập tin +label_file_added: Đã thêm tập tin +label_report: Báo cáo +label_report_plural: Báo cáo +label_news: Tin tức +label_news_new: Thêm tin +label_news_plural: Tin tức +label_news_latest: Tin mới +label_news_view_all: Xem mọi tin +label_news_added: Đã thêm tin +label_change_log: Nhật ký thay đổi +label_settings: Thiết lập +label_overview: Tóm tắt +label_version: Phiên bản +label_version_new: Phiên bản mới +label_version_plural: Phiên bản +label_confirmation: Khẳng định +label_export_to: 'Định dạng khác của trang này:' +label_read: Read... +label_public_projects: Các dá»± án công cộng +label_open_issues: mở +label_open_issues_plural: mở +label_closed_issues: đóng +label_closed_issues_plural: đóng +label_total: Tổng cộng +label_permissions: Quyền +label_current_status: Trạng thái hiện tại +label_new_statuses_allowed: Trạng thái mới được phép +label_all: tất cả +label_none: không +label_nobody: Chẳng ai +label_next: Sau +label_previous: Trước +label_used_by: Used by +label_details: Chi tiết +label_add_note: Thêm ghi chú +label_per_page: Mỗi trang +label_calendar: Lịch +label_months_from: tháng từ +label_gantt: Biểu đồ sá»± kiện +label_internal: Nội bộ +label_last_changes: %d thay đổi cuối +label_change_view_all: Xem mọi thay đổi +label_personalize_page: Điều chỉnh trang này +label_comment: Bình luận +label_comment_plural: Bình luận +label_comment_add: Thêm bình luận +label_comment_added: Đã thêm bình luận +label_comment_delete: Xóa bình luận +label_query: Truy vấn riêng +label_query_plural: Truy vấn riêng +label_query_new: Truy vấn mới +label_filter_add: Thêm lọc +label_filter_plural: Bộ lọc +label_equals: là +label_not_equals: không là +label_in_less_than: ít hÆ¡n +label_in_more_than: nhiều hÆ¡n +label_in: trong +label_today: hôm nay +label_all_time: mọi thời gian +label_yesterday: hôm qua +label_this_week: tuần này +label_last_week: tuần trước +label_last_n_days: %d ngày cuối +label_this_month: tháng này +label_last_month: tháng cuối +label_this_year: năm này +label_date_range: Thời gian +label_less_than_ago: cách đây dưới +label_more_than_ago: cách đây hÆ¡n +label_ago: cách đây +label_contains: chứa +label_not_contains: không chứa +label_day_plural: ngày +label_repository: Kho lÆ°u trữ +label_repository_plural: Kho lÆ°u trữ +label_browse: Duyệt +label_modification: %d thay đổi +label_modification_plural: %d thay đổi +label_revision: Bản điều chỉnh +label_revision_plural: Bản điều chỉnh +label_associated_revisions: Associated revisions +label_added: thêm +label_modified: đổi +label_copied: chép +label_renamed: đổi tên +label_deleted: xóa +label_latest_revision: Bản điều chỉnh cuối cùng +label_latest_revision_plural: Bản điều chỉnh cuối cùng +label_view_revisions: Xem các bản điều chỉnh +label_max_size: Dung lượng tối đa +label_on: '/ tổng số' +label_sort_highest: Lên trên cùng +label_sort_higher: Dịch lên +label_sort_lower: Dịch xuống +label_sort_lowest: Xuống dưới cùng +label_roadmap: Kế hoạch +label_roadmap_due_in: Hết hạn trong %s +label_roadmap_overdue: Trễ %s +label_roadmap_no_issues: Không có vấn đề cho phiên bản này +label_search: Tìm +label_result_plural: Kết quả +label_all_words: Mọi từ +label_wiki: Wiki +label_wiki_edit: Wiki edit +label_wiki_edit_plural: Thay đổi wiki +label_wiki_page: Trang wiki +label_wiki_page_plural: Trang wiki +label_index_by_title: Danh sách theo tên +label_index_by_date: Danh sách theo ngày +label_current_version: Bản hiện tại +label_preview: Xem trước +label_feed_plural: Feeds +label_changes_details: Chi tiết của mọi thay đổi +label_issue_tracking: Vấn đề +label_spent_time: Thời gian +label_f_hour: %.2f giờ +label_f_hour_plural: %.2f giờ +label_time_tracking: Theo dõi thời gian +label_change_plural: Thay đổi +label_statistics: Thống kê +label_commits_per_month: Commits per month +label_commits_per_author: Commits per author +label_view_diff: So sánh +label_diff_inline: inline +label_diff_side_by_side: side by side +label_options: Tùy chọn +label_copy_workflow_from: Copy workflow from +label_permissions_report: Thống kê các quyền +label_watched_issues: Chủ đề đang theo dõi +label_related_issues: Liên quan +label_applied_status: Trạng thái áp dụng +label_loading: Đang xá»­ lý... +label_relation_new: Quan hệ mới +label_relation_delete: Xóa quan hệ +label_relates_to: liên quan +label_duplicates: trùng với +label_duplicated_by: bị trùng bởi +label_blocks: chặn +label_blocked_by: chặn bởi +label_precedes: đi trước +label_follows: đi sau +label_end_to_start: cuối tới đầu +label_end_to_end: cuối tới cuối +label_start_to_start: đầu tớ đầu +label_start_to_end: đầu tới cuối +label_stay_logged_in: LÆ°u thông tin đăng nhập +label_disabled: bị vô hiệu +label_show_completed_versions: Xem phiên bản đã xong +label_me: tôi +label_board: Diễn đàn +label_board_new: Tạo diễn đàn mới +label_board_plural: Diễn đàn +label_topic_plural: Chủ đề +label_message_plural: Diễn đàn +label_message_last: Bài cuối +label_message_new: Tạo bài mới +label_message_posted: Đã thêm bài viết +label_reply_plural: Hồi âm +label_send_information: Gá»­i thông tin đến người dùng qua email +label_year: Năm +label_month: Tháng +label_week: Tuần +label_date_from: Từ +label_date_to: Đến +label_language_based: Theo ngôn ngữ người dùng +label_sort_by: Sắp xếp theo %s +label_send_test_email: Send a test email +label_feeds_access_key_created_on: "Mã chứng thá»±c RSS được tạo ra cách đây %s" +label_module_plural: Mô-đun +label_added_time_by: thêm bởi %s cách đây %s +label_updated_time: Cập nhật cách đây %s +label_jump_to_a_project: Nhảy đến dá»± án... +label_file_plural: Tập tin +label_changeset_plural: Thay đổi +label_default_columns: Cột mặc định +label_no_change_option: (không đổi) +label_bulk_edit_selected_issues: Sá»­a nhiều vấn đề +label_theme: Giao diện +label_default: Mặc định +label_search_titles_only: Chỉ tìm trong tá»±a đề +label_user_mail_option_all: "Mọi sá»± kiện trên mọi dá»± án của bạn" +label_user_mail_option_selected: "Mọi sá»± kiện trên các dá»± án được chọn..." +label_user_mail_option_none: "Chỉ những vấn đề bạn theo dõi hoặc được gán" +label_user_mail_no_self_notified: "Đừng gá»­i email về các thay đổi do chính bạn thá»±c hiện" +label_registration_activation_by_email: account activation by email +label_registration_manual_activation: manual account activation +label_registration_automatic_activation: automatic account activation +label_display_per_page: 'mỗi trang: %s' +label_age: Age +label_change_properties: Thay đổi thuộc tính +label_general: Tổng quan +label_more: Chi tiết +label_scm: SCM +label_plugins: Mô-đun +label_ldap_authentication: Chứng thá»±c LDAP +label_downloads_abbr: Tải về +label_optional_description: Mô tả bổ sung +label_add_another_file: Thêm tập tin khác +label_preferences: Cấu hình +label_chronological_order: Bài cÅ© xếp trước +label_reverse_chronological_order: Bài mới xếp trước +label_planning: Kế hoạch +label_incoming_emails: Nhận mail +label_generate_key: Tạo mã +label_issue_watchers: Theo dõi + +button_login: Đăng nhập +button_submit: Gá»­i +button_save: LÆ°u +button_check_all: Đánh dấu tất cả +button_uncheck_all: Bỏ dấu tất cả +button_delete: Xóa +button_create: Tạo +button_test: Kiểm tra +button_edit: Sá»­a +button_add: Thêm +button_change: Đổi +button_apply: Áp dụng +button_clear: Xóa +button_lock: Khóa +button_unlock: Mở khóa +button_download: Tải về +button_list: Liệt kê +button_view: Xem +button_move: Chuyển +button_back: Quay lại +button_cancel: Bỏ qua +button_activate: Kích hoạt +button_sort: Sắp xếp +button_log_time: Thêm thời gian +button_rollback: Quay trở lại phiên bản này +button_watch: Theo dõi +button_unwatch: Bỏ theo dõi +button_reply: Trả lời +button_archive: Đóng băng +button_unarchive: Xả băng +button_reset: Tạo lại +button_rename: Đổi tên +button_change_password: Đổi mật mã +button_copy: Chép +button_annotate: Chú giải +button_update: Cập nhật +button_configure: Cấu hình +button_quote: Trích dẫn + +status_active: hoạt động +status_registered: đăng ký +status_locked: khóa + +text_select_mail_notifications: Chọn hành động đối với mỗi email thông báo sẽ gá»­i. +text_regexp_info: eg. ^[A-Z0-9]+$ +text_min_max_length_info: 0 để chỉ không hạn chế +text_project_destroy_confirmation: 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: Bạn chắc chứ? +text_journal_changed: đổi từ %s sang %s +text_journal_set_to: đặt thành %s +text_journal_deleted: xóa +text_tip_task_begin_day: ngày bắt đầu +text_tip_task_end_day: ngày kết thúc +text_tip_task_begin_end_day: bắt đầu và kết thúc cùng ngày +text_project_identifier_info: 'Chỉ cho phép chữ cái thường (a-z), con số và dấu gạch ngang.
    Sau khi lÆ°u, chỉ số ID không thể thay đổi.' +text_caracters_maximum: Tối đa %d ký tá»±. +text_caracters_minimum: Phải gồm ít nhất %d ký tá»±. +text_length_between: Length between %d and %d characters. +text_tracker_no_workflow: No workflow defined for this tracker +text_unallowed_characters: Ký tá»± không hợp lệ +text_comma_separated: Multiple values allowed (comma separated). +text_issues_ref_in_commit_messages: Referencing and fixing issues in commit messages +text_issue_added: Issue %s has been reported by %s. +text_issue_updated: Issue %s has been updated by %s. +text_wiki_destroy_confirmation: Are you sure you want to delete this wiki and all its content ? +text_issue_category_destroy_question: Some issues (%d) are assigned to this category. What do you want to do ? +text_issue_category_destroy_assignments: Remove category assignments +text_issue_category_reassign_to: Reassign issues to this category +text_user_mail_option: "Với các dá»± án không được chọn, bạn chỉ có thể nhận được thông báo về các vấn đề bạn đăng ký theo dõi hoặc có liên quan đến bạn (chẳng hạn, vấn đề được gán cho bạn)." +text_no_configuration_data: "Roles, trackers, issue statuses and workflow have not been configured yet.\nIt is highly recommended to load the default configuration. You will be able to modify it once loaded." +text_load_default_configuration: Load the default configuration +text_status_changed_by_changeset: Applied in changeset %s. +text_issues_destroy_confirmation: 'Are you sure you want to delete the selected issue(s) ?' +text_select_project_modules: 'Chọn các mô-đun cho dá»± án:' +text_default_administrator_account_changed: Default administrator account changed +text_file_repository_writable: File repository writable +text_rmagick_available: RMagick available (optional) +text_destroy_time_entries_question: %.02f hours were reported on the issues you are about to delete. What do you want to do ? +text_destroy_time_entries: Delete reported hours +text_assign_time_entries_to_project: Assign reported hours to the project +text_reassign_time_entries: 'Reassign reported hours to this issue:' +text_user_wrote: '%s wrote:' +text_enumeration_destroy_question: '%d objects are assigned to this value.' +text_enumeration_category_reassign_to: 'Reassign them to this value:' +text_email_delivery_not_configured: "Email delivery is not configured, and notifications are disabled.\nConfigure your SMTP server in config/email.yml and restart the application to enable them." + +default_role_manager: Điều hành +default_role_developper: Phát triển +default_role_reporter: Báo cáo +default_tracker_bug: Lỗi +default_tracker_feature: Tính năng +default_tracker_support: Hỗ trợ +default_issue_status_new: Mới +default_issue_status_assigned: Đã gán +default_issue_status_resolved: Quyết tâm +default_issue_status_feedback: Phản hồi +default_issue_status_closed: Đóng +default_issue_status_rejected: Từ chối +default_doc_category_user: Tài liệu người dùng +default_doc_category_tech: Tài liệu kỹ thuật +default_priority_low: Thấp +default_priority_normal: Bình thường +default_priority_high: Cao +default_priority_urgent: Khẩn cấp +default_priority_immediate: Trung bình +default_activity_design: Thiết kế +default_activity_development: Phát triển + +enumeration_issue_priorities: Mức độ Æ°u tiên vấn đề +enumeration_doc_categories: Chủ đề tài liệu +enumeration_activities: Hoạt động (theo dõi thời gian) + +setting_plain_text_mail: mail dạng text đơn giản (không dùng HTML) +setting_gravatar_enabled: Dùng biểu tượng Gravatar +permission_edit_project: Chỉnh dá»± án +permission_select_project_modules: Chọn mô-đun +permission_manage_members: Quản lý thành viên +permission_manage_versions: Quản lý phiên bản +permission_manage_categories: Quản lý chủ đề +permission_add_issues: Thêm vấn đề +permission_edit_issues: Sá»­a vấn đề +permission_manage_issue_relations: Quản lý quan hệ vấn đề +permission_add_issue_notes: Thêm chú thích +permission_edit_issue_notes: Sá»­a chú thích +permission_edit_own_issue_notes: Sá»­a chú thích cá nhân +permission_move_issues: Chuyển vấn đề +permission_delete_issues: Xóa vấn đề +permission_manage_public_queries: Quản lý truy cấn công cộng +permission_save_queries: LÆ°u truy vấn +permission_view_gantt: Xem biểu đồ sá»± kiện +permission_view_calendar: Xem lịch +permission_view_issue_watchers: Xem các người theo dõi +permission_add_issue_watchers: Thêm người theo dõi +permission_log_time: LÆ°u thời gian đã tốn +permission_view_time_entries: Xem thời gian đã tốn +permission_edit_time_entries: Xem nhật ký thời gian +permission_edit_own_time_entries: Sá»­a thời gian đã lÆ°u +permission_manage_news: Quản lý tin mới +permission_comment_news: Chú thích vào tin mới +permission_manage_documents: Quản lý tài liệu +permission_view_documents: Xem tài liệu +permission_manage_files: Quản lý tập tin +permission_view_files: Xem tập tin +permission_manage_wiki: Quản lý wiki +permission_rename_wiki_pages: Đổi tên trang wiki +permission_delete_wiki_pages: Xóa trang wiki +permission_view_wiki_pages: Xem wiki +permission_view_wiki_edits: Xem lược sá»­ trang wiki +permission_edit_wiki_pages: Sá»­a trang wiki +permission_delete_wiki_pages_attachments: Xóa tệp đính kèm +permission_protect_wiki_pages: Bảo vệ trang wiki +permission_manage_repository: Quản lý kho lÆ°u trữ +permission_browse_repository: Duyệt kho lÆ°u trữ +permission_view_changesets: Xem các thay đổi +permission_commit_access: Truy cập commit +permission_manage_boards: Quản lý diễn đàn +permission_view_messages: Xem bài viết +permission_add_messages: Gá»­i bài viết +permission_edit_messages: Sá»­a bài viết +permission_edit_own_messages: Sá»­a bài viết cá nhân +permission_delete_messages: Xóa bài viết +permission_delete_own_messages: Xóa bài viết cá nhân +label_example: Ví dụ +text_repository_usernames_mapping: "Chọn hoặc cập nhật ánh xạ người dùng hệ thống với người dùng trong kho lÆ°u trữ.\nNhững trường hợp trùng hợp về tên và email sẽ được tá»± động ánh xạ." +permission_delete_own_messages: Delete own messages +label_user_activity: "%s's activity" +label_updated_time_by: Updated by %s %s ago +text_diff_truncated: '... This diff was truncated because it exceeds the maximum size that can be displayed.' +setting_diff_max_lines_displayed: Max number of diff lines displayed +text_plugin_assets_writable: Plugin assets directory writable +warning_attachments_not_saved: "%d file(s) could not be saved." +button_create_and_continue: Create and continue +text_custom_field_possible_values_info: 'One line for each value' +label_display: Display +field_editable: Editable +setting_repository_log_display_limit: Maximum number of revisions displayed on file log +field_identity_url: OpenID URL +setting_openid: Allow OpenID login and registration +label_login_with_open_id_option: or login with OpenID +field_watcher: Watcher diff --git a/lang/zh-tw.yml b/lang/zh-tw.yml index 3ddf1402e..9f3788a85 100644 --- a/lang/zh-tw.yml +++ b/lang/zh-tw.yml @@ -85,6 +85,8 @@ error_scm_command_failed: "嘗試存取儲存庫時發生錯誤: %s" error_scm_annotate: "SCM 儲存庫中無此項目或此項目無法被加註。" error_issue_not_found_in_project: '該項目不存在或不屬於此專案' +warning_attachments_not_saved: "%d 個附加檔案無法儲存。" + mail_subject_lost_password: 您的 Redmine 網站密碼 mail_body_lost_password: '欲變更您的 Redmine 網站密碼, 請點選以下鏈結:' mail_subject_register: 啟用您的 Redmine 帳號 @@ -184,6 +186,7 @@ field_searchable: 可用做搜尋條件 field_default_value: 預設值 field_comments_sorting: 註解排序 field_parent_title: 父頁面 +field_editable: 可編輯 setting_app_title: 標題 setting_app_subtitle: 副標題 @@ -195,6 +198,7 @@ setting_attachment_max_size: 附件大小限制 setting_issues_export_limit: 項目匯出限制 setting_mail_from: 寄件者電子郵件 setting_bcc_recipients: 使用密件副本 (BCC) +setting_plain_text_mail: 純文字郵件 (不含 HTML) setting_host_name: 主機名稱 setting_text_formatting: 文字格式 setting_wiki_compression: 壓縮 Wiki 歷史文章 @@ -221,6 +225,58 @@ setting_enabled_scm: 啟用的 SCM setting_mail_handler_api_enabled: 啟用處理傳入電子郵件的服務 setting_mail_handler_api_key: API 金鑰 setting_sequential_project_identifiers: 循序產生專案識別碼 +setting_gravatar_enabled: 啟用 Gravatar 全球認證大頭像 +setting_diff_max_lines_displayed: 差異顯示行數之最大值 +setting_repository_log_display_limit: 版次顯示數目之最大值 + +permission_edit_project: 編輯專案 +permission_select_project_modules: 選擇專案模組 +permission_manage_members: 管理成員 +permission_manage_versions: 管理版本 +permission_manage_categories: 管理項目分類 +permission_add_issues: 新增項目 +permission_edit_issues: 編輯項目 +permission_manage_issue_relations: 管理項目關聯 +permission_add_issue_notes: 新增筆記 +permission_edit_issue_notes: 編輯筆記 +permission_edit_own_issue_notes: 編輯自己的筆記 +permission_move_issues: 搬移項目 +permission_delete_issues: 刪除項目 +permission_manage_public_queries: 管理公開查詢 +permission_save_queries: 儲存查詢 +permission_view_gantt: 檢視甘特圖 +permission_view_calendar: 檢視日曆 +permission_view_issue_watchers: 檢視觀察者清單 +permission_add_issue_watchers: 增加觀察者 +permission_log_time: 紀錄耗用工時 +permission_view_time_entries: 檢視耗用工時 +permission_edit_time_entries: 編輯工時紀錄 +permission_edit_own_time_entries: 編輯自己的工時記錄 +permission_manage_news: 管理新聞 +permission_comment_news: 註解新聞 +permission_manage_documents: 管理文件 +permission_view_documents: 檢視文件 +permission_manage_files: 管理檔案 +permission_view_files: 檢視檔案 +permission_manage_wiki: 管理 wiki +permission_rename_wiki_pages: 重新命名 wiki 頁面 +permission_delete_wiki_pages: 刪除 wiki 頁面 +permission_view_wiki_pages: 檢視 wiki +permission_view_wiki_edits: 檢視 wiki 歷史 +permission_edit_wiki_pages: 編輯 wiki 頁面 +permission_delete_wiki_pages_attachments: 刪除附件 +permission_protect_wiki_pages: 專案 wiki 頁面 +permission_manage_repository: 管理版本庫 +permission_browse_repository: 瀏覽版本庫 +permission_view_changesets: 檢視變更集 +permission_commit_access: 存取送交之變更 +permission_manage_boards: 管理討論版 +permission_view_messages: 檢視訊息 +permission_add_messages: 新增訊息 +permission_edit_messages: 編輯訊息 +permission_edit_own_messages: 編輯自己的訊息 +permission_delete_messages: 刪除訊息 +permission_delete_own_messages: 刪除自己的訊息 project_module_issue_tracking: 項目追蹤 project_module_time_tracking: 工時追蹤 @@ -293,6 +349,7 @@ label_last_updates_plural: %d 個最近更新 label_registered_on: 註冊於 label_activity: 活動 label_overall_activity: 檢視所有活動 +label_user_activity: "%s 的活動" label_new: 建立新的... label_logged_as: 目前登入 label_environment: 環境 @@ -418,7 +475,7 @@ label_sort_higher: 往上移動 label_sort_lower: 往下移動 label_sort_lowest: 移動至結尾 label_roadmap: 版本藍圖 -label_roadmap_due_in: 倒數天數 %s +label_roadmap_due_in: 倒數天數: label_roadmap_overdue: %s 逾期 label_roadmap_no_issues: 此版本尚未包含任何項目 label_search: 搜尋 @@ -492,6 +549,7 @@ label_send_test_email: 寄送測試郵件 label_feeds_access_key_created_on: RSS 存取鍵建立於 %s 之前 label_module_plural: 模組 label_added_time_by: 是由 %s 於 %s 前加入 +label_updated_time_by: 是由 %s 於 %s 前更新 label_updated_time: 於 %s 前更新 label_jump_to_a_project: 選擇欲前往的專案... label_file_plural: 檔案清單 @@ -503,7 +561,7 @@ label_theme: 畫面主題 label_default: 預設 label_search_titles_only: 僅搜尋標題 label_user_mail_option_all: "提醒與我的專案有關的所有事件" -label_user_mail_option_selected: "只停醒我所選擇專案中的事件..." +label_user_mail_option_selected: "只提醒我所選擇專案中的事件..." label_user_mail_option_none: "只提醒我觀察中或參與中的事件" label_user_mail_no_self_notified: "不提醒我自己所做的變更" label_registration_activation_by_email: 透過電子郵件啟用帳戶 @@ -527,6 +585,8 @@ label_planning: 計劃表 label_incoming_emails: 傳入的電子郵件 label_generate_key: 產生金鑰 label_issue_watchers: 觀察者 +label_example: 範例 +label_display: 顯示 button_login: 登入 button_submit: 送出 @@ -535,6 +595,7 @@ button_check_all: 全選 button_uncheck_all: 全不選 button_delete: 刪除 button_create: 建立 +button_create_and_continue: 繼續建立 button_test: 測試 button_edit: 編輯 button_add: 新增 @@ -605,7 +666,8 @@ text_status_changed_by_changeset: 已套用至變更集 %s. text_issues_destroy_confirmation: '確定刪除已選擇的項目?' text_select_project_modules: '選擇此專案可使用之模組:' text_default_administrator_account_changed: 已變更預設管理員帳號內容 -text_file_repository_writable: 可寫入檔案 +text_file_repository_writable: 可寫入附加檔案目錄 +text_plugin_assets_writable: 可寫入附加元件目錄 text_rmagick_available: 可使用 RMagick (選配) text_destroy_time_entries_question: 您即將刪除的項目已報工 %.02f 小時. 您的選擇是? text_destroy_time_entries: 刪除已報工的時數 @@ -615,6 +677,9 @@ text_user_wrote: '%s 先前提到:' text_enumeration_destroy_question: '目前有 %d 個物件使用此列舉值。' text_enumeration_category_reassign_to: '重新設定其列舉值為:' text_email_delivery_not_configured: "您尚未設定電子郵件傳送方式,因此提醒選項已被停用。\n請在 config/email.yml 中設定 SMTP 之後,重新啟動 Redmine,以啟用電子郵件提醒選項。" +text_repository_usernames_mapping: "選擇或更新 Redmine 使用者與版本庫使用者之對應關係。\n版本庫中之使用者帳號或電子郵件信箱,與 Redmine 設定相同者,將自動產生對應關係。" +text_diff_truncated: '... 這份差異已被截短以符合顯示行數之最大值' +text_custom_field_possible_values_info: '一列輸入一個值' default_role_manager: 管理人員 default_role_developper: 開發人員 @@ -641,5 +706,7 @@ default_activity_development: 開發 enumeration_issue_priorities: 項目優先權 enumeration_doc_categories: 文件分類 enumeration_activities: 活動 (時間追蹤) -setting_repositories_cache_directory: Cache directory for repositories -field_cache: Local cache +field_identity_url: OpenID URL +setting_openid: Allow OpenID login and registration +label_login_with_open_id_option: or login with OpenID +field_watcher: Watcher diff --git a/lang/zh.yml b/lang/zh.yml index cd2d3e407..4be80b3bb 100644 --- a/lang/zh.yml +++ b/lang/zh.yml @@ -85,6 +85,8 @@ error_scm_command_failed: "访问版本库时发生错误:%s" error_scm_annotate: "该条目不存在或无法追溯。" error_issue_not_found_in_project: '问题不存在或不属于此项目' +warning_attachments_not_saved: "%d 个文件保存失败。" + mail_subject_lost_password: 您的 %s 密码 mail_body_lost_password: '请点击以下链接来修改您的密码:' mail_subject_register: %s帐号激活 @@ -184,6 +186,7 @@ field_searchable: 可用作搜索条件 field_default_value: 默认值 field_comments_sorting: 显示注释 field_parent_title: 上级页面 +field_editable: 可编辑 setting_app_title: 应用程序标题 setting_app_subtitle: 应用程序子标题 @@ -195,6 +198,7 @@ setting_attachment_max_size: 附件大小限制 setting_issues_export_limit: 问题输出条目的限制 setting_mail_from: 邮件发件人地址 setting_bcc_recipients: 使用密件抄送 (bcc) +setting_plain_text_mail: 纯文本(无HTML) setting_host_name: 主机名称 setting_text_formatting: 文本格式 setting_wiki_compression: 压缩Wiki历史文档 @@ -218,9 +222,61 @@ setting_user_format: 用户显示格式 setting_activity_days_default: 在项目活动中显示的天数 setting_display_subprojects_issues: 在项目页面上默认显示子项目的问题 setting_enabled_scm: 启用 SCM -setting_mail_handler_api_enabled: 启用用于接收邮件的Web Service +setting_mail_handler_api_enabled: 启用用于接收邮件的服务 setting_mail_handler_api_key: API key setting_sequential_project_identifiers: 顺序产生项目标识 +setting_gravatar_enabled: 使用Gravatar用户头像 +setting_diff_max_lines_displayed: 查看差别页面上显示的最大行数 +setting_repository_log_display_limit: 在文件变更记录页面上显示的最大修订版本数量 + +permission_edit_project: 编辑项目 +permission_select_project_modules: 选择项目模块 +permission_manage_members: 管理成员 +permission_manage_versions: 管理版本 +permission_manage_categories: 管理问题类别 +permission_add_issues: 新建问题 +permission_edit_issues: 更新问题 +permission_manage_issue_relations: 管理问题关联 +permission_add_issue_notes: 添加说明 +permission_edit_issue_notes: 编辑说明 +permission_edit_own_issue_notes: 编辑自己的说明 +permission_move_issues: 移动问题 +permission_delete_issues: 删除问题 +permission_manage_public_queries: 管理公开的查询 +permission_save_queries: 保存查询 +permission_view_gantt: 查看甘特图 +permission_view_calendar: 查看日历 +permission_view_issue_watchers: 查看跟踪者列表 +permission_add_issue_watchers: 添加跟踪者 +permission_log_time: 登记工时 +permission_view_time_entries: 查看耗时 +permission_edit_time_entries: 编辑耗时 +permission_edit_own_time_entries: 编辑自己的耗时 +permission_manage_news: 管理新闻 +permission_comment_news: 为新闻添加评论 +permission_manage_documents: 管理文档 +permission_view_documents: 查看文档 +permission_manage_files: 管理文件 +permission_view_files: 查看文件 +permission_manage_wiki: 管理Wiki +permission_rename_wiki_pages: 重命名Wiki页面 +permission_delete_wiki_pages: 删除Wiki页面 +permission_view_wiki_pages: 查看Wiki +permission_view_wiki_edits: 查看Wiki历史记录 +permission_edit_wiki_pages: 编辑Wiki页面 +permission_delete_wiki_pages_attachments: 删除附件 +permission_protect_wiki_pages: 保护Wiki页面 +permission_manage_repository: 管理版本库 +permission_browse_repository: 浏览版本库 +permission_view_changesets: 查看变更 +permission_commit_access: 访问提交信息 +permission_manage_boards: 管理讨论区 +permission_view_messages: 查看帖子 +permission_add_messages: 发表帖子 +permission_edit_messages: 编辑帖子 +permission_edit_own_messages: 编辑自己的帖子 +permission_delete_messages: 删除帖子 +permission_delete_own_messages: 删除自己的帖子 project_module_issue_tracking: 问题跟踪 project_module_time_tracking: 时间跟踪 @@ -293,6 +349,7 @@ label_last_updates_plural: %d 最后更新 label_registered_on: 注册于 label_activity: 活动 label_overall_activity: 全部活动 +label_user_activity: "%s 的活动" label_new: 新建 label_logged_as: 登录为 label_environment: 环境 @@ -492,7 +549,8 @@ label_send_test_email: 发送测试邮件 label_feeds_access_key_created_on: RSS 存取键是在 %s 之前建立的 label_module_plural: 模块 label_added_time_by: 由 %s 在 %s 之前添加 -label_updated_time: 更新于 %s 前 +label_updated_time: 更新于 %s 之前 +label_updated_time_by: 由 %s 更新于 %s 之前 label_jump_to_a_project: 选择一个项目... label_file_plural: 文件 label_changeset_plural: 变更 @@ -527,6 +585,8 @@ label_planning: 计划 label_incoming_emails: 接收邮件 label_generate_key: 生成一个key label_issue_watchers: 跟踪者 +label_example: 示例 +label_display: 显示 button_login: 登录 button_submit: 提交 @@ -535,6 +595,7 @@ button_check_all: 全选 button_uncheck_all: 清除 button_delete: 删除 button_create: 创建 +button_create_and_continue: 创建并继续 button_test: 测试 button_edit: 编辑 button_add: 新增 @@ -605,7 +666,8 @@ text_status_changed_by_changeset: 已应用到变更列表 %s. text_issues_destroy_confirmation: '您确定要删除选中的问题吗?' text_select_project_modules: '请选择此项目可以使用的模块:' text_default_administrator_account_changed: 默认的管理员帐号已改变 -text_file_repository_writable: 文件版本库可修改 +text_file_repository_writable: 附件路径可写 +text_plugin_assets_writable: 插件的附件路径可写 text_rmagick_available: RMagick 可用(可选的) text_destroy_time_entries_question: 您要删除的问题已经上报了 %.02f 小时的工作量。您想进行那种操作? text_destroy_time_entries: 删除上报的工作量 @@ -615,6 +677,9 @@ text_user_wrote: '%s 写到:' text_enumeration_category_reassign_to: '将它们关联到新的枚举值:' text_enumeration_destroy_question: '%d 个对象被关联到了这个枚举值。' text_email_delivery_not_configured: "邮件参数尚未配置,因此邮件通知功能已被禁用。\n请在config/email.yml中配置您的SMTP服务器信息并重新启动以使其生效。" +text_repository_usernames_mapping: "选择或更新与版本库中的用户名对应的Redmine用户。\n版本库中与Redmine中的同名用户将被自动对应。" +text_diff_truncated: '... 差别内容超过了可显示的最大行数并已被截断' +text_custom_field_possible_values_info: '每项数值一行' default_role_manager: 管理人员 default_role_developper: 开发人员 @@ -641,5 +706,7 @@ default_activity_development: 开发 enumeration_issue_priorities: 问题优先级 enumeration_doc_categories: 文档类别 enumeration_activities: 活动(时间跟踪) -setting_repositories_cache_directory: Cache directory for repositories -field_cache: Local cache +field_identity_url: OpenID URL +setting_openid: Allow OpenID login and registration +label_login_with_open_id_option: or login with OpenID +field_watcher: Watcher diff --git a/lib/generators/redmine_plugin/redmine_plugin_generator.rb b/lib/generators/redmine_plugin/redmine_plugin_generator.rb index 666386abd..bd161a5d7 100644 --- a/lib/generators/redmine_plugin/redmine_plugin_generator.rb +++ b/lib/generators/redmine_plugin/redmine_plugin_generator.rb @@ -22,10 +22,10 @@ class RedminePluginGenerator < Rails::Generator::NamedBase m.directory "#{plugin_path}/lang" m.directory "#{plugin_path}/test" - m.template 'README', "#{plugin_path}/README" - m.template 'init.rb', "#{plugin_path}/init.rb" + m.template 'README.rdoc', "#{plugin_path}/README.rdoc" + m.template 'init.rb.erb', "#{plugin_path}/init.rb" m.template 'en.yml', "#{plugin_path}/lang/en.yml" - m.template 'test_helper.rb', "#{plugin_path}/test/test_helper.rb" + m.template 'test_helper.rb.erb', "#{plugin_path}/test/test_helper.rb" end end end diff --git a/lib/generators/redmine_plugin/templates/README b/lib/generators/redmine_plugin/templates/README.rdoc similarity index 100% rename from lib/generators/redmine_plugin/templates/README rename to lib/generators/redmine_plugin/templates/README.rdoc diff --git a/lib/generators/redmine_plugin/templates/init.rb b/lib/generators/redmine_plugin/templates/init.rb.erb similarity index 100% rename from lib/generators/redmine_plugin/templates/init.rb rename to lib/generators/redmine_plugin/templates/init.rb.erb diff --git a/lib/generators/redmine_plugin/templates/test_helper.rb b/lib/generators/redmine_plugin/templates/test_helper.rb.erb similarity index 100% rename from lib/generators/redmine_plugin/templates/test_helper.rb rename to lib/generators/redmine_plugin/templates/test_helper.rb.erb diff --git a/lib/generators/redmine_plugin_controller/redmine_plugin_controller_generator.rb b/lib/generators/redmine_plugin_controller/redmine_plugin_controller_generator.rb index 533d65ce8..efe28c5da 100644 --- a/lib/generators/redmine_plugin_controller/redmine_plugin_controller_generator.rb +++ b/lib/generators/redmine_plugin_controller/redmine_plugin_controller_generator.rb @@ -15,4 +15,40 @@ class RedminePluginControllerGenerator < ControllerGenerator def destination_root File.join(RAILS_ROOT, plugin_path) end + + def manifest + record do |m| + # Check for class naming collisions. + m.class_collisions class_path, "#{class_name}Controller", "#{class_name}ControllerTest", "#{class_name}Helper" + + # Controller, helper, views, and test directories. + m.directory File.join('app/controllers', class_path) + m.directory File.join('app/helpers', class_path) + m.directory File.join('app/views', class_path, file_name) + m.directory File.join('test/functional', class_path) + + # Controller class, functional test, and helper class. + m.template 'controller.rb.erb', + File.join('app/controllers', + class_path, + "#{file_name}_controller.rb") + + m.template 'functional_test.rb.erb', + File.join('test/functional', + class_path, + "#{file_name}_controller_test.rb") + + m.template 'helper.rb.erb', + File.join('app/helpers', + class_path, + "#{file_name}_helper.rb") + + # View template for each action. + actions.each do |action| + path = File.join('app/views', class_path, file_name, "#{action}.html.erb") + m.template 'view.html.erb', path, + :assigns => { :action => action, :path => path } + end + end + end end diff --git a/lib/generators/redmine_plugin_controller/templates/controller.rb b/lib/generators/redmine_plugin_controller/templates/controller.rb.erb similarity index 100% rename from lib/generators/redmine_plugin_controller/templates/controller.rb rename to lib/generators/redmine_plugin_controller/templates/controller.rb.erb diff --git a/lib/generators/redmine_plugin_controller/templates/functional_test.rb b/lib/generators/redmine_plugin_controller/templates/functional_test.rb.erb similarity index 100% rename from lib/generators/redmine_plugin_controller/templates/functional_test.rb rename to lib/generators/redmine_plugin_controller/templates/functional_test.rb.erb diff --git a/lib/generators/redmine_plugin_controller/templates/helper.rb b/lib/generators/redmine_plugin_controller/templates/helper.rb.erb similarity index 100% rename from lib/generators/redmine_plugin_controller/templates/helper.rb rename to lib/generators/redmine_plugin_controller/templates/helper.rb.erb diff --git a/lib/generators/redmine_plugin_model/redmine_plugin_model_generator.rb b/lib/generators/redmine_plugin_model/redmine_plugin_model_generator.rb index b712d9b07..059a028d6 100644 --- a/lib/generators/redmine_plugin_model/redmine_plugin_model_generator.rb +++ b/lib/generators/redmine_plugin_model/redmine_plugin_model_generator.rb @@ -15,4 +15,30 @@ class RedminePluginModelGenerator < ModelGenerator def destination_root File.join(RAILS_ROOT, plugin_path) end + + def manifest + record do |m| + # Check for class naming collisions. + m.class_collisions class_path, class_name, "#{class_name}Test" + + # Model, test, and fixture directories. + m.directory File.join('app/models', class_path) + m.directory File.join('test/unit', class_path) + m.directory File.join('test/fixtures', class_path) + + # Model class, unit test, and fixtures. + m.template 'model.rb.erb', File.join('app/models', class_path, "#{file_name}.rb") + m.template 'unit_test.rb.erb', File.join('test/unit', class_path, "#{file_name}_test.rb") + + unless options[:skip_fixture] + m.template 'fixtures.yml', File.join('test/fixtures', "#{table_name}.yml") + end + + unless options[:skip_migration] + m.migration_template 'migration.rb.erb', 'db/migrate', :assigns => { + :migration_name => "Create#{class_name.pluralize.gsub(/::/, '')}" + }, :migration_file_name => "create_#{file_path.gsub(/\//, '_').pluralize}" + end + end + end end diff --git a/lib/generators/redmine_plugin_model/templates/migration.rb b/lib/generators/redmine_plugin_model/templates/migration.rb.erb similarity index 100% rename from lib/generators/redmine_plugin_model/templates/migration.rb rename to lib/generators/redmine_plugin_model/templates/migration.rb.erb diff --git a/lib/generators/redmine_plugin_model/templates/model.rb b/lib/generators/redmine_plugin_model/templates/model.rb.erb similarity index 100% rename from lib/generators/redmine_plugin_model/templates/model.rb rename to lib/generators/redmine_plugin_model/templates/model.rb.erb diff --git a/lib/generators/redmine_plugin_model/templates/unit_test.rb b/lib/generators/redmine_plugin_model/templates/unit_test.rb.erb similarity index 100% rename from lib/generators/redmine_plugin_model/templates/unit_test.rb rename to lib/generators/redmine_plugin_model/templates/unit_test.rb.erb diff --git a/lib/redcloth3.rb b/lib/redcloth3.rb index a5e63262c..9e63bf5ac 100644 --- a/lib/redcloth3.rb +++ b/lib/redcloth3.rb @@ -272,7 +272,7 @@ class RedCloth3 < String @shelf = [] textile_rules = [:refs_textile, :block_textile_table, :block_textile_lists, :block_textile_prefix, :inline_textile_image, :inline_textile_link, - :inline_textile_code, :inline_textile_span] + :inline_textile_code, :inline_textile_span, :glyphs_textile] markdown_rules = [:refs_markdown, :block_markdown_setext, :block_markdown_atx, :block_markdown_rule, :block_markdown_bq, :block_markdown_lists, :inline_markdown_reflink, :inline_markdown_link] @@ -341,7 +341,7 @@ class RedCloth3 < String A_HLGN = /(?:(?:<>|<|>|\=|[()]+)+)/ A_VLGN = /[\-^~]/ C_CLAS = '(?:\([^)]+\))' - C_LNGE = '(?:\[[^\]]+\])' + C_LNGE = '(?:\[[^\[\]]+\])' C_STYL = '(?:\{[^}]+\})' S_CSPN = '(?:\\\\\d+)' S_RSPN = '(?:/\d+)' @@ -382,14 +382,14 @@ class RedCloth3 < String (#{rcq}) (#{C}) (?::(\S+?))? - ([^\s\-].*?[^\s\-]|\w) + (\w|[^\s\-].*?[^\s\-]) #{rcq} (?=[[:punct:]]|\s|\)|$)/x else /(#{rcq}) (#{C}) (?::(\S+))? - ([^\s\-].*?[^\s\-]|\w) + (\w|[^\s\-].*?[^\s\-]) #{rcq}/xm end [rc, ht, re, rtype] @@ -401,22 +401,22 @@ class RedCloth3 < String # [ /([^\s\[{(>#{PUNCT_Q}][#{PUNCT_Q}]*)\'/, '\1’' ], # single closing # [ /\'(?=[#{PUNCT_Q}]*(s\b|[\s#{PUNCT_NOQ}]))/, '’' ], # single closing # [ /\'/, '‘' ], # single opening - [ //, '>' ], # greater-than + # [ //, '>' ], # greater-than # [ /([^\s\[{(])?"(\s|:|$)/, '\1”\2' ], # double closing # [ /([^\s\[{(>#{PUNCT_Q}][#{PUNCT_Q}]*)"/, '\1”' ], # double closing # [ /"(?=[#{PUNCT_Q}]*[\s#{PUNCT_NOQ}])/, '”' ], # double closing # [ /"/, '“' ], # double opening - [ /\b( )?\.{3}/, '\1…' ], # ellipsis - [ /\b([A-Z][A-Z0-9]{2,})\b(?:[(]([^)]*)[)])/, '\1' ], # 3+ uppercase acronym - [ /(^|[^"][>\s])([A-Z][A-Z0-9 ]+[A-Z0-9])([^\2\3', :no_span_caps ], # 3+ uppercase caps - [ /(\.\s)?\s?--\s?/, '\1—' ], # em dash - [ /\s->\s/, ' → ' ], # right arrow - [ /\s-\s/, ' – ' ], # en dash - [ /(\d+) ?x ?(\d+)/, '\1×\2' ], # dimension sign - [ /\b ?[(\[]TM[\])]/i, '™' ], # trademark - [ /\b ?[(\[]R[\])]/i, '®' ], # registered - [ /\b ?[(\[]C[\])]/i, '©' ] # copyright + # [ /\b( )?\.{3}/, '\1…' ], # ellipsis + # [ /\b([A-Z][A-Z0-9]{2,})\b(?:[(]([^)]*)[)])/, '\1' ], # 3+ uppercase acronym + # [ /(^|[^"][>\s])([A-Z][A-Z0-9 ]+[A-Z0-9])([^\2\3', :no_span_caps ], # 3+ uppercase caps + # [ /(\.\s)?\s?--\s?/, '\1—' ], # em dash + # [ /\s->\s/, ' → ' ], # right arrow + # [ /\s-\s/, ' – ' ], # en dash + # [ /(\d+) ?x ?(\d+)/, '\1×\2' ], # dimension sign + # [ /\b ?[(\[]TM[\])]/i, '™' ], # trademark + # [ /\b ?[(\[]R[\])]/i, '®' ], # registered + # [ /\b ?[(\[]C[\])]/i, '©' ] # copyright ] H_ALGN_VALS = { @@ -435,19 +435,25 @@ class RedCloth3 < String # # Flexible HTML escaping # - def htmlesc( str, mode ) + def htmlesc( str, mode=:Quotes ) + if str str.gsub!( '&', '&' ) str.gsub!( '"', '"' ) if mode != :NoQuotes str.gsub!( "'", ''' ) if mode == :Quotes str.gsub!( '<', '<') str.gsub!( '>', '>') + end + str end # Search and replace for Textile glyphs (quotes, dashes, other symbols) def pgl( text ) - GLYPHS.each do |re, resub, tog| - next if tog and method( tog ).call - text.gsub! re, resub + #GLYPHS.each do |re, resub, tog| + # next if tog and method( tog ).call + # text.gsub! re, resub + #end + text.gsub!(/\b([A-Z][A-Z0-9]{2,})\b(?:[(]([^)]*)[)])/) do |m| + "#{$1}" end end @@ -464,8 +470,7 @@ class RedCloth3 < String style << "vertical-align:#{ v_align( $& ) };" if text =~ A_VLGN end - style << "#{ $1 };" if not filter_styles and - text.sub!( /\{([^}]*)\}/, '' ) + style << "#{ htmlesc $1 };" if text.sub!( /\{([^}]*)\}/, '' ) && !filter_styles lang = $1 if text.sub!( /\[([^)]+?)\]/, '' ) @@ -684,7 +689,7 @@ class RedCloth3 < String alias textile_h6 textile_p def textile_fn_( tag, num, atts, cite, content ) - atts << " id=\"fn#{ num }\"" + atts << " id=\"fn#{ num }\" class=\"footnote\"" content = "#{ num } #{ content }" atts = shelve( atts ) if atts "\t#{ content }

    " @@ -786,7 +791,10 @@ class RedCloth3 < String \s? (?:\(([^)]+?)\)(?="))? # $title ": - ([\w\/]\S+?) # $url + ( # $url + (\/|[a-zA-Z]+:\/\/|www\.) # $proto + [\w\/]\S+? + ) (\/)? # $slash ([^\w\=\/;\(\)]*?) # $post (?=<|\s|$) @@ -794,7 +802,7 @@ class RedCloth3 < String #" def inline_textile_link( text ) text.gsub!( LINK_RE ) do |m| - pre,atts,text,title,url,slash,post = $~[1..7] + pre,atts,text,title,url,proto,slash,post = $~[1..8] url, url_title = check_refs( url ) title ||= url_title @@ -807,7 +815,7 @@ class RedCloth3 < String end atts = pba( atts ) atts = " href=\"#{ url }#{ slash }\"#{ atts }" - atts << " title=\"#{ title }\"" if title + atts << " title=\"#{ htmlesc title }\"" if title atts = shelve( atts ) if atts external = (url =~ /^https?:\/\//) ? ' class="external"' : '' @@ -914,6 +922,7 @@ class RedCloth3 < String def inline_textile_image( text ) text.gsub!( IMAGE_RE ) do |m| stln,algn,atts,url,title,href,href_a1,href_a2 = $~[1..8] + htmlesc title atts = pba( atts ) atts = " src=\"#{ url }\"#{ atts }" atts << " title=\"#{ title }\"" if title @@ -1045,17 +1054,21 @@ class RedCloth3 < String codepre += 1 used_offtags[offtag] = true if codepre - used_offtags.length > 0 - htmlesc( line, :NoQuotes ) unless used_offtags['notextile'] + htmlesc( line, :NoQuotes ) @pre_list.last << line line = "" else - htmlesc( aftertag, :NoQuotes ) if aftertag and not used_offtags['notextile'] + htmlesc( aftertag, :NoQuotes ) if aftertag line = "" - @pre_list << "#{ $3 }#{ aftertag }" + $3.match(/<#{ OFFTAGS }([^>]*)>/) + tag = $1 + $2.to_s.match(/(class\=\S+)/i) + tag << " #{$1}" if $1 + @pre_list << "<#{ tag }>#{ aftertag }" end elsif $1 and codepre > 0 if codepre - used_offtags.length > 0 - htmlesc( line, :NoQuotes ) unless used_offtags['notextile'] + htmlesc( line, :NoQuotes ) @pre_list.last << line line = "" end diff --git a/lib/redmine.rb b/lib/redmine.rb index 5529e0bf5..c8d64b8c3 100644 --- a/lib/redmine.rb +++ b/lib/redmine.rb @@ -6,6 +6,7 @@ require 'redmine/core_ext' require 'redmine/themes' require 'redmine/hook' require 'redmine/plugin' +require 'redmine/wiki_formatting' begin require_library_or_gem 'RMagick' unless Object.const_defined?(:Magick) @@ -34,7 +35,7 @@ Redmine::AccessControl.map do |map| :queries => :index, :reports => :issue_report}, :public => true map.permission :add_issues, {:issues => :new} - map.permission :edit_issues, {:issues => [:edit, :reply, :bulk_edit, :destroy_attachment]} + map.permission :edit_issues, {:issues => [:edit, :reply, :bulk_edit]} map.permission :manage_issue_relations, {:issue_relations => [:new, :destroy]} map.permission :add_issue_notes, {:issues => [:edit, :reply]} map.permission :edit_issue_notes, {:journals => :edit}, :require => :loggedin @@ -66,12 +67,12 @@ Redmine::AccessControl.map do |map| end map.project_module :documents do |map| - map.permission :manage_documents, {:documents => [:new, :edit, :destroy, :add_attachment, :destroy_attachment]}, :require => :loggedin + map.permission :manage_documents, {:documents => [:new, :edit, :destroy, :add_attachment]}, :require => :loggedin map.permission :view_documents, :documents => [:index, :show, :download] end map.project_module :files do |map| - map.permission :manage_files, {:projects => :add_file, :versions => :destroy_file}, :require => :loggedin + map.permission :manage_files, {:projects => :add_file}, :require => :loggedin map.permission :view_files, :projects => :list_files, :versions => :download end @@ -81,12 +82,13 @@ Redmine::AccessControl.map do |map| map.permission :delete_wiki_pages, {:wiki => :destroy}, :require => :member map.permission :view_wiki_pages, :wiki => [:index, :special] map.permission :view_wiki_edits, :wiki => [:history, :diff, :annotate] - map.permission :edit_wiki_pages, :wiki => [:edit, :preview, :add_attachment, :destroy_attachment] + map.permission :edit_wiki_pages, :wiki => [:edit, :preview, :add_attachment] + map.permission :delete_wiki_pages_attachments, {} map.permission :protect_wiki_pages, {:wiki => :protect}, :require => :member end map.project_module :repository do |map| - map.permission :manage_repository, {:repositories => [:edit, :destroy]}, :require => :member + map.permission :manage_repository, {:repositories => [:edit, :committers, :destroy]}, :require => :member map.permission :browse_repository, :repositories => [:show, :browse, :entry, :annotate, :changes, :diff, :stats, :graph] map.permission :view_changesets, :repositories => [:show, :revisions, :revision] map.permission :commit_access, {} @@ -97,29 +99,35 @@ Redmine::AccessControl.map do |map| map.permission :view_messages, {:boards => [:index, :show], :messages => [:show]}, :public => true map.permission :add_messages, {:messages => [:new, :reply, :quote]} map.permission :edit_messages, {:messages => :edit}, :require => :member + map.permission :edit_own_messages, {:messages => :edit}, :require => :loggedin map.permission :delete_messages, {:messages => :destroy}, :require => :member + map.permission :delete_own_messages, {:messages => :destroy}, :require => :loggedin end end Redmine::MenuManager.map :top_menu do |menu| - 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? }, :last => true - menu.push :help, Redmine::Info.help_url, :html => { :class => 'help' }, :last => true + menu.push :home, :home_path + menu.push :my_page, { :controller => 'my', :action => 'page' }, :if => Proc.new { User.current.logged? } + menu.push :projects, { :controller => 'projects', :action => 'index' }, :caption => :label_project_plural + menu.push :administration, { :controller => 'admin', :action => 'index' }, :if => Proc.new { User.current.admin? }, :last => true + menu.push :help, Redmine::Info.help_url, :last => true end Redmine::MenuManager.map :account_menu do |menu| - 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_path, :html => { :class => 'logout' }, :if => Proc.new { User.current.logged? } + menu.push :login, :signin_path, :if => Proc.new { !User.current.logged? } + menu.push :register, { :controller => 'account', :action => 'register' }, :if => Proc.new { !User.current.logged? && Setting.self_registration? } + menu.push :my_account, { :controller => 'my', :action => 'account' }, :if => Proc.new { User.current.logged? } + menu.push :logout, :signout_path, :if => Proc.new { User.current.logged? } end Redmine::MenuManager.map :application_menu do |menu| # Empty end +Redmine::MenuManager.map :admin_menu do |menu| + # Empty +end + Redmine::MenuManager.map :project_menu do |menu| menu.push :overview, { :controller => 'projects', :action => 'show' } menu.push :activity, { :controller => 'projects', :action => 'activity' } @@ -149,3 +157,7 @@ Redmine::Activity.map do |activity| activity.register :wiki_edits, :class_name => 'WikiContent::Version', :default => false activity.register :messages, :default => false end + +Redmine::WikiFormatting.map do |format| + format.register :textile, Redmine::WikiFormatting::Textile::Formatter, Redmine::WikiFormatting::Textile::Helper +end diff --git a/lib/redmine/access_control.rb b/lib/redmine/access_control.rb index f5b25f277..25cf63d61 100644 --- a/lib/redmine/access_control.rb +++ b/lib/redmine/access_control.rb @@ -30,8 +30,15 @@ module Redmine @permissions end + # Returns the permission of given name or nil if it wasn't found + # Argument should be a symbol + def permission(name) + permissions.detect {|p| p.name == name} + end + + # Returns the actions that are allowed by the permission of given name def allowed_actions(permission_name) - perm = @permissions.detect {|p| p.name == permission_name} + perm = permission(permission_name) perm ? perm.actions : [] end @@ -94,6 +101,7 @@ module Redmine @actions << "#{controller}/#{actions}" end end + @actions.flatten! end def public? diff --git a/lib/redmine/activity/fetcher.rb b/lib/redmine/activity/fetcher.rb index adaead564..1d0bd8a16 100644 --- a/lib/redmine/activity/fetcher.rb +++ b/lib/redmine/activity/fetcher.rb @@ -25,7 +25,7 @@ module Redmine @@constantized_providers = Hash.new {|h,k| h[k] = Redmine::Activity.providers[k].collect {|t| t.constantize } } def initialize(user, options={}) - options.assert_valid_keys(:project, :with_subprojects) + options.assert_valid_keys(:project, :with_subprojects, :author) @user = user @project = options[:project] @options = options @@ -48,8 +48,16 @@ module Redmine end # Sets the scope + # Argument can be :all, :default or an array of event types def scope=(s) - @scope = s & event_types + case s + when :all + @scope = event_types + when :default + default_scope! + else + @scope = s & event_types + end end # Resets the scope to the default scope @@ -58,14 +66,20 @@ module Redmine end # Returns an array of events for the given date range - def events(from, to) + def events(from = nil, to = nil, options={}) e = [] + @options[:limit] = options[:limit] @scope.each do |event_type| constantized_providers(event_type).each do |provider| e += provider.find_events(event_type, @user, from, to, @options) end end + + if options[:limit] + e.sort! {|a,b| b.event_date <=> a.event_date} + e = e.slice(0, options[:limit]) + end e end diff --git a/lib/redmine/core_ext/string/conversions.rb b/lib/redmine/core_ext/string/conversions.rb index 41149f5ea..68fbcde75 100644 --- a/lib/redmine/core_ext/string/conversions.rb +++ b/lib/redmine/core_ext/string/conversions.rb @@ -24,7 +24,9 @@ module Redmine #:nodoc: def to_hours s = self.dup s.strip! - unless s =~ %r{^[\d\.,]+$} + if s =~ %r{^(\d+([.,]\d+)?)h?$} + s = $1 + else # 2:30 => 2.5 s.gsub!(%r{^(\d+):(\d+)$}) { $1.to_i + $2.to_i / 60.0 } # 2h30, 2h, 30m => 2.5, 2, 0.5 diff --git a/lib/redmine/default_data/loader.rb b/lib/redmine/default_data/loader.rb index 1c3b1f939..b7cab56ca 100644 --- a/lib/redmine/default_data/loader.rb +++ b/lib/redmine/default_data/loader.rb @@ -65,6 +65,7 @@ module Redmine :edit_wiki_pages, :delete_wiki_pages, :add_messages, + :edit_own_messages, :view_files, :manage_files, :browse_repository, @@ -85,6 +86,7 @@ module Redmine :view_wiki_pages, :view_wiki_edits, :add_messages, + :edit_own_messages, :view_files, :browse_repository, :view_changesets] diff --git a/lib/redmine/export/pdf.rb b/lib/redmine/export/pdf.rb new file mode 100644 index 000000000..5918b6d37 --- /dev/null +++ b/lib/redmine/export/pdf.rb @@ -0,0 +1,462 @@ +# Redmine - project management software +# Copyright (C) 2006-2009 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +require 'iconv' +require 'rfpdf/fpdf' +require 'rfpdf/chinese' + +module Redmine + module Export + module PDF + include ActionView::Helpers::NumberHelper + + class IFPDF < FPDF + include GLoc + attr_accessor :footer_date + + def initialize(lang) + super() + set_language_if_valid lang + case current_language.to_s + when 'ja' + extend(PDF_Japanese) + AddSJISFont() + @font_for_content = 'SJIS' + @font_for_footer = 'SJIS' + when 'zh' + extend(PDF_Chinese) + AddGBFont() + @font_for_content = 'GB' + @font_for_footer = 'GB' + when 'zh-tw' + extend(PDF_Chinese) + AddBig5Font() + @font_for_content = 'Big5' + @font_for_footer = 'Big5' + else + @font_for_content = 'Arial' + @font_for_footer = 'Helvetica' + end + SetCreator(Redmine::Info.app_name) + SetFont(@font_for_content) + end + + def SetFontStyle(style, size) + SetFont(@font_for_content, style, size) + end + + def SetTitle(txt) + txt = begin + utf16txt = Iconv.conv('UTF-16BE', 'UTF-8', txt) + hextxt = "" + rescue + txt + end || '' + super(txt) + end + + def textstring(s) + # Format a text string + if s =~ /^ [:user, :details], :order => "#{Journal.table_name}.created_on ASC") + pdf.SetFontStyle('B',8) + pdf.Cell(190,5, format_time(journal.created_on) + " - " + journal.user.name) + pdf.Ln + pdf.SetFontStyle('I',8) + for detail in journal.details + pdf.Cell(190,5, "- " + show_detail(detail, true)) + pdf.Ln + end + if journal.notes? + pdf.SetFontStyle('',8) + pdf.MultiCell(190,5, journal.notes) + end + pdf.Ln + end + + if issue.attachments.any? + pdf.SetFontStyle('B',9) + pdf.Cell(190,5, l(:label_attachment_plural), "B") + pdf.Ln + for attachment in issue.attachments + pdf.SetFontStyle('',8) + pdf.Cell(80,5, attachment.filename) + pdf.Cell(20,5, number_to_human_size(attachment.filesize),0,0,"R") + pdf.Cell(25,5, format_date(attachment.created_on),0,0,"R") + pdf.Cell(65,5, attachment.author.name,0,0,"R") + pdf.Ln + end + end + pdf.Output + end + + # Returns a PDF string of a gantt chart + def gantt_to_pdf(gantt, project) + pdf = IFPDF.new(current_language) + pdf.SetTitle("#{l(:label_gantt)} #{project}") + pdf.AliasNbPages + pdf.footer_date = format_date(Date.today) + pdf.AddPage("L") + pdf.SetFontStyle('B',12) + pdf.SetX(15) + pdf.Cell(70, 20, project.to_s) + pdf.Ln + pdf.SetFontStyle('B',9) + + subject_width = 70 + header_heigth = 5 + + headers_heigth = header_heigth + show_weeks = false + show_days = false + + if gantt.months < 7 + show_weeks = true + headers_heigth = 2*header_heigth + if gantt.months < 3 + show_days = true + headers_heigth = 3*header_heigth + end + end + + g_width = 210 + zoom = (g_width) / (gantt.date_to - gantt.date_from + 1) + g_height = 120 + t_height = g_height + headers_heigth + + y_start = pdf.GetY + + # Months headers + month_f = gantt.date_from + left = subject_width + height = header_heigth + gantt.months.times do + width = ((month_f >> 1) - month_f) * zoom + pdf.SetY(y_start) + pdf.SetX(left) + pdf.Cell(width, height, "#{month_f.year}-#{month_f.month}", "LTR", 0, "C") + left = left + width + month_f = month_f >> 1 + end + + # Weeks headers + if show_weeks + left = subject_width + height = header_heigth + if gantt.date_from.cwday == 1 + # gantt.date_from is monday + week_f = gantt.date_from + else + # find next monday after gantt.date_from + week_f = gantt.date_from + (7 - gantt.date_from.cwday + 1) + width = (7 - gantt.date_from.cwday + 1) * zoom-1 + pdf.SetY(y_start + header_heigth) + pdf.SetX(left) + pdf.Cell(width + 1, height, "", "LTR") + left = left + width+1 + end + while week_f <= gantt.date_to + width = (week_f + 6 <= gantt.date_to) ? 7 * zoom : (gantt.date_to - week_f + 1) * zoom + pdf.SetY(y_start + header_heigth) + pdf.SetX(left) + pdf.Cell(width, height, (width >= 5 ? week_f.cweek.to_s : ""), "LTR", 0, "C") + left = left + width + week_f = week_f+7 + end + end + + # Days headers + if show_days + left = subject_width + height = header_heigth + wday = gantt.date_from.cwday + pdf.SetFontStyle('B',7) + (gantt.date_to - gantt.date_from + 1).to_i.times do + width = zoom + pdf.SetY(y_start + 2 * header_heigth) + pdf.SetX(left) + pdf.Cell(width, height, day_name(wday).first, "LTR", 0, "C") + left = left + width + wday = wday + 1 + wday = 1 if wday > 7 + end + end + + pdf.SetY(y_start) + pdf.SetX(15) + pdf.Cell(subject_width+g_width-15, headers_heigth, "", 1) + + # Tasks + top = headers_heigth + y_start + pdf.SetFontStyle('B',7) + gantt.events.each do |i| + pdf.SetY(top) + pdf.SetX(15) + + if i.is_a? Issue + pdf.Cell(subject_width-15, 5, "#{i.tracker} #{i.id}: #{i.subject}".sub(/^(.{30}[^\s]*\s).*$/, '\1 (...)'), "LR") + else + pdf.Cell(subject_width-15, 5, "#{l(:label_version)}: #{i.name}", "LR") + end + + pdf.SetY(top) + pdf.SetX(subject_width) + pdf.Cell(g_width, 5, "", "LR") + + pdf.SetY(top+1.5) + + if i.is_a? Issue + i_start_date = (i.start_date >= gantt.date_from ? i.start_date : gantt.date_from ) + i_end_date = (i.due_before <= gantt.date_to ? i.due_before : gantt.date_to ) + + i_done_date = i.start_date + ((i.due_before - i.start_date+1)*i.done_ratio/100).floor + i_done_date = (i_done_date <= gantt.date_from ? gantt.date_from : i_done_date ) + i_done_date = (i_done_date >= gantt.date_to ? gantt.date_to : i_done_date ) + + i_late_date = [i_end_date, Date.today].min if i_start_date < Date.today + + i_left = ((i_start_date - gantt.date_from)*zoom) + i_width = ((i_end_date - i_start_date + 1)*zoom) + d_width = ((i_done_date - i_start_date)*zoom) + l_width = ((i_late_date - i_start_date+1)*zoom) if i_late_date + l_width ||= 0 + + pdf.SetX(subject_width + i_left) + pdf.SetFillColor(200,200,200) + pdf.Cell(i_width, 2, "", 0, 0, "", 1) + + if l_width > 0 + pdf.SetY(top+1.5) + pdf.SetX(subject_width + i_left) + pdf.SetFillColor(255,100,100) + pdf.Cell(l_width, 2, "", 0, 0, "", 1) + end + if d_width > 0 + pdf.SetY(top+1.5) + pdf.SetX(subject_width + i_left) + pdf.SetFillColor(100,100,255) + pdf.Cell(d_width, 2, "", 0, 0, "", 1) + end + + pdf.SetY(top+1.5) + pdf.SetX(subject_width + i_left + i_width) + pdf.Cell(30, 2, "#{i.status} #{i.done_ratio}%") + else + i_left = ((i.start_date - gantt.date_from)*zoom) + + pdf.SetX(subject_width + i_left) + pdf.SetFillColor(50,200,50) + pdf.Cell(2, 2, "", 0, 0, "", 1) + + pdf.SetY(top+1.5) + pdf.SetX(subject_width + i_left + 3) + pdf.Cell(30, 2, "#{i.name}") + end + + top = top + 5 + pdf.SetDrawColor(200, 200, 200) + pdf.Line(15, top, subject_width+g_width, top) + if pdf.GetY() > 180 + pdf.AddPage("L") + top = 20 + pdf.Line(15, top, subject_width+g_width, top) + end + pdf.SetDrawColor(0, 0, 0) + end + + pdf.Line(15, top, subject_width+g_width, top) + pdf.Output + end + end + end +end diff --git a/lib/redmine/hook.rb b/lib/redmine/hook.rb index 9bf92b3e7..bcd23b64f 100644 --- a/lib/redmine/hook.rb +++ b/lib/redmine/hook.rb @@ -17,6 +17,8 @@ module Redmine module Hook + include ActionController::UrlWriter + @@listener_classes = [] @@listeners = nil @@hook_listeners = {} @@ -55,17 +57,29 @@ module Redmine # Calls a hook. # Returns the listeners response. def call_hook(hook, context={}) - response = '' - hook_listeners(hook).each do |listener| - response << listener.send(hook, context).to_s + returning [] do |response| + hls = hook_listeners(hook) + if hls.any? + request = context[:request] + if request + default_url_options[:host] ||= request.env["SERVER_NAME"] + # Only set port if it's requested and isn't port 80. Otherwise a url + # like: +http://example.com:/url+ may be generated + if request.env["SERVER_PORT"] && request.env["SERVER_PORT"] != 80 + default_url_options[:port] ||= request.env["SERVER_PORT"] + end + default_url_options[:protocol] ||= request.protocol + end + hls.each {|listener| response << listener.send(hook, context)} + end end - response end end # Base class for hook listeners. class Listener include Singleton + include GLoc # Registers the listener def self.inherited(child) @@ -90,20 +104,52 @@ module Redmine include ActionView::Helpers::TextHelper include ActionController::UrlWriter include ApplicationHelper + + # Helper method to directly render a partial using the context: + # + # class MyHook < Redmine::Hook::ViewListener + # render_on :view_issues_show_details_bottom, :partial => "show_more_data" + # end + # + def self.render_on(hook, options={}) + define_method hook do |context| + context[:controller].send(:render_to_string, {:locals => context}.merge(options)) + end + end end - # Helper module included in ApplicationHelper so that hooks can be called - # in views like this: + # Helper module included in ApplicationHelper and ActionControllerso that + # hooks can be called in views like this: + # # <%= call_hook(:some_hook) %> # <%= call_hook(:another_hook, :foo => 'bar' %> # - # Current project is automatically added to the call context. + # Or in controllers like: + # call_hook(:some_hook) + # call_hook(:another_hook, :foo => 'bar' + # + # Hooks added to views will be concatenated into a string. Hooks added to + # controllers will return an array of results. + # + # Several objects are automatically added to the call context: + # + # * project => current project + # * request => Request instance + # * controller => current Controller instance + # module Helper def call_hook(hook, context={}) - Redmine::Hook.call_hook(hook, {:project => @project}.merge(context)) + if is_a?(ActionController::Base) + default_context = {:controller => self, :project => @project, :request => request} + Redmine::Hook.call_hook(hook, default_context.merge(context)) + else + default_context = {:controller => controller, :project => @project, :request => request} + Redmine::Hook.call_hook(hook, default_context.merge(context)).join(' ') + end end end end end ApplicationHelper.send(:include, Redmine::Hook::Helper) +ActionController::Base.send(:include, Redmine::Hook::Helper) diff --git a/lib/redmine/imap.rb b/lib/redmine/imap.rb index a6cd958cd..383d82f23 100644 --- a/lib/redmine/imap.rb +++ b/lib/redmine/imap.rb @@ -1,4 +1,4 @@ -# redMine - project management software +# Redmine - project management software # Copyright (C) 2006-2008 Jean-Philippe Lang # # This program is free software; you can redistribute it and/or @@ -33,9 +33,18 @@ module Redmine msg = imap.fetch(message_id,'RFC822')[0].attr['RFC822'] logger.debug "Receiving message #{message_id}" if logger && logger.debug? if MailHandler.receive(msg, options) + logger.debug "Message #{message_id} successfully received" if logger && logger.debug? + if imap_options[:move_on_success] + imap.copy(message_id, imap_options[:move_on_success]) + end imap.store(message_id, "+FLAGS", [:Seen, :Deleted]) else + logger.debug "Message #{message_id} can not be processed" if logger && logger.debug? imap.store(message_id, "+FLAGS", [:Seen]) + if imap_options[:move_on_failure] + imap.copy(message_id, imap_options[:move_on_failure]) + imap.store(message_id, "+FLAGS", [:Deleted]) + end end end imap.expunge diff --git a/lib/redmine/menu_manager.rb b/lib/redmine/menu_manager.rb index f6431928e..7a89a32b9 100644 --- a/lib/redmine/menu_manager.rb +++ b/lib/redmine/menu_manager.rb @@ -52,8 +52,19 @@ module Redmine # Returns the menu item name according to the current action def current_menu_item - menu_items[controller_name.to_sym][:actions][action_name.to_sym] || - menu_items[controller_name.to_sym][:default] + @current_menu_item ||= menu_items[controller_name.to_sym][:actions][action_name.to_sym] || + menu_items[controller_name.to_sym][:default] + end + + # Redirects user to the menu item of the given project + # Returns false if user is not authorized + def redirect_to_project_menu_item(project, name) + item = Redmine::MenuManager.items(:project_menu).detect {|i| i.name.to_s == name.to_s} + if item && User.current.allowed_to?(item.url, project) && (item.condition.nil? || item.condition.call(project)) + redirect_to({item.param => project}.merge(item.url)) + return true + end + false end end @@ -70,6 +81,15 @@ module Redmine def render_menu(menu, project=nil) links = [] + menu_items_for(menu, project) do |item, caption, url, selected| + links << content_tag('li', + link_to(h(caption), url, item.html_options(:selected => selected))) + end + links.empty? ? nil : content_tag('ul', links.join("\n")) + end + + def menu_items_for(menu, project=nil) + items = [] Redmine::MenuManager.allowed_items(menu, User.current, project).each do |item| unless item.condition && !item.condition.call(project) url = case item.url @@ -82,11 +102,14 @@ module Redmine end caption = item.caption(project) caption = l(caption) if caption.is_a?(Symbol) - links << content_tag('li', - link_to(h(caption), url, (current_menu_item == item.name ? item.html_options.merge(:class => 'selected') : item.html_options))) + if block_given? + yield item, caption, url, (current_menu_item == item.name) + else + items << [item, caption, url, (current_menu_item == item.name)] + end end end - links.empty? ? nil : content_tag('ul', links.join("\n")) + return block_given? ? nil : items end end @@ -94,7 +117,11 @@ module Redmine def map(menu_name) @items ||= {} mapper = Mapper.new(menu_name.to_sym, @items) - yield mapper + if block_given? + yield mapper + else + mapper + end end def items(menu_name) @@ -152,7 +179,7 @@ module Redmine class MenuItem include GLoc - attr_reader :name, :url, :param, :condition, :html_options + attr_reader :name, :url, :param, :condition def initialize(name, url, options) raise "Invalid option :if for menu item '#{name}'" if options[:if] && !options[:if].respond_to?(:call) @@ -163,6 +190,8 @@ module Redmine @param = options[:param] || :id @caption = options[:caption] @html_options = options[:html] || {} + # Adds a unique class to each menu item based on its name + @html_options[:class] = [@html_options[:class], @name.to_s.dasherize].compact.join(' ') end def caption(project=nil) @@ -175,6 +204,16 @@ module Redmine @caption_key ||= (@caption || (l_has_string?("label_#{@name}".to_sym) ? "label_#{@name}".to_sym : @name.to_s.humanize)) end end + + def html_options(options={}) + if options[:selected] + o = @html_options.dup + o[:class] += ' selected' + o + else + @html_options + end + end end end end diff --git a/lib/redmine/plugin.rb b/lib/redmine/plugin.rb index cf6c194a2..0fc6985f4 100644 --- a/lib/redmine/plugin.rb +++ b/lib/redmine/plugin.rb @@ -17,6 +17,9 @@ module Redmine #:nodoc: + class PluginNotFound < StandardError; end + class PluginRequirementError < StandardError; end + # Base class for Redmine plugins. # Plugins are registered using the register class method that acts as the public constructor. # @@ -55,13 +58,75 @@ module Redmine #:nodoc: end end end - def_field :name, :description, :author, :version, :settings - + def_field :name, :description, :url, :author, :author_url, :version, :settings + attr_reader :id + # Plugin constructor - def self.register(name, &block) - p = new + def self.register(id, &block) + p = new(id) p.instance_eval(&block) - Plugin.registered_plugins[name] = p + # Set a default name if it was not provided during registration + p.name(id.to_s.humanize) if p.name.nil? + registered_plugins[id] = p + end + + # Returns an array off all registered plugins + def self.all + registered_plugins.values.sort + end + + # Finds a plugin by its id + # Returns a PluginNotFound exception if the plugin doesn't exist + def self.find(id) + registered_plugins[id.to_sym] || raise(PluginNotFound) + end + + # Clears the registered plugins hash + # It doesn't unload installed plugins + def self.clear + @registered_plugins = {} + end + + def initialize(id) + @id = id.to_sym + end + + def <=>(plugin) + self.id.to_s <=> plugin.id.to_s + end + + # Sets a requirement on Redmine version + # Raises a PluginRequirementError exception if the requirement is not met + # + # Examples + # # Requires Redmine 0.7.3 or higher + # requires_redmine :version_or_higher => '0.7.3' + # requires_redmine '0.7.3' + # + # # Requires a specific Redmine version + # requires_redmine :version => '0.7.3' # 0.7.3 only + # requires_redmine :version => ['0.7.3', '0.8.0'] # 0.7.3 or 0.8.0 + def requires_redmine(arg) + arg = { :version_or_higher => arg } unless arg.is_a?(Hash) + arg.assert_valid_keys(:version, :version_or_higher) + + current = Redmine::VERSION.to_a + arg.each do |k, v| + v = [] << v unless v.is_a?(Array) + versions = v.collect {|s| s.split('.').collect(&:to_i)} + case k + when :version_or_higher + raise ArgumentError.new("wrong number of versions (#{versions.size} for 1)") unless versions.size == 1 + unless (current <=> versions.first) >= 0 + raise PluginRequirementError.new("#{id} plugin requires Redmine #{v} or higher but current is #{current.join('.')}") + end + when :version + unless versions.include?(current.slice(0,3)) + raise PluginRequirementError.new("#{id} plugin requires one the following Redmine versions: #{v.join(', ')} but current is #{current.join('.')}") + end + end + end + true end # Adds an item to the given +menu+. @@ -70,8 +135,14 @@ module Redmine #:nodoc: # # +name+ parameter can be: :top_menu, :account_menu, :application_menu or :project_menu # - def menu(name, item, url, options={}) - Redmine::MenuManager.map(name) {|menu| menu.push item, url, options} + def menu(menu, item, url, options={}) + Redmine::MenuManager.map(menu).push(item, url, options) + end + alias :add_menu_item :menu + + # Removes +item+ from the given +menu+. + def delete_menu_item(menu, item) + Redmine::MenuManager.map(menu).delete(item) end # Defines a permission called +name+ for the given +actions+. @@ -142,6 +213,16 @@ module Redmine #:nodoc: def activity_provider(*args) Redmine::Activity.register(*args) end + + # Registers a wiki formatter. + # + # Parameters: + # * +name+ - human-readable name + # * +formatter+ - formatter class, which should have an instance method +to_html+ + # * +helper+ - helper module, which will be included by wiki pages + def wiki_format_provider(name, formatter, helper) + Redmine::WikiFormatting.register(name, formatter, helper) + end # Returns +true+ if the plugin can be configured. def configurable? diff --git a/lib/redmine/scm/adapters/abstract_adapter.rb b/lib/redmine/scm/adapters/abstract_adapter.rb index 7e09d1611..cb8e7674e 100644 --- a/lib/redmine/scm/adapters/abstract_adapter.rb +++ b/lib/redmine/scm/adapters/abstract_adapter.rb @@ -192,6 +192,10 @@ module Redmine def self.shellout(cmd, &block) logger.debug "Shelling out: #{cmd}" if logger && logger.debug? + if Rails.env == 'development' + # Capture stderr when running in dev environment + cmd = "#{cmd} 2>>#{RAILS_ROOT}/log/scm.stderr.log" + end begin IO.popen(cmd, "r+") do |io| io.close_write diff --git a/lib/redmine/scm/adapters/bazaar_adapter.rb b/lib/redmine/scm/adapters/bazaar_adapter.rb index ff69e3e6b..39afb0565 100644 --- a/lib/redmine/scm/adapters/bazaar_adapter.rb +++ b/lib/redmine/scm/adapters/bazaar_adapter.rb @@ -50,7 +50,8 @@ module Redmine path ||= '' entries = Entries.new cmd = "#{BZR_BIN} ls -v --show-ids" - cmd << " -r#{identifier.to_i}" if identifier && identifier.to_i > 0 + identifier = -1 unless identifier && identifier.to_i > 0 + cmd << " -r#{identifier.to_i}" cmd << " #{target(path)}" shellout(cmd) do |io| prefix = "#{url}/#{path}".gsub('\\', '/') diff --git a/lib/redmine/scm/adapters/cvs_adapter.rb b/lib/redmine/scm/adapters/cvs_adapter.rb index 089a6b153..fc8d56f83 100644 --- a/lib/redmine/scm/adapters/cvs_adapter.rb +++ b/lib/redmine/scm/adapters/cvs_adapter.rb @@ -63,7 +63,7 @@ module Redmine logger.debug " entries '#{path}' with identifier '#{identifier}'" path_with_project="#{url}#{with_leading_slash(path)}" entries = Entries.new - cmd = "#{CVS_BIN} -d #{root_url} rls -ed" + cmd = "#{CVS_BIN} -d #{root_url} rls -e" cmd << " -D \"#{time_to_cvstime(identifier)}\"" if identifier cmd << " #{shell_quote path_with_project}" shellout(cmd) do |io| @@ -133,8 +133,7 @@ module Redmine if state=="entry_start" branch_map=Hash.new - # gsub(/^:.*@[^:]+:\d*/, '') is here to remove :pserver:anonymous@foo.bar: string if present in the url - if /^RCS file: #{Regexp.escape(root_url.gsub(/^:.*@[^:]+:\d*/, ''))}\/#{Regexp.escape(path_with_project)}(.+),v$/ =~ line + if /^RCS file: #{Regexp.escape(root_url_path)}\/#{Regexp.escape(path_with_project)}(.+),v$/ =~ line entry_path = normalize_cvs_path($1) entry_name = normalize_path(File.basename($1)) logger.debug("Path #{entry_path} <=> Name #{entry_name}") @@ -273,6 +272,13 @@ module Redmine end private + + # Returns the root url without the connexion string + # :pserver:anonymous@foo.bar:/path => /path + # :ext:cvsservername:/path => /path + def root_url_path + root_url.to_s.gsub(/^:.+:\d*/, '') + end # convert a date/time into the CVS-format def time_to_cvstime(time) diff --git a/lib/redmine/scm/adapters/darcs_adapter.rb b/lib/redmine/scm/adapters/darcs_adapter.rb index 4a5183f79..1cf792fb8 100644 --- a/lib/redmine/scm/adapters/darcs_adapter.rb +++ b/lib/redmine/scm/adapters/darcs_adapter.rb @@ -67,8 +67,8 @@ module Redmine path = '.' if path.blank? entries = Entries.new cmd = "#{DARCS_BIN} annotate --repodir #{@url} --xml-output" - cmd << " --match \"hash #{identifier}\"" if identifier - cmd << " #{path}" + cmd << " --match #{shell_quote("hash #{identifier}")}" if identifier + cmd << " #{shell_quote path}" shellout(cmd) do |io| begin doc = REXML::Document.new(io) @@ -84,14 +84,14 @@ module Redmine end end return nil if $? && $?.exitstatus != 0 - entries.sort_by_name + entries.compact.sort_by_name end def revisions(path=nil, identifier_from=nil, identifier_to=nil, options={}) path = '.' if path.blank? revisions = Revisions.new cmd = "#{DARCS_BIN} changes --repodir #{@url} --xml-output" - cmd << " --from-match \"hash #{identifier_from}\"" if identifier_from + cmd << " --from-match #{shell_quote("hash #{identifier_from}")}" if identifier_from cmd << " --last #{options[:limit].to_i}" if options[:limit] shellout(cmd) do |io| begin @@ -118,12 +118,12 @@ module Redmine path = '*' if path.blank? cmd = "#{DARCS_BIN} diff --repodir #{@url}" if identifier_to.nil? - cmd << " --match \"hash #{identifier_from}\"" + cmd << " --match #{shell_quote("hash #{identifier_from}")}" else - cmd << " --to-match \"hash #{identifier_from}\"" - cmd << " --from-match \"hash #{identifier_to}\"" + cmd << " --to-match #{shell_quote("hash #{identifier_from}")}" + cmd << " --from-match #{shell_quote("hash #{identifier_to}")}" end - cmd << " -u #{path}" + cmd << " -u #{shell_quote path}" diff = [] shellout(cmd) do |io| io.each_line do |line| @@ -136,7 +136,7 @@ module Redmine def cat(path, identifier=nil) cmd = "#{DARCS_BIN} show content --repodir #{@url}" - cmd << " --match \"hash #{identifier}\"" if identifier + cmd << " --match #{shell_quote("hash #{identifier}")}" if identifier cmd << " #{shell_quote path}" cat = nil shellout(cmd) do |io| @@ -148,15 +148,22 @@ module Redmine end private - + + # Returns an Entry from the given XML element + # or nil if the entry was deleted def entry_from_xml(element, path_prefix) + modified_element = element.elements['modified'] + if modified_element.elements['modified_how'].text.match(/removed/) + return nil + end + Entry.new({:name => element.attributes['name'], :path => path_prefix + element.attributes['name'], :kind => element.name == 'file' ? 'file' : 'dir', :size => nil, :lastrev => Revision.new({ :identifier => nil, - :scmid => element.elements['modified'].elements['patch'].attributes['hash'] + :scmid => modified_element.elements['patch'].attributes['hash'] }) }) end @@ -164,7 +171,7 @@ module Redmine # Retrieve changed paths for a single patch def get_paths_for_patch(hash) cmd = "#{DARCS_BIN} annotate --repodir #{@url} --summary --xml-output" - cmd << " --match \"hash #{hash}\" " + cmd << " --match #{shell_quote("hash #{hash}")} " paths = [] shellout(cmd) do |io| begin diff --git a/lib/redmine/scm/adapters/git_adapter.rb b/lib/redmine/scm/adapters/git_adapter.rb index c1f3e335b..85418133f 100644 --- a/lib/redmine/scm/adapters/git_adapter.rb +++ b/lib/redmine/scm/adapters/git_adapter.rb @@ -34,10 +34,10 @@ module Redmine def get_rev (rev,path) if rev != 'latest' && !rev.nil? - cmd="#{GIT_BIN} --git-dir #{target('')} show #{shell_quote rev} -- #{shell_quote path}" + cmd="#{GIT_BIN} --git-dir #{target('')} show --date=iso --pretty=fuller #{shell_quote rev} -- #{shell_quote path}" else - branch = shellout("#{GIT_BIN} --git-dir #{target('')} branch") { |io| io.grep(/\*/)[0].strip.match(/\* (.*)/)[1] } - cmd="#{GIT_BIN} --git-dir #{target('')} log -1 #{branch} -- #{shell_quote path}" + @branch ||= shellout("#{GIT_BIN} --git-dir #{target('')} branch") { |io| io.grep(/\*/)[0].strip.match(/\* (.*)/)[1] } + cmd="#{GIT_BIN} --git-dir #{target('')} log --date=iso --pretty=fuller -1 #{@branch} -- #{shell_quote path}" end rev=[] i=0 @@ -68,7 +68,7 @@ module Redmine value = $2 if key == "Author" changeset[:author] = value - elsif key == "Date" + elsif key == "CommitDate" changeset[:date] = value end elsif (parsing_descr == 0) && line.chomp.to_s == "" @@ -101,7 +101,6 @@ module Redmine return rev end - def info revs = revisions(url,nil,nil,{:limit => 1}) if revs && revs.any? @@ -143,7 +142,7 @@ module Redmine def revisions(path, identifier_from, identifier_to, options={}) revisions = Revisions.new - cmd = "#{GIT_BIN} --git-dir #{target('')} log --raw " + cmd = "#{GIT_BIN} --git-dir #{target('')} log --raw --date=iso --pretty=fuller" cmd << " --reverse" if options[:reverse] cmd << " -n #{options[:limit].to_i} " if (!options.nil?) && options[:limit] cmd << " #{shell_quote(identifier_from + '..')} " if identifier_from @@ -182,7 +181,7 @@ module Redmine value = $2 if key == "Author" changeset[:author] = value - elsif key == "Date" + elsif key == "CommitDate" changeset[:date] = value end elsif (parsing_descr == 0) && line.chomp.to_s == "" diff --git a/lib/redmine/scm/adapters/subversion_adapter.rb b/lib/redmine/scm/adapters/subversion_adapter.rb index bd04f582b..e59022582 100644 --- a/lib/redmine/scm/adapters/subversion_adapter.rb +++ b/lib/redmine/scm/adapters/subversion_adapter.rb @@ -17,6 +17,7 @@ require 'redmine/scm/adapters/abstract_adapter' require 'rexml/document' +require 'uri' module Redmine module Scm @@ -81,24 +82,27 @@ module Redmine path ||= '' identifier = (identifier and identifier.to_i > 0) ? identifier.to_i : "HEAD" entries = Entries.new - cmd = "#{SVN_BIN} list --xml #{target(path)}@#{identifier}" + cmd = "#{SVN_BIN} list --xml #{target(URI.escape(path))}@#{identifier}" cmd << credentials_string shellout(cmd) do |io| output = io.read begin doc = REXML::Document.new(output) doc.elements.each("lists/list/entry") do |entry| + commit = entry.elements['commit'] + commit_date = commit.elements['date'] # Skip directory if there is no commit date (usually that # means that we don't have read access to it) - next if entry.attributes['kind'] == 'dir' && entry.elements['commit'].elements['date'].nil? - entries << Entry.new({:name => entry.elements['name'].text, - :path => ((path.empty? ? "" : "#{path}/") + entry.elements['name'].text), + next if entry.attributes['kind'] == 'dir' && commit_date.nil? + name = entry.elements['name'].text + entries << Entry.new({:name => URI.unescape(name), + :path => ((path.empty? ? "" : "#{path}/") + name), :kind => entry.attributes['kind'], - :size => (entry.elements['size'] and entry.elements['size'].text).to_i, + :size => ((s = entry.elements['size']) ? s.text.to_i : nil), :lastrev => Revision.new({ - :identifier => entry.elements['commit'].attributes['revision'], - :time => Time.parse(entry.elements['commit'].elements['date'].text).localtime, - :author => (entry.elements['commit'].elements['author'] ? entry.elements['commit'].elements['author'].text : "") + :identifier => commit.attributes['revision'], + :time => Time.parse(commit_date.text).localtime, + :author => ((a = commit.elements['author']) ? a.text : nil) }) }) end @@ -117,7 +121,7 @@ module Redmine return nil unless self.class.client_version_above?([1, 5, 0]) identifier = (identifier and identifier.to_i > 0) ? identifier.to_i : "HEAD" - cmd = "#{SVN_BIN} proplist --verbose --xml #{target(path)}@#{identifier}" + cmd = "#{SVN_BIN} proplist --verbose --xml #{target(URI.escape(path))}@#{identifier}" cmd << credentials_string properties = {} shellout(cmd) do |io| @@ -142,7 +146,8 @@ module Redmine cmd = "#{SVN_BIN} log --xml -r #{identifier_from}:#{identifier_to}" cmd << credentials_string cmd << " --verbose " if options[:with_paths] - cmd << ' ' + target(path) + cmd << " --limit #{options[:limit].to_i}" if options[:limit] + cmd << ' ' + target(URI.escape(path)) shellout(cmd) do |io| begin doc = REXML::Document.new(io) @@ -179,7 +184,7 @@ module Redmine cmd = "#{SVN_BIN} diff -r " cmd << "#{identifier_to}:" cmd << "#{identifier_from}" - cmd << " #{target(path)}@#{identifier_from}" + cmd << " #{target(URI.escape(path))}@#{identifier_from}" cmd << credentials_string diff = [] shellout(cmd) do |io| @@ -193,7 +198,7 @@ module Redmine def cat(path, identifier=nil) identifier = (identifier and identifier.to_i > 0) ? identifier.to_i : "HEAD" - cmd = "#{SVN_BIN} cat #{target(path)}@#{identifier}" + cmd = "#{SVN_BIN} cat #{target(URI.escape(path))}@#{identifier}" cmd << credentials_string cat = nil shellout(cmd) do |io| @@ -206,7 +211,7 @@ module Redmine def annotate(path, identifier=nil) identifier = (identifier and identifier.to_i > 0) ? identifier.to_i : "HEAD" - cmd = "#{SVN_BIN} blame #{target(path)}@#{identifier}" + cmd = "#{SVN_BIN} blame #{target(URI.escape(path))}@#{identifier}" cmd << credentials_string blame = Annotate.new shellout(cmd) do |io| diff --git a/lib/redmine/unified_diff.rb b/lib/redmine/unified_diff.rb index 36a36cba5..bf4dec335 100644 --- a/lib/redmine/unified_diff.rb +++ b/lib/redmine/unified_diff.rb @@ -18,18 +18,30 @@ module Redmine # Class used to parse unified diffs class UnifiedDiff < Array - def initialize(diff, type="inline") - diff_table = DiffTable.new type + def initialize(diff, options={}) + options.assert_valid_keys(:type, :max_lines) + diff_type = options[:type] || 'inline' + + lines = 0 + @truncated = false + diff_table = DiffTable.new(diff_type) diff.each do |line| if line =~ /^(---|\+\+\+) (.*)$/ self << diff_table if diff_table.length > 1 - diff_table = DiffTable.new type + diff_table = DiffTable.new(diff_type) + end + diff_table.add_line line + lines += 1 + if options[:max_lines] && lines > options[:max_lines] + @truncated = true + break end - a = diff_table.add_line line end self << diff_table unless diff_table.empty? self end + + def truncated?; @truncated; end end # Class that represents a file diff diff --git a/lib/redmine/utils.rb b/lib/redmine/utils.rb new file mode 100644 index 000000000..02f9d3e63 --- /dev/null +++ b/lib/redmine/utils.rb @@ -0,0 +1,38 @@ +# Redmine - project management software +# Copyright (C) 2006-2009 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +module Redmine + module Utils + class << self + # Returns the relative root url of the application + def relative_url_root + ActionController::Base.respond_to?('relative_url_root') ? + ActionController::Base.relative_url_root.to_s : + ActionController::AbstractRequest.relative_url_root.to_s + end + + # Sets the relative root url of the application + def relative_url_root=(arg) + if ActionController::Base.respond_to?('relative_url_root=') + ActionController::Base.relative_url_root=arg + else + ActionController::AbstractRequest.relative_url_root=arg + end + end + end + end +end diff --git a/lib/redmine/version.rb b/lib/redmine/version.rb index 81006fe2d..f51d1741e 100644 --- a/lib/redmine/version.rb +++ b/lib/redmine/version.rb @@ -3,8 +3,14 @@ require 'rexml/document' module Redmine module VERSION #:nodoc: MAJOR = 0 - MINOR = 7 - TINY = 'devel' + MINOR = 8 + TINY = 0 + + # Branch values: + # * official release: nil + # * stable branch: stable + # * trunk: devel + BRANCH = 'devel' def self.revision revision = nil @@ -28,8 +34,10 @@ module Redmine end REVISION = self.revision - STRING = [MAJOR, MINOR, TINY, REVISION].compact.join('.') + ARRAY = [MAJOR, MINOR, TINY, BRANCH, REVISION].compact + STRING = ARRAY.join('.') + def self.to_a; ARRAY end def self.to_s; STRING end end end diff --git a/lib/redmine/views/other_formats_builder.rb b/lib/redmine/views/other_formats_builder.rb new file mode 100644 index 000000000..c3c89b24d --- /dev/null +++ b/lib/redmine/views/other_formats_builder.rb @@ -0,0 +1,33 @@ +# Redmine - project management software +# Copyright (C) 2006-2009 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +module Redmine + module Views + class OtherFormatsBuilder + def initialize(view) + @view = view + end + + def link_to(name, options={}) + url = { :format => name.to_s.downcase }.merge(options.delete(:url) || {}) + caption = options.delete(:caption) || name + html_options = { :class => name.to_s.downcase, :rel => 'nofollow' }.merge(options) + @view.content_tag('span', @view.link_to(caption, url, html_options)) + end + end + end +end diff --git a/lib/redmine/wiki_formatting.rb b/lib/redmine/wiki_formatting.rb index 7dffff492..1525dbc19 100644 --- a/lib/redmine/wiki_formatting.rb +++ b/lib/redmine/wiki_formatting.rb @@ -1,5 +1,5 @@ -# redMine - project management software -# Copyright (C) 2006-2007 Jean-Philippe Lang +# Redmine - project management software +# 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 @@ -15,176 +15,65 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -require 'redcloth3' -require 'coderay' - module Redmine module WikiFormatting - - private - - class TextileFormatter < RedCloth3 - - # auto_link rule after textile rules so that it doesn't break !image_url! tags - RULES = [:textile, :block_markdown_rule, :inline_auto_link, :inline_auto_mailto, :inline_toc, :inline_macros] + @@formatters = {} + + class << self + def map + yield self + end - def initialize(*args) - super - self.hard_breaks=true - self.no_span_caps=true + def register(name, formatter, helper) + raise ArgumentError, "format name '#{name}' is already taken" if @@formatters[name] + @@formatters[name.to_sym] = {:formatter => formatter, :helper => helper} end - def to_html(*rules, &block) - @toc = [] - @macros_runner = block - super(*RULES).to_s + def formatter_for(name) + entry = @@formatters[name.to_sym] + (entry && entry[:formatter]) || Redmine::WikiFormatting::NullFormatter::Formatter end - - private - - # Patch for RedCloth. Fixed in RedCloth r128 but _why hasn't released it yet. - # http://code.whytheluckystiff.net/redcloth/changeset/128 - def hard_break( text ) - text.gsub!( /(.)\n(?!\n|\Z|>| *(>? *[#*=]+(\s|$)|[{|]))/, "\\1
    \n" ) if hard_breaks + + def helper_for(name) + entry = @@formatters[name.to_sym] + (entry && entry[:helper]) || Redmine::WikiFormatting::NullFormatter::Helper end - # Patch to add code highlighting support to RedCloth - def smooth_offtags( text ) - unless @pre_list.empty? - ## replace
     content
    -          text.gsub!(//) do
    -            content = @pre_list[$1.to_i]
    -            if content.match(/\s?(.+)/m)
    -              content = "" + 
    -                CodeRay.scan($2, $1.downcase).html(:escape => false, :line_numbers => :inline)
    -            end
    -            content
    -          end
    -        end
    +      def format_names
    +        @@formatters.keys.map
           end
           
    -      # Patch to add 'table of content' support to RedCloth
    -      def textile_p_withtoc(tag, atts, cite, content)
    -        # removes wiki links from the item
    -        toc_item = content.gsub(/(\[\[|\]\])/, '')
    -        # removes styles
    -        # eg. %{color:red}Triggers% => Triggers
    -        toc_item.gsub! %r[%\{[^\}]*\}([^%]+)%], '\\1'
    +      def to_html(format, text, options = {}, &block)
    +        formatter_for(format).new(text).to_html(&block)
    +      end
    +    end
    +    
    +    # Default formatter module
    +    module NullFormatter
    +      class Formatter
    +        include ActionView::Helpers::TagHelper
    +        include ActionView::Helpers::TextHelper
             
    -        # replaces non word caracters by dashes
    -        anchor = toc_item.gsub(%r{[^\w\s\-]}, '').gsub(%r{\s+(\-+\s*)?}, '-')
    -
    -        unless anchor.blank?
    -          if tag =~ /^h(\d)$/
    -            @toc << [$1.to_i, anchor, toc_item]
    -          end
    -          atts << " id=\"#{anchor}\""
    -          content = content + ""
    +        def initialize(text)
    +          @text = text
             end
    -        textile_p(tag, atts, cite, content)
    -      end
    -
    -      alias :textile_h1 :textile_p_withtoc
    -      alias :textile_h2 :textile_p_withtoc
    -      alias :textile_h3 :textile_p_withtoc
    -      
    -      def inline_toc(text)
    -        text.gsub!(/

    \{\{([<>]?)toc\}\}<\/p>/i) do - div_class = 'toc' - div_class << ' right' if $1 == '>' - div_class << ' left' if $1 == '<' - out = "

      " - @toc.each do |heading| - level, anchor, toc_item = heading - out << "
    • #{toc_item}
    • \n" - end - out << '
    ' - out + + def to_html(*args) + simple_format(auto_link(CGI::escapeHTML(@text))) end end - MACROS_RE = / - (!)? # escaping - ( - \{\{ # opening tag - ([\w]+) # macro name - (\(([^\}]*)\))? # optional arguments - \}\} # closing tag - ) - /x unless const_defined?(:MACROS_RE) - - def inline_macros(text) - text.gsub!(MACROS_RE) do - esc, all, macro = $1, $2, $3.downcase - args = ($5 || '').split(',').each(&:strip) - if esc.nil? - begin - @macros_runner.call(macro, args) - rescue => e - "
    Error executing the #{macro} macro (#{e})
    " - end || all - else - all - end + module Helper + def wikitoolbar_for(field_id) end - end - AUTO_LINK_RE = %r{ - ( # leading text - <\w+.*?>| # leading HTML tag, or - [^=<>!:'"/]| # leading punctuation, or - ^ # beginning of line - ) - ( - (?:https?://)| # protocol spec, or - (?:ftp://)| - (?:www\.) # www.* - ) - ( - (\S+?) # url - (\/)? # slash - ) - ([^\w\=\/;\(\)]*?) # post - (?=<|\s|$) - }x unless const_defined?(:AUTO_LINK_RE) - - # Turns all urls into clickable links (code from Rails). - def inline_auto_link(text) - text.gsub!(AUTO_LINK_RE) do - all, leading, proto, url, post = $&, $1, $2, $3, $6 - if leading =~ /=]?/ - # don't replace URL's that are already linked - # and URL's prefixed with ! !> !< != (textile images) - all - else - # Idea below : an URL with unbalanced parethesis and - # ending by ')' is put into external parenthesis - if ( url[-1]==?) and ((url.count("(") - url.count(")")) < 0 ) ) - url=url[0..-2] # discard closing parenth from url - post = ")"+post # add closing parenth to post - end - %(#{leading}#{proto + url}#{post}) - end + def heads_for_wiki_formatter end - end - - # Turns all email addresses into clickable links (code from Rails). - def inline_auto_mailto(text) - text.gsub!(/([\w\.!#\$%\-+.]+@[A-Za-z0-9\-]+(\.[A-Za-z0-9\-]+)+)/) do - mail = $1 - if text.match(/]*>(.*)(#{Regexp.escape(mail)})(.*)<\/a>/) - mail - else - %{} - end + + def initial_page_content(page) + page.pretty_title.to_s end end end - - public - - def self.to_html(text, options = {}, &block) - TextileFormatter.new(text).to_html(&block) - end end end diff --git a/lib/redmine/wiki_formatting/macros.rb b/lib/redmine/wiki_formatting/macros.rb index adfc590e4..abc07b947 100644 --- a/lib/redmine/wiki_formatting/macros.rb +++ b/lib/redmine/wiki_formatting/macros.rb @@ -23,6 +23,15 @@ module Redmine method_name = "macro_#{name}" send(method_name, obj, args) if respond_to?(method_name) end + + def extract_macro_options(args, *keys) + options = {} + while args.last.to_s.strip =~ %r{^(.+)\=(.+)$} && keys.include?($1.downcase.to_sym) + options[$1.downcase.to_sym] = $2 + args.pop + end + return [args, options] + end end @@available_macros = {} @@ -77,24 +86,29 @@ module Redmine content_tag('dl', out) end - desc "Displays a list of child pages." + desc "Displays a list of child pages. With no argument, it displays the child pages of the current wiki page. Examples:\n\n" + + " !{{child_pages}} -- can be used from a wiki page only\n" + + " !{{child_pages(Foo)}} -- lists all children of page Foo\n" + + " !{{child_pages(Foo, parent=1)}} -- same as above with a link to page Foo" macro :child_pages do |obj, args| - raise 'This macro applies to wiki pages only.' unless obj.is_a?(WikiContent) - render_page_hierarchy(obj.page.descendants.group_by(&:parent_id), obj.page.id) + args, options = extract_macro_options(args, :parent) + page = nil + if args.size > 0 + page = Wiki.find_page(args.first.to_s, :project => @project) + elsif obj.is_a?(WikiContent) + page = obj.page + else + raise 'With no argument, this macro can be called from wiki pages only.' + end + raise 'Page not found' if page.nil? || !User.current.allowed_to?(:view_wiki_pages, page.wiki.project) + pages = ([page] + page.descendants).group_by(&:parent_id) + render_page_hierarchy(pages, options[:parent] ? page.parent_id : page.id) end desc "Include a wiki page. Example:\n\n !{{include(Foo)}}\n\nor to include a page of a specific project wiki:\n\n !{{include(projectname:Foo)}}" macro :include do |obj, args| - project = @project - title = args.first.to_s - if title =~ %r{^([^\:]+)\:(.*)$} - project_identifier, title = $1, $2 - project = Project.find_by_identifier(project_identifier) || Project.find_by_name(project_identifier) - end - raise 'Unknow project' unless project && User.current.allowed_to?(:view_wiki_pages, project) - raise 'No wiki for this project' unless !project.wiki.nil? - page = project.wiki.find_page(title) - raise "Page #{args.first} doesn't exist" unless page && page.content + page = Wiki.find_page(args.first.to_s, :project => @project) + raise 'Page not found' if page.nil? || !User.current.allowed_to?(:view_wiki_pages, page.wiki.project) @included_wiki_pages ||= [] raise 'Circular inclusion detected' if @included_wiki_pages.include?(page.title) @included_wiki_pages << page.title diff --git a/lib/redmine/wiki_formatting/textile/formatter.rb b/lib/redmine/wiki_formatting/textile/formatter.rb new file mode 100644 index 000000000..67e3579df --- /dev/null +++ b/lib/redmine/wiki_formatting/textile/formatter.rb @@ -0,0 +1,184 @@ +# Redmine - project management software +# 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 +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +require 'redcloth3' +require 'coderay' + +module Redmine + module WikiFormatting + module Textile + class Formatter < RedCloth3 + + # auto_link rule after textile rules so that it doesn't break !image_url! tags + RULES = [:textile, :block_markdown_rule, :inline_auto_link, :inline_auto_mailto, :inline_toc, :inline_macros] + + def initialize(*args) + super + self.hard_breaks=true + self.no_span_caps=true + self.filter_styles=true + end + + def to_html(*rules, &block) + @toc = [] + @macros_runner = block + super(*RULES).to_s + end + + private + + # Patch for RedCloth. Fixed in RedCloth r128 but _why hasn't released it yet. + # http://code.whytheluckystiff.net/redcloth/changeset/128 + def hard_break( text ) + text.gsub!( /(.)\n(?!\n|\Z|>| *(>? *[#*=]+(\s|$)|[{|]))/, "\\1
    \n" ) if hard_breaks + end + + # Patch to add code highlighting support to RedCloth + def smooth_offtags( text ) + unless @pre_list.empty? + ## replace
     content
    +            text.gsub!(//) do
    +              content = @pre_list[$1.to_i]
    +              if content.match(/\s?(.+)/m)
    +                content = "" + 
    +                  CodeRay.scan($2, $1.downcase).html(:escape => false, :line_numbers => :inline)
    +              end
    +              content
    +            end
    +          end
    +        end
    +        
    +        # Patch to add 'table of content' support to RedCloth
    +        def textile_p_withtoc(tag, atts, cite, content)
    +          # removes wiki links from the item
    +          toc_item = content.gsub(/(\[\[([^\]\|]*)(\|([^\]]*))?\]\])/) { $4 || $2 }
    +          # removes styles
    +          # eg. %{color:red}Triggers% => Triggers
    +          toc_item.gsub! %r[%\{[^\}]*\}([^%]+)%], '\\1'
    +          
    +          # replaces non word caracters by dashes
    +          anchor = toc_item.gsub(%r{[^\w\s\-]}, '').gsub(%r{\s+(\-+\s*)?}, '-')
    +  
    +          unless anchor.blank?
    +            if tag =~ /^h(\d)$/
    +              @toc << [$1.to_i, anchor, toc_item]
    +            end
    +            atts << " id=\"#{anchor}\""
    +            content = content + ""
    +          end
    +          textile_p(tag, atts, cite, content)
    +        end
    +  
    +        alias :textile_h1 :textile_p_withtoc
    +        alias :textile_h2 :textile_p_withtoc
    +        alias :textile_h3 :textile_p_withtoc
    +        
    +        def inline_toc(text)
    +          text.gsub!(/

    \{\{([<>]?)toc\}\}<\/p>/i) do + div_class = 'toc' + div_class << ' right' if $1 == '>' + div_class << ' left' if $1 == '<' + out = "

      " + @toc.each do |heading| + level, anchor, toc_item = heading + out << "
    • #{toc_item}
    • \n" + end + out << '
    ' + out + end + end + + MACROS_RE = / + (!)? # escaping + ( + \{\{ # opening tag + ([\w]+) # macro name + (\(([^\}]*)\))? # optional arguments + \}\} # closing tag + ) + /x unless const_defined?(:MACROS_RE) + + def inline_macros(text) + text.gsub!(MACROS_RE) do + esc, all, macro = $1, $2, $3.downcase + args = ($5 || '').split(',').each(&:strip) + if esc.nil? + begin + @macros_runner.call(macro, args) + rescue => e + "
    Error executing the #{macro} macro (#{e})
    " + end || all + else + all + end + end + end + + AUTO_LINK_RE = %r{ + ( # leading text + <\w+.*?>| # leading HTML tag, or + [^=<>!:'"/]| # leading punctuation, or + ^ # beginning of line + ) + ( + (?:https?://)| # protocol spec, or + (?:s?ftps?://)| + (?:www\.) # www.* + ) + ( + (\S+?) # url + (\/)? # slash + ) + ([^\w\=\/;\(\)]*?) # post + (?=<|\s|$) + }x unless const_defined?(:AUTO_LINK_RE) + + # Turns all urls into clickable links (code from Rails). + def inline_auto_link(text) + text.gsub!(AUTO_LINK_RE) do + all, leading, proto, url, post = $&, $1, $2, $3, $6 + if leading =~ /=]?/ + # don't replace URL's that are already linked + # and URL's prefixed with ! !> !< != (textile images) + all + else + # Idea below : an URL with unbalanced parethesis and + # ending by ')' is put into external parenthesis + if ( url[-1]==?) and ((url.count("(") - url.count(")")) < 0 ) ) + url=url[0..-2] # discard closing parenth from url + post = ")"+post # add closing parenth to post + end + %(#{leading}#{proto + url}#{post}) + end + end + end + + # Turns all email addresses into clickable links (code from Rails). + def inline_auto_mailto(text) + text.gsub!(/([\w\.!#\$%\-+.]+@[A-Za-z0-9\-]+(\.[A-Za-z0-9\-]+)+)/) do + mail = $1 + if text.match(/]*>(.*)(#{Regexp.escape(mail)})(.*)<\/a>/) + mail + else + %{} + end + end + end + end + end + end +end diff --git a/lib/redmine/wiki_formatting/textile/helper.rb b/lib/redmine/wiki_formatting/textile/helper.rb new file mode 100644 index 000000000..c4bde572b --- /dev/null +++ b/lib/redmine/wiki_formatting/textile/helper.rb @@ -0,0 +1,46 @@ +# Redmine - project management software +# 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 +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +module Redmine + module WikiFormatting + module Textile + module Helper + def wikitoolbar_for(field_id) + # Is there a simple way to link to a public resource? + url = "#{Redmine::Utils.relative_url_root}/help/wiki_syntax.html" + + help_link = l(:setting_text_formatting) + ': ' + + link_to(l(:label_help), url, + :onclick => "window.open(\"#{ url }\", \"\", \"resizable=yes, location=no, width=300, height=640, menubar=no, status=no, scrollbars=yes\"); return false;") + + javascript_include_tag('jstoolbar/jstoolbar') + + javascript_include_tag('jstoolbar/textile') + + javascript_include_tag("jstoolbar/lang/jstoolbar-#{current_language}") + + javascript_tag("var toolbar = new jsToolBar($('#{field_id}')); toolbar.setHelpLink('#{help_link}'); toolbar.draw();") + end + + def initial_page_content(page) + "h1. #{@page.pretty_title}" + end + + def heads_for_wiki_formatter + stylesheet_link_tag 'jstoolbar' + end + end + end + end +end diff --git a/lib/tabular_form_builder.rb b/lib/tabular_form_builder.rb index 88e35a6d2..3ca2d7aab 100644 --- a/lib/tabular_form_builder.rb +++ b/lib/tabular_form_builder.rb @@ -28,24 +28,24 @@ class TabularFormBuilder < ActionView::Helpers::FormBuilder (field_helpers - %w(radio_button hidden_field) + %w(date_select)).each do |selector| src = <<-END_SRC def #{selector}(field, options = {}) - return super if options.delete :no_label - label_text = l(options[:label]) if options[:label] - label_text ||= l(("field_"+field.to_s.gsub(/\_id$/, "")).to_sym) - label_text << @template.content_tag("span", " *", :class => "required") if options.delete(:required) - label = @template.content_tag("label", label_text, - :class => (@object && @object.errors[field] ? "error" : nil), - :for => (@object_name.to_s + "_" + field.to_s)) - label + super + label_for_field(field, options) + super end END_SRC class_eval src, __FILE__, __LINE__ end def select(field, choices, options = {}, html_options = {}) - label_text = l(("field_"+field.to_s.gsub(/\_id$/, "")).to_sym) + (options.delete(:required) ? @template.content_tag("span", " *", :class => "required"): "") - label = @template.content_tag("label", label_text, - :class => (@object && @object.errors[field] ? "error" : nil), - :for => (@object_name.to_s + "_" + field.to_s)) - label + super + label_for_field(field, options) + super + end + + # Returns a label tag for the given field + def label_for_field(field, options = {}) + return '' if options.delete(:no_label) + text = l(options[:label]) if options[:label] + text ||= l(("field_" + field.to_s.gsub(/\_id$/, "")).to_sym) + text << @template.content_tag("span", " *", :class => "required") if options.delete(:required) + @template.content_tag("label", text, + :class => (@object && @object.errors[field] ? "error" : nil), + :for => (@object_name.to_s + "_" + field.to_s)) end end diff --git a/lib/tasks/email.rake b/lib/tasks/email.rake index a37b3e197..0f74d6bd3 100644 --- a/lib/tasks/email.rake +++ b/lib/tasks/email.rake @@ -1,4 +1,4 @@ -# redMine - project management software +# Redmine - project management software # Copyright (C) 2006-2008 Jean-Philippe Lang # # This program is free software; you can redistribute it and/or @@ -23,6 +23,7 @@ Read an email from standard input. Issue attributes control options: project=PROJECT identifier of the target project + status=STATUS name of the target status tracker=TRACKER name of the target tracker category=CATEGORY name of the target category priority=PRIORITY name of the target priority @@ -44,7 +45,7 @@ END_DESC task :read => :environment do options = { :issue => {} } - %w(project tracker category priority).each { |a| options[:issue][a.to_sym] = ENV[a] if ENV[a] } + %w(project status tracker category priority).each { |a| options[:issue][a.to_sym] = ENV[a] if ENV[a] } options[:allow_override] = ENV['allow_override'] if ENV['allow_override'] MailHandler.receive(STDIN.read, options) @@ -63,12 +64,18 @@ Available IMAP options: Issue attributes control options: project=PROJECT identifier of the target project + status=STATUS name of the target status tracker=TRACKER name of the target tracker category=CATEGORY name of the target category priority=PRIORITY name of the target priority allow_override=ATTRS allow email content to override attributes specified by previous options ATTRS is a comma separated list of attributes + +Processed emails control options: + move_on_success=MAILBOX move emails that were successfully received + to MAILBOX instead of deleting them + move_on_failure=MAILBOX move emails that were ignored to MAILBOX Examples: # No project specified. Emails MUST contain the 'Project' keyword: @@ -93,10 +100,12 @@ END_DESC :ssl => ENV['ssl'], :username => ENV['username'], :password => ENV['password'], - :folder => ENV['folder']} + :folder => ENV['folder'], + :move_on_success => ENV['move_on_success'], + :move_on_failure => ENV['move_on_failure']} options = { :issue => {} } - %w(project tracker category priority).each { |a| options[:issue][a.to_sym] = ENV[a] if ENV[a] } + %w(project status tracker category priority).each { |a| options[:issue][a.to_sym] = ENV[a] if ENV[a] } options[:allow_override] = ENV['allow_override'] if ENV['allow_override'] Redmine::IMAP.check(imap_options, options) diff --git a/lib/tasks/migrate_from_trac.rake b/lib/tasks/migrate_from_trac.rake index 880964ff8..02d921300 100644 --- a/lib/tasks/migrate_from_trac.rake +++ b/lib/tasks/migrate_from_trac.rake @@ -5,12 +5,12 @@ # 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. @@ -22,10 +22,10 @@ require 'pp' namespace :redmine do desc 'Trac migration script' task :migrate_from_trac => :environment do - + module TracMigrate TICKET_MAP = [] - + DEFAULT_STATUS = IssueStatus.default assigned_status = IssueStatus.find_by_position(2) resolved_status = IssueStatus.find_by_position(3) @@ -36,7 +36,7 @@ namespace :redmine do 'assigned' => assigned_status, 'closed' => closed_status } - + priorities = Enumeration.get_values('IPRI') DEFAULT_PRIORITY = priorities[0] PRIORITY_MAPPING = {'lowest' => priorities[0], @@ -51,7 +51,7 @@ namespace :redmine do 'critical' => priorities[3], 'blocker' => priorities[4] } - + TRACKER_BUG = Tracker.find_by_position(1) TRACKER_FEATURE = Tracker.find_by_position(2) DEFAULT_TRACKER = TRACKER_BUG @@ -60,7 +60,7 @@ namespace :redmine do 'task' => TRACKER_FEATURE, 'patch' =>TRACKER_FEATURE } - + roles = Role.find(:all, :conditions => {:builtin => 0}, :order => 'position ASC') manager_role = roles[0] developer_role = roles[1] @@ -68,7 +68,7 @@ namespace :redmine do ROLE_MAPPING = {'admin' => manager_role, 'developer' => developer_role } - + class ::Time class << self alias :real_now :now @@ -87,10 +87,10 @@ namespace :redmine do class TracComponent < ActiveRecord::Base set_table_name :component end - + class TracMilestone < ActiveRecord::Base set_table_name :milestone - + # If this attribute is set a milestone has a defined target timepoint def due if read_attribute(:due) && read_attribute(:due) > 0 Time.at(read_attribute(:due)).to_date @@ -98,43 +98,51 @@ namespace :redmine do nil end end + # This is the real timepoint at which the milestone has finished. + def completed + if read_attribute(:completed) && read_attribute(:completed) > 0 + Time.at(read_attribute(:completed)).to_date + else + nil + end + end def description # Attribute is named descr in Trac v0.8.x has_attribute?(:descr) ? read_attribute(:descr) : read_attribute(:description) end end - + class TracTicketCustom < ActiveRecord::Base set_table_name :ticket_custom end - + class TracAttachment < ActiveRecord::Base set_table_name :attachment set_inheritance_column :none - + def time; Time.at(read_attribute(:time)) end - + def original_filename filename end - + def content_type Redmine::MimeType.of(filename) || '' end - + def exist? File.file? trac_fullpath end - + def read File.open("#{trac_fullpath}", 'rb').read end - + def description read_attribute(:description).to_s.slice(0,255) end - + private def trac_fullpath attachment_type = read_attribute(:type) @@ -142,11 +150,11 @@ namespace :redmine do "#{TracMigrate.trac_attachments_directory}/#{attachment_type}/#{id}/#{trac_file}" end end - + class TracTicket < ActiveRecord::Base set_table_name :ticket set_inheritance_column :none - + # ticket changes: only migrate status changes and comments has_many :changes, :class_name => "TracTicketChange", :foreign_key => :ticket has_many :attachments, :class_name => "TracAttachment", @@ -154,29 +162,29 @@ namespace :redmine do " WHERE #{TracMigrate::TracAttachment.table_name}.type = 'ticket'" + ' AND #{TracMigrate::TracAttachment.table_name}.id = \'#{id}\'' has_many :customs, :class_name => "TracTicketCustom", :foreign_key => :ticket - + def ticket_type read_attribute(:type) end - + def summary read_attribute(:summary).blank? ? "(no subject)" : read_attribute(:summary) end - + def description read_attribute(:description).blank? ? summary : read_attribute(:description) end - + def time; Time.at(read_attribute(:time)) end def changetime; Time.at(read_attribute(:changetime)) end end - + class TracTicketChange < ActiveRecord::Base set_table_name :ticket_change - + def time; Time.at(read_attribute(:time)) end end - + TRAC_WIKI_PAGES = %w(InterMapTxt InterTrac InterWiki RecentChanges SandBox TracAccessibility TracAdmin TracBackup TracBrowser TracCgi TracChangeset \ TracEnvironment TracFastCgi TracGuide TracImport TracIni TracInstall TracInterfaceCustomization \ TracLinks TracLogging TracModPython TracNotification TracPermissions TracPlugins TracQuery \ @@ -184,35 +192,35 @@ namespace :redmine do TracTicketsCustomFields TracTimeline TracUnicode TracUpgrade TracWiki WikiDeletePage WikiFormatting \ WikiHtml WikiMacros WikiNewPage WikiPageNames WikiProcessors WikiRestructuredText WikiRestructuredTextLinks \ CamelCase TitleIndex) - + class TracWikiPage < ActiveRecord::Base set_table_name :wiki set_primary_key :name - + has_many :attachments, :class_name => "TracAttachment", :finder_sql => "SELECT DISTINCT attachment.* FROM #{TracMigrate::TracAttachment.table_name}" + " WHERE #{TracMigrate::TracAttachment.table_name}.type = 'wiki'" + ' AND #{TracMigrate::TracAttachment.table_name}.id = \'#{id}\'' - + def self.columns # Hides readonly Trac field to prevent clash with AR readonly? method (Rails 2.0) super.select {|column| column.name.to_s != 'readonly'} end - + def time; Time.at(read_attribute(:time)) end end - + class TracPermission < ActiveRecord::Base - set_table_name :permission + set_table_name :permission end - + class TracSessionAttribute < ActiveRecord::Base set_table_name :session_attribute end - + def self.find_or_create_user(username, project_member = false) return User.anonymous if username.blank? - + u = User.find_by_login(username) if !u # Create a new user if not found @@ -221,7 +229,7 @@ namespace :redmine do mail = mail_attr.value end mail = "#{mail}@foo.bar" unless mail.include?("@") - + name = username if name_attr = TracSessionAttribute.find_by_sid_and_name(username, 'name') name = name_attr.value @@ -229,7 +237,7 @@ namespace :redmine do name =~ (/(.*)(\s+\w+)?/) fn = $1.strip ln = ($2 || '-').strip - + u = User.new :mail => mail.gsub(/[^-@a-z0-9\.]/i, '-'), :firstname => fn[0, limit_for(User, 'firstname')].gsub(/[^\w\s\'\-]/i, '-'), :lastname => ln[0, limit_for(User, 'lastname')].gsub(/[^\w\s\'\-]/i, '-') @@ -253,13 +261,30 @@ namespace :redmine do end u end - + # Basic wiki syntax conversion def self.convert_wiki_text(text) # Titles text = text.gsub(/^(\=+)\s(.+)\s(\=+)/) {|s| "\nh#{$1.length}. #{$2}\n"} # External Links text = text.gsub(/\[(http[^\s]+)\s+([^\]]+)\]/) {|s| "\"#{$2}\":#{$1}"} + # Ticket links: + # [ticket:234 Text],[ticket:234 This is a test] + text = text.gsub(/\[ticket\:([^\ ]+)\ (.+?)\]/, '"\2":/issues/show/\1') + # ticket:1234 + # #1 is working cause Redmine uses the same syntax. + text = text.gsub(/ticket\:([^\ ]+)/, '#\1') + # Milestone links: + # [milestone:"0.1.0 Mercury" Milestone 0.1.0 (Mercury)] + # The text "Milestone 0.1.0 (Mercury)" is not converted, + # cause Redmine's wiki does not support this. + text = text.gsub(/\[milestone\:\"([^\"]+)\"\ (.+?)\]/, 'version:"\1"') + # [milestone:"0.1.0 Mercury"] + text = text.gsub(/\[milestone\:\"([^\"]+)\"\]/, 'version:"\1"') + text = text.gsub(/milestone\:\"([^\"]+)\"/, 'version:"\1"') + # milestone:0.1.0 + text = text.gsub(/\[milestone\:([^\ ]+)\]/, 'version:\1') + text = text.gsub(/milestone\:([^\ ]+)/, 'version:\1') # Internal Links text = text.gsub(/\[\[BR\]\]/, "\n") # This has to go before the rules below text = text.gsub(/\[\"(.+)\".*\]/) {|s| "[[#{$1.delete(',./?;|:')}]]"} @@ -268,11 +293,11 @@ namespace :redmine do text = text.gsub(/\[wiki:([^\s\]]+)\]/) {|s| "[[#{$1.delete(',./?;|:')}]]"} text = text.gsub(/\[wiki:([^\s\]]+)\s(.*)\]/) {|s| "[[#{$1.delete(',./?;|:')}|#{$2.delete(',./?;|:')}]]"} - # Links to pages UsingJustWikiCaps - text = text.gsub(/([^!]|^)(^| )([A-Z][a-z]+[A-Z][a-zA-Z]+)/, '\\1\\2[[\3]]') - # Normalize things that were supposed to not be links - # like !NotALink - text = text.gsub(/(^| )!([A-Z][A-Za-z]+)/, '\1\2') + # Links to pages UsingJustWikiCaps + text = text.gsub(/([^!]|^)(^| )([A-Z][a-z]+[A-Z][a-zA-Z]+)/, '\\1\\2[[\3]]') + # Normalize things that were supposed to not be links + # like !NotALink + text = text.gsub(/(^| )!([A-Z][A-Za-z]+)/, '\1\2') # Revisions links text = text.gsub(/\[(\d+)\]/, 'r\1') # Ticket number re-writing @@ -284,9 +309,38 @@ namespace :redmine do s end end - # Preformatted blocks - text = text.gsub(/\{\{\{/, '
    ')
    -        text = text.gsub(/\}\}\}/, '
    ') + # We would like to convert the Code highlighting too + # This will go into the next line. + shebang_line = false + # Reguar expression for start of code + pre_re = /\{\{\{/ + # Code hightlighing... + shebang_re = /^\#\!([a-z]+)/ + # Regular expression for end of code + pre_end_re = /\}\}\}/ + + # Go through the whole text..extract it line by line + text = text.gsub(/^(.*)$/) do |line| + m_pre = pre_re.match(line) + if m_pre + line = '
    '
    +          else
    +            m_sl = shebang_re.match(line)
    +            if m_sl
    +              shebang_line = true
    +              line = ''
    +            end
    +            m_pre_end = pre_end_re.match(line)
    +            if m_pre_end
    +              line = '
    ' + if shebang_line + line = '' + line + end + end + end + line + end + # Highlighting text = text.gsub(/'''''([^\s])/, '_*\1') text = text.gsub(/([^\s])'''''/, '\1*_') @@ -295,57 +349,73 @@ namespace :redmine do text = text.gsub(/__/, '+') text = text.gsub(/~~/, '-') text = text.gsub(/`/, '@') - text = text.gsub(/,,/, '~') + text = text.gsub(/,,/, '~') # Lists text = text.gsub(/^([ ]+)\* /) {|s| '*' * $1.length + " "} text end - + def self.migrate establish_connection # Quick database test TracComponent.count - + migrated_components = 0 migrated_milestones = 0 migrated_tickets = 0 migrated_custom_values = 0 migrated_ticket_attachments = 0 - migrated_wiki_edits = 0 + migrated_wiki_edits = 0 migrated_wiki_attachments = 0 - + + #Wiki system initializing... + @target_project.wiki.destroy if @target_project.wiki + @target_project.reload + wiki = Wiki.new(:project => @target_project, :start_page => 'WikiStart') + wiki_edit_count = 0 + # Components print "Migrating components" issues_category_map = {} TracComponent.find(:all).each do |component| - print '.' - STDOUT.flush + print '.' + STDOUT.flush c = IssueCategory.new :project => @target_project, :name => encode(component.name[0, limit_for(IssueCategory, 'name')]) - next unless c.save - issues_category_map[component.name] = c - migrated_components += 1 + next unless c.save + issues_category_map[component.name] = c + migrated_components += 1 end puts - + # Milestones print "Migrating milestones" version_map = {} TracMilestone.find(:all).each do |milestone| print '.' STDOUT.flush + # First we try to find the wiki page... + p = wiki.find_or_new_page(milestone.name.to_s) + p.content = WikiContent.new(:page => p) if p.new_record? + p.content.text = milestone.description.to_s + p.content.author = find_or_create_user('trac') + p.content.comments = 'Milestone' + p.save + v = Version.new :project => @target_project, :name => encode(milestone.name[0, limit_for(Version, 'name')]), - :description => encode(milestone.description.to_s[0, limit_for(Version, 'description')]), - :effective_date => milestone.due + :description => nil, + :wiki_page_title => milestone.name.to_s, + :effective_date => milestone.completed + next unless v.save version_map[milestone.name] = v migrated_milestones += 1 end puts - + # Custom fields # TODO: read trac.ini instead print "Migrating custom fields" @@ -360,14 +430,14 @@ namespace :redmine do # Or create a new one f ||= IssueCustomField.create(:name => encode(field.name[0, limit_for(IssueCustomField, 'name')]).humanize, :field_format => 'string') - + next if f.new_record? f.trackers = Tracker.find(:all) f.projects << @target_project custom_field_map[field.name] = f end puts - + # Trac 'resolution' field as a Redmine custom field r = IssueCustomField.find(:first, :conditions => { :name => "Resolution" }) r = IssueCustomField.new(:name => 'Resolution', @@ -378,45 +448,44 @@ namespace :redmine do r.possible_values = (r.possible_values + %w(fixed invalid wontfix duplicate worksforme)).flatten.compact.uniq r.save! custom_field_map['resolution'] = r - + # Tickets print "Migrating tickets" TracTicket.find(:all, :order => 'id ASC').each do |ticket| - print '.' - STDOUT.flush - i = Issue.new :project => @target_project, + print '.' + STDOUT.flush + i = Issue.new :project => @target_project, :subject => encode(ticket.summary[0, limit_for(Issue, 'subject')]), :description => convert_wiki_text(encode(ticket.description)), :priority => PRIORITY_MAPPING[ticket.priority] || DEFAULT_PRIORITY, :created_on => ticket.time - i.author = find_or_create_user(ticket.reporter) - i.category = issues_category_map[ticket.component] unless ticket.component.blank? - i.fixed_version = version_map[ticket.milestone] unless ticket.milestone.blank? - i.status = STATUS_MAPPING[ticket.status] || DEFAULT_STATUS - i.tracker = TRACKER_MAPPING[ticket.ticket_type] || DEFAULT_TRACKER - i.custom_values << CustomValue.new(:custom_field => custom_field_map['resolution'], :value => ticket.resolution) unless ticket.resolution.blank? - i.id = ticket.id unless Issue.exists?(ticket.id) - next unless Time.fake(ticket.changetime) { i.save } - TICKET_MAP[ticket.id] = i.id - migrated_tickets += 1 - - # Owner + i.author = find_or_create_user(ticket.reporter) + i.category = issues_category_map[ticket.component] unless ticket.component.blank? + i.fixed_version = version_map[ticket.milestone] unless ticket.milestone.blank? + i.status = STATUS_MAPPING[ticket.status] || DEFAULT_STATUS + i.tracker = TRACKER_MAPPING[ticket.ticket_type] || DEFAULT_TRACKER + i.id = ticket.id unless Issue.exists?(ticket.id) + next unless Time.fake(ticket.changetime) { i.save } + TICKET_MAP[ticket.id] = i.id + migrated_tickets += 1 + + # Owner unless ticket.owner.blank? i.assigned_to = find_or_create_user(ticket.owner, true) Time.fake(ticket.changetime) { i.save } end - - # Comments and status/resolution changes - ticket.changes.group_by(&:time).each do |time, changeset| + + # Comments and status/resolution changes + ticket.changes.group_by(&:time).each do |time, changeset| status_change = changeset.select {|change| change.field == 'status'}.first resolution_change = changeset.select {|change| change.field == 'resolution'}.first comment_change = changeset.select {|change| change.field == 'comment'}.first - + n = Journal.new :notes => (comment_change ? convert_wiki_text(encode(comment_change.newvalue)) : ''), :created_on => time n.user = find_or_create_user(changeset.first.author) n.journalized = i - if status_change && + if status_change && STATUS_MAPPING[status_change.oldvalue] && STATUS_MAPPING[status_change.newvalue] && (STATUS_MAPPING[status_change.oldvalue] != STATUS_MAPPING[status_change.newvalue]) @@ -432,40 +501,40 @@ namespace :redmine do :value => resolution_change.newvalue) end n.save unless n.details.empty? && n.notes.blank? - end - - # Attachments - ticket.attachments.each do |attachment| - next unless attachment.exist? + end + + # Attachments + ticket.attachments.each do |attachment| + next unless attachment.exist? a = Attachment.new :created_on => attachment.time a.file = attachment a.author = find_or_create_user(attachment.author) a.container = i a.description = attachment.description migrated_ticket_attachments += 1 if a.save - end - - # Custom fields - ticket.customs.each do |custom| - next if custom_field_map[custom.name].nil? - v = CustomValue.new :custom_field => custom_field_map[custom.name], - :value => custom.value - v.customized = i - next unless v.save + end + + # Custom fields + custom_values = ticket.customs.inject({}) do |h, custom| + if custom_field = custom_field_map[custom.name] + h[custom_field.id] = custom.value migrated_custom_values += 1 - end + end + h + end + if custom_field_map['resolution'] && !ticket.resolution.blank? + custom_values[custom_field_map['resolution'].id] = ticket.resolution + end + i.custom_field_values = custom_values + i.save_custom_field_values end - + # update issue id sequence if needed (postgresql) Issue.connection.reset_pk_sequence!(Issue.table_name) if Issue.connection.respond_to?('reset_pk_sequence!') puts - - # Wiki + + # Wiki print "Migrating wiki" - @target_project.wiki.destroy if @target_project.wiki - @target_project.reload - wiki = Wiki.new(:project => @target_project, :start_page => 'WikiStart') - wiki_edit_count = 0 if wiki.save TracWikiPage.find(:all, :order => 'name, version').each do |page| # Do not migrate Trac manual wiki pages @@ -479,10 +548,10 @@ namespace :redmine do p.content.author = find_or_create_user(page.author) unless page.author.blank? || page.author == 'trac' p.content.comments = page.comment Time.fake(page.time) { p.new_record? ? p.save : p.content.save } - + next if p.content.new_record? - migrated_wiki_edits += 1 - + migrated_wiki_edits += 1 + # Attachments page.attachments.each do |attachment| next unless attachment.exist? @@ -495,7 +564,7 @@ namespace :redmine do migrated_wiki_attachments += 1 if a.save end end - + wiki.reload wiki.pages.each do |page| page.content.text = convert_wiki_text(page.content.text) @@ -503,7 +572,7 @@ namespace :redmine do end end puts - + puts puts "Components: #{migrated_components}/#{TracComponent.count}" puts "Milestones: #{migrated_milestones}/#{TracMilestone.count}" @@ -513,18 +582,18 @@ namespace :redmine do puts "Wiki edits: #{migrated_wiki_edits}/#{wiki_edit_count}" puts "Wiki files: #{migrated_wiki_attachments}/" + TracAttachment.count(:conditions => {:type => 'wiki'}).to_s end - + def self.limit_for(klass, attribute) klass.columns_hash[attribute.to_s].limit end - + def self.encoding(charset) @ic = Iconv.new('UTF-8', charset) rescue Iconv::InvalidEncoding puts "Invalid encoding!" return false end - + def self.set_trac_directory(path) @@trac_directory = path raise "This directory doesn't exist!" unless File.directory?(path) @@ -549,7 +618,7 @@ namespace :redmine do puts e return false end - + def self.set_trac_db_host(host) return nil if host.blank? @@trac_db_host = host @@ -559,7 +628,7 @@ namespace :redmine do return nil if port.to_i == 0 @@trac_db_port = port.to_i end - + def self.set_trac_db_name(name) return nil if name.blank? @@trac_db_name = name @@ -568,22 +637,22 @@ namespace :redmine do def self.set_trac_db_username(username) @@trac_db_username = username end - + def self.set_trac_db_password(password) @@trac_db_password = password end - + def self.set_trac_db_schema(schema) @@trac_db_schema = schema end mattr_reader :trac_directory, :trac_adapter, :trac_db_host, :trac_db_port, :trac_db_name, :trac_db_schema, :trac_db_username, :trac_db_password - + def self.trac_db_path; "#{trac_directory}/db/trac.db" end def self.trac_attachments_directory; "#{trac_directory}/attachments" end - + def self.target_project_identifier(identifier) - project = Project.find_by_identifier(identifier) + project = Project.find_by_identifier(identifier) if !project # create the target project project = Project.new :name => identifier.humanize, @@ -596,16 +665,16 @@ namespace :redmine do puts puts "This project already exists in your Redmine database." print "Are you sure you want to append data to this project ? [Y/n] " - exit if STDIN.gets.match(/^n$/i) + exit if STDIN.gets.match(/^n$/i) end project.trackers << TRACKER_BUG unless project.trackers.include?(TRACKER_BUG) project.trackers << TRACKER_FEATURE unless project.trackers.include?(TRACKER_FEATURE) @target_project = project.new_record? ? nil : project end - + def self.connection_params if %w(sqlite sqlite3).include?(trac_adapter) - {:adapter => trac_adapter, + {:adapter => trac_adapter, :database => trac_db_path} else {:adapter => trac_adapter, @@ -618,7 +687,7 @@ namespace :redmine do } end end - + def self.establish_connection constants.each do |const| klass = const_get(const) @@ -626,7 +695,7 @@ namespace :redmine do klass.establish_connection connection_params end end - + private def self.encode(text) @ic.iconv text @@ -634,7 +703,7 @@ namespace :redmine do text end end - + puts if Redmine::DefaultData::Loader.no_data? puts "Redmine configuration need to be loaded before importing data." @@ -643,10 +712,10 @@ namespace :redmine do puts " rake redmine:load_default_data RAILS_ENV=\"#{ENV['RAILS_ENV']}\"" exit end - + puts "WARNING: a new project will be added to Redmine during this process." print "Are you sure you want to continue ? [y/N] " - break unless STDIN.gets.match(/^y$/i) + break unless STDIN.gets.match(/^y$/i) puts def prompt(text, options = {}, &block) @@ -658,9 +727,9 @@ namespace :redmine do break if yield value end end - + DEFAULT_PORTS = {'mysql' => 3306, 'postgresql' => 5432} - + prompt('Trac directory') {|directory| TracMigrate.set_trac_directory directory.strip} prompt('Trac database adapter (sqlite, sqlite3, mysql, postgresql)', :default => 'sqlite') {|adapter| TracMigrate.set_trac_adapter adapter} unless %w(sqlite sqlite3).include?(TracMigrate.trac_adapter) @@ -674,7 +743,8 @@ namespace :redmine do prompt('Trac database encoding', :default => 'UTF-8') {|encoding| TracMigrate.encoding encoding} prompt('Target project identifier') {|identifier| TracMigrate.target_project_identifier identifier} puts - + TracMigrate.migrate end end + diff --git a/lib/tasks/testing.rake b/lib/tasks/testing.rake index 42f756f68..da832b3e7 100644 --- a/lib/tasks/testing.rake +++ b/lib/tasks/testing.rake @@ -1,5 +1,35 @@ ### From http://svn.geekdaily.org/public/rails/plugins/generally_useful/tasks/coverage_via_rcov.rake +namespace :test do + namespace :scm do + namespace :setup do + desc "Creates directory for test repositories" + task :create_dir do + FileUtils.mkdir_p Rails.root + '/tmp/test' + end + + supported_scms = [:subversion, :cvs, :bazaar, :mercurial, :git, :darcs, :filesystem] + + desc "Creates a test subversion repository" + task :subversion => :create_dir do + repo_path = "tmp/test/subversion_repository" + system "svnadmin create #{repo_path}" + system "gunzip < test/fixtures/repositories/subversion_repository.dump.gz | svnadmin load #{repo_path}" + end + + (supported_scms - [:subversion]).each do |scm| + desc "Creates a test #{scm} repository" + task scm => :create_dir do + system "gunzip < test/fixtures/repositories/#{scm}_repository.tar.gz | tar -xv -C tmp/test" + end + end + + desc "Creates all test repositories" + task :all => supported_scms + end + end +end + ### Inspired by http://blog.labratz.net/articles/2006/12/2/a-rake-task-for-rcov begin require 'rcov/rcovtask' diff --git a/public/dispatch.cgi.example b/public/dispatch.cgi.example index 9730473f2..ce705d36e 100755 --- a/public/dispatch.cgi.example +++ b/public/dispatch.cgi.example @@ -1,4 +1,4 @@ -#!/usr/bin/ruby +#!/usr/bin/env ruby require File.dirname(__FILE__) + "/../config/environment" unless defined?(RAILS_ROOT) diff --git a/public/dispatch.fcgi.example b/public/dispatch.fcgi.example index f934b3002..664dbbbee 100755 --- a/public/dispatch.fcgi.example +++ b/public/dispatch.fcgi.example @@ -1,4 +1,4 @@ -#!/usr/bin/ruby +#!/usr/bin/env ruby # # You may specify the path to the FastCGI crash log (a log of unhandled # exceptions which forced the FastCGI instance to exit, great for debugging) diff --git a/public/dispatch.rb.example b/public/dispatch.rb.example index 9730473f2..ce705d36e 100755 --- a/public/dispatch.rb.example +++ b/public/dispatch.rb.example @@ -1,4 +1,4 @@ -#!/usr/bin/ruby +#!/usr/bin/env ruby require File.dirname(__FILE__) + "/../config/environment" unless defined?(RAILS_ROOT) diff --git a/public/help/wiki_syntax_detailed.html b/public/help/wiki_syntax_detailed.html index ce416b573..b3db673b9 100644 --- a/public/help/wiki_syntax_detailed.html +++ b/public/help/wiki_syntax_detailed.html @@ -1,352 +1,247 @@ - - - -RedmineWikiFormatting - - - - - -

    Wiki formatting

    - - - -

    Links

    - - -

    Redmine links

    - - -

    Redmine allows hyperlinking between issues, changesets and wiki pages from anywhere wiki formatting is used.

    - - -
      -
    • Link to an issue: #124 (displays #124, link is striked-through if the issue is closed)
    • -
    • Link to a changeset: r758 (displays r758)
    • -
    • Link to a changeset with a non-numeric hash: commit:c6f4d0fd (displays c6f4d0fd). Added in r1236.
    • -
    - - -

    Wiki links:

    - - -
      -
    • [[Guide]] displays a link to the page named 'Guide': Guide
    • -
    • [[Guide|User manual]] displays a link to the same page but with a different text: User manual
    • -
    - - -

    You can also link to pages of an other project wiki:

    - - -
      -
    • [[sandbox:some page]] displays a link to the page named 'Some page' of the Sandbox wiki
    • -
    • [[sandbox:]] displays a link to the Sandbox wiki main page
    • -
    - - -

    Wiki links are displayed in red if the page doesn't exist yet, eg: Nonexistent page.

    - - -

    Links to others resources (0.7):

    - - -
      -
    • Documents: - -
        -
      • document#17 (link to document with id 17)
      • -
      • document:Greetings (link to the document with title "Greetings")
      • -
      • document:"Some document" (double quotes can be used when document title contains spaces)
      • -
    • -
    - - -
      -
    • Versions: - -
        -
      • version#3 (link to version with id 3)
      • -
      • version:1.0.0 (link to version named "1.0.0")
      • -
      • version:"1.0 beta 2"
      • -
    • -
    - - -
      -
    • Attachments: - -
        -
      • attachment:file.zip (link to the attachment of the current object named file.zip)
      • -
      • For now, attachments of the current object can be referenced only (if you're on an issue, it's possible to reference attachments of this issue only)
      • -
    • -
    - - -
      -
    • Repository files - -
        -
      • source:some/file -- Link to the file located at /some/file in the project's repository
      • -
      • source:some/file@52 -- Link to the file's revision 52
      • - -
      • source:some/file#L120 -- Link to line 120 of the file
      • -
      • source:some/file@52#L120 -- Link to line 120 of the file's revision 52
      • -
      • export:some/file -- Force the download of the file
      • -
    • - -
    - - - -

    Escaping (0.7):

    - - -
      -
    • You can prevent Redmine links from being parsed by preceding them with an exclamation mark: !
    • -
    - - -

    External links

    - - -

    HTTP URLs and email addresses are automatically turned into clickable links:

    - - -
    -http://www.redmine.org, someone@foo.bar
    -
    - -

    displays: http://www.redmine.org,

    - - -

    If you want to display a specific text instead of the URL, you can use the standard textile syntax:

    - - -
    -"Redmine web site":http://www.redmine.org
    -
    - -

    displays: Redmine web site

    - - -

    Text formatting

    - - -

    For things such as headlines, bold, tables, lists, Redmine supports Textile syntax. See http://hobix.com/textile/ for information on using any of these features. A few samples are included below, but the engine is capable of much more of that.

    - - -

    Font style

    - - -
    -* *bold*
    -* _italic_
    -* _*bold italic*_
    -* +underline+
    -* -strike-through-
    -
    - -

    Display:

    - - -
      -
    • bold
    • -
    • italic
    • -
    • *bold italic*
    • -
    • underline
    • -
    • strike-through
    • -
    - - -

    Inline images

    - - -
      -
    • !image_url! displays an image located at image_url (textile syntax)
    • -
    • !>image_url! right floating image
    • -
    • If you have an image attached to your wiki page, it can be displayed inline using its filename: !attached_image.png!
    • -
    - - -

    Headings

    - - -
    -h1. Heading
    -h2. Subheading
    -h3. Subheading
    -
    - -

    Paragraphs

    - - -
    -p>. right aligned
    -p=. centered
    -
    - -

    This is centered paragraph.

    - - -

    Blockquotes

    - - -

    Start the paragraph with bq.

    - - -
    -bq. Rails is a full-stack framework for developing database-backed web applications according to the Model-View-Control pattern.
    -To go live, all you need to add is a database and a web server.
    -
    - -

    Display:

    - - -
    -

    Rails is a full-stack framework for developing database-backed web applications according to the Model-View-Control pattern.
    To go live, all you need to add is a database and a web server.

    -
    - - -

    Table of content

    - - -
    -{{toc}} => left aligned toc
    -{{>toc}} => right aligned toc
    -
    - -

    Macros

    - - -

    Redmine has the following builtin macros:

    - - -

    hello_world

    Sample macro.

    include

    Include a wiki page. Example:

    - - -
    {{include(Foo)}}
    macro_list

    Displays a list of all available macros, including description if available.

    - - -

    Code highlighting

    - - -

    Code highlightment relies on CodeRay, a fast syntax highlighting library written completely in Ruby. It currently supports c, html, javascript, rhtml, ruby, scheme, xml languages.

    - - -

    You can highlight code in your wiki page using this syntax:

    - - -
    -<pre><code class="ruby">
    -  Place you code here.
    -</code></pre>
    -
    - -

    Example:

    - - -
     1 # The Greeter class
    - 2 class Greeter
    - 3   def initialize(name)
    - 4     @name = name.capitalize
    - 5   end
    - 6 
    - 7   def salute
    - 8     puts "Hello #{@name}!" 
    - 9   end
    -10 end
    -
    -
    - - + + + +RedmineWikiFormatting + + + + + +

    Wiki formatting

    + +

    Links

    + +

    Redmine links

    + +

    Redmine allows hyperlinking between issues, changesets and wiki pages from anywhere wiki formatting is used.

    +
      +
    • Link to an issue: #124 (displays #124, link is striked-through if the issue is closed)
    • +
    • Link to a changeset: r758 (displays r758)
    • +
    • Link to a changeset with a non-numeric hash: commit:c6f4d0fd (displays c6f4d0fd). Added in r1236.
    • +
    + +

    Wiki links:

    + +
      +
    • [[Guide]] displays a link to the page named 'Guide': Guide
    • +
    • [[Guide#further-reading]] takes you to the anchor "further-reading". Headings get automatically assigned anchors so that you can refer to them: Guide
    • +
    • [[Guide|User manual]] displays a link to the same page but with a different text: User manual
    • +
    + +

    You can also link to pages of an other project wiki:

    + +
      +
    • [[sandbox:some page]] displays a link to the page named 'Some page' of the Sandbox wiki
    • +
    • [[sandbox:]] displays a link to the Sandbox wiki main page
    • +
    + +

    Wiki links are displayed in red if the page doesn't exist yet, eg: Nonexistent page.

    + +

    Links to others resources (0.7):

    + +
      +
    • Documents: +
        +
      • document#17 (link to document with id 17)
      • +
      • document:Greetings (link to the document with title "Greetings")
      • +
      • document:"Some document" (double quotes can be used when document title contains spaces)
      • +
    • +
    + +
      +
    • Versions: +
        +
      • version#3 (link to version with id 3)
      • +
      • version:1.0.0 (link to version named "1.0.0")
      • +
      • version:"1.0 beta 2"
      • +
    • +
    + +
      +
    • Attachments: +
        +
      • attachment:file.zip (link to the attachment of the current object named file.zip)
      • +
      • For now, attachments of the current object can be referenced only (if you're on an issue, it's possible to reference attachments of this issue only)
      • +
    • +
    + +
      +
    • Repository files +
        +
      • source:some/file -- Link to the file located at /some/file in the project's repository
      • +
      • source:some/file@52 -- Link to the file's revision 52
      • +
      • source:some/file#L120 -- Link to line 120 of the file
      • +
      • source:some/file@52#L120 -- Link to line 120 of the file's revision 52
      • +
      • export:some/file -- Force the download of the file
      • +
    • +
    + +

    Escaping (0.7):

    + +
      +
    • You can prevent Redmine links from being parsed by preceding them with an exclamation mark: !
    • +
    + + +

    External links

    + +

    HTTP URLs and email addresses are automatically turned into clickable links:

    + +
    +http://www.redmine.org, someone@foo.bar
    +
    + +

    displays: http://www.redmine.org,

    + +

    If you want to display a specific text instead of the URL, you can use the standard textile syntax:

    + +
    +"Redmine web site":http://www.redmine.org
    +
    + +

    displays: Redmine web site

    + + +

    Text formatting

    + + +

    For things such as headlines, bold, tables, lists, Redmine supports Textile syntax. See http://hobix.com/textile/ for information on using any of these features. A few samples are included below, but the engine is capable of much more of that.

    + +

    Font style

    + +
    +* *bold*
    +* _italic_
    +* _*bold italic*_
    +* +underline+
    +* -strike-through-
    +
    + +

    Display:

    + +
      +
    • bold
    • +
    • italic
    • +
    • *bold italic*
    • +
    • underline
    • +
    • strike-through
    • +
    + +

    Inline images

    + +
      +
    • !image_url! displays an image located at image_url (textile syntax)
    • +
    • !>image_url! right floating image
    • +
    • If you have an image attached to your wiki page, it can be displayed inline using its filename: !attached_image.png!
    • +
    + +

    Headings

    + +
    +h1. Heading
    +h2. Subheading
    +h3. Subsubheading
    +
    + +

    Redmine assigns an anchor to each of those headings thus you can link to them with "#Heading", "#Subheading" and so forth.

    + + +

    Paragraphs

    + +
    +p>. right aligned
    +p=. centered
    +
    + +

    This is centered paragraph.

    + + +

    Blockquotes

    + +

    Start the paragraph with bq.

    + +
    +bq. Rails is a full-stack framework for developing database-backed web applications according to the Model-View-Control pattern.
    +To go live, all you need to add is a database and a web server.
    +
    + +

    Display:

    + +
    +

    Rails is a full-stack framework for developing database-backed web applications according to the Model-View-Control pattern.
    To go live, all you need to add is a database and a web server.

    +
    + + +

    Table of content

    + +
    +{{toc}} => left aligned toc
    +{{>toc}} => right aligned toc
    +
    + +

    Macros

    + +

    Redmine has the following builtin macros:

    + +

    hello_world

    Sample macro.

    include

    Include a wiki page. Example:

    + +
    {{include(Foo)}}
    macro_list

    Displays a list of all available macros, including description if available.

    + + +

    Code highlighting

    + +

    Code highlightment relies on CodeRay, a fast syntax highlighting library written completely in Ruby. It currently supports c, html, javascript, rhtml, ruby, scheme, xml languages.

    + +

    You can highlight code in your wiki page using this syntax:

    + +
    +<pre><code class="ruby">
    +  Place you code here.
    +</code></pre>
    +
    + +

    Example:

    + +
     1 # The Greeter class
    + 2 class Greeter
    + 3   def initialize(name)
    + 4     @name = name.capitalize
    + 5   end
    + 6 
    + 7   def salute
    + 8     puts "Hello #{@name}!" 
    + 9   end
    +10 end
    +
    +
    + + diff --git a/public/images/openid-bg.gif b/public/images/openid-bg.gif new file mode 100644 index 0000000000000000000000000000000000000000..e2d8377db023a3915cc9e8c2f1f5c7462622f0a1 GIT binary patch literal 328 zcmZ?wbhEHb6krfwxXQrr>({UQ_wR4qxN*;(J#*&FS-N!TvSrKGuV4S?%F;i7{_Nbj z^V6qK`}XadJ9qBs)2Dx~3p;V*#MZ4_j~qF&aN)v#|Nb2~aNyvg9 ztXT2$=g%EGcI@80`{m1*Z{NOs{rdIFl`EeF4W-ruOthu2f ztl_Mdp@*QzZPDcui{^-N`o3xq@(UMrZh5FF-w`Y#$*8QNq^Zf+5a!Y$(d{Fk$;RMZ d?jf!z+?DC8mZr!$-G@O{mX$wbm9ry*H2@d`j5z=R literal 0 HcmV?d00001 diff --git a/public/images/time.png b/public/images/time.png index 81aa780e3890457478c32059f264b776220741ff..911da3f1d31fca4494a4beb22014e5c5c724c236 100644 GIT binary patch delta 781 zcmV+o1M>Wo1DOVp8Gi-<001BJ|6u?C00d`2O+f$vugEtAis=9V02y>eSaefwW^{L9 za%BKPWN%_+AW3auXJt}lVPtu6$z?nM00OH?L_t(I%caxXPtpMZ#qs{6dZ^acQ!hPP zE^C=vZnd^rmj?}lBugyJuA+&WW|UA0-f}e&3ok_E1tru>6o2`Jl$SvK0Rs9f{q{y{ zIa}-Dyqt&6(>dFKZU2)$ik`;X`y5SIt-~)BOCLIw((tQ%$!^S9u+-(ec=0fQ&z6AA zR9rdQrC1Ai`uR3LLnIPL6hnOZJj$rOkJGWB(yB#;DR8&Lhqi{0(# zwc#SwSB~jZKzIFx`8od>2Fo-Pfe7*M8^q#qw2yTxihm-})m2(7-Poo??lia=8#Gd@ z%n(w5_38O!IP`_v&)h5~B*LrftO1t`RTx^^kzZ5M+0y=9> zCqv(6Q0ZLE#v~RK>jcCoH}2j;eockVHA?V1I71Q_H1F}x^ig*?;}_6!KifAmW=3Oj z(>E>?DWLA=x$X5uM-!9IdY+kwxn-KfB`gz5NW|h2 zZeba9!zZen-!ft?q9P|PS*AR>^S2?@s7@%Jmwy~#qQ8=!K_|t!elC^25BvM6b~dytCUw3X6J$BMQ* zleXZ*uClz0h6lL^{8h5FM3pQp@gVnrUn4tYEX&W{{nt1CYkmS4ybI=lp*k1<0000< LMFvhpu0mjf9CL3< delta 388 zcmV-~0ek+L29yJk8Gi!+001a04^sdD04#JxSad^jWnpw_Z*Cw|X>DZyb75^RAT=Ou zVQC;TFfcbDF)}(bHaaymAS*C2FfhPrBK!aV00(qQO+^RS1qBKm5xs!{3;+NC32;bR za{vGf5&!@T5&_cPe*6Fc00d`2O+f$vv5yP}*`v1q;sj*qIw3LR9Aru{O*7(5? zYtEIhFJ~?hqeW8j)sg)tUr)8(1w+dV~#6Y3?6FD7nDHK>VL42oe(*rZTUs{)lBOewOJrAS)@sgRZy z%F>hyq)^%d($a+jvbEIPma<%g&wCql)nJT?C;2jG&YAhmnKKgsAmV>?EHES~x~T7X zs+sKJY)$uZ$;sXvQYTGaS2d(|cfZX!|5t!kR#0tLbM}|5W7u4C!0-2gAiP*vG{dZu zpszlDTUwr!_ea36B)`&b5W?qi!|L|o{h$lgowKNt&7f6j$CPayE~_4jy2lXZ$7TKo zP_^Rg$&G$-I%;z7v@(FfmgKcnw*_L=0_Lcb zLkC9)hC&cDim*X}0(*PtR1HFFBT(FKf@MOAIxfq_05r`>yFTv5iHukZk`&|+%R~ULN=n0< zwMH{M2Y|s#BDvxd+>Q}6WV3z(I?H054vP{MG80A?2&__JW&z`G!!PDX?YR7GjC`?n{pDbW%Dq)z9LBVBN!qPTXY$6O9kX}RpA#Z z8F+~Dfp{9Q%Y39-UM%Mw{}$%PsxdTSK!IosPpU?dUZKMkZX^^l_4w63ngulA_kS(O zy_Z+Zxe=5L?_x@m59gd1&eSqXN&&j;A0wZRe+P0j{YEgzubTh>002ovPDHLk FV1g6?b$0*& literal 0 HcmV?d00001 diff --git a/public/images/warning.png b/public/images/warning.png index bbef670b6a1db9f4fe60d34fd2b664daae4452a8..628cf2dae3d419ae220c8928ac71393b480745a3 100644 GIT binary patch delta 653 zcmV;80&@MA1eyhq8Gi-<001BJ|6u?C00d`2O+f$vugEtAis=9V02y>eSaefwW^{L9 za%BKPWN%_+AW3auXJt}lVPtu6$z?nM00JyYL_t(I%cWCGNR$B({{DxnuIp>dR02a= zQjko_$TbabJq+s9W2tM=DWqeEE*&HYLW}H>M1@d?iV!RjEPsiJP6b&gMn-0?yRw*y z{*RfjgBpQr1rE&2VP-zQZRa2^LF5drI()F2Z0Z`Z;C^=Xi zC_d0g(KBmOAi2sD{f*&xU&BvvXXvJeIPrA%^!Vdl;dH%e8K~&p?6O#{VVbaW!U&ef z!W6yyUku{U8-Hpid+UYb(1~BCo9LptNq&8>!yoJ3Ui(i5RJ|XnYBklL!{@$-7=3mJ z>P@1c=7Oc79e-V7yf+%lD2!I;Y&nXBZ>=B!5?CB>LvEx6nI%n)qqi$#X#wKB(U7XP z2P=+4{b@j#r%9-K(8UqtSDk>0UKzf*HM9yqMZ1D!$A30t7FNJZJ_0~w6$Dp=!I`{) z?4mN{Ri51JFM1bO<_wbf(X%H))la2|25eb)2XE>YQ~@(13-ifYWacO=i?H&VVdWmd zP)D6Bj$gg=QgYN>IvVW`Z98XE=OD9h04f0D%iu7kK2882K!u;`hhfg6sJ=DeJKi+_ zFup&jYk#rwYkD>{wZor%2`_PPNsE5$Q4GmniDLRmNb^bI(p`!RRizg7rgYS3{$AdUN n#PuPbKz)Jw^43`IJO2WdOk>%nxl=Cy0000DZyb75^RAU7ak zc5*HtGB7YVATc>QF*7| z-rnBct*zFKgwA_&#&c`Vb8GkK=hl>r-g9HlQbNWl5XK<@#vusCN-^)&*5}5?)_ZH# zT1w72A;vKf&M_F)oRr>sYxl;z_ukgdwXMCJobTS=-h_MawXOgE|JK&ly}iBOt)1j|t$(Ght*wNFgy)=;-nF&fjD-L1@78Nt_wVoTt(>i;oZgg-*0rtHy}jP0 zrRSxT-kgl*l!V^3tpoEM=l}o!0d!JMQvg8b*k%9#0H8@kK~#9!b&hKnLO>XVtz|{- z%GzwKhu zBYo`CAfVK=Y*Gb=x?x(4Y};`KBok%ON>xc+i$oD)Ns=%YtFLdNlMR&*tH%of0000< LMNUMnLIPld5xDyw diff --git a/public/javascripts/calendar/lang/calendar-da.js b/public/javascripts/calendar/lang/calendar-da.js index 2cba5f683..dfad32179 100644 --- a/public/javascripts/calendar/lang/calendar-da.js +++ b/public/javascripts/calendar/lang/calendar-da.js @@ -91,21 +91,21 @@ Calendar._TT["ABOUT"] = "Dato valg:\n" + "- Benyt \xab, \xbb tasterne til at vælge år\n" + "- Benyt " + String.fromCharCode(0x2039) + ", " + String.fromCharCode(0x203a) + " tasterne til at vælge måned\n" + -"- Hold muse tasten inde på punkterne for at vælge hurtigere."; +"- Hold musetasten inde på punkterne for at vælge hurtigere."; Calendar._TT["ABOUT_TIME"] = "\n\n" + "Tids valg:\n" + -"- Klik på en af tidsramerne for at forhøje det\n" + +"- Klik på en af tidsrammerne for at forhøje det\n" + "- eller Shift-klik for at mindske det\n" + "- eller klik og træk for hurtigere valg."; Calendar._TT["PREV_YEAR"] = "Forrige år (hold for menu)"; Calendar._TT["PREV_MONTH"] = "Forrige måned (hold for menu)"; -Calendar._TT["GO_TODAY"] = "Gå til idag"; +Calendar._TT["GO_TODAY"] = "Gå til dags dato"; Calendar._TT["NEXT_MONTH"] = "Næste måned (hold for menu)"; Calendar._TT["NEXT_YEAR"] = "Næste år (hold for menu)"; Calendar._TT["SEL_DATE"] = "Vælg dato"; Calendar._TT["DRAG_TO_MOVE"] = "Træk for at flytte"; -Calendar._TT["PART_TODAY"] = " (idag)"; +Calendar._TT["PART_TODAY"] = " (dags dato)"; // the following is to inform that "%s" is to be the first day of week // %s will be replaced with the day name. @@ -117,7 +117,7 @@ Calendar._TT["DAY_FIRST"] = "Vis %s først"; Calendar._TT["WEEKEND"] = "6,7"; Calendar._TT["CLOSE"] = "Luk"; -Calendar._TT["TODAY"] = "Idag"; +Calendar._TT["TODAY"] = "I dag"; Calendar._TT["TIME_PART"] = "(Shift-)Klik eller træk for at ændre værdi"; // date formats diff --git a/public/javascripts/calendar/lang/calendar-gl.js b/public/javascripts/calendar/lang/calendar-gl.js new file mode 100644 index 000000000..6141a761e --- /dev/null +++ b/public/javascripts/calendar/lang/calendar-gl.js @@ -0,0 +1,128 @@ +// ** I18N + +// Calendar GL (galician) language +// Author: Martín Vázquez Cabanas, +// Updated: 2009-01-23 +// Encoding: utf-8 +// Distributed under the same terms as the calendar itself. + +// For translators: please use UTF-8 if possible. We strongly believe that +// Unicode is the answer to a real internationalized world. Also please +// include your contact information in the header, as can be seen above. + +// full day names +Calendar._DN = new Array +("Domingo", + "Luns", + "Martes", + "Mércores", + "Xoves", + "Venres", + "Sábado", + "Domingo"); + +// Please note that the following array of short day names (and the same goes +// for short month names, _SMN) isn't absolutely necessary. We give it here +// for exemplification on how one can customize the short day names, but if +// they are simply the first N letters of the full name you can simply say: +// +// Calendar._SDN_len = N; // short day name length +// Calendar._SMN_len = N; // short month name length +// +// If N = 3 then this is not needed either since we assume a value of 3 if not +// present, to be compatible with translation files that were written before +// this feature. + +// short day names +Calendar._SDN = new Array +("Dom", + "Lun", + "Mar", + "Mér", + "Xov", + "Ven", + "Sáb", + "Dom"); + +// First day of the week. "0" means display Sunday first, "1" means display +// Monday first, etc. +Calendar._FD = 1; + +// full month names +Calendar._MN = new Array +("Xaneiro", + "Febreiro", + "Marzo", + "Abril", + "Maio", + "Xuño", + "Xullo", + "Agosto", + "Setembro", + "Outubro", + "Novembro", + "Decembro"); + +// short month names +Calendar._SMN = new Array +("Xan", + "Feb", + "Mar", + "Abr", + "Mai", + "Xun", + "Xull", + "Ago", + "Set", + "Out", + "Nov", + "Dec"); + +// tooltips +Calendar._TT = {}; +Calendar._TT["INFO"] = "Acerca do calendario"; + +Calendar._TT["ABOUT"] = +"Selector DHTML de Data/Hora\n" + +"(c) dynarch.com 2002-2005 / Author: Mihai Bazon\n" + // don't translate this this ;-) +"Para conseguila última versión visite: http://www.dynarch.com/projects/calendar/\n" + +"Distribuído baixo licenza GNU LGPL. Visite http://gnu.org/licenses/lgpl.html para máis detalles." + +"\n\n" + +"Selección de data:\n" + +"- Use os botóns \xab, \xbb para seleccionalo ano\n" + +"- Use os botóns " + String.fromCharCode(0x2039) + ", " + String.fromCharCode(0x203a) + " para seleccionalo mes\n" + +"- Manteña pulsado o rato en calquera destes botóns para unha selección rápida."; +Calendar._TT["ABOUT_TIME"] = "\n\n" + +"Selección de hora:\n" + +"- Pulse en calquera das partes da hora para incrementala\n" + +"- ou pulse maiúsculas mentres fai clic para decrementala\n" + +"- ou faga clic e arrastre o rato para unha selección máis rápida."; + +Calendar._TT["PREV_YEAR"] = "Ano anterior (manter para menú)"; +Calendar._TT["PREV_MONTH"] = "Mes anterior (manter para menú)"; +Calendar._TT["GO_TODAY"] = "Ir a hoxe"; +Calendar._TT["NEXT_MONTH"] = "Mes seguinte (manter para menú)"; +Calendar._TT["NEXT_YEAR"] = "Ano seguinte (manter para menú)"; +Calendar._TT["SEL_DATE"] = "Seleccionar data"; +Calendar._TT["DRAG_TO_MOVE"] = "Arrastrar para mover"; +Calendar._TT["PART_TODAY"] = " (hoxe)"; + +// the following is to inform that "%s" is to be the first day of week +// %s will be replaced with the day name. +Calendar._TT["DAY_FIRST"] = "Facer %s primeiro día da semana"; + +// This may be locale-dependent. It specifies the week-end days, as an array +// of comma-separated numbers. The numbers are from 0 to 6: 0 means Sunday, 1 +// means Monday, etc. +Calendar._TT["WEEKEND"] = "0,6"; + +Calendar._TT["CLOSE"] = "Pechar"; +Calendar._TT["TODAY"] = "Hoxe"; +Calendar._TT["TIME_PART"] = "(Maiúscula-)Clic ou arrastre para cambiar valor"; + +// date formats +Calendar._TT["DEF_DATE_FORMAT"] = "%d/%m/%Y"; +Calendar._TT["TT_DATE_FORMAT"] = "%A, %e de %B de %Y"; + +Calendar._TT["WK"] = "sem"; +Calendar._TT["TIME"] = "Hora:"; diff --git a/public/javascripts/calendar/lang/calendar-ko.js b/public/javascripts/calendar/lang/calendar-ko.js index 016453bfc..6570bb61d 100644 --- a/public/javascripts/calendar/lang/calendar-ko.js +++ b/public/javascripts/calendar/lang/calendar-ko.js @@ -79,23 +79,23 @@ Calendar._SMN = new Array // tooltips Calendar._TT = {}; -Calendar._TT["INFO"] = "About the calendar"; +Calendar._TT["INFO"] = "이 달력은 ... & 도움말"; Calendar._TT["ABOUT"] = -"DHTML Date/Time Selector\n" + +"DHTML 날짜/시간 선택기\n" + "(c) dynarch.com 2002-2005 / Author: Mihai Bazon\n" + // don't translate this this ;-) -"For latest version visit: http://www.dynarch.com/projects/calendar/\n" + -"Distributed under GNU LGPL. See http://gnu.org/licenses/lgpl.html for details." + +"최신 버전을 구하려면 여기로: http://www.dynarch.com/projects/calendar/\n" + +"배포라이센스:GNU LGPL. 참조:http://gnu.org/licenses/lgpl.html for details." + "\n\n" + -"Date selection:\n" + -"- Use the \xab, \xbb buttons to select year\n" + -"- Use the " + String.fromCharCode(0x2039) + ", " + String.fromCharCode(0x203a) + " buttons to select month\n" + -"- Hold mouse button on any of the above buttons for faster selection."; +"날짜 선택:\n" + +"- 해를 선택하려면 \xab, \xbb 버튼을 사용하세요.\n" + +"- 달을 선택하려면 " + String.fromCharCode(0x2039) + ", " + String.fromCharCode(0x203a) + " 버튼을 사용하세요.\n" + +"- 좀 더 빠르게 선택하려면 위의 버튼을 꾹 눌러주세요."; Calendar._TT["ABOUT_TIME"] = "\n\n" + -"Time selection:\n" + -"- Click on any of the time parts to increase it\n" + -"- or Shift-click to decrease it\n" + -"- or click and drag for faster selection."; +"시간 선택:\n" + +"- 시, 분을 더하려면 클릭하세요.\n" + +"- 시, 분을 빼려면 쉬프트 누르고 클릭하세요.\n" + +"- 좀 더 빠르게 선택하려면 클릭하고 드래그하세요."; Calendar._TT["PREV_YEAR"] = "이전 해"; Calendar._TT["PREV_MONTH"] = "이전 달"; @@ -117,11 +117,11 @@ Calendar._TT["WEEKEND"] = "0,6"; Calendar._TT["CLOSE"] = "닫기"; Calendar._TT["TODAY"] = "오늘"; -Calendar._TT["TIME_PART"] = "(Shift-)클릭 or drag to change value"; +Calendar._TT["TIME_PART"] = "클릭(+),쉬프트+클릭(-),드래그"; // date formats Calendar._TT["DEF_DATE_FORMAT"] = "%Y-%m-%d"; Calendar._TT["TT_DATE_FORMAT"] = "%a, %b %e"; Calendar._TT["WK"] = "주"; -Calendar._TT["TIME"] = "Time:"; +Calendar._TT["TIME"] = "시간:"; diff --git a/public/javascripts/calendar/lang/calendar-mk.js b/public/javascripts/calendar/lang/calendar-mk.js new file mode 100644 index 000000000..34fcaaee7 --- /dev/null +++ b/public/javascripts/calendar/lang/calendar-mk.js @@ -0,0 +1,127 @@ +// ** I18N + +// Calendar МК language +// Author: Илин Татабитовски, +// Encoding: UTF-8 +// Distributed under the same terms as the calendar itself. + +// For translators: please use UTF-8 if possible. We strongly believe that +// Unicode is the answer to a real internationalized world. Also please +// include your contact information in the header, as can be seen above. + +// full day names +Calendar._DN = new Array +("недела", + "понеделник", + "вторник", + "среда", + "четврток", + "петок", + "сабота", + "недела"); + +// Please note that the following array of short day names (and the same goes +// for short month names, _SMN) isn't absolutely necessary. We give it here +// for exemplification on how one can customize the short day names, but if +// they are simply the first N letters of the full name you can simply say: +// +// Calendar._SDN_len = N; // short day name length +// Calendar._SMN_len = N; // short month name length +// +// If N = 3 then this is not needed either since we assume a value of 3 if not +// present, to be compatible with translation files that were written before +// this feature. + +// short day names +Calendar._SDN = new Array +("нед", + "пон", + "вто", + "сре", + "чет", + "пет", + "саб", + "нед"); + +// First day of the week. "0" means display Sunday first, "1" means display +// Monday first, etc. +Calendar._FD = 1; + +// full month names +Calendar._MN = new Array +("јануари", + "февруари", + "март", + "април", + "мај", + "јуни", + "јули", + "август", + "септември", + "октомври", + "ноември", + "декември"); + +// short month names +Calendar._SMN = new Array +("јан", + "фев", + "мар", + "апр", + "мај", + "јун", + "јул", + "авг", + "сеп", + "окт", + "ное", + "дек"); + +// tooltips +Calendar._TT = {}; +Calendar._TT["INFO"] = "За календарот"; + +Calendar._TT["ABOUT"] = +"DHTML Date/Time Selector\n" + +"(c) dynarch.com 2002-2005 / Author: Mihai Bazon\n" + // don't translate this this ;-) +"For latest version visit: http://www.dynarch.com/projects/calendar/\n" + +"Distributed under GNU LGPL. See http://gnu.org/licenses/lgpl.html for details." + +"\n\n" + +"Date selection:\n" + +"- Use the \xab, \xbb buttons to select year\n" + +"- Use the " + String.fromCharCode(0x2039) + ", " + String.fromCharCode(0x203a) + " buttons to select month\n" + +"- Hold mouse button on any of the above buttons for faster selection."; +Calendar._TT["ABOUT_TIME"] = "\n\n" + +"Time selection:\n" + +"- Click on any of the time parts to increase it\n" + +"- or Shift-click to decrease it\n" + +"- or click and drag for faster selection."; + +Calendar._TT["PREV_YEAR"] = "Претходна година (hold for menu)"; +Calendar._TT["PREV_MONTH"] = "Претходен месец (hold for menu)"; +Calendar._TT["GO_TODAY"] = "Go Today"; +Calendar._TT["NEXT_MONTH"] = "Следен месец (hold for menu)"; +Calendar._TT["NEXT_YEAR"] = "Следна година (hold for menu)"; +Calendar._TT["SEL_DATE"] = "Изберете дата"; +Calendar._TT["DRAG_TO_MOVE"] = "Drag to move"; +Calendar._TT["PART_TODAY"] = " (денес)"; + +// the following is to inform that "%s" is to be the first day of week +// %s will be replaced with the day name. +Calendar._TT["DAY_FIRST"] = "Прикажи %s прво"; + +// This may be locale-dependent. It specifies the week-end days, as an array +// of comma-separated numbers. The numbers are from 0 to 6: 0 means Sunday, 1 +// means Monday, etc. +Calendar._TT["WEEKEND"] = "0,6"; + +Calendar._TT["CLOSE"] = "Затвори"; +Calendar._TT["TODAY"] = "Денес"; +Calendar._TT["TIME_PART"] = "(Shift-)Click or drag to change value"; + +// date formats +Calendar._TT["DEF_DATE_FORMAT"] = "%d-%m-%Y"; +Calendar._TT["TT_DATE_FORMAT"] = "%a, %e %b"; + +Calendar._TT["WK"] = "нед"; +Calendar._TT["TIME"] = "Време:"; diff --git a/public/javascripts/calendar/lang/calendar-pt.js b/public/javascripts/calendar/lang/calendar-pt.js index 5d4d014ce..1ab579592 100644 --- a/public/javascripts/calendar/lang/calendar-pt.js +++ b/public/javascripts/calendar/lang/calendar-pt.js @@ -1,7 +1,8 @@ // ** I18N -// Calendar pt_BR language +// Calendar pt language // Author: Adalberto Machado, +// Corrected by: Pedro Araújo // Encoding: any // Distributed under the same terms as the calendar itself. @@ -13,11 +14,11 @@ Calendar._DN = new Array ("Domingo", "Segunda", - "Terca", + "Terça", "Quarta", "Quinta", "Sexta", - "Sabado", + "Sábado", "Domingo"); // Please note that the following array of short day names (and the same goes @@ -40,7 +41,7 @@ Calendar._SDN = new Array "Qua", "Qui", "Sex", - "Sab", + "Sáb", "Dom"); // First day of the week. "0" means display Sunday first, "1" means display @@ -51,7 +52,7 @@ Calendar._FD = 1; Calendar._MN = new Array ("Janeiro", "Fevereiro", - "Marco", + "Março", "Abril", "Maio", "Junho", @@ -79,30 +80,30 @@ Calendar._SMN = new Array // tooltips Calendar._TT = {}; -Calendar._TT["INFO"] = "Sobre o calendario"; +Calendar._TT["INFO"] = "Sobre o calendário"; Calendar._TT["ABOUT"] = "DHTML Date/Time Selector\n" + "(c) dynarch.com 2002-2005 / Author: Mihai Bazon\n" + // don't translate this this ;-) -"Ultima versao visite: http://www.dynarch.com/projects/calendar/\n" + -"Distribuido sobre GNU LGPL. Veja http://gnu.org/licenses/lgpl.html para detalhes." + +"Última versão visite: http://www.dynarch.com/projects/calendar/\n" + +"Distribuído sobre a licença GNU LGPL. Veja http://gnu.org/licenses/lgpl.html para detalhes." + "\n\n" + -"Selecao de data:\n" + -"- Use os botoes \xab, \xbb para selecionar o ano\n" + -"- Use os botoes " + String.fromCharCode(0x2039) + ", " + String.fromCharCode(0x203a) + " para selecionar o mes\n" + -"- Segure o botao do mouse em qualquer um desses botoes para selecao rapida."; +"Selecção de data:\n" + +"- Use os botões \xab, \xbb para seleccionar o ano\n" + +"- Use os botões " + String.fromCharCode(0x2039) + ", " + String.fromCharCode(0x203a) + " para seleccionar o mês\n" + +"- Segure o botão do rato em qualquer um desses botões para selecção rápida."; Calendar._TT["ABOUT_TIME"] = "\n\n" + -"Selecao de hora:\n" + +"Selecção de hora:\n" + "- Clique em qualquer parte da hora para incrementar\n" + "- ou Shift-click para decrementar\n" + -"- ou clique e segure para selecao rapida."; +"- ou clique e segure para selecção rápida."; -Calendar._TT["PREV_YEAR"] = "Ant. ano (segure para menu)"; -Calendar._TT["PREV_MONTH"] = "Ant. mes (segure para menu)"; +Calendar._TT["PREV_YEAR"] = "Ano ant. (segure para menu)"; +Calendar._TT["PREV_MONTH"] = "Mês ant. (segure para menu)"; Calendar._TT["GO_TODAY"] = "Hoje"; -Calendar._TT["NEXT_MONTH"] = "Prox. mes (segure para menu)"; +Calendar._TT["NEXT_MONTH"] = "Prox. mês (segure para menu)"; Calendar._TT["NEXT_YEAR"] = "Prox. ano (segure para menu)"; -Calendar._TT["SEL_DATE"] = "Selecione a data"; +Calendar._TT["SEL_DATE"] = "Seleccione a data"; Calendar._TT["DRAG_TO_MOVE"] = "Arraste para mover"; Calendar._TT["PART_TODAY"] = " (hoje)"; diff --git a/public/javascripts/calendar/lang/calendar-sk.js b/public/javascripts/calendar/lang/calendar-sk.js new file mode 100644 index 000000000..c54d9ac93 --- /dev/null +++ b/public/javascripts/calendar/lang/calendar-sk.js @@ -0,0 +1,68 @@ +/* + calendar-sk.js + language: Slovak + encoding: UTF-8 + author: Stanislav Pach (stano.pach@seznam.cz) +*/ + +// ** I18N +Calendar._DN = new Array('Nedeľa','Pondelok','Utorok','Streda','Štvrtok','Piatok','Sobota','Nedeľa'); +Calendar._SDN = new Array('Ne','Po','Ut','St','Št','Pi','So','Ne'); +Calendar._MN = new Array('Január','Február','Marec','Apríl','Máj','Jún','Júl','August','September','Október','November','December'); +Calendar._SMN = new Array('Jan','Feb','Mar','Apr','Máj','Jún','Júl','Aug','Sep','Okt','Nov','Dec'); + +// First day of the week. "0" means display Sunday first, "1" means display +// Monday first, etc. +Calendar._FD = 1; + +// tooltips +Calendar._TT = {}; +Calendar._TT["INFO"] = "O komponente kalendár"; +Calendar._TT["TOGGLE"] = "Zmena prvého dňa v týždni"; +Calendar._TT["PREV_YEAR"] = "Predchádzajúci rok (pridrž pre menu)"; +Calendar._TT["PREV_MONTH"] = "Predchádzajúci mesiac (pridrž pre menu)"; +Calendar._TT["GO_TODAY"] = "Dnešný dátum"; +Calendar._TT["NEXT_MONTH"] = "Ďalší mesiac (pridrž pre menu)"; +Calendar._TT["NEXT_YEAR"] = "Ďalší rok (pridrž pre menu)"; +Calendar._TT["SEL_DATE"] = "Zvoľ dátum"; +Calendar._TT["DRAG_TO_MOVE"] = "Chyť a ťahaj pre presun"; +Calendar._TT["PART_TODAY"] = " (dnes)"; +Calendar._TT["MON_FIRST"] = "Ukáž ako prvný Pondelok"; +//Calendar._TT["SUN_FIRST"] = "Ukaž jako první Neděli"; + +Calendar._TT["ABOUT"] = +"DHTML Date/Time Selector\n" + +"(c) dynarch.com 2002-2005 / Author: Mihai Bazon\n" + // don't translate this this ;-) +"For latest version visit: http://www.dynarch.com/projects/calendar/\n" + +"Distributed under GNU LGPL. See http://gnu.org/licenses/lgpl.html for details." + +"\n\n" + +"Výber dátumu:\n" + +"- Použijte tlačítka \xab, \xbb pre voľbu roku\n" + +"- Použijte tlačítka " + String.fromCharCode(0x2039) + ", " + String.fromCharCode(0x203a) + " pre výber mesiaca\n" + +"- Podržte tlačítko myši na akomkoľvek z týchto tlačítok pre rýchlejší výber."; + +Calendar._TT["ABOUT_TIME"] = "\n\n" + +"Výber času:\n" + +"- Kliknite na akúkoľvek časť z výberu času pre zvýšenie.\n" + +"- alebo Shift-klick pre zníženie\n" + +"- alebo kliknite a ťahajte pre rýchlejší výber."; + +// the following is to inform that "%s" is to be the first day of week +// %s will be replaced with the day name. +Calendar._TT["DAY_FIRST"] = "Zobraz %s ako prvý"; + +// This may be locale-dependent. It specifies the week-end days, as an array +// of comma-separated numbers. The numbers are from 0 to 6: 0 means Sunday, 1 +// means Monday, etc. +Calendar._TT["WEEKEND"] = "0,6"; + +Calendar._TT["CLOSE"] = "Zavrieť"; +Calendar._TT["TODAY"] = "Dnes"; +Calendar._TT["TIME_PART"] = "(Shift-)Klikni alebo ťahaj pre zmenu hodnoty"; + +// date formats +Calendar._TT["DEF_DATE_FORMAT"] = "d.m.yy"; +Calendar._TT["TT_DATE_FORMAT"] = "%a, %b %e"; + +Calendar._TT["WK"] = "týž"; +Calendar._TT["TIME"] = "Čas:"; diff --git a/public/javascripts/calendar/lang/calendar-sl.js b/public/javascripts/calendar/lang/calendar-sl.js new file mode 100644 index 000000000..771731c5b --- /dev/null +++ b/public/javascripts/calendar/lang/calendar-sl.js @@ -0,0 +1,127 @@ +// ** I18N + +// Calendar SL language +// Author: Jernej Vidmar, +// Encoding: any +// Distributed under the same terms as the calendar itself. + +// For translators: please use UTF-8 if possible. We strongly believe that +// Unicode is the answer to a real internationalized world. Also please +// include your contact information in the header, as can be seen above. + +// full day names +Calendar._DN = new Array +("Nedelja", + "Ponedeljek", + "Torek", + "Sreda", + "Četrtek", + "Petek", + "Sobota", + "Nedelja"); + +// Please note that the following array of short day names (and the same goes +// for short month names, _SMN) isn't absolutely necessary. We give it here +// for exemplification on how one can customize the short day names, but if +// they are simply the first N letters of the full name you can simply say: +// +// Calendar._SDN_len = N; // short day name length +// Calendar._SMN_len = N; // short month name length +// +// If N = 3 then this is not needed either since we assume a value of 3 if not +// present, to be compatible with translation files that were written before +// this feature. + +// short day names +Calendar._SDN = new Array +("Ned", + "Pon", + "Tor", + "Sre", + "Čet", + "Pet", + "Sob", + "Ned"); + +// First day of the week. "0" means display Sunday first, "1" means display +// Monday first, etc. +Calendar._FD = 0; + +// full month names +Calendar._MN = new Array +("Januar", + "Februar", + "Marec", + "April", + "Maj", + "Junij", + "Julij", + "Avgust", + "September", + "Oktober", + "November", + "December"); + +// short month names +Calendar._SMN = new Array +("Jan", + "Feb", + "Mar", + "Apr", + "Maj", + "Jun", + "Jul", + "Avg", + "Sep", + "Okt", + "Nov", + "Dec"); + +// tooltips +Calendar._TT = {}; +Calendar._TT["INFO"] = "O koledarju"; + +Calendar._TT["ABOUT"] = +"DHTML Date/Time Selector\n" + +"(c) dynarch.com 2002-2005 / Author: Mihai Bazon\n" + // don't translate this this ;-) +"For latest version visit: http://www.dynarch.com/projects/calendar/\n" + +"Distributed under GNU LGPL. See http://gnu.org/licenses/lgpl.html for details." + +"\n\n" + +"Izbira datuma:\n" + +"- Uporabite \xab, \xbb gumbe za izbiro leta\n" + +"- Uporabite " + String.fromCharCode(0x2039) + ", " + String.fromCharCode(0x203a) + " gumbe za izbiro meseca\n" + +"- Za hitrejšo izbiro držite miškin gumb nad enim od zgornjih gumbov."; +Calendar._TT["ABOUT_TIME"] = "\n\n" + +"Izbira časa:\n" + +"- Kliknite na katerikoli del časa da ga povečate\n" + +"- oziroma kliknite s Shiftom za znižanje\n" + +"- ali kliknite in vlecite za hitrejšo izbiro."; + +Calendar._TT["PREV_YEAR"] = "Prejšnje leto (držite za meni)"; +Calendar._TT["PREV_MONTH"] = "Prejšnji mesec (držite za meni)"; +Calendar._TT["GO_TODAY"] = "Pojdi na danes"; +Calendar._TT["NEXT_MONTH"] = "Naslednji mesec (držite za meni)"; +Calendar._TT["NEXT_YEAR"] = "Naslednje leto (držite za meni)"; +Calendar._TT["SEL_DATE"] = "Izberite datum"; +Calendar._TT["DRAG_TO_MOVE"] = "Povlecite za premik"; +Calendar._TT["PART_TODAY"] = " (danes)"; + +// the following is to inform that "%s" is to be the first day of week +// %s will be replaced with the day name. +Calendar._TT["DAY_FIRST"] = "Najprej prikaži %s"; + +// This may be locale-dependent. It specifies the week-end days, as an array +// of comma-separated numbers. The numbers are from 0 to 6: 0 means Sunday, 1 +// means Monday, etc. +Calendar._TT["WEEKEND"] = "0,6"; + +Calendar._TT["CLOSE"] = "Zapri"; +Calendar._TT["TODAY"] = "Danes"; +Calendar._TT["TIME_PART"] = "(Shift-)klik ali povleči, da spremeniš vrednost"; + +// date formats +Calendar._TT["DEF_DATE_FORMAT"] = "%Y-%m-%d"; +Calendar._TT["TT_DATE_FORMAT"] = "%a, %b %e"; + +Calendar._TT["WK"] = "wk"; +Calendar._TT["TIME"] = "Time:"; diff --git a/public/javascripts/calendar/lang/calendar-sv.js b/public/javascripts/calendar/lang/calendar-sv.js index 7e73d7926..fcc0eaa67 100644 --- a/public/javascripts/calendar/lang/calendar-sv.js +++ b/public/javascripts/calendar/lang/calendar-sv.js @@ -17,7 +17,7 @@ Calendar._SMN_len = 3; // short month name length // First day of the week. "0" means display Sunday first, "1" means display // Monday first, etc. -Calendar._FD = 0; +Calendar._FD = 1; // full month names Calendar._MN = new Array @@ -36,49 +36,49 @@ Calendar._MN = new Array // tooltips Calendar._TT = {}; -Calendar._TT["INFO"] = "About the calendar"; +Calendar._TT["INFO"] = "Om kalendern"; Calendar._TT["ABOUT"] = -"DHTML Date/Time Selector\n" + -"(c) dynarch.com 2002-2005 / Author: Mihai Bazon\n" + // don't translate this this ;-) -"For latest version visit: http://www.dynarch.com/projects/calendar/\n" + -"Distributed under GNU LGPL. See http://gnu.org/licenses/lgpl.html for details." + +"DHTML Datum/Tid-väljare\n" + +"(c) dynarch.com 2002-2005 / Upphovsman: Mihai Bazon\n" + // don't translate this this ;-) +"För senaste version besök: http://www.dynarch.com/projects/calendar/\n" + +"Distribueras under GNU LGPL. Se http://gnu.org/licenses/lgpl.html för detaljer." + "\n\n" + -"Date selection:\n" + -"- Use the \xab, \xbb buttons to select year\n" + -"- Use the " + String.fromCharCode(0x2039) + ", " + String.fromCharCode(0x203a) + " buttons to select month\n" + -"- Hold mouse button on any of the above buttons for faster selection."; +"Välja datum:\n" + +"- Använd \xab, \xbb knapparna för att välja år\n" + +"- Använd " + String.fromCharCode(0x2039) + ", " + String.fromCharCode(0x203a) + " knapparna för att välja månad\n" + +"- Håll nere musknappen på någon av ovanstående knappar för att se snabbval."; Calendar._TT["ABOUT_TIME"] = "\n\n" + -"Time selection:\n" + -"- Click on any of the time parts to increase it\n" + -"- or Shift-click to decrease it\n" + -"- or click and drag for faster selection."; +"Välja tid:\n" + +"- Klicka på något av tidsfälten för att öka\n" + +"- eller Skift-klicka för att minska\n" + +"- eller klicka och dra för att välja snabbare."; -Calendar._TT["PREV_YEAR"] = "Prev. year (hold for menu)"; -Calendar._TT["PREV_MONTH"] = "Prev. month (hold for menu)"; -Calendar._TT["GO_TODAY"] = "Go Today"; -Calendar._TT["NEXT_MONTH"] = "Next month (hold for menu)"; -Calendar._TT["NEXT_YEAR"] = "Next year (hold for menu)"; -Calendar._TT["SEL_DATE"] = "Select date"; -Calendar._TT["DRAG_TO_MOVE"] = "Drag to move"; -Calendar._TT["PART_TODAY"] = " (today)"; +Calendar._TT["PREV_YEAR"] = "Föreg. år (håll nere för lista)"; +Calendar._TT["PREV_MONTH"] = "Föreg. månad (håll nere för lista)"; +Calendar._TT["GO_TODAY"] = "Gå till Idag"; +Calendar._TT["NEXT_MONTH"] = "Nästa månad (håll nere för lista)"; +Calendar._TT["NEXT_YEAR"] = "Nästa år (håll nere för lista)"; +Calendar._TT["SEL_DATE"] = "Välj datum"; +Calendar._TT["DRAG_TO_MOVE"] = "Dra för att flytta"; +Calendar._TT["PART_TODAY"] = " (idag)"; // the following is to inform that "%s" is to be the first day of week // %s will be replaced with the day name. -Calendar._TT["DAY_FIRST"] = "Display %s first"; +Calendar._TT["DAY_FIRST"] = "Visa %s först"; // This may be locale-dependent. It specifies the week-end days, as an array // of comma-separated numbers. The numbers are from 0 to 6: 0 means Sunday, 1 // means Monday, etc. Calendar._TT["WEEKEND"] = "0,6"; -Calendar._TT["CLOSE"] = "Close"; -Calendar._TT["TODAY"] = "Today"; -Calendar._TT["TIME_PART"] = "(Shift-)Click or drag to change value"; +Calendar._TT["CLOSE"] = "Stäng"; +Calendar._TT["TODAY"] = "Idag"; +Calendar._TT["TIME_PART"] = "(Skift-)klicka eller dra för att ändra värde"; // date formats Calendar._TT["DEF_DATE_FORMAT"] = "%Y-%m-%d"; Calendar._TT["TT_DATE_FORMAT"] = "%a, %b %e"; -Calendar._TT["WK"] = "wk"; -Calendar._TT["TIME"] = "Time:"; +Calendar._TT["WK"] = "v."; +Calendar._TT["TIME"] = "Tid:"; diff --git a/public/javascripts/calendar/lang/calendar-vn.js b/public/javascripts/calendar/lang/calendar-vn.js new file mode 100644 index 000000000..9172c6638 --- /dev/null +++ b/public/javascripts/calendar/lang/calendar-vn.js @@ -0,0 +1,126 @@ +// ** I18N + +// Calendar EN language +// Author: Mihai Bazon, +// Encoding: any +// Distributed under the same terms as the calendar itself. + +// For translators: please use UTF-8 if possible. We strongly believe that +// Unicode is the answer to a real internationalized world. Also please +// include your contact information in the header, as can be seen above. + +// full day names +Calendar._DN = new Array +("Chủ nhật", + "Thứ Hai", + "Thứ Ba", + "Thứ Tư", + "Thứ Năm", + "Thứ Sáu", + "Thứ Bảy", + "Chủ Nhật"); + +// Please note that the following array of short day names (and the same goes +// for short month names, _SMN) isn't absolutely necessary. We give it here +// for exemplification on how one can customize the short day names, but if +// they are simply the first N letters of the full name you can simply say: +// +// Calendar._SDN_len = N; // short day name length +// Calendar._SMN_len = N; // short month name length +// +// If N = 3 then this is not needed either since we assume a value of 3 if not +// present, to be compatible with translation files that were written before +// this feature. + +// short day names +Calendar._SDN = new Array +("C.Nhật", + "Hai", + "Ba", + "Tư", + "Năm", + "Sáu", + "Bảy", + "C.Nhật"); + +// First day of the week. "0" means display Sunday first, "1" means display +// Monday first, etc. +Calendar._FD = 1; + +// full month names +Calendar._MN = new Array +("Tháng Giêng", + "Tháng Hai", + "Tháng Ba", + "Tháng Tư", + "Tháng Năm", + "Tháng Sáu", + "Tháng Bảy", + "Tháng Tám", + "Tháng Chín", + "Tháng Mười", + "Tháng M.Một", + "Tháng Chạp"); + +// short month names +Calendar._SMN = new Array +("Mmột", + "Hai", + "Ba", + "Tư", + "Năm", + "Sáu", + "Bảy", + "Tám", + "Chín", + "Mười", + "MMột", + "Chạp"); + +// tooltips +Calendar._TT = {}; +Calendar._TT["INFO"] = "Giới thiệu"; + +Calendar._TT["ABOUT"] = +"DHTML Date/Time Selector (c) dynarch.com 2002-2005 / Tác giả: Mihai Bazon. " + // don't translate this this ;-) +"Phiên bản mới nhất có tại: http://www.dynarch.com/projects/calendar/. " + +"Sản phẩm được phân phối theo giấy phép GNU LGPL. Xem chi tiết tại http://gnu.org/licenses/lgpl.html." + +"\n\n" + +"Chọn ngày:\n" + +"- Dùng nút \xab, \xbb để chọn năm\n" + +"- Dùng nút " + String.fromCharCode(0x2039) + ", " + String.fromCharCode(0x203a) + " để chọn tháng\n" + +"- Giữ chuột vào các nút trên để có danh sách năm và tháng."; +Calendar._TT["ABOUT_TIME"] = "\n\n" + +"Chọn thời gian:\n" + +"- Click chuột trên từng phần của thời gian để chỉnh sửa\n" + +"- hoặc nhấn Shift + click chuột để tăng giá trị\n" + +"- hoặc click chuột và kéo (drag) để chọn nhanh."; + +Calendar._TT["PREV_YEAR"] = "Năm trước (giữ chuột để có menu)"; +Calendar._TT["PREV_MONTH"] = "Tháng trước (giữ chuột để có menu)"; +Calendar._TT["GO_TODAY"] = "đến Hôm nay"; +Calendar._TT["NEXT_MONTH"] = "Tháng tới (giữ chuột để có menu)"; +Calendar._TT["NEXT_YEAR"] = "Ngày tới (giữ chuột để có menu)"; +Calendar._TT["SEL_DATE"] = "Chọn ngày"; +Calendar._TT["DRAG_TO_MOVE"] = "Kéo (drag) để di chuyển"; +Calendar._TT["PART_TODAY"] = " (hôm nay)"; + +// the following is to inform that "%s" is to be the first day of week +// %s will be replaced with the day name. +Calendar._TT["DAY_FIRST"] = "Hiển thị %s trước"; + +// This may be locale-dependent. It specifies the week-end days, as an array +// of comma-separated numbers. The numbers are from 0 to 6: 0 means Sunday, 1 +// means Monday, etc. +Calendar._TT["WEEKEND"] = "0,6"; + +Calendar._TT["CLOSE"] = "Đóng"; +Calendar._TT["TODAY"] = "Hôm nay"; +Calendar._TT["TIME_PART"] = "Click, shift-click hoặc kéo (drag) để đổi giá trị"; + +// date formats +Calendar._TT["DEF_DATE_FORMAT"] = "%Y-%m-%d"; +Calendar._TT["TT_DATE_FORMAT"] = "%a, %b %e"; + +Calendar._TT["WK"] = "wk"; +Calendar._TT["TIME"] = "Time:"; diff --git a/public/javascripts/context_menu.js b/public/javascripts/context_menu.js index 20f0fc5a7..955650d6a 100644 --- a/public/javascripts/context_menu.js +++ b/public/javascripts/context_menu.js @@ -48,7 +48,7 @@ ContextMenu.prototype = { if (window.opera && e.altKey) { return; } if (Event.isLeftClick(e) || (navigator.appVersion.match(/\bMSIE\b/))) { var tr = Event.findElement(e, 'tr'); - if (tr!=document && tr.hasClassName('hascontextmenu')) { + if (tr!=null && tr!=document && tr.hasClassName('hascontextmenu')) { // a row was clicked, check if the click was on checkbox var box = Event.findElement(e, 'input'); if (box!=document && box!=undefined) { diff --git a/public/javascripts/jstoolbar/jstoolbar.js b/public/javascripts/jstoolbar/jstoolbar.js index 64c460217..66669ceee 100644 --- a/public/javascripts/jstoolbar/jstoolbar.js +++ b/public/javascripts/jstoolbar/jstoolbar.js @@ -378,182 +378,3 @@ jsToolBar.prototype.resizeDragStop = function(event) { document.removeEventListener('mousemove', this.dragMoveHdlr, false); document.removeEventListener('mouseup', this.dragStopHdlr, false); }; - -// Elements definition ------------------------------------ - -// strong -jsToolBar.prototype.elements.strong = { - type: 'button', - title: 'Strong', - fn: { - wiki: function() { this.singleTag('*') } - } -} - -// em -jsToolBar.prototype.elements.em = { - type: 'button', - title: 'Italic', - fn: { - wiki: function() { this.singleTag("_") } - } -} - -// ins -jsToolBar.prototype.elements.ins = { - type: 'button', - title: 'Underline', - fn: { - wiki: function() { this.singleTag('+') } - } -} - -// del -jsToolBar.prototype.elements.del = { - type: 'button', - title: 'Deleted', - fn: { - wiki: function() { this.singleTag('-') } - } -} - -// code -jsToolBar.prototype.elements.code = { - type: 'button', - title: 'Code', - fn: { - wiki: function() { this.singleTag('@') } - } -} - -// spacer -jsToolBar.prototype.elements.space1 = {type: 'space'} - -// headings -jsToolBar.prototype.elements.h1 = { - type: 'button', - title: 'Heading 1', - fn: { - wiki: function() { - this.encloseLineSelection('h1. ', '',function(str) { - str = str.replace(/^h\d+\.\s+/, '') - return str; - }); - } - } -} -jsToolBar.prototype.elements.h2 = { - type: 'button', - title: 'Heading 2', - fn: { - wiki: function() { - this.encloseLineSelection('h2. ', '',function(str) { - str = str.replace(/^h\d+\.\s+/, '') - return str; - }); - } - } -} -jsToolBar.prototype.elements.h3 = { - type: 'button', - title: 'Heading 3', - fn: { - wiki: function() { - this.encloseLineSelection('h3. ', '',function(str) { - str = str.replace(/^h\d+\.\s+/, '') - return str; - }); - } - } -} - -// spacer -jsToolBar.prototype.elements.space2 = {type: 'space'} - -// ul -jsToolBar.prototype.elements.ul = { - type: 'button', - title: 'Unordered list', - fn: { - wiki: function() { - this.encloseLineSelection('','',function(str) { - str = str.replace(/\r/g,''); - return str.replace(/(\n|^)[#-]?\s*/g,"$1* "); - }); - } - } -} - -// ol -jsToolBar.prototype.elements.ol = { - type: 'button', - title: 'Ordered list', - fn: { - wiki: function() { - this.encloseLineSelection('','',function(str) { - str = str.replace(/\r/g,''); - return str.replace(/(\n|^)[*-]?\s*/g,"$1# "); - }); - } - } -} - -// spacer -jsToolBar.prototype.elements.space3 = {type: 'space'} - -// bq -jsToolBar.prototype.elements.bq = { - type: 'button', - title: 'Quote', - fn: { - wiki: function() { - this.encloseLineSelection('','',function(str) { - str = str.replace(/\r/g,''); - return str.replace(/(\n|^) *([^\n]*)/g,"$1> $2"); - }); - } - } -} - -// unbq -jsToolBar.prototype.elements.unbq = { - type: 'button', - title: 'Unquote', - fn: { - wiki: function() { - this.encloseLineSelection('','',function(str) { - str = str.replace(/\r/g,''); - return str.replace(/(\n|^) *[>]? *([^\n]*)/g,"$1$2"); - }); - } - } -} - -// pre -jsToolBar.prototype.elements.pre = { - type: 'button', - title: 'Preformatted text', - fn: { - wiki: function() { this.encloseLineSelection('
    \n', '\n
    ') } - } -} - -// spacer -jsToolBar.prototype.elements.space4 = {type: 'space'} - -// wiki page -jsToolBar.prototype.elements.link = { - type: 'button', - title: 'Wiki link', - fn: { - wiki: function() { this.encloseSelection("[[", "]]") } - } -} -// image -jsToolBar.prototype.elements.img = { - type: 'button', - title: 'Image', - fn: { - wiki: function() { this.encloseSelection("!", "!") } - } -} diff --git a/public/javascripts/jstoolbar/lang/jstoolbar-da.js b/public/javascripts/jstoolbar/lang/jstoolbar-da.js index 6ccc8ead2..4b6b431ed 100644 --- a/public/javascripts/jstoolbar/lang/jstoolbar-da.js +++ b/public/javascripts/jstoolbar/lang/jstoolbar-da.js @@ -1,16 +1,16 @@ jsToolBar.strings = {}; jsToolBar.strings['Strong'] = 'Fed'; jsToolBar.strings['Italic'] = 'Kursiv'; -jsToolBar.strings['Underline'] = 'Underskrevet'; +jsToolBar.strings['Underline'] = 'Understreget'; jsToolBar.strings['Deleted'] = 'Slettet'; -jsToolBar.strings['Code'] = 'Inline Kode'; +jsToolBar.strings['Code'] = 'Inline-kode'; jsToolBar.strings['Heading 1'] = 'Overskrift 1'; jsToolBar.strings['Heading 2'] = 'Overskrift 2'; jsToolBar.strings['Heading 3'] = 'Overskrift 3'; -jsToolBar.strings['Unordered list'] = 'Unummereret list'; -jsToolBar.strings['Ordered list'] = 'Nummereret list'; +jsToolBar.strings['Unordered list'] = 'Unummereret liste'; +jsToolBar.strings['Ordered list'] = 'Nummereret liste'; jsToolBar.strings['Quote'] = 'Quote'; jsToolBar.strings['Unquote'] = 'Remove Quote'; -jsToolBar.strings['Preformatted text'] = 'Preformatteret tekst'; -jsToolBar.strings['Wiki link'] = 'Link til en Wiki side'; +jsToolBar.strings['Preformatted text'] = 'Præformateret tekst'; +jsToolBar.strings['Wiki link'] = 'Link til en wiki-side'; jsToolBar.strings['Image'] = 'Billede'; diff --git a/public/javascripts/jstoolbar/lang/jstoolbar-es.js b/public/javascripts/jstoolbar/lang/jstoolbar-es.js index 2d68498f9..878489fbf 100644 --- a/public/javascripts/jstoolbar/lang/jstoolbar-es.js +++ b/public/javascripts/jstoolbar/lang/jstoolbar-es.js @@ -1,16 +1,16 @@ jsToolBar.strings = {}; -jsToolBar.strings['Strong'] = 'Strong'; -jsToolBar.strings['Italic'] = 'Italic'; -jsToolBar.strings['Underline'] = 'Underline'; -jsToolBar.strings['Deleted'] = 'Deleted'; -jsToolBar.strings['Code'] = 'Inline Code'; -jsToolBar.strings['Heading 1'] = 'Heading 1'; -jsToolBar.strings['Heading 2'] = 'Heading 2'; -jsToolBar.strings['Heading 3'] = 'Heading 3'; -jsToolBar.strings['Unordered list'] = 'Unordered list'; -jsToolBar.strings['Ordered list'] = 'Ordered list'; -jsToolBar.strings['Quote'] = 'Quote'; -jsToolBar.strings['Unquote'] = 'Remove Quote'; -jsToolBar.strings['Preformatted text'] = 'Preformatted text'; -jsToolBar.strings['Wiki link'] = 'Link to a Wiki page'; -jsToolBar.strings['Image'] = 'Image'; +jsToolBar.strings['Strong'] = 'Negrita'; +jsToolBar.strings['Italic'] = 'Itálica'; +jsToolBar.strings['Underline'] = 'Subrayado'; +jsToolBar.strings['Deleted'] = 'Tachado'; +jsToolBar.strings['Code'] = 'Código fuente'; +jsToolBar.strings['Heading 1'] = 'Encabezado 1'; +jsToolBar.strings['Heading 2'] = 'Encabezado 2'; +jsToolBar.strings['Heading 3'] = 'Encabezado 3'; +jsToolBar.strings['Unordered list'] = 'Lista sin ordenar'; +jsToolBar.strings['Ordered list'] = 'Lista ordenada'; +jsToolBar.strings['Quote'] = 'Citar'; +jsToolBar.strings['Unquote'] = 'Quitar cita'; +jsToolBar.strings['Preformatted text'] = 'Texto con formato'; +jsToolBar.strings['Wiki link'] = 'Enlace a página Wiki'; +jsToolBar.strings['Image'] = 'Imagen'; diff --git a/public/javascripts/jstoolbar/lang/jstoolbar-gl.js b/public/javascripts/jstoolbar/lang/jstoolbar-gl.js new file mode 100644 index 000000000..bd1462aeb --- /dev/null +++ b/public/javascripts/jstoolbar/lang/jstoolbar-gl.js @@ -0,0 +1,16 @@ +jsToolBar.strings = {}; +jsToolBar.strings['Strong'] = 'Negriña'; +jsToolBar.strings['Italic'] = 'Itálica'; +jsToolBar.strings['Underline'] = 'Suliñado'; +jsToolBar.strings['Deleted'] = 'Tachado'; +jsToolBar.strings['Code'] = 'Código fonte'; +jsToolBar.strings['Heading 1'] = 'Encabezado 1'; +jsToolBar.strings['Heading 2'] = 'Encabezado 2'; +jsToolBar.strings['Heading 3'] = 'Encabezado 3'; +jsToolBar.strings['Unordered list'] = 'Lista sen ordenar'; +jsToolBar.strings['Ordered list'] = 'Lista ordenada'; +jsToolBar.strings['Quote'] = 'Citar'; +jsToolBar.strings['Unquote'] = 'Quitar cita'; +jsToolBar.strings['Preformatted text'] = 'Texto con formato'; +jsToolBar.strings['Wiki link'] = 'Enlace a páxina Wiki'; +jsToolBar.strings['Image'] = 'Imaxe'; diff --git a/public/javascripts/jstoolbar/lang/jstoolbar-it.js b/public/javascripts/jstoolbar/lang/jstoolbar-it.js index 2d68498f9..bf7fcefb2 100644 --- a/public/javascripts/jstoolbar/lang/jstoolbar-it.js +++ b/public/javascripts/jstoolbar/lang/jstoolbar-it.js @@ -1,16 +1,16 @@ jsToolBar.strings = {}; -jsToolBar.strings['Strong'] = 'Strong'; -jsToolBar.strings['Italic'] = 'Italic'; -jsToolBar.strings['Underline'] = 'Underline'; -jsToolBar.strings['Deleted'] = 'Deleted'; -jsToolBar.strings['Code'] = 'Inline Code'; -jsToolBar.strings['Heading 1'] = 'Heading 1'; -jsToolBar.strings['Heading 2'] = 'Heading 2'; -jsToolBar.strings['Heading 3'] = 'Heading 3'; -jsToolBar.strings['Unordered list'] = 'Unordered list'; -jsToolBar.strings['Ordered list'] = 'Ordered list'; -jsToolBar.strings['Quote'] = 'Quote'; -jsToolBar.strings['Unquote'] = 'Remove Quote'; -jsToolBar.strings['Preformatted text'] = 'Preformatted text'; -jsToolBar.strings['Wiki link'] = 'Link to a Wiki page'; -jsToolBar.strings['Image'] = 'Image'; +jsToolBar.strings['Strong'] = 'Grassetto'; +jsToolBar.strings['Italic'] = 'Corsivo'; +jsToolBar.strings['Underline'] = 'Sottolineato'; +jsToolBar.strings['Deleted'] = 'Barrato'; +jsToolBar.strings['Code'] = 'Codice sorgente'; +jsToolBar.strings['Heading 1'] = 'Titolo 1'; +jsToolBar.strings['Heading 2'] = 'Titolo 2'; +jsToolBar.strings['Heading 3'] = 'Titolo 3'; +jsToolBar.strings['Unordered list'] = 'Elenco puntato'; +jsToolBar.strings['Ordered list'] = 'Numerazione'; +jsToolBar.strings['Quote'] = 'Aumenta rientro'; +jsToolBar.strings['Unquote'] = 'Riduci rientro'; +jsToolBar.strings['Preformatted text'] = 'Testo preformattato'; +jsToolBar.strings['Wiki link'] = 'Collegamento a pagina Wiki'; +jsToolBar.strings['Image'] = 'Immagine'; diff --git a/public/javascripts/jstoolbar/lang/jstoolbar-ko.js b/public/javascripts/jstoolbar/lang/jstoolbar-ko.js index 2d68498f9..1c437ef76 100644 --- a/public/javascripts/jstoolbar/lang/jstoolbar-ko.js +++ b/public/javascripts/jstoolbar/lang/jstoolbar-ko.js @@ -1,16 +1,16 @@ jsToolBar.strings = {}; -jsToolBar.strings['Strong'] = 'Strong'; -jsToolBar.strings['Italic'] = 'Italic'; -jsToolBar.strings['Underline'] = 'Underline'; -jsToolBar.strings['Deleted'] = 'Deleted'; -jsToolBar.strings['Code'] = 'Inline Code'; -jsToolBar.strings['Heading 1'] = 'Heading 1'; -jsToolBar.strings['Heading 2'] = 'Heading 2'; -jsToolBar.strings['Heading 3'] = 'Heading 3'; -jsToolBar.strings['Unordered list'] = 'Unordered list'; -jsToolBar.strings['Ordered list'] = 'Ordered list'; -jsToolBar.strings['Quote'] = 'Quote'; -jsToolBar.strings['Unquote'] = 'Remove Quote'; -jsToolBar.strings['Preformatted text'] = 'Preformatted text'; -jsToolBar.strings['Wiki link'] = 'Link to a Wiki page'; -jsToolBar.strings['Image'] = 'Image'; +jsToolBar.strings['Strong'] = '굵게'; +jsToolBar.strings['Italic'] = '기울임'; +jsToolBar.strings['Underline'] = '밑줄'; +jsToolBar.strings['Deleted'] = '취소선'; +jsToolBar.strings['Code'] = '코드'; +jsToolBar.strings['Heading 1'] = '제목 1'; +jsToolBar.strings['Heading 2'] = '제목 2'; +jsToolBar.strings['Heading 3'] = '제목 3'; +jsToolBar.strings['Unordered list'] = '글머리 기호'; +jsToolBar.strings['Ordered list'] = '번호 매기기'; +jsToolBar.strings['Quote'] = '인용'; +jsToolBar.strings['Unquote'] = '인용 취소'; +jsToolBar.strings['Preformatted text'] = '있는 그대로 표현 (Preformatted text)'; +jsToolBar.strings['Wiki link'] = 'Wiki 페이지에 연결'; +jsToolBar.strings['Image'] = '그림'; diff --git a/public/javascripts/jstoolbar/lang/jstoolbar-mk.js b/public/javascripts/jstoolbar/lang/jstoolbar-mk.js new file mode 100644 index 000000000..3af63a1cc --- /dev/null +++ b/public/javascripts/jstoolbar/lang/jstoolbar-mk.js @@ -0,0 +1,16 @@ +jsToolBar.strings = {}; +jsToolBar.strings['Strong'] = 'Strong'; +jsToolBar.strings['Italic'] = 'Italic'; +jsToolBar.strings['Underline'] = 'Underline'; +jsToolBar.strings['Deleted'] = 'Deleted'; +jsToolBar.strings['Code'] = 'Inline Code'; +jsToolBar.strings['Heading 1'] = 'Heading 1'; +jsToolBar.strings['Heading 2'] = 'Heading 2'; +jsToolBar.strings['Heading 3'] = 'Heading 3'; +jsToolBar.strings['Unordered list'] = 'Unordered list'; +jsToolBar.strings['Ordered list'] = 'Подредена листа'; +jsToolBar.strings['Quote'] = 'Цитат'; +jsToolBar.strings['Unquote'] = 'Отстрани цитат'; +jsToolBar.strings['Preformatted text'] = 'Preformatted text'; +jsToolBar.strings['Wiki link'] = 'Линк до вики страна'; +jsToolBar.strings['Image'] = 'Слика'; diff --git a/public/javascripts/jstoolbar/lang/jstoolbar-nl.js b/public/javascripts/jstoolbar/lang/jstoolbar-nl.js index 2d68498f9..0c54163f0 100644 --- a/public/javascripts/jstoolbar/lang/jstoolbar-nl.js +++ b/public/javascripts/jstoolbar/lang/jstoolbar-nl.js @@ -1,16 +1,16 @@ jsToolBar.strings = {}; -jsToolBar.strings['Strong'] = 'Strong'; -jsToolBar.strings['Italic'] = 'Italic'; -jsToolBar.strings['Underline'] = 'Underline'; -jsToolBar.strings['Deleted'] = 'Deleted'; -jsToolBar.strings['Code'] = 'Inline Code'; -jsToolBar.strings['Heading 1'] = 'Heading 1'; -jsToolBar.strings['Heading 2'] = 'Heading 2'; -jsToolBar.strings['Heading 3'] = 'Heading 3'; -jsToolBar.strings['Unordered list'] = 'Unordered list'; -jsToolBar.strings['Ordered list'] = 'Ordered list'; -jsToolBar.strings['Quote'] = 'Quote'; -jsToolBar.strings['Unquote'] = 'Remove Quote'; -jsToolBar.strings['Preformatted text'] = 'Preformatted text'; -jsToolBar.strings['Wiki link'] = 'Link to a Wiki page'; -jsToolBar.strings['Image'] = 'Image'; +jsToolBar.strings['Strong'] = 'Extra nadruk'; +jsToolBar.strings['Italic'] = 'Cursief'; +jsToolBar.strings['Underline'] = 'Onderstreept'; +jsToolBar.strings['Deleted'] = 'Verwijderd'; +jsToolBar.strings['Code'] = 'Computercode'; +jsToolBar.strings['Heading 1'] = 'Kop 1'; +jsToolBar.strings['Heading 2'] = 'Kop 2'; +jsToolBar.strings['Heading 3'] = 'Kop 3'; +jsToolBar.strings['Unordered list'] = 'Ongeordende lijst'; +jsToolBar.strings['Ordered list'] = 'Geordende lijst'; +jsToolBar.strings['Quote'] = 'Citaat'; +jsToolBar.strings['Unquote'] = 'Verwijder citaat'; +jsToolBar.strings['Preformatted text'] = 'Voor-geformateerde tekst'; +jsToolBar.strings['Wiki link'] = 'Link naar een Wiki pagina'; +jsToolBar.strings['Image'] = 'Afbeelding'; diff --git a/public/javascripts/jstoolbar/lang/jstoolbar-pl.js b/public/javascripts/jstoolbar/lang/jstoolbar-pl.js index 2d68498f9..0e7a38c90 100644 --- a/public/javascripts/jstoolbar/lang/jstoolbar-pl.js +++ b/public/javascripts/jstoolbar/lang/jstoolbar-pl.js @@ -1,16 +1,17 @@ +// Keep this line in order to avoid problems with Windows Notepad UTF-8 EF-BB-BF idea... jsToolBar.strings = {}; -jsToolBar.strings['Strong'] = 'Strong'; -jsToolBar.strings['Italic'] = 'Italic'; -jsToolBar.strings['Underline'] = 'Underline'; -jsToolBar.strings['Deleted'] = 'Deleted'; -jsToolBar.strings['Code'] = 'Inline Code'; -jsToolBar.strings['Heading 1'] = 'Heading 1'; -jsToolBar.strings['Heading 2'] = 'Heading 2'; -jsToolBar.strings['Heading 3'] = 'Heading 3'; -jsToolBar.strings['Unordered list'] = 'Unordered list'; -jsToolBar.strings['Ordered list'] = 'Ordered list'; -jsToolBar.strings['Quote'] = 'Quote'; -jsToolBar.strings['Unquote'] = 'Remove Quote'; -jsToolBar.strings['Preformatted text'] = 'Preformatted text'; -jsToolBar.strings['Wiki link'] = 'Link to a Wiki page'; -jsToolBar.strings['Image'] = 'Image'; +jsToolBar.strings['Strong'] = 'Pogrubienie'; +jsToolBar.strings['Italic'] = 'Kursywa'; +jsToolBar.strings['Underline'] = 'Podkreślenie'; +jsToolBar.strings['Deleted'] = 'Usunięte'; +jsToolBar.strings['Code'] = 'Wstawka kodu'; +jsToolBar.strings['Heading 1'] = 'Nagłowek 1'; +jsToolBar.strings['Heading 2'] = 'Nagłówek 2'; +jsToolBar.strings['Heading 3'] = 'Nagłówek 3'; +jsToolBar.strings['Unordered list'] = 'Nieposortowana lista'; +jsToolBar.strings['Ordered list'] = 'Posortowana lista'; +jsToolBar.strings['Quote'] = 'Cytat'; +jsToolBar.strings['Unquote'] = 'Usuń cytat'; +jsToolBar.strings['Preformatted text'] = 'Sformatowany tekst'; +jsToolBar.strings['Wiki link'] = 'Odnośnik do strony Wiki'; +jsToolBar.strings['Image'] = 'Obraz'; diff --git a/public/javascripts/jstoolbar/lang/jstoolbar-pt.js b/public/javascripts/jstoolbar/lang/jstoolbar-pt.js index 2d68498f9..137d7952a 100644 --- a/public/javascripts/jstoolbar/lang/jstoolbar-pt.js +++ b/public/javascripts/jstoolbar/lang/jstoolbar-pt.js @@ -1,16 +1,17 @@ +// Translated by: Pedro Araújo jsToolBar.strings = {}; -jsToolBar.strings['Strong'] = 'Strong'; -jsToolBar.strings['Italic'] = 'Italic'; -jsToolBar.strings['Underline'] = 'Underline'; -jsToolBar.strings['Deleted'] = 'Deleted'; -jsToolBar.strings['Code'] = 'Inline Code'; -jsToolBar.strings['Heading 1'] = 'Heading 1'; -jsToolBar.strings['Heading 2'] = 'Heading 2'; -jsToolBar.strings['Heading 3'] = 'Heading 3'; -jsToolBar.strings['Unordered list'] = 'Unordered list'; -jsToolBar.strings['Ordered list'] = 'Ordered list'; -jsToolBar.strings['Quote'] = 'Quote'; -jsToolBar.strings['Unquote'] = 'Remove Quote'; -jsToolBar.strings['Preformatted text'] = 'Preformatted text'; -jsToolBar.strings['Wiki link'] = 'Link to a Wiki page'; -jsToolBar.strings['Image'] = 'Image'; +jsToolBar.strings['Strong'] = 'Negrito'; +jsToolBar.strings['Italic'] = 'Itálico'; +jsToolBar.strings['Underline'] = 'Sublinhado'; +jsToolBar.strings['Deleted'] = 'Apagado'; +jsToolBar.strings['Code'] = 'Código Inline'; +jsToolBar.strings['Heading 1'] = 'Cabeçalho 1'; +jsToolBar.strings['Heading 2'] = 'Cabeçalho 2'; +jsToolBar.strings['Heading 3'] = 'Cabeçalho 3'; +jsToolBar.strings['Unordered list'] = 'Lista não ordenada'; +jsToolBar.strings['Ordered list'] = 'Lista ordenada'; +jsToolBar.strings['Quote'] = 'Citação'; +jsToolBar.strings['Unquote'] = 'Remover citação'; +jsToolBar.strings['Preformatted text'] = 'Texto pré-formatado'; +jsToolBar.strings['Wiki link'] = 'Link para uma página da Wiki'; +jsToolBar.strings['Image'] = 'Imagem'; diff --git a/public/javascripts/jstoolbar/lang/jstoolbar-sk.js b/public/javascripts/jstoolbar/lang/jstoolbar-sk.js new file mode 100644 index 000000000..0d47cd516 --- /dev/null +++ b/public/javascripts/jstoolbar/lang/jstoolbar-sk.js @@ -0,0 +1,16 @@ +jsToolBar.strings = {}; +jsToolBar.strings['Strong'] = 'Tučné'; +jsToolBar.strings['Italic'] = 'Kurzíva'; +jsToolBar.strings['Underline'] = 'Podčiarknuté'; +jsToolBar.strings['Deleted'] = 'Preškrtnuté'; +jsToolBar.strings['Code'] = 'Zobrazenie kódu'; +jsToolBar.strings['Heading 1'] = 'Záhlavie 1'; +jsToolBar.strings['Heading 2'] = 'Záhlavie 2'; +jsToolBar.strings['Heading 3'] = 'Záhlavie 3'; +jsToolBar.strings['Unordered list'] = 'Zoznam'; +jsToolBar.strings['Ordered list'] = 'Zoradený zoznam'; +jsToolBar.strings['Quote'] = 'Citácia'; +jsToolBar.strings['Unquote'] = 'Odstránenie citácie'; +jsToolBar.strings['Preformatted text'] = 'Predformátovaný text'; +jsToolBar.strings['Wiki link'] = 'Link na Wiki stránku'; +jsToolBar.strings['Image'] = 'Obrázok'; diff --git a/public/javascripts/jstoolbar/lang/jstoolbar-sl.js b/public/javascripts/jstoolbar/lang/jstoolbar-sl.js new file mode 100644 index 000000000..70949957e --- /dev/null +++ b/public/javascripts/jstoolbar/lang/jstoolbar-sl.js @@ -0,0 +1,16 @@ +jsToolBar.strings = {}; +jsToolBar.strings['Strong'] = 'Krepko'; +jsToolBar.strings['Italic'] = 'Poševno'; +jsToolBar.strings['Underline'] = 'Podčrtano'; +jsToolBar.strings['Deleted'] = 'Izbrisano'; +jsToolBar.strings['Code'] = 'Koda med vrsticami'; +jsToolBar.strings['Heading 1'] = 'Naslov 1'; +jsToolBar.strings['Heading 2'] = 'Naslov 2'; +jsToolBar.strings['Heading 3'] = 'Naslov 3'; +jsToolBar.strings['Unordered list'] = 'Neurejen seznam'; +jsToolBar.strings['Ordered list'] = 'Urejen seznam'; +jsToolBar.strings['Quote'] = 'Citat'; +jsToolBar.strings['Unquote'] = 'Odstrani citat'; +jsToolBar.strings['Preformatted text'] = 'Predoblikovano besedilo'; +jsToolBar.strings['Wiki link'] = 'Povezava na Wiki stran'; +jsToolBar.strings['Image'] = 'Slika'; diff --git a/public/javascripts/jstoolbar/lang/jstoolbar-sv.js b/public/javascripts/jstoolbar/lang/jstoolbar-sv.js index 2d68498f9..08c0b69a3 100644 --- a/public/javascripts/jstoolbar/lang/jstoolbar-sv.js +++ b/public/javascripts/jstoolbar/lang/jstoolbar-sv.js @@ -1,16 +1,16 @@ jsToolBar.strings = {}; -jsToolBar.strings['Strong'] = 'Strong'; -jsToolBar.strings['Italic'] = 'Italic'; -jsToolBar.strings['Underline'] = 'Underline'; -jsToolBar.strings['Deleted'] = 'Deleted'; -jsToolBar.strings['Code'] = 'Inline Code'; -jsToolBar.strings['Heading 1'] = 'Heading 1'; -jsToolBar.strings['Heading 2'] = 'Heading 2'; -jsToolBar.strings['Heading 3'] = 'Heading 3'; -jsToolBar.strings['Unordered list'] = 'Unordered list'; -jsToolBar.strings['Ordered list'] = 'Ordered list'; -jsToolBar.strings['Quote'] = 'Quote'; -jsToolBar.strings['Unquote'] = 'Remove Quote'; -jsToolBar.strings['Preformatted text'] = 'Preformatted text'; -jsToolBar.strings['Wiki link'] = 'Link to a Wiki page'; -jsToolBar.strings['Image'] = 'Image'; +jsToolBar.strings['Strong'] = 'Fet'; +jsToolBar.strings['Italic'] = 'Kursiv'; +jsToolBar.strings['Underline'] = 'Understruken'; +jsToolBar.strings['Deleted'] = 'Genomstruken'; +jsToolBar.strings['Code'] = 'Kod'; +jsToolBar.strings['Heading 1'] = 'Rubrik 1'; +jsToolBar.strings['Heading 2'] = 'Rubrik 2'; +jsToolBar.strings['Heading 3'] = 'Rubrik 3'; +jsToolBar.strings['Unordered list'] = 'Osorterad lista'; +jsToolBar.strings['Ordered list'] = 'Sorterad lista'; +jsToolBar.strings['Quote'] = 'Citat'; +jsToolBar.strings['Unquote'] = 'Ta bort citat'; +jsToolBar.strings['Preformatted text'] = 'Förformaterad text'; +jsToolBar.strings['Wiki link'] = 'Länk till en wikisida'; +jsToolBar.strings['Image'] = 'Bild'; diff --git a/public/javascripts/jstoolbar/lang/jstoolbar-vn.js b/public/javascripts/jstoolbar/lang/jstoolbar-vn.js new file mode 100644 index 000000000..f598bfe0a --- /dev/null +++ b/public/javascripts/jstoolbar/lang/jstoolbar-vn.js @@ -0,0 +1,16 @@ +jsToolBar.strings = {}; +jsToolBar.strings['Strong'] = 'Đậm'; +jsToolBar.strings['Italic'] = 'Nghiêng'; +jsToolBar.strings['Underline'] = 'Gạch chân'; +jsToolBar.strings['Deleted'] = 'Xóa'; +jsToolBar.strings['Code'] = 'Mã chung dòng'; +jsToolBar.strings['Heading 1'] = 'Tiêu đề 1'; +jsToolBar.strings['Heading 2'] = 'Tiêu đề 2'; +jsToolBar.strings['Heading 3'] = 'Tiêu đề 3'; +jsToolBar.strings['Unordered list'] = 'Danh sách không thứ tự'; +jsToolBar.strings['Ordered list'] = 'Danh sách có thứ tự'; +jsToolBar.strings['Quote'] = 'Trích dẫn'; +jsToolBar.strings['Unquote'] = 'Bỏ trích dẫn'; +jsToolBar.strings['Preformatted text'] = 'Mã nguồn'; +jsToolBar.strings['Wiki link'] = 'Liên kết đến trang wiki'; +jsToolBar.strings['Image'] = 'Ảnh'; diff --git a/public/javascripts/jstoolbar/textile.js b/public/javascripts/jstoolbar/textile.js new file mode 100644 index 000000000..c461b9d2e --- /dev/null +++ b/public/javascripts/jstoolbar/textile.js @@ -0,0 +1,200 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * This file is part of DotClear. + * Copyright (c) 2005 Nicolas Martin & Olivier Meunier and contributors. All + * rights reserved. + * + * DotClear is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * DotClear is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with DotClear; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * ***** END LICENSE BLOCK ***** +*/ + +/* Modified by JP LANG for textile formatting */ + +// strong +jsToolBar.prototype.elements.strong = { + type: 'button', + title: 'Strong', + fn: { + wiki: function() { this.singleTag('*') } + } +} + +// em +jsToolBar.prototype.elements.em = { + type: 'button', + title: 'Italic', + fn: { + wiki: function() { this.singleTag("_") } + } +} + +// ins +jsToolBar.prototype.elements.ins = { + type: 'button', + title: 'Underline', + fn: { + wiki: function() { this.singleTag('+') } + } +} + +// del +jsToolBar.prototype.elements.del = { + type: 'button', + title: 'Deleted', + fn: { + wiki: function() { this.singleTag('-') } + } +} + +// code +jsToolBar.prototype.elements.code = { + type: 'button', + title: 'Code', + fn: { + wiki: function() { this.singleTag('@') } + } +} + +// spacer +jsToolBar.prototype.elements.space1 = {type: 'space'} + +// headings +jsToolBar.prototype.elements.h1 = { + type: 'button', + title: 'Heading 1', + fn: { + wiki: function() { + this.encloseLineSelection('h1. ', '',function(str) { + str = str.replace(/^h\d+\.\s+/, '') + return str; + }); + } + } +} +jsToolBar.prototype.elements.h2 = { + type: 'button', + title: 'Heading 2', + fn: { + wiki: function() { + this.encloseLineSelection('h2. ', '',function(str) { + str = str.replace(/^h\d+\.\s+/, '') + return str; + }); + } + } +} +jsToolBar.prototype.elements.h3 = { + type: 'button', + title: 'Heading 3', + fn: { + wiki: function() { + this.encloseLineSelection('h3. ', '',function(str) { + str = str.replace(/^h\d+\.\s+/, '') + return str; + }); + } + } +} + +// spacer +jsToolBar.prototype.elements.space2 = {type: 'space'} + +// ul +jsToolBar.prototype.elements.ul = { + type: 'button', + title: 'Unordered list', + fn: { + wiki: function() { + this.encloseLineSelection('','',function(str) { + str = str.replace(/\r/g,''); + return str.replace(/(\n|^)[#-]?\s*/g,"$1* "); + }); + } + } +} + +// ol +jsToolBar.prototype.elements.ol = { + type: 'button', + title: 'Ordered list', + fn: { + wiki: function() { + this.encloseLineSelection('','',function(str) { + str = str.replace(/\r/g,''); + return str.replace(/(\n|^)[*-]?\s*/g,"$1# "); + }); + } + } +} + +// spacer +jsToolBar.prototype.elements.space3 = {type: 'space'} + +// bq +jsToolBar.prototype.elements.bq = { + type: 'button', + title: 'Quote', + fn: { + wiki: function() { + this.encloseLineSelection('','',function(str) { + str = str.replace(/\r/g,''); + return str.replace(/(\n|^) *([^\n]*)/g,"$1> $2"); + }); + } + } +} + +// unbq +jsToolBar.prototype.elements.unbq = { + type: 'button', + title: 'Unquote', + fn: { + wiki: function() { + this.encloseLineSelection('','',function(str) { + str = str.replace(/\r/g,''); + return str.replace(/(\n|^) *[>]? *([^\n]*)/g,"$1$2"); + }); + } + } +} + +// pre +jsToolBar.prototype.elements.pre = { + type: 'button', + title: 'Preformatted text', + fn: { + wiki: function() { this.encloseLineSelection('
    \n', '\n
    ') } + } +} + +// spacer +jsToolBar.prototype.elements.space4 = {type: 'space'} + +// wiki page +jsToolBar.prototype.elements.link = { + type: 'button', + title: 'Wiki link', + fn: { + wiki: function() { this.encloseSelection("[[", "]]") } + } +} +// image +jsToolBar.prototype.elements.img = { + type: 'button', + title: 'Image', + fn: { + wiki: function() { this.encloseSelection("!", "!") } + } +} diff --git a/public/robots.txt b/public/robots.txt deleted file mode 100644 index 5fb2d1597..000000000 --- a/public/robots.txt +++ /dev/null @@ -1,4 +0,0 @@ -User-agent: * -Disallow: /projects/gantt -Disallow: /projects/calendar -Disallow: /repositories/diff diff --git a/public/stylesheets/application.css b/public/stylesheets/application.css index 8c4173413..653ae152f 100644 --- a/public/stylesheets/application.css +++ b/public/stylesheets/application.css @@ -18,7 +18,7 @@ h4, .wiki h3 {font-size: 13px;padding: 2px 10px 1px 0px;margin-bottom: 5px; bord padding: 0px 0px 0px 0px; white-space:nowrap; } -#top-menu a {color: #fff; padding-right: 8px; font-weight: bold;} +#top-menu a {color: #fff; margin-right: 8px; font-weight: bold;} #top-menu #loggedas { float: right; margin-right: 0.5em; color: #fff; } #account {float:right;} @@ -55,9 +55,10 @@ h4, .wiki h3 {font-size: 13px;padding: 2px 10px 1px 0px;margin-bottom: 5px; bord #sidebar hr{ width: 100%; margin: 0 auto; height: 1px; background: #ccc; border: 0; } * html #sidebar hr{ width: 95%; position: relative; left: -6px; color: #ccc; } -#content { width: 80%; background-color: #fff; margin: 0px; border-right: 1px solid #ddd; padding: 6px 10px 10px 10px; z-index: 10; height:600px; min-height: 600px;} +#content { width: 80%; background-color: #fff; margin: 0px; border-right: 1px solid #ddd; padding: 6px 10px 10px 10px; z-index: 10; } * html #content{ width: 80%; padding-left: 0; margin-top: 0px; padding: 6px 10px 10px 10px;} -html>body #content { height: auto; min-height: 600px; overflow: auto; } +html>body #content { min-height: 600px; } +* html body #content { height: 600px; } /* IE */ #main.nosidebar #sidebar{ display: none; } #main.nosidebar #content{ width: auto; border-right: 0; } @@ -68,6 +69,8 @@ html>body #content { height: auto; min-height: 600px; overflow: auto; } #login-form table td {padding: 6px;} #login-form label {font-weight: bold;} +input#openid_url { background: url(../images/openid-bg.gif) no-repeat; background-color: #fff; background-position: 0 50%; padding-left: 18px; } + .clear:after{ content: "."; display: block; height: 0; clear: both; visibility: hidden; } /***** Links *****/ @@ -84,8 +87,11 @@ table.list td { vertical-align: top; } table.list td.id { width: 2%; text-align: center;} table.list td.checkbox { width: 15px; padding: 0px;} +tr.project td.name a { padding-left: 16px; white-space:nowrap; } +tr.project.parent td.name a { background: url('../images/bullet_toggle_minus.png') no-repeat; } + tr.issue { text-align: center; white-space: nowrap; } -tr.issue td.subject, tr.issue td.category { white-space: normal; } +tr.issue td.subject, tr.issue td.category, td.assigned_to { white-space: normal; } tr.issue td.subject { text-align: left; } tr.issue td.done_ratio table.progress { margin-left:auto; margin-right: auto;} @@ -119,6 +125,12 @@ tr.time-entry td.subject, tr.time-entry td.comments { text-align: left; white-sp td.hours { text-align: right; font-weight: bold; padding-right: 0.5em; } td.hours .hours-dec { font-size: 0.9em; } +table.plugins td { vertical-align: middle; } +table.plugins td.configure { text-align: right; padding-right: 1em; } +table.plugins span.name { font-weight: bold; display: block; margin-bottom: 6px; } +table.plugins span.description { display: block; font-size: 0.9em; } +table.plugins span.url { display: block; font-size: 0.9em; } + table.list tbody tr:hover { background-color:#ffffdd; } table td {padding:2px;} table p {margin:0;} @@ -148,6 +160,7 @@ div.square { } .contextual {float:right; white-space: nowrap; line-height:1.4em;margin-top:5px; padding-left: 10px; font-size:0.9em;} .contextual input {font-size:0.9em;} +.message .contextual { margin-top: 0; } .splitcontentleft{float:left; width:49%;} .splitcontentright{float:right; width:49%;} @@ -163,6 +176,7 @@ li p {margin-top: 0;} div.issue {background:#ffffdd; padding:6px; margin-bottom:6px;border: 1px solid #d7d7d7;} p.breadcrumb { font-size: 0.9em; margin: 4px 0 4px 0;} p.subtitle { font-size: 0.9em; margin: -6px 0 12px 0; font-style: italic; } +p.footnote { font-size: 0.9em; margin-top: 0px; margin-bottom: 0px; } fieldset#filters, fieldset#date-range { padding: 0.7em; margin-bottom: 8px; } fieldset#filters p { margin: 1.2em 0 0.8em 2px; } @@ -184,9 +198,10 @@ div#activity dt.me .time { border-bottom: 1px solid #999; } div#activity dt .time { color: #777; font-size: 80%; } div#activity dd .description, #search-results dd .description { font-style: italic; } div#activity span.project:after, #search-results span.project:after { content: " -"; } -div#activity dd span.description, #search-results dd span.description { display:block; } +div#activity dd span.description, #search-results dd span.description { display:block; color: #808080; } #search-results dd { margin-bottom: 1em; padding-left: 20px; margin-left:0px; } + div#search-results-counts {float:right;} div#search-results-counts ul { margin-top: 0.5em; } div#search-results-counts li { list-style-type:none; float: left; margin-left: 1em; } @@ -204,6 +219,8 @@ dt.attachment { background-image: url(../images/attachment.png); } dt.document { background-image: url(../images/document.png); } dt.project { background-image: url(../images/projects.png); } +#search-results dt.issue.closed { background-image: url(../images/ticket_checked.png); } + div#roadmap fieldset.related-issues { margin-bottom: 1em; } div#roadmap fieldset.related-issues ul { margin-top: 0.3em; margin-bottom: 0.3em; } div#roadmap .wiki h1:first-child { display: none; } @@ -220,6 +237,22 @@ table#time-report tbody tr.last-level { font-style: normal; color: #555; } table#time-report tbody tr.total { font-style: normal; font-weight: bold; color: #555; background-color:#EEEEEE; } table#time-report .hours-dec { font-size: 0.9em; } +form#issue-form .attributes { margin-bottom: 8px; } +form#issue-form .attributes p { padding-top: 1px; padding-bottom: 2px; } +form#issue-form .attributes select { min-width: 30%; } + +ul.projects { margin: 0; padding-left: 1em; } +ul.projects.root { margin: 0; padding: 0; } +ul.projects ul { border-left: 3px solid #e0e0e0; } +ul.projects li { list-style-type:none; } +ul.projects li.root { margin-bottom: 1em; } +ul.projects li.child { margin-top: 1em;} +ul.projects div.root a.project { font-family: "Trebuchet MS", Verdana, sans-serif; font-weight: bold; font-size: 16px; margin: 0 0 10px 0; } +.my-project { padding-left: 18px; background: url(../images/fav.png) no-repeat 0 50%; } + +#tracker_project_ids ul { margin: 0; padding-left: 1em; } +#tracker_project_ids li { list-style-type:none; } + ul.properties {padding:0; font-size: 0.9em; color: #777;} ul.properties li {list-style-type:none;} ul.properties li span {font-style:italic;} @@ -257,7 +290,7 @@ margin*/ font-weight: normal; margin-left: 0px; text-align: left; -width: 200px; +width: 270px; } input#time_entry_comments { width: 90%;} @@ -272,6 +305,7 @@ input#time_entry_comments { width: 90%;} #attachments_fields input[type=text] {margin-left: 8px; } +div.attachments { margin-top: 12px; } div.attachments p { margin:4px 0 2px 0; } div.attachments img { vertical-align: middle; } div.attachments span.author { font-size: 0.9em; color: #888; } @@ -279,7 +313,7 @@ div.attachments span.author { font-size: 0.9em; color: #888; } p.other-formats { text-align: right; font-size:0.9em; color: #666; } .other-formats span + span:before { content: "| "; } -a.feed { background: url(../images/feed.png) no-repeat 1px 50%; padding: 2px 0px 3px 16px; } +a.atom { background: url(../images/feed.png) no-repeat 1px 50%; padding: 2px 0px 3px 16px; } /***** Flash & error messages ****/ #errorExplanation, div.flash, .nodata, .warning { @@ -305,6 +339,14 @@ div.flash.notice { color: #005f00; } +div.flash.warning { + background: url(../images/warning.png) 8px 5px no-repeat; + background-color: #FFEBC1; + border-color: #FDBF3B; + color: #A6750C; + text-align: left; +} + .nodata, .warning { text-align: center; background-color: #FFEBC1; @@ -587,6 +629,7 @@ vertical-align: middle; .icon-index { background-image: url(../images/index.png); } .icon-history { background-image: url(../images/history.png); } .icon-time { background-image: url(../images/time.png); } +.icon-time-add { background-image: url(../images/time_add.png); } .icon-stats { background-image: url(../images/stats.png); } .icon-warning { background-image: url(../images/warning.png); } .icon-fav { background-image: url(../images/fav.png); } @@ -613,9 +656,53 @@ vertical-align: middle; .icon22-settings { background-image: url(../images/22x22/settings.png); } .icon22-plugin { background-image: url(../images/22x22/plugin.png); } +img.gravatar { + padding: 2px; + border: solid 1px #d5d5d5; + background: #fff; +} + +div.issue img.gravatar { + float: right; + margin: 0 0 0 1em; + padding: 5px; +} + +div.issue table img.gravatar { + height: 14px; + width: 14px; + padding: 2px; + float: left; + margin: 0 0.5em 0 0; +} + +#history img.gravatar { + padding: 3px; + margin: 0 1.5em 1em 0; + float: left; +} + +td.username img.gravatar { + float: left; + margin: 0 1em 0 0; +} + +#activity dt img.gravatar { + float: left; + margin: 0 1em 1em 0; +} + +#activity dt, +.journal { + clear: left; +} + +h2 img { vertical-align:middle; } + + /***** Media print specific styles *****/ @media print { #top-menu, #header, #main-menu, #sidebar, #footer, .contextual, .other-formats { display:none; } #main { background: #fff; } - #content { width: 99%; margin: 0; padding: 0; border: 0; background: #fff; } + #content { width: 99%; margin: 0; padding: 0; border: 0; background: #fff; overflow: visible !important;} } diff --git a/public/themes/classic/stylesheets/application.css b/public/themes/classic/stylesheets/application.css index 57f911da6..280b86edd 100644 --- a/public/themes/classic/stylesheets/application.css +++ b/public/themes/classic/stylesheets/application.css @@ -26,7 +26,7 @@ h2, h3, h4, .wiki h1, .wiki h2, .wiki h3 { border-bottom: 0px; color:#606060; fo h2, .wiki h1 { letter-spacing:-1px; } h4 { border-bottom: dotted 1px #c0c0c0; } -#top-menu a.home, #top-menu a.mypage, #top-menu a.projects, #top-menu a.admin, #top-menu a.help { +#top-menu a.home, #top-menu a.my-page, #top-menu a.projects, #top-menu a.administration, #top-menu a.help { background-position: 0% 40%; background-repeat: no-repeat; padding-left: 20px; @@ -35,7 +35,7 @@ h4 { border-bottom: dotted 1px #c0c0c0; } } #top-menu a.home { background-image: url(../../../images/home.png); } -#top-menu a.mypage { background-image: url(../../../images/user_page.png); } +#top-menu a.my-page { background-image: url(../../../images/user_page.png); } #top-menu a.projects { background-image: url(../../../images/projects.png); } -#top-menu a.admin { background-image: url(../../../images/admin.png); } +#top-menu a.administration { background-image: url(../../../images/admin.png); } #top-menu a.help { background-image: url(../../../images/help.png); } diff --git a/test/fixtures/attachments.yml b/test/fixtures/attachments.yml index ec57aa6dd..2497bd9a3 100644 --- a/test/fixtures/attachments.yml +++ b/test/fixtures/attachments.yml @@ -85,4 +85,28 @@ attachments_007: filename: archive.zip author_id: 1 content_type: application/octet-stream +attachments_008: + created_on: 2006-07-19 21:07:27 +02:00 + container_type: Project + container_id: 1 + downloads: 0 + disk_filename: 060719210727_project_file.zip + digest: b91e08d0cf966d5c6ff411bd8c4cc3a2 + id: 8 + filesize: 320 + filename: project_file.zip + author_id: 2 + content_type: application/octet-stream +attachments_009: + created_on: 2006-07-19 21:07:27 +02:00 + container_type: Version + container_id: 1 + downloads: 0 + disk_filename: 060719210727_version_file.zip + digest: b91e08d0cf966d5c6ff411bd8c4cc3a2 + id: 9 + filesize: 452 + filename: version_file.zip + author_id: 2 + content_type: application/octet-stream \ No newline at end of file diff --git a/test/fixtures/changesets.yml b/test/fixtures/changesets.yml index 3b47eecd8..cbc00eb83 100644 --- a/test/fixtures/changesets.yml +++ b/test/fixtures/changesets.yml @@ -7,6 +7,7 @@ changesets_001: comments: My very first commit repository_id: 10 committer: dlopper + user_id: 3 changesets_002: commit_date: 2007-04-12 committed_on: 2007-04-12 15:14:44 +02:00 @@ -15,6 +16,7 @@ changesets_002: comments: 'This commit fixes #1, #2 and references #1 & #3' repository_id: 10 committer: dlopper + user_id: 3 changesets_003: commit_date: 2007-04-12 committed_on: 2007-04-12 15:14:44 +02:00 @@ -25,6 +27,7 @@ changesets_003: IssueID 666 3 repository_id: 10 committer: dlopper + user_id: 3 changesets_004: commit_date: 2007-04-12 committed_on: 2007-04-12 15:14:44 +02:00 @@ -35,4 +38,5 @@ changesets_004: IssueID 4 2 repository_id: 10 committer: dlopper + user_id: 3 \ No newline at end of file diff --git a/test/fixtures/custom_fields.yml b/test/fixtures/custom_fields.yml index 1005edae4..a17827473 100644 --- a/test/fixtures/custom_fields.yml +++ b/test/fixtures/custom_fields.yml @@ -15,6 +15,7 @@ custom_fields_001: is_required: false field_format: list default_value: "" + editable: true custom_fields_002: name: Searchable field min_length: 1 @@ -28,6 +29,7 @@ custom_fields_002: field_format: string searchable: true default_value: "Default string" + editable: true custom_fields_003: name: Development status min_length: 0 @@ -45,6 +47,7 @@ custom_fields_003: is_required: true field_format: list default_value: "" + editable: true custom_fields_004: name: Phone number min_length: 0 @@ -57,6 +60,7 @@ custom_fields_004: is_required: false field_format: string default_value: "" + editable: true custom_fields_005: name: Money min_length: 0 @@ -69,4 +73,18 @@ custom_fields_005: is_required: false field_format: float default_value: "" + editable: true +custom_fields_006: + name: Float field + min_length: 0 + regexp: "" + is_for_all: true + type: IssueCustomField + max_length: 0 + possible_values: "" + id: 6 + is_required: false + field_format: float + default_value: "" + editable: true \ No newline at end of file diff --git a/test/fixtures/custom_fields_trackers.yml b/test/fixtures/custom_fields_trackers.yml index cb06d2fcf..bfbe0d24c 100644 --- a/test/fixtures/custom_fields_trackers.yml +++ b/test/fixtures/custom_fields_trackers.yml @@ -8,3 +8,12 @@ custom_fields_trackers_002: custom_fields_trackers_003: custom_field_id: 2 tracker_id: 3 +custom_fields_trackers_004: + custom_field_id: 6 + tracker_id: 1 +custom_fields_trackers_005: + custom_field_id: 6 + tracker_id: 2 +custom_fields_trackers_006: + custom_field_id: 6 + tracker_id: 3 diff --git a/test/fixtures/custom_values.yml b/test/fixtures/custom_values.yml index 572142889..0e2b454ab 100644 --- a/test/fixtures/custom_values.yml +++ b/test/fixtures/custom_values.yml @@ -3,54 +3,84 @@ custom_values_006: customized_type: Issue custom_field_id: 2 customized_id: 3 - id: 9 + id: 6 value: "125" custom_values_007: customized_type: Project custom_field_id: 3 customized_id: 1 - id: 10 + id: 7 value: Stable custom_values_001: customized_type: User custom_field_id: 4 customized_id: 3 - id: 2 + id: 1 value: "" custom_values_002: customized_type: User custom_field_id: 4 customized_id: 4 - id: 3 + id: 2 value: 01 23 45 67 89 custom_values_003: customized_type: User custom_field_id: 4 customized_id: 2 - id: 4 + id: 3 value: "" custom_values_004: customized_type: Issue custom_field_id: 2 customized_id: 1 - id: 7 + id: 4 value: "125" custom_values_005: customized_type: Issue custom_field_id: 2 customized_id: 2 - id: 8 + id: 5 value: "" custom_values_008: customized_type: Issue custom_field_id: 1 customized_id: 3 - id: 11 + id: 8 value: "MySQL" custom_values_009: customized_type: Issue custom_field_id: 2 customized_id: 3 - id: 12 + id: 9 value: "this is a stringforcustomfield search" +custom_values_010: + customized_type: Issue + custom_field_id: 6 + customized_id: 1 + id: 10 + value: "2.1" +custom_values_011: + customized_type: Issue + custom_field_id: 6 + customized_id: 2 + id: 11 + value: "2.05" +custom_values_012: + customized_type: Issue + custom_field_id: 6 + customized_id: 3 + id: 12 + value: "11.65" +custom_values_013: + customized_type: Issue + custom_field_id: 6 + customized_id: 7 + id: 13 + value: "" +custom_values_014: + customized_type: Issue + custom_field_id: 6 + customized_id: 5 + id: 14 + value: "-7.6" \ No newline at end of file diff --git a/test/fixtures/diffs/subversion.diff b/test/fixtures/diffs/subversion.diff new file mode 100644 index 000000000..9b6c9d086 --- /dev/null +++ b/test/fixtures/diffs/subversion.diff @@ -0,0 +1,79 @@ +Index: app/views/settings/_general.rhtml +=================================================================== +--- app/views/settings/_general.rhtml (revision 2094) ++++ app/views/settings/_general.rhtml (working copy) +@@ -48,6 +48,9 @@ +

    + <%= text_field_tag 'settings[feeds_limit]', Setting.feeds_limit, :size => 6 %>

    + ++

    ++<%= text_field_tag 'settings[diff_max_lines_displayed]', Setting.diff_max_lines_displayed, :size => 6 %>

    ++ +

    + <%= check_box_tag 'settings[gravatar_enabled]', 1, Setting.gravatar_enabled? %><%= hidden_field_tag 'settings[gravatar_enabled]', 0 %>

    +
    +Index: app/views/common/_diff.rhtml +=================================================================== +--- app/views/common/_diff.rhtml (revision 2111) ++++ app/views/common/_diff.rhtml (working copy) +@@ -1,4 +1,5 @@ +-<% Redmine::UnifiedDiff.new(diff, :type => diff_type).each do |table_file| -%> ++<% diff = Redmine::UnifiedDiff.new(diff, :type => diff_type, :max_lines => Setting.diff_max_lines_displayed.to_i) -%> ++<% diff.each do |table_file| -%> +
    + <% if diff_type == 'sbs' -%> + +@@ -62,3 +63,5 @@ + + + <% end -%> ++ ++<%= l(:text_diff_truncated) if diff.truncated? %> +Index: lang/lt.yml +=================================================================== +--- config/settings.yml (revision 2094) ++++ config/settings.yml (working copy) +@@ -61,6 +61,9 @@ + feeds_limit: + format: int + default: 15 ++diff_max_lines_displayed: ++ format: int ++ default: 1500 + enabled_scm: + serialized: true + default: +Index: lib/redmine/unified_diff.rb +=================================================================== +--- lib/redmine/unified_diff.rb (revision 2110) ++++ lib/redmine/unified_diff.rb (working copy) +@@ -19,8 +19,11 @@ + # Class used to parse unified diffs + class UnifiedDiff < Array + def initialize(diff, options={}) ++ options.assert_valid_keys(:type, :max_lines) + diff_type = options[:type] || 'inline' + ++ lines = 0 ++ @truncated = false + diff_table = DiffTable.new(diff_type) + diff.each do |line| + if line =~ /^(---|\+\+\+) (.*)$/ +@@ -28,10 +31,17 @@ + diff_table = DiffTable.new(diff_type) + end + diff_table.add_line line ++ lines += 1 ++ if options[:max_lines] && lines > options[:max_lines] ++ @truncated = true ++ break ++ end + end + self << diff_table unless diff_table.empty? + self + end ++ ++ def truncated?; @truncated; end + end + + # Class that represents a file diff diff --git a/test/fixtures/enabled_modules.yml b/test/fixtures/enabled_modules.yml index da63bad5d..6639dfa1a 100644 --- a/test/fixtures/enabled_modules.yml +++ b/test/fixtures/enabled_modules.yml @@ -43,4 +43,16 @@ enabled_modules_011: name: issue_tracking project_id: 2 id: 11 +enabled_modules_012: + name: time_tracking + project_id: 3 + id: 12 +enabled_modules_013: + name: issue_tracking + project_id: 3 + id: 13 +enabled_modules_014: + name: issue_tracking + project_id: 5 + id: 14 \ No newline at end of file diff --git a/test/fixtures/files/testfile.txt b/test/fixtures/files/testfile.txt index 4b2a49c69..84f601ee6 100644 --- a/test/fixtures/files/testfile.txt +++ b/test/fixtures/files/testfile.txt @@ -1 +1,2 @@ -this is a text file for upload tests \ No newline at end of file +this is a text file for upload tests +with multiple lines diff --git a/test/fixtures/issues.yml b/test/fixtures/issues.yml index 9d3287c6f..921ba40c4 100644 --- a/test/fixtures/issues.yml +++ b/test/fixtures/issues.yml @@ -91,4 +91,38 @@ issues_006: status_id: 1 start_date: <%= Date.today.to_s(:db) %> due_date: <%= 1.days.from_now.to_date.to_s(:db) %> +issues_007: + created_on: <%= 10.days.ago.to_date.to_s(:db) %> + project_id: 1 + updated_on: <%= 10.days.ago.to_date.to_s(:db) %> + priority_id: 3 + subject: Issue due today + id: 7 + fixed_version_id: + category_id: + description: This is an issue that is due today + tracker_id: 1 + assigned_to_id: + author_id: 2 + status_id: 1 + start_date: <%= 10.days.ago.to_s(:db) %> + due_date: <%= Date.today.to_s(:db) %> + lock_version: 0 +issues_008: + created_on: <%= 10.days.ago.to_date.to_s(:db) %> + project_id: 1 + updated_on: <%= 10.days.ago.to_date.to_s(:db) %> + priority_id: 3 + subject: Closed issue + id: 8 + fixed_version_id: + category_id: + description: This is a closed issue. + tracker_id: 1 + assigned_to_id: + author_id: 2 + status_id: 5 + start_date: + due_date: + lock_version: 0 \ No newline at end of file diff --git a/test/fixtures/mail_handler/message_reply.eml b/test/fixtures/mail_handler/message_reply.eml new file mode 100644 index 000000000..a2ef8ee14 --- /dev/null +++ b/test/fixtures/mail_handler/message_reply.eml @@ -0,0 +1,15 @@ +Message-ID: <4974C93E.3070005@somenet.foo> +Date: Mon, 19 Jan 2009 19:41:02 +0100 +From: "John Smith" +User-Agent: Thunderbird 2.0.0.19 (Windows/20081209) +MIME-Version: 1.0 +To: redmine@somenet.foo +Subject: Reply via email +References: +In-Reply-To: +Content-Type: text/plain; charset=UTF-8; format=flowed +Content-Transfer-Encoding: 7bit + +This is a reply to a forum message. + + diff --git a/test/fixtures/mail_handler/message_reply_by_subject.eml b/test/fixtures/mail_handler/message_reply_by_subject.eml new file mode 100644 index 000000000..985aaa0e4 --- /dev/null +++ b/test/fixtures/mail_handler/message_reply_by_subject.eml @@ -0,0 +1,13 @@ +Message-ID: <4974C93E.3070005@somenet.foo> +Date: Mon, 19 Jan 2009 19:41:02 +0100 +From: "John Smith" +User-Agent: Thunderbird 2.0.0.19 (Windows/20081209) +MIME-Version: 1.0 +To: redmine@somenet.foo +Subject: Re: [eCookbook - Help board - msg2] Reply to the first post +Content-Type: text/plain; charset=UTF-8; format=flowed +Content-Transfer-Encoding: 7bit + +This is a reply to a forum message. + + diff --git a/test/fixtures/mail_handler/ticket_html_only.eml b/test/fixtures/mail_handler/ticket_html_only.eml new file mode 100644 index 000000000..511e5f107 --- /dev/null +++ b/test/fixtures/mail_handler/ticket_html_only.eml @@ -0,0 +1,22 @@ +x-sender: +x-receiver: +Received: from [127.0.0.1] ([127.0.0.1]) by somenet.foo with Quick 'n Easy Mail Server SMTP (1.0.0.0); + Sun, 14 Dec 2008 16:18:06 GMT +Message-ID: <494531B9.1070709@somenet.foo> +Date: Sun, 14 Dec 2008 17:18:01 +0100 +From: "John Smith" +User-Agent: Thunderbird 2.0.0.18 (Windows/20081105) +MIME-Version: 1.0 +To: redmine@somenet.foo +Subject: HTML email +Content-Type: text/html; charset=ISO-8859-1 +Content-Transfer-Encoding: 7bit + + + + + + +This is a html-only email.
    + + diff --git a/test/fixtures/mail_handler/ticket_on_given_project.eml b/test/fixtures/mail_handler/ticket_on_given_project.eml index 927dbc63e..5dbd0dc2e 100644 --- a/test/fixtures/mail_handler/ticket_on_given_project.eml +++ b/test/fixtures/mail_handler/ticket_on_given_project.eml @@ -1,9 +1,9 @@ -Return-Path: +Return-Path: Received: from osiris ([127.0.0.1]) by OSIRIS with hMailServer ; Sun, 22 Jun 2008 12:28:07 +0200 Message-ID: <000501c8d452$a95cd7e0$0a00a8c0@osiris> -From: "John Smith" +From: "John Smith" To: Subject: New ticket on a given project Date: Sun, 22 Jun 2008 12:28:07 +0200 diff --git a/test/fixtures/mail_handler/ticket_reply.eml b/test/fixtures/mail_handler/ticket_reply.eml index 99fcfa0d1..74724ccf4 100644 --- a/test/fixtures/mail_handler/ticket_reply.eml +++ b/test/fixtures/mail_handler/ticket_reply.eml @@ -3,10 +3,11 @@ Received: from osiris ([127.0.0.1]) by OSIRIS with hMailServer ; Sat, 21 Jun 2008 18:41:39 +0200 Message-ID: <006a01c8d3bd$ad9baec0$0a00a8c0@osiris> +In-Reply-To: From: "John Smith" To: References: <485d0ad366c88_d7014663a025f@osiris.tmail> -Subject: Re: [Cookbook - Feature #2] (New) Add ingredients categories +Subject: Re: Add ingredients categories Date: Sat, 21 Jun 2008 18:41:39 +0200 MIME-Version: 1.0 Content-Type: multipart/alternative; diff --git a/test/fixtures/mail_handler/ticket_with_cc.eml b/test/fixtures/mail_handler/ticket_with_cc.eml new file mode 100644 index 000000000..f809fed77 --- /dev/null +++ b/test/fixtures/mail_handler/ticket_with_cc.eml @@ -0,0 +1,40 @@ +Return-Path: +Received: from osiris ([127.0.0.1]) + by OSIRIS + with hMailServer ; Sun, 22 Jun 2008 12:28:07 +0200 +Message-ID: <000501c8d452$a95cd7e0$0a00a8c0@osiris> +From: "John Smith" +To: +Cc: +Subject: New ticket on a given project +Date: Sun, 22 Jun 2008 12:28:07 +0200 +MIME-Version: 1.0 +Content-Type: text/plain; + format=flowed; + charset="iso-8859-1"; + reply-type=original +Content-Transfer-Encoding: 7bit +X-Priority: 3 +X-MSMail-Priority: Normal +X-Mailer: Microsoft Outlook Express 6.00.2900.2869 +X-MimeOLE: Produced By Microsoft MimeOLE V6.00.2900.2869 + +Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Maecenas imperdiet +turpis et odio. Integer eget pede vel dolor euismod varius. Phasellus +blandit eleifend augue. Nulla facilisi. Duis id diam. Class aptent taciti +sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. In +in urna sed tellus aliquet lobortis. Morbi scelerisque tortor in dolor. Cras +sagittis odio eu lacus. Aliquam sem tortor, consequat sit amet, vestibulum +id, iaculis at, lectus. Fusce tortor libero, congue ut, euismod nec, luctus +eget, eros. Pellentesque tortor enim, feugiat in, dignissim eget, tristique +sed, mauris. Pellentesque habitant morbi tristique senectus et netus et +malesuada fames ac turpis egestas. Quisque sit amet libero. In hac habitasse +platea dictumst. + +Nulla et nunc. Duis pede. Donec et ipsum. Nam ut dui tincidunt neque +sollicitudin iaculis. Duis vitae dolor. Vestibulum eget massa. Sed lorem. +Nullam volutpat cursus erat. Cras felis dolor, lacinia quis, rutrum et, +dictum et, ligula. Sed erat nibh, gravida in, accumsan non, placerat sed, +massa. Sed sodales, ante fermentum ultricies sollicitudin, massa leo +pulvinar dui, a gravida orci mi eget odio. Nunc a lacus. + diff --git a/test/fixtures/mail_handler/ticket_with_custom_fields.eml b/test/fixtures/mail_handler/ticket_with_custom_fields.eml new file mode 100644 index 000000000..f3798a4b6 --- /dev/null +++ b/test/fixtures/mail_handler/ticket_with_custom_fields.eml @@ -0,0 +1,41 @@ +Return-Path: +Received: from osiris ([127.0.0.1]) + by OSIRIS + with hMailServer ; Sun, 22 Jun 2008 12:28:07 +0200 +Message-ID: <000501c8d452$a95cd7e0$0a00a8c0@osiris> +From: "John Smith" +To: +Subject: New ticket with custom field values +Date: Sun, 22 Jun 2008 12:28:07 +0200 +MIME-Version: 1.0 +Content-Type: text/plain; + format=flowed; + charset="iso-8859-1"; + reply-type=original +Content-Transfer-Encoding: 7bit +X-Priority: 3 +X-MSMail-Priority: Normal +X-Mailer: Microsoft Outlook Express 6.00.2900.2869 +X-MimeOLE: Produced By Microsoft MimeOLE V6.00.2900.2869 + +Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Maecenas imperdiet +turpis et odio. Integer eget pede vel dolor euismod varius. Phasellus +blandit eleifend augue. Nulla facilisi. Duis id diam. Class aptent taciti +sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. In +in urna sed tellus aliquet lobortis. Morbi scelerisque tortor in dolor. Cras +sagittis odio eu lacus. Aliquam sem tortor, consequat sit amet, vestibulum +id, iaculis at, lectus. Fusce tortor libero, congue ut, euismod nec, luctus +eget, eros. Pellentesque tortor enim, feugiat in, dignissim eget, tristique +sed, mauris. Pellentesque habitant morbi tristique senectus et netus et +malesuada fames ac turpis egestas. Quisque sit amet libero. In hac habitasse +platea dictumst. + +Nulla et nunc. Duis pede. Donec et ipsum. Nam ut dui tincidunt neque +sollicitudin iaculis. Duis vitae dolor. Vestibulum eget massa. Sed lorem. +Nullam volutpat cursus erat. Cras felis dolor, lacinia quis, rutrum et, +dictum et, ligula. Sed erat nibh, gravida in, accumsan non, placerat sed, +massa. Sed sodales, ante fermentum ultricies sollicitudin, massa leo +pulvinar dui, a gravida orci mi eget odio. Nunc a lacus. + +category: Stock management +searchable field: Value for a custom field diff --git a/test/fixtures/members.yml b/test/fixtures/members.yml index 32c65c673..4156bb867 100644 --- a/test/fixtures/members.yml +++ b/test/fixtures/members.yml @@ -5,18 +5,21 @@ members_001: role_id: 1 id: 1 user_id: 2 + mail_notification: true members_002: created_on: 2006-07-19 19:35:36 +02:00 project_id: 1 role_id: 2 id: 2 user_id: 3 + mail_notification: true members_003: created_on: 2006-07-19 19:35:36 +02:00 project_id: 2 role_id: 2 id: 3 user_id: 2 + mail_notification: true members_004: id: 4 created_on: 2006-07-19 19:35:36 +02:00 @@ -24,10 +27,12 @@ members_004: role_id: 2 # Locked user user_id: 5 + mail_notification: true members_005: id: 5 created_on: 2006-07-19 19:35:33 +02:00 project_id: 5 role_id: 1 user_id: 2 + mail_notification: true \ No newline at end of file diff --git a/test/fixtures/messages.yml b/test/fixtures/messages.yml index f82f376c1..8ed376eb2 100644 --- a/test/fixtures/messages.yml +++ b/test/fixtures/messages.yml @@ -30,7 +30,7 @@ messages_003: replies_count: 0 last_reply_id: content: "An other reply" - author_id: + author_id: 2 parent_id: 1 board_id: 1 messages_004: @@ -38,8 +38,8 @@ messages_004: updated_on: 2007-08-12 17:15:32 +02:00 subject: Post 2 id: 4 - replies_count: 1 - last_reply_id: 5 + replies_count: 2 + last_reply_id: 6 content: "This is an other post" author_id: parent_id: @@ -55,3 +55,14 @@ messages_005: author_id: 1 parent_id: 4 board_id: 1 +messages_006: + created_on: <%= 2.days.ago.to_date.to_s(:db) %> + updated_on: <%= 2.days.ago.to_date.to_s(:db) %> + subject: 'RE: post 2' + id: 6 + replies_count: 0 + last_reply_id: + content: "Another reply to the second post" + author_id: 3 + parent_id: 4 + board_id: 1 diff --git a/test/fixtures/projects.yml b/test/fixtures/projects.yml index 8e1b3fe1d..de692af0d 100644 --- a/test/fixtures/projects.yml +++ b/test/fixtures/projects.yml @@ -3,55 +3,72 @@ projects_001: created_on: 2006-07-19 19:13:59 +02:00 name: eCookbook updated_on: 2006-07-19 22:53:01 +02:00 - projects_count: 3 id: 1 description: Recipes management application homepage: http://ecookbook.somenet.foo/ is_public: true identifier: ecookbook parent_id: + lft: 1 + rgt: 10 projects_002: created_on: 2006-07-19 19:14:19 +02:00 name: OnlineStore updated_on: 2006-07-19 19:14:19 +02:00 - projects_count: 0 id: 2 description: E-commerce web site homepage: "" is_public: false identifier: onlinestore parent_id: + lft: 11 + rgt: 12 projects_003: created_on: 2006-07-19 19:15:21 +02:00 name: eCookbook Subproject 1 updated_on: 2006-07-19 19:18:12 +02:00 - projects_count: 0 id: 3 description: eCookBook Subproject 1 homepage: "" is_public: true identifier: subproject1 parent_id: 1 + lft: 6 + rgt: 7 projects_004: created_on: 2006-07-19 19:15:51 +02:00 name: eCookbook Subproject 2 updated_on: 2006-07-19 19:17:07 +02:00 - projects_count: 0 id: 4 description: eCookbook Subproject 2 homepage: "" is_public: true identifier: subproject2 parent_id: 1 + lft: 8 + rgt: 9 projects_005: created_on: 2006-07-19 19:15:51 +02:00 name: Private child of eCookbook updated_on: 2006-07-19 19:17:07 +02:00 - projects_count: 0 id: 5 description: This is a private subproject of a public project homepage: "" is_public: false - identifier: private_child + identifier: private-child parent_id: 1 + lft: 2 + rgt: 5 +projects_006: + created_on: 2006-07-19 19:15:51 +02:00 + name: Child of private child + updated_on: 2006-07-19 19:17:07 +02:00 + id: 6 + description: This is a public subproject of a private project + homepage: "" + is_public: true + identifier: project6 + parent_id: 5 + lft: 3 + rgt: 4 \ No newline at end of file diff --git a/test/fixtures/projects_trackers.yml b/test/fixtures/projects_trackers.yml index 31f7f943a..4766a9f82 100644 --- a/test/fixtures/projects_trackers.yml +++ b/test/fixtures/projects_trackers.yml @@ -1,44 +1,44 @@ --- -projects_trackers_012: +projects_trackers_001: project_id: 4 tracker_id: 3 -projects_trackers_001: +projects_trackers_002: project_id: 1 tracker_id: 1 -projects_trackers_013: +projects_trackers_003: project_id: 5 tracker_id: 1 -projects_trackers_002: +projects_trackers_004: project_id: 1 tracker_id: 2 -projects_trackers_014: +projects_trackers_005: project_id: 5 tracker_id: 2 -projects_trackers_015: +projects_trackers_006: project_id: 5 tracker_id: 3 -projects_trackers_004: +projects_trackers_007: project_id: 2 tracker_id: 1 -projects_trackers_005: +projects_trackers_008: project_id: 2 tracker_id: 2 -projects_trackers_006: +projects_trackers_009: project_id: 2 tracker_id: 3 -projects_trackers_008: +projects_trackers_010: project_id: 3 tracker_id: 2 -projects_trackers_009: +projects_trackers_011: project_id: 3 tracker_id: 3 -projects_trackers_010: +projects_trackers_012: project_id: 4 tracker_id: 1 -projects_trackers_011: +projects_trackers_013: project_id: 4 tracker_id: 2 -projects_trackers_012: +projects_trackers_014: project_id: 1 tracker_id: 3 \ No newline at end of file diff --git a/test/fixtures/roles.yml b/test/fixtures/roles.yml index 74cba2706..d8ae2c819 100644 --- a/test/fixtures/roles.yml +++ b/test/fixtures/roles.yml @@ -32,6 +32,7 @@ roles_001: - :view_wiki_pages - :view_wiki_edits - :edit_wiki_pages + - :delete_wiki_pages_attachments - :protect_wiki_pages - :delete_wiki_pages - :rename_wiki_pages @@ -42,6 +43,7 @@ roles_001: - :view_files - :manage_files - :browse_repository + - :manage_repository - :view_changesets position: 1 @@ -78,6 +80,8 @@ roles_002: - :protect_wiki_pages - :delete_wiki_pages - :add_messages + - :edit_own_messages + - :delete_own_messages - :manage_boards - :view_files - :manage_files diff --git a/test/fixtures/watchers.yml b/test/fixtures/watchers.yml index 6c8cdfb5e..803b03e5e 100644 --- a/test/fixtures/watchers.yml +++ b/test/fixtures/watchers.yml @@ -7,4 +7,8 @@ watchers_002: watchable_type: Message watchable_id: 1 user_id: 1 +watchers_003: + watchable_type: Issue + watchable_id: 2 + user_id: 1 \ No newline at end of file diff --git a/test/fixtures/wiki_contents.yml b/test/fixtures/wiki_contents.yml index 8c53d4d97..8798ff229 100644 --- a/test/fixtures/wiki_contents.yml +++ b/test/fixtures/wiki_contents.yml @@ -47,4 +47,26 @@ wiki_contents_004: version: 1 author_id: 1 comments: +wiki_contents_005: + text: |- + h1. Child page 1 + + This is a child page + updated_on: 2007-03-08 00:18:07 +01:00 + page_id: 5 + id: 5 + version: 1 + author_id: 1 + comments: +wiki_contents_006: + text: |- + h1. Child page 2 + + This is a child page + updated_on: 2007-03-08 00:18:07 +01:00 + page_id: 6 + id: 6 + version: 1 + author_id: 1 + comments: \ No newline at end of file diff --git a/test/fixtures/wiki_pages.yml b/test/fixtures/wiki_pages.yml index e285441ff..8d29c2f72 100644 --- a/test/fixtures/wiki_pages.yml +++ b/test/fixtures/wiki_pages.yml @@ -27,4 +27,18 @@ wiki_pages_004: wiki_id: 1 protected: false parent_id: 1 +wiki_pages_005: + created_on: 2007-03-08 00:18:07 +01:00 + title: Child_1 + id: 5 + wiki_id: 1 + protected: false + parent_id: 2 +wiki_pages_006: + created_on: 2007-03-08 00:18:07 +01:00 + title: Child_2 + id: 6 + wiki_id: 1 + protected: false + parent_id: 2 \ No newline at end of file diff --git a/test/functional/account_controller_test.rb b/test/functional/account_controller_test.rb index a6e379991..c5a78dad2 100644 --- a/test/functional/account_controller_test.rb +++ b/test/functional/account_controller_test.rb @@ -22,7 +22,7 @@ require 'account_controller' class AccountController; def rescue_action(e) raise e end; end class AccountControllerTest < Test::Unit::TestCase - fixtures :users + fixtures :users, :roles def setup @controller = AccountController.new @@ -64,6 +64,83 @@ class AccountControllerTest < Test::Unit::TestCase :content => /Invalid user or password/ end + if Object.const_defined?(:OpenID) + + def test_login_with_openid_for_existing_user + Setting.self_registration = '3' + Setting.openid = '1' + existing_user = User.new(:firstname => 'Cool', + :lastname => 'User', + :mail => 'user@somedomain.com', + :identity_url => 'http://openid.example.com/good_user') + existing_user.login = 'cool_user' + assert existing_user.save! + + post :login, :openid_url => existing_user.identity_url + assert_redirected_to 'my/page' + end + + def test_login_with_openid_with_new_user_created + Setting.self_registration = '3' + Setting.openid = '1' + post :login, :openid_url => 'http://openid.example.com/good_user' + assert_redirected_to 'my/account' + user = User.find_by_login('cool_user') + assert user + assert_equal 'Cool', user.firstname + assert_equal 'User', user.lastname + end + + def test_login_with_openid_with_new_user_and_self_registration_off + Setting.self_registration = '0' + Setting.openid = '1' + post :login, :openid_url => 'http://openid.example.com/good_user' + assert_redirected_to home_url + user = User.find_by_login('cool_user') + assert ! user + end + + def test_login_with_openid_with_new_user_created_with_email_activation_should_have_a_token + Setting.self_registration = '1' + Setting.openid = '1' + post :login, :openid_url => 'http://openid.example.com/good_user' + assert_redirected_to 'login' + user = User.find_by_login('cool_user') + assert user + + token = Token.find_by_user_id_and_action(user.id, 'register') + assert token + end + + def test_login_with_openid_with_new_user_created_with_manual_activation + Setting.self_registration = '2' + Setting.openid = '1' + post :login, :openid_url => 'http://openid.example.com/good_user' + assert_redirected_to 'login' + user = User.find_by_login('cool_user') + assert user + assert_equal User::STATUS_REGISTERED, user.status + end + + def test_login_with_openid_with_new_user_with_conflict_should_register + Setting.self_registration = '3' + Setting.openid = '1' + existing_user = User.new(:firstname => 'Cool', :lastname => 'User', :mail => 'user@somedomain.com') + existing_user.login = 'cool_user' + assert existing_user.save! + + post :login, :openid_url => 'http://openid.example.com/good_user' + assert_response :success + assert_template 'register' + assert assigns(:user) + assert_equal 'http://openid.example.com/good_user', assigns(:user)[:identity_url] + end + + else + puts "Skipping openid tests." + end + + def test_autologin Setting.autologin = "7" Token.delete_all diff --git a/test/functional/admin_controller_test.rb b/test/functional/admin_controller_test.rb index 05205b399..32965de4c 100644 --- a/test/functional/admin_controller_test.rb +++ b/test/functional/admin_controller_test.rb @@ -38,6 +38,13 @@ class AdminControllerTest < Test::Unit::TestCase :attributes => { :class => /nodata/ } end + def test_projects_routing + assert_routing( + {:method => :get, :path => '/admin/projects'}, + :controller => 'admin', :action => 'projects' + ) + end + def test_index_with_no_configuration_data delete_configuration_data get :index @@ -45,6 +52,25 @@ class AdminControllerTest < Test::Unit::TestCase :attributes => { :class => /nodata/ } end + def test_projects + get :projects + assert_response :success + assert_template 'projects' + assert_not_nil assigns(:projects) + # active projects only + assert_nil assigns(:projects).detect {|u| !u.active?} + end + + def test_projects_with_name_filter + get :projects, :name => 'store', :status => '' + assert_response :success + assert_template 'projects' + projects = assigns(:projects) + assert_not_nil projects + assert_equal 1, projects.size + assert_equal 'OnlineStore', projects.first.name + end + def test_load_default_configuration_data delete_configuration_data post :default_configuration, :lang => 'fr' @@ -53,12 +79,40 @@ class AdminControllerTest < Test::Unit::TestCase def test_test_email get :test_email - assert_redirected_to 'settings/edit' + assert_redirected_to '/settings/edit?tab=notifications' mail = ActionMailer::Base.deliveries.last assert_kind_of TMail::Mail, mail user = User.find(1) assert_equal [user.mail], mail.bcc end + + def test_no_plugins + Redmine::Plugin.clear + + get :plugins + assert_response :success + assert_template 'plugins' + end + + def test_plugins + # Register a few plugins + Redmine::Plugin.register :foo do + name 'Foo plugin' + author 'John Smith' + description 'This is a test plugin' + version '0.0.1' + settings :default => {'sample_setting' => 'value', 'foo'=>'bar'}, :partial => 'foo/settings' + end + Redmine::Plugin.register :bar do + end + + get :plugins + assert_response :success + assert_template 'plugins' + + assert_tag :td, :child => { :tag => 'span', :content => 'Foo plugin' } + assert_tag :td, :child => { :tag => 'span', :content => 'Bar' } + end def test_info get :info @@ -66,6 +120,8 @@ class AdminControllerTest < Test::Unit::TestCase assert_template 'info' end + private + def delete_configuration_data Role.delete_all('builtin = 0') Tracker.delete_all diff --git a/test/functional/application_controller_test.rb b/test/functional/application_controller_test.rb index 6fcf8fe9a..7d1cc8391 100644 --- a/test/functional/application_controller_test.rb +++ b/test/functional/application_controller_test.rb @@ -37,4 +37,8 @@ class ApplicationControllerTest < Test::Unit::TestCase end set_language_if_valid('en') end + + def test_call_hook_mixed_in + assert @controller.respond_to?(:call_hook) + end end diff --git a/test/functional/attachments_controller_test.rb b/test/functional/attachments_controller_test.rb index 139896ce6..634d4279b 100644 --- a/test/functional/attachments_controller_test.rb +++ b/test/functional/attachments_controller_test.rb @@ -23,7 +23,8 @@ class AttachmentsController; def rescue_action(e) raise e end; end class AttachmentsControllerTest < Test::Unit::TestCase - fixtures :users, :projects, :roles, :members, :enabled_modules, :issues, :attachments + fixtures :users, :projects, :roles, :members, :enabled_modules, :issues, :attachments, + :versions, :wiki_pages, :wikis def setup @controller = AttachmentsController.new @@ -74,6 +75,52 @@ class AttachmentsControllerTest < Test::Unit::TestCase def test_anonymous_on_private_private get :download, :id => 7 - assert_redirected_to 'account/login' + assert_redirected_to '/login?back_url=http%3A%2F%2Ftest.host%2Fattachments%2Fdownload%2F7' + end + + def test_destroy_issue_attachment + issue = Issue.find(3) + @request.session[:user_id] = 2 + + assert_difference 'issue.attachments.count', -1 do + post :destroy, :id => 1 + end + # no referrer + assert_redirected_to 'projects/show/ecookbook' + assert_nil Attachment.find_by_id(1) + j = issue.journals.find(:first, :order => 'created_on DESC') + assert_equal 'attachment', j.details.first.property + assert_equal '1', j.details.first.prop_key + assert_equal 'error281.txt', j.details.first.old_value + end + + def test_destroy_wiki_page_attachment + @request.session[:user_id] = 2 + assert_difference 'Attachment.count', -1 do + post :destroy, :id => 3 + assert_response 302 + end + end + + def test_destroy_project_attachment + @request.session[:user_id] = 2 + assert_difference 'Attachment.count', -1 do + post :destroy, :id => 8 + assert_response 302 + end + end + + def test_destroy_version_attachment + @request.session[:user_id] = 2 + assert_difference 'Attachment.count', -1 do + post :destroy, :id => 9 + assert_response 302 + end + end + + def test_destroy_without_permission + post :destroy, :id => 3 + assert_redirected_to '/login?back_url=http%3A%2F%2Ftest.host%2Fattachments%2Fdestroy%2F3' + assert Attachment.find_by_id(3) end end diff --git a/test/functional/boards_controller_test.rb b/test/functional/boards_controller_test.rb index 3ff71bc4e..190eae237 100644 --- a/test/functional/boards_controller_test.rb +++ b/test/functional/boards_controller_test.rb @@ -31,6 +31,13 @@ class BoardsControllerTest < Test::Unit::TestCase User.current = nil end + def test_index_routing + assert_routing( + {:method => :get, :path => '/projects/world_domination/boards'}, + :controller => 'boards', :action => 'index', :project_id => 'world_domination' + ) + end + def test_index get :index, :project_id => 1 assert_response :success @@ -39,6 +46,24 @@ class BoardsControllerTest < Test::Unit::TestCase assert_not_nil assigns(:project) end + def test_new_routing + assert_routing( + {:method => :get, :path => '/projects/world_domination/boards/new'}, + :controller => 'boards', :action => 'new', :project_id => 'world_domination' + ) + assert_recognizes( + {:controller => 'boards', :action => 'new', :project_id => 'world_domination'}, + {:method => :post, :path => '/projects/world_domination/boards'} + ) + end + + def test_show_routing + assert_routing( + {:method => :get, :path => '/projects/world_domination/boards/44'}, + :controller => 'boards', :action => 'show', :id => '44', :project_id => 'world_domination' + ) + end + def test_show get :show, :project_id => 1, :id => 1 assert_response :success @@ -47,4 +72,22 @@ class BoardsControllerTest < Test::Unit::TestCase assert_not_nil assigns(:project) assert_not_nil assigns(:topics) end + + def test_edit_routing + assert_routing( + {:method => :get, :path => '/projects/world_domination/boards/44/edit'}, + :controller => 'boards', :action => 'edit', :id => '44', :project_id => 'world_domination' + ) + assert_recognizes(#TODO: use PUT method to board_path, modify form accordingly + {:controller => 'boards', :action => 'edit', :id => '44', :project_id => 'world_domination'}, + {:method => :post, :path => '/projects/world_domination/boards/44/edit'} + ) + end + + def test_destroy_routing + assert_routing(#TODO: use DELETE method to board_path, modify form accoringly + {:method => :post, :path => '/projects/world_domination/boards/44/destroy'}, + :controller => 'boards', :action => 'destroy', :id => '44', :project_id => 'world_domination' + ) + end end diff --git a/test/functional/custom_fields_controller_test.rb b/test/functional/custom_fields_controller_test.rb new file mode 100644 index 000000000..42dedb3c1 --- /dev/null +++ b/test/functional/custom_fields_controller_test.rb @@ -0,0 +1,61 @@ +# Redmine - project management software +# Copyright (C) 2006-2009 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +require File.dirname(__FILE__) + '/../test_helper' +require 'custom_fields_controller' + +# Re-raise errors caught by the controller. +class CustomFieldsController; def rescue_action(e) raise e end; end + +class CustomFieldsControllerTest < Test::Unit::TestCase + fixtures :custom_fields, :trackers, :users + + def setup + @controller = CustomFieldsController.new + @request = ActionController::TestRequest.new + @response = ActionController::TestResponse.new + @request.session[:user_id] = 1 + end + + def test_post_new_list_custom_field + assert_difference 'CustomField.count' do + post :new, :type => "IssueCustomField", + :custom_field => {:name => "test_post_new_list", + :default_value => "", + :min_length => "0", + :searchable => "0", + :regexp => "", + :is_for_all => "1", + :possible_values => "0.1\n0.2\n", + :max_length => "0", + :is_filter => "0", + :is_required =>"0", + :field_format => "list", + :tracker_ids => ["1", ""]} + end + assert_redirected_to '/custom_fields' + field = IssueCustomField.find_by_name('test_post_new_list') + assert_not_nil field + assert_equal ["0.1", "0.2"], field.possible_values + assert_equal 1, field.trackers.size + end + + def test_invalid_custom_field_class_should_redirect_to_list + get :new, :type => 'UnknownCustomField' + assert_redirected_to '/custom_fields' + end +end diff --git a/test/functional/documents_controller_test.rb b/test/functional/documents_controller_test.rb index 7c1f0213a..2ad94aacf 100644 --- a/test/functional/documents_controller_test.rb +++ b/test/functional/documents_controller_test.rb @@ -30,12 +30,39 @@ class DocumentsControllerTest < Test::Unit::TestCase @response = ActionController::TestResponse.new User.current = nil end - + + def test_index_routing + assert_routing( + {:method => :get, :path => '/projects/567/documents'}, + :controller => 'documents', :action => 'index', :project_id => '567' + ) + end + def test_index + # Sets a default category + e = Enumeration.find_by_name('Technical documentation') + e.update_attributes(:is_default => true) + get :index, :project_id => 'ecookbook' assert_response :success assert_template 'index' assert_not_nil assigns(:grouped) + + # Default category selected in the new document form + assert_tag :select, :attributes => {:name => 'document[category_id]'}, + :child => {:tag => 'option', :attributes => {:selected => 'selected'}, + :content => 'Technical documentation'} + end + + def test_new_routing + assert_routing( + {:method => :get, :path => '/projects/567/documents/new'}, + :controller => 'documents', :action => 'new', :project_id => '567' + ) + assert_recognizes( + {:controller => 'documents', :action => 'new', :project_id => '567'}, + {:method => :post, :path => '/projects/567/documents'} + ) end def test_new_with_one_attachment @@ -57,6 +84,31 @@ class DocumentsControllerTest < Test::Unit::TestCase assert_equal 'testfile.txt', document.attachments.first.filename end + def test_edit_routing + assert_routing( + {:method => :get, :path => '/documents/22/edit'}, + :controller => 'documents', :action => 'edit', :id => '22' + ) + assert_recognizes(#TODO: should be using PUT on document URI + {:controller => 'documents', :action => 'edit', :id => '567'}, + {:method => :post, :path => '/documents/567/edit'} + ) + end + + def test_show_routing + assert_routing( + {:method => :get, :path => '/documents/22'}, + :controller => 'documents', :action => 'show', :id => '22' + ) + end + + def test_destroy_routing + assert_recognizes(#TODO: should be using DELETE on document URI + {:controller => 'documents', :action => 'destroy', :id => '567'}, + {:method => :post, :path => '/documents/567/destroy'} + ) + end + def test_destroy @request.session[:user_id] = 2 post :destroy, :id => 1 diff --git a/test/functional/issue_relations_controller_test.rb b/test/functional/issue_relations_controller_test.rb new file mode 100644 index 000000000..dc64a004e --- /dev/null +++ b/test/functional/issue_relations_controller_test.rb @@ -0,0 +1,58 @@ +require File.dirname(__FILE__) + '/../test_helper' +require 'issue_relations_controller' + +# Re-raise errors caught by the controller. +class IssueRelationsController; def rescue_action(e) raise e end; end + + +class IssueRelationsControllerTest < Test::Unit::TestCase + fixtures :projects, + :users, + :roles, + :members, + :issues, + :issue_statuses, + :enabled_modules, + :enumerations, + :trackers + + def setup + @controller = IssueRelationsController.new + @request = ActionController::TestRequest.new + @response = ActionController::TestResponse.new + User.current = nil + end + + def test_new_routing + assert_routing( + {:method => :post, :path => '/issues/1/relations'}, + {:controller => 'issue_relations', :action => 'new', :issue_id => '1'} + ) + end + + def test_destroy_routing + assert_recognizes( #TODO: use DELETE on issue URI + {:controller => 'issue_relations', :action => 'destroy', :issue_id => '1', :id => '23'}, + {:method => :post, :path => '/issues/1/relations/23/destroy'} + ) + end + + def test_new + assert_difference 'IssueRelation.count' do + @request.session[:user_id] = 3 + post :new, :issue_id => 1, + :relation => {:issue_to_id => '2', :relation_type => 'relates', :delay => ''} + end + end + + def test_should_create_relations_with_visible_issues_only + Setting.cross_project_issue_relations = '1' + assert_nil Issue.visible(User.find(3)).find_by_id(4) + + assert_no_difference 'IssueRelation.count' do + @request.session[:user_id] = 3 + post :new, :issue_id => 1, + :relation => {:issue_to_id => '4', :relation_type => 'relates', :delay => ''} + end + end +end diff --git a/test/functional/issues_controller_test.rb b/test/functional/issues_controller_test.rb index 9e2a9ffd5..cc1c77408 100644 --- a/test/functional/issues_controller_test.rb +++ b/test/functional/issues_controller_test.rb @@ -49,6 +49,13 @@ class IssuesControllerTest < Test::Unit::TestCase @response = ActionController::TestResponse.new User.current = nil end + + def test_index_routing + assert_routing( + {:method => :get, :path => '/issues'}, + :controller => 'issues', :action => 'index' + ) + end def test_index get :index @@ -62,7 +69,43 @@ class IssuesControllerTest < Test::Unit::TestCase assert_no_tag :tag => 'a', :content => /Issue of a private subproject/ assert_no_tag :tag => 'a', :content => /Issue on project 2/ end + + def test_index_should_not_list_issues_when_module_disabled + EnabledModule.delete_all("name = 'issue_tracking' AND project_id = 1") + get :index + assert_response :success + assert_template 'index.rhtml' + assert_not_nil assigns(:issues) + assert_nil assigns(:project) + assert_no_tag :tag => 'a', :content => /Can't print recipes/ + assert_tag :tag => 'a', :content => /Subproject issue/ + end + def test_index_with_project_routing + assert_routing( + {:method => :get, :path => '/projects/23/issues'}, + :controller => 'issues', :action => 'index', :project_id => '23' + ) + end + + def test_index_should_not_list_issues_when_module_disabled + EnabledModule.delete_all("name = 'issue_tracking' AND project_id = 1") + get :index + assert_response :success + assert_template 'index.rhtml' + assert_not_nil assigns(:issues) + assert_nil assigns(:project) + assert_no_tag :tag => 'a', :content => /Can't print recipes/ + assert_tag :tag => 'a', :content => /Subproject issue/ + end + + def test_index_with_project_routing + assert_routing( + {:method => :get, :path => 'projects/23/issues'}, + :controller => 'issues', :action => 'index', :project_id => '23' + ) + end + def test_index_with_project Setting.display_subprojects_issues = 0 get :index, :project_id => 1 @@ -96,6 +139,17 @@ class IssuesControllerTest < Test::Unit::TestCase assert_tag :tag => 'a', :content => /Issue of a private subproject/ end + def test_index_with_project_routing_formatted + assert_routing( + {:method => :get, :path => 'projects/23/issues.pdf'}, + :controller => 'issues', :action => 'index', :project_id => '23', :format => 'pdf' + ) + assert_routing( + {:method => :get, :path => 'projects/23/issues.atom'}, + :controller => 'issues', :action => 'index', :project_id => '23', :format => 'atom' + ) + end + def test_index_with_project_and_filter get :index, :project_id => 1, :set_filter => 1 assert_response :success @@ -115,6 +169,17 @@ class IssuesControllerTest < Test::Unit::TestCase assert_equal 'text/csv', @response.content_type end + def test_index_formatted + assert_routing( + {:method => :get, :path => 'issues.pdf'}, + :controller => 'issues', :action => 'index', :format => 'pdf' + ) + assert_routing( + {:method => :get, :path => 'issues.atom'}, + :controller => 'issues', :action => 'index', :format => 'atom' + ) + end + def test_index_pdf get :index, :format => 'pdf' assert_response :success @@ -126,6 +191,16 @@ class IssuesControllerTest < Test::Unit::TestCase assert_not_nil assigns(:issues) assert_equal 'application/pdf', @response.content_type end + + def test_index_sort + get :index, :sort_key => 'tracker' + assert_response :success + + sort_params = @request.session['issuesindex_sort'] + assert sort_params.is_a?(Hash) + assert_equal 'tracker', sort_params[:key] + assert_equal 'ASC', sort_params[:order] + end def test_gantt get :gantt, :project_id => 1 @@ -144,11 +219,28 @@ class IssuesControllerTest < Test::Unit::TestCase assert events.include?(i) end + def test_cross_project_gantt + get :gantt + assert_response :success + assert_template 'gantt.rhtml' + assert_not_nil assigns(:gantt) + events = assigns(:gantt).events + assert_not_nil events + end + def test_gantt_export_to_pdf get :gantt, :project_id => 1, :format => 'pdf' assert_response :success - assert_template 'gantt.rfpdf' assert_equal 'application/pdf', @response.content_type + assert @response.body.starts_with?('%PDF') + assert_not_nil assigns(:gantt) + end + + def test_cross_project_gantt_export_to_pdf + get :gantt, :format => 'pdf' + assert_response :success + assert_equal 'application/pdf', @response.content_type + assert @response.body.starts_with?('%PDF') assert_not_nil assigns(:gantt) end @@ -169,6 +261,13 @@ class IssuesControllerTest < Test::Unit::TestCase assert_not_nil assigns(:calendar) end + def test_cross_project_calendar + get :calendar + assert_response :success + assert_template 'calendar' + assert_not_nil assigns(:calendar) + end + def test_changes get :changes, :project_id => 1 assert_response :success @@ -176,6 +275,24 @@ class IssuesControllerTest < Test::Unit::TestCase assert_equal 'application/atom+xml', @response.content_type end + def test_show_routing + assert_routing( + {:method => :get, :path => '/issues/64'}, + :controller => 'issues', :action => 'show', :id => '64' + ) + end + + def test_show_routing_formatted + assert_routing( + {:method => :get, :path => '/issues/2332.pdf'}, + :controller => 'issues', :action => 'show', :id => '2332', :format => 'pdf' + ) + assert_routing( + {:method => :get, :path => '/issues/23123.atom'}, + :controller => 'issues', :action => 'show', :id => '23123', :format => 'atom' + ) + end + def test_show_by_anonymous get :show, :id => 1 assert_response :success @@ -206,6 +323,40 @@ class IssuesControllerTest < Test::Unit::TestCase :child => { :tag => 'legend', :content => /Notes/ } } end + + def test_show_should_not_disclose_relations_to_invisible_issues + Setting.cross_project_issue_relations = '1' + IssueRelation.create!(:issue_from => Issue.find(1), :issue_to => Issue.find(2), :relation_type => 'relates') + # Relation to a private project issue + IssueRelation.create!(:issue_from => Issue.find(1), :issue_to => Issue.find(4), :relation_type => 'relates') + + get :show, :id => 1 + assert_response :success + + assert_tag :div, :attributes => { :id => 'relations' }, + :descendant => { :tag => 'a', :content => /#2$/ } + assert_no_tag :div, :attributes => { :id => 'relations' }, + :descendant => { :tag => 'a', :content => /#4$/ } + end + + def test_new_routing + assert_routing( + {:method => :get, :path => '/projects/1/issues/new'}, + :controller => 'issues', :action => 'new', :project_id => '1' + ) + assert_recognizes( + {:controller => 'issues', :action => 'new', :project_id => '1'}, + {:method => :post, :path => '/projects/1/issues'} + ) + end + + def test_show_export_to_pdf + get :show, :id => 3, :format => 'pdf' + assert_response :success + assert_equal 'application/pdf', @response.content_type + assert @response.body.starts_with?('%PDF') + assert_not_nil assigns(:issue) + end def test_get_new @request.session[:user_id] = 2 @@ -237,7 +388,7 @@ class IssuesControllerTest < Test::Unit::TestCase :priority_id => 5} assert_response :success assert_template 'new' - end + end def test_post_new @request.session[:user_id] = 2 @@ -248,7 +399,7 @@ class IssuesControllerTest < Test::Unit::TestCase :priority_id => 5, :estimated_hours => '', :custom_field_values => {'2' => 'Value for field 2'}} - assert_redirected_to 'issues/show' + assert_redirected_to :action => 'show' issue = Issue.find_by_subject('This is the test_new issue') assert_not_nil issue @@ -260,6 +411,16 @@ class IssuesControllerTest < Test::Unit::TestCase assert_equal 'Value for field 2', v.value end + def test_post_new_and_continue + @request.session[:user_id] = 2 + post :new, :project_id => 1, + :issue => {:tracker_id => 3, + :subject => 'This is first issue', + :priority_id => 5}, + :continue => '' + assert_redirected_to :controller => 'issues', :action => 'new', :tracker_id => 3 + end + def test_post_new_without_custom_fields_param @request.session[:user_id] = 2 post :new, :project_id => 1, @@ -267,9 +428,9 @@ class IssuesControllerTest < Test::Unit::TestCase :subject => 'This is the test_new issue', :description => 'This is the description', :priority_id => 5} - assert_redirected_to 'issues/show' + assert_redirected_to :action => 'show' end - + def test_post_new_with_required_custom_field_and_without_custom_fields_param field = IssueCustomField.find_by_name('Database') field.update_attribute(:is_required, true) @@ -287,20 +448,45 @@ class IssuesControllerTest < Test::Unit::TestCase assert_equal 'activerecord_error_invalid', issue.errors.on(:custom_values) end + def test_post_new_with_watchers + @request.session[:user_id] = 2 + ActionMailer::Base.deliveries.clear + + assert_difference 'Watcher.count', 2 do + post :new, :project_id => 1, + :issue => {:tracker_id => 1, + :subject => 'This is a new issue with watchers', + :description => 'This is the description', + :priority_id => 5, + :watcher_user_ids => ['2', '3']} + end + issue = Issue.find_by_subject('This is a new issue with watchers') + assert_not_nil issue + assert_redirected_to :controller => 'issues', :action => 'show', :id => issue + + # Watchers added + assert_equal [2, 3], issue.watcher_user_ids.sort + assert issue.watched_by?(User.find(3)) + # Watchers notified + mail = ActionMailer::Base.deliveries.last + assert_kind_of TMail::Mail, mail + assert [mail.bcc, mail.cc].flatten.include?(User.find(3).mail) + end + def test_post_should_preserve_fields_values_on_validation_failure @request.session[:user_id] = 2 post :new, :project_id => 1, :issue => {:tracker_id => 1, - :subject => 'This is the test_new issue', - # empty description - :description => '', + # empty subject + :subject => '', + :description => 'This is a description', :priority_id => 6, :custom_field_values => {'1' => 'Oracle', '2' => 'Value for field 2'}} assert_response :success assert_template 'new' - assert_tag :input, :attributes => { :name => 'issue[subject]', - :value => 'This is the test_new issue' } + assert_tag :textarea, :attributes => { :name => 'issue[description]' }, + :content => 'This is a description' assert_tag :select, :attributes => { :name => 'issue[priority_id]' }, :child => { :tag => 'option', :attributes => { :selected => 'selected', :value => '6' }, @@ -314,6 +500,13 @@ class IssuesControllerTest < Test::Unit::TestCase :value => 'Value for field 2'} end + def test_copy_routing + assert_routing( + {:method => :get, :path => '/projects/world_domination/issues/567/copy'}, + :controller => 'issues', :action => 'new', :project_id => 'world_domination', :copy_from => '567' + ) + end + def test_copy_issue @request.session[:user_id] = 2 get :new, :project_id => 1, :copy_from => 1 @@ -323,6 +516,17 @@ class IssuesControllerTest < Test::Unit::TestCase assert_equal orig.subject, assigns(:issue).subject end + def test_edit_routing + assert_routing( + {:method => :get, :path => '/issues/1/edit'}, + :controller => 'issues', :action => 'edit', :id => '1' + ) + assert_recognizes( #TODO: use a PUT on the issue URI isntead, need to adjust form + {:controller => 'issues', :action => 'edit', :id => '1'}, + {:method => :post, :path => '/issues/1/edit'} + ) + end + def test_get_edit @request.session[:user_id] = 2 get :edit, :id => 1 @@ -354,6 +558,13 @@ class IssuesControllerTest < Test::Unit::TestCase :attributes => { :selected => 'selected' } } end + def test_reply_routing + assert_routing( + {:method => :post, :path => '/issues/1/quoted'}, + :controller => 'issues', :action => 'reply', :id => '1' + ) + end + def test_reply_to_issue @request.session[:user_id] = 2 get :reply, :id => 1 @@ -385,7 +596,7 @@ class IssuesControllerTest < Test::Unit::TestCase } end end - assert_redirected_to 'issues/show/1' + assert_redirected_to :action => 'show', :id => '1' issue.reload assert_equal new_subject, issue.subject # Make sure custom fields were not cleared @@ -411,7 +622,7 @@ class IssuesControllerTest < Test::Unit::TestCase } end end - assert_redirected_to 'issues/show/1' + assert_redirected_to :action => 'show', :id => '1' issue.reload assert_equal 'New custom value', issue.custom_value_for(2).value @@ -431,7 +642,7 @@ class IssuesControllerTest < Test::Unit::TestCase :notes => 'Assigned to dlopper', :time_entry => { :hours => '', :comments => '', :activity_id => Enumeration.get_values('ACTI').first } end - assert_redirected_to 'issues/show/1' + assert_redirected_to :action => 'show', :id => '1' issue.reload assert_equal 2, issue.status_id j = issue.journals.find(:first, :order => 'id DESC') @@ -448,7 +659,7 @@ class IssuesControllerTest < Test::Unit::TestCase post :edit, :id => 1, :notes => notes - assert_redirected_to 'issues/show/1' + assert_redirected_to :action => 'show', :id => '1' j = Issue.find(1).journals.find(:first, :order => 'id DESC') assert_equal notes, j.notes assert_equal 0, j.details.size @@ -467,7 +678,7 @@ class IssuesControllerTest < Test::Unit::TestCase :notes => '2.5 hours added', :time_entry => { :hours => '2.5', :comments => '', :activity_id => Enumeration.get_values('ACTI').first } end - assert_redirected_to 'issues/show/1' + assert_redirected_to :action => 'show', :id => '1' issue = Issue.find(1) @@ -484,12 +695,16 @@ class IssuesControllerTest < Test::Unit::TestCase def test_post_edit_with_attachment_only set_tmp_attachments_directory + # Delete all fixtured journals, a race condition can occur causing the wrong + # journal to get fetched in the next find. + Journal.delete_all + # anonymous user post :edit, :id => 1, :notes => '', :attachments => {'1' => {'file' => test_uploaded_file('testfile.txt', 'text/plain')}} - assert_redirected_to 'issues/show/1' + assert_redirected_to :action => 'show', :id => '1' j = Issue.find(1).journals.find(:first, :order => 'id DESC') assert j.notes.blank? assert_equal 1, j.details.size @@ -508,22 +723,65 @@ class IssuesControllerTest < Test::Unit::TestCase post :edit, :id => 1, :notes => '' - assert_redirected_to 'issues/show/1' + assert_redirected_to :action => 'show', :id => '1' issue.reload assert issue.journals.empty? # No email should be sent assert ActionMailer::Base.deliveries.empty? end + + def test_post_edit_with_invalid_spent_time + @request.session[:user_id] = 2 + notes = 'Note added by IssuesControllerTest#test_post_edit_with_invalid_spent_time' + + assert_no_difference('Journal.count') do + post :edit, + :id => 1, + :notes => notes, + :time_entry => {"comments"=>"", "activity_id"=>"", "hours"=>"2z"} + end + assert_response :success + assert_template 'edit' + + assert_tag :textarea, :attributes => { :name => 'notes' }, + :content => notes + assert_tag :input, :attributes => { :name => 'time_entry[hours]', :value => "2z" } + end def test_bulk_edit @request.session[:user_id] = 2 # update issues priority - post :bulk_edit, :ids => [1, 2], :priority_id => 7, :notes => 'Bulk editing', :assigned_to_id => '' + post :bulk_edit, :ids => [1, 2], :priority_id => 7, + :assigned_to_id => '', + :custom_field_values => {'2' => ''}, + :notes => 'Bulk editing' assert_response 302 # check that the issues were updated assert_equal [7, 7], Issue.find_all_by_id([1, 2]).collect {|i| i.priority.id} - assert_equal 'Bulk editing', Issue.find(1).journals.find(:first, :order => 'created_on DESC').notes + + issue = Issue.find(1) + journal = issue.journals.find(:first, :order => 'created_on DESC') + assert_equal '125', issue.custom_value_for(2).value + assert_equal 'Bulk editing', journal.notes + assert_equal 1, journal.details.size + end + + def test_bulk_edit_custom_field + @request.session[:user_id] = 2 + # update issues priority + post :bulk_edit, :ids => [1, 2], :priority_id => '', + :assigned_to_id => '', + :custom_field_values => {'2' => '777'}, + :notes => 'Bulk editing custom field' + assert_response 302 + + issue = Issue.find(1) + journal = issue.journals.find(:first, :order => 'created_on DESC') + assert_equal '777', issue.custom_value_for(2).value + assert_equal 1, journal.details.size + assert_equal '125', journal.details.first.old_value + assert_equal '777', journal.details.first.value end def test_bulk_unassign @@ -536,17 +794,28 @@ class IssuesControllerTest < Test::Unit::TestCase assert_nil Issue.find(2).assigned_to end + def test_move_routing + assert_routing( + {:method => :get, :path => '/issues/1/move'}, + :controller => 'issues', :action => 'move', :id => '1' + ) + assert_recognizes( + {:controller => 'issues', :action => 'move', :id => '1'}, + {:method => :post, :path => '/issues/1/move'} + ) + end + def test_move_one_issue_to_another_project @request.session[:user_id] = 1 post :move, :id => 1, :new_project_id => 2 - assert_redirected_to 'projects/ecookbook/issues' + assert_redirected_to :action => 'index', :project_id => 'ecookbook' assert_equal 2, Issue.find(1).project_id end def test_bulk_move_to_another_project @request.session[:user_id] = 1 post :move, :ids => [1, 2], :new_project_id => 2 - assert_redirected_to 'projects/ecookbook/issues' + assert_redirected_to :action => 'index', :project_id => 'ecookbook' # Issues moved to project 2 assert_equal 2, Issue.find(1).project_id assert_equal 2, Issue.find(2).project_id @@ -558,10 +827,20 @@ class IssuesControllerTest < Test::Unit::TestCase def test_bulk_move_to_another_tracker @request.session[:user_id] = 1 post :move, :ids => [1, 2], :new_tracker_id => 2 - assert_redirected_to 'projects/ecookbook/issues' + assert_redirected_to :action => 'index', :project_id => 'ecookbook' assert_equal 2, Issue.find(1).tracker_id assert_equal 2, Issue.find(2).tracker_id end + + def test_bulk_copy_to_another_project + @request.session[:user_id] = 1 + assert_difference 'Issue.count', 2 do + assert_no_difference 'Project.find(1).issues.count' do + post :move, :ids => [1, 2], :new_project_id => 2, :copy_options => {:copy => '1'} + end + end + assert_redirected_to 'projects/ecookbook/issues' + end def test_context_menu_one_issue @request.session[:user_id] = 2 @@ -569,10 +848,10 @@ class IssuesControllerTest < Test::Unit::TestCase assert_response :success assert_template 'context_menu' assert_tag :tag => 'a', :content => 'Edit', - :attributes => { :href => '/issues/edit/1', + :attributes => { :href => '/issues/1/edit', :class => 'icon-edit' } assert_tag :tag => 'a', :content => 'Closed', - :attributes => { :href => '/issues/edit/1?issue%5Bstatus_id%5D=5', + :attributes => { :href => '/issues/1/edit?issue%5Bstatus_id%5D=5', :class => '' } assert_tag :tag => 'a', :content => 'Immediate', :attributes => { :href => '/issues/bulk_edit?ids%5B%5D=1&priority_id=8', @@ -581,7 +860,7 @@ class IssuesControllerTest < Test::Unit::TestCase :attributes => { :href => '/issues/bulk_edit?assigned_to_id=3&ids%5B%5D=1', :class => '' } assert_tag :tag => 'a', :content => 'Copy', - :attributes => { :href => '/projects/ecookbook/issues/new?copy_from=1', + :attributes => { :href => '/projects/ecookbook/issues/1/copy', :class => 'icon-copy' } assert_tag :tag => 'a', :content => 'Move', :attributes => { :href => '/issues/move?ids%5B%5D=1', @@ -632,11 +911,18 @@ class IssuesControllerTest < Test::Unit::TestCase :class => 'icon-del disabled' } end + def test_destroy_routing + assert_recognizes( #TODO: use DELETE on issue URI (need to change forms) + {:controller => 'issues', :action => 'destroy', :id => '1'}, + {:method => :post, :path => '/issues/1/destroy'} + ) + end + def test_destroy_issue_with_no_time_entries assert_nil TimeEntry.find_by_issue_id(2) @request.session[:user_id] = 2 post :destroy, :id => 2 - assert_redirected_to 'projects/ecookbook/issues' + assert_redirected_to :action => 'index', :project_id => 'ecookbook' assert_nil Issue.find_by_id(2) end @@ -652,7 +938,7 @@ class IssuesControllerTest < Test::Unit::TestCase def test_destroy_issues_and_destroy_time_entries @request.session[:user_id] = 2 post :destroy, :ids => [1, 3], :todo => 'destroy' - assert_redirected_to 'projects/ecookbook/issues' + assert_redirected_to :action => 'index', :project_id => 'ecookbook' assert !(Issue.find_by_id(1) || Issue.find_by_id(3)) assert_nil TimeEntry.find_by_id([1, 2]) end @@ -660,7 +946,7 @@ class IssuesControllerTest < Test::Unit::TestCase def test_destroy_issues_and_assign_time_entries_to_project @request.session[:user_id] = 2 post :destroy, :ids => [1, 3], :todo => 'nullify' - assert_redirected_to 'projects/ecookbook/issues' + assert_redirected_to :action => 'index', :project_id => 'ecookbook' assert !(Issue.find_by_id(1) || Issue.find_by_id(3)) assert_nil TimeEntry.find(1).issue_id assert_nil TimeEntry.find(2).issue_id @@ -669,22 +955,9 @@ class IssuesControllerTest < Test::Unit::TestCase def test_destroy_issues_and_reassign_time_entries_to_another_issue @request.session[:user_id] = 2 post :destroy, :ids => [1, 3], :todo => 'reassign', :reassign_to_id => 2 - assert_redirected_to 'projects/ecookbook/issues' + assert_redirected_to :action => 'index', :project_id => 'ecookbook' assert !(Issue.find_by_id(1) || Issue.find_by_id(3)) assert_equal 2, TimeEntry.find(1).issue_id assert_equal 2, TimeEntry.find(2).issue_id end - - def test_destroy_attachment - issue = Issue.find(3) - a = issue.attachments.size - @request.session[:user_id] = 2 - post :destroy_attachment, :id => 3, :attachment_id => 1 - assert_redirected_to 'issues/show/3' - assert_nil Attachment.find_by_id(1) - issue.reload - assert_equal((a-1), issue.attachments.size) - j = issue.journals.find(:first, :order => 'created_on DESC') - assert_equal 'attachment', j.details.first.property - end end diff --git a/test/functional/members_controller_test.rb b/test/functional/members_controller_test.rb new file mode 100644 index 000000000..f69bde193 --- /dev/null +++ b/test/functional/members_controller_test.rb @@ -0,0 +1,15 @@ +require File.dirname(__FILE__) + '/../test_helper' +require 'members_controller' + +# Re-raise errors caught by the controller. +class MembersController; def rescue_action(e) raise e end; end + + +class MembersControllerTest < Test::Unit::TestCase + def test_members_routing + assert_routing( + {:method => :post, :path => 'projects/5234/members/new'}, + :controller => 'members', :action => 'new', :id => '5234' + ) + end +end diff --git a/test/functional/messages_controller_test.rb b/test/functional/messages_controller_test.rb index b1b3ea942..d19249c06 100644 --- a/test/functional/messages_controller_test.rb +++ b/test/functional/messages_controller_test.rb @@ -31,6 +31,13 @@ class MessagesControllerTest < Test::Unit::TestCase User.current = nil end + def test_show_routing + assert_routing( + {:method => :get, :path => '/boards/22/topics/2'}, + :controller => 'messages', :action => 'show', :id => '2', :board_id => '22' + ) + end + def test_show get :show, :board_id => 1, :id => 1 assert_response :success @@ -54,6 +61,17 @@ class MessagesControllerTest < Test::Unit::TestCase assert_response 404 end + def test_new_routing + assert_routing( + {:method => :get, :path => '/boards/lala/topics/new'}, + :controller => 'messages', :action => 'new', :board_id => 'lala' + ) + assert_recognizes(#TODO: POST to collection, need to adjust form accordingly + {:controller => 'messages', :action => 'new', :board_id => 'lala'}, + {:method => :post, :path => '/boards/lala/topics/new'} + ) + end + def test_get_new @request.session[:user_id] = 2 get :new, :board_id => 1 @@ -64,7 +82,7 @@ class MessagesControllerTest < Test::Unit::TestCase def test_post_new @request.session[:user_id] = 2 ActionMailer::Base.deliveries.clear - Setting.notified_events << 'message_posted' + Setting.notified_events = ['message_posted'] post :new, :board_id => 1, :message => { :subject => 'Test created message', @@ -78,7 +96,7 @@ class MessagesControllerTest < Test::Unit::TestCase mail = ActionMailer::Base.deliveries.last assert_kind_of TMail::Mail, mail - assert_equal "[#{message.board.project.name} - #{message.board.name}] Test created message", mail.subject + assert_equal "[#{message.board.project.name} - #{message.board.name} - msg#{message.root.id}] Test created message", mail.subject assert mail.body.include?('Message body') # author assert mail.bcc.include?('jsmith@somenet.foo') @@ -86,6 +104,17 @@ class MessagesControllerTest < Test::Unit::TestCase assert mail.bcc.include?('dlopper@somenet.foo') end + def test_edit_routing + assert_routing( + {:method => :get, :path => '/boards/lala/topics/22/edit'}, + :controller => 'messages', :action => 'edit', :board_id => 'lala', :id => '22' + ) + assert_recognizes( #TODO: use PUT to topic_path, modify form accordingly + {:controller => 'messages', :action => 'edit', :board_id => 'lala', :id => '22'}, + {:method => :post, :path => '/boards/lala/topics/22/edit'} + ) + end + def test_get_edit @request.session[:user_id] = 2 get :edit, :board_id => 1, :id => 1 @@ -104,6 +133,13 @@ class MessagesControllerTest < Test::Unit::TestCase assert_equal 'New body', message.content end + def test_reply_routing + assert_recognizes( + {:controller => 'messages', :action => 'reply', :board_id => '22', :id => '555'}, + {:method => :post, :path => '/boards/22/topics/555/replies'} + ) + end + def test_reply @request.session[:user_id] = 2 post :reply, :board_id => 1, :id => 1, :reply => { :content => 'This is a test reply', :subject => 'Test reply' } @@ -111,6 +147,13 @@ class MessagesControllerTest < Test::Unit::TestCase assert Message.find_by_subject('Test reply') end + def test_destroy_routing + assert_recognizes(#TODO: use DELETE to topic_path, adjust form accordingly + {:controller => 'messages', :action => 'destroy', :board_id => '22', :id => '555'}, + {:method => :post, :path => '/boards/22/topics/555/destroy'} + ) + end + def test_destroy_topic @request.session[:user_id] = 2 post :destroy, :board_id => 1, :id => 1 diff --git a/test/functional/my_controller_test.rb b/test/functional/my_controller_test.rb index c1349ace4..997340096 100644 --- a/test/functional/my_controller_test.rb +++ b/test/functional/my_controller_test.rb @@ -22,7 +22,7 @@ require 'my_controller' class MyController; def rescue_action(e) raise e end; end class MyControllerTest < Test::Unit::TestCase - fixtures :users, :issues, :issue_statuses, :trackers, :enumerations + fixtures :users, :issues, :issue_statuses, :trackers, :enumerations, :custom_fields def setup @controller = MyController.new @@ -43,20 +43,37 @@ class MyControllerTest < Test::Unit::TestCase assert_template 'page' end - def test_get_account + def test_my_account_should_show_editable_custom_fields get :account assert_response :success assert_template 'account' assert_equal User.find(2), assigns(:user) + + assert_tag :input, :attributes => { :name => 'user[custom_field_values][4]'} + end + + def test_my_account_should_not_show_non_editable_custom_fields + UserCustomField.find(4).update_attribute :editable, false + + get :account + assert_response :success + assert_template 'account' + assert_equal User.find(2), assigns(:user) + + assert_no_tag :input, :attributes => { :name => 'user[custom_field_values][4]'} end def test_update_account - post :account, :user => {:firstname => "Joe", :login => "root", :admin => 1} + post :account, :user => {:firstname => "Joe", + :login => "root", + :admin => 1, + :custom_field_values => {"4" => "0100562500"}} assert_redirected_to 'my/account' user = User.find(2) assert_equal user, assigns(:user) assert_equal "Joe", user.firstname assert_equal "jsmith", user.login + assert_equal "0100562500", user.custom_value_for(4).value assert !user.admin? end diff --git a/test/functional/news_controller_test.rb b/test/functional/news_controller_test.rb index 01f8015b9..651471b66 100644 --- a/test/functional/news_controller_test.rb +++ b/test/functional/news_controller_test.rb @@ -31,6 +31,20 @@ class NewsControllerTest < Test::Unit::TestCase User.current = nil end + def test_index_routing + assert_routing( + {:method => :get, :path => '/news'}, + :controller => 'news', :action => 'index' + ) + end + + def test_index_routing_formatted + assert_routing( + {:method => :get, :path => '/news.atom'}, + :controller => 'news', :action => 'index', :format => 'atom' + ) + end + def test_index get :index assert_response :success @@ -38,6 +52,20 @@ class NewsControllerTest < Test::Unit::TestCase assert_not_nil assigns(:newss) assert_nil assigns(:project) end + + def test_index_with_project_routing + assert_routing( + {:method => :get, :path => '/projects/567/news'}, + :controller => 'news', :action => 'index', :project_id => '567' + ) + end + + def test_index_with_project_routing_formatted + assert_routing( + {:method => :get, :path => '/projects/567/news.atom'}, + :controller => 'news', :action => 'index', :project_id => '567', :format => 'atom' + ) + end def test_index_with_project get :index, :project_id => 1 @@ -46,6 +74,13 @@ class NewsControllerTest < Test::Unit::TestCase assert_not_nil assigns(:newss) end + def test_show_routing + assert_routing( + {:method => :get, :path => '/news/2'}, + :controller => 'news', :action => 'show', :id => '2' + ) + end + def test_show get :show, :id => 1 assert_response :success @@ -58,6 +93,17 @@ class NewsControllerTest < Test::Unit::TestCase assert_response 404 end + def test_new_routing + assert_routing( + {:method => :get, :path => '/projects/567/news/new'}, + :controller => 'news', :action => 'new', :project_id => '567' + ) + assert_recognizes( + {:controller => 'news', :action => 'new', :project_id => '567'}, + {:method => :post, :path => '/projects/567/news'} + ) + end + def test_get_new @request.session[:user_id] = 2 get :new, :project_id => 1 @@ -79,6 +125,17 @@ class NewsControllerTest < Test::Unit::TestCase assert_equal Project.find(1), news.project end + def test_edit_routing + assert_routing( + {:method => :get, :path => '/news/234'}, + :controller => 'news', :action => 'show', :id => '234' + ) + assert_recognizes(#TODO: PUT to news URI instead, need to modify form + {:controller => 'news', :action => 'edit', :id => '567'}, + {:method => :post, :path => '/news/567/edit'} + ) + end + def test_get_edit @request.session[:user_id] = 2 get :edit, :id => 1 @@ -127,6 +184,13 @@ class NewsControllerTest < Test::Unit::TestCase assert_equal comments_count - 1, News.find(1).comments.size end + def test_destroy_routing + assert_recognizes(#TODO: should use DELETE to news URI, need to change form + {:controller => 'news', :action => 'destroy', :id => '567'}, + {:method => :post, :path => '/news/567/destroy'} + ) + end + def test_destroy @request.session[:user_id] = 2 post :destroy, :id => 1 diff --git a/test/functional/projects_controller_test.rb b/test/functional/projects_controller_test.rb index 45af4e33e..25f9ad78e 100644 --- a/test/functional/projects_controller_test.rb +++ b/test/functional/projects_controller_test.rb @@ -23,25 +23,48 @@ class ProjectsController; def rescue_action(e) raise e end; end class ProjectsControllerTest < Test::Unit::TestCase fixtures :projects, :versions, :users, :roles, :members, :issues, :journals, :journal_details, - :trackers, :projects_trackers, :issue_statuses, :enabled_modules, :enumerations, :boards, :messages + :trackers, :projects_trackers, :issue_statuses, :enabled_modules, :enumerations, :boards, :messages, + :attachments def setup @controller = ProjectsController.new @request = ActionController::TestRequest.new @response = ActionController::TestResponse.new @request.session[:user_id] = nil + Setting.default_language = 'en' end - + + def test_index_routing + assert_routing( + {:method => :get, :path => '/projects'}, + :controller => 'projects', :action => 'index' + ) + end + def test_index get :index assert_response :success assert_template 'index' - assert_not_nil assigns(:project_tree) - # Root project as hash key - assert assigns(:project_tree).keys.include?(Project.find(1)) - # Subproject in corresponding value - assert assigns(:project_tree)[Project.find(1)].include?(Project.find(3)) - end + assert_not_nil assigns(:projects) + + assert_tag :ul, :child => {:tag => 'li', + :descendant => {:tag => 'a', :content => 'eCookbook'}, + :child => { :tag => 'ul', + :descendant => { :tag => 'a', + :content => 'Child of private child' + } + } + } + + assert_no_tag :a, :content => /Private child of eCookbook/ + end + + def test_index_atom_routing + assert_routing( + {:method => :get, :path => '/projects.atom'}, + :controller => 'projects', :action => 'index', :format => 'atom' + ) + end def test_index_atom get :index, :format => 'atom' @@ -50,12 +73,34 @@ class ProjectsControllerTest < Test::Unit::TestCase assert_select 'feed>title', :text => 'Redmine: Latest projects' assert_select 'feed>entry', :count => Project.count(:conditions => Project.visible_by(User.current)) end - - def test_show_by_id - get :show, :id => 1 + + def test_add_routing + assert_routing( + {:method => :get, :path => '/projects/new'}, + :controller => 'projects', :action => 'add' + ) + assert_recognizes( + {:controller => 'projects', :action => 'add'}, + {:method => :post, :path => '/projects/new'} + ) + assert_recognizes( + {:controller => 'projects', :action => 'add'}, + {:method => :post, :path => '/projects'} + ) + end + + def test_show_routing + assert_routing( + {:method => :get, :path => '/projects/test'}, + :controller => 'projects', :action => 'show', :id => 'test' + ) + end + + def test_show_by_id + get :show, :id => 1 assert_response :success - assert_template 'show' - assert_not_nil assigns(:project) + assert_template 'show' + assert_not_nil assigns(:project) end def test_show_by_identifier @@ -81,6 +126,17 @@ class ProjectsControllerTest < Test::Unit::TestCase assert_tag :tag => 'a', :content => /Private child/ end + def test_settings_routing + assert_routing( + {:method => :get, :path => '/projects/4223/settings'}, + :controller => 'projects', :action => 'settings', :id => '4223' + ) + assert_routing( + {:method => :get, :path => '/projects/4223/settings/members'}, + :controller => 'projects', :action => 'settings', :id => '4223', :tab => 'members' + ) + end + def test_settings @request.session[:user_id] = 2 # manager get :settings, :id => 1 @@ -97,13 +153,49 @@ class ProjectsControllerTest < Test::Unit::TestCase assert_equal 'Test changed name', project.name end + def test_add_version_routing + assert_routing( + {:method => :get, :path => 'projects/64/versions/new'}, + :controller => 'projects', :action => 'add_version', :id => '64' + ) + assert_routing( + #TODO: use PUT + {:method => :post, :path => 'projects/64/versions/new'}, + :controller => 'projects', :action => 'add_version', :id => '64' + ) + end + + def test_add_issue_category_routing + assert_routing( + {:method => :get, :path => 'projects/test/categories/new'}, + :controller => 'projects', :action => 'add_issue_category', :id => 'test' + ) + assert_routing( + #TODO: use PUT and update form + {:method => :post, :path => 'projects/64/categories/new'}, + :controller => 'projects', :action => 'add_issue_category', :id => '64' + ) + end + + def test_destroy_routing + assert_routing( + {:method => :get, :path => '/projects/567/destroy'}, + :controller => 'projects', :action => 'destroy', :id => '567' + ) + assert_routing( + #TODO: use DELETE and update form + {:method => :post, :path => 'projects/64/destroy'}, + :controller => 'projects', :action => 'destroy', :id => '64' + ) + end + def test_get_destroy @request.session[:user_id] = 1 # admin get :destroy, :id => 1 assert_response :success assert_template 'destroy' assert_not_nil Project.find_by_id(1) - end + end def test_post_destroy @request.session[:user_id] = 1 # admin @@ -111,19 +203,95 @@ class ProjectsControllerTest < Test::Unit::TestCase assert_redirected_to 'admin/projects' assert_nil Project.find_by_id(1) end - - def test_list_files - get :list_files, :id => 1 - assert_response :success - assert_template 'list_files' - assert_not_nil assigns(:versions) - end - - def test_changelog - get :changelog, :id => 1 - assert_response :success - assert_template 'changelog' - assert_not_nil assigns(:versions) + + def test_add_file + set_tmp_attachments_directory + @request.session[:user_id] = 2 + Setting.notified_events = ['file_added'] + ActionMailer::Base.deliveries.clear + + assert_difference 'Attachment.count' do + post :add_file, :id => 1, :version_id => '', + :attachments => {'1' => {'file' => test_uploaded_file('testfile.txt', 'text/plain')}} + end + assert_redirected_to 'projects/list_files/ecookbook' + a = Attachment.find(:first, :order => 'created_on DESC') + assert_equal 'testfile.txt', a.filename + assert_equal Project.find(1), a.container + + mail = ActionMailer::Base.deliveries.last + assert_kind_of TMail::Mail, mail + assert_equal "[eCookbook] New file", mail.subject + assert mail.body.include?('testfile.txt') + end + + def test_add_file_routing + assert_routing( + {:method => :get, :path => '/projects/33/files/new'}, + :controller => 'projects', :action => 'add_file', :id => '33' + ) + assert_routing( + {:method => :post, :path => '/projects/33/files/new'}, + :controller => 'projects', :action => 'add_file', :id => '33' + ) + end + + def test_add_version_file + set_tmp_attachments_directory + @request.session[:user_id] = 2 + Setting.notified_events = ['file_added'] + + assert_difference 'Attachment.count' do + post :add_file, :id => 1, :version_id => '2', + :attachments => {'1' => {'file' => test_uploaded_file('testfile.txt', 'text/plain')}} + end + assert_redirected_to 'projects/list_files/ecookbook' + a = Attachment.find(:first, :order => 'created_on DESC') + assert_equal 'testfile.txt', a.filename + assert_equal Version.find(2), a.container + end + + def test_list_files + get :list_files, :id => 1 + assert_response :success + assert_template 'list_files' + assert_not_nil assigns(:containers) + + # file attached to the project + assert_tag :a, :content => 'project_file.zip', + :attributes => { :href => '/attachments/download/8/project_file.zip' } + + # file attached to a project's version + assert_tag :a, :content => 'version_file.zip', + :attributes => { :href => '/attachments/download/9/version_file.zip' } + end + + def test_list_files_routing + assert_routing( + {:method => :get, :path => '/projects/33/files'}, + :controller => 'projects', :action => 'list_files', :id => '33' + ) + end + + def test_changelog_routing + assert_routing( + {:method => :get, :path => '/projects/44/changelog'}, + :controller => 'projects', :action => 'changelog', :id => '44' + ) + end + + def test_changelog + get :changelog, :id => 1 + assert_response :success + assert_template 'changelog' + assert_not_nil assigns(:versions) + end + + def test_roadmap_routing + assert_routing( + {:method => :get, :path => 'projects/33/roadmap'}, + :controller => 'projects', :action => 'roadmap', :id => '33' + ) end def test_roadmap @@ -147,7 +315,21 @@ class ProjectsControllerTest < Test::Unit::TestCase # Completed version appears assert assigns(:versions).include?(Version.find(1)) end - + + def test_project_activity_routing + assert_routing( + {:method => :get, :path => '/projects/1/activity'}, + :controller => 'projects', :action => 'activity', :id => '1' + ) + end + + def test_project_activity_atom_routing + assert_routing( + {:method => :get, :path => '/projects/1/activity.atom'}, + :controller => 'projects', :action => 'activity', :id => '1', :format => 'atom' + ) + end + def test_project_activity get :activity, :id => 1, :with_subprojects => 0 assert_response :success @@ -184,6 +366,10 @@ class ProjectsControllerTest < Test::Unit::TestCase } end + def test_global_activity_routing + assert_routing({:method => :get, :path => '/activity'}, :controller => 'projects', :action => 'activity') + end + def test_global_activity get :activity assert_response :success @@ -202,19 +388,57 @@ class ProjectsControllerTest < Test::Unit::TestCase } end + def test_user_activity + get :activity, :user_id => 2 + assert_response :success + assert_template 'activity' + assert_not_nil assigns(:events_by_day) + + assert_tag :tag => "h3", + :content => /#{3.day.ago.to_date.day}/, + :sibling => { :tag => "dl", + :child => { :tag => "dt", + :attributes => { :class => /issue/ }, + :child => { :tag => "a", + :content => /#{Issue.find(1).subject}/, + } + } + } + end + + def test_global_activity_atom_routing + assert_routing({:method => :get, :path => '/activity.atom'}, :controller => 'projects', :action => 'activity', :format => 'atom') + end + def test_activity_atom_feed get :activity, :format => 'atom' assert_response :success assert_template 'common/feed.atom.rxml' end - def test_archive + def test_archive_routing + assert_routing( + #TODO: use PUT to project path and modify form + {:method => :post, :path => 'projects/64/archive'}, + :controller => 'projects', :action => 'archive', :id => '64' + ) + end + + def test_archive @request.session[:user_id] = 1 # admin post :archive, :id => 1 assert_redirected_to 'admin/projects' assert !Project.find(1).active? end + def test_unarchive_routing + assert_routing( + #TODO: use PUT to project path and modify form + {:method => :post, :path => '/projects/567/unarchive'}, + :controller => 'projects', :action => 'unarchive', :id => '567' + ) + end + def test_unarchive @request.session[:user_id] = 1 # admin Project.find(1).archive @@ -223,6 +447,23 @@ class ProjectsControllerTest < Test::Unit::TestCase assert Project.find(1).active? end + def test_jump_should_redirect_to_active_tab + get :show, :id => 1, :jump => 'issues' + assert_redirected_to 'projects/ecookbook/issues' + end + + def test_jump_should_not_redirect_to_inactive_tab + get :show, :id => 3, :jump => 'documents' + assert_response :success + assert_template 'show' + end + + def test_jump_should_not_redirect_to_unknown_tab + get :show, :id => 3, :jump => 'foobar' + assert_response :success + assert_template 'show' + end + def test_project_menu assert_no_difference 'Redmine::MenuManager.items(:project_menu).size' do Redmine::MenuManager.map :project_menu do |menu| @@ -233,14 +474,17 @@ class ProjectsControllerTest < Test::Unit::TestCase get :show, :id => 1 assert_tag :div, :attributes => { :id => 'main-menu' }, - :descendant => { :tag => 'li', :child => { :tag => 'a', :content => 'Foo' } } + :descendant => { :tag => 'li', :child => { :tag => 'a', :content => 'Foo', + :attributes => { :class => 'foo' } } } assert_tag :div, :attributes => { :id => 'main-menu' }, - :descendant => { :tag => 'li', :child => { :tag => 'a', :content => 'Bar' }, + :descendant => { :tag => 'li', :child => { :tag => 'a', :content => 'Bar', + :attributes => { :class => 'bar' } }, :before => { :tag => 'li', :child => { :tag => 'a', :content => 'ECOOKBOOK' } } } assert_tag :div, :attributes => { :id => 'main-menu' }, - :descendant => { :tag => 'li', :child => { :tag => 'a', :content => 'ECOOKBOOK' }, + :descendant => { :tag => 'li', :child => { :tag => 'a', :content => 'ECOOKBOOK', + :attributes => { :class => 'hello' } }, :before => { :tag => 'li', :child => { :tag => 'a', :content => 'Activity' } } } # Remove the menu items diff --git a/test/functional/reports_controller_test.rb b/test/functional/reports_controller_test.rb new file mode 100644 index 000000000..b90d904f8 --- /dev/null +++ b/test/functional/reports_controller_test.rb @@ -0,0 +1,20 @@ +require File.dirname(__FILE__) + '/../test_helper' +require 'reports_controller' + +# Re-raise errors caught by the controller. +class ReportsController; def rescue_action(e) raise e end; end + + +class ReportsControllerTest < Test::Unit::TestCase + def test_issue_report_routing + assert_routing( + {:method => :get, :path => '/projects/567/issues/report'}, + :controller => 'reports', :action => 'issue_report', :id => '567' + ) + assert_routing( + {:method => :get, :path => '/projects/567/issues/report/assigned_to'}, + :controller => 'reports', :action => 'issue_report', :id => '567', :detail => 'assigned_to' + ) + + end +end diff --git a/test/functional/repositories_controller_test.rb b/test/functional/repositories_controller_test.rb index 2892f3bd1..ccf5e77ba 100644 --- a/test/functional/repositories_controller_test.rb +++ b/test/functional/repositories_controller_test.rb @@ -31,25 +31,134 @@ class RepositoriesControllerTest < Test::Unit::TestCase User.current = nil end + def test_show_routing + assert_routing( + {:method => :get, :path => '/projects/redmine/repository'}, + :controller => 'repositories', :action => 'show', :id => 'redmine' + ) + end + + def test_edit_routing + assert_routing( + {:method => :get, :path => '/projects/world_domination/repository/edit'}, + :controller => 'repositories', :action => 'edit', :id => 'world_domination' + ) + assert_routing( + {:method => :post, :path => '/projects/world_domination/repository/edit'}, + :controller => 'repositories', :action => 'edit', :id => 'world_domination' + ) + end + + def test_revisions_routing + assert_routing( + {:method => :get, :path => '/projects/redmine/repository/revisions'}, + :controller => 'repositories', :action => 'revisions', :id => 'redmine' + ) + end + + def test_revisions_atom_routing + assert_routing( + {:method => :get, :path => '/projects/redmine/repository/revisions.atom'}, + :controller => 'repositories', :action => 'revisions', :id => 'redmine', :format => 'atom' + ) + end + def test_revisions get :revisions, :id => 1 assert_response :success assert_template 'revisions' assert_not_nil assigns(:changesets) end + + def test_revision_routing + assert_routing( + {:method => :get, :path => '/projects/restmine/repository/revisions/2457'}, + :controller => 'repositories', :action => 'revision', :id => 'restmine', :rev => '2457' + ) + end def test_revision_with_before_nil_and_afer_normal get :revision, {:id => 1, :rev => 1} assert_response :success assert_template 'revision' assert_no_tag :tag => "div", :attributes => { :class => "contextual" }, - :child => { :tag => "a", :attributes => { :href => '/repositories/revision/ecookbook/0'} + :child => { :tag => "a", :attributes => { :href => '/projects/ecookbook/repository/revisions/0'} } assert_tag :tag => "div", :attributes => { :class => "contextual" }, - :child => { :tag => "a", :attributes => { :href => '/repositories/revision/ecookbook/2'} + :child => { :tag => "a", :attributes => { :href => '/projects/ecookbook/repository/revisions/2'} } end + + def test_diff_routing + assert_routing( + {:method => :get, :path => '/projects/restmine/repository/revisions/2457/diff'}, + :controller => 'repositories', :action => 'diff', :id => 'restmine', :rev => '2457' + ) + end + + def test_unified_diff_routing + assert_routing( + {:method => :get, :path => '/projects/restmine/repository/revisions/2457/diff.diff'}, + :controller => 'repositories', :action => 'diff', :id => 'restmine', :rev => '2457', :format => 'diff' + ) + end + + def test_diff_path_routing + assert_routing( + {:method => :get, :path => '/projects/restmine/repository/diff/path/to/file.c'}, + :controller => 'repositories', :action => 'diff', :id => 'restmine', :path => %w[path to file.c] + ) + end + def test_diff_path_routing_with_revision + assert_routing( + {:method => :get, :path => '/projects/restmine/repository/revisions/2/diff/path/to/file.c'}, + :controller => 'repositories', :action => 'diff', :id => 'restmine', :path => %w[path to file.c], :rev => '2' + ) + end + + def test_browse_routing + assert_routing( + {:method => :get, :path => '/projects/restmine/repository/browse/path/to/dir'}, + :controller => 'repositories', :action => 'browse', :id => 'restmine', :path => %w[path to dir] + ) + end + + def test_entry_routing + assert_routing( + {:method => :get, :path => '/projects/restmine/repository/entry/path/to/file.c'}, + :controller => 'repositories', :action => 'entry', :id => 'restmine', :path => %w[path to file.c] + ) + end + + def test_entry_routing_with_revision + assert_routing( + {:method => :get, :path => '/projects/restmine/repository/revisions/2/entry/path/to/file.c'}, + :controller => 'repositories', :action => 'entry', :id => 'restmine', :path => %w[path to file.c], :rev => '2' + ) + end + + def test_annotate_routing + assert_routing( + {:method => :get, :path => '/projects/restmine/repository/annotate/path/to/file.c'}, + :controller => 'repositories', :action => 'annotate', :id => 'restmine', :path => %w[path to file.c] + ) + end + + def test_changesrouting + assert_routing( + {:method => :get, :path => '/projects/restmine/repository/changes/path/to/file.c'}, + :controller => 'repositories', :action => 'changes', :id => 'restmine', :path => %w[path to file.c] + ) + end + + def test_statistics_routing + assert_routing( + {:method => :get, :path => '/projects/restmine/repository/statistics'}, + :controller => 'repositories', :action => 'stats', :id => 'restmine' + ) + end + def test_graph_commits_per_month get :graph, :id => 1, :graph => 'commits_per_month' assert_response :success @@ -61,4 +170,38 @@ class RepositoriesControllerTest < Test::Unit::TestCase assert_response :success assert_equal 'image/svg+xml', @response.content_type end + + def test_committers + @request.session[:user_id] = 2 + # add a commit with an unknown user + Changeset.create!(:repository => Project.find(1).repository, :committer => 'foo', :committed_on => Time.now, :revision => 100, :comments => 'Committed by foo.') + + get :committers, :id => 1 + assert_response :success + assert_template 'committers' + + assert_tag :td, :content => 'dlopper', + :sibling => { :tag => 'td', + :child => { :tag => 'select', :attributes => { :name => %r{^committers\[\d+\]\[\]$} }, + :child => { :tag => 'option', :content => 'Dave Lopper', + :attributes => { :value => '3', :selected => 'selected' }}}} + assert_tag :td, :content => 'foo', + :sibling => { :tag => 'td', + :child => { :tag => 'select', :attributes => { :name => %r{^committers\[\d+\]\[\]$} }}} + assert_no_tag :td, :content => 'foo', + :sibling => { :tag => 'td', + :descendant => { :tag => 'option', :attributes => { :selected => 'selected' }}} + end + + def test_map_committers + @request.session[:user_id] = 2 + # add a commit with an unknown user + c = Changeset.create!(:repository => Project.find(1).repository, :committer => 'foo', :committed_on => Time.now, :revision => 100, :comments => 'Committed by foo.') + + assert_no_difference "Changeset.count(:conditions => 'user_id = 3')" do + post :committers, :id => 1, :committers => { '0' => ['foo', '2'], '1' => ['dlopper', '3']} + assert_redirected_to '/repositories/committers/ecookbook' + assert_equal User.find(2), c.reload.user + end + end end diff --git a/test/functional/repositories_subversion_controller_test.rb b/test/functional/repositories_subversion_controller_test.rb index 245a170d1..a3918a922 100644 --- a/test/functional/repositories_subversion_controller_test.rb +++ b/test/functional/repositories_subversion_controller_test.rb @@ -78,13 +78,15 @@ class RepositoriesSubversionControllerTest < Test::Unit::TestCase get :changes, :id => 1, :path => ['subversion_test', 'folder', 'helloworld.rb' ] assert_response :success assert_template 'changes' - # svn properties - assert_not_nil assigns(:properties) - assert_equal 'native', assigns(:properties)['svn:eol-style'] - assert_tag :ul, - :child => { :tag => 'li', - :child => { :tag => 'b', :content => 'svn:eol-style' }, - :child => { :tag => 'span', :content => 'native' } } + # svn properties displayed with svn >= 1.5 only + if Redmine::Scm::Adapters::SubversionAdapter.client_version_above?([1, 5, 0]) + assert_not_nil assigns(:properties) + assert_equal 'native', assigns(:properties)['svn:eol-style'] + assert_tag :ul, + :child => { :tag => 'li', + :child => { :tag => 'b', :content => 'svn:eol-style' }, + :child => { :tag => 'span', :content => 'native' } } + end end def test_entry @@ -129,11 +131,11 @@ class RepositoriesSubversionControllerTest < Test::Unit::TestCase :child => { :tag => 'li', # link to the entry at rev 2 :child => { :tag => 'a', - :attributes => {:href => '/repositories/entry/ecookbook/test/some/path/in/the/repo?rev=2'}, + :attributes => {:href => '/projects/ecookbook/repository/revisions/2/entry/test/some/path/in/the/repo'}, :content => 'repo', # link to partial diff :sibling => { :tag => 'a', - :attributes => { :href => '/repositories/diff/ecookbook/test/some/path/in/the/repo?rev=2' } + :attributes => { :href => '/projects/ecookbook/repository/revisions/2/diff/test/some/path/in/the/repo' } } } } @@ -151,11 +153,11 @@ class RepositoriesSubversionControllerTest < Test::Unit::TestCase :child => { :tag => 'li', # link to the entry at rev 2 :child => { :tag => 'a', - :attributes => {:href => '/repositories/entry/ecookbook/path/in/the/repo?rev=2'}, + :attributes => {:href => '/projects/ecookbook/repository/revisions/2/entry/path/in/the/repo'}, :content => 'repo', # link to partial diff :sibling => { :tag => 'a', - :attributes => { :href => '/repositories/diff/ecookbook/path/in/the/repo?rev=2' } + :attributes => { :href => '/projects/ecookbook/repository/revisions/2/diff/path/in/the/repo' } } } } diff --git a/test/functional/roles_controller_test.rb b/test/functional/roles_controller_test.rb index d70a4f0c3..188e79e2d 100644 --- a/test/functional/roles_controller_test.rb +++ b/test/functional/roles_controller_test.rb @@ -118,46 +118,6 @@ class RolesControllerTest < Test::Unit::TestCase assert_not_nil Role.find_by_id(1) end - def test_get_workflow - get :workflow - assert_response :success - assert_template 'workflow' - assert_not_nil assigns(:roles) - assert_not_nil assigns(:trackers) - end - - def test_get_workflow_with_role_and_tracker - get :workflow, :role_id => 2, :tracker_id => 1 - assert_response :success - assert_template 'workflow' - # allowed transitions - assert_tag :tag => 'input', :attributes => { :type => 'checkbox', - :name => 'issue_status[2][]', - :value => '1', - :checked => 'checked' } - # not allowed - assert_tag :tag => 'input', :attributes => { :type => 'checkbox', - :name => 'issue_status[2][]', - :value => '3', - :checked => nil } - end - - def test_post_workflow - post :workflow, :role_id => 2, :tracker_id => 1, :issue_status => {'4' => ['5'], '3' => ['1', '2']} - assert_redirected_to 'roles/workflow' - - assert_equal 3, Workflow.count(:conditions => {:tracker_id => 1, :role_id => 2}) - assert_not_nil Workflow.find(:first, :conditions => {:role_id => 2, :tracker_id => 1, :old_status_id => 3, :new_status_id => 2}) - assert_nil Workflow.find(:first, :conditions => {:role_id => 2, :tracker_id => 1, :old_status_id => 5, :new_status_id => 4}) - end - - def test_clear_workflow - assert Workflow.count(:conditions => {:tracker_id => 1, :role_id => 2}) > 0 - - post :workflow, :role_id => 2, :tracker_id => 1 - assert_equal 0, Workflow.count(:conditions => {:tracker_id => 1, :role_id => 2}) - end - def test_get_report get :report assert_response :success diff --git a/test/functional/search_controller_test.rb b/test/functional/search_controller_test.rb index ce06ec298..b804bbd28 100644 --- a/test/functional/search_controller_test.rb +++ b/test/functional/search_controller_test.rb @@ -45,6 +45,17 @@ class SearchControllerTest < Test::Unit::TestCase assert_tag :a, :content => 'Changesets (4)' end + def test_search_issues + get :index, :q => 'issue', :issues => 1 + assert_response :success + assert_template 'index' + + assert assigns(:results).include?(Issue.find(8)) + assert assigns(:results).include?(Issue.find(5)) + assert_tag :dt, :attributes => { :class => /issue closed/ }, + :child => { :tag => 'a', :content => /Closed/ } + end + def test_search_project_and_subprojects get :index, :id => 1, :q => 'recipe subproject', :scope => 'subprojects', :submit => 'Search' assert_response :success diff --git a/test/functional/sys_api_test.rb b/test/functional/sys_api_test.rb deleted file mode 100644 index 48ed780d0..000000000 --- a/test/functional/sys_api_test.rb +++ /dev/null @@ -1,50 +0,0 @@ -require File.dirname(__FILE__) + '/../test_helper' -require 'sys_controller' - -# Re-raise errors caught by the controller. -class SysController; def rescue_action(e) raise e end; end - -class SysControllerTest < Test::Unit::TestCase - fixtures :projects, :enabled_modules, :repositories - - def setup - @controller = SysController.new - @request = ActionController::TestRequest.new - @response = ActionController::TestResponse.new - # Enable WS - Setting.sys_api_enabled = 1 - end - - def test_projects_with_repository_enabled - result = invoke :projects_with_repository_enabled - assert_equal EnabledModule.count(:all, :conditions => {:name => 'repository'}), result.size - - project = result.first - assert project.is_a?(AWSProjectWithRepository) - - assert project.respond_to?(:id) - assert_equal 1, project.id - - assert project.respond_to?(:identifier) - assert_equal 'ecookbook', project.identifier - - assert project.respond_to?(:name) - assert_equal 'eCookbook', project.name - - assert project.respond_to?(:is_public) - assert project.is_public - - assert project.respond_to?(:repository) - assert project.repository.is_a?(Repository) - end - - def test_repository_created - project = Project.find(3) - assert_nil project.repository - assert invoke(:repository_created, project.identifier, 'Subversion', 'http://localhost/svn') - project.reload - assert_not_nil project.repository - assert project.repository.is_a?(Repository::Subversion) - assert_equal 'http://localhost/svn', project.repository.url - end -end diff --git a/test/functional/sys_controller_test.rb b/test/functional/sys_controller_test.rb new file mode 100644 index 000000000..47228a4db --- /dev/null +++ b/test/functional/sys_controller_test.rb @@ -0,0 +1,55 @@ +# Redmine - project management software +# Copyright (C) 2006-2009 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +require File.dirname(__FILE__) + '/../test_helper' +require 'sys_controller' + +# Re-raise errors caught by the controller. +class SysController; def rescue_action(e) raise e end; end + +class SysControllerTest < Test::Unit::TestCase + fixtures :projects, :repositories + + def setup + @controller = SysController.new + @request = ActionController::TestRequest.new + @response = ActionController::TestResponse.new + Setting.sys_api_enabled = '1' + end + + def test_projects_with_repository_enabled + get :projects + assert_response :success + assert_equal 'application/xml', @response.content_type + with_options :tag => 'projects' do |test| + test.assert_tag :children => { :count => Project.active.has_module(:repository).count } + end + end + + def test_create_project_repository + assert_nil Project.find(4).repository + + post :create_project_repository, :id => 4, + :vendor => 'Subversion', + :repository => { :url => 'file:///create/project/repository/subproject2'} + assert_response :created + + r = Project.find(4).repository + assert r.is_a?(Repository::Subversion) + assert_equal 'file:///create/project/repository/subproject2', r.url + end +end diff --git a/test/functional/timelog_controller_test.rb b/test/functional/timelog_controller_test.rb index 28f2a28e2..46c3f3ef8 100644 --- a/test/functional/timelog_controller_test.rb +++ b/test/functional/timelog_controller_test.rb @@ -30,6 +30,28 @@ class TimelogControllerTest < Test::Unit::TestCase @response = ActionController::TestResponse.new end + def test_edit_routing + assert_routing( + {:method => :get, :path => '/issues/567/time_entries/new'}, + :controller => 'timelog', :action => 'edit', :issue_id => '567' + ) + assert_routing( + {:method => :get, :path => '/projects/ecookbook/time_entries/new'}, + :controller => 'timelog', :action => 'edit', :project_id => 'ecookbook' + ) + assert_routing( + {:method => :get, :path => '/projects/ecookbook/issues/567/time_entries/new'}, + :controller => 'timelog', :action => 'edit', :project_id => 'ecookbook', :issue_id => '567' + ) + + #TODO: change new form to POST to issue_time_entries_path instead of to edit action + #TODO: change edit form to PUT to time_entry_path + assert_routing( + {:method => :get, :path => '/time_entries/22/edit'}, + :controller => 'timelog', :action => 'edit', :id => '22' + ) + end + def test_get_edit @request.session[:user_id] = 3 get :edit, :project_id => 1 @@ -40,7 +62,18 @@ class TimelogControllerTest < Test::Unit::TestCase :content => 'Development' end + def test_get_edit_existing_time + @request.session[:user_id] = 2 + get :edit, :id => 2, :project_id => nil + assert_response :success + assert_template 'edit' + # Default activity selected + assert_tag :tag => 'form', :attributes => { :action => '/projects/ecookbook/timelog/edit/2' } + end + def test_post_edit + # TODO: should POST to issues’ time log instead of project. change form + # and routing @request.session[:user_id] = 3 post :edit, :project_id => 1, :time_entry => {:comments => 'Some work on TimelogControllerTest', @@ -49,7 +82,7 @@ class TimelogControllerTest < Test::Unit::TestCase :spent_on => '2008-03-14', :issue_id => '1', :hours => '7.3'} - assert_redirected_to 'projects/ecookbook/timelog/details' + assert_redirected_to :action => 'details', :project_id => 'ecookbook' i = Issue.find(1) t = TimeEntry.find_by_comments('Some work on TimelogControllerTest') @@ -70,7 +103,7 @@ class TimelogControllerTest < Test::Unit::TestCase post :edit, :id => 1, :time_entry => {:issue_id => '2', :hours => '8'} - assert_redirected_to 'projects/ecookbook/timelog/details' + assert_redirected_to :action => 'details', :project_id => 'ecookbook' entry.reload assert_equal 8, entry.hours @@ -78,18 +111,44 @@ class TimelogControllerTest < Test::Unit::TestCase assert_equal 2, entry.user_id end + def test_destroy_routing + #TODO: use DELETE to time_entry_path + assert_routing( + {:method => :post, :path => '/time_entries/55/destroy'}, + :controller => 'timelog', :action => 'destroy', :id => '55' + ) + end + def test_destroy @request.session[:user_id] = 2 post :destroy, :id => 1 - assert_redirected_to 'projects/ecookbook/timelog/details' + assert_redirected_to :action => 'details', :project_id => 'ecookbook' assert_nil TimeEntry.find_by_id(1) end - + + def test_report_routing + assert_routing( + {:method => :get, :path => '/projects/567/time_entries/report'}, + :controller => 'timelog', :action => 'report', :project_id => '567' + ) + assert_routing( + {:method => :get, :path => '/projects/567/time_entries/report.csv'}, + :controller => 'timelog', :action => 'report', :project_id => '567', :format => 'csv' + ) + end + def test_report_no_criteria get :report, :project_id => 1 assert_response :success assert_template 'report' end + + def test_report_routing_for_all_projects + assert_routing( + {:method => :get, :path => '/time_entries/report'}, + :controller => 'timelog', :action => 'report' + ) + end def test_report_all_projects get :report @@ -103,7 +162,7 @@ class TimelogControllerTest < Test::Unit::TestCase r.permissions_will_change! r.save get :report - assert_redirected_to '/account/login' + assert_redirected_to '/login?back_url=http%3A%2F%2Ftest.host%2Ftime_entries%2Freport' end def test_report_all_projects_one_criteria @@ -201,7 +260,14 @@ class TimelogControllerTest < Test::Unit::TestCase assert_not_nil assigns(:total_hours) assert_equal "162.90", "%.2f" % assigns(:total_hours) end - + + def test_project_details_routing + assert_routing( + {:method => :get, :path => '/projects/567/time_entries'}, + :controller => 'timelog', :action => 'details', :project_id => '567' + ) + end + def test_details_at_project_level get :details, :project_id => 1 assert_response :success @@ -239,6 +305,23 @@ class TimelogControllerTest < Test::Unit::TestCase assert_equal Date.today, assigns(:to) end + def test_issue_details_routing + assert_routing( + {:method => :get, :path => 'time_entries'}, + :controller => 'timelog', :action => 'details' + ) + assert_routing( + {:method => :get, :path => '/issues/234/time_entries'}, + :controller => 'timelog', :action => 'details', :issue_id => '234' + ) + # TODO: issue detail page shouldnt link to project_issue_time_entries_path but to normal issues one + # doesnt seem to have effect on resulting page so controller can be left untouched + assert_routing( + {:method => :get, :path => '/projects/ecookbook/issues/123/time_entries'}, + :controller => 'timelog', :action => 'details', :project_id => 'ecookbook', :issue_id => '123' + ) + end + def test_details_at_issue_level get :details, :issue_id => 1 assert_response :success @@ -252,6 +335,39 @@ class TimelogControllerTest < Test::Unit::TestCase assert_equal '2007-04-22'.to_date, assigns(:to) end + def test_details_formatted_routing + assert_routing( + {:method => :get, :path => 'time_entries.atom'}, + :controller => 'timelog', :action => 'details', :format => 'atom' + ) + assert_routing( + {:method => :get, :path => 'time_entries.csv'}, + :controller => 'timelog', :action => 'details', :format => 'csv' + ) + end + + def test_details_for_project_formatted_routing + assert_routing( + {:method => :get, :path => '/projects/567/time_entries.atom'}, + :controller => 'timelog', :action => 'details', :format => 'atom', :project_id => '567' + ) + assert_routing( + {:method => :get, :path => '/projects/567/time_entries.csv'}, + :controller => 'timelog', :action => 'details', :format => 'csv', :project_id => '567' + ) + end + + def test_details_for_issue_formatted_routing + assert_routing( + {:method => :get, :path => '/projects/ecookbook/issues/123/time_entries.atom'}, + :controller => 'timelog', :action => 'details', :project_id => 'ecookbook', :issue_id => '123', :format => 'atom' + ) + assert_routing( + {:method => :get, :path => '/projects/ecookbook/issues/123/time_entries.csv'}, + :controller => 'timelog', :action => 'details', :project_id => 'ecookbook', :issue_id => '123', :format => 'csv' + ) + end + def test_details_atom_feed get :details, :project_id => 1, :format => 'atom' assert_response :success diff --git a/test/functional/trackers_controller_test.rb b/test/functional/trackers_controller_test.rb new file mode 100644 index 000000000..89bbf228f --- /dev/null +++ b/test/functional/trackers_controller_test.rb @@ -0,0 +1,68 @@ +# Redmine - project management software +# Copyright (C) 2006-2009 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +require File.dirname(__FILE__) + '/../test_helper' +require 'trackers_controller' + +# Re-raise errors caught by the controller. +class TrackersController; def rescue_action(e) raise e end; end + +class TrackersControllerTest < Test::Unit::TestCase + fixtures :trackers, :projects, :projects_trackers, :users + + def setup + @controller = TrackersController.new + @request = ActionController::TestRequest.new + @response = ActionController::TestResponse.new + User.current = nil + @request.session[:user_id] = 1 # admin + end + + def test_get_edit + Tracker.find(1).project_ids = [1, 3] + + get :edit, :id => 1 + assert_response :success + assert_template 'edit' + + assert_tag :input, :attributes => { :name => 'tracker[project_ids][]', + :value => '1', + :checked => 'checked' } + + assert_tag :input, :attributes => { :name => 'tracker[project_ids][]', + :value => '2', + :checked => nil } + + assert_tag :input, :attributes => { :name => 'tracker[project_ids][]', + :value => '', + :type => 'hidden'} + end + + def test_post_edit + post :edit, :id => 1, :tracker => { :name => 'Renamed', + :project_ids => ['1', '2', ''] } + assert_redirected_to '/trackers/list' + assert_equal [1, 2], Tracker.find(1).project_ids.sort + end + + def test_post_edit_without_projects + post :edit, :id => 1, :tracker => { :name => 'Renamed', + :project_ids => [''] } + assert_redirected_to '/trackers/list' + assert Tracker.find(1).project_ids.empty? + end +end diff --git a/test/functional/users_controller_test.rb b/test/functional/users_controller_test.rb index 8629a7131..42e69f48d 100644 --- a/test/functional/users_controller_test.rb +++ b/test/functional/users_controller_test.rb @@ -32,11 +32,27 @@ class UsersControllerTest < Test::Unit::TestCase @request.session[:user_id] = 1 # admin end + def test_index_routing + #TODO: unify with list + assert_generates( + '/users', + :controller => 'users', :action => 'index' + ) + end + def test_index get :index assert_response :success assert_template 'list' end + + def test_list_routing + #TODO: rename action to index + assert_routing( + {:method => :get, :path => '/users'}, + :controller => 'users', :action => 'list' + ) + end def test_list get :list @@ -47,16 +63,80 @@ class UsersControllerTest < Test::Unit::TestCase assert_nil assigns(:users).detect {|u| !u.active?} end + def test_list_with_name_filter + get :list, :name => 'john' + assert_response :success + assert_template 'list' + users = assigns(:users) + assert_not_nil users + assert_equal 1, users.size + assert_equal 'John', users.first.firstname + end + + def test_add_routing + assert_routing( + {:method => :get, :path => '/users/new'}, + :controller => 'users', :action => 'add' + ) + assert_recognizes( + #TODO: remove this and replace with POST to collection, need to modify form + {:controller => 'users', :action => 'add'}, + {:method => :post, :path => '/users/new'} + ) + assert_recognizes( + {:controller => 'users', :action => 'add'}, + {:method => :post, :path => '/users'} + ) + end + + def test_edit_routing + assert_routing( + {:method => :get, :path => '/users/444/edit'}, + :controller => 'users', :action => 'edit', :id => '444' + ) + assert_routing( + {:method => :get, :path => '/users/222/edit/membership'}, + :controller => 'users', :action => 'edit', :id => '222', :tab => 'membership' + ) + assert_recognizes( + #TODO: use PUT on user_path, modify form + {:controller => 'users', :action => 'edit', :id => '444'}, + {:method => :post, :path => '/users/444/edit'} + ) + end + + def test_add_membership_routing + assert_routing( + {:method => :post, :path => '/users/123/memberships'}, + :controller => 'users', :action => 'edit_membership', :id => '123' + ) + end + + def test_edit_membership_routing + assert_routing( + {:method => :post, :path => '/users/123/memberships/55'}, + :controller => 'users', :action => 'edit_membership', :id => '123', :membership_id => '55' + ) + end + def test_edit_membership post :edit_membership, :id => 2, :membership_id => 1, :membership => { :role_id => 2} - assert_redirected_to 'users/edit/2' + assert_redirected_to :action => 'edit', :id => '2', :tab => 'memberships' assert_equal 2, Member.find(1).role_id end + def test_destroy_membership + assert_routing( + #TODO: use DELETE method on user_membership_path, modify form + {:method => :post, :path => '/users/567/memberships/12/destroy'}, + :controller => 'users', :action => 'destroy_membership', :id => '567', :membership_id => '12' + ) + end + def test_destroy_membership post :destroy_membership, :id => 2, :membership_id => 1 - assert_redirected_to 'users/edit/2' + assert_redirected_to :action => 'edit', :id => '2', :tab => 'memberships' assert_nil Member.find_by_id(1) end end diff --git a/test/functional/versions_controller_test.rb b/test/functional/versions_controller_test.rb index 3a118701a..2ddf3a9f1 100644 --- a/test/functional/versions_controller_test.rb +++ b/test/functional/versions_controller_test.rb @@ -52,7 +52,7 @@ class VersionsControllerTest < Test::Unit::TestCase post :edit, :id => 2, :version => { :name => 'New version name', :effective_date => Date.today.strftime("%Y-%m-%d")} - assert_redirected_to 'projects/settings/ecookbook' + assert_redirected_to :controller => 'projects', :action => 'settings', :tab => 'versions', :id => 'ecookbook' version = Version.find(2) assert_equal 'New version name', version.name assert_equal Date.today, version.effective_date @@ -61,7 +61,7 @@ class VersionsControllerTest < Test::Unit::TestCase def test_destroy @request.session[:user_id] = 2 post :destroy, :id => 3 - assert_redirected_to 'projects/settings/ecookbook' + assert_redirected_to :controller => 'projects', :action => 'settings', :tab => 'versions', :id => 'ecookbook' assert_nil Version.find_by_id(3) end diff --git a/test/functional/welcome_controller_test.rb b/test/functional/welcome_controller_test.rb index df565a751..b45cb97c8 100644 --- a/test/functional/welcome_controller_test.rb +++ b/test/functional/welcome_controller_test.rb @@ -60,4 +60,11 @@ class WelcomeControllerTest < Test::Unit::TestCase get :index assert_equal :fr, @controller.current_language end + + def test_robots + get :robots + assert_response :success + assert_equal 'text/plain', @response.content_type + assert @response.body.match(%r{^Disallow: /projects/ecookbook/issues$}) + end end diff --git a/test/functional/wiki_controller_test.rb b/test/functional/wiki_controller_test.rb index b5325357c..40dc04ae4 100644 --- a/test/functional/wiki_controller_test.rb +++ b/test/functional/wiki_controller_test.rb @@ -31,6 +31,21 @@ class WikiControllerTest < Test::Unit::TestCase User.current = nil end + def test_index_routing + assert_routing( + {:method => :get, :path => '/projects/567/wiki'}, + :controller => 'wiki', :action => 'index', :id => '567' + ) + assert_routing( + {:method => :get, :path => '/projects/567/wiki/lalala'}, + :controller => 'wiki', :action => 'index', :id => '567', :page => 'lalala' + ) + assert_generates( + '/projects/567/wiki', + :controller => 'wiki', :action => 'index', :id => '567', :page => nil + ) + end + def test_show_start_page get :index, :id => 'ecookbook' assert_response :success @@ -40,7 +55,7 @@ class WikiControllerTest < Test::Unit::TestCase # child_pages macro assert_tag :ul, :attributes => { :class => 'pages-hierarchy' }, :child => { :tag => 'li', - :child => { :tag => 'a', :attributes => { :href => '/wiki/ecookbook/Page_with_an_inline_image' }, + :child => { :tag => 'a', :attributes => { :href => '/projects/ecookbook/wiki/Page_with_an_inline_image' }, :content => 'Page with an inline image' } } end @@ -67,6 +82,17 @@ class WikiControllerTest < Test::Unit::TestCase assert_template 'edit' end + def test_edit_routing + assert_routing( + {:method => :get, :path => '/projects/567/wiki/my_page/edit'}, + :controller => 'wiki', :action => 'edit', :id => '567', :page => 'my_page' + ) + assert_recognizes(#TODO: use PUT to page path, adjust forms accordingly + {:controller => 'wiki', :action => 'edit', :id => '567', :page => 'my_page'}, + {:method => :post, :path => '/projects/567/wiki/my_page/edit'} + ) + end + def test_create_page @request.session[:user_id] = 2 post :edit, :id => 1, @@ -74,13 +100,20 @@ class WikiControllerTest < Test::Unit::TestCase :content => {:comments => 'Created the page', :text => "h1. New page\n\nThis is a new page", :version => 0} - assert_redirected_to 'wiki/ecookbook/New_page' + assert_redirected_to :action => 'index', :id => 'ecookbook', :page => 'New_page' page = Project.find(1).wiki.find_page('New page') assert !page.new_record? assert_not_nil page.content assert_equal 'Created the page', page.content.comments end + def test_preview_routing + assert_routing( + {:method => :post, :path => '/projects/567/wiki/CookBook_documentation/preview'}, + :controller => 'wiki', :action => 'preview', :id => '567', :page => 'CookBook_documentation' + ) + end + def test_preview @request.session[:user_id] = 2 xhr :post, :preview, :id => 1, :page => 'CookBook_documentation', @@ -103,6 +136,13 @@ class WikiControllerTest < Test::Unit::TestCase assert_tag :tag => 'h1', :content => /New page/ end + def test_history_routing + assert_routing( + {:method => :get, :path => '/projects/1/wiki/CookBook_documentation/history'}, + :controller => 'wiki', :action => 'history', :id => '1', :page => 'CookBook_documentation' + ) + end + def test_history get :history, :id => 1, :page => 'CookBook_documentation' assert_response :success @@ -120,6 +160,13 @@ class WikiControllerTest < Test::Unit::TestCase assert_equal 1, assigns(:versions).size assert_select "input[type=submit][name=commit]", false end + + def test_diff_routing + assert_routing( + {:method => :get, :path => '/projects/1/wiki/CookBook_documentation/diff/2/vs/1'}, + :controller => 'wiki', :action => 'diff', :id => '1', :page => 'CookBook_documentation', :version => '2', :version_from => '1' + ) + end def test_diff get :diff, :id => 1, :page => 'CookBook_documentation', :version => 2, :version_from => 1 @@ -129,6 +176,13 @@ class WikiControllerTest < Test::Unit::TestCase :content => /updated/ end + def test_annotate_routing + assert_routing( + {:method => :get, :path => '/projects/1/wiki/CookBook_documentation/annotate/2'}, + :controller => 'wiki', :action => 'annotate', :id => '1', :page => 'CookBook_documentation', :version => '2' + ) + end + def test_annotate get :annotate, :id => 1, :page => 'CookBook_documentation', :version => 2 assert_response :success @@ -143,12 +197,24 @@ class WikiControllerTest < Test::Unit::TestCase :child => { :tag => 'td', :content => /Some updated \[\[documentation\]\] here/ } end + def test_rename_routing + assert_routing( + {:method => :get, :path => '/projects/22/wiki/ladida/rename'}, + :controller => 'wiki', :action => 'rename', :id => '22', :page => 'ladida' + ) + assert_recognizes( + #TODO: should be moved into a update action and use a PUT to the page URI + {:controller => 'wiki', :action => 'rename', :id => '22', :page => 'ladida'}, + {:method => :post, :path => '/projects/22/wiki/ladida/rename'} + ) + end + def test_rename_with_redirect @request.session[:user_id] = 2 post :rename, :id => 1, :page => 'Another_page', :wiki_page => { :title => 'Another renamed page', :redirect_existing_links => 1 } - assert_redirected_to 'wiki/ecookbook/Another_renamed_page' + assert_redirected_to :action => 'index', :id => 'ecookbook', :page => 'Another_renamed_page' wiki = Project.find(1).wiki # Check redirects assert_not_nil wiki.find_page('Another page') @@ -160,16 +226,43 @@ class WikiControllerTest < Test::Unit::TestCase post :rename, :id => 1, :page => 'Another_page', :wiki_page => { :title => 'Another renamed page', :redirect_existing_links => "0" } - assert_redirected_to 'wiki/ecookbook/Another_renamed_page' + assert_redirected_to :action => 'index', :id => 'ecookbook', :page => 'Another_renamed_page' wiki = Project.find(1).wiki # Check that there's no redirects assert_nil wiki.find_page('Another page') end + def test_destroy_routing + assert_recognizes( + #TODO: should use DELETE on page URI + {:controller => 'wiki', :action => 'destroy', :id => '22', :page => 'ladida'}, + {:method => :post, :path => 'projects/22/wiki/ladida/destroy'} + ) + end + def test_destroy @request.session[:user_id] = 2 post :destroy, :id => 1, :page => 'CookBook_documentation' - assert_redirected_to 'wiki/ecookbook/Page_index/special' + assert_redirected_to :action => 'special', :id => 'ecookbook', :page => 'Page_index' + end + + def test_special_routing + assert_routing( + {:method => :get, :path => '/projects/567/wiki/page_index'}, + :controller => 'wiki', :action => 'special', :id => '567', :page => 'page_index' + ) + assert_routing( + {:method => :get, :path => '/projects/567/wiki/Page_Index'}, + :controller => 'wiki', :action => 'special', :id => '567', :page => 'Page_Index' + ) + assert_routing( + {:method => :get, :path => '/projects/567/wiki/date_index'}, + :controller => 'wiki', :action => 'special', :id => '567', :page => 'date_index' + ) + assert_routing( + {:method => :get, :path => '/projects/567/wiki/export'}, + :controller => 'wiki', :action => 'special', :id => '567', :page => 'export' + ) end def test_page_index @@ -181,13 +274,13 @@ class WikiControllerTest < Test::Unit::TestCase assert_equal Project.find(1).wiki.pages.size, pages.size assert_tag :ul, :attributes => { :class => 'pages-hierarchy' }, - :child => { :tag => 'li', :child => { :tag => 'a', :attributes => { :href => '/wiki/ecookbook/CookBook_documentation' }, + :child => { :tag => 'li', :child => { :tag => 'a', :attributes => { :href => '/projects/ecookbook/wiki/CookBook_documentation' }, :content => 'CookBook documentation' }, :child => { :tag => 'ul', :child => { :tag => 'li', - :child => { :tag => 'a', :attributes => { :href => '/wiki/ecookbook/Page_with_an_inline_image' }, + :child => { :tag => 'a', :attributes => { :href => '/projects/ecookbook/wiki/Page_with_an_inline_image' }, :content => 'Page with an inline image' } } } }, - :child => { :tag => 'li', :child => { :tag => 'a', :attributes => { :href => '/wiki/ecookbook/Another_page' }, + :child => { :tag => 'li', :child => { :tag => 'a', :attributes => { :href => '/projects/ecookbook/wiki/Another_page' }, :content => 'Another page' } } end @@ -196,12 +289,19 @@ class WikiControllerTest < Test::Unit::TestCase assert_response 404 end + def test_protect_routing + assert_routing( + {:method => :post, :path => 'projects/22/wiki/ladida/protect'}, + {:controller => 'wiki', :action => 'protect', :id => '22', :page => 'ladida'} + ) + end + def test_protect_page page = WikiPage.find_by_wiki_id_and_title(1, 'Another_page') assert !page.protected? @request.session[:user_id] = 2 post :protect, :id => 1, :page => page.title, :protected => '1' - assert_redirected_to 'wiki/ecookbook/Another_page' + assert_redirected_to :action => 'index', :id => 'ecookbook', :page => 'Another_page' assert page.reload.protected? end @@ -210,7 +310,7 @@ class WikiControllerTest < Test::Unit::TestCase assert page.protected? @request.session[:user_id] = 2 post :protect, :id => 1, :page => page.title, :protected => '0' - assert_redirected_to 'wiki/ecookbook' + assert_redirected_to :action => 'index', :id => 'ecookbook', :page => 'CookBook_documentation' assert !page.reload.protected? end @@ -219,7 +319,7 @@ class WikiControllerTest < Test::Unit::TestCase get :index, :id => 1 assert_response :success assert_template 'show' - assert_tag :tag => 'a', :attributes => { :href => '/wiki/1/CookBook_documentation/edit' } + assert_tag :tag => 'a', :attributes => { :href => '/projects/1/wiki/CookBook_documentation/edit' } end def test_show_page_without_edit_link @@ -227,7 +327,7 @@ class WikiControllerTest < Test::Unit::TestCase get :index, :id => 1 assert_response :success assert_template 'show' - assert_no_tag :tag => 'a', :attributes => { :href => '/wiki/1/CookBook_documentation/edit' } + assert_no_tag :tag => 'a', :attributes => { :href => '/projects/1/wiki/CookBook_documentation/edit' } end def test_edit_unprotected_page @@ -251,4 +351,9 @@ class WikiControllerTest < Test::Unit::TestCase assert_response :success assert_template 'edit' end + + def test_history_of_non_existing_page_should_return_404 + get :history, :id => 1, :page => 'Unknown_page' + assert_response 404 + end end diff --git a/test/functional/wikis_controller_test.rb b/test/functional/wikis_controller_test.rb index 3e51314a5..4000b1128 100644 --- a/test/functional/wikis_controller_test.rb +++ b/test/functional/wikis_controller_test.rb @@ -31,6 +31,14 @@ class WikisControllerTest < Test::Unit::TestCase User.current = nil end + def test_edit_routing + assert_routing( + #TODO: use PUT + {:method => :post, :path => 'projects/ladida/wiki'}, + :controller => 'wikis', :action => 'edit', :id => 'ladida' + ) + end + def test_create @request.session[:user_id] = 1 assert_nil Project.find(3).wiki @@ -41,10 +49,21 @@ class WikisControllerTest < Test::Unit::TestCase assert_equal 'Start page', wiki.start_page end + def test_destroy_routing + assert_routing( + {:method => :get, :path => 'projects/ladida/wiki/destroy'}, + :controller => 'wikis', :action => 'destroy', :id => 'ladida' + ) + assert_recognizes( #TODO: use DELETE and update form + {:controller => 'wikis', :action => 'destroy', :id => 'ladida'}, + {:method => :post, :path => 'projects/ladida/wiki/destroy'} + ) + end + def test_destroy @request.session[:user_id] = 1 post :destroy, :id => 1, :confirm => 1 - assert_redirected_to 'projects/settings/ecookbook' + assert_redirected_to :action => 'settings', :id => 'ecookbook', :tab => 'wiki' assert_nil Project.find(1).wiki end @@ -53,4 +72,4 @@ class WikisControllerTest < Test::Unit::TestCase post :destroy, :id => 999, :confirm => 1 assert_response 404 end -end +end diff --git a/test/functional/workflows_controller_test.rb b/test/functional/workflows_controller_test.rb new file mode 100644 index 000000000..d6078bbb9 --- /dev/null +++ b/test/functional/workflows_controller_test.rb @@ -0,0 +1,84 @@ +# Redmine - project management software +# 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 +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +require File.dirname(__FILE__) + '/../test_helper' +require 'workflows_controller' + +# Re-raise errors caught by the controller. +class WorkflowsController; def rescue_action(e) raise e end; end + +class WorkflowsControllerTest < Test::Unit::TestCase + fixtures :roles, :trackers, :workflows + + def setup + @controller = WorkflowsController.new + @request = ActionController::TestRequest.new + @response = ActionController::TestResponse.new + User.current = nil + @request.session[:user_id] = 1 # admin + end + + def test_index + get :index + assert_response :success + assert_template 'index' + + count = Workflow.count(:all, :conditions => 'role_id = 1 AND tracker_id = 2') + assert_tag :tag => 'a', :content => count.to_s, + :attributes => { :href => '/workflows/edit?role_id=1&tracker_id=2' } + end + + def test_get_edit + get :edit + assert_response :success + assert_template 'edit' + assert_not_nil assigns(:roles) + assert_not_nil assigns(:trackers) + end + + def test_get_edit_with_role_and_tracker + get :edit, :role_id => 2, :tracker_id => 1 + assert_response :success + assert_template 'edit' + # allowed transitions + assert_tag :tag => 'input', :attributes => { :type => 'checkbox', + :name => 'issue_status[2][]', + :value => '1', + :checked => 'checked' } + # not allowed + assert_tag :tag => 'input', :attributes => { :type => 'checkbox', + :name => 'issue_status[2][]', + :value => '3', + :checked => nil } + end + + def test_post_edit + post :edit, :role_id => 2, :tracker_id => 1, :issue_status => {'4' => ['5'], '3' => ['1', '2']} + assert_redirected_to '/workflows/edit?role_id=2&tracker_id=1' + + assert_equal 3, Workflow.count(:conditions => {:tracker_id => 1, :role_id => 2}) + assert_not_nil Workflow.find(:first, :conditions => {:role_id => 2, :tracker_id => 1, :old_status_id => 3, :new_status_id => 2}) + assert_nil Workflow.find(:first, :conditions => {:role_id => 2, :tracker_id => 1, :old_status_id => 5, :new_status_id => 4}) + end + + def test_clear_workflow + assert Workflow.count(:conditions => {:tracker_id => 1, :role_id => 2}) > 0 + + post :edit, :role_id => 2, :tracker_id => 1 + assert_equal 0, Workflow.count(:conditions => {:tracker_id => 1, :role_id => 2}) + end +end diff --git a/test/integration/account_test.rb b/test/integration/account_test.rb index c349200d3..c6cfd080e 100644 --- a/test/integration/account_test.rb +++ b/test/integration/account_test.rb @@ -44,7 +44,7 @@ class AccountTest < ActionController::IntegrationTest assert_response :success assert_template "account/lost_password" - post "account/lost_password", :mail => 'jsmith@somenet.foo' + post "account/lost_password", :mail => 'jSmith@somenet.foo' assert_redirected_to "account/login" token = Token.find(:first) diff --git a/test/integration/admin_test.rb b/test/integration/admin_test.rb index 6e385873e..5182c9abd 100644 --- a/test/integration/admin_test.rb +++ b/test/integration/admin_test.rb @@ -42,10 +42,10 @@ class AdminTest < ActionController::IntegrationTest def test_add_project log_user("admin", "admin") - get "projects/add" + get "projects/new" assert_response :success assert_template "projects/add" - post "projects/add", :project => { :name => "blog", + post "projects", :project => { :name => "blog", :description => "weblog", :identifier => "blog", :is_public => 1, diff --git a/test/integration/issues_test.rb b/test/integration/issues_test.rb index 2ef933fc2..61bbbce34 100644 --- a/test/integration/issues_test.rb +++ b/test/integration/issues_test.rb @@ -39,7 +39,7 @@ class IssuesTest < ActionController::IntegrationTest assert_response :success assert_template 'issues/new' - post 'projects/1/issues/new', :tracker_id => "1", + post 'projects/1/issues', :tracker_id => "1", :issue => { :start_date => "2006-12-26", :priority_id => "3", :subject => "new test issue", @@ -54,7 +54,7 @@ class IssuesTest < ActionController::IntegrationTest assert_kind_of Issue, issue # check redirection - assert_redirected_to "issues/show" + assert_redirected_to :controller => 'issues', :action => 'show' follow_redirect! assert_equal issue, assigns(:issue) @@ -69,10 +69,10 @@ class IssuesTest < ActionController::IntegrationTest log_user('jsmith', 'jsmith') set_tmp_attachments_directory - post 'issues/edit/1', + post 'issues/1/edit', :notes => 'Some notes', :attachments => {'1' => {'file' => test_uploaded_file('testfile.txt', 'text/plain'), 'description' => 'This is an attachment'}} - assert_redirected_to "issues/show/1" + assert_redirected_to "issues/1" # make sure attachment was saved attachment = Issue.find(1).attachments.find_by_filename("testfile.txt") diff --git a/test/integration/projects_test.rb b/test/integration/projects_test.rb index e56bee484..14175ea98 100644 --- a/test/integration/projects_test.rb +++ b/test/integration/projects_test.rb @@ -27,18 +27,18 @@ class ProjectsTest < ActionController::IntegrationTest assert_response :success assert_template "admin/projects" post "projects/archive", :id => 1 - assert_redirected_to "admin/projects" + assert_redirected_to "admin/projects" assert !Project.find(1).active? - get "projects/show", :id => 1 + get 'projects/1' assert_response 403 - get "projects/show", :id => subproject.id + get "projects/#{subproject.id}" assert_response 403 post "projects/unarchive", :id => 1 - assert_redirected_to "admin/projects" + assert_redirected_to "admin/projects" assert Project.find(1).active? - get "projects/show", :id => 1 + get "projects/1" assert_response :success end end diff --git a/test/mocks/open_id_authentication_mock.rb b/test/mocks/open_id_authentication_mock.rb new file mode 100644 index 000000000..cca1e9edb --- /dev/null +++ b/test/mocks/open_id_authentication_mock.rb @@ -0,0 +1,45 @@ +# Mocks out OpenID +# +# http://www.northpub.com/articles/2007/04/02/testing-openid-support +module OpenIdAuthentication + + EXTENSION_FIELDS = {'email' => 'user@somedomain.com', + 'nickname' => 'cool_user', + 'country' => 'US', + 'postcode' => '12345', + 'fullname' => 'Cool User', + 'dob' => '1970-04-01', + 'language' => 'en', + 'timezone' => 'America/New_York'} + + protected + + def authenticate_with_open_id(identity_url = params[:openid_url], options = {}) #:doc: + if User.find_by_identity_url(identity_url) || identity_url.include?('good') + # Don't process registration fields unless it is requested. + unless identity_url.include?('blank') || (options[:required].nil? && options[:optional].nil?) + extension_response_fields = {} + + options[:required].each do |field| + extension_response_fields[field.to_s] = EXTENSION_FIELDS[field.to_s] + end unless options[:required].nil? + + options[:optional].each do |field| + extension_response_fields[field.to_s] = EXTENSION_FIELDS[field.to_s] + end unless options[:optional].nil? + end + + yield Result[:successful], identity_url , extension_response_fields + else + logger.info "OpenID authentication failed: #{identity_url}" + yield Result[:failed], identity_url, nil + end + end + + private + + def add_simple_registration_fields(open_id_response, fields) + open_id_response.add_extension_arg('sreg', 'required', [ fields[:required] ].flatten * ',') if fields[:required] + open_id_response.add_extension_arg('sreg', 'optional', [ fields[:optional] ].flatten * ',') if fields[:optional] + end +end diff --git a/test/test_helper.rb b/test/test_helper.rb index f61b88d8c..ebc9bae46 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -19,6 +19,7 @@ ENV["RAILS_ENV"] ||= "test" require File.expand_path(File.dirname(__FILE__) + "/../config/environment") require 'test_help' require File.expand_path(File.dirname(__FILE__) + '/helper_testcase') +require File.join(RAILS_ROOT,'test', 'mocks', 'open_id_authentication_mock.rb') class Test::Unit::TestCase # Transactional fixtures accelerate your tests by wrapping each test method diff --git a/test/unit/activity_test.rb b/test/unit/activity_test.rb index ccda9f119..e5bc0d266 100644 --- a/test/unit/activity_test.rb +++ b/test/unit/activity_test.rb @@ -63,6 +63,15 @@ class ActivityTest < Test::Unit::TestCase assert events.include?(Issue.find(4)) end + def test_user_activity + user = User.find(2) + events = Redmine::Activity::Fetcher.new(User.anonymous, :author => user).events(nil, nil, :limit => 10) + + assert(events.size > 0) + assert(events.size <= 10) + assert_nil(events.detect {|e| e.event_author != user}) + end + private def find_events(user, options={}) diff --git a/test/unit/attachment_test.rb b/test/unit/attachment_test.rb index 99f7c29f9..a8c533238 100644 --- a/test/unit/attachment_test.rb +++ b/test/unit/attachment_test.rb @@ -18,7 +18,8 @@ require File.dirname(__FILE__) + '/../test_helper' class AttachmentTest < Test::Unit::TestCase - + fixtures :issues, :users + def setup end @@ -29,4 +30,8 @@ class AttachmentTest < Test::Unit::TestCase assert_equal 'f8139524ebb8f32e51976982cd20a85d', Attachment.disk_filename("test_accentué")[13..-1] assert_equal 'cbb5b0f30978ba03731d61f9f6d10011', Attachment.disk_filename("test_accentué.ça")[13..-1] end + + def test_digest + assert_equal '1478adae0d4eb06d35897518540e25d6', Attachment.digest(Test::Unit::TestCase.fixture_path + "/files/testfile.txt") + end end diff --git a/test/unit/custom_field_test.rb b/test/unit/custom_field_test.rb index 1b9c9aea9..2f17d99cf 100644 --- a/test/unit/custom_field_test.rb +++ b/test/unit/custom_field_test.rb @@ -25,6 +25,24 @@ class CustomFieldTest < Test::Unit::TestCase assert field.save end + def test_possible_values_should_accept_an_array + field = CustomField.new + field.possible_values = ["One value", ""] + assert_equal ["One value"], field.possible_values + end + + def test_possible_values_should_accept_a_string + field = CustomField.new + field.possible_values = "One value" + assert_equal ["One value"], field.possible_values + end + + def test_possible_values_should_accept_a_multiline_string + field = CustomField.new + field.possible_values = "One value\nAnd another one \r\n \n" + assert_equal ["One value", "And another one"], field.possible_values + end + def test_destroy field = CustomField.find(1) assert field.destroy diff --git a/test/unit/document_test.rb b/test/unit/document_test.rb new file mode 100644 index 000000000..17a0ad6ea --- /dev/null +++ b/test/unit/document_test.rb @@ -0,0 +1,37 @@ +# Redmine - project management software +# 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 +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +require File.dirname(__FILE__) + '/../test_helper' + +class DocumentTest < Test::Unit::TestCase + fixtures :projects, :enumerations, :documents + + def test_create + doc = Document.new(:project => Project.find(1), :title => 'New document', :category => Enumeration.find_by_name('User documentation')) + assert doc.save + end + + def test_create_with_default_category + # Sets a default category + e = Enumeration.find_by_name('Technical documentation') + e.update_attributes(:is_default => true) + + doc = Document.new(:project => Project.find(1), :title => 'New document') + assert_equal e, doc.category + assert doc.save + end +end diff --git a/test/unit/enumeration_test.rb b/test/unit/enumeration_test.rb index 9b7bfd174..4da3f094b 100644 --- a/test/unit/enumeration_test.rb +++ b/test/unit/enumeration_test.rb @@ -37,6 +37,43 @@ class EnumerationTest < Test::Unit::TestCase assert !Enumeration.find(7).in_use? end + def test_default + e = Enumeration.default('IPRI') + assert e.is_a?(Enumeration) + assert e.is_default? + assert_equal 'Normal', e.name + end + + def test_create + e = Enumeration.new(:opt => 'IPRI', :name => 'Very urgent', :is_default => false) + assert e.save + assert_equal 'Normal', Enumeration.default('IPRI').name + end + + def test_create_as_default + e = Enumeration.new(:opt => 'IPRI', :name => 'Very urgent', :is_default => true) + assert e.save + assert_equal e, Enumeration.default('IPRI') + end + + def test_update_default + e = Enumeration.default('IPRI') + e.update_attributes(:name => 'Changed', :is_default => true) + assert_equal e, Enumeration.default('IPRI') + end + + def test_update_default_to_non_default + e = Enumeration.default('IPRI') + e.update_attributes(:name => 'Changed', :is_default => false) + assert_nil Enumeration.default('IPRI') + end + + def test_change_default + e = Enumeration.find_by_name('Urgent') + e.update_attributes(:name => 'Urgent', :is_default => true) + assert_equal e, Enumeration.default('IPRI') + end + def test_destroy_with_reassign Enumeration.find(4).destroy(Enumeration.find(6)) assert_nil Issue.find(:first, :conditions => {:priority_id => 4}) diff --git a/test/unit/helpers/application_helper_test.rb b/test/unit/helpers/application_helper_test.rb index 35e26ebd4..c72ab1706 100644 --- a/test/unit/helpers/application_helper_test.rb +++ b/test/unit/helpers/application_helper_test.rb @@ -20,11 +20,12 @@ require File.dirname(__FILE__) + '/../../test_helper' class ApplicationHelperTest < HelperTestCase include ApplicationHelper include ActionView::Helpers::TextHelper - fixtures :projects, :roles, :enabled_modules, + fixtures :projects, :roles, :enabled_modules, :users, :repositories, :changesets, :trackers, :issue_statuses, :issues, :versions, :documents, :wikis, :wiki_pages, :wiki_contents, - :boards, :messages + :boards, :messages, + :attachments def setup super @@ -35,6 +36,7 @@ class ApplicationHelperTest < HelperTestCase 'http://foo.bar' => 'http://foo.bar', 'http://foo.bar/~user' => 'http://foo.bar/~user', 'http://foo.bar.' => 'http://foo.bar.', + 'https://foo.bar.' => 'https://foo.bar.', 'This is a link: http://foo.bar.' => 'This is a link: http://foo.bar.', 'A link (eg. http://foo.bar).' => 'A link (eg. http://foo.bar).', 'http://foo.bar/foo.bar#foo.bar.' => 'http://foo.bar/foo.bar#foo.bar.', @@ -51,6 +53,8 @@ class ApplicationHelperTest < HelperTestCase 'http://foo@www.bar.com' => 'http://foo@www.bar.com', 'http://foo:bar@www.bar.com' => 'http://foo:bar@www.bar.com', 'ftp://foo.bar' => 'ftp://foo.bar', + 'ftps://foo.bar' => 'ftps://foo.bar', + 'sftp://foo.bar' => 'sftp://foo.bar', } to_test.each { |text, result| assert_equal "

    #{result}

    ", textilizable(text) } end @@ -65,16 +69,40 @@ class ApplicationHelperTest < HelperTestCase '!http://foo.bar/image.jpg!' => '', 'floating !>http://foo.bar/image.jpg!' => 'floating
    ', 'with class !(some-class)http://foo.bar/image.jpg!' => 'with class ', - 'with style !{width:100px;height100px}http://foo.bar/image.jpg!' => 'with style ', + # inline styles should be stripped + 'with style !{width:100px;height100px}http://foo.bar/image.jpg!' => 'with style ', + 'with title !http://foo.bar/image.jpg(This is a title)!' => 'with title This is a title', + 'with title !http://foo.bar/image.jpg(This is a double-quoted "title")!' => 'with title This is a double-quoted "title"', } to_test.each { |text, result| assert_equal "

    #{result}

    ", textilizable(text) } end + def test_acronyms + to_test = { + 'this is an acronym: GPL(General Public License)' => 'this is an acronym: GPL', + 'GPL(This is a double-quoted "title")' => 'GPL', + } + to_test.each { |text, result| assert_equal "

    #{result}

    ", textilizable(text) } + + end + + def test_attached_images + to_test = { + 'Inline image: !logo.gif!' => 'Inline image: This is a logo', + 'Inline image: !logo.GIF!' => 'Inline image: This is a logo', + 'No match: !ogo.gif!' => 'No match: ', + 'No match: !ogo.GIF!' => 'No match: ' + } + attachments = Attachment.find(:all) + to_test.each { |text, result| assert_equal "

    #{result}

    ", textilizable(text, :attachments => attachments) } + end + def test_textile_external_links to_test = { 'This is a "link":http://foo.bar' => 'This is a link', 'This is an intern "link":/foo/bar' => 'This is an intern link', '"link (Link title)":http://foo.bar' => 'link', + '"link (Link title with "double-quotes")":http://foo.bar' => 'link', "This is not a \"Link\":\n\nAnother paragraph" => "This is not a \"Link\":

    \n\n\n\t

    Another paragraph", # no multiline link text "This is a double quote \"on the first line\nand another on a second line\":test" => "This is a double quote \"on the first line
    \nand another on a second line\":test" @@ -148,24 +176,28 @@ class ApplicationHelperTest < HelperTestCase def test_wiki_links to_test = { - '[[CookBook documentation]]' => 'CookBook documentation', - '[[Another page|Page]]' => 'Page', + '[[CookBook documentation]]' => 'CookBook documentation', + '[[Another page|Page]]' => 'Page', # link with anchor - '[[CookBook documentation#One-section]]' => 'CookBook documentation', - '[[Another page#anchor|Page]]' => 'Page', + '[[CookBook documentation#One-section]]' => 'CookBook documentation', + '[[Another page#anchor|Page]]' => 'Page', # page that doesn't exist - '[[Unknown page]]' => 'Unknown page', - '[[Unknown page|404]]' => '404', + '[[Unknown page]]' => 'Unknown page', + '[[Unknown page|404]]' => '404', # link to another project wiki - '[[onlinestore:]]' => 'onlinestore', - '[[onlinestore:|Wiki]]' => 'Wiki', - '[[onlinestore:Start page]]' => 'Start page', - '[[onlinestore:Start page|Text]]' => 'Text', - '[[onlinestore:Unknown page]]' => 'Unknown page', + '[[onlinestore:]]' => 'onlinestore', + '[[onlinestore:|Wiki]]' => 'Wiki', + '[[onlinestore:Start page]]' => 'Start page', + '[[onlinestore:Start page|Text]]' => 'Text', + '[[onlinestore:Unknown page]]' => 'Unknown page', # striked through link - '-[[Another page|Page]]-' => 'Page', + '-[[Another page|Page]]-' => 'Page', + '-[[Another page|Page]] link-' => 'Page link', # escaping '![[Another page|Page]]' => '[[Another page|Page]]', + # project does not exist + '[[unknowproject:Start]]' => '[[unknowproject:Start]]', + '[[unknowproject:Start|Page title]]' => '[[unknowproject:Start|Page title]]', } @project = Project.find(1) to_test.each { |text, result| assert_equal "

    #{result}

    ", textilizable(text) } @@ -181,7 +213,10 @@ class ApplicationHelperTest < HelperTestCase "
    \nline 1\nline2
    " => "
    \nline 1\nline2
    ", "
    content
    " => "
    <div>content</div>
    ", "HTML comment: " => "

    HTML comment: <!-- no comments -->

    ", - " ' + rel if verbose? - @currdir = rel - yield - Dir.chdir prevdir - $stderr.puts '<--- ' + rel if verbose? - @currdir = File.dirname(rel) - end - -end - - -if $0 == __FILE__ - begin - if multipackage_install? - ToplevelInstallerMulti.invoke - else - ToplevelInstaller.invoke - end - rescue SetupError - raise if $DEBUG - $stderr.puts $!.message - $stderr.puts "Try 'ruby #{$0} --help' for detailed usage." - exit 1 - end -end diff --git a/vendor/plugins/acts_as_activity_provider/lib/acts_as_activity_provider.rb b/vendor/plugins/acts_as_activity_provider/lib/acts_as_activity_provider.rb index 7c4fac8b1..bbbf5814b 100644 --- a/vendor/plugins/acts_as_activity_provider/lib/acts_as_activity_provider.rb +++ b/vendor/plugins/acts_as_activity_provider/lib/acts_as_activity_provider.rb @@ -29,7 +29,7 @@ module Redmine send :include, Redmine::Acts::ActivityProvider::InstanceMethods end - options.assert_valid_keys(:type, :permission, :timestamp, :find_options) + options.assert_valid_keys(:type, :permission, :timestamp, :author_key, :find_options) self.activity_provider_options ||= {} # One model can provide different event types @@ -39,6 +39,7 @@ module Redmine options[:permission] = "view_#{self.name.underscore.pluralize}".to_sym unless options.has_key?(:permission) options[:timestamp] ||= "#{table_name}.created_on" options[:find_options] ||= {} + options[:author_key] = "#{table_name}.#{options[:author_key]}" if options[:author_key].is_a?(Symbol) self.activity_provider_options[event_type] = options end end @@ -54,11 +55,25 @@ module Redmine provider_options = activity_provider_options[event_type] raise "#{self.name} can not provide #{event_type} events." if provider_options.nil? - cond = ARCondition.new(["#{provider_options[:timestamp]} BETWEEN ? AND ?", from, to]) + scope_options = {} + cond = ARCondition.new + if from && to + cond.add(["#{provider_options[:timestamp]} BETWEEN ? AND ?", from, to]) + end + if options[:author] + return [] if provider_options[:author_key].nil? + cond.add(["#{provider_options[:author_key]} = ?", options[:author].id]) + end cond.add(Project.allowed_to_condition(user, provider_options[:permission], options)) if provider_options[:permission] + scope_options[:conditions] = cond.conditions + if options[:limit] + # id and creation time should be in same order in most cases + scope_options[:order] = "#{table_name}.id DESC" + scope_options[:limit] = options[:limit] + end - with_scope(:find => { :conditions => cond.conditions }) do - find(:all, provider_options[:find_options]) + with_scope(:find => scope_options) do + find(:all, provider_options[:find_options].dup) end end end diff --git a/vendor/plugins/acts_as_attachable/init.rb b/vendor/plugins/acts_as_attachable/init.rb new file mode 100644 index 000000000..213e1d4b1 --- /dev/null +++ b/vendor/plugins/acts_as_attachable/init.rb @@ -0,0 +1,2 @@ +require File.dirname(__FILE__) + '/lib/acts_as_attachable' +ActiveRecord::Base.send(:include, Redmine::Acts::Attachable) diff --git a/vendor/plugins/acts_as_attachable/lib/acts_as_attachable.rb b/vendor/plugins/acts_as_attachable/lib/acts_as_attachable.rb new file mode 100644 index 000000000..78d42c215 --- /dev/null +++ b/vendor/plugins/acts_as_attachable/lib/acts_as_attachable.rb @@ -0,0 +1,57 @@ +# Redmine - project management software +# 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 +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +module Redmine + module Acts + module Attachable + def self.included(base) + base.extend ClassMethods + end + + module ClassMethods + def acts_as_attachable(options = {}) + cattr_accessor :attachable_options + self.attachable_options = {} + attachable_options[:view_permission] = options.delete(:view_permission) || "view_#{self.name.pluralize.underscore}".to_sym + attachable_options[:delete_permission] = options.delete(:delete_permission) || "edit_#{self.name.pluralize.underscore}".to_sym + + has_many :attachments, options.merge(:as => :container, + :order => "#{Attachment.table_name}.created_on", + :dependent => :destroy) + send :include, Redmine::Acts::Attachable::InstanceMethods + end + end + + module InstanceMethods + def self.included(base) + base.extend ClassMethods + end + + def attachments_visible?(user=User.current) + user.allowed_to?(self.class.attachable_options[:view_permission], self.project) + end + + def attachments_deletable?(user=User.current) + user.allowed_to?(self.class.attachable_options[:delete_permission], self.project) + end + + module ClassMethods + end + end + end + end +end diff --git a/vendor/plugins/acts_as_watchable/lib/acts_as_watchable.rb b/vendor/plugins/acts_as_watchable/lib/acts_as_watchable.rb index 2cb122795..3d0de0dca 100644 --- a/vendor/plugins/acts_as_watchable/lib/acts_as_watchable.rb +++ b/vendor/plugins/acts_as_watchable/lib/acts_as_watchable.rb @@ -14,6 +14,8 @@ module Redmine class_eval do has_many :watchers, :as => :watchable, :dependent => :delete_all has_many :watcher_users, :through => :watchers, :source => :user + + attr_protected :watcher_ids, :watcher_user_ids end end end diff --git a/vendor/plugins/actionwebservice/MIT-LICENSE b/vendor/plugins/awesome_nested_set/MIT-LICENSE similarity index 95% rename from vendor/plugins/actionwebservice/MIT-LICENSE rename to vendor/plugins/awesome_nested_set/MIT-LICENSE index 528941e84..570ecf870 100644 --- a/vendor/plugins/actionwebservice/MIT-LICENSE +++ b/vendor/plugins/awesome_nested_set/MIT-LICENSE @@ -1,4 +1,4 @@ -Copyright (C) 2005 Leon Breedt +Copyright (c) 2007 [name of plugin creator] Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the @@ -18,4 +18,3 @@ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - diff --git a/vendor/plugins/awesome_nested_set/README.rdoc b/vendor/plugins/awesome_nested_set/README.rdoc new file mode 100644 index 000000000..c093f751d --- /dev/null +++ b/vendor/plugins/awesome_nested_set/README.rdoc @@ -0,0 +1,64 @@ += AwesomeNestedSet + +Awesome Nested Set is an implementation of the nested set pattern for ActiveRecord models. It is replacement for acts_as_nested_set and BetterNestedSet, but awesomer. + +== What makes this so awesome? + +This is a new implementation of nested set based off of BetterNestedSet that fixes some bugs, removes tons of duplication, adds a few useful methods, and adds STI support. + +== Installation + +If you are on Rails 2.1 or later: + + script/plugin install git://github.com/collectiveidea/awesome_nested_set.git + +== Usage + +To make use of awesome_nested_set, your model needs to have 3 fields: lft, rgt, and parent_id: + + class CreateCategories < ActiveRecord::Migration + def self.up + create_table :categories do |t| + t.string :name + t.integer :parent_id + t.integer :lft + t.integer :rgt + end + end + + def self.down + drop_table :categories + end + end + +Enable the nested set functionality by declaring acts_as_nested_set on your model + + class Category < ActiveRecord::Base + acts_as_nested_set + end + +Run `rake rdoc` to generate the API docs and see CollectiveIdea::Acts::NestedSet::SingletonMethods for more info. + +== View Helper + +The view helper is called #nested_set_options. + +Example usage: + + <%= f.select :parent_id, nested_set_options(Category, @category) {|i| "#{'-' * i.level} #{i.name}" } %> + + <%= select_tag 'parent_id', options_for_select(nested_set_options(Category) {|i| "#{'-' * i.level} #{i.name}" } ) %> + +See CollectiveIdea::Acts::NestedSet::Helper for more information about the helpers. + +== References + +You can learn more about nested sets at: + + http://www.dbmsmag.com/9603d06.html + http://threebit.net/tutorials/nestedset/tutorial1.html + http://api.rubyonrails.com/classes/ActiveRecord/Acts/NestedSet/ClassMethods.html + http://opensource.symetrie.com/trac/better_nested_set/ + + +Copyright (c) 2008 Collective Idea, released under the MIT license \ No newline at end of file diff --git a/vendor/plugins/awesome_nested_set/Rakefile b/vendor/plugins/awesome_nested_set/Rakefile new file mode 100644 index 000000000..53906f68b --- /dev/null +++ b/vendor/plugins/awesome_nested_set/Rakefile @@ -0,0 +1,46 @@ +require 'rake' +require 'rake/testtask' +require 'rake/rdoctask' +require 'rake/gempackagetask' +require 'rcov/rcovtask' +require "load_multi_rails_rake_tasks" + +spec = eval(File.read("#{File.dirname(__FILE__)}/awesome_nested_set.gemspec")) +PKG_NAME = spec.name +PKG_VERSION = spec.version + +Rake::GemPackageTask.new(spec) do |pkg| + pkg.need_zip = true + pkg.need_tar = true +end + + +desc 'Default: run unit tests.' +task :default => :test + +desc 'Test the awesome_nested_set plugin.' +Rake::TestTask.new(:test) do |t| + t.libs << 'lib' + t.pattern = 'test/**/*_test.rb' + t.verbose = true +end + +desc 'Generate documentation for the awesome_nested_set plugin.' +Rake::RDocTask.new(:rdoc) do |rdoc| + rdoc.rdoc_dir = 'rdoc' + rdoc.title = 'AwesomeNestedSet' + rdoc.options << '--line-numbers' << '--inline-source' + rdoc.rdoc_files.include('README.rdoc') + rdoc.rdoc_files.include('lib/**/*.rb') +end + +namespace :test do + desc "just rcov minus html output" + Rcov::RcovTask.new(:coverage) do |t| + # t.libs << 'test' + t.test_files = FileList['test/**/*_test.rb'] + t.output_dir = 'coverage' + t.verbose = true + t.rcov_opts = %w(--exclude test,/usr/lib/ruby,/Library/Ruby,lib/awesome_nested_set/named_scope.rb --sort coverage) + end +end \ No newline at end of file diff --git a/vendor/plugins/awesome_nested_set/awesome_nested_set.gemspec b/vendor/plugins/awesome_nested_set/awesome_nested_set.gemspec new file mode 100644 index 000000000..c5a1d49e5 --- /dev/null +++ b/vendor/plugins/awesome_nested_set/awesome_nested_set.gemspec @@ -0,0 +1,20 @@ +Gem::Specification.new do |s| + s.name = "awesome_nested_set" + s.version = "1.1.1" + s.summary = "An awesome replacement for acts_as_nested_set and better_nested_set." + s.description = s.summary + + s.files = %w(init.rb MIT-LICENSE Rakefile README.rdoc lib/awesome_nested_set.rb lib/awesome_nested_set/compatability.rb lib/awesome_nested_set/helper.rb lib/awesome_nested_set/named_scope.rb rails/init.rb test/awesome_nested_set_test.rb test/test_helper.rb test/awesome_nested_set/helper_test.rb test/db/database.yml test/db/schema.rb test/fixtures/categories.yml test/fixtures/category.rb test/fixtures/departments.yml test/fixtures/notes.yml) + + s.add_dependency "activerecord", ['>= 1.1'] + + s.has_rdoc = true + s.extra_rdoc_files = [ "README.rdoc"] + s.rdoc_options = ["--main", "README.rdoc", "--inline-source", "--line-numbers"] + + s.test_files = %w(test/awesome_nested_set_test.rb test/test_helper.rb test/awesome_nested_set/helper_test.rb test/db/database.yml test/db/schema.rb test/fixtures/categories.yml test/fixtures/category.rb test/fixtures/departments.yml test/fixtures/notes.yml) + s.require_path = 'lib' + s.author = "Collective Idea" + s.email = "info@collectiveidea.com" + s.homepage = "http://collectiveidea.com" +end diff --git a/vendor/plugins/awesome_nested_set/init.rb b/vendor/plugins/awesome_nested_set/init.rb new file mode 100644 index 000000000..43dc7c274 --- /dev/null +++ b/vendor/plugins/awesome_nested_set/init.rb @@ -0,0 +1 @@ +require File.dirname(__FILE__) + "/rails/init" diff --git a/vendor/plugins/awesome_nested_set/lib/awesome_nested_set.rb b/vendor/plugins/awesome_nested_set/lib/awesome_nested_set.rb new file mode 100644 index 000000000..fb67341b6 --- /dev/null +++ b/vendor/plugins/awesome_nested_set/lib/awesome_nested_set.rb @@ -0,0 +1,547 @@ +module CollectiveIdea #:nodoc: + module Acts #:nodoc: + module NestedSet #:nodoc: + def self.included(base) + base.extend(SingletonMethods) + end + + # This acts provides Nested Set functionality. Nested Set is a smart way to implement + # an _ordered_ tree, with the added feature that you can select the children and all of their + # descendants with a single query. The drawback is that insertion or move need some complex + # sql queries. But everything is done here by this module! + # + # Nested sets are appropriate each time you want either an orderd tree (menus, + # commercial categories) or an efficient way of querying big trees (threaded posts). + # + # == API + # + # Methods names are aligned with acts_as_tree as much as possible, to make replacment from one + # by another easier, except for the creation: + # + # in acts_as_tree: + # item.children.create(:name => "child1") + # + # in acts_as_nested_set: + # # adds a new item at the "end" of the tree, i.e. with child.left = max(tree.right)+1 + # child = MyClass.new(:name => "child1") + # child.save + # # now move the item to its right place + # child.move_to_child_of my_item + # + # You can pass an id or an object to: + # * #move_to_child_of + # * #move_to_right_of + # * #move_to_left_of + # + module SingletonMethods + # Configuration options are: + # + # * +:parent_column+ - specifies the column name to use for keeping the position integer (default: parent_id) + # * +:left_column+ - column name for left boundry data, default "lft" + # * +:right_column+ - column name for right boundry data, default "rgt" + # * +:scope+ - restricts what is to be considered a list. Given a symbol, it'll attach "_id" + # (if it hasn't been already) and use that as the foreign key restriction. You + # can also pass an array to scope by multiple attributes. + # Example: acts_as_nested_set :scope => [:notable_id, :notable_type] + # * +:dependent+ - behavior for cascading destroy. If set to :destroy, all the + # child objects are destroyed alongside this object by calling their destroy + # method. If set to :delete_all (default), all the child objects are deleted + # without calling their destroy method. + # + # See CollectiveIdea::Acts::NestedSet::ClassMethods for a list of class methods and + # CollectiveIdea::Acts::NestedSet::InstanceMethods for a list of instance methods added + # to acts_as_nested_set models + def acts_as_nested_set(options = {}) + options = { + :parent_column => 'parent_id', + :left_column => 'lft', + :right_column => 'rgt', + :order => 'id', + :dependent => :delete_all, # or :destroy + }.merge(options) + + if options[:scope].is_a?(Symbol) && options[:scope].to_s !~ /_id$/ + options[:scope] = "#{options[:scope]}_id".intern + end + + write_inheritable_attribute :acts_as_nested_set_options, options + class_inheritable_reader :acts_as_nested_set_options + + include Comparable + include Columns + include InstanceMethods + extend Columns + extend ClassMethods + + # no bulk assignment + attr_protected left_column_name.intern, + right_column_name.intern, + parent_column_name.intern + + before_create :set_default_left_and_right + before_destroy :prune_from_tree + + # no assignment to structure fields + [left_column_name, right_column_name, parent_column_name].each do |column| + module_eval <<-"end_eval", __FILE__, __LINE__ + def #{column}=(x) + raise ActiveRecord::ActiveRecordError, "Unauthorized assignment to #{column}: it's an internal field handled by acts_as_nested_set code, use move_to_* methods instead." + end + end_eval + end + + named_scope :roots, :conditions => {parent_column_name => nil}, :order => quoted_left_column_name + named_scope :leaves, :conditions => "#{quoted_right_column_name} - #{quoted_left_column_name} = 1", :order => quoted_left_column_name + if self.respond_to?(:define_callbacks) + define_callbacks("before_move", "after_move") + end + + + end + + end + + module ClassMethods + + # Returns the first root + def root + roots.find(:first) + end + + def valid? + left_and_rights_valid? && no_duplicates_for_columns? && all_roots_valid? + end + + def left_and_rights_valid? + count( + :joins => "LEFT OUTER JOIN #{quoted_table_name} AS parent ON " + + "#{quoted_table_name}.#{quoted_parent_column_name} = parent.#{primary_key}", + :conditions => + "#{quoted_table_name}.#{quoted_left_column_name} IS NULL OR " + + "#{quoted_table_name}.#{quoted_right_column_name} IS NULL OR " + + "#{quoted_table_name}.#{quoted_left_column_name} >= " + + "#{quoted_table_name}.#{quoted_right_column_name} OR " + + "(#{quoted_table_name}.#{quoted_parent_column_name} IS NOT NULL AND " + + "(#{quoted_table_name}.#{quoted_left_column_name} <= parent.#{quoted_left_column_name} OR " + + "#{quoted_table_name}.#{quoted_right_column_name} >= parent.#{quoted_right_column_name}))" + ) == 0 + end + + def no_duplicates_for_columns? + scope_string = Array(acts_as_nested_set_options[:scope]).map do |c| + connection.quote_column_name(c) + end.push(nil).join(", ") + [quoted_left_column_name, quoted_right_column_name].all? do |column| + # No duplicates + find(:first, + :select => "#{scope_string}#{column}, COUNT(#{column})", + :group => "#{scope_string}#{column} + HAVING COUNT(#{column}) > 1").nil? + end + end + + # Wrapper for each_root_valid? that can deal with scope. + def all_roots_valid? + if acts_as_nested_set_options[:scope] + roots(:group => scope_column_names).group_by{|record| scope_column_names.collect{|col| record.send(col.to_sym)}}.all? do |scope, grouped_roots| + each_root_valid?(grouped_roots) + end + else + each_root_valid?(roots) + end + end + + def each_root_valid?(roots_to_validate) + left = right = 0 + roots_to_validate.all? do |root| + returning(root.left > left && root.right > right) do + left = root.left + right = root.right + end + end + end + + # Rebuilds the left & rights if unset or invalid. Also very useful for converting from acts_as_tree. + def rebuild! + # Don't rebuild a valid tree. + return true if valid? + + scope = lambda{} + if acts_as_nested_set_options[:scope] + scope = lambda{|node| + scope_column_names.inject(""){|str, column_name| + str << "AND #{connection.quote_column_name(column_name)} = #{connection.quote(node.send(column_name.to_sym))} " + } + } + end + indices = {} + + set_left_and_rights = lambda do |node| + # set left + node[left_column_name] = indices[scope.call(node)] += 1 + # find + find(:all, :conditions => ["#{quoted_parent_column_name} = ? #{scope.call(node)}", node], :order => "#{quoted_left_column_name}, #{quoted_right_column_name}, #{acts_as_nested_set_options[:order]}").each{|n| set_left_and_rights.call(n) } + # set right + node[right_column_name] = indices[scope.call(node)] += 1 + node.save! + end + + # Find root node(s) + root_nodes = find(:all, :conditions => "#{quoted_parent_column_name} IS NULL", :order => "#{quoted_left_column_name}, #{quoted_right_column_name}, #{acts_as_nested_set_options[:order]}").each do |root_node| + # setup index for this scope + indices[scope.call(root_node)] ||= 0 + set_left_and_rights.call(root_node) + end + end + end + + # Mixed into both classes and instances to provide easy access to the column names + module Columns + def left_column_name + acts_as_nested_set_options[:left_column] + end + + def right_column_name + acts_as_nested_set_options[:right_column] + end + + def parent_column_name + acts_as_nested_set_options[:parent_column] + end + + def scope_column_names + Array(acts_as_nested_set_options[:scope]) + end + + def quoted_left_column_name + connection.quote_column_name(left_column_name) + end + + def quoted_right_column_name + connection.quote_column_name(right_column_name) + end + + def quoted_parent_column_name + connection.quote_column_name(parent_column_name) + end + + def quoted_scope_column_names + scope_column_names.collect {|column_name| connection.quote_column_name(column_name) } + end + end + + # Any instance method that returns a collection makes use of Rails 2.1's named_scope (which is bundled for Rails 2.0), so it can be treated as a finder. + # + # category.self_and_descendants.count + # category.ancestors.find(:all, :conditions => "name like '%foo%'") + module InstanceMethods + # Value of the parent column + def parent_id + self[parent_column_name] + end + + # Value of the left column + def left + self[left_column_name] + end + + # Value of the right column + def right + self[right_column_name] + end + + # Returns true if this is a root node. + def root? + parent_id.nil? + end + + def leaf? + right - left == 1 + end + + # Returns true is this is a child node + def child? + !parent_id.nil? + end + + # order by left column + def <=>(x) + left <=> x.left + end + + # Redefine to act like active record + def ==(comparison_object) + comparison_object.equal?(self) || + (comparison_object.instance_of?(self.class) && + comparison_object.id == id && + !comparison_object.new_record?) + end + + # Returns root + def root + self_and_ancestors.find(:first) + end + + # Returns the immediate parent + def parent + nested_set_scope.find_by_id(parent_id) if parent_id + end + + # Returns the array of all parents and self + def self_and_ancestors + nested_set_scope.scoped :conditions => [ + "#{self.class.table_name}.#{quoted_left_column_name} <= ? AND #{self.class.table_name}.#{quoted_right_column_name} >= ?", left, right + ] + end + + # Returns an array of all parents + def ancestors + without_self self_and_ancestors + end + + # Returns the array of all children of the parent, including self + def self_and_siblings + nested_set_scope.scoped :conditions => {parent_column_name => parent_id} + end + + # Returns the array of all children of the parent, except self + def siblings + without_self self_and_siblings + end + + # Returns a set of all of its nested children which do not have children + def leaves + descendants.scoped :conditions => "#{self.class.table_name}.#{quoted_right_column_name} - #{self.class.table_name}.#{quoted_left_column_name} = 1" + end + + # Returns the level of this object in the tree + # root level is 0 + def level + parent_id.nil? ? 0 : ancestors.count + end + + # Returns a set of itself and all of its nested children + def self_and_descendants + nested_set_scope.scoped :conditions => [ + "#{self.class.table_name}.#{quoted_left_column_name} >= ? AND #{self.class.table_name}.#{quoted_right_column_name} <= ?", left, right + ] + end + + # Returns a set of all of its children and nested children + def descendants + without_self self_and_descendants + end + + # Returns a set of only this entry's immediate children + def children + nested_set_scope.scoped :conditions => {parent_column_name => self} + end + + def is_descendant_of?(other) + other.left < self.left && self.left < other.right && same_scope?(other) + end + + def is_or_is_descendant_of?(other) + other.left <= self.left && self.left < other.right && same_scope?(other) + end + + def is_ancestor_of?(other) + self.left < other.left && other.left < self.right && same_scope?(other) + end + + def is_or_is_ancestor_of?(other) + self.left <= other.left && other.left < self.right && same_scope?(other) + end + + # Check if other model is in the same scope + def same_scope?(other) + Array(acts_as_nested_set_options[:scope]).all? do |attr| + self.send(attr) == other.send(attr) + end + end + + # Find the first sibling to the left + def left_sibling + siblings.find(:first, :conditions => ["#{self.class.table_name}.#{quoted_left_column_name} < ?", left], + :order => "#{self.class.table_name}.#{quoted_left_column_name} DESC") + end + + # Find the first sibling to the right + def right_sibling + siblings.find(:first, :conditions => ["#{self.class.table_name}.#{quoted_left_column_name} > ?", left]) + end + + # Shorthand method for finding the left sibling and moving to the left of it. + def move_left + move_to_left_of left_sibling + end + + # Shorthand method for finding the right sibling and moving to the right of it. + def move_right + move_to_right_of right_sibling + end + + # Move the node to the left of another node (you can pass id only) + def move_to_left_of(node) + move_to node, :left + end + + # Move the node to the left of another node (you can pass id only) + def move_to_right_of(node) + move_to node, :right + end + + # Move the node to the child of another node (you can pass id only) + def move_to_child_of(node) + move_to node, :child + end + + # Move the node to root nodes + def move_to_root + move_to nil, :root + end + + def move_possible?(target) + self != target && # Can't target self + same_scope?(target) && # can't be in different scopes + # !(left..right).include?(target.left..target.right) # this needs tested more + # detect impossible move + !((left <= target.left && right >= target.left) or (left <= target.right && right >= target.right)) + end + + def to_text + self_and_descendants.map do |node| + "#{'*'*(node.level+1)} #{node.id} #{node.to_s} (#{node.parent_id}, #{node.left}, #{node.right})" + end.join("\n") + end + + protected + + def without_self(scope) + scope.scoped :conditions => ["#{self.class.table_name}.#{self.class.primary_key} != ?", self] + end + + # All nested set queries should use this nested_set_scope, which performs finds on + # the base ActiveRecord class, using the :scope declared in the acts_as_nested_set + # declaration. + def nested_set_scope + options = {:order => quoted_left_column_name} + scopes = Array(acts_as_nested_set_options[:scope]) + options[:conditions] = scopes.inject({}) do |conditions,attr| + conditions.merge attr => self[attr] + end unless scopes.empty? + self.class.base_class.scoped options + end + + # on creation, set automatically lft and rgt to the end of the tree + def set_default_left_and_right + maxright = nested_set_scope.maximum(right_column_name) || 0 + # adds the new node to the right of all existing nodes + self[left_column_name] = maxright + 1 + self[right_column_name] = maxright + 2 + end + + # Prunes a branch off of the tree, shifting all of the elements on the right + # back to the left so the counts still work. + def prune_from_tree + return if right.nil? || left.nil? + diff = right - left + 1 + + delete_method = acts_as_nested_set_options[:dependent] == :destroy ? + :destroy_all : :delete_all + + self.class.base_class.transaction do + nested_set_scope.send(delete_method, + ["#{quoted_left_column_name} > ? AND #{quoted_right_column_name} < ?", + left, right] + ) + nested_set_scope.update_all( + ["#{quoted_left_column_name} = (#{quoted_left_column_name} - ?)", diff], + ["#{quoted_left_column_name} >= ?", right] + ) + nested_set_scope.update_all( + ["#{quoted_right_column_name} = (#{quoted_right_column_name} - ?)", diff], + ["#{quoted_right_column_name} >= ?", right] + ) + end + end + + # reload left, right, and parent + def reload_nested_set + reload(:select => "#{quoted_left_column_name}, " + + "#{quoted_right_column_name}, #{quoted_parent_column_name}") + end + + def move_to(target, position) + raise ActiveRecord::ActiveRecordError, "You cannot move a new node" if self.new_record? + return if callback(:before_move) == false + transaction do + if target.is_a? self.class.base_class + target.reload_nested_set + elsif position != :root + # load object if node is not an object + target = nested_set_scope.find(target) + end + self.reload_nested_set + + unless position == :root || move_possible?(target) + raise ActiveRecord::ActiveRecordError, "Impossible move, target node cannot be inside moved tree." + end + + bound = case position + when :child; target[right_column_name] + when :left; target[left_column_name] + when :right; target[right_column_name] + 1 + when :root; 1 + else raise ActiveRecord::ActiveRecordError, "Position should be :child, :left, :right or :root ('#{position}' received)." + end + + if bound > self[right_column_name] + bound = bound - 1 + other_bound = self[right_column_name] + 1 + else + other_bound = self[left_column_name] - 1 + end + + # there would be no change + return if bound == self[right_column_name] || bound == self[left_column_name] + + # we have defined the boundaries of two non-overlapping intervals, + # so sorting puts both the intervals and their boundaries in order + a, b, c, d = [self[left_column_name], self[right_column_name], bound, other_bound].sort + + new_parent = case position + when :child; target.id + when :root; nil + else target[parent_column_name] + end + + self.class.base_class.update_all([ + "#{quoted_left_column_name} = CASE " + + "WHEN #{quoted_left_column_name} BETWEEN :a AND :b " + + "THEN #{quoted_left_column_name} + :d - :b " + + "WHEN #{quoted_left_column_name} BETWEEN :c AND :d " + + "THEN #{quoted_left_column_name} + :a - :c " + + "ELSE #{quoted_left_column_name} END, " + + "#{quoted_right_column_name} = CASE " + + "WHEN #{quoted_right_column_name} BETWEEN :a AND :b " + + "THEN #{quoted_right_column_name} + :d - :b " + + "WHEN #{quoted_right_column_name} BETWEEN :c AND :d " + + "THEN #{quoted_right_column_name} + :a - :c " + + "ELSE #{quoted_right_column_name} END, " + + "#{quoted_parent_column_name} = CASE " + + "WHEN #{self.class.base_class.primary_key} = :id THEN :new_parent " + + "ELSE #{quoted_parent_column_name} END", + {:a => a, :b => b, :c => c, :d => d, :id => self.id, :new_parent => new_parent} + ], nested_set_scope.proxy_options[:conditions]) + end + target.reload_nested_set if target + self.reload_nested_set + callback(:after_move) + end + + end + + end + end +end diff --git a/vendor/plugins/awesome_nested_set/lib/awesome_nested_set/compatability.rb b/vendor/plugins/awesome_nested_set/lib/awesome_nested_set/compatability.rb new file mode 100644 index 000000000..2d11da330 --- /dev/null +++ b/vendor/plugins/awesome_nested_set/lib/awesome_nested_set/compatability.rb @@ -0,0 +1,29 @@ +# Rails <2.x doesn't define #except +class Hash #:nodoc: + # Returns a new hash without the given keys. + def except(*keys) + clone.except!(*keys) + end unless method_defined?(:except) + + # Replaces the hash without the given keys. + def except!(*keys) + keys.map! { |key| convert_key(key) } if respond_to?(:convert_key) + keys.each { |key| delete(key) } + self + end unless method_defined?(:except!) +end + +# NamedScope is new to Rails 2.1 +unless defined? ActiveRecord::NamedScope + require 'awesome_nested_set/named_scope' + ActiveRecord::Base.class_eval do + include CollectiveIdea::NamedScope + end +end + +# Rails 1.2.x doesn't define #quoted_table_name +class ActiveRecord::Base #:nodoc: + def self.quoted_table_name + self.connection.quote_column_name(self.table_name) + end unless methods.include?('quoted_table_name') +end \ No newline at end of file diff --git a/vendor/plugins/awesome_nested_set/lib/awesome_nested_set/helper.rb b/vendor/plugins/awesome_nested_set/lib/awesome_nested_set/helper.rb new file mode 100644 index 000000000..09c803fd0 --- /dev/null +++ b/vendor/plugins/awesome_nested_set/lib/awesome_nested_set/helper.rb @@ -0,0 +1,40 @@ +module CollectiveIdea #:nodoc: + module Acts #:nodoc: + module NestedSet #:nodoc: + # This module provides some helpers for the model classes using acts_as_nested_set. + # It is included by default in all views. + # + module Helper + # Returns options for select. + # You can exclude some items from the tree. + # You can pass a block receiving an item and returning the string displayed in the select. + # + # == Params + # * +class_or_item+ - Class name or top level times + # * +mover+ - The item that is being move, used to exlude impossible moves + # * +&block+ - a block that will be used to display: { |item| ... item.name } + # + # == Usage + # + # <%= f.select :parent_id, nested_set_options(Category, @category) {|i| + # "#{'–' * i.level} #{i.name}" + # }) %> + # + def nested_set_options(class_or_item, mover = nil) + class_or_item = class_or_item.roots if class_or_item.is_a?(Class) + items = Array(class_or_item) + result = [] + items.each do |root| + result += root.self_and_descendants.map do |i| + if mover.nil? || mover.new_record? || mover.move_possible?(i) + [yield(i), i.id] + end + end.compact + end + result + end + + end + end + end +end \ No newline at end of file diff --git a/vendor/plugins/awesome_nested_set/lib/awesome_nested_set/named_scope.rb b/vendor/plugins/awesome_nested_set/lib/awesome_nested_set/named_scope.rb new file mode 100644 index 000000000..1836498bd --- /dev/null +++ b/vendor/plugins/awesome_nested_set/lib/awesome_nested_set/named_scope.rb @@ -0,0 +1,140 @@ +# Taken from Rails 2.1 +module CollectiveIdea #:nodoc: + module NamedScope #:nodoc: + # All subclasses of ActiveRecord::Base have two named_scopes: + # * all, which is similar to a find(:all) query, and + # * scoped, which allows for the creation of anonymous scopes, on the fly: + # + # Shirt.scoped(:conditions => {:color => 'red'}).scoped(:include => :washing_instructions) + # + # These anonymous scopes tend to be useful when procedurally generating complex queries, where passing + # intermediate values (scopes) around as first-class objects is convenient. + def self.included(base) + base.class_eval do + extend ClassMethods + named_scope :scoped, lambda { |scope| scope } + end + end + + module ClassMethods #:nodoc: + def scopes + read_inheritable_attribute(:scopes) || write_inheritable_attribute(:scopes, {}) + end + + # Adds a class method for retrieving and querying objects. A scope represents a narrowing of a database query, + # such as :conditions => {:color => :red}, :select => 'shirts.*', :include => :washing_instructions. + # + # class Shirt < ActiveRecord::Base + # named_scope :red, :conditions => {:color => 'red'} + # named_scope :dry_clean_only, :joins => :washing_instructions, :conditions => ['washing_instructions.dry_clean_only = ?', true] + # end + # + # The above calls to named_scope define class methods Shirt.red and Shirt.dry_clean_only. Shirt.red, + # in effect, represents the query Shirt.find(:all, :conditions => {:color => 'red'}). + # + # Unlike Shirt.find(...), however, the object returned by Shirt.red is not an Array; it resembles the association object + # constructed by a has_many declaration. For instance, you can invoke Shirt.red.find(:first), Shirt.red.count, + # Shirt.red.find(:all, :conditions => {:size => 'small'}). Also, just + # as with the association objects, name scopes acts like an Array, implementing Enumerable; Shirt.red.each(&block), + # Shirt.red.first, and Shirt.red.inject(memo, &block) all behave as if Shirt.red really were an Array. + # + # These named scopes are composable. For instance, Shirt.red.dry_clean_only will produce all shirts that are both red and dry clean only. + # Nested finds and calculations also work with these compositions: Shirt.red.dry_clean_only.count returns the number of garments + # for which these criteria obtain. Similarly with Shirt.red.dry_clean_only.average(:thread_count). + # + # All scopes are available as class methods on the ActiveRecord descendent upon which the scopes were defined. But they are also available to + # has_many associations. If, + # + # class Person < ActiveRecord::Base + # has_many :shirts + # end + # + # then elton.shirts.red.dry_clean_only will return all of Elton's red, dry clean + # only shirts. + # + # Named scopes can also be procedural. + # + # class Shirt < ActiveRecord::Base + # named_scope :colored, lambda { |color| + # { :conditions => { :color => color } } + # } + # end + # + # In this example, Shirt.colored('puce') finds all puce shirts. + # + # Named scopes can also have extensions, just as with has_many declarations: + # + # class Shirt < ActiveRecord::Base + # named_scope :red, :conditions => {:color => 'red'} do + # def dom_id + # 'red_shirts' + # end + # end + # end + # + # + # For testing complex named scopes, you can examine the scoping options using the + # proxy_options method on the proxy itself. + # + # class Shirt < ActiveRecord::Base + # named_scope :colored, lambda { |color| + # { :conditions => { :color => color } } + # } + # end + # + # expected_options = { :conditions => { :colored => 'red' } } + # assert_equal expected_options, Shirt.colored('red').proxy_options + def named_scope(name, options = {}, &block) + scopes[name] = lambda do |parent_scope, *args| + Scope.new(parent_scope, case options + when Hash + options + when Proc + options.call(*args) + end, &block) + end + (class << self; self end).instance_eval do + define_method name do |*args| + scopes[name].call(self, *args) + end + end + end + end + + class Scope #:nodoc: + attr_reader :proxy_scope, :proxy_options + [].methods.each { |m| delegate m, :to => :proxy_found unless m =~ /(^__|^nil\?|^send|class|extend|find|count|sum|average|maximum|minimum|paginate)/ } + delegate :scopes, :with_scope, :to => :proxy_scope + + def initialize(proxy_scope, options, &block) + [options[:extend]].flatten.each { |extension| extend extension } if options[:extend] + extend Module.new(&block) if block_given? + @proxy_scope, @proxy_options = proxy_scope, options.except(:extend) + end + + def reload + load_found; self + end + + protected + def proxy_found + @found || load_found + end + + private + def method_missing(method, *args, &block) + if scopes.include?(method) + scopes[method].call(self, *args) + else + with_scope :find => proxy_options do + proxy_scope.send(method, *args, &block) + end + end + end + + def load_found + @found = find(:all) + end + end + end +end \ No newline at end of file diff --git a/vendor/plugins/awesome_nested_set/rails/init.rb b/vendor/plugins/awesome_nested_set/rails/init.rb new file mode 100644 index 000000000..e0a4e8b06 --- /dev/null +++ b/vendor/plugins/awesome_nested_set/rails/init.rb @@ -0,0 +1,13 @@ +require 'awesome_nested_set/compatability' +require 'awesome_nested_set' + +ActiveRecord::Base.class_eval do + include CollectiveIdea::Acts::NestedSet +end + +if defined?(ActionView) + require 'awesome_nested_set/helper' + ActionView::Base.class_eval do + include CollectiveIdea::Acts::NestedSet::Helper + end +end \ No newline at end of file diff --git a/vendor/plugins/awesome_nested_set/test/awesome_nested_set/helper_test.rb b/vendor/plugins/awesome_nested_set/test/awesome_nested_set/helper_test.rb new file mode 100644 index 000000000..6122a0e60 --- /dev/null +++ b/vendor/plugins/awesome_nested_set/test/awesome_nested_set/helper_test.rb @@ -0,0 +1,41 @@ +require File.dirname(__FILE__) + '/../test_helper' + +module CollectiveIdea + module Acts #:nodoc: + module NestedSet #:nodoc: + class AwesomeNestedSetTest < Test::Unit::TestCase + include Helper + fixtures :categories + + def test_nested_set_options + expected = [ + [" Top Level", 1], + ["- Child 1", 2], + ['- Child 2', 3], + ['-- Child 2.1', 4], + ['- Child 3', 5], + [" Top Level 2", 6] + ] + actual = nested_set_options(Category) do |c| + "#{'-' * c.level} #{c.name}" + end + assert_equal expected, actual + end + + def test_nested_set_options_with_mover + expected = [ + [" Top Level", 1], + ["- Child 1", 2], + ['- Child 3', 5], + [" Top Level 2", 6] + ] + actual = nested_set_options(Category, categories(:child_2)) do |c| + "#{'-' * c.level} #{c.name}" + end + assert_equal expected, actual + end + + end + end + end +end \ No newline at end of file diff --git a/vendor/plugins/awesome_nested_set/test/awesome_nested_set_test.rb b/vendor/plugins/awesome_nested_set/test/awesome_nested_set_test.rb new file mode 100644 index 000000000..5252d804e --- /dev/null +++ b/vendor/plugins/awesome_nested_set/test/awesome_nested_set_test.rb @@ -0,0 +1,603 @@ +require File.dirname(__FILE__) + '/test_helper' + +class Note < ActiveRecord::Base + acts_as_nested_set :scope => [:notable_id, :notable_type] +end + +class AwesomeNestedSetTest < Test::Unit::TestCase + + class Default < ActiveRecord::Base + acts_as_nested_set + set_table_name 'categories' + end + class Scoped < ActiveRecord::Base + acts_as_nested_set :scope => :organization + set_table_name 'categories' + end + + def test_left_column_default + assert_equal 'lft', Default.acts_as_nested_set_options[:left_column] + end + + def test_right_column_default + assert_equal 'rgt', Default.acts_as_nested_set_options[:right_column] + end + + def test_parent_column_default + assert_equal 'parent_id', Default.acts_as_nested_set_options[:parent_column] + end + + def test_scope_default + assert_nil Default.acts_as_nested_set_options[:scope] + end + + def test_left_column_name + assert_equal 'lft', Default.left_column_name + assert_equal 'lft', Default.new.left_column_name + end + + def test_right_column_name + assert_equal 'rgt', Default.right_column_name + assert_equal 'rgt', Default.new.right_column_name + end + + def test_parent_column_name + assert_equal 'parent_id', Default.parent_column_name + assert_equal 'parent_id', Default.new.parent_column_name + end + + def test_quoted_left_column_name + quoted = Default.connection.quote_column_name('lft') + assert_equal quoted, Default.quoted_left_column_name + assert_equal quoted, Default.new.quoted_left_column_name + end + + def test_quoted_right_column_name + quoted = Default.connection.quote_column_name('rgt') + assert_equal quoted, Default.quoted_right_column_name + assert_equal quoted, Default.new.quoted_right_column_name + end + + def test_left_column_protected_from_assignment + assert_raises(ActiveRecord::ActiveRecordError) { Category.new.lft = 1 } + end + + def test_right_column_protected_from_assignment + assert_raises(ActiveRecord::ActiveRecordError) { Category.new.rgt = 1 } + end + + def test_parent_column_protected_from_assignment + assert_raises(ActiveRecord::ActiveRecordError) { Category.new.parent_id = 1 } + end + + def test_colums_protected_on_initialize + c = Category.new(:lft => 1, :rgt => 2, :parent_id => 3) + assert_nil c.lft + assert_nil c.rgt + assert_nil c.parent_id + end + + def test_scoped_appends_id + assert_equal :organization_id, Scoped.acts_as_nested_set_options[:scope] + end + + def test_roots_class_method + assert_equal Category.find_all_by_parent_id(nil), Category.roots + end + + def test_root_class_method + assert_equal categories(:top_level), Category.root + end + + def test_root + assert_equal categories(:top_level), categories(:child_3).root + end + + def test_root? + assert categories(:top_level).root? + assert categories(:top_level_2).root? + end + + def test_leaves_class_method + assert_equal Category.find(:all, :conditions => "#{Category.right_column_name} - #{Category.left_column_name} = 1"), Category.leaves + assert_equal Category.leaves.count, 4 + assert (Category.leaves.include? categories(:child_1)) + assert (Category.leaves.include? categories(:child_2_1)) + assert (Category.leaves.include? categories(:child_3)) + assert (Category.leaves.include? categories(:top_level_2)) + end + + def test_leaf + assert categories(:child_1).leaf? + assert categories(:child_2_1).leaf? + assert categories(:child_3).leaf? + assert categories(:top_level_2).leaf? + + assert !categories(:top_level).leaf? + assert !categories(:child_2).leaf? + end + + def test_parent + assert_equal categories(:child_2), categories(:child_2_1).parent + end + + def test_self_and_ancestors + child = categories(:child_2_1) + self_and_ancestors = [categories(:top_level), categories(:child_2), child] + assert_equal self_and_ancestors, child.self_and_ancestors + end + + def test_ancestors + child = categories(:child_2_1) + ancestors = [categories(:top_level), categories(:child_2)] + assert_equal ancestors, child.ancestors + end + + def test_self_and_siblings + child = categories(:child_2) + self_and_siblings = [categories(:child_1), child, categories(:child_3)] + assert_equal self_and_siblings, child.self_and_siblings + assert_nothing_raised do + tops = [categories(:top_level), categories(:top_level_2)] + assert_equal tops, categories(:top_level).self_and_siblings + end + end + + def test_siblings + child = categories(:child_2) + siblings = [categories(:child_1), categories(:child_3)] + assert_equal siblings, child.siblings + end + + def test_leaves + leaves = [categories(:child_1), categories(:child_2_1), categories(:child_3), categories(:top_level_2)] + assert categories(:top_level).leaves, leaves + end + + def test_level + assert_equal 0, categories(:top_level).level + assert_equal 1, categories(:child_1).level + assert_equal 2, categories(:child_2_1).level + end + + def test_has_children? + assert categories(:child_2_1).children.empty? + assert !categories(:child_2).children.empty? + assert !categories(:top_level).children.empty? + end + + def test_self_and_descendents + parent = categories(:top_level) + self_and_descendants = [parent, categories(:child_1), categories(:child_2), + categories(:child_2_1), categories(:child_3)] + assert_equal self_and_descendants, parent.self_and_descendants + assert_equal self_and_descendants, parent.self_and_descendants.count + end + + def test_descendents + lawyers = Category.create!(:name => "lawyers") + us = Category.create!(:name => "United States") + us.move_to_child_of(lawyers) + patent = Category.create!(:name => "Patent Law") + patent.move_to_child_of(us) + lawyers.reload + + assert_equal 1, lawyers.children.size + assert_equal 1, us.children.size + assert_equal 2, lawyers.descendants.size + end + + def test_self_and_descendents + parent = categories(:top_level) + descendants = [categories(:child_1), categories(:child_2), + categories(:child_2_1), categories(:child_3)] + assert_equal descendants, parent.descendants + end + + def test_children + category = categories(:top_level) + category.children.each {|c| assert_equal category.id, c.parent_id } + end + + def test_is_or_is_ancestor_of? + assert categories(:top_level).is_or_is_ancestor_of?(categories(:child_1)) + assert categories(:top_level).is_or_is_ancestor_of?(categories(:child_2_1)) + assert categories(:child_2).is_or_is_ancestor_of?(categories(:child_2_1)) + assert !categories(:child_2_1).is_or_is_ancestor_of?(categories(:child_2)) + assert !categories(:child_1).is_or_is_ancestor_of?(categories(:child_2)) + assert categories(:child_1).is_or_is_ancestor_of?(categories(:child_1)) + end + + def test_is_ancestor_of? + assert categories(:top_level).is_ancestor_of?(categories(:child_1)) + assert categories(:top_level).is_ancestor_of?(categories(:child_2_1)) + assert categories(:child_2).is_ancestor_of?(categories(:child_2_1)) + assert !categories(:child_2_1).is_ancestor_of?(categories(:child_2)) + assert !categories(:child_1).is_ancestor_of?(categories(:child_2)) + assert !categories(:child_1).is_ancestor_of?(categories(:child_1)) + end + + def test_is_or_is_ancestor_of_with_scope + root = Scoped.root + child = root.children.first + assert root.is_or_is_ancestor_of?(child) + child.update_attribute :organization_id, 'different' + assert !root.is_or_is_ancestor_of?(child) + end + + def test_is_or_is_descendant_of? + assert categories(:child_1).is_or_is_descendant_of?(categories(:top_level)) + assert categories(:child_2_1).is_or_is_descendant_of?(categories(:top_level)) + assert categories(:child_2_1).is_or_is_descendant_of?(categories(:child_2)) + assert !categories(:child_2).is_or_is_descendant_of?(categories(:child_2_1)) + assert !categories(:child_2).is_or_is_descendant_of?(categories(:child_1)) + assert categories(:child_1).is_or_is_descendant_of?(categories(:child_1)) + end + + def test_is_descendant_of? + assert categories(:child_1).is_descendant_of?(categories(:top_level)) + assert categories(:child_2_1).is_descendant_of?(categories(:top_level)) + assert categories(:child_2_1).is_descendant_of?(categories(:child_2)) + assert !categories(:child_2).is_descendant_of?(categories(:child_2_1)) + assert !categories(:child_2).is_descendant_of?(categories(:child_1)) + assert !categories(:child_1).is_descendant_of?(categories(:child_1)) + end + + def test_is_or_is_descendant_of_with_scope + root = Scoped.root + child = root.children.first + assert child.is_or_is_descendant_of?(root) + child.update_attribute :organization_id, 'different' + assert !child.is_or_is_descendant_of?(root) + end + + def test_same_scope? + root = Scoped.root + child = root.children.first + assert child.same_scope?(root) + child.update_attribute :organization_id, 'different' + assert !child.same_scope?(root) + end + + def test_left_sibling + assert_equal categories(:child_1), categories(:child_2).left_sibling + assert_equal categories(:child_2), categories(:child_3).left_sibling + end + + def test_left_sibling_of_root + assert_nil categories(:top_level).left_sibling + end + + def test_left_sibling_without_siblings + assert_nil categories(:child_2_1).left_sibling + end + + def test_left_sibling_of_leftmost_node + assert_nil categories(:child_1).left_sibling + end + + def test_right_sibling + assert_equal categories(:child_3), categories(:child_2).right_sibling + assert_equal categories(:child_2), categories(:child_1).right_sibling + end + + def test_right_sibling_of_root + assert_equal categories(:top_level_2), categories(:top_level).right_sibling + assert_nil categories(:top_level_2).right_sibling + end + + def test_right_sibling_without_siblings + assert_nil categories(:child_2_1).right_sibling + end + + def test_right_sibling_of_rightmost_node + assert_nil categories(:child_3).right_sibling + end + + def test_move_left + categories(:child_2).move_left + assert_nil categories(:child_2).left_sibling + assert_equal categories(:child_1), categories(:child_2).right_sibling + assert Category.valid? + end + + def test_move_right + categories(:child_2).move_right + assert_nil categories(:child_2).right_sibling + assert_equal categories(:child_3), categories(:child_2).left_sibling + assert Category.valid? + end + + def test_move_to_left_of + categories(:child_3).move_to_left_of(categories(:child_1)) + assert_nil categories(:child_3).left_sibling + assert_equal categories(:child_1), categories(:child_3).right_sibling + assert Category.valid? + end + + def test_move_to_right_of + categories(:child_1).move_to_right_of(categories(:child_3)) + assert_nil categories(:child_1).right_sibling + assert_equal categories(:child_3), categories(:child_1).left_sibling + assert Category.valid? + end + + def test_move_to_root + categories(:child_2).move_to_root + assert_nil categories(:child_2).parent + assert_equal 0, categories(:child_2).level + assert_equal 1, categories(:child_2_1).level + assert_equal 1, categories(:child_2).left + assert_equal 4, categories(:child_2).right + assert Category.valid? + end + + def test_move_to_child_of + categories(:child_1).move_to_child_of(categories(:child_3)) + assert_equal categories(:child_3).id, categories(:child_1).parent_id + assert Category.valid? + end + + def test_move_to_child_of_appends_to_end + child = Category.create! :name => 'New Child' + child.move_to_child_of categories(:top_level) + assert_equal child, categories(:top_level).children.last + end + + def test_subtree_move_to_child_of + assert_equal 4, categories(:child_2).left + assert_equal 7, categories(:child_2).right + + assert_equal 2, categories(:child_1).left + assert_equal 3, categories(:child_1).right + + categories(:child_2).move_to_child_of(categories(:child_1)) + assert Category.valid? + assert_equal categories(:child_1).id, categories(:child_2).parent_id + + assert_equal 3, categories(:child_2).left + assert_equal 6, categories(:child_2).right + assert_equal 2, categories(:child_1).left + assert_equal 7, categories(:child_1).right + end + + def test_slightly_difficult_move_to_child_of + assert_equal 11, categories(:top_level_2).left + assert_equal 12, categories(:top_level_2).right + + # create a new top-level node and move single-node top-level tree inside it. + new_top = Category.create(:name => 'New Top') + assert_equal 13, new_top.left + assert_equal 14, new_top.right + + categories(:top_level_2).move_to_child_of(new_top) + + assert Category.valid? + assert_equal new_top.id, categories(:top_level_2).parent_id + + assert_equal 12, categories(:top_level_2).left + assert_equal 13, categories(:top_level_2).right + assert_equal 11, new_top.left + assert_equal 14, new_top.right + end + + def test_difficult_move_to_child_of + assert_equal 1, categories(:top_level).left + assert_equal 10, categories(:top_level).right + assert_equal 5, categories(:child_2_1).left + assert_equal 6, categories(:child_2_1).right + + # create a new top-level node and move an entire top-level tree inside it. + new_top = Category.create(:name => 'New Top') + categories(:top_level).move_to_child_of(new_top) + categories(:child_2_1).reload + assert Category.valid? + assert_equal new_top.id, categories(:top_level).parent_id + + assert_equal 4, categories(:top_level).left + assert_equal 13, categories(:top_level).right + assert_equal 8, categories(:child_2_1).left + assert_equal 9, categories(:child_2_1).right + end + + #rebuild swaps the position of the 2 children when added using move_to_child twice onto same parent + def test_move_to_child_more_than_once_per_parent_rebuild + root1 = Category.create(:name => 'Root1') + root2 = Category.create(:name => 'Root2') + root3 = Category.create(:name => 'Root3') + + root2.move_to_child_of root1 + root3.move_to_child_of root1 + + output = Category.roots.last.to_text + Category.update_all('lft = null, rgt = null') + Category.rebuild! + + assert_equal Category.roots.last.to_text, output + end + + # doing move_to_child twice onto same parent from the furthest right first + def test_move_to_child_more_than_once_per_parent_outside_in + node1 = Category.create(:name => 'Node-1') + node2 = Category.create(:name => 'Node-2') + node3 = Category.create(:name => 'Node-3') + + node2.move_to_child_of node1 + node3.move_to_child_of node1 + + output = Category.roots.last.to_text + Category.update_all('lft = null, rgt = null') + Category.rebuild! + + assert_equal Category.roots.last.to_text, output + end + + + def test_valid_with_null_lefts + assert Category.valid? + Category.update_all('lft = null') + assert !Category.valid? + end + + def test_valid_with_null_rights + assert Category.valid? + Category.update_all('rgt = null') + assert !Category.valid? + end + + def test_valid_with_missing_intermediate_node + # Even though child_2_1 will still exist, it is a sign of a sloppy delete, not an invalid tree. + assert Category.valid? + Category.delete(categories(:child_2).id) + assert Category.valid? + end + + def test_valid_with_overlapping_and_rights + assert Category.valid? + categories(:top_level_2)['lft'] = 0 + categories(:top_level_2).save + assert !Category.valid? + end + + def test_rebuild + assert Category.valid? + before_text = Category.root.to_text + Category.update_all('lft = null, rgt = null') + Category.rebuild! + assert Category.valid? + assert_equal before_text, Category.root.to_text + end + + def test_move_possible_for_sibling + assert categories(:child_2).move_possible?(categories(:child_1)) + end + + def test_move_not_possible_to_self + assert !categories(:top_level).move_possible?(categories(:top_level)) + end + + def test_move_not_possible_to_parent + categories(:top_level).descendants.each do |descendant| + assert !categories(:top_level).move_possible?(descendant) + assert descendant.move_possible?(categories(:top_level)) + end + end + + def test_is_or_is_ancestor_of? + [:child_1, :child_2, :child_2_1, :child_3].each do |c| + assert categories(:top_level).is_or_is_ancestor_of?(categories(c)) + end + assert !categories(:top_level).is_or_is_ancestor_of?(categories(:top_level_2)) + end + + def test_left_and_rights_valid_with_blank_left + assert Category.left_and_rights_valid? + categories(:child_2)[:lft] = nil + categories(:child_2).save(false) + assert !Category.left_and_rights_valid? + end + + def test_left_and_rights_valid_with_blank_right + assert Category.left_and_rights_valid? + categories(:child_2)[:rgt] = nil + categories(:child_2).save(false) + assert !Category.left_and_rights_valid? + end + + def test_left_and_rights_valid_with_equal + assert Category.left_and_rights_valid? + categories(:top_level_2)[:lft] = categories(:top_level_2)[:rgt] + categories(:top_level_2).save(false) + assert !Category.left_and_rights_valid? + end + + def test_left_and_rights_valid_with_left_equal_to_parent + assert Category.left_and_rights_valid? + categories(:child_2)[:lft] = categories(:top_level)[:lft] + categories(:child_2).save(false) + assert !Category.left_and_rights_valid? + end + + def test_left_and_rights_valid_with_right_equal_to_parent + assert Category.left_and_rights_valid? + categories(:child_2)[:rgt] = categories(:top_level)[:rgt] + categories(:child_2).save(false) + assert !Category.left_and_rights_valid? + end + + def test_moving_dirty_objects_doesnt_invalidate_tree + r1 = Category.create + r2 = Category.create + r3 = Category.create + r4 = Category.create + nodes = [r1, r2, r3, r4] + + r2.move_to_child_of(r1) + assert Category.valid? + + r3.move_to_child_of(r1) + assert Category.valid? + + r4.move_to_child_of(r2) + assert Category.valid? + end + + def test_multi_scoped_no_duplicates_for_columns? + assert_nothing_raised do + Note.no_duplicates_for_columns? + end + end + + def test_multi_scoped_all_roots_valid? + assert_nothing_raised do + Note.all_roots_valid? + end + end + + def test_multi_scoped + note1 = Note.create!(:body => "A", :notable_id => 2, :notable_type => 'Category') + note2 = Note.create!(:body => "B", :notable_id => 2, :notable_type => 'Category') + note3 = Note.create!(:body => "C", :notable_id => 2, :notable_type => 'Default') + + assert_equal [note1, note2], note1.self_and_siblings + assert_equal [note3], note3.self_and_siblings + end + + def test_multi_scoped_rebuild + root = Note.create!(:body => "A", :notable_id => 3, :notable_type => 'Category') + child1 = Note.create!(:body => "B", :notable_id => 3, :notable_type => 'Category') + child2 = Note.create!(:body => "C", :notable_id => 3, :notable_type => 'Category') + + child1.move_to_child_of root + child2.move_to_child_of root + + Note.update_all('lft = null, rgt = null') + Note.rebuild! + + assert_equal Note.roots.find_by_body('A'), root + assert_equal [child1, child2], Note.roots.find_by_body('A').children + end + + def test_same_scope_with_multi_scopes + assert_nothing_raised do + notes(:scope1).same_scope?(notes(:child_1)) + end + assert notes(:scope1).same_scope?(notes(:child_1)) + assert notes(:child_1).same_scope?(notes(:scope1)) + assert !notes(:scope1).same_scope?(notes(:scope2)) + end + + def test_quoting_of_multi_scope_column_names + assert_equal ["\"notable_id\"", "\"notable_type\""], Note.quoted_scope_column_names + end + + def test_equal_in_same_scope + assert_equal notes(:scope1), notes(:scope1) + assert_not_equal notes(:scope1), notes(:child_1) + end + + def test_equal_in_different_scopes + assert_not_equal notes(:scope1), notes(:scope2) + end + +end diff --git a/vendor/plugins/awesome_nested_set/test/db/database.yml b/vendor/plugins/awesome_nested_set/test/db/database.yml new file mode 100644 index 000000000..9281236d2 --- /dev/null +++ b/vendor/plugins/awesome_nested_set/test/db/database.yml @@ -0,0 +1,18 @@ +sqlite3: + adapter: sqlite3 + dbfile: awesome_nested_set.sqlite3.db +sqlite3mem: + :adapter: sqlite3 + :dbfile: ":memory:" +postgresql: + :adapter: postgresql + :username: postgres + :password: postgres + :database: awesome_nested_set_plugin_test + :min_messages: ERROR +mysql: + :adapter: mysql + :host: localhost + :username: root + :password: + :database: awesome_nested_set_plugin_test \ No newline at end of file diff --git a/vendor/plugins/awesome_nested_set/test/db/schema.rb b/vendor/plugins/awesome_nested_set/test/db/schema.rb new file mode 100644 index 000000000..bbed1eb16 --- /dev/null +++ b/vendor/plugins/awesome_nested_set/test/db/schema.rb @@ -0,0 +1,23 @@ +ActiveRecord::Schema.define(:version => 0) do + + create_table :categories, :force => true do |t| + t.column :name, :string + t.column :parent_id, :integer + t.column :lft, :integer + t.column :rgt, :integer + t.column :organization_id, :integer + end + + create_table :departments, :force => true do |t| + t.column :name, :string + end + + create_table :notes, :force => true do |t| + t.column :body, :text + t.column :parent_id, :integer + t.column :lft, :integer + t.column :rgt, :integer + t.column :notable_id, :integer + t.column :notable_type, :string + end +end diff --git a/vendor/plugins/awesome_nested_set/test/fixtures/categories.yml b/vendor/plugins/awesome_nested_set/test/fixtures/categories.yml new file mode 100644 index 000000000..bc8e078e8 --- /dev/null +++ b/vendor/plugins/awesome_nested_set/test/fixtures/categories.yml @@ -0,0 +1,34 @@ +top_level: + id: 1 + name: Top Level + lft: 1 + rgt: 10 +child_1: + id: 2 + name: Child 1 + parent_id: 1 + lft: 2 + rgt: 3 +child_2: + id: 3 + name: Child 2 + parent_id: 1 + lft: 4 + rgt: 7 +child_2_1: + id: 4 + name: Child 2.1 + parent_id: 3 + lft: 5 + rgt: 6 +child_3: + id: 5 + name: Child 3 + parent_id: 1 + lft: 8 + rgt: 9 +top_level_2: + id: 6 + name: Top Level 2 + lft: 11 + rgt: 12 diff --git a/vendor/plugins/awesome_nested_set/test/fixtures/category.rb b/vendor/plugins/awesome_nested_set/test/fixtures/category.rb new file mode 100644 index 000000000..506b0dac5 --- /dev/null +++ b/vendor/plugins/awesome_nested_set/test/fixtures/category.rb @@ -0,0 +1,15 @@ +class Category < ActiveRecord::Base + acts_as_nested_set + + def to_s + name + end + + def recurse &block + block.call self, lambda{ + self.children.each do |child| + child.recurse &block + end + } + end +end \ No newline at end of file diff --git a/vendor/plugins/awesome_nested_set/test/fixtures/departments.yml b/vendor/plugins/awesome_nested_set/test/fixtures/departments.yml new file mode 100644 index 000000000..e50a944f1 --- /dev/null +++ b/vendor/plugins/awesome_nested_set/test/fixtures/departments.yml @@ -0,0 +1,3 @@ +top: + id: 1 + name: Top \ No newline at end of file diff --git a/vendor/plugins/awesome_nested_set/test/fixtures/notes.yml b/vendor/plugins/awesome_nested_set/test/fixtures/notes.yml new file mode 100644 index 000000000..004a5335a --- /dev/null +++ b/vendor/plugins/awesome_nested_set/test/fixtures/notes.yml @@ -0,0 +1,38 @@ +scope1: + id: 1 + body: Top Level + lft: 1 + rgt: 10 + notable_id: 1 + notable_type: Category +child_1: + id: 2 + body: Child 1 + parent_id: 1 + lft: 2 + rgt: 3 + notable_id: 1 + notable_type: Category +child_2: + id: 3 + body: Child 2 + parent_id: 1 + lft: 4 + rgt: 7 + notable_id: 1 + notable_type: Category +child_3: + id: 4 + body: Child 3 + parent_id: 1 + lft: 8 + rgt: 9 + notable_id: 1 + notable_type: Category +scope2: + id: 5 + body: Top Level 2 + lft: 1 + rgt: 2 + notable_id: 1 + notable_type: Departments diff --git a/vendor/plugins/awesome_nested_set/test/test_helper.rb b/vendor/plugins/awesome_nested_set/test/test_helper.rb new file mode 100644 index 000000000..693982236 --- /dev/null +++ b/vendor/plugins/awesome_nested_set/test/test_helper.rb @@ -0,0 +1,31 @@ +$:.unshift(File.dirname(__FILE__) + '/../lib') +plugin_test_dir = File.dirname(__FILE__) + +require 'rubygems' +require 'test/unit' +require 'multi_rails_init' +# gem 'activerecord', '>= 2.0' +require 'active_record' +require 'action_controller' +require 'action_view' +require 'active_record/fixtures' + +require plugin_test_dir + '/../init.rb' + +ActiveRecord::Base.logger = Logger.new(plugin_test_dir + "/debug.log") + +ActiveRecord::Base.configurations = YAML::load(IO.read(plugin_test_dir + "/db/database.yml")) +ActiveRecord::Base.establish_connection(ENV["DB"] || "sqlite3mem") +ActiveRecord::Migration.verbose = false +load(File.join(plugin_test_dir, "db", "schema.rb")) + +Dir["#{plugin_test_dir}/fixtures/*.rb"].each {|file| require file } + + +class Test::Unit::TestCase #:nodoc: + self.fixture_path = File.dirname(__FILE__) + "/fixtures/" + self.use_transactional_fixtures = true + self.use_instantiated_fixtures = false + + fixtures :categories, :notes, :departments +end \ No newline at end of file diff --git a/vendor/plugins/classic_pagination/lib/pagination.rb b/vendor/plugins/classic_pagination/lib/pagination.rb index b6e9cf4bc..6a3e1a97b 100644 --- a/vendor/plugins/classic_pagination/lib/pagination.rb +++ b/vendor/plugins/classic_pagination/lib/pagination.rb @@ -97,8 +97,8 @@ module ActionController "Unknown options: #{unknown_option_keys.join(', ')}" unless unknown_option_keys.empty? - options[:singular_name] ||= Inflector.singularize(collection_id.to_s) - options[:class_name] ||= Inflector.camelize(options[:singular_name]) + options[:singular_name] ||= ActiveSupport::Inflector.singularize(collection_id.to_s) + options[:class_name] ||= ActiveSupport::Inflector.camelize(options[:singular_name]) end # Returns a paginator and a collection of Active Record model instances diff --git a/vendor/plugins/engines/lib/engines/rails_extensions/dependencies.rb b/vendor/plugins/engines/lib/engines/rails_extensions/dependencies.rb index 82ecaa880..05ba0eb58 100644 --- a/vendor/plugins/engines/lib/engines/rails_extensions/dependencies.rb +++ b/vendor/plugins/engines/lib/engines/rails_extensions/dependencies.rb @@ -140,4 +140,4 @@ module Engines::RailsExtensions::Dependencies end end -Dependencies.send :include, Engines::RailsExtensions::Dependencies +ActiveSupport::Dependencies.send :include, Engines::RailsExtensions::Dependencies diff --git a/vendor/plugins/gloc-1.1.0/lib/gloc.rb b/vendor/plugins/gloc-1.1.0/lib/gloc.rb index bcad0ed9b..8123785b7 100644 --- a/vendor/plugins/gloc-1.1.0/lib/gloc.rb +++ b/vendor/plugins/gloc-1.1.0/lib/gloc.rb @@ -52,7 +52,7 @@ module GLoc # Sets the current language for this instance/class. # Setting the language of a class effects all instances unless the instance has its own language defined. def set_language(language) - @gloc_language= language.nil? ? nil : language.to_sym + GLoc.current_language = language end # Sets the current language if the language passed is a valid language. @@ -75,7 +75,7 @@ module GLoc include ::GLoc::InstanceMethods # Returns the instance-level current language, or if not set, returns the class-level current language. def current_language - @gloc_language || self.class.current_language + GLoc.current_language end #--------------------------------------------------------------------------- @@ -87,7 +87,7 @@ module GLoc include ::GLoc::InstanceMethods # Returns the current language, or if not set, returns the GLoc current language. def current_language - @gloc_language || GLoc.current_language + GLoc.current_language end end @@ -103,10 +103,16 @@ module GLoc class << self include ::GLoc::InstanceMethods + + @@current_language = nil - # Returns the default language + # Returns the current language def current_language - GLoc::CONFIG[:default_language] + @@current_language || GLoc::CONFIG[:default_language] + end + + def current_language=(lang) + @@current_language = lang.blank? ? nil : lang.to_sym end # Adds a collection of localized strings to the in-memory string store. diff --git a/vendor/plugins/gloc-1.1.0/tasks/gloc.rake b/vendor/plugins/gloc-1.1.0/tasks/gloc.rake index 88f3472ec..fb5dfb8d3 100644 --- a/vendor/plugins/gloc-1.1.0/tasks/gloc.rake +++ b/vendor/plugins/gloc-1.1.0/tasks/gloc.rake @@ -28,7 +28,7 @@ namespace :gloc do } end - desc 'Updates language files based on em.yml content' + desc 'Updates language files based on en.yml content' task :update do dir = ENV['DIR'] || './lang' diff --git a/vendor/plugins/gravatar/MIT-LICENSE b/vendor/plugins/gravatar/MIT-LICENSE new file mode 100644 index 000000000..6a222ac4d --- /dev/null +++ b/vendor/plugins/gravatar/MIT-LICENSE @@ -0,0 +1,20 @@ +Copyright (c) 2007 West Arete Computing, Inc. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/vendor/plugins/gravatar/README b/vendor/plugins/gravatar/README new file mode 100644 index 000000000..dc516d367 --- /dev/null +++ b/vendor/plugins/gravatar/README @@ -0,0 +1,52 @@ +== Gravatar Plugin + +This plugin provides a handful of view helpers for displaying gravatars +(globally-recognized avatars). + +Gravatars allow users to configure an avatar to go with their email address at +a central location: http://gravatar.com. Gravatar-aware websites (such +as yours) can then look up and display each user's preferred avatar, without +having to handle avatar management. The user gets the benefit of not having to +set up an avatar for each site that they post on. + +== Installation + + cd ~/myapp + ruby script/plugin install svn://rubyforge.org//var/svn/gravatarplugin/plugins/gravatar + +or, if you're using piston[http://piston.rubyforge.org] (worth it!): + + cd ~/myapp/vendor/plugins + piston import svn://rubyforge.org//var/svn/gravatarplugin/plugins/gravatar + +== Example + +If you represent your users with a model that has an +email+ method (typical +for most rails authentication setups), then you can simply use this method +in your views: + + <%= gravatar_for @user %> + +This will be replaced with the full HTML +img+ tag necessary for displaying +that user's gravatar. + +Other helpers are documented under GravatarHelper::PublicMethods. + +== Acknowledgments + +The following people have also written gravatar-related Ruby libraries: +* Seth Rasmussen created the gravatar gem[http://gravatar.rubyforge.org] +* Matt McCray has also created a gravatar + plugin[http://mattmccray.com/svn/rails/plugins/gravatar_helper] + +== Author + + Scott A. Woods + West Arete Computing, Inc. + http://westarete.com + scott at westarete dot com + +== TODO + +* Get full spec coverage +* Finish rdoc documentation \ No newline at end of file diff --git a/vendor/plugins/gravatar/Rakefile b/vendor/plugins/gravatar/Rakefile new file mode 100644 index 000000000..5a8d92a8a --- /dev/null +++ b/vendor/plugins/gravatar/Rakefile @@ -0,0 +1,33 @@ +require 'spec/rake/spectask' +require 'rake/rdoctask' + +desc 'Default: run all specs' +task :default => :spec + +desc 'Run all application-specific specs' +Spec::Rake::SpecTask.new(:spec) do |t| + t.warning = true + t.rcov = true +end + +desc "Report code statistics (KLOCs, etc) from the application" +task :stats do + RAILS_ROOT = File.dirname(__FILE__) + STATS_DIRECTORIES = [ + %w(Libraries lib/), + %w(Specs spec/), + ].collect { |name, dir| [ name, "#{RAILS_ROOT}/#{dir}" ] }.select { |name, dir| File.directory?(dir) } + require 'code_statistics' + CodeStatistics.new(*STATS_DIRECTORIES).to_s +end + +namespace :doc do + desc 'Generate documentation for the assert_request plugin.' + Rake::RDocTask.new(:plugin) do |rdoc| + rdoc.rdoc_dir = 'rdoc' + rdoc.title = 'Gravatar Rails Plugin' + rdoc.options << '--line-numbers' << '--inline-source' << '--accessor' << 'cattr_accessor=rw' + rdoc.rdoc_files.include('README') + rdoc.rdoc_files.include('lib/**/*.rb') + end +end diff --git a/vendor/plugins/gravatar/about.yml b/vendor/plugins/gravatar/about.yml new file mode 100644 index 000000000..a801d2582 --- /dev/null +++ b/vendor/plugins/gravatar/about.yml @@ -0,0 +1,7 @@ +author: Scott Woods, West Arete Computing +summary: View helpers for displaying gravatars. +homepage: http://gravatarplugin.rubyforge.org/ +plugin: svn://rubyforge.org//var/svn/gravatarplugin/plugins/gravatar +license: MIT +version: 0.1 +rails_version: 1.0+ diff --git a/vendor/plugins/gravatar/init.rb b/vendor/plugins/gravatar/init.rb new file mode 100644 index 000000000..aab3f75f3 --- /dev/null +++ b/vendor/plugins/gravatar/init.rb @@ -0,0 +1,2 @@ +require 'gravatar' +ActionView::Base.send :include, GravatarHelper::PublicMethods diff --git a/vendor/plugins/gravatar/lib/gravatar.rb b/vendor/plugins/gravatar/lib/gravatar.rb new file mode 100644 index 000000000..58cb4cabe --- /dev/null +++ b/vendor/plugins/gravatar/lib/gravatar.rb @@ -0,0 +1,67 @@ +require 'digest/md5' +require 'cgi' + +module GravatarHelper + + # These are the options that control the default behavior of the public + # methods. They can be overridden during the actual call to the helper, + # or you can set them in your environment.rb as such: + # + # # Allow racier gravatars + # GravatarHelper::DEFAULT_OPTIONS[:rating] = 'R' + # + DEFAULT_OPTIONS = { + # The URL of a default image to display if the given email address does + # not have a gravatar. + :default => nil, + + # The default size in pixels for the gravatar image (they're square). + :size => 50, + + # The maximum allowed MPAA rating for gravatars. This allows you to + # exclude gravatars that may be out of character for your site. + :rating => 'PG', + + # The alt text to use in the img tag for the gravatar. + :alt => 'avatar', + + # The class to assign to the img tag for the gravatar. + :class => 'gravatar', + } + + # The methods that will be made available to your views. + module PublicMethods + + # Return the HTML img tag for the given user's gravatar. Presumes that + # the given user object will respond_to "email", and return the user's + # email address. + def gravatar_for(user, options={}) + gravatar(user.email, options) + end + + # Return the HTML img tag for the given email address's gravatar. + def gravatar(email, options={}) + src = h(gravatar_url(email, options)) + options = DEFAULT_OPTIONS.merge(options) + [:class, :alt, :size].each { |opt| options[opt] = h(options[opt]) } + "\"#{options[:alt]}\"" + end + + # Return the gravatar URL for the given email address. + def gravatar_url(email, options={}) + email_hash = Digest::MD5.hexdigest(email) + options = DEFAULT_OPTIONS.merge(options) + options[:default] = CGI::escape(options[:default]) unless options[:default].nil? + returning "http://www.gravatar.com/avatar.php?gravatar_id=#{email_hash}" do |url| + [:rating, :size, :default].each do |opt| + unless options[opt].nil? + value = h(options[opt]) + url << "&#{opt}=#{value}" + end + end + end + end + + end + +end \ No newline at end of file diff --git a/vendor/plugins/gravatar/spec/gravatar_spec.rb b/vendor/plugins/gravatar/spec/gravatar_spec.rb new file mode 100644 index 000000000..a11d2683a --- /dev/null +++ b/vendor/plugins/gravatar/spec/gravatar_spec.rb @@ -0,0 +1,37 @@ +require 'rubygems' +require 'erb' # to get "h" +require 'active_support' # to get "returning" +require File.dirname(__FILE__) + '/../lib/gravatar' +include GravatarHelper, GravatarHelper::PublicMethods, ERB::Util + +context "gravatar_url with a custom default URL" do + setup do + @original_options = DEFAULT_OPTIONS.dup + DEFAULT_OPTIONS[:default] = "no_avatar.png" + @url = gravatar_url("somewhere") + end + + specify "should include the \"default\" argument in the result" do + @url.should match(/&default=no_avatar.png/) + end + + teardown do + DEFAULT_OPTIONS.merge!(@original_options) + end + +end + +context "gravatar_url with default settings" do + setup do + @url = gravatar_url("somewhere") + end + + specify "should have a nil default URL" do + DEFAULT_OPTIONS[:default].should be_nil + end + + specify "should not include the \"default\" argument in the result" do + @url.should_not match(/&default=/) + end + +end \ No newline at end of file diff --git a/vendor/plugins/open_id_authentication/CHANGELOG b/vendor/plugins/open_id_authentication/CHANGELOG new file mode 100644 index 000000000..7349bd3c0 --- /dev/null +++ b/vendor/plugins/open_id_authentication/CHANGELOG @@ -0,0 +1,35 @@ +* Fake HTTP method from OpenID server since they only support a GET. Eliminates the need to set an extra route to match the server's reply. [Josh Peek] + +* OpenID 2.0 recommends that forms should use the field name "openid_identifier" rather than "openid_url" [Josh Peek] + +* Return open_id_response.display_identifier to the application instead of .endpoints.claimed_id. [nbibler] + +* Add Timeout protection [Rick] + +* An invalid identity url passed through authenticate_with_open_id will no longer raise an InvalidOpenId exception. Instead it will return Result[:missing] to the completion block. + +* Allow a return_to option to be used instead of the requested url [Josh Peek] + +* Updated plugin to use Ruby OpenID 2.x.x [Josh Peek] + +* Tied plugin to ruby-openid 1.1.4 gem until we can make it compatible with 2.x [DHH] + +* Use URI instead of regexps to normalize the URL and gain free, better matching #8136 [dkubb] + +* Allow -'s in #normalize_url [Rick] + +* remove instance of mattr_accessor, it was breaking tests since they don't load ActiveSupport. Fix Timeout test [Rick] + +* Throw a InvalidOpenId exception instead of just a RuntimeError when the URL can't be normalized [DHH] + +* Just use the path for the return URL, so extra query parameters don't interfere [DHH] + +* Added a new default database-backed store after experiencing trouble with the filestore on NFS. The file store is still available as an option [DHH] + +* Added normalize_url and applied it to all operations going through the plugin [DHH] + +* Removed open_id? as the idea of using the same input box for both OpenID and username has died -- use using_open_id? instead (which checks for the presence of params[:openid_url] by default) [DHH] + +* Added OpenIdAuthentication::Result to make it easier to deal with default situations where you don't care to do something particular for each error state [DHH] + +* Stop relying on root_url being defined, we can just grab the current url instead [DHH] \ No newline at end of file diff --git a/vendor/plugins/open_id_authentication/README b/vendor/plugins/open_id_authentication/README new file mode 100644 index 000000000..807cdc756 --- /dev/null +++ b/vendor/plugins/open_id_authentication/README @@ -0,0 +1,231 @@ +OpenIdAuthentication +==================== + +Provides a thin wrapper around the excellent ruby-openid gem from JanRan. Be sure to install that first: + + gem install ruby-openid + +To understand what OpenID is about and how it works, it helps to read the documentation for lib/openid/consumer.rb +from that gem. + +The specification used is http://openid.net/specs/openid-authentication-2_0.html. + + +Prerequisites +============= + +OpenID authentication uses the session, so be sure that you haven't turned that off. It also relies on a number of +database tables to store the authentication keys. So you'll have to run the migration to create these before you get started: + + rake open_id_authentication:db:create + +Or, use the included generators to install or upgrade: + + ./script/generate open_id_authentication_tables MigrationName + ./script/generate upgrade_open_id_authentication_tables MigrationName + +Alternatively, you can use the file-based store, which just relies on on tmp/openids being present in RAILS_ROOT. But be aware that this store only works if you have a single application server. And it's not safe to use across NFS. It's recommended that you use the database store if at all possible. To use the file-based store, you'll also have to add this line to your config/environment.rb: + + OpenIdAuthentication.store = :file + +This particular plugin also relies on the fact that the authentication action allows for both POST and GET operations. +If you're using RESTful authentication, you'll need to explicitly allow for this in your routes.rb. + +The plugin also expects to find a root_url method that points to the home page of your site. You can accomplish this by using a root route in config/routes.rb: + + map.root :controller => 'articles' + +This plugin relies on Rails Edge revision 6317 or newer. + + +Example +======= + +This example is just to meant to demonstrate how you could use OpenID authentication. You might well want to add +salted hash logins instead of plain text passwords and other requirements on top of this. Treat it as a starting point, +not a destination. + +Note that the User model referenced in the simple example below has an 'identity_url' attribute. You will want to add the same or similar field to whatever +model you are using for authentication. + +Also of note is the following code block used in the example below: + + authenticate_with_open_id do |result, identity_url| + ... + end + +In the above code block, 'identity_url' will need to match user.identity_url exactly. 'identity_url' will be a string in the form of 'http://example.com' - +If you are storing just 'example.com' with your user, the lookup will fail. + +There is a handy method in this plugin called 'normalize_url' that will help with validating OpenID URLs. + + OpenIdAuthentication.normalize_url(user.identity_url) + +The above will return a standardized version of the OpenID URL - the above called with 'example.com' will return 'http://example.com/' +It will also raise an InvalidOpenId exception if the URL is determined to not be valid. +Use the above code in your User model and validate OpenID URLs before saving them. + +config/routes.rb + + map.root :controller => 'articles' + map.resource :session + + +app/views/sessions/new.erb + + <% form_tag(session_url) do %> +

    + + <%= text_field_tag "name" %> +

    + +

    + + <%= password_field_tag %> +

    + +

    + ...or use: +

    + +

    + + <%= text_field_tag "openid_identifier" %> +

    + +

    + <%= submit_tag 'Sign in', :disable_with => "Signing in…" %> +

    + <% end %> + +app/controllers/sessions_controller.rb + class SessionsController < ApplicationController + def create + if using_open_id? + open_id_authentication + else + password_authentication(params[:name], params[:password]) + end + end + + + protected + def password_authentication(name, password) + if @current_user = @account.users.authenticate(params[:name], params[:password]) + successful_login + else + failed_login "Sorry, that username/password doesn't work" + end + end + + def open_id_authentication + authenticate_with_open_id do |result, identity_url| + if result.successful? + if @current_user = @account.users.find_by_identity_url(identity_url) + successful_login + else + failed_login "Sorry, no user by that identity URL exists (#{identity_url})" + end + else + failed_login result.message + end + end + end + + + private + def successful_login + session[:user_id] = @current_user.id + redirect_to(root_url) + end + + def failed_login(message) + flash[:error] = message + redirect_to(new_session_url) + end + end + + + +If you're fine with the result messages above and don't need individual logic on a per-failure basis, +you can collapse the case into a mere boolean: + + def open_id_authentication + authenticate_with_open_id do |result, identity_url| + if result.successful? && @current_user = @account.users.find_by_identity_url(identity_url) + successful_login + else + failed_login(result.message || "Sorry, no user by that identity URL exists (#{identity_url})") + end + end + end + + +Simple Registration OpenID Extension +==================================== + +Some OpenID Providers support this lightweight profile exchange protocol. See more: http://www.openidenabled.com/openid/simple-registration-extension + +You can support it in your app by changing #open_id_authentication + + def open_id_authentication(identity_url) + # Pass optional :required and :optional keys to specify what sreg fields you want. + # Be sure to yield registration, a third argument in the #authenticate_with_open_id block. + authenticate_with_open_id(identity_url, + :required => [ :nickname, :email ], + :optional => :fullname) do |result, identity_url, registration| + case result.status + when :missing + failed_login "Sorry, the OpenID server couldn't be found" + when :invalid + failed_login "Sorry, but this does not appear to be a valid OpenID" + when :canceled + failed_login "OpenID verification was canceled" + when :failed + failed_login "Sorry, the OpenID verification failed" + when :successful + if @current_user = @account.users.find_by_identity_url(identity_url) + assign_registration_attributes!(registration) + + if current_user.save + successful_login + else + failed_login "Your OpenID profile registration failed: " + + @current_user.errors.full_messages.to_sentence + end + else + failed_login "Sorry, no user by that identity URL exists" + end + end + end + end + + # registration is a hash containing the valid sreg keys given above + # use this to map them to fields of your user model + def assign_registration_attributes!(registration) + model_to_registration_mapping.each do |model_attribute, registration_attribute| + unless registration[registration_attribute].blank? + @current_user.send("#{model_attribute}=", registration[registration_attribute]) + end + end + end + + def model_to_registration_mapping + { :login => 'nickname', :email => 'email', :display_name => 'fullname' } + end + +Attribute Exchange OpenID Extension +=================================== + +Some OpenID providers also support the OpenID AX (attribute exchange) protocol for exchanging identity information between endpoints. See more: http://openid.net/specs/openid-attribute-exchange-1_0.html + +Accessing AX data is very similar to the Simple Registration process, described above -- just add the URI identifier for the AX field to your :optional or :required parameters. For example: + + authenticate_with_open_id(identity_url, + :required => [ :email, 'http://schema.openid.net/birthDate' ]) do |result, identity_url, registration| + +This would provide the sreg data for :email, and the AX data for 'http://schema.openid.net/birthDate' + + + +Copyright (c) 2007 David Heinemeier Hansson, released under the MIT license \ No newline at end of file diff --git a/vendor/plugins/open_id_authentication/Rakefile b/vendor/plugins/open_id_authentication/Rakefile new file mode 100644 index 000000000..31074b856 --- /dev/null +++ b/vendor/plugins/open_id_authentication/Rakefile @@ -0,0 +1,22 @@ +require 'rake' +require 'rake/testtask' +require 'rake/rdoctask' + +desc 'Default: run unit tests.' +task :default => :test + +desc 'Test the open_id_authentication plugin.' +Rake::TestTask.new(:test) do |t| + t.libs << 'lib' + t.pattern = 'test/**/*_test.rb' + t.verbose = true +end + +desc 'Generate documentation for the open_id_authentication plugin.' +Rake::RDocTask.new(:rdoc) do |rdoc| + rdoc.rdoc_dir = 'rdoc' + rdoc.title = 'OpenIdAuthentication' + rdoc.options << '--line-numbers' << '--inline-source' + rdoc.rdoc_files.include('README') + rdoc.rdoc_files.include('lib/**/*.rb') +end diff --git a/vendor/plugins/open_id_authentication/generators/open_id_authentication_tables/open_id_authentication_tables_generator.rb b/vendor/plugins/open_id_authentication/generators/open_id_authentication_tables/open_id_authentication_tables_generator.rb new file mode 100644 index 000000000..6f78afc71 --- /dev/null +++ b/vendor/plugins/open_id_authentication/generators/open_id_authentication_tables/open_id_authentication_tables_generator.rb @@ -0,0 +1,11 @@ +class OpenIdAuthenticationTablesGenerator < Rails::Generator::NamedBase + def initialize(runtime_args, runtime_options = {}) + super + end + + def manifest + record do |m| + m.migration_template 'migration.rb', 'db/migrate' + end + end +end diff --git a/vendor/plugins/open_id_authentication/generators/open_id_authentication_tables/templates/migration.rb b/vendor/plugins/open_id_authentication/generators/open_id_authentication_tables/templates/migration.rb new file mode 100644 index 000000000..ef2a0cfb4 --- /dev/null +++ b/vendor/plugins/open_id_authentication/generators/open_id_authentication_tables/templates/migration.rb @@ -0,0 +1,20 @@ +class <%= class_name %> < ActiveRecord::Migration + def self.up + create_table :open_id_authentication_associations, :force => true do |t| + t.integer :issued, :lifetime + t.string :handle, :assoc_type + t.binary :server_url, :secret + end + + create_table :open_id_authentication_nonces, :force => true do |t| + t.integer :timestamp, :null => false + t.string :server_url, :null => true + t.string :salt, :null => false + end + end + + def self.down + drop_table :open_id_authentication_associations + drop_table :open_id_authentication_nonces + end +end diff --git a/vendor/plugins/open_id_authentication/generators/upgrade_open_id_authentication_tables/templates/migration.rb b/vendor/plugins/open_id_authentication/generators/upgrade_open_id_authentication_tables/templates/migration.rb new file mode 100644 index 000000000..d13bbab23 --- /dev/null +++ b/vendor/plugins/open_id_authentication/generators/upgrade_open_id_authentication_tables/templates/migration.rb @@ -0,0 +1,26 @@ +class <%= class_name %> < ActiveRecord::Migration + def self.up + drop_table :open_id_authentication_settings + drop_table :open_id_authentication_nonces + + create_table :open_id_authentication_nonces, :force => true do |t| + t.integer :timestamp, :null => false + t.string :server_url, :null => true + t.string :salt, :null => false + end + end + + def self.down + drop_table :open_id_authentication_nonces + + create_table :open_id_authentication_nonces, :force => true do |t| + t.integer :created + t.string :nonce + end + + create_table :open_id_authentication_settings, :force => true do |t| + t.string :setting + t.binary :value + end + end +end diff --git a/vendor/plugins/open_id_authentication/generators/upgrade_open_id_authentication_tables/upgrade_open_id_authentication_tables_generator.rb b/vendor/plugins/open_id_authentication/generators/upgrade_open_id_authentication_tables/upgrade_open_id_authentication_tables_generator.rb new file mode 100644 index 000000000..02fddd7fd --- /dev/null +++ b/vendor/plugins/open_id_authentication/generators/upgrade_open_id_authentication_tables/upgrade_open_id_authentication_tables_generator.rb @@ -0,0 +1,11 @@ +class UpgradeOpenIdAuthenticationTablesGenerator < Rails::Generator::NamedBase + def initialize(runtime_args, runtime_options = {}) + super + end + + def manifest + record do |m| + m.migration_template 'migration.rb', 'db/migrate' + end + end +end diff --git a/vendor/plugins/open_id_authentication/init.rb b/vendor/plugins/open_id_authentication/init.rb new file mode 100644 index 000000000..2055ef700 --- /dev/null +++ b/vendor/plugins/open_id_authentication/init.rb @@ -0,0 +1,16 @@ +begin + require 'openid' +rescue LoadError + begin + gem 'ruby-openid', '>=2.1.4' + rescue Gem::LoadError + # no openid support + end +end + +if Object.const_defined?(:OpenID) + config.to_prepare do + OpenID::Util.logger = Rails.logger + ActionController::Base.send :include, OpenIdAuthentication + end +end diff --git a/vendor/plugins/open_id_authentication/lib/open_id_authentication.rb b/vendor/plugins/open_id_authentication/lib/open_id_authentication.rb new file mode 100644 index 000000000..54a38acc1 --- /dev/null +++ b/vendor/plugins/open_id_authentication/lib/open_id_authentication.rb @@ -0,0 +1,241 @@ +require 'uri' +require 'openid/extensions/sreg' +require 'openid/extensions/ax' +require 'openid/store/filesystem' + +require File.dirname(__FILE__) + '/open_id_authentication/db_store' +require File.dirname(__FILE__) + '/open_id_authentication/mem_cache_store' +require File.dirname(__FILE__) + '/open_id_authentication/request' +require File.dirname(__FILE__) + '/open_id_authentication/timeout_fixes' if OpenID::VERSION == "2.0.4" + +module OpenIdAuthentication + OPEN_ID_AUTHENTICATION_DIR = RAILS_ROOT + "/tmp/openids" + + def self.store + @@store + end + + def self.store=(*store_option) + store, *parameters = *([ store_option ].flatten) + + @@store = case store + when :db + OpenIdAuthentication::DbStore.new + when :mem_cache + OpenIdAuthentication::MemCacheStore.new(*parameters) + when :file + OpenID::Store::Filesystem.new(OPEN_ID_AUTHENTICATION_DIR) + else + raise "Unknown store: #{store}" + end + end + + self.store = :db + + class InvalidOpenId < StandardError + end + + class Result + ERROR_MESSAGES = { + :missing => "Sorry, the OpenID server couldn't be found", + :invalid => "Sorry, but this does not appear to be a valid OpenID", + :canceled => "OpenID verification was canceled", + :failed => "OpenID verification failed", + :setup_needed => "OpenID verification needs setup" + } + + def self.[](code) + new(code) + end + + def initialize(code) + @code = code + end + + def status + @code + end + + ERROR_MESSAGES.keys.each { |state| define_method("#{state}?") { @code == state } } + + def successful? + @code == :successful + end + + def unsuccessful? + ERROR_MESSAGES.keys.include?(@code) + end + + def message + ERROR_MESSAGES[@code] + end + end + + # normalizes an OpenID according to http://openid.net/specs/openid-authentication-2_0.html#normalization + def self.normalize_identifier(identifier) + # clean up whitespace + identifier = identifier.to_s.strip + + # if an XRI has a prefix, strip it. + identifier.gsub!(/xri:\/\//i, '') + + # dodge XRIs -- TODO: validate, don't just skip. + unless ['=', '@', '+', '$', '!', '('].include?(identifier.at(0)) + # does it begin with http? if not, add it. + identifier = "http://#{identifier}" unless identifier =~ /^http/i + + # strip any fragments + identifier.gsub!(/\#(.*)$/, '') + + begin + uri = URI.parse(identifier) + uri.scheme = uri.scheme.downcase # URI should do this + identifier = uri.normalize.to_s + rescue URI::InvalidURIError + raise InvalidOpenId.new("#{identifier} is not an OpenID identifier") + end + end + + return identifier + end + + # deprecated for OpenID 2.0, where not all OpenIDs are URLs + def self.normalize_url(url) + ActiveSupport::Deprecation.warn "normalize_url has been deprecated, use normalize_identifier instead" + self.normalize_identifier(url) + end + + protected + def normalize_url(url) + OpenIdAuthentication.normalize_url(url) + end + + def normalize_identifier(url) + OpenIdAuthentication.normalize_identifier(url) + end + + # The parameter name of "openid_identifier" is used rather than the Rails convention "open_id_identifier" + # because that's what the specification dictates in order to get browser auto-complete working across sites + def using_open_id?(identity_url = nil) #:doc: + identity_url ||= params[:openid_identifier] || params[:openid_url] + !identity_url.blank? || params[:open_id_complete] + end + + def authenticate_with_open_id(identity_url = nil, options = {}, &block) #:doc: + identity_url ||= params[:openid_identifier] || params[:openid_url] + + if params[:open_id_complete].nil? + begin_open_id_authentication(identity_url, options, &block) + else + complete_open_id_authentication(&block) + end + end + + private + def begin_open_id_authentication(identity_url, options = {}) + identity_url = normalize_identifier(identity_url) + return_to = options.delete(:return_to) + method = options.delete(:method) + + options[:required] ||= [] # reduces validation later + options[:optional] ||= [] + + open_id_request = open_id_consumer.begin(identity_url) + add_simple_registration_fields(open_id_request, options) + add_ax_fields(open_id_request, options) + redirect_to(open_id_redirect_url(open_id_request, return_to, method)) + rescue OpenIdAuthentication::InvalidOpenId => e + yield Result[:invalid], identity_url, nil + rescue OpenID::OpenIDError, Timeout::Error => e + logger.error("[OPENID] #{e}") + yield Result[:missing], identity_url, nil + end + + def complete_open_id_authentication + params_with_path = params.reject { |key, value| request.path_parameters[key] } + params_with_path.delete(:format) + open_id_response = timeout_protection_from_identity_server { open_id_consumer.complete(params_with_path, requested_url) } + identity_url = normalize_identifier(open_id_response.display_identifier) if open_id_response.display_identifier + + case open_id_response.status + when OpenID::Consumer::SUCCESS + profile_data = {} + + # merge the SReg data and the AX data into a single hash of profile data + [ OpenID::SReg::Response, OpenID::AX::FetchResponse ].each do |data_response| + if data_response.from_success_response( open_id_response ) + profile_data.merge! data_response.from_success_response( open_id_response ).data + end + end + + yield Result[:successful], identity_url, profile_data + when OpenID::Consumer::CANCEL + yield Result[:canceled], identity_url, nil + when OpenID::Consumer::FAILURE + yield Result[:failed], identity_url, nil + when OpenID::Consumer::SETUP_NEEDED + yield Result[:setup_needed], open_id_response.setup_url, nil + end + end + + def open_id_consumer + OpenID::Consumer.new(session, OpenIdAuthentication.store) + end + + def add_simple_registration_fields(open_id_request, fields) + sreg_request = OpenID::SReg::Request.new + + # filter out AX identifiers (URIs) + required_fields = fields[:required].collect { |f| f.to_s unless f =~ /^https?:\/\// }.compact + optional_fields = fields[:optional].collect { |f| f.to_s unless f =~ /^https?:\/\// }.compact + + sreg_request.request_fields(required_fields, true) unless required_fields.blank? + sreg_request.request_fields(optional_fields, false) unless optional_fields.blank? + sreg_request.policy_url = fields[:policy_url] if fields[:policy_url] + open_id_request.add_extension(sreg_request) + end + + def add_ax_fields( open_id_request, fields ) + ax_request = OpenID::AX::FetchRequest.new + + # look through the :required and :optional fields for URIs (AX identifiers) + fields[:required].each do |f| + next unless f =~ /^https?:\/\// + ax_request.add( OpenID::AX::AttrInfo.new( f, nil, true ) ) + end + + fields[:optional].each do |f| + next unless f =~ /^https?:\/\// + ax_request.add( OpenID::AX::AttrInfo.new( f, nil, false ) ) + end + + open_id_request.add_extension( ax_request ) + end + + def open_id_redirect_url(open_id_request, return_to = nil, method = nil) + open_id_request.return_to_args['_method'] = (method || request.method).to_s + open_id_request.return_to_args['open_id_complete'] = '1' + open_id_request.redirect_url(root_url, return_to || requested_url) + end + + def requested_url + relative_url_root = self.class.respond_to?(:relative_url_root) ? + self.class.relative_url_root.to_s : + request.relative_url_root + "#{request.protocol}#{request.host_with_port}#{ActionController::AbstractRequest.relative_url_root}#{request.path}" + end + + def timeout_protection_from_identity_server + yield + rescue Timeout::Error + Class.new do + def status + OpenID::FAILURE + end + + def msg + "Identity server timed out" + end + end.new + end +end diff --git a/vendor/plugins/open_id_authentication/lib/open_id_authentication/association.rb b/vendor/plugins/open_id_authentication/lib/open_id_authentication/association.rb new file mode 100644 index 000000000..9654eaeb2 --- /dev/null +++ b/vendor/plugins/open_id_authentication/lib/open_id_authentication/association.rb @@ -0,0 +1,9 @@ +module OpenIdAuthentication + class Association < ActiveRecord::Base + set_table_name :open_id_authentication_associations + + def from_record + OpenID::Association.new(handle, secret, issued, lifetime, assoc_type) + end + end +end diff --git a/vendor/plugins/open_id_authentication/lib/open_id_authentication/db_store.rb b/vendor/plugins/open_id_authentication/lib/open_id_authentication/db_store.rb new file mode 100644 index 000000000..780fb6ad2 --- /dev/null +++ b/vendor/plugins/open_id_authentication/lib/open_id_authentication/db_store.rb @@ -0,0 +1,55 @@ +require 'openid/store/interface' + +module OpenIdAuthentication + class DbStore < OpenID::Store::Interface + def self.cleanup_nonces + now = Time.now.to_i + Nonce.delete_all(["timestamp > ? OR timestamp < ?", now + OpenID::Nonce.skew, now - OpenID::Nonce.skew]) + end + + def self.cleanup_associations + now = Time.now.to_i + Association.delete_all(['issued + lifetime > ?',now]) + end + + def store_association(server_url, assoc) + remove_association(server_url, assoc.handle) + Association.create(:server_url => server_url, + :handle => assoc.handle, + :secret => assoc.secret, + :issued => assoc.issued, + :lifetime => assoc.lifetime, + :assoc_type => assoc.assoc_type) + end + + def get_association(server_url, handle = nil) + assocs = if handle.blank? + Association.find_all_by_server_url(server_url) + else + Association.find_all_by_server_url_and_handle(server_url, handle) + end + + assocs.reverse.each do |assoc| + a = assoc.from_record + if a.expires_in == 0 + assoc.destroy + else + return a + end + end if assocs.any? + + return nil + end + + def remove_association(server_url, handle) + Association.delete_all(['server_url = ? AND handle = ?', server_url, handle]) > 0 + end + + def use_nonce(server_url, timestamp, salt) + return false if Nonce.find_by_server_url_and_timestamp_and_salt(server_url, timestamp, salt) + return false if (timestamp - Time.now.to_i).abs > OpenID::Nonce.skew + Nonce.create(:server_url => server_url, :timestamp => timestamp, :salt => salt) + return true + end + end +end diff --git a/vendor/plugins/open_id_authentication/lib/open_id_authentication/mem_cache_store.rb b/vendor/plugins/open_id_authentication/lib/open_id_authentication/mem_cache_store.rb new file mode 100644 index 000000000..b520e4a8b --- /dev/null +++ b/vendor/plugins/open_id_authentication/lib/open_id_authentication/mem_cache_store.rb @@ -0,0 +1,73 @@ +require 'digest/sha1' +require 'openid/store/interface' + +module OpenIdAuthentication + class MemCacheStore < OpenID::Store::Interface + def initialize(*addresses) + @connection = ActiveSupport::Cache::MemCacheStore.new(addresses) + end + + def store_association(server_url, assoc) + server_key = association_server_key(server_url) + assoc_key = association_key(server_url, assoc.handle) + + assocs = @connection.read(server_key) || {} + assocs[assoc.issued] = assoc_key + + @connection.write(server_key, assocs) + @connection.write(assoc_key, assoc, :expires_in => assoc.lifetime) + end + + def get_association(server_url, handle = nil) + if handle + @connection.read(association_key(server_url, handle)) + else + server_key = association_server_key(server_url) + assocs = @connection.read(server_key) + return if assocs.nil? + + last_key = assocs[assocs.keys.sort.last] + @connection.read(last_key) + end + end + + def remove_association(server_url, handle) + server_key = association_server_key(server_url) + assoc_key = association_key(server_url, handle) + assocs = @connection.read(server_key) + + return false unless assocs && assocs.has_value?(assoc_key) + + assocs = assocs.delete_if { |key, value| value == assoc_key } + + @connection.write(server_key, assocs) + @connection.delete(assoc_key) + + return true + end + + def use_nonce(server_url, timestamp, salt) + return false if @connection.read(nonce_key(server_url, salt)) + return false if (timestamp - Time.now.to_i).abs > OpenID::Nonce.skew + @connection.write(nonce_key(server_url, salt), timestamp, :expires_in => OpenID::Nonce.skew) + return true + end + + private + def association_key(server_url, handle = nil) + "openid_association_#{digest(server_url)}_#{digest(handle)}" + end + + def association_server_key(server_url) + "openid_association_server_#{digest(server_url)}" + end + + def nonce_key(server_url, salt) + "openid_nonce_#{digest(server_url)}_#{digest(salt)}" + end + + def digest(text) + Digest::SHA1.hexdigest(text) + end + end +end diff --git a/vendor/plugins/open_id_authentication/lib/open_id_authentication/nonce.rb b/vendor/plugins/open_id_authentication/lib/open_id_authentication/nonce.rb new file mode 100644 index 000000000..c52f6c50d --- /dev/null +++ b/vendor/plugins/open_id_authentication/lib/open_id_authentication/nonce.rb @@ -0,0 +1,5 @@ +module OpenIdAuthentication + class Nonce < ActiveRecord::Base + set_table_name :open_id_authentication_nonces + end +end diff --git a/vendor/plugins/open_id_authentication/lib/open_id_authentication/request.rb b/vendor/plugins/open_id_authentication/lib/open_id_authentication/request.rb new file mode 100644 index 000000000..e0cc8e3fc --- /dev/null +++ b/vendor/plugins/open_id_authentication/lib/open_id_authentication/request.rb @@ -0,0 +1,23 @@ +module OpenIdAuthentication + module Request + def self.included(base) + base.alias_method_chain :request_method, :openid + end + + def request_method_with_openid + if !parameters[:_method].blank? && parameters[:open_id_complete] == '1' + parameters[:_method].to_sym + else + request_method_without_openid + end + end + end +end + +# In Rails 2.3, the request object has been renamed +# from AbstractRequest to Request +if defined? ActionController::Request + ActionController::Request.send :include, OpenIdAuthentication::Request +else + ActionController::AbstractRequest.send :include, OpenIdAuthentication::Request +end diff --git a/vendor/plugins/open_id_authentication/lib/open_id_authentication/timeout_fixes.rb b/vendor/plugins/open_id_authentication/lib/open_id_authentication/timeout_fixes.rb new file mode 100644 index 000000000..cc711c9ac --- /dev/null +++ b/vendor/plugins/open_id_authentication/lib/open_id_authentication/timeout_fixes.rb @@ -0,0 +1,20 @@ +# http://trac.openidenabled.com/trac/ticket/156 +module OpenID + @@timeout_threshold = 20 + + def self.timeout_threshold + @@timeout_threshold + end + + def self.timeout_threshold=(value) + @@timeout_threshold = value + end + + class StandardFetcher + def make_http(uri) + http = @proxy.new(uri.host, uri.port) + http.read_timeout = http.open_timeout = OpenID.timeout_threshold + http + end + end +end \ No newline at end of file diff --git a/vendor/plugins/open_id_authentication/tasks/open_id_authentication_tasks.rake b/vendor/plugins/open_id_authentication/tasks/open_id_authentication_tasks.rake new file mode 100644 index 000000000..c71434a50 --- /dev/null +++ b/vendor/plugins/open_id_authentication/tasks/open_id_authentication_tasks.rake @@ -0,0 +1,30 @@ +namespace :open_id_authentication do + namespace :db do + desc "Creates authentication tables for use with OpenIdAuthentication" + task :create => :environment do + generate_migration(["open_id_authentication_tables", "add_open_id_authentication_tables"]) + end + + desc "Upgrade authentication tables from ruby-openid 1.x.x to 2.x.x" + task :upgrade => :environment do + generate_migration(["upgrade_open_id_authentication_tables", "upgrade_open_id_authentication_tables"]) + end + + def generate_migration(args) + require 'rails_generator' + require 'rails_generator/scripts/generate' + + if ActiveRecord::Base.connection.supports_migrations? + Rails::Generator::Scripts::Generate.new.run(args) + else + raise "Task unavailable to this database (no migration support)" + end + end + + desc "Clear the authentication tables" + task :clear => :environment do + OpenIdAuthentication::DbStore.cleanup_nonces + OpenIdAuthentication::DbStore.cleanup_associations + end + end +end diff --git a/vendor/plugins/open_id_authentication/test/mem_cache_store_test.rb b/vendor/plugins/open_id_authentication/test/mem_cache_store_test.rb new file mode 100644 index 000000000..18a943979 --- /dev/null +++ b/vendor/plugins/open_id_authentication/test/mem_cache_store_test.rb @@ -0,0 +1,151 @@ +require File.dirname(__FILE__) + '/test_helper' +require File.dirname(__FILE__) + '/../lib/open_id_authentication/mem_cache_store' + +# Mock MemCacheStore with MemoryStore for testing +class OpenIdAuthentication::MemCacheStore < OpenID::Store::Interface + def initialize(*addresses) + @connection = ActiveSupport::Cache::MemoryStore.new + end +end + +class MemCacheStoreTest < Test::Unit::TestCase + ALLOWED_HANDLE = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~' + + def setup + @store = OpenIdAuthentication::MemCacheStore.new + end + + def test_store + server_url = "http://www.myopenid.com/openid" + assoc = gen_assoc(0) + + # Make sure that a missing association returns no result + assert_retrieve(server_url) + + # Check that after storage, getting returns the same result + @store.store_association(server_url, assoc) + assert_retrieve(server_url, nil, assoc) + + # more than once + assert_retrieve(server_url, nil, assoc) + + # Storing more than once has no ill effect + @store.store_association(server_url, assoc) + assert_retrieve(server_url, nil, assoc) + + # Removing an association that does not exist returns not present + assert_remove(server_url, assoc.handle + 'x', false) + + # Removing an association that does not exist returns not present + assert_remove(server_url + 'x', assoc.handle, false) + + # Removing an association that is present returns present + assert_remove(server_url, assoc.handle, true) + + # but not present on subsequent calls + assert_remove(server_url, assoc.handle, false) + + # Put assoc back in the store + @store.store_association(server_url, assoc) + + # More recent and expires after assoc + assoc2 = gen_assoc(1) + @store.store_association(server_url, assoc2) + + # After storing an association with a different handle, but the + # same server_url, the handle with the later expiration is returned. + assert_retrieve(server_url, nil, assoc2) + + # We can still retrieve the older association + assert_retrieve(server_url, assoc.handle, assoc) + + # Plus we can retrieve the association with the later expiration + # explicitly + assert_retrieve(server_url, assoc2.handle, assoc2) + + # More recent, and expires earlier than assoc2 or assoc. Make sure + # that we're picking the one with the latest issued date and not + # taking into account the expiration. + assoc3 = gen_assoc(2, 100) + @store.store_association(server_url, assoc3) + + assert_retrieve(server_url, nil, assoc3) + assert_retrieve(server_url, assoc.handle, assoc) + assert_retrieve(server_url, assoc2.handle, assoc2) + assert_retrieve(server_url, assoc3.handle, assoc3) + + assert_remove(server_url, assoc2.handle, true) + + assert_retrieve(server_url, nil, assoc3) + assert_retrieve(server_url, assoc.handle, assoc) + assert_retrieve(server_url, assoc2.handle, nil) + assert_retrieve(server_url, assoc3.handle, assoc3) + + assert_remove(server_url, assoc2.handle, false) + assert_remove(server_url, assoc3.handle, true) + + assert_retrieve(server_url, nil, assoc) + assert_retrieve(server_url, assoc.handle, assoc) + assert_retrieve(server_url, assoc2.handle, nil) + assert_retrieve(server_url, assoc3.handle, nil) + + assert_remove(server_url, assoc2.handle, false) + assert_remove(server_url, assoc.handle, true) + assert_remove(server_url, assoc3.handle, false) + + assert_retrieve(server_url, nil, nil) + assert_retrieve(server_url, assoc.handle, nil) + assert_retrieve(server_url, assoc2.handle, nil) + assert_retrieve(server_url, assoc3.handle, nil) + + assert_remove(server_url, assoc2.handle, false) + assert_remove(server_url, assoc.handle, false) + assert_remove(server_url, assoc3.handle, false) + end + + def test_nonce + server_url = "http://www.myopenid.com/openid" + + [server_url, ''].each do |url| + nonce1 = OpenID::Nonce::mk_nonce + + assert_nonce(nonce1, true, url, "#{url}: nonce allowed by default") + assert_nonce(nonce1, false, url, "#{url}: nonce not allowed twice") + assert_nonce(nonce1, false, url, "#{url}: nonce not allowed third time") + + # old nonces shouldn't pass + old_nonce = OpenID::Nonce::mk_nonce(3600) + assert_nonce(old_nonce, false, url, "Old nonce #{old_nonce.inspect} passed") + end + end + + private + def gen_assoc(issued, lifetime = 600) + secret = OpenID::CryptUtil.random_string(20, nil) + handle = OpenID::CryptUtil.random_string(128, ALLOWED_HANDLE) + OpenID::Association.new(handle, secret, Time.now + issued, lifetime, 'HMAC-SHA1') + end + + def assert_retrieve(url, handle = nil, expected = nil) + assoc = @store.get_association(url, handle) + + if expected.nil? + assert_nil(assoc) + else + assert_equal(expected, assoc) + assert_equal(expected.handle, assoc.handle) + assert_equal(expected.secret, assoc.secret) + end + end + + def assert_remove(url, handle, expected) + present = @store.remove_association(url, handle) + assert_equal(expected, present) + end + + def assert_nonce(nonce, expected, server_url, msg = "") + stamp, salt = OpenID::Nonce::split_nonce(nonce) + actual = @store.use_nonce(server_url, stamp, salt) + assert_equal(expected, actual, msg) + end +end diff --git a/vendor/plugins/open_id_authentication/test/normalize_test.rb b/vendor/plugins/open_id_authentication/test/normalize_test.rb new file mode 100644 index 000000000..635d3abc9 --- /dev/null +++ b/vendor/plugins/open_id_authentication/test/normalize_test.rb @@ -0,0 +1,32 @@ +require File.dirname(__FILE__) + '/test_helper' + +class NormalizeTest < Test::Unit::TestCase + include OpenIdAuthentication + + NORMALIZATIONS = { + "openid.aol.com/nextangler" => "http://openid.aol.com/nextangler", + "http://openid.aol.com/nextangler" => "http://openid.aol.com/nextangler", + "https://openid.aol.com/nextangler" => "https://openid.aol.com/nextangler", + "HTTP://OPENID.AOL.COM/NEXTANGLER" => "http://openid.aol.com/NEXTANGLER", + "HTTPS://OPENID.AOL.COM/NEXTANGLER" => "https://openid.aol.com/NEXTANGLER", + "loudthinking.com" => "http://loudthinking.com/", + "http://loudthinking.com" => "http://loudthinking.com/", + "http://loudthinking.com:80" => "http://loudthinking.com/", + "https://loudthinking.com:443" => "https://loudthinking.com/", + "http://loudthinking.com:8080" => "http://loudthinking.com:8080/", + "techno-weenie.net" => "http://techno-weenie.net/", + "http://techno-weenie.net" => "http://techno-weenie.net/", + "http://techno-weenie.net " => "http://techno-weenie.net/", + "=name" => "=name" + } + + def test_normalizations + NORMALIZATIONS.each do |from, to| + assert_equal to, normalize_identifier(from) + end + end + + def test_broken_open_id + assert_raises(InvalidOpenId) { normalize_identifier(nil) } + end +end diff --git a/vendor/plugins/open_id_authentication/test/open_id_authentication_test.rb b/vendor/plugins/open_id_authentication/test/open_id_authentication_test.rb new file mode 100644 index 000000000..ddcc17b96 --- /dev/null +++ b/vendor/plugins/open_id_authentication/test/open_id_authentication_test.rb @@ -0,0 +1,46 @@ +require File.dirname(__FILE__) + '/test_helper' + +class OpenIdAuthenticationTest < Test::Unit::TestCase + def setup + @controller = Class.new do + include OpenIdAuthentication + def params() {} end + end.new + end + + def test_authentication_should_fail_when_the_identity_server_is_missing + open_id_consumer = mock() + open_id_consumer.expects(:begin).raises(OpenID::OpenIDError) + @controller.expects(:open_id_consumer).returns(open_id_consumer) + @controller.expects(:logger).returns(mock(:error => true)) + + @controller.send(:authenticate_with_open_id, "http://someone.example.com") do |result, identity_url| + assert result.missing? + assert_equal "Sorry, the OpenID server couldn't be found", result.message + end + end + + def test_authentication_should_be_invalid_when_the_identity_url_is_invalid + @controller.send(:authenticate_with_open_id, "!") do |result, identity_url| + assert result.invalid?, "Result expected to be invalid but was not" + assert_equal "Sorry, but this does not appear to be a valid OpenID", result.message + end + end + + def test_authentication_should_fail_when_the_identity_server_times_out + open_id_consumer = mock() + open_id_consumer.expects(:begin).raises(Timeout::Error, "Identity Server took too long.") + @controller.expects(:open_id_consumer).returns(open_id_consumer) + @controller.expects(:logger).returns(mock(:error => true)) + + @controller.send(:authenticate_with_open_id, "http://someone.example.com") do |result, identity_url| + assert result.missing? + assert_equal "Sorry, the OpenID server couldn't be found", result.message + end + end + + def test_authentication_should_begin_when_the_identity_server_is_present + @controller.expects(:begin_open_id_authentication) + @controller.send(:authenticate_with_open_id, "http://someone.example.com") + end +end diff --git a/vendor/plugins/open_id_authentication/test/status_test.rb b/vendor/plugins/open_id_authentication/test/status_test.rb new file mode 100644 index 000000000..b1d5e0933 --- /dev/null +++ b/vendor/plugins/open_id_authentication/test/status_test.rb @@ -0,0 +1,14 @@ +require File.dirname(__FILE__) + '/test_helper' + +class StatusTest < Test::Unit::TestCase + include OpenIdAuthentication + + def test_state_conditional + assert Result[:missing].missing? + assert Result[:missing].unsuccessful? + assert !Result[:missing].successful? + + assert Result[:successful].successful? + assert !Result[:successful].unsuccessful? + end +end \ No newline at end of file diff --git a/vendor/plugins/open_id_authentication/test/test_helper.rb b/vendor/plugins/open_id_authentication/test/test_helper.rb new file mode 100644 index 000000000..43216e1ef --- /dev/null +++ b/vendor/plugins/open_id_authentication/test/test_helper.rb @@ -0,0 +1,17 @@ +require 'test/unit' +require 'rubygems' + +gem 'activesupport' +require 'active_support' + +gem 'actionpack' +require 'action_controller' + +gem 'mocha' +require 'mocha' + +gem 'ruby-openid' +require 'openid' + +RAILS_ROOT = File.dirname(__FILE__) unless defined? RAILS_ROOT +require File.dirname(__FILE__) + "/../lib/open_id_authentication" -- 2.39.5