diff --git a/.bowerrc b/.bowerrc index ce4030ae..3c5e8c33 100644 --- a/.bowerrc +++ b/.bowerrc @@ -1,3 +1,3 @@ { - "directory" : "app/vendor" + "directory" : "vendor" } diff --git a/.gitignore b/.gitignore index e71e87b6..71b48a51 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ dist/ node_modules/ app/vendor +vendor/ config/main.coffee bower_components app/coffee/modules/locales/locale*.coffee diff --git a/.tx/config b/.tx/config new file mode 100644 index 00000000..191c665f --- /dev/null +++ b/.tx/config @@ -0,0 +1,9 @@ +[main] +host = https://www.transifex.com +lang_map = sr@latin:sr-latn, zh-Hans:zh-hans, zh-Hant:zh-hant + +[taiga-front.locale-enjson] +file_filter = app/locales/locale-.json +source_file = app/locales/locale-en.json +source_lang = en +type = KEYVALUEJSON diff --git a/CHANGELOG.md b/CHANGELOG.md index f4648024..d6c5e017 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,23 @@ # Changelog # +## 1.7.0 Empetrum Nigrum (unreleased) + +### Features +- Make Taiga translatable (i18n support). +- i18n. + - Add spanish (es) translation. + - Add french (fr) translation. + - Add finish (fi) translation. + - Add catalan (ca) translation. + - Add traditional chinese (zh-Hant) translation. +- Add Jitsi to our supported videoconference apps list + +### Misc +- New contrib plugin for letschat (by Δndrea Stagi) +- Lots of small and not so small bugfixes. + + ## 1.6.0 Abies Bifolia (2015-03-17) ### Features diff --git a/README.md b/README.md index c03c93a2..47039de2 100644 --- a/README.md +++ b/README.md @@ -44,3 +44,10 @@ All the information about the different installation methods (production, develo [Taiga has a mailing list](http://groups.google.com/d/forum/taigaio). Feel free to join it and ask any questions you may have. To subscribe for announcements of releases, important changes and so on, please follow [@taigaio](https://twitter.com/taigaio) on Twitter. + +## Donations ## + +We are grateful for your emails volunteering donations to Taiga. We feel comfortable accepting them under these conditions: The first that we will only do so while we are in the current beta / pre-revenue stage and that whatever money is donated will go towards a bounty fund. Starting Q2 2015 we will be engaging much more actively with our community to help further the development of Taiga, and we will use these donations to reward people working alongside us. + +If you wish to make a donation to this Taiga fund, you can do so via http://www.paypal.com using the email: eposner@taiga.io + diff --git a/app-loader/app-loader.coffee b/app-loader/app-loader.coffee index e216a9f0..fba45384 100644 --- a/app-loader/app-loader.coffee +++ b/app-loader/app-loader.coffee @@ -3,6 +3,7 @@ window.taigaConfig = { "api": "http://localhost:8000/api/v1/", "eventsUrl": null, "debug": true, + "defaultLanguage": "en", "publicRegisterEnabled": true, "feedbackEnabled": true, "privacyPolicyUrl": null, diff --git a/app/coffee/app.coffee b/app/coffee/app.coffee index cdec6711..32807348 100644 --- a/app/coffee/app.coffee +++ b/app/coffee/app.coffee @@ -36,7 +36,8 @@ taiga.generateUniqueSessionIdentifier = -> taiga.sessionId = taiga.generateUniqueSessionIdentifier() -configure = ($routeProvider, $locationProvider, $httpProvider, $provide, $tgEventsProvider, tgLoaderProvider, $compileProvider) -> +configure = ($routeProvider, $locationProvider, $httpProvider, $provide, $tgEventsProvider, tgLoaderProvider, + $compileProvider, $translateProvider) -> $routeProvider.when("/", {templateUrl: "project/projects.html", resolve: {loader: tgLoaderProvider.add()}}) @@ -159,12 +160,12 @@ configure = ($routeProvider, $locationProvider, $httpProvider, $provide, $tgEven $routeProvider.when("/permission-denied", {templateUrl: "error/permission-denied.html"}) - $routeProvider.otherwise({redirectTo: '/not-found'}) + $routeProvider.otherwise({redirectTo: "/not-found"}) $locationProvider.html5Mode({enabled: true, requireBase: false}) defaultHeaders = { "Content-Type": "application/json" - "Accept-Language": "en" + "Accept-Language": window.taigaConfig.defaultLanguage || "en" "X-Session-Id": taiga.sessionId } @@ -195,30 +196,30 @@ configure = ($routeProvider, $locationProvider, $httpProvider, $provide, $tgEven responseError: httpResponseError } - $provide.factory("authHttpIntercept", ["$q", "$location", "$tgNavUrls", "lightboxService", authHttpIntercept]) + $provide.factory("authHttpIntercept", ["$q", "$location", "$tgNavUrls", "lightboxService", + authHttpIntercept]) - $httpProvider.interceptors.push('authHttpIntercept') - - # If there is an error in the version throw a notify error - versionCheckHttpIntercept = ($q, $confirm) -> - versionErrorMsg = "Someone inside Taiga has changed this before and our Oompa Loompas cannot apply your changes. - Please reload and apply your changes again (they will be lost)." #TODO: i18n + $httpProvider.interceptors.push("authHttpIntercept") + # If there is an error in the version throw a notify error. + # IMPROVEiMENT: Move this version error handler to USs, issues and tasks repository + versionCheckHttpIntercept = ($q) -> httpResponseError = (response) -> if response.status == 400 && response.data.version - $confirm.notify("error", versionErrorMsg, null, 10000) - - return $q.reject(response) + # HACK: to prevent circular dependencies with [$tgConfirm, $translate] + $injector = angular.element("body").injector() + $injector.invoke(["$tgConfirm", "$translate", ($confirm, $translate) => + versionErrorMsg = $translate.instant("ERROR.VERSION_ERROR") + $confirm.notify("error", versionErrorMsg, null, 10000) + ]) return $q.reject(response) - return { - responseError: httpResponseError - } + return {responseError: httpResponseError} - $provide.factory("versionCheckHttpIntercept", ["$q", "$tgConfirm", versionCheckHttpIntercept]) + $provide.factory("versionCheckHttpIntercept", ["$q", versionCheckHttpIntercept]) - $httpProvider.interceptors.push('versionCheckHttpIntercept'); + $httpProvider.interceptors.push("versionCheckHttpIntercept") window.checksley.updateValidators({ linewidth: (val, width) -> @@ -230,21 +231,78 @@ configure = ($routeProvider, $locationProvider, $httpProvider, $provide, $tgEven return valid }) - window.checksley.updateMessages("default", { - linewidth: "The subject must have a maximum size of %s" - }) - $compileProvider.debugInfoEnabled(window.taigaConfig.debugInfo || false) -init = ($log, $i18n, $config, $rootscope, $auth, $events, $analytics) -> - $i18n.initialize($config.get("defaultLanguage")) + if localStorage.userInfo + userInfo = JSON.parse(localStorage.userInfo) + + # i18n + preferedLangCode = userInfo?.lang || window.taigaConfig.defaultLanguage || "en" + + $translateProvider + .useStaticFilesLoader({ + prefix: "/locales/locale-", + suffix: ".json" + }) + .addInterpolation('$translateMessageFormatInterpolation') + .preferredLanguage(preferedLangCode) + + if not window.taigaConfig.debugInfo + $translateProvider.fallbackLanguage(preferedLangCode) + + +i18nInit = (lang, $translate) -> + # i18n - moment.js + moment.locale(lang) + + # i18n - checksley.js + messages = { + defaultMessage: $translate.instant("COMMON.FORM_ERRORS.DEFAULT_MESSAGE") + type: { + email: $translate.instant("COMMON.FORM_ERRORS.TYPE_EMAIL") + url: $translate.instant("COMMON.FORM_ERRORS.TYPE_URL") + urlstrict: $translate.instant("COMMON.FORM_ERRORS.TYPE_URLSTRICT") + number: $translate.instant("COMMON.FORM_ERRORS.TYPE_NUMBER") + digits: $translate.instant("COMMON.FORM_ERRORS.TYPE_DIGITS") + dateIso: $translate.instant("COMMON.FORM_ERRORS.TYPE_DATEISO") + alphanum: $translate.instant("COMMON.FORM_ERRORS.TYPE_ALPHANUM") + phone: $translate.instant("COMMON.FORM_ERRORS.TYPE_PHONE") + } + notnull: $translate.instant("COMMON.FORM_ERRORS.NOTNULL") + notblank: $translate.instant("COMMON.FORM_ERRORS.NOT_BLANK") + required: $translate.instant("COMMON.FORM_ERRORS.REQUIRED") + regexp: $translate.instant("COMMON.FORM_ERRORS.REGEXP") + min: $translate.instant("COMMON.FORM_ERRORS.MIN") + max: $translate.instant("COMMON.FORM_ERRORS.MAX") + range: $translate.instant("COMMON.FORM_ERRORS.RANGE") + minlength: $translate.instant("COMMON.FORM_ERRORS.MIN_LENGTH") + maxlength: $translate.instant("COMMON.FORM_ERRORS.MAX_LENGTH") + rangelength: $translate.instant("COMMON.FORM_ERRORS.RANGE_LENGTH") + mincheck: $translate.instant("COMMON.FORM_ERRORS.MIN_CHECK") + maxcheck: $translate.instant("COMMON.FORM_ERRORS.MAX_CHECK") + rangecheck: $translate.instant("COMMON.FORM_ERRORS.RANGE_CHECK") + equalto: $translate.instant("COMMON.FORM_ERRORS.EQUAL_TO") + } + checksley.updateMessages('default', messages) + + +init = ($log, $config, $rootscope, $auth, $events, $analytics, $translate) -> $log.debug("Initialize application") + + # Taiga Plugins $rootscope.contribPlugins = @.taigaContribPlugins $rootscope.adminPlugins = _.where(@.taigaContribPlugins, {"type": "admin"}) + $rootscope.$on "$translateChangeEnd", (e, ctx) -> + lang = ctx.language + i18nInit(lang, $translate) + + # Load user if $auth.isAuthenticated() $events.setupConnection() + user = $auth.getUser() + # Analytics $analytics.initialize() @@ -253,7 +311,6 @@ modules = [ "taigaBase", "taigaCommon", "taigaResources", - "taigaLocales", "taigaAuth", "taigaEvents", @@ -261,7 +318,7 @@ modules = [ "taigaRelatedTasks", "taigaBacklog", "taigaTaskboard", - "taigaKanban" + "taigaKanban", "taigaIssues", "taigaUserStories", "taigaTasks", @@ -275,13 +332,15 @@ modules = [ "taigaFeedback", "taigaPlugins", "taigaIntegrations", + "taigaComponents", # template cache - "templates" + "templates", # Vendor modules "ngRoute", "ngAnimate", + "pascalprecht.translate" ].concat(_.map(@.taigaContribPlugins, (plugin) -> plugin.module)) # Main module definition @@ -295,16 +354,17 @@ module.config([ "$tgEventsProvider", "tgLoaderProvider", "$compileProvider", + "$translateProvider", configure ]) module.run([ "$log", - "$tgI18n", "$tgConfig", "$rootScope", "$tgAuth", "$tgEvents", "$tgAnalytics", + "$translate" init ]) diff --git a/app/coffee/modules/admin/lightboxes.coffee b/app/coffee/modules/admin/lightboxes.coffee index a900273c..b8230dfa 100644 --- a/app/coffee/modules/admin/lightboxes.coffee +++ b/app/coffee/modules/admin/lightboxes.coffee @@ -30,19 +30,19 @@ MAX_MEMBERSHIP_FIELDSETS = 4 ## Create Members Lightbox Directive ############################################################################# -CreateMembersDirective = ($rs, $rootScope, $confirm, $loading ,lightboxService) -> +CreateMembersDirective = ($rs, $rootScope, $confirm, $loading, lightboxService, $compile) -> extraTextTemplate = """
- +
""" template = _.template("""
- data-required="true" <% } %> data-type="email" /> + data-required="true" <% } %> data-type="email" />
disabled="disabled"<% } %> <% if(permission.active) { %>checked="checked"<% } %>/> + disabled="disabled" <% } %> + <% if(permission.active) { %> checked="checked" <% } %>/>
- Yes - No + +
<% }) %> @@ -325,58 +329,73 @@ RolePermissionsDirective = ($rootscope, $repo, $confirm) -> categories = [] milestonePermissions = [ - { key: "view_milestones", description: "View sprints" } - { key: "add_milestone", description: "Add sprint" } - { key: "modify_milestone", description: "Modify sprint" } - { key: "delete_milestone", description: "Delete sprint" } + { key: "view_milestones", name: "COMMON.PERMISIONS_CATEGORIES.SPRINTS.VIEW_SPRINTS"} + { key: "add_milestone", name: "COMMON.PERMISIONS_CATEGORIES.SPRINTS.ADD_SPRINTS"} + { key: "modify_milestone", name: "COMMON.PERMISIONS_CATEGORIES.SPRINTS.MODIFY_SPRINTS"} + { key: "delete_milestone", name: "COMMON.PERMISIONS_CATEGORIES.SPRINTS.DELETE_SPRINTS"} ] - categories.push({ name: "Sprints", permissions: setActivePermissions(milestonePermissions) }) + categories.push({ + name: "COMMON.PERMISIONS_CATEGORIES.SPRINTS.NAME", + permissions: setActivePermissions(milestonePermissions) + }) userStoryPermissions = [ - { key: "view_us", description: "View user story" } - { key: "add_us", description: "Add user story" } - { key: "modify_us", description: "Modify user story" } - { key: "delete_us", description: "Delete user story" } + { key: "view_us", name: "COMMON.PERMISIONS_CATEGORIES.USER_STORIES.VIEW_USER_STORIES"} + { key: "add_us", name: "COMMON.PERMISIONS_CATEGORIES.USER_STORIES.ADD_USER_STORIES"} + { key: "modify_us", name: "COMMON.PERMISIONS_CATEGORIES.USER_STORIES.MODIFY_USER_STORIES"} + { key: "delete_us", name: "COMMON.PERMISIONS_CATEGORIES.USER_STORIES.DELETE_USER_STORIES"} ] - categories.push({ name: "User Stories", permissions: setActivePermissions(userStoryPermissions) }) + categories.push({ + name: "COMMON.PERMISIONS_CATEGORIES.USER_STORIES.NAME", + permissions: setActivePermissions(userStoryPermissions) + }) taskPermissions = [ - { key: "view_tasks", description: "View tasks" } - { key: "add_task", description: "Add task" } - { key: "modify_task", description: "Modify task" } - { key: "delete_task", description: "Delete task" } + { key: "view_tasks", name: "COMMON.PERMISIONS_CATEGORIES.TASKS.VIEW_TASKS"} + { key: "add_task", name: "COMMON.PERMISIONS_CATEGORIES.TASKS.ADD_TASKS"} + { key: "modify_task", name: "COMMON.PERMISIONS_CATEGORIES.TASKS.MODIFY_TASKS"} + { key: "delete_task", name: "COMMON.PERMISIONS_CATEGORIES.TASKS.DELETE_TASKS"} ] - categories.push({ name: "Tasks", permissions: setActivePermissions(taskPermissions) }) + categories.push({ + name: "COMMON.PERMISIONS_CATEGORIES.TASKS.NAME" , + permissions: setActivePermissions(taskPermissions) + }) issuePermissions = [ - { key: "view_issues", description: "View issues" } - { key: "add_issue", description: "Add issue" } - { key: "modify_issue", description: "Modify issue" } - { key: "delete_issue", description: "Delete issue" } + { key: "view_issues", name: "COMMON.PERMISIONS_CATEGORIES.ISSUES.VIEW_ISSUES"} + { key: "add_issue", name: "COMMON.PERMISIONS_CATEGORIES.ISSUES.ADD_ISSUES"} + { key: "modify_issue", name: "COMMON.PERMISIONS_CATEGORIES.ISSUES.MODIFY_ISSUES"} + { key: "delete_issue", name: "COMMON.PERMISIONS_CATEGORIES.ISSUES.DELETE_ISSUES"} ] - categories.push({ name: "Issues", permissions: setActivePermissions(issuePermissions) }) + categories.push({ + name: "COMMON.PERMISIONS_CATEGORIES.ISSUES.NAME", + permissions: setActivePermissions(issuePermissions) + }) wikiPermissions = [ - { key: "view_wiki_pages", description: "View wiki pages" } - { key: "add_wiki_page", description: "Add wiki page" } - { key: "modify_wiki_page", description: "Modify wiki page" } - { key: "delete_wiki_page", description: "Delete wiki page" } - { key: "view_wiki_links", description: "View wiki links" } - { key: "add_wiki_link", description: "Add wiki link" } - { key: "delete_wiki_link", description: "Delete wiki link" } + { key: "view_wiki_pages", name: "COMMON.PERMISIONS_CATEGORIES.WIKI.VIEW_WIKI_PAGES"} + { key: "add_wiki_page", name: "COMMON.PERMISIONS_CATEGORIES.WIKI.ADD_WIKI_PAGES"} + { key: "modify_wiki_page", name: "COMMON.PERMISIONS_CATEGORIES.WIKI.MODIFY_WIKI_PAGES"} + { key: "delete_wiki_page", name: "COMMON.PERMISIONS_CATEGORIES.WIKI.DELETE_WIKI_PAGES"} + { key: "view_wiki_links", name: "COMMON.PERMISIONS_CATEGORIES.WIKI.VIEW_WIKI_LINKS"} + { key: "add_wiki_link", name: "COMMON.PERMISIONS_CATEGORIES.WIKI.ADD_WIKI_LINKS"} + { key: "delete_wiki_link", name: "COMMON.PERMISIONS_CATEGORIES.WIKI.DELETE_WIKI_LINKS"} ] - categories.push({ name: "Wiki", permissions: setActivePermissions(wikiPermissions) }) + categories.push({ + name: "COMMON.PERMISIONS_CATEGORIES.WIKI.NAME", + permissions: setActivePermissions(wikiPermissions) + }) return setActivePermissionsPerCategory(categories) renderResume = (element, category) -> - element.find(".resume").html(resumeTemplate({category: category})) + element.find(".resume").html($compile(resumeTemplate({category: category}))($scope)) renderCategory = (category, index) -> html = categoryTemplate({category: category, index: index}) html = angular.element(html) renderResume(html, category) - return html + return $compile(html)($scope) renderPermissions = () -> $el.off() @@ -437,4 +456,5 @@ RolePermissionsDirective = ($rootscope, $repo, $confirm) -> return {link:link} -module.directive("tgRolePermissions", ["$rootScope", "$tgRepo", "$tgConfirm", RolePermissionsDirective]) +module.directive("tgRolePermissions", ["$rootScope", "$tgRepo", "$tgConfirm", "$compile", + RolePermissionsDirective]) diff --git a/app/coffee/modules/admin/third-parties.coffee b/app/coffee/modules/admin/third-parties.coffee index ceeaaf2f..06bb946e 100644 --- a/app/coffee/modules/admin/third-parties.coffee +++ b/app/coffee/modules/admin/third-parties.coffee @@ -40,19 +40,21 @@ class WebhooksController extends mixOf(taiga.Controller, taiga.PageMixin, taiga. "$routeParams", "$tgLocation", "$tgNavUrls", - "$appTitle" + "$appTitle", + "$translate" ] - constructor: (@scope, @repo, @rs, @params, @location, @navUrls, @appTitle) -> + constructor: (@scope, @repo, @rs, @params, @location, @navUrls, @appTitle, @translate) -> bindMethods(@) - @scope.sectionName = "Webhooks" #i18n + @scope.sectionName = "ADMIN.WEBHOOKS.SECTION_NAME" @scope.project = {} promise = @.loadInitialData() promise.then () => - @appTitle.set("Webhooks - " + @scope.project.name) + text = @translate.instant("ADMIN.WEBHOOKS.APP_TITLE", {"projectName": @scope.project.name}) + @appTitle.set(text) promise.then null, @.onInitialDataError.bind(@) @@ -85,17 +87,19 @@ module.controller("WebhooksController", WebhooksController) ## Webhook Directive ############################################################################# -WebhookDirective = ($rs, $repo, $confirm, $loading) -> +WebhookDirective = ($rs, $repo, $confirm, $loading, $translate) -> link = ($scope, $el, $attrs) -> webhook = $scope.$eval($attrs.tgWebhook) updateLogs = () -> + prettyDate = $translate.instant("ADMIN.WEBHOOKS.DATE") + $rs.webhooklogs.list(webhook.id).then (webhooklogs) => for log in webhooklogs log.validStatus = 200 <= log.status < 300 log.prettySentHeaders = _.map(_.pairs(log.request_headers), ([header, value]) -> "#{header}: #{value}").join("\n") log.prettySentData = JSON.stringify(log.request_data) - log.prettyDate = moment(log.created).format("DD MMM YYYY [at] hh:mm:ss") # TODO: i18n + log.prettyDate = moment(log.created).format(prettyDate) webhook.logs_counter = webhooklogs.length webhook.logs = webhooklogs @@ -104,10 +108,16 @@ WebhookDirective = ($rs, $repo, $confirm, $loading) -> updateShowHideHistoryText = () -> textElement = $el.find(".toggle-history") historyElement = textElement.parents(".single-webhook-wrapper").find(".webhooks-history") + if historyElement.hasClass("open") - textElement.text("(Hide history)") # TODO: i18n + text = $translate.instant("ADMIN.WEBHOOKS.ACTION_HIDE_HISTORY") + title = $translate.instant("ADMIN.WEBHOOKS.ACTION_HIDE_HISTORY_TITLE") else - textElement.text("(Show history)") # TODO: i18n + text = $translate.instant("ADMIN.WEBHOOKS.ACTION_SHOW_HISTORY") + title = $translate.instant("ADMIN.WEBHOOKS.ACTION_SHOW_HISTORY_TITLE") + + textElement.text(text) + textElement.prop("title", title) showVisualizationMode = () -> $el.find(".edition-mode").addClass("hidden") @@ -161,8 +171,8 @@ WebhookDirective = ($rs, $repo, $confirm, $loading) -> cancel(target) $el.on "click", ".delete-webhook", () -> - title = "Delete webhook" #TODO: i18n - message = "Webhook '#{webhook.name}'" #TODO: i18n + title = $translate.instant("ADMIN.WEBHOOKS.DELETE") + message = $translate.instant("ADMIN.WEBHOOKS.WEBHOOK_NAME", {name: webhook.name}) $confirm.askOnDelete(title, message).then (finish) => onSucces = -> @@ -203,7 +213,7 @@ WebhookDirective = ($rs, $repo, $confirm, $loading) -> return {link:link} -module.directive("tgWebhook", ["$tgResources", "$tgRepo", "$tgConfirm", "$tgLoading", WebhookDirective]) +module.directive("tgWebhook", ["$tgResources", "$tgRepo", "$tgConfirm", "$tgLoading", "$translate", WebhookDirective]) ############################################################################# @@ -279,19 +289,21 @@ class GithubController extends mixOf(taiga.Controller, taiga.PageMixin, taiga.Fi "$tgRepo", "$tgResources", "$routeParams", - "$appTitle" + "$appTitle", + "$translate" ] - constructor: (@scope, @repo, @rs, @params, @appTitle) -> + constructor: (@scope, @repo, @rs, @params, @appTitle, @translate) -> bindMethods(@) - @scope.sectionName = "Github" #i18n + @scope.sectionName = @translate.instant("ADMIN.GITHUB.SECTION_NAME") @scope.project = {} promise = @.loadInitialData() promise.then () => - @appTitle.set("Github - " + @scope.project.name) + title = @translate.instant("ADMIN.GITHUB.APP_TITLE", {projectName: @scope.project.name}) + @appTitle.set(title) promise.then null, @.onInitialDataError.bind(@) @@ -327,18 +339,20 @@ class GitlabController extends mixOf(taiga.Controller, taiga.PageMixin, taiga.Fi "$tgRepo", "$tgResources", "$routeParams", - "$appTitle" + "$appTitle", + "$translate" ] - constructor: (@scope, @repo, @rs, @params, @appTitle) -> + constructor: (@scope, @repo, @rs, @params, @appTitle, @translate) -> bindMethods(@) - @scope.sectionName = "Gitlab" #i18n + @scope.sectionName = @translate.instant("ADMIN.GITLAB.SECTION_NAME") @scope.project = {} promise = @.loadInitialData() promise.then () => - @appTitle.set("Gitlab - " + @scope.project.name) + title = @translate.instant("ADMIN.GITLAB.APP_TITLE", {projectName: @scope.project.name}) + @appTitle.set(title) promise.then null, @.onInitialDataError.bind(@) @@ -377,18 +391,20 @@ class BitbucketController extends mixOf(taiga.Controller, taiga.PageMixin, taiga "$tgRepo", "$tgResources", "$routeParams", - "$appTitle" + "$appTitle", + "$translate" ] - constructor: (@scope, @repo, @rs, @params, @appTitle) -> + constructor: (@scope, @repo, @rs, @params, @appTitle, @translate) -> bindMethods(@) - @scope.sectionName = "Bitbucket" #i18n + @scope.sectionName = @translate.instant("ADMIN.BITBUCKET.SECTION_NAME") @scope.project = {} promise = @.loadInitialData() promise.then () => - @appTitle.set("Bitbucket - " + @scope.project.name) + title = @translate.instant("ADMIN.BITBUCKET.APP_TITLE", {projectName: @scope.project.name}) + @appTitle.set(title) promise.then null, @.onInitialDataError.bind(@) diff --git a/app/coffee/modules/auth.coffee b/app/coffee/modules/auth.coffee index 587067bd..7735eb04 100644 --- a/app/coffee/modules/auth.coffee +++ b/app/coffee/modules/auth.coffee @@ -34,11 +34,17 @@ class AuthService extends taiga.Service "$tgModel", "$tgResources", "$tgHttp", - "$tgUrls"] + "$tgUrls", + "$tgConfig", + "$translate"] - constructor: (@rootscope, @storage, @model, @rs, @http, @urls) -> + constructor: (@rootscope, @storage, @model, @rs, @http, @urls, @config, @translate) -> super() + _setLocales: -> + lang = @rootscope.user.lang || @config.get("defaultLanguage") || "en" + @translate.use(lang) + getUser: -> if @rootscope.user return @rootscope.user @@ -47,16 +53,18 @@ class AuthService extends taiga.Service if userData user = @model.make_model("users", userData) @rootscope.user = user + @._setLocales() return user return null setUser: (user) -> @rootscope.auth = user - @rootscope.$broadcast("i18n:change", user.default_language) @storage.set("userInfo", user.getAttrs()) @rootscope.user = user + @._setLocales() + clear: -> @rootscope.auth = null @rootscope.user = null @@ -171,7 +179,7 @@ PublicRegisterMessageDirective = ($config, $navUrls, templates) -> module.directive("tgPublicRegisterMessage", ["$tgConfig", "$tgNavUrls", "$tgTemplate", PublicRegisterMessageDirective]) -LoginDirective = ($auth, $confirm, $location, $config, $routeParams, $navUrls, $events) -> +LoginDirective = ($auth, $confirm, $location, $config, $routeParams, $navUrls, $events, $translate) -> link = ($scope, $el, $attrs) -> onSuccess = (response) -> if $routeParams['next'] and $routeParams['next'] != $navUrls.resolve("login") @@ -183,8 +191,8 @@ LoginDirective = ($auth, $confirm, $location, $config, $routeParams, $navUrls, $ $location.path(nextUrl) onError = (response) -> - $confirm.notify("light-error", "According to our Oompa Loompas, your username/email - or password are incorrect.") #TODO: i18n + $confirm.notify("light-error", $translate.instant("LOGIN_FORM.ERROR_AUTH_INCORRECT")) + submit = debounce 2000, (event) => event.preventDefault() @@ -207,13 +215,13 @@ LoginDirective = ($auth, $confirm, $location, $config, $routeParams, $navUrls, $ return {link:link} module.directive("tgLogin", ["$tgAuth", "$tgConfirm", "$tgLocation", "$tgConfig", "$routeParams", - "$tgNavUrls", "$tgEvents", LoginDirective]) + "$tgNavUrls", "$tgEvents", "$translate", LoginDirective]) ############################################################################# ## Register Directive ############################################################################# -RegisterDirective = ($auth, $confirm, $location, $navUrls, $config, $analytics) -> +RegisterDirective = ($auth, $confirm, $location, $navUrls, $config, $analytics, $translate) -> link = ($scope, $el, $attrs) -> if not $config.get("publicRegisterEnabled") $location.path($navUrls.resolve("not-found")) @@ -224,12 +232,15 @@ RegisterDirective = ($auth, $confirm, $location, $navUrls, $config, $analytics) onSuccessSubmit = (response) -> $analytics.trackEvent("auth", "register", "user registration", 1) - $confirm.notify("success", "Our Oompa Loompas are happy, welcome to Taiga.") #TODO: i18n + + $confirm.notify("success", $translate.instant("LOGIN_FORM.SUCCESS")) + $location.path($navUrls.resolve("home")) onErrorSubmit = (response) -> if response.data._error_message? - $confirm.notify("light-error", "According to our Oompa Loompas there was an error. #{response.data._error_message}") #TODO: i18n + text = $translate.instant("LOGIN_FORM.ERROR_GENERIC") + " " + response.data._error_message + $confirm.notify("light-error", text + " " + response.data._error_message) form.setErrors(response.data) @@ -247,25 +258,27 @@ RegisterDirective = ($auth, $confirm, $location, $navUrls, $config, $analytics) return {link:link} module.directive("tgRegister", ["$tgAuth", "$tgConfirm", "$tgLocation", "$tgNavUrls", "$tgConfig", - "$tgAnalytics", RegisterDirective]) + "$tgAnalytics", "$translate", RegisterDirective]) ############################################################################# ## Forgot Password Directive ############################################################################# -ForgotPasswordDirective = ($auth, $confirm, $location, $navUrls) -> +ForgotPasswordDirective = ($auth, $confirm, $location, $navUrls, $translate) -> link = ($scope, $el, $attrs) -> $scope.data = {} form = $el.find("form").checksley() onSuccessSubmit = (response) -> $location.path($navUrls.resolve("login")) - $confirm.success("Check your inbox!
- We have sent you an email with the instructions to set a new password") #TODO: i18n + + text = $translate.instant("FORGOT_PASSWORD_FORM.SUCCESS") + $confirm.success(text) onErrorSubmit = (response) -> - $confirm.notify("light-error", "According to our Oompa Loompas, - your are not registered yet.") #TODO: i18n + text = $translate.instant("FORGOT_PASSWORD_FORM.ERROR") + + $confirm.notify("light-error", text) submit = debounce 2000, (event) => event.preventDefault() @@ -280,14 +293,14 @@ ForgotPasswordDirective = ($auth, $confirm, $location, $navUrls) -> return {link:link} -module.directive("tgForgotPassword", ["$tgAuth", "$tgConfirm", "$tgLocation", "$tgNavUrls", +module.directive("tgForgotPassword", ["$tgAuth", "$tgConfirm", "$tgLocation", "$tgNavUrls", "$translate", ForgotPasswordDirective]) ############################################################################# ## Change Password from Recovery Directive ############################################################################# -ChangePasswordFromRecoveryDirective = ($auth, $confirm, $location, $params, $navUrls) -> +ChangePasswordFromRecoveryDirective = ($auth, $confirm, $location, $params, $navUrls, $translate) -> link = ($scope, $el, $attrs) -> $scope.data = {} @@ -301,12 +314,15 @@ ChangePasswordFromRecoveryDirective = ($auth, $confirm, $location, $params, $nav onSuccessSubmit = (response) -> $location.path($navUrls.resolve("login")) - $confirm.success("Our Oompa Loompas saved your new password.
- Try to sign in with it.") #TODO: i18n + + text = $translate.instant("CHANGE_PASSWORD_RECOVERY_FORM.SUCCESS") + + $confirm.success(text) onErrorSubmit = (response) -> - $confirm.notify("light-error", "One of our Oompa Loompas say - '#{response.data._error_message}'.") #TODO: i18n + text = $translate.instant("COMMON.GENERIC_ERROR", {error: response.data._error_message}) + + $confirm.notify("light-error", text) submit = debounce 2000, (event) => event.preventDefault() @@ -322,13 +338,13 @@ ChangePasswordFromRecoveryDirective = ($auth, $confirm, $location, $params, $nav return {link:link} module.directive("tgChangePasswordFromRecovery", ["$tgAuth", "$tgConfirm", "$tgLocation", "$routeParams", - "$tgNavUrls", ChangePasswordFromRecoveryDirective]) + "$tgNavUrls", "$translate", ChangePasswordFromRecoveryDirective]) ############################################################################# ## Invitation ############################################################################# -InvitationDirective = ($auth, $confirm, $location, $params, $navUrls, $analytics) -> +InvitationDirective = ($auth, $confirm, $location, $params, $navUrls, $analytics, $translate) -> link = ($scope, $el, $attrs) -> token = $params.token @@ -338,8 +354,9 @@ InvitationDirective = ($auth, $confirm, $location, $params, $navUrls, $analytics promise.then null, (response) -> $location.path($navUrls.resolve("login")) - $confirm.success("Ooops, we have a problem
- Our Oompa Loompas can't find your invitation.") #TODO: i18n + + text = $translate.instant("INVITATION_LOGIN_FORM.NOT_FOUND") + $confirm.success(text) # Login form $scope.dataLogin = {token: token} @@ -348,12 +365,14 @@ InvitationDirective = ($auth, $confirm, $location, $params, $navUrls, $analytics onSuccessSubmitLogin = (response) -> $analytics.trackEvent("auth", "invitationAccept", "invitation accept with existing user", 1) $location.path($navUrls.resolve("project", {project: $scope.invitation.project_slug})) - $confirm.notify("success", "You've successfully joined this project", - "Welcome to #{_.escape($scope.invitation.project_name)}") + text = $translate.instant("INVITATION_LOGIN_FORM.SUCCESS", {"project_name": $scope.invitation.project_name}) + + $confirm.notify("success", text) onErrorSubmitLogin = (response) -> - $confirm.notify("light-error", "According to our Oompa Loompas, your are not registered yet or - typed an invalid password.") #TODO: i18n + text = $translate.instant("INVITATION_LOGIN_FORM.ERROR") + + $confirm.notify("light-error", text) submitLogin = debounce 2000, (event) => event.preventDefault() @@ -378,8 +397,9 @@ InvitationDirective = ($auth, $confirm, $location, $params, $navUrls, $analytics "Welcome to #{_.escape($scope.invitation.project_name)}") onErrorSubmitRegister = (response) -> - $confirm.notify("light-error", "According to our Oompa Loompas, that - username or email is already in use.") #TODO: i18n + text = $translate.instant("LOGIN_FORM.ERROR_AUTH_INCORRECT") + + $confirm.notify("light-error", text) submitRegister = debounce 2000, (event) => event.preventDefault() @@ -396,13 +416,13 @@ InvitationDirective = ($auth, $confirm, $location, $params, $navUrls, $analytics return {link:link} module.directive("tgInvitation", ["$tgAuth", "$tgConfirm", "$tgLocation", "$routeParams", - "$tgNavUrls", "$tgAnalytics", InvitationDirective]) + "$tgNavUrls", "$tgAnalytics", "$translate", InvitationDirective]) ############################################################################# ## Change Email ############################################################################# -ChangeEmailDirective = ($repo, $model, $auth, $confirm, $location, $params, $navUrls) -> +ChangeEmailDirective = ($repo, $model, $auth, $confirm, $location, $params, $navUrls, $translate) -> link = ($scope, $el, $attrs) -> $scope.data = {} $scope.data.email_token = $params.email_token @@ -412,11 +432,14 @@ ChangeEmailDirective = ($repo, $model, $auth, $confirm, $location, $params, $nav $repo.queryOne("users", $auth.getUser().id).then (data) => $auth.setUser(data) $location.path($navUrls.resolve("home")) - $confirm.success("Our Oompa Loompas updated your email") #TODO: i18n + + text = $translate.instant("CHANGE_EMAIL_FORM.SUCCESS") + $confirm.success(text) onErrorSubmit = (response) -> - $confirm.notify("error", "One of our Oompa Loompas says - '#{response.data._error_message}'.") #TODO: i18n + text = $translate.instant("COMMON.GENERIC_ERROR", {error: response.data._error_message}) + + $confirm.notify("light-error", text) submit = -> if not form.validate() @@ -436,7 +459,7 @@ ChangeEmailDirective = ($repo, $model, $auth, $confirm, $location, $params, $nav return {link:link} module.directive("tgChangeEmail", ["$tgRepo", "$tgModel", "$tgAuth", "$tgConfirm", "$tgLocation", "$routeParams", - "$tgNavUrls", ChangeEmailDirective]) + "$tgNavUrls", "$translate", ChangeEmailDirective]) ############################################################################# ## Cancel account @@ -451,11 +474,15 @@ CancelAccountDirective = ($repo, $model, $auth, $confirm, $location, $params, $n onSuccessSubmit = (response) -> $auth.logout() $location.path($navUrls.resolve("home")) - $confirm.success("Our Oompa Loompas removed your account") #TODO: i18n + + text = $translate.instant("CANCEL_ACCOUNT.SUCCESS") + + $confirm.success(text) onErrorSubmit = (response) -> - $confirm.notify("error", "One of our Oompa Loompas says - '#{response.data._error_message}'.") #TODO: i18n + text = $translate.instant("COMMON.GENERIC_ERROR", {error: response.data._error_message}) + + $confirm.notify("error", text) submit = debounce 2000, (event) => event.preventDefault() diff --git a/app/coffee/modules/backlog/filters.coffee b/app/coffee/modules/backlog/filters.coffee index 8185fdf2..bf6a4186 100644 --- a/app/coffee/modules/backlog/filters.coffee +++ b/app/coffee/modules/backlog/filters.coffee @@ -116,6 +116,9 @@ BacklogFiltersDirective = ($log, $location, $templates) -> $scope.$on "filters:loaded", (ctx, filters) -> initializeSelectedFilters(filters) + $scope.$on "filters:update", (ctx, filters) -> + renderFilters(filters) + ## Dom Event Handlers $el.on "click", ".filters-cats > ul > li > a", (event) -> event.preventDefault() diff --git a/app/coffee/modules/backlog/lightboxes.coffee b/app/coffee/modules/backlog/lightboxes.coffee index d77ac2ee..cd72905e 100644 --- a/app/coffee/modules/backlog/lightboxes.coffee +++ b/app/coffee/modules/backlog/lightboxes.coffee @@ -29,7 +29,7 @@ module = angular.module("taigaBacklog") ## Creare/Edit Sprint Lightbox Directive ############################################################################# -CreateEditSprint = ($repo, $confirm, $rs, $rootscope, lightboxService, $loading) -> +CreateEditSprint = ($repo, $confirm, $rs, $rootscope, lightboxService, $loading, $translate) -> link = ($scope, $el, attrs) -> hasErrors = false createSprint = true @@ -43,8 +43,10 @@ CreateEditSprint = ($repo, $confirm, $rs, $rootscope, lightboxService, $loading) submit = debounce 2000, (event) => event.preventDefault() - target = angular.element(event.currentTarget) + prettyDate = $translate.instant("COMMON.PICKERDATE.FORMAT") + + submitButton = $el.find(".submit-button") form = $el.find("form").checksley() if not form.validate() @@ -57,13 +59,15 @@ CreateEditSprint = ($repo, $confirm, $rs, $rootscope, lightboxService, $loading) broadcastEvent = null if createSprint - newSprint.estimated_start = moment(newSprint.estimated_start).format("YYYY-MM-DD") - newSprint.estimated_finish = moment(newSprint.estimated_finish).format("YYYY-MM-DD") + newSprint.estimated_start = moment(newSprint.estimated_start, prettyDate).format("YYYY-MM-DD") + newSprint.estimated_finish = moment(newSprint.estimated_finish,prettyDate).format("YYYY-MM-DD") promise = $repo.create("milestones", newSprint) broadcastEvent = "sprintform:create:success" else - newSprint.setAttr("estimated_start", moment(newSprint.estimated_start).format("YYYY-MM-DD")) - newSprint.setAttr("estimated_finish", moment(newSprint.estimated_finish).format("YYYY-MM-DD")) + newSprint.setAttr("estimated_start", + moment(newSprint.estimated_start, prettyDate).format("YYYY-MM-DD")) + newSprint.setAttr("estimated_finish", + moment(newSprint.estimated_finish, prettyDate).format("YYYY-MM-DD")) promise = $repo.save(newSprint) broadcastEvent = "sprintform:edit:success" @@ -86,8 +90,7 @@ CreateEditSprint = ($repo, $confirm, $rs, $rootscope, lightboxService, $loading) $confirm.notify("light-error", data.__all__[0]) remove = -> - #TODO: i18n - title = "Delete sprint" + title = $translate.instant("LIGHTBOX.DELETE_SPRINT.TITLE") message = $scope.sprint.name $confirm.askOnDelete(title, message).then (finish) => @@ -107,6 +110,7 @@ CreateEditSprint = ($repo, $confirm, $rs, $rootscope, lightboxService, $loading) form.reset() createSprint = true + prettyDate = $translate.instant("COMMON.PICKERDATE.FORMAT") $scope.sprint.project = projectId $scope.sprint.name = null $scope.sprint.slug = null @@ -118,36 +122,50 @@ CreateEditSprint = ($repo, $confirm, $rs, $rootscope, lightboxService, $loading) estimatedStart = moment($scope.sprint.estimated_start) else if lastSprint? estimatedStart = moment(lastSprint.estimated_finish) - $scope.sprint.estimated_start = estimatedStart.format("DD MMM YYYY") + $scope.sprint.estimated_start = estimatedStart.format(prettyDate) estimatedFinish = moment().add(2, "weeks") if $scope.sprint.estimated_finish estimatedFinish = moment($scope.sprint.estimated_finish) else if lastSprint? estimatedFinish = moment(lastSprint.estimated_finish).add(2, "weeks") - $scope.sprint.estimated_finish = estimatedFinish.format("DD MMM YYYY") + $scope.sprint.estimated_finish = estimatedFinish.format(prettyDate) lastSprintNameDom = $el.find(".last-sprint-name") if lastSprint?.name? - lastSprintNameDom.html(" last sprint is #{lastSprint.name} ;-) ") + text = $translate.instant("LIGHTBOX.ADD_EDIT_SPRINT.LAST_SPRINT_NAME", { + lastSprint: lastSprint.name}) + lastSprintNameDom.html(text) $el.find(".delete-sprint").addClass("hidden") - $el.find(".title").text("New sprint") #TODO i18n - $el.find(".button-green").text("Create") #TODO i18n + + text = $translate.instant("LIGHTBOX.ADD_EDIT_SPRINT.TITLE") + $el.find(".title").text(text) + + text = $translate.instant("COMMON.CREATE") + $el.find(".button-green").text(text) + lightboxService.open($el) $el.find(".sprint-name").focus() $el.find(".last-sprint-name").removeClass("disappear") $scope.$on "sprintform:edit", (ctx, sprint) -> createSprint = false + prettyDate = $translate.instant("COMMON.PICKERDATE.FORMAT") + $scope.$apply -> $scope.sprint = sprint - $scope.sprint.estimated_start = moment($scope.sprint.estimated_start).format("DD MMM YYYY") - $scope.sprint.estimated_finish = moment($scope.sprint.estimated_finish).format("DD MMM YYYY") + $scope.sprint.estimated_start = moment($scope.sprint.estimated_start).format(prettyDate) + $scope.sprint.estimated_finish = moment($scope.sprint.estimated_finish).format(prettyDate) $el.find(".delete-sprint").removeClass("hidden") - $el.find(".title").text("Edit sprint") #TODO i18n - $el.find(".button-green").text("Save") #TODO i18n + + editSprint = $translate.instant("BACKLOG.EDIT_SPRINT") + $el.find(".title").text(editSprint) + + save = $translate.instant("COMMON.SAVE") + $el.find(".button-green").text(save) + lightboxService.open($el) $el.find(".sprint-name").focus().select() $el.find(".last-sprint-name").addClass("disappear") @@ -158,8 +176,6 @@ CreateEditSprint = ($repo, $confirm, $rs, $rootscope, lightboxService, $loading) else $el.find(".last-sprint-name").removeClass("disappear") - submitButton = $el.find(".submit-button") - $el.on "submit", "form", submit $el.on "click", ".delete-sprint .icon-delete", (event) -> @@ -178,6 +194,7 @@ module.directive("tgLbCreateEditSprint", [ "$tgResources", "$rootScope", "lightboxService" - "$tgLoading" + "$tgLoading", + "$translate", CreateEditSprint ]) diff --git a/app/coffee/modules/backlog/main.coffee b/app/coffee/modules/backlog/main.coffee index ab7773c8..27ce413c 100644 --- a/app/coffee/modules/backlog/main.coffee +++ b/app/coffee/modules/backlog/main.coffee @@ -49,14 +49,15 @@ class BacklogController extends mixOf(taiga.Controller, taiga.PageMixin, taiga.F "$tgNavUrls", "$tgEvents", "$tgAnalytics", - "tgLoader" + "tgLoader", + "$translate" ] constructor: (@scope, @rootscope, @repo, @confirm, @rs, @params, @q, - @location, @appTitle, @navUrls, @events, @analytics, tgLoader) -> + @location, @appTitle, @navUrls, @events, @analytics, tgLoader, @translate) -> bindMethods(@) - @scope.sectionName = "Backlog" + @scope.sectionName = @translate.instant("BACKLOG.SECTION_NAME") @showTags = false @activeFilters = false @@ -439,12 +440,16 @@ class BacklogController extends mixOf(taiga.Controller, taiga.PageMixin, taiga.F return _.pick(@location.search(), "statuses", "tags", "q") generateFilters: -> + urlfilters = @.getUrlFilters() @scope.filters = {} #tags plainTags = _.flatten(_.filter(_.map(@scope.visibleUserstories, "tags"))) plainTags.sort() + if plainTags.length == 0 and urlfilters["tags"] + plainTags.push(urlfilters["tags"]) + @scope.filters.tags = _.map _.countBy(plainTags), (v, k) => obj = { id: k, @@ -466,6 +471,9 @@ class BacklogController extends mixOf(taiga.Controller, taiga.PageMixin, taiga.F if status return status + if plainStatuses.length == 0 and urlfilters["statuses"] + plainStatuses.push(urlfilters["statuses"]) + @scope.filters.statuses = _.map _.countBy(plainStatuses), (v, k) => obj = { id: k, @@ -491,12 +499,19 @@ class BacklogController extends mixOf(taiga.Controller, taiga.PageMixin, taiga.F ## Template actions + updateUserStoryStatus: () -> + @.setSearchDataFilters() + @.filterVisibleUserstories() + @.generateFilters() + @rootscope.$broadcast("filters:update", @scope.filters['statuses']) + @.loadProjectStats() + editUserStory: (us) -> @rootscope.$broadcast("usform:edit", us) deleteUserStory: (us) -> - #TODO: i18n - title = "Delete User Story" + title = @translate.instant("US.TITLE_DELETE_ACTION") + message = us.subject @confirm.askOnDelete(title, message).then (finish) => @@ -527,12 +542,11 @@ module.controller("BacklogController", BacklogController) ## Backlog Directive ############################################################################# -BacklogDirective = ($repo, $rootscope) -> +BacklogDirective = ($repo, $rootscope, $translate) -> ## Doom line Link doomLineTemplate = _.template(""" -
Project Scope [Doomline]
+
<%- text %>
""") - # TODO: i18n linkDoomLine = ($scope, $el, $attrs, $ctrl) -> reloadDoomLine = -> @@ -559,7 +573,8 @@ BacklogDirective = ($repo, $rootscope) -> $el.find(".doom-line").remove() addDoomLineDom = (element) -> - $(element).before(doomLineTemplate({})) + text = $translate.instant("BACKLOG.DOOMLINE") + $(element).before(doomLineTemplate({"text": text})) getUsItems = -> rowElements = $el.find('.backlog-table-body .us-item-row') @@ -629,10 +644,14 @@ BacklogDirective = ($repo, $rootscope) -> if $ctrl.showTags elm.addClass("active") - elm.find(".text").text("Hide Tags") # TODO: i18n + + text = $translate.instant("BACKLOG.TAGS.HIDE") + elm.find(".text").text(text) else elm.removeClass("active") - elm.find(".text").text("Show Tags") # TODO: i18n + + text = $translate.instant("BACKLOG.TAGS.SHOW") + elm.find(".text").text(text) showHideFilter = ($scope, $el, $ctrl) -> sidebar = $el.find("sidebar.filters-bar") @@ -646,7 +665,10 @@ BacklogDirective = ($repo, $rootscope) -> sidebar.toggleClass("active") target.toggleClass("active") - toggleText(target.find(".text"), ["Remove Filters", "Show Filters"]) # TODO: i18n + hideText = $translate.instant("BACKLOG.FILTERS.HIDE") + showText = $translate.instant("BACKLOG.FILTERS.SHOW") + + toggleText(target.find(".text"), [hideText, showText]) if !sidebar.hasClass("active") $ctrl.resetFilters() @@ -687,14 +709,13 @@ BacklogDirective = ($repo, $rootscope) -> return {link: link} -module.directive("tgBacklog", ["$tgRepo", "$rootScope", BacklogDirective]) +module.directive("tgBacklog", ["$tgRepo", "$rootScope", "$translate", BacklogDirective]) ############################################################################# ## User story points directive ############################################################################# -UsRolePointsSelectorDirective = ($rootscope, $template) -> - #TODO: i18n +UsRolePointsSelectorDirective = ($rootscope, $template, $compile, $translate) -> selectionTemplate = $template.get("backlog/us-role-points-popover.html", true) link = ($scope, $el, $attrs) -> @@ -704,7 +725,7 @@ UsRolePointsSelectorDirective = ($rootscope, $template) -> numberOfRoles = _.size(roles) if numberOfRoles > 1 - $el.append(selectionTemplate({"roles":roles})) + $el.append($compile(selectionTemplate({"roles": roles}))($scope)) else $el.find(".icon-arrow-bottom").remove() $el.find(".header-points").addClass("not-clickable") @@ -715,7 +736,9 @@ UsRolePointsSelectorDirective = ($rootscope, $template) -> $scope.$on "uspoints:clear-selection", (ctx, roleId) -> $el.find(".popover").popover().close() - $el.find(".header-points").text("Points") #TODO: i18n + + text = $translate.instant("COMMON.FIELDS.POINTS") + $el.find(".header-points").text(text) # Dom Event Handlers $el.on "click", (event) -> @@ -743,7 +766,7 @@ UsRolePointsSelectorDirective = ($rootscope, $template) -> return {link: link} -module.directive("tgUsRolePointsSelector", ["$rootScope", "$tgTemplate", UsRolePointsSelectorDirective]) +module.directive("tgUsRolePointsSelector", ["$rootScope", "$tgTemplate", "$compile", UsRolePointsSelectorDirective]) UsPointsDirective = ($tgEstimationsService, $repo, $tgTemplate) -> @@ -848,11 +871,12 @@ UsPointsDirective = ($tgEstimationsService, $repo, $tgTemplate) -> module.directive("tgBacklogUsPoints", ["$tgEstimationsService", "$tgRepo", "$tgTemplate", UsPointsDirective]) + ############################################################################# ## Burndown graph directive ############################################################################# -tgBacklogGraphDirective = -> +BurndownBacklogGraphDirective = ($translate) -> redrawChart = (element, dataToDraw) -> width = element.width() element.height(width/6) @@ -908,13 +932,20 @@ tgBacklogGraphDirective = -> } xaxis: { ticks: dataToDraw.milestones.length - axisLabel: "Sprints" + axisLabel: $translate.instant("BACKLOG.CHART.XAXIS_LABEL"), axisLabelUseCanvas: true - axisLabelFontSizePixels: 14 + axisLabelFontSizePixels: 12 axisLabelFontFamily: "Verdana, Arial, Helvetica, Tahoma, sans-serif" - axisLabelPadding: 15 + axisLabelPadding: 5 tickFormatter: (val, axis) -> "" } + yaxis: { + axisLabel: $translate.instant("BACKLOG.CHART.YAXIS_LABEL"), + axisLabelUseCanvas: true + axisLabelFontSizePixels: 12 + axisLabelFontFamily: "Verdana, Arial, Helvetica, Tahoma, sans-serif" + axisLabelPadding: 5 + } series: { shadowSize: 0 lines: { @@ -932,18 +963,18 @@ tgBacklogGraphDirective = -> tooltip: true tooltipOpts: { content: (label, xval, yval, flotItem) -> - #TODO: i18n if flotItem.seriesIndex == 1 - return "Optimal pending points for sprint #{xval} should be #{yval}" - + ctx = {xval: xval, yval: yval} + return $translate.instant("BACKLOG.CHART.OPTIMAL", ctx) else if flotItem.seriesIndex == 2 - return "Real pending points for sprint #{xval} is #{yval}" - + ctx = {xval: xval, yval: yval} + return $translate.instant("BACKLOG.CHART.REAL", ctx) else if flotItem.seriesIndex == 3 - return "Incremented points by team requirements for sprint #{xval} is #{Math.abs(yval)}" - + ctx = {xval: xval, yval: Math.abs(yval)} + return $translate.instant("BACKLOG.CHART.INCREMENT_TEAM", ctx) else - return "Incremented points by client requirements for sprint #{xval} is #{Math.abs(yval)}" + ctx = {xval: xval, yval: Math.abs(yval)} + return $translate.instant("BACKLOG.CHART.INCREMENT_CLIENT", ctx) } } @@ -965,8 +996,7 @@ tgBacklogGraphDirective = -> return {link: link} - -module.directive("tgGmBacklogGraph", tgBacklogGraphDirective) +module.directive("tgBurndownBacklogGraph", ["$translate", BurndownBacklogGraphDirective]) ############################################################################# diff --git a/app/coffee/modules/backlog/sortable.coffee b/app/coffee/modules/backlog/sortable.coffee index 3d9415c0..48d9eea2 100644 --- a/app/coffee/modules/backlog/sortable.coffee +++ b/app/coffee/modules/backlog/sortable.coffee @@ -39,7 +39,7 @@ deleteElement = (el) -> el.off() el.remove() -BacklogSortableDirective = ($repo, $rs, $rootscope, $tgConfirm) -> +BacklogSortableDirective = ($repo, $rs, $rootscope, $tgConfirm, $translate) -> # Notes about jquery bug: # http://stackoverflow.com/questions/5791886/jquery-draggable-shows- # helper-in-wrong-place-when-scrolled-down-page @@ -54,7 +54,7 @@ BacklogSortableDirective = ($repo, $rs, $rootscope, $tgConfirm) -> return filterError = -> - text = "You can't drop on backlog when filters are open" + text = $translate.instant("BACKLOG.SORTABLE_FILTER_ERROR") $tgConfirm.notify("error", text) $el.sortable({ @@ -215,6 +215,7 @@ module.directive("tgBacklogSortable", [ "$tgResources", "$rootScope", "$tgConfirm", + "$translate", BacklogSortableDirective ]) diff --git a/app/coffee/modules/backlog/sprints.coffee b/app/coffee/modules/backlog/sprints.coffee index 98419c65..09127a7d 100644 --- a/app/coffee/modules/backlog/sprints.coffee +++ b/app/coffee/modules/backlog/sprints.coffee @@ -85,10 +85,12 @@ module.directive("tgBacklogSprint", ["$tgRepo", "$rootScope", BacklogSprintDirec ## Sprint Header Directive ############################################################################# -BacklogSprintHeaderDirective = ($navUrls, $template) -> - template = $template.get("backlog/sprint-header.html", true) +BacklogSprintHeaderDirective = ($navUrls, $template, $compile, $translate) -> + template = $template.get("backlog/sprint-header.html") link = ($scope, $el, $attrs, $model) -> + prettyDate = $translate.instant("BACKLOG.SPRINTS.DATE") + isEditable = -> return $scope.project.my_permissions.indexOf("modify_milestone") != -1 @@ -99,8 +101,8 @@ BacklogSprintHeaderDirective = ($navUrls, $template) -> taskboardUrl = $navUrls.resolve("project-taskboard", {project: $scope.project.slug, sprint: sprint.slug}) - start = moment(sprint.estimated_start).format("DD MMM YYYY") - finish = moment(sprint.estimated_finish).format("DD MMM YYYY") + start = moment(sprint.estimated_start).format(prettyDate) + finish = moment(sprint.estimated_finish).format(prettyDate) estimatedDateRange = "#{start}-#{finish}" ctx = { @@ -112,8 +114,13 @@ BacklogSprintHeaderDirective = ($navUrls, $template) -> isVisible: isVisible() isEditable: isEditable() } - $el.html(template(ctx)) + templateScope = $scope.$new() + + _.assign(templateScope, ctx) + + compiledTemplate = $compile(template)(templateScope) + $el.html(compiledTemplate) $scope.$watch $attrs.ngModel, (sprint) -> render(sprint) @@ -130,13 +137,15 @@ BacklogSprintHeaderDirective = ($navUrls, $template) -> require: "ngModel" } -module.directive("tgBacklogSprintHeader", ["$tgNavUrls", "$tgTemplate", BacklogSprintHeaderDirective]) +module.directive("tgBacklogSprintHeader", ["$tgNavUrls", "$tgTemplate", "$compile", "$translate" + BacklogSprintHeaderDirective]) + ############################################################################# ## Toggle Closed Sprints Directive ############################################################################# -ToggleExcludeClosedSprintsVisualization = ($rootscope, $loading) -> +ToggleExcludeClosedSprintsVisualization = ($rootscope, $loading, $translate) -> excludeClosedSprints = true link = ($scope, $el, $attrs) -> @@ -162,14 +171,16 @@ ToggleExcludeClosedSprintsVisualization = ($rootscope, $loading) -> $scope.$on "closed-sprints:reloaded", (ctx, sprints) => $loading.finish(loadingElm) - #TODO: i18n if sprints.length > 0 - text = "Hide closed sprints" + key = "BACKLOG.SPRINTS.ACTION_HIDE_CLOSED_SPRINTS" else - text = "Show closed sprints" + key = "BACKLOG.SPRINTS.ACTION_SHOW_CLOSED_SPRINTS" + + text = $translate.instant(key) $el.find(".text").text(text) return {link: link} -module.directive("tgBacklogToggleClosedSprintsVisualization", ["$rootScope", "$tgLoading", ToggleExcludeClosedSprintsVisualization]) +module.directive("tgBacklogToggleClosedSprintsVisualization", ["$rootScope", "$tgLoading", "$translate", + ToggleExcludeClosedSprintsVisualization]) diff --git a/app/coffee/modules/base.coffee b/app/coffee/modules/base.coffee index 8c762e77..8bdf9917 100644 --- a/app/coffee/modules/base.coffee +++ b/app/coffee/modules/base.coffee @@ -23,7 +23,7 @@ taiga = @.taiga groupBy = @.taiga.groupBy bindOnce = @.taiga.bindOnce -module = angular.module("taigaBase", ["taigaLocales"]) +module = angular.module("taigaBase", []) ############################################################################# ## Main Directive diff --git a/app/coffee/modules/base/http.coffee b/app/coffee/modules/base/http.coffee index f76ed280..ddf2c7a9 100644 --- a/app/coffee/modules/base/http.coffee +++ b/app/coffee/modules/base/http.coffee @@ -22,16 +22,25 @@ taiga = @.taiga class HttpService extends taiga.Service - @.$inject = ["$http", "$q", "$tgStorage"] + @.$inject = ["$http", "$q", "$tgStorage", "$rootScope"] + + constructor: (@http, @q, @storage, @rootScope) -> + super() headers: -> + headers = {} + + # Authorization token = @storage.get('token') if token - return {"Authorization":"Bearer #{token}"} - return {} + headers["Authorization"] = "Bearer #{token}" - constructor: (@http, @q, @storage) -> - super() + # Accept-Language + lang = @rootScope.user?.lang + if lang + headers["Accept-Language"] = lang + + return headers request: (options) -> options.headers = _.merge({}, options.headers or {}, @.headers()) diff --git a/app/coffee/modules/base/i18n.coffee b/app/coffee/modules/base/i18n.coffee deleted file mode 100644 index 6097cf6b..00000000 --- a/app/coffee/modules/base/i18n.coffee +++ /dev/null @@ -1,74 +0,0 @@ -### -# Copyright (C) 2014 Andrey Antukh -# Copyright (C) 2014 Jesús Espino Garcia -# Copyright (C) 2014 David Barragán Merino -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as -# published by the Free Software Foundation, either version 3 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 Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . -# -# File: modules/base/i18n.coffee -### - -taiga = @.taiga -bindOnce = @.taiga.bindOnce - -defaults = { - ns: "app" - fallbackLng: "en" - async: false - lng: "en" -} - -class I18nService extends taiga.Service - constructor: (@rootscope, localesEn) -> - @.options = _.clone(defaults, true) - @.options.resStore = { - en: { app: localesEn } - } - - setLanguage: (language) -> - i18n.setLng(language) - @rootscope.currentLang = language - @rootscope.$broadcast("i18n:changeLang", language) - - initialize: -> - i18n.init(@.options) - @rootscope.t = i18n.t - - t: (path, opts) -> - return i18n.t(path, opts) - - -I18nDirective = ($rootscope, $i18n) -> - link = ($scope, $el, $attrs) -> - values = $attrs.tr.split(",") - options = $attrs.trOpts or '{}' - opts = $scope.$eval(options) - - for v in values - if v.indexOf(":") == -1 - $el.html(_.escape($i18n.t(v, opts))) - else - [ns, v] = v.split(":") - $el.attr(ns, _.escape($i18n.t(v, opts))) - - return { - link: link - restrict: "A" - scope: false - } - - -module = angular.module("taigaBase") -module.service("$tgI18n", ["$rootScope", "localesEn", I18nService]) -module.directive("tr", ["$rootScope", "$tgI18n", I18nDirective]) diff --git a/app/coffee/modules/common/attachments.coffee b/app/coffee/modules/common/attachments.coffee index 1327dd98..343635a1 100644 --- a/app/coffee/modules/common/attachments.coffee +++ b/app/coffee/modules/common/attachments.coffee @@ -28,9 +28,9 @@ module = angular.module("taigaCommon") class AttachmentsController extends taiga.Controller - @.$inject = ["$scope", "$rootScope", "$tgRepo", "$tgResources", "$tgConfirm", "$q"] + @.$inject = ["$scope", "$rootScope", "$tgRepo", "$tgResources", "$tgConfirm", "$q", "$translate"] - constructor: (@scope, @rootscope, @repo, @rs, @confirm, @q) -> + constructor: (@scope, @rootscope, @repo, @rs, @confirm, @q, @translate) -> bindMethods(@) @.type = null @.objectId = null @@ -75,10 +75,13 @@ class AttachmentsController extends taiga.Controller promise = promise.then null, (data) => @scope.$emit("attachments:size-error") if data.status == 413 + index = @.uploadingAttachments.indexOf(attachment) @.uploadingAttachments.splice(index, 1) - @confirm.notify("error", "We have not been able to upload '#{attachment.name}'. - #{data.data._error_message}") + + message = @translate.instant("ATTACHMENT.ERROR_UPLOAD_ATTACHMENT", { + fileName: attachment.name, errorMessage: data.data._error_message}) + @confirm.notify("error", message) return @q.reject(data) return promise @@ -130,8 +133,8 @@ class AttachmentsController extends taiga.Controller # Remove one concrete attachment. removeAttachment: (attachment) -> - title = "Delete attachment" #TODO: i18in - message = "the attachment '#{attachment.name}'" #TODO: i18in + title = @translate.instant("ATTACHMENT.TITLE_LIGHTBOX_DELETE_ATTACHMENT") + message = @translate.instant("ATTACHMENT.MSG_LIGHTBOX_DELETE_ATTACHMENT", {fileName: attachment.name}) return @confirm.askOnDelete(title, message).then (finish) => onSuccess = => @@ -143,7 +146,8 @@ class AttachmentsController extends taiga.Controller onError = => finish(false) - @confirm.notify("error", null, "We have not been able to delete #{message}.") + message = @translate.instant("ATTACHMENT.ERROR_DELETE_ATTACHMENT", {errorMessage: message}) + @confirm.notify("error", null, message) return @q.reject() return @repo.remove(attachment).then(onSuccess, onError) @@ -155,7 +159,7 @@ class AttachmentsController extends taiga.Controller return not item.is_deprecated -AttachmentsDirective = ($config, $confirm, $templates) -> +AttachmentsDirective = ($config, $confirm, $templates, $translate) -> template = $templates.get("attachment/attachments.html", true) link = ($scope, $el, $attrs, $ctrls) -> @@ -220,8 +224,7 @@ AttachmentsDirective = ($config, $confirm, $templates) -> templateFn = ($el, $attrs) -> maxFileSize = $config.get("maxUploadFileSize", null) maxFileSize = sizeFormat(maxFileSize) if maxFileSize - maxFileSizeMsg = if maxFileSize then "Maximum upload size is #{maxFileSize}" else "" # TODO: i18n - + maxFileSizeMsg = if maxFileSize then $translate.instant("ATTACHMENT.MAX_UPLOAD_SIZE", {maxFileSize: maxFileSize}) else "" ctx = { type: $attrs.type maxFileSize: maxFileSize @@ -239,10 +242,10 @@ AttachmentsDirective = ($config, $confirm, $templates) -> template: templateFn } -module.directive("tgAttachments", ["$tgConfig", "$tgConfirm", "$tgTemplate", AttachmentsDirective]) +module.directive("tgAttachments", ["$tgConfig", "$tgConfirm", "$tgTemplate", "$translate", AttachmentsDirective]) -AttachmentDirective = ($template) -> +AttachmentDirective = ($template, $compile, $translate) -> template = $template.get("attachment/attachment.html", true) templateEdit = $template.get("attachment/attachment-edit.html", true) @@ -254,7 +257,9 @@ AttachmentDirective = ($template) -> ctx = { id: attachment.id name: attachment.name - created_date: moment(attachment.created_date).format("DD MMM YYYY [at] hh:mm") #TODO: i18n + title : $translate.instant("ATTACHMENT.TITLE", { + fileName: attachment.name, + date: moment(attachment.created_date).format($translate.instant("ATTACHMENT.DATE"))}) url: attachment.url size: sizeFormat(attachment.size) description: attachment.description @@ -263,9 +268,9 @@ AttachmentDirective = ($template) -> } if edit - html = templateEdit(ctx) + html = $compile(templateEdit(ctx))($scope) else - html = template(ctx) + html = $compile(template(ctx))($scope) $el.html(html) @@ -322,4 +327,4 @@ AttachmentDirective = ($template) -> restrict: "AE" } -module.directive("tgAttachment", ["$tgTemplate", AttachmentDirective]) +module.directive("tgAttachment", ["$tgTemplate", "$compile", "$translate", AttachmentDirective]) diff --git a/app/coffee/modules/common/components.coffee b/app/coffee/modules/common/components.coffee index dd902037..cbd96abc 100644 --- a/app/coffee/modules/common/components.coffee +++ b/app/coffee/modules/common/components.coffee @@ -29,10 +29,11 @@ module = angular.module("taigaCommon") ## Date Range Directive (used mainly for sprint date range) ############################################################################# -DateRangeDirective = -> +DateRangeDirective = ($translate) -> renderRange = ($el, first, second) -> - initDate = moment(first).format("DD MMM YYYY") - endDate = moment(second).format("DD MMM YYYY") + prettyDate = $translate.instant("BACKLOG.SPRINTS.DATE") + initDate = moment(first).format(prettyDate) + endDate = moment(second).format(prettyDate) $el.html("#{initDate}-#{endDate}") link = ($scope, $el, $attrs) -> @@ -44,34 +45,75 @@ DateRangeDirective = -> return {link:link} -module.directive("tgDateRange", DateRangeDirective) +module.directive("tgDateRange", ["$translate", DateRangeDirective]) ############################################################################# ## Date Selector Directive (using pikaday) ############################################################################# -DateSelectorDirective =-> +DateSelectorDirective = ($rootscope, $translate) -> link = ($scope, $el, $attrs, $model) -> selectedDate = null - $el.picker = new Pikaday({ - field: $el[0] - format: "DD MMM YYYY" - onSelect: (date) => - selectedDate = date - onOpen: => - $el.picker.setDate(selectedDate) if selectedDate? - }) + + initialize = () -> + $el.picker = new Pikaday({ + field: $el[0] + onSelect: (date) => + selectedDate = date + onOpen: => + $el.picker.setDate(selectedDate) if selectedDate? + i18n: { + previousMonth: $translate.instant("COMMON.PICKERDATE.PREV_MONTH"), + nextMonth: $translate.instant("COMMON.PICKERDATE.NEXT_MONTH"), + months: [$translate.instant("COMMON.PICKERDATE.MONTHS.JAN"), + $translate.instant("COMMON.PICKERDATE.MONTHS.FEB"), + $translate.instant("COMMON.PICKERDATE.MONTHS.MAR"), + $translate.instant("COMMON.PICKERDATE.MONTHS.APR"), + $translate.instant("COMMON.PICKERDATE.MONTHS.MAY"), + $translate.instant("COMMON.PICKERDATE.MONTHS.JUN"), + $translate.instant("COMMON.PICKERDATE.MONTHS.JUL"), + $translate.instant("COMMON.PICKERDATE.MONTHS.AUG"), + $translate.instant("COMMON.PICKERDATE.MONTHS.SEP"), + $translate.instant("COMMON.PICKERDATE.MONTHS.OCT"), + $translate.instant("COMMON.PICKERDATE.MONTHS.NOV"), + $translate.instant("COMMON.PICKERDATE.MONTHS.DEC")], + weekdays: [$translate.instant("COMMON.PICKERDATE.WEEK_DAYS.SUN"), + $translate.instant("COMMON.PICKERDATE.WEEK_DAYS.MON"), + $translate.instant("COMMON.PICKERDATE.WEEK_DAYS.TUE"), + $translate.instant("COMMON.PICKERDATE.WEEK_DAYS.WED"), + $translate.instant("COMMON.PICKERDATE.WEEK_DAYS.THU"), + $translate.instant("COMMON.PICKERDATE.WEEK_DAYS.FRI"), + $translate.instant("COMMON.PICKERDATE.WEEK_DAYS.SAT")], + weekdaysShort: [$translate.instant("COMMON.PICKERDATE.WEEK_DAYS_SHORT.SUN"), + $translate.instant("COMMON.PICKERDATE.WEEK_DAYS_SHORT.MON"), + $translate.instant("COMMON.PICKERDATE.WEEK_DAYS_SHORT.TUE"), + $translate.instant("COMMON.PICKERDATE.WEEK_DAYS_SHORT.WED"), + $translate.instant("COMMON.PICKERDATE.WEEK_DAYS_SHORT.THU"), + $translate.instant("COMMON.PICKERDATE.WEEK_DAYS_SHORT.FRI"), + $translate.instant("COMMON.PICKERDATE.WEEK_DAYS_SHORT.SAT")] + }, + isRTL: $translate.instant("COMMON.PICKERDATE.IS_RTL") == "true", + firstDay: parseInt($translate.instant("COMMON.PICKERDATE.FIRST_DAY_OF_WEEK"), 10), + format: $translate.instant("COMMON.PICKERDATE.FORMAT") + }) + + unbind = $rootscope.$on "$translateChangeEnd", (ctx) => initialize() $scope.$watch $attrs.ngModel, (val) -> + initialize() if val? and not $el.picker $el.picker.setDate(val) if val? + $scope.$on "$destroy", -> + $el.off() + unbind() + return { link: link require: "ngModel" } -module.directive("tgDateSelector", DateSelectorDirective) +module.directive("tgDateSelector", ["$rootScope", "$translate", DateSelectorDirective]) ############################################################################# @@ -98,6 +140,9 @@ SprintProgressBarDirective = -> renderProgress($el, percentage, visual_percentage) + $scope.$on "$destroy", -> + $el.off() + return {link: link} module.directive("tgSprintProgressbar", SprintProgressBarDirective) @@ -107,7 +152,7 @@ module.directive("tgSprintProgressbar", SprintProgressBarDirective) ## Created-by display directive ############################################################################# -CreatedByDisplayDirective = ($template)-> +CreatedByDisplayDirective = ($template, $compile, $translate)-> # Display the owner information (full name and photo) and the date of # creation of an object (like USs, tasks and issues). # @@ -119,18 +164,22 @@ CreatedByDisplayDirective = ($template)-> # 'owner'(ng-model) # - scope.usersById object is required. - template = $template.get("common/components/created-by.html", true) # TODO: i18n + template = $template.get("common/components/created-by.html", true) link = ($scope, $el, $attrs) -> render = (model) -> owner = $scope.usersById?[model.owner] or { - full_name_display: "external user" + full_name_display: $translate.instant("COMMON.EXTERNAL_USER") photo: "/images/unnamed.png" } + html = template({ owner: owner - date: moment(model.created_date).format("DD MMM YYYY HH:mm") + date: moment(model.created_date).format($translate.instant("COMMON.DATETIME")) }) + + html = $compile(html)($scope) + $el.html(html) bindOnce $scope, $attrs.ngModel, (model) -> @@ -145,18 +194,16 @@ CreatedByDisplayDirective = ($template)-> require: "ngModel" } -module.directive("tgCreatedByDisplay", ["$tgTemplate", CreatedByDisplayDirective]) +module.directive("tgCreatedByDisplay", ["$tgTemplate", "$compile", "$translate", CreatedByDisplayDirective]) ############################################################################# ## Watchers directive ############################################################################# -WatchersDirective = ($rootscope, $confirm, $repo, $qqueue, $template) -> +WatchersDirective = ($rootscope, $confirm, $repo, $qqueue, $template, $compile, $translate) -> # You have to include a div with the tg-lb-watchers directive in the page # where use this directive - # - # TODO: i18n template = $template.get("common/components/watchers.html", true) link = ($scope, $el, $attrs, $model) -> @@ -200,7 +247,7 @@ WatchersDirective = ($rootscope, $confirm, $repo, $qqueue, $template) -> isEditable: isEditable() } - html = template(ctx) + html = $compile(template(ctx))($scope) $el.html(html) if isEditable() and watchers.length == 0 @@ -213,7 +260,7 @@ WatchersDirective = ($rootscope, $confirm, $repo, $qqueue, $template) -> target = angular.element(event.currentTarget) watcherId = target.data("watcher-id") - title = "Delete watcher" + title = $translate.instant("COMMON.WATCHERS.TITLE_LIGHTBOX_DELETE_WARTCHER") message = $scope.usersById[watcherId].full_name_display $confirm.askOnDelete(title, message).then (finish) => @@ -247,18 +294,17 @@ WatchersDirective = ($rootscope, $confirm, $repo, $qqueue, $template) -> return {link:link, require:"ngModel"} -module.directive("tgWatchers", ["$rootScope", "$tgConfirm", "$tgRepo", "$tgQqueue", "$tgTemplate", WatchersDirective]) +module.directive("tgWatchers", ["$rootScope", "$tgConfirm", "$tgRepo", "$tgQqueue", "$tgTemplate", "$compile", + "$translate", WatchersDirective]) ############################################################################# ## Assigned to directive ############################################################################# -AssignedToDirective = ($rootscope, $confirm, $repo, $loading, $qqueue, $template) -> +AssignedToDirective = ($rootscope, $confirm, $repo, $loading, $qqueue, $template, $translate, $compile) -> # You have to include a div with the tg-lb-assignedto directive in the page # where use this directive - # - # TODO: i18n template = $template.get("common/components/assigned-to.html", true) link = ($scope, $el, $attrs, $model) -> @@ -291,7 +337,7 @@ AssignedToDirective = ($rootscope, $confirm, $repo, $loading, $qqueue, $template assignedTo: assignedTo isEditable: isEditable() } - html = template(ctx) + html = $compile(template(ctx))($scope) $el.html(html) $el.on "click", ".user-assigned", (event) -> @@ -303,7 +349,7 @@ AssignedToDirective = ($rootscope, $confirm, $repo, $loading, $qqueue, $template $el.on "click", ".icon-delete", (event) -> event.preventDefault() return if not isEditable() - title = "Are you sure you want to leave it unassigned?" # TODO: i18n + title = $translate.instant("COMMON.ASSIGNED_TO.CONFIRM_UNASSIGNED") $confirm.ask(title).then (finish) => finish() @@ -326,7 +372,8 @@ AssignedToDirective = ($rootscope, $confirm, $repo, $loading, $qqueue, $template require:"ngModel" } -module.directive("tgAssignedTo", ["$rootScope", "$tgConfirm", "$tgRepo", "$tgLoading", "$tgQqueue", "$tgTemplate", AssignedToDirective]) +module.directive("tgAssignedTo", ["$rootScope", "$tgConfirm", "$tgRepo", "$tgLoading", "$tgQqueue", "$tgTemplate", "$translate", "$compile", + AssignedToDirective]) ############################################################################# @@ -392,7 +439,7 @@ DeleteButtonDirective = ($log, $repo, $confirm, $location, $template) -> return $log.error "DeleteButtonDirective requires on-delete-title set in scope." $el.on "click", ".button", (event) -> - title = $scope.$eval($attrs.onDeleteTitle) + title = $attrs.onDeleteTitle subtitle = $model.$modelValue.subject $confirm.askOnDelete(title, subtitle).then (finish) => @@ -471,7 +518,6 @@ EditableSubjectDirective = ($rootscope, $repo, $confirm, $loading, $qqueue, $tem $el.find('div.edit-subject').hide() $el.find('div.view-subject span.edit').hide() - $scope.$watch $attrs.ngModel, (value) -> return if not value $scope.item = value @@ -490,7 +536,8 @@ EditableSubjectDirective = ($rootscope, $repo, $confirm, $loading, $qqueue, $tem template: template } -module.directive("tgEditableSubject", ["$rootScope", "$tgRepo", "$tgConfirm", "$tgLoading", "$tgQqueue", "$tgTemplate", EditableSubjectDirective]) +module.directive("tgEditableSubject", ["$rootScope", "$tgRepo", "$tgConfirm", "$tgLoading", "$tgQqueue", + "$tgTemplate", EditableSubjectDirective]) ############################################################################# @@ -498,9 +545,9 @@ module.directive("tgEditableSubject", ["$rootScope", "$tgRepo", "$tgConfirm", "$ ############################################################################# EditableDescriptionDirective = ($rootscope, $repo, $confirm, $compile, $loading, $selectedText, $qqueue, $template) -> - template = $template.get("common/components/editable-description.html") # TODO: i18n - noDescriptionMegEditMode = $template.get("common/components/editable-description-msg-edit-mode.html") # TODO: i18n - noDescriptionMegReadMode = $template.get("common/components/editable-description-msg-read-mode.html") # TODO: i18n + template = $template.get("common/components/editable-description.html") + noDescriptionMegEditMode = $template.get("common/components/editable-description-msg-edit-mode.html") + noDescriptionMegReadMode = $template.get("common/components/editable-description-msg-read-mode.html") link = ($scope, $el, $attrs, $model) -> $el.find('.edit-description').hide() @@ -555,9 +602,9 @@ EditableDescriptionDirective = ($rootscope, $repo, $confirm, $compile, $loading, if isEditable() $el.find('.view-description .edit').show() $el.find('.view-description .us-content').addClass('editable') - $scope.noDescriptionMsg = noDescriptionMegEditMode + $scope.noDescriptionMsg = $compile(noDescriptionMegEditMode)($scope) else - $scope.noDescriptionMsg = noDescriptionMegReadMode + $scope.noDescriptionMsg = $compile(noDescriptionMegReadMode)($scope) $scope.$on "$destroy", -> $el.off() @@ -569,8 +616,8 @@ EditableDescriptionDirective = ($rootscope, $repo, $confirm, $compile, $loading, template: template } -module.directive("tgEditableDescription", ["$rootScope", "$tgRepo", "$tgConfirm", - "$compile", "$tgLoading", "$selectedText", "$tgQqueue", "$tgTemplate", EditableDescriptionDirective]) +module.directive("tgEditableDescription", ["$rootScope", "$tgRepo", "$tgConfirm", "$compile", "$tgLoading", + "$selectedText", "$tgQqueue", "$tgTemplate", EditableDescriptionDirective]) ############################################################################# @@ -580,14 +627,16 @@ module.directive("tgEditableDescription", ["$rootScope", "$tgRepo", "$tgConfirm" ## completely bindonce, they only serves for visualization of data. ############################################################################# -ListItemIssueStatusDirective = -> +ListItemUsStatusDirective = -> link = ($scope, $el, $attrs) -> - issue = $scope.$eval($attrs.tgListitemIssueStatus) - bindOnce $scope, "issueStatusById", (issueStatusById) -> - $el.html(issueStatusById[issue.status].name) + us = $scope.$eval($attrs.tgListitemUsStatus) + bindOnce $scope, "usStatusById", (usStatusById) -> + $el.html(usStatusById[us.status].name) return {link:link} +module.directive("tgListitemUsStatus", ListItemUsStatusDirective) + ListItemTaskStatusDirective = -> link = ($scope, $el, $attrs) -> @@ -597,14 +646,7 @@ ListItemTaskStatusDirective = -> return {link:link} - -ListItemUsStatusDirective = -> - link = ($scope, $el, $attrs) -> - us = $scope.$eval($attrs.tgListitemUsStatus) - bindOnce $scope, "usStatusById", (usStatusById) -> - $el.html(usStatusById[us.status].name) - - return {link:link} +module.directive("tgListitemTaskStatus", ListItemTaskStatusDirective) ListItemAssignedtoDirective = ($template) -> @@ -626,6 +668,41 @@ ListItemAssignedtoDirective = ($template) -> module.directive("tgListitemAssignedto", ["$tgTemplate", ListItemAssignedtoDirective]) + +ListItemIssueStatusDirective = -> + link = ($scope, $el, $attrs) -> + issue = $scope.$eval($attrs.tgListitemIssueStatus) + bindOnce $scope, "issueStatusById", (issueStatusById) -> + $el.html(issueStatusById[issue.status].name) + + return {link:link} + +module.directive("tgListitemIssueStatus", ListItemIssueStatusDirective) + + +ListItemTypeDirective = -> + link = ($scope, $el, $attrs) -> + render = (issueTypeById, issue) -> + type = issueTypeById[issue.type] + domNode = $el.find(".level") + domNode.css("background-color", type.color) + domNode.attr("title", type.name) + + bindOnce $scope, "issueTypeById", (issueTypeById) -> + issue = $scope.$eval($attrs.tgListitemType) + render(issueTypeById, issue) + + $scope.$watch $attrs.tgListitemType, (issue) -> + render($scope.issueTypeById, issue) + + return { + link: link + templateUrl: "common/components/level.html" + } + +module.directive("tgListitemType", ListItemTypeDirective) + + ListItemPriorityDirective = -> link = ($scope, $el, $attrs) -> render = (priorityById, issue) -> @@ -648,6 +725,7 @@ ListItemPriorityDirective = -> module.directive("tgListitemPriority", ListItemPriorityDirective) + ListItemSeverityDirective = -> link = ($scope, $el, $attrs) -> render = (severityById, issue) -> @@ -668,26 +746,7 @@ ListItemSeverityDirective = -> templateUrl: "common/components/level.html" } - -ListItemTypeDirective = -> - link = ($scope, $el, $attrs) -> - render = (issueTypeById, issue) -> - type = issueTypeById[issue.type] - domNode = $el.find(".level") - domNode.css("background-color", type.color) - domNode.attr("title", type.name) - - bindOnce $scope, "issueTypeById", (issueTypeById) -> - issue = $scope.$eval($attrs.tgListitemType) - render(issueTypeById, issue) - - $scope.$watch $attrs.tgListitemType, (issue) -> - render($scope.issueTypeById, issue) - - return { - link: link - templateUrl: "common/components/level.html" - } +module.directive("tgListitemSeverity", ListItemSeverityDirective) ############################################################################# @@ -715,35 +774,27 @@ TgProgressBarDirective = ($template) -> module.directive("tgProgressBar", ["$tgTemplate", TgProgressBarDirective]) + ############################################################################# ## Main title directive ############################################################################# -TgMainTitleDirective = ($template) -> - template = $template.get("common/components/main-title.html", true) - - render = (el, projectName, sectionName) -> - el.html(template({ - projectName: projectName - sectionName: sectionName - })) +TgMainTitleDirective = ($translate) -> link = ($scope, $el, $attrs) -> - element = angular.element($el) - $scope.$watch "project", (project) -> - render($el, project.name, $scope.sectionName) if project - - $scope.$on "project:loaded", (ctx, project) => - render($el, project.name, $scope.sectionName) + $attrs.$observe "i18nSectionName", (i18nSectionName) -> + trans = $translate(i18nSectionName) + trans.then (sectionName) -> $scope.sectionName = sectionName + trans.catch (sectionName) -> $scope.sectionName = sectionName $scope.$on "$destroy", -> $el.off() - return {link: link} + return { + link: link + templateUrl: "common/components/main-title.html" + scope: { + projectName : "=projectName" + } + } -module.directive("tgMainTitle", ["$tgTemplate", TgMainTitleDirective]) - -module.directive("tgListitemType", ListItemTypeDirective) -module.directive("tgListitemIssueStatus", ListItemIssueStatusDirective) -module.directive("tgListitemSeverity", ListItemSeverityDirective) -module.directive("tgListitemTaskStatus", ListItemTaskStatusDirective) -module.directive("tgListitemUsStatus", ListItemUsStatusDirective) +module.directive("tgMainTitle", ["$translate", TgMainTitleDirective]) diff --git a/app/coffee/modules/common/confirm.coffee b/app/coffee/modules/common/confirm.coffee index 039fc89a..fd877c4b 100644 --- a/app/coffee/modules/common/confirm.coffee +++ b/app/coffee/modules/common/confirm.coffee @@ -27,21 +27,21 @@ bindMethods = @.taiga.bindMethods NOTIFICATION_MSG = { "success": - title: "Everything is ok" - message: "Our Oompa Loompas saved all your changes!" + title: "NOTIFICATION.OK" + message: "NOTIFICATION.SAVED" "error": - title: "Oops, something happened..." - message: "Our Oompa Loompas are sad, your changes were not saved!" + title: "NOTIFICATION.WARNING" + message: "NOTIFICATION.WARNING_TEXT" "light-error": - title: "Oops, something happened..." - message: "Our Oompa Loompas are sad, your changes were not saved!" + title: "NOTIFICATION.WARNING" + message: "NOTIFICATION.WARNING_TEXT" } class ConfirmService extends taiga.Service - @.$inject = ["$q", "lightboxService", "$tgLoading"] + @.$inject = ["$q", "lightboxService", "$tgLoading", "$translate"] - constructor: (@q, @lightboxService, @loading) -> + constructor: (@q, @lightboxService, @loading, @translate) -> bindMethods(@) hide: (el)-> @@ -51,6 +51,8 @@ class ConfirmService extends taiga.Service el.off(".confirm-dialog") ask: (title, subtitle, message, lightboxSelector=".lightbox-generic-ask") -> + defered = @q.defer() + el = angular.element(lightboxSelector) # Render content @@ -58,8 +60,6 @@ class ConfirmService extends taiga.Service el.find("span.subtitle").html(subtitle) el.find("span.message").html(message) - defered = @q.defer() - # Assign event handlers el.on "click.confirm-dialog", "a.button-green", debounce 2000, (event) => event.preventDefault() @@ -80,9 +80,11 @@ class ConfirmService extends taiga.Service return defered.promise askOnDelete: (title, message) -> - return @.ask(title, "Are you sure you want to delete?", message) #TODO: i18n + return @.ask(title, @translate.instant("NOTIFICATION.ASK_DELETE"), message) askChoice: (title, subtitle, choices, replacement, warning, lightboxSelector=".lightbox-ask-choice") -> + defered = @q.defer() + el = angular.element(lightboxSelector) # Render content @@ -103,7 +105,6 @@ class ConfirmService extends taiga.Service choicesField.html('') _.each choices, (value, key) -> choicesField.append(angular.element("")) - defered = @q.defer() # Assign event handlers el.on "click.confirm-dialog", "a.button-green", debounce 2000, (event) => @@ -127,11 +128,12 @@ class ConfirmService extends taiga.Service return defered.promise error: (message) -> + defered = @q.defer() + el = angular.element(".lightbox-generic-error") # Render content el.find("h2.title").html(message) - defered = @q.defer() # Assign event handlers el.on "click.confirm-dialog", "a.button-green", (event) => @@ -149,12 +151,13 @@ class ConfirmService extends taiga.Service return defered.promise success: (title, message) -> + defered = @q.defer() + el = angular.element(".lightbox-generic-success") # Render content el.find("h2.title").html(title) if title el.find("p.message").html(message) if message - defered = @q.defer() # Assign event handlers el.on "click.confirm-dialog", "a.button-green", (event) => @@ -208,12 +211,12 @@ class ConfirmService extends taiga.Service if title el.find("h4").html(title) else - el.find("h4").html(NOTIFICATION_MSG[type].title) + el.find("h4").html(@translate.instant(NOTIFICATION_MSG[type].title)) if message el.find("p").html(message) else - el.find("p").html(NOTIFICATION_MSG[type].message) + el.find("p").html(@translate.instant(NOTIFICATION_MSG[type].message)) body = angular.element("body") body.find(".notification-message .notification-light") diff --git a/app/coffee/modules/common/custom-field-values.coffee b/app/coffee/modules/common/custom-field-values.coffee index c827afb8..8203d59f 100644 --- a/app/coffee/modules/common/custom-field-values.coffee +++ b/app/coffee/modules/common/custom-field-values.coffee @@ -121,7 +121,7 @@ CustomAttributesValuesDirective = ($templates, $storage) -> module.directive("tgCustomAttributesValues", ["$tgTemplate", "$tgStorage", CustomAttributesValuesDirective]) -CustomAttributeValueDirective = ($template, $selectedText) -> +CustomAttributeValueDirective = ($template, $selectedText, $compile) -> template = $template.get("custom-attributes/custom-attribute-value.html", true) templateEdit = $template.get("custom-attributes/custom-attribute-value-edit.html", true) @@ -139,8 +139,10 @@ CustomAttributeValueDirective = ($template, $selectedText) -> if editable and (edit or not value) html = templateEdit(ctx) + html = $compile(html)($scope) else html = template(ctx) + html = $compile(html)($scope) $el.html(html) @@ -168,11 +170,13 @@ CustomAttributeValueDirective = ($template, $selectedText) -> return if $selectedText.get().length render(attributeValue, true) $el.find("input[name='description']").focus().select() + $scope.$apply() $el.on "click", "a.icon-edit", (event) -> event.preventDefault() render(attributeValue, true) $el.find("input[name='description']").focus().select() + $scope.$apply() ## Actions (on edit mode) submit = debounce 2000, (event) => @@ -195,4 +199,4 @@ CustomAttributeValueDirective = ($template, $selectedText) -> restrict: "AE" } -module.directive("tgCustomAttributeValue", ["$tgTemplate", "$selectedText", CustomAttributeValueDirective]) +module.directive("tgCustomAttributeValue", ["$tgTemplate", "$selectedText", "$compile", CustomAttributeValueDirective]) diff --git a/app/coffee/modules/common/estimation.coffee b/app/coffee/modules/common/estimation.coffee index 3a5f4a83..18348762 100644 --- a/app/coffee/modules/common/estimation.coffee +++ b/app/coffee/modules/common/estimation.coffee @@ -28,7 +28,7 @@ module = angular.module("taigaCommon") ## User story estimation directive (for Lightboxes) ############################################################################# -LbUsEstimationDirective = ($tgEstimationsService, $rootScope, $repo, $confirm, $template) -> +LbUsEstimationDirective = ($tgEstimationsService, $rootScope, $repo, $confirm, $template, $compile) -> # Display the points of a US and you can edit it. # # Example: @@ -56,6 +56,7 @@ LbUsEstimationDirective = ($tgEstimationsService, $rootScope, $repo, $confirm, $ mainTemplate = "common/estimation/us-estimation-points-per-role.html" template = $template.get(mainTemplate, true) html = template(ctx) + html = $compile(html)($scope) @$el.html(html) estimationProcess.render() @@ -68,14 +69,14 @@ LbUsEstimationDirective = ($tgEstimationsService, $rootScope, $repo, $confirm, $ require: "ngModel" } -module.directive("tgLbUsEstimation", ["$tgEstimationsService", "$rootScope", "$tgRepo", "$tgConfirm", "$tgTemplate", LbUsEstimationDirective]) +module.directive("tgLbUsEstimation", ["$tgEstimationsService", "$rootScope", "$tgRepo", "$tgConfirm", "$tgTemplate", "$compile", LbUsEstimationDirective]) ############################################################################# ## User story estimation directive ############################################################################# -UsEstimationDirective = ($tgEstimationsService, $rootScope, $repo, $confirm, $qqueue, $template) -> +UsEstimationDirective = ($tgEstimationsService, $rootScope, $repo, $confirm, $qqueue, $template, $compile) -> # Display the points of a US and you can edit it. # # Example: @@ -102,6 +103,7 @@ UsEstimationDirective = ($tgEstimationsService, $rootScope, $repo, $confirm, $qq mainTemplate = "common/estimation/us-estimation-points-per-role.html" template = $template.get(mainTemplate, true) html = template(ctx) + html = $compile(html)($scope) @$el.html(html) estimationProcess.render() @@ -115,7 +117,7 @@ UsEstimationDirective = ($tgEstimationsService, $rootScope, $repo, $confirm, $qq require: "ngModel" } -module.directive("tgUsEstimation", ["$tgEstimationsService", "$rootScope", "$tgRepo", "$tgConfirm", "$tgQqueue", "$tgTemplate", +module.directive("tgUsEstimation", ["$tgEstimationsService", "$rootScope", "$tgRepo", "$tgConfirm", "$tgQqueue", "$tgTemplate", "$compile" UsEstimationDirective]) diff --git a/app/coffee/modules/common/filters.coffee b/app/coffee/modules/common/filters.coffee index e9559306..27647dd6 100644 --- a/app/coffee/modules/common/filters.coffee +++ b/app/coffee/modules/common/filters.coffee @@ -33,15 +33,14 @@ defaultFilter = -> module.filter("default", defaultFilter) -yesNoFilter = -> - #TODO: i18n +yesNoFilter = ($translate) -> return (value) -> if value - return "Yes" + return $translate.instant("COMMON.YES") - return "No" + return $translate.instant("COMMON.NO") -module.filter("yesNo", yesNoFilter) +module.filter("yesNo", ["$translate", yesNoFilter]) unslugify = -> diff --git a/app/coffee/modules/common/history.coffee b/app/coffee/modules/common/history.coffee index c7ab11d5..4dff84db 100644 --- a/app/coffee/modules/common/history.coffee +++ b/app/coffee/modules/common/history.coffee @@ -68,7 +68,7 @@ class HistoryController extends taiga.Controller return @rs.history.undeleteComment(type, objectId, activityId).then => @.loadHistory(type, objectId) -HistoryDirective = ($log, $loading, $qqueue, $template, $confirm) -> +HistoryDirective = ($log, $loading, $qqueue, $template, $confirm, $translate, $compile) -> templateChangeDiff = $template.get("common/history/history-change-diff.html", true) templateChangePoints = $template.get("common/history/history-change-points.html", true) templateChangeGeneric = $template.get("common/history/history-change-generic.html", true) @@ -87,6 +87,9 @@ HistoryDirective = ($log, $loading, $qqueue, $template, $confirm) -> showAllComments = false showAllActivity = false + getPrettyDateFormat = -> + return $translate.instant("ACTIVITY.DATETIME") + bindOnce $scope, $attrs.ngModel, (model) -> type = $attrs.type objectId = model.id @@ -97,24 +100,40 @@ HistoryDirective = ($log, $loading, $qqueue, $template, $confirm) -> # Helpers getHumanizedFieldName = (field) -> humanizedFieldNames = { - # US - assigned_to: "assigned to" - is_closed: "is closed" - finish_date: "finish date" - client_requirement: "client requirement" - team_requirement: "team requirement" + subject : $translate.instant("ACTIVITY.FIELDS.SUBJECT") + name: $translate.instant("ACTIVITY.FIELDS.NAME") + description : $translate.instant("ACTIVITY.FIELDS.DESCRIPTION") + content: $translate.instant("ACTIVITY.FIELDS.CONTENT") + status: $translate.instant("ACTIVITY.FIELDS.STATUS") + is_closed : $translate.instant("ACTIVITY.FIELDS.IS_CLOSED") + finish_date : $translate.instant("ACTIVITY.FIELDS.FINISH_DATE") + type: $translate.instant("ACTIVITY.FIELDS.TYPE") + priority: $translate.instant("ACTIVITY.FIELDS.PRIORITY") + severity: $translate.instant("ACTIVITY.FIELDS.SEVERITY") + assigned_to : $translate.instant("ACTIVITY.FIELDS.ASSIGNED_TO") + watchers : $translate.instant("ACTIVITY.FIELDS.WATCHERS") + milestone : $translate.instant("ACTIVITY.FIELDS.MILESTONE") + user_story: $translate.instant("ACTIVITY.FIELDS.USER_STORY") + project: $translate.instant("ACTIVITY.FIELDS.PROJECT") + is_blocked: $translate.instant("ACTIVITY.FIELDS.IS_BLOCKED") + blocked_note: $translate.instant("ACTIVITY.FIELDS.BLOCKED_NOTE") + points: $translate.instant("ACTIVITY.FIELDS.POINTS") + client_requirement : $translate.instant("ACTIVITY.FIELDS.CLIENT_REQUIREMENT") + team_requirement : $translate.instant("ACTIVITY.FIELDS.TEAM_REQUIREMENT") + is_iocaine: $translate.instant("ACTIVITY.FIELDS.IS_IOCAINE") + tags: $translate.instant("ACTIVITY.FIELDS.TAGS") + attachments : $translate.instant("ACTIVITY.FIELDS.ATTACHMENTS") + is_deprecated: $translate.instant("ACTIVITY.FIELDS.IS_DEPRECATED") + blocked_note: $translate.instant("ACTIVITY.FIELDS.BLOCKED_NOTE") + is_blocked: $translate.instant("ACTIVITY.FIELDS.IS_BLOCKED") + order: $translate.instant("ACTIVITY.FIELDS.ORDER") + backlog_order: $translate.instant("ACTIVITY.FIELDS.BACKLOG_ORDER") + sprint_order: $translate.instant("ACTIVITY.FIELDS.SPRINT_ORDER") + kanban_order: $translate.instant("ACTIVITY.FIELDS.KANBAN_ORDER") + taskboard_order: $translate.instant("ACTIVITY.FIELDS.TASKBOARD_ORDER") + us_order: $translate.instant("ACTIVITY.FIELDS.US_ORDER") + } - # Task - milestone: "sprint" - user_story: "user story" - is_iocaine: "is iocaine" - - # Attachment - is_deprecated: "is deprecated" - - blocked_note: "blocked note" - is_blocked: "is blocked" - } # TODO i18n return humanizedFieldNames[field] or field getUserFullName = (userId) -> @@ -132,17 +151,17 @@ HistoryDirective = ($log, $loading, $qqueue, $template, $confirm) -> formatChange = (change) -> if _.isArray(change) if change.length == 0 - return "empty" + return $translate.instant("ACTIVITY.VALUES.EMPTY") return change.join(", ") if change == "" - return "empty" + return $translate.instant("ACTIVITY.VALUES.EMPTY") if not change? or change == false - return "no" + return $translate.instant("ACTIVITY.VALUES.NO") if change == true - return "yes" + return $translate.instant("ACTIVITY.VALUES.YES") return change @@ -152,22 +171,26 @@ HistoryDirective = ($log, $loading, $qqueue, $template, $confirm) -> attachments = _.map value, (changes, type) -> if type == "new" return _.map changes, (change) -> - # TODO: i18n - return templateChangeDiff({name: "new attachment", diff: change.filename}) + return templateChangeDiff({ + name: $translate.instant("ACTIVITY.NEW_ATTACHMENT"), + diff: change.filename + }) else if type == "deleted" return _.map changes, (change) -> - # TODO: i18n - return templateChangeDiff({name: "deleted attachment", diff: change.filename}) + return templateChangeDiff({ + name: $translate.instant("ACTIVITY.DELETED_ATTACHMENT"), + diff: change.filename + }) else return _.map changes, (change) -> - # TODO: i18n - name = "updated attachment #{change.filename}" + name = $translate.instant("ACTIVITY.UPDATED_ATTACHMENT", {filename: change.filename}) + diff = _.map change.changes, (values, name) -> return { name: getHumanizedFieldName(name) from: formatChange(values[0]) to: formatChange(values[1]) - } + } return templateChangeAttachment({name: name, diff: diff}) @@ -177,16 +200,19 @@ HistoryDirective = ($log, $loading, $qqueue, $template, $confirm) -> customAttributes = _.map value, (changes, type) -> if type == "new" return _.map changes, (change) -> - return templateChangeGeneric({ + html = templateChangeGeneric({ name: change.name, from: formatChange(""), to: formatChange(change.value) }) + + html = $compile(html)($scope) + + return html[0].outerHTML else if type == "deleted" return _.map changes, (change) -> - # TODO: i18n return templateChangeDiff({ - name: "deleted custom attribute", + name: $translate.instant("ACTIVITY.DELETED_CUSTOM_ATTRIBUTE") diff: change.name }) else @@ -207,7 +233,11 @@ HistoryDirective = ($log, $loading, $qqueue, $template, $confirm) -> else if field == "blocked_note" return templateChangeDiff({name: getHumanizedFieldName("blocked_note"), diff: value[1]}) else if field == "points" - return templateChangePoints({points: value}) + html = templateChangePoints({points: value}) + + html = $compile(html)($scope) + + return html[0].outerHTML else if field == "attachments" return renderAttachmentEntry(value) else if field == "custom_attributes" @@ -216,11 +246,15 @@ HistoryDirective = ($log, $loading, $qqueue, $template, $confirm) -> name = getHumanizedFieldName(field) removed = _.difference(value[0], value[1]) added = _.difference(value[1], value[0]) - return templateChangeList({name:name, removed:removed, added: added}) + html = templateChangeList({name:name, removed:removed, added: added}) + + html = $compile(html)($scope) + + return html[0].outerHTML else if field == "assigned_to" name = getHumanizedFieldName(field) - from = formatChange(value[0] or "Unassigned") - to = formatChange(value[1] or "Unassigned") + from = formatChange(value[0] or $translate.instant("ACTIVITY.VALUES.UNASSIGNED")) + to = formatChange(value[1] or $translate.instant("ACTIVITY.VALUES.UNASSIGNED")) return templateChangeGeneric({name:name, from:from, to: to}) else name = getHumanizedFieldName(field) @@ -233,44 +267,51 @@ HistoryDirective = ($log, $loading, $qqueue, $template, $confirm) -> renderChangesHelperText = (change) -> size = countChanges(change) - if size == 1 - return "Made #{size} change" # TODO: i18n - return "Made #{size} changes" # TODO: i18n + return $translate.instant("ACTIVITY.SIZE_CHANGE", {size: size}, 'messageformat') renderComment = (comment) -> if (comment.delete_comment_date or comment.delete_comment_user?.name) - return templateDeletedComment({ - deleteCommentDate: moment(comment.delete_comment_date).format("DD MMM YYYY HH:mm") if comment.delete_comment_date + html = templateDeletedComment({ + deleteCommentDate: moment(comment.delete_comment_date).format(getPrettyDateFormat()) if comment.delete_comment_date deleteCommentUser: comment.delete_comment_user.name deleteComment: comment.comment_html activityId: comment.id - canRestoreComment: comment.delete_comment_user.pk == $scope.user.id or $scope.project.my_permissions.indexOf("modify_project") > -1 + canRestoreComment: (comment.delete_comment_user.pk == $scope.user.id or + $scope.project.my_permissions.indexOf("modify_project") > -1) }) - return templateActivity({ + html = $compile(html)($scope) + + return html[0].outerHTML + + html = templateActivity({ avatar: getUserAvatar(comment.user.pk) userFullName: comment.user.name - creationDate: moment(comment.created_at).format("DD MMM YYYY HH:mm") + creationDate: moment(comment.created_at).format(getPrettyDateFormat()) comment: comment.comment_html changesText: renderChangesHelperText(comment) changes: renderChangeEntries(comment) mode: "comment" - deleteCommentDate: moment(comment.delete_comment_date).format("DD MMM YYYY HH:mm") if comment.delete_comment_date + deleteCommentDate: moment(comment.delete_comment_date).format(getPrettyDateFormat()) if comment.delete_comment_date deleteCommentUser: comment.delete_comment_user.name if comment.delete_comment_user?.name activityId: comment.id canDeleteComment: comment.user.pk == $scope.user?.id or $scope.project.my_permissions.indexOf("modify_project") > -1 }) + html = $compile(html)($scope) + + return html[0].outerHTML + renderChange = (change) -> return templateActivity({ avatar: getUserAvatar(change.user.pk) userFullName: change.user.name - creationDate: moment(change.created_at).format("DD MMM YYYY HH:mm") + creationDate: moment(change.created_at).format(getPrettyDateFormat()) comment: change.comment_html changes: renderChangeEntries(change) changesText: "" mode: "activity" - deleteCommentDate: moment(change.delete_comment_date).format("DD MMM YYYY HH:mm") if change.delete_comment_date + deleteCommentDate: moment(change.delete_comment_date).format(getPrettyDateFormat()) if change.delete_comment_date deleteCommentUser: change.delete_comment_user.name if change.delete_comment_user?.name activityId: change.id }) @@ -281,7 +322,9 @@ HistoryDirective = ($log, $loading, $qqueue, $template, $confirm) -> else showMore = totalEntries - entries.length - return templateBaseEntries({entries: entries, showMore:showMore}) + html = templateBaseEntries({entries: entries, showMore:showMore}) + html = $compile(html)($scope) + return html # Render into DOM (operations with dom mutability) @@ -394,7 +437,9 @@ HistoryDirective = ($log, $loading, $qqueue, $template, $confirm) -> $el.off() templateFn = ($el, $attrs) -> - return templateBase({ngmodel: $attrs.ngModel, type: $attrs.type, mode: $attrs.mode}) + html = templateBase({ngmodel: $attrs.ngModel, type: $attrs.type, mode: $attrs.mode}) + + return html return { controller: HistoryController @@ -405,4 +450,5 @@ HistoryDirective = ($log, $loading, $qqueue, $template, $confirm) -> } -module.directive("tgHistory", ["$log", "$tgLoading", "$tgQqueue", "$tgTemplate", "$tgConfirm", HistoryDirective]) +module.directive("tgHistory", ["$log", "$tgLoading", "$tgQqueue", "$tgTemplate", "$tgConfirm", "$translate", + "$compile", HistoryDirective]) diff --git a/app/coffee/modules/common/importer.coffee b/app/coffee/modules/common/importer.coffee index e1bdbd96..4027bf25 100644 --- a/app/coffee/modules/common/importer.coffee +++ b/app/coffee/modules/common/importer.coffee @@ -22,7 +22,7 @@ module = angular.module("taigaCommon") -ImportProjectButtonDirective = ($rs, $confirm, $location, $navUrls) -> +ImportProjectButtonDirective = ($rs, $confirm, $location, $navUrls, $translate) -> link = ($scope, $el, $attrs) -> $el.on "click", ".import-project-button", (event) -> event.preventDefault() @@ -34,34 +34,29 @@ ImportProjectButtonDirective = ($rs, $confirm, $location, $navUrls) -> file = event.target.files[0] return if not file - loader = $confirm.loader("Uploading dump file") + loader = $confirm.loader($translate.instant("PROJECT.IMPORT.UPLOADING_FILE")) onSuccess = (result) -> loader.stop() if result.status == 202 # Async mode - title = "Our Oompa Loompas are importing your project" # TODO: i18n - message = "This process could take a few minutes
We will send you - an email when ready" # TODO: i18n + title = $translate.instant("PROJECT.IMPORT.ASYNC_IN_PROGRESS_TITLE") + message = $translate.instant("PROJECT.IMPORT.ASYNC_IN_PROGRESS_MESSAGE") $confirm.success(title, message) else # result.status == 201 # Sync mode ctx = {project: result.data.slug} $location.path($navUrls.resolve("project-admin-project-profile-details", ctx)) - $confirm.notify("success", "Your project has been imported successfuly.") # TODO: i18n + msg = $translate.instant("PROJECT.IMPORT.SYNC_SUCCESS") + $confirm.notify("success", msg) onError = (result) -> loader.stop() - console.log "Error", result - errorMsg = "Our oompa loompas have some problems importing your dump data. - Please try again. " # TODO: i18n + errorMsg = $translate.instant("PROJECT.IMPORT.ERROR") if result.status == 429 # TOO MANY REQUESTS - errorMsg = "Sorry, our oompa loompas are very busy right now. - Please try again in a few minutes. " # TODO: i18n + errorMsg = $translate.instant("PROJECT.IMPORT.ERROR_TOO_MANY_REQUEST") else if result.data?._error_message - errorMsg = "Our oompa loompas have some problems importing your dump data: - #{result.data._error_message}" # TODO: i18n - + errorMsg = $translate.instant("PROJECT.IMPORT.ERROR_MESSAGE", {error_message: result.data._error_message}) $confirm.notify("error", errorMsg) loader.start() @@ -69,5 +64,5 @@ ImportProjectButtonDirective = ($rs, $confirm, $location, $navUrls) -> return {link: link} -module.directive("tgImportProjectButton", ["$tgResources", "$tgConfirm", "$location", "$tgNavUrls", +module.directive("tgImportProjectButton", ["$tgResources", "$tgConfirm", "$location", "$tgNavUrls", "$translate", ImportProjectButtonDirective]) diff --git a/app/coffee/modules/common/lightboxes.coffee b/app/coffee/modules/common/lightboxes.coffee index f270837d..f4d089e9 100644 --- a/app/coffee/modules/common/lightboxes.coffee +++ b/app/coffee/modules/common/lightboxes.coffee @@ -86,7 +86,10 @@ class LightboxKeyboardNavigationService extends taiga.Service # Key: enter if code == 13 - activeElement.trigger("click") + if $el.find(".watcher-single").length == 1 + $el.find('.watcher-single:first').trigger("click") + else + activeElement.trigger("click") # Key: down else if code == 40 @@ -143,9 +146,10 @@ module.directive("lightbox", ["lightboxService", LightboxDirective]) # Issue/Userstory blocking message lightbox directive. -BlockLightboxDirective = ($rootscope, $tgrepo, $confirm, lightboxService, $loading, $qqueue) -> +BlockLightboxDirective = ($rootscope, $tgrepo, $confirm, lightboxService, $loading, $qqueue, $translate) -> link = ($scope, $el, $attrs, $model) -> - $el.find("h2.title").text($attrs.title) + $translate($attrs.title).then (title) -> + $el.find("h2.title").text(title) unblock = $qqueue.bindAdd (item, finishCallback) => promise = $tgrepo.save(item) @@ -213,14 +217,14 @@ BlockLightboxDirective = ($rootscope, $tgrepo, $confirm, lightboxService, $loadi require: "ngModel" } -module.directive("tgLbBlock", ["$rootScope", "$tgRepo", "$tgConfirm", "lightboxService", "$tgLoading", "$tgQqueue", BlockLightboxDirective]) +module.directive("tgLbBlock", ["$rootScope", "$tgRepo", "$tgConfirm", "lightboxService", "$tgLoading", "$tgQqueue", "$translate", BlockLightboxDirective]) ############################################################################# ## Generic Lightbox Blocking-Message Input Directive ############################################################################# -BlockingMessageInputDirective = ($log, $template) -> +BlockingMessageInputDirective = ($log, $template, $compile) -> template = $template.get("common/lightbox/lightbox-blocking-message-input.html", true) link = ($scope, $el, $attrs, $model) -> @@ -243,14 +247,14 @@ BlockingMessageInputDirective = ($log, $template) -> restrict: "EA" } -module.directive("tgBlockingMessageInput", ["$log", "$tgTemplate", BlockingMessageInputDirective]) +module.directive("tgBlockingMessageInput", ["$log", "$tgTemplate", "$compile", BlockingMessageInputDirective]) ############################################################################# ## Create/Edit Userstory Lightbox Directive ############################################################################# -CreateEditUserstoryDirective = ($repo, $model, $rs, $rootScope, lightboxService, $loading) -> +CreateEditUserstoryDirective = ($repo, $model, $rs, $rootScope, lightboxService, $loading, $translate) -> link = ($scope, $el, attrs) -> $scope.isNew = true @@ -267,8 +271,8 @@ CreateEditUserstoryDirective = ($repo, $model, $rs, $rootScope, lightboxService, }) # Update texts for creation - $el.find(".button-green").html("Create") #TODO: i18n - $el.find(".title").html("New user story ") #TODO: i18n + $el.find(".button-green").html($translate.instant("COMMON.CREATE")) + $el.find(".title").html($translate.instant("LIGHTBOX.CREATE_EDIT_US.NEW_US")) $el.find(".tag-input").val("") $el.find(".blocked-note").addClass("hidden") @@ -283,8 +287,8 @@ CreateEditUserstoryDirective = ($repo, $model, $rs, $rootScope, lightboxService, $scope.isNew = false # Update texts for edition - $el.find(".button-green").html("Save") #TODO: i18n - $el.find(".title").html("Edit user story ") #TODO: i18n + $el.find(".button-green").html($translate.instant("COMMON.SAVE")) + $el.find(".title").html($translate.instant("LIGHTBOX.CREATE_EDIT_US.EDIT_US")) $el.find(".tag-input").val("") # Update requirement info (team, client or blocked) @@ -362,6 +366,7 @@ module.directive("tgLbCreateEditUserstory", [ "$rootScope", "lightboxService", "$tgLoading", + "$translate", CreateEditUserstoryDirective ]) @@ -424,7 +429,7 @@ module.directive("tgLbCreateBulkUserstories", [ ## AssignedTo Lightbox Directive ############################################################################# -AssignedToLightboxDirective = (lightboxService, lightboxKeyboardNavigationService, $template) -> +AssignedToLightboxDirective = (lightboxService, lightboxKeyboardNavigationService, $template, $compile) -> link = ($scope, $el, $attrs) -> selectedUser = null selectedItem = null @@ -458,6 +463,9 @@ AssignedToLightboxDirective = (lightboxService, lightboxKeyboardNavigationServic } html = usersTemplate(ctx) + + html = $compile(html)($scope) + $el.find("div.watchers").html(html) lightboxKeyboardNavigationService.init($el) @@ -517,7 +525,7 @@ AssignedToLightboxDirective = (lightboxService, lightboxKeyboardNavigationServic } -module.directive("tgLbAssignedto", ["lightboxService", "lightboxKeyboardNavigationService", "$tgTemplate", AssignedToLightboxDirective]) +module.directive("tgLbAssignedto", ["lightboxService", "lightboxKeyboardNavigationService", "$tgTemplate", "$compile", AssignedToLightboxDirective]) ############################################################################# @@ -554,6 +562,7 @@ WatchersLightboxDirective = ($repo, lightboxService, lightboxKeyboardNavigationS html = usersTemplate(ctx) $el.find("div.watchers").html(html) + lightboxKeyboardNavigationService.init($el) closeLightbox = () -> lightboxKeyboardNavigationService.stop() diff --git a/app/coffee/modules/common/tags.coffee b/app/coffee/modules/common/tags.coffee index 5707c490..e915fd84 100644 --- a/app/coffee/modules/common/tags.coffee +++ b/app/coffee/modules/common/tags.coffee @@ -99,7 +99,7 @@ module.directive("tgColorizeTags", ColorizeTagsDirective) ## TagLine Directive (for Lightboxes) ############################################################################# -LbTagLineDirective = ($rs, $template) -> +LbTagLineDirective = ($rs, $template, $compile) -> ENTER_KEY = 13 COMMA_KEY = 188 @@ -116,7 +116,7 @@ LbTagLineDirective = ($rs, $template) -> if tag.color tag.style = "border-left: 5px solid #{tag.color}" - html = templateTags(ctx) + html = $compile(templateTags(ctx))($scope) $el.find("div.tags-container").html(html) showSaveButton = -> $el.find(".save").removeClass("hidden") @@ -221,14 +221,14 @@ LbTagLineDirective = ($rs, $template) -> templateUrl: "common/tag/lb-tag-line.html" } -module.directive("tgLbTagLine", ["$tgResources", "$tgTemplate", LbTagLineDirective]) +module.directive("tgLbTagLine", ["$tgResources", "$tgTemplate", "$compile", LbTagLineDirective]) ############################################################################# ## TagLine Directive (for detail pages) ############################################################################# -TagLineDirective = ($rootScope, $repo, $rs, $confirm, $qqueue, $template) -> +TagLineDirective = ($rootScope, $repo, $rs, $confirm, $qqueue, $template, $compile) -> ENTER_KEY = 13 ESC_KEY = 27 COMMA_KEY = 188 @@ -237,7 +237,10 @@ TagLineDirective = ($rootScope, $repo, $rs, $confirm, $qqueue, $template) -> link = ($scope, $el, $attrs, $model) -> isEditable = -> - return $scope.project.my_permissions.indexOf($attrs.requiredPerm) != -1 + if $attrs.requiredPerm? + return $scope.project.my_permissions.indexOf($attrs.requiredPerm) != -1 + + return true ## Render renderTags = (tags, tagsColors) -> @@ -245,7 +248,7 @@ TagLineDirective = ($rootScope, $repo, $rs, $confirm, $qqueue, $template) -> tags: _.map(tags, (t) -> {name: t, color: tagsColors[t]}) isEditable: isEditable() } - html = templateTags(ctx) + html = $compile(templateTags(ctx))($scope) $el.find("div.tags-container").html(html) renderInReadModeOnly = -> @@ -362,7 +365,7 @@ TagLineDirective = ($rootScope, $repo, $rs, $confirm, $qqueue, $template) -> deleteValue(value) - bindOnce $scope, "project", (project) -> + bindOnce $scope, "project.tags_colors", (tags_colors) -> if not isEditable() renderInReadModeOnly() return @@ -376,7 +379,7 @@ TagLineDirective = ($rootScope, $repo, $rs, $confirm, $qqueue, $template) -> menu.css("left", position.left) $el.find("input").autocomplete({ - source: _.keys(project.tags_colors) + source: _.keys(tags_colors) position: { my: "left top", using: positioningFunction @@ -406,4 +409,5 @@ TagLineDirective = ($rootScope, $repo, $rs, $confirm, $qqueue, $template) -> templateUrl: "common/tag/tag-line.html" } -module.directive("tgTagLine", ["$rootScope", "$tgRepo", "$tgResources", "$tgConfirm", "$tgQqueue", "$tgTemplate", TagLineDirective]) +module.directive("tgTagLine", ["$rootScope", "$tgRepo", "$tgResources", "$tgConfirm", "$tgQqueue", + "$tgTemplate", "$compile", TagLineDirective]) diff --git a/app/coffee/modules/common/wisiwyg.coffee b/app/coffee/modules/common/wisiwyg.coffee index 1527ec01..37ade9d3 100644 --- a/app/coffee/modules/common/wisiwyg.coffee +++ b/app/coffee/modules/common/wisiwyg.coffee @@ -55,16 +55,13 @@ module = angular.module("taigaCommon") ############################################################################# ## WYSIWYG markitup editor directive ############################################################################# -tgMarkitupDirective = ($rootscope, $rs, $tr, $selectedText, $template) -> +MarkitupDirective = ($rootscope, $rs, $selectedText, $template, $compile, $translate) -> previewTemplate = $template.get("common/wysiwyg/wysiwyg-markitup-preview.html", true) link = ($scope, $el, $attrs, $model) -> element = angular.element($el) previewDomNode = $("
", {class: "preview"}) - #openHelp = -> - # window.open($rootscope.urls.wikiHelpUrl(), "_blank") - closePreviewMode = -> element.parents(".markdown").find(".preview").remove() element.parents(".markItUp").show() @@ -76,7 +73,10 @@ tgMarkitupDirective = ($rootscope, $rs, $tr, $selectedText, $template) -> markdownDomNode = element.parents(".markdown") markItUpDomNode = element.parents(".markItUp") $rs.mdrender.render($scope.projectId, $model.$modelValue).then (data) -> - markdownDomNode.append(previewTemplate({data: data.data})) + html = previewTemplate({data: data.data}) + html = $compile(html)($scope) + + markdownDomNode.append(html) markItUpDomNode.hide() markdown = element.closest(".markdown") @@ -130,168 +130,14 @@ tgMarkitupDirective = ($rootscope, $rs, $tr, $selectedText, $template) -> else return cursorPosition - markdownSettings = - nameSpace: "markdown" - onShiftEnter: {keepDefault:false, openWith:"\n\n"} - onEnter: - keepDefault: false, - replaceWith: () -> "\n" - afterInsert: (data) -> - lines = data.textarea.value.split("\n") - cursorLine = data.textarea.value[0..(data.caretPosition - 1)].split("\n").length - newLineContent = data.textarea.value[data.caretPosition..].split("\n")[0] - lastLine = lines[cursorLine - 1] - - # unordered list - - match = lastLine.match /^(\s*- ).*/ - - if match - emptyListItem = lastLine.match /^(\s*)\-\s$/ - - if emptyListItem - markdownCaretPositon = addLine(data.textarea, cursorLine - 1) - else - markdownCaretPositon = addLine(data.textarea, cursorLine, "#{match[1]}") - - # unordered list * - match = lastLine.match /^(\s*\* ).*/ - - if match - emptyListItem = lastLine.match /^(\s*\* )$/ - - if emptyListItem - markdownCaretPositon = addLine(data.textarea, cursorLine - 1) - else - markdownCaretPositon = addLine(data.textarea, cursorLine, "#{match[1]}") - - # ordered list - match = lastLine.match /^(\s*)(\d+)\.\s/ - - if match - emptyListItem = lastLine.match /^(\s*)(\d+)\.\s$/ - - if emptyListItem - markdownCaretPositon = addLine(data.textarea, cursorLine - 1) - else - markdownCaretPositon = addLine(data.textarea, cursorLine, "#{match[1] + (parseInt(match[2], 10) + 1)}. ") - - - setCaretPosition(data.textarea, markdownCaretPositon) if markdownCaretPositon - - markupSet: [ - { - name: $tr.t("markdown-editor.heading-1") - key: "1" - placeHolder: $tr.t("markdown-editor.placeholder") - closeWith: (markItUp) -> markdownTitle(markItUp, "=") - }, - { - name: $tr.t("markdown-editor.heading-2") - key: "2" - placeHolder: $tr.t("markdown-editor.placeholder") - closeWith: (markItUp) -> markdownTitle(markItUp, "-") - }, - { - name: $tr.t("markdown-editor.heading-3") - key: "3" - openWith: "### " - placeHolder: $tr.t("markdown-editor.placeholder") - }, - { - separator: "---------------" - }, - { - name: $tr.t("markdown-editor.bold") - key: "B" - openWith: "**" - closeWith: "**" - }, - { - name: $tr.t("markdown-editor.italic") - key: "I" - openWith: "_" - closeWith: "_" - }, - { - name: $tr.t("markdown-editor.strike") - key: "S" - openWith: "~~" - closeWith: "~~" - }, - { - separator: "---------------" - }, - { - name: $tr.t("markdown-editor.bulleted-list") - openWith: "- " - }, - { - name: $tr.t("markdown-editor.numeric-list") - openWith: (markItUp) -> markItUp.line+". " - }, - { - separator: "---------------" - }, - { - name: $tr.t("markdown-editor.picture") - key: "P" - replaceWith: '![[![Alternative text]!]](<<<[![Url:!:http://]!]>>> "[![Title]!]")' - beforeInsert:(markItUp) -> prepareUrlFormatting(markItUp) - afterInsert:(markItUp) -> urlFormatting(markItUp) - }, - { - name: $tr.t("markdown-editor.link") - key: "L" - openWith: "[" - closeWith: '](<<<[![Url:!:http://]!]>>> "[![Title]!]")' - placeHolder: $tr.t("markdown-editor.link-placeholder") - beforeInsert:(markItUp) -> prepareUrlFormatting(markItUp) - afterInsert:(markItUp) -> urlFormatting(markItUp) - }, - { - separator: "---------------" - }, - { - name: $tr.t("markdown-editor.quotes") - openWith: "> " - }, - { - name: $tr.t("markdown-editor.code-block") - openWith: "```\n" - closeWith: "\n```" - }, - { - separator: "---------------" - }, - { - name: $tr.t("markdown-editor.preview") - call: preview - className: "preview-icon" - }, - # { - # separator: "---------------" - # }, - # { - # name: $tr.t("markdown-editor.help") - # call: openHelp - # className: "help" - # } - ] - afterInsert: (event) -> - target = angular.element(event.textarea) - $model.$setViewValue(target.val()) - prepareUrlFormatting = (markItUp) -> - console.log(markItUp) regex = /(<<<|>>>)/gi result = 0 indices = [] (indices.push(result.index)) while ( (result = regex.exec(markItUp.textarea.value)) ) markItUp.donotparse = indices - console.log(indices) urlFormatting = (markItUp) -> - console.log(markItUp.donotparse) regex = /<< return "\n"+heading+"\n" - element.markItUp(markdownSettings) + renderMarkItUp = () -> + markdownSettings = + nameSpace: "markdown" + onShiftEnter: {keepDefault:false, openWith:"\n\n"} + onEnter: + keepDefault: false, + replaceWith: () -> "\n" + afterInsert: (data) -> + lines = data.textarea.value.split("\n") + cursorLine = data.textarea.value[0..(data.caretPosition - 1)].split("\n").length + newLineContent = data.textarea.value[data.caretPosition..].split("\n")[0] + lastLine = lines[cursorLine - 1] + + # unordered list - + match = lastLine.match /^(\s*- ).*/ + + if match + emptyListItem = lastLine.match /^(\s*)\-\s$/ + + if emptyListItem + nline = cursorLine - 1 + replace = null + else + nline = cursorLine + replace = "#{match[1]}" + + markdownCaretPositon = addLine(data.textarea, nline, replace) + + # unordered list * + match = lastLine.match /^(\s*\* ).*/ + + if match + emptyListItem = lastLine.match /^(\s*\* )$/ + + if emptyListItem + nline = cursorLine - 1 + replace = null + else + nline = cursorLine + replace = "#{match[1]}" + + markdownCaretPositon = addLine(data.textarea, nline, replace) + + # ordered list + match = lastLine.match /^(\s*)(\d+)\.\s/ + + if match + emptyListItem = lastLine.match /^(\s*)(\d+)\.\s$/ + + if emptyListItem + nline = cursorLine - 1 + replace = null + else + nline = cursorLine + replace = "#{match[1] + (parseInt(match[2], 10) + 1)}. " + + markdownCaretPositon = addLine(data.textarea, nline, replace) + + setCaretPosition(data.textarea, markdownCaretPositon) if markdownCaretPositon + + markupSet: [ + { + name: $translate.instant("COMMON.WYSIWYG.H1_BUTTON") + key: "1" + placeHolder: $translate.instant("COMMON.WYSIWYG.H1_SAMPLE_TEXT") + closeWith: (markItUp) -> markdownTitle(markItUp, "=") + }, + { + name: $translate.instant("COMMON.WYSIWYG.H2_BUTTON") + key: "2" + placeHolder: $translate.instant("COMMON.WYSIWYG.H2_SAMPLE_TEXT") + closeWith: (markItUp) -> markdownTitle(markItUp, "-") + }, + { + name: $translate.instant("COMMON.WYSIWYG.H3_BUTTON") + key: "3" + openWith: "### " + placeHolder: $translate.instant("COMMON.WYSIWYG.H3_SAMPLE_TEXT") + }, + { + separator: "---------------" + }, + { + name: $translate.instant("COMMON.WYSIWYG.BOLD_BUTTON") + key: "B" + openWith: "**" + closeWith: "**" + placeHolder: $translate.instant("COMMON.WYSIWYG.BOLD_BUTTON_SAMPLE_TEXT") + }, + { + name: $translate.instant("COMMON.WYSIWYG.ITALIC_SAMPLE_TEXT") + key: "I" + openWith: "_" + closeWith: "_" + placeHolder: $translate.instant("COMMON.WYSIWYG.ITALIC_SAMPLE_TEXT") + }, + { + name: $translate.instant("COMMON.WYSIWYG.STRIKE_BUTTON") + key: "S" + openWith: "~~" + closeWith: "~~" + placeHolder: $translate.instant("COMMON.WYSIWYG.STRIKE_SAMPLE_TEXT") + }, + { + separator: "---------------" + }, + { + name: $translate.instant("COMMON.WYSIWYG.BULLETED_LIST_BUTTON") + openWith: "- " + placeHolder: $translate.instant("COMMON.WYSIWYG.BULLETED_LIST_SAMPLE_TEXT") + }, + { + name: $translate.instant("COMMON.WYSIWYG.NUMERIC_LIST_BUTTON") + openWith: (markItUp) -> markItUp.line+". " + placeHolder: $translate.instant("COMMON.WYSIWYG.NUMERIC_LIST_SAMPLE_TEXT") + }, + { + separator: "---------------" + }, + { + name: $translate.instant("COMMON.WYSIWYG.PICTURE_BUTTON") + key: "P" + openWith: "![" + closeWith: '](<<<[![Url:!:http://]!]>>> "[![Title]!]")' + placeHolder: $translate.instant("COMMON.WYSIWYG.PICTURE_SAMPLE_TEXT") + beforeInsert:(markItUp) -> prepareUrlFormatting(markItUp) + afterInsert:(markItUp) -> urlFormatting(markItUp) + }, + { + name: $translate.instant("COMMON.WYSIWYG.LINK_BUTTON") + key: "L" + openWith: "[" + closeWith: '](<<<[![Url:!:http://]!]>>> "[![Title]!]")' + placeHolder: $translate.instant("COMMON.WYSIWYG.LINK_SAMPLE_TEXT") + beforeInsert:(markItUp) -> prepareUrlFormatting(markItUp) + afterInsert:(markItUp) -> urlFormatting(markItUp) + }, + { + separator: "---------------" + }, + { + name: $translate.instant("COMMON.WYSIWYG.QUOTE_BLOCK_BUTTON") + openWith: "> " + placeHolder: $translate.instant("COMMON.WYSIWYG.QUOTE_BLOCK_SAMPLE_TEXT") + }, + { + name: $translate.instant("COMMON.WYSIWYG.CODE_BLOCK_BUTTON") + openWith: "```\n" + placeHolder: $translate.instant("COMMON.WYSIWYG.CODE_BLOCK_SAMPLE_TEXT") + closeWith: "\n```" + }, + { + separator: "---------------" + }, + { + name: $translate.instant("COMMON.WYSIWYG.PREVIEW_BUTTON") + call: preview + className: "preview-icon" + }, + ] + afterInsert: (event) -> + target = angular.element(event.textarea) + $model.$setViewValue(target.val()) + + element + .markItUpRemove() + .markItUp(markdownSettings) + + renderMarkItUp() + + unbind = $rootscope.$on "$translateChangeEnd", renderMarkItUp + element.on "keypress", (event) -> $scope.$apply() $scope.$on "$destroy", -> $el.off() + unbind() return {link:link, require:"ngModel"} -module.directive("tgMarkitup", ["$rootScope", "$tgResources", "$tgI18n", "$selectedText", "$tgTemplate", tgMarkitupDirective]) +module.directive("tgMarkitup", ["$rootScope", "$tgResources", "$selectedText", "$tgTemplate", "$compile", + "$translate", MarkitupDirective]) diff --git a/app/coffee/modules/issues/detail.coffee b/app/coffee/modules/issues/detail.coffee index 7db1ecf4..db633dc2 100644 --- a/app/coffee/modules/issues/detail.coffee +++ b/app/coffee/modules/issues/detail.coffee @@ -47,13 +47,14 @@ class IssueDetailController extends mixOf(taiga.Controller, taiga.PageMixin) "$appTitle", "$tgAnalytics", "$tgNavUrls", + "$translate", "tgLoader" ] constructor: (@scope, @rootscope, @repo, @confirm, @rs, @params, @q, @location, - @log, @appTitle, @analytics, @navUrls, tgLoader) -> + @log, @appTitle, @analytics, @navUrls, @translate, tgLoader) -> @scope.issueRef = @params.issueref - @scope.sectionName = "Issue Details" + @scope.sectionName = @translate.instant("ISSUES.SECTION_NAME") @.initializeEventHandlers() promise = @.loadInitialData() @@ -145,7 +146,7 @@ module.controller("IssueDetailController", IssueDetailController) ## Issue status display directive ############################################################################# -IssueStatusDisplayDirective = ($template)-> +IssueStatusDisplayDirective = ($template, $compile)-> # Display if a Issue is open or closed and its issueboard status. # # Example: @@ -165,6 +166,9 @@ IssueStatusDisplayDirective = ($template)-> is_closed: status.is_closed status: status }) + + html = $compile(html)($scope) + $el.html(html) $scope.$watch $attrs.ngModel, (issue) -> @@ -179,14 +183,14 @@ IssueStatusDisplayDirective = ($template)-> require: "ngModel" } -module.directive("tgIssueStatusDisplay", ["$tgTemplate", IssueStatusDisplayDirective]) +module.directive("tgIssueStatusDisplay", ["$tgTemplate", "$compile", IssueStatusDisplayDirective]) ############################################################################# ## Issue status button directive ############################################################################# -IssueStatusButtonDirective = ($rootScope, $repo, $confirm, $loading, $qqueue, $template) -> +IssueStatusButtonDirective = ($rootScope, $repo, $confirm, $loading, $qqueue, $template, $compile) -> # Display the status of Issue and you can edit it. # # Example: @@ -211,6 +215,9 @@ IssueStatusButtonDirective = ($rootScope, $repo, $confirm, $loading, $qqueue, $t statuses: $scope.statusList editable: isEditable() }) + + html = $compile(html)($scope) + $el.html(html) save = $qqueue.bindAdd (statusId) => @@ -262,13 +269,13 @@ IssueStatusButtonDirective = ($rootScope, $repo, $confirm, $loading, $qqueue, $t require: "ngModel" } -module.directive("tgIssueStatusButton", ["$rootScope", "$tgRepo", "$tgConfirm", "$tgLoading", "$tgQqueue", "$tgTemplate", IssueStatusButtonDirective]) +module.directive("tgIssueStatusButton", ["$rootScope", "$tgRepo", "$tgConfirm", "$tgLoading", "$tgQqueue", "$tgTemplate", "$compile", IssueStatusButtonDirective]) ############################################################################# ## Issue type button directive ############################################################################# -IssueTypeButtonDirective = ($rootScope, $repo, $confirm, $loading, $qqueue, $template) -> +IssueTypeButtonDirective = ($rootScope, $repo, $confirm, $loading, $qqueue, $template, $compile) -> # Display the type of Issue and you can edit it. # # Example: @@ -293,6 +300,9 @@ IssueTypeButtonDirective = ($rootScope, $repo, $confirm, $loading, $qqueue, $tem typees: $scope.typeList editable: isEditable() }) + + html = $compile(html)($scope) + $el.html(html) save = $qqueue.bindAdd (type) => @@ -343,14 +353,14 @@ IssueTypeButtonDirective = ($rootScope, $repo, $confirm, $loading, $qqueue, $tem require: "ngModel" } -module.directive("tgIssueTypeButton", ["$rootScope", "$tgRepo", "$tgConfirm", "$tgLoading", "$tgQqueue", "$tgTemplate", IssueTypeButtonDirective]) +module.directive("tgIssueTypeButton", ["$rootScope", "$tgRepo", "$tgConfirm", "$tgLoading", "$tgQqueue", "$tgTemplate", "$compile", IssueTypeButtonDirective]) ############################################################################# ## Issue severity button directive ############################################################################# -IssueSeverityButtonDirective = ($rootScope, $repo, $confirm, $loading, $qqueue, $template) -> +IssueSeverityButtonDirective = ($rootScope, $repo, $confirm, $loading, $qqueue, $template, $compile) -> # Display the severity of Issue and you can edit it. # # Example: @@ -375,6 +385,9 @@ IssueSeverityButtonDirective = ($rootScope, $repo, $confirm, $loading, $qqueue, severityes: $scope.severityList editable: isEditable() }) + + html = $compile(html)($scope) + $el.html(html) save = $qqueue.bindAdd (severity) => @@ -427,14 +440,14 @@ IssueSeverityButtonDirective = ($rootScope, $repo, $confirm, $loading, $qqueue, require: "ngModel" } -module.directive("tgIssueSeverityButton", ["$rootScope", "$tgRepo", "$tgConfirm", "$tgLoading", "$tgQqueue", "$tgTemplate", IssueSeverityButtonDirective]) +module.directive("tgIssueSeverityButton", ["$rootScope", "$tgRepo", "$tgConfirm", "$tgLoading", "$tgQqueue", "$tgTemplate", "$compile", IssueSeverityButtonDirective]) ############################################################################# ## Issue priority button directive ############################################################################# -IssuePriorityButtonDirective = ($rootScope, $repo, $confirm, $loading, $qqueue, $template) -> +IssuePriorityButtonDirective = ($rootScope, $repo, $confirm, $loading, $qqueue, $template, $compile) -> # Display the priority of Issue and you can edit it. # # Example: @@ -459,6 +472,9 @@ IssuePriorityButtonDirective = ($rootScope, $repo, $confirm, $loading, $qqueue, priorityes: $scope.priorityList editable: isEditable() }) + + html = $compile(html)($scope) + $el.html(html) save = $qqueue.bindAdd (priority) => @@ -511,14 +527,14 @@ IssuePriorityButtonDirective = ($rootScope, $repo, $confirm, $loading, $qqueue, require: "ngModel" } -module.directive("tgIssuePriorityButton", ["$rootScope", "$tgRepo", "$tgConfirm", "$tgLoading", "$tgQqueue", "$tgTemplate", IssuePriorityButtonDirective]) +module.directive("tgIssuePriorityButton", ["$rootScope", "$tgRepo", "$tgConfirm", "$tgLoading", "$tgQqueue", "$tgTemplate", "$compile", IssuePriorityButtonDirective]) ############################################################################# ## Promote Issue to US button directive ############################################################################# -PromoteIssueToUsButtonDirective = ($rootScope, $repo, $confirm, $qqueue) -> +PromoteIssueToUsButtonDirective = ($rootScope, $repo, $confirm, $qqueue, $translate) -> link = ($scope, $el, $attrs, $model) -> save = $qqueue.bindAdd (issue, finish) => @@ -548,8 +564,8 @@ PromoteIssueToUsButtonDirective = ($rootScope, $repo, $confirm, $qqueue) -> event.preventDefault() issue = $model.$modelValue - title = "Promote this issue to a new user story" # TODO: i18n - message = "Are you sure you want to create a new US from this Issue?" # TODO: i18n + title = $translate.instant("ISSUES.CONFIRM_PROMOTE.TITLE") + message = $translate.instant("ISSUES.CONFIRM_PROMOTE.MESSAGE") subtitle = issue.subject $confirm.ask(title, subtitle, message).then (finish) => @@ -566,5 +582,5 @@ PromoteIssueToUsButtonDirective = ($rootScope, $repo, $confirm, $qqueue) -> link: link } -module.directive("tgPromoteIssueToUsButton", ["$rootScope", "$tgRepo", "$tgConfirm", "$tgQqueue", +module.directive("tgPromoteIssueToUsButton", ["$rootScope", "$tgRepo", "$tgConfirm", "$tgQqueue", "$translate" PromoteIssueToUsButtonDirective]) diff --git a/app/coffee/modules/issues/list.coffee b/app/coffee/modules/issues/list.coffee index 47944bc5..59ff2a0d 100644 --- a/app/coffee/modules/issues/list.coffee +++ b/app/coffee/modules/issues/list.coffee @@ -51,12 +51,14 @@ class IssuesController extends mixOf(taiga.Controller, taiga.PageMixin, taiga.Fi "$tgNavUrls", "$tgEvents", "$tgAnalytics", - "tgLoader" + "tgLoader", + "$translate" ] constructor: (@scope, @rootscope, @repo, @confirm, @rs, @urls, @params, @q, @location, @appTitle, - @navUrls, @events, @analytics, tgLoader) -> - @scope.sectionName = "Issues" + @navUrls, @events, @analytics, tgLoader, @translate) -> + + @scope.sectionName = @translate.instant("ISSUES.LIST_SECTION_NAME") @scope.filters = {} if _.isEmpty(@location.search()) @@ -310,7 +312,7 @@ module.controller("IssuesController", IssuesController) ## Issues Directive ############################################################################# -IssuesDirective = ($log, $location, $template) -> +IssuesDirective = ($log, $location, $template, $compile) -> ## Issues Pagination template = $template.get("issue/issue-paginator.html", true) @@ -360,7 +362,11 @@ IssuesDirective = ($log, $location, $template) -> else pages.push({classes: "page", num: i, type: "page"}) - $pagEl.html(template(options)) + + html = template(options) + html = $compile(html)($scope) + + $pagEl.html(html) $scope.$watch "issues", (value) -> # Do nothing if value is not logical true @@ -427,14 +433,14 @@ IssuesDirective = ($log, $location, $template) -> return {link:link} -module.directive("tgIssues", ["$log", "$tgLocation", "$tgTemplate", IssuesDirective]) +module.directive("tgIssues", ["$log", "$tgLocation", "$tgTemplate", "$compile", IssuesDirective]) ############################################################################# ## Issues Filters Directive ############################################################################# -IssuesFiltersDirective = ($log, $location, $rs, $confirm, $loading, $template) -> +IssuesFiltersDirective = ($log, $location, $rs, $confirm, $loading, $template, $translate, $compile) -> template = $template.get("issue/issues-filters.html", true) templateSelected = $template.get("issue/issues-filters-selected.html", true) @@ -468,6 +474,7 @@ IssuesFiltersDirective = ($log, $location, $rs, $confirm, $loading, $template) - f.style = "border-left: 3px solid #{f.color}" html = templateSelected({filters:selectedFilters}) + html = $compile(html)($scope) $el.find(".filters-applied").html(html) if selectedFilters.length > 0 @@ -481,6 +488,7 @@ IssuesFiltersDirective = ($log, $location, $rs, $confirm, $loading, $template) - f.style = "border-left: 3px solid #{f.color}" html = template({filters:filters}) + html = $compile(html)($scope) $el.find(".filter-list").html(html) toggleFilterSelection = (type, id) -> @@ -533,12 +541,13 @@ IssuesFiltersDirective = ($log, $location, $rs, $confirm, $loading, $template) - $scope.$on "filters:issueupdate", (ctx, filters) -> html = template({filters:filters.statuses}) + html = $compile(html)($scope) $el.find(".filter-list").html(html) selectQFilter = debounceLeading 100, (value) -> return if value is undefined - $ctrl.replaceFilter("page", null) + $ctrl.replaceFilter("page", null, true) if value.length == 0 $ctrl.replaceFilter("q", null) @@ -590,8 +599,8 @@ IssuesFiltersDirective = ($log, $location, $rs, $confirm, $loading, $template) - target = angular.element(event.currentTarget) customFilterName = target.parent().data('id') - title = "Delete custom filter" # TODO: i18n - message = "the custom filter '#{customFilterName}'" # TODO: i18n + title = $translate.instant("ISSUES.FILTERS.CONFIRM_DELETE.TITLE") + message = $translate.instant("ISSUES.FILTERS.CONFIRM_DELETE.MESSAGE", {customFilterName: customFilterName}) $confirm.askOnDelete(title, message).then (finish) -> promise = $ctrl.deleteMyFilter(customFilterName) @@ -615,6 +624,7 @@ IssuesFiltersDirective = ($log, $location, $rs, $confirm, $loading, $template) - $el.find('.save-filters').hide() $el.find('.my-filter-name').removeClass("hidden") $el.find('.my-filter-name').focus() + $scope.$apply() $el.on "keyup", ".my-filter-name", (event) -> event.preventDefault() @@ -652,8 +662,8 @@ IssuesFiltersDirective = ($log, $location, $rs, $confirm, $loading, $template) - return {link:link} -module.directive("tgIssuesFilters", ["$log", "$tgLocation", "$tgResources", "$tgConfirm", "$tgLoading", "$tgTemplate", - IssuesFiltersDirective]) +module.directive("tgIssuesFilters", ["$log", "$tgLocation", "$tgResources", "$tgConfirm", "$tgLoading", + "$tgTemplate", "$translate", "$compile", IssuesFiltersDirective]) ############################################################################# @@ -708,7 +718,28 @@ IssueStatusInlineEditionDirective = ($repo, $template, $rootscope) -> updateIssueStatus($el, issue, $scope.issueStatusById) $scope.$apply () -> - $repo.save(issue).then + $repo.save(issue).then -> + + for filter in $scope.filters.statuses + if filter.id == issue.status + filter.count++ + + $rootscope.$broadcast("filters:issueupdate", $scope.filters) + + filtering = false + + for filter in $scope.filters.statuses + if filter.selected == true + filtering = true + if filter.id == issue.status + return + + if not filtering + return + + for el, i in $scope.issues + if el and el.id == issue.id + $scope.issues.splice(i, 1) for filter in $scope.filters.statuses if filter.id == issue.status @@ -732,7 +763,8 @@ IssueStatusInlineEditionDirective = ($repo, $template, $rootscope) -> return {link: link} -module.directive("tgIssueStatusInlineEdition", ["$tgRepo", "$tgTemplate", "$rootScope", IssueStatusInlineEditionDirective]) +module.directive("tgIssueStatusInlineEdition", ["$tgRepo", "$tgTemplate", "$rootScope", + IssueStatusInlineEditionDirective]) ############################################################################# @@ -783,4 +815,5 @@ IssueAssignedToInlineEditionDirective = ($repo, $rootscope, popoverService) -> return {link: link} -module.directive("tgIssueAssignedToInlineEdition", ["$tgRepo", "$rootScope", IssueAssignedToInlineEditionDirective]) +module.directive("tgIssueAssignedToInlineEdition", ["$tgRepo", "$rootScope", + IssueAssignedToInlineEditionDirective]) diff --git a/app/coffee/modules/kanban/main.coffee b/app/coffee/modules/kanban/main.coffee index b56a46a7..6b45ea6b 100644 --- a/app/coffee/modules/kanban/main.coffee +++ b/app/coffee/modules/kanban/main.coffee @@ -62,15 +62,16 @@ class KanbanController extends mixOf(taiga.Controller, taiga.PageMixin, taiga.Fi "$tgNavUrls", "$tgEvents", "$tgAnalytics", - "tgLoader" + "tgLoader", + "$translate" ] constructor: (@scope, @rootscope, @repo, @confirm, @rs, @params, @q, @location, - @appTitle, @navUrls, @events, @analytics, tgLoader) -> + @appTitle, @navUrls, @events, @analytics, tgLoader, @translate) -> bindMethods(@) - @scope.sectionName = "Kanban" + @scope.sectionName = @translate.instant("KANBAN.SECTION_NAME") @scope.statusViewModes = {} @.initializeEventHandlers() @@ -307,10 +308,9 @@ module.directive("tgKanban", ["$tgRepo", "$rootScope", KanbanDirective]) ## Kanban Archived Status Column Header Control ############################################################################# -KanbanArchivedStatusHeaderDirective = ($rootscope) -> - #TODO: i18N - showArchivedText = "Show archived" - hideArchivedText = "Hide archived" +KanbanArchivedStatusHeaderDirective = ($rootscope, $translate) -> + showArchivedText = $translate.instant("KANBAN.ACTION_SHOW_ARCHIVED") + hideArchivedText = $translate.instant("KANBAN.ACTION_HIDE_ARCHIVED") link = ($scope, $el, $attrs) -> status = $scope.$eval($attrs.tgKanbanArchivedStatusHeader) @@ -338,19 +338,18 @@ KanbanArchivedStatusHeaderDirective = ($rootscope) -> return {link:link} -module.directive("tgKanbanArchivedStatusHeader", [ "$rootScope", KanbanArchivedStatusHeaderDirective]) +module.directive("tgKanbanArchivedStatusHeader", [ "$rootScope", "$translate", KanbanArchivedStatusHeaderDirective]) ############################################################################# ## Kanban Archived Status Column Intro Directive ############################################################################# -KanbanArchivedStatusIntroDirective = -> - # TODO: i18n - hiddenUserStoriexText = "The user stories in this status are hidden by default" +KanbanArchivedStatusIntroDirective = ($translate) -> userStories = [] link = ($scope, $el, $attrs) -> + hiddenUserStoriexText = $translate.instant("KANBAN.HIDDEN_USER_STORIES") status = $scope.$eval($attrs.tgKanbanArchivedStatusIntro) $el.text(hiddenUserStoriexText) @@ -397,7 +396,7 @@ KanbanArchivedStatusIntroDirective = -> return {link:link} -module.directive("tgKanbanArchivedStatusIntro", KanbanArchivedStatusIntroDirective) +module.directive("tgKanbanArchivedStatusIntro", ["$translate", KanbanArchivedStatusIntroDirective]) ############################################################################# @@ -471,17 +470,20 @@ KanbanWipLimitDirective = -> link = ($scope, $el, $attrs) -> $el.disableSelection() - redrawWipLimit = -> + status = $scope.$eval($attrs.tgKanbanWipLimit) + + redrawWipLimit = => $el.find(".kanban-wip-limit").remove() - timeout 200, -> - element = $el.find(".kanban-task")[$scope.$eval($attrs.tgKanbanWipLimit)] + timeout 200, => + element = $el.find(".kanban-task")[status.wip_limit] if element angular.element(element).before("
") - $scope.$on "redraw:wip", redrawWipLimit - $scope.$on "kanban:us:move", redrawWipLimit - $scope.$on "usform:new:success", redrawWipLimit - $scope.$on "usform:bulk:success", redrawWipLimit + if status and not status.is_archived + $scope.$on "redraw:wip", redrawWipLimit + $scope.$on "kanban:us:move", redrawWipLimit + $scope.$on "usform:new:success", redrawWipLimit + $scope.$on "usform:bulk:success", redrawWipLimit $scope.$on "$destroy", -> $el.off() @@ -495,14 +497,14 @@ module.directive("tgKanbanWipLimit", KanbanWipLimitDirective) ## Kanban User Directive ############################################################################# -KanbanUserDirective = ($log) -> +KanbanUserDirective = ($log, $compile) -> template = _.template("""
- class="not-clickable"<% } %>> + class="not-clickable"<% } %>> <%- name %>
- """) # TODO: i18n + """) clickable = false @@ -527,7 +529,7 @@ KanbanUserDirective = ($log) -> else ctx = {name: user.full_name_display, imgurl: user.photo, clickable: clickable} - html = template(ctx) + html = $compile(template(ctx))($scope) $el.html(html) username_label.text(ctx.name) @@ -556,4 +558,4 @@ KanbanUserDirective = ($log) -> return {link: link, require:"ngModel"} -module.directive("tgKanbanUserAvatar", ["$log", KanbanUserDirective]) +module.directive("tgKanbanUserAvatar", ["$log", "$compile", KanbanUserDirective]) diff --git a/app/coffee/modules/locales/.empty b/app/coffee/modules/locales/.empty deleted file mode 100644 index e69de29b..00000000 diff --git a/app/coffee/modules/nav.coffee b/app/coffee/modules/nav.coffee index 578890e0..ec95aa6c 100644 --- a/app/coffee/modules/nav.coffee +++ b/app/coffee/modules/nav.coffee @@ -249,15 +249,19 @@ ProjectMenuDirective = ($log, $compile, $auth, $rootscope, $tgAuth, $location, $ container.replaceWith(dom) videoConferenceUrl = (project) -> + urlSeparator = "-" if project.videoconferences == "appear-in" baseUrl = "https://appear.in/" else if project.videoconferences == "talky" baseUrl = "https://talky.io/" + else if project.videoconferences == "jitsi" + urlSeparator = "" + baseUrl = "https://meet.jit.si/" else return "" if project.videoconferences_salt - url = "#{project.slug}-#{project.videoconferences_salt}" + url = "#{project.slug}#{urlSeparator}#{project.videoconferences_salt}" else url = "#{project.slug}" diff --git a/app/coffee/modules/projects/lightboxes.coffee b/app/coffee/modules/projects/lightboxes.coffee index c38afbc8..e83d328b 100644 --- a/app/coffee/modules/projects/lightboxes.coffee +++ b/app/coffee/modules/projects/lightboxes.coffee @@ -26,7 +26,7 @@ debounce = @.taiga.debounce module = angular.module("taigaProject") -CreateProject = ($rootscope, $repo, $confirm, $location, $navurls, $rs, $projectUrl, $loading, lightboxService, $cacheFactory) -> +CreateProject = ($rootscope, $repo, $confirm, $location, $navurls, $rs, $projectUrl, $loading, lightboxService, $cacheFactory, $translate) -> link = ($scope, $el, attrs) -> $scope.data = {} $scope.templates = [] @@ -41,7 +41,9 @@ CreateProject = ($rootscope, $repo, $confirm, $location, $navurls, $rs, $project $loading.finish(submitButton) $rootscope.$broadcast("projects:reload") - $confirm.notify("success", "Success") #TODO: i18n + + $confirm.notify("success", $translate.instant("COMMON.SAVE")) + $location.url($projectUrl.get(response)) lightboxService.close($el) @@ -126,7 +128,7 @@ CreateProject = ($rootscope, $repo, $confirm, $location, $navurls, $rs, $project return {link:link} module.directive("tgLbCreateProject", ["$rootScope", "$tgRepo", "$tgConfirm", "$location", "$tgNavUrls", - "$tgResources", "$projectUrl", "$tgLoading", "lightboxService", "$cacheFactory", CreateProject]) + "$tgResources", "$projectUrl", "$tgLoading", "lightboxService", "$cacheFactory", "$translate", CreateProject]) ############################################################################# diff --git a/app/coffee/modules/related-tasks.coffee b/app/coffee/modules/related-tasks.coffee index 740f12d9..2aaa96ea 100644 --- a/app/coffee/modules/related-tasks.coffee +++ b/app/coffee/modules/related-tasks.coffee @@ -25,7 +25,7 @@ debounce = @.taiga.debounce module = angular.module("taigaRelatedTasks", []) -RelatedTaskRowDirective = ($repo, $compile, $confirm, $rootscope, $loading, $template) -> +RelatedTaskRowDirective = ($repo, $compile, $confirm, $rootscope, $loading, $template, $translate) -> templateView = $template.get("task/related-task-row.html", true) templateEdit = $template.get("task/related-task-row-edit.html", true) @@ -79,9 +79,8 @@ RelatedTaskRowDirective = ($repo, $compile, $confirm, $rootscope, $loading, $tem $el.find('input').focus().select() $el.on "click", ".delete-task", (event) -> - #TODO: i18n + title = $translate.instant("TASK.TITLE_DELETE_ACTION") task = $model.$modelValue - title = "Delete Task" message = task.subject $confirm.askOnDelete(title, message).then (finish) -> @@ -109,7 +108,7 @@ RelatedTaskRowDirective = ($repo, $compile, $confirm, $rootscope, $loading, $tem return {link:link, require:"ngModel"} -module.directive("tgRelatedTaskRow", ["$tgRepo", "$compile", "$tgConfirm", "$rootScope", "$tgLoading", "$tgTemplate", RelatedTaskRowDirective]) +module.directive("tgRelatedTaskRow", ["$tgRepo", "$compile", "$tgConfirm", "$rootScope", "$tgLoading", "$tgTemplate", "$translate", RelatedTaskRowDirective]) RelatedTaskCreateFormDirective = ($repo, $compile, $confirm, $tgmodel, $loading, $analytics, $template) -> template = $template.get("task/related-task-create-form.html", true) diff --git a/app/coffee/modules/resources.coffee b/app/coffee/modules/resources.coffee index 2364baa3..52028c90 100644 --- a/app/coffee/modules/resources.coffee +++ b/app/coffee/modules/resources.coffee @@ -24,59 +24,42 @@ taiga = @.taiga class ResourcesService extends taiga.Service urls = { + # Auth "auth": "/auth" "auth-register": "/auth/register" "invitations": "/invitations" - "permissions": "/permissions" - "roles": "/roles" - "projects": "/projects" - "memberships": "/memberships" - "notify-policies": "/notify-policies" - "bulk-create-memberships": "/memberships/bulk_create" - "milestones": "/milestones" - "userstories": "/userstories" - "bulk-create-us": "/userstories/bulk_create" - "bulk-update-us-backlog-order": "/userstories/bulk_update_backlog_order" - "bulk-update-us-sprint-order": "/userstories/bulk_update_sprint_order" - "bulk-update-us-kanban-order": "/userstories/bulk_update_kanban_order" - "userstories-restore": "/userstories/%s/restore" - "tasks": "/tasks" - "bulk-create-tasks": "/tasks/bulk_create" - "bulk-update-task-taskboard-order": "/tasks/bulk_update_taskboard_order" - "tasks-restore": "/tasks/%s/restore" - "issues": "/issues" - "bulk-create-issues": "/issues/bulk_create" - "issues-restore": "/issues/%s/restore" - "wiki": "/wiki" - "wiki-restore": "/wiki/%s/restore" - "wiki-links": "/wiki-links" - "choices/userstory-statuses": "/userstory-statuses" - "choices/userstory-statuses/bulk-update-order": "/userstory-statuses/bulk_update_order" - "choices/points": "/points" - "choices/points/bulk-update-order": "/points/bulk_update_order" - "choices/task-statuses": "/task-statuses" - "choices/task-statuses/bulk-update-order": "/task-statuses/bulk_update_order" - "choices/issue-statuses": "/issue-statuses" - "choices/issue-statuses/bulk-update-order": "/issue-statuses/bulk_update_order" - "choices/issue-types": "/issue-types" - "choices/issue-types/bulk-update-order": "/issue-types/bulk_update_order" - "choices/priorities": "/priorities" - "choices/priorities/bulk-update-order": "/priorities/bulk_update_order" - "choices/severities": "/severities" - "choices/severities/bulk-update-order": "/severities/bulk_update_order" - "search": "/search" - "sites": "/sites" - "project-templates": "/project-templates" - "site-members": "/site-members" - "site-projects": "/site-projects" + + # User "users": "/users" "users-password-recovery": "/users/password_recovery" "users-change-password-from-recovery": "/users/change_password_from_recovery" "users-change-password": "/users/change_password" "users-change-email": "/users/change_email" "users-cancel-account": "/users/cancel" + + # User - Notification + "notify-policies": "/notify-policies" + + # User - Storage "user-storage": "/user-storage" + + # Memberships + "memberships": "/memberships" + "bulk-create-memberships": "/memberships/bulk_create" + + # Roles & Permissions + "roles": "/roles" + "permissions": "/permissions" + + # Resolver "resolver": "/resolver" + + # Project + "projects": "/projects" + "project-templates": "/project-templates" + "project-modules": "/projects/%s/modules" + + # Project Values - Choises "userstory-statuses": "/userstory-statuses" "points": "/points" "task-statuses": "/task-statuses" @@ -84,11 +67,30 @@ urls = { "issue-types": "/issue-types" "priorities": "/priorities" "severities": "/severities" - "project-modules": "/projects/%s/modules" - "webhooks": "/webhooks" - "webhooks-test": "/webhooks/%s/test" - "webhooklogs": "/webhooklogs" - "webhooklogs-resend": "/webhooklogs/%s/resend" + + # Milestones/Sprints + "milestones": "/milestones" + + # User stories + "userstories": "/userstories" + "bulk-create-us": "/userstories/bulk_create" + "bulk-update-us-backlog-order": "/userstories/bulk_update_backlog_order" + "bulk-update-us-sprint-order": "/userstories/bulk_update_sprint_order" + "bulk-update-us-kanban-order": "/userstories/bulk_update_kanban_order" + + # Tasks + "tasks": "/tasks" + "bulk-create-tasks": "/tasks/bulk_create" + "bulk-update-task-taskboard-order": "/tasks/bulk_update_taskboard_order" + + # Issues + "issues": "/issues" + "bulk-create-issues": "/issues/bulk_create" + + # Wiki pages + "wiki": "/wiki" + "wiki-restore": "/wiki/%s/restore" + "wiki-links": "/wiki-links" # History "history/us": "/history/userstory" @@ -107,22 +109,34 @@ urls = { "custom-attributes/issue": "/issue-custom-attributes" "custom-attributes/task": "/task-custom-attributes" - # Custom field values + # Custom Attributess - Values "custom-attributes-values/userstory": "/userstories/custom-attributes-values" "custom-attributes-values/issue": "/issues/custom-attributes-values" "custom-attributes-values/task": "/tasks/custom-attributes-values" - # Feedback - "feedback": "/feedback" + # Webhooks + "webhooks": "/webhooks" + "webhooks-test": "/webhooks/%s/test" + "webhooklogs": "/webhooklogs" + "webhooklogs-resend": "/webhooklogs/%s/resend" + + # Reports - CSV + "userstories-csv": "/userstories/csv?uuid=%s" + "tasks-csv": "/tasks/csv?uuid=%s" + "issues-csv": "/issues/csv?uuid=%s" + + # Search + "search": "/search" # Export/Import "exporter": "/exporter" "importer": "/importer/load_dump" - # CSV - "userstories-csv": "/userstories/csv?uuid=%s" - "tasks-csv": "/tasks/csv?uuid=%s" - "issues-csv": "/issues/csv?uuid=%s" + # Feedback + "feedback": "/feedback" + + # locales + "locales": "/locales" } # Initialize api urls service @@ -168,5 +182,6 @@ module.run([ "$tgModulesResourcesProvider", "$tgWebhooksResourcesProvider", "$tgWebhookLogsResourcesProvider", + "$tgLocalesResourcesProvider", initResources ]) diff --git a/app/coffee/modules/resources/locales.coffee b/app/coffee/modules/resources/locales.coffee new file mode 100644 index 00000000..2c2fd170 --- /dev/null +++ b/app/coffee/modules/resources/locales.coffee @@ -0,0 +1,38 @@ +### +# Copyright (C) 2015 Andrey Antukh +# Copyright (C) 2015 Jesús Espino Garcia +# Copyright (C) 2015 David Barragán Merino +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +# File: modules/resources/locales.coffee +### + + +taiga = @.taiga +sizeFormat = @.taiga.sizeFormat + + +resourceProvider = ($repo) -> + service = { + list: -> return $repo.queryMany("locales") + } + + return (instance) -> + instance.locales = service + + +module = angular.module("taigaResources") +module.factory("$tgLocalesResourcesProvider", ["$tgRepo", resourceProvider]) + diff --git a/app/coffee/modules/resources/projects.coffee b/app/coffee/modules/resources/projects.coffee index 88393f48..ad712d42 100644 --- a/app/coffee/modules/resources/projects.coffee +++ b/app/coffee/modules/resources/projects.coffee @@ -24,7 +24,7 @@ taiga = @.taiga sizeFormat = @.taiga.sizeFormat -resourceProvider = ($config, $repo, $http, $urls, $auth, $q, $rootScope) -> +resourceProvider = ($config, $repo, $http, $urls, $auth, $q, $translate) -> service = {} service.get = (projectId) -> @@ -85,21 +85,31 @@ resourceProvider = ($config, $repo, $http, $urls, $auth, $q, $rootScope) -> maxFileSize = $config.get("maxUploadFileSize", null) if maxFileSize and file.size > maxFileSize + errorMsg = $translate.instant("PROJECT.IMPORT.ERROR_MAX_SIZE_EXCEEDED", { + fileName: file.name + fileSize: sizeFormat(file.size) + maxFileSize: sizeFormat(maxFileSize) + }) + response = { status: 413, - data: _error_message: "'#{file.name}' (#{sizeFormat(file.size)}) is too heavy for our oompa - loompas, try it with a smaller than (#{sizeFormat(maxFileSize)})" + data: _error_message: errorMsg } defered.reject(response) return defered.promise uploadProgress = (evt) => percent = Math.round((evt.loaded / evt.total) * 100) - message = "Uloaded #{sizeFormat(evt.loaded)} of #{sizeFormat(evt.total)}" + message = $translate.instant("PROJECT.IMPORT.UPLOAD_IN_PROGRESS_MESSAGE", { + uploadedSize: sizeFormat(evt.loaded) + totalSize: sizeFormat(evt.total) + }) statusUpdater("in-progress", null, message, percent) uploadComplete = (evt) => - statusUpdater("done", "Importing Project", "This process can take a while, please keep the window open.") # i18n + statusUpdater("done", + $translate.instant("PROJECT.IMPORT.TITLE"), + $translate.instant("PROJECT.IMPORT.DESCRIPTION")) uploadFailed = (evt) => statusUpdater("error") @@ -141,5 +151,5 @@ resourceProvider = ($config, $repo, $http, $urls, $auth, $q, $rootScope) -> module = angular.module("taigaResources") -module.factory("$tgProjectsResourcesProvider", ["$tgConfig", "$tgRepo", "$tgHttp", "$tgUrls", "$tgAuth", "$q", - resourceProvider]) +module.factory("$tgProjectsResourcesProvider", ["$tgConfig", "$tgRepo", "$tgHttp", "$tgUrls", "$tgAuth", + "$q", "$translate", resourceProvider]) diff --git a/app/coffee/modules/taskboard/charts.coffee b/app/coffee/modules/taskboard/charts.coffee index 55b80cc3..2e50389d 100644 --- a/app/coffee/modules/taskboard/charts.coffee +++ b/app/coffee/modules/taskboard/charts.coffee @@ -34,7 +34,7 @@ module = angular.module("taigaTaskboard") ## Sprint burndown graph directive ############################################################################# -SprintGraphDirective = -> +SprintGraphDirective = ($translate)-> redrawChart = (element, dataToDraw) -> width = element.width() element.height(240) @@ -64,13 +64,18 @@ SprintGraphDirective = -> max: _.last(days) mode: "time" daysNames: days - axisLabel: 'Day' + axisLabel: $translate.instant("TASKBOARD.CHARTS.XAXIS_LABEL") axisLabelUseCanvas: true axisLabelFontSizePixels: 12 axisLabelFontFamily: 'Verdana, Arial, Helvetica, Tahoma, sans-serif' axisLabelPadding: 5 yaxis: min: 0 + axisLabel: $translate.instant("TASKBOARD.CHARTS.YAXIS_LABEL") + axisLabelUseCanvas: true + axisLabelFontSizePixels: 12 + axisLabelFontFamily: 'Verdana, Arial, Helvetica, Tahoma, sans-serif' + axisLabelPadding: 5 series: shadowSize: 0 lines: @@ -85,14 +90,20 @@ SprintGraphDirective = -> tooltip: true tooltipOpts: content: (label, xval, yval, flotItem) -> - #TODO: i18n - formattedDate = moment(xval).format("DD MMM") + formattedDate = moment(xval).format($translate.instant("TASKBOARD.CHARTS.DATE")) roundedValue = Math.round(yval) + if flotItem.seriesIndex == 1 - return "Optimal pending points for day #{formattedDate} should be #{roundedValue}" + return $translate.instant("TASKBOARD.CHARTS.OPTIMAL", { + formattedDate: formattedDate, + roundedValue: roundedValue + }) else - return "Real pending points for day #{formattedDate} is #{roundedValue}" + return $translate.instant("TASKBOARD.CHARTS.REAL", { + formattedDate: formattedDate, + roundedValue: roundedValue + }) element.empty() element.plot(data, options).data("plot") @@ -121,5 +132,4 @@ SprintGraphDirective = -> return {link: link} - -module.directive("tgSprintGraph", SprintGraphDirective) +module.directive("tgSprintGraph", ["$translate", SprintGraphDirective]) diff --git a/app/coffee/modules/taskboard/lightboxes.coffee b/app/coffee/modules/taskboard/lightboxes.coffee index 367aba17..c57e67eb 100644 --- a/app/coffee/modules/taskboard/lightboxes.coffee +++ b/app/coffee/modules/taskboard/lightboxes.coffee @@ -23,7 +23,7 @@ taiga = @.taiga bindOnce = @.taiga.bindOnce debounce = @.taiga.debounce -CreateEditTaskDirective = ($repo, $model, $rs, $rootscope, $loading, lightboxService) -> +CreateEditTaskDirective = ($repo, $model, $rs, $rootscope, $loading, lightboxService, $translate) -> link = ($scope, $el, attrs) -> $scope.isNew = true @@ -40,10 +40,13 @@ CreateEditTaskDirective = ($repo, $model, $rs, $rootscope, $loading, lightboxSer $scope.isNew = true # Update texts for creation - $el.find(".button-green").html("Create") #TODO: i18n - $el.find(".title").html("New task ") #TODO: i18n - $el.find(".tag-input").val("") + create = $translate.instant("COMMON.CREATE") + $el.find(".button-green").html(create) + newTask = $translate.instant("LIGHTBOX.CREATE_EDIT_TASK.TITLE") + $el.find(".title").html(newTask + " ") + + $el.find(".tag-input").val("") lightboxService.open($el) $scope.$on "taskform:edit", (ctx, task) -> @@ -51,10 +54,13 @@ CreateEditTaskDirective = ($repo, $model, $rs, $rootscope, $loading, lightboxSer $scope.isNew = false # Update texts for edition - $el.find(".button-green").html("Save") #TODO: i18n - $el.find(".title").html("Edit task ") #TODO: i18n - $el.find(".tag-input").val("") + save = $translate.instant("COMMON.SAVE") + edit = $translate.instant("LIGHTBOX.CREATE_EDIT_TASK.ACTION_EDIT") + $el.find(".button-green").html(save) + $el.find(".title").html(edit + " ") + + $el.find(".tag-input").val("") lightboxService.open($el) @@ -142,6 +148,7 @@ module.directive("tgLbCreateEditTask", [ "$rootScope", "$tgLoading", "lightboxService", + "$translate" CreateEditTaskDirective ]) diff --git a/app/coffee/modules/taskboard/main.coffee b/app/coffee/modules/taskboard/main.coffee index 8a922148..75018b97 100644 --- a/app/coffee/modules/taskboard/main.coffee +++ b/app/coffee/modules/taskboard/main.coffee @@ -50,13 +50,14 @@ class TaskboardController extends mixOf(taiga.Controller, taiga.PageMixin) "$tgEvents" "$tgAnalytics", "tgLoader" + "$translate" ] constructor: (@scope, @rootscope, @repo, @confirm, @rs, @params, @q, @appTitle, @location, @navUrls, - @events, @analytics, tgLoader) -> + @events, @analytics, tgLoader, @translate) -> bindMethods(@) - @scope.sectionName = "Taskboard" + @scope.sectionName = @translate.instant("TASKBOARD.SECTION_NAME") @.initializeEventHandlers() promise = @.loadInitialData() @@ -259,7 +260,6 @@ TaskboardDirective = ($rootscope) -> event.preventDefault() target = angular.element(event.currentTarget) target.toggleClass('active'); - #toggleText(target, ["Hide statistics", "Show statistics"]) # TODO: i18n $rootscope.$broadcast("taskboard:graph:toggle-visibility") tableBodyDom = $el.find(".taskboard-table-body") diff --git a/app/coffee/modules/tasks/detail.coffee b/app/coffee/modules/tasks/detail.coffee index 8f6bb6b8..bd25d2f2 100644 --- a/app/coffee/modules/tasks/detail.coffee +++ b/app/coffee/modules/tasks/detail.coffee @@ -26,6 +26,7 @@ groupBy = @.taiga.groupBy module = angular.module("taigaTasks") + ############################################################################# ## Task Detail Controller ############################################################################# @@ -44,13 +45,14 @@ class TaskDetailController extends mixOf(taiga.Controller, taiga.PageMixin) "$appTitle", "$tgNavUrls", "$tgAnalytics", + "$translate", "tgLoader" ] constructor: (@scope, @rootscope, @repo, @confirm, @rs, @params, @q, @location, - @log, @appTitle, @navUrls, @analytics, tgLoader) -> + @log, @appTitle, @navUrls, @analytics, @translate, tgLoader) -> @scope.taskRef = @params.taskref - @scope.sectionName = "Task Details" + @scope.sectionName = @translate.instant("TASK.SECTION_NAME") @.initializeEventHandlers() promise = @.loadInitialData() @@ -145,7 +147,7 @@ module.controller("TaskDetailController", TaskDetailController) ## Task status display directive ############################################################################# -TaskStatusDisplayDirective = ($template) -> +TaskStatusDisplayDirective = ($template, $compile) -> # Display if a Task is open or closed and its taskboard status. # # Example: @@ -165,6 +167,9 @@ TaskStatusDisplayDirective = ($template) -> is_closed: status.is_closed status: status }) + + html = $compile(html)($scope) + $el.html(html) $scope.$watch $attrs.ngModel, (task) -> @@ -179,14 +184,14 @@ TaskStatusDisplayDirective = ($template) -> require: "ngModel" } -module.directive("tgTaskStatusDisplay", ["$tgTemplate", TaskStatusDisplayDirective]) +module.directive("tgTaskStatusDisplay", ["$tgTemplate", "$compile", TaskStatusDisplayDirective]) ############################################################################# ## Task status button directive ############################################################################# -TaskStatusButtonDirective = ($rootScope, $repo, $confirm, $loading, $qqueue) -> +TaskStatusButtonDirective = ($rootScope, $repo, $confirm, $loading, $qqueue, $compile, $translate) -> # Display the status of Task and you can edit it. # # Example: @@ -202,7 +207,7 @@ TaskStatusButtonDirective = ($rootScope, $repo, $confirm, $loading, $qqueue) -> <%- status.name %> <% if(editable){ %><% }%> - status +
    <% _.each(statuses, function(st) { %> @@ -211,7 +216,7 @@ TaskStatusButtonDirective = ($rootScope, $repo, $confirm, $loading, $qqueue) -> <% }); %>
- """) #TODO: i18n + """) link = ($scope, $el, $attrs, $model) -> isEditable = -> @@ -220,11 +225,12 @@ TaskStatusButtonDirective = ($rootScope, $repo, $confirm, $loading, $qqueue) -> render = (task) => status = $scope.statusById[task.status] - html = template({ + html = $compile(template({ status: status statuses: $scope.statusList editable: isEditable() - }) + }))($scope) + $el.html(html) save = $qqueue.bindAdd (status) => @@ -278,14 +284,15 @@ TaskStatusButtonDirective = ($rootScope, $repo, $confirm, $loading, $qqueue) -> } module.directive("tgTaskStatusButton", ["$rootScope", "$tgRepo", "$tgConfirm", "$tgLoading", "$tgQqueue", - TaskStatusButtonDirective]) + "$compile", "$translate", TaskStatusButtonDirective]) -TaskIsIocaineButtonDirective = ($rootscope, $tgrepo, $confirm, $loading, $qqueue) -> +TaskIsIocaineButtonDirective = ($rootscope, $tgrepo, $confirm, $loading, $qqueue, $compile) -> template = _.template(""" -
+
@@ -305,7 +312,7 @@ TaskIsIocaineButtonDirective = ($rootscope, $tgrepo, $confirm, $loading, $qqueue isIocaine: task.is_iocaine isEditable: isEditable() } - html = template(ctx) + html = $compile(template(ctx))($scope) $el.html(html) save = $qqueue.bindAdd (is_iocaine) => @@ -347,4 +354,5 @@ TaskIsIocaineButtonDirective = ($rootscope, $tgrepo, $confirm, $loading, $qqueue require: "ngModel" } -module.directive("tgTaskIsIocaineButton", ["$rootScope", "$tgRepo", "$tgConfirm", "$tgLoading", "$tgQqueue", TaskIsIocaineButtonDirective]) +module.directive("tgTaskIsIocaineButton", ["$rootScope", "$tgRepo", "$tgConfirm", "$tgLoading", "$tgQqueue", + "$compile", TaskIsIocaineButtonDirective]) diff --git a/app/coffee/modules/team/main.coffee b/app/coffee/modules/team/main.coffee index 9bc9b57a..df13508c 100644 --- a/app/coffee/modules/team/main.coffee +++ b/app/coffee/modules/team/main.coffee @@ -41,18 +41,20 @@ class TeamController extends mixOf(taiga.Controller, taiga.PageMixin) "$tgNavUrls", "$appTitle", "$tgAuth", - "tgLoader" + "tgLoader", + "$translate" ] - constructor: (@scope, @rootscope, @repo, @rs, @params, @q, @location, @navUrls, @appTitle, @auth, tgLoader) -> - @scope.sectionName = "Team" + constructor: (@scope, @rootscope, @repo, @rs, @params, @q, @location, @navUrls, @appTitle, @auth, tgLoader, + @translate) -> + @scope.sectionName = "TEAM.SECTION_NAME" promise = @.loadInitialData() # On Success promise.then => - #TODO: i18n - @appTitle.set("Team - " + @scope.project.name) + text = @translate.instant("TEAM.APP_TITLE", {"projectName": @scope.project.name}) + @appTitle.set(text) # On Error promise.then null, @.onInitialDataError.bind(@) @@ -137,6 +139,7 @@ class TeamController extends mixOf(taiga.Controller, taiga.PageMixin) module.controller("TeamController", TeamController) + ############################################################################# ## Team Filters Directive ############################################################################# @@ -148,6 +151,7 @@ TeamFiltersDirective = () -> module.directive("tgTeamFilters", [TeamFiltersDirective]) + ############################################################################# ## Team Member Stats Directive ############################################################################# @@ -166,6 +170,7 @@ TeamMemberStatsDirective = () -> module.directive("tgTeamMemberStats", TeamMemberStatsDirective) + ############################################################################# ## Team Current User Directive ############################################################################# @@ -185,6 +190,7 @@ TeamMemberCurrentUserDirective = () -> module.directive("tgTeamCurrentUser", TeamMemberCurrentUserDirective) + ############################################################################# ## Team Members Directive ############################################################################# @@ -207,15 +213,18 @@ TeamMembersDirective = () -> module.directive("tgTeamMembers", TeamMembersDirective) + ############################################################################# ## Leave project Directive ############################################################################# -LeaveProjectDirective = ($repo, $confirm, $location, $rs, $navurls) -> +LeaveProjectDirective = ($repo, $confirm, $location, $rs, $navurls, $translate) -> link = ($scope, $el, $attrs) -> $scope.leave = () -> - #TODO: i18n - $confirm.ask("Leave this project", "Are you sure you want to leave the project?").then (finish) => + leave_project_text = $translate.instant("TEAM.ACTION_LEAVE_PROJECT") + confirm_leave_project_text = $translate.instant("TEAM.CONFIRM_LEAVE_PROJECT") + + $confirm.ask(leave_project_text, confirm_leave_project_text).then (finish) => promise = $rs.projects.leave($attrs.projectid) promise.then => @@ -233,10 +242,17 @@ LeaveProjectDirective = ($repo, $confirm, $location, $rs, $navurls) -> link: link } -module.directive("tgLeaveProject", ["$tgRepo", "$tgConfirm", "$tgLocation", "$tgResources", "$tgNavUrls", LeaveProjectDirective]) +module.directive("tgLeaveProject", ["$tgRepo", "$tgConfirm", "$tgLocation", "$tgResources", "$tgNavUrls", "$translate", + LeaveProjectDirective]) -module.filter 'membersRoleFilter', () -> - (input, filtersRole) -> - if filtersRole? - return _.filter(input, {role: filtersRole.id}) - return input + +############################################################################# +## Team Filters +############################################################################# + +membersFilter = -> + return (members, filtersQ, filtersRole) -> + return _.filter members, (m) -> (not filtersRole or m.role == filtersRole.id) and + (not filtersQ or m.full_name.search(new RegExp(filtersQ, "i")) >= 0) + +module.filter('membersFilter', membersFilter) diff --git a/app/coffee/modules/user-settings/change-password.coffee b/app/coffee/modules/user-settings/change-password.coffee index d8df8ddd..387b92d6 100644 --- a/app/coffee/modules/user-settings/change-password.coffee +++ b/app/coffee/modules/user-settings/change-password.coffee @@ -42,11 +42,12 @@ class UserChangePasswordController extends mixOf(taiga.Controller, taiga.PageMix "$q", "$tgLocation", "$tgNavUrls", - "$tgAuth" + "$tgAuth", + "$translate" ] - constructor: (@scope, @rootscope, @repo, @confirm, @rs, @params, @q, @location, @navUrls, @auth) -> - @scope.sectionName = "Change Password" #i18n + constructor: (@scope, @rootscope, @repo, @confirm, @rs, @params, @q, @location, @navUrls, @auth, @translate) -> + @scope.sectionName = @translate.instant("CHANGE_PASSWORD.SECTION_NAME") @scope.project = {} @scope.user = @auth.getUser() @@ -74,13 +75,13 @@ module.controller("UserChangePasswordController", UserChangePasswordController) ## User ChangePassword Directive ############################################################################# -UserChangePasswordDirective = ($rs, $confirm, $loading) -> +UserChangePasswordDirective = ($rs, $confirm, $loading, $translate) -> link = ($scope, $el, $attrs, ctrl) -> submit = debounce 2000, (event) => event.preventDefault() if $scope.newPassword1 != $scope.newPassword2 - $confirm.notify('error', "The passwords dosn't match") + $confirm.notify('error', $translate.instant("CHANGE_PASSWORD.ERROR_PASSWORD_MATCH")) return $loading.start(submitButton) diff --git a/app/coffee/modules/user-settings/main.coffee b/app/coffee/modules/user-settings/main.coffee index 656decd4..620236b3 100644 --- a/app/coffee/modules/user-settings/main.coffee +++ b/app/coffee/modules/user-settings/main.coffee @@ -41,17 +41,21 @@ class UserSettingsController extends mixOf(taiga.Controller, taiga.PageMixin) "$q", "$tgLocation", "$tgNavUrls", - "$tgAuth" + "$tgAuth", + "$translate" ] - constructor: (@scope, @rootscope, @config, @repo, @confirm, @rs, @params, @q, @location, @navUrls, @auth) -> - @scope.sectionName = "User Profile" #i18n + constructor: (@scope, @rootscope, @config, @repo, @confirm, @rs, @params, @q, @location, @navUrls, @auth, @translate) -> + @scope.sectionName = "USER_SETTINGS.MENU.SECTION_TITLE" + @scope.project = {} @scope.user = @auth.getUser() + @scope.lang = @getLan() maxFileSize = @config.get("maxUploadFileSize", null) if maxFileSize - @scope.maxFileSizeMsg = "[Max, size: #{sizeFormat(maxFileSize)}" # TODO: i18n + @translate("USER_SETTINGS.AVATAR_MAX_SIZE", {"maxFileSize": sizeFormat(maxFileSize)}).then (text) => + @scope.maxFileSizeMsg = text promise = @.loadInitialData() @@ -63,16 +67,26 @@ class UserSettingsController extends mixOf(taiga.Controller, taiga.PageMixin) @scope.$emit('project:loaded', project) return project + loadLocales: -> + return @rs.locales.list().then (locales) => + @scope.locales = locales + return locales + loadInitialData: -> promise = @repo.resolve({pslug: @params.pslug}).then (data) => @scope.projectId = data.project return data - return promise.then(=> @.loadProject()) + return @q.all([promise.then(=> @.loadProject()), + @.loadLocales()]) openDeleteLightbox: -> @rootscope.$broadcast("deletelightbox:new", @scope.user) + getLan: -> + return @scope.user.lang || + @translate.preferredLanguage() + module.controller("UserSettingsController", UserSettingsController) @@ -80,7 +94,7 @@ module.controller("UserSettingsController", UserSettingsController) ## User Profile Directive ############################################################################# -UserProfileDirective = ($confirm, $auth, $repo) -> +UserProfileDirective = ($confirm, $auth, $repo, $translate) -> link = ($scope, $el, $attrs) -> submit = debounce 2000, (event) => event.preventDefault() @@ -89,14 +103,14 @@ UserProfileDirective = ($confirm, $auth, $repo) -> return if not form.validate() changeEmail = $scope.user.isAttributeModified("email") + $scope.user.lang = $scope.lang onSuccess = (data) => $auth.setUser(data) if changeEmail - $confirm.success("Check your inbox!
- We have sent a mail to your account
- with the instructions to set your new address") #TODO: i18n + text = $translate.instant("USER_PROFILE.CHANGE_EMAIL_SUCCESS") + $confirm.success(text) else $confirm.notify('success') @@ -113,7 +127,7 @@ UserProfileDirective = ($confirm, $auth, $repo) -> return {link:link} -module.directive("tgUserProfile", ["$tgConfirm", "$tgAuth", "$tgRepo", UserProfileDirective]) +module.directive("tgUserProfile", ["$tgConfirm", "$tgAuth", "$tgRepo", "$translate", UserProfileDirective]) ############################################################################# diff --git a/app/coffee/modules/user-settings/notifications.coffee b/app/coffee/modules/user-settings/notifications.coffee index 6af3c428..ca299c71 100644 --- a/app/coffee/modules/user-settings/notifications.coffee +++ b/app/coffee/modules/user-settings/notifications.coffee @@ -45,7 +45,7 @@ class UserNotificationsController extends mixOf(taiga.Controller, taiga.PageMixi ] constructor: (@scope, @rootscope, @repo, @confirm, @rs, @params, @q, @location, @navUrls, @auth) -> - @scope.sectionName = "Email Notifications" #i18n + @scope.sectionName = "USER_SETTINGS.NOTIFICATIONS.SECTION_NAME" @scope.project = {} @scope.user = @auth.getUser() @@ -94,7 +94,7 @@ module.directive("tgUserNotifications", UserNotificationsDirective) ## User Notifications List Directive ############################################################################# -UserNotificationsListDirective = ($repo, $confirm) -> +UserNotificationsListDirective = ($repo, $confirm, $compile) -> template = _.template(""" <% _.each(notifyPolicies, function (notifyPolicy, index) { %>
@@ -104,7 +104,8 @@ UserNotificationsListDirective = ($repo, $confirm) -> checked="checked"<% } %>/> - +
@@ -112,7 +113,8 @@ UserNotificationsListDirective = ($repo, $confirm) -> checked="checked"<% } %> /> - +
@@ -120,7 +122,8 @@ UserNotificationsListDirective = ($repo, $confirm) -> checked="checked"<% } %> /> - +
@@ -130,13 +133,17 @@ UserNotificationsListDirective = ($repo, $confirm) -> link = ($scope, $el, $attrs) -> render = -> $el.off() - $el.html(template({notifyPolicies: $scope.notifyPolicies})) + + ctx = {notifyPolicies: $scope.notifyPolicies} + html = template(ctx) + + $el.html($compile(html)($scope)) $el.on "change", "input[type=radio]", (event) -> target = angular.element(event.currentTarget) + policyIndex = target.parents(".policy-table-row").data('index') policy = $scope.notifyPolicies[policyIndex] - prev_level = policy.notify_level policy.notify_level = parseInt(target.val(), 10) @@ -145,7 +152,9 @@ UserNotificationsListDirective = ($repo, $confirm) -> onError = -> $confirm.notify("error") - target.parents(".policy-table-row").find("input[value=#{prev_level}]").prop("checked", true) + target.parents(".policy-table-row") + .find("input[value=#{prev_level}]") + .prop("checked", true) $repo.save(policy).then(onSuccess, onError) @@ -156,4 +165,5 @@ UserNotificationsListDirective = ($repo, $confirm) -> return {link:link} -module.directive("tgUserNotificationsList", ["$tgRepo", "$tgConfirm", UserNotificationsListDirective]) +module.directive("tgUserNotificationsList", ["$tgRepo", "$tgConfirm", "$compile", + UserNotificationsListDirective]) diff --git a/app/coffee/modules/userstories/detail.coffee b/app/coffee/modules/userstories/detail.coffee index 650885d6..79525316 100644 --- a/app/coffee/modules/userstories/detail.coffee +++ b/app/coffee/modules/userstories/detail.coffee @@ -45,13 +45,14 @@ class UserStoryDetailController extends mixOf(taiga.Controller, taiga.PageMixin) "$appTitle", "$tgNavUrls", "$tgAnalytics", + "$translate", "tgLoader" ] constructor: (@scope, @rootscope, @repo, @confirm, @rs, @params, @q, @location, - @log, @appTitle, @navUrls, @analytics, tgLoader) -> + @log, @appTitle, @navUrls, @analytics, @translate, tgLoader) -> @scope.usRef = @params.usref - @scope.sectionName = "User Story Details" + @scope.sectionName = @translate.instant("US.SECTION_NAME") @.initializeEventHandlers() promise = @.loadInitialData() @@ -178,7 +179,7 @@ module.controller("UserStoryDetailController", UserStoryDetailController) ## User story status display directive ############################################################################# -UsStatusDisplayDirective = ($template) -> +UsStatusDisplayDirective = ($template, $compile) -> # Display if a US is open or closed and its kanban status. # # Example: @@ -192,10 +193,14 @@ UsStatusDisplayDirective = ($template) -> link = ($scope, $el, $attrs) -> render = (us) -> + status = $scope.statusById[us.status] + html = template({ is_closed: us.is_closed - status: $scope.statusById[us.status] + status: status }) + + html = $compile(html)($scope) $el.html(html) $scope.$watch $attrs.ngModel, (us) -> @@ -210,14 +215,14 @@ UsStatusDisplayDirective = ($template) -> require: "ngModel" } -module.directive("tgUsStatusDisplay", ["$tgTemplate", UsStatusDisplayDirective]) +module.directive("tgUsStatusDisplay", ["$tgTemplate", "$compile", UsStatusDisplayDirective]) ############################################################################# ## User story related tasts progress splay Directive ############################################################################# -UsTasksProgressDisplayDirective = ($template) -> +UsTasksProgressDisplayDirective = ($template, $compile) -> # Display a progress bar with the stats of completed tasks. # # Example: @@ -227,8 +232,6 @@ UsTasksProgressDisplayDirective = ($template) -> # - Task object list (ng-model) # - scope.taskStatusById object - template = $template.get("us/us-task-progress.html", true) - link = ($scope, $el, $attrs) -> render = (tasks) -> totalTasks = tasks.length @@ -236,12 +239,14 @@ UsTasksProgressDisplayDirective = ($template) -> progress = if totalTasks > 0 then 100 * totalClosedTasks / totalTasks else 0 - html = template({ + _.assign($scope, { totalTasks: totalTasks totalClosedTasks: totalClosedTasks - progress: progress + progress: progress, + style: { + width: progress + "%" + } }) - $el.html(html) $scope.$watch $attrs.ngModel, (tasks) -> render(tasks) if tasks? @@ -250,12 +255,14 @@ UsTasksProgressDisplayDirective = ($template) -> $el.off() return { + templateUrl: "us/us-task-progress.html" link: link restrict: "EA" require: "ngModel" + scope: true } -module.directive("tgUsTasksProgressDisplay", ["$tgTemplate", UsTasksProgressDisplayDirective]) +module.directive("tgUsTasksProgressDisplay", ["$tgTemplate", "$compile", UsTasksProgressDisplayDirective]) ############################################################################# @@ -350,7 +357,7 @@ module.directive("tgUsStatusButton", ["$rootScope", "$tgRepo", "$tgConfirm", "$t ## User story team requirements button directive ############################################################################# -UsTeamRequirementButtonDirective = ($rootscope, $tgrepo, $confirm, $loading, $qqueue, $template) -> +UsTeamRequirementButtonDirective = ($rootscope, $tgrepo, $confirm, $loading, $qqueue, $template, $compile) -> template = $template.get("us/us-team-requirement-button.html", true) link = ($scope, $el, $attrs, $model) -> @@ -367,6 +374,8 @@ UsTeamRequirementButtonDirective = ($rootscope, $tgrepo, $confirm, $loading, $qq isRequired: us.team_requirement } html = template(ctx) + html = $compile(html)($scope) + $el.html(html) save = $qqueue.bindAdd (team_requirement) => @@ -407,13 +416,13 @@ UsTeamRequirementButtonDirective = ($rootscope, $tgrepo, $confirm, $loading, $qq require: "ngModel" } -module.directive("tgUsTeamRequirementButton", ["$rootScope", "$tgRepo", "$tgConfirm", "$tgLoading", "$tgQqueue", "$tgTemplate", UsTeamRequirementButtonDirective]) +module.directive("tgUsTeamRequirementButton", ["$rootScope", "$tgRepo", "$tgConfirm", "$tgLoading", "$tgQqueue", "$tgTemplate", "$compile", UsTeamRequirementButtonDirective]) ############################################################################# ## User story client requirements button directive ############################################################################# -UsClientRequirementButtonDirective = ($rootscope, $tgrepo, $confirm, $loading, $qqueue, $template) -> +UsClientRequirementButtonDirective = ($rootscope, $tgrepo, $confirm, $loading, $qqueue, $template, $compile) -> template = $template.get("us/us-client-requirement-button.html", true) link = ($scope, $el, $attrs, $model) -> @@ -429,7 +438,7 @@ UsClientRequirementButtonDirective = ($rootscope, $tgrepo, $confirm, $loading, $ canEdit: canEdit() isRequired: us.client_requirement } - html = template(ctx) + html = $compile(template(ctx))($scope) $el.html(html) save = $qqueue.bindAdd (client_requirement) => @@ -467,5 +476,5 @@ UsClientRequirementButtonDirective = ($rootscope, $tgrepo, $confirm, $loading, $ require: "ngModel" } -module.directive("tgUsClientRequirementButton", ["$rootScope", "$tgRepo", "$tgConfirm", "$tgLoading", "$tgQqueue", "$tgTemplate", +module.directive("tgUsClientRequirementButton", ["$rootScope", "$tgRepo", "$tgConfirm", "$tgLoading", "$tgQqueue", "$tgTemplate", "$compile", UsClientRequirementButtonDirective]) diff --git a/app/coffee/modules/wiki/main.coffee b/app/coffee/modules/wiki/main.coffee index 9596212b..f8141940 100644 --- a/app/coffee/modules/wiki/main.coffee +++ b/app/coffee/modules/wiki/main.coffee @@ -49,11 +49,12 @@ class WikiDetailController extends mixOf(taiga.Controller, taiga.PageMixin) "$appTitle", "$tgNavUrls", "$tgAnalytics", - "tgLoader" + "tgLoader", + "$translate" ] constructor: (@scope, @rootscope, @repo, @model, @confirm, @rs, @params, @q, @location, - @filter, @log, @appTitle, @navUrls, @analytics, tgLoader) -> + @filter, @log, @appTitle, @navUrls, @analytics, tgLoader, @translate) -> @scope.projectSlug = @params.pslug @scope.wikiSlug = @params.slug @scope.sectionName = "Wiki" @@ -111,8 +112,7 @@ class WikiDetailController extends mixOf(taiga.Controller, taiga.PageMixin) @q.all([@.loadWikiLinks(), @.loadWiki()]) delete: -> - # TODO: i18n - title = "Delete Wiki Page" + title = @translate.instant("WIKI.DELETE_LIGHTBOX_TITLE") message = unslugify(@scope.wiki.slug) @confirm.askOnDelete(title, message).then (finish) => @@ -135,7 +135,7 @@ module.controller("WikiDetailController", WikiDetailController) ## Wiki Summary Directive ############################################################################# -WikiSummaryDirective = ($log, $template) -> +WikiSummaryDirective = ($log, $template, $compile, $translate) -> template = $template.get("wiki/wiki-summary.html", true) link = ($scope, $el, $attrs, $model) -> @@ -152,10 +152,11 @@ WikiSummaryDirective = ($log, $template) -> ctx = { totalEditions: wiki.editions - lastModifiedDate: moment(wiki.modified_date).format("DD MMM YYYY HH:mm") + lastModifiedDate: moment(wiki.modified_date).format($translate.instant("WIKI.DATETIME")) user: user } html = template(ctx) + html = $compile(html)($scope) $el.html(html) $scope.$watch $attrs.ngModel, (wikiPage) -> @@ -171,7 +172,7 @@ WikiSummaryDirective = ($log, $template) -> require: "ngModel" } -module.directive("tgWikiSummary", ["$log", "$tgTemplate", WikiSummaryDirective]) +module.directive("tgWikiSummary", ["$log", "$tgTemplate", "$compile", "$translate", WikiSummaryDirective]) ############################################################################# @@ -215,7 +216,7 @@ EditableWikiContentDirective = ($window, $document, $repo, $confirm, $loading, $ if not wiki.id? $analytics.trackEvent("wikipage", "create", "create wiki page", 1) - $model.$setViewValue wikiPage + $model.$setViewValue wikiPage.clone() $confirm.notify("success") switchToReadMode() diff --git a/app/coffee/modules/wiki/nav.coffee b/app/coffee/modules/wiki/nav.coffee index 21cd19e6..558ff820 100644 --- a/app/coffee/modules/wiki/nav.coffee +++ b/app/coffee/modules/wiki/nav.coffee @@ -34,7 +34,7 @@ module = angular.module("taigaWiki") ## Wiki Main Directive ############################################################################# -WikiNavDirective = ($tgrepo, $log, $location, $confirm, $navUrls, $analytics, $loading, $template) -> +WikiNavDirective = ($tgrepo, $log, $location, $confirm, $navUrls, $analytics, $loading, $template, $compile, $translate) -> template = $template.get("wiki/wiki-nav.html", true) link = ($scope, $el, $attrs) -> $ctrl = $el.controller() @@ -53,6 +53,8 @@ WikiNavDirective = ($tgrepo, $log, $location, $confirm, $navUrls, $analytics, $l deleteWikiLinkPermission: deleteWikiLinkPermission }) + html = $compile(html)($scope) + $el.off() $el.html(html) @@ -80,8 +82,7 @@ WikiNavDirective = ($tgrepo, $log, $location, $confirm, $navUrls, $analytics, $l target = angular.element(event.currentTarget) linkId = target.parents('.wiki-link').data('id') - # TODO: i18n - title = "Delete Wiki Link" + title = $translate.instant("WIKI.DELETE_LIGHTBOX_TITLE") message = $scope.wikiLinks[linkId].title $confirm.askOnDelete(title, message).then (finish) => @@ -143,4 +144,4 @@ WikiNavDirective = ($tgrepo, $log, $location, $confirm, $navUrls, $analytics, $l return {link:link} module.directive("tgWikiNav", ["$tgRepo", "$log", "$tgLocation", "$tgConfirm", "$tgNavUrls", - "$tgAnalytics", "$tgLoading", "$tgTemplate", WikiNavDirective]) + "$tgAnalytics", "$tgLoading", "$tgTemplate", "$compile", "$translate", WikiNavDirective]) diff --git a/app/js/jquery.ui.touch-punch.min.js b/app/js/jquery.ui.touch-punch.min.js new file mode 100644 index 00000000..8c8ceb4d --- /dev/null +++ b/app/js/jquery.ui.touch-punch.min.js @@ -0,0 +1,11 @@ +/*! + * jQuery UI Touch Punch 0.2.3 + * + * Copyright 2011–2014, Dave Furfero + * Dual licensed under the MIT or GPL Version 2 licenses. + * + * Depends: + * jquery.ui.widget.js + * jquery.ui.mouse.js + */ +!function(a){function f(a,b){if(!(a.originalEvent.touches.length>1)){a.preventDefault();var c=a.originalEvent.changedTouches[0],d=document.createEvent("MouseEvents");d.initMouseEvent(b,!0,!0,window,1,c.screenX,c.screenY,c.clientX,c.clientY,!1,!1,!1,!1,0,null),a.target.dispatchEvent(d)}}if(a.support.touch="ontouchend"in document,a.support.touch){var e,b=a.ui.mouse.prototype,c=b._mouseInit,d=b._mouseDestroy;b._touchStart=function(a){var b=this;!e&&b._mouseCapture(a.originalEvent.changedTouches[0])&&(e=!0,b._touchMoved=!1,f(a,"mouseover"),f(a,"mousemove"),f(a,"mousedown"))},b._touchMove=function(a){e&&(this._touchMoved=!0,f(a,"mousemove"))},b._touchEnd=function(a){e&&(f(a,"mouseup"),f(a,"mouseout"),this._touchMoved||f(a,"click"),e=!1)},b._mouseInit=function(){var b=this;b.element.bind({touchstart:a.proxy(b,"_touchStart"),touchmove:a.proxy(b,"_touchMove"),touchend:a.proxy(b,"_touchEnd")}),c.call(b)},b._mouseDestroy=function(){var b=this;b.element.unbind({touchstart:a.proxy(b,"_touchStart"),touchmove:a.proxy(b,"_touchMove"),touchend:a.proxy(b,"_touchEnd")}),d.call(b)}}}(jQuery); diff --git a/app/locales/en/app.json b/app/locales/en/app.json deleted file mode 100644 index 6498b36c..00000000 --- a/app/locales/en/app.json +++ /dev/null @@ -1,63 +0,0 @@ -{ - "checksley": { - "defaultMessage": "This value seems to be invalid.", - "type-email": "This value should be a valid email.", - "type-url": "This value should be a valid url.", - "type-urlstrict": "This value should be a valid url.", - "type-number": "This value should be a valid number.", - "type-digits": "This value should be digits.", - "type-dateIso": "This value should be a valid date (YYYY-MM-DD).", - "type-alphanum": "This value should be alphanumeric.", - "type-phone": "This value should be a valid phone number.", - "notnull": "This value should not be null.", - "notblank": "This value should not be blank.", - "required": "This value is required.", - "regexp": "This value seems to be invalid.", - "min": "This value should be greater than or equal to %s.", - "max": "This value should be lower than or equal to %s.", - "range": "This value should be between %s and %s.", - "minlength": "This value is too short. It should have %s characters or more.", - "maxlength": "This value is too long. It should have %s characters or less.", - "rangelength": "This value length is invalid. It should be between %s and %s characters long.", - "mincheck": "You must select at least %s choices.", - "maxcheck": "You must select %s choices or less.", - "rangecheck": "You must select between %s and %s choices.", - "equalto": "This value should be the same." - }, - "common": { - "subject": "Subject", - "save": "Save", - "blocked": "Blocked", - "cancel": "Cancel", - "status": "Status", - "new-bulk": "New bulk insert", - "one-item-line": "One item per line..." - }, - "pagination": { - "next": "Next", - "prev": "Previous" - }, - "markdown-editor": { - "heading-1": "First Level Heading", - "heading-2": "Second Level Heading", - "heading-3": "Third Level Heading", - "bold": "Bold", - "italic": "Italic", - "strike": "Strike", - "bulleted-list": "Bulleted List", - "numeric-list": "Numeric List", - "picture": "Picture", - "link": "Link", - "quotes": "Quotes", - "code-block": "Code Block / Code", - "preview": "Preview", - "help": "Help", - "placeholder": "Your title here...", - "link-placeholder": "Your text to link here..." - }, - "us": { - "title-new": "New User Story", - "team-requirement": "Team Requirement", - "client-requirement": "Client Requirement" - } -} diff --git a/app/locales/locale-ca.json b/app/locales/locale-ca.json new file mode 100644 index 00000000..b2fd9755 --- /dev/null +++ b/app/locales/locale-ca.json @@ -0,0 +1,1091 @@ +{ + "COMMON": { + "YES": "Si", + "NO": "No", + "LOADING": "Carregant...", + "LOADING_PROJECT": "Carregant projecte...", + "DATE": "DD MMM YYYY", + "DATETIME": "DD MMM YYYY HH:mm", + "SAVE": "Guardar", + "CANCEL": "Següent", + "ACCEPT": "Acceptar", + "DELETE": "Esborrar", + "CREATE": "Crear", + "ADD": "Afegir", + "COPY_TO_CLIPBOARD": "Copia al portapapers: Ctrl + C", + "EDIT": "edita", + "DRAG": "Moure", + "TAG_LINE": "La teua eïna de gestió de projectes àgil, gratuita i de codi obert ", + "TAG_LINE_2": "ESTIMA EL TEU PROJECTE", + "BLOCK": "Bloquejar", + "UNBLOCK": "Desbloquejar", + "BLOCKED": "Bloquejat", + "CREATED_BY": "Creat per {{fullDisplayName}}", + "FROM": "de", + "TO": "a", + "CLOSE": "Tancar", + "BLOCKED_NOTE": "Per qué està bloquejada esta tasca?", + "BLOCKED_REASON": "Per favor, explica la raó", + "GO_HOME": "Porta'm a l'inici ", + "PLUGINS": "Plugins", + "BETA": "Estem en beta!", + "ONE_ITEM_LINE": "In item per línia", + "NEW_BULK": "Nova inserció en grup", + "RELATED_TASKS": "Tasques relacionades", + "LOGOUT": "Logout", + "EXTERNAL_USER": "un usuari extern", + "GENERIC_ERROR": "Un Oompa Loompas diu {{error}}.", + "IOCAINE_TEXT": "Un poc saturat per una tasca? Fes-ho saber als teus companys clicant a Iocaina quan edites la tasca. Es possible ser inmune a aquesta (fictícia) poció mortal consumint xicotetes dòsis poc a poc, així com es possible millorar amb xicotets nous desafiaments!", + "FORM_ERRORS": { + "DEFAULT_MESSAGE": "Aquest valor pareix invàlid.", + "TYPE_EMAIL": "Deu ser un correu vàlid.", + "TYPE_URL": "Deu ser una URL vàlida.", + "TYPE_URLSTRICT": "Deu ser una URL vàlida.", + "TYPE_NUMBER": "Deu ser un nombre vàlid.", + "TYPE_DIGITS": "This value should be digits.", + "TYPE_DATEISO": "This value should be a valid date (YYYY-MM-DD).", + "TYPE_ALPHANUM": "This value should be alphanumeric.", + "TYPE_PHONE": "This value should be a valid phone number.", + "NOTNULL": "This value should not be null.", + "NOT_BLANK": "This value should not be blank.", + "REQUIRED": "This value is required.", + "REGEXP": "Aquest valor pareix invàlid.", + "MIN": "This value should be greater than or equal to %s.", + "MAX": "This value should be lower than or equal to %s.", + "RANGE": "This value should be between %s and %s.", + "MIN_LENGTH": "This value is too short. It should have %s characters or more.", + "MAX_LENGTH": "This value is too long. It should have %s characters or less.", + "RANGE_LENGTH": "This value length is invalid. It should be between %s and %s characters long.", + "MIN_CHECK": "You must select at least %s choices.", + "MAX_CHECK": "You must select %s choices or less.", + "RANGE_CHECK": "You must select between %s and %s choices.", + "EQUAL_TO": "This value should be the same." + }, + "PICKERDATE": { + "FORMAT": "DD MMM YYYY", + "IS_RTL": "false", + "FIRST_DAY_OF_WEEK": "1", + "PREV_MONTH": "Mes anterior", + "NEXT_MONTH": "Mes que ve", + "MONTHS": { + "JAN": "Gener", + "FEB": "Febrer", + "MAR": "Març", + "APR": "Abril", + "MAY": "Maig", + "JUN": "Juny", + "JUL": "Juliol", + "AUG": "Agost", + "SEP": "Setembre", + "OCT": "Octubre", + "NOV": "Novembre", + "DEC": "Desembre" + }, + "WEEK_DAYS": { + "SUN": "Diumenge", + "MON": "Dilluns", + "TUE": "Dimarts", + "WED": "Dimecres", + "THU": "Dijous", + "FRI": "Divendres", + "SAT": "Dissabte" + }, + "WEEK_DAYS_SHORT": { + "SUN": "Dg", + "MON": "Dl", + "TUE": "Dt", + "WED": "Dc", + "THU": "Dj", + "FRI": "Dv", + "SAT": "Ds" + } + }, + "TAGS": { + "PLACEHOLDER": "Afegir tag", + "DELETE": "Esborrar tag", + "ADD": "Afegit tag" + }, + "DESCRIPTION": { + "EMPTY": "Els espai buit es molt aburrit. Sé descriptiu!", + "NO_DESCRIPTION": "Sense descripció" + }, + "FIELDS": { + "SUBJECT": "Descripció", + "NAME": "Nom", + "URL": "URL", + "DESCRIPTION": "Descripció", + "VALUE": "Valor", + "SLUG": "Slug", + "COLOR": "Color", + "IS_CLOSED": "Està tancat?", + "STATUS": "Estatus", + "TYPE": "Tipus", + "SEVERITY": "Severitat", + "PRIORITY": "Prioritat", + "ASSIGNED_TO": "Assignat a", + "POINTS": "Punts", + "BLOCKED_NOTE": "Nota de bloqueig", + "IS_BLOCKED": "està bloquejat" + }, + "ROLES": { + "ALL": "Tot" + }, + "ASSIGNED_TO": { + "NOT_ASSIGNED": "Sense assignar", + "DELETE_ASSIGNMENT": "Esborrar assignament", + "REMOVE_ASSIGNED": "Esborra assignat", + "TOO_MANY": ".. massa usuaris, segueix filtrant", + "CONFIRM_UNASSIGNED": "Segut que vols deixar-ho sense assignar?", + "TITLE_ACTION_EDIT_ASSIGNMENT": "Editar assignament" + }, + "STATUS": { + "CLOSED": "Tancat", + "OPEN": "Obert" + }, + "WATCHERS": { + "ADD": "Afegir seguidor", + "TITLE": "Seguidors", + "DELETE": "Esborrar seguidor", + "TITLE_LIGHTBOX_DELETE_WARTCHER": "Esborrar seguidor..." + }, + "CUSTOM_ATTRIBUTES": { + "CUSTOM_FIELDS": "Camps personalitzats", + "SAVE": "Salva camp personalitzat", + "EDIT": "Edita el camp personalitzat", + "DELETE": "Esborrar atribut personalitzat", + "CONFIRM_DELETE": "Recorda que tots els valors a aquest camp personalitzat seràn esborrats.
Segur que voleu continuar? " + }, + "FILTERS": { + "TITLE": "filtres", + "INPUT_PLACEHOLDER": "Descripció o referència", + "TITLE_ACTION_FILTER_BUTTON": "buscar", + "BREADCRUMB_TITLE": "tornar a categories", + "BREADCRUMB_FILTERS": "Filtres", + "BREADCRUMB_STATUS": "estatus" + }, + "WYSIWYG": { + "H1_BUTTON": "Capçcalera de primer nivel", + "H1_SAMPLE_TEXT": "El títul ací...", + "H2_BUTTON": "Capçalera de segon nivel", + "H2_SAMPLE_TEXT": "El títul ací...", + "H3_BUTTON": "Tercer nivell de capçalera", + "H3_SAMPLE_TEXT": "El títul ací...", + "BOLD_BUTTON": "Gros", + "BOLD_BUTTON_SAMPLE_TEXT": "El teu text ací...", + "ITALIC_BUTTON": "Itàlica", + "ITALIC_SAMPLE_TEXT": "El teu text ací...", + "STRIKE_BUTTON": "Tatxar", + "STRIKE_SAMPLE_TEXT": "El teu text ací...", + "BULLETED_LIST_BUTTON": "Llista ordenada", + "BULLETED_LIST_SAMPLE_TEXT": "El teu text ací...", + "NUMERIC_LIST_BUTTON": "Llista numèrica", + "NUMERIC_LIST_SAMPLE_TEXT": "El teu text ací...", + "PICTURE_BUTTON": "Foto", + "PICTURE_SAMPLE_TEXT": "El text alternatiu a la foto ací", + "LINK_BUTTON": "Enllaç", + "LINK_SAMPLE_TEXT": "El teu text per al link ací...", + "QUOTE_BLOCK_BUTTON": "Bloc de cita", + "QUOTE_BLOCK_SAMPLE_TEXT": "El teu text ací...", + "CODE_BLOCK_BUTTON": "Bolc de codi", + "CODE_BLOCK_SAMPLE_TEXT": "El teu text ací...", + "PREVIEW_BUTTON": "Previsualitzar", + "EDIT_BUTTON": "Editar", + "MARKDOWN_HELP": "Ajuda de Markdown" + }, + "PERMISIONS_CATEGORIES": { + "SPRINTS": { + "NAME": "Sprints", + "VIEW_SPRINTS": "Vore sprints", + "ADD_SPRINTS": "Afegir sprint", + "MODIFY_SPRINTS": "Editar sprint", + "DELETE_SPRINTS": "Esborrar sprints" + }, + "USER_STORIES": { + "NAME": "Històries d'usuari", + "VIEW_USER_STORIES": "Vore istòries d'usuari", + "ADD_USER_STORIES": "Afegir històries d'usuari", + "MODIFY_USER_STORIES": "Editar història d'usuari", + "DELETE_USER_STORIES": "Esborrar històries d'usuari" + }, + "TASKS": { + "NAME": "Tasques", + "VIEW_TASKS": "Vore tasca", + "ADD_TASKS": "Afegit tasques", + "MODIFY_TASKS": "Modificar tasques", + "DELETE_TASKS": "Esborrar tasques" + }, + "ISSUES": { + "NAME": "Incidències", + "VIEW_ISSUES": "Vore incidències", + "ADD_ISSUES": "Afegir incidències", + "MODIFY_ISSUES": "Modificar incidències", + "DELETE_ISSUES": "Esborrar incidències" + }, + "WIKI": { + "NAME": "Wiki", + "VIEW_WIKI_PAGES": "Vore pàgines de Wiki", + "ADD_WIKI_PAGES": "Afegir pàgines de Wiki", + "MODIFY_WIKI_PAGES": "Modificar pàgina del Wiki", + "DELETE_WIKI_PAGES": "Esborrar pàgines de Wiki", + "VIEW_WIKI_LINKS": "Vore enllaços de Wiki", + "ADD_WIKI_LINKS": "Afegir link de wiki", + "DELETE_WIKI_LINKS": "Esborrar enllaços de wiki" + } + } + }, + "AUTH": { + "INVITED_YOU": "T'ha convidat a participar en el projecte", + "NOT_REGISTERED_YET": "No t'has registrat encara?", + "REGISTER": "Registrat", + "CREATE_ACCOUNT": "Crea el teu conter gratis ací" + }, + "ATTACHMENT": { + "SECTION_NAME": "Adjunts", + "TITLE": "{{ fileName }} pujat el {{ date }}", + "DESCRIPTION": "Escriu una descripció curta", + "DEPRECATED": "(deprecated)", + "DEPRECATED_FILE": "Obsolet?", + "ADD": "Afegir nou adjunt. <%- maxFileSizeMsg %>", + "MAX_FILE_SIZE": "[Max. grandària: {{maxFileSize}}]", + "SHOW_DEPRECATED": "+ mostra els adjunts obsolets", + "HIDE_DEPRECATED": "- Amagar els adjunts obsolets", + "COUNT_DEPRECATED": "({{ counter }} deprecated)", + "MAX_UPLOAD_SIZE": "El tamany màxim de pujada es ", + "DATE": "DD MMM YYYY [at] hh:mm", + "ERROR_UPLOAD_ATTACHMENT": "No hem pogut pujar '{{fileName}}'. {{errorMessage}}", + "TITLE_LIGHTBOX_DELETE_ATTACHMENT": "Esborrar adjunt...", + "MSG_LIGHTBOX_DELETE_ATTACHMENT": "l'adjunt '{{fileName}}'", + "ERROR_DELETE_ATTACHMENT": "No hem pogut esborrar: {{errorMessage}}", + "FIELDS": { + "IS_DEPRECATED": "es obsolet" + } + }, + "PAGINATION": { + "PREVIOUS": "Abans", + "NEXT": "Següent" + }, + "ADMIN": { + "COMMON": { + "TITLE_ACTION_EDIT_VALUE": "Editar valor", + "TITLE_ACTION_DELETE_VALUE": "Borrar valor" + }, + "HELP": "Necessites ajuda? Mira la nosta pàgina de suport!", + "PROJECT_DEFAULT_VALUES": { + "TITLE": "Valors per defecte", + "SUBTITLE": "Selecciona els valors per defecte per a tots els selectors" + }, + "MEMBERSHIPS": { + "TITLE": "Gestió de Membres", + "ADD_BUTTON": "+ Nou membre", + "ADD_BUTTON_TITLE": "Afegir nou membre" + }, + "PROJECT_EXPORT": { + "TITLE": "Exportar", + "SUBTITLE": "Exporta el teu projecte per a fer una còpia de seguretat o crear un nou basat en aquest", + "EXPORT_BUTTON": "Exportar", + "EXPORT_BUTTON_TITLE": "Exporta el teu projecte", + "LOADING_TITLE": "Estem generant el teu fitxer", + "DUMP_READY": "El fitxer de daes està llest!", + "LOADING_MESSAGE": "Per favor no tanquest aquest pàgina", + "ASYNC_MESSAGE": "T'enviarem un correu quan estiga llest.", + "SYNC_MESSAGE": "Si la descàrrega no baixa directament clica ací.", + "ERROR": "Els Oompa Loompas tenen problemes generant el teu arxiu de dades. Per favor intenta-ho de nou.", + "ERROR_BUSY": "Ho sentim, els Oompa Loompas estàn molt ocupats ara mateix. Intenta-ho de nou en uns moments.", + "ERROR_MESSAGE": "Els Oompa Loompas tenen problemes generant el teu arxiu de dades: {{message}}" + }, + "MODULES": { + "TITLE": "Mòdules", + "ENABLE": "Activa", + "DISABLE": "Desactiva", + "BACKLOG": "Backlog", + "BACKLOG_DESCRIPTION": "Organitza les històries d'usuari per a mantindre una vista organitzada i prioritzada del treball.", + "KANBAN": "Kanban", + "KANBAN_DESCRIPTION": "Organitza els projectes de un mode sencill amb aquest tauler", + "ISSUES": "Incidències", + "ISSUES_DESCRIPTION": "Gestiona els bugs, questions i milores del teu projecte. No te pergues res!", + "WIKI": "Wiki", + "WIKI_DESCRIPTION": "Afegix, modifica o borra contingut en col3laboració amb altres. Aquest es el lloc correcte per a la teua documentació.", + "MEETUP": "Trobar-se", + "MEETUP_DESCRIPTION": "Tria el teu sistema de videonconferéncia. Inclosos els desenvolupadors necessitan contacte cara a cara", + "SELECT_VIDEOCONFERENCE": "Selecciona un sistema de videconferència", + "SALT_CHAT_ROOM": "Pots afegir un code salt a la sala de xat" + }, + "PROJECT_PROFILE": { + "PAGE_TITLE": "Perfil de projecte - {{sectionName}} - {{projectName}}", + "PROJECT_DETAILS": "Detalls de projecte", + "PROJECT_NAME": "Nom del projecte", + "PROJECT_SLUG": "Slug de projecte", + "NUMBER_SPRINTS": "Nombre de sprints", + "NUMBER_US_POINTS": "Nombre de punts de US", + "TAGS": "Tags", + "DESCRIPTION": "Descripció", + "PUBLIC_PROJECT": "Projecte públic", + "PRIVATE_PROJECT": "Projecte privat", + "DELETE": "Esborra aquest projecte" + }, + "REPORTS": { + "TITLE": "Informes", + "SUBTITLE": "Exporta les dades del teu projecte en CSV i fes els teus propis informes.", + "DESCRIPTION": "Descarrega el fitxer CSV o copia la URL generada o obri-la amb el teu editor de text o fulla de càlcul per a fer els teus propis informes. Podràs visualitzar i analitzar les dades fàcilment.", + "HELP": "Com utilitzar açó a la meu fulla de càlcul?", + "REGENERATE_TITLE": "Canviar URL", + "REGENERATE_SUBTITLE": "Vas a canviar la URL d'accés al CSV. La URL previa no funcionarà. Estàs segur?" + }, + "CSV": { + "SECTION_TITLE_US": "user stories reports", + "SECTION_TITLE_TASK": "infome de tasques", + "SECTION_TITLE_ISSUE": "informe d'incidències", + "DOWNLOAD": "Descarrega el CSV", + "URL_FIELD_PLACEHOLDER": "Per favor regenera la url del CSV", + "TITLE_REGENERATE_URL": "Regenera l'Url del CSV", + "ACTION_GENERATE_URL": "Genera URL", + "ACTION_REGENERATE": "Regenerar" + }, + "CUSTOM_FIELDS": { + "TITLE": "Camps personalitzats", + "SUBTITLE": "Especifica els camps personalitzats del les teues históries d'usuari, tasques e incidències", + "US_DESCRIPTION": "Camps personalitzats d'històries d'usuari", + "US_ADD": "Afegeix camps personalitzats en històries d'usuari", + "TASK_DESCRIPTION": "Camps personalitzats de tasques", + "TASK_ADD": "Afegix camps personalitzats en tasques", + "ISSUE_DESCRIPTION": "Camps personalitzats d'incidències", + "ISSUE_ADD": "Afegix camps personalitzats en incidències" + }, + "PROJECT_VALUES": { + "APP_TITLE": "Valors de projecte - {{sectionName}} - {{projectName}}", + "REPLACEMENT": "Tots els elements amb aquest valor seràn canviats a", + "ERROR_DELETE_ALL": "No pots esborrar tots els valors." + }, + "PROJECT_VALUES_POINTS": { + "TITLE": "Punts d'US", + "SUBTITLE": "Especifica els punts en els que poden ser estimades les històries d'usuari", + "ACTION_ADD": "Afegir punts nous" + }, + "PROJECT_VALUES_PRIORITIES": { + "TITLE": "Prioritats d'incidències", + "SUBTITLE": "Especifica les prioritats que tindran les teues tasques", + "ACTION_ADD": "Add new priority" + }, + "PROJECT_VALUES_SEVERITIES": { + "TITLE": "Severitat d'incidències", + "SUBTITLE": "Especifica les severitats que tindran les teues incidències", + "ACTION_ADD": "Add new severity" + }, + "PROJECT_VALUES_STATUS": { + "TITLE": "Estatus", + "SUBTITLE": "Especifica els estatus del les teues históries d'usuari, tasques e incidències", + "US_TITLE": "Estatus d'US", + "TASK_TITLE": "Estatus de tasques", + "ISSUE_TITLE": "Estatus d'incidències" + }, + "PROJECT_VALUES_TYPES": { + "TITLE": "Tipus", + "SUBTITLE": "Especifica quin tipus d'incidència podria ser.", + "ISSUE_TITLE": "Tipus d'incidències", + "ACTION_ADD": "Add new type" + }, + "ROLES": { + "SECTION_NAME": "Rols - {{projectName}}", + "WARNING_NO_ROLE": "Ves amb compte, cap rol en el teu projecte pot estimar punts per a les històries d'usuari", + "HELP_ROLE_ENABLED": "Si està activat, els membres assignats a aquest rol podràn estimar els punts d'històries d'usuaris", + "COUNT_MEMBERS": "{{ role.members_count }} membres amb aquest rol", + "TITLE_DELETE_ROLE": "Esborrar rol", + "REPLACEMENT_ROLE": "Tots els usuaris amb aquest rol es canviaran a", + "WARNING_DELETE_ROLE": "Atenció, totes les estimacions del rol seràn esborrades", + "ERROR_DELETE_ALL": "No pots esborrar tots els valors", + "EXTERNAL_USER": "Usuari extern" + }, + "THIRD_PARTIES": { + "SECRET_KEY": "Clau secreta", + "PAYLOAD_URL": "Payload URL", + "VALID_IPS": "IPs amb orige vàlid separades per ,)" + }, + "BITBUCKET": { + "SECTION_NAME": "Bitbucket", + "APP_TITLE": "Bitbucket - {{projectName}}", + "INFO_VERIFYING_IP": "Les peticions a Bitbuket no estan signades. El millor mode de verificar l'oritge es per IP. Si el camp està buit no hi haurà verificació per IP." + }, + "GITLAB": { + "SECTION_NAME": "Gitlab", + "APP_TITLE": "Gitlab - {{projectName}}", + "INFO_VERIFYING_IP": "Les peticions a Bitbuket no estan signades. El millor mode de verificar l'oritge es per IP. Si el camp està buit no hi haurà verificació per IP." + }, + "GITHUB": { + "SECTION_NAME": "Github", + "APP_TITLE": "Github - {{projectName}}" + }, + "WEBHOOKS": { + "APP_TITLE": "Webhooks - {{projectName}}", + "SECTION_NAME": "Webhooks", + "SUBTITLE": "Els Webhooks notifiquen serveis extens de events en taiga com comentaris, històries d'usuari...", + "ADD_NEW": "Afegir un nou Webhook", + "TYPE_NAME": "Escriu el nom del servei", + "TYPE_PAYLOAD_URL": "Escriu el service payload url", + "TYPE_SERVICE_SECRET": "Escriu la clau secreta del servei", + "SAVE": "Salvar Webhook", + "CANCEL": "Cancel·la Webhook", + "SHOW_HISTORY": "(Mostra històric)", + "TEST": "Testar Webhook", + "EDIT": "Editar Webhooks", + "DELETE": "Esborrar Webhooks", + "REQUEST": "Petició", + "RESEND_REQUEST": "Reenviar petició", + "HEADERS": "Capçaleres", + "PAYLOAD": "Payload", + "RESPONSE": "Resposta", + "DATE": "DD MMM YYYY [at] hh:mm", + "ACTION_HIDE_HISTORY": "(Amaga històric)", + "ACTION_HIDE_HISTORY_TITLE": "Amaga detalls d'històric", + "ACTION_SHOW_HISTORY": "(Mostra històric)", + "ACTION_SHOW_HISTORY_TITLE": "Mostra detall d'històric", + "WEBHOOK_NAME": "Webhook '{{name}}'" + }, + "CUSTOM_ATTRIBUTES": { + "ADD": "Afegix camp personalitzat", + "EDIT": "Edita el camp personalitzat", + "DELETE": "Esborrar camp personalitzat", + "SAVE_TITLE": "Salva camp personalitzat", + "CANCEL_TITLE": "Cancel·la la creació", + "SET_FIELD_NAME": "Escriu el nom del camp personalitzat", + "SET_FIELD_DESCRIPTION": "Escriu la descripció del camp personalitzat", + "ACTION_UPDATE": "Actualitza el camp personalitzat", + "ACTION_CANCEL_EDITION": "Cancel·la la edició" + }, + "MEMBERSHIP": { + "COLUMN_MEMBER": "Membre", + "COLUMN_ADMIN": "Admin", + "COLUMN_ROLE": "Rol", + "COLUMN_STATUS": "Estatus", + "STATUS_ACTIVE": "Actiu", + "STATUS_PENDING": "Pendent", + "DELETE_MEMBER": "Esborrar membre", + "SUCCESS_SEND_INVITATION": "Hem tornat a enviar la invitació a '{{email}}'.", + "ERROR_SEND_INVITATION": "No s'ha enviat la invitació", + "SUCCESS_DELETE": "Hem esborrat {{message}}.", + "ERROR_DELETE": "No hem pogut esborrar ", + "DEFAULT_DELETE_MESSAGE": "la invitació a '{{email}}'." + }, + "DEFAULT_VALUES": { + "LABEL_POINTS": "Valor per defecte per a selector de punts", + "LABEL_US": "Valor per defecte per a selector d'estatus d'US", + "LABEL_TASK_STATUS": "Valor per defecte per a selector d'estatus de tasques", + "LABEL_PRIORITY": "Valor per defecte per a selector de prioritat", + "LABEL_SEVERITY": "Valor per defecte per a selector de severitat", + "LABEL_ISSUE_TYPE": "Valor per defecte per a selector de tipus", + "LABEL_ISSUE_STATUS": "Valor per defecte per a selector de estatus" + }, + "STATUS": { + "PLACEHOLDER_WRITE_STATUS_NAME": "Escriu un nom per a nou estatus" + }, + "TYPES": { + "PLACEHOLDER_WRITE_NAME": "Escriu un nom per a nou element" + }, + "US_STATUS": { + "ACTION_ADD_STATUS": "Afegir estatus nou", + "IS_ARCHIVED_COLUMN": "Es arxivat?", + "WIP_LIMIT_COLUMN": "Limit WIP", + "PLACEHOLDER_WRITE_NAME": "Escriu un nom per a nou estatus" + }, + "MENU": { + "TITLE": "Admin", + "PROJECT": "Projecte", + "ATTRIBUTES": "Atributs", + "MEMBERS": "Membres", + "PERMISSIONS": "Permisos", + "INTEGRATIONS": "Integracions", + "PLUGINS": "Plugins" + }, + "SUBMENU_PROJECT_ATTRIBUTES": { + "TITLE": "Attributes" + }, + "SUBMENU_PROJECT_VALUES": { + "STATUS": "Estatus", + "POINTS": "Punts", + "PRIORITIES": "Prioritats", + "SEVERITIES": "severitats", + "TYPES": "Tipus", + "CUSTOM_FIELDS": "Camps personalitzats" + }, + "SUBMENU_PROJECT_PROFILE": { + "TITLE": "Perfil de projecte" + }, + "SUBMENU_ROLES": { + "TITLE": "Rols", + "ACTION_NEW_ROLE": "+ Nou rol", + "TITLE_ACTION_NEW_ROLE": "Afegir nou rol" + }, + "SUBMENU_THIDPARTIES": { + "TITLE": "Serveis" + } + }, + "PROJECT": { + "WELCOME": "Benvinguts", + "SECTION_PROJECTS": "Projectes", + "STATS": { + "PROJECT": "punts
projecte", + "DEFINED": "punts
definits", + "ASSIGNED": "punts
assignats", + "CLOSED": "punts
tancats" + }, + "SECTION": { + "SEARCH": "Buscar", + "BACKLOG": "Backlog", + "KANBAN": "Kanban", + "ISSUES": "Incidències", + "WIKI": "Wiki", + "TEAM": "Equip", + "MEETUP": "Trobar-se", + "ADMIN": "Admin" + }, + "NAVIGATION": { + "SECTION_TITLE": "Els teus projectes", + "PLACEHOLDER_SEARCH": "Buscar en...", + "ACTION_CREATE_PROJECT": "Crear projecte", + "TITLE_ACTION_IMPORT": "Importar projecte", + "TITLE_PRVIOUS_PROJECT": "Mostra projectes previs", + "TITLE_NEXT_PROJECT": "Mostrar próxims projectes" + }, + "IMPORT": { + "TITLE": "Important Projecte", + "UPLOADING_FILE": "Uploading dump file", + "DESCRIPTION": "Aquest procés pot durar una mica, pero favor mantinga la finestra oberta", + "ASYNC_IN_PROGRESS_TITLE": "Els Oompa Loompas estàn important el teu projecte", + "ASYNC_IN_PROGRESS_MESSAGE": "Aquest procés pot durar uns moments
T'enviarem un correo quan estiga llest.", + "UPLOAD_IN_PROGRESS_MESSAGE": "Pujat {{uploadedSize}} de {{totalSize}}", + "ERROR": "Els Oompa Loompas han tingut problemes pujan les teues dades. Per favor intenta-ho de nou.", + "ERROR_TOO_MANY_REQUEST": "Ho sentim, els Oompa Loompas estàn molt ocupats ara mateix. Intenta-ho de nou en uns moments.", + "ERROR_MESSAGE": "Els Oompa Loompas tenen problemes important les teues dades: {{error_message}}", + "ERROR_MAX_SIZE_EXCEEDED": "'{{fileName}}' ({{fileSize}}) es massa gran per als nostres Oompa Loompas, prova amb algun inferior a ({{maxFileSize}})", + "SYNC_SUCCESS": "El teu projecte s'ha importat correctament" + } + }, + "LIGHTBOX": { + "DELETE_ACCOUNT": { + "SECTION_NAME": "Esborrar compte de Taiga", + "CONFIRM": "Segur que vols borrar el teu compte de Taiga? ", + "SUBTITLE": "Te trobarem a faltar! :-(", + "NEWSLETTER_LABEL_TEXT": "I don't wanna receive your newsletter anymore" + }, + "DELETE_PROJECT": { + "TITLE": "Esborrar projecte", + "QUESTION": "Estàs segur que vols borrar este projecte?", + "SUBTITLE": "Totes les dades del projecte (històries d'usuari, tasques, incidències, wikis) es perdràn :-(", + "CONFIRM": "Si, estic segur" + }, + "ASSIGNED_TO": { + "SELECT": "Selecciona assignació", + "SEARCH": "Buscar usuaris" + }, + "ADD_MEMBER": { + "TITLE": "Nou membre", + "HELP_TEXT": "Si els usuaris ja estàn registrats en Taiga seràn afegits automàticament. Si no, rebran una invitació." + }, + "CREATE_ISSUE": { + "TITLE": "Afegir incidència" + }, + "FEEDBACK": { + "TITLE": "Contans...", + "COMMENT": "...un bug, una sugerència, algo bonic... inclús el teu pitjor malson amb Taiga.", + "ACTION_SEND": "Enviar sugerències" + }, + "SEARCH": { + "TITLE": "Buscar", + "PLACEHOLDER_SEARCH": "Què estàs buscant?" + }, + "ADD_EDIT_SPRINT": { + "TITLE": "Nou sprint", + "PLACEHOLDER_SPRINT_NAME": "Nom de Sprint", + "PLACEHOLDER_SPRINT_START": "Data d'inici", + "PLACEHOLDER_SPRINT_END": "Data de finalització", + "ACTION_DELETE_SPRINT": "Vols esborrar aquest sprint?", + "TITLE_ACTION_DELETE_SPRINT": "Esborra sprint", + "LAST_SPRINT_NAME": "L'ultim sprint ès {{lastSprint}} ;-) " + }, + "CREATE_EDIT_TASK": { + "TITLE": "Nova tasca", + "PLACEHOLDER_SUBJECT": "Descripció de tasca", + "PLACEHOLDER_STATUS": "Estatus de tasca", + "OPTION_UNASSIGNED": "Sense assignar", + "PLACEHOLDER_SHORT_DESCRIPTION": "Escriu una descripció curta", + "ACTION_EDIT": "Editar tasca" + }, + "CREATE_EDIT_US": { + "TITLE": "Nova US", + "PLACEHOLDER_DESCRIPTION": "Per favor afegix una descripció per que altres puguen entendre millor aquesta US", + "NEW_US": "Nova història d'usuari", + "EDIT_US": "Edita història d'usuari" + }, + "DELETE_SPRINT": { + "TITLE": "Esborrar sprint" + }, + "CREATE_MEMBER": { + "PLACEHOLDER_INVITATION_TEXT": "(Opcional) Afegix un text personalizat a la invitació. Dis-li algo divertit als nous membres. ;-)", + "PLACEHOLDER_TYPE_EMAIL": "Escriu un correu" + } + }, + "US": { + "SECTION_NAME": "User story details", + "LINK_TASKBOARD": "Panell de tasques", + "TITLE_LINK_TASKBOARD": "Anar a panell de tasques", + "TOTAL_POINTS": "total", + "ADD": "+ Afegir nova història d'usuari", + "ADD_BULK": "Afegeix noves històries d'usuari en grup", + "PROMOTED": "Aquesta US ha sigut promocionada desde:", + "TITLE_LINK_GO_TO_ISSUE": "Anar a la incidència", + "EXTERNAL_REFERENCE": "Aquesta US ha sigut creada desde", + "GO_TO_EXTERNAL_REFERENCE": "Anar a l'orige", + "BLOCKED": "Aquest història d'usuari està bloquejada", + "PREVIOUS": "previa història d'usuari", + "NEXT": "Pròxima història d'usuari", + "TITLE_DELETE_ACTION": "Esborra història d'usuari", + "LIGHTBOX_TITLE_BLOKING_US": "Bloquejant US", + "TASK_COMPLETED": "{{totalClosedTasks}}/{{totalTasks}} tasques completades", + "ASSIGN": "Assigna història d'usuari", + "NOT_ESTIMATED": "Sense estimar", + "TOTAL_US_POINTS": "Punts totals d'US", + "FIELDS": { + "TEAM_REQUIREMENT": "Requeriment d'equip", + "CLIENT_REQUIREMENT": "Requeriment de client", + "FINISH_DATE": "Data de finalització" + } + }, + "COMMENTS": { + "DELETED_INFO": "Comentari esborrat per {{user}} el {{date}}", + "TITLE": "Comentaris", + "COMMENT": "Comentar", + "TYPE_NEW_COMMENT": "Escriu un nou comentari ací", + "SHOW_DELETED": "Mostra el comentari esborrat.", + "HIDE_DELETED": "Amaga el comentari esborrat", + "RESTORE": "Resturar comentari." + }, + "ACTIVITY": { + "SHOW_ACTIVITY": "Mostrar activitat", + "DATETIME": "DD MMM YYYY HH:mm", + "SHOW_MORE": "+ Mostrar activitat anterior ({{showMore}} més)", + "TITLE": "Activitat", + "REMOVED": "Borrat", + "ADDED": "Afegit", + "US_POINTS": "Punts d'US ({{name}})", + "NEW_ATTACHMENT": "Nou adjunt", + "DELETED_ATTACHMENT": "Adjunts esborrats", + "UPDATED_ATTACHMENT": "Actualitzat adjunt {{filename}}", + "DELETED_CUSTOM_ATTRIBUTE": "Esborrar camps personalitzat", + "SIZE_CHANGE": "Fet {size, plural, one{un canvi} other{# changes}}", + "VALUES": { + "YES": "si", + "NO": "no", + "EMPTY": "buit", + "UNASSIGNED": "Sense assignar" + }, + "FIELDS": { + "SUBJECT": "descripció", + "NAME": "nom", + "DESCRIPTION": "descripció", + "CONTENT": "Contingut", + "STATUS": "Estatus", + "IS_CLOSED": "tancat", + "FINISH_DATE": "Data de finalització", + "TYPE": "tipus", + "PRIORITY": "prioritat", + "SEVERITY": "severitat", + "ASSIGNED_TO": "Assignat a", + "WATCHERS": "Seguidors", + "MILESTONE": "sprint", + "USER_STORY": "història d'usuari", + "PROJECT": "projecte", + "IS_BLOCKED": "Està bloquejat", + "BLOCKED_NOTE": "Nota de bloqueig", + "POINTS": "punts", + "CLIENT_REQUIREMENT": "requeriment de client", + "TEAM_REQUIREMENT": "requeriment d'equip", + "IS_IOCAINE": "Es iocaina", + "TAGS": "tags", + "ATTACHMENTS": "adjunts", + "IS_DEPRECATED": "és obsolet", + "ORDER": "ordre", + "BACKLOG_ORDER": "ordre de backlog", + "SPRINT_ORDER": "ordre d'sprint", + "KANBAN_ORDER": "ordre de kanban", + "TASKBOARD_ORDER": "ordre de panell de tasques", + "US_ORDER": "ordre d'US" + } + }, + "BACKLOG": { + "SECTION_NAME": "Backlog", + "MOVE_US_TO_CURRENT_SPRINT": "Envia al Sprint", + "SHOW_FILTERS": "Mostra filtres", + "SHOW_TAGS": "Mostrar tags", + "EMPTY": "El teu backlog està buit!", + "CREATE_NEW_US": "Crea una nova US", + "CREATE_NEW_US_EMPTY_HELP": "Potser vols crear una nova història d'usuari", + "EXCESS_OF_POINTS": "Excés de punts", + "PENDING_POINTS": "Punts pendents", + "CLOSED_POINTS": "tancat", + "COMPACT_SPRINT": "Compacta Sprint", + "GO_TO_TASKBOARD": "Anar al panell de {{::name}}", + "EDIT_SPRINT": "Editar sprint", + "TOTAL_POINTS": "total", + "STATUS_NAME": "Nom d'estatus", + "SORTABLE_FILTER_ERROR": "No pots portar al backlog si els filtres estàn oberts", + "DOOMLINE": "Extensió de projecte [Doomline]", + "CHART": { + "XAXIS_LABEL": "Sprints", + "YAXIS_LABEL": "Punts", + "OPTIMAL": "Punts pendent òptims per sprint {{xval}} deuría ser {{yval}}", + "REAL": "Punts pendent reals per sprint {{xval}} es {{yval}}", + "INCREMENT_TEAM": "Punts incrementats per requeriment de l'equip per sprint {{xval}} és {{yval}}", + "INCREMENT_CLIENT": "Punts incrementat per requeriment de client {{xval}} és {{yval}}" + }, + "TAGS": { + "TOGGLE": "Toggle tags visibility", + "SHOW": "Mostrar tags", + "HIDE": "Amaga tags" + }, + "TABLE": { + "COLUMN_US": "Històries d'usuari", + "TITLE_COLUMN_POINTS": "Selecciona vista per rol" + }, + "SPRINT_SUMMARY": { + "TOTAL_POINTS": "punts
totals", + "COMPLETED_POINTS": "punts
completats", + "OPEN_TASKS": "tasques
obertes", + "CLOSED_TASKS": "tasques
tancades", + "IOCAINE_DOSES": "dosis
iocaína", + "SHOW_STATISTICS_TITLE": "Mostrar estadístiques" + }, + "SUMMARY": { + "PROJECT_POINTS": "punts
projecte", + "DEFINED_POINTS": "punts
definits", + "CLOSED_POINTS": "punts
tancats", + "POINTS_PER_SPRINT": "punts
sprint" + }, + "FILTERS": { + "TOGGLE": "Toggle filters visibility", + "TITLE": "Filtres", + "REMOVE": "Esborra filtres", + "HIDE": "Hide Filters", + "SHOW": "Mostra filtres", + "FILTER_CATEGORY_STATUS": "Estatus", + "FILTER_CATEGORY_TAGS": "Tags" + }, + "SPRINTS": { + "TITLE": "SPRINTS", + "DATE": "DD MMM YYYY", + "LINK_TASKBOARD": "Anar al panell de sprint", + "TITLE_LINK_TASKBOARD": "Anar al panell de {{::name}}", + "NUMBER_SPRINTS": "
sprints", + "TITLE_ACTION_NEW_SPRINT": "+ Nou sprint", + "ACTION_NEW_SPRINT": "+ Nou sprint", + "ACTION_SHOW_CLOSED_SPRINTS": "Mostra sprints tancats", + "ACTION_HIDE_CLOSED_SPRINTS": "Amaga sprints tancats" + } + }, + "ERROR": { + "TEXT1": "Ha passat algo i els nostres Oompa Loompas estàn arreglant-ho.", + "TEXT2": "Prova a recarregar de nou", + "NOT_FOUND": "No trobat", + "NOT_FOUND_TEXT": "Error 404. La pàgina que busques no existeix. Pots tornar a la página principal de taiga i provar desde allí.", + "PERMISSION_DENIED": "Permis denegat", + "PERMISSION_DENIED_CODE": "Error 403", + "VERSION_ERROR": "Algú dins de Taiga ha canviat aȯ abans i els Oompa Loompas no pode aplicar els teus canvis. Per favor recarrega i aplica els teus canvis (es perdràn)" + }, + "TASKBOARD": { + "SECTION_NAME": "Panell de tasques", + "TITLE_ACTION_ADD": "Afegir nova tasca", + "TITLE_ACTION_ADD_BULK": "Afegeix noves històries d'usuari en grup", + "TITLE_ACTION_ASSIGN": "Assignar tasca", + "TITLE_ACTION_EDIT": "Editar tasca", + "TABLE": { + "COLUMN": "Història d'usuari", + "TITLE_ACTION_FOLD": "Plegar columna", + "TITLE_ACTION_UNFOLD": "Desplegar columna", + "TITLE_ACTION_FOLD_ROW": "Plegar fila", + "TITLE_ACTION_UNFOLD_ROW": "Desplegar fila", + "FIELD_POINTS": "punts", + "ROW_UNASSIGED_TASKS_TITLE": "Tasques sense assignar" + }, + "CHARTS": { + "XAXIS_LABEL": "Díes", + "YAXIS_LABEL": "Punts", + "OPTIMAL": "Punts pendents òptims per dia {{formattedDate}} deu ser {{roundedValue}}", + "REAL": "Punts pendents el dia {{formattedDate}} son {{roundedValue}}", + "DATE": "DD MMMM YYYY" + } + }, + "TASK": { + "SECTION_NAME": "Task details", + "LINK_TASKBOARD": "Panell de tasques", + "TITLE_LINK_TASKBOARD": "Anar a panell de tasques", + "PLACEHOLDER_SUBJECT": "Afegix la descripció de la tasca", + "TITLE_SELECT_STATUS": "Nom d'estatus", + "OWNER_US": "Aquesta tasca pertany a", + "TITLE_LINK_GO_OWNER": "Anar a història d'usuari", + "ORIGIN_US": "Aquesta tasca ha sigut creada desde", + "TITLE_LINK_GO_ORIGIN": "Anar a història d'usuari", + "BLOCKED": "Aquesta tasca està bloquejada", + "PREVIOUS": "tasca prèvia", + "NEXT": "pròxima tasca", + "TITLE_DELETE_ACTION": "Esborrar tasca", + "LIGHTBOX_TITLE_BLOKING_TASK": "Bloquejant tasca", + "FIELDS": { + "MILESTONE": "Sprint", + "USER_STORY": "Història d'usuari", + "IS_IOCAINE": "Es iocaina" + }, + "ACTION_IOCAINE": "Iocaína", + "TITLE_ACTION_IOCAINE": "Un poc saturat per una tasca? Fes-ho saber als teus companys clicant a Iocaina quan edites la tasca. Es possible ser inmune a aquesta (fictícia) poció mortal consumint xicotetes dòsis poc a poc, així com es possible millorar amb xicotets nous desafiaments!" + }, + "NOTIFICATION": { + "OK": "Tot està ok", + "WARNING": "Oops, ha passat algo...", + "WARNING_TEXT": "Els teus canvis no s'han salvat!", + "SAVED": "Els Oompa Loompas han salvat els teus canvis!", + "CLOSE": "Tancar notificació", + "MAIL": "Notificaciones per correo", + "ASK_DELETE": "Segur que vols borrar?" + }, + "CANCEL_ACCOUNT": { + "TITLE": "Cancel·la el teu conter ací", + "SUBTITLE": "Sentim molt que deixes Taiga, esperem que hages disfrutat la teua estància :)", + "PLACEHOLDER_INPUT_TOKEN": "Cancela token de conter", + "ACTION_LEAVING": "Sí, m'hen vaig!", + "SUCCESS": "Els Oompa Loompas han esborrat el teu conter" + }, + "CHANGE_EMAIL_FORM": { + "TITLE": "Canvia el teu correu", + "SUBTITLE": "Un click més i el teu correu estarà actualitzat!", + "PLACEHOLDER_INPUT_TOKEN": "Canvia el token de correu", + "ACTION_CHANGE_EMAIL": "Canviar correu", + "SUCCESS": "Els Oompa Loompas han actualitzat el teu correu" + }, + "CHANGE_PASSWORD_RECOVERY_FORM": { + "TITLE": "Crea un nou password", + "SUBTITLE": "Menja un poc més de ferro, es bo pel cervell :P ", + "PLACEHOLDER_RECOVER_PASSWORD_TOKEN": "Recuperar token de contrasenya", + "LINK_NEED_TOKEN": "Neccesites un?", + "TITLE_LINK_NEED_TOKEN": "Necessites un token per a recuperar la teua contrasenya perque l'has oblidat?", + "PLACEHOLDER_NEW_PASSWORD": "nova contrasenya", + "PLACEHOLDER_RE_TYPE_NEW_PASSWORD": "Reescriu la nova contrasenya", + "ACTION_RESET_PASSWORD": "Resetejar contrasenya", + "SUCCESS": "Els Oompa Loompas han salvat la teua contrasenya
Prova a entrar amb ella." + }, + "FORGOT_PASSWORD_FORM": { + "TITLE": "Oops, has oblidat la teua contrasenya?", + "SUBTITLE": "Escriu el teu mot d'usuari o correo per a conseguir uno nou", + "PLACEHOLDER_FIELD": "Mot d'usuari i correu", + "ACTION_RESET_PASSWORD": "Resetejar contrasenya", + "LINK_CANCEL": "No, portam enrere, crec que ho recorde.", + "SUCCESS": "Mira el teu correu!
Hem enviat un correu amb les instrucciones per a setejar una nova contrasenya.", + "ERROR": "Segons els nostres Oompa Loompas, no estàs registrat encara." + }, + "LOGIN_COMMON": { + "HEADER": "Ja tinc un conter de Taiga", + "PLACEHOLDER_AUTH_NAME": "Mot d'usuari i correu (sensible a majúscules i minúscules)", + "LINK_FORGOT_PASSWORD": "L'has oblidat?", + "TITLE_LINK_FORGOT_PASSWORD": "Has oblidat la teua contrasenya?", + "ACTION_ENTER": "Entrar", + "ACTION_SIGN_IN": "Entrar", + "PLACEHOLDER_AUTH_PASSWORD": "Contrasenya (sensible a majúscules i minúscules)" + }, + "LOGIN_FORM": { + "ERROR_AUTH_INCORRECT": "Segons els Oompa Loompas el teu mot d'usuari/correu o contrasenya sòn incorrectes.", + "ERROR_GENERIC": "Segons els Oompa Loompas ha hagut un error.", + "SUCCESS": "Our Oompa Loompas están contents, benvinguts a Taiga." + }, + "INVITATION_LOGIN_FORM": { + "NOT_FOUND": "Ooops, ha hagut un problema
Els nosters Oompa Loompas no troben la teua invitació.", + "SUCCESS": "T'has incorporat a este projecte. Vos donem la benvinguda a {{project_name}}", + "ERROR": "Segons els nostres OOmpa Loompas, no estàs registrat encara o has escrit una contrasenya invàlida." + }, + "REGISTER_FORM": { + "TITLE": "Register a new Taiga account (free)", + "PLACEHOLDER_NAME": "Tria un mot d'usuari (sensible a majúscules i minúscules)", + "PLACEHOLDER_FULL_NAME": "Escriu el teu nom complet", + "PLACEHOLDER_EMAIL": "El teu correu", + "PLACEHOLDER_PASSWORD": "Tria una contrasenya(sensible a majúscules i minúscules)", + "ACTION_SIGN_UP": "Registrar-se", + "TITLE_LINK_LOGIN": "Entrar", + "LINK_LOGIN": "Ja estàs registrat? Entra" + }, + "ISSUES": { + "LIST_SECTION_NAME": "Incidències", + "SECTION_NAME": "Issue details", + "ACTION_NEW_ISSUE": "+ NOVA INCIDÈNCIA", + "ACTION_PROMOTE_TO_US": "Promocionar història d'usuari", + "PLACEHOLDER_FILTER_NAME": "Escriu el filtre i pressiona Intro", + "PROMOTED": "Esta incidència ha sigut promcionada a US:", + "EXTERNAL_REFERENCE": "Esta incidència ha sigut creada desde", + "GO_TO_EXTERNAL_REFERENCE": "Anar a l'orige", + "BLOCKED": "Aquesta incidència està bloquejada", + "TITLE_PREVIOUS_ISSUE": "incidència prèvia", + "TITLE_NEXT_ISSUE": "pròxima incidència", + "ACTION_DELETE": "Esborrar incidència", + "LIGHTBOX_TITLE_BLOKING_ISSUE": "Bloquejant incidència", + "CONFIRM_PROMOTE": { + "TITLE": "Promociona aquesta incidència a història d'usuari", + "MESSAGE": "Segur que vols crear una nova US desde aquesta incidència" + }, + "FILTERS": { + "TITLE": "Filtres", + "INPUT_SEARCH_PLACEHOLDER": "Descripció o ref", + "TITLE_ACTION_SEARCH": "Busca", + "ACTION_SAVE_CUSTOM_FILTER": "Guarda com a filtre", + "BREADCRUMB": "Filtres", + "TITLE_BREADCRUMB": "Filtres", + "CATEGORIES": { + "TYPE": "Tipus", + "STATUS": "Estatus", + "SEVERITY": "Severitat", + "PRIORITIES": "Prioritats", + "TAGS": "Tags", + "ASSIGNED_TO": "Assignat a", + "CREATED_BY": "Creat per", + "CUSTOM_FILTERS": "Filtres personalitzats" + }, + "CONFIRM_DELETE": { + "TITLE": "Esborrar filtre", + "MESSAGE": "el filtre '{{customFilterName}}'" + } + }, + "TABLE": { + "COLUMNS": { + "TYPE": "Tipus", + "SEVERITY": "Severitat", + "PRIORITY": "Prioritat", + "SUBJECT": "Descripció", + "STATUS": "Estatus", + "CREATED": "Creat", + "ASSIGNED_TO": "Assignat a" + }, + "TITLE_ACTION_CHANGE_STATUS": "Canviar estatus", + "TITLE_ACTION_ASSIGNED_TO": "Assignat a", + "EMPTY": { + "TITLE": "No hi ha incidències a reportar :-)", + "SUBTITLE": "Has trobat una incidència?", + "ACTION_CREATE_ISSUE": "Crea nova incidència" + } + } + }, + "KANBAN": { + "SECTION_NAME": "Kanban", + "TITLE_ACTION_FOLD": "Plegar columna", + "TITLE_ACTION_UNFOLD": "Desplegar columna", + "TITLE_ACTION_FOLD_CARDS": "Plegar targeta", + "TITLE_ACTION_UNFOLD_CARDS": "Desplegar targetes", + "TITLE_ACTION_ADD_US": "Afegir història d'usuari", + "TITLE_ACTION_ADD_BULK": "Afegir en grup", + "ACTION_SHOW_ARCHIVED": "Mostrar arxivats", + "ACTION_HIDE_ARCHIVED": "Amagar arxivats", + "HIDDEN_USER_STORIES": "Les històries d'usuar en aques estatus estàn amagades", + "ARCHIVED": "Has arxivat", + "UNDO_ARCHIVED": "Arrastra de nou per desfer" + }, + "SEARCH": { + "FILTER_USER_STORIES": "Històries d'usuari", + "FILTER_ISSUES": "Incidències", + "FILTER_TASKS": "Tasca", + "FILTER_WIKI": "Pàgines de Wiki", + "PLACEHOLDER_SEARCH": "Buscar en...", + "TITLE_ACTION_SEARCH": "buscar", + "EMPTY_TITLE": "Pareix que no hem trobat res amb este criteri de recerca", + "EMPTY_DESCRIPTION": "Prova amb una de les pestanyes o busca de nou" + }, + "TEAM": { + "SECTION_NAME": "Equip", + "APP_TITLE": "EQUIP - {{projectName}}", + "PLACEHOLDER_INPUT_SEARCH": "Busca per nom complet...", + "COLUMN_MR_WOLF": "Mr. Wolf", + "EXPLANATION_COLUMN_MR_WOLF": "Incidències tancades", + "COLUMN_IOCAINE": "Beguedor de iocaína", + "EXPLANATION_COLUMN_IOCAINE": "Dosis de iocaina ingerides", + "COLUMN_CERVANTES": "Cervantes", + "EXPLANATION_COLUMN_CERVANTES": "Pàgines de Wiki editades", + "COLUMN_BUG_HUNTER": "Caçador de bug", + "EXPLANATION_COLUMN_BUG_HUNTER": "Incidència reportada", + "COLUMN_NIGHT_SHIFT": "Torn de nit", + "EXPLANATION_COLUMN_NIGHT_SHIFT": "Tasques tancades", + "COLUMN_TOTAL_POWER": "Punts totals", + "EXPLANATION_COLUMN_TOTAL_POWER": "Punts totals", + "SECTION_TITLE_TEAM": "Equip >", + "SECTION_FILTER_ALL": "Tot", + "CONFIRM_LEAVE_PROJECT": "Segur que vols deixar el projecte?", + "ACTION_LEAVE_PROJECT": "Abandonar aquest projecte" + }, + "CHANGE_PASSWORD": { + "SECTION_NAME": "Canviar contrasenya", + "FIELD_CURRENT_PASSWORD": "Contrasenya actual", + "PLACEHOLDER_CURRENT_PASSWORD": "La teua contrasenya actua (buit si no tens contrasenya encara)", + "FIELD_NEW_PASSWORD": "Nova contrasenya", + "PLACEHOLDER_NEW_PASSWORD": "Escriu una nova contrasenya", + "FIELD_RETYPE_PASSWORD": "Reescriu contrasenya", + "PLACEHOLDER_RETYPE_PASSWORD": "Reescriu contrasenya", + "ERROR_PASSWORD_MATCH": "Les contrasenyes no coincideixen" + }, + "USER_SETTINGS": { + "AVATAR_MAX_SIZE": "[Max. grandària: {{maxFileSize}}]", + "MENU": { + "SECTION_TITLE": "Configuració d'usuari", + "USER_PROFILE": "Perfil d'usuari", + "CHANGE_PASSWORD": "Canviar contrasenya", + "EMAIL_NOTIFICATIONS": "Notificacions de correu" + }, + "NOTIFICATIONS": { + "SECTION_NAME": "Notificacions de correu", + "COLUMN_PROJECT": "Projecte", + "COLUMN_RECEIVE_ALL": "Recibir tot", + "COLUMN_ONLY_INVOLVED": "Només relevants", + "COLUMN_NO_NOTIFICATIONS": "Sense notificacions", + "OPTION_ALL": "Tot", + "OPTION_INVOLVED": "Implicat", + "OPTION_NONE": "Sense notificacions" + }, + "POPOVER": { + "USER_PROFILE": "Perfil d'usuari", + "CHANGE_PASSWORD": "Canviar contrasenya", + "NOTIFICATIONS": "Notificacions", + "FEEDBACK": "Sugerències", + "TITLE_AVATAR": "Preferències d'usuari" + } + }, + "USER_PROFILE": { + "IMAGE_HELP": "La imatge serà escalada a 80x80px.
", + "ACTION_CHANGE_IMAGE": "Canviar", + "ACTION_USE_GRAVATAR": "Utilitza imatge de gravatar", + "ACTION_DELETE_ACCOUNT": "Esborrar compte de Taiga", + "CHANGE_EMAIL_SUCCESS": "Mira el teu correu!
Hem enviat un correu al teu conter
amb les instrucciones per a escriure una nova adreça de correu", + "CHANGE_PHOTO": "Canviar foto", + "FIELD": { + "USERNAME": "Mot d'usuari", + "EMAIL": "Email", + "FULL_NAME": "Nom complet", + "PLACEHOLDER_FULL_NAME": "Esciur el teu nom complet (ex. Íñigo Montoya)", + "BIO": "Bio", + "PLACEHOLDER_BIO": "Contans algo sobre tu mateix", + "LANGUAGE": "Llengua", + "LANGUAGE_DEFAULT": "-- utilizat llengua per defecte --" + } + }, + "WIZARD": { + "SECTION_TITLE_CHOOSE_TEMPLATE": "Tria una plantilla", + "CHOOSE_TEMPLATE_TEXT": "Quina plantilla encaixa millor al teu projecte?", + "SECTION_TITLE_CREATE_PROJECT": "Crear projecte", + "CREATE_PROJECT_TEXT": "Nou projecte. Qué il·lusió!", + "PROGRESS_TEMPLATE_SELECTION": "Selecció de plantilla", + "PROGRESS_NAME_DESCRIPTION": "Nom i descripció" + }, + "WIKI": { + "DATETIME": "DD MMM YYYY HH:mm", + "PLACEHOLDER_PAGE": "Esciu pàgina del Wiki", + "REMOVE": "Esborrar pàgina de Wiki", + "DELETE_LIGHTBOX_TITLE": "Esborrar pàgina de Wiki", + "NAVIGATION": { + "SECTION_NAME": "Enllaços", + "ACTION_ADD_LINK": "Afegir link" + }, + "SUMMARY": { + "TIMES_EDITED": "voltes
editat", + "LAST_EDIT": "última
edició", + "LAST_MODIFICATION": "última modificació" + } + } +} \ No newline at end of file diff --git a/app/locales/locale-en.json b/app/locales/locale-en.json new file mode 100644 index 00000000..1b1f3779 --- /dev/null +++ b/app/locales/locale-en.json @@ -0,0 +1,1093 @@ +{ + "COMMON": { + "YES": "Yes", + "NO": "No", + "LOADING": "Loading...", + "LOADING_PROJECT": "Loading project...", + "DATE": "DD MMM YYYY", + "DATETIME": "DD MMM YYYY HH:mm", + "SAVE": "Save", + "CANCEL": "Cancel", + "ACCEPT": "Accept", + "DELETE": "Delete", + "CREATE": "Create", + "ADD": "Add", + "COPY_TO_CLIPBOARD": "Copy to clipboard: Ctrl+C", + "EDIT": "Edit", + "DRAG": "Drag", + "TAG_LINE": "Your agile, free, and open source project management tool", + "TAG_LINE_2": "LOVE YOUR PROJECT", + "BLOCK": "Block", + "UNBLOCK": "Unblock", + "BLOCKED": "Blocked", + "CREATED_BY": "Created by {{fullDisplayName}}", + "FROM": "from", + "TO": "to", + "CLOSE": "close", + "BLOCKED_NOTE": "Why is this user story blocked?", + "BLOCKED_REASON": "Please explain the reason", + "GO_HOME": "Take me home", + "PLUGINS": "Plugins", + "BETA": "We are on beta!", + "ONE_ITEM_LINE": "One item per line...", + "NEW_BULK": "New bulk insert", + "RELATED_TASKS": "Related tasks", + "LOGOUT": "Logout", + "EXTERNAL_USER": "an external user", + "GENERIC_ERROR": "One of our Oompa Loompas says {{error}}.", + "IOCAINE_TEXT": "Feeling a bit overwhelmed by a task? Make sure others know about it by clicking on Iocaine when editing a task. It's possible to become immune to this (fictional) deadly poison by consuming small amounts over time just as it's possible to get better at what you do by occasionally taking on extra challenges!", + "FORM_ERRORS": { + "DEFAULT_MESSAGE": "This value seems to be invalid.", + "TYPE_EMAIL": "This value should be a valid email.", + "TYPE_URL": "This value should be a valid url.", + "TYPE_URLSTRICT": "This value should be a valid url.", + "TYPE_NUMBER": "This value should be a valid number.", + "TYPE_DIGITS": "This value should be digits.", + "TYPE_DATEISO": "This value should be a valid date (YYYY-MM-DD).", + "TYPE_ALPHANUM": "This value should be alphanumeric.", + "TYPE_PHONE": "This value should be a valid phone number.", + "NOTNULL": "This value should not be null.", + "NOT_BLANK": "This value should not be blank.", + "REQUIRED": "This value is required.", + "REGEXP": "This value seems to be invalid.", + "MIN": "This value should be greater than or equal to %s.", + "MAX": "This value should be lower than or equal to %s.", + "RANGE": "This value should be between %s and %s.", + "MIN_LENGTH": "This value is too short. It should have %s characters or more.", + "MAX_LENGTH": "This value is too long. It should have %s characters or less.", + "RANGE_LENGTH": "This value length is invalid. It should be between %s and %s characters long.", + "MIN_CHECK": "You must select at least %s choices.", + "MAX_CHECK": "You must select %s choices or less.", + "RANGE_CHECK": "You must select between %s and %s choices.", + "EQUAL_TO": "This value should be the same." + }, + "PICKERDATE": { + "FORMAT": "DD MMM YYYY", + "IS_RTL": "false", + "FIRST_DAY_OF_WEEK": "1", + "PREV_MONTH": "Previous Month", + "NEXT_MONTH": "Next Month", + "MONTHS": { + "JAN": "January", + "FEB": "February", + "MAR": "March", + "APR": "April", + "MAY": "May", + "JUN": "June", + "JUL": "July", + "AUG": "August", + "SEP": "September", + "OCT": "October", + "NOV": "November", + "DEC": "December" + }, + "WEEK_DAYS": { + "SUN": "Sunday", + "MON": "Monday", + "TUE": "Tuesday", + "WED": "Wednesday", + "THU": "Thursday", + "FRI": "Friday", + "SAT": "Saturday" + }, + "WEEK_DAYS_SHORT": { + "SUN": "Sun", + "MON": "Mon", + "TUE": "Tue", + "WED": "Wed", + "THU": "Thu", + "FRI": "Fri", + "SAT": "Sat" + } + }, + "TAGS": { + "PLACEHOLDER": "I'm it! Tag me...", + "DELETE": "Delete tag", + "ADD": "Add tag" + }, + "DESCRIPTION": { + "EMPTY": "Empty space is so boring... go on be descriptive...", + "NO_DESCRIPTION": "No description yet" + }, + "FIELDS": { + "SUBJECT": "Subject", + "NAME": "Name", + "URL": "URL", + "DESCRIPTION": "Description", + "VALUE": "Value", + "SLUG": "Slug", + "COLOR": "Color", + "IS_CLOSED": "Is closed?", + "STATUS": "Status", + "TYPE": "Type", + "SEVERITY": "Severity", + "PRIORITY": "Priority", + "ASSIGNED_TO": "Assigned to", + "POINTS": "Points", + "BLOCKED_NOTE": "blocked note", + "IS_BLOCKED": "is blocked" + }, + "ROLES": { + "ALL": "All" + }, + "ASSIGNED_TO": { + "NOT_ASSIGNED": "Not assigned", + "DELETE_ASSIGNMENT": "Delete assignment", + "REMOVE_ASSIGNED": "Remove assigned", + "TOO_MANY": "...too many users, keep filtering", + "CONFIRM_UNASSIGNED": "Are you sure you want to leave it unassigned?", + "TITLE_ACTION_EDIT_ASSIGNMENT": "Edit assignment" + }, + "STATUS": { + "CLOSED": "Closed", + "OPEN": "Open" + }, + "WATCHERS": { + "ADD": "Add watcher", + "TITLE": "watchers", + "DELETE": "Delete watcher", + "TITLE_LIGHTBOX_DELETE_WARTCHER": "Delete watcher..." + }, + "CUSTOM_ATTRIBUTES": { + "CUSTOM_FIELDS": "Custom Fields", + "SAVE": "Save Custom Field", + "EDIT": "Edit Custom Field", + "DELETE": "Delete custom attribute", + "CONFIRM_DELETE": "Remeber that all values in this custom field will be deleted.
Are you sure you want to continue?" + }, + "FILTERS": { + "TITLE": "filters", + "INPUT_PLACEHOLDER": "Subject or reference", + "TITLE_ACTION_FILTER_BUTTON": "search", + "BREADCRUMB_TITLE": "back to categories", + "BREADCRUMB_FILTERS": "Filters", + "BREADCRUMB_STATUS": "status" + }, + "WYSIWYG": { + "H1_BUTTON": "First Level Heading", + "H1_SAMPLE_TEXT": "Your title here...", + "H2_BUTTON": "Second Level Heading", + "H2_SAMPLE_TEXT": "Your title here...", + "H3_BUTTON": "Third Level Heading", + "H3_SAMPLE_TEXT": "Your title here...", + "BOLD_BUTTON": "Bold", + "BOLD_BUTTON_SAMPLE_TEXT": "Your text here...", + "ITALIC_BUTTON": "Italic", + "ITALIC_SAMPLE_TEXT": "Your text here...", + "STRIKE_BUTTON": "Strike", + "STRIKE_SAMPLE_TEXT": "Your text here...", + "BULLETED_LIST_BUTTON": "Bulleted List", + "BULLETED_LIST_SAMPLE_TEXT": "Your text here...", + "NUMERIC_LIST_BUTTON": "Numeric List", + "NUMERIC_LIST_SAMPLE_TEXT": "Your text here...", + "PICTURE_BUTTON": "Picture", + "PICTURE_SAMPLE_TEXT": "Your alternative text to picture here...", + "LINK_BUTTON": "Link", + "LINK_SAMPLE_TEXT": "Your text to link here....", + "QUOTE_BLOCK_BUTTON": "Quote Block", + "QUOTE_BLOCK_SAMPLE_TEXT": "Your text here...", + "CODE_BLOCK_BUTTON": "Code Block", + "CODE_BLOCK_SAMPLE_TEXT": "Your text here...", + "PREVIEW_BUTTON": "Preview", + "EDIT_BUTTON": "Edit", + "MARKDOWN_HELP": "Markdown syntax help" + }, + "PERMISIONS_CATEGORIES": { + "SPRINTS": { + "NAME": "Sprints", + "VIEW_SPRINTS": "View sprints", + "ADD_SPRINTS": "Add sprints", + "MODIFY_SPRINTS": "Modify sprints", + "DELETE_SPRINTS": "Delete sprints" + }, + "USER_STORIES": { + "NAME": "User Stories", + "VIEW_USER_STORIES": "View user stories", + "ADD_USER_STORIES": "Add user stories", + "MODIFY_USER_STORIES": "Modify user stories", + "DELETE_USER_STORIES": "Delete user stories" + }, + "TASKS": { + "NAME": "Tasks", + "VIEW_TASKS": "View tasks", + "ADD_TASKS": "Add tasks", + "MODIFY_TASKS": "Modify tasks", + "DELETE_TASKS": "Delete tasks" + }, + "ISSUES": { + "NAME": "Issues", + "VIEW_ISSUES": "View issues", + "ADD_ISSUES": "Add issues", + "MODIFY_ISSUES": "Modify issues", + "DELETE_ISSUES": "Delete issues" + }, + "WIKI": { + "NAME": "Wiki", + "VIEW_WIKI_PAGES": "View wiki pages", + "ADD_WIKI_PAGES": "Add wiki pages", + "MODIFY_WIKI_PAGES": "Modify wiki pages", + "DELETE_WIKI_PAGES": "Delete wiki pages", + "VIEW_WIKI_LINKS": "View wiki links", + "ADD_WIKI_LINKS": "Add wiki links", + "DELETE_WIKI_LINKS": "Delete wiki links" + } + } + }, + "AUTH": { + "INVITED_YOU": "has invited you to join the project", + "NOT_REGISTERED_YET": "Not registered yet?", + "REGISTER": "Register", + "CREATE_ACCOUNT": "create your free account here" + }, + "ATTACHMENT": { + "SECTION_NAME": "attachments", + "TITLE": "{{ fileName }} uploaded on {{ date }}", + "DESCRIPTION": "Type a short description", + "DEPRECATED": "(deprecated)", + "DEPRECATED_FILE": "Deprecated?", + "ADD": "Add new attachment. <%- maxFileSizeMsg %>", + "MAX_FILE_SIZE": "[Max. size: {{maxFileSize}}]", + "SHOW_DEPRECATED": "+ show deprecated atachments", + "HIDE_DEPRECATED": "- hide deprecated atachments", + "COUNT_DEPRECATED": "({{ counter }} deprecated)", + "MAX_UPLOAD_SIZE": "Maximum upload size is {{maxFileSize}}", + "DATE": "DD MMM YYYY [at] hh:mm", + "ERROR_UPLOAD_ATTACHMENT": "We have not been able to upload '{{fileName}}'. {{errorMessage}}", + "TITLE_LIGHTBOX_DELETE_ATTACHMENT": "Delete attachment...", + "MSG_LIGHTBOX_DELETE_ATTACHMENT": "the attachment '{{fileName}}'", + "ERROR_DELETE_ATTACHMENT": "We have not been able to delete: {{errorMessage}}", + "FIELDS": { + "IS_DEPRECATED": "is deprecated" + } + }, + "PAGINATION": { + "PREVIOUS": "Prev", + "NEXT": "Next" + }, + "ADMIN": { + "COMMON": { + "TITLE_ACTION_EDIT_VALUE": "Edit value", + "TITLE_ACTION_DELETE_VALUE": "Delete value" + }, + "HELP": "Do you need help? Check out our support page!", + "PROJECT_DEFAULT_VALUES": { + "TITLE": "Default Values", + "SUBTITLE": "Set default values for all selector inputs." + }, + "MEMBERSHIPS": { + "TITLE": "Manage members", + "ADD_BUTTON": "+ New member", + "ADD_BUTTON_TITLE": "Add new member" + }, + "PROJECT_EXPORT": { + "TITLE": "Export", + "SUBTITLE": "Export your project to save a backup or to create a new one based on this.", + "EXPORT_BUTTON": "Export", + "EXPORT_BUTTON_TITLE": "Export your project", + "LOADING_TITLE": "We are generating your dump file", + "DUMP_READY": "Your dump file is ready!", + "LOADING_MESSAGE": "Please don't close this page.", + "ASYNC_MESSAGE": "We will send you an email when ready.", + "SYNC_MESSAGE": "If the download doesn't start automatically click here.", + "ERROR": "Our Oompa Loompas have some problems generating your dump. Please try it again.", + "ERROR_BUSY": "Sorry, our Oompa Loompas are very busy right now. Please try again in a few minutes.", + "ERROR_MESSAGE": "Our Oompa Loompas have some problems generating your dump: {{message}}" + }, + "MODULES": { + "TITLE": "Modules", + "ENABLE": "Enable", + "DISABLE": "Disable", + "BACKLOG": "Backlog", + "BACKLOG_DESCRIPTION": "Manage your user stories to maintain an organized view of upcoming and prioritized work.", + "KANBAN": "Kanban", + "KANBAN_DESCRIPTION": "Organize your project in a lean way with this board.", + "ISSUES": "Issues", + "ISSUES_DESCRIPTION": "Track the bugs, questions and enhancements related to your project. Don't miss anything!", + "WIKI": "Wiki", + "WIKI_DESCRIPTION": "Add, modify, or delete content in collaboration with others. This is the right place for your project documentation.", + "MEETUP": "Meet Up", + "MEETUP_DESCRIPTION": "Choose your videoconference system. Even developers need face to face contact.", + "SELECT_VIDEOCONFERENCE": "Select a videoconference system", + "SALT_CHAT_ROOM": "If you want you can append a salt code to the name of the chat room" + }, + "PROJECT_PROFILE": { + "PAGE_TITLE": "Project profile - {{sectionName}} - {{projectName}}", + "PROJECT_DETAILS": "Project details", + "PROJECT_NAME": "Project name", + "PROJECT_SLUG": "Project slug", + "NUMBER_SPRINTS": "Number of sprints", + "NUMBER_US_POINTS": "Number of US points", + "TAGS": "Tags", + "DESCRIPTION": "Description", + "PUBLIC_PROJECT": "Public project", + "PRIVATE_PROJECT": "Private project", + "DELETE": "Delete this project" + }, + "REPORTS": { + "TITLE": "Reports", + "SUBTITLE": "Export your project data in CSV format and make your own reports.", + "DESCRIPTION": "Download a CSV file or copy the generated URL and open it in your favourite text editor or spreadsheet to make your own project data reports. You will be able to visualize and analize all your data easily.", + "HELP": "How to use this on my own spreadsheet?", + "REGENERATE_TITLE": "Change URL", + "REGENERATE_SUBTITLE": "You going to change the CSV data access url. The previous url will be disabled. Are you sure?" + }, + "CSV": { + "SECTION_TITLE_US": "user stories reports", + "SECTION_TITLE_TASK": "tasks reports", + "SECTION_TITLE_ISSUE": "issues reports", + "DOWNLOAD": "Download CSV", + "URL_FIELD_PLACEHOLDER": "Please regenerate CSV url", + "TITLE_REGENERATE_URL": "Regenerate CSV url", + "ACTION_GENERATE_URL": "Generate Url", + "ACTION_REGENERATE": "Regenerate" + }, + "CUSTOM_FIELDS": { + "TITLE": "Custom Fields", + "SUBTITLE": "Specify the custom fields for your user stories, tasks and issues", + "US_DESCRIPTION": "User stories custom fields", + "US_ADD": "Add a custom field in user stories", + "TASK_DESCRIPTION": "Tasks custom fields", + "TASK_ADD": "Add a custom field in tasks", + "ISSUE_DESCRIPTION": "Issues custom fields", + "ISSUE_ADD": "Add a custom field in issues" + }, + "PROJECT_VALUES": { + "APP_TITLE": "Project values - {{sectionName}} - {{projectName}}", + "REPLACEMENT": "All items with this value will be changed to", + "ERROR_DELETE_ALL": "You can't delete all values." + }, + "PROJECT_VALUES_POINTS": { + "TITLE": "Us points", + "SUBTITLE": "Specify the points your user stories could be estimated to", + "ACTION_ADD": "Add new point" + }, + "PROJECT_VALUES_PRIORITIES": { + "TITLE": "Issue priorities", + "SUBTITLE": "Specify the priorities your issues will have", + "ACTION_ADD": "Add new priority" + }, + "PROJECT_VALUES_SEVERITIES": { + "TITLE": "Issue severities", + "SUBTITLE": "Specify the severities your issues will have", + "ACTION_ADD": "Add new severity" + }, + "PROJECT_VALUES_STATUS": { + "TITLE": "Status", + "SUBTITLE": "Specify the statuses your user stories, tasks and issues will go through", + "US_TITLE": "US Statuses", + "TASK_TITLE": "Task Statuses", + "ISSUE_TITLE": "Issue Statuses" + }, + "PROJECT_VALUES_TYPES": { + "TITLE": "Types", + "SUBTITLE": "Specify the types your issues could be", + "ISSUE_TITLE": "Issues types", + "ACTION_ADD": "Add new type" + }, + "ROLES": { + "SECTION_NAME": "Roles - {{projectName}}", + "WARNING_NO_ROLE": "Be careful, no role in your project will be able to estimate the point value for user stories", + "HELP_ROLE_ENABLED": "When enabled, members assigned to this role will be able to estimate the point value for user stories", + "COUNT_MEMBERS": "{{ role.members_count }} members with this role", + "TITLE_DELETE_ROLE": "Delete Role", + "REPLACEMENT_ROLE": "All the users with this role will be moved to", + "WARNING_DELETE_ROLE": "Be careful, all role estimations will be removed", + "ERROR_DELETE_ALL": "You can't delete all values", + "EXTERNAL_USER": "External user" + }, + "THIRD_PARTIES": { + "SECRET_KEY": "Secret key", + "PAYLOAD_URL": "Payload URL", + "VALID_IPS": "Valid origin IPs (separated by ,)" + }, + "BITBUCKET": { + "SECTION_NAME": "Bitbucket", + "APP_TITLE": "Bitbucket - {{projectName}}", + "INFO_VERIFYING_IP": "Bitbucket requests are not signed so the best way of verifying the origin is by IP. If the field is empty there will be no IP validation." + }, + "GITLAB": { + "SECTION_NAME": "Gitlab", + "APP_TITLE": "Gitlab - {{projectName}}", + "INFO_VERIFYING_IP": "Gitlab requests are not signed so the best way of verifying the origin is by IP. If the field is empty there will be no IP validation." + }, + "GITHUB": { + "SECTION_NAME": "Github", + "APP_TITLE": "Github - {{projectName}}" + }, + "WEBHOOKS": { + "APP_TITLE": "Webhooks - {{projectName}}", + "SECTION_NAME": "Webhooks", + "SUBTITLE": "Webhooks notify external services about events in Taiga, like comments, user stories....", + "ADD_NEW": "Add a New Webhook", + "TYPE_NAME": "Type the service name", + "TYPE_PAYLOAD_URL": "Type the service payload url", + "TYPE_SERVICE_SECRET": "Type the service secret key", + "SAVE": "Save Webhook", + "CANCEL": "Cancel Webhook", + "SHOW_HISTORY": "(Show history)", + "TEST": "Test Webhook", + "EDIT": "Edit Webhook", + "DELETE": "Delete Webhook", + "REQUEST": "Request", + "RESEND_REQUEST": "Resend request", + "HEADERS": "Headers", + "PAYLOAD": "Payload", + "RESPONSE": "Response", + "DATE": "DD MMM YYYY [at] hh:mm:ss", + "ACTION_HIDE_HISTORY": "(Hide history)", + "ACTION_HIDE_HISTORY_TITLE": "Hide history details", + "ACTION_SHOW_HISTORY": "(Show history)", + "ACTION_SHOW_HISTORY_TITLE": "Show history details", + "WEBHOOK_NAME": "Webhook '{{name}}'" + }, + "CUSTOM_ATTRIBUTES": { + "ADD": "Add custom field", + "EDIT": "Edit Custom Field", + "DELETE": "Delete Custom Field", + "SAVE_TITLE": "Save Custom Field", + "CANCEL_TITLE": "Cancel creation", + "SET_FIELD_NAME": "Set your custom field name", + "SET_FIELD_DESCRIPTION": "Set your custom field description", + "ACTION_UPDATE": "Update Custom Field", + "ACTION_CANCEL_EDITION": "Cancel edition" + }, + "MEMBERSHIP": { + "COLUMN_MEMBER": "Member", + "COLUMN_ADMIN": "Admin", + "COLUMN_ROLE": "Role", + "COLUMN_STATUS": "Status", + "STATUS_ACTIVE": "Active", + "STATUS_PENDING": "Pending", + "DELETE_MEMBER": "Delete member", + "SUCCESS_SEND_INVITATION": "We've sent the invitation again to '{{email}}'.", + "ERROR_SEND_INVITATION": "We haven't sent the invitation.", + "SUCCESS_DELETE": "We've deleted {{message}}.", + "ERROR_DELETE": "We have not been able to delete {{message}}.", + "DEFAULT_DELETE_MESSAGE": "the invitation to {{email}}" + }, + "DEFAULT_VALUES": { + "LABEL_POINTS": "Default value for points selector", + "LABEL_US": "Default value for US status selector", + "LABEL_TASK_STATUS": "Default value for task status selector", + "LABEL_PRIORITY": "Default value for priority selector", + "LABEL_SEVERITY": "Default value for severity selector", + "LABEL_ISSUE_TYPE": "Default value for issue type selector", + "LABEL_ISSUE_STATUS": "Default value for issue status selector" + }, + "STATUS": { + "PLACEHOLDER_WRITE_STATUS_NAME": "Write a name for the new status" + }, + "TYPES": { + "PLACEHOLDER_WRITE_NAME": "Write a name for the new element" + }, + "US_STATUS": { + "ACTION_ADD_STATUS": "Add new status", + "IS_ARCHIVED_COLUMN": "Is archived?", + "WIP_LIMIT_COLUMN": "WIP Limit", + "PLACEHOLDER_WRITE_NAME": "Write a name for the new status" + }, + "MENU": { + "TITLE": "Admin", + "PROJECT": "Project", + "ATTRIBUTES": "Attributes", + "MEMBERS": "Members", + "PERMISSIONS": "Permissions", + "INTEGRATIONS": "Integrations", + "PLUGINS": "Plugins" + }, + "SUBMENU_PROJECT_ATTRIBUTES": { + "TITLE": "Attributes" + }, + "SUBMENU_PROJECT_VALUES": { + "STATUS": "Status", + "POINTS": "Points", + "PRIORITIES": "Priorities", + "SEVERITIES": "Severities", + "TYPES": "Types", + "CUSTOM_FIELDS": "Custom fields" + }, + "SUBMENU_PROJECT_PROFILE": { + "TITLE": "Project Profile" + }, + "SUBMENU_ROLES": { + "TITLE": "Roles", + "ACTION_NEW_ROLE": "+ New role", + "TITLE_ACTION_NEW_ROLE": "Add new role" + }, + "SUBMENU_THIDPARTIES": { + "TITLE": "Services" + } + }, + "PROJECT": { + "WELCOME": "Welcome", + "SECTION_PROJECTS": "Projects", + "STATS": { + "PROJECT": "project
points", + "DEFINED": "defined
points", + "ASSIGNED": "assigned
points", + "CLOSED": "closed
points" + }, + "SECTION": { + "SEARCH": "Search", + "BACKLOG": "Backlog", + "KANBAN": "Kanban", + "ISSUES": "Issues", + "WIKI": "Wiki", + "TEAM": "Team", + "MEETUP": "Meet Up", + "ADMIN": "Admin" + }, + "NAVIGATION": { + "SECTION_TITLE": "Your projects", + "PLACEHOLDER_SEARCH": "Search in...", + "ACTION_CREATE_PROJECT": "Create project", + "TITLE_ACTION_IMPORT": "Import project", + "TITLE_PRVIOUS_PROJECT": "Show previous projects", + "TITLE_NEXT_PROJECT": "Show next projects" + }, + "IMPORT": { + "TITLE": "Importing Project", + "UPLOADING_FILE": "Uploading dump file", + "DESCRIPTION": "This process can take a while, please keep the window open.", + "ASYNC_IN_PROGRESS_TITLE": "Our Oompa Loompas are importing your project", + "ASYNC_IN_PROGRESS_MESSAGE": "This process could take a few minutes
We will send you an email when ready", + "UPLOAD_IN_PROGRESS_MESSAGE": "Uploaded {{uploadedSize}} of {{totalSize}}", + "ERROR": "Our Oompa Loompas have some problems importing your dump data. Please try again.", + "ERROR_TOO_MANY_REQUEST": "Sorry, our Oompa Loompas are very busy right now. Please try again in a few minutes.", + "ERROR_MESSAGE": "Our Oompa Loompas have some problems importing your dump data: {{error_message}}", + "ERROR_MAX_SIZE_EXCEEDED": "'{{fileName}}' ({{fileSize}}) is too heavy for our Oompa Loompas, try it with a smaller than ({{maxFileSize}})", + "SYNC_SUCCESS": "Your project has been imported successfuly" + } + }, + "LIGHTBOX": { + "DELETE_ACCOUNT": { + "SECTION_NAME": "Delete Taiga Account", + "CONFIRM": "Are you sure you want to delete your Taiga account?", + "SUBTITLE": "We're going to miss you! :-(", + "NEWSLETTER_LABEL_TEXT": "I don't wanna receive your newsletter anymore" + + }, + "DELETE_PROJECT": { + "TITLE": "Delete project", + "QUESTION": "Are you sure you want to delete this project?", + "SUBTITLE": "All project data (user stories, tasks, issues, sprints and wiki pages) will be lost! :-(", + "CONFIRM": "Yes, I'm really sure" + }, + "ASSIGNED_TO": { + "SELECT": "Select assigned to", + "SEARCH": "Search for users" + }, + "ADD_MEMBER": { + "TITLE": "New Member", + "HELP_TEXT": "If users are already registered on Taiga, they will be added automatically. Otherwise they will receive an invitation." + }, + "CREATE_ISSUE": { + "TITLE": "Add Issue" + }, + "FEEDBACK": { + "TITLE": "Tell us something...", + "COMMENT": "...a bug, some suggestions, something cool... or even your worst nightmare with Taiga", + "ACTION_SEND": "Send feedback" + }, + "SEARCH": { + "TITLE": "Search", + "PLACEHOLDER_SEARCH": "What are you looking for?" + }, + "ADD_EDIT_SPRINT": { + "TITLE": "New sprint", + "PLACEHOLDER_SPRINT_NAME": "sprint name", + "PLACEHOLDER_SPRINT_START": "Estimated Start", + "PLACEHOLDER_SPRINT_END": "Estimated End", + "ACTION_DELETE_SPRINT": "Do you want to delete this sprint?", + "TITLE_ACTION_DELETE_SPRINT": "delete sprint", + "LAST_SPRINT_NAME": " last sprint is {{lastSprint}} ;-) " + }, + "CREATE_EDIT_TASK": { + "TITLE": "New task", + "PLACEHOLDER_SUBJECT": "A task subject", + "PLACEHOLDER_STATUS": "Task status", + "OPTION_UNASSIGNED": "Unassigned", + "PLACEHOLDER_SHORT_DESCRIPTION": "Type a short description", + "ACTION_EDIT": "Edit task" + }, + "CREATE_EDIT_US": { + "TITLE": "New US", + "PLACEHOLDER_DESCRIPTION": "Please add descriptive text to help others better understand this US", + "NEW_US": "New user story", + "EDIT_US": "Edit user story" + }, + "DELETE_SPRINT": { + "TITLE": "Delete sprint" + }, + "CREATE_MEMBER": { + "PLACEHOLDER_INVITATION_TEXT": "(Optional) Add a personalized text to the invitation. Tell something lovely to your new members ;-)", + "PLACEHOLDER_TYPE_EMAIL": "Type an Email" + } + }, + "US": { + "SECTION_NAME": "User story details", + "LINK_TASKBOARD": "Taskboard", + "TITLE_LINK_TASKBOARD": "Go to the taskboard", + "TOTAL_POINTS": "total", + "ADD": "+ Add a new User Story", + "ADD_BULK": "Add some new User Stories in bulk", + "PROMOTED": "This US has been promoted from Issue:", + "TITLE_LINK_GO_TO_ISSUE": "Go to issue", + "EXTERNAL_REFERENCE": "This US has been created from", + "GO_TO_EXTERNAL_REFERENCE": "Go to origin", + "BLOCKED": "This user story is blocked", + "PREVIOUS": "previous user story", + "NEXT": "next user story", + "TITLE_DELETE_ACTION": "Delete User Story", + "LIGHTBOX_TITLE_BLOKING_US": "Blocking us", + "TASK_COMPLETED": "{{totalClosedTasks}}/{{totalTasks}} tasks completed", + "ASSIGN": "Assign User Story", + "NOT_ESTIMATED": "Not estimated", + "TOTAL_US_POINTS": "Total Us points", + "FIELDS": { + "TEAM_REQUIREMENT": "Team Requirement", + "CLIENT_REQUIREMENT": "Client Requirement", + "FINISH_DATE": "Finish date" + } + }, + "COMMENTS": { + "DELETED_INFO": "Comment deleted by {{user}} on {{date}}", + "TITLE": "Comments", + "COMMENT": "Comment", + "TYPE_NEW_COMMENT": "Type a new comment here", + "SHOW_DELETED": "Show deleted comment", + "HIDE_DELETED": "Hide deleted comment", + "RESTORE": "Restore comment" + }, + "ACTIVITY": { + "SHOW_ACTIVITY": "Show activity", + "DATETIME": "DD MMM YYYY HH:mm", + "SHOW_MORE": "+ Show previous entries ({{showMore}} more)", + "TITLE": "Activity", + "REMOVED": "removed", + "ADDED": "added", + "US_POINTS": "US points ({{name}})", + "NEW_ATTACHMENT": "new attachment", + "DELETED_ATTACHMENT": "deleted attachment", + "UPDATED_ATTACHMENT": "updated attachment {{filename}}", + "DELETED_CUSTOM_ATTRIBUTE": "deleted custom attribute", + "SIZE_CHANGE": "Made {size, plural, one{one change} other{# changes}}", + "VALUES": { + "YES": "yes", + "NO": "no", + "EMPTY": "empty", + "UNASSIGNED": "unassigned" + }, + "FIELDS": { + "SUBJECT" : "subject", + "NAME": "name", + "DESCRIPTION" : "description", + "CONTENT": "content", + "STATUS": "status", + "IS_CLOSED" : "is closed", + "FINISH_DATE" : "finish date", + "TYPE": "type", + "PRIORITY": "priority", + "SEVERITY": "severity", + "ASSIGNED_TO" : "assigned to", + "WATCHERS" : "watchers", + "MILESTONE" : "sprint", + "USER_STORY": "user story", + "PROJECT": "project", + "IS_BLOCKED": "is blocked", + "BLOCKED_NOTE": "blocked note", + "POINTS": "points", + "CLIENT_REQUIREMENT" : "client requirement", + "TEAM_REQUIREMENT" : "team requirement", + "IS_IOCAINE": "is iocaine", + "TAGS": "tags", + "ATTACHMENTS" : "attachments", + "IS_DEPRECATED": "is deprecated", + "ORDER" : "order", + "BACKLOG_ORDER" : "backlog order", + "SPRINT_ORDER" : "sprint order", + "KANBAN_ORDER" : "kanban order", + "TASKBOARD_ORDER" : "taskboard order", + "US_ORDER" : "us order" + } + }, + "BACKLOG": { + "SECTION_NAME": "Backlog", + "MOVE_US_TO_CURRENT_SPRINT": "Move to Current Sprint", + "SHOW_FILTERS": "Show filters", + "SHOW_TAGS": "Show tags", + "EMPTY": "Your backlog is empty!", + "CREATE_NEW_US": "Create a new US", + "CREATE_NEW_US_EMPTY_HELP": "You may want to create a new user story", + "EXCESS_OF_POINTS": "Excess of points", + "PENDING_POINTS": "Pending Points", + "CLOSED_POINTS": "Closed points", + "COMPACT_SPRINT": "Compact Sprint", + "GO_TO_TASKBOARD": "Go to the taskboard of {{::name}}", + "EDIT_SPRINT": "Edit Sprint", + "CLOSED_POINTS": "closed", + "TOTAL_POINTS": "total", + "STATUS_NAME": "Status Name", + "SORTABLE_FILTER_ERROR": "You can't drop on backlog when filters are open", + "DOOMLINE": "Project Scope [Doomline]", + "CHART": { + "XAXIS_LABEL": "Sprints", + "YAXIS_LABEL": "Points", + "OPTIMAL": "Optimal pending points for sprint {{xval}} should be {{yval}}", + "REAL": "Real pending points for sprint {{xval}} is {{yval}}", + "INCREMENT_TEAM": "Incremented points by team requirements for sprint {{xval}} is {{yval}}", + "INCREMENT_CLIENT": "Incremented points by client requirements for sprint {{xval}} is {{yval}}" + }, + "TAGS": { + "TOGGLE": "Toggle tags visibility", + "SHOW": "Show tags", + "HIDE": "Hide tags" + }, + "TABLE": { + "COLUMN_US": "User Stories", + "TITLE_COLUMN_POINTS": "Select view per Role" + }, + "SPRINT_SUMMARY": { + "TOTAL_POINTS": "total
points", + "COMPLETED_POINTS": "completed
points", + "OPEN_TASKS": "open
tasks", + "CLOSED_TASKS": "closed
tasks", + "IOCAINE_DOSES": "iocaine
doses", + "SHOW_STATISTICS_TITLE": "Show statistics" + }, + "SUMMARY": { + "PROJECT_POINTS": "project
points", + "DEFINED_POINTS": "defined
points", + "CLOSED_POINTS": "closed
points", + "POINTS_PER_SPRINT": "points /
sprint" + }, + "FILTERS": { + "TOGGLE": "Toggle filters visibility", + "TITLE": "Filters", + "REMOVE": "Remove Filters", + "HIDE": "Hide Filters", + "SHOW": "Show Filters", + "FILTER_CATEGORY_STATUS": "Status", + "FILTER_CATEGORY_TAGS": "Tags" + }, + "SPRINTS": { + "TITLE": "SPRINTS", + "DATE": "DD MMM YYYY", + "LINK_TASKBOARD": "Sprint Taskboard", + "TITLE_LINK_TASKBOARD": "Go to Taskboard of \"{{name}}\"", + "NUMBER_SPRINTS": "
sprints", + "TITLE_ACTION_NEW_SPRINT": "+ New sprint", + "ACTION_NEW_SPRINT": "+ New sprint", + "ACTION_SHOW_CLOSED_SPRINTS": "Show closed sprints", + "ACTION_HIDE_CLOSED_SPRINTS": "Hide closed sprints" + } + }, + "ERROR": { + "TEXT1": "Something happened and our Oompa Loompas are working on it.", + "TEXT2": "Try reloading again soon.", + "NOT_FOUND": "Not found", + "NOT_FOUND_TEXT": "Error 404. The page you are looking for no longer exists. Perhaps you can return back to TAIGA homepage and see if you can find what you are looking for.", + "PERMISSION_DENIED": "Permission denied", + "PERMISSION_DENIED_CODE": "Error 403.", + "VERSION_ERROR": "Someone inside Taiga has changed this before and our Oompa Loompas cannot apply your changes. Please reload and apply your changes again (they will be lost)." + }, + "TASKBOARD": { + "SECTION_NAME": "Taskboard", + "TITLE_ACTION_ADD": "Add a new Task", + "TITLE_ACTION_ADD_BULK": "Add some new Tasks in bulk", + "TITLE_ACTION_ASSIGN": "Assign task", + "TITLE_ACTION_EDIT": "Edit task", + "TABLE": { + "COLUMN": "User story", + "TITLE_ACTION_FOLD": "Fold column", + "TITLE_ACTION_UNFOLD": "Unfold column", + "TITLE_ACTION_FOLD_ROW": "Fold Row", + "TITLE_ACTION_UNFOLD_ROW": "Unfold Row", + "FIELD_POINTS": "points", + "ROW_UNASSIGED_TASKS_TITLE": "Unassigned tasks" + }, + "CHARTS": { + "XAXIS_LABEL": "Days", + "YAXIS_LABEL": "Points", + "OPTIMAL": "Optimal pending points for day {{formattedDate}} should be {{roundedValue}}", + "REAL": "Real pending points for day {{formattedDate}} is {{roundedValue}}", + "DATE": "DD MMMM YYYY" + } + }, + "TASK": { + "SECTION_NAME": "Task details", + "LINK_TASKBOARD": "Taskboard", + "TITLE_LINK_TASKBOARD": "Go to the taskboard", + "PLACEHOLDER_SUBJECT": "Type the new task subject", + "TITLE_SELECT_STATUS": "Status Name", + "OWNER_US": "This task belongs to", + "TITLE_LINK_GO_OWNER": "Go to user story", + "ORIGIN_US": "This task has been created from", + "TITLE_LINK_GO_ORIGIN": "Go to user story", + "BLOCKED": "This task is blocked", + "PREVIOUS": "previous task", + "NEXT": "next task", + "TITLE_DELETE_ACTION": "Delete Task", + "LIGHTBOX_TITLE_BLOKING_TASK": "Blocking task", + "FIELDS": { + "MILESTONE": "Sprint", + "USER_STORY": "User story", + "IS_IOCAINE": "Is iocaine" + }, + "ACTION_IOCAINE": "Iocaine", + "TITLE_ACTION_IOCAINE": "Feeling a bit overwhelmed by a task? Make sure others know about it by clicking on Iocaine when editing a task. It's possible to become immune to this (fictional) deadly poison by consuming small amounts over time just as it's possible to get better at what you do by occasionally taking on extra challenges!" + }, + "NOTIFICATION": { + "OK": "Everything is ok", + "WARNING": "Oops, something happened...", + "WARNING_TEXT": "Our Oompa Loompas are sad, your changes were not saved!", + "SAVED": "Our Oompa Loompas saved all your changes!", + "CLOSE": "Close notification", + "MAIL": "Notifications By Mail", + "ASK_DELETE": "Are you sure you want to delete?" + }, + "CANCEL_ACCOUNT": { + "TITLE": "Cancel your account", + "SUBTITLE": "We're sorry you are leaving the taiga, we hope you enjoyed your stay :)", + "PLACEHOLDER_INPUT_TOKEN": "cancel account token", + "ACTION_LEAVING": "Yes, I'm leaving!", + "SUCCESS": "Our Oompa Loompas removed your account" + }, + "CHANGE_EMAIL_FORM": { + "TITLE": "Change your email", + "SUBTITLE": "One click more and your email will be updated!", + "PLACEHOLDER_INPUT_TOKEN": "change email token", + "ACTION_CHANGE_EMAIL": "Change email", + "SUCCESS": "Our Oompa Loompas updated your email" + }, + "CHANGE_PASSWORD_RECOVERY_FORM": { + "TITLE": "Create a new Taiga pass", + "SUBTITLE": "And hey, you may want to eat some more iron-rich food, it's good for your brain :P", + "PLACEHOLDER_RECOVER_PASSWORD_TOKEN": "Recover password token", + "LINK_NEED_TOKEN": "Need one?", + "TITLE_LINK_NEED_TOKEN": "Did you need a token to recover your password because you forgot it?", + "PLACEHOLDER_NEW_PASSWORD": "New password", + "PLACEHOLDER_RE_TYPE_NEW_PASSWORD": "Re-type new password", + "ACTION_RESET_PASSWORD": "Reset Password", + "SUCCESS": "Our Oompa Loompas saved your new password.
Try to sign in with it." + }, + "FORGOT_PASSWORD_FORM": { + "TITLE": "Oops, did you forget your password?", + "SUBTITLE": "Enter your username or email to get a new one", + "PLACEHOLDER_FIELD": "Username or email", + "ACTION_RESET_PASSWORD": "Reset Password", + "LINK_CANCEL": "Nah, take me back. I think I remember it.", + "SUCCESS": "Check your inbox!
We have sent you an email with the instructions to set a new password", + "ERROR": "According to our Oompa Loompas, your are not registered yet." + }, + "LOGIN_COMMON": { + "HEADER": "I already have a Taiga login", + "PLACEHOLDER_AUTH_NAME": "Username or email (case sensitive)", + "LINK_FORGOT_PASSWORD": "Forgot it?", + "TITLE_LINK_FORGOT_PASSWORD": "Did you forgot your password?", + "ACTION_ENTER": "Enter", + "ACTION_SIGN_IN": "Sign in", + "PLACEHOLDER_AUTH_PASSWORD": "Password (case sensitive)" + }, + "LOGIN_FORM": { + "ERROR_AUTH_INCORRECT": "According to our Oompa Loompas, your username/email or password are incorrect.", + "ERROR_GENERIC": "According to our Oompa Loompas there was an error.", + "SUCCESS": "Our Oompa Loompas are happy, welcome to Taiga." + }, + "INVITATION_LOGIN_FORM": { + "NOT_FOUND": "Ooops, we have a problem
Our Oompa Loompas can't find your invitation.", + "SUCCESS": "You've successfully joined this project, Welcome to {{project_name}}", + "ERROR": "According to our Oompa Loompas, your are not registered yet or typed an invalid password." + }, + "REGISTER_FORM": { + "TITLE": "Register a new Taiga account (free)", + "PLACEHOLDER_NAME": "Pick a username (case sensitive)", + "PLACEHOLDER_FULL_NAME": "Pick your full name", + "PLACEHOLDER_EMAIL": "Your email", + "PLACEHOLDER_PASSWORD": "Set a password (case sensitive)", + "ACTION_SIGN_UP": "Sign up", + "TITLE_LINK_LOGIN": "Log in", + "LINK_LOGIN": "Are you already registered? Log in" + }, + "ISSUES": { + "LIST_SECTION_NAME": "Issues", + "SECTION_NAME": "Issue details", + "ACTION_NEW_ISSUE": "+ NEW ISSUE", + "ACTION_PROMOTE_TO_US": "Promote to User Story", + "PLACEHOLDER_FILTER_NAME": "Write the filter name and press enter", + "PROMOTED": "This issue has been promoted to US:", + "EXTERNAL_REFERENCE": "This issue has been created from", + "GO_TO_EXTERNAL_REFERENCE": "Go to origin", + "BLOCKED": "This issue is blocked", + "TITLE_PREVIOUS_ISSUE": "previous issue", + "TITLE_NEXT_ISSUE": "next issue", + "ACTION_DELETE": "Delete issue", + "LIGHTBOX_TITLE_BLOKING_ISSUE": "Blocking issue", + "CONFIRM_PROMOTE": { + "TITLE": "Promote this issue to a new user story", + "MESSAGE": "Are you sure you want to create a new US from this Issue?" + }, + "FILTERS": { + "TITLE": "Filters", + "INPUT_SEARCH_PLACEHOLDER": "Subject or ref", + "TITLE_ACTION_SEARCH": "Search", + "ACTION_SAVE_CUSTOM_FILTER": "save as custom filter", + "BREADCRUMB": "Filters", + "TITLE_BREADCRUMB": "Filters", + "CATEGORIES": { + "TYPE": "Type", + "STATUS": "Status", + "SEVERITY": "Severity", + "PRIORITIES": "Priorities", + "TAGS": "Tags", + "ASSIGNED_TO": "Assigned to", + "CREATED_BY": "Created by", + "CUSTOM_FILTERS": "Custom filters" + }, + "CONFIRM_DELETE": { + "TITLE": "Delete custom filter", + "MESSAGE": "the custom filter '{{customFilterName}}'" + } + }, + "TABLE": { + "COLUMNS": { + "TYPE": "Type", + "SEVERITY": "Severity", + "PRIORITY": "Priority", + "SUBJECT": "Subject", + "STATUS": "Status", + "CREATED": "Created", + "ASSIGNED_TO": "Assigned to" + }, + "TITLE_ACTION_CHANGE_STATUS": "Change status", + "TITLE_ACTION_ASSIGNED_TO": "Assigned to", + "EMPTY": { + "TITLE": "There are no issues to report :-)", + "SUBTITLE": "Did you find an issue?", + "ACTION_CREATE_ISSUE": "Create a new Issue" + } + } + }, + "KANBAN": { + "SECTION_NAME": "Kanban", + "TITLE_ACTION_FOLD": "Fold column", + "TITLE_ACTION_UNFOLD": "Unfold column", + "TITLE_ACTION_FOLD_CARDS": "Fold cards", + "TITLE_ACTION_UNFOLD_CARDS": "Unfold cards", + "TITLE_ACTION_ADD_US": "Add New User Story", + "TITLE_ACTION_ADD_BULK": "Add New bulk", + "ACTION_SHOW_ARCHIVED": "Show archived", + "ACTION_HIDE_ARCHIVED": "Hide archived", + "HIDDEN_USER_STORIES": "The user stories in this status are hidden by default", + "ARCHIVED": "You have archived", + "UNDO_ARCHIVED": "Drag & drop again to undo" + }, + "SEARCH": { + "FILTER_USER_STORIES": "User Stories", + "FILTER_ISSUES": "Issues", + "FILTER_TASKS": "Tasks", + "FILTER_WIKI": "Wiki Pages", + "PLACEHOLDER_SEARCH": "Search in...", + "TITLE_ACTION_SEARCH": "search", + "EMPTY_TITLE": "It looks like nothing was found with your search criteria.", + "EMPTY_DESCRIPTION": "Maybe try one of the tabs above or search again" + }, + "TEAM": { + "SECTION_NAME": "Team", + "APP_TITLE": "TEAM - {{projectName}}", + "PLACEHOLDER_INPUT_SEARCH": "Search by full name...", + "COLUMN_MR_WOLF": "Mr. Wolf", + "EXPLANATION_COLUMN_MR_WOLF": "Closed issues", + "COLUMN_IOCAINE": "Iocaine Drinker", + "EXPLANATION_COLUMN_IOCAINE": "Iocaine doses ingested", + "COLUMN_CERVANTES": "Cervantes", + "EXPLANATION_COLUMN_CERVANTES": "Wiki pages edited", + "COLUMN_BUG_HUNTER": "Bug Hunter", + "EXPLANATION_COLUMN_BUG_HUNTER": "Issues reported", + "COLUMN_NIGHT_SHIFT": "Night Shift", + "EXPLANATION_COLUMN_NIGHT_SHIFT": "Tasks closed", + "COLUMN_TOTAL_POWER": "Total Power", + "EXPLANATION_COLUMN_TOTAL_POWER": "Total Points", + "SECTION_TITLE_TEAM": "Team >", + "SECTION_FILTER_ALL": "All", + "CONFIRM_LEAVE_PROJECT": "Are you sure you want to leave the project?", + "ACTION_LEAVE_PROJECT": "Leave this project" + }, + "CHANGE_PASSWORD": { + "SECTION_NAME": "Change password", + "FIELD_CURRENT_PASSWORD": "Current password", + "PLACEHOLDER_CURRENT_PASSWORD": "Your current password (or empty if you have no password yet)", + "FIELD_NEW_PASSWORD": "New password", + "PLACEHOLDER_NEW_PASSWORD": "Type a new password", + "FIELD_RETYPE_PASSWORD": "Retype new password", + "PLACEHOLDER_RETYPE_PASSWORD": "Retype the new password", + "ERROR_PASSWORD_MATCH": "The passwords doesn't match" + }, + "USER_SETTINGS": { + "AVATAR_MAX_SIZE": "[Max. size: {{maxFileSize}}]", + "MENU": { + "SECTION_TITLE": "User Settings", + "USER_PROFILE": "User profile", + "CHANGE_PASSWORD": "Change password", + "EMAIL_NOTIFICATIONS": "Email notifications" + }, + "NOTIFICATIONS": { + "SECTION_NAME": "Email Notifications", + "COLUMN_PROJECT": "Project", + "COLUMN_RECEIVE_ALL": "Receive All", + "COLUMN_ONLY_INVOLVED": "Only Involved", + "COLUMN_NO_NOTIFICATIONS": "No notifications", + "OPTION_ALL": "All", + "OPTION_INVOLVED": "Involved", + "OPTION_NONE": "None" + }, + "POPOVER": { + "USER_PROFILE": "User Profile", + "CHANGE_PASSWORD": "Change Password", + "NOTIFICATIONS": "Notifications", + "FEEDBACK": "Feedback", + "TITLE_AVATAR": "User preferences" + } + }, + "USER_PROFILE": { + "IMAGE_HELP": "The image will be scaled to 80x80px.
", + "ACTION_CHANGE_IMAGE": "Change", + "ACTION_USE_GRAVATAR": "Use gravatar image", + "ACTION_DELETE_ACCOUNT": "Delete Taiga account", + "CHANGE_EMAIL_SUCCESS": "Check your inbox!
We have sent a mail to your account
with the instructions to set your new address", + "CHANGE_PHOTO": "Change photo", + "FIELD": { + "USERNAME": "Username", + "EMAIL": "Email", + "FULL_NAME": "Full name", + "PLACEHOLDER_FULL_NAME": "Set your full name (ex. Íñigo Montoya)", + "BIO": "Bio", + "PLACEHOLDER_BIO": "Tell us something about you", + "LANGUAGE": "Language", + "LANGUAGE_DEFAULT": "-- use default language --" + } + }, + "WIZARD": { + "SECTION_TITLE_CHOOSE_TEMPLATE": "Choose a template", + "CHOOSE_TEMPLATE_TEXT": "Which template would fit better in your project?", + "SECTION_TITLE_CREATE_PROJECT": "Create Project", + "CREATE_PROJECT_TEXT": "Fresh and clean. So exciting!", + "PROGRESS_TEMPLATE_SELECTION": "Template selection", + "PROGRESS_NAME_DESCRIPTION": "Name and description" + }, + "WIKI": { + "DATETIME": "DD MMM YYYY HH:mm", + "PLACEHOLDER_PAGE": "Write your wiki page", + "REMOVE": "Remove this wiki page", + "DELETE_LIGHTBOX_TITLE": "Delete Wiki Page", + "NAVIGATION": { + "SECTION_NAME": "Links", + "ACTION_ADD_LINK": "Add link" + }, + "SUMMARY": { + "TIMES_EDITED": "times
edited", + "LAST_EDIT": "last
edit", + "LAST_MODIFICATION": "last modification" + } + } +} diff --git a/app/locales/locale-es.json b/app/locales/locale-es.json new file mode 100644 index 00000000..27b4ea4b --- /dev/null +++ b/app/locales/locale-es.json @@ -0,0 +1,1091 @@ +{ + "COMMON": { + "YES": "Si", + "NO": "No", + "LOADING": "Cargando...", + "LOADING_PROJECT": "Cargando projecto...", + "DATE": "DD MMM YYYY", + "DATETIME": "DD MMM YYYY HH:mm", + "SAVE": "Guardar", + "CANCEL": "Cancelar", + "ACCEPT": "Aceptar", + "DELETE": "Borrar", + "CREATE": "Crear", + "ADD": "Añadir", + "COPY_TO_CLIPBOARD": "Copiar en el portapapeles: Ctrl+C", + "EDIT": "Editar", + "DRAG": "Arrastra", + "TAG_LINE": "Tu herramienta de gestión de proyecto ágil, gratuíta y de código abierto", + "TAG_LINE_2": "AMA TU PROYECTO", + "BLOCK": "Bloqueada", + "UNBLOCK": "Desbloquear", + "BLOCKED": "Bloqueada", + "CREATED_BY": "Creada por {{fullDisplayName}}", + "FROM": "de", + "TO": "a", + "CLOSE": "cerrar", + "BLOCKED_NOTE": "¿Por qué está esta historia de usuario bloqueada?", + "BLOCKED_REASON": "Por favor, explica la razón", + "GO_HOME": "Llévame a casa", + "PLUGINS": "Plugins", + "BETA": "¡Estamos en fase beta!", + "ONE_ITEM_LINE": "Un elemento por línea...", + "NEW_BULK": "Nueva inserción en bloque", + "RELATED_TASKS": "Tareas relacionadas", + "LOGOUT": "Cerrar sesión", + "EXTERNAL_USER": "un usuario externo", + "GENERIC_ERROR": "Uno de nuestros Oompa Loompas dice {{error}}.", + "IOCAINE_TEXT": "¿Te sientes fuera de tu zona de confort en una tarea? Asegúrate de que los demás están al tanto de ello, marca el check de la Iocaína al editar una tarea. Igual eu era posible llegar a ser inmune a este veneno mortal a base de consumir pequeñas dosis a lo largo del tiempo, es posible conseguir mejor en lo que estás haciendo si afrontas de vez en cuando esta clase de retos!", + "FORM_ERRORS": { + "DEFAULT_MESSAGE": "Este valor parece inválido.", + "TYPE_EMAIL": "El valor debe ser un email.", + "TYPE_URL": "El valor debe ser una url.", + "TYPE_URLSTRICT": "El valor debe ser una url.", + "TYPE_NUMBER": "El valor debe ser un número.", + "TYPE_DIGITS": "El valor deben ser digitos.", + "TYPE_DATEISO": "El valor debe ser una fecha válida (DD-MM-YYY)", + "TYPE_ALPHANUM": "El valor debe ser alfanumérico.", + "TYPE_PHONE": "El valor debe ser un teléfono válido.", + "NOTNULL": "No puede ser un valor nulo.", + "NOT_BLANK": "El valor no puede quedar en blanco.", + "REQUIRED": "Valor requerido.", + "REGEXP": "Este valor parece inválido.", + "MIN": "El valor debe ser mayor o igual que %s.", + "MAX": "El valor debe ser menor o igual que %s.", + "RANGE": "El valor debe estar entre %s y %s.", + "MIN_LENGTH": "El valor es demasiado corto. Debe contener al menos %s caracteres.", + "MAX_LENGTH": "El valor es demasiado corto. Debe contener %s caracteres como máximo.", + "RANGE_LENGTH": "Longitud erronea. Debe estar entre %s y %s caracteres.", + "MIN_CHECK": "Debes seleccionar al menos %s.", + "MAX_CHECK": "Debes seleccionar %s o menos.", + "RANGE_CHECK": "Debes seleccionar de %s a %s.", + "EQUAL_TO": "Este valor debe ser el mismo." + }, + "PICKERDATE": { + "FORMAT": "DD MMM YYYY", + "IS_RTL": "false", + "FIRST_DAY_OF_WEEK": "1", + "PREV_MONTH": "Mes Anterior", + "NEXT_MONTH": "Mes Siguiente", + "MONTHS": { + "JAN": "Enero", + "FEB": "Febrero", + "MAR": "Marzo", + "APR": "Abril", + "MAY": "Mayo", + "JUN": "Junio", + "JUL": "Julio", + "AUG": "Agosto", + "SEP": "Septiembre", + "OCT": "Octubre", + "NOV": "Noviembre", + "DEC": "Diciembre" + }, + "WEEK_DAYS": { + "SUN": "Domingo", + "MON": "Lunes", + "TUE": "Martes", + "WED": "Miércoles", + "THU": "Jueves", + "FRI": "Viernes", + "SAT": "Sábado" + }, + "WEEK_DAYS_SHORT": { + "SUN": "Dom", + "MON": "Lun", + "TUE": "Mar", + "WED": "Mie", + "THU": "Jue", + "FRI": "Vie", + "SAT": "Sáb" + } + }, + "TAGS": { + "PLACEHOLDER": "¿Qué soy? Etiquétame...", + "DELETE": "Borrar etiqueta", + "ADD": "Añadir etiqueta" + }, + "DESCRIPTION": { + "EMPTY": "El espacio vacío es tan aburrido... trata de ser descriptivo... ", + "NO_DESCRIPTION": "Sin descripción todavía" + }, + "FIELDS": { + "SUBJECT": "Asunto", + "NAME": "Nombre", + "URL": "URL", + "DESCRIPTION": "Descripción", + "VALUE": "Valor", + "SLUG": "Slug", + "COLOR": "Color", + "IS_CLOSED": "¿Está Cerrado?", + "STATUS": "Estado", + "TYPE": "Tipo", + "SEVERITY": "Gravedad", + "PRIORITY": "Prioridad", + "ASSIGNED_TO": "Asignado a", + "POINTS": "Puntos", + "BLOCKED_NOTE": "Motivo del bloqueo", + "IS_BLOCKED": "está bloqueada" + }, + "ROLES": { + "ALL": "Todos" + }, + "ASSIGNED_TO": { + "NOT_ASSIGNED": "Sin asignar", + "DELETE_ASSIGNMENT": "Eliminar asignaciones", + "REMOVE_ASSIGNED": "Eliminar asignación", + "TOO_MANY": "...Demasiados usuarios, continué filtrando", + "CONFIRM_UNASSIGNED": "¿Está seguro de que desea dejarla sin asignar?", + "TITLE_ACTION_EDIT_ASSIGNMENT": "Editar asignación" + }, + "STATUS": { + "CLOSED": "Cerrada", + "OPEN": "Abierto" + }, + "WATCHERS": { + "ADD": "Añadir un observador...", + "TITLE": "observadores", + "DELETE": "Eliminar el observador", + "TITLE_LIGHTBOX_DELETE_WARTCHER": "Eliminar el observador..." + }, + "CUSTOM_ATTRIBUTES": { + "CUSTOM_FIELDS": "Atributo Personalizados", + "SAVE": "Guardar atributo personalizado", + "EDIT": "Editar Atributo Personalizado", + "DELETE": "Borrar atributos personalizados", + "CONFIRM_DELETE": "Recuerda que todos los valores en este atributo personalizado serán borrados.
¿Estás seguro que desea continuar?" + }, + "FILTERS": { + "TITLE": "filtros", + "INPUT_PLACEHOLDER": "Asunto o referencia", + "TITLE_ACTION_FILTER_BUTTON": "busqueda", + "BREADCRUMB_TITLE": "Regresar a categorias", + "BREADCRUMB_FILTERS": "Filtros", + "BREADCRUMB_STATUS": "estado" + }, + "WYSIWYG": { + "H1_BUTTON": "Título de primer nivel", + "H1_SAMPLE_TEXT": "Tu título aquí...", + "H2_BUTTON": "Título de segundo nivel", + "H2_SAMPLE_TEXT": "Tu título aquí...", + "H3_BUTTON": "Título de tercer nivel", + "H3_SAMPLE_TEXT": "Tu título aquí...", + "BOLD_BUTTON": "Negrita", + "BOLD_BUTTON_SAMPLE_TEXT": "Tu texto aquí...", + "ITALIC_BUTTON": "Cursiva", + "ITALIC_SAMPLE_TEXT": "Tu texto aquí...", + "STRIKE_BUTTON": "Tachado", + "STRIKE_SAMPLE_TEXT": "Tu texto aquí...", + "BULLETED_LIST_BUTTON": "Lista con viñetas", + "BULLETED_LIST_SAMPLE_TEXT": "Tu texto aquí...", + "NUMERIC_LIST_BUTTON": "Lista numérica", + "NUMERIC_LIST_SAMPLE_TEXT": "Tu texto aquí...", + "PICTURE_BUTTON": "Imagen", + "PICTURE_SAMPLE_TEXT": "Tu texto alternatívo para la imagen aquí...", + "LINK_BUTTON": "Enlace", + "LINK_SAMPLE_TEXT": "Tu texto del enlace aquí...", + "QUOTE_BLOCK_BUTTON": "Cita", + "QUOTE_BLOCK_SAMPLE_TEXT": "Tu texto aquí...", + "CODE_BLOCK_BUTTON": "Código", + "CODE_BLOCK_SAMPLE_TEXT": "Tu texto aquí...", + "PREVIEW_BUTTON": "Previsualizar", + "EDIT_BUTTON": "Editar", + "MARKDOWN_HELP": "Ayuda de sintaxis Markdown" + }, + "PERMISIONS_CATEGORIES": { + "SPRINTS": { + "NAME": "Sprints", + "VIEW_SPRINTS": "Ver sprints", + "ADD_SPRINTS": "Crear sprints", + "MODIFY_SPRINTS": "Editar sprints", + "DELETE_SPRINTS": "Borrar sprints" + }, + "USER_STORIES": { + "NAME": "Historias de Usuario", + "VIEW_USER_STORIES": "Ver historias de usuario", + "ADD_USER_STORIES": "Crear historias de usuario", + "MODIFY_USER_STORIES": "Editar historias de usuario", + "DELETE_USER_STORIES": "Borrar historias de usuario" + }, + "TASKS": { + "NAME": "Tareas", + "VIEW_TASKS": "Ver tareas", + "ADD_TASKS": "Crear tareas", + "MODIFY_TASKS": "Editar tareas", + "DELETE_TASKS": "Borrar tareas" + }, + "ISSUES": { + "NAME": "Peticiones", + "VIEW_ISSUES": "Ver peticiones", + "ADD_ISSUES": "Crear peticiones", + "MODIFY_ISSUES": "Editar peticiones", + "DELETE_ISSUES": "Borrar peticiones" + }, + "WIKI": { + "NAME": "Wiki", + "VIEW_WIKI_PAGES": "Ver páginas", + "ADD_WIKI_PAGES": "Crear páginas", + "MODIFY_WIKI_PAGES": "Editar páginas", + "DELETE_WIKI_PAGES": "Borrar páginas", + "VIEW_WIKI_LINKS": "Ver enlaces", + "ADD_WIKI_LINKS": "Crear enlaces", + "DELETE_WIKI_LINKS": "Borrar enlaces" + } + } + }, + "AUTH": { + "INVITED_YOU": "te ha invitado a unirte al proyecto", + "NOT_REGISTERED_YET": "¿Aún no está registrado?", + "REGISTER": "Registro", + "CREATE_ACCOUNT": "crea tu cuenta gratis aquí" + }, + "ATTACHMENT": { + "SECTION_NAME": "adjuntos", + "TITLE": "{{ fileName }} subido el {{ date }}", + "DESCRIPTION": "Escribe una pequeña descripción", + "DEPRECATED": "(obsoleto)", + "DEPRECATED_FILE": "¿Desactualizado?", + "ADD": "Agrega nuevos adjunto", + "MAX_FILE_SIZE": "[Tamaño Max. : {{maxFileSize}}]", + "SHOW_DEPRECATED": "+ muestra adjuntos desactualizados", + "HIDE_DEPRECATED": "- ocultar adjuntos obsoletos", + "COUNT_DEPRECATED": "({{ counter }} obsoletos)\n", + "MAX_UPLOAD_SIZE": "El tamaño máximo de subida es de {{maxFileSize}}", + "DATE": "DD MMM YYYY [a las] hh:mm\n", + "ERROR_UPLOAD_ATTACHMENT": "No hemos podido subir el fichero '{{fileName}}'. {{errorMessage}}", + "TITLE_LIGHTBOX_DELETE_ATTACHMENT": "Borrar adjunto...", + "MSG_LIGHTBOX_DELETE_ATTACHMENT": "el adjunto '{{fileName}}'", + "ERROR_DELETE_ATTACHMENT": "No hemos podido borrarlo: {{errorMessage}}", + "FIELDS": { + "IS_DEPRECATED": "Está desactualizado" + } + }, + "PAGINATION": { + "PREVIOUS": "Anterior", + "NEXT": "Siguiente" + }, + "ADMIN": { + "COMMON": { + "TITLE_ACTION_EDIT_VALUE": "Editar valor", + "TITLE_ACTION_DELETE_VALUE": "Eliminar valor" + }, + "HELP": "¿Necesitas ayuda? ¡Revisa nuestra pagina de soporte! ", + "PROJECT_DEFAULT_VALUES": { + "TITLE": "Valores por defecto", + "SUBTITLE": "Define los valores por defecto para todos los selectores." + }, + "MEMBERSHIPS": { + "TITLE": "Administrar miembros", + "ADD_BUTTON": "+ Nuevo miembro", + "ADD_BUTTON_TITLE": "Añadir un nuevo miembro" + }, + "PROJECT_EXPORT": { + "TITLE": "Exportar", + "SUBTITLE": "Exportar tu proyecto para guardar una copia de seguridad o para crear uno nuevo basado en este.", + "EXPORT_BUTTON": "Exportar", + "EXPORT_BUTTON_TITLE": "Exportar tus proyecto", + "LOADING_TITLE": "Estamos generando tu fichero con el volcado de datos", + "DUMP_READY": "¡Tu fichero con el volcado de datos está listo!", + "LOADING_MESSAGE": "Por favor no cierres la ventana.", + "ASYNC_MESSAGE": "Te enviaremos un email cuando esté listo.", + "SYNC_MESSAGE": "Si la descarga no comienza automáticamente haz click aquí.", + "ERROR": "Nuestros Oompa Loompas tienen algunos problemas generando el volcado de tus datos. Por favor inténtalo de nuevo.", + "ERROR_BUSY": "Lo sentimos, nuestros Oompa Loompas están muy ocupados en este momento. Por favor inténtalo nuevamente en unos minutos.", + "ERROR_MESSAGE": "Nuestros Oompa Loompas han tenido algunos problemas generando el volcado de datos: {{message}}" + }, + "MODULES": { + "TITLE": "Módulos", + "ENABLE": "Activado", + "DISABLE": "Desactivado", + "BACKLOG": "Backlog", + "BACKLOG_DESCRIPTION": "Gestiona tus historias de usuario para mantener una vista organizada y priorizada de los próximos trabajos que deberás afrontar. ", + "KANBAN": "Kanban", + "KANBAN_DESCRIPTION": "Organiza tus proyectos de una manera flexible con este panel.", + "ISSUES": "Peticiones", + "ISSUES_DESCRIPTION": "Haz seguimiento de los bugs, preguntas y peticiones de mejoras relacionadas con tu proyecto. ¡No te pierdas nada!", + "WIKI": "Wiki", + "WIKI_DESCRIPTION": "Añade, modifica o borra contenido en colaboración con otros miembros. Este es el lugar adecuado para la documentación de tu proyecto.", + "MEETUP": "Meet Up", + "MEETUP_DESCRIPTION": "Elige tu sistema de videoconferencia. Incluso los desarrolladores necesitan el contacto cara a cara.", + "SELECT_VIDEOCONFERENCE": "Elige un sistema de videoconferencia", + "SALT_CHAT_ROOM": "Puedes añadirle un código salt al nombre del chat room" + }, + "PROJECT_PROFILE": { + "PAGE_TITLE": "Perfil del proyecto - {{sectionName}} - {{projectName}}", + "PROJECT_DETAILS": "Info del proyecto", + "PROJECT_NAME": "Nombre del proyecto", + "PROJECT_SLUG": "Slug de proyecto", + "NUMBER_SPRINTS": "Número de sprints totales estimado", + "NUMBER_US_POINTS": "Número de puntos de historia totales estimados", + "TAGS": "Etiquetas", + "DESCRIPTION": "Descripción", + "PUBLIC_PROJECT": "Proyecto público", + "PRIVATE_PROJECT": "Proyecto privado", + "DELETE": "Eliminar este proyecto" + }, + "REPORTS": { + "TITLE": "Informes", + "SUBTITLE": "Exporta los datos de tu proyecto en formato CSV y crea tus propios informes.", + "DESCRIPTION": "Descarga el fichero CSV o copia la URL generada y abre tu editor de textos o hoja de cálculo favorito para realizar tus propios informes. Podrás visualizar y analizar todos los datos fácilmente.", + "HELP": "¿Cómo puedo usar esto en mi hoja de cálculo?", + "REGENERATE_TITLE": "Cambiar URL", + "REGENERATE_SUBTITLE": "Vas a cambiar la url de acceso a los datos en formato CSV. La url anterior se deshabilitará. ¿Estás seguro?" + }, + "CSV": { + "SECTION_TITLE_US": "informes de historias de usuario", + "SECTION_TITLE_TASK": "Informes de tareas", + "SECTION_TITLE_ISSUE": "informes de peticiones", + "DOWNLOAD": "Descargar el CSV", + "URL_FIELD_PLACEHOLDER": "Por favor regenera la url del origen CSV", + "TITLE_REGENERATE_URL": "Regenerar url de origen CSV", + "ACTION_GENERATE_URL": "Generar Url", + "ACTION_REGENERATE": "Regenerar" + }, + "CUSTOM_FIELDS": { + "TITLE": "Atributos personalizados", + "SUBTITLE": "Especifica los atributos personalizados para las historias de usuario, tareas y peticiones", + "US_DESCRIPTION": "Atributos personalizados de historias de usuario", + "US_ADD": "Añadir un atributo personalizado en las historias de usuario", + "TASK_DESCRIPTION": "Atributos personalizados de tareas", + "TASK_ADD": "Añadir un atributo personalizado en las tareas", + "ISSUE_DESCRIPTION": "Atributos personalizados de peticiones", + "ISSUE_ADD": "Añadir un atributo personalizado en las peticiones" + }, + "PROJECT_VALUES": { + "APP_TITLE": "Valores del proyecto - {{sectionName}} - {{projectName}}", + "REPLACEMENT": "Todos los elementos con este valor cambiarán a", + "ERROR_DELETE_ALL": "No puedes eliminar todos los valores." + }, + "PROJECT_VALUES_POINTS": { + "TITLE": "Puntos de historia", + "SUBTITLE": "Especifica los puntos a los que se podrían estimar tus historias de usuario", + "ACTION_ADD": "Añadir nuevo punto" + }, + "PROJECT_VALUES_PRIORITIES": { + "TITLE": "Prioridades de las peticiones", + "SUBTITLE": "Especifica las prioridades que podrán tener tus peticiones", + "ACTION_ADD": "Añadir nueva prioridad" + }, + "PROJECT_VALUES_SEVERITIES": { + "TITLE": "Gravedad de las peticiones", + "SUBTITLE": "Especifica la gravedad que tendrán tus peticiones", + "ACTION_ADD": "Añadir nueva gravedad" + }, + "PROJECT_VALUES_STATUS": { + "TITLE": "Estado", + "SUBTITLE": "Especifica los estado que atravesarán tus historias de usuario, tareas y peticiones", + "US_TITLE": "Estados de historias", + "TASK_TITLE": "Estados de Tarea", + "ISSUE_TITLE": "Estados de la petición" + }, + "PROJECT_VALUES_TYPES": { + "TITLE": "Tipos", + "SUBTITLE": "Especifica los deferentes tipos posibles de peticiones que pueden existir.", + "ISSUE_TITLE": "Tipos de la petición", + "ACTION_ADD": "Añadir nuevo tipo" + }, + "ROLES": { + "SECTION_NAME": "Roles - {{projectName}}", + "WARNING_NO_ROLE": "Ojo, ningún rol en tu proyecto podrá estimar historias de usuario", + "HELP_ROLE_ENABLED": "Si lo activas, los miembros que posean este rol serán capaces de estimar las histórias de usuario", + "COUNT_MEMBERS": "{{ role.members_count }} miembros con este rol", + "TITLE_DELETE_ROLE": "Borrar Rol", + "REPLACEMENT_ROLE": "Todos los usuarios con este rol serán movidos a", + "WARNING_DELETE_ROLE": "Cuidado, todas las estimaciones asociadas a este rol se perderán", + "ERROR_DELETE_ALL": "No puedes eliminar todos los valores", + "EXTERNAL_USER": "Usuario externo" + }, + "THIRD_PARTIES": { + "SECRET_KEY": "Secret key", + "PAYLOAD_URL": "Payload URL", + "VALID_IPS": "IPs de origen válidas (separadas por ,)" + }, + "BITBUCKET": { + "SECTION_NAME": "Bitbucket", + "APP_TITLE": "Bitbucket - {{projectName}}", + "INFO_VERIFYING_IP": "Las peticiones de Bitbucket no van firmadas, con la IP de origen verificamos su procedencia. Déjalo vacío y no se verificarán." + }, + "GITLAB": { + "SECTION_NAME": "Gitlab", + "APP_TITLE": "Gitlab - {{projectName}}", + "INFO_VERIFYING_IP": "Las peticiones de Gitlab no van firmadas, con la IP de origen verificamos su procedencia. Déjalo vacío y no se verificarán." + }, + "GITHUB": { + "SECTION_NAME": "Github", + "APP_TITLE": "Github - {{projectName}}" + }, + "WEBHOOKS": { + "APP_TITLE": "Webhooks - {{projectName}}", + "SECTION_NAME": "Webhooks", + "SUBTITLE": "Los Webhooks notificarán a servicios externos sobre todos los eventos que ocurren en Taiga como comentarios, historias de usuario...", + "ADD_NEW": "Añadir un Nuevo Webhook", + "TYPE_NAME": "Escribe el nombre del servicio", + "TYPE_PAYLOAD_URL": "Escribe la 'payload URL' del servicio", + "TYPE_SERVICE_SECRET": "Escribe la \"secret key\" del servicio", + "SAVE": "Guardar Webhook", + "CANCEL": "Cancelar Webhook", + "SHOW_HISTORY": "(Mostrar histórico)", + "TEST": "Testea el Webhook", + "EDIT": "Editar Webhook", + "DELETE": "Eliminar Webhook", + "REQUEST": "Solicitud", + "RESEND_REQUEST": "Reenviar solicitud", + "HEADERS": "Cabeceras", + "PAYLOAD": "Payload", + "RESPONSE": "Respuesta", + "DATE": "DD MMM YYYY [a las] hh:mm:ss", + "ACTION_HIDE_HISTORY": "(Ocultar historial)", + "ACTION_HIDE_HISTORY_TITLE": "+ info", + "ACTION_SHOW_HISTORY": "(Mostrar historial)", + "ACTION_SHOW_HISTORY_TITLE": "- info", + "WEBHOOK_NAME": "Webhook '{{name}}'" + }, + "CUSTOM_ATTRIBUTES": { + "ADD": "Añadir atributo personalizado", + "EDIT": "Editar atributo personalizado", + "DELETE": "Eliminar atributo personalizado", + "SAVE_TITLE": "Guardar atributo personalizado", + "CANCEL_TITLE": "Cancelar la creación", + "SET_FIELD_NAME": "Escribe el nombre del atributo personalizado", + "SET_FIELD_DESCRIPTION": "Escribe una descripción para el atributo personalizado", + "ACTION_UPDATE": "Actualizar Atributo Personalizado", + "ACTION_CANCEL_EDITION": "Cancelar edición" + }, + "MEMBERSHIP": { + "COLUMN_MEMBER": "Miembro", + "COLUMN_ADMIN": "Admin", + "COLUMN_ROLE": "Rol", + "COLUMN_STATUS": "Estado", + "STATUS_ACTIVE": "Activado", + "STATUS_PENDING": "Pendiente", + "DELETE_MEMBER": "Borrar miembro", + "SUCCESS_SEND_INVITATION": "Hemos enviado nuevamente la invitación a '{{email}}'.", + "ERROR_SEND_INVITATION": "No hemos enviado la invitación.", + "SUCCESS_DELETE": "Hemos eliminado {{message}}.", + "ERROR_DELETE": "No se ha podido eliminar {{message}}. ", + "DEFAULT_DELETE_MESSAGE": "la invitación enviada a" + }, + "DEFAULT_VALUES": { + "LABEL_POINTS": "Valor por defecto para el selector de puntos", + "LABEL_US": "Valor por defecto para el selector de estado de historia", + "LABEL_TASK_STATUS": "Valor por defecto para el selector de estado de tarea", + "LABEL_PRIORITY": "Valor por defecto para el selector de prioridad", + "LABEL_SEVERITY": "Valor por defecto para el selector de gravedad", + "LABEL_ISSUE_TYPE": "Valor por defecto para el selector de tipo de la petición", + "LABEL_ISSUE_STATUS": "Valor por defecto para el selector de estado de petición" + }, + "STATUS": { + "PLACEHOLDER_WRITE_STATUS_NAME": "Escribe un nombre para el nuevo estado" + }, + "TYPES": { + "PLACEHOLDER_WRITE_NAME": "Escribe un nombre para el nuevo elemento" + }, + "US_STATUS": { + "ACTION_ADD_STATUS": "Añadir nuevo estado", + "IS_ARCHIVED_COLUMN": "¿Archivar?", + "WIP_LIMIT_COLUMN": "Límite WIP", + "PLACEHOLDER_WRITE_NAME": "Escribe un nombre para el nuevo estado" + }, + "MENU": { + "TITLE": "Admin", + "PROJECT": "Proyecto", + "ATTRIBUTES": "Atributos", + "MEMBERS": "Miembros", + "PERMISSIONS": "Permisos", + "INTEGRATIONS": "Integraciones", + "PLUGINS": "Plugins" + }, + "SUBMENU_PROJECT_ATTRIBUTES": { + "TITLE": "Atributos" + }, + "SUBMENU_PROJECT_VALUES": { + "STATUS": "Estados", + "POINTS": "Puntos", + "PRIORITIES": "Prioridades", + "SEVERITIES": "Gravedades", + "TYPES": "Tipos", + "CUSTOM_FIELDS": "Atributos personalizados" + }, + "SUBMENU_PROJECT_PROFILE": { + "TITLE": "Perfil de proyecto" + }, + "SUBMENU_ROLES": { + "TITLE": "Roles", + "ACTION_NEW_ROLE": "+ Nuevo Rol", + "TITLE_ACTION_NEW_ROLE": "Añadir nuevo rol" + }, + "SUBMENU_THIDPARTIES": { + "TITLE": "Servicios" + } + }, + "PROJECT": { + "WELCOME": "Bienvenido", + "SECTION_PROJECTS": "Proyectos", + "STATS": { + "PROJECT": "puntos
proyecto", + "DEFINED": "puntos
definidos", + "ASSIGNED": "puntos
asignados", + "CLOSED": "puntos
cerrados" + }, + "SECTION": { + "SEARCH": "Buscar", + "BACKLOG": "Backlog", + "KANBAN": "Kanban", + "ISSUES": "Peticiones", + "WIKI": "Wiki", + "TEAM": "Equipo", + "MEETUP": "Meet Up", + "ADMIN": "Admin" + }, + "NAVIGATION": { + "SECTION_TITLE": "Tus proyectos", + "PLACEHOLDER_SEARCH": "Buscar en...", + "ACTION_CREATE_PROJECT": "Crear proyecto", + "TITLE_ACTION_IMPORT": "Importar proyecto", + "TITLE_PRVIOUS_PROJECT": "Mostrar proyectos anteriores", + "TITLE_NEXT_PROJECT": "Mostrar siguientes proyectos" + }, + "IMPORT": { + "TITLE": "Importando Proyecto", + "UPLOADING_FILE": "Subiendo el fichero con el volcado de datos", + "DESCRIPTION": "Este proceso puede tardar un ratito, por favor mantén la ventana abierta.", + "ASYNC_IN_PROGRESS_TITLE": "Nuestros Oompa Loompa están importando tu proyecto", + "ASYNC_IN_PROGRESS_MESSAGE": "Este proceso puede llevarnos algún tiempo
Te enviaremos un email cuando esté listo", + "UPLOAD_IN_PROGRESS_MESSAGE": "Subidos {{uploadedSize}} de {{totalSize}}", + "ERROR": "Nuestros Oompa Loompas tienen problemas para importar tus datos. Por favor inténtalo nuevamente.", + "ERROR_TOO_MANY_REQUEST": "Lo sentimos, nuestros Oompa Loompas están muy ocupados en este momento. Por favor inténtalo nuevamente en unos minutos.", + "ERROR_MESSAGE": "Nuestros Oompa Loompas tienen algunos problemas importando tus datos: {{error_message}}", + "ERROR_MAX_SIZE_EXCEEDED": "El fichero '{{fileName}}' ({{fileSize}}) es demasiado pesado para nuestros Oompa Loompas, prueba con uno de menos de ({{maxFileSize}}).", + "SYNC_SUCCESS": "Tu proyecto se ha importado con éxito." + } + }, + "LIGHTBOX": { + "DELETE_ACCOUNT": { + "SECTION_NAME": "Eliminar cuenta de Taiga", + "CONFIRM": "¿Está seguro que deseas eliminar tu cuenta de Taiga?", + "SUBTITLE": "¡Te extrañaremos! :-(", + "NEWSLETTER_LABEL_TEXT": "No quiero recibir la newsletter nunca más." + }, + "DELETE_PROJECT": { + "TITLE": "Borrar proyecto", + "QUESTION": "¿Esta seguro que decea eliminar este proyecto?", + "SUBTITLE": "Todos los datos del proyecto (historias de usuario, tareas, peticiones, sprints y páginas del wiki) se perderán :-(", + "CONFIRM": "Si, Estoy realmente seguro" + }, + "ASSIGNED_TO": { + "SELECT": "Asignar a...", + "SEARCH": "Buscar usuarios" + }, + "ADD_MEMBER": { + "TITLE": "Nuevo miembro", + "HELP_TEXT": "Si los usuarios ya están registrado en Taiga, se añadirán automáticamente. De lo contrario recibirán una invitación." + }, + "CREATE_ISSUE": { + "TITLE": "Añadir petición" + }, + "FEEDBACK": { + "TITLE": "Dinos algo...", + "COMMENT": "...un error, algunas sugerencias, algo cool... o incluso tus peores pesadillas con Taiga", + "ACTION_SEND": "Envíanos tu feedback" + }, + "SEARCH": { + "TITLE": "Busqueda", + "PLACEHOLDER_SEARCH": "¿Qué es lo que estás buscando?" + }, + "ADD_EDIT_SPRINT": { + "TITLE": "Nuevo sprint", + "PLACEHOLDER_SPRINT_NAME": "nombre del sprint", + "PLACEHOLDER_SPRINT_START": "Comienzo estimado", + "PLACEHOLDER_SPRINT_END": "Final Estimado", + "ACTION_DELETE_SPRINT": "¿Quiéres borrar este sprint?", + "TITLE_ACTION_DELETE_SPRINT": "borrar sprint", + "LAST_SPRINT_NAME": "el último sprint es {{lastSprint}} ;-) " + }, + "CREATE_EDIT_TASK": { + "TITLE": "Nueva tarea", + "PLACEHOLDER_SUBJECT": "El asunto de la tarea", + "PLACEHOLDER_STATUS": "Estado de tarea", + "OPTION_UNASSIGNED": "No asignada", + "PLACEHOLDER_SHORT_DESCRIPTION": "Escribe una breve descripción", + "ACTION_EDIT": "Editar tarea" + }, + "CREATE_EDIT_US": { + "TITLE": "Nueva Historia de Usuario", + "PLACEHOLDER_DESCRIPTION": "Por favor añade un texto descriptivo que pueda ayudar a otros a entender mejor esta historia.", + "NEW_US": "Nueva historia de usuario", + "EDIT_US": "Editar historia de usuario" + }, + "DELETE_SPRINT": { + "TITLE": "Borrar sprint" + }, + "CREATE_MEMBER": { + "PLACEHOLDER_INVITATION_TEXT": "(Opcional) Añade un texto personalizado a la invitación. Dile algo encantador a tus nuevos miembros ;-)", + "PLACEHOLDER_TYPE_EMAIL": "Escribe un email" + } + }, + "US": { + "SECTION_NAME": "Detalles de historia de usuario", + "LINK_TASKBOARD": "Panel de tareas", + "TITLE_LINK_TASKBOARD": "Ir al panel de tareas", + "TOTAL_POINTS": "total", + "ADD": "+ Añadir una Historia de Usuario", + "ADD_BULK": "Añadir nuevas Historias de Usuario en bloque", + "PROMOTED": "Esta historia ha sido promovida desde la petición:", + "TITLE_LINK_GO_TO_ISSUE": "Ir a petición", + "EXTERNAL_REFERENCE": "Esta historia ha sido creada desde", + "GO_TO_EXTERNAL_REFERENCE": "Ir al origen", + "BLOCKED": "Esta historia de usuario está bloqueada", + "PREVIOUS": "anterior historia de usuario", + "NEXT": "siguiente historia de usuario", + "TITLE_DELETE_ACTION": "Borrar Historia de Usuario", + "LIGHTBOX_TITLE_BLOKING_US": "Historia bloqueada", + "TASK_COMPLETED": "{{totalClosedTasks}}/{{totalTasks}} tareas completadas", + "ASSIGN": "Asignar Historia de Usuario", + "NOT_ESTIMATED": "No estimada", + "TOTAL_US_POINTS": "Total puntos de historia", + "FIELDS": { + "TEAM_REQUIREMENT": "Requerido por el Equipo", + "CLIENT_REQUIREMENT": "Requerido por el Cliente", + "FINISH_DATE": "Fecha de finalización" + } + }, + "COMMENTS": { + "DELETED_INFO": "Comentario borrado por {{user}} el {{date}}", + "TITLE": "Comentarios", + "COMMENT": "Comentar", + "TYPE_NEW_COMMENT": "Escribe un nuevo comentario aquí", + "SHOW_DELETED": "Mostrar comentarios eliminados", + "HIDE_DELETED": "Ocultar comentarios eliminados", + "RESTORE": "Restaurar comentario" + }, + "ACTIVITY": { + "SHOW_ACTIVITY": "Mostrar actividad", + "DATETIME": "DD MMM YYYY HH:mm", + "SHOW_MORE": "+ Ver entradas anteriores ({{showMore}} más)", + "TITLE": "Actividad", + "REMOVED": "borrado", + "ADDED": "agregado", + "US_POINTS": "Puntos de historia ({{name}})", + "NEW_ATTACHMENT": "nuevo adjunto", + "DELETED_ATTACHMENT": "adjunto eliminado", + "UPDATED_ATTACHMENT": "Adjunto {{filename}} actualizado", + "DELETED_CUSTOM_ATTRIBUTE": "eliminar atributos personalizados", + "SIZE_CHANGE": "{size, plural, one{Un cambio realizado} other{# cambios realizados}}", + "VALUES": { + "YES": "sí", + "NO": "no", + "EMPTY": "vacío", + "UNASSIGNED": "sin asignar" + }, + "FIELDS": { + "SUBJECT": "asunto", + "NAME": "nombre", + "DESCRIPTION": "descripción", + "CONTENT": "contenido", + "STATUS": "estado", + "IS_CLOSED": "está cerrada", + "FINISH_DATE": "fecha de finalización", + "TYPE": "tipo", + "PRIORITY": "prioridad", + "SEVERITY": "gravedad", + "ASSIGNED_TO": "asignado a", + "WATCHERS": "observadores", + "MILESTONE": "sprint", + "USER_STORY": "historia de usuario", + "PROJECT": "proyecto", + "IS_BLOCKED": "está bloqueada", + "BLOCKED_NOTE": "motivo del bloqueo", + "POINTS": "puntos", + "CLIENT_REQUIREMENT": "requerido por el cliente", + "TEAM_REQUIREMENT": "requerido por el equipo", + "IS_IOCAINE": "tiene iocaína", + "TAGS": "etiquetas", + "ATTACHMENTS": "adjuntos", + "IS_DEPRECATED": "está desactualizado", + "ORDER": "orden", + "BACKLOG_ORDER": "orden en backlog", + "SPRINT_ORDER": "orden en sprint", + "KANBAN_ORDER": "orden en kanban", + "TASKBOARD_ORDER": "orden en panel de tareas", + "US_ORDER": "orden en historia" + } + }, + "BACKLOG": { + "SECTION_NAME": "Backlog", + "MOVE_US_TO_CURRENT_SPRINT": "Mover al Sprint en curso", + "SHOW_FILTERS": "Mostrar filtros", + "SHOW_TAGS": "Ver etiquetas", + "EMPTY": "¡Tu backlog está vacío!", + "CREATE_NEW_US": "Crear una nueva historia", + "CREATE_NEW_US_EMPTY_HELP": "Es posible que desees crear una nueva historia de usuario", + "EXCESS_OF_POINTS": "Exceso de puntos", + "PENDING_POINTS": "Puntos pendientes", + "CLOSED_POINTS": "cerrada", + "COMPACT_SPRINT": "Compactar Sprint", + "GO_TO_TASKBOARD": "Ir al panel de tareas de {{::name}}", + "EDIT_SPRINT": "Editar Sprint", + "TOTAL_POINTS": "total", + "STATUS_NAME": "Nombre del Estado", + "SORTABLE_FILTER_ERROR": "No puedes arrastrar historias en el backlog cuando los filtros están en uso", + "DOOMLINE": "Alcance del proyecto (línea de la fatalidad :-P)", + "CHART": { + "XAXIS_LABEL": "Sprints", + "YAXIS_LABEL": "Puntos", + "OPTIMAL": "El número de puntos óptimos pendientes para el sprint {{xval}} debería ser de {{yval}}", + "REAL": "El número real de puntos pendientes para el sprint {{xval}} es de {{yval}}", + "INCREMENT_TEAM": "El número de puntos incrementados por requerimientos del equipo para el sprint {{xval}} es de {{yval}}", + "INCREMENT_CLIENT": "El número de puntos incrementados por requerimientos del cliente para el sprint {{xval}} es de {{yval}}" + }, + "TAGS": { + "TOGGLE": "Cambia la visibilidad de los tags", + "SHOW": "Mostrar etiquetas", + "HIDE": "Ocultar etiquetas" + }, + "TABLE": { + "COLUMN_US": "Historias de Usuario", + "TITLE_COLUMN_POINTS": "Seleccionar vista por Rol" + }, + "SPRINT_SUMMARY": { + "TOTAL_POINTS": "puntos
totales", + "COMPLETED_POINTS": "puntos
completados", + "OPEN_TASKS": "tareas
abiertas", + "CLOSED_TASKS": "tareas
cerradas", + "IOCAINE_DOSES": "dosis de
iocaína", + "SHOW_STATISTICS_TITLE": "Ver estadísticas" + }, + "SUMMARY": { + "PROJECT_POINTS": "puntos
proyecto", + "DEFINED_POINTS": "puntos
definidos", + "CLOSED_POINTS": "puntos
cerrados", + "POINTS_PER_SPRINT": "puntos /
sprint" + }, + "FILTERS": { + "TOGGLE": "Cambia la visibilidad de los filtros", + "TITLE": "Filtros", + "REMOVE": "Borrar Filtros", + "HIDE": "Ocultar filtros", + "SHOW": "Ver Filtros", + "FILTER_CATEGORY_STATUS": "Estado", + "FILTER_CATEGORY_TAGS": "Etiquetas" + }, + "SPRINTS": { + "TITLE": "SPRINTS", + "DATE": "DD MMM YYYY", + "LINK_TASKBOARD": "Panel de Tareas del Sprint", + "TITLE_LINK_TASKBOARD": "Ir al panel de tareas de \"{{name}}\"", + "NUMBER_SPRINTS": "
sprints", + "TITLE_ACTION_NEW_SPRINT": "+ Nuevo Sprint", + "ACTION_NEW_SPRINT": "+ Nuevo sprint", + "ACTION_SHOW_CLOSED_SPRINTS": "Mostrar sprints cerrados", + "ACTION_HIDE_CLOSED_SPRINTS": "Ocultar sprints cerrados" + } + }, + "ERROR": { + "TEXT1": "Algo no va bien y nuestros Oompa Loompas están trabajando para resolverlo.", + "TEXT2": "Inténtalo de nuevo más tarde.", + "NOT_FOUND": "No encontrado", + "NOT_FOUND_TEXT": "Error 404. La página que estás buscando ya no existe. Puedes volver a la página de inicio de TAIGA y ver si encuentras lo que estás buscando. ", + "PERMISSION_DENIED": "Permiso denegado", + "PERMISSION_DENIED_CODE": "Error 403.", + "VERSION_ERROR": "Algún compañero se te ha adelantado y ha actualizado esto, nuestros Oompa Loompas no pueden aplicar tus cambios. Por favor, recarga la página y aplícalos nuevamente (se perderán)." + }, + "TASKBOARD": { + "SECTION_NAME": "Panel de Tareas", + "TITLE_ACTION_ADD": "Añade una nueva tarea", + "TITLE_ACTION_ADD_BULK": "Añadir nuevas tareas en bloque", + "TITLE_ACTION_ASSIGN": "Asignar tarea", + "TITLE_ACTION_EDIT": "Editar tarea", + "TABLE": { + "COLUMN": "Historia de usuario", + "TITLE_ACTION_FOLD": "Plegar columna", + "TITLE_ACTION_UNFOLD": "Desplegar columna", + "TITLE_ACTION_FOLD_ROW": "Plegar Fila", + "TITLE_ACTION_UNFOLD_ROW": "Desplegar Fila", + "FIELD_POINTS": "puntos", + "ROW_UNASSIGED_TASKS_TITLE": "Tareas no asignadas" + }, + "CHARTS": { + "XAXIS_LABEL": "Días", + "YAXIS_LABEL": "Puntos", + "OPTIMAL": "El número de puntos óptimos pendientes para el día {{formattedDate}} debería ser de {{roundedValue}}", + "REAL": "El número de puntos pendientes para el día {{formattedDate}} es de {{roundedValue}}", + "DATE": "DD MMMM YYYY" + } + }, + "TASK": { + "SECTION_NAME": "Detalles de tarea", + "LINK_TASKBOARD": "Panel de tareas", + "TITLE_LINK_TASKBOARD": "Ir al panel de tareas", + "PLACEHOLDER_SUBJECT": "Escribe el asunto de la nueva tarea", + "TITLE_SELECT_STATUS": "Nombre del estado", + "OWNER_US": "Esta tarea pertenece a\n", + "TITLE_LINK_GO_OWNER": "Ir a historia de usuario", + "ORIGIN_US": "Esta tarea pertenece a ", + "TITLE_LINK_GO_ORIGIN": "Ir a historia de usuario", + "BLOCKED": "Esta tarea está bloqueada", + "PREVIOUS": "tarea anterior", + "NEXT": "tarea siguiente", + "TITLE_DELETE_ACTION": "Eliminar Tarea", + "LIGHTBOX_TITLE_BLOKING_TASK": "Tarea bloqueada", + "FIELDS": { + "MILESTONE": "Sprint", + "USER_STORY": "Historia de usuario", + "IS_IOCAINE": "Tiene iocaína" + }, + "ACTION_IOCAINE": "Iocaína", + "TITLE_ACTION_IOCAINE": "¿Te sientes fuera de tu zona de confort en una tarea? Asegúrate de que los demás están al tanto de ello, marca el check de la Iocaína al editar una tarea. Igual eu era posible llegar a ser inmune a este veneno mortal a base de consumir pequeñas dosis a lo largo del tiempo, es posible conseguir mejor en lo que estás haciendo si afrontas de vez en cuando esta clase de retos!" + }, + "NOTIFICATION": { + "OK": "¡Todo Ok!", + "WARNING": "¡Cáspitas!, algo no ha ido bien...", + "WARNING_TEXT": "Nuestros Oompa Loompas están tristes, ¡Tus cambios no fueron guardados!", + "SAVED": "¡Nuestros Oompa Loompas guardaron todos tus cambios!", + "CLOSE": "Cerrar notificación", + "MAIL": "Notificaciones Por Mail", + "ASK_DELETE": "¿Esta seguro que desea eliminar?" + }, + "CANCEL_ACCOUNT": { + "TITLE": "Cancelar tu cuenta de usuario", + "SUBTITLE": "Sentimos que estés abandonando la taiga, esperamos que hayas disfrutado de tu estancia :)", + "PLACEHOLDER_INPUT_TOKEN": "token de cancelación de cuenta", + "ACTION_LEAVING": "¡Sí, me largo!", + "SUCCESS": "Nuestros Oompa Loompas eliminaron tu cuenta" + }, + "CHANGE_EMAIL_FORM": { + "TITLE": "Cambiar tu email", + "SUBTITLE": "̀¡Un click más y tu email se actualizará!", + "PLACEHOLDER_INPUT_TOKEN": "token de cambio de email", + "ACTION_CHANGE_EMAIL": "Cambiar email", + "SUCCESS": "Nuestros Oompa Loompas actualizaron tu correo" + }, + "CHANGE_PASSWORD_RECOVERY_FORM": { + "TITLE": "Crear una nueva contraseña de Taiga", + "SUBTITLE": "Y bueno, es posible que quieras comer un poco más de alimentos ricos en hierro, son buenos para tu cerebro :P", + "PLACEHOLDER_RECOVER_PASSWORD_TOKEN": "token de recuperación de contraseña", + "LINK_NEED_TOKEN": "¿Necesitas una?", + "TITLE_LINK_NEED_TOKEN": "¿Necesitas un token para recuperar tu contraseña porque la has olvidado?", + "PLACEHOLDER_NEW_PASSWORD": "Nueva contraseña", + "PLACEHOLDER_RE_TYPE_NEW_PASSWORD": "Reescriba la nueva contraseña", + "ACTION_RESET_PASSWORD": "Restablecer contraseña", + "SUCCESS": "Nuestro Oompa Loopas guardaron tu nueva contraseña.
Intenta registrarte con ella" + }, + "FORGOT_PASSWORD_FORM": { + "TITLE": "Vaya, ¿has olvidado tu contraseña?", + "SUBTITLE": "Escribe tu nombre de usuario o email para obtener una nueva", + "PLACEHOLDER_FIELD": "Nombre de usuario o email", + "ACTION_RESET_PASSWORD": "Restablecer Contraseña", + "LINK_CANCEL": "Nah, llévame de vuelta, creo que lo recordé.", + "SUCCESS": "¡Revisa tu bandeja de entrada!
Te hemos enviado un mail con las instrucciones necesarias para restablecer tu contraseña\n", + "ERROR": "Según nuestros Oompa Loompas tú no estás registrado" + }, + "LOGIN_COMMON": { + "HEADER": "Ya tengo una cuenta en Taiga", + "PLACEHOLDER_AUTH_NAME": "Nombre de usuario o email (distingue mayúsculas y minúsculas)", + "LINK_FORGOT_PASSWORD": "¿La olvidaste?", + "TITLE_LINK_FORGOT_PASSWORD": "¿Has olvidado tu contraseña?", + "ACTION_ENTER": "Entrar", + "ACTION_SIGN_IN": "Ingresar", + "PLACEHOLDER_AUTH_PASSWORD": "Contraseña (distingue mayúsculas y minúsculas)" + }, + "LOGIN_FORM": { + "ERROR_AUTH_INCORRECT": "Nuestros Oompa Loompas indican que tu nombre de usuario/correo o contraseña son incorrectos", + "ERROR_GENERIC": "Nuestros Oompa Loompas indican que ha habido un error.", + "SUCCESS": "Nuestros Oompa Loompas están felices, bienvenido a Taiga." + }, + "INVITATION_LOGIN_FORM": { + "NOT_FOUND": "Ooops, tenemos un problema
Nuestros Oompa Loompas no pueden encontrar tu invitación.", + "SUCCESS": "¡Acabas de unirte al proyecto! Bienvenido a {{project_name}}", + "ERROR": "Según nuestros Oompa Loompas tú no estás registrado o has escrito mal tu contraseña." + }, + "REGISTER_FORM": { + "TITLE": "Crea tu nueva cuenta en Taiga, ¡es gratis!", + "PLACEHOLDER_NAME": "Escribe un nombre de usuario (distingue mayúsculas y minúsculas)", + "PLACEHOLDER_FULL_NAME": "Escribe tu nombre completo", + "PLACEHOLDER_EMAIL": "Tu email", + "PLACEHOLDER_PASSWORD": "Establece una contraseña (distingue mayúsculas y minúsculas)", + "ACTION_SIGN_UP": "Registrarme", + "TITLE_LINK_LOGIN": "Iniciar sesión", + "LINK_LOGIN": "¿Ya te has registrado? Inicia sesión" + }, + "ISSUES": { + "LIST_SECTION_NAME": "Peticiones", + "SECTION_NAME": "Detalles de petición", + "ACTION_NEW_ISSUE": "+ NUEVA PETICIÓN", + "ACTION_PROMOTE_TO_US": "Promover a Historia de Usuario", + "PLACEHOLDER_FILTER_NAME": "Escribe un nombre para el filtro y pulsa enter", + "PROMOTED": "Esta petición ha sido promovida a la historia:", + "EXTERNAL_REFERENCE": "Esta petición ha sido creada a partir de ", + "GO_TO_EXTERNAL_REFERENCE": "Ir al origen", + "BLOCKED": "La petición está bloqueada", + "TITLE_PREVIOUS_ISSUE": "petición anterior", + "TITLE_NEXT_ISSUE": "petición siguiente", + "ACTION_DELETE": "Borrar petición", + "LIGHTBOX_TITLE_BLOKING_ISSUE": "Petición bloqueada", + "CONFIRM_PROMOTE": { + "TITLE": "Promover esta petición a una nueva historia de usuario", + "MESSAGE": "¿Está seguro de que desea crear una nueva Historia de Usuario a partir de esta Petición?" + }, + "FILTERS": { + "TITLE": "Filtros", + "INPUT_SEARCH_PLACEHOLDER": "Asunto o referencia", + "TITLE_ACTION_SEARCH": "Buscar", + "ACTION_SAVE_CUSTOM_FILTER": "guardar como filtro personalizado", + "BREADCRUMB": "Filtros", + "TITLE_BREADCRUMB": "Filtros", + "CATEGORIES": { + "TYPE": "Tipo", + "STATUS": "Estado", + "SEVERITY": "Gravedad", + "PRIORITIES": "Prioridad", + "TAGS": "Etiquetas", + "ASSIGNED_TO": "Asignado a", + "CREATED_BY": "Creada por", + "CUSTOM_FILTERS": "Filtros personalizados" + }, + "CONFIRM_DELETE": { + "TITLE": "Eliminar filtros personalizados", + "MESSAGE": "el filtro personalizado '{{customFilterName}}'" + } + }, + "TABLE": { + "COLUMNS": { + "TYPE": "Tipo", + "SEVERITY": "Gravedad", + "PRIORITY": "Prioridad", + "SUBJECT": "Asunto", + "STATUS": "Estado", + "CREATED": "Creado", + "ASSIGNED_TO": "Asignado a" + }, + "TITLE_ACTION_CHANGE_STATUS": "Cambio de estado", + "TITLE_ACTION_ASSIGNED_TO": "Asignado a", + "EMPTY": { + "TITLE": "No hay peticiones a reportar :-)", + "SUBTITLE": "¿Ha encontrado una petición?", + "ACTION_CREATE_ISSUE": "Crear una nueva petición" + } + } + }, + "KANBAN": { + "SECTION_NAME": "Kanban", + "TITLE_ACTION_FOLD": "Plegar columna", + "TITLE_ACTION_UNFOLD": "Desplegar columna", + "TITLE_ACTION_FOLD_CARDS": "Plegar tarjetas", + "TITLE_ACTION_UNFOLD_CARDS": "Desplegar tarjetas", + "TITLE_ACTION_ADD_US": "Añadir Nueva Historia de Usuario", + "TITLE_ACTION_ADD_BULK": "Añadir nuevas en bloque", + "ACTION_SHOW_ARCHIVED": "Ver archivados", + "ACTION_HIDE_ARCHIVED": "Ocultar archivados", + "HIDDEN_USER_STORIES": "Las historias de usuario en este estado están ocultas por defecto", + "ARCHIVED": "Tu has archivado", + "UNDO_ARCHIVED": "Arrástrala y suéltala de nuevo para deshacer el cambio" + }, + "SEARCH": { + "FILTER_USER_STORIES": "Historias de Usuario", + "FILTER_ISSUES": "Peticiones", + "FILTER_TASKS": "Tareas", + "FILTER_WIKI": "Páginas del Wiki", + "PLACEHOLDER_SEARCH": "Buscar...", + "TITLE_ACTION_SEARCH": "buscar", + "EMPTY_TITLE": "Parece que no se ha encontrado nada con tus criterios de búsqueda.", + "EMPTY_DESCRIPTION": "Prueba con otra pestaña de las de arriba o busca de nuevo" + }, + "TEAM": { + "SECTION_NAME": "Equipo", + "APP_TITLE": "EQUIPO - {{projectName}}", + "PLACEHOLDER_INPUT_SEARCH": "Buscar por nombre completo...", + "COLUMN_MR_WOLF": "Sr. Lobo", + "EXPLANATION_COLUMN_MR_WOLF": "Peticiones cerradas", + "COLUMN_IOCAINE": "Bebedor de Iocaína", + "EXPLANATION_COLUMN_IOCAINE": "Dósis de iocaína ingeridas", + "COLUMN_CERVANTES": "Cervantes", + "EXPLANATION_COLUMN_CERVANTES": "Páginas del Wiki editadas", + "COLUMN_BUG_HUNTER": "Cazador de Bugs", + "EXPLANATION_COLUMN_BUG_HUNTER": "Peticiones reportadas", + "COLUMN_NIGHT_SHIFT": "Turno de noche", + "EXPLANATION_COLUMN_NIGHT_SHIFT": "Tareas cerradas", + "COLUMN_TOTAL_POWER": "Potencia Total", + "EXPLANATION_COLUMN_TOTAL_POWER": "Puntos Totales", + "SECTION_TITLE_TEAM": "Equipo >", + "SECTION_FILTER_ALL": "Todo", + "CONFIRM_LEAVE_PROJECT": "¿Esta seguro que desea dejar el proyecto?", + "ACTION_LEAVE_PROJECT": "Abandonar este proyecto" + }, + "CHANGE_PASSWORD": { + "SECTION_NAME": "Cambiar contraseña", + "FIELD_CURRENT_PASSWORD": "Contraseña actual", + "PLACEHOLDER_CURRENT_PASSWORD": "Tu contraseña actual (o déjalo vacío si todavía no tienes contraseña)", + "FIELD_NEW_PASSWORD": "Nueva contraseña", + "PLACEHOLDER_NEW_PASSWORD": "Escribe una contraseña nueva", + "FIELD_RETYPE_PASSWORD": "Reescribe la nueva contraseña", + "PLACEHOLDER_RETYPE_PASSWORD": "Reescribe la nueva contraseña", + "ERROR_PASSWORD_MATCH": "Las contraseñas no coinciden" + }, + "USER_SETTINGS": { + "AVATAR_MAX_SIZE": "[Tamaño Max.: {{maxFileSize}}]", + "MENU": { + "SECTION_TITLE": "Configuración de Usuario", + "USER_PROFILE": "Perfil de usuario", + "CHANGE_PASSWORD": "Cambiar contraseña", + "EMAIL_NOTIFICATIONS": "Notificaciones por email" + }, + "NOTIFICATIONS": { + "SECTION_NAME": "Notificaciones por Email", + "COLUMN_PROJECT": "Proyecto", + "COLUMN_RECEIVE_ALL": "Recibir Todo", + "COLUMN_ONLY_INVOLVED": "Estoy involucrado", + "COLUMN_NO_NOTIFICATIONS": "Sin notificaciones", + "OPTION_ALL": "Todas", + "OPTION_INVOLVED": "Involucrado", + "OPTION_NONE": "Ninguna" + }, + "POPOVER": { + "USER_PROFILE": "Perfil de Usuario", + "CHANGE_PASSWORD": "Cambiar contraseña", + "NOTIFICATIONS": "Notificaciones", + "FEEDBACK": "Feedback", + "TITLE_AVATAR": "Preferencias de usuario" + } + }, + "USER_PROFILE": { + "IMAGE_HELP": "La imagen se escalará a 80x80px
", + "ACTION_CHANGE_IMAGE": "Cambiar", + "ACTION_USE_GRAVATAR": "Usar imagen de Gravatar", + "ACTION_DELETE_ACCOUNT": "Elimina cuenta de Taiga", + "CHANGE_EMAIL_SUCCESS": "¡Revisa tu bandeja de entrada!
Hemos enviado un mail a tu cuenta
con instrucciones para establecer tu nueva dirección", + "CHANGE_PHOTO": "Cambiar foto", + "FIELD": { + "USERNAME": "Nombre de usuario", + "EMAIL": "Correo", + "FULL_NAME": "Nombre completo", + "PLACEHOLDER_FULL_NAME": "Indica tu nombre completo (p. e. Íñigo Montoya)", + "BIO": "Bio", + "PLACEHOLDER_BIO": "Dinos algo acerca de ti", + "LANGUAGE": "Idioma", + "LANGUAGE_DEFAULT": "- usar idioma por defecto -" + } + }, + "WIZARD": { + "SECTION_TITLE_CHOOSE_TEMPLATE": "Elija una plantilla", + "CHOOSE_TEMPLATE_TEXT": "¿Que plantilla se ajusta mejor con tu proyecto?", + "SECTION_TITLE_CREATE_PROJECT": "Crear Proyecto", + "CREATE_PROJECT_TEXT": "Fresco y claro. ¡Es emocionante!", + "PROGRESS_TEMPLATE_SELECTION": "Selección de plantilla", + "PROGRESS_NAME_DESCRIPTION": "Nombre y descripción" + }, + "WIKI": { + "DATETIME": "DD MMM YYYY HH:mm", + "PLACEHOLDER_PAGE": "Escribe el contenido de tu página", + "REMOVE": "Eliminar esta página del wiki", + "DELETE_LIGHTBOX_TITLE": "Eliminar Página del Wiki", + "NAVIGATION": { + "SECTION_NAME": "Enlaces", + "ACTION_ADD_LINK": "Añadir enlace" + }, + "SUMMARY": { + "TIMES_EDITED": "veces
editada", + "LAST_EDIT": "última
edición", + "LAST_MODIFICATION": "ultima modificación" + } + } +} \ No newline at end of file diff --git a/app/locales/locale-fi.json b/app/locales/locale-fi.json new file mode 100644 index 00000000..4296274d --- /dev/null +++ b/app/locales/locale-fi.json @@ -0,0 +1,1091 @@ +{ + "COMMON": { + "YES": "Kyllä", + "NO": "Ei", + "LOADING": "Ladataan...", + "LOADING_PROJECT": "Ladataan projektia...", + "DATE": "DD MMM YYYY", + "DATETIME": "DD MMM YYYY HH:mm", + "SAVE": "Tallenna", + "CANCEL": "Peru", + "ACCEPT": "Hyväksy", + "DELETE": "Poista", + "CREATE": "Luo uusi", + "ADD": "Lisää", + "COPY_TO_CLIPBOARD": "Kopio leikekirjalle: Ctrl+C", + "EDIT": "Muokkaa", + "DRAG": "Vedä", + "TAG_LINE": "Ketterä, ilmainne avoimen koodin projektinhallintaohjelmisto", + "TAG_LINE_2": "Rakasta projektiasi", + "BLOCK": "Estä", + "UNBLOCK": "Salli", + "BLOCKED": "Suljettu", + "CREATED_BY": "Luonut {{fullDisplayName}}", + "FROM": "käyttäjältä", + "TO": "käyttäjälle", + "CLOSE": "sulje", + "BLOCKED_NOTE": "Miksi tämä käyttäjätarina on suljettu?", + "BLOCKED_REASON": "Ole hyvä ja anna syy", + "GO_HOME": "Vie minut kotiin", + "PLUGINS": "Pluginit", + "BETA": "Tämä on beta-versio!", + "ONE_ITEM_LINE": "Yksi riviä kohti...", + "NEW_BULK": "Lisää monta", + "RELATED_TASKS": "Liittyvät tehtävät", + "LOGOUT": "Kirjaudu ulos", + "EXTERNAL_USER": "ulkoinen käyttäjä", + "GENERIC_ERROR": "Oompa Loompas havaitsivat virheen {{error}}.", + "IOCAINE_TEXT": "Jos tehtävä ahdistaa, merkitse se hidasteeksi.", + "FORM_ERRORS": { + "DEFAULT_MESSAGE": "This value seems to be invalid.", + "TYPE_EMAIL": "This value should be a valid email.", + "TYPE_URL": "This value should be a valid url.", + "TYPE_URLSTRICT": "This value should be a valid url.", + "TYPE_NUMBER": "This value should be a valid number.", + "TYPE_DIGITS": "This value should be digits.", + "TYPE_DATEISO": "This value should be a valid date (YYYY-MM-DD).", + "TYPE_ALPHANUM": "This value should be alphanumeric.", + "TYPE_PHONE": "This value should be a valid phone number.", + "NOTNULL": "This value should not be null.", + "NOT_BLANK": "This value should not be blank.", + "REQUIRED": "This value is required.", + "REGEXP": "This value seems to be invalid.", + "MIN": "This value should be greater than or equal to %s.", + "MAX": "This value should be lower than or equal to %s.", + "RANGE": "This value should be between %s and %s.", + "MIN_LENGTH": "This value is too short. It should have %s characters or more.", + "MAX_LENGTH": "This value is too long. It should have %s characters or less.", + "RANGE_LENGTH": "This value length is invalid. It should be between %s and %s characters long.", + "MIN_CHECK": "You must select at least %s choices.", + "MAX_CHECK": "You must select %s choices or less.", + "RANGE_CHECK": "You must select between %s and %s choices.", + "EQUAL_TO": "This value should be the same." + }, + "PICKERDATE": { + "FORMAT": "DD MMM YYYY", + "IS_RTL": "false", + "FIRST_DAY_OF_WEEK": "1", + "PREV_MONTH": "Previous Month", + "NEXT_MONTH": "Next Month", + "MONTHS": { + "JAN": "January", + "FEB": "February", + "MAR": "March", + "APR": "April", + "MAY": "May", + "JUN": "June", + "JUL": "July", + "AUG": "August", + "SEP": "September", + "OCT": "October", + "NOV": "November", + "DEC": "December" + }, + "WEEK_DAYS": { + "SUN": "Sunday", + "MON": "Monday", + "TUE": "Tuesday", + "WED": "Wednesday", + "THU": "Thursday", + "FRI": "Friday", + "SAT": "Saturday" + }, + "WEEK_DAYS_SHORT": { + "SUN": "Sun", + "MON": "Mon", + "TUE": "Tue", + "WED": "Wed", + "THU": "Thu", + "FRI": "Fri", + "SAT": "Sat" + } + }, + "TAGS": { + "PLACEHOLDER": "Anna avainsana...", + "DELETE": "Poista avainsana", + "ADD": "Lisää avainsana" + }, + "DESCRIPTION": { + "EMPTY": "Tyhjä tila on tylsää...kerro jotain...", + "NO_DESCRIPTION": "Ei vielä kuvausta lisätty" + }, + "FIELDS": { + "SUBJECT": "Aihe", + "NAME": "Nimi", + "URL": "URL", + "DESCRIPTION": "Kuvaus", + "VALUE": "Arvo", + "SLUG": "Hitaus", + "COLOR": "Väri", + "IS_CLOSED": "Onko suljettu?", + "STATUS": "Tila", + "TYPE": "Tyyppi", + "SEVERITY": "Vakavuus", + "PRIORITY": "Tärkeys", + "ASSIGNED_TO": "Tekijä", + "POINTS": "Pisteet", + "BLOCKED_NOTE": "estetty muistiinpano", + "IS_BLOCKED": "on estetty" + }, + "ROLES": { + "ALL": "Kaikki" + }, + "ASSIGNED_TO": { + "NOT_ASSIGNED": "Tekijää ei valittu", + "DELETE_ASSIGNMENT": "Poista tekijä", + "REMOVE_ASSIGNED": "Poista tekijä", + "TOO_MANY": "...liikaa käyttäjiä, lisää suodattimia", + "CONFIRM_UNASSIGNED": "Haluatko varmasti jättää tämän ilman tekijää?", + "TITLE_ACTION_EDIT_ASSIGNMENT": "Muokkaa tekijää" + }, + "STATUS": { + "CLOSED": "Suljettu", + "OPEN": "Avoin" + }, + "WATCHERS": { + "ADD": "Lisää vahti", + "TITLE": "vahdit", + "DELETE": "Poista vahti", + "TITLE_LIGHTBOX_DELETE_WARTCHER": "Poista vahti..." + }, + "CUSTOM_ATTRIBUTES": { + "CUSTOM_FIELDS": "Omat kentät", + "SAVE": "Tallenna oma kenttä", + "EDIT": "Muokkaa omaa kenttää", + "DELETE": "Poista oma attribuutti", + "CONFIRM_DELETE": "Muista että oman kentän arvot poistetaan kentän mukana.
Jatketaanko?" + }, + "FILTERS": { + "TITLE": "suodattimet", + "INPUT_PLACEHOLDER": "Aihe tai viittaus", + "TITLE_ACTION_FILTER_BUTTON": "hae", + "BREADCRUMB_TITLE": "takaisin kategorioihin", + "BREADCRUMB_FILTERS": "Suodattimet", + "BREADCRUMB_STATUS": "tila" + }, + "WYSIWYG": { + "H1_BUTTON": "Päätason otsikko", + "H1_SAMPLE_TEXT": "Nimikkeesei tänne...", + "H2_BUTTON": "Toisen tason otsikko", + "H2_SAMPLE_TEXT": "Nimikkeesi tänne...", + "H3_BUTTON": "Kolmannen tason otsikko", + "H3_SAMPLE_TEXT": "Nimikkeesi tänne...", + "BOLD_BUTTON": "Lihavoitu", + "BOLD_BUTTON_SAMPLE_TEXT": "Kirjoita tänne...", + "ITALIC_BUTTON": "Kursiivi", + "ITALIC_SAMPLE_TEXT": "Kirjoita tänne...", + "STRIKE_BUTTON": "Lakko", + "STRIKE_SAMPLE_TEXT": "Kirjoita tänne...", + "BULLETED_LIST_BUTTON": "Numeroimaton lista", + "BULLETED_LIST_SAMPLE_TEXT": "Kirjoita tänne...", + "NUMERIC_LIST_BUTTON": "Numeroitu lista", + "NUMERIC_LIST_SAMPLE_TEXT": "Kirjoita tänne...", + "PICTURE_BUTTON": "Kuva", + "PICTURE_SAMPLE_TEXT": "Vaihtoehtoinen kuvan teksti tänne...", + "LINK_BUTTON": "Linkki", + "LINK_SAMPLE_TEXT": "Linkkiteksti tänne...", + "QUOTE_BLOCK_BUTTON": "Lainaus", + "QUOTE_BLOCK_SAMPLE_TEXT": "Kirjoita tänne...", + "CODE_BLOCK_BUTTON": "Koodi-lohko", + "CODE_BLOCK_SAMPLE_TEXT": "Kirjoita tänne...", + "PREVIEW_BUTTON": "Esikatselu", + "EDIT_BUTTON": "Muokkaa", + "MARKDOWN_HELP": "Merkintätavan ohjeet" + }, + "PERMISIONS_CATEGORIES": { + "SPRINTS": { + "NAME": "Kierrokset", + "VIEW_SPRINTS": "Katso kierroksia", + "ADD_SPRINTS": "Lisää kierroksia", + "MODIFY_SPRINTS": "Muokkaa kieroksia", + "DELETE_SPRINTS": "Poista kierroksia" + }, + "USER_STORIES": { + "NAME": "Käyttäjätarinat", + "VIEW_USER_STORIES": "Katso käyttäjätarinoita", + "ADD_USER_STORIES": "Lisää käyttäjätarinoita", + "MODIFY_USER_STORIES": "Muokkaa käyttäjätarinoita", + "DELETE_USER_STORIES": "Poista käyttäjätarinoita" + }, + "TASKS": { + "NAME": "Tehtävät", + "VIEW_TASKS": "Katsot tehtäviä", + "ADD_TASKS": "Lisää tehtäviä", + "MODIFY_TASKS": "Muokkaa tehtäviä", + "DELETE_TASKS": "Poista tehtäviä" + }, + "ISSUES": { + "NAME": "Pyynnöt", + "VIEW_ISSUES": "Katso pyyntöjä", + "ADD_ISSUES": "Lisää pyyntöjä", + "MODIFY_ISSUES": "Muokkaa pyyntöjä", + "DELETE_ISSUES": "Poista pyyntöjä" + }, + "WIKI": { + "NAME": "Wiki", + "VIEW_WIKI_PAGES": "Katso wiki-sivuja", + "ADD_WIKI_PAGES": "Lisää wiki-sivuja", + "MODIFY_WIKI_PAGES": "Muokkaa wiki-sivuja", + "DELETE_WIKI_PAGES": "Poista wiki-sivuja", + "VIEW_WIKI_LINKS": "Katso wiki-linkkejä", + "ADD_WIKI_LINKS": "Lisää wiki-linkkejä", + "DELETE_WIKI_LINKS": "Poista wiki-linkkejä" + } + } + }, + "AUTH": { + "INVITED_YOU": "on kutsunut sinut projektiin", + "NOT_REGISTERED_YET": "Etkö ole vielä rekisteröitynyt?", + "REGISTER": "Rekisteröidy", + "CREATE_ACCOUNT": "luo ilmainen tunnuksesi täällä" + }, + "ATTACHMENT": { + "SECTION_NAME": "liitteet", + "TITLE": "{{ fileName }} ladattu {{ date }}\n", + "DESCRIPTION": "Kirjoita lyhyt kuvaus", + "DEPRECATED": "(deprecated)", + "DEPRECATED_FILE": "Vanhentunut?", + "ADD": "Lisää liite. <%- maxFileSizeMsg %>", + "MAX_FILE_SIZE": "[Maks. koko: {{maxFileSize}}]", + "SHOW_DEPRECATED": "+ näytä vanhentuneet liitteet", + "HIDE_DEPRECATED": "- piilota vanhentuneet liitteet", + "COUNT_DEPRECATED": "({{ counter }} deprecated)", + "MAX_UPLOAD_SIZE": "Maksimi tiedoston koko {{maxFileSize}}", + "DATE": "DD MMM YYYY - hh:mm", + "ERROR_UPLOAD_ATTACHMENT": "Emme onnistuneet lataamaan tiedostoa '{{fileName}}'. {{errorMessage}}", + "TITLE_LIGHTBOX_DELETE_ATTACHMENT": "Poista liite...", + "MSG_LIGHTBOX_DELETE_ATTACHMENT": "liite '{{fileName}}'", + "ERROR_DELETE_ATTACHMENT": "Emme pystyneet poistamaan: {{errorMessage}}", + "FIELDS": { + "IS_DEPRECATED": "on vanhentunut" + } + }, + "PAGINATION": { + "PREVIOUS": "Edellinen", + "NEXT": "Seuraava" + }, + "ADMIN": { + "COMMON": { + "TITLE_ACTION_EDIT_VALUE": "Muokkaa arvoa", + "TITLE_ACTION_DELETE_VALUE": "Poista arvo" + }, + "HELP": "Tarvitsetko apua? Katso tukisivuilta.", + "PROJECT_DEFAULT_VALUES": { + "TITLE": "Oletusarvot", + "SUBTITLE": "Aseta oletukset kaikille syötteille." + }, + "MEMBERSHIPS": { + "TITLE": "Hallinnoi jäseniä", + "ADD_BUTTON": "+ Uusi jäsen", + "ADD_BUTTON_TITLE": "Lisää jäsen" + }, + "PROJECT_EXPORT": { + "TITLE": "Vie", + "SUBTITLE": "Vie projekti varmuuskopioksi tai luo uusi tämän pohjalta.", + "EXPORT_BUTTON": "Vie", + "EXPORT_BUTTON_TITLE": "Vie projekti", + "LOADING_TITLE": "Varmistustiedostoa muodostetaan", + "DUMP_READY": "Tiedostosi on valmis", + "LOADING_MESSAGE": "Älä sulje tätä sivua.", + "ASYNC_MESSAGE": "Lähetämme sähköpostia, kun on valmista.", + "SYNC_MESSAGE": "Jos lataus ei ala automaattisesti klikkaa tästä.", + "ERROR": "Oompa Loompas eivät onnistuneet tekemään tiedostoasi. Yritä uudelleen.", + "ERROR_BUSY": "Valitettavasti Oompa Loompas ovat kiireisiä juuri. Yritä kohta uudestaan.", + "ERROR_MESSAGE": "Oompa Loompas eivät onnistuneet luomaan tiedostoasi: {{message}}" + }, + "MODULES": { + "TITLE": "Modulit", + "ENABLE": "Aktivoi", + "DISABLE": "Passivoi", + "BACKLOG": "Odottavat", + "BACKLOG_DESCRIPTION": "Hallinnoi käyttäjätarinoita: järjestele ja priorisoi työtä.", + "KANBAN": "Kanban", + "KANBAN_DESCRIPTION": "Järjestä projektisi tehokkaasti tällä taululla.", + "ISSUES": "Pyynnöt", + "ISSUES_DESCRIPTION": "Seuraa projektisi virheitä, kysymyksiä ja parannusehdotuksia. Älä jätä mitään huomiotta!", + "WIKI": "Wiki", + "WIKI_DESCRIPTION": "Lisää, muokkaa tai poista sisältöä yhteistyössä muiden kanssa. Tämä on oikea paikka projektin dokumentaatiolle.", + "MEETUP": "Tapaa", + "MEETUP_DESCRIPTION": "Valitse videoconferenssisysteemi. Jopa kehittäjät tarvitsevat katsekontaktia.", + "SELECT_VIDEOCONFERENCE": "Valitse videoconferenssi-järjestelmä", + "SALT_CHAT_ROOM": "Voit halutessasi lisätä suolaan chat-huoneen nimeen" + }, + "PROJECT_PROFILE": { + "PAGE_TITLE": "Projektin profiili - {{sectionName}} - {{projectName}}", + "PROJECT_DETAILS": "Projektin tiedot", + "PROJECT_NAME": "Projektin nimi", + "PROJECT_SLUG": "Projektin hukka-aika", + "NUMBER_SPRINTS": "Kierrosten määrä", + "NUMBER_US_POINTS": "Kt pisteitä", + "TAGS": "Avainsanat", + "DESCRIPTION": "Kuvaus", + "PUBLIC_PROJECT": "Julkinen projekti", + "PRIVATE_PROJECT": "Yksityinen projekti", + "DELETE": "Poista tämä projekti" + }, + "REPORTS": { + "TITLE": "Raportit", + "SUBTITLE": "Vie projektisi CSV-tiedostoon", + "DESCRIPTION": "Lataa CSV-tiedosto tai luo URL ja avaa haluamassasi ohjelmassa. Voit visualisoida ja analysoida tietoa helposti.", + "HELP": "Kuinka tätä käytetään omassa taulukossani?", + "REGENERATE_TITLE": "Vaihda URL", + "REGENERATE_SUBTITLE": "Jos muutata CSV-datan URLia, edellien lakkaa toimimasta. Oletko varma?" + }, + "CSV": { + "SECTION_TITLE_US": "user stories reports", + "SECTION_TITLE_TASK": "tasks reports", + "SECTION_TITLE_ISSUE": "issues reports", + "DOWNLOAD": "Lataa CSV-tiedosto", + "URL_FIELD_PLACEHOLDER": "Tee uusi CSV-url", + "TITLE_REGENERATE_URL": "Tee uusi CSV-url", + "ACTION_GENERATE_URL": "Luo URL", + "ACTION_REGENERATE": "Tee uusi" + }, + "CUSTOM_FIELDS": { + "TITLE": "Omat kentät", + "SUBTITLE": "Määritele omia kenttiä käyttäjätarinoihin, tehtäviin ja pyytöihin", + "US_DESCRIPTION": "Käyttäjätarinoiden omat kentät", + "US_ADD": "Lisää käyttäjätarinoihin oma kenttä", + "TASK_DESCRIPTION": "Tehtävien omat kentät", + "TASK_ADD": "Lisää omia kenttiä tehtäviin", + "ISSUE_DESCRIPTION": "Pyyntöjen omat kentät", + "ISSUE_ADD": "Lisää oma kenttä pyynnöille" + }, + "PROJECT_VALUES": { + "APP_TITLE": "Projektin arvot - {{sectionName}} - {{projectName}}", + "REPLACEMENT": "Kaikkii riveihin joissa on tämä arvo muutetaan ", + "ERROR_DELETE_ALL": "Et voi poistaa kaikkia arvoja." + }, + "PROJECT_VALUES_POINTS": { + "TITLE": "Kt pisteet", + "SUBTITLE": "Määrittele pisteet joihin käyttäjätarinat voidaan arvioida", + "ACTION_ADD": "Lisää uusi piste" + }, + "PROJECT_VALUES_PRIORITIES": { + "TITLE": "Pyyntöjen tärkeydet", + "SUBTITLE": "Määrittele tärkeydet pyynnöille", + "ACTION_ADD": "Add new priority" + }, + "PROJECT_VALUES_SEVERITIES": { + "TITLE": "Pyyntöjen vakavuudet", + "SUBTITLE": "Määrittele pyyntöjen vakavuudet", + "ACTION_ADD": "Add new severity" + }, + "PROJECT_VALUES_STATUS": { + "TITLE": "Tila", + "SUBTITLE": "Määrittele tilat joiden kautta käyttäjätarinasi, tehtäväsi ja pyyntösi kulkevat", + "US_TITLE": "Kt tilat", + "TASK_TITLE": "Tehtävien tilat", + "ISSUE_TITLE": "Pyyntöjen tilat" + }, + "PROJECT_VALUES_TYPES": { + "TITLE": "Tyypit", + "SUBTITLE": "Määrittele pyyntöjen tyypit", + "ISSUE_TITLE": "Pyyntöjen tyypit", + "ACTION_ADD": "Add new type" + }, + "ROLES": { + "SECTION_NAME": "Roolit - {{projectName}}", + "WARNING_NO_ROLE": "Ole varovainen, yksikään rooli projektissasi ei voi arvioida käyttäjätarinoidesi kokoa", + "HELP_ROLE_ENABLED": "Tämän roolin omaavat jäsenet voivat arvioida käyttäjätarinoiden kokoja", + "COUNT_MEMBERS": "{{ role.members_count }} jäsentä joilla tämä rooli", + "TITLE_DELETE_ROLE": "Poista rooli", + "REPLACEMENT_ROLE": "Kaikki käyttäjä joilla on tämä rooli siirretään", + "WARNING_DELETE_ROLE": "Ole varovainen, rooli-arvioinnit poistetaan", + "ERROR_DELETE_ALL": "Voit poistaa kaikki arvot", + "EXTERNAL_USER": "Ulkoinen käyttäjä" + }, + "THIRD_PARTIES": { + "SECRET_KEY": "Salainen avain", + "PAYLOAD_URL": "Yhteyden URL-osoite", + "VALID_IPS": "Vaadittavat lähdeIPt (pilkuilla eroteltuna)" + }, + "BITBUCKET": { + "SECTION_NAME": "Bitbucket", + "APP_TITLE": "Bitbucket - {{projectName}}", + "INFO_VERIFYING_IP": "Bitbucket pyynnöt eivät ole allekirjoitettuja joten tarkista IP. Jos IP on tyhjä, ei sitä tarkisteta." + }, + "GITLAB": { + "SECTION_NAME": "Gitlab", + "APP_TITLE": "Gitlab - {{projectName}}", + "INFO_VERIFYING_IP": "Gitlab pyynnöt eivät ole allekirjoitettuja joten tarkista IP. Jos IP on tyhjä, ei sitä tarkisteta." + }, + "GITHUB": { + "SECTION_NAME": "Github", + "APP_TITLE": "Github - {{projectName}}" + }, + "WEBHOOKS": { + "APP_TITLE": "Webhooks - {{projectName}}", + "SECTION_NAME": "Webhookit", + "SUBTITLE": "Webhookit ilmoittvat ulkoisille palveluille Taigan kommenteista, käyttäjätarinoista ...", + "ADD_NEW": "Lisää webhook", + "TYPE_NAME": "Anna palvelun nimi", + "TYPE_PAYLOAD_URL": "Anna palvelun yhteysosoite (URL)", + "TYPE_SERVICE_SECRET": "Anna palvelun yksityinen avain", + "SAVE": "Tallenna Webhook", + "CANCEL": "Peruuta Webhook", + "SHOW_HISTORY": "(Näytä historia)", + "TEST": "Testaa webhook", + "EDIT": "Muokkaa webhookkia", + "DELETE": "Poista Webhook", + "REQUEST": "Pyyntö", + "RESEND_REQUEST": "Lähetä pyyntö uudestaan", + "HEADERS": "Ylätunnisteet", + "PAYLOAD": "Hyötykuorma", + "RESPONSE": "Vastaus", + "DATE": "DD MMM YYYY - hh:mm:ss", + "ACTION_HIDE_HISTORY": "(Piilota historia)", + "ACTION_HIDE_HISTORY_TITLE": "Piilota historian yksityiskohdat", + "ACTION_SHOW_HISTORY": "(Näytä historia)", + "ACTION_SHOW_HISTORY_TITLE": "Näytä historian yksityiskohdat", + "WEBHOOK_NAME": "Webhook '{{name}}'" + }, + "CUSTOM_ATTRIBUTES": { + "ADD": "Anna oma kenttä", + "EDIT": "Muokkaa omaa kenttää", + "DELETE": "Poista oma kenttä", + "SAVE_TITLE": "Tallenna oma kenttä", + "CANCEL_TITLE": "Peru luonti", + "SET_FIELD_NAME": "Anna oman kentän nimi", + "SET_FIELD_DESCRIPTION": "Anna oman kenttäsi kuvaus", + "ACTION_UPDATE": "Päivitä oma kenttä", + "ACTION_CANCEL_EDITION": "Peru versio" + }, + "MEMBERSHIP": { + "COLUMN_MEMBER": "Jäsen", + "COLUMN_ADMIN": "Hallinnoi", + "COLUMN_ROLE": "Rooli", + "COLUMN_STATUS": "Tila", + "STATUS_ACTIVE": "Aktiivinen", + "STATUS_PENDING": "Odottaa", + "DELETE_MEMBER": "Poista jäsen", + "SUCCESS_SEND_INVITATION": "Olemme lähettäneet kutsun uudelleen osoitteeseen '{{email}}'.", + "ERROR_SEND_INVITATION": "Olemme lähettäneet kutsun.", + "SUCCESS_DELETE": "Olemme poistaneet viestin {{message}}.", + "ERROR_DELETE": "Emme pystyneet poistamaan viestiä {{message}}.", + "DEFAULT_DELETE_MESSAGE": "kutsu sähköpostiin {{email}}" + }, + "DEFAULT_VALUES": { + "LABEL_POINTS": "Oletukset pisteiden valintaan", + "LABEL_US": "Oletusarvo Kt:n tilan valintaan", + "LABEL_TASK_STATUS": "Oletusarvo tehtävän tilan valintaan", + "LABEL_PRIORITY": "Oletus arvo tärkeyden valiintaan", + "LABEL_SEVERITY": "Oletusarvo vakavuuden valintaan", + "LABEL_ISSUE_TYPE": "Oletusarvo pyynnön tyypin valintaan", + "LABEL_ISSUE_STATUS": "Oletusarvo pyyntöjen statuksen valintaan" + }, + "STATUS": { + "PLACEHOLDER_WRITE_STATUS_NAME": "Anna uuden tilan nimi" + }, + "TYPES": { + "PLACEHOLDER_WRITE_NAME": "Anna uuden elementin nimi" + }, + "US_STATUS": { + "ACTION_ADD_STATUS": "Lisää uusi tila", + "IS_ARCHIVED_COLUMN": "Onko arkistoitu?", + "WIP_LIMIT_COLUMN": "WIP raja", + "PLACEHOLDER_WRITE_NAME": "Anna uuden tilan nimi" + }, + "MENU": { + "TITLE": "Hallinnoi", + "PROJECT": "Projekti", + "ATTRIBUTES": "Attribuutit", + "MEMBERS": "Jäsenet", + "PERMISSIONS": "Oikeudet", + "INTEGRATIONS": "Intergraatiot", + "PLUGINS": "Pluginit" + }, + "SUBMENU_PROJECT_ATTRIBUTES": { + "TITLE": "Attributes" + }, + "SUBMENU_PROJECT_VALUES": { + "STATUS": "Tila", + "POINTS": "Pisteet", + "PRIORITIES": "Tärkeydet", + "SEVERITIES": "Vakavuudet", + "TYPES": "Tyypit", + "CUSTOM_FIELDS": "Omat kentät" + }, + "SUBMENU_PROJECT_PROFILE": { + "TITLE": "Projektin profiili" + }, + "SUBMENU_ROLES": { + "TITLE": "Roolit", + "ACTION_NEW_ROLE": "+ Uusi rooli", + "TITLE_ACTION_NEW_ROLE": "Lisää uusi rooli" + }, + "SUBMENU_THIDPARTIES": { + "TITLE": "Palvelut" + } + }, + "PROJECT": { + "WELCOME": "Tervetuloa", + "SECTION_PROJECTS": "Projektit", + "STATS": { + "PROJECT": "projekti
pisteet", + "DEFINED": "määritely
pistettä", + "ASSIGNED": "kohdistettu
pistettä", + "CLOSED": "suljettu
pistettä" + }, + "SECTION": { + "SEARCH": "Hae", + "BACKLOG": "Odottavat", + "KANBAN": "Kanban", + "ISSUES": "Pyynnöt", + "WIKI": "Wiki", + "TEAM": "Tiimi", + "MEETUP": "Tapaa", + "ADMIN": "Hallinnoi" + }, + "NAVIGATION": { + "SECTION_TITLE": "Your projects", + "PLACEHOLDER_SEARCH": "Hae täältä...", + "ACTION_CREATE_PROJECT": "Luo projekti", + "TITLE_ACTION_IMPORT": "Luo projekti tiedostosta", + "TITLE_PRVIOUS_PROJECT": "Näytä aikaisemmat projektit", + "TITLE_NEXT_PROJECT": "Näytä seuraavat projektit" + }, + "IMPORT": { + "TITLE": "Luetaan sisään projektia", + "UPLOADING_FILE": "Uploading dump file", + "DESCRIPTION": "Tämä voi kestää hetken, pidä ikkuna auki.", + "ASYNC_IN_PROGRESS_TITLE": " Oompa Loompas tuovat projektia", + "ASYNC_IN_PROGRESS_MESSAGE": "Tämä voi kestää muutaman minuutin
Lähetämme sähköpostin on valmista", + "UPLOAD_IN_PROGRESS_MESSAGE": "Uploaded {{uploadedSize}} of {{totalSize}}", + "ERROR": "Oompa Loompas eivät onnistuneet tuomaan tiedostoasi. Yritä uudestaan.", + "ERROR_TOO_MANY_REQUEST": "Oompa Loompas ovat kiireisiä juuri nyt. Yritä hetken päästä uudelleen.", + "ERROR_MESSAGE": "Oompa Loompas eivät pysty lukemaan tiedostoasi: {{error_message}}", + "ERROR_MAX_SIZE_EXCEEDED": "'{{fileName}}' ({{fileSize}}) is too heavy for our Oompa Loompas, try it with a smaller than ({{maxFileSize}})", + "SYNC_SUCCESS": "Projektisi on tuotu sisään onnistuneesti" + } + }, + "LIGHTBOX": { + "DELETE_ACCOUNT": { + "SECTION_NAME": "Poista Taiga-tunnus", + "CONFIRM": "Haluatko varmasti poistaa Taiga-tunnuksesi?", + "SUBTITLE": "Tulemme kaipaamaan sinua! :-(", + "NEWSLETTER_LABEL_TEXT": "I don't wanna receive your newsletter anymore" + }, + "DELETE_PROJECT": { + "TITLE": "Poista projekti", + "QUESTION": "Haluatko varmasti poistaa tämän projektin?", + "SUBTITLE": "Projektin kaikki tiedot poistetaan :-(", + "CONFIRM": "Kyllä, tiedän mitä teen" + }, + "ASSIGNED_TO": { + "SELECT": "Valitse tekijä", + "SEARCH": "Hae käyttäjiä" + }, + "ADD_MEMBER": { + "TITLE": "Uusi jäsen", + "HELP_TEXT": "Taigan käyttäjät lisätään automaattisesti, muille lähetetään kutsu." + }, + "CREATE_ISSUE": { + "TITLE": "Lisää pyyntö" + }, + "FEEDBACK": { + "TITLE": "Kerro jotain...", + "COMMENT": "...virhe, ehdotuksia, tai huonoin kokemuksesi Taigan kanssa", + "ACTION_SEND": "Lähetä palautetta" + }, + "SEARCH": { + "TITLE": "Hae", + "PLACEHOLDER_SEARCH": "Mitä etsit?" + }, + "ADD_EDIT_SPRINT": { + "TITLE": "Uusi kierros", + "PLACEHOLDER_SPRINT_NAME": "kierroksen nimi", + "PLACEHOLDER_SPRINT_START": "Arvioitu alku", + "PLACEHOLDER_SPRINT_END": "Arvioitu loppu", + "ACTION_DELETE_SPRINT": "Haluatko poistaa tämän kierroksen?", + "TITLE_ACTION_DELETE_SPRINT": "poista kierros", + "LAST_SPRINT_NAME": "viimeinen kierros on {{lastSprint}} ;-) " + }, + "CREATE_EDIT_TASK": { + "TITLE": "Uusi tehtävä", + "PLACEHOLDER_SUBJECT": "Tehtävän aihe", + "PLACEHOLDER_STATUS": "Tehtävän tila", + "OPTION_UNASSIGNED": "Ilman tekijää", + "PLACEHOLDER_SHORT_DESCRIPTION": "Kirjoita lyhyt kuvaus", + "ACTION_EDIT": "Muokkaa tehtävää" + }, + "CREATE_EDIT_US": { + "TITLE": "Uusi Kt", + "PLACEHOLDER_DESCRIPTION": "Lisää kuvaus jotta muut ymmärtäisivät käyttäjätarinasi paremmin", + "NEW_US": "Uusi käyttäjätarina", + "EDIT_US": "Muokkaa käyttäjätarinaa" + }, + "DELETE_SPRINT": { + "TITLE": "Poista kierros" + }, + "CREATE_MEMBER": { + "PLACEHOLDER_INVITATION_TEXT": "(Vapaaehtoinen) Lisää oma kuvaus kutsuusi uusille jäsenille ;-)", + "PLACEHOLDER_TYPE_EMAIL": "Anna sähköposti" + } + }, + "US": { + "SECTION_NAME": "User story details", + "LINK_TASKBOARD": "Tehtävätaulu", + "TITLE_LINK_TASKBOARD": "Siirry tehtävätauluun", + "TOTAL_POINTS": "yhteensä", + "ADD": "+ Lisää uusi käyttäjätarina", + "ADD_BULK": "Lisää monta käyttäjätarinaa", + "PROMOTED": "Tämä Kt on liitetty pyyntöön:", + "TITLE_LINK_GO_TO_ISSUE": "Siirry pyyntöön", + "EXTERNAL_REFERENCE": "Tämä Kt oon luotu täältä: ", + "GO_TO_EXTERNAL_REFERENCE": "Palaa alkuun", + "BLOCKED": "Tämä käyttäjätarina on suljettu", + "PREVIOUS": "edellinen käyttäjätarina", + "NEXT": "seuraava käyttäjätarina", + "TITLE_DELETE_ACTION": "Poista käyttäjätarina", + "LIGHTBOX_TITLE_BLOKING_US": "Meitä estää", + "TASK_COMPLETED": "{{totalClosedTasks}}/{{totalTasks}} tehtyä tehtävää", + "ASSIGN": "Käyttäjätarinan tekijä", + "NOT_ESTIMATED": "Ei arvioitu", + "TOTAL_US_POINTS": "Kt pisteet yhteensä", + "FIELDS": { + "TEAM_REQUIREMENT": "Tiimin vaatimus", + "CLIENT_REQUIREMENT": "Asiakkaan vaatimus", + "FINISH_DATE": "Loppupvm" + } + }, + "COMMENTS": { + "DELETED_INFO": "{{user}} poisti kommentin {{date}}", + "TITLE": "Kommentit", + "COMMENT": "Kommentti", + "TYPE_NEW_COMMENT": "Lisää uusi kommentti tässä", + "SHOW_DELETED": "Näytä poistettu kommentti", + "HIDE_DELETED": "Piilota poistettu kommentti", + "RESTORE": "Palauta kommentti" + }, + "ACTIVITY": { + "SHOW_ACTIVITY": "Näytä tapahtumat", + "DATETIME": "DD MMM YYYY HH:mm", + "SHOW_MORE": "+ Näytä edelliset rivit ({{showMore}} lisää)", + "TITLE": "Aktiivisuus", + "REMOVED": "poistettu", + "ADDED": "lisätty", + "US_POINTS": "Kt pisteet ({{name}})", + "NEW_ATTACHMENT": "uusi liite", + "DELETED_ATTACHMENT": "poistettu liite", + "UPDATED_ATTACHMENT": "päivitetty liite {{filename}}", + "DELETED_CUSTOM_ATTRIBUTE": "poista oma attribuutti", + "SIZE_CHANGE": "Tehty {size, plural, one{muutos} other{# muutosta}}", + "VALUES": { + "YES": "Kyllä", + "NO": "ei", + "EMPTY": "tyhjä", + "UNASSIGNED": "ilman tekijää" + }, + "FIELDS": { + "SUBJECT": "aihe", + "NAME": "nimi", + "DESCRIPTION": "kuvaus", + "CONTENT": "sisältö", + "STATUS": "tila", + "IS_CLOSED": "on suljettu", + "FINISH_DATE": "loppupvm", + "TYPE": "tyyppi", + "PRIORITY": "tärkeys", + "SEVERITY": "vakavuus", + "ASSIGNED_TO": "tekijä on", + "WATCHERS": "vahdit", + "MILESTONE": "kierros", + "USER_STORY": "käyttäjätarina", + "PROJECT": "projekti", + "IS_BLOCKED": "on estetty", + "BLOCKED_NOTE": "estetty muistiinpano", + "POINTS": "pisteet", + "CLIENT_REQUIREMENT": "asiakkaan vaatimus", + "TEAM_REQUIREMENT": "tiimin vaatimus", + "IS_IOCAINE": "on hidaste", + "TAGS": "avainsanat", + "ATTACHMENTS": "liitteet", + "IS_DEPRECATED": "on vanhentunut", + "ORDER": "järjestys", + "BACKLOG_ORDER": "odottavien järjestys", + "SPRINT_ORDER": "kierroksen järjestys", + "KANBAN_ORDER": "kanban järjestys", + "TASKBOARD_ORDER": "Tehtävätaulun järjestys", + "US_ORDER": "kt järjestys" + } + }, + "BACKLOG": { + "SECTION_NAME": "Odottavat", + "MOVE_US_TO_CURRENT_SPRINT": "Siirrä nykyiseen kierrokseen", + "SHOW_FILTERS": "Näytä suodattimet", + "SHOW_TAGS": "Näytä avainsanat", + "EMPTY": "Odottavien lista on tyhjä!", + "CREATE_NEW_US": "Luo uusi Kt", + "CREATE_NEW_US_EMPTY_HELP": "Voit haluta lisätä uuden käyttäjätarinan", + "EXCESS_OF_POINTS": "Pisteiden ylimäärä", + "PENDING_POINTS": "Odottavat pisteet", + "CLOSED_POINTS": "suljettu", + "COMPACT_SPRINT": "Kompakti kierros", + "GO_TO_TASKBOARD": "Siirry tehtävätauluun {{::name}}", + "EDIT_SPRINT": "Muokkaa kierrosta", + "TOTAL_POINTS": "yhteensä", + "STATUS_NAME": "Tilan nimi", + "SORTABLE_FILTER_ERROR": "Et voi viedä odottaviin, kun suodattimet ovat auki", + "DOOMLINE": "Projektin laajuus [Doomline]", + "CHART": { + "XAXIS_LABEL": "Kierrokset", + "YAXIS_LABEL": "Pisteet", + "OPTIMAL": "Optimaaliset odottavat pisteet kierokselle {{xval}} ovat {{yval}}", + "REAL": "Todelliset odottavat pisteet kierrokselle {{xval}} ovat {{yval}}", + "INCREMENT_TEAM": "Lisätyt tiimin vaatimat pisteet kierrokselle {{xval}} ovat {{yval}}", + "INCREMENT_CLIENT": "Lisätyt asiakkaan vaatimat pisteet kierrokselle {{xval}} ovat {{yval}}" + }, + "TAGS": { + "TOGGLE": "Toggle tags visibility", + "SHOW": "Näytä avainsanat", + "HIDE": "Piilota avainsanat" + }, + "TABLE": { + "COLUMN_US": "Käyttäjätarinat", + "TITLE_COLUMN_POINTS": "Valitse näkymä roolille" + }, + "SPRINT_SUMMARY": { + "TOTAL_POINTS": "yhteensä
pistettä", + "COMPLETED_POINTS": "valmiina
pistettä", + "OPEN_TASKS": "avaa
tehtävät", + "CLOSED_TASKS": "suljettu
tehtävää", + "IOCAINE_DOSES": "hidastetia
annosta", + "SHOW_STATISTICS_TITLE": "Näytä tilastot" + }, + "SUMMARY": { + "PROJECT_POINTS": "projekti
pistettä", + "DEFINED_POINTS": "määritellyt
pisteet", + "CLOSED_POINTS": "suljettu
pistettä", + "POINTS_PER_SPRINT": "pisettä/
kierros" + }, + "FILTERS": { + "TOGGLE": "Toggle filters visibility", + "TITLE": "Suodattimet", + "REMOVE": "Poista suodattimet", + "HIDE": "Hide Filters", + "SHOW": "Näytä suodattimet", + "FILTER_CATEGORY_STATUS": "Tila", + "FILTER_CATEGORY_TAGS": "Avainsanat" + }, + "SPRINTS": { + "TITLE": "KIERROKSET", + "DATE": "DD MMM YYYY", + "LINK_TASKBOARD": "Kierroksien tehtävätaulu", + "TITLE_LINK_TASKBOARD": "Siirry tehtävätauluun {{name}}", + "NUMBER_SPRINTS": "
kierrokset", + "TITLE_ACTION_NEW_SPRINT": "+ Uusi kierros", + "ACTION_NEW_SPRINT": "+ Uusi kierros", + "ACTION_SHOW_CLOSED_SPRINTS": "Näytä suljetut kierrokset", + "ACTION_HIDE_CLOSED_SPRINTS": "Piilota suljetut kierrokset" + } + }, + "ERROR": { + "TEXT1": "Jotain tapahtui ja Oompa Loompas työskentelevät sen parissa.", + "TEXT2": "Lataa sivu uudestaan", + "NOT_FOUND": "Ei löytynyt", + "NOT_FOUND_TEXT": "Virhe 404. Sivua ei löydy. Palaa takaisin TAIGA etusivulle ja katso löydätkö haluamasi sieltä.", + "PERMISSION_DENIED": "Ei oikeutta", + "PERMISSION_DENIED_CODE": "Virhe 403.", + "VERSION_ERROR": "Joku Taigassa on päivittänyt tätä ennen sinua. Muutoksiasi ei voida tallentaa. Lataa sivu uudestaan ja korjaa tilanne." + }, + "TASKBOARD": { + "SECTION_NAME": "Tehtävätaulu", + "TITLE_ACTION_ADD": "Lisää uusi tehtävä", + "TITLE_ACTION_ADD_BULK": "Lisää monta tehtävää", + "TITLE_ACTION_ASSIGN": "Valitse tekijä", + "TITLE_ACTION_EDIT": "Muokkaa tehtävää", + "TABLE": { + "COLUMN": "Käyttäjätarina", + "TITLE_ACTION_FOLD": "Kavenna sarake", + "TITLE_ACTION_UNFOLD": "Laajenna sarake", + "TITLE_ACTION_FOLD_ROW": "Kavenna rivi", + "TITLE_ACTION_UNFOLD_ROW": "Laajenna rivi", + "FIELD_POINTS": "pisteet", + "ROW_UNASSIGED_TASKS_TITLE": "Poista tekijä" + }, + "CHARTS": { + "XAXIS_LABEL": "Päivät", + "YAXIS_LABEL": "Pisteet", + "OPTIMAL": "Optimaaliset odottavat pisteet {{formattedDate}} ovat {{roundedValue}}", + "REAL": "Todelliset odottavat pisteet {{formattedDate}} ovat {{roundedValue}}", + "DATE": "DD MMMM YYYY" + } + }, + "TASK": { + "SECTION_NAME": "Task details", + "LINK_TASKBOARD": "Tehtävätaulu", + "TITLE_LINK_TASKBOARD": "Siirry tehtävätauluun", + "PLACEHOLDER_SUBJECT": "Anna tehtävän aihe", + "TITLE_SELECT_STATUS": "Tilan nimi", + "OWNER_US": "Tehtävä kuuluu käyttäjälle ", + "TITLE_LINK_GO_OWNER": "Siirry käyttäjätarinaan", + "ORIGIN_US": "Tämä tehtävä on luotu", + "TITLE_LINK_GO_ORIGIN": "Siirry käyttäjätarinaan", + "BLOCKED": "Tämä tehtävä on suljettu", + "PREVIOUS": "edellinen tehtävä", + "NEXT": "seuraava tehtävä", + "TITLE_DELETE_ACTION": "Poista tehtävä", + "LIGHTBOX_TITLE_BLOKING_TASK": "Estävä tehtävä", + "FIELDS": { + "MILESTONE": "Kierros", + "USER_STORY": "Käyttäjätarina", + "IS_IOCAINE": "On hidaste" + }, + "ACTION_IOCAINE": "Hidaste", + "TITLE_ACTION_IOCAINE": "Rasittaako tehtävä? Kerro muillekin klikkaamalla hidasteen kuvaketta. Sattaa myös helpottaa jatkossa jos kerrot asiasta vähitellen." + }, + "NOTIFICATION": { + "OK": "Kaikki on kunnossa", + "WARNING": "Oops, jotain tapahtui...", + "WARNING_TEXT": "Oompa Loompas eivät pystyneet tallentamaan muutoksiasi!", + "SAVED": "Oompa Loompas tallensivat kaikki muutoksesi!", + "CLOSE": "Sulje ilmoitus", + "MAIL": "Ilmoitukset sähköpostilla", + "ASK_DELETE": "Oletko varma että haluat poistaa tämän?" + }, + "CANCEL_ACCOUNT": { + "TITLE": "Peru tunnuksesi", + "SUBTITLE": "Olemme pahoillamme että jätät Taigan. Toivottavasti nautit oleskelusta :)", + "PLACEHOLDER_INPUT_TOKEN": "peru tunnus tokeni", + "ACTION_LEAVING": "Kyllä, olen lähdössä!", + "SUCCESS": " Oompa Loompas poistivat tunnuksesi" + }, + "CHANGE_EMAIL_FORM": { + "TITLE": "Muuta sähköpostisi", + "SUBTITLE": "Vielä yksi klikki ja sähköpostisi on päivitetty!", + "PLACEHOLDER_INPUT_TOKEN": "muuta sähköposti-tokenia", + "ACTION_CHANGE_EMAIL": "Muuta sähköpostisi", + "SUCCESS": "Oompa Loompas päivittivät sähköpostisi" + }, + "CHANGE_PASSWORD_RECOVERY_FORM": { + "TITLE": "Luo uusi pääsy Taigaan", + "SUBTITLE": "Rautapitoinen ruoka on hyväksi aivoille :P", + "PLACEHOLDER_RECOVER_PASSWORD_TOKEN": "Palauta sähköposti-tokeni", + "LINK_NEED_TOKEN": "Tarvitsetko yhden?", + "TITLE_LINK_NEED_TOKEN": "Tarvitsitko tokenia palauttaakseni salasanan koska unohdit sen?", + "PLACEHOLDER_NEW_PASSWORD": "Uusi salasana", + "PLACEHOLDER_RE_TYPE_NEW_PASSWORD": "Anna salasana uudelleen", + "ACTION_RESET_PASSWORD": "Uusi salsanasi", + "SUCCESS": "Oompa Loompas tallensivat uuden salasanasi.
Yritä kirjautua sisään sillä." + }, + "FORGOT_PASSWORD_FORM": { + "TITLE": "Oops, unohditko salasanasi?", + "SUBTITLE": "Anna käyttäjänimesi tai sähköpostisi saadaksesi uuden", + "PLACEHOLDER_FIELD": "Käyttäjänimi tai sähköposti", + "ACTION_RESET_PASSWORD": "Uusi salsanasi", + "LINK_CANCEL": "Vie minut takaisin, muistan sen.", + "SUCCESS": "Check your inbox!
We have sent you an email with the instructions to set a new password", + "ERROR": "Oompa Loompas sanovat että käyttäjänimesi tai sähköpostisi tai salasanasi on väärä." + }, + "LOGIN_COMMON": { + "HEADER": "Minulla on jo Taiga tunnus", + "PLACEHOLDER_AUTH_NAME": "Käyttäjänimi tai sähköposti (kirjainkoko merkitsevä)", + "LINK_FORGOT_PASSWORD": "Unohditko?", + "TITLE_LINK_FORGOT_PASSWORD": "Unohditko salasanasi?", + "ACTION_ENTER": "Sisään", + "ACTION_SIGN_IN": "Kirjaudu sisään", + "PLACEHOLDER_AUTH_PASSWORD": "Salasana (kirjainkoko merkitsevä)" + }, + "LOGIN_FORM": { + "ERROR_AUTH_INCORRECT": "Oompa Loompas sanovat että käyttäjänimesi tai sähköpostisi tai salasanasi on väärä.", + "ERROR_GENERIC": "Oompa Loompas havaitsivat virheen", + "SUCCESS": "Oompa Loompas ovat onnellisia, tervetuloa Taigaan." + }, + "INVITATION_LOGIN_FORM": { + "NOT_FOUND": "Ooops, meillä on ongelma
Our Oompa Loompas eivät löydä kutsuasi.", + "SUCCESS": "Olet onnistuneesti liittynyt projektiin {{project_name}}. Tervetuloa!", + "ERROR": "Oompa Loompas sanovat että käyttäjänimesi tai sähköpostisi tai salasanasi on väärä." + }, + "REGISTER_FORM": { + "TITLE": "Register a new Taiga account (free)", + "PLACEHOLDER_NAME": "Anna käyttäjänimi (kirjainkoko on merkitsevä)", + "PLACEHOLDER_FULL_NAME": "Anna koko nimesi", + "PLACEHOLDER_EMAIL": "Sähköpostisi", + "PLACEHOLDER_PASSWORD": "Anna salasana (kirjainkoko merkitsevä)", + "ACTION_SIGN_UP": "Kirjaudu sisään", + "TITLE_LINK_LOGIN": "Kirjaudu sisään", + "LINK_LOGIN": "Oletko jo rekisteröitynyt? Kirjaudu sisään" + }, + "ISSUES": { + "LIST_SECTION_NAME": "Pyynnöt", + "SECTION_NAME": "Issue details", + "ACTION_NEW_ISSUE": "+ UUSI PYYNTÖ", + "ACTION_PROMOTE_TO_US": "Liitä käyttäjätarinaan", + "PLACEHOLDER_FILTER_NAME": "Anna suodattimen nimi ja paina enter", + "PROMOTED": "Tämä pyyntö on liitetty Kthen:", + "EXTERNAL_REFERENCE": "Tämä pyyntö on luotu täältä:", + "GO_TO_EXTERNAL_REFERENCE": "Palaa alkuun", + "BLOCKED": "Tämä pyyntö on estetty", + "TITLE_PREVIOUS_ISSUE": "edellinen pyyntö", + "TITLE_NEXT_ISSUE": "seuraava pyyntö", + "ACTION_DELETE": "Poista pyyntö", + "LIGHTBOX_TITLE_BLOKING_ISSUE": "Estävä pyyntö", + "CONFIRM_PROMOTE": { + "TITLE": "Liitä tämä pyyntö uuteen käyttäjätarinaan", + "MESSAGE": "Haluatko varmasti lisätä uuden käyttäjätarinan tästä pyynnöstä?" + }, + "FILTERS": { + "TITLE": "Suodattimet", + "INPUT_SEARCH_PLACEHOLDER": "Otsikko tai viittaus", + "TITLE_ACTION_SEARCH": "Hae", + "ACTION_SAVE_CUSTOM_FILTER": "tallenna omaksi suodattimeksi", + "BREADCRUMB": "Suodattimet", + "TITLE_BREADCRUMB": "Suodattimet", + "CATEGORIES": { + "TYPE": "Tyyppi", + "STATUS": "Tila", + "SEVERITY": "Vakavuus", + "PRIORITIES": "Tärkeydet", + "TAGS": "Avainsanat", + "ASSIGNED_TO": "Tekijä", + "CREATED_BY": "Luoja", + "CUSTOM_FILTERS": "Omat suodattimet" + }, + "CONFIRM_DELETE": { + "TITLE": "Poista oma suodatin", + "MESSAGE": "oma suodatin '{{customFilterName}}'" + } + }, + "TABLE": { + "COLUMNS": { + "TYPE": "Tyyppi", + "SEVERITY": "Vakavuus", + "PRIORITY": "Tärkeys", + "SUBJECT": "Aihe", + "STATUS": "Tila", + "CREATED": "Luotu", + "ASSIGNED_TO": "Tekijä" + }, + "TITLE_ACTION_CHANGE_STATUS": "Muuta tilaa", + "TITLE_ACTION_ASSIGNED_TO": "Tekijä", + "EMPTY": { + "TITLE": "Ei raportoitavia pyyntöjä:-)", + "SUBTITLE": "Löysitkö ongelman?", + "ACTION_CREATE_ISSUE": "Luo uusi pyyntö" + } + } + }, + "KANBAN": { + "SECTION_NAME": "Kanban", + "TITLE_ACTION_FOLD": "Kavenna sarake", + "TITLE_ACTION_UNFOLD": "Laajenna sarake", + "TITLE_ACTION_FOLD_CARDS": "Kavenna kortit", + "TITLE_ACTION_UNFOLD_CARDS": "Laajenna kortit", + "TITLE_ACTION_ADD_US": "Lisää uusi käyttäjätarina", + "TITLE_ACTION_ADD_BULK": "Lisää monta", + "ACTION_SHOW_ARCHIVED": "Näytä arkisto", + "ACTION_HIDE_ARCHIVED": "Piilota arkisto", + "HIDDEN_USER_STORIES": "Käyttäjätarinat tällä alueella ovat oletuksena piilotettuna", + "ARCHIVED": "Olet arkistoitu", + "UNDO_ARCHIVED": "Raahaa ja pudota uudelleen peruaksesi" + }, + "SEARCH": { + "FILTER_USER_STORIES": "Käyttäjätarinat", + "FILTER_ISSUES": "Pyynnöt", + "FILTER_TASKS": "Tehtävät", + "FILTER_WIKI": "Wiki-sivut", + "PLACEHOLDER_SEARCH": "Etsi täältä...", + "TITLE_ACTION_SEARCH": "hae", + "EMPTY_TITLE": "Mitään ei löytynyt.", + "EMPTY_DESCRIPTION": "Kokeile ylempiä välilehtiä ja hae uudestaan" + }, + "TEAM": { + "SECTION_NAME": "Tiimi", + "APP_TITLE": "TIIMI - {{projectName}}", + "PLACEHOLDER_INPUT_SEARCH": "Etsi koko nimellä...", + "COLUMN_MR_WOLF": "Mr. Wolf", + "EXPLANATION_COLUMN_MR_WOLF": "Suljetut pyynnöt", + "COLUMN_IOCAINE": "Hidasteiden syöjä", + "EXPLANATION_COLUMN_IOCAINE": "Kertyneet hidasteet", + "COLUMN_CERVANTES": "Cervantes", + "EXPLANATION_COLUMN_CERVANTES": "Wiki-sivuja muokattu", + "COLUMN_BUG_HUNTER": "Virheiden metsästäjä", + "EXPLANATION_COLUMN_BUG_HUNTER": "Pyyntöjä raportoitu", + "COLUMN_NIGHT_SHIFT": "Yövuoro", + "EXPLANATION_COLUMN_NIGHT_SHIFT": "Suljetut tehtävät", + "COLUMN_TOTAL_POWER": "Kokonaisvoima", + "EXPLANATION_COLUMN_TOTAL_POWER": "Kokonaispisteet", + "SECTION_TITLE_TEAM": "Tiimi >", + "SECTION_FILTER_ALL": "Kaikki", + "CONFIRM_LEAVE_PROJECT": "Oletko varma että haluat poistua projektista?", + "ACTION_LEAVE_PROJECT": "Poistu projektista" + }, + "CHANGE_PASSWORD": { + "SECTION_NAME": "Muuta salasanaa", + "FIELD_CURRENT_PASSWORD": "Nykyinen salasana", + "PLACEHOLDER_CURRENT_PASSWORD": "Nykyinen salasanasi (tai on tyhjä jos sinulla ei vielä ole)", + "FIELD_NEW_PASSWORD": "Uusi salasana", + "PLACEHOLDER_NEW_PASSWORD": "Anna uusi salasana", + "FIELD_RETYPE_PASSWORD": "Anna salasana uudelleen", + "PLACEHOLDER_RETYPE_PASSWORD": "Anna salasana uudelleen", + "ERROR_PASSWORD_MATCH": "Salasanat eivät täsmää" + }, + "USER_SETTINGS": { + "AVATAR_MAX_SIZE": "Maksimi koko {{maxFileSize}}", + "MENU": { + "SECTION_TITLE": "Käyttäjän asetukset", + "USER_PROFILE": "Käyttäjän profiili", + "CHANGE_PASSWORD": "Muuta salasanaa", + "EMAIL_NOTIFICATIONS": "Sähköposti-ilmoitukset" + }, + "NOTIFICATIONS": { + "SECTION_NAME": "Sähköposti-ilmoitukset", + "COLUMN_PROJECT": "Projekti", + "COLUMN_RECEIVE_ALL": "Vastaanota kaikki", + "COLUMN_ONLY_INVOLVED": "Ainoa osallinen", + "COLUMN_NO_NOTIFICATIONS": "Ei ilmoituksia", + "OPTION_ALL": "Kaikki", + "OPTION_INVOLVED": "Osallisena", + "OPTION_NONE": "Ei yhtään" + }, + "POPOVER": { + "USER_PROFILE": "Käyttäjäprofiili", + "CHANGE_PASSWORD": "Muuta salasanaa", + "NOTIFICATIONS": "Ilmoitukset", + "FEEDBACK": "Palaute", + "TITLE_AVATAR": "Käyttäjän asetukset" + } + }, + "USER_PROFILE": { + "IMAGE_HELP": "Kuvan kooksi astetaan 80x80px.
", + "ACTION_CHANGE_IMAGE": "Muuta", + "ACTION_USE_GRAVATAR": "Käytä gravatar kuvaa", + "ACTION_DELETE_ACCOUNT": "Poista Taiga-tunnus", + "CHANGE_EMAIL_SUCCESS": "Tarkista sähköpostisi!
Lähetimme ohjeet
{{email}}
uuden osoitteen asettamiseen", + "CHANGE_PHOTO": "Muuta kuva", + "FIELD": { + "USERNAME": "Käyttäjänimi", + "EMAIL": "Sähköposti", + "FULL_NAME": "Koko nimi", + "PLACEHOLDER_FULL_NAME": "Anna koko nimesi", + "BIO": "Bio", + "PLACEHOLDER_BIO": "Kerro jotain itsestäsi", + "LANGUAGE": "Kieli", + "LANGUAGE_DEFAULT": "-- käytä oletuskieltä --" + } + }, + "WIZARD": { + "SECTION_TITLE_CHOOSE_TEMPLATE": "Valitse pohja", + "CHOOSE_TEMPLATE_TEXT": "Mikä pohja sopii paremmin projektillesi?", + "SECTION_TITLE_CREATE_PROJECT": "Luo projekti", + "CREATE_PROJECT_TEXT": "Täysin koskematon. Jännittävää!", + "PROGRESS_TEMPLATE_SELECTION": "Pohjan valinta", + "PROGRESS_NAME_DESCRIPTION": "Nimi ja kuvaus" + }, + "WIKI": { + "DATETIME": "DD MMM YYYY HH:mm", + "PLACEHOLDER_PAGE": "Kirjoita wiki-sivu", + "REMOVE": "Poista tämä wiki-sivu", + "DELETE_LIGHTBOX_TITLE": "Poista wiki-sivu", + "NAVIGATION": { + "SECTION_NAME": "Linkit", + "ACTION_ADD_LINK": "Lisää linkki" + }, + "SUMMARY": { + "TIMES_EDITED": "kertaa
muokattu", + "LAST_EDIT": "viimeinen
muokkaus", + "LAST_MODIFICATION": "viimeinen muokkaus" + } + } +} \ No newline at end of file diff --git a/app/locales/locale-fr.json b/app/locales/locale-fr.json new file mode 100644 index 00000000..0d79d36f --- /dev/null +++ b/app/locales/locale-fr.json @@ -0,0 +1,1091 @@ +{ + "COMMON": { + "YES": "Oui", + "NO": "Non", + "LOADING": "Chargement...", + "LOADING_PROJECT": "Chargement du projet...", + "DATE": "DD MMM YYYY", + "DATETIME": "DD MMM YYYY HH:mm", + "SAVE": "Enregistré", + "CANCEL": "Annuler", + "ACCEPT": "Accepter", + "DELETE": "Supprimer", + "CREATE": "Créer", + "ADD": "Ajouter", + "COPY_TO_CLIPBOARD": "Copier dans le presse-papier: Ctrl+C", + "EDIT": "Éditer", + "DRAG": "Faire glisser", + "TAG_LINE": "Votre outil de gestion de projet agile, libre et open source", + "TAG_LINE_2": "AIMEZ VOTRE PROJET", + "BLOCK": "Bloquer", + "UNBLOCK": "Débloquer", + "BLOCKED": "Bloqué", + "CREATED_BY": "Créé par {{fullDisplayName}}", + "FROM": "de", + "TO": "à", + "CLOSE": "clos", + "BLOCKED_NOTE": "Pourquoi cette histoire utilisateur est-elle bloquée?", + "BLOCKED_REASON": "Veillez s'il vous plait indiquer la raison", + "GO_HOME": "Retour à l'accueil", + "PLUGINS": "Plugins", + "BETA": "Version beta!", + "ONE_ITEM_LINE": "Un élément par ligne...", + "NEW_BULK": "Nouvel ajout en bloc", + "RELATED_TASKS": "Tâches associées", + "LOGOUT": "Déconnexion", + "EXTERNAL_USER": "an external user", + "GENERIC_ERROR": "L'un de nos Ooompa Loompas dit {{error}}.", + "IOCAINE_TEXT": "Vous vous sentez un peu submergé par une tâche ? Soyez certains d'en informer les autres en cliquant su Iocaine lors de la modification de la tâche. Il est possible de s'immuniser contre ce poison (fictif) en consommant de petites quantités en heures supplémentaires, tout comme il est possible de s'améliorer en acceptant parfois de nouveaux défis !", + "FORM_ERRORS": { + "DEFAULT_MESSAGE": "Cette valeur semble être invalide.", + "TYPE_EMAIL": "This value should be a valid email.", + "TYPE_URL": "This value should be a valid url.", + "TYPE_URLSTRICT": "This value should be a valid url.", + "TYPE_NUMBER": "This value should be a valid number.", + "TYPE_DIGITS": "This value should be digits.", + "TYPE_DATEISO": "Cette valeur n'est pas une date valide (AAAA-MM-JJ).", + "TYPE_ALPHANUM": "Cette valeur doit être alphanumérique.", + "TYPE_PHONE": "This value should be a valid phone number.", + "NOTNULL": "This value should not be null.", + "NOT_BLANK": "Cette valeur ne doit pas être vide.", + "REQUIRED": "Cette valeur est obligatoire.", + "REGEXP": "Cette valeur semble être invalide.", + "MIN": "This value should be greater than or equal to %s.", + "MAX": "This value should be lower than or equal to %s.", + "RANGE": "This value should be between %s and %s.", + "MIN_LENGTH": "This value is too short. It should have %s characters or more.", + "MAX_LENGTH": "This value is too long. It should have %s characters or less.", + "RANGE_LENGTH": "This value length is invalid. It should be between %s and %s characters long.", + "MIN_CHECK": "You must select at least %s choices.", + "MAX_CHECK": "You must select %s choices or less.", + "RANGE_CHECK": "You must select between %s and %s choices.", + "EQUAL_TO": "This value should be the same." + }, + "PICKERDATE": { + "FORMAT": "DD MMM YYYY", + "IS_RTL": "false", + "FIRST_DAY_OF_WEEK": "1", + "PREV_MONTH": "Mois précédent", + "NEXT_MONTH": "Mois suivant", + "MONTHS": { + "JAN": "Janvier", + "FEB": "Février", + "MAR": "Mars", + "APR": "Avril", + "MAY": "Mai", + "JUN": "Juin", + "JUL": "Juillet", + "AUG": "Août", + "SEP": "Septembre", + "OCT": "Octobre", + "NOV": "Novembre", + "DEC": "Décembre" + }, + "WEEK_DAYS": { + "SUN": "Dimanche", + "MON": "Lundi", + "TUE": "Mardi", + "WED": "Mercredi", + "THU": "Jeudi", + "FRI": "Vendredi", + "SAT": "Dimanche" + }, + "WEEK_DAYS_SHORT": { + "SUN": "Dim", + "MON": "Lun", + "TUE": "Mar", + "WED": "Mer", + "THU": "Jeu", + "FRI": "Ven", + "SAT": "Sam" + } + }, + "TAGS": { + "PLACEHOLDER": "Taggez moi !", + "DELETE": "Supprimer l'étiquette", + "ADD": "Ajouter un label" + }, + "DESCRIPTION": { + "EMPTY": "Un espace vide est si ennuyeux… allez-y, soyez descriptif… ", + "NO_DESCRIPTION": "Pas encore de description" + }, + "FIELDS": { + "SUBJECT": "Sujet", + "NAME": "Nom", + "URL": "URL", + "DESCRIPTION": "Description", + "VALUE": "Valeur", + "SLUG": "Slug", + "COLOR": "Couleur", + "IS_CLOSED": "Fermé ?", + "STATUS": "Etat", + "TYPE": "Type", + "SEVERITY": "Sévérité", + "PRIORITY": "Priorité", + "ASSIGNED_TO": "Affecté à", + "POINTS": "Points", + "BLOCKED_NOTE": "note bloquée", + "IS_BLOCKED": "est bloqué" + }, + "ROLES": { + "ALL": "Tout" + }, + "ASSIGNED_TO": { + "NOT_ASSIGNED": "Non affecté", + "DELETE_ASSIGNMENT": "Supprimer l'affectation", + "REMOVE_ASSIGNED": "Supprimer l'affectation", + "TOO_MANY": "...trop d'utilisateurs ; filtrez davantage", + "CONFIRM_UNASSIGNED": "Etes-vous sûr de vouloir continuer sans affectation ?", + "TITLE_ACTION_EDIT_ASSIGNMENT": "Modifier l'affectation" + }, + "STATUS": { + "CLOSED": "Clos", + "OPEN": "Ouvert" + }, + "WATCHERS": { + "ADD": "Ajouter un observateur", + "TITLE": "Observateurs", + "DELETE": "Supprimer l'observateur", + "TITLE_LIGHTBOX_DELETE_WARTCHER": "Supprimer l'observateur..." + }, + "CUSTOM_ATTRIBUTES": { + "CUSTOM_FIELDS": "Champs personnalisés", + "SAVE": "Sauver le champ personnalisé", + "EDIT": "Editer un champ personnalisé", + "DELETE": "Supprimer un attribut personnalisé", + "CONFIRM_DELETE": "Toutes les valeurs dans ce champ personnalisé vont être supprimées.
Etes-vous sure de vouloir continuer ?" + }, + "FILTERS": { + "TITLE": "filtres", + "INPUT_PLACEHOLDER": "Sujet ou référence", + "TITLE_ACTION_FILTER_BUTTON": "recherche", + "BREADCRUMB_TITLE": "retour aux catégories", + "BREADCRUMB_FILTERS": "Filtres", + "BREADCRUMB_STATUS": "état" + }, + "WYSIWYG": { + "H1_BUTTON": "Premier niveau de titre", + "H1_SAMPLE_TEXT": "Votre titre ici…", + "H2_BUTTON": "Deuxième niveau de titre", + "H2_SAMPLE_TEXT": "Votre titre ici…", + "H3_BUTTON": "Troisième niveau de titre", + "H3_SAMPLE_TEXT": "Votre titre ici…", + "BOLD_BUTTON": "Gras", + "BOLD_BUTTON_SAMPLE_TEXT": "Votre texte ici…", + "ITALIC_BUTTON": "Italique", + "ITALIC_SAMPLE_TEXT": "Votre texte ici…", + "STRIKE_BUTTON": "Barré", + "STRIKE_SAMPLE_TEXT": "Votre texte ici…", + "BULLETED_LIST_BUTTON": "Liste à puces", + "BULLETED_LIST_SAMPLE_TEXT": "Votre texte ici…", + "NUMERIC_LIST_BUTTON": "Liste numérotée", + "NUMERIC_LIST_SAMPLE_TEXT": "Votre texte ici…", + "PICTURE_BUTTON": "Image", + "PICTURE_SAMPLE_TEXT": "Votre texte alternatif à l'image ici…", + "LINK_BUTTON": "Lien", + "LINK_SAMPLE_TEXT": "Votre texte de lien ici…", + "QUOTE_BLOCK_BUTTON": "Bloc de citation", + "QUOTE_BLOCK_SAMPLE_TEXT": "Votre texte ici…", + "CODE_BLOCK_BUTTON": "Bloc de code", + "CODE_BLOCK_SAMPLE_TEXT": "Votre texte ici…", + "PREVIEW_BUTTON": "Prévisualiser", + "EDIT_BUTTON": "Éditer", + "MARKDOWN_HELP": "Aide sur la syntaxe Markdown" + }, + "PERMISIONS_CATEGORIES": { + "SPRINTS": { + "NAME": "Sprints", + "VIEW_SPRINTS": "Voir les sprints", + "ADD_SPRINTS": "Ajouter des sprints", + "MODIFY_SPRINTS": "Modifier des sprints", + "DELETE_SPRINTS": "Supprimer des sprints" + }, + "USER_STORIES": { + "NAME": "Histoires Utilisateur", + "VIEW_USER_STORIES": "Voir les histoires utilisateur", + "ADD_USER_STORIES": "Ajouter des histoires utilisateur", + "MODIFY_USER_STORIES": "Modifier des histoires utilisateur", + "DELETE_USER_STORIES": "Supprimer des histoires utilisateur" + }, + "TASKS": { + "NAME": "Tâches", + "VIEW_TASKS": "Voir les tâches", + "ADD_TASKS": "Ajouter des tâches", + "MODIFY_TASKS": "Modifier des tâches", + "DELETE_TASKS": "Supprimer des tâches" + }, + "ISSUES": { + "NAME": "Problèmes", + "VIEW_ISSUES": "Voir les problèmes", + "ADD_ISSUES": "Ajouter des problèmes", + "MODIFY_ISSUES": "Modifier des problèmes", + "DELETE_ISSUES": "Supprimer des problèmes" + }, + "WIKI": { + "NAME": "Wiki", + "VIEW_WIKI_PAGES": "Voir les pages wiki", + "ADD_WIKI_PAGES": "Ajouter des pages wiki", + "MODIFY_WIKI_PAGES": "Modifier des pages wiki", + "DELETE_WIKI_PAGES": "Supprimer des pages wiki", + "VIEW_WIKI_LINKS": "Voir les liens wiki", + "ADD_WIKI_LINKS": "Ajouter des liens wiki", + "DELETE_WIKI_LINKS": "Supprimer des liens wiki" + } + } + }, + "AUTH": { + "INVITED_YOU": "vous a invité-e à rejoindre le projet", + "NOT_REGISTERED_YET": "Pas encore inscrit?", + "REGISTER": "S'inscrire", + "CREATE_ACCOUNT": "créer votre compte gratuit ici" + }, + "ATTACHMENT": { + "SECTION_NAME": "pièces jointes", + "TITLE": "{{ fileName }} transmis le {{ date }}\n", + "DESCRIPTION": "Saisissez une description courte", + "DEPRECATED": "(deprecated)", + "DEPRECATED_FILE": "Obsolète?", + "ADD": "Ajouter une pièce jointe. <%- maxFileSizeMsg %>", + "MAX_FILE_SIZE": "[Taille max.: {{maxFileSize}}]", + "SHOW_DEPRECATED": "+ montrer les pièces jointes obsolètes", + "HIDE_DEPRECATED": "- cacher les pièces jointes obsolètes", + "COUNT_DEPRECATED": "({{ counter }} deprecated)", + "MAX_UPLOAD_SIZE": "La taille maximum d'upload est {{maxFileSize}}", + "DATE": "DD MMM YYYY [at] hh:mm", + "ERROR_UPLOAD_ATTACHMENT": "We have not been able to upload '{{fileName}}'. {{errorMessage}}", + "TITLE_LIGHTBOX_DELETE_ATTACHMENT": "Supprimer la pièce jointe...", + "MSG_LIGHTBOX_DELETE_ATTACHMENT": "la pièce jointe \"{{fileName}}\"", + "ERROR_DELETE_ATTACHMENT": "We have not been able to delete: {{errorMessage}}", + "FIELDS": { + "IS_DEPRECATED": "est obsolète" + } + }, + "PAGINATION": { + "PREVIOUS": "Précédent", + "NEXT": "Suivant" + }, + "ADMIN": { + "COMMON": { + "TITLE_ACTION_EDIT_VALUE": "Modifier", + "TITLE_ACTION_DELETE_VALUE": "Supprimer" + }, + "HELP": "Avez-vous besoin d'aide? Consultez notre page de soutien!", + "PROJECT_DEFAULT_VALUES": { + "TITLE": "Valeurs par défaut", + "SUBTITLE": "Définir les valeurs par défaut pour toutes les listes de sélection" + }, + "MEMBERSHIPS": { + "TITLE": "Gérer les membres", + "ADD_BUTTON": "+ Nouveau membre", + "ADD_BUTTON_TITLE": "Ajouter un membre" + }, + "PROJECT_EXPORT": { + "TITLE": "Exporter", + "SUBTITLE": "Exportez votre projet pour le sauvegarder ou en créer un nouveau basé sur celui-ci.", + "EXPORT_BUTTON": "Exporter", + "EXPORT_BUTTON_TITLE": "Exportez votre projet", + "LOADING_TITLE": "Nous sommes en train de générer votre fichier de dump.", + "DUMP_READY": "Votre fichier de dump est prêt !", + "LOADING_MESSAGE": "Merci de ne pas fermer cette page.", + "ASYNC_MESSAGE": "Nous vous enverrons un email lorsque ce sera prêt", + "SYNC_MESSAGE": "Si le téléchargement ne commence pas automatiquement, cliquez ici.", + "ERROR": "Nos oompa loompas ont des problèmes à générer le dump S'il vous plait, essayez de nouveau.", + "ERROR_BUSY": "Nous sommes désolés, nos oompa loompas sont très occupés en ce moment. Veuillez réessayer dans quelques minutes.", + "ERROR_MESSAGE": "Nos oompa loompas ont des problèmes à générer votre dump : {{message}}" + }, + "MODULES": { + "TITLE": "Modules", + "ENABLE": "Activer", + "DISABLE": "Désactiver", + "BACKLOG": "Historique", + "BACKLOG_DESCRIPTION": "Gérez votre histoires utilisateur pour garder une vue organisée des travaux à venir et priorisés.", + "KANBAN": "Kanban", + "KANBAN_DESCRIPTION": "Organisez votre projet de manière agile avec ce tableau.", + "ISSUES": "Problèmes", + "ISSUES_DESCRIPTION": "Suivez les bugs, questions et améliorations liés à votre projet. Ne ratez rien!", + "WIKI": "Wiki", + "WIKI_DESCRIPTION": "Ajoutez, modifiez, ou supprimez du contenu en collaboration avec d'autres. C'est le bon endroit pour la documentation de votre projet.", + "MEETUP": "Meet Up", + "MEETUP_DESCRIPTION": "Choisissez votre système de vidéoconférence. Même les développeurs ont besoin de contact en face à face.", + "SELECT_VIDEOCONFERENCE": "Choisissez un système de vidéoconférence", + "SALT_CHAT_ROOM": "Si vous le souhaitez vous pouvez ajouter un code de salage au nom du salon de discussion" + }, + "PROJECT_PROFILE": { + "PAGE_TITLE": "Profil projet - {{sectionName}} - {{projectName}}", + "PROJECT_DETAILS": "Détails du projet", + "PROJECT_NAME": "Nom du projet", + "PROJECT_SLUG": "Slug du projet", + "NUMBER_SPRINTS": "Nombre de sprints", + "NUMBER_US_POINTS": "Nombre de points HU", + "TAGS": "Étiquettes", + "DESCRIPTION": "Description", + "PUBLIC_PROJECT": "Projet public", + "PRIVATE_PROJECT": "Projet privé", + "DELETE": "Supprimer ce projet" + }, + "REPORTS": { + "TITLE": "Rapports", + "SUBTITLE": "Exportez les données de votre projet au format CSV pour créer vos propres rapports.", + "DESCRIPTION": "Téléchargez un fichier CSV ou copiez l'URL générée et ouvrez-là dans votre éditeur de texte ou feuille de calcul favorite pour créer vos propres rapports de projet. Vous pourrez visualiser et analyser toutes vos données facilement.", + "HELP": "Comment utiliser ceci dans ma propre feuille de calcul?", + "REGENERATE_TITLE": "Changer l'URL", + "REGENERATE_SUBTITLE": "Vous êtes sur le point de changer l'url d'accès aux données CSV. L'url précédente sera désactivée. Etes-vous sûre ?" + }, + "CSV": { + "SECTION_TITLE_US": "user stories reports", + "SECTION_TITLE_TASK": "Rapports des tâches", + "SECTION_TITLE_ISSUE": "issues reports", + "DOWNLOAD": "Télécharger au format CSV", + "URL_FIELD_PLACEHOLDER": "Merci de regénérer l'url de téléchargement au format CSV", + "TITLE_REGENERATE_URL": "Regénérer l'URL du CSV", + "ACTION_GENERATE_URL": "Générer l'URL", + "ACTION_REGENERATE": "Regénérer" + }, + "CUSTOM_FIELDS": { + "TITLE": "Champs Personnalisés", + "SUBTITLE": "Spécifiez les champs personnalisés de vos histoires utilisateur, tâches et problèmes", + "US_DESCRIPTION": "Champs personnalisés des histoires utilisateur", + "US_ADD": "Ajouter un champ personnalisé dans les histoires utilisateur", + "TASK_DESCRIPTION": "Champs personnalisés de tâches", + "TASK_ADD": "Ajouter un champ personnalisé dans les tâches", + "ISSUE_DESCRIPTION": "Champs personnalisés des problèmes", + "ISSUE_ADD": "Ajouter un champ personnalisé dans les problèmes" + }, + "PROJECT_VALUES": { + "APP_TITLE": "Valeurs projet - {{sectionName}} - {{projectName}}", + "REPLACEMENT": "Tous les éléments avec cette valeur seront modifiés par ", + "ERROR_DELETE_ALL": "Vous ne pouvez pas effacer toutes les valeurs" + }, + "PROJECT_VALUES_POINTS": { + "TITLE": "Points HU", + "SUBTITLE": "Spécifiez les points auxquels vos histoires utilisateur pourraient être estimés", + "ACTION_ADD": "Ajouter un nouveau point" + }, + "PROJECT_VALUES_PRIORITIES": { + "TITLE": "Priorités des problèmes", + "SUBTITLE": "Spécifiez les priorités qu'auront vos problèmes", + "ACTION_ADD": "Ajouter une priorité" + }, + "PROJECT_VALUES_SEVERITIES": { + "TITLE": "Sévérités des problèmes", + "SUBTITLE": "Spécifiez les sévérités qu'auront vos problèmes", + "ACTION_ADD": "Add new severity" + }, + "PROJECT_VALUES_STATUS": { + "TITLE": "Statut", + "SUBTITLE": "Spécifiez les statuts que vont prendre vos histoires utilisateur, tâches et problèmes", + "US_TITLE": "Statuts des HU", + "TASK_TITLE": "Statuts des Tâches", + "ISSUE_TITLE": "Statuts des Problèmes" + }, + "PROJECT_VALUES_TYPES": { + "TITLE": "Types", + "SUBTITLE": "Spécifiez les priorités qu'auront vos bugs", + "ISSUE_TITLE": "Types de problèmes", + "ACTION_ADD": "Add new type" + }, + "ROLES": { + "SECTION_NAME": "Rôles - {{projectName}}", + "WARNING_NO_ROLE": "Attention, aucun rôle dans votre projet ne pourra estimer la valeur du point pour les histoires utilisateurs", + "HELP_ROLE_ENABLED": "Si activé, les membres affectés à ce rôle pourront estimer la valeur du point pour les histoires utilisateurs", + "COUNT_MEMBERS": "{{ role.members_count }} membres avec ce rôle", + "TITLE_DELETE_ROLE": "Supprimer des rôles", + "REPLACEMENT_ROLE": "Tous les utilisateurs avec ce rôle seront déplacés dans", + "WARNING_DELETE_ROLE": "Attention, toutes les estimations de role seront supprimées", + "ERROR_DELETE_ALL": "Vous ne pouvez pas supprimer toutes les valeurs", + "EXTERNAL_USER": " " + }, + "THIRD_PARTIES": { + "SECRET_KEY": "Clé secrète", + "PAYLOAD_URL": "URL de Payload", + "VALID_IPS": "IP sources valides (séparées par des virgules)" + }, + "BITBUCKET": { + "SECTION_NAME": "Bitbucket", + "APP_TITLE": "Bitbucket - {{projectName}}", + "INFO_VERIFYING_IP": "Les requêtes Bitbucket ne sont pas signées, donc le meilleur moyen de vérifier l'origine est par l'adresse IP. Si le champ est vide il n'y aura pas de validation de l'IP." + }, + "GITLAB": { + "SECTION_NAME": "Gitlab", + "APP_TITLE": "Gitlab - {{projectName}}", + "INFO_VERIFYING_IP": "Les requêtes Gitlab ne sont pas signées, donc le meilleur moyen de vérifier l'origine est par l'adresse IP. Si le champ est vide il n'y aura pas de validation de l'IP." + }, + "GITHUB": { + "SECTION_NAME": "Github", + "APP_TITLE": "Github - {{projectName}}" + }, + "WEBHOOKS": { + "APP_TITLE": "Webhooks - {{projectName}}", + "SECTION_NAME": "Webhooks", + "SUBTITLE": "Les dérivations web informent des services externes d'événements dans Taiga, comme les commentaires, les histoires utilisateur…", + "ADD_NEW": "Ajouter une nouvelle dérivation", + "TYPE_NAME": "Entrez le nom du service", + "TYPE_PAYLOAD_URL": "Entrez l'URL de payload du service", + "TYPE_SERVICE_SECRET": "Entrez la clé secrète du service", + "SAVE": "Enregistrer la dérivation", + "CANCEL": "Annuler la dérivation", + "SHOW_HISTORY": "(Montrer l'historique)", + "TEST": "Tester la dérivation", + "EDIT": "Éditer la dérivation", + "DELETE": "Supprimer la dérivation", + "REQUEST": "Requête", + "RESEND_REQUEST": "Renvoyer la requête", + "HEADERS": "Entêtes", + "PAYLOAD": "Payload", + "RESPONSE": "Réponse", + "DATE": "DD MMM YYYY [at] hh:mm:ss", + "ACTION_HIDE_HISTORY": "(Cacher l'historique)", + "ACTION_HIDE_HISTORY_TITLE": "Cacher l'historique", + "ACTION_SHOW_HISTORY": "(Afficher l'historique)", + "ACTION_SHOW_HISTORY_TITLE": "Montrer l'historique", + "WEBHOOK_NAME": "Webhook '{{name}}'" + }, + "CUSTOM_ATTRIBUTES": { + "ADD": "Ajouter un champ personnalisé", + "EDIT": "Editer un champ personnalisé", + "DELETE": "Supprimer un champ personnalisé", + "SAVE_TITLE": "Sauvegarder le champ personnalisé", + "CANCEL_TITLE": "Annuler la création", + "SET_FIELD_NAME": "Saisissez le nom du champ personnalisé", + "SET_FIELD_DESCRIPTION": "Entrez la description de votre champ personnalisé", + "ACTION_UPDATE": "Mettre à jour le champ personnalisé", + "ACTION_CANCEL_EDITION": "Annuler l'édition" + }, + "MEMBERSHIP": { + "COLUMN_MEMBER": "Membre", + "COLUMN_ADMIN": "Admin", + "COLUMN_ROLE": "Rôle", + "COLUMN_STATUS": "Etat", + "STATUS_ACTIVE": "Actif", + "STATUS_PENDING": "En attente", + "DELETE_MEMBER": "Supprimer un membre", + "SUCCESS_SEND_INVITATION": "Nous avons envoyé une autre invitation à '{{email}}'.", + "ERROR_SEND_INVITATION": "Nous n'avons pas envoyé l'invitation", + "SUCCESS_DELETE": "Nous avons supprimé {{message}}.", + "ERROR_DELETE": "Nous n'avons pas été capable de supprimer {{message}}.", + "DEFAULT_DELETE_MESSAGE": "l'invitation à {{email}}" + }, + "DEFAULT_VALUES": { + "LABEL_POINTS": "Valeur par défaut pour la sélection des points", + "LABEL_US": "Valeur par défaut pour la sélection de l'histoire utilisateur", + "LABEL_TASK_STATUS": "Valeur par défaut pour la sélection de l'état des tâches", + "LABEL_PRIORITY": "Valeur par défaut de la sélection des priorités", + "LABEL_SEVERITY": "Valeur par défaut pour le sélecteur de sévérité", + "LABEL_ISSUE_TYPE": "Valeur par défaut pour le sélecteur de type", + "LABEL_ISSUE_STATUS": "Valeur par défaut pour le sélecteur de statut de bug" + }, + "STATUS": { + "PLACEHOLDER_WRITE_STATUS_NAME": "Entrez le nom du nouvel état" + }, + "TYPES": { + "PLACEHOLDER_WRITE_NAME": "Entrez un nom pour le nouvel élément" + }, + "US_STATUS": { + "ACTION_ADD_STATUS": "Ajouter un nouveau status", + "IS_ARCHIVED_COLUMN": "Est archivé?", + "WIP_LIMIT_COLUMN": "Limite de Work In Progress", + "PLACEHOLDER_WRITE_NAME": "Donnez un nom au nouvel état" + }, + "MENU": { + "TITLE": "Admin", + "PROJECT": "Projet", + "ATTRIBUTES": "Attributs", + "MEMBERS": "Membres", + "PERMISSIONS": "Permissions", + "INTEGRATIONS": "Intégrations", + "PLUGINS": "Plugins" + }, + "SUBMENU_PROJECT_ATTRIBUTES": { + "TITLE": "Attributes" + }, + "SUBMENU_PROJECT_VALUES": { + "STATUS": "Etats", + "POINTS": "Points", + "PRIORITIES": "Priorités", + "SEVERITIES": "Sévérités", + "TYPES": "Types", + "CUSTOM_FIELDS": "Champs personnalisés" + }, + "SUBMENU_PROJECT_PROFILE": { + "TITLE": "Profil projet" + }, + "SUBMENU_ROLES": { + "TITLE": "Rôles", + "ACTION_NEW_ROLE": "+ Nouveau rôle", + "TITLE_ACTION_NEW_ROLE": "Ajouter un nouveau rôle" + }, + "SUBMENU_THIDPARTIES": { + "TITLE": "Services" + } + }, + "PROJECT": { + "WELCOME": "Bienvenue", + "SECTION_PROJECTS": "Projets", + "STATS": { + "PROJECT": "points
projet", + "DEFINED": "points
définis", + "ASSIGNED": "points
affectés", + "CLOSED": "points
fermés" + }, + "SECTION": { + "SEARCH": "Rechercher", + "BACKLOG": "Backlog", + "KANBAN": "Kanban", + "ISSUES": "Problèmes", + "WIKI": "Wiki", + "TEAM": "Equipe", + "MEETUP": "Meet up", + "ADMIN": "Admin" + }, + "NAVIGATION": { + "SECTION_TITLE": "Vos projets", + "PLACEHOLDER_SEARCH": "Rechercher dans", + "ACTION_CREATE_PROJECT": "Créer un projet", + "TITLE_ACTION_IMPORT": "Importer un projet", + "TITLE_PRVIOUS_PROJECT": "Montrer les projets précédents", + "TITLE_NEXT_PROJECT": "Montrer les projets suivants" + }, + "IMPORT": { + "TITLE": "Import du projet en cours", + "UPLOADING_FILE": "Uploading dump file", + "DESCRIPTION": "Ce processus peut prendre du temps, veuillez garder cette fenêtre ouverte.", + "ASYNC_IN_PROGRESS_TITLE": "Nos Oompas Loompas sont en train d'importer votre projet", + "ASYNC_IN_PROGRESS_MESSAGE": "Ce processus pourrait durer plusieurs minutes
Nous vous enverrons un emai quand ce sera prêt", + "UPLOAD_IN_PROGRESS_MESSAGE": "Uploaded {{uploadedSize}} of {{totalSize}}", + "ERROR": "Nos Oompas Loompas ont rencontré des problèmes en important votre dump de données. Merci de réessayer.", + "ERROR_TOO_MANY_REQUEST": "Nous sommes désolés, nos oompa loompas sont très occupés en ce moment. Veuillez réessayer dans quelques minutes.", + "ERROR_MESSAGE": "Nos oompa loompas ont des problèmes pour importer le dump de vos données : {{error_message}}", + "ERROR_MAX_SIZE_EXCEEDED": "'{{fileName}}' ({{fileSize}}) is too heavy for our Oompa Loompas, try it with a smaller than ({{maxFileSize}})", + "SYNC_SUCCESS": "Votre projet a été importé avec succès" + } + }, + "LIGHTBOX": { + "DELETE_ACCOUNT": { + "SECTION_NAME": "Supprimer le compte Taiga", + "CONFIRM": "Etes-vous sûr de vouloir votre compte Taiga ?", + "SUBTITLE": "Vous allez nous manquer :(", + "NEWSLETTER_LABEL_TEXT": "Je ne veux plus recevoir votre newsletter" + }, + "DELETE_PROJECT": { + "TITLE": "Supprimer le projet", + "QUESTION": "Êtes-vous sûr de vouloir supprimer ce projet?", + "SUBTITLE": "Toutes les données ( histoires utilisateurs, tâches, problèmes, sprints et pages de wiki) seront perdues! :-(", + "CONFIRM": "Oui, je suis sûr" + }, + "ASSIGNED_TO": { + "SELECT": "Affecté à", + "SEARCH": "Chercher des utilisateurs" + }, + "ADD_MEMBER": { + "TITLE": "Nouveau membre", + "HELP_TEXT": "Si vos utilisateurs sont déjà inscrits sur Taiga, ils seront automatiquement ajoutés. Sinon, ils recevront une invitation." + }, + "CREATE_ISSUE": { + "TITLE": "Ajouter un problème" + }, + "FEEDBACK": { + "TITLE": "Dites nous quelque chose...", + "COMMENT": "...un bug, des suggestions, quelque chose de cool... ou même votre pire cauchemar avec Taiga", + "ACTION_SEND": "Envoyez vos commentaires" + }, + "SEARCH": { + "TITLE": "Rechercher", + "PLACEHOLDER_SEARCH": "Que cherchez-vous ?" + }, + "ADD_EDIT_SPRINT": { + "TITLE": "Nouveau sprint", + "PLACEHOLDER_SPRINT_NAME": "nom du sprint", + "PLACEHOLDER_SPRINT_START": "Début estimé", + "PLACEHOLDER_SPRINT_END": "Fin estimée", + "ACTION_DELETE_SPRINT": "Voulez-vous supprimer ce sprint ?", + "TITLE_ACTION_DELETE_SPRINT": "supprimer un sprint", + "LAST_SPRINT_NAME": "le dernier sprint est {{lastSprint}} ;-) " + }, + "CREATE_EDIT_TASK": { + "TITLE": "Nouvelle tâche", + "PLACEHOLDER_SUBJECT": "Le sujet de la tâche", + "PLACEHOLDER_STATUS": "Etat de la tâche", + "OPTION_UNASSIGNED": "Non affecté", + "PLACEHOLDER_SHORT_DESCRIPTION": "Saisissez une description courte", + "ACTION_EDIT": "Editer la tâche" + }, + "CREATE_EDIT_US": { + "TITLE": "Nouvelle US", + "PLACEHOLDER_DESCRIPTION": "Veuillez ajouter une description pour aider les autres à mieux comprendre cette histoire utilisateur", + "NEW_US": "Nouvelle histoire utilisateur", + "EDIT_US": "Éditer l'histoire utilisateur" + }, + "DELETE_SPRINT": { + "TITLE": "Supprimer le sprint" + }, + "CREATE_MEMBER": { + "PLACEHOLDER_INVITATION_TEXT": "(Optionnel) Ajoutez un texte personnalisé à l'invitation. Dites quelque chose de gentil à vos nouveaux membres ;-)", + "PLACEHOLDER_TYPE_EMAIL": "Saisissez un email" + } + }, + "US": { + "SECTION_NAME": "User story details", + "LINK_TASKBOARD": "Tableau des tâches", + "TITLE_LINK_TASKBOARD": "Aller au tableau des tâches", + "TOTAL_POINTS": "total", + "ADD": "Ajouter une nouvelle User Story", + "ADD_BULK": "Ajouter de nouvelles User Stories en masse", + "PROMOTED": "Cette US a été promue à partir d'un problème:", + "TITLE_LINK_GO_TO_ISSUE": "Aller vers ce problème", + "EXTERNAL_REFERENCE": "Cette US a été créée depuis", + "GO_TO_EXTERNAL_REFERENCE": "Allez sur l'origine", + "BLOCKED": "Cette user story est bloquée", + "PREVIOUS": "user story précédente", + "NEXT": "histoire utilisateur suivante", + "TITLE_DELETE_ACTION": "Supprimer l'histoire utilisateur", + "LIGHTBOX_TITLE_BLOKING_US": "US bloquante", + "TASK_COMPLETED": "{{totalClosedTasks}}/{{totalTasks}} tâches complétées", + "ASSIGN": "Affecter l'histoire utilisateur", + "NOT_ESTIMATED": "Non estimé", + "TOTAL_US_POINTS": "Total des points HU", + "FIELDS": { + "TEAM_REQUIREMENT": "Exigence de l'équipe", + "CLIENT_REQUIREMENT": "Exigence du client", + "FINISH_DATE": "Date de fin" + } + }, + "COMMENTS": { + "DELETED_INFO": "Commentaire supprimé par {{user}} on {{date}}\n", + "TITLE": "Commentaires", + "COMMENT": "Commentaire", + "TYPE_NEW_COMMENT": "Entrez un nouveau commentaire ici", + "SHOW_DELETED": "Monter le commentaire supprimé", + "HIDE_DELETED": "Cacher le commentaire supprimé", + "RESTORE": "Restaurer le commentaire" + }, + "ACTIVITY": { + "SHOW_ACTIVITY": "Montrer l'activité", + "DATETIME": "DD MMM YYYY HH:mm", + "SHOW_MORE": "+ Montrer les entrées précédentes ({{showMore}} plus)", + "TITLE": "Activité", + "REMOVED": "supprimé", + "ADDED": "ajouté", + "US_POINTS": "Points HU ({{name}})", + "NEW_ATTACHMENT": "nouvelle pièce jointe", + "DELETED_ATTACHMENT": "Pièce-jointe supprimée", + "UPDATED_ATTACHMENT": "Pièce jointe {{filename}} modifiée", + "DELETED_CUSTOM_ATTRIBUTE": "Attribut personnalisé supprimé", + "SIZE_CHANGE": "Made {size, plural, one{one change} other{# changes}}", + "VALUES": { + "YES": "oui", + "NO": "no", + "EMPTY": "empty", + "UNASSIGNED": "non affecté" + }, + "FIELDS": { + "SUBJECT": "sujet", + "NAME": "nom", + "DESCRIPTION": "description", + "CONTENT": "content", + "STATUS": "état", + "IS_CLOSED": "is closed", + "FINISH_DATE": "date de fin", + "TYPE": "type", + "PRIORITY": "priorité", + "SEVERITY": "sévérité", + "ASSIGNED_TO": "affecté à", + "WATCHERS": "observateurs", + "MILESTONE": "sprint", + "USER_STORY": "histoire utilisateur", + "PROJECT": "projet", + "IS_BLOCKED": "est bloqué", + "BLOCKED_NOTE": "note bloquée", + "POINTS": "points", + "CLIENT_REQUIREMENT": "exigence du client", + "TEAM_REQUIREMENT": "exigence de l'équipe", + "IS_IOCAINE": "est sous iocaine", + "TAGS": "étiquettes", + "ATTACHMENTS": "pièces jointes", + "IS_DEPRECATED": "est obsolète", + "ORDER": "order", + "BACKLOG_ORDER": "backlog order", + "SPRINT_ORDER": "sprint order", + "KANBAN_ORDER": "kanban order", + "TASKBOARD_ORDER": "trier le tableau des tâches", + "US_ORDER": "us order" + } + }, + "BACKLOG": { + "SECTION_NAME": "Backlog", + "MOVE_US_TO_CURRENT_SPRINT": "Déplacer vers le Sprint Courant", + "SHOW_FILTERS": "Montrer les filtres", + "SHOW_TAGS": "Montrer les étiquettes", + "EMPTY": "Votre historique est vide!", + "CREATE_NEW_US": "Créer une nouvelle HU", + "CREATE_NEW_US_EMPTY_HELP": "Vous pouvez envisager de créer une nouvelle histoire utilisateur", + "EXCESS_OF_POINTS": "Excès de points", + "PENDING_POINTS": "Points restants", + "CLOSED_POINTS": "clos", + "COMPACT_SPRINT": "Sprint Compact", + "GO_TO_TASKBOARD": "Aller au tableau des tâches de {{::name}}", + "EDIT_SPRINT": "Éditer le Sprint", + "TOTAL_POINTS": "total", + "STATUS_NAME": "Nom de l'état", + "SORTABLE_FILTER_ERROR": "Vous ne pouvez pas glisser-déposer quand les filtres sont ouverts", + "DOOMLINE": "Périmètre projet", + "CHART": { + "XAXIS_LABEL": "Sprints", + "YAXIS_LABEL": "Points", + "OPTIMAL": "Le nombre optimal de points en attente pour le sprint {{xval}} devrait être {{yval}}", + "REAL": "Le nombre réel de points pour le sprint {{xval}} est {{yval}}", + "INCREMENT_TEAM": "Le nombre de points ajoutés par les exigences de l'équipe pour le sprint {{xval}} est {{yval}}", + "INCREMENT_CLIENT": "Le nombre de points ajoutés par les exigences du client pour le sprint {{xval}} est {{yval}}" + }, + "TAGS": { + "TOGGLE": "Toggle tags visibility", + "SHOW": "Montrer les étiquettes", + "HIDE": "Cacher les étiquettes" + }, + "TABLE": { + "COLUMN_US": "Histoires utilisateur", + "TITLE_COLUMN_POINTS": "Sélectionnez la vue par rôle" + }, + "SPRINT_SUMMARY": { + "TOTAL_POINTS": "total
points", + "COMPLETED_POINTS": "complétés
points", + "OPEN_TASKS": "tâches
ouvertes", + "CLOSED_TASKS": "tâches
fermées", + "IOCAINE_DOSES": "doses
de iocaine", + "SHOW_STATISTICS_TITLE": "Afficher les statistiques" + }, + "SUMMARY": { + "PROJECT_POINTS": "projet
points", + "DEFINED_POINTS": "points
définis", + "CLOSED_POINTS": "points
fermés", + "POINTS_PER_SPRINT": "points /
sprint" + }, + "FILTERS": { + "TOGGLE": "Toggle filters visibility", + "TITLE": "Filtres", + "REMOVE": "Supprimer les filtres", + "HIDE": "Hide Filters", + "SHOW": "Afficher les filtres", + "FILTER_CATEGORY_STATUS": "Etat", + "FILTER_CATEGORY_TAGS": "Labels" + }, + "SPRINTS": { + "TITLE": "SPRINTS", + "DATE": "DD MMM YYYY", + "LINK_TASKBOARD": "Taskboard du sprint", + "TITLE_LINK_TASKBOARD": "Aller au Taskboard de \"{{name}}\"", + "NUMBER_SPRINTS": "
sprints", + "TITLE_ACTION_NEW_SPRINT": "+ Nouveau sprint", + "ACTION_NEW_SPRINT": "+ Nouveau sprint", + "ACTION_SHOW_CLOSED_SPRINTS": "Afficher les sprints échus", + "ACTION_HIDE_CLOSED_SPRINTS": "Cacher les sprints échus" + } + }, + "ERROR": { + "TEXT1": "Un problème s'est produit et nos Ooma Loompas y travaillent.", + "TEXT2": "Veuillez essayer de rafraîchir dans quelques instants.", + "NOT_FOUND": "Non trouvé", + "NOT_FOUND_TEXT": "Erreur 404. La page que vous cherchez n'existe plus. Peut-être pouvez-vous retourner à la page d'accueil de Taiga et voir si vous trouvez ce que vous cherchez.", + "PERMISSION_DENIED": "Permission refusée", + "PERMISSION_DENIED_CODE": "Erreur 403.", + "VERSION_ERROR": "Quelqu'un a changé ça auparavant dans Taiga et nos Oompa Loompas ne peuvent appliquer vos modifications. Veuillez recharger la page et appliquer vos modifications de nouveaux (elles seront perdues)." + }, + "TASKBOARD": { + "SECTION_NAME": "Tableau des tâches", + "TITLE_ACTION_ADD": "Ajouter une nouvelle tâche", + "TITLE_ACTION_ADD_BULK": "Ajouter de nouvelles tâches en masse", + "TITLE_ACTION_ASSIGN": "Affecter une tâche", + "TITLE_ACTION_EDIT": "Editer la tâche", + "TABLE": { + "COLUMN": "Histoire utilisateur", + "TITLE_ACTION_FOLD": "Replier la colonne", + "TITLE_ACTION_UNFOLD": "Déplier la colonne", + "TITLE_ACTION_FOLD_ROW": "Replier la ligne", + "TITLE_ACTION_UNFOLD_ROW": "Déplier la ligne", + "FIELD_POINTS": "points", + "ROW_UNASSIGED_TASKS_TITLE": "Tâches non assignées" + }, + "CHARTS": { + "XAXIS_LABEL": "Journées", + "YAXIS_LABEL": "Points", + "OPTIMAL": "Le nombre optimal de points pour le jour {{formattedDate}} devrait être {{roundedValue}}", + "REAL": "Le nombre réel de points pour le jour {{formattedDate}} est {{roundedValue}}", + "DATE": "DD MMMM YYYY" + } + }, + "TASK": { + "SECTION_NAME": "Détails de la tâche", + "LINK_TASKBOARD": "Tableau des tâches", + "TITLE_LINK_TASKBOARD": "Aller au tableau des tâches", + "PLACEHOLDER_SUBJECT": "Entrez le sujet de la nouvelle tâche", + "TITLE_SELECT_STATUS": "Nom de l'état", + "OWNER_US": "La tâche appartient à", + "TITLE_LINK_GO_OWNER": "Aller à l'histoire utilisateur", + "ORIGIN_US": "Cette tâche a été créée par", + "TITLE_LINK_GO_ORIGIN": "Aller à l'histoire utilisateur", + "BLOCKED": "Cette tâche est bloquée", + "PREVIOUS": "tâche précédente", + "NEXT": "tâche suivante", + "TITLE_DELETE_ACTION": "Supprimer une tâche", + "LIGHTBOX_TITLE_BLOKING_TASK": "Tâche bloquante", + "FIELDS": { + "MILESTONE": "Sprint", + "USER_STORY": "Histoire utilisateur", + "IS_IOCAINE": "est sous iocaine" + }, + "ACTION_IOCAINE": "locaine", + "TITLE_ACTION_IOCAINE": "Vous vous sentez un peu dépassé par une tâche? Assurez-vous que les autres le savent en cliquant sur locaine en éditant une tâche. Il est possible de s'immuniser contre ce poison (fictif) en en consommant de faibles doses pendant un moment tout comme il est possible de devenir meilleur à ce que vous faîtes en relevant quelques défis à l'occasion!" + }, + "NOTIFICATION": { + "OK": "Tout est ok", + "WARNING": "Oops, quelque chose s'est produit...", + "WARNING_TEXT": "Nos oompa Loompas sont tristes, vos modification n'ont pas été sauvegardées!", + "SAVED": "Nos oompa Loompas ont sauvegardés toutes vos modifications !", + "CLOSE": "Fermer la notification", + "MAIL": "Notifications par mail", + "ASK_DELETE": "Etes-vous sûre de vouloir supprimer ?" + }, + "CANCEL_ACCOUNT": { + "TITLE": "Annuler votre compte", + "SUBTITLE": "Nous sommes tristes de vous voir quitter la taiga, et nous espérons que vous avez apprécié votre séjour. :)", + "PLACEHOLDER_INPUT_TOKEN": "Annuler le jeton du compte", + "ACTION_LEAVING": "Oui, je m'en vais!", + "SUCCESS": "Nos Oompa Loompas ont supprimés votre compte" + }, + "CHANGE_EMAIL_FORM": { + "TITLE": "Modifier votre email", + "SUBTITLE": "Plus qu'un click et votre email sera mis à jour!", + "PLACEHOLDER_INPUT_TOKEN": "modifier le jeton email", + "ACTION_CHANGE_EMAIL": "Modifier l'email", + "SUCCESS": "Nos Oompa Loompas ont mis à jour votre email" + }, + "CHANGE_PASSWORD_RECOVERY_FORM": { + "TITLE": "Créez un nouveau mot de passe pour Taiga", + "SUBTITLE": "Et au fait, vous devriez penser à manger de la nourriture plus riche en fer, c'est bon pour le cerveau. :p", + "PLACEHOLDER_RECOVER_PASSWORD_TOKEN": "Récupérer le jeton du mot de passe", + "LINK_NEED_TOKEN": "En avez-vous besoin?", + "TITLE_LINK_NEED_TOKEN": "Avez-vous besoin d'un token pour récupérer votre mot de passe que vous avez oublié ?", + "PLACEHOLDER_NEW_PASSWORD": "Nouveau mot de passe", + "PLACEHOLDER_RE_TYPE_NEW_PASSWORD": "Confirmez votre nouveau mot de passe", + "ACTION_RESET_PASSWORD": "Réinitialiser le mot de passe", + "SUCCESS": "Nos Oompa Loompas ont sauvegardé votre nouveau mot de passe.
Essayez de vous connecter avec." + }, + "FORGOT_PASSWORD_FORM": { + "TITLE": "Oops, avez-vous oublié votre mot de passe ?", + "SUBTITLE": "Saisissez votre nom d'utilisateur ou votre email pour en obtenir un nouveau", + "PLACEHOLDER_FIELD": "Nom d'utilisateur ou email", + "ACTION_RESET_PASSWORD": "Réinitialiser le mot de passe", + "LINK_CANCEL": "Nan, ramenez-moi en arrière. Je crois que je m'en rappelle.", + "SUCCESS": "Consultez votre messagerie!
Nous venons d'envoyer un mail avec les instructions pour créer un nouveau mot de passe", + "ERROR": "Selon nos Oompa Loompas, vous n'êtes pas encore enregistré." + }, + "LOGIN_COMMON": { + "HEADER": "J'ai déjà un login Taiga", + "PLACEHOLDER_AUTH_NAME": "Nom d'utilisateur ou email (sensible à la casse)", + "LINK_FORGOT_PASSWORD": "Mot de passe oublié?", + "TITLE_LINK_FORGOT_PASSWORD": "Avez-vous oublié votre mot de passe ?", + "ACTION_ENTER": "Entrer", + "ACTION_SIGN_IN": "Connexion", + "PLACEHOLDER_AUTH_PASSWORD": "Mot de passe (sensible à la casse)" + }, + "LOGIN_FORM": { + "ERROR_AUTH_INCORRECT": "Selon nos Oompa Loompas, votre nom d'utilisateur / email ou votre mot de passe sont incorrects.", + "ERROR_GENERIC": "Selon nos Oompa Loompas, une erreur est survenue.", + "SUCCESS": "Nos Oompa Loompas sont heureux, bienvenue sur Taiga." + }, + "INVITATION_LOGIN_FORM": { + "NOT_FOUND": "Ooops, nous avons un problème
Nos Oompa Loompas trouvent pas votre invitation.", + "SUCCESS": "Vous avez rejoint ce projet, Bienvenue sur {{project_name}}", + "ERROR": "Selon nos Oompa Loompas, vous n'êtes pas encore enregistrés ou vous avez saisi un mot de passe incorrecte." + }, + "REGISTER_FORM": { + "TITLE": "Register a new Taiga account (free)", + "PLACEHOLDER_NAME": "Choisissez un nom d'utilisateur (sensible à la casse)", + "PLACEHOLDER_FULL_NAME": "Choisissez votre nom complet", + "PLACEHOLDER_EMAIL": "Votre email", + "PLACEHOLDER_PASSWORD": "Saisissez un mot de passe (sensible à la casse)", + "ACTION_SIGN_UP": "S'enregistrer", + "TITLE_LINK_LOGIN": "Se connecter", + "LINK_LOGIN": "Êtes-vous déjà enregistré? Connectez-vous." + }, + "ISSUES": { + "LIST_SECTION_NAME": "Problèmes", + "SECTION_NAME": "Issue details", + "ACTION_NEW_ISSUE": "+ NOUVEAU PROBLÈME", + "ACTION_PROMOTE_TO_US": "Transformer en User Story", + "PLACEHOLDER_FILTER_NAME": "Écrivez le nom du filtre et appuyez sur \"Entrée\"", + "PROMOTED": "Le problème a été promu en histoire utilisateur", + "EXTERNAL_REFERENCE": "Ce problème a été créé à partir de", + "GO_TO_EXTERNAL_REFERENCE": "Aller à l'origine", + "BLOCKED": "Ce bug est bloqué", + "TITLE_PREVIOUS_ISSUE": "bug précédent", + "TITLE_NEXT_ISSUE": "problème suivant", + "ACTION_DELETE": "Supprimer le problème", + "LIGHTBOX_TITLE_BLOKING_ISSUE": "Problème bloquant", + "CONFIRM_PROMOTE": { + "TITLE": "Transformer ce problème en une nouvelle user story", + "MESSAGE": "Etes-vous sure de vouloir créer un nouvelle US à partir de ce problème ?" + }, + "FILTERS": { + "TITLE": "Filtres", + "INPUT_SEARCH_PLACEHOLDER": "Sujet ou réf.", + "TITLE_ACTION_SEARCH": "Rechercher", + "ACTION_SAVE_CUSTOM_FILTER": "sauvegarder en tant que filtre personnalisé", + "BREADCRUMB": "Filtres", + "TITLE_BREADCRUMB": "Filtres", + "CATEGORIES": { + "TYPE": "Type", + "STATUS": "Statut", + "SEVERITY": "Sévérité", + "PRIORITIES": "Priorités", + "TAGS": "Étiquettes", + "ASSIGNED_TO": "Affecté à", + "CREATED_BY": "Créé par", + "CUSTOM_FILTERS": "Filtres personnalisés" + }, + "CONFIRM_DELETE": { + "TITLE": "Supprime le filtre personnalisé", + "MESSAGE": "le filtre personnalisé '{{customFilterName}}'" + } + }, + "TABLE": { + "COLUMNS": { + "TYPE": "Type", + "SEVERITY": "Sévérité", + "PRIORITY": "Priorité", + "SUBJECT": "Sujet", + "STATUS": "Statut", + "CREATED": "Créé le", + "ASSIGNED_TO": "Affecté à" + }, + "TITLE_ACTION_CHANGE_STATUS": "Modifier l'état", + "TITLE_ACTION_ASSIGNED_TO": "Affecté à", + "EMPTY": { + "TITLE": "Aucun bug rapporté :-)", + "SUBTITLE": "Avez-vous trouvé un bug ?", + "ACTION_CREATE_ISSUE": "Créer un nouveau problème" + } + } + }, + "KANBAN": { + "SECTION_NAME": "Kanban", + "TITLE_ACTION_FOLD": "Replier la colonne", + "TITLE_ACTION_UNFOLD": "Déplier la colonne", + "TITLE_ACTION_FOLD_CARDS": "Replier les cartes", + "TITLE_ACTION_UNFOLD_CARDS": "Déplier les cartes", + "TITLE_ACTION_ADD_US": "Ajouter une nouvelle histoire utilisateur", + "TITLE_ACTION_ADD_BULK": "Ajout en masse", + "ACTION_SHOW_ARCHIVED": "Montrer les éléments archivés", + "ACTION_HIDE_ARCHIVED": "Cacher les éléments archivés", + "HIDDEN_USER_STORIES": "Les user stories avec ce statut sont masquées par défaut", + "ARCHIVED": "Vous avez archivé", + "UNDO_ARCHIVED": "Refaites le glisser-déposer pour annuler" + }, + "SEARCH": { + "FILTER_USER_STORIES": "Histoires utilisateur", + "FILTER_ISSUES": "Problèmes", + "FILTER_TASKS": "Tâches", + "FILTER_WIKI": "Pages Wiki", + "PLACEHOLDER_SEARCH": "Rechercher dans...", + "TITLE_ACTION_SEARCH": "rechercher", + "EMPTY_TITLE": "Il semble que vos critères de recherche n'aient rapporté aucun résultat.", + "EMPTY_DESCRIPTION": "Vous pouvez essayer l'un des onglets au-dessus ou relancer une recherche" + }, + "TEAM": { + "SECTION_NAME": "Equipe", + "APP_TITLE": "EQUIPE - {{projectName}}", + "PLACEHOLDER_INPUT_SEARCH": "Rechercher par nom...", + "COLUMN_MR_WOLF": "Mr. Wolf", + "EXPLANATION_COLUMN_MR_WOLF": "Bugs fermés", + "COLUMN_IOCAINE": "Buveur de iocaine", + "EXPLANATION_COLUMN_IOCAINE": "Doses de iocaine ingérées", + "COLUMN_CERVANTES": "Cervantes", + "EXPLANATION_COLUMN_CERVANTES": "Page Wiki éditée", + "COLUMN_BUG_HUNTER": "Chasseur de bug", + "EXPLANATION_COLUMN_BUG_HUNTER": "Problèmes rapportés", + "COLUMN_NIGHT_SHIFT": "Equipe de nuit", + "EXPLANATION_COLUMN_NIGHT_SHIFT": "Tâches fermées", + "COLUMN_TOTAL_POWER": "Puissance totale", + "EXPLANATION_COLUMN_TOTAL_POWER": "Points au total", + "SECTION_TITLE_TEAM": "Equipe >", + "SECTION_FILTER_ALL": "Tout", + "CONFIRM_LEAVE_PROJECT": "Êtes-vous sûr de vouloir quitter le projet ?", + "ACTION_LEAVE_PROJECT": "Quitter le projet" + }, + "CHANGE_PASSWORD": { + "SECTION_NAME": "Modifier le mot de passe", + "FIELD_CURRENT_PASSWORD": "Mot de passe courant", + "PLACEHOLDER_CURRENT_PASSWORD": "Votre mot de passe courant (ne rien saisir si vous ne possédez pas encore de mot de passe)", + "FIELD_NEW_PASSWORD": "Nouveau mot de passe", + "PLACEHOLDER_NEW_PASSWORD": "Entrez un nouveau mot de passe", + "FIELD_RETYPE_PASSWORD": "Confirmez le mot de passe", + "PLACEHOLDER_RETYPE_PASSWORD": "Confirmez le mot de passe", + "ERROR_PASSWORD_MATCH": "Les mots de passe ne correspondent pas" + }, + "USER_SETTINGS": { + "AVATAR_MAX_SIZE": "[Taille max.: {{maxFileSize}}]", + "MENU": { + "SECTION_TITLE": "Paramètres de l'utilisateur", + "USER_PROFILE": "Profil utilisateur", + "CHANGE_PASSWORD": "Modifier le mot de passe", + "EMAIL_NOTIFICATIONS": "Notifications email" + }, + "NOTIFICATIONS": { + "SECTION_NAME": "Notifications email", + "COLUMN_PROJECT": "Projet", + "COLUMN_RECEIVE_ALL": "Tout recevoir", + "COLUMN_ONLY_INVOLVED": "Uniquement si impliqué", + "COLUMN_NO_NOTIFICATIONS": "Aucune notification", + "OPTION_ALL": "Toutes", + "OPTION_INVOLVED": "Impliqué", + "OPTION_NONE": "Aucune" + }, + "POPOVER": { + "USER_PROFILE": "Profil utilisateur", + "CHANGE_PASSWORD": "Changer de mot de passe", + "NOTIFICATIONS": "Notifications", + "FEEDBACK": "Feedback", + "TITLE_AVATAR": "Préférences utilisateur" + } + }, + "USER_PROFILE": { + "IMAGE_HELP": "L'image va être mise à l'échelle à 80x80px.
", + "ACTION_CHANGE_IMAGE": "Modifier", + "ACTION_USE_GRAVATAR": "Utiliser une image gravatar", + "ACTION_DELETE_ACCOUNT": "Supprime le compte Taiga", + "CHANGE_EMAIL_SUCCESS": "Consultez votre messagerie!
Nous vous avons envoyé un mail
avec les instructions à suivre pour saisir votre nouvelle adresse", + "CHANGE_PHOTO": "Changer la photo", + "FIELD": { + "USERNAME": "Identifiant", + "EMAIL": "Email", + "FULL_NAME": "Nom complet", + "PLACEHOLDER_FULL_NAME": "Saisissez votre nom complet (ex. Íñigo Montoya)", + "BIO": "Bio", + "PLACEHOLDER_BIO": "Dites m'en plus sur vous", + "LANGUAGE": "Langue", + "LANGUAGE_DEFAULT": "-- utiliser la langue par défaut --" + } + }, + "WIZARD": { + "SECTION_TITLE_CHOOSE_TEMPLATE": "Choisissez un template", + "CHOOSE_TEMPLATE_TEXT": "Quel template conviendrait le mieux à votre projet ?", + "SECTION_TITLE_CREATE_PROJECT": "Créer un projet", + "CREATE_PROJECT_TEXT": "Tout beau, tout nouveau !", + "PROGRESS_TEMPLATE_SELECTION": "Choix du modèle", + "PROGRESS_NAME_DESCRIPTION": "Nom et description" + }, + "WIKI": { + "DATETIME": "DD MMM YYYY HH:mm", + "PLACEHOLDER_PAGE": "Ecrivez votre page wiki", + "REMOVE": "Supprimer cette page wiki", + "DELETE_LIGHTBOX_TITLE": "Supprimer la page Wiki", + "NAVIGATION": { + "SECTION_NAME": "Liens", + "ACTION_ADD_LINK": "Ajouter un lien" + }, + "SUMMARY": { + "TIMES_EDITED": "modifications", + "LAST_EDIT": "dernière
modification", + "LAST_MODIFICATION": "dernière modification" + } + } +} \ No newline at end of file diff --git a/app/locales/locale-zh-hant.json b/app/locales/locale-zh-hant.json new file mode 100644 index 00000000..9d7cc7ab --- /dev/null +++ b/app/locales/locale-zh-hant.json @@ -0,0 +1,1091 @@ +{ + "COMMON": { + "YES": "Yes", + "NO": "No", + "LOADING": "載入中...", + "LOADING_PROJECT": "載入專案中...", + "DATE": "DD MMM YYYY", + "DATETIME": "DD MMM YYYY HH:mm", + "SAVE": "儲存", + "CANCEL": "取消", + "ACCEPT": "接受", + "DELETE": "刪除", + "CREATE": "創建", + "ADD": "新增", + "COPY_TO_CLIPBOARD": "複製到剪貼簿:Ctrl+C", + "EDIT": "編輯", + "DRAG": "拖拉", + "TAG_LINE": "你的敏捷、免費、和開放原始碼的專案管理工具", + "TAG_LINE_2": "愛你的專案", + "BLOCK": "封鎖", + "UNBLOCK": "解除封鎖", + "BLOCKED": "已封鎖", + "CREATED_BY": "由 {{fullDisplayName}}創建", + "FROM": "from", + "TO": "to", + "CLOSE": "關閉", + "BLOCKED_NOTE": "為何這個使用者故事被封鎖?", + "BLOCKED_REASON": "請解釋此原因", + "GO_HOME": "帶我回到首頁", + "PLUGINS": "外掛", + "BETA": "我們在測試中", + "ONE_ITEM_LINE": "一行一物 ", + "NEW_BULK": "新批次插入", + "RELATED_TASKS": "相關任務 ", + "LOGOUT": "登出", + "EXTERNAL_USER": "外部使用者", + "GENERIC_ERROR": "我們的系統指出{{error}}.", + "IOCAINE_TEXT": "感到任務的不堪負荷?確認其它人在編輯任務時知道此狀況,可以點選Iocaine。它可能會成為免疫的致命狀況,只要長期小量消耗,但如果你只是偶而挑戰它可有助表現。", + "FORM_ERRORS": { + "DEFAULT_MESSAGE": "該數值似乎為無效", + "TYPE_EMAIL": "該電子郵件應為有效地址", + "TYPE_URL": "該網址應為有效連結", + "TYPE_URLSTRICT": "該網址應為有效連結", + "TYPE_NUMBER": "該數值應為有效號碼 ", + "TYPE_DIGITS": "該數值應為有效數字", + "TYPE_DATEISO": "該數值應為有效日期 (YYYY-MM-DD).", + "TYPE_ALPHANUM": "該數值應為字母", + "TYPE_PHONE": "該數值應為有效的電話號碼 ", + "NOTNULL": "該數值不應為零", + "NOT_BLANK": "該數值不應為空白", + "REQUIRED": "該數值為必要", + "REGEXP": "該數值似乎無效", + "MIN": "該數值應大於或等於 %s", + "MAX": "該數值應小於或等於 %s", + "RANGE": "該數值應介於 %s 與 %s之間", + "MIN_LENGTH": "該數值過簡短,它至少要有 %s個字元", + "MAX_LENGTH": "該數值過長,它不可多於 %s個字元。", + "RANGE_LENGTH": "該數值長度為無效,它應介於 %s 與 %s 字元之間", + "MIN_CHECK": "你必須至少選擇 %s 選項", + "MAX_CHECK": "你必須至多選出 %s選項", + "RANGE_CHECK": "你必須在%s 與 %s 之間作出選擇", + "EQUAL_TO": "該數值應為一致" + }, + "PICKERDATE": { + "FORMAT": "DD MMM YYYY", + "IS_RTL": "false", + "FIRST_DAY_OF_WEEK": "1", + "PREV_MONTH": "Previous Month", + "NEXT_MONTH": "Next Month", + "MONTHS": { + "JAN": "January", + "FEB": "February", + "MAR": "March", + "APR": "April", + "MAY": "May", + "JUN": "June", + "JUL": "July", + "AUG": "August", + "SEP": "September", + "OCT": "October", + "NOV": "November", + "DEC": "December" + }, + "WEEK_DAYS": { + "SUN": "Sunday", + "MON": "Monday", + "TUE": "Tuesday", + "WED": "Wednesday", + "THU": "Thursday", + "FRI": "Friday", + "SAT": "Saturday" + }, + "WEEK_DAYS_SHORT": { + "SUN": "Sun", + "MON": "Mon", + "TUE": "Tue", + "WED": "Wed", + "THU": "Thu", + "FRI": "Fri", + "SAT": "Sat" + } + }, + "TAGS": { + "PLACEHOLDER": "我在這裏,請標注我", + "DELETE": "刪除Tag", + "ADD": "新增標籤" + }, + "DESCRIPTION": { + "EMPTY": "留下空白顯得很無趣,寫下點描述吧", + "NO_DESCRIPTION": "未有任何描述" + }, + "FIELDS": { + "SUBJECT": "主旨", + "NAME": "名稱 ", + "URL": "網址", + "DESCRIPTION": "描述", + "VALUE": "數值", + "SLUG": "代稱 ", + "COLOR": "顏色", + "IS_CLOSED": "關閉中?", + "STATUS": "狀態", + "TYPE": "類型", + "SEVERITY": "急迫性", + "PRIORITY": "優先性", + "ASSIGNED_TO": "指派給 ", + "POINTS": "點數", + "BLOCKED_NOTE": "已封鎖之筆記", + "IS_BLOCKED": "封鎖" + }, + "ROLES": { + "ALL": "所有" + }, + "ASSIGNED_TO": { + "NOT_ASSIGNED": "未指派", + "DELETE_ASSIGNMENT": "刪除指派", + "REMOVE_ASSIGNED": "數值", + "TOO_MANY": "太多用戶,繼續過濾中", + "CONFIRM_UNASSIGNED": "你確定要讓它無任何指派嗎?", + "TITLE_ACTION_EDIT_ASSIGNMENT": "編輯指派" + }, + "STATUS": { + "CLOSED": "關閉", + "OPEN": "開啟" + }, + "WATCHERS": { + "ADD": "新增監督者", + "TITLE": "監督者", + "DELETE": "已刪除監督者", + "TITLE_LIGHTBOX_DELETE_WARTCHER": "刪除監督者" + }, + "CUSTOM_ATTRIBUTES": { + "CUSTOM_FIELDS": "客製化欄位", + "SAVE": "儲存客製化欄位", + "EDIT": "編輯客製化欄位", + "DELETE": "刪除客製屬性", + "CONFIRM_DELETE": "記得這個客制欄位的數值都將被刪除
你確定要繼續嗎" + }, + "FILTERS": { + "TITLE": "過濾器", + "INPUT_PLACEHOLDER": "主旨或參考", + "TITLE_ACTION_FILTER_BUTTON": "搜尋", + "BREADCRUMB_TITLE": "回到類別", + "BREADCRUMB_FILTERS": "過濾器", + "BREADCRUMB_STATUS": "狀態" + }, + "WYSIWYG": { + "H1_BUTTON": "第一層標頭 ", + "H1_SAMPLE_TEXT": "你的頭銜 ", + "H2_BUTTON": "第二層標頭 ", + "H2_SAMPLE_TEXT": "你的頭銜 ", + "H3_BUTTON": "第三標頭", + "H3_SAMPLE_TEXT": "你的頭銜", + "BOLD_BUTTON": "粗體字", + "BOLD_BUTTON_SAMPLE_TEXT": "你的文字在此", + "ITALIC_BUTTON": "斜體字", + "ITALIC_SAMPLE_TEXT": "你的文字在此", + "STRIKE_BUTTON": "刪除線", + "STRIKE_SAMPLE_TEXT": "你的文字在此", + "BULLETED_LIST_BUTTON": "次序列表", + "BULLETED_LIST_SAMPLE_TEXT": "你的文字在此", + "NUMERIC_LIST_BUTTON": "列號清單", + "NUMERIC_LIST_SAMPLE_TEXT": "你的文字在此 ", + "PICTURE_BUTTON": "圖片", + "PICTURE_SAMPLE_TEXT": "對照圖片的說明文", + "LINK_BUTTON": "連結", + "LINK_SAMPLE_TEXT": "文字連結在此", + "QUOTE_BLOCK_BUTTON": "引言區塊", + "QUOTE_BLOCK_SAMPLE_TEXT": "你的文字在此", + "CODE_BLOCK_BUTTON": "原始碼區塊", + "CODE_BLOCK_SAMPLE_TEXT": "你的文字在此", + "PREVIEW_BUTTON": "預視 ", + "EDIT_BUTTON": "編輯", + "MARKDOWN_HELP": "Markdown 語法協助" + }, + "PERMISIONS_CATEGORIES": { + "SPRINTS": { + "NAME": "衝刺任務", + "VIEW_SPRINTS": "檢視衝刺任務 ", + "ADD_SPRINTS": "增加衝刺任務", + "MODIFY_SPRINTS": "修正衝刺任務", + "DELETE_SPRINTS": "刪除衝刺任務" + }, + "USER_STORIES": { + "NAME": "使用者故事", + "VIEW_USER_STORIES": "檢視使用者故事", + "ADD_USER_STORIES": "新增使用者故事", + "MODIFY_USER_STORIES": "修正使用者故事", + "DELETE_USER_STORIES": "刪除使用者故事" + }, + "TASKS": { + "NAME": "任務 ", + "VIEW_TASKS": "檢視任務 ", + "ADD_TASKS": "新增任務 ", + "MODIFY_TASKS": "修正任務 ", + "DELETE_TASKS": "刪除任務" + }, + "ISSUES": { + "NAME": "問題 ", + "VIEW_ISSUES": "檢視問題 ", + "ADD_ISSUES": "新增問題 ", + "MODIFY_ISSUES": "修正議題 ", + "DELETE_ISSUES": "刪除問題 " + }, + "WIKI": { + "NAME": "維基", + "VIEW_WIKI_PAGES": "檢視維基頁", + "ADD_WIKI_PAGES": "新增維基頁", + "MODIFY_WIKI_PAGES": "修正維基頁", + "DELETE_WIKI_PAGES": "刪除維基頁 ", + "VIEW_WIKI_LINKS": "檢視維基連結", + "ADD_WIKI_LINKS": "新增維基連結", + "DELETE_WIKI_LINKS": "刪除維基連結" + } + } + }, + "AUTH": { + "INVITED_YOU": "已邀請您加入此專案", + "NOT_REGISTERED_YET": "還沒註冊嗎?", + "REGISTER": "註冊", + "CREATE_ACCOUNT": "在此建立您的免費帳號" + }, + "ATTACHMENT": { + "SECTION_NAME": "附件", + "TITLE": "{{ fileName }} 上傳於 {{ date }}", + "DESCRIPTION": "輸入一段簡短描述", + "DEPRECATED": "(deprecated)", + "DEPRECATED_FILE": "棄用?", + "ADD": "加入新附件 <%- maxFileSizeMsg %>", + "MAX_FILE_SIZE": "[Max. size: {{maxFileSize}}]", + "SHOW_DEPRECATED": "+ 顯示棄用的附件", + "HIDE_DEPRECATED": "+ 隱藏棄用的附件", + "COUNT_DEPRECATED": "({{ counter }} deprecated)", + "MAX_UPLOAD_SIZE": "上傳檔案最大容量限制 {{maxFileSize}}", + "DATE": "DD MMM YYYY [at] hh:mm", + "ERROR_UPLOAD_ATTACHMENT": "無法成功上傳 '{{fileName}}'. {{errorMessage}}", + "TITLE_LIGHTBOX_DELETE_ATTACHMENT": "刪除附件....", + "MSG_LIGHTBOX_DELETE_ATTACHMENT": "附件 '{{fileName}}'", + "ERROR_DELETE_ATTACHMENT": "無法刪除: {{errorMessage}}", + "FIELDS": { + "IS_DEPRECATED": "被棄用" + } + }, + "PAGINATION": { + "PREVIOUS": "Prev", + "NEXT": "下一個" + }, + "ADMIN": { + "COMMON": { + "TITLE_ACTION_EDIT_VALUE": "編輯數值", + "TITLE_ACTION_DELETE_VALUE": "删除值" + }, + "HELP": "需要幫助嗎?看看我們的支援頁面吧!", + "PROJECT_DEFAULT_VALUES": { + "TITLE": "預設值", + "SUBTITLE": "將所有選項設為預設值" + }, + "MEMBERSHIPS": { + "TITLE": "管理成員", + "ADD_BUTTON": "+ 新成員", + "ADD_BUTTON_TITLE": "增加新成員" + }, + "PROJECT_EXPORT": { + "TITLE": "匯出", + "SUBTITLE": "匯出你的專案以備份,或以此為基礎來建立一個新的。", + "EXPORT_BUTTON": "匯出", + "EXPORT_BUTTON_TITLE": "匯出你的專案", + "LOADING_TITLE": "傾倒檔案正在生成中", + "DUMP_READY": "你注入的檔案已完成", + "LOADING_MESSAGE": "請勿關閉本頁", + "ASYNC_MESSAGE": "準備好後,我們會送給 你一封電子郵件", + "SYNC_MESSAGE": "如果未能自動下載,
請點選此處 . ", + "ERROR": "我們的系統無法製作你的滙出資料,請再試一次 ", + "ERROR_BUSY": "抱歉系統繁忙中,請稍後再試試 ", + "ERROR_MESSAGE": "我們的系統在生成你的傾倒時遇到一些問題: {{message}}" + }, + "MODULES": { + "TITLE": "模組", + "ENABLE": "啟用", + "DISABLE": "停用", + "BACKLOG": "待辦任務優先表", + "BACKLOG_DESCRIPTION": "管理你的 User Story 讓接下來的及優先的工作能被有條理地檢視 ", + "KANBAN": "Kanban(看板)", + "KANBAN_DESCRIPTION": "在此看板上組織你的專案", + "ISSUES": "問題 ", + "ISSUES_DESCRIPTION": "追踪系統錯誤問題強化你的專案,不要錯過任何事 ", + "WIKI": "維基", + "WIKI_DESCRIPTION": "新增,修正或是刪除與他人合作的內容。這裏正是專案文件記錄區", + "MEETUP": "符合", + "MEETUP_DESCRIPTION": "選擇你的視訊系統。有些開發者需要面對面接觸", + "SELECT_VIDEOCONFERENCE": "選擇一個視訊會議系統 ", + "SALT_CHAT_ROOM": "你可以把聊天室名稱加上salt code亂數密碼 " + }, + "PROJECT_PROFILE": { + "PAGE_TITLE": "專案檔案 - {{sectionName}} - {{projectName}}", + "PROJECT_DETAILS": "專案細節", + "PROJECT_NAME": "專案名稱", + "PROJECT_SLUG": "專案代稱", + "NUMBER_SPRINTS": "衝刺任務數目 ", + "NUMBER_US_POINTS": "使用者故事點數數目", + "TAGS": "標籤", + "DESCRIPTION": "描述", + "PUBLIC_PROJECT": "公開專案", + "PRIVATE_PROJECT": "不公開專案", + "DELETE": "刪除此專案" + }, + "REPORTS": { + "TITLE": "Reports", + "SUBTITLE": "以 CSV 格式匯出你的專案資料,並製作你的專屬報告", + "DESCRIPTION": "下載CSV檔案或是複製這個生成的網址到你愛用的文字編輯器或電子表格上製作自己的專案檔案資料報告。你可能輕易地視覺化或分析這些資料。", + "HELP": "使用者故事預設欄位", + "REGENERATE_TITLE": "改變網址", + "REGENERATE_SUBTITLE": "你將要改變CSV資料的連結網址,之前的網址將失效。你確定要這樣做嗎?" + }, + "CSV": { + "SECTION_TITLE_US": "使用者故事報告", + "SECTION_TITLE_TASK": "任務報告", + "SECTION_TITLE_ISSUE": "問題報告", + "DOWNLOAD": "下戴CSV檔案", + "URL_FIELD_PLACEHOLDER": "再次產生CSV 網址", + "TITLE_REGENERATE_URL": "再次產生CSV 網址", + "ACTION_GENERATE_URL": "產生網址", + "ACTION_REGENERATE": "再次產生" + }, + "CUSTOM_FIELDS": { + "TITLE": "客製化欄位", + "SUBTITLE": "指定使用者故事,任務與問題一些客製化欄位", + "US_DESCRIPTION": "使用者客製欄位", + "US_ADD": "在使用者故事中加入客制欄位", + "TASK_DESCRIPTION": "任務客製化欄位", + "TASK_ADD": "在任務中加入客制欄位", + "ISSUE_DESCRIPTION": "問題客製化欄位", + "ISSUE_ADD": "在問題中加入客制欄位" + }, + "PROJECT_VALUES": { + "APP_TITLE": "專案數值- {{sectionName}} - {{projectName}}", + "REPLACEMENT": "所有此數值物品將改成", + "ERROR_DELETE_ALL": "你不能刪除所有數值" + }, + "PROJECT_VALUES_POINTS": { + "TITLE": "使用者故事點數", + "SUBTITLE": "指定你的使用者故事點數可能預估為", + "ACTION_ADD": "增加點數" + }, + "PROJECT_VALUES_PRIORITIES": { + "TITLE": "問題優先性", + "SUBTITLE": "指明你將遇到的問題優先程度", + "ACTION_ADD": "Add new priority" + }, + "PROJECT_VALUES_SEVERITIES": { + "TITLE": "問題急迫性", + "SUBTITLE": "指明你將遇到問題的嚴重程度", + "ACTION_ADD": "Add new severity" + }, + "PROJECT_VALUES_STATUS": { + "TITLE": "狀態", + "SUBTITLE": "指明你的使用者故事狀態,任務以及經歷問題 ", + "US_TITLE": "使用者故事狀態", + "TASK_TITLE": "任務狀態", + "ISSUE_TITLE": "問題狀態" + }, + "PROJECT_VALUES_TYPES": { + "TITLE": "類型", + "SUBTITLE": "指定你的問題類型可能是", + "ISSUE_TITLE": "問題類型", + "ACTION_ADD": "Add new type" + }, + "ROLES": { + "SECTION_NAME": "角色- {{projectName}}", + "WARNING_NO_ROLE": "注意,你的專案中無角色可以評估使用者故事的點數", + "HELP_ROLE_ENABLED": "當啟動時,被指派此角色的成員將可以評估使用者故事點數", + "COUNT_MEMBERS": "{{ role.members_count }} 這類角色的成員", + "TITLE_DELETE_ROLE": "删除角色", + "REPLACEMENT_ROLE": "和此角色有關的使用者都將遭移除 ", + "WARNING_DELETE_ROLE": "小心, 所有角色的估算都將會移除", + "ERROR_DELETE_ALL": "你不能刪除所有數值", + "EXTERNAL_USER": "外部使用者" + }, + "THIRD_PARTIES": { + "SECRET_KEY": "Secret key", + "PAYLOAD_URL": "有效載荷網址", + "VALID_IPS": "有效來源IP(請用逗點分開)" + }, + "BITBUCKET": { + "SECTION_NAME": "Bitbucket", + "APP_TITLE": "Bitbucket - {{projectName}}", + "INFO_VERIFYING_IP": "Bitbucket要求不指派因此最佳確認方式為IP位置來源。如果此處空白,表示IP未有效確核。" + }, + "GITLAB": { + "SECTION_NAME": "Gitlob", + "APP_TITLE": "Gitlab - {{projectName}}", + "INFO_VERIFYING_IP": "GitHub要求不指派因此最佳確認方式為IP位置來源。如果此處空白,表示IP未有效確核。" + }, + "GITHUB": { + "SECTION_NAME": "Githun", + "APP_TITLE": "Gitlab - {{projectName}}" + }, + "WEBHOOKS": { + "APP_TITLE": "Webhooks- {{projectName}}", + "SECTION_NAME": "網頁觸發 ", + "SUBTITLE": "網頁觸發通知關於Taiga事件的外部服務,例如評論,使用者故事等。 ", + "ADD_NEW": "新增一個網頁觸發 ", + "TYPE_NAME": "鍵入服務名稱 ", + "TYPE_PAYLOAD_URL": "鍵入服務有效載荷網址", + "TYPE_SERVICE_SECRET": "鍵入服務密碼鑰匙 ", + "SAVE": "儲存網頁觸發 ", + "CANCEL": "取消網頁觸發 ", + "SHOW_HISTORY": "(顯示記錄)", + "TEST": "測試網頁觸發 ", + "EDIT": "編輯網頁觸發 ", + "DELETE": "刪除網頁觸發 ", + "REQUEST": "要求", + "RESEND_REQUEST": "重送出要求", + "HEADERS": "標頭 ", + "PAYLOAD": "有效載荷", + "RESPONSE": "回應", + "DATE": "DD MMM YYYY [at] hh:mm", + "ACTION_HIDE_HISTORY": "(藏記錄)", + "ACTION_HIDE_HISTORY_TITLE": "藏記錄細節", + "ACTION_SHOW_HISTORY": "(顯示記錄)", + "ACTION_SHOW_HISTORY_TITLE": "顯示記錄細節", + "WEBHOOK_NAME": "網頁觸發 '{{name}}'" + }, + "CUSTOM_ATTRIBUTES": { + "ADD": "加入客製化欄位", + "EDIT": "編輯客製化欄位", + "DELETE": "刪除客製欄位", + "SAVE_TITLE": "儲存客製化欄位", + "CANCEL_TITLE": "取消創建", + "SET_FIELD_NAME": "設定你的客制欄位名稱 ", + "SET_FIELD_DESCRIPTION": "設定你客製化欄位的文字描述", + "ACTION_UPDATE": "更新客製化欄位", + "ACTION_CANCEL_EDITION": "取消編輯 " + }, + "MEMBERSHIP": { + "COLUMN_MEMBER": "成員", + "COLUMN_ADMIN": "管理者", + "COLUMN_ROLE": "角色", + "COLUMN_STATUS": "狀態", + "STATUS_ACTIVE": "活躍 ", + "STATUS_PENDING": "待辦中", + "DELETE_MEMBER": "刪除成員", + "SUCCESS_SEND_INVITATION": "我們已再次發出邀請信給'{{email}}'. ", + "ERROR_SEND_INVITATION": "我們未送出邀請 ", + "SUCCESS_DELETE": "已刪除 {{message}}.", + "ERROR_DELETE": "我們無法刪除 {{message}}.", + "DEFAULT_DELETE_MESSAGE": "邀請 {{email}}" + }, + "DEFAULT_VALUES": { + "LABEL_POINTS": "點數選擇器預設值", + "LABEL_US": "使用者故事狀態選擇器預設值", + "LABEL_TASK_STATUS": "任務狀態選擇器預設值", + "LABEL_PRIORITY": "優先選擇器預設值", + "LABEL_SEVERITY": "急迫性選擇器預設值", + "LABEL_ISSUE_TYPE": "問題類型選擇器預設值", + "LABEL_ISSUE_STATUS": "問題狀態選擇器預設值" + }, + "STATUS": { + "PLACEHOLDER_WRITE_STATUS_NAME": "為此新狀態命名" + }, + "TYPES": { + "PLACEHOLDER_WRITE_NAME": "為此新要素命名" + }, + "US_STATUS": { + "ACTION_ADD_STATUS": "增加新狀態", + "IS_ARCHIVED_COLUMN": "是否歸檔", + "WIP_LIMIT_COLUMN": "WIP限制", + "PLACEHOLDER_WRITE_NAME": "為此新狀態命名" + }, + "MENU": { + "TITLE": "管理者", + "PROJECT": "專案", + "ATTRIBUTES": "屬性", + "MEMBERS": "成員", + "PERMISSIONS": "權限", + "INTEGRATIONS": "整合", + "PLUGINS": "外掛" + }, + "SUBMENU_PROJECT_ATTRIBUTES": { + "TITLE": "Attributes" + }, + "SUBMENU_PROJECT_VALUES": { + "STATUS": "狀態", + "POINTS": "點數", + "PRIORITIES": "優先性", + "SEVERITIES": "急迫性", + "TYPES": "類型", + "CUSTOM_FIELDS": "客製化欄位" + }, + "SUBMENU_PROJECT_PROFILE": { + "TITLE": "專案檔案" + }, + "SUBMENU_ROLES": { + "TITLE": "角色", + "ACTION_NEW_ROLE": "+ 新角色", + "TITLE_ACTION_NEW_ROLE": "新增角色" + }, + "SUBMENU_THIDPARTIES": { + "TITLE": "服務 " + } + }, + "PROJECT": { + "WELCOME": "歡迎", + "SECTION_PROJECTS": "專案", + "STATS": { + "PROJECT": "專案
點數", + "DEFINED": "已定義
點數", + "ASSIGNED": "已指派
點數", + "CLOSED": "已關閉
點數" + }, + "SECTION": { + "SEARCH": "搜尋", + "BACKLOG": "待辦任務優先表", + "KANBAN": "Kanban(看板)", + "ISSUES": "問題 ", + "WIKI": "維基", + "TEAM": "團隊", + "MEETUP": "符合", + "ADMIN": "管理者" + }, + "NAVIGATION": { + "SECTION_TITLE": "你的專案", + "PLACEHOLDER_SEARCH": "搜尋", + "ACTION_CREATE_PROJECT": "創建專案", + "TITLE_ACTION_IMPORT": "滙入專案", + "TITLE_PRVIOUS_PROJECT": "顯示過去專案", + "TITLE_NEXT_PROJECT": "顯示下一個任務" + }, + "IMPORT": { + "TITLE": "滙入專案中", + "UPLOADING_FILE": "Uploading dump file", + "DESCRIPTION": "這個過桯要花點時間,請保持视窗開啟", + "ASYNC_IN_PROGRESS_TITLE": "我們的工程師對你的專案很重要哦", + "ASYNC_IN_PROGRESS_MESSAGE": "這個過程要花上一點時間
當弄好時我們會發給你一封郵件", + "UPLOAD_IN_PROGRESS_MESSAGE": "已上傳 {{totalSize}}中的{{uploadedSize}} ", + "ERROR": "系統在滙進你倒入的資料時遇上一些問題,請再試一次", + "ERROR_TOO_MANY_REQUEST": "抱歉系統繁忙中,請稍後再試試 ", + "ERROR_MESSAGE": "我們的系統無法滙入你的資料", + "ERROR_MAX_SIZE_EXCEEDED": "'{{fileName}}' ({{fileSize}}) 超過系統容量上限, 請重傳小一點的檔案 ({{maxFileSize}})", + "SYNC_SUCCESS": "你的專案已成功滙入" + } + }, + "LIGHTBOX": { + "DELETE_ACCOUNT": { + "SECTION_NAME": "刪除Taiga帳戶", + "CONFIRM": "你確定要刪除Taiga帳戶嗎?", + "SUBTITLE": "我們會想念你:-(", + "NEWSLETTER_LABEL_TEXT": "I don't wanna receive your newsletter anymore" + }, + "DELETE_PROJECT": { + "TITLE": "刪除專案", + "QUESTION": "你確定要刪除這個專案嗎?", + "SUBTITLE": "所有專案資料 (US/Tasks/Issues/Sprints/WikiPages) 將會遺失! :-(", + "CONFIRM": "是的,我很確定" + }, + "ASSIGNED_TO": { + "SELECT": "選擇要旨派給", + "SEARCH": "搜尋使用者" + }, + "ADD_MEMBER": { + "TITLE": "新成員", + "HELP_TEXT": "如果用戶已註冊Taiga帳戶,他們會自動被加入。否則他們會收到一封加入的邀請信" + }, + "CREATE_ISSUE": { + "TITLE": "新增問題 " + }, + "FEEDBACK": { + "TITLE": "告訴我們你的故事", + "COMMENT": "系統錯誤,有改進建議有樂趣,或者是你使用Taiga 上的惡夢?", + "ACTION_SEND": "送出回饋 " + }, + "SEARCH": { + "TITLE": "搜尋", + "PLACEHOLDER_SEARCH": "你在找什麼?" + }, + "ADD_EDIT_SPRINT": { + "TITLE": "新衝刺任務 ", + "PLACEHOLDER_SPRINT_NAME": "衝刺任務名稱", + "PLACEHOLDER_SPRINT_START": "預估開始", + "PLACEHOLDER_SPRINT_END": "預估結束", + "ACTION_DELETE_SPRINT": "你確定要刪除這個衝刺任務嗎?", + "TITLE_ACTION_DELETE_SPRINT": "刪除衝刺任務", + "LAST_SPRINT_NAME": "最後衝刺任務 {{lastSprint}} ;-) " + }, + "CREATE_EDIT_TASK": { + "TITLE": "新任務 ", + "PLACEHOLDER_SUBJECT": "任務主旨", + "PLACEHOLDER_STATUS": "任務狀態", + "OPTION_UNASSIGNED": "未指派", + "PLACEHOLDER_SHORT_DESCRIPTION": "輸入一段簡短描述", + "ACTION_EDIT": "編輯任務 " + }, + "CREATE_EDIT_US": { + "TITLE": "新使用者故事", + "PLACEHOLDER_DESCRIPTION": "請加上一些描述文字以幫助其它人易了解此使用者故事", + "NEW_US": "新使用者故事", + "EDIT_US": "編輯使用者故事" + }, + "DELETE_SPRINT": { + "TITLE": "刪除衝刺任務" + }, + "CREATE_MEMBER": { + "PLACEHOLDER_INVITATION_TEXT": "(非必要) 加上一段私人文字在邀請信,告訴你的新成員一些好事 ;-)", + "PLACEHOLDER_TYPE_EMAIL": "輸入一個電郵地址" + } + }, + "US": { + "SECTION_NAME": "User story details", + "LINK_TASKBOARD": "任務板", + "TITLE_LINK_TASKBOARD": "到任務板去", + "TOTAL_POINTS": "全部", + "ADD": "+新增使用者故事", + "ADD_BULK": "批次加入新使用者故事", + "PROMOTED": "此使用者故事已提昇成問題:", + "TITLE_LINK_GO_TO_ISSUE": "到問題 ", + "EXTERNAL_REFERENCE": "此使用者故事創造者是", + "GO_TO_EXTERNAL_REFERENCE": "回到一開始", + "BLOCKED": "這個使用者故事已被封鎖", + "PREVIOUS": "之前的使用者故事", + "NEXT": "下一個使用者故事", + "TITLE_DELETE_ACTION": "刪除使用者故事", + "LIGHTBOX_TITLE_BLOKING_US": "封鎖中的使用者故事", + "TASK_COMPLETED": "{{totalClosedTasks}}/{{totalTasks}} 任務完成", + "ASSIGN": "指派使用者故事", + "NOT_ESTIMATED": "無預估", + "TOTAL_US_POINTS": "全部使用者故事點數", + "FIELDS": { + "TEAM_REQUIREMENT": "團隊要求", + "CLIENT_REQUIREMENT": "客戶要求", + "FINISH_DATE": "完成日期" + } + }, + "COMMENTS": { + "DELETED_INFO": "評論被 {{user}} 於 {{date}}刪除 ", + "TITLE": "評論", + "COMMENT": "評論", + "TYPE_NEW_COMMENT": "在此輸入一個新的評論", + "SHOW_DELETED": "顯示遭刪除的評論 ", + "HIDE_DELETED": "隱藏已刪除之評論 ", + "RESTORE": "恢復原評論 " + }, + "ACTIVITY": { + "SHOW_ACTIVITY": "顯示動態", + "DATETIME": "DD MMM YYYY HH:mm", + "SHOW_MORE": "+ 顯示過去條目 ({{showMore}} more)", + "TITLE": "動態", + "REMOVED": "已移除", + "ADDED": "已加入", + "US_POINTS": "使用者故事點數({{name}})", + "NEW_ATTACHMENT": "新附件", + "DELETED_ATTACHMENT": "已刪除附件", + "UPDATED_ATTACHMENT": "更新附件 {{filename}}", + "DELETED_CUSTOM_ATTRIBUTE": "刪除客製屬性", + "SIZE_CHANGE": "使 {size, plural, one{change} 其它{changes}}", + "VALUES": { + "YES": "yes", + "NO": "no", + "EMPTY": "空白", + "UNASSIGNED": "未指派" + }, + "FIELDS": { + "SUBJECT": "主旨", + "NAME": "名稱 ", + "DESCRIPTION": "描述", + "CONTENT": "內容", + "STATUS": "狀態", + "IS_CLOSED": "關閉中", + "FINISH_DATE": "完成日期", + "TYPE": "類型", + "PRIORITY": "優先性", + "SEVERITY": "急迫性", + "ASSIGNED_TO": "指派給 ", + "WATCHERS": "監督者", + "MILESTONE": "衝刺任務", + "USER_STORY": "使用者故事", + "PROJECT": "專案", + "IS_BLOCKED": "封鎖", + "BLOCKED_NOTE": "已封鎖之筆記", + "POINTS": "點數", + "CLIENT_REQUIREMENT": "客戶要求", + "TEAM_REQUIREMENT": "團隊要求", + "IS_IOCAINE": "負予全新任務", + "TAGS": "標籤", + "ATTACHMENTS": "附件", + "IS_DEPRECATED": "被棄用", + "ORDER": "次序", + "BACKLOG_ORDER": "待辦任務先後次序", + "SPRINT_ORDER": "衝刺任務次序", + "KANBAN_ORDER": "kanban看板次序", + "TASKBOARD_ORDER": "任務板次序", + "US_ORDER": "使用者故事次序" + } + }, + "BACKLOG": { + "SECTION_NAME": "待辦任務優先表", + "MOVE_US_TO_CURRENT_SPRINT": "移到目前的 Sprint", + "SHOW_FILTERS": "顯示過濾器", + "SHOW_TAGS": "顯示標籤 (Tag)", + "EMPTY": "你的待辦任務優先表已清空", + "CREATE_NEW_US": "創建一個新的使用者故事", + "CREATE_NEW_US_EMPTY_HELP": "你可以創建一個新使用者故事", + "EXCESS_OF_POINTS": "超過的點數", + "PENDING_POINTS": "待核點數", + "CLOSED_POINTS": "關閉", + "COMPACT_SPRINT": "濃縮衝刺點數", + "GO_TO_TASKBOARD": "到任務板 {{spring.name}}", + "EDIT_SPRINT": "編輯衝刺任務 ", + "TOTAL_POINTS": "全部", + "STATUS_NAME": "狀態名稱 ", + "SORTABLE_FILTER_ERROR": "當過濾器開啟時,無法放入待辦任務優先表", + "DOOMLINE": "專案規模 [Doomline]", + "CHART": { + "XAXIS_LABEL": "衝刺任務", + "YAXIS_LABEL": "點數", + "OPTIMAL": "最佳給衝刺任務待辦點數 {{xval}} 應是 {{yval}}", + "REAL": "任務衝刺實際待辦點數 {{xval}} 為 {{yval}}", + "INCREMENT_TEAM": "團隊要求的任務衝刺逐步新增點數 {{xval}} 為 {{yval}}", + "INCREMENT_CLIENT": "客戶要求的任務衝刺逐步新增點數 {{xval}} 為 {{yval}}" + }, + "TAGS": { + "TOGGLE": "Toggle tags visibility", + "SHOW": "顯示標籤", + "HIDE": "隱藏標籤" + }, + "TABLE": { + "COLUMN_US": "使用者故事", + "TITLE_COLUMN_POINTS": "選擇檢示每個角色" + }, + "SPRINT_SUMMARY": { + "TOTAL_POINTS": "全部
點數", + "COMPLETED_POINTS": "已完成
點數", + "OPEN_TASKS": "開啟
任務", + "CLOSED_TASKS": "已關閉
任務", + "IOCAINE_DOSES": "毒物(全新任務挑戰)
劑量", + "SHOW_STATISTICS_TITLE": "顯示統計" + }, + "SUMMARY": { + "PROJECT_POINTS": "專案
點數", + "DEFINED_POINTS": "已定義
點數", + "CLOSED_POINTS": "已關閉
點數", + "POINTS_PER_SPRINT": "點數 /
衝刺任務" + }, + "FILTERS": { + "TOGGLE": "Toggle filters visibility", + "TITLE": "過濾器", + "REMOVE": "移除過濾器", + "HIDE": "Hide Filters", + "SHOW": "顯示過濾器", + "FILTER_CATEGORY_STATUS": "狀態", + "FILTER_CATEGORY_TAGS": "標籤" + }, + "SPRINTS": { + "TITLE": "衝刺任務", + "DATE": "DD MMM YYYY", + "LINK_TASKBOARD": "衝刺任務板", + "TITLE_LINK_TASKBOARD": "到任務板 {{spring.name}}", + "NUMBER_SPRINTS": "
衝刺任務 ", + "TITLE_ACTION_NEW_SPRINT": "+ 新衝刺任務 ", + "ACTION_NEW_SPRINT": "+ 新衝刺任務 ", + "ACTION_SHOW_CLOSED_SPRINTS": "顯示關閉衝刺任務", + "ACTION_HIDE_CLOSED_SPRINTS": "隱藏衝刺任務" + } + }, + "ERROR": { + "TEXT1": "系統出了一點問題,工程師正在搶修中", + "TEXT2": "請再重新載入", + "NOT_FOUND": "找不到", + "NOT_FOUND_TEXT": "Error 404,你要找的網頁不存在,你可以稍後再回來TAIGA首頁,看看是否能再次找到要找的東西。", + "PERMISSION_DENIED": "無此權限", + "PERMISSION_DENIED_CODE": "Error 403.", + "VERSION_ERROR": "Taiga某人之前更改了這個,而我們的工程師無法再做改變。請重新載入頁面來使用你的更新(之前設定將消失)" + }, + "TASKBOARD": { + "SECTION_NAME": "任務板", + "TITLE_ACTION_ADD": "增加新任務 ", + "TITLE_ACTION_ADD_BULK": "批次加入新任務 ", + "TITLE_ACTION_ASSIGN": "指派任務 ", + "TITLE_ACTION_EDIT": "結束任務 ", + "TABLE": { + "COLUMN": "使用者故事", + "TITLE_ACTION_FOLD": "隱藏欄位", + "TITLE_ACTION_UNFOLD": "未隱藏欄位", + "TITLE_ACTION_FOLD_ROW": "隱藏列數", + "TITLE_ACTION_UNFOLD_ROW": "未隱藏列數", + "FIELD_POINTS": "點數", + "ROW_UNASSIGED_TASKS_TITLE": "未指派的任務" + }, + "CHARTS": { + "XAXIS_LABEL": "天數", + "YAXIS_LABEL": "點數", + "OPTIMAL": "一天最適待辦點數{formattedDate}應為{{roundedValue}}", + "REAL": "一天真實的待辦點數 {{formattedDate}} is {{roundedValue}}", + "DATE": "DD MMM YYYY" + } + }, + "TASK": { + "SECTION_NAME": "Task details", + "LINK_TASKBOARD": "任務板", + "TITLE_LINK_TASKBOARD": "到任務板去", + "PLACEHOLDER_SUBJECT": "鍵入新任務主旨", + "TITLE_SELECT_STATUS": "狀態名稱 ", + "OWNER_US": "這任務屬於", + "TITLE_LINK_GO_OWNER": "到使用者故事", + "ORIGIN_US": "此任務創造者是", + "TITLE_LINK_GO_ORIGIN": "到使用者故事", + "BLOCKED": "這任務已被封鎖", + "PREVIOUS": "之前的任務 ", + "NEXT": "下一個任務 ", + "TITLE_DELETE_ACTION": "刪除任務", + "LIGHTBOX_TITLE_BLOKING_TASK": "封鎖中的任務 ", + "FIELDS": { + "MILESTONE": "衝刺任務", + "USER_STORY": "使用者故事", + "IS_IOCAINE": "負予全新任務" + }, + "ACTION_IOCAINE": "挑戰全新任務", + "TITLE_ACTION_IOCAINE": "感到任務的不勘負荷?確定其它人知道此狀況在編輯任務時點選此「毒藥鍵」。這種致命毒物如果長期吸食微量,最後可能免疫。因此你最好偶而做點出奇的挑戰。" + }, + "NOTIFICATION": { + "OK": "一切還好", + "WARNING": "哇,有狀況發生", + "WARNING_TEXT": "很抱歉你的變動並未成功儲存", + "SAVED": "我們系統已儲存你所有變動", + "CLOSE": "關閉通知", + "MAIL": "透過郵件通知", + "ASK_DELETE": "你確定要刪除嗎?" + }, + "CANCEL_ACCOUNT": { + "TITLE": "取消您的帳戶", + "SUBTITLE": "很遺憾你要離開Taiga,希望你喜歡這段時光:", + "PLACEHOLDER_INPUT_TOKEN": "取消帳戶代碼 ", + "ACTION_LEAVING": "是的,我要走了", + "SUCCESS": "我們系統已移附你的帳戶" + }, + "CHANGE_EMAIL_FORM": { + "TITLE": "變更電子郵件", + "SUBTITLE": "確認你的電子郵件要更新", + "PLACEHOLDER_INPUT_TOKEN": "變更電郵代碼 ", + "ACTION_CHANGE_EMAIL": "變更電郵地址", + "SUCCESS": "我們系統已更新你的電子郵件" + }, + "CHANGE_PASSWORD_RECOVERY_FORM": { + "TITLE": "創建新Taiga通過", + "SUBTITLE": "你也許該吃點鐵質豐富的食物,它對你的大腦有益處:p", + "PLACEHOLDER_RECOVER_PASSWORD_TOKEN": "回復密碼代碼 ", + "LINK_NEED_TOKEN": "需要一個?", + "TITLE_LINK_NEED_TOKEN": "你是否需要代碼來恢復你所忘記的密碼?", + "PLACEHOLDER_NEW_PASSWORD": "新密碼 ", + "PLACEHOLDER_RE_TYPE_NEW_PASSWORD": "重新輸入新密碼", + "ACTION_RESET_PASSWORD": "重設密碼 ", + "SUCCESS": "系統已儲存你的新密碼
試試 用它登入 " + }, + "FORGOT_PASSWORD_FORM": { + "TITLE": "你是否忘了密碼嗎", + "SUBTITLE": "輸入你的帳戶名稱或電子郵件以進行註冊", + "PLACEHOLDER_FIELD": "使用者名稱或電子郵件", + "ACTION_RESET_PASSWORD": "重設密碼 ", + "LINK_CANCEL": "不,請帶我回去,我記起來了", + "SUCCESS": "檢查你的收信箱
我們送出了一封信
裏面有設定你新電子郵件的相關指示", + "ERROR": "按我們的記錄,你尚未註冊" + }, + "LOGIN_COMMON": { + "HEADER": "我已登入Taiga", + "PLACEHOLDER_AUTH_NAME": "使用者名稱或電子郵件(注意大小寫)", + "LINK_FORGOT_PASSWORD": "忘記了?", + "TITLE_LINK_FORGOT_PASSWORD": "你忘了密碼嗎", + "ACTION_ENTER": "Enter", + "ACTION_SIGN_IN": "登入", + "PLACEHOLDER_AUTH_PASSWORD": "密碼(大小寫有別)" + }, + "LOGIN_FORM": { + "ERROR_AUTH_INCORRECT": "按我們的箹統記錄,你的帳戶名稱/電子郵件或密碼並不正確 ", + "ERROR_GENERIC": "根據系統,此處有錯誤", + "SUCCESS": "我們系統歡迎你加入Taiga" + }, + "INVITATION_LOGIN_FORM": { + "NOT_FOUND": "Ooops, 有點問題
我們的系統無法找到你的邀請信", + "SUCCESS": "你成功地加入此專案,歡迎來到 {{project_name}}", + "ERROR": "按我們的記錄,你尚未註冊或是未輸入有效的密碼 " + }, + "REGISTER_FORM": { + "TITLE": "註冊一個新的Taiga帳戶(免費 )", + "PLACEHOLDER_NAME": "選一個用戶帳號(注意大小寫)", + "PLACEHOLDER_FULL_NAME": "選取你的全名", + "PLACEHOLDER_EMAIL": "你的電子郵件", + "PLACEHOLDER_PASSWORD": "設定密碼(注意大小寫不同) ", + "ACTION_SIGN_UP": "註冊", + "TITLE_LINK_LOGIN": "登入", + "LINK_LOGIN": "你是否已註冊? 登入" + }, + "ISSUES": { + "LIST_SECTION_NAME": "問題 ", + "SECTION_NAME": "Issue details", + "ACTION_NEW_ISSUE": "+ 新問題 ", + "ACTION_PROMOTE_TO_US": "提昇到使用者故事", + "PLACEHOLDER_FILTER_NAME": "寫入過濾器名稱後按下enter ", + "PROMOTED": "此問題已提昇成使用者故事 ", + "EXTERNAL_REFERENCE": "此問題的提供者是", + "GO_TO_EXTERNAL_REFERENCE": "回到一開始", + "BLOCKED": "這個議題已被封鎖", + "TITLE_PREVIOUS_ISSUE": "之前的問題 ", + "TITLE_NEXT_ISSUE": "下一個問題 ", + "ACTION_DELETE": "删除議題 ", + "LIGHTBOX_TITLE_BLOKING_ISSUE": "封鎖中的問題", + "CONFIRM_PROMOTE": { + "TITLE": "將此問題提到使用者故事", + "MESSAGE": "你確定此問題要創建一個新的使用者故事?" + }, + "FILTERS": { + "TITLE": "過濾器", + "INPUT_SEARCH_PLACEHOLDER": "主旨或參考", + "TITLE_ACTION_SEARCH": "搜尋", + "ACTION_SAVE_CUSTOM_FILTER": "儲存為客製過濾器 ", + "BREADCRUMB": "過濾器", + "TITLE_BREADCRUMB": "過濾器", + "CATEGORIES": { + "TYPE": "類型", + "STATUS": "狀態", + "SEVERITY": "急迫性", + "PRIORITIES": "優先性", + "TAGS": "標籤", + "ASSIGNED_TO": "指派給 ", + "CREATED_BY": "由創建", + "CUSTOM_FILTERS": "客製過濾器 " + }, + "CONFIRM_DELETE": { + "TITLE": "刪除客製過濾器 ", + "MESSAGE": "預設過濾器 '{{customFilterName}}'" + } + }, + "TABLE": { + "COLUMNS": { + "TYPE": "類型", + "SEVERITY": "急迫性", + "PRIORITY": "優先性", + "SUBJECT": "主旨", + "STATUS": "狀態", + "CREATED": "已創建", + "ASSIGNED_TO": "指派給 " + }, + "TITLE_ACTION_CHANGE_STATUS": "改變狀態", + "TITLE_ACTION_ASSIGNED_TO": "指派給 ", + "EMPTY": { + "TITLE": "沒有問題回報:-)", + "SUBTITLE": "你有發現任何問題嗎", + "ACTION_CREATE_ISSUE": "創建一個新問題" + } + } + }, + "KANBAN": { + "SECTION_NAME": "Kanban(看板)", + "TITLE_ACTION_FOLD": "隱藏欄位", + "TITLE_ACTION_UNFOLD": "未隱藏欄位", + "TITLE_ACTION_FOLD_CARDS": "隱藏卡片", + "TITLE_ACTION_UNFOLD_CARDS": "未隱藏卡片", + "TITLE_ACTION_ADD_US": "新增使用者故事", + "TITLE_ACTION_ADD_BULK": "增加新批次", + "ACTION_SHOW_ARCHIVED": "顯示歸檔資料", + "ACTION_HIDE_ARCHIVED": "隱藏歸檔", + "HIDDEN_USER_STORIES": "此狀態下的使用者故事預設為隱藏", + "ARCHIVED": "你已歸檔", + "UNDO_ARCHIVED": "拖移 & 丟到未做" + }, + "SEARCH": { + "FILTER_USER_STORIES": "使用者故事", + "FILTER_ISSUES": "問題 ", + "FILTER_TASKS": "任務 ", + "FILTER_WIKI": "維基頁", + "PLACEHOLDER_SEARCH": "搜尋", + "TITLE_ACTION_SEARCH": "搜尋", + "EMPTY_TITLE": "依你搜尋標準並未找到任何東西", + "EMPTY_DESCRIPTION": "請試試上方某一個分頁或再搜尋一次" + }, + "TEAM": { + "SECTION_NAME": "團隊", + "APP_TITLE": "團隊- {{projectName}}", + "PLACEHOLDER_INPUT_SEARCH": "以全名搜尋", + "COLUMN_MR_WOLF": "問題解決高手", + "EXPLANATION_COLUMN_MR_WOLF": "已關閉議題 ", + "COLUMN_IOCAINE": "毒品吸食者(新領域任務挑戰)", + "EXPLANATION_COLUMN_IOCAINE": "毒物(新任務)劑量攝取", + "COLUMN_CERVANTES": "大文豪", + "EXPLANATION_COLUMN_CERVANTES": "已編輯之維基頁", + "COLUMN_BUG_HUNTER": "程式錯誤獵人", + "EXPLANATION_COLUMN_BUG_HUNTER": "問題回報", + "COLUMN_NIGHT_SHIFT": "熬夜工作", + "EXPLANATION_COLUMN_NIGHT_SHIFT": "任務關閉", + "COLUMN_TOTAL_POWER": "所有力量", + "EXPLANATION_COLUMN_TOTAL_POWER": "所有點數", + "SECTION_TITLE_TEAM": "團隊 >", + "SECTION_FILTER_ALL": "所有", + "CONFIRM_LEAVE_PROJECT": "你確定要退出這個專案嗎?", + "ACTION_LEAVE_PROJECT": "退出此專案" + }, + "CHANGE_PASSWORD": { + "SECTION_NAME": "改變密碼 ", + "FIELD_CURRENT_PASSWORD": "現用密碼 ", + "PLACEHOLDER_CURRENT_PASSWORD": "你目前的密碼(如果你未有密碼,此處請空白)", + "FIELD_NEW_PASSWORD": "新密碼 ", + "PLACEHOLDER_NEW_PASSWORD": "輸入新密碼", + "FIELD_RETYPE_PASSWORD": "重新輸入新密碼", + "PLACEHOLDER_RETYPE_PASSWORD": "重新輸入新密碼", + "ERROR_PASSWORD_MATCH": "密碼不符" + }, + "USER_SETTINGS": { + "AVATAR_MAX_SIZE": "[最大. 尺寸: {{maxFileSize}}] ", + "MENU": { + "SECTION_TITLE": "使用者設定", + "USER_PROFILE": "使用者設定檔案", + "CHANGE_PASSWORD": "更換密碼 ", + "EMAIL_NOTIFICATIONS": "電子郵件通知" + }, + "NOTIFICATIONS": { + "SECTION_NAME": "電子郵件通知", + "COLUMN_PROJECT": "專案", + "COLUMN_RECEIVE_ALL": "接收所有", + "COLUMN_ONLY_INVOLVED": "只有相關", + "COLUMN_NO_NOTIFICATIONS": "無通知", + "OPTION_ALL": "所有", + "OPTION_INVOLVED": "涉入", + "OPTION_NONE": "無" + }, + "POPOVER": { + "USER_PROFILE": "使用者設定檔案", + "CHANGE_PASSWORD": "更換密碼 ", + "NOTIFICATIONS": "通知", + "FEEDBACK": "回饋 ", + "TITLE_AVATAR": "使用者偏好" + } + }, + "USER_PROFILE": { + "IMAGE_HELP": "此圖片將被裁成80x80px.
", + "ACTION_CHANGE_IMAGE": "變更", + "ACTION_USE_GRAVATAR": "用戶大頭貼圖片", + "ACTION_DELETE_ACCOUNT": "刪除Taiga帳戶", + "CHANGE_EMAIL_SUCCESS": "檢查你的收信箱
我們送出了一封信
裏面有設定你新電子郵件的相關指示", + "CHANGE_PHOTO": "變更照片", + "FIELD": { + "USERNAME": "使用者名稱", + "EMAIL": "電子郵件", + "FULL_NAME": "全名", + "PLACEHOLDER_FULL_NAME": "你的全名", + "BIO": "簡介", + "PLACEHOLDER_BIO": "請自我介紹", + "LANGUAGE": "語言", + "LANGUAGE_DEFAULT": "-- 使用設預語言 -- " + } + }, + "WIZARD": { + "SECTION_TITLE_CHOOSE_TEMPLATE": "選擇外觀 ", + "CHOOSE_TEMPLATE_TEXT": "哪一個樣版最適合你的專案", + "SECTION_TITLE_CREATE_PROJECT": "創建專案", + "CREATE_PROJECT_TEXT": "新鮮與乾淨,太好了", + "PROGRESS_TEMPLATE_SELECTION": "外觀選擇", + "PROGRESS_NAME_DESCRIPTION": "名稱與描述" + }, + "WIKI": { + "DATETIME": "DD MMM YYYY HH:mm", + "PLACEHOLDER_PAGE": "編寫你的維基頁", + "REMOVE": "移除此維基頁 ", + "DELETE_LIGHTBOX_TITLE": "刪除維基頁", + "NAVIGATION": { + "SECTION_NAME": "連結", + "ACTION_ADD_LINK": "新增連結" + }, + "SUMMARY": { + "TIMES_EDITED": "次數
編輯 ", + "LAST_EDIT": "上次
編輯 ", + "LAST_MODIFICATION": "上回修改" + } + } +} \ No newline at end of file diff --git a/app/coffee/modules/locales.coffee b/app/modules/components/components.module.coffee similarity index 72% rename from app/coffee/modules/locales.coffee rename to app/modules/components/components.module.coffee index c5f75116..a714b61f 100644 --- a/app/coffee/modules/locales.coffee +++ b/app/modules/components/components.module.coffee @@ -1,7 +1,5 @@ ### -# Copyright (C) 2014 Andrey Antukh -# Copyright (C) 2014 Jesús Espino Garcia -# Copyright (C) 2014 David Barragán Merino +# Copyright (C) 2015 Taiga Agile LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as @@ -16,7 +14,7 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . # -# File: modules/locales.coffee +# File: components.module.coffee ### -module = angular.module("taigaLocales", []) +angular.module("taigaComponents", []) diff --git a/app/partials/admin/admin-membership-paginator.jade b/app/partials/admin/admin-membership-paginator.jade index 6d6a0aa0..742bdfac 100644 --- a/app/partials/admin/admin-membership-paginator.jade +++ b/app/partials/admin/admin-membership-paginator.jade @@ -2,7 +2,7 @@ ul.paginator <% if (showPrevious) { %> li.previous a(href="", class="previous next_prev_button", class="disabled") - span(i18next="pagination.prev") Prev + span(translate="PAGINATION.PREVIOUS") <% } %> <% _.each(pages, function(item) { %> @@ -19,5 +19,5 @@ ul.paginator <% if (showNext) { %> li.next a(href="", class="next next_prev_button", class="disabled") - span(i18next="pagination.next") Next + span(translate="PAGINATION.NEXT") <% } %> diff --git a/app/partials/admin/admin-memberships-row-checkbox.jade b/app/partials/admin/admin-memberships-row-checkbox.jade index 108bcd40..efa25b23 100644 --- a/app/partials/admin/admin-memberships-row-checkbox.jade +++ b/app/partials/admin/admin-memberships-row-checkbox.jade @@ -1,5 +1,5 @@ .check input(type="checkbox", id!="<%- inputId %>") div - span.check-text.check-yes Yes - span.check-text.check-no No + span.check-text.check-yes(translate="COMMON.YES") + span.check-text.check-no(translate="COMMON.NO") diff --git a/app/partials/admin/admin-memberships.jade b/app/partials/admin/admin-memberships.jade index 880ccb68..dd0d8510 100644 --- a/app/partials/admin/admin-memberships.jade +++ b/app/partials/admin/admin-memberships.jade @@ -1,5 +1,7 @@ +doctype html + div.wrapper.memberships(ng-controller="MembershipsController as ctrl", - ng-init="section='admin'", tg-memberships) + ng-init="section='admin'; sectionName='ADMIN.MEMBERSHIPS.TITLE'", tg-memberships) sidebar.menu-secondary.sidebar(tg-admin-navigation="memberships") include ../includes/modules/admin-menu @@ -9,8 +11,9 @@ div.wrapper.memberships(ng-controller="MembershipsController as ctrl", include ../includes/components/mainTitle .action-buttons - a.button-green(title="Add new member" href="" ng-click="ctrl.addNewMembers()") - span.text + New member + a.button-green(href="", title="{{ ADMIN.MEMBERSHIPS.ADD_BUTTON_TITLE | translate }}", + ng-click="ctrl.addNewMembers()") + span.text(translate="ADMIN.MEMBERSHIPS.ADD_BUTTON") include ../includes/modules/admin/admin-membership-table diff --git a/app/partials/admin/admin-project-default-values.jade b/app/partials/admin/admin-project-default-values.jade index 14182365..886b2bac 100644 --- a/app/partials/admin/admin-project-default-values.jade +++ b/app/partials/admin/admin-project-default-values.jade @@ -1,5 +1,7 @@ +doctype html + div.wrapper(tg-project-default-values, ng-controller="ProjectProfileController as ctrl", - ng-init="section='admin'; sectionName='Default values'") + ng-init="section='admin'; sectionName='ADMIN.PROJECT_DEFAULT_VALUES.TITLE'") sidebar.menu-secondary.sidebar(tg-admin-navigation="project-profile") include ../includes/modules/admin-menu @@ -9,7 +11,6 @@ div.wrapper(tg-project-default-values, ng-controller="ProjectProfileController a section.main.admin-common header include ../includes/components/mainTitle - - p.total Default Values + p.admin-subtitle(translate="ADMIN.PROJECT_DEFAULT_VALUES.SUBTITLE") include ../includes/modules/admin/default-values diff --git a/app/partials/admin/admin-project-export.jade b/app/partials/admin/admin-project-export.jade index 3274b08a..f92a33c3 100644 --- a/app/partials/admin/admin-project-export.jade +++ b/app/partials/admin/admin-project-export.jade @@ -1,5 +1,8 @@ +doctype html + div.wrapper(ng-controller="ProjectProfileController as ctrl", - ng-init="section='admin'; sectionName='Export'") + ng-init="section='admin'; sectionName='ADMIN.PROJECT_EXPORT.TITLE'") + sidebar.menu-secondary.sidebar(tg-admin-navigation="project-profile") include ../includes/modules/admin-menu @@ -9,18 +12,18 @@ div.wrapper(ng-controller="ProjectProfileController as ctrl", section.main.admin-common(tg-project-export) header include ../includes/components/mainTitle - p.admin-subtitle Export your project to save a backup or to create a new one based on this. + p.admin-subtitle(translate="ADMIN.PROJECT_EXPORT.SUBTITLE") div.admin-project-export-buttons - a.button-green.button-export(href="", title="Export your project") - span Export + a.button-green.button-export(href="", title="{{ 'ADMIN.PROJECT_EXPORT.EXPORT_BUTTON_TITLE' | translate }}") + span(translate="ADMIN.PROJECT_EXPORT.EXPORT_BUTTON") div.admin-project-export-result.hidden div.spin.hidden - img(src="/svg/spinner-circle.svg", alt="loading...") + img(src="/svg/spinner-circle.svg", alt="{{ 'COMMON.LOADING' | translate }}") h3.result-title p.result-message a.help-button(href="https://taiga.io/support/import-export-projects/", target="_blank") span.icon.icon-help - span Do you need help? Check out our support page! + span(translate="ADMIN.HELP") diff --git a/app/partials/admin/admin-project-modules.jade b/app/partials/admin/admin-project-modules.jade index 0df09adf..11e440b7 100644 --- a/app/partials/admin/admin-project-modules.jade +++ b/app/partials/admin/admin-project-modules.jade @@ -1,5 +1,7 @@ +doctype html + div.wrapper(tg-project-modules, ng-controller="ProjectProfileController as ctrl", - ng-init="section='admin'; sectionName='Modules'") + ng-init="section='admin'; sectionName='ADMIN.MODULES.TITLE'") sidebar.menu-secondary.sidebar(tg-admin-navigation="project-profile") include ../includes/modules/admin-menu @@ -15,76 +17,76 @@ div.wrapper(tg-project-modules, ng-controller="ProjectProfileController as ctrl" div.icon.icon-backlog div.desc p - span Backlog - | Manage your user stories to maintain an organized view of upcoming and prioritized work. + span.title(translate="ADMIN.MODULES.BACKLOG") + span(translate="ADMIN.MODULES.BACKLOG_DESCRIPTION") div.activate input.activate-input(type="checkbox", id="functionality-backlog", ng-model="project.is_backlog_activated") label.button.button-gray(ng-switch="project.is_backlog_activated", for="functionality-backlog") - span(ng-switch-when="true") Disable - span(ng-switch-when="false") Enable + span(ng-switch-when="true", translate="ADMIN.MODULES.DISABLE") + span(ng-switch-when="false", translate="ADMIN.MODULES.ENABLE") div.functionality(ng-class="{true:'active', false:''}[project.is_kanban_activated]") div.icon.icon-kanban div.desc p - span Kanban - | Organize your project in a lean way with this board. + span.title(translate="ADMIN.MODULES.KANBAN") + span(translate="ADMIN.MODULES.KANBAN_DESCRIPTION") div.activate input.activate-input(type="checkbox", id="functionality-kanban", ng-model="project.is_kanban_activated") label.button.button-gray(ng-switch="project.is_kanban_activated", for="functionality-kanban") - span(ng-switch-when="true") Disable - span(ng-switch-when="false") Enable + span(ng-switch-when="true", translate="ADMIN.MODULES.DISABLE") + span(ng-switch-when="false", translate="ADMIN.MODULES.ENABLE") div.functionality(ng-class="{true:'active', false:''}[project.is_issues_activated]") div.icon.icon-issues div.desc p - span Issues - | Track the bugs, questions and enhancements related to your project. Don't miss anything! + span.title(translate="ADMIN.MODULES.ISSUES") + span(translate="ADMIN.MODULES.ISSUES_DESCRIPTION") div.activate input.activate-input(type="checkbox", id="functionality-issues", ng-model="project.is_issues_activated") label.button.button-gray(ng-switch="project.is_issues_activated", for="functionality-issues") - span(ng-switch-when="true") Disable - span(ng-switch-when="false") Enable + span(ng-switch-when="true", translate="ADMIN.MODULES.DISABLE") + span(ng-switch-when="false", translate="ADMIN.MODULES.ENABLE") div.functionality(ng-class="{true:'active', false:''}[project.is_wiki_activated]") div.icon.icon-wiki div.desc p - span Wiki - | Add, modify, or delete content in collaboration with others. This is the right place for your project documentation. + span.title(translate="ADMIN.MODULES.WIKI") + span(translate="ADMIN.MODULES.WIKI_DESCRIPTION") div.activate input.activate-input(type="checkbox", id="functionality-wiki", ng-model="project.is_wiki_activated") label.button.button-gray(ng-switch="project.is_wiki_activated", for="functionality-wiki") - span(ng-switch-when="true") Disable - span(ng-switch-when="false") Enable + span(ng-switch-when="true", translate="ADMIN.MODULES.DISABLE") + span(ng-switch-when="false", translate="ADMIN.MODULES.ENABLE") div.functionality(ng-class="{true:'active', false:''}[isVideoconferenceActivated]") div.icon.icon-video div.desc p - span Meet Up - | Choose your videoconference system. Even developers need face to face contact. + span.title(translate="ADMIN.MODULES.MEETUP") + span(translate="ADMIN.MODULES.MEETUP_DESCRIPTION") div.activate input.activate-input(type="checkbox", id="functionality-video", ng-model="isVideoconferenceActivated") label.button.button-gray(ng-switch="isVideoconferenceActivated", for="functionality-video") - span(ng-switch-when="true") Disable - span(ng-switch-when="false") Enable + span(ng-switch-when="true", translate="ADMIN.MODULES.DISABLE") + span(ng-switch-when="false", translate="ADMIN.MODULES.ENABLE") div.videoconference-attributes.hidden select(ng-model="project.videoconferences", - ng-options="e.id as e.name for e in [{'id':'appear-in', 'name':'AppearIn'},{'id':'talky', 'name': 'Talky'}]") - option(value="") Select a videoconference system + ng-options="e.id as e.name for e in [{'id':'appear-in', 'name':'AppearIn'},{'id':'jitsi', 'name': 'Jitsi'},{'id':'talky', 'name': 'Talky'}]") + option(value="", translate="ADMIN.MODULES.SELECT_VIDEOCONFERENCE") input(type="text", ng-model="project.videoconferences_salt", - placeholder="If you want you can append a salt code to the name of the chat room") - button.button-green.submit-button(type="submit", title="Save") Save + placeholder="{{'ADMIN.MODULES.SALT_CHAT_ROOM' | translate}}") + button.button-green.submit-button(type="submit", title="{{'COMMON.SAVE' | translate}}", translate="COMMON.SAVE") diff --git a/app/partials/admin/admin-project-profile.jade b/app/partials/admin/admin-project-profile.jade index cb90def2..fdb89da0 100644 --- a/app/partials/admin/admin-project-profile.jade +++ b/app/partials/admin/admin-project-profile.jade @@ -1,5 +1,7 @@ +doctype html + div.wrapper(tg-project-profile, ng-controller="ProjectProfileController as ctrl", - ng-init="section='admin'; sectionName='Project details'") + ng-init="section='admin'; sectionName='ADMIN.PROJECT_PROFILE.PROJECT_DETAILS'") sidebar.menu-secondary.sidebar(tg-admin-navigation="project-profile") include ../includes/modules/admin-menu @@ -12,29 +14,33 @@ div.wrapper(tg-project-profile, ng-controller="ProjectProfileController as ctrl" form fieldset - label(for="project-name") Project Name - input(type="text", name="name", placeholder="Project name", id="project-name", + label(for="project-name", translate="ADMIN.PROJECT_PROFILE.PROJECT_NAME") + input(type="text", name="name", placeholder="{{'ADMIN.PROJECT_PROFILE.PROJECT_NAME' | translate}}", id="project-name", ng-model="project.name", data-required="true", maxlength="45") fieldset - label(for="project-slug") Project Slug - input(type="text", name="slug", placeholder="Slug", id="project-slug", + label(for="project-slug", translate="ADMIN.PROJECT_PROFILE.PROJECT_SLUG") + input(type="text", name="slug", placeholder="{{'ADMIN.PROJECT_PROFILE.PROJECT_SLUG' | translate}}", id="project-slug", ng-model="project.slug", data-required="true") fieldset - label(for="project-sprints") Number of sprints - input(type="number", name="total_milestones", min="0", placeholder="Number of sprints", + label(for="project-sprints", translate="ADMIN.PROJECT_PROFILE.NUMBER_SPRINTS") + input(type="number", name="total_milestones", min="0", placeholder="{{'ADMIN.PROJECT_PROFILE.NUMBER_SPRINTS' | translate}}", id="project-sprints", ng-model="project.total_milestones", data-type="digits") fieldset - label(for="total-story-points") Number of US points - input(type="number", name="total_story_points", min="0", placeholder="Number of US points", + label(for="total-story-points", translate="ADMIN.PROJECT_PROFILE.NUMBER_US_POINTS") + input(type="number", name="total_story_points", min="0", placeholder="{{'ADMIN.PROJECT_PROFILE.NUMBER_US_POINTS' | translate}}", id="total-story-points", ng-model="project.total_story_points", data-type="digits", data-required="true") fieldset - label(for="project-description") Description - textarea(name="description", placeholder="Description", id="project-description", + label(for="tags", translate="ADMIN.PROJECT_PROFILE.TAGS") + div.tags-block(tg-lb-tag-line, ng-model="project.tags") + + fieldset + label(for="project-description", translate="ADMIN.PROJECT_PROFILE.DESCRIPTION") + textarea(name="description", ng-attr-placeholder="{{'ADMIN.PROJECT_PROFILE.DESCRIPTION' | translate}}", id="project-description", ng-model="project.description", data-required="true") div @@ -42,14 +48,14 @@ div.wrapper(tg-project-profile, ng-controller="ProjectProfileController as ctrl" div input.privacy-project(type="radio", name="private-project", ng-model="project.is_private", ng-value="false") label.trans-button(for="public-project") - span Public Project + span(translate="ADMIN.PROJECT_PROFILE.PUBLIC_PROJECT") div input.privacy-project(type="radio", name="private-project", ng-model="project.is_private", ng-value="true") label.trans-button(for="private-project") - span Private Project + span(translate="ADMIN.PROJECT_PROFILE.PRIVATE_PROJECT") - button.button-green.submit-button(type="submit", title="Save") Save - a.delete-project(href="", title="Delete this project", ng-click="ctrl.openDeleteLightbox()") Delete this project + button.button-green.submit-button(type="submit", title="{{'COMMON.SAVE' | translate}}", translate="COMMON.SAVE") + a.delete-project(href="", title="{{'ADMIN.PROJECT_PROFILE.DELETE' | translate}}", ng-click="ctrl.openDeleteLightbox()", translate="ADMIN.PROJECT_PROFILE.DELETE") div.lightbox.lightbox-delete-project(tg-lb-delete-project) include ../includes/modules/lightbox-delete-project diff --git a/app/partials/admin/admin-project-reports.jade b/app/partials/admin/admin-project-reports.jade index a066b767..a4dffd1f 100644 --- a/app/partials/admin/admin-project-reports.jade +++ b/app/partials/admin/admin-project-reports.jade @@ -1,5 +1,7 @@ +doctype html + div.wrapper(ng-controller="ProjectProfileController as ctrl", - ng-init="section='admin'; sectionName='Reports'") + ng-init="section='admin'; sectionName='ADMIN.REPORTS.TITLE'") sidebar.menu-secondary.sidebar(tg-admin-navigation="project-profile") include ../includes/modules/admin-menu @@ -9,24 +11,15 @@ div.wrapper(ng-controller="ProjectProfileController as ctrl", section.main.admin-common(tg-project-export) header include ../includes/components/mainTitle - p.admin-subtitle Export your project data in CSV format and make your own reports. + p.admin-subtitle(translate="ADMIN.REPORTS.SUBTITLE") - p Download a CSV file or copy the generated URL and open it in your favourite text editor or spreadsheet to make your own project data reports. You will be able to visualize and analize all your data easily. + p(translate="ADMIN.REPORTS.DESCRIPTION") - - var csvType = "US"; - - var controller = "CsvExporterUserstoriesController"; - div.admin-attributes-section - include ../includes/modules/admin/project-csv + div.admin-attributes-section(tg-csv-us) + div.admin-attributes-section(tg-csv-task) + div.admin-attributes-section(tg-csv-issue) - - var csvType = "Task"; - - var controller = "CsvExporterTasksController"; - div.admin-attributes-section - include ../includes/modules/admin/project-csv - - - var csvType = "Issues"; - - var controller = "CsvExporterIssuesController"; - div.admin-attributes-section - include ../includes/modules/admin/project-csv + div a.help-button(href="https://taiga.io/support/csv-reports/", target="_blank") span.icon.icon-help - span How to use this on my own spreadsheet? + span(translate="ADMIN.REPORTS.HELP") diff --git a/app/partials/admin/admin-project-values-custom-fields.jade b/app/partials/admin/admin-project-values-custom-fields.jade index ddc03dfc..d8b93d59 100644 --- a/app/partials/admin/admin-project-values-custom-fields.jade +++ b/app/partials/admin/admin-project-values-custom-fields.jade @@ -1,4 +1,7 @@ -div.wrapper(ng-controller="ProjectValuesSectionController") +doctype html + +div.wrapper(ng-controller="ProjectValuesSectionController", + ng-init="sectionName='ADMIN.CUSTOM_FIELDS.TITLE'") sidebar.menu-secondary.sidebar(tg-admin-navigation="project-values") include ../includes/modules/admin-menu @@ -7,25 +10,19 @@ div.wrapper(ng-controller="ProjectValuesSectionController") section.main.admin-common.admin-attributes include ../includes/components/mainTitle - p.admin-subtitle Specify the custom fields for your user stories, tasks and issues + p.admin-subtitle(translate="ADMIN.CUSTOM_FIELDS.SUBTITLE") div.admin-attributes-section(tg-project-custom-attributes, ng-controller="ProjectCustomAttributesController as ctrl", - ng-init="type='userstory';") - - var customFieldSectionTitle = "User stories custom fields" - - var customFieldButtonTitle = "Add a custom field in user stories" + ng-init="type='userstory'; customFieldSectionTitle='ADMIN.CUSTOM_FIELDS.US_DESCRIPTION'; customFieldButtonTitle='ADMIN.CUSTOM_FIELDS.US_ADD'") include ../includes/modules/admin/admin-custom-attributes div.admin-attributes-section(tg-project-custom-attributes, ng-controller="ProjectCustomAttributesController as ctrl", - ng-init="type='task';") - - var customFieldSectionTitle = "Tasks custom fields" - - var customFieldButtonTitle = "Add a custom field in tasks" + ng-init="type='task'; customFieldSectionTitle='ADMIN.CUSTOM_FIELDS.TASK_DESCRIPTION'; customFieldButtonTitle='ADMIN.CUSTOM_FIELDS.TASK_ADD'") include ../includes/modules/admin/admin-custom-attributes div.admin-attributes-section(tg-project-custom-attributes, ng-controller="ProjectCustomAttributesController as ctrl", - ng-init="type='issue';") - - var customFieldSectionTitle = "Issues custom fields" - - var customFieldButtonTitle = "Add a custom field in issues" + ng-init="type='issue'; customFieldSectionTitle='ADMIN.CUSTOM_FIELDS.ISSUE_DESCRIPTION'; customFieldButtonTitle='ADMIN.CUSTOM_FIELDS.ISSUE_ADD'") include ../includes/modules/admin/admin-custom-attributes diff --git a/app/partials/admin/admin-project-values-points.jade b/app/partials/admin/admin-project-values-points.jade index 64ef3fb1..b47bd8ef 100644 --- a/app/partials/admin/admin-project-values-points.jade +++ b/app/partials/admin/admin-project-values-points.jade @@ -1,3 +1,5 @@ +doctype html + div.wrapper(ng-controller="ProjectValuesSectionController") sidebar.menu-secondary.sidebar(tg-admin-navigation="project-values") include ../includes/modules/admin-menu @@ -7,9 +9,10 @@ div.wrapper(ng-controller="ProjectValuesSectionController") section.main.admin-common.admin-attributes include ../includes/components/mainTitle - p.admin-subtitle Specify the points your user stories could be estimated to + p.admin-subtitle(translate="ADMIN.PROJECT_VALUES_POINTS.SUBTITLE") div.admin-attributes-section(tg-project-values, ng-controller="ProjectValuesController as ctrl", - ng-init="section='admin'; resource='userstories'; type='points'; sectionName='Us points'", + ng-init="section='admin'; resource='userstories'; type='points'; sectionName='ADMIN.PROJECT_VALUES_POINTS.TITLE'", + objName="points", type="points") include ../includes/modules/admin/project-points diff --git a/app/partials/admin/admin-project-values-priorities.jade b/app/partials/admin/admin-project-values-priorities.jade index 4e0c5098..0658f0d1 100644 --- a/app/partials/admin/admin-project-values-priorities.jade +++ b/app/partials/admin/admin-project-values-priorities.jade @@ -1,3 +1,5 @@ +doctype html + div.wrapper(ng-controller="ProjectValuesSectionController") sidebar.menu-secondary.sidebar(tg-admin-navigation="project-values") include ../includes/modules/admin-menu @@ -7,9 +9,10 @@ div.wrapper(ng-controller="ProjectValuesSectionController") section.main.admin-common.admin-attributes include ../includes/components/mainTitle - p.admin-subtitle Specify the priorities your issues will have + p.admin-subtitle(translate="ADMIN.PROJECT_VALUES_PRIORITIES.SUBTITLE") div.admin-attributes-section(tg-project-values, ng-controller="ProjectValuesController as ctrl", - ng-init="section='admin'; resource='issues'; type='priorities'; sectionName='Issue priorities'; objName='priority'", + ng-init="section='admin'; resource='issues'; type='priorities'; sectionName='ADMIN.PROJECT_VALUES_PRIORITIES.TITLE';", + objName="priorities", type="priorities") include ../includes/modules/admin/project-types diff --git a/app/partials/admin/admin-project-values-severities.jade b/app/partials/admin/admin-project-values-severities.jade index 507ff930..93101293 100644 --- a/app/partials/admin/admin-project-values-severities.jade +++ b/app/partials/admin/admin-project-values-severities.jade @@ -1,3 +1,5 @@ +doctype html + div.wrapper(ng-controller="ProjectValuesSectionController") sidebar.menu-secondary.sidebar(tg-admin-navigation="project-values") include ../includes/modules/admin-menu @@ -7,9 +9,10 @@ div.wrapper(ng-controller="ProjectValuesSectionController") section.main.admin-common.admin-attributes include ../includes/components/mainTitle - p.admin-subtitle Specify the severities your issues will have + p.admin-subtitle(translate="ADMIN.PROJECT_VALUES_SEVERITIES.SUBTITLE") div.admin-attributes-section(tg-project-values, ng-controller="ProjectValuesController as ctrl", - ng-init="section='admin'; resource='issues'; type='severities'; sectionName='Issue severities'; objName='severity'", + ng-init="section='admin'; resource='issues'; type='severities'; sectionName='ADMIN.PROJECT_VALUES_SEVERITIES.TITLE';", + objName="severities", type="severities") include ../includes/modules/admin/project-types diff --git a/app/partials/admin/admin-project-values-status.jade b/app/partials/admin/admin-project-values-status.jade index 5f6e8876..5d7e6343 100644 --- a/app/partials/admin/admin-project-values-status.jade +++ b/app/partials/admin/admin-project-values-status.jade @@ -1,4 +1,7 @@ -div.wrapper(ng-controller="ProjectValuesSectionController") +doctype html + +div.wrapper(ng-controller="ProjectValuesSectionController", + ng-init="section='admin'; sectionName='ADMIN.PROJECT_VALUES_STATUS.TITLE'") sidebar.menu-secondary.sidebar(tg-admin-navigation="project-values") include ../includes/modules/admin-menu @@ -7,19 +10,22 @@ div.wrapper(ng-controller="ProjectValuesSectionController") section.main.admin-common.admin-attributes include ../includes/components/mainTitle - p.admin-subtitle Specify the statuses your user stories, tasks and issues will go through + p.admin-subtitle(translate="ADMIN.PROJECT_VALUES_STATUS.SUBTITLE") - div.admin-attributes-section(tg-project-values, ng-controller="ProjectValuesController as ctrl", - ng-init="section='admin'; resource='userstories'; type='userstory-statuses'; sectionName='Us Statuses'", - type="userstory-statuses") + div.admin-attributes-section(tg-project-values, type="userstory-statuses", + ng-controller="ProjectValuesController as ctrl", + ng-init="section='admin'; resource='userstories'; type='userstory-statuses'; sectionName='ADMIN.PROJECT_VALUES_STATUS.US_TITLE'", + objName="status") include ../includes/modules/admin/project-us-status - div.admin-attributes-section(tg-project-values, ng-controller="ProjectValuesController as ctrl", - ng-init="section='admin'; resource='tasks'; type='task-statuses'; sectionName='Task Statuses'", - type="task-statuses") + div.admin-attributes-section(tg-project-values, type="task-statuses", + ng-controller="ProjectValuesController as ctrl", + ng-init="section='admin'; resource='tasks'; type='task-statuses'; sectionName='ADMIN.PROJECT_VALUES_STATUS.TASK_TITLE'" + objName="status") include ../includes/modules/admin/project-status - div.admin-attributes-section(tg-project-values, ng-controller="ProjectValuesController as ctrl", - ng-init="section='admin'; resource='issues'; type='issue-statuses'; sectionName='Issue Statuses'", - type="issue-statuses") + div.admin-attributes-section(tg-project-values, type="issue-statuses", + ng-controller="ProjectValuesController as ctrl", + ng-init="section='admin'; resource='issues'; type='issue-statuses'; sectionName='ADMIN.PROJECT_VALUES_STATUS.ISSUE_TITLE'", + objName="status") include ../includes/modules/admin/project-status diff --git a/app/partials/admin/admin-project-values-types.jade b/app/partials/admin/admin-project-values-types.jade index 2f033b29..8cb5092f 100644 --- a/app/partials/admin/admin-project-values-types.jade +++ b/app/partials/admin/admin-project-values-types.jade @@ -1,4 +1,7 @@ -div.wrapper(ng-controller="ProjectValuesSectionController") +doctype html + +div.wrapper(ng-controller="ProjectValuesSectionController" + ng-init="sectionName='ADMIN.PROJECT_VALUES_TYPES.TITLE'") sidebar.menu-secondary.sidebar(tg-admin-navigation="project-values") include ../includes/modules/admin-menu @@ -7,9 +10,10 @@ div.wrapper(ng-controller="ProjectValuesSectionController") section.main.admin-common.admin-attributes include ../includes/components/mainTitle - p.admin-subtitle Specify the types your user stories could be estimated to + p.admin-subtitle(translate="ADMIN.PROJECT_VALUES_TYPES.SUBTITLE") div.admin-attributes-section(tg-project-values, ng-controller="ProjectValuesController as ctrl", - ng-init="section='admin'; resource='issues'; type='issue-types'; sectionName='Issue types'; objName='type'", + ng-init="section='admin'; resource='issues'; sectionName='ADMIN.PROJECT_VALUES_TYPES.ISSUE_TITLE'; type='issue-types';", + objName="types", type="issue-types") include ../includes/modules/admin/project-types diff --git a/app/partials/admin/admin-roles.jade b/app/partials/admin/admin-roles.jade index 2899d960..34b6d23d 100644 --- a/app/partials/admin/admin-roles.jade +++ b/app/partials/admin/admin-roles.jade @@ -1,3 +1,5 @@ +doctype html + div.wrapper.roles(ng-controller="RolesController as ctrl", ng-init="section='admin'", tg-roles) sidebar.menu-secondary.sidebar(tg-admin-navigation="roles") @@ -6,32 +8,31 @@ div.wrapper.roles(ng-controller="RolesController as ctrl", include ../includes/modules/admin-submenu-roles section.main.admin-roles.admin-common - .header-with-actions + header.header-with-actions include ../includes/components/mainTitle .action-buttons(ng-if="!role.external_user") - a.button-red.delete-role(href="", title="Delete", ng-click="ctrl.delete()") - span Delete + a.button-red.delete-role(href="", title="{{'COMMON.DELETE' | translate}}", ng-click="ctrl.delete()") + span(translate="COMMON.DELETE") div(ng-if="!role.external_user") div(tg-edit-role) .edit-role input(type="text", value="{{ role.name }}") - a.save.icon.icon-floppy(href="", title="Save") + a.save.icon.icon-floppy(href="", title="{{'COMMON.SAVE' | translate}}") p.total - span.role-name(title="{{ role.members_count }} members with this role") {{ role.name }} + span.role-name(title="{{'ADMIN.ROLES.COUNT_MEMBERS' | translate}}") {{ role.name }} a.edit-value.icon.icon-edit - div.any-computable-role(ng-hide="anyComputableRole") Be careful, no role in your project will be able to estimate the point value for user stories + div.any-computable-role(ng-hide="anyComputableRole", translate="ADMIN.ROLES.WARNING_NO_ROLE") - div.general-category - | When enabled, members assigned to this role will be able to estimate the point value for user stories + div.general-category(translate="ADMIN.ROLES.HELP_ROLE_ENABLED") div.check input(type="checkbox", ng-model="role.computable", ng-change="ctrl.setComputable()") div - span.check-text.check-yes Yes - span.check-text.check-no No + span.check-text.check-yes(translate="COMMON.YES") + span.check-text.check-no(translate="COMMON.NO") div(ng-if="role.external_user") p.total diff --git a/app/partials/admin/admin-third-parties-bitbucket.jade b/app/partials/admin/admin-third-parties-bitbucket.jade index 0fb33c63..992da283 100644 --- a/app/partials/admin/admin-third-parties-bitbucket.jade +++ b/app/partials/admin/admin-third-parties-bitbucket.jade @@ -1,3 +1,5 @@ +doctype html + div.wrapper.roles(tg-bitbucket-webhooks, ng-controller="BitbucketController as ctrl", ng-init="section='admin'") sidebar.menu-secondary.sidebar(tg-admin-navigation="third-parties") @@ -10,25 +12,25 @@ div.wrapper.roles(tg-bitbucket-webhooks, ng-controller="BitbucketController as c form fieldset - label(for="secret-key") Secret key - input(type="text", name="secret-key", ng-model="bitbucket.secret", placeholder="Secret key", id="secret-key") + label(for="secret-key", translate="ADMIN.THIRD_PARTIES.SECRET_KEY") + input(type="text", name="secret-key", ng-model="bitbucket.secret", placeholder="{{'ADMIN.THIRD_PARTIES.SECRET_KEY' | translate}}", id="secret-key") fieldset .select-input-text(tg-select-input-text) div - label(for="payload-url") Payload URL + label(for="payload-url", translate="ADMIN.THIRD_PARTIES.PAYLOAD_URL") .field-with-option - input(type="text", ng-model="bitbucket.webhooks_url", name="payload-url", readonly="readonly", placeholder="Payload URL", id="payload-url") + input(type="text", ng-model="bitbucket.webhooks_url", name="payload-url", readonly="readonly", placeholder="{{'ADMIN.THIRD_PARTIES.PAYLOAD_URL' | translate}}", id="payload-url") .option-wrapper.select-input-content .icon.icon-copy - .help-copy Copy to clipboard: Ctrl+C + .help-copy(translate="COMMON.COPY_TO_CLIPBOARD") fieldset - label(for="valid-origin-ips") Valid origin ips (separated by ,) - input(type="text", name="valid-origin-ips", tg-valid-origin-ips, ng-model="bitbucket.valid_origin_ips", placeholder="Bitbucket requests are not signed so the best way of verifying the origin is by IP. If the field is empty there will be no IP validation.", id="valid-origin-ips") + label(for="valid-origin-ips", translate="ADMIN.THIRD_PARTIES.VALID_IPS") + input(type="text", name="valid-origin-ips", tg-valid-origin-ips, ng-model="bitbucket.valid_origin_ips", placeholder="{{'ADMIN.BITBUCKET.INFO_VERIFYING_IP' | translate}}", id="valid-origin-ips") - button.button-green.submit-button(type="submit", title="Save") Save + button.button-green.submit-button(type="submit", title="{{'COMMON.SAVE' | translate}}", translate="COMMON.SAVE") a.help-button(href="https://taiga.io/support/bitbucket-integration/", target="_blank") span.icon.icon-help - span Do you need help? Check out our support page! + span(translate="ADMIN.HELP") diff --git a/app/partials/admin/admin-third-parties-github.jade b/app/partials/admin/admin-third-parties-github.jade index c9ce5e8d..0b3efe32 100644 --- a/app/partials/admin/admin-third-parties-github.jade +++ b/app/partials/admin/admin-third-parties-github.jade @@ -1,3 +1,5 @@ +doctype html + div.wrapper.roles(tg-github-webhooks, ng-controller="GithubController as ctrl", ng-init="section='admin'") sidebar.menu-secondary.sidebar(tg-admin-navigation="third-parties") @@ -10,21 +12,21 @@ div.wrapper.roles(tg-github-webhooks, ng-controller="GithubController as ctrl", form fieldset - label(for="secret-key") Secret key - input(type="text", name="secret-key", ng-model="github.secret", placeholder="Secret key", id="secret-key") + label(for="secret-key", translate="ADMIN.THIRD_PARTIES.SECRET_KEY") + input(type="text", name="secret-key", ng-model="github.secret", placeholder="{{'ADMIN.THIRD_PARTIES.SECRET_KEY' | translate}}", id="secret-key") fieldset .select-input-text(tg-select-input-text) div - label(for="payload-url") Payload URL + label(for="payload-url", translate="ADMIN.THIRD_PARTIES.PAYLOAD_URL") .field-with-option - input(type="text", ng-model="github.webhooks_url", name="payload-url", readonly="readonly", placeholder="Payload URL", id="payload-url") + input(type="text", ng-model="github.webhooks_url", name="payload-url", readonly="readonly", placeholder="{{'ADMIN.THIRD_PARTIES.PAYLOAD_URL' | translate}}", id="payload-url") .option-wrapper.select-input-content .icon.icon-copy - .help-copy Copy to clipboard: Ctrl+C + .help-copy(translate="COMMON.COPY_TO_CLIPBOARD") - button.button-green.submit-button(type="submit", title="Save") Save + button.button-green.submit-button(type="submit", title="{{'COMMON.SAVE' | translate}}", translate="COMMON.SAVE") a.help-button(href="https://taiga.io/support/github-integration/", target="_blank") span.icon.icon-help - span Do you need help? Check out our support page! + span(translate="ADMIN.HELP") diff --git a/app/partials/admin/admin-third-parties-gitlab.jade b/app/partials/admin/admin-third-parties-gitlab.jade index 6ce05ce2..9a552bbc 100644 --- a/app/partials/admin/admin-third-parties-gitlab.jade +++ b/app/partials/admin/admin-third-parties-gitlab.jade @@ -1,38 +1,36 @@ -block head - title Taiga Your agile, free, and open source project management tool +doctype html -block content - div.wrapper.roles(tg-gitlab-webhooks, ng-controller="GitlabController as ctrl", - ng-init="section='admin'") - sidebar.menu-secondary.sidebar(tg-admin-navigation="third-parties") - include ../includes/modules/admin-menu - sidebar.menu-tertiary.sidebar(tg-admin-navigation="third-parties-gitlab") - include ../includes/modules/admin-submenu-third-parties +div.wrapper.roles(tg-gitlab-webhooks, ng-controller="GitlabController as ctrl", + ng-init="section='admin'") + sidebar.menu-secondary.sidebar(tg-admin-navigation="third-parties") + include ../includes/modules/admin-menu + sidebar.menu-tertiary.sidebar(tg-admin-navigation="third-parties-gitlab") + include ../includes/modules/admin-submenu-third-parties - section.main.admin-common.admin-third-parties - include ../includes/components/mainTitle + section.main.admin-common.admin-third-parties + include ../includes/components/mainTitle - form - fieldset - label(for="secret-key") Secret key - input(type="text", name="secret-key", ng-model="gitlab.secret", placeholder="Secret key", id="secret-key") + form + fieldset + label(for="secret-key", translate="ADMIN.THIRD_PARTIES.SECRET_KEY") + input(type="text", name="secret-key", ng-model="gitlab.secret", placeholder="{{'ADMIN.THIRD_PARTIES.SECRET_KEY' | translate}}", id="secret-key") - fieldset - .select-input-text(tg-select-input-text) - div - label(for="payload-url") Payload URL - .field-with-option - input(type="text", ng-model="gitlab.webhooks_url", name="payload-url", readonly="readonly", placeholder="Payload URL", id="payload-url") - .option-wrapper.select-input-content - .icon.icon-copy - .help-copy Copy to clipboard: Ctrl+C + fieldset + .select-input-text(tg-select-input-text) + div + label(for="payload-url", translate="ADMIN.THIRD_PARTIES.PAYLOAD_URL") + .field-with-option + input(type="text", ng-model="gitlab.webhooks_url", name="payload-url", readonly="readonly", placeholder="{{'ADMIN.THIRD_PARTIES.PAYLOAD_URL' | translate}}", id="payload-url") + .option-wrapper.select-input-content + .icon.icon-copy + .help-copy(translate="COMMON.COPY_TO_CLIPBOARD") - fieldset - label(for="valid-origin-ips") Valid origin ips (separated by ,) - input(type="text", name="valid-origin-ips", tg-valid-origin-ips, ng-model="gitlab.valid_origin_ips", placeholder="Gitlab requests are not signed so the best way of verifying the origin is by IP. If the field is empty there will be no IP validation.", id="valid-origin-ips") + fieldset + label(for="valid-origin-ips", translate="ADMIN.THIRD_PARTIES.VALID_IPS") + input(type="text", name="valid-origin-ips", tg-valid-origin-ips, ng-model="gitlab.valid_origin_ips", placeholder="{{'ADMIN.GITLAB.INFO_VERIFYING_IP' | translate}}", id="valid-origin-ips") - button.button-green.submit-button(type="submit", title="Save") Save + button.button-green.submit-button(type="submit", title="{{'COMMON.SAVE' | translate}}", translate="COMMON.SAVE") - a.help-button(href="https://taiga.io/support/gitlab-integration/", target="_blank") - span.icon.icon-help - span Do you need help? Check out our support page! + a.help-button(href="https://taiga.io/support/gitlab-integration/", target="_blank") + span.icon.icon-help + span(translate="ADMIN.HELP") diff --git a/app/partials/admin/admin-third-parties-webhooks.jade b/app/partials/admin/admin-third-parties-webhooks.jade index b88fd939..345ffd8a 100644 --- a/app/partials/admin/admin-third-parties-webhooks.jade +++ b/app/partials/admin/admin-third-parties-webhooks.jade @@ -1,99 +1,97 @@ -block head - title Taiga Your agile, free, and open source project management tool +doctype html -block content - div.wrapper.roles(ng-controller="WebhooksController as ctrl", - ng-init="section='admin'") - sidebar.menu-secondary.sidebar(tg-admin-navigation="Webhooks") - include ../includes/modules/admin-menu - sidebar.menu-tertiary.sidebar(tg-admin-navigation="third-parties-webhooks") - include ../includes/modules/admin-submenu-third-parties +div.wrapper.roles(ng-controller="WebhooksController as ctrl", + ng-init="section='admin'") + sidebar.menu-secondary.sidebar(tg-admin-navigation="third-parties") + include ../includes/modules/admin-menu + sidebar.menu-tertiary.sidebar(tg-admin-navigation="third-parties-webhooks") + include ../includes/modules/admin-submenu-third-parties - section.main.admin-common.admin-webhooks(tg-new-webhook) - include ../includes/components/mainTitle + section.main.admin-common.admin-webhooks(tg-new-webhook) + include ../includes/components/mainTitle - p.admin-subtitle Webhooks notify external services about events in Taiga, like comments, user stories.... - div.webhooks-options - a.button-green.hidden.add-webhook(href="",title="Add a New Webhook") Add Webhook + p.admin-subtitle(translate="ADMIN.WEBHOOKS.SUBTITLE") + div.webhooks-options + a.button-green.hidden.add-webhook(href="", title="{{'ADMIN.WEBHOOKS.ADD_NEW' | translate}}", translate="ADMIN.WEBHOOKS.ADD_NEW") - section.webhooks-table.basic-table - div.table-header - div.row - div.webhook-service Name - div.webhook-url URL - div.webhook-options - div.table-body - div.single-webhook-wrapper(tg-webhook="webhook", ng-repeat="webhook in webhooks") - div.edition-mode.hidden - form.row - fieldset.webhook-service - input(type="text", name="name", placeholder="Type the service name", data-required="true", ng-model="webhook.name") - div.webhook-url - div.webhook-url-inputs - fieldset - input(type="text", name="url", data-type="url", placeholder="Type the service payload url", data-required="true", ng-model="webhook.url") - fieldset - input(type="text", name="key", placeholder="Type the service secret key", data-required="true", ng-model="webhook.key") - div.webhook-options - a.edit-existing.icon.icon-floppy(href="", title="Save Webhook") - a.cancel-existing.icon.icon-delete(href="", title="Cancel Webhook") + section.webhooks-table.basic-table + div.table-header + div.row + div.webhook-service(translate="COMMON.FIELDS.NAME") + div.webhook-url(translate="COMMON.FIELDS.URL") + div.webhook-options + div.table-body + div.single-webhook-wrapper(tg-webhook="webhook", ng-repeat="webhook in webhooks") + div.edition-mode.hidden + form.row + fieldset.webhook-service + input(type="text", name="name", placeholder="{{'ADMIN.WEBHOOKS.TYPE_NAME' | translate}}", data-required="true", ng-model="webhook.name") + div.webhook-url + div.webhook-url-inputs + fieldset + input(type="text", name="url", data-type="url", placeholder="{{'ADMIN.WEBHOOKS.TYPE_PAYLOAD_URL' | translate}}", data-required="true", ng-model="webhook.url") + fieldset + input(type="text", name="key", placeholder="{{'ADMIN.WEBHOOKS.TYPE_SERVICE_SECRET' | translate}}", data-required="true", ng-model="webhook.key") + div.webhook-options + a.edit-existing.icon.icon-floppy(href="", title="{{'ADMIN.WEBHOOKS.SAVE' | translate}}") + a.cancel-existing.icon.icon-delete(href="", title="{{'ADMIN.WEBHOOKS.CANCEL' | translate}}") - div.visualization-mode - div.row - div.webhook-service - span(ng-bind="webhook.name") - div.webhook-url - span(ng-bind="webhook.url") - a.show-history.toggle-history(href="", title="Toggle history", ng-show="webhook.logs_counter") (Show history) + div.visualization-mode + div.row + div.webhook-service + span(ng-bind="webhook.name") + div.webhook-url + span(ng-bind="webhook.url") + a.show-history.toggle-history(href="", title="{{'ADMIN.WEBHOOKS.SHOW_HISTORY_TITLE' | translate}}", ng-show="webhook.logs_counter", translate="ADMIN.WEBHOOKS.SHOW_HISTORY") - div.webhook-options - div.webhook-options-wrapper - a.test-webhook.icon.icon-check-square(href="", title="Test Webhook") - a.edit-webhook.icon.icon-edit(href="", title="Edit Webhook") - a.delete-webhook.icon.icon-delete(href="", title="Delete Webhook") + div.webhook-options + div.webhook-options-wrapper + a.test-webhook.icon.icon-check-square(href="", title="{{'ADMIN.WEBHOOKS.TEST' | translate}}") + a.edit-webhook.icon.icon-edit(href="", title="{{'ADMIN.WEBHOOKS.EDIT' | translate}}") + a.delete-webhook.icon.icon-delete(href="", title="{{'ADMIN.WEBHOOKS.DELETE' | translate}}") - div.webhooks-history(ng-show="webhook.logs") - div.history-single-wrapper(ng-repeat="log in webhook.logs") - div.history-single - div - span.history-response-icon(ng-class="log.validStatus ? 'history-success' : 'history-error'", title="{{log.status}}") - span.history-date(ng-bind="log.prettyDate") - span.toggle-log.icon.icon-arrow-bottom + div.webhooks-history(ng-show="webhook.logs") + div.history-single-wrapper(ng-repeat="log in webhook.logs") + div.history-single + div + span.history-response-icon(ng-class="log.validStatus ? 'history-success' : 'history-error'", title="{{log.status}}") + span.history-date(ng-bind="log.prettyDate") + span.toggle-log.icon.icon-arrow-bottom - div.history-single-response - div.history-single-request-header - span Request - a.resend-request(href="", title="Resend request", data-log="{{log.id}}") - span.icon.icon-reload - span Resend request - div.history-single-request-body - div.response-container - span.response-title Headers - textarea(name="headers", ng-bind="log.prettySentHeaders") + div.history-single-response + div.history-single-request-header + span(translate="ADMIN.WEBHOOKS.REQUEST") + a.resend-request(href="", title="{{'ADMIN.WEBHOOKS.RESEND_REQUEST' | translate}}", data-log="{{log.id}}") + span.icon.icon-reload + span(translate="ADMIN.WEBHOOKS.RESEND_REQUEST") + div.history-single-request-body + div.response-container + span.response-title(translate="ADMIN.WEBHOOKS.HEADERS") + textarea(name="headers", ng-bind="log.prettySentHeaders") - div.response-container - span.response-title Payload - textarea(name="payload", ng-bind="log.prettySentData") + div.response-container + span.response-title(translate="ADMIN.WEBHOOKS.PAYLOAD") + textarea(name="payload", ng-bind="log.prettySentData") - div.history-single-response-header - span Response - div.history-single-response-body - div.response-container - textarea(name="response-data", ng-bind="log.response_data") + div.history-single-response-header + span(translate="ADMIN.WEBHOOKS.RESPONSE") + div.history-single-response-body + div.response-container + textarea(name="response-data", ng-bind="log.response_data") - form.new-webhook-form.row.hidden - fieldset.webhook-service - input(type="text", name="name", placeholder="Type the service name", data-required="true", ng-model="newValue.name") - div.webhook-url - div.webhook-url-inputs - fieldset - input(type="text", name="url", data-type="url", placeholder="Type the service payload url", data-required="true", ng-model="newValue.url") - fieldset - input(type="text", name="key", placeholder="Type the service secret key", data-required="true", ng-model="newValue.key") - div.webhook-options - a.add-new.icon.icon-floppy(href="", title="Save Webhook") - a.cancel-new.icon.icon-delete(href="", title="Cancel Webhook") + form.new-webhook-form.row.hidden + fieldset.webhook-service + input(type="text", name="name", placeholder="{{'ADMIN.WEBHOOKS.TYPE_NAME' | translate}}", data-required="true", ng-model="newValue.name") + div.webhook-url + div.webhook-url-inputs + fieldset + input(type="text", name="url", data-type="url", placeholder="{{'ADMIN.WEBHOOKS.TYPE_PAYLOAD_URL' | translate}}", data-required="true", ng-model="newValue.url") + fieldset + input(type="text", name="key", placeholder="{{'ADMIN.WEBHOOKS.TYPE_SERVICE_SECRET' | translate}}", data-required="true", ng-model="newValue.key") + div.webhook-options + a.add-new.icon.icon-floppy(href="", title="{{'ADMIN.WEBHOOKS.SAVE' | translate}}") + a.cancel-new.icon.icon-delete(href="", title="{{'ADMIN.WEBHOOKS.CANCEL' | translate}}") - a.help-button(href="https://taiga.io/support/webhooks/", target="_blank") - span.icon.icon-help - span Do you need help? Check out our support page! + a.help-button(href="https://taiga.io/support/webhooks/", target="_blank") + span.icon.icon-help + span(translate="ADMIN.HELP") diff --git a/app/partials/admin/project-csv.jade b/app/partials/admin/project-csv.jade new file mode 100644 index 00000000..8e709dd9 --- /dev/null +++ b/app/partials/admin/project-csv.jade @@ -0,0 +1,20 @@ +section.project-csv(tg-select-input-text) + div.project-values-title + h2(translate="{{::sectionTitle}}") + a.button.button-gray(title="{{'ADMIN.CSV.DOWNLOAD' | translate}}", + ng-href="{{csvUrl}}", ng-show="csvUrl", target="_blank") + span(translate="ADMIN.CSV.DOWNLOAD") + + div.csv-regenerate-field + div.field-with-options + input(type="text", placeholder="{{'ADMIN.CSV.URL_FIELD_PLACEHOLDER' | translate}}", + readonly, ng-model="csvUrl") + div.option-wrapper.select-input-content + div.icon.icon-copy + + a(href="", title="{{'ADMIN.CSV.TITLE_REGENERATE_URL' | translate}}", ng-click="ctrl.regenerateUuid()") + span.icon.icon-plus(ng-hide="csvUrl") + span(ng-hide="csvUrl", translate="ADMIN.CSV.ACTION_GENERATE_URL") + + span.icon.icon-reload(ng-Show="csvUrl") + span(ng-Show="csvUrl", translate="ADMIN.CSV.ACTION_REGENERATE") diff --git a/app/partials/attachment/attachment-edit.jade b/app/partials/attachment/attachment-edit.jade index 6c0f4ed8..ceb287ad 100644 --- a/app/partials/attachment/attachment-edit.jade +++ b/app/partials/attachment/attachment-edit.jade @@ -1,19 +1,19 @@ .attachment-name span.icon.icon-document - a(href!="<%- url %>", title!="<%- name %> uploaded on <%- created_date %>", target="_blank") + a(href!="<%- url %>", title!="<%- title %>", target="_blank") | <%- name %> .attachment-size span <%- size %> .editable.editable-attachment-comment input(type="text", name="description", maxlength="140", - value!="<%- description %>", placeholder="Type a short description") + value!="<%- description %>", placeholder="{{'ATTACHMENT.DESCRIPTION' | translate}}") .editable.editable-attachment-deprecated input(type="checkbox", name="is-deprecated", id!="attach-<%- id %>-is-deprecated") - label(for!="attach-<%- id %>-is-deprecated") Deprecated? + label(for!="attach-<%- id %>-is-deprecated", translate="{{'ATTACHMENT.DEPRECATED_FILE' | translate}}") .attachment-settings - a.editable-settings.icon.icon-floppy(href="", title="Save") - a.editable-settings.icon.icon-delete(href="", title="Cancel") + a.editable-settings.icon.icon-floppy(href="", title="{{'COMMON.SAVE' | translate}}") + a.editable-settings.icon.icon-delete(href="", title="{{'COMMON.CANCEL' | translate}}") diff --git a/app/partials/attachment/attachment.jade b/app/partials/attachment/attachment.jade index 840e0ac0..0f783021 100644 --- a/app/partials/attachment/attachment.jade +++ b/app/partials/attachment/attachment.jade @@ -1,5 +1,5 @@ .attachment-name - a(href!="<%- url %>", title!="<%- name %> uploaded on <%- created_date %>", target="_blank") + a(href!="<%- url %>", title!="<%- title %>", target="_blank") span.icon.icon-documents span <%- name %> .attachment-size @@ -7,13 +7,13 @@ .attachment-comments <% if (isDeprecated){ %> - span.deprecated-file (deprecated) + span.deprecated-file {{'ATTACHMENT.DEPRECATED' | translate}} <% } %> span <%- description %> <% if (modifyPermission) {%> .attachment-settings - a.settings.icon.icon-edit(href="", title="Edit") - a.settings.icon.icon-delete(href="", title="Delete") - a.settings.icon.icon-drag-v(href="", title="Drag") -<% } %> \ No newline at end of file + a.settings.icon.icon-edit(href="", title="{{'COMMON.EDIT' | translate}}") + a.settings.icon.icon-delete(href="", title="{{'COMMON.DELETE' | translate}}") + a.settings.icon.icon-drag-v(href="", title="{{'COMMON.DRAG' | translate}}") +<% } %> diff --git a/app/partials/attachment/attachments.jade b/app/partials/attachment/attachments.jade index bc025b6c..0cd720a8 100644 --- a/app/partials/attachment/attachments.jade +++ b/app/partials/attachment/attachments.jade @@ -2,10 +2,10 @@ section.attachments .attachments-header h3.attachments-title span.attachments-num(tg-bind-html="ctrl.attachmentsCount") - span.attachments-text attachments - .add-attach(tg-check-permission!="modify_<%- type %>", title!="Add new attachment. <%- maxFileSizeMsg %>") + span.attachments-text(translate="ATTACHMENT.SECTION_NAME") + .add-attach(tg-check-permission!="modify_<%- type %>", title!="{{'ATTACHMENT.ADD' | translate}}") <% if (maxFileSize){ %> - span.size-info.hidden [Max. size: <%- maxFileSize %>] + span.size-info.hidden(translate="ATTACHMENT.MAX_FILE_SIZE", translate-values!="{ 'maxFileSize': '<%- maxFileSize %>'}") <% }; %> label(for="add-attach", class="icon icon-plus related-tasks-buttons") input(id="add-attach", type="file", multiple="multiple") @@ -22,9 +22,7 @@ section.attachments span(ng-bind="file.progressMessage") .percentage(ng-style="{'width': file.progressPercent}") - a.more-attachments(href="", title="show deprecated atachments", ng-if="ctrl.deprecatedAttachmentsCount > 0") - span.text(data-type="show") + show deprecated atachments - span.text.hidden(data-type="hide") - | - hide deprecated atachments - span.more-attachments-num - | ({{ctrl.deprecatedAttachmentsCount }} deprecated) + a.more-attachments(href="", title="{{'ATTACHMENT.SHOW_DEPRECATED' | translate}}", ng-if="ctrl.deprecatedAttachmentsCount > 0") + span.text(data-type="show", translate="ATTACHMENT.SHOW_DEPRECATED") + span.text.hidden(data-type="hide", translate="ATTACHMENT.HIDE_DEPRECATED") + span.more-attachments-num(translate="ATTACHMENT.COUNT_DEPRECATED", translate-values="{counter: '{{ctrl.deprecatedAttachmentsCount}}'}") diff --git a/app/partials/auth/change-password-from-recovery.jade b/app/partials/auth/change-password-from-recovery.jade index 19781326..0ab0cf39 100644 --- a/app/partials/auth/change-password-from-recovery.jade +++ b/app/partials/auth/change-password-from-recovery.jade @@ -1,8 +1,10 @@ +doctype html + div.wrapper div.login-main div.login-container h1.logo img.logo-svg(src="/svg/logo.svg", alt="TAIGA") - p.tagline Your agile, free, and open source project management tool + p.tagline(translate="COMMON.TAG_LINE") include ../includes/modules/change-password-from-recovery-form diff --git a/app/partials/auth/forgot-password.jade b/app/partials/auth/forgot-password.jade index b9e848cb..22dfd2a6 100644 --- a/app/partials/auth/forgot-password.jade +++ b/app/partials/auth/forgot-password.jade @@ -1,9 +1,11 @@ +doctype html + include ../includes/components/beta div.wrapper div.login-main div.login-container img.logo-svg(src="/svg/logo.svg", alt="TAIGA") h1.logo Taiga - h2.tagline LOVE YOUR PROJECT + h2.tagline(translate="COMMON.TAG_LINE_2") include ../includes/modules/forgot-form diff --git a/app/partials/auth/invitation.jade b/app/partials/auth/invitation.jade index 18270792..43088cc8 100644 --- a/app/partials/auth/invitation.jade +++ b/app/partials/auth/invitation.jade @@ -1,3 +1,5 @@ +doctype html + div.wrapper div.invitation-main div.invitation-container(tg-invitation) @@ -8,7 +10,7 @@ div.wrapper span.person-name(tg-bo-bind="invitation.invited_by.full_name_display") span.invitation-text - p has invited you to join the project + p(translate="AUTH.INVITED_YOU") p.project-name(tg-bo-bind="invitation.project_name") div.invitation-form diff --git a/app/partials/auth/login-text.jade b/app/partials/auth/login-text.jade index 90007171..f5db9ef4 100644 --- a/app/partials/auth/login-text.jade +++ b/app/partials/auth/login-text.jade @@ -1,3 +1,4 @@ p.login-text - span Not registered yet? - a(href!='<%- url %>', tg-nav='register', title='Register') create your free account here + span(translate="AUTH.NOT_REGISTERED_YET") + |   + a(href!='<%- url %>', tg-nav='register', title='{{"AUTH.REGISTER" | translate}}', translate="AUTH.CREATE_ACCOUNT") diff --git a/app/partials/auth/login.jade b/app/partials/auth/login.jade index 26ab4ac4..fadbd2f2 100644 --- a/app/partials/auth/login.jade +++ b/app/partials/auth/login.jade @@ -1,9 +1,11 @@ +doctype html + include ../includes/components/beta div.wrapper div.login-main div.login-container img.logo-svg(src="/svg/logo.svg", alt="TAIGA") h1.logo Taiga - h2.tagline LOVE YOUR PROJECT + h2.tagline(translate="COMMON.TAG_LINE_2") include ../includes/modules/login-form diff --git a/app/partials/auth/register.jade b/app/partials/auth/register.jade index 95eb00d2..1c658f36 100644 --- a/app/partials/auth/register.jade +++ b/app/partials/auth/register.jade @@ -1,8 +1,10 @@ +doctype html + div.wrapper div.login-main div.login-container img.logo-svg(src="/svg/logo.svg", alt="TAIGA") h1.logo Taiga - h2.tagline LOVE YOUR PROJECT + h2.tagline(translate="COMMON.TAG_LINE_2") include ../includes/modules/register-form diff --git a/app/partials/backlog/backlog.jade b/app/partials/backlog/backlog.jade index 1b96fa32..29edba68 100644 --- a/app/partials/backlog/backlog.jade +++ b/app/partials/backlog/backlog.jade @@ -1,32 +1,48 @@ +doctype html + div.wrapper(tg-backlog, ng-controller="BacklogController as ctrl", ng-init="section='backlog'") + sidebar.menu-secondary.extrabar.filters-bar(tg-backlog-filters) include ../includes/modules/backlog-filters section.main.backlog include ../includes/components/mainTitle include ../includes/components/summary + div.graphics-container.burndown-container - div.burndown(tg-gm-backlog-graph) + div.burndown(tg-burndown-backlog-graph) include ../includes/modules/burndown + div.backlog-menu div.backlog-table-options - a.trans-button.move-to-current-sprint(href="", title="Move to Current Sprint", + a.trans-button.move-to-current-sprint(href="", + title="{{'BACKLOG.MOVE_US_TO_CURRENT_SPRINT' | translate}}", id="move-to-current-sprint") span.icon.icon-move - span.text Move to current Sprint - a.trans-button(href="", title="Show Filters", id="show-filters-button") + span.text(translate="BACKLOG.MOVE_US_TO_CURRENT_SPRINT") + a.trans-button(href="", + title="{{'BACKLOG.FILTERS.TOGGLE' | translate}}", + id="show-filters-button") span.icon.icon-filter - span.text Show Filters - a.trans-button(href="", title="Show Tags", id="show-tags") + span.text(translate="BACKLOG.FILTERS.SHOW") + a.trans-button(href="", + title="{{'BACKLOG.TAGS.TOGGLE' | translate}}", + id="show-tags") span.icon.icon-tag - span.text Show Tags + span.text(translate="BACKLOG.TAGS.SHOW") include ../includes/components/addnewus + section.backlog-table(ng-class="{'hidden': !visibleUserstories.length}") include ../includes/modules/backlog-table + div.empty.empty-backlog(ng-class="{'hidden': visibleUserstories.length}", tg-backlog-empty-sortable) span.icon.icon-backlog - span.title Your backlog is empty! - a(href="", title+"Create a new US", ng-click="ctrl.addNewUs('standard')", tg-check-permission="add_us") You may want to create a new user story + span.title(translate="BACKLOG.EMPTY") + a(href="", title="{{'BACKLOG.CREATE_NEW_US' | translate}}", + ng-click="ctrl.addNewUs('standard')", + tg-check-permission="add_us", + translate="BACKLOG.CREATE_NEW_US_EMPTY_HELP") + sidebar.menu-secondary.sidebar include ../includes/modules/sprints diff --git a/app/partials/backlog/progress-bar.jade b/app/partials/backlog/progress-bar.jade index 1c0b0831..2fbfaadd 100644 --- a/app/partials/backlog/progress-bar.jade +++ b/app/partials/backlog/progress-bar.jade @@ -1,3 +1,6 @@ -.defined-points(title="Excess of points") -.project-points-progress(title="Pending Points", style!="width: <%- projectPointsPercentaje %>%") -.closed-points-progress(title="Closed points", style!="width: <%- closedPointsPercentaje %>%") \ No newline at end of file +.defined-points(title="{{'BACKLOG.EXCESS_OF_POINTS' | translate}}") + +.project-points-progress(title="{{'BACKLOG.PENDING_POINTS' | translate}}", + style!="width: <%- projectPointsPercentaje %>%") +.closed-points-progress(title="{{'BACKLOG.CLOSED_POINTS' | translate}}", + style!="width: <%- closedPointsPercentaje %>%") diff --git a/app/partials/backlog/sprint-header.jade b/app/partials/backlog/sprint-header.jade index 852c2ab1..cd0b85fd 100644 --- a/app/partials/backlog/sprint-header.jade +++ b/app/partials/backlog/sprint-header.jade @@ -1,20 +1,16 @@ .sprint-name - a.icon.icon-arrow-up(href="", title="Compact Sprint") - <% if(isVisible){ %> - a(href!="<%- taskboardUrl %>", title!="'Go to the taskboard of '<%- name %>'") - span <%- name %> - <% } %> + a.icon.icon-arrow-up(href="", title="{{'BACKLOG.COMPACT_SPRINT' | translate}}") + a(ng-if="::isVisible", href="{{::taskboardUrl}}", title="{{'BACKLOG.GO_TO_TASKBOARD' | translate}}") + span {{::name}} - <% if(isEditable){ %> - a.icon.icon-edit(href="", title="Edit Sprint") - <% } %> + a.icon.icon-edit(ng-if="::isEditable", href="", title="{{'BACKLOG.EDIT_SPRINT' | translate}}") .sprint-summary - .sprint-date <%- estimatedDateRange %> + .sprint-date {{::estimatedDateRange}} ul li - span.number <%- closedPoints %> - span.description closed + span.number {{::closedPoints}} + span.description(translate="BACKLOG.CLOSED_POINTS") li - span.number <%- totalPoints %> - span.description total + span.number {{::totalPoints}} + span.description(translate="BACKLOG.TOTAL_POINTS") diff --git a/app/partials/backlog/us-role-points-popover.jade b/app/partials/backlog/us-role-points-popover.jade index 4fcc2f65..1b864ef4 100644 --- a/app/partials/backlog/us-role-points-popover.jade +++ b/app/partials/backlog/us-role-points-popover.jade @@ -1,6 +1,6 @@ ul.popover.pop-role li - a.clear-selection(href="", title="All") All + a.clear-selection(href="", title="{{'COMMON.ROLES.ALL' | translate}}", translate="COMMON.ROLES.ALL") <% _.each(roles, function(role) { %> li a(href="", class="role", title!="<%- role.name %>", data-role-id!="<%- role.id %>") diff --git a/app/partials/common/components/assigned-to.jade b/app/partials/common/components/assigned-to.jade index be741f01..ee144283 100644 --- a/app/partials/common/components/assigned-to.jade +++ b/app/partials/common/components/assigned-to.jade @@ -4,18 +4,19 @@ <% } %> .assigned-to - span.assigned-title Assigned to + span.assigned-title(translate="COMMON.FIELDS.ASSIGNED_TO") - a(href="" title="edit assignment", class!="user-assigned <% if(isEditable){ %>editable<% }; %>") + a(href="" title="{{ 'COMMON.ASSIGNED_TO.TITLE_ACTION_EDIT_ASSIGNMENT'|translate }}", + class!="user-assigned <% if(isEditable){ %>editable<% }; %>") span.assigned-name <% if (assignedTo) { %> <%- assignedTo.full_name_display %> <% } else { %> - | Not assigned + | {{ 'COMMON.ASSIGNED_TO.NOT_ASSIGNED'|translate }} <% } %> <% if(isEditable){ %> span.icon.icon-arrow-bottom <% }; %> <% if (assignedTo!==null && isEditable) { %> - a.icon.icon-delete(href="" title="delete assignment") + a.icon.icon-delete(href="" title="{{'COMMON.ASSIGNED_TO.DELETE_ASSIGNMENT' | translate}}") <% } %> diff --git a/app/partials/common/components/block-button.jade b/app/partials/common/components/block-button.jade index 7e187687..8dc4e055 100644 --- a/app/partials/common/components/block-button.jade +++ b/app/partials/common/components/block-button.jade @@ -1,4 +1,4 @@ a(href="#", class="button button-gray item-block") - span Block + span(translate="COMMON.BLOCK") a(href="#", class="button button-red item-unblock") - span Unblock + span(translate="COMMON.UNBLOCK") diff --git a/app/partials/common/components/created-by.jade b/app/partials/common/components/created-by.jade index 6f4eb960..e9f74f06 100644 --- a/app/partials/common/components/created-by.jade +++ b/app/partials/common/components/created-by.jade @@ -2,7 +2,6 @@ img(src!="<%- owner.photo %>", alt!="<%- owner.full_name_display %>") .created-by - span.created-title - | Created by <%- owner.full_name_display %> + span.created-title(translate="COMMON.CREATED_BY", translate-values!="{ 'fullDisplayName': '<%- owner.full_name_display %>'}") span.created-date | <%- date %> diff --git a/app/partials/common/components/delete-button.jade b/app/partials/common/components/delete-button.jade index dc2f2065..205e4fb4 100644 --- a/app/partials/common/components/delete-button.jade +++ b/app/partials/common/components/delete-button.jade @@ -1,2 +1,2 @@ a(href="", class="button button-red") - span Delete + span(translate="COMMON.DELETE") diff --git a/app/partials/common/components/editable-description-msg-edit-mode.jade b/app/partials/common/components/editable-description-msg-edit-mode.jade index 7b761cd9..264804ea 100644 --- a/app/partials/common/components/editable-description-msg-edit-mode.jade +++ b/app/partials/common/components/editable-description-msg-edit-mode.jade @@ -1,2 +1 @@ -p.no-description.editable - | Empty space is so boring... go on be descriptive... A rose by any other name would smell as sweet... \ No newline at end of file +p.no-description.editable(translate="COMMON.DESCRIPTION.EMPTY") diff --git a/app/partials/common/components/editable-description-msg-read-mode.jade b/app/partials/common/components/editable-description-msg-read-mode.jade index 2ca9dae8..b25abdef 100644 --- a/app/partials/common/components/editable-description-msg-read-mode.jade +++ b/app/partials/common/components/editable-description-msg-read-mode.jade @@ -1 +1 @@ -p.no-description No description yet. \ No newline at end of file +p.no-description(translate="COMMON.DESCRIPTION.NO_DESCRIPTION") diff --git a/app/partials/common/components/editable-description.jade b/app/partials/common/components/editable-description.jade index 41d3bcf2..caa56bd6 100644 --- a/app/partials/common/components/editable-description.jade +++ b/app/partials/common/components/editable-description.jade @@ -3,9 +3,9 @@ span.edit.icon.icon-edit .edit-description - textarea(placeholder="Empty space is so boring... go on be descriptive... A rose by any other name would smell as sweet...", ng-model="item.description", tg-markitup="tg-markitup") - a.help-markdown(href="https://taiga.io/support/taiga-markdown-syntax/", target="_blank", title="Mardown syntax help") + textarea(ng-attr-placeholder="{{'COMMON.DESCRIPTION.EMPTY' | translate}}", ng-model="item.description", tg-markitup="tg-markitup") + a.help-markdown(href="https://taiga.io/support/taiga-markdown-syntax/", target="_blank", title="{{'COMMON.WYSIWYG.MARKDOWN_HELP' | translate}}") span.icon.icon-help - span Markdown syntax help + span(translate="COMMON.WYSIWYG.MARKDOWN_HELP") span.save-container - a.save.icon.icon-floppy(href="", title="Save") + a.save.icon.icon-floppy(href="", title="{{'COMMON.SAVE' | translate}}") diff --git a/app/partials/common/components/editable-subject.jade b/app/partials/common/components/editable-subject.jade index 85958e88..f77ba862 100644 --- a/app/partials/common/components/editable-subject.jade +++ b/app/partials/common/components/editable-subject.jade @@ -1,7 +1,7 @@ .view-subject | {{ item.subject }} - a.edit.icon.icon-edit(href="" title="Edit") + a.edit.icon.icon-edit(href="" title="{{'COMMON.EDIT' | translate}}") .edit-subject input(type="text", ng-model="item.subject", data-required="true", data-maxlength="500") span.save-container - a.save.icon.icon-floppy(href="", title="Save") + a.save.icon.icon-floppy(href="", title="{{'COMMON.SAVE' | translate}}") diff --git a/app/partials/common/components/main-title.jade b/app/partials/common/components/main-title.jade index 6b44ed63..b5b1756f 100644 --- a/app/partials/common/components/main-title.jade +++ b/app/partials/common/components/main-title.jade @@ -1,2 +1,4 @@ -span.project-name <%- projectName %> -span.green <%- sectionName %> \ No newline at end of file +span.project-name + | {{ projectName }} +span.green + | {{ sectionName }} diff --git a/app/partials/common/components/status-display.jade b/app/partials/common/components/status-display.jade index e42aa074..1062f3f4 100644 --- a/app/partials/common/components/status-display.jade +++ b/app/partials/common/components/status-display.jade @@ -1,9 +1,7 @@ -span - <% if (is_closed) { %> - | Closed - <% } else { %> - | Open - <% } %> - +<% if (is_closed) { %> +span(translate="COMMON.STATUS.CLOSED") +<% } else { %> +span(translate="COMMON.STATUS.OPEN") +<% } %> span(class="us-detail-status", style!="color:<%- status.color %>") | <%- status.name %> diff --git a/app/partials/common/components/watchers.jade b/app/partials/common/components/watchers.jade index 8d5dac17..b11a4aeb 100644 --- a/app/partials/common/components/watchers.jade +++ b/app/partials/common/components/watchers.jade @@ -1,10 +1,10 @@ <% if(isEditable){ %> .watchers-header - span.title watchers - a.icon.icon-plus.add-watcher(href="", title="Add watcher") + span.title(translate="COMMON.WATCHERS.TITLE") + a.icon.icon-plus.add-watcher(href="", title="{{'COMMON.WATCHERS.ADD' | translate}}") <% } else if(watchers.length > 0){ %> .watchers-header - span.title watchers + span.title(translate="COMMON.WATCHERS.TITLE") <% }; %> <% _.each(watchers, function(watcher) { %> @@ -16,7 +16,7 @@ span <%- watcher.full_name_display %> <% if(isEditable){ %> - a.icon.icon-delete(data-watcher-id!="<%- watcher.id %>" href="" title="delete-watcher") + a.icon.icon-delete(data-watcher-id!="<%- watcher.id %>" href="" title="{{'COMMON.WATCHERS.DELETE' | translate}}") <% }; %> <% } %> <% }); %> diff --git a/app/partials/common/estimation/us-estimation-points-per-role.jade b/app/partials/common/estimation/us-estimation-points-per-role.jade index 7491d5a8..8fd9ce85 100644 --- a/app/partials/common/estimation/us-estimation-points-per-role.jade +++ b/app/partials/common/estimation/us-estimation-points-per-role.jade @@ -1,7 +1,7 @@ ul.points-per-role li.total span.points <%- totalPoints %> - span.role total + span.role(translate="US.TOTAL_POINTS") <% _.each(roles, function(role) { %> li(class!="total <% if(editable){ %>clickable<% } %>", data-role-id!="<%- role.id %>", title!="<%- role.name %>") span.points <%- role.points %> diff --git a/app/partials/common/history/history-activity.jade b/app/partials/common/history/history-activity.jade index 83cdb260..89ed64fd 100644 --- a/app/partials/common/history/history-activity.jade +++ b/app/partials/common/history/history-activity.jade @@ -12,8 +12,8 @@ div(class!="activity-single <%- mode %>") <% if (comment.length > 0) { %> <% if ((deleteCommentDate || deleteCommentUser)) { %> .deleted-comment - span - | Comment deleted by <%- deleteCommentUser %> on <%- deleteCommentDate %> + span(translate="COMMENTS.DELETED_INFO", + translate-values!="{ user: '<%- deleteCommentUser %>', date: '<%- deleteCommentDate %>'}") <% } %> .comment.wysiwyg | <%= comment %> @@ -25,7 +25,7 @@ div(class!="activity-single <%- mode %>") <% if(changes.length > 0) { %> .changes <% if (mode != "activity") { %> - a.changes-title(href="", title="Show activity") + a.changes-title(href="", title="{{'ACTIVITY.SHOW_ACTIVITY' | translate}}") span <%- changesText %> span.icon.icon-arrow-up <% } %> diff --git a/app/partials/common/history/history-base-entries.jade b/app/partials/common/history/history-base-entries.jade index c9f566da..fe662b98 100644 --- a/app/partials/common/history/history-base-entries.jade +++ b/app/partials/common/history/history-base-entries.jade @@ -1,6 +1,5 @@ <% if (showMore > 0) { %> -a(href="" title="Show more" class="show-more show-more-comments") - | + Show previous entries (<%- showMore %> more) +a(href="" title="{{ 'ACTIVITY.SHOW_MORE' | translate}}" class="show-more show-more-comments", translate="ACTIVITY.SHOW_MORE", translate-values!="{showMore: '<%- showMore %>'}") <% } %> <% _.each(entries, function(entry) { %> <%= entry %> diff --git a/app/partials/common/history/history-base.jade b/app/partials/common/history/history-base.jade index 383c21ab..ad720c45 100644 --- a/app/partials/common/history/history-base.jade +++ b/app/partials/common/history/history-base.jade @@ -3,21 +3,21 @@ section.history li a(href="#", class="active") span.icon.icon-comment - span.tab-title Comments + span.tab-title(translate="COMMENTS.TITLE") li a(href="#") span.icon.icon-issues - span.tab-title Activity + span.tab-title(translate="ACTIVITY.TITLE") section.history-comments .comments-list div(tg-check-permission!="modify_<%- type %>", tg-toggle-comment, class="add-comment") - textarea(placeholder="Type a new comment here", ng-model!="<%- ngmodel %>.comment", tg-markitup="tg-markitup") + textarea(ng-attr-placeholder="{{'COMMENTS.TYPE_NEW_COMMENT' | translate}}", ng-model!="<%- ngmodel %>.comment", tg-markitup="tg-markitup") <% if (mode !== "edit") { %> - a(class="help-markdown", href="https://taiga.io/support/taiga-markdown-syntax/", target="_blank", title="Mardown syntax help") + a(class="help-markdown", href="https://taiga.io/support/taiga-markdown-syntax/", target="_blank", title="{{'COMMON.WYSIWYG.MARKDOWN_HELP' | translate}}") span.icon.icon-help - span Markdown syntax help - a(href="", title="Comment", class="button button-green save-comment") - span Comment + span(translate="COMMON.WYSIWYG.MARKDOWN_HELP") + a(href="", title="{{'COMMENTS.COMMENT' | translate}}", class="button button-green save-comment") + span(translate="COMMENTS.COMMENT") <% } %> section.history-activity.hidden .changes-list diff --git a/app/partials/common/history/history-change-attachment.jade b/app/partials/common/history/history-change-attachment.jade index 8b4ac0f1..6b12816f 100644 --- a/app/partials/common/history/history-change-attachment.jade +++ b/app/partials/common/history/history-change-attachment.jade @@ -4,11 +4,13 @@ .activity-fromto <% _.each(diff, function(change) { %> p - strong <%- change.name %> from + strong <%- change.name %>  + strong(translate="COMMON.FROM") br span <%- change.from %> p - strong <%- change.name %> to + strong <%- change.name %>  + strong(translate="COMMON.TO") br span <%- change.to %> <% }) %> diff --git a/app/partials/common/history/history-change-generic.jade b/app/partials/common/history/history-change-generic.jade index a5fbb73b..8c29b5c1 100644 --- a/app/partials/common/history/history-change-generic.jade +++ b/app/partials/common/history/history-change-generic.jade @@ -3,10 +3,10 @@ span <%- name %> .activity-fromto p - strong from + strong(translate="COMMON.FROM") br span <%- from %> p - strong to + strong(translate="COMMON.TO") br span <%- to %> diff --git a/app/partials/common/history/history-change-list.jade b/app/partials/common/history/history-change-list.jade index f11c5fa0..038cfc88 100644 --- a/app/partials/common/history/history-change-list.jade +++ b/app/partials/common/history/history-change-list.jade @@ -4,14 +4,14 @@ .activity-fromto <% if (removed.length > 0) { %> p - strong removed + strong(translate="ACTIVITY.REMOVED") br span <%- removed %> <% } %> <% if (added.length > 0) { %> p - strong added + strong(translate="ACTIVITY.ADDED") br span <%- added %> <% } %> diff --git a/app/partials/common/history/history-change-points.jade b/app/partials/common/history/history-change-points.jade index d226cd79..1f4df3c6 100644 --- a/app/partials/common/history/history-change-points.jade +++ b/app/partials/common/history/history-change-points.jade @@ -1,14 +1,14 @@ <% _.each(points, function(point, name) { %> .change-entry .activity-changed - span US points (<%- name.toLowerCase() %>) + span(translate="ACTIVITY.US_POINTS", translate-values!="<%- name.toLowerCase() %>") .activity-fromto p - strong from + strong(translate="COMMON.FROM") br span <%- point[0] %> p - strong to + strong(translate="COMMON.TO") br span <%- point[1] %> <% }); %> \ No newline at end of file diff --git a/app/partials/common/history/history-deleted-comment.jade b/app/partials/common/history/history-deleted-comment.jade index 434a84c2..2e8cfe44 100644 --- a/app/partials/common/history/history-deleted-comment.jade +++ b/app/partials/common/history/history-deleted-comment.jade @@ -1,11 +1,14 @@ .activity-single.comment.deleted-comment div - span Comment deleted by <%- deleteCommentUser %> on <%- deleteCommentDate %> - a(href="", title="Show comment", class="show-deleted-comment") (Show deleted comment) - a(href="", title="Show comment", class="hide-deleted-comment hidden") (Hide deleted comment) + span(translate="COMMENTS.DELETED_INFO", + translate-values!="{user: '<%- deleteCommentUser %>', date: '<%- deleteCommentDate %>'}") + a(href="", title="{{'COMMENTS.SHOW_DELETED' | translate}}", + class="show-deleted-comment", translate="COMMENTS.SHOW_DELETED") + a(href="", title="{{'COMMENTS.HIDE_DELETED' | translate}}", + class="hide-deleted-comment hidden", translate="COMMENTS.HIDE_DELETED") .comment-body.wysiwyg <%= deleteComment %> <% if (canRestoreComment) { %> a(href="", class="comment-restore", data-activity-id!="<%- activityId %>") span.icon.icon-reload - span Restore comment + span(translate="COMMENTS.RESTORE") <% } %> diff --git a/app/partials/common/lightbox/lightbox-assigned-to-users.jade b/app/partials/common/lightbox/lightbox-assigned-to-users.jade index d734bc8a..792d4ec3 100644 --- a/app/partials/common/lightbox/lightbox-assigned-to-users.jade +++ b/app/partials/common/lightbox/lightbox-assigned-to-users.jade @@ -1,17 +1,17 @@ <% if (selected) { %> .watcher-single.active .watcher-avatar - a(href="", title="Assigned to", class="avatar") + a(href="", title="{{'COMMON.ASSIGNED_TO' | translate}}", class="avatar") img(src!="<%- selected.photo %>") a(href="", title!="<%- selected.full_name_display %>", class="watcher-name") | <%-selected.full_name_display %> - a(href="", title="Remove assigned", class="icon icon-delete remove-assigned-to") + a(href="", title="{{'COMMON.ASSIGNED_TO.REMOVE_ASSIGNED' | translate}}", class="icon icon-delete remove-assigned-to") <% } %> <% _.each(users, function(user) { %> .watcher-single(data-user-id!="<%- user.id %>") .watcher-avatar - a(href="#", title="Assigned to", class="avatar") + a(href="#", title="{{'COMMON.ASSIGNED_TO.TITLE' | translate}}", class="avatar") img(src!="<%- user.photo %>") a(href="", title!="<%- user.full_name_display %>", class="watcher-name") | <%- user.full_name_display %> @@ -19,5 +19,5 @@ <% if (showMore) { %> div(ng-show="filteringUsers", class="more-watchers") - span ...too many users, keep filtering -<% } %> \ No newline at end of file + span(translate="COMMON.ASSIGNED_TO.TOO_MANY") +<% } %> diff --git a/app/partials/common/lightbox/lightbox-assigned-to.jade b/app/partials/common/lightbox/lightbox-assigned-to.jade index 97885e59..34e87b9a 100644 --- a/app/partials/common/lightbox/lightbox-assigned-to.jade +++ b/app/partials/common/lightbox/lightbox-assigned-to.jade @@ -1,9 +1,9 @@ a.close(href="", title="close") span.icon.icon-delete div.form - h2.title Select assigned to + h2.title(translate="LIGHTBOX.ASSIGNED_TO.SELECT") fieldset - input(type="text", data-maxlength="500", placeholder="Search for users", ng-model="usersSearch") + input(type="text", data-maxlength="500", placeholder="{{'LIGHTBOX.ASSIGNED_TO.SEARCH' | translate}}", ng-model="usersSearch") //-This block is rendered by the directive div.watchers diff --git a/app/partials/common/lightbox/lightbox-block.jade b/app/partials/common/lightbox/lightbox-block.jade index a6290d16..b74ee6d4 100644 --- a/app/partials/common/lightbox/lightbox-block.jade +++ b/app/partials/common/lightbox/lightbox-block.jade @@ -1,9 +1,9 @@ -a.close(href="", title="close") +a.close(href="", title="{{'COMMON.CLOSE' | translate}}") span.icon.icon-delete div.form h2.title fieldset - textarea.reason(placeholder="Please explain the reason") + textarea.reason(ng-attr-placeholder="{{'COMMON.BLOCKED_REASON' | translate}}") a.button-green(href="") - span Save + span(translate="COMMON.SAVE") diff --git a/app/partials/common/lightbox/lightbox-blocking-message-input.jade b/app/partials/common/lightbox/lightbox-blocking-message-input.jade index 63c0b0a8..3c1c84c8 100644 --- a/app/partials/common/lightbox/lightbox-blocking-message-input.jade +++ b/app/partials/common/lightbox/lightbox-blocking-message-input.jade @@ -1,4 +1,4 @@ fieldset.blocked-note.hidden textarea(name="blocked_note", - placeholder="Why is this user story blocked?", + ng-attr-placeholder="{{'COMMON.BLOCKED_NOTE' | translate}}", ng-model!="<%- ngmodel %>") diff --git a/app/partials/common/lightbox/lightbox-users.jade b/app/partials/common/lightbox/lightbox-users.jade index a4c3dfc0..90a1b369 100644 --- a/app/partials/common/lightbox/lightbox-users.jade +++ b/app/partials/common/lightbox/lightbox-users.jade @@ -1,7 +1,7 @@ -a.close(href="", title="close") +a.close(href="", title="{{'COMMON.CLOSE' | translate}}") span.icon.icon-delete div.form - h2.title Add watchers + h2.title(translate="COMMON.WATCHERS.ADD") fieldset - input(type="text", data-maxlength="500", placeholder="Search for users", ng-model="usersSearch") + input(type="text", data-maxlength="500", placeholder="{{'LIGHTBOX.ASSIGNED_TO.SEARCH' | translate}}", ng-model="usersSearch") div.watchers //- The content of this is rendered by directive diff --git a/app/partials/common/tag/lb-tag-line-tags.jade b/app/partials/common/tag/lb-tag-line-tags.jade index 203e54bc..fb6be1eb 100644 --- a/app/partials/common/tag/lb-tag-line-tags.jade +++ b/app/partials/common/tag/lb-tag-line-tags.jade @@ -1,5 +1,5 @@ <% _.each(tags, function(tag) { %> span(class="tag", style!="<%- tag.style %>") span.tag-name <%- tag.name %> - a(href="", title="delete tag", class="icon icon-delete") -<% }); %> \ No newline at end of file + a(href="", title="{{ 'COMMON.TAGS.DELETE' | translate }}", class="icon icon-delete") +<% }); %> diff --git a/app/partials/common/tag/lb-tag-line.jade b/app/partials/common/tag/lb-tag-line.jade index 22b8813b..1c06a23e 100644 --- a/app/partials/common/tag/lb-tag-line.jade +++ b/app/partials/common/tag/lb-tag-line.jade @@ -1,3 +1,3 @@ .tags-container -input(type="text", placeholder="I'm it! Tag me...", class="tag-input") -a(href="", title="Save", class="save icon icon-floppy hidden") +input(type="text", placeholder="{{'COMMON.TAGS.PLACEHOLDER' | translate}}", class="tag-input") +a(href="", title="{{'COMMON.SAVE' | translate}}", class="save icon icon-floppy hidden") diff --git a/app/partials/common/tag/tag-line.jade b/app/partials/common/tag/tag-line.jade index cdac294f..c7df1c3a 100644 --- a/app/partials/common/tag/tag-line.jade +++ b/app/partials/common/tag/tag-line.jade @@ -1,7 +1,7 @@ .tags-container -a(href="#", class="add-tag hidden", title="Add tag") +a(href="#", class="add-tag hidden", title="{{'COMMON.TAGS.ADD' | translate}}") span.icon.icon-plus - span.add-tag-text Add tag + span.add-tag-text(translate="COMMON.TAGS.ADD") -input(type="text", placeholder="I'm it! Tag me...", class="tag-input hidden") -a(href="", title="Save", class="save icon icon-floppy hidden") \ No newline at end of file +input(type="text", placeholder="{{'COMMON.TAGS.PLACEHOLDER' | translate}}", class="tag-input hidden") +a(href="", title="{{'COMMON.SAVE' | translate}}", class="save icon icon-floppy hidden") \ No newline at end of file diff --git a/app/partials/common/tag/tags-line-tags.jade b/app/partials/common/tag/tags-line-tags.jade index 5be6c1fa..c9b0dbd9 100644 --- a/app/partials/common/tag/tags-line-tags.jade +++ b/app/partials/common/tag/tags-line-tags.jade @@ -2,6 +2,6 @@ span(class="tag", style!="border-left: 5px solid <%- tag.color %>;") span.tag-name <%- tag.name %> <% if (isEditable) { %> - a(href="", title="delete tag", class="icon icon-delete") + a(href="", title="{{ 'COMMON.TAGS.DELETE' | translate }}", class="icon icon-delete") <% } %> -<% }); %> \ No newline at end of file +<% }); %> diff --git a/app/partials/common/wysiwyg/wysiwyg-markitup-preview.jade b/app/partials/common/wysiwyg/wysiwyg-markitup-preview.jade index 814b728f..a674385d 100644 --- a/app/partials/common/wysiwyg/wysiwyg-markitup-preview.jade +++ b/app/partials/common/wysiwyg/wysiwyg-markitup-preview.jade @@ -1,5 +1,5 @@ .preview .actions - a(href="#" title="Edit" class="icon icon-edit edit") + a(href="#" title="{{'COMMON.WYSIWYG.EDIT_BUTTON' | translate}}" class="icon icon-edit edit") .content.wysiwyg | <%= data %> diff --git a/app/partials/contrib/main.jade b/app/partials/contrib/main.jade index 80474817..cc9a2b5e 100644 --- a/app/partials/contrib/main.jade +++ b/app/partials/contrib/main.jade @@ -1,12 +1,10 @@ -block head - title Taiga Your agile, free, and open source project management tool +doctype html -block content - div.wrapper.roles(ng-init="section='admin'", ng-controller="ContribController as ctrl") - sidebar.menu-secondary.sidebar(tg-admin-navigation="contrib") - include ../includes/modules/admin-menu +div.wrapper.roles(ng-init="section='admin'", ng-controller="ContribController as ctrl") + sidebar.menu-secondary.sidebar(tg-admin-navigation="contrib") + include ../includes/modules/admin-menu - sidebar.menu-tertiary.sidebar - include ../includes/modules/admin/admin-submenu-contrib + sidebar.menu-tertiary.sidebar + include ../includes/modules/admin/admin-submenu-contrib - section.main.admin-common.admin-contrib(ng-include="pluginTemplate") + section.main.admin-common.admin-contrib(ng-include="pluginTemplate") diff --git a/app/partials/custom-attributes/custom-attribute-value-edit.jade b/app/partials/custom-attributes/custom-attribute-value-edit.jade index d3c3aabc..900518bb 100644 --- a/app/partials/custom-attributes/custom-attribute-value-edit.jade +++ b/app/partials/custom-attributes/custom-attribute-value-edit.jade @@ -11,4 +11,4 @@ form.custom-field-single.editable input#custom-field-description(name="description", type="text", value!="<%- value %>") div.custom-field-options - a.icon.icon-floppy(href="", title="Save Custom Field") + a.icon.icon-floppy(href="", title="{{'COMMON.CUSTOM_ATTRIBUTES.SAVE' | translate}}") diff --git a/app/partials/custom-attributes/custom-attribute-value.jade b/app/partials/custom-attributes/custom-attribute-value.jade index b2502c04..499bce57 100644 --- a/app/partials/custom-attributes/custom-attribute-value.jade +++ b/app/partials/custom-attributes/custom-attribute-value.jade @@ -13,5 +13,5 @@ div.custom-field-single <% if (isEditable) { %> div.custom-field-options - a.icon.icon-edit(href="", title="Edit Custom Field") + a.icon.icon-edit(href="", title="{{'COMMON.CUSTOM_ATTRIBUTES.EDIT' | translate}}") <% } %> diff --git a/app/partials/custom-attributes/custom-attributes-values.jade b/app/partials/custom-attributes/custom-attributes-values.jade index cadbb100..3c34c6e1 100644 --- a/app/partials/custom-attributes/custom-attributes-values.jade +++ b/app/partials/custom-attributes/custom-attributes-values.jade @@ -1,6 +1,6 @@ section.duty-custom-fields(ng-show="ctrl.customAttributes.length") div.custom-fields-header - span Custom Fields + span(translate="COMMON.CUSTOM_ATTRIBUTES.CUSTOM_FIELDS") // Remove .open class on click on this button in both .icon and .custom-fields-body to close a.icon.icon-arrow-bottom(class!="<% if (!collapsed) { %>open<% } %>") div.custom-fields-body(class!="<% if (!collapsed) { %>open<% } %>") diff --git a/app/partials/error/error.jade b/app/partials/error/error.jade index 5e3da8ed..356339f8 100644 --- a/app/partials/error/error.jade +++ b/app/partials/error/error.jade @@ -1,7 +1,10 @@ +doctype html + div.error-main div.error-container object.logo-svg(type="image/svg+xml", data="/svg/logo.svg") img(src="/images/logo.png", alt="TAIGA") h1.logo Taiga - p.error-text Something happened and our Oompa Loompas are working on it.
Try reloading again soon. - a(href="/", title="") Take me home + p.error-text(translate="ERROR.TEXT1") + p.error-text(translate="ERROR.TEXT2") + a(href="/", title="", translate="COMMON.GO_HOME") diff --git a/app/partials/error/not-found.jade b/app/partials/error/not-found.jade index faf411b2..12172038 100644 --- a/app/partials/error/not-found.jade +++ b/app/partials/error/not-found.jade @@ -1,7 +1,9 @@ +doctype html + div.error-main div.error-container object.logo-svg(type="image/svg+xml", data="/svg/logo.svg") img(src="/images/logo.png", alt="TAIGA") - h1.logo Not found - p.error-text Error 404. The page you are looking for no longer exists. Perhaps you can return back to TAIGA homepage and see if you can find what you are looking for. - a(href="/", title="") Take me home + h1.logo(translate="ERROR.NOT_FOUND") + p.error-text(translate="ERROR.NOT_FOUND_TEXT") + a(href="/", title="", translate="COMMON.GO_HOME") diff --git a/app/partials/error/permission-denied.jade b/app/partials/error/permission-denied.jade index a855c2af..6f3b8efb 100644 --- a/app/partials/error/permission-denied.jade +++ b/app/partials/error/permission-denied.jade @@ -1,7 +1,9 @@ +doctype html + div.error-main div.error-container object.logo-svg(type="image/svg+xml", data="/svg/logo.svg") img(src="/images/logo.png", alt="TAIGA") - h1.logo Permission denied - p.error-text Error 403. - a(href="/", title="") Take me home + h1.logo(translate="ERROR.PERMISSION_DENIED") + p.error-text(translate="ERROR.PERMISSION_DENIED_CODE") + a(href="/", title="", translate="COMMON.GO_HOME") diff --git a/app/partials/includes/components/addnewtask.jade b/app/partials/includes/components/addnewtask.jade index 0ec02634..fd25ed2d 100644 --- a/app/partials/includes/components/addnewtask.jade +++ b/app/partials/includes/components/addnewtask.jade @@ -1,6 +1,6 @@ a.icon.icon-plus(tg-check-permission="add_task", - href="", title="Add a new Task", + href="", title="{{'TASKBOARD.TITLE_ACTION_ADD' | translate}}", ng-click="ctrl.addNewTask('standard', us)") a.icon.icon-bulk(tg-check-permission="add_task", - href="", title="Add some new Tasks in bulk", + href="", title="{{'TASKBOARD.TITLE_ACTION_ADD_BULK' | translate}}", ng-click="ctrl.addNewTask('bulk', us)") diff --git a/app/partials/includes/components/addnewus.jade b/app/partials/includes/components/addnewus.jade index 403c271c..52f59b9a 100644 --- a/app/partials/includes/components/addnewus.jade +++ b/app/partials/includes/components/addnewus.jade @@ -1,9 +1,9 @@ div.new-us - a.button-green(href="", title="Add a new User Story", + a.button-green(href="", title="{{'US.ADD' | translate}}", ng-click="ctrl.addNewUs('standard')", tg-check-permission="add_us") - span.text + Add a new User Story - a.button-bulk(href="", title="Add some new User Stories in bulk", + span.text {{'US.ADD' | translate}} + a.button-bulk(href="", title="{{'US.ADD_BULK' | translate}}", ng-click="ctrl.addNewUs('bulk')", tg-check-permission="add_us") span.icon.icon-bulk diff --git a/app/partials/includes/components/backlog-row.jade b/app/partials/includes/components/backlog-row.jade index 8498f107..fb8ebfc0 100644 --- a/app/partials/includes/components/backlog-row.jade +++ b/app/partials/includes/components/backlog-row.jade @@ -10,16 +10,16 @@ div.row.us-item-row(ng-repeat="us in visibleUserstories track by us.id", tg-bind span(ng-bind="us.subject") div.us-settings a.icon.icon-edit(tg-check-permission="modify_us", href="", - ng-click="ctrl.editUserStory(us)", title="Edit") + ng-click="ctrl.editUserStory(us)", title="{{'COMMON.EDIT' | translate}}") a.icon.icon-delete(tg-check-permission="delete_us", href="", - ng-click="ctrl.deleteUserStory(us)", title="Delete") + ng-click="ctrl.deleteUserStory(us)", title="{{'COMMON.DELETE' | translate}}") - div.status(tg-us-status="us" on-update="ctrl.loadProjectStats()") - a.us-status(href="", title="Status Name") + div.status(tg-us-status="us" on-update="ctrl.updateUserStoryStatus()") + a.us-status(href="", title="{{'BACKLOG.STATUS_NAME' | translate}}") span.us-status-bind span.icon.icon-arrow-bottom(tg-check-permission="modify_us") div.points(tg-backlog-us-points="us") - a.us-points(href="", title="Points") + a.us-points(href="", title="{{'COMMON.FIELDS.POINTS' | translate}}") - a.icon.icon-drag-v(tg-check-permission="modify_us", href="", title="Drag") + a.icon.icon-drag-v(tg-check-permission="modify_us", href="", title="{{'COMMON.DRAG' | translate}}") diff --git a/app/partials/includes/components/beta.jade b/app/partials/includes/components/beta.jade index 08f38297..a82f61ed 100644 --- a/app/partials/includes/components/beta.jade +++ b/app/partials/includes/components/beta.jade @@ -1 +1 @@ -img.beta(src="/images/beta.png", title="We are on beta!") +img.beta(src="/images/beta.png", title="{{'COMMON.BETA' | translate}}") diff --git a/app/partials/includes/components/filter.jade b/app/partials/includes/components/filter.jade deleted file mode 100644 index 19d8392f..00000000 --- a/app/partials/includes/components/filter.jade +++ /dev/null @@ -1,5 +0,0 @@ -// Depreacted, should be removed when any -// other static template not need it. -a.single-filter(href="", title="filter") - span.name filter - span.number 23 diff --git a/app/partials/includes/components/large-summary.jade b/app/partials/includes/components/large-summary.jade deleted file mode 100644 index ed410e63..00000000 --- a/app/partials/includes/components/large-summary.jade +++ /dev/null @@ -1,36 +0,0 @@ -div.summary.large-summary - div.large-summary-wrapper - div - div.summary-progress-bar - div.current-progress - div.data - span.number 30% - span.description completed - div.summary-stats - span.number 12 - span.description project
points - div.summary-stats - span.number 23 - span.description defined
points - div.summary-stats - span.number 12 - span.description assigned
points - div.summary-stats.summary-stats-divider - span.number 23 - span.description closed
points - - div.summary-stats - span.icon.icon-bulk - span.number 73 - span.description created
tasks - div.summary-stats - span.number 72 - span.description closed
tasks - div.summary-stats - span.number 18 - span.description remaining
tasks - div.summary-stats - span.icon.icon-iocaine - span.number 10 - span.description iocanie
doses - a.icon.icon-stats.toggle-analytics-visibility(href="", title="Show statistics") diff --git a/app/partials/includes/components/mainTitle.jade b/app/partials/includes/components/mainTitle.jade index 9e15a6bb..8e7fa75d 100644 --- a/app/partials/includes/components/mainTitle.jade +++ b/app/partials/includes/components/mainTitle.jade @@ -1,2 +1,2 @@ header - h1(tg-main-title) + h1(tg-main-title, project-name="project.name", i18n-section-name="{{ sectionName }}") diff --git a/app/partials/includes/components/notification-message.jade b/app/partials/includes/components/notification-message.jade index cb227eaa..d0feaeaf 100644 --- a/app/partials/includes/components/notification-message.jade +++ b/app/partials/includes/components/notification-message.jade @@ -10,21 +10,19 @@ //-See coffe/modules/base/confirm.coffee div.notification-message.notification-message-success - div.icon.icon-notification-success div.text - h4.warning Everything is ok - p Our oompa Loompas saved all your changes! - a.icon.icon-delete(href="", title="Close notification") + h4.warning(translate="NOTIFICATION.OK") + p(translate="NOTIFICATION.SAVED") div.notification-message.notification-message-error div.icon.icon-notification-error div.text - h4.warning Oops, something happened... - p Our oompa Loompas are sad, your changes were not saved! - a.icon.icon-delete(href="", title="Close notification") + h4.warning(translate="NOTIFICATION.WARNING") + p(translate="NOTIFICATION.WARNING_TEXT") + a.icon.icon-delete(href="", title="{{'NOTIFICATION.CLOSE' | translate}}") div.notification-light.notification-message-light-error div.text - h4.warning Oops, something happened... - p Our oompa Loompas are sad, your changes were not saved! - a.icon.icon-delete(href="", title="Close notification") + h4.warning(translate="NOTIFICATION.WARNING") + p(translate="NOTIFICATION.WARNING_TEXT") + a.icon.icon-delete(href="", title="{{'NOTIFICATION.CLOSE' | translate}}") diff --git a/app/partials/includes/components/select-color.jade b/app/partials/includes/components/select-color.jade index 0a519b2d..3f9f4306 100644 --- a/app/partials/includes/components/select-color.jade +++ b/app/partials/includes/components/select-color.jade @@ -23,4 +23,4 @@ div.popover.select-color li.color(style="background: #2e3436", data-color="#2e3436") input(type="text", placeholder="personalized colors", ng-model="color") - div.selected-color(style="background-color: {{ color }}") + div.selected-color(ng-style="{'background-color': color}") diff --git a/app/partials/includes/components/sprint-summary.jade b/app/partials/includes/components/sprint-summary.jade index 64d6bdbb..caa16ba2 100644 --- a/app/partials/includes/components/sprint-summary.jade +++ b/app/partials/includes/components/sprint-summary.jade @@ -7,22 +7,22 @@ div.summary.large-summary div.summary-stats span.number(ng-bind="stats.totalPointsSum|default:'--'") - span.description total
points + span.description(translate="BACKLOG.SPRINT_SUMMARY.TOTAL_POINTS") div.summary-stats span.number(ng-bind="stats.completedPointsSum|default:'--'") - span.description completed
points + span.description(translate="BACKLOG.SPRINT_SUMMARY.COMPLETED_POINTS") div.summary-stats span.icon.icon-bulk span.number(ng-bind="stats.openTasks|default:'--'") - span.description open
tasks + span.description(translate="BACKLOG.SPRINT_SUMMARY.OPEN_TASKS") div.summary-stats span.number(ng-bind="stats.completed_tasks|default:'--'") - span.description closed
tasks + span.description(translate="BACKLOG.SPRINT_SUMMARY.CLOSED_TASKS") - div.summary-stats(title="Feeling a bit overwhelmed by a task? Make sure others know about it by clicking on Iocaine when editing a task. It's possible to become immune to this (fictional) deadly poison by consuming small amounts over time just as it's possible to get better at what you do by occasionally taking on extra challenges!") + div.summary-stats(title="{{'COMMON.IOCAINE_TEXT' | translate}}") span.icon.icon-iocaine span.number(ng-bind="stats.iocaine_doses|default:'--'") - span.description iocaine
doses + span.description(translate="BACKLOG.SPRINT_SUMMARY.IOCAINE_DOSES") - a.icon.icon-stats.toggle-analytics-visibility(href="", title="Show statistics") + a.icon.icon-stats.toggle-analytics-visibility(href="", title="{{'BACKLOG.SPRINT_SUMMARY.SHOW_STATISTICS_TITLE' | translate}}") diff --git a/app/partials/includes/components/summary.jade b/app/partials/includes/components/summary.jade index 11624d8d..1b29810d 100644 --- a/app/partials/includes/components/summary.jade +++ b/app/partials/includes/components/summary.jade @@ -6,13 +6,13 @@ div.summary div.summary-stats span.number(ng-bind="stats.total_points") -- - span.description project
points + span.description(translate="BACKLOG.SUMMARY.PROJECT_POINTS") div.summary-stats span.number(ng-bind="stats.defined_points") -- - span.description defined
points + span.description(translate="BACKLOG.SUMMARY.DEFINED_POINTS") div.summary-stats span.number(ng-bind="stats.closed_points") -- - span.description closed
points + span.description(translate="BACKLOG.SUMMARY.CLOSED_POINTS") div.summary-stats span.number(ng-bind="stats.speed | number:0") -- - span.description points /
sprint + span.description(translate="BACKLOG.SUMMARY.POINTS_PER_SPRINT") diff --git a/app/partials/includes/components/taskboard-task.jade b/app/partials/includes/components/taskboard-task.jade index 7460a74f..dd34369e 100644 --- a/app/partials/includes/components/taskboard-task.jade +++ b/app/partials/includes/components/taskboard-task.jade @@ -1,11 +1,11 @@ div.taskboard-tagline(tg-colorize-tags="task.tags", tg-colorize-tags-type="taskboard") div.taskboard-task-inner div.taskboard-user-avatar(tg-taskboard-user-avatar, users="usersById", task="task", project="project", ng-class="{iocaine: task.is_iocaine}") - span.icon.icon-iocaine(ng-if="task.is_iocaine", title="Feeling a bit overwhelmed by a task? Make sure others know about it by clicking on Iocaine when editing a task. It's possible to become immune to this (fictional) deadly poison by consuming small amounts over time just as it's possible to get better at what you do by occasionally taking on extra challenges!") + span.icon.icon-iocaine(ng-if="task.is_iocaine", title="{{'COMMON.IOCAINE_TEXT' | translate}}") p.taskboard-text - a.task-assigned(href="", title="Assign task") + a.task-assigned(href="", title="{{'TASKBOARD.TITLE_ACTION_ASSIGN' | translate}}") span.task-num(tg-bo-ref="task.ref") a.task-name(href="", title="#{{ ::task.ref }} {{ ::task.subject }}", ng-bind="task.subject", tg-nav="project-tasks-detail:project=project.slug,ref=task.ref") a.icon.icon-edit(tg-check-permission="modify_task", - href="", title="Edit task") + href="", title="{{'TASKBOARD.TITLE_ACTION_EDIT' | translate}}") diff --git a/app/partials/includes/components/watchers.jade b/app/partials/includes/components/watchers.jade deleted file mode 100644 index cbc03c5b..00000000 --- a/app/partials/includes/components/watchers.jade +++ /dev/null @@ -1,13 +0,0 @@ -//- Father [section.watchers] should be out of the template -div.watchers-header - span.title watchers - a.icon.icon-plus(href="", title="Add watcher") -div.watchers-content - - for(var y=0; y<5; y++) - div.watcher-single - div.watcher-avatar - a.avatar(href="", title="Assigned to") - img(src="http://thecodeplayer.com/u/uifaces/32.jpg", alt="username") - div.watcher-name - a(href="", title="Jesús Espino") Jesús - a.icon.icon-delete(href="", title="delete-watcher") diff --git a/app/partials/includes/modules/admin-menu.jade b/app/partials/includes/modules/admin-menu.jade index 0ab40adf..56eab9f8 100644 --- a/app/partials/includes/modules/admin-menu.jade +++ b/app/partials/includes/modules/admin-menu.jade @@ -1,30 +1,30 @@ section.admin-menu header - h1 Admin + h1(translate="ADMIN.MENU.TITLE") nav ul li#adminmenu-project-profile a(href="", tg-nav="project-admin-project-profile-details:project=project.slug") - span.title Project + span.title(translate="ADMIN.MENU.PROJECT") span.icon.icon-arrow-right li#adminmenu-project-values a(href="", tg-nav="project-admin-project-values-status:project=project.slug") - span.title Attributes + span.title(translate="ADMIN.MENU.ATTRIBUTES") span.icon.icon-arrow-right li#adminmenu-memberships a(href="" tg-nav="project-admin-memberships:project=project.slug") - span.title Members + span.title(translate="ADMIN.MENU.MEMBERS") span.icon.icon-arrow-right li#adminmenu-roles a(href="" tg-nav="project-admin-roles:project=project.slug") - span.title Permissions + span.title(translate="ADMIN.MENU.PERMISSIONS") span.icon.icon-arrow-right li#adminmenu-third-parties a(href="" tg-nav="project-admin-third-parties-webhooks:project=project.slug") - span.title Integrations + span.title(translate="ADMIN.MENU.INTEGRATIONS") span.icon.icon-arrow-right li#adminmenu-contrib(ng-show="adminPlugins.length > 0") a(href="" tg-nav="project-admin-contrib:project=project.slug,plugin=adminPlugins[0].slug") - span.title Plugins + span.title(translate="COMMON.PLUGINS") span.icon.icon-arrow-right diff --git a/app/partials/includes/modules/admin-submenu-project-profile.jade b/app/partials/includes/modules/admin-submenu-project-profile.jade index 30be41da..404b6d52 100644 --- a/app/partials/includes/modules/admin-submenu-project-profile.jade +++ b/app/partials/includes/modules/admin-submenu-project-profile.jade @@ -1,26 +1,26 @@ section.admin-submenu header - h1 Project Profile + h1(translate="ADMIN.SUBMENU_PROJECT_PROFILE.TITLE") nav ul li#adminmenu-details a(href="", tg-nav="project-admin-project-profile-details:project=project.slug") - span.title Project Details + span.title(translate="ADMIN.PROJECT_PROFILE.PROJECT_DETAILS") span.icon.icon-arrow-right li#adminmenu-default-values a(href="", tg-nav="project-admin-project-profile-default-values:project=project.slug") - span.title Default Values + span.title(translate="ADMIN.PROJECT_DEFAULT_VALUES.TITLE") span.icon.icon-arrow-right li#adminmenu-modules a(href="", tg-nav="project-admin-project-profile-modules:project=project.slug") - span.title Modules + span.title(translate="ADMIN.MODULES.TITLE") span.icon.icon-arrow-right li#adminmenu-export a(href="", tg-nav="project-admin-project-profile-export:project=project.slug") - span.title Export + span.title(translate="ADMIN.PROJECT_EXPORT.TITLE") span.icon.icon-arrow-right li#adminmenu-reports a(href="", tg-nav="project-admin-project-profile-reports:project=project.slug") - span.title Reports + span.title(translate="ADMIN.REPORTS.TITLE") span.icon.icon-arrow-right diff --git a/app/partials/includes/modules/admin-submenu-project-values.jade b/app/partials/includes/modules/admin-submenu-project-values.jade index 57df5300..73047d78 100644 --- a/app/partials/includes/modules/admin-submenu-project-values.jade +++ b/app/partials/includes/modules/admin-submenu-project-values.jade @@ -1,35 +1,35 @@ section.admin-submenu header - h1 Attributes + h1(translate="ADMIN.SUBMENU_PROJECT_ATTRIBUTES.TITLE") nav ul li#adminmenu-values-status a(href="", tg-nav="project-admin-project-values-status:project=project.slug") - span.title Status + span.title(translate="ADMIN.SUBMENU_PROJECT_VALUES.STATUS") span.icon.icon-arrow-right li#adminmenu-values-points a(href="", tg-nav="project-admin-project-values-points:project=project.slug") - span.title Points + span.title(translate="ADMIN.SUBMENU_PROJECT_VALUES.POINTS") span.icon.icon-arrow-right li#adminmenu-values-priorities a(href="", tg-nav="project-admin-project-values-priorities:project=project.slug") - span.title Priorities + span.title(translate="ADMIN.SUBMENU_PROJECT_VALUES.PRIORITIES") span.icon.icon-arrow-right li#adminmenu-values-severities a(href="", tg-nav="project-admin-project-values-severities:project=project.slug") - span.title Severities + span.title(translate="ADMIN.SUBMENU_PROJECT_VALUES.SEVERITIES") span.icon.icon-arrow-right li#adminmenu-values-types a(href="", tg-nav="project-admin-project-values-types:project=project.slug") - span.title Types + span.title(translate="ADMIN.SUBMENU_PROJECT_VALUES.TYPES") span.icon.icon-arrow-right li#adminmenu-values-custom-fields a(href="", tg-nav="project-admin-project-values-custom-fields:project=project.slug") - span.title Custom fields + span.title(translate="ADMIN.SUBMENU_PROJECT_VALUES.CUSTOM_FIELDS") span.icon.icon-arrow-right diff --git a/app/partials/includes/modules/admin-submenu-roles.jade b/app/partials/includes/modules/admin-submenu-roles.jade index 3b5b12e0..08827eff 100644 --- a/app/partials/includes/modules/admin-submenu-roles.jade +++ b/app/partials/includes/modules/admin-submenu-roles.jade @@ -1,6 +1,6 @@ section.admin-submenu-roles header - h1 Roles + h1(translate="ADMIN.SUBMENU_ROLES.TITLE") nav ul @@ -10,6 +10,6 @@ section.admin-submenu-roles span.icon.icon-arrow-right div(tg-new-role) - a.button-gray.add-button(href="", title="Add New Role") - span.text + New role + a.button-gray.add-button(href="", title="{{'ADMIN.SUBMENU_ROLES.TITLE_ACTION_NEW_ROLE' | translate}}") + span.text(translate="ADMIN.SUBMENU_ROLES.ACTION_NEW_ROLE") input(type="text", class="hidden new") diff --git a/app/partials/includes/modules/admin-submenu-third-parties.jade b/app/partials/includes/modules/admin-submenu-third-parties.jade index 2e30e607..b045c4ee 100644 --- a/app/partials/includes/modules/admin-submenu-third-parties.jade +++ b/app/partials/includes/modules/admin-submenu-third-parties.jade @@ -1,6 +1,6 @@ section.admin-submenu header - h1 Services + h1(translate="ADMIN.SUBMENU_THIDPARTIES.TITLE") nav ul diff --git a/app/partials/includes/modules/admin-submenu.jade b/app/partials/includes/modules/admin-submenu.jade deleted file mode 100644 index ecd19c37..00000000 --- a/app/partials/includes/modules/admin-submenu.jade +++ /dev/null @@ -1,24 +0,0 @@ -section.admin-submenu - header - h1 Roles - - nav - ul - li - a(href="") UX - span.icon.icon-arrow-right - li - a(href="") Product Owner - span.icon.icon-arrow-right - li - a(href="") Designer - span.icon.icon-arrow-right - li - a(href="") Back - span.icon.icon-arrow-right - li - a(href="") Front - span.icon.icon-arrow-right - - a.button-gray(href="", title="Add New role") - span.text + New role diff --git a/app/partials/includes/modules/admin/admin-custom-attributes.jade b/app/partials/includes/modules/admin/admin-custom-attributes.jade index 09186600..1872a0a9 100644 --- a/app/partials/includes/modules/admin/admin-custom-attributes.jade +++ b/app/partials/includes/modules/admin/admin-custom-attributes.jade @@ -1,15 +1,15 @@ section.custom-fields-table.basic-table div.project-values-title - h2 #{customFieldSectionTitle} - a.button.button-gray.show-add-new.js-add-custom-field-button(href="", title="#{customFieldButtonTitle}") - span Add custom field + h2 {{ customFieldSectionTitle | translate }} + a.button.button-gray.show-add-new.js-add-custom-field-button(href="", title="{{ customFieldButtonTitle | translate }}") + span(translate="ADMIN.CUSTOM_ATTRIBUTES.ADD") div.table-header div.row div.custom-name - span Name + span(translate="COMMON.FIELDS.NAME") div.custom-description - span Description + span(translate="COMMON.FIELDS.DESCRIPTION") div.custom-options div.table-body @@ -23,31 +23,31 @@ section.custom-fields-table.basic-table span {{ attr.description }} div.custom-options div.custom-options-wrapper - a.js-edit-custom-field-button.icon.icon-edit(href="", title="Edit Custom Field") - a.js-delete-custom-field-button.icon.icon-delete(href="", title="Delete Custom Field") + a.js-edit-custom-field-button.icon.icon-edit(href="", title="{{'ADMIN.CUSTOM_ATTRIBUTES.EDIT' | translate}}") + a.js-delete-custom-field-button.icon.icon-delete(href="", title="{{'ADMIN.CUSTOM_ATTRIBUTES.DELETE' | translate}}") div.row.single-custom-field.js-edit-custom-field.hidden fieldset.custom-name - input(type="text", name="name", placeholder="Set your custom field name", + input(type="text", name="name", placeholder="{{'ADMIN.CUSTOM_ATTRIBUTES.SET_FIELD_NAME' | translate}}", ng-model="attr.name", data-required="true" data-maxlength="64") fieldset.custom-description - input(type="text", name="description", placeholder="Set your custom field description", + input(type="text", name="description", placeholder="{{'ADMIN.CUSTOM_ATTRIBUTES.SET_FIELD_DESCRIPTION' | translate}}", ng-model="attr.description") fieldset.custom-options div.custom-options-wrapper - a.js-update-custom-field-button.icon.icon-floppy(href="", title="Update Custom Field") - a.js-cancel-edit-custom-field-button.icon.icon-delete(href="", title="Cancel edition") + a.js-update-custom-field-button.icon.icon-floppy(href="", title="{{'ADMIN.CUSTOM_ATTRIBUTES.ACTION_UPDATE' | translate}}") + a.js-cancel-edit-custom-field-button.icon.icon-delete(href="", title="{{'ADMIN.CUSTOM_ATTRIBUTES.ACTION_CANCEL_EDITION' | translate}}") form.row.single-custom-field.js-new-custom-field.hidden fieldset.custom-name - input(type="text", name="name", placeholder="Set your custom field name", + input(type="text", name="name", placeholder="{{'ADMIN.CUSTOM_ATTRIBUTES.SET_FIELD_NAME' | translate}}", ng-model="newAttr.name", data-required="true", data-maxlength="64") fieldset.custom-description - input(type="text", name="description", placeholder="Set your custom field description", + input(type="text", name="description", placeholder="{{'ADMIN.CUSTOM_ATTRIBUTES.SET_FIELD_DESCRIPTION' | translate}}", ng-model="newAttr.description") fieldset.custom-options div.custom-options-wrapper - a.js-create-custom-field-button.icon.icon-floppy(href="", title="Save Custom Field") - a.js-cancel-new-custom-field-button.icon.icon-delete(href="", title="Cancel creation") + a.js-create-custom-field-button.icon.icon-floppy(href="", title="{{'ADMIN.CUSTOM_ATTRIBUTES.SAVE_TITLE' | translate}}") + a.js-cancel-new-custom-field-button.icon.icon-delete(href="", title="{{'ADMIN.CUSTOM_ATTRIBUTES.CANCEL_TITLE' | translate}}") diff --git a/app/partials/includes/modules/admin/admin-membership-table.jade b/app/partials/includes/modules/admin/admin-membership-table.jade index 490c5cf0..8ddb19f5 100644 --- a/app/partials/includes/modules/admin/admin-membership-table.jade +++ b/app/partials/includes/modules/admin/admin-membership-table.jade @@ -1,9 +1,9 @@ section.admin-membership-table.basic-table div.row.title - div.header-member Member - div.header-admin Admin - div.header-role Role - div.header-status Status + div.header-member(translate="ADMIN.MEMBERSHIP.COLUMN_MEMBER") + div.header-admin(translate="ADMIN.MEMBERSHIP.COLUMN_ADMIN") + div.header-role(translate="ADMIN.MEMBERSHIP.COLUMN_ROLE") + div.header-status(translate="ADMIN.MEMBERSHIP.COLUMN_STATUS") div.row(ng-repeat="member in memberships") div.row-member(tg-memberships-row-avatar="member") diff --git a/app/partials/includes/modules/admin/admin-submenu-contrib.jade b/app/partials/includes/modules/admin/admin-submenu-contrib.jade index c4e429e4..d3ee28ec 100644 --- a/app/partials/includes/modules/admin/admin-submenu-contrib.jade +++ b/app/partials/includes/modules/admin/admin-submenu-contrib.jade @@ -1,6 +1,6 @@ section.admin-submenu header - h1 Plugins + h1(translate="COMMON.PLUGINS") nav ul diff --git a/app/partials/includes/modules/admin/default-values.jade b/app/partials/includes/modules/admin/default-values.jade index 6cff329a..a8ab9e6e 100644 --- a/app/partials/includes/modules/admin/default-values.jade +++ b/app/partials/includes/modules/admin/default-values.jade @@ -1,40 +1,40 @@ section.default-values form fieldset - label(for="default-points") Default value for points selector + label(for="default-points", translate="ADMIN.DEFAULT_VALUES.LABEL_POINTS") select(id="default-points", ng-model="project.default_points", ng-options="s.id as s.name for s in pointsList") fieldset - label(for="default-value-us") Default value for US status selector + label(for="default-value-us", translate="ADMIN.DEFAULT_VALUES.LABEL_US") select(id="default-value-us", ng-model="project.default_us_status", ng-options="s.id as s.name for s in usStatusList") fieldset - label(for="default-value-task") Default value for task status selector + label(for="default-value-task", translate="ADMIN.DEFAULT_VALUES.LABEL_TASK_STATUS") select(id="default-value-task", ng-model="project.default_task_status", ng-options="s.id as s.name for s in taskStatusList") fieldset - label(for="default-value-priority") Default value for priority selector + label(for="default-value-priority", translate="ADMIN.DEFAULT_VALUES.LABEL_PRIORITY") select(id="default-value-priority", ng-model="project.default_priority", ng-options="s.id as s.name for s in prioritiesList") fieldset - label(for="default-value-severity") Default value for severity selector + label(for="default-value-severity", translate="ADMIN.DEFAULT_VALUES.LABEL_SEVERITY") select(id="default-value-severity", ng-model="project.default_severity", ng-options="s.id as s.name for s in severitiesList") fieldset - label(for="default-value-issue-type") Default value for issue type selector + label(for="default-value-issue-type", translate="ADMIN.DEFAULT_VALUES.LABEL_ISSUE_TYPE") select(id="default-value-issue-type", ng-model="project.default_issue_type", ng-options="s.id as s.name for s in issueTypesList") fieldset - label(for="default-value-issue-status") Default value for issue status selector + label(for="default-value-issue-status", translate="ADMIN.DEFAULT_VALUES.LABEL_ISSUE_STATUS") select(id="default-value-issue-status", ng-model="project.default_issue_status", ng-options="s.id as s.name for s in issueStatusList") fieldset - button.button-green.submit-button(type="submit", title="Save") - span Save + button.button-green.submit-button(type="submit", title="{{'COMMON.SAVE' | translate}}") + span(translate="COMMON.SAVE") diff --git a/app/partials/includes/modules/admin/project-csv.jade b/app/partials/includes/modules/admin/project-csv.jade deleted file mode 100644 index 07254021..00000000 --- a/app/partials/includes/modules/admin/project-csv.jade +++ /dev/null @@ -1,16 +0,0 @@ -section.project-csv(ng-controller='#{controller} as ctrl', tg-select-input-text) - div.project-values-title - h2 #{csvType} reports - a.button.button-gray(title="Download #{csvType} CSV", ng-href="{{csvUrl}}", ng-show="csvUrl", target="_blank") - span Download CSV - - div.csv-regenerate-field - .field-with-options - input(type="text", placeholder="Please regenerate CSV url", readonly, ng-model="csvUrl") - .option-wrapper.select-input-content - .icon.icon-copy - a(href="", title="Regenerate CSV url", ng-click="ctrl.regenerateUuid()") - span.icon.icon-plus(ng-hide="csvUrl") - span(ng-hide="csvUrl") Generate URL - span.icon.icon-reload(ng-Show="csvUrl") - span(ng-Show="csvUrl") Regenerate diff --git a/app/partials/includes/modules/admin/project-points.jade b/app/partials/includes/modules/admin/project-points.jade index 70ecb29c..ce42b043 100644 --- a/app/partials/includes/modules/admin/project-points.jade +++ b/app/partials/includes/modules/admin/project-points.jade @@ -1,16 +1,16 @@ section.project-values-table div.project-values-title - h2(ng-bind="sectionName") - a.button.button-gray.show-add-new(href="", title="Add New") - span Add new point + h2 {{sectionName | translate}} + a.button.button-gray.show-add-new(href="", title="{{'ADMIN.PROJECT_VALUES_POINTS.ACTION_ADD' | translate}}") + span(translate="ADMIN.PROJECT_VALUES_POINTS.ACTION_ADD") div.project-values-header div.project-values-row div.project-values-name - span Name + span(translate="COMMON.FIELDS.NAME") div.project-values-value - span Value + span(translate="COMMON.FIELDS.VALUE") div.project-values-settings div.project-values-body @@ -26,32 +26,32 @@ section.project-values-table span {{ value.value }} div.project-values-settings - a.edit-value.icon.icon-edit(href="", title="Edit value") - a.delete-value.icon.icon-delete(href="", title="Delete value") + a.edit-value.icon.icon-edit(href="", title="{{'ADMIN.POINTS.TITLE_ACTION_EDIT_VALUE' | translate}}") + a.delete-value.icon.icon-delete(href="", title="{{'ADMIN.POINTS.TITLE_ACTION_DELETE_VALUE' | translate}}") div.project-values-row.row.table-main.edition.hidden div.project-values-name - input(name="name", type="text", placeholder="Name", ng-model="value.name", + input(name="name", type="text", placeholder="{{'COMMON.FIELDS.NAME' | translate}}", ng-model="value.name", data-required="true") div.project-values-value - input(name="value", type="text", placeholder="Value", ng-model="value.value", + input(name="value", type="text", placeholder="{{'COMMON.FIELDS.VALUE' | translate}}", ng-model="value.value", data-type="number") div.project-values-settings - a.save.icon.icon-floppy(href="", title="Save changes") - a.cancel.icon.icon-delete(href="", title="Cancel") + a.save.icon.icon-floppy(href="", title="{{'COMMON.SAVE' | translate}}") + a.cancel.icon.icon-delete(href="", title="{{'COMON.CANCEL' | translate}}") form div.project-values-row.new-value.hidden div.project-values-name - input(name="name", type="text", placeholder="Name", ng-model="newValue.name", + input(name="name", type="text", placeholder="{{'COMMON.FIELDS.NAME' | translate}}", ng-model="newValue.name", data-required="true") div.project-values-value - input("name=value", type="text", placeholder="Value", ng-model="newValue.value", + input("name=value", type="text", placeholder="{{'COMMON.FIELDS.VALUE' | translate}}", ng-model="newValue.value", data-type="number") div.project-values-settings - a.add-new.icon.icon-floppy(href="", title="Add") - a.delete-new.icon.icon-delete(href="", title="Cancel") + a.add-new.icon.icon-floppy(href="", title="{{'COMMON.ADD' | translate}}") + a.delete-new.icon.icon-delete(href="", title="{{'COMMON.CANCEL' | translate}}") diff --git a/app/partials/includes/modules/admin/project-status.jade b/app/partials/includes/modules/admin/project-status.jade index 4e90d97d..087ddc65 100644 --- a/app/partials/includes/modules/admin/project-status.jade +++ b/app/partials/includes/modules/admin/project-status.jade @@ -1,15 +1,15 @@ section.colors-table.admin-status-table div.project-values-title - h2(ng-bind="sectionName") - a.button.button-gray.show-add-new(href="", title="Add New") - span Add new status + h2 {{ sectionName | translate }} + a.button.button-gray.show-add-new(href="", title="{{'ADMIN.US_STATUS.ACTION_ADD_STATUS' | translate}}") + span(translate="ADMIN.US_STATUS.ACTION_ADD_STATUS") div.table-header div.row - div.color-column Color - div.status-name Name - div.status-slug Slug - div.is-closed-column Is closed? + div.color-column(translate="COMMON.FIELDS.COLOR") + div.status-name(translate="COMMON.FIELDS.NAME") + div.status-slug(translate="COMMON.FIELDS.SLUG") + div.is-closed-column(translate="COMMON.FIELDS.IS_CLOSED") div.options-column div.table-main @@ -18,7 +18,7 @@ section.colors-table.admin-status-table div.row.table-main.visualization span.icon.icon-drag-v div.color-column - div.current-color(style="background: {{ value.color }}") + div.current-color(ng-style="{background: value.color}") div.status-name span {{ value.name }} @@ -30,40 +30,40 @@ section.colors-table.admin-status-table div.icon.icon-check-square(ng-show="value.is_closed") div.options-column - a.edit-value.icon.icon-edit(href="", title="Edit value") - a.delete-value.icon.icon-delete(href="", title="Delete value") + a.edit-value.icon.icon-edit(href="", title="{{'ADMIN.COMMON.TITLE_ACTION_EDIT_VALUE' | translate}}") + a.delete-value.icon.icon-delete(href="", title="{{'ADMIN.COMMON.TITLE_ACTION_DELETE_VALUE' | translate}}") div.row.table-main.edition.hidden div.color-column(tg-color-selection, ng-model="value") - div.current-color(style="background: {{ value.color }}") + div.current-color(ng-style="{background: value.color}") include ../../components/select-color div.status-name - input(name="name", type="text", placeholder="Write a name for the new status", + input(name="name", type="text", placeholder="{{'ADMIN.STATUS.PLACEHOLDER_WRITE_STATUS_NAME' | translate}}", ng-model="value.name", data-required="true", data-maxlength="255") div.is-closed-column select(name="is_closed", ng-model="value.is_closed", data-required="true", - ng-options="e.id as e.name for e in [{'id':true, 'name':'Yes'},{'id':false, 'name': 'No'}]") + ng-options="e.id as e.name | translate for e in [{'id':true, 'name':'COMMON.YES'},{'id':false, 'name': 'COMMON.NO'}]") div.options-column - a.save.icon.icon-floppy(href="", title="Save changes") - a.cancel.icon.icon-delete(href="", title="Cancel") + a.save.icon.icon-floppy(href="", title="{{'COMMON.SAVE' | translate}}") + a.cancel.icon.icon-delete(href="", title="{{'COMMON.CANCEL' | translate}}") form div.row.table-main.new-value.hidden div.color-column(tg-color-selection, ng-model="newValue") - div.current-color(style="background: {{ newValue.color }}") + div.current-color(ng-style="{background: newValue.color}") include ../../components/select-color div.status-name - input(name="name", type="text", placeholder="Write a name for the new status", + input(name="name", type="text", placeholder="{{'ADMIN.STATUS.PLACEHOLDER_WRITE_STATUS_NAME' | translate}}", ng-model="newValue.name", data-required="true", data-maxlength="255") div.is-closed-column select(name="is_closed", ng-model="newValue.is_closed", data-required="true", - ng-options="e.id as e.name for e in [{'id':true, 'name':'Yes'},{'id':false, 'name': 'No'}]") + ng-options="e.id as e.name | translate for e in [{'id':true, 'name': 'COMMON.YES'},{'id':false, 'name': 'COMMON.NO'}]") div.options-column - a.add-new.icon.icon-floppy(href="", title="Add") - a.delete-new.icon.icon-delete(href="", title="Cancel") + a.add-new.icon.icon-floppy(href="", title="{{'COMMON.ADD' | translate}}") + a.delete-new.icon.icon-delete(href="", title="{{'COMMON.CANCEL' | translate}}") diff --git a/app/partials/includes/modules/admin/project-types.jade b/app/partials/includes/modules/admin/project-types.jade index 6d02b520..9d5b1f00 100644 --- a/app/partials/includes/modules/admin/project-types.jade +++ b/app/partials/includes/modules/admin/project-types.jade @@ -1,14 +1,14 @@ section.colors-table div.project-values-title - h2 {{ sectionName }} - a.button.button-gray.show-add-new(href="", title="Add New") - span Add new {{ objName }} + h2 {{ sectionName | translate }} + a.button.button-gray.show-add-new(href="", title="{{ addNewElementText }}") + span(ng-bind="addNewElementText") div.table-header div.row - div.color-column Color - div.status-name Name + div.color-column(translate="COMMON.FIELDS.COLOR") + div.status-name(translate="COMMON.FIELDS.NAME") div.options-column div.table-main @@ -18,38 +18,38 @@ section.colors-table span.icon.icon-drag-v div.color-column - div.current-color(style="background: {{ value.color }}") + div.current-color(ng-style="{background: value.color}") div.status-name span {{ value.name }} div.options-column - a.edit-value.icon.icon-edit(href="", title="Edit value") - a.delete-value.icon.icon-delete(href="", title="Delete value") + a.edit-value.icon.icon-edit(href="", title="{{'ADMIN.COMMON.TITLE_ACTION_EDIT_VALUE' | translate}}") + a.delete-value.icon.icon-delete(href="", title="{{'ADMIN.COMMON.TITLE_ACTION_DELETE_VALUE' | translate}}") div.row.table-main.edition.hidden div.color-column(tg-color-selection, ng-model="value") - div.current-color(style="background: {{ value.color }}") + div.current-color(ng-style="{background: value.color}") include ../../components/select-color div.status-name - input(name="name", type="text", placeholder="Write a name for the new element", + input(name="name", type="text", placeholder="{{'ADMIN.TYPES.PLACEHOLDER_WRITE_NAME' | translate}}", ng-model="value.name", data-required="true", data-maxlength="255") div.options-column - a.save.icon.icon-floppy(href="", title="Save changes") - a.cancel.icon.icon-delete(href="", title="Cancel") + a.save.icon.icon-floppy(href="", title="{{'COMMON.SAVE' | translate}}") + a.cancel.icon.icon-delete(href="", title="{{'COMMON.CANCEL' | translate}}") form div.row.table-main.new-value.hidden div.color-column(tg-color-selection, ng-model="newValue") - div.current-color(style="background: {{ newValue.color }}") + div.current-color(ng-style="{background: newValue.color}") include ../../components/select-color div.status-name - input(name="name", type="text", placeholder="Write a name for the new element", + input(name="name", type="text", placeholder="{{'ADMIN.TYPES.PLACEHOLDER_WRITE_NAME' | translate}}", ng-model="newValue.name", data-required="true", data-maxlength="255") div.options-column - a.add-new.icon.icon-floppy(href="", title="Add") - a.delete-new.icon.icon-delete(href="", title="Cancel") + a.add-new.icon.icon-floppy(href="", title="{{'COMMON.ADD' | translate}}") + a.delete-new.icon.icon-delete(href="", title="{{'COMMON.CANCEL' | translate}}") diff --git a/app/partials/includes/modules/admin/project-us-status.jade b/app/partials/includes/modules/admin/project-us-status.jade index f9f2a8ba..98eea63f 100644 --- a/app/partials/includes/modules/admin/project-us-status.jade +++ b/app/partials/includes/modules/admin/project-us-status.jade @@ -1,19 +1,19 @@ section.project-us-status div.project-values-title - h2(ng-bind="sectionName") - a.button.button-gray.show-add-new(href="", title="Add New") - span Add new status + h2 {{ sectionName | translate }} + a.button.button-gray.show-add-new(href="", title="{{'ADMIN.US_STATUS.ACTION_ADD_STATUS' | translate}}") + span(translate="ADMIN.US_STATUS.ACTION_ADD_STATUS") div.colors-table div.table-header div.row - div.color-column Color - div.status-name Name - div.status-slug Slug - div.is-closed-column Is closed? - div.is-archived-column Is archived? - div.status-wip-limit WIP Limit + div.color-column(translate="COMMON.FIELDS.COLOR") + div.status-name(translate="COMMON.FIELDS.NAME") + div.status-slug(translate="COMMON.FIELDS.SLUG") + div.is-closed-column(translate="COMMON.FIELDS.IS_CLOSED") + div.is-archived-column(translate="ADMIN.US_STATUS.IS_ARCHIVED_COLUMN") + div.status-wip-limit(translate="ADMIN.US_STATUS.WIP_LIMIT_COLUMN") div.options-column div.table-main @@ -23,7 +23,7 @@ section.project-us-status span.icon.icon-drag-v div.color-column - div.current-color(style="background: {{ value.color }}") + div.current-color(ng-style="{background: value.color}") div.status-name span {{ value.name }} @@ -38,59 +38,63 @@ section.project-us-status div.icon.icon-check-square(ng-show="value.is_archived") div.status-wip-limit - span {{ value.wip_limit }} + span(ng-hide="value.is_archived") {{ value.wip_limit }} div.options-column - a.edit-value.icon.icon-edit(href="", title="Edit value") - a.delete-value.icon.icon-delete(href="", title="Delete value") + a.edit-value.icon.icon-edit(href="", title="{{'ADMIN.COMMON.TITLE_ACTION_EDIT_VALUE' | translate}}") + a.delete-value.icon.icon-delete(href="", title="{{'ADMIN.COMMON.TITLE_ACTION_DELETE_VALUE' | translate}}") div.row.table-main.edition.hidden div.color-column(tg-color-selection, ng-model="value") - div.current-color(style="background: {{ value.color }}") + div.current-color(ng-style="{background: value.color}") include ../../components/select-color + div.status-name - input(name="name", type="text", placeholder="Write a name for the new status", + input(name="name", type="text", placeholder="{{'ADMIN.US_STATUS.PLACEHOLDER_WRITE_NAME' | translate}}", ng-model="value.name", data-required="true", data-maxlength="255") div.is-closed-column select(name="is_closed", ng-model="value.is_closed", data-required="true", - ng-options="e.id as e.name for e in [{'id':true, 'name':'Yes'},{'id':false, 'name': 'No'}]") + ng-options="e.id as e.name | translate for e in [{'id':true, 'name':'COMMON.YES'},{'id':false, 'name': 'COMMON.NO'}]") div.is-archived-column select(name="is_archived", ng-model="value.is_archived", data-required="true", - ng-options="e.id as e.name for e in [{'id':true, 'name':'Yes'},{'id':false, 'name': 'No'}]") + ng-options="e.id as e.name | translate for e in [{'id':true, 'name':'COMMON.YES'},{'id':false, 'name': 'COMMON.NO'}]") div.status-wip-limit - input(name="wip_limit", type="number", placeholder="WIP Limit", - ng-model="value.wip_limit", data-type="digits") + input(name="wip_limit", type="number", ng-hide="value.is_archived", + ng-model="value.wip_limit", data-type="digits", + placeholder="{{'ADMIN.US_STATUS.WIP_LIMIT_COLUMN' | translate}}") div.options-column - a.save.icon.icon-floppy(href="", title="Save changes") - a.cancel.icon.icon-delete(href="", title="Cancel") + a.save.icon.icon-floppy(href="", title="{{'COMMON.SAVE' | translate}}") + a.cancel.icon.icon-delete(href="", title="{{'COMMON.CANCEL' | translate}}") form div.row.table-main.new-value.hidden div.color-column(tg-color-selection, ng-model="newValue") - div.current-color(style="background: {{ newValue.color }}") + div.current-color(ng-style="{background: newValue.color}") include ../../components/select-color div.status-name - input(name="name", type="text", placeholder="Write a name for the new status", - ng-model="newValue.name", data-required="true", data-maxlength="255") + input(name="name", type="text", + ng-model="newValue.name", data-required="true", data-maxlength="255", + placeholder="{{'ADMIN.US_STATUS.PLACEHOLDER_WRITE_NAME' | translate}}") div.is-closed-column select(name="is_closed", ng-model="newValue.is_closed", data-required="true", - ng-options="e.id as e.name for e in [{'id':true, 'name':'Yes'},{'id':false, 'name': 'No'}]") + ng-options="e.id as e.name | translate for e in [{'id':true, 'name':'COMMON.YES'},{'id':false, 'name': 'COMMON.NO'}]") div.is-archived-column select(name="is_archived", ng-model="newValue.is_archived", data-required="true", - ng-options="e.id as e.name for e in [{'id':true, 'name':'Yes'},{'id':false, 'name': 'No'}]") + ng-options="e.id as e.name | translate for e in [{'id':true, 'name':'COMMON.YES'},{'id':false, 'name': 'COMMON.NO'}]") div.status-wip-limit - input(name="wip_limit", type="number", placeholder="WIP Limit", - ng-model="newValue.wip_limit", data-type="digits") + input(name="wip_limit", type="number", ng-hide="newValue.is_archived", + ng-model="newValue.wip_limit", data-type="digits", + placeholder="{{'ADMIN.US_STATUS.WIP_LIMIT_COLUMN' | translate}}") div.options-column - a.add-new.icon.icon-floppy(href="", title="Add") - a.delete-new.icon.icon-delete(href="", title="Cancel") + a.add-new.icon.icon-floppy(href="", title="{{'COMMON.ADD' | translate}}") + a.delete-new.icon.icon-delete(href="", title="{{'COMMON.CANCEL' | translate}}") diff --git a/app/partials/includes/modules/backlog-filters.jade b/app/partials/includes/modules/backlog-filters.jade index 4008631b..5533851d 100644 --- a/app/partials/includes/modules/backlog-filters.jade +++ b/app/partials/includes/modules/backlog-filters.jade @@ -1,29 +1,29 @@ section.filters div.filters-inner h1 - span.title filters + span.title(translate="COMMON.FILTERS.TITLE") form fieldset - input(type="text", placeholder="Subject or reference", ng-model="filtersQ") - a.icon.icon-search(href="", title="search") + input(type="text", placeholder="{{'COMMON.FILTERS.INPUT_PLACEHOLDER' | translate}}", ng-model="filtersQ") + a.icon.icon-search(href="", title="{{'COMMON.FILTERS.TITLE_ACTION_FILTER_BUTTON' | translate}}") div.filters-step-cat div.filters-applied h2.hidden.breadcrumb - a.back(href="", title="back to categories") Filters + a.back(href="", title="{{'COMMON.FILTERS.BREADCRUMB_TITLE' | translate}}", translate="BACKLOG.FILTERS.TITLE") span.icon-arrow-right - a.subfilter(href="", title="cat-name") - span.title status + a.subfilter(href="") + span.title(translate="COMMON.FILTERS.BREADCRUMB_STATUS") div.filters-cats ul li - a(href="", title="Status", data-type="statuses") - span.title Status + a(href="", title="{{'BACKLOG.FILTERS.FILTER_CATEGORY_STATUS' | translate}}", data-type="statuses") + span.title(translate="BACKLOG.FILTERS.FILTER_CATEGORY_STATUS") span.icon.icon-arrow-right li - a(href="", title="Tags", data-type="tags") - span.title Tags + a(href="", title="{{'BACKLOG.FILTERS.FILTER_CATEGORY_TAGS' | translate}}", data-type="tags") + span.title(translate="BACKLOG.FILTERS.FILTER_CATEGORY_TAGS") span.icon.icon-arrow-right div.filter-list.hidden diff --git a/app/partials/includes/modules/backlog-table.jade b/app/partials/includes/modules/backlog-table.jade index 95375e3c..ce2c5439 100644 --- a/app/partials/includes/modules/backlog-table.jade +++ b/app/partials/includes/modules/backlog-table.jade @@ -1,9 +1,9 @@ div.backlog-table-header div.row.backlog-table-title - div.user-stories User Stories - div.status Status - div.points(tg-us-role-points-selector, title="Select view per Role") - span.header-points Points + div.user-stories(translate="BACKLOG.TABLE.COLUMN_US") + div.status(translate="COMMON.FIELDS.STATUS") + div.points(tg-us-role-points-selector, title="{{'BACKLOG.TABLE.TITLE_COLUMN_POINTS' | translate}}") + span.header-points(translate="COMMON.FIELDS.POINTS") span.icon.icon-arrow-bottom div.backlog-table-body(tg-backlog-sortable, ng-class="{'show-tags': ctrl.showTags, 'active-filters': ctrl.activeFilters}" ) diff --git a/app/partials/includes/modules/cancel-account-form.jade b/app/partials/includes/modules/cancel-account-form.jade index 979dc25a..cfd79196 100644 --- a/app/partials/includes/modules/cancel-account-form.jade +++ b/app/partials/includes/modules/cancel-account-form.jade @@ -1,11 +1,12 @@ -div.change-email-form-container(tg-cancel-account) - p.change-password-text - strong Cancel your account
- span We're sorry you are leaving the taiga, we hope you enjoyed your stay :) +div.cancel-account(tg-cancel-account) + p + strong(translate="CANCEL_ACCOUNT.TITLE") + p + span(translate="CANCEL_ACCOUNT.SUBTITLE") form fieldset input(type="hidden", name="cancel_token", ng-model="data.cancel_token", data-required="true", - placeholder="cancel account token") + placeholder="{{'CANCEL_ACCOUNT.PLACEHOLDER_INPUT_TOKEN' | translate}}") - button.button-cancel-account.button-gray(type="submit", title="Yes, I'm leaving!") Yes, I'm leaving! + button.button-cancel-account.button-gray(type="submit", title="{{'CANCEL_ACCOUNT.ACTION_LEAVING' | translate}}", translate="CANCEL_ACCOUNT.ACTION_LEAVING") diff --git a/app/partials/includes/modules/category-config.jade b/app/partials/includes/modules/category-config.jade deleted file mode 100644 index 24a8fe44..00000000 --- a/app/partials/includes/modules/category-config.jade +++ /dev/null @@ -1,75 +0,0 @@ -///////////////////////////////////////////////////////////////////////////// -// Included in the admin-roles.jade and in the RolePermissionsDirective // -// in the modules/admin/roles.coffee file. // -///////////////////////////////////////////////////////////////////////////// -div.general-category - | Can do estimations? - div.check - input(type="checkbox", checked) - div -div.category-config-list - div.category-config - div.resume - div.resume-title Attachments - div.count 2/7 - div.summary-role - div.role-summary-single.active - div.role-summary-single.inactive - div.role-summary-single.inactive - div.role-summary-single.active - div.role-summary-single.inactive - div.role-summary-single.inactive - div.icon.icon-arrow-bottom - - div.category-config - div.resume - div.resume-title User stories - div.count 2/7 - div.summary-role - div.role-summary-single.active - div.role-summary-single.inactive - div.icon.icon-arrow-bottom - - div.category-config - div.resume - div.resume-title Issues - div.count 2/7 - div.summary-role - div.role-summary-single.active - div.role-summary-single.inactive - div.icon.icon-arrow-up - div.category-items - div.category-item - | Can modify owned user stories - div.check - input(type="checkbox") - div - div.category-item - | Can delete user story status - div.check - input(type="checkbox", checked) - div - div.category-item - | Can delete user story status - div.check.enabled - input(type="checkbox") - div - div.category-item - | Can delete user story statsu - div.check - input(type="checkbox", checked) - div - div.category-item - | Can delete user story status - div.check - input(type="checkbox") - div - - div.category-config - div.resume - div.resume-title User stories - div.count 2/7 - div.summary-role - div.role-summary-single.active - div.role-summary-single.inactive - div.icon.icon-arrow-bottom diff --git a/app/partials/includes/modules/change-email-form.jade b/app/partials/includes/modules/change-email-form.jade index bd980f8b..74d15ad6 100644 --- a/app/partials/includes/modules/change-email-form.jade +++ b/app/partials/includes/modules/change-email-form.jade @@ -1,12 +1,13 @@ -div.change-email-form-container(tg-change-email) - p.change-password-text - strong Change your email
- span One click more and your email will be updated! +div.change-email-form(tg-change-email) + p + strong(translate="CHANGE_EMAIL_FORM.TITLE") + p + span(translate="CHANGE_EMAIL_FORM.SUBTITLE") form fieldset input(type="hidden", name="email_token", ng-model="data.email_token", data-required="true", - placeholder="change email token") + placeholder="{{'CHANGE_EMAIL_FORM.PLACEHOLDER_INPUT_TOKEN' | translate}}") - a.button-change-email.button-gray(href="", title="Change email") Change email + a.button-change-email.button-gray(href="", title="{{'CHANGE_EMAIL_FORM.ACTION_CHANGE_EMAIL' | translate}}", translate="CHANGE_EMAIL_FORM.ACTION_CHANGE_EMAIL") button(type="submit", class="hidden") diff --git a/app/partials/includes/modules/change-password-from-recovery-form.jade b/app/partials/includes/modules/change-password-from-recovery-form.jade index 22f527df..3c64b179 100644 --- a/app/partials/includes/modules/change-password-from-recovery-form.jade +++ b/app/partials/includes/modules/change-password-from-recovery-form.jade @@ -1,19 +1,20 @@ div.change-password-form-container(tg-change-password-from-recovery) p.change-password-text - strong Create a new Taiga pass
- span And hey, you may want to eat some more iron-rich food, it's good for your brain :P + strong(translate="CHANGE_PASSWORD_RECOVERY_FORM.TITLE") + br + span(translate="CHANGE_PASSWORD_RECOVERY_FORM.SUBTITLE") form fieldset.token-change-password(ng-hide="tokenInParams") input(type="text", name="token", ng-model="data.token", data-required="true", - placeholder="Recover password token") + placeholder="{{'CHANGE_PASSWORD_RECOVERY_FORM.PLACEHOLDER_RECOVER_PASSWORD_TOKEN' | translate}}") a.get-token(href="", tg-nav="forgot-password", - title="Did you need a token to recover your password because you forgot it?") Need one? + title="{{'CHANGE_PASSWORD_RECOVERY_FORM.TITLE_LINK_NEED_TOKEN' | translate}}", translate="CHANGE_PASSWORD_RECOVERY_FORM.LINK_NEED_TOKEN") fieldset input(type="password", name="password", id="password", ng-model="data.password", - data-required="true", placeholder="New password") + data-required="true", placeholder="{{'CHANGE_PASSWORD_RECOVERY_FORM.PLACEHOLDER_NEW_PASSWORD' | translate}}") fieldset input(type="password", name="password2", id="password2", ng-model="data.password2", - data-required="true", data-equalto="#password", placeholder="Re-type new password") + data-required="true", data-equalto="#password", placeholder="{{'CHANGE_PASSWORD_RECOVERY_FORM.PLACEHOLDER_RE_TYPE_NEW_PASSWORD' | translate}}") fieldset - button.button-change-password.button-gray.submit-button(type="submit", title="Reset Password") Reset Password + button.button-change-password.button-gray.submit-button(type="submit", title="{{'CHANGE_PASSWORD_RECOVERY_FORM.ACTION_RESET_PASSWORD' | translate}}", translate="CHANGE_PASSWORD_RECOVERY_FORM.ACTION_RESET_PASSWORD") diff --git a/app/partials/includes/modules/colors-table.jade b/app/partials/includes/modules/colors-table.jade index 6eb9c4fc..b989422c 100644 --- a/app/partials/includes/modules/colors-table.jade +++ b/app/partials/includes/modules/colors-table.jade @@ -1,9 +1,9 @@ section.colors-table div.table-header div.row - div.color-column Color - div.status-name Name - div.is-closed-column Is closed? + div.color-column(translate="COMMON.FIELDS.COLOR") + div.status-name(translate="COMMON.FIELDS.NAME") + div.is-closed-column(translate="COMMON.IS_CLOSED") div.options-column div.table-main @@ -19,16 +19,3 @@ section.colors-table div.options-column a.icon.icon-floppy(href="#") a.icon.icon-delete(href="#") - - - for (var x = 0; x < 50; x++) - div.row.table-main - div.color-column - div.current-color - include ../components/select-color - - div.status-name Ready for test - div.is-closed-column - div.icon.icon-check-square - div.options-column - a.icon.icon-edit(href="#") - a.icon.icon-delete(href="#") diff --git a/app/partials/includes/modules/comment-activity.jade b/app/partials/includes/modules/comment-activity.jade index 352c1669..86eb047d 100644 --- a/app/partials/includes/modules/comment-activity.jade +++ b/app/partials/includes/modules/comment-activity.jade @@ -1,5 +1,5 @@ div.us-activity - a.activity-title(ng-show="ctrl.countChanges(comment)", href="", title="Show activity") + a.activity-title(ng-show="ctrl.countChanges(comment)", href="", title="{{'ACTIVITY.SHOW_ACTIVITY' | translate}}") span(tg-bo-bind="ctrl.buildChangesText(comment)") span.icon.icon-arrow-up @@ -8,8 +8,10 @@ div.us-activity span(tg-bo-bind="key") div.activity-fromto p - strong from
+ strong(translate="COMMON.FROM") + br span(tg-bo-bind="ctrl.getChangeText(change[0])") p - strong to
+ strong(translate="COMMON.TO") + br span(tg-bo-bind="ctrl.getChangeText(change[1])") diff --git a/app/partials/includes/modules/filter-tags.jade b/app/partials/includes/modules/filter-tags.jade deleted file mode 100644 index 8f4ac66f..00000000 --- a/app/partials/includes/modules/filter-tags.jade +++ /dev/null @@ -1,12 +0,0 @@ -section.filter-tags - div.filter-tag.active(style="background-color: red") - div.tag-name Tagname - div.tag-count 4 - - div.filter-tag(style="background-color: blue") - div.tag-name Tagname - div.tag-count 4 - - div.filter-tag(style="background-color: green") - div.tag-name Tagname - div.tag-count 4 \ No newline at end of file diff --git a/app/partials/includes/modules/filters.jade b/app/partials/includes/modules/filters.jade deleted file mode 100644 index 7f3bcde2..00000000 --- a/app/partials/includes/modules/filters.jade +++ /dev/null @@ -1,41 +0,0 @@ -// This template is now not used. It is replaced with -// issues-filters.jade and filters-backlog.jade. - -section.filters - div.filters-inner - h1 - span.title filters - - form - fieldset - input(type="text", placeholder="Subject or reference", ng-model="filtersQ") - a.icon.icon-search(href="", title="search") - h2 - a.hidden(href="", title="cat-name") - span.title status - div.filters-step-cat - div.filters-applied - div.filters-cats - ul - li - a(href="", title="Status", data-type="statuses") - span.title Status - span.icon.icon-arrow-right - li - a(href="", title="Severity", data-type="severities") - span.title Severity - span.icon.icon-arrow-right - li - a(href="", title="Priorities", data-type="priorities") - span.title Priorities - span.icon.icon-arrow-right - li - a(href="", title="Tags", data-type="tags") - span.title Tags - span.icon.icon-arrow-right - li - a(href="", title="Assigned to", data-type="assignedTo") - span.title Assigned to - span.icon.icon-arrow-right - - div.filter-list.hidden diff --git a/app/partials/includes/modules/forgot-form.jade b/app/partials/includes/modules/forgot-form.jade index fe7b595f..ce276287 100644 --- a/app/partials/includes/modules/forgot-form.jade +++ b/app/partials/includes/modules/forgot-form.jade @@ -1,15 +1,14 @@ div.forgot-form-container(tg-forgot-password) p.forgot-text - strong - | Oops, did you forget your password? + strong(translate="FORGOT_PASSWORD_FORM.TITLE") br - | Enter your username or email to get a new one + strong(translate="FORGOT_PASSWORD_FORM.SUBTITLE") form(ng-submit="ctrl.submit()") fieldset input(type="text", name="username", ng-model="data.username", data-required="true", - placeholder="Username or email") + placeholder="{{'FORGOT_PASSWORD_FORM.PLACEHOLDER_FIELD' | translate}}") fieldset - button.button-gray.submit-button.button-forgot(type="submit", title="Reset Password") Reset Password + button.button-gray.submit-button.button-forgot(type="submit", title="{{'FORGOT_PASSWORD_FORM.ACTION_RESET_PASSWORD' | translate}}", translate="FORGOT_PASSWORD_FORM.ACTION_RESET_PASSWORD") - a(href="", title="Login", tg-nav="login") Nah, take me back. I think I remember it. + a(href="", tg-nav="login", translate="FORGOT_PASSWORD_FORM.LINK_CANCEL") diff --git a/app/partials/includes/modules/invitation-login-form.jade b/app/partials/includes/modules/invitation-login-form.jade index ebdd4bbc..ef3ab6e0 100644 --- a/app/partials/includes/modules/invitation-login-form.jade +++ b/app/partials/includes/modules/invitation-login-form.jade @@ -1,13 +1,20 @@ form.login-form - p.form-header I already have a Taiga login + p.form-header(translate="LOGIN_COMMON.HEADER") + fieldset input(type="text", name="username", ng-model="dataLogin.username", data-required="true", - placeholder="Username or email (case sensitive)") + placeholder="{{'LOGIN_COMMON.PLACEHOLDER_AUTH_NAME' | translate}}") + fieldset.login-password input(type="password", name="password", ng-model="dataLogin.password", data-required="true", - placeholder="Password") - a.forgot-pass(href="", tg-nav="forgot-password", title="Did you forgot your password?") Forgot it? + placeholder="{{'LOGIN_COMMON.PLACEHOLDER_AUTH_PASSWORD' | translate}}") + a.forgot-pass(href="", tg-nav="forgot-password", + title="{{'LOGIN_COMMON.TITLE_LINK_FORGOT_PASSWORD' | translate}}", + translate="LOGIN_COMMON.LINK_FORGOT_PASSWORD") + fieldset - button.button-login.button-gray.submit-button(type="submit", title="Enter") Enter + button.button-login.button-gray.submit-button(type="submit", + title="{{'LOGIN_COMMON.ACTION_ENTER' | translate}}", + translate="LOGIN_COMMON.ACTION_ENTER") fieldset(ng-repeat="plugin in contribPlugins|filter:{type: 'auth'}", ng-include="plugin.template") diff --git a/app/partials/includes/modules/invitation-register-form.jade b/app/partials/includes/modules/invitation-register-form.jade index 04ef0fbb..fce13f15 100644 --- a/app/partials/includes/modules/invitation-register-form.jade +++ b/app/partials/includes/modules/invitation-register-form.jade @@ -1,25 +1,25 @@ form.register-form - p.form-header Register a new Taiga account (free) + p.form-header(translate="REGISTER_FORM.TITLE") fieldset input(type="text", name="username", ng-model="dataRegister.username", data-required="true", data-maxlength="255", data-regexp="^[\\w.-]+$", - placeholder="Pick a username (case sensitive)") + placeholder="{{'REGISTER_FORM.PLACEHOLDER_NAME' | translate}}") fieldset input(type="text", name="full_name", ng-model="dataRegister.full_name", data-required="true", data-maxlength="256", - placeholder="Pick your full name") + placeholder="{{'REGISTER_FORM.PLACEHOLDER_FULL_NAME' | translate}}") fieldset input(type="text", name="email", ng-model="dataRegister.email", data-required="true", data-maxlength="255", - placeholder="Your email") + placeholder="{{'REGISTER_FORM.PLACEHOLDER_EMAIL' | translate}}") fieldset input(type="password", name="password", ng-model="dataRegister.password", data-required="true", - placeholder="Set a password") + placeholder="{{'REGISTER_FORM.PLACEHOLDER_PASSWORD' | translate}}") fieldset - button.button-register.button-gray.submit-button(type="submit", title="Sign up") Sign up + button.button-register.button-gray.submit-button(type="submit", title="{{'REGISTER_FORM.ACTION_SIGN_UP' | translate}}", translate="REGISTER_FORM.ACTION_SIGN_UP") tg-terms-notice diff --git a/app/partials/includes/modules/issues-filters.jade b/app/partials/includes/modules/issues-filters.jade index 0de01d96..3b427086 100644 --- a/app/partials/includes/modules/issues-filters.jade +++ b/app/partials/includes/modules/issues-filters.jade @@ -1,52 +1,54 @@ section.filters div.filters-inner h1 - span.title filters + span.title(translate="ISSUES.FILTERS.TITLE") form fieldset - input(type="text", placeholder="Subject or reference", ng-model="filtersQ") - a.icon.icon-search(href="", title="search") + input(type="text", placeholder="{{'ISSUES.FILTERS.INPUT_SEARCH_PLACEHOLDER' | translate}}", + ng-model="filtersQ") + a.icon.icon-search(href="", title="{{'ISSUES.FILTERS.TITLE_ACTION_SEARCH' | translate}}") div.filters-step-cat div.filters-applied - a.hide.button.button-gray.save-filters(href="", title="save", ng-class="{hide: filters.length}") save as custom filter + a.hide.button.button-gray.save-filters(href="", title="{{'COMMON.SAVE' | translate}}", ng-class="{hide: filters.length}", translate="ISSUES.FILTERS.ACTION_SAVE_CUSTOM_FILTER") h2.hidden.breadcrumb - a.back(href="", title="back to categories") Filters + a.back(href="", title="{{'ISSUES.FILTERS.TITLE_BREADCRUMB' | translate}}", translate="ISSUES.FILTERS.BREADCRUMB") span.icon-arrow-right a.subfilter(href="", title="cat-name") - span.title status + span.title(translate="COMMON.FILTERS.BREADCRUMB_STATUS") div.filters-cats ul li - a(href="", title="Type", data-type="types") - span.title Type + a(href="", title="{{ 'ISSUES.FILTERS.CATEGORIES.TYPE' | translate}}", data-type="types") + span.title(translate="ISSUES.FILTERS.CATEGORIES.TYPE") span.icon.icon-arrow-right li - a(href="", title="Status", data-type="statuses") - span.title Status + a(href="", title="{{ 'ISSUES.FILTERS.CATEGORIES.STATUS' | translate}}", data-type="statuses") + span.title(translate="ISSUES.FILTERS.CATEGORIES.STATUS") span.icon.icon-arrow-right li - a(href="", title="Severity", data-type="severities") - span.title Severity + a(href="", title="{{ 'ISSUES.FILTERS.CATEGORIES.SEVERITY' | translate}}", data-type="severities") + span.title(translate="ISSUES.FILTERS.CATEGORIES.SEVERITY") span.icon.icon-arrow-right li - a(href="", title="Priorities", data-type="priorities") - span.title Priorities + a(href="", title="{{ 'ISSUES.FILTERS.CATEGORIES.PRIORITIES' | translate}}", data-type="priorities") + span.title(translate="ISSUES.FILTERS.CATEGORIES.PRIORITIES") span.icon.icon-arrow-right li - a(href="", title="Tags", data-type="tags") - span.title Tags + a(href="", title="{{ 'ISSUES.FILTERS.CATEGORIES.TAGS' | translate}}", data-type="tags") + span.title(translate="ISSUES.FILTERS.CATEGORIES.TAGS") span.icon.icon-arrow-right li - a(href="", title="Assigned to", data-type="assignedTo") - span.title Assigned to + a(href="", title="{{ 'ISSUES.FILTERS.CATEGORIES.ASSIGNED_TO' | translate}}", data-type="assignedTo") + span.title(translate="ISSUES.FILTERS.CATEGORIES.ASSIGNED_TO") span.icon.icon-arrow-right li - a(href="", title="Created by", data-type="createdBy") - span.title Created by + a(href="", title="{{ 'ISSUES.FILTERS.CATEGORIES.CREATED_BY' | translate}}", data-type="createdBy") + span.title(translate="ISSUES.FILTERS.CATEGORIES.CREATED_BY") span.icon.icon-arrow-right li.custom-filters(ng-if="filters.myFilters.length") - a(href="", title="Custom filters", data-type="myFilters") - span.title Custom filters + a(href="", title="{{ 'ISSUES.FILTERS.CATEGORIES.CUSTOM_FILTERS' | translate}}", + data-type="myFilters") + span.title(translate="ISSUES.FILTERS.CATEGORIES.CUSTOM_FILTERS") span.icon.icon-arrow-right div.filter-list.hidden diff --git a/app/partials/includes/modules/issues-table.jade b/app/partials/includes/modules/issues-table.jade index 0c75f311..d3672c83 100644 --- a/app/partials/includes/modules/issues-table.jade +++ b/app/partials/includes/modules/issues-table.jade @@ -1,35 +1,39 @@ section.issues-table.basic-table(ng-class="{empty: !issues.length}") div.row.title - div.level-field(data-fieldname="type") Type - div.level-field(data-fieldname="severity") Severity - div.level-field(data-fieldname="priority") Priority - div.subject(data-fieldname="subject") Subject - div.issue-field(data-fieldname="status") Status - div.created-field(data-fieldname="created_date") Created - div.assigned-field(data-fieldname="assigned_to") Assigned to + div.level-field(data-fieldname="type", translate="ISSUES.TABLE.COLUMNS.TYPE") + div.level-field(data-fieldname="severity", translate="ISSUES.TABLE.COLUMNS.SEVERITY") + div.level-field(data-fieldname="priority", translate="ISSUES.TABLE.COLUMNS.PRIORITY") + div.subject(data-fieldname="subject", translate="ISSUES.TABLE.COLUMNS.SUBJECT") + div.issue-field(data-fieldname="status", translate="ISSUES.TABLE.COLUMNS.STATUS") + div.created-field(data-fieldname="created_date", translate="ISSUES.TABLE.COLUMNS.CREATED") + div.assigned-field(data-fieldname="assigned_to", translate="ISSUES.TABLE.COLUMNS.ASSIGNED_TO") + div.row.table-main(ng-repeat="issue in issues track by issue.id") div.level-field(tg-listitem-type="issue") div.level-field(tg-listitem-severity="issue") div.level-field(tg-listitem-priority="issue") div.subject - a(href="", tg-nav="project-issues-detail:project=project.slug,ref=issue.ref", title="#{{ ::issue.ref }} {{ ::issue.subject }}") + a(href="", tg-nav="project-issues-detail:project=project.slug,ref=issue.ref", + title="#{{ ::issue.ref }} {{ ::issue.subject }}") span(tg-bo-ref="issue.ref") span(ng-bind="issue.subject") div.issue-field(tg-issue-status-inline-edition="issue") - a.issue-status(href="", title="Change status") + a.issue-status(href="", title="{{'ISSUES.TABLE.TITLE_ACTION_CHANGE_STATUS' | translate}}") span.issue-status-bind span.icon.icon-arrow-bottom(tg-check-permission="modify_issue") div.created-field(tg-bo-bind="issue.created_date|momentFormat:'DD MMM YYYY HH:mm'") div.assigned-field(tg-issue-assigned-to-inline-edition="issue") - div.issue-assignedto(title="Assigned to") + div.issue-assignedto(title="{{'ISSUES.TABLE.TITLE_ACTION_ASSIGNED_TO' | translate}}") figure.avatar span.icon.icon-arrow-bottom(tg-check-permission="modify_issue") section.empty.empty-issues(ng-class="{hidden: issues.length}") span.icon.icon-issues - span.title There are no issues to report :-) - span Did you find an issue? - a(href="", title+"Create a new US", ng-click="ctrl.addNewIssue()") Create a new Issue + span.title(translate="ISSUES.TABLE.EMPTY.TITLE") + span(translate="ISSUES.TABLE.EMPTY.SUBTITLE") + a(href="", ng-click="ctrl.addNewIssue()", + title="{{'ISSUES.TABLE.EMPTY.ACTION_CREATE_ISSUE' | translate}}", + translate="ISSUES.TABLE.EMPTY.ACTION_CREATE_ISSUE") diff --git a/app/partials/includes/modules/kanban-table.jade b/app/partials/includes/modules/kanban-table.jade index 4152d5f6..8c624c10 100644 --- a/app/partials/includes/modules/kanban-table.jade +++ b/app/partials/includes/modules/kanban-table.jade @@ -5,22 +5,22 @@ div.kanban-table(tg-kanban-squish-column) span(tg-bo-bind="s.name") div.options - a.icon.icon-vfold.hfold(href="", ng-click='foldStatus(s)' title="Fold Column", ng-class='{hidden:folds[s.id]}') - a.icon.icon-vunfold.hunfold(href="", ng-click='foldStatus(s)', title="Unfold Column", ng-class='{hidden:!folds[s.id]}') + a.icon.icon-vfold.hfold(href="", ng-click='foldStatus(s)' title="{{'KANBAN.TITLE_ACTION_FOLD' | translate}}", ng-class='{hidden:folds[s.id]}') + a.icon.icon-vunfold.hunfold(href="", ng-click='foldStatus(s)', title="{{'KANBAN.TITLE_ACTION_UNFOLD' | translate}}", ng-class='{hidden:!folds[s.id]}') - a.icon.icon-vfold(href="", title="Fold Cards", + a.icon.icon-vfold(href="", title="{{'KANBAN.TITLE_ACTION_FOLD_CARDS' | translate}}", ng-class="{hidden:statusViewModes[s.id] == 'minimized'}", ng-click="ctrl.updateStatusViewMode(s.id, 'minimized')") - a.icon.icon-vunfold(href="", title="Unfold Cards", + a.icon.icon-vunfold(href="", title="{{'KANBAN.TITLE_ACTION_UNFOLD_CARDS' | translate}}", ng-class="{hidden:statusViewModes[s.id] == 'maximized'}", ng-click="ctrl.updateStatusViewMode(s.id, 'maximized')") - a.icon.icon-plus(href="", title="Add New User Story", + a.icon.icon-plus(href="", title="{{'KANBAN.TITLE_ACTION_ADD_US' | translate}}", ng-click="ctrl.addNewUs('standard', s.id)", tg-check-permission="add_us", ng-hide="s.is_archived") - a.icon.icon-bulk(href="", title="Add New bulk", + a.icon.icon-bulk(href="", title="{{'KANBAN.TITLE_ACTION_ADD_BULK' | translate}}", ng-click="ctrl.addNewUs('bulk', s.id)", tg-check-permission="add_us", ng-hide="s.is_archived") @@ -36,7 +36,7 @@ div.kanban-table(tg-kanban-squish-column) div.kanban-uses-box.task-column(ng-class='{vfold:folds[s.id]}', ng-repeat="s in usStatusList track by s.id", tg-kanban-sortable, - tg-kanban-wip-limit="s.wip_limit", + tg-kanban-wip-limit="s", tg-kanban-column-height-fixer, tg-bind-scope) diff --git a/app/partials/includes/modules/lightbox-add-member.jade b/app/partials/includes/modules/lightbox-add-member.jade index dfb3d4eb..624af87f 100644 --- a/app/partials/includes/modules/lightbox-add-member.jade +++ b/app/partials/includes/modules/lightbox-add-member.jade @@ -1,11 +1,11 @@ a.close(href="", title="close") span.icon.icon-delete form - h2.title New Member + h2.title(translate="LIGHTBOX.ADD_MEMBER.TITLE") //- Form is set in a directive .add-member-forms - button.button-green.submit-button(type="submit", title="Create") Create + button.button-green.submit-button(type="submit", title="{{'COMMON.CREATE' | translate}}", translate="COMMON.CREATE") - p.help-text If users are already registered on Taiga, they will be added automatically. Otherwise they will receive an invitation. + p.help-text(translate="LIGHTBOX.ADD_MEMBER.HELP_TEXT") diff --git a/app/partials/includes/modules/lightbox-ask-choice.jade b/app/partials/includes/modules/lightbox-ask-choice.jade index 815c1076..cc7336a0 100644 --- a/app/partials/includes/modules/lightbox-ask-choice.jade +++ b/app/partials/includes/modules/lightbox-ask-choice.jade @@ -1,4 +1,4 @@ -a.close(href="", title="close") +a.close(href="", title="{{'COMMON.CLOSE' | translate}}") span.icon.icon-delete form h2.title @@ -9,7 +9,7 @@ form p.warning div.options - a.button-green(href="", title="Accept") - span Accept - a.button-red(href="", title="Delete") - span Cancel + a.button-green(href="", title="{{'COMMON.ACCEPT' | translate}}") + span(translate="COMMON.ACCEPT") + a.button-red(href="", title="{{'COMMON.CANCEL' | translate}}") + span(translate="COMMON.CANCEL") diff --git a/app/partials/includes/modules/lightbox-attachments.jade b/app/partials/includes/modules/lightbox-attachments.jade deleted file mode 100644 index 8e86d3d5..00000000 --- a/app/partials/includes/modules/lightbox-attachments.jade +++ /dev/null @@ -1,17 +0,0 @@ -fieldset.attachments - div.attachments-header - h3.attachments-title - span.icon.icon-attachment - span.attachments-num 1 - span.attachments-text attachment - a.button-gray(href="", title="Add new attachment") - span + add attachment - div.attachment-body - - for(var x = 0; x < 1; x++) - div.single-attachment - div.attachment-name - span.icon.icon-document - a(href="", title="Attachment pefildeusuario.png") pefildeusuariopefildeusuariopefildeusuario.png - div.attachment-comment - span Comentario sobre el contenido - span.attachment-size (125kb.) diff --git a/app/partials/includes/modules/lightbox-create-issue.jade b/app/partials/includes/modules/lightbox-create-issue.jade index cf36de34..dae01853 100644 --- a/app/partials/includes/modules/lightbox-create-issue.jade +++ b/app/partials/includes/modules/lightbox-create-issue.jade @@ -1,9 +1,9 @@ -a.close(href="", title="close") +a.close(href="", title="{{'COMMON.CLOSE' | translate}}") span.icon.icon-delete form - h2.title Add Issue + h2.title(translate="LIGHTBOX.CREATE_ISSUE.TITLE") fieldset - input(type="text", ng-model="issue.subject", placeholder="Subject", + input(type="text", ng-model="issue.subject", ng-attr-placeholder="{{'COMMON.FIELDS.SUBJECT' | translate}}", data-required="true", data-maxlength="500") div.fieldset-row fieldset @@ -17,7 +17,7 @@ form div.tags-block(tg-lb-tag-line, ng-model="issue.tags") fieldset - textarea.description(placeholder="Description", ng-model="issue.description") + textarea.description(ng-attr-placeholder="{{'COMMON.FIELDS.DESCRIPTION' | translate}}", ng-model="issue.description") // include lightbox-attachments - button.button-green.submit-button(type="submit", title="Create") Create + button.button-green.submit-button(type="submit", title="{{'COMMON.CREATE' | translate}}", translate="COMMON.CREATE") diff --git a/app/partials/includes/modules/lightbox-delete-project.jade b/app/partials/includes/modules/lightbox-delete-project.jade index 843f80f7..0ae8f2ad 100644 --- a/app/partials/includes/modules/lightbox-delete-project.jade +++ b/app/partials/includes/modules/lightbox-delete-project.jade @@ -1,12 +1,12 @@ -a.close(href="", title="close") +a.close(href="", title="{{'close' | translate}}") span.icon.icon-delete form - h2.title Delete project + h2.title(translate="LIGHTBOX.DELETE_PROJECT.TITLE") p - span.question Are you sure you want to delete this project? - span.subtitle All project data US/Tasks/Issues/Sprints/WikiPages will be lost! :-( + span.question(translate="LIGHTBOX.DELETE_PROJECT.QUESTION") + span.subtitle(translate="LIGHTBOX.DELETE_PROJECT.SUBTITLE") div.options - a.button-green(href="", title="Yes, I'm really sure") - span Yes, I'm really sure - a.button-red(href="", title="Cancel") - span Cancel + a.button-green(href="", title="{{'LIGHTBOX.DELETE_PROJECT.CONFIRM' | translate}}") + span(translate="LIGHTBOX.DELETE_PROJECT.CONFIRM") + a.button-red(href="", title="{{'COMMON.CANCEL' | translate}}") + span(translate="COMMON.CANCEL") diff --git a/app/partials/includes/modules/lightbox-feedback.jade b/app/partials/includes/modules/lightbox-feedback.jade index 1aa22336..d985a8a6 100644 --- a/app/partials/includes/modules/lightbox-feedback.jade +++ b/app/partials/includes/modules/lightbox-feedback.jade @@ -1,9 +1,9 @@ -a.close(href="", title="close") +a.close(href="", title="{{'COMMON.CLOSE' | translate}}") span.icon.icon-delete form - h2.title Tell us something... + h2.title(translate="LIGHTBOX.FEEDBACK.TITLE") fieldset textarea(ng-model="feedback.comment", data-required="true", - placeholder="...a bug, some suggestions, something cool... or even your worst nightmare with Taiga") + ng-attr-placeholder="{{'LIGHTBOX.FEEDBACK.COMMENT' | translate}}") fieldset - button.button-green.submit-button(type="submit", title="Send feedback") Send feedback + button.button-green.submit-button(type="submit", title="{{'LIGHTBOX.FEEDBACK.ACTION_SEND' | translate}}", translate="LIGHTBOX.FEEDBACK.ACTION_SEND") diff --git a/app/partials/includes/modules/lightbox-generic-ask.jade b/app/partials/includes/modules/lightbox-generic-ask.jade index e09ef2ae..c51ba250 100644 --- a/app/partials/includes/modules/lightbox-generic-ask.jade +++ b/app/partials/includes/modules/lightbox-generic-ask.jade @@ -1,4 +1,4 @@ -a.close(href="", title="close") +a.close(href="", title="{{'COMMON.CLOSE' | translate}}") span.icon.icon-delete form h2.title @@ -6,7 +6,7 @@ form span.subtitle span.message div.options - a.button-green(href="", title="Accept") - span Accept - a.button-red(href="", title="Delete") - span Cancel + a.button-green(href="", title="{{'COMMON.ACCEPT' | translate}}") + span(translate="COMMON.ACCEPT") + a.button-red(href="", title="{{'COMMON.CANCEL' | translate}}") + span(translate="COMMON.CANCEL") diff --git a/app/partials/includes/modules/lightbox-generic-error.jade b/app/partials/includes/modules/lightbox-generic-error.jade index 75fc6022..ca06f309 100644 --- a/app/partials/includes/modules/lightbox-generic-error.jade +++ b/app/partials/includes/modules/lightbox-generic-error.jade @@ -1,7 +1,7 @@ -a.close(href="", title="close") +a.close(href="", title="{{'COMMON.CLOSE' | translate}}") span.icon.icon-delete section h2.title div.options - a.button-green(href="", title="Accept") - span Accept + a.button-green(href="", title="{{'COMMON.ACCEPT' | translate}}") + span(translate="COMMON.ACCEPT") diff --git a/app/partials/includes/modules/lightbox-generic-loading.jade b/app/partials/includes/modules/lightbox-generic-loading.jade index d4bb9f06..95d01cac 100644 --- a/app/partials/includes/modules/lightbox-generic-loading.jade +++ b/app/partials/includes/modules/lightbox-generic-loading.jade @@ -2,7 +2,7 @@ section div.spin.hidden - img(src="/svg/spinner-circle.svg", alt="loading...") + img(src="/svg/spinner-circle.svg", alt="{{'COMMON.LOADING' | translate}}") div.progress-bar-wrapper.hidden div.bar diff --git a/app/partials/includes/modules/lightbox-generic-success.jade b/app/partials/includes/modules/lightbox-generic-success.jade index 1fd9208b..35828685 100644 --- a/app/partials/includes/modules/lightbox-generic-success.jade +++ b/app/partials/includes/modules/lightbox-generic-success.jade @@ -1,8 +1,8 @@ -a.close(href="", title="close") +a.close(href="", title="{{'COMMON.CLOSE' | translate}}") span.icon.icon-delete section h2.title p.message div.options - a.button-green(href="", title="Accept") - span Accept + a.button-green(href="", title="{{'COMMON.ACCEPT' | translate}}") + span(translate="COMMON.ACCEPT") diff --git a/app/partials/includes/modules/lightbox-issue-bulk.jade b/app/partials/includes/modules/lightbox-issue-bulk.jade index a3d70883..bef68aac 100644 --- a/app/partials/includes/modules/lightbox-issue-bulk.jade +++ b/app/partials/includes/modules/lightbox-issue-bulk.jade @@ -1,8 +1,8 @@ -a.close(href="", title="close") +a.close(href="", title="{{'COMMON.CLOSE' | translate}}") span.icon.icon-delete form - h2.title(tr="common.new-bulk") + h2.title(translate="COMMON.NEW_BULK") fieldset - textarea(cols="200", wrap="off", tg-limit-line-length, tr="placeholder:common.one-item-line", ng-model="new.bulk", data-required="true", data-linewidth="200") + textarea(cols="200", wrap="off", tg-limit-line-length, ng-attr-placeholder="{{'COMMON.ONE_ITEM_LINE' | translate}}", ng-model="new.bulk", data-required="true", data-linewidth="200") - button.button-green.submit-button(type="submit", title="Save") Save + button.button-green.submit-button(type="submit", title="{{'COMMON.SAVE' | translate}}", translate="COMMON.SAVE") diff --git a/app/partials/includes/modules/lightbox-search.jade b/app/partials/includes/modules/lightbox-search.jade index 09ef479f..189c4890 100644 --- a/app/partials/includes/modules/lightbox-search.jade +++ b/app/partials/includes/modules/lightbox-search.jade @@ -1,8 +1,8 @@ -a.close(href="", title="close") +a.close(href="", title="{{'COMMON.CLOSE' | translate}}") span.icon.icon-delete form - h2.title Search + h2.title(translate="LIGHTBOX.SEARCH.TITLE") fieldset - input(type="text", name="text", id="search-text", placeholder="What are you looking for?", data-required="true") + input(type="text", name="text", id="search-text", placeholder="{{'LIGHTBOX.SEARCH.PLACEHOLDER_SEARCH' | translate}}", data-required="true") fieldset - button.button-green.submit-button(type="submit", title="Search") Search \ No newline at end of file + button.button-green.submit-button(type="submit", title="{{' LIGHTBOX.SEARCH.TITLE' | translate}}", translate="LIGHTBOX.SEARCH.TITLE") \ No newline at end of file diff --git a/app/partials/includes/modules/lightbox-sprint-add-edit.jade b/app/partials/includes/modules/lightbox-sprint-add-edit.jade index 61ab85ad..7d9263cd 100644 --- a/app/partials/includes/modules/lightbox-sprint-add-edit.jade +++ b/app/partials/includes/modules/lightbox-sprint-add-edit.jade @@ -1,22 +1,29 @@ -a.close(href="", title="close") +a.close(href="", title="{{'COMMON.CLOSE' | translate}}") span.icon.icon-delete + form - h2.title New Sprint + h2.title(translate="LIGHTBOX.ADD_EDIT_SPRINT.TITLE") fieldset - input.sprint-name(type="text", name="name", placeholder="sprint name", ng-model="sprint.name", - data-required="true", data-maxlength="500") + input.sprint-name(type="text", name="name", ng-model="sprint.name", + data-required="true", data-maxlength="500", + placeholder="{{'LIGHTBOX.ADD_EDIT_SPRINT.PLACEHOLDER_SPRINT_NAME' | translate}}") label.last-sprint-name fieldset.dates div - input.date-start(type="text", name="estimated_start", placeholder="Estimated Start", - ng-model="sprint.estimated_start", data-required="true", tg-date-selector) + input.date-start(type="text", name="estimated_start", + ng-model="sprint.estimated_start", data-required="true", tg-date-selector, + placeholder="{{'LIGHTBOX.ADD_EDIT_SPRINT.PLACEHOLDER_SPRINT_START' | translate}}") div - input.date-end(type="text", name="estimated_finish", placeholder="Estimated End", - ng-model="sprint.estimated_finish", data-required="true", tg-date-selector) + input.date-end(type="text", name="estimated_finish", + ng-model="sprint.estimated_finish", data-required="true", tg-date-selector, + placeholder="{{'LIGHTBOX.ADD_EDIT_SPRINT.PLACEHOLDER_SPRINT_END' | translate}}") - button.button-green.submit-button(type="submit", title="Create") Create + button.button-green.submit-button(type="submit", title="{{'COMMON.CREATE' | translate}}", + translate="COMMON.CREATE") div(tg-check-permission="delete_milestone") - span.delete-sprint.hidden Do you want to delete this sprint? - a.icon.icon-delete(href="", title="delete sprint") + span.delete-sprint.hidden(translate) + span(translate="LIGHTBOX.ADD_EDIT_SPRINT.ACTION_DELETE_SPRINT") + a.icon.icon-delete(href="", + title="{{'LIGHTBOX.ADD_EDIT_SPRINT.TITLE_ACTION_DELETE_SPRINT' | translate}}") diff --git a/app/partials/includes/modules/lightbox-task-bulk.jade b/app/partials/includes/modules/lightbox-task-bulk.jade index 8b1ef334..f07ef517 100644 --- a/app/partials/includes/modules/lightbox-task-bulk.jade +++ b/app/partials/includes/modules/lightbox-task-bulk.jade @@ -1,8 +1,8 @@ -a.close(href="", title="close") +a.close(href="", title="{{'COMMON.CLOSE' | translate}}") span.icon.icon-delete form - h2.title(tr="common.new-bulk") + h2.title(translate="COMMON.NEW_BULK") fieldset - textarea(cols="200", wrap="off", tg-limit-line-length, tr="placeholder:common.one-item-line", ng-model="form.data", data-required="true") + textarea(cols="200", wrap="off", tg-limit-line-length, ng-attr-placeholder="{{'COMMON.ONE_ITEM_LINE' | translate}}", ng-model="form.data", data-required="true") - button.button-green.submit-button(type="submit", title="Save") Save + button.button-green.submit-button(type="submit", title="{{'COMMON.SAVE' | translate}}", translate="COMMON.SAVE") diff --git a/app/partials/includes/modules/lightbox-task-create-edit.jade b/app/partials/includes/modules/lightbox-task-create-edit.jade index 4541d3a4..3c7c7ca7 100644 --- a/app/partials/includes/modules/lightbox-task-create-edit.jade +++ b/app/partials/includes/modules/lightbox-task-create-edit.jade @@ -1,28 +1,28 @@ -a.close(href="", title="close") +a.close(href="", title="{{'COMMON.CLOSE' | translate}}") span.icon.icon-delete form - h2.title(tr="task.title-new") + h2.title(translate="LIGHTBOX.CREATE_EDIT_TASK.TITLE") fieldset - input(type="text", ng-model="task.subject", placeholder="A task subject", + input(type="text", ng-model="task.subject", ng-attr-placeholder="{{'LIGHTBOX.CREATE_EDIT_TASK.PLACEHOLDER_SUBJECT' | translate}}", data-required="true", data-maxlength="500") fieldset select(ng-model="task.status", ng-options="s.id as s.name for s in taskStatusList", - placeholder="Task status") + placeholder="{{'LIGHTBOX.CREATE_EDIT_TASK.PLACEHOLDER_STATUS' | translate}}") fieldset select(ng-model="task.assigned_to", ng-options="s.id as s.full_name_display for s in users", - placeholder="Assigned to") - option(value="") Unassigned + placeholder="{{'Assigned to'}}") + option(value="", translate="LIGHTBOX.CREATE_EDIT_TASK.OPTION_UNASSIGNED") fieldset div.tags-block(tg-lb-tag-line, ng-model="task.tags") fieldset - textarea.description(placeholder="Type a short description", ng-model="task.description") + textarea.description(ng-attr-placeholder="{{'LIGHTBOX.CREATE_EDIT_TASK.PLACEHOLDER_SHORT_DESCRIPTION' | translate}}", ng-model="task.description") div.settings - fieldset.iocaine-flag(title="Feeling a bit overwhelmed by a task? Make sure others know about it by clicking on Iocaine when editing a task. It's possible to become immune to this (fictional) deadly poison by consuming small amounts over time just as it's possible to get better at what you do by occasionally taking on extra challenges!") + fieldset.iocaine-flag(title="{{'COMMON.IOCAINE_TEXT' | translate}}") input(type="checkbox", ng-model="task.is_iocaine", name="iocaine-task", id="iocaine-task", ng-value="true") label.iocaine.trans-button(for="iocaine-task") span.icon.icon-iocaine(for="iocaine-task icon-iocaine") @@ -30,8 +30,8 @@ form fieldset.blocking-flag input(type="checkbox", ng-model="task.is_blocked", name="blocked-task", id="blocked-task", ng-value="true") - label.blocked.trans-button(for="blocked-task", tr="common.blocked") + label.blocked.trans-button(for="blocked-task", translate="COMMON.BLOCKED") tg-blocking-message-input(watch="task.is_blocked", ng-model="task.blocked_note") - button.button-green.submit-button(type="submit", title="Create") Create + button.button-green.submit-button(type="submit", title="{{'COMMON.CREATE' | translate}}", translate="COMMON.CREATE") diff --git a/app/partials/includes/modules/lightbox-us-bulk.jade b/app/partials/includes/modules/lightbox-us-bulk.jade index 45fe85e0..e12442fd 100644 --- a/app/partials/includes/modules/lightbox-us-bulk.jade +++ b/app/partials/includes/modules/lightbox-us-bulk.jade @@ -1,8 +1,8 @@ -a.close(href="", title="close") +a.close(href="", title="{{'COMMON.CLOSE' | translate}}") span.icon.icon-delete form - h2.title(tr="common.new-bulk") + h2.title(translate="COMMON.NEW_BULK") fieldset - textarea(cols="200", wrap="off", tg-limit-line-length, tr="placeholder:common.one-item-line", ng-model="new.bulk", data-required="true", data-linewidth="200") + textarea(cols="200", wrap="off", tg-limit-line-length, ng-attr-placeholder="{{'COMMON.ONE_ITEM_LINE' | translate}}", ng-model="new.bulk", data-required="true", data-linewidth="200") - button.button-green.submit-button(type="submit", title="Save") Save \ No newline at end of file + button.button-green.submit-button(type="submit", title="{{'COMMON.SAVE' | translate}}", translate="COMMON.SAVE") \ No newline at end of file diff --git a/app/partials/includes/modules/lightbox-us-create-edit.jade b/app/partials/includes/modules/lightbox-us-create-edit.jade index bbeb8962..067d5c27 100644 --- a/app/partials/includes/modules/lightbox-us-create-edit.jade +++ b/app/partials/includes/modules/lightbox-us-create-edit.jade @@ -1,39 +1,38 @@ -a.close(href="", title="close") +a.close(href="", title="{{'COMMON.CLOSE' | translate}}") span.icon.icon-delete form - h2.title(tr="us.title-new") + h2.title(translate="LIGHTBOX.CREATE_EDIT_US.TITLE") fieldset - input(type="text", name="subject", ng-model="us.subject", tr="placeholder:common.subject", + input(type="text", name="subject", ng-model="us.subject", placeholder="{{'COMMON.FIELDS.SUBJECT' | translate}}", data-required="true", data-maxlength="500") fieldset.estimation tg-lb-us-estimation(ng-model="us") fieldset - select(name="status", ng-model="us.status", ng-options="s.id as s.name for s in usStatusList", - tr="placeholder:common.status") + select(name="status", ng-model="us.status", ng-options="s.id as s.name for s in usStatusList") fieldset div.tags-block(tg-lb-tag-line, ng-model="us.tags") fieldset textarea.description(name="description", ng-model="us.description", - placeholder="Please add descriptive text to help others better understand this US") + ng-attr-placeholder="{{'LIGHTBOX.CREATE_EDIT_US.PLACEHOLDER_DESCRIPTION' | translate}}") div.settings fieldset.team-requirement input(type="checkbox", name="team_requirement", ng-model="us.team_requirement", id="team-requirement", ng-value="true") - label.requirement.trans-button(for="team-requirement", tr="us.team-requirement") + label.requirement.trans-button(for="team-requirement", translate="US.FIELDS.TEAM_REQUIREMENT") fieldset.client-requirement input(type="checkbox", name="client_requirement", ng-model="us.client_requirement", id="client-requirement", ng-value="true") - label.requirement.trans-button(for="client-requirement", tr="us.client-requirement") + label.requirement.trans-button(for="client-requirement", translate="US.FIELDS.CLIENT_REQUIREMENT") fieldset.blocking-flag input(type="checkbox", name="is_blocked", ng-model="us.is_blocked", id="blocked-us" ng-value="true") - label.blocked.trans-button(for="blocked-us", tr="common.blocked") + label.blocked.trans-button(for="blocked-us", translate="COMMON.BLOCKED") tg-blocking-message-input(watch="us.is_blocked", ng-model="us.blocked_note") - button.button-green.submit-button(type="submit", title="Create") Create + button.button-green.submit-button(type="submit", title="{{'COMMON.CREATE' | translate}}", translate="COMMON.CREATE") diff --git a/app/partials/includes/modules/list-filters-kanban.jade b/app/partials/includes/modules/list-filters-kanban.jade deleted file mode 100644 index 75151fb0..00000000 --- a/app/partials/includes/modules/list-filters-kanban.jade +++ /dev/null @@ -1,12 +0,0 @@ -section.list-filters - ul - li - a.trans-button(href="#") - span.icon.icon-filter - | SHOW FILTERS - - div.new-issue - a.button-green(href="") - span.text + NEW TASK - a.button-bulk(href="") - span.icon.icon-bulk diff --git a/app/partials/includes/modules/list-filters.jade b/app/partials/includes/modules/list-filters.jade index 459540c9..5ebb73a8 100644 --- a/app/partials/includes/modules/list-filters.jade +++ b/app/partials/includes/modules/list-filters.jade @@ -1,7 +1,6 @@ section.list-filters(tg-check-permission="add_issue") div.new-issue a.button-green(href="", ng-click="ctrl.addNewIssue()") - span.text - | + NEW ISSUE + span.text(translate="ISSUES.ACTION_NEW_ISSUE") a.button-bulk(href="", ng-click="ctrl.addIssuesInBulk()") span.icon.icon-bulk diff --git a/app/partials/includes/modules/loader.jade b/app/partials/includes/modules/loader.jade index 957ff663..f818d738 100644 --- a/app/partials/includes/modules/loader.jade +++ b/app/partials/includes/modules/loader.jade @@ -1,4 +1,4 @@ .loader(tg-loader) include ../components/loading-bar div.container - p Loading... + p(translate="COMMON.LOADING") diff --git a/app/partials/includes/modules/login-form.jade b/app/partials/includes/modules/login-form.jade index 3517cbde..18bfa351 100644 --- a/app/partials/includes/modules/login-form.jade +++ b/app/partials/includes/modules/login-form.jade @@ -2,15 +2,15 @@ div.login-form-container(tg-login) form.login-form fieldset input(type="text", name="username", data-required="true", - placeholder="Username or Email (case sensitive)") + placeholder="{{'LOGIN_COMMON.PLACEHOLDER_AUTH_NAME' | translate}}") fieldset.login-password input(type="password", name="password", data-required="true", - placeholder="Password (case sensitive)") + placeholder="{{'LOGIN_COMMON.PLACEHOLDER_AUTH_PASSWORD' | translate}}") // This should be hidden when focus on pass - a.forgot-pass(href="", tg-nav="forgot-password", title="Did you forgot your password?") Forgot it? + a.forgot-pass(href="", tg-nav="forgot-password", title="{{'LOGIN_COMMON.TITLE_LINK_FORGOT_PASSWORD' | translate}}", translate="LOGIN_COMMON.LINK_FORGOT_PASSWORD") fieldset - button.button-green.submit-button(type="submit", title="Sign in") Sign in + button.button-green.submit-button(type="submit", title="{{'LOGIN_COMMON.ACTION_SIGN_IN' | translate}}", translate="LOGIN_COMMON.ACTION_SIGN_IN") fieldset(ng-repeat="plugin in contribPlugins|filter:{type: 'auth'}", ng-include="plugin.template") diff --git a/app/partials/includes/modules/projects-nav.jade b/app/partials/includes/modules/projects-nav.jade index c3d23e0d..2a26f099 100644 --- a/app/partials/includes/modules/projects-nav.jade +++ b/app/partials/includes/modules/projects-nav.jade @@ -1,6 +1,6 @@ .projects-nav-overlay div.container - p Loading project... + p(translate="COMMON.LOADING_PROJECT") div.wizard-create-project(tg-lb-create-project) include wizard-create-project diff --git a/app/partials/includes/modules/register-form.jade b/app/partials/includes/modules/register-form.jade index 5341588a..0b955507 100644 --- a/app/partials/includes/modules/register-form.jade +++ b/app/partials/includes/modules/register-form.jade @@ -3,29 +3,29 @@ div.register-form-container(tg-register) fieldset input(type="text", name="username", ng-model="data.username", data-required="true", data-maxlength="255", data-regexp="^[\\w.-]+$", - placeholder="Pick a username (case sensitive)") + placeholder="{{'REGISTER_FORM.PLACEHOLDER_NAME' | translate}}") fieldset input(type="text", name="full_name", ng-model="data.full_name", data-required="true", data-maxlength="256", - placeholder="Pick your full name") + placeholder="{{'REGISTER_FORM.PLACEHOLDER_FULL_NAME' | translate}}") fieldset input(type="text", name="email", ng-model="data.email", data-required="true", data-maxlength="255", - placeholder="Your email") + placeholder="{{'REGISTER_FORM.PLACEHOLDER_EMAIL' | translate}}") fieldset input(type="password", name="password", ng-model="data.password", data-required="true", data-minlength="4", - placeholder="Set a password (case sensitive)") + placeholder="{{'REGISTER_FORM.PLACEHOLDER_PASSWORD' | translate}}") fieldset - button.button-register.button-gray.submit-button(type="submit", title="Sign up") Sign up + button.button-register.button-gray.submit-button(type="submit", title="{{'REGISTER_FORM.ACTION_SIGN_UP' | translate}}", translate="REGISTER_FORM.ACTION_SIGN_UP") fieldset(tg-github-login-button) // Only displays terms notice when terms plugin is loaded. tg-terms-notice - a.register-text-top(href="", title="Login", tg-nav="login") Are you already registered? Log in + a.register-text-top(href="", title="{{'REGISTER_FORM.TITLE_LINK_LOGIN' | translate}}", tg-nav="login", translate="REGISTER_FORM.LINK_LOGIN") diff --git a/app/partials/includes/modules/related-tasks.jade b/app/partials/includes/modules/related-tasks.jade index fae17e69..37efe89c 100644 --- a/app/partials/includes/modules/related-tasks.jade +++ b/app/partials/includes/modules/related-tasks.jade @@ -1,6 +1,6 @@ section.related-tasks(tg-related-tasks) div.related-tasks-header - span.related-tasks-title Related tasks + span.related-tasks-title(translate="COMMON.RELATED_TASKS") div(tg-related-task-create-button) div.related-tasks-body div.row.single-related-task(ng-repeat="task in tasks", ng-class="{closed: task.is_closed, blocked: task.is_blocked, iocaine: task.is_iocaine}", diff --git a/app/partials/includes/modules/search-filter.jade b/app/partials/includes/modules/search-filter.jade index d2d447fe..22cb8f89 100644 --- a/app/partials/includes/modules/search-filter.jade +++ b/app/partials/includes/modules/search-filter.jade @@ -4,25 +4,25 @@ section.search-filter a.active(href="#") span.icon.icon-bulk span.num 0 - span.name User Stories + span.name(translate="SEARCH.FILTER_USER_STORIES") li.issues(data-name="issues") a(href="#") span.icon.icon-issues span.num 0 - span.name Issues + span.name(translate="SEARCH.FILTER_ISSUES") li.tasks(data-name="tasks") a(href="#") span.icon.icon-bulk span.num 0 - span.name Task + span.name(translate="SEARCH.FILTER_TASKS") li.wikipages(data-name="wikipages") a(href="#") span.icon.icon-wiki span.num 0 - span.name Wiki Pages + span.name(translate="SEARCH.FILTER_WIKI") //- li //- a(href="#") diff --git a/app/partials/includes/modules/search-in.jade b/app/partials/includes/modules/search-in.jade index ab323a37..f121ff1e 100644 --- a/app/partials/includes/modules/search-in.jade +++ b/app/partials/includes/modules/search-in.jade @@ -1,5 +1,5 @@ section.search-in header fieldset - input(type="text", placeholder="Search in...", ng-model="searchTerm") - a.icon.icon-search(href="", title="search") + input(type="text", placeholder="{{'SEARCH.PLACEHOLDER_SEARCH' | translate}}", ng-model="searchTerm") + a.icon.icon-search(href="", title="{{'SEARCH.TITLE_ACTION_SEARCH' | translate}}") diff --git a/app/partials/includes/modules/search-result-table.jade b/app/partials/includes/modules/search-result-table.jade index c22f92a5..aaebd465 100644 --- a/app/partials/includes/modules/search-result-table.jade +++ b/app/partials/includes/modules/search-result-table.jade @@ -4,9 +4,9 @@ script(type="text/ng-template", id="search-issues") div.search-result-table-container(ng-class="{'hidden': !issues.length}", tg-bind-scope) div.search-result-table-header div.row.title - div.user-stories Issues - div.status Status - div.assigned-to Assigned to + div.user-stories(translate="SEARCH.FILTER_ISSUES") + div.status(translate="COMMON.FIELDS.STATUS") + div.assigned-to(translate="COMMON.FIELDS.ASSIGNED_TO") div.search-result-table-body div.row.table-main(ng-repeat="issue in issues track by issue.id") div.user-stories @@ -18,17 +18,17 @@ script(type="text/ng-template", id="search-issues") div.empty.empty-search-results(ng-class="{'hidden': issues.length}") span.icon.icon-issues - span.title It looks like nothing was found with your search criteria. - span Maybe try one of the tabs above or search again + span.title(translate="SEARCH.EMPTY_TITLE") + span(translate="SEARCH.EMPTY_DESCRIPTION") script(type="text/ng-template", id="search-userstories") div.search-result-table-container(ng-class="{'hidden': !userstories.length}", tg-bind-scope) div.search-result-table-header div.row.title - div.user-stories User Stories - div.status Status - div.points Points + div.user-stories(translate="SEARCH.FILTER_USER_STORIES") + div.status(translate="COMMON.FIELDS.STATUS") + div.points(translate="COMMON.FIELDS.POINTS") div.search-result-table-body div.row.table-main(ng-repeat="us in userstories track by us.id") div.user-stories @@ -40,16 +40,16 @@ script(type="text/ng-template", id="search-userstories") div.empty.empty-search-results(ng-class="{'hidden': userstories.length}") span.icon.icon-issues - span.title It looks like nothing was found with your search criteria. - span Maybe try one of the tabs above or search again + span.title(translate="SEARCH.EMPTY_TITLE") + span(translate="SEARCH.EMPTY_DESCRIPTION") script(type="text/ng-template", id="search-tasks") div.search-result-table-container(ng-class="{'hidden': !tasks.length}", tg-bind-scope) div.search-result-table-header div.row.title - div.user-stories Task - div.status Status - div.assigned-to Assigned to + div.user-stories(translate="SEARCH.FILTER_TASKS") + div.status(translate="COMMON.FIELDS.STATUS") + div.assigned-to(translate="COMMON.FIELDS.ASSIGNED_TO") div.search-result-table-body div.row.table-main(ng-repeat="task in tasks track by task.id") div.user-stories @@ -61,14 +61,14 @@ script(type="text/ng-template", id="search-tasks") div.empty.empty-search-results(ng-class="{'hidden': tasks.length}") span.icon.icon-issues - span.title It looks like nothing was found with your search criteria. - span Maybe try one of the tabs above or search again + span.title(translate="SEARCH.EMPTY_TITLE") + span(translate="SEARCH.EMPTY_DESCRIPTION") script(type="text/ng-template", id="search-wikipages") div.search-result-table-container(ng-class="{'hidden': !wikipages.length}", tg-bind-scope) div.search-result-table-header div.row.title - div.user-stories Wiki page + div.user-stories(translate="SEARCH.FILTER_WIKI") div.search-result-table-body div.row.table-main(ng-repeat="wikipage in wikipages track by wikipage.id") div.user-stories @@ -78,5 +78,5 @@ script(type="text/ng-template", id="search-wikipages") div.empty.empty-search-results(ng-class="{'hidden': wikipages.length}") span.icon.icon-issues - span.title It looks like nothing was found with your search criteria. - span Maybe try one of the tabs above or search again + span.title(translate="SEARCH.EMPTY_TITLE") + span(translate="SEARCH.EMPTY_DESCRIPTION") diff --git a/app/partials/includes/modules/sprint.jade b/app/partials/includes/modules/sprint.jade index 7e0037ba..dfc1aabf 100644 --- a/app/partials/includes/modules/sprint.jade +++ b/app/partials/includes/modules/sprint.jade @@ -11,10 +11,11 @@ div.sprint-table ng-class="{closed: us.is_closed, blocked: us.is_blocked}") span(tg-bo-ref="us.ref") span(tg-bo-bind="us.subject") - div.column-points.width-1(tg-bo-bind="us.total_points", ng-class="{closed: us.is_closed, blocked: us.is_blocked}") + div.column-points.width-1(tg-bo-bind="us.total_points", + ng-class="{closed: us.is_closed, blocked: us.is_blocked}") -a.button-gray(tg-bo-title="'Go to Taskboard of ' + sprint.name", - tg-nav="project-taskboard:project=project.slug,sprint=sprint.slug", - tg-check-permission="view_milestones") +a.button-gray(title="{{ 'BACKLOG.SPRINTS.TITLE_LINK_TASKBOARD' | translate:sprint }}", + tg-nav="project-taskboard:project=project.slug,sprint=sprint.slug", + tg-check-permission="view_milestones") - span Sprint Taskboard + span(translate="BACKLOG.SPRINTS.LINK_TASKBOARD") diff --git a/app/partials/includes/modules/sprints.jade b/app/partials/includes/modules/sprints.jade index 2974915a..462b9301 100644 --- a/app/partials/includes/modules/sprints.jade +++ b/app/partials/includes/modules/sprints.jade @@ -1,19 +1,25 @@ section.sprints header - h1 SPRINTS + h1(translate="BACKLOG.SPRINTS.TITLE") div.summary div.total-sprints span.number(ng-bind="project.total_milestones") -- - span.description
sprints - a.button-green.add-sprint(href="", title="Add New sprint", ng-click="ctrl.addNewSprint()", tg-check-permission="add_milestone") - span.text + New sprint + span.description(translate="BACKLOG.SPRINTS.NUMBER_SPRINTS") + a.button-green.add-sprint(href="", title="{{ 'BACKLOG.TITLE_ACTION_NEW_SPRINT' | translate }}", + ng-click="ctrl.addNewSprint()", tg-check-permission="add_milestone") + span.text(translate="BACKLOG.SPRINTS.ACTION_NEW_SPRINT") - div.sprint.sprint-open(ng-repeat="sprint in openSprints track by sprint.id", tg-backlog-sprint="sprint", tg-sprint-sortable) + div.sprint.sprint-open(ng-repeat="sprint in openSprints track by sprint.id", + tg-backlog-sprint="sprint", + tg-sprint-sortable) include sprint - a.filter-closed-sprints(tg-backlog-toggle-closed-sprints-visualization, href="", ng-show="totalClosedMilestones") + a.filter-closed-sprints(href="", tg-backlog-toggle-closed-sprints-visualization, + ng-show="totalClosedMilestones") span.icon.icon-archive - span.text Show closed sprints + span.text(translate="BACKLOG.SPRINTS.ACTION_SHOW_CLOSED_SPRINTS") - div.sprint.sprint-closed(ng-repeat="sprint in closedSprints track by sprint.id" tg-backlog-sprint="sprint", tg-sprint-sortable) + div.sprint.sprint-closed(ng-repeat="sprint in closedSprints track by sprint.id", + tg-backlog-sprint="sprint", + tg-sprint-sortable) include sprint diff --git a/app/partials/includes/modules/taskboard-table.jade b/app/partials/includes/modules/taskboard-table.jade index 6c645a8a..dfd46060 100644 --- a/app/partials/includes/modules/taskboard-table.jade +++ b/app/partials/includes/modules/taskboard-table.jade @@ -1,18 +1,18 @@ div.taskboard-table(tg-taskboard-squish-column) div.taskboard-table-header div.taskboard-table-inner - h2.task-colum-name "User story" + h2.task-colum-name(translate="TASKBOARD.TABLE.COLUMN") h2.task-colum-name(ng-repeat="s in taskStatusList track by s.id", ng-style="{'border-top-color':s.color}", ng-class="{'column-fold':statusesFolded[s.id]}", class="squish-status-{{s.id}}", tg-bo-title="s.name") span(tg-bo-bind="s.name") - a.icon.icon-vfold.hfold(href="", ng-click='foldStatus(s)', title="Fold Column", ng-class='{hidden:statusesFolded[s.id]}') - a.icon.icon-vunfold.hunfold(href="", title="Unfold Column", ng-click='foldStatus(s)', ng-class='{hidden:!statusesFolded[s.id]}') + a.icon.icon-vfold.hfold(href="", ng-click='foldStatus(s)', title="{{'TASKBOARD.TABLE.TITLE_ACTION_FOLD' | translate}}", ng-class='{hidden:statusesFolded[s.id]}') + a.icon.icon-vunfold.hunfold(href="", title="{{'TASKBOARD.TABLE.TITLE_ACTION_UNFOLD' | translate}}", ng-click='foldStatus(s)', ng-class='{hidden:!statusesFolded[s.id]}') div.taskboard-table-body(tg-taskboard-table-height-fixer) div.taskboard-table-inner div.task-row(ng-repeat="us in userstories track by us.id", ng-class="{blocked: us.is_blocked, 'row-fold':usFolded[us.id]}") div.taskboard-userstory-box.task-column(tg-bo-title="us.blocked_note") - a.icon.icon-vfold.vfold(href="", title="Fold Row", ng-click='foldUs(us)', ng-class='{hidden:usFolded[us.id]}') - a.icon.icon-vunfold.vunfold(href="", title="Unfold Row", ng-click='foldUs(us)', ng-class='{hidden:!usFolded[us.id]}') + a.icon.icon-vfold.vfold(href="", title="{{'TASKBOARD.TABLE.TITLE_ACTION_FOLD_ROW' | translate}}", ng-click='foldUs(us)', ng-class='{hidden:usFolded[us.id]}') + a.icon.icon-vunfold.vunfold(href="", title="{{'TASKBOARD.TABLE.TITLE_ACTION_UNFOLD_ROW' | translate}}", ng-click='foldUs(us)', ng-class='{hidden:!usFolded[us.id]}') h3.us-title a(href="", tg-nav="project-userstories-detail:project=project.slug,ref=us.ref", @@ -22,7 +22,7 @@ div.taskboard-table(tg-taskboard-squish-column) span(ng-bind="us.subject") p.points-value span(ng-bind="us.total_points") - span points + span(translate="TASKBOARD.TABLE.FIELD_POINTS") include ../components/addnewtask div.taskboard-tasks-box.task-column(ng-repeat="st in taskStatusList track by st.id", tg-taskboard-sortable, class="squish-status-{{st.id}}", ng-class="{'column-fold':statusesFolded[st.id]}", tg-bind-scope) div.taskboard-task(ng-repeat="task in usTasks[us.id][st.id] track by task.id", @@ -31,10 +31,10 @@ div.taskboard-table(tg-taskboard-squish-column) div.task-row(ng-init="us = null", ng-class="{'row-fold':usFolded[null]}") div.taskboard-userstory-box.task-column - a.icon.icon-vfold.vfold(href="", title="Fold Row", ng-click='foldUs()', ng-class="{hidden:usFolded[null]}") - a.icon.icon-vunfold.vunfold(href="", title="Unfold Row", ng-click='foldUs()', ng-class="{hidden:!usFolded[null]}") + a.icon.icon-vfold.vfold(href="", title="{{'TASKBOARD.TABLE.TITLE_ACTION_FOLD_ROW' | translate}}", ng-click='foldUs()', ng-class="{hidden:usFolded[null]}") + a.icon.icon-vunfold.vunfold(href="", title="{{'TASKBOARD.TABLE.TITLE_ACTION_UNFOLD_ROW' | translate}}", ng-click='foldUs()', ng-class="{hidden:!usFolded[null]}") h3.us-title - span Unassigned tasks + span(translate="TASKBOARD.TABLE.ROW_UNASSIGED_TASKS_TITLE") include ../components/addnewtask.jade div.taskboard-tasks-box.task-column(ng-repeat="st in taskStatusList track by st.id", tg-taskboard-sortable, class="squish-status-{{st.id}}", ng-class="{'column-fold':statusesFolded[st.id]}", tg-bind-scope) div.taskboard-task(ng-repeat="task in usTasks[null][st.id] track by task.id", diff --git a/app/partials/includes/modules/team/team-filters.jade b/app/partials/includes/modules/team/team-filters.jade index 27e2942e..bd0fe677 100644 --- a/app/partials/includes/modules/team/team-filters.jade +++ b/app/partials/includes/modules/team/team-filters.jade @@ -1,11 +1,11 @@ section.team-filters div.team-filters-inner header - h1 filters + h1(translate="COMMON.FILTERS.TITLE") form.search-in fieldset - input(type="text", placeholder="Search by username or role...", ng-model="filtersQ") - a.icon.icon-search(href="", title="search") + input(type="text", placeholder="{{'TEAM.PLACEHOLDER_INPUT_SEARCH' | translate}}", ng-model="filtersQ") + a.icon.icon-search(href="", title="{{'COMMON.FILTERS.TITLE_ACTION_FILTER_BUTTON' | translate}}") nav(tg-team-filters) \ No newline at end of file diff --git a/app/partials/includes/modules/team/team-table.jade b/app/partials/includes/modules/team/team-table.jade index f4e0c739..f2a2e3a2 100644 --- a/app/partials/includes/modules/team/team-table.jade +++ b/app/partials/includes/modules/team/team-table.jade @@ -3,34 +3,34 @@ section.table-team.basic-table div.username div.member-stats div.attribute.attribute-name(ng-if="issuesEnabled") - span Mr. Wolf + span(translate="TEAM.COLUMN_MR_WOLF") div.popover.attribute-explanation - span Closed issues + span(translate="TEAM.EXPLANATION_COLUMN_MR_WOLF") div.attribute(ng-if="tasksEnabled") - span Iocaine Drinker + span(translate="TEAM.COLUMN_IOCAINE") div.popover.attribute-explanation - span Iocaine doses ingested + span(translate="TEAM.EXPLANATION_COLUMN_IOCAINE") div.attribute(ng-if="wikiEnabled") - span Cervantes + span(translate="TEAM.COLUMN_CERVANTES") div.popover.attribute-explanation - span Wiki pages edited + span(translate="TEAM.EXPLANATION_COLUMN_CERVANTES") div.attribute(ng-if="issuesEnabled") - Total Bug Hunter + span(translate="TEAM.COLUMN_BUG_HUNTER") div.popover.attribute-explanation - span Bugs reported + span(translate="TEAM.EXPLANATION_COLUMN_BUG_HUNTER") div.attribute(ng-if="tasksEnabled") - span Night Shift + span(translate="TEAM.COLUMN_NIGHT_SHIFT") div.popover.attribute-explanation - span Tasks closed + span(translate="TEAM.EXPLANATION_COLUMN_NIGHT_SHIFT") div.attribute - Total Power + span(translate="TEAM.COLUMN_TOTAL_POWER") div.popover.attribute-explanation - span Total Points + span(translate="TEAM.EXPLANATION_COLUMN_TOTAL_POWER") div.hero(tg-team-current-user, stats="stats", currentuser="currentUser", projectid="projectId", issuesEnabled="issuesEnabled", tasksenabled="tasksEnabled", wikienabled="wikiEnabled", ng-if="::currentUser") h2(ng-show="memberships.length") - span Team > - span {{filtersRole.name || "All"}} + span(translate="TEAM.SECTION_TITLE_TEAM") + span {{filtersRole.name || ("TEAM.SECTION_FILTER_ALL" | translate)}} section.table-team.basic-table(tg-team-members, memberships="memberships", stats="stats", filtersq="filtersQ", filtersrole="filtersRole", issuesEnabled="issuesEnabled", tasksenabled="tasksEnabled", wikienabled="wikiEnabled") diff --git a/app/partials/includes/modules/user-settings-menu.jade b/app/partials/includes/modules/user-settings-menu.jade index a388e367..e93963a4 100644 --- a/app/partials/includes/modules/user-settings-menu.jade +++ b/app/partials/includes/modules/user-settings-menu.jade @@ -1,18 +1,18 @@ section.admin-menu header - h1 User Settings + h1(translate="USER_SETTINGS.MENU.SECTION_TITLE") nav ul li#usersettingsmenu-user-profile a(href="", tg-nav="user-settings-user-profile:project=project.slug") - span.title User profile + span.title(translate="USER_SETTINGS.MENU.USER_PROFILE") span.icon.icon-arrow-right li#usersettingsmenu-change-password a(href="" tg-nav="user-settings-user-change-password:project=project.slug") - span.title Change password + span.title(translate="USER_SETTINGS.MENU.CHANGE_PASSWORD") span.icon.icon-arrow-right li#usersettingsmenu-mail-notifications a(href="", tg-nav="user-settings-mail-notifications:project=project.slug") - span.title Email notifications + span.title(translate="USER_SETTINGS.MENU.EMAIL_NOTIFICATIONS") span.icon.icon-arrow-right diff --git a/app/partials/includes/modules/user-settings/mail-notifications-table.jade b/app/partials/includes/modules/user-settings/mail-notifications-table.jade index 56c0af7d..f444d758 100644 --- a/app/partials/includes/modules/user-settings/mail-notifications-table.jade +++ b/app/partials/includes/modules/user-settings/mail-notifications-table.jade @@ -2,11 +2,11 @@ section.policy-table div.policy-table-header div.policy-table-row div.policy-table-project - span Project + span(translate="USER_SETTINGS.NOTIFICATIONS.COLUMN_PROJECT") div.policy-table-all - span Receive All + span(translate="USER_SETTINGS.NOTIFICATIONS.COLUMN_RECEIVE_ALL") div.policy-table-involved - span Only Involved + span(translate="USER_SETTINGS.NOTIFICATIONS.COLUMN_ONLY_INVOLVED") div.policy-table-none - span No notifications + span(translate="USER_SETTINGS.NOTIFICATIONS.COLUMN_NO_NOTIFICATIONS") div.policy-table-body(tg-user-notifications-list, ng-model="notifyPolicies") diff --git a/app/partials/includes/modules/wiki-nav.jade b/app/partials/includes/modules/wiki-nav.jade deleted file mode 100644 index e69de29b..00000000 diff --git a/app/partials/includes/modules/wizard-create-project.jade b/app/partials/includes/modules/wizard-create-project.jade index 52075256..e0d3f3d7 100644 --- a/app/partials/includes/modules/wizard-create-project.jade +++ b/app/partials/includes/modules/wizard-create-project.jade @@ -1,8 +1,8 @@ form section.wizard-step.create-step1(data-step="step1") div.title - h1 Choose a template - p Which template would fit better in your project? + h1(translate="WIZARD.SECTION_TITLE_CHOOSE_TEMPLATE") + p(translate="WIZARD.CHOOSE_TEMPLATE_TEXT") div.template-wrapper div.template-inner fieldset(ng-repeat="template in templates") @@ -15,32 +15,32 @@ form p {{ template.description }} fieldset - a.button-next.button.button-green(href="", title="Next") Next + a.button-next.button.button-green(href="", title="{{'PAGINATION.NEXT' | translate}}", translate="PAGINATION.NEXT") section.wizard-step.create-step2.active(data-step="step2") div.title - h1 Create Project - p Fresh and clean. So exciting! + h1(translate="WIZARD.SECTION_TITLE_CREATE_PROJECT") + p(translate="WIZARD.CREATE_PROJECT_TEXT") div.template-wrapper div.template-inner fieldset - input(type="text", name="name", ng-model="data.name", data-required="true", placeholder="Name", maxlength="45") + input(type="text", name="name", ng-model="data.name", data-required="true", placeholder="{{'COMMON.FIELDS.NAME' | translate}}", maxlength="45") fieldset - textarea(name="description", ng-model="data.description", data-required="true", placeholder="Description") + textarea(name="description", ng-model="data.description", data-required="true", ng-attr-placeholder="{{'COMMON.FIELDS.DESCRIPTION' | translate}}") fieldset.wizard-action div - a.button-prev.button.button-gray(href="", title="Prev") Prev - button.button-green.submit-button(type="submit", title="Create") Create + a.button-prev.button.button-gray(href="", title="{{'PAGINATION.PREVIOUS' | translate}}", translate="PAGINATION.PREVIOUS") + button.button-green.submit-button(type="submit", title="{{'COMMON.CREATE' | translate}}", translate="COMMON.CREATE") button(type="submit", class="hidden") div.progress-bar div.progress-state - span Template selection - span Name and description + span(translate="WIZARD.PROGRESS_TEMPLATE_SELECTION") + span(translate="WIZARD.PROGRESS_NAME_DESCRIPTION") // span Final touches div.progress-bar-wrapper div.bar -a.close(href="" title="close") +a.close(href="" title="{{'COMMON.CLOSE' | translate}}") span.icon.icon-delete diff --git a/app/partials/issue/issue-paginator.jade b/app/partials/issue/issue-paginator.jade index 618dd768..4e7271e7 100644 --- a/app/partials/issue/issue-paginator.jade +++ b/app/partials/issue/issue-paginator.jade @@ -2,7 +2,7 @@ ul(class="paginator") <% if (showPrevious) { %> li(class="previous") a(href="", class="previous next_prev_button", class="disabled") - span(i18next="pagination.prev") Prev + span(translate="PAGINATION.PREVIOUS") <% } %> <% _.each(pages, function(item) { %> li(class!="<%- item.classes %>") @@ -18,5 +18,5 @@ ul(class="paginator") <% if (showNext) { %> li(class="next") a(href="", class="next next_prev_button", class="disabled") - span(i18next="pagination.next") Next + span(translate="PAGINATION.NEXT") <% } %> diff --git a/app/partials/issue/issue-priority-button.jade b/app/partials/issue/issue-priority-button.jade index d990b27e..62055e0b 100644 --- a/app/partials/issue/issue-priority-button.jade +++ b/app/partials/issue/issue-priority-button.jade @@ -4,7 +4,8 @@ div(class!="priority-data <% if(editable){ %>clickable<% }%>") <% if(editable){ %> span(class="icon icon-arrow-bottom") <% }%> - span(class="level-name") priority + span(class="level-name", translate="COMMON.FIELDS.PRIORITY") + ul(class="popover pop-priority") <% _.each(priorityes, function(pr) { %> li diff --git a/app/partials/issue/issue-severity-button.jade b/app/partials/issue/issue-severity-button.jade index ec114ab4..6ffe35dd 100644 --- a/app/partials/issue/issue-severity-button.jade +++ b/app/partials/issue/issue-severity-button.jade @@ -4,7 +4,7 @@ div(class!="severity-data <% if(editable){ %>clickable<% }%>") <% if(editable){ %> span(class="icon icon-arrow-bottom") <% }%> - span(class="level-name") severity + span(class="level-name", translate="COMMON.FIELDS.SEVERITY") ul(class="popover pop-severity") <% _.each(severityes, function(sv) { %> diff --git a/app/partials/issue/issue-type-button.jade b/app/partials/issue/issue-type-button.jade index 64db0363..675e7d92 100644 --- a/app/partials/issue/issue-type-button.jade +++ b/app/partials/issue/issue-type-button.jade @@ -4,7 +4,7 @@ div(class!="type-data <% if(editable){ %>clickable<% }%>") <% if(editable){ %> span(class="icon icon-arrow-bottom") <% }%> - span(class="level-name") type + span(class="level-name", translate="COMMON.FIELDS.TYPE") ul(class="popover pop-type") <% _.each(typees, function(tp) { %> diff --git a/app/partials/issue/issues-detail.jade b/app/partials/issue/issues-detail.jade index ab528bc9..e1e780b6 100644 --- a/app/partials/issue/issues-detail.jade +++ b/app/partials/issue/issues-detail.jade @@ -1,3 +1,5 @@ +doctype html + div.wrapper(ng-controller="IssueDetailController as ctrl", ng-init="section='issues'") div.main.us-detail @@ -10,26 +12,29 @@ div.wrapper(ng-controller="IssueDetailController as ctrl", span.us-number(tg-bo-ref="issue.ref") span.us-name(tg-editable-subject, ng-model="issue", required-perm="modify_issue") - p.us-related-task(ng-if="issue.generated_user_stories.length") This issue has been promoted to US: + p.us-related-task(ng-if="issue.generated_user_stories.length") + | {{ 'ISSUES.PROMOTED'|translate }} a(ng-repeat="us in issue.generated_user_stories", tg-check-permission="view_us", href="", tg-bo-title="'#' + us.ref + ' ' + us.subject", tg-nav="project-userstories-detail:project=project.slug, ref=us.ref") span(tg-bo-ref="us.ref") - p.external-reference(ng-if="issue.external_reference") This issue has been created from - a(target="_blank", tg-bo-href="issue.external_reference[1]", title="Go to origin") + p.external-reference(ng-if="issue.external_reference") + | {{ 'ISSUES.EXTERNAL_REFERENCE'|translate }} + a(target="_blank", tg-bo-href="issue.external_reference[1]", + title="{{'ISSUES.GO_TO_EXTERNAL_REFERENCE' | translate}}") span {{ issue.external_reference[1] }} p.block-desc-container(ng-show="issue.is_blocked") - span.block-description-title Blocked - span.block-description(ng-bind="issue.blocked_note || 'This issue is blocked'") + span.block-description-title(translate="COMMON.BLOCKED") + span.block-description(ng-bind="issue.blocked_note || ('ISSUES.BLOCKED' | translate)") div.issue-nav a.icon.icon-arrow-left(ng-show="previousUrl", tg-bo-href="previousUrl", - title="previous issue") + title="{{'ISSUES.TITLE_PREVIOUS_ISSUE' | translate}}") a.icon.icon-arrow-right(ng-show="nextUrl", tg-bo-href="nextUrl", - title="next issue") + title="{{'ISSUES.TITLE_NEXT_ISSUE' | translate}}") div.tags-block(tg-tag-line, ng-model="issue", required-perm="modify_issue") @@ -59,10 +64,10 @@ div.wrapper(ng-controller="IssueDetailController as ctrl", tg-promote-issue-to-us-button(tg-check-permission="add_us", ng-model="issue") tg-block-button(tg-check-permission="modify_issue", ng-model="issue") tg-delete-button(tg-check-permission="delete_issue", - on-delete-title="'Delete issue'", + on-delete-title="{{'ISSUES.ACTION_DELETE' | translate}}", on-delete-go-to-url="onDeleteGoToUrl", ng-model="issue") - div.lightbox.lightbox-block(tg-lb-block, title="Blocking issue", ng-model="issue") + div.lightbox.lightbox-block(tg-lb-block, title="ISSUES.LIGHTBOX_TITLE_BLOKING_ISSUE", ng-model="issue") div.lightbox.lightbox-select-user(tg-lb-assignedto) div.lightbox.lightbox-select-user(tg-lb-watchers) diff --git a/app/partials/issue/issues-filters.jade b/app/partials/issue/issues-filters.jade index a15c3269..8738bc6a 100644 --- a/app/partials/issue/issues-filters.jade +++ b/app/partials/issue/issues-filters.jade @@ -13,4 +13,4 @@ a(class="single-filter", data-type!="<%- f.type %>", data-id!="<%- f.id %>") <% }) %> span(class="new") input(class="hidden my-filter-name", type="text", - placeholder="Write the filter name and press enter") + placeholder="{{'ISSUES.PLACEHOLDER_FILTER_NAME' | translate}}") diff --git a/app/partials/issue/issues-status-button.jade b/app/partials/issue/issues-status-button.jade index d901bf10..6d56fae8 100644 --- a/app/partials/issue/issues-status-button.jade +++ b/app/partials/issue/issues-status-button.jade @@ -4,7 +4,7 @@ div(class!="status-data <% if(editable){ %>clickable<% }%>") <% if(editable){ %> span(class="icon icon-arrow-bottom") <% } %> - span(class="level-name") status + span(class="level-name", translate="COMMON.FIELDS.STATUS") ul(class="popover pop-status") <% _.each(statuses, function(st) { %> diff --git a/app/partials/issue/issues.jade b/app/partials/issue/issues.jade index be94a680..ed8f5ff0 100644 --- a/app/partials/issue/issues.jade +++ b/app/partials/issue/issues.jade @@ -1,3 +1,5 @@ +doctype html + div.wrapper.issues(tg-issues, ng-controller="IssuesController as ctrl", ng-init="section='issues'") sidebar.menu-secondary.extrabar.filters-bar(tg-issues-filters) include ../includes/modules/issues-filters diff --git a/app/partials/issue/promote-issue-to-us-button.jade b/app/partials/issue/promote-issue-to-us-button.jade index 6bbd17c5..6d56172b 100644 --- a/app/partials/issue/promote-issue-to-us-button.jade +++ b/app/partials/issue/promote-issue-to-us-button.jade @@ -1,2 +1,2 @@ a(class="button button-gray editable", tg-check-permission="add_us") - span Promote to User Story + span(translate="ISSUES.ACTION_PROMOTE_TO_US") diff --git a/app/partials/kanban/kanban-task.jade b/app/partials/kanban/kanban-task.jade index 47e931c3..e108a4ab 100644 --- a/app/partials/kanban/kanban-task.jade +++ b/app/partials/kanban/kanban-task.jade @@ -2,22 +2,22 @@ div.kanban-tagline(tg-colorize-tags="us.tags", tg-colorize-tags-type="kanban", n div.kanban-task-inner(ng-class="{'task-archived': us.isArchived}") div.avatar-wrapper(tg-kanban-user-avatar="us.assigned_to", ng-model="us", ng-hide="us.isArchived") div.task-text(ng-hide="us.isArchived") - a.task-assigned(href="", title="Assign User Story") + a.task-assigned(href="", title="{{'US.ASSIGN' | translate}}") span.task-num(tg-bo-ref="us.ref") a.task-name(href="", title="#{{ ::us.ref }} {{ us.subject }}", ng-bind="us.subject", tg-nav="project-userstories-detail:project=project.slug,ref=us.ref", tg-nav-get-params="{\"kanban-status\": {{us.status}}}") - p.task-points(href="", title="Total Us points") + p.task-points(href="", title="{{'US.TOTAL_US_POINTS' | translate}}") span(ng-if="us.total_points !== null", ng-bind="us.total_points") - span(ng-if="us.total_points !== null") points - span(ng-if="us.total_points === null") Not estimated + span.points-text(ng-if="us.total_points !== null", translate="COMMON.FIELDS.POINTS") + span(ng-if="us.total_points === null", translate="US.NOT_ESTIMATED") div.task-archived-text(ng-show="us.isArchived") - p You have archived + p(translate="KANBAN.ARCHIVED") p span.task-num(tg-bo-ref="us.ref") span.task-name(ng-bind="us.subject") - p Drag & drop again to undo + p(translate="KANBAN.UNDO_ARCHIVED") - a.icon.icon-edit(tg-check-permission="modify_us", href="", title="Edit", ng-hide="us.isArchived") + a.icon.icon-edit(tg-check-permission="modify_us", href="", title="{{'COMMON.EDIT' | translate}}", ng-hide="us.isArchived") diff --git a/app/partials/kanban/kanban.jade b/app/partials/kanban/kanban.jade index 606098d0..7a85f542 100644 --- a/app/partials/kanban/kanban.jade +++ b/app/partials/kanban/kanban.jade @@ -1,3 +1,5 @@ +doctype html + div.wrapper(tg-kanban, ng-controller="KanbanController as ctrl" ng-init="section='kanban'") section.main.kanban diff --git a/app/partials/project/project-colors.jade b/app/partials/project/project-colors.jade deleted file mode 100644 index bab64a73..00000000 --- a/app/partials/project/project-colors.jade +++ /dev/null @@ -1,17 +0,0 @@ -div.wrapper - sidebar.menu-secondary.sidebar - include ../includes/modules/admin-menu - - sidebar.menu-tertiary.sidebar - include ../includes/modules/admin-submenu - - section.main.project-colors - header - include ../includes/components/mainTitle - - div.project-colors-options - a.button-green.new-color(href="") - span.text - | + Add new status - - include ../includes/modules/colors-table diff --git a/app/partials/project/project-menu.jade b/app/partials/project/project-menu.jade index ea56ff56..4eeaede7 100644 --- a/app/partials/project/project-menu.jade +++ b/app/partials/project/project-menu.jade @@ -1,65 +1,65 @@ div(class="menu-container") ul(class="main-nav") li(id="nav-search") - a(href="" title="Search") + a(href="" title="{{'PROJECT.SECTION.SEARCH' | translate}}") span(class="icon icon-search") - span(class="item") Search + span(class="item", translate="PROJECT.SECTION.SEARCH") <% if (project.is_backlog_activated && project.my_permissions.indexOf("view_us") != -1) { %> li(id="nav-backlog") - a(href="" title="Backlog" tg-nav="project-backlog:project=project.slug") + a(href="" title="{{'PROJECT.SECTION.BACKLOG' | translate}}" tg-nav="project-backlog:project=project.slug") span(class="icon icon-backlog") - span(class="item") Backlog + span(class="item", translate="PROJECT.SECTION.BACKLOG") <% } %> <% if (project.is_kanban_activated && project.my_permissions.indexOf("view_us") != -1) { %> li(id="nav-kanban") - a(href="" title="Kanban" tg-nav="project-kanban:project=project.slug") + a(href="" title="{{'PROJECT.SECTION.KANBAN' | translate}}" tg-nav="project-kanban:project=project.slug") span(class="icon icon-kanban") - span(class="item") Kanban + span(class="item", translate="PROJECT.SECTION.KANBAN") <% } %> <% if (project.is_issues_activated && project.my_permissions.indexOf("view_issues") != -1) { %> li(id="nav-issues") - a(href="" title="Issues" tg-nav="project-issues:project=project.slug") + a(href="" title="{{'PROJECT.SECTION.ISSUES' | translate}}" tg-nav="project-issues:project=project.slug") span(class="icon icon-issues") - span(class="item") Issues + span(class="item", translate="PROJECT.SECTION.ISSUES") <% } %> <% if (project.is_wiki_activated && project.my_permissions.indexOf("view_wiki_pages") != -1) { %> li(id="nav-wiki") - a(href="" title="Wiki" tg-nav="project-wiki:project=project.slug") + a(href="" title="{{'PROJECT.SECTION.WIKI' | translate}}" tg-nav="project-wiki:project=project.slug") span(class="icon icon-wiki") - span(class="item") Wiki + span(class="item", translate="PROJECT.SECTION.WIKI") <% } %> li(id="nav-team") - a(href="" title="Team" tg-nav="project-team:project=project.slug") + a(href="" title="{{'PROJECT.SECTION.TEAM' | translate}}" tg-nav="project-team:project=project.slug") span(class="icon icon-team") - span(class="item") Team + span(class="item", translate="PROJECT.SECTION.TEAM") <% if (project.videoconferences) { %> li(id="nav-video") - a(href!="<%- project.videoconferenceUrl %>" target="_blank" title="Meet Up") + a(href!="<%- project.videoconferenceUrl %>" target="_blank" title="{{'PROJECT.SECTION.MEETUP' | translate}}") span(class="icon icon-video") - span(class="item") Meet Up + span(class="item", translate="PROJECT.SECTION.MEETUP") <% } %> <% if (project.i_am_owner) { %> li(id="nav-admin") - a(href="" tg-nav="project-admin-home:project=project.slug" title="Admin") + a(href="" tg-nav="project-admin-home:project=project.slug" title="{{'PROJECT.SECTION.ADMIN' | translate}}") span(class="icon icon-settings") - span(class="item") Admin + span(class="item", translate="PROJECT.SECTION.ADMIN") <% } %> <% if (user) { %> div(class="user") div(class="user-settings") ul(class="popover") li - a(href="" title="User Profile", tg-nav="user-settings-user-profile:project=project.slug") User Profile + a(href="" title="{{'USER_SETTINGS.POPOVER.USER_PROFILE' | translate}}", tg-nav="user-settings-user-profile:project=project.slug", translate="USER_SETTINGS.POPOVER.USER_PROFILE") li - a(href="" title="Change Password", tg-nav="user-settings-user-change-password:project=project.slug") Change Password + a(href="" title="{{'USER_SETTINGS.POPOVER.CHANGE_PASSWORD' | translate}}", tg-nav="user-settings-user-change-password:project=project.slug", translate="USER_SETTINGS.POPOVER.CHANGE_PASSWORD") li - a(href="" title="Notifications", tg-nav="user-settings-mail-notifications:project=project.slug") Notifications + a(href="" title="{{'USER_SETTINGS.POPOVER.NOTIFICATIONS' | translate}}", tg-nav="user-settings-mail-notifications:project=project.slug", translate="USER_SETTINGS.POPOVER.NOTIFICATIONS") <% if (feedbackEnabled) { %> li - a(href="" class="feedback" title="Feedback") Feedback + a(href="" class="feedback" title="{{'USER_SETTINGS.POPOVER.FEEDBACK' | translate}}", translate="USER_SETTINGS.POPOVER.FEEDBACK") <% } %> li - a(href="" title="Logout" class="logout") Logout - a(href="" title="User preferences" class="avatar" id="nav-user-settings") + a(href="" title="{{'COMMON.LOGOUT' | translate}}" class="logout", translate="COMMON.LOGOUT") + a(href="" title="{{'USER_SETTINGS.POPOVER.TITLE_AVATAR' | translate}}" class="avatar" id="nav-user-settings") img(src="{{ user.photo }}" alt="{{ user.full_name_display }}") <% } %> diff --git a/app/partials/project/project-navigation-base.jade b/app/partials/project/project-navigation-base.jade index 030087b6..c360b971 100644 --- a/app/partials/project/project-navigation-base.jade +++ b/app/partials/project/project-navigation-base.jade @@ -1,20 +1,25 @@ -h1 Your projects +h1(translate='PROJECT.NAVIGATION.SECTION_TITLE') form fieldset - input.search-project(type="text", placeholder="Search in...") + input.search-project(type="text", + placeholder="{{'PROJECT.NAVIGATION.PLACEHOLDER_SEARCH' | translate}}") a.icon.icon-search div.create-project-button-wrapper - a.button-green.create-project-button(href="" title="Create new project") - span Create project + a.button-green.create-project-button(href="", + title="{{'PROJECT.NAVIGATION.ACTION_CREATE_PROJECT' | translate}}") + span(translate="PROJECT.NAVIGATION.ACTION_CREATE_PROJECT") - div(tg-import-project-button) - a.button-blackish.import-project-button(href="" title="Import project") + div(tg-import-project-button) + a.button-blackish.import-project-button(href="", + title="{{'PROJECT.NAVIGATION.TITLE_ACTION_IMPORT' | translate}}") span.icon.icon-upload input.import-file.hidden(type="file") div.projects-pagination(tg-projects-pagination) - a.v-pagination-previous.icon.icon-arrow-up(href="", title="Show previous projects") + a.v-pagination-previous.icon.icon-arrow-up(href="", + title="{{'PROJECT.NAVIGATION.TITLE_PRVIOUS_PROJECT' | translate}}") div.v-pagination-list ul.projects-list - a.v-pagination-next.icon.icon-arrow-bottom(href="", title="Show next projects") + a.v-pagination-next.icon.icon-arrow-bottom(href="", + title="{{'PROJECT.NAVIGATION.TITLE_NEXT_PROJECT' | translate}}") diff --git a/app/partials/project/project.jade b/app/partials/project/project.jade index 56fb4f81..d639d50d 100644 --- a/app/partials/project/project.jade +++ b/app/partials/project/project.jade @@ -1,20 +1,23 @@ +doctype html + div.wrapper(ng-controller="ProjectController as ctrl") section.main.single-project h1 span.green(tg-bo-bind="project.name", class="project-name") div.summary div.summary-stats - span.info-num(tg-bo-bind="stats.total_points") - span.info-text project
points + span.number(ng-bind="stats.total_points") -- + span.description(translate="BACKLOG.SUMMARY.PROJECT_POINTS") div.summary-stats - span.info-num(tg-bo-bind="stats.defined_points") - span.info-text defined
points + span.number(ng-bind="stats.defined_points") -- + span.description(translate="BACKLOG.SUMMARY.DEFINED_POINTS") div.summary-stats - span.info-num(tg-bo-bind="stats.assigned_points") - span.info-text assigned
points + span.number(ng-bind="stats.closed_points") -- + span.description(translate="BACKLOG.SUMMARY.CLOSED_POINTS") div.summary-stats - span.info-num(tg-bo-bind="stats.closed_points") - span.info-text closed
points + span.number(ng-bind="stats.speed | number:0") -- + span.description(translate="BACKLOG.SUMMARY.POINTS_PER_SPRINT") + div.project-data-container p.description(tg-bo-bind="project.description") ul diff --git a/app/partials/project/projects.jade b/app/partials/project/projects.jade index 94a16268..2eb47170 100644 --- a/app/partials/project/projects.jade +++ b/app/partials/project/projects.jade @@ -1,12 +1,13 @@ +doctype html + include ../includes/components/beta div.home-projects-list(ng-controller="ProjectsController as ctrl") .home-projects-wrapper div.welcome-user div.info - p - | Welcome + p(translate="PROJECT.WELCOME") span(tg-bo-bind="ctrl.user.full_name_display") - a.logout(ng-click="ctrl.logout()" href="", title="Logout") logout + a.logout(ng-click="ctrl.logout()" href="", title="{{'COMMON.LOGOUT' | translate}}", translate="COMMON.LOGOUT") .avatar img(tg-bo-src="ctrl.user.photo", tg-bo-alt="ctrl.user.full_name_display") @@ -21,14 +22,13 @@ div.home-projects-list(ng-controller="ProjectsController as ctrl") p(tg-bo-bind="project.description") div.all-projects - h1 Projects + h1(translate="PROJECT.SECTION_PROJECTS") div(tg-projects-list) .create-project-button-wrapper - a.button-green.create-project-button(href="", ng-click="ctrl.newProject()", title="Create new project") - span Create project + a.button-green.create-project-button(href="", ng-click="ctrl.newProject()", title="{{'PROJECT.NAVIGATION.ACTION_CREATE_PROJECT' | translate}}") + span(translate="PROJECT.NAVIGATION.ACTION_CREATE_PROJECT") div(tg-import-project-button) - a.button-blackish.import-project-button(href="", title="Import project") + a.button-blackish.import-project-button(href="", title="{{'PROJECT.NAVIGATION.TITLE_ACTION_IMPORT' | translate}}") span.icon.icon-upload input.import-file.hidden(type="file") - diff --git a/app/partials/search/search.jade b/app/partials/search/search.jade index cf584252..68836dc4 100644 --- a/app/partials/search/search.jade +++ b/app/partials/search/search.jade @@ -1,3 +1,5 @@ +doctype html + div.wrapper(tg-search, ng-controller="SearchController as ctrl", ng-init="section='search'") diff --git a/app/partials/task/related-task-create-form.jade b/app/partials/task/related-task-create-form.jade index 2110afcf..03b822a5 100644 --- a/app/partials/task/related-task-create-form.jade +++ b/app/partials/task/related-task-create-form.jade @@ -1,16 +1,16 @@ .tasks .task-name - input(type='text', placeholder='Type the new task subject') + input(type='text', placeholder="{{'TASK.PLACEHOLDER_SUBJECT' | translate}}") .task-settings - a.icon.icon-floppy(href='', title='Save') - a.icon.icon-delete.cancel-edit(href='', title='Cancel') + a.icon.icon-floppy(href='', title="{{'COMMON.SAVE' | translate}}") + a.icon.icon-delete.cancel-edit(href='', title="{{'COMMON.CANCEL' | translate}}") .status(tg-related-task-status='newTask', ng-model='newTask', not-auto-save='true') - a.task-status(href='', title='Status Name') + a.task-status(href='', title="{{'TITLE_SELECT_STATUS' | translate}}") span.task-status-bind span.icon.icon-arrow-bottom .assigned-to(tg-related-task-assigned-to-inline-edition='newTask', not-auto-save='true') - .task-assignedto(title='Assigned to') + .task-assignedto(title="{{'COMMON.FIELDS.ASSIGNED_TO' | translate}}") figure.avatar span.icon.icon-arrow-bottom diff --git a/app/partials/task/related-task-row-edit.jade b/app/partials/task/related-task-row-edit.jade index cfc4950f..8016c273 100644 --- a/app/partials/task/related-task-row-edit.jade +++ b/app/partials/task/related-task-row-edit.jade @@ -1,16 +1,16 @@ .tasks .task-name - input(type='text', value!='<%- task.subject %>', placeholder='Type the task subject') + input(type='text', value!='<%- task.subject %>', placeholder="{{'TASK.PLACEHOLDER_SUBJECT' | translate}}") .task-settings - a.icon.icon-floppy(href='', title='Save') - a.icon.icon-delete.cancel-edit(href='', title='Cancel') + a.icon.icon-floppy(href='', title="{{'COMMON.SAVE' | translate}}") + a.icon.icon-delete.cancel-edit(href='', title="{{'COMMON.CANCEL' | translate}}") .status(tg-related-task-status='task', ng-model='task') - a.task-status(href='', title='Status Name') + a.task-status(href='', title="{{'COMON.TITLE_SELECT_STATUS' | translate}}") span.task-status-bind span.icon.icon-arrow-bottom .assigned-to(tg-related-task-assigned-to-inline-edition='task') - .task-assignedto(title='Assigned to') + .task-assignedto(title="{{'COMMON.FIELDS.ASSIGNED_TO' | translate}}") figure.avatar span.icon.icon-arrow-bottom diff --git a/app/partials/task/related-task-row.jade b/app/partials/task/related-task-row.jade index d384c9a0..bbef4fd6 100644 --- a/app/partials/task/related-task-row.jade +++ b/app/partials/task/related-task-row.jade @@ -2,25 +2,25 @@ div(class="tasks") div(class="task-name") span(class="icon icon-iocaine") a(tg-nav="project-tasks-detail:project=project.slug,ref=task.ref" title!="#<%- task.ref %> <%- task.subject %>" class="clickable") - span #<%- task.ref %>  + span #<%- task.ref %>  span <%- task.subject %> div(class="task-settings") <% if(perms.modify_task) { %> - a(href="" title="Edit" class="icon icon-edit") + a(href="" title="{{'COMMON.EDIT' | translate}}" class="icon icon-edit") <% } %> <% if(perms.delete_task) { %> - a(href="" title="Delete" class="icon icon-delete delete-task") + a(href="" title="{{'COMMON.DELETE' | translate}}" class="icon icon-delete delete-task") <% } %> div(tg-related-task-status="task" ng-model="task" class="status") - a(href="" title="Status Name" class="task-status") + a(href="" title="{{'TASK.TITLE_SELECT_STATUS' | translate}}" class="task-status") span(class="task-status-bind") <% if(perms.modify_task) { %> span(class="icon icon-arrow-bottom") <% } %> div(tg-related-task-assigned-to-inline-edition="task" class="assigned-to") - div(title="Assigned to" class="task-assignedto <% if(perms.modify_task) { %>editable<% } %>") + div(title="{{'COMMON.FIELDS.ASSIGNED_TO' | translate}}" class="task-assignedto <% if(perms.modify_task) { %>editable<% } %>") figure(class="avatar") <% if(perms.modify_task) { %> span(class="icon icon-arrow-bottom") diff --git a/app/partials/task/task-detail.jade b/app/partials/task/task-detail.jade index 4d149454..a1f43b5d 100644 --- a/app/partials/task/task-detail.jade +++ b/app/partials/task/task-detail.jade @@ -1,3 +1,5 @@ +doctype html + div.wrapper(ng-controller="TaskDetailController as ctrl", ng-init="section='backlog-kanban'") div.main.us-detail @@ -6,9 +8,9 @@ div.wrapper(ng-controller="TaskDetailController as ctrl", .action-buttons a.button-gray( tg-check-permission="view_milestones", - href="", title="Go to taskboard", + href="", title="{{'TASK.TITLE_LINK_TASKBOARD' | translate}}", tg-nav="project-taskboard:project=project.slug,sprint=sprint.slug", - ng-if="sprint && project.is_backlog_activated") Taskboard + ng-if="sprint && project.is_backlog_activated", translate="TASK.LINK_TASKBOARD") section.us-story-main-data div.us-title(ng-class="{blocked: task.is_blocked}") @@ -16,25 +18,28 @@ div.wrapper(ng-controller="TaskDetailController as ctrl", span.us-number(tg-bo-ref="task.ref") span.us-name(tg-editable-subject, ng-model="task", required-perm="modify_task") - h3.us-related-task This task belongs to - a(tg-check-permission="view_us", href="", title="Go to user story", - tg-nav="project-userstories-detail:project=project.slug, ref=us.ref", - ng-if="us") + h3.us-related-task(ng-if="us") + | {{ 'TASK.OWNER_US'|translate }} + a(tg-check-permission="view_us", href="", title="{{'TASK.TITLE_LINK_GO_OWNER' | translate}}", + tg-nav="project-userstories-detail:project=project.slug, ref=us.ref") span(tg-bo-ref="us.ref") span(tg-bo-bind="us.subject") - p.external-reference(ng-if="task.external_reference") This task has been created from - a(target="_blank", tg-bo-href="task.external_reference[1]", title="Go to origin") + p.external-reference(ng-if="task.external_reference") + a(target="_blank", tg-bo-href="task.external_reference[1]", + title="{{'TASK.TITLE_LINK_GO_ORIGIN' | translate}}") + | {{ "TASK.ORIGIN_US"| translate }} span {{ task.external_reference[1] }} p.block-desc-container(ng-show="task.is_blocked") - span.block-description-title Blocked - span.block-description(ng-bind="task.blocked_note || 'This task is blocked'") + span.block-description-title(translate="COMMON.BLOCKED") + span.block-description(ng-bind="task.blocked_note || ('TASK.BLOCKED_DESCRIPTION' | translate)") + div.issue-nav a.icon.icon-arrow-left(ng-show="previousUrl", tg-bo-href="previousUrl", - title="previous task") + title="{{'TASK.PREVIOUS' | translate}}") a.icon.icon-arrow-right(ng-show="nextUrl", tg-bo-href="nextUrl", - title="next task") + title="{{'TASK.NEXT' | translate}}") div.tags-block(tg-tag-line, ng-model="task", required-perm="modify_task") @@ -61,10 +66,10 @@ div.wrapper(ng-controller="TaskDetailController as ctrl", tg-task-is-iocaine-button(ng-model="task") tg-block-button(tg-check-permission="modify_task", ng-model="task") tg-delete-button(tg-check-permission="delete_task", - on-delete-title="'Delete Task'", + on-delete-title="{{'TASK.TITLE_DELETE_ACTION' | translate}}", on-delete-go-to-url="onDeleteGoToUrl", ng-model="task") - div.lightbox.lightbox-block(tg-lb-block, title="Blocking task", ng-model="task") + div.lightbox.lightbox-block(tg-lb-block, title="TASK.LIGHTBOX_TITLE_BLOKING_TASK", ng-model="task") div.lightbox.lightbox-select-user(tg-lb-assignedto) div.lightbox.lightbox-select-user(tg-lb-watchers) diff --git a/app/partials/taskboard/taskboard-user.jade b/app/partials/taskboard/taskboard-user.jade index 68fe53dc..ca05113f 100644 --- a/app/partials/taskboard/taskboard-user.jade +++ b/app/partials/taskboard/taskboard-user.jade @@ -1,5 +1,5 @@ figure.avatar.avatar-assigned-to - a(href='#', title='Assign task', ng-class="{'not-clickable': !clickable}") + a(href='#', title="{{'TASKBOARD.TITLE_ACTION_ASSIGN' | translate}}", ng-class="{'not-clickable': !clickable}") img(ng-src='{{imgurl}}') figure.avatar.avatar-task-link a(tg-nav='project-tasks-detail:project=project.slug,ref=task.ref', ng-attr-title='{{task.subject}}') diff --git a/app/partials/taskboard/taskboard.jade b/app/partials/taskboard/taskboard.jade index 33faab92..5f4cfda1 100644 --- a/app/partials/taskboard/taskboard.jade +++ b/app/partials/taskboard/taskboard.jade @@ -1,3 +1,5 @@ +doctype html + div.wrapper(tg-taskboard, ng-controller="TaskboardController as ctrl", ng-init="section='backlog'") section.main.taskboard diff --git a/app/partials/team/leave-project.jade b/app/partials/team/leave-project.jade index 8b482f7b..b9d52ae0 100644 --- a/app/partials/team/leave-project.jade +++ b/app/partials/team/leave-project.jade @@ -1,4 +1,3 @@ -a.leave-project(ng-click='leave()', href='') +a.leave-project(ng-click="leave()", href="") span.icon.icon-delete - - | Leave this project + | {{ 'TEAM.ACTION_LEAVE_PROJECT' | translate }} diff --git a/app/partials/team/team-filter.jade b/app/partials/team/team-filter.jade index 62cffffe..d23c8644 100644 --- a/app/partials/team/team-filter.jade +++ b/app/partials/team/team-filter.jade @@ -1,10 +1,10 @@ ul li - a(ng-class='{active: !filtersRole.id}', ng-click='ctrl.setRole()', href='') - span.title All + a(ng-class="{active: !filtersRole.id}", ng-click="ctrl.setRole()", href="") + span.title(translate="TEAM.SECTION_FILTER_ALL") span.icon.icon-arrow-right - li(ng-repeat='role in roles') - a(ng-class='{active: role.id == filtersRole.id}', ng-click='ctrl.setRole(role)', href='') - span.title(tg-bo-bind='role.name') - span.icon.icon-arrow-right + li(ng-repeat="role in roles") + a(ng-class="{active: role.id == filtersRole.id}", ng-click="ctrl.setRole(role)", href="") + span.title(tg-bo-bind="role.name") + span.icon.icon-arrow-right diff --git a/app/partials/team/team-member-current-user.jade b/app/partials/team/team-member-current-user.jade index d25c2a16..698c2f7f 100644 --- a/app/partials/team/team-member-current-user.jade +++ b/app/partials/team/team-member-current-user.jade @@ -1,13 +1,17 @@ .row .username figure.avatar - img(tg-bo-src='currentUser.photo', tg-bo-alt='currentUser.full_name') + img(tg-bo-src="currentUser.photo", tg-bo-alt="currentUser.full_name") - figcaption - span.name(tg-bo-bind='currentUser.full_name') + figcaption + span.name(tg-bo-bind="currentUser.full_name") - span.position(tg-bo-bind='currentUser.role_name') + span.position(tg-bo-bind="currentUser.role_name") - div(tg-leave-project='', projectid='{{projectId}}') + div(tg-leave-project="", projectid="{{projectId}}") - .member-stats(tg-team-member-stats, stats="stats", user="currentUser.user", issuesEnabled="issuesEnabled", tasksenabled="tasksEnabled", wikienabled="wikiEnabled") + .member-stats(tg-team-member-stats, stats="stats", + user="currentUser.user", + issuesEnabled="issuesEnabled", + tasksenabled="tasksEnabled", + wikienabled="wikiEnabled") diff --git a/app/partials/team/team-member-stats.jade b/app/partials/team/team-member-stats.jade index e611ef0c..c271ffe0 100644 --- a/app/partials/team/team-member-stats.jade +++ b/app/partials/team/team-member-stats.jade @@ -1,17 +1,22 @@ -.attribute(ng-if='issuesEnabled') - span.icon.icon-briefcase(ng-style="{'opacity': stats.closed_bugs[userId]}", ng-class="{'top': stats.closed_bugs[userId] == 1}") +.attribute(ng-if="issuesEnabled") + span.icon.icon-briefcase(ng-style="{'opacity': stats.closed_bugs[userId]}", + ng-class="{'top': stats.closed_bugs[userId] == 1}") -.attribute(ng-if='tasksEnabled') - span.icon.icon-iocaine(ng-style="{'opacity': stats.iocaine_tasks[userId]}", ng-class="{'top': stats.iocaine_tasks[userId] == 1}") +.attribute(ng-if="tasksEnabled") + span.icon.icon-iocaine(ng-style="{'opacity': stats.iocaine_tasks[userId]}", + ng-class="{'top': stats.iocaine_tasks[userId] == 1}") -.attribute(ng-if='wikiEnabled') - span.icon.icon-writer(ng-style="{'opacity': stats.wiki_changes[userId]}", ng-class="{'top': stats.wiki_changes[userId] == 1}") +.attribute(ng-if="wikiEnabled") + span.icon.icon-writer(ng-style="{'opacity': stats.wiki_changes[userId]}", + ng-class="{'top': stats.wiki_changes[userId] == 1}") -.attribute(ng-if='issuesEnabled') - span.icon.icon-bug(ng-style="{'opacity': stats.created_bugs[userId]}", ng-class="{'top': stats.created_bugs[userId] == 1}") +.attribute(ng-if="issuesEnabled") + span.icon.icon-bug(ng-style="{'opacity': stats.created_bugs[userId]}", + ng-class="{'top': stats.created_bugs[userId] == 1}") -.attribute(ng-if='tasksEnabled') - span.icon.icon-tasks(ng-style="{'opacity': stats.closed_tasks[userId]}", ng-class="{'top': stats.closed_tasks[userId] == 1}") +.attribute(ng-if="tasksEnabled") + span.icon.icon-tasks(ng-style="{'opacity': stats.closed_tasks[userId]}", + ng-class="{'top': stats.closed_tasks[userId] == 1}") .attribute - span.points(ng-bind='stats.totals[userId]') + span.points(ng-bind="stats.totals[userId]") diff --git a/app/partials/team/team-members.jade b/app/partials/team/team-members.jade index ed77d85d..7cc07391 100644 --- a/app/partials/team/team-members.jade +++ b/app/partials/team/team-members.jade @@ -1,11 +1,15 @@ -.row.member(ng-repeat='user in memberships | filter:filtersQ | membersRoleFilter:filtersRole') +.row.member(ng-repeat="user in memberships | membersFilter:filtersQ:filtersRole") .username figure.avatar - img(tg-bo-src='user.photo', tg-bo-alt='user.full_name') + img(tg-bo-src="user.photo", tg-bo-alt="user.full_name") - figcaption - span.name(tg-bo-bind='user.full_name') + figcaption + span.name(tg-bo-bind="user.full_name") - span.position(tg-bo-bind='user.role_name') + span.position(tg-bo-bind="user.role_name") - .member-stats(tg-team-member-stats, stats="stats", user="user.user", issuesEnabled="issuesEnabled", tasksenabled="tasksEnabled", wikienabled="wikiEnabled") + .member-stats(tg-team-member-stats, stats="stats", + user="user.user", + issuesEnabled="issuesEnabled", + tasksenabled="tasksEnabled", + wikienabled="wikiEnabled") diff --git a/app/partials/team/team.jade b/app/partials/team/team.jade index 84f47d4f..96323560 100644 --- a/app/partials/team/team.jade +++ b/app/partials/team/team.jade @@ -1,3 +1,5 @@ +doctype html + div.wrapper(ng-controller="TeamController as ctrl", ng-init="section='team'") sidebar.menu-secondary include ../includes/modules/team/team-filters diff --git a/app/partials/us/us-client-requirement-button.jade b/app/partials/us/us-client-requirement-button.jade index a3dbe9d3..dc269cbc 100644 --- a/app/partials/us/us-client-requirement-button.jade +++ b/app/partials/us/us-client-requirement-button.jade @@ -1,5 +1,4 @@ label(for="client-requirement", - class!="button button-gray client-requirement <% if(canEdit){ %>editable<% }; %> <% if(isRequired){ %>active<% }; %>") - | Client requirement + class!="button button-gray client-requirement <% if(canEdit){ %>editable<% }; %> <% if(isRequired){ %>active<% }; %>", translate="US.FIELDS.CLIENT_REQUIREMENT") input(type="checkbox", id="client-requirement", name="client-requirement") \ No newline at end of file diff --git a/app/partials/us/us-detail.jade b/app/partials/us/us-detail.jade index 8c8708a1..f930e9e7 100644 --- a/app/partials/us/us-detail.jade +++ b/app/partials/us/us-detail.jade @@ -1,3 +1,5 @@ +doctype html + div.wrapper(ng-controller="UserStoryDetailController as ctrl", ng-init="section='backlog-kanban'") div.main.us-detail @@ -6,9 +8,9 @@ div.wrapper(ng-controller="UserStoryDetailController as ctrl", .action-buttons a.button-gray( tg-check-permission="view_milestones", - href="", title="Go to taskboard", + href="", title="{{'US.TITLE_LINK_TASKBOARD' | translate}}", tg-nav="project-taskboard:project=project.slug,sprint=sprint.slug", - ng-if="sprint && project.is_backlog_activated") Taskboard + ng-if="sprint && project.is_backlog_activated", translate="US.LINK_TASKBOARD") section.us-story-main-data div.us-title(ng-class="{blocked: us.is_blocked}") @@ -16,24 +18,27 @@ div.wrapper(ng-controller="UserStoryDetailController as ctrl", span.us-number(tg-bo-ref="us.ref") span.us-name(tg-editable-subject, ng-model="us", required-perm="modify_us") - p.us-related-task(ng-if="us.origin_issue") This US has been promoted from Issue - a(tg-check-permission="view_us", href="", title="Go to issue", + p.us-related-task(ng-if="us.origin_issue") + | {{ 'US.PROMOTED'|translate }} + a(tg-check-permission="view_us", href="", title="{{'US.TITLE_LINK_GO_TO_ISSUE' | translate}}", tg-nav="project-issues-detail:project=project.slug, ref=us.origin_issue.ref" tg-bo-title="'#' + us.origin_issue.ref + ' ' + us.origin_issue.subject") span(tg-bo-ref="us.origin_issue.ref") - p.external-reference(ng-if="us.external_reference") This US has been created from - a(target="_blank", tg-bo-href="us.external_reference[1]", title="Go to origin") + p.external-reference(ng-if="us.external_reference") + | {{ 'US.EXTERNAL_REFERENCE'|translate }} + a(target="_blank", tg-bo-href="us.external_reference[1]", + title="{{'US.GO_TO_EXTERNAL_REFERENCE' | translate}}") span {{ us.external_reference[1] }} p.block-desc-container(ng-show="us.is_blocked") - span.block-description-title Blocked - span.block-description(ng-bind="us.blocked_note || 'This user story is blocked'") + span.block-description-title(translate="COMMON.BLOCKED") + span.block-description(ng-bind="us.blocked_note || ('US.BLOCKED' | translate)") div.issue-nav a.icon.icon-arrow-left(ng-show="previousUrl", tg-bo-href="previousUrl", - title="previous user story") + title="{{'US.PREVIOUS' | translate}}") a.icon.icon-arrow-right(ng-show="nextUrl", tg-bo-href="nextUrl", - title="next user story") + title="{{'US.NEXT' | translate}}") div.tags-block(tg-tag-line, ng-model="us", required-perm="modify_us") @@ -65,10 +70,10 @@ div.wrapper(ng-controller="UserStoryDetailController as ctrl", tg-us-client-requirement-button(ng-model="us") tg-block-button(tg-check-permission="modify_us", ng-model="us") tg-delete-button(tg-check-permission="delete_us", - on-delete-title="'Delete User Story'", + on-delete-title="{{'Delete User Story' | translate}}", on-delete-go-to-url="onDeleteGoToUrl", ng-model="us") - div.lightbox.lightbox-block(tg-lb-block, title="Blocking us", ng-model="us") + div.lightbox.lightbox-block(tg-lb-block, title="US.LIGHTBOX_TITLE_BLOKING_US", ng-model="us") div.lightbox.lightbox-select-user(tg-lb-assignedto) div.lightbox.lightbox-select-user(tg-lb-watchers) diff --git a/app/partials/us/us-status-button.jade b/app/partials/us/us-status-button.jade index b46f156f..7a3ba3b5 100644 --- a/app/partials/us/us-status-button.jade +++ b/app/partials/us/us-status-button.jade @@ -4,7 +4,7 @@ div(class!="status-data <% if(editable){ %>clickable<% }%>") <% if(editable){ %> span.icon.icon-arrow-bottom <% }%> - span.level-name status + span.level-name(translate="COMMON.FIELDS.STATUS") ul.popover.pop-status <% _.each(statuses, function(st) { %> diff --git a/app/partials/us/us-task-progress.jade b/app/partials/us/us-task-progress.jade index 8ced2ed5..df2f8b7c 100644 --- a/app/partials/us/us-task-progress.jade +++ b/app/partials/us/us-task-progress.jade @@ -1,3 +1,2 @@ -.current-progress(style!='width:<%- progress %>%') -div.tasks-completed - | <%- totalClosedTasks %>/<%- totalTasks %> tasks completed \ No newline at end of file +.current-progress(ng-style='style') +div.tasks-completed(translate="US.TASK_COMPLETED", translate-values='{ totalTasks: totalTasks, totalClosedTasks: totalClosedTasks}') diff --git a/app/partials/us/us-team-requirement-button.jade b/app/partials/us/us-team-requirement-button.jade index 3067d7d9..e1520364 100644 --- a/app/partials/us/us-team-requirement-button.jade +++ b/app/partials/us/us-team-requirement-button.jade @@ -1,4 +1,3 @@ -label(for="team-requirement", class!="button button-gray team-requirement <% if(canEdit){ %>editable<% }; %> <% if(isRequired){ %>active<% }; %>") - | Team requirement +label(for="team-requirement", class!="button button-gray team-requirement <% if(canEdit){ %>editable<% }; %> <% if(isRequired){ %>active<% }; %>", translate="US.FIELDS.TEAM_REQUIREMENT") input(type="checkbox", id="team-requirement", name="team-requirement") \ No newline at end of file diff --git a/app/partials/user/cancel-account.jade b/app/partials/user/cancel-account.jade index 1735da1e..9d3043e5 100644 --- a/app/partials/user/cancel-account.jade +++ b/app/partials/user/cancel-account.jade @@ -1,8 +1,10 @@ +doctype html + div.wrapper.cancel-account div.login-main div.login-container h1.logo img.logo-svg(src="/svg/logo.svg", alt="TAIGA") - p.tagline Your agile, free, and open source project management tool + p.tagline(translate="COMMON.TAG_LINE") include ../includes/modules/cancel-account-form diff --git a/app/partials/user/change-email.jade b/app/partials/user/change-email.jade index 1102d53c..7f2ef8ab 100644 --- a/app/partials/user/change-email.jade +++ b/app/partials/user/change-email.jade @@ -1,8 +1,10 @@ +doctype html + div.wrapper div.login-main div.login-container h1.logo img.logo-svg(src="/svg/logo.svg", alt="TAIGA") - p.tagline Your agile, free, and open source project management tool + p.tagline(translate="COMMON.TAG_LINE") include ../includes/modules/change-email-form diff --git a/app/partials/user/lightbox/lightbox-delete-account.jade b/app/partials/user/lightbox/lightbox-delete-account.jade index 03b3b528..9d4fb190 100644 --- a/app/partials/user/lightbox/lightbox-delete-account.jade +++ b/app/partials/user/lightbox/lightbox-delete-account.jade @@ -1,12 +1,12 @@ -a.close(href="", title="close") +a.close(href="", title="{{'close' | translate}}") span.icon.icon-delete form - h2.title Delete Taiga Account + h2.title(translate="LIGHTBOX.DELETE_ACCOUNT.SECTION_NAME") p - span.question Are you sure you want to delete your Taiga account? - span.subtitle We're going to miss you! :-( + span.question(translate="LIGHBOX.DELETE_ACCOUNT.CONFIRM") + span.subtitle(translate="LIGHBOX.DELETE_ACCOUNT.SUBTITLE") div.options - a.button-green(href="", title="Accept") - span Accept - a.button-red(href="", title="Cancel") - span Cancel + a.button-green(href="", title="{{'COMMON.ACCEPT' | translate}}") + span(translate="COMMON.ACCEPT") Accept + a.button-red(href="", title="{{'Cancel' | translate}}", ) + span(translate="COMMON.CANCEL") Accept diff --git a/app/partials/user/mail-notifications.jade b/app/partials/user/mail-notifications.jade index 2676f575..a798aad6 100644 --- a/app/partials/user/mail-notifications.jade +++ b/app/partials/user/mail-notifications.jade @@ -1,3 +1,5 @@ +doctype html + div.wrapper(tg-user-notifications, ng-controller="UserNotificationsController as ctrl", ng-init="section='mail-notifications'") sidebar.menu-secondary.sidebar(tg-user-settings-navigation="mail-notifications") @@ -6,8 +8,8 @@ div.wrapper(tg-user-notifications, ng-controller="UserNotificationsController as section.main.admin-common header h1 - span.green(tg-bo-html="sectionName") + span.green {{sectionName | translate}} - p.total Notifications By Mail + p.total(translate="NOTIFICATION.MAIL") include ../includes/modules/user-settings/mail-notifications-table diff --git a/app/partials/user/user-change-password.jade b/app/partials/user/user-change-password.jade index 4eb2698d..625993ad 100644 --- a/app/partials/user/user-change-password.jade +++ b/app/partials/user/user-change-password.jade @@ -1,3 +1,5 @@ +doctype html + div.wrapper(tg-user-change-password, ng-controller="UserChangePasswordController as ctrl", ng-init="section='user-settings'") sidebar.menu-secondary.sidebar(tg-user-settings-navigation="change-password") @@ -6,17 +8,17 @@ div.wrapper(tg-user-change-password, ng-controller="UserChangePasswordController section.main.user-change-password header h1 - span.green(tg-bo-html="sectionName") + span.green {{sectionName | translate}} form fieldset - label(for="current-password") Current Password - input(type="password", placeholder="Your current password (or empty if you have no password yet)", id="current-password", ng-model="currentPassword") + label(for="current-password", translate="CHANGE_PASSWORD.FIELD_CURRENT_PASSWORD") + input(type="password", placeholder="{{'CHANGE_PASSWORD.PLACEHOLDER_CURRENT_PASSWORD' | translate}}", id="current-password", ng-model="currentPassword") fieldset - label(for="new-password") New Password - input(type="password", placeholder="New Password", id="new-password", ng-model="newPassword1") + label(for="new-password", translate="CHANGE_PASSWORD.FIELD_NEW_PASSWORD") + input(type="password", placeholder="{{'CHANGE_PASSWORD.PLACEHOLDER_NEW_PASSWORD' | translate}}", id="new-password", ng-model="newPassword1") fieldset - label(for="retype-password") Retype Password - input(type="password", placeholder="Retype Password", id="retype-password", ng-model="newPassword2") + label(for="retype-password", translate="CHANGE_PASSWORD.FIELD_RETYPE_PASSWORD") + input(type="password", placeholder="{{'CHANGE_PASSWORD.PLACEHOLDER_RETYPE_PASSWORD' | translate}}", id="retype-password", ng-model="newPassword2") fieldset - button.button-green.submit-button(type="submit", title="Save") Save + button.button-green.submit-button(type="submit", title="{{'COMMON.SAVE' | translate}}", translate="COMMON.SAVE") diff --git a/app/partials/user/user-profile.jade b/app/partials/user/user-profile.jade index 6c39fb79..7709cf60 100644 --- a/app/partials/user/user-profile.jade +++ b/app/partials/user/user-profile.jade @@ -1,3 +1,5 @@ +doctype html + div.wrapper(tg-user-profile, ng-controller="UserSettingsController as ctrl", ng-init="section='user-settings'") sidebar.menu-secondary.sidebar(tg-user-settings-navigation="user-profile") @@ -6,7 +8,7 @@ div.wrapper(tg-user-profile, ng-controller="UserSettingsController as ctrl", section.main.user-profile header h1 - span.green(tg-bo-html="sectionName") + span.green {{sectionName | translate}} form div.container @@ -15,42 +17,54 @@ div.wrapper(tg-user-profile, ng-controller="UserSettingsController as ctrl", .image-container img.avatar(ng-src="{{user.big_photo}}" alt="avatar") .overlay.hidden - img.loading-spinner(src="/svg/spinner-circle.svg", alt="loading...") + img.loading-spinner(src="/svg/spinner-circle.svg", + alt="{{'COMMON.LOADING' | translate}}") input(type="file", id="avatar-field", class="hidden", tg-avatar-model="avatarAttachment") - p The image will be cropped to 80x80px.
+ p(translate="USER_PROFILE.IMAGE_HELP") span.size-info.hidden(tg-bo-html="maxFileSizeMsg") - a.button-green.change.js-change-avatar(tg-bo-title="'Change photo. ' + maxFileSizeMsg") Change - a.use-gravatar Use gravatar image + a.button-green.change.js-change-avatar(translate="USER_PROFILE.ACTION_CHANGE_IMAGE", + title="{{'USER_PROFILE.CHANGE_PHOTO' | translate}} {{maxFileSizeMsg}}") + a.use-gravatar(translate="USER_PROFILE.ACTION_USE_GRAVATAR") div.data fieldset - label(for="email") Username - input(type="text", name="username", id="username", placeholder="username", - ng-model="user.username", data-required="true", data-maxlength="255", - data-regexp="^[\\w.-]+$") + label(for="email", translate="USER_PROFILE.FIELD.USERNAME") + input(type="text", name="username", id="username", + placeholder="{{'USER_PROFILE.FIELD.USERNAME' | translate}}", + ng-model="user.username", data-required="true", data-maxlength="255", + data-regexp="^[\\w.-]+$") fieldset - label(for="email") Email - input(type="text", name="email", id="email", placeholder="email", + label(for="email", translate="USER_PROFILE.FIELD.EMAIL") + input(type="text", name="email", id="email", + placeholder="{{'USER_PROFILE.FIELD.EMAIL' | translate}}", ng-model="user.email", data-type="email", data-required="true", data-maxlength="255") fieldset - label(for="full-name") Full name + label(for="full-name", translate="USER_PROFILE.FIELD.FULL_NAME") input(type="text", name="full_name", id="full-name", - placeholder="Set your full name (ex. Íñigo Montoya)", + placeholder="{{'USER_PROFILE.FIELD.PLACEHOLDER_FULL_NAME' | translate}}", ng-model="user.full_name", data-required="true", data-maxlength="256") fieldset - label(for="bio") Bio - textarea(name="bio", id="bio", placeholder="Tell us something about you", - ng-model="user.bio") + label(for="full-name", translate="USER_PROFILE.FIELD.LANGUAGE") + select(ng-model="lang", + ng-options="locale.code as locale.name for locale in locales") + option(value="", translate="USER_PROFILE.FIELD.LANGUAGE_DEFAULT") + + fieldset + label(for="bio", translate="USER_PROFILE.FIELD.BIO") + textarea(name="bio", id="bio", ng-model="user.bio", + ng-attr-placeholder="{{'USER_PROFILE.FIELD.PLACEHOLDER_BIO' | translate}}") fieldset.submit - button.button-green.submit-button(type="submit", title="Save") Save - a.delete-account(href="", title="Delete Taiga account", - ng-click="ctrl.openDeleteLightbox()") Delete Taiga account + button.button-green.submit-button(type="submit", title="{{'COMMON.SAVE' | translate}}", + translate="COMMON.SAVE") + a.delete-account(href="", title="{{'USER_PROFILE.ACTION_DELETE_ACCOUNT' | translate}}", + ng-click="ctrl.openDeleteLightbox()", + translate="USER_PROFILE.ACTION_DELETE_ACCOUNT") div.lightbox.lightbox-delete-account(tg-lb-delete-user) diff --git a/app/partials/wiki/editable-wiki-content.jade b/app/partials/wiki/editable-wiki-content.jade index ddeb2581..9c9533ed 100644 --- a/app/partials/wiki/editable-wiki-content.jade +++ b/app/partials/wiki/editable-wiki-content.jade @@ -1,11 +1,11 @@ .view-wiki-content section.wysiwyg(tg-bind-html='wiki.html') - span.edit.icon.icon-edit(title='Edit') + span.edit.icon.icon-edit(title="{{'COMMON.EDIT' | translate}}") .edit-wiki-content(style='display: none;') - textarea(placeholder='Write your wiki page here', ng-model='wiki.content', tg-markitup='tg-markitup') - a.help-markdown(href='https://taiga.io/support/taiga-markdown-syntax/', target='_blank', title='Mardown syntax help') + textarea(ng-attr-placeholder="{{'WIKI.PLACEHOLDER_PAGE' | translate}}", ng-model='wiki.content', tg-markitup='tg-markitup') + a.help-markdown(href='https://taiga.io/support/taiga-markdown-syntax/', target='_blank', title="{{'COMMON.WYSIWYG.MARKDOWN_HELP' | translate}}") span.icon.icon-help - span Markdown syntax help + span(translate="COMMON.WYSIWYG.MARKDOWN_HELP") span.action-container - a.save.icon.icon-floppy(href='', title='Save') - a.cancel.icon.icon-delete(href='', title='Cancel') + a.save.icon.icon-floppy(href='', title="{{'COMMON.SAVE' | translate}}") + a.cancel.icon.icon-delete(href='', title="{{'COMMON.CANCEL' | translate}}") diff --git a/app/partials/wiki/wiki-nav.jade b/app/partials/wiki/wiki-nav.jade index 759bccaa..8e2c97bc 100644 --- a/app/partials/wiki/wiki-nav.jade +++ b/app/partials/wiki/wiki-nav.jade @@ -1,5 +1,5 @@ header - h1 Links + h1(translate="WIKI.NAVIGATION.SECTION_NAME") nav ul @@ -10,11 +10,11 @@ nav <% if (deleteWikiLinkPermission) { %> span.icon.icon-delete <% } %> - input(type="text" placeholder="name" class="hidden" value!="<%- link.title %>") + input(type="text" placeholder="{{'COMMON.FIELDS.NAME' | translate}}" class="hidden" value!="<%- link.title %>") <% }) %> li.new.hidden - input(type="text" placeholder="name") + input(type="text" placeholder="{{'COMMON.FIELDS.NAME' | translate}}") <% if (addWikiLinkPermission) { %> -a(href="" title="Add link" class="add-button button-gray") - span Add link +a(href="" title="{{'WIKI.NAVIGATION.ACTION_ADD_LINK' | translate}}" class="add-button button-gray") + span(translate="WIKI.NAVIGATION.ACTION_ADD_LINK") <% } %> diff --git a/app/partials/wiki/wiki-summary.jade b/app/partials/wiki/wiki-summary.jade index 7fb31db1..f2855cba 100644 --- a/app/partials/wiki/wiki-summary.jade +++ b/app/partials/wiki/wiki-summary.jade @@ -1,14 +1,14 @@ div.wiki-times-edited span.number <%- totalEditions %> - span.description times
edited + span.description(translate="WIKI.SUMMARY.TIMES_EDITED") div.wiki-last-modified span.number <%- lastModifiedDate %> - span.description last
edit + span.description(translate="WIKI.SUMMARY.LAST_EDIT") div.wiki-username-edition figure.avatar img(src!="<%- user.imgUrl %>" alt!="<%- user.name %>") div.wiki-user-modification - span.description last modification + span.description(translate="WIKI.SUMMARY.LAST_MODIFICATION") span.username <%- user.name %> diff --git a/app/partials/wiki/wiki.jade b/app/partials/wiki/wiki.jade index aabca782..34463d42 100644 --- a/app/partials/wiki/wiki.jade +++ b/app/partials/wiki/wiki.jade @@ -1,3 +1,5 @@ +doctype html + div.wrapper(ng-controller="WikiDetailController as ctrl", ng-init="section='wiki'") sidebar.menu-secondary.extrabar(tg-check-permission="view_wiki_links") @@ -6,7 +8,7 @@ div.wrapper(ng-controller="WikiDetailController as ctrl", .header h1 span(tg-bo-bind="project.name") - span.green Wiki + span.green(translate="PROJECT.SECTION.WIKI") span.wiki-title(tg-bo-bind='wikiSlug|unslugify') div.summary.wiki-summary(tg-wiki-summary, ng-model="wiki", ng-if="wiki.id") @@ -14,6 +16,6 @@ div.wrapper(ng-controller="WikiDetailController as ctrl", tg-attachments(ng-model="wiki", type="wiki_page", ng-if="wiki.id") - a.remove(href="", ng-click="ctrl.delete()", ng-if="wiki.id", title="Remove this wiki page", tg-check-permission="delete_wiki_page") + a.remove(href="", ng-click="ctrl.delete()", ng-if="wiki.id", title="{{'WIKI.REMOVE' | translate}}", tg-check-permission="delete_wiki_page") span.icon.icon-delete - span Remove this wiki page + span(translate="WIKI.REMOVE") diff --git a/app/styles/components/check.scss b/app/styles/components/check.scss new file mode 100644 index 00000000..9c15e077 --- /dev/null +++ b/app/styles/components/check.scss @@ -0,0 +1,61 @@ +.check { + background-color: darken($whitish, 10%); + border-radius: 2px; + cursor: pointer; + height: 1.5rem; + overflow: hidden; + position: relative; + width: 65px; + input { + cursor: pointer; + height: 500px; + left: -10px; + opacity: 0; + position: absolute; + top: -10px; + width: 500px; + z-index: 999; + + div { + background-color: $gray; + height: 25px; + transition: all .2s linear; + width: 50%; + } + ~ .check-text { + //@include transition(opacity .3s linear); + @extend %small; + color: $white; + position: absolute; + top: .1rem; + } + ~ .check-yes { + opacity: 0; + right: .5rem; + } + ~ .check-no { + left: .5rem; + opacity: .6; + } + } + input:checked { + + div { + background-color: $fresh-taiga; + margin-left: 50%; + transition: all .2s linear; + } + ~ .check-yes { + opacity: .6; + right: .4rem; + } + ~ .check-no { + left: .4rem; + opacity: 0; + } + } + input:disabled { + cursor: auto; + + div { + background-color: $gray-light; + } + } +} diff --git a/app/styles/components/kanban-task.scss b/app/styles/components/kanban-task.scss index 5cc71ed5..429edda7 100644 --- a/app/styles/components/kanban-task.scss +++ b/app/styles/components/kanban-task.scss @@ -152,6 +152,9 @@ padding-right: .2rem; } } + .points-text { + text-transform: lowercase; + } } .kanban-tag { border-top: .3rem solid; diff --git a/app/styles/components/loading-bar.scss b/app/styles/components/loading-bar.scss index 1e68bf04..3cf3e26f 100644 --- a/app/styles/components/loading-bar.scss +++ b/app/styles/components/loading-bar.scss @@ -13,7 +13,7 @@ height: 5px; } - $colors-list: #bbe831 #237400 #e43050 #810061 #618000; + $colors-list: $yellow-pear $green-japanese-laurel $red-amaranth $purple-eggplant $green-olive; @each $current-color in $colors-list { $i: index($colors-list, $current-color) - 1; .item-#{$i} { diff --git a/app/styles/components/loading-spinner.scss b/app/styles/components/loading-spinner.scss new file mode 100644 index 00000000..b035d515 --- /dev/null +++ b/app/styles/components/loading-spinner.scss @@ -0,0 +1,3 @@ +.loading-spinner { + @extend %loading-spinner; +} diff --git a/app/styles/components/notification-message.scss b/app/styles/components/notification-message.scss index 40b6840d..f43d9a50 100644 --- a/app/styles/components/notification-message.scss +++ b/app/styles/components/notification-message.scss @@ -1,21 +1,76 @@ -.notification-message { - background: rgba($gray-light, .95); - color: $white; - opacity: 0; - padding: 1rem; - position: fixed; +.notification-message-success { + background: rgba($fresh-taiga, .95); + box-shadow: 0 25px 10px -15px rgba(0, 0, 0, .05); + opacity: 1; + right: -370px; + top: 2%; + transition: opacity .2s ease-in; + width: 370px; + &.active { + animation: animSlide 2000ms linear both; + opacity: 1; + } + p { + margin: 0; + } + .warning { + @extend %large; + @extend %bold; + color: $white; + line-height: 1.2; + } +} + +// Generated with Bounce.js. Edit at http://goo.gl/yZlDYR + +@keyframes animSlide { + 0% { transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1); } + 0.52% { transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -34.485, 0, 0, 1); } + 1.02% { transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -66.555, 0, 0, 1); } + 2.28% { transform: matrix3d(1.111, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -141.457, 0, 0, 1); } + 3.52% { transform: matrix3d(1.281, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -205.594, 0, 0, 1); } + 4.1% { transform: matrix3d(1.111, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -232.117, 0, 0, 1); } + 4.78% { transform: matrix3d(1.034, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -260.381, 0, 0, 1); } + 6.03% { transform: matrix3d(.947, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -304.285, 0, 0, 1); } + 8.11% { transform: matrix3d(.986, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -357.804, 0, 0, 1); } + 11.03% { transform: matrix3d(1.001, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -399.29, 0, 0, 1); } + 12.11% { transform: matrix3d(1.001, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -407.374, 0, 0, 1); } + 16.04% { transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -417.343, 0, 0, 1); } + 16.12% { transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -417.342, 0, 0, 1); } + 20% { transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -413.214, 0, 0, 1); } + 27.23% { transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -403.135, 0, 0, 1); } + 38.34% { transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -399.585, 0, 0, 1); } + 60.56% { transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -400.01, 0, 0, 1); } + 82.78% { opacity: 1; transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -400, 0, 0, 1); } + 100% { opacity: 0; transform: matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, -400, 0, 0, 1); } +} + + + +.notification-message-error { + background: rgba($red, .9); top: 0; transform: translateY(-100%); width: 100%; - z-index: 99920; - &.inactive { - transition: all .6s ease-in-out; - } &.active { opacity: 1; transform: translateY(0); transition: all .6s ease-in-out; } + &.inactive { + transition: all .6s ease-in-out; + } + .icon-notification-error { + @extend %xxlarge; + display: inline; + vertical-align: sub; + } + .warning { + @extend %xlarge; + @extend %bold; + color: $white; + line-height: 2.4rem; + } .text { display: inline-block; margin-left: .5rem; @@ -24,12 +79,6 @@ margin: 0; } } - .warning { - @extend %xlarge; - @extend %bold; - color: $white; - line-height: 2.4rem; - } .icon-delete { color: $white; position: absolute; @@ -38,22 +87,12 @@ } } -.notification-message-success { - background: rgba($fresh-taiga, .9); - .icon-notification-success { - @extend %xxlarge; - display: inline; - vertical-align: sub; - } -} - -.notification-message-error { - background: rgba($red, .9); - .icon-notification-error { - @extend %xxlarge; - display: inline; - vertical-align: sub; - } +.notification-message { + color: $white; + opacity: 0; + padding: 1rem; + position: fixed; + z-index: 99920; } .notification-light { diff --git a/app/styles/components/summary.scss b/app/styles/components/summary.scss index 0c50809c..33ee7665 100644 --- a/app/styles/components/summary.scss +++ b/app/styles/components/summary.scss @@ -67,7 +67,6 @@ } } - .large-summary { justify-content: space-between; .large-summary-wrapper { diff --git a/app/styles/components/taskboard-task.scss b/app/styles/components/taskboard-task.scss index be1b0678..398aeee1 100644 --- a/app/styles/components/taskboard-task.scss +++ b/app/styles/components/taskboard-task.scss @@ -89,6 +89,9 @@ @extend %small; color: $postit-dark-hover; display: block; + &:hover { + color: $green-taiga; + } } .task-num { color: $grayer; diff --git a/app/styles/components/wysiwyg.scss b/app/styles/components/wysiwyg.scss index 5e906637..18dfa7af 100644 --- a/app/styles/components/wysiwyg.scss +++ b/app/styles/components/wysiwyg.scss @@ -1,6 +1,7 @@ .wysiwyg { line-height: 1.4rem; overflow: auto; + padding: 1rem; h1 { @extend %xlarge; @extend %text; @@ -19,7 +20,7 @@ } ul, ol { - list-style-position: inside; + list-style-position: outside; margin-left: 1rem; } ul { diff --git a/app/styles/layout/animation.scss b/app/styles/core/animation.scss similarity index 100% rename from app/styles/layout/animation.scss rename to app/styles/core/animation.scss diff --git a/app/styles/layout/base.scss b/app/styles/core/base.scss similarity index 97% rename from app/styles/layout/base.scss rename to app/styles/core/base.scss index cae94352..a98ce08e 100644 --- a/app/styles/layout/base.scss +++ b/app/styles/core/base.scss @@ -5,8 +5,8 @@ html { } body { @extend %text; - background: #fff; // fallback - color: #444; + background: $white; // fallback + color: $grayer; min-height: 100%; width: 100%; .master { @@ -138,6 +138,7 @@ body { } .hidden { + // scss-lint:disable ImportantRule display: none !important; } diff --git a/app/styles/layout/elements.scss b/app/styles/core/elements.scss similarity index 93% rename from app/styles/layout/elements.scss rename to app/styles/core/elements.scss index 44f9c1da..965dedeb 100644 --- a/app/styles/layout/elements.scss +++ b/app/styles/core/elements.scss @@ -3,17 +3,17 @@ // Blockquotes blockquote, blockquote p { - color: #777; + color: $gray; font-style: italic; line-height: 24px; } blockquote { - border-left: 1px solid #ddd; + border-left: 1px solid $gray-light; margin: 0 0 20px; padding: 9px 20px 0 19px; cite { @extend %small; - color: #555; + color: $gray; display: block; &:before { content: '\2014 \0020'; @@ -53,6 +53,7 @@ sup { //Datepicker .pika-single { + // scss-lint:disable ImportantRule z-index: 999999; .pika-title { color: $grayer; diff --git a/app/styles/layout/forms.scss b/app/styles/core/forms.scss similarity index 100% rename from app/styles/layout/forms.scss rename to app/styles/core/forms.scss diff --git a/app/styles/layout/reset.scss b/app/styles/core/reset.scss similarity index 100% rename from app/styles/layout/reset.scss rename to app/styles/core/reset.scss diff --git a/app/styles/layout/typography.scss b/app/styles/core/typography.scss similarity index 97% rename from app/styles/layout/typography.scss rename to app/styles/core/typography.scss index bf4bbba9..67e91155 100755 --- a/app/styles/layout/typography.scss +++ b/app/styles/core/typography.scss @@ -20,6 +20,7 @@ h5, h6 { color: $blackish; font-weight: normal; + line-height: 1.5; a { font-weight: inherit; } @@ -80,7 +81,7 @@ strong { } hr { - border: solid #ddd; + border: solid $blackish; border-width: 1px 0 0; clear: both; height: 0; @@ -101,6 +102,7 @@ a:visited { // Taiga Icons [data-icon]:before { + // scss-lint:disable ImportantRule content: attr(data-icon); font-family: 'taiga' !important; -moz-osx-font-smoothing: grayscale; @@ -115,6 +117,7 @@ a:visited { [class^='icon-']:before, [class*=' icon-']:before { + // scss-lint:disable ImportantRule font-family: 'taiga' !important; -moz-osx-font-smoothing: grayscale; -webkit-font-smoothing: antialiased; diff --git a/app/styles/dependencies/colors.scss b/app/styles/dependencies/colors.scss index aeaffb2d..3275443a 100755 --- a/app/styles/dependencies/colors.scss +++ b/app/styles/dependencies/colors.scss @@ -8,6 +8,7 @@ $gray-light: #b8b8b8; $whitish: #f5f5f5; $white: #fff; + $green-taiga: #72a114; $fresh-taiga: #9dce0a; $dark-taiga: #879b89; @@ -18,3 +19,12 @@ $red: #f00; $postit: #fff8e4; $postit-hover: #f1e8cd; $postit-dark-hover: #cfc29b; + +//Loading bar +$green-japanese-laurel: #237400; +$green-olive: #618000; +$red-amaranth: #e43050; +$purple-eggplant: #810061; +$yellow-pear: #bbe831; + +$menu: #232323; diff --git a/app/styles/dependencies/helpers.scss b/app/styles/dependencies/helpers.scss index 9440bf64..e1d484f5 100644 --- a/app/styles/dependencies/helpers.scss +++ b/app/styles/dependencies/helpers.scss @@ -80,7 +80,3 @@ max-width: 1rem; transform-origin: 32 32; } - -.loading-spinner { - @extend %loading-spinner; -} diff --git a/app/styles/dependencies/responsive.scss b/app/styles/dependencies/responsive.scss index 69c4ecc7..94218c7f 100644 --- a/app/styles/dependencies/responsive.scss +++ b/app/styles/dependencies/responsive.scss @@ -2,17 +2,18 @@ // - I know, I know, but look it closer, it makes sense // - Oh, I see. It's ok for this time... -$break-small: 320px; -$break-large: 1024px; +@mixin breakpoint($point) { + @if $point == desktop { + @media (min-width: 1200px) { @content ; } + } + @else if $point == laptop { + @media (max-width: 1200px) { @content ; } + } + @else if $point == tablet { + @media (max-width: 767px) { @content ; } + } + @else if $point == mobileonly { + @media (max-width: 480px) { @content ; } -@mixin respond-to($media) { - @if $media == handhelds { - @media only screen and (max-width: $break-small) { @content; } - } - @if $media == medium-screens { - @media only screen and (min-width: $break-small + 1) and (max-width: $break-large - 1) { @content; } - } - @if $media == wide-screens { - @media only screen and (min-width: $break-large) { @content; } } } diff --git a/app/styles/layout/invitation.scss b/app/styles/layout/invitation.scss index 6f66c900..d11889f4 100644 --- a/app/styles/layout/invitation.scss +++ b/app/styles/layout/invitation.scss @@ -100,7 +100,7 @@ text-align: center; width: 200px; .form-header { - color: #999; + color: $gray-light; } } .register-form { diff --git a/app/styles/layout/project-colors.scss b/app/styles/layout/project-colors.scss deleted file mode 100644 index 6e699bd1..00000000 --- a/app/styles/layout/project-colors.scss +++ /dev/null @@ -1,11 +0,0 @@ -.project-colors { - .new-color { - float: right; - } - .colors-table { - margin-top: 1rem; - } - .project-colors-options { - @include clearfix; - } -} diff --git a/app/styles/layout/us-detail.scss b/app/styles/layout/us-detail.scss index 90107884..b3322b59 100644 --- a/app/styles/layout/us-detail.scss +++ b/app/styles/layout/us-detail.scss @@ -100,7 +100,7 @@ margin-top: .5rem; a { border-left: 1px solid $gray-light; - padding: 0 .2rem; + padding: 0 .2rem; } a:hover { color: $green-taiga; @@ -357,6 +357,7 @@ .level-name { color: darken($whitish, 20%); float: right; + text-transform: lowercase; } } diff --git a/app/styles/modules/admin/admin-functionalities.scss b/app/styles/modules/admin/admin-functionalities.scss index 6f92a677..9f0842fe 100644 --- a/app/styles/modules/admin/admin-functionalities.scss +++ b/app/styles/modules/admin/admin-functionalities.scss @@ -19,7 +19,7 @@ vertical-align: top; width: 32%; &.active { - background-color: #e9f0da; + background-color: rgba($green-taiga, .3); opacity: 1; } .icon { @@ -41,7 +41,7 @@ text-align: center; } } - span { + .title { @extend %bold; display: block; } diff --git a/app/styles/modules/admin/admin-membership-table.scss b/app/styles/modules/admin/admin-membership-table.scss index 820a3232..544dc21f 100644 --- a/app/styles/modules/admin/admin-membership-table.scss +++ b/app/styles/modules/admin/admin-membership-table.scss @@ -98,59 +98,4 @@ flex-basis: 50px; flex-grow: 1; } - .check { - background-color: darken($whitish, 10%); - border-radius: 2px; - cursor: pointer; - height: 1.5rem; - overflow: hidden; - position: relative; - width: 65px; - input { - cursor: pointer; - height: 500px; - left: -10px; - opacity: 0; - position: absolute; - top: -10px; - width: 500px; - z-index: 999; - + div { - background-color: $gray; - height: 25px; - transition: all .2s linear; - width: 50%; - } - ~ .check-text { - //@include transition(opacity .3s linear); - @extend %small; - color: $white; - position: absolute; - top: .1rem; - } - ~ .check-yes { - opacity: 0; - right: .5rem; - } - ~ .check-no { - left: .5rem; - opacity: .6; - } - } - input:checked { - + div { - background-color: #74a218; - margin-left: 50%; - transition: all .2s linear; - } - ~ .check-yes { - opacity: .6; - right: .4rem; - } - ~ .check-no { - left: .4rem; - opacity: 0; - } - } - } } diff --git a/app/styles/modules/admin/admin-roles.scss b/app/styles/modules/admin/admin-roles.scss index daa55c21..83e0511c 100644 --- a/app/styles/modules/admin/admin-roles.scss +++ b/app/styles/modules/admin/admin-roles.scss @@ -47,65 +47,4 @@ margin-left: .5rem; } } - .check { - background-color: darken($whitish, 10%); - border-radius: 2px; - cursor: pointer; - height: 1.5rem; - overflow: hidden; - position: relative; - width: 65px; - input { - cursor: pointer; - height: 500px; - left: -10px; - opacity: 0; - position: absolute; - top: -10px; - width: 500px; - z-index: 999; - + div { - background-color: $gray; - height: 25px; - transition: all .2s linear; - width: 50%; - } - ~ .check-text { - //@include transition(opacity .3s linear); - @extend %small; - color: $white; - position: absolute; - top: .1rem; - } - ~ .check-yes { - opacity: 0; - right: .5rem; - } - ~ .check-no { - left: .5rem; - opacity: .6; - } - } - input:checked { - + div { - background-color: #74a218; - margin-left: 50%; - transition: all .2s linear; - } - ~ .check-yes { - opacity: .6; - right: .4rem; - } - ~ .check-no { - left: .4rem; - opacity: 0; - } - } - input:disabled { - cursor: auto; - + div { - background-color: #ccc; - } - } - } } diff --git a/app/styles/modules/admin/admin-submenu-roles.scss b/app/styles/modules/admin/admin-submenu-roles.scss index 441df1ab..e9cb013c 100644 --- a/app/styles/modules/admin/admin-submenu-roles.scss +++ b/app/styles/modules/admin/admin-submenu-roles.scss @@ -6,7 +6,7 @@ li { @extend %larger; @extend %title; - border-bottom: 1px solid #a6b2a7; + border-bottom: 1px solid $gray-light; text-transform: uppercase; &:last-child { border-bottom: 0; diff --git a/app/styles/modules/admin/admin-submenu.scss b/app/styles/modules/admin/admin-submenu.scss index 5af5f8e5..58e32f39 100644 --- a/app/styles/modules/admin/admin-submenu.scss +++ b/app/styles/modules/admin/admin-submenu.scss @@ -6,7 +6,7 @@ li { @extend %larger; @extend %title; - border-bottom: 1px solid #a6b2a7; + border-bottom: 1px solid $gray-light; text-transform: uppercase; &:last-child { border-bottom: 0; @@ -14,7 +14,8 @@ } a { color: $white; - display: block; + display: flex; + justify-content: space-between; padding: 1rem 0 1rem 1rem; &.active, &:hover { @@ -25,6 +26,13 @@ transition: opacity .3s linear; } } + span { + display: block; + max-width: 85%; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } } .icon { color: $white; diff --git a/app/styles/modules/admin/contrib.scss b/app/styles/modules/admin/contrib.scss index 0581bf82..e8745d6b 100644 --- a/app/styles/modules/admin/contrib.scss +++ b/app/styles/modules/admin/contrib.scss @@ -54,6 +54,16 @@ } } } + .check-item { + align-items: center; + border-bottom: 1px solid $whitish; + display: flex; + justify-content: space-between; + margin-top: 2rem; + &:last-child { + border-bottom: 0; + } + } .help { margin-top: 2rem; h3 { diff --git a/app/styles/modules/auth/cancel-account.scss b/app/styles/modules/auth/cancel-account.scss index 52776464..7f3447f8 100644 --- a/app/styles/modules/auth/cancel-account.scss +++ b/app/styles/modules/auth/cancel-account.scss @@ -2,4 +2,12 @@ fieldset { text-align: center; } + p { + color: $grayer; + margin-bottom: .5rem; + text-align: center; + } + form { + margin-top: 1rem; + } } diff --git a/app/styles/modules/auth/change-email-form.scss b/app/styles/modules/auth/change-email-form.scss new file mode 100644 index 00000000..5d88044c --- /dev/null +++ b/app/styles/modules/auth/change-email-form.scss @@ -0,0 +1,13 @@ +.change-email-form { + fieldset { + text-align: center; + } + p { + color: $grayer; + margin-bottom: .5rem; + text-align: center; + } + form { + margin-top: 1rem; + } +} diff --git a/app/styles/modules/backlog/backlog-table.scss b/app/styles/modules/backlog/backlog-table.scss index c92e6333..1dc5c5d3 100644 --- a/app/styles/modules/backlog/backlog-table.scss +++ b/app/styles/modules/backlog/backlog-table.scss @@ -189,6 +189,7 @@ transition: background .2s ease-in; } a { + // scss-lint:disable ImportantRule color: $white !important; &:hover { color: $white; diff --git a/app/styles/modules/common/colors-table.scss b/app/styles/modules/common/colors-table.scss index f84a0d6e..56caeca1 100644 --- a/app/styles/modules/common/colors-table.scss +++ b/app/styles/modules/common/colors-table.scss @@ -120,6 +120,9 @@ color: $green-taiga; transition: all .2s ease-in; } + &.icon-check-square { + opacity: 1; + } } .icon-delete { &:hover { diff --git a/app/styles/modules/common/lightbox.scss b/app/styles/modules/common/lightbox.scss index bdfdd09c..198e7cbf 100644 --- a/app/styles/modules/common/lightbox.scss +++ b/app/styles/modules/common/lightbox.scss @@ -58,7 +58,7 @@ .iocaine { &:hover { background: $fresh-taiga; - border: 1px solid $fresh-taiga; + border: 1px solid $green-taiga; color: $white; transition: all .2s ease-in; } @@ -68,7 +68,7 @@ padding: 8px 30px; &:hover { background: $red-light; - border: 1px solid $red-light; + border: 1px solid $red; color: $white; transition: all .2s ease-in; } @@ -79,14 +79,17 @@ .team-requirement, .iocaine-flag { input:checked+label { - background: $fresh-taiga; + background: $green-taiga; + border: 1px solid $green-taiga; color: $white; + } } .blocking-flag { input:checked+label { background: $red; + border: 1px solid $red; color: $white; } } diff --git a/app/styles/modules/common/projects-nav.scss b/app/styles/modules/common/projects-nav.scss index d922ff23..ca3d0671 100644 --- a/app/styles/modules/common/projects-nav.scss +++ b/app/styles/modules/common/projects-nav.scss @@ -1,5 +1,5 @@ .projects-nav { - background-color: #232323; + background-color: $menu; display: flex; flex-direction: column; height: 100%; diff --git a/app/styles/modules/common/related-tasks.scss b/app/styles/modules/common/related-tasks.scss index aab7266b..b807de9f 100644 --- a/app/styles/modules/common/related-tasks.scss +++ b/app/styles/modules/common/related-tasks.scss @@ -136,7 +136,7 @@ background: $red-light; color: $white; a { - color: $white !important; + color: $white; &:hover { color: $white; } diff --git a/app/styles/modules/filters/filter-tags.scss b/app/styles/modules/filters/filter-tags.scss deleted file mode 100644 index d640d9a7..00000000 --- a/app/styles/modules/filters/filter-tags.scss +++ /dev/null @@ -1,21 +0,0 @@ -.filter-tags { - margin-top: 2rem; - .filter-tag { - color: $white; - cursor: pointer; - margin-bottom: 1rem; - opacity: .5; - padding: .5rem 1rem; - position: relative; - &.active { - opacity: 1; - } - } - .tag-count { - background: none repeat scroll 0 0 rgba(0, 0, 0, .3); - padding: .5rem 1rem; - position: absolute; - right: 0; - top: 0; - } -} diff --git a/app/styles/modules/issues/issues-table.scss b/app/styles/modules/issues/issues-table.scss index 9ff1a1fc..22a4a2ec 100644 --- a/app/styles/modules/issues/issues-table.scss +++ b/app/styles/modules/issues/issues-table.scss @@ -111,4 +111,19 @@ top: auto; } } + .level-field, + .created-field { + @include breakpoint(laptop) { + display: none; + } + } + .level-field, + .created-field, + .assigned-field { + @include breakpoint(tablet) { + display: none; + } + } } + + diff --git a/app/styles/modules/search/search-result-table.scss b/app/styles/modules/search/search-result-table.scss index dbce9244..ed37282e 100644 --- a/app/styles/modules/search/search-result-table.scss +++ b/app/styles/modules/search/search-result-table.scss @@ -10,26 +10,27 @@ align-content: center; align-items: center; display: flex; + justify-content: space-between; padding: .5rem; &:hover { background: lighten($green-taiga, 60%); transition: background .2s ease-in; } .user-stories { - flex-basis: 0; - flex-grow: 5; + flex-basis: 300px; + flex-grow: 10; flex-shrink: 1; } .status, .points { - flex-basis: 100px; - flex-grow: 1; + flex-basis: 150px; + flex-grow: 0; padding: 0 1rem; text-align: center; } .assigned-to { - flex-basis: 250px; - flex-grow: 1; + flex-basis: 150px; + flex-grow: 0; padding: 0 1rem; } } @@ -79,11 +80,13 @@ align-items: center; display: flex; img { - flex-basis: 35px; + width: 35px; } figcaption { - display: inline-block; + display: flex; + flex-basis: 60%; margin-left: .5rem; + max-width: 60%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; diff --git a/app/styles/modules/wiki/wiki-nav.scss b/app/styles/modules/wiki/wiki-nav.scss index d80724ab..39c20db9 100644 --- a/app/styles/modules/wiki/wiki-nav.scss +++ b/app/styles/modules/wiki/wiki-nav.scss @@ -2,7 +2,7 @@ li { @extend %large; @extend %title; - border-bottom: 1px solid #cdcdcd; + border-bottom: 1px solid $gray-light; text-transform: uppercase; &:hover { .icon { diff --git a/bower.json b/bower.json index 69a278e9..3b1f68c8 100644 --- a/bower.json +++ b/bower.json @@ -55,9 +55,7 @@ "angular-animate": "1.3.11", "angular-sanitize": "1.3.11", "angular-mocks": "1.3.11", - "kalendae": "~0.4.1", "checksley": "~0.6.0", - "i18next": "~1.7.1", "jquery": "~2.1.1", "select2": "~3.4.5", "angular-ui-select2": "~0.0.5", @@ -68,18 +66,21 @@ "flot-orderBars": "emmerich/flot-orderBars", "flot-axislabels": "markrcote/flot-axislabels", "flot.tooltip": "~0.8.4", - "moment": "~2.6.0", + "moment": "~2.10.2", "isMobile": "~0.3.1", "favico.js": "0.3.4", "Sortable": "~0.1.8", "pikaday": "~1.2.0", "malihu-custom-scrollbar-plugin": "~3.0.4", "raven-js": "~1.1.16", - "l.js": "~0.1.0" + "l.js": "~0.1.0", + "angular-translate": "~2.6.1", + "angular-translate-loader-static-files": "~2.6.1", + "angular-translate-interpolation-messageformat": "~2.6.1" }, "resolutions": { "lodash": "~2.4.1", - "moment": "~2.6.0", + "moment": "~2.10.2", "jquery": "~2.1.1", "angular": "1.3.11" }, diff --git a/coffeelint.json b/coffeelint.json new file mode 100644 index 00000000..912d7827 --- /dev/null +++ b/coffeelint.json @@ -0,0 +1,120 @@ +{ + "arrow_spacing": { + "level": "ignore" + }, + "braces_spacing": { + "level": "ignore", + "spaces": 0 + }, + "camel_case_classes": { + "level": "error" + }, + "coffeescript_error": { + "level": "error" + }, + "colon_assignment_spacing": { + "level": "ignore", + "spacing": { + "left": 0, + "right": 0 + } + }, + "cyclomatic_complexity": { + "value": 10, + "level": "ignore" + }, + "duplicate_key": { + "level": "error" + }, + "empty_constructor_needs_parens": { + "level": "ignore" + }, + "ensure_comprehensions": { + "level": "warn" + }, + "indentation": { + "value": 4, + "level": "error" + }, + "line_endings": { + "level": "ignore", + "value": "unix" + }, + "max_line_length": { + "value": 120, + "level": "error", + "limitComments": true + }, + "missing_fat_arrows": { + "level": "ignore" + }, + "newlines_after_classes": { + "value": 3, + "level": "ignore" + }, + "no_backticks": { + "level": "error" + }, + "no_debugger": { + "level": "warn" + }, + "no_empty_functions": { + "level": "ignore" + }, + "no_empty_param_list": { + "level": "ignore" + }, + "no_implicit_braces": { + "level": "ignore", + "strict": true + }, + "no_implicit_parens": { + "strict": true, + "level": "ignore" + }, + "no_interpolation_in_single_quotes": { + "level": "ignore" + }, + "no_plusplus": { + "level": "ignore" + }, + "no_stand_alone_at": { + "level": "ignore" + }, + "no_tabs": { + "level": "error" + }, + "no_throwing_strings": { + "level": "error" + }, + "no_trailing_semicolons": { + "level": "error" + }, + "no_trailing_whitespace": { + "level": "error", + "allowed_in_comments": false, + "allowed_in_empty_lines": true + }, + "no_unnecessary_double_quotes": { + "level": "ignore" + }, + "no_unnecessary_fat_arrows": { + "level": "warn" + }, + "non_empty_constructor_needs_parens": { + "level": "ignore" + }, + "prefer_english_operator": { + "level": "ignore", + "doubleNotLevel": "ignore" + }, + "space_operators": { + "level": "ignore" + }, + "spacing_after_comma": { + "level": "ignore" + }, + "transform_messes_up_line_numbers": { + "level": "warn" + } +} diff --git a/conf/conf.example.json b/conf/conf.example.json index f378107e..2a78a5ea 100644 --- a/conf/conf.example.json +++ b/conf/conf.example.json @@ -2,11 +2,12 @@ "api": "http://localhost:8000/api/v1/", "eventsUrl": null, "debug": true, + "debugInfo": false, + "defaultLanguage": "en", "publicRegisterEnabled": true, "feedbackEnabled": true, "privacyPolicyUrl": null, "termsOfServiceUrl": null, "maxUploadFileSize": null, - "contribPlugins": [], - "debugInfo": false + "contribPlugins": [] } diff --git a/extras/humans.txt b/extras/humans.txt index a612f8d1..6bfa6c65 100644 --- a/extras/humans.txt +++ b/extras/humans.txt @@ -48,8 +48,8 @@ Site: http://kaleidos.net Twitter: @elhombretecla Location: Madrid, Spain - - Taiga UX Consultan: Esther Moreno + + Taiga UX Consultan & LEGO architect: Esther Moreno Site: http://kaleidos.net Twitter: @plumilla Location: Madrid, Spain diff --git a/gulpfile.js b/gulpfile.js index dbef97e0..b436c775 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -22,15 +22,17 @@ var gulp = require("gulp"), autoprefixer = require("gulp-autoprefixer"), templateCache = require("gulp-angular-templatecache"), runSequence = require("run-sequence"), - del = require("del"); - -var mainSass = require("./main-sass").files; + order = require("gulp-order"), + print = require('gulp-print'), + del = require("del"), + coffeelint = require('gulp-coffeelint'); var paths = {}; paths.app = "app/"; paths.dist = "dist/"; paths.tmp = "tmp/"; paths.extras = "extras/"; +paths.vendor = "vendor/"; paths.jade = [ paths.app + "**/*.jade" @@ -39,12 +41,13 @@ paths.jade = [ paths.htmlPartials = [ paths.tmp + "partials/**/*.html", paths.tmp + "plugins/**/*.html", + paths.tmp + "modules/**/*.html", "!" + paths.tmp + "partials/includes/**/*.html" ]; paths.images = paths.app + "images/**/*"; paths.svg = paths.app + "svg/**/*"; -paths.css = paths.app + "styles/vendor/*.css"; +paths.css_vendor = paths.app + "styles/vendor/*.css"; paths.locales = paths.app + "locales/**/*.json"; paths.sass = [ @@ -54,57 +57,92 @@ paths.sass = [ "!" + paths.app + "/styles/extras/**/*.scss" ]; -paths.coffee = paths.app + "**/*.coffee"; +paths.styles_dependencies = paths.app + "/styles/dependencies/**/*.scss"; -paths.js = [ - paths.tmp + "coffee/app.js", - paths.tmp + "coffee/*.js", - paths.tmp + "coffee/modules/controllerMixins.js", - paths.tmp + "coffee/modules/*.js", - paths.tmp + "coffee/modules/common/*.js", - paths.tmp + "coffee/modules/backlog/*.js", - paths.tmp + "coffee/modules/taskboard/*.js", - paths.tmp + "coffee/modules/kanban/*.js", - paths.tmp + "coffee/modules/issues/*.js", - paths.tmp + "coffee/modules/userstories/*.js", - paths.tmp + "coffee/modules/tasks/*.js", - paths.tmp + "coffee/modules/team/*.js", - paths.tmp + "coffee/modules/wiki/*.js", - paths.tmp + "coffee/modules/admin/*.js", - paths.tmp + "coffee/modules/projects/*.js", - paths.tmp + "coffee/modules/locales/*.js", - paths.tmp + "coffee/modules/base/*.js", - paths.tmp + "coffee/modules/resources/*.js", - paths.tmp + "coffee/modules/user-settings/*.js", - paths.tmp + "coffee/modules/integrations/*.js", - paths.tmp + "plugins/**/*.js" +paths.css = [ + paths.tmp + "styles/**/*.css", + paths.tmp + "modules/**/*.css", + paths.tmp + "plugins/**/*.css" +]; + +paths.css_order = [ + paths.tmp + "styles/vendor/*", + paths.tmp + "styles/core/reset.css", + paths.tmp + "styles/core/base.css", + paths.tmp + "styles/core/animation.css", + paths.tmp + "styles/core/typography.css", + paths.tmp + "styles/core/elements.css", + paths.tmp + "styles/core/forms.css", + paths.tmp + "styles/layout/*", + paths.tmp + "styles/components/*", + paths.tmp + "styles/modules/**/*.css", + paths.tmp + "modules/**/*.css", + paths.tmp + "styles/shame/*.css", + paths.tmp + "plugins/**/*.css" +]; + +paths.coffee = [ + paths.app + "**/*.coffee", + "!" + paths.app + "**/*.spec.coffee", +]; + +paths.coffee_order = [ + paths.app + "coffee/app.coffee", + paths.app + "coffee/*.coffee", + paths.app + "coffee/modules/controllerMixins.coffee", + paths.app + "coffee/modules/*.coffee", + paths.app + "coffee/modules/common/*.coffee", + paths.app + "coffee/modules/backlog/*.coffee", + paths.app + "coffee/modules/taskboard/*.coffee", + paths.app + "coffee/modules/kanban/*.coffee", + paths.app + "coffee/modules/issues/*.coffee", + paths.app + "coffee/modules/userstories/*.coffee", + paths.app + "coffee/modules/tasks/*.coffee", + paths.app + "coffee/modules/team/*.coffee", + paths.app + "coffee/modules/wiki/*.coffee", + paths.app + "coffee/modules/admin/*.coffee", + paths.app + "coffee/modules/projects/*.coffee", + paths.app + "coffee/modules/locales/*.coffee", + paths.app + "coffee/modules/base/*.coffee", + paths.app + "coffee/modules/resources/*.coffee", + paths.app + "coffee/modules/user-settings/*.coffee", + paths.app + "coffee/modules/integrations/*.coffee", + paths.app + "modules/**/*.module.coffee", + paths.app + "modules/**/*.coffee", + paths.app + "plugins/*.coffee", + paths.app + "plugins/**/*.coffee" ]; paths.libs = [ - paths.app + "vendor/jquery/dist/jquery.js", - paths.app + "vendor/lodash/dist/lodash.js", - paths.app + "vendor/emoticons/lib/emoticons.js", - paths.app + "vendor/underscore.string/lib/underscore.string.js", - paths.app + "vendor/angular/angular.js", - paths.app + "vendor/angular-route/angular-route.js", - paths.app + "vendor/angular-sanitize/angular-sanitize.js", - paths.app + "vendor/angular-animate/angular-animate.js", - paths.app + "vendor/i18next/i18next.js", - paths.app + "vendor/moment/min/moment-with-langs.js", - paths.app + "vendor/checksley/checksley.js", - paths.app + "vendor/pikaday/pikaday.js", - paths.app + "vendor/jquery-flot/jquery.flot.js", - paths.app + "vendor/jquery-flot/jquery.flot.pie.js", - paths.app + "vendor/jquery-flot/jquery.flot.time.js", - paths.app + "vendor/flot-axislabels/jquery.flot.axislabels.js", - paths.app + "vendor/flot.tooltip/js/jquery.flot.tooltip.js", - paths.app + "vendor/jquery-textcomplete/jquery.textcomplete.js", - paths.app + "vendor/markitup-1x/markitup/jquery.markitup.js", - paths.app + "vendor/malihu-custom-scrollbar-plugin/jquery.mCustomScrollbar.concat.min.js", - paths.app + "vendor/raven-js/dist/raven.js", - paths.app + "vendor/l.js/l.js", + paths.vendor + "jquery/dist/jquery.js", + paths.vendor + "lodash/dist/lodash.js", + paths.vendor + "emoticons/lib/emoticons.js", + paths.vendor + "underscore.string/lib/underscore.string.js", + paths.vendor + "messageformat/messageformat.js", + paths.vendor + "angular/angular.js", + paths.vendor + "angular-route/angular-route.js", + paths.vendor + "angular-sanitize/angular-sanitize.js", + paths.vendor + "angular-animate/angular-animate.js", + paths.vendor + "angular-translate/angular-translate.js", + paths.vendor + "angular-translate-loader-static-files/angular-translate-loader-static-files.js", + paths.vendor + "angular-translate-interpolation-messageformat/angular-translate-interpolation-messageformat.js", + paths.vendor + "moment/min/moment-with-locales.js", + paths.vendor + "checksley/checksley.js", + paths.vendor + "pikaday/pikaday.js", + paths.vendor + "jquery-flot/jquery.flot.js", + paths.vendor + "jquery-flot/jquery.flot.pie.js", + paths.vendor + "jquery-flot/jquery.flot.time.js", + paths.vendor + "flot-axislabels/jquery.flot.axislabels.js", + paths.vendor + "flot.tooltip/js/jquery.flot.tooltip.js", + paths.vendor + "jquery-textcomplete/jquery.textcomplete.js", + paths.vendor + "markitup-1x/markitup/jquery.markitup.js", + paths.vendor + "malihu-custom-scrollbar-plugin/jquery.mCustomScrollbar.concat.min.js", + paths.vendor + "raven-js/dist/raven.js", + paths.vendor + "l.js/l.js", + paths.vendor + "messageformat/locale/*.js", paths.app + "js/jquery.ui.git-custom.js", paths.app + "js/jquery-ui.drag-multiple-custom.js", + paths.app + "js/jquery.ui.touch-punch.min.js", paths.app + "js/sha1-custom.js" ]; @@ -182,20 +220,25 @@ gulp.task("scss-lint", [], function() { .pipe(gulpif(fail, scsslint.failReporter())) }); -gulp.task("sass-compile", ["scss-lint"], function() { +gulp.task("clear-sass-cache", function() { + delete cached.caches["sass"]; +}); + +gulp.task("sass-compile", [], function() { return gulp.src(paths.sass) .pipe(plumber()) .pipe(insert.prepend('@import "dependencies";')) - .pipe(cache(sass({ + .pipe(cached("sass")) + .pipe(sass({ includePaths: [ paths.app + "styles/extras/" ] - }))) + })) .pipe(gulp.dest(paths.tmp)); }); gulp.task("css-lint-app", function() { - return gulp.src(mainSass.concat([paths.tmp + "plugins/**/*.css"])) + return gulp.src(paths.css) .pipe(gulpif(!isDeploy, cache(csslint("csslintrc.json"), { success: function(csslintFile) { return csslintFile.csslint.success; @@ -209,8 +252,9 @@ gulp.task("css-lint-app", function() { .pipe(csslint.reporter()); }); -gulp.task("css-join", ["css-lint-app"], function() { - return gulp.src(mainSass.concat([paths.tmp + "plugins/**/*.css"])) +gulp.task("app-css", function() { + return gulp.src(paths.css) + .pipe(order(paths.css_order, {base: '.'})) .pipe(concat("app.css")) .pipe(autoprefixer({ cascade: false @@ -218,17 +262,13 @@ gulp.task("css-join", ["css-lint-app"], function() { .pipe(gulp.dest(paths.tmp)); }); -gulp.task("css-app", function(cb) { - return runSequence("sass-compile", "css-join", cb); -}); - -gulp.task("css-vendor", function() { - return gulp.src(paths.css) +gulp.task("vendor-css", function() { + return gulp.src(paths.css_vendor) .pipe(concat("vendor.css")) .pipe(gulp.dest(paths.tmp)); }); -gulp.task("styles", ["css-app", "css-vendor"], function() { +gulp.task("main-css", function() { var _paths = [ paths.tmp + "vendor.css", paths.tmp + "app.css" @@ -240,6 +280,24 @@ gulp.task("styles", ["css-app", "css-vendor"], function() { .pipe(gulp.dest(paths.dist + "styles/")) }); +gulp.task("styles", function(cb) { + return runSequence("scss-lint", + "sass-compile", + "css-lint-app", + ["app-css", "vendor-css"], + "main-css", + cb); + +}); + +gulp.task("styles-dependencies", function(cb) { + return runSequence("clear-sass-cache", + "sass-compile", + ["app-css", "vendor-css"], + "main-css", + cb); +}); + /* ############################################################################## # JS Related tasks @@ -258,25 +316,43 @@ gulp.task("app-loader", function() { }); gulp.task("locales", function() { - return gulp.src("app/locales/en/app.json") - .pipe(wrap("angular.module('taigaBase').value('localesEn', <%= contents %>);", {}, {parse: false})) - .pipe(rename("locales.en.js")) - .pipe(gulp.dest(paths.tmp)); + return gulp.src(paths.locales) + .pipe(gulp.dest(paths.dist + "locales")); +}); + +gulp.task("coffee-lint", function () { + gulp.src([ + paths.app + "modules/**/*.coffee", + "!" + paths.app + "modules/**/*.spec.coffee" + ]) + .pipe(gulpif(!isDeploy, cache(coffeelint(), { + key: function(lintFile) { + return "coffee-lint" + lintFile.contents.toString('utf8'); + }, + success: function(lintFile) { + return lintFile.coffeelint.success; + }, + value: function(lintFile) { + return { + coffeelint: lintFile.coffeelint + }; + } + }))) + .pipe(coffeelint.reporter()); }); gulp.task("coffee", function() { return gulp.src(paths.coffee) + .pipe(order(paths.coffee_order, {base: '.'})) + .pipe(sourcemaps.init()) .pipe(cache(coffee())) .on("error", function(err) { console.log(err.toString()); this.emit("end"); }) - .pipe(gulp.dest(paths.tmp)); -}); - -gulp.task("plugins-js", function() { - return gulp.src(paths.app + "plugins/**/*.js") - .pipe(gulp.dest(paths.tmp)); + .pipe(concat("app.js")) + .pipe(sourcemaps.write('./maps')) + .pipe(gulp.dest(paths.dist + "js/")); }); gulp.task("jslibs-watch", function() { @@ -292,26 +368,19 @@ gulp.task("jslibs-deploy", function() { .pipe(sourcemaps.init()) .pipe(concat("libs.js")) .pipe(uglify({mangle:false, preserveComments: false})) - .pipe(sourcemaps.write("./")) + .pipe(sourcemaps.write("./maps")) .pipe(gulp.dest(paths.dist + "js/")); }); -gulp.task("app-watch", ["coffee", "plugins-js", "conf", "locales", "app-loader"], function() { - var _paths = paths.js.concat(paths.tmp + "locales.en.js") +gulp.task("app-watch", ["coffee-lint", "coffee", "conf", "locales", "app-loader"]); - return gulp.src(_paths) - .pipe(concat("app.js")) - .pipe(gulp.dest(paths.dist + "js/")); -}); - -gulp.task("app-deploy", ["coffee", "plugins-js", "conf", "locales", "app-loader"], function() { - var _paths = paths.js.concat(paths.tmp + "locales.en.js") - - return gulp.src(_paths) +gulp.task("app-deploy", ["coffee", "conf", "locales", "app-loader"], function() { + return gulp.src(paths.dist) + .pipe(order(paths.coffee_order, {base: '.'})) .pipe(sourcemaps.init()) .pipe(concat("app.js")) .pipe(uglify({mangle:false, preserveComments: false})) - .pipe(sourcemaps.write("./")) + .pipe(sourcemaps.write("./maps")) .pipe(gulp.dest(paths.dist + "js/")); }); @@ -321,8 +390,6 @@ gulp.task("app-deploy", ["coffee", "plugins-js", "conf", "locales", "app-loader" ############################################################################## */ gulp.task("clear", function(done) { - del.sync(paths.tmp); - return cache.clearAll(done); }); @@ -339,7 +406,7 @@ gulp.task("copy-fonts", function() { gulp.task("copy-images", function() { return gulp.src(paths.app + "/images/**/*") - .pipe(imagemin({progressive: true})) + .pipe(gulpif(isDeploy, imagemin({progressive: true}))) .pipe(gulp.dest(paths.dist + "/images/")); }); @@ -372,6 +439,8 @@ gulp.task("express", function() { app.use("/partials", express.static(__dirname + "/dist/partials")); app.use("/fonts", express.static(__dirname + "/dist/fonts")); app.use("/plugins", express.static(__dirname + "/dist/plugins")); + app.use("/locales", express.static(__dirname + "/dist/locales")); + app.use("/maps", express.static(__dirname + "/dist/maps")); app.all("/*", function(req, res, next) { //Just send the index.html for other files to support HTML5Mode @@ -385,14 +454,17 @@ gulp.task("express", function() { gulp.task("watch", function() { gulp.watch(paths.jade, ["jade-watch"]); gulp.watch(paths.sass, ["styles"]); + gulp.watch(paths.styles_dependencies, ["styles-dependencies"]); gulp.watch(paths.svg, ["copy-svg"]); gulp.watch(paths.coffee, ["app-watch"]); gulp.watch(paths.libs, ["jslibs-watch"]); - gulp.watch(paths.locales, ["app-watch"]); + gulp.watch(paths.locales, ["locales"]); gulp.watch(paths.images, ["copy-images"]); gulp.watch(paths.fonts, ["copy-fonts"]); }); +del.sync(paths.tmp); + gulp.task("deploy", function(cb) { runSequence("clear", [ "copy", diff --git a/karma.app.conf.js b/karma.app.conf.js new file mode 100644 index 00000000..9a04d7c8 --- /dev/null +++ b/karma.app.conf.js @@ -0,0 +1,12 @@ +window.taigaConfig = { + "api": "http://localhost:8000/api/v1/", + "eventsUrl": null, + "debug": true, + "defaultLanguage": "en", + "publicRegisterEnabled": true, + "feedbackEnabled": true, + "privacyPolicyUrl": null, + "termsOfServiceUrl": null, + "maxUploadFileSize": null, + "contribPlugins": [] +} diff --git a/karma.conf.js b/karma.conf.js new file mode 100644 index 00000000..3487e4cf --- /dev/null +++ b/karma.conf.js @@ -0,0 +1,84 @@ +// Karma configuration +// Generated on Wed Apr 15 2015 09:44:14 GMT+0200 (CEST) + +module.exports = function(config) { + config.set({ + + // base path that will be used to resolve all patterns (eg. files, exclude) + basePath: '', + + + // frameworks to use + // available frameworks: https://npmjs.org/browse/keyword/karma-adapter + frameworks: ['mocha', 'sinon-chai'], + + + // list of files / patterns to load in the browser + files: [ + 'karma.app.conf.js', + 'dist/js/libs.js', + 'node_modules/angular-mocks/angular-mocks.js', + 'dist/js/app.js', + 'dist/js/templates.js', + 'app/**/*spec.coffee' + ], + + + // list of files to exclude + exclude: [ + ], + + + // preprocess matching files before serving them to the browser + // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor + preprocessors: { + '**/*.coffee': ['coffee'], + 'dist/js/app.js': ['sourcemap'] + }, + + coffeePreprocessor: { + // options passed to the coffee compiler + options: { + bare: true, + sourceMap: true + }, + // transforming the filenames + transformPath: function(path) { + return path.replace(/\.coffee$/, '.js'); + } + }, + + + // test results reporter to use + // possible values: 'dots', 'progress' + // available reporters: https://npmjs.org/browse/keyword/karma-reporter + reporters: ['progress'], + + + // web server port + port: 9876, + + + // enable / disable colors in the output (reporters and logs) + colors: true, + + + // level of logging + // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG + logLevel: config.LOG_INFO, + + + // enable / disable watching file and executing tests whenever any file changes + autoWatch: true, + + + // start these browsers + // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher + browsers: ['Chrome'], + + + // Continuous Integration mode + // if true, Karma captures browsers, runs the tests and exits + singleRun: false + }); +}; diff --git a/locales.js b/locales.js new file mode 100644 index 00000000..76cec254 --- /dev/null +++ b/locales.js @@ -0,0 +1,175 @@ +var glob = require('glob') +var inquirer = require('inquirer'); +var fs = require('fs'); +var _ = require('lodash'); +var Promise = require("bluebird"); +var clc = require('cli-color'); + +var app = 'app/'; + +var question = { + type: 'list', + name: 'command', + message: 'Action', + choices: [ + { + name: 'Replace keys', + value: 'replace-keys' + }, + { + name: 'Find duplicates', + value: 'find-duplicates' + } + ] +}; + +inquirer.prompt([question], function( answer ) { + if (answer.command === 'replace-keys') replaceKeys(); + if (answer.command === 'find-duplicates') findDuplicates(); +}); + +function replaceKeys() { + question() + .then(searchKey) + .then(printFiles) + .then(confirm) + .then(replace) + + + function question() { + return new Promise(function (resolve, reject) { + var questions = [ + { + type: 'input', + message: 'Write the key', + name: 'find_key' + }, + { + type: 'input', + message: 'Write the new key', + name: 'replace_key' + } + ]; + + inquirer.prompt(questions, function(answers) { + resolve({ + answers: answers, + files: [] + }); + }); + }); + } + + function searchKey(obj) { + return new Promise(function (resolve, reject) { + var key = obj.answers.find_key; + + glob(app + '**/*.+(jade|coffee)', {}, function (er, files) { + obj.files = files.filter(function(filepath) { + var file = fs.readFileSync(filepath).toString('utf8'); + + return file.indexOf(key) !== -1; + }); + + resolve(obj); + }); + }); + } + + function printFiles(obj) { + return new Promise(function (resolve, reject) { + obj.files.forEach(function(file) { + console.log(file); + }); + + resolve(obj); + }); + } + + function confirm(obj) { + return new Promise(function (resolve, reject) { + var questions = [ + { + type: 'confirm', + message: 'Are you sure?', + name: 'sure' + } + ]; + + inquirer.prompt(questions, function(answer) { + if (answer.sure) { + resolve(obj); + } else { + reject('Cancel replace'); + } + }); + }); + }; + + function replace(obj) { + obj.files.forEach(function(filepath) { + var file = fs.readFileSync(filepath).toString('utf8'); + var re = new RegExp(obj.answers.find_key, 'g'); + + file = file.replace(re, obj.answers.replace_key); + + fs.writeFile(filepath, file); + }); + } +} + + +function findDuplicates() { + glob(app + 'locales/*.json', {}, function (er, files) { + files.forEach(duplicates); + }); + + function duplicates(file) { + var fileKeys = flatKeys(file); + var duplicates = []; + var value = ''; + var values = _.values(fileKeys); + + for (key in fileKeys) { + value = fileKeys[key]; + + if(duplicates.indexOf(value) !== -1) continue; + + if (values.indexOf(value) !== values.lastIndexOf(value)) { + duplicates.push(value); + + console.log(clc.red(value) + ' duplicate in ' + file); + } + } + } + + function flatKeys(filepath) { + var locale = JSON.parse(fs.readFileSync(filepath).toString('utf8')); + return flatObject(locale); + } +} + + +function flatObject(data, path) { + var flat, keyWithPath, val; + var result = {}; + + if (!path) { + path = []; + } + + for (var key in data) { + val = data[key]; + + if (typeof val === 'object') { + flat = flatObject(val, path.concat(key)); + + _.assign(result, flat); + } else { + keyWithPath = path.length ? ("" + path.join(".") + "." + key) : key; + result[keyWithPath] = val; + } + } + + return result; +}; diff --git a/main-sass.js b/main-sass.js deleted file mode 100644 index 5ebdb49f..00000000 --- a/main-sass.js +++ /dev/null @@ -1,162 +0,0 @@ -exports.files = function () { - var base = process.cwd() + "/tmp/styles/"; - - var files = [ - // Codehilite - 'vendor/codehilite.github', - - //################################################# - // Layout - //################################################# - - 'layout/reset', - 'layout/base', - 'layout/animation', - 'layout/typography', - 'layout/login', - 'layout/invitation', - 'layout/elements', - 'layout/forms', - 'layout/not-found', - 'layout/backlog', - 'layout/taskboard', - 'layout/us-detail', - 'layout/admin-memberships', - 'layout/admin-project-values', - 'layout/project-colors', - 'layout/kanban', - 'layout/issues', - 'layout/wiki', - 'layout/wiki-edit', - 'layout/team', - - //################################################# - // components - //################################################# - - 'components/buttons', - 'components/avatar', - 'components/summary', - 'components/popover', - 'components/tag', - 'components/filter', - 'components/taskboard-task', - 'components/kanban-task', - 'components/notification-message', - 'components/basic-table', - 'components/paginator', - 'components/watchers', - 'components/level', - 'components/created-by', - 'components/wysiwyg', - 'components/select-color', - 'components/loader', - 'components/loading-bar', - 'components/beta', - 'components/markitup', - 'components/markdown-help', - 'components/popover-points', - - - //################################################# - // Modules - //################################################# - - //Common modules - 'modules/common/assigned-to', - 'modules/common/nav', - 'modules/common/projects-nav', - 'modules/common/lightbox', - 'modules/common/colors-table', - 'modules/common/category-config', - 'modules/common/attachments', - 'modules/common/related-tasks', - 'modules/common/history', - 'modules/common/wizard', - 'modules/common/external-reference', - 'modules/common/custom-fields', - - //Project modules - 'modules/home-projects-list', - 'modules/home-project', - 'modules/create-project', - - //Issues modules - 'modules/issues/issues-table', - - //Kanban modules - 'modules/kanban/kanban-table', - - //Search modules - 'modules/search/search-filter', - 'modules/search/search-result-table', - 'modules/search/search-in', - - //Filters modules - 'modules/filters/filters', - 'modules/filters/list-filters', - 'modules/filters/filter-tags', - - //Backlog modules - 'modules/backlog/sprints', - 'modules/backlog/burndown', - 'modules/backlog/backlog-table', - 'modules/backlog/taskboard-table', - - //Login modules - 'modules/auth/login-form', - 'modules/auth/register-form', - 'modules/auth/forgot-form', - 'modules/auth/change-password-from-recovery', - 'modules/auth/cancel-account', - - //Wiki modules - 'modules/wiki/wiki-nav', - 'modules/wiki/wiki-summary', - - //modules admin - 'modules/admin/admin-menu', - 'modules/admin/admin-common', - 'modules/admin/admin-submenu', - 'modules/admin/admin-submenu-roles', - 'modules/admin/admin-roles', - 'modules/admin/admin-functionalities', - 'modules/admin/admin-project-export', - 'modules/admin/admin-membership-table', - 'modules/admin/admin-project-profile', - 'modules/admin/default-values', - 'modules/admin/admin-custom-attributes', - 'modules/admin/project-values', - 'modules/admin/third-parties', - 'modules/admin/admin-third-parties-webhooks', - 'modules/admin/contrib', - 'modules/admin/project-csv', - - //Modules user Settings - 'modules/user-settings/user-profile', - 'modules/user-settings/user-change-password', - 'modules/user-settings/mail-notifications-table', - - //Team - 'modules/team/team-filters', - 'modules/team/team-table', - - //################################################# - // Help - //################################################# - - 'modules/help/lightbox-generic-notion', - - //################################################# - // Shame - //################################################# - - 'shame/shame', - ]; - - files = files.map(function (file) { - return base + file + ".css"; - }); - - return files; -}(); diff --git a/package.json b/package.json index 0b5bd476..46b73b46 100644 --- a/package.json +++ b/package.json @@ -20,16 +20,21 @@ "scss-lint": "gulp scss-lint --fail" }, "devDependencies": { + "angular-mocks": "^1.3.15", + "bluebird": "^2.9.21", + "chai": "^2.2.0", + "cli-color": "^0.3.3", "coffee-script": "^1.9.1", "del": "^1.1.1", "express": "^4.12.0", + "glob": "^5.0.3", "gulp": "^3.8.11", "gulp-angular-templatecache": "^1.5.0", "gulp-autoprefixer": "^2.1.0", "gulp-cache": "^0.2.8", "gulp-cached": "1.0.2", "gulp-coffee": "^2.3.1", - "gulp-coffeelint": "~0.4.0", + "gulp-coffeelint": "^0.4.0", "gulp-concat": "^2.5.2", "gulp-csslint": "^0.1.5", "gulp-flatten": "0.0.4", @@ -39,7 +44,9 @@ "gulp-jade": "^1.0.0", "gulp-jade-inheritance": "0.5.0", "gulp-minify-css": "^0.4.6", + "gulp-order": "^1.1.1", "gulp-plumber": "^0.6.6", + "gulp-print": "^1.1.0", "gulp-rename": "^1.2.0", "gulp-replace": "^0.5.3", "gulp-sass": "^1.3.3", @@ -48,9 +55,20 @@ "gulp-template": "^3.0.0", "gulp-uglify": "~1.1.0", "gulp-wrap": "^0.11.0", + "inquirer": "^0.8.2", + "karma": "^0.12.31", + "karma-chai": "^0.1.0", + "karma-chrome-launcher": "^0.1.7", + "karma-coffee-preprocessor": "^0.2.1", + "karma-mocha": "^0.1.10", + "karma-sinon": "^1.0.4", + "karma-sinon-chai": "^0.3.0", + "karma-sourcemap-loader": "^0.3.4", + "mocha": "^2.2.4", "pre-commit": "^1.0.5", "readable-stream": "~1.0.33", "run-sequence": "^1.0.2", + "sinon": "^1.14.1", "through2": "~0.6.3" }, "pre-commit": [ diff --git a/scripts/manage_translations.py b/scripts/manage_translations.py new file mode 100644 index 00000000..b756efbd --- /dev/null +++ b/scripts/manage_translations.py @@ -0,0 +1,119 @@ +#!/usr/bin/env python +# +# NOTE: This script is based on taiga-back manage_translations.py script +# (https://github.com/taigaio/taiga-back/blob/master/scripts/manage_translations.py) +# +# This python file contains utility scripts to manage taiga translations. +# It has to be run inside the taiga-front git root directory (over the taiga-back env). +# +# The following commands are available: +# +# * fetch: fetch translations from transifex.com +# +# * commit: update resources in transifex.com with the local files +# +# Each command support the --languages and --resources options to limit their +# operation to the specified language or resource. For example, to get stats +# for Spanish in contrib.admin, run: +# +# $ python scripts/manage_translations.py fetch --language=es --resources=locale + + +import os +from argparse import ArgumentParser +from argparse import RawTextHelpFormatter + +from subprocess import PIPE, Popen, call + + +def _tx_resource_for_name(name): + """ Return the Transifex resource name """ + return "taiga-front.{}".format(name) + + +def fetch(resources=None, languages=None): + """ + Fetch translations from Transifex. + """ + if not resources: + if languages is None: + call("tx pull -f --minimum-perc=5", shell=True) + else: + for lang in languages: + call("tx pull -f -l {lang}".format(lang=lang), shell=True) + + else: + for resource in resources: + if languages is None: + call("tx pull -r {res} -f --minimum-perc=5".format(res=_tx_resource_for_name(resource)), + shell=True) + else: + for lang in languages: + call("tx pull -r {res} -f -l {lang}".format(res=_tx_resource_for_name(resource), lang=lang), + shell=True) + + +def commit(resources=None, languages=None): + """ + Commit messages to Transifex, + """ + if not resources: + if languages is None: + call("tx push -s -l en", shell=True) + else: + for lang in languages: + call("tx push -t -l {lang}".format(lang=lang), shell=True) + else: + for resource in resources: + # Transifex push + if languages is None: + call("tx push -r {res} -s -l en".format(res=_tx_resource_for_name(resource)), shell=True) + else: + for lang in languages: + call("tx push -r {res} -t -l {lang}".format(res= _tx_resource_for_name(resource), lang=lang), shell=True) + + +if __name__ == "__main__": + try: + devnull = open(os.devnull) + Popen(["tx"], stdout=devnull, stderr=devnull).communicate() + except OSError as e: + if e.errno == os.errno.ENOENT: + print(""" +You need transifex-client, install it. + + 1. Install transifex-client, use + + $ pip install --upgrade transifex-client==0.11.1.beta + + 2. Create ~/.transifexrc file: + + $ vim ~/.transifexrc" + + [https://www.transifex.com] + hostname = https://www.transifex.com + token = + username = + password = + """) + exit(1) + + RUNABLE_SCRIPTS = { + "commit": "send .json file to transifex ('en' by default).", + "fetch": "get .json files from transifex.", + } + + parser = ArgumentParser(description="manage translations in taiga-front between the repo and transifex.", + formatter_class=RawTextHelpFormatter) + parser.add_argument("cmd", nargs=1, + help="\n".join(["{0} - {1}".format(c, h) for c, h in RUNABLE_SCRIPTS.items()])) + parser.add_argument("-r", "--resources", action="append", + help="limit operation to the specified resources") + parser.add_argument("-l", "--languages", action="append", + help="limit operation to the specified languages") + options = parser.parse_args() + + if options.cmd[0] in RUNABLE_SCRIPTS.keys(): + eval(options.cmd[0])(options.resources, options.languages) + else: + print("Available commands are: {}".format(", ".join(RUNABLE_SCRIPTS.keys())))