提交 64014b15 编写于 作者: D Douwe Maan

Merge branch '28433-internationalise-cycle-analytics-page' into 'master'

Internationalise Cycle Analytics page

Closes #28433

See merge request !10669
......@@ -7,3 +7,4 @@
/vendor/
karma.config.js
webpack.config.js
/app/assets/javascripts/locale/**/*.js
*.log
*.swp
*.mo
*.edit.po
.DS_Store
.bundle
.chef
......@@ -54,3 +56,4 @@ eslint-report.html
/shared/*
/.gitlab_workhorse_secret
/webpack-report/
/locale/**/LC_MESSAGES
......@@ -256,6 +256,11 @@ gem 'sentry-raven', '~> 2.4.0'
gem 'premailer-rails', '~> 1.9.0'
# I18n
gem 'gettext_i18n_rails', '~> 1.8.0'
gem 'gettext_i18n_rails_js', '~> 1.2.0'
gem 'gettext', '~> 3.2.2', require: false, group: :development
# Metrics
group :metrics do
gem 'allocations', '~> 1.0', require: false, platform: :mri
......
......@@ -198,6 +198,7 @@ GEM
faraday_middleware-multi_json (0.0.6)
faraday_middleware
multi_json
fast_gettext (1.4.0)
ffaker (2.4.0)
ffi (1.9.10)
flay (2.8.1)
......@@ -251,6 +252,16 @@ GEM
gemojione (3.0.1)
json
get_process_mem (0.2.0)
gettext (3.2.2)
locale (>= 2.0.5)
text (>= 1.3.0)
gettext_i18n_rails (1.8.0)
fast_gettext (>= 0.9.0)
gettext_i18n_rails_js (1.2.0)
gettext (>= 3.0.2)
gettext_i18n_rails (>= 0.7.1)
po_to_json (>= 1.0.0)
rails (>= 3.2.0)
gherkin-ruby (0.3.2)
gitaly (0.5.0)
google-protobuf (~> 3.1)
......@@ -422,6 +433,7 @@ GEM
licensee (8.7.0)
rugged (~> 0.24)
little-plugger (1.1.4)
locale (2.1.2)
logging (2.1.0)
little-plugger (~> 1.1)
multi_json (~> 1.10)
......@@ -525,6 +537,8 @@ GEM
ast (~> 2.2)
path_expander (1.0.1)
pg (0.18.4)
po_to_json (1.0.1)
json (>= 1.6.0)
poltergeist (1.9.0)
capybara (~> 2.1)
cliver (~> 0.3.1)
......@@ -777,6 +791,7 @@ GEM
temple (0.7.7)
test_after_commit (1.1.0)
activerecord (>= 3.2)
text (1.3.1)
thin (1.7.0)
daemons (~> 1.0, >= 1.0.9)
eventmachine (~> 1.0, >= 1.0.4)
......@@ -904,6 +919,9 @@ DEPENDENCIES
fuubar (~> 2.0.0)
gemnasium-gitlab-service (~> 0.2)
gemojione (~> 3.0)
gettext (~> 3.2.2)
gettext_i18n_rails (~> 1.8.0)
gettext_i18n_rails_js (~> 1.2.0)
gitaly (~> 0.5.0)
github-linguist (~> 4.7.0)
gitlab-flowdock-git-hook (~> 1.0.1)
......
......@@ -9,9 +9,9 @@ export default {
<span v-if="count === 50" class="events-info pull-right">
<i class="fa fa-warning has-tooltip"
aria-hidden="true"
title="Limited to showing 50 events at most"
:title="n__('Limited to showing %d event at most', 'Limited to showing %d events at most', 50)"
data-placement="top"></i>
Showing 50 events
{{ n__('Showing %d event', 'Showing %d events', 50) }}
</span>
`,
};
......@@ -28,11 +28,11 @@ global.cycleAnalytics.StageCodeComponent = Vue.extend({
<a :href="mergeRequest.url" class="issue-link">!{{ mergeRequest.iid }}</a>
&middot;
<span>
Opened
{{ __('OpenedNDaysAgo|Opened') }}
<a :href="mergeRequest.url" class="issue-date">{{ mergeRequest.createdAt }}</a>
</span>
<span>
by
{{ __('ByAuthor|by') }}
<a :href="mergeRequest.author.webUrl" class="issue-author-link">{{ mergeRequest.author.name }}</a>
</span>
</div>
......
......@@ -28,11 +28,11 @@ global.cycleAnalytics.StageIssueComponent = Vue.extend({
<a :href="issue.url" class="issue-link">#{{ issue.iid }}</a>
&middot;
<span>
Opened
{{ __('OpenedNDaysAgo|Opened') }}
<a :href="issue.url" class="issue-date">{{ issue.createdAt }}</a>
</span>
<span>
by
{{ __('ByAuthor|by') }}
<a :href="issue.author.webUrl" class="issue-author-link">
{{ issue.author.name }}
</a>
......
......@@ -31,10 +31,10 @@ global.cycleAnalytics.StagePlanComponent = Vue.extend({
</a>
</h5>
<span>
First
{{ __('FirstPushedBy|First') }}
<span class="commit-icon">${iconCommit}</span>
<a :href="commit.commitUrl" class="commit-hash-link monospace">{{ commit.shortSha }}</a>
pushed by
{{ __('FirstPushedBy|pushed by') }}
<a :href="commit.author.webUrl" class="commit-author-link">
{{ commit.author.name }}
</a>
......
......@@ -28,11 +28,11 @@ global.cycleAnalytics.StageProductionComponent = Vue.extend({
<a :href="issue.url" class="issue-link">#{{ issue.iid }}</a>
&middot;
<span>
Opened
{{ __('OpenedNDaysAgo|Opened') }}
<a :href="issue.url" class="issue-date">{{ issue.createdAt }}</a>
</span>
<span>
by
{{ __('ByAuthor|by') }}
<a :href="issue.author.webUrl" class="issue-author-link">
{{ issue.author.name }}
</a>
......
......@@ -28,11 +28,11 @@ global.cycleAnalytics.StageReviewComponent = Vue.extend({
<a :href="mergeRequest.url" class="issue-link">!{{ mergeRequest.iid }}</a>
&middot;
<span>
Opened
{{ __('OpenedNDaysAgo|Opened') }}
<a :href="mergeRequest.url" class="issue-date">{{ mergeRequest.createdAt }}</a>
</span>
<span>
by
{{ __('ByAuthor|by') }}
<a :href="mergeRequest.author.webUrl" class="issue-author-link">{{ mergeRequest.author.name }}</a>
</span>
<template v-if="mergeRequest.state === 'closed'">
......
......@@ -32,7 +32,7 @@ global.cycleAnalytics.StageStagingComponent = Vue.extend({
</h5>
<span>
<a :href="build.url" class="build-date">{{ build.date }}</a>
by
{{ __('ByAuthor|by') }}
<a :href="build.author.webUrl" class="issue-author-link">
{{ build.author.name }}
</a>
......
......@@ -12,10 +12,10 @@ global.cycleAnalytics.TotalTimeComponent = Vue.extend({
template: `
<span class="total-time">
<template v-if="Object.keys(time).length">
<template v-if="time.days">{{ time.days }} <span>{{ time.days === 1 ? 'day' : 'days' }}</span></template>
<template v-if="time.hours">{{ time.hours }} <span>hr</span></template>
<template v-if="time.mins && !time.days">{{ time.mins }} <span>mins</span></template>
<template v-if="time.seconds && Object.keys(time).length === 1 || time.seconds === 0">{{ time.seconds }} <span>s</span></template>
<template v-if="time.days">{{ time.days }} <span>{{ n__('day', 'days', time.days) }}</span></template>
<template v-if="time.hours">{{ time.hours }} <span>{{ n__('Time|hr', 'Time|hrs', time.hours) }}</span></template>
<template v-if="time.mins && !time.days">{{ time.mins }} <span>{{ n__('Time|min', 'Time|mins', time.mins) }}</span></template>
<template v-if="time.seconds && Object.keys(time).length === 1 || time.seconds === 0">{{ time.seconds }} <span>{{ s__('Time|s') }}</span></template>
</template>
<template v-else>
--
......
......@@ -2,6 +2,7 @@
import Vue from 'vue';
import Cookies from 'js-cookie';
import Translate from '../vue_shared/translate';
import LimitWarningComponent from './components/limit_warning_component';
require('./components/stage_code_component');
......@@ -16,6 +17,8 @@ require('./cycle_analytics_service');
require('./cycle_analytics_store');
require('./default_event_objects');
Vue.use(Translate);
$(() => {
const OVERVIEW_DIALOG_COOKIE = 'cycle_analytics_help_dismissed';
const cycleAnalyticsEl = document.querySelector('#cycle-analytics');
......
......@@ -30,7 +30,7 @@ class CycleAnalyticsService {
startDate,
} = options;
return $.get(`${this.requestPath}/events/${stage.title.toLowerCase()}.json`, {
return $.get(`${this.requestPath}/events/${stage.name}.json`, {
cycle_analytics: {
start_date: startDate,
},
......
/* eslint-disable no-param-reassign */
import { __ } from '../locale';
require('../lib/utils/text_utility');
const DEFAULT_EVENT_OBJECTS = require('./default_event_objects');
......@@ -7,13 +8,13 @@ const global = window.gl || (window.gl = {});
global.cycleAnalytics = global.cycleAnalytics || {};
const EMPTY_STAGE_TEXTS = {
issue: 'The issue stage shows the time it takes from creating an issue to assigning the issue to a milestone, or add the issue to a list on your Issue Board. Begin creating issues to see data for this stage.',
plan: 'The planning stage shows the time from the previous step to pushing your first commit. This time will be added automatically once you push your first commit.',
code: 'The coding stage shows the time from the first commit to creating the merge request. The data will automatically be added here once you create your first merge request.',
test: 'The testing stage shows the time GitLab CI takes to run every pipeline for the related merge request. The data will automatically be added after your first pipeline finishes running.',
review: 'The review stage shows the time from creating the merge request to merging it. The data will automatically be added after you merge your first merge request.',
staging: 'The staging stage shows the time between merging the MR and deploying code to the production environment. The data will be automatically added once you deploy to production for the first time.',
production: 'The production stage shows the total time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle.',
issue: __('The issue stage shows the time it takes from creating an issue to assigning the issue to a milestone, or add the issue to a list on your Issue Board. Begin creating issues to see data for this stage.'),
plan: __('The planning stage shows the time from the previous step to pushing your first commit. This time will be added automatically once you push your first commit.'),
code: __('The coding stage shows the time from the first commit to creating the merge request. The data will automatically be added here once you create your first merge request.'),
test: __('The testing stage shows the time GitLab CI takes to run every pipeline for the related merge request. The data will automatically be added after your first pipeline finishes running.'),
review: __('The review stage shows the time from creating the merge request to merging it. The data will automatically be added after you merge your first merge request.'),
staging: __('The staging stage shows the time between merging the MR and deploying code to the production environment. The data will be automatically added once you deploy to production for the first time.'),
production: __('The production stage shows the total time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle.'),
};
global.cycleAnalytics.CycleAnalyticsStore = {
......@@ -38,7 +39,7 @@ global.cycleAnalytics.CycleAnalyticsStore = {
});
newData.stages.forEach((item) => {
const stageSlug = gl.text.dasherize(item.title.toLowerCase());
const stageSlug = gl.text.dasherize(item.name.toLowerCase());
item.active = false;
item.isUserAllowed = data.permissions[stageSlug];
item.emptyStageText = EMPTY_STAGE_TEXTS[stageSlug];
......
var locales = locales || {}; locales['de'] = {"domain":"app","locale_data":{"app":{"":{"Project-Id-Version":"gitlab 1.0.0","Report-Msgid-Bugs-To":"","PO-Revision-Date":"2017-04-12 22:37-0500","Last-Translator":"FULL NAME <EMAIL@ADDRESS>","Language-Team":"German","Language":"de","MIME-Version":"1.0","Content-Type":"text/plain; charset=UTF-8","Content-Transfer-Encoding":"8bit","Plural-Forms":"nplurals=2; plural=n != 1;","lang":"de","domain":"app","plural_forms":"nplurals=2; plural=n != 1;"},"ByAuthor|by":[""],"Commit":["",""],"Cycle Analytics gives an overview of how much time it takes to go from idea to production in your project.":[""],"CycleAnalyticsStage|Code":[""],"CycleAnalyticsStage|Issue":[""],"CycleAnalyticsStage|Plan":[""],"CycleAnalyticsStage|Production":[""],"CycleAnalyticsStage|Review":[""],"CycleAnalyticsStage|Staging":[""],"CycleAnalyticsStage|Test":[""],"Deploy":["",""],"FirstPushedBy|First":[""],"FirstPushedBy|pushed by":[""],"From issue creation until deploy to production":[""],"From merge request merge until deploy to production":[""],"Introducing Cycle Analytics":[""],"Last %d day":["",""],"Limited to showing %d event at most":["",""],"Median":[""],"New Issue":["",""],"Not available":[""],"Not enough data":[""],"OpenedNDaysAgo|Opened":[""],"Pipeline Health":[""],"ProjectLifecycle|Stage":[""],"Read more":[""],"Related Commits":[""],"Related Deployed Jobs":[""],"Related Issues":[""],"Related Jobs":[""],"Related Merge Requests":[""],"Related Merged Requests":[""],"Showing %d event":["",""],"The coding stage shows the time from the first commit to creating the merge request. The data will automatically be added here once you create your first merge request.":[""],"The collection of events added to the data gathered for that stage.":[""],"The issue stage shows the time it takes from creating an issue to assigning the issue to a milestone, or add the issue to a list on your Issue Board. Begin creating issues to see data for this stage.":[""],"The phase of the development lifecycle.":[""],"The planning stage shows the time from the previous step to pushing your first commit. This time will be added automatically once you push your first commit.":[""],"The production stage shows the total time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle.":[""],"The review stage shows the time from creating the merge request to merging it. The data will automatically be added after you merge your first merge request.":[""],"The staging stage shows the time between merging the MR and deploying code to the production environment. The data will be automatically added once you deploy to production for the first time.":[""],"The testing stage shows the time GitLab CI takes to run every pipeline for the related merge request. The data will automatically be added after your first pipeline finishes running.":[""],"The time taken by each data entry gathered by that stage.":[""],"The value lying at the midpoint of a series of observed values. E.g., between 3, 5, 9, the median is 5. Between 3, 5, 7, 8, the median is (5+7)/2 = 6.":[""],"Time before an issue gets scheduled":[""],"Time before an issue starts implementation":[""],"Time between merge request creation and merge/close":[""],"Time until first merge request":[""],"Time|hr":["",""],"Time|min":["",""],"Time|s":[""],"Total Time":[""],"Total test time for all commits/merges":[""],"Want to see the data? Please ask an administrator for access.":[""],"We don't have enough data to show this stage.":[""],"You need permission.":[""],"day":["",""]}}};
\ No newline at end of file
var locales = locales || {}; locales['en'] = {"domain":"app","locale_data":{"app":{"":{"Project-Id-Version":"gitlab 1.0.0","Report-Msgid-Bugs-To":"","PO-Revision-Date":"2017-04-12 22:36-0500","Last-Translator":"FULL NAME <EMAIL@ADDRESS>","Language-Team":"English","Language":"en","MIME-Version":"1.0","Content-Type":"text/plain; charset=UTF-8","Content-Transfer-Encoding":"8bit","Plural-Forms":"nplurals=2; plural=n != 1;","lang":"en","domain":"app","plural_forms":"nplurals=2; plural=n != 1;"},"ByAuthor|by":[""],"Commit":["",""],"Cycle Analytics gives an overview of how much time it takes to go from idea to production in your project.":[""],"CycleAnalyticsStage|Code":[""],"CycleAnalyticsStage|Issue":[""],"CycleAnalyticsStage|Plan":[""],"CycleAnalyticsStage|Production":[""],"CycleAnalyticsStage|Review":[""],"CycleAnalyticsStage|Staging":[""],"CycleAnalyticsStage|Test":[""],"Deploy":["",""],"FirstPushedBy|First":[""],"FirstPushedBy|pushed by":[""],"From issue creation until deploy to production":[""],"From merge request merge until deploy to production":[""],"Introducing Cycle Analytics":[""],"Last %d day":["",""],"Limited to showing %d event at most":["",""],"Median":[""],"New Issue":["",""],"Not available":[""],"Not enough data":[""],"OpenedNDaysAgo|Opened":[""],"Pipeline Health":[""],"ProjectLifecycle|Stage":[""],"Read more":[""],"Related Commits":[""],"Related Deployed Jobs":[""],"Related Issues":[""],"Related Jobs":[""],"Related Merge Requests":[""],"Related Merged Requests":[""],"Showing %d event":["",""],"The coding stage shows the time from the first commit to creating the merge request. The data will automatically be added here once you create your first merge request.":[""],"The collection of events added to the data gathered for that stage.":[""],"The issue stage shows the time it takes from creating an issue to assigning the issue to a milestone, or add the issue to a list on your Issue Board. Begin creating issues to see data for this stage.":[""],"The phase of the development lifecycle.":[""],"The planning stage shows the time from the previous step to pushing your first commit. This time will be added automatically once you push your first commit.":[""],"The production stage shows the total time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle.":[""],"The review stage shows the time from creating the merge request to merging it. The data will automatically be added after you merge your first merge request.":[""],"The staging stage shows the time between merging the MR and deploying code to the production environment. The data will be automatically added once you deploy to production for the first time.":[""],"The testing stage shows the time GitLab CI takes to run every pipeline for the related merge request. The data will automatically be added after your first pipeline finishes running.":[""],"The time taken by each data entry gathered by that stage.":[""],"The value lying at the midpoint of a series of observed values. E.g., between 3, 5, 9, the median is 5. Between 3, 5, 7, 8, the median is (5+7)/2 = 6.":[""],"Time before an issue gets scheduled":[""],"Time before an issue starts implementation":[""],"Time between merge request creation and merge/close":[""],"Time until first merge request":[""],"Time|hr":["",""],"Time|min":["",""],"Time|s":[""],"Total Time":[""],"Total test time for all commits/merges":[""],"Want to see the data? Please ask an administrator for access.":[""],"We don't have enough data to show this stage.":[""],"You need permission.":[""],"day":["",""]}}};
\ No newline at end of file
var locales = locales || {}; locales['es'] = {"domain":"app","locale_data":{"app":{"":{"Project-Id-Version":"gitlab 1.0.0","Report-Msgid-Bugs-To":"","PO-Revision-Date":"2017-05-04 19:24-0500","Language-Team":"Spanish","Language":"es","MIME-Version":"1.0","Content-Type":"text/plain; charset=UTF-8","Content-Transfer-Encoding":"8bit","Plural-Forms":"nplurals=2; plural=n != 1;","Last-Translator":"","X-Generator":"Poedit 2.0.1","lang":"es","domain":"app","plural_forms":"nplurals=2; plural=n != 1;"},"ByAuthor|by":["por"],"Commit":["Cambio","Cambios"],"Cycle Analytics gives an overview of how much time it takes to go from idea to production in your project.":["Cycle Analytics ofrece una visión general de cuánto tiempo tarda en pasar de idea a producción en su proyecto."],"CycleAnalyticsStage|Code":["Código"],"CycleAnalyticsStage|Issue":["Incidencia"],"CycleAnalyticsStage|Plan":["Planificación"],"CycleAnalyticsStage|Production":["Producción"],"CycleAnalyticsStage|Review":["Revisión"],"CycleAnalyticsStage|Staging":["Puesta en escena"],"CycleAnalyticsStage|Test":["Pruebas"],"Deploy":["Despliegue","Despliegues"],"FirstPushedBy|First":["Primer"],"FirstPushedBy|pushed by":["enviado por"],"From issue creation until deploy to production":["Desde la creación de la incidencia hasta el despliegue a producción"],"From merge request merge until deploy to production":["Desde la integración de la solicitud de fusión hasta el despliegue a producción"],"Introducing Cycle Analytics":["Introducción a Cycle Analytics"],"Last %d day":["Último %d día","Últimos %d días"],"Limited to showing %d event at most":["Limitado a mostrar máximo %d evento","Limitado a mostrar máximo %d eventos"],"Median":["Mediana"],"New Issue":["Nueva incidencia","Nuevas incidencias"],"Not available":["No disponible"],"Not enough data":["No hay suficientes datos"],"OpenedNDaysAgo|Opened":["Abierto"],"Pipeline Health":["Estado del Pipeline"],"ProjectLifecycle|Stage":["Etapa"],"Read more":["Leer más"],"Related Commits":["Cambios Relacionados"],"Related Deployed Jobs":["Trabajos Desplegados Relacionados"],"Related Issues":["Incidencias Relacionadas"],"Related Jobs":["Trabajos Relacionados"],"Related Merge Requests":["Solicitudes de fusión Relacionadas"],"Related Merged Requests":["Solicitudes de fusión Relacionadas"],"Showing %d event":["Mostrando %d evento","Mostrando %d eventos"],"The coding stage shows the time from the first commit to creating the merge request. The data will automatically be added here once you create your first merge request.":["La etapa de codificación muestra el tiempo desde el primer cambio hasta la creación de la solicitud de fusión. Los datos serán automáticamente incorporados aquí una vez creada tu primera solicitud de fusión."],"The collection of events added to the data gathered for that stage.":["La colección de eventos agregados a los datos recopilados para esa etapa."],"The issue stage shows the time it takes from creating an issue to assigning the issue to a milestone, or add the issue to a list on your Issue Board. Begin creating issues to see data for this stage.":["La etapa de incidencia muestra el tiempo que toma desde la creación de un tema hasta asignar el tema a un hito, o añadir el tema a una lista en el panel de temas. Empieza a crear temas para ver los datos de esta etapa."],"The phase of the development lifecycle.":["La etapa del ciclo de vida de desarrollo."],"The planning stage shows the time from the previous step to pushing your first commit. This time will be added automatically once you push your first commit.":["La etapa de planificación muestra el tiempo desde el paso anterior hasta el envío de tu primera confirmación. Este tiempo se añadirá automáticamente una vez que usted envíe el primer cambio."],"The production stage shows the total time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle.":["La etapa de producción muestra el tiempo total que tarda entre la creación de una incidencia y el despliegue del código a producción. Los datos se añadirán automáticamente una vez haya finalizado por completo el ciclo de idea a producción."],"The review stage shows the time from creating the merge request to merging it. The data will automatically be added after you merge your first merge request.":["La etapa de revisión muestra el tiempo desde la creación de la solicitud de fusión hasta que los cambios se fusionaron. Los datos se añadirán automáticamente después de fusionar su primera solicitud de fusión."],"The staging stage shows the time between merging the MR and deploying code to the production environment. The data will be automatically added once you deploy to production for the first time.":["La etapa de puesta en escena muestra el tiempo entre la fusión y el despliegue de código en el entorno de producción. Los datos se añadirán automáticamente una vez que se despliega a producción por primera vez."],"The testing stage shows the time GitLab CI takes to run every pipeline for the related merge request. The data will automatically be added after your first pipeline finishes running.":["La etapa de pruebas muestra el tiempo que GitLab CI toma para ejecutar cada pipeline para la solicitud de fusión relacionada. Los datos se añadirán automáticamente luego de que el primer pipeline termine de ejecutarse."],"The time taken by each data entry gathered by that stage.":["El tiempo utilizado por cada entrada de datos obtenido por esa etapa."],"The value lying at the midpoint of a series of observed values. E.g., between 3, 5, 9, the median is 5. Between 3, 5, 7, 8, the median is (5+7)/2 = 6.":["El valor en el punto medio de una serie de valores observados. Por ejemplo, entre 3, 5, 9, la mediana es 5. Entre 3, 5, 7, 8, la mediana es (5 + 7) / 2 = 6."],"Time before an issue gets scheduled":["Tiempo antes de que una incidencia sea programada"],"Time before an issue starts implementation":["Tiempo antes de que empieze la implementación de una incidencia"],"Time between merge request creation and merge/close":["Tiempo entre la creación de la solicitud de fusión y la integración o cierre de ésta"],"Time until first merge request":["Tiempo hasta la primera solicitud de fusión"],"Time|hr":["hr","hrs"],"Time|min":["min","mins"],"Time|s":["s"],"Total Time":["Tiempo Total"],"Total test time for all commits/merges":["Tiempo total de pruebas para todos los cambios o integraciones"],"Want to see the data? Please ask an administrator for access.":["¿Quieres ver los datos? Por favor pide acceso al administrador."],"We don't have enough data to show this stage.":["No hay suficientes datos para mostrar en esta etapa."],"You need permission.":["Necesitas permisos."],"day":["día","días"]}}};
\ No newline at end of file
import Jed from 'jed';
/**
This is required to require all the translation folders in the current directory
this saves us having to do this manually & keep up to date with new languages
**/
function requireAll(requireContext) { return requireContext.keys().map(requireContext); }
const allLocales = requireAll(require.context('./', true, /^(?!.*(?:index.js$)).*\.js$/));
const locales = allLocales.reduce((d, obj) => {
const data = d;
const localeKey = Object.keys(obj)[0];
data[localeKey] = obj[localeKey];
return data;
}, {});
let lang = document.querySelector('html').getAttribute('lang') || 'en';
lang = lang.replace(/-/g, '_');
const locale = new Jed(locales[lang]);
/**
Translates `text`
@param text The text to be translated
@returns {String} The translated text
**/
const gettext = locale.gettext.bind(locale);
/**
Translate the text with a number
if the number is more than 1 it will use the `pluralText` translation.
This method allows for contexts, see below re. contexts
@param text Singular text to translate (eg. '%d day')
@param pluralText Plural text to translate (eg. '%d days')
@param count Number to decide which translation to use (eg. 2)
@returns {String} Translated text with the number replaced (eg. '2 days')
**/
const ngettext = (text, pluralText, count) => {
const translated = locale.ngettext(text, pluralText, count).replace(/%d/g, count).split('|');
return translated[translated.length - 1];
};
/**
Translate context based text
Either pass in the context translation like `Context|Text to translate`
or allow for dynamic text by doing passing in the context first & then the text to translate
@param keyOrContext Can be either the key to translate including the context
(eg. 'Context|Text') or just the context for the translation
(eg. 'Context')
@param key Is the dynamic variable you want to be translated
@returns {String} Translated context based text
**/
const pgettext = (keyOrContext, key) => {
const normalizedKey = key ? `${keyOrContext}|${key}` : keyOrContext;
const translated = gettext(normalizedKey).split('|');
return translated[translated.length - 1];
};
export { lang };
export { gettext as __ };
export { ngettext as n__ };
export { pgettext as s__ };
export default locale;
import {
__,
n__,
s__,
} from '../locale';
export default (Vue) => {
Vue.mixin({
methods: {
/**
Translates `text`
@param text The text to be translated
@returns {String} The translated text
**/
__,
/**
Translate the text with a number
if the number is more than 1 it will use the `pluralText` translation.
This method allows for contexts, see below re. contexts
@param text Singular text to translate (eg. '%d day')
@param pluralText Plural text to translate (eg. '%d days')
@param count Number to decide which translation to use (eg. 2)
@returns {String} Translated text with the number replaced (eg. '2 days')
**/
n__,
/**
Translate context based text
Either pass in the context translation like `Context|Text to translate`
or allow for dynamic text by doing passing in the context first & then the text to translate
@param keyOrContext Can be either the key to translate including the context
(eg. 'Context|Text') or just the context for the translation
(eg. 'Context')
@param key Is the dynamic variable you want to be translated
@returns {String} Translated context based text
**/
s__,
},
});
};
......@@ -175,7 +175,7 @@
}
.stage-nav-item {
display: block;
display: flex;
line-height: 65px;
border-top: 1px solid transparent;
border-bottom: 1px solid transparent;
......@@ -209,14 +209,10 @@
}
.stage-nav-item-cell {
float: left;
&.stage-name {
width: 65%;
}
&.stage-median {
width: 35%;
margin-left: auto;
margin-right: $gl-padding;
min-width: calc(35% - #{$gl-padding});
}
}
......
......@@ -21,6 +21,8 @@ class ApplicationController < ActionController::Base
before_action :configure_permitted_parameters, if: :devise_controller?
before_action :require_email, unless: :devise_controller?
around_action :set_locale
protect_from_forgery with: :exception
helper_method :can?, :current_application_settings
......@@ -269,4 +271,12 @@ class ApplicationController < ActionController::Base
def u2f_app_id
request.base_url
end
def set_locale
Gitlab::I18n.set_locale(current_user)
yield
ensure
Gitlab::I18n.reset_locale
end
end
......@@ -85,7 +85,8 @@ class ProfilesController < Profiles::ApplicationController
:twitter,
:username,
:website_url,
:organization
:organization,
:preferred_language
)
end
end
......@@ -23,6 +23,7 @@ class User < ActiveRecord::Base
default_value_for :hide_no_password, false
default_value_for :project_view, :files
default_value_for :notified_of_own_activity, false
default_value_for :preferred_language, I18n.default_locale
attr_encrypted :otp_secret,
key: Gitlab::Application.secrets.otp_key_base,
......
......@@ -2,6 +2,7 @@ class AnalyticsStageEntity < Grape::Entity
include EntityDateHelper
expose :title
expose :name
expose :legend
expose :description
......
class AnalyticsSummaryEntity < Grape::Entity
expose :value, safe: true
expose :title do |object|
object.title.pluralize(object.value)
end
expose :title
end
!!! 5
%html{ lang: "en", class: "#{page_class}" }
%html{ lang: I18n.locale, class: "#{page_class}" }
= render "layouts/head"
%body{ class: @body_class, data: { page: body_data_page, project: "#{@project.path if @project}", group: "#{@group.path if @group}" } }
= Gon::Base.render_data
......
......@@ -72,6 +72,11 @@
= f.label :public_email, class: "label-light"
= f.select :public_email, options_for_select(@user.all_emails, selected: @user.public_email), { include_blank: 'Do not show on profile' }, class: "select2"
%span.help-block This email will be displayed on your public profile.
.form-group
= f.label :preferred_language, class: "label-light"
= f.select :preferred_language, Gitlab::I18n::AVAILABLE_LANGUAGES.map { |value, label| [label, value] },
{}, class: "select2"
%span.help-block This feature is experimental and translations are not complete yet.
.form-group
= f.label :skype, class: "label-light"
= f.text_field :skype, class: "form-control"
......
......@@ -2,6 +2,6 @@
.empty-stage
.icon-no-data
= custom_icon ('icon_no_data')
%h4 We don't have enough data to show this stage.
%h4 {{ __('We don\'t have enough data to show this stage.') }}
%p
{{currentStage.emptyStageText}}
......@@ -2,6 +2,6 @@
.no-access-stage
.icon-lock
= custom_icon ('icon_lock')
%h4 You need permission.
%h4 {{ __('You need permission.') }}
%p
Want to see the data? Please ask administrator for access.
{{ __('Want to see the data? Please ask an administrator for access.') }}
......@@ -2,6 +2,7 @@
- page_title "Cycle Analytics"
- content_for :page_specific_javascripts do
= page_specific_javascript_bundle_tag('common_vue')
= page_specific_javascript_bundle_tag('locale')
= page_specific_javascript_bundle_tag('cycle_analytics')
= render "projects/head"
......@@ -15,16 +16,16 @@
= custom_icon('icon_cycle_analytics_splash')
.col-sm-8.col-xs-12.inner-content
%h4
Introducing Cycle Analytics
{{ __('Introducing Cycle Analytics') }}
%p
Cycle Analytics gives an overview of how much time it takes to go from idea to production in your project.
{{ __('Cycle Analytics gives an overview of how much time it takes to go from idea to production in your project.') }}
= link_to "Read more", help_page_path('user/project/cycle_analytics'), target: '_blank', class: 'btn'
= link_to _('Read more'), help_page_path('user/project/cycle_analytics'), target: '_blank', class: 'btn'
= icon("spinner spin", "v-show" => "isLoading")
.wrapper{ "v-show" => "!isLoading && !hasError" }
.panel.panel-default
.panel-heading
Pipeline Health
{{ __('Pipeline Health') }}
.content-block
.container-fluid
.row
......@@ -34,15 +35,15 @@
.col-sm-3.col-xs-12.column
.dropdown.inline.js-ca-dropdown
%button.dropdown-menu-toggle{ "data-toggle" => "dropdown", :type => "button" }
%span.dropdown-label Last 30 days
%span.dropdown-label {{ n__('Last %d day', 'Last %d days', 30) }}
%i.fa.fa-chevron-down
%ul.dropdown-menu.dropdown-menu-align-right
%li
%a{ "href" => "#", "data-value" => "30" }
Last 30 days
{{ n__('Last %d day', 'Last %d days', 30) }}
%li
%a{ "href" => "#", "data-value" => "90" }
Last 90 days
{{ n__('Last %d day', 'Last %d days', 90) }}
.stage-panel-container
.panel.panel-default.stage-panel
.panel-heading
......@@ -50,20 +51,20 @@
%ul
%li.stage-header
%span.stage-name
Stage
%i.has-tooltip.fa.fa-question-circle{ "data-placement" => "top", title: "The phase of the development lifecycle.", "aria-hidden" => "true" }
{{ __('ProjectLifecycle|Stage') }}
%i.has-tooltip.fa.fa-question-circle{ "data-placement" => "top", title: _("The phase of the development lifecycle."), "aria-hidden" => "true" }
%li.median-header
%span.stage-name
Median
%i.has-tooltip.fa.fa-question-circle{ "data-placement" => "top", title: "The value lying at the midpoint of a series of observed values. E.g., between 3, 5, 9, the median is 5. Between 3, 5, 7, 8, the median is (5+7)/2 = 6.", "aria-hidden" => "true" }
{{ __('Median') }}
%i.has-tooltip.fa.fa-question-circle{ "data-placement" => "top", title: _("The value lying at the midpoint of a series of observed values. E.g., between 3, 5, 9, the median is 5. Between 3, 5, 7, 8, the median is (5+7)/2 = 6."), "aria-hidden" => "true" }
%li.event-header
%span.stage-name
{{ currentStage ? currentStage.legend : 'Related Issues' }}
%i.has-tooltip.fa.fa-question-circle{ "data-placement" => "top", title: "The collection of events added to the data gathered for that stage.", "aria-hidden" => "true" }
{{ currentStage ? __(currentStage.legend) : __('Related Issues') }}
%i.has-tooltip.fa.fa-question-circle{ "data-placement" => "top", title: _("The collection of events added to the data gathered for that stage."), "aria-hidden" => "true" }
%li.total-time-header
%span.stage-name
Total Time
%i.has-tooltip.fa.fa-question-circle{ "data-placement" => "top", title: "The time taken by each data entry gathered by that stage.", "aria-hidden" => "true" }
{{ __('Total Time') }}
%i.has-tooltip.fa.fa-question-circle{ "data-placement" => "top", title: _("The time taken by each data entry gathered by that stage."), "aria-hidden" => "true" }
.stage-panel-body
%nav.stage-nav
%ul
......@@ -75,10 +76,10 @@
%span{ "v-if" => "stage.value" }
{{ stage.value }}
%span.stage-empty{ "v-else" => true }
Not enough data
{{ __('Not enough data') }}
%template{ "v-else" => true }
%span.not-available
Not available
{{ __('Not available') }}
.section.stage-events
%template{ "v-if" => "isLoadingStage" }
= icon("spinner spin")
......
---
title: Add support for i18n on Cycle Analytics page
merge_request: 10669
author:
......@@ -40,6 +40,9 @@ module Gitlab
# config.i18n.default_locale = :de
config.i18n.enforce_available_locales = false
# Translation for AR attrs is not working well for POROs like WikiPage
config.gettext_i18n_rails.use_for_active_record_attributes = false
# Configure the default encoding used in templates for Ruby 1.9.
config.encoding = "utf-8"
......
FastGettext.add_text_domain 'gitlab', path: 'locale', type: :po
FastGettext.default_text_domain = 'gitlab'
FastGettext.default_available_locales = Gitlab::I18n.available_locales
I18n.available_locales = Gitlab::I18n.available_locales
require 'gettext_i18n_rails/haml_parser'
require 'gettext_i18n_rails_js/parser/javascript'
VUE_TRANSLATE_REGEX = /((%[\w.-]+)(?:\s))?{{ (N|n|s)?__\((.*)\) }}/
module GettextI18nRails
class HamlParser
singleton_class.send(:alias_method, :old_convert_to_code, :convert_to_code)
# We need to convert text in Mustache format
# to a format that can be parsed by Gettext scripts.
# If we found a content like "{{ __('Stage') }}"
# in a HAML file we convert it to "= _('Stage')", that way
# it can be processed by the "rake gettext:find" script.
#
# Overwrites: https://github.com/grosser/gettext_i18n_rails/blob/8396387a431e0f8ead72fc1cd425cad2fa4992f2/lib/gettext_i18n_rails/haml_parser.rb#L9
def self.convert_to_code(text)
text.gsub!(VUE_TRANSLATE_REGEX, "\\2= \\3_(\\4)")
old_convert_to_code(text)
end
end
end
module GettextI18nRailsJs
module Parser
module Javascript
# This is required to tell the `rake gettext:find` script to use the Javascript
# parser for *.vue files.
#
# Overwrites: https://github.com/webhippie/gettext_i18n_rails_js/blob/46c58db6d2053a4f5f36a0eb024ea706ff5707cb/lib/gettext_i18n_rails_js/parser/javascript.rb#L36
def target?(file)
[
".js",
".jsx",
".coffee",
".vue"
].include? ::File.extname(file)
end
end
end
end
---
de:
activerecord:
errors:
messages:
record_invalid: 'Gültigkeitsprüfung ist fehlgeschlagen: %{errors}'
restrict_dependent_destroy:
has_one: Datensatz kann nicht gelöscht werden, da ein abhängiger %{record}-Datensatz
existiert.
has_many: Datensatz kann nicht gelöscht werden, da abhängige %{record} existieren.
date:
abbr_day_names:
- So
- Mo
- Di
- Mi
- Do
- Fr
- Sa
abbr_month_names:
-
- Jan
- Feb
- Mär
- Apr
- Mai
- Jun
- Jul
- Aug
- Sep
- Okt
- Nov
- Dez
day_names:
- Sonntag
- Montag
- Dienstag
- Mittwoch
- Donnerstag
- Freitag
- Samstag
formats:
default: "%d.%m.%Y"
long: "%e. %B %Y"
short: "%e. %b"
month_names:
-
- Januar
- Februar
- März
- April
- Mai
- Juni
- Juli
- August
- September
- Oktober
- November
- Dezember
order:
- :day
- :month
- :year
datetime:
distance_in_words:
about_x_hours:
one: etwa eine Stunde
other: etwa %{count} Stunden
about_x_months:
one: etwa ein Monat
other: etwa %{count} Monate
about_x_years:
one: etwa ein Jahr
other: etwa %{count} Jahre
almost_x_years:
one: fast ein Jahr
other: fast %{count} Jahre
half_a_minute: eine halbe Minute
less_than_x_minutes:
one: weniger als eine Minute
other: weniger als %{count} Minuten
less_than_x_seconds:
one: weniger als eine Sekunde
other: weniger als %{count} Sekunden
over_x_years:
one: mehr als ein Jahr
other: mehr als %{count} Jahre
x_days:
one: ein Tag
other: "%{count} Tage"
x_minutes:
one: eine Minute
other: "%{count} Minuten"
x_months:
one: ein Monat
other: "%{count} Monate"
x_seconds:
one: eine Sekunde
other: "%{count} Sekunden"
prompts:
day: Tag
hour: Stunden
minute: Minute
month: Monat
second: Sekunde
year: Jahr
errors:
format: "%{attribute} %{message}"
messages:
accepted: muss akzeptiert werden
blank: muss ausgefüllt werden
present: darf nicht ausgefüllt werden
confirmation: stimmt nicht mit %{attribute} überein
empty: muss ausgefüllt werden
equal_to: muss genau %{count} sein
even: muss gerade sein
exclusion: ist nicht verfügbar
greater_than: muss größer als %{count} sein
greater_than_or_equal_to: muss größer oder gleich %{count} sein
inclusion: ist kein gültiger Wert
invalid: ist nicht gültig
less_than: muss kleiner als %{count} sein
less_than_or_equal_to: muss kleiner oder gleich %{count} sein
model_invalid: 'Gültigkeitsprüfung ist fehlgeschlagen: %{errors}'
not_a_number: ist keine Zahl
not_an_integer: muss ganzzahlig sein
odd: muss ungerade sein
required: muss ausgefüllt werden
taken: ist bereits vergeben
too_long:
one: ist zu lang (mehr als 1 Zeichen)
other: ist zu lang (mehr als %{count} Zeichen)
too_short:
one: ist zu kurz (weniger als 1 Zeichen)
other: ist zu kurz (weniger als %{count} Zeichen)
wrong_length:
one: hat die falsche Länge (muss genau 1 Zeichen haben)
other: hat die falsche Länge (muss genau %{count} Zeichen haben)
other_than: darf nicht gleich %{count} sein
template:
body: 'Bitte überprüfen Sie die folgenden Felder:'
header:
one: 'Konnte %{model} nicht speichern: ein Fehler.'
other: 'Konnte %{model} nicht speichern: %{count} Fehler.'
helpers:
select:
prompt: Bitte wählen
submit:
create: "%{model} erstellen"
submit: "%{model} speichern"
update: "%{model} aktualisieren"
number:
currency:
format:
delimiter: "."
format: "%n %u"
precision: 2
separator: ","
significant: false
strip_insignificant_zeros: false
unit: "€"
format:
delimiter: "."
precision: 2
separator: ","
significant: false
strip_insignificant_zeros: false
human:
decimal_units:
format: "%n %u"
units:
billion:
one: Milliarde
other: Milliarden
million:
one: Million
other: Millionen
quadrillion:
one: Billiarde
other: Billiarden
thousand: Tausend
trillion:
one: Billion
other: Billionen
unit: ''
format:
delimiter: ''
precision: 3
significant: true
strip_insignificant_zeros: true
storage_units:
format: "%n %u"
units:
byte:
one: Byte
other: Bytes
gb: GB
kb: KB
mb: MB
tb: TB
percentage:
format:
delimiter: ''
format: "%n %"
precision:
format:
delimiter: ''
support:
array:
last_word_connector: " und "
two_words_connector: " und "
words_connector: ", "
time:
am: vormittags
formats:
default: "%A, %d. %B %Y, %H:%M Uhr"
long: "%A, %d. %B %Y, %H:%M Uhr"
short: "%d. %B, %H:%M Uhr"
pm: nachmittags
---
es:
activerecord:
errors:
messages:
record_invalid: "La validación falló: %{errors}"
restrict_dependent_destroy:
has_one: No se puede eliminar el registro porque existe un %{record} dependiente
has_many: No se puede eliminar el registro porque existen %{record} dependientes
date:
abbr_day_names:
- dom
- lun
- mar
- mié
- jue
- vie
- sáb
abbr_month_names:
-
- ene
- feb
- mar
- abr
- may
- jun
- jul
- ago
- sep
- oct
- nov
- dic
day_names:
- domingo
- lunes
- martes
- miércoles
- jueves
- viernes
- sábado
formats:
default: "%d/%m/%Y"
long: "%d de %B de %Y"
short: "%d de %b"
month_names:
-
- enero
- febrero
- marzo
- abril
- mayo
- junio
- julio
- agosto
- septiembre
- octubre
- noviembre
- diciembre
order:
- :day
- :month
- :year
datetime:
distance_in_words:
about_x_hours:
one: alrededor de 1 hora
other: alrededor de %{count} horas
about_x_months:
one: alrededor de 1 mes
other: alrededor de %{count} meses
about_x_years:
one: alrededor de 1 año
other: alrededor de %{count} años
almost_x_years:
one: casi 1 año
other: casi %{count} años
half_a_minute: medio minuto
less_than_x_minutes:
one: menos de 1 minuto
other: menos de %{count} minutos
less_than_x_seconds:
one: menos de 1 segundo
other: menos de %{count} segundos
over_x_years:
one: más de 1 año
other: más de %{count} años
x_days:
one: 1 día
other: "%{count} días"
x_minutes:
one: 1 minuto
other: "%{count} minutos"
x_months:
one: 1 mes
other: "%{count} meses"
x_years:
one: 1 año
other: "%{count} años"
x_seconds:
one: 1 segundo
other: "%{count} segundos"
prompts:
day: Día
hour: Hora
minute: Minutos
month: Mes
second: Segundos
year: Año
errors:
format: "%{attribute} %{message}"
messages:
accepted: debe ser aceptado
blank: no puede estar en blanco
present: debe estar en blanco
confirmation: no coincide
empty: no puede estar vacío
equal_to: debe ser igual a %{count}
even: debe ser par
exclusion: está reservado
greater_than: debe ser mayor que %{count}
greater_than_or_equal_to: debe ser mayor que o igual a %{count}
inclusion: no está incluido en la lista
invalid: no es válido
less_than: debe ser menor que %{count}
less_than_or_equal_to: debe ser menor que o igual a %{count}
model_invalid: "La validación falló: %{errors}"
not_a_number: no es un número
not_an_integer: debe ser un entero
odd: debe ser impar
required: debe existir
taken: ya está en uso
too_long:
one: "es demasiado largo (1 carácter máximo)"
other: "es demasiado largo (%{count} caracteres máximo)"
too_short:
one: "es demasiado corto (1 carácter mínimo)"
other: "es demasiado corto (%{count} caracteres mínimo)"
wrong_length:
one: "no tiene la longitud correcta (1 carácter exactos)"
other: "no tiene la longitud correcta (%{count} caracteres exactos)"
other_than: debe ser distinto de %{count}
template:
body: 'Se encontraron problemas con los siguientes campos:'
header:
one: No se pudo guardar este/a %{model} porque se encontró 1 error
other: No se pudo guardar este/a %{model} porque se encontraron %{count} errores
helpers:
select:
prompt: Por favor seleccione
submit:
create: Crear %{model}
submit: Guardar %{model}
update: Actualizar %{model}
number:
currency:
format:
delimiter: "."
format: "%n %u"
precision: 2
separator: ","
significant: false
strip_insignificant_zeros: false
unit: "€"
format:
delimiter: "."
precision: 3
separator: ","
significant: false
strip_insignificant_zeros: false
human:
decimal_units:
format: "%n %u"
units:
billion: mil millones
million:
one: millón
other: millones
quadrillion: mil billones
thousand: mil
trillion:
one: billón
other: billones
unit: ''
format:
delimiter: ''
precision: 1
significant: true
strip_insignificant_zeros: true
storage_units:
format: "%n %u"
units:
byte:
one: Byte
other: Bytes
gb: GB
kb: KB
mb: MB
tb: TB
percentage:
format:
delimiter: ''
format: "%n %"
precision:
format:
delimiter: ''
support:
array:
last_word_connector: " y "
two_words_connector: " y "
words_connector: ", "
time:
am: am
formats:
default: "%A, %d de %B de %Y %H:%M:%S %z"
long: "%d de %B de %Y %H:%M"
short: "%d de %b %H:%M"
pm: pm
......@@ -35,7 +35,9 @@ var config = {
group: './group.js',
groups_list: './groups_list.js',
issuable: './issuable/issuable_bundle.js',
locale: './locale/index.js',
issue_show: './issue_show/index.js',
locale: './locale/index.js',
main: './main.js',
merge_conflicts: './merge_conflicts/merge_conflicts_bundle.js',
merge_request_widget: './merge_request_widget/ci_bundle.js',
......@@ -88,6 +90,10 @@ var config = {
exclude: /node_modules/,
loader: 'file-loader',
},
{
test: /locale\/[a-z]+\/(.*)\.js$/,
loader: 'exports-loader?locales',
},
]
},
......@@ -153,6 +159,14 @@ var config = {
new webpack.optimize.CommonsChunkPlugin({
names: ['main', 'common', 'runtime'],
}),
// locale common library
new webpack.optimize.CommonsChunkPlugin({
name: 'locale',
chunks: [
'cycle_analytics',
],
}),
],
resolve: {
......
# See http://doc.gitlab.com/ce/development/migration_style_guide.html
# for more information on how to write migrations for GitLab.
class AddPreferredLanguageToUsers < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
def up
add_column :users, :preferred_language, :string
end
def down
remove_column :users, :preferred_language
end
end
......@@ -1328,6 +1328,7 @@ ActiveRecord::Schema.define(version: 20170503004425) do
t.boolean "notified_of_own_activity"
t.boolean "require_two_factor_authentication_from_group", default: false, null: false
t.integer "two_factor_grace_period", default: 48, null: false
t.string "preferred_language"
end
add_index "users", ["admin"], name: "index_users_on_admin", using: :btree
......
......@@ -44,6 +44,9 @@ module API
end
before { allow_access_with_scope :api }
before { Gitlab::I18n.set_locale(current_user) }
after { Gitlab::I18n.reset_locale }
rescue_from Gitlab::Access::AccessDeniedError do
rack_response({ 'message' => '403 Forbidden' }.to_json, 403)
......
......@@ -17,7 +17,7 @@ module Gitlab
end
def title
name.to_s.capitalize
raise NotImplementedError.new("Expected #{self.name} to implement title")
end
def median
......
......@@ -13,12 +13,16 @@ module Gitlab
:code
end
def title
s_('CycleAnalyticsStage|Code')
end
def legend
"Related Merge Requests"
_("Related Merge Requests")
end
def description
"Time until first merge request"
_("Time until first merge request")
end
end
end
......
......@@ -14,12 +14,16 @@ module Gitlab
:issue
end
def title
s_('CycleAnalyticsStage|Issue')
end
def legend
"Related Issues"
_("Related Issues")
end
def description
"Time before an issue gets scheduled"
_("Time before an issue gets scheduled")
end
end
end
......
......@@ -14,12 +14,16 @@ module Gitlab
:plan
end
def title
s_('CycleAnalyticsStage|Plan')
end
def legend
"Related Commits"
_("Related Commits")
end
def description
"Time before an issue starts implementation"
_("Time before an issue starts implementation")
end
end
end
......
......@@ -15,12 +15,16 @@ module Gitlab
:production
end
def title
s_('CycleAnalyticsStage|Production')
end
def legend
"Related Issues"
_("Related Issues")
end
def description
"From issue creation until deploy to production"
_("From issue creation until deploy to production")
end
def query
......
......@@ -13,12 +13,16 @@ module Gitlab
:review
end
def title
s_('CycleAnalyticsStage|Review')
end
def legend
"Related Merged Requests"
_("Related Merged Requests")
end
def description
"Time between merge request creation and merge/close"
_("Time between merge request creation and merge/close")
end
end
end
......
......@@ -14,12 +14,16 @@ module Gitlab
:staging
end
def title
s_('CycleAnalyticsStage|Staging')
end
def legend
"Related Deployed Jobs"
_("Related Deployed Jobs")
end
def description
"From merge request merge until deploy to production"
_("From merge request merge until deploy to production")
end
end
end
......
......@@ -8,7 +8,7 @@ module Gitlab
end
def title
self.class.name.demodulize
raise NotImplementedError.new("Expected #{self.name} to implement title")
end
def value
......
......@@ -2,6 +2,10 @@ module Gitlab
module CycleAnalytics
module Summary
class Commit < Base
def title
n_('Commit', 'Commits', value)
end
def value
@value ||= count_commits
end
......
......@@ -2,6 +2,10 @@ module Gitlab
module CycleAnalytics
module Summary
class Deploy < Base
def title
n_('Deploy', 'Deploys', value)
end
def value
@value ||= @project.deployments.where("created_at > ?", @from).count
end
......
......@@ -9,7 +9,7 @@ module Gitlab
end
def title
'New Issue'
n_('New Issue', 'New Issues', value)
end
def value
......
......@@ -13,12 +13,16 @@ module Gitlab
:test
end
def title
s_('CycleAnalyticsStage|Test')
end
def legend
"Related Jobs"
_("Related Jobs")
end
def description
"Total test time for all commits/merges"
_("Total test time for all commits/merges")
end
def stage_query
......
module Gitlab
module I18n
extend self
AVAILABLE_LANGUAGES = {
'en' => 'English',
'es' => 'Español',
'de' => 'Deutsch'
}.freeze
def available_locales
AVAILABLE_LANGUAGES.keys
end
def set_locale(current_user)
requested_locale = current_user&.preferred_language || ::I18n.default_locale
locale = FastGettext.set_locale(requested_locale)
::I18n.locale = locale
end
def reset_locale
FastGettext.set_locale(::I18n.default_locale)
::I18n.locale = ::I18n.default_locale
end
end
end
require "gettext_i18n_rails/tasks"
namespace :gettext do
# Customize list of translatable files
# See: https://github.com/grosser/gettext_i18n_rails#customizing-list-of-translatable-files
def files_to_translate
folders = %W(app lib config #{locale_path}).join(',')
exts = %w(rb erb haml slim rhtml js jsx vue coffee handlebars hbs mustache).join(',')
Dir.glob(
"{#{folders}}/**/*.{#{exts}}"
)
end
end
# German translations for gitlab package.
# Copyright (C) 2017 THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the gitlab package.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2017.
#
msgid ""
msgstr ""
"Project-Id-Version: gitlab 1.0.0\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2017-04-12 22:37-0500\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: German\n"
"Language: de\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"\n"
msgid "ByAuthor|by"
msgstr ""
msgid "Commit"
msgid_plural "Commits"
msgstr[0] ""
msgstr[1] ""
msgid "Cycle Analytics gives an overview of how much time it takes to go from idea to production in your project."
msgstr ""
msgid "CycleAnalyticsStage|Code"
msgstr ""
msgid "CycleAnalyticsStage|Issue"
msgstr ""
msgid "CycleAnalyticsStage|Plan"
msgstr ""
msgid "CycleAnalyticsStage|Production"
msgstr ""
msgid "CycleAnalyticsStage|Review"
msgstr ""
msgid "CycleAnalyticsStage|Staging"
msgstr ""
msgid "CycleAnalyticsStage|Test"
msgstr ""
msgid "Deploy"
msgid_plural "Deploys"
msgstr[0] ""
msgstr[1] ""
msgid "FirstPushedBy|First"
msgstr ""
msgid "FirstPushedBy|pushed by"
msgstr ""
msgid "From issue creation until deploy to production"
msgstr ""
msgid "From merge request merge until deploy to production"
msgstr ""
msgid "Introducing Cycle Analytics"
msgstr ""
msgid "Last %d day"
msgid_plural "Last %d days"
msgstr[0] ""
msgstr[1] ""
msgid "Limited to showing %d event at most"
msgid_plural "Limited to showing %d events at most"
msgstr[0] ""
msgstr[1] ""
msgid "Median"
msgstr ""
msgid "New Issue"
msgid_plural "New Issues"
msgstr[0] ""
msgstr[1] ""
msgid "Not available"
msgstr ""
msgid "Not enough data"
msgstr ""
msgid "OpenedNDaysAgo|Opened"
msgstr ""
msgid "Pipeline Health"
msgstr ""
msgid "ProjectLifecycle|Stage"
msgstr ""
msgid "Read more"
msgstr ""
msgid "Related Commits"
msgstr ""
msgid "Related Deployed Jobs"
msgstr ""
msgid "Related Issues"
msgstr ""
msgid "Related Jobs"
msgstr ""
msgid "Related Merge Requests"
msgstr ""
msgid "Related Merged Requests"
msgstr ""
msgid "Showing %d event"
msgid_plural "Showing %d events"
msgstr[0] ""
msgstr[1] ""
msgid "The coding stage shows the time from the first commit to creating the merge request. The data will automatically be added here once you create your first merge request."
msgstr ""
msgid "The collection of events added to the data gathered for that stage."
msgstr ""
msgid "The issue stage shows the time it takes from creating an issue to assigning the issue to a milestone, or add the issue to a list on your Issue Board. Begin creating issues to see data for this stage."
msgstr ""
msgid "The phase of the development lifecycle."
msgstr ""
msgid "The planning stage shows the time from the previous step to pushing your first commit. This time will be added automatically once you push your first commit."
msgstr ""
msgid "The production stage shows the total time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle."
msgstr ""
msgid "The review stage shows the time from creating the merge request to merging it. The data will automatically be added after you merge your first merge request."
msgstr ""
msgid "The staging stage shows the time between merging the MR and deploying code to the production environment. The data will be automatically added once you deploy to production for the first time."
msgstr ""
msgid "The testing stage shows the time GitLab CI takes to run every pipeline for the related merge request. The data will automatically be added after your first pipeline finishes running."
msgstr ""
msgid "The time taken by each data entry gathered by that stage."
msgstr ""
msgid "The value lying at the midpoint of a series of observed values. E.g., between 3, 5, 9, the median is 5. Between 3, 5, 7, 8, the median is (5+7)/2 = 6."
msgstr ""
msgid "Time before an issue gets scheduled"
msgstr ""
msgid "Time before an issue starts implementation"
msgstr ""
msgid "Time between merge request creation and merge/close"
msgstr ""
msgid "Time until first merge request"
msgstr ""
msgid "Time|hr"
msgid_plural "Time|hrs"
msgstr[0] ""
msgstr[1] ""
msgid "Time|min"
msgid_plural "Time|mins"
msgstr[0] ""
msgstr[1] ""
msgid "Time|s"
msgstr ""
msgid "Total Time"
msgstr ""
msgid "Total test time for all commits/merges"
msgstr ""
msgid "Want to see the data? Please ask an administrator for access."
msgstr ""
msgid "We don't have enough data to show this stage."
msgstr ""
msgid "You need permission."
msgstr ""
msgid "day"
msgid_plural "days"
msgstr[0] ""
msgstr[1] ""
# English translations for gitlab package.
# Copyright (C) 2017 THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the gitlab package.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2017.
#
msgid ""
msgstr ""
"Project-Id-Version: gitlab 1.0.0\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2017-04-12 22:36-0500\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: English\n"
"Language: en\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"\n"
msgid "ByAuthor|by"
msgstr ""
msgid "Commit"
msgid_plural "Commits"
msgstr[0] ""
msgstr[1] ""
msgid "Cycle Analytics gives an overview of how much time it takes to go from idea to production in your project."
msgstr ""
msgid "CycleAnalyticsStage|Code"
msgstr ""
msgid "CycleAnalyticsStage|Issue"
msgstr ""
msgid "CycleAnalyticsStage|Plan"
msgstr ""
msgid "CycleAnalyticsStage|Production"
msgstr ""
msgid "CycleAnalyticsStage|Review"
msgstr ""
msgid "CycleAnalyticsStage|Staging"
msgstr ""
msgid "CycleAnalyticsStage|Test"
msgstr ""
msgid "Deploy"
msgid_plural "Deploys"
msgstr[0] ""
msgstr[1] ""
msgid "FirstPushedBy|First"
msgstr ""
msgid "FirstPushedBy|pushed by"
msgstr ""
msgid "From issue creation until deploy to production"
msgstr ""
msgid "From merge request merge until deploy to production"
msgstr ""
msgid "Introducing Cycle Analytics"
msgstr ""
msgid "Last %d day"
msgid_plural "Last %d days"
msgstr[0] ""
msgstr[1] ""
msgid "Limited to showing %d event at most"
msgid_plural "Limited to showing %d events at most"
msgstr[0] ""
msgstr[1] ""
msgid "Median"
msgstr ""
msgid "New Issue"
msgid_plural "New Issues"
msgstr[0] ""
msgstr[1] ""
msgid "Not available"
msgstr ""
msgid "Not enough data"
msgstr ""
msgid "OpenedNDaysAgo|Opened"
msgstr ""
msgid "Pipeline Health"
msgstr ""
msgid "ProjectLifecycle|Stage"
msgstr ""
msgid "Read more"
msgstr ""
msgid "Related Commits"
msgstr ""
msgid "Related Deployed Jobs"
msgstr ""
msgid "Related Issues"
msgstr ""
msgid "Related Jobs"
msgstr ""
msgid "Related Merge Requests"
msgstr ""
msgid "Related Merged Requests"
msgstr ""
msgid "Showing %d event"
msgid_plural "Showing %d events"
msgstr[0] ""
msgstr[1] ""
msgid "The coding stage shows the time from the first commit to creating the merge request. The data will automatically be added here once you create your first merge request."
msgstr ""
msgid "The collection of events added to the data gathered for that stage."
msgstr ""
msgid "The issue stage shows the time it takes from creating an issue to assigning the issue to a milestone, or add the issue to a list on your Issue Board. Begin creating issues to see data for this stage."
msgstr ""
msgid "The phase of the development lifecycle."
msgstr ""
msgid "The planning stage shows the time from the previous step to pushing your first commit. This time will be added automatically once you push your first commit."
msgstr ""
msgid "The production stage shows the total time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle."
msgstr ""
msgid "The review stage shows the time from creating the merge request to merging it. The data will automatically be added after you merge your first merge request."
msgstr ""
msgid "The staging stage shows the time between merging the MR and deploying code to the production environment. The data will be automatically added once you deploy to production for the first time."
msgstr ""
msgid "The testing stage shows the time GitLab CI takes to run every pipeline for the related merge request. The data will automatically be added after your first pipeline finishes running."
msgstr ""
msgid "The time taken by each data entry gathered by that stage."
msgstr ""
msgid "The value lying at the midpoint of a series of observed values. E.g., between 3, 5, 9, the median is 5. Between 3, 5, 7, 8, the median is (5+7)/2 = 6."
msgstr ""
msgid "Time before an issue gets scheduled"
msgstr ""
msgid "Time before an issue starts implementation"
msgstr ""
msgid "Time between merge request creation and merge/close"
msgstr ""
msgid "Time until first merge request"
msgstr ""
msgid "Time|hr"
msgid_plural "Time|hrs"
msgstr[0] ""
msgstr[1] ""
msgid "Time|min"
msgid_plural "Time|mins"
msgstr[0] ""
msgstr[1] ""
msgid "Time|s"
msgstr ""
msgid "Total Time"
msgstr ""
msgid "Total test time for all commits/merges"
msgstr ""
msgid "Want to see the data? Please ask an administrator for access."
msgstr ""
msgid "We don't have enough data to show this stage."
msgstr ""
msgid "You need permission."
msgstr ""
msgid "day"
msgid_plural "days"
msgstr[0] ""
msgstr[1] ""
# Spanish translations for gitlab package.
# Copyright (C) 2017 THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the gitlab package.
# FIRST AUTHOR <EMAIL@ADDRESS>, 2017.
#
msgid ""
msgstr ""
"Project-Id-Version: gitlab 1.0.0\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2017-05-04 19:24-0500\n"
"Language-Team: Spanish\n"
"Language: es\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"Last-Translator: \n"
"X-Generator: Poedit 2.0.1\n"
msgid "ByAuthor|by"
msgstr "por"
msgid "Commit"
msgid_plural "Commits"
msgstr[0] "Cambio"
msgstr[1] "Cambios"
msgid "Cycle Analytics gives an overview of how much time it takes to go from idea to production in your project."
msgstr "Cycle Analytics ofrece una visión general de cuánto tiempo tarda en pasar de idea a producción en su proyecto."
msgid "CycleAnalyticsStage|Code"
msgstr "Código"
msgid "CycleAnalyticsStage|Issue"
msgstr "Incidencia"
msgid "CycleAnalyticsStage|Plan"
msgstr "Planificación"
msgid "CycleAnalyticsStage|Production"
msgstr "Producción"
msgid "CycleAnalyticsStage|Review"
msgstr "Revisión"
#, fuzzy
msgid "CycleAnalyticsStage|Staging"
msgstr "Puesta en escena"
msgid "CycleAnalyticsStage|Test"
msgstr "Pruebas"
msgid "Deploy"
msgid_plural "Deploys"
msgstr[0] "Despliegue"
msgstr[1] "Despliegues"
msgid "FirstPushedBy|First"
msgstr "Primer"
msgid "FirstPushedBy|pushed by"
msgstr "enviado por"
msgid "From issue creation until deploy to production"
msgstr "Desde la creación de la incidencia hasta el despliegue a producción"
msgid "From merge request merge until deploy to production"
msgstr "Desde la integración de la solicitud de fusión hasta el despliegue a producción"
msgid "Introducing Cycle Analytics"
msgstr "Introducción a Cycle Analytics"
msgid "Last %d day"
msgid_plural "Last %d days"
msgstr[0] "Último %d día"
msgstr[1] "Últimos %d días"
msgid "Limited to showing %d event at most"
msgid_plural "Limited to showing %d events at most"
msgstr[0] "Limitado a mostrar máximo %d evento"
msgstr[1] "Limitado a mostrar máximo %d eventos"
msgid "Median"
msgstr "Mediana"
msgid "New Issue"
msgid_plural "New Issues"
msgstr[0] "Nueva incidencia"
msgstr[1] "Nuevas incidencias"
msgid "Not available"
msgstr "No disponible"
msgid "Not enough data"
msgstr "No hay suficientes datos"
msgid "OpenedNDaysAgo|Opened"
msgstr "Abierto"
msgid "Pipeline Health"
msgstr "Estado del Pipeline"
msgid "ProjectLifecycle|Stage"
msgstr "Etapa"
msgid "Read more"
msgstr "Leer más"
msgid "Related Commits"
msgstr "Cambios Relacionados"
msgid "Related Deployed Jobs"
msgstr "Trabajos Desplegados Relacionados"
msgid "Related Issues"
msgstr "Incidencias Relacionadas"
msgid "Related Jobs"
msgstr "Trabajos Relacionados"
msgid "Related Merge Requests"
msgstr "Solicitudes de fusión Relacionadas"
msgid "Related Merged Requests"
msgstr "Solicitudes de fusión Relacionadas"
msgid "Showing %d event"
msgid_plural "Showing %d events"
msgstr[0] "Mostrando %d evento"
msgstr[1] "Mostrando %d eventos"
msgid "The coding stage shows the time from the first commit to creating the merge request. The data will automatically be added here once you create your first merge request."
msgstr "La etapa de codificación muestra el tiempo desde el primer cambio hasta la creación de la solicitud de fusión. Los datos serán automáticamente incorporados aquí una vez creada tu primera solicitud de fusión."
msgid "The collection of events added to the data gathered for that stage."
msgstr "La colección de eventos agregados a los datos recopilados para esa etapa."
msgid "The issue stage shows the time it takes from creating an issue to assigning the issue to a milestone, or add the issue to a list on your Issue Board. Begin creating issues to see data for this stage."
msgstr "La etapa de incidencia muestra el tiempo que toma desde la creación de un tema hasta asignar el tema a un hito, o añadir el tema a una lista en el panel de temas. Empieza a crear temas para ver los datos de esta etapa."
msgid "The phase of the development lifecycle."
msgstr "La etapa del ciclo de vida de desarrollo."
msgid "The planning stage shows the time from the previous step to pushing your first commit. This time will be added automatically once you push your first commit."
msgstr "La etapa de planificación muestra el tiempo desde el paso anterior hasta el envío de tu primera confirmación. Este tiempo se añadirá automáticamente una vez que usted envíe el primer cambio."
msgid "The production stage shows the total time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle."
msgstr "La etapa de producción muestra el tiempo total que tarda entre la creación de una incidencia y el despliegue del código a producción. Los datos se añadirán automáticamente una vez haya finalizado por completo el ciclo de idea a producción."
msgid "The review stage shows the time from creating the merge request to merging it. The data will automatically be added after you merge your first merge request."
msgstr "La etapa de revisión muestra el tiempo desde la creación de la solicitud de fusión hasta que los cambios se fusionaron. Los datos se añadirán automáticamente después de fusionar su primera solicitud de fusión."
msgid "The staging stage shows the time between merging the MR and deploying code to the production environment. The data will be automatically added once you deploy to production for the first time."
msgstr "La etapa de puesta en escena muestra el tiempo entre la fusión y el despliegue de código en el entorno de producción. Los datos se añadirán automáticamente una vez que se despliega a producción por primera vez."
msgid "The testing stage shows the time GitLab CI takes to run every pipeline for the related merge request. The data will automatically be added after your first pipeline finishes running."
msgstr "La etapa de pruebas muestra el tiempo que GitLab CI toma para ejecutar cada pipeline para la solicitud de fusión relacionada. Los datos se añadirán automáticamente luego de que el primer pipeline termine de ejecutarse."
msgid "The time taken by each data entry gathered by that stage."
msgstr "El tiempo utilizado por cada entrada de datos obtenido por esa etapa."
msgid "The value lying at the midpoint of a series of observed values. E.g., between 3, 5, 9, the median is 5. Between 3, 5, 7, 8, the median is (5+7)/2 = 6."
msgstr "El valor en el punto medio de una serie de valores observados. Por ejemplo, entre 3, 5, 9, la mediana es 5. Entre 3, 5, 7, 8, la mediana es (5 + 7) / 2 = 6."
msgid "Time before an issue gets scheduled"
msgstr "Tiempo antes de que una incidencia sea programada"
msgid "Time before an issue starts implementation"
msgstr "Tiempo antes de que empieze la implementación de una incidencia"
msgid "Time between merge request creation and merge/close"
msgstr "Tiempo entre la creación de la solicitud de fusión y la integración o cierre de ésta"
msgid "Time until first merge request"
msgstr "Tiempo hasta la primera solicitud de fusión"
msgid "Time|hr"
msgid_plural "Time|hrs"
msgstr[0] "hr"
msgstr[1] "hrs"
msgid "Time|min"
msgid_plural "Time|mins"
msgstr[0] "min"
msgstr[1] "mins"
msgid "Time|s"
msgstr "s"
msgid "Total Time"
msgstr "Tiempo Total"
msgid "Total test time for all commits/merges"
msgstr "Tiempo total de pruebas para todos los cambios o integraciones"
msgid "Want to see the data? Please ask an administrator for access."
msgstr "¿Quieres ver los datos? Por favor pide acceso al administrador."
msgid "We don't have enough data to show this stage."
msgstr "No hay suficientes datos para mostrar en esta etapa."
msgid "You need permission."
msgstr "Necesitas permisos."
msgid "day"
msgid_plural "days"
msgstr[0] "día"
msgstr[1] "días"
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the gitlab package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: gitlab 1.0.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2017-05-04 19:24-0500\n"
"PO-Revision-Date: 2017-05-04 19:24-0500\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n"
msgid "ByAuthor|by"
msgstr ""
msgid "Commit"
msgid_plural "Commits"
msgstr[0] ""
msgstr[1] ""
msgid "Cycle Analytics gives an overview of how much time it takes to go from idea to production in your project."
msgstr ""
msgid "CycleAnalyticsStage|Code"
msgstr ""
msgid "CycleAnalyticsStage|Issue"
msgstr ""
msgid "CycleAnalyticsStage|Plan"
msgstr ""
msgid "CycleAnalyticsStage|Production"
msgstr ""
msgid "CycleAnalyticsStage|Review"
msgstr ""
msgid "CycleAnalyticsStage|Staging"
msgstr ""
msgid "CycleAnalyticsStage|Test"
msgstr ""
msgid "Deploy"
msgid_plural "Deploys"
msgstr[0] ""
msgstr[1] ""
msgid "FirstPushedBy|First"
msgstr ""
msgid "FirstPushedBy|pushed by"
msgstr ""
msgid "From issue creation until deploy to production"
msgstr ""
msgid "From merge request merge until deploy to production"
msgstr ""
msgid "Introducing Cycle Analytics"
msgstr ""
msgid "Last %d day"
msgid_plural "Last %d days"
msgstr[0] ""
msgstr[1] ""
msgid "Limited to showing %d event at most"
msgid_plural "Limited to showing %d events at most"
msgstr[0] ""
msgstr[1] ""
msgid "Median"
msgstr ""
msgid "New Issue"
msgid_plural "New Issues"
msgstr[0] ""
msgstr[1] ""
msgid "Not available"
msgstr ""
msgid "Not enough data"
msgstr ""
msgid "OpenedNDaysAgo|Opened"
msgstr ""
msgid "Pipeline Health"
msgstr ""
msgid "ProjectLifecycle|Stage"
msgstr ""
msgid "Read more"
msgstr ""
msgid "Related Commits"
msgstr ""
msgid "Related Deployed Jobs"
msgstr ""
msgid "Related Issues"
msgstr ""
msgid "Related Jobs"
msgstr ""
msgid "Related Merge Requests"
msgstr ""
msgid "Related Merged Requests"
msgstr ""
msgid "Showing %d event"
msgid_plural "Showing %d events"
msgstr[0] ""
msgstr[1] ""
msgid "The coding stage shows the time from the first commit to creating the merge request. The data will automatically be added here once you create your first merge request."
msgstr ""
msgid "The collection of events added to the data gathered for that stage."
msgstr ""
msgid "The issue stage shows the time it takes from creating an issue to assigning the issue to a milestone, or add the issue to a list on your Issue Board. Begin creating issues to see data for this stage."
msgstr ""
msgid "The phase of the development lifecycle."
msgstr ""
msgid "The planning stage shows the time from the previous step to pushing your first commit. This time will be added automatically once you push your first commit."
msgstr ""
msgid "The production stage shows the total time it takes between creating an issue and deploying the code to production. The data will be automatically added once you have completed the full idea to production cycle."
msgstr ""
msgid "The review stage shows the time from creating the merge request to merging it. The data will automatically be added after you merge your first merge request."
msgstr ""
msgid "The staging stage shows the time between merging the MR and deploying code to the production environment. The data will be automatically added once you deploy to production for the first time."
msgstr ""
msgid "The testing stage shows the time GitLab CI takes to run every pipeline for the related merge request. The data will automatically be added after your first pipeline finishes running."
msgstr ""
msgid "The time taken by each data entry gathered by that stage."
msgstr ""
msgid "The value lying at the midpoint of a series of observed values. E.g., between 3, 5, 9, the median is 5. Between 3, 5, 7, 8, the median is (5+7)/2 = 6."
msgstr ""
msgid "Time before an issue gets scheduled"
msgstr ""
msgid "Time before an issue starts implementation"
msgstr ""
msgid "Time between merge request creation and merge/close"
msgstr ""
msgid "Time until first merge request"
msgstr ""
msgid "Time|hr"
msgid_plural "Time|hrs"
msgstr[0] ""
msgstr[1] ""
msgid "Time|min"
msgid_plural "Time|mins"
msgstr[0] ""
msgstr[1] ""
msgid "Time|s"
msgstr ""
msgid "Total Time"
msgstr ""
msgid "Total test time for all commits/merges"
msgstr ""
msgid "Want to see the data? Please ask an administrator for access."
msgstr ""
msgid "We don't have enough data to show this stage."
msgstr ""
msgid "You need permission."
msgstr ""
msgid "day"
msgid_plural "days"
msgstr[0] ""
msgstr[1] ""
......@@ -62,6 +62,25 @@ feature 'Cycle Analytics', feature: true, js: true do
expect_issue_to_be_present
end
end
context "when my preferred language is Spanish" do
before do
user.update_attribute(:preferred_language, 'es')
project.team << [user, :master]
login_as(user)
visit namespace_project_cycle_analytics_path(project.namespace, project)
wait_for_ajax
end
it 'shows the content in Spanish' do
expect(page).to have_content('Estado del Pipeline')
end
it 'resets the language to English' do
expect(I18n.locale).to eq(:en)
end
end
end
context "as a guest" do
......
import Vue from 'vue';
import Translate from '~/vue_shared/translate';
import limitWarningComp from '~/cycle_analytics/components/limit_warning_component';
Vue.use(Translate);
describe('Limit warning component', () => {
let component;
let LimitWarningComponent;
......
import Vue from 'vue';
import Translate from '~/vue_shared/translate';
Vue.use(Translate);
describe('Vue translate filter', () => {
let el;
beforeEach(() => {
el = document.createElement('div');
document.body.appendChild(el);
});
it('translate single text', (done) => {
const comp = new Vue({
el,
template: `
<span>
{{ __('testing') }}
</span>
`,
}).$mount();
Vue.nextTick(() => {
expect(
comp.$el.textContent.trim(),
).toBe('testing');
done();
});
});
it('translate plural text with single count', (done) => {
const comp = new Vue({
el,
template: `
<span>
{{ n__('%d day', '%d days', 1) }}
</span>
`,
}).$mount();
Vue.nextTick(() => {
expect(
comp.$el.textContent.trim(),
).toBe('1 day');
done();
});
});
it('translate plural text with multiple count', (done) => {
const comp = new Vue({
el,
template: `
<span>
{{ n__('%d day', '%d days', 2) }}
</span>
`,
}).$mount();
Vue.nextTick(() => {
expect(
comp.$el.textContent.trim(),
).toBe('2 days');
done();
});
});
it('translate plural without replacing any text', (done) => {
const comp = new Vue({
el,
template: `
<span>
{{ n__('day', 'days', 2) }}
</span>
`,
}).$mount();
Vue.nextTick(() => {
expect(
comp.$el.textContent.trim(),
).toBe('days');
done();
});
});
});
require 'spec_helper'
module Gitlab
describe I18n, lib: true do
let(:user) { create(:user, preferred_language: 'es') }
describe '.set_locale' do
it 'sets the locale based on current user preferred language' do
Gitlab::I18n.set_locale(user)
expect(FastGettext.locale).to eq('es')
expect(::I18n.locale).to eq(:es)
end
end
describe '.reset_locale' do
it 'resets the locale to the default language' do
Gitlab::I18n.set_locale(user)
Gitlab::I18n.reset_locale
expect(FastGettext.locale).to eq('en')
expect(::I18n.locale).to eq(:en)
end
end
end
end
......@@ -1663,4 +1663,12 @@ describe User, models: true do
expect(User.active.count).to eq(1)
end
end
describe 'preferred language' do
it 'is English by default' do
user = create(:user)
expect(user.preferred_language).to eq('en')
end
end
end
......@@ -2159,6 +2159,13 @@ expand-range@^1.8.1:
dependencies:
fill-range "^2.1.0"
exports-loader@^0.6.4:
version "0.6.4"
resolved "https://registry.yarnpkg.com/exports-loader/-/exports-loader-0.6.4.tgz#d70fc6121975b35fc12830cf52754be2740fc886"
dependencies:
loader-utils "^1.0.2"
source-map "0.5.x"
express@^4.13.3, express@^4.14.1:
version "4.14.1"
resolved "https://registry.yarnpkg.com/express/-/express-4.14.1.tgz#646c237f766f148c2120aff073817b9e4d7e0d33"
......@@ -3102,6 +3109,10 @@ jasmine-jquery@^2.1.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/jasmine-jquery/-/jasmine-jquery-2.1.1.tgz#d4095e646944a26763235769ab018d9f30f0d47b"
jed@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/jed/-/jed-1.1.1.tgz#7a549bbd9ffe1585b0cd0a191e203055bee574b4"
jodid25519@^1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/jodid25519/-/jodid25519-1.0.2.tgz#06d4912255093419477d425633606e0e90782967"
......@@ -5118,6 +5129,10 @@ source-map-support@^0.4.2:
dependencies:
source-map "^0.5.3"
source-map@0.5.x, source-map@^0.5.0, source-map@^0.5.3, source-map@^0.5.6, source-map@~0.5.1, source-map@~0.5.3:
version "0.5.6"
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.6.tgz#75ce38f52bf0733c5a7f0c118d81334a2bb5f412"
source-map@^0.1.41:
version "0.1.43"
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.1.43.tgz#c24bc146ca517c1471f5dacbe2571b2b7f9e3346"
......@@ -5130,10 +5145,6 @@ source-map@^0.4.4:
dependencies:
amdefine ">=0.0.4"
source-map@^0.5.0, source-map@^0.5.3, source-map@^0.5.6, source-map@~0.5.1, source-map@~0.5.3:
version "0.5.6"
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.6.tgz#75ce38f52bf0733c5a7f0c118d81334a2bb5f412"
source-map@~0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.2.0.tgz#dab73fbcfc2ba819b4de03bd6f6eaa48164b3f9d"
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册