]> source.dussan.org Git - gitblit.git/commitdiff
Revised TimeUtils for localization
authorJames Moger <james.moger@gitblit.com>
Fri, 15 Jun 2012 20:01:30 +0000 (16:01 -0400)
committerJames Moger <james.moger@gitblit.com>
Fri, 15 Jun 2012 20:01:30 +0000 (16:01 -0400)
TimeUtils needs to output localized strings like "5 days ago" and "6 months".  In order to do this it needs a translation resource.  Additionally, that resource can not be static because the single Gitblit server can handle multiple connections in different locales/languages.

TimeUtils has changed from a collection of static methods to some static methods and some instance methods.  A TimeUtils is instantiated with an optional resource bundle which contains the preferred translation.  If the resourec bundle is null or the requested translation key does not exist, an English  default will be used.

This change required adjusting the signatures of several key methods and that cascaded out to adjusting those methods calls in many, many  classes.

28 files changed:
src/com/gitblit/client/DateCellRenderer.java
src/com/gitblit/client/StatusPanel.java
src/com/gitblit/client/Translation.java
src/com/gitblit/models/IssueModel.java
src/com/gitblit/utils/TimeUtils.java
src/com/gitblit/wicket/WicketUtils.java
src/com/gitblit/wicket/pages/BasePage.java
src/com/gitblit/wicket/pages/CommitPage.java
src/com/gitblit/wicket/pages/FederationRegistrationPage.java
src/com/gitblit/wicket/pages/LuceneSearchPage.java
src/com/gitblit/wicket/pages/MetricsPage.java
src/com/gitblit/wicket/pages/ReviewProposalPage.java
src/com/gitblit/wicket/pages/SummaryPage.java
src/com/gitblit/wicket/pages/TagPage.java
src/com/gitblit/wicket/pages/TicketPage.java
src/com/gitblit/wicket/pages/TicketsPage.java
src/com/gitblit/wicket/panels/ActivityPanel.java
src/com/gitblit/wicket/panels/BasePanel.java
src/com/gitblit/wicket/panels/BranchesPanel.java
src/com/gitblit/wicket/panels/CommitHeaderPanel.java
src/com/gitblit/wicket/panels/FederationProposalsPanel.java
src/com/gitblit/wicket/panels/FederationRegistrationsPanel.java
src/com/gitblit/wicket/panels/HistoryPanel.java
src/com/gitblit/wicket/panels/LogPanel.java
src/com/gitblit/wicket/panels/RepositoriesPanel.java
src/com/gitblit/wicket/panels/SearchPanel.java
src/com/gitblit/wicket/panels/TagsPanel.java
tests/com/gitblit/tests/TimeUtilsTest.java

index 3d0ab15beb7f0c0e569f419d6012b422775be102..954dad2a26a8678b9ca246e84232f35af5c77966 100644 (file)
@@ -37,7 +37,7 @@ public class DateCellRenderer extends DefaultTableCellRenderer {
        private static final long serialVersionUID = 1L;\r
 \r
        private final String pattern;\r
-\r
+       \r
        public DateCellRenderer(String pattern, Color foreground) {\r
                this.pattern = (pattern == null ? "yyyy-MM-dd HH:mm" : pattern);\r
                setForeground(foreground);\r
@@ -55,7 +55,7 @@ public class DateCellRenderer extends DefaultTableCellRenderer {
                                title = "--";\r
                                dateString = "never";\r
                        } else {\r
-                               title = TimeUtils.timeAgo(date);\r
+                               title = Translation.getTimeUtils().timeAgo(date);\r
                                dateString = new SimpleDateFormat(pattern).format((Date) value);\r
                        }\r
 \r
index f22d69c8a69134e7f57abbf7e6068234a4b3cb60..7506dfeac60763075bc3f8da0e87a96d3e95ea14 100644 (file)
@@ -35,7 +35,6 @@ import com.gitblit.Constants;
 import com.gitblit.Constants.RpcRequest;\r
 import com.gitblit.models.ServerStatus;\r
 import com.gitblit.utils.ByteFormat;\r
-import com.gitblit.utils.TimeUtils;\r
 \r
 /**\r
  * This panel displays the server status.\r
@@ -155,8 +154,8 @@ public class StatusPanel extends JPanel {
                ServerStatus status = gitblit.getStatus();\r
                header.setText(Translation.get("gb.status"));\r
                version.setText(Constants.NAME + (status.isGO ? " GO v" : " WAR v") + status.version);\r
-               releaseDate.setText(status.releaseDate);\r
-               bootDate.setText(status.bootDate.toString() + " (" + TimeUtils.timeAgo(status.bootDate)\r
+               releaseDate.setText(status.releaseDate);                \r
+               bootDate.setText(status.bootDate.toString() + " (" + Translation.getTimeUtils().timeAgo(status.bootDate)\r
                                + ")");\r
                url.setText(gitblit.url);\r
                servletContainer.setText(status.servletContainer);\r
index 2e7b5bb4f43527dbe2918bcd7fc351fb93c6b158..16ef20d4c1f1a83b3a9aa6d7f2ee581f3504735c 100644 (file)
@@ -18,6 +18,8 @@ package com.gitblit.client;
 import java.util.MissingResourceException;\r
 import java.util.ResourceBundle;\r
 \r
+import com.gitblit.utils.TimeUtils;\r
+\r
 /**\r
  * Loads the Gitblit language resource file.\r
  * \r
@@ -27,6 +29,8 @@ import java.util.ResourceBundle;
 public class Translation {\r
 \r
        private final static ResourceBundle translation;\r
+       \r
+       private final static TimeUtils timeUtils;\r
 \r
        static {\r
                ResourceBundle bundle;\r
@@ -38,6 +42,8 @@ public class Translation {
                        bundle = ResourceBundle.getBundle("GitBlitWebApp");\r
                }\r
                translation = bundle;\r
+               \r
+               timeUtils = new TimeUtils(translation);\r
        }\r
 \r
        public static String get(String key) {\r
@@ -46,4 +52,8 @@ public class Translation {
                }\r
                return key;\r
        }\r
+       \r
+       public static TimeUtils getTimeUtils() {\r
+               return timeUtils;\r
+       }\r
 }\r
index 3c191e241b608c53107eac050dc6c6aa7c33e2b4..c90389139d8c4fd7c9f8c0a26b829116700cef77 100644 (file)
@@ -297,8 +297,8 @@ public class IssueModel implements Serializable, Comparable<IssueModel> {
 \r
                @Override\r
                public String toString() {\r
-                       StringBuilder sb = new StringBuilder();\r
-                       sb.append(TimeUtils.timeAgo(created));\r
+                       StringBuilder sb = new StringBuilder();                 \r
+                       sb.append(new TimeUtils().timeAgo(created));\r
                        switch (code) {\r
                        case '+':\r
                                sb.append(" created by ");\r
index 662025be79a1c479be0a06a732ca35f6aec31ba8..7f695625a41a410e81c92f3442100eac02ba38dd 100644 (file)
  */\r
 package com.gitblit.utils;\r
 \r
+import java.text.MessageFormat;\r
 import java.text.SimpleDateFormat;\r
 import java.util.Calendar;\r
 import java.util.Date;\r
+import java.util.ResourceBundle;\r
 \r
 /**\r
  * Utility class of time functions.\r
@@ -35,6 +37,16 @@ public class TimeUtils {
        public static final long ONEDAY = ONEHOUR * 24L;\r
 \r
        public static final long ONEYEAR = ONEDAY * 365L;\r
+       \r
+       private final ResourceBundle translation;\r
+       \r
+       public TimeUtils() {\r
+               this(null);\r
+       }\r
+       \r
+       public TimeUtils(ResourceBundle translation) {\r
+               this.translation = translation;\r
+       }\r
 \r
        /**\r
         * Returns true if date is today.\r
@@ -67,21 +79,21 @@ public class TimeUtils {
         * @param days\r
         * @return duration as string in days, months, and/or years\r
         */\r
-       public static String duration(int days) {\r
+       public String duration(int days) {\r
                if (days <= 60) {\r
-                       return days + (days > 1 ? " days" : " day");\r
+                       return (days > 1 ? translate(days, "gb.duration.days", "{0} days") : translate("gb.duration.oneDay", "1 day"));\r
                } else if (days < 365) {\r
                        int rem = days % 30;\r
-                       return ((days / 30) + (rem >= 15 ? 1 : 0)) + " months";\r
+                       return translate(((days / 30) + (rem >= 15 ? 1 : 0)), "gb.duration.months", "{0} months");\r
                } else {\r
                        int years = days / 365;\r
                        int rem = days % 365;\r
-                       String yearsString = years + (years > 1 ? " years" : " year");\r
+                       String yearsString = (years > 1 ? translate(years, "gb.duration.years", "{0} years") : translate("gb.duration.oneYear", "1 year"));\r
                        if (rem < 30) {\r
                                if (rem == 0) {\r
                                        return yearsString;\r
                                } else {\r
-                                       return yearsString + (rem >= 15 ? ", 1 month" : "");\r
+                                       return yearsString + (rem >= 15 ? (", " + translate("gb.duration.oneMonth", "1 month")): "");\r
                                }\r
                        } else {\r
                                int months = rem / 30;\r
@@ -89,8 +101,8 @@ public class TimeUtils {
                                if (remDays >= 15) {\r
                                        months++;\r
                                }\r
-                               String monthsString = yearsString + ", " + months\r
-                                               + (months > 1 ? " months" : " month");\r
+                               String monthsString = yearsString + ", "\r
+                                               + (months > 1 ? translate(months, "gb.duration.months", "{0} months") : translate("gb.duration.oneMonth", "1 month"));\r
                                return monthsString;\r
                        }\r
                }\r
@@ -155,6 +167,14 @@ public class TimeUtils {
                return days;\r
        }\r
 \r
+       public String today() {\r
+               return translate("gb.time.today", "today");\r
+       }\r
+\r
+       public String yesterday() {\r
+               return translate("gb.time.yesterday", "yesterday");\r
+       }\r
+\r
        /**\r
         * Returns the string representation of the duration between now and the\r
         * date.\r
@@ -162,7 +182,7 @@ public class TimeUtils {
         * @param date\r
         * @return duration as a string\r
         */\r
-       public static String timeAgo(Date date) {\r
+       public String timeAgo(Date date) {\r
                return timeAgo(date, false);\r
        }\r
 \r
@@ -172,7 +192,7 @@ public class TimeUtils {
         * @param date\r
         * @return the css class\r
         */\r
-       public static String timeAgoCss(Date date) {\r
+       public String timeAgoCss(Date date) {\r
                return timeAgo(date, true);\r
        }\r
 \r
@@ -184,7 +204,7 @@ public class TimeUtils {
         * @param css\r
         * @return the string representation of the duration OR the css class\r
         */\r
-       private static String timeAgo(Date date, boolean css) {\r
+       private String timeAgo(Date date, boolean css) {\r
                if (isToday(date) || isYesterday(date)) {\r
                        int mins = minutesAgo(date, true);\r
                        if (mins >= 120) {\r
@@ -193,15 +213,18 @@ public class TimeUtils {
                                }\r
                                int hours = hoursAgo(date, true);\r
                                if (hours > 23) {\r
-                                       return "yesterday";\r
+                                       return yesterday();\r
                                } else {\r
-                                       return hours + " hours ago";\r
+                                       return translate(hours, "gb.time.hoursAgo", "{0} hours ago");\r
                                }\r
                        }\r
                        if (css) {\r
                                return "age0";\r
                        }\r
-                       return mins + " min" + (mins > 1 ? "s" : "") + " ago";\r
+                       if (mins > 2) {\r
+                               return translate(mins, "gb.time.minsAgo", "{0} mins ago");\r
+                       }\r
+                       return translate("gb.time.justNow", "just now");\r
                } else {\r
                        int days = daysAgo(date);\r
                        if (css) {\r
@@ -215,13 +238,13 @@ public class TimeUtils {
                        }\r
                        if (days < 365) {\r
                                if (days <= 30) {\r
-                                       return days + " days ago";\r
+                                       return translate(days, "gb.time.daysAgo", "{0} days ago");\r
                                } else if (days <= 90) {\r
                                        int weeks = days / 7;\r
                                        if (weeks == 12) {\r
-                                               return "3 months ago";\r
+                                               return translate(3, "gb.time.monthsAgo", "{0} months ago");\r
                                        } else {\r
-                                               return weeks + " weeks ago";\r
+                                               return translate(weeks, "gb.time.weeksAgo", "{0} weeks ago");\r
                                        }\r
                                }\r
                                int months = days / 30;\r
@@ -229,21 +252,43 @@ public class TimeUtils {
                                if (weeks >= 2) {\r
                                        months++;\r
                                }\r
-                               return months + " months ago";\r
+                               return translate(months, "gb.time.monthsAgo", "{0} months ago");\r
                        } else if (days == 365) {\r
-                               return "1 year ago";\r
+                               return translate("gb.time.oneYearAgo", "1 year ago");\r
                        } else {\r
                                int yr = days / 365;\r
                                days = days % 365;\r
                                int months = (yr * 12) + (days / 30);\r
                                if (months > 23) {\r
-                                       return yr + " years ago";\r
+                                       return translate(yr, "gb.time.yearsAgo", "{0} years ago");\r
                                } else {\r
-                                       return months + " months ago";\r
+                                       return translate(months, "gb.time.monthsAgo", "{0} months ago");\r
                                }\r
                        }\r
                }\r
        }\r
+       \r
+       private String translate(String key, String defaultValue) {\r
+               String value = defaultValue;\r
+               if (translation != null && translation.containsKey(key)) {\r
+                       String aValue = translation.getString(key);\r
+                       if (!StringUtils.isEmpty(aValue)) {\r
+                               value = aValue;\r
+                       }\r
+               }\r
+               return value;\r
+       }\r
+       \r
+       private String translate(int val, String key, String defaultPattern) {\r
+               String pattern = defaultPattern;\r
+               if (translation != null && translation.containsKey(key)) {\r
+                       String aValue = translation.getString(key);\r
+                       if (!StringUtils.isEmpty(aValue)) {\r
+                               pattern = aValue;\r
+                       }\r
+               }\r
+               return MessageFormat.format(pattern, val);\r
+       }\r
 \r
        /**\r
         * Convert a frequency string into minutes.\r
index 864ebe6aa0f30b5b2a3b2bb5b037c8503cfe5e64..34a14a13e74e0ed0033ec055aa6a980a305076e3 100644 (file)
@@ -418,7 +418,7 @@ public class WicketUtils {
                return params.getString("n", "");\r
        }\r
 \r
-       public static Label createDateLabel(String wicketId, Date date, TimeZone timeZone) {\r
+       public static Label createDateLabel(String wicketId, Date date, TimeZone timeZone, TimeUtils timeUtils) {\r
                String format = GitBlit.getString(Keys.web.datestampShortFormat, "MM/dd/yy");\r
                DateFormat df = new SimpleDateFormat(format);\r
                if (timeZone == null) {\r
@@ -434,7 +434,7 @@ public class WicketUtils {
                String title = null;\r
                if (date.getTime() <= System.currentTimeMillis()) {\r
                        // past\r
-                       title = TimeUtils.timeAgo(date);\r
+                       title = timeUtils.timeAgo(date);\r
                }\r
                if ((System.currentTimeMillis() - date.getTime()) < 10 * 24 * 60 * 60 * 1000L) {\r
                        String tmp = dateString;\r
@@ -442,14 +442,14 @@ public class WicketUtils {
                        title = tmp;\r
                }\r
                Label label = new Label(wicketId, dateString);\r
-               WicketUtils.setCssClass(label, TimeUtils.timeAgoCss(date));\r
+               WicketUtils.setCssClass(label, timeUtils.timeAgoCss(date));\r
                if (!StringUtils.isEmpty(title)) {\r
                        WicketUtils.setHtmlTooltip(label, title);\r
                }\r
                return label;\r
        }\r
 \r
-       public static Label createTimeLabel(String wicketId, Date date, TimeZone timeZone) {\r
+       public static Label createTimeLabel(String wicketId, Date date, TimeZone timeZone, TimeUtils timeUtils) {\r
                String format = GitBlit.getString(Keys.web.timeFormat, "HH:mm");\r
                DateFormat df = new SimpleDateFormat(format);\r
                if (timeZone == null) {\r
@@ -462,7 +462,7 @@ public class WicketUtils {
                } else {\r
                        timeString = df.format(date);\r
                }\r
-               String title = TimeUtils.timeAgo(date);\r
+               String title = timeUtils.timeAgo(date);\r
                Label label = new Label(wicketId, timeString);\r
                if (!StringUtils.isEmpty(title)) {\r
                        WicketUtils.setHtmlTooltip(label, title);\r
@@ -470,7 +470,7 @@ public class WicketUtils {
                return label;\r
        }\r
 \r
-       public static Label createDatestampLabel(String wicketId, Date date, TimeZone timeZone) {\r
+       public static Label createDatestampLabel(String wicketId, Date date, TimeZone timeZone, TimeUtils timeUtils) {\r
                String format = GitBlit.getString(Keys.web.datestampLongFormat, "EEEE, MMMM d, yyyy");\r
                DateFormat df = new SimpleDateFormat(format);\r
                if (timeZone == null) {\r
@@ -485,12 +485,12 @@ public class WicketUtils {
                }\r
                String title = null;\r
                if (TimeUtils.isToday(date)) {\r
-                       title = "today";\r
+                       title = timeUtils.today();\r
                } else if (TimeUtils.isYesterday(date)) {\r
-                               title = "yesterday";\r
+                               title = timeUtils.yesterday();\r
                } else if (date.getTime() <= System.currentTimeMillis()) {\r
                        // past\r
-                       title = TimeUtils.timeAgo(date);\r
+                       title = timeUtils.timeAgo(date);\r
                }\r
                if ((System.currentTimeMillis() - date.getTime()) < 10 * 24 * 60 * 60 * 1000L) {\r
                        String tmp = dateString;\r
@@ -504,7 +504,7 @@ public class WicketUtils {
                return label;\r
        }\r
 \r
-       public static Label createTimestampLabel(String wicketId, Date date, TimeZone timeZone) {\r
+       public static Label createTimestampLabel(String wicketId, Date date, TimeZone timeZone, TimeUtils timeUtils) {\r
                String format = GitBlit.getString(Keys.web.datetimestampLongFormat,\r
                                "EEEE, MMMM d, yyyy HH:mm Z");\r
                DateFormat df = new SimpleDateFormat(format);\r
@@ -521,7 +521,7 @@ public class WicketUtils {
                String title = null;\r
                if (date.getTime() <= System.currentTimeMillis()) {\r
                        // past\r
-                       title = TimeUtils.timeAgo(date);\r
+                       title = timeUtils.timeAgo(date);\r
                }\r
                Label label = new Label(wicketId, dateString);\r
                if (!StringUtils.isEmpty(title)) {\r
index 31da3a64c4c0a60a4afdad31c34c89638a182c21..aadab876a4c9f5f8351797504fd4f76895502575 100644 (file)
@@ -17,6 +17,7 @@ package com.gitblit.wicket.pages;
 \r
 import java.util.LinkedHashMap;\r
 import java.util.Map;\r
+import java.util.ResourceBundle;\r
 import java.util.TimeZone;\r
 \r
 import javax.servlet.http.Cookie;\r
@@ -47,6 +48,7 @@ import com.gitblit.GitBlit;
 import com.gitblit.Keys;\r
 import com.gitblit.models.RepositoryModel;\r
 import com.gitblit.models.UserModel;\r
+import com.gitblit.utils.TimeUtils;\r
 import com.gitblit.wicket.GitBlitWebSession;\r
 import com.gitblit.wicket.WicketUtils;\r
 import com.gitblit.wicket.panels.LinkPanel;\r
@@ -54,6 +56,8 @@ import com.gitblit.wicket.panels.LinkPanel;
 public abstract class BasePage extends WebPage {\r
 \r
        private final Logger logger;\r
+       \r
+       private transient TimeUtils timeUtils;\r
 \r
        public BasePage() {\r
                super();\r
@@ -75,6 +79,23 @@ public abstract class BasePage extends WebPage {
                }\r
        }\r
        \r
+       protected String getLanguageCode() {\r
+               return GitBlitWebSession.get().getLocale().getLanguage();\r
+       }\r
+       \r
+       protected TimeUtils getTimeUtils() {\r
+               if (timeUtils == null) {\r
+                       ResourceBundle bundle;          \r
+                       try {\r
+                               bundle = ResourceBundle.getBundle("com.gitblit.wicket.GitBlitWebApp", GitBlitWebSession.get().getLocale());\r
+                       } catch (Throwable t) {\r
+                               bundle = ResourceBundle.getBundle("com.gitblit.wicket.GitBlitWebApp");\r
+                       }\r
+                       timeUtils = new TimeUtils(bundle);\r
+               }\r
+               return timeUtils;\r
+       }\r
+       \r
        @Override\r
        protected void onBeforeRender() {\r
                if (GitBlit.isDebugMode()) {\r
index 0e250b8b8f2351e45ca585ee6cac9af1a7e90c3b..f3b32652b86fcd7a0056216c5d5b9b2b4c3a72be 100644 (file)
@@ -81,12 +81,12 @@ public class CommitPage extends RepositoryPage {
                // author\r
                add(createPersonPanel("commitAuthor", c.getAuthorIdent(), Constants.SearchType.AUTHOR));\r
                add(WicketUtils.createTimestampLabel("commitAuthorDate", c.getAuthorIdent().getWhen(),\r
-                               getTimeZone()));\r
+                               getTimeZone(), getTimeUtils()));\r
                \r
                // committer\r
                add(createPersonPanel("commitCommitter", c.getCommitterIdent(), Constants.SearchType.COMMITTER));\r
                add(WicketUtils.createTimestampLabel("commitCommitterDate",\r
-                               c.getCommitterIdent().getWhen(), getTimeZone()));\r
+                               c.getCommitterIdent().getWhen(), getTimeZone(), getTimeUtils()));\r
 \r
                add(new Label("commitId", c.getName()));\r
 \r
@@ -129,7 +129,7 @@ public class CommitPage extends RepositoryPage {
                                                Constants.SearchType.AUTHOR));\r
                                item.add(new GravatarImage("noteAuthorAvatar", entry.notesRef.getAuthorIdent()));\r
                                item.add(WicketUtils.createTimestampLabel("authorDate", entry.notesRef\r
-                                               .getAuthorIdent().getWhen(), getTimeZone()));\r
+                                               .getAuthorIdent().getWhen(), getTimeZone(), getTimeUtils()));\r
                                item.add(new Label("noteContent", GitBlit.self().processCommitMessage(\r
                                                repositoryName, entry.content)).setEscapeModelStrings(false));\r
                        }\r
index 751dac8f19e6691fd712491e3e00ba09fc5e7d1a..19c30a5ef24a118695c1fec695c35ae168cece1d 100644 (file)
@@ -52,8 +52,8 @@ public class FederationRegistrationPage extends RootSubPage {
                add(new Label("frequency", registration.frequency));\r
                add(new Label("folder", registration.folder));\r
                add(new Label("token", showAdmin ? registration.token : "--"));\r
-               add(WicketUtils.createTimestampLabel("lastPull", registration.lastPull, getTimeZone()));\r
-               add(WicketUtils.createTimestampLabel("nextPull", registration.nextPull, getTimeZone()));\r
+               add(WicketUtils.createTimestampLabel("lastPull", registration.lastPull, getTimeZone(), getTimeUtils()));\r
+               add(WicketUtils.createTimestampLabel("nextPull", registration.nextPull, getTimeZone(), getTimeUtils()));\r
 \r
                StringBuilder inclusions = new StringBuilder();\r
                for (String inc : registration.inclusions) {\r
index 2894add427b5b04a1cdd628ac0bc8f30a336a8b7..54e27ce54b3ec435347fd944a89e7ca0cc1b158b 100644 (file)
@@ -234,7 +234,7 @@ public class LuceneSearchPage extends RootPage {
                                        item.add(new LinkPanel("branch", "branch", StringUtils.getRelativePath(Constants.R_HEADS, sr.branch), LogPage.class, WicketUtils.newObjectParameter(sr.repository, sr.branch)));\r
                                }\r
                                item.add(new Label("author", sr.author));\r
-                               item.add(WicketUtils.createDatestampLabel("date", sr.date, getTimeZone()));\r
+                               item.add(WicketUtils.createDatestampLabel("date", sr.date, getTimeZone(), getTimeUtils()));\r
                        }\r
                };\r
                add(resultsView.setVisible(results.size() > 0));\r
index f6df7c51e874aebd3fc4dbd4385ac9616971a595..5904a64aa1e3f688758eca5ac8fc530989d817dd 100644 (file)
@@ -41,7 +41,6 @@ import org.wicketstuff.googlecharts.ShapeMarker;
 import com.gitblit.models.Metric;\r
 import com.gitblit.utils.MetricUtils;\r
 import com.gitblit.utils.StringUtils;\r
-import com.gitblit.utils.TimeUtils;\r
 import com.gitblit.wicket.WicketUtils;\r
 \r
 public class MetricsPage extends RepositoryPage {\r
@@ -62,7 +61,7 @@ public class MetricsPage extends RepositoryPage {
                } else {\r
                        add(new Label("branchStats",\r
                                        MessageFormat.format(getString("gb.branchStats"), metricsTotal.count,\r
-                                                       metricsTotal.tag, TimeUtils.duration(metricsTotal.duration))));\r
+                                                       metricsTotal.tag, getTimeUtils().duration(metricsTotal.duration))));\r
                }\r
                insertLinePlot("commitsChart", metrics);\r
                insertBarPlot("dayOfWeekChart", getDayOfWeekMetrics(r, objectId));\r
index 25ceb65dc37234e98716dffb830dec4d51566c52..df7b1bc11bc6aa0176b7a18e991d11e258e03177 100644 (file)
@@ -54,7 +54,7 @@ public class ReviewProposalPage extends RootSubPage {
 \r
                add(new Label("url", proposal.url));\r
                add(new Label("message", proposal.message));\r
-               add(WicketUtils.createTimestampLabel("received", proposal.received, getTimeZone()));\r
+               add(WicketUtils.createTimestampLabel("received", proposal.received, getTimeZone(), getTimeUtils()));\r
                add(new Label("token", proposal.token));\r
                add(new Label("tokenType", proposal.tokenType.name()));\r
                \r
index ef2ee550b4c4aa87149bc83f2f93467287097b90..cb507d2371632fc5f7d74887a475d7376efba4ce 100644 (file)
@@ -49,7 +49,6 @@ import com.gitblit.utils.ArrayUtils;
 import com.gitblit.utils.JGitUtils;\r
 import com.gitblit.utils.MarkdownUtils;\r
 import com.gitblit.utils.StringUtils;\r
-import com.gitblit.utils.TimeUtils;\r
 import com.gitblit.wicket.WicketUtils;\r
 import com.gitblit.wicket.panels.BranchesPanel;\r
 import com.gitblit.wicket.panels.LogPanel;\r
@@ -84,13 +83,13 @@ public class SummaryPage extends RepositoryPage {
                add(new Label("repositoryOwner", getRepositoryModel().owner));\r
 \r
                add(WicketUtils.createTimestampLabel("repositoryLastChange",\r
-                               JGitUtils.getLastChange(r), getTimeZone()));\r
+                               JGitUtils.getLastChange(r), getTimeZone(), getTimeUtils()));\r
                if (metricsTotal == null) {\r
                        add(new Label("branchStats", ""));\r
                } else {\r
                        add(new Label("branchStats",\r
                                        MessageFormat.format(getString("gb.branchStats"), metricsTotal.count,\r
-                                                       metricsTotal.tag, TimeUtils.duration(metricsTotal.duration))));\r
+                                                       metricsTotal.tag, getTimeUtils().duration(metricsTotal.duration))));\r
                }\r
                add(new BookmarkablePageLink<Void>("metrics", MetricsPage.class,\r
                                WicketUtils.newRepositoryParameter(repositoryName)));\r
index b7a53747b2083c51cfa722c23b891c1ded32e7b2..91c913d2a7a2f5618616ae2e4926d5c968fc9fc6 100644 (file)
@@ -87,7 +87,7 @@ public class TagPage extends RepositoryPage {
                if (tagRef.getAuthorIdent() != null) {\r
                        when = tagRef.getAuthorIdent().getWhen();\r
                }\r
-               add(WicketUtils.createTimestampLabel("tagDate", when, getTimeZone()));\r
+               add(WicketUtils.createTimestampLabel("tagDate", when, getTimeZone(), getTimeUtils()));\r
 \r
                addFullText("fullMessage", tagRef.getFullMessage(), true);\r
        }\r
index 48db1cea2cfb1aeacc49d83dd95c607c0c8c7fa8..572338670a122a821a44be99b3b7206136618fc8 100644 (file)
@@ -42,7 +42,7 @@ public class TicketPage extends RepositoryPage {
                add(new Label("ticketTitle", t.title));\r
                add(new Label("ticketId", t.id));\r
                add(new Label("ticketHandler", t.handler.toLowerCase()));\r
-               add(WicketUtils.createTimestampLabel("ticketOpenDate", t.date, getTimeZone()));\r
+               add(WicketUtils.createTimestampLabel("ticketOpenDate", t.date, getTimeZone(), getTimeUtils()));\r
                Label stateLabel = new Label("ticketState", t.state);\r
                WicketUtils.setTicketCssClass(stateLabel, t.state);\r
                add(stateLabel);\r
@@ -56,7 +56,7 @@ public class TicketPage extends RepositoryPage {
                        public void populateItem(final Item<Comment> item) {\r
                                final Comment entry = item.getModelObject();\r
                                item.add(WicketUtils.createDateLabel("commentDate", entry.date, GitBlitWebSession\r
-                                               .get().getTimezone()));\r
+                                               .get().getTimezone(), getTimeUtils()));\r
                                item.add(new Label("commentAuthor", entry.author.toLowerCase()));\r
                                item.add(new Label("commentText", prepareComment(entry.text))\r
                                                .setEscapeModelStrings(false));\r
index 0ac8114b6b2fb237670ac1ac215b6c2a9a548854..b68b7e42484c37b4f97725bc9b2e08ca0e11eafa 100644 (file)
@@ -52,7 +52,7 @@ public class TicketsPage extends RepositoryPage {
                                WicketUtils.setTicketCssClass(stateLabel, entry.state);\r
                                item.add(stateLabel);\r
                                item.add(WicketUtils.createDateLabel("ticketDate", entry.date, GitBlitWebSession\r
-                                               .get().getTimezone()));\r
+                                               .get().getTimezone(), getTimeUtils()));\r
                                item.add(new Label("ticketHandler", StringUtils.trimString(\r
                                                entry.handler.toLowerCase(), 30)));\r
                                item.add(new LinkPanel("ticketTitle", "list subject", StringUtils.trimString(\r
index f75cf7d517acc729e1136fbc2f27c2e6159308b8..e86a68902dec2e1f054a488276d1029e5f85d0f6 100644 (file)
@@ -56,7 +56,7 @@ public class ActivityPanel extends BasePanel {
 \r
                        public void populateItem(final Item<Activity> activityItem) {\r
                                final Activity entry = activityItem.getModelObject();\r
-                               activityItem.add(WicketUtils.createDatestampLabel("title", entry.startDate, getTimeZone()));\r
+                               activityItem.add(WicketUtils.createDatestampLabel("title", entry.startDate, getTimeZone(), getTimeUtils()));\r
 \r
                                // display the commits in chronological order\r
                                DataView<RepositoryCommit> commits = new DataView<RepositoryCommit>("commit",\r
@@ -68,7 +68,7 @@ public class ActivityPanel extends BasePanel {
 \r
                                                // commit time of day\r
                                                commitItem.add(WicketUtils.createTimeLabel("time", commit.getCommitterIdent()\r
-                                                               .getWhen(), getTimeZone()));\r
+                                                               .getWhen(), getTimeZone(), getTimeUtils()));\r
 \r
                                                // avatar\r
                                                commitItem.add(new GravatarImage("avatar", commit.getAuthorIdent(), 36));\r
index 3606dd041b845039e81047cd3b23221dd6a85cd3..ec879178fe6a292dc121ac9f00c4e491bc417b4f 100644 (file)
@@ -15,6 +15,7 @@
  */\r
 package com.gitblit.wicket.panels;\r
 \r
+import java.util.ResourceBundle;\r
 import java.util.TimeZone;\r
 \r
 import org.apache.wicket.AttributeModifier;\r
@@ -25,12 +26,15 @@ import org.apache.wicket.model.Model;
 import com.gitblit.Constants;\r
 import com.gitblit.GitBlit;\r
 import com.gitblit.Keys;\r
+import com.gitblit.utils.TimeUtils;\r
 import com.gitblit.wicket.GitBlitWebSession;\r
 import com.gitblit.wicket.WicketUtils;\r
 \r
 public abstract class BasePanel extends Panel {\r
 \r
        private static final long serialVersionUID = 1L;\r
+       \r
+       private transient TimeUtils timeUtils;\r
 \r
        public BasePanel(String wicketId) {\r
                super(wicketId);\r
@@ -40,6 +44,19 @@ public abstract class BasePanel extends Panel {
                return GitBlit.getBoolean(Keys.web.useClientTimezone, false) ? GitBlitWebSession.get()\r
                                .getTimezone() : GitBlit.getTimezone();\r
        }\r
+       \r
+       protected TimeUtils getTimeUtils() {\r
+               if (timeUtils == null) {\r
+                       ResourceBundle bundle;          \r
+                       try {\r
+                               bundle = ResourceBundle.getBundle("com.gitblit.wicket.GitBlitWebApp", GitBlitWebSession.get().getLocale());\r
+                       } catch (Throwable t) {\r
+                               bundle = ResourceBundle.getBundle("com.gitblit.wicket.GitBlitWebApp");\r
+                       }\r
+                       timeUtils = new TimeUtils(bundle);\r
+               }\r
+               return timeUtils;\r
+       }\r
 \r
        protected void setPersonSearchTooltip(Component component, String value, Constants.SearchType searchType) {\r
                if (searchType.equals(Constants.SearchType.AUTHOR)) {\r
index 5f1b0588224544d3ec975a212ff20d0d4fe99225..8bbab9a0884ca2c7c7f2b5e79c8be4fdfdf8870d 100644 (file)
@@ -83,7 +83,7 @@ public class BranchesPanel extends BasePanel {
                        public void populateItem(final Item<RefModel> item) {\r
                                final RefModel entry = item.getModelObject();\r
 \r
-                               item.add(WicketUtils.createDateLabel("branchDate", entry.getDate(), getTimeZone()));\r
+                               item.add(WicketUtils.createDateLabel("branchDate", entry.getDate(), getTimeZone(), getTimeUtils()));\r
 \r
                                item.add(new LinkPanel("branchName", "list name", StringUtils.trimString(\r
                                                entry.displayName, 28), LogPage.class, WicketUtils.newObjectParameter(\r
index f411397ef88ee2ce054317bfd41bf013d90877ff..bb960cca2ddb70b9f530669993d6e463f7f895e5 100644 (file)
@@ -42,7 +42,7 @@ public class CommitHeaderPanel extends BasePanel {
                                WicketUtils.newObjectParameter(repositoryName, c.getName())));\r
                add(new Label("commitid", c.getName()));\r
                add(new Label("author", c.getAuthorIdent().getName()));\r
-               add(WicketUtils.createDateLabel("date", c.getAuthorIdent().getWhen(), getTimeZone()));\r
+               add(WicketUtils.createDateLabel("date", c.getAuthorIdent().getWhen(), getTimeZone(), getTimeUtils()));\r
                add(new GravatarImage("authorAvatar", c.getAuthorIdent()));\r
        }\r
 }
\ No newline at end of file
index 11f3f5c9580b197949137d8b7caa2e2405c41ba0..3e70ccec9fb9ff593f3e684aef67d804832fd5b0 100644 (file)
@@ -56,7 +56,7 @@ public class FederationProposalsPanel extends BasePanel {
                                final FederationProposal entry = item.getModelObject();\r
                                item.add(new LinkPanel("url", "list", entry.url, ReviewProposalPage.class,\r
                                                WicketUtils.newTokenParameter(entry.token)));\r
-                               item.add(WicketUtils.createDateLabel("received", entry.received, getTimeZone()));\r
+                               item.add(WicketUtils.createDateLabel("received", entry.received, getTimeZone(), getTimeUtils()));\r
                                item.add(new Label("tokenType", entry.tokenType.name()));\r
                                item.add(new LinkPanel("token", "list", entry.token, ReviewProposalPage.class,\r
                                                WicketUtils.newTokenParameter(entry.token)));\r
index a2bfd8cf02fb76a2aa701c69bf1757d6b35701ab..ff947175d677037a7f378a859e6c4d593465653e 100644 (file)
@@ -66,9 +66,9 @@ public class FederationRegistrationsPanel extends BasePanel {
 \r
                                item.add(WicketUtils.getRegistrationImage("typeIcon", entry, this));\r
 \r
-                               item.add(WicketUtils.createDateLabel("lastPull", entry.lastPull, getTimeZone()));\r
+                               item.add(WicketUtils.createDateLabel("lastPull", entry.lastPull, getTimeZone(), getTimeUtils()));\r
                                item.add(WicketUtils\r
-                                               .createTimestampLabel("nextPull", entry.nextPull, getTimeZone()));\r
+                                               .createTimestampLabel("nextPull", entry.nextPull, getTimeZone(), getTimeUtils()));\r
                                item.add(new Label("frequency", entry.frequency));\r
                                WicketUtils.setAlternatingBackground(item, counter);\r
                                counter++;\r
index 15a4aa276acc8a7986d64f38864c860e2f5aa163..befd7011063c257db0ffdf8fc45312b9e031e2ae 100644 (file)
@@ -103,7 +103,7 @@ public class HistoryPanel extends BasePanel {
                                final RevCommit entry = item.getModelObject();\r
                                final Date date = JGitUtils.getCommitDate(entry);\r
 \r
-                               item.add(WicketUtils.createDateLabel("commitDate", date, getTimeZone()));\r
+                               item.add(WicketUtils.createDateLabel("commitDate", date, getTimeZone(), getTimeUtils()));\r
 \r
                                // author search link\r
                                String author = entry.getAuthorIdent().getName();\r
index 5ced2f6f5cdd5cfd76a7cbde67220cd3b0fc57af..f441ba57aaf611448dc2532e4db3f44c27748677 100644 (file)
@@ -91,7 +91,7 @@ public class LogPanel extends BasePanel {
                                final RevCommit entry = item.getModelObject();\r
                                final Date date = JGitUtils.getCommitDate(entry);\r
 \r
-                               item.add(WicketUtils.createDateLabel("commitDate", date, getTimeZone()));\r
+                               item.add(WicketUtils.createDateLabel("commitDate", date, getTimeZone(), getTimeUtils()));\r
 \r
                                // author search link\r
                                String author = entry.getAuthorIdent().getName();\r
index 3b42972026c407156fa39d5866feb43070d42c5b..9664e05b33037413a6307f3f24ee438f2b09712c 100644 (file)
@@ -49,7 +49,6 @@ import com.gitblit.SyndicationServlet;
 import com.gitblit.models.RepositoryModel;\r
 import com.gitblit.models.UserModel;\r
 import com.gitblit.utils.StringUtils;\r
-import com.gitblit.utils.TimeUtils;\r
 import com.gitblit.wicket.GitBlitWebSession;\r
 import com.gitblit.wicket.WicketUtils;\r
 import com.gitblit.wicket.pages.BasePage;\r
@@ -242,11 +241,11 @@ public class RepositoriesPanel extends BasePanel {
                                if (entry.lastChange.getTime() == 0) {\r
                                        lastChange = "--";\r
                                } else {\r
-                                       lastChange = TimeUtils.timeAgo(entry.lastChange);\r
+                                       lastChange = getTimeUtils().timeAgo(entry.lastChange);\r
                                }\r
                                Label lastChangeLabel = new Label("repositoryLastChange", lastChange);\r
                                row.add(lastChangeLabel);\r
-                               WicketUtils.setCssClass(lastChangeLabel, TimeUtils.timeAgoCss(entry.lastChange));\r
+                               WicketUtils.setCssClass(lastChangeLabel, getTimeUtils().timeAgoCss(entry.lastChange));\r
 \r
                                boolean showOwner = user != null && user.username.equalsIgnoreCase(entry.owner);\r
                                if (showAdmin) {\r
index 4d195c52d0e663aa17ffd9f15482410481fb87f1..eab3aea1edcaf8834ef60b512192370e256c7c4b 100644 (file)
@@ -87,7 +87,7 @@ public class SearchPanel extends BasePanel {
                                final RevCommit entry = item.getModelObject();\r
                                final Date date = JGitUtils.getCommitDate(entry);\r
 \r
-                               item.add(WicketUtils.createDateLabel("commitDate", date, getTimeZone()));\r
+                               item.add(WicketUtils.createDateLabel("commitDate", date, getTimeZone(), getTimeUtils()));\r
 \r
                                // author search link\r
                                String author = entry.getAuthorIdent().getName();\r
index a06c1c2e8bacf9a8e4d048759cddfb991eaeb07f..2bee6a60149b3637b2d41659c29ea3c397619c89 100644 (file)
@@ -69,7 +69,7 @@ public class TagsPanel extends BasePanel {
                        public void populateItem(final Item<RefModel> item) {\r
                                RefModel entry = item.getModelObject();\r
 \r
-                               item.add(WicketUtils.createDateLabel("tagDate", entry.getDate(), getTimeZone()));\r
+                               item.add(WicketUtils.createDateLabel("tagDate", entry.getDate(), getTimeZone(), getTimeUtils()));\r
 \r
                                Class<? extends RepositoryPage> linkClass;\r
                                switch (entry.getReferencedObjectType()) {\r
index 9d94df89c282f1ffec6b6c6e9d6ae2722f09bddf..f9d5d8342befcd1a59ed4be637dbc32e0cd72c3f 100644 (file)
@@ -53,50 +53,52 @@ public class TimeUtilsTest {
 \r
        @Test\r
        public void testDurations() throws Exception {\r
-               assertEquals("1 day", TimeUtils.duration(1));\r
-               assertEquals("5 days", TimeUtils.duration(5));\r
-               assertEquals("3 months", TimeUtils.duration(75));\r
-               assertEquals("12 months", TimeUtils.duration(364));\r
-               assertEquals("1 year", TimeUtils.duration(365 + 0));\r
-               assertEquals("1 year", TimeUtils.duration(365 + 10));\r
-               assertEquals("1 year, 1 month", TimeUtils.duration(365 + 15));\r
-               assertEquals("1 year, 1 month", TimeUtils.duration(365 + 30));\r
-               assertEquals("1 year, 1 month", TimeUtils.duration(365 + 44));\r
-               assertEquals("1 year, 2 months", TimeUtils.duration(365 + 45));\r
-               assertEquals("1 year, 2 months", TimeUtils.duration(365 + 60));\r
-\r
-               assertEquals("2 years", TimeUtils.duration(2 * 365 + 0));\r
-               assertEquals("2 years", TimeUtils.duration(2 * 365 + 10));\r
-               assertEquals("2 years, 1 month", TimeUtils.duration(2 * 365 + 15));\r
-               assertEquals("2 years, 1 month", TimeUtils.duration(2 * 365 + 30));\r
-               assertEquals("2 years, 1 month", TimeUtils.duration(2 * 365 + 44));\r
-               assertEquals("2 years, 2 months", TimeUtils.duration(2 * 365 + 45));\r
-               assertEquals("2 years, 2 months", TimeUtils.duration(2 * 365 + 60));\r
+               TimeUtils timeUtils = new TimeUtils();\r
+               assertEquals("1 day", timeUtils.duration(1));\r
+               assertEquals("5 days", timeUtils.duration(5));\r
+               assertEquals("3 months", timeUtils.duration(75));\r
+               assertEquals("12 months", timeUtils.duration(364));\r
+               assertEquals("1 year", timeUtils.duration(365 + 0));\r
+               assertEquals("1 year", timeUtils.duration(365 + 10));\r
+               assertEquals("1 year, 1 month", timeUtils.duration(365 + 15));\r
+               assertEquals("1 year, 1 month", timeUtils.duration(365 + 30));\r
+               assertEquals("1 year, 1 month", timeUtils.duration(365 + 44));\r
+               assertEquals("1 year, 2 months", timeUtils.duration(365 + 45));\r
+               assertEquals("1 year, 2 months", timeUtils.duration(365 + 60));\r
+\r
+               assertEquals("2 years", timeUtils.duration(2 * 365 + 0));\r
+               assertEquals("2 years", timeUtils.duration(2 * 365 + 10));\r
+               assertEquals("2 years, 1 month", timeUtils.duration(2 * 365 + 15));\r
+               assertEquals("2 years, 1 month", timeUtils.duration(2 * 365 + 30));\r
+               assertEquals("2 years, 1 month", timeUtils.duration(2 * 365 + 44));\r
+               assertEquals("2 years, 2 months", timeUtils.duration(2 * 365 + 45));\r
+               assertEquals("2 years, 2 months", timeUtils.duration(2 * 365 + 60));\r
        }\r
 \r
        @Test\r
        public void testTimeAgo() throws Exception {\r
                // standard time ago tests\r
-               assertEquals("1 min ago", TimeUtils.timeAgo(offset(1 * TimeUtils.MIN)));\r
-               assertEquals("60 mins ago", TimeUtils.timeAgo(offset(60 * TimeUtils.MIN)));\r
-               assertEquals("2 hours ago", TimeUtils.timeAgo(offset(120 * TimeUtils.MIN)));\r
-               assertEquals("15 hours ago", TimeUtils.timeAgo(offset(15 * TimeUtils.ONEHOUR)));\r
-               assertEquals("yesterday", TimeUtils.timeAgo(offset(24 * TimeUtils.ONEHOUR)));\r
-               assertEquals("2 days ago", TimeUtils.timeAgo(offset(2 * TimeUtils.ONEDAY)));\r
-               assertEquals("5 weeks ago", TimeUtils.timeAgo(offset(35 * TimeUtils.ONEDAY)));\r
-               assertEquals("3 months ago", TimeUtils.timeAgo(offset(84 * TimeUtils.ONEDAY)));\r
-               assertEquals("3 months ago", TimeUtils.timeAgo(offset(95 * TimeUtils.ONEDAY)));\r
-               assertEquals("4 months ago", TimeUtils.timeAgo(offset(104 * TimeUtils.ONEDAY)));\r
-               assertEquals("1 year ago", TimeUtils.timeAgo(offset(365 * TimeUtils.ONEDAY)));\r
-               assertEquals("13 months ago", TimeUtils.timeAgo(offset(395 * TimeUtils.ONEDAY)));\r
-               assertEquals("2 years ago", TimeUtils.timeAgo(offset((2 * 365 + 30) * TimeUtils.ONEDAY)));\r
+               TimeUtils timeUtils = new TimeUtils();\r
+               assertEquals("just now", timeUtils.timeAgo(offset(1 * TimeUtils.MIN)));\r
+               assertEquals("60 mins ago", timeUtils.timeAgo(offset(60 * TimeUtils.MIN)));\r
+               assertEquals("2 hours ago", timeUtils.timeAgo(offset(120 * TimeUtils.MIN)));\r
+               assertEquals("15 hours ago", timeUtils.timeAgo(offset(15 * TimeUtils.ONEHOUR)));\r
+               assertEquals("yesterday", timeUtils.timeAgo(offset(24 * TimeUtils.ONEHOUR)));\r
+               assertEquals("2 days ago", timeUtils.timeAgo(offset(2 * TimeUtils.ONEDAY)));\r
+               assertEquals("5 weeks ago", timeUtils.timeAgo(offset(35 * TimeUtils.ONEDAY)));\r
+               assertEquals("3 months ago", timeUtils.timeAgo(offset(84 * TimeUtils.ONEDAY)));\r
+               assertEquals("3 months ago", timeUtils.timeAgo(offset(95 * TimeUtils.ONEDAY)));\r
+               assertEquals("4 months ago", timeUtils.timeAgo(offset(104 * TimeUtils.ONEDAY)));\r
+               assertEquals("1 year ago", timeUtils.timeAgo(offset(365 * TimeUtils.ONEDAY)));\r
+               assertEquals("13 months ago", timeUtils.timeAgo(offset(395 * TimeUtils.ONEDAY)));\r
+               assertEquals("2 years ago", timeUtils.timeAgo(offset((2 * 365 + 30) * TimeUtils.ONEDAY)));\r
 \r
                // css class tests\r
-               assertEquals("age0", TimeUtils.timeAgoCss(offset(1 * TimeUtils.MIN)));\r
-               assertEquals("age0", TimeUtils.timeAgoCss(offset(60 * TimeUtils.MIN)));\r
-               assertEquals("age1", TimeUtils.timeAgoCss(offset(120 * TimeUtils.MIN)));\r
-               assertEquals("age1", TimeUtils.timeAgoCss(offset(24 * TimeUtils.ONEHOUR)));\r
-               assertEquals("age2", TimeUtils.timeAgoCss(offset(2 * TimeUtils.ONEDAY)));\r
+               assertEquals("age0", timeUtils.timeAgoCss(offset(1 * TimeUtils.MIN)));\r
+               assertEquals("age0", timeUtils.timeAgoCss(offset(60 * TimeUtils.MIN)));\r
+               assertEquals("age1", timeUtils.timeAgoCss(offset(120 * TimeUtils.MIN)));\r
+               assertEquals("age1", timeUtils.timeAgoCss(offset(24 * TimeUtils.ONEHOUR)));\r
+               assertEquals("age2", timeUtils.timeAgoCss(offset(2 * TimeUtils.ONEDAY)));\r
        }\r
 \r
        @Test\r